From dfdf4f69f19e402790bf4b13dbcbb312955515f6 Mon Sep 17 00:00:00 2001 From: 3manuek <3manuek@gmailc.om> Date: Mon, 28 Mar 2022 16:59:05 +0200 Subject: [PATCH] Rebuild Babelfish 1.1 RC2 Signed-off-by: 3manuek <3manuek@gmailc.om> --- .github/workflows/jdbc_unit_tests.yml | 155 + .github/workflows/main.yml | 34 - INSTALLING | 112 + contrib/Makefile | 16 +- contrib/babelfishpg_common/Makefile | 97 + contrib/babelfishpg_common/Version.config | 4 + .../babelfishpg_common.control.in | 7 + .../sql/babelfishpg_common--1.0.0.sql | 5794 ++++++ .../sql/babelfishpg_common.in | 39 + contrib/babelfishpg_common/sql/binary.sql | 275 + contrib/babelfishpg_common/sql/bit.sql | 431 + contrib/babelfishpg_common/sql/bpchar.sql | 298 + contrib/babelfishpg_common/sql/coerce.sql | 145 + contrib/babelfishpg_common/sql/datetime.sql | 392 + contrib/babelfishpg_common/sql/datetime2.sql | 321 + .../babelfishpg_common/sql/datetimeoffset.sql | 304 + .../fixeddecimal--1.1.0_base_parallel.sql | 1602 ++ .../sql/money/fixeddecimal--brin.sql | 12 + .../sql/money/fixeddecimal--parallelaggs.sql | 70 + contrib/babelfishpg_common/sql/numerics.sql | 77 + .../babelfishpg_common/sql/smalldatetime.sql | 588 + contrib/babelfishpg_common/sql/sqlvariant.sql | 548 + .../sql/string_operators.sql | 67 + contrib/babelfishpg_common/sql/strings.sql | 2 + .../sql/uniqueidentifier.sql | 214 + .../sql/upgrades/Release.md | 1 + .../babelfishpg_common--1.0.0--1.1.0.sql | 338 + contrib/babelfishpg_common/sql/utils.sql | 16 + contrib/babelfishpg_common/sql/varbinary.sql | 278 + contrib/babelfishpg_common/sql/varchar.sql | 243 + .../src/babelfishpg_common.c | 26 + contrib/babelfishpg_common/src/bit.c | 548 + contrib/babelfishpg_common/src/coerce.c | 339 + contrib/babelfishpg_common/src/datetime.c | 600 + contrib/babelfishpg_common/src/datetime.h | 31 + contrib/babelfishpg_common/src/datetime2.c | 416 + contrib/babelfishpg_common/src/datetime2.h | 25 + .../babelfishpg_common/src/datetimeoffset.c | 773 + .../babelfishpg_common/src/datetimeoffset.h | 38 + contrib/babelfishpg_common/src/instr.c | 18 + contrib/babelfishpg_common/src/instr.h | 473 + contrib/babelfishpg_common/src/numeric.c | 1031 + contrib/babelfishpg_common/src/numeric.h | 9 + .../babelfishpg_common/src/smalldatetime.c | 594 + contrib/babelfishpg_common/src/sqlvariant.c | 2257 +++ contrib/babelfishpg_common/src/typecode.c | 285 + contrib/babelfishpg_common/src/typecode.h | 84 + .../babelfishpg_common/src/uniqueidentifier.c | 238 + contrib/babelfishpg_common/src/varbinary.c | 1192 ++ contrib/babelfishpg_common/src/varchar.c | 1258 ++ contrib/babelfishpg_money/Makefile | 47 + contrib/babelfishpg_money/README.md | 162 + .../babelfishpg_money.control | 4 + .../fixeddecimal--1.0.0--1.1.0.sql | 800 + .../fixeddecimal--1.0.0_base.sql | 527 + .../fixeddecimal--1.1.0_base.sql | 1193 ++ .../fixeddecimal--1.1.0_base_parallel.sql | 1419 ++ .../babelfishpg_money/fixeddecimal--aggs.sql | 44 + .../babelfishpg_money/fixeddecimal--brin.sql | 12 + .../fixeddecimal--parallelaggs.sql | 70 + .../fixeddecimal--xlaggs.sql | 57 + contrib/babelfishpg_money/fixeddecimal.c | 3032 +++ .../fixeddecimalaggstate.sql | 41 + .../test/expected/aggregate.out | 33 + .../test/expected/brin-xl.out | 23 + .../babelfishpg_money/test/expected/brin.out | 22 + .../babelfishpg_money/test/expected/cast.out | 48 + .../test/expected/comparison.out | 310 + .../test/expected/index-xl.out | 95 + .../babelfishpg_money/test/expected/index.out | 92 + .../test/expected/overflow.out | 123 + .../babelfishpg_money/test/sql/aggregate.sql | 21 + .../babelfishpg_money/test/sql/brin-xl.sql | 14 + contrib/babelfishpg_money/test/sql/brin.sql | 14 + contrib/babelfishpg_money/test/sql/cast.sql | 23 + .../babelfishpg_money/test/sql/comparison.sql | 118 + .../babelfishpg_money/test/sql/index-xl.sql | 47 + contrib/babelfishpg_money/test/sql/index.sql | 50 + .../babelfishpg_money/test/sql/overflow.sql | 79 + contrib/babelfishpg_tds/Makefile | 43 + contrib/babelfishpg_tds/README | 8 + contrib/babelfishpg_tds/README.err | 4 + .../babelfishpg_tds--1.0.0.sql | 50 + .../babelfishpg_tds/babelfishpg_tds.control | 7 + contrib/babelfishpg_tds/error_mapping.txt | 169 + .../babelfishpg_tds/generate_error_mapping.pl | 35 + .../src/backend/encoding/encoding_utils.c | 121 + .../backend/fault_injection/fault_injection.c | 403 + .../fault_injection/fault_injection_tests.c | 239 + .../src/backend/tds/err_handler.c | 324 + contrib/babelfishpg_tds/src/backend/tds/guc.c | 303 + .../src/backend/tds/support_funcs.c | 632 + .../src/backend/tds/tds-secure-openssl.c | 1442 ++ contrib/babelfishpg_tds/src/backend/tds/tds.c | 124 + .../src/backend/tds/tds_data_map.c | 221 + .../babelfishpg_tds/src/backend/tds/tds_srv.c | 477 + .../src/backend/tds/tdsbulkload.c | 691 + .../babelfishpg_tds/src/backend/tds/tdscomm.c | 953 + .../src/backend/tds/tdslogin.c | 2366 +++ .../src/backend/tds/tdsprinttup.c | 116 + .../src/backend/tds/tdsprotocol.c | 707 + .../src/backend/tds/tdsresponse.c | 2905 +++ .../babelfishpg_tds/src/backend/tds/tdsrpc.c | 3905 ++++ .../src/backend/tds/tdssecure.c | 411 + .../src/backend/tds/tdssqlbatch.c | 139 + .../src/backend/tds/tdstimestamp.c | 473 + .../src/backend/tds/tdstypeio.c | 3561 ++++ .../src/backend/tds/tdsutils.c | 536 + .../babelfishpg_tds/src/backend/tds/tdsxact.c | 442 + .../src/backend/utils/adt/README | 62 + .../src/backend/utils/adt/numeric.c | 786 + .../src/backend/utils/adt/varchar.c | 109 + .../src/backend/utils/adt/xml.c | 738 + .../src/backend/utils/mb/README | 0 .../src/backend/utils/mb/conv.c | 361 + .../utf8_and_big5/utf8_and_big5.c | 42 + .../utf8_and_gbk/utf8_and_gbk.c | 42 + .../utf8_and_sjis/utf8_and_sjis.c | 42 + .../utf8_and_uhc/utf8_and_uhc.c | 42 + .../utf8_and_win/utf8_and_win.c | 98 + .../babelfishpg_tds/src/include/.gitignore | 1 + .../babelfishpg_tds/src/include/err_handler.h | 51 + .../src/include/faultinjection.h | 81 + contrib/babelfishpg_tds/src/include/guc.h | 28 + contrib/babelfishpg_tds/src/include/tds.h | 34 + .../babelfishpg_tds/src/include/tds_debug.h | 113 + .../babelfishpg_tds/src/include/tds_instr.h | 96 + contrib/babelfishpg_tds/src/include/tds_int.h | 345 + .../src/include/tds_iofuncmap.h | 159 + .../src/include/tds_protocol.h | 81 + .../babelfishpg_tds/src/include/tds_request.h | 896 + .../src/include/tds_response.h | 102 + .../babelfishpg_tds/src/include/tds_secure.h | 61 + .../src/include/tds_timestamp.h | 48 + .../src/include/tds_typecode.h | 57 + .../babelfishpg_tds/src/include/tds_typeio.h | 474 + .../babelfishpg_tds/src/include/tdsprinttup.h | 15 + contrib/babelfishpg_tsql/Makefile | 235 + contrib/babelfishpg_tsql/Release.md | 49 + contrib/babelfishpg_tsql/Version.config | 7 + contrib/babelfishpg_tsql/antlr/CMakeLists.txt | 33 + contrib/babelfishpg_tsql/antlr/TSqlLexer.g4 | 1287 ++ contrib/babelfishpg_tsql/antlr/TSqlParser.g4 | 5031 +++++ .../antlr/cmake-dir/FindANTLR.cmake | 128 + .../antlr/cmake-dir/README.md | 157 + .../thirdparty/antlr/antlr-4.9.3-complete.jar | Bin 0 -> 3508089 bytes .../babelfishpg_tsql.control.in | 7 + contrib/babelfishpg_tsql/runtime/basic.sql | 16 + contrib/babelfishpg_tsql/runtime/functions.c | 542 + .../sql/babelfishpg_tsql--1.0.0.sql | 16610 ++++++++++++++++ .../babelfishpg_tsql/sql/babelfishpg_tsql.in | 28 + .../babelfishpg_tsql/sql/babelfishpg_tsql.sql | 1146 ++ contrib/babelfishpg_tsql/sql/coerce.sql | 11 + contrib/babelfishpg_tsql/sql/collation.sql | 347 + contrib/babelfishpg_tsql/sql/datatype.sql | 6 + .../sql/datatype_string_operators.sql | 53 + .../sql/import_export_compatibility.sql | 37 + contrib/babelfishpg_tsql/sql/ownership.sql | 314 + contrib/babelfishpg_tsql/sql/sys.sql | 129 + contrib/babelfishpg_tsql/sql/sys_cast.sql | 131 + .../sql/sys_function_helpers.sql | 10128 ++++++++++ .../babelfishpg_tsql/sql/sys_functions.sql | 1879 ++ .../babelfishpg_tsql/sql/sys_languages.sql | 2025 ++ .../babelfishpg_tsql/sql/sys_procedures.sql | 153 + contrib/babelfishpg_tsql/sql/sys_views.sql | 1100 + .../babelfishpg_tsql/sql/upgrades/.gitignore | 0 .../babelfishpg_tsql--1.0.0--1.1.0.sql | 1282 ++ contrib/babelfishpg_tsql/src/analyzer.c | 318 + contrib/babelfishpg_tsql/src/analyzer.h | 8 + .../babelfishpg_tsql/src/antlrTests/decl.sql | 14 + .../src/antlrTests/ifelse.sql | 17 + .../babelfishpg_tsql/src/antlrTests/inval.sql | 23 + .../src/antlrTests/nestedBlocks.sql | 15 + .../src/antlrTests/oneBlock.sql | 6 + .../babelfishpg_tsql/src/antlrTests/print.sql | 14 + .../src/antlrTests/print2.sql | 13 + .../src/antlrTests/proc_simple.sql | 6 + .../src/antlrTests/returnsTable.sql | 5 + .../src/antlrTests/series.sql | 11 + .../src/antlrTests/simple.sql | 6 + .../src/antlrTests/simple2.sql | 10 + .../src/antlrTests/single.sql | 3 + .../babelfishpg_tsql/src/antlrTests/throw.sql | 3 + .../src/antlrTests/tryCatch.sql | 26 + .../babelfishpg_tsql/src/antlrTests/while.sql | 23 + contrib/babelfishpg_tsql/src/applock.c | 889 + .../babelfishpg_tsql/src/babelfish_version.h | 15 + .../src/backend_parser/gram-tsql-decl.y | 110 + .../src/backend_parser/gram-tsql-epilogue.y.c | 1307 ++ .../gram-tsql-nonassoc-ident-tokens | 1 + .../src/backend_parser/gram-tsql-prologue.y.h | 70 + .../src/backend_parser/gram-tsql-rule.y | 3763 ++++ .../src/backend_parser/gram_hook.c | 254 + .../src/backend_parser/gramparse.h | 49 + .../src/backend_parser/include.pl | 168 + .../src/backend_parser/keywords.c | 18 + .../src/backend_parser/kwlist.h | 546 + .../src/backend_parser/parser.c | 266 + .../src/backend_parser/scan-tsql-decl.l | 64 + .../src/backend_parser/scan-tsql-epilogue.l.c | 88 + .../backend_parser/scan-tsql-prologue-top.l.h | 8 + .../src/backend_parser/scan-tsql-prologue.l.h | 39 + .../src/backend_parser/scan-tsql-rule.l | 349 + .../src/backend_parser/scanner.h | 19 + contrib/babelfishpg_tsql/src/catalog.c | 632 + contrib/babelfishpg_tsql/src/catalog.h | 115 + contrib/babelfishpg_tsql/src/codegen.c | 669 + contrib/babelfishpg_tsql/src/codegen.h | 8 + contrib/babelfishpg_tsql/src/collation.c | 1542 ++ contrib/babelfishpg_tsql/src/collation.h | 102 + .../babelfishpg_tsql/src/collationproperty.c | 45 + .../babelfishpg_tsql/src/compile_context.c | 46 + .../babelfishpg_tsql/src/compile_context.h | 50 + contrib/babelfishpg_tsql/src/cursor.c | 1715 ++ .../babelfishpg_tsql/src/databasepropertyex.c | 235 + contrib/babelfishpg_tsql/src/datatypes.h | 18 + contrib/babelfishpg_tsql/src/dbcmds.c | 778 + contrib/babelfishpg_tsql/src/dbcmds.h | 8 + contrib/babelfishpg_tsql/src/dynastack.c | 43 + contrib/babelfishpg_tsql/src/dynastack.h | 25 + contrib/babelfishpg_tsql/src/dynavec.c | 102 + contrib/babelfishpg_tsql/src/dynavec.h | 41 + contrib/babelfishpg_tsql/src/err_handler.c | 282 + contrib/babelfishpg_tsql/src/err_handler.h | 132 + contrib/babelfishpg_tsql/src/forxml.c | 260 + .../src/generate-plerrcodes.pl | 40 + contrib/babelfishpg_tsql/src/guc.c | 1107 + contrib/babelfishpg_tsql/src/guc.h | 18 + contrib/babelfishpg_tsql/src/hooks.c | 805 + contrib/babelfishpg_tsql/src/hooks.h | 14 + contrib/babelfishpg_tsql/src/iterative_exec.c | 1614 ++ contrib/babelfishpg_tsql/src/iterative_exec.h | 37 + contrib/babelfishpg_tsql/src/multidb.c | 962 + contrib/babelfishpg_tsql/src/multidb.h | 26 + contrib/babelfishpg_tsql/src/pl_comp-2.c | 124 + contrib/babelfishpg_tsql/src/pl_comp.c | 3225 +++ contrib/babelfishpg_tsql/src/pl_exec-2.c | 2670 +++ contrib/babelfishpg_tsql/src/pl_exec.c | 9859 +++++++++ contrib/babelfishpg_tsql/src/pl_funcs-2.c | 699 + contrib/babelfishpg_tsql/src/pl_funcs-2.h | 7 + contrib/babelfishpg_tsql/src/pl_funcs.c | 1799 ++ contrib/babelfishpg_tsql/src/pl_gram.y | 8338 ++++++++ contrib/babelfishpg_tsql/src/pl_handler.c | 3786 ++++ .../babelfishpg_tsql/src/pl_reserved_kwlist.h | 59 + contrib/babelfishpg_tsql/src/pl_scanner.c | 829 + .../src/pl_unreserved_kwlist.h | 127 + contrib/babelfishpg_tsql/src/plan_inval.c | 143 + contrib/babelfishpg_tsql/src/plerrcodes.h | 1002 + contrib/babelfishpg_tsql/src/pltsql-2.h | 310 + contrib/babelfishpg_tsql/src/pltsql.h | 1964 ++ contrib/babelfishpg_tsql/src/pltsql_coerce.c | 1105 + .../src/pltsql_function_probin_handler.c | 492 + .../babelfishpg_tsql/src/pltsql_identity.c | 310 + contrib/babelfishpg_tsql/src/pltsql_instr.h | 641 + contrib/babelfishpg_tsql/src/pltsql_utils.c | 726 + contrib/babelfishpg_tsql/src/prepare.c | 683 + contrib/babelfishpg_tsql/src/procedures.c | 510 + contrib/babelfishpg_tsql/src/properties.c | 457 + contrib/babelfishpg_tsql/src/rolecmds.c | 750 + contrib/babelfishpg_tsql/src/rolecmds.h | 28 + contrib/babelfishpg_tsql/src/schemacmds.c | 168 + contrib/babelfishpg_tsql/src/schemacmds.h | 10 + contrib/babelfishpg_tsql/src/session.c | 168 + contrib/babelfishpg_tsql/src/session.h | 11 + contrib/babelfishpg_tsql/src/stmt_walker.c | 209 + contrib/babelfishpg_tsql/src/stmt_walker.h | 164 + contrib/babelfishpg_tsql/src/string.c | 493 + contrib/babelfishpg_tsql/src/tablecmds.c | 522 + contrib/babelfishpg_tsql/src/tsqlHandler.c | 30 + contrib/babelfishpg_tsql/src/tsqlIface.cpp | 5357 +++++ contrib/babelfishpg_tsql/src/tsqlIface.hpp | 92 + contrib/babelfishpg_tsql/src/tsqlNodes.c | 41 + contrib/babelfishpg_tsql/src/tsqlNodes.h | 103 + .../src/tsqlUnsupportedFeatureHandler.cpp | 1540 ++ .../src/tsqlUnsupportedFeatureHandler.h | 0 .../src/utils/update_pg_files | 35 + .../old_expected/pltsql_at_prefixed_vars.out | 240 + .../test/old_expected/pltsql_case.out | 23 + .../test/old_expected/pltsql_if.out | 81 + .../old_expected/pltsql_localtempobjs.out | 113 + .../old_expected/pltsql_optsemicolterm.out | 155 + .../test/old_expected/pltsql_print.out | 94 + .../test/old_expected/pltsql_print_0.out | 91 + .../test/old_expected/pltsql_sanitychecks.out | 22 + .../old_expected/top_percent_keywords.out | 20 + .../test/old_sql/pltsql_at_prefixed_vars.sql | 177 + .../test/old_sql/pltsql_case.sql | 18 + .../test/old_sql/pltsql_if.sql | 65 + .../test/old_sql/pltsql_localtempobjs.sql | 86 + .../test/old_sql/pltsql_optsemicolterm.sql | 119 + .../test/old_sql/pltsql_print.sql | 63 + .../test/old_sql/pltsql_sanitychecks.sql | 12 + .../test/old_sql/top_percent_keywords.sql | 12 + contrib/test/JDBC/BABEL-2267.sql | 14 + contrib/test/JDBC/BABEL-2455.sql | 170 + contrib/test/JDBC/Info/.gitignore | 4 + contrib/test/JDBC/README.md | 5 + contrib/test/JDBC/cleanup.sh | 12 + contrib/test/JDBC/expected/102_1.out | 487 + contrib/test/JDBC/expected/102_2.out | 497 + contrib/test/JDBC/expected/102_3.out | 497 + contrib/test/JDBC/expected/102_6.out | 487 + contrib/test/JDBC/expected/113_1.out | 294 + contrib/test/JDBC/expected/11704_1.out | 245 + contrib/test/JDBC/expected/11704_2.out | 263 + contrib/test/JDBC/expected/129_1.out | 432 + contrib/test/JDBC/expected/1770_1750_1.out | 236 + contrib/test/JDBC/expected/1774_1750_1.out | 284 + contrib/test/JDBC/expected/208_1.out | 224 + contrib/test/JDBC/expected/218_1.out | 325 + contrib/test/JDBC/expected/222_1.out | 230 + contrib/test/JDBC/expected/257_2.out | 306 + contrib/test/JDBC/expected/2760_1.out | 221 + contrib/test/JDBC/expected/2812_1.out | 264 + contrib/test/JDBC/expected/2812_2.out | 212 + contrib/test/JDBC/expected/2812_3.out | 264 + contrib/test/JDBC/expected/4924_1.out | 260 + contrib/test/JDBC/expected/4924_2.out | 260 + contrib/test/JDBC/expected/4936_1.out | 230 + contrib/test/JDBC/expected/4936_2.out | 248 + contrib/test/JDBC/expected/BABEL-1000.out | 296 + contrib/test/JDBC/expected/BABEL-101.out | 86 + contrib/test/JDBC/expected/BABEL-1044.out | 286 + contrib/test/JDBC/expected/BABEL-1056.out | 61 + contrib/test/JDBC/expected/BABEL-1066.out | 47 + contrib/test/JDBC/expected/BABEL-1073.out | 39 + contrib/test/JDBC/expected/BABEL-1091.out | 355 + contrib/test/JDBC/expected/BABEL-1094.out | 28 + contrib/test/JDBC/expected/BABEL-1096.out | 69 + contrib/test/JDBC/expected/BABEL-1098.out | 725 + contrib/test/JDBC/expected/BABEL-1113.out | 66 + contrib/test/JDBC/expected/BABEL-1114.out | 145 + contrib/test/JDBC/expected/BABEL-1149.out | 83 + contrib/test/JDBC/expected/BABEL-1161.out | 176 + contrib/test/JDBC/expected/BABEL-1164.out | 98 + contrib/test/JDBC/expected/BABEL-1167.out | 34 + contrib/test/JDBC/expected/BABEL-1173.out | 13 + contrib/test/JDBC/expected/BABEL-1179.out | 121 + contrib/test/JDBC/expected/BABEL-1184.out | 96 + contrib/test/JDBC/expected/BABEL-1185.out | 22 + contrib/test/JDBC/expected/BABEL-1189.out | 43 + contrib/test/JDBC/expected/BABEL-1193.out | 291 + contrib/test/JDBC/expected/BABEL-1206.out | 110 + contrib/test/JDBC/expected/BABEL-1208.out | 110 + contrib/test/JDBC/expected/BABEL-1210.out | 149 + contrib/test/JDBC/expected/BABEL-1212.out | 25 + contrib/test/JDBC/expected/BABEL-1231.out | 49 + contrib/test/JDBC/expected/BABEL-1234.out | 7 + contrib/test/JDBC/expected/BABEL-1239.out | 23 + contrib/test/JDBC/expected/BABEL-1241.out | 133 + contrib/test/JDBC/expected/BABEL-1249.out | 98 + contrib/test/JDBC/expected/BABEL-1251.out | 157 + contrib/test/JDBC/expected/BABEL-1252.out | 168 + contrib/test/JDBC/expected/BABEL-1261.out | 153 + contrib/test/JDBC/expected/BABEL-1270.out | 37 + contrib/test/JDBC/expected/BABEL-1287.out | 182 + contrib/test/JDBC/expected/BABEL-1291.out | 38 + contrib/test/JDBC/expected/BABEL-1299.out | 44 + contrib/test/JDBC/expected/BABEL-1309.out | 58 + contrib/test/JDBC/expected/BABEL-1311.out | 128 + contrib/test/JDBC/expected/BABEL-1319.out | 34 + contrib/test/JDBC/expected/BABEL-1320.out | 66 + contrib/test/JDBC/expected/BABEL-1329.out | 71 + contrib/test/JDBC/expected/BABEL-1331.out | 53 + contrib/test/JDBC/expected/BABEL-1363.out | 59 + contrib/test/JDBC/expected/BABEL-1365.out | 48 + contrib/test/JDBC/expected/BABEL-1381.out | 149 + contrib/test/JDBC/expected/BABEL-1389.out | 76 + contrib/test/JDBC/expected/BABEL-1390.out | 35 + contrib/test/JDBC/expected/BABEL-1400.out | 73 + contrib/test/JDBC/expected/BABEL-1435.out | 258 + contrib/test/JDBC/expected/BABEL-1437.out | 116 + contrib/test/JDBC/expected/BABEL-1438.out | 9 + contrib/test/JDBC/expected/BABEL-1442.out | 434 + contrib/test/JDBC/expected/BABEL-1444.out | 263 + contrib/test/JDBC/expected/BABEL-1446.out | 163 + contrib/test/JDBC/expected/BABEL-1454.out | 411 + contrib/test/JDBC/expected/BABEL-1465.out | 598 + contrib/test/JDBC/expected/BABEL-1466.out | 133 + contrib/test/JDBC/expected/BABEL-1475.out | 144 + contrib/test/JDBC/expected/BABEL-1481.out | 167 + contrib/test/JDBC/expected/BABEL-1499.out | 61 + contrib/test/JDBC/expected/BABEL-1502.out | 26 + contrib/test/JDBC/expected/BABEL-1510.out | 226 + contrib/test/JDBC/expected/BABEL-1513.out | 111 + contrib/test/JDBC/expected/BABEL-1515.out | 63 + contrib/test/JDBC/expected/BABEL-1531.out | 58 + contrib/test/JDBC/expected/BABEL-1566.out | 52 + contrib/test/JDBC/expected/BABEL-1569.out | 84 + contrib/test/JDBC/expected/BABEL-1577.out | 32 + contrib/test/JDBC/expected/BABEL-1603.out | 78 + contrib/test/JDBC/expected/BABEL-1621.out | 15 + contrib/test/JDBC/expected/BABEL-1636.out | 91 + contrib/test/JDBC/expected/BABEL-1661.out | 33 + contrib/test/JDBC/expected/BABEL-1666.out | 39 + contrib/test/JDBC/expected/BABEL-1671.out | 38 + contrib/test/JDBC/expected/BABEL-1682.out | 26 + contrib/test/JDBC/expected/BABEL-1683.out | 170 + contrib/test/JDBC/expected/BABEL-1708.out | 174 + contrib/test/JDBC/expected/BABEL-1712.out | 77 + contrib/test/JDBC/expected/BABEL-1715.out | 67 + contrib/test/JDBC/expected/BABEL-1719.out | 31 + contrib/test/JDBC/expected/BABEL-1746.out | 13 + contrib/test/JDBC/expected/BABEL-1756.out | 27 + contrib/test/JDBC/expected/BABEL-1757.out | 13 + contrib/test/JDBC/expected/BABEL-1771.out | 116 + contrib/test/JDBC/expected/BABEL-1792.out | 77 + contrib/test/JDBC/expected/BABEL-1797.out | 20 + contrib/test/JDBC/expected/BABEL-1808.out | 65 + contrib/test/JDBC/expected/BABEL-1813.out | 215 + contrib/test/JDBC/expected/BABEL-1839.out | 67 + contrib/test/JDBC/expected/BABEL-1845.out | 50 + contrib/test/JDBC/expected/BABEL-1858.out | 68 + contrib/test/JDBC/expected/BABEL-1963.out | 40 + contrib/test/JDBC/expected/BABEL-1975.out | 73 + contrib/test/JDBC/expected/BABEL-1978.out | 48 + .../test/JDBC/expected/BABEL-1994-CHAR.out | 215 + .../test/JDBC/expected/BABEL-1994-VARCHAR.out | 213 + contrib/test/JDBC/expected/BABEL-1997.out | 38 + contrib/test/JDBC/expected/BABEL-2010.out | 48 + contrib/test/JDBC/expected/BABEL-2011.out | 45 + .../test/JDBC/expected/BABEL-2020-DELETE.out | 292 + .../test/JDBC/expected/BABEL-2020-UPDATE.out | 292 + contrib/test/JDBC/expected/BABEL-2034.out | 98 + contrib/test/JDBC/expected/BABEL-2049.out | 119 + contrib/test/JDBC/expected/BABEL-2051.out | 12 + contrib/test/JDBC/expected/BABEL-2060.out | 203 + contrib/test/JDBC/expected/BABEL-2086.out | 573 + contrib/test/JDBC/expected/BABEL-2089.out | 388 + contrib/test/JDBC/expected/BABEL-213.out | 451 + contrib/test/JDBC/expected/BABEL-2145.out | 56 + contrib/test/JDBC/expected/BABEL-2203.out | 174 + contrib/test/JDBC/expected/BABEL-2208.out | 76 + contrib/test/JDBC/expected/BABEL-2218.out | 51 + contrib/test/JDBC/expected/BABEL-2225.out | 40 + contrib/test/JDBC/expected/BABEL-2234.out | 38 + contrib/test/JDBC/expected/BABEL-2257.out | 92 + contrib/test/JDBC/expected/BABEL-2258.out | 31 + contrib/test/JDBC/expected/BABEL-2262.out | 54 + contrib/test/JDBC/expected/BABEL-2266.out | 85 + contrib/test/JDBC/expected/BABEL-2267.out | 26 + contrib/test/JDBC/expected/BABEL-2276.out | 18 + contrib/test/JDBC/expected/BABEL-2288.out | 41 + contrib/test/JDBC/expected/BABEL-2303.out | 84 + contrib/test/JDBC/expected/BABEL-2317.out | 47 + contrib/test/JDBC/expected/BABEL-2325.out | 74 + contrib/test/JDBC/expected/BABEL-2328.out | 78 + contrib/test/JDBC/expected/BABEL-2337.out | 11 + contrib/test/JDBC/expected/BABEL-2347.out | 282 + contrib/test/JDBC/expected/BABEL-2349.out | 20 + contrib/test/JDBC/expected/BABEL-235.out | 123 + contrib/test/JDBC/expected/BABEL-2350.out | 70 + contrib/test/JDBC/expected/BABEL-2355.out | 31 + contrib/test/JDBC/expected/BABEL-2357.out | 14 + contrib/test/JDBC/expected/BABEL-2371.out | 133 + contrib/test/JDBC/expected/BABEL-2372.out | 22 + contrib/test/JDBC/expected/BABEL-2381.out | 969 + contrib/test/JDBC/expected/BABEL-2390.out | 36 + contrib/test/JDBC/expected/BABEL-2392.out | 89 + contrib/test/JDBC/expected/BABEL-2403.out | 7 + contrib/test/JDBC/expected/BABEL-2409.out | 45 + contrib/test/JDBC/expected/BABEL-2410.out | 47 + contrib/test/JDBC/expected/BABEL-2412.out | 5 + contrib/test/JDBC/expected/BABEL-2416.out | 25 + contrib/test/JDBC/expected/BABEL-2417.out | 10 + contrib/test/JDBC/expected/BABEL-2418.out | 41 + contrib/test/JDBC/expected/BABEL-2433.out | 70 + contrib/test/JDBC/expected/BABEL-244.out | 58 + contrib/test/JDBC/expected/BABEL-2440.out | 80 + contrib/test/JDBC/expected/BABEL-2445.out | 31 + contrib/test/JDBC/expected/BABEL-2451.out | 13 + contrib/test/JDBC/expected/BABEL-2455.out | 345 + contrib/test/JDBC/expected/BABEL-2458.out | 137 + contrib/test/JDBC/expected/BABEL-2470.out | 34 + contrib/test/JDBC/expected/BABEL-2482.out | 43 + contrib/test/JDBC/expected/BABEL-2485.out | 158 + contrib/test/JDBC/expected/BABEL-2513.out | 1548 ++ contrib/test/JDBC/expected/BABEL-2514.out | 199 + contrib/test/JDBC/expected/BABEL-2515.out | 36 + contrib/test/JDBC/expected/BABEL-2535.out | 307 + contrib/test/JDBC/expected/BABEL-2569.out | 25 + contrib/test/JDBC/expected/BABEL-2576.out | 127 + contrib/test/JDBC/expected/BABEL-2585.out | 183 + contrib/test/JDBC/expected/BABEL-2593.out | 74 + contrib/test/JDBC/expected/BABEL-2596.out | 81 + contrib/test/JDBC/expected/BABEL-2602.out | 24 + contrib/test/JDBC/expected/BABEL-2604.out | 152 + contrib/test/JDBC/expected/BABEL-2607.out | 57 + contrib/test/JDBC/expected/BABEL-2622.out | 47 + contrib/test/JDBC/expected/BABEL-2647.out | 18 + contrib/test/JDBC/expected/BABEL-265.out | 109 + contrib/test/JDBC/expected/BABEL-2659.out | 72 + contrib/test/JDBC/expected/BABEL-2674.out | 133 + contrib/test/JDBC/expected/BABEL-2676.out | 34 + contrib/test/JDBC/expected/BABEL-2706.out | 20 + contrib/test/JDBC/expected/BABEL-2724.out | 90 + contrib/test/JDBC/expected/BABEL-2725.out | 103 + contrib/test/JDBC/expected/BABEL-338.out | 249 + contrib/test/JDBC/expected/BABEL-388.out | 115 + contrib/test/JDBC/expected/BABEL-405.out | 385 + contrib/test/JDBC/expected/BABEL-407.out | 25 + contrib/test/JDBC/expected/BABEL-453.out | 215 + contrib/test/JDBC/expected/BABEL-480.out | 17 + contrib/test/JDBC/expected/BABEL-493.out | 157 + contrib/test/JDBC/expected/BABEL-559.out | 35 + contrib/test/JDBC/expected/BABEL-565.out | 37 + contrib/test/JDBC/expected/BABEL-586.out | 99 + contrib/test/JDBC/expected/BABEL-588.out | 1833 ++ contrib/test/JDBC/expected/BABEL-597.out | 10 + contrib/test/JDBC/expected/BABEL-604.out | 46 + contrib/test/JDBC/expected/BABEL-625.out | 9 + contrib/test/JDBC/expected/BABEL-627.out | 25 + contrib/test/JDBC/expected/BABEL-637.out | 1772 ++ contrib/test/JDBC/expected/BABEL-646.out | 96 + contrib/test/JDBC/expected/BABEL-662.out | 128 + contrib/test/JDBC/expected/BABEL-672.out | 5 + contrib/test/JDBC/expected/BABEL-694.out | 44 + contrib/test/JDBC/expected/BABEL-701.out | 17 + contrib/test/JDBC/expected/BABEL-708.out | 285 + contrib/test/JDBC/expected/BABEL-719.out | 129 + contrib/test/JDBC/expected/BABEL-728.out | 651 + contrib/test/JDBC/expected/BABEL-735.out | 480 + contrib/test/JDBC/expected/BABEL-741.out | 102 + contrib/test/JDBC/expected/BABEL-758.out | 182 + contrib/test/JDBC/expected/BABEL-768.out | 116 + contrib/test/JDBC/expected/BABEL-775.out | 42 + contrib/test/JDBC/expected/BABEL-776.out | 189 + contrib/test/JDBC/expected/BABEL-785.out | 224 + contrib/test/JDBC/expected/BABEL-788.out | 258 + contrib/test/JDBC/expected/BABEL-798.out | 19 + contrib/test/JDBC/expected/BABEL-807.out | 24 + contrib/test/JDBC/expected/BABEL-820.out | 36 + contrib/test/JDBC/expected/BABEL-872.out | 36 + contrib/test/JDBC/expected/BABEL-909.out | 34 + contrib/test/JDBC/expected/BABEL-911.out | 19 + contrib/test/JDBC/expected/BABEL-931.out | 66 + contrib/test/JDBC/expected/BABEL-941.out | 49 + contrib/test/JDBC/expected/BABEL-955.out | 70 + contrib/test/JDBC/expected/BABEL-APPLOCK.out | 182 + .../test/JDBC/expected/BABEL-COLUMN-ALIAS.out | 226 + .../JDBC/expected/BABEL-COLUMN-CONSTRAINT.out | 86 + .../expected/BABEL-DATABASEPROPERTYEX.out | 71 + contrib/test/JDBC/expected/BABEL-GUC-PLAN.out | 362 + .../JDBC/expected/BABEL-IDENTITY-BIFS.out | 877 + .../JDBC/expected/BABEL-IDENTITY-COLUMN.out | 219 + .../JDBC/expected/BABEL-INSERT-EXECUTE.out | 732 + .../test/JDBC/expected/BABEL-LIKE2ILIKE.out | 273 + .../JDBC/expected/BABEL-LOGIN-USER-EXT.out | 557 + .../JDBC/expected/BABEL-OBJECT-FUNCTIONS.out | 50 + contrib/test/JDBC/expected/BABEL-PROCID.out | 299 + contrib/test/JDBC/expected/BABEL-RAND.out | 89 + .../JDBC/expected/BABEL-RECURSIVE-CTE.out | 135 + contrib/test/JDBC/expected/BABEL-ROWCOUNT.out | 145 + .../JDBC/expected/BABEL-SCHEMABINDING.out | 105 + contrib/test/JDBC/expected/BABEL-SEQUENCE.out | 608 + .../JDBC/expected/BABEL-SERVERPROPERTY.out | 47 + .../test/JDBC/expected/BABEL-SET-COMMAND.out | 97 + .../test/JDBC/expected/BABEL-SPCOLUMNS.out | 100 + contrib/test/JDBC/expected/BABEL-SPCURSOR.out | 469 + .../test/JDBC/expected/BABEL-SP_DATABASES.out | 37 + .../JDBC/expected/BABEL-SP_DATATYPE_INFO.out | 25 + .../BABEL-SP_DESCRIBE_FRIST_RESULT_SET.out | 30 + contrib/test/JDBC/expected/BABEL-SP_PKEYS.out | 78 + .../JDBC/expected/BABEL-SP_STATISTICS.out | 122 + .../test/JDBC/expected/BABEL-SP_TABLES.out | 111 + .../expected/BABEL-SQL-CONFIG-FUNCTIONS.out | 7 + contrib/test/JDBC/expected/BABEL-SQUARE.out | 114 + .../JDBC/expected/BABEL-SYS-DATABASES.out | 52 + .../test/JDBC/expected/BABEL-SYSCHARSETS.out | 10 + .../test/JDBC/expected/BABEL-SYS_COLUMNS.out | 73 + .../test/JDBC/expected/BABEL-TABLEHINT.out | 215 + .../test/JDBC/expected/BABEL-TARGETLIST.out | 32 + .../test/JDBC/expected/BABEL-UNSUPPORTED.out | 2703 +++ contrib/test/JDBC/expected/BABEL_2429.out | 35 + contrib/test/JDBC/expected/Babel-2655.out | 33 + contrib/test/JDBC/expected/TestBIT.out | 45 + .../test/JDBC/expected/TestBasicInterop.out | 188 + contrib/test/JDBC/expected/TestBigInt.out | 102 + contrib/test/JDBC/expected/TestBinary.out | 69 + contrib/test/JDBC/expected/TestChar.out | 60 + .../TestCompileTimeErrorWithDefaultBehave.out | 268 + .../JDBC/expected/TestCursorFetchNext.out | 269 + .../expected/TestCursorPrepExecFetchNext.out | 288 + contrib/test/JDBC/expected/TestDate.out | 57 + contrib/test/JDBC/expected/TestDatetime.out | 156 + contrib/test/JDBC/expected/TestDatetime2.out | 43 + contrib/test/JDBC/expected/TestDecimal.out | 546 + .../test/JDBC/expected/TestErrorFunctions.out | 282 + .../expected/TestErrorHelperFunctions.out | 168 + contrib/test/JDBC/expected/TestFloat.out | 102 + contrib/test/JDBC/expected/TestForXML.out | 486 + contrib/test/JDBC/expected/TestInt.out | 111 + .../JDBC/expected/TestInteropProcedures.out | 220 + .../JDBC/expected/TestIsolationLevels.out | 104 + contrib/test/JDBC/expected/TestMoney.out | 111 + contrib/test/JDBC/expected/TestNotNull.out | 832 + contrib/test/JDBC/expected/TestNumeric.out | 734 + .../test/JDBC/expected/TestPrepareExec.out | 55 + .../TestProcedureWithErrorHandling.out | 499 + .../TestProcedureWithTransactions.out | 748 + .../expected/TestProcedureWithTriggers.out | 1402 ++ contrib/test/JDBC/expected/TestRaiserror.out | 754 + .../JDBC/expected/TestRaiserrorFormat.out | 113 + contrib/test/JDBC/expected/TestReal.out | 102 + .../TestRunTimeErrorWithDefaultBehave.out | 295 + .../test/JDBC/expected/TestSPExecutesql.out | 285 + contrib/test/JDBC/expected/TestSPPrepare.out | 720 + contrib/test/JDBC/expected/TestSQLQueries.out | 839 + .../test/JDBC/expected/TestSmallDatetime.out | 148 + contrib/test/JDBC/expected/TestSmallInt.out | 102 + .../JDBC/expected/TestStoredProcedures.out | 241 + contrib/test/JDBC/expected/TestText.out | 32 + contrib/test/JDBC/expected/TestThrow.out | 659 + contrib/test/JDBC/expected/TestTime.out | 300 + contrib/test/JDBC/expected/TestTinyInt.out | 103 + .../JDBC/expected/TestTransactionName.out | 135 + .../TestTransactionSupportForProcedure.out | 976 + .../expected/TestTransactionsSQLBatch.out | 494 + contrib/test/JDBC/expected/TestUDD.out | 139 + .../JDBC/expected/TestUniqueIdentifier.out | 151 + contrib/test/JDBC/expected/TestVarChar.out | 159 + contrib/test/JDBC/expected/TestXML.out | 29 + contrib/test/JDBC/expected/babel_613.out | 199 + contrib/test/JDBC/expected/babel_bit_comp.out | 264 + .../JDBC/expected/babel_ceiling_floor.out | 116 + contrib/test/JDBC/expected/babel_char.out | 73 + .../test/JDBC/expected/babel_collation.out | 201 + contrib/test/JDBC/expected/babel_iif.out | 109 + contrib/test/JDBC/expected/babel_isnull.out | 215 + contrib/test/JDBC/expected/babel_money.out | 544 + contrib/test/JDBC/expected/babel_numeric.out | 123 + .../test/JDBC/expected/babel_operators.out | 208 + contrib/test/JDBC/expected/babel_print.out | 39 + .../JDBC/expected/babel_smalldatetime.out | 388 + contrib/test/JDBC/expected/babel_top.out | 91 + contrib/test/JDBC/expected/babel_trigger.out | 407 + .../test/JDBC/expected/babel_varbinary.out | 206 + contrib/test/JDBC/expected/insertbulk.out | 721 + .../test/JDBC/expected/pg_stat_activity.out | 62 + .../JDBC/expected/sys-column-property.out | 110 + contrib/test/JDBC/expected/sys-datefirst.out | 26 + .../test/JDBC/expected/sys-lock_timeout.out | 28 + .../JDBC/expected/sys-max_connections.out | 30 + .../test/JDBC/expected/sys-original_login.out | 7 + .../test/JDBC/expected/sys-schema-name.out | 15 + contrib/test/JDBC/expected/sys-syscolumns.out | 114 + .../JDBC/expected/sys-trigger_nestlevel.out | 58 + .../test/JDBC/expected/tds_faultinjection.out | 79 + contrib/test/JDBC/init.sh | 21 + contrib/test/JDBC/input/BABEL-1000.sql | 177 + contrib/test/JDBC/input/BABEL-101.sql | 82 + contrib/test/JDBC/input/BABEL-1044.sql | 199 + contrib/test/JDBC/input/BABEL-1056.sql | 48 + contrib/test/JDBC/input/BABEL-1066.sql | 17 + contrib/test/JDBC/input/BABEL-1073.sql | 27 + contrib/test/JDBC/input/BABEL-1091.sql | 173 + contrib/test/JDBC/input/BABEL-1094.sql | 28 + contrib/test/JDBC/input/BABEL-1096.sql | 60 + contrib/test/JDBC/input/BABEL-1098.sql | 403 + contrib/test/JDBC/input/BABEL-1113.sql | 34 + contrib/test/JDBC/input/BABEL-1114.sql | 50 + contrib/test/JDBC/input/BABEL-1149.sql | 62 + contrib/test/JDBC/input/BABEL-1161.sql | 134 + contrib/test/JDBC/input/BABEL-1164.sql | 52 + contrib/test/JDBC/input/BABEL-1167.sql | 24 + contrib/test/JDBC/input/BABEL-1173.sql | 13 + contrib/test/JDBC/input/BABEL-1179.sql | 61 + contrib/test/JDBC/input/BABEL-1184.sql | 66 + contrib/test/JDBC/input/BABEL-1185.sql | 14 + contrib/test/JDBC/input/BABEL-1189.sql | 27 + contrib/test/JDBC/input/BABEL-1193.sql | 158 + contrib/test/JDBC/input/BABEL-1206.sql | 73 + contrib/test/JDBC/input/BABEL-1208.sql | 59 + contrib/test/JDBC/input/BABEL-1210.sql | 98 + contrib/test/JDBC/input/BABEL-1212.sql | 10 + contrib/test/JDBC/input/BABEL-1231.sql | 29 + contrib/test/JDBC/input/BABEL-1234.sql | 2 + contrib/test/JDBC/input/BABEL-1239.sql | 15 + contrib/test/JDBC/input/BABEL-1241.sql | 73 + contrib/test/JDBC/input/BABEL-1243.sql | 19 + contrib/test/JDBC/input/BABEL-1249.sql | 43 + contrib/test/JDBC/input/BABEL-1251.sql | 76 + contrib/test/JDBC/input/BABEL-1252.sql | 65 + contrib/test/JDBC/input/BABEL-1261.sql | 73 + contrib/test/JDBC/input/BABEL-1270.txt | 15 + contrib/test/JDBC/input/BABEL-1287.sql | 98 + contrib/test/JDBC/input/BABEL-1291.sql | 16 + contrib/test/JDBC/input/BABEL-1299.sql | 29 + contrib/test/JDBC/input/BABEL-1309.mix | 32 + contrib/test/JDBC/input/BABEL-1311.sql | 118 + contrib/test/JDBC/input/BABEL-1319.sql | 30 + contrib/test/JDBC/input/BABEL-1320.sql | 46 + contrib/test/JDBC/input/BABEL-1329.sql | 26 + contrib/test/JDBC/input/BABEL-1331.sql | 16 + contrib/test/JDBC/input/BABEL-1363.mix | 32 + contrib/test/JDBC/input/BABEL-1381.sql | 99 + contrib/test/JDBC/input/BABEL-1389.sql | 36 + contrib/test/JDBC/input/BABEL-1400.sql | 53 + contrib/test/JDBC/input/BABEL-1435.sql | 112 + contrib/test/JDBC/input/BABEL-1437.sql | 46 + contrib/test/JDBC/input/BABEL-1438.sql | 3 + contrib/test/JDBC/input/BABEL-1442.sql | 253 + contrib/test/JDBC/input/BABEL-1444.sql | 110 + contrib/test/JDBC/input/BABEL-1446.sql | 93 + contrib/test/JDBC/input/BABEL-1454.mix | 273 + contrib/test/JDBC/input/BABEL-1465.sql | 258 + contrib/test/JDBC/input/BABEL-1466.sql | 73 + contrib/test/JDBC/input/BABEL-1475.sql | 109 + contrib/test/JDBC/input/BABEL-1481.sql | 83 + contrib/test/JDBC/input/BABEL-1499.sql | 25 + contrib/test/JDBC/input/BABEL-1502.sql | 22 + contrib/test/JDBC/input/BABEL-1510.sql | 74 + contrib/test/JDBC/input/BABEL-1513.sql | 41 + contrib/test/JDBC/input/BABEL-1515.sql | 23 + contrib/test/JDBC/input/BABEL-1531.sql | 18 + contrib/test/JDBC/input/BABEL-1566.sql | 24 + contrib/test/JDBC/input/BABEL-1569.sql | 57 + contrib/test/JDBC/input/BABEL-1577.sql | 25 + contrib/test/JDBC/input/BABEL-1603.sql | 35 + contrib/test/JDBC/input/BABEL-1621.sql | 5 + contrib/test/JDBC/input/BABEL-1636.sql | 50 + contrib/test/JDBC/input/BABEL-1661.sql | 13 + contrib/test/JDBC/input/BABEL-1666.sql | 19 + contrib/test/JDBC/input/BABEL-1671.sql | 18 + contrib/test/JDBC/input/BABEL-1682.sql | 26 + contrib/test/JDBC/input/BABEL-1683.sql | 106 + contrib/test/JDBC/input/BABEL-1708.sql | 76 + contrib/test/JDBC/input/BABEL-1712.sql | 41 + contrib/test/JDBC/input/BABEL-1715.sql | 39 + contrib/test/JDBC/input/BABEL-1719.sql | 26 + contrib/test/JDBC/input/BABEL-1746.sql | 5 + contrib/test/JDBC/input/BABEL-1756.sql | 13 + contrib/test/JDBC/input/BABEL-1757.sql | 9 + contrib/test/JDBC/input/BABEL-1771.sql | 63 + contrib/test/JDBC/input/BABEL-1792.sql | 51 + contrib/test/JDBC/input/BABEL-1797.sql | 13 + contrib/test/JDBC/input/BABEL-1808.sql | 40 + contrib/test/JDBC/input/BABEL-1813.sql | 132 + contrib/test/JDBC/input/BABEL-1839.sql | 39 + contrib/test/JDBC/input/BABEL-1845.sql | 35 + contrib/test/JDBC/input/BABEL-1858.sql | 38 + contrib/test/JDBC/input/BABEL-1944.sql | 140 + contrib/test/JDBC/input/BABEL-1963.sql | 32 + contrib/test/JDBC/input/BABEL-1975.sql | 34 + contrib/test/JDBC/input/BABEL-1978.sql | 24 + contrib/test/JDBC/input/BABEL-1994-CHAR.sql | 146 + .../test/JDBC/input/BABEL-1994-VARCHAR.sql | 130 + contrib/test/JDBC/input/BABEL-1997.sql | 25 + contrib/test/JDBC/input/BABEL-2010.sql | 31 + contrib/test/JDBC/input/BABEL-2011.sql | 29 + contrib/test/JDBC/input/BABEL-2020-DELETE.sql | 138 + contrib/test/JDBC/input/BABEL-2020-UPDATE.sql | 138 + contrib/test/JDBC/input/BABEL-2034.sql | 79 + contrib/test/JDBC/input/BABEL-2049.sql | 62 + contrib/test/JDBC/input/BABEL-2051.sql | 12 + contrib/test/JDBC/input/BABEL-2060.sql | 104 + contrib/test/JDBC/input/BABEL-2079.sql | 44 + contrib/test/JDBC/input/BABEL-2086.sql | 286 + contrib/test/JDBC/input/BABEL-2089.sql | 384 + contrib/test/JDBC/input/BABEL-213.mix | 352 + contrib/test/JDBC/input/BABEL-2145.sql | 32 + contrib/test/JDBC/input/BABEL-2203.sql | 122 + contrib/test/JDBC/input/BABEL-2208.sql | 46 + contrib/test/JDBC/input/BABEL-2218.sql | 40 + contrib/test/JDBC/input/BABEL-2225.sql | 24 + contrib/test/JDBC/input/BABEL-2234.sql | 21 + contrib/test/JDBC/input/BABEL-2257.sql | 75 + contrib/test/JDBC/input/BABEL-2258.sql | 11 + contrib/test/JDBC/input/BABEL-2262.sql | 41 + contrib/test/JDBC/input/BABEL-2266.sql | 61 + contrib/test/JDBC/input/BABEL-2276.sql | 6 + contrib/test/JDBC/input/BABEL-2288.sql | 26 + contrib/test/JDBC/input/BABEL-2303.sql | 67 + contrib/test/JDBC/input/BABEL-2317.sql | 22 + contrib/test/JDBC/input/BABEL-2325.sql | 39 + contrib/test/JDBC/input/BABEL-2328.sql | 58 + contrib/test/JDBC/input/BABEL-2337.sql | 5 + contrib/test/JDBC/input/BABEL-2347.sql | 162 + contrib/test/JDBC/input/BABEL-2349.sql | 15 + contrib/test/JDBC/input/BABEL-235.sql | 59 + contrib/test/JDBC/input/BABEL-2350.sql | 44 + contrib/test/JDBC/input/BABEL-2354.sql | 15 + contrib/test/JDBC/input/BABEL-2355.sql | 15 + contrib/test/JDBC/input/BABEL-2357.sql | 9 + contrib/test/JDBC/input/BABEL-2371.sql | 65 + contrib/test/JDBC/input/BABEL-2372.sql | 18 + contrib/test/JDBC/input/BABEL-2381.sql | 306 + contrib/test/JDBC/input/BABEL-2390.sql | 24 + contrib/test/JDBC/input/BABEL-2392.sql | 49 + contrib/test/JDBC/input/BABEL-2403.mix | 3 + contrib/test/JDBC/input/BABEL-2409.mix | 31 + contrib/test/JDBC/input/BABEL-2410.sql | 27 + contrib/test/JDBC/input/BABEL-2412.sql | 5 + contrib/test/JDBC/input/BABEL-2416.sql | 15 + contrib/test/JDBC/input/BABEL-2417.sql | 5 + contrib/test/JDBC/input/BABEL-2418.sql | 26 + contrib/test/JDBC/input/BABEL-2419.sql | 20 + contrib/test/JDBC/input/BABEL-2432.sql | 27 + contrib/test/JDBC/input/BABEL-2433.sql | 34 + contrib/test/JDBC/input/BABEL-2437.sql | 16 + contrib/test/JDBC/input/BABEL-244.sql | 43 + contrib/test/JDBC/input/BABEL-2440.mix | 38 + contrib/test/JDBC/input/BABEL-2445.sql | 11 + contrib/test/JDBC/input/BABEL-2451.sql | 11 + contrib/test/JDBC/input/BABEL-2458.mix | 82 + contrib/test/JDBC/input/BABEL-2470.sql | 22 + contrib/test/JDBC/input/BABEL-2482.sql | 28 + contrib/test/JDBC/input/BABEL-2485.sql | 74 + contrib/test/JDBC/input/BABEL-2513.sql | 354 + contrib/test/JDBC/input/BABEL-2514.sql | 128 + contrib/test/JDBC/input/BABEL-2515.sql | 32 + contrib/test/JDBC/input/BABEL-2535.sql | 177 + contrib/test/JDBC/input/BABEL-2569.sql | 17 + contrib/test/JDBC/input/BABEL-2576.sql | 67 + contrib/test/JDBC/input/BABEL-2585.sql | 178 + contrib/test/JDBC/input/BABEL-2593.sql | 48 + contrib/test/JDBC/input/BABEL-2596.sql | 41 + contrib/test/JDBC/input/BABEL-2602.mix | 20 + contrib/test/JDBC/input/BABEL-2604.sql | 86 + contrib/test/JDBC/input/BABEL-2607.sql | 35 + contrib/test/JDBC/input/BABEL-2622.mix | 27 + contrib/test/JDBC/input/BABEL-2647.sql | 13 + contrib/test/JDBC/input/BABEL-265.sql | 56 + contrib/test/JDBC/input/BABEL-2659.sql | 50 + contrib/test/JDBC/input/BABEL-2674.sql | 55 + contrib/test/JDBC/input/BABEL-2676.sql | 23 + contrib/test/JDBC/input/BABEL-2681.sql | 9 + contrib/test/JDBC/input/BABEL-2706.sql | 20 + contrib/test/JDBC/input/BABEL-2724.sql | 41 + contrib/test/JDBC/input/BABEL-2725.sql | 42 + contrib/test/JDBC/input/BABEL-338.sql | 126 + contrib/test/JDBC/input/BABEL-388.sql | 65 + contrib/test/JDBC/input/BABEL-405.sql | 200 + contrib/test/JDBC/input/BABEL-407.sql | 20 + contrib/test/JDBC/input/BABEL-453.sql | 117 + contrib/test/JDBC/input/BABEL-480.sql | 17 + contrib/test/JDBC/input/BABEL-493.sql | 70 + contrib/test/JDBC/input/BABEL-559.sql | 35 + contrib/test/JDBC/input/BABEL-565.sql | 37 + contrib/test/JDBC/input/BABEL-586.sql | 99 + contrib/test/JDBC/input/BABEL-588.sql | 1072 + contrib/test/JDBC/input/BABEL-597.sql | 6 + contrib/test/JDBC/input/BABEL-604.sql | 20 + contrib/test/JDBC/input/BABEL-625.sql | 9 + contrib/test/JDBC/input/BABEL-627.sql | 10 + contrib/test/JDBC/input/BABEL-637.sql | 734 + contrib/test/JDBC/input/BABEL-646.sql | 77 + contrib/test/JDBC/input/BABEL-662.sql | 71 + contrib/test/JDBC/input/BABEL-672.sql | 5 + contrib/test/JDBC/input/BABEL-694.sql | 24 + contrib/test/JDBC/input/BABEL-701.sql | 12 + contrib/test/JDBC/input/BABEL-708.sql | 190 + contrib/test/JDBC/input/BABEL-719.sql | 54 + contrib/test/JDBC/input/BABEL-728.sql | 248 + contrib/test/JDBC/input/BABEL-735.sql | 185 + contrib/test/JDBC/input/BABEL-741.sql | 39 + contrib/test/JDBC/input/BABEL-758.sql | 101 + contrib/test/JDBC/input/BABEL-768.sql | 88 + contrib/test/JDBC/input/BABEL-775.sql | 42 + contrib/test/JDBC/input/BABEL-776.sql | 74 + contrib/test/JDBC/input/BABEL-785.sql | 115 + contrib/test/JDBC/input/BABEL-788.sql | 91 + contrib/test/JDBC/input/BABEL-798.sql | 9 + contrib/test/JDBC/input/BABEL-807.sql | 9 + contrib/test/JDBC/input/BABEL-820.sql | 21 + contrib/test/JDBC/input/BABEL-872.sql | 21 + contrib/test/JDBC/input/BABEL-909.sql | 30 + contrib/test/JDBC/input/BABEL-911.sql | 11 + contrib/test/JDBC/input/BABEL-931.sql | 51 + contrib/test/JDBC/input/BABEL-941.sql | 43 + contrib/test/JDBC/input/BABEL-955.sql | 50 + contrib/test/JDBC/input/BABEL-APPLOCK.sql | 136 + .../test/JDBC/input/BABEL-COLUMN-ALIAS.sql | 114 + .../JDBC/input/BABEL-COLUMN-CONSTRAINT.sql | 57 + .../JDBC/input/BABEL-DATABASEPROPERTYEX.sql | 21 + .../JDBC/input/BABEL-EXTENDEDPROPERTY.sql | 17 + contrib/test/JDBC/input/BABEL-GUC-PLAN.sql | 213 + .../test/JDBC/input/BABEL-IDENTITY-BIFS.sql | 346 + .../test/JDBC/input/BABEL-IDENTITY-COLUMN.sql | 123 + contrib/test/JDBC/input/BABEL-IDENTITY.sql | 270 + .../input/BABEL-IMPLICIT_TRAN-PREPEXEC.txt | 40 + .../test/JDBC/input/BABEL-IMPLICIT_TRAN.sql | 232 + .../test/JDBC/input/BABEL-INSERT-EXECUTE.sql | 272 + contrib/test/JDBC/input/BABEL-LIKE2ILIKE.sql | 96 + .../test/JDBC/input/BABEL-LOGIN-USER-EXT.mix | 289 + .../JDBC/input/BABEL-OBJECT-FUNCTIONS.sql | 25 + contrib/test/JDBC/input/BABEL-PROCID.sql | 198 + contrib/test/JDBC/input/BABEL-RAND.sql | 29 + .../test/JDBC/input/BABEL-RECURSIVE-CTE.sql | 85 + contrib/test/JDBC/input/BABEL-ROWCOUNT.sql | 112 + .../test/JDBC/input/BABEL-SCHEMABINDING.sql | 64 + contrib/test/JDBC/input/BABEL-SEQUENCE.sql | 300 + .../test/JDBC/input/BABEL-SERVERPROPERTY.sql | 17 + contrib/test/JDBC/input/BABEL-SET-COMMAND.sql | 52 + contrib/test/JDBC/input/BABEL-SPCOLUMNS.sql | 56 + contrib/test/JDBC/input/BABEL-SPCURSOR.sql | 226 + .../test/JDBC/input/BABEL-SP_DATABASES.sql | 24 + .../JDBC/input/BABEL-SP_DATATYPE_INFO.sql | 9 + .../BABEL-SP_DESCRIBE_FRIST_RESULT_SET.sql | 17 + contrib/test/JDBC/input/BABEL-SP_PKEYS.sql | 46 + .../test/JDBC/input/BABEL-SP_STATISTICS.sql | 71 + contrib/test/JDBC/input/BABEL-SP_TABLES.sql | 55 + .../JDBC/input/BABEL-SQL-CONFIG-FUNCTIONS.sql | 2 + contrib/test/JDBC/input/BABEL-SQUARE.sql | 40 + .../test/JDBC/input/BABEL-SYS-DATABASES.mix | 26 + contrib/test/JDBC/input/BABEL-SYSCHARSETS.sql | 5 + contrib/test/JDBC/input/BABEL-SYS_COLUMNS.sql | 37 + contrib/test/JDBC/input/BABEL-TABLEHINT.sql | 84 + contrib/test/JDBC/input/BABEL-TARGETLIST.sql | 16 + contrib/test/JDBC/input/BABEL-UNSUPPORTED.sql | 1512 ++ contrib/test/JDBC/input/BABEL_2429.sql | 30 + contrib/test/JDBC/input/Babel-2655.sql | 26 + .../test/JDBC/input/ErrorMapping/102_1.sql | 316 + .../test/JDBC/input/ErrorMapping/102_2.sql | 326 + .../test/JDBC/input/ErrorMapping/102_3.sql | 326 + .../test/JDBC/input/ErrorMapping/102_6.sql | 316 + .../test/JDBC/input/ErrorMapping/1034_1.sql | 54 + .../test/JDBC/input/ErrorMapping/1049_1.sql | 323 + .../test/JDBC/input/ErrorMapping/1051_1.sql | 58 + .../test/JDBC/input/ErrorMapping/10610_1.sql | 267 + .../test/JDBC/input/ErrorMapping/113_1.sql | 207 + .../test/JDBC/input/ErrorMapping/11700_1.sql | 189 + .../test/JDBC/input/ErrorMapping/11701_1.sql | 201 + .../test/JDBC/input/ErrorMapping/11702_1.sql | 260 + .../test/JDBC/input/ErrorMapping/11703_1.sql | 300 + .../test/JDBC/input/ErrorMapping/11703_2.sql | 300 + .../test/JDBC/input/ErrorMapping/11704_1.sql | 201 + .../test/JDBC/input/ErrorMapping/11704_2.sql | 219 + .../test/JDBC/input/ErrorMapping/11705_1.sql | 195 + .../test/JDBC/input/ErrorMapping/11706_1.sql | 213 + .../test/JDBC/input/ErrorMapping/11708_1.sql | 201 + .../test/JDBC/input/ErrorMapping/129_1.sql | 305 + .../test/JDBC/input/ErrorMapping/132_1.sql | 376 + .../test/JDBC/input/ErrorMapping/133_1.sql | 378 + .../test/JDBC/input/ErrorMapping/134_1.sql | 365 + .../test/JDBC/input/ErrorMapping/135_1.sql | 336 + .../test/JDBC/input/ErrorMapping/136_1.sql | 336 + .../test/JDBC/input/ErrorMapping/141_1.sql | 343 + .../test/JDBC/input/ErrorMapping/142_1.sql | 282 + .../test/JDBC/input/ErrorMapping/1505_1.sql | 211 + .../test/JDBC/input/ErrorMapping/16948_1.sql | 500 + .../test/JDBC/input/ErrorMapping/16950_1.sql | 322 + .../JDBC/input/ErrorMapping/1752_1750_2.sql | 201 + .../JDBC/input/ErrorMapping/1765_1750_1.sql | 303 + .../JDBC/input/ErrorMapping/1768_1750_1.sql | 291 + .../JDBC/input/ErrorMapping/1770_1750_1.sql | 201 + .../JDBC/input/ErrorMapping/1774_1750_1.sql | 249 + .../test/JDBC/input/ErrorMapping/180_1.sql | 4246 ++++ .../test/JDBC/input/ErrorMapping/180_2.sql | 4242 ++++ .../test/JDBC/input/ErrorMapping/1946_1.sql | 523 + .../test/JDBC/input/ErrorMapping/208_1.sql | 189 + .../test/JDBC/input/ErrorMapping/217_1.sql | 285 + .../test/JDBC/input/ErrorMapping/218_1.sql | 263 + .../test/JDBC/input/ErrorMapping/219_1.sql | 183 + .../test/JDBC/input/ErrorMapping/220_1.sql | 219 + .../test/JDBC/input/ErrorMapping/220_2.sql | 213 + .../test/JDBC/input/ErrorMapping/220_3.sql | 213 + .../test/JDBC/input/ErrorMapping/220_4.sql | 213 + .../test/JDBC/input/ErrorMapping/222_1.sql | 195 + .../test/JDBC/input/ErrorMapping/257_2.sql | 195 + .../test/JDBC/input/ErrorMapping/2732_1.sql | 282 + .../test/JDBC/input/ErrorMapping/2747_1.sql | 300 + .../test/JDBC/input/ErrorMapping/2760_1.sql | 186 + .../test/JDBC/input/ErrorMapping/2787_1.sql | 282 + .../test/JDBC/input/ErrorMapping/2812_1.sql | 177 + .../test/JDBC/input/ErrorMapping/2812_2.sql | 177 + .../test/JDBC/input/ErrorMapping/2812_3.sql | 177 + .../test/JDBC/input/ErrorMapping/293_1.sql | 378 + .../test/JDBC/input/ErrorMapping/3609_1.sql | 403 + .../test/JDBC/input/ErrorMapping/3701_3.sql | 189 + .../test/JDBC/input/ErrorMapping/3701_4.sql | 189 + .../test/JDBC/input/ErrorMapping/3701_5.sql | 189 + .../JDBC/input/ErrorMapping/3728_3727_1.sql | 225 + .../test/JDBC/input/ErrorMapping/3729_1.sql | 282 + .../test/JDBC/input/ErrorMapping/3902_1.sql | 189 + .../test/JDBC/input/ErrorMapping/3903_1.sql | 195 + .../test/JDBC/input/ErrorMapping/3930_1.sql | 271 + .../test/JDBC/input/ErrorMapping/4708_1.sql | 249 + .../test/JDBC/input/ErrorMapping/4712_1.sql | 243 + .../test/JDBC/input/ErrorMapping/4901_1.sql | 326 + .../test/JDBC/input/ErrorMapping/4920_1.sql | 243 + .../test/JDBC/input/ErrorMapping/4924_1.sql | 225 + .../test/JDBC/input/ErrorMapping/4924_2.sql | 225 + .../test/JDBC/input/ErrorMapping/4936_1.sql | 195 + .../test/JDBC/input/ErrorMapping/4936_2.sql | 213 + .../test/JDBC/input/ErrorMapping/512_1.sql | 207 + .../test/JDBC/input/ErrorMapping/515_1.sql | 201 + .../test/JDBC/input/ErrorMapping/517_1.sql | 282 + .../test/JDBC/input/ErrorMapping/545_1.sql | 261 + .../test/JDBC/input/ErrorMapping/550_1.sql | 279 + .../test/JDBC/input/ErrorMapping/556_1.sql | 468 + .../test/JDBC/input/ErrorMapping/6401_1.sql | 213 + .../test/JDBC/input/ErrorMapping/8106_1.sql | 314 + .../test/JDBC/input/ErrorMapping/8107_1.sql | 291 + .../test/JDBC/input/ErrorMapping/8143_1.sql | 201 + .../test/JDBC/input/ErrorMapping/8143_2.sql | 201 + .../test/JDBC/input/ErrorMapping/8152_1.sql | 207 + .../test/JDBC/input/ErrorMapping/8152_2.sql | 195 + .../test/JDBC/input/ErrorMapping/8159_1.sql | 40 + .../test/JDBC/input/ErrorMapping/8179_1.sql | 302 + .../test/JDBC/input/ErrorMapping/9809_1.sql | 292 + .../TestCompileTimeErrorWithDefaultBehave.sql | 190 + .../ErrorMapping/TestErrorHelperFunctions.sql | 23 + .../TestRunTimeErrorWithDefaultBehave.sql | 207 + contrib/test/JDBC/input/TestNotNull.txt | 260 + .../JDBC/input/authentication/TestAuth.txt | 18 + contrib/test/JDBC/input/babel_613.sql | 81 + contrib/test/JDBC/input/babel_bit_comp.sql | 94 + .../test/JDBC/input/babel_ceiling_floor.sql | 94 + contrib/test/JDBC/input/babel_char.sql | 18 + contrib/test/JDBC/input/babel_collation.sql | 31 + contrib/test/JDBC/input/babel_iif.sql | 35 + contrib/test/JDBC/input/babel_isnull.mix | 124 + contrib/test/JDBC/input/babel_money.sql | 199 + contrib/test/JDBC/input/babel_numeric.sql | 63 + contrib/test/JDBC/input/babel_operators.sql | 58 + contrib/test/JDBC/input/babel_print.sql | 39 + .../test/JDBC/input/babel_smalldatetime.sql | 102 + contrib/test/JDBC/input/babel_top.sql | 40 + contrib/test/JDBC/input/babel_trigger.sql | 329 + contrib/test/JDBC/input/babel_varbinary.sql | 86 + .../test/JDBC/input/cursors/BABEL-1390.txt | 19 + .../input/cursors/TestCursorFetchNext.txt | 89 + .../cursors/TestCursorPrepExecFetchNext.txt | 97 + contrib/test/JDBC/input/datatypes/TestBIT.txt | 16 + .../test/JDBC/input/datatypes/TestBigInt.txt | 24 + .../test/JDBC/input/datatypes/TestBinary.txt | 29 + .../test/JDBC/input/datatypes/TestChar.txt | 16 + .../test/JDBC/input/datatypes/TestDate.txt | 14 + .../JDBC/input/datatypes/TestDatetime.txt | 36 + .../JDBC/input/datatypes/TestDatetime2.txt | 15 + .../test/JDBC/input/datatypes/TestDecimal.txt | 180 + .../test/JDBC/input/datatypes/TestFloat.txt | 24 + contrib/test/JDBC/input/datatypes/TestInt.txt | 29 + .../test/JDBC/input/datatypes/TestMoney.txt | 30 + .../test/JDBC/input/datatypes/TestNumeric.txt | 228 + .../test/JDBC/input/datatypes/TestReal.txt | 24 + .../input/datatypes/TestSmallDatetime.txt | 35 + .../JDBC/input/datatypes/TestSmallInt.txt | 24 + .../test/JDBC/input/datatypes/TestText.txt | 10 + .../test/JDBC/input/datatypes/TestTime.txt | 104 + .../test/JDBC/input/datatypes/TestTinyInt.txt | 24 + contrib/test/JDBC/input/datatypes/TestUDD.txt | 79 + .../input/datatypes/TestUniqueIdentifier.txt | 34 + .../test/JDBC/input/datatypes/TestVarChar.txt | 48 + contrib/test/JDBC/input/datatypes/TestXML.txt | 11 + contrib/test/JDBC/input/ddl/temp-tables.sql | 303 + .../errorHandling/TestErrorFunctions.sql | 190 + .../errorHandling/TestErrorsWithTryCatch.sql | 979 + .../input/errorHandling/TestRaiserror.sql | 410 + .../errorHandling/TestRaiserrorFormat.sql | 53 + .../input/errorHandling/TestSimpleErrors.sql | 2532 +++ .../TestSimpleErrorsWithImplicitTran.txt | 9 + .../TestSimpleErrorsWithXactAbort.sql | 2379 +++ .../JDBC/input/errorHandling/TestThrow.sql | 382 + contrib/test/JDBC/input/forxml/TestForXML.sql | 250 + .../input/functions/sys-column-property.sql | 40 + .../JDBC/input/functions/sys-datefirst.sql | 11 + .../JDBC/input/functions/sys-lock_timeout.sql | 13 + .../input/functions/sys-max_connections.sql | 11 + .../input/functions/sys-original_login.sql | 2 + .../JDBC/input/functions/sys-schema-name.sql | 5 + .../input/functions/sys-trigger_nestlevel.sql | 34 + contrib/test/JDBC/input/insertbulk.txt | 275 + .../interoperability/TestBasicInterop.mix | 129 + .../TestInteropProcedures.mix | 161 + .../TestProcedureWithErrorHandling.mix | 292 + .../TestProcedureWithTransactions.mix | 457 + .../TestProcedureWithTriggers.mix | 597 + contrib/test/JDBC/input/pg_stat_activity.txt | 17 + .../JDBC/input/sqlBatch/TestSQLQueries.txt | 234 + .../input/storedProcedures/BABEL-1365.sql | 23 + .../storedProcedures/TestPrepareExec.txt | 15 + .../storedProcedures/TestSPExecutesql.sql | 194 + .../input/storedProcedures/TestSPPrepare.sql | 357 + .../storedProcedures/TestStoredProcedures.txt | 140 + .../test/JDBC/input/tds_faultinjection.txt | 33 + .../transactions/TestIsolationLevels.sql | 36 + .../transactions/TestTransactionName.sql | 70 + .../TestTransactionSupportForProcedure.txt | 260 + .../transactions/TestTransactionsSQLBatch.txt | 189 + .../JDBC/input/transactions/TestTriggers.sql | 197 + .../test/JDBC/input/views/sys-all_columns.sql | 21 + .../input/views/sys-check_constraints.sql | 16 + .../JDBC/input/views/sys-computed_columns.sql | 18 + .../test/JDBC/input/views/sys-databases.sql | 14 + .../input/views/sys-default_constraints.sql | 17 + .../input/views/sys-extended_properties.sql | 2 + .../JDBC/input/views/sys-index_columns.sql | 21 + contrib/test/JDBC/input/views/sys-indexes.sql | 41 + contrib/test/JDBC/input/views/sys-schemas.sql | 22 + .../input/views/sys-server_principals.sql | 23 + .../test/JDBC/input/views/sys-syscolumns.sql | 70 + contrib/test/JDBC/jdbc_schedule | 12 + contrib/test/JDBC/pom.xml | 87 + contrib/test/JDBC/sql_expected/1034_1.out | 71 + contrib/test/JDBC/sql_expected/1049_1.out | 406 + contrib/test/JDBC/sql_expected/1051_1.out | 75 + contrib/test/JDBC/sql_expected/10610_1.out | 311 + contrib/test/JDBC/sql_expected/11700_1.out | 232 + contrib/test/JDBC/sql_expected/11701_1.out | 245 + contrib/test/JDBC/sql_expected/11702_1.out | 331 + contrib/test/JDBC/sql_expected/11703_1.out | 371 + contrib/test/JDBC/sql_expected/11703_2.out | 371 + contrib/test/JDBC/sql_expected/11705_1.out | 239 + contrib/test/JDBC/sql_expected/11706_1.out | 257 + contrib/test/JDBC/sql_expected/11708_1.out | 245 + contrib/test/JDBC/sql_expected/132_1.out | 455 + contrib/test/JDBC/sql_expected/133_1.out | 457 + contrib/test/JDBC/sql_expected/134_1.out | 444 + contrib/test/JDBC/sql_expected/135_1.out | 415 + contrib/test/JDBC/sql_expected/136_1.out | 415 + contrib/test/JDBC/sql_expected/141_1.out | 426 + contrib/test/JDBC/sql_expected/142_1.out | 365 + contrib/test/JDBC/sql_expected/1505_1.out | 267 + contrib/test/JDBC/sql_expected/16948_1.out | 601 + contrib/test/JDBC/sql_expected/16950_1.out | 398 + .../test/JDBC/sql_expected/1752_1750_2.out | 236 + .../test/JDBC/sql_expected/1765_1750_1.out | 371 + .../test/JDBC/sql_expected/1768_1750_1.out | 335 + contrib/test/JDBC/sql_expected/180_1.out | 4259 ++++ contrib/test/JDBC/sql_expected/180_2.out | 4255 ++++ contrib/test/JDBC/sql_expected/1946_1.out | 598 + contrib/test/JDBC/sql_expected/217_1.out | 329 + contrib/test/JDBC/sql_expected/219_1.out | 227 + contrib/test/JDBC/sql_expected/220_1.out | 268 + contrib/test/JDBC/sql_expected/220_2.out | 262 + contrib/test/JDBC/sql_expected/220_3.out | 262 + contrib/test/JDBC/sql_expected/220_4.out | 262 + contrib/test/JDBC/sql_expected/2732_1.out | 358 + contrib/test/JDBC/sql_expected/2747_1.out | 379 + contrib/test/JDBC/sql_expected/2787_1.out | 363 + contrib/test/JDBC/sql_expected/293_1.out | 491 + contrib/test/JDBC/sql_expected/3609_1.out | 474 + contrib/test/JDBC/sql_expected/3701_3.out | 243 + contrib/test/JDBC/sql_expected/3701_4.out | 243 + contrib/test/JDBC/sql_expected/3701_5.out | 243 + .../test/JDBC/sql_expected/3728_3727_1.out | 305 + contrib/test/JDBC/sql_expected/3729_1.out | 326 + contrib/test/JDBC/sql_expected/3902_1.out | 261 + contrib/test/JDBC/sql_expected/3903_1.out | 267 + contrib/test/JDBC/sql_expected/3930_1.out | 330 + contrib/test/JDBC/sql_expected/4708_1.out | 293 + contrib/test/JDBC/sql_expected/4712_1.out | 311 + contrib/test/JDBC/sql_expected/4901_1.out | 423 + contrib/test/JDBC/sql_expected/4920_1.out | 287 + contrib/test/JDBC/sql_expected/512_1.out | 276 + contrib/test/JDBC/sql_expected/515_1.out | 250 + contrib/test/JDBC/sql_expected/517_1.out | 374 + contrib/test/JDBC/sql_expected/545_1.out | 310 + contrib/test/JDBC/sql_expected/550_1.out | 328 + contrib/test/JDBC/sql_expected/556_1.out | 591 + contrib/test/JDBC/sql_expected/6401_1.out | 275 + contrib/test/JDBC/sql_expected/8106_1.out | 389 + contrib/test/JDBC/sql_expected/8107_1.out | 347 + contrib/test/JDBC/sql_expected/8143_1.out | 250 + contrib/test/JDBC/sql_expected/8143_2.out | 250 + contrib/test/JDBC/sql_expected/8152_1.out | 256 + contrib/test/JDBC/sql_expected/8152_2.out | 244 + contrib/test/JDBC/sql_expected/8159_1.out | 61 + contrib/test/JDBC/sql_expected/8179_1.out | 378 + contrib/test/JDBC/sql_expected/9809_1.out | 384 + contrib/test/JDBC/sql_expected/BABEL-1243.out | 33 + contrib/test/JDBC/sql_expected/BABEL-1944.out | 312 + contrib/test/JDBC/sql_expected/BABEL-2079.out | 50 + contrib/test/JDBC/sql_expected/BABEL-2354.out | 23 + contrib/test/JDBC/sql_expected/BABEL-2419.out | 37 + contrib/test/JDBC/sql_expected/BABEL-2432.out | 51 + contrib/test/JDBC/sql_expected/BABEL-2437.out | 16 + contrib/test/JDBC/sql_expected/BABEL-2681.out | 29 + .../sql_expected/BABEL-EXTENDEDPROPERTY.out | 29 + .../test/JDBC/sql_expected/BABEL-IDENTITY.out | 458 + .../BABEL-IMPLICIT_TRAN-PREPEXEC.out | 128 + .../JDBC/sql_expected/BABEL-IMPLICIT_TRAN.out | 564 + contrib/test/JDBC/sql_expected/TestAuth.out | 49 + .../sql_expected/TestErrorsWithTryCatch.out | 1702 ++ .../JDBC/sql_expected/TestSimpleErrors.out | 4844 +++++ .../TestSimpleErrorsWithImplicitTran.out | 4918 +++++ .../TestSimpleErrorsWithXactAbort.out | 4022 ++++ .../test/JDBC/sql_expected/TestTriggers.out | 391 + .../JDBC/sql_expected/sys-all_columns.out | 33 + .../sql_expected/sys-check_constraints.out | 26 + .../sql_expected/sys-computed_columns.out | 28 + .../test/JDBC/sql_expected/sys-databases.out | 24 + .../sql_expected/sys-default_constraints.out | 27 + .../sql_expected/sys-extended_properties.out | 7 + .../JDBC/sql_expected/sys-index_columns.out | 31 + .../test/JDBC/sql_expected/sys-indexes.out | 69 + .../test/JDBC/sql_expected/sys-schemas.out | 44 + .../sql_expected/sys-server_principals.out | 44 + .../test/JDBC/sql_expected/temp-tables.out | 431 + .../java/com/sqlsamples/CompareResults.java | 296 + .../src/main/java/com/sqlsamples/Config.java | 145 + .../java/com/sqlsamples/ExportResults.java | 33 + .../java/com/sqlsamples/HandleException.java | 55 + .../com/sqlsamples/JDBCAuthentication.java | 85 + .../java/com/sqlsamples/JDBCBulkCopy.java | 47 + .../com/sqlsamples/JDBCCallableStatement.java | 196 + .../java/com/sqlsamples/JDBCCrossDialect.java | 170 + .../main/java/com/sqlsamples/JDBCCursor.java | 192 + .../com/sqlsamples/JDBCPreparedStatement.java | 191 + .../java/com/sqlsamples/JDBCStatement.java | 53 + .../java/com/sqlsamples/JDBCTransaction.java | 121 + .../main/java/com/sqlsamples/Statistics.java | 34 + .../main/java/com/sqlsamples/batch_run.java | 294 + .../test/JDBC/src/main/resources/config.txt | 40 + .../main/resources/junit-platform.properties | 2 + .../java/com/sqlsamples/TestQueryFile.java | 356 + contrib/test/JDBC/utils/Blank.jpeg | Bin 0 -> 631 bytes .../test/JDBC/utils/TxnErrorHandingCases.py | 597 + contrib/test/JDBC/utils/blank.txt | 0 contrib/test/JDBC/utils/devanagari.txt | 1 + contrib/test/JDBC/utils/emojisText.txt | 1 + contrib/test/JDBC/utils/flower.jpg | Bin 0 -> 3572 bytes contrib/test/JDBC/utils/sample.txt | 6 + contrib/test/JDBC/utils/utf16.txt | 1 + .../ScalarFunctionsSQLBatch.out | 79 + .../ExpectedOutput/TestAuthentication.out | 46 + .../test/dotnet/ExpectedOutput/TestBIT.out | 21 + .../test/dotnet/ExpectedOutput/TestBigInt.out | 56 + .../test/dotnet/ExpectedOutput/TestBinary.out | 9 + .../test/dotnet/ExpectedOutput/TestChar.out | 38 + .../test/dotnet/ExpectedOutput/TestDate.out | 31 + .../dotnet/ExpectedOutput/TestDatetime.out | 86 + .../dotnet/ExpectedOutput/TestDatetime2.out | 22 + .../dotnet/ExpectedOutput/TestDecimal.out | 208 + .../test/dotnet/ExpectedOutput/TestFloat.out | 56 + .../test/dotnet/ExpectedOutput/TestInt.out | 59 + .../test/dotnet/ExpectedOutput/TestMoney.out | 55 + .../dotnet/ExpectedOutput/TestNumeric.out | 196 + .../dotnet/ExpectedOutput/TestPrepareExec.out | 32 + .../test/dotnet/ExpectedOutput/TestReal.out | 56 + .../dotnet/ExpectedOutput/TestSQLQueries.out | 257 + .../ExpectedOutput/TestSmallDatetime.out | 84 + .../dotnet/ExpectedOutput/TestSmallInt.out | 56 + .../dotnet/ExpectedOutput/TestSqlVariant.out | 77 + .../ExpectedOutput/TestStoredProcedure.out | 387 + .../test/dotnet/ExpectedOutput/TestText.out | 25 + .../test/dotnet/ExpectedOutput/TestTime.out | 140 + .../dotnet/ExpectedOutput/TestTinyInt.out | 56 + .../ExpectedOutput/TestTransactions.out | 263 + .../TestTransactionsSQLBatch.out | 322 + .../test/dotnet/ExpectedOutput/TestTvp.out | 6 + .../test/dotnet/ExpectedOutput/TestUDD.out | 51 + .../test/dotnet/ExpectedOutput/TestUID.out | 89 + .../dotnet/ExpectedOutput/TestVarChar.out | 10 + .../test/dotnet/ExpectedOutput/TestXML.out | 17 + contrib/test/dotnet/Info/.gitignore | 4 + contrib/test/dotnet/Output/.gitignore | 4 + contrib/test/dotnet/ReadMe.txt | 78 + contrib/test/dotnet/config.txt | 25 + contrib/test/dotnet/dotnet.csproj | 26 + .../Authentication/TestAuthentication.txt | 60 + .../test/dotnet/input/Datatypes/TestBIT.txt | 16 + .../dotnet/input/Datatypes/TestBigInt.txt | 24 + .../dotnet/input/Datatypes/TestBinary.txt | 28 + .../test/dotnet/input/Datatypes/TestChar.txt | 17 + .../test/dotnet/input/Datatypes/TestDate.txt | 18 + .../dotnet/input/Datatypes/TestDatetime.txt | 36 + .../dotnet/input/Datatypes/TestDatetime2.txt | 15 + .../dotnet/input/Datatypes/TestDecimal.txt | 158 + .../test/dotnet/input/Datatypes/TestFloat.txt | 24 + .../test/dotnet/input/Datatypes/TestInt.txt | 29 + .../test/dotnet/input/Datatypes/TestMoney.txt | 30 + .../dotnet/input/Datatypes/TestNumeric.txt | 178 + .../test/dotnet/input/Datatypes/TestReal.txt | 24 + .../input/Datatypes/TestSmallDatetime.txt | 35 + .../dotnet/input/Datatypes/TestSmallInt.txt | 24 + .../dotnet/input/Datatypes/TestSqlVariant.txt | 41 + .../test/dotnet/input/Datatypes/TestText.txt | 12 + .../test/dotnet/input/Datatypes/TestTime.txt | 104 + .../dotnet/input/Datatypes/TestTinyInt.txt | 24 + .../test/dotnet/input/Datatypes/TestTvp.txt | 5 + .../test/dotnet/input/Datatypes/TestUDD.txt | 78 + .../test/dotnet/input/Datatypes/TestUID.txt | 36 + .../dotnet/input/Datatypes/TestVarChar.txt | 6 + .../test/dotnet/input/Datatypes/TestXML.txt | 8 + .../input/PrepareExec/TestPrepareExec.txt | 61 + .../dotnet/input/SQLBatch/TestSQLQueries.txt | 222 + .../ScalarFunctionsSQLBatch.txt | 59 + .../input/Storedproc/TestStoredProcedure.txt | 213 + .../input/Transaction/TestTransactions.txt | 189 + .../Transaction/TestTransactionsSQLBatch.txt | 189 + contrib/test/dotnet/src/BatchRun.cs | 383 + contrib/test/dotnet/src/ExecuteTests.cs | 130 + contrib/test/dotnet/src/PrepareExecBinding.cs | 453 + contrib/test/dotnet/utils/ConfigSetup.cs | 68 + contrib/test/dotnet/utils/TestUtils.cs | 563 + contrib/test/dotnet/utils/devanagari.txt | 1 + contrib/test/dotnet/utils/emojisText.txt | 1 + contrib/test/dotnet/utils/sample.txt | 6 + contrib/test/dotnet/utils/utf16.txt | 1 + contrib/test/odbc/CMakeLists.txt | 48 + contrib/test/odbc/README.md | 54 + contrib/test/odbc/config.txt | 6 + contrib/test/odbc/constants.cpp | 19 + contrib/test/odbc/constants.h | 34 + contrib/test/odbc/database_objects.cpp | 82 + contrib/test/odbc/database_objects.h | 54 + contrib/test/odbc/main.cpp | 8 + contrib/test/odbc/odbc_handler.cpp | 311 + contrib/test/odbc/odbc_handler.h | 138 + contrib/test/odbc/query_generator.cpp | 124 + contrib/test/odbc/query_generator.h | 67 + contrib/test/odbc/test_connection.cpp | 29 + contrib/test/odbc/test_data_types.cpp | 457 + contrib/test/odbc/test_diagnostics.cpp | 140 + .../odbc/test_direct_executed_statements.cpp | 268 + contrib/test/odbc/test_metadata.cpp | 949 + .../test/odbc/test_prepared_statements.cpp | 367 + contrib/test/odbc/test_resultset.cpp | 760 + contrib/test/odbc/test_sqlgetinfo.cpp | 146 + contrib/test/odbc/test_transactions.cpp | 129 + contrib/test/odbc/utils/blank.txt | 0 contrib/test/odbc/utils/devanagari.txt | 1 + contrib/test/odbc/utils/sample.txt | 6 + contrib/test/python/batch_run.py | 94 + contrib/test/python/compare_results.py | 139 + contrib/test/python/config.txt | 44 + contrib/test/python/execute_query.py | 376 + .../python/expected/pymssql/BABEL-1056.out | 23 + .../python/expected/pymssql/BABEL-1270.out | 14 + .../python/expected/pymssql/BABEL-1365.out | 52 + .../python/expected/pymssql/BABEL-1390.out | 25 + .../python/expected/pymssql/BABEL-1643.out | 18 + .../test/python/expected/pymssql/TestAuth.out | 4 + .../test/python/expected/pymssql/TestBIT.out | 49 + .../python/expected/pymssql/TestBigInt.out | 106 + .../python/expected/pymssql/TestBinary.out | 49 + .../test/python/expected/pymssql/TestChar.out | 64 + .../expected/pymssql/TestCursorFetchNext.out | 83 + .../pymssql/TestCursorPrepExecFetchNext.out | 83 + .../test/python/expected/pymssql/TestDate.out | 61 + .../python/expected/pymssql/TestDatetime.out | 160 + .../python/expected/pymssql/TestDatetime2.out | 45 + .../python/expected/pymssql/TestDecimal.out | 564 + .../python/expected/pymssql/TestFloat.out | 106 + .../test/python/expected/pymssql/TestInt.out | 115 + .../python/expected/pymssql/TestMoney.out | 115 + .../python/expected/pymssql/TestNumeric.out | 606 + .../test/python/expected/pymssql/TestReal.out | 106 + .../expected/pymssql/TestSPExecutesql.out | 253 + .../python/expected/pymssql/TestSPPrepare.out | 601 + .../expected/pymssql/TestSQLQueries.out | 897 + .../TestSimpleErrorsWithImplicitTran.out | 20 + .../expected/pymssql/TestSmallDatetime.out | 152 + .../python/expected/pymssql/TestSmallInt.out | 106 + .../expected/pymssql/TestStoredProcedures.out | 185 + .../test/python/expected/pymssql/TestText.out | 34 + .../test/python/expected/pymssql/TestTime.out | 265 + .../python/expected/pymssql/TestTinyInt.out | 105 + .../TestTransactionSupportForProcedure.out | 1096 + .../pymssql/TestTransactionsSQLBatch.out | 564 + .../test/python/expected/pymssql/TestUDD.out | 132 + .../expected/pymssql/TestUniqueIdentifier.out | 157 + .../python/expected/pymssql/TestVarChar.out | 168 + .../test/python/expected/pymssql/TestXML.out | 30 + .../expected/pymssql/pg_stat_activity.out | 79 + .../python/expected/pyodbc/BABEL-1056.out | 27 + .../python/expected/pyodbc/BABEL-1270.out | 14 + .../python/expected/pyodbc/BABEL-1365.out | 46 + .../python/expected/pyodbc/BABEL-1390.out | 25 + .../python/expected/pyodbc/BABEL-1643.out | 14 + .../test/python/expected/pyodbc/TestAuth.out | 34 + .../test/python/expected/pyodbc/TestBIT.out | 44 + .../python/expected/pyodbc/TestBigInt.out | 102 + .../python/expected/pyodbc/TestBinary.out | 43 + .../test/python/expected/pyodbc/TestChar.out | 60 + .../expected/pyodbc/TestCursorFetchNext.out | 83 + .../pyodbc/TestCursorPrepExecFetchNext.out | 83 + .../test/python/expected/pyodbc/TestDate.out | 56 + .../python/expected/pyodbc/TestDatetime.out | 156 + .../python/expected/pyodbc/TestDatetime2.out | 43 + .../python/expected/pyodbc/TestDecimal.out | 546 + .../test/python/expected/pyodbc/TestFloat.out | 102 + .../test/python/expected/pyodbc/TestInt.out | 111 + .../test/python/expected/pyodbc/TestMoney.out | 111 + .../python/expected/pyodbc/TestNumeric.out | 578 + .../test/python/expected/pyodbc/TestReal.out | 102 + .../expected/pyodbc/TestSPExecutesql.out | 243 + .../python/expected/pyodbc/TestSPPrepare.out | 567 + .../python/expected/pyodbc/TestSQLQueries.out | 839 + .../TestSimpleErrorsWithImplicitTran.out | 20 + .../expected/pyodbc/TestSmallDatetime.out | 148 + .../python/expected/pyodbc/TestSmallInt.out | 102 + .../expected/pyodbc/TestStoredProcedures.out | 181 + .../test/python/expected/pyodbc/TestText.out | 32 + .../test/python/expected/pyodbc/TestTime.out | 300 + .../python/expected/pyodbc/TestTinyInt.out | 101 + .../TestTransactionSupportForProcedure.out | 928 + .../pyodbc/TestTransactionsSQLBatch.out | 492 + .../test/python/expected/pyodbc/TestUDD.out | 128 + .../expected/pyodbc/TestUniqueIdentifier.out | 151 + .../python/expected/pyodbc/TestVarChar.out | 158 + .../test/python/expected/pyodbc/TestXML.out | 28 + .../expected/pyodbc/pg_stat_activity.out | 65 + contrib/test/python/file_handler.py | 146 + contrib/test/python/input/BABEL-1056.txt | 14 + contrib/test/python/input/BABEL-1270.txt | 12 + .../TestSimpleErrorsWithImplicitTran.txt | 11 + .../python/input/authentication/TestAuth.txt | 13 + .../test/python/input/cursors/BABEL-1390.txt | 15 + .../input/cursors/TestCursorFetchNext.txt | 86 + .../cursors/TestCursorPrepExecFetchNext.txt | 94 + .../python/input/datatypes/BABEL-1643.txt | 3 + .../test/python/input/datatypes/TestBIT.txt | 16 + .../python/input/datatypes/TestBigInt.txt | 24 + .../python/input/datatypes/TestBinary.txt | 19 + .../test/python/input/datatypes/TestChar.txt | 16 + .../test/python/input/datatypes/TestDate.txt | 14 + .../python/input/datatypes/TestDatetime.txt | 36 + .../python/input/datatypes/TestDatetime2.txt | 15 + .../python/input/datatypes/TestDecimal.txt | 180 + .../test/python/input/datatypes/TestFloat.txt | 24 + .../test/python/input/datatypes/TestInt.txt | 29 + .../test/python/input/datatypes/TestMoney.txt | 30 + .../python/input/datatypes/TestNumeric.txt | 187 + .../test/python/input/datatypes/TestReal.txt | 24 + .../input/datatypes/TestSmallDatetime.txt | 35 + .../python/input/datatypes/TestSmallInt.txt | 24 + .../test/python/input/datatypes/TestText.txt | 10 + .../test/python/input/datatypes/TestTime.txt | 104 + .../python/input/datatypes/TestTinyInt.txt | 24 + .../test/python/input/datatypes/TestUDD.txt | 78 + .../input/datatypes/TestUniqueIdentifier.txt | 34 + .../python/input/datatypes/TestVarChar.txt | 48 + .../test/python/input/datatypes/TestXML.txt | 11 + .../test/python/input/pg_stat_activity.txt | 20 + .../python/input/sqlBatch/TestSQLQueries.txt | 232 + .../input/storedProcedures/BABEL-1365.sql | 23 + .../storedProcedures/TestSPExecutesql.sql | 194 + .../input/storedProcedures/TestSPPrepare.sql | 357 + .../storedProcedures/TestStoredProcedures.txt | 140 + .../TestTransactionSupportForProcedure.txt | 260 + .../transactions/TestTransactionsSQLBatch.txt | 189 + contrib/test/python/logs/.gitignore | 4 + contrib/test/python/output/pymssql/.gitkeep | 0 contrib/test/python/output/pyodbc/.gitkeep | 0 contrib/test/python/python_authentication.py | 47 + .../test/python/sql_expected/pymssql/.gitkeep | 0 .../test/python/sql_expected/pyodbc/.gitkeep | 0 contrib/test/python/start.py | 24 + contrib/test/python/test_main.py | 71 + contrib/test/python/utils/__init__.py | 0 contrib/test/python/utils/base.py | 57 + contrib/test/python/utils/blank.txt | 0 contrib/test/python/utils/config.py | 28 + contrib/test/python/utils/db_client.py | 106 + contrib/test/python/utils/devanagari.txt | 1 + contrib/test/python/utils/emojisText.txt | 1 + contrib/test/python/utils/sample.txt | 6 + contrib/test/python/utils/utf16.txt | 1 + 1452 files changed, 383287 insertions(+), 35 deletions(-) create mode 100644 .github/workflows/jdbc_unit_tests.yml delete mode 100644 .github/workflows/main.yml create mode 100644 INSTALLING create mode 100644 contrib/babelfishpg_common/Makefile create mode 100644 contrib/babelfishpg_common/Version.config create mode 100644 contrib/babelfishpg_common/babelfishpg_common.control.in create mode 100644 contrib/babelfishpg_common/sql/babelfishpg_common--1.0.0.sql create mode 100644 contrib/babelfishpg_common/sql/babelfishpg_common.in create mode 100644 contrib/babelfishpg_common/sql/binary.sql create mode 100644 contrib/babelfishpg_common/sql/bit.sql create mode 100644 contrib/babelfishpg_common/sql/bpchar.sql create mode 100644 contrib/babelfishpg_common/sql/coerce.sql create mode 100644 contrib/babelfishpg_common/sql/datetime.sql create mode 100644 contrib/babelfishpg_common/sql/datetime2.sql create mode 100644 contrib/babelfishpg_common/sql/datetimeoffset.sql create mode 100755 contrib/babelfishpg_common/sql/money/fixeddecimal--1.1.0_base_parallel.sql create mode 100644 contrib/babelfishpg_common/sql/money/fixeddecimal--brin.sql create mode 100644 contrib/babelfishpg_common/sql/money/fixeddecimal--parallelaggs.sql create mode 100644 contrib/babelfishpg_common/sql/numerics.sql create mode 100644 contrib/babelfishpg_common/sql/smalldatetime.sql create mode 100644 contrib/babelfishpg_common/sql/sqlvariant.sql create mode 100644 contrib/babelfishpg_common/sql/string_operators.sql create mode 100644 contrib/babelfishpg_common/sql/strings.sql create mode 100644 contrib/babelfishpg_common/sql/uniqueidentifier.sql create mode 100644 contrib/babelfishpg_common/sql/upgrades/Release.md create mode 100644 contrib/babelfishpg_common/sql/upgrades/babelfishpg_common--1.0.0--1.1.0.sql create mode 100644 contrib/babelfishpg_common/sql/utils.sql create mode 100644 contrib/babelfishpg_common/sql/varbinary.sql create mode 100644 contrib/babelfishpg_common/sql/varchar.sql create mode 100644 contrib/babelfishpg_common/src/babelfishpg_common.c create mode 100644 contrib/babelfishpg_common/src/bit.c create mode 100644 contrib/babelfishpg_common/src/coerce.c create mode 100644 contrib/babelfishpg_common/src/datetime.c create mode 100644 contrib/babelfishpg_common/src/datetime.h create mode 100644 contrib/babelfishpg_common/src/datetime2.c create mode 100644 contrib/babelfishpg_common/src/datetime2.h create mode 100644 contrib/babelfishpg_common/src/datetimeoffset.c create mode 100644 contrib/babelfishpg_common/src/datetimeoffset.h create mode 100644 contrib/babelfishpg_common/src/instr.c create mode 100644 contrib/babelfishpg_common/src/instr.h create mode 100644 contrib/babelfishpg_common/src/numeric.c create mode 100644 contrib/babelfishpg_common/src/numeric.h create mode 100644 contrib/babelfishpg_common/src/smalldatetime.c create mode 100644 contrib/babelfishpg_common/src/sqlvariant.c create mode 100644 contrib/babelfishpg_common/src/typecode.c create mode 100644 contrib/babelfishpg_common/src/typecode.h create mode 100644 contrib/babelfishpg_common/src/uniqueidentifier.c create mode 100644 contrib/babelfishpg_common/src/varbinary.c create mode 100644 contrib/babelfishpg_common/src/varchar.c create mode 100755 contrib/babelfishpg_money/Makefile create mode 100755 contrib/babelfishpg_money/README.md create mode 100755 contrib/babelfishpg_money/babelfishpg_money.control create mode 100644 contrib/babelfishpg_money/fixeddecimal--1.0.0--1.1.0.sql create mode 100755 contrib/babelfishpg_money/fixeddecimal--1.0.0_base.sql create mode 100755 contrib/babelfishpg_money/fixeddecimal--1.1.0_base.sql create mode 100755 contrib/babelfishpg_money/fixeddecimal--1.1.0_base_parallel.sql create mode 100644 contrib/babelfishpg_money/fixeddecimal--aggs.sql create mode 100644 contrib/babelfishpg_money/fixeddecimal--brin.sql create mode 100644 contrib/babelfishpg_money/fixeddecimal--parallelaggs.sql create mode 100644 contrib/babelfishpg_money/fixeddecimal--xlaggs.sql create mode 100755 contrib/babelfishpg_money/fixeddecimal.c create mode 100644 contrib/babelfishpg_money/fixeddecimalaggstate.sql create mode 100755 contrib/babelfishpg_money/test/expected/aggregate.out create mode 100644 contrib/babelfishpg_money/test/expected/brin-xl.out create mode 100644 contrib/babelfishpg_money/test/expected/brin.out create mode 100755 contrib/babelfishpg_money/test/expected/cast.out create mode 100755 contrib/babelfishpg_money/test/expected/comparison.out create mode 100644 contrib/babelfishpg_money/test/expected/index-xl.out create mode 100644 contrib/babelfishpg_money/test/expected/index.out create mode 100755 contrib/babelfishpg_money/test/expected/overflow.out create mode 100755 contrib/babelfishpg_money/test/sql/aggregate.sql create mode 100644 contrib/babelfishpg_money/test/sql/brin-xl.sql create mode 100644 contrib/babelfishpg_money/test/sql/brin.sql create mode 100755 contrib/babelfishpg_money/test/sql/cast.sql create mode 100755 contrib/babelfishpg_money/test/sql/comparison.sql create mode 100644 contrib/babelfishpg_money/test/sql/index-xl.sql create mode 100644 contrib/babelfishpg_money/test/sql/index.sql create mode 100755 contrib/babelfishpg_money/test/sql/overflow.sql create mode 100644 contrib/babelfishpg_tds/Makefile create mode 100644 contrib/babelfishpg_tds/README create mode 100644 contrib/babelfishpg_tds/README.err create mode 100644 contrib/babelfishpg_tds/babelfishpg_tds--1.0.0.sql create mode 100644 contrib/babelfishpg_tds/babelfishpg_tds.control create mode 100644 contrib/babelfishpg_tds/error_mapping.txt create mode 100644 contrib/babelfishpg_tds/generate_error_mapping.pl create mode 100644 contrib/babelfishpg_tds/src/backend/encoding/encoding_utils.c create mode 100644 contrib/babelfishpg_tds/src/backend/fault_injection/fault_injection.c create mode 100644 contrib/babelfishpg_tds/src/backend/fault_injection/fault_injection_tests.c create mode 100644 contrib/babelfishpg_tds/src/backend/tds/err_handler.c create mode 100644 contrib/babelfishpg_tds/src/backend/tds/guc.c create mode 100644 contrib/babelfishpg_tds/src/backend/tds/support_funcs.c create mode 100644 contrib/babelfishpg_tds/src/backend/tds/tds-secure-openssl.c create mode 100644 contrib/babelfishpg_tds/src/backend/tds/tds.c create mode 100644 contrib/babelfishpg_tds/src/backend/tds/tds_data_map.c create mode 100644 contrib/babelfishpg_tds/src/backend/tds/tds_srv.c create mode 100644 contrib/babelfishpg_tds/src/backend/tds/tdsbulkload.c create mode 100644 contrib/babelfishpg_tds/src/backend/tds/tdscomm.c create mode 100644 contrib/babelfishpg_tds/src/backend/tds/tdslogin.c create mode 100644 contrib/babelfishpg_tds/src/backend/tds/tdsprinttup.c create mode 100644 contrib/babelfishpg_tds/src/backend/tds/tdsprotocol.c create mode 100644 contrib/babelfishpg_tds/src/backend/tds/tdsresponse.c create mode 100644 contrib/babelfishpg_tds/src/backend/tds/tdsrpc.c create mode 100644 contrib/babelfishpg_tds/src/backend/tds/tdssecure.c create mode 100644 contrib/babelfishpg_tds/src/backend/tds/tdssqlbatch.c create mode 100644 contrib/babelfishpg_tds/src/backend/tds/tdstimestamp.c create mode 100644 contrib/babelfishpg_tds/src/backend/tds/tdstypeio.c create mode 100644 contrib/babelfishpg_tds/src/backend/tds/tdsutils.c create mode 100644 contrib/babelfishpg_tds/src/backend/tds/tdsxact.c create mode 100644 contrib/babelfishpg_tds/src/backend/utils/adt/README create mode 100644 contrib/babelfishpg_tds/src/backend/utils/adt/numeric.c create mode 100644 contrib/babelfishpg_tds/src/backend/utils/adt/varchar.c create mode 100644 contrib/babelfishpg_tds/src/backend/utils/adt/xml.c create mode 100644 contrib/babelfishpg_tds/src/backend/utils/mb/README create mode 100644 contrib/babelfishpg_tds/src/backend/utils/mb/conv.c create mode 100644 contrib/babelfishpg_tds/src/backend/utils/mb/conversion_procs/utf8_and_big5/utf8_and_big5.c create mode 100644 contrib/babelfishpg_tds/src/backend/utils/mb/conversion_procs/utf8_and_gbk/utf8_and_gbk.c create mode 100644 contrib/babelfishpg_tds/src/backend/utils/mb/conversion_procs/utf8_and_sjis/utf8_and_sjis.c create mode 100644 contrib/babelfishpg_tds/src/backend/utils/mb/conversion_procs/utf8_and_uhc/utf8_and_uhc.c create mode 100644 contrib/babelfishpg_tds/src/backend/utils/mb/conversion_procs/utf8_and_win/utf8_and_win.c create mode 100644 contrib/babelfishpg_tds/src/include/.gitignore create mode 100644 contrib/babelfishpg_tds/src/include/err_handler.h create mode 100644 contrib/babelfishpg_tds/src/include/faultinjection.h create mode 100644 contrib/babelfishpg_tds/src/include/guc.h create mode 100644 contrib/babelfishpg_tds/src/include/tds.h create mode 100644 contrib/babelfishpg_tds/src/include/tds_debug.h create mode 100644 contrib/babelfishpg_tds/src/include/tds_instr.h create mode 100644 contrib/babelfishpg_tds/src/include/tds_int.h create mode 100644 contrib/babelfishpg_tds/src/include/tds_iofuncmap.h create mode 100644 contrib/babelfishpg_tds/src/include/tds_protocol.h create mode 100644 contrib/babelfishpg_tds/src/include/tds_request.h create mode 100644 contrib/babelfishpg_tds/src/include/tds_response.h create mode 100644 contrib/babelfishpg_tds/src/include/tds_secure.h create mode 100644 contrib/babelfishpg_tds/src/include/tds_timestamp.h create mode 100644 contrib/babelfishpg_tds/src/include/tds_typecode.h create mode 100644 contrib/babelfishpg_tds/src/include/tds_typeio.h create mode 100644 contrib/babelfishpg_tds/src/include/tdsprinttup.h create mode 100644 contrib/babelfishpg_tsql/Makefile create mode 100644 contrib/babelfishpg_tsql/Release.md create mode 100644 contrib/babelfishpg_tsql/Version.config create mode 100644 contrib/babelfishpg_tsql/antlr/CMakeLists.txt create mode 100644 contrib/babelfishpg_tsql/antlr/TSqlLexer.g4 create mode 100644 contrib/babelfishpg_tsql/antlr/TSqlParser.g4 create mode 100644 contrib/babelfishpg_tsql/antlr/cmake-dir/FindANTLR.cmake create mode 100644 contrib/babelfishpg_tsql/antlr/cmake-dir/README.md create mode 100644 contrib/babelfishpg_tsql/antlr/thirdparty/antlr/antlr-4.9.3-complete.jar create mode 100644 contrib/babelfishpg_tsql/babelfishpg_tsql.control.in create mode 100644 contrib/babelfishpg_tsql/runtime/basic.sql create mode 100644 contrib/babelfishpg_tsql/runtime/functions.c create mode 100644 contrib/babelfishpg_tsql/sql/babelfishpg_tsql--1.0.0.sql create mode 100644 contrib/babelfishpg_tsql/sql/babelfishpg_tsql.in create mode 100644 contrib/babelfishpg_tsql/sql/babelfishpg_tsql.sql create mode 100644 contrib/babelfishpg_tsql/sql/coerce.sql create mode 100644 contrib/babelfishpg_tsql/sql/collation.sql create mode 100644 contrib/babelfishpg_tsql/sql/datatype.sql create mode 100644 contrib/babelfishpg_tsql/sql/datatype_string_operators.sql create mode 100644 contrib/babelfishpg_tsql/sql/import_export_compatibility.sql create mode 100644 contrib/babelfishpg_tsql/sql/ownership.sql create mode 100644 contrib/babelfishpg_tsql/sql/sys.sql create mode 100644 contrib/babelfishpg_tsql/sql/sys_cast.sql create mode 100644 contrib/babelfishpg_tsql/sql/sys_function_helpers.sql create mode 100644 contrib/babelfishpg_tsql/sql/sys_functions.sql create mode 100644 contrib/babelfishpg_tsql/sql/sys_languages.sql create mode 100644 contrib/babelfishpg_tsql/sql/sys_procedures.sql create mode 100644 contrib/babelfishpg_tsql/sql/sys_views.sql create mode 100644 contrib/babelfishpg_tsql/sql/upgrades/.gitignore create mode 100644 contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--1.0.0--1.1.0.sql create mode 100644 contrib/babelfishpg_tsql/src/analyzer.c create mode 100644 contrib/babelfishpg_tsql/src/analyzer.h create mode 100644 contrib/babelfishpg_tsql/src/antlrTests/decl.sql create mode 100644 contrib/babelfishpg_tsql/src/antlrTests/ifelse.sql create mode 100644 contrib/babelfishpg_tsql/src/antlrTests/inval.sql create mode 100644 contrib/babelfishpg_tsql/src/antlrTests/nestedBlocks.sql create mode 100644 contrib/babelfishpg_tsql/src/antlrTests/oneBlock.sql create mode 100644 contrib/babelfishpg_tsql/src/antlrTests/print.sql create mode 100644 contrib/babelfishpg_tsql/src/antlrTests/print2.sql create mode 100644 contrib/babelfishpg_tsql/src/antlrTests/proc_simple.sql create mode 100644 contrib/babelfishpg_tsql/src/antlrTests/returnsTable.sql create mode 100644 contrib/babelfishpg_tsql/src/antlrTests/series.sql create mode 100644 contrib/babelfishpg_tsql/src/antlrTests/simple.sql create mode 100644 contrib/babelfishpg_tsql/src/antlrTests/simple2.sql create mode 100644 contrib/babelfishpg_tsql/src/antlrTests/single.sql create mode 100644 contrib/babelfishpg_tsql/src/antlrTests/throw.sql create mode 100644 contrib/babelfishpg_tsql/src/antlrTests/tryCatch.sql create mode 100644 contrib/babelfishpg_tsql/src/antlrTests/while.sql create mode 100644 contrib/babelfishpg_tsql/src/applock.c create mode 100644 contrib/babelfishpg_tsql/src/babelfish_version.h create mode 100644 contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-decl.y create mode 100644 contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-epilogue.y.c create mode 100644 contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-nonassoc-ident-tokens create mode 100644 contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-prologue.y.h create mode 100644 contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y create mode 100644 contrib/babelfishpg_tsql/src/backend_parser/gram_hook.c create mode 100644 contrib/babelfishpg_tsql/src/backend_parser/gramparse.h create mode 100644 contrib/babelfishpg_tsql/src/backend_parser/include.pl create mode 100644 contrib/babelfishpg_tsql/src/backend_parser/keywords.c create mode 100644 contrib/babelfishpg_tsql/src/backend_parser/kwlist.h create mode 100644 contrib/babelfishpg_tsql/src/backend_parser/parser.c create mode 100644 contrib/babelfishpg_tsql/src/backend_parser/scan-tsql-decl.l create mode 100644 contrib/babelfishpg_tsql/src/backend_parser/scan-tsql-epilogue.l.c create mode 100644 contrib/babelfishpg_tsql/src/backend_parser/scan-tsql-prologue-top.l.h create mode 100644 contrib/babelfishpg_tsql/src/backend_parser/scan-tsql-prologue.l.h create mode 100644 contrib/babelfishpg_tsql/src/backend_parser/scan-tsql-rule.l create mode 100644 contrib/babelfishpg_tsql/src/backend_parser/scanner.h create mode 100644 contrib/babelfishpg_tsql/src/catalog.c create mode 100644 contrib/babelfishpg_tsql/src/catalog.h create mode 100644 contrib/babelfishpg_tsql/src/codegen.c create mode 100644 contrib/babelfishpg_tsql/src/codegen.h create mode 100644 contrib/babelfishpg_tsql/src/collation.c create mode 100644 contrib/babelfishpg_tsql/src/collation.h create mode 100644 contrib/babelfishpg_tsql/src/collationproperty.c create mode 100644 contrib/babelfishpg_tsql/src/compile_context.c create mode 100644 contrib/babelfishpg_tsql/src/compile_context.h create mode 100644 contrib/babelfishpg_tsql/src/cursor.c create mode 100644 contrib/babelfishpg_tsql/src/databasepropertyex.c create mode 100644 contrib/babelfishpg_tsql/src/datatypes.h create mode 100644 contrib/babelfishpg_tsql/src/dbcmds.c create mode 100644 contrib/babelfishpg_tsql/src/dbcmds.h create mode 100644 contrib/babelfishpg_tsql/src/dynastack.c create mode 100644 contrib/babelfishpg_tsql/src/dynastack.h create mode 100644 contrib/babelfishpg_tsql/src/dynavec.c create mode 100644 contrib/babelfishpg_tsql/src/dynavec.h create mode 100644 contrib/babelfishpg_tsql/src/err_handler.c create mode 100644 contrib/babelfishpg_tsql/src/err_handler.h create mode 100644 contrib/babelfishpg_tsql/src/forxml.c create mode 100644 contrib/babelfishpg_tsql/src/generate-plerrcodes.pl create mode 100644 contrib/babelfishpg_tsql/src/guc.c create mode 100644 contrib/babelfishpg_tsql/src/guc.h create mode 100644 contrib/babelfishpg_tsql/src/hooks.c create mode 100644 contrib/babelfishpg_tsql/src/hooks.h create mode 100644 contrib/babelfishpg_tsql/src/iterative_exec.c create mode 100644 contrib/babelfishpg_tsql/src/iterative_exec.h create mode 100644 contrib/babelfishpg_tsql/src/multidb.c create mode 100644 contrib/babelfishpg_tsql/src/multidb.h create mode 100644 contrib/babelfishpg_tsql/src/pl_comp-2.c create mode 100644 contrib/babelfishpg_tsql/src/pl_comp.c create mode 100644 contrib/babelfishpg_tsql/src/pl_exec-2.c create mode 100644 contrib/babelfishpg_tsql/src/pl_exec.c create mode 100644 contrib/babelfishpg_tsql/src/pl_funcs-2.c create mode 100644 contrib/babelfishpg_tsql/src/pl_funcs-2.h create mode 100644 contrib/babelfishpg_tsql/src/pl_funcs.c create mode 100644 contrib/babelfishpg_tsql/src/pl_gram.y create mode 100644 contrib/babelfishpg_tsql/src/pl_handler.c create mode 100644 contrib/babelfishpg_tsql/src/pl_reserved_kwlist.h create mode 100644 contrib/babelfishpg_tsql/src/pl_scanner.c create mode 100644 contrib/babelfishpg_tsql/src/pl_unreserved_kwlist.h create mode 100644 contrib/babelfishpg_tsql/src/plan_inval.c create mode 100644 contrib/babelfishpg_tsql/src/plerrcodes.h create mode 100644 contrib/babelfishpg_tsql/src/pltsql-2.h create mode 100644 contrib/babelfishpg_tsql/src/pltsql.h create mode 100644 contrib/babelfishpg_tsql/src/pltsql_coerce.c create mode 100644 contrib/babelfishpg_tsql/src/pltsql_function_probin_handler.c create mode 100644 contrib/babelfishpg_tsql/src/pltsql_identity.c create mode 100644 contrib/babelfishpg_tsql/src/pltsql_instr.h create mode 100644 contrib/babelfishpg_tsql/src/pltsql_utils.c create mode 100644 contrib/babelfishpg_tsql/src/prepare.c create mode 100644 contrib/babelfishpg_tsql/src/procedures.c create mode 100644 contrib/babelfishpg_tsql/src/properties.c create mode 100644 contrib/babelfishpg_tsql/src/rolecmds.c create mode 100644 contrib/babelfishpg_tsql/src/rolecmds.h create mode 100644 contrib/babelfishpg_tsql/src/schemacmds.c create mode 100644 contrib/babelfishpg_tsql/src/schemacmds.h create mode 100644 contrib/babelfishpg_tsql/src/session.c create mode 100644 contrib/babelfishpg_tsql/src/session.h create mode 100644 contrib/babelfishpg_tsql/src/stmt_walker.c create mode 100644 contrib/babelfishpg_tsql/src/stmt_walker.h create mode 100644 contrib/babelfishpg_tsql/src/string.c create mode 100644 contrib/babelfishpg_tsql/src/tablecmds.c create mode 100644 contrib/babelfishpg_tsql/src/tsqlHandler.c create mode 100644 contrib/babelfishpg_tsql/src/tsqlIface.cpp create mode 100644 contrib/babelfishpg_tsql/src/tsqlIface.hpp create mode 100644 contrib/babelfishpg_tsql/src/tsqlNodes.c create mode 100644 contrib/babelfishpg_tsql/src/tsqlNodes.h create mode 100644 contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp create mode 100644 contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.h create mode 100755 contrib/babelfishpg_tsql/src/utils/update_pg_files create mode 100644 contrib/babelfishpg_tsql/test/old_expected/pltsql_at_prefixed_vars.out create mode 100644 contrib/babelfishpg_tsql/test/old_expected/pltsql_case.out create mode 100644 contrib/babelfishpg_tsql/test/old_expected/pltsql_if.out create mode 100644 contrib/babelfishpg_tsql/test/old_expected/pltsql_localtempobjs.out create mode 100644 contrib/babelfishpg_tsql/test/old_expected/pltsql_optsemicolterm.out create mode 100644 contrib/babelfishpg_tsql/test/old_expected/pltsql_print.out create mode 100644 contrib/babelfishpg_tsql/test/old_expected/pltsql_print_0.out create mode 100644 contrib/babelfishpg_tsql/test/old_expected/pltsql_sanitychecks.out create mode 100644 contrib/babelfishpg_tsql/test/old_expected/top_percent_keywords.out create mode 100644 contrib/babelfishpg_tsql/test/old_sql/pltsql_at_prefixed_vars.sql create mode 100644 contrib/babelfishpg_tsql/test/old_sql/pltsql_case.sql create mode 100644 contrib/babelfishpg_tsql/test/old_sql/pltsql_if.sql create mode 100644 contrib/babelfishpg_tsql/test/old_sql/pltsql_localtempobjs.sql create mode 100644 contrib/babelfishpg_tsql/test/old_sql/pltsql_optsemicolterm.sql create mode 100644 contrib/babelfishpg_tsql/test/old_sql/pltsql_print.sql create mode 100644 contrib/babelfishpg_tsql/test/old_sql/pltsql_sanitychecks.sql create mode 100644 contrib/babelfishpg_tsql/test/old_sql/top_percent_keywords.sql create mode 100644 contrib/test/JDBC/BABEL-2267.sql create mode 100644 contrib/test/JDBC/BABEL-2455.sql create mode 100644 contrib/test/JDBC/Info/.gitignore create mode 100644 contrib/test/JDBC/README.md create mode 100755 contrib/test/JDBC/cleanup.sh create mode 100644 contrib/test/JDBC/expected/102_1.out create mode 100644 contrib/test/JDBC/expected/102_2.out create mode 100644 contrib/test/JDBC/expected/102_3.out create mode 100644 contrib/test/JDBC/expected/102_6.out create mode 100644 contrib/test/JDBC/expected/113_1.out create mode 100644 contrib/test/JDBC/expected/11704_1.out create mode 100644 contrib/test/JDBC/expected/11704_2.out create mode 100644 contrib/test/JDBC/expected/129_1.out create mode 100644 contrib/test/JDBC/expected/1770_1750_1.out create mode 100644 contrib/test/JDBC/expected/1774_1750_1.out create mode 100644 contrib/test/JDBC/expected/208_1.out create mode 100644 contrib/test/JDBC/expected/218_1.out create mode 100644 contrib/test/JDBC/expected/222_1.out create mode 100644 contrib/test/JDBC/expected/257_2.out create mode 100644 contrib/test/JDBC/expected/2760_1.out create mode 100644 contrib/test/JDBC/expected/2812_1.out create mode 100644 contrib/test/JDBC/expected/2812_2.out create mode 100644 contrib/test/JDBC/expected/2812_3.out create mode 100644 contrib/test/JDBC/expected/4924_1.out create mode 100644 contrib/test/JDBC/expected/4924_2.out create mode 100644 contrib/test/JDBC/expected/4936_1.out create mode 100644 contrib/test/JDBC/expected/4936_2.out create mode 100644 contrib/test/JDBC/expected/BABEL-1000.out create mode 100644 contrib/test/JDBC/expected/BABEL-101.out create mode 100644 contrib/test/JDBC/expected/BABEL-1044.out create mode 100644 contrib/test/JDBC/expected/BABEL-1056.out create mode 100644 contrib/test/JDBC/expected/BABEL-1066.out create mode 100644 contrib/test/JDBC/expected/BABEL-1073.out create mode 100644 contrib/test/JDBC/expected/BABEL-1091.out create mode 100644 contrib/test/JDBC/expected/BABEL-1094.out create mode 100644 contrib/test/JDBC/expected/BABEL-1096.out create mode 100644 contrib/test/JDBC/expected/BABEL-1098.out create mode 100644 contrib/test/JDBC/expected/BABEL-1113.out create mode 100644 contrib/test/JDBC/expected/BABEL-1114.out create mode 100644 contrib/test/JDBC/expected/BABEL-1149.out create mode 100644 contrib/test/JDBC/expected/BABEL-1161.out create mode 100644 contrib/test/JDBC/expected/BABEL-1164.out create mode 100644 contrib/test/JDBC/expected/BABEL-1167.out create mode 100644 contrib/test/JDBC/expected/BABEL-1173.out create mode 100644 contrib/test/JDBC/expected/BABEL-1179.out create mode 100644 contrib/test/JDBC/expected/BABEL-1184.out create mode 100644 contrib/test/JDBC/expected/BABEL-1185.out create mode 100644 contrib/test/JDBC/expected/BABEL-1189.out create mode 100644 contrib/test/JDBC/expected/BABEL-1193.out create mode 100644 contrib/test/JDBC/expected/BABEL-1206.out create mode 100644 contrib/test/JDBC/expected/BABEL-1208.out create mode 100644 contrib/test/JDBC/expected/BABEL-1210.out create mode 100644 contrib/test/JDBC/expected/BABEL-1212.out create mode 100644 contrib/test/JDBC/expected/BABEL-1231.out create mode 100644 contrib/test/JDBC/expected/BABEL-1234.out create mode 100644 contrib/test/JDBC/expected/BABEL-1239.out create mode 100644 contrib/test/JDBC/expected/BABEL-1241.out create mode 100644 contrib/test/JDBC/expected/BABEL-1249.out create mode 100644 contrib/test/JDBC/expected/BABEL-1251.out create mode 100644 contrib/test/JDBC/expected/BABEL-1252.out create mode 100644 contrib/test/JDBC/expected/BABEL-1261.out create mode 100644 contrib/test/JDBC/expected/BABEL-1270.out create mode 100644 contrib/test/JDBC/expected/BABEL-1287.out create mode 100644 contrib/test/JDBC/expected/BABEL-1291.out create mode 100644 contrib/test/JDBC/expected/BABEL-1299.out create mode 100644 contrib/test/JDBC/expected/BABEL-1309.out create mode 100644 contrib/test/JDBC/expected/BABEL-1311.out create mode 100644 contrib/test/JDBC/expected/BABEL-1319.out create mode 100644 contrib/test/JDBC/expected/BABEL-1320.out create mode 100644 contrib/test/JDBC/expected/BABEL-1329.out create mode 100644 contrib/test/JDBC/expected/BABEL-1331.out create mode 100644 contrib/test/JDBC/expected/BABEL-1363.out create mode 100644 contrib/test/JDBC/expected/BABEL-1365.out create mode 100644 contrib/test/JDBC/expected/BABEL-1381.out create mode 100644 contrib/test/JDBC/expected/BABEL-1389.out create mode 100644 contrib/test/JDBC/expected/BABEL-1390.out create mode 100644 contrib/test/JDBC/expected/BABEL-1400.out create mode 100644 contrib/test/JDBC/expected/BABEL-1435.out create mode 100644 contrib/test/JDBC/expected/BABEL-1437.out create mode 100644 contrib/test/JDBC/expected/BABEL-1438.out create mode 100644 contrib/test/JDBC/expected/BABEL-1442.out create mode 100644 contrib/test/JDBC/expected/BABEL-1444.out create mode 100644 contrib/test/JDBC/expected/BABEL-1446.out create mode 100644 contrib/test/JDBC/expected/BABEL-1454.out create mode 100644 contrib/test/JDBC/expected/BABEL-1465.out create mode 100644 contrib/test/JDBC/expected/BABEL-1466.out create mode 100644 contrib/test/JDBC/expected/BABEL-1475.out create mode 100644 contrib/test/JDBC/expected/BABEL-1481.out create mode 100644 contrib/test/JDBC/expected/BABEL-1499.out create mode 100644 contrib/test/JDBC/expected/BABEL-1502.out create mode 100644 contrib/test/JDBC/expected/BABEL-1510.out create mode 100644 contrib/test/JDBC/expected/BABEL-1513.out create mode 100644 contrib/test/JDBC/expected/BABEL-1515.out create mode 100644 contrib/test/JDBC/expected/BABEL-1531.out create mode 100644 contrib/test/JDBC/expected/BABEL-1566.out create mode 100644 contrib/test/JDBC/expected/BABEL-1569.out create mode 100644 contrib/test/JDBC/expected/BABEL-1577.out create mode 100644 contrib/test/JDBC/expected/BABEL-1603.out create mode 100644 contrib/test/JDBC/expected/BABEL-1621.out create mode 100644 contrib/test/JDBC/expected/BABEL-1636.out create mode 100644 contrib/test/JDBC/expected/BABEL-1661.out create mode 100644 contrib/test/JDBC/expected/BABEL-1666.out create mode 100644 contrib/test/JDBC/expected/BABEL-1671.out create mode 100644 contrib/test/JDBC/expected/BABEL-1682.out create mode 100644 contrib/test/JDBC/expected/BABEL-1683.out create mode 100644 contrib/test/JDBC/expected/BABEL-1708.out create mode 100644 contrib/test/JDBC/expected/BABEL-1712.out create mode 100644 contrib/test/JDBC/expected/BABEL-1715.out create mode 100644 contrib/test/JDBC/expected/BABEL-1719.out create mode 100644 contrib/test/JDBC/expected/BABEL-1746.out create mode 100644 contrib/test/JDBC/expected/BABEL-1756.out create mode 100644 contrib/test/JDBC/expected/BABEL-1757.out create mode 100644 contrib/test/JDBC/expected/BABEL-1771.out create mode 100644 contrib/test/JDBC/expected/BABEL-1792.out create mode 100644 contrib/test/JDBC/expected/BABEL-1797.out create mode 100644 contrib/test/JDBC/expected/BABEL-1808.out create mode 100644 contrib/test/JDBC/expected/BABEL-1813.out create mode 100644 contrib/test/JDBC/expected/BABEL-1839.out create mode 100644 contrib/test/JDBC/expected/BABEL-1845.out create mode 100644 contrib/test/JDBC/expected/BABEL-1858.out create mode 100644 contrib/test/JDBC/expected/BABEL-1963.out create mode 100644 contrib/test/JDBC/expected/BABEL-1975.out create mode 100644 contrib/test/JDBC/expected/BABEL-1978.out create mode 100644 contrib/test/JDBC/expected/BABEL-1994-CHAR.out create mode 100644 contrib/test/JDBC/expected/BABEL-1994-VARCHAR.out create mode 100644 contrib/test/JDBC/expected/BABEL-1997.out create mode 100644 contrib/test/JDBC/expected/BABEL-2010.out create mode 100644 contrib/test/JDBC/expected/BABEL-2011.out create mode 100644 contrib/test/JDBC/expected/BABEL-2020-DELETE.out create mode 100644 contrib/test/JDBC/expected/BABEL-2020-UPDATE.out create mode 100644 contrib/test/JDBC/expected/BABEL-2034.out create mode 100644 contrib/test/JDBC/expected/BABEL-2049.out create mode 100644 contrib/test/JDBC/expected/BABEL-2051.out create mode 100644 contrib/test/JDBC/expected/BABEL-2060.out create mode 100644 contrib/test/JDBC/expected/BABEL-2086.out create mode 100644 contrib/test/JDBC/expected/BABEL-2089.out create mode 100644 contrib/test/JDBC/expected/BABEL-213.out create mode 100644 contrib/test/JDBC/expected/BABEL-2145.out create mode 100644 contrib/test/JDBC/expected/BABEL-2203.out create mode 100644 contrib/test/JDBC/expected/BABEL-2208.out create mode 100644 contrib/test/JDBC/expected/BABEL-2218.out create mode 100644 contrib/test/JDBC/expected/BABEL-2225.out create mode 100644 contrib/test/JDBC/expected/BABEL-2234.out create mode 100644 contrib/test/JDBC/expected/BABEL-2257.out create mode 100644 contrib/test/JDBC/expected/BABEL-2258.out create mode 100644 contrib/test/JDBC/expected/BABEL-2262.out create mode 100644 contrib/test/JDBC/expected/BABEL-2266.out create mode 100644 contrib/test/JDBC/expected/BABEL-2267.out create mode 100644 contrib/test/JDBC/expected/BABEL-2276.out create mode 100644 contrib/test/JDBC/expected/BABEL-2288.out create mode 100644 contrib/test/JDBC/expected/BABEL-2303.out create mode 100644 contrib/test/JDBC/expected/BABEL-2317.out create mode 100644 contrib/test/JDBC/expected/BABEL-2325.out create mode 100644 contrib/test/JDBC/expected/BABEL-2328.out create mode 100644 contrib/test/JDBC/expected/BABEL-2337.out create mode 100644 contrib/test/JDBC/expected/BABEL-2347.out create mode 100644 contrib/test/JDBC/expected/BABEL-2349.out create mode 100644 contrib/test/JDBC/expected/BABEL-235.out create mode 100644 contrib/test/JDBC/expected/BABEL-2350.out create mode 100644 contrib/test/JDBC/expected/BABEL-2355.out create mode 100644 contrib/test/JDBC/expected/BABEL-2357.out create mode 100644 contrib/test/JDBC/expected/BABEL-2371.out create mode 100644 contrib/test/JDBC/expected/BABEL-2372.out create mode 100644 contrib/test/JDBC/expected/BABEL-2381.out create mode 100644 contrib/test/JDBC/expected/BABEL-2390.out create mode 100644 contrib/test/JDBC/expected/BABEL-2392.out create mode 100644 contrib/test/JDBC/expected/BABEL-2403.out create mode 100644 contrib/test/JDBC/expected/BABEL-2409.out create mode 100644 contrib/test/JDBC/expected/BABEL-2410.out create mode 100644 contrib/test/JDBC/expected/BABEL-2412.out create mode 100644 contrib/test/JDBC/expected/BABEL-2416.out create mode 100644 contrib/test/JDBC/expected/BABEL-2417.out create mode 100644 contrib/test/JDBC/expected/BABEL-2418.out create mode 100644 contrib/test/JDBC/expected/BABEL-2433.out create mode 100644 contrib/test/JDBC/expected/BABEL-244.out create mode 100644 contrib/test/JDBC/expected/BABEL-2440.out create mode 100644 contrib/test/JDBC/expected/BABEL-2445.out create mode 100644 contrib/test/JDBC/expected/BABEL-2451.out create mode 100644 contrib/test/JDBC/expected/BABEL-2455.out create mode 100644 contrib/test/JDBC/expected/BABEL-2458.out create mode 100644 contrib/test/JDBC/expected/BABEL-2470.out create mode 100644 contrib/test/JDBC/expected/BABEL-2482.out create mode 100644 contrib/test/JDBC/expected/BABEL-2485.out create mode 100644 contrib/test/JDBC/expected/BABEL-2513.out create mode 100644 contrib/test/JDBC/expected/BABEL-2514.out create mode 100644 contrib/test/JDBC/expected/BABEL-2515.out create mode 100644 contrib/test/JDBC/expected/BABEL-2535.out create mode 100644 contrib/test/JDBC/expected/BABEL-2569.out create mode 100644 contrib/test/JDBC/expected/BABEL-2576.out create mode 100644 contrib/test/JDBC/expected/BABEL-2585.out create mode 100644 contrib/test/JDBC/expected/BABEL-2593.out create mode 100644 contrib/test/JDBC/expected/BABEL-2596.out create mode 100644 contrib/test/JDBC/expected/BABEL-2602.out create mode 100644 contrib/test/JDBC/expected/BABEL-2604.out create mode 100644 contrib/test/JDBC/expected/BABEL-2607.out create mode 100644 contrib/test/JDBC/expected/BABEL-2622.out create mode 100644 contrib/test/JDBC/expected/BABEL-2647.out create mode 100644 contrib/test/JDBC/expected/BABEL-265.out create mode 100644 contrib/test/JDBC/expected/BABEL-2659.out create mode 100644 contrib/test/JDBC/expected/BABEL-2674.out create mode 100644 contrib/test/JDBC/expected/BABEL-2676.out create mode 100644 contrib/test/JDBC/expected/BABEL-2706.out create mode 100644 contrib/test/JDBC/expected/BABEL-2724.out create mode 100644 contrib/test/JDBC/expected/BABEL-2725.out create mode 100644 contrib/test/JDBC/expected/BABEL-338.out create mode 100644 contrib/test/JDBC/expected/BABEL-388.out create mode 100644 contrib/test/JDBC/expected/BABEL-405.out create mode 100644 contrib/test/JDBC/expected/BABEL-407.out create mode 100644 contrib/test/JDBC/expected/BABEL-453.out create mode 100644 contrib/test/JDBC/expected/BABEL-480.out create mode 100644 contrib/test/JDBC/expected/BABEL-493.out create mode 100644 contrib/test/JDBC/expected/BABEL-559.out create mode 100644 contrib/test/JDBC/expected/BABEL-565.out create mode 100644 contrib/test/JDBC/expected/BABEL-586.out create mode 100644 contrib/test/JDBC/expected/BABEL-588.out create mode 100644 contrib/test/JDBC/expected/BABEL-597.out create mode 100644 contrib/test/JDBC/expected/BABEL-604.out create mode 100644 contrib/test/JDBC/expected/BABEL-625.out create mode 100644 contrib/test/JDBC/expected/BABEL-627.out create mode 100644 contrib/test/JDBC/expected/BABEL-637.out create mode 100644 contrib/test/JDBC/expected/BABEL-646.out create mode 100644 contrib/test/JDBC/expected/BABEL-662.out create mode 100644 contrib/test/JDBC/expected/BABEL-672.out create mode 100644 contrib/test/JDBC/expected/BABEL-694.out create mode 100644 contrib/test/JDBC/expected/BABEL-701.out create mode 100644 contrib/test/JDBC/expected/BABEL-708.out create mode 100644 contrib/test/JDBC/expected/BABEL-719.out create mode 100644 contrib/test/JDBC/expected/BABEL-728.out create mode 100644 contrib/test/JDBC/expected/BABEL-735.out create mode 100644 contrib/test/JDBC/expected/BABEL-741.out create mode 100644 contrib/test/JDBC/expected/BABEL-758.out create mode 100644 contrib/test/JDBC/expected/BABEL-768.out create mode 100644 contrib/test/JDBC/expected/BABEL-775.out create mode 100644 contrib/test/JDBC/expected/BABEL-776.out create mode 100644 contrib/test/JDBC/expected/BABEL-785.out create mode 100644 contrib/test/JDBC/expected/BABEL-788.out create mode 100644 contrib/test/JDBC/expected/BABEL-798.out create mode 100644 contrib/test/JDBC/expected/BABEL-807.out create mode 100644 contrib/test/JDBC/expected/BABEL-820.out create mode 100644 contrib/test/JDBC/expected/BABEL-872.out create mode 100644 contrib/test/JDBC/expected/BABEL-909.out create mode 100644 contrib/test/JDBC/expected/BABEL-911.out create mode 100644 contrib/test/JDBC/expected/BABEL-931.out create mode 100644 contrib/test/JDBC/expected/BABEL-941.out create mode 100644 contrib/test/JDBC/expected/BABEL-955.out create mode 100644 contrib/test/JDBC/expected/BABEL-APPLOCK.out create mode 100644 contrib/test/JDBC/expected/BABEL-COLUMN-ALIAS.out create mode 100644 contrib/test/JDBC/expected/BABEL-COLUMN-CONSTRAINT.out create mode 100644 contrib/test/JDBC/expected/BABEL-DATABASEPROPERTYEX.out create mode 100644 contrib/test/JDBC/expected/BABEL-GUC-PLAN.out create mode 100644 contrib/test/JDBC/expected/BABEL-IDENTITY-BIFS.out create mode 100644 contrib/test/JDBC/expected/BABEL-IDENTITY-COLUMN.out create mode 100644 contrib/test/JDBC/expected/BABEL-INSERT-EXECUTE.out create mode 100644 contrib/test/JDBC/expected/BABEL-LIKE2ILIKE.out create mode 100644 contrib/test/JDBC/expected/BABEL-LOGIN-USER-EXT.out create mode 100644 contrib/test/JDBC/expected/BABEL-OBJECT-FUNCTIONS.out create mode 100644 contrib/test/JDBC/expected/BABEL-PROCID.out create mode 100644 contrib/test/JDBC/expected/BABEL-RAND.out create mode 100644 contrib/test/JDBC/expected/BABEL-RECURSIVE-CTE.out create mode 100644 contrib/test/JDBC/expected/BABEL-ROWCOUNT.out create mode 100644 contrib/test/JDBC/expected/BABEL-SCHEMABINDING.out create mode 100644 contrib/test/JDBC/expected/BABEL-SEQUENCE.out create mode 100644 contrib/test/JDBC/expected/BABEL-SERVERPROPERTY.out create mode 100644 contrib/test/JDBC/expected/BABEL-SET-COMMAND.out create mode 100644 contrib/test/JDBC/expected/BABEL-SPCOLUMNS.out create mode 100644 contrib/test/JDBC/expected/BABEL-SPCURSOR.out create mode 100644 contrib/test/JDBC/expected/BABEL-SP_DATABASES.out create mode 100644 contrib/test/JDBC/expected/BABEL-SP_DATATYPE_INFO.out create mode 100644 contrib/test/JDBC/expected/BABEL-SP_DESCRIBE_FRIST_RESULT_SET.out create mode 100644 contrib/test/JDBC/expected/BABEL-SP_PKEYS.out create mode 100644 contrib/test/JDBC/expected/BABEL-SP_STATISTICS.out create mode 100644 contrib/test/JDBC/expected/BABEL-SP_TABLES.out create mode 100644 contrib/test/JDBC/expected/BABEL-SQL-CONFIG-FUNCTIONS.out create mode 100644 contrib/test/JDBC/expected/BABEL-SQUARE.out create mode 100644 contrib/test/JDBC/expected/BABEL-SYS-DATABASES.out create mode 100644 contrib/test/JDBC/expected/BABEL-SYSCHARSETS.out create mode 100644 contrib/test/JDBC/expected/BABEL-SYS_COLUMNS.out create mode 100644 contrib/test/JDBC/expected/BABEL-TABLEHINT.out create mode 100644 contrib/test/JDBC/expected/BABEL-TARGETLIST.out create mode 100644 contrib/test/JDBC/expected/BABEL-UNSUPPORTED.out create mode 100644 contrib/test/JDBC/expected/BABEL_2429.out create mode 100644 contrib/test/JDBC/expected/Babel-2655.out create mode 100644 contrib/test/JDBC/expected/TestBIT.out create mode 100644 contrib/test/JDBC/expected/TestBasicInterop.out create mode 100644 contrib/test/JDBC/expected/TestBigInt.out create mode 100644 contrib/test/JDBC/expected/TestBinary.out create mode 100644 contrib/test/JDBC/expected/TestChar.out create mode 100644 contrib/test/JDBC/expected/TestCompileTimeErrorWithDefaultBehave.out create mode 100644 contrib/test/JDBC/expected/TestCursorFetchNext.out create mode 100644 contrib/test/JDBC/expected/TestCursorPrepExecFetchNext.out create mode 100644 contrib/test/JDBC/expected/TestDate.out create mode 100644 contrib/test/JDBC/expected/TestDatetime.out create mode 100644 contrib/test/JDBC/expected/TestDatetime2.out create mode 100644 contrib/test/JDBC/expected/TestDecimal.out create mode 100644 contrib/test/JDBC/expected/TestErrorFunctions.out create mode 100644 contrib/test/JDBC/expected/TestErrorHelperFunctions.out create mode 100644 contrib/test/JDBC/expected/TestFloat.out create mode 100644 contrib/test/JDBC/expected/TestForXML.out create mode 100644 contrib/test/JDBC/expected/TestInt.out create mode 100644 contrib/test/JDBC/expected/TestInteropProcedures.out create mode 100644 contrib/test/JDBC/expected/TestIsolationLevels.out create mode 100644 contrib/test/JDBC/expected/TestMoney.out create mode 100644 contrib/test/JDBC/expected/TestNotNull.out create mode 100644 contrib/test/JDBC/expected/TestNumeric.out create mode 100644 contrib/test/JDBC/expected/TestPrepareExec.out create mode 100644 contrib/test/JDBC/expected/TestProcedureWithErrorHandling.out create mode 100644 contrib/test/JDBC/expected/TestProcedureWithTransactions.out create mode 100644 contrib/test/JDBC/expected/TestProcedureWithTriggers.out create mode 100644 contrib/test/JDBC/expected/TestRaiserror.out create mode 100644 contrib/test/JDBC/expected/TestRaiserrorFormat.out create mode 100644 contrib/test/JDBC/expected/TestReal.out create mode 100644 contrib/test/JDBC/expected/TestRunTimeErrorWithDefaultBehave.out create mode 100644 contrib/test/JDBC/expected/TestSPExecutesql.out create mode 100644 contrib/test/JDBC/expected/TestSPPrepare.out create mode 100644 contrib/test/JDBC/expected/TestSQLQueries.out create mode 100644 contrib/test/JDBC/expected/TestSmallDatetime.out create mode 100644 contrib/test/JDBC/expected/TestSmallInt.out create mode 100644 contrib/test/JDBC/expected/TestStoredProcedures.out create mode 100644 contrib/test/JDBC/expected/TestText.out create mode 100644 contrib/test/JDBC/expected/TestThrow.out create mode 100644 contrib/test/JDBC/expected/TestTime.out create mode 100644 contrib/test/JDBC/expected/TestTinyInt.out create mode 100644 contrib/test/JDBC/expected/TestTransactionName.out create mode 100644 contrib/test/JDBC/expected/TestTransactionSupportForProcedure.out create mode 100644 contrib/test/JDBC/expected/TestTransactionsSQLBatch.out create mode 100644 contrib/test/JDBC/expected/TestUDD.out create mode 100644 contrib/test/JDBC/expected/TestUniqueIdentifier.out create mode 100644 contrib/test/JDBC/expected/TestVarChar.out create mode 100644 contrib/test/JDBC/expected/TestXML.out create mode 100644 contrib/test/JDBC/expected/babel_613.out create mode 100644 contrib/test/JDBC/expected/babel_bit_comp.out create mode 100644 contrib/test/JDBC/expected/babel_ceiling_floor.out create mode 100644 contrib/test/JDBC/expected/babel_char.out create mode 100644 contrib/test/JDBC/expected/babel_collation.out create mode 100644 contrib/test/JDBC/expected/babel_iif.out create mode 100644 contrib/test/JDBC/expected/babel_isnull.out create mode 100644 contrib/test/JDBC/expected/babel_money.out create mode 100644 contrib/test/JDBC/expected/babel_numeric.out create mode 100644 contrib/test/JDBC/expected/babel_operators.out create mode 100644 contrib/test/JDBC/expected/babel_print.out create mode 100644 contrib/test/JDBC/expected/babel_smalldatetime.out create mode 100644 contrib/test/JDBC/expected/babel_top.out create mode 100644 contrib/test/JDBC/expected/babel_trigger.out create mode 100644 contrib/test/JDBC/expected/babel_varbinary.out create mode 100644 contrib/test/JDBC/expected/insertbulk.out create mode 100644 contrib/test/JDBC/expected/pg_stat_activity.out create mode 100644 contrib/test/JDBC/expected/sys-column-property.out create mode 100644 contrib/test/JDBC/expected/sys-datefirst.out create mode 100644 contrib/test/JDBC/expected/sys-lock_timeout.out create mode 100644 contrib/test/JDBC/expected/sys-max_connections.out create mode 100644 contrib/test/JDBC/expected/sys-original_login.out create mode 100644 contrib/test/JDBC/expected/sys-schema-name.out create mode 100644 contrib/test/JDBC/expected/sys-syscolumns.out create mode 100644 contrib/test/JDBC/expected/sys-trigger_nestlevel.out create mode 100644 contrib/test/JDBC/expected/tds_faultinjection.out create mode 100755 contrib/test/JDBC/init.sh create mode 100644 contrib/test/JDBC/input/BABEL-1000.sql create mode 100644 contrib/test/JDBC/input/BABEL-101.sql create mode 100644 contrib/test/JDBC/input/BABEL-1044.sql create mode 100644 contrib/test/JDBC/input/BABEL-1056.sql create mode 100644 contrib/test/JDBC/input/BABEL-1066.sql create mode 100644 contrib/test/JDBC/input/BABEL-1073.sql create mode 100644 contrib/test/JDBC/input/BABEL-1091.sql create mode 100644 contrib/test/JDBC/input/BABEL-1094.sql create mode 100644 contrib/test/JDBC/input/BABEL-1096.sql create mode 100644 contrib/test/JDBC/input/BABEL-1098.sql create mode 100644 contrib/test/JDBC/input/BABEL-1113.sql create mode 100644 contrib/test/JDBC/input/BABEL-1114.sql create mode 100644 contrib/test/JDBC/input/BABEL-1149.sql create mode 100644 contrib/test/JDBC/input/BABEL-1161.sql create mode 100644 contrib/test/JDBC/input/BABEL-1164.sql create mode 100644 contrib/test/JDBC/input/BABEL-1167.sql create mode 100644 contrib/test/JDBC/input/BABEL-1173.sql create mode 100644 contrib/test/JDBC/input/BABEL-1179.sql create mode 100644 contrib/test/JDBC/input/BABEL-1184.sql create mode 100644 contrib/test/JDBC/input/BABEL-1185.sql create mode 100644 contrib/test/JDBC/input/BABEL-1189.sql create mode 100644 contrib/test/JDBC/input/BABEL-1193.sql create mode 100644 contrib/test/JDBC/input/BABEL-1206.sql create mode 100644 contrib/test/JDBC/input/BABEL-1208.sql create mode 100644 contrib/test/JDBC/input/BABEL-1210.sql create mode 100644 contrib/test/JDBC/input/BABEL-1212.sql create mode 100644 contrib/test/JDBC/input/BABEL-1231.sql create mode 100644 contrib/test/JDBC/input/BABEL-1234.sql create mode 100644 contrib/test/JDBC/input/BABEL-1239.sql create mode 100644 contrib/test/JDBC/input/BABEL-1241.sql create mode 100644 contrib/test/JDBC/input/BABEL-1243.sql create mode 100644 contrib/test/JDBC/input/BABEL-1249.sql create mode 100644 contrib/test/JDBC/input/BABEL-1251.sql create mode 100644 contrib/test/JDBC/input/BABEL-1252.sql create mode 100644 contrib/test/JDBC/input/BABEL-1261.sql create mode 100644 contrib/test/JDBC/input/BABEL-1270.txt create mode 100644 contrib/test/JDBC/input/BABEL-1287.sql create mode 100644 contrib/test/JDBC/input/BABEL-1291.sql create mode 100644 contrib/test/JDBC/input/BABEL-1299.sql create mode 100644 contrib/test/JDBC/input/BABEL-1309.mix create mode 100644 contrib/test/JDBC/input/BABEL-1311.sql create mode 100644 contrib/test/JDBC/input/BABEL-1319.sql create mode 100644 contrib/test/JDBC/input/BABEL-1320.sql create mode 100644 contrib/test/JDBC/input/BABEL-1329.sql create mode 100644 contrib/test/JDBC/input/BABEL-1331.sql create mode 100644 contrib/test/JDBC/input/BABEL-1363.mix create mode 100644 contrib/test/JDBC/input/BABEL-1381.sql create mode 100644 contrib/test/JDBC/input/BABEL-1389.sql create mode 100644 contrib/test/JDBC/input/BABEL-1400.sql create mode 100644 contrib/test/JDBC/input/BABEL-1435.sql create mode 100644 contrib/test/JDBC/input/BABEL-1437.sql create mode 100644 contrib/test/JDBC/input/BABEL-1438.sql create mode 100644 contrib/test/JDBC/input/BABEL-1442.sql create mode 100644 contrib/test/JDBC/input/BABEL-1444.sql create mode 100644 contrib/test/JDBC/input/BABEL-1446.sql create mode 100644 contrib/test/JDBC/input/BABEL-1454.mix create mode 100644 contrib/test/JDBC/input/BABEL-1465.sql create mode 100644 contrib/test/JDBC/input/BABEL-1466.sql create mode 100644 contrib/test/JDBC/input/BABEL-1475.sql create mode 100644 contrib/test/JDBC/input/BABEL-1481.sql create mode 100644 contrib/test/JDBC/input/BABEL-1499.sql create mode 100644 contrib/test/JDBC/input/BABEL-1502.sql create mode 100644 contrib/test/JDBC/input/BABEL-1510.sql create mode 100644 contrib/test/JDBC/input/BABEL-1513.sql create mode 100644 contrib/test/JDBC/input/BABEL-1515.sql create mode 100644 contrib/test/JDBC/input/BABEL-1531.sql create mode 100644 contrib/test/JDBC/input/BABEL-1566.sql create mode 100644 contrib/test/JDBC/input/BABEL-1569.sql create mode 100644 contrib/test/JDBC/input/BABEL-1577.sql create mode 100644 contrib/test/JDBC/input/BABEL-1603.sql create mode 100644 contrib/test/JDBC/input/BABEL-1621.sql create mode 100644 contrib/test/JDBC/input/BABEL-1636.sql create mode 100644 contrib/test/JDBC/input/BABEL-1661.sql create mode 100644 contrib/test/JDBC/input/BABEL-1666.sql create mode 100644 contrib/test/JDBC/input/BABEL-1671.sql create mode 100644 contrib/test/JDBC/input/BABEL-1682.sql create mode 100644 contrib/test/JDBC/input/BABEL-1683.sql create mode 100644 contrib/test/JDBC/input/BABEL-1708.sql create mode 100644 contrib/test/JDBC/input/BABEL-1712.sql create mode 100644 contrib/test/JDBC/input/BABEL-1715.sql create mode 100644 contrib/test/JDBC/input/BABEL-1719.sql create mode 100644 contrib/test/JDBC/input/BABEL-1746.sql create mode 100644 contrib/test/JDBC/input/BABEL-1756.sql create mode 100644 contrib/test/JDBC/input/BABEL-1757.sql create mode 100644 contrib/test/JDBC/input/BABEL-1771.sql create mode 100644 contrib/test/JDBC/input/BABEL-1792.sql create mode 100644 contrib/test/JDBC/input/BABEL-1797.sql create mode 100644 contrib/test/JDBC/input/BABEL-1808.sql create mode 100644 contrib/test/JDBC/input/BABEL-1813.sql create mode 100644 contrib/test/JDBC/input/BABEL-1839.sql create mode 100644 contrib/test/JDBC/input/BABEL-1845.sql create mode 100644 contrib/test/JDBC/input/BABEL-1858.sql create mode 100644 contrib/test/JDBC/input/BABEL-1944.sql create mode 100644 contrib/test/JDBC/input/BABEL-1963.sql create mode 100644 contrib/test/JDBC/input/BABEL-1975.sql create mode 100644 contrib/test/JDBC/input/BABEL-1978.sql create mode 100644 contrib/test/JDBC/input/BABEL-1994-CHAR.sql create mode 100644 contrib/test/JDBC/input/BABEL-1994-VARCHAR.sql create mode 100644 contrib/test/JDBC/input/BABEL-1997.sql create mode 100644 contrib/test/JDBC/input/BABEL-2010.sql create mode 100644 contrib/test/JDBC/input/BABEL-2011.sql create mode 100644 contrib/test/JDBC/input/BABEL-2020-DELETE.sql create mode 100644 contrib/test/JDBC/input/BABEL-2020-UPDATE.sql create mode 100644 contrib/test/JDBC/input/BABEL-2034.sql create mode 100644 contrib/test/JDBC/input/BABEL-2049.sql create mode 100644 contrib/test/JDBC/input/BABEL-2051.sql create mode 100644 contrib/test/JDBC/input/BABEL-2060.sql create mode 100644 contrib/test/JDBC/input/BABEL-2079.sql create mode 100644 contrib/test/JDBC/input/BABEL-2086.sql create mode 100644 contrib/test/JDBC/input/BABEL-2089.sql create mode 100644 contrib/test/JDBC/input/BABEL-213.mix create mode 100644 contrib/test/JDBC/input/BABEL-2145.sql create mode 100644 contrib/test/JDBC/input/BABEL-2203.sql create mode 100644 contrib/test/JDBC/input/BABEL-2208.sql create mode 100644 contrib/test/JDBC/input/BABEL-2218.sql create mode 100644 contrib/test/JDBC/input/BABEL-2225.sql create mode 100644 contrib/test/JDBC/input/BABEL-2234.sql create mode 100644 contrib/test/JDBC/input/BABEL-2257.sql create mode 100644 contrib/test/JDBC/input/BABEL-2258.sql create mode 100644 contrib/test/JDBC/input/BABEL-2262.sql create mode 100644 contrib/test/JDBC/input/BABEL-2266.sql create mode 100644 contrib/test/JDBC/input/BABEL-2276.sql create mode 100644 contrib/test/JDBC/input/BABEL-2288.sql create mode 100644 contrib/test/JDBC/input/BABEL-2303.sql create mode 100644 contrib/test/JDBC/input/BABEL-2317.sql create mode 100644 contrib/test/JDBC/input/BABEL-2325.sql create mode 100644 contrib/test/JDBC/input/BABEL-2328.sql create mode 100644 contrib/test/JDBC/input/BABEL-2337.sql create mode 100644 contrib/test/JDBC/input/BABEL-2347.sql create mode 100644 contrib/test/JDBC/input/BABEL-2349.sql create mode 100644 contrib/test/JDBC/input/BABEL-235.sql create mode 100644 contrib/test/JDBC/input/BABEL-2350.sql create mode 100644 contrib/test/JDBC/input/BABEL-2354.sql create mode 100644 contrib/test/JDBC/input/BABEL-2355.sql create mode 100644 contrib/test/JDBC/input/BABEL-2357.sql create mode 100644 contrib/test/JDBC/input/BABEL-2371.sql create mode 100644 contrib/test/JDBC/input/BABEL-2372.sql create mode 100644 contrib/test/JDBC/input/BABEL-2381.sql create mode 100644 contrib/test/JDBC/input/BABEL-2390.sql create mode 100644 contrib/test/JDBC/input/BABEL-2392.sql create mode 100644 contrib/test/JDBC/input/BABEL-2403.mix create mode 100644 contrib/test/JDBC/input/BABEL-2409.mix create mode 100644 contrib/test/JDBC/input/BABEL-2410.sql create mode 100644 contrib/test/JDBC/input/BABEL-2412.sql create mode 100644 contrib/test/JDBC/input/BABEL-2416.sql create mode 100644 contrib/test/JDBC/input/BABEL-2417.sql create mode 100644 contrib/test/JDBC/input/BABEL-2418.sql create mode 100644 contrib/test/JDBC/input/BABEL-2419.sql create mode 100644 contrib/test/JDBC/input/BABEL-2432.sql create mode 100644 contrib/test/JDBC/input/BABEL-2433.sql create mode 100644 contrib/test/JDBC/input/BABEL-2437.sql create mode 100644 contrib/test/JDBC/input/BABEL-244.sql create mode 100644 contrib/test/JDBC/input/BABEL-2440.mix create mode 100644 contrib/test/JDBC/input/BABEL-2445.sql create mode 100644 contrib/test/JDBC/input/BABEL-2451.sql create mode 100644 contrib/test/JDBC/input/BABEL-2458.mix create mode 100644 contrib/test/JDBC/input/BABEL-2470.sql create mode 100644 contrib/test/JDBC/input/BABEL-2482.sql create mode 100644 contrib/test/JDBC/input/BABEL-2485.sql create mode 100644 contrib/test/JDBC/input/BABEL-2513.sql create mode 100644 contrib/test/JDBC/input/BABEL-2514.sql create mode 100644 contrib/test/JDBC/input/BABEL-2515.sql create mode 100644 contrib/test/JDBC/input/BABEL-2535.sql create mode 100644 contrib/test/JDBC/input/BABEL-2569.sql create mode 100644 contrib/test/JDBC/input/BABEL-2576.sql create mode 100644 contrib/test/JDBC/input/BABEL-2585.sql create mode 100644 contrib/test/JDBC/input/BABEL-2593.sql create mode 100644 contrib/test/JDBC/input/BABEL-2596.sql create mode 100644 contrib/test/JDBC/input/BABEL-2602.mix create mode 100644 contrib/test/JDBC/input/BABEL-2604.sql create mode 100644 contrib/test/JDBC/input/BABEL-2607.sql create mode 100644 contrib/test/JDBC/input/BABEL-2622.mix create mode 100644 contrib/test/JDBC/input/BABEL-2647.sql create mode 100644 contrib/test/JDBC/input/BABEL-265.sql create mode 100644 contrib/test/JDBC/input/BABEL-2659.sql create mode 100644 contrib/test/JDBC/input/BABEL-2674.sql create mode 100644 contrib/test/JDBC/input/BABEL-2676.sql create mode 100644 contrib/test/JDBC/input/BABEL-2681.sql create mode 100644 contrib/test/JDBC/input/BABEL-2706.sql create mode 100644 contrib/test/JDBC/input/BABEL-2724.sql create mode 100644 contrib/test/JDBC/input/BABEL-2725.sql create mode 100644 contrib/test/JDBC/input/BABEL-338.sql create mode 100644 contrib/test/JDBC/input/BABEL-388.sql create mode 100644 contrib/test/JDBC/input/BABEL-405.sql create mode 100644 contrib/test/JDBC/input/BABEL-407.sql create mode 100644 contrib/test/JDBC/input/BABEL-453.sql create mode 100644 contrib/test/JDBC/input/BABEL-480.sql create mode 100644 contrib/test/JDBC/input/BABEL-493.sql create mode 100644 contrib/test/JDBC/input/BABEL-559.sql create mode 100644 contrib/test/JDBC/input/BABEL-565.sql create mode 100644 contrib/test/JDBC/input/BABEL-586.sql create mode 100644 contrib/test/JDBC/input/BABEL-588.sql create mode 100644 contrib/test/JDBC/input/BABEL-597.sql create mode 100644 contrib/test/JDBC/input/BABEL-604.sql create mode 100644 contrib/test/JDBC/input/BABEL-625.sql create mode 100644 contrib/test/JDBC/input/BABEL-627.sql create mode 100644 contrib/test/JDBC/input/BABEL-637.sql create mode 100644 contrib/test/JDBC/input/BABEL-646.sql create mode 100644 contrib/test/JDBC/input/BABEL-662.sql create mode 100644 contrib/test/JDBC/input/BABEL-672.sql create mode 100644 contrib/test/JDBC/input/BABEL-694.sql create mode 100644 contrib/test/JDBC/input/BABEL-701.sql create mode 100644 contrib/test/JDBC/input/BABEL-708.sql create mode 100644 contrib/test/JDBC/input/BABEL-719.sql create mode 100644 contrib/test/JDBC/input/BABEL-728.sql create mode 100644 contrib/test/JDBC/input/BABEL-735.sql create mode 100644 contrib/test/JDBC/input/BABEL-741.sql create mode 100644 contrib/test/JDBC/input/BABEL-758.sql create mode 100644 contrib/test/JDBC/input/BABEL-768.sql create mode 100644 contrib/test/JDBC/input/BABEL-775.sql create mode 100644 contrib/test/JDBC/input/BABEL-776.sql create mode 100644 contrib/test/JDBC/input/BABEL-785.sql create mode 100644 contrib/test/JDBC/input/BABEL-788.sql create mode 100644 contrib/test/JDBC/input/BABEL-798.sql create mode 100644 contrib/test/JDBC/input/BABEL-807.sql create mode 100644 contrib/test/JDBC/input/BABEL-820.sql create mode 100644 contrib/test/JDBC/input/BABEL-872.sql create mode 100644 contrib/test/JDBC/input/BABEL-909.sql create mode 100644 contrib/test/JDBC/input/BABEL-911.sql create mode 100644 contrib/test/JDBC/input/BABEL-931.sql create mode 100644 contrib/test/JDBC/input/BABEL-941.sql create mode 100644 contrib/test/JDBC/input/BABEL-955.sql create mode 100644 contrib/test/JDBC/input/BABEL-APPLOCK.sql create mode 100644 contrib/test/JDBC/input/BABEL-COLUMN-ALIAS.sql create mode 100644 contrib/test/JDBC/input/BABEL-COLUMN-CONSTRAINT.sql create mode 100644 contrib/test/JDBC/input/BABEL-DATABASEPROPERTYEX.sql create mode 100644 contrib/test/JDBC/input/BABEL-EXTENDEDPROPERTY.sql create mode 100644 contrib/test/JDBC/input/BABEL-GUC-PLAN.sql create mode 100644 contrib/test/JDBC/input/BABEL-IDENTITY-BIFS.sql create mode 100644 contrib/test/JDBC/input/BABEL-IDENTITY-COLUMN.sql create mode 100644 contrib/test/JDBC/input/BABEL-IDENTITY.sql create mode 100644 contrib/test/JDBC/input/BABEL-IMPLICIT_TRAN-PREPEXEC.txt create mode 100644 contrib/test/JDBC/input/BABEL-IMPLICIT_TRAN.sql create mode 100644 contrib/test/JDBC/input/BABEL-INSERT-EXECUTE.sql create mode 100644 contrib/test/JDBC/input/BABEL-LIKE2ILIKE.sql create mode 100644 contrib/test/JDBC/input/BABEL-LOGIN-USER-EXT.mix create mode 100644 contrib/test/JDBC/input/BABEL-OBJECT-FUNCTIONS.sql create mode 100644 contrib/test/JDBC/input/BABEL-PROCID.sql create mode 100644 contrib/test/JDBC/input/BABEL-RAND.sql create mode 100644 contrib/test/JDBC/input/BABEL-RECURSIVE-CTE.sql create mode 100644 contrib/test/JDBC/input/BABEL-ROWCOUNT.sql create mode 100644 contrib/test/JDBC/input/BABEL-SCHEMABINDING.sql create mode 100644 contrib/test/JDBC/input/BABEL-SEQUENCE.sql create mode 100644 contrib/test/JDBC/input/BABEL-SERVERPROPERTY.sql create mode 100644 contrib/test/JDBC/input/BABEL-SET-COMMAND.sql create mode 100644 contrib/test/JDBC/input/BABEL-SPCOLUMNS.sql create mode 100644 contrib/test/JDBC/input/BABEL-SPCURSOR.sql create mode 100644 contrib/test/JDBC/input/BABEL-SP_DATABASES.sql create mode 100644 contrib/test/JDBC/input/BABEL-SP_DATATYPE_INFO.sql create mode 100644 contrib/test/JDBC/input/BABEL-SP_DESCRIBE_FRIST_RESULT_SET.sql create mode 100644 contrib/test/JDBC/input/BABEL-SP_PKEYS.sql create mode 100644 contrib/test/JDBC/input/BABEL-SP_STATISTICS.sql create mode 100644 contrib/test/JDBC/input/BABEL-SP_TABLES.sql create mode 100644 contrib/test/JDBC/input/BABEL-SQL-CONFIG-FUNCTIONS.sql create mode 100644 contrib/test/JDBC/input/BABEL-SQUARE.sql create mode 100644 contrib/test/JDBC/input/BABEL-SYS-DATABASES.mix create mode 100644 contrib/test/JDBC/input/BABEL-SYSCHARSETS.sql create mode 100644 contrib/test/JDBC/input/BABEL-SYS_COLUMNS.sql create mode 100644 contrib/test/JDBC/input/BABEL-TABLEHINT.sql create mode 100644 contrib/test/JDBC/input/BABEL-TARGETLIST.sql create mode 100644 contrib/test/JDBC/input/BABEL-UNSUPPORTED.sql create mode 100644 contrib/test/JDBC/input/BABEL_2429.sql create mode 100644 contrib/test/JDBC/input/Babel-2655.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/102_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/102_2.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/102_3.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/102_6.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/1034_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/1049_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/1051_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/10610_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/113_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/11700_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/11701_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/11702_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/11703_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/11703_2.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/11704_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/11704_2.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/11705_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/11706_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/11708_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/129_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/132_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/133_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/134_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/135_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/136_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/141_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/142_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/1505_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/16948_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/16950_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/1752_1750_2.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/1765_1750_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/1768_1750_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/1770_1750_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/1774_1750_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/180_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/180_2.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/1946_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/208_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/217_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/218_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/219_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/220_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/220_2.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/220_3.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/220_4.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/222_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/257_2.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/2732_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/2747_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/2760_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/2787_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/2812_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/2812_2.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/2812_3.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/293_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/3609_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/3701_3.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/3701_4.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/3701_5.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/3728_3727_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/3729_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/3902_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/3903_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/3930_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/4708_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/4712_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/4901_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/4920_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/4924_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/4924_2.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/4936_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/4936_2.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/512_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/515_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/517_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/545_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/550_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/556_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/6401_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/8106_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/8107_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/8143_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/8143_2.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/8152_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/8152_2.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/8159_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/8179_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/9809_1.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/TestCompileTimeErrorWithDefaultBehave.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/TestErrorHelperFunctions.sql create mode 100644 contrib/test/JDBC/input/ErrorMapping/TestRunTimeErrorWithDefaultBehave.sql create mode 100644 contrib/test/JDBC/input/TestNotNull.txt create mode 100644 contrib/test/JDBC/input/authentication/TestAuth.txt create mode 100644 contrib/test/JDBC/input/babel_613.sql create mode 100644 contrib/test/JDBC/input/babel_bit_comp.sql create mode 100644 contrib/test/JDBC/input/babel_ceiling_floor.sql create mode 100644 contrib/test/JDBC/input/babel_char.sql create mode 100644 contrib/test/JDBC/input/babel_collation.sql create mode 100644 contrib/test/JDBC/input/babel_iif.sql create mode 100644 contrib/test/JDBC/input/babel_isnull.mix create mode 100644 contrib/test/JDBC/input/babel_money.sql create mode 100644 contrib/test/JDBC/input/babel_numeric.sql create mode 100644 contrib/test/JDBC/input/babel_operators.sql create mode 100644 contrib/test/JDBC/input/babel_print.sql create mode 100644 contrib/test/JDBC/input/babel_smalldatetime.sql create mode 100644 contrib/test/JDBC/input/babel_top.sql create mode 100644 contrib/test/JDBC/input/babel_trigger.sql create mode 100644 contrib/test/JDBC/input/babel_varbinary.sql create mode 100644 contrib/test/JDBC/input/cursors/BABEL-1390.txt create mode 100644 contrib/test/JDBC/input/cursors/TestCursorFetchNext.txt create mode 100644 contrib/test/JDBC/input/cursors/TestCursorPrepExecFetchNext.txt create mode 100644 contrib/test/JDBC/input/datatypes/TestBIT.txt create mode 100644 contrib/test/JDBC/input/datatypes/TestBigInt.txt create mode 100644 contrib/test/JDBC/input/datatypes/TestBinary.txt create mode 100644 contrib/test/JDBC/input/datatypes/TestChar.txt create mode 100644 contrib/test/JDBC/input/datatypes/TestDate.txt create mode 100644 contrib/test/JDBC/input/datatypes/TestDatetime.txt create mode 100644 contrib/test/JDBC/input/datatypes/TestDatetime2.txt create mode 100644 contrib/test/JDBC/input/datatypes/TestDecimal.txt create mode 100644 contrib/test/JDBC/input/datatypes/TestFloat.txt create mode 100644 contrib/test/JDBC/input/datatypes/TestInt.txt create mode 100644 contrib/test/JDBC/input/datatypes/TestMoney.txt create mode 100644 contrib/test/JDBC/input/datatypes/TestNumeric.txt create mode 100644 contrib/test/JDBC/input/datatypes/TestReal.txt create mode 100644 contrib/test/JDBC/input/datatypes/TestSmallDatetime.txt create mode 100644 contrib/test/JDBC/input/datatypes/TestSmallInt.txt create mode 100644 contrib/test/JDBC/input/datatypes/TestText.txt create mode 100644 contrib/test/JDBC/input/datatypes/TestTime.txt create mode 100644 contrib/test/JDBC/input/datatypes/TestTinyInt.txt create mode 100644 contrib/test/JDBC/input/datatypes/TestUDD.txt create mode 100644 contrib/test/JDBC/input/datatypes/TestUniqueIdentifier.txt create mode 100644 contrib/test/JDBC/input/datatypes/TestVarChar.txt create mode 100644 contrib/test/JDBC/input/datatypes/TestXML.txt create mode 100644 contrib/test/JDBC/input/ddl/temp-tables.sql create mode 100644 contrib/test/JDBC/input/errorHandling/TestErrorFunctions.sql create mode 100644 contrib/test/JDBC/input/errorHandling/TestErrorsWithTryCatch.sql create mode 100644 contrib/test/JDBC/input/errorHandling/TestRaiserror.sql create mode 100644 contrib/test/JDBC/input/errorHandling/TestRaiserrorFormat.sql create mode 100644 contrib/test/JDBC/input/errorHandling/TestSimpleErrors.sql create mode 100644 contrib/test/JDBC/input/errorHandling/TestSimpleErrorsWithImplicitTran.txt create mode 100644 contrib/test/JDBC/input/errorHandling/TestSimpleErrorsWithXactAbort.sql create mode 100644 contrib/test/JDBC/input/errorHandling/TestThrow.sql create mode 100644 contrib/test/JDBC/input/forxml/TestForXML.sql create mode 100644 contrib/test/JDBC/input/functions/sys-column-property.sql create mode 100644 contrib/test/JDBC/input/functions/sys-datefirst.sql create mode 100644 contrib/test/JDBC/input/functions/sys-lock_timeout.sql create mode 100644 contrib/test/JDBC/input/functions/sys-max_connections.sql create mode 100644 contrib/test/JDBC/input/functions/sys-original_login.sql create mode 100644 contrib/test/JDBC/input/functions/sys-schema-name.sql create mode 100644 contrib/test/JDBC/input/functions/sys-trigger_nestlevel.sql create mode 100644 contrib/test/JDBC/input/insertbulk.txt create mode 100644 contrib/test/JDBC/input/interoperability/TestBasicInterop.mix create mode 100644 contrib/test/JDBC/input/interoperability/TestInteropProcedures.mix create mode 100644 contrib/test/JDBC/input/interoperability/TestProcedureWithErrorHandling.mix create mode 100644 contrib/test/JDBC/input/interoperability/TestProcedureWithTransactions.mix create mode 100644 contrib/test/JDBC/input/interoperability/TestProcedureWithTriggers.mix create mode 100644 contrib/test/JDBC/input/pg_stat_activity.txt create mode 100644 contrib/test/JDBC/input/sqlBatch/TestSQLQueries.txt create mode 100644 contrib/test/JDBC/input/storedProcedures/BABEL-1365.sql create mode 100644 contrib/test/JDBC/input/storedProcedures/TestPrepareExec.txt create mode 100644 contrib/test/JDBC/input/storedProcedures/TestSPExecutesql.sql create mode 100644 contrib/test/JDBC/input/storedProcedures/TestSPPrepare.sql create mode 100644 contrib/test/JDBC/input/storedProcedures/TestStoredProcedures.txt create mode 100644 contrib/test/JDBC/input/tds_faultinjection.txt create mode 100644 contrib/test/JDBC/input/transactions/TestIsolationLevels.sql create mode 100644 contrib/test/JDBC/input/transactions/TestTransactionName.sql create mode 100644 contrib/test/JDBC/input/transactions/TestTransactionSupportForProcedure.txt create mode 100644 contrib/test/JDBC/input/transactions/TestTransactionsSQLBatch.txt create mode 100644 contrib/test/JDBC/input/transactions/TestTriggers.sql create mode 100644 contrib/test/JDBC/input/views/sys-all_columns.sql create mode 100644 contrib/test/JDBC/input/views/sys-check_constraints.sql create mode 100644 contrib/test/JDBC/input/views/sys-computed_columns.sql create mode 100644 contrib/test/JDBC/input/views/sys-databases.sql create mode 100644 contrib/test/JDBC/input/views/sys-default_constraints.sql create mode 100644 contrib/test/JDBC/input/views/sys-extended_properties.sql create mode 100644 contrib/test/JDBC/input/views/sys-index_columns.sql create mode 100644 contrib/test/JDBC/input/views/sys-indexes.sql create mode 100644 contrib/test/JDBC/input/views/sys-schemas.sql create mode 100644 contrib/test/JDBC/input/views/sys-server_principals.sql create mode 100644 contrib/test/JDBC/input/views/sys-syscolumns.sql create mode 100644 contrib/test/JDBC/jdbc_schedule create mode 100644 contrib/test/JDBC/pom.xml create mode 100644 contrib/test/JDBC/sql_expected/1034_1.out create mode 100644 contrib/test/JDBC/sql_expected/1049_1.out create mode 100644 contrib/test/JDBC/sql_expected/1051_1.out create mode 100644 contrib/test/JDBC/sql_expected/10610_1.out create mode 100644 contrib/test/JDBC/sql_expected/11700_1.out create mode 100644 contrib/test/JDBC/sql_expected/11701_1.out create mode 100644 contrib/test/JDBC/sql_expected/11702_1.out create mode 100644 contrib/test/JDBC/sql_expected/11703_1.out create mode 100644 contrib/test/JDBC/sql_expected/11703_2.out create mode 100644 contrib/test/JDBC/sql_expected/11705_1.out create mode 100644 contrib/test/JDBC/sql_expected/11706_1.out create mode 100644 contrib/test/JDBC/sql_expected/11708_1.out create mode 100644 contrib/test/JDBC/sql_expected/132_1.out create mode 100644 contrib/test/JDBC/sql_expected/133_1.out create mode 100644 contrib/test/JDBC/sql_expected/134_1.out create mode 100644 contrib/test/JDBC/sql_expected/135_1.out create mode 100644 contrib/test/JDBC/sql_expected/136_1.out create mode 100644 contrib/test/JDBC/sql_expected/141_1.out create mode 100644 contrib/test/JDBC/sql_expected/142_1.out create mode 100644 contrib/test/JDBC/sql_expected/1505_1.out create mode 100644 contrib/test/JDBC/sql_expected/16948_1.out create mode 100644 contrib/test/JDBC/sql_expected/16950_1.out create mode 100644 contrib/test/JDBC/sql_expected/1752_1750_2.out create mode 100644 contrib/test/JDBC/sql_expected/1765_1750_1.out create mode 100644 contrib/test/JDBC/sql_expected/1768_1750_1.out create mode 100644 contrib/test/JDBC/sql_expected/180_1.out create mode 100644 contrib/test/JDBC/sql_expected/180_2.out create mode 100644 contrib/test/JDBC/sql_expected/1946_1.out create mode 100644 contrib/test/JDBC/sql_expected/217_1.out create mode 100644 contrib/test/JDBC/sql_expected/219_1.out create mode 100644 contrib/test/JDBC/sql_expected/220_1.out create mode 100644 contrib/test/JDBC/sql_expected/220_2.out create mode 100644 contrib/test/JDBC/sql_expected/220_3.out create mode 100644 contrib/test/JDBC/sql_expected/220_4.out create mode 100644 contrib/test/JDBC/sql_expected/2732_1.out create mode 100644 contrib/test/JDBC/sql_expected/2747_1.out create mode 100644 contrib/test/JDBC/sql_expected/2787_1.out create mode 100644 contrib/test/JDBC/sql_expected/293_1.out create mode 100644 contrib/test/JDBC/sql_expected/3609_1.out create mode 100644 contrib/test/JDBC/sql_expected/3701_3.out create mode 100644 contrib/test/JDBC/sql_expected/3701_4.out create mode 100644 contrib/test/JDBC/sql_expected/3701_5.out create mode 100644 contrib/test/JDBC/sql_expected/3728_3727_1.out create mode 100644 contrib/test/JDBC/sql_expected/3729_1.out create mode 100644 contrib/test/JDBC/sql_expected/3902_1.out create mode 100644 contrib/test/JDBC/sql_expected/3903_1.out create mode 100644 contrib/test/JDBC/sql_expected/3930_1.out create mode 100644 contrib/test/JDBC/sql_expected/4708_1.out create mode 100644 contrib/test/JDBC/sql_expected/4712_1.out create mode 100644 contrib/test/JDBC/sql_expected/4901_1.out create mode 100644 contrib/test/JDBC/sql_expected/4920_1.out create mode 100644 contrib/test/JDBC/sql_expected/512_1.out create mode 100644 contrib/test/JDBC/sql_expected/515_1.out create mode 100644 contrib/test/JDBC/sql_expected/517_1.out create mode 100644 contrib/test/JDBC/sql_expected/545_1.out create mode 100644 contrib/test/JDBC/sql_expected/550_1.out create mode 100644 contrib/test/JDBC/sql_expected/556_1.out create mode 100644 contrib/test/JDBC/sql_expected/6401_1.out create mode 100644 contrib/test/JDBC/sql_expected/8106_1.out create mode 100644 contrib/test/JDBC/sql_expected/8107_1.out create mode 100644 contrib/test/JDBC/sql_expected/8143_1.out create mode 100644 contrib/test/JDBC/sql_expected/8143_2.out create mode 100644 contrib/test/JDBC/sql_expected/8152_1.out create mode 100644 contrib/test/JDBC/sql_expected/8152_2.out create mode 100644 contrib/test/JDBC/sql_expected/8159_1.out create mode 100644 contrib/test/JDBC/sql_expected/8179_1.out create mode 100644 contrib/test/JDBC/sql_expected/9809_1.out create mode 100644 contrib/test/JDBC/sql_expected/BABEL-1243.out create mode 100644 contrib/test/JDBC/sql_expected/BABEL-1944.out create mode 100644 contrib/test/JDBC/sql_expected/BABEL-2079.out create mode 100644 contrib/test/JDBC/sql_expected/BABEL-2354.out create mode 100644 contrib/test/JDBC/sql_expected/BABEL-2419.out create mode 100644 contrib/test/JDBC/sql_expected/BABEL-2432.out create mode 100644 contrib/test/JDBC/sql_expected/BABEL-2437.out create mode 100644 contrib/test/JDBC/sql_expected/BABEL-2681.out create mode 100644 contrib/test/JDBC/sql_expected/BABEL-EXTENDEDPROPERTY.out create mode 100644 contrib/test/JDBC/sql_expected/BABEL-IDENTITY.out create mode 100644 contrib/test/JDBC/sql_expected/BABEL-IMPLICIT_TRAN-PREPEXEC.out create mode 100644 contrib/test/JDBC/sql_expected/BABEL-IMPLICIT_TRAN.out create mode 100644 contrib/test/JDBC/sql_expected/TestAuth.out create mode 100644 contrib/test/JDBC/sql_expected/TestErrorsWithTryCatch.out create mode 100644 contrib/test/JDBC/sql_expected/TestSimpleErrors.out create mode 100644 contrib/test/JDBC/sql_expected/TestSimpleErrorsWithImplicitTran.out create mode 100644 contrib/test/JDBC/sql_expected/TestSimpleErrorsWithXactAbort.out create mode 100644 contrib/test/JDBC/sql_expected/TestTriggers.out create mode 100644 contrib/test/JDBC/sql_expected/sys-all_columns.out create mode 100644 contrib/test/JDBC/sql_expected/sys-check_constraints.out create mode 100644 contrib/test/JDBC/sql_expected/sys-computed_columns.out create mode 100644 contrib/test/JDBC/sql_expected/sys-databases.out create mode 100644 contrib/test/JDBC/sql_expected/sys-default_constraints.out create mode 100644 contrib/test/JDBC/sql_expected/sys-extended_properties.out create mode 100644 contrib/test/JDBC/sql_expected/sys-index_columns.out create mode 100644 contrib/test/JDBC/sql_expected/sys-indexes.out create mode 100644 contrib/test/JDBC/sql_expected/sys-schemas.out create mode 100644 contrib/test/JDBC/sql_expected/sys-server_principals.out create mode 100644 contrib/test/JDBC/sql_expected/temp-tables.out create mode 100644 contrib/test/JDBC/src/main/java/com/sqlsamples/CompareResults.java create mode 100644 contrib/test/JDBC/src/main/java/com/sqlsamples/Config.java create mode 100644 contrib/test/JDBC/src/main/java/com/sqlsamples/ExportResults.java create mode 100644 contrib/test/JDBC/src/main/java/com/sqlsamples/HandleException.java create mode 100644 contrib/test/JDBC/src/main/java/com/sqlsamples/JDBCAuthentication.java create mode 100644 contrib/test/JDBC/src/main/java/com/sqlsamples/JDBCBulkCopy.java create mode 100644 contrib/test/JDBC/src/main/java/com/sqlsamples/JDBCCallableStatement.java create mode 100644 contrib/test/JDBC/src/main/java/com/sqlsamples/JDBCCrossDialect.java create mode 100644 contrib/test/JDBC/src/main/java/com/sqlsamples/JDBCCursor.java create mode 100644 contrib/test/JDBC/src/main/java/com/sqlsamples/JDBCPreparedStatement.java create mode 100644 contrib/test/JDBC/src/main/java/com/sqlsamples/JDBCStatement.java create mode 100644 contrib/test/JDBC/src/main/java/com/sqlsamples/JDBCTransaction.java create mode 100644 contrib/test/JDBC/src/main/java/com/sqlsamples/Statistics.java create mode 100644 contrib/test/JDBC/src/main/java/com/sqlsamples/batch_run.java create mode 100644 contrib/test/JDBC/src/main/resources/config.txt create mode 100644 contrib/test/JDBC/src/main/resources/junit-platform.properties create mode 100644 contrib/test/JDBC/src/test/java/com/sqlsamples/TestQueryFile.java create mode 100644 contrib/test/JDBC/utils/Blank.jpeg create mode 100644 contrib/test/JDBC/utils/TxnErrorHandingCases.py create mode 100644 contrib/test/JDBC/utils/blank.txt create mode 100644 contrib/test/JDBC/utils/devanagari.txt create mode 100644 contrib/test/JDBC/utils/emojisText.txt create mode 100644 contrib/test/JDBC/utils/flower.jpg create mode 100644 contrib/test/JDBC/utils/sample.txt create mode 100644 contrib/test/JDBC/utils/utf16.txt create mode 100644 contrib/test/dotnet/ExpectedOutput/ScalarFunctionsSQLBatch.out create mode 100644 contrib/test/dotnet/ExpectedOutput/TestAuthentication.out create mode 100644 contrib/test/dotnet/ExpectedOutput/TestBIT.out create mode 100644 contrib/test/dotnet/ExpectedOutput/TestBigInt.out create mode 100644 contrib/test/dotnet/ExpectedOutput/TestBinary.out create mode 100644 contrib/test/dotnet/ExpectedOutput/TestChar.out create mode 100644 contrib/test/dotnet/ExpectedOutput/TestDate.out create mode 100644 contrib/test/dotnet/ExpectedOutput/TestDatetime.out create mode 100644 contrib/test/dotnet/ExpectedOutput/TestDatetime2.out create mode 100644 contrib/test/dotnet/ExpectedOutput/TestDecimal.out create mode 100644 contrib/test/dotnet/ExpectedOutput/TestFloat.out create mode 100644 contrib/test/dotnet/ExpectedOutput/TestInt.out create mode 100644 contrib/test/dotnet/ExpectedOutput/TestMoney.out create mode 100644 contrib/test/dotnet/ExpectedOutput/TestNumeric.out create mode 100644 contrib/test/dotnet/ExpectedOutput/TestPrepareExec.out create mode 100644 contrib/test/dotnet/ExpectedOutput/TestReal.out create mode 100644 contrib/test/dotnet/ExpectedOutput/TestSQLQueries.out create mode 100644 contrib/test/dotnet/ExpectedOutput/TestSmallDatetime.out create mode 100644 contrib/test/dotnet/ExpectedOutput/TestSmallInt.out create mode 100644 contrib/test/dotnet/ExpectedOutput/TestSqlVariant.out create mode 100644 contrib/test/dotnet/ExpectedOutput/TestStoredProcedure.out create mode 100644 contrib/test/dotnet/ExpectedOutput/TestText.out create mode 100644 contrib/test/dotnet/ExpectedOutput/TestTime.out create mode 100644 contrib/test/dotnet/ExpectedOutput/TestTinyInt.out create mode 100644 contrib/test/dotnet/ExpectedOutput/TestTransactions.out create mode 100644 contrib/test/dotnet/ExpectedOutput/TestTransactionsSQLBatch.out create mode 100644 contrib/test/dotnet/ExpectedOutput/TestTvp.out create mode 100644 contrib/test/dotnet/ExpectedOutput/TestUDD.out create mode 100644 contrib/test/dotnet/ExpectedOutput/TestUID.out create mode 100644 contrib/test/dotnet/ExpectedOutput/TestVarChar.out create mode 100644 contrib/test/dotnet/ExpectedOutput/TestXML.out create mode 100644 contrib/test/dotnet/Info/.gitignore create mode 100644 contrib/test/dotnet/Output/.gitignore create mode 100644 contrib/test/dotnet/ReadMe.txt create mode 100644 contrib/test/dotnet/config.txt create mode 100644 contrib/test/dotnet/dotnet.csproj create mode 100644 contrib/test/dotnet/input/Authentication/TestAuthentication.txt create mode 100644 contrib/test/dotnet/input/Datatypes/TestBIT.txt create mode 100644 contrib/test/dotnet/input/Datatypes/TestBigInt.txt create mode 100644 contrib/test/dotnet/input/Datatypes/TestBinary.txt create mode 100644 contrib/test/dotnet/input/Datatypes/TestChar.txt create mode 100644 contrib/test/dotnet/input/Datatypes/TestDate.txt create mode 100644 contrib/test/dotnet/input/Datatypes/TestDatetime.txt create mode 100644 contrib/test/dotnet/input/Datatypes/TestDatetime2.txt create mode 100644 contrib/test/dotnet/input/Datatypes/TestDecimal.txt create mode 100644 contrib/test/dotnet/input/Datatypes/TestFloat.txt create mode 100644 contrib/test/dotnet/input/Datatypes/TestInt.txt create mode 100644 contrib/test/dotnet/input/Datatypes/TestMoney.txt create mode 100644 contrib/test/dotnet/input/Datatypes/TestNumeric.txt create mode 100644 contrib/test/dotnet/input/Datatypes/TestReal.txt create mode 100644 contrib/test/dotnet/input/Datatypes/TestSmallDatetime.txt create mode 100644 contrib/test/dotnet/input/Datatypes/TestSmallInt.txt create mode 100644 contrib/test/dotnet/input/Datatypes/TestSqlVariant.txt create mode 100644 contrib/test/dotnet/input/Datatypes/TestText.txt create mode 100644 contrib/test/dotnet/input/Datatypes/TestTime.txt create mode 100644 contrib/test/dotnet/input/Datatypes/TestTinyInt.txt create mode 100644 contrib/test/dotnet/input/Datatypes/TestTvp.txt create mode 100644 contrib/test/dotnet/input/Datatypes/TestUDD.txt create mode 100644 contrib/test/dotnet/input/Datatypes/TestUID.txt create mode 100644 contrib/test/dotnet/input/Datatypes/TestVarChar.txt create mode 100644 contrib/test/dotnet/input/Datatypes/TestXML.txt create mode 100644 contrib/test/dotnet/input/PrepareExec/TestPrepareExec.txt create mode 100644 contrib/test/dotnet/input/SQLBatch/TestSQLQueries.txt create mode 100644 contrib/test/dotnet/input/ScalarFunctions/ScalarFunctionsSQLBatch.txt create mode 100644 contrib/test/dotnet/input/Storedproc/TestStoredProcedure.txt create mode 100644 contrib/test/dotnet/input/Transaction/TestTransactions.txt create mode 100644 contrib/test/dotnet/input/Transaction/TestTransactionsSQLBatch.txt create mode 100644 contrib/test/dotnet/src/BatchRun.cs create mode 100644 contrib/test/dotnet/src/ExecuteTests.cs create mode 100644 contrib/test/dotnet/src/PrepareExecBinding.cs create mode 100644 contrib/test/dotnet/utils/ConfigSetup.cs create mode 100644 contrib/test/dotnet/utils/TestUtils.cs create mode 100644 contrib/test/dotnet/utils/devanagari.txt create mode 100644 contrib/test/dotnet/utils/emojisText.txt create mode 100644 contrib/test/dotnet/utils/sample.txt create mode 100644 contrib/test/dotnet/utils/utf16.txt create mode 100644 contrib/test/odbc/CMakeLists.txt create mode 100644 contrib/test/odbc/README.md create mode 100644 contrib/test/odbc/config.txt create mode 100644 contrib/test/odbc/constants.cpp create mode 100644 contrib/test/odbc/constants.h create mode 100644 contrib/test/odbc/database_objects.cpp create mode 100644 contrib/test/odbc/database_objects.h create mode 100644 contrib/test/odbc/main.cpp create mode 100644 contrib/test/odbc/odbc_handler.cpp create mode 100644 contrib/test/odbc/odbc_handler.h create mode 100644 contrib/test/odbc/query_generator.cpp create mode 100644 contrib/test/odbc/query_generator.h create mode 100644 contrib/test/odbc/test_connection.cpp create mode 100644 contrib/test/odbc/test_data_types.cpp create mode 100644 contrib/test/odbc/test_diagnostics.cpp create mode 100644 contrib/test/odbc/test_direct_executed_statements.cpp create mode 100644 contrib/test/odbc/test_metadata.cpp create mode 100644 contrib/test/odbc/test_prepared_statements.cpp create mode 100644 contrib/test/odbc/test_resultset.cpp create mode 100644 contrib/test/odbc/test_sqlgetinfo.cpp create mode 100644 contrib/test/odbc/test_transactions.cpp create mode 100644 contrib/test/odbc/utils/blank.txt create mode 100644 contrib/test/odbc/utils/devanagari.txt create mode 100644 contrib/test/odbc/utils/sample.txt create mode 100644 contrib/test/python/batch_run.py create mode 100644 contrib/test/python/compare_results.py create mode 100644 contrib/test/python/config.txt create mode 100644 contrib/test/python/execute_query.py create mode 100644 contrib/test/python/expected/pymssql/BABEL-1056.out create mode 100644 contrib/test/python/expected/pymssql/BABEL-1270.out create mode 100644 contrib/test/python/expected/pymssql/BABEL-1365.out create mode 100644 contrib/test/python/expected/pymssql/BABEL-1390.out create mode 100644 contrib/test/python/expected/pymssql/BABEL-1643.out create mode 100644 contrib/test/python/expected/pymssql/TestAuth.out create mode 100644 contrib/test/python/expected/pymssql/TestBIT.out create mode 100644 contrib/test/python/expected/pymssql/TestBigInt.out create mode 100644 contrib/test/python/expected/pymssql/TestBinary.out create mode 100644 contrib/test/python/expected/pymssql/TestChar.out create mode 100644 contrib/test/python/expected/pymssql/TestCursorFetchNext.out create mode 100644 contrib/test/python/expected/pymssql/TestCursorPrepExecFetchNext.out create mode 100644 contrib/test/python/expected/pymssql/TestDate.out create mode 100644 contrib/test/python/expected/pymssql/TestDatetime.out create mode 100644 contrib/test/python/expected/pymssql/TestDatetime2.out create mode 100644 contrib/test/python/expected/pymssql/TestDecimal.out create mode 100644 contrib/test/python/expected/pymssql/TestFloat.out create mode 100644 contrib/test/python/expected/pymssql/TestInt.out create mode 100644 contrib/test/python/expected/pymssql/TestMoney.out create mode 100644 contrib/test/python/expected/pymssql/TestNumeric.out create mode 100644 contrib/test/python/expected/pymssql/TestReal.out create mode 100644 contrib/test/python/expected/pymssql/TestSPExecutesql.out create mode 100644 contrib/test/python/expected/pymssql/TestSPPrepare.out create mode 100644 contrib/test/python/expected/pymssql/TestSQLQueries.out create mode 100644 contrib/test/python/expected/pymssql/TestSimpleErrorsWithImplicitTran.out create mode 100644 contrib/test/python/expected/pymssql/TestSmallDatetime.out create mode 100644 contrib/test/python/expected/pymssql/TestSmallInt.out create mode 100644 contrib/test/python/expected/pymssql/TestStoredProcedures.out create mode 100644 contrib/test/python/expected/pymssql/TestText.out create mode 100644 contrib/test/python/expected/pymssql/TestTime.out create mode 100644 contrib/test/python/expected/pymssql/TestTinyInt.out create mode 100644 contrib/test/python/expected/pymssql/TestTransactionSupportForProcedure.out create mode 100644 contrib/test/python/expected/pymssql/TestTransactionsSQLBatch.out create mode 100644 contrib/test/python/expected/pymssql/TestUDD.out create mode 100644 contrib/test/python/expected/pymssql/TestUniqueIdentifier.out create mode 100644 contrib/test/python/expected/pymssql/TestVarChar.out create mode 100644 contrib/test/python/expected/pymssql/TestXML.out create mode 100644 contrib/test/python/expected/pymssql/pg_stat_activity.out create mode 100644 contrib/test/python/expected/pyodbc/BABEL-1056.out create mode 100644 contrib/test/python/expected/pyodbc/BABEL-1270.out create mode 100644 contrib/test/python/expected/pyodbc/BABEL-1365.out create mode 100644 contrib/test/python/expected/pyodbc/BABEL-1390.out create mode 100644 contrib/test/python/expected/pyodbc/BABEL-1643.out create mode 100644 contrib/test/python/expected/pyodbc/TestAuth.out create mode 100644 contrib/test/python/expected/pyodbc/TestBIT.out create mode 100644 contrib/test/python/expected/pyodbc/TestBigInt.out create mode 100644 contrib/test/python/expected/pyodbc/TestBinary.out create mode 100644 contrib/test/python/expected/pyodbc/TestChar.out create mode 100644 contrib/test/python/expected/pyodbc/TestCursorFetchNext.out create mode 100644 contrib/test/python/expected/pyodbc/TestCursorPrepExecFetchNext.out create mode 100644 contrib/test/python/expected/pyodbc/TestDate.out create mode 100644 contrib/test/python/expected/pyodbc/TestDatetime.out create mode 100644 contrib/test/python/expected/pyodbc/TestDatetime2.out create mode 100644 contrib/test/python/expected/pyodbc/TestDecimal.out create mode 100644 contrib/test/python/expected/pyodbc/TestFloat.out create mode 100644 contrib/test/python/expected/pyodbc/TestInt.out create mode 100644 contrib/test/python/expected/pyodbc/TestMoney.out create mode 100644 contrib/test/python/expected/pyodbc/TestNumeric.out create mode 100644 contrib/test/python/expected/pyodbc/TestReal.out create mode 100644 contrib/test/python/expected/pyodbc/TestSPExecutesql.out create mode 100644 contrib/test/python/expected/pyodbc/TestSPPrepare.out create mode 100644 contrib/test/python/expected/pyodbc/TestSQLQueries.out create mode 100644 contrib/test/python/expected/pyodbc/TestSimpleErrorsWithImplicitTran.out create mode 100644 contrib/test/python/expected/pyodbc/TestSmallDatetime.out create mode 100644 contrib/test/python/expected/pyodbc/TestSmallInt.out create mode 100644 contrib/test/python/expected/pyodbc/TestStoredProcedures.out create mode 100644 contrib/test/python/expected/pyodbc/TestText.out create mode 100644 contrib/test/python/expected/pyodbc/TestTime.out create mode 100644 contrib/test/python/expected/pyodbc/TestTinyInt.out create mode 100644 contrib/test/python/expected/pyodbc/TestTransactionSupportForProcedure.out create mode 100644 contrib/test/python/expected/pyodbc/TestTransactionsSQLBatch.out create mode 100644 contrib/test/python/expected/pyodbc/TestUDD.out create mode 100644 contrib/test/python/expected/pyodbc/TestUniqueIdentifier.out create mode 100644 contrib/test/python/expected/pyodbc/TestVarChar.out create mode 100644 contrib/test/python/expected/pyodbc/TestXML.out create mode 100644 contrib/test/python/expected/pyodbc/pg_stat_activity.out create mode 100644 contrib/test/python/file_handler.py create mode 100644 contrib/test/python/input/BABEL-1056.txt create mode 100644 contrib/test/python/input/BABEL-1270.txt create mode 100644 contrib/test/python/input/TestSimpleErrorsWithImplicitTran.txt create mode 100644 contrib/test/python/input/authentication/TestAuth.txt create mode 100644 contrib/test/python/input/cursors/BABEL-1390.txt create mode 100644 contrib/test/python/input/cursors/TestCursorFetchNext.txt create mode 100644 contrib/test/python/input/cursors/TestCursorPrepExecFetchNext.txt create mode 100644 contrib/test/python/input/datatypes/BABEL-1643.txt create mode 100644 contrib/test/python/input/datatypes/TestBIT.txt create mode 100644 contrib/test/python/input/datatypes/TestBigInt.txt create mode 100644 contrib/test/python/input/datatypes/TestBinary.txt create mode 100644 contrib/test/python/input/datatypes/TestChar.txt create mode 100644 contrib/test/python/input/datatypes/TestDate.txt create mode 100644 contrib/test/python/input/datatypes/TestDatetime.txt create mode 100644 contrib/test/python/input/datatypes/TestDatetime2.txt create mode 100644 contrib/test/python/input/datatypes/TestDecimal.txt create mode 100644 contrib/test/python/input/datatypes/TestFloat.txt create mode 100644 contrib/test/python/input/datatypes/TestInt.txt create mode 100644 contrib/test/python/input/datatypes/TestMoney.txt create mode 100644 contrib/test/python/input/datatypes/TestNumeric.txt create mode 100644 contrib/test/python/input/datatypes/TestReal.txt create mode 100644 contrib/test/python/input/datatypes/TestSmallDatetime.txt create mode 100644 contrib/test/python/input/datatypes/TestSmallInt.txt create mode 100644 contrib/test/python/input/datatypes/TestText.txt create mode 100644 contrib/test/python/input/datatypes/TestTime.txt create mode 100644 contrib/test/python/input/datatypes/TestTinyInt.txt create mode 100644 contrib/test/python/input/datatypes/TestUDD.txt create mode 100644 contrib/test/python/input/datatypes/TestUniqueIdentifier.txt create mode 100644 contrib/test/python/input/datatypes/TestVarChar.txt create mode 100644 contrib/test/python/input/datatypes/TestXML.txt create mode 100644 contrib/test/python/input/pg_stat_activity.txt create mode 100644 contrib/test/python/input/sqlBatch/TestSQLQueries.txt create mode 100644 contrib/test/python/input/storedProcedures/BABEL-1365.sql create mode 100644 contrib/test/python/input/storedProcedures/TestSPExecutesql.sql create mode 100644 contrib/test/python/input/storedProcedures/TestSPPrepare.sql create mode 100644 contrib/test/python/input/storedProcedures/TestStoredProcedures.txt create mode 100644 contrib/test/python/input/transactions/TestTransactionSupportForProcedure.txt create mode 100644 contrib/test/python/input/transactions/TestTransactionsSQLBatch.txt create mode 100644 contrib/test/python/logs/.gitignore create mode 100644 contrib/test/python/output/pymssql/.gitkeep create mode 100644 contrib/test/python/output/pyodbc/.gitkeep create mode 100644 contrib/test/python/python_authentication.py create mode 100644 contrib/test/python/sql_expected/pymssql/.gitkeep create mode 100644 contrib/test/python/sql_expected/pyodbc/.gitkeep create mode 100644 contrib/test/python/start.py create mode 100644 contrib/test/python/test_main.py create mode 100644 contrib/test/python/utils/__init__.py create mode 100644 contrib/test/python/utils/base.py create mode 100644 contrib/test/python/utils/blank.txt create mode 100644 contrib/test/python/utils/config.py create mode 100644 contrib/test/python/utils/db_client.py create mode 100644 contrib/test/python/utils/devanagari.txt create mode 100644 contrib/test/python/utils/emojisText.txt create mode 100644 contrib/test/python/utils/sample.txt create mode 100644 contrib/test/python/utils/utf16.txt diff --git a/.github/workflows/jdbc_unit_tests.yml b/.github/workflows/jdbc_unit_tests.yml new file mode 100644 index 00000000000..a89d63169f2 --- /dev/null +++ b/.github/workflows/jdbc_unit_tests.yml @@ -0,0 +1,155 @@ +name: JDBC Unit Tests +on: + push: + branches: + - BABEL_1_X_DEV__PG_13_5 + pull_request: + branches: + - BABEL_1_X_DEV__PG_13_5 + +env: + ANTLR4_VERSION: 4.9.3 + +jobs: + extension-tests: + name: Build and test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Requirements + 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 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 unzip libutfcpp-dev gnupg mssql-tools unixodbc-dev + export PATH=/opt/mssql-tools/bin:$PATH + - name: Set up JDK 8 + uses: actions/setup-java@v2 + with: + distribution: 'adopt' + java-version: '8' + check-latest: true + - name: Copy ANTLR jar file + run: | + cd contrib/babelfishpg_tsql/antlr/thirdparty/antlr/ + sudo cp antlr-${ANTLR4_VERSION}-complete.jar /usr/local/lib + - name: Compile ANTLR + run: | + cd .. + wget http://www.antlr.org/download/antlr4-cpp-runtime-${ANTLR4_VERSION}-source.zip + unzip -d antlr4 antlr4-cpp-runtime-${ANTLR4_VERSION}-source.zip + cd antlr4 + 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 4 + sudo make install + # cp /usr/local/lib/libantlr4-runtime.so.${ANTLR4_VERSION} ~/postgres/lib/ + - name: Build, and binary installation + run: | + # CFLAGS="${CFLAGS:--Wall -Wmissing-prototypes -Wpointer-arith -Wdeclaration-after-statement -Wendif-labels -Wmissing-format-attribute -Wformat-security -fno-strict-aliasing -fwrapv -fexcess-precision=standard -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic}" + ./configure CFLAGS="-ggdb" \ + --prefix=$HOME/postgres/ \ + --enable-debug \ + --with-ldap \ + --with-libxml \ + --with-pam \ + --with-uuid=ossp \ + --enable-nls \ + --with-libxslt \ + --with-icu \ + --with-extra-version=" Babelfish for PostgreSQL" + # ./configure --prefix=$HOME/postgres/ --with-python PYTHON=/usr/bin/python2.7 --enable-debug CFLAGS="-ggdb" --with-libxml --with-uuid=ossp --with-icu + make clean && make DESTDIR=~/postgres/ -j 4 2>error.txt + # make check + sudo make install + - name: Build antlr + run: | + 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 + #PG_SRC=~/work/postgresql_modified_for_babelfish + export PG_SRC=/home/runner/work/postgresql_modified_for_babelfish/postgresql_modified_for_babelfish/ + export PG_CONFIG=~/postgres/bin/pg_config + cmake=$(which cmake) + + # Copy runtime in Postgres lib + sudo cp /usr/local/lib/libantlr4-runtime.so.${ANTLR4_VERSION} ~/postgres/lib + + cd ${PG_SRC}/contrib/babelfishpg_tsql/antlr + cmake -Wno-dev . + - name: Compile and Install Extensions + run: | + 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 + export PG_SRC=/home/runner/work/postgresql_modified_for_babelfish/postgresql_modified_for_babelfish/ + export PG_CONFIG=~/postgres/bin/pg_config + cmake=$(which cmake) + + cd $PG_SRC/contrib/ && make && sudo make install + - name: Install extensions + run: | + cd ~ + sudo chown -R runner: ~/postgres + ~/postgres/bin/initdb -D ~/postgres/data/ -E "UTF8" + ~/postgres/bin/pg_ctl -D ~/postgres/data/ -l logfile start + cd postgres/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 + ipaddress=$(ifconfig eth0 | grep 'inet ' | cut -d: -f2 | awk '{ print $2}') + sudo echo "host all all $ipaddress/32 trust" >> pg_hba.conf + ~/postgres/bin/pg_ctl -D ~/postgres/data/ -l logfile restart + sudo ~/postgres/bin/psql -d postgres -U runner -c "CREATE USER jdbc_user WITH SUPERUSER CREATEDB CREATEROLE PASSWORD '12345678' INHERIT;" + sudo ~/postgres/bin/psql -d postgres -U runner -c "DROP DATABASE IF EXISTS jdbc_testdb;" + sudo ~/postgres/bin/psql -d postgres -U runner -c "CREATE DATABASE jdbc_testdb OWNER jdbc_user;" + sudo ~/postgres/bin/psql -d jdbc_testdb -U runner -c "set allow_system_table_mods = on;" + sudo ~/postgres/bin/psql -d jdbc_testdb -U runner -c "CREATE EXTENSION IF NOT EXISTS "babelfishpg_tds" CASCADE;" + sudo ~/postgres/bin/psql -d jdbc_testdb -U runner -c "GRANT ALL ON SCHEMA sys to jdbc_user;" + sudo ~/postgres/bin/psql -d jdbc_testdb -U runner -c "ALTER USER jdbc_user CREATEDB;" + sudo ~/postgres/bin/psql -d jdbc_testdb -U runner -c "ALTER SYSTEM SET babelfishpg_tsql.database_name = 'jdbc_testdb';" + sudo ~/postgres/bin/psql -d jdbc_testdb -U runner -c "ALTER SYSTEM SET babelfishpg_tds.set_db_session_property = true;" + sudo ~/postgres/bin/psql -d jdbc_testdb -U runner -c "SELECT pg_reload_conf();" + sudo ~/postgres/bin/psql -d jdbc_testdb -U runner -c "CALL sys.initialize_babelfish('jdbc_user');" + sqlcmd -S localhost -U jdbc_user -P 12345678 -Q "SELECT @@version GO" + - name: Run JDBC test framework + timeout-minutes: 15 + run: | + cd contrib/test/JDBC/ + mvn test + - name: Upload log + if: ${{ failure() }} + uses: actions/upload-artifact@v2 + with: + name: postgres-log + path: ~/postgres/data/logfile + # The test summary files contain paths with ':' characters, which is not allowed with the upload-artifact actions + - name: Rename test summary files + if: ${{ failure() }} + run: | + cd contrib/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: ${{ failure() }} + uses: actions/upload-artifact@v2 + with: + name: run-summary.log + path: contrib/test/JDBC/Info/run-summary.log + - name: Upload output diff + if: ${{ failure() }} + uses: actions/upload-artifact@v2 + with: + name: output-diff.diff + path: contrib/test/JDBC/Info/output-diff.diff \ No newline at end of file diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml deleted file mode 100644 index 5ab388a05b0..00000000000 --- a/.github/workflows/main.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: CI - -on: - push: - pull_request: - branches: - - BABEL_1_X_DEV__13_4 - -jobs: - build-and-run-tests: - name: Build and run tests - runs-on: ubuntu-latest - steps: - - name: clone-repository - uses: actions/checkout@v2 - - name: build-postgres - run: | - ./configure - make world-bin -j8 - - name: run-tests - run: | - make check -j8 - - name: upload-test-summary - if: failure() - uses: actions/upload-artifact@v2 - with: - name: regression-summary - path: src/test/regress/regression.out - - name: upload-test-differences - if: failure() - uses: actions/upload-artifact@v2 - with: - name: regression-differences - path: src/test/regress/regression.diffs diff --git a/INSTALLING b/INSTALLING new file mode 100644 index 00000000000..0a00a635bfe --- /dev/null +++ b/INSTALLING @@ -0,0 +1,112 @@ +# Babelfish distribution compilation and installation + +### NOTE: these directions assume you are running from the directory that you +### uncompressed the Babelfish source code into. +### By default that would be babel_1.0.0__pg_13.4 + +export MAX_JOBS=2 # Or any other value suitable for your CPU capacity + +export PREFIX=/opt/target/babelfishpg +export ANTLR4_VERSION=4.9.3 + +export PG_CONFIG=${PREFIX}/bin/pg_config +export PG_SRC=$(pwd) + +export ANTLR4_RUNTIME_INCLUDE_DIR=/usr/local/include/antlr4-runtime/ + +export ANTLR4_JAVA_BIN=/usr/bin/java + + +## Prerequisites + +apt update + +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 pkg-config libossp-uuid-dev gnulib bison git + +apt install -y --no-install-recommends \ + xsltproc icu-devtools libicu66 libicu-dev gawk curl + +apt install -y openjdk-8-jre openssl \ + libssl-dev python-dev libpq-dev \ + pkgconf unzip libutfcpp-dev gnupg + +## Antlr compilation + +Compiling and installing antlr runtime + +ANTLR_EXECUTABLE=/usr/local/lib/antlr-${ANTLR4_VERSION}-complete.jar + +curl https://www.antlr.org/download/antlr-${ANTLR4_VERSION}-complete.jar \ + --output ${ANTLR_EXECUTABLE} && chmod +x ${ANTLR_EXECUTABLE} + +mkdir -p antlr_runtime + +curl https://www.antlr.org/download/antlr4-cpp-runtime-${ANTLR4_VERSION}-source.zip \ + --output /opt/antlr4-cpp-runtime-${ANTLR4_VERSION}-source.zip && \ + unzip -d antlr_runtime /opt/antlr4-cpp-runtime-${ANTLR4_VERSION}-source.zip + +cd antlr_runtime +mkdir build && cd build && \ + cmake .. -D ANTLR_JAR_LOCATION=${ANTLR_EXECUTABLE} \ + -DCMAKE_INSTALL_PREFIX=/usr/local -DWITH_DEMO=True && \ + make && make install + +## Compiling Babelfish + + +./configure CFLAGS="${CFLAGS:--Wall -Wmissing-prototypes -Wpointer-arith -Wdeclaration-after-statement -Wendif-labels -Wmissing-format-attribute -Wformat-security -fno-strict-aliasing -fwrapv -fexcess-precision=standard -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic}" \ + --prefix=${PREFIX} \ + --enable-debug \ + --with-ldap \ + --with-libxml \ + --with-pam \ + --with-uuid=ossp \ + --enable-nls \ + --with-libxslt \ + --with-icu \ + --with-extra-version=" Babelfish for PostgreSQL" + +# Compilation + +make clean && make DESTDIR=${PREFIX} -j ${MAX_JOBS} + +#world-bin + +# Install core + +make install + +# Compile ANTLR shared object + +cp /usr/local/lib/libantlr4-runtime.so.${ANTLR4_VERSION} ${PREFIX}/lib + +cmake=$(which cmake) ANTLR4_RUNTIME_LIBRARIES=/usr/include/antlr4-runtime +cd contrib/babelfishpg_tsql/antlr +cmake . + +# Build all the extensions +cd ../.. && make && make install && cd .. + + + +## Starting Babelfish + +### For starting and initiating Babelfish, follow up the instructions at +### https://babelfishpg.org/docs/installation/compiling-babelfish-from-source/#additional-installation-steps). + + +## Clients + +### SQL Server Tooling dependencies +# Reference: https://docs.microsoft.com/en-us/sql/linux/sql-server-linux-setup-tools?view=sql-server-ver15#ubuntu +# mssql-cli on arm currently isn't supported https://github.com/dbcli/mssql-cli/issues/152#issuecomment-446311124 +# For arm platform, you may find useful: pip install --upgrade mssql-cli +curl -L https://packages.microsoft.com/keys/microsoft.asc | apt-key add - && \ +curl -L https://packages.microsoft.com/config/ubuntu/20.04/prod.list | tee /etc/apt/sources.list.d/msprod.list && \ +apt update && ACCEPT_EULA=Y apt install -y mssql-tools unixodbc-dev + +PATH="${PREFIX}/bin:/opt/mssql-tools/bin/:${PATH}" diff --git a/contrib/Makefile b/contrib/Makefile index 1846d415b6f..13939a4fc3c 100644 --- a/contrib/Makefile +++ b/contrib/Makefile @@ -9,6 +9,10 @@ SUBDIRS = \ amcheck \ auth_delay \ auto_explain \ + babelfishpg_common \ + babelfishpg_money \ + babelfishpg_tds \ + babelfishpg_tsql \ bloom \ btree_gin \ btree_gist \ @@ -50,6 +54,8 @@ SUBDIRS = \ unaccent \ vacuumlo +SUBDIRS += babelfishpg_tsql + ifeq ($(with_openssl),yes) SUBDIRS += sslinfo else @@ -89,6 +95,14 @@ endif # Missing: # start-scripts \ (does not have a makefile) - $(recurse) $(recurse_always) + + +# all: $(SUBDIRS) +# $(SUBDIRS): +# $(MAKE) -C $@ + +# .PHONY: all $(SUBDIRS) + + diff --git a/contrib/babelfishpg_common/Makefile b/contrib/babelfishpg_common/Makefile new file mode 100644 index 00000000000..b1681806624 --- /dev/null +++ b/contrib/babelfishpg_common/Makefile @@ -0,0 +1,97 @@ +include Version.config + +EXTENSION = babelfishpg_common +EXTVERSION = $(BBFPGCMN_MAJOR_VERSION).$(BBFPGCMN_MINOR_VERSION).$(BBFPGCMN_MICRO_VERSION) + +# Note: +# Set PREV_EXTVERSION after release, i.e after release of 2.0.0, set PREV_EXTVERSION to 1.0.0 +# babel_upgrade test target should at the top of the src/test/regress/babel_schedule +# src/test/regress/sql/babel_upgrade.sql should be modified to include the PREV_EXTVERSION to test the upgrade path +# contrib/babelfishpg_tsql/sql/upgrades/$(EXTENSION)--$(PREV_EXTVERSION).sql should be present to test the upgrade path +PREV_EXTVERSION = 1.0.0 +MODULEPATH = $$libdir/$(EXTENSION)-$(BBFPGCMN_MAJOR_VERSION) +MODULE_big = $(EXTENSION) + +PG_CFLAGS += -g + +ifdef PREV_EXTVERSION +DATA = sql/$(EXTENSION)--$(PREV_EXTVERSION).sql +endif + +DATA_built = \ + $(EXTENSION).control \ + sql/$(EXTENSION)--$(EXTVERSION).sql + +OBJS = src/babelfishpg_common.o +OBJS += src/varchar.o +OBJS += src/bit.o +OBJS += src/instr.o +OBJS += src/typecode.o +OBJS += src/numeric.o +OBJS += src/varbinary.o +OBJS += src/uniqueidentifier.o +OBJS += src/datetime.o +OBJS += src/datetime2.o +OBJS += src/smalldatetime.o +OBJS += src/datetimeoffset.o +OBJS += src/sqlvariant.o +OBJS += src/coerce.o + +ifdef USE_PGXS +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/babelfishpg_common +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif + + +MODULEPATH = $$libdir/$(EXTENSION)-$(BBFPGCMN_MAJOR_VERSION) + +UPGRADES = $(patsubst sql/upgrades/%.sql,sql/%.sql,$(wildcard sql/upgrades/*.sql)) + +ifdef PREV_EXTVERSION +DATA = sql/$(EXTENSION)--$(PREV_EXTVERSION).sql +endif + +DATA_built = \ + $(EXTENSION).control \ + sql/$(EXTENSION)--$(EXTVERSION).sql $(UPGRADES) + +#include ../Makefile.common + +# Get Postgres version, as well as major (9.4, etc) version. Remove '.' from MAJORVER. +VERSION = $(shell $(PG_CONFIG) --version | awk '{print $$2}' | sed -e 's/devel$$//') +MAJORVER = $(shell echo $(VERSION) | cut -d . -f1,2 | tr -d .) + +# Function for testing a condition +test = $(shell test $(1) $(2) $(3) && echo yes || echo no) + +GE91 = $(call test, $(MAJORVER), -ge, 91) + +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) + +ifeq ($(GE91),yes) +all: sql/$(EXTENSION)--$(EXTVERSION).sql $(UPGRADES) +endif + +$(EXTENSION).control: $(EXTENSION).control.in + cat $< \ + | sed -e 's|@EXTVERSION@|$(EXTVERSION)|g' \ + | sed -e 's|@EXTENSION@|$(EXTENSION)|g' \ + | sed -e 's|@MODULEPATH@|$(MODULEPATH)|g' \ + > $@ + +sql/$(EXTENSION)--$(EXTVERSION).sql: sql/$(EXTENSION).in + cpp $< | sed 's/^# /-- /g' > $@ + +sql/%.sql: sql/upgrades/%.sql + cp $< $@ + + +CFLAGS = `$(PG_CONFIG) --includedir-server` + +$(recurse) diff --git a/contrib/babelfishpg_common/Version.config b/contrib/babelfishpg_common/Version.config new file mode 100644 index 00000000000..a412d68e871 --- /dev/null +++ b/contrib/babelfishpg_common/Version.config @@ -0,0 +1,4 @@ +BBFPGCMN_MAJOR_VERSION=1 +BBFPGCMN_MINOR_VERSION=1 +BBFPGCMN_MICRO_VERSION=0 + diff --git a/contrib/babelfishpg_common/babelfishpg_common.control.in b/contrib/babelfishpg_common/babelfishpg_common.control.in new file mode 100644 index 00000000000..7ae1a3eb720 --- /dev/null +++ b/contrib/babelfishpg_common/babelfishpg_common.control.in @@ -0,0 +1,7 @@ +# TSQL Datatype extension +comment = 'Transact SQL Datatype Support' +default_version = '1.1.0' +module_pathname = '$libdir/babelfishpg_common' +relocatable = true +superuser = true +requires = '' diff --git a/contrib/babelfishpg_common/sql/babelfishpg_common--1.0.0.sql b/contrib/babelfishpg_common/sql/babelfishpg_common--1.0.0.sql new file mode 100644 index 00000000000..5273f6dd72b --- /dev/null +++ b/contrib/babelfishpg_common/sql/babelfishpg_common--1.0.0.sql @@ -0,0 +1,5794 @@ +-- 1 "sql/babelfishpg_common.in" +-- 1 "" +-- 1 "" +-- 1 "sql/babelfishpg_common.in" + + + + + +CREATE SCHEMA sys; +GRANT USAGE ON SCHEMA sys TO PUBLIC; + + +SELECT set_config('search_path', 'sys, '||current_setting('search_path'), false); + +-- 1 "sql/money/fixeddecimal--1.1.0_base_parallel.sql" 1 +------------------ +-- FIXEDDECIMAL -- +------------------ + +CREATE TYPE sys.FIXEDDECIMAL; + +CREATE FUNCTION sys.fixeddecimalin(cstring, oid, int4) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalin' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalout(fixeddecimal) +RETURNS cstring +AS 'babelfishpg_money', 'fixeddecimalout' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalrecv(internal) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalrecv' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalsend(FIXEDDECIMAL) +RETURNS bytea +AS 'babelfishpg_money', 'fixeddecimalsend' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimaltypmodin(_cstring) +RETURNS INT4 +AS 'babelfishpg_money', 'fixeddecimaltypmodin' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimaltypmodout(INT4) +RETURNS cstring +AS 'babelfishpg_money', 'fixeddecimaltypmodout' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + + +CREATE TYPE sys.FIXEDDECIMAL ( + INPUT = fixeddecimalin, + OUTPUT = fixeddecimalout, + RECEIVE = fixeddecimalrecv, + SEND = fixeddecimalsend, + TYPMOD_IN = fixeddecimaltypmodin, + TYPMOD_OUT = fixeddecimaltypmodout, + INTERNALLENGTH = 8, + ALIGNMENT = 'double', + STORAGE = plain, + CATEGORY = 'N', + PREFERRED = false, + COLLATABLE = false, + PASSEDBYVALUE -- But not always.. XXX fix that. +); + +-- FIXEDDECIMAL, NUMERIC +CREATE FUNCTION sys.fixeddecimaleq(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimaleq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalne(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimalne' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimallt(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimallt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalle(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimalle' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalgt(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimalgt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalge(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimalge' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalum(FIXEDDECIMAL) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'fixeddecimalum' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalpl(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'fixeddecimalpl' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalmi(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'fixeddecimalmi' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalmul(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'fixeddecimalmul' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimaldiv(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'fixeddecimaldiv' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.abs(FIXEDDECIMAL) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'fixeddecimalabs' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimallarger(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimallarger' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalsmaller(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalsmaller' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_cmp(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS INT4 +AS 'babelfishpg_money', 'fixeddecimal_cmp' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_hash(FIXEDDECIMAL) +RETURNS INT4 +AS 'babelfishpg_money', 'fixeddecimal_hash' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- +-- Operators. +-- + +-- FIXEDDECIMAL op FIXEDDECIMAL +CREATE OPERATOR sys.= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = fixeddecimaleq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR sys.<> ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = fixeddecimalne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR sys.< ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = fixeddecimallt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.<= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = fixeddecimalle, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.>= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = fixeddecimalge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.> ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = fixeddecimalgt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.+ ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = +, + PROCEDURE = fixeddecimalpl +); + +CREATE OPERATOR sys.- ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = fixeddecimalmi +); + +CREATE OPERATOR sys.- ( + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = fixeddecimalum +); + +CREATE OPERATOR sys.* ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = *, + PROCEDURE = fixeddecimalmul +); + +CREATE OPERATOR sys./ ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = fixeddecimaldiv +); + +CREATE OPERATOR CLASS sys.fixeddecimal_ops +DEFAULT FOR TYPE FIXEDDECIMAL USING btree AS + OPERATOR 1 < (FIXEDDECIMAL, FIXEDDECIMAL), + OPERATOR 2 <= (FIXEDDECIMAL, FIXEDDECIMAL), + OPERATOR 3 = (FIXEDDECIMAL, FIXEDDECIMAL), + OPERATOR 4 >= (FIXEDDECIMAL, FIXEDDECIMAL), + OPERATOR 5 > (FIXEDDECIMAL, FIXEDDECIMAL), + FUNCTION 1 fixeddecimal_cmp(FIXEDDECIMAL, FIXEDDECIMAL); + +CREATE OPERATOR CLASS sys.fixeddecimal_ops +DEFAULT FOR TYPE FIXEDDECIMAL USING hash AS + OPERATOR 1 = (FIXEDDECIMAL, FIXEDDECIMAL), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + +-- FIXEDDECIMAL, NUMERIC +CREATE FUNCTION sys.fixeddecimal_numeric_cmp(FIXEDDECIMAL, NUMERIC) +RETURNS INT4 +AS 'babelfishpg_money', 'fixeddecimal_numeric_cmp' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.numeric_fixeddecimal_cmp(NUMERIC, FIXEDDECIMAL) +RETURNS INT4 +AS 'babelfishpg_money', 'numeric_fixeddecimal_cmp' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_numeric_eq(FIXEDDECIMAL, NUMERIC) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_numeric_eq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_numeric_ne(FIXEDDECIMAL, NUMERIC) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_numeric_ne' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_numeric_lt(FIXEDDECIMAL, NUMERIC) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_numeric_lt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_numeric_le(FIXEDDECIMAL, NUMERIC) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_numeric_le' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_numeric_gt(FIXEDDECIMAL, NUMERIC) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_numeric_gt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_numeric_ge(FIXEDDECIMAL, NUMERIC) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_numeric_ge' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = NUMERIC, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = fixeddecimal_numeric_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR sys.<> ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = NUMERIC, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = fixeddecimal_numeric_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR sys.< ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = NUMERIC, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = fixeddecimal_numeric_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.<= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = NUMERIC, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = fixeddecimal_numeric_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.>= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = NUMERIC, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = fixeddecimal_numeric_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.> ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = NUMERIC, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = fixeddecimal_numeric_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR CLASS sys.fixeddecimal_numeric_ops +FOR TYPE FIXEDDECIMAL USING btree AS + OPERATOR 1 < (FIXEDDECIMAL, NUMERIC), + OPERATOR 2 <= (FIXEDDECIMAL, NUMERIC), + OPERATOR 3 = (FIXEDDECIMAL, NUMERIC), + OPERATOR 4 >= (FIXEDDECIMAL, NUMERIC), + OPERATOR 5 > (FIXEDDECIMAL, NUMERIC), + FUNCTION 1 fixeddecimal_numeric_cmp(FIXEDDECIMAL, NUMERIC); + +CREATE OPERATOR CLASS sys.fixeddecimal_numeric_ops +FOR TYPE FIXEDDECIMAL USING hash AS + OPERATOR 1 = (FIXEDDECIMAL, NUMERIC), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + +-- NUMERIC, FIXEDDECIMAL +CREATE FUNCTION sys.numeric_fixeddecimal_eq(NUMERIC, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'numeric_fixeddecimal_eq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.numeric_fixeddecimal_ne(NUMERIC, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'numeric_fixeddecimal_ne' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.numeric_fixeddecimal_lt(NUMERIC, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'numeric_fixeddecimal_lt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.numeric_fixeddecimal_le(NUMERIC, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'numeric_fixeddecimal_le' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.numeric_fixeddecimal_gt(NUMERIC, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'numeric_fixeddecimal_gt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.numeric_fixeddecimal_ge(NUMERIC, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'numeric_fixeddecimal_ge' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.= ( + LEFTARG = NUMERIC, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = numeric_fixeddecimal_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR sys.<> ( + LEFTARG = NUMERIC, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = numeric_fixeddecimal_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR sys.< ( + LEFTARG = NUMERIC, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = numeric_fixeddecimal_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.<= ( + LEFTARG = NUMERIC, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = numeric_fixeddecimal_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR >= ( + LEFTARG = NUMERIC, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = numeric_fixeddecimal_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.> ( + LEFTARG = NUMERIC, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = numeric_fixeddecimal_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR CLASS sys.numeric_fixeddecimal_ops +FOR TYPE FIXEDDECIMAL USING btree AS + OPERATOR 1 < (NUMERIC, FIXEDDECIMAL) FOR SEARCH, + OPERATOR 2 <= (NUMERIC, FIXEDDECIMAL) FOR SEARCH, + OPERATOR 3 = (NUMERIC, FIXEDDECIMAL) FOR SEARCH, + OPERATOR 4 >= (NUMERIC, FIXEDDECIMAL) FOR SEARCH, + OPERATOR 5 > (NUMERIC, FIXEDDECIMAL) FOR SEARCH, + FUNCTION 1 numeric_fixeddecimal_cmp(NUMERIC, FIXEDDECIMAL); + +CREATE OPERATOR CLASS sys.numeric_fixeddecimal_ops +FOR TYPE FIXEDDECIMAL USING hash AS + OPERATOR 1 = (NUMERIC, FIXEDDECIMAL), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + +-- +-- Cross type operators with int8 +-- + +-- FIXEDDECIMAL, INT8 +CREATE FUNCTION sys.fixeddecimal_int8_cmp(FIXEDDECIMAL, INT8) +RETURNS INT4 +AS 'babelfishpg_money', 'fixeddecimal_int8_cmp' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_int8_eq(FIXEDDECIMAL, INT8) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int8_eq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_int8_ne(FIXEDDECIMAL, INT8) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int8_ne' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_int8_lt(FIXEDDECIMAL, INT8) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int8_lt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_int8_le(FIXEDDECIMAL, INT8) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int8_le' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_int8_gt(FIXEDDECIMAL, INT8) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int8_gt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_int8_ge(FIXEDDECIMAL, INT8) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int8_ge' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalint8pl(FIXEDDECIMAL, INT8) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'fixeddecimalint8pl' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalint8mi(FIXEDDECIMAL, INT8) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'fixeddecimalint8mi' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalint8mul(FIXEDDECIMAL, INT8) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'fixeddecimalint8mul' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalint8div(FIXEDDECIMAL, INT8) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'fixeddecimalint8div' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT8, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = fixeddecimal_int8_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR sys.<> ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT8, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = fixeddecimal_int8_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR sys.< ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT8, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = fixeddecimal_int8_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.<= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT8, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = fixeddecimal_int8_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.>= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT8, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = fixeddecimal_int8_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.> ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT8, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = fixeddecimal_int8_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.+ ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT8, + COMMUTATOR = +, + PROCEDURE = fixeddecimalint8pl +); + +CREATE OPERATOR sys.- ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT8, + PROCEDURE = fixeddecimalint8mi +); + +CREATE OPERATOR sys.* ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT8, + COMMUTATOR = *, + PROCEDURE = fixeddecimalint8mul +); + +CREATE OPERATOR sys./ ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT8, + PROCEDURE = fixeddecimalint8div +); + +CREATE OPERATOR CLASS sys.fixeddecimal_int8_ops +FOR TYPE FIXEDDECIMAL USING btree AS + OPERATOR 1 < (FIXEDDECIMAL, INT8), + OPERATOR 2 <= (FIXEDDECIMAL, INT8), + OPERATOR 3 = (FIXEDDECIMAL, INT8), + OPERATOR 4 >= (FIXEDDECIMAL, INT8), + OPERATOR 5 > (FIXEDDECIMAL, INT8), + FUNCTION 1 fixeddecimal_int8_cmp(FIXEDDECIMAL, INT8); + +CREATE OPERATOR CLASS sys.fixeddecimal_int8_ops +FOR TYPE FIXEDDECIMAL USING hash AS + OPERATOR 1 = (FIXEDDECIMAL, INT8), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + +-- INT8, FIXEDDECIMAL +CREATE FUNCTION sys.int8_fixeddecimal_cmp(INT8, FIXEDDECIMAL) +RETURNS INT4 +AS 'babelfishpg_money', 'int8_fixeddecimal_cmp' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int8_fixeddecimal_eq(INT8, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int8_fixeddecimal_eq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int8_fixeddecimal_ne(INT8, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int8_fixeddecimal_ne' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int8_fixeddecimal_lt(INT8, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int8_fixeddecimal_lt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int8_fixeddecimal_le(INT8, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int8_fixeddecimal_le' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int8_fixeddecimal_gt(INT8, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int8_fixeddecimal_gt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int8_fixeddecimal_ge(INT8, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int8_fixeddecimal_ge' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int8fixeddecimalpl(INT8, FIXEDDECIMAL) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'int8fixeddecimalpl' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int8fixeddecimalmi(INT8, FIXEDDECIMAL) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'int8fixeddecimalmi' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int8fixeddecimalmul(INT8, FIXEDDECIMAL) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'int8fixeddecimalmul' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int8fixeddecimaldiv(INT8, FIXEDDECIMAL) +RETURNS DOUBLE PRECISION +AS 'babelfishpg_money', 'int8fixeddecimaldiv' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.= ( + LEFTARG = INT8, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = int8_fixeddecimal_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR sys.<> ( + LEFTARG = INT8, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = int8_fixeddecimal_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR sys.< ( + LEFTARG = INT8, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = int8_fixeddecimal_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.<= ( + LEFTARG = INT8, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = int8_fixeddecimal_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.>= ( + LEFTARG = INT8, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = int8_fixeddecimal_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.> ( + LEFTARG = INT8, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = int8_fixeddecimal_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.+ ( + LEFTARG = INT8, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = +, + PROCEDURE = int8fixeddecimalpl +); + +CREATE OPERATOR sys.- ( + LEFTARG = INT8, + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = int8fixeddecimalmi +); + +CREATE OPERATOR sys.* ( + LEFTARG = INT8, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = *, + PROCEDURE = int8fixeddecimalmul +); + +CREATE OPERATOR sys./ ( + LEFTARG = INT8, + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = int8fixeddecimaldiv +); + +CREATE OPERATOR CLASS sys.int8_fixeddecimal_ops +FOR TYPE FIXEDDECIMAL USING btree AS + OPERATOR 1 < (INT8, FIXEDDECIMAL), + OPERATOR 2 <= (INT8, FIXEDDECIMAL), + OPERATOR 3 = (INT8, FIXEDDECIMAL), + OPERATOR 4 >= (INT8, FIXEDDECIMAL), + OPERATOR 5 > (INT8, FIXEDDECIMAL), + FUNCTION 1 int8_fixeddecimal_cmp(INT8, FIXEDDECIMAL); + +CREATE OPERATOR CLASS sys.int8_fixeddecimal_ops +FOR TYPE FIXEDDECIMAL USING hash AS + OPERATOR 1 = (INT8, FIXEDDECIMAL), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + +-- +-- Cross type operators with int4 +-- + +-- FIXEDDECIMAL, INT4 +CREATE FUNCTION sys.fixeddecimal_int4_cmp(FIXEDDECIMAL, INT4) +RETURNS INT4 +AS 'babelfishpg_money', 'fixeddecimal_int4_cmp' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_int4_eq(FIXEDDECIMAL, INT4) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int4_eq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_int4_ne(FIXEDDECIMAL, INT4) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int4_ne' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_int4_lt(FIXEDDECIMAL, INT4) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int4_lt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_int4_le(FIXEDDECIMAL, INT4) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int4_le' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_int4_gt(FIXEDDECIMAL, INT4) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int4_gt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_int4_ge(FIXEDDECIMAL, INT4) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int4_ge' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalint4pl(FIXEDDECIMAL, INT4) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'fixeddecimalint4pl' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalint4mi(FIXEDDECIMAL, INT4) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'fixeddecimalint4mi' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalint4mul(FIXEDDECIMAL, INT4) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'fixeddecimalint4mul' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalint4div(FIXEDDECIMAL, INT4) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'fixeddecimalint4div' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = fixeddecimal_int4_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR sys.<> ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = fixeddecimal_int4_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR sys.< ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = fixeddecimal_int4_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.<= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = fixeddecimal_int4_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.>= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = fixeddecimal_int4_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.> ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = fixeddecimal_int4_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.+ ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + COMMUTATOR = +, + PROCEDURE = fixeddecimalint4pl +); + +CREATE OPERATOR sys.- ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + PROCEDURE = fixeddecimalint4mi +); + +CREATE OPERATOR sys.* ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + COMMUTATOR = *, + PROCEDURE = fixeddecimalint4mul +); + +CREATE OPERATOR sys./ ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + PROCEDURE = fixeddecimalint4div +); + +CREATE OPERATOR CLASS sys.fixeddecimal_int4_ops +FOR TYPE FIXEDDECIMAL USING btree AS + OPERATOR 1 < (FIXEDDECIMAL, INT4), + OPERATOR 2 <= (FIXEDDECIMAL, INT4), + OPERATOR 3 = (FIXEDDECIMAL, INT4), + OPERATOR 4 >= (FIXEDDECIMAL, INT4), + OPERATOR 5 > (FIXEDDECIMAL, INT4), + FUNCTION 1 fixeddecimal_int4_cmp(FIXEDDECIMAL, INT4); + +CREATE OPERATOR CLASS sys.fixeddecimal_int4_ops +FOR TYPE FIXEDDECIMAL USING hash AS + OPERATOR 1 = (FIXEDDECIMAL, INT4), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + +-- INT4, FIXEDDECIMAL +CREATE FUNCTION sys.int4_fixeddecimal_cmp(INT4, FIXEDDECIMAL) +RETURNS INT4 +AS 'babelfishpg_money', 'int4_fixeddecimal_cmp' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int4_fixeddecimal_eq(INT4, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int4_fixeddecimal_eq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int4_fixeddecimal_ne(INT4, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int4_fixeddecimal_ne' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int4_fixeddecimal_lt(INT4, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int4_fixeddecimal_lt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int4_fixeddecimal_le(INT4, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int4_fixeddecimal_le' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int4_fixeddecimal_gt(INT4, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int4_fixeddecimal_gt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int4_fixeddecimal_ge(INT4, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int4_fixeddecimal_ge' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int4fixeddecimalpl(INT4, FIXEDDECIMAL) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'int4fixeddecimalpl' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int4fixeddecimalmi(INT4, FIXEDDECIMAL) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'int4fixeddecimalmi' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int4fixeddecimalmul(INT4, FIXEDDECIMAL) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'int4fixeddecimalmul' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int4fixeddecimaldiv(INT4, FIXEDDECIMAL) +RETURNS DOUBLE PRECISION +AS 'babelfishpg_money', 'int4fixeddecimaldiv' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.= ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = int4_fixeddecimal_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR sys.<> ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = int4_fixeddecimal_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR sys.< ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = int4_fixeddecimal_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.<= ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = int4_fixeddecimal_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.>= ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = int4_fixeddecimal_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.> ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = int4_fixeddecimal_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.+ ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = +, + PROCEDURE = int4fixeddecimalpl +); + +CREATE OPERATOR sys.- ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = int4fixeddecimalmi +); + +CREATE OPERATOR sys.* ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = *, + PROCEDURE = int4fixeddecimalmul +); + +CREATE OPERATOR sys./ ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = int4fixeddecimaldiv +); + +CREATE OPERATOR CLASS sys.int4_fixeddecimal_ops +FOR TYPE FIXEDDECIMAL USING btree AS + OPERATOR 1 < (INT4, FIXEDDECIMAL), + OPERATOR 2 <= (INT4, FIXEDDECIMAL), + OPERATOR 3 = (INT4, FIXEDDECIMAL), + OPERATOR 4 >= (INT4, FIXEDDECIMAL), + OPERATOR 5 > (INT4, FIXEDDECIMAL), + FUNCTION 1 int4_fixeddecimal_cmp(INT4, FIXEDDECIMAL); + +CREATE OPERATOR CLASS sys.int4_fixeddecimal_ops +FOR TYPE FIXEDDECIMAL USING hash AS + OPERATOR 1 = (INT4, FIXEDDECIMAL), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + +-- +-- Cross type operators with int2 +-- +-- FIXEDDECIMAL, INT2 +CREATE FUNCTION sys.fixeddecimal_int2_cmp(FIXEDDECIMAL, INT2) +RETURNS INT4 +AS 'babelfishpg_money', 'fixeddecimal_int2_cmp' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_int2_eq(FIXEDDECIMAL, INT2) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int2_eq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_int2_ne(FIXEDDECIMAL, INT2) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int2_ne' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_int2_lt(FIXEDDECIMAL, INT2) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int2_lt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_int2_le(FIXEDDECIMAL, INT2) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int2_le' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_int2_gt(FIXEDDECIMAL, INT2) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int2_gt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_int2_ge(FIXEDDECIMAL, INT2) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int2_ge' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalint2pl(FIXEDDECIMAL, INT2) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'fixeddecimalint2pl' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalint2mi(FIXEDDECIMAL, INT2) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'fixeddecimalint2mi' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalint2mul(FIXEDDECIMAL, INT2) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'fixeddecimalint2mul' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalint2div(FIXEDDECIMAL, INT2) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'fixeddecimalint2div' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = fixeddecimal_int2_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR sys.<> ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = fixeddecimal_int2_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR sys.< ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = fixeddecimal_int2_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.<= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = fixeddecimal_int2_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.>= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = fixeddecimal_int2_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.> ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = fixeddecimal_int2_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.+ ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + COMMUTATOR = +, + PROCEDURE = fixeddecimalint2pl +); + +CREATE OPERATOR sys.- ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + PROCEDURE = fixeddecimalint2mi +); + +CREATE OPERATOR sys.* ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + COMMUTATOR = *, + PROCEDURE = fixeddecimalint2mul +); + +CREATE OPERATOR sys./ ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + PROCEDURE = fixeddecimalint2div +); + +CREATE OPERATOR CLASS sys.fixeddecimal_int2_ops +FOR TYPE FIXEDDECIMAL USING btree AS + OPERATOR 1 < (FIXEDDECIMAL, INT2), + OPERATOR 2 <= (FIXEDDECIMAL, INT2), + OPERATOR 3 = (FIXEDDECIMAL, INT2), + OPERATOR 4 >= (FIXEDDECIMAL, INT2), + OPERATOR 5 > (FIXEDDECIMAL, INT2), + FUNCTION 1 fixeddecimal_int2_cmp(FIXEDDECIMAL, INT2); + +CREATE OPERATOR CLASS sys.fixeddecimal_int2_ops +FOR TYPE FIXEDDECIMAL USING hash AS + OPERATOR 1 = (FIXEDDECIMAL, INT2), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + +-- INT2, FIXEDDECIMAL +CREATE FUNCTION sys.int2_fixeddecimal_cmp(INT2, FIXEDDECIMAL) +RETURNS INT4 +AS 'babelfishpg_money', 'int2_fixeddecimal_cmp' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int2_fixeddecimal_eq(INT2, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int2_fixeddecimal_eq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int2_fixeddecimal_ne(INT2, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int2_fixeddecimal_ne' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int2_fixeddecimal_lt(INT2, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int2_fixeddecimal_lt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int2_fixeddecimal_le(INT2, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int2_fixeddecimal_le' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int2_fixeddecimal_gt(INT2, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int2_fixeddecimal_gt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int2_fixeddecimal_ge(INT2, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int2_fixeddecimal_ge' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int2fixeddecimalpl(INT2, FIXEDDECIMAL) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'int2fixeddecimalpl' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int2fixeddecimalmi(INT2, FIXEDDECIMAL) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'int2fixeddecimalmi' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int2fixeddecimalmul(INT2, FIXEDDECIMAL) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'int2fixeddecimalmul' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int2fixeddecimaldiv(INT2, FIXEDDECIMAL) +RETURNS DOUBLE PRECISION +AS 'babelfishpg_money', 'int2fixeddecimaldiv' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.= ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = int2_fixeddecimal_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR sys.<> ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = int2_fixeddecimal_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR sys.< ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = int2_fixeddecimal_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.<= ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = int2_fixeddecimal_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.>= ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = int2_fixeddecimal_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.> ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = int2_fixeddecimal_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.+ ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = +, + PROCEDURE = int2fixeddecimalpl +); + +CREATE OPERATOR sys.- ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = int2fixeddecimalmi +); + +CREATE OPERATOR sys.* ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = *, + PROCEDURE = int2fixeddecimalmul +); + +CREATE OPERATOR sys./ ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = int2fixeddecimaldiv +); + +CREATE OPERATOR CLASS sys.int2_fixeddecimal_ops +FOR TYPE FIXEDDECIMAL USING btree AS + OPERATOR 1 < (INT2, FIXEDDECIMAL), + OPERATOR 2 <= (INT2, FIXEDDECIMAL), + OPERATOR 3 = (INT2, FIXEDDECIMAL), + OPERATOR 4 >= (INT2, FIXEDDECIMAL), + OPERATOR 5 > (INT2, FIXEDDECIMAL), + FUNCTION 1 int2_fixeddecimal_cmp(INT2, FIXEDDECIMAL); + +CREATE OPERATOR CLASS sys.int2_fixeddecimal_ops +FOR TYPE FIXEDDECIMAL USING hash AS + OPERATOR 1 = (INT2, FIXEDDECIMAL), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + +-- +-- Casts +-- + +CREATE FUNCTION sys.fixeddecimal(FIXEDDECIMAL, INT4) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimal' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int8fixeddecimal(INT8) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'int8fixeddecimal' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalint8(FIXEDDECIMAL) +RETURNS INT8 +AS 'babelfishpg_money', 'fixeddecimalint8' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int4fixeddecimal(INT4) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'int4fixeddecimal' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalint4(FIXEDDECIMAL) +RETURNS INT4 +AS 'babelfishpg_money', 'fixeddecimalint4' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int2fixeddecimal(INT2) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'int2fixeddecimal' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalint2(FIXEDDECIMAL) +RETURNS INT2 +AS 'babelfishpg_money', 'fixeddecimalint2' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimaltod(FIXEDDECIMAL) +RETURNS DOUBLE PRECISION +AS 'babelfishpg_money', 'fixeddecimaltod' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.dtofixeddecimal(DOUBLE PRECISION) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'dtofixeddecimal' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimaltof(FIXEDDECIMAL) +RETURNS REAL +AS 'babelfishpg_money', 'fixeddecimaltof' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.ftofixeddecimal(REAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'ftofixeddecimal' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_numeric(FIXEDDECIMAL) +RETURNS NUMERIC +AS 'babelfishpg_money', 'fixeddecimal_numeric' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.numeric_fixeddecimal(NUMERIC) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'numeric_fixeddecimal' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (FIXEDDECIMAL AS FIXEDDECIMAL) + WITH FUNCTION fixeddecimal (FIXEDDECIMAL, INT4) AS ASSIGNMENT; + +CREATE CAST (INT8 AS FIXEDDECIMAL) + WITH FUNCTION int8fixeddecimal (INT8) AS IMPLICIT; + +CREATE CAST (FIXEDDECIMAL AS INT8) + WITH FUNCTION fixeddecimalint8 (FIXEDDECIMAL) AS ASSIGNMENT; + +CREATE CAST (INT4 AS FIXEDDECIMAL) + WITH FUNCTION int4fixeddecimal (INT4) AS IMPLICIT; + +CREATE CAST (FIXEDDECIMAL AS INT4) + WITH FUNCTION fixeddecimalint4 (FIXEDDECIMAL) AS ASSIGNMENT; + +CREATE CAST (INT2 AS FIXEDDECIMAL) + WITH FUNCTION int2fixeddecimal (INT2) AS IMPLICIT; + +CREATE CAST (FIXEDDECIMAL AS INT2) + WITH FUNCTION fixeddecimalint2 (FIXEDDECIMAL) AS ASSIGNMENT; + +CREATE CAST (FIXEDDECIMAL AS DOUBLE PRECISION) + WITH FUNCTION fixeddecimaltod (FIXEDDECIMAL) AS IMPLICIT; + +CREATE CAST (DOUBLE PRECISION AS FIXEDDECIMAL) + WITH FUNCTION dtofixeddecimal (DOUBLE PRECISION) AS ASSIGNMENT; -- XXX? or Implicit? + +CREATE CAST (FIXEDDECIMAL AS REAL) + WITH FUNCTION fixeddecimaltof (FIXEDDECIMAL) AS IMPLICIT; + +CREATE CAST (REAL AS FIXEDDECIMAL) + WITH FUNCTION ftofixeddecimal (REAL) AS ASSIGNMENT; -- XXX or Implicit? + +CREATE CAST (FIXEDDECIMAL AS NUMERIC) + WITH FUNCTION fixeddecimal_numeric (FIXEDDECIMAL) AS IMPLICIT; + +CREATE CAST (NUMERIC AS FIXEDDECIMAL) + WITH FUNCTION numeric_fixeddecimal (NUMERIC) AS IMPLICIT; + +CREATE DOMAIN sys.MONEY as sys.FIXEDDECIMAL CHECK (VALUE >= -922337203685477.5808 AND VALUE <= 922337203685477.5807); +CREATE DOMAIN sys.SMALLMONEY as sys.FIXEDDECIMAL CHECK (VALUE >= -214748.3648 AND VALUE <= 214748.3647); +-- 13 "sql/babelfishpg_common.in" 2 +-- 1 "sql/money/fixeddecimal--parallelaggs.sql" 1 + +-- Aggregate Support + +CREATE FUNCTION sys.fixeddecimalaggstatecombine(INTERNAL, INTERNAL) +RETURNS INTERNAL +AS 'babelfishpg_money', 'fixeddecimalaggstatecombine' +LANGUAGE C IMMUTABLE PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalaggstateserialize(INTERNAL) +RETURNS BYTEA +AS 'babelfishpg_money', 'fixeddecimalaggstateserialize' +LANGUAGE C IMMUTABLE PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalaggstatedeserialize(BYTEA, INTERNAL) +RETURNS INTERNAL +AS 'babelfishpg_money', 'fixeddecimalaggstatedeserialize' +LANGUAGE C IMMUTABLE PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_avg_accum(INTERNAL, FIXEDDECIMAL) +RETURNS INTERNAL +AS 'babelfishpg_money', 'fixeddecimal_avg_accum' +LANGUAGE C IMMUTABLE PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_sum(INTERNAL) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'fixeddecimal_sum' +LANGUAGE C IMMUTABLE PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_avg(INTERNAL) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'fixeddecimal_avg' +LANGUAGE C IMMUTABLE PARALLEL SAFE; + +CREATE AGGREGATE sys.min(FIXEDDECIMAL) ( + SFUNC = fixeddecimalsmaller, + STYPE = FIXEDDECIMAL, + SORTOP = <, + COMBINEFUNC = fixeddecimalsmaller, + PARALLEL = SAFE +); + +CREATE AGGREGATE sys.max(FIXEDDECIMAL) ( + SFUNC = fixeddecimallarger, + STYPE = FIXEDDECIMAL, + SORTOP = >, + COMBINEFUNC = fixeddecimallarger, + PARALLEL = SAFE +); + +CREATE AGGREGATE sys.sum(FIXEDDECIMAL) ( + SFUNC = fixeddecimal_avg_accum, + FINALFUNC = fixeddecimal_sum, + STYPE = INTERNAL, + COMBINEFUNC = fixeddecimalaggstatecombine, + SERIALFUNC = fixeddecimalaggstateserialize, + DESERIALFUNC = fixeddecimalaggstatedeserialize, + PARALLEL = SAFE +); + +CREATE AGGREGATE sys.avg(FIXEDDECIMAL) ( + SFUNC = fixeddecimal_avg_accum, + FINALFUNC = fixeddecimal_avg, + STYPE = INTERNAL, + COMBINEFUNC = fixeddecimalaggstatecombine, + SERIALFUNC = fixeddecimalaggstateserialize, + DESERIALFUNC = fixeddecimalaggstatedeserialize, + PARALLEL = SAFE +); +-- 14 "sql/babelfishpg_common.in" 2 +-- 1 "sql/money/fixeddecimal--brin.sql" 1 +CREATE OPERATOR CLASS sys.fixeddecimal_minmax_ops +DEFAULT FOR TYPE FIXEDDECIMAL USING brin AS + OPERATOR 1 < (FIXEDDECIMAL, FIXEDDECIMAL), + OPERATOR 2 <= (FIXEDDECIMAL, FIXEDDECIMAL), + OPERATOR 3 = (FIXEDDECIMAL, FIXEDDECIMAL), + OPERATOR 4 >= (FIXEDDECIMAL, FIXEDDECIMAL), + OPERATOR 5 > (FIXEDDECIMAL, FIXEDDECIMAL), + FUNCTION 1 brin_minmax_opcinfo(INTERNAL), + FUNCTION 2 brin_minmax_add_value(INTERNAL, INTERNAL, INTERNAL, INTERNAL), + FUNCTION 3 brin_minmax_consistent(INTERNAL, INTERNAL, INTERNAL), + FUNCTION 4 brin_minmax_union(INTERNAL, INTERNAL, INTERNAL); +-- 15 "sql/babelfishpg_common.in" 2 +-- 1 "sql/bpchar.sql" 1 +CREATE TYPE sys.BPCHAR; + +-- Basic functions +CREATE OR REPLACE FUNCTION sys.bpcharin(cstring) +RETURNS sys.BPCHAR +AS 'babelfishpg_common', 'bpcharin' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.bpcharout(sys.BPCHAR) +RETURNS cstring +AS 'bpcharout' +LANGUAGE INTERNAL IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.bpcharrecv(internal) +RETURNS sys.BPCHAR +AS 'babelfishpg_common', 'bpcharrecv' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.bpcharsend(sys.BPCHAR) +RETURNS bytea +AS 'bpcharsend' +LANGUAGE INTERNAL IMMUTABLE STRICT PARALLEL SAFE; + +CREATE TYPE sys.BPCHAR ( + INPUT = sys.bpcharin, + OUTPUT = sys.bpcharout, + RECEIVE = sys.bpcharrecv, + SEND = sys.bpcharsend, + TYPMOD_IN = bpchartypmodin, + TYPMOD_OUT = bpchartypmodout, + CATEGORY = 'S', + COLLATABLE = True, + LIKE = pg_catalog.BPCHAR +); + +-- Basic operator functions +CREATE FUNCTION sys.bpchareq(sys.BPCHAR, sys.BPCHAR) +RETURNS bool +AS 'bpchareq' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.bpcharne(sys.BPCHAR, sys.BPCHAR) +RETURNS bool +AS 'bpcharne' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.bpcharlt(sys.BPCHAR, sys.BPCHAR) +RETURNS bool +AS 'bpcharlt' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.bpcharle(sys.BPCHAR, sys.BPCHAR) +RETURNS bool +AS 'bpcharle' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.bpchargt(sys.BPCHAR, sys.BPCHAR) +RETURNS bool +AS 'bpchargt' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.bpcharge(sys.BPCHAR, sys.BPCHAR) +RETURNS bool +AS 'bpcharge' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +-- Basic operators +-- Note that if those operators are not in pg_catalog, we will see different behaviors depending on sql_dialect +CREATE OPERATOR pg_catalog.= ( + LEFTARG = sys.BPCHAR, + RIGHTARG = sys.BPCHAR, + COMMUTATOR = OPERATOR(pg_catalog.=), + NEGATOR = OPERATOR(pg_catalog.<>), + PROCEDURE = sys.bpchareq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES, + HASHES +); + +CREATE OPERATOR pg_catalog.<> ( + LEFTARG = sys.BPCHAR, + RIGHTARG = sys.BPCHAR, + NEGATOR = OPERATOR(pg_catalog.=), + COMMUTATOR = OPERATOR(pg_catalog.<>), + PROCEDURE = sys.bpcharne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR pg_catalog.< ( + LEFTARG = sys.BPCHAR, + RIGHTARG = sys.BPCHAR, + NEGATOR = OPERATOR(pg_catalog.>=), + COMMUTATOR = OPERATOR(pg_catalog.>), + PROCEDURE = sys.bpcharlt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR pg_catalog.<= ( + LEFTARG = sys.BPCHAR, + RIGHTARG = sys.BPCHAR, + NEGATOR = OPERATOR(pg_catalog.>), + COMMUTATOR = OPERATOR(pg_catalog.>=), + PROCEDURE = sys.bpcharle, + RESTRICT = scalarlesel, + JOIN = scalarlejoinsel +); + +CREATE OPERATOR pg_catalog.> ( + LEFTARG = sys.BPCHAR, + RIGHTARG = sys.BPCHAR, + NEGATOR = OPERATOR(pg_catalog.<=), + COMMUTATOR = OPERATOR(pg_catalog.<), + PROCEDURE = sys.bpchargt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR pg_catalog.>= ( + LEFTARG = sys.BPCHAR, + RIGHTARG = sys.BPCHAR, + NEGATOR = OPERATOR(pg_catalog.<), + COMMUTATOR = OPERATOR(pg_catalog.<=), + PROCEDURE = sys.bpcharge, + RESTRICT = scalargesel, + JOIN = scalargejoinsel +); + +-- Operator classes +CREATE FUNCTION sys.bpcharcmp(sys.BPCHAR, sys.BPCHAR) +RETURNS INT4 +AS 'bpcharcmp' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.hashbpchar(sys.BPCHAR) +RETURNS INT4 +AS 'hashbpchar' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR CLASS bpchar_ops + DEFAULT FOR TYPE sys.BPCHAR USING btree AS + OPERATOR 1 pg_catalog.< (sys.BPCHAR, sys.BPCHAR), + OPERATOR 2 pg_catalog.<= (sys.BPCHAR, sys.BPCHAR), + OPERATOR 3 pg_catalog.= (sys.BPCHAR, sys.BPCHAR), + OPERATOR 4 pg_catalog.>= (sys.BPCHAR, sys.BPCHAR), + OPERATOR 5 pg_catalog.> (sys.BPCHAR, sys.BPCHAR), + FUNCTION 1 sys.bpcharcmp(sys.BPCHAR, sys.BPCHAR); + +CREATE OPERATOR CLASS bpchar_ops + DEFAULT FOR TYPE sys.BPCHAR USING hash AS + OPERATOR 1 pg_catalog.= (sys.BPCHAR, sys.BPCHAR), + FUNCTION 1 sys.hashbpchar(sys.BPCHAR); + +CREATE OR REPLACE FUNCTION sys.bpchar(sys.BPCHAR, integer, boolean) +RETURNS sys.BPCHAR +AS 'babelfishpg_common', 'bpchar' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- To sys.BPCHAR +CREATE CAST (sys.BPCHAR AS sys.BPCHAR) +WITH FUNCTION sys.BPCHAR (sys.BPCHAR, integer, boolean) AS IMPLICIT; + +CREATE CAST (pg_catalog.VARCHAR as sys.BPCHAR) +WITHOUT FUNCTION AS IMPLICIT; + +CREATE CAST (pg_catalog.TEXT as sys.BPCHAR) +WITHOUT FUNCTION AS IMPLICIT; + +CREATE CAST (pg_catalog.BOOL as sys.BPCHAR) +WITH FUNCTION pg_catalog.text(pg_catalog.BOOL) AS ASSIGNMENT; + +-- From sys.BPCHAR +CREATE CAST (sys.BPCHAR AS pg_catalog.BPCHAR) +WITHOUT FUNCTION AS IMPLICIT; + +CREATE CAST (sys.BPCHAR as pg_catalog.VARCHAR) +WITHOUT FUNCTION AS IMPLICIT; + +CREATE CAST (sys.BPCHAR as pg_catalog.TEXT) +WITHOUT FUNCTION AS IMPLICIT; + +-- Operators between different types +CREATE FUNCTION sys.bpchareq(sys.BPCHAR, pg_catalog.TEXT) +RETURNS bool +AS 'bpchareq' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.bpchareq(pg_catalog.TEXT, sys.BPCHAR) +RETURNS bool +AS 'bpchareq' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.bpcharne(sys.BPCHAR, pg_catalog.TEXT) +RETURNS bool +AS 'bpcharne' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.bpcharne(pg_catalog.TEXT, sys.BPCHAR) +RETURNS bool +AS 'bpcharne' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR pg_catalog.= ( + LEFTARG = sys.BPCHAR, + RIGHTARG = pg_catalog.TEXT, + COMMUTATOR = OPERATOR(pg_catalog.=), + NEGATOR = OPERATOR(pg_catalog.<>), + PROCEDURE = sys.bpchareq, + RESTRICT = eqsel, + JOIN = eqjoinsel +); + +CREATE OPERATOR pg_catalog.= ( + LEFTARG = pg_catalog.TEXT, + RIGHTARG = sys.BPCHAR, + COMMUTATOR = OPERATOR(pg_catalog.=), + NEGATOR = OPERATOR(pg_catalog.<>), + PROCEDURE = sys.bpchareq, + RESTRICT = eqsel, + JOIN = eqjoinsel +); + +CREATE OPERATOR pg_catalog.<> ( + LEFTARG = sys.BPCHAR, + RIGHTARG = pg_catalog.TEXT, + NEGATOR = OPERATOR(pg_catalog.=), + COMMUTATOR = OPERATOR(pg_catalog.<>), + PROCEDURE = sys.bpcharne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR pg_catalog.<> ( + LEFTARG = pg_catalog.TEXT, + RIGHTARG = sys.BPCHAR, + NEGATOR = OPERATOR(pg_catalog.=), + COMMUTATOR = OPERATOR(pg_catalog.<>), + PROCEDURE = sys.bpcharne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +SET enable_domain_typmod = TRUE; +CREATE DOMAIN sys.NCHAR AS sys.BPCHAR; +RESET enable_domain_typmod; + +CREATE OR REPLACE FUNCTION sys.nchar(sys.nchar, integer, boolean) +RETURNS sys.nchar +AS 'babelfishpg_common', 'bpchar' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + + +SET client_min_messages = 'ERROR'; +CREATE CAST (sys.nchar AS sys.nchar) +WITH FUNCTION sys.nchar (sys.nchar, integer, BOOLEAN) AS ASSIGNMENT; +SET client_min_messages = 'WARNING'; +-- 16 "sql/babelfishpg_common.in" 2 +-- 1 "sql/varchar.sql" 1 +CREATE TYPE sys.VARCHAR; + +-- Basic functions +CREATE OR REPLACE FUNCTION sys.varcharin(cstring) +RETURNS sys.VARCHAR +AS 'babelfishpg_common', 'varcharin' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.varcharout(sys.VARCHAR) +RETURNS cstring +AS 'varcharout' +LANGUAGE INTERNAL IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.varcharrecv(internal) +RETURNS sys.VARCHAR +AS 'babelfishpg_common', 'varcharrecv' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.varcharsend(sys.VARCHAR) +RETURNS bytea +AS 'varcharsend' +LANGUAGE INTERNAL IMMUTABLE STRICT PARALLEL SAFE; + +CREATE TYPE sys.VARCHAR ( + INPUT = sys.varcharin, + OUTPUT = sys.varcharout, + RECEIVE = sys.varcharrecv, + SEND = sys.varcharsend, + TYPMOD_IN = varchartypmodin, + TYPMOD_OUT = varchartypmodout, + CATEGORY = 'S', + COLLATABLE = True, + LIKE = pg_catalog.VARCHAR +); + +-- Basic operator functions +CREATE FUNCTION sys.varchareq(sys.VARCHAR, sys.VARCHAR) +RETURNS bool +AS 'babelfishpg_common', 'varchareq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.varcharne(sys.VARCHAR, sys.VARCHAR) +RETURNS bool +AS 'babelfishpg_common', 'varcharne' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.varcharlt(sys.VARCHAR, sys.VARCHAR) +RETURNS bool +AS 'babelfishpg_common', 'varcharlt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.varcharle(sys.VARCHAR, sys.VARCHAR) +RETURNS bool +AS 'babelfishpg_common', 'varcharle' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.varchargt(sys.VARCHAR, sys.VARCHAR) +RETURNS bool +AS 'babelfishpg_common', 'varchargt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.varcharge(sys.VARCHAR, sys.VARCHAR) +RETURNS bool +AS 'babelfishpg_common', 'varcharge' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- Basic operators +-- Note that if those operators are not in pg_catalog, we will see different behaviors depending on sql_dialect +CREATE OPERATOR pg_catalog.= ( + LEFTARG = sys.VARCHAR, + RIGHTARG = sys.VARCHAR, + COMMUTATOR = OPERATOR(pg_catalog.=), + NEGATOR = OPERATOR(pg_catalog.<>), + PROCEDURE = sys.varchareq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES, + HASHES +); + +CREATE OPERATOR pg_catalog.<> ( + LEFTARG = sys.VARCHAR, + RIGHTARG = sys.VARCHAR, + NEGATOR = OPERATOR(pg_catalog.=), + COMMUTATOR = OPERATOR(pg_catalog.<>), + PROCEDURE = sys.varcharne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR pg_catalog.< ( + LEFTARG = sys.VARCHAR, + RIGHTARG = sys.VARCHAR, + NEGATOR = OPERATOR(pg_catalog.>=), + COMMUTATOR = OPERATOR(pg_catalog.>), + PROCEDURE = sys.varcharlt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR pg_catalog.<= ( + LEFTARG = sys.VARCHAR, + RIGHTARG = sys.VARCHAR, + NEGATOR = OPERATOR(pg_catalog.>), + COMMUTATOR = OPERATOR(pg_catalog.>=), + PROCEDURE = sys.varcharle, + RESTRICT = scalarlesel, + JOIN = scalarlejoinsel +); + +CREATE OPERATOR pg_catalog.> ( + LEFTARG = sys.VARCHAR, + RIGHTARG = sys.VARCHAR, + NEGATOR = OPERATOR(pg_catalog.<=), + COMMUTATOR = OPERATOR(pg_catalog.<), + PROCEDURE = sys.varchargt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR pg_catalog.>= ( + LEFTARG = sys.VARCHAR, + RIGHTARG = sys.VARCHAR, + NEGATOR = OPERATOR(pg_catalog.<), + COMMUTATOR = OPERATOR(pg_catalog.<=), + PROCEDURE = sys.varcharge, + RESTRICT = scalargesel, + JOIN = scalargejoinsel +); + +-- Operator classes +CREATE FUNCTION sys.varcharcmp(sys.VARCHAR, sys.VARCHAR) +RETURNS INT4 +AS 'babelfishpg_common', 'varcharcmp' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.hashvarchar(sys.VARCHAR) +RETURNS INT4 +AS 'babelfishpg_common', 'hashvarchar' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR CLASS varchar_ops + DEFAULT FOR TYPE sys.VARCHAR USING btree AS + OPERATOR 1 pg_catalog.< (sys.VARCHAR, sys.VARCHAR), + OPERATOR 2 pg_catalog.<= (sys.VARCHAR, sys.VARCHAR), + OPERATOR 3 pg_catalog.= (sys.VARCHAR, sys.VARCHAR), + OPERATOR 4 pg_catalog.>= (sys.VARCHAR, sys.VARCHAR), + OPERATOR 5 pg_catalog.> (sys.VARCHAR, sys.VARCHAR), + FUNCTION 1 sys.varcharcmp(sys.VARCHAR, sys.VARCHAR); + +CREATE OPERATOR CLASS varchar_ops + DEFAULT FOR TYPE sys.VARCHAR USING hash AS + OPERATOR 1 pg_catalog.= (sys.VARCHAR, sys.VARCHAR), + FUNCTION 1 sys.hashvarchar(sys.VARCHAR); + +-- Typmode cast function +CREATE OR REPLACE FUNCTION sys.varchar(sys.VARCHAR, integer, boolean) +RETURNS sys.VARCHAR +AS 'babelfishpg_common', 'varchar' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- To sys.VARCHAR +CREATE CAST (sys.VARCHAR AS sys.VARCHAR) +WITH FUNCTION sys.VARCHAR (sys.VARCHAR, integer, boolean) AS IMPLICIT; + +CREATE CAST (pg_catalog.VARCHAR as sys.VARCHAR) +WITHOUT FUNCTION AS IMPLICIT; + +CREATE CAST (pg_catalog.TEXT as sys.VARCHAR) +WITHOUT FUNCTION AS IMPLICIT; + +CREATE CAST (sys.BPCHAR as sys.VARCHAR) +WITHOUT FUNCTION AS IMPLICIT; + +CREATE CAST (pg_catalog.BOOL as sys.VARCHAR) +WITH FUNCTION pg_catalog.text(pg_catalog.BOOL) AS ASSIGNMENT; + +-- From sys.VARCHAR +CREATE CAST (sys.VARCHAR AS pg_catalog.VARCHAR) +WITHOUT FUNCTION AS IMPLICIT; + +CREATE CAST (sys.VARCHAR as pg_catalog.TEXT) +WITHOUT FUNCTION AS IMPLICIT; + +CREATE CAST (sys.VARCHAR as pg_catalog.BPCHAR) +WITHOUT FUNCTION AS IMPLICIT; + +SET enable_domain_typmod = TRUE; +CREATE DOMAIN sys.NVARCHAR AS sys.VARCHAR; +RESET enable_domain_typmod; + +CREATE OR REPLACE FUNCTION sys.nvarchar(sys.nvarchar, integer, boolean) +RETURNS sys.nvarchar +AS 'babelfishpg_common', 'varchar' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +SET client_min_messages = 'ERROR'; +CREATE CAST (sys.nvarchar AS sys.nvarchar) +WITH FUNCTION sys.nvarchar (sys.nvarchar, integer, BOOLEAN) AS ASSIGNMENT; +SET client_min_messages = 'WARNING'; +-- 17 "sql/babelfishpg_common.in" 2 +-- 1 "sql/numerics.sql" 1 +CREATE DOMAIN sys.TINYINT AS SMALLINT CHECK (VALUE >= 0 AND VALUE <= 255); +CREATE DOMAIN sys.INT AS INTEGER; +CREATE DOMAIN sys.BIGINT AS BIGINT; +CREATE DOMAIN sys.REAL AS REAL; +CREATE DOMAIN sys.FLOAT AS DOUBLE PRECISION; + +-- Types with different default typmod behavior +SET enable_domain_typmod = TRUE; +CREATE DOMAIN sys.DECIMAL AS NUMERIC; +RESET enable_domain_typmod; + +-- Domain Self Cast Functions to support Typmod Cast in Domain +CREATE OR REPLACE FUNCTION sys.decimal(sys.nchar, integer, boolean) +RETURNS sys.nchar +AS 'numeric' +LANGUAGE INTERNAL IMMUTABLE STRICT PARALLEL SAFE; + + +CREATE OR REPLACE FUNCTION sys.tinyintxor(leftarg sys.tinyint, rightarg sys.tinyint) +RETURNS sys.tinyint +AS $$ +SELECT CAST(CAST(sys.bitxor(CAST(CAST(leftarg AS int4) AS pg_catalog.bit(16)), + CAST(CAST(rightarg AS int4) AS pg_catalog.bit(16))) AS int4) AS sys.tinyint); +$$ +LANGUAGE SQL; + +CREATE OPERATOR sys.^ ( + LEFTARG = sys.tinyint, + RIGHTARG = sys.tinyint, + FUNCTION = sys.tinyintxor, + COMMUTATOR = ^ +); + +CREATE OR REPLACE FUNCTION sys.int2xor(leftarg int2, rightarg int2) +RETURNS int2 +AS $$ +SELECT CAST(CAST(sys.bitxor(CAST(CAST(leftarg AS int4) AS pg_catalog.bit(16)), + CAST(CAST(rightarg AS int4) AS pg_catalog.bit(16))) AS int4) AS int2); +$$ +LANGUAGE SQL; + +CREATE OPERATOR sys.^ ( + LEFTARG = int2, + RIGHTARG = int2, + FUNCTION = sys.int2xor, + COMMUTATOR = ^ +); + +CREATE OR REPLACE FUNCTION sys.intxor(leftarg int4, rightarg int4) +RETURNS int4 +AS $$ +SELECT CAST(sys.bitxor(CAST(leftarg AS pg_catalog.bit(32)), + CAST(rightarg AS pg_catalog.bit(32))) AS int4) +$$ +LANGUAGE SQL; + +CREATE OPERATOR sys.^ ( + LEFTARG = int4, + RIGHTARG = int4, + FUNCTION = sys.intxor, + COMMUTATOR = ^ +); + +CREATE OR REPLACE FUNCTION sys.int8xor(leftarg int8, rightarg int8) +RETURNS int8 +AS $$ +SELECT CAST(sys.bitxor(CAST(leftarg AS pg_catalog.bit(64)), + CAST(rightarg AS pg_catalog.bit(64))) AS int8) +$$ +LANGUAGE SQL; + +CREATE OPERATOR sys.^ ( + LEFTARG = int8, + RIGHTARG = int8, + FUNCTION = sys.int8xor, + COMMUTATOR = ^ +); +-- 18 "sql/babelfishpg_common.in" 2 +-- 1 "sql/strings.sql" 1 +CREATE DOMAIN sys.NTEXT AS TEXT; +CREATE DOMAIN sys.SYSNAME AS sys.VARCHAR(128); +-- 19 "sql/babelfishpg_common.in" 2 +-- 1 "sql/bit.sql" 1 +CREATE TYPE sys.BIT; + +CREATE OR REPLACE FUNCTION sys.bitin(cstring) +RETURNS sys.BIT +AS 'babelfishpg_common', 'bitin' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.bitout(sys.BIT) +RETURNS cstring +AS 'babelfishpg_common', 'bitout' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.bitrecv(internal) +RETURNS sys.BIT +AS 'babelfishpg_common', 'bitrecv' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.bitsend(sys.BIT) +RETURNS bytea +AS 'babelfishpg_common', 'bitsend' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE TYPE sys.BIT ( + INPUT = sys.bitin, + OUTPUT = sys.bitout, + RECEIVE = sys.bitrecv, + SEND = sys.bitsend, + INTERNALLENGTH = 1, + PASSEDBYVALUE, + ALIGNMENT = 'char', + STORAGE = 'plain', + CATEGORY = 'B', + PREFERRED = true, + COLLATABLE = false + ); + +CREATE OR REPLACE FUNCTION sys.int2bit(INT2) +RETURNS sys.BIT +AS 'babelfishpg_common', 'int2bit' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (INT2 AS sys.BIT) +WITH FUNCTION sys.int2bit (INT2) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.int4bit(INT4) +RETURNS sys.BIT +AS 'babelfishpg_common', 'int4bit' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (INT4 AS sys.BIT) +WITH FUNCTION sys.int4bit (INT4) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.int8bit(INT8) +RETURNS sys.BIT +AS 'babelfishpg_common', 'int8bit' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (INT8 AS sys.BIT) +WITH FUNCTION sys.int8bit (INT8) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.ftobit(REAL) +RETURNS sys.BIT +AS 'babelfishpg_common', 'ftobit' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (REAL AS sys.BIT) +WITH FUNCTION sys.ftobit (REAL) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.dtobit(DOUBLE PRECISION) +RETURNS sys.BIT +AS 'babelfishpg_common', 'dtobit' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (DOUBLE PRECISION AS sys.BIT) +WITH FUNCTION sys.dtobit (DOUBLE PRECISION) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.numeric_bit(NUMERIC) +RETURNS sys.BIT +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; + +CREATE OR REPLACE FUNCTION sys.bit2int2(sys.BIT) +RETURNS INT2 +AS 'babelfishpg_common', 'bit2int2' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BIT AS INT2) +WITH FUNCTION sys.bit2int2 (sys.BIT) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.bit2int4(sys.BIT) +RETURNS INT4 +AS 'babelfishpg_common', 'bit2int4' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BIT AS INT4) +WITH FUNCTION sys.bit2int4 (sys.BIT) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.bit2int8(sys.BIT) +RETURNS INT8 +AS 'babelfishpg_common', 'bit2int8' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BIT AS INT8) +WITH FUNCTION sys.bit2int8 (sys.BIT) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.bit2numeric(sys.BIT) +RETURNS NUMERIC +AS 'babelfishpg_common', 'bit2numeric' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BIT AS NUMERIC) +WITH FUNCTION sys.bit2numeric (sys.BIT) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.bit2fixeddec(sys.BIT) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_common', 'bit2fixeddec' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BIT AS FIXEDDECIMAL) +WITH FUNCTION sys.bit2fixeddec (sys.BIT) AS IMPLICIT; + +CREATE FUNCTION sys.bitneg(sys.BIT) +RETURNS sys.BIT +AS 'babelfishpg_common', 'bitneg' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.biteq(sys.BIT, sys.BIT) +RETURNS bool +AS 'babelfishpg_common', 'biteq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.bitne(sys.BIT, sys.BIT) +RETURNS bool +AS 'babelfishpg_common', 'bitne' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.bitlt(sys.BIT, sys.BIT) +RETURNS bool +AS 'babelfishpg_common', 'bitlt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.bitle(sys.BIT, sys.BIT) +RETURNS bool +AS 'babelfishpg_common', 'bitle' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.bitgt(sys.BIT, sys.BIT) +RETURNS bool +AS 'babelfishpg_common', 'bitgt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.bitge(sys.BIT, sys.BIT) +RETURNS bool +AS 'babelfishpg_common', 'bitge' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.bit_cmp(sys.BIT, sys.BIT) +RETURNS int +AS 'babelfishpg_common', 'bit_cmp' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- Operators for sys.BIT. TSQL doesn't support + - * / of bit +CREATE OPERATOR sys.- ( + RIGHTARG = sys.BIT, + PROCEDURE = sys.bitneg +); + +CREATE OPERATOR sys.= ( + LEFTARG = sys.BIT, + RIGHTARG = sys.BIT, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = sys.biteq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR sys.<> ( + LEFTARG = sys.BIT, + RIGHTARG = sys.BIT, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = sys.bitne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR sys.< ( + LEFTARG = sys.BIT, + RIGHTARG = sys.BIT, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = sys.bitlt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.<= ( + LEFTARG = sys.BIT, + RIGHTARG = sys.BIT, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = sys.bitle, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.> ( + LEFTARG = sys.BIT, + RIGHTARG = sys.BIT, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = sys.bitgt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.>= ( + LEFTARG = sys.BIT, + RIGHTARG = sys.BIT, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = sys.bitge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR CLASS sys.bit_ops +DEFAULT FOR TYPE sys.bit USING btree AS + OPERATOR 1 < (sys.bit, sys.bit), + OPERATOR 2 <= (sys.bit, sys.bit), + OPERATOR 3 = (sys.bit, sys.bit), + OPERATOR 4 >= (sys.bit, sys.bit), + OPERATOR 5 > (sys.bit, sys.bit), + FUNCTION 1 sys.bit_cmp(sys.bit, sys.bit); + + +CREATE FUNCTION sys.int4biteq(INT4, sys.BIT) +RETURNS bool +AS 'babelfishpg_common', 'int4biteq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int4bitne(INT4, sys.BIT) +RETURNS bool +AS 'babelfishpg_common', 'int4bitne' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int4bitlt(INT4, sys.BIT) +RETURNS bool +AS 'babelfishpg_common', 'int4bitlt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int4bitle(INT4, sys.BIT) +RETURNS bool +AS 'babelfishpg_common', 'int4bitle' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int4bitgt(INT4, sys.BIT) +RETURNS bool +AS 'babelfishpg_common', 'int4bitgt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int4bitge(INT4, sys.BIT) +RETURNS bool +AS 'babelfishpg_common', 'int4bitge' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.= ( + LEFTARG = INT4, + RIGHTARG = sys.BIT, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = sys.int4biteq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR sys.<> ( + LEFTARG = INT4, + RIGHTARG = sys.BIT, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = sys.int4bitne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR sys.< ( + LEFTARG = INT4, + RIGHTARG = sys.BIT, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = sys.int4bitlt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.<= ( + LEFTARG = INT4, + RIGHTARG = sys.BIT, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = sys.int4bitle, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.> ( + LEFTARG = INT4, + RIGHTARG = sys.BIT, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = sys.int4bitgt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.>= ( + LEFTARG = INT4, + RIGHTARG = sys.BIT, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = sys.int4bitge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + + +CREATE FUNCTION sys.bitint4eq(sys.BIT, INT4) +RETURNS bool +AS 'babelfishpg_common', 'bitint4eq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.bitint4ne(sys.BIT, INT4) +RETURNS bool +AS 'babelfishpg_common', 'bitint4ne' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.bitint4lt(sys.BIT, INT4) +RETURNS bool +AS 'babelfishpg_common', 'bitint4lt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.bitint4le(sys.BIT, INT4) +RETURNS bool +AS 'babelfishpg_common', 'bitint4le' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.bitint4gt(sys.BIT, INT4) +RETURNS bool +AS 'babelfishpg_common', 'bitint4gt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.bitint4ge(sys.BIT, INT4) +RETURNS bool +AS 'babelfishpg_common', 'bitint4ge' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.= ( + LEFTARG = sys.BIT, + RIGHTARG = INT4, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = sys.bitint4eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR sys.<> ( + LEFTARG = sys.BIT, + RIGHTARG = INT4, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = sys.bitint4ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR sys.< ( + LEFTARG = sys.BIT, + RIGHTARG = INT4, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = sys.bitint4lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.<= ( + LEFTARG = sys.BIT, + RIGHTARG = INT4, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = sys.bitint4le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.> ( + LEFTARG = sys.BIT, + RIGHTARG = INT4, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = sys.bitint4gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.>= ( + LEFTARG = sys.BIT, + RIGHTARG = INT4, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = sys.bitint4ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OR REPLACE FUNCTION sys.bitxor(leftarg pg_catalog.bit, rightarg pg_catalog.bit) +RETURNS pg_catalog.bit +AS $$ +SELECT (leftarg & ~rightarg) | (~leftarg & rightarg); +$$ +LANGUAGE SQL; +-- 20 "sql/babelfishpg_common.in" 2 +-- 1 "sql/varbinary.sql" 1 +-- VARBINARY +CREATE TYPE sys.BBF_VARBINARY; + +CREATE OR REPLACE FUNCTION sys.varbinaryin(cstring, oid, integer) +RETURNS sys.BBF_VARBINARY +AS 'babelfishpg_common', 'varbinaryin' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.varbinaryout(sys.BBF_VARBINARY) +RETURNS cstring +AS 'babelfishpg_common', 'varbinaryout' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.varbinaryrecv(internal, oid, integer) +RETURNS sys.BBF_VARBINARY +AS 'babelfishpg_common', 'varbinaryrecv' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.varbinarysend(sys.BBF_VARBINARY) +RETURNS bytea +AS 'babelfishpg_common', 'varbinarysend' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.varbinarytypmodin(cstring[]) +RETURNS integer +AS 'babelfishpg_common', 'varbinarytypmodin' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.varbinarytypmodout(integer) +RETURNS cstring +AS 'babelfishpg_common', 'varbinarytypmodout' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE TYPE sys.BBF_VARBINARY ( + INPUT = sys.varbinaryin, + OUTPUT = sys.varbinaryout, + RECEIVE = sys.varbinaryrecv, + SEND = sys.varbinarysend, + TYPMOD_IN = sys.varbinarytypmodin, + TYPMOD_OUT = sys.varbinarytypmodout, + INTERNALLENGTH = VARIABLE, + ALIGNMENT = 'int4', + STORAGE = 'extended', + CATEGORY = 'U', + PREFERRED = false, + COLLATABLE = false +); + +CREATE OR REPLACE FUNCTION sys.varcharvarbinary(sys.VARCHAR, integer, boolean) +RETURNS sys.BBF_VARBINARY +AS 'babelfishpg_common', 'varcharvarbinary' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.VARCHAR AS sys.BBF_VARBINARY) +WITH FUNCTION sys.varcharvarbinary (sys.VARCHAR, integer, boolean) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.varcharvarbinary(pg_catalog.VARCHAR, integer, boolean) +RETURNS sys.BBF_VARBINARY +AS 'babelfishpg_common', 'varcharvarbinary' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (pg_catalog.VARCHAR AS sys.BBF_VARBINARY) +WITH FUNCTION sys.varcharvarbinary (pg_catalog.VARCHAR, integer, boolean) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.bpcharvarbinary(pg_catalog.BPCHAR, integer, boolean) +RETURNS sys.BBF_VARBINARY +AS 'babelfishpg_common', 'bpcharvarbinary' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (pg_catalog.BPCHAR AS sys.BBF_VARBINARY) +WITH FUNCTION sys.bpcharvarbinary (pg_catalog.BPCHAR, integer, boolean) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.bpcharvarbinary(sys.BPCHAR, integer, boolean) +RETURNS sys.BBF_VARBINARY +AS 'babelfishpg_common', 'bpcharvarbinary' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BPCHAR AS sys.BBF_VARBINARY) +WITH FUNCTION sys.bpcharvarbinary (sys.BPCHAR, integer, boolean) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.varbinarysysvarchar(sys.BBF_VARBINARY, integer, boolean) +RETURNS sys.VARCHAR +AS 'babelfishpg_common', 'varbinaryvarchar' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BBF_VARBINARY AS sys.VARCHAR) +WITH FUNCTION sys.varbinarysysvarchar (sys.BBF_VARBINARY, integer, boolean) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.varbinaryvarchar(sys.BBF_VARBINARY, integer, boolean) +RETURNS pg_catalog.VARCHAR +AS 'babelfishpg_common', 'varbinaryvarchar' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BBF_VARBINARY AS pg_catalog.VARCHAR) +WITH FUNCTION sys.varbinaryvarchar (sys.BBF_VARBINARY, integer, boolean) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.int2varbinary(INT2, integer, boolean) +RETURNS sys.BBF_VARBINARY +AS 'babelfishpg_common', 'int2varbinary' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (INT2 AS sys.BBF_VARBINARY) +WITH FUNCTION sys.int2varbinary (INT2, integer, boolean) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.int4varbinary(INT4, integer, boolean) +RETURNS sys.BBF_VARBINARY +AS 'babelfishpg_common', 'int4varbinary' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (INT4 AS sys.BBF_VARBINARY) +WITH FUNCTION sys.int4varbinary (INT4, integer, boolean) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.int8varbinary(INT8, integer, boolean) +RETURNS sys.BBF_VARBINARY +AS 'babelfishpg_common', 'int8varbinary' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (INT8 AS sys.BBF_VARBINARY) +WITH FUNCTION sys.int8varbinary (INT8, integer, boolean) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.float4varbinary(REAL, integer, boolean) +RETURNS sys.BBF_VARBINARY +AS 'babelfishpg_common', 'float4varbinary' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (REAL AS sys.BBF_VARBINARY) +WITH FUNCTION sys.float4varbinary (REAL, integer, boolean) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.float8varbinary(DOUBLE PRECISION, integer, boolean) +RETURNS sys.BBF_VARBINARY +AS 'babelfishpg_common', 'float8varbinary' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (DOUBLE PRECISION AS sys.BBF_VARBINARY) +WITH FUNCTION sys.float8varbinary (DOUBLE PRECISION, integer, boolean) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.varbinaryint2(sys.BBF_VARBINARY) +RETURNS INT2 +AS 'babelfishpg_common', 'varbinaryint2' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BBF_VARBINARY as INT2) +WITH FUNCTION sys.varbinaryint2 (sys.BBF_VARBINARY) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.varbinaryint4(sys.BBF_VARBINARY) +RETURNS INT4 +AS 'babelfishpg_common', 'varbinaryint4' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BBF_VARBINARY as INT4) +WITH FUNCTION sys.varbinaryint4 (sys.BBF_VARBINARY) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.varbinaryint8(sys.BBF_VARBINARY) +RETURNS INT8 +AS 'babelfishpg_common', 'varbinaryint8' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BBF_VARBINARY as INT8) +WITH FUNCTION sys.varbinaryint8 (sys.BBF_VARBINARY) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.varbinaryfloat4(sys.BBF_VARBINARY) +RETURNS REAL +AS 'babelfishpg_common', 'varbinaryfloat4' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BBF_VARBINARY as REAL) +WITH FUNCTION sys.varbinaryfloat4 (sys.BBF_VARBINARY) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.varbinaryfloat8(sys.BBF_VARBINARY) +RETURNS DOUBLE PRECISION +AS 'babelfishpg_common', 'varbinaryfloat8' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BBF_VARBINARY as DOUBLE PRECISION) +WITH FUNCTION sys.varbinaryfloat8 (sys.BBF_VARBINARY) AS ASSIGNMENT; + +SET enable_domain_typmod = TRUE; +CREATE DOMAIN sys.VARBINARY AS sys.BBF_VARBINARY; +RESET enable_domain_typmod; + +CREATE OR REPLACE FUNCTION sys.varbinary(sys.VARBINARY, integer, boolean) +RETURNS sys.VARBINARY +AS 'babelfishpg_common', 'varbinary' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +SET client_min_messages = 'ERROR'; +CREATE CAST (sys.VARBINARY AS sys.VARBINARY) +WITH FUNCTION sys.varbinary (sys.VARBINARY, integer, BOOLEAN) AS ASSIGNMENT; +SET client_min_messages = 'WARNING'; + +-- Add support for varbinary and binary with operators +-- Support equals +CREATE FUNCTION sys.varbinary_eq(leftarg sys.bbf_varbinary, rightarg sys.bbf_varbinary) +RETURNS boolean +AS 'babelfishpg_common', 'varbinary_eq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.= ( + LEFTARG = sys.bbf_varbinary, + RIGHTARG = sys.bbf_varbinary, + FUNCTION = sys.varbinary_eq, + COMMUTATOR = = +); + +-- Support not equals +CREATE FUNCTION sys.varbinary_neq(leftarg sys.bbf_varbinary, rightarg sys.bbf_varbinary) +RETURNS boolean +AS 'babelfishpg_common', 'varbinary_neq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.<> ( + LEFTARG = sys.bbf_varbinary, + RIGHTARG = sys.bbf_varbinary, + FUNCTION = sys.varbinary_neq, + COMMUTATOR = <> +); + +-- Support greater than +CREATE FUNCTION sys.varbinary_gt(leftarg sys.bbf_varbinary, rightarg sys.bbf_varbinary) +RETURNS boolean +AS 'babelfishpg_common', 'varbinary_gt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.> ( + LEFTARG = sys.bbf_varbinary, + RIGHTARG = sys.bbf_varbinary, + FUNCTION = sys.varbinary_gt, + COMMUTATOR = < +); + +-- Support greater than equals +CREATE FUNCTION sys.varbinary_geq(leftarg sys.bbf_varbinary, rightarg sys.bbf_varbinary) +RETURNS boolean +AS 'babelfishpg_common', 'varbinary_geq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.>= ( + LEFTARG = sys.bbf_varbinary, + RIGHTARG = sys.bbf_varbinary, + FUNCTION = sys.varbinary_geq, + COMMUTATOR = <= +); + +-- Support less than +CREATE FUNCTION sys.varbinary_lt(leftarg sys.bbf_varbinary, rightarg sys.bbf_varbinary) +RETURNS boolean +AS 'babelfishpg_common', 'varbinary_lt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.< ( + LEFTARG = sys.bbf_varbinary, + RIGHTARG = sys.bbf_varbinary, + FUNCTION = sys.varbinary_lt, + COMMUTATOR = > +); + +-- Support less than equals +CREATE FUNCTION sys.varbinary_leq(leftarg sys.bbf_varbinary, rightarg sys.bbf_varbinary) +RETURNS boolean +AS 'babelfishpg_common', 'varbinary_leq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.<= ( + LEFTARG = sys.bbf_varbinary, + RIGHTARG = sys.bbf_varbinary, + FUNCTION = sys.varbinary_leq, + COMMUTATOR = >= +); + +CREATE FUNCTION sys.bbf_varbinary_cmp(sys.bbf_varbinary, sys.bbf_varbinary) +RETURNS int +AS 'babelfishpg_common', 'varbinary_cmp' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + + +CREATE OPERATOR CLASS sys.bbf_varbinary_ops +DEFAULT FOR TYPE sys.bbf_varbinary USING btree AS + OPERATOR 1 < (sys.bbf_varbinary, sys.bbf_varbinary), + OPERATOR 2 <= (sys.bbf_varbinary, sys.bbf_varbinary), + OPERATOR 3 = (sys.bbf_varbinary, sys.bbf_varbinary), + OPERATOR 4 >= (sys.bbf_varbinary, sys.bbf_varbinary), + OPERATOR 5 > (sys.bbf_varbinary, sys.bbf_varbinary), + FUNCTION 1 sys.bbf_varbinary_cmp(sys.bbf_varbinary, sys.bbf_varbinary); +-- 21 "sql/babelfishpg_common.in" 2 +-- 1 "sql/binary.sql" 1 +-- sys.BINARY +CREATE TYPE sys.BBF_BINARY; + +CREATE OR REPLACE FUNCTION sys.binaryin(cstring, oid, integer) +RETURNS sys.BBF_BINARY +AS 'babelfishpg_common', 'varbinaryin' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.binaryout(sys.BBF_BINARY) +RETURNS cstring +AS 'babelfishpg_common', 'varbinaryout' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.binaryrecv(internal, oid, integer) +RETURNS sys.BBF_BINARY +AS 'babelfishpg_common', 'varbinaryrecv' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.binarysend(sys.BBF_BINARY) +RETURNS bytea +AS 'babelfishpg_common', 'varbinarysend' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.binarytypmodin(cstring[]) +RETURNS integer +AS 'babelfishpg_common', 'varbinarytypmodin' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.binarytypmodout(integer) +RETURNS cstring +AS 'babelfishpg_common', 'varbinarytypmodout' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE TYPE sys.BBF_BINARY ( + INPUT = sys.binaryin, + OUTPUT = sys.binaryout, + RECEIVE = sys.binaryrecv, + SEND = sys.binarysend, + TYPMOD_IN = sys.binarytypmodin, + TYPMOD_OUT = sys.binarytypmodout, + INTERNALLENGTH = VARIABLE, + ALIGNMENT = 'int4', + STORAGE = 'extended', + CATEGORY = 'U', + PREFERRED = false, + COLLATABLE = false +); + +-- casting functions for sys.BINARY +CREATE OR REPLACE FUNCTION sys.varcharbinary(sys.VARCHAR, integer, boolean) +RETURNS sys.BBF_BINARY +AS 'babelfishpg_common', 'varcharbinary' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.VARCHAR AS sys.BBF_BINARY) +WITH FUNCTION sys.varcharbinary (sys.VARCHAR, integer, boolean) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.varcharbinary(pg_catalog.VARCHAR, integer, boolean) +RETURNS sys.BBF_BINARY +AS 'babelfishpg_common', 'varcharbinary' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (pg_catalog.VARCHAR AS sys.BBF_BINARY) +WITH FUNCTION sys.varcharbinary (pg_catalog.VARCHAR, integer, boolean) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.bpcharbinary(pg_catalog.BPCHAR, integer, boolean) +RETURNS sys.BBF_BINARY +AS 'babelfishpg_common', 'bpcharbinary' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (pg_catalog.BPCHAR AS sys.BBF_BINARY) +WITH FUNCTION sys.bpcharbinary (pg_catalog.BPCHAR, integer, boolean) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.bpcharbinary(sys.BPCHAR, integer, boolean) +RETURNS sys.BBF_BINARY +AS 'babelfishpg_common', 'bpcharbinary' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BPCHAR AS sys.BBF_BINARY) +WITH FUNCTION sys.bpcharbinary (sys.BPCHAR, integer, boolean) AS ASSIGNMENT; + + +CREATE OR REPLACE FUNCTION sys.binarysysvarchar(sys.BBF_BINARY) +RETURNS sys.VARCHAR +AS 'babelfishpg_common', 'varbinaryvarchar' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BBF_BINARY AS sys.VARCHAR) +WITH FUNCTION sys.binarysysvarchar (sys.BBF_BINARY) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.binaryvarchar(sys.BBF_BINARY) +RETURNS pg_catalog.VARCHAR +AS 'babelfishpg_common', 'varbinaryvarchar' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BBF_BINARY AS pg_catalog.VARCHAR) +WITH FUNCTION sys.binaryvarchar (sys.BBF_BINARY) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.int2binary(INT2, integer, boolean) +RETURNS sys.BBF_BINARY +AS 'babelfishpg_common', 'int2binary' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (INT2 AS sys.BBF_BINARY) +WITH FUNCTION sys.int2binary (INT2, integer, boolean) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.int4binary(INT4, integer, boolean) +RETURNS sys.BBF_BINARY +AS 'babelfishpg_common', 'int4binary' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (INT4 AS sys.BBF_BINARY) +WITH FUNCTION sys.int4binary (INT4, integer, boolean) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.int8binary(INT8, integer, boolean) +RETURNS sys.BBF_BINARY +AS 'babelfishpg_common', 'int8binary' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (INT8 AS sys.BBF_BINARY) +WITH FUNCTION sys.int8binary (INT8, integer, boolean) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.binaryint2(sys.BBF_BINARY) +RETURNS INT2 +AS 'babelfishpg_common', 'binaryint2' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BBF_BINARY as INT2) +WITH FUNCTION sys.binaryint2 (sys.BBF_BINARY) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.binaryint4(sys.BBF_BINARY) +RETURNS INT4 +AS 'babelfishpg_common', 'binaryint4' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BBF_BINARY as INT4) +WITH FUNCTION sys.binaryint4 (sys.BBF_BINARY) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.binaryint8(sys.BBF_BINARY) +RETURNS INT8 +AS 'babelfishpg_common', 'binaryint8' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BBF_BINARY as INT8) +WITH FUNCTION sys.binaryint8 (sys.BBF_BINARY) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.float4binary(REAL, integer, boolean) +RETURNS sys.BBF_BINARY +AS 'babelfishpg_common', 'float4binary' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (REAL AS sys.BBF_BINARY) +WITH FUNCTION sys.float4binary (REAL, integer, boolean) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.float8binary(DOUBLE PRECISION, integer, boolean) +RETURNS sys.BBF_BINARY +AS 'babelfishpg_common', 'float8binary' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (DOUBLE PRECISION AS sys.BBF_BINARY) +WITH FUNCTION sys.float8binary (DOUBLE PRECISION, integer, boolean) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.binaryfloat4(sys.BBF_BINARY) +RETURNS REAL +AS 'babelfishpg_common', 'binaryfloat4' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BBF_BINARY as REAL) +WITH FUNCTION sys.binaryfloat4 (sys.BBF_BINARY) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.binaryfloat8(sys.BBF_BINARY) +RETURNS DOUBLE PRECISION +AS 'babelfishpg_common', 'binaryfloat8' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BBF_BINARY as DOUBLE PRECISION) +WITH FUNCTION sys.binaryfloat8 (sys.BBF_BINARY) AS ASSIGNMENT; + +CREATE DOMAIN sys.IMAGE AS sys.BBF_VARBINARY; + +SET enable_domain_typmod = TRUE; +CREATE DOMAIN sys.BINARY AS sys.BBF_BINARY; +RESET enable_domain_typmod; + +CREATE OR REPLACE FUNCTION sys.binary(sys.BINARY, integer, boolean) +RETURNS sys.BINARY +AS 'babelfishpg_common', 'binary' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +SET client_min_messages = 'ERROR'; +CREATE CAST (sys.BINARY AS sys.BINARY) +WITH FUNCTION sys.binary (sys.BINARY, integer, BOOLEAN) AS ASSIGNMENT; +SET client_min_messages = 'WARNING'; + +CREATE FUNCTION sys.binary_eq(leftarg sys.bbf_binary, rightarg sys.bbf_binary) +RETURNS boolean +AS 'babelfishpg_common', 'varbinary_eq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.= ( + LEFTARG = sys.bbf_binary, + RIGHTARG = sys.bbf_binary, + FUNCTION = sys.binary_eq, + COMMUTATOR = = +); + + +CREATE FUNCTION sys.binary_neq(leftarg sys.bbf_binary, rightarg sys.bbf_binary) +RETURNS boolean +AS 'babelfishpg_common', 'varbinary_neq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.<> ( + LEFTARG = sys.bbf_binary, + RIGHTARG = sys.bbf_binary, + FUNCTION = sys.binary_neq, + COMMUTATOR = <> +); + +CREATE FUNCTION sys.binary_gt(leftarg sys.bbf_binary, rightarg sys.bbf_binary) +RETURNS boolean +AS 'babelfishpg_common', 'varbinary_gt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.> ( + LEFTARG = sys.bbf_binary, + RIGHTARG = sys.bbf_binary, + FUNCTION = sys.binary_gt, + COMMUTATOR = < +); + +CREATE FUNCTION sys.binary_geq(leftarg sys.bbf_binary, rightarg sys.bbf_binary) +RETURNS boolean +AS 'babelfishpg_common', 'varbinary_geq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.>= ( + LEFTARG = sys.bbf_binary, + RIGHTARG = sys.bbf_binary, + FUNCTION = sys.binary_geq, + COMMUTATOR = <= +); + +CREATE FUNCTION sys.binary_lt(leftarg sys.bbf_binary, rightarg sys.bbf_binary) +RETURNS boolean +AS 'babelfishpg_common', 'varbinary_eq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.< ( + LEFTARG = sys.bbf_binary, + RIGHTARG = sys.bbf_binary, + FUNCTION = sys.binary_lt, + COMMUTATOR = > +); + +CREATE FUNCTION sys.binary_leq(leftarg sys.bbf_binary, rightarg sys.bbf_binary) +RETURNS boolean +AS 'babelfishpg_common', 'varbinary_leq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.<= ( + LEFTARG = sys.bbf_binary, + RIGHTARG = sys.bbf_binary, + FUNCTION = sys.binary_leq, + COMMUTATOR = >= +); + +CREATE FUNCTION sys.bbf_binary_cmp(sys.bbf_binary, sys.bbf_binary) +RETURNS int +AS 'babelfishpg_common', 'varbinary_cmp' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR CLASS sys.bbf_binary_ops +DEFAULT FOR TYPE sys.bbf_binary USING btree AS + OPERATOR 1 < (sys.bbf_binary, sys.bbf_binary), + OPERATOR 2 <= (sys.bbf_binary, sys.bbf_binary), + OPERATOR 3 = (sys.bbf_binary, sys.bbf_binary), + OPERATOR 4 >= (sys.bbf_binary, sys.bbf_binary), + OPERATOR 5 > (sys.bbf_binary, sys.bbf_binary), + FUNCTION 1 sys.bbf_binary_cmp(sys.bbf_binary, sys.bbf_binary); +-- 22 "sql/babelfishpg_common.in" 2 +-- 1 "sql/uniqueidentifier.sql" 1 +CREATE TYPE sys.UNIQUEIDENTIFIER; + +CREATE OR REPLACE FUNCTION sys.uniqueidentifierin(cstring) +RETURNS sys.UNIQUEIDENTIFIER +AS 'babelfishpg_common', 'uniqueidentifier_in' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.uniqueidentifierout(sys.UNIQUEIDENTIFIER) +RETURNS cstring +AS 'babelfishpg_common', 'uniqueidentifier_out' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.uniqueidentifierrecv(internal) +RETURNS sys.UNIQUEIDENTIFIER +AS 'uuid_recv' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.uniqueidentifiersend(sys.UNIQUEIDENTIFIER) +RETURNS bytea +AS 'uuid_send' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE TYPE sys.UNIQUEIDENTIFIER ( + INPUT = sys.uniqueidentifierin, + OUTPUT = sys.uniqueidentifierout, + RECEIVE = sys.uniqueidentifierrecv, + SEND = sys.uniqueidentifiersend, + INTERNALLENGTH = 16, + ALIGNMENT = 'int4', + STORAGE = 'plain', + CATEGORY = 'U', + PREFERRED = false, + COLLATABLE = false +); + +CREATE OR REPLACE FUNCTION sys.newid() +RETURNS sys.UNIQUEIDENTIFIER +AS 'uuid-ossp', 'uuid_generate_v4' -- uuid-ossp was added as dependency +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +-- in tsql, NEWSEQUENTIALID() produces a new unique value +-- greater than a sequence of previous values. Since PG doesn't +-- have this capability, we will reuse the NEWID() functionality and be +-- aware of the functional shortcoming +CREATE OR REPLACE FUNCTION sys.NEWSEQUENTIALID() +RETURNS sys.UNIQUEIDENTIFIER +AS 'uuid-ossp', 'uuid_generate_v4' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.uniqueidentifiereq(sys.UNIQUEIDENTIFIER, sys.UNIQUEIDENTIFIER) +RETURNS bool +AS 'uuid_eq' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.uniqueidentifierne(sys.UNIQUEIDENTIFIER, sys.UNIQUEIDENTIFIER) +RETURNS bool +AS 'uuid_ne' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.uniqueidentifierlt(sys.UNIQUEIDENTIFIER, sys.UNIQUEIDENTIFIER) +RETURNS bool +AS 'uuid_lt' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.uniqueidentifierle(sys.UNIQUEIDENTIFIER, sys.UNIQUEIDENTIFIER) +RETURNS bool +AS 'uuid_le' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.uniqueidentifiergt(sys.UNIQUEIDENTIFIER, sys.UNIQUEIDENTIFIER) +RETURNS bool +AS 'uuid_gt' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.uniqueidentifierge(sys.UNIQUEIDENTIFIER, sys.UNIQUEIDENTIFIER) +RETURNS bool +AS 'uuid_ge' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.= ( + LEFTARG = sys.UNIQUEIDENTIFIER, + RIGHTARG = sys.UNIQUEIDENTIFIER, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = sys.uniqueidentifiereq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR sys.<> ( + LEFTARG = sys.UNIQUEIDENTIFIER, + RIGHTARG = sys.UNIQUEIDENTIFIER, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = sys.uniqueidentifierne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR sys.< ( + LEFTARG = sys.UNIQUEIDENTIFIER, + RIGHTARG = sys.UNIQUEIDENTIFIER, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = sys.uniqueidentifierlt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.<= ( + LEFTARG = sys.UNIQUEIDENTIFIER, + RIGHTARG = sys.UNIQUEIDENTIFIER, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = sys.uniqueidentifierle, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.> ( + LEFTARG = sys.UNIQUEIDENTIFIER, + RIGHTARG = sys.UNIQUEIDENTIFIER, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = sys.uniqueidentifiergt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.>= ( + LEFTARG = sys.UNIQUEIDENTIFIER, + RIGHTARG = sys.UNIQUEIDENTIFIER, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = sys.uniqueidentifierge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE FUNCTION uniqueidentifier_cmp(sys.UNIQUEIDENTIFIER, sys.UNIQUEIDENTIFIER) +RETURNS INT4 +AS 'uuid_cmp' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION uniqueidentifier_hash(sys.UNIQUEIDENTIFIER) +RETURNS INT4 +AS 'uuid_hash' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR CLASS sys.uniqueidentifier_ops +DEFAULT FOR TYPE sys.UNIQUEIDENTIFIER USING btree AS + OPERATOR 1 < (sys.UNIQUEIDENTIFIER, sys.UNIQUEIDENTIFIER), + OPERATOR 2 <= (sys.UNIQUEIDENTIFIER, sys.UNIQUEIDENTIFIER), + OPERATOR 3 = (sys.UNIQUEIDENTIFIER, sys.UNIQUEIDENTIFIER), + OPERATOR 4 >= (sys.UNIQUEIDENTIFIER, sys.UNIQUEIDENTIFIER), + OPERATOR 5 > (sys.UNIQUEIDENTIFIER, sys.UNIQUEIDENTIFIER), + FUNCTION 1 uniqueidentifier_cmp(sys.UNIQUEIDENTIFIER, sys.UNIQUEIDENTIFIER); + +CREATE OPERATOR CLASS sys.uniqueidentifier_ops +DEFAULT FOR TYPE sys.UNIQUEIDENTIFIER USING hash AS + OPERATOR 1 = (sys.UNIQUEIDENTIFIER, sys.UNIQUEIDENTIFIER), + FUNCTION 1 uniqueidentifier_hash(sys.UNIQUEIDENTIFIER); + +CREATE FUNCTION sys.varchar2uniqueidentifier(pg_catalog.VARCHAR, integer, boolean) +RETURNS sys.UNIQUEIDENTIFIER +AS 'babelfishpg_common', 'varchar2uniqueidentifier' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (pg_catalog.VARCHAR as sys.UNIQUEIDENTIFIER) +WITH FUNCTION sys.varchar2uniqueidentifier(pg_catalog.VARCHAR, integer, boolean) AS ASSIGNMENT; + +CREATE FUNCTION sys.varchar2uniqueidentifier(sys.VARCHAR, integer, boolean) +RETURNS sys.UNIQUEIDENTIFIER +AS 'babelfishpg_common', 'varchar2uniqueidentifier' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.VARCHAR as sys.UNIQUEIDENTIFIER) +WITH FUNCTION sys.varchar2uniqueidentifier(sys.VARCHAR, integer, boolean) AS ASSIGNMENT; + + +CREATE FUNCTION sys.varbinary2uniqueidentifier(sys.bbf_varbinary, integer, boolean) +RETURNS sys.UNIQUEIDENTIFIER +AS 'babelfishpg_common', 'varbinary2uniqueidentifier' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.bbf_varbinary as sys.UNIQUEIDENTIFIER) +WITH FUNCTION sys.varbinary2uniqueidentifier(sys.bbf_varbinary, integer, boolean) AS ASSIGNMENT; + +CREATE FUNCTION sys.binary2uniqueidentifier(sys.bbf_binary, integer, boolean) +RETURNS sys.UNIQUEIDENTIFIER +AS 'babelfishpg_common', 'varbinary2uniqueidentifier' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.bbf_binary as sys.UNIQUEIDENTIFIER) +WITH FUNCTION sys.binary2uniqueidentifier(sys.bbf_binary, integer, boolean) AS ASSIGNMENT; + +CREATE FUNCTION sys.uniqueidentifier2varbinary(sys.UNIQUEIDENTIFIER, integer, boolean) +RETURNS sys.bbf_varbinary +AS 'babelfishpg_common', 'uniqueidentifier2varbinary' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.UNIQUEIDENTIFIER as sys.bbf_varbinary) +WITH FUNCTION sys.uniqueidentifier2varbinary(sys.UNIQUEIDENTIFIER, integer, boolean) AS IMPLICIT; + +CREATE FUNCTION sys.uniqueidentifier2binary(sys.UNIQUEIDENTIFIER, integer, boolean) +RETURNS sys.bbf_binary +AS 'babelfishpg_common', 'uniqueidentifier2binary' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.UNIQUEIDENTIFIER as sys.bbf_binary) +WITH FUNCTION sys.uniqueidentifier2binary(sys.UNIQUEIDENTIFIER, integer, boolean) AS IMPLICIT; +-- 23 "sql/babelfishpg_common.in" 2 +-- 1 "sql/datetime.sql" 1 +CREATE TYPE sys.DATETIME; + +CREATE OR REPLACE FUNCTION sys.datetimein(cstring) +RETURNS sys.DATETIME +AS 'babelfishpg_common', 'datetime_in' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetimeout(sys.DATETIME) +RETURNS cstring +AS 'babelfishpg_common', 'datetime_out' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetimerecv(internal) +RETURNS sys.DATETIME +AS 'timestamp_recv' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetimesend(sys.DATETIME) +RETURNS bytea +AS 'timestamp_send' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetimetypmodin(cstring[]) +RETURNS integer +AS 'timestamptypmodin' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetimetypmodout(integer) +RETURNS cstring +AS 'timestamptypmodout' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE TYPE sys.DATETIME ( + INPUT = sys.datetimein, + OUTPUT = sys.datetimeout, + RECEIVE = sys.datetimerecv, + SEND = sys.datetimesend, + TYPMOD_IN = sys.datetimetypmodin, + TYPMOD_OUT = sys.datetimetypmodout, + INTERNALLENGTH = 8, + ALIGNMENT = 'double', + STORAGE = 'plain', + CATEGORY = 'D', + PREFERRED = false, + COLLATABLE = false, + DEFAULT = '1900-01-01 00:00:00', + PASSEDBYVALUE +); + +CREATE FUNCTION sys.datetimeeq(sys.DATETIME, sys.DATETIME) +RETURNS bool +AS 'timestamp_eq' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.datetimene(sys.DATETIME, sys.DATETIME) +RETURNS bool +AS 'timestamp_ne' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.datetimelt(sys.DATETIME, sys.DATETIME) +RETURNS bool +AS 'timestamp_lt' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.datetimele(sys.DATETIME, sys.DATETIME) +RETURNS bool +AS 'timestamp_le' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.datetimegt(sys.DATETIME, sys.DATETIME) +RETURNS bool +AS 'timestamp_gt' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.datetimege(sys.DATETIME, sys.DATETIME) +RETURNS bool +AS 'timestamp_ge' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.= ( + LEFTARG = sys.DATETIME, + RIGHTARG = sys.DATETIME, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = sys.datetimeeq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR sys.<> ( + LEFTARG = sys.DATETIME, + RIGHTARG = sys.DATETIME, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = sys.datetimene, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR sys.< ( + LEFTARG = sys.DATETIME, + RIGHTARG = sys.DATETIME, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = sys.datetimelt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.<= ( + LEFTARG = sys.DATETIME, + RIGHTARG = sys.DATETIME, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = sys.datetimele, + RESTRICT = scalarlesel, + JOIN = scalarlejoinsel +); + +CREATE OPERATOR sys.> ( + LEFTARG = sys.DATETIME, + RIGHTARG = sys.DATETIME, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = sys.datetimegt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.>= ( + LEFTARG = sys.DATETIME, + RIGHTARG = sys.DATETIME, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = sys.datetimege, + RESTRICT = scalargesel, + JOIN = scalargejoinsel +); + +-- datetime <-> int operators for datetime-int +/- arithmetic +CREATE FUNCTION sys.datetimeplint4(sys.DATETIME, INT4) +RETURNS sys.DATETIME +AS 'babelfishpg_common', 'datetime_pl_int4' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int4pldatetime(INT4, sys.DATETIME) +RETURNS sys.DATETIME +AS 'babelfishpg_common', 'int4_pl_datetime' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.datetimemiint4(sys.DATETIME, INT4) +RETURNS sys.DATETIME +AS 'babelfishpg_common', 'datetime_mi_int4' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int4midatetime(INT4, sys.DATETIME) +RETURNS sys.DATETIME +AS 'babelfishpg_common', 'int4_mi_datetime' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.+ ( + LEFTARG = sys.DATETIME, + RIGHTARG = INT4, + PROCEDURE = sys.datetimeplint4 +); + +CREATE OPERATOR sys.+ ( + LEFTARG = INT4, + RIGHTARG = sys.DATETIME, + PROCEDURE = sys.int4pldatetime +); + +CREATE OPERATOR sys.- ( + LEFTARG = sys.DATETIME, + RIGHTARG = INT4, + PROCEDURE = sys.datetimemiint4 +); + +CREATE OPERATOR sys.- ( + LEFTARG = INT4, + RIGHTARG = sys.DATETIME, + PROCEDURE = sys.int4midatetime +); + + + +CREATE FUNCTION sys.datetimeplfloat8(sys.DATETIME, float8) +RETURNS sys.DATETIME +AS 'babelfishpg_common', 'datetime_pl_float8' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.+ ( + LEFTARG = sys.DATETIME, + RIGHTARG = float8, + PROCEDURE = sys.datetimeplfloat8 +); + +CREATE FUNCTION sys.datetimemifloat8(sys.DATETIME, float8) +RETURNS sys.DATETIME +AS 'babelfishpg_common', 'datetime_mi_float8' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.- ( + LEFTARG = sys.DATETIME, + RIGHTARG = float8, + PROCEDURE = sys.datetimemifloat8 +); + +CREATE FUNCTION sys.float8pldatetime(float8, sys.DATETIME) +RETURNS sys.DATETIME +AS 'babelfishpg_common', 'float8_pl_datetime' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.+ ( + LEFTARG = float8, + RIGHTARG = sys.DATETIME, + PROCEDURE = sys.float8pldatetime +); + +CREATE FUNCTION sys.float8midatetime(float8, sys.DATETIME) +RETURNS sys.DATETIME +AS 'babelfishpg_common', 'float8_mi_datetime' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.- ( + LEFTARG = float8, + RIGHTARG = sys.DATETIME, + PROCEDURE = sys.float8midatetime +); + + + + +CREATE FUNCTION datetime_cmp(sys.DATETIME, sys.DATETIME) +RETURNS INT4 +AS 'timestamp_cmp' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION datetime_hash(sys.DATETIME) +RETURNS INT4 +AS 'timestamp_hash' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR CLASS sys.datetime_ops +DEFAULT FOR TYPE sys.DATETIME USING btree AS + OPERATOR 1 < (sys.DATETIME, sys.DATETIME), + OPERATOR 2 <= (sys.DATETIME, sys.DATETIME), + OPERATOR 3 = (sys.DATETIME, sys.DATETIME), + OPERATOR 4 >= (sys.DATETIME, sys.DATETIME), + OPERATOR 5 > (sys.DATETIME, sys.DATETIME), + FUNCTION 1 datetime_cmp(sys.DATETIME, sys.DATETIME); + +CREATE OPERATOR CLASS sys.datetime_ops +DEFAULT FOR TYPE sys.DATETIME USING hash AS + OPERATOR 1 = (sys.DATETIME, sys.DATETIME), + FUNCTION 1 datetime_hash(sys.DATETIME); + +-- cast TO datetime +CREATE OR REPLACE FUNCTION sys.timestamp2datetime(TIMESTAMP) +RETURNS DATETIME +AS 'babelfishpg_common', 'timestamp_datetime' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (TIMESTAMP AS DATETIME) +WITH FUNCTION sys.timestamp2datetime(TIMESTAMP) AS ASSIGNMENT; + + +CREATE OR REPLACE FUNCTION sys.timestamptz2datetime(TIMESTAMPTZ) +RETURNS DATETIME +AS 'babelfishpg_common', 'timestamptz_datetime' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (TIMESTAMPTZ AS DATETIME) +WITH FUNCTION sys.timestamptz2datetime (TIMESTAMPTZ) AS ASSIGNMENT; + + +CREATE OR REPLACE FUNCTION sys.date2datetime(DATE) +RETURNS DATETIME +AS 'babelfishpg_common', 'date_datetime' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (DATE AS DATETIME) +WITH FUNCTION sys.date2datetime (DATE) AS IMPLICIT; + + +CREATE OR REPLACE FUNCTION sys.time2datetime(TIME) +RETURNS DATETIME +AS 'babelfishpg_common', 'time_datetime' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (TIME AS DATETIME) +WITH FUNCTION sys.time2datetime (TIME) AS IMPLICIT; + + +CREATE OR REPLACE FUNCTION sys.varchar2datetime(sys.VARCHAR) +RETURNS DATETIME +AS 'babelfishpg_common', 'varchar_datetime' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.VARCHAR AS DATETIME) +WITH FUNCTION sys.varchar2datetime (sys.VARCHAR) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.varchar2datetime(pg_catalog.VARCHAR) +RETURNS DATETIME +AS 'babelfishpg_common', 'varchar_datetime' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (pg_catalog.VARCHAR AS DATETIME) +WITH FUNCTION sys.varchar2datetime (pg_catalog.VARCHAR) AS ASSIGNMENT; + + +CREATE OR REPLACE FUNCTION sys.char2datetime(CHAR) +RETURNS DATETIME +AS 'babelfishpg_common', 'char_datetime' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (CHAR AS DATETIME) +WITH FUNCTION sys.char2datetime (CHAR) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.bpchar2datetime(sys.BPCHAR) +RETURNS sys.DATETIME +AS 'babelfishpg_common', 'char_datetime' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BPCHAR AS sys.DATETIME) +WITH FUNCTION sys.bpchar2datetime (sys.BPCHAR) AS ASSIGNMENT; + +-- cast FROM datetime +CREATE CAST (DATETIME AS TIMESTAMP) +WITHOUT FUNCTION AS IMPLICIT; + + +CREATE OR REPLACE FUNCTION sys.datetime2timestamptz(DATETIME) +RETURNS TIMESTAMPTZ +AS 'timestamp_timestamptz' +LANGUAGE internal VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (DATETIME AS TIMESTAMPTZ) +WITH FUNCTION sys.datetime2timestamptz (DATETIME) AS IMPLICIT; + + +CREATE OR REPLACE FUNCTION sys.datetime2date(DATETIME) +RETURNS DATE +AS 'timestamp_date' +LANGUAGE internal VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (DATETIME AS DATE) +WITH FUNCTION sys.datetime2date (DATETIME) AS ASSIGNMENT; + + +CREATE OR REPLACE FUNCTION sys.datetime2time(DATETIME) +RETURNS TIME +AS 'timestamp_time' +LANGUAGE internal VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (DATETIME AS TIME) +WITH FUNCTION sys.datetime2time (DATETIME) AS ASSIGNMENT; + + +CREATE OR REPLACE FUNCTION sys.datetime2sysvarchar(DATETIME) +RETURNS sys.VARCHAR +AS 'babelfishpg_common', 'datetime_varchar' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (DATETIME AS sys.VARCHAR) +WITH FUNCTION sys.datetime2sysvarchar (DATETIME) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.datetime2varchar(DATETIME) +RETURNS pg_catalog.VARCHAR +AS 'babelfishpg_common', 'datetime_varchar' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (DATETIME AS pg_catalog.VARCHAR) +WITH FUNCTION sys.datetime2varchar (DATETIME) AS ASSIGNMENT; + + +CREATE OR REPLACE FUNCTION sys.datetime2char(DATETIME) +RETURNS CHAR +AS 'babelfishpg_common', 'datetime_char' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (DATETIME AS CHAR) +WITH FUNCTION sys.datetime2char (DATETIME) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.datetime2bpchar(sys.DATETIME) +RETURNS sys.BPCHAR +AS 'babelfishpg_common', 'datetime_char' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.DATETIME AS sys.BPCHAR) +WITH FUNCTION sys.datetime2bpchar (sys.DATETIME) AS ASSIGNMENT; +-- 24 "sql/babelfishpg_common.in" 2 +-- 1 "sql/datetime2.sql" 1 +CREATE TYPE sys.DATETIME2; + +CREATE OR REPLACE FUNCTION sys.datetime2in(cstring) +RETURNS sys.DATETIME2 +AS 'babelfishpg_common', 'datetime2_in' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetime2out(sys.DATETIME2) +RETURNS cstring +AS 'timestamp_out' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetime2recv(internal) +RETURNS sys.DATETIME2 +AS 'timestamp_recv' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetime2send(sys.DATETIME2) +RETURNS bytea +AS 'timestamp_send' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetime2typmodin(cstring[]) +RETURNS integer +AS 'timestamptypmodin' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetime2typmodout(integer) +RETURNS cstring +AS 'timestamptypmodout' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE TYPE sys.DATETIME2 ( + INPUT = sys.datetime2in, + OUTPUT = sys.datetime2out, + RECEIVE = sys.datetime2recv, + SEND = sys.datetime2send, + TYPMOD_IN = sys.datetime2typmodin, + TYPMOD_OUT = sys.datetime2typmodout, + INTERNALLENGTH = 8, + ALIGNMENT = 'double', + STORAGE = 'plain', + CATEGORY = 'D', + PREFERRED = false, + COLLATABLE = false, + DEFAULT = '1900-01-01 00:00:00', + PASSEDBYVALUE +); + +CREATE FUNCTION sys.datetime2eq(sys.DATETIME2, sys.DATETIME2) +RETURNS bool +AS 'timestamp_eq' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.datetime2ne(sys.DATETIME2, sys.DATETIME2) +RETURNS bool +AS 'timestamp_ne' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.datetime2lt(sys.DATETIME2, sys.DATETIME2) +RETURNS bool +AS 'timestamp_lt' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.datetime2le(sys.DATETIME2, sys.DATETIME2) +RETURNS bool +AS 'timestamp_le' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.datetime2gt(sys.DATETIME2, sys.DATETIME2) +RETURNS bool +AS 'timestamp_gt' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.datetime2ge(sys.DATETIME2, sys.DATETIME2) +RETURNS bool +AS 'timestamp_ge' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.= ( + LEFTARG = sys.DATETIME2, + RIGHTARG = sys.DATETIME2, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = sys.datetime2eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR sys.<> ( + LEFTARG = sys.DATETIME2, + RIGHTARG = sys.DATETIME2, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = sys.datetime2ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR sys.< ( + LEFTARG = sys.DATETIME2, + RIGHTARG = sys.DATETIME2, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = sys.datetime2lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.<= ( + LEFTARG = sys.DATETIME2, + RIGHTARG = sys.DATETIME2, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = sys.datetime2le, + RESTRICT = scalarlesel, + JOIN = scalarlejoinsel +); + +CREATE OPERATOR sys.> ( + LEFTARG = sys.DATETIME2, + RIGHTARG = sys.DATETIME2, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = sys.datetime2gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.>= ( + LEFTARG = sys.DATETIME2, + RIGHTARG = sys.DATETIME2, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = sys.datetime2ge, + RESTRICT = scalargesel, + JOIN = scalargejoinsel +); + +CREATE FUNCTION datetime2_cmp(sys.DATETIME2, sys.DATETIME2) +RETURNS INT4 +AS 'timestamp_cmp' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION datetime2_hash(sys.DATETIME2) +RETURNS INT4 +AS 'timestamp_hash' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR CLASS sys.datetime2_ops +DEFAULT FOR TYPE sys.DATETIME2 USING btree AS + OPERATOR 1 < (sys.DATETIME2, sys.DATETIME2), + OPERATOR 2 <= (sys.DATETIME2, sys.DATETIME2), + OPERATOR 3 = (sys.DATETIME2, sys.DATETIME2), + OPERATOR 4 >= (sys.DATETIME2, sys.DATETIME2), + OPERATOR 5 > (sys.DATETIME2, sys.DATETIME2), + FUNCTION 1 datetime2_cmp(sys.DATETIME2, sys.DATETIME2); + +CREATE OPERATOR CLASS sys.datetime2_ops +DEFAULT FOR TYPE sys.DATETIME2 USING hash AS + OPERATOR 1 = (sys.DATETIME2, sys.DATETIME2), + FUNCTION 1 datetime2_hash(sys.DATETIME2); + +-- cast TO datetime2 +CREATE OR REPLACE FUNCTION sys.timestamp2datetime2(TIMESTAMP) +RETURNS DATETIME2 +AS 'babelfishpg_common', 'timestamp_datetime2' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (TIMESTAMP AS DATETIME2) +WITH FUNCTION sys.timestamp2datetime2(TIMESTAMP) AS ASSIGNMENT; +-- CREATE CAST (TIMESTAMP AS DATETIME2) +-- WITHOUT FUNCTION AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.timestamptz2datetime2(TIMESTAMPTZ) +RETURNS DATETIME2 +AS 'babelfishpg_common', 'timestamptz_datetime2' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (TIMESTAMPTZ AS DATETIME2) +WITH FUNCTION sys.timestamptz2datetime2 (TIMESTAMPTZ) AS ASSIGNMENT; + + +CREATE OR REPLACE FUNCTION sys.date2datetime2(DATE) +RETURNS DATETIME2 +AS 'babelfishpg_common', 'date_datetime2' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (DATE AS DATETIME2) +WITH FUNCTION sys.date2datetime2 (DATE) AS IMPLICIT; + + +CREATE OR REPLACE FUNCTION sys.time2datetime2(TIME) +RETURNS DATETIME2 +AS 'babelfishpg_common', 'time_datetime2' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (TIME AS DATETIME2) +WITH FUNCTION sys.time2datetime2 (TIME) AS IMPLICIT; + + +CREATE CAST (DATETIME AS DATETIME2) +WITHOUT FUNCTION AS IMPLICIT; + + +-- BABEL-1465 CAST from VARCHAR/NVARCHAR/CHAR/NCHAR to datetime2 is VOLATILE +CREATE OR REPLACE FUNCTION sys.varchar2datetime2(sys.VARCHAR) +RETURNS DATETIME2 +AS 'babelfishpg_common', 'varchar_datetime2' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.VARCHAR AS DATETIME2) +WITH FUNCTION sys.varchar2datetime2 (sys.VARCHAR) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.varchar2datetime2(pg_catalog.VARCHAR) +RETURNS DATETIME2 +AS 'babelfishpg_common', 'varchar_datetime2' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (pg_catalog.VARCHAR AS DATETIME2) +WITH FUNCTION sys.varchar2datetime2 (pg_catalog.VARCHAR) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.char2datetime2(CHAR) +RETURNS DATETIME2 +AS 'babelfishpg_common', 'char_datetime2' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (CHAR AS DATETIME2) +WITH FUNCTION sys.char2datetime2 (CHAR) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.bpchar2datetime2(sys.BPCHAR) +RETURNS sys.DATETIME2 +AS 'babelfishpg_common', 'char_datetime2' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BPCHAR AS sys.DATETIME2) +WITH FUNCTION sys.bpchar2datetime2 (sys.BPCHAR) AS ASSIGNMENT; + +-- cast FROM datetime2 +CREATE CAST (DATETIME2 AS TIMESTAMP) +WITHOUT FUNCTION AS IMPLICIT; + + +CREATE OR REPLACE FUNCTION sys.datetime22datetime(DATETIME2) +RETURNS DATETIME +AS 'babelfishpg_common', 'timestamp_datetime' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (DATETIME2 AS DATETIME) +WITH FUNCTION sys.datetime22datetime(DATETIME2) AS ASSIGNMENT; + + +CREATE OR REPLACE FUNCTION sys.datetime22timestamptz(DATETIME2) +RETURNS TIMESTAMPTZ +AS 'timestamp_timestamptz' +LANGUAGE internal VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (DATETIME2 AS TIMESTAMPTZ) +WITH FUNCTION sys.datetime22timestamptz (DATETIME2) AS IMPLICIT; + + +CREATE OR REPLACE FUNCTION sys.datetime22date(DATETIME2) +RETURNS DATE +AS 'timestamp_date' +LANGUAGE internal VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (DATETIME2 AS DATE) +WITH FUNCTION sys.datetime22date (DATETIME2) AS ASSIGNMENT; + + +CREATE OR REPLACE FUNCTION sys.datetime22time(DATETIME2) +RETURNS TIME +AS 'timestamp_time' +LANGUAGE internal VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (DATETIME2 AS TIME) +WITH FUNCTION sys.datetime22time (DATETIME2) AS ASSIGNMENT; + + +CREATE FUNCTION sys.datetime2scale(sys.DATETIME2, INT4) +RETURNS sys.DATETIME2 +AS 'babelfishpg_common', 'datetime2_scale' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.DATETIME2 AS sys.DATETIME2) +WITH FUNCTION datetime2scale (sys.DATETIME2, INT4) AS ASSIGNMENT; + + +-- BABEL-1465 CAST from datetime2 to VARCHAR/NVARCHAR/CHAR/NCHAR is VOLATILE +CREATE OR REPLACE FUNCTION sys.datetime22sysvarchar(DATETIME2) +RETURNS sys.VARCHAR +AS 'babelfishpg_common', 'datetime2_varchar' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (DATETIME2 AS sys.VARCHAR) +WITH FUNCTION sys.datetime22sysvarchar (DATETIME2) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.datetime22varchar(DATETIME2) +RETURNS pg_catalog.VARCHAR +AS 'babelfishpg_common', 'datetime2_varchar' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (DATETIME2 AS pg_catalog.VARCHAR) +WITH FUNCTION sys.datetime22varchar (DATETIME2) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.datetime22char(DATETIME2) +RETURNS CHAR +AS 'babelfishpg_common', 'datetime2_char' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (DATETIME2 AS CHAR) +WITH FUNCTION sys.datetime22char (DATETIME2) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.datetime22bpchar(sys.DATETIME2) +RETURNS sys.BPCHAR +AS 'babelfishpg_common', 'datetime2_char' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.DATETIME2 AS sys.BPCHAR) +WITH FUNCTION sys.datetime22bpchar (sys.DATETIME2) AS ASSIGNMENT; +-- 25 "sql/babelfishpg_common.in" 2 +-- 1 "sql/smalldatetime.sql" 1 +CREATE TYPE sys.SMALLDATETIME; + +CREATE OR REPLACE FUNCTION sys.smalldatetimein(cstring) +RETURNS sys.SMALLDATETIME +AS 'babelfishpg_common', 'smalldatetime_in' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.smalldatetimeout(sys.SMALLDATETIME) +RETURNS cstring +AS 'timestamp_out' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.smalldatetimerecv(internal) +RETURNS sys.SMALLDATETIME +AS 'timestamp_recv' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.smalldatetimesend(sys.SMALLDATETIME) +RETURNS bytea +AS 'timestamp_send' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.smalltypmodin(cstring[]) +RETURNS integer +AS 'timestamptypmodin' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.smalltypmodout(integer) +RETURNS cstring +AS 'timestamptypmodout' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE TYPE sys.SMALLDATETIME ( + INPUT = sys.smalldatetimein, + OUTPUT = sys.smalldatetimeout, + RECEIVE = sys.smalldatetimerecv, + SEND = sys.smalldatetimesend, + TYPMOD_IN = sys.smalltypmodin, + TYPMOD_OUT = sys.smalltypmodout, + INTERNALLENGTH = 8, + ALIGNMENT = 'double', + STORAGE = 'plain', + CATEGORY = 'D', + PREFERRED = false, + COLLATABLE = false, + DEFAULT = '1900-01-01 00:00', + PASSEDBYVALUE +); + +CREATE FUNCTION sys.smalldatetimeeq(sys.SMALLDATETIME, sys.SMALLDATETIME) +RETURNS bool +AS 'timestamp_eq' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.smalldatetimene(sys.SMALLDATETIME, sys.SMALLDATETIME) +RETURNS bool +AS 'timestamp_ne' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.smalldatetimelt(sys.SMALLDATETIME, sys.SMALLDATETIME) +RETURNS bool +AS 'timestamp_lt' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.smalldatetimele(sys.SMALLDATETIME, sys.SMALLDATETIME) +RETURNS bool +AS 'timestamp_le' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.smalldatetimegt(sys.SMALLDATETIME, sys.SMALLDATETIME) +RETURNS bool +AS 'timestamp_gt' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.smalldatetimege(sys.SMALLDATETIME, sys.SMALLDATETIME) +RETURNS bool +AS 'timestamp_ge' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.= ( + LEFTARG = sys.SMALLDATETIME, + RIGHTARG = sys.SMALLDATETIME, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = sys.smalldatetimeeq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR sys.<> ( + LEFTARG = sys.SMALLDATETIME, + RIGHTARG = sys.SMALLDATETIME, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = sys.smalldatetimene, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR sys.< ( + LEFTARG = sys.SMALLDATETIME, + RIGHTARG = sys.SMALLDATETIME, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = sys.smalldatetimelt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.<= ( + LEFTARG = sys.SMALLDATETIME, + RIGHTARG = sys.SMALLDATETIME, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = sys.smalldatetimele, + RESTRICT = scalarlesel, + JOIN = scalarlejoinsel +); + +CREATE OPERATOR sys.> ( + LEFTARG = sys.SMALLDATETIME, + RIGHTARG = sys.SMALLDATETIME, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = sys.smalldatetimegt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.>= ( + LEFTARG = sys.SMALLDATETIME, + RIGHTARG = sys.SMALLDATETIME, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = sys.smalldatetimege, + RESTRICT = scalargesel, + JOIN = scalargejoinsel +); + +-- smalldate vs pg_catalog.date +CREATE FUNCTION sys.smalldatetime_eq_date(sys.SMALLDATETIME, pg_catalog.date) +RETURNS bool +AS 'timestamp_eq_date' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.smalldatetime_ne_date(sys.SMALLDATETIME, pg_catalog.date) +RETURNS bool +AS 'timestamp_ne_date' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.smalldatetime_lt_date(sys.SMALLDATETIME, pg_catalog.date) +RETURNS bool +AS 'timestamp_lt_date' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.smalldatetime_le_date(sys.SMALLDATETIME, pg_catalog.date) +RETURNS bool +AS 'timestamp_le_date' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.smalldatetime_gt_date(sys.SMALLDATETIME, pg_catalog.date) +RETURNS bool +AS 'timestamp_gt_date' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.smalldatetime_ge_date(sys.SMALLDATETIME, pg_catalog.date) +RETURNS bool +AS 'timestamp_ge_date' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.= ( + LEFTARG = sys.SMALLDATETIME, + RIGHTARG = pg_catalog.date, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = smalldatetime_eq_date, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR sys.<> ( + LEFTARG = sys.SMALLDATETIME, + RIGHTARG = pg_catalog.date, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = smalldatetime_ne_date, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR sys.< ( + LEFTARG = sys.SMALLDATETIME, + RIGHTARG = pg_catalog.date, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = smalldatetime_lt_date, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.<= ( + LEFTARG = sys.SMALLDATETIME, + RIGHTARG = pg_catalog.date, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = smalldatetime_le_date, + RESTRICT = scalarlesel, + JOIN = scalarlejoinsel +); + +CREATE OPERATOR sys.> ( + LEFTARG = sys.SMALLDATETIME, + RIGHTARG = pg_catalog.date, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = smalldatetime_gt_date, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.>= ( + LEFTARG = sys.SMALLDATETIME, + RIGHTARG = pg_catalog.date, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = smalldatetime_ge_date, + RESTRICT = scalargesel, + JOIN = scalargejoinsel +); + +-- pg_catalog.date vs smalldate +CREATE FUNCTION sys.date_eq_smalldatetime(pg_catalog.date, sys.SMALLDATETIME) +RETURNS bool +AS 'date_eq_timestamp' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.date_ne_smalldatetime(pg_catalog.date, sys.SMALLDATETIME) +RETURNS bool +AS 'date_ne_timestamp' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.date_lt_smalldatetime(pg_catalog.date, sys.SMALLDATETIME) +RETURNS bool +AS 'date_lt_timestamp' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.date_le_smalldatetime(pg_catalog.date, sys.SMALLDATETIME) +RETURNS bool +AS 'date_le_timestamp' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.date_gt_smalldatetime(pg_catalog.date, sys.SMALLDATETIME) +RETURNS bool +AS 'date_gt_timestamp' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.date_ge_smalldatetime(pg_catalog.date, sys.SMALLDATETIME) +RETURNS bool +AS 'date_ge_timestamp' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.= ( + LEFTARG = pg_catalog.date, + RIGHTARG = sys.SMALLDATETIME, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = date_eq_smalldatetime, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR sys.<> ( + LEFTARG = pg_catalog.date, + RIGHTARG = sys.SMALLDATETIME, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = date_ne_smalldatetime, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR sys.< ( + LEFTARG = pg_catalog.date, + RIGHTARG = sys.SMALLDATETIME, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = date_lt_smalldatetime, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.<= ( + LEFTARG = pg_catalog.date, + RIGHTARG = sys.SMALLDATETIME, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = date_le_smalldatetime, + RESTRICT = scalarlesel, + JOIN = scalarlejoinsel +); + +CREATE OPERATOR sys.> ( + LEFTARG = pg_catalog.date, + RIGHTARG = sys.SMALLDATETIME, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = date_gt_smalldatetime, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.>= ( + LEFTARG = pg_catalog.date, + RIGHTARG = sys.SMALLDATETIME, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = date_ge_smalldatetime, + RESTRICT = scalargesel, + JOIN = scalargejoinsel +); + + +-- smalldatetime <-> int/float operators for smalldatetime-int +/- arithmetic +CREATE FUNCTION sys.smalldatetimeplint4(sys.smalldatetime, INT4) +RETURNS sys.smalldatetime +AS 'babelfishpg_common', 'smalldatetime_pl_int4' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int4plsmalldatetime(INT4, sys.smalldatetime) +RETURNS sys.smalldatetime +AS 'babelfishpg_common', 'int4_pl_smalldatetime' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.smalldatetimemiint4(sys.smalldatetime, INT4) +RETURNS sys.smalldatetime +AS 'babelfishpg_common', 'smalldatetime_mi_int4' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int4mismalldatetime(INT4, sys.smalldatetime) +RETURNS sys.smalldatetime +AS 'babelfishpg_common', 'int4_mi_smalldatetime' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.+ ( + LEFTARG = sys.smalldatetime, + RIGHTARG = INT4, + PROCEDURE = sys.smalldatetimeplint4 +); + +CREATE OPERATOR sys.+ ( + LEFTARG = INT4, + RIGHTARG = sys.smalldatetime, + PROCEDURE = sys.int4plsmalldatetime +); + +CREATE OPERATOR sys.- ( + LEFTARG = sys.smalldatetime, + RIGHTARG = INT4, + PROCEDURE = sys.smalldatetimemiint4 +); + +CREATE OPERATOR sys.- ( + LEFTARG = INT4, + RIGHTARG = sys.smalldatetime, + PROCEDURE = sys.int4mismalldatetime +); + + + +CREATE FUNCTION sys.smalldatetimeplfloat8(sys.smalldatetime, float8) +RETURNS sys.smalldatetime +AS 'babelfishpg_common', 'smalldatetime_pl_float8' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.+ ( + LEFTARG = sys.smalldatetime, + RIGHTARG = float8, + PROCEDURE = sys.smalldatetimeplfloat8 +); + +CREATE FUNCTION sys.smalldatetimemifloat8(sys.smalldatetime, float8) +RETURNS sys.smalldatetime +AS 'babelfishpg_common', 'smalldatetime_mi_float8' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.- ( + LEFTARG = sys.smalldatetime, + RIGHTARG = float8, + PROCEDURE = sys.smalldatetimemifloat8 +); + +CREATE FUNCTION sys.float8plsmalldatetime(float8, sys.smalldatetime) +RETURNS sys.smalldatetime +AS 'babelfishpg_common', 'float8_pl_smalldatetime' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.+ ( + LEFTARG = float8, + RIGHTARG = sys.smalldatetime, + PROCEDURE = sys.float8plsmalldatetime +); + +CREATE FUNCTION sys.float8mismalldatetime(float8, sys.smalldatetime) +RETURNS sys.smalldatetime +AS 'babelfishpg_common', 'float8_mi_smalldatetime' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.- ( + LEFTARG = float8, + RIGHTARG = sys.smalldatetime, + PROCEDURE = sys.float8mismalldatetime +); + + + +CREATE FUNCTION smalldatetime_cmp(sys.SMALLDATETIME, sys.SMALLDATETIME) +RETURNS INT4 +AS 'timestamp_cmp' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION smalldatetime_hash(sys.SMALLDATETIME) +RETURNS INT4 +AS 'timestamp_hash' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR CLASS sys.smalldatetime_ops +DEFAULT FOR TYPE sys.SMALLDATETIME USING btree AS + OPERATOR 1 < (sys.SMALLDATETIME, sys.SMALLDATETIME), + OPERATOR 2 <= (sys.SMALLDATETIME, sys.SMALLDATETIME), + OPERATOR 3 = (sys.SMALLDATETIME, sys.SMALLDATETIME), + OPERATOR 4 >= (sys.SMALLDATETIME, sys.SMALLDATETIME), + OPERATOR 5 > (sys.SMALLDATETIME, sys.SMALLDATETIME), + FUNCTION 1 smalldatetime_cmp(sys.SMALLDATETIME, sys.SMALLDATETIME); + +CREATE OPERATOR CLASS sys.smalldatetime_ops +DEFAULT FOR TYPE sys.SMALLDATETIME USING hash AS + OPERATOR 1 = (sys.SMALLDATETIME, sys.SMALLDATETIME), + FUNCTION 1 smalldatetime_hash(sys.SMALLDATETIME); + +CREATE OR REPLACE FUNCTION sys.timestamp2smalldatetime(TIMESTAMP) +RETURNS SMALLDATETIME +AS 'babelfishpg_common', 'timestamp_smalldatetime' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetime2smalldatetime(DATETIME) +RETURNS SMALLDATETIME +AS 'babelfishpg_common', 'timestamp_smalldatetime' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetime22smalldatetime(DATETIME2) +RETURNS SMALLDATETIME +AS 'babelfishpg_common', 'timestamp_smalldatetime' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.date2smalldatetime(DATE) +RETURNS SMALLDATETIME +AS 'babelfishpg_common', 'date_smalldatetime' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.smalldatetime2date(SMALLDATETIME) +RETURNS DATE +AS 'timestamp_date' +LANGUAGE internal VOLATILE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.timestamptz2smalldatetime(TIMESTAMPTZ) +RETURNS SMALLDATETIME +AS 'babelfishpg_common', 'timestamptz_smalldatetime' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.smalldatetime2timestamptz(SMALLDATETIME) +RETURNS TIMESTAMPTZ +AS 'timestamp_timestamptz' +LANGUAGE internal VOLATILE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.time2smalldatetime(TIME) +RETURNS SMALLDATETIME +AS 'babelfishpg_common', 'time_smalldatetime' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.smalldatetime2time(SMALLDATETIME) +RETURNS TIME +AS 'timestamp_time' +LANGUAGE internal VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (TIMESTAMP AS SMALLDATETIME) +WITH FUNCTION sys.timestamp2smalldatetime(TIMESTAMP) AS ASSIGNMENT; + +CREATE CAST (DATETIME AS SMALLDATETIME) +WITH FUNCTION sys.datetime2smalldatetime(DATETIME) AS ASSIGNMENT; + +CREATE CAST (DATETIME2 AS SMALLDATETIME) +WITH FUNCTION sys.datetime22smalldatetime(DATETIME2) AS ASSIGNMENT; + +CREATE CAST (SMALLDATETIME AS DATETIME) +WITHOUT FUNCTION AS IMPLICIT; + +CREATE CAST (SMALLDATETIME AS DATETIME2) +WITHOUT FUNCTION AS IMPLICIT; + +CREATE CAST (SMALLDATETIME AS TIMESTAMP) +WITHOUT FUNCTION AS IMPLICIT; + +CREATE CAST (TIMESTAMPTZ AS SMALLDATETIME) +WITH FUNCTION sys.timestamptz2smalldatetime (TIMESTAMPTZ) AS IMPLICIT; + +CREATE CAST (SMALLDATETIME AS TIMESTAMPTZ) +WITH FUNCTION sys.smalldatetime2timestamptz (SMALLDATETIME) AS ASSIGNMENT; + +CREATE CAST (DATE AS SMALLDATETIME) +WITH FUNCTION sys.date2smalldatetime (DATE) AS IMPLICIT; + +CREATE CAST (SMALLDATETIME AS DATE) +WITH FUNCTION sys.smalldatetime2date (SMALLDATETIME) AS ASSIGNMENT; + +CREATE CAST (TIME AS SMALLDATETIME) +WITH FUNCTION sys.time2smalldatetime (TIME) AS IMPLICIT; + +CREATE CAST (SMALLDATETIME AS TIME) +WITH FUNCTION sys.smalldatetime2time (SMALLDATETIME) AS ASSIGNMENT; + +-- BABEL-1465 CAST from VARCHAR/NVARCHAR/CHAR/NCHAR to smalldatetime is VOLATILE +CREATE OR REPLACE FUNCTION sys.varchar2smalldatetime(sys.VARCHAR) +RETURNS SMALLDATETIME +AS 'babelfishpg_common', 'varchar_smalldatetime' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.VARCHAR AS SMALLDATETIME) +WITH FUNCTION sys.varchar2smalldatetime (sys.VARCHAR) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.varchar2smalldatetime(pg_catalog.VARCHAR) +RETURNS SMALLDATETIME +AS 'babelfishpg_common', 'varchar_smalldatetime' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (pg_catalog.VARCHAR AS SMALLDATETIME) +WITH FUNCTION sys.varchar2smalldatetime (pg_catalog.VARCHAR) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.char2smalldatetime(CHAR) +RETURNS SMALLDATETIME +AS 'babelfishpg_common', 'char_smalldatetime' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (CHAR AS SMALLDATETIME) +WITH FUNCTION sys.char2smalldatetime (CHAR) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.bpchar2smalldatetime(sys.BPCHAR) +RETURNS sys.SMALLDATETIME +AS 'babelfishpg_common', 'char_smalldatetime' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BPCHAR AS sys.SMALLDATETIME) +WITH FUNCTION sys.bpchar2smalldatetime (sys.BPCHAR) AS ASSIGNMENT; + +-- BABEL-1465 CAST from smalldatetime to VARCHAR/NVARCHAR/CHAR/NCHAR is VOLATILE +CREATE OR REPLACE FUNCTION sys.smalldatetime2sysvarchar(SMALLDATETIME) +RETURNS sys.VARCHAR +AS 'babelfishpg_common', 'smalldatetime_varchar' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (SMALLDATETIME AS sys.VARCHAR) +WITH FUNCTION sys.smalldatetime2sysvarchar (SMALLDATETIME) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.smalldatetime2varchar(SMALLDATETIME) +RETURNS pg_catalog.VARCHAR +AS 'babelfishpg_common', 'smalldatetime_varchar' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (SMALLDATETIME AS pg_catalog.VARCHAR) +WITH FUNCTION sys.smalldatetime2varchar (SMALLDATETIME) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.smalldatetime2char(SMALLDATETIME) +RETURNS CHAR +AS 'babelfishpg_common', 'smalldatetime_char' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (SMALLDATETIME AS CHAR) +WITH FUNCTION sys.smalldatetime2char (SMALLDATETIME) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.smalldatetime2bpchar(sys.SMALLDATETIME) +RETURNS sys.BPCHAR +AS 'babelfishpg_common', 'smalldatetime_char' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.SMALLDATETIME AS sys.BPCHAR) +WITH FUNCTION sys.smalldatetime2bpchar (sys.SMALLDATETIME) AS ASSIGNMENT; +-- 26 "sql/babelfishpg_common.in" 2 +-- 1 "sql/datetimeoffset.sql" 1 +CREATE TYPE sys.DATETIMEOFFSET; + +CREATE OR REPLACE FUNCTION sys.datetimeoffsetin(cstring) +RETURNS sys.DATETIMEOFFSET +AS 'babelfishpg_common', 'datetimeoffset_in' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetimeoffsetout(sys.DATETIMEOFFSET) +RETURNS cstring +AS 'babelfishpg_common', 'datetimeoffset_out' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetimeoffsetrecv(internal) +RETURNS sys.DATETIMEOFFSET +AS 'babelfishpg_common', 'datetimeoffset_recv' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetimeoffsetsend(sys.DATETIMEOFFSET) +RETURNS bytea +AS 'babelfishpg_common', 'datetimeoffset_send' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetimeofftypmodin(cstring[]) +RETURNS integer +AS 'timestamptztypmodin' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetimeofftypmodout(integer) +RETURNS cstring +AS 'timestamptztypmodout' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE TYPE sys.DATETIMEOFFSET ( + INPUT = sys.datetimeoffsetin, + OUTPUT = sys.datetimeoffsetout, + RECEIVE = sys.datetimeoffsetrecv, + SEND = sys.datetimeoffsetsend, + TYPMOD_IN = sys.datetimeofftypmodin, + TYPMOD_OUT = sys.datetimeofftypmodout, + INTERNALLENGTH = 10, + ALIGNMENT = 'double', + STORAGE = 'plain', + CATEGORY = 'D', + PREFERRED = false, + DEFAULT = '1900-01-01 00:00+0' +); + +CREATE FUNCTION sys.datetimeoffseteq(sys.DATETIMEOFFSET, sys.DATETIMEOFFSET) +RETURNS bool +AS 'babelfishpg_common', 'datetimeoffset_eq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.datetimeoffsetne(sys.DATETIMEOFFSET, sys.DATETIMEOFFSET) +RETURNS bool +AS 'babelfishpg_common', 'datetimeoffset_ne' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.datetimeoffsetlt(sys.DATETIMEOFFSET, sys.DATETIMEOFFSET) +RETURNS bool +AS 'babelfishpg_common', 'datetimeoffset_lt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.datetimeoffsetle(sys.DATETIMEOFFSET, sys.DATETIMEOFFSET) +RETURNS bool +AS 'babelfishpg_common', 'datetimeoffset_le' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.datetimeoffsetgt(sys.DATETIMEOFFSET, sys.DATETIMEOFFSET) +RETURNS bool +AS 'babelfishpg_common', 'datetimeoffset_gt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.datetimeoffsetge(sys.DATETIMEOFFSET, sys.DATETIMEOFFSET) +RETURNS bool +AS 'babelfishpg_common', 'datetimeoffset_ge' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.datetimeoffsetplinterval(sys.DATETIMEOFFSET, INTERVAL) +RETURNS sys.DATETIMEOFFSET +AS 'babelfishpg_common', 'datetimeoffset_pl_interval' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.intervalpldatetimeoffset(INTERVAL, sys.DATETIMEOFFSET) +RETURNS sys.DATETIMEOFFSET +AS 'babelfishpg_common', 'interval_pl_datetimeoffset' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.datetimeoffsetmiinterval(sys.DATETIMEOFFSET, INTERVAL) +RETURNS sys.DATETIMEOFFSET +AS 'babelfishpg_common', 'datetimeoffset_mi_interval' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.datetimeoffsetmi(sys.DATETIMEOFFSET, sys.DATETIMEOFFSET) +RETURNS INTERVAL +AS 'babelfishpg_common', 'datetimeoffset_mi' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.= ( + LEFTARG = sys.DATETIMEOFFSET, + RIGHTARG = sys.DATETIMEOFFSET, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = sys.datetimeoffseteq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR sys.<> ( + LEFTARG = sys.DATETIMEOFFSET, + RIGHTARG = sys.DATETIMEOFFSET, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = sys.datetimeoffsetne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR sys.< ( + LEFTARG = sys.DATETIMEOFFSET, + RIGHTARG = sys.DATETIMEOFFSET, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = sys.datetimeoffsetlt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.<= ( + LEFTARG = sys.DATETIMEOFFSET, + RIGHTARG = sys.DATETIMEOFFSET, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = sys.datetimeoffsetle, + RESTRICT = scalarlesel, + JOIN = scalarlejoinsel +); + +CREATE OPERATOR sys.> ( + LEFTARG = sys.DATETIMEOFFSET, + RIGHTARG = sys.DATETIMEOFFSET, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = sys.datetimeoffsetgt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.>= ( + LEFTARG = sys.DATETIMEOFFSET, + RIGHTARG = sys.DATETIMEOFFSET, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = sys.datetimeoffsetge, + RESTRICT = scalargesel, + JOIN = scalargejoinsel +); + +CREATE OPERATOR sys.+ ( + LEFTARG = sys.DATETIMEOFFSET, + RIGHTARG = interval, + PROCEDURE = sys.datetimeoffsetplinterval +); + +CREATE OPERATOR sys.+ ( + LEFTARG = interval, + RIGHTARG = sys.DATETIMEOFFSET, + PROCEDURE = sys.intervalpldatetimeoffset +); + +CREATE OPERATOR sys.- ( + LEFTARG = sys.DATETIMEOFFSET, + RIGHTARG = interval, + PROCEDURE = sys.datetimeoffsetmiinterval +); + +CREATE OPERATOR sys.- ( + LEFTARG = sys.DATETIMEOFFSET, + RIGHTARG = sys.DATETIMEOFFSET, + PROCEDURE = sys.datetimeoffsetmi +); + +CREATE FUNCTION datetimeoffset_cmp(sys.DATETIMEOFFSET, sys.DATETIMEOFFSET) +RETURNS INT4 +AS 'babelfishpg_common', 'datetimeoffset_cmp' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION datetimeoffset_hash(sys.DATETIMEOFFSET) +RETURNS INT4 +AS 'babelfishpg_common', 'datetimeoffset_hash' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR CLASS sys.datetimeoffset_ops +DEFAULT FOR TYPE sys.DATETIMEOFFSET USING btree AS + OPERATOR 1 < (sys.DATETIMEOFFSET, sys.DATETIMEOFFSET), + OPERATOR 2 <= (sys.DATETIMEOFFSET, sys.DATETIMEOFFSET), + OPERATOR 3 = (sys.DATETIMEOFFSET, sys.DATETIMEOFFSET), + OPERATOR 4 >= (sys.DATETIMEOFFSET, sys.DATETIMEOFFSET), + OPERATOR 5 > (sys.DATETIMEOFFSET, sys.DATETIMEOFFSET), + FUNCTION 1 datetimeoffset_cmp(sys.DATETIMEOFFSET, sys.DATETIMEOFFSET); + +CREATE OPERATOR CLASS sys.datetimeoffset_ops +DEFAULT FOR TYPE sys.DATETIMEOFFSET USING hash AS + OPERATOR 1 = (sys.DATETIMEOFFSET, sys.DATETIMEOFFSET), + FUNCTION 1 datetimeoffset_hash(sys.DATETIMEOFFSET); + +-- Casts +CREATE FUNCTION sys.datetimeoffsetscale(sys.DATETIMEOFFSET, INT4) +RETURNS sys.DATETIMEOFFSET +AS 'babelfishpg_common', 'datetimeoffset_scale' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.timestamp2datetimeoffset(TIMESTAMP) +RETURNS sys.DATETIMEOFFSET +AS 'babelfishpg_common', 'timestamp_datetimeoffset' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetimeoffset2timestamp(sys.DATETIMEOFFSET) +RETURNS TIMESTAMP +AS 'babelfishpg_common', 'datetimeoffset_timestamp' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.date2datetimeoffset(DATE) +RETURNS sys.DATETIMEOFFSET +AS 'babelfishpg_common', 'date_datetimeoffset' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetimeoffset2date(sys.DATETIMEOFFSET) +RETURNS DATE +AS 'babelfishpg_common', 'datetimeoffset_date' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.time2datetimeoffset(TIME) +RETURNS sys.DATETIMEOFFSET +AS 'babelfishpg_common', 'time_datetimeoffset' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetimeoffset2time(sys.DATETIMEOFFSET) +RETURNS TIME +AS 'babelfishpg_common', 'datetimeoffset_time' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.smalldatetime2datetimeoffset(sys.SMALLDATETIME) +RETURNS sys.DATETIMEOFFSET +AS 'babelfishpg_common', 'smalldatetime_datetimeoffset' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetimeoffset2smalldatetime(sys.DATETIMEOFFSET) +RETURNS sys.SMALLDATETIME +AS 'babelfishpg_common', 'datetimeoffset_smalldatetime' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetime2datetimeoffset(sys.DATETIME) +RETURNS sys.DATETIMEOFFSET +AS 'babelfishpg_common', 'datetime_datetimeoffset' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetimeoffset2datetime(sys.DATETIMEOFFSET) +RETURNS sys.DATETIME +AS 'babelfishpg_common', 'datetimeoffset_datetime' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetime22datetimeoffset(sys.DATETIME2) +RETURNS sys.DATETIMEOFFSET +AS 'babelfishpg_common', 'datetime2_datetimeoffset' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetimeoffset2datetime2(sys.DATETIMEOFFSET) +RETURNS sys.DATETIME2 +AS 'babelfishpg_common', 'datetimeoffset_datetime2' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.DATETIMEOFFSET AS sys.DATETIMEOFFSET) +WITH FUNCTION datetimeoffsetscale (sys.DATETIMEOFFSET, INT4) AS ASSIGNMENT; + +CREATE CAST (TIMESTAMP AS sys.DATETIMEOFFSET) +WITH FUNCTION sys.timestamp2datetimeoffset(TIMESTAMP) AS IMPLICIT; +CREATE CAST (sys.DATETIMEOFFSET AS TIMESTAMP) +WITH FUNCTION sys.datetimeoffset2timestamp(sys.DATETIMEOFFSET) AS ASSIGNMENT; + +CREATE CAST (DATE AS sys.DATETIMEOFFSET) +WITH FUNCTION sys.date2datetimeoffset(DATE) AS IMPLICIT; +CREATE CAST (sys.DATETIMEOFFSET AS DATE) +WITH FUNCTION sys.datetimeoffset2date(sys.DATETIMEOFFSET) AS ASSIGNMENT; + +CREATE CAST (TIME AS sys.DATETIMEOFFSET) +WITH FUNCTION sys.time2datetimeoffset(TIME) AS IMPLICIT; +CREATE CAST (sys.DATETIMEOFFSET AS TIME) +WITH FUNCTION sys.datetimeoffset2time(sys.DATETIMEOFFSET) AS ASSIGNMENT; + +CREATE CAST (sys.SMALLDATETIME AS sys.DATETIMEOFFSET) +WITH FUNCTION sys.smalldatetime2datetimeoffset(sys.SMALLDATETIME) AS IMPLICIT; +CREATE CAST (sys.DATETIMEOFFSET AS sys.SMALLDATETIME) +WITH FUNCTION sys.datetimeoffset2smalldatetime(sys.DATETIMEOFFSET) AS ASSIGNMENT; + +CREATE CAST (sys.DATETIME AS sys.DATETIMEOFFSET) +WITH FUNCTION sys.datetime2datetimeoffset(sys.DATETIME) AS IMPLICIT; +CREATE CAST (sys.DATETIMEOFFSET AS sys.DATETIME) +WITH FUNCTION sys.datetimeoffset2datetime(sys.DATETIMEOFFSET) AS ASSIGNMENT; + +CREATE CAST (sys.DATETIME2 AS sys.DATETIMEOFFSET) +WITH FUNCTION sys.datetime22datetimeoffset(sys.DATETIME2) AS IMPLICIT; +CREATE CAST (sys.DATETIMEOFFSET AS sys.DATETIME2) +WITH FUNCTION sys.datetimeoffset2datetime2(sys.DATETIMEOFFSET) AS ASSIGNMENT; +-- 27 "sql/babelfishpg_common.in" 2 +-- 1 "sql/sqlvariant.sql" 1 +CREATE TYPE sys.SQL_VARIANT; + +CREATE OR REPLACE FUNCTION sys.sqlvariantin(cstring, oid, integer) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'sqlvariantin' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.sqlvariantout(sys.SQL_VARIANT) +RETURNS cstring +AS 'babelfishpg_common', 'sqlvariantout' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.sqlvariantrecv(internal, oid, integer) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'sqlvariantrecv' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.sqlvariantsend(sys.SQL_VARIANT) +RETURNS bytea +AS 'babelfishpg_common', 'sqlvariantsend' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE TYPE sys.SQL_VARIANT ( + INPUT = sys.sqlvariantin, + OUTPUT = sys.sqlvariantout, + RECEIVE = sys.sqlvariantrecv, + SEND = sys.sqlvariantsend, + INTERNALLENGTH = VARIABLE, + ALIGNMENT = 'int4', + STORAGE = 'extended', + CATEGORY = 'U', + PREFERRED = false, + COLLATABLE = true +); + +-- DATALENGTH function for SQL_VARIANT +CREATE OR REPLACE FUNCTION sys.datalength(sys.SQL_VARIANT) +RETURNS integer +AS 'babelfishpg_common', 'datalength_sqlvariant' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- CAST FUNCTIONS to SQL_VARIANT + +-- cast functions from domain types are overloaded such that we support casts both in pg and tsql: +-- money/smallmoney, smallint/tinyint, varchar/nvarchar, char/nchar +-- in pg, we will have minimal support of casts since domains are not distinguished +-- in tsql, we will allow domain casts in coerce.sql such that exact type info are saved +-- this is required for sql_variant since we may call sql_variant_property() to retrieve base type + +CREATE OR REPLACE FUNCTION sys.datetime_sqlvariant(sys.DATETIME) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'datetime2sqlvariant' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.DATETIME AS sys.SQL_VARIANT) +WITH FUNCTION sys.datetime_sqlvariant (sys.DATETIME) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.datetime2_sqlvariant(sys.DATETIME2) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'datetime22sqlvariant' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.DATETIME2 AS sys.SQL_VARIANT) +WITH FUNCTION sys.datetime2_sqlvariant (sys.DATETIME2) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.datetimeoffset_sqlvariant(sys.DATETIMEOFFSET) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'datetimeoffset2sqlvariant' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.DATETIMEOFFSET AS sys.SQL_VARIANT) +WITH FUNCTION sys.datetimeoffset_sqlvariant (sys.DATETIMEOFFSET) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.smalldatetime_sqlvariant(sys.SMALLDATETIME) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'smalldatetime2sqlvariant' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.SMALLDATETIME AS sys.SQL_VARIANT) +WITH FUNCTION sys.smalldatetime_sqlvariant (sys.SMALLDATETIME) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.date_sqlvariant(DATE) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'date2sqlvariant' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (DATE AS sys.SQL_VARIANT) +WITH FUNCTION sys.date_sqlvariant (DATE) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.time_sqlvariant(TIME) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'time2sqlvariant' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (TIME AS sys.SQL_VARIANT) +WITH FUNCTION sys.time_sqlvariant (TIME) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.float_sqlvariant(FLOAT) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'float2sqlvariant' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (FLOAT AS sys.SQL_VARIANT) +WITH FUNCTION sys.float_sqlvariant (FLOAT) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.real_sqlvariant(REAL) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'real2sqlvariant' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (REAL AS sys.SQL_VARIANT) +WITH FUNCTION sys.real_sqlvariant (REAL) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.numeric_sqlvariant(NUMERIC) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'numeric2sqlvariant' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (NUMERIC AS sys.SQL_VARIANT) +WITH FUNCTION sys.numeric_sqlvariant (NUMERIC) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.money_sqlvariant(FIXEDDECIMAL) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'money2sqlvariant' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.money_sqlvariant(sys.money) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'money2sqlvariant' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.smallmoney_sqlvariant(sys.smallmoney) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'smallmoney2sqlvariant' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (FIXEDDECIMAL AS sys.SQL_VARIANT) +WITH FUNCTION sys.money_sqlvariant (FIXEDDECIMAL) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.bigint_sqlvariant(BIGINT) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'bigint2sqlvariant' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (BIGINT AS sys.SQL_VARIANT) +WITH FUNCTION sys.bigint_sqlvariant (BIGINT) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.int_sqlvariant(INT) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'int2sqlvariant' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (INT AS sys.SQL_VARIANT) +WITH FUNCTION sys.int_sqlvariant (INT) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.smallint_sqlvariant(SMALLINT) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'smallint2sqlvariant' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.smallint_sqlvariant(smallint) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'smallint2sqlvariant' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.tinyint_sqlvariant(sys.tinyint) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'tinyint2sqlvariant' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (SMALLINT AS sys.SQL_VARIANT) +WITH FUNCTION sys.smallint_sqlvariant (SMALLINT) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.bit_sqlvariant(sys.BIT) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'bit2sqlvariant' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BIT AS sys.SQL_VARIANT) +WITH FUNCTION sys.bit_sqlvariant (sys.BIT) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.varchar_sqlvariant(sys.varchar) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'varchar2sqlvariant' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.nvarchar_sqlvariant(sys.nvarchar) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'nvarchar2sqlvariant' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.VARCHAR AS sys.SQL_VARIANT) +WITH FUNCTION sys.varchar_sqlvariant (sys.VARCHAR) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.varchar_sqlvariant(pg_catalog.varchar) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'varchar2sqlvariant' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (pg_catalog.VARCHAR AS sys.SQL_VARIANT) +WITH FUNCTION sys.varchar_sqlvariant (pg_catalog.VARCHAR) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.char_sqlvariant(CHAR) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'char2sqlvariant' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.nchar_sqlvariant(sys.nchar) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'nchar2sqlvariant' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (CHAR AS sys.SQL_VARIANT) +WITH FUNCTION sys.char_sqlvariant (CHAR) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.char_sqlvariant(sys.BPCHAR) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'char2sqlvariant' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BPCHAR AS sys.SQL_VARIANT) +WITH FUNCTION sys.char_sqlvariant (sys.BPCHAR) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.bbfvarbinary_sqlvariant(sys.BBF_VARBINARY) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'bbfvarbinary2sqlvariant' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BBF_VARBINARY AS sys.SQL_VARIANT) +WITH FUNCTION sys.bbfvarbinary_sqlvariant (sys.BBF_VARBINARY) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.bbfbinary_sqlvariant(sys.BBF_BINARY) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'bbfbinary2sqlvariant' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BBF_BINARY AS sys.SQL_VARIANT) +WITH FUNCTION sys.bbfbinary_sqlvariant (sys.BBF_BINARY) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.uniqueidentifier_sqlvariant(sys.UNIQUEIDENTIFIER) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'uniqueidentifier2sqlvariant' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.UNIQUEIDENTIFIER AS sys.SQL_VARIANT) +WITH FUNCTION sys.uniqueidentifier_sqlvariant (sys.UNIQUEIDENTIFIER) AS IMPLICIT; + +-- CAST functions from SQL_VARIANT + +CREATE OR REPLACE FUNCTION sys.sqlvariant_datetime(sys.SQL_VARIANT) +RETURNS sys.DATETIME +AS 'babelfishpg_common', 'sqlvariant2timestamp' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.SQL_VARIANT AS sys.DATETIME) +WITH FUNCTION sys.sqlvariant_datetime (sys.SQL_VARIANT) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.sqlvariant_datetime2(sys.SQL_VARIANT) +RETURNS sys.DATETIME2 +AS 'babelfishpg_common', 'sqlvariant2timestamp' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.SQL_VARIANT AS sys.DATETIME2) +WITH FUNCTION sys.sqlvariant_datetime2 (sys.SQL_VARIANT) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.sqlvariant_datetimeoffset(sys.SQL_VARIANT) +RETURNS sys.DATETIMEOFFSET +AS 'babelfishpg_common', 'sqlvariant2datetimeoffset' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.SQL_VARIANT AS sys.DATETIMEOFFSET) +WITH FUNCTION sys.sqlvariant_datetimeoffset (sys.SQL_VARIANT) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.sqlvariant_smalldatetime(sys.SQL_VARIANT) +RETURNS sys.SMALLDATETIME +AS 'babelfishpg_common', 'sqlvariant2timestamp' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.SQL_VARIANT AS sys.SMALLDATETIME) +WITH FUNCTION sys.sqlvariant_smalldatetime (sys.SQL_VARIANT) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.sqlvariant_date(sys.SQL_VARIANT) +RETURNS DATE +AS 'babelfishpg_common', 'sqlvariant2date' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.SQL_VARIANT AS DATE) +WITH FUNCTION sys.sqlvariant_date (sys.SQL_VARIANT) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.sqlvariant_time(sys.SQL_VARIANT) +RETURNS TIME +AS 'babelfishpg_common', 'sqlvariant2time' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.SQL_VARIANT AS TIME) +WITH FUNCTION sys.sqlvariant_time (sys.SQL_VARIANT) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.sqlvariant_float(sys.SQL_VARIANT) +RETURNS FLOAT +AS 'babelfishpg_common', 'sqlvariant2float' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.SQL_VARIANT AS FLOAT) +WITH FUNCTION sys.sqlvariant_float (sys.SQL_VARIANT) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.sqlvariant_real(sys.SQL_VARIANT) +RETURNS REAL +AS 'babelfishpg_common', 'sqlvariant2real' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.SQL_VARIANT AS REAL) +WITH FUNCTION sys.sqlvariant_real (sys.SQL_VARIANT) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.sqlvariant_numeric(sys.SQL_VARIANT) +RETURNS NUMERIC +AS 'babelfishpg_common', 'sqlvariant2numeric' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.SQL_VARIANT AS NUMERIC) +WITH FUNCTION sys.sqlvariant_numeric (sys.SQL_VARIANT) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.sqlvariant_money(sys.SQL_VARIANT) +RETURNS sys.MONEY +AS 'babelfishpg_common', 'sqlvariant2fixeddecimal' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.sqlvariant_smallmoney(sys.SQL_VARIANT) +RETURNS sys.SMALLMONEY +AS 'babelfishpg_common', 'sqlvariant2fixeddecimal' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.SQL_VARIANT AS FIXEDDECIMAL) +WITH FUNCTION sys.sqlvariant_money (sys.SQL_VARIANT) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.sqlvariant_bigint(sys.SQL_VARIANT) +RETURNS BIGINT +AS 'babelfishpg_common', 'sqlvariant2bigint' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.SQL_VARIANT AS BIGINT) +WITH FUNCTION sys.sqlvariant_bigint (sys.SQL_VARIANT) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.sqlvariant_int(sys.SQL_VARIANT) +RETURNS INT +AS 'babelfishpg_common', 'sqlvariant2int' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.SQL_VARIANT AS INT) +WITH FUNCTION sys.sqlvariant_int (sys.SQL_VARIANT) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.sqlvariant_smallint(sys.SQL_VARIANT) +RETURNS SMALLINT +AS 'babelfishpg_common', 'sqlvariant2smallint' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.sqlvariant_tinyint(sys.SQL_VARIANT) +RETURNS sys.TINYINT +AS 'babelfishpg_common', 'sqlvariant2smallint' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.SQL_VARIANT AS SMALLINT) +WITH FUNCTION sys.sqlvariant_smallint (sys.SQL_VARIANT) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.sqlvariant_bit(sys.SQL_VARIANT) +RETURNS sys.BIT +AS 'babelfishpg_common', 'sqlvariant2bit' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.SQL_VARIANT AS sys.BIT) +WITH FUNCTION sys.sqlvariant_bit (sys.SQL_VARIANT) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.sqlvariant_sysvarchar(sys.SQL_VARIANT) +RETURNS sys.VARCHAR +AS 'babelfishpg_common', 'sqlvariant2varchar' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.SQL_VARIANT AS sys.VARCHAR) +WITH FUNCTION sys.sqlvariant_sysvarchar (sys.SQL_VARIANT) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.sqlvariant_varchar(sys.SQL_VARIANT) +RETURNS pg_catalog.VARCHAR +AS 'babelfishpg_common', 'sqlvariant2varchar' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.SQL_VARIANT AS pg_catalog.VARCHAR) +WITH FUNCTION sys.sqlvariant_varchar (sys.SQL_VARIANT) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.sqlvariant_nvarchar(sys.SQL_VARIANT) +RETURNS sys.NVARCHAR +AS 'babelfishpg_common', 'sqlvariant2varchar' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.sqlvariant_char(sys.SQL_VARIANT) +RETURNS CHAR +AS 'babelfishpg_common', 'sqlvariant2char' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.sqlvariant_nchar(sys.SQL_VARIANT) +RETURNS sys.NCHAR +AS 'babelfishpg_common', 'sqlvariant2char' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.SQL_VARIANT AS CHAR) +WITH FUNCTION sys.sqlvariant_char (sys.SQL_VARIANT) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.sqlvariant_bbfvarbinary(sys.SQL_VARIANT) +RETURNS sys.VARBINARY +AS 'babelfishpg_common', 'sqlvariant2bbfvarbinary' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.SQL_VARIANT AS sys.BBF_VARBINARY) +WITH FUNCTION sys.sqlvariant_bbfvarbinary (sys.SQL_VARIANT) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.sqlvariant_bbfbinary(sys.SQL_VARIANT) +RETURNS sys.BINARY +AS 'babelfishpg_common', 'sqlvariant2bbfbinary' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.SQL_VARIANT AS sys.BBF_BINARY) +WITH FUNCTION sys.sqlvariant_bbfbinary (sys.SQL_VARIANT) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.sqlvariant_uniqueidentifier(sys.SQL_VARIANT) +RETURNS sys.UNIQUEIDENTIFIER +AS 'babelfishpg_common', 'sqlvariant2uniqueidentifier' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.SQL_VARIANT AS sys.UNIQUEIDENTIFIER) +WITH FUNCTION sys.sqlvariant_uniqueidentifier (sys.SQL_VARIANT) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.SQL_VARIANT_PROPERTY(sys.SQL_VARIANT, sys.VARCHAR(20)) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'sql_variant_property' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.sqlvarianteq(sys.SQL_VARIANT, sys.SQL_VARIANT) +RETURNS bool +AS 'babelfishpg_common', 'sqlvarianteq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.sqlvariantne(sys.SQL_VARIANT, sys.SQL_VARIANT) +RETURNS bool +AS 'babelfishpg_common', 'sqlvariantne' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.sqlvariantlt(sys.SQL_VARIANT, sys.SQL_VARIANT) +RETURNS bool +AS 'babelfishpg_common', 'sqlvariantlt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.sqlvariantle(sys.SQL_VARIANT, sys.SQL_VARIANT) +RETURNS bool +AS 'babelfishpg_common', 'sqlvariantle' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.sqlvariantgt(sys.SQL_VARIANT, sys.SQL_VARIANT) +RETURNS bool +AS 'babelfishpg_common', 'sqlvariantgt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.sqlvariantge(sys.SQL_VARIANT, sys.SQL_VARIANT) +RETURNS bool +AS 'babelfishpg_common', 'sqlvariantge' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.= ( + LEFTARG = sys.SQL_VARIANT, + RIGHTARG = sys.SQL_VARIANT, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = sys.sqlvarianteq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR sys.<> ( + LEFTARG = sys.SQL_VARIANT, + RIGHTARG = sys.SQL_VARIANT, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = sys.sqlvariantne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR sys.< ( + LEFTARG = sys.SQL_VARIANT, + RIGHTARG = sys.SQL_VARIANT, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = sys.sqlvariantlt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.<= ( + LEFTARG = sys.SQL_VARIANT, + RIGHTARG = sys.SQL_VARIANT, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = sys.sqlvariantle, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.> ( + LEFTARG = sys.SQL_VARIANT, + RIGHTARG = sys.SQL_VARIANT, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = sys.sqlvariantgt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.>= ( + LEFTARG = sys.SQL_VARIANT, + RIGHTARG = sys.SQL_VARIANT, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = sys.sqlvariantge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE FUNCTION sqlvariant_cmp(sys.SQL_VARIANT, sys.SQL_VARIANT) +RETURNS INT4 +AS 'babelfishpg_common', 'sqlvariant_cmp' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sqlvariant_hash(sys.SQL_VARIANT) +RETURNS INT4 +AS 'babelfishpg_common', 'sqlvariant_hash' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR CLASS sys.sqlvariant_ops +DEFAULT FOR TYPE sys.SQL_VARIANT USING btree AS + OPERATOR 1 < (sys.SQL_VARIANT, sys.SQL_VARIANT), + OPERATOR 2 <= (sys.SQL_VARIANT, sys.SQL_VARIANT), + OPERATOR 3 = (sys.SQL_VARIANT, sys.SQL_VARIANT), + OPERATOR 4 >= (sys.SQL_VARIANT, sys.SQL_VARIANT), + OPERATOR 5 > (sys.SQL_VARIANT, sys.SQL_VARIANT), + FUNCTION 1 sqlvariant_cmp(sys.SQL_VARIANT, sys.SQL_VARIANT); + +CREATE OPERATOR CLASS sys.sqlvariant_ops +DEFAULT FOR TYPE sys.SQL_VARIANT USING hash AS + OPERATOR 1 = (sys.SQL_VARIANT, sys.SQL_VARIANT), + FUNCTION 1 sqlvariant_hash(sys.SQL_VARIANT); +-- 28 "sql/babelfishpg_common.in" 2 +-- 1 "sql/string_operators.sql" 1 +-- 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 VOLATILE; + +-- Support strings for + operator. +CREATE OPERATOR sys.+ ( + LEFTARG = text, + RIGHTARG = text, + FUNCTION = sys.babelfish_concat_wrapper +); + +create or replace function sys.CHAR(x in int)returns char +AS +$body$ +BEGIN + + + + if x between 1 and 255 then + return chr(x); + else + return null; + end if; +END; +$body$ +language plpgsql; + +CREATE OR REPLACE FUNCTION sys.nchar(IN x INTEGER) RETURNS sys.nvarchar +AS +$body$ +BEGIN + --- 1114111 is 0x10FFFF - max value permitted as specified by documentation + if x between 1 and 1114111 then + return(select chr(x))::sys.nvarchar; + else + return null; + end if; +END; +$body$ +LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.nchar(IN x varbinary) RETURNS sys.nvarchar +AS +$body$ +BEGIN + --- 1114111 is 0x10FFFF - max value permitted as specified by documentation + if x::integer between 1 and 1114111 then + return(select chr(x::integer))::sys.nvarchar; + else + return null; + end if; +END; +$body$ +LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE; +-- 29 "sql/babelfishpg_common.in" 2 +-- 1 "sql/coerce.sql" 1 +-- Add Missing casting functions +-- Casting functions used in catalog should use the exact type of castsource and casttarget. + +-- double precision -> int8 +CREATE OR REPLACE FUNCTION sys.dtrunci8(double precision) +RETURNS INT8 +AS 'babelfishpg_common', 'dtrunci8' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- double precision -> int4 +CREATE OR REPLACE FUNCTION sys.dtrunci4(double precision) +RETURNS INT4 +AS 'babelfishpg_common', 'dtrunci4' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- double precision -> int2 +CREATE OR REPLACE FUNCTION sys.dtrunci2(double precision) +RETURNS INT2 +AS 'babelfishpg_common', 'dtrunci2' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- real -> int8 +CREATE OR REPLACE FUNCTION sys.ftrunci8(real) +RETURNS INT8 +AS 'babelfishpg_common', 'ftrunci8' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- real -> int4 +CREATE OR REPLACE FUNCTION sys.ftrunci4(real) +RETURNS INT4 +AS 'babelfishpg_common', 'ftrunci4' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- real -> int2 +CREATE OR REPLACE FUNCTION sys.ftrunci2(real) +RETURNS INT2 +AS 'babelfishpg_common', 'ftrunci2' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +--- XXX: it is desriable to use SQL (or C) rather than plpgsql. But SQL function is not working +--- if tsql is enabled for some reasons. (BABEL-766) + +-- fixeddecimal -> int8 +CREATE OR REPLACE FUNCTION sys._round_fixeddecimal_to_int8(In arg sys.fixeddecimal) +RETURNS INT8 AS $$ +BEGIN + RETURN CAST(round(arg) AS INT8); +END; +$$ LANGUAGE plpgsql; + +-- fixeddecimal -> int8 +CREATE OR REPLACE FUNCTION sys._round_fixeddecimal_to_int4(In arg sys.fixeddecimal) +RETURNS INT4 AS $$ +BEGIN + RETURN CAST(round(arg) AS INT4); +END; +$$ LANGUAGE plpgsql; + +-- fixeddecimal -> int8 +CREATE OR REPLACE FUNCTION sys._round_fixeddecimal_to_int2(In arg sys.fixeddecimal) +RETURNS INT2 AS $$ +BEGIN + RETURN CAST(round(arg) AS INT2); +END; +$$ LANGUAGE plpgsql; + +-- numeric -> int8 +CREATE OR REPLACE FUNCTION sys._trunc_numeric_to_int8(In arg numeric) +RETURNS INT8 AS $$ +BEGIN + RETURN CAST(trunc(arg) AS INT8); +END; +$$ LANGUAGE plpgsql; + +-- numeric -> int4 +CREATE OR REPLACE FUNCTION sys._trunc_numeric_to_int4(In arg numeric) +RETURNS INT4 AS $$ +BEGIN + RETURN CAST(trunc(arg) AS INT4); +END; +$$ LANGUAGE plpgsql; + +-- numeric -> int2 +CREATE OR REPLACE FUNCTION sys._trunc_numeric_to_int2(In arg numeric) +RETURNS INT2 AS $$ +BEGIN + RETURN CAST(trunc(arg) AS INT2); +END; +$$ LANGUAGE plpgsql; + +-- text -> fixeddecimal +CREATE FUNCTION sys.char_to_fixeddecimal(text) +RETURNS sys.FIXEDDECIMAL +AS 'babelfishpg_money', 'char_to_fixeddecimal' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- char -> fixeddecimal +CREATE FUNCTION sys.char_to_fixeddecimal(char) +RETURNS sys.FIXEDDECIMAL +AS 'babelfishpg_money', 'char_to_fixeddecimal' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.char_to_fixeddecimal(sys.bpchar) +RETURNS sys.FIXEDDECIMAL +AS 'babelfishpg_money', 'char_to_fixeddecimal' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- varchar -> fixeddecimal +CREATE FUNCTION sys.char_to_fixeddecimal(sys.varchar) +RETURNS sys.FIXEDDECIMAL +AS 'babelfishpg_money', 'char_to_fixeddecimal' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.char_to_fixeddecimal(pg_catalog.varchar) +RETURNS sys.FIXEDDECIMAL +AS 'babelfishpg_money', 'char_to_fixeddecimal' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- text -> name +CREATE FUNCTION sys.text_to_name(text) +RETURNS pg_catalog.name +AS 'babelfishpg_common', 'pltsql_text_name' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- bpchar -> name +CREATE FUNCTION sys.bpchar_to_name(pg_catalog.bpchar) +RETURNS pg_catalog.name +AS 'babelfishpg_common', 'pltsql_bpchar_name' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.bpchar_to_name(sys.bpchar) +RETURNS pg_catalog.name +AS 'babelfishpg_common', 'pltsql_bpchar_name' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- varchar -> name +CREATE FUNCTION sys.varchar_to_name(sys.varchar) +RETURNS pg_catalog.name +AS 'babelfishpg_common', 'pltsql_text_name' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.varchar_to_name(pg_catalog.varchar) +RETURNS pg_catalog.name +AS 'babelfishpg_common', 'pltsql_text_name' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; +-- 30 "sql/babelfishpg_common.in" 2 + +-- 1 "sql/utils.sql" 1 +CREATE OR REPLACE PROCEDURE sys.babel_type_initializer() +LANGUAGE C +AS 'babelfishpg_common', 'init_tcode_trans_tab'; +CALL sys.babel_type_initializer(); +DROP PROCEDURE sys.babel_type_initializer(); + +CREATE OR REPLACE FUNCTION sys.babelfish_typecode_list() +RETURNS table ( + oid int, + pg_namespace text, + pg_typname text, + tsql_typname text, + type_family_priority smallint, + priority smallint, + sql_variant_hdr_size smallint +) AS 'babelfishpg_common', 'typecode_list' LANGUAGE C; +-- 32 "sql/babelfishpg_common.in" 2 + + + + + + +SELECT set_config('search_path', trim(leading 'sys, ' from current_setting('search_path')), false); +RESET client_min_messages; diff --git a/contrib/babelfishpg_common/sql/babelfishpg_common.in b/contrib/babelfishpg_common/sql/babelfishpg_common.in new file mode 100644 index 00000000000..8a43693c404 --- /dev/null +++ b/contrib/babelfishpg_common/sql/babelfishpg_common.in @@ -0,0 +1,39 @@ +/* + * All objects created by the included files will be created in sys + */ + + +CREATE SCHEMA sys; +GRANT USAGE ON SCHEMA sys TO PUBLIC; + + +SELECT set_config('search_path', 'sys, '||current_setting('search_path'), false); + +#include "money/fixeddecimal--1.1.0_base_parallel.sql" +#include "money/fixeddecimal--parallelaggs.sql" +#include "money/fixeddecimal--brin.sql" +#include "bpchar.sql" +#include "varchar.sql" +#include "numerics.sql" +#include "strings.sql" +#include "bit.sql" +#include "varbinary.sql" +#include "binary.sql" +#include "uniqueidentifier.sql" +#include "datetime.sql" +#include "datetime2.sql" +#include "smalldatetime.sql" +#include "datetimeoffset.sql" +#include "sqlvariant.sql" +#include "string_operators.sql" +#include "coerce.sql" + +#include "utils.sql" + +/* + * Remove schema sys from search_path otherwise it causes BABEL-257 for some reason + * Notice schema sys will be automatically added to implicitly-searched namespaces by + * recomputeNamespacePath() in tsql dialect + */ +SELECT set_config('search_path', trim(leading 'sys, ' from current_setting('search_path')), false); +RESET client_min_messages; diff --git a/contrib/babelfishpg_common/sql/binary.sql b/contrib/babelfishpg_common/sql/binary.sql new file mode 100644 index 00000000000..9e0802ee396 --- /dev/null +++ b/contrib/babelfishpg_common/sql/binary.sql @@ -0,0 +1,275 @@ +-- sys.BINARY +CREATE TYPE sys.BBF_BINARY; + +CREATE OR REPLACE FUNCTION sys.binaryin(cstring, oid, integer) +RETURNS sys.BBF_BINARY +AS 'babelfishpg_common', 'varbinaryin' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.binaryout(sys.BBF_BINARY) +RETURNS cstring +AS 'babelfishpg_common', 'varbinaryout' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.binaryrecv(internal, oid, integer) +RETURNS sys.BBF_BINARY +AS 'babelfishpg_common', 'varbinaryrecv' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.binarysend(sys.BBF_BINARY) +RETURNS bytea +AS 'babelfishpg_common', 'varbinarysend' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.binarytypmodin(cstring[]) +RETURNS integer +AS 'babelfishpg_common', 'varbinarytypmodin' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.binarytypmodout(integer) +RETURNS cstring +AS 'babelfishpg_common', 'varbinarytypmodout' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE TYPE sys.BBF_BINARY ( + INPUT = sys.binaryin, + OUTPUT = sys.binaryout, + RECEIVE = sys.binaryrecv, + SEND = sys.binarysend, + TYPMOD_IN = sys.binarytypmodin, + TYPMOD_OUT = sys.binarytypmodout, + INTERNALLENGTH = VARIABLE, + ALIGNMENT = 'int4', + STORAGE = 'extended', + CATEGORY = 'U', + PREFERRED = false, + COLLATABLE = false +); + +-- casting functions for sys.BINARY +CREATE OR REPLACE FUNCTION sys.varcharbinary(sys.VARCHAR, integer, boolean) +RETURNS sys.BBF_BINARY +AS 'babelfishpg_common', 'varcharbinary' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.VARCHAR AS sys.BBF_BINARY) +WITH FUNCTION sys.varcharbinary (sys.VARCHAR, integer, boolean) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.varcharbinary(pg_catalog.VARCHAR, integer, boolean) +RETURNS sys.BBF_BINARY +AS 'babelfishpg_common', 'varcharbinary' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (pg_catalog.VARCHAR AS sys.BBF_BINARY) +WITH FUNCTION sys.varcharbinary (pg_catalog.VARCHAR, integer, boolean) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.bpcharbinary(pg_catalog.BPCHAR, integer, boolean) +RETURNS sys.BBF_BINARY +AS 'babelfishpg_common', 'bpcharbinary' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (pg_catalog.BPCHAR AS sys.BBF_BINARY) +WITH FUNCTION sys.bpcharbinary (pg_catalog.BPCHAR, integer, boolean) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.bpcharbinary(sys.BPCHAR, integer, boolean) +RETURNS sys.BBF_BINARY +AS 'babelfishpg_common', 'bpcharbinary' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BPCHAR AS sys.BBF_BINARY) +WITH FUNCTION sys.bpcharbinary (sys.BPCHAR, integer, boolean) AS ASSIGNMENT; + + +CREATE OR REPLACE FUNCTION sys.binarysysvarchar(sys.BBF_BINARY) +RETURNS sys.VARCHAR +AS 'babelfishpg_common', 'varbinaryvarchar' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BBF_BINARY AS sys.VARCHAR) +WITH FUNCTION sys.binarysysvarchar (sys.BBF_BINARY) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.binaryvarchar(sys.BBF_BINARY) +RETURNS pg_catalog.VARCHAR +AS 'babelfishpg_common', 'varbinaryvarchar' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BBF_BINARY AS pg_catalog.VARCHAR) +WITH FUNCTION sys.binaryvarchar (sys.BBF_BINARY) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.int2binary(INT2, integer, boolean) +RETURNS sys.BBF_BINARY +AS 'babelfishpg_common', 'int2binary' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (INT2 AS sys.BBF_BINARY) +WITH FUNCTION sys.int2binary (INT2, integer, boolean) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.int4binary(INT4, integer, boolean) +RETURNS sys.BBF_BINARY +AS 'babelfishpg_common', 'int4binary' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (INT4 AS sys.BBF_BINARY) +WITH FUNCTION sys.int4binary (INT4, integer, boolean) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.int8binary(INT8, integer, boolean) +RETURNS sys.BBF_BINARY +AS 'babelfishpg_common', 'int8binary' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (INT8 AS sys.BBF_BINARY) +WITH FUNCTION sys.int8binary (INT8, integer, boolean) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.binaryint2(sys.BBF_BINARY) +RETURNS INT2 +AS 'babelfishpg_common', 'binaryint2' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BBF_BINARY as INT2) +WITH FUNCTION sys.binaryint2 (sys.BBF_BINARY) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.binaryint4(sys.BBF_BINARY) +RETURNS INT4 +AS 'babelfishpg_common', 'binaryint4' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BBF_BINARY as INT4) +WITH FUNCTION sys.binaryint4 (sys.BBF_BINARY) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.binaryint8(sys.BBF_BINARY) +RETURNS INT8 +AS 'babelfishpg_common', 'binaryint8' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BBF_BINARY as INT8) +WITH FUNCTION sys.binaryint8 (sys.BBF_BINARY) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.float4binary(REAL, integer, boolean) +RETURNS sys.BBF_BINARY +AS 'babelfishpg_common', 'float4binary' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (REAL AS sys.BBF_BINARY) +WITH FUNCTION sys.float4binary (REAL, integer, boolean) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.float8binary(DOUBLE PRECISION, integer, boolean) +RETURNS sys.BBF_BINARY +AS 'babelfishpg_common', 'float8binary' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (DOUBLE PRECISION AS sys.BBF_BINARY) +WITH FUNCTION sys.float8binary (DOUBLE PRECISION, integer, boolean) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.binaryfloat4(sys.BBF_BINARY) +RETURNS REAL +AS 'babelfishpg_common', 'binaryfloat4' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.binaryfloat8(sys.BBF_BINARY) +RETURNS DOUBLE PRECISION +AS 'babelfishpg_common', 'binaryfloat8' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE DOMAIN sys.IMAGE AS sys.BBF_VARBINARY; + +SET enable_domain_typmod = TRUE; +CREATE DOMAIN sys.BINARY AS sys.BBF_BINARY; +RESET enable_domain_typmod; + +CREATE OR REPLACE FUNCTION sys.binary(sys.BINARY, integer, boolean) +RETURNS sys.BINARY +AS 'babelfishpg_common', 'binary' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +SET client_min_messages = 'ERROR'; +CREATE CAST (sys.BINARY AS sys.BINARY) +WITH FUNCTION sys.binary (sys.BINARY, integer, BOOLEAN) AS ASSIGNMENT; +SET client_min_messages = 'WARNING'; + +CREATE FUNCTION sys.binary_eq(leftarg sys.bbf_binary, rightarg sys.bbf_binary) +RETURNS boolean +AS 'babelfishpg_common', 'varbinary_eq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.= ( + LEFTARG = sys.bbf_binary, + RIGHTARG = sys.bbf_binary, + FUNCTION = sys.binary_eq, + COMMUTATOR = = +); + + +CREATE FUNCTION sys.binary_neq(leftarg sys.bbf_binary, rightarg sys.bbf_binary) +RETURNS boolean +AS 'babelfishpg_common', 'varbinary_neq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.<> ( + LEFTARG = sys.bbf_binary, + RIGHTARG = sys.bbf_binary, + FUNCTION = sys.binary_neq, + COMMUTATOR = <> +); + +CREATE FUNCTION sys.binary_gt(leftarg sys.bbf_binary, rightarg sys.bbf_binary) +RETURNS boolean +AS 'babelfishpg_common', 'varbinary_gt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.> ( + LEFTARG = sys.bbf_binary, + RIGHTARG = sys.bbf_binary, + FUNCTION = sys.binary_gt, + COMMUTATOR = < +); + +CREATE FUNCTION sys.binary_geq(leftarg sys.bbf_binary, rightarg sys.bbf_binary) +RETURNS boolean +AS 'babelfishpg_common', 'varbinary_geq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.>= ( + LEFTARG = sys.bbf_binary, + RIGHTARG = sys.bbf_binary, + FUNCTION = sys.binary_geq, + COMMUTATOR = <= +); + +CREATE FUNCTION sys.binary_lt(leftarg sys.bbf_binary, rightarg sys.bbf_binary) +RETURNS boolean +AS 'babelfishpg_common', 'varbinary_eq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.< ( + LEFTARG = sys.bbf_binary, + RIGHTARG = sys.bbf_binary, + FUNCTION = sys.binary_lt, + COMMUTATOR = > +); + +CREATE FUNCTION sys.binary_leq(leftarg sys.bbf_binary, rightarg sys.bbf_binary) +RETURNS boolean +AS 'babelfishpg_common', 'varbinary_leq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.<= ( + LEFTARG = sys.bbf_binary, + RIGHTARG = sys.bbf_binary, + FUNCTION = sys.binary_leq, + COMMUTATOR = >= +); + +CREATE FUNCTION sys.bbf_binary_cmp(sys.bbf_binary, sys.bbf_binary) +RETURNS int +AS 'babelfishpg_common', 'varbinary_cmp' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR CLASS sys.bbf_binary_ops +DEFAULT FOR TYPE sys.bbf_binary USING btree AS + OPERATOR 1 < (sys.bbf_binary, sys.bbf_binary), + OPERATOR 2 <= (sys.bbf_binary, sys.bbf_binary), + OPERATOR 3 = (sys.bbf_binary, sys.bbf_binary), + OPERATOR 4 >= (sys.bbf_binary, sys.bbf_binary), + OPERATOR 5 > (sys.bbf_binary, sys.bbf_binary), + FUNCTION 1 sys.bbf_binary_cmp(sys.bbf_binary, sys.bbf_binary); + diff --git a/contrib/babelfishpg_common/sql/bit.sql b/contrib/babelfishpg_common/sql/bit.sql new file mode 100644 index 00000000000..2e0dea70c16 --- /dev/null +++ b/contrib/babelfishpg_common/sql/bit.sql @@ -0,0 +1,431 @@ +CREATE TYPE sys.BIT; + +CREATE OR REPLACE FUNCTION sys.bitin(cstring) +RETURNS sys.BIT +AS 'babelfishpg_common', 'bitin' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.bitout(sys.BIT) +RETURNS cstring +AS 'babelfishpg_common', 'bitout' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.bitrecv(internal) +RETURNS sys.BIT +AS 'babelfishpg_common', 'bitrecv' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.bitsend(sys.BIT) +RETURNS bytea +AS 'babelfishpg_common', 'bitsend' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE TYPE sys.BIT ( + INPUT = sys.bitin, + OUTPUT = sys.bitout, + RECEIVE = sys.bitrecv, + SEND = sys.bitsend, + INTERNALLENGTH = 1, + PASSEDBYVALUE, + ALIGNMENT = 'char', + STORAGE = 'plain', + CATEGORY = 'B', + PREFERRED = true, + COLLATABLE = false + ); + +CREATE OR REPLACE FUNCTION sys.int2bit(INT2) +RETURNS sys.BIT +AS 'babelfishpg_common', 'int2bit' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (INT2 AS sys.BIT) +WITH FUNCTION sys.int2bit (INT2) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.int4bit(INT4) +RETURNS sys.BIT +AS 'babelfishpg_common', 'int4bit' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (INT4 AS sys.BIT) +WITH FUNCTION sys.int4bit (INT4) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.int8bit(INT8) +RETURNS sys.BIT +AS 'babelfishpg_common', 'int8bit' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (INT8 AS sys.BIT) +WITH FUNCTION sys.int8bit (INT8) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.ftobit(REAL) +RETURNS sys.BIT +AS 'babelfishpg_common', 'ftobit' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (REAL AS sys.BIT) +WITH FUNCTION sys.ftobit (REAL) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.dtobit(DOUBLE PRECISION) +RETURNS sys.BIT +AS 'babelfishpg_common', 'dtobit' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (DOUBLE PRECISION AS sys.BIT) +WITH FUNCTION sys.dtobit (DOUBLE PRECISION) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.numeric_bit(NUMERIC) +RETURNS sys.BIT +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; + +CREATE OR REPLACE FUNCTION sys.bit2int2(sys.BIT) +RETURNS INT2 +AS 'babelfishpg_common', 'bit2int2' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BIT AS INT2) +WITH FUNCTION sys.bit2int2 (sys.BIT) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.bit2int4(sys.BIT) +RETURNS INT4 +AS 'babelfishpg_common', 'bit2int4' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BIT AS INT4) +WITH FUNCTION sys.bit2int4 (sys.BIT) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.bit2int8(sys.BIT) +RETURNS INT8 +AS 'babelfishpg_common', 'bit2int8' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BIT AS INT8) +WITH FUNCTION sys.bit2int8 (sys.BIT) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.bit2numeric(sys.BIT) +RETURNS NUMERIC +AS 'babelfishpg_common', 'bit2numeric' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BIT AS NUMERIC) +WITH FUNCTION sys.bit2numeric (sys.BIT) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.bit2fixeddec(sys.BIT) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_common', 'bit2fixeddec' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BIT AS FIXEDDECIMAL) +WITH FUNCTION sys.bit2fixeddec (sys.BIT) AS IMPLICIT; + +CREATE FUNCTION sys.bitneg(sys.BIT) +RETURNS sys.BIT +AS 'babelfishpg_common', 'bitneg' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.biteq(sys.BIT, sys.BIT) +RETURNS bool +AS 'babelfishpg_common', 'biteq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.bitne(sys.BIT, sys.BIT) +RETURNS bool +AS 'babelfishpg_common', 'bitne' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.bitlt(sys.BIT, sys.BIT) +RETURNS bool +AS 'babelfishpg_common', 'bitlt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.bitle(sys.BIT, sys.BIT) +RETURNS bool +AS 'babelfishpg_common', 'bitle' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.bitgt(sys.BIT, sys.BIT) +RETURNS bool +AS 'babelfishpg_common', 'bitgt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.bitge(sys.BIT, sys.BIT) +RETURNS bool +AS 'babelfishpg_common', 'bitge' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.bit_cmp(sys.BIT, sys.BIT) +RETURNS int +AS 'babelfishpg_common', 'bit_cmp' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +/* Operators for sys.BIT. TSQL doesn't support + - * / for bit */ +CREATE OPERATOR sys.- ( + RIGHTARG = sys.BIT, + PROCEDURE = sys.bitneg +); + +CREATE OPERATOR sys.= ( + LEFTARG = sys.BIT, + RIGHTARG = sys.BIT, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = sys.biteq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR sys.<> ( + LEFTARG = sys.BIT, + RIGHTARG = sys.BIT, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = sys.bitne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR sys.< ( + LEFTARG = sys.BIT, + RIGHTARG = sys.BIT, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = sys.bitlt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.<= ( + LEFTARG = sys.BIT, + RIGHTARG = sys.BIT, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = sys.bitle, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.> ( + LEFTARG = sys.BIT, + RIGHTARG = sys.BIT, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = sys.bitgt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.>= ( + LEFTARG = sys.BIT, + RIGHTARG = sys.BIT, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = sys.bitge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR CLASS sys.bit_ops +DEFAULT FOR TYPE sys.bit USING btree AS + OPERATOR 1 < (sys.bit, sys.bit), + OPERATOR 2 <= (sys.bit, sys.bit), + OPERATOR 3 = (sys.bit, sys.bit), + OPERATOR 4 >= (sys.bit, sys.bit), + OPERATOR 5 > (sys.bit, sys.bit), + FUNCTION 1 sys.bit_cmp(sys.bit, sys.bit); + +/* Comparison between int and bit */ +CREATE FUNCTION sys.int4biteq(INT4, sys.BIT) +RETURNS bool +AS 'babelfishpg_common', 'int4biteq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int4bitne(INT4, sys.BIT) +RETURNS bool +AS 'babelfishpg_common', 'int4bitne' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int4bitlt(INT4, sys.BIT) +RETURNS bool +AS 'babelfishpg_common', 'int4bitlt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int4bitle(INT4, sys.BIT) +RETURNS bool +AS 'babelfishpg_common', 'int4bitle' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int4bitgt(INT4, sys.BIT) +RETURNS bool +AS 'babelfishpg_common', 'int4bitgt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int4bitge(INT4, sys.BIT) +RETURNS bool +AS 'babelfishpg_common', 'int4bitge' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.= ( + LEFTARG = INT4, + RIGHTARG = sys.BIT, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = sys.int4biteq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR sys.<> ( + LEFTARG = INT4, + RIGHTARG = sys.BIT, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = sys.int4bitne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR sys.< ( + LEFTARG = INT4, + RIGHTARG = sys.BIT, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = sys.int4bitlt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.<= ( + LEFTARG = INT4, + RIGHTARG = sys.BIT, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = sys.int4bitle, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.> ( + LEFTARG = INT4, + RIGHTARG = sys.BIT, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = sys.int4bitgt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.>= ( + LEFTARG = INT4, + RIGHTARG = sys.BIT, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = sys.int4bitge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +/* Comparison between bit and int */ +CREATE FUNCTION sys.bitint4eq(sys.BIT, INT4) +RETURNS bool +AS 'babelfishpg_common', 'bitint4eq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.bitint4ne(sys.BIT, INT4) +RETURNS bool +AS 'babelfishpg_common', 'bitint4ne' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.bitint4lt(sys.BIT, INT4) +RETURNS bool +AS 'babelfishpg_common', 'bitint4lt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.bitint4le(sys.BIT, INT4) +RETURNS bool +AS 'babelfishpg_common', 'bitint4le' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.bitint4gt(sys.BIT, INT4) +RETURNS bool +AS 'babelfishpg_common', 'bitint4gt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.bitint4ge(sys.BIT, INT4) +RETURNS bool +AS 'babelfishpg_common', 'bitint4ge' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.= ( + LEFTARG = sys.BIT, + RIGHTARG = INT4, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = sys.bitint4eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR sys.<> ( + LEFTARG = sys.BIT, + RIGHTARG = INT4, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = sys.bitint4ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR sys.< ( + LEFTARG = sys.BIT, + RIGHTARG = INT4, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = sys.bitint4lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.<= ( + LEFTARG = sys.BIT, + RIGHTARG = INT4, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = sys.bitint4le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.> ( + LEFTARG = sys.BIT, + RIGHTARG = INT4, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = sys.bitint4gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.>= ( + LEFTARG = sys.BIT, + RIGHTARG = INT4, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = sys.bitint4ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OR REPLACE FUNCTION sys.bitxor(leftarg pg_catalog.bit, rightarg pg_catalog.bit) +RETURNS pg_catalog.bit +AS $$ +SELECT (leftarg & ~rightarg) | (~leftarg & rightarg); +$$ +LANGUAGE SQL; + diff --git a/contrib/babelfishpg_common/sql/bpchar.sql b/contrib/babelfishpg_common/sql/bpchar.sql new file mode 100644 index 00000000000..876065da79f --- /dev/null +++ b/contrib/babelfishpg_common/sql/bpchar.sql @@ -0,0 +1,298 @@ +CREATE TYPE sys.BPCHAR; + +-- Basic functions +CREATE OR REPLACE FUNCTION sys.bpcharin(cstring) +RETURNS sys.BPCHAR +AS 'babelfishpg_common', 'bpcharin' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.bpcharout(sys.BPCHAR) +RETURNS cstring +AS 'bpcharout' +LANGUAGE INTERNAL IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.bpcharrecv(internal) +RETURNS sys.BPCHAR +AS 'babelfishpg_common', 'bpcharrecv' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.bpcharsend(sys.BPCHAR) +RETURNS bytea +AS 'bpcharsend' +LANGUAGE INTERNAL IMMUTABLE STRICT PARALLEL SAFE; + +CREATE TYPE sys.BPCHAR ( + INPUT = sys.bpcharin, + OUTPUT = sys.bpcharout, + RECEIVE = sys.bpcharrecv, + SEND = sys.bpcharsend, + TYPMOD_IN = bpchartypmodin, + TYPMOD_OUT = bpchartypmodout, + CATEGORY = 'S', + COLLATABLE = True, + LIKE = pg_catalog.BPCHAR +); + +-- Basic operator functions +CREATE FUNCTION sys.bpchareq(sys.BPCHAR, sys.BPCHAR) +RETURNS bool +AS 'bpchareq' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.bpcharne(sys.BPCHAR, sys.BPCHAR) +RETURNS bool +AS 'bpcharne' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.bpcharlt(sys.BPCHAR, sys.BPCHAR) +RETURNS bool +AS 'bpcharlt' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.bpcharle(sys.BPCHAR, sys.BPCHAR) +RETURNS bool +AS 'bpcharle' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.bpchargt(sys.BPCHAR, sys.BPCHAR) +RETURNS bool +AS 'bpchargt' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.bpcharge(sys.BPCHAR, sys.BPCHAR) +RETURNS bool +AS 'bpcharge' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +-- Basic operators +-- Note that if those operators are not in pg_catalog, we will see different behaviors depending on sql_dialect +CREATE OPERATOR pg_catalog.= ( + LEFTARG = sys.BPCHAR, + RIGHTARG = sys.BPCHAR, + COMMUTATOR = OPERATOR(pg_catalog.=), + NEGATOR = OPERATOR(pg_catalog.<>), + PROCEDURE = sys.bpchareq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES, + HASHES +); + +CREATE OPERATOR pg_catalog.<> ( + LEFTARG = sys.BPCHAR, + RIGHTARG = sys.BPCHAR, + NEGATOR = OPERATOR(pg_catalog.=), + COMMUTATOR = OPERATOR(pg_catalog.<>), + PROCEDURE = sys.bpcharne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR pg_catalog.< ( + LEFTARG = sys.BPCHAR, + RIGHTARG = sys.BPCHAR, + NEGATOR = OPERATOR(pg_catalog.>=), + COMMUTATOR = OPERATOR(pg_catalog.>), + PROCEDURE = sys.bpcharlt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR pg_catalog.<= ( + LEFTARG = sys.BPCHAR, + RIGHTARG = sys.BPCHAR, + NEGATOR = OPERATOR(pg_catalog.>), + COMMUTATOR = OPERATOR(pg_catalog.>=), + PROCEDURE = sys.bpcharle, + RESTRICT = scalarlesel, + JOIN = scalarlejoinsel +); + +CREATE OPERATOR pg_catalog.> ( + LEFTARG = sys.BPCHAR, + RIGHTARG = sys.BPCHAR, + NEGATOR = OPERATOR(pg_catalog.<=), + COMMUTATOR = OPERATOR(pg_catalog.<), + PROCEDURE = sys.bpchargt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR pg_catalog.>= ( + LEFTARG = sys.BPCHAR, + RIGHTARG = sys.BPCHAR, + NEGATOR = OPERATOR(pg_catalog.<), + COMMUTATOR = OPERATOR(pg_catalog.<=), + PROCEDURE = sys.bpcharge, + RESTRICT = scalargesel, + JOIN = scalargejoinsel +); + +-- Operator classes +CREATE FUNCTION sys.bpcharcmp(sys.BPCHAR, sys.BPCHAR) +RETURNS INT4 +AS 'bpcharcmp' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.hashbpchar(sys.BPCHAR) +RETURNS INT4 +AS 'hashbpchar' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR CLASS bpchar_ops + DEFAULT FOR TYPE sys.BPCHAR USING btree AS + OPERATOR 1 pg_catalog.< (sys.BPCHAR, sys.BPCHAR), + OPERATOR 2 pg_catalog.<= (sys.BPCHAR, sys.BPCHAR), + OPERATOR 3 pg_catalog.= (sys.BPCHAR, sys.BPCHAR), + OPERATOR 4 pg_catalog.>= (sys.BPCHAR, sys.BPCHAR), + OPERATOR 5 pg_catalog.> (sys.BPCHAR, sys.BPCHAR), + FUNCTION 1 sys.bpcharcmp(sys.BPCHAR, sys.BPCHAR); + +CREATE OPERATOR CLASS bpchar_ops + DEFAULT FOR TYPE sys.BPCHAR USING hash AS + OPERATOR 1 pg_catalog.= (sys.BPCHAR, sys.BPCHAR), + FUNCTION 1 sys.hashbpchar(sys.BPCHAR); + +CREATE OR REPLACE FUNCTION sys.bpchar(sys.BPCHAR, integer, boolean) +RETURNS sys.BPCHAR +AS 'babelfishpg_common', 'bpchar' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- To sys.BPCHAR +CREATE CAST (sys.BPCHAR AS sys.BPCHAR) +WITH FUNCTION sys.BPCHAR (sys.BPCHAR, integer, boolean) AS IMPLICIT; + +CREATE CAST (pg_catalog.VARCHAR as sys.BPCHAR) +WITHOUT FUNCTION AS IMPLICIT; + +CREATE CAST (pg_catalog.TEXT as sys.BPCHAR) +WITHOUT FUNCTION AS IMPLICIT; + +CREATE CAST (pg_catalog.BOOL as sys.BPCHAR) +WITH FUNCTION pg_catalog.text(pg_catalog.BOOL) AS ASSIGNMENT; + +-- From sys.BPCHAR +CREATE CAST (sys.BPCHAR AS pg_catalog.BPCHAR) +WITHOUT FUNCTION AS IMPLICIT; + +CREATE CAST (sys.BPCHAR as pg_catalog.VARCHAR) +WITHOUT FUNCTION AS IMPLICIT; + +CREATE CAST (sys.BPCHAR as pg_catalog.TEXT) +WITHOUT FUNCTION AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.bpchar2int2(sys.BPCHAR) +RETURNS INT2 +AS 'babelfishpg_common', 'bpchar2int2' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BPCHAR AS INT2) +WITH FUNCTION sys.bpchar2int2(sys.BPCHAR) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.bpchar2int4(sys.BPCHAR) +RETURNS INT4 +AS 'babelfishpg_common', 'bpchar2int4' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BPCHAR AS INT4) +WITH FUNCTION sys.bpchar2int4(sys.BPCHAR) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.bpchar2int8(sys.BPCHAR) +RETURNS INT8 +AS 'babelfishpg_common', 'bpchar2int8' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BPCHAR AS INT8) +WITH FUNCTION sys.bpchar2int8(sys.BPCHAR) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.bpchar2float4(sys.BPCHAR) +RETURNS FLOAT4 +AS 'babelfishpg_common', 'bpchar2float4' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BPCHAR AS FLOAT4) +WITH FUNCTION sys.bpchar2float4(sys.BPCHAR) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.bpchar2float8(sys.BPCHAR) +RETURNS FLOAT8 +AS 'babelfishpg_common', 'bpchar2float8' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BPCHAR AS FLOAT8) +WITH FUNCTION sys.bpchar2float8(sys.BPCHAR) AS IMPLICIT; + +-- Operators between different types +CREATE FUNCTION sys.bpchareq(sys.BPCHAR, pg_catalog.TEXT) +RETURNS bool +AS 'bpchareq' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.bpchareq(pg_catalog.TEXT, sys.BPCHAR) +RETURNS bool +AS 'bpchareq' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.bpcharne(sys.BPCHAR, pg_catalog.TEXT) +RETURNS bool +AS 'bpcharne' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.bpcharne(pg_catalog.TEXT, sys.BPCHAR) +RETURNS bool +AS 'bpcharne' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR pg_catalog.= ( + LEFTARG = sys.BPCHAR, + RIGHTARG = pg_catalog.TEXT, + COMMUTATOR = OPERATOR(pg_catalog.=), + NEGATOR = OPERATOR(pg_catalog.<>), + PROCEDURE = sys.bpchareq, + RESTRICT = eqsel, + JOIN = eqjoinsel +); + +CREATE OPERATOR pg_catalog.= ( + LEFTARG = pg_catalog.TEXT, + RIGHTARG = sys.BPCHAR, + COMMUTATOR = OPERATOR(pg_catalog.=), + NEGATOR = OPERATOR(pg_catalog.<>), + PROCEDURE = sys.bpchareq, + RESTRICT = eqsel, + JOIN = eqjoinsel +); + +CREATE OPERATOR pg_catalog.<> ( + LEFTARG = sys.BPCHAR, + RIGHTARG = pg_catalog.TEXT, + NEGATOR = OPERATOR(pg_catalog.=), + COMMUTATOR = OPERATOR(pg_catalog.<>), + PROCEDURE = sys.bpcharne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR pg_catalog.<> ( + LEFTARG = pg_catalog.TEXT, + RIGHTARG = sys.BPCHAR, + NEGATOR = OPERATOR(pg_catalog.=), + COMMUTATOR = OPERATOR(pg_catalog.<>), + PROCEDURE = sys.bpcharne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +SET enable_domain_typmod = TRUE; +CREATE DOMAIN sys.NCHAR AS sys.BPCHAR; +RESET enable_domain_typmod; + +CREATE OR REPLACE FUNCTION sys.nchar(sys.nchar, integer, boolean) +RETURNS sys.nchar +AS 'babelfishpg_common', 'bpchar' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + + +SET client_min_messages = 'ERROR'; +CREATE CAST (sys.nchar AS sys.nchar) +WITH FUNCTION sys.nchar (sys.nchar, integer, BOOLEAN) AS ASSIGNMENT; +SET client_min_messages = 'WARNING'; diff --git a/contrib/babelfishpg_common/sql/coerce.sql b/contrib/babelfishpg_common/sql/coerce.sql new file mode 100644 index 00000000000..23c5f9a3544 --- /dev/null +++ b/contrib/babelfishpg_common/sql/coerce.sql @@ -0,0 +1,145 @@ +-- Add Missing casting functions +-- Casting functions used in catalog should use the exact type of castsource and casttarget. + +-- double precision -> int8 +CREATE OR REPLACE FUNCTION sys.dtrunci8(double precision) +RETURNS INT8 +AS 'babelfishpg_common', 'dtrunci8' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- double precision -> int4 +CREATE OR REPLACE FUNCTION sys.dtrunci4(double precision) +RETURNS INT4 +AS 'babelfishpg_common', 'dtrunci4' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- double precision -> int2 +CREATE OR REPLACE FUNCTION sys.dtrunci2(double precision) +RETURNS INT2 +AS 'babelfishpg_common', 'dtrunci2' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- real -> int8 +CREATE OR REPLACE FUNCTION sys.ftrunci8(real) +RETURNS INT8 +AS 'babelfishpg_common', 'ftrunci8' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- real -> int4 +CREATE OR REPLACE FUNCTION sys.ftrunci4(real) +RETURNS INT4 +AS 'babelfishpg_common', 'ftrunci4' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- real -> int2 +CREATE OR REPLACE FUNCTION sys.ftrunci2(real) +RETURNS INT2 +AS 'babelfishpg_common', 'ftrunci2' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +--- XXX: it is desriable to use SQL (or C) rather than plpgsql. But SQL function is not working +--- if tsql is enabled for some reasons. (BABEL-766) + +-- fixeddecimal -> int8 +CREATE OR REPLACE FUNCTION sys._round_fixeddecimal_to_int8(In arg sys.fixeddecimal) +RETURNS INT8 AS $$ +BEGIN + RETURN CAST(round(arg) AS INT8); +END; +$$ LANGUAGE plpgsql; + +-- fixeddecimal -> int8 +CREATE OR REPLACE FUNCTION sys._round_fixeddecimal_to_int4(In arg sys.fixeddecimal) +RETURNS INT4 AS $$ +BEGIN + RETURN CAST(round(arg) AS INT4); +END; +$$ LANGUAGE plpgsql; + +-- fixeddecimal -> int8 +CREATE OR REPLACE FUNCTION sys._round_fixeddecimal_to_int2(In arg sys.fixeddecimal) +RETURNS INT2 AS $$ +BEGIN + RETURN CAST(round(arg) AS INT2); +END; +$$ LANGUAGE plpgsql; + +-- numeric -> int8 +CREATE OR REPLACE FUNCTION sys._trunc_numeric_to_int8(In arg numeric) +RETURNS INT8 AS $$ +BEGIN + RETURN CAST(trunc(arg) AS INT8); +END; +$$ LANGUAGE plpgsql; + +-- numeric -> int4 +CREATE OR REPLACE FUNCTION sys._trunc_numeric_to_int4(In arg numeric) +RETURNS INT4 AS $$ +BEGIN + RETURN CAST(trunc(arg) AS INT4); +END; +$$ LANGUAGE plpgsql; + +-- numeric -> int2 +CREATE OR REPLACE FUNCTION sys._trunc_numeric_to_int2(In arg numeric) +RETURNS INT2 AS $$ +BEGIN + RETURN CAST(trunc(arg) AS INT2); +END; +$$ LANGUAGE plpgsql; + +-- text -> fixeddecimal +CREATE FUNCTION sys.char_to_fixeddecimal(text) +RETURNS sys.FIXEDDECIMAL +AS 'babelfishpg_money', 'char_to_fixeddecimal' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- char -> fixeddecimal +CREATE FUNCTION sys.char_to_fixeddecimal(char) +RETURNS sys.FIXEDDECIMAL +AS 'babelfishpg_money', 'char_to_fixeddecimal' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.char_to_fixeddecimal(sys.bpchar) +RETURNS sys.FIXEDDECIMAL +AS 'babelfishpg_money', 'char_to_fixeddecimal' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- varchar -> fixeddecimal +CREATE FUNCTION sys.char_to_fixeddecimal(sys.varchar) +RETURNS sys.FIXEDDECIMAL +AS 'babelfishpg_money', 'char_to_fixeddecimal' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.char_to_fixeddecimal(pg_catalog.varchar) +RETURNS sys.FIXEDDECIMAL +AS 'babelfishpg_money', 'char_to_fixeddecimal' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- text -> name +CREATE FUNCTION sys.text_to_name(text) +RETURNS pg_catalog.name +AS 'babelfishpg_common', 'pltsql_text_name' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- bpchar -> name +CREATE FUNCTION sys.bpchar_to_name(pg_catalog.bpchar) +RETURNS pg_catalog.name +AS 'babelfishpg_common', 'pltsql_bpchar_name' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.bpchar_to_name(sys.bpchar) +RETURNS pg_catalog.name +AS 'babelfishpg_common', 'pltsql_bpchar_name' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- varchar -> name +CREATE FUNCTION sys.varchar_to_name(sys.varchar) +RETURNS pg_catalog.name +AS 'babelfishpg_common', 'pltsql_text_name' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.varchar_to_name(pg_catalog.varchar) +RETURNS pg_catalog.name +AS 'babelfishpg_common', 'pltsql_text_name' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; diff --git a/contrib/babelfishpg_common/sql/datetime.sql b/contrib/babelfishpg_common/sql/datetime.sql new file mode 100644 index 00000000000..d2f17d36908 --- /dev/null +++ b/contrib/babelfishpg_common/sql/datetime.sql @@ -0,0 +1,392 @@ +CREATE TYPE sys.DATETIME; + +CREATE OR REPLACE FUNCTION sys.datetimein(cstring) +RETURNS sys.DATETIME +AS 'babelfishpg_common', 'datetime_in' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetimeout(sys.DATETIME) +RETURNS cstring +AS 'babelfishpg_common', 'datetime_out' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetimerecv(internal) +RETURNS sys.DATETIME +AS 'timestamp_recv' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetimesend(sys.DATETIME) +RETURNS bytea +AS 'timestamp_send' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetimetypmodin(cstring[]) +RETURNS integer +AS 'timestamptypmodin' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetimetypmodout(integer) +RETURNS cstring +AS 'timestamptypmodout' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE TYPE sys.DATETIME ( + INPUT = sys.datetimein, + OUTPUT = sys.datetimeout, + RECEIVE = sys.datetimerecv, + SEND = sys.datetimesend, + TYPMOD_IN = sys.datetimetypmodin, + TYPMOD_OUT = sys.datetimetypmodout, + INTERNALLENGTH = 8, + ALIGNMENT = 'double', + STORAGE = 'plain', + CATEGORY = 'D', + PREFERRED = false, + COLLATABLE = false, + DEFAULT = '1900-01-01 00:00:00', + PASSEDBYVALUE +); + +CREATE FUNCTION sys.datetimeeq(sys.DATETIME, sys.DATETIME) +RETURNS bool +AS 'timestamp_eq' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.datetimene(sys.DATETIME, sys.DATETIME) +RETURNS bool +AS 'timestamp_ne' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.datetimelt(sys.DATETIME, sys.DATETIME) +RETURNS bool +AS 'timestamp_lt' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.datetimele(sys.DATETIME, sys.DATETIME) +RETURNS bool +AS 'timestamp_le' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.datetimegt(sys.DATETIME, sys.DATETIME) +RETURNS bool +AS 'timestamp_gt' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.datetimege(sys.DATETIME, sys.DATETIME) +RETURNS bool +AS 'timestamp_ge' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.= ( + LEFTARG = sys.DATETIME, + RIGHTARG = sys.DATETIME, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = sys.datetimeeq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR sys.<> ( + LEFTARG = sys.DATETIME, + RIGHTARG = sys.DATETIME, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = sys.datetimene, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR sys.< ( + LEFTARG = sys.DATETIME, + RIGHTARG = sys.DATETIME, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = sys.datetimelt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.<= ( + LEFTARG = sys.DATETIME, + RIGHTARG = sys.DATETIME, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = sys.datetimele, + RESTRICT = scalarlesel, + JOIN = scalarlejoinsel +); + +CREATE OPERATOR sys.> ( + LEFTARG = sys.DATETIME, + RIGHTARG = sys.DATETIME, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = sys.datetimegt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.>= ( + LEFTARG = sys.DATETIME, + RIGHTARG = sys.DATETIME, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = sys.datetimege, + RESTRICT = scalargesel, + JOIN = scalargejoinsel +); + +-- datetime <-> int operators for datetime-int +/- arithmetic +CREATE FUNCTION sys.datetimeplint4(sys.DATETIME, INT4) +RETURNS sys.DATETIME +AS 'babelfishpg_common', 'datetime_pl_int4' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int4pldatetime(INT4, sys.DATETIME) +RETURNS sys.DATETIME +AS 'babelfishpg_common', 'int4_pl_datetime' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.datetimemiint4(sys.DATETIME, INT4) +RETURNS sys.DATETIME +AS 'babelfishpg_common', 'datetime_mi_int4' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int4midatetime(INT4, sys.DATETIME) +RETURNS sys.DATETIME +AS 'babelfishpg_common', 'int4_mi_datetime' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.+ ( + LEFTARG = sys.DATETIME, + RIGHTARG = INT4, + PROCEDURE = sys.datetimeplint4 +); + +CREATE OPERATOR sys.+ ( + LEFTARG = INT4, + RIGHTARG = sys.DATETIME, + PROCEDURE = sys.int4pldatetime +); + +CREATE OPERATOR sys.- ( + LEFTARG = sys.DATETIME, + RIGHTARG = INT4, + PROCEDURE = sys.datetimemiint4 +); + +CREATE OPERATOR sys.- ( + LEFTARG = INT4, + RIGHTARG = sys.DATETIME, + PROCEDURE = sys.int4midatetime +); + + + +CREATE FUNCTION sys.datetimeplfloat8(sys.DATETIME, float8) +RETURNS sys.DATETIME +AS 'babelfishpg_common', 'datetime_pl_float8' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.+ ( + LEFTARG = sys.DATETIME, + RIGHTARG = float8, + PROCEDURE = sys.datetimeplfloat8 +); + +CREATE FUNCTION sys.datetimemifloat8(sys.DATETIME, float8) +RETURNS sys.DATETIME +AS 'babelfishpg_common', 'datetime_mi_float8' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.- ( + LEFTARG = sys.DATETIME, + RIGHTARG = float8, + PROCEDURE = sys.datetimemifloat8 +); + +CREATE FUNCTION sys.float8pldatetime(float8, sys.DATETIME) +RETURNS sys.DATETIME +AS 'babelfishpg_common', 'float8_pl_datetime' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.+ ( + LEFTARG = float8, + RIGHTARG = sys.DATETIME, + PROCEDURE = sys.float8pldatetime +); + +CREATE FUNCTION sys.float8midatetime(float8, sys.DATETIME) +RETURNS sys.DATETIME +AS 'babelfishpg_common', 'float8_mi_datetime' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.- ( + LEFTARG = float8, + RIGHTARG = sys.DATETIME, + PROCEDURE = sys.float8midatetime +); + + + + +CREATE FUNCTION datetime_cmp(sys.DATETIME, sys.DATETIME) +RETURNS INT4 +AS 'timestamp_cmp' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION datetime_hash(sys.DATETIME) +RETURNS INT4 +AS 'timestamp_hash' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR CLASS sys.datetime_ops +DEFAULT FOR TYPE sys.DATETIME USING btree AS + OPERATOR 1 < (sys.DATETIME, sys.DATETIME), + OPERATOR 2 <= (sys.DATETIME, sys.DATETIME), + OPERATOR 3 = (sys.DATETIME, sys.DATETIME), + OPERATOR 4 >= (sys.DATETIME, sys.DATETIME), + OPERATOR 5 > (sys.DATETIME, sys.DATETIME), + FUNCTION 1 datetime_cmp(sys.DATETIME, sys.DATETIME); + +CREATE OPERATOR CLASS sys.datetime_ops +DEFAULT FOR TYPE sys.DATETIME USING hash AS + OPERATOR 1 = (sys.DATETIME, sys.DATETIME), + FUNCTION 1 datetime_hash(sys.DATETIME); + +-- cast TO datetime +CREATE OR REPLACE FUNCTION sys.timestamp2datetime(TIMESTAMP) +RETURNS DATETIME +AS 'babelfishpg_common', 'timestamp_datetime' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (TIMESTAMP AS DATETIME) +WITH FUNCTION sys.timestamp2datetime(TIMESTAMP) AS ASSIGNMENT; + + +CREATE OR REPLACE FUNCTION sys.timestamptz2datetime(TIMESTAMPTZ) +RETURNS DATETIME +AS 'babelfishpg_common', 'timestamptz_datetime' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (TIMESTAMPTZ AS DATETIME) +WITH FUNCTION sys.timestamptz2datetime (TIMESTAMPTZ) AS ASSIGNMENT; + + +CREATE OR REPLACE FUNCTION sys.date2datetime(DATE) +RETURNS DATETIME +AS 'babelfishpg_common', 'date_datetime' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (DATE AS DATETIME) +WITH FUNCTION sys.date2datetime (DATE) AS IMPLICIT; + + +CREATE OR REPLACE FUNCTION sys.time2datetime(TIME) +RETURNS DATETIME +AS 'babelfishpg_common', 'time_datetime' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (TIME AS DATETIME) +WITH FUNCTION sys.time2datetime (TIME) AS IMPLICIT; + + +CREATE OR REPLACE FUNCTION sys.varchar2datetime(sys.VARCHAR) +RETURNS DATETIME +AS 'babelfishpg_common', 'varchar_datetime' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.VARCHAR AS DATETIME) +WITH FUNCTION sys.varchar2datetime (sys.VARCHAR) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.varchar2datetime(pg_catalog.VARCHAR) +RETURNS DATETIME +AS 'babelfishpg_common', 'varchar_datetime' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (pg_catalog.VARCHAR AS DATETIME) +WITH FUNCTION sys.varchar2datetime (pg_catalog.VARCHAR) AS ASSIGNMENT; + + +CREATE OR REPLACE FUNCTION sys.char2datetime(CHAR) +RETURNS DATETIME +AS 'babelfishpg_common', 'char_datetime' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (CHAR AS DATETIME) +WITH FUNCTION sys.char2datetime (CHAR) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.bpchar2datetime(sys.BPCHAR) +RETURNS sys.DATETIME +AS 'babelfishpg_common', 'char_datetime' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BPCHAR AS sys.DATETIME) +WITH FUNCTION sys.bpchar2datetime (sys.BPCHAR) AS ASSIGNMENT; + +-- cast FROM datetime +CREATE CAST (DATETIME AS TIMESTAMP) +WITHOUT FUNCTION AS IMPLICIT; + + +CREATE OR REPLACE FUNCTION sys.datetime2timestamptz(DATETIME) +RETURNS TIMESTAMPTZ +AS 'timestamp_timestamptz' +LANGUAGE internal VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (DATETIME AS TIMESTAMPTZ) +WITH FUNCTION sys.datetime2timestamptz (DATETIME) AS IMPLICIT; + + +CREATE OR REPLACE FUNCTION sys.datetime2date(DATETIME) +RETURNS DATE +AS 'timestamp_date' +LANGUAGE internal VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (DATETIME AS DATE) +WITH FUNCTION sys.datetime2date (DATETIME) AS ASSIGNMENT; + + +CREATE OR REPLACE FUNCTION sys.datetime2time(DATETIME) +RETURNS TIME +AS 'timestamp_time' +LANGUAGE internal VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (DATETIME AS TIME) +WITH FUNCTION sys.datetime2time (DATETIME) AS ASSIGNMENT; + + +CREATE OR REPLACE FUNCTION sys.datetime2sysvarchar(DATETIME) +RETURNS sys.VARCHAR +AS 'babelfishpg_common', 'datetime_varchar' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (DATETIME AS sys.VARCHAR) +WITH FUNCTION sys.datetime2sysvarchar (DATETIME) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.datetime2varchar(DATETIME) +RETURNS pg_catalog.VARCHAR +AS 'babelfishpg_common', 'datetime_varchar' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (DATETIME AS pg_catalog.VARCHAR) +WITH FUNCTION sys.datetime2varchar (DATETIME) AS ASSIGNMENT; + + +CREATE OR REPLACE FUNCTION sys.datetime2char(DATETIME) +RETURNS CHAR +AS 'babelfishpg_common', 'datetime_char' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (DATETIME AS CHAR) +WITH FUNCTION sys.datetime2char (DATETIME) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.datetime2bpchar(sys.DATETIME) +RETURNS sys.BPCHAR +AS 'babelfishpg_common', 'datetime_char' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.DATETIME AS sys.BPCHAR) +WITH FUNCTION sys.datetime2bpchar (sys.DATETIME) AS ASSIGNMENT; diff --git a/contrib/babelfishpg_common/sql/datetime2.sql b/contrib/babelfishpg_common/sql/datetime2.sql new file mode 100644 index 00000000000..3a98109b581 --- /dev/null +++ b/contrib/babelfishpg_common/sql/datetime2.sql @@ -0,0 +1,321 @@ +CREATE TYPE sys.DATETIME2; + +CREATE OR REPLACE FUNCTION sys.datetime2in(cstring) +RETURNS sys.DATETIME2 +AS 'babelfishpg_common', 'datetime2_in' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetime2out(sys.DATETIME2) +RETURNS cstring +AS 'timestamp_out' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetime2recv(internal) +RETURNS sys.DATETIME2 +AS 'timestamp_recv' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetime2send(sys.DATETIME2) +RETURNS bytea +AS 'timestamp_send' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetime2typmodin(cstring[]) +RETURNS integer +AS 'timestamptypmodin' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetime2typmodout(integer) +RETURNS cstring +AS 'timestamptypmodout' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE TYPE sys.DATETIME2 ( + INPUT = sys.datetime2in, + OUTPUT = sys.datetime2out, + RECEIVE = sys.datetime2recv, + SEND = sys.datetime2send, + TYPMOD_IN = sys.datetime2typmodin, + TYPMOD_OUT = sys.datetime2typmodout, + INTERNALLENGTH = 8, + ALIGNMENT = 'double', + STORAGE = 'plain', + CATEGORY = 'D', + PREFERRED = false, + COLLATABLE = false, + DEFAULT = '1900-01-01 00:00:00', + PASSEDBYVALUE +); + +CREATE FUNCTION sys.datetime2eq(sys.DATETIME2, sys.DATETIME2) +RETURNS bool +AS 'timestamp_eq' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.datetime2ne(sys.DATETIME2, sys.DATETIME2) +RETURNS bool +AS 'timestamp_ne' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.datetime2lt(sys.DATETIME2, sys.DATETIME2) +RETURNS bool +AS 'timestamp_lt' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.datetime2le(sys.DATETIME2, sys.DATETIME2) +RETURNS bool +AS 'timestamp_le' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.datetime2gt(sys.DATETIME2, sys.DATETIME2) +RETURNS bool +AS 'timestamp_gt' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.datetime2ge(sys.DATETIME2, sys.DATETIME2) +RETURNS bool +AS 'timestamp_ge' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.= ( + LEFTARG = sys.DATETIME2, + RIGHTARG = sys.DATETIME2, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = sys.datetime2eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR sys.<> ( + LEFTARG = sys.DATETIME2, + RIGHTARG = sys.DATETIME2, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = sys.datetime2ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR sys.< ( + LEFTARG = sys.DATETIME2, + RIGHTARG = sys.DATETIME2, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = sys.datetime2lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.<= ( + LEFTARG = sys.DATETIME2, + RIGHTARG = sys.DATETIME2, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = sys.datetime2le, + RESTRICT = scalarlesel, + JOIN = scalarlejoinsel +); + +CREATE OPERATOR sys.> ( + LEFTARG = sys.DATETIME2, + RIGHTARG = sys.DATETIME2, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = sys.datetime2gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.>= ( + LEFTARG = sys.DATETIME2, + RIGHTARG = sys.DATETIME2, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = sys.datetime2ge, + RESTRICT = scalargesel, + JOIN = scalargejoinsel +); + +CREATE FUNCTION datetime2_cmp(sys.DATETIME2, sys.DATETIME2) +RETURNS INT4 +AS 'timestamp_cmp' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION datetime2_hash(sys.DATETIME2) +RETURNS INT4 +AS 'timestamp_hash' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR CLASS sys.datetime2_ops +DEFAULT FOR TYPE sys.DATETIME2 USING btree AS + OPERATOR 1 < (sys.DATETIME2, sys.DATETIME2), + OPERATOR 2 <= (sys.DATETIME2, sys.DATETIME2), + OPERATOR 3 = (sys.DATETIME2, sys.DATETIME2), + OPERATOR 4 >= (sys.DATETIME2, sys.DATETIME2), + OPERATOR 5 > (sys.DATETIME2, sys.DATETIME2), + FUNCTION 1 datetime2_cmp(sys.DATETIME2, sys.DATETIME2); + +CREATE OPERATOR CLASS sys.datetime2_ops +DEFAULT FOR TYPE sys.DATETIME2 USING hash AS + OPERATOR 1 = (sys.DATETIME2, sys.DATETIME2), + FUNCTION 1 datetime2_hash(sys.DATETIME2); + +-- cast TO datetime2 +CREATE OR REPLACE FUNCTION sys.timestamp2datetime2(TIMESTAMP) +RETURNS DATETIME2 +AS 'babelfishpg_common', 'timestamp_datetime2' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (TIMESTAMP AS DATETIME2) +WITH FUNCTION sys.timestamp2datetime2(TIMESTAMP) AS ASSIGNMENT; +-- CREATE CAST (TIMESTAMP AS DATETIME2) +-- WITHOUT FUNCTION AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.timestamptz2datetime2(TIMESTAMPTZ) +RETURNS DATETIME2 +AS 'babelfishpg_common', 'timestamptz_datetime2' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (TIMESTAMPTZ AS DATETIME2) +WITH FUNCTION sys.timestamptz2datetime2 (TIMESTAMPTZ) AS ASSIGNMENT; + + +CREATE OR REPLACE FUNCTION sys.date2datetime2(DATE) +RETURNS DATETIME2 +AS 'babelfishpg_common', 'date_datetime2' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (DATE AS DATETIME2) +WITH FUNCTION sys.date2datetime2 (DATE) AS IMPLICIT; + + +CREATE OR REPLACE FUNCTION sys.time2datetime2(TIME) +RETURNS DATETIME2 +AS 'babelfishpg_common', 'time_datetime2' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (TIME AS DATETIME2) +WITH FUNCTION sys.time2datetime2 (TIME) AS IMPLICIT; + + +CREATE CAST (DATETIME AS DATETIME2) +WITHOUT FUNCTION AS IMPLICIT; + + +-- BABEL-1465 CAST from VARCHAR/NVARCHAR/CHAR/NCHAR to datetime2 is VOLATILE +CREATE OR REPLACE FUNCTION sys.varchar2datetime2(sys.VARCHAR) +RETURNS DATETIME2 +AS 'babelfishpg_common', 'varchar_datetime2' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.VARCHAR AS DATETIME2) +WITH FUNCTION sys.varchar2datetime2 (sys.VARCHAR) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.varchar2datetime2(pg_catalog.VARCHAR) +RETURNS DATETIME2 +AS 'babelfishpg_common', 'varchar_datetime2' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (pg_catalog.VARCHAR AS DATETIME2) +WITH FUNCTION sys.varchar2datetime2 (pg_catalog.VARCHAR) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.char2datetime2(CHAR) +RETURNS DATETIME2 +AS 'babelfishpg_common', 'char_datetime2' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (CHAR AS DATETIME2) +WITH FUNCTION sys.char2datetime2 (CHAR) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.bpchar2datetime2(sys.BPCHAR) +RETURNS sys.DATETIME2 +AS 'babelfishpg_common', 'char_datetime2' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BPCHAR AS sys.DATETIME2) +WITH FUNCTION sys.bpchar2datetime2 (sys.BPCHAR) AS ASSIGNMENT; + +-- cast FROM datetime2 +CREATE CAST (DATETIME2 AS TIMESTAMP) +WITHOUT FUNCTION AS IMPLICIT; + + +CREATE OR REPLACE FUNCTION sys.datetime22datetime(DATETIME2) +RETURNS DATETIME +AS 'babelfishpg_common', 'timestamp_datetime' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (DATETIME2 AS DATETIME) +WITH FUNCTION sys.datetime22datetime(DATETIME2) AS ASSIGNMENT; + + +CREATE OR REPLACE FUNCTION sys.datetime22timestamptz(DATETIME2) +RETURNS TIMESTAMPTZ +AS 'timestamp_timestamptz' +LANGUAGE internal VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (DATETIME2 AS TIMESTAMPTZ) +WITH FUNCTION sys.datetime22timestamptz (DATETIME2) AS IMPLICIT; + + +CREATE OR REPLACE FUNCTION sys.datetime22date(DATETIME2) +RETURNS DATE +AS 'timestamp_date' +LANGUAGE internal VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (DATETIME2 AS DATE) +WITH FUNCTION sys.datetime22date (DATETIME2) AS ASSIGNMENT; + + +CREATE OR REPLACE FUNCTION sys.datetime22time(DATETIME2) +RETURNS TIME +AS 'timestamp_time' +LANGUAGE internal VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (DATETIME2 AS TIME) +WITH FUNCTION sys.datetime22time (DATETIME2) AS ASSIGNMENT; + + +CREATE FUNCTION sys.datetime2scale(sys.DATETIME2, INT4) +RETURNS sys.DATETIME2 +AS 'babelfishpg_common', 'datetime2_scale' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.DATETIME2 AS sys.DATETIME2) +WITH FUNCTION datetime2scale (sys.DATETIME2, INT4) AS ASSIGNMENT; + + +-- BABEL-1465 CAST from datetime2 to VARCHAR/NVARCHAR/CHAR/NCHAR is VOLATILE +CREATE OR REPLACE FUNCTION sys.datetime22sysvarchar(DATETIME2) +RETURNS sys.VARCHAR +AS 'babelfishpg_common', 'datetime2_varchar' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (DATETIME2 AS sys.VARCHAR) +WITH FUNCTION sys.datetime22sysvarchar (DATETIME2) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.datetime22varchar(DATETIME2) +RETURNS pg_catalog.VARCHAR +AS 'babelfishpg_common', 'datetime2_varchar' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (DATETIME2 AS pg_catalog.VARCHAR) +WITH FUNCTION sys.datetime22varchar (DATETIME2) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.datetime22char(DATETIME2) +RETURNS CHAR +AS 'babelfishpg_common', 'datetime2_char' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (DATETIME2 AS CHAR) +WITH FUNCTION sys.datetime22char (DATETIME2) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.datetime22bpchar(sys.DATETIME2) +RETURNS sys.BPCHAR +AS 'babelfishpg_common', 'datetime2_char' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.DATETIME2 AS sys.BPCHAR) +WITH FUNCTION sys.datetime22bpchar (sys.DATETIME2) AS ASSIGNMENT; diff --git a/contrib/babelfishpg_common/sql/datetimeoffset.sql b/contrib/babelfishpg_common/sql/datetimeoffset.sql new file mode 100644 index 00000000000..c967f312cc1 --- /dev/null +++ b/contrib/babelfishpg_common/sql/datetimeoffset.sql @@ -0,0 +1,304 @@ +CREATE TYPE sys.DATETIMEOFFSET; + +CREATE OR REPLACE FUNCTION sys.datetimeoffsetin(cstring) +RETURNS sys.DATETIMEOFFSET +AS 'babelfishpg_common', 'datetimeoffset_in' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetimeoffsetout(sys.DATETIMEOFFSET) +RETURNS cstring +AS 'babelfishpg_common', 'datetimeoffset_out' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetimeoffsetrecv(internal) +RETURNS sys.DATETIMEOFFSET +AS 'babelfishpg_common', 'datetimeoffset_recv' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetimeoffsetsend(sys.DATETIMEOFFSET) +RETURNS bytea +AS 'babelfishpg_common', 'datetimeoffset_send' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetimeofftypmodin(cstring[]) +RETURNS integer +AS 'timestamptztypmodin' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetimeofftypmodout(integer) +RETURNS cstring +AS 'timestamptztypmodout' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE TYPE sys.DATETIMEOFFSET ( + INPUT = sys.datetimeoffsetin, + OUTPUT = sys.datetimeoffsetout, + RECEIVE = sys.datetimeoffsetrecv, + SEND = sys.datetimeoffsetsend, + TYPMOD_IN = sys.datetimeofftypmodin, + TYPMOD_OUT = sys.datetimeofftypmodout, + INTERNALLENGTH = 10, + ALIGNMENT = 'double', + STORAGE = 'plain', + CATEGORY = 'D', + PREFERRED = false, + DEFAULT = '1900-01-01 00:00+0' +); + +CREATE FUNCTION sys.datetimeoffseteq(sys.DATETIMEOFFSET, sys.DATETIMEOFFSET) +RETURNS bool +AS 'babelfishpg_common', 'datetimeoffset_eq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.datetimeoffsetne(sys.DATETIMEOFFSET, sys.DATETIMEOFFSET) +RETURNS bool +AS 'babelfishpg_common', 'datetimeoffset_ne' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.datetimeoffsetlt(sys.DATETIMEOFFSET, sys.DATETIMEOFFSET) +RETURNS bool +AS 'babelfishpg_common', 'datetimeoffset_lt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.datetimeoffsetle(sys.DATETIMEOFFSET, sys.DATETIMEOFFSET) +RETURNS bool +AS 'babelfishpg_common', 'datetimeoffset_le' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.datetimeoffsetgt(sys.DATETIMEOFFSET, sys.DATETIMEOFFSET) +RETURNS bool +AS 'babelfishpg_common', 'datetimeoffset_gt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.datetimeoffsetge(sys.DATETIMEOFFSET, sys.DATETIMEOFFSET) +RETURNS bool +AS 'babelfishpg_common', 'datetimeoffset_ge' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.datetimeoffsetplinterval(sys.DATETIMEOFFSET, INTERVAL) +RETURNS sys.DATETIMEOFFSET +AS 'babelfishpg_common', 'datetimeoffset_pl_interval' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.intervalpldatetimeoffset(INTERVAL, sys.DATETIMEOFFSET) +RETURNS sys.DATETIMEOFFSET +AS 'babelfishpg_common', 'interval_pl_datetimeoffset' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.datetimeoffsetmiinterval(sys.DATETIMEOFFSET, INTERVAL) +RETURNS sys.DATETIMEOFFSET +AS 'babelfishpg_common', 'datetimeoffset_mi_interval' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.datetimeoffsetmi(sys.DATETIMEOFFSET, sys.DATETIMEOFFSET) +RETURNS INTERVAL +AS 'babelfishpg_common', 'datetimeoffset_mi' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.= ( + LEFTARG = sys.DATETIMEOFFSET, + RIGHTARG = sys.DATETIMEOFFSET, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = sys.datetimeoffseteq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR sys.<> ( + LEFTARG = sys.DATETIMEOFFSET, + RIGHTARG = sys.DATETIMEOFFSET, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = sys.datetimeoffsetne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR sys.< ( + LEFTARG = sys.DATETIMEOFFSET, + RIGHTARG = sys.DATETIMEOFFSET, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = sys.datetimeoffsetlt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.<= ( + LEFTARG = sys.DATETIMEOFFSET, + RIGHTARG = sys.DATETIMEOFFSET, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = sys.datetimeoffsetle, + RESTRICT = scalarlesel, + JOIN = scalarlejoinsel +); + +CREATE OPERATOR sys.> ( + LEFTARG = sys.DATETIMEOFFSET, + RIGHTARG = sys.DATETIMEOFFSET, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = sys.datetimeoffsetgt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.>= ( + LEFTARG = sys.DATETIMEOFFSET, + RIGHTARG = sys.DATETIMEOFFSET, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = sys.datetimeoffsetge, + RESTRICT = scalargesel, + JOIN = scalargejoinsel +); + +CREATE OPERATOR sys.+ ( + LEFTARG = sys.DATETIMEOFFSET, + RIGHTARG = interval, + PROCEDURE = sys.datetimeoffsetplinterval +); + +CREATE OPERATOR sys.+ ( + LEFTARG = interval, + RIGHTARG = sys.DATETIMEOFFSET, + PROCEDURE = sys.intervalpldatetimeoffset +); + +CREATE OPERATOR sys.- ( + LEFTARG = sys.DATETIMEOFFSET, + RIGHTARG = interval, + PROCEDURE = sys.datetimeoffsetmiinterval +); + +CREATE OPERATOR sys.- ( + LEFTARG = sys.DATETIMEOFFSET, + RIGHTARG = sys.DATETIMEOFFSET, + PROCEDURE = sys.datetimeoffsetmi +); + +CREATE FUNCTION datetimeoffset_cmp(sys.DATETIMEOFFSET, sys.DATETIMEOFFSET) +RETURNS INT4 +AS 'babelfishpg_common', 'datetimeoffset_cmp' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION datetimeoffset_hash(sys.DATETIMEOFFSET) +RETURNS INT4 +AS 'babelfishpg_common', 'datetimeoffset_hash' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR CLASS sys.datetimeoffset_ops +DEFAULT FOR TYPE sys.DATETIMEOFFSET USING btree AS + OPERATOR 1 < (sys.DATETIMEOFFSET, sys.DATETIMEOFFSET), + OPERATOR 2 <= (sys.DATETIMEOFFSET, sys.DATETIMEOFFSET), + OPERATOR 3 = (sys.DATETIMEOFFSET, sys.DATETIMEOFFSET), + OPERATOR 4 >= (sys.DATETIMEOFFSET, sys.DATETIMEOFFSET), + OPERATOR 5 > (sys.DATETIMEOFFSET, sys.DATETIMEOFFSET), + FUNCTION 1 datetimeoffset_cmp(sys.DATETIMEOFFSET, sys.DATETIMEOFFSET); + +CREATE OPERATOR CLASS sys.datetimeoffset_ops +DEFAULT FOR TYPE sys.DATETIMEOFFSET USING hash AS + OPERATOR 1 = (sys.DATETIMEOFFSET, sys.DATETIMEOFFSET), + FUNCTION 1 datetimeoffset_hash(sys.DATETIMEOFFSET); + +-- Casts +CREATE FUNCTION sys.datetimeoffsetscale(sys.DATETIMEOFFSET, INT4) +RETURNS sys.DATETIMEOFFSET +AS 'babelfishpg_common', 'datetimeoffset_scale' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.timestamp2datetimeoffset(TIMESTAMP) +RETURNS sys.DATETIMEOFFSET +AS 'babelfishpg_common', 'timestamp_datetimeoffset' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetimeoffset2timestamp(sys.DATETIMEOFFSET) +RETURNS TIMESTAMP +AS 'babelfishpg_common', 'datetimeoffset_timestamp' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.date2datetimeoffset(DATE) +RETURNS sys.DATETIMEOFFSET +AS 'babelfishpg_common', 'date_datetimeoffset' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetimeoffset2date(sys.DATETIMEOFFSET) +RETURNS DATE +AS 'babelfishpg_common', 'datetimeoffset_date' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.time2datetimeoffset(TIME) +RETURNS sys.DATETIMEOFFSET +AS 'babelfishpg_common', 'time_datetimeoffset' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetimeoffset2time(sys.DATETIMEOFFSET) +RETURNS TIME +AS 'babelfishpg_common', 'datetimeoffset_time' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.smalldatetime2datetimeoffset(sys.SMALLDATETIME) +RETURNS sys.DATETIMEOFFSET +AS 'babelfishpg_common', 'smalldatetime_datetimeoffset' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetimeoffset2smalldatetime(sys.DATETIMEOFFSET) +RETURNS sys.SMALLDATETIME +AS 'babelfishpg_common', 'datetimeoffset_smalldatetime' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetime2datetimeoffset(sys.DATETIME) +RETURNS sys.DATETIMEOFFSET +AS 'babelfishpg_common', 'datetime_datetimeoffset' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetimeoffset2datetime(sys.DATETIMEOFFSET) +RETURNS sys.DATETIME +AS 'babelfishpg_common', 'datetimeoffset_datetime' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetime22datetimeoffset(sys.DATETIME2) +RETURNS sys.DATETIMEOFFSET +AS 'babelfishpg_common', 'datetime2_datetimeoffset' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetimeoffset2datetime2(sys.DATETIMEOFFSET) +RETURNS sys.DATETIME2 +AS 'babelfishpg_common', 'datetimeoffset_datetime2' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.DATETIMEOFFSET AS sys.DATETIMEOFFSET) +WITH FUNCTION datetimeoffsetscale (sys.DATETIMEOFFSET, INT4) AS ASSIGNMENT; + +CREATE CAST (TIMESTAMP AS sys.DATETIMEOFFSET) +WITH FUNCTION sys.timestamp2datetimeoffset(TIMESTAMP) AS IMPLICIT; +CREATE CAST (sys.DATETIMEOFFSET AS TIMESTAMP) +WITH FUNCTION sys.datetimeoffset2timestamp(sys.DATETIMEOFFSET) AS ASSIGNMENT; + +CREATE CAST (DATE AS sys.DATETIMEOFFSET) +WITH FUNCTION sys.date2datetimeoffset(DATE) AS IMPLICIT; +CREATE CAST (sys.DATETIMEOFFSET AS DATE) +WITH FUNCTION sys.datetimeoffset2date(sys.DATETIMEOFFSET) AS ASSIGNMENT; + +CREATE CAST (TIME AS sys.DATETIMEOFFSET) +WITH FUNCTION sys.time2datetimeoffset(TIME) AS IMPLICIT; +CREATE CAST (sys.DATETIMEOFFSET AS TIME) +WITH FUNCTION sys.datetimeoffset2time(sys.DATETIMEOFFSET) AS ASSIGNMENT; + +CREATE CAST (sys.SMALLDATETIME AS sys.DATETIMEOFFSET) +WITH FUNCTION sys.smalldatetime2datetimeoffset(sys.SMALLDATETIME) AS IMPLICIT; +CREATE CAST (sys.DATETIMEOFFSET AS sys.SMALLDATETIME) +WITH FUNCTION sys.datetimeoffset2smalldatetime(sys.DATETIMEOFFSET) AS ASSIGNMENT; + +CREATE CAST (sys.DATETIME AS sys.DATETIMEOFFSET) +WITH FUNCTION sys.datetime2datetimeoffset(sys.DATETIME) AS IMPLICIT; +CREATE CAST (sys.DATETIMEOFFSET AS sys.DATETIME) +WITH FUNCTION sys.datetimeoffset2datetime(sys.DATETIMEOFFSET) AS ASSIGNMENT; + +CREATE CAST (sys.DATETIME2 AS sys.DATETIMEOFFSET) +WITH FUNCTION sys.datetime22datetimeoffset(sys.DATETIME2) AS IMPLICIT; +CREATE CAST (sys.DATETIMEOFFSET AS sys.DATETIME2) +WITH FUNCTION sys.datetimeoffset2datetime2(sys.DATETIMEOFFSET) AS ASSIGNMENT; diff --git a/contrib/babelfishpg_common/sql/money/fixeddecimal--1.1.0_base_parallel.sql b/contrib/babelfishpg_common/sql/money/fixeddecimal--1.1.0_base_parallel.sql new file mode 100755 index 00000000000..c9d8bbf963e --- /dev/null +++ b/contrib/babelfishpg_common/sql/money/fixeddecimal--1.1.0_base_parallel.sql @@ -0,0 +1,1602 @@ +------------------ +-- FIXEDDECIMAL -- +------------------ + +CREATE TYPE sys.FIXEDDECIMAL; + +CREATE FUNCTION sys.fixeddecimalin(cstring, oid, int4) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalin' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalout(fixeddecimal) +RETURNS cstring +AS 'babelfishpg_money', 'fixeddecimalout' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalrecv(internal) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalrecv' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalsend(FIXEDDECIMAL) +RETURNS bytea +AS 'babelfishpg_money', 'fixeddecimalsend' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimaltypmodin(_cstring) +RETURNS INT4 +AS 'babelfishpg_money', 'fixeddecimaltypmodin' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimaltypmodout(INT4) +RETURNS cstring +AS 'babelfishpg_money', 'fixeddecimaltypmodout' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + + +CREATE TYPE sys.FIXEDDECIMAL ( + INPUT = fixeddecimalin, + OUTPUT = fixeddecimalout, + RECEIVE = fixeddecimalrecv, + SEND = fixeddecimalsend, + TYPMOD_IN = fixeddecimaltypmodin, + TYPMOD_OUT = fixeddecimaltypmodout, + INTERNALLENGTH = 8, + ALIGNMENT = 'double', + STORAGE = plain, + CATEGORY = 'N', + PREFERRED = false, + COLLATABLE = false, + PASSEDBYVALUE -- But not always.. XXX fix that. +); + +-- FIXEDDECIMAL, NUMERIC +CREATE FUNCTION sys.fixeddecimaleq(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimaleq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalne(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimalne' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimallt(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimallt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalle(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimalle' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalgt(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimalgt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalge(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimalge' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalum(FIXEDDECIMAL) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'fixeddecimalum' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalpl(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'fixeddecimalpl' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalmi(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'fixeddecimalmi' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalmul(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'fixeddecimalmul' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimaldiv(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'fixeddecimaldiv' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.abs(FIXEDDECIMAL) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'fixeddecimalabs' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimallarger(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimallarger' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalsmaller(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalsmaller' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_cmp(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS INT4 +AS 'babelfishpg_money', 'fixeddecimal_cmp' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_hash(FIXEDDECIMAL) +RETURNS INT4 +AS 'babelfishpg_money', 'fixeddecimal_hash' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- +-- Operators. +-- + +CREATE OPERATOR FAMILY fixeddecimal_ops USING btree; +CREATE OPERATOR FAMILY fixeddecimal_ops USING hash; + +-- FIXEDDECIMAL op FIXEDDECIMAL +CREATE OPERATOR sys.= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = fixeddecimaleq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR sys.<> ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = fixeddecimalne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR sys.< ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = fixeddecimallt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.<= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = fixeddecimalle, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.>= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = fixeddecimalge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.> ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = fixeddecimalgt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.+ ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = +, + PROCEDURE = fixeddecimalpl +); + +CREATE OPERATOR sys.- ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = fixeddecimalmi +); + +CREATE OPERATOR sys.- ( + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = fixeddecimalum +); + +CREATE OPERATOR sys.* ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = *, + PROCEDURE = fixeddecimalmul +); + +CREATE OPERATOR sys./ ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = fixeddecimaldiv +); + +CREATE OPERATOR CLASS sys.fixeddecimal_ops +DEFAULT FOR TYPE FIXEDDECIMAL USING btree FAMILY fixeddecimal_ops AS + OPERATOR 1 < (FIXEDDECIMAL, FIXEDDECIMAL), + OPERATOR 2 <= (FIXEDDECIMAL, FIXEDDECIMAL), + OPERATOR 3 = (FIXEDDECIMAL, FIXEDDECIMAL), + OPERATOR 4 >= (FIXEDDECIMAL, FIXEDDECIMAL), + OPERATOR 5 > (FIXEDDECIMAL, FIXEDDECIMAL), + FUNCTION 1 fixeddecimal_cmp(FIXEDDECIMAL, FIXEDDECIMAL); + +CREATE OPERATOR CLASS sys.fixeddecimal_ops +DEFAULT FOR TYPE FIXEDDECIMAL USING hash FAMILY fixeddecimal_ops AS + OPERATOR 1 = (FIXEDDECIMAL, FIXEDDECIMAL), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + +-- FIXEDDECIMAL, NUMERIC +CREATE FUNCTION sys.fixeddecimal_numeric_cmp(FIXEDDECIMAL, NUMERIC) +RETURNS INT4 +AS 'babelfishpg_money', 'fixeddecimal_numeric_cmp' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.numeric_fixeddecimal_cmp(NUMERIC, FIXEDDECIMAL) +RETURNS INT4 +AS 'babelfishpg_money', 'numeric_fixeddecimal_cmp' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_numeric_eq(FIXEDDECIMAL, NUMERIC) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_numeric_eq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_numeric_ne(FIXEDDECIMAL, NUMERIC) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_numeric_ne' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_numeric_lt(FIXEDDECIMAL, NUMERIC) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_numeric_lt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_numeric_le(FIXEDDECIMAL, NUMERIC) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_numeric_le' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_numeric_gt(FIXEDDECIMAL, NUMERIC) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_numeric_gt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_numeric_ge(FIXEDDECIMAL, NUMERIC) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_numeric_ge' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = NUMERIC, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = fixeddecimal_numeric_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR sys.<> ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = NUMERIC, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = fixeddecimal_numeric_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR sys.< ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = NUMERIC, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = fixeddecimal_numeric_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.<= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = NUMERIC, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = fixeddecimal_numeric_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.>= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = NUMERIC, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = fixeddecimal_numeric_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.> ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = NUMERIC, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = fixeddecimal_numeric_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +ALTER OPERATOR FAMILY fixeddecimal_ops USING btree ADD + OPERATOR 1 < (FIXEDDECIMAL, NUMERIC), + OPERATOR 2 <= (FIXEDDECIMAL, NUMERIC), + OPERATOR 3 = (FIXEDDECIMAL, NUMERIC), + OPERATOR 4 >= (FIXEDDECIMAL, NUMERIC), + OPERATOR 5 > (FIXEDDECIMAL, NUMERIC), + FUNCTION 1 fixeddecimal_numeric_cmp(FIXEDDECIMAL, NUMERIC); + +ALTER OPERATOR FAMILY fixeddecimal_ops USING hash ADD + OPERATOR 1 = (FIXEDDECIMAL, NUMERIC); + +-- NUMERIC, FIXEDDECIMAL +CREATE FUNCTION sys.numeric_fixeddecimal_eq(NUMERIC, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'numeric_fixeddecimal_eq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.numeric_fixeddecimal_ne(NUMERIC, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'numeric_fixeddecimal_ne' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.numeric_fixeddecimal_lt(NUMERIC, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'numeric_fixeddecimal_lt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.numeric_fixeddecimal_le(NUMERIC, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'numeric_fixeddecimal_le' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.numeric_fixeddecimal_gt(NUMERIC, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'numeric_fixeddecimal_gt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.numeric_fixeddecimal_ge(NUMERIC, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'numeric_fixeddecimal_ge' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.= ( + LEFTARG = NUMERIC, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = numeric_fixeddecimal_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR sys.<> ( + LEFTARG = NUMERIC, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = numeric_fixeddecimal_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR sys.< ( + LEFTARG = NUMERIC, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = numeric_fixeddecimal_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.<= ( + LEFTARG = NUMERIC, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = numeric_fixeddecimal_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR >= ( + LEFTARG = NUMERIC, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = numeric_fixeddecimal_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.> ( + LEFTARG = NUMERIC, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = numeric_fixeddecimal_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +ALTER OPERATOR FAMILY fixeddecimal_ops USING btree ADD + OPERATOR 1 < (NUMERIC, FIXEDDECIMAL) FOR SEARCH, + OPERATOR 2 <= (NUMERIC, FIXEDDECIMAL) FOR SEARCH, + OPERATOR 3 = (NUMERIC, FIXEDDECIMAL) FOR SEARCH, + OPERATOR 4 >= (NUMERIC, FIXEDDECIMAL) FOR SEARCH, + OPERATOR 5 > (NUMERIC, FIXEDDECIMAL) FOR SEARCH, + FUNCTION 1 numeric_fixeddecimal_cmp(NUMERIC, FIXEDDECIMAL); + +ALTER OPERATOR FAMILY fixeddecimal_ops USING hash ADD + OPERATOR 1 = (NUMERIC, FIXEDDECIMAL); + +-- +-- Cross type operators with int8 +-- + +-- FIXEDDECIMAL, INT8 +CREATE FUNCTION sys.fixeddecimal_int8_cmp(FIXEDDECIMAL, INT8) +RETURNS INT4 +AS 'babelfishpg_money', 'fixeddecimal_int8_cmp' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_int8_eq(FIXEDDECIMAL, INT8) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int8_eq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_int8_ne(FIXEDDECIMAL, INT8) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int8_ne' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_int8_lt(FIXEDDECIMAL, INT8) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int8_lt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_int8_le(FIXEDDECIMAL, INT8) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int8_le' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_int8_gt(FIXEDDECIMAL, INT8) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int8_gt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_int8_ge(FIXEDDECIMAL, INT8) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int8_ge' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalint8pl(FIXEDDECIMAL, INT8) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'fixeddecimalint8pl' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalint8mi(FIXEDDECIMAL, INT8) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'fixeddecimalint8mi' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalint8mul(FIXEDDECIMAL, INT8) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'fixeddecimalint8mul' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalint8div(FIXEDDECIMAL, INT8) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'fixeddecimalint8div' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT8, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = fixeddecimal_int8_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR sys.<> ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT8, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = fixeddecimal_int8_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR sys.< ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT8, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = fixeddecimal_int8_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.<= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT8, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = fixeddecimal_int8_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.>= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT8, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = fixeddecimal_int8_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.> ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT8, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = fixeddecimal_int8_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.+ ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT8, + COMMUTATOR = +, + PROCEDURE = fixeddecimalint8pl +); + +CREATE OPERATOR sys.- ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT8, + PROCEDURE = fixeddecimalint8mi +); + +CREATE OPERATOR sys.* ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT8, + COMMUTATOR = *, + PROCEDURE = fixeddecimalint8mul +); + +CREATE OPERATOR sys./ ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT8, + PROCEDURE = fixeddecimalint8div +); + +ALTER OPERATOR FAMILY fixeddecimal_ops USING btree ADD + OPERATOR 1 < (FIXEDDECIMAL, INT8), + OPERATOR 2 <= (FIXEDDECIMAL, INT8), + OPERATOR 3 = (FIXEDDECIMAL, INT8), + OPERATOR 4 >= (FIXEDDECIMAL, INT8), + OPERATOR 5 > (FIXEDDECIMAL, INT8), + FUNCTION 1 fixeddecimal_int8_cmp(FIXEDDECIMAL, INT8); + +ALTER OPERATOR FAMILY fixeddecimal_ops USING hash ADD + OPERATOR 1 = (FIXEDDECIMAL, INT8); + +-- INT8, FIXEDDECIMAL +CREATE FUNCTION sys.int8_fixeddecimal_cmp(INT8, FIXEDDECIMAL) +RETURNS INT4 +AS 'babelfishpg_money', 'int8_fixeddecimal_cmp' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int8_fixeddecimal_eq(INT8, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int8_fixeddecimal_eq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int8_fixeddecimal_ne(INT8, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int8_fixeddecimal_ne' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int8_fixeddecimal_lt(INT8, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int8_fixeddecimal_lt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int8_fixeddecimal_le(INT8, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int8_fixeddecimal_le' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int8_fixeddecimal_gt(INT8, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int8_fixeddecimal_gt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int8_fixeddecimal_ge(INT8, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int8_fixeddecimal_ge' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int8fixeddecimalpl(INT8, FIXEDDECIMAL) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'int8fixeddecimalpl' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int8fixeddecimalmi(INT8, FIXEDDECIMAL) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'int8fixeddecimalmi' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int8fixeddecimalmul(INT8, FIXEDDECIMAL) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'int8fixeddecimalmul' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int8fixeddecimaldiv(INT8, FIXEDDECIMAL) +RETURNS DOUBLE PRECISION +AS 'babelfishpg_money', 'int8fixeddecimaldiv' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.= ( + LEFTARG = INT8, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = int8_fixeddecimal_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR sys.<> ( + LEFTARG = INT8, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = int8_fixeddecimal_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR sys.< ( + LEFTARG = INT8, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = int8_fixeddecimal_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.<= ( + LEFTARG = INT8, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = int8_fixeddecimal_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.>= ( + LEFTARG = INT8, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = int8_fixeddecimal_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.> ( + LEFTARG = INT8, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = int8_fixeddecimal_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.+ ( + LEFTARG = INT8, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = +, + PROCEDURE = int8fixeddecimalpl +); + +CREATE OPERATOR sys.- ( + LEFTARG = INT8, + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = int8fixeddecimalmi +); + +CREATE OPERATOR sys.* ( + LEFTARG = INT8, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = *, + PROCEDURE = int8fixeddecimalmul +); + +CREATE OPERATOR sys./ ( + LEFTARG = INT8, + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = int8fixeddecimaldiv +); + +ALTER OPERATOR FAMILY fixeddecimal_ops USING btree ADD + OPERATOR 1 < (INT8, FIXEDDECIMAL), + OPERATOR 2 <= (INT8, FIXEDDECIMAL), + OPERATOR 3 = (INT8, FIXEDDECIMAL), + OPERATOR 4 >= (INT8, FIXEDDECIMAL), + OPERATOR 5 > (INT8, FIXEDDECIMAL), + FUNCTION 1 int8_fixeddecimal_cmp(INT8, FIXEDDECIMAL); + +ALTER OPERATOR FAMILY fixeddecimal_ops USING hash ADD + OPERATOR 1 = (INT8, FIXEDDECIMAL); + +-- +-- Cross type operators with int4 +-- + +-- FIXEDDECIMAL, INT4 +CREATE FUNCTION sys.fixeddecimal_int4_cmp(FIXEDDECIMAL, INT4) +RETURNS INT4 +AS 'babelfishpg_money', 'fixeddecimal_int4_cmp' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_int4_eq(FIXEDDECIMAL, INT4) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int4_eq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_int4_ne(FIXEDDECIMAL, INT4) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int4_ne' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_int4_lt(FIXEDDECIMAL, INT4) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int4_lt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_int4_le(FIXEDDECIMAL, INT4) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int4_le' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_int4_gt(FIXEDDECIMAL, INT4) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int4_gt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_int4_ge(FIXEDDECIMAL, INT4) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int4_ge' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalint4pl(FIXEDDECIMAL, INT4) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'fixeddecimalint4pl' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalint4mi(FIXEDDECIMAL, INT4) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'fixeddecimalint4mi' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalint4mul(FIXEDDECIMAL, INT4) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'fixeddecimalint4mul' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalint4div(FIXEDDECIMAL, INT4) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'fixeddecimalint4div' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = fixeddecimal_int4_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR sys.<> ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = fixeddecimal_int4_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR sys.< ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = fixeddecimal_int4_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.<= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = fixeddecimal_int4_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.>= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = fixeddecimal_int4_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.> ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = fixeddecimal_int4_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.+ ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + COMMUTATOR = +, + PROCEDURE = fixeddecimalint4pl +); + +CREATE OPERATOR sys.- ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + PROCEDURE = fixeddecimalint4mi +); + +CREATE OPERATOR sys.* ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + COMMUTATOR = *, + PROCEDURE = fixeddecimalint4mul +); + +CREATE OPERATOR sys./ ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + PROCEDURE = fixeddecimalint4div +); + +ALTER OPERATOR FAMILY fixeddecimal_ops USING btree ADD + OPERATOR 1 < (FIXEDDECIMAL, INT4), + OPERATOR 2 <= (FIXEDDECIMAL, INT4), + OPERATOR 3 = (FIXEDDECIMAL, INT4), + OPERATOR 4 >= (FIXEDDECIMAL, INT4), + OPERATOR 5 > (FIXEDDECIMAL, INT4), + FUNCTION 1 fixeddecimal_int4_cmp(FIXEDDECIMAL, INT4); + +ALTER OPERATOR FAMILY fixeddecimal_ops USING hash ADD + OPERATOR 1 = (FIXEDDECIMAL, INT4); + +-- INT4, FIXEDDECIMAL +CREATE FUNCTION sys.int4_fixeddecimal_cmp(INT4, FIXEDDECIMAL) +RETURNS INT4 +AS 'babelfishpg_money', 'int4_fixeddecimal_cmp' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int4_fixeddecimal_eq(INT4, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int4_fixeddecimal_eq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int4_fixeddecimal_ne(INT4, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int4_fixeddecimal_ne' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int4_fixeddecimal_lt(INT4, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int4_fixeddecimal_lt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int4_fixeddecimal_le(INT4, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int4_fixeddecimal_le' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int4_fixeddecimal_gt(INT4, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int4_fixeddecimal_gt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int4_fixeddecimal_ge(INT4, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int4_fixeddecimal_ge' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int4fixeddecimalpl(INT4, FIXEDDECIMAL) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'int4fixeddecimalpl' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int4fixeddecimalmi(INT4, FIXEDDECIMAL) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'int4fixeddecimalmi' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int4fixeddecimalmul(INT4, FIXEDDECIMAL) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'int4fixeddecimalmul' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int4fixeddecimaldiv(INT4, FIXEDDECIMAL) +RETURNS DOUBLE PRECISION +AS 'babelfishpg_money', 'int4fixeddecimaldiv' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.= ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = int4_fixeddecimal_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR sys.<> ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = int4_fixeddecimal_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR sys.< ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = int4_fixeddecimal_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.<= ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = int4_fixeddecimal_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.>= ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = int4_fixeddecimal_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.> ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = int4_fixeddecimal_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.+ ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = +, + PROCEDURE = int4fixeddecimalpl +); + +CREATE OPERATOR sys.- ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = int4fixeddecimalmi +); + +CREATE OPERATOR sys.* ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = *, + PROCEDURE = int4fixeddecimalmul +); + +CREATE OPERATOR sys./ ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = int4fixeddecimaldiv +); + +ALTER OPERATOR FAMILY fixeddecimal_ops USING btree ADD + OPERATOR 1 < (INT4, FIXEDDECIMAL), + OPERATOR 2 <= (INT4, FIXEDDECIMAL), + OPERATOR 3 = (INT4, FIXEDDECIMAL), + OPERATOR 4 >= (INT4, FIXEDDECIMAL), + OPERATOR 5 > (INT4, FIXEDDECIMAL), + FUNCTION 1 int4_fixeddecimal_cmp(INT4, FIXEDDECIMAL); + +ALTER OPERATOR FAMILY fixeddecimal_ops USING hash ADD + OPERATOR 1 = (INT4, FIXEDDECIMAL); + +-- +-- Cross type operators with int2 +-- +-- FIXEDDECIMAL, INT2 +CREATE FUNCTION sys.fixeddecimal_int2_cmp(FIXEDDECIMAL, INT2) +RETURNS INT4 +AS 'babelfishpg_money', 'fixeddecimal_int2_cmp' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_int2_eq(FIXEDDECIMAL, INT2) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int2_eq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_int2_ne(FIXEDDECIMAL, INT2) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int2_ne' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_int2_lt(FIXEDDECIMAL, INT2) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int2_lt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_int2_le(FIXEDDECIMAL, INT2) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int2_le' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_int2_gt(FIXEDDECIMAL, INT2) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int2_gt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_int2_ge(FIXEDDECIMAL, INT2) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int2_ge' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalint2pl(FIXEDDECIMAL, INT2) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'fixeddecimalint2pl' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalint2mi(FIXEDDECIMAL, INT2) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'fixeddecimalint2mi' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalint2mul(FIXEDDECIMAL, INT2) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'fixeddecimalint2mul' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalint2div(FIXEDDECIMAL, INT2) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'fixeddecimalint2div' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = fixeddecimal_int2_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR sys.<> ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = fixeddecimal_int2_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR sys.< ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = fixeddecimal_int2_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.<= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = fixeddecimal_int2_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.>= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = fixeddecimal_int2_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.> ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = fixeddecimal_int2_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.+ ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + COMMUTATOR = +, + PROCEDURE = fixeddecimalint2pl +); + +CREATE OPERATOR sys.- ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + PROCEDURE = fixeddecimalint2mi +); + +CREATE OPERATOR sys.* ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + COMMUTATOR = *, + PROCEDURE = fixeddecimalint2mul +); + +CREATE OPERATOR sys./ ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + PROCEDURE = fixeddecimalint2div +); + +ALTER OPERATOR FAMILY fixeddecimal_ops USING btree ADD + OPERATOR 1 < (FIXEDDECIMAL, INT2), + OPERATOR 2 <= (FIXEDDECIMAL, INT2), + OPERATOR 3 = (FIXEDDECIMAL, INT2), + OPERATOR 4 >= (FIXEDDECIMAL, INT2), + OPERATOR 5 > (FIXEDDECIMAL, INT2), + FUNCTION 1 fixeddecimal_int2_cmp(FIXEDDECIMAL, INT2); + +ALTER OPERATOR FAMILY fixeddecimal_ops USING hash ADD + OPERATOR 1 = (FIXEDDECIMAL, INT2); + +-- INT2, FIXEDDECIMAL +CREATE FUNCTION sys.int2_fixeddecimal_cmp(INT2, FIXEDDECIMAL) +RETURNS INT4 +AS 'babelfishpg_money', 'int2_fixeddecimal_cmp' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int2_fixeddecimal_eq(INT2, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int2_fixeddecimal_eq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int2_fixeddecimal_ne(INT2, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int2_fixeddecimal_ne' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int2_fixeddecimal_lt(INT2, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int2_fixeddecimal_lt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int2_fixeddecimal_le(INT2, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int2_fixeddecimal_le' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int2_fixeddecimal_gt(INT2, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int2_fixeddecimal_gt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int2_fixeddecimal_ge(INT2, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int2_fixeddecimal_ge' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int2fixeddecimalpl(INT2, FIXEDDECIMAL) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'int2fixeddecimalpl' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int2fixeddecimalmi(INT2, FIXEDDECIMAL) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'int2fixeddecimalmi' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int2fixeddecimalmul(INT2, FIXEDDECIMAL) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'int2fixeddecimalmul' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int2fixeddecimaldiv(INT2, FIXEDDECIMAL) +RETURNS DOUBLE PRECISION +AS 'babelfishpg_money', 'int2fixeddecimaldiv' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.= ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = int2_fixeddecimal_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR sys.<> ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = int2_fixeddecimal_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR sys.< ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = int2_fixeddecimal_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.<= ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = int2_fixeddecimal_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.>= ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = int2_fixeddecimal_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.> ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = int2_fixeddecimal_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.+ ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = +, + PROCEDURE = int2fixeddecimalpl +); + +CREATE OPERATOR sys.- ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = int2fixeddecimalmi +); + +CREATE OPERATOR sys.* ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = *, + PROCEDURE = int2fixeddecimalmul +); + +CREATE OPERATOR sys./ ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = int2fixeddecimaldiv +); + +ALTER OPERATOR FAMILY fixeddecimal_ops USING btree ADD + OPERATOR 1 < (INT2, FIXEDDECIMAL), + OPERATOR 2 <= (INT2, FIXEDDECIMAL), + OPERATOR 3 = (INT2, FIXEDDECIMAL), + OPERATOR 4 >= (INT2, FIXEDDECIMAL), + OPERATOR 5 > (INT2, FIXEDDECIMAL), + FUNCTION 1 int2_fixeddecimal_cmp(INT2, FIXEDDECIMAL); + +ALTER OPERATOR FAMILY fixeddecimal_ops USING hash ADD + OPERATOR 1 = (INT2, FIXEDDECIMAL); + +-- add combination of (int8/int4/int2) to fixeddecimal_ops to make it complete +ALTER OPERATOR FAMILY fixeddecimal_ops USING btree ADD + -- INT8 + OPERATOR 1 < (INT8, INT8), + OPERATOR 2 <= (INT8, INT8), + OPERATOR 3 = (INT8, INT8), + OPERATOR 4 >= (INT8, INT8), + OPERATOR 5 > (INT8, INT8), + FUNCTION 1 btint8cmp(INT8, INT8), + + OPERATOR 1 < (INT8, INT4), + OPERATOR 2 <= (INT8, INT4), + OPERATOR 3 = (INT8, INT4), + OPERATOR 4 >= (INT8, INT4), + OPERATOR 5 > (INT8, INT4), + FUNCTION 1 btint84cmp(INT8, INT4), + + OPERATOR 1 < (INT8, INT2), + OPERATOR 2 <= (INT8, INT2), + OPERATOR 3 = (INT8, INT2), + OPERATOR 4 >= (INT8, INT2), + OPERATOR 5 > (INT8, INT2), + FUNCTION 1 btint82cmp(INT8, INT2), + + -- INT4 + OPERATOR 1 < (INT4, INT8), + OPERATOR 2 <= (INT4, INT8), + OPERATOR 3 = (INT4, INT8), + OPERATOR 4 >= (INT4, INT8), + OPERATOR 5 > (INT4, INT8), + FUNCTION 1 btint48cmp(INT4, INT8), + + OPERATOR 1 < (INT4, INT4), + OPERATOR 2 <= (INT4, INT4), + OPERATOR 3 = (INT4, INT4), + OPERATOR 4 >= (INT4, INT4), + OPERATOR 5 > (INT4, INT4), + FUNCTION 1 btint4cmp(INT4, INT4), + + OPERATOR 1 < (INT4, INT2), + OPERATOR 2 <= (INT4, INT2), + OPERATOR 3 = (INT4, INT2), + OPERATOR 4 >= (INT4, INT2), + OPERATOR 5 > (INT4, INT2), + FUNCTION 1 btint42cmp(INT4, INT2), + + -- INT2 + OPERATOR 1 < (INT2, INT8), + OPERATOR 2 <= (INT2, INT8), + OPERATOR 3 = (INT2, INT8), + OPERATOR 4 >= (INT2, INT8), + OPERATOR 5 > (INT2, INT8), + FUNCTION 1 btint28cmp(INT2, INT8), + + OPERATOR 1 < (INT2, INT4), + OPERATOR 2 <= (INT2, INT4), + OPERATOR 3 = (INT2, INT4), + OPERATOR 4 >= (INT2, INT4), + OPERATOR 5 > (INT2, INT4), + FUNCTION 1 btint24cmp(INT2, INT4), + + OPERATOR 1 < (INT2, INT2), + OPERATOR 2 <= (INT2, INT2), + OPERATOR 3 = (INT2, INT2), + OPERATOR 4 >= (INT2, INT2), + OPERATOR 5 > (INT2, INT2), + FUNCTION 1 btint2cmp(INT2, INT2), + + -- numeric + OPERATOR 1 < (NUMERIC, NUMERIC), + OPERATOR 2 <= (NUMERIC, NUMERIC), + OPERATOR 3 = (NUMERIC, NUMERIC), + OPERATOR 4 >= (NUMERIC, NUMERIC), + OPERATOR 5 > (NUMERIC, NUMERIC), + FUNCTION 1 numeric_cmp(NUMERIC, NUMERIC); + + +ALTER OPERATOR FAMILY fixeddecimal_ops USING hash ADD + OPERATOR 1 = (INT8, INT8), + OPERATOR 1 = (INT8, INT4), + OPERATOR 1 = (INT8, INT2), + OPERATOR 1 = (INT4, INT8), + OPERATOR 1 = (INT4, INT4), + OPERATOR 1 = (INT4, INT2), + OPERATOR 1 = (INT2, INT8), + OPERATOR 1 = (INT2, INT4), + OPERATOR 1 = (INT2, INT2), + OPERATOR 1 = (NUMERIC, NUMERIC), + FUNCTION 1 hashint8(INT8), + FUNCTION 1 hashint4(INT4), + FUNCTION 1 hashint2(INT2), + FUNCTION 1 hash_numeric(NUMERIC); + +-- +-- Casts +-- + +CREATE FUNCTION sys.fixeddecimal(FIXEDDECIMAL, INT4) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimal' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int8fixeddecimal(INT8) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'int8fixeddecimal' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalint8(FIXEDDECIMAL) +RETURNS INT8 +AS 'babelfishpg_money', 'fixeddecimalint8' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int4fixeddecimal(INT4) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'int4fixeddecimal' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalint4(FIXEDDECIMAL) +RETURNS INT4 +AS 'babelfishpg_money', 'fixeddecimalint4' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int2fixeddecimal(INT2) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'int2fixeddecimal' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalint2(FIXEDDECIMAL) +RETURNS INT2 +AS 'babelfishpg_money', 'fixeddecimalint2' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimaltod(FIXEDDECIMAL) +RETURNS DOUBLE PRECISION +AS 'babelfishpg_money', 'fixeddecimaltod' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.dtofixeddecimal(DOUBLE PRECISION) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'dtofixeddecimal' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimaltof(FIXEDDECIMAL) +RETURNS REAL +AS 'babelfishpg_money', 'fixeddecimaltof' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.ftofixeddecimal(REAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'ftofixeddecimal' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_numeric(FIXEDDECIMAL) +RETURNS NUMERIC +AS 'babelfishpg_money', 'fixeddecimal_numeric' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.numeric_fixeddecimal(NUMERIC) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'numeric_fixeddecimal' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (FIXEDDECIMAL AS FIXEDDECIMAL) + WITH FUNCTION fixeddecimal (FIXEDDECIMAL, INT4) AS ASSIGNMENT; + +CREATE CAST (INT8 AS FIXEDDECIMAL) + WITH FUNCTION int8fixeddecimal (INT8) AS IMPLICIT; + +CREATE CAST (FIXEDDECIMAL AS INT8) + WITH FUNCTION fixeddecimalint8 (FIXEDDECIMAL) AS ASSIGNMENT; + +CREATE CAST (INT4 AS FIXEDDECIMAL) + WITH FUNCTION int4fixeddecimal (INT4) AS IMPLICIT; + +CREATE CAST (FIXEDDECIMAL AS INT4) + WITH FUNCTION fixeddecimalint4 (FIXEDDECIMAL) AS ASSIGNMENT; + +CREATE CAST (INT2 AS FIXEDDECIMAL) + WITH FUNCTION int2fixeddecimal (INT2) AS IMPLICIT; + +CREATE CAST (FIXEDDECIMAL AS INT2) + WITH FUNCTION fixeddecimalint2 (FIXEDDECIMAL) AS ASSIGNMENT; + +CREATE CAST (FIXEDDECIMAL AS DOUBLE PRECISION) + WITH FUNCTION fixeddecimaltod (FIXEDDECIMAL) AS IMPLICIT; + +CREATE CAST (DOUBLE PRECISION AS FIXEDDECIMAL) + WITH FUNCTION dtofixeddecimal (DOUBLE PRECISION) AS ASSIGNMENT; -- XXX? or Implicit? + +CREATE CAST (FIXEDDECIMAL AS REAL) + WITH FUNCTION fixeddecimaltof (FIXEDDECIMAL) AS IMPLICIT; + +CREATE CAST (REAL AS FIXEDDECIMAL) + WITH FUNCTION ftofixeddecimal (REAL) AS ASSIGNMENT; -- XXX or Implicit? + +CREATE CAST (FIXEDDECIMAL AS NUMERIC) + WITH FUNCTION fixeddecimal_numeric (FIXEDDECIMAL) AS IMPLICIT; + +CREATE CAST (NUMERIC AS FIXEDDECIMAL) + WITH FUNCTION numeric_fixeddecimal (NUMERIC) AS IMPLICIT; + +CREATE DOMAIN sys.MONEY as sys.FIXEDDECIMAL CHECK (VALUE >= -922337203685477.5808 AND VALUE <= 922337203685477.5807); +CREATE DOMAIN sys.SMALLMONEY as sys.FIXEDDECIMAL CHECK (VALUE >= -214748.3648 AND VALUE <= 214748.3647); diff --git a/contrib/babelfishpg_common/sql/money/fixeddecimal--brin.sql b/contrib/babelfishpg_common/sql/money/fixeddecimal--brin.sql new file mode 100644 index 00000000000..7969a0a60e2 --- /dev/null +++ b/contrib/babelfishpg_common/sql/money/fixeddecimal--brin.sql @@ -0,0 +1,12 @@ +CREATE OPERATOR CLASS sys.fixeddecimal_minmax_ops +DEFAULT FOR TYPE FIXEDDECIMAL USING brin AS + OPERATOR 1 < (FIXEDDECIMAL, FIXEDDECIMAL), + OPERATOR 2 <= (FIXEDDECIMAL, FIXEDDECIMAL), + OPERATOR 3 = (FIXEDDECIMAL, FIXEDDECIMAL), + OPERATOR 4 >= (FIXEDDECIMAL, FIXEDDECIMAL), + OPERATOR 5 > (FIXEDDECIMAL, FIXEDDECIMAL), + FUNCTION 1 brin_minmax_opcinfo(INTERNAL), + FUNCTION 2 brin_minmax_add_value(INTERNAL, INTERNAL, INTERNAL, INTERNAL), + FUNCTION 3 brin_minmax_consistent(INTERNAL, INTERNAL, INTERNAL), + FUNCTION 4 brin_minmax_union(INTERNAL, INTERNAL, INTERNAL); + diff --git a/contrib/babelfishpg_common/sql/money/fixeddecimal--parallelaggs.sql b/contrib/babelfishpg_common/sql/money/fixeddecimal--parallelaggs.sql new file mode 100644 index 00000000000..c30c0463494 --- /dev/null +++ b/contrib/babelfishpg_common/sql/money/fixeddecimal--parallelaggs.sql @@ -0,0 +1,70 @@ + +-- Aggregate Support + +CREATE FUNCTION sys.fixeddecimalaggstatecombine(INTERNAL, INTERNAL) +RETURNS INTERNAL +AS 'babelfishpg_money', 'fixeddecimalaggstatecombine' +LANGUAGE C IMMUTABLE PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalaggstateserialize(INTERNAL) +RETURNS BYTEA +AS 'babelfishpg_money', 'fixeddecimalaggstateserialize' +LANGUAGE C IMMUTABLE PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimalaggstatedeserialize(BYTEA, INTERNAL) +RETURNS INTERNAL +AS 'babelfishpg_money', 'fixeddecimalaggstatedeserialize' +LANGUAGE C IMMUTABLE PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_avg_accum(INTERNAL, FIXEDDECIMAL) +RETURNS INTERNAL +AS 'babelfishpg_money', 'fixeddecimal_avg_accum' +LANGUAGE C IMMUTABLE PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_sum(INTERNAL) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'fixeddecimal_sum' +LANGUAGE C IMMUTABLE PARALLEL SAFE; + +CREATE FUNCTION sys.fixeddecimal_avg(INTERNAL) +RETURNS sys.MONEY +AS 'babelfishpg_money', 'fixeddecimal_avg' +LANGUAGE C IMMUTABLE PARALLEL SAFE; + +CREATE AGGREGATE sys.min(FIXEDDECIMAL) ( + SFUNC = fixeddecimalsmaller, + STYPE = FIXEDDECIMAL, + SORTOP = <, + COMBINEFUNC = fixeddecimalsmaller, + PARALLEL = SAFE +); + +CREATE AGGREGATE sys.max(FIXEDDECIMAL) ( + SFUNC = fixeddecimallarger, + STYPE = FIXEDDECIMAL, + SORTOP = >, + COMBINEFUNC = fixeddecimallarger, + PARALLEL = SAFE +); + +CREATE AGGREGATE sys.sum(FIXEDDECIMAL) ( + SFUNC = fixeddecimal_avg_accum, + FINALFUNC = fixeddecimal_sum, + STYPE = INTERNAL, + COMBINEFUNC = fixeddecimalaggstatecombine, + SERIALFUNC = fixeddecimalaggstateserialize, + DESERIALFUNC = fixeddecimalaggstatedeserialize, + PARALLEL = SAFE +); + +CREATE AGGREGATE sys.avg(FIXEDDECIMAL) ( + SFUNC = fixeddecimal_avg_accum, + FINALFUNC = fixeddecimal_avg, + STYPE = INTERNAL, + COMBINEFUNC = fixeddecimalaggstatecombine, + SERIALFUNC = fixeddecimalaggstateserialize, + DESERIALFUNC = fixeddecimalaggstatedeserialize, + PARALLEL = SAFE +); + + diff --git a/contrib/babelfishpg_common/sql/numerics.sql b/contrib/babelfishpg_common/sql/numerics.sql new file mode 100644 index 00000000000..8a40ec6f801 --- /dev/null +++ b/contrib/babelfishpg_common/sql/numerics.sql @@ -0,0 +1,77 @@ +CREATE DOMAIN sys.TINYINT AS SMALLINT CHECK (VALUE >= 0 AND VALUE <= 255); +CREATE DOMAIN sys.INT AS INTEGER; +CREATE DOMAIN sys.BIGINT AS BIGINT; +CREATE DOMAIN sys.REAL AS REAL; +CREATE DOMAIN sys.FLOAT AS DOUBLE PRECISION; + +-- Types with different default typmod behavior +SET enable_domain_typmod = TRUE; +CREATE DOMAIN sys.DECIMAL AS NUMERIC; +RESET enable_domain_typmod; + +-- Domain Self Cast Functions to support Typmod Cast in Domain +CREATE OR REPLACE FUNCTION sys.decimal(sys.nchar, integer, boolean) +RETURNS sys.nchar +AS 'numeric' +LANGUAGE INTERNAL IMMUTABLE STRICT PARALLEL SAFE; + + +CREATE OR REPLACE FUNCTION sys.tinyintxor(leftarg sys.tinyint, rightarg sys.tinyint) +RETURNS sys.tinyint +AS $$ +SELECT CAST(CAST(sys.bitxor(CAST(CAST(leftarg AS int4) AS pg_catalog.bit(16)), + CAST(CAST(rightarg AS int4) AS pg_catalog.bit(16))) AS int4) AS sys.tinyint); +$$ +LANGUAGE SQL; + +CREATE OPERATOR sys.^ ( + LEFTARG = sys.tinyint, + RIGHTARG = sys.tinyint, + FUNCTION = sys.tinyintxor, + COMMUTATOR = ^ +); + +CREATE OR REPLACE FUNCTION sys.int2xor(leftarg int2, rightarg int2) +RETURNS int2 +AS $$ +SELECT CAST(CAST(sys.bitxor(CAST(CAST(leftarg AS int4) AS pg_catalog.bit(16)), + CAST(CAST(rightarg AS int4) AS pg_catalog.bit(16))) AS int4) AS int2); +$$ +LANGUAGE SQL; + +CREATE OPERATOR sys.^ ( + LEFTARG = int2, + RIGHTARG = int2, + FUNCTION = sys.int2xor, + COMMUTATOR = ^ +); + +CREATE OR REPLACE FUNCTION sys.intxor(leftarg int4, rightarg int4) +RETURNS int4 +AS $$ +SELECT CAST(sys.bitxor(CAST(leftarg AS pg_catalog.bit(32)), + CAST(rightarg AS pg_catalog.bit(32))) AS int4) +$$ +LANGUAGE SQL; + +CREATE OPERATOR sys.^ ( + LEFTARG = int4, + RIGHTARG = int4, + FUNCTION = sys.intxor, + COMMUTATOR = ^ +); + +CREATE OR REPLACE FUNCTION sys.int8xor(leftarg int8, rightarg int8) +RETURNS int8 +AS $$ +SELECT CAST(sys.bitxor(CAST(leftarg AS pg_catalog.bit(64)), + CAST(rightarg AS pg_catalog.bit(64))) AS int8) +$$ +LANGUAGE SQL; + +CREATE OPERATOR sys.^ ( + LEFTARG = int8, + RIGHTARG = int8, + FUNCTION = sys.int8xor, + COMMUTATOR = ^ +); diff --git a/contrib/babelfishpg_common/sql/smalldatetime.sql b/contrib/babelfishpg_common/sql/smalldatetime.sql new file mode 100644 index 00000000000..a6504df6530 --- /dev/null +++ b/contrib/babelfishpg_common/sql/smalldatetime.sql @@ -0,0 +1,588 @@ +CREATE TYPE sys.SMALLDATETIME; + +CREATE OR REPLACE FUNCTION sys.smalldatetimein(cstring) +RETURNS sys.SMALLDATETIME +AS 'babelfishpg_common', 'smalldatetime_in' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.smalldatetimeout(sys.SMALLDATETIME) +RETURNS cstring +AS 'timestamp_out' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.smalldatetimerecv(internal) +RETURNS sys.SMALLDATETIME +AS 'timestamp_recv' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.smalldatetimesend(sys.SMALLDATETIME) +RETURNS bytea +AS 'timestamp_send' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.smalltypmodin(cstring[]) +RETURNS integer +AS 'timestamptypmodin' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.smalltypmodout(integer) +RETURNS cstring +AS 'timestamptypmodout' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE TYPE sys.SMALLDATETIME ( + INPUT = sys.smalldatetimein, + OUTPUT = sys.smalldatetimeout, + RECEIVE = sys.smalldatetimerecv, + SEND = sys.smalldatetimesend, + TYPMOD_IN = sys.smalltypmodin, + TYPMOD_OUT = sys.smalltypmodout, + INTERNALLENGTH = 8, + ALIGNMENT = 'double', + STORAGE = 'plain', + CATEGORY = 'D', + PREFERRED = false, + COLLATABLE = false, + DEFAULT = '1900-01-01 00:00', + PASSEDBYVALUE +); + +CREATE FUNCTION sys.smalldatetimeeq(sys.SMALLDATETIME, sys.SMALLDATETIME) +RETURNS bool +AS 'timestamp_eq' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.smalldatetimene(sys.SMALLDATETIME, sys.SMALLDATETIME) +RETURNS bool +AS 'timestamp_ne' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.smalldatetimelt(sys.SMALLDATETIME, sys.SMALLDATETIME) +RETURNS bool +AS 'timestamp_lt' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.smalldatetimele(sys.SMALLDATETIME, sys.SMALLDATETIME) +RETURNS bool +AS 'timestamp_le' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.smalldatetimegt(sys.SMALLDATETIME, sys.SMALLDATETIME) +RETURNS bool +AS 'timestamp_gt' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.smalldatetimege(sys.SMALLDATETIME, sys.SMALLDATETIME) +RETURNS bool +AS 'timestamp_ge' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.= ( + LEFTARG = sys.SMALLDATETIME, + RIGHTARG = sys.SMALLDATETIME, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = sys.smalldatetimeeq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR sys.<> ( + LEFTARG = sys.SMALLDATETIME, + RIGHTARG = sys.SMALLDATETIME, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = sys.smalldatetimene, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR sys.< ( + LEFTARG = sys.SMALLDATETIME, + RIGHTARG = sys.SMALLDATETIME, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = sys.smalldatetimelt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.<= ( + LEFTARG = sys.SMALLDATETIME, + RIGHTARG = sys.SMALLDATETIME, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = sys.smalldatetimele, + RESTRICT = scalarlesel, + JOIN = scalarlejoinsel +); + +CREATE OPERATOR sys.> ( + LEFTARG = sys.SMALLDATETIME, + RIGHTARG = sys.SMALLDATETIME, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = sys.smalldatetimegt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.>= ( + LEFTARG = sys.SMALLDATETIME, + RIGHTARG = sys.SMALLDATETIME, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = sys.smalldatetimege, + RESTRICT = scalargesel, + JOIN = scalargejoinsel +); + +-- smalldate vs pg_catalog.date +CREATE FUNCTION sys.smalldatetime_eq_date(sys.SMALLDATETIME, pg_catalog.date) +RETURNS bool +AS 'timestamp_eq_date' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.smalldatetime_ne_date(sys.SMALLDATETIME, pg_catalog.date) +RETURNS bool +AS 'timestamp_ne_date' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.smalldatetime_lt_date(sys.SMALLDATETIME, pg_catalog.date) +RETURNS bool +AS 'timestamp_lt_date' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.smalldatetime_le_date(sys.SMALLDATETIME, pg_catalog.date) +RETURNS bool +AS 'timestamp_le_date' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.smalldatetime_gt_date(sys.SMALLDATETIME, pg_catalog.date) +RETURNS bool +AS 'timestamp_gt_date' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.smalldatetime_ge_date(sys.SMALLDATETIME, pg_catalog.date) +RETURNS bool +AS 'timestamp_ge_date' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.= ( + LEFTARG = sys.SMALLDATETIME, + RIGHTARG = pg_catalog.date, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = smalldatetime_eq_date, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR sys.<> ( + LEFTARG = sys.SMALLDATETIME, + RIGHTARG = pg_catalog.date, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = smalldatetime_ne_date, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR sys.< ( + LEFTARG = sys.SMALLDATETIME, + RIGHTARG = pg_catalog.date, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = smalldatetime_lt_date, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.<= ( + LEFTARG = sys.SMALLDATETIME, + RIGHTARG = pg_catalog.date, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = smalldatetime_le_date, + RESTRICT = scalarlesel, + JOIN = scalarlejoinsel +); + +CREATE OPERATOR sys.> ( + LEFTARG = sys.SMALLDATETIME, + RIGHTARG = pg_catalog.date, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = smalldatetime_gt_date, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.>= ( + LEFTARG = sys.SMALLDATETIME, + RIGHTARG = pg_catalog.date, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = smalldatetime_ge_date, + RESTRICT = scalargesel, + JOIN = scalargejoinsel +); + +-- pg_catalog.date vs smalldate +CREATE FUNCTION sys.date_eq_smalldatetime(pg_catalog.date, sys.SMALLDATETIME) +RETURNS bool +AS 'date_eq_timestamp' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.date_ne_smalldatetime(pg_catalog.date, sys.SMALLDATETIME) +RETURNS bool +AS 'date_ne_timestamp' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.date_lt_smalldatetime(pg_catalog.date, sys.SMALLDATETIME) +RETURNS bool +AS 'date_lt_timestamp' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.date_le_smalldatetime(pg_catalog.date, sys.SMALLDATETIME) +RETURNS bool +AS 'date_le_timestamp' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.date_gt_smalldatetime(pg_catalog.date, sys.SMALLDATETIME) +RETURNS bool +AS 'date_gt_timestamp' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.date_ge_smalldatetime(pg_catalog.date, sys.SMALLDATETIME) +RETURNS bool +AS 'date_ge_timestamp' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.= ( + LEFTARG = pg_catalog.date, + RIGHTARG = sys.SMALLDATETIME, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = date_eq_smalldatetime, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR sys.<> ( + LEFTARG = pg_catalog.date, + RIGHTARG = sys.SMALLDATETIME, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = date_ne_smalldatetime, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR sys.< ( + LEFTARG = pg_catalog.date, + RIGHTARG = sys.SMALLDATETIME, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = date_lt_smalldatetime, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.<= ( + LEFTARG = pg_catalog.date, + RIGHTARG = sys.SMALLDATETIME, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = date_le_smalldatetime, + RESTRICT = scalarlesel, + JOIN = scalarlejoinsel +); + +CREATE OPERATOR sys.> ( + LEFTARG = pg_catalog.date, + RIGHTARG = sys.SMALLDATETIME, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = date_gt_smalldatetime, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.>= ( + LEFTARG = pg_catalog.date, + RIGHTARG = sys.SMALLDATETIME, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = date_ge_smalldatetime, + RESTRICT = scalargesel, + JOIN = scalargejoinsel +); + + +-- smalldatetime <-> int/float operators for smalldatetime-int +/- arithmetic +CREATE FUNCTION sys.smalldatetimeplint4(sys.smalldatetime, INT4) +RETURNS sys.smalldatetime +AS 'babelfishpg_common', 'smalldatetime_pl_int4' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int4plsmalldatetime(INT4, sys.smalldatetime) +RETURNS sys.smalldatetime +AS 'babelfishpg_common', 'int4_pl_smalldatetime' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.smalldatetimemiint4(sys.smalldatetime, INT4) +RETURNS sys.smalldatetime +AS 'babelfishpg_common', 'smalldatetime_mi_int4' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.int4mismalldatetime(INT4, sys.smalldatetime) +RETURNS sys.smalldatetime +AS 'babelfishpg_common', 'int4_mi_smalldatetime' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.+ ( + LEFTARG = sys.smalldatetime, + RIGHTARG = INT4, + PROCEDURE = sys.smalldatetimeplint4 +); + +CREATE OPERATOR sys.+ ( + LEFTARG = INT4, + RIGHTARG = sys.smalldatetime, + PROCEDURE = sys.int4plsmalldatetime +); + +CREATE OPERATOR sys.- ( + LEFTARG = sys.smalldatetime, + RIGHTARG = INT4, + PROCEDURE = sys.smalldatetimemiint4 +); + +CREATE OPERATOR sys.- ( + LEFTARG = INT4, + RIGHTARG = sys.smalldatetime, + PROCEDURE = sys.int4mismalldatetime +); + + + +CREATE FUNCTION sys.smalldatetimeplfloat8(sys.smalldatetime, float8) +RETURNS sys.smalldatetime +AS 'babelfishpg_common', 'smalldatetime_pl_float8' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.+ ( + LEFTARG = sys.smalldatetime, + RIGHTARG = float8, + PROCEDURE = sys.smalldatetimeplfloat8 +); + +CREATE FUNCTION sys.smalldatetimemifloat8(sys.smalldatetime, float8) +RETURNS sys.smalldatetime +AS 'babelfishpg_common', 'smalldatetime_mi_float8' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.- ( + LEFTARG = sys.smalldatetime, + RIGHTARG = float8, + PROCEDURE = sys.smalldatetimemifloat8 +); + +CREATE FUNCTION sys.float8plsmalldatetime(float8, sys.smalldatetime) +RETURNS sys.smalldatetime +AS 'babelfishpg_common', 'float8_pl_smalldatetime' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.+ ( + LEFTARG = float8, + RIGHTARG = sys.smalldatetime, + PROCEDURE = sys.float8plsmalldatetime +); + +CREATE FUNCTION sys.float8mismalldatetime(float8, sys.smalldatetime) +RETURNS sys.smalldatetime +AS 'babelfishpg_common', 'float8_mi_smalldatetime' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.- ( + LEFTARG = float8, + RIGHTARG = sys.smalldatetime, + PROCEDURE = sys.float8mismalldatetime +); + + + +CREATE FUNCTION smalldatetime_cmp(sys.SMALLDATETIME, sys.SMALLDATETIME) +RETURNS INT4 +AS 'timestamp_cmp' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION smalldatetime_hash(sys.SMALLDATETIME) +RETURNS INT4 +AS 'timestamp_hash' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR CLASS sys.smalldatetime_ops +DEFAULT FOR TYPE sys.SMALLDATETIME USING btree AS + OPERATOR 1 < (sys.SMALLDATETIME, sys.SMALLDATETIME), + OPERATOR 2 <= (sys.SMALLDATETIME, sys.SMALLDATETIME), + OPERATOR 3 = (sys.SMALLDATETIME, sys.SMALLDATETIME), + OPERATOR 4 >= (sys.SMALLDATETIME, sys.SMALLDATETIME), + OPERATOR 5 > (sys.SMALLDATETIME, sys.SMALLDATETIME), + FUNCTION 1 smalldatetime_cmp(sys.SMALLDATETIME, sys.SMALLDATETIME); + +CREATE OPERATOR CLASS sys.smalldatetime_ops +DEFAULT FOR TYPE sys.SMALLDATETIME USING hash AS + OPERATOR 1 = (sys.SMALLDATETIME, sys.SMALLDATETIME), + FUNCTION 1 smalldatetime_hash(sys.SMALLDATETIME); + +CREATE OR REPLACE FUNCTION sys.timestamp2smalldatetime(TIMESTAMP) +RETURNS SMALLDATETIME +AS 'babelfishpg_common', 'timestamp_smalldatetime' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetime2smalldatetime(DATETIME) +RETURNS SMALLDATETIME +AS 'babelfishpg_common', 'timestamp_smalldatetime' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetime22smalldatetime(DATETIME2) +RETURNS SMALLDATETIME +AS 'babelfishpg_common', 'timestamp_smalldatetime' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.date2smalldatetime(DATE) +RETURNS SMALLDATETIME +AS 'babelfishpg_common', 'date_smalldatetime' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.smalldatetime2date(SMALLDATETIME) +RETURNS DATE +AS 'timestamp_date' +LANGUAGE internal VOLATILE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.timestamptz2smalldatetime(TIMESTAMPTZ) +RETURNS SMALLDATETIME +AS 'babelfishpg_common', 'timestamptz_smalldatetime' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.smalldatetime2timestamptz(SMALLDATETIME) +RETURNS TIMESTAMPTZ +AS 'timestamp_timestamptz' +LANGUAGE internal VOLATILE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.time2smalldatetime(TIME) +RETURNS SMALLDATETIME +AS 'babelfishpg_common', 'time_smalldatetime' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.smalldatetime2time(SMALLDATETIME) +RETURNS TIME +AS 'timestamp_time' +LANGUAGE internal VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (TIMESTAMP AS SMALLDATETIME) +WITH FUNCTION sys.timestamp2smalldatetime(TIMESTAMP) AS ASSIGNMENT; + +CREATE CAST (DATETIME AS SMALLDATETIME) +WITH FUNCTION sys.datetime2smalldatetime(DATETIME) AS ASSIGNMENT; + +CREATE CAST (DATETIME2 AS SMALLDATETIME) +WITH FUNCTION sys.datetime22smalldatetime(DATETIME2) AS ASSIGNMENT; + +CREATE CAST (SMALLDATETIME AS DATETIME) +WITHOUT FUNCTION AS IMPLICIT; + +CREATE CAST (SMALLDATETIME AS DATETIME2) +WITHOUT FUNCTION AS IMPLICIT; + +CREATE CAST (SMALLDATETIME AS TIMESTAMP) +WITHOUT FUNCTION AS IMPLICIT; + +CREATE CAST (TIMESTAMPTZ AS SMALLDATETIME) +WITH FUNCTION sys.timestamptz2smalldatetime (TIMESTAMPTZ) AS IMPLICIT; + +CREATE CAST (SMALLDATETIME AS TIMESTAMPTZ) +WITH FUNCTION sys.smalldatetime2timestamptz (SMALLDATETIME) AS ASSIGNMENT; + +CREATE CAST (DATE AS SMALLDATETIME) +WITH FUNCTION sys.date2smalldatetime (DATE) AS IMPLICIT; + +CREATE CAST (SMALLDATETIME AS DATE) +WITH FUNCTION sys.smalldatetime2date (SMALLDATETIME) AS ASSIGNMENT; + +CREATE CAST (TIME AS SMALLDATETIME) +WITH FUNCTION sys.time2smalldatetime (TIME) AS IMPLICIT; + +CREATE CAST (SMALLDATETIME AS TIME) +WITH FUNCTION sys.smalldatetime2time (SMALLDATETIME) AS ASSIGNMENT; + +-- BABEL-1465 CAST from VARCHAR/NVARCHAR/CHAR/NCHAR to smalldatetime is VOLATILE +CREATE OR REPLACE FUNCTION sys.varchar2smalldatetime(sys.VARCHAR) +RETURNS SMALLDATETIME +AS 'babelfishpg_common', 'varchar_smalldatetime' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.VARCHAR AS SMALLDATETIME) +WITH FUNCTION sys.varchar2smalldatetime (sys.VARCHAR) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.varchar2smalldatetime(pg_catalog.VARCHAR) +RETURNS SMALLDATETIME +AS 'babelfishpg_common', 'varchar_smalldatetime' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (pg_catalog.VARCHAR AS SMALLDATETIME) +WITH FUNCTION sys.varchar2smalldatetime (pg_catalog.VARCHAR) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.char2smalldatetime(CHAR) +RETURNS SMALLDATETIME +AS 'babelfishpg_common', 'char_smalldatetime' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (CHAR AS SMALLDATETIME) +WITH FUNCTION sys.char2smalldatetime (CHAR) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.bpchar2smalldatetime(sys.BPCHAR) +RETURNS sys.SMALLDATETIME +AS 'babelfishpg_common', 'char_smalldatetime' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BPCHAR AS sys.SMALLDATETIME) +WITH FUNCTION sys.bpchar2smalldatetime (sys.BPCHAR) AS ASSIGNMENT; + +-- BABEL-1465 CAST from smalldatetime to VARCHAR/NVARCHAR/CHAR/NCHAR is VOLATILE +CREATE OR REPLACE FUNCTION sys.smalldatetime2sysvarchar(SMALLDATETIME) +RETURNS sys.VARCHAR +AS 'babelfishpg_common', 'smalldatetime_varchar' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (SMALLDATETIME AS sys.VARCHAR) +WITH FUNCTION sys.smalldatetime2sysvarchar (SMALLDATETIME) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.smalldatetime2varchar(SMALLDATETIME) +RETURNS pg_catalog.VARCHAR +AS 'babelfishpg_common', 'smalldatetime_varchar' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (SMALLDATETIME AS pg_catalog.VARCHAR) +WITH FUNCTION sys.smalldatetime2varchar (SMALLDATETIME) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.smalldatetime2char(SMALLDATETIME) +RETURNS CHAR +AS 'babelfishpg_common', 'smalldatetime_char' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (SMALLDATETIME AS CHAR) +WITH FUNCTION sys.smalldatetime2char (SMALLDATETIME) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.smalldatetime2bpchar(sys.SMALLDATETIME) +RETURNS sys.BPCHAR +AS 'babelfishpg_common', 'smalldatetime_char' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.SMALLDATETIME AS sys.BPCHAR) +WITH FUNCTION sys.smalldatetime2bpchar (sys.SMALLDATETIME) AS ASSIGNMENT; diff --git a/contrib/babelfishpg_common/sql/sqlvariant.sql b/contrib/babelfishpg_common/sql/sqlvariant.sql new file mode 100644 index 00000000000..5c7342e00ca --- /dev/null +++ b/contrib/babelfishpg_common/sql/sqlvariant.sql @@ -0,0 +1,548 @@ +CREATE TYPE sys.SQL_VARIANT; + +CREATE OR REPLACE FUNCTION sys.sqlvariantin(cstring, oid, integer) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'sqlvariantin' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.sqlvariantout(sys.SQL_VARIANT) +RETURNS cstring +AS 'babelfishpg_common', 'sqlvariantout' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.sqlvariantrecv(internal, oid, integer) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'sqlvariantrecv' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.sqlvariantsend(sys.SQL_VARIANT) +RETURNS bytea +AS 'babelfishpg_common', 'sqlvariantsend' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE TYPE sys.SQL_VARIANT ( + INPUT = sys.sqlvariantin, + OUTPUT = sys.sqlvariantout, + RECEIVE = sys.sqlvariantrecv, + SEND = sys.sqlvariantsend, + INTERNALLENGTH = VARIABLE, + ALIGNMENT = 'int4', + STORAGE = 'extended', + CATEGORY = 'U', + PREFERRED = false, + COLLATABLE = true +); + +-- DATALENGTH function for SQL_VARIANT +CREATE OR REPLACE FUNCTION sys.datalength(sys.SQL_VARIANT) +RETURNS integer +AS 'babelfishpg_common', 'datalength_sqlvariant' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- CAST FUNCTIONS to SQL_VARIANT + +-- cast functions from domain types are overloaded such that we support casts both in pg and tsql: +-- money/smallmoney, smallint/tinyint, varchar/nvarchar, char/nchar +-- in pg, we will have minimal support of casts since domains are not distinguished +-- in tsql, we will allow domain casts in coerce.sql such that exact type info are saved +-- this is required for sql_variant since we may call sql_variant_property() to retrieve base type + +CREATE OR REPLACE FUNCTION sys.datetime_sqlvariant(sys.DATETIME) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'datetime2sqlvariant' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.DATETIME AS sys.SQL_VARIANT) +WITH FUNCTION sys.datetime_sqlvariant (sys.DATETIME) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.datetime2_sqlvariant(sys.DATETIME2) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'datetime22sqlvariant' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.DATETIME2 AS sys.SQL_VARIANT) +WITH FUNCTION sys.datetime2_sqlvariant (sys.DATETIME2) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.datetimeoffset_sqlvariant(sys.DATETIMEOFFSET) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'datetimeoffset2sqlvariant' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.DATETIMEOFFSET AS sys.SQL_VARIANT) +WITH FUNCTION sys.datetimeoffset_sqlvariant (sys.DATETIMEOFFSET) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.smalldatetime_sqlvariant(sys.SMALLDATETIME) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'smalldatetime2sqlvariant' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.SMALLDATETIME AS sys.SQL_VARIANT) +WITH FUNCTION sys.smalldatetime_sqlvariant (sys.SMALLDATETIME) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.date_sqlvariant(DATE) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'date2sqlvariant' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (DATE AS sys.SQL_VARIANT) +WITH FUNCTION sys.date_sqlvariant (DATE) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.time_sqlvariant(TIME) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'time2sqlvariant' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (TIME AS sys.SQL_VARIANT) +WITH FUNCTION sys.time_sqlvariant (TIME) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.float_sqlvariant(FLOAT) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'float2sqlvariant' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (FLOAT AS sys.SQL_VARIANT) +WITH FUNCTION sys.float_sqlvariant (FLOAT) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.real_sqlvariant(REAL) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'real2sqlvariant' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (REAL AS sys.SQL_VARIANT) +WITH FUNCTION sys.real_sqlvariant (REAL) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.numeric_sqlvariant(NUMERIC) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'numeric2sqlvariant' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (NUMERIC AS sys.SQL_VARIANT) +WITH FUNCTION sys.numeric_sqlvariant (NUMERIC) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.money_sqlvariant(FIXEDDECIMAL) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'money2sqlvariant' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.money_sqlvariant(sys.money) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'money2sqlvariant' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.smallmoney_sqlvariant(sys.smallmoney) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'smallmoney2sqlvariant' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (FIXEDDECIMAL AS sys.SQL_VARIANT) +WITH FUNCTION sys.money_sqlvariant (FIXEDDECIMAL) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.bigint_sqlvariant(BIGINT) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'bigint2sqlvariant' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (BIGINT AS sys.SQL_VARIANT) +WITH FUNCTION sys.bigint_sqlvariant (BIGINT) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.int_sqlvariant(INT) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'int2sqlvariant' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (INT AS sys.SQL_VARIANT) +WITH FUNCTION sys.int_sqlvariant (INT) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.smallint_sqlvariant(SMALLINT) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'smallint2sqlvariant' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.smallint_sqlvariant(smallint) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'smallint2sqlvariant' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.tinyint_sqlvariant(sys.tinyint) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'tinyint2sqlvariant' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (SMALLINT AS sys.SQL_VARIANT) +WITH FUNCTION sys.smallint_sqlvariant (SMALLINT) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.bit_sqlvariant(sys.BIT) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'bit2sqlvariant' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BIT AS sys.SQL_VARIANT) +WITH FUNCTION sys.bit_sqlvariant (sys.BIT) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.varchar_sqlvariant(sys.varchar) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'varchar2sqlvariant' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.nvarchar_sqlvariant(sys.nvarchar) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'nvarchar2sqlvariant' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.VARCHAR AS sys.SQL_VARIANT) +WITH FUNCTION sys.varchar_sqlvariant (sys.VARCHAR) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.varchar_sqlvariant(pg_catalog.varchar) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'varchar2sqlvariant' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (pg_catalog.VARCHAR AS sys.SQL_VARIANT) +WITH FUNCTION sys.varchar_sqlvariant (pg_catalog.VARCHAR) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.char_sqlvariant(CHAR) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'char2sqlvariant' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.nchar_sqlvariant(sys.nchar) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'nchar2sqlvariant' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (CHAR AS sys.SQL_VARIANT) +WITH FUNCTION sys.char_sqlvariant (CHAR) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.char_sqlvariant(sys.BPCHAR) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'char2sqlvariant' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BPCHAR AS sys.SQL_VARIANT) +WITH FUNCTION sys.char_sqlvariant (sys.BPCHAR) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.bbfvarbinary_sqlvariant(sys.BBF_VARBINARY) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'bbfvarbinary2sqlvariant' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BBF_VARBINARY AS sys.SQL_VARIANT) +WITH FUNCTION sys.bbfvarbinary_sqlvariant (sys.BBF_VARBINARY) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.bbfbinary_sqlvariant(sys.BBF_BINARY) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'bbfbinary2sqlvariant' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BBF_BINARY AS sys.SQL_VARIANT) +WITH FUNCTION sys.bbfbinary_sqlvariant (sys.BBF_BINARY) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.uniqueidentifier_sqlvariant(sys.UNIQUEIDENTIFIER) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'uniqueidentifier2sqlvariant' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.UNIQUEIDENTIFIER AS sys.SQL_VARIANT) +WITH FUNCTION sys.uniqueidentifier_sqlvariant (sys.UNIQUEIDENTIFIER) AS IMPLICIT; + +-- CAST functions from SQL_VARIANT + +CREATE OR REPLACE FUNCTION sys.sqlvariant_datetime(sys.SQL_VARIANT) +RETURNS sys.DATETIME +AS 'babelfishpg_common', 'sqlvariant2timestamp' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.SQL_VARIANT AS sys.DATETIME) +WITH FUNCTION sys.sqlvariant_datetime (sys.SQL_VARIANT) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.sqlvariant_datetime2(sys.SQL_VARIANT) +RETURNS sys.DATETIME2 +AS 'babelfishpg_common', 'sqlvariant2timestamp' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.SQL_VARIANT AS sys.DATETIME2) +WITH FUNCTION sys.sqlvariant_datetime2 (sys.SQL_VARIANT) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.sqlvariant_datetimeoffset(sys.SQL_VARIANT) +RETURNS sys.DATETIMEOFFSET +AS 'babelfishpg_common', 'sqlvariant2datetimeoffset' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.SQL_VARIANT AS sys.DATETIMEOFFSET) +WITH FUNCTION sys.sqlvariant_datetimeoffset (sys.SQL_VARIANT) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.sqlvariant_smalldatetime(sys.SQL_VARIANT) +RETURNS sys.SMALLDATETIME +AS 'babelfishpg_common', 'sqlvariant2timestamp' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.SQL_VARIANT AS sys.SMALLDATETIME) +WITH FUNCTION sys.sqlvariant_smalldatetime (sys.SQL_VARIANT) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.sqlvariant_date(sys.SQL_VARIANT) +RETURNS DATE +AS 'babelfishpg_common', 'sqlvariant2date' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.SQL_VARIANT AS DATE) +WITH FUNCTION sys.sqlvariant_date (sys.SQL_VARIANT) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.sqlvariant_time(sys.SQL_VARIANT) +RETURNS TIME +AS 'babelfishpg_common', 'sqlvariant2time' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.SQL_VARIANT AS TIME) +WITH FUNCTION sys.sqlvariant_time (sys.SQL_VARIANT) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.sqlvariant_float(sys.SQL_VARIANT) +RETURNS FLOAT +AS 'babelfishpg_common', 'sqlvariant2float' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.SQL_VARIANT AS FLOAT) +WITH FUNCTION sys.sqlvariant_float (sys.SQL_VARIANT) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.sqlvariant_real(sys.SQL_VARIANT) +RETURNS REAL +AS 'babelfishpg_common', 'sqlvariant2real' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.SQL_VARIANT AS REAL) +WITH FUNCTION sys.sqlvariant_real (sys.SQL_VARIANT) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.sqlvariant_numeric(sys.SQL_VARIANT) +RETURNS NUMERIC +AS 'babelfishpg_common', 'sqlvariant2numeric' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.SQL_VARIANT AS NUMERIC) +WITH FUNCTION sys.sqlvariant_numeric (sys.SQL_VARIANT) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.sqlvariant_money(sys.SQL_VARIANT) +RETURNS sys.MONEY +AS 'babelfishpg_common', 'sqlvariant2fixeddecimal' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.sqlvariant_smallmoney(sys.SQL_VARIANT) +RETURNS sys.SMALLMONEY +AS 'babelfishpg_common', 'sqlvariant2fixeddecimal' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.SQL_VARIANT AS FIXEDDECIMAL) +WITH FUNCTION sys.sqlvariant_money (sys.SQL_VARIANT) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.sqlvariant_bigint(sys.SQL_VARIANT) +RETURNS BIGINT +AS 'babelfishpg_common', 'sqlvariant2bigint' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.SQL_VARIANT AS BIGINT) +WITH FUNCTION sys.sqlvariant_bigint (sys.SQL_VARIANT) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.sqlvariant_int(sys.SQL_VARIANT) +RETURNS INT +AS 'babelfishpg_common', 'sqlvariant2int' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.SQL_VARIANT AS INT) +WITH FUNCTION sys.sqlvariant_int (sys.SQL_VARIANT) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.sqlvariant_smallint(sys.SQL_VARIANT) +RETURNS SMALLINT +AS 'babelfishpg_common', 'sqlvariant2smallint' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.sqlvariant_tinyint(sys.SQL_VARIANT) +RETURNS sys.TINYINT +AS 'babelfishpg_common', 'sqlvariant2smallint' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.SQL_VARIANT AS SMALLINT) +WITH FUNCTION sys.sqlvariant_smallint (sys.SQL_VARIANT) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.sqlvariant_bit(sys.SQL_VARIANT) +RETURNS sys.BIT +AS 'babelfishpg_common', 'sqlvariant2bit' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.SQL_VARIANT AS sys.BIT) +WITH FUNCTION sys.sqlvariant_bit (sys.SQL_VARIANT) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.sqlvariant_sysvarchar(sys.SQL_VARIANT) +RETURNS sys.VARCHAR +AS 'babelfishpg_common', 'sqlvariant2varchar' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.SQL_VARIANT AS sys.VARCHAR) +WITH FUNCTION sys.sqlvariant_sysvarchar (sys.SQL_VARIANT) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.sqlvariant_varchar(sys.SQL_VARIANT) +RETURNS pg_catalog.VARCHAR +AS 'babelfishpg_common', 'sqlvariant2varchar' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.SQL_VARIANT AS pg_catalog.VARCHAR) +WITH FUNCTION sys.sqlvariant_varchar (sys.SQL_VARIANT) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.sqlvariant_nvarchar(sys.SQL_VARIANT) +RETURNS sys.NVARCHAR +AS 'babelfishpg_common', 'sqlvariant2varchar' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.sqlvariant_char(sys.SQL_VARIANT) +RETURNS CHAR +AS 'babelfishpg_common', 'sqlvariant2char' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.sqlvariant_nchar(sys.SQL_VARIANT) +RETURNS sys.NCHAR +AS 'babelfishpg_common', 'sqlvariant2char' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.SQL_VARIANT AS CHAR) +WITH FUNCTION sys.sqlvariant_char (sys.SQL_VARIANT) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.sqlvariant_bbfvarbinary(sys.SQL_VARIANT) +RETURNS sys.VARBINARY +AS 'babelfishpg_common', 'sqlvariant2bbfvarbinary' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.SQL_VARIANT AS sys.BBF_VARBINARY) +WITH FUNCTION sys.sqlvariant_bbfvarbinary (sys.SQL_VARIANT) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.sqlvariant_bbfbinary(sys.SQL_VARIANT) +RETURNS sys.BINARY +AS 'babelfishpg_common', 'sqlvariant2bbfbinary' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.SQL_VARIANT AS sys.BBF_BINARY) +WITH FUNCTION sys.sqlvariant_bbfbinary (sys.SQL_VARIANT) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.sqlvariant_uniqueidentifier(sys.SQL_VARIANT) +RETURNS sys.UNIQUEIDENTIFIER +AS 'babelfishpg_common', 'sqlvariant2uniqueidentifier' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE CAST (sys.SQL_VARIANT AS sys.UNIQUEIDENTIFIER) +WITH FUNCTION sys.sqlvariant_uniqueidentifier (sys.SQL_VARIANT) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.SQL_VARIANT_PROPERTY(sys.SQL_VARIANT, sys.VARCHAR(20)) +RETURNS sys.SQL_VARIANT +AS 'babelfishpg_common', 'sql_variant_property' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.sqlvarianteq(sys.SQL_VARIANT, sys.SQL_VARIANT) +RETURNS bool +AS 'babelfishpg_common', 'sqlvarianteq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.sqlvariantne(sys.SQL_VARIANT, sys.SQL_VARIANT) +RETURNS bool +AS 'babelfishpg_common', 'sqlvariantne' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.sqlvariantlt(sys.SQL_VARIANT, sys.SQL_VARIANT) +RETURNS bool +AS 'babelfishpg_common', 'sqlvariantlt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.sqlvariantle(sys.SQL_VARIANT, sys.SQL_VARIANT) +RETURNS bool +AS 'babelfishpg_common', 'sqlvariantle' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.sqlvariantgt(sys.SQL_VARIANT, sys.SQL_VARIANT) +RETURNS bool +AS 'babelfishpg_common', 'sqlvariantgt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.sqlvariantge(sys.SQL_VARIANT, sys.SQL_VARIANT) +RETURNS bool +AS 'babelfishpg_common', 'sqlvariantge' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.= ( + LEFTARG = sys.SQL_VARIANT, + RIGHTARG = sys.SQL_VARIANT, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = sys.sqlvarianteq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR sys.<> ( + LEFTARG = sys.SQL_VARIANT, + RIGHTARG = sys.SQL_VARIANT, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = sys.sqlvariantne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR sys.< ( + LEFTARG = sys.SQL_VARIANT, + RIGHTARG = sys.SQL_VARIANT, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = sys.sqlvariantlt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.<= ( + LEFTARG = sys.SQL_VARIANT, + RIGHTARG = sys.SQL_VARIANT, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = sys.sqlvariantle, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.> ( + LEFTARG = sys.SQL_VARIANT, + RIGHTARG = sys.SQL_VARIANT, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = sys.sqlvariantgt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.>= ( + LEFTARG = sys.SQL_VARIANT, + RIGHTARG = sys.SQL_VARIANT, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = sys.sqlvariantge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE FUNCTION sqlvariant_cmp(sys.SQL_VARIANT, sys.SQL_VARIANT) +RETURNS INT4 +AS 'babelfishpg_common', 'sqlvariant_cmp' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sqlvariant_hash(sys.SQL_VARIANT) +RETURNS INT4 +AS 'babelfishpg_common', 'sqlvariant_hash' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR CLASS sys.sqlvariant_ops +DEFAULT FOR TYPE sys.SQL_VARIANT USING btree AS + OPERATOR 1 < (sys.SQL_VARIANT, sys.SQL_VARIANT), + OPERATOR 2 <= (sys.SQL_VARIANT, sys.SQL_VARIANT), + OPERATOR 3 = (sys.SQL_VARIANT, sys.SQL_VARIANT), + OPERATOR 4 >= (sys.SQL_VARIANT, sys.SQL_VARIANT), + OPERATOR 5 > (sys.SQL_VARIANT, sys.SQL_VARIANT), + FUNCTION 1 sqlvariant_cmp(sys.SQL_VARIANT, sys.SQL_VARIANT); + +CREATE OPERATOR CLASS sys.sqlvariant_ops +DEFAULT FOR TYPE sys.SQL_VARIANT USING hash AS + OPERATOR 1 = (sys.SQL_VARIANT, sys.SQL_VARIANT), + FUNCTION 1 sqlvariant_hash(sys.SQL_VARIANT); diff --git a/contrib/babelfishpg_common/sql/string_operators.sql b/contrib/babelfishpg_common/sql/string_operators.sql new file mode 100644 index 00000000000..7d2b9a79a86 --- /dev/null +++ b/contrib/babelfishpg_common/sql/string_operators.sql @@ -0,0 +1,67 @@ +-- 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 VOLATILE; + +-- Support strings for + operator. +CREATE OPERATOR sys.+ ( + LEFTARG = text, + RIGHTARG = text, + FUNCTION = sys.babelfish_concat_wrapper +); + +create or replace function sys.CHAR(x in int)returns char +AS +$body$ +BEGIN +/*************************************************************** +EXTENSION PACK function CHAR(x) +***************************************************************/ + if x between 1 and 255 then + return chr(x); + else + return null; + end if; +END; +$body$ +language plpgsql; + +CREATE OR REPLACE FUNCTION sys.nchar(IN x INTEGER) RETURNS sys.nvarchar +AS +$body$ +BEGIN + --- 1114111 is 0x10FFFF - max value permitted as specified by documentation + if x between 1 and 1114111 then + return(select chr(x))::sys.nvarchar; + else + return null; + end if; +END; +$body$ +LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.nchar(IN x varbinary) RETURNS sys.nvarchar +AS +$body$ +BEGIN + --- 1114111 is 0x10FFFF - max value permitted as specified by documentation + if x::integer between 1 and 1114111 then + return(select chr(x::integer))::sys.nvarchar; + else + return null; + end if; +END; +$body$ +LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE; diff --git a/contrib/babelfishpg_common/sql/strings.sql b/contrib/babelfishpg_common/sql/strings.sql new file mode 100644 index 00000000000..2f98a63bbf7 --- /dev/null +++ b/contrib/babelfishpg_common/sql/strings.sql @@ -0,0 +1,2 @@ +CREATE DOMAIN sys.NTEXT AS TEXT; +CREATE DOMAIN sys.SYSNAME AS sys.VARCHAR(128); diff --git a/contrib/babelfishpg_common/sql/uniqueidentifier.sql b/contrib/babelfishpg_common/sql/uniqueidentifier.sql new file mode 100644 index 00000000000..8c9ea554629 --- /dev/null +++ b/contrib/babelfishpg_common/sql/uniqueidentifier.sql @@ -0,0 +1,214 @@ +CREATE TYPE sys.UNIQUEIDENTIFIER; + +CREATE OR REPLACE FUNCTION sys.uniqueidentifierin(cstring) +RETURNS sys.UNIQUEIDENTIFIER +AS 'babelfishpg_common', 'uniqueidentifier_in' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.uniqueidentifierout(sys.UNIQUEIDENTIFIER) +RETURNS cstring +AS 'babelfishpg_common', 'uniqueidentifier_out' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.uniqueidentifierrecv(internal) +RETURNS sys.UNIQUEIDENTIFIER +AS 'uuid_recv' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.uniqueidentifiersend(sys.UNIQUEIDENTIFIER) +RETURNS bytea +AS 'uuid_send' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE TYPE sys.UNIQUEIDENTIFIER ( + INPUT = sys.uniqueidentifierin, + OUTPUT = sys.uniqueidentifierout, + RECEIVE = sys.uniqueidentifierrecv, + SEND = sys.uniqueidentifiersend, + INTERNALLENGTH = 16, + ALIGNMENT = 'int4', + STORAGE = 'plain', + CATEGORY = 'U', + PREFERRED = false, + COLLATABLE = false +); + +CREATE OR REPLACE FUNCTION sys.newid() +RETURNS sys.UNIQUEIDENTIFIER +AS 'uuid-ossp', 'uuid_generate_v4' -- uuid-ossp was added as dependency +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +/* + * in tsql, NEWSEQUENTIALID() produces a new unique value + * greater than a sequence of previous values. Since PG doesn't + * have this capability, we will reuse the NEWID() functionality and be + * aware of the functional shortcoming + */ +CREATE OR REPLACE FUNCTION sys.NEWSEQUENTIALID() +RETURNS sys.UNIQUEIDENTIFIER +AS 'uuid-ossp', 'uuid_generate_v4' +LANGUAGE C VOLATILE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.uniqueidentifiereq(sys.UNIQUEIDENTIFIER, sys.UNIQUEIDENTIFIER) +RETURNS bool +AS 'uuid_eq' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.uniqueidentifierne(sys.UNIQUEIDENTIFIER, sys.UNIQUEIDENTIFIER) +RETURNS bool +AS 'uuid_ne' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.uniqueidentifierlt(sys.UNIQUEIDENTIFIER, sys.UNIQUEIDENTIFIER) +RETURNS bool +AS 'uuid_lt' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.uniqueidentifierle(sys.UNIQUEIDENTIFIER, sys.UNIQUEIDENTIFIER) +RETURNS bool +AS 'uuid_le' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.uniqueidentifiergt(sys.UNIQUEIDENTIFIER, sys.UNIQUEIDENTIFIER) +RETURNS bool +AS 'uuid_gt' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.uniqueidentifierge(sys.UNIQUEIDENTIFIER, sys.UNIQUEIDENTIFIER) +RETURNS bool +AS 'uuid_ge' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.= ( + LEFTARG = sys.UNIQUEIDENTIFIER, + RIGHTARG = sys.UNIQUEIDENTIFIER, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = sys.uniqueidentifiereq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR sys.<> ( + LEFTARG = sys.UNIQUEIDENTIFIER, + RIGHTARG = sys.UNIQUEIDENTIFIER, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = sys.uniqueidentifierne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR sys.< ( + LEFTARG = sys.UNIQUEIDENTIFIER, + RIGHTARG = sys.UNIQUEIDENTIFIER, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = sys.uniqueidentifierlt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.<= ( + LEFTARG = sys.UNIQUEIDENTIFIER, + RIGHTARG = sys.UNIQUEIDENTIFIER, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = sys.uniqueidentifierle, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR sys.> ( + LEFTARG = sys.UNIQUEIDENTIFIER, + RIGHTARG = sys.UNIQUEIDENTIFIER, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = sys.uniqueidentifiergt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR sys.>= ( + LEFTARG = sys.UNIQUEIDENTIFIER, + RIGHTARG = sys.UNIQUEIDENTIFIER, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = sys.uniqueidentifierge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE FUNCTION uniqueidentifier_cmp(sys.UNIQUEIDENTIFIER, sys.UNIQUEIDENTIFIER) +RETURNS INT4 +AS 'uuid_cmp' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION uniqueidentifier_hash(sys.UNIQUEIDENTIFIER) +RETURNS INT4 +AS 'uuid_hash' +LANGUAGE internal IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR CLASS sys.uniqueidentifier_ops +DEFAULT FOR TYPE sys.UNIQUEIDENTIFIER USING btree AS + OPERATOR 1 < (sys.UNIQUEIDENTIFIER, sys.UNIQUEIDENTIFIER), + OPERATOR 2 <= (sys.UNIQUEIDENTIFIER, sys.UNIQUEIDENTIFIER), + OPERATOR 3 = (sys.UNIQUEIDENTIFIER, sys.UNIQUEIDENTIFIER), + OPERATOR 4 >= (sys.UNIQUEIDENTIFIER, sys.UNIQUEIDENTIFIER), + OPERATOR 5 > (sys.UNIQUEIDENTIFIER, sys.UNIQUEIDENTIFIER), + FUNCTION 1 uniqueidentifier_cmp(sys.UNIQUEIDENTIFIER, sys.UNIQUEIDENTIFIER); + +CREATE OPERATOR CLASS sys.uniqueidentifier_ops +DEFAULT FOR TYPE sys.UNIQUEIDENTIFIER USING hash AS + OPERATOR 1 = (sys.UNIQUEIDENTIFIER, sys.UNIQUEIDENTIFIER), + FUNCTION 1 uniqueidentifier_hash(sys.UNIQUEIDENTIFIER); + +CREATE FUNCTION sys.varchar2uniqueidentifier(pg_catalog.VARCHAR, integer, boolean) +RETURNS sys.UNIQUEIDENTIFIER +AS 'babelfishpg_common', 'varchar2uniqueidentifier' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (pg_catalog.VARCHAR as sys.UNIQUEIDENTIFIER) +WITH FUNCTION sys.varchar2uniqueidentifier(pg_catalog.VARCHAR, integer, boolean) AS ASSIGNMENT; + +CREATE FUNCTION sys.varchar2uniqueidentifier(sys.VARCHAR, integer, boolean) +RETURNS sys.UNIQUEIDENTIFIER +AS 'babelfishpg_common', 'varchar2uniqueidentifier' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.VARCHAR as sys.UNIQUEIDENTIFIER) +WITH FUNCTION sys.varchar2uniqueidentifier(sys.VARCHAR, integer, boolean) AS ASSIGNMENT; + + +CREATE FUNCTION sys.varbinary2uniqueidentifier(sys.bbf_varbinary, integer, boolean) +RETURNS sys.UNIQUEIDENTIFIER +AS 'babelfishpg_common', 'varbinary2uniqueidentifier' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.bbf_varbinary as sys.UNIQUEIDENTIFIER) +WITH FUNCTION sys.varbinary2uniqueidentifier(sys.bbf_varbinary, integer, boolean) AS ASSIGNMENT; + +CREATE FUNCTION sys.binary2uniqueidentifier(sys.bbf_binary, integer, boolean) +RETURNS sys.UNIQUEIDENTIFIER +AS 'babelfishpg_common', 'varbinary2uniqueidentifier' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.bbf_binary as sys.UNIQUEIDENTIFIER) +WITH FUNCTION sys.binary2uniqueidentifier(sys.bbf_binary, integer, boolean) AS ASSIGNMENT; + +CREATE FUNCTION sys.uniqueidentifier2varbinary(sys.UNIQUEIDENTIFIER, integer, boolean) +RETURNS sys.bbf_varbinary +AS 'babelfishpg_common', 'uniqueidentifier2varbinary' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.UNIQUEIDENTIFIER as sys.bbf_varbinary) +WITH FUNCTION sys.uniqueidentifier2varbinary(sys.UNIQUEIDENTIFIER, integer, boolean) AS IMPLICIT; + +CREATE FUNCTION sys.uniqueidentifier2binary(sys.UNIQUEIDENTIFIER, integer, boolean) +RETURNS sys.bbf_binary +AS 'babelfishpg_common', 'uniqueidentifier2binary' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.UNIQUEIDENTIFIER as sys.bbf_binary) +WITH FUNCTION sys.uniqueidentifier2binary(sys.UNIQUEIDENTIFIER, integer, boolean) AS IMPLICIT; diff --git a/contrib/babelfishpg_common/sql/upgrades/Release.md b/contrib/babelfishpg_common/sql/upgrades/Release.md new file mode 100644 index 00000000000..13710c9d2b4 --- /dev/null +++ b/contrib/babelfishpg_common/sql/upgrades/Release.md @@ -0,0 +1 @@ +Upgrade script files, i.e babelfishpg_common--1.0.0--1.1.0.sql, etc diff --git a/contrib/babelfishpg_common/sql/upgrades/babelfishpg_common--1.0.0--1.1.0.sql b/contrib/babelfishpg_common/sql/upgrades/babelfishpg_common--1.0.0--1.1.0.sql new file mode 100644 index 00000000000..0e23b3124cd --- /dev/null +++ b/contrib/babelfishpg_common/sql/upgrades/babelfishpg_common--1.0.0--1.1.0.sql @@ -0,0 +1,338 @@ +-- complain if script is sourced in psql, rather than via ALTER EXTENSION +\echo Use "ALTER EXTENSION ""babelfishpg_common"" UPDATE TO '1.1.0'" to load this file. \quit + +DROP OPERATOR FAMILY IF EXISTS sys.fixeddecimal_ops USING btree; +DROP OPERATOR FAMILY IF EXISTS sys.fixeddecimal_ops USING hash; + +CREATE OPERATOR FAMILY sys.fixeddecimal_ops USING btree; +CREATE OPERATOR FAMILY sys.fixeddecimal_ops USING hash; + +-- drop fixeddecimal_ops and re-create it in operator family fixeddecimal_ops +DROP OPERATOR CLASS IF EXISTS sys.fixeddecimal_ops USING btree; +DROP OPERATOR CLASS IF EXISTS sys.fixeddecimal_ops USING hash; + +CREATE OPERATOR CLASS sys.fixeddecimal_ops +DEFAULT FOR TYPE sys.FIXEDDECIMAL USING btree FAMILY sys.fixeddecimal_ops AS + OPERATOR 1 sys.< (sys.FIXEDDECIMAL, sys.FIXEDDECIMAL), + OPERATOR 2 sys.<= (sys.FIXEDDECIMAL, sys.FIXEDDECIMAL), + OPERATOR 3 sys.= (sys.FIXEDDECIMAL, sys.FIXEDDECIMAL), + OPERATOR 4 sys.>= (sys.FIXEDDECIMAL, sys.FIXEDDECIMAL), + OPERATOR 5 sys.> (sys.FIXEDDECIMAL, sys.FIXEDDECIMAL), + FUNCTION 1 sys.fixeddecimal_cmp(sys.FIXEDDECIMAL, sys.FIXEDDECIMAL); + +CREATE OPERATOR CLASS sys.fixeddecimal_ops +DEFAULT FOR TYPE sys.FIXEDDECIMAL USING hash FAMILY sys.fixeddecimal_ops AS + OPERATOR 1 sys.= (sys.FIXEDDECIMAL, sys.FIXEDDECIMAL), + FUNCTION 1 sys.fixeddecimal_hash(sys.FIXEDDECIMAL); + + +-- drop fixeddecimal_numeric_ops and add corresponding operators to operator family fixeddecimal_ops +DROP OPERATOR CLASS IF EXISTS sys.fixeddecimal_numeric_ops USING btree; +DROP OPERATOR CLASS IF EXISTS sys.fixeddecimal_numeric_ops USING hash; + +ALTER OPERATOR FAMILY sys.fixeddecimal_ops USING btree ADD + OPERATOR 1 sys.< (sys.FIXEDDECIMAL, NUMERIC), + OPERATOR 2 sys.<= (sys.FIXEDDECIMAL, NUMERIC), + OPERATOR 3 sys.= (sys.FIXEDDECIMAL, NUMERIC), + OPERATOR 4 sys.>= (sys.FIXEDDECIMAL, NUMERIC), + OPERATOR 5 sys.> (sys.FIXEDDECIMAL, NUMERIC), + FUNCTION 1 sys.fixeddecimal_numeric_cmp(sys.FIXEDDECIMAL, NUMERIC); + +ALTER OPERATOR FAMILY sys.fixeddecimal_ops USING hash ADD + OPERATOR 1 sys.= (sys.FIXEDDECIMAL, NUMERIC); + + +-- drop numeric_fixeddecimal_ops and add corresponding operators to operator family fixeddecimal_ops +DROP OPERATOR CLASS IF EXISTS sys.numeric_fixeddecimal_ops USING btree; +DROP OPERATOR CLASS IF EXISTS sys.numeric_fixeddecimal_ops USING hash; + +ALTER OPERATOR FAMILY sys.fixeddecimal_ops USING btree ADD + OPERATOR 1 sys.< (NUMERIC, sys.FIXEDDECIMAL) FOR SEARCH, + OPERATOR 2 sys.<= (NUMERIC, sys.FIXEDDECIMAL) FOR SEARCH, + OPERATOR 3 sys.= (NUMERIC, sys.FIXEDDECIMAL) FOR SEARCH, + OPERATOR 4 sys.>= (NUMERIC, sys.FIXEDDECIMAL) FOR SEARCH, + OPERATOR 5 sys.> (NUMERIC, sys.FIXEDDECIMAL) FOR SEARCH, + FUNCTION 1 sys.numeric_fixeddecimal_cmp(NUMERIC, sys.FIXEDDECIMAL); + +ALTER OPERATOR FAMILY sys.fixeddecimal_ops USING hash ADD + OPERATOR 1 sys.= (NUMERIC, sys.FIXEDDECIMAL); + + +-- drop fixeddecimal_int8_ops and add corresponding operators to operator family fixeddecimal_ops +DROP OPERATOR CLASS IF EXISTS sys.fixeddecimal_int8_ops USING btree; +DROP OPERATOR CLASS IF EXISTS sys.fixeddecimal_int8_ops USING hash; + +ALTER OPERATOR FAMILY sys.fixeddecimal_ops USING btree ADD + OPERATOR 1 sys.< (sys.FIXEDDECIMAL, INT8), + OPERATOR 2 sys.<= (sys.FIXEDDECIMAL, INT8), + OPERATOR 3 sys.= (sys.FIXEDDECIMAL, INT8), + OPERATOR 4 sys.>= (sys.FIXEDDECIMAL, INT8), + OPERATOR 5 sys.> (sys.FIXEDDECIMAL, INT8), + FUNCTION 1 sys.fixeddecimal_int8_cmp(sys.FIXEDDECIMAL, INT8); + +ALTER OPERATOR FAMILY sys.fixeddecimal_ops USING hash ADD + OPERATOR 1 sys.= (sys.FIXEDDECIMAL, INT8); + + +-- drop int8_fixeddecimal_ops and add corresponding operators to operator family fixeddecimal_ops +DROP OPERATOR CLASS IF EXISTS sys.int8_fixeddecimal_ops USING btree; +DROP OPERATOR CLASS IF EXISTS sys.int8_fixeddecimal_ops USING hash; + +ALTER OPERATOR FAMILY sys.fixeddecimal_ops USING btree ADD + OPERATOR 1 sys.< (INT8, sys.FIXEDDECIMAL), + OPERATOR 2 sys.<= (INT8, sys.FIXEDDECIMAL), + OPERATOR 3 sys.= (INT8, sys.FIXEDDECIMAL), + OPERATOR 4 sys.>= (INT8, sys.FIXEDDECIMAL), + OPERATOR 5 sys.> (INT8, sys.FIXEDDECIMAL), + FUNCTION 1 sys.int8_fixeddecimal_cmp(INT8, sys.FIXEDDECIMAL); + +ALTER OPERATOR FAMILY sys.fixeddecimal_ops USING hash ADD + OPERATOR 1 sys.= (INT8, sys.FIXEDDECIMAL); + + +-- drop fixeddecimal_int4_ops and add corresponding operators to operator family fixeddecimal_ops +DROP OPERATOR CLASS IF EXISTS sys.fixeddecimal_int4_ops USING btree; +DROP OPERATOR CLASS IF EXISTS sys.fixeddecimal_int4_ops USING hash; + +ALTER OPERATOR FAMILY sys.fixeddecimal_ops USING btree ADD + OPERATOR 1 sys.< (sys.FIXEDDECIMAL, INT4), + OPERATOR 2 sys.<= (sys.FIXEDDECIMAL, INT4), + OPERATOR 3 sys.= (sys.FIXEDDECIMAL, INT4), + OPERATOR 4 sys.>= (sys.FIXEDDECIMAL, INT4), + OPERATOR 5 sys.> (sys.FIXEDDECIMAL, INT4), + FUNCTION 1 sys.fixeddecimal_int4_cmp(sys.FIXEDDECIMAL, INT4); + +ALTER OPERATOR FAMILY sys.fixeddecimal_ops USING hash ADD + OPERATOR 1 sys.= (sys.FIXEDDECIMAL, INT4); + + +-- drop int4_fixeddecimal_ops and add corresponding operators to operator family fixeddecimal_ops +DROP OPERATOR CLASS IF EXISTS sys.int4_fixeddecimal_ops USING btree; +DROP OPERATOR CLASS IF EXISTS sys.int4_fixeddecimal_ops USING hash; + +ALTER OPERATOR FAMILY sys.fixeddecimal_ops USING btree ADD + OPERATOR 1 sys.< (INT4, sys.FIXEDDECIMAL), + OPERATOR 2 sys.<= (INT4, sys.FIXEDDECIMAL), + OPERATOR 3 sys.= (INT4, sys.FIXEDDECIMAL), + OPERATOR 4 sys.>= (INT4, sys.FIXEDDECIMAL), + OPERATOR 5 sys.> (INT4, sys.FIXEDDECIMAL), + FUNCTION 1 sys.int4_fixeddecimal_cmp(INT4, sys.FIXEDDECIMAL); + +ALTER OPERATOR FAMILY sys.fixeddecimal_ops USING hash ADD + OPERATOR 1 sys.= (INT4, sys.FIXEDDECIMAL); + + +-- drop fixeddecimal_int2_ops and add corresponding operators to operator family fixeddecimal_ops +DROP OPERATOR CLASS IF EXISTS sys.fixeddecimal_int2_ops USING btree; +DROP OPERATOR CLASS IF EXISTS sys.fixeddecimal_int2_ops USING hash; + +ALTER OPERATOR FAMILY sys.fixeddecimal_ops USING btree ADD + OPERATOR 1 sys.< (sys.FIXEDDECIMAL, INT2), + OPERATOR 2 sys.<= (sys.FIXEDDECIMAL, INT2), + OPERATOR 3 sys.= (sys.FIXEDDECIMAL, INT2), + OPERATOR 4 sys.>= (sys.FIXEDDECIMAL, INT2), + OPERATOR 5 sys.> (sys.FIXEDDECIMAL, INT2), + FUNCTION 1 sys.fixeddecimal_int2_cmp(sys.FIXEDDECIMAL, INT2); + +ALTER OPERATOR FAMILY sys.fixeddecimal_ops USING hash ADD + OPERATOR 1 sys.= (sys.FIXEDDECIMAL, INT2); + + +-- drop int2_fixeddecimal_ops and add corresponding operators to operator family fixeddecimal_ops +DROP OPERATOR CLASS IF EXISTS sys.int2_fixeddecimal_ops USING btree; +DROP OPERATOR CLASS IF EXISTS sys.int2_fixeddecimal_ops USING hash; + +ALTER OPERATOR FAMILY sys.fixeddecimal_ops USING btree ADD + OPERATOR 1 sys.< (INT2, sys.FIXEDDECIMAL), + OPERATOR 2 sys.<= (INT2, sys.FIXEDDECIMAL), + OPERATOR 3 sys.= (INT2, sys.FIXEDDECIMAL), + OPERATOR 4 sys.>= (INT2, sys.FIXEDDECIMAL), + OPERATOR 5 sys.> (INT2, sys.FIXEDDECIMAL), + FUNCTION 1 sys.int2_fixeddecimal_cmp(INT2, sys.FIXEDDECIMAL); + +ALTER OPERATOR FAMILY sys.fixeddecimal_ops USING hash ADD + OPERATOR 1 sys.= (INT2, sys.FIXEDDECIMAL); + + +-- add combination of (int8/int4/int2/numeric) to fixeddecimal_ops to make it complete +ALTER OPERATOR FAMILY sys.fixeddecimal_ops USING btree ADD + -- INT8 + OPERATOR 1 < (INT8, INT8), + OPERATOR 2 <= (INT8, INT8), + OPERATOR 3 = (INT8, INT8), + OPERATOR 4 >= (INT8, INT8), + OPERATOR 5 > (INT8, INT8), + FUNCTION 1 btint8cmp(INT8, INT8), + + OPERATOR 1 < (INT8, INT4), + OPERATOR 2 <= (INT8, INT4), + OPERATOR 3 = (INT8, INT4), + OPERATOR 4 >= (INT8, INT4), + OPERATOR 5 > (INT8, INT4), + FUNCTION 1 btint84cmp(INT8, INT4), + + OPERATOR 1 < (INT8, INT2), + OPERATOR 2 <= (INT8, INT2), + OPERATOR 3 = (INT8, INT2), + OPERATOR 4 >= (INT8, INT2), + OPERATOR 5 > (INT8, INT2), + FUNCTION 1 btint82cmp(INT8, INT2), + + -- INT4 + OPERATOR 1 < (INT4, INT8), + OPERATOR 2 <= (INT4, INT8), + OPERATOR 3 = (INT4, INT8), + OPERATOR 4 >= (INT4, INT8), + OPERATOR 5 > (INT4, INT8), + FUNCTION 1 btint48cmp(INT4, INT8), + + OPERATOR 1 < (INT4, INT4), + OPERATOR 2 <= (INT4, INT4), + OPERATOR 3 = (INT4, INT4), + OPERATOR 4 >= (INT4, INT4), + OPERATOR 5 > (INT4, INT4), + FUNCTION 1 btint4cmp(INT4, INT4), + + OPERATOR 1 < (INT4, INT2), + OPERATOR 2 <= (INT4, INT2), + OPERATOR 3 = (INT4, INT2), + OPERATOR 4 >= (INT4, INT2), + OPERATOR 5 > (INT4, INT2), + FUNCTION 1 btint42cmp(INT4, INT2), + + -- INT2 + OPERATOR 1 < (INT2, INT8), + OPERATOR 2 <= (INT2, INT8), + OPERATOR 3 = (INT2, INT8), + OPERATOR 4 >= (INT2, INT8), + OPERATOR 5 > (INT2, INT8), + FUNCTION 1 btint28cmp(INT2, INT8), + + OPERATOR 1 < (INT2, INT4), + OPERATOR 2 <= (INT2, INT4), + OPERATOR 3 = (INT2, INT4), + OPERATOR 4 >= (INT2, INT4), + OPERATOR 5 > (INT2, INT4), + FUNCTION 1 btint24cmp(INT2, INT4), + + OPERATOR 1 < (INT2, INT2), + OPERATOR 2 <= (INT2, INT2), + OPERATOR 3 = (INT2, INT2), + OPERATOR 4 >= (INT2, INT2), + OPERATOR 5 > (INT2, INT2), + FUNCTION 1 btint2cmp(INT2, INT2), + + -- numeric + OPERATOR 1 < (NUMERIC, NUMERIC), + OPERATOR 2 <= (NUMERIC, NUMERIC), + OPERATOR 3 = (NUMERIC, NUMERIC), + OPERATOR 4 >= (NUMERIC, NUMERIC), + OPERATOR 5 > (NUMERIC, NUMERIC), + FUNCTION 1 numeric_cmp(NUMERIC, NUMERIC); + + +ALTER OPERATOR FAMILY sys.fixeddecimal_ops USING hash ADD + OPERATOR 1 = (INT8, INT8), + OPERATOR 1 = (INT8, INT4), + OPERATOR 1 = (INT8, INT2), + OPERATOR 1 = (INT4, INT8), + OPERATOR 1 = (INT4, INT4), + OPERATOR 1 = (INT4, INT2), + OPERATOR 1 = (INT2, INT8), + OPERATOR 1 = (INT2, INT4), + OPERATOR 1 = (INT2, INT2), + OPERATOR 1 = (NUMERIC, NUMERIC), + FUNCTION 1 hashint8(INT8), + FUNCTION 1 hashint4(INT4), + FUNCTION 1 hashint2(INT2), + FUNCTION 1 hash_numeric(NUMERIC); + + +-- Any casting from (var)binary to float4 and float8 is not allowed. drop CAST +DROP CAST IF EXISTS (sys.BBF_BINARY as REAL); +DROP CAST IF EXISTS (sys.BBF_BINARY as DOUBLE PRECISION); +DROP CAST IF EXISTS (sys.BBF_VARBINARY as REAL); +DROP CAST IF EXISTS (sys.BBF_VARBINARY as DOUBLE PRECISION); + +CREATE CAST (sys.VARCHAR as sys.BPCHAR) +WITHOUT FUNCTION AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.bpchar2int2(sys.BPCHAR) +RETURNS INT2 +AS 'babelfishpg_common', 'bpchar2int2' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BPCHAR AS INT2) +WITH FUNCTION sys.bpchar2int2(sys.BPCHAR) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.bpchar2int4(sys.BPCHAR) +RETURNS INT4 +AS 'babelfishpg_common', 'bpchar2int4' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BPCHAR AS INT4) +WITH FUNCTION sys.bpchar2int4(sys.BPCHAR) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.bpchar2int8(sys.BPCHAR) +RETURNS INT8 +AS 'babelfishpg_common', 'bpchar2int8' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BPCHAR AS INT8) +WITH FUNCTION sys.bpchar2int8(sys.BPCHAR) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.bpchar2float4(sys.BPCHAR) +RETURNS FLOAT4 +AS 'babelfishpg_common', 'bpchar2float4' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BPCHAR AS FLOAT4) +WITH FUNCTION sys.bpchar2float4(sys.BPCHAR) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.bpchar2float8(sys.BPCHAR) +RETURNS FLOAT8 +AS 'babelfishpg_common', 'bpchar2float8' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BPCHAR AS FLOAT8) +WITH FUNCTION sys.bpchar2float8(sys.BPCHAR) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.varchar2int2(sys.VARCHAR) +RETURNS INT2 +AS 'babelfishpg_common', 'varchar2int2' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.VARCHAR AS INT2) +WITH FUNCTION sys.varchar2int2(sys.VARCHAR) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.varchar2int4(sys.VARCHAR) +RETURNS INT4 +AS 'babelfishpg_common', 'varchar2int4' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.VARCHAR AS INT4) +WITH FUNCTION sys.varchar2int4(sys.VARCHAR) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.varchar2int8(sys.VARCHAR) +RETURNS INT8 +AS 'babelfishpg_common', 'varchar2int8' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.VARCHAR AS INT8) +WITH FUNCTION sys.varchar2int8(sys.VARCHAR) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.varchar2float4(sys.VARCHAR) +RETURNS FLOAT4 +AS 'babelfishpg_common', 'varchar2float4' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.VARCHAR AS FLOAT4) +WITH FUNCTION sys.varchar2float4(sys.VARCHAR) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.varchar2float8(sys.VARCHAR) +RETURNS FLOAT8 +AS 'babelfishpg_common', 'varchar2float8' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.VARCHAR AS FLOAT8) +WITH FUNCTION sys.varchar2float8(sys.VARCHAR) AS IMPLICIT; \ No newline at end of file diff --git a/contrib/babelfishpg_common/sql/utils.sql b/contrib/babelfishpg_common/sql/utils.sql new file mode 100644 index 00000000000..8f9e1f8c8b9 --- /dev/null +++ b/contrib/babelfishpg_common/sql/utils.sql @@ -0,0 +1,16 @@ +CREATE OR REPLACE PROCEDURE sys.babel_type_initializer() +LANGUAGE C +AS 'babelfishpg_common', 'init_tcode_trans_tab'; +CALL sys.babel_type_initializer(); +DROP PROCEDURE sys.babel_type_initializer(); + +CREATE OR REPLACE FUNCTION sys.babelfish_typecode_list() +RETURNS table ( + oid int, + pg_namespace text, + pg_typname text, + tsql_typname text, + type_family_priority smallint, + priority smallint, + sql_variant_hdr_size smallint +) AS 'babelfishpg_common', 'typecode_list' LANGUAGE C; diff --git a/contrib/babelfishpg_common/sql/varbinary.sql b/contrib/babelfishpg_common/sql/varbinary.sql new file mode 100644 index 00000000000..bdf6862ba44 --- /dev/null +++ b/contrib/babelfishpg_common/sql/varbinary.sql @@ -0,0 +1,278 @@ +-- VARBINARY +CREATE TYPE sys.BBF_VARBINARY; + +CREATE OR REPLACE FUNCTION sys.varbinaryin(cstring, oid, integer) +RETURNS sys.BBF_VARBINARY +AS 'babelfishpg_common', 'varbinaryin' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.varbinaryout(sys.BBF_VARBINARY) +RETURNS cstring +AS 'babelfishpg_common', 'varbinaryout' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.varbinaryrecv(internal, oid, integer) +RETURNS sys.BBF_VARBINARY +AS 'babelfishpg_common', 'varbinaryrecv' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.varbinarysend(sys.BBF_VARBINARY) +RETURNS bytea +AS 'babelfishpg_common', 'varbinarysend' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.varbinarytypmodin(cstring[]) +RETURNS integer +AS 'babelfishpg_common', 'varbinarytypmodin' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.varbinarytypmodout(integer) +RETURNS cstring +AS 'babelfishpg_common', 'varbinarytypmodout' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE TYPE sys.BBF_VARBINARY ( + INPUT = sys.varbinaryin, + OUTPUT = sys.varbinaryout, + RECEIVE = sys.varbinaryrecv, + SEND = sys.varbinarysend, + TYPMOD_IN = sys.varbinarytypmodin, + TYPMOD_OUT = sys.varbinarytypmodout, + INTERNALLENGTH = VARIABLE, + ALIGNMENT = 'int4', + STORAGE = 'extended', + CATEGORY = 'U', + PREFERRED = false, + COLLATABLE = false +); + +CREATE OR REPLACE FUNCTION sys.varcharvarbinary(sys.VARCHAR, integer, boolean) +RETURNS sys.BBF_VARBINARY +AS 'babelfishpg_common', 'varcharvarbinary' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.VARCHAR AS sys.BBF_VARBINARY) +WITH FUNCTION sys.varcharvarbinary (sys.VARCHAR, integer, boolean) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.varcharvarbinary(pg_catalog.VARCHAR, integer, boolean) +RETURNS sys.BBF_VARBINARY +AS 'babelfishpg_common', 'varcharvarbinary' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (pg_catalog.VARCHAR AS sys.BBF_VARBINARY) +WITH FUNCTION sys.varcharvarbinary (pg_catalog.VARCHAR, integer, boolean) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.bpcharvarbinary(pg_catalog.BPCHAR, integer, boolean) +RETURNS sys.BBF_VARBINARY +AS 'babelfishpg_common', 'bpcharvarbinary' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (pg_catalog.BPCHAR AS sys.BBF_VARBINARY) +WITH FUNCTION sys.bpcharvarbinary (pg_catalog.BPCHAR, integer, boolean) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.bpcharvarbinary(sys.BPCHAR, integer, boolean) +RETURNS sys.BBF_VARBINARY +AS 'babelfishpg_common', 'bpcharvarbinary' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BPCHAR AS sys.BBF_VARBINARY) +WITH FUNCTION sys.bpcharvarbinary (sys.BPCHAR, integer, boolean) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.varbinarysysvarchar(sys.BBF_VARBINARY, integer, boolean) +RETURNS sys.VARCHAR +AS 'babelfishpg_common', 'varbinaryvarchar' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BBF_VARBINARY AS sys.VARCHAR) +WITH FUNCTION sys.varbinarysysvarchar (sys.BBF_VARBINARY, integer, boolean) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.varbinaryvarchar(sys.BBF_VARBINARY, integer, boolean) +RETURNS pg_catalog.VARCHAR +AS 'babelfishpg_common', 'varbinaryvarchar' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BBF_VARBINARY AS pg_catalog.VARCHAR) +WITH FUNCTION sys.varbinaryvarchar (sys.BBF_VARBINARY, integer, boolean) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.int2varbinary(INT2, integer, boolean) +RETURNS sys.BBF_VARBINARY +AS 'babelfishpg_common', 'int2varbinary' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (INT2 AS sys.BBF_VARBINARY) +WITH FUNCTION sys.int2varbinary (INT2, integer, boolean) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.int4varbinary(INT4, integer, boolean) +RETURNS sys.BBF_VARBINARY +AS 'babelfishpg_common', 'int4varbinary' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (INT4 AS sys.BBF_VARBINARY) +WITH FUNCTION sys.int4varbinary (INT4, integer, boolean) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.int8varbinary(INT8, integer, boolean) +RETURNS sys.BBF_VARBINARY +AS 'babelfishpg_common', 'int8varbinary' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (INT8 AS sys.BBF_VARBINARY) +WITH FUNCTION sys.int8varbinary (INT8, integer, boolean) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.float4varbinary(REAL, integer, boolean) +RETURNS sys.BBF_VARBINARY +AS 'babelfishpg_common', 'float4varbinary' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (REAL AS sys.BBF_VARBINARY) +WITH FUNCTION sys.float4varbinary (REAL, integer, boolean) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.float8varbinary(DOUBLE PRECISION, integer, boolean) +RETURNS sys.BBF_VARBINARY +AS 'babelfishpg_common', 'float8varbinary' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (DOUBLE PRECISION AS sys.BBF_VARBINARY) +WITH FUNCTION sys.float8varbinary (DOUBLE PRECISION, integer, boolean) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.varbinaryint2(sys.BBF_VARBINARY) +RETURNS INT2 +AS 'babelfishpg_common', 'varbinaryint2' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BBF_VARBINARY as INT2) +WITH FUNCTION sys.varbinaryint2 (sys.BBF_VARBINARY) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.varbinaryint4(sys.BBF_VARBINARY) +RETURNS INT4 +AS 'babelfishpg_common', 'varbinaryint4' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BBF_VARBINARY as INT4) +WITH FUNCTION sys.varbinaryint4 (sys.BBF_VARBINARY) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.varbinaryint8(sys.BBF_VARBINARY) +RETURNS INT8 +AS 'babelfishpg_common', 'varbinaryint8' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.BBF_VARBINARY as INT8) +WITH FUNCTION sys.varbinaryint8 (sys.BBF_VARBINARY) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.varbinaryfloat4(sys.BBF_VARBINARY) +RETURNS REAL +AS 'babelfishpg_common', 'varbinaryfloat4' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.varbinaryfloat8(sys.BBF_VARBINARY) +RETURNS DOUBLE PRECISION +AS 'babelfishpg_common', 'varbinaryfloat8' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +SET enable_domain_typmod = TRUE; +CREATE DOMAIN sys.VARBINARY AS sys.BBF_VARBINARY; +RESET enable_domain_typmod; + +CREATE OR REPLACE FUNCTION sys.varbinary(sys.VARBINARY, integer, boolean) +RETURNS sys.VARBINARY +AS 'babelfishpg_common', 'varbinary' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +SET client_min_messages = 'ERROR'; +CREATE CAST (sys.VARBINARY AS sys.VARBINARY) +WITH FUNCTION sys.varbinary (sys.VARBINARY, integer, BOOLEAN) AS ASSIGNMENT; +SET client_min_messages = 'WARNING'; + +-- Add support for varbinary and binary with operators +-- Support equals +CREATE FUNCTION sys.varbinary_eq(leftarg sys.bbf_varbinary, rightarg sys.bbf_varbinary) +RETURNS boolean +AS 'babelfishpg_common', 'varbinary_eq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.= ( + LEFTARG = sys.bbf_varbinary, + RIGHTARG = sys.bbf_varbinary, + FUNCTION = sys.varbinary_eq, + COMMUTATOR = = +); + +-- Support not equals +CREATE FUNCTION sys.varbinary_neq(leftarg sys.bbf_varbinary, rightarg sys.bbf_varbinary) +RETURNS boolean +AS 'babelfishpg_common', 'varbinary_neq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.<> ( + LEFTARG = sys.bbf_varbinary, + RIGHTARG = sys.bbf_varbinary, + FUNCTION = sys.varbinary_neq, + COMMUTATOR = <> +); + +-- Support greater than +CREATE FUNCTION sys.varbinary_gt(leftarg sys.bbf_varbinary, rightarg sys.bbf_varbinary) +RETURNS boolean +AS 'babelfishpg_common', 'varbinary_gt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.> ( + LEFTARG = sys.bbf_varbinary, + RIGHTARG = sys.bbf_varbinary, + FUNCTION = sys.varbinary_gt, + COMMUTATOR = < +); + +-- Support greater than equals +CREATE FUNCTION sys.varbinary_geq(leftarg sys.bbf_varbinary, rightarg sys.bbf_varbinary) +RETURNS boolean +AS 'babelfishpg_common', 'varbinary_geq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.>= ( + LEFTARG = sys.bbf_varbinary, + RIGHTARG = sys.bbf_varbinary, + FUNCTION = sys.varbinary_geq, + COMMUTATOR = <= +); + +-- Support less than +CREATE FUNCTION sys.varbinary_lt(leftarg sys.bbf_varbinary, rightarg sys.bbf_varbinary) +RETURNS boolean +AS 'babelfishpg_common', 'varbinary_lt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.< ( + LEFTARG = sys.bbf_varbinary, + RIGHTARG = sys.bbf_varbinary, + FUNCTION = sys.varbinary_lt, + COMMUTATOR = > +); + +-- Support less than equals +CREATE FUNCTION sys.varbinary_leq(leftarg sys.bbf_varbinary, rightarg sys.bbf_varbinary) +RETURNS boolean +AS 'babelfishpg_common', 'varbinary_leq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR sys.<= ( + LEFTARG = sys.bbf_varbinary, + RIGHTARG = sys.bbf_varbinary, + FUNCTION = sys.varbinary_leq, + COMMUTATOR = >= +); + +CREATE FUNCTION sys.bbf_varbinary_cmp(sys.bbf_varbinary, sys.bbf_varbinary) +RETURNS int +AS 'babelfishpg_common', 'varbinary_cmp' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + + +CREATE OPERATOR CLASS sys.bbf_varbinary_ops +DEFAULT FOR TYPE sys.bbf_varbinary USING btree AS + OPERATOR 1 < (sys.bbf_varbinary, sys.bbf_varbinary), + OPERATOR 2 <= (sys.bbf_varbinary, sys.bbf_varbinary), + OPERATOR 3 = (sys.bbf_varbinary, sys.bbf_varbinary), + OPERATOR 4 >= (sys.bbf_varbinary, sys.bbf_varbinary), + OPERATOR 5 > (sys.bbf_varbinary, sys.bbf_varbinary), + FUNCTION 1 sys.bbf_varbinary_cmp(sys.bbf_varbinary, sys.bbf_varbinary); + diff --git a/contrib/babelfishpg_common/sql/varchar.sql b/contrib/babelfishpg_common/sql/varchar.sql new file mode 100644 index 00000000000..3f767379e42 --- /dev/null +++ b/contrib/babelfishpg_common/sql/varchar.sql @@ -0,0 +1,243 @@ +CREATE TYPE sys.VARCHAR; + +-- Basic functions +CREATE OR REPLACE FUNCTION sys.varcharin(cstring) +RETURNS sys.VARCHAR +AS 'babelfishpg_common', 'varcharin' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.varcharout(sys.VARCHAR) +RETURNS cstring +AS 'varcharout' +LANGUAGE INTERNAL IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.varcharrecv(internal) +RETURNS sys.VARCHAR +AS 'babelfishpg_common', 'varcharrecv' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.varcharsend(sys.VARCHAR) +RETURNS bytea +AS 'varcharsend' +LANGUAGE INTERNAL IMMUTABLE STRICT PARALLEL SAFE; + +CREATE TYPE sys.VARCHAR ( + INPUT = sys.varcharin, + OUTPUT = sys.varcharout, + RECEIVE = sys.varcharrecv, + SEND = sys.varcharsend, + TYPMOD_IN = varchartypmodin, + TYPMOD_OUT = varchartypmodout, + CATEGORY = 'S', + COLLATABLE = True, + LIKE = pg_catalog.VARCHAR +); + +-- Basic operator functions +CREATE FUNCTION sys.varchareq(sys.VARCHAR, sys.VARCHAR) +RETURNS bool +AS 'babelfishpg_common', 'varchareq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.varcharne(sys.VARCHAR, sys.VARCHAR) +RETURNS bool +AS 'babelfishpg_common', 'varcharne' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.varcharlt(sys.VARCHAR, sys.VARCHAR) +RETURNS bool +AS 'babelfishpg_common', 'varcharlt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.varcharle(sys.VARCHAR, sys.VARCHAR) +RETURNS bool +AS 'babelfishpg_common', 'varcharle' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.varchargt(sys.VARCHAR, sys.VARCHAR) +RETURNS bool +AS 'babelfishpg_common', 'varchargt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.varcharge(sys.VARCHAR, sys.VARCHAR) +RETURNS bool +AS 'babelfishpg_common', 'varcharge' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- Basic operators +-- Note that if those operators are not in pg_catalog, we will see different behaviors depending on sql_dialect +CREATE OPERATOR pg_catalog.= ( + LEFTARG = sys.VARCHAR, + RIGHTARG = sys.VARCHAR, + COMMUTATOR = OPERATOR(pg_catalog.=), + NEGATOR = OPERATOR(pg_catalog.<>), + PROCEDURE = sys.varchareq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES, + HASHES +); + +CREATE OPERATOR pg_catalog.<> ( + LEFTARG = sys.VARCHAR, + RIGHTARG = sys.VARCHAR, + NEGATOR = OPERATOR(pg_catalog.=), + COMMUTATOR = OPERATOR(pg_catalog.<>), + PROCEDURE = sys.varcharne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR pg_catalog.< ( + LEFTARG = sys.VARCHAR, + RIGHTARG = sys.VARCHAR, + NEGATOR = OPERATOR(pg_catalog.>=), + COMMUTATOR = OPERATOR(pg_catalog.>), + PROCEDURE = sys.varcharlt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR pg_catalog.<= ( + LEFTARG = sys.VARCHAR, + RIGHTARG = sys.VARCHAR, + NEGATOR = OPERATOR(pg_catalog.>), + COMMUTATOR = OPERATOR(pg_catalog.>=), + PROCEDURE = sys.varcharle, + RESTRICT = scalarlesel, + JOIN = scalarlejoinsel +); + +CREATE OPERATOR pg_catalog.> ( + LEFTARG = sys.VARCHAR, + RIGHTARG = sys.VARCHAR, + NEGATOR = OPERATOR(pg_catalog.<=), + COMMUTATOR = OPERATOR(pg_catalog.<), + PROCEDURE = sys.varchargt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR pg_catalog.>= ( + LEFTARG = sys.VARCHAR, + RIGHTARG = sys.VARCHAR, + NEGATOR = OPERATOR(pg_catalog.<), + COMMUTATOR = OPERATOR(pg_catalog.<=), + PROCEDURE = sys.varcharge, + RESTRICT = scalargesel, + JOIN = scalargejoinsel +); + +-- Operator classes +CREATE FUNCTION sys.varcharcmp(sys.VARCHAR, sys.VARCHAR) +RETURNS INT4 +AS 'babelfishpg_common', 'varcharcmp' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sys.hashvarchar(sys.VARCHAR) +RETURNS INT4 +AS 'babelfishpg_common', 'hashvarchar' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR CLASS varchar_ops + DEFAULT FOR TYPE sys.VARCHAR USING btree AS + OPERATOR 1 pg_catalog.< (sys.VARCHAR, sys.VARCHAR), + OPERATOR 2 pg_catalog.<= (sys.VARCHAR, sys.VARCHAR), + OPERATOR 3 pg_catalog.= (sys.VARCHAR, sys.VARCHAR), + OPERATOR 4 pg_catalog.>= (sys.VARCHAR, sys.VARCHAR), + OPERATOR 5 pg_catalog.> (sys.VARCHAR, sys.VARCHAR), + FUNCTION 1 sys.varcharcmp(sys.VARCHAR, sys.VARCHAR); + +CREATE OPERATOR CLASS varchar_ops + DEFAULT FOR TYPE sys.VARCHAR USING hash AS + OPERATOR 1 pg_catalog.= (sys.VARCHAR, sys.VARCHAR), + FUNCTION 1 sys.hashvarchar(sys.VARCHAR); + +-- Typmode cast function +CREATE OR REPLACE FUNCTION sys.varchar(sys.VARCHAR, integer, boolean) +RETURNS sys.VARCHAR +AS 'babelfishpg_common', 'varchar' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- To sys.VARCHAR +CREATE CAST (sys.VARCHAR AS sys.VARCHAR) +WITH FUNCTION sys.VARCHAR (sys.VARCHAR, integer, boolean) AS IMPLICIT; + +CREATE CAST (pg_catalog.VARCHAR as sys.VARCHAR) +WITHOUT FUNCTION AS IMPLICIT; + +CREATE CAST (pg_catalog.TEXT as sys.VARCHAR) +WITHOUT FUNCTION AS IMPLICIT; + +CREATE CAST (sys.BPCHAR as sys.VARCHAR) +WITHOUT FUNCTION AS IMPLICIT; + +CREATE CAST (pg_catalog.BOOL as sys.VARCHAR) +WITH FUNCTION pg_catalog.text(pg_catalog.BOOL) AS ASSIGNMENT; + +-- From sys.VARCHAR +CREATE CAST (sys.VARCHAR AS pg_catalog.VARCHAR) +WITHOUT FUNCTION AS IMPLICIT; + +CREATE CAST (sys.VARCHAR as pg_catalog.TEXT) +WITHOUT FUNCTION AS IMPLICIT; + +CREATE CAST (sys.VARCHAR as pg_catalog.BPCHAR) +WITHOUT FUNCTION AS IMPLICIT; + +CREATE CAST (sys.VARCHAR as sys.BPCHAR) +WITHOUT FUNCTION AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.varchar2int2(sys.VARCHAR) +RETURNS INT2 +AS 'babelfishpg_common', 'varchar2int2' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.VARCHAR AS INT2) +WITH FUNCTION sys.varchar2int2(sys.VARCHAR) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.varchar2int4(sys.VARCHAR) +RETURNS INT4 +AS 'babelfishpg_common', 'varchar2int4' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.VARCHAR AS INT4) +WITH FUNCTION sys.varchar2int4(sys.VARCHAR) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.varchar2int8(sys.VARCHAR) +RETURNS INT8 +AS 'babelfishpg_common', 'varchar2int8' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.VARCHAR AS INT8) +WITH FUNCTION sys.varchar2int8(sys.VARCHAR) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.varchar2float4(sys.VARCHAR) +RETURNS FLOAT4 +AS 'babelfishpg_common', 'varchar2float4' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.VARCHAR AS FLOAT4) +WITH FUNCTION sys.varchar2float4(sys.VARCHAR) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.varchar2float8(sys.VARCHAR) +RETURNS FLOAT8 +AS 'babelfishpg_common', 'varchar2float8' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (sys.VARCHAR AS FLOAT8) +WITH FUNCTION sys.varchar2float8(sys.VARCHAR) AS IMPLICIT; + +SET enable_domain_typmod = TRUE; +CREATE DOMAIN sys.NVARCHAR AS sys.VARCHAR; +RESET enable_domain_typmod; + +CREATE OR REPLACE FUNCTION sys.nvarchar(sys.nvarchar, integer, boolean) +RETURNS sys.nvarchar +AS 'babelfishpg_common', 'varchar' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +SET client_min_messages = 'ERROR'; +CREATE CAST (sys.nvarchar AS sys.nvarchar) +WITH FUNCTION sys.nvarchar (sys.nvarchar, integer, BOOLEAN) AS ASSIGNMENT; +SET client_min_messages = 'WARNING'; diff --git a/contrib/babelfishpg_common/src/babelfishpg_common.c b/contrib/babelfishpg_common/src/babelfishpg_common.c new file mode 100644 index 00000000000..df0cca9d22d --- /dev/null +++ b/contrib/babelfishpg_common/src/babelfishpg_common.c @@ -0,0 +1,26 @@ +#include "postgres.h" + +#include "fmgr.h" +#include "instr.h" + +extern Datum init_tcode_trans_tab(PG_FUNCTION_ARGS); + +PG_MODULE_MAGIC; + +/* Module callbacks */ +void _PG_init(void); +void _PG_fini(void); + +void +_PG_init(void) +{ + FunctionCallInfo fcinfo = NULL; /* empty interface */ + + init_instr(); + init_tcode_trans_tab(fcinfo); +} + +void +_PG_fini(void) +{ +} diff --git a/contrib/babelfishpg_common/src/bit.c b/contrib/babelfishpg_common/src/bit.c new file mode 100644 index 00000000000..835c74f9f4d --- /dev/null +++ b/contrib/babelfishpg_common/src/bit.c @@ -0,0 +1,548 @@ +/*------------------------------------------------------------------------- + * + * bit.c + * Functions for the type "bit". + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include + +#include "libpq/pqformat.h" +#include "utils/builtins.h" +#include "utils/numeric.h" + +#include "instr.h" +#include "typecode.h" +#include "numeric.h" + + +PG_FUNCTION_INFO_V1(bitin); +PG_FUNCTION_INFO_V1(bitout); +PG_FUNCTION_INFO_V1(bitrecv); +PG_FUNCTION_INFO_V1(bitsend); +PG_FUNCTION_INFO_V1(int2bit); +PG_FUNCTION_INFO_V1(int4bit); +PG_FUNCTION_INFO_V1(int8bit); +PG_FUNCTION_INFO_V1(numeric_bit); +PG_FUNCTION_INFO_V1(ftobit); +PG_FUNCTION_INFO_V1(dtobit); +PG_FUNCTION_INFO_V1(bitneg); +PG_FUNCTION_INFO_V1(biteq); +PG_FUNCTION_INFO_V1(bitne); +PG_FUNCTION_INFO_V1(bitlt); +PG_FUNCTION_INFO_V1(bitle); +PG_FUNCTION_INFO_V1(bitgt); +PG_FUNCTION_INFO_V1(bitge); +PG_FUNCTION_INFO_V1(bit_cmp); +PG_FUNCTION_INFO_V1(bit2int2); +PG_FUNCTION_INFO_V1(bit2int4); +PG_FUNCTION_INFO_V1(bit2int8); +PG_FUNCTION_INFO_V1(bit2numeric); +PG_FUNCTION_INFO_V1(bit2fixeddec); + +/* Comparison between int and bit */ +PG_FUNCTION_INFO_V1(int4biteq); +PG_FUNCTION_INFO_V1(int4bitne); +PG_FUNCTION_INFO_V1(int4bitlt); +PG_FUNCTION_INFO_V1(int4bitle); +PG_FUNCTION_INFO_V1(int4bitgt); +PG_FUNCTION_INFO_V1(int4bitge); + +/* Comparison between bit and int */ +PG_FUNCTION_INFO_V1(bitint4eq); +PG_FUNCTION_INFO_V1(bitint4ne); +PG_FUNCTION_INFO_V1(bitint4lt); +PG_FUNCTION_INFO_V1(bitint4le); +PG_FUNCTION_INFO_V1(bitint4gt); +PG_FUNCTION_INFO_V1(bitint4ge); + +/* + * Try to interpret value as boolean value. Valid values are: true, + * false, TRUE, FALSE, digital string as well as unique prefixes thereof. + * If the string parses okay, return true, else false. + * If okay and result is not NULL, return the value in *result. + */ + +static bool +parse_bit_with_len(const char *value, size_t len, bool *result) +{ + switch (*value) + { + case 't': + case 'T': + if (len == 4 && pg_strncasecmp(value, "true", len) == 0) + { + if (result) + *result = true; + return true; + } + break; + case 'f': + case 'F': + if (len == 5 && pg_strncasecmp(value, "false", len) == 0) + { + if (result) + *result = false; + return true; + } + 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; + } + /* 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) + *result = false; /* suppress compiler warning */ + return false; +} + +/***************************************************************************** + * USER I/O ROUTINES * + *****************************************************************************/ + +/* + * bitin - converts "t" or "f" to 1 or 0 + * + * Check explicitly for "true/false" and TRUE/FALSE, 1/0 and any digital string + * Reject other values. + * + * In the switch statement, check the most-used possibilities first. + */ +Datum +bitin(PG_FUNCTION_ARGS) +{ + const char *in_str = PG_GETARG_CSTRING(0); + const char *str; + size_t len; + bool result; + + /* + * Skip leading and trailing whitespace + */ + str = in_str; + while (isspace((unsigned char) *str)) + str++; + + len = strlen(str); + while (len > 0 && isspace((unsigned char) str[len - 1])) + len--; + + if (parse_bit_with_len(str, len, &result)) + PG_RETURN_BOOL(result); + + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for type %s: \"%s\"", + "bit", in_str))); + + /* not reached */ + PG_RETURN_BOOL(false); +} + +/* + * bitout - converts 1 or 0 to "t" or "f" + */ +Datum +bitout(PG_FUNCTION_ARGS) +{ + bool b = PG_GETARG_BOOL(0); + char *result = (char *) palloc(2); + + result[0] = (b) ? '1' : '0'; + result[1] = '\0'; + PG_RETURN_CSTRING(result); +} + +/* + * bitrecv - converts external binary format to bit + * + * The external representation is one byte. Any nonzero value is taken + * as "true". + */ +Datum +bitrecv(PG_FUNCTION_ARGS) +{ + StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); + int ext; + + INSTR_METRIC_INC(INSTR_TSQL_BIT_RECV); + + ext = pq_getmsgbyte(buf); + PG_RETURN_BOOL((ext != 0) ? true : false); +} + +/* + * bitsend - converts bit to binary format + */ +Datum +bitsend(PG_FUNCTION_ARGS) +{ + bool arg1 = PG_GETARG_BOOL(0); + StringInfoData buf; + + INSTR_METRIC_INC(INSTR_TSQL_BIT_SEND); + + pq_begintypsend(&buf); + pq_sendbyte(&buf, arg1 ? 1 : 0); + PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); +} + +/* + * Cast functions + */ +Datum +int2bit(PG_FUNCTION_ARGS) +{ + int input = PG_GETARG_INT16(0); + bool result = input == 0 ? false : true; + + PG_RETURN_BOOL(result); +} + +Datum +int4bit(PG_FUNCTION_ARGS) +{ + int32 input = PG_GETARG_INT32(0); + bool result = input == 0 ? false : true; + + PG_RETURN_BOOL(result); +} + +Datum +int8bit(PG_FUNCTION_ARGS) +{ + int64 input = PG_GETARG_INT64(0); + bool result = input == 0 ? false : true; + + PG_RETURN_BOOL(result); +} + +/* Convert float4 to fixeddecimal */ +Datum +ftobit(PG_FUNCTION_ARGS) +{ + float4 arg = PG_GETARG_FLOAT4(0); + bool result = arg == 0 ? false : true; + + PG_RETURN_BOOL(result); +} + +/* Convert float8 to fixeddecimal */ +Datum +dtobit(PG_FUNCTION_ARGS) +{ + float8 arg = PG_GETARG_FLOAT8(0); + bool result = arg == 0 ? false : true; + + PG_RETURN_BOOL(result); +} + +Datum +numeric_bit(PG_FUNCTION_ARGS) +{ + Numeric num = PG_GETARG_NUMERIC(0); + char *tmp; + bool result = false; + int len; + int i; + + if (numeric_is_nan(num)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot convert NaN to bit"))); + + tmp = DatumGetCString(DirectFunctionCall1(numeric_out, + NumericGetDatum(num))); + + len = strlen(tmp); + for(i = 0; i < len; i++) + { + /* Skip the decimal point */ + if (tmp[i] == '.') + continue; + if (tmp[i] != '0') + { + result = true; + break; + } + } + + PG_RETURN_BOOL(result); +} + +/* Arithmetic operators on bit */ +Datum +bitneg(PG_FUNCTION_ARGS) +{ + bool arg = PG_GETARG_BOOL(0); + + PG_RETURN_BOOL(arg); +} + +Datum +biteq(PG_FUNCTION_ARGS) +{ + bool arg1 = PG_GETARG_BOOL(0); + bool arg2 = PG_GETARG_BOOL(1); + + PG_RETURN_BOOL(arg1 == arg2); +} + +Datum +bitne(PG_FUNCTION_ARGS) +{ + bool arg1 = PG_GETARG_BOOL(0); + bool arg2 = PG_GETARG_BOOL(1); + + PG_RETURN_BOOL(arg1 != arg2); +} + +Datum +bitlt(PG_FUNCTION_ARGS) +{ + bool arg1 = PG_GETARG_BOOL(0); + bool arg2 = PG_GETARG_BOOL(1); + + PG_RETURN_BOOL(arg1 < arg2); +} + +Datum +bitgt(PG_FUNCTION_ARGS) +{ + bool arg1 = PG_GETARG_BOOL(0); + bool arg2 = PG_GETARG_BOOL(1); + + PG_RETURN_BOOL(arg1 > arg2); +} + +Datum +bitle(PG_FUNCTION_ARGS) +{ + bool arg1 = PG_GETARG_BOOL(0); + bool arg2 = PG_GETARG_BOOL(1); + + PG_RETURN_BOOL(arg1 <= arg2); +} + +Datum +bitge(PG_FUNCTION_ARGS) +{ + bool arg1 = PG_GETARG_BOOL(0); + bool arg2 = PG_GETARG_BOOL(1); + + PG_RETURN_BOOL(arg1 >= arg2); +} + +Datum +bit_cmp(PG_FUNCTION_ARGS) +{ + bool arg1 = PG_GETARG_BOOL(0); + bool arg2 = PG_GETARG_BOOL(1); + + PG_RETURN_INT32((arg1 < arg2) ? -1 : ((arg1 > arg2) ? 1 : 0)); +} + +/* Comparison between int and bit */ +Datum +int4biteq(PG_FUNCTION_ARGS) +{ + int input1 = PG_GETARG_INT32(0); + bool arg1 = input1 == 0 ? false : true; + bool arg2 = PG_GETARG_BOOL(1); + + 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); + + 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); + + 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); + + 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); + + 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); + + 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; + + 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; + + 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; + + 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; + + 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; + + 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; + + PG_RETURN_BOOL(arg1 >= arg2); +} + +Datum +bit2int2(PG_FUNCTION_ARGS) +{ + bool bit = PG_GETARG_BOOL(0); + + PG_RETURN_INT16(bit ? 1 : 0); +} + +Datum +bit2int4(PG_FUNCTION_ARGS) +{ + bool bit = PG_GETARG_BOOL(0); + + PG_RETURN_INT32(bit ? 1 : 0); +} + +Datum +bit2int8(PG_FUNCTION_ARGS) +{ + bool bit = PG_GETARG_BOOL(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"); + + PG_RETURN_NUMERIC(num); +} + +Datum +bit2fixeddec(PG_FUNCTION_ARGS) +{ + bool bit = PG_GETARG_BOOL(0); + + PG_RETURN_INT64(bit ? 1*FIXEDDECIMAL_MULTIPLIER : 0); +} diff --git a/contrib/babelfishpg_common/src/coerce.c b/contrib/babelfishpg_common/src/coerce.c new file mode 100644 index 00000000000..85d33d1fe71 --- /dev/null +++ b/contrib/babelfishpg_common/src/coerce.c @@ -0,0 +1,339 @@ +/*------------------------------------------------------------------------- + * + * pltsql_coerce.c + * Datatype Coercion Utility for Babel + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "access/htup_details.h" +#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 "executor/spi.h" +#include "mb/pg_wchar.h" +#include "parser/parse_coerce.h" +#include "parser/parse_func.h" +#include "utils/builtins.h" +#include "utils/float.h" +#include "utils/guc.h" +#include "common/int.h" +#include "utils/int8.h" +#include "utils/numeric.h" +#include "utils/memutils.h" +#include "utils/lsyscache.h" +#include "utils/syscache.h" + + +#include + +/* + * Additional Casting Functions for T-SQL + * + * Some castings in T-SQL has different behavior with PG. + * (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) +{ + float8 result; + + if (arg1 >= 0) + result = floor(arg1); + else + result = -floor(-arg1); + + return result; +} + +inline static float4 ftrunc_(float4 arg1) +{ + float8 result; + + if (arg1 >= 0) + result = floor(arg1); + else + result = -floor(-arg1); + + return result; +} + +/* dtrunci8(X) = dtoi8(dtrunc(X)) */ +PG_FUNCTION_INFO_V1(dtrunci8); + +Datum +dtrunci8(PG_FUNCTION_ARGS) +{ + float8 num = PG_GETARG_FLOAT8(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. + */ + num = rint(dtrunc_(num)); + + /* Range check */ + if (unlikely(isnan(num) || !FLOAT8_FITS_IN_INT64(num))) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("integer out of range"))); + + PG_RETURN_INT64((int64) num); +} + + +/* dtrunci4(X) = dtoi4(dtrunc(X)) */ +PG_FUNCTION_INFO_V1(dtrunci4); + +Datum +dtrunci4(PG_FUNCTION_ARGS) +{ + float8 num = PG_GETARG_FLOAT8(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. + */ + num = rint(dtrunc_(num)); + + /* Range check */ + if (unlikely(isnan(num) || !FLOAT8_FITS_IN_INT32(num))) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("integer out of range"))); + + PG_RETURN_INT32((int32) num); +} + + +/* dtrunci2(X) = dtoi2(dtrunc(X)) */ +PG_FUNCTION_INFO_V1(dtrunci2); + +Datum +dtrunci2(PG_FUNCTION_ARGS) +{ + float8 num = PG_GETARG_FLOAT8(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. + */ + num = rint(dtrunc_(num)); + + /* Range check */ + if (unlikely(isnan(num) || !FLOAT8_FITS_IN_INT16(num))) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("smallint out of range"))); + + PG_RETURN_INT16((int16) num); +} + + +/* ftrunci8(X) = ftoi8(ftrunc(X)) */ +PG_FUNCTION_INFO_V1(ftrunci8); + +Datum +ftrunci8(PG_FUNCTION_ARGS) +{ + 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. + */ + num = rint(ftrunc_(num)); + + /* Range check */ + if (unlikely(isnan(num) || !FLOAT4_FITS_IN_INT64(num))) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("integer out of range"))); + + PG_RETURN_INT64((int64) num); +} + + +/* ftrunci4(X) = ftoi4(ftrunc(X)) */ +PG_FUNCTION_INFO_V1(ftrunci4); + +Datum +ftrunci4(PG_FUNCTION_ARGS) +{ + 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. + */ + num = rint(ftrunc_(num)); + + /* Range check */ + if (unlikely(isnan(num) || !FLOAT4_FITS_IN_INT32(num))) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("integer out of range"))); + + 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); + + /* + * 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. + */ + num = rint(ftrunc_(num)); + + /* Range check */ + if (unlikely(isnan(num) || !FLOAT4_FITS_IN_INT16(num))) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("integer out of range"))); + + PG_RETURN_INT16((int16) num); +} + + + +PG_FUNCTION_INFO_V1(pltsql_text_name); +PG_FUNCTION_INFO_V1(pltsql_bpchar_name); + +/* replace text_name() to handle t-sql identifier truncation */ +Datum +pltsql_text_name(PG_FUNCTION_ARGS) +{ + 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); + + /* Truncate oversize input */ + if (len >= NAMEDATALEN) + { + if (cstr_to_name_hook) /* to apply special truncation logic */ + { + 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); + } + 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); + 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); + + PG_RETURN_NAME(n); + } + + len = pg_mbcliplen(VARDATA_ANY(s), len, NAMEDATALEN - 1); + } + + /* 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); +} + +/* replace bpchar_name() to handle t-sql identifier truncation */ +Datum +pltsql_bpchar_name(PG_FUNCTION_ARGS) +{ + 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); + s_data = VARDATA_ANY(s); + + /* Truncate oversize input */ + if (len >= NAMEDATALEN) + { + if (cstr_to_name_hook) /* to apply special truncation logic */ + { + Name n; + + /* Remove trailing blanks */ + while (len > 0) + { + if (s_data[len - 1] != ' ') + break; + len--; + } + + 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); + } + 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); + 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); + + PG_RETURN_NAME(n); + } + + len = pg_mbcliplen(s_data, len, NAMEDATALEN - 1); + } + + /* Remove trailing blanks */ + while (len > 0) + { + if (s_data[len - 1] != ' ') + break; + len--; + } + + /* 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_common/src/datetime.c b/contrib/babelfishpg_common/src/datetime.c new file mode 100644 index 00000000000..e3a68147bda --- /dev/null +++ b/contrib/babelfishpg_common/src/datetime.c @@ -0,0 +1,600 @@ +/*------------------------------------------------------------------------- + * + * datetime.c + * Functions for the type "datetime". + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "fmgr.h" +#include "utils/builtins.h" +#include "utils/date.h" +#include "utils/datetime.h" +#include "utils/timestamp.h" +#include "libpq/pqformat.h" + +#include "miscadmin.h" +#include "datetime.h" + + +PG_FUNCTION_INFO_V1(datetime_in); +PG_FUNCTION_INFO_V1(datetime_out); +PG_FUNCTION_INFO_V1(datetime_recv); +PG_FUNCTION_INFO_V1(date_datetime); +PG_FUNCTION_INFO_V1(time_datetime); +PG_FUNCTION_INFO_V1(timestamp_datetime); +PG_FUNCTION_INFO_V1(timestamptz_datetime); +PG_FUNCTION_INFO_V1(datetime_varchar); +PG_FUNCTION_INFO_V1(varchar_datetime); +PG_FUNCTION_INFO_V1(datetime_char); +PG_FUNCTION_INFO_V1(char_datetime); +PG_FUNCTION_INFO_V1(datetime_pl_int4); +PG_FUNCTION_INFO_V1(int4_mi_datetime); +PG_FUNCTION_INFO_V1(int4_pl_datetime); +PG_FUNCTION_INFO_V1(datetime_mi_int4); + +PG_FUNCTION_INFO_V1(datetime_pl_float8); +PG_FUNCTION_INFO_V1(datetime_mi_float8); +PG_FUNCTION_INFO_V1(float8_pl_datetime); +PG_FUNCTION_INFO_V1(float8_mi_datetime); + + + +void CheckDatetimeRange(const Timestamp time); +void CheckDatetimePrecision(fsec_t fsec); +Datum datetime_in_str(char *str); + +Datum +datetime_in_str(char *str) +{ +#ifdef NOT_USED + Oid typelem = PG_GETARG_OID(1); +#endif + Timestamp result; + fsec_t fsec; + struct pg_tm tt, + *tm = &tt; + int tz; + int dtype; + int nf; + int dterr; + char *field[MAXDATEFIELDS]; + int ftype[MAXDATEFIELDS]; + char workbuf[MAXDATELEN + MAXDATEFIELDS]; + + 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 + if (dterr == 1) + { + tm->tm_year = 1900; + tm->tm_mon = 1; + tm->tm_mday = 1; + dterr = 0; + } + if (dterr != 0) + DateTimeParseError(dterr, str, "datetime"); + switch (dtype) + { + case DTK_DATE: + if (tm2timestamp(tm, fsec, NULL, &result) != 0) + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("datetime out of range: \"%s\"", str))); + break; + + case DTK_EPOCH: + result = SetEpochTimestamp(); + break; + + case DTK_LATE: + TIMESTAMP_NOEND(result); + break; + + case DTK_EARLY: + TIMESTAMP_NOBEGIN(result); + break; + + default: + elog(ERROR, "unexpected dtype %d while parsing datetime \"%s\"", + dtype, str); + TIMESTAMP_NOEND(result); + } + /* TODO: round datetime fsec to fixed bins (e.g. .000, .003, .007) + * see: BABEL-1081 + */ + CheckDatetimeRange(result); + CheckDatetimePrecision(fsec); + + PG_RETURN_TIMESTAMP(result); + +} + +/* datetime_in() + * Convert a string to internal form. + * Most parts of this functions is same as timestamp_in(), + * but we use a different rounding function for datetime. + */ +Datum +datetime_in(PG_FUNCTION_ARGS) +{ + char *str = PG_GETARG_CSTRING(0); + return datetime_in_str(str); +} + +/* datetime_out() + * Convert a datetime to external form. + */ +Datum +datetime_out(PG_FUNCTION_ARGS) +{ + Timestamp timestamp = PG_GETARG_TIMESTAMP(0); + char *result; + struct pg_tm tt, + *tm = &tt; + fsec_t fsec; + char buf[MAXDATELEN + 1]; + + if (TIMESTAMP_NOT_FINITE(timestamp)) + EncodeSpecialTimestamp(timestamp, buf); + else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0) + { + // round fractional seconds to datetime precision + fsec = DTROUND(fsec); + EncodeDateTime(tm, fsec, false, 0, NULL, DateStyle, buf); + } + else + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("timestamp out of range"))); + result = pstrdup(buf); + PG_RETURN_CSTRING(result); +} + +/* + * CheckDatetimeRange --- Check if timestamp is out of range for datetime + */ +void +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"))); + } +} + +/* + * CheckDatetimePrecision --- Check precision for datetime + */ +void +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"))); + } +} + +/* date_datetime() + * Convert date to datetime + */ +Datum +date_datetime(PG_FUNCTION_ARGS) +{ + DateADT dateVal = PG_GETARG_DATEADT(0); + Timestamp result; + + if (DATE_IS_NOBEGIN(dateVal)) + TIMESTAMP_NOBEGIN(result); + else if (DATE_IS_NOEND(dateVal)) + TIMESTAMP_NOEND(result); + else + result = dateVal * USECS_PER_DAY; + + CheckDatetimeRange(result); + PG_RETURN_TIMESTAMP(result); +} + +/* time_datetime() + * Convert time to datetime + */ +Datum +time_datetime(PG_FUNCTION_ARGS) +{ + TimeADT timeVal = PG_GETARG_TIMEADT(0); + Timestamp result; + + 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 datetime"))); + + PG_RETURN_TIMESTAMP(result); +} + +/* timestamp_datetime() + * Convert timestamp to datetime + */ +Datum +timestamp_datetime(PG_FUNCTION_ARGS) +{ + Timestamp result = PG_GETARG_TIMESTAMP(0); + + CheckDatetimeRange(result); + PG_RETURN_TIMESTAMP(result); +} + +/* timestamptz_datetime() + * Convert timestamptz to datetime + */ +Datum +timestamptz_datetime(PG_FUNCTION_ARGS) +{ + TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0); + Timestamp result; + + struct pg_tm tt, + *tm = &tt; + fsec_t fsec; + int tz; + + if (TIMESTAMP_NOT_FINITE(timestamp)) + result = timestamp; + else + { + if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0) + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("data out of range for datetime"))); + if (tm2timestamp(tm, fsec, NULL, &result) != 0) + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("data out of range for datetime"))); + } + CheckDatetimeRange(result); + PG_RETURN_TIMESTAMP(result); +} + +/* datetime_varchar() + * Convert a datetime to varchar. + */ +Datum +datetime_varchar(PG_FUNCTION_ARGS) +{ + Timestamp timestamp = PG_GETARG_TIMESTAMP(0); + char *s; + struct pg_tm tt, + *tm = &tt; + fsec_t fsec; + char buf[MAXDATELEN + 1]; + VarChar *result; + + if (TIMESTAMP_NOT_FINITE(timestamp)) + EncodeSpecialTimestamp(timestamp, buf); + else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0) + { + // round fractional seconds to datetime precision + fsec = DTROUND(fsec); + EncodeDateTime(tm, fsec, false, 0, NULL, DateStyle, buf); + } + else + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("timestamp out of range"))); + s = pstrdup(buf); + result = (VarChar *) cstring_to_text(s); + PG_RETURN_VARCHAR_P(result); +} + +/* + * varchar_datetime() + * Convert a VARCHAR to datetime + */ +Datum +varchar_datetime(PG_FUNCTION_ARGS) +{ + Datum txt = PG_GETARG_DATUM(0); + char *str = TextDatumGetCString(txt); + + return datetime_in_str(str); +} + +/* datetime_char() + * Convert a datetime to char. + */ +Datum +datetime_char(PG_FUNCTION_ARGS) +{ + Timestamp timestamp = PG_GETARG_TIMESTAMP(0); + char *s; + struct pg_tm tt, + *tm = &tt; + fsec_t fsec; + char buf[MAXDATELEN + 1]; + VarChar *result; + + if (TIMESTAMP_NOT_FINITE(timestamp)) + EncodeSpecialTimestamp(timestamp, buf); + else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0) + { + // round fractional seconds to datetime precision + fsec = DTROUND(fsec); + EncodeDateTime(tm, fsec, false, 0, NULL, DateStyle, buf); + } + else + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("timestamp out of range"))); + s = pstrdup(buf); + result = (BpChar *) cstring_to_text(s); + PG_RETURN_BPCHAR_P(result); +} + +/* + * char_datetime() + * Convert a CHAR type to datetime + */ +Datum +char_datetime(PG_FUNCTION_ARGS) +{ + Datum txt = PG_GETARG_DATUM(0); + char *str = TextDatumGetCString(txt); + + return datetime_in_str(str); +} + +/* + * 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; + + if (TIMESTAMP_NOT_FINITE(timestamp)) + PG_RETURN_TIMESTAMP(timestamp); + + /* make interval */ + input_interval = (Interval *) DirectFunctionCall7(make_interval, 0, 0, 0, days, 0, 0, 0); + + /* add interval */ + result = DirectFunctionCall2(timestamp_pl_interval, timestamp, PointerGetDatum(input_interval)); + + CheckDatetimeRange(result); + PG_RETURN_TIMESTAMP(result); +} + +/* + * 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 + * above to the default datetime value (1/1/1900). + * + * 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 + * result = 1/1/1900 + diff = 1899-12-31 + */ +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; + + 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); + 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 */ + result = DirectFunctionCall2(timestamp_pl_interval, default_timestamp, PointerGetDatum(result_interval)); + + CheckDatetimeRange(result); + PG_RETURN_TIMESTAMP(result); +} + +/* + * int4_pl_datetime() + * operator function for adding int plus datetime + */ +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)); +} + +/* + * datetime_mi_int4() + * operator function for subtracting datetime minus int + */ +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)); +} + + +/* + * 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, 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); + + /* make interval */ + input_interval = (Interval *) DirectFunctionCall7(make_interval, 0, 0, 0, (int32) day_whole, 0, 0, Float8GetDatum(sec_whole)); + + /* add interval */ + result = DirectFunctionCall2(timestamp_pl_interval, timestamp, PointerGetDatum(input_interval)); + + CheckDatetimeRange(result); + PG_RETURN_TIMESTAMP(result); +} + + +/* + * 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 + * 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, sec_whole; + Timestamp result; + Timestamp default_timestamp; + Timestamp timestamp_left; + 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); + + + /* inialize input int(days) as timestamp */ + 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 */ + result = DirectFunctionCall2(timestamp_pl_interval, default_timestamp, PointerGetDatum(result_interval)); + + + CheckDatetimeRange(result); + PG_RETURN_TIMESTAMP(result); +} + +/* + * float8_pl_datetime() + * operator function for adding float8 plus datetime + */ +Datum +float8_pl_datetime(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; + 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); + + /* make interval */ + input_interval = (Interval *) DirectFunctionCall7(make_interval, 0, 0, 0, (int32) day_whole, 0, 0, Float8GetDatum(sec_whole)); + + /* add interval */ + result = DirectFunctionCall2(timestamp_pl_interval, timestamp, PointerGetDatum(input_interval)); + + CheckDatetimeRange(result); + PG_RETURN_TIMESTAMP(result); +} + +/* + * datetime_mi_float8() + * operator function for subtracting datetime minus float8 + */ +Datum +datetime_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; + 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); + + /* make interval */ + input_interval = (Interval *) DirectFunctionCall7(make_interval, 0, 0, 0, (int32) day_whole, 0, 0, Float8GetDatum(sec_whole)); + + + /* subtract interval */ + result = DirectFunctionCall2(timestamp_mi_interval, timestamp, PointerGetDatum(input_interval)); + + CheckDatetimeRange(result); + PG_RETURN_TIMESTAMP(result); +} \ No newline at end of file diff --git a/contrib/babelfishpg_common/src/datetime.h b/contrib/babelfishpg_common/src/datetime.h new file mode 100644 index 00000000000..8e6cc69e5a9 --- /dev/null +++ b/contrib/babelfishpg_common/src/datetime.h @@ -0,0 +1,31 @@ +/*------------------------------------------------------------------------- + * + * datetime.h + * Definitions for the TSQL "datetime" type. + * + *------------------------------------------------------------------------- + */ +#ifndef PLTSQL_DATETIME_H +#define PLTSQL_DATETIME_H + +/* Round off to MAX_DATETIME_PRECISION decimal places. */ +#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) + * see: BABEL-1081 + */ + +/* Check precision is valid for datetime */ +#define IS_VALID_DT_PRECISION(j) (j % (int) DT_PREC_INV == 0) + +/* Datetime limits */ +/* lower bound: 1753-01-01 00:00:00.000 */ +#define MIN_DATETIME INT64CONST(-7794489600000000) +/* upper bond: 9999-12-31 23:59:29.999 */ +#define END_DATETIME INT64CONST(252455615999999000) + +/* Range-check a datetime */ +#define IS_VALID_DATETIME(t) (MIN_DATETIME <= (t) && (t) < END_DATETIME) + +#endif /* PLTSQL_DATETIME_H */ diff --git a/contrib/babelfishpg_common/src/datetime2.c b/contrib/babelfishpg_common/src/datetime2.c new file mode 100644 index 00000000000..9bd3c2150e6 --- /dev/null +++ b/contrib/babelfishpg_common/src/datetime2.c @@ -0,0 +1,416 @@ +/*------------------------------------------------------------------------- + * + * datetime2.c + * Functions for the type "datetime2". + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "fmgr.h" +#include "utils/builtins.h" +#include "utils/date.h" +#include "utils/datetime.h" +#include "utils/timestamp.h" +#include "libpq/pqformat.h" + +#include "miscadmin.h" +#include "datetime2.h" + + +PG_FUNCTION_INFO_V1(datetime2_in); +PG_FUNCTION_INFO_V1(datetime2_out); +PG_FUNCTION_INFO_V1(datetime2_recv); +PG_FUNCTION_INFO_V1(date_datetime2); +PG_FUNCTION_INFO_V1(time_datetime2); +PG_FUNCTION_INFO_V1(timestamp_datetime2); +PG_FUNCTION_INFO_V1(timestamptz_datetime2); +PG_FUNCTION_INFO_V1(datetime2_scale); +PG_FUNCTION_INFO_V1(datetime2_varchar); +PG_FUNCTION_INFO_V1(varchar_datetime2); +PG_FUNCTION_INFO_V1(datetime2_char); +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); + +/* datetime2_in_str() + * Convert a string to internal form. + * Most parts of this functions is same as timestamp_in(), + * but we use a different rounding function for datetime2. + */ +static Datum +datetime2_in_str(char *str, int32 typmod) +{ + Timestamp result; + fsec_t fsec; + struct pg_tm tt, + *tm = &tt; + int tz; + int dtype; + int nf; + int dterr; + char *field[MAXDATEFIELDS]; + int ftype[MAXDATEFIELDS]; + char workbuf[MAXDATELEN + MAXDATEFIELDS]; + + 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 + */ + if (dterr == 1) + { + tm->tm_year = 1900; + tm->tm_mon = 1; + tm->tm_mday = 1; + dterr = 0; + } + + 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 + */ + if ((fsec == USECS_PER_SEC) && + (tm->tm_year == 9999) && + (tm->tm_mon == 12) && + (tm->tm_mday == 31) && + (tm->tm_hour == 23) && + (tm->tm_min == 59) && + (tm->tm_sec == 59)) + fsec = 999999; + + switch (dtype) + { + case DTK_DATE: + if (tm2timestamp(tm, fsec, NULL, &result) != 0) + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("datetime2 out of range: \"%s\"", str))); + break; + + case DTK_EPOCH: + result = SetEpochTimestamp(); + break; + + case DTK_LATE: + TIMESTAMP_NOEND(result); + break; + + case DTK_EARLY: + TIMESTAMP_NOBEGIN(result); + break; + + default: + elog(ERROR, "unexpected dtype %d while parsing datetime2 \"%s\"", + dtype, str); + TIMESTAMP_NOEND(result); + } + AdjustDatetime2ForTypmod(&result, typmod); + CheckDatetime2Range(result); + + PG_RETURN_TIMESTAMP(result); +} + +/* datetime2_in() + * Convert a string to internal form. + * Most parts of this functions is same as timestamp_in(), + * but we use a different rounding function for datetime2. + */ +Datum +datetime2_in(PG_FUNCTION_ARGS) +{ + char *str = PG_GETARG_CSTRING(0); + #ifdef NOT_USED + Oid typelem = PG_GETARG_OID(1); + #endif + int32 typmod = PG_GETARG_INT32(2); + + return datetime2_in_str(str, typmod); +} + +/* AdjustDatetime2ForTypmod() + * round off a datetime2 to suit given typmod + */ +static void +AdjustDatetime2ForTypmod(Timestamp *time, int32 typmod) +{ + static const int64 TimestampScales[MAX_TIMESTAMP_PRECISION + 1] = { + INT64CONST(1000000), + INT64CONST(100000), + INT64CONST(10000), + INT64CONST(1000), + INT64CONST(100), + INT64CONST(10), + INT64CONST(1) + }; + + static const int64 TimestampOffsets[MAX_TIMESTAMP_PRECISION + 1] = { + INT64CONST(500000), + INT64CONST(50000), + INT64CONST(5000), + INT64CONST(500), + INT64CONST(50), + INT64CONST(5), + INT64CONST(0) + }; + + /* new offset for negative timestamp value */ + static const int64 TimestampOffsetsNegative[MAX_TIMESTAMP_PRECISION + 1] = { + INT64CONST(499999), + INT64CONST(49999), + INT64CONST(4999), + INT64CONST(499), + INT64CONST(49), + INT64CONST(4), + INT64CONST(0) + }; + + int64 adjustedTime; + + if (!TIMESTAMP_NOT_FINITE(*time) + && (typmod != -1)) + { + if (typmod < 0 || typmod > MAX_TIMESTAMP_PRECISION) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("datetime2(%d) precision must be between %d and %d", + typmod, 0, MAX_TIMESTAMP_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 + * truncate fractional seconds to typmod precision + */ + else + { + *time = (*time / TimestampScales[typmod]) * TimestampScales[typmod]; + } + } + else + { + *time = -((((-*time) + TimestampOffsetsNegative[typmod]) / TimestampScales[typmod]) + * TimestampScales[typmod]); + } + } +} + +/* + * CheckDatetime2Range() + * Check if timestamp is out of range for datetime2 + */ +void +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"))); + } +} + +/* date_datetime2() + * Convert date to datetime2 + */ +Datum +date_datetime2(PG_FUNCTION_ARGS) +{ + DateADT dateVal = PG_GETARG_DATEADT(0); + Timestamp result; + + if (DATE_IS_NOBEGIN(dateVal)) + TIMESTAMP_NOBEGIN(result); + else if (DATE_IS_NOEND(dateVal)) + TIMESTAMP_NOEND(result); + else + result = dateVal * USECS_PER_DAY; + + PG_RETURN_TIMESTAMP(result); +} + +/* time_datetime2() + * Convert time to datetime2 + */ +Datum +time_datetime2(PG_FUNCTION_ARGS) +{ + TimeADT timeVal = PG_GETARG_TIMEADT(0); + Timestamp result; + + 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"))); + + PG_RETURN_TIMESTAMP(result); +} + +/* timestamp_datetime2() + * Convert timestamp to datetime2 + */ +Datum +timestamp_datetime2(PG_FUNCTION_ARGS) +{ + Timestamp result = PG_GETARG_TIMESTAMP(0); + CheckDatetime2Range(result); + PG_RETURN_TIMESTAMP(result); +} + +/* timestamptz_datetime2() + * Convert timestamptz to datetime2 + */ +Datum +timestamptz_datetime2(PG_FUNCTION_ARGS) +{ + TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0); + Timestamp result; + + struct pg_tm tt, + *tm = &tt; + fsec_t fsec; + int tz; + + if (TIMESTAMP_NOT_FINITE(timestamp)) + result = timestamp; + else + { + if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0) + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("data out of range for datetime2"))); + if (tm2timestamp(tm, fsec, NULL, &result) != 0) + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("data out of range for datetime2"))); + } + CheckDatetime2Range(result); + PG_RETURN_TIMESTAMP(result); +} + +/* datetime2_scale() + * Adjust datetime2_scale type for specified scale factor. + * Used by PostgreSQL type system to stuff columns. + */ +Datum +datetime2_scale(PG_FUNCTION_ARGS) +{ + Timestamp result = PG_GETARG_TIMESTAMP(0); + int32 typmod = PG_GETARG_INT32(1); + + AdjustDatetime2ForTypmod(&result, typmod); + PG_RETURN_TIMESTAMP(result); +} + +/* datetime2_varchar() + * Convert a datetime2 to varchar. + * The function is the same as timestamp_out() except the return type is a VARCHAR Datum. + */ +Datum +datetime2_varchar(PG_FUNCTION_ARGS) +{ + Timestamp timestamp = PG_GETARG_TIMESTAMP(0); + char *s; + struct pg_tm tt, + *tm = &tt; + fsec_t fsec; + char buf[MAXDATELEN + 1]; + VarChar *result; + + if (TIMESTAMP_NOT_FINITE(timestamp)) + EncodeSpecialTimestamp(timestamp, buf); + else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0) + EncodeDateTime(tm, fsec, false, 0, NULL, DateStyle, buf); + else + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("timestamp out of range"))); + s = pstrdup(buf); + result = (VarChar *) cstring_to_text(s); + PG_RETURN_VARCHAR_P(result); +} + +/* + * varchar_datetime2() + * Convert a varchar to datetime2 + */ +Datum +varchar_datetime2(PG_FUNCTION_ARGS) +{ + Datum txt = PG_GETARG_DATUM(0); + char *str = TextDatumGetCString(txt); + + return datetime2_in_str(str, MAX_TIMESTAMP_PRECISION); +} + +/* datetime2_char() + * Convert a datetim2 to char. + * The function is the same as timestamp_out() except the return type is a CHAR Datum. + */ +Datum +datetime2_char(PG_FUNCTION_ARGS) +{ + Timestamp timestamp = PG_GETARG_TIMESTAMP(0); + char *s; + struct pg_tm tt, + *tm = &tt; + fsec_t fsec; + char buf[MAXDATELEN + 1]; + VarChar *result; + + if (TIMESTAMP_NOT_FINITE(timestamp)) + EncodeSpecialTimestamp(timestamp, buf); + else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0) + EncodeDateTime(tm, fsec, false, 0, NULL, DateStyle, buf); + else + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("timestamp out of range"))); + s = pstrdup(buf); + result = (BpChar *) cstring_to_text(s); + PG_RETURN_BPCHAR_P(result); +} + +/* + * char_datetime2() + * Convert a CHAR to datetim2 + */ +Datum +char_datetime2(PG_FUNCTION_ARGS) +{ + 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 new file mode 100644 index 00000000000..cfe285fc832 --- /dev/null +++ b/contrib/babelfishpg_common/src/datetime2.h @@ -0,0 +1,25 @@ +/*------------------------------------------------------------------------- +* +* datetime2.h +* Definitions for the TSQL "datetime2" type. +* +*------------------------------------------------------------------------- +*/ +#ifndef PLTSQL_DATETIME2_H +#define PLTSQL_DATETIME2_H + +/* Maximum precision for datetime2 + * TODO: alter datetime2 to have max precision == 7 + */ +#define MAX_DATETIME2_PRECISION 6 + +/* Datetime2 limits */ +/* lower bound: 0001-01-01 00:00:00.000 */ +#define MIN_DATETIME2 INT64CONST(-63082281600000000) +/* upper bound: 10000-00-00 00:00:00 */ +#define END_DATETIME2 INT64CONST(252455616000000000) + +/* 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 diff --git a/contrib/babelfishpg_common/src/datetimeoffset.c b/contrib/babelfishpg_common/src/datetimeoffset.c new file mode 100644 index 00000000000..379f10b1ccd --- /dev/null +++ b/contrib/babelfishpg_common/src/datetimeoffset.c @@ -0,0 +1,773 @@ +/*------------------------------------------------------------------------- + * + * datetimeoffset.c + * Functions for the type "datetimeoffset". + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" +#include "access/hash.h" +#include "utils/builtins.h" +#include "utils/date.h" +#include "utils/datetime.h" +#include "libpq/pqformat.h" +#include "utils/timestamp.h" + +#include "fmgr.h" +#include "miscadmin.h" +#include "datetimeoffset.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 EncodeDatetimeoffsetTimezone(char *str, int tz, int style); + +PG_FUNCTION_INFO_V1(datetimeoffset_in); +PG_FUNCTION_INFO_V1(datetimeoffset_out); +PG_FUNCTION_INFO_V1(datetimeoffset_recv); +PG_FUNCTION_INFO_V1(datetimeoffset_send); + +PG_FUNCTION_INFO_V1(datetimeoffset_eq); +PG_FUNCTION_INFO_V1(datetimeoffset_ne); +PG_FUNCTION_INFO_V1(datetimeoffset_lt); +PG_FUNCTION_INFO_V1(datetimeoffset_le); +PG_FUNCTION_INFO_V1(datetimeoffset_gt); +PG_FUNCTION_INFO_V1(datetimeoffset_ge); +PG_FUNCTION_INFO_V1(datetimeoffset_cmp); + +PG_FUNCTION_INFO_V1(datetimeoffset_pl_interval); +PG_FUNCTION_INFO_V1(datetimeoffset_mi_interval); +PG_FUNCTION_INFO_V1(interval_pl_datetimeoffset); +PG_FUNCTION_INFO_V1(datetimeoffset_mi); + +PG_FUNCTION_INFO_V1(datetimeoffset_hash); +PG_FUNCTION_INFO_V1(datetimeoffset_hash_extended); + +PG_FUNCTION_INFO_V1(timestamp_datetimeoffset); +PG_FUNCTION_INFO_V1(datetimeoffset_timestamp); +PG_FUNCTION_INFO_V1(date_datetimeoffset); +PG_FUNCTION_INFO_V1(datetimeoffset_date); +PG_FUNCTION_INFO_V1(time_datetimeoffset); +PG_FUNCTION_INFO_V1(datetimeoffset_time); +PG_FUNCTION_INFO_V1(smalldatetime_datetimeoffset); +PG_FUNCTION_INFO_V1(datetimeoffset_smalldatetime); +PG_FUNCTION_INFO_V1(datetime_datetimeoffset); +PG_FUNCTION_INFO_V1(datetimeoffset_datetime); +PG_FUNCTION_INFO_V1(datetime2_datetimeoffset); +PG_FUNCTION_INFO_V1(datetimeoffset_datetime2); +PG_FUNCTION_INFO_V1(datetimeoffset_scale); + +PG_FUNCTION_INFO_V1(get_datetimeoffset_tzoffset_internal); + + +/* datetimeoffset_in() + * Convert a string to internal form. + * Most parts of this functions is same as timestamptz_in(), + * but we store the timezone in a seperate int16 variable. + */ +Datum +datetimeoffset_in(PG_FUNCTION_ARGS) +{ + char *str = PG_GETARG_CSTRING(0); + +#ifdef NOT_USED + Oid typelem = PG_GETARG_OID(1); +#endif + int32 typmod = PG_GETARG_INT32(2); + tsql_datetimeoffset* datetimeoffset; + Timestamp tsql_ts; + fsec_t fsec; + struct pg_tm tt, + *tm = &tt; + int tz; + int dtype; + int nf; + int dterr; + char *field[MAXDATEFIELDS]; + int ftype[MAXDATEFIELDS]; + char workbuf[MAXDATELEN + MAXDATEFIELDS]; + + datetimeoffset = (tsql_datetimeoffset *)palloc(DATETIMEOFFSET_LEN); + 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 + if (dterr == 1) + { + tm->tm_year = 1900; + tm->tm_mon = 1; + tm->tm_mday = 1; + dterr = 0; + } + if (dterr != 0) + DateTimeParseError(dterr, str, "timestamp with time zone"); + + datetimeoffset->tsql_tz = (int16)(tz/60); + tz = 0; + switch (dtype) + { + case DTK_DATE: + if (tm2timestamp(tm, fsec, &tz, &tsql_ts) != 0) + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("timestamp out of range: \"%s\"", str))); + break; + + case DTK_EPOCH: + tsql_ts = SetEpochTimestamp(); + break; + + case DTK_LATE: + TIMESTAMP_NOEND(tsql_ts); + break; + + case DTK_EARLY: + TIMESTAMP_NOBEGIN(tsql_ts); + break; + + default: + elog(ERROR, "unexpected dtype %d while parsing timestamptz \"%s\"", + dtype, str); + TIMESTAMP_NOEND(tsql_ts); + } + AdjustDatetimeoffsetForTypmod(&tsql_ts, typmod); + datetimeoffset->tsql_ts = (int64)tsql_ts; + CheckDatetimeoffsetRange(datetimeoffset); + + PG_RETURN_DATETIMEOFFSET(datetimeoffset); +} + +/* datetimeoffset_out() + * Convert datetimeoffset to external form. + */ +Datum +datetimeoffset_out(PG_FUNCTION_ARGS) +{ + 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 = df->tsql_ts; + if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0) + EncodeDateTime(tm, fsec, false, 0, NULL, DateStyle, buf); + else + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("datetimeoffset out of range"))); + EncodeDatetimeoffsetTimezone(buf, df->tsql_tz, DateStyle); + result = pstrdup(buf); + + PG_RETURN_CSTRING(result); +} + +/* + * datetimeoffset_recv - converts external binary format to datetimeoffset + */ +Datum +datetimeoffset_recv(PG_FUNCTION_ARGS) +{ + StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); + +#ifdef NOT_USED + Oid typelem = PG_GETARG_OID(1); +#endif + int32 typmod = PG_GETARG_INT32(2); + tsql_datetimeoffset *result; + + result = (tsql_datetimeoffset *) palloc(DATETIMEOFFSET_LEN); + + result->tsql_ts = pq_getmsgint64(buf); + + result->tsql_tz = pq_getmsgint(buf, sizeof(int16)); + /* Check for sane GMT displacement; see notes in datatype/timestamp.h */ + if (result->tsql_tz <= -DATETIMEOFFSET_TIMEZONE_LIMIT || result->tsql_tz >= DATETIMEOFFSET_TIMEZONE_LIMIT) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TIME_ZONE_DISPLACEMENT_VALUE), + errmsg("datetimeoffset time zone out of range"))); + + AdjustDatetimeoffsetForTypmod(&(result->tsql_ts), typmod); + CheckDatetimeoffsetRange(result); + + PG_RETURN_DATETIMEOFFSET(result); +} + +/* + * datetimeoffset_send - converts datetimeoffset to external binary format + */ +Datum +datetimeoffset_send(PG_FUNCTION_ARGS) +{ + tsql_datetimeoffset *datetimeoffset = PG_GETARG_DATETIMEOFFSET(0); + StringInfoData buffer; + + pq_begintypsend(&buffer); + pq_sendint64(&buffer, datetimeoffset->tsql_ts); + pq_sendint16(&buffer, datetimeoffset->tsql_tz); + + PG_RETURN_BYTEA_P(pq_endtypsend(&buffer)); +} + +/* cast datetimeoffset to timestamp internal representation */ +static void +datetimeoffset_timestamp_internal(const tsql_datetimeoffset *df, Timestamp* time) +{ + *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) +{ + Timestamp t1; + Timestamp t2; + datetimeoffset_timestamp_internal(df1, &t1); + datetimeoffset_timestamp_internal(df2, &t2); + + return (t1 < t2) ? -1 : ((t1 > t2) ? 1 : 0); +} + +Datum +datetimeoffset_eq(PG_FUNCTION_ARGS) +{ + tsql_datetimeoffset *df1 = PG_GETARG_DATETIMEOFFSET(0); + tsql_datetimeoffset *df2 = PG_GETARG_DATETIMEOFFSET(1); + + PG_RETURN_BOOL(datetimeoffset_cmp_internal(df1, df2) == 0); +} + +Datum +datetimeoffset_ne(PG_FUNCTION_ARGS) +{ + tsql_datetimeoffset *df1 = PG_GETARG_DATETIMEOFFSET(0); + tsql_datetimeoffset *df2 = PG_GETARG_DATETIMEOFFSET(1); + + PG_RETURN_BOOL(datetimeoffset_cmp_internal(df1, df2) != 0); +} + +Datum +datetimeoffset_lt(PG_FUNCTION_ARGS) +{ + tsql_datetimeoffset *df1 = PG_GETARG_DATETIMEOFFSET(0); + tsql_datetimeoffset *df2 = PG_GETARG_DATETIMEOFFSET(1); + + PG_RETURN_BOOL(datetimeoffset_cmp_internal(df1, df2) < 0); +} + +Datum +datetimeoffset_gt(PG_FUNCTION_ARGS) +{ + tsql_datetimeoffset *df1 = PG_GETARG_DATETIMEOFFSET(0); + tsql_datetimeoffset *df2 = PG_GETARG_DATETIMEOFFSET(1); + + PG_RETURN_BOOL(datetimeoffset_cmp_internal(df1, df2) > 0); +} + +Datum +datetimeoffset_le(PG_FUNCTION_ARGS) +{ + tsql_datetimeoffset *df1 = PG_GETARG_DATETIMEOFFSET(0); + tsql_datetimeoffset *df2 = PG_GETARG_DATETIMEOFFSET(1); + + PG_RETURN_BOOL(datetimeoffset_cmp_internal(df1, df2) <= 0); +} + +Datum +datetimeoffset_ge(PG_FUNCTION_ARGS) +{ + tsql_datetimeoffset *df1 = PG_GETARG_DATETIMEOFFSET(0); + tsql_datetimeoffset *df2 = PG_GETARG_DATETIMEOFFSET(1); + + PG_RETURN_BOOL(datetimeoffset_cmp_internal(df1, df2) >= 0); +} + +Datum +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)); +} + +/* datetimeoffset_pl_interval() + * This function is similar to timestamptz_pl_interval, + * adding some logic to handle the timezone. + */ +Datum +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; + + if (span->month != 0) + { + struct pg_tm tt, + *tm = &tt; + fsec_t fsec; + + if (timestamp2tm(tmp, &tz, tm, &fsec, NULL, NULL) != 0) + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("datetimeoffset out of range"))); + + tm->tm_mon += span->month; + if (tm->tm_mon > MONTHS_PER_YEAR) + { + tm->tm_year += (tm->tm_mon - 1) / MONTHS_PER_YEAR; + tm->tm_mon = ((tm->tm_mon - 1) % MONTHS_PER_YEAR) + 1; + } + else if (tm->tm_mon < 1) + { + tm->tm_year += tm->tm_mon / MONTHS_PER_YEAR - 1; + tm->tm_mon = tm->tm_mon % MONTHS_PER_YEAR + MONTHS_PER_YEAR; + } + + /* adjust for end of month boundary problems... */ + 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) + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("datetimeoffset out of range"))); + } + + if (span->day != 0) + { + struct pg_tm tt, + *tm = &tt; + fsec_t fsec; + int julian; + + if (timestamp2tm(tmp, &tz, tm, &fsec, NULL, NULL) != 0) + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("datetimeoffset out of range"))); + + /* 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) + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("datetimeoffset out of range"))); + } + + tmp += span->time; + result->tsql_ts = tmp + df->tsql_tz * USECS_PER_MINUTE; + result->tsql_tz = df->tsql_tz; + CheckDatetimeoffsetRange(result); + + PG_RETURN_DATETIMEOFFSET(result); +} + +Datum +datetimeoffset_mi_interval(PG_FUNCTION_ARGS) +{ + tsql_datetimeoffset *df = PG_GETARG_DATETIMEOFFSET(0); + Interval *span = PG_GETARG_INTERVAL_P(1); + Interval tspan; + + tspan.month = -span->month; + tspan.day = -span->day; + tspan.time = -span->time; + + return DirectFunctionCall2(datetimeoffset_pl_interval, + DatetimeoffsetGetDatum(df), + PointerGetDatum(&tspan)); +} + +Datum +interval_pl_datetimeoffset(PG_FUNCTION_ARGS) +{ + Interval *span = PG_GETARG_INTERVAL_P(0); + tsql_datetimeoffset *df = PG_GETARG_DATETIMEOFFSET(1); + + return DirectFunctionCall2(datetimeoffset_pl_interval, + DatetimeoffsetGetDatum(df), + PointerGetDatum(span)); +} + +Datum +datetimeoffset_mi(PG_FUNCTION_ARGS) +{ + tsql_datetimeoffset *df1 = PG_GETARG_DATETIMEOFFSET(0); + tsql_datetimeoffset *df2 = PG_GETARG_DATETIMEOFFSET(1); + Timestamp t1; + Timestamp t2; + Interval *result; + + datetimeoffset_timestamp_internal(df1, &t1); + datetimeoffset_timestamp_internal(df2, &t2); + result = (Interval *) palloc(sizeof(Interval)); + + result->time = t1 - t2; + + result->month = 0; + result->day = 0; + + + result = DatumGetIntervalP(DirectFunctionCall1(interval_justify_hours, + IntervalPGetDatum(result))); + + PG_RETURN_INTERVAL_P(result); +} + +/* hash index support */ +Datum +datetimeoffset_hash(PG_FUNCTION_ARGS) +{ + tsql_datetimeoffset *df = PG_GETARG_DATETIMEOFFSET(0); + return hash_any((unsigned char *)df, DATETIMEOFFSET_LEN); +} + +/* smalldatetime_datetimeoffset() + * Convert smalldatetime to datetimeoffset + */ +Datum +smalldatetime_datetimeoffset(PG_FUNCTION_ARGS) +{ + Timestamp time = PG_GETARG_TIMESTAMP(0); + tsql_datetimeoffset* result; + + result = (tsql_datetimeoffset *) palloc(DATETIMEOFFSET_LEN); + result->tsql_ts = time; + result->tsql_tz = 0; + CheckDatetimeoffsetRange(result); + + PG_RETURN_DATETIMEOFFSET(result); +} + +/* datetimeoffset_smalldatetime() + * Convert datetimeoffset to smalldatetime + */ +Datum +datetimeoffset_smalldatetime(PG_FUNCTION_ARGS) +{ + tsql_datetimeoffset *df = PG_GETARG_DATETIMEOFFSET(0); + Timestamp result; + datetimeoffset_timestamp_internal(df, &result); + CheckSmalldatetimeRange(result); + AdjustTimestampForSmallDatetime(&result); + + PG_RETURN_TIMESTAMP(result); +} + +/* datetime_datetimeoffset() + * Convert datetime to datetimeoffset + */ +Datum +datetime_datetimeoffset(PG_FUNCTION_ARGS) +{ + Timestamp time = PG_GETARG_TIMESTAMP(0); + tsql_datetimeoffset* result; + + result = (tsql_datetimeoffset *) palloc(DATETIMEOFFSET_LEN); + result->tsql_ts = time; + result->tsql_tz = 0; + CheckDatetimeoffsetRange(result); + + PG_RETURN_DATETIMEOFFSET(result); +} + +/* datetimeoffset_datetime() + * Convert datetimeoffset to datetime + */ +Datum +datetimeoffset_datetime(PG_FUNCTION_ARGS) +{ + tsql_datetimeoffset *df = PG_GETARG_DATETIMEOFFSET(0); + Timestamp result; + datetimeoffset_timestamp_internal(df, &result); + CheckDatetimeRange(result); + + PG_RETURN_TIMESTAMP(result); +} + +/* datetime2_datetimeoffset() + * Convert datetime2 to datetimeoffset + */ +Datum +datetime2_datetimeoffset(PG_FUNCTION_ARGS) +{ + Timestamp time = PG_GETARG_TIMESTAMP(0); + tsql_datetimeoffset* result; + + result = (tsql_datetimeoffset *) palloc(DATETIMEOFFSET_LEN); + result->tsql_ts = time; + result->tsql_tz = 0; + CheckDatetimeoffsetRange(result); + + PG_RETURN_DATETIMEOFFSET(result); +} + +/* datetimeoffset_datetime2() + * Convert datetimeoffset to datetime + */ +Datum +datetimeoffset_datetime2(PG_FUNCTION_ARGS) +{ + tsql_datetimeoffset *df = PG_GETARG_DATETIMEOFFSET(0); + Timestamp result; + datetimeoffset_timestamp_internal(df, &result); + CheckDatetime2Range(result); + + PG_RETURN_TIMESTAMP(result); +} + +/* timestamp_datetimeoffset() + * Convert timestamp to datetimeoffset + */ +Datum +timestamp_datetimeoffset(PG_FUNCTION_ARGS) +{ + Timestamp time = PG_GETARG_TIMESTAMP(0); + tsql_datetimeoffset* result; + + result = (tsql_datetimeoffset *) palloc(DATETIMEOFFSET_LEN); + result->tsql_ts = time; + result->tsql_tz = 0; + CheckDatetimeoffsetRange(result); + + PG_RETURN_DATETIMEOFFSET(result); +} + +/* datetimeoffset_timestamp() + * Convert datetimeoffset to timestamp + */ +Datum +datetimeoffset_timestamp(PG_FUNCTION_ARGS) +{ + tsql_datetimeoffset *df = PG_GETARG_DATETIMEOFFSET(0); + Timestamp result; + datetimeoffset_timestamp_internal(df, &result); + + PG_RETURN_TIMESTAMP(result); +} + +/* date_datetimeoffset() + * Convert date to datetimeoffset + */ +Datum +date_datetimeoffset(PG_FUNCTION_ARGS) +{ + DateADT dateVal = PG_GETARG_DATEADT(0); + tsql_datetimeoffset* result; + + result = (tsql_datetimeoffset *) palloc(DATETIMEOFFSET_LEN); + result->tsql_ts = (int64)dateVal * USECS_PER_DAY; + result->tsql_tz = 0; + CheckDatetimeoffsetRange(result); + + PG_RETURN_DATETIMEOFFSET(result); +} + +/* datetimeoffset_date() + * Convert datetimeoffset to date + */ +Datum +datetimeoffset_date(PG_FUNCTION_ARGS) +{ + tsql_datetimeoffset *df = PG_GETARG_DATETIMEOFFSET(0); + 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) + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("datetimeoffset out of range"))); + + result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE; + + PG_RETURN_DATEADT(result); +} + +/* datetimeoffset_time() + * Convert datetimeoffset to time data type. + */ +Datum +datetimeoffset_time(PG_FUNCTION_ARGS) +{ + tsql_datetimeoffset *df = PG_GETARG_DATETIMEOFFSET(0); + Timestamp time; + TimeADT result; + + datetimeoffset_timestamp_internal(df, &time); + if (time < 0) + result = time - (time / USECS_PER_DAY * USECS_PER_DAY) + USECS_PER_DAY; + else + result = time - (time / USECS_PER_DAY * USECS_PER_DAY); + + PG_RETURN_TIMEADT(result); +} + +/* time_datetimeoffset() + * Convert time to datetimeoffset data type. + */ +Datum +time_datetimeoffset(PG_FUNCTION_ARGS) +{ + TimeADT time = PG_GETARG_TIMEADT(0); + tsql_datetimeoffset *result; + + result = (tsql_datetimeoffset *) palloc(DATETIMEOFFSET_LEN); + result->tsql_ts = DATETIMEOFFSET_DEFAULT_TS + time; + result->tsql_tz = 0; + + PG_RETURN_DATETIMEOFFSET(result); +} + +/* datetimeoffset_scale() + * Adjust datetimeoffset_scale type for specified scale factor. + * Used by PostgreSQL type system to stuff columns. + */ +Datum +datetimeoffset_scale(PG_FUNCTION_ARGS) +{ + tsql_datetimeoffset *df = PG_GETARG_DATETIMEOFFSET(0); + int32 typmod = PG_GETARG_INT32(1); + tsql_datetimeoffset *result = (tsql_datetimeoffset *) palloc(DATETIMEOFFSET_LEN); + + result->tsql_ts = df->tsql_ts; + result->tsql_tz = df->tsql_tz; + AdjustDatetimeoffsetForTypmod(&(result->tsql_ts), typmod); + + PG_RETURN_DATETIMEOFFSET(result); +} + + +Datum +get_datetimeoffset_tzoffset_internal(PG_FUNCTION_ARGS) +{ + tsql_datetimeoffset *df = PG_GETARG_DATETIMEOFFSET(0); + PG_RETURN_INT16(-df->tsql_tz); +} + +/* + * CheckDatetimeoffsetRange --- Check if datetimeoffset is out of range + * for 0001-01-01 through 9999-12-31 + */ +static void +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 */ + static const int64 lower_bound = -63082281600000000; + static const int64 upper_bound = 252455616000000000; + + datetimeoffset_timestamp_internal(df, &time); + if (time < lower_bound || time >= upper_bound) + { + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("data out of range for datetimeoffset"))); + } +} + +/* + * AdjustDatetimeoffsetForTypmod --- round off a datetimeoffset to suit given typmod + * this function is from timestamp.c + */ +static void +AdjustDatetimeoffsetForTypmod(Timestamp *time, int32 typmod) +{ + static const int64 TimestampScales[MAX_TIMESTAMP_PRECISION + 1] = { + INT64CONST(1000000), + INT64CONST(100000), + INT64CONST(10000), + INT64CONST(1000), + INT64CONST(100), + INT64CONST(10), + INT64CONST(1) + }; + + static const int64 TimestampOffsets[MAX_TIMESTAMP_PRECISION + 1] = { + INT64CONST(500000), + INT64CONST(50000), + INT64CONST(5000), + INT64CONST(500), + INT64CONST(50), + INT64CONST(5), + INT64CONST(0) + }; + + /* new offset for negative timestamp value */ + static const int64 TimestampOffsetsNegative[MAX_TIMESTAMP_PRECISION + 1] = { + INT64CONST(499999), + INT64CONST(49999), + INT64CONST(4999), + INT64CONST(499), + INT64CONST(49), + INT64CONST(4), + INT64CONST(0) + }; + + if (!TIMESTAMP_NOT_FINITE(*time) + && (typmod != -1) && (typmod != MAX_TIMESTAMP_PRECISION)) + { + if (typmod < 0 || typmod > MAX_TIMESTAMP_PRECISION) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("datetimeoffset(%d) precision must be between %d and %d", + typmod, 0, MAX_TIMESTAMP_PRECISION))); + + if (*time >= INT64CONST(0)) + { + *time = ((*time + TimestampOffsets[typmod]) / TimestampScales[typmod]) * + TimestampScales[typmod]; + } + else + { + *time = -((((-*time) + TimestampOffsetsNegative[typmod]) / TimestampScales[typmod]) + * TimestampScales[typmod]); + } + } +} + +/* EncodeDatetimeoffsetTimezone() + * Copies representation of a numeric timezone offset to str. + * Note: we need to hanlde the '\0' at the end of original input string. + */ +static void +EncodeDatetimeoffsetTimezone(char *str, int tz, int style) +{ + int hour, + min; + char *tmp; + + min = abs(tz); + hour = min / MINS_PER_HOUR; + min = min % MINS_PER_HOUR; + /* point tmp to '\0' */ + tmp = str + strlen(str); + *tmp++ = ' '; + /* TZ is negated compared to sign we wish to display ... */ + *tmp++ = (tz <= 0 ? '+' : '-'); + + tmp = pg_ultostr_zeropad(tmp, hour, 2); + *tmp++ = ':'; + tmp = pg_ultostr_zeropad(tmp, min, 2); + + *tmp = '\0'; +} diff --git a/contrib/babelfishpg_common/src/datetimeoffset.h b/contrib/babelfishpg_common/src/datetimeoffset.h new file mode 100644 index 00000000000..ae1c9d8e554 --- /dev/null +++ b/contrib/babelfishpg_common/src/datetimeoffset.h @@ -0,0 +1,38 @@ +/*------------------------------------------------------------------------- + * + * datetimeoffset.h + * Definitions for the TSQL "datetimeoffset" type. + * + *------------------------------------------------------------------------- + */ +#ifndef DATETIMEOFFSET_H +#define DATETIMEOFFSET_H +#include "fmgr.h" // check if necessary + +/* datetimeoffset size in bytes */ +#define DATETIMEOFFSET_LEN MAXALIGN(sizeof(tsql_datetimeoffset)) +/* datetimeoffset default value in internal representation */ +#define DATETIMEOFFSET_DEFAULT_TS -3155673600000000 +/* datetimeoffset timezone limit, it is valid for -14:00 to +14:00 + * So the limit to mins will be 14*60+1 = 841 + */ +#define DATETIMEOFFSET_TIMEZONE_LIMIT 841 + + +extern void AdjustTimestampForSmallDatetime(Timestamp *time); +extern void CheckSmalldatetimeRange(const Timestamp time); +extern void CheckDatetimeRange(const Timestamp time); +extern void CheckDatetime2Range(const Timestamp time); +typedef struct tsql_datetimeoffset +{ + int64 tsql_ts; + int16 tsql_tz; +} tsql_datetimeoffset; + +/* fmgr interface macros */ +#define DatetimeoffsetGetDatum(X) PointerGetDatum(X) +#define PG_RETURN_DATETIMEOFFSET(X) return DatetimeoffsetGetDatum(X) +#define DatumGetDatetimeoffset(X) ((tsql_datetimeoffset *) DatumGetPointer(X)) +#define PG_GETARG_DATETIMEOFFSET(X) DatumGetDatetimeoffset(PG_GETARG_DATUM(X)) + +#endif /* DATETIMEOFFSET_H */ diff --git a/contrib/babelfishpg_common/src/instr.c b/contrib/babelfishpg_common/src/instr.c new file mode 100644 index 00000000000..37b3c60b443 --- /dev/null +++ b/contrib/babelfishpg_common/src/instr.c @@ -0,0 +1,18 @@ +#include "postgres.h" +#include "fmgr.h" + +#include "instr.h" + +instr_plugin *instr_plugin_ptr = NULL; + +void +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 new file mode 100644 index 00000000000..a9d2fc6ccd8 --- /dev/null +++ b/contrib/babelfishpg_common/src/instr.h @@ -0,0 +1,473 @@ +#ifndef INSTR_H +#define INSTR_H + +#include "postgres.h" + +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); +} instr_plugin; + +extern instr_plugin *instr_plugin_ptr; +extern void init_instr(void); + + +#define INSTR_ENABLED() \ + (instr_plugin_ptr && instr_plugin_ptr->instr_increment_metric) + +#define INSTR_METRIC_INC(metric) \ +({ if (INSTR_ENABLED()) \ + instr_plugin_ptr->instr_increment_metric(metric); \ +}) + +/* copy from pltsql_instr.h */ +typedef enum PgTsqlInstrMetricType { + + INSTR_START = -1, + INSTR_TSQL_ALTER_COLUMN, + INSTR_TSQL_IDENTITY_COLUMN, + INSTR_TSQL_COMPUTED_COLUMN, + INSTR_TSQL_CREATE_TEMP_TABLE, + INSTR_TSQL_CREATE_FUNCTION_RETURNS_TABLE, + + INSTR_UNSUPPORTED_TSQL_TOP_PERCENT_IN_STMT, + INSTR_UNSUPPORTED_TSQL_XML_OPTION_AUTO, + INSTR_UNSUPPORTED_TSQL_XML_OPTION_EXPLICIT, + INSTR_TSQL_OPTION_CLUSTERED, + INSTR_TSQL_OPTION_NON_CLUSTERED, + INSTR_TSQL_DATEADD, + INSTR_TSQL_DATEDIFF, + INSTR_TSQL_DATEPART, + INSTR_TSQL_DATENAME, + INSTR_TSQL_DAY, + INSTR_TSQL_MONTH, + INSTR_TSQL_YEAR, + INSTR_TSQL_DB_ID, + INSTR_TSQL_DB_NAME, + INSTR_TSQL_CHARINDEX, + INSTR_TSQL_DATALENGTH, + INSTR_TSQL_NCHAR, + INSTR_TSQL_PATINDEX, + INSTR_TSQL_QUOTENAME, + INSTR_TSQL_REPLICATE, + INSTR_TSQL_SPACE, + INSTR_TSQL_STRING_ESCAPE, + INSTR_TSQL_STRING_SPLIT, + INSTR_TSQL_ISNUMERIC, + INSTR_TSQL_CEILING, + INSTR_TSQL_FLOOR, + INSTR_TSQL_ROUND, + + + + INSTR_TSQL_FUNCTION_IIF, + INSTR_TSQL_FUNCTION_CHOOSE, + INSTR_UNSUPPORTED_TSQL_TEXTIMAGE_ON, + INSTR_TSQL_FUNCTION_TRY_CAST, + INSTR_TSQL_TRY_CONVERT, + INSTR_TSQL_PARSE, + INSTR_TSQL_FUNCTION_PARSE, + INSTR_TSQL_FUNCTION_CONVERT, + + INSTR_TSQL_SCHEMABINDING, + INSTR_TSQL_OPTION_IDENTITY_INSERT, + INSTR_TSQL_OPTION_LANGUAGE, + INSTR_UNSUPPORTED_TSQL_OPTION_ANSI_NULL_DFLT, + INSTR_UNSUPPORTED_TSQL_OPTION_ANSI_PADDING, + INSTR_UNSUPPORTED_TSQL_OPTION_ANSI_WARNINGS, + INSTR_UNSUPPORTED_TSQL_OPTION_ALLOW_SNAPSHOT_ISOLATION, + INSTR_UNSUPPORTED_TSQL_OPTION_ARITHABORT, + INSTR_UNSUPPORTED_TSQL_OPTION_ARITHIGNORE, + INSTR_UNSUPPORTED_TSQL_OPTION_NUMERIC_ROUNDABORT, + + INSTR_TSQL_INSERT_STMT, + INSTR_TSQL_DELETE_STMT, + INSTR_TSQL_UPDATE_STMT, + INSTR_TSQL_SELECT_STMT, + INSTR_TSQL_TRANS_STMT_START, + INSTR_TSQL_TRANS_STMT_COMMIT, + INSTR_TSQL_TRANS_STMT_ROLLBACK, + INSTR_TSQL_TRANS_STMT_SAVEPOINT, + INSTR_TSQL_TRANS_STMT_RELEASE, + INSTR_TSQL_TRANS_STMT_PREPARE, + INSTR_TSQL_TRANS_STMT_COMMIT_PREPARED, + INSTR_TSQL_TRANS_STMT_ROLLBACK_PREPARED, + INSTR_TSQL_TRANS_STMT_START_ISO_LEVEL_READ_UNCOMMITTED, + INSTR_TSQL_TRANS_STMT_START_ISO_LEVEL_READ_COMMITTED, + INSTR_TSQL_TRANS_STMT_START_ISO_LEVEL_REPEATABLE_READ, + INSTR_TSQL_TRANS_STMT_START_ISO_LEVEL_LEVEL_SERIALIZABLE, + INSTR_TSQL_DECLARE_CURSOR, + INSTR_TSQL_CLOSE_CURSOR_ALL, + INSTR_TSQL_CLOSE_CURSOR, + INSTR_TSQL_MOVE_CURSOR, + INSTR_TSQL_FETCH_CURSOR, + INSTR_TSQL_CREATE_DOMAIN, + INSTR_TSQL_CREATE_SCHEMA, + INSTR_TSQL_CREATE_TABLE_IF_NOT_EXISTS, + INSTR_TSQL_CREATE_TABLE, + INSTR_TSQL_CREATE_TABLESPACE, + INSTR_TSQL_DROP_TABLESPACE, + INSTR_TSQL_ALTER_TABLESPACE, + INSTR_TSQL_CREATE_EXTENSION, + INSTR_TSQL_ALTER_EXTENSION, + INSTR_TSQL_ALTER_EXTENSION_CONTENTS_STMT, + INSTR_TSQL_CREATE_FOREIGN_DATA_WRAPPER, + INSTR_TSQL_ALTER_FOREIGN_DATA_WRAPPER, + INSTR_TSQL_CREATE_SERVER, + INSTR_TSQL_ALTER_SERVER, + INSTR_TSQL_CREATE_USER_MAPPING, + INSTR_TSQL_ALTER_USER_MAPPING, + INSTR_TSQL_DROP_USER_MAPPING, + INSTR_TSQL_CREATE_FOREIGN_TABLE, + INSTR_TSQL_IMPORT_FOREIGN_SCHEMA, + INSTR_TSQL_DROP_TABLE, + INSTR_TSQL_DROP_SEQUENCE, + INSTR_TSQL_DROP_VIEW, + INSTR_TSQL_DROP_MATERIALIZED_VIEW, + INSTR_TSQL_DROP_INDEX, + INSTR_TSQL_DROP_TYPE, + INSTR_TSQL_DROP_DOMAIN, + INSTR_TSQL_DROP_COLLATION, + INSTR_TSQL_DROP_CONVERSION, + INSTR_TSQL_DROP_SCHEMA, + INSTR_TSQL_DROP_TEXT_SEARCH_PARSER, + INSTR_TSQL_DROP_TEXT_SEARCH_DICTIONARY, + INSTR_TSQL_DROP_TEXT_SEARCH_TEMPLATE, + INSTR_TSQL_DROP_TEXT_SEARCH_CONFIGURATION, + INSTR_TSQL_DROP_FOREIGN_TABLE, + INSTR_TSQL_DROP_EXTENSION, + INSTR_TSQL_DROP_FUNCTION, + INSTR_TSQL_DROP_PROCEDURE, + INSTR_TSQL_DROP_ROUTINE, + INSTR_TSQL_DROP_AGGREGATE, + INSTR_TSQL_DROP_OPERATOR, + INSTR_TSQL_DROP_LANGUAGE, + INSTR_TSQL_DROP_CAST, + INSTR_TSQL_DROP_TRIGGER, + INSTR_TSQL_DROP_EVENT_TRIGGER, + INSTR_TSQL_DROP_RULE, + INSTR_TSQL_DROP_FOREIGN_DATA_WRAPPER, + INSTR_TSQL_DROP_SERVER, + INSTR_TSQL_DROP_OPERATOR_CLASS, + INSTR_TSQL_DROP_OPERATOR_FAMILY, + INSTR_TSQL_DROP_POLICY, + INSTR_TSQL_DROP_TRANSFORM, + INSTR_TSQL_DROP_ACCESS_METHOD, + INSTR_TSQL_DROP_PUBLICATION, + INSTR_TSQL_DROP_STATISTICS, + INSTR_TSQL_TRUNCATE_TABLE, + INSTR_TSQL_COMMENT_STMT, + INSTR_TSQL_SECURITY_LABEL, + INSTR_TSQL_COPY_STMT, + INSTR_TSQL_RENAME_STMT, + INSTR_TSQL_ALTER_OBJECT_DEPENDS_STMT, + INSTR_TSQL_ALTER_OBJECT_SCHEMA_STMT, + INSTR_TSQL_ALTER_OWNER_STMT, + INSTR_TSQL_ALTER_TABLE_MOVE_ALL_STMT, + INSTR_TSQL_ALTER_TABLE_STMT, + INSTR_TSQL_ALTER_DOMAIN, + INSTR_TSQL_ALTER_FUNCTION, + INSTR_TSQL_ALTER_PROCEDURE, + INSTR_TSQL_ALTER_ROUTINE, + INSTR_TSQL_GRANT_STMT, + INSTR_TSQL_REVOKE_STMT, + INSTR_TSQL_GRANT_ROLE, + INSTR_TSQL_REVOKE_ROLE, + INSTR_TSQL_ALTER_DEFAULT_PRIVILEGES, + INSTR_TSQL_CREATE_AGGREGATE, + INSTR_TSQL_CREATE_OPERATOR, + INSTR_TSQL_CREATE_TYPE, + INSTR_TSQL_CREATE_TEXT_SEARCH_PARSER, + INSTR_TSQL_CREATE_TEXT_SEARCH_DICTIONARY, + INSTR_TSQL_CREATE_TEXT_SEARCH_TEMPLATE, + INSTR_TSQL_CREATE_TEXT_SEARCH_CONFIGURATION, + INSTR_TSQL_CREATE_COLLATION, + INSTR_TSQL_CREATE_ACCESS_METHOD, + INSTR_TSQL_CREATE_COMPOSITE_TYPE, + INSTR_TSQL_CREATE_ENUM_STMT, + INSTR_TSQL_CREATE_RANGE_STMT, + INSTR_TSQL_ALTER_ENUM, + INSTR_TSQL_CREATE_VIEW, + INSTR_TSQL_CREATE_PROCEDURE, + INSTR_TSQL_CREATE_FUNCTION, + INSTR_TSQL_CREATE_INDEX, + INSTR_TSQL_CREATE_RULE, + INSTR_TSQL_CREATE_SEQUENCE, + INSTR_TSQL_ALTER_SEQUENCE, + INSTR_TSQL_DO_STMT, + INSTR_TSQL_CREATE_DATABASE, + INSTR_TSQL_ALTER_DATABASE, + INSTR_TSQL_DROP_DATABASE, + INSTR_TSQL_NOTIFY_STMT, + INSTR_TSQL_LISTEN_STMT, + INSTR_TSQL_UNLISTEN_STMT, + INSTR_TSQL_LOAD_STMT, + INSTR_TSQL_CALL_STMT, + INSTR_TSQL_CLUSTER_STMT, + INSTR_TSQL_VACUUM_STMT, + INSTR_TSQL_ANALYZE_STMT, + INSTR_TSQL_EXPLAIN_STMT, + INSTR_TSQL_SELECT_INTO, + INSTR_TSQL_CREATE_TABLE_AS, + INSTR_TSQL_CREATE_MATERIALIZED_VIEW, + INSTR_TSQL_REFRESH_MATERIALIZED_VIEW, + INSTR_TSQL_ALTER_SYSTEM, + INSTR_TSQL_SET, + INSTR_TSQL_RESET, + INSTR_TSQL_VARIABLE_SHOW_STMT, + INSTR_TSQL_DISCARD_ALL, + INSTR_TSQL_DISCARD_PLANS, + INSTR_TSQL_DISCARD_TEMP, + INSTR_TSQL_DISCARD_SEQUENCES, + INSTR_TSQL_CREATE_TRANSFORM, + INSTR_TSQL_CREATE_TRIGGER, + INSTR_TSQL_CREATE_EVENT_TRIGGER, + INSTR_TSQL_ALTER_EVENT_TRIGGER, + INSTR_TSQL_CREATE_LANGUAGE, + INSTR_TSQL_CREATE_ROLE, + INSTR_TSQL_ALTER_ROLE, + INSTR_TSQL_DROP_ROLE, + INSTR_TSQL_DROP_OWNED, + INSTR_TSQL_REASSIGN_OWNED, + INSTR_TSQL_LOCK_TABLE, + INSTR_TSQL_SET_CONSTRAINTS, + INSTR_TSQL_CHECKPOINT, + INSTR_TSQL_REINDEX, + INSTR_TSQL_CREATE_CONVERSION, + INSTR_TSQL_CREATE_CAST, + INSTR_TSQL_CREATE_OPERATOR_CLASS, + INSTR_TSQL_CREATE_OPERATOR_FAMILY, + INSTR_TSQL_ALTER_OPERATOR_FAMILY, + INSTR_TSQL_ALTER_OPERATOR, + INSTR_TSQL_ALTER_TEXT_SEARCH_DICTIONARY, + INSTR_TSQL_ALTER_TEXT_SEARCH_CONFIGURATION, + INSTR_TSQL_CREATE_POLICY, + INSTR_TSQL_ALTER_POLICY, + INSTR_TSQL_CREATE_PUBLICATION, + INSTR_TSQL_ALTER_PUBLICATION, + INSTR_TSQL_CREATE_SUBSCRIPTION, + INSTR_TSQL_ALTER_SUBSCRIPTION, + INSTR_TSQL_DROP_SUBSCRIPTION, + INSTR_TSQL_ALTER_COLLATION, + INSTR_TSQL_PREPARE, + INSTR_TSQL_EXECUTE, + INSTR_TSQL_CREATE_STATISTICS, + INSTR_TSQL_DEALLOCATE_ALL, + INSTR_TSQL_DEALLOCATE, + INSTR_TSQL_SELECT_FOR_KEY_SHARE, + INSTR_TSQL_SELECT_FOR_SHARE, + INSTR_TSQL_SELECT_FOR_NO_KEY_UPDATE, + INSTR_TSQL_SELECT_FOR_UPDATE, + + INSTR_TSQL_BITIN, + INSTR_TSQL_BIT_RECV, + INSTR_TSQL_BITOUT, + INSTR_TSQL_BIT_SEND, + INSTR_TSQL_INT2BIT, + INSTR_TSQL_INT4BIT, + INSTR_TSQL_INT8BIT, + INSTR_TSQL_FTOBIT, + INSTR_TSQL_DTOBIT, + INSTR_TSQL_NUMERIC_BIT, + INSTR_TSQL_BITNEG, + INSTR_TSQL_BITEQ, + INSTR_TSQL_BITNE, + INSTR_TSQL_BITLT, + INSTR_TSQL_BITGT, + INSTR_TSQL_BITLE, + INSTR_TSQL_BITGE, + INSTR_TSQL_BIT_CMP, + INSTR_TSQL_INT4BITEQ, + INSTR_TSQL_INT4BITNE, + INSTR_TSQL_INT4BITLT, + INSTR_TSQL_INT4BITLE, + INSTR_TSQL_INT4BITGT, + INSTR_TSQL_INT4BITGE, + INSTR_TSQL_BITINT4EQ, + INSTR_TSQL_BITINT4NE, + INSTR_TSQL_BITINT4LT, + INSTR_TSQL_BITINT4LE, + INSTR_TSQL_BITINT4GT, + INSTR_TSQL_BITINT4GE, + INSTR_TSQL_BIT2INT2, + INSTR_TSQL_BIT2INT4, + INSTR_TSQL_BIT2INT8, + INSTR_TSQL_BIT2NUMERIC, + INSTR_TSQL_BIT2FIXEDDEC, + + INSTR_TSQL_VARBINARYIN, + INSTR_TSQL_VARBINARYOUT, + INSTR_TSQL_VARBINARY_RECV, + INSTR_TSQL_VARBINARY_SEND, + INSTR_TSQL_VARCHARVARBINARY, + INSTR_TSQL_BPCHARVARBINARY, + INSTR_TSQL_VARBINARYVARCHAR, + INSTR_TSQL_VARCHARBINARY, + INSTR_TSQL_BPCHARBINARY, + INSTR_TSQL_INT2VARBINARY, + INSTR_TSQL_INT4VARBINARY, + INSTR_TSQL_INT8VARBINARY, + INSTR_TSQL_VARBINARYINT2, + INSTR_TSQL_VARBINARYINT4, + INSTR_TSQL_VARBINARYINT8, + INSTR_TSQL_FLOAT4VARBINARY, + INSTR_TSQL_FLOAT8VARBINARY, + INSTR_TSQL_VARBINARYFLOAT4, + INSTR_TSQL_VARBINARYFLOAT8, + INSTR_TSQL_INT2BINARY, + INSTR_TSQL_INT4BINARY, + INSTR_TSQL_INT8BINARY, + INSTR_TSQL_BINARYINT2, + INSTR_TSQL_BINARYINT4, + INSTR_TSQL_BINARYINT8, + INSTR_TSQL_FLOAT4BINARY, + INSTR_TSQL_FLOAT8BINARY, + INSTR_TSQL_BINARYFLOAT4, + INSTR_TSQL_BINARYFLOAT8, + INSTR_TSQL_VARBINARY_COMPARE, + + INSTR_TSQL_SMALLDATETIMEIN, + INSTR_TSQL_TIME2SMALLDATETIME, + INSTR_TSQL_DATE2SMALLDATETIME, + INSTR_TSQL_TIMESTAMP2SMALLDATETIME, + INSTR_TSQL_TIMESTAMPTZ2SMALLDATETIME, + INSTR_TSQL_SMALLDATETIME2VARCHAR, + INSTR_TSQL_CONVERT_VARCHAR_SMALLDATETIME, + INSTR_TSQL_CONVERT_SMALLDATETIME_CHAR, + INSTR_TSQL_CONVERT_CHAR_SMALLDATETIME, + + INSTR_TSQL_DATETIMEIN, + INSTR_TSQL_DATETIMEOUT, + INSTR_TSQL_DATE2DATETIME, + INSTR_TSQL_TIME2DATETIME, + INSTR_TSQL_TIMESTAMP2DATETIME, + INSTR_TSQL_TIMESTAMPTZ2DATETIME, + INSTR_TSQL_DATETIME2VARCHAR, + INSTR_TSQL_VARCHAR2DATETIME, + INSTR_TSQL_DATETIME2CHAR, + INSTR_TSQL_CHAR2DATETIME, + + INSTR_TSQL_DATETIME22VARCHAR, + INSTR_TSQL_VARCHAR2DATETIME2, + INSTR_TSQL_DATETIME22CHAR, + INSTR_TSQL_CHAR2DATETIME2, + + INSTR_TSQL_SQLVARIANTIN, + INSTR_TSQL_SQLVARIANTOUT, + INSTR_TSQL_SQLVARIANT_RECV, + INSTR_TSQL_SQLVARIANT_SEND, + INSTR_TSQL_DATETIME_SQLVARIANT, + INSTR_TSQL_DATETIME2_SQLVARIANT, + INSTR_TSQL_SMALLDATETIME_SQLVARIANT, + INSTR_TSQL_DATETIMEOFFSET_SQLVARIANT, + INSTR_TSQL_DATE_SQLVARIANT, + INSTR_TSQL_TIME_SQLVARIANT, + INSTR_TSQL_FLOAT4_SQLVARIANT, + INSTR_TSQL_FLOAT8_SQLVARIANT, + INSTR_TSQL_NUMERIC_SQLVARIANT, + INSTR_TSQL_MONEY_SQLVARIANT, + INSTR_TSQL_SMALLMONEY_SQLVARIANT, + INSTR_TSQL_BIGINT_SQLVARIANT, + INSTR_TSQL_INT_SQLVARIANT, + INSTR_TSQL_SMALLINT_SQLVARIANT, + INSTR_TSQL_TINYINT_SQLVARIANT, + INSTR_TSQL_BIT_SQLVARIANT, + INSTR_TSQL_VARCHAR_SQLVARIANT, + INSTR_TSQL_NVARCHAR_SQLVARIANT, + INSTR_TSQL_CHAR_SQLVARIANT, + INSTR_TSQL_NCHAR_SQLVARIANT, + INSTR_TSQL_BBFVARBINARY_SQLVARIANT, + INSTR_TSQL_BBFBINARY_SQLVARIANT, + INSTR_TSQL_UNIQUEIDENTIFIER_SQLVARIANT, + INSTR_TSQL_SQLVARIANT_TIMESTAMP, + INSTR_TSQL_SQLVARIANT_DATETIMEOFFSET, + INSTR_TSQL_SQLVARIANT_DATE, + INSTR_TSQL_SQLVARIANT_TIME, + INSTR_TSQL_SQLVARIANT_FLOAT4, + INSTR_TSQL_SQLVARIANT_FLOAT8, + INSTR_TSQL_SQLVARIANT_NUMERIC, + INSTR_TSQL_SQLVARIANT_FIXEDDEC, + INSTR_TSQL_SQLVARIANT_BIGINT, + INSTR_TSQL_SQLVARIANT_INT, + INSTR_TSQL_SQLVARIANT_SMALLINT, + INSTR_TSQL_SQLVARIANT_BIT, + INSTR_TSQL_SQLVARIANT_VARCHAR, + INSTR_TSQL_SQLVARIANT_CHAR, + INSTR_TSQL_SQLVARIANT_BBFVARBINARY, + INSTR_TSQL_SQLVARIANT_BBFBINARY, + INSTR_TSQL_SQLVARIANT_UNIQUEINDETIFIER, + INSTR_TSQL_SQLVARIANTLT, + INSTR_TSQL_SQLVARIANTLE, + INSTR_TSQL_SQLVARIANTEQ, + INSTR_TSQL_SQLVARIANTGE, + INSTR_TSQL_SQLVARIANTGT, + INSTR_TSQL_SQLVARIANTNE, + + INSTR_TSQL_SERVERPROPERTY_BUILDCLRVERSION, + INSTR_TSQL_SERVERPROPERTY_COLLATION, + INSTR_TSQL_SERVERPROPERTY_COLLATIONID, + INSTR_UNSUPPORTED_TSQL_SERVERPROPERTY_COMPARISON_STYLE, + INSTR_UNSUPPORTED_TSQL_SERVERPROPERTY_COMPUTERNAME_PHYSICAL_NETBIOS, + INSTR_TSQL_SERVERPROPERTY_EDITION, + INSTR_TSQL_SERVERPROPERTY_EDITIONID, + INSTR_UNSUPPORTED_TSQL_SERVERPROPERTY_ENGINE_EDITION, + INSTR_UNSUPPORTED_TSQL_SERVERPROPERTY_HADR_MANAGER_STATUS, + INSTR_UNSUPPORTED_TSQL_SERVERPROPERTY_INSTANCE_DEFAULT_PATH, + INSTR_UNSUPPORTED_TSQL_SERVERPROPERTY_INSTANCE_DEFAULT_LOG_PATH, + INSTR_UNSUPPORTED_TSQL_SERVERPROPERTY_INSTANCE_NAME, + INSTR_UNSUPPORTED_TSQL_SERVERPROPERTY_IS_ADVANCED_ANALYTICS_INSTALLED, + INSTR_UNSUPPORTED_TSQL_SERVERPROPERTY_IS_BIG_DATA_CLUSTER, + INSTR_UNSUPPORTED_TSQL_SERVERPROPERTY_IS_CLUSTERED, + INSTR_UNSUPPORTED_TSQL_SERVERPROPERTY_IS_FULL_TEXT_INSTALLED, + INSTR_UNSUPPORTED_TSQL_SERVERPROPERTY_IS_HADR_ENABLED, + INSTR_UNSUPPORTED_TSQL_SERVERPROPERTY_IS_INTEGRATED_SECURITY, + INSTR_UNSUPPORTED_TSQL_SERVERPROPERTY_IS_LOCAL_DB, + INSTR_UNSUPPORTED_TSQL_SERVERPROPERTY_IS_POLYBASE_INSTALLED, + INSTR_TSQL_SERVERPROPERTY_IS_SINGLE_USER, + INSTR_UNSUPPORTED_TSQL_SERVERPROPERTY_IS_XTP_SUPPORTED, + INSTR_UNSUPPORTED_TSQL_SERVERPROPERTY_LCID, + INSTR_UNSUPPORTED_TSQL_SERVERPROPERTY_LICENSE_TYPE, + INSTR_TSQL_XACT_STATE, + + INSTR_TSQL_TRANCOUNT, + INSTR_TSQL_ERROR, + INSTR_UNSUPPORTED_TSQL_PROCID, + INSTR_TSQL_VERSION, + INSTR_TSQL_SERVERNAME, + + INSTR_UNSUPPORTED_TSQL_OPTION_ROWCOUNT, + INSTR_TSQL_FETCH_STATUS, + + INSTR_TSQL_TRY_CATCH_BLOCK, + INSTR_TSQL_TRY_BLOCK, + INSTR_TSQL_CATCH_BLOCK, + INSTR_TSQL_GOTO_STMT, + + INSTR_TSQL_INIT_TSQL_COERCE_HASH_TAB, + INSTR_TSQL_INIT_TSQL_DATATYPE_PRECEDENCE_HASH_TAB, + INSTR_TSQL_DTRUNCI8, + INSTR_TSQL_DTRUNCI4, + INSTR_TSQL_DTRUNCI2, + INSTR_TSQL_FTRUNCI8, + INSTR_TSQL_FTRUNCI4, + INSTR_TSQL_FTRUNCI2, + + INSTR_TSQL_SP_EXECUTESQL, + INSTR_TSQL_SP_PREPARE, + INSTR_TSQL_SP_UNPREPARE, + INSTR_TSQL_SP_GETAPPLOCK, + INSTR_TSQL_SP_RELEASEAPPLOCK, + INSTR_TSQL_SP_REMOVEAPPLOCKCACHE, + + INSTR_TSQL_ISOLATION_LEVEL_READ_UNCOMMITTED, + INSTR_TSQL_ISOLATION_LEVEL_READ_COMMITTED, + INSTR_UNSUPPORTED_TSQL_ISOLATION_LEVEL_REPEATABLE_READ, + INSTR_TSQL_ISOLATION_LEVEL_SNAPSHOT, + INSTR_UNSUPPORTED_TSQL_ISOLATION_LEVEL_SERIALIZABLE, + + INSTR_TSQL_COUNT +} PgTsqlInstrMetricType; + +#endif diff --git a/contrib/babelfishpg_common/src/numeric.c b/contrib/babelfishpg_common/src/numeric.c new file mode 100644 index 00000000000..3cab6709a06 --- /dev/null +++ b/contrib/babelfishpg_common/src/numeric.c @@ -0,0 +1,1031 @@ +/*------------------------------------------------------------------------- + * + * numeric.c + * An exact numeric data type for the Postgres database system + * + * Original coding 1998, Jan Wieck. Heavily revised 2003, Tom Lane. + * + * Many of the algorithmic ideas are borrowed from David M. Smith's "FM" + * multiple-precision math library, most recently published as Algorithm + * 786: Multiple-Precision Complex Arithmetic and Functions, ACM + * Transactions on Mathematical Software, Vol. 24, No. 4, December 1998, + * pages 359-367. + * + * Copyright (c) 1998-2018, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/backend/utils/adt/numeric.c + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" +#include "fmgr.h" + +#include +#include +#include +#include + +#include "access/hash.h" +#include "catalog/pg_type.h" +#include "common/int.h" +#include "funcapi.h" +#include "lib/hyperloglog.h" +#include "libpq/pqformat.h" +#include "miscadmin.h" +#include "nodes/nodeFuncs.h" +#include "utils/array.h" +#include "utils/builtins.h" +#include "utils/guc.h" +#include "utils/int8.h" +#include "utils/numeric.h" +#include "utils/sortsupport.h" + +#include "numeric.h" + +/* ---------- + * Uncomment the following to enable compilation of dump_numeric() + * and dump_var() and to get a dump of any result produced by make_result(). + * ---------- +#define NUMERIC_DEBUG + */ + + +/* ---------- + * Local data types + * + * Numeric values are represented in a base-NBASE floating point format. + * Each "digit" ranges from 0 to NBASE-1. The type NumericDigit is signed + * and wide enough to store a digit. We assume that NBASE*NBASE can fit in + * an int. Although the purely calculational routines could handle any even + * NBASE that's less than sqrt(INT_MAX), in practice we are only interested + * in NBASE a power of ten, so that I/O conversions and decimal rounding + * are easy. Also, it's actually more efficient if NBASE is rather less than + * sqrt(INT_MAX), so that there is "headroom" for mul_var and div_var_fast to + * postpone processing carries. + * + * Values of NBASE other than 10000 are considered of historical interest only + * and are no longer supported in any sense; no mechanism exists for the client + * to discover the base, so every client supporting binary mode expects the + * base-10000 format. If you plan to change this, also note the numeric + * abbreviation code, which assumes NBASE=10000. + * ---------- + */ + +#if 0 +#define NBASE 10 +#define HALF_NBASE 5 +#define DEC_DIGITS 1 /* decimal digits per NBASE digit */ +#define MUL_GUARD_DIGITS 4 /* these are measured in NBASE digits */ +#define DIV_GUARD_DIGITS 8 + +typedef signed char NumericDigit; +#endif + +#if 0 +#define NBASE 100 +#define HALF_NBASE 50 +#define DEC_DIGITS 2 /* decimal digits per NBASE digit */ +#define MUL_GUARD_DIGITS 3 /* these are measured in NBASE digits */ +#define DIV_GUARD_DIGITS 6 + +typedef signed char NumericDigit; +#endif + +#if 1 +#define NBASE 10000 +#define HALF_NBASE 5000 +#define DEC_DIGITS 4 /* decimal digits per NBASE digit */ +#define MUL_GUARD_DIGITS 2 /* these are measured in NBASE digits */ +#define DIV_GUARD_DIGITS 4 + +typedef int16 NumericDigit; +#endif + +/* + * The Numeric type as stored on disk. + * + * If the high bits of the first word of a NumericChoice (n_header, or + * n_short.n_header, or n_long.n_sign_dscale) are NUMERIC_SHORT, then the + * numeric follows the NumericShort format; if they are NUMERIC_POS or + * NUMERIC_NEG, it follows the NumericLong format. If they are NUMERIC_NAN, + * it is a NaN. We currently always store a NaN using just two bytes (i.e. + * only n_header), but previous releases used only the NumericLong format, + * so we might find 4-byte NaNs on disk if a database has been migrated using + * pg_upgrade. In either case, when the high bits indicate a NaN, the + * remaining bits are never examined. Currently, we always initialize these + * to zero, but it might be possible to use them for some other purpose in + * the future. + * + * In the NumericShort format, the remaining 14 bits of the header word + * (n_short.n_header) are allocated as follows: 1 for sign (positive or + * negative), 6 for dynamic scale, and 7 for weight. In practice, most + * commonly-encountered values can be represented this way. + * + * In the NumericLong format, the remaining 14 bits of the header word + * (n_long.n_sign_dscale) represent the display scale; and the weight is + * stored separately in n_weight. + * + * NOTE: by convention, values in the packed form have been stripped of + * all leading and trailing zero digits (where a "digit" is of base NBASE). + * In particular, if the value is zero, there will be no digits at all! + * The weight is arbitrary in that case, but we normally set it to zero. + */ + +struct NumericShort +{ + uint16 n_header; /* Sign + display scale + weight */ + NumericDigit n_data[FLEXIBLE_ARRAY_MEMBER]; /* Digits */ +}; + +struct NumericLong +{ + uint16 n_sign_dscale; /* Sign + display scale */ + int16 n_weight; /* Weight of 1st digit */ + NumericDigit n_data[FLEXIBLE_ARRAY_MEMBER]; /* Digits */ +}; + +union NumericChoice +{ + uint16 n_header; /* Header word */ + struct NumericLong n_long; /* Long form (4-byte header) */ + struct NumericShort n_short; /* Short form (2-byte header) */ +}; + +struct NumericData +{ + int32 vl_len_; /* varlena header (do not touch directly!) */ + union NumericChoice choice; /* choice of format */ +}; + + +/* + * Interpretation of high bits. + */ + +#define NUMERIC_SIGN_MASK 0xC000 +#define NUMERIC_POS 0x0000 +#define NUMERIC_NEG 0x4000 +#define NUMERIC_SHORT 0x8000 +#define NUMERIC_NAN 0xC000 + +#define NUMERIC_FLAGBITS(n) ((n)->choice.n_header & NUMERIC_SIGN_MASK) +#define NUMERIC_IS_NAN(n) (NUMERIC_FLAGBITS(n) == NUMERIC_NAN) +#define NUMERIC_IS_SHORT(n) (NUMERIC_FLAGBITS(n) == NUMERIC_SHORT) + +#define NUMERIC_HDRSZ (VARHDRSZ + sizeof(uint16) + sizeof(int16)) +#define NUMERIC_HDRSZ_SHORT (VARHDRSZ + sizeof(uint16)) + +/* + * If the flag bits are NUMERIC_SHORT or NUMERIC_NAN, we want the short header; + * otherwise, we want the long one. Instead of testing against each value, we + * can just look at the high bit, for a slight efficiency gain. + */ +#define NUMERIC_HEADER_IS_SHORT(n) (((n)->choice.n_header & 0x8000) != 0) +#define NUMERIC_HEADER_SIZE(n) \ + (VARHDRSZ + sizeof(uint16) + \ + (NUMERIC_HEADER_IS_SHORT(n) ? 0 : sizeof(int16))) + +/* + * Short format definitions. + */ + +#define NUMERIC_SHORT_SIGN_MASK 0x2000 +#define NUMERIC_SHORT_DSCALE_MASK 0x1F80 +#define NUMERIC_SHORT_DSCALE_SHIFT 7 +#define NUMERIC_SHORT_DSCALE_MAX \ + (NUMERIC_SHORT_DSCALE_MASK >> NUMERIC_SHORT_DSCALE_SHIFT) +#define NUMERIC_SHORT_WEIGHT_SIGN_MASK 0x0040 +#define NUMERIC_SHORT_WEIGHT_MASK 0x003F +#define NUMERIC_SHORT_WEIGHT_MAX NUMERIC_SHORT_WEIGHT_MASK +#define NUMERIC_SHORT_WEIGHT_MIN (-(NUMERIC_SHORT_WEIGHT_MASK+1)) + +/* + * Extract sign, display scale, weight. + */ + +#define NUMERIC_DSCALE_MASK 0x3FFF + +#define NUMERIC_SIGN(n) \ + (NUMERIC_IS_SHORT(n) ? \ + (((n)->choice.n_short.n_header & NUMERIC_SHORT_SIGN_MASK) ? \ + NUMERIC_NEG : NUMERIC_POS) : NUMERIC_FLAGBITS(n)) +#define NUMERIC_DSCALE(n) (NUMERIC_HEADER_IS_SHORT((n)) ? \ + ((n)->choice.n_short.n_header & NUMERIC_SHORT_DSCALE_MASK) \ + >> NUMERIC_SHORT_DSCALE_SHIFT \ + : ((n)->choice.n_long.n_sign_dscale & NUMERIC_DSCALE_MASK)) +#define NUMERIC_WEIGHT(n) (NUMERIC_HEADER_IS_SHORT((n)) ? \ + (((n)->choice.n_short.n_header & NUMERIC_SHORT_WEIGHT_SIGN_MASK ? \ + ~NUMERIC_SHORT_WEIGHT_MASK : 0) \ + | ((n)->choice.n_short.n_header & NUMERIC_SHORT_WEIGHT_MASK)) \ + : ((n)->choice.n_long.n_weight)) + +/* ---------- + * NumericVar is the format we use for arithmetic. The digit-array part + * is the same as the NumericData storage format, but the header is more + * complex. + * + * The value represented by a NumericVar is determined by the sign, weight, + * ndigits, and digits[] array. + * + * Note: the first digit of a NumericVar's value is assumed to be multiplied + * by NBASE ** weight. Another way to say it is that there are weight+1 + * digits before the decimal point. It is possible to have weight < 0. + * + * buf points at the physical start of the palloc'd digit buffer for the + * NumericVar. digits points at the first digit in actual use (the one + * with the specified weight). We normally leave an unused digit or two + * (preset to zeroes) between buf and digits, so that there is room to store + * a carry out of the top digit without reallocating space. We just need to + * decrement digits (and increment weight) to make room for the carry digit. + * (There is no such extra space in a numeric value stored in the database, + * only in a NumericVar in memory.) + * + * If buf is NULL then the digit buffer isn't actually palloc'd and should + * not be freed --- see the constants below for an example. + * + * dscale, or display scale, is the nominal precision expressed as number + * of digits after the decimal point (it must always be >= 0 at present). + * dscale may be more than the number of physically stored fractional digits, + * implying that we have suppressed storage of significant trailing zeroes. + * It should never be less than the number of stored digits, since that would + * imply hiding digits that are present. NOTE that dscale is always expressed + * in *decimal* digits, and so it may correspond to a fractional number of + * base-NBASE digits --- divide by DEC_DIGITS to convert to NBASE digits. + * + * rscale, or result scale, is the target precision for a computation. + * Like dscale it is expressed as number of *decimal* digits after the decimal + * point, and is always >= 0 at present. + * Note that rscale is not stored in variables --- it's figured on-the-fly + * from the dscales of the inputs. + * + * While we consistently use "weight" to refer to the base-NBASE weight of + * a numeric value, it is convenient in some scale-related calculations to + * make use of the base-10 weight (ie, the approximate log10 of the value). + * To avoid confusion, such a decimal-units weight is called a "dweight". + * + * NB: All the variable-level functions are written in a style that makes it + * possible to give one and the same variable as argument and destination. + * This is feasible because the digit buffer is separate from the variable. + * ---------- + */ +typedef struct NumericVar +{ + int ndigits; /* # of digits in digits[] - can be 0! */ + int weight; /* weight of first digit */ + int sign; /* NUMERIC_POS, NUMERIC_NEG, or NUMERIC_NAN */ + int dscale; /* display scale */ + NumericDigit *buf; /* start of palloc'd space for digits[] */ + NumericDigit *digits; /* base-NBASE digits */ +} NumericVar; + + +/* ---------- + * Data for generate_series + * ---------- + */ +typedef struct +{ + NumericVar current; + NumericVar stop; + NumericVar step; +} generate_series_numeric_fctx; + + +/* ---------- + * Sort support. + * ---------- + */ +typedef struct +{ + void *buf; /* buffer for short varlenas */ + int64 input_count; /* number of non-null values seen */ + bool estimating; /* true if estimating cardinality */ + + hyperLogLogState abbr_card; /* cardinality estimator */ +} NumericSortSupport; + + +/* ---------- + * Fast sum accumulator. + * + * NumericSumAccum is used to implement SUM(), and other standard aggregates + * that track the sum of input values. It uses 32-bit integers to store the + * digits, instead of the normal 16-bit integers (with NBASE=10000). This + * way, we can safely accumulate up to NBASE - 1 values without propagating + * carry, before risking overflow of any of the digits. 'num_uncarried' + * tracks how many values have been accumulated without propagating carry. + * + * Positive and negative values are accumulated separately, in 'pos_digits' + * and 'neg_digits'. This is simpler and faster than deciding whether to add + * or subtract from the current value, for each new value (see sub_var() for + * the logic we avoid by doing this). Both buffers are of same size, and + * have the same weight and scale. In accum_sum_final(), the positive and + * negative sums are added together to produce the final result. + * + * When a new value has a larger ndigits or weight than the accumulator + * currently does, the accumulator is enlarged to accommodate the new value. + * We normally have one zero digit reserved for carry propagation, and that + * is indicated by the 'have_carry_space' flag. When accum_sum_carry() uses + * up the reserved digit, it clears the 'have_carry_space' flag. The next + * call to accum_sum_add() will enlarge the buffer, to make room for the + * extra digit, and set the flag again. + * + * To initialize a new accumulator, simply reset all fields to zeros. + * + * The accumulator does not handle NaNs. + * ---------- + */ +typedef struct NumericSumAccum +{ + int ndigits; + int weight; + int dscale; + int num_uncarried; + bool have_carry_space; + int32 *pos_digits; + int32 *neg_digits; +} NumericSumAccum; + + +/* + * We define our own macros for packing and unpacking abbreviated-key + * representations for numeric values in order to avoid depending on + * USE_FLOAT8_BYVAL. The type of abbreviation we use is based only on + * the size of a datum, not the argument-passing convention for float8. + */ +#define NUMERIC_ABBREV_BITS (SIZEOF_DATUM * BITS_PER_BYTE) +#if SIZEOF_DATUM == 8 +#define NumericAbbrevGetDatum(X) ((Datum) (X)) +#define DatumGetNumericAbbrev(X) ((int64) (X)) +#define NUMERIC_ABBREV_NAN NumericAbbrevGetDatum(PG_INT64_MIN) +#else +#define NumericAbbrevGetDatum(X) ((Datum) (X)) +#define DatumGetNumericAbbrev(X) ((int32) (X)) +#define NUMERIC_ABBREV_NAN NumericAbbrevGetDatum(PG_INT32_MIN) +#endif + +/* ---------- + * Local functions + * ---------- + */ + +#ifdef NUMERIC_DEBUG +static void dump_numeric(const char *str, Numeric num); +static void dump_var(const char *str, NumericVar *var); +#else +#define dump_numeric(s,n) +#define dump_var(s,v) +#endif + +#define digitbuf_alloc(ndigits) \ + ((NumericDigit *) palloc((ndigits) * sizeof(NumericDigit))) +#define digitbuf_free(buf) \ + do { \ + if ((buf) != NULL) \ + pfree(buf); \ + } while (0) + +#define init_var(v) MemSetAligned(v, 0, sizeof(NumericVar)) + +#define NUMERIC_DIGITS(num) (NUMERIC_HEADER_IS_SHORT(num) ? \ + (num)->choice.n_short.n_data : (num)->choice.n_long.n_data) +#define NUMERIC_NDIGITS(num) \ + ((VARSIZE(num) - NUMERIC_HEADER_SIZE(num)) / sizeof(NumericDigit)) +#define NUMERIC_CAN_BE_SHORT(scale,weight) \ + ((scale) <= NUMERIC_SHORT_DSCALE_MAX && \ + (weight) <= NUMERIC_SHORT_WEIGHT_MAX && \ + (weight) >= NUMERIC_SHORT_WEIGHT_MIN) + +static const NumericVar const_nan = +{0, 0, NUMERIC_NAN, 0, NULL, NULL}; +#if DEC_DIGITS == 4 +static const int round_powers[4] = {0, 1000, 100, 10}; +#endif + +PG_FUNCTION_INFO_V1(tsql_numeric_round); +PG_FUNCTION_INFO_V1(tsql_numeric_trunc); + +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); +static Numeric make_result(const NumericVar *var); +static void strip_var(NumericVar *var); + +/* ---------------------------------------------------------------------- + * + * Local functions follow + * + * In general, these do not support NaNs --- callers must eliminate + * the possibility of NaN first. (make_result() is an exception.) + * + * ---------------------------------------------------------------------- + */ + + +/* + * alloc_var() - + * + * Allocate a digit buffer of ndigits digits (plus a spare digit for rounding) + */ +static void +alloc_var(NumericVar *var, int ndigits) +{ + digitbuf_free(var->buf); + var->buf = digitbuf_alloc(ndigits + 1); + var->buf[0] = 0; /* spare digit for rounding */ + var->digits = var->buf + 1; + var->ndigits = ndigits; +} + + +/* + * free_var() - + * + * Return the digit buffer of a variable to the free pool + */ +static void +free_var(NumericVar *var) +{ + digitbuf_free(var->buf); + var->buf = NULL; + var->digits = NULL; + var->sign = NUMERIC_NAN; +} + +/* + * set_var_from_str() + * + * Parse a string and put the number into a variable + * + * This function does not handle leading or trailing spaces, and it doesn't + * accept "NaN" either. It returns the end+1 position so that caller can + * check for trailing spaces/garbage if deemed necessary. + * + * cp is the place to actually start parsing; str is what to use in error + * reports. (Typically cp would be the same except advanced over spaces.) + */ +static const char * +set_var_from_str(const char *str, const char *cp, NumericVar *dest) +{ + bool have_dp = false; + int i; + unsigned char *decdigits; + int sign = NUMERIC_POS; + int dweight = -1; + int ddigits; + int dscale = 0; + int weight; + int ndigits; + int offset; + NumericDigit *digits; + + /* + * We first parse the string to extract decimal digits and determine the + * correct decimal weight. Then convert to NBASE representation. + */ + switch (*cp) + { + case '+': + sign = NUMERIC_POS; + cp++; + break; + + case '-': + sign = NUMERIC_NEG; + cp++; + break; + } + + if (*cp == '.') + { + have_dp = true; + cp++; + } + + if (!isdigit((unsigned char) *cp)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for type %s: \"%s\"", + "numeric", str))); + + decdigits = (unsigned char *) palloc(strlen(cp) + DEC_DIGITS * 2); + + /* leading padding for digit alignment later */ + memset(decdigits, 0, DEC_DIGITS); + i = DEC_DIGITS; + + while (*cp) + { + if (isdigit((unsigned char) *cp)) + { + decdigits[i++] = *cp++ - '0'; + if (!have_dp) + dweight++; + else + dscale++; + } + else if (*cp == '.') + { + if (have_dp) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for type %s: \"%s\"", + "numeric", str))); + have_dp = true; + cp++; + } + else + break; + } + + ddigits = i - DEC_DIGITS; + /* trailing padding for digit alignment later */ + memset(decdigits + i, 0, DEC_DIGITS - 1); + + /* Handle exponent, if any */ + if (*cp == 'e' || *cp == 'E') + { + long exponent; + char *endptr; + + cp++; + exponent = strtol(cp, &endptr, 10); + if (endptr == cp) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for type %s: \"%s\"", + "numeric", str))); + cp = endptr; + + /* + * At this point, dweight and dscale can't be more than about + * INT_MAX/2 due to the MaxAllocSize limit on string length, so + * constraining the exponent similarly should be enough to prevent + * integer overflow in this function. If the value is too large to + * fit in storage format, make_result() will complain about it later; + * for consistency use the same ereport errcode/text as make_result(). + */ + if (exponent >= INT_MAX / 2 || exponent <= -(INT_MAX / 2)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("value overflows numeric format"))); + dweight += (int) exponent; + dscale -= (int) exponent; + if (dscale < 0) + dscale = 0; + } + + /* + * Okay, convert pure-decimal representation to base NBASE. First we need + * to determine the converted weight and ndigits. offset is the number of + * decimal zeroes to insert before the first given digit to have a + * correctly aligned first NBASE digit. + */ + if (dweight >= 0) + weight = (dweight + 1 + DEC_DIGITS - 1) / DEC_DIGITS - 1; + else + weight = -((-dweight - 1) / DEC_DIGITS + 1); + offset = (weight + 1) * DEC_DIGITS - (dweight + 1); + ndigits = (ddigits + offset + DEC_DIGITS - 1) / DEC_DIGITS; + + alloc_var(dest, ndigits); + dest->sign = sign; + dest->weight = weight; + dest->dscale = dscale; + + i = DEC_DIGITS - offset; + digits = dest->digits; + + while (ndigits-- > 0) + { +#if DEC_DIGITS == 4 + *digits++ = ((decdigits[i] * 10 + decdigits[i + 1]) * 10 + + decdigits[i + 2]) * 10 + decdigits[i + 3]; +#elif DEC_DIGITS == 2 + *digits++ = decdigits[i] * 10 + decdigits[i + 1]; +#elif DEC_DIGITS == 1 + *digits++ = decdigits[i]; +#else +#error unsupported NBASE +#endif + i += DEC_DIGITS; + } + + pfree(decdigits); + + /* Strip any leading/trailing zeroes, and normalize weight if zero */ + strip_var(dest); + + /* Return end+1 position for caller */ + return cp; +} + +/* + * make_result() - + * + * Create the packed db numeric format in palloc()'d memory from + * a variable. + */ +static Numeric +make_result(const NumericVar *var) +{ + Numeric result; + NumericDigit *digits = var->digits; + int weight = var->weight; + int sign = var->sign; + int n; + Size len; + + if (sign == NUMERIC_NAN) + { + result = (Numeric) palloc(NUMERIC_HDRSZ_SHORT); + + SET_VARSIZE(result, NUMERIC_HDRSZ_SHORT); + result->choice.n_header = NUMERIC_NAN; + /* the header word is all we need */ + + dump_numeric("make_result()", result); + return result; + } + + n = var->ndigits; + + /* truncate leading zeroes */ + while (n > 0 && *digits == 0) + { + digits++; + weight--; + n--; + } + /* truncate trailing zeroes */ + while (n > 0 && digits[n - 1] == 0) + n--; + + /* If zero result, force to weight=0 and positive sign */ + if (n == 0) + { + weight = 0; + sign = NUMERIC_POS; + } + + /* Build the result */ + if (NUMERIC_CAN_BE_SHORT(var->dscale, weight)) + { + len = NUMERIC_HDRSZ_SHORT + n * sizeof(NumericDigit); + result = (Numeric) palloc(len); + SET_VARSIZE(result, len); + result->choice.n_short.n_header = + (sign == NUMERIC_NEG ? (NUMERIC_SHORT | NUMERIC_SHORT_SIGN_MASK) + : NUMERIC_SHORT) + | (var->dscale << NUMERIC_SHORT_DSCALE_SHIFT) + | (weight < 0 ? NUMERIC_SHORT_WEIGHT_SIGN_MASK : 0) + | (weight & NUMERIC_SHORT_WEIGHT_MASK); + } + else + { + len = NUMERIC_HDRSZ + n * sizeof(NumericDigit); + result = (Numeric) palloc(len); + SET_VARSIZE(result, len); + result->choice.n_long.n_sign_dscale = + sign | (var->dscale & NUMERIC_DSCALE_MASK); + result->choice.n_long.n_weight = weight; + } + + Assert(NUMERIC_NDIGITS(result) == n); + if (n > 0) + memcpy(NUMERIC_DIGITS(result), digits, n * sizeof(NumericDigit)); + + /* Check for overflow of int16 fields */ + if (NUMERIC_WEIGHT(result) != weight || + NUMERIC_DSCALE(result) != var->dscale) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("value overflows numeric format"))); + + dump_numeric("make_result()", result); + return result; +} + +/* + * strip_var + * + * Strip any leading and trailing zeroes from a numeric variable + */ +static void +strip_var(NumericVar *var) +{ + NumericDigit *digits = var->digits; + int ndigits = var->ndigits; + + /* Strip leading zeroes */ + while (ndigits > 0 && *digits == 0) + { + digits++; + var->weight--; + ndigits--; + } + + /* Strip trailing zeroes */ + while (ndigits > 0 && digits[ndigits - 1] == 0) + ndigits--; + + /* If it's zero, normalize the sign and weight */ + if (ndigits == 0) + { + var->sign = NUMERIC_POS; + var->weight = 0; + } + + var->digits = digits; + var->ndigits = ndigits; +} + +/* + * Converts input string to numeric value in TDS receiver side + */ +Numeric +tsql_set_var_from_str_wrapper(const char *str) +{ + NumericVar value; + Numeric res; + init_var(&value); + set_var_from_str(str, str, &value); + res = make_result(&value); + free_var(&value); + return res; +} + +/* + * set_var_from_num() - + * Set NumericVar from Numeric + */ +static void +set_var_from_num(Numeric num, NumericVar *dest) +{ + int ndigits; + + ndigits = NUMERIC_NDIGITS(num); + + alloc_var(dest, ndigits); + + dest->weight = NUMERIC_WEIGHT(num); + dest->sign = NUMERIC_SIGN(num); + dest->dscale = NUMERIC_DSCALE(num); + + memcpy(dest->digits, NUMERIC_DIGITS(num), ndigits * sizeof(NumericDigit)); +} + + +/* + * tsql_round_var + * + * This function is similar to round_var, + * but we check if rounding up will cause an overflow + */ +static void +tsql_round_var(NumericVar *var, int rscale) +{ + NumericDigit *digits = var->digits; + int di; + int ndigits; + int carry; + + var->dscale = rscale; + + /* decimal digits wanted */ + di = (var->weight + 1) * DEC_DIGITS + rscale; + + /* checking numeric overflow for TSQL */ + if (rscale < 0) + { + int integral_digits = di - DEC_DIGITS; + int leading_digits = digits[0]; + static const int32 timescales[DEC_DIGITS] = { + 1000, + 100, + 10, + 1, + }; + + for(int i = 0; i < DEC_DIGITS; i++) + { + if(leading_digits >= timescales[i]) + { + integral_digits += (4-i); + break; + } + } + /* Overflow when rounding up*/ + if (integral_digits == 0) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("value overflows for numeric format"))); + /* should lose all digits */ + else if (integral_digits < 0) + di = -1; + } + + /* + * If di < 0, the value loses all digits + */ + if (di < 0) + { + var->ndigits = 0; + var->weight = 0; + var->sign = NUMERIC_POS; + } + else + { + /* NBASE digits wanted */ + ndigits = (di + DEC_DIGITS - 1) / DEC_DIGITS; + + /* 0, or number of decimal digits to keep in last NBASE digit */ + di %= DEC_DIGITS; + + if (ndigits < var->ndigits || + (ndigits == var->ndigits && di > 0)) + { + var->ndigits = ndigits; + +#if DEC_DIGITS == 1 + /* di must be zero */ + carry = (digits[ndigits] >= HALF_NBASE) ? 1 : 0; +#else + if (di == 0) + carry = (digits[ndigits] >= HALF_NBASE) ? 1 : 0; + else + { + /* Must round within last NBASE digit */ + int extra, + pow10; + +#if DEC_DIGITS == 4 + pow10 = round_powers[di]; +#elif DEC_DIGITS == 2 + pow10 = 10; +#else +#error unsupported NBASE +#endif + extra = digits[--ndigits] % pow10; + digits[ndigits] -= extra; + carry = 0; + if (extra >= pow10 / 2) + { + pow10 += digits[ndigits]; + if (pow10 >= NBASE) + { + pow10 -= NBASE; + carry = 1; + } + digits[ndigits] = pow10; + } + } +#endif + + /* Propagate carry if needed */ + while (carry) + { + carry += digits[--ndigits]; + if (carry >= NBASE) + { + digits[ndigits] = carry - NBASE; + carry = 1; + } + else + { + digits[ndigits] = carry; + carry = 0; + } + } + + if (ndigits < 0) + { + Assert(ndigits == -1); /* better not have added > 1 digit */ + Assert(var->digits > var->buf); + var->digits--; + var->ndigits++; + var->weight++; + } + } + } +} + +/* + * tsql_numeric_round() - + * + * compared to numeric_round(), we handle NULL input parameter in this function, + * and calls tsql_round_var() for rounding + */ +Datum +tsql_numeric_round(PG_FUNCTION_ARGS) +{ + Numeric num; + int32 scale; + Numeric res; + NumericVar arg; + /* when num or scale is NULL, return NULL */ + if(PG_ARGISNULL(0) || PG_ARGISNULL(1)) + PG_RETURN_NULL(); + + num = PG_GETARG_NUMERIC(0); + scale = PG_GETARG_INT32(1); + + /* + * Handle NaN + */ + if (NUMERIC_IS_NAN(num)) + PG_RETURN_NUMERIC(make_result(&const_nan)); + + /* + * Limit the scale value to avoid possible overflow in calculations + */ + scale = Max(scale, -NUMERIC_MAX_RESULT_SCALE); + scale = Min(scale, NUMERIC_MAX_RESULT_SCALE); + + /* + * Unpack the argument and round it at the proper digit position + */ + init_var(&arg); + set_var_from_num(num, &arg); + + tsql_round_var(&arg, scale); + + /* We don't allow negative output dscale */ + if (scale < 0) + arg.dscale = 0; + + /* + * Return the rounded result + */ + res = make_result(&arg); + + free_var(&arg); + PG_RETURN_NUMERIC(res); +} + +/* + * tsql_numeric_round() - + * + * Directly call numeric_trunc() or + * call tsql_numeric_round() when 'function' is 0 or null +*/ +Datum +tsql_numeric_trunc(PG_FUNCTION_ARGS) +{ + Numeric num; + int32 scale ; + /* when num or scale is NULL, return NULL */ + 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) + return DirectFunctionCall2(tsql_numeric_round, + NumericGetDatum(num), + Int32GetDatum(scale)); + + + return DirectFunctionCall2(numeric_trunc, + 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; + + if (weight >= 0) + { + static const int32 timescales[DEC_DIGITS] = { + 1000, + 100, + 10, + 1, + }; + int leading_digits = NUMERIC_DIGITS(num)[0]; + precision = weight * DEC_DIGITS + scale; + + for(int i = 0; i < DEC_DIGITS; i++) + { + if(leading_digits >= timescales[i]) + { + precision += (4-i); + break; + } + } + } + else + /* weight < 0 means the integral part of the number is 0 */ + precision = 1 + scale; + + return (((precision & 0xFFFF) << 16 ) | (scale & 0xFFFF)) + VARHDRSZ; +} diff --git a/contrib/babelfishpg_common/src/numeric.h b/contrib/babelfishpg_common/src/numeric.h new file mode 100644 index 00000000000..19cccc238ff --- /dev/null +++ b/contrib/babelfishpg_common/src/numeric.h @@ -0,0 +1,9 @@ +#ifndef NUMERIC_H +#define NUMERIC_H + +#include "utils/numeric.h" + +extern Numeric tsql_set_var_from_str_wrapper(const char *str); +extern int32_t tsql_numeric_get_typmod(Numeric num); + +#endif diff --git a/contrib/babelfishpg_common/src/smalldatetime.c b/contrib/babelfishpg_common/src/smalldatetime.c new file mode 100644 index 00000000000..9596dcf0f39 --- /dev/null +++ b/contrib/babelfishpg_common/src/smalldatetime.c @@ -0,0 +1,594 @@ +/*------------------------------------------------------------------------- + * + * smalldatetime.c + * Functions for the type "smalldatetime". + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "fmgr.h" +#include "utils/builtins.h" +#include "utils/date.h" +#include "utils/datetime.h" +#include "utils/timestamp.h" + +#include "miscadmin.h" + +PG_FUNCTION_INFO_V1(smalldatetime_in); +PG_FUNCTION_INFO_V1(smalldatetime_recv); +PG_FUNCTION_INFO_V1(time_smalldatetime); +PG_FUNCTION_INFO_V1(date_smalldatetime); +PG_FUNCTION_INFO_V1(timestamp_smalldatetime); +PG_FUNCTION_INFO_V1(timestamptz_smalldatetime); +PG_FUNCTION_INFO_V1(smalldatetime_varchar); +PG_FUNCTION_INFO_V1(varchar_smalldatetime); +PG_FUNCTION_INFO_V1(smalldatetime_char); +PG_FUNCTION_INFO_V1(char_smalldatetime); + +PG_FUNCTION_INFO_V1(smalldatetime_pl_int4); +PG_FUNCTION_INFO_V1(int4_mi_smalldatetime); +PG_FUNCTION_INFO_V1(int4_pl_smalldatetime); +PG_FUNCTION_INFO_V1(smalldatetime_mi_int4); + +PG_FUNCTION_INFO_V1(smalldatetime_pl_float8); +PG_FUNCTION_INFO_V1(smalldatetime_mi_float8); +PG_FUNCTION_INFO_V1(float8_pl_smalldatetime); +PG_FUNCTION_INFO_V1(float8_mi_smalldatetime); + +void AdjustTimestampForSmallDatetime(Timestamp *time); +void CheckSmalldatetimeRange(const Timestamp time); +static Datum smalldatetime_in_str(char *str); + +/* smalldatetime_in_str() + * Convert a string to internal form. + * Most parts of this functions is same as timestamp_in(), + * but we use a different rounding function for smalldatetime. + */ +static Datum +smalldatetime_in_str(char *str) +{ +#ifdef NOT_USED + Oid typelem = PG_GETARG_OID(1); +#endif + Timestamp result; + fsec_t fsec; + struct pg_tm tt, + *tm = &tt; + int tz; + int dtype; + int nf; + int dterr; + char *field[MAXDATEFIELDS]; + int ftype[MAXDATEFIELDS]; + char workbuf[MAXDATELEN + MAXDATEFIELDS]; + + 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 + if (dterr == 1) + { + tm->tm_year = 1900; + tm->tm_mon = 1; + tm->tm_mday = 1; + dterr = 0; + } + if (dterr != 0) + DateTimeParseError(dterr, str, "smalldatetime"); + switch (dtype) + { + case DTK_DATE: + if (tm2timestamp(tm, fsec, NULL, &result) != 0) + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("smalldatetime out of range: \"%s\"", str))); + break; + + case DTK_EPOCH: + result = SetEpochTimestamp(); + break; + + case DTK_LATE: + TIMESTAMP_NOEND(result); + break; + + case DTK_EARLY: + TIMESTAMP_NOBEGIN(result); + break; + + default: + elog(ERROR, "unexpected dtype %d while parsing smalldatetime \"%s\"", + dtype, str); + TIMESTAMP_NOEND(result); + } + + CheckSmalldatetimeRange(result); + AdjustTimestampForSmallDatetime(&result); + + PG_RETURN_TIMESTAMP(result); +} + +/* smalldatetime_in() + * Convert a string to internal form. + * Most parts of this functions is same as timestamp_in(), + * but we use a different rounding function for smalldatetime. + */ +Datum +smalldatetime_in(PG_FUNCTION_ARGS) +{ + char *str = PG_GETARG_CSTRING(0); + + return smalldatetime_in_str(str); +} + +/* + * CheckSmalldatetimeRange --- Check if timestamp is out of range for smalldatetime + */ +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 */ + 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"))); + } +} + +/* + * AdjustTimestampForSmallDatetime --- round off a timestamp to suit smalldatetime. + * The rounding logic: if second is larger or equal to 29.999 round up, otherwise round down. + */ +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; + } + } +} + +/* time_smalldatetime() + * Convert time to smalldatetime + */ +Datum +time_smalldatetime(PG_FUNCTION_ARGS) +{ + TimeADT timeVal = PG_GETARG_TIMEADT(0); + Timestamp result; + + struct pg_tm tt, + *tm = &tt; + fsec_t fsec; + + // 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 + 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"))); + + AdjustTimestampForSmallDatetime(&result); + + PG_RETURN_TIMESTAMP(result); +} + +/* date_smalldatetime() + * Convert date to smalldatetime + */ +Datum +date_smalldatetime(PG_FUNCTION_ARGS) +{ + DateADT dateVal = PG_GETARG_DATEADT(0); + Timestamp result; + + if (DATE_IS_NOBEGIN(dateVal)) + TIMESTAMP_NOBEGIN(result); + else if (DATE_IS_NOEND(dateVal)) + TIMESTAMP_NOEND(result); + else + result = dateVal * USECS_PER_DAY; + + CheckSmalldatetimeRange(result); + PG_RETURN_TIMESTAMP(result); +} + +/* timestamp_smalldatetime() + * Convert timestamp to smalldatetime + */ +Datum +timestamp_smalldatetime(PG_FUNCTION_ARGS) +{ + Timestamp result = PG_GETARG_TIMESTAMP(0); + + CheckSmalldatetimeRange(result); + AdjustTimestampForSmallDatetime(&result); + PG_RETURN_TIMESTAMP(result); +} + +/* timestamptz_smalldatetime() + * Convert timestamptz to smalldatetime + */ +Datum +timestamptz_smalldatetime(PG_FUNCTION_ARGS) +{ + TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0); + Timestamp result; + + struct pg_tm tt, + *tm = &tt; + fsec_t fsec; + int tz; + + if (TIMESTAMP_NOT_FINITE(timestamp)) + result = timestamp; + else + { + if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0) + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("data out of range for smalldatetime"))); + if (tm2timestamp(tm, fsec, NULL, &result) != 0) + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("data out of range for smalldatetime"))); + } + CheckSmalldatetimeRange(result); + AdjustTimestampForSmallDatetime(&result); + PG_RETURN_TIMESTAMP(result); +} + +/* smalldatetime_varchar() + * Convert a smalldatetime to varchar. + * The function is the same as timestamp_out() except the return type is a VARCHAR Datum. + */ +Datum +smalldatetime_varchar(PG_FUNCTION_ARGS) +{ + Timestamp timestamp = PG_GETARG_TIMESTAMP(0); + char *s; + struct pg_tm tt, + *tm = &tt; + fsec_t fsec; + char buf[MAXDATELEN + 1]; + VarChar *result; + + if (TIMESTAMP_NOT_FINITE(timestamp)) + EncodeSpecialTimestamp(timestamp, buf); + else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0) + EncodeDateTime(tm, fsec, false, 0, NULL, DateStyle, buf); + else + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("timestamp out of range"))); + s = pstrdup(buf); + result = (VarChar *) cstring_to_text(s); + PG_RETURN_VARCHAR_P(result); +} + +/* + * varchar_smalldatetime() + * Convert a varchar to smalldatetime + */ +Datum +varchar_smalldatetime(PG_FUNCTION_ARGS) +{ + Datum txt = PG_GETARG_DATUM(0); + char *str = TextDatumGetCString(txt); + + return smalldatetime_in_str(str); +} + +/* smalldatetime_char() + * Convert a smalldatetime to char. + * The function is the same as timestamp_out() except the return type is a CHAR Datum. + */ +Datum +smalldatetime_char(PG_FUNCTION_ARGS) +{ + Timestamp timestamp = PG_GETARG_TIMESTAMP(0); + char *s; + struct pg_tm tt, + *tm = &tt; + fsec_t fsec; + char buf[MAXDATELEN + 1]; + VarChar *result; + + if (TIMESTAMP_NOT_FINITE(timestamp)) + EncodeSpecialTimestamp(timestamp, buf); + else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0) + EncodeDateTime(tm, fsec, false, 0, NULL, DateStyle, buf); + else + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("timestamp out of range"))); + s = pstrdup(buf); + result = (BpChar *) cstring_to_text(s); + PG_RETURN_BPCHAR_P(result); +} + +/* + * char_smalldatetime() + * Convert a CHAR to smalldatetime + */ +Datum +char_smalldatetime(PG_FUNCTION_ARGS) +{ + Datum txt = PG_GETARG_DATUM(0); + char *str = TextDatumGetCString(txt); + + return smalldatetime_in_str(str); +} + +/* + * 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; + + if (TIMESTAMP_NOT_FINITE(timestamp)) + PG_RETURN_TIMESTAMP(timestamp); + + /* make interval */ + input_interval = (Interval *) DirectFunctionCall7(make_interval, 0, 0, 0, days, 0, 0, 0); + + /* add interval */ + result = DirectFunctionCall2(timestamp_pl_interval, timestamp, PointerGetDatum(input_interval)); + + CheckSmalldatetimeRange(result); + PG_RETURN_TIMESTAMP(result); +} + +/* + * 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 + * above to the default smalldatetime value (1/1/1900). + * + * 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 + * result = 1/1/1900 + diff = 1899-12-31 + */ +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; + + 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); + 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 */ + result = DirectFunctionCall2(timestamp_pl_interval, default_timestamp, PointerGetDatum(result_interval)); + + CheckSmalldatetimeRange(result); + PG_RETURN_TIMESTAMP(result); +} + +/* + * int4_pl_smalldatetime() + * operator function for adding int plus smalldatetime + */ +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)); +} + +/* + * smalldatetime_mi_int4() + * operator function for subtracting smalldatetime minus int + */ +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)); +} + + +/* + * 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; + 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); + + /* make interval */ + input_interval = (Interval *) DirectFunctionCall7(make_interval, 0, 0, 0, (int32) day_whole, 0, 0, Float8GetDatum(sec_whole)); + + /* add interval */ + result = DirectFunctionCall2(timestamp_pl_interval, timestamp, PointerGetDatum(input_interval)); + + CheckSmalldatetimeRange(result); + PG_RETURN_TIMESTAMP(result); +} + + +/* + * 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 + * 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; + Timestamp result; + Timestamp default_timestamp; + Timestamp timestamp_left; + 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); + + + /* inialize input int(days) as timestamp */ + 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 */ + result = DirectFunctionCall2(timestamp_pl_interval, default_timestamp, PointerGetDatum(result_interval)); + + + CheckSmalldatetimeRange(result); + PG_RETURN_TIMESTAMP(result); +} + +/* + * float8_pl_smalldatetime() + * operator function for adding float8 plus smalldatetime + */ +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; + 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); + + /* make interval */ + input_interval = (Interval *) DirectFunctionCall7(make_interval, 0, 0, 0, (int32) day_whole, 0, 0, Float8GetDatum(sec_whole)); + + /* add interval */ + result = DirectFunctionCall2(timestamp_pl_interval, timestamp, PointerGetDatum(input_interval)); + + CheckSmalldatetimeRange(result); + PG_RETURN_TIMESTAMP(result); +} + +/* + * smalldatetime_mi_float8() + * operator function for subtracting smalldatetime minus float8 + */ +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; + 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); + + /* make interval */ + input_interval = (Interval *) DirectFunctionCall7(make_interval, 0, 0, 0, (int32) day_whole, 0, 0, Float8GetDatum(sec_whole)); + + + /* subtract interval */ + result = DirectFunctionCall2(timestamp_mi_interval, timestamp, PointerGetDatum(input_interval)); + + CheckSmalldatetimeRange(result); + PG_RETURN_TIMESTAMP(result); +} \ No newline at end of file diff --git a/contrib/babelfishpg_common/src/sqlvariant.c b/contrib/babelfishpg_common/src/sqlvariant.c new file mode 100644 index 00000000000..12e78ab841a --- /dev/null +++ b/contrib/babelfishpg_common/src/sqlvariant.c @@ -0,0 +1,2257 @@ +/*------------------------------------------------------------------------- + * + * sqlvariant.c + * Functions for the type "sql_variant". + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "executor/spi.h" +#include "fmgr.h" +#include "miscadmin.h" +#include "access/hash.h" +#include "access/htup_details.h" +#include "catalog/namespace.h" +#include "catalog/pg_authid.h" +#include "catalog/pg_collation.h" +#include "catalog/pg_database.h" +#include "catalog/pg_type.h" +#include "catalog/pg_operator.h" +#include "commands/dbcommands.h" +#include "lib/stringinfo.h" +#include "libpq/pqformat.h" +#include "port.h" +#include "utils/array.h" +#include "utils/date.h" +#include "parser/parse_coerce.h" +#include "parser/parse_oper.h" +#include "instr.h" +#include "utils/builtins.h" +#include "utils/elog.h" +#include "utils/guc.h" +#include "utils/hsearch.h" +#include "utils/lsyscache.h" +#include "utils/memutils.h" +#include "utils/numeric.h" +#include "utils/syscache.h" +#include "utils/timestamp.h" +#include "utils/uuid.h" +#include "utils/varbit.h" + +#include "datetimeoffset.h" +#include "typecode.h" +#include "numeric.h" + +/* + * macros for supporting sqlvariant datatype on TDS side + */ + +#define VARIANT_TYPE_TINYINT 48 +#define VARIANT_TYPE_BIT 50 +#define VARIANT_TYPE_SMALLINT 52 +#define VARIANT_TYPE_INT 56 +#define VARIANT_TYPE_BIGINT 127 +#define VARIANT_TYPE_REAL 59 +#define VARIANT_TYPE_FLOAT 62 +#define VARIANT_TYPE_NUMERIC 108 +#define VARIANT_TYPE_MONEY 60 +#define VARIANT_TYPE_SMALLMONEY 122 +#define VARIANT_TYPE_DATE 40 +#define VARIANT_TYPE_CHAR 175 +#define VARIANT_TYPE_VARCHAR 167 +#define VARIANT_TYPE_NCHAR 239 +#define VARIANT_TYPE_NVARCHAR 231 +#define VARIANT_TYPE_BINARY 173 +#define VARIANT_TYPE_VARBINARY 165 +#define VARIANT_TYPE_UNIQUEIDENTIFIER 36 +#define VARIANT_TYPE_TIME 41 +#define VARIANT_TYPE_SMALLDATETIME 58 +#define VARIANT_TYPE_DATETIME 61 +#define VARIANT_TYPE_DATETIME2 42 +#define VARIANT_TYPE_DATETIMEOFFSET 43 + +/* Function Registeration */ +PG_FUNCTION_INFO_V1(sqlvariantin); +PG_FUNCTION_INFO_V1(sqlvariantout); +PG_FUNCTION_INFO_V1(sqlvariantrecv); +PG_FUNCTION_INFO_V1(sqlvariantsend); + + +/* Header version + * For now, we assume that headers of all types use Header Version 1. + * However, in future we may want to define header versions for each types, + * for example we may want to store addional data for a type. + * As of now there's no use cases where we could use that. + */ +#define HDR_VER 1 + +/* Header related macros */ +#define SV_HDR_1B(PTR) ((svhdr_1B_t *) (VARDATA_ANY(PTR))) +#define SV_HDR_2B(PTR) ((svhdr_2B_t *) (VARDATA_ANY(PTR))) +#define SV_HDR_3B(PTR) ((svhdr_3B_t *) (VARDATA_ANY(PTR))) +#define SV_HDR_5B(PTR) ((svhdr_5B_t *) (VARDATA_ANY(PTR))) + +#define SV_GET_TYPCODE(HEADER) (HEADER->metadata >> 3) +#define SV_GET_TYPCODE_PTR(PTR) (SV_HDR_1B(PTR)->metadata >> 3) +#define SV_GET_MDVER(HEADER) (HEADER->metadata & 0x07) +#define SV_SET_METADATA(HEADER, TYPCODE, MDVER) (HEADER->metadata = TYPCODE << 3 | MDVER) + +#define SV_DATA(PTR, SVHDR) (VARDATA_ANY(PTR) + SVHDR) +#define SV_DATUM(PTR, SVHDR) ((Datum) (VARDATA_ANY(PTR) + SVHDR)) +#define SV_DATUM_PTR(PTR, SVHDR) ((Datum *) (VARDATA_ANY(PTR) + SVHDR)) + +#define SV_CAN_USE_SHORT_VALENA(DATALEN, SVHDR) (DATALEN + SVHDR + VARHDRSZ_SHORT <= VARATT_SHORT_MAX) + +bytea *convertVarcharToSQLVariantByteA(VarChar *vch, Oid coll); +bytea *convertIntToSQLVariantByteA(int ret); + + +/******************** Collation Utilities *************************/ + +/* match definition in babelfishpg_tsql:collation.h */ +typedef struct Tsql_collation_callbacks +{ + /* Function pointers set up by the plugin */ + Oid (*get_tsql_collation_oid_f)(int persist_coll_id); + int (*get_persist_collation_id_f)(Oid coll_oid); + int (*get_server_collation_collidx_f)(void); + int8_t (*cmp_collation_f)(uint16_t coll1, uint16_t coll2); + +} Tsql_collation_callbacks; + +Tsql_collation_callbacks *collation_callbacks_ptr = NULL; + +static void init_collation_callbacks(void); +static Oid get_tsql_collation_oid(int persist_coll_id); +static int get_persist_collation_id(Oid coll_oid); +static int get_server_collation_collidx(void); +static int8_t cmp_collation(uint16_t coll1, uint16_t coll2); + +/* extract type and coll related info*/ +extern type_info_t type_infos[]; +extern HTAB *ht_oid2collid; + + +/* + * Storage Layout of SQL_VARIANT Header + * Total length 2-9 bytes : varlena header (1-4B) + sv header (1-5B) + * Bytes are interpreted differently for different types + * WARNING: Modification on storage layout need backward compatibility support + * Place holders MUST filled with 0 to avoid ambiguity in the future + */ + +/* HDR: Basic format + * following custom of PG, typmod is stored + * It could be interpreted differently for difffernt types + * e.g + * for decimal types, precision and scale are encoded + * for datetime2, datetimeoffset it is scale + */ +typedef struct __attribute__((packed)) svhdr_1B +{ + uint8_t metadata; +} svhdr_1B_t; + +typedef struct __attribute__((packed)) svhdr_2B +{ + uint8_t metadata; + int8_t typmod; +} svhdr_2B_t; + +typedef struct __attribute__((packed)) svhdr_3B +{ + uint8_t metadata; + int16_t typmod; +} svhdr_3B_t; + +typedef struct __attribute__((packed)) svhdr_5B +{ + uint8_t metadata; + int16_t typmod; + uint16_t collid; +} svhdr_5B_t; + +/* + * SQL_VARINT does not have its own textual representation + * All supported types are expected to be cased into SQL_VARIANT + * String values are treated as VARCHAR(len) type + */ + +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; + Oid type = type_infos[VARCHAR_T].oid; /* hardcoded varchar */ + uint8_t svhdr_size = type_infos[VARCHAR_T].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); +} + +/* + * SQL_VARIANT does not have its own textual representation + * It always calls internal types's output function + */ + +Datum +sqlvariantout(PG_FUNCTION_ARGS) +{ + char *result = NULL; + bytea *vlena = PG_GETARG_BYTEA_PP(0); + uint8_t type_code = SV_GET_TYPCODE_PTR(vlena); + Oid type = (Oid) type_infos[type_code].oid; + uint8_t svhdr_size = type_infos[type_code].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); + + PG_FREE_IF_COPY(vlena, 0); + PG_RETURN_CSTRING(result); +} + +/* + * Binary representation is identical, only do memory copy in RECV/SEND functions + */ + +Datum +sqlvariantrecv(PG_FUNCTION_ARGS) +{ + StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); + bytea *result; + int nbytes; + + INSTR_METRIC_INC(INSTR_TSQL_SQLVARIANT_RECV); + + 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); + } + + 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); + + INSTR_METRIC_INC(INSTR_TSQL_SQLVARIANT_SEND); + + PG_RETURN_BYTEA_P(vlena); +} + +/* Helper functions */ +static Datum get_varchar128_sv_datum(const char *value); +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 = type_infos[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); + + /* 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); +} + +Datum +get_int_sv_datum(int32_t value) +{ + bytea *result; + svhdr_1B_t *svhdr; + uint8_t svhdr_size = type_infos[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; + + svhdr = SV_HDR_1B(result); + SV_SET_METADATA(svhdr, INT_T, HDR_VER); + + 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 compare_value(char *oprname, Oid type, Datum d1, Datum d2, Oid coll); + +static bytea* gen_sqlvariant_bytea_from_type_datum(size_t typcode, Datum data); + +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 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 = compatible_oper(NULL, list_make1(makeString(oprname)), type, type, false, -1); + oprcode = oprfuncid(operator); + ReleaseSysCache(operator); + + 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; +} + +bytea * +gen_sqlvariant_bytea_from_type_datum(size_t typcode, Datum data) +{ + Oid typoid = type_infos[typcode].oid; + int8_t svhdr_size = type_infos[typcode].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); + Oid type_oid = (Oid) type_infos[typcode].oid; + uint8_t svhdr_size = type_infos[typcode].svhdr_size; + Oid target_oid = (Oid) type_infos[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); + + if (typcode == target_typcode) + return *target_datum; + else + return do_cast(type_oid, target_oid, *target_datum, typmod, coll, COERCION_EXPLICIT, &cast_by_relabel); +} + +/* + * Time could not be implicitly cast to any other date & time types + * Within SQL_VARIANT type, we regard time is alwasy smaller than + * other date & time types + */ +Datum +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); + +} + +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); + Oid type_oid1 = (Oid) type_infos[type_code1].oid; + Oid type_oid2 = (Oid) type_infos[type_code2].oid; + uint8_t svhdr_size1 = type_infos[type_code1].svhdr_size; + uint8_t svhdr_size2 = type_infos[type_code2].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; + } + } +} + + +/* + * CAST functions to SQL_VARIANT + */ + +PG_FUNCTION_INFO_V1(datetime2sqlvariant); +PG_FUNCTION_INFO_V1(datetime22sqlvariant); +PG_FUNCTION_INFO_V1(smalldatetime2sqlvariant); +PG_FUNCTION_INFO_V1(datetimeoffset2sqlvariant); +PG_FUNCTION_INFO_V1(date2sqlvariant); +PG_FUNCTION_INFO_V1(time2sqlvariant); +PG_FUNCTION_INFO_V1(float2sqlvariant); +PG_FUNCTION_INFO_V1(real2sqlvariant); +PG_FUNCTION_INFO_V1(numeric2sqlvariant); +PG_FUNCTION_INFO_V1(money2sqlvariant); +PG_FUNCTION_INFO_V1(smallmoney2sqlvariant); +PG_FUNCTION_INFO_V1(bigint2sqlvariant); +PG_FUNCTION_INFO_V1(int2sqlvariant); +PG_FUNCTION_INFO_V1(smallint2sqlvariant); +PG_FUNCTION_INFO_V1(tinyint2sqlvariant); +PG_FUNCTION_INFO_V1(bit2sqlvariant); +PG_FUNCTION_INFO_V1(varchar2sqlvariant); +PG_FUNCTION_INFO_V1(nvarchar2sqlvariant); +PG_FUNCTION_INFO_V1(char2sqlvariant); +PG_FUNCTION_INFO_V1(nchar2sqlvariant); +PG_FUNCTION_INFO_V1(bbfvarbinary2sqlvariant); +PG_FUNCTION_INFO_V1(bbfbinary2sqlvariant); +PG_FUNCTION_INFO_V1(uniqueidentifier2sqlvariant); + +/* Date and time */ +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; + + /* Type Specific Header */ + svhdr = SV_HDR_1B(result); + SV_SET_METADATA(svhdr, DATETIME_T, HDR_VER); + + 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; + + /* Type Specific Header */ + svhdr = SV_HDR_2B(result); + SV_SET_METADATA(svhdr, DATETIME2_T, HDR_VER); + svhdr->typmod = -1; + + 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; + + /* Type Specific Header */ + svhdr = SV_HDR_1B(result); + SV_SET_METADATA(svhdr, SMALLDATETIME_T, HDR_VER); + + 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; + + /* Type Specific Header */ + svhdr = SV_HDR_2B(result); + SV_SET_METADATA(svhdr, DATETIMEOFFSET_T, HDR_VER); + svhdr->typmod = -1; + + 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; + + /* Type Specific Header */ + svhdr = SV_HDR_1B(result); + SV_SET_METADATA(svhdr, DATE_T, HDR_VER); + + 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; + + /* Type Specific Header */ + svhdr = SV_HDR_2B(result); + SV_SET_METADATA(svhdr, TIME_T, HDR_VER); + svhdr->typmod = -1; + + 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; + + /* Type Specific Header */ + svhdr = SV_HDR_1B(result); + SV_SET_METADATA(svhdr, FLOAT_T, HDR_VER); + + 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; + + /* Type Specific Header */ + svhdr = SV_HDR_1B(result); + SV_SET_METADATA(svhdr, REAL_T, HDR_VER); + + 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; + + /* 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); +} + +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; + + /* Type Specific Header */ + svhdr = SV_HDR_1B(result); + SV_SET_METADATA(svhdr, MONEY_T, HDR_VER); + + 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; + + /* Type Specific Header */ + svhdr = SV_HDR_1B(result); + SV_SET_METADATA(svhdr, SMALLMONEY_T, HDR_VER); + + 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; + + /* Type Specific Header */ + svhdr = SV_HDR_1B(result); + SV_SET_METADATA(svhdr, BIGINT_T, HDR_VER); + + 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; + + /* Type Specific Header */ + svhdr = SV_HDR_1B(result); + SV_SET_METADATA(svhdr, INT_T, HDR_VER); + + 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; + + /* Type Specific Header */ + svhdr = SV_HDR_1B(result); + SV_SET_METADATA(svhdr, SMALLINT_T, HDR_VER); + + 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; + + /* Type Specific Header */ + svhdr = SV_HDR_1B(result); + SV_SET_METADATA(svhdr, TINYINT_T, HDR_VER); + + 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; + + /* Type Specific Header */ + svhdr = SV_HDR_1B(result); + SV_SET_METADATA(svhdr, BIT_T, HDR_VER); + + 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; + + /* 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); +} + +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; + + /* 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); +} + +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; + + /* 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); +} + +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; + + /* 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); +} + +/* 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; + + /* 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); +} + +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; + + /* 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); +} + +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; + + /* Type Specific Header */ + svhdr = SV_HDR_1B(result); + SV_SET_METADATA(svhdr, UNIQUEIDENTIFIER_T, HDR_VER); + + PG_RETURN_BYTEA_P(result); +} + + +/* + * CAST functions from SQL_VARIANT + */ + +PG_FUNCTION_INFO_V1(sqlvariant2timestamp); +PG_FUNCTION_INFO_V1(sqlvariant2datetimeoffset); +PG_FUNCTION_INFO_V1(sqlvariant2date); +PG_FUNCTION_INFO_V1(sqlvariant2time); +PG_FUNCTION_INFO_V1(sqlvariant2float); +PG_FUNCTION_INFO_V1(sqlvariant2real); +PG_FUNCTION_INFO_V1(sqlvariant2numeric); +PG_FUNCTION_INFO_V1(sqlvariant2fixeddecimal); +PG_FUNCTION_INFO_V1(sqlvariant2bigint); +PG_FUNCTION_INFO_V1(sqlvariant2int); +PG_FUNCTION_INFO_V1(sqlvariant2smallint); +PG_FUNCTION_INFO_V1(sqlvariant2bit); +PG_FUNCTION_INFO_V1(sqlvariant2varchar); +PG_FUNCTION_INFO_V1(sqlvariant2char); +PG_FUNCTION_INFO_V1(sqlvariant2bbfvarbinary); +PG_FUNCTION_INFO_V1(sqlvariant2bbfbinary); +PG_FUNCTION_INFO_V1(sqlvariant2uniqueidentifier); + + +/* Postgres will do self casts to apply typmod + * if we does not apply typmod during type cast. + * However, it may be faster may be if we apply typmod + * directly during type cast. +*/ +Datum +sqlvariant2timestamp(PG_FUNCTION_ARGS) +{ + 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)); + + PG_RETURN_TIMESTAMP(result); +} + +Datum +sqlvariant2datetimeoffset(PG_FUNCTION_ARGS) +{ + 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)); + + PG_RETURN_DATETIMEOFFSET(result); +} + +Datum +sqlvariant2date(PG_FUNCTION_ARGS) +{ + 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)); + + PG_RETURN_DATEADT(result); +} + +Datum +sqlvariant2time(PG_FUNCTION_ARGS) +{ + 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)); + + PG_RETURN_TIMEADT(result); +} + +Datum +sqlvariant2float(PG_FUNCTION_ARGS) +{ + 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)); + + PG_RETURN_FLOAT8(result); +} + +Datum +sqlvariant2real(PG_FUNCTION_ARGS) +{ + 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)); + + PG_RETURN_FLOAT4(result); +} + +Datum +sqlvariant2numeric(PG_FUNCTION_ARGS) +{ + 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)); + + PG_RETURN_NUMERIC(result); +} + +Datum +sqlvariant2fixeddecimal(PG_FUNCTION_ARGS) +{ + 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)); + + PG_RETURN_INT64(result); +} + +Datum +sqlvariant2bigint(PG_FUNCTION_ARGS) +{ + 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)); + + PG_RETURN_INT64(result); +} + +Datum +sqlvariant2int(PG_FUNCTION_ARGS) +{ + 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)); + + PG_RETURN_INT32(result); +} + +Datum +sqlvariant2smallint(PG_FUNCTION_ARGS) +{ + 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)); + + PG_RETURN_INT16(result); +} + +Datum +sqlvariant2bit(PG_FUNCTION_ARGS) +{ + 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)); + + PG_RETURN_BOOL(result); +} + +Datum +sqlvariant2varchar(PG_FUNCTION_ARGS) +{ + 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)); + + PG_RETURN_VARCHAR_P(result); +} + +Datum +sqlvariant2char(PG_FUNCTION_ARGS) +{ + 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)); + + PG_RETURN_BPCHAR_P(result); +} + +Datum +sqlvariant2bbfvarbinary(PG_FUNCTION_ARGS) +{ + 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)); + + PG_RETURN_BYTEA_P(result); +} + +Datum +sqlvariant2bbfbinary(PG_FUNCTION_ARGS) +{ + 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)); + + 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; + + result = DatumGetUUIDP(gen_type_datum_from_sqlvariant_bytea(sv, UNIQUEIDENTIFIER_T, -1, coll)); + + PG_RETURN_UUID_P(result); +} + +/* + * SQL_VARIANT_PROPERTY + */ + +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_t; + +static sv_property_t get_property_type(const char *arg, int len); +static Datum get_base_type(bytea *sv_value); +static Datum get_precision(bytea *sv_value); +static Datum get_scale(bytea *sv_value); +static Datum get_total_bytes(bytea *sv_value); +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; +} + +Datum +get_base_type(bytea *sv_value) +{ + uint8_t type_code = SV_GET_TYPCODE_PTR(sv_value); + const char *type_name = type_infos[type_code].tsql_typname; + + 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 = type_infos[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 = type_infos[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)); +} + +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); +} + +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 */ +} + +/* + * Comparision functions + */ + +PG_FUNCTION_INFO_V1(sqlvarianteq); +PG_FUNCTION_INFO_V1(sqlvariantne); +PG_FUNCTION_INFO_V1(sqlvariantlt); +PG_FUNCTION_INFO_V1(sqlvariantle); +PG_FUNCTION_INFO_V1(sqlvariantgt); +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 = type_infos[type_code1].family_prio; + uint8_t type_family2 = type_infos[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); + + /* Avoid leaking memory for toasted inputs */ + PG_FREE_IF_COPY(arg1, 0); + PG_FREE_IF_COPY(arg2, 1); + + 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 = type_infos[type_code1].family_prio; + uint8_t type_family2 = type_infos[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); + + /* Avoid leaking memory for toasted inputs */ + PG_FREE_IF_COPY(arg1, 0); + PG_FREE_IF_COPY(arg2, 1); + + 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 = type_infos[type_code1].family_prio; + uint8_t type_family2 = type_infos[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); + + /* Avoid leaking memory for toasted inputs */ + PG_FREE_IF_COPY(arg1, 0); + PG_FREE_IF_COPY(arg2, 1); + + 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 = type_infos[type_code1].family_prio; + uint8_t type_family2 = type_infos[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); + + /* Avoid leaking memory for toasted inputs */ + PG_FREE_IF_COPY(arg1, 0); + PG_FREE_IF_COPY(arg2, 1); + + 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 = type_infos[type_code1].family_prio; + uint8_t type_family2 = type_infos[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); + + /* Avoid leaking memory for toasted inputs */ + PG_FREE_IF_COPY(arg1, 0); + PG_FREE_IF_COPY(arg2, 1); + + 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 = type_infos[type_code1].family_prio; + uint8_t type_family2 = type_infos[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); + + /* Avoid leaking memory for toasted inputs */ + PG_FREE_IF_COPY(arg1, 0); + PG_FREE_IF_COPY(arg2, 1); + + return result; +} + +/* + * Index Supporting Functions + */ + +PG_FUNCTION_INFO_V1(sqlvariant_cmp); +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 = type_infos[type_code1].family_prio; + uint8_t type_family2 = type_infos[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; + + /* 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); + + return result; +} + + +/* + * DATALENGTH function for SQL_VARIANT + */ + +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 = type_infos[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; + + PG_RETURN_INT32(octet_len); +} + +/* + * TDS side code support on sql variant + */ +/* + * Retrieve PGbaseType code, dataLen, variable header length + * for each base datatype on sql variant + */ +extern void +TdsGetPGbaseType(uint8 variantBaseType, int *pgBaseType, int tempLen, + int *dataLen, int *variantHeaderLen); +extern void +TdsGetPGbaseType(uint8 variantBaseType, int *pgBaseType, int tempLen, + int *dataLen, int *variantHeaderLen) +{ + switch (variantBaseType) + { + case VARIANT_TYPE_BIT: + *pgBaseType = BIT_T; + *dataLen = tempLen - 2; + break; + case VARIANT_TYPE_TINYINT: + *pgBaseType = TINYINT_T; + *dataLen = tempLen - 2; + break; + case VARIANT_TYPE_SMALLINT: + *pgBaseType = SMALLINT_T; + *dataLen = tempLen - 2; + break; + case VARIANT_TYPE_INT: + *pgBaseType = INT_T; + *dataLen = tempLen - 2; + break; + case VARIANT_TYPE_BIGINT: + *pgBaseType = BIGINT_T; + *dataLen = tempLen - 2; + break; + case VARIANT_TYPE_REAL: + *pgBaseType = REAL_T; + *dataLen = tempLen - 2; + break; + case VARIANT_TYPE_FLOAT: + *pgBaseType = FLOAT_T; + *dataLen = tempLen - 2; + break; + case VARIANT_TYPE_CHAR: + *pgBaseType = CHAR_T; + *dataLen = tempLen - 5; + break; + case VARIANT_TYPE_NCHAR: + *pgBaseType = NCHAR_T; + *dataLen = (tempLen - 9) / 2 + 4; + break; + case VARIANT_TYPE_VARCHAR: + *pgBaseType = VARCHAR_T; + *dataLen = tempLen - 5; + break; + case VARIANT_TYPE_NVARCHAR: + *pgBaseType = NVARCHAR_T; + *dataLen = (tempLen - 9) / 2 + 4; + break; + case VARIANT_TYPE_BINARY: + *pgBaseType = BINARY_T; + *dataLen = tempLen; + break; + case VARIANT_TYPE_VARBINARY: + *pgBaseType = VARBINARY_T; + *dataLen = tempLen; + break; + case VARIANT_TYPE_DATE: + *pgBaseType = DATE_T; + *dataLen = tempLen - 2; + break; + case VARIANT_TYPE_TIME: + *pgBaseType = TIME_T; + *dataLen = tempLen - 3; + break; + case VARIANT_TYPE_SMALLDATETIME: + *pgBaseType = SMALLDATETIME_T; + *dataLen = tempLen - 2; + break; + case VARIANT_TYPE_DATETIME: + *pgBaseType = DATETIME_T; + *dataLen = tempLen - 2; + break; + case VARIANT_TYPE_DATETIME2: + *pgBaseType = DATETIME2_T; + *dataLen = tempLen - 3; + break; + case VARIANT_TYPE_UNIQUEIDENTIFIER: + *pgBaseType = UNIQUEIDENTIFIER_T; + *dataLen = tempLen - 2; + break; + case VARIANT_TYPE_NUMERIC: + *pgBaseType = NUMERIC_T; + *dataLen = tempLen - 5; + break; + case VARIANT_TYPE_MONEY: + *pgBaseType = MONEY_T; + *dataLen = tempLen - 2; + break; + case VARIANT_TYPE_SMALLMONEY: + *pgBaseType = SMALLMONEY_T; + *dataLen = tempLen - 2; + break; + case VARIANT_TYPE_DATETIMEOFFSET: + *pgBaseType = DATETIMEOFFSET_T; + *dataLen = tempLen - 3; + break; + default: + elog(ERROR, "%d: datatype not supported in TDS receiver", variantBaseType); + break; + } + + *variantHeaderLen = type_infos[*pgBaseType].svhdr_size; +} + + +/* + * set metadata on sqlvariant header for variable length datatypes + */ +void TdsSetMetaData(bytea *result, int pgBaseType, int scale, + int precision, int maxLen); +void TdsSetMetaData(bytea *result, int pgBaseType, int scale, + int precision, int maxLen) +{ + svhdr_5B_t *svhdr; + svhdr = SV_HDR_5B(result); + + SV_SET_METADATA(svhdr, pgBaseType, HDR_VER); + + if (pgBaseType == TIME_T || pgBaseType == DATETIME2_T || + pgBaseType == DATETIMEOFFSET_T) + { + svhdr->typmod = scale; + } + else if (pgBaseType == NUMERIC_T) + { + svhdr->typmod = (precision << 8) | scale; + } + else if (pgBaseType == BINARY_T || pgBaseType == VARBINARY_T || + pgBaseType == CHAR_T || pgBaseType == NCHAR_T || + pgBaseType == VARCHAR_T || pgBaseType == NVARCHAR_T) + { + svhdr->typmod = (int16)maxLen; + } +} + +int +TdsPGbaseType(bytea *vlena); +int +TdsPGbaseType(bytea *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); +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; + } + 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); +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 = type_infos[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); + + return result; +} + +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); + + return result; +} + +static void +init_collation_callbacks(void) +{ + Tsql_collation_callbacks **callbacks_ptr; + callbacks_ptr = (Tsql_collation_callbacks **) find_rendezvous_variable("PLtsql_collation_callbacks"); + collation_callbacks_ptr = *callbacks_ptr; +} + +static Oid +get_tsql_collation_oid(int persist_coll_id) +{ + if (collation_callbacks_ptr) + init_collation_callbacks(); + + if (collation_callbacks_ptr && collation_callbacks_ptr->get_tsql_collation_oid_f) + return (*collation_callbacks_ptr->get_tsql_collation_oid_f)(persist_coll_id); + else + return -1; +} + +static int +get_persist_collation_id(Oid coll_oid) +{ + if (collation_callbacks_ptr) + init_collation_callbacks(); + + if (collation_callbacks_ptr && collation_callbacks_ptr->get_persist_collation_id_f) + return (*collation_callbacks_ptr->get_persist_collation_id_f)(coll_oid); + else + return -1; +} + +static int +get_server_collation_collidx(void) +{ + if (collation_callbacks_ptr) + init_collation_callbacks(); + + if (collation_callbacks_ptr && collation_callbacks_ptr->get_server_collation_collidx_f) + return (*collation_callbacks_ptr->get_server_collation_collidx_f)(); + else + return -1; +} + +static int8_t +cmp_collation(uint16_t coll1, uint16_t coll2) +{ + if (collation_callbacks_ptr) + init_collation_callbacks(); + + if (collation_callbacks_ptr && collation_callbacks_ptr->cmp_collation_f) + return (*collation_callbacks_ptr->cmp_collation_f)(coll1, coll2); + else + return 0; +} + diff --git a/contrib/babelfishpg_common/src/typecode.c b/contrib/babelfishpg_common/src/typecode.c new file mode 100644 index 00000000000..b1859e8a5ff --- /dev/null +++ b/contrib/babelfishpg_common/src/typecode.c @@ -0,0 +1,285 @@ +#include "postgres.h" + +#include "typecode.h" +#include "fmgr.h" +#include "nodes/execnodes.h" +#include "utils/hsearch.h" +#include "utils/syscache.h" +#include "utils/memutils.h" +#include "utils/elog.h" +#include "utils/builtins.h" +#include "catalog/namespace.h" +#include "catalog/pg_namespace.h" +#include "catalog/pg_type.h" + + +/* Memory context */ +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, 0, "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} +}; + +/* Hash tables to help backward searching (from OID to Persist ID) */ +HTAB *ht_oid2typecode = NULL; + +/* + * Translation Table Initializers + * Load information from C arrays into hash tables + * Initializers are called right after shared library loading + * During "CREATE EXTENSION", data types are created after initialization call + * In this case, initializers do nothing + * After data types are created, initializers will be triggered again + * with a built-in procedure + * + */ + +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", false); + /* retrieve oid and setup hashtable*/ + for (int i=0; ipersist_id = i; + } + } + + PG_RETURN_INT32(0); +} + +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(); +} + +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 +lookup_tsql_datatype_oid(const char *typename) +{ + Oid nspoid; + Oid typoid; + + nspoid = get_namespace_oid("sys", true); + if (nspoid == InvalidOid) + return InvalidOid; + + typoid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid, CStringGetDatum(typename), ObjectIdGetDatum(nspoid)); + return typoid; +} + +bool +is_tsql_bpchar_datatype(Oid oid) +{ + if (tsql_bpchar_oid == InvalidOid) + tsql_bpchar_oid = lookup_tsql_datatype_oid("bpchar"); + return tsql_bpchar_oid == oid; +} + +bool +is_tsql_nchar_datatype(Oid oid) +{ + if (tsql_nchar_oid == InvalidOid) + tsql_nchar_oid = lookup_tsql_datatype_oid("nchar"); + return tsql_nchar_oid == oid; +} + +bool +is_tsql_varchar_datatype(Oid oid) +{ + if (tsql_varchar_oid == InvalidOid) + tsql_varchar_oid = lookup_tsql_datatype_oid("varchar"); + return tsql_varchar_oid == oid; +} + +bool +is_tsql_nvarchar_datatype(Oid oid) +{ + if (tsql_nvarchar_oid == InvalidOid) + tsql_nvarchar_oid = lookup_tsql_datatype_oid("nvarchar"); + return tsql_nvarchar_oid == oid; +} + +bool +is_tsql_text_datatype(Oid oid) +{ + return TEXTOID == oid; +} + +bool +is_tsql_ntext_datatype(Oid oid) +{ + if (tsql_ntext_oid == InvalidOid) + tsql_ntext_oid = lookup_tsql_datatype_oid("ntext"); + return tsql_ntext_oid == oid; +} + +bool +is_tsql_image_datatype(Oid oid) +{ + if (tsql_image_oid == InvalidOid) + tsql_image_oid = lookup_tsql_datatype_oid("image"); + return tsql_image_oid == oid; +} + +bool +is_tsql_binary_datatype(Oid oid) +{ + if (tsql_binary_oid == InvalidOid) + tsql_binary_oid = lookup_tsql_datatype_oid("bbf_binary"); + return tsql_binary_oid == oid; +} + +bool +is_tsql_varbinary_datatype(Oid oid) +{ + if (tsql_varbinary_oid == InvalidOid) + tsql_varbinary_oid = lookup_tsql_datatype_oid("bbf_varbinary"); + return tsql_varbinary_oid == oid; +} diff --git a/contrib/babelfishpg_common/src/typecode.h b/contrib/babelfishpg_common/src/typecode.h new file mode 100644 index 00000000000..01dc727f976 --- /dev/null +++ b/contrib/babelfishpg_common/src/typecode.h @@ -0,0 +1,84 @@ +#ifndef TSQL_TYPECODE_H +#define TSQL_TYPECODE_H + +/* Persistent Type Code for SQL Variant Type */ +/* WARNING: EXISTING VALUES MUST NOT BE CHANGED */ + +#define SQLVARIANT_T 0 +#define DATETIMEOFFSET_T 1 +#define DATETIME2_T 2 +#define DATETIME_T 3 +#define SMALLDATETIME_T 4 +#define DATE_T 5 +#define TIME_T 6 +#define FLOAT_T 7 +#define REAL_T 8 +#define NUMERIC_T 9 +#define MONEY_T 10 +#define SMALLMONEY_T 11 +#define BIGINT_T 12 +#define INT_T 13 +#define SMALLINT_T 14 +#define TINYINT_T 15 +#define BIT_T 16 +#define NVARCHAR_T 17 +#define NCHAR_T 18 +#define VARCHAR_T 19 +#define CHAR_T 20 +#define VARBINARY_T 21 +#define BINARY_T 22 +#define UNIQUEIDENTIFIER_T 23 + +#define IS_STRING_TYPE(t) \ + ( ((t) == NVARCHAR_T) || ((t) == NCHAR_T) \ + || ((t) == VARCHAR_T) || ((t) == CHAR_T)) + +#define IS_MONEY_TYPE(t) (((t) == MONEY_T) || ((t) == SMALLMONEY_T)) +#define IS_BINARY_TYPE(t) (((t) == VARBINARY_T) || ((t) == BINARY_T)) + +/* MACRO from fixed decimal */ +#ifndef FIXEDDECIMAL_MULTIPLIER +#define FIXEDDECIMAL_MULTIPLIER 10000LL +#endif + +#define TOTAL_TYPECODE_COUNT 24 + +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; +} type_info_t; + +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 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); +extern bool is_tsql_nvarchar_datatype(Oid oid); +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_varbinary_datatype(Oid oid); + +#endif diff --git a/contrib/babelfishpg_common/src/uniqueidentifier.c b/contrib/babelfishpg_common/src/uniqueidentifier.c new file mode 100644 index 00000000000..566a2e23d6d --- /dev/null +++ b/contrib/babelfishpg_common/src/uniqueidentifier.c @@ -0,0 +1,238 @@ +/*------------------------------------------------------------------------- + * + * uniqueidentifier.c + * Functions for the type "uniqueidentifier". + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "fmgr.h" +#include "utils/builtins.h" +#include "utils/uuid.h" +#include "lib/stringinfo.h" + +static void string_to_uuid(const char *source, pg_uuid_t *uuid); +static void reverse_memcpy(unsigned char *dst, unsigned char *src, size_t n); + +PG_FUNCTION_INFO_V1(uniqueidentifier_in); + +Datum +uniqueidentifier_in(PG_FUNCTION_ARGS) +{ + 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); +} + +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); +} + +/* + * We allow UUIDs as a series of 32 hexadecimal digits with an optional dash + * after each group of 4 hexadecimal digits, and optionally surrounded by {}. + * (The canonical format 8x-4x-4x-4x-12x, where "nx" means n hexadecimal + * digits, is the only one used for output.) + */ +static void +string_to_uuid(const char *source, pg_uuid_t *uuid) +{ + const char *src = source; + bool braces = false; + int i; + + if (src[0] == '{') + { + src++; + braces = true; + } + + for (i = 0; i < UUID_LEN; i++) + { + char str_buf[3]; + + if (src[0] == '\0' || src[1] == '\0') + goto syntax_error; + memcpy(str_buf, src, 2); + if (!isxdigit((unsigned char) str_buf[0]) || + !isxdigit((unsigned char) str_buf[1])) + goto syntax_error; + + str_buf[2] = '\0'; + uuid->data[i] = (unsigned char) strtoul(str_buf, NULL, 16); + src += 2; + if (src[0] == '-' && (i % 2) == 1 && i < UUID_LEN - 1) + src++; + } + + if (braces) + { + if (*src != '}') + goto syntax_error; + src++; + } + + return; + +syntax_error: + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for type %s: \"%s\"", + "uuid", source))); +} + +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_FUNCTION_INFO_V1(varbinary2uniqueidentifier); + +Datum +varbinary2uniqueidentifier(PG_FUNCTION_ARGS) +{ + 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); + + memset(buffer, 0, UUID_LEN); + memcpy(buffer, data, (len > UUID_LEN) ? UUID_LEN : len); + + 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); + PG_RETURN_UUID_P(uuid); +} + + +PG_FUNCTION_INFO_V1(uniqueidentifier2varbinary); + +Datum +uniqueidentifier2varbinary(PG_FUNCTION_ARGS) +{ + 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); + + /* 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); + + /* If typmod is -1 (or invalid), use the actual length */ + if (typmod < (int32) VARHDRSZ) + maxlen = len; + else + maxlen = typmod - VARHDRSZ; + + if (len > maxlen) + len = maxlen; + + result = (bytea *) palloc(len + VARHDRSZ); + SET_VARSIZE(result, len + VARHDRSZ); + rp = VARDATA(result); + memcpy(rp, buffer, len); + + PG_RETURN_BYTEA_P(result); +} + +PG_FUNCTION_INFO_V1(uniqueidentifier2binary); + +Datum +uniqueidentifier2binary(PG_FUNCTION_ARGS) +{ + 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); + + /* 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); + + /* If typmod is -1 (or invalid), use the actual length */ + if (typmod < (int32) VARHDRSZ) + maxlen = len; + else + maxlen = typmod - VARHDRSZ; + + if (len > maxlen) + len = maxlen; + + result = (bytea *) palloc(maxlen + VARHDRSZ); + SET_VARSIZE(result, maxlen + VARHDRSZ); + rp = VARDATA(result); + memcpy(rp, buffer, len); + + /* NULL pad the rest of the space */ + memset(rp + len, '\0', maxlen - len); + + PG_RETURN_BYTEA_P(result); +} + +static void +reverse_memcpy(unsigned char *dst, unsigned char *src, size_t n) +{ + size_t i; + + for (i = 0; i < n; i++) + dst[n-1-i] = src[i]; +} diff --git a/contrib/babelfishpg_common/src/varbinary.c b/contrib/babelfishpg_common/src/varbinary.c new file mode 100644 index 00000000000..1a1cf41e49d --- /dev/null +++ b/contrib/babelfishpg_common/src/varbinary.c @@ -0,0 +1,1192 @@ +/*------------------------------------------------------------------------- + * + * varbinary.c + * Functions for the variable-length binary type. + * + * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include +#include + +#include "access/hash.h" +#include "catalog/pg_collation.h" +#include "catalog/pg_type.h" +#include "common/int.h" +#include "lib/hyperloglog.h" +#include "libpq/pqformat.h" +#include "miscadmin.h" +#include "parser/parser.h" +#include "parser/scansup.h" +#include "port/pg_bswap.h" +#include "regex/regex.h" +#include "utils/builtins.h" +#include "utils/bytea.h" +#include "utils/lsyscache.h" +#include "utils/memutils.h" +#include "utils/pg_locale.h" +#include "utils/sortsupport.h" +#include "utils/varlena.h" + +#include "instr.h" + +PG_FUNCTION_INFO_V1(varbinaryin); +PG_FUNCTION_INFO_V1(varbinaryout); +PG_FUNCTION_INFO_V1(varbinaryrecv); +PG_FUNCTION_INFO_V1(varbinarysend); +PG_FUNCTION_INFO_V1(varbinary); +PG_FUNCTION_INFO_V1(binary); +PG_FUNCTION_INFO_V1(varbinarytypmodin); +PG_FUNCTION_INFO_V1(varbinarytypmodout); +PG_FUNCTION_INFO_V1(varcharvarbinary); +PG_FUNCTION_INFO_V1(bpcharvarbinary); +PG_FUNCTION_INFO_V1(varbinaryvarchar); +PG_FUNCTION_INFO_V1(varcharbinary); +PG_FUNCTION_INFO_V1(bpcharbinary); +PG_FUNCTION_INFO_V1(int2varbinary); +PG_FUNCTION_INFO_V1(int4varbinary); +PG_FUNCTION_INFO_V1(int8varbinary); +PG_FUNCTION_INFO_V1(int2binary); +PG_FUNCTION_INFO_V1(int4binary); +PG_FUNCTION_INFO_V1(int8binary); +PG_FUNCTION_INFO_V1(varbinaryint2); +PG_FUNCTION_INFO_V1(varbinaryint4); +PG_FUNCTION_INFO_V1(varbinaryint8); +PG_FUNCTION_INFO_V1(binaryint2); +PG_FUNCTION_INFO_V1(binaryint4); +PG_FUNCTION_INFO_V1(binaryint8); +PG_FUNCTION_INFO_V1(float4varbinary); +PG_FUNCTION_INFO_V1(float8varbinary); +PG_FUNCTION_INFO_V1(varbinaryfloat4); +PG_FUNCTION_INFO_V1(varbinaryfloat8); +PG_FUNCTION_INFO_V1(float4binary); +PG_FUNCTION_INFO_V1(float8binary); +PG_FUNCTION_INFO_V1(binaryfloat4); +PG_FUNCTION_INFO_V1(binaryfloat8); + +/***************************************************************************** + * USER I/O ROUTINES * + *****************************************************************************/ + +#define VAL(CH) ((CH) - '0') +#define DIG(VAL) ((VAL) + '0') + +#define MAX_BINARY_SIZE 8000 + +/* + * varbinaryin - input function of varbinary + */ +Datum +varbinaryin(PG_FUNCTION_ARGS) +{ + char *inputText = PG_GETARG_CSTRING(0); + char *rp; + char *tp; + int len; + bytea *result; + int32 typmod = PG_GETARG_INT32(2); + + len = strlen(inputText); + + if (typmod == TSQLHexConstTypmod) + { + /* + * 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 */ + result = palloc(bc); + bc = hex_decode_allow_odd_digits(inputText + 2, len - 2, VARDATA(result)); + SET_VARSIZE(result, bc + VARHDRSZ); /* actual length */ + + PG_RETURN_BYTEA_P(result); + } + + tp = inputText; + + result = (bytea *) palloc(len + VARHDRSZ); + SET_VARSIZE(result, len + VARHDRSZ); + + rp = VARDATA(result); + memcpy(rp, tp, len); + + PG_RETURN_BYTEA_P(result); +} + +/* + * varbinaryout - converts to printable representation of byte array + * + * In the traditional escaped format, non-printable characters are + * printed as '\nnn' (octal) and '\' as '\\'. + * This routine is copied from byteaout + */ +Datum +varbinaryout(PG_FUNCTION_ARGS) +{ + bytea *vlena = PG_GETARG_BYTEA_PP(0); + char *result; + char *rp; + + if (bytea_output == BYTEA_OUTPUT_HEX) + { + /* Print hex format */ + rp = result = palloc(VARSIZE_ANY_EXHDR(vlena) * 2 + 2 + 1); + *rp++ = '0'; + *rp++ = 'x'; + rp += hex_encode(VARDATA_ANY(vlena), VARSIZE_ANY_EXHDR(vlena), rp); + } + else if (bytea_output == BYTEA_OUTPUT_ESCAPE) + { + /* Print traditional escaped format */ + char *vp; + int len; + int i; + + len = 1; /* empty string has 1 char */ + vp = VARDATA_ANY(vlena); + for (i = VARSIZE_ANY_EXHDR(vlena); i != 0; i--, vp++) + { + if (*vp == '\\') + len += 2; + else if ((unsigned char) *vp < 0x20 || (unsigned char) *vp > 0x7e) + len += 4; + else + len++; + } + rp = result = (char *) palloc(len); + vp = VARDATA_ANY(vlena); + for (i = VARSIZE_ANY_EXHDR(vlena); i != 0; i--, vp++) + { + if (*vp == '\\') + { + *rp++ = '\\'; + *rp++ = '\\'; + } + else if ((unsigned char) *vp < 0x20 || (unsigned char) *vp > 0x7e) + { + int val; /* holds unprintable chars */ + + val = *vp; + rp[0] = '\\'; + rp[3] = DIG(val & 07); + val >>= 3; + rp[2] = DIG(val & 07); + val >>= 3; + rp[1] = DIG(val & 03); + rp += 4; + } + else + *rp++ = *vp; + } + } + else + { + elog(ERROR, "unrecognized bytea_output setting: %d", + bytea_output); + rp = result = NULL; /* keep compiler quiet */ + } + *rp = '\0'; + PG_RETURN_CSTRING(result); +} + +/* + * varbinaryrecv - converts external binary format to bytea + */ +Datum +varbinaryrecv(PG_FUNCTION_ARGS) +{ + StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); + bytea *result; + int nbytes; + + INSTR_METRIC_INC(INSTR_TSQL_VARBINARY_RECV); + + nbytes = buf->len - buf->cursor; + result = (bytea *) palloc(nbytes + VARHDRSZ); + SET_VARSIZE(result, nbytes + VARHDRSZ); + pq_copymsgbytes(buf, VARDATA(result), nbytes); + PG_RETURN_BYTEA_P(result); +} + +/* + * varbinarysend - converts bytea to binary format + * + * This is a special case: just copy the input... + */ +Datum +varbinarysend(PG_FUNCTION_ARGS) +{ + bytea *vlena = PG_GETARG_BYTEA_P_COPY(0); + + INSTR_METRIC_INC(INSTR_TSQL_VARBINARY_SEND); + + PG_RETURN_BYTEA_P(vlena); +} + +/* + * Converts a VARBINARY type to the specified size. + * + * maxlen is the typmod, ie, declared length plus VARHDRSZ bytes. + * + * Truncation rules: for an explicit cast, silently truncate to the given + * length; for an implicit cast, raise error. + * (This is sort-of per SQL: the spec would actually have us + * raise a "completion condition" for the explicit cast case, but Postgres + * hasn't got such a concept.) + */ +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; + + len = VARSIZE_ANY_EXHDR(source); + + /* If typmod is -1 (or invalid), use the actual length */ + if (typmod < (int32) VARHDRSZ) + maxlen = len; + else + maxlen = typmod - VARHDRSZ; + + if (!isExplicit && + !(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" + "The statement has been terminated."))); + + /* No work if typmod is invalid or supplied data fits it already */ + if (maxlen < 0 || len <= maxlen) + PG_RETURN_BYTEA_P(source); + + /* + * 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)); +} + +/* + * Converts a BINARY type to the specified size. + * + * maxlen is the typmod, ie, declared length plus VARHDRSZ bytes. + * + * Truncation rules: for an explicit cast, silently truncate to the given + * length; for an implicit cast, raise error. + * (This is sort-of per SQL: the spec would actually have us + * raise a "completion condition" for the explicit cast case, but Postgres + * hasn't got such a concept.) + */ +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; + + len = VARSIZE_ANY_EXHDR(source); + + /* If typmod is -1 (or invalid), use the actual length */ + if (typmod < (int32) VARHDRSZ) + maxlen = len; + else + maxlen = typmod - VARHDRSZ; + + if (maxlen > MAX_BINARY_SIZE) + ereport(ERROR, + (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION), + errmsg("The size (%d) given to the type 'binary' exceeds the maximum allowed (%d)", + maxlen, MAX_BINARY_SIZE))); + + if (!isExplicit && + !(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" + "The statement has been terminated."))); + + /* No work if maxlen is invalid or supplied data fits it exactly */ + if (maxlen < 0 || len == maxlen) + PG_RETURN_BYTEA_P(source); + + if (len < maxlen) + { + bytea *result; + int total_size = maxlen + VARHDRSZ; + char *tp; + char *rp; + + result = (bytea *) palloc(total_size); + SET_VARSIZE(result, total_size); + tp = VARDATA(source); + rp = VARDATA(result); + + memcpy(rp, tp, len); + /* NULL pad the rest of the space */ + memset(rp + len, '\0', maxlen - len); + + PG_RETURN_BYTEA_P(result); + } + + /* + * 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)); +} + +/* common code for varbinarytypmodin, bpchartypmodin and varchartypmodin */ +static int32 +anychar_typmodin(ArrayType *ta, const char *typename) +{ + int32 typmod; + int32 *tl; + int n; + + tl = ArrayGetIntegerTypmods(ta, &n); + + /* Allow typmod of VARBINARY(MAX) to go through as is */ + if (*tl == TSQLMaxTypmod) + { + return *tl; + } + + /* + * we're not too tense about good error message here because grammar + * shouldn't allow wrong number of modifiers for CHAR + */ + if (n != 1) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid type modifier"))); + + if (*tl < 1) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("length for type %s must be at least 1", typename))); + if (*tl > MaxAttrSize) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("length for type %s cannot exceed %d", + typename, MaxAttrSize))); + + /* + * For largely historical reasons, the typmod is VARHDRSZ plus the number + * of characters; there is enough client-side code that knows about that + * that we'd better not change it. + */ + typmod = VARHDRSZ + *tl; + + return typmod; +} + +/* + * code for varbinarytypmodout + * copied from bpchartypmodout and varchartypmodout + */ +static char * +anychar_typmodout(int32 typmod) +{ + char *res = (char *) palloc(64); + + if (typmod > VARHDRSZ) + snprintf(res, 64, "(%d)", (int) (typmod - VARHDRSZ)); + else + *res = '\0'; + + return res; +} + +Datum +varbinarytypmodin(PG_FUNCTION_ARGS) +{ + ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0); + + PG_RETURN_INT32(anychar_typmodin(ta, "varbinary")); +} + +Datum +varbinarytypmodout(PG_FUNCTION_ARGS) +{ + int32 typmod = PG_GETARG_INT32(0); + + PG_RETURN_CSTRING(anychar_typmodout(typmod)); +} + +static void +reverse_memcpy(char* dst, char* src, size_t n) +{ + size_t i; + + for (i = 0; i < n; i++) + dst[n-1-i] = src[i]; +} + +/* + * Cast functions + */ +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; + + 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."))); + + /* If typmod is -1 (or invalid), use the actual length */ + if (typmod < (int32) VARHDRSZ) + maxlen = len; + else + maxlen = typmod - VARHDRSZ; + + if (len > maxlen) + len = maxlen; + + result = (bytea *) palloc(len + VARHDRSZ); + SET_VARSIZE(result, len + VARHDRSZ); + + rp = VARDATA(result); + memcpy(rp, data, len); + + PG_RETURN_BYTEA_P(result); +} + +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; + + 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."))); + + /* If typmod is -1 (or invalid), use the actual length */ + if (typmod < (int32) VARHDRSZ) + maxlen = len; + else + maxlen = typmod - VARHDRSZ; + + if (len > maxlen) + len = maxlen; + + result = (bytea *) palloc(len + VARHDRSZ); + SET_VARSIZE(result, len + VARHDRSZ); + + rp = VARDATA(result); + memcpy(rp, data, len); + + PG_RETURN_BYTEA_P(result); +} + + + +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); + 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; + + 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."))); + + /* If typmod is -1 (or invalid), use the actual length */ + if (typmod < (int32) VARHDRSZ) + maxlen = len; + else + maxlen = typmod - VARHDRSZ; + + if (len > maxlen) + len = maxlen; + + result = (bytea *) palloc(maxlen + VARHDRSZ); + SET_VARSIZE(result, maxlen + VARHDRSZ); + + rp = VARDATA(result); + memcpy(rp, data, len); + + /* NULL pad the rest of the space */ + memset(rp + len, '\0', maxlen - len); + PG_RETURN_BYTEA_P(result); +} + +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; + + 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."))); + + /* If typmod is -1 (or invalid), use the actual length */ + if (typmod < (int32) VARHDRSZ) + maxlen = len; + else + maxlen = typmod - VARHDRSZ; + + if (len > maxlen) + len = maxlen; + + result = (bytea *) palloc(maxlen + VARHDRSZ); + SET_VARSIZE(result, maxlen + VARHDRSZ); + + rp = VARDATA(result); + memcpy(rp, data, len); + + /* NULL pad the rest of the space */ + memset(rp + len, '\0', maxlen - len); + PG_RETURN_BYTEA_P(result); +} + +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; + + /* If typmod is -1 (or invalid), use the actual length */ + if (typmod < (int32) VARHDRSZ) + maxlen = len; + else + maxlen = typmod - VARHDRSZ; + + actual_len = maxlen < len ? maxlen : len; + + result = (bytea *) palloc(actual_len + VARHDRSZ); + SET_VARSIZE(result, actual_len + VARHDRSZ); + + rp = VARDATA(result); + /* Need reverse copy because endianness is different in MSSQL */ + reverse_memcpy(rp, (char *) &input , actual_len); + + PG_RETURN_BYTEA_P(result); +} + +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; + + /* If typmod is -1 (or invalid), use the actual length */ + if (typmod < (int32) VARHDRSZ) + maxlen = len; + else + maxlen = typmod - VARHDRSZ; + + actual_len = maxlen < len ? maxlen : len; + + result = (bytea *) palloc(actual_len + VARHDRSZ); + SET_VARSIZE(result, actual_len + VARHDRSZ); + + rp = VARDATA(result); + /* Need reverse copy because endianness is different in MSSQL */ + reverse_memcpy(rp, (char *) &input , actual_len); + + PG_RETURN_BYTEA_P(result); +} + +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; + + /* If typmod is -1 (or invalid), use the actual length */ + if (typmod < (int32) VARHDRSZ) + maxlen = len; + else + maxlen = typmod - VARHDRSZ; + + actual_len = maxlen < len ? maxlen : len; + + result = (bytea *) palloc(actual_len + VARHDRSZ); + SET_VARSIZE(result, actual_len + VARHDRSZ); + + rp = VARDATA(result); + /* Need reverse copy because endianness is different in MSSQL */ + reverse_memcpy(rp, (char *) &input , actual_len); + + PG_RETURN_BYTEA_P(result); +} + +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)); + + len = VARSIZE_ANY_EXHDR(source); + result_len = len > sizeof(int16) ? sizeof(int16) : len; + reverse_memcpy((char *)result, data, result_len); + + PG_RETURN_INT16(*result); +} + +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)); + + len = VARSIZE_ANY_EXHDR(source); + result_len = len > sizeof(int32) ? sizeof(int32) : len; + reverse_memcpy((char *)result, data, result_len); + + PG_RETURN_INT32(*result); +} + +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)); + + len = VARSIZE_ANY_EXHDR(source); + result_len = len > sizeof(int64) ? sizeof(int64) : len; + reverse_memcpy((char *)result, data, result_len); + + PG_RETURN_INT64(*result); +} + +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; + + /* If typmod is -1 (or invalid), use the actual length */ + if (typmod < (int32) VARHDRSZ) + maxlen = len; + else + maxlen = typmod - VARHDRSZ; + + actual_len = maxlen < len ? maxlen : len; + + result = (bytea *) palloc(actual_len + VARHDRSZ); + SET_VARSIZE(result, actual_len + VARHDRSZ); + + rp = VARDATA(result); + /* Need reverse copy because endianness is different in MSSQL */ + reverse_memcpy(rp, (char *) &input , actual_len); + + PG_RETURN_BYTEA_P(result); +} + +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; + + /* If typmod is -1 (or invalid), use the actual length */ + if (typmod < (int32) VARHDRSZ) + maxlen = len; + else + maxlen = typmod - VARHDRSZ; + + actual_len = maxlen < len ? maxlen : len; + + result = (bytea *) palloc(actual_len + VARHDRSZ); + SET_VARSIZE(result, actual_len + VARHDRSZ); + + rp = VARDATA(result); + /* Need reverse copy because endianness is different in MSSQL */ + reverse_memcpy(rp, (char *) &input , actual_len); + + PG_RETURN_BYTEA_P(result); +} + +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)); + + len = VARSIZE_ANY_EXHDR(source); + result_len = len > sizeof(float4) ? sizeof(float4) : len; + reverse_memcpy((char *)result, data, result_len); + + PG_RETURN_FLOAT4(*result); +} + +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)); + + len = VARSIZE_ANY_EXHDR(source); + result_len = len > sizeof(float8) ? sizeof(float8) : len; + reverse_memcpy((char *)result, data, result_len); + + PG_RETURN_FLOAT8(*result); +} + +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; + + /* If typmod is -1 (or invalid), use the actual length */ + if (typmod < (int32) VARHDRSZ) + maxlen = len; + else + maxlen = typmod - VARHDRSZ; + + result = (bytea *) palloc0(maxlen + VARHDRSZ); + SET_VARSIZE(result, maxlen + VARHDRSZ); + + rp = VARDATA(result); + if (maxlen <= len) + /* Need reverse copy because endianness is different in MSSQL */ + 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); + + PG_RETURN_BYTEA_P(result); +} + +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; + + /* If typmod is -1 (or invalid), use the actual length */ + if (typmod < (int32) VARHDRSZ) + maxlen = len; + else + maxlen = typmod - VARHDRSZ; + + + result = (bytea *) palloc0(maxlen + VARHDRSZ); + SET_VARSIZE(result, maxlen + VARHDRSZ); + + rp = VARDATA(result); + if (maxlen <= len) + /* Need reverse copy because endianness is different in MSSQL */ + 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); + + PG_RETURN_BYTEA_P(result); +} + +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; + + /* If typmod is -1 (or invalid), use the actual length */ + if (typmod < (int32) VARHDRSZ) + maxlen = len; + else + maxlen = typmod - VARHDRSZ; + + + result = (bytea *) palloc0(maxlen + VARHDRSZ); + SET_VARSIZE(result, maxlen + VARHDRSZ); + + rp = VARDATA(result); + if (maxlen <= len) + /* Need reverse copy because endianness is different in MSSQL */ + 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); + + PG_RETURN_BYTEA_P(result); +} + +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)); + + 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); + else + reverse_memcpy((char *)result, data, result_len); + + PG_RETURN_INT16(*result); +} + +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)); + + 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); + else + reverse_memcpy((char *)result, data, result_len); + + PG_RETURN_INT32(*result); +} + +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)); + + 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); + else + reverse_memcpy((char *)result, data, result_len); + + PG_RETURN_INT64(*result); +} + +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; + + /* If typmod is -1 (or invalid), use the actual length */ + if (typmod < (int32) VARHDRSZ) + maxlen = len; + else + maxlen = typmod - VARHDRSZ; + + + result = (bytea *) palloc0(maxlen + VARHDRSZ); + SET_VARSIZE(result, maxlen + VARHDRSZ); + + rp = VARDATA(result); + if (maxlen <= len) + /* Need reverse copy because endianness is different in MSSQL */ + 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); + + PG_RETURN_BYTEA_P(result); +} + +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; + + /* If typmod is -1 (or invalid), use the actual length */ + if (typmod < (int32) VARHDRSZ) + maxlen = len; + else + maxlen = typmod - VARHDRSZ; + + + result = (bytea *) palloc0(maxlen + VARHDRSZ); + SET_VARSIZE(result, maxlen + VARHDRSZ); + + rp = VARDATA(result); + if (maxlen <= len) + /* Need reverse copy because endianness is different in MSSQL */ + 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); + + PG_RETURN_BYTEA_P(result); +} + +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)); + + 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); + else + reverse_memcpy((char *)result, data, result_len); + + PG_RETURN_FLOAT4(*result); +} + +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)); + + 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); + else + reverse_memcpy((char *)result, data, result_len); + + PG_RETURN_FLOAT8(*result); +} + +int8 +varbinarycompare(bytea *source1, bytea *source2); + +int8 +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); + + unsigned char byte1; + unsigned char byte2; + int32 maxlen = len2 > len1 ? len2 : len1; + + INSTR_METRIC_INC(INSTR_TSQL_VARBINARY_COMPARE); + + /* loop all the bytes */ + for (int i=0; i byte2) + return 1; + else if (byte1 < byte2) + return -1; + } + return 0; +} + +PG_FUNCTION_INFO_V1(varbinary_eq); +PG_FUNCTION_INFO_V1(varbinary_neq); +PG_FUNCTION_INFO_V1(varbinary_gt); +PG_FUNCTION_INFO_V1(varbinary_geq); +PG_FUNCTION_INFO_V1(varbinary_lt); +PG_FUNCTION_INFO_V1(varbinary_leq); +PG_FUNCTION_INFO_V1(varbinary_cmp); + +Datum +varbinary_eq (PG_FUNCTION_ARGS) +{ + 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_neq (PG_FUNCTION_ARGS) +{ + 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_gt (PG_FUNCTION_ARGS) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + bytea *source1 = PG_GETARG_BYTEA_PP(0); + bytea *source2 = PG_GETARG_BYTEA_PP(1); + PG_RETURN_INT32(varbinarycompare(source1, source2)); +} diff --git a/contrib/babelfishpg_common/src/varchar.c b/contrib/babelfishpg_common/src/varchar.c new file mode 100644 index 00000000000..ad2c42ac77b --- /dev/null +++ b/contrib/babelfishpg_common/src/varchar.c @@ -0,0 +1,1258 @@ +/*------------------------------------------------------------------------- + * + * varchar.c + * Functions for the built-in types char(n) and varchar(n). + * + * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/utils/adt/varchar.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + + +#include "access/hash.h" +#include "catalog/pg_collation.h" +#include "fmgr.h" +#include "libpq/pqformat.h" +#include "nodes/nodeFuncs.h" +#include "parser/parser.h" /* only needed for GUC variables */ +#include "utils/array.h" +#include "utils/builtins.h" +#include "utils/float.h" +#include "utils/int8.h" +#include "utils/pg_locale.h" +#include "utils/varlena.h" +#include "mb/pg_wchar.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); +void *tsql_varchar_input(const char *s, size_t len, int32 atttypmod); +static inline int varcharTruelen(VarChar *arg); + +/* + * GetUTF8CodePoint - extract the next Unicode code point from 1..4 + * bytes at 'in' in UTF-8 encoding. + */ +static inline int32_t +GetUTF8CodePoint(const unsigned char *in, int len, int *consumed_p) +{ + int32_t code; + int consumed; + + if (len == 0) + return EOF; + + if ((in[0] & 0x80) == 0) + { + /* 1 byte - 0xxxxxxx */ + code = in[0]; + consumed = 1; + } + else if ((in[0] & 0xE0) == 0xC0) + { + /* 2 byte - 110xxxxx 10xxxxxx */ + if (len < 2) + ereport(ERROR, + (errcode(ERRCODE_DATA_EXCEPTION), + errmsg("truncated UTF8 byte sequence starting with 0x%02x", + in[0]))); + if ((in[1] & 0xC0) != 0x80) + ereport(ERROR, + (errcode(ERRCODE_DATA_EXCEPTION), + errmsg("invalid UTF8 byte sequence starting with 0x%02x", + in[0]))); + code = ((in[0] & 0x1F) << 6) | (in[1] & 0x3F); + consumed = 2; + } + else if ((in[0] & 0xF0) == 0xE0) + { + /* 3 byte - 1110xxxx 10xxxxxx 10xxxxxx */ + if (len < 3) + ereport(ERROR, + (errcode(ERRCODE_DATA_EXCEPTION), + errmsg("truncated UTF8 byte sequence starting with 0x%02x", + in[0]))); + if ((in[1] & 0xC0) != 0x80 || (in[2] & 0xC0) != 0x80) + ereport(ERROR, + (errcode(ERRCODE_DATA_EXCEPTION), + errmsg("invalid UTF8 byte sequence starting with 0x%02x", + in[0]))); + code = ((in[0] & 0x0F) << 12) | ((in[1] & 0x3F) << 6) | (in[2] & 0x3F); + consumed = 3; + } + else if ((in[0] & 0xF8) == 0xF0) + { + /* 4 byte - 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */ + if (len < 4) + ereport(ERROR, + (errcode(ERRCODE_DATA_EXCEPTION), + errmsg("truncated UTF8 byte sequence starting with 0x%02x", + in[0]))); + if ((in[1] & 0xC0) != 0x80 || (in[2] & 0xC0) != 0x80 || + (in[3] & 0xC0) != 0x80) + ereport(ERROR, + (errcode(ERRCODE_DATA_EXCEPTION), + 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); + consumed = 4; + } + else + { + ereport(ERROR, + (errcode(ERRCODE_DATA_EXCEPTION), + errmsg("invalid UTF8 byte sequence starting with 0x%02x", + in[0]))); + } + + if (code > 0x10FFFF || (code >= 0xD800 && code < 0xE000)) + ereport(ERROR, + (errcode(ERRCODE_DATA_EXCEPTION), + errmsg("invalid UTF8 code point 0x%x", code))); + + if (consumed_p) + *consumed_p = consumed; + + return code; +} + +/* + * 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; + int result = 0; + int i; + int consumed; + int32_t code; + + for (i = 0; i < len;) + { + code = GetUTF8CodePoint(&in[i], len - i, &consumed); + + /* Check that this is a valid code point */ + if ((code > 0xD800 && code < 0xE000) || code < 0x0001 || code > 0x10FFFF) + ereport(ERROR, + (errcode(ERRCODE_DATA_EXCEPTION), + errmsg("invalid Unicode code point 0x%x", code))); + + if (code <= 0xFFFF) + /* This code point would result in a single 16-bit output */ + result += 1; + else + /* This code point would result in a 16-bit surrogate pair */ + result += 2; + + i += consumed; + } + + return result; +} + +static inline void +TsqlCheckUTF16Length(const char *utf8_str, size_t len, size_t maxlen, + char *varstr) +{ + 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) " + "as UTF16 output", + varstr, (int)maxlen))); +} + +/* + * Check for T-SQL varchar function + */ +void +TsqlCheckUTF16Length_varchar(const char *s_data, int32 len, int32 maxlen, bool isExplicit) +{ + int i; + size_t maxmblen; + if (maxlen < 0) + return ; + + if (len <= maxlen) + { + TsqlCheckUTF16Length(s_data, len, maxlen, " varying"); + 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)())) + { + for (i = maxmblen; i < len; i++) + if (s_data[i] != ' ') + ereport(ERROR, + (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION), + errmsg("value too long for type character varying(%d)", + maxlen))); + TsqlCheckUTF16Length(s_data, len, maxlen, " varying"); + } + else + TsqlCheckUTF16Length(s_data, maxmblen, maxlen, " varying"); +} + +/* + * Check for T-SQL bpchar function + */ +void +TsqlCheckUTF16Length_bpchar(const char *s, int32 len, int32 maxlen, int charlen, bool isExplicit) +{ + int i; + if (charlen == maxlen) + { + TsqlCheckUTF16Length(s, len, maxlen, ""); + } + else if (charlen > maxlen) + { + /* Verify that extra characters are spaces, and clip them off */ + size_t maxmblen; + + maxmblen = pg_mbcharcliplen(s, len, maxlen); + + if (!isExplicit && + !(suppress_string_truncation_error_hook && (*suppress_string_truncation_error_hook)())) + { + for (i = maxmblen; i < len; i++) + if (s[i] != ' ') + ereport(ERROR, + (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION), + errmsg("value too long for type character(%d)", + maxlen))); + } + + len = maxmblen; + TsqlCheckUTF16Length(s, len, maxlen, ""); + } + else + { + TsqlCheckUTF16Length(s, len, maxlen, ""); + } +} + +/* + * Check for T-SQL varchar common input function, varchar_input() + */ +void TsqlCheckUTF16Length_varchar_input(const char *s, int32 len, int32 maxlen) +{ + TsqlCheckUTF16Length(s, len, maxlen, " varying"); +} + +/* + * Check for T-SQL bpchar function + */ +void TsqlCheckUTF16Length_bpchar_input(const char *s, int32 len, int32 maxlen, int charlen) +{ + if (charlen > maxlen) + { + /* Verify that extra characters are spaces, and clip them off */ + size_t mbmaxlen = pg_mbcharcliplen(s, len, maxlen); + 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. + */ + for (j = mbmaxlen; j < len; j++) + { + if (s[j] != ' ') + ereport(ERROR, + (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION), + errmsg("value too long for type character(%d)", + (int) maxlen))); + } + + TsqlCheckUTF16Length(s, len, maxlen, ""); + } + else + { + TsqlCheckUTF16Length(s, len, maxlen, ""); + } +} + +/* Function Registeration */ +PG_FUNCTION_INFO_V1(bpcharin); +PG_FUNCTION_INFO_V1(bpchar); +PG_FUNCTION_INFO_V1(bpcharrecv); + +PG_FUNCTION_INFO_V1(bpchar2int2); +PG_FUNCTION_INFO_V1(bpchar2int4); +PG_FUNCTION_INFO_V1(bpchar2int8); +PG_FUNCTION_INFO_V1(bpchar2float4); +PG_FUNCTION_INFO_V1(bpchar2float8); + +PG_FUNCTION_INFO_V1(varcharin); +PG_FUNCTION_INFO_V1(varchar); +PG_FUNCTION_INFO_V1(varcharrecv); +PG_FUNCTION_INFO_V1(varchareq); +PG_FUNCTION_INFO_V1(varcharne); +PG_FUNCTION_INFO_V1(varcharlt); +PG_FUNCTION_INFO_V1(varcharle); +PG_FUNCTION_INFO_V1(varchargt); +PG_FUNCTION_INFO_V1(varcharge); +PG_FUNCTION_INFO_V1(varcharcmp); +PG_FUNCTION_INFO_V1(hashvarchar); + +PG_FUNCTION_INFO_V1(varchar2int2); +PG_FUNCTION_INFO_V1(varchar2int4); +PG_FUNCTION_INFO_V1(varchar2int8); +PG_FUNCTION_INFO_V1(varchar2float4); +PG_FUNCTION_INFO_V1(varchar2float8); + +/***************************************************************************** + * varchar - varchar(n) + * + * Note: varchar piggybacks on type text for most operations, and so has no + * C-coded functions except for I/O and typmod checking. + *****************************************************************************/ + +/* + * varchar_input -- common guts of varcharin and varcharrecv + * + * s is the input text of length len (may not be null-terminated) + * atttypmod is the typmod value to apply + * + * Note that atttypmod is measured in characters, which + * is not necessarily the same as the number of bytes. + * + * If the input string is too long, raise an error, unless the extra + * characters are spaces, in which case they're truncated. (per SQL) + * + * Uses the C string to text conversion function, which is only appropriate + * if VarChar and text are equivalent types. + */ +static VarChar * +varchar_input(const char *s, size_t len, int32 atttypmod) +{ + VarChar *result; + size_t maxlen; + + maxlen = atttypmod - VARHDRSZ; + + if (atttypmod >= (int32) VARHDRSZ && len > maxlen) + { + /* Verify that extra characters are spaces, and clip them off */ + size_t mbmaxlen = pg_mbcharcliplen(s, len, maxlen); + size_t j; + + for (j = mbmaxlen; j < len; j++) + { + if (s[j] != ' ') + ereport(ERROR, + (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION), + errmsg("value too long for type character varying(%d)", + (int) maxlen))); + } + + len = mbmaxlen; + } + + if (atttypmod >= (int32) VARHDRSZ) + TsqlCheckUTF16Length_varchar_input(s, len, maxlen); + + result = (VarChar *) cstring_to_text_with_len(s, len); + return result; +} + +void * +tsql_varchar_input(const char *s, size_t len, int32 atttypmod) +{ + return varchar_input(s, len, atttypmod); +} + +/* + * Convert a C string to VARCHAR internal representation. atttypmod + * is the declared length of the type plus VARHDRSZ. + */ +Datum +varcharin(PG_FUNCTION_ARGS) +{ + char *s = PG_GETARG_CSTRING(0); + +#ifdef NOT_USED + Oid typelem = PG_GETARG_OID(1); +#endif + int32 atttypmod = PG_GETARG_INT32(2); + VarChar *result; + + result = varchar_input(s, strlen(s), atttypmod); + PG_RETURN_VARCHAR_P(result); +} + +/* + * varcharrecv - converts external binary format to varchar + */ +Datum +varcharrecv(PG_FUNCTION_ARGS) +{ + StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); + +#ifdef NOT_USED + Oid typelem = PG_GETARG_OID(1); +#endif + int32 atttypmod = PG_GETARG_INT32(2); + VarChar *result; + char *str; + int nbytes; + + str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes); + result = varchar_input(str, nbytes, atttypmod); + pfree(str); + PG_RETURN_VARCHAR_P(result); +} + +/* + * Converts a VARCHAR type to the specified size. + * + * maxlen is the typmod, ie, declared length plus VARHDRSZ bytes. + * isExplicit is true if this is for an explicit cast to varchar(N). + * + * Truncation rules: for an explicit cast, silently truncate to the given + * length; for an implicit cast, raise error unless extra characters are + * all spaces. (This is sort-of per SQL: the spec would actually have us + * raise a "completion condition" for the explicit cast case, but Postgres + * hasn't got such a concept.) + */ +Datum +varchar(PG_FUNCTION_ARGS) +{ + VarChar *source = PG_GETARG_VARCHAR_PP(0); + int32 typmod = PG_GETARG_INT32(1); + bool isExplicit = PG_GETARG_BOOL(2); + int32 len, + maxlen; + size_t maxmblen; + int i; + char *s_data; + + len = VARSIZE_ANY_EXHDR(source); + s_data = VARDATA_ANY(source); + maxlen = typmod - VARHDRSZ; + + TsqlCheckUTF16Length_varchar(s_data, len, maxlen, isExplicit); + + /* No work if typmod is invalid or supplied data fits it already */ + if (maxlen < 0 || len <= maxlen) + PG_RETURN_VARCHAR_P(source); + + /* only reach here if string is too long... */ + + /* 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)())) + { + for (i = maxmblen; i < len; i++) + if (s_data[i] != ' ') + ereport(ERROR, + (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION), + errmsg("value too long for type character varying(%d)", + maxlen))); + } + + PG_RETURN_VARCHAR_P((VarChar *) cstring_to_text_with_len(s_data, + maxmblen)); +} + +static char * +varchar2cstring(const VarChar *source) +{ + const char *s_data = VARDATA_ANY(source); + int len = VARSIZE_ANY_EXHDR(source); + + char *result = (char *) palloc(len + 1); + memcpy(result, s_data, len); + result[len] = '\0'; + + return result; +} + +Datum +varchar2int2(PG_FUNCTION_ARGS) +{ + VarChar *source = PG_GETARG_VARCHAR_PP(0); + if (varcharTruelen(source) == 0) + PG_RETURN_INT16(0); + + PG_RETURN_INT16(pg_strtoint16(varchar2cstring(source))); +} + +Datum +varchar2int4(PG_FUNCTION_ARGS) +{ + VarChar *source = PG_GETARG_VARCHAR_PP(0); + if (varcharTruelen(source) == 0) + PG_RETURN_INT32(0); + + PG_RETURN_INT32(pg_strtoint32(varchar2cstring(source))); +} + +Datum +varchar2int8(PG_FUNCTION_ARGS) +{ + int64 result; + VarChar *source = PG_GETARG_VARCHAR_PP(0); + if (varcharTruelen(source) == 0) + PG_RETURN_INT64(0); + + (void) scanint8(varchar2cstring(source), false, &result); + PG_RETURN_INT64(result); +} + +static Datum +cstring2float4(char *num) +{ + /* This came from float4in() in backend/utils/adt/float.c */ + 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 + * string. + */ + orig_num = num; + + /* skip leading whitespace */ + while (*num != '\0' && isspace((unsigned char) *num)) + num++; + + /* + * Check for an empty-string input to begin with, to avoid the vagaries of + * strtod() on different platforms. + */ + if (*num == '\0') + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for type %s: \"%s\"", + "real", orig_num))); + + errno = 0; + val = strtof(num, &endptr); + + /* did we not see anything that looks like a double? */ + if (endptr == num || errno != 0) + { + int save_errno = errno; + + /* + * C99 requires that strtof() accept NaN, [+-]Infinity, and [+-]Inf, + * but not all platforms support all of these (and some accept them + * but set ERANGE anyway...) Therefore, we check for these inputs + * ourselves if strtof() fails. + * + * Note: C99 also requires hexadecimal input as well as some extended + * forms of NaN, but we consider these forms unportable and don't try + * to support them. You can use 'em if your strtof() takes 'em. + */ + if (pg_strncasecmp(num, "NaN", 3) == 0) + { + val = get_float4_nan(); + endptr = num + 3; + } + else if (pg_strncasecmp(num, "Infinity", 8) == 0) + { + val = get_float4_infinity(); + endptr = num + 8; + } + else if (pg_strncasecmp(num, "+Infinity", 9) == 0) + { + val = get_float4_infinity(); + endptr = num + 9; + } + else if (pg_strncasecmp(num, "-Infinity", 9) == 0) + { + val = -get_float4_infinity(); + endptr = num + 9; + } + else if (pg_strncasecmp(num, "inf", 3) == 0) + { + val = get_float4_infinity(); + endptr = num + 3; + } + else if (pg_strncasecmp(num, "+inf", 4) == 0) + { + val = get_float4_infinity(); + endptr = num + 4; + } + else if (pg_strncasecmp(num, "-inf", 4) == 0) + { + val = -get_float4_infinity(); + endptr = num + 4; + } + else if (save_errno == ERANGE) + { + /* + * Some platforms return ERANGE for denormalized numbers (those + * that are not zero, but are too close to zero to have full + * precision). We'd prefer not to throw error for that, so try to + * detect whether it's a "real" out-of-range condition by checking + * to see if the result is zero or huge. + * + * Use isinf() rather than HUGE_VALF on VS2013 because it + * generates a spurious overflow warning for -HUGE_VALF. Also use + * isinf() if HUGE_VALF is missing. + */ + if (val == 0.0 || +#if !defined(HUGE_VALF) || (defined(_MSC_VER) && (_MSC_VER < 1900)) + isinf(val) +#else + (val >= HUGE_VALF || val <= -HUGE_VALF) +#endif + ) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("\"%s\" is out of range for type real", + orig_num))); + } + else + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for type %s: \"%s\"", + "real", orig_num))); + } +#ifdef HAVE_BUGGY_SOLARIS_STRTOD + else + { + /* + * Many versions of Solaris have a bug wherein strtod sets endptr to + * point one byte beyond the end of the string when given "inf" or + * "infinity". + */ + if (endptr != num && endptr[-1] == '\0') + endptr--; + } +#endif /* HAVE_BUGGY_SOLARIS_STRTOD */ + + /* skip trailing whitespace */ + while (*endptr != '\0' && isspace((unsigned char) *endptr)) + endptr++; + + /* if there is any junk left at the end of the string, bail out */ + if (*endptr != '\0') + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for type %s: \"%s\"", + "real", orig_num))); + + PG_RETURN_FLOAT4(val); +} + +Datum +varchar2float4(PG_FUNCTION_ARGS) +{ + VarChar *source = PG_GETARG_VARCHAR_PP(0); + + if (varcharTruelen(source) == 0) + PG_RETURN_FLOAT4(0); + + return cstring2float4(varchar2cstring(source)); +} + +Datum +varchar2float8(PG_FUNCTION_ARGS) +{ + VarChar *source = PG_GETARG_VARCHAR_PP(0); + char *num; + + if (varcharTruelen(source) == 0) + PG_RETURN_FLOAT8(0); + + num = varchar2cstring(source); + PG_RETURN_FLOAT8(float8in_internal(num, NULL, "double precision", num)); +} + +/***************************************************************************** + * bpchar - char() * + *****************************************************************************/ + +/* + * bpchar_input -- common guts of bpcharin and bpcharrecv + * + * s is the input text of length len (may not be null-terminated) + * atttypmod is the typmod value to apply + * + * Note that atttypmod is measured in characters, which + * is not necessarily the same as the number of bytes. + * + * If the input string is too long, raise an error, unless the extra + * characters are spaces, in which case they're truncated. (per SQL) + */ +static BpChar * +bpchar_input(const char *s, size_t len, int32 atttypmod) +{ + BpChar *result; + char *r; + size_t maxlen; + + /* If typmod is -1 (or invalid), use the actual string length */ + if (atttypmod < (int32) VARHDRSZ) + maxlen = len; + else + { + size_t charlen; /* number of CHARACTERS in the input */ + + maxlen = atttypmod - VARHDRSZ; + charlen = pg_mbstrlen_with_len(s, len); + + TsqlCheckUTF16Length_bpchar_input(s, len, maxlen, charlen); + + if (charlen > maxlen) + { + /* Verify that extra characters are spaces, and clip them off */ + size_t mbmaxlen = pg_mbcharcliplen(s, len, maxlen); + 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. + */ + for (j = mbmaxlen; j < len; j++) + { + if (s[j] != ' ') + ereport(ERROR, + (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION), + errmsg("value too long for type character(%d)", + (int) maxlen))); + } + + /* + * Now we set maxlen to the necessary byte length, not the number + * of CHARACTERS! + */ + maxlen = len = mbmaxlen; + } + else + { + /* + * Now we set maxlen to the necessary byte length, not the number + * of CHARACTERS! + */ + maxlen = len + (maxlen - charlen); + } + } + + result = (BpChar *) palloc(maxlen + VARHDRSZ); + SET_VARSIZE(result, maxlen + VARHDRSZ); + r = VARDATA(result); + memcpy(r, s, len); + + /* blank pad the string if necessary */ + if (maxlen > len) + memset(r + len, ' ', maxlen - len); + + return result; +} + +/* + * Convert a C string to CHARACTER internal representation. atttypmod + * is the declared length of the type plus VARHDRSZ. + */ +Datum +bpcharin(PG_FUNCTION_ARGS) +{ + char *s = PG_GETARG_CSTRING(0); + +#ifdef NOT_USED + Oid typelem = PG_GETARG_OID(1); +#endif + int32 atttypmod = PG_GETARG_INT32(2); + BpChar *result; + + result = bpchar_input(s, strlen(s), atttypmod); + PG_RETURN_BPCHAR_P(result); +} + +/* + * bpcharrecv - converts external binary format to bpchar + */ +Datum +bpcharrecv(PG_FUNCTION_ARGS) +{ + StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); + +#ifdef NOT_USED + Oid typelem = PG_GETARG_OID(1); +#endif + int32 atttypmod = PG_GETARG_INT32(2); + BpChar *result; + char *str; + int nbytes; + + str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes); + result = bpchar_input(str, nbytes, atttypmod); + pfree(str); + PG_RETURN_BPCHAR_P(result); +} + +/* + * Converts a CHARACTER type to the specified size. + * + * maxlen is the typmod, ie, declared length plus VARHDRSZ bytes. + * isExplicit is true if this is for an explicit cast to char(N). + * + * Truncation rules: for an explicit cast, silently truncate to the given + * length; for an implicit cast, raise error unless extra characters are + * all spaces. (This is sort-of per SQL: the spec would actually have us + * raise a "completion condition" for the explicit cast case, but Postgres + * hasn't got such a concept.) + */ +Datum +bpchar(PG_FUNCTION_ARGS) +{ + BpChar *source = PG_GETARG_BPCHAR_PP(0); + int32 maxlen = PG_GETARG_INT32(1); + bool isExplicit = PG_GETARG_BOOL(2); + BpChar *result; + int32 len; + char *r; + char *s; + int i; + int charlen; /* number of characters in the input string + + * VARHDRSZ */ + + /* No work if typmod is invalid */ + if (maxlen < (int32) VARHDRSZ) + PG_RETURN_BPCHAR_P(source); + + maxlen -= VARHDRSZ; + + len = VARSIZE_ANY_EXHDR(source); + s = VARDATA_ANY(source); + + charlen = pg_mbstrlen_with_len(s, len); + + TsqlCheckUTF16Length_bpchar(s, len, maxlen, charlen, isExplicit); + + /* No work if supplied data matches typmod already */ + if (charlen == maxlen) + PG_RETURN_BPCHAR_P(source); + + if (charlen > maxlen) + { + /* Verify that extra characters are spaces, and clip them off */ + size_t maxmblen; + + maxmblen = pg_mbcharcliplen(s, len, maxlen); + + if (!isExplicit && + !(suppress_string_truncation_error_hook && (*suppress_string_truncation_error_hook)())) + { + for (i = maxmblen; i < len; i++) + if (s[i] != ' ') + ereport(ERROR, + (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION), + errmsg("value too long for type character(%d)", + maxlen))); + } + + len = maxmblen; + + /* + * At this point, maxlen is the necessary byte length, not the number + * of CHARACTERS! + */ + maxlen = len; + } + else + { + + /* + * At this point, maxlen is the necessary byte length, not the number + * of CHARACTERS! + */ + maxlen = len + (maxlen - charlen); + } + + Assert(maxlen >= len); + + result = palloc(maxlen + VARHDRSZ); + SET_VARSIZE(result, maxlen + VARHDRSZ); + r = VARDATA(result); + + memcpy(r, s, len); + + /* blank pad the string if necessary */ + if (maxlen > len) + memset(r + len, ' ', maxlen - len); + + PG_RETURN_BPCHAR_P(result); +} + +static char * +bpchar2cstring(const BpChar *source) +{ + const char *s_data = VARDATA_ANY(source); + int len = VARSIZE_ANY_EXHDR(source); + + char *result = (char *) palloc(len + 1); + memcpy(result, s_data, len); + result[len] = '\0'; + + return result; +} + +Datum +bpchar2int2(PG_FUNCTION_ARGS) +{ + BpChar *source = PG_GETARG_BPCHAR_PP(0); + if (bpchartruelen(VARDATA_ANY(source), VARSIZE_ANY_EXHDR(source)) == 0) + PG_RETURN_INT16(0); + + PG_RETURN_INT16(pg_strtoint16(bpchar2cstring(source))); +} + +Datum +bpchar2int4(PG_FUNCTION_ARGS) +{ + BpChar *source = PG_GETARG_BPCHAR_PP(0); + if (bpchartruelen(VARDATA_ANY(source), VARSIZE_ANY_EXHDR(source)) == 0) + PG_RETURN_INT32(0); + + PG_RETURN_INT32(pg_strtoint32(bpchar2cstring(source))); +} + +Datum +bpchar2int8(PG_FUNCTION_ARGS) +{ + int64 result; + BpChar *source = PG_GETARG_BPCHAR_PP(0); + if (bpchartruelen(VARDATA_ANY(source), VARSIZE_ANY_EXHDR(source)) == 0) + PG_RETURN_INT64(0); + + (void) scanint8(bpchar2cstring(source), false, &result); + PG_RETURN_INT64(result); +} + +Datum +bpchar2float4(PG_FUNCTION_ARGS) +{ + BpChar *source = PG_GETARG_BPCHAR_PP(0); + + if (bpchartruelen(VARDATA_ANY(source), VARSIZE_ANY_EXHDR(source)) == 0) + PG_RETURN_FLOAT4(0); + + return cstring2float4(bpchar2cstring(source)); +} + +Datum +bpchar2float8(PG_FUNCTION_ARGS) +{ + BpChar *source = PG_GETARG_BPCHAR_PP(0); + char *num; + + if (bpchartruelen(VARDATA_ANY(source), VARSIZE_ANY_EXHDR(source)) == 0) + PG_RETURN_FLOAT8(0); + + num = bpchar2cstring(source); + PG_RETURN_FLOAT8(float8in_internal(num, NULL, "double precision", num)); +} + +static inline int +varcharTruelen(VarChar *arg) +{ + char *s = VARDATA_ANY(arg); + int len = VARSIZE_ANY_EXHDR(arg); + + int i; + + /* + * Note that we rely on the assumption that ' ' is a singleton unit on + * every supported multibyte server encoding. + */ + for (i = len - 1; i >= 0; i--) + { + if (s[i] != ' ') + break; + } + return i + 1; +} + +static inline void +check_collation_set(Oid collid) +{ + if (!OidIsValid(collid)) + { + /* + * This typically means that the parser could not resolve a conflict + * of implicit collations, so report it that way. + */ + ereport(ERROR, + (errcode(ERRCODE_INDETERMINATE_COLLATION), + errmsg("could not determine which collation to use for string comparison"), + errhint("Use the COLLATE clause to set the collation explicitly."))); + } +} + +Datum +varchareq(PG_FUNCTION_ARGS) +{ + VarChar *arg1 = PG_GETARG_VARCHAR_PP(0); + VarChar *arg2 = PG_GETARG_VARCHAR_PP(1); + int len1, + len2; + bool result; + Oid collid = PG_GET_COLLATION(); + + check_collation_set(collid); + + len1 = varcharTruelen(arg1); + len2 = varcharTruelen(arg2); + + if (lc_collate_is_c(collid) || + collid == DEFAULT_COLLATION_OID || + pg_newlocale_from_collation(collid)->deterministic) + { + /* + * Since we only care about equality or not-equality, we can avoid all + * the expense of strcoll() here, and just do bitwise comparison. + */ + if (len1 != len2) + result = false; + else + result = (memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), len1) == 0); + } + else + { + result = (varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2, + collid) == 0); + } + + PG_FREE_IF_COPY(arg1, 0); + PG_FREE_IF_COPY(arg2, 1); + + PG_RETURN_BOOL(result); +} + +Datum +varcharne(PG_FUNCTION_ARGS) +{ + VarChar *arg1 = PG_GETARG_VARCHAR_PP(0); + VarChar *arg2 = PG_GETARG_VARCHAR_PP(1); + int len1, + len2; + bool result; + Oid collid = PG_GET_COLLATION(); + + check_collation_set(collid); + + len1 = varcharTruelen(arg1); + len2 = varcharTruelen(arg2); + + if (lc_collate_is_c(collid) || + collid == DEFAULT_COLLATION_OID || + pg_newlocale_from_collation(collid)->deterministic) + { + /* + * Since we only care about equality or not-equality, we can avoid all + * the expense of strcoll() here, and just do bitwise comparison. + */ + if (len1 != len2) + result = true; + else + result = (memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), len1) != 0); + } + else + { + result = (varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2, + collid) != 0); + } + + PG_FREE_IF_COPY(arg1, 0); + PG_FREE_IF_COPY(arg2, 1); + + PG_RETURN_BOOL(result); +} + +Datum +varcharlt(PG_FUNCTION_ARGS) +{ + VarChar *arg1 = PG_GETARG_VARCHAR_PP(0); + VarChar *arg2 = PG_GETARG_VARCHAR_PP(1); + int len1, + len2; + int cmp; + + len1 = varcharTruelen(arg1); + len2 = varcharTruelen(arg2); + + cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2, + PG_GET_COLLATION()); + + PG_FREE_IF_COPY(arg1, 0); + PG_FREE_IF_COPY(arg2, 1); + + PG_RETURN_BOOL(cmp < 0); +} + +Datum +varcharle(PG_FUNCTION_ARGS) +{ + VarChar *arg1 = PG_GETARG_VARCHAR_PP(0); + VarChar *arg2 = PG_GETARG_VARCHAR_PP(1); + int len1, + len2; + int cmp; + + len1 = varcharTruelen(arg1); + len2 = varcharTruelen(arg2); + + cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2, + PG_GET_COLLATION()); + + PG_FREE_IF_COPY(arg1, 0); + PG_FREE_IF_COPY(arg2, 1); + + PG_RETURN_BOOL(cmp <= 0); +} + +Datum +varchargt(PG_FUNCTION_ARGS) +{ + VarChar *arg1 = PG_GETARG_VARCHAR_PP(0); + VarChar *arg2 = PG_GETARG_VARCHAR_PP(1); + int len1, + len2; + int cmp; + + len1 = varcharTruelen(arg1); + len2 = varcharTruelen(arg2); + + cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2, + PG_GET_COLLATION()); + + PG_FREE_IF_COPY(arg1, 0); + PG_FREE_IF_COPY(arg2, 1); + + PG_RETURN_BOOL(cmp > 0); +} + +Datum +varcharge(PG_FUNCTION_ARGS) +{ + VarChar *arg1 = PG_GETARG_VARCHAR_PP(0); + VarChar *arg2 = PG_GETARG_VARCHAR_PP(1); + int len1, + len2; + int cmp; + + len1 = varcharTruelen(arg1); + len2 = varcharTruelen(arg2); + + cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2, + PG_GET_COLLATION()); + + PG_FREE_IF_COPY(arg1, 0); + PG_FREE_IF_COPY(arg2, 1); + + PG_RETURN_BOOL(cmp >= 0); +} + +Datum +varcharcmp(PG_FUNCTION_ARGS) +{ + VarChar *arg1 = PG_GETARG_VARCHAR_PP(0); + VarChar *arg2 = PG_GETARG_VARCHAR_PP(1); + int len1, + len2; + int cmp; + + len1 = varcharTruelen(arg1); + len2 = varcharTruelen(arg2); + + cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2, + PG_GET_COLLATION()); + + PG_FREE_IF_COPY(arg1, 0); + PG_FREE_IF_COPY(arg2, 1); + + PG_RETURN_INT32(cmp); +} + +/* + * varchar needs a specialized hash function because we want to ignore + * trailing blanks in comparisons. + */ +Datum +hashvarchar(PG_FUNCTION_ARGS) +{ + VarChar *key = PG_GETARG_VARCHAR_PP(0); + Oid collid = PG_GET_COLLATION(); + char *keydata; + int keylen; + pg_locale_t mylocale = 0; + Datum result; + + if (!collid) + ereport(ERROR, + (errcode(ERRCODE_INDETERMINATE_COLLATION), + errmsg("could not determine which collation to use for string hashing"), + errhint("Use the COLLATE clause to set the collation explicitly."))); + + keydata = VARDATA_ANY(key); + keylen = varcharTruelen(key); + + if (!lc_collate_is_c(collid) && collid != DEFAULT_COLLATION_OID) + mylocale = pg_newlocale_from_collation(collid); + + if (!mylocale || mylocale->deterministic) + { + result = hash_any((unsigned char *) keydata, keylen); + } + else + { +#ifdef USE_ICU + if (mylocale->provider == COLLPROVIDER_ICU) + { + int32_t ulen = -1; + UChar *uchar = NULL; + Size bsize; + uint8_t *buf; + + ulen = icu_to_uchar(&uchar, keydata, keylen); + + bsize = ucol_getSortKey(mylocale->info.icu.ucol, + uchar, ulen, NULL, 0); + buf = palloc(bsize); + ucol_getSortKey(mylocale->info.icu.ucol, + uchar, ulen, buf, bsize); + + result = hash_any(buf, bsize); + + pfree(buf); + } + else +#endif + /* shouldn't happen */ + elog(ERROR, "unsupported collprovider: %c", mylocale->provider); + } + + /* Avoid leaking memory for toasted inputs */ + PG_FREE_IF_COPY(key, 0); + + return result; +} diff --git a/contrib/babelfishpg_money/Makefile b/contrib/babelfishpg_money/Makefile new file mode 100755 index 00000000000..07c719d3c48 --- /dev/null +++ b/contrib/babelfishpg_money/Makefile @@ -0,0 +1,47 @@ +MODULE_big = babelfishpg_money +OBJS = fixeddecimal.o + +EXTENSION = babelfishpg_money + +#subdir = contrib/babelfishpg_money + +DATA = fixeddecimal--1.0.0--1.1.0.sql +DATA_built = babelfishpg_money--1.1.0.sql + +#include ../Makefile.common + +CFLAGS = `$(PG_CONFIG) --includedir-server` + +TESTS = $(wildcard test/sql/*.sql) + +REGRESS_BRIN := $(shell LD_LIBRARY_PATH=$(LD_LIBRARY_PATH) $(PG_CONFIG) --version | grep -qE "XL 9\.[5-9]| 10\.0| 11\.[0-9]| 12\.[0-9]" && echo brin-xl) +REGRESS_BRIN += $(shell LD_LIBRARY_PATH=$(LD_LIBRARY_PATH) $(PG_CONFIG) --version | grep -E "9\.[5-9]| 10\.0| 11\.[0-9]| 12\.[0-9]" | grep -qEv "XL" && echo brin) +REGRESS_VERSION_SPECIFIC := $(shell LD_LIBRARY_PATH=$(LD_LIBRARY_PATH) $(PG_CONFIG) --version | grep -qE "XL" && echo index-xl || echo index) +REGRESS = $(shell echo aggregate cast comparison overflow $(REGRESS_BRIN) $(REGRESS_VERSION_SPECIFIC)) + +REGRESS_OPTS = --inputdir=test --outputdir=test --load-extension=babelfishpg_money + +ifdef USE_PGXS +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/babelfishpg_money +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif + +AGGSTATESQL := $(shell LD_LIBRARY_PATH=$(LD_LIBRARY_PATH) $(PG_CONFIG) --version | grep -qE "XL" && echo fixeddecimalaggstate.sql) +AGGFUNCSSQL := $(shell LD_LIBRARY_PATH=$(LD_LIBRARY_PATH) $(PG_CONFIG) --version | grep -qE "XL" && echo fixeddecimal--xlaggs.sql) + +AGGFUNCSSQL := $(shell LD_LIBRARY_PATH=$(LD_LIBRARY_PATH) $(PG_CONFIG) --version | grep -qE "9\.[6-9]| 10\.[0-9]| 11\.[0-9]| 12\.[0-9]" && echo fixeddecimal--parallelaggs.sql || echo fixeddecimal--aggs.sql) + +BRINSQL := $(shell LD_LIBRARY_PATH=$(LD_LIBRARY_PATH) $(PG_CONFIG) --version | grep -qE "9\.[5-9]| 10\.[0-9]| 11\.[0-9]| 12\.[0-9]" && echo fixeddecimal--brin.sql) + +# 9.6 was the dawn of parallel query, so we'll use the parallel enabled .sql file from then on. +BASESQL := $(shell LD_LIBRARY_PATH=$(LD_LIBRARY_PATH) $(PG_CONFIG) --version | grep -qE "9\.[6-9]| 10\.[0-9]| 11\.[0-9]| 12\.[0-9]" && echo fixeddecimal--1.1.0_base_parallel.sql || echo fixeddecimal--1.1.0_base.sql) + +OBJECTS := $(addprefix $(srcdir)/, $(AGGSTATESQL) $(BASESQL) $(AGGFUNCSSQL) $(BRINSQL)) + +babelfishpg_money--1.1.0.sql: $(OBJECTS) + cat $^ > $@ diff --git a/contrib/babelfishpg_money/README.md b/contrib/babelfishpg_money/README.md new file mode 100755 index 00000000000..8199dc6e707 --- /dev/null +++ b/contrib/babelfishpg_money/README.md @@ -0,0 +1,162 @@ +FIXEDDECIMAL +============ + +Works with PostgreSQL 9.5 or higher. +The latest test was executed on version 12. + +Overview +-------- + +FixedDecimal is a fixed precision decimal type which provides a subset of the +features of PostgreSQL's builtin NUMERIC type, but with vastly increased +performance. Fixeddecimal is targeted to cases where performance and disk space +are a critical. + +Just use FIXEDDECIMAL(n, 2) rather than NUMERIC(n, 2) for n=3..17 + +Often there are data storage requirements where the built in REAL and +DOUBLE PRECISION types cannot be used due to the non-exact representation of +numbers using these types, e.g. where monetary values need to be stored. In many +of these cases NUMERIC is an almost perfect type, although with NUMERIC +performance is no match for the performance of REAL or DOUBLE PRECISION, as +these use CPU native processor types. + +FixedDecimal delivers performance advantages over NUMERIC with full precision for +addition and subtraction. Just as occurs with REAL and DOUBLE PRECISION, there +are some caveats for multiplication and division. + +Behavioural differences between FIXEDDECIMAL and NUMERIC +-------------------------------------------------------- + +It should be noted that there are cases were FIXEDDECIMAL behaves differently +from NUMERIC. + +1. FIXEDDECIMAL has a much more limited range of values than NUMERIC. By + default this type can represent a maximum range of FIXEDDECIMAL(17,2), + although the underlying type is unable to represent the full range of + of the 17th significant digit. + +2. FIXEDDECIMAL always rounds towards zero. + +3. FIXEDDECIMAL does not support NaN. + +4. Any attempt to use a numerical scale other than the default fixed scale + will result in an error. e.g. SELECT '123.223'::FIXEDDECIMAL(4,1) will fail + by default, as the default scale is 2, not 1. + +Internals +--------- + +FIXEDDECIMAL internally uses a 64bit integer type for its underlying storage. +This is what gives the type the performance advantage over NUMERIC, as most +calculations are performed as native processor operations rather than software +implementations as in the case with NUMERIC. + +FIXEDDECIMAL has a fixed scale value, which by default is 2. Internally numbers +are stores as the actual value multiplied by 100. e.g. 50 would be stored as +5000, and 1.23 would be stored as 123. This internal representation allows very +fast and accurate addition and subtraction between two fixeddecimal types. + +Multiplication between two fixeddecimal types is slightly more complex. If we +perform 2.00 * 3.00 in fixeddecimal, internally these numbers would be 200 and +300 respectively, so internally 200 * 300 becomes 60000, which must be divided +by 100 in order to obtain the correct internal result of 600, which of course +externally is 6.00. This method of multiplication is hazard to overflowing the +internal 64bit integer type, for this reason all multiplication and division is +performed using 128bit integer types. + +Internally, by default, FIXEDDECIMAL is limited to a maximum value of +92233720368547758.07 and a minimum value of -92233720368547758.08. If any of +these limits are exceeded the query will fail with an error. + +By default the scale of FIXEDDECIMAL is 2 decimal digits after the decimal +point. This value may be changed only by recompiling FIXEDDECIMAL from source, +which is done by altering the FIXEDDECIMAL_MULTIPLIER and FIXEDDECIMAL_SCALE +constants. If the FIXEDDECIMAL_SCALE was set to 4, then the +FIXEDDECIMAL_MULTIPLIER should be set to 10000. Doing this will mean that the +absolute limits of the type decrease to a range of -922337203685477.5808 to +922337203685477.5807. + +Caution +------- + +FIXEDDECIMAL is mainly intended as a fast and efficient data type which will +suit a limited set numerical data storage and retrieval needs. Complex +arithmetic could be said to be one of fixeddecimal's limits. As stated above +division always rounds towards zero. Please observe the following example: + +``` +test=# select '2.00'::fixeddecimal / '3.00'::fixeddecimal; + ?column? +---------- + 0.66 +(1 row) +``` + +A workaround of this would be to perform all calculations in NUMERIC, and +ROUND() the result into the maximum scale of FIXEDDECIMAL: + +``` +test=# select round('2.00'::numeric / '3.00'::numeric, 2)::fixeddecimal; + ?column? +---------- + 0.67 +(1 row) +``` + +It should also be noted that excess precision is ignored by fixeddecimal. +With a FIXEDDECIMAL_PRECISION of 2, any value after the 2nd digit following +the decimal point is completely ignored rather than rounded. The following +example demonstrates this: + +``` +test=# select '1.239'::fixeddecimal; + fixeddecimal +-------------- + 1.23 +(1 row) +``` + +It is especially important to remember that this truncation also occurs during +arithmetic. Notice in the following example the result is 1120 rather than +1129, since 1.129 is immediately rounded to 1.12 on input. + +``` +test=# select '1000'::fixeddecimal * '1.129'::fixeddecimal; + ?column? +---------- + 1120.00 +(1 row) +``` + +Installation +------------ + +To install fixeddecimal you must build the extension from source code. + +First ensure that your PATH environment variable is setup to find the correct +PostgreSQL installation first. You can check this by typing running the +pg_config command and checking the paths listed. + +Once you are confident your PATH variable is set correctly + +``` +make +make install +make installcheck +``` + +From psql, in order to create the extension you must type: + +``` +CREATE EXTENSION fixeddecimal; +``` + +Credits +------- + +fixeddecimal is open source using The PostgreSQL Licence, copyright is novated to the PostgreSQL Global Development Group. + +Source code developed by 2ndQuadrant, as part of the AXLE project (http://axleproject.eu) which received funding from the European Union’s Seventh Framework Programme (FP7/2007-2015) under grant agreement n° 318633 + +Lead Developer - David Rowley diff --git a/contrib/babelfishpg_money/babelfishpg_money.control b/contrib/babelfishpg_money/babelfishpg_money.control new file mode 100755 index 00000000000..d4ddb8a067b --- /dev/null +++ b/contrib/babelfishpg_money/babelfishpg_money.control @@ -0,0 +1,4 @@ +comment = 'babelfishpg_money' +default_version = '1.1.0' +relocatable = false +module_pathname = '$libdir/babelfishpg_money' diff --git a/contrib/babelfishpg_money/fixeddecimal--1.0.0--1.1.0.sql b/contrib/babelfishpg_money/fixeddecimal--1.0.0--1.1.0.sql new file mode 100644 index 00000000000..2eb08ae4d54 --- /dev/null +++ b/contrib/babelfishpg_money/fixeddecimal--1.0.0--1.1.0.sql @@ -0,0 +1,800 @@ +CREATE FUNCTION fixeddecimal_numeric_cmp(FIXEDDECIMAL, NUMERIC) +RETURNS INT4 +AS 'babelfishpg_money', 'fixeddecimal_numeric_cmp' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION numeric_fixeddecimal_cmp(NUMERIC, FIXEDDECIMAL) +RETURNS INT4 +AS 'babelfishpg_money', 'numeric_fixeddecimal_cmp' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_numeric_eq(FIXEDDECIMAL, NUMERIC) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_numeric_eq' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_numeric_ne(FIXEDDECIMAL, NUMERIC) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_numeric_ne' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_numeric_lt(FIXEDDECIMAL, NUMERIC) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_numeric_lt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_numeric_le(FIXEDDECIMAL, NUMERIC) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_numeric_le' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_numeric_gt(FIXEDDECIMAL, NUMERIC) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_numeric_gt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_numeric_ge(FIXEDDECIMAL, NUMERIC) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_numeric_ge' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR = ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = NUMERIC, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = fixeddecimal_numeric_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR <> ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = NUMERIC, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = fixeddecimal_numeric_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR < ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = NUMERIC, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = fixeddecimal_numeric_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR <= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = NUMERIC, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = fixeddecimal_numeric_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR >= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = NUMERIC, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = fixeddecimal_numeric_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR > ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = NUMERIC, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = fixeddecimal_numeric_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR CLASS fixeddecimal_numeric_ops +FOR TYPE FIXEDDECIMAL USING btree AS + OPERATOR 1 < (FIXEDDECIMAL, NUMERIC), + OPERATOR 2 <= (FIXEDDECIMAL, NUMERIC), + OPERATOR 3 = (FIXEDDECIMAL, NUMERIC), + OPERATOR 4 >= (FIXEDDECIMAL, NUMERIC), + OPERATOR 5 > (FIXEDDECIMAL, NUMERIC), + FUNCTION 1 fixeddecimal_numeric_cmp(FIXEDDECIMAL, NUMERIC); + +CREATE OPERATOR CLASS fixeddecimal_numeric_ops +FOR TYPE FIXEDDECIMAL USING hash AS + OPERATOR 1 = (FIXEDDECIMAL, NUMERIC), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + +-- NUMERIC, FIXEDDECIMAL +CREATE FUNCTION numeric_fixeddecimal_eq(NUMERIC, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'numeric_fixeddecimal_eq' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION numeric_fixeddecimal_ne(NUMERIC, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'numeric_fixeddecimal_ne' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION numeric_fixeddecimal_lt(NUMERIC, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'numeric_fixeddecimal_lt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION numeric_fixeddecimal_le(NUMERIC, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'numeric_fixeddecimal_le' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION numeric_fixeddecimal_gt(NUMERIC, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'numeric_fixeddecimal_gt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION numeric_fixeddecimal_ge(NUMERIC, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'numeric_fixeddecimal_ge' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR = ( + LEFTARG = NUMERIC, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = numeric_fixeddecimal_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR <> ( + LEFTARG = NUMERIC, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = numeric_fixeddecimal_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR < ( + LEFTARG = NUMERIC, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = numeric_fixeddecimal_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR <= ( + LEFTARG = NUMERIC, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = numeric_fixeddecimal_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR >= ( + LEFTARG = NUMERIC, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = numeric_fixeddecimal_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR > ( + LEFTARG = NUMERIC, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = numeric_fixeddecimal_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR CLASS numeric_fixeddecimal_ops +FOR TYPE FIXEDDECIMAL USING btree AS + OPERATOR 1 < (NUMERIC, FIXEDDECIMAL) FOR SEARCH, + OPERATOR 2 <= (NUMERIC, FIXEDDECIMAL) FOR SEARCH, + OPERATOR 3 = (NUMERIC, FIXEDDECIMAL) FOR SEARCH, + OPERATOR 4 >= (NUMERIC, FIXEDDECIMAL) FOR SEARCH, + OPERATOR 5 > (NUMERIC, FIXEDDECIMAL) FOR SEARCH, + FUNCTION 1 numeric_fixeddecimal_cmp(NUMERIC, FIXEDDECIMAL); + +CREATE OPERATOR CLASS numeric_fixeddecimal_ops +FOR TYPE FIXEDDECIMAL USING hash AS + OPERATOR 1 = (NUMERIC, FIXEDDECIMAL), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + +-- FIXEDDECIMAL, INT4 +CREATE FUNCTION fixeddecimal_int4_cmp(FIXEDDECIMAL, INT4) +RETURNS INT4 +AS 'babelfishpg_money', 'fixeddecimal_int4_cmp' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_int4_eq(FIXEDDECIMAL, INT4) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int4_eq' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_int4_ne(FIXEDDECIMAL, INT4) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int4_ne' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_int4_lt(FIXEDDECIMAL, INT4) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int4_lt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_int4_le(FIXEDDECIMAL, INT4) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int4_le' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_int4_gt(FIXEDDECIMAL, INT4) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int4_gt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_int4_ge(FIXEDDECIMAL, INT4) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int4_ge' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR = ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = fixeddecimal_int4_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR <> ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = fixeddecimal_int4_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR < ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = fixeddecimal_int4_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR <= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = fixeddecimal_int4_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR >= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = fixeddecimal_int4_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR > ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = fixeddecimal_int4_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR CLASS fixeddecimal_int4_ops +FOR TYPE FIXEDDECIMAL USING btree AS + OPERATOR 1 < (FIXEDDECIMAL, INT4), + OPERATOR 2 <= (FIXEDDECIMAL, INT4), + OPERATOR 3 = (FIXEDDECIMAL, INT4), + OPERATOR 4 >= (FIXEDDECIMAL, INT4), + OPERATOR 5 > (FIXEDDECIMAL, INT4), + FUNCTION 1 fixeddecimal_int4_cmp(FIXEDDECIMAL, INT4); + +CREATE OPERATOR CLASS fixeddecimal_int4_ops +FOR TYPE FIXEDDECIMAL USING hash AS + OPERATOR 1 = (FIXEDDECIMAL, INT4), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + +-- INT4, FIXEDDECIMAL +CREATE FUNCTION int4_fixeddecimal_cmp(INT4, FIXEDDECIMAL) +RETURNS INT4 +AS 'babelfishpg_money', 'int4_fixeddecimal_cmp' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int4_fixeddecimal_eq(INT4, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int4_fixeddecimal_eq' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int4_fixeddecimal_ne(INT4, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int4_fixeddecimal_ne' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int4_fixeddecimal_lt(INT4, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int4_fixeddecimal_lt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int4_fixeddecimal_le(INT4, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int4_fixeddecimal_le' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int4_fixeddecimal_gt(INT4, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int4_fixeddecimal_gt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int4_fixeddecimal_ge(INT4, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int4_fixeddecimal_ge' +LANGUAGE C IMMUTABLE STRICT; +CREATE OPERATOR = ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = int4_fixeddecimal_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR <> ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = int4_fixeddecimal_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR < ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = int4_fixeddecimal_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR <= ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = int4_fixeddecimal_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR >= ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = int4_fixeddecimal_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR > ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = int4_fixeddecimal_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR CLASS int4_fixeddecimal_ops +FOR TYPE FIXEDDECIMAL USING btree AS + OPERATOR 1 < (INT4, FIXEDDECIMAL), + OPERATOR 2 <= (INT4, FIXEDDECIMAL), + OPERATOR 3 = (INT4, FIXEDDECIMAL), + OPERATOR 4 >= (INT4, FIXEDDECIMAL), + OPERATOR 5 > (INT4, FIXEDDECIMAL), + FUNCTION 1 int4_fixeddecimal_cmp(INT4, FIXEDDECIMAL); + +CREATE OPERATOR CLASS int4_fixeddecimal_ops +FOR TYPE FIXEDDECIMAL USING hash AS + OPERATOR 1 = (INT4, FIXEDDECIMAL), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + +-- FIXEDDECIMAL, INT2 +CREATE FUNCTION fixeddecimal_int2_cmp(FIXEDDECIMAL, INT2) +RETURNS INT4 +AS 'babelfishpg_money', 'fixeddecimal_int2_cmp' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_int2_eq(FIXEDDECIMAL, INT2) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int2_eq' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_int2_ne(FIXEDDECIMAL, INT2) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int2_ne' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_int2_lt(FIXEDDECIMAL, INT2) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int2_lt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_int2_le(FIXEDDECIMAL, INT2) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int2_le' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_int2_gt(FIXEDDECIMAL, INT2) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int2_gt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_int2_ge(FIXEDDECIMAL, INT2) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int2_ge' +LANGUAGE C IMMUTABLE STRICT; +CREATE OPERATOR = ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = fixeddecimal_int2_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR <> ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = fixeddecimal_int2_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR < ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = fixeddecimal_int2_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR <= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = fixeddecimal_int2_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR >= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = fixeddecimal_int2_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR > ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = fixeddecimal_int2_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR CLASS fixeddecimal_int2_ops +FOR TYPE FIXEDDECIMAL USING btree AS + OPERATOR 1 < (FIXEDDECIMAL, INT2), + OPERATOR 2 <= (FIXEDDECIMAL, INT2), + OPERATOR 3 = (FIXEDDECIMAL, INT2), + OPERATOR 4 >= (FIXEDDECIMAL, INT2), + OPERATOR 5 > (FIXEDDECIMAL, INT2), + FUNCTION 1 fixeddecimal_int2_cmp(FIXEDDECIMAL, INT2); + +CREATE OPERATOR CLASS fixeddecimal_int2_ops +FOR TYPE FIXEDDECIMAL USING hash AS + OPERATOR 1 = (FIXEDDECIMAL, INT2), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + +-- INT2, FIXEDDECIMAL +CREATE FUNCTION int2_fixeddecimal_cmp(INT2, FIXEDDECIMAL) +RETURNS INT4 +AS 'babelfishpg_money', 'int2_fixeddecimal_cmp' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int2_fixeddecimal_eq(INT2, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int2_fixeddecimal_eq' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int2_fixeddecimal_ne(INT2, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int2_fixeddecimal_ne' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int2_fixeddecimal_lt(INT2, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int2_fixeddecimal_lt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int2_fixeddecimal_le(INT2, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int2_fixeddecimal_le' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int2_fixeddecimal_gt(INT2, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int2_fixeddecimal_gt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int2_fixeddecimal_ge(INT2, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int2_fixeddecimal_ge' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR = ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = int2_fixeddecimal_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR <> ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = int2_fixeddecimal_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR < ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = int2_fixeddecimal_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR <= ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = int2_fixeddecimal_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR >= ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = int2_fixeddecimal_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR > ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = int2_fixeddecimal_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR CLASS int2_fixeddecimal_ops +FOR TYPE FIXEDDECIMAL USING btree AS + OPERATOR 1 < (INT2, FIXEDDECIMAL), + OPERATOR 2 <= (INT2, FIXEDDECIMAL), + OPERATOR 3 = (INT2, FIXEDDECIMAL), + OPERATOR 4 >= (INT2, FIXEDDECIMAL), + OPERATOR 5 > (INT2, FIXEDDECIMAL), + FUNCTION 1 int2_fixeddecimal_cmp(INT2, FIXEDDECIMAL); + +CREATE OPERATOR CLASS int2_fixeddecimal_ops +FOR TYPE FIXEDDECIMAL USING hash AS + OPERATOR 1 = (INT2, FIXEDDECIMAL), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + + +-- 9.6+ Parallel function changes. +ALTER FUNCTION fixeddecimalin(cstring, oid, int4) PARALLEL SAFE; +ALTER FUNCTION fixeddecimalout(fixeddecimal) PARALLEL SAFE; +ALTER FUNCTION fixeddecimalrecv(internal) PARALLEL SAFE; +ALTER FUNCTION fixeddecimalsend(FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION fixeddecimaltypmodin(_cstring) PARALLEL SAFE; +ALTER FUNCTION fixeddecimaltypmodout(INT4) PARALLEL SAFE; +ALTER FUNCTION fixeddecimaleq(FIXEDDECIMAL, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION fixeddecimalne(FIXEDDECIMAL, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION fixeddecimallt(FIXEDDECIMAL, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION fixeddecimalle(FIXEDDECIMAL, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION fixeddecimalgt(FIXEDDECIMAL, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION fixeddecimalge(FIXEDDECIMAL, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION fixeddecimalum(FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION fixeddecimalpl(FIXEDDECIMAL, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION fixeddecimalmi(FIXEDDECIMAL, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION fixeddecimalmul(FIXEDDECIMAL, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION fixeddecimaldiv(FIXEDDECIMAL, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION abs(FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION fixeddecimallarger(FIXEDDECIMAL, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION fixeddecimalsmaller(FIXEDDECIMAL, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION fixeddecimal_cmp(FIXEDDECIMAL, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION fixeddecimal_hash(FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION fixeddecimal_numeric_cmp(FIXEDDECIMAL, NUMERIC) PARALLEL SAFE; +ALTER FUNCTION numeric_fixeddecimal_cmp(NUMERIC, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION fixeddecimal_numeric_eq(FIXEDDECIMAL, NUMERIC) PARALLEL SAFE; +ALTER FUNCTION fixeddecimal_numeric_ne(FIXEDDECIMAL, NUMERIC) PARALLEL SAFE; +ALTER FUNCTION fixeddecimal_numeric_lt(FIXEDDECIMAL, NUMERIC) PARALLEL SAFE; +ALTER FUNCTION fixeddecimal_numeric_le(FIXEDDECIMAL, NUMERIC) PARALLEL SAFE; +ALTER FUNCTION fixeddecimal_numeric_gt(FIXEDDECIMAL, NUMERIC) PARALLEL SAFE; +ALTER FUNCTION fixeddecimal_numeric_ge(FIXEDDECIMAL, NUMERIC) PARALLEL SAFE; +ALTER FUNCTION numeric_fixeddecimal_eq(NUMERIC, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION numeric_fixeddecimal_ne(NUMERIC, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION numeric_fixeddecimal_lt(NUMERIC, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION numeric_fixeddecimal_le(NUMERIC, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION numeric_fixeddecimal_gt(NUMERIC, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION numeric_fixeddecimal_ge(NUMERIC, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION fixeddecimal_int4_cmp(FIXEDDECIMAL, INT4) PARALLEL SAFE; +ALTER FUNCTION fixeddecimal_int4_eq(FIXEDDECIMAL, INT4) PARALLEL SAFE; +ALTER FUNCTION fixeddecimal_int4_ne(FIXEDDECIMAL, INT4) PARALLEL SAFE; +ALTER FUNCTION fixeddecimal_int4_lt(FIXEDDECIMAL, INT4) PARALLEL SAFE; +ALTER FUNCTION fixeddecimal_int4_le(FIXEDDECIMAL, INT4) PARALLEL SAFE; +ALTER FUNCTION fixeddecimal_int4_gt(FIXEDDECIMAL, INT4) PARALLEL SAFE; +ALTER FUNCTION fixeddecimal_int4_ge(FIXEDDECIMAL, INT4) PARALLEL SAFE; +ALTER FUNCTION fixeddecimalint4pl(FIXEDDECIMAL, INT4) PARALLEL SAFE; +ALTER FUNCTION fixeddecimalint4mi(FIXEDDECIMAL, INT4) PARALLEL SAFE; +ALTER FUNCTION fixeddecimalint4mul(FIXEDDECIMAL, INT4) PARALLEL SAFE; +ALTER FUNCTION fixeddecimalint4div(FIXEDDECIMAL, INT4) PARALLEL SAFE; +ALTER FUNCTION int4_fixeddecimal_cmp(INT4, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION int4_fixeddecimal_eq(INT4, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION int4_fixeddecimal_ne(INT4, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION int4_fixeddecimal_lt(INT4, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION int4_fixeddecimal_le(INT4, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION int4_fixeddecimal_gt(INT4, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION int4_fixeddecimal_ge(INT4, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION int4fixeddecimalpl(INT4, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION int4fixeddecimalmi(INT4, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION int4fixeddecimalmul(INT4, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION int4fixeddecimaldiv(INT4, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION fixeddecimal_int2_cmp(FIXEDDECIMAL, INT2) PARALLEL SAFE; +ALTER FUNCTION fixeddecimal_int2_eq(FIXEDDECIMAL, INT2) PARALLEL SAFE; +ALTER FUNCTION fixeddecimal_int2_ne(FIXEDDECIMAL, INT2) PARALLEL SAFE; +ALTER FUNCTION fixeddecimal_int2_lt(FIXEDDECIMAL, INT2) PARALLEL SAFE; +ALTER FUNCTION fixeddecimal_int2_le(FIXEDDECIMAL, INT2) PARALLEL SAFE; +ALTER FUNCTION fixeddecimal_int2_gt(FIXEDDECIMAL, INT2) PARALLEL SAFE; +ALTER FUNCTION fixeddecimal_int2_ge(FIXEDDECIMAL, INT2) PARALLEL SAFE; +ALTER FUNCTION fixeddecimalint2pl(FIXEDDECIMAL, INT2) PARALLEL SAFE; +ALTER FUNCTION fixeddecimalint2mi(FIXEDDECIMAL, INT2) PARALLEL SAFE; +ALTER FUNCTION fixeddecimalint2mul(FIXEDDECIMAL, INT2) PARALLEL SAFE; +ALTER FUNCTION fixeddecimalint2div(FIXEDDECIMAL, INT2) PARALLEL SAFE; +ALTER FUNCTION int2_fixeddecimal_cmp(INT2, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION int2_fixeddecimal_eq(INT2, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION int2_fixeddecimal_ne(INT2, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION int2_fixeddecimal_lt(INT2, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION int2_fixeddecimal_le(INT2, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION int2_fixeddecimal_gt(INT2, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION int2_fixeddecimal_ge(INT2, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION int2fixeddecimalpl(INT2, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION int2fixeddecimalmi(INT2, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION int2fixeddecimalmul(INT2, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION int2fixeddecimaldiv(INT2, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION fixeddecimal(FIXEDDECIMAL, INT4) PARALLEL SAFE; +ALTER FUNCTION int4fixeddecimal(INT4) PARALLEL SAFE; +ALTER FUNCTION fixeddecimalint4(FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION int2fixeddecimal(INT2) PARALLEL SAFE; +ALTER FUNCTION fixeddecimalint2(FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION fixeddecimaltod(FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION dtofixeddecimal(DOUBLE PRECISION) PARALLEL SAFE; +ALTER FUNCTION fixeddecimaltof(FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION ftofixeddecimal(REAL) PARALLEL SAFE; +ALTER FUNCTION fixeddecimal_numeric(FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION numeric_fixeddecimal(NUMERIC) PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalaggstatecombine(INTERNAL, INTERNAL) +RETURNS INTERNAL +AS 'babelfishpg_money', 'fixeddecimalaggstatecombine' +LANGUAGE C IMMUTABLE PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalaggstateserialize(INTERNAL) +RETURNS BYTEA +AS 'babelfishpg_money', 'fixeddecimalaggstateserialize' +LANGUAGE C IMMUTABLE PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalaggstatedeserialize(BYTEA, INTERNAL) +RETURNS INTERNAL +AS 'babelfishpg_money', 'fixeddecimalaggstatedeserialize' +LANGUAGE C IMMUTABLE PARALLEL SAFE; + + +UPDATE pg_proc SET proparallel = 's' +WHERE oid = 'min(FIXEDDECIMAL)'::pg_catalog.regprocedure; + +UPDATE pg_proc SET proparallel = 's' +WHERE oid = 'max(FIXEDDECIMAL)'::pg_catalog.regprocedure; + +UPDATE pg_proc SET proparallel = 's' +WHERE oid = 'sum(FIXEDDECIMAL)'::pg_catalog.regprocedure; + +UPDATE pg_proc SET proparallel = 's' +WHERE oid = 'avg(FIXEDDECIMAL)'::pg_catalog.regprocedure; + +UPDATE pg_aggregate SET aggcombinefn = 'fixeddecimalsmaller' +WHERE aggfnoid = 'min(FIXEDDECIMAL)'::pg_catalog.regprocedure; + +UPDATE pg_aggregate SET aggcombinefn = 'fixeddecimallarger' +WHERE aggfnoid = 'max(FIXEDDECIMAL)'::pg_catalog.regprocedure; + +UPDATE pg_aggregate SET aggcombinefn = 'fixeddecimalaggstatecombine', + aggserialfn = 'fixeddecimalaggstateserialize', + aggdeserialfn = 'fixeddecimalaggstatedeserialize' +WHERE aggfnoid = 'sum(FIXEDDECIMAL)'::pg_catalog.regprocedure; + +UPDATE pg_aggregate SET aggcombinefn = 'fixeddecimalaggstatecombine', + aggserialfn = 'fixeddecimalaggstateserialize', + aggdeserialfn = 'fixeddecimalaggstatedeserialize' +WHERE aggfnoid = 'avg(FIXEDDECIMAL)'::pg_catalog.regprocedure; diff --git a/contrib/babelfishpg_money/fixeddecimal--1.0.0_base.sql b/contrib/babelfishpg_money/fixeddecimal--1.0.0_base.sql new file mode 100755 index 00000000000..f991e9a5ac0 --- /dev/null +++ b/contrib/babelfishpg_money/fixeddecimal--1.0.0_base.sql @@ -0,0 +1,527 @@ +------------------ +-- FIXEDDECIMAL -- +------------------ + +CREATE TYPE FIXEDDECIMAL; + +CREATE FUNCTION fixeddecimalin(cstring, oid, int4) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalin' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalout(fixeddecimal) +RETURNS cstring +AS 'babelfishpg_money', 'fixeddecimalout' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalrecv(internal) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalrecv' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalsend(FIXEDDECIMAL) +RETURNS bytea +AS 'babelfishpg_money', 'fixeddecimalsend' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimaltypmodin(_cstring) +RETURNS INT4 +AS 'babelfishpg_money', 'fixeddecimaltypmodin' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimaltypmodout(INT4) +RETURNS cstring +AS 'babelfishpg_money', 'fixeddecimaltypmodout' +LANGUAGE C IMMUTABLE STRICT; + + +CREATE TYPE FIXEDDECIMAL ( + INPUT = fixeddecimalin, + OUTPUT = fixeddecimalout, + RECEIVE = fixeddecimalrecv, + SEND = fixeddecimalsend, + TYPMOD_IN = fixeddecimaltypmodin, + TYPMOD_OUT = fixeddecimaltypmodout, + INTERNALLENGTH = 8, + ALIGNMENT = 'double', + STORAGE = plain, + CATEGORY = 'N', + PREFERRED = true, + COLLATABLE = false, + PASSEDBYVALUE -- But not always.. XXX fix that. +); + +CREATE FUNCTION fixeddecimaleq(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimaleq' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalne(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimalne' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimallt(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimallt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalle(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimalle' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalgt(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimalgt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalge(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimalge' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalum(FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalum' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalpl(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalpl' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalmi(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalmi' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalmul(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalmul' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimaldiv(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimaldiv' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION abs(FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalabs' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimallarger(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimallarger' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalsmaller(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalsmaller' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_cmp(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS INT4 +AS 'babelfishpg_money', 'fixeddecimal_cmp' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_hash(FIXEDDECIMAL) +RETURNS INT4 +AS 'babelfishpg_money', 'fixeddecimal_hash' +LANGUAGE C IMMUTABLE STRICT; + +-- +-- Operators. +-- + +CREATE OPERATOR = ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = fixeddecimaleq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR <> ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = fixeddecimalne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR < ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = fixeddecimallt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR <= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = fixeddecimalle, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR >= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = fixeddecimalge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR > ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = fixeddecimalgt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR + ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = +, + PROCEDURE = fixeddecimalpl +); + +CREATE OPERATOR - ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = fixeddecimalmi +); + +CREATE OPERATOR - ( + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = fixeddecimalum +); + +CREATE OPERATOR * ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = *, + PROCEDURE = fixeddecimalmul +); + +CREATE OPERATOR / ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = fixeddecimaldiv +); + +CREATE OPERATOR CLASS fixeddecimal_ops +DEFAULT FOR TYPE FIXEDDECIMAL USING btree AS + OPERATOR 1 < (FIXEDDECIMAL, FIXEDDECIMAL), + OPERATOR 2 <= (FIXEDDECIMAL, FIXEDDECIMAL), + OPERATOR 3 = (FIXEDDECIMAL, FIXEDDECIMAL), + OPERATOR 4 >= (FIXEDDECIMAL, FIXEDDECIMAL), + OPERATOR 5 > (FIXEDDECIMAL, FIXEDDECIMAL), + FUNCTION 1 fixeddecimal_cmp(FIXEDDECIMAL, FIXEDDECIMAL); + +CREATE OPERATOR CLASS fixeddecimal_ops +DEFAULT FOR TYPE FIXEDDECIMAL USING hash AS + OPERATOR 1 = (FIXEDDECIMAL, FIXEDDECIMAL), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + +-- +-- Cross type operators with int4 +-- + +CREATE FUNCTION fixeddecimalint4pl(FIXEDDECIMAL, INT4) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalint4pl' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalint4mi(FIXEDDECIMAL, INT4) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalint4mi' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalint4mul(FIXEDDECIMAL, INT4) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalint4mul' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalint4div(FIXEDDECIMAL, INT4) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalint4div' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR + ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + COMMUTATOR = +, + PROCEDURE = fixeddecimalint4pl +); + +CREATE OPERATOR - ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + PROCEDURE = fixeddecimalint4mi +); + +CREATE OPERATOR * ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + COMMUTATOR = *, + PROCEDURE = fixeddecimalint4mul +); + +CREATE OPERATOR / ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + PROCEDURE = fixeddecimalint4div +); + + +CREATE FUNCTION int4fixeddecimalpl(INT4, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'int4fixeddecimalpl' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int4fixeddecimalmi(INT4, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'int4fixeddecimalmi' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int4fixeddecimalmul(INT4, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'int4fixeddecimalmul' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int4fixeddecimaldiv(INT4, FIXEDDECIMAL) +RETURNS DOUBLE PRECISION +AS 'babelfishpg_money', 'int4fixeddecimaldiv' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR + ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = +, + PROCEDURE = int4fixeddecimalpl +); + +CREATE OPERATOR - ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = int4fixeddecimalmi +); + +CREATE OPERATOR * ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = *, + PROCEDURE = int4fixeddecimalmul +); + +CREATE OPERATOR / ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = int4fixeddecimaldiv +); + +-- +-- Cross type operators with int2 +-- + +CREATE FUNCTION fixeddecimalint2pl(FIXEDDECIMAL, INT2) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalint2pl' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalint2mi(FIXEDDECIMAL, INT2) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalint2mi' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalint2mul(FIXEDDECIMAL, INT2) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalint2mul' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalint2div(FIXEDDECIMAL, INT2) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalint2div' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR + ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + COMMUTATOR = +, + PROCEDURE = fixeddecimalint2pl +); + +CREATE OPERATOR - ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + PROCEDURE = fixeddecimalint2mi +); + +CREATE OPERATOR * ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + COMMUTATOR = *, + PROCEDURE = fixeddecimalint2mul +); + +CREATE OPERATOR / ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + PROCEDURE = fixeddecimalint2div +); + +CREATE FUNCTION int2fixeddecimalpl(INT2, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'int2fixeddecimalpl' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int2fixeddecimalmi(INT2, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'int2fixeddecimalmi' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int2fixeddecimalmul(INT2, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'int2fixeddecimalmul' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int2fixeddecimaldiv(INT2, FIXEDDECIMAL) +RETURNS DOUBLE PRECISION +AS 'babelfishpg_money', 'int2fixeddecimaldiv' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR + ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = +, + PROCEDURE = int2fixeddecimalpl +); + +CREATE OPERATOR - ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = int2fixeddecimalmi +); + +CREATE OPERATOR * ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = *, + PROCEDURE = int2fixeddecimalmul +); + +CREATE OPERATOR / ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = int2fixeddecimaldiv +); + +-- +-- Casts +-- + +CREATE FUNCTION fixeddecimal(FIXEDDECIMAL, INT4) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimal' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int4fixeddecimal(INT4) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'int4fixeddecimal' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalint4(FIXEDDECIMAL) +RETURNS INT4 +AS 'babelfishpg_money', 'fixeddecimalint4' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int2fixeddecimal(INT2) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'int2fixeddecimal' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalint2(FIXEDDECIMAL) +RETURNS INT2 +AS 'babelfishpg_money', 'fixeddecimalint2' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimaltod(FIXEDDECIMAL) +RETURNS DOUBLE PRECISION +AS 'babelfishpg_money', 'fixeddecimaltod' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION dtofixeddecimal(DOUBLE PRECISION) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'dtofixeddecimal' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimaltof(FIXEDDECIMAL) +RETURNS REAL +AS 'babelfishpg_money', 'fixeddecimaltof' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION ftofixeddecimal(REAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'ftofixeddecimal' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_numeric(FIXEDDECIMAL) +RETURNS NUMERIC +AS 'babelfishpg_money', 'fixeddecimal_numeric' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION numeric_fixeddecimal(NUMERIC) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'numeric_fixeddecimal' +LANGUAGE C IMMUTABLE STRICT; + +CREATE CAST (FIXEDDECIMAL AS FIXEDDECIMAL) + WITH FUNCTION fixeddecimal (FIXEDDECIMAL, INT4) AS ASSIGNMENT; + +CREATE CAST (INT4 AS FIXEDDECIMAL) + WITH FUNCTION int4fixeddecimal (INT4) AS IMPLICIT; + +CREATE CAST (FIXEDDECIMAL AS INT4) + WITH FUNCTION fixeddecimalint4 (FIXEDDECIMAL) AS ASSIGNMENT; + +CREATE CAST (INT2 AS FIXEDDECIMAL) + WITH FUNCTION int2fixeddecimal (INT2) AS IMPLICIT; + +CREATE CAST (FIXEDDECIMAL AS INT2) + WITH FUNCTION fixeddecimalint2 (FIXEDDECIMAL) AS ASSIGNMENT; + +CREATE CAST (FIXEDDECIMAL AS DOUBLE PRECISION) + WITH FUNCTION fixeddecimaltod (FIXEDDECIMAL) AS IMPLICIT; + +CREATE CAST (DOUBLE PRECISION AS FIXEDDECIMAL) + WITH FUNCTION dtofixeddecimal (DOUBLE PRECISION) AS ASSIGNMENT; -- XXX? or Implicit? + +CREATE CAST (FIXEDDECIMAL AS REAL) + WITH FUNCTION fixeddecimaltof (FIXEDDECIMAL) AS IMPLICIT; + +CREATE CAST (REAL AS FIXEDDECIMAL) + WITH FUNCTION ftofixeddecimal (REAL) AS ASSIGNMENT; -- XXX or Implicit? + +CREATE CAST (FIXEDDECIMAL AS NUMERIC) + WITH FUNCTION fixeddecimal_numeric (FIXEDDECIMAL) AS IMPLICIT; + +CREATE CAST (NUMERIC AS FIXEDDECIMAL) + WITH FUNCTION numeric_fixeddecimal (NUMERIC) AS ASSIGNMENT; diff --git a/contrib/babelfishpg_money/fixeddecimal--1.1.0_base.sql b/contrib/babelfishpg_money/fixeddecimal--1.1.0_base.sql new file mode 100755 index 00000000000..c9ff33d5ad0 --- /dev/null +++ b/contrib/babelfishpg_money/fixeddecimal--1.1.0_base.sql @@ -0,0 +1,1193 @@ +------------------ +-- FIXEDDECIMAL -- +------------------ + +CREATE TYPE FIXEDDECIMAL; + +CREATE FUNCTION fixeddecimalin(cstring, oid, int4) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalin' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalout(fixeddecimal) +RETURNS cstring +AS 'babelfishpg_money', 'fixeddecimalout' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalrecv(internal) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalrecv' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalsend(FIXEDDECIMAL) +RETURNS bytea +AS 'babelfishpg_money', 'fixeddecimalsend' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimaltypmodin(_cstring) +RETURNS INT4 +AS 'babelfishpg_money', 'fixeddecimaltypmodin' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimaltypmodout(INT4) +RETURNS cstring +AS 'babelfishpg_money', 'fixeddecimaltypmodout' +LANGUAGE C IMMUTABLE STRICT; + + +CREATE TYPE FIXEDDECIMAL ( + INPUT = fixeddecimalin, + OUTPUT = fixeddecimalout, + RECEIVE = fixeddecimalrecv, + SEND = fixeddecimalsend, + TYPMOD_IN = fixeddecimaltypmodin, + TYPMOD_OUT = fixeddecimaltypmodout, + INTERNALLENGTH = 8, + ALIGNMENT = 'double', + STORAGE = plain, + CATEGORY = 'N', + PREFERRED = true, + COLLATABLE = false, + PASSEDBYVALUE -- But not always.. XXX fix that. +); + +-- FIXEDDECIMAL, NUMERIC +CREATE FUNCTION fixeddecimaleq(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimaleq' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalne(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimalne' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimallt(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimallt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalle(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimalle' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalgt(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimalgt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalge(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimalge' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalum(FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalum' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalpl(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalpl' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalmi(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalmi' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalmul(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalmul' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimaldiv(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimaldiv' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION abs(FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalabs' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimallarger(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimallarger' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalsmaller(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalsmaller' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_cmp(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS INT4 +AS 'babelfishpg_money', 'fixeddecimal_cmp' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_hash(FIXEDDECIMAL) +RETURNS INT4 +AS 'babelfishpg_money', 'fixeddecimal_hash' +LANGUAGE C IMMUTABLE STRICT; + +-- +-- Operators. +-- + +-- FIXEDDECIMAL op FIXEDDECIMAL +CREATE OPERATOR = ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = fixeddecimaleq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR <> ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = fixeddecimalne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR < ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = fixeddecimallt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR <= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = fixeddecimalle, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR >= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = fixeddecimalge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR > ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = fixeddecimalgt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR + ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = +, + PROCEDURE = fixeddecimalpl +); + +CREATE OPERATOR - ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = fixeddecimalmi +); + +CREATE OPERATOR - ( + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = fixeddecimalum +); + +CREATE OPERATOR * ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = *, + PROCEDURE = fixeddecimalmul +); + +CREATE OPERATOR / ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = fixeddecimaldiv +); + +CREATE OPERATOR CLASS fixeddecimal_ops +DEFAULT FOR TYPE FIXEDDECIMAL USING btree AS + OPERATOR 1 < (FIXEDDECIMAL, FIXEDDECIMAL), + OPERATOR 2 <= (FIXEDDECIMAL, FIXEDDECIMAL), + OPERATOR 3 = (FIXEDDECIMAL, FIXEDDECIMAL), + OPERATOR 4 >= (FIXEDDECIMAL, FIXEDDECIMAL), + OPERATOR 5 > (FIXEDDECIMAL, FIXEDDECIMAL), + FUNCTION 1 fixeddecimal_cmp(FIXEDDECIMAL, FIXEDDECIMAL); + +CREATE OPERATOR CLASS fixeddecimal_ops +DEFAULT FOR TYPE FIXEDDECIMAL USING hash AS + OPERATOR 1 = (FIXEDDECIMAL, FIXEDDECIMAL), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + +-- FIXEDDECIMAL, NUMERIC +CREATE FUNCTION fixeddecimal_numeric_cmp(FIXEDDECIMAL, NUMERIC) +RETURNS INT4 +AS 'babelfishpg_money', 'fixeddecimal_numeric_cmp' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION numeric_fixeddecimal_cmp(NUMERIC, FIXEDDECIMAL) +RETURNS INT4 +AS 'babelfishpg_money', 'numeric_fixeddecimal_cmp' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_numeric_eq(FIXEDDECIMAL, NUMERIC) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_numeric_eq' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_numeric_ne(FIXEDDECIMAL, NUMERIC) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_numeric_ne' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_numeric_lt(FIXEDDECIMAL, NUMERIC) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_numeric_lt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_numeric_le(FIXEDDECIMAL, NUMERIC) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_numeric_le' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_numeric_gt(FIXEDDECIMAL, NUMERIC) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_numeric_gt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_numeric_ge(FIXEDDECIMAL, NUMERIC) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_numeric_ge' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR = ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = NUMERIC, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = fixeddecimal_numeric_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR <> ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = NUMERIC, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = fixeddecimal_numeric_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR < ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = NUMERIC, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = fixeddecimal_numeric_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR <= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = NUMERIC, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = fixeddecimal_numeric_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR >= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = NUMERIC, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = fixeddecimal_numeric_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR > ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = NUMERIC, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = fixeddecimal_numeric_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR CLASS fixeddecimal_numeric_ops +FOR TYPE FIXEDDECIMAL USING btree AS + OPERATOR 1 < (FIXEDDECIMAL, NUMERIC), + OPERATOR 2 <= (FIXEDDECIMAL, NUMERIC), + OPERATOR 3 = (FIXEDDECIMAL, NUMERIC), + OPERATOR 4 >= (FIXEDDECIMAL, NUMERIC), + OPERATOR 5 > (FIXEDDECIMAL, NUMERIC), + FUNCTION 1 fixeddecimal_numeric_cmp(FIXEDDECIMAL, NUMERIC); + +CREATE OPERATOR CLASS fixeddecimal_numeric_ops +FOR TYPE FIXEDDECIMAL USING hash AS + OPERATOR 1 = (FIXEDDECIMAL, NUMERIC), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + +-- NUMERIC, FIXEDDECIMAL +CREATE FUNCTION numeric_fixeddecimal_eq(NUMERIC, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'numeric_fixeddecimal_eq' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION numeric_fixeddecimal_ne(NUMERIC, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'numeric_fixeddecimal_ne' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION numeric_fixeddecimal_lt(NUMERIC, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'numeric_fixeddecimal_lt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION numeric_fixeddecimal_le(NUMERIC, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'numeric_fixeddecimal_le' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION numeric_fixeddecimal_gt(NUMERIC, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'numeric_fixeddecimal_gt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION numeric_fixeddecimal_ge(NUMERIC, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'numeric_fixeddecimal_ge' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR = ( + LEFTARG = NUMERIC, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = numeric_fixeddecimal_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR <> ( + LEFTARG = NUMERIC, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = numeric_fixeddecimal_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR < ( + LEFTARG = NUMERIC, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = numeric_fixeddecimal_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR <= ( + LEFTARG = NUMERIC, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = numeric_fixeddecimal_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR >= ( + LEFTARG = NUMERIC, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = numeric_fixeddecimal_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR > ( + LEFTARG = NUMERIC, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = numeric_fixeddecimal_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR CLASS numeric_fixeddecimal_ops +FOR TYPE FIXEDDECIMAL USING btree AS + OPERATOR 1 < (NUMERIC, FIXEDDECIMAL) FOR SEARCH, + OPERATOR 2 <= (NUMERIC, FIXEDDECIMAL) FOR SEARCH, + OPERATOR 3 = (NUMERIC, FIXEDDECIMAL) FOR SEARCH, + OPERATOR 4 >= (NUMERIC, FIXEDDECIMAL) FOR SEARCH, + OPERATOR 5 > (NUMERIC, FIXEDDECIMAL) FOR SEARCH, + FUNCTION 1 numeric_fixeddecimal_cmp(NUMERIC, FIXEDDECIMAL); + +CREATE OPERATOR CLASS numeric_fixeddecimal_ops +FOR TYPE FIXEDDECIMAL USING hash AS + OPERATOR 1 = (NUMERIC, FIXEDDECIMAL), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + +-- +-- Cross type operators with int4 +-- + +-- FIXEDDECIMAL, INT4 +CREATE FUNCTION fixeddecimal_int4_cmp(FIXEDDECIMAL, INT4) +RETURNS INT4 +AS 'babelfishpg_money', 'fixeddecimal_int4_cmp' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_int4_eq(FIXEDDECIMAL, INT4) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int4_eq' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_int4_ne(FIXEDDECIMAL, INT4) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int4_ne' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_int4_lt(FIXEDDECIMAL, INT4) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int4_lt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_int4_le(FIXEDDECIMAL, INT4) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int4_le' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_int4_gt(FIXEDDECIMAL, INT4) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int4_gt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_int4_ge(FIXEDDECIMAL, INT4) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int4_ge' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalint4pl(FIXEDDECIMAL, INT4) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalint4pl' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalint4mi(FIXEDDECIMAL, INT4) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalint4mi' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalint4mul(FIXEDDECIMAL, INT4) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalint4mul' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalint4div(FIXEDDECIMAL, INT4) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalint4div' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR = ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = fixeddecimal_int4_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR <> ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = fixeddecimal_int4_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR < ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = fixeddecimal_int4_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR <= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = fixeddecimal_int4_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR >= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = fixeddecimal_int4_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR > ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = fixeddecimal_int4_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR + ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + COMMUTATOR = +, + PROCEDURE = fixeddecimalint4pl +); + +CREATE OPERATOR - ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + PROCEDURE = fixeddecimalint4mi +); + +CREATE OPERATOR * ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + COMMUTATOR = *, + PROCEDURE = fixeddecimalint4mul +); + +CREATE OPERATOR / ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + PROCEDURE = fixeddecimalint4div +); + +CREATE OPERATOR CLASS fixeddecimal_int4_ops +FOR TYPE FIXEDDECIMAL USING btree AS + OPERATOR 1 < (FIXEDDECIMAL, INT4), + OPERATOR 2 <= (FIXEDDECIMAL, INT4), + OPERATOR 3 = (FIXEDDECIMAL, INT4), + OPERATOR 4 >= (FIXEDDECIMAL, INT4), + OPERATOR 5 > (FIXEDDECIMAL, INT4), + FUNCTION 1 fixeddecimal_int4_cmp(FIXEDDECIMAL, INT4); + +CREATE OPERATOR CLASS fixeddecimal_int4_ops +FOR TYPE FIXEDDECIMAL USING hash AS + OPERATOR 1 = (FIXEDDECIMAL, INT4), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + +-- INT4, FIXEDDECIMAL +CREATE FUNCTION int4_fixeddecimal_cmp(INT4, FIXEDDECIMAL) +RETURNS INT4 +AS 'babelfishpg_money', 'int4_fixeddecimal_cmp' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int4_fixeddecimal_eq(INT4, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int4_fixeddecimal_eq' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int4_fixeddecimal_ne(INT4, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int4_fixeddecimal_ne' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int4_fixeddecimal_lt(INT4, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int4_fixeddecimal_lt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int4_fixeddecimal_le(INT4, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int4_fixeddecimal_le' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int4_fixeddecimal_gt(INT4, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int4_fixeddecimal_gt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int4_fixeddecimal_ge(INT4, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int4_fixeddecimal_ge' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int4fixeddecimalpl(INT4, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'int4fixeddecimalpl' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int4fixeddecimalmi(INT4, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'int4fixeddecimalmi' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int4fixeddecimalmul(INT4, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'int4fixeddecimalmul' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int4fixeddecimaldiv(INT4, FIXEDDECIMAL) +RETURNS DOUBLE PRECISION +AS 'babelfishpg_money', 'int4fixeddecimaldiv' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR = ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = int4_fixeddecimal_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR <> ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = int4_fixeddecimal_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR < ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = int4_fixeddecimal_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR <= ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = int4_fixeddecimal_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR >= ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = int4_fixeddecimal_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR > ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = int4_fixeddecimal_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR + ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = +, + PROCEDURE = int4fixeddecimalpl +); + +CREATE OPERATOR - ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = int4fixeddecimalmi +); + +CREATE OPERATOR * ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = *, + PROCEDURE = int4fixeddecimalmul +); + +CREATE OPERATOR / ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = int4fixeddecimaldiv +); + +CREATE OPERATOR CLASS int4_fixeddecimal_ops +FOR TYPE FIXEDDECIMAL USING btree AS + OPERATOR 1 < (INT4, FIXEDDECIMAL), + OPERATOR 2 <= (INT4, FIXEDDECIMAL), + OPERATOR 3 = (INT4, FIXEDDECIMAL), + OPERATOR 4 >= (INT4, FIXEDDECIMAL), + OPERATOR 5 > (INT4, FIXEDDECIMAL), + FUNCTION 1 int4_fixeddecimal_cmp(INT4, FIXEDDECIMAL); + +CREATE OPERATOR CLASS int4_fixeddecimal_ops +FOR TYPE FIXEDDECIMAL USING hash AS + OPERATOR 1 = (INT4, FIXEDDECIMAL), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + +-- +-- Cross type operators with int2 +-- +-- FIXEDDECIMAL, INT2 +CREATE FUNCTION fixeddecimal_int2_cmp(FIXEDDECIMAL, INT2) +RETURNS INT4 +AS 'babelfishpg_money', 'fixeddecimal_int2_cmp' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_int2_eq(FIXEDDECIMAL, INT2) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int2_eq' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_int2_ne(FIXEDDECIMAL, INT2) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int2_ne' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_int2_lt(FIXEDDECIMAL, INT2) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int2_lt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_int2_le(FIXEDDECIMAL, INT2) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int2_le' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_int2_gt(FIXEDDECIMAL, INT2) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int2_gt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_int2_ge(FIXEDDECIMAL, INT2) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int2_ge' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalint2pl(FIXEDDECIMAL, INT2) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalint2pl' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalint2mi(FIXEDDECIMAL, INT2) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalint2mi' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalint2mul(FIXEDDECIMAL, INT2) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalint2mul' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalint2div(FIXEDDECIMAL, INT2) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalint2div' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR = ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = fixeddecimal_int2_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR <> ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = fixeddecimal_int2_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR < ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = fixeddecimal_int2_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR <= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = fixeddecimal_int2_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR >= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = fixeddecimal_int2_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR > ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = fixeddecimal_int2_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR + ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + COMMUTATOR = +, + PROCEDURE = fixeddecimalint2pl +); + +CREATE OPERATOR - ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + PROCEDURE = fixeddecimalint2mi +); + +CREATE OPERATOR * ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + COMMUTATOR = *, + PROCEDURE = fixeddecimalint2mul +); + +CREATE OPERATOR / ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + PROCEDURE = fixeddecimalint2div +); + +CREATE OPERATOR CLASS fixeddecimal_int2_ops +FOR TYPE FIXEDDECIMAL USING btree AS + OPERATOR 1 < (FIXEDDECIMAL, INT2), + OPERATOR 2 <= (FIXEDDECIMAL, INT2), + OPERATOR 3 = (FIXEDDECIMAL, INT2), + OPERATOR 4 >= (FIXEDDECIMAL, INT2), + OPERATOR 5 > (FIXEDDECIMAL, INT2), + FUNCTION 1 fixeddecimal_int2_cmp(FIXEDDECIMAL, INT2); + +CREATE OPERATOR CLASS fixeddecimal_int2_ops +FOR TYPE FIXEDDECIMAL USING hash AS + OPERATOR 1 = (FIXEDDECIMAL, INT2), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + +-- INT2, FIXEDDECIMAL +CREATE FUNCTION int2_fixeddecimal_cmp(INT2, FIXEDDECIMAL) +RETURNS INT4 +AS 'babelfishpg_money', 'int2_fixeddecimal_cmp' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int2_fixeddecimal_eq(INT2, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int2_fixeddecimal_eq' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int2_fixeddecimal_ne(INT2, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int2_fixeddecimal_ne' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int2_fixeddecimal_lt(INT2, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int2_fixeddecimal_lt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int2_fixeddecimal_le(INT2, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int2_fixeddecimal_le' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int2_fixeddecimal_gt(INT2, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int2_fixeddecimal_gt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int2_fixeddecimal_ge(INT2, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int2_fixeddecimal_ge' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int2fixeddecimalpl(INT2, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'int2fixeddecimalpl' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int2fixeddecimalmi(INT2, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'int2fixeddecimalmi' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int2fixeddecimalmul(INT2, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'int2fixeddecimalmul' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int2fixeddecimaldiv(INT2, FIXEDDECIMAL) +RETURNS DOUBLE PRECISION +AS 'babelfishpg_money', 'int2fixeddecimaldiv' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR = ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = int2_fixeddecimal_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR <> ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = int2_fixeddecimal_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR < ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = int2_fixeddecimal_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR <= ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = int2_fixeddecimal_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR >= ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = int2_fixeddecimal_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR > ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = int2_fixeddecimal_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR + ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = +, + PROCEDURE = int2fixeddecimalpl +); + +CREATE OPERATOR - ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = int2fixeddecimalmi +); + +CREATE OPERATOR * ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = *, + PROCEDURE = int2fixeddecimalmul +); + +CREATE OPERATOR / ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = int2fixeddecimaldiv +); + +CREATE OPERATOR CLASS int2_fixeddecimal_ops +FOR TYPE FIXEDDECIMAL USING btree AS + OPERATOR 1 < (INT2, FIXEDDECIMAL), + OPERATOR 2 <= (INT2, FIXEDDECIMAL), + OPERATOR 3 = (INT2, FIXEDDECIMAL), + OPERATOR 4 >= (INT2, FIXEDDECIMAL), + OPERATOR 5 > (INT2, FIXEDDECIMAL), + FUNCTION 1 int2_fixeddecimal_cmp(INT2, FIXEDDECIMAL); + +CREATE OPERATOR CLASS int2_fixeddecimal_ops +FOR TYPE FIXEDDECIMAL USING hash AS + OPERATOR 1 = (INT2, FIXEDDECIMAL), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + +-- +-- Casts +-- + +CREATE FUNCTION fixeddecimal(FIXEDDECIMAL, INT4) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimal' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int4fixeddecimal(INT4) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'int4fixeddecimal' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalint4(FIXEDDECIMAL) +RETURNS INT4 +AS 'babelfishpg_money', 'fixeddecimalint4' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int2fixeddecimal(INT2) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'int2fixeddecimal' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalint2(FIXEDDECIMAL) +RETURNS INT2 +AS 'babelfishpg_money', 'fixeddecimalint2' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimaltod(FIXEDDECIMAL) +RETURNS DOUBLE PRECISION +AS 'babelfishpg_money', 'fixeddecimaltod' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION dtofixeddecimal(DOUBLE PRECISION) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'dtofixeddecimal' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimaltof(FIXEDDECIMAL) +RETURNS REAL +AS 'babelfishpg_money', 'fixeddecimaltof' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION ftofixeddecimal(REAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'ftofixeddecimal' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_numeric(FIXEDDECIMAL) +RETURNS NUMERIC +AS 'babelfishpg_money', 'fixeddecimal_numeric' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION numeric_fixeddecimal(NUMERIC) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'numeric_fixeddecimal' +LANGUAGE C IMMUTABLE STRICT; + +CREATE CAST (FIXEDDECIMAL AS FIXEDDECIMAL) + WITH FUNCTION fixeddecimal (FIXEDDECIMAL, INT4) AS ASSIGNMENT; + +CREATE CAST (INT4 AS FIXEDDECIMAL) + WITH FUNCTION int4fixeddecimal (INT4) AS IMPLICIT; + +CREATE CAST (FIXEDDECIMAL AS INT4) + WITH FUNCTION fixeddecimalint4 (FIXEDDECIMAL) AS ASSIGNMENT; + +CREATE CAST (INT2 AS FIXEDDECIMAL) + WITH FUNCTION int2fixeddecimal (INT2) AS IMPLICIT; + +CREATE CAST (FIXEDDECIMAL AS INT2) + WITH FUNCTION fixeddecimalint2 (FIXEDDECIMAL) AS ASSIGNMENT; + +CREATE CAST (FIXEDDECIMAL AS DOUBLE PRECISION) + WITH FUNCTION fixeddecimaltod (FIXEDDECIMAL) AS IMPLICIT; + +CREATE CAST (DOUBLE PRECISION AS FIXEDDECIMAL) + WITH FUNCTION dtofixeddecimal (DOUBLE PRECISION) AS ASSIGNMENT; -- XXX? or Implicit? + +CREATE CAST (FIXEDDECIMAL AS REAL) + WITH FUNCTION fixeddecimaltof (FIXEDDECIMAL) AS IMPLICIT; + +CREATE CAST (REAL AS FIXEDDECIMAL) + WITH FUNCTION ftofixeddecimal (REAL) AS ASSIGNMENT; -- XXX or Implicit? + +CREATE CAST (FIXEDDECIMAL AS NUMERIC) + WITH FUNCTION fixeddecimal_numeric (FIXEDDECIMAL) AS IMPLICIT; + +CREATE CAST (NUMERIC AS FIXEDDECIMAL) + WITH FUNCTION numeric_fixeddecimal (NUMERIC) AS ASSIGNMENT; diff --git a/contrib/babelfishpg_money/fixeddecimal--1.1.0_base_parallel.sql b/contrib/babelfishpg_money/fixeddecimal--1.1.0_base_parallel.sql new file mode 100755 index 00000000000..97880d6e114 --- /dev/null +++ b/contrib/babelfishpg_money/fixeddecimal--1.1.0_base_parallel.sql @@ -0,0 +1,1419 @@ +------------------ +-- FIXEDDECIMAL -- +------------------ + +CREATE TYPE FIXEDDECIMAL; + +CREATE FUNCTION fixeddecimalin(cstring, oid, int4) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalin' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalout(fixeddecimal) +RETURNS cstring +AS 'babelfishpg_money', 'fixeddecimalout' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalrecv(internal) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalrecv' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalsend(FIXEDDECIMAL) +RETURNS bytea +AS 'babelfishpg_money', 'fixeddecimalsend' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimaltypmodin(_cstring) +RETURNS INT4 +AS 'babelfishpg_money', 'fixeddecimaltypmodin' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimaltypmodout(INT4) +RETURNS cstring +AS 'babelfishpg_money', 'fixeddecimaltypmodout' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + + +CREATE TYPE FIXEDDECIMAL ( + INPUT = fixeddecimalin, + OUTPUT = fixeddecimalout, + RECEIVE = fixeddecimalrecv, + SEND = fixeddecimalsend, + TYPMOD_IN = fixeddecimaltypmodin, + TYPMOD_OUT = fixeddecimaltypmodout, + INTERNALLENGTH = 8, + ALIGNMENT = 'double', + STORAGE = plain, + CATEGORY = 'N', + PREFERRED = true, + COLLATABLE = false, + PASSEDBYVALUE -- But not always.. XXX fix that. +); + +-- FIXEDDECIMAL, NUMERIC +CREATE FUNCTION fixeddecimaleq(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimaleq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalne(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimalne' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimallt(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimallt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalle(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimalle' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalgt(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimalgt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalge(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimalge' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalum(FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalum' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalpl(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalpl' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalmi(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalmi' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalmul(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalmul' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimaldiv(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimaldiv' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION abs(FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalabs' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimallarger(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimallarger' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalsmaller(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalsmaller' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_cmp(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS INT4 +AS 'babelfishpg_money', 'fixeddecimal_cmp' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_hash(FIXEDDECIMAL) +RETURNS INT4 +AS 'babelfishpg_money', 'fixeddecimal_hash' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- +-- Operators. +-- + +-- FIXEDDECIMAL op FIXEDDECIMAL +CREATE OPERATOR = ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = fixeddecimaleq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR <> ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = fixeddecimalne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR < ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = fixeddecimallt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR <= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = fixeddecimalle, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR >= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = fixeddecimalge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR > ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = fixeddecimalgt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR + ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = +, + PROCEDURE = fixeddecimalpl +); + +CREATE OPERATOR - ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = fixeddecimalmi +); + +CREATE OPERATOR - ( + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = fixeddecimalum +); + +CREATE OPERATOR * ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = *, + PROCEDURE = fixeddecimalmul +); + +CREATE OPERATOR / ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = fixeddecimaldiv +); + +CREATE OPERATOR CLASS fixeddecimal_ops +DEFAULT FOR TYPE FIXEDDECIMAL USING btree AS + OPERATOR 1 < (FIXEDDECIMAL, FIXEDDECIMAL), + OPERATOR 2 <= (FIXEDDECIMAL, FIXEDDECIMAL), + OPERATOR 3 = (FIXEDDECIMAL, FIXEDDECIMAL), + OPERATOR 4 >= (FIXEDDECIMAL, FIXEDDECIMAL), + OPERATOR 5 > (FIXEDDECIMAL, FIXEDDECIMAL), + FUNCTION 1 fixeddecimal_cmp(FIXEDDECIMAL, FIXEDDECIMAL); + +CREATE OPERATOR CLASS fixeddecimal_ops +DEFAULT FOR TYPE FIXEDDECIMAL USING hash AS + OPERATOR 1 = (FIXEDDECIMAL, FIXEDDECIMAL), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + +-- FIXEDDECIMAL, NUMERIC +CREATE FUNCTION fixeddecimal_numeric_cmp(FIXEDDECIMAL, NUMERIC) +RETURNS INT4 +AS 'babelfishpg_money', 'fixeddecimal_numeric_cmp' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION numeric_fixeddecimal_cmp(NUMERIC, FIXEDDECIMAL) +RETURNS INT4 +AS 'babelfishpg_money', 'numeric_fixeddecimal_cmp' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_numeric_eq(FIXEDDECIMAL, NUMERIC) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_numeric_eq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_numeric_ne(FIXEDDECIMAL, NUMERIC) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_numeric_ne' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_numeric_lt(FIXEDDECIMAL, NUMERIC) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_numeric_lt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_numeric_le(FIXEDDECIMAL, NUMERIC) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_numeric_le' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_numeric_gt(FIXEDDECIMAL, NUMERIC) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_numeric_gt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_numeric_ge(FIXEDDECIMAL, NUMERIC) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_numeric_ge' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR = ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = NUMERIC, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = fixeddecimal_numeric_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR <> ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = NUMERIC, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = fixeddecimal_numeric_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR < ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = NUMERIC, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = fixeddecimal_numeric_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR <= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = NUMERIC, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = fixeddecimal_numeric_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR >= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = NUMERIC, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = fixeddecimal_numeric_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR > ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = NUMERIC, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = fixeddecimal_numeric_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR CLASS fixeddecimal_numeric_ops +FOR TYPE FIXEDDECIMAL USING btree AS + OPERATOR 1 < (FIXEDDECIMAL, NUMERIC), + OPERATOR 2 <= (FIXEDDECIMAL, NUMERIC), + OPERATOR 3 = (FIXEDDECIMAL, NUMERIC), + OPERATOR 4 >= (FIXEDDECIMAL, NUMERIC), + OPERATOR 5 > (FIXEDDECIMAL, NUMERIC), + FUNCTION 1 fixeddecimal_numeric_cmp(FIXEDDECIMAL, NUMERIC); + +CREATE OPERATOR CLASS fixeddecimal_numeric_ops +FOR TYPE FIXEDDECIMAL USING hash AS + OPERATOR 1 = (FIXEDDECIMAL, NUMERIC), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + +-- NUMERIC, FIXEDDECIMAL +CREATE FUNCTION numeric_fixeddecimal_eq(NUMERIC, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'numeric_fixeddecimal_eq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION numeric_fixeddecimal_ne(NUMERIC, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'numeric_fixeddecimal_ne' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION numeric_fixeddecimal_lt(NUMERIC, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'numeric_fixeddecimal_lt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION numeric_fixeddecimal_le(NUMERIC, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'numeric_fixeddecimal_le' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION numeric_fixeddecimal_gt(NUMERIC, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'numeric_fixeddecimal_gt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION numeric_fixeddecimal_ge(NUMERIC, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'numeric_fixeddecimal_ge' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR = ( + LEFTARG = NUMERIC, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = numeric_fixeddecimal_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR <> ( + LEFTARG = NUMERIC, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = numeric_fixeddecimal_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR < ( + LEFTARG = NUMERIC, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = numeric_fixeddecimal_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR <= ( + LEFTARG = NUMERIC, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = numeric_fixeddecimal_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR >= ( + LEFTARG = NUMERIC, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = numeric_fixeddecimal_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR > ( + LEFTARG = NUMERIC, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = numeric_fixeddecimal_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR CLASS numeric_fixeddecimal_ops +FOR TYPE FIXEDDECIMAL USING btree AS + OPERATOR 1 < (NUMERIC, FIXEDDECIMAL) FOR SEARCH, + OPERATOR 2 <= (NUMERIC, FIXEDDECIMAL) FOR SEARCH, + OPERATOR 3 = (NUMERIC, FIXEDDECIMAL) FOR SEARCH, + OPERATOR 4 >= (NUMERIC, FIXEDDECIMAL) FOR SEARCH, + OPERATOR 5 > (NUMERIC, FIXEDDECIMAL) FOR SEARCH, + FUNCTION 1 numeric_fixeddecimal_cmp(NUMERIC, FIXEDDECIMAL); + +CREATE OPERATOR CLASS numeric_fixeddecimal_ops +FOR TYPE FIXEDDECIMAL USING hash AS + OPERATOR 1 = (NUMERIC, FIXEDDECIMAL), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + +-- +-- Cross type operators with int8 +-- + +-- FIXEDDECIMAL, INT8 +CREATE FUNCTION fixeddecimal_int8_cmp(FIXEDDECIMAL, INT8) +RETURNS INT4 +AS 'babelfishpg_money', 'fixeddecimal_int8_cmp' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_int8_eq(FIXEDDECIMAL, INT8) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int8_eq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_int8_ne(FIXEDDECIMAL, INT8) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int8_ne' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_int8_lt(FIXEDDECIMAL, INT8) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int8_lt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_int8_le(FIXEDDECIMAL, INT8) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int8_le' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_int8_gt(FIXEDDECIMAL, INT8) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int8_gt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_int8_ge(FIXEDDECIMAL, INT8) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int8_ge' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR = ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT8, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = fixeddecimal_int8_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR <> ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT8, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = fixeddecimal_int8_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR < ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT8, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = fixeddecimal_int8_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR <= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT8, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = fixeddecimal_int8_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR >= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT8, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = fixeddecimal_int8_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR > ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT8, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = fixeddecimal_int8_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR CLASS fixeddecimal_int8_ops +FOR TYPE FIXEDDECIMAL USING btree AS + OPERATOR 1 < (FIXEDDECIMAL, INT8), + OPERATOR 2 <= (FIXEDDECIMAL, INT8), + OPERATOR 3 = (FIXEDDECIMAL, INT8), + OPERATOR 4 >= (FIXEDDECIMAL, INT8), + OPERATOR 5 > (FIXEDDECIMAL, INT8), + FUNCTION 1 fixeddecimal_int8_cmp(FIXEDDECIMAL, INT8); + +CREATE OPERATOR CLASS fixeddecimal_int8_ops +FOR TYPE FIXEDDECIMAL USING hash AS + OPERATOR 1 = (FIXEDDECIMAL, INT8), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + +-- INT8, FIXEDDECIMAL +CREATE FUNCTION int8_fixeddecimal_cmp(INT8, FIXEDDECIMAL) +RETURNS INT4 +AS 'babelfishpg_money', 'int8_fixeddecimal_cmp' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION int8_fixeddecimal_eq(INT8, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int8_fixeddecimal_eq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION int8_fixeddecimal_ne(INT8, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int8_fixeddecimal_ne' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION int8_fixeddecimal_lt(INT8, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int8_fixeddecimal_lt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION int8_fixeddecimal_le(INT8, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int8_fixeddecimal_le' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION int8_fixeddecimal_gt(INT8, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int8_fixeddecimal_gt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION int8_fixeddecimal_ge(INT8, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int8_fixeddecimal_ge' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR = ( + LEFTARG = INT8, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = int8_fixeddecimal_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR <> ( + LEFTARG = INT8, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = int8_fixeddecimal_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR < ( + LEFTARG = INT8, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = int8_fixeddecimal_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR <= ( + LEFTARG = INT8, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = int8_fixeddecimal_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR >= ( + LEFTARG = INT8, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = int8_fixeddecimal_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR > ( + LEFTARG = INT8, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = int8_fixeddecimal_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR CLASS int8_fixeddecimal_ops +FOR TYPE FIXEDDECIMAL USING btree AS + OPERATOR 1 < (INT8, FIXEDDECIMAL), + OPERATOR 2 <= (INT8, FIXEDDECIMAL), + OPERATOR 3 = (INT8, FIXEDDECIMAL), + OPERATOR 4 >= (INT8, FIXEDDECIMAL), + OPERATOR 5 > (INT8, FIXEDDECIMAL), + FUNCTION 1 int8_fixeddecimal_cmp(INT8, FIXEDDECIMAL); + +CREATE OPERATOR CLASS int8_fixeddecimal_ops +FOR TYPE FIXEDDECIMAL USING hash AS + OPERATOR 1 = (INT8, FIXEDDECIMAL), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + +-- +-- Cross type operators with int4 +-- + +-- FIXEDDECIMAL, INT4 +CREATE FUNCTION fixeddecimal_int4_cmp(FIXEDDECIMAL, INT4) +RETURNS INT4 +AS 'babelfishpg_money', 'fixeddecimal_int4_cmp' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_int4_eq(FIXEDDECIMAL, INT4) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int4_eq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_int4_ne(FIXEDDECIMAL, INT4) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int4_ne' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_int4_lt(FIXEDDECIMAL, INT4) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int4_lt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_int4_le(FIXEDDECIMAL, INT4) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int4_le' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_int4_gt(FIXEDDECIMAL, INT4) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int4_gt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_int4_ge(FIXEDDECIMAL, INT4) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int4_ge' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalint4pl(FIXEDDECIMAL, INT4) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalint4pl' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalint4mi(FIXEDDECIMAL, INT4) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalint4mi' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalint4mul(FIXEDDECIMAL, INT4) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalint4mul' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalint4div(FIXEDDECIMAL, INT4) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalint4div' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR = ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = fixeddecimal_int4_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR <> ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = fixeddecimal_int4_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR < ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = fixeddecimal_int4_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR <= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = fixeddecimal_int4_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR >= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = fixeddecimal_int4_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR > ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = fixeddecimal_int4_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR + ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + COMMUTATOR = +, + PROCEDURE = fixeddecimalint4pl +); + +CREATE OPERATOR - ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + PROCEDURE = fixeddecimalint4mi +); + +CREATE OPERATOR * ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + COMMUTATOR = *, + PROCEDURE = fixeddecimalint4mul +); + +CREATE OPERATOR / ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + PROCEDURE = fixeddecimalint4div +); + +CREATE OPERATOR CLASS fixeddecimal_int4_ops +FOR TYPE FIXEDDECIMAL USING btree AS + OPERATOR 1 < (FIXEDDECIMAL, INT4), + OPERATOR 2 <= (FIXEDDECIMAL, INT4), + OPERATOR 3 = (FIXEDDECIMAL, INT4), + OPERATOR 4 >= (FIXEDDECIMAL, INT4), + OPERATOR 5 > (FIXEDDECIMAL, INT4), + FUNCTION 1 fixeddecimal_int4_cmp(FIXEDDECIMAL, INT4); + +CREATE OPERATOR CLASS fixeddecimal_int4_ops +FOR TYPE FIXEDDECIMAL USING hash AS + OPERATOR 1 = (FIXEDDECIMAL, INT4), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + +-- INT4, FIXEDDECIMAL +CREATE FUNCTION int4_fixeddecimal_cmp(INT4, FIXEDDECIMAL) +RETURNS INT4 +AS 'babelfishpg_money', 'int4_fixeddecimal_cmp' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION int4_fixeddecimal_eq(INT4, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int4_fixeddecimal_eq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION int4_fixeddecimal_ne(INT4, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int4_fixeddecimal_ne' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION int4_fixeddecimal_lt(INT4, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int4_fixeddecimal_lt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION int4_fixeddecimal_le(INT4, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int4_fixeddecimal_le' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION int4_fixeddecimal_gt(INT4, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int4_fixeddecimal_gt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION int4_fixeddecimal_ge(INT4, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int4_fixeddecimal_ge' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION int4fixeddecimalpl(INT4, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'int4fixeddecimalpl' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION int4fixeddecimalmi(INT4, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'int4fixeddecimalmi' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION int4fixeddecimalmul(INT4, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'int4fixeddecimalmul' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION int4fixeddecimaldiv(INT4, FIXEDDECIMAL) +RETURNS DOUBLE PRECISION +AS 'babelfishpg_money', 'int4fixeddecimaldiv' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR = ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = int4_fixeddecimal_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR <> ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = int4_fixeddecimal_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR < ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = int4_fixeddecimal_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR <= ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = int4_fixeddecimal_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR >= ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = int4_fixeddecimal_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR > ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = int4_fixeddecimal_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR + ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = +, + PROCEDURE = int4fixeddecimalpl +); + +CREATE OPERATOR - ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = int4fixeddecimalmi +); + +CREATE OPERATOR * ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = *, + PROCEDURE = int4fixeddecimalmul +); + +CREATE OPERATOR / ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = int4fixeddecimaldiv +); + +CREATE OPERATOR CLASS int4_fixeddecimal_ops +FOR TYPE FIXEDDECIMAL USING btree AS + OPERATOR 1 < (INT4, FIXEDDECIMAL), + OPERATOR 2 <= (INT4, FIXEDDECIMAL), + OPERATOR 3 = (INT4, FIXEDDECIMAL), + OPERATOR 4 >= (INT4, FIXEDDECIMAL), + OPERATOR 5 > (INT4, FIXEDDECIMAL), + FUNCTION 1 int4_fixeddecimal_cmp(INT4, FIXEDDECIMAL); + +CREATE OPERATOR CLASS int4_fixeddecimal_ops +FOR TYPE FIXEDDECIMAL USING hash AS + OPERATOR 1 = (INT4, FIXEDDECIMAL), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + +-- +-- Cross type operators with int2 +-- +-- FIXEDDECIMAL, INT2 +CREATE FUNCTION fixeddecimal_int2_cmp(FIXEDDECIMAL, INT2) +RETURNS INT4 +AS 'babelfishpg_money', 'fixeddecimal_int2_cmp' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_int2_eq(FIXEDDECIMAL, INT2) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int2_eq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_int2_ne(FIXEDDECIMAL, INT2) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int2_ne' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_int2_lt(FIXEDDECIMAL, INT2) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int2_lt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_int2_le(FIXEDDECIMAL, INT2) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int2_le' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_int2_gt(FIXEDDECIMAL, INT2) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int2_gt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_int2_ge(FIXEDDECIMAL, INT2) +RETURNS bool +AS 'babelfishpg_money', 'fixeddecimal_int2_ge' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalint2pl(FIXEDDECIMAL, INT2) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalint2pl' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalint2mi(FIXEDDECIMAL, INT2) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalint2mi' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalint2mul(FIXEDDECIMAL, INT2) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalint2mul' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalint2div(FIXEDDECIMAL, INT2) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimalint2div' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR = ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = fixeddecimal_int2_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR <> ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = fixeddecimal_int2_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR < ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = fixeddecimal_int2_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR <= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = fixeddecimal_int2_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR >= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = fixeddecimal_int2_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR > ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = fixeddecimal_int2_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR + ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + COMMUTATOR = +, + PROCEDURE = fixeddecimalint2pl +); + +CREATE OPERATOR - ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + PROCEDURE = fixeddecimalint2mi +); + +CREATE OPERATOR * ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + COMMUTATOR = *, + PROCEDURE = fixeddecimalint2mul +); + +CREATE OPERATOR / ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + PROCEDURE = fixeddecimalint2div +); + +CREATE OPERATOR CLASS fixeddecimal_int2_ops +FOR TYPE FIXEDDECIMAL USING btree AS + OPERATOR 1 < (FIXEDDECIMAL, INT2), + OPERATOR 2 <= (FIXEDDECIMAL, INT2), + OPERATOR 3 = (FIXEDDECIMAL, INT2), + OPERATOR 4 >= (FIXEDDECIMAL, INT2), + OPERATOR 5 > (FIXEDDECIMAL, INT2), + FUNCTION 1 fixeddecimal_int2_cmp(FIXEDDECIMAL, INT2); + +CREATE OPERATOR CLASS fixeddecimal_int2_ops +FOR TYPE FIXEDDECIMAL USING hash AS + OPERATOR 1 = (FIXEDDECIMAL, INT2), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + +-- INT2, FIXEDDECIMAL +CREATE FUNCTION int2_fixeddecimal_cmp(INT2, FIXEDDECIMAL) +RETURNS INT4 +AS 'babelfishpg_money', 'int2_fixeddecimal_cmp' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION int2_fixeddecimal_eq(INT2, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int2_fixeddecimal_eq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION int2_fixeddecimal_ne(INT2, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int2_fixeddecimal_ne' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION int2_fixeddecimal_lt(INT2, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int2_fixeddecimal_lt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION int2_fixeddecimal_le(INT2, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int2_fixeddecimal_le' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION int2_fixeddecimal_gt(INT2, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int2_fixeddecimal_gt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION int2_fixeddecimal_ge(INT2, FIXEDDECIMAL) +RETURNS bool +AS 'babelfishpg_money', 'int2_fixeddecimal_ge' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION int2fixeddecimalpl(INT2, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'int2fixeddecimalpl' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION int2fixeddecimalmi(INT2, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'int2fixeddecimalmi' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION int2fixeddecimalmul(INT2, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'int2fixeddecimalmul' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION int2fixeddecimaldiv(INT2, FIXEDDECIMAL) +RETURNS DOUBLE PRECISION +AS 'babelfishpg_money', 'int2fixeddecimaldiv' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR = ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = int2_fixeddecimal_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR <> ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = int2_fixeddecimal_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR < ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = int2_fixeddecimal_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR <= ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = int2_fixeddecimal_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR >= ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = int2_fixeddecimal_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR > ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = int2_fixeddecimal_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR + ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = +, + PROCEDURE = int2fixeddecimalpl +); + +CREATE OPERATOR - ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = int2fixeddecimalmi +); + +CREATE OPERATOR * ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = *, + PROCEDURE = int2fixeddecimalmul +); + +CREATE OPERATOR / ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = int2fixeddecimaldiv +); + +CREATE OPERATOR CLASS int2_fixeddecimal_ops +FOR TYPE FIXEDDECIMAL USING btree AS + OPERATOR 1 < (INT2, FIXEDDECIMAL), + OPERATOR 2 <= (INT2, FIXEDDECIMAL), + OPERATOR 3 = (INT2, FIXEDDECIMAL), + OPERATOR 4 >= (INT2, FIXEDDECIMAL), + OPERATOR 5 > (INT2, FIXEDDECIMAL), + FUNCTION 1 int2_fixeddecimal_cmp(INT2, FIXEDDECIMAL); + +CREATE OPERATOR CLASS int2_fixeddecimal_ops +FOR TYPE FIXEDDECIMAL USING hash AS + OPERATOR 1 = (INT2, FIXEDDECIMAL), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + +-- +-- Casts +-- + +CREATE FUNCTION fixeddecimal(FIXEDDECIMAL, INT4) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimal' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION int4fixeddecimal(INT4) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'int4fixeddecimal' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalint4(FIXEDDECIMAL) +RETURNS INT4 +AS 'babelfishpg_money', 'fixeddecimalint4' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION int2fixeddecimal(INT2) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'int2fixeddecimal' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalint2(FIXEDDECIMAL) +RETURNS INT2 +AS 'babelfishpg_money', 'fixeddecimalint2' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimaltod(FIXEDDECIMAL) +RETURNS DOUBLE PRECISION +AS 'babelfishpg_money', 'fixeddecimaltod' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION dtofixeddecimal(DOUBLE PRECISION) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'dtofixeddecimal' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimaltof(FIXEDDECIMAL) +RETURNS REAL +AS 'babelfishpg_money', 'fixeddecimaltof' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION ftofixeddecimal(REAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'ftofixeddecimal' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_numeric(FIXEDDECIMAL) +RETURNS NUMERIC +AS 'babelfishpg_money', 'fixeddecimal_numeric' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION numeric_fixeddecimal(NUMERIC) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'numeric_fixeddecimal' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (FIXEDDECIMAL AS FIXEDDECIMAL) + WITH FUNCTION fixeddecimal (FIXEDDECIMAL, INT4) AS ASSIGNMENT; + +CREATE CAST (INT4 AS FIXEDDECIMAL) + WITH FUNCTION int4fixeddecimal (INT4) AS IMPLICIT; + +CREATE CAST (FIXEDDECIMAL AS INT4) + WITH FUNCTION fixeddecimalint4 (FIXEDDECIMAL) AS ASSIGNMENT; + +CREATE CAST (INT2 AS FIXEDDECIMAL) + WITH FUNCTION int2fixeddecimal (INT2) AS IMPLICIT; + +CREATE CAST (FIXEDDECIMAL AS INT2) + WITH FUNCTION fixeddecimalint2 (FIXEDDECIMAL) AS ASSIGNMENT; + +CREATE CAST (FIXEDDECIMAL AS DOUBLE PRECISION) + WITH FUNCTION fixeddecimaltod (FIXEDDECIMAL) AS IMPLICIT; + +CREATE CAST (DOUBLE PRECISION AS FIXEDDECIMAL) + WITH FUNCTION dtofixeddecimal (DOUBLE PRECISION) AS ASSIGNMENT; -- XXX? or Implicit? + +CREATE CAST (FIXEDDECIMAL AS REAL) + WITH FUNCTION fixeddecimaltof (FIXEDDECIMAL) AS IMPLICIT; + +CREATE CAST (REAL AS FIXEDDECIMAL) + WITH FUNCTION ftofixeddecimal (REAL) AS ASSIGNMENT; -- XXX or Implicit? + +CREATE CAST (FIXEDDECIMAL AS NUMERIC) + WITH FUNCTION fixeddecimal_numeric (FIXEDDECIMAL) AS IMPLICIT; + +CREATE CAST (NUMERIC AS FIXEDDECIMAL) + WITH FUNCTION numeric_fixeddecimal (NUMERIC) AS ASSIGNMENT; diff --git a/contrib/babelfishpg_money/fixeddecimal--aggs.sql b/contrib/babelfishpg_money/fixeddecimal--aggs.sql new file mode 100644 index 00000000000..baf02bf3428 --- /dev/null +++ b/contrib/babelfishpg_money/fixeddecimal--aggs.sql @@ -0,0 +1,44 @@ + +-- Aggregate Support + + +CREATE FUNCTION fixeddecimal_avg_accum(INTERNAL, FIXEDDECIMAL) +RETURNS INTERNAL +AS 'babelfishpg_money', 'fixeddecimal_avg_accum' +LANGUAGE C IMMUTABLE; + +CREATE FUNCTION fixeddecimal_sum(INTERNAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimal_sum' +LANGUAGE C IMMUTABLE; + +CREATE FUNCTION fixeddecimal_avg(INTERNAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimal_avg' +LANGUAGE C IMMUTABLE; + +CREATE AGGREGATE min(FIXEDDECIMAL) ( + SFUNC = fixeddecimalsmaller, + STYPE = FIXEDDECIMAL, + SORTOP = < +); + +CREATE AGGREGATE max(FIXEDDECIMAL) ( + SFUNC = fixeddecimallarger, + STYPE = FIXEDDECIMAL, + SORTOP = > +); + +CREATE AGGREGATE sum(FIXEDDECIMAL) ( + SFUNC = fixeddecimal_avg_accum, + FINALFUNC = fixeddecimal_sum, + STYPE = INTERNAL +); + +CREATE AGGREGATE avg(FIXEDDECIMAL) ( + SFUNC = fixeddecimal_avg_accum, + FINALFUNC = fixeddecimal_avg, + STYPE = INTERNAL +); + + diff --git a/contrib/babelfishpg_money/fixeddecimal--brin.sql b/contrib/babelfishpg_money/fixeddecimal--brin.sql new file mode 100644 index 00000000000..ce98da4be7d --- /dev/null +++ b/contrib/babelfishpg_money/fixeddecimal--brin.sql @@ -0,0 +1,12 @@ +CREATE OPERATOR CLASS fixeddecimal_minmax_ops +DEFAULT FOR TYPE FIXEDDECIMAL USING brin AS + OPERATOR 1 < (FIXEDDECIMAL, FIXEDDECIMAL), + OPERATOR 2 <= (FIXEDDECIMAL, FIXEDDECIMAL), + OPERATOR 3 = (FIXEDDECIMAL, FIXEDDECIMAL), + OPERATOR 4 >= (FIXEDDECIMAL, FIXEDDECIMAL), + OPERATOR 5 > (FIXEDDECIMAL, FIXEDDECIMAL), + FUNCTION 1 brin_minmax_opcinfo(INTERNAL), + FUNCTION 2 brin_minmax_add_value(INTERNAL, INTERNAL, INTERNAL, INTERNAL), + FUNCTION 3 brin_minmax_consistent(INTERNAL, INTERNAL, INTERNAL), + FUNCTION 4 brin_minmax_union(INTERNAL, INTERNAL, INTERNAL); + diff --git a/contrib/babelfishpg_money/fixeddecimal--parallelaggs.sql b/contrib/babelfishpg_money/fixeddecimal--parallelaggs.sql new file mode 100644 index 00000000000..4e3b51e520a --- /dev/null +++ b/contrib/babelfishpg_money/fixeddecimal--parallelaggs.sql @@ -0,0 +1,70 @@ + +-- Aggregate Support + +CREATE FUNCTION fixeddecimalaggstatecombine(INTERNAL, INTERNAL) +RETURNS INTERNAL +AS 'babelfishpg_money', 'fixeddecimalaggstatecombine' +LANGUAGE C IMMUTABLE PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalaggstateserialize(INTERNAL) +RETURNS BYTEA +AS 'babelfishpg_money', 'fixeddecimalaggstateserialize' +LANGUAGE C IMMUTABLE PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalaggstatedeserialize(BYTEA, INTERNAL) +RETURNS INTERNAL +AS 'babelfishpg_money', 'fixeddecimalaggstatedeserialize' +LANGUAGE C IMMUTABLE PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_avg_accum(INTERNAL, FIXEDDECIMAL) +RETURNS INTERNAL +AS 'babelfishpg_money', 'fixeddecimal_avg_accum' +LANGUAGE C IMMUTABLE PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_sum(INTERNAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimal_sum' +LANGUAGE C IMMUTABLE PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_avg(INTERNAL) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimal_avg' +LANGUAGE C IMMUTABLE PARALLEL SAFE; + +CREATE AGGREGATE min(FIXEDDECIMAL) ( + SFUNC = fixeddecimalsmaller, + STYPE = FIXEDDECIMAL, + SORTOP = <, + COMBINEFUNC = fixeddecimalsmaller, + PARALLEL = SAFE +); + +CREATE AGGREGATE max(FIXEDDECIMAL) ( + SFUNC = fixeddecimallarger, + STYPE = FIXEDDECIMAL, + SORTOP = >, + COMBINEFUNC = fixeddecimallarger, + PARALLEL = SAFE +); + +CREATE AGGREGATE sum(FIXEDDECIMAL) ( + SFUNC = fixeddecimal_avg_accum, + FINALFUNC = fixeddecimal_sum, + STYPE = INTERNAL, + COMBINEFUNC = fixeddecimalaggstatecombine, + SERIALFUNC = fixeddecimalaggstateserialize, + DESERIALFUNC = fixeddecimalaggstatedeserialize, + PARALLEL = SAFE +); + +CREATE AGGREGATE avg(FIXEDDECIMAL) ( + SFUNC = fixeddecimal_avg_accum, + FINALFUNC = fixeddecimal_avg, + STYPE = INTERNAL, + COMBINEFUNC = fixeddecimalaggstatecombine, + SERIALFUNC = fixeddecimalaggstateserialize, + DESERIALFUNC = fixeddecimalaggstatedeserialize, + PARALLEL = SAFE +); + + diff --git a/contrib/babelfishpg_money/fixeddecimal--xlaggs.sql b/contrib/babelfishpg_money/fixeddecimal--xlaggs.sql new file mode 100644 index 00000000000..0e3d0f87291 --- /dev/null +++ b/contrib/babelfishpg_money/fixeddecimal--xlaggs.sql @@ -0,0 +1,57 @@ + +-- Aggregate Support + + +CREATE FUNCTION fixeddecimalaggstatecombine(FIXEDDECIMALAGGSTATE, FIXEDDECIMALAGGSTATE) +RETURNS FIXEDDECIMALAGGSTATE +AS 'babelfishpg_money', 'fixeddecimalaggstatecombine' +LANGUAGE C IMMUTABLE; + +CREATE FUNCTION fixeddecimal_avg_accum(FIXEDDECIMALAGGSTATE, FIXEDDECIMAL) +RETURNS FIXEDDECIMALAGGSTATE +AS 'babelfishpg_money', 'fixeddecimal_avg_accum' +LANGUAGE C IMMUTABLE; + +CREATE FUNCTION fixeddecimal_sum(FIXEDDECIMALAGGSTATE) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimal_sum' +LANGUAGE C IMMUTABLE; + +CREATE FUNCTION fixeddecimal_avg(FIXEDDECIMALAGGSTATE) +RETURNS FIXEDDECIMAL +AS 'babelfishpg_money', 'fixeddecimal_avg' +LANGUAGE C IMMUTABLE; + +CREATE AGGREGATE min(FIXEDDECIMAL) ( + SFUNC = fixeddecimalsmaller, + CFUNC = fixeddecimalsmaller, + CTYPE = FIXEDDECIMAL, + STYPE = FIXEDDECIMAL, + SORTOP = < +); + +CREATE AGGREGATE max(FIXEDDECIMAL) ( + SFUNC = fixeddecimallarger, + CFUNC = fixeddecimallarger, + CTYPE = FIXEDDECIMAL, + STYPE = FIXEDDECIMAL, + SORTOP = > +); + +CREATE AGGREGATE sum(FIXEDDECIMAL) ( + SFUNC = fixeddecimal_avg_accum, + CFUNC = fixeddecimalaggstatecombine, + CTYPE = FIXEDDECIMALAGGSTATE, + FINALFUNC = fixeddecimal_sum, + STYPE = FIXEDDECIMALAGGSTATE +); + +CREATE AGGREGATE avg(FIXEDDECIMAL) ( + SFUNC = fixeddecimal_avg_accum, + CFUNC = fixeddecimalaggstatecombine, + CTYPE = FIXEDDECIMALAGGSTATE, + FINALFUNC = fixeddecimal_avg, + STYPE = FIXEDDECIMALAGGSTATE +); + + diff --git a/contrib/babelfishpg_money/fixeddecimal.c b/contrib/babelfishpg_money/fixeddecimal.c new file mode 100755 index 00000000000..e835b3e0145 --- /dev/null +++ b/contrib/babelfishpg_money/fixeddecimal.c @@ -0,0 +1,3032 @@ +/*------------------------------------------------------------------------- + * + * fixeddecimal.c + * Fixed Decimal numeric type extension + * + * Copyright (c) 2015, PostgreSQL Global Development Group + * + * IDENTIFICATION + * fixeddecimal.c + * + * The research leading to these results has received funding from the European + * Union’s Seventh Framework Programme (FP7/2007-2015) under grant agreement + * n° 318633 + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include +#include +#include + +#include "funcapi.h" +#include "libpq/pqformat.h" +#include "access/hash.h" +#include "utils/array.h" +#include "utils/builtins.h" + +#include "utils/int8.h" + +#include "utils/numeric.h" + +/* + * The scale which the number is actually stored. + * For example: 100 will allow 2 decimal places of precision + * This must always be a '1' followed by a number of '0's. + */ +#define FIXEDDECIMAL_MULTIPLIER 10000LL + +/* + * Number of decimal places to store. + * This number should be the number of decimal digits that it takes to + * represent FIXEDDECIMAL_MULTIPLIER - 1 + */ +#define FIXEDDECIMAL_SCALE 4 + +/* Sanity checks */ +#if FIXEDDECIMAL_SCALE == 0 +#error "FIXEDDECIMAL_SCALE cannot be zero. Just use a BIGINT if that's what you really want" +#endif + +#if FIXEDDECIMAL_SCALE > 19 +#error "FIXEDDECIMAL_SCALE cannot be greater than 19" +#endif + +/* + * This is bounded by the maximum and minimum values of int64. + * 9223372036854775807 is 19 decimal digits long, but we we can only represent + * this number / FIXEDDECIMAL_MULTIPLIER, so we must subtract + * FIXEDDECIMAL_SCALE + */ +#define FIXEDDECIMAL_MAX_PRECISION 19 - FIXEDDECIMAL_SCALE + +/* Define this if your compiler has _builtin_add_overflow() */ +/* #define HAVE_BUILTIN_OVERFLOW */ + +#ifndef HAVE_BUILTIN_OVERFLOW +#define SAMESIGN(a,b) (((a) < 0) == ((b) < 0)) +#endif /* HAVE_BUILTIN_OVERFLOW */ + +#define FIXEDDECIMAL_MAX (INT64_MAX/FIXEDDECIMAL_MULTIPLIER) +#define FIXEDDECIMAL_MIN (INT64_MIN/FIXEDDECIMAL_MULTIPLIER) + +/* Compiler must have a working 128 int type */ +typedef __int128 int128; + +#ifdef PG_MODULE_MAGIC +PG_MODULE_MAGIC; +#endif + +PG_FUNCTION_INFO_V1(fixeddecimalin); +PG_FUNCTION_INFO_V1(fixeddecimaltypmodin); +PG_FUNCTION_INFO_V1(fixeddecimaltypmodout); +PG_FUNCTION_INFO_V1(fixeddecimalout); +PG_FUNCTION_INFO_V1(fixeddecimalrecv); +PG_FUNCTION_INFO_V1(fixeddecimalsend); + +PG_FUNCTION_INFO_V1(fixeddecimaleq); +PG_FUNCTION_INFO_V1(fixeddecimalne); +PG_FUNCTION_INFO_V1(fixeddecimallt); +PG_FUNCTION_INFO_V1(fixeddecimalgt); +PG_FUNCTION_INFO_V1(fixeddecimalle); +PG_FUNCTION_INFO_V1(fixeddecimalge); +PG_FUNCTION_INFO_V1(fixeddecimal_cmp); + +PG_FUNCTION_INFO_V1(fixeddecimal_int2_eq); +PG_FUNCTION_INFO_V1(fixeddecimal_int2_ne); +PG_FUNCTION_INFO_V1(fixeddecimal_int2_lt); +PG_FUNCTION_INFO_V1(fixeddecimal_int2_gt); +PG_FUNCTION_INFO_V1(fixeddecimal_int2_le); +PG_FUNCTION_INFO_V1(fixeddecimal_int2_ge); +PG_FUNCTION_INFO_V1(fixeddecimal_int2_cmp); + +PG_FUNCTION_INFO_V1(int2_fixeddecimal_eq); +PG_FUNCTION_INFO_V1(int2_fixeddecimal_ne); +PG_FUNCTION_INFO_V1(int2_fixeddecimal_lt); +PG_FUNCTION_INFO_V1(int2_fixeddecimal_gt); +PG_FUNCTION_INFO_V1(int2_fixeddecimal_le); +PG_FUNCTION_INFO_V1(int2_fixeddecimal_ge); +PG_FUNCTION_INFO_V1(int2_fixeddecimal_cmp); + +PG_FUNCTION_INFO_V1(fixeddecimal_int4_eq); +PG_FUNCTION_INFO_V1(fixeddecimal_int4_ne); +PG_FUNCTION_INFO_V1(fixeddecimal_int4_lt); +PG_FUNCTION_INFO_V1(fixeddecimal_int4_gt); +PG_FUNCTION_INFO_V1(fixeddecimal_int4_le); +PG_FUNCTION_INFO_V1(fixeddecimal_int4_ge); +PG_FUNCTION_INFO_V1(fixeddecimal_int4_cmp); + +PG_FUNCTION_INFO_V1(int4_fixeddecimal_eq); +PG_FUNCTION_INFO_V1(int4_fixeddecimal_ne); +PG_FUNCTION_INFO_V1(int4_fixeddecimal_lt); +PG_FUNCTION_INFO_V1(int4_fixeddecimal_gt); +PG_FUNCTION_INFO_V1(int4_fixeddecimal_le); +PG_FUNCTION_INFO_V1(int4_fixeddecimal_ge); +PG_FUNCTION_INFO_V1(int4_fixeddecimal_cmp); + + +PG_FUNCTION_INFO_V1(fixeddecimal_int8_eq); +PG_FUNCTION_INFO_V1(fixeddecimal_int8_ne); +PG_FUNCTION_INFO_V1(fixeddecimal_int8_lt); +PG_FUNCTION_INFO_V1(fixeddecimal_int8_gt); +PG_FUNCTION_INFO_V1(fixeddecimal_int8_le); +PG_FUNCTION_INFO_V1(fixeddecimal_int8_ge); +PG_FUNCTION_INFO_V1(fixeddecimal_int8_cmp); + +PG_FUNCTION_INFO_V1(int8_fixeddecimal_eq); +PG_FUNCTION_INFO_V1(int8_fixeddecimal_ne); +PG_FUNCTION_INFO_V1(int8_fixeddecimal_lt); +PG_FUNCTION_INFO_V1(int8_fixeddecimal_gt); +PG_FUNCTION_INFO_V1(int8_fixeddecimal_le); +PG_FUNCTION_INFO_V1(int8_fixeddecimal_ge); +PG_FUNCTION_INFO_V1(int8_fixeddecimal_cmp); + +PG_FUNCTION_INFO_V1(fixeddecimal_numeric_cmp); +PG_FUNCTION_INFO_V1(fixeddecimal_numeric_eq); +PG_FUNCTION_INFO_V1(fixeddecimal_numeric_ne); +PG_FUNCTION_INFO_V1(fixeddecimal_numeric_lt); +PG_FUNCTION_INFO_V1(fixeddecimal_numeric_gt); +PG_FUNCTION_INFO_V1(fixeddecimal_numeric_le); +PG_FUNCTION_INFO_V1(fixeddecimal_numeric_ge); +PG_FUNCTION_INFO_V1(numeric_fixeddecimal_cmp); +PG_FUNCTION_INFO_V1(numeric_fixeddecimal_eq); +PG_FUNCTION_INFO_V1(numeric_fixeddecimal_ne); +PG_FUNCTION_INFO_V1(numeric_fixeddecimal_lt); +PG_FUNCTION_INFO_V1(numeric_fixeddecimal_gt); +PG_FUNCTION_INFO_V1(numeric_fixeddecimal_le); +PG_FUNCTION_INFO_V1(numeric_fixeddecimal_ge); +PG_FUNCTION_INFO_V1(fixeddecimal_hash); +PG_FUNCTION_INFO_V1(fixeddecimalum); +PG_FUNCTION_INFO_V1(fixeddecimalup); +PG_FUNCTION_INFO_V1(fixeddecimalpl); +PG_FUNCTION_INFO_V1(fixeddecimalmi); +PG_FUNCTION_INFO_V1(fixeddecimalmul); +PG_FUNCTION_INFO_V1(fixeddecimaldiv); +PG_FUNCTION_INFO_V1(fixeddecimalabs); +PG_FUNCTION_INFO_V1(fixeddecimallarger); +PG_FUNCTION_INFO_V1(fixeddecimalsmaller); +PG_FUNCTION_INFO_V1(fixeddecimalint8pl); +PG_FUNCTION_INFO_V1(fixeddecimalint8mi); +PG_FUNCTION_INFO_V1(fixeddecimalint8mul); +PG_FUNCTION_INFO_V1(fixeddecimalint8div); +PG_FUNCTION_INFO_V1(int8fixeddecimalpl); +PG_FUNCTION_INFO_V1(int8fixeddecimalmi); +PG_FUNCTION_INFO_V1(int8fixeddecimalmul); +PG_FUNCTION_INFO_V1(int8fixeddecimaldiv); +PG_FUNCTION_INFO_V1(fixeddecimalint4pl); +PG_FUNCTION_INFO_V1(fixeddecimalint4mi); +PG_FUNCTION_INFO_V1(fixeddecimalint4mul); +PG_FUNCTION_INFO_V1(fixeddecimalint4div); +PG_FUNCTION_INFO_V1(fixeddecimal); +PG_FUNCTION_INFO_V1(int4fixeddecimalpl); +PG_FUNCTION_INFO_V1(int4fixeddecimalmi); +PG_FUNCTION_INFO_V1(int4fixeddecimalmul); +PG_FUNCTION_INFO_V1(int4fixeddecimaldiv); +PG_FUNCTION_INFO_V1(fixeddecimalint2pl); +PG_FUNCTION_INFO_V1(fixeddecimalint2mi); +PG_FUNCTION_INFO_V1(fixeddecimalint2mul); +PG_FUNCTION_INFO_V1(fixeddecimalint2div); +PG_FUNCTION_INFO_V1(int2fixeddecimalpl); +PG_FUNCTION_INFO_V1(int2fixeddecimalmi); +PG_FUNCTION_INFO_V1(int2fixeddecimalmul); +PG_FUNCTION_INFO_V1(int2fixeddecimaldiv); +PG_FUNCTION_INFO_V1(int8fixeddecimal); +PG_FUNCTION_INFO_V1(fixeddecimalint8); +PG_FUNCTION_INFO_V1(int4fixeddecimal); +PG_FUNCTION_INFO_V1(fixeddecimalint4); +PG_FUNCTION_INFO_V1(int2fixeddecimal); +PG_FUNCTION_INFO_V1(fixeddecimalint2); +PG_FUNCTION_INFO_V1(fixeddecimaltod); +PG_FUNCTION_INFO_V1(dtofixeddecimal); +PG_FUNCTION_INFO_V1(fixeddecimaltof); +PG_FUNCTION_INFO_V1(ftofixeddecimal); +PG_FUNCTION_INFO_V1(numeric_fixeddecimal); +PG_FUNCTION_INFO_V1(fixeddecimal_numeric); +PG_FUNCTION_INFO_V1(fixeddecimal_avg_accum); +PG_FUNCTION_INFO_V1(fixeddecimal_avg); +PG_FUNCTION_INFO_V1(fixeddecimal_sum); +PG_FUNCTION_INFO_V1(fixeddecimalaggstatecombine); +PG_FUNCTION_INFO_V1(fixeddecimalaggstateserialize); +PG_FUNCTION_INFO_V1(fixeddecimalaggstatedeserialize); + +PG_FUNCTION_INFO_V1(fixeddecimalaggstatein); +PG_FUNCTION_INFO_V1(fixeddecimalaggstateout); +PG_FUNCTION_INFO_V1(fixeddecimalaggstatesend); +PG_FUNCTION_INFO_V1(fixeddecimalaggstaterecv); + +PG_FUNCTION_INFO_V1(char_to_fixeddecimal); + +/* Aggregate Internal State */ +typedef struct FixedDecimalAggState +{ + MemoryContext agg_context; /* context we're calculating in */ + int64 N; /* count of processed numbers */ + int64 sumX; /* sum of processed numbers */ +} FixedDecimalAggState; + +static char *pg_int64tostr(char *str, int64 value); +static char *pg_int64tostr_zeropad(char *str, int64 value, int64 padding); +static void apply_typmod(int64 value, int32 typmod, int precision, int scale); +static int64 scanfixeddecimal(const char *str, int *precision, int *scale); +static FixedDecimalAggState *makeFixedDecimalAggState(FunctionCallInfo fcinfo); +static void fixeddecimal_accum(FixedDecimalAggState *state, int64 newval); + +/*********************************************************************** + ** + ** Routines for fixeddecimal + ** + ***********************************************************************/ + +/*---------------------------------------------------------- + * Formatting and conversion routines. + *---------------------------------------------------------*/ + + /* + * 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; + + /* + * 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. + */ + if (value < 0) + { + *str++ = '-'; + + /* mark the position we must reverse the string from. */ + start = str; + + /* Compute the result string backwards. */ + do + { + int64 remainder; + int64 oldval = value; + + value /= 10; + remainder = oldval - value * 10; + *str++ = '0' + -remainder; + } while (value != 0); + } + else + { + /* mark the position we must reverse the string from. */ + start = str; + do + { + int64 remainder; + int64 oldval = value; + + value /= 10; + remainder = oldval - value * 10; + *str++ = '0' + remainder; + } while (value != 0); + } + + /* Add trailing NUL byte, and back up 'str' to the last character. */ + end = str; + *str-- = '\0'; + + /* Reverse string. */ + while (start < str) + { + char swap = *start; + *start++ = *str; + *str-- = swap; + } + return end; +} + +/* + * pg_int64tostr_zeropad + * Converts 'value' into a decimal string representation of the number. + * 'padding' specifies the minimum width of the number. Any extra space + * is filled up by prefixing the number with zeros. The return value is a + * pointer to the NUL terminated end of the string. + * + * Note: Callers should ensure that 'padding' is above zero. + * Note: This function is optimized for the case where the number is not too + * big to fit inside of the specified padding. + * Note: Caller must ensure that 'str' points to enough memory to hold the + result (at least 21 bytes, counting a leading sign and trailing NUL, + or padding + 1 bytes, whichever is larger). + */ +static char * +pg_int64tostr_zeropad(char *str, int64 value, int64 padding) +{ + char *start = str; + char *end = &str[padding]; + 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. + */ + if (num < 0) + { + *start++ = '-'; + padding--; + + /* + * Build the number starting at the end. Here remainder will be a + * negative number, we must reverse this sign on this before adding + * '0' in order to get the correct ASCII digit + */ + while (padding--) + { + int64 remainder; + int64 oldval = num; + + num /= 10; + remainder = oldval - num * 10; + start[padding] = '0' + -remainder; + } + } + else + { + /* build the number starting at the end */ + while (padding--) + { + int64 remainder; + int64 oldval = num; + + num /= 10; + remainder = oldval - num * 10; + start[padding] = '0' + remainder; + } + } + + /* + * If padding was not high enough to fit this number then num won't have + * been divided down to zero. We'd better have another go, this time we + * know there won't be any zero padding required so we can just enlist the + * help of pg_int64tostr() + */ + if (num != 0) + return pg_int64tostr(str, value); + + *end = '\0'; + return end; +} + +/* + * fixeddecimal2str + * Prints the fixeddecimal 'val' to buffer as a string. + * Returns a pointer to the end of the written string. + */ +static char * +fixeddecimal2str(int64 val, char *buffer) +{ + char *ptr = buffer; + int64 integralpart = val / FIXEDDECIMAL_MULTIPLIER; + int64 fractionalpart = val % FIXEDDECIMAL_MULTIPLIER; + + if (val < 0) + { + fractionalpart = -fractionalpart; + + /* + * Handle special case for negative numbers where the intergral part + * is zero. pg_int64tostr() won't prefix with "-0" in this case, so + * we'll do it manually + */ + if (integralpart == 0) + *ptr++ = '-'; + } + ptr = pg_int64tostr(ptr, integralpart); + *ptr++ = '.'; + ptr = pg_int64tostr_zeropad(ptr, fractionalpart, FIXEDDECIMAL_SCALE); + return ptr; +} + +/* + * scanfixeddecimal --- try to parse a string into a fixeddecimal. + */ +static int64 +scanfixeddecimal(const char *str, int *precision, int *scale) +{ + const char *ptr = str; + int64 integralpart = 0; + int64 fractionalpart = 0; + bool negative; + int vprecision = 0; + int vscale = 0; + bool has_seen_sign = false; + + /* + * Do our own scan, rather than relying on sscanf which might be broken + * for long long. + */ + + /* skip leading spaces */ + while (isspace((unsigned char) *ptr)) + ptr++; + + /* handle sign */ + if (*ptr == '-') + { + has_seen_sign = true; + negative = true; + ptr++; + } + else + { + negative = false; + + if (*ptr == '+') + { + has_seen_sign = true; + ptr++; + } + } + + /* skip leading spaces */ + while (isspace((unsigned char) *ptr)) + ptr++; + + /* skip currency symbol bytes */ + while (!isdigit((unsigned char) *ptr) && + (unsigned int) *ptr != '.' && + (unsigned int) *ptr != '-' && + (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')) + { + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("invalid characters found: cannot cast value \"%s\" to money", + str))); + } + 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 */ + 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))); + } + negative = true; + ptr++; + + /* skip leading spaces */ + while (isspace((unsigned char) *ptr)) + ptr++; + + while (isdigit((unsigned char) *ptr)) + { + int64 tmp = integralpart * 10 - (*ptr++ - '0'); + + vprecision++; + 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))); + } + integralpart = tmp; + /* skip thousand separator */ + if(*ptr == ',') + ptr++; + } + } + else + { + if (!has_seen_sign) + negative = false; + + 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))); + } + ptr++; + } + + /* 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? */ + { + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("value \"%s\" is out of range for type fixeddecimal", + str))); + } + integralpart = tmp; + /* skip thousand separator */ + if(*ptr == ',') + ptr++; + } + } + /* process the part after the decimal point */ + if (*ptr == '.') + { + int64 multiplier = FIXEDDECIMAL_MULTIPLIER; + ptr++; + + while (isdigit((unsigned char) *ptr) && multiplier > 1) + { + multiplier /= 10; + fractionalpart += (*ptr++ - '0') * multiplier; + vscale++; + } + + /* + * Eat into any excess precision digits. + * XXX These are ignored, should we error instead? + */ + while (isdigit((unsigned char) *ptr)) + ptr++, vscale++; + } + + /* consume any remaining space chars */ + while (isspace((unsigned char) *ptr)) + ptr++; + + if (*ptr != '\0') + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("value \"%s\" is out of range for type fixeddecimal", str))); + + *precision = vprecision; + *scale = vscale; + + if (negative) + { + + int64 value; + +#ifdef HAVE_BUILTIN_OVERFLOW + 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))); + + 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))); + return value; + +#else + value = integralpart * FIXEDDECIMAL_MULTIPLIER; + if (value != 0 && (!SAMESIGN(value, integralpart) || + !SAMESIGN(value - fractionalpart, value) || + !SAMESIGN(value - fractionalpart, value))) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("value \"%s\" is out of range for type fixeddecimal", + str))); + + return value - fractionalpart; +#endif /* HAVE_BUILTIN_OVERFLOW */ + + } + else + { + 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))); + + 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))); + return value; +#else + value = integralpart * FIXEDDECIMAL_MULTIPLIER; + if (value != 0 && (!SAMESIGN(value, integralpart) || + !SAMESIGN(value - fractionalpart, value) || + !SAMESIGN(value + fractionalpart, value))) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("value \"%s\" is out of range for type fixeddecimal", + str))); + + return value + fractionalpart; +#endif /* HAVE_BUILTIN_OVERFLOW */ + + } +} + +/* + * fixeddecimalin() + */ +Datum +fixeddecimalin(PG_FUNCTION_ARGS) +{ + char *str = PG_GETARG_CSTRING(0); + int32 typmod = PG_GETARG_INT32(2); + int precision; + int scale; + int64 result = scanfixeddecimal(str, &precision, &scale); + + apply_typmod(result, typmod, precision, scale); + + PG_RETURN_INT64(result); +} + +static void +apply_typmod(int64 value, int32 typmod, int precision, int scale) +{ + int precisionlimit; + int scalelimit; + int maxdigits; + + /* Do nothing if we have a default typmod (-1) */ + if (typmod < (int32) (VARHDRSZ)) + return; + + typmod -= VARHDRSZ; + precisionlimit = (typmod >> 16) & 0xffff; + scalelimit = typmod & 0xffff; + maxdigits = precisionlimit - scalelimit; + + if (scale > scalelimit) + + if (scale != FIXEDDECIMAL_SCALE) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("FIXEDDECIMAL scale must be %d", + FIXEDDECIMAL_SCALE))); + + if (precision > maxdigits) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + 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 */ + maxdigits ? "10^" : "", + maxdigits ? maxdigits : 1 + ))); + +} + +Datum +fixeddecimaltypmodin(PG_FUNCTION_ARGS) +{ + ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0); + int32 *tl; + int n; + int32 typmod; + + tl = ArrayGetIntegerTypmods(ta, &n); + + if (n == 2) + { + /* + * we demand that the precision is at least the scale, since later we + * enforce that the scale is exactly FIXEDDECIMAL_SCALE + */ + if (tl[0] < FIXEDDECIMAL_SCALE || tl[0] > FIXEDDECIMAL_MAX_PRECISION) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("FIXEDDECIMAL precision %d must be between %d and %d", + tl[0], FIXEDDECIMAL_SCALE, FIXEDDECIMAL_MAX_PRECISION))); + + if (tl[1] != FIXEDDECIMAL_SCALE) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("FIXEDDECIMAL scale must be %d", + FIXEDDECIMAL_SCALE))); + + typmod = ((tl[0] << 16) | tl[1]) + VARHDRSZ; + } + else if (n == 1) + { + if (tl[0] < FIXEDDECIMAL_SCALE || tl[0] > FIXEDDECIMAL_MAX_PRECISION) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("FIXEDDECIMAL precision %d must be between %d and %d", + tl[0], FIXEDDECIMAL_SCALE, FIXEDDECIMAL_MAX_PRECISION))); + + /* scale defaults to FIXEDDECIMAL_SCALE */ + typmod = ((tl[0] << 16) | FIXEDDECIMAL_SCALE) + VARHDRSZ; + } + else + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid FIXEDDECIMAL type modifier"))); + typmod = 0; /* keep compiler quiet */ + } + + PG_RETURN_INT32(typmod); +} + +Datum +fixeddecimaltypmodout(PG_FUNCTION_ARGS) +{ + int32 typmod = PG_GETARG_INT32(0); + char *res = (char *) palloc(64); + + if (typmod >= 0) + snprintf(res, 64, "(%d,%d)", + ((typmod - VARHDRSZ) >> 16) & 0xffff, + (typmod - VARHDRSZ) & 0xffff); + else + *res = '\0'; + + PG_RETURN_CSTRING(res); +} + + +/* + * fixeddecimalout() + */ +Datum +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)); +} + +/* + * fixeddecimalrecv - converts external binary format to int8 + */ +Datum +fixeddecimalrecv(PG_FUNCTION_ARGS) +{ + StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); + + PG_RETURN_INT64(pq_getmsgint64(buf)); +} + +/* + * fixeddecimalsend - converts int8 to binary format + */ +Datum +fixeddecimalsend(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + StringInfoData buf; + + pq_begintypsend(&buf); + pq_sendint64(&buf, arg1); + PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); +} + + +/*---------------------------------------------------------- + * Relational operators for fixeddecimals, including cross-data-type comparisons. + *---------------------------------------------------------*/ + +Datum +fixeddecimaleq(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT64(0); + int64 val2 = PG_GETARG_INT64(1); + + PG_RETURN_BOOL(val1 == val2); +} + +Datum +fixeddecimalne(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT64(0); + int64 val2 = PG_GETARG_INT64(1); + + PG_RETURN_BOOL(val1 != val2); +} + +Datum +fixeddecimallt(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT64(0); + int64 val2 = PG_GETARG_INT64(1); + + PG_RETURN_BOOL(val1 < val2); +} + +Datum +fixeddecimalgt(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT64(0); + int64 val2 = PG_GETARG_INT64(1); + + PG_RETURN_BOOL(val1 > val2); +} + +Datum +fixeddecimalle(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT64(0); + int64 val2 = PG_GETARG_INT64(1); + + PG_RETURN_BOOL(val1 <= val2); +} + +Datum +fixeddecimalge(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT64(0); + int64 val2 = PG_GETARG_INT64(1); + + PG_RETURN_BOOL(val1 >= val2); +} + +Datum +fixeddecimal_cmp(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT64(0); + int64 val2 = PG_GETARG_INT64(1); + + if (val1 == val2) + PG_RETURN_INT32(0); + else if (val1 < val2) + PG_RETURN_INT32(-1); + else + PG_RETURN_INT32(1); +} + +/* int2, fixeddecimal */ +Datum +fixeddecimal_int2_eq(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT64(0); + int64 val2 = PG_GETARG_INT16(1) * FIXEDDECIMAL_MULTIPLIER; + + PG_RETURN_BOOL(val1 == val2); +} + +Datum +fixeddecimal_int2_ne(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT64(0); + int64 val2 = PG_GETARG_INT16(1) * FIXEDDECIMAL_MULTIPLIER; + + PG_RETURN_BOOL(val1 != val2); +} + +Datum +fixeddecimal_int2_lt(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT64(0); + int64 val2 = PG_GETARG_INT16(1) * FIXEDDECIMAL_MULTIPLIER; + + PG_RETURN_BOOL(val1 < val2); +} + +Datum +fixeddecimal_int2_gt(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT64(0); + int64 val2 = PG_GETARG_INT16(1) * FIXEDDECIMAL_MULTIPLIER; + + PG_RETURN_BOOL(val1 > val2); +} + +Datum +fixeddecimal_int2_le(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT64(0); + int64 val2 = PG_GETARG_INT16(1) * FIXEDDECIMAL_MULTIPLIER; + + PG_RETURN_BOOL(val1 <= val2); +} + +Datum +fixeddecimal_int2_ge(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT64(0); + int64 val2 = PG_GETARG_INT16(1) * FIXEDDECIMAL_MULTIPLIER; + + PG_RETURN_BOOL(val1 >= val2); +} + +Datum +fixeddecimal_int2_cmp(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT64(0); + int64 val2 = PG_GETARG_INT16(1) * FIXEDDECIMAL_MULTIPLIER; + + if (val1 == val2) + PG_RETURN_INT32(0); + else if (val1 < val2) + PG_RETURN_INT32(-1); + else + PG_RETURN_INT32(1); +} + +Datum +int2_fixeddecimal_eq(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT16(0) * FIXEDDECIMAL_MULTIPLIER; + int64 val2 = PG_GETARG_INT64(1); + + PG_RETURN_BOOL(val1 == val2); +} + +Datum +int2_fixeddecimal_ne(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT16(0) * FIXEDDECIMAL_MULTIPLIER; + int64 val2 = PG_GETARG_INT64(1); + + PG_RETURN_BOOL(val1 != val2); +} + +Datum +int2_fixeddecimal_lt(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT16(0) * FIXEDDECIMAL_MULTIPLIER; + int64 val2 = PG_GETARG_INT64(1); + + PG_RETURN_BOOL(val1 < val2); +} + +Datum +int2_fixeddecimal_gt(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT16(0) * FIXEDDECIMAL_MULTIPLIER; + int64 val2 = PG_GETARG_INT64(1); + + PG_RETURN_BOOL(val1 > val2); +} + +Datum +int2_fixeddecimal_le(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT16(0) * FIXEDDECIMAL_MULTIPLIER; + int64 val2 = PG_GETARG_INT64(1); + + PG_RETURN_BOOL(val1 <= val2); +} + +Datum +int2_fixeddecimal_ge(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT16(0) * FIXEDDECIMAL_MULTIPLIER; + int64 val2 = PG_GETARG_INT64(1); + + PG_RETURN_BOOL(val1 >= val2); +} + +Datum +int2_fixeddecimal_cmp(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT16(0) * FIXEDDECIMAL_MULTIPLIER; + int64 val2 = PG_GETARG_INT64(1); + + if (val1 == val2) + PG_RETURN_INT32(0); + else if (val1 < val2) + PG_RETURN_INT32(-1); + else + PG_RETURN_INT32(1); +} + +/* fixeddecimal, int4 */ +Datum +fixeddecimal_int4_eq(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT64(0); + int64 val2 = PG_GETARG_INT32(1) * FIXEDDECIMAL_MULTIPLIER; + + PG_RETURN_BOOL(val1 == val2); +} + +Datum +fixeddecimal_int4_ne(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT64(0); + int64 val2 = PG_GETARG_INT32(1) * FIXEDDECIMAL_MULTIPLIER; + + PG_RETURN_BOOL(val1 != val2); +} + +Datum +fixeddecimal_int4_lt(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT64(0); + int64 val2 = PG_GETARG_INT32(1) * FIXEDDECIMAL_MULTIPLIER; + + PG_RETURN_BOOL(val1 < val2); +} + +Datum +fixeddecimal_int4_gt(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT64(0); + int64 val2 = PG_GETARG_INT32(1) * FIXEDDECIMAL_MULTIPLIER; + + PG_RETURN_BOOL(val1 > val2); +} + +Datum +fixeddecimal_int4_le(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT64(0); + int64 val2 = PG_GETARG_INT32(1) * FIXEDDECIMAL_MULTIPLIER; + + PG_RETURN_BOOL(val1 <= val2); +} + +Datum +fixeddecimal_int4_ge(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT64(0); + int64 val2 = PG_GETARG_INT32(1) * FIXEDDECIMAL_MULTIPLIER; + + PG_RETURN_BOOL(val1 >= val2); +} + +Datum +fixeddecimal_int4_cmp(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT64(0); + int64 val2 = PG_GETARG_INT32(1) * FIXEDDECIMAL_MULTIPLIER; + + if (val1 == val2) + PG_RETURN_INT32(0); + else if (val1 < val2) + PG_RETURN_INT32(-1); + else + PG_RETURN_INT32(1); +} + +Datum +int4_fixeddecimal_eq(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT32(0) * FIXEDDECIMAL_MULTIPLIER; + int64 val2 = PG_GETARG_INT64(1); + + PG_RETURN_BOOL(val1 == val2); +} + +Datum +int4_fixeddecimal_ne(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT32(0) * FIXEDDECIMAL_MULTIPLIER; + int64 val2 = PG_GETARG_INT64(1); + + PG_RETURN_BOOL(val1 != val2); +} + +Datum +int4_fixeddecimal_lt(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT32(0) * FIXEDDECIMAL_MULTIPLIER; + int64 val2 = PG_GETARG_INT64(1); + + PG_RETURN_BOOL(val1 < val2); +} + +Datum +int4_fixeddecimal_gt(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT32(0) * FIXEDDECIMAL_MULTIPLIER; + int64 val2 = PG_GETARG_INT64(1); + + PG_RETURN_BOOL(val1 > val2); +} + +Datum +int4_fixeddecimal_le(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT32(0) * FIXEDDECIMAL_MULTIPLIER; + int64 val2 = PG_GETARG_INT64(1); + + PG_RETURN_BOOL(val1 <= val2); +} + +Datum +int4_fixeddecimal_ge(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT32(0) * FIXEDDECIMAL_MULTIPLIER; + int64 val2 = PG_GETARG_INT64(1); + + PG_RETURN_BOOL(val1 >= val2); +} + +Datum +int4_fixeddecimal_cmp(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT32(0) * FIXEDDECIMAL_MULTIPLIER; + int64 val2 = PG_GETARG_INT64(1); + + if (val1 == val2) + PG_RETURN_INT32(0); + else if (val1 < val2) + PG_RETURN_INT32(-1); + else + PG_RETURN_INT32(1); +} + +/* fixeddecimal, int8 */ +Datum +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; +} + +Datum +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; +} + +Datum +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; +} + +Datum +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; +} + +Datum +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; +} + +Datum +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; +} + +Datum +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 (val1 == val2) + PG_RETURN_INT32(0); + else if (val1 < val2) + PG_RETURN_INT32(-1); + else + PG_RETURN_INT32(1); +} + +Datum +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; +} + +Datum +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; +} + +Datum +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; +} + +Datum +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; +} + +Datum +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; +} + +Datum +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; +} + +Datum +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 == val2) + PG_RETURN_INT32(0); + else if (val1 < val2) + PG_RETURN_INT32(-1); + else + PG_RETURN_INT32(1); +} + +Datum +fixeddecimal_numeric_cmp(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + Datum val2 = PG_GETARG_DATUM(1); + Datum val1; + + val1 = DirectFunctionCall1(fixeddecimal_numeric, Int64GetDatum(arg1)); + + PG_RETURN_INT32(DirectFunctionCall2(numeric_cmp, val1, val2)); +} + +Datum +fixeddecimal_numeric_eq(PG_FUNCTION_ARGS) +{ + Datum val1 = PG_GETARG_DATUM(0); + Datum val2 = PG_GETARG_DATUM(1); + int32 result; + + result = DatumGetInt32(DirectFunctionCall2(fixeddecimal_numeric_cmp, val1, + val2)); + + PG_RETURN_BOOL(result == 0); +} + +Datum +fixeddecimal_numeric_ne(PG_FUNCTION_ARGS) +{ + Datum val1 = PG_GETARG_DATUM(0); + Datum val2 = PG_GETARG_DATUM(1); + int32 result; + + result = DatumGetInt32(DirectFunctionCall2(fixeddecimal_numeric_cmp, val1, + val2)); + + PG_RETURN_BOOL(result != 0); +} + +Datum +fixeddecimal_numeric_lt(PG_FUNCTION_ARGS) +{ + Datum val1 = PG_GETARG_DATUM(0); + Datum val2 = PG_GETARG_DATUM(1); + int32 result; + + result = DatumGetInt32(DirectFunctionCall2(fixeddecimal_numeric_cmp, val1, + val2)); + + PG_RETURN_BOOL(result < 0); +} + +Datum +fixeddecimal_numeric_gt(PG_FUNCTION_ARGS) +{ + Datum val1 = PG_GETARG_DATUM(0); + Datum val2 = PG_GETARG_DATUM(1); + int32 result; + + result = DatumGetInt32(DirectFunctionCall2(fixeddecimal_numeric_cmp, val1, + val2)); + + PG_RETURN_BOOL(result > 0); +} + +Datum +fixeddecimal_numeric_le(PG_FUNCTION_ARGS) +{ + Datum val1 = PG_GETARG_DATUM(0); + Datum val2 = PG_GETARG_DATUM(1); + int32 result; + + result = DatumGetInt32(DirectFunctionCall2(fixeddecimal_numeric_cmp, val1, + val2)); + + PG_RETURN_BOOL(result <= 0); +} + +Datum +fixeddecimal_numeric_ge(PG_FUNCTION_ARGS) +{ + Datum val1 = PG_GETARG_DATUM(0); + Datum val2 = PG_GETARG_DATUM(1); + int32 result; + + result = DatumGetInt32(DirectFunctionCall2(fixeddecimal_numeric_cmp, val1, + val2)); + + PG_RETURN_BOOL(result >= 0); +} + +Datum +numeric_fixeddecimal_cmp(PG_FUNCTION_ARGS) +{ + Datum val1 = PG_GETARG_DATUM(0); + int64 arg2 = PG_GETARG_INT64(1); + Datum val2; + + val2 = DirectFunctionCall1(fixeddecimal_numeric, Int64GetDatum(arg2)); + + PG_RETURN_INT32(DirectFunctionCall2(numeric_cmp, val1, val2)); +} + +Datum +numeric_fixeddecimal_eq(PG_FUNCTION_ARGS) +{ + Datum val1 = PG_GETARG_DATUM(0); + Datum val2 = PG_GETARG_DATUM(1); + int32 result; + + result = DatumGetInt32(DirectFunctionCall2(numeric_fixeddecimal_cmp, val1, + val2)); + + PG_RETURN_BOOL(result == 0); +} + +Datum +numeric_fixeddecimal_ne(PG_FUNCTION_ARGS) +{ + Datum val1 = PG_GETARG_DATUM(0); + Datum val2 = PG_GETARG_DATUM(1); + int32 result; + + result = DatumGetInt32(DirectFunctionCall2(numeric_fixeddecimal_cmp, val1, + val2)); + + PG_RETURN_BOOL(result != 0); +} + +Datum +numeric_fixeddecimal_lt(PG_FUNCTION_ARGS) +{ + Datum val1 = PG_GETARG_DATUM(0); + Datum val2 = PG_GETARG_DATUM(1); + int32 result; + + result = DatumGetInt32(DirectFunctionCall2(numeric_fixeddecimal_cmp, val1, + val2)); + + PG_RETURN_BOOL(result < 0); +} + +Datum +numeric_fixeddecimal_gt(PG_FUNCTION_ARGS) +{ + Datum val1 = PG_GETARG_DATUM(0); + Datum val2 = PG_GETARG_DATUM(1); + int32 result; + + result = DatumGetInt32(DirectFunctionCall2(numeric_fixeddecimal_cmp, val1, + val2)); + + PG_RETURN_BOOL(result > 0); +} + +Datum +numeric_fixeddecimal_le(PG_FUNCTION_ARGS) +{ + Datum val1 = PG_GETARG_DATUM(0); + Datum val2 = PG_GETARG_DATUM(1); + int32 result; + + result = DatumGetInt32(DirectFunctionCall2(numeric_fixeddecimal_cmp, val1, + val2)); + + PG_RETURN_BOOL(result <= 0); +} + +Datum +numeric_fixeddecimal_ge(PG_FUNCTION_ARGS) +{ + Datum val1 = PG_GETARG_DATUM(0); + Datum val2 = PG_GETARG_DATUM(1); + int32 result; + + result = DatumGetInt32(DirectFunctionCall2(numeric_fixeddecimal_cmp, val1, + val2)); + + PG_RETURN_BOOL(result >= 0); +} + +Datum +fixeddecimal_hash(PG_FUNCTION_ARGS) +{ + int64 val = PG_GETARG_INT64(0); + Datum result; + + result = hash_any((unsigned char *) &val, sizeof(int64)); + PG_RETURN_DATUM(result); +} + +/*---------------------------------------------------------- + * Arithmetic operators on fixeddecimal. + *---------------------------------------------------------*/ + +Datum +fixeddecimalum(PG_FUNCTION_ARGS) +{ + int64 arg = PG_GETARG_INT64(0); + int64 result; + +#ifdef HAVE_BUILTIN_OVERFLOW + int64 zero = 0; + + if (__builtin_sub_overflow(zero, arg, &result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#else + result = -arg; + /* overflow check (needed for INT64_MIN) */ + if (arg != 0 && SAMESIGN(result, arg)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#endif /* HAVE_BUILTIN_OVERFLOW */ + PG_RETURN_INT64(result); +} + +Datum +fixeddecimalup(PG_FUNCTION_ARGS) +{ + int64 arg = PG_GETARG_INT64(0); + + PG_RETURN_INT64(arg); +} + +Datum +fixeddecimalpl(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + int64 arg2 = PG_GETARG_INT64(1); + int64 result; + +#ifdef HAVE_BUILTIN_OVERFLOW + if (__builtin_add_overflow(arg1, arg2, &result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#else + result = arg1 + arg2; + + /* + * Overflow check. If the inputs are of different signs then their sum + * cannot overflow. If the inputs are of the same sign, their sum had + * better be that sign too. + */ + if (SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#endif /* HAVE_BUILTIN_OVERFLOW */ + + PG_RETURN_INT64(result); +} + +Datum +fixeddecimalmi(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + int64 arg2 = PG_GETARG_INT64(1); + int64 result; + +#ifdef HAVE_BUILTIN_OVERFLOW + if (__builtin_sub_overflow(arg1, arg2, &result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#else + result = arg1 - arg2; + + /* + * Overflow check. If the inputs are of the same sign then their + * difference cannot overflow. If they are of different signs then the + * result should be of the same sign as the first input. + */ + if (!SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#endif /* HAVE_BUILTIN_OVERFLOW */ + + PG_RETURN_INT64(result); +} + +Datum +fixeddecimalmul(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + 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. + */ + result = (int128) arg1 * arg2 / FIXEDDECIMAL_MULTIPLIER; + + if (result != ((int64) result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); + + PG_RETURN_INT64((int64) result); +} + +Datum +fixeddecimaldiv(PG_FUNCTION_ARGS) +{ + int64 dividend = PG_GETARG_INT64(0); + int64 divisor = PG_GETARG_INT64(1); + int128 result; + + 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(); + } + + if (divisor == 0) + ereport(ERROR, + (errcode(ERRCODE_DIVISION_BY_ZERO), + errmsg("division by zero"))); + + /* + * this can't overflow, but we can end up with a number that's too big for + * int64 + */ + result = (int128) dividend * FIXEDDECIMAL_MULTIPLIER / divisor; + + if (result != ((int64) result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); + + PG_RETURN_INT64((int64) result); +} + +/* fixeddecimalabs() + * Absolute value + */ +Datum +fixeddecimalabs(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + int64 result; + + result = (arg1 < 0) ? -arg1 : arg1; + /* overflow check (needed for INT64_MIN) */ + if (result < 0) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); + PG_RETURN_INT64(result); +} + + +Datum +fixeddecimallarger(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + int64 arg2 = PG_GETARG_INT64(1); + int64 result; + + result = ((arg1 > arg2) ? arg1 : arg2); + + PG_RETURN_INT64(result); +} + +Datum +fixeddecimalsmaller(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + int64 arg2 = PG_GETARG_INT64(1); + int64 result; + + result = ((arg1 < arg2) ? arg1 : arg2); + + PG_RETURN_INT64(result); +} + +Datum +fixeddecimalint8pl(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + int64 adder = PG_GETARG_INT64(1) * FIXEDDECIMAL_MULTIPLIER; + int64 result; + +#ifdef HAVE_BUILTIN_OVERFLOW + if (__builtin_add_overflow(arg1, adder, &result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#else + result = arg1 + adder; + + /* + * Overflow check. If the inputs are of different signs then their sum + * cannot overflow. If the inputs are of the same sign, their sum had + * better be that sign too. + */ + if (SAMESIGN(arg1, adder) && !SAMESIGN(result, arg1)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#endif /* HAVE_BUILTIN_OVERFLOW */ + + PG_RETURN_INT64(result); +} + +Datum +fixeddecimalint8mi(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + int64 subtractor = PG_GETARG_INT64(1) * FIXEDDECIMAL_MULTIPLIER; + int64 result; + + +#ifdef HAVE_BUILTIN_OVERFLOW + if (__builtin_sub_overflow(arg1, subtractor, &result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#else + result = arg1 - subtractor; + + /* + * Overflow check. If the inputs are of the same sign then their + * difference cannot overflow. If they are of different signs then the + * result should be of the same sign as the first input. + */ + if (!SAMESIGN(arg1, subtractor) && !SAMESIGN(result, arg1)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#endif /* HAVE_BUILTIN_OVERFLOW */ + + PG_RETURN_INT64(result); +} + +Datum +fixeddecimalint8mul(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + int64 arg2 = PG_GETARG_INT64(1); + int64 result; + +#ifdef HAVE_BUILTIN_OVERFLOW + if (__builtin_mul_overflow(arg1, arg2, &result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#else + result = arg1 * arg2; + + /* + * Overflow check. We basically check to see if result / arg1 gives arg2 + * again. There is one case where this fails: arg1 = 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 + * the buck seems to be to check whether both inputs are in the int32 + * range; if so, no overflow is possible. + */ + if (arg1 != (int64) ((int32) arg1) && + result / arg1 != arg2) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#endif /* HAVE_BUILTIN_OVERFLOW */ + + PG_RETURN_INT64(result); +} + +Datum +fixeddecimalint8div(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + int64 arg2 = PG_GETARG_INT64(1); + int64 result; + + if (arg2 == 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(); + } + + /* + * INT64_MIN / -1 is problematic, since the result can't be represented on + * a two's-complement machine. Some machines produce INT64_MIN, some + * produce zero, some throw an exception. We can dodge the problem by + * recognizing that division by -1 is the same as negation. + */ + if (arg2 == -1) + { +#ifdef HAVE_BUILTIN_OVERFLOW + int64 zero = 0; + if (__builtin_sub_overflow(zero, arg1, &result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#else + result = -arg1; + /* overflow check (needed for INT64_MIN) */ + if (arg1 != 0 && SAMESIGN(result, arg1)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#endif /* HAVE_BUILTIN_OVERFLOW */ + + PG_RETURN_INT64(result); + } + + /* No overflow is possible */ + + result = arg1 / arg2; + + PG_RETURN_INT64(result); +} + +Datum +int8fixeddecimalpl(PG_FUNCTION_ARGS) +{ + int64 adder = PG_GETARG_INT64(0) * FIXEDDECIMAL_MULTIPLIER; + int64 arg2 = PG_GETARG_INT64(1); + int64 result; + +#ifdef HAVE_BUILTIN_OVERFLOW + if (__builtin_add_overflow(adder, arg2, &result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#else + result = adder + arg2; + + /* + * Overflow check. If the inputs are of different signs then their sum + * cannot overflow. If the inputs are of the same sign, their sum had + * better be that sign too. + */ + if (SAMESIGN(adder, arg2) && !SAMESIGN(result, adder)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#endif /* HAVE_BUILTIN_OVERFLOW */ + + PG_RETURN_INT64(result); +} + +Datum +int8fixeddecimalmi(PG_FUNCTION_ARGS) +{ + int64 subtractor = PG_GETARG_INT64(0) * FIXEDDECIMAL_MULTIPLIER; + int64 arg2 = PG_GETARG_INT64(1); + int64 result; + +#ifdef HAVE_BUILTIN_OVERFLOW + if (__builtin_sub_overflow(subtractor, arg2, &result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#else + result = subtractor - arg2; + + /* + * Overflow check. If the inputs are of the same sign then their + * difference cannot overflow. If they are of different signs then the + * result should be of the same sign as the first input. + */ + if (!SAMESIGN(subtractor, arg2) && !SAMESIGN(result, subtractor)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#endif /* HAVE_BUILTIN_OVERFLOW */ + + PG_RETURN_INT64(result); +} + +Datum +int8fixeddecimalmul(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + int64 arg2 = PG_GETARG_INT64(1); + int64 result; + +#ifdef HAVE_BUILTIN_OVERFLOW + if (__builtin_mul_overflow(arg1, arg2, &result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#else + 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). + * + * Since the division is likely much more expensive than the actual + * multiplication, we'd like to skip it where possible. The best bang for + * the buck seems to be to check whether both inputs are in the int32 + * range; if so, no overflow is possible. + */ + if (arg2 != (int64) ((int32) arg2) && + result / arg2 != arg1) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#endif /* HAVE_BUILTIN_OVERFLOW */ + + PG_RETURN_INT64(result); +} + +Datum +int8fixeddecimaldiv(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + float8 arg2 = (float8) PG_GETARG_INT64(1) / (float8) FIXEDDECIMAL_MULTIPLIER; + + if (arg2 == 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(); + } + + /* No overflow is possible */ + PG_RETURN_FLOAT8((float8) arg1 / arg2); +} + +Datum +fixeddecimalint4pl(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + int64 adder = PG_GETARG_INT32(1) * FIXEDDECIMAL_MULTIPLIER; + int64 result; + +#ifdef HAVE_BUILTIN_OVERFLOW + if (__builtin_add_overflow(arg1, adder, &result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#else + result = arg1 + adder; + + /* + * Overflow check. If the inputs are of different signs then their sum + * cannot overflow. If the inputs are of the same sign, their sum had + * better be that sign too. + */ + if (SAMESIGN(arg1, adder) && !SAMESIGN(result, arg1)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#endif /* HAVE_BUILTIN_OVERFLOW */ + + PG_RETURN_INT64(result); +} + +Datum +fixeddecimalint4mi(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + int64 subtractor = PG_GETARG_INT32(1) * FIXEDDECIMAL_MULTIPLIER; + int64 result; + + +#ifdef HAVE_BUILTIN_OVERFLOW + if (__builtin_sub_overflow(arg1, subtractor, &result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#else + result = arg1 - subtractor; + + /* + * Overflow check. If the inputs are of the same sign then their + * difference cannot overflow. If they are of different signs then the + * result should be of the same sign as the first input. + */ + if (!SAMESIGN(arg1, subtractor) && !SAMESIGN(result, arg1)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#endif /* HAVE_BUILTIN_OVERFLOW */ + + PG_RETURN_INT64(result); +} + +Datum +fixeddecimalint4mul(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + int32 arg2 = PG_GETARG_INT32(1); + int64 result; + +#ifdef HAVE_BUILTIN_OVERFLOW + if (__builtin_mul_overflow(arg1, arg2, &result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#else + result = arg1 * arg2; + + /* + * Overflow check. We basically check to see if result / arg1 gives arg2 + * again. There is one case where this fails: arg1 = 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 + * the buck seems to be to check whether both inputs are in the int32 + * range; if so, no overflow is possible. + */ + if (arg1 != (int64) ((int32) arg1) && + result / arg1 != arg2) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#endif /* HAVE_BUILTIN_OVERFLOW */ + + PG_RETURN_INT64(result); +} + +Datum +fixeddecimalint4div(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + int32 arg2 = PG_GETARG_INT32(1); + int64 result; + + if (arg2 == 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(); + } + + /* + * INT64_MIN / -1 is problematic, since the result can't be represented on + * a two's-complement machine. Some machines produce INT64_MIN, some + * produce zero, some throw an exception. We can dodge the problem by + * recognizing that division by -1 is the same as negation. + */ + if (arg2 == -1) + { +#ifdef HAVE_BUILTIN_OVERFLOW + int64 zero = 0; + if (__builtin_sub_overflow(zero, arg1, &result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#else + result = -arg1; + /* overflow check (needed for INT64_MIN) */ + if (arg1 != 0 && SAMESIGN(result, arg1)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#endif /* HAVE_BUILTIN_OVERFLOW */ + + PG_RETURN_INT64(result); + } + + /* No overflow is possible */ + + result = arg1 / arg2; + + PG_RETURN_INT64(result); +} + +Datum +int4fixeddecimalpl(PG_FUNCTION_ARGS) +{ + int64 adder = PG_GETARG_INT32(0) * FIXEDDECIMAL_MULTIPLIER; + int64 arg2 = PG_GETARG_INT64(1); + int64 result; + +#ifdef HAVE_BUILTIN_OVERFLOW + if (__builtin_add_overflow(adder, arg2, &result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#else + result = adder + arg2; + + /* + * Overflow check. If the inputs are of different signs then their sum + * cannot overflow. If the inputs are of the same sign, their sum had + * better be that sign too. + */ + if (SAMESIGN(adder, arg2) && !SAMESIGN(result, adder)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#endif /* HAVE_BUILTIN_OVERFLOW */ + + PG_RETURN_INT64(result); +} + +Datum +int4fixeddecimalmi(PG_FUNCTION_ARGS) +{ + int64 subtractor = PG_GETARG_INT32(0) * FIXEDDECIMAL_MULTIPLIER; + int64 arg2 = PG_GETARG_INT64(1); + int64 result; + +#ifdef HAVE_BUILTIN_OVERFLOW + if (__builtin_sub_overflow(subtractor, arg2, &result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#else + result = subtractor - arg2; + + /* + * Overflow check. If the inputs are of the same sign then their + * difference cannot overflow. If they are of different signs then the + * result should be of the same sign as the first input. + */ + if (!SAMESIGN(subtractor, arg2) && !SAMESIGN(result, subtractor)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#endif /* HAVE_BUILTIN_OVERFLOW */ + + PG_RETURN_INT64(result); +} + +Datum +int4fixeddecimalmul(PG_FUNCTION_ARGS) +{ + int32 arg1 = PG_GETARG_INT32(0); + int64 arg2 = PG_GETARG_INT64(1); + int64 result; + +#ifdef HAVE_BUILTIN_OVERFLOW + if (__builtin_mul_overflow(arg1, arg2, &result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#else + 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). + * + * Since the division is likely much more expensive than the actual + * multiplication, we'd like to skip it where possible. The best bang for + * the buck seems to be to check whether both inputs are in the int32 + * range; if so, no overflow is possible. + */ + if (arg2 != (int64) ((int32) arg2) && + result / arg2 != arg1) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#endif /* HAVE_BUILTIN_OVERFLOW */ + + PG_RETURN_INT64(result); +} + +Datum +int4fixeddecimaldiv(PG_FUNCTION_ARGS) +{ + int32 arg1 = PG_GETARG_INT32(0); + float8 arg2 = (float8) PG_GETARG_INT64(1) / (float8) FIXEDDECIMAL_MULTIPLIER; + + if (arg2 == 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(); + } + + /* No overflow is possible */ + PG_RETURN_FLOAT8((float8) arg1 / arg2); +} + +Datum +fixeddecimalint2pl(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + int64 adder = PG_GETARG_INT16(1) * FIXEDDECIMAL_MULTIPLIER; + int64 result; + +#ifdef HAVE_BUILTIN_OVERFLOW + if (__builtin_add_overflow(arg1, adder, &result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#else + result = arg1 + adder; + + /* + * Overflow check. If the inputs are of different signs then their sum + * cannot overflow. If the inputs are of the same sign, their sum had + * better be that sign too. + */ + if (SAMESIGN(arg1, adder) && !SAMESIGN(result, arg1)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#endif /* HAVE_BUILTIN_OVERFLOW */ + + PG_RETURN_INT64(result); +} + +Datum +fixeddecimalint2mi(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + int64 subtractor = PG_GETARG_INT16(1) * FIXEDDECIMAL_MULTIPLIER; + int64 result; + +#ifdef HAVE_BUILTIN_OVERFLOW + if (__builtin_sub_overflow(arg1, subtractor, &result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#else + result = arg1 - subtractor; + + /* + * Overflow check. If the inputs are of the same sign then their + * difference cannot overflow. If they are of different signs then the + * result should be of the same sign as the first input. + */ + if (!SAMESIGN(arg1, subtractor) && !SAMESIGN(result, arg1)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#endif /* HAVE_BUILTIN_OVERFLOW */ + + PG_RETURN_INT64(result); +} + +Datum +fixeddecimalint2mul(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + int16 arg2 = PG_GETARG_INT16(1); + int64 result; + +#ifdef HAVE_BUILTIN_OVERFLOW + if (__builtin_mul_overflow(arg1, arg2, &result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#else + result = arg1 * arg2; + + /* + * Overflow check. We basically check to see if result / arg1 gives arg2 + * again. There is one case where this fails: arg1 = 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 + * the buck seems to be to check whether both inputs are in the int32 + * range; if so, no overflow is possible. + */ + if (arg1 != (int64) ((int32) arg1) && + result / arg1 != arg2) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#endif /* HAVE_BUILTIN_OVERFLOW */ + + PG_RETURN_INT64(result); +} + +Datum +fixeddecimalint2div(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + int16 arg2 = PG_GETARG_INT16(1); + int64 result; + + if (arg2 == 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(); + } + + /* + * INT64_MIN / -1 is problematic, since the result can't be represented on + * a two's-complement machine. Some machines produce INT64_MIN, some + * produce zero, some throw an exception. We can dodge the problem by + * recognizing that division by -1 is the same as negation. + */ + if (arg2 == -1) + { +#ifdef HAVE_BUILTIN_OVERFLOW + int64 zero = 0; + if (__builtin_sub_overflow(zero, arg1, &result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#else + result = -arg1; + /* overflow check (needed for INT64_MIN) */ + if (arg1 != 0 && SAMESIGN(result, arg1)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#endif /* HAVE_BUILTIN_OVERFLOW */ + + PG_RETURN_INT64(result); + } + + /* No overflow is possible */ + result = arg1 / arg2; + + PG_RETURN_INT64(result); +} + +Datum +int2fixeddecimalpl(PG_FUNCTION_ARGS) +{ + int64 adder = PG_GETARG_INT16(0) * FIXEDDECIMAL_MULTIPLIER; + int64 arg2 = PG_GETARG_INT64(1); + int64 result; + +#ifdef HAVE_BUILTIN_OVERFLOW + if (__builtin_add_overflow(adder, arg2, &result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#else + result = adder + arg2; + + /* + * Overflow check. If the inputs are of different signs then their sum + * cannot overflow. If the inputs are of the same sign, their sum had + * better be that sign too. + */ + if (SAMESIGN(adder, arg2) && !SAMESIGN(result, adder)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#endif /* HAVE_BUILTIN_OVERFLOW */ + + PG_RETURN_INT64(result); +} + +Datum +int2fixeddecimalmi(PG_FUNCTION_ARGS) +{ + int64 subtractor = PG_GETARG_INT16(0) * FIXEDDECIMAL_MULTIPLIER; + int64 arg2 = PG_GETARG_INT64(1); + int64 result; + +#ifdef HAVE_BUILTIN_OVERFLOW + if (__builtin_sub_overflow(subtractor, arg2, &result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#else + result = subtractor - arg2; + + /* + * Overflow check. If the inputs are of the same sign then their + * difference cannot overflow. If they are of different signs then the + * result should be of the same sign as the first input. + */ + if (!SAMESIGN(subtractor, arg2) && !SAMESIGN(result, subtractor)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#endif /* HAVE_BUILTIN_OVERFLOW */ + + PG_RETURN_INT64(result); +} + +Datum +int2fixeddecimalmul(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT16(0); + int64 arg2 = PG_GETARG_INT64(1); + int64 result; + +#ifdef HAVE_BUILTIN_OVERFLOW + if (__builtin_mul_overflow(multiplier, arg2, &result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#else + 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). + * + * Since the division is likely much more expensive than the actual + * multiplication, we'd like to skip it where possible. The best bang for + * the buck seems to be to check whether both inputs are in the int32 + * range; if so, no overflow is possible. + */ + if (arg2 != (int64) ((int32) arg2) && + result / arg2 != arg1) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#endif /* HAVE_BUILTIN_OVERFLOW */ + + PG_RETURN_INT64(result); +} + +Datum +int2fixeddecimaldiv(PG_FUNCTION_ARGS) +{ + int16 arg1 = PG_GETARG_INT16(0); + float8 arg2 = PG_GETARG_INT64(1) / (float8) FIXEDDECIMAL_MULTIPLIER; + + if (arg2 == 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(); + } + + /* No overflow is possible */ + PG_RETURN_FLOAT8((float8) arg1 / arg2); +} + +/*---------------------------------------------------------- + * Conversion operators. + *---------------------------------------------------------*/ + +/* + * fixeddecimal serves as casting function for fixeddecimal to fixeddecimal. + * The only serves to generate an error if the fixedecimal is too big for the + * specified typmod. + */ +Datum +fixeddecimal(PG_FUNCTION_ARGS) +{ + int64 num = PG_GETARG_INT64(0); + int32 typmod = PG_GETARG_INT32(1); + Datum result; + + /* no need to check typmod if it's -1 */ + if (typmod != -1) + { + result = DirectFunctionCall1(fixeddecimalout, num); + result = DirectFunctionCall3(fixeddecimalin, result, 0, typmod); + } + PG_RETURN_INT64(num); +} + +Datum +int8fixeddecimal(PG_FUNCTION_ARGS) +{ + int64 arg = PG_GETARG_INT64(0); + + PG_RETURN_INT64(arg * FIXEDDECIMAL_MULTIPLIER); +} + +Datum +fixeddecimalint8(PG_FUNCTION_ARGS) +{ + int64 arg = PG_GETARG_INT64(0) / FIXEDDECIMAL_MULTIPLIER; + + if ((int64) arg != arg) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("integer out of range"))); + + PG_RETURN_INT64((int64) arg); +} + +Datum +int4fixeddecimal(PG_FUNCTION_ARGS) +{ + int64 arg = PG_GETARG_INT32(0); + + PG_RETURN_INT64(arg * FIXEDDECIMAL_MULTIPLIER); +} + +Datum +fixeddecimalint4(PG_FUNCTION_ARGS) +{ + int64 arg = PG_GETARG_INT64(0) / FIXEDDECIMAL_MULTIPLIER; + + if ((int32) arg != arg) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("integer out of range"))); + + PG_RETURN_INT32((int32) arg); +} + +Datum +int2fixeddecimal(PG_FUNCTION_ARGS) +{ + int64 arg = PG_GETARG_INT16(0); + + PG_RETURN_INT64(arg * FIXEDDECIMAL_MULTIPLIER); +} + +Datum +fixeddecimalint2(PG_FUNCTION_ARGS) +{ + int64 arg = PG_GETARG_INT64(0) / FIXEDDECIMAL_MULTIPLIER; + + if ((int16) arg != arg) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("smallint out of range"))); + + PG_RETURN_INT16((int16) arg); +} + +Datum +fixeddecimaltod(PG_FUNCTION_ARGS) +{ + int64 arg = PG_GETARG_INT64(0); + float8 result; + + result = (float8) arg / FIXEDDECIMAL_MULTIPLIER; + + PG_RETURN_FLOAT8(result); +} + +/* dtofixeddecimal() + * Convert float8 to fixeddecimal + */ +Datum +dtofixeddecimal(PG_FUNCTION_ARGS) +{ + float8 arg = PG_GETARG_FLOAT8(0) * FIXEDDECIMAL_MULTIPLIER; + int64 result; + + /* Round arg to nearest integer (but it's still in float form) */ + arg = rint(arg); + + /* + * Does it fit in an int64? Avoid assuming that we have handy constants + * defined for the range boundaries, instead test for overflow by + * reverse-conversion. + */ + result = (int64) arg; + + if ((float8) result != arg) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); + + PG_RETURN_INT64(result); +} + +Datum +fixeddecimaltof(PG_FUNCTION_ARGS) +{ + int64 arg = PG_GETARG_INT64(0); + float4 result; + + result = (float4) arg / FIXEDDECIMAL_MULTIPLIER; + + PG_RETURN_FLOAT4(result); +} + +/* ftofixeddecimal() + * Convert float4 to fixeddecimal. + */ +Datum +ftofixeddecimal(PG_FUNCTION_ARGS) +{ + float4 arg = PG_GETARG_FLOAT4(0) * FIXEDDECIMAL_MULTIPLIER; + int64 result; + float8 darg; + + /* Round arg to nearest integer (but it's still in float form) */ + darg = rint(arg); + + /* + * Does it fit in an int64? Avoid assuming that we have handy constants + * defined for the range boundaries, instead test for overflow by + * reverse-conversion. + */ + result = (int64) darg; + + if ((float8) result != darg) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); + + PG_RETURN_INT64(result); +} + + +Datum +fixeddecimal_numeric(PG_FUNCTION_ARGS) +{ + int64 num = PG_GETARG_INT64(0); + char *tmp; + Datum result; + + tmp = DatumGetCString(DirectFunctionCall1(fixeddecimalout, + Int64GetDatum(num))); + + result = DirectFunctionCall3(numeric_in, CStringGetDatum(tmp), 0, -1); + + pfree(tmp); + + PG_RETURN_DATUM(result); +} + +Datum +numeric_fixeddecimal(PG_FUNCTION_ARGS) +{ + Numeric num = PG_GETARG_NUMERIC(0); + char *tmp; + Datum result; + + if (numeric_is_nan(num)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot convert NaN to fixeddecimal"))); + + tmp = DatumGetCString(DirectFunctionCall1(numeric_out, + NumericGetDatum(num))); + + result = DirectFunctionCall3(fixeddecimalin, CStringGetDatum(tmp), 0, -1); + + pfree(tmp); + + PG_RETURN_DATUM(result); +} + + +/* Aggregate Support */ + +static FixedDecimalAggState * +makeFixedDecimalAggState(FunctionCallInfo fcinfo) +{ + FixedDecimalAggState *state; + 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); + + state = (FixedDecimalAggState *) palloc0(sizeof(FixedDecimalAggState)); + state->agg_context = agg_context; + + MemoryContextSwitchTo(old_context); + + return state; +} + +/* + * Accumulate a new input value for fixeddecimal aggregate functions. + */ +static void +fixeddecimal_accum(FixedDecimalAggState *state, int64 newval) +{ +#ifdef HAVE_BUILTIN_OVERFLOW + if (__builtin_add_overflow(state->sumX, newval, &state->sumX)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); + state->N++; +#else + if (state->N++ > 0) + { + int64 result = state->sumX + newval; + + if (SAMESIGN(state->sumX, newval) && !SAMESIGN(result, state->sumX)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); + + state->sumX = result; + } + else + state->sumX = newval; +#endif /* HAVE_BUILTIN_OVERFLOW */ +} + +Datum +fixeddecimal_avg_accum(PG_FUNCTION_ARGS) +{ + FixedDecimalAggState *state; + + state = PG_ARGISNULL(0) ? NULL : (FixedDecimalAggState *) PG_GETARG_POINTER(0); + + /* Create the state data on the first call */ + if (state == NULL) + state = makeFixedDecimalAggState(fcinfo); + + if (!PG_ARGISNULL(1)) + fixeddecimal_accum(state, PG_GETARG_INT64(1)); + + PG_RETURN_POINTER(state); +} + +Datum +fixeddecimal_avg(PG_FUNCTION_ARGS) +{ + FixedDecimalAggState *state; + + state = PG_ARGISNULL(0) ? NULL : (FixedDecimalAggState *) PG_GETARG_POINTER(0); + + /* If there were no non-null inputs, return NULL */ + if (state == NULL || state->N == 0) + PG_RETURN_NULL(); + + PG_RETURN_INT64(state->sumX / state->N); +} + + +Datum +fixeddecimal_sum(PG_FUNCTION_ARGS) +{ + FixedDecimalAggState *state; + + state = PG_ARGISNULL(0) ? NULL : (FixedDecimalAggState *) PG_GETARG_POINTER(0); + + /* If there were no non-null inputs, return NULL */ + if (state == NULL || state->N == 0) + PG_RETURN_NULL(); + + PG_RETURN_INT64(state->sumX); +} + + +/* + * Input / Output / Send / Receive functions for aggrgate states + * Currently for XL only + */ + +Datum +fixeddecimalaggstatein(PG_FUNCTION_ARGS) +{ + char *str = pstrdup(PG_GETARG_CSTRING(0)); + FixedDecimalAggState *state; + char *token; + + state = (FixedDecimalAggState *) palloc(sizeof(FixedDecimalAggState)); + + token = strtok(str, ":"); + state->sumX = DatumGetInt64(DirectFunctionCall3(fixeddecimalin, CStringGetDatum(token), 0, -1)); + token = strtok(NULL, ":"); + state->N = DatumGetInt64(DirectFunctionCall1(int8in, CStringGetDatum(token))); + pfree(str); + + PG_RETURN_POINTER(state); +} + + +/* + * fixeddecimalaggstateout() + */ +Datum +fixeddecimalaggstateout(PG_FUNCTION_ARGS) +{ + FixedDecimalAggState *state = (FixedDecimalAggState *) PG_GETARG_POINTER(0); + char buf[MAXINT8LEN + 1 + MAXINT8LEN + 1]; + char *p; + + p = fixeddecimal2str(state->sumX, buf); + *p++ = ':'; + p = pg_int64tostr(p, state->N); + + PG_RETURN_CSTRING(pnstrdup(buf, p - buf)); +} + +/* + * fixeddecimalaggstaterecv + */ +Datum +fixeddecimalaggstaterecv(PG_FUNCTION_ARGS) +{ + StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); + FixedDecimalAggState *state; + state = (FixedDecimalAggState *) palloc(sizeof(FixedDecimalAggState)); + + state->sumX = pq_getmsgint(buf, sizeof(int64)); + state->N = pq_getmsgint(buf, sizeof(int64)); + + PG_RETURN_POINTER(state); +} + +/* + * fixeddecimalaggstatesend + */ +Datum +fixeddecimalaggstatesend(PG_FUNCTION_ARGS) +{ + 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)); + + PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); +} + +Datum +fixeddecimalaggstateserialize(PG_FUNCTION_ARGS) +{ + FixedDecimalAggState *state; + StringInfoData buf; + bytea *result; + + /* Ensure we disallow calling when not in aggregate context */ + if (!AggCheckCallContext(fcinfo, NULL)) + elog(ERROR, "aggregate function called in non-aggregate context"); + + state = (FixedDecimalAggState *) PG_GETARG_POINTER(0); + + pq_begintypsend(&buf); + + /* N */ + pq_sendint64(&buf, state->N); + + /* sumX */ + pq_sendint64(&buf, state->sumX); + + result = pq_endtypsend(&buf); + + PG_RETURN_BYTEA_P(result); +} + +Datum +fixeddecimalaggstatedeserialize(PG_FUNCTION_ARGS) +{ + bytea *sstate; + FixedDecimalAggState *result; + StringInfoData buf; + + if (!AggCheckCallContext(fcinfo, NULL)) + elog(ERROR, "aggregate function called in non-aggregate context"); + + sstate = PG_GETARG_BYTEA_P(0); + + /* + * Copy the bytea into a StringInfo so that we can "receive" it using the + * standard recv-function infrastructure. + */ + initStringInfo(&buf); + appendBinaryStringInfo(&buf, VARDATA(sstate), VARSIZE(sstate) - VARHDRSZ); + + result = (FixedDecimalAggState *) palloc(sizeof(FixedDecimalAggState)); + + /* N */ + result->N = pq_getmsgint64(&buf); + + /* sumX */ + result->sumX = pq_getmsgint64(&buf); + + pq_getmsgend(&buf); + pfree(buf.data); + + PG_RETURN_POINTER(result); +} + + +Datum +fixeddecimalaggstatecombine(PG_FUNCTION_ARGS) +{ + FixedDecimalAggState *collectstate; + FixedDecimalAggState *transstate; + 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); + + collectstate = PG_ARGISNULL(0) ? NULL : (FixedDecimalAggState *) + PG_GETARG_POINTER(0); + + if (collectstate == NULL) + { + collectstate = (FixedDecimalAggState *) palloc(sizeof + (FixedDecimalAggState)); + collectstate->sumX = 0; + collectstate->N = 0; + } + + transstate = PG_ARGISNULL(1) ? NULL : (FixedDecimalAggState *) + PG_GETARG_POINTER(1); + + if (transstate == NULL) + PG_RETURN_POINTER(collectstate); + + collectstate->sumX = DatumGetInt64(DirectFunctionCall2(fixeddecimalpl, + Int64GetDatum(collectstate->sumX), Int64GetDatum(transstate->sumX))); + collectstate->N = DatumGetInt64(DirectFunctionCall2(int8pl, + Int64GetDatum(collectstate->N), Int64GetDatum(transstate->N))); + + MemoryContextSwitchTo(old_context); + + PG_RETURN_POINTER(collectstate); +} + + +/* + * Function to support implicit casting from Char/Varchar/Text to fixeddecimal + */ +Datum +char_to_fixeddecimal(PG_FUNCTION_ARGS) +{ + char *str = TextDatumGetCString(PG_GETARG_DATUM(0)); + int precision; + int scale; + int64 result = scanfixeddecimal(str, &precision, &scale); + + PG_RETURN_INT64(result); +} diff --git a/contrib/babelfishpg_money/fixeddecimalaggstate.sql b/contrib/babelfishpg_money/fixeddecimalaggstate.sql new file mode 100644 index 00000000000..564f50ab7c2 --- /dev/null +++ b/contrib/babelfishpg_money/fixeddecimalaggstate.sql @@ -0,0 +1,41 @@ +-------------------------- +-- FIXEDDECIMALAGGSTATE -- +------------------------- + +CREATE TYPE FIXEDDECIMALAGGSTATE; + +CREATE FUNCTION fixeddecimalaggstatein(cstring, oid, int4) +RETURNS FIXEDDECIMALAGGSTATE +AS 'babelfishpg_money', 'fixeddecimalaggstatein' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalaggstateout(fixeddecimalaggstate) +RETURNS cstring +AS 'babelfishpg_money', 'fixeddecimalaggstateout' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalaggstaterecv(internal) +RETURNS FIXEDDECIMALAGGSTATE +AS 'babelfishpg_money', 'fixeddecimalaggstaterecv' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalaggstatesend(FIXEDDECIMALAGGSTATE) +RETURNS bytea +AS 'babelfishpg_money', 'fixeddecimalaggstatesend' +LANGUAGE C IMMUTABLE STRICT; + + +CREATE TYPE FIXEDDECIMALAGGSTATE ( + INPUT = fixeddecimalaggstatein, + OUTPUT = fixeddecimalaggstateout, + RECEIVE = fixeddecimalaggstaterecv, + SEND = fixeddecimalaggstatesend, + INTERNALLENGTH = 8, + ALIGNMENT = 'double', + STORAGE = plain, + CATEGORY = 'N', + PREFERRED = false, + COLLATABLE = false, + PASSEDBYVALUE +); + diff --git a/contrib/babelfishpg_money/test/expected/aggregate.out b/contrib/babelfishpg_money/test/expected/aggregate.out new file mode 100755 index 00000000000..934c51b9b13 --- /dev/null +++ b/contrib/babelfishpg_money/test/expected/aggregate.out @@ -0,0 +1,33 @@ +CREATE TABLE fixed_decimal(a FIXEDDECIMAL NOT NULL); +INSERT INTO fixed_decimal VALUES('92233720368547758.07'),('0.01'),('-92233720368547758.08'),('-0.01'); +SELECT SUM(a) FROM fixed_decimal WHERE a > 0; +ERROR: fixeddecimal out of range +SELECT SUM(a) FROM fixed_decimal WHERE a < 0; +ERROR: fixeddecimal out of range +TRUNCATE TABLE fixed_decimal; +INSERT INTO fixed_decimal VALUES('11.11'),('22.22'),('33.33'); +SELECT SUM(a) FROM fixed_decimal; + sum +------- + 66.66 +(1 row) + +SELECT MAX(a) FROM fixed_decimal; + max +------- + 33.33 +(1 row) + +SELECT MIN(a) FROM fixed_decimal; + min +------- + 11.11 +(1 row) + +SELECT AVG(a) FROM fixed_decimal; + avg +------- + 22.22 +(1 row) + +DROP TABLE fixed_decimal; diff --git a/contrib/babelfishpg_money/test/expected/brin-xl.out b/contrib/babelfishpg_money/test/expected/brin-xl.out new file mode 100644 index 00000000000..a66f7cf515e --- /dev/null +++ b/contrib/babelfishpg_money/test/expected/brin-xl.out @@ -0,0 +1,23 @@ +-- Test BRIN indexes +SET enable_seqscan = off; +CREATE TABLE fixdec (d FIXEDDECIMAL, txt TEXT); +INSERT INTO fixdec SELECT s.i,REPEAT('0',64) FROM generate_series(1,10000) s(i); +CREATE INDEX fixdec_d_idx ON fixdec USING BRIN (d); +EXPLAIN (COSTS OFF) SELECT * FROM fixdec WHERE d > '9999'::FIXEDDECIMAL; + QUERY PLAN +--------------------------------------------------------- + Remote Subquery Scan on all (datanode_1,datanode_2) + -> Bitmap Heap Scan on fixdec + Recheck Cond: (d > '9999.00'::fixeddecimal) + -> Bitmap Index Scan on fixdec_d_idx + Index Cond: (d > '9999.00'::fixeddecimal) +(5 rows) + +SELECT * FROM fixdec WHERE d > '9999'::FIXEDDECIMAL; + d | txt +----------+------------------------------------------------------------------ + 10000.00 | 0000000000000000000000000000000000000000000000000000000000000000 +(1 row) + +DROP TABLE fixdec; +RESET enable_seqscan; diff --git a/contrib/babelfishpg_money/test/expected/brin.out b/contrib/babelfishpg_money/test/expected/brin.out new file mode 100644 index 00000000000..e3ecea1c12b --- /dev/null +++ b/contrib/babelfishpg_money/test/expected/brin.out @@ -0,0 +1,22 @@ +-- Test BRIN indexes +SET enable_seqscan = off; +CREATE TABLE fixdec (d FIXEDDECIMAL, txt TEXT); +INSERT INTO fixdec SELECT s.i,REPEAT('0',64) FROM generate_series(1,10000) s(i); +CREATE INDEX fixdec_d_idx ON fixdec USING BRIN (d); +EXPLAIN (COSTS OFF) SELECT * FROM fixdec WHERE d > '9999'::FIXEDDECIMAL; + QUERY PLAN +--------------------------------------------------- + Bitmap Heap Scan on fixdec + Recheck Cond: (d > '9999.00'::fixeddecimal) + -> Bitmap Index Scan on fixdec_d_idx + Index Cond: (d > '9999.00'::fixeddecimal) +(4 rows) + +SELECT * FROM fixdec WHERE d > '9999'::FIXEDDECIMAL; + d | txt +----------+------------------------------------------------------------------ + 10000.00 | 0000000000000000000000000000000000000000000000000000000000000000 +(1 row) + +DROP TABLE fixdec; +RESET enable_seqscan; diff --git a/contrib/babelfishpg_money/test/expected/cast.out b/contrib/babelfishpg_money/test/expected/cast.out new file mode 100755 index 00000000000..b230ed59787 --- /dev/null +++ b/contrib/babelfishpg_money/test/expected/cast.out @@ -0,0 +1,48 @@ +SELECT CAST('2147483647'::FIXEDDECIMAL AS INT); + int4 +------------ + 2147483647 +(1 row) + +-- Ensure overflow is detected +SELECT CAST('2147483648'::FIXEDDECIMAL AS INT); +ERROR: integer out of range +SELECT CAST('-2147483648'::FIXEDDECIMAL AS INT); + int4 +------------- + -2147483648 +(1 row) + +-- Ensure underflow is detected +SELECT CAST('-2147483649'::FIXEDDECIMAL AS INT); +ERROR: integer out of range +SELECT CAST('32767'::FIXEDDECIMAL AS SMALLINT); + int2 +------- + 32767 +(1 row) + +-- Ensure overflow is detected +SELECT CAST('32768'::FIXEDDECIMAL AS SMALLINT); +ERROR: smallint out of range +SELECT CAST('-32768'::FIXEDDECIMAL AS SMALLINT); + int2 +-------- + -32768 +(1 row) + +-- Ensure underflow is detected +SELECT CAST('-32769'::FIXEDDECIMAL AS SMALLINT); +ERROR: smallint out of range +SELECT CAST('1234321.23'::FIXEDDECIMAL AS FLOAT); + float8 +------------ + 1234321.23 +(1 row) + +SELECT CAST('1234321.23'::FIXEDDECIMAL AS DOUBLE PRECISION); + float8 +------------ + 1234321.23 +(1 row) + diff --git a/contrib/babelfishpg_money/test/expected/comparison.out b/contrib/babelfishpg_money/test/expected/comparison.out new file mode 100755 index 00000000000..9ba9abe9ae5 --- /dev/null +++ b/contrib/babelfishpg_money/test/expected/comparison.out @@ -0,0 +1,310 @@ +-- True comparisons +SELECT '123'::FIXEDDECIMAL < '123.01'::FIXEDDECIMAL; + ?column? +---------- + t +(1 row) + +SELECT '123'::FIXEDDECIMAL <= '123.01'::FIXEDDECIMAL; + ?column? +---------- + t +(1 row) + +SELECT '123'::FIXEDDECIMAL > '122.99'::FIXEDDECIMAL; + ?column? +---------- + t +(1 row) + +SELECT '123'::FIXEDDECIMAL >= '122.99'::FIXEDDECIMAL; + ?column? +---------- + t +(1 row) + +SELECT '123.00'::FIXEDDECIMAL = '123'::FIXEDDECIMAL; + ?column? +---------- + t +(1 row) + +-- Compare to int4 +SELECT '123'::INT < '123.01'::FIXEDDECIMAL; + ?column? +---------- + t +(1 row) + +SELECT '123'::INT <= '123.01'::FIXEDDECIMAL; + ?column? +---------- + t +(1 row) + +SELECT '123'::INT > '122.99'::FIXEDDECIMAL; + ?column? +---------- + t +(1 row) + +SELECT '123'::INT >= '122.99'::FIXEDDECIMAL; + ?column? +---------- + t +(1 row) + +SELECT '123'::INT = '123.00'::FIXEDDECIMAL; + ?column? +---------- + t +(1 row) + +-- Compare to int4 reversed +SELECT '123.01'::FIXEDDECIMAL > '123'::INT; + ?column? +---------- + t +(1 row) + +SELECT '123.01'::FIXEDDECIMAL >= '123'::INT; + ?column? +---------- + t +(1 row) + +SELECT '122.99'::FIXEDDECIMAL < '123'::INT; + ?column? +---------- + t +(1 row) + +SELECT '122.99'::FIXEDDECIMAL <= '123'::INT; + ?column? +---------- + t +(1 row) + +SELECT '123.00'::FIXEDDECIMAL = '123'::INT; + ?column? +---------- + t +(1 row) + +-- Compare to int2 +SELECT '123'::SMALLINT < '123.01'::FIXEDDECIMAL; + ?column? +---------- + t +(1 row) + +SELECT '123'::SMALLINT <= '123.01'::FIXEDDECIMAL; + ?column? +---------- + t +(1 row) + +SELECT '123'::SMALLINT > '122.99'::FIXEDDECIMAL; + ?column? +---------- + t +(1 row) + +SELECT '123'::SMALLINT >= '122.99'::FIXEDDECIMAL; + ?column? +---------- + t +(1 row) + +SELECT '123'::SMALLINT = '123.00'::FIXEDDECIMAL; + ?column? +---------- + t +(1 row) + +-- Compare to int4 reversed +SELECT '123.01'::FIXEDDECIMAL > '123'::SMALLINT; + ?column? +---------- + t +(1 row) + +SELECT '123.01'::FIXEDDECIMAL >= '123'::SMALLINT; + ?column? +---------- + t +(1 row) + +SELECT '122.99'::FIXEDDECIMAL < '123'::SMALLINT; + ?column? +---------- + t +(1 row) + +SELECT '122.99'::FIXEDDECIMAL <= '123'::SMALLINT; + ?column? +---------- + t +(1 row) + +SELECT '123.00'::FIXEDDECIMAL = '123'::SMALLINT; + ?column? +---------- + t +(1 row) + +-- False comparisons +SELECT '123'::FIXEDDECIMAL >= '123.01'::FIXEDDECIMAL; + ?column? +---------- + f +(1 row) + +SELECT '123'::FIXEDDECIMAL > '123.01'::FIXEDDECIMAL; + ?column? +---------- + f +(1 row) + +SELECT '123'::FIXEDDECIMAL <= '122.99'::FIXEDDECIMAL; + ?column? +---------- + f +(1 row) + +SELECT '123'::FIXEDDECIMAL < '122.99'::FIXEDDECIMAL; + ?column? +---------- + f +(1 row) + +SELECT '123.00'::FIXEDDECIMAL <> '123'::FIXEDDECIMAL; + ?column? +---------- + f +(1 row) + +-- Compare to int4 +SELECT '123'::INT >= '123.01'::FIXEDDECIMAL; + ?column? +---------- + f +(1 row) + +SELECT '123'::INT > '123.01'::FIXEDDECIMAL; + ?column? +---------- + f +(1 row) + +SELECT '123'::INT <= '122.99'::FIXEDDECIMAL; + ?column? +---------- + f +(1 row) + +SELECT '123'::INT < '122.99'::FIXEDDECIMAL; + ?column? +---------- + f +(1 row) + +SELECT '123'::INT <> '123.00'::FIXEDDECIMAL; + ?column? +---------- + f +(1 row) + +-- Compare to int4 reversed +SELECT '123.01'::FIXEDDECIMAL <= '123'::INT; + ?column? +---------- + f +(1 row) + +SELECT '123.01'::FIXEDDECIMAL < '123'::INT; + ?column? +---------- + f +(1 row) + +SELECT '122.99'::FIXEDDECIMAL >= '123'::INT; + ?column? +---------- + f +(1 row) + +SELECT '122.99'::FIXEDDECIMAL > '123'::INT; + ?column? +---------- + f +(1 row) + +SELECT '123.00'::FIXEDDECIMAL <> '123'::INT; + ?column? +---------- + f +(1 row) + +-- Compare to int2 +SELECT '123'::SMALLINT >= '123.01'::FIXEDDECIMAL; + ?column? +---------- + f +(1 row) + +SELECT '123'::SMALLINT > '123.01'::FIXEDDECIMAL; + ?column? +---------- + f +(1 row) + +SELECT '123'::SMALLINT <= '122.99'::FIXEDDECIMAL; + ?column? +---------- + f +(1 row) + +SELECT '123'::SMALLINT < '122.99'::FIXEDDECIMAL; + ?column? +---------- + f +(1 row) + +SELECT '123'::SMALLINT <> '123.00'::FIXEDDECIMAL; + ?column? +---------- + f +(1 row) + +-- Compare to int4 reversed +SELECT '123.01'::FIXEDDECIMAL <= '123'::SMALLINT; + ?column? +---------- + f +(1 row) + +SELECT '123.01'::FIXEDDECIMAL < '123'::SMALLINT; + ?column? +---------- + f +(1 row) + +SELECT '122.99'::FIXEDDECIMAL >= '123'::SMALLINT; + ?column? +---------- + f +(1 row) + +SELECT '122.99'::FIXEDDECIMAL > '123'::SMALLINT; + ?column? +---------- + f +(1 row) + +SELECT '123.00'::FIXEDDECIMAL <> '123'::SMALLINT; + ?column? +---------- + f +(1 row) + diff --git a/contrib/babelfishpg_money/test/expected/index-xl.out b/contrib/babelfishpg_money/test/expected/index-xl.out new file mode 100644 index 00000000000..43c34566432 --- /dev/null +++ b/contrib/babelfishpg_money/test/expected/index-xl.out @@ -0,0 +1,95 @@ +CREATE TABLE fixdec (id INT, d FIXEDDECIMAL(5,2)); +INSERT INTO fixdec (id,d) VALUES(1,-123.45); +INSERT INTO fixdec (id,d) VALUES(2,-123); +INSERT INTO fixdec (id,d) VALUES(3,-12.34); +INSERT INTO fixdec (id,d) VALUES(4,-1.34); +INSERT INTO fixdec (id,d) VALUES(5, 0.12); +INSERT INTO fixdec (id,d) VALUES(6, 1.23); +INSERT INTO fixdec (id,d) VALUES(7, 12.34); +INSERT INTO fixdec (id,d) VALUES(8, 123.45); +INSERT INTO fixdec (id,d) VALUES(9, 123.456); +CREATE INDEX fixdec_d_idx ON fixdec (d); +DELETE FROM fixdec WHERE id = 9; +SET enable_seqscan = off; +EXPLAIN (COSTS OFF) SELECT * FROM fixdec ORDER BY d; + QUERY PLAN +----------------------------------------------------- + Remote Subquery Scan on all (datanode_1,datanode_2) + -> Index Scan using fixdec_d_idx on fixdec +(2 rows) + +SELECT * FROM fixdec ORDER BY d; + id | d +----+--------- + 1 | -123.45 + 2 | -123.00 + 3 | -12.34 + 4 | -1.34 + 5 | 0.12 + 6 | 1.23 + 7 | 12.34 + 8 | 123.45 +(8 rows) + +EXPLAIN (COSTS OFF) SELECT * FROM fixdec WHERE d = '12.34'::FIXEDDECIMAL; + QUERY PLAN +------------------------------------------------------- + Remote Subquery Scan on all (datanode_1,datanode_2) + -> Bitmap Heap Scan on fixdec + Recheck Cond: (d = '12.34'::fixeddecimal) + -> Bitmap Index Scan on fixdec_d_idx + Index Cond: (d = '12.34'::fixeddecimal) +(5 rows) + +SELECT * FROM fixdec WHERE d = '12.34'::FIXEDDECIMAL; + id | d +----+------- + 7 | 12.34 +(1 row) + +SELECT * FROM fixdec WHERE d = '-12.34'::FIXEDDECIMAL; + id | d +----+-------- + 3 | -12.34 +(1 row) + +SELECT * FROM fixdec WHERE d = '123.45'::FIXEDDECIMAL; + id | d +----+-------- + 8 | 123.45 +(1 row) + +DROP INDEX fixdec_d_idx; +SET client_min_messages = ERROR; +CREATE INDEX fixdec_d_idx ON fixdec USING hash (d); +RESET client_min_messages; +EXPLAIN (COSTS OFF) SELECT * FROM fixdec WHERE d = '12.34'::FIXEDDECIMAL; + QUERY PLAN +------------------------------------------------------- + Remote Subquery Scan on all (datanode_1,datanode_2) + -> Bitmap Heap Scan on fixdec + Recheck Cond: (d = '12.34'::fixeddecimal) + -> Bitmap Index Scan on fixdec_d_idx + Index Cond: (d = '12.34'::fixeddecimal) +(5 rows) + +SELECT * FROM fixdec WHERE d = '12.34'::FIXEDDECIMAL; + id | d +----+------- + 7 | 12.34 +(1 row) + +SELECT * FROM fixdec WHERE d = '-12.34'::FIXEDDECIMAL; + id | d +----+-------- + 3 | -12.34 +(1 row) + +SELECT * FROM fixdec WHERE d = '123.45'::FIXEDDECIMAL; + id | d +----+-------- + 8 | 123.45 +(1 row) + +DROP TABLE fixdec; +SET enable_seqscan = on; diff --git a/contrib/babelfishpg_money/test/expected/index.out b/contrib/babelfishpg_money/test/expected/index.out new file mode 100644 index 00000000000..f02aaf91065 --- /dev/null +++ b/contrib/babelfishpg_money/test/expected/index.out @@ -0,0 +1,92 @@ +CREATE TABLE fixdec (id INT, d FIXEDDECIMAL(5,2)); +INSERT INTO fixdec (id,d) VALUES(1,-123.45); +INSERT INTO fixdec (id,d) VALUES(2,-123); +INSERT INTO fixdec (id,d) VALUES(3,-12.34); +INSERT INTO fixdec (id,d) VALUES(4,-1.34); +INSERT INTO fixdec (id,d) VALUES(5, 0.12); +INSERT INTO fixdec (id,d) VALUES(6, 1.23); +INSERT INTO fixdec (id,d) VALUES(7, 12.34); +INSERT INTO fixdec (id,d) VALUES(8, 123.45); +INSERT INTO fixdec (id,d) VALUES(9, 123.456); +-- Should fail +CREATE UNIQUE INDEX fixdec_d_idx ON fixdec (d); +ERROR: could not create unique index "fixdec_d_idx" +DETAIL: Key (d)=(123.45) is duplicated. +DELETE FROM fixdec WHERE id = 9; +CREATE UNIQUE INDEX fixdec_d_idx ON fixdec (d); +SET enable_seqscan = off; +EXPLAIN (COSTS OFF) SELECT * FROM fixdec ORDER BY d; + QUERY PLAN +----------------------------------------- + Index Scan using fixdec_d_idx on fixdec +(1 row) + +SELECT * FROM fixdec ORDER BY d; + id | d +----+--------- + 1 | -123.45 + 2 | -123.00 + 3 | -12.34 + 4 | -1.34 + 5 | 0.12 + 6 | 1.23 + 7 | 12.34 + 8 | 123.45 +(8 rows) + +EXPLAIN (COSTS OFF) SELECT * FROM fixdec WHERE d = '12.34'::FIXEDDECIMAL; + QUERY PLAN +------------------------------------------- + Index Scan using fixdec_d_idx on fixdec + Index Cond: (d = '12.34'::fixeddecimal) +(2 rows) + +SELECT * FROM fixdec WHERE d = '12.34'::FIXEDDECIMAL; + id | d +----+------- + 7 | 12.34 +(1 row) + +SELECT * FROM fixdec WHERE d = '-12.34'::FIXEDDECIMAL; + id | d +----+-------- + 3 | -12.34 +(1 row) + +SELECT * FROM fixdec WHERE d = '123.45'::FIXEDDECIMAL; + id | d +----+-------- + 8 | 123.45 +(1 row) + +DROP INDEX fixdec_d_idx; +SET client_min_messages = ERROR; +CREATE INDEX fixdec_d_idx ON fixdec USING hash (d); +RESET client_min_messages; +EXPLAIN (COSTS OFF) SELECT * FROM fixdec WHERE d = '12.34'::FIXEDDECIMAL; + QUERY PLAN +------------------------------------------- + Index Scan using fixdec_d_idx on fixdec + Index Cond: (d = '12.34'::fixeddecimal) +(2 rows) + +SELECT * FROM fixdec WHERE d = '12.34'::FIXEDDECIMAL; + id | d +----+------- + 7 | 12.34 +(1 row) + +SELECT * FROM fixdec WHERE d = '-12.34'::FIXEDDECIMAL; + id | d +----+-------- + 3 | -12.34 +(1 row) + +SELECT * FROM fixdec WHERE d = '123.45'::FIXEDDECIMAL; + id | d +----+-------- + 8 | 123.45 +(1 row) + +DROP TABLE fixdec; +SET enable_seqscan = on; diff --git a/contrib/babelfishpg_money/test/expected/overflow.out b/contrib/babelfishpg_money/test/expected/overflow.out new file mode 100755 index 00000000000..ee0010080d4 --- /dev/null +++ b/contrib/babelfishpg_money/test/expected/overflow.out @@ -0,0 +1,123 @@ +-- Ensure the expected extreme values can be represented +SELECT '-92233720368547758.08'::FIXEDDECIMAL as minvalue,'92233720368547758.07'::FIXEDDECIMAL as maxvalue; + minvalue | maxvalue +-----------------------+---------------------- + -92233720368547758.08 | 92233720368547758.07 +(1 row) + +SELECT '-92233720368547758.09'::FIXEDDECIMAL; +ERROR: value "-92233720368547758.09" is out of range for type fixeddecimal +LINE 1: SELECT '-92233720368547758.09'::FIXEDDECIMAL; + ^ +SELECT '92233720368547758.08'::FIXEDDECIMAL; +ERROR: value "92233720368547758.08" is out of range for type fixeddecimal +LINE 1: SELECT '92233720368547758.08'::FIXEDDECIMAL; + ^ +-- Ensure casts from numeric to fixeddecimal work +SELECT '92233720368547758.07'::numeric::FIXEDDECIMAL; + fixeddecimal +---------------------- + 92233720368547758.07 +(1 row) + +-- The literal below must be quoted as the parser seems to read the literal as +-- a positive number first and then us the - unary operator to make it negaive. +-- This would overflow without the quotes as this number cannot be represented +-- in a positive fixeddecimal. +SELECT '-92233720368547758.08'::numeric::FIXEDDECIMAL; + fixeddecimal +----------------------- + -92233720368547758.08 +(1 row) + +-- Ensure casts from numeric to fixed decimal detect overflow +SELECT '92233720368547758.08'::numeric::FIXEDDECIMAL; +ERROR: value "92233720368547758.08" is out of range for type fixeddecimal +SELECT '-92233720368547758.09'::numeric::FIXEDDECIMAL; +ERROR: value "-92233720368547758.09" is out of range for type fixeddecimal +SELECT '-92233720368547758.08'::FIXEDDECIMAL - '0.01'::FIXEDDECIMAL; +ERROR: fixeddecimal out of range +SELECT '92233720368547758.07'::FIXEDDECIMAL + '0.01'::FIXEDDECIMAL; +ERROR: fixeddecimal out of range +-- Should not overflow +SELECT '46116860184273879.03'::FIXEDDECIMAL * '2.00'::FIXEDDECIMAL; + ?column? +---------------------- + 92233720368547758.06 +(1 row) + +-- Ensure this overflows +SELECT '46116860184273879.04'::FIXEDDECIMAL * '2.00'::FIXEDDECIMAL; +ERROR: fixeddecimal out of range +-- Should not overflow +SELECT '46116860184273879.03'::FIXEDDECIMAL / '0.50'::FIXEDDECIMAL; + ?column? +---------------------- + 92233720368547758.06 +(1 row) + +-- Ensure this overflows +SELECT '46116860184273879.04'::FIXEDDECIMAL / '0.50'::FIXEDDECIMAL; +ERROR: fixeddecimal out of range +-- Ensure limits of int2 can be represented +SELECT '32767'::FIXEDDECIMAL::INT2,'-32768'::FIXEDDECIMAL::INT2; + int2 | int2 +-------+-------- + 32767 | -32768 +(1 row) + +-- Ensure overflow of int2 is detected +SELECT '32768'::FIXEDDECIMAL::INT2; +ERROR: smallint out of range +-- Ensure underflow of int2 is detected +SELECT '-32769'::FIXEDDECIMAL::INT2; +ERROR: smallint out of range +-- Ensure limits of int4 can be represented +SELECT '2147483647'::FIXEDDECIMAL::INT4,'-2147483648'::FIXEDDECIMAL::INT4; + int4 | int4 +------------+------------- + 2147483647 | -2147483648 +(1 row) + +-- Ensure overflow of int4 is detected +SELECT '2147483648'::FIXEDDECIMAL::INT4; +ERROR: integer out of range +-- Ensure underflow of int4 is detected +SELECT '-2147483649'::FIXEDDECIMAL::INT4; +ERROR: integer out of range +-- Ensure overflow is detected +SELECT SUM(a) FROM (VALUES('92233720368547758.07'::FIXEDDECIMAL),('0.01'::FIXEDDECIMAL)) a(a); +ERROR: fixeddecimal out of range +-- Ensure underflow is detected +SELECT SUM(a) FROM (VALUES('-92233720368547758.08'::FIXEDDECIMAL),('-0.01'::FIXEDDECIMAL)) a(a); +ERROR: fixeddecimal out of range +-- Test typmods +SELECT 12345.33::FIXEDDECIMAL(3,2); -- Fail +ERROR: FIXEDDECIMAL field overflow +DETAIL: A field with precision 5, scale 2 must round to an absolute value less than 10^1. +SELECT 12345.33::FIXEDDECIMAL(5,2); -- Fail +ERROR: FIXEDDECIMAL field overflow +DETAIL: A field with precision 5, scale 2 must round to an absolute value less than 10^3. +-- scale of 2 should be enforced. +SELECT 12345.44::FIXEDDECIMAL(7,0); +ERROR: FIXEDDECIMAL scale must be 2 +LINE 1: SELECT 12345.44::FIXEDDECIMAL(7,0); + ^ +-- should work. +SELECT 12345.33::FIXEDDECIMAL(7,2); + fixeddecimal +-------------- + 12345.33 +(1 row) + +-- error, precision limit should be 17 +SELECT 12345.33::FIXEDDECIMAL(18,2); +ERROR: FIXEDDECIMAL precision 18 must be between 2 and 17 +LINE 1: SELECT 12345.33::FIXEDDECIMAL(18,2); + ^ +CREATE TABLE fixdec (d FIXEDDECIMAL(3,2)); +INSERT INTO fixdec VALUES(12.34); -- Fail +ERROR: FIXEDDECIMAL field overflow +DETAIL: A field with precision 2, scale 2 must round to an absolute value less than 10^1. +INSERT INTO fixdec VALUES(1.23); -- Pass +DROP TABLE fixdec; diff --git a/contrib/babelfishpg_money/test/sql/aggregate.sql b/contrib/babelfishpg_money/test/sql/aggregate.sql new file mode 100755 index 00000000000..6c00a7205aa --- /dev/null +++ b/contrib/babelfishpg_money/test/sql/aggregate.sql @@ -0,0 +1,21 @@ +CREATE TABLE fixed_decimal(a FIXEDDECIMAL NOT NULL); + +INSERT INTO fixed_decimal VALUES('92233720368547758.07'),('0.01'),('-92233720368547758.08'),('-0.01'); + +SELECT SUM(a) FROM fixed_decimal WHERE a > 0; + +SELECT SUM(a) FROM fixed_decimal WHERE a < 0; + +TRUNCATE TABLE fixed_decimal; + +INSERT INTO fixed_decimal VALUES('11.11'),('22.22'),('33.33'); + +SELECT SUM(a) FROM fixed_decimal; + +SELECT MAX(a) FROM fixed_decimal; + +SELECT MIN(a) FROM fixed_decimal; + +SELECT AVG(a) FROM fixed_decimal; + +DROP TABLE fixed_decimal; \ No newline at end of file diff --git a/contrib/babelfishpg_money/test/sql/brin-xl.sql b/contrib/babelfishpg_money/test/sql/brin-xl.sql new file mode 100644 index 00000000000..802328517d5 --- /dev/null +++ b/contrib/babelfishpg_money/test/sql/brin-xl.sql @@ -0,0 +1,14 @@ +-- Test BRIN indexes +SET enable_seqscan = off; +CREATE TABLE fixdec (d FIXEDDECIMAL, txt TEXT); +INSERT INTO fixdec SELECT s.i,REPEAT('0',64) FROM generate_series(1,10000) s(i); + +CREATE INDEX fixdec_d_idx ON fixdec USING BRIN (d); + +EXPLAIN (COSTS OFF) SELECT * FROM fixdec WHERE d > '9999'::FIXEDDECIMAL; + +SELECT * FROM fixdec WHERE d > '9999'::FIXEDDECIMAL; + +DROP TABLE fixdec; + +RESET enable_seqscan; diff --git a/contrib/babelfishpg_money/test/sql/brin.sql b/contrib/babelfishpg_money/test/sql/brin.sql new file mode 100644 index 00000000000..802328517d5 --- /dev/null +++ b/contrib/babelfishpg_money/test/sql/brin.sql @@ -0,0 +1,14 @@ +-- Test BRIN indexes +SET enable_seqscan = off; +CREATE TABLE fixdec (d FIXEDDECIMAL, txt TEXT); +INSERT INTO fixdec SELECT s.i,REPEAT('0',64) FROM generate_series(1,10000) s(i); + +CREATE INDEX fixdec_d_idx ON fixdec USING BRIN (d); + +EXPLAIN (COSTS OFF) SELECT * FROM fixdec WHERE d > '9999'::FIXEDDECIMAL; + +SELECT * FROM fixdec WHERE d > '9999'::FIXEDDECIMAL; + +DROP TABLE fixdec; + +RESET enable_seqscan; diff --git a/contrib/babelfishpg_money/test/sql/cast.sql b/contrib/babelfishpg_money/test/sql/cast.sql new file mode 100755 index 00000000000..3b7b1c8bbc6 --- /dev/null +++ b/contrib/babelfishpg_money/test/sql/cast.sql @@ -0,0 +1,23 @@ +SELECT CAST('2147483647'::FIXEDDECIMAL AS INT); + +-- Ensure overflow is detected +SELECT CAST('2147483648'::FIXEDDECIMAL AS INT); + +SELECT CAST('-2147483648'::FIXEDDECIMAL AS INT); + +-- Ensure underflow is detected +SELECT CAST('-2147483649'::FIXEDDECIMAL AS INT); + +SELECT CAST('32767'::FIXEDDECIMAL AS SMALLINT); + +-- Ensure overflow is detected +SELECT CAST('32768'::FIXEDDECIMAL AS SMALLINT); + +SELECT CAST('-32768'::FIXEDDECIMAL AS SMALLINT); + +-- Ensure underflow is detected +SELECT CAST('-32769'::FIXEDDECIMAL AS SMALLINT); + +SELECT CAST('1234321.23'::FIXEDDECIMAL AS FLOAT); + +SELECT CAST('1234321.23'::FIXEDDECIMAL AS DOUBLE PRECISION); \ No newline at end of file diff --git a/contrib/babelfishpg_money/test/sql/comparison.sql b/contrib/babelfishpg_money/test/sql/comparison.sql new file mode 100755 index 00000000000..ed3e6ad0c2f --- /dev/null +++ b/contrib/babelfishpg_money/test/sql/comparison.sql @@ -0,0 +1,118 @@ +-- True comparisons + +SELECT '123'::FIXEDDECIMAL < '123.01'::FIXEDDECIMAL; + +SELECT '123'::FIXEDDECIMAL <= '123.01'::FIXEDDECIMAL; + +SELECT '123'::FIXEDDECIMAL > '122.99'::FIXEDDECIMAL; + +SELECT '123'::FIXEDDECIMAL >= '122.99'::FIXEDDECIMAL; + +SELECT '123.00'::FIXEDDECIMAL = '123'::FIXEDDECIMAL; + +-- Compare to int4 + +SELECT '123'::INT < '123.01'::FIXEDDECIMAL; + +SELECT '123'::INT <= '123.01'::FIXEDDECIMAL; + +SELECT '123'::INT > '122.99'::FIXEDDECIMAL; + +SELECT '123'::INT >= '122.99'::FIXEDDECIMAL; + +SELECT '123'::INT = '123.00'::FIXEDDECIMAL; + +-- Compare to int4 reversed + +SELECT '123.01'::FIXEDDECIMAL > '123'::INT; + +SELECT '123.01'::FIXEDDECIMAL >= '123'::INT; + +SELECT '122.99'::FIXEDDECIMAL < '123'::INT; + +SELECT '122.99'::FIXEDDECIMAL <= '123'::INT; + +SELECT '123.00'::FIXEDDECIMAL = '123'::INT; + +-- Compare to int2 + +SELECT '123'::SMALLINT < '123.01'::FIXEDDECIMAL; + +SELECT '123'::SMALLINT <= '123.01'::FIXEDDECIMAL; + +SELECT '123'::SMALLINT > '122.99'::FIXEDDECIMAL; + +SELECT '123'::SMALLINT >= '122.99'::FIXEDDECIMAL; + +SELECT '123'::SMALLINT = '123.00'::FIXEDDECIMAL; + +-- Compare to int4 reversed + +SELECT '123.01'::FIXEDDECIMAL > '123'::SMALLINT; + +SELECT '123.01'::FIXEDDECIMAL >= '123'::SMALLINT; + +SELECT '122.99'::FIXEDDECIMAL < '123'::SMALLINT; + +SELECT '122.99'::FIXEDDECIMAL <= '123'::SMALLINT; + +SELECT '123.00'::FIXEDDECIMAL = '123'::SMALLINT; + +-- False comparisons +SELECT '123'::FIXEDDECIMAL >= '123.01'::FIXEDDECIMAL; + +SELECT '123'::FIXEDDECIMAL > '123.01'::FIXEDDECIMAL; + +SELECT '123'::FIXEDDECIMAL <= '122.99'::FIXEDDECIMAL; + +SELECT '123'::FIXEDDECIMAL < '122.99'::FIXEDDECIMAL; + +SELECT '123.00'::FIXEDDECIMAL <> '123'::FIXEDDECIMAL; + +-- Compare to int4 + +SELECT '123'::INT >= '123.01'::FIXEDDECIMAL; + +SELECT '123'::INT > '123.01'::FIXEDDECIMAL; + +SELECT '123'::INT <= '122.99'::FIXEDDECIMAL; + +SELECT '123'::INT < '122.99'::FIXEDDECIMAL; + +SELECT '123'::INT <> '123.00'::FIXEDDECIMAL; + +-- Compare to int4 reversed + +SELECT '123.01'::FIXEDDECIMAL <= '123'::INT; + +SELECT '123.01'::FIXEDDECIMAL < '123'::INT; + +SELECT '122.99'::FIXEDDECIMAL >= '123'::INT; + +SELECT '122.99'::FIXEDDECIMAL > '123'::INT; + +SELECT '123.00'::FIXEDDECIMAL <> '123'::INT; + +-- Compare to int2 + +SELECT '123'::SMALLINT >= '123.01'::FIXEDDECIMAL; + +SELECT '123'::SMALLINT > '123.01'::FIXEDDECIMAL; + +SELECT '123'::SMALLINT <= '122.99'::FIXEDDECIMAL; + +SELECT '123'::SMALLINT < '122.99'::FIXEDDECIMAL; + +SELECT '123'::SMALLINT <> '123.00'::FIXEDDECIMAL; + +-- Compare to int4 reversed + +SELECT '123.01'::FIXEDDECIMAL <= '123'::SMALLINT; + +SELECT '123.01'::FIXEDDECIMAL < '123'::SMALLINT; + +SELECT '122.99'::FIXEDDECIMAL >= '123'::SMALLINT; + +SELECT '122.99'::FIXEDDECIMAL > '123'::SMALLINT; + +SELECT '123.00'::FIXEDDECIMAL <> '123'::SMALLINT; diff --git a/contrib/babelfishpg_money/test/sql/index-xl.sql b/contrib/babelfishpg_money/test/sql/index-xl.sql new file mode 100644 index 00000000000..c963ba1f888 --- /dev/null +++ b/contrib/babelfishpg_money/test/sql/index-xl.sql @@ -0,0 +1,47 @@ +CREATE TABLE fixdec (id INT, d FIXEDDECIMAL(5,2)); + +INSERT INTO fixdec (id,d) VALUES(1,-123.45); +INSERT INTO fixdec (id,d) VALUES(2,-123); +INSERT INTO fixdec (id,d) VALUES(3,-12.34); +INSERT INTO fixdec (id,d) VALUES(4,-1.34); +INSERT INTO fixdec (id,d) VALUES(5, 0.12); +INSERT INTO fixdec (id,d) VALUES(6, 1.23); +INSERT INTO fixdec (id,d) VALUES(7, 12.34); +INSERT INTO fixdec (id,d) VALUES(8, 123.45); +INSERT INTO fixdec (id,d) VALUES(9, 123.456); + +CREATE INDEX fixdec_d_idx ON fixdec (d); + +DELETE FROM fixdec WHERE id = 9; + +SET enable_seqscan = off; + +EXPLAIN (COSTS OFF) SELECT * FROM fixdec ORDER BY d; + +SELECT * FROM fixdec ORDER BY d; + +EXPLAIN (COSTS OFF) SELECT * FROM fixdec WHERE d = '12.34'::FIXEDDECIMAL; + +SELECT * FROM fixdec WHERE d = '12.34'::FIXEDDECIMAL; + +SELECT * FROM fixdec WHERE d = '-12.34'::FIXEDDECIMAL; + +SELECT * FROM fixdec WHERE d = '123.45'::FIXEDDECIMAL; + +DROP INDEX fixdec_d_idx; + +SET client_min_messages = ERROR; +CREATE INDEX fixdec_d_idx ON fixdec USING hash (d); +RESET client_min_messages; + +EXPLAIN (COSTS OFF) SELECT * FROM fixdec WHERE d = '12.34'::FIXEDDECIMAL; + +SELECT * FROM fixdec WHERE d = '12.34'::FIXEDDECIMAL; + +SELECT * FROM fixdec WHERE d = '-12.34'::FIXEDDECIMAL; + +SELECT * FROM fixdec WHERE d = '123.45'::FIXEDDECIMAL; + +DROP TABLE fixdec; + +SET enable_seqscan = on; diff --git a/contrib/babelfishpg_money/test/sql/index.sql b/contrib/babelfishpg_money/test/sql/index.sql new file mode 100644 index 00000000000..3782593fb8c --- /dev/null +++ b/contrib/babelfishpg_money/test/sql/index.sql @@ -0,0 +1,50 @@ +CREATE TABLE fixdec (id INT, d FIXEDDECIMAL(5,2)); + +INSERT INTO fixdec (id,d) VALUES(1,-123.45); +INSERT INTO fixdec (id,d) VALUES(2,-123); +INSERT INTO fixdec (id,d) VALUES(3,-12.34); +INSERT INTO fixdec (id,d) VALUES(4,-1.34); +INSERT INTO fixdec (id,d) VALUES(5, 0.12); +INSERT INTO fixdec (id,d) VALUES(6, 1.23); +INSERT INTO fixdec (id,d) VALUES(7, 12.34); +INSERT INTO fixdec (id,d) VALUES(8, 123.45); +INSERT INTO fixdec (id,d) VALUES(9, 123.456); + +-- Should fail +CREATE UNIQUE INDEX fixdec_d_idx ON fixdec (d); + +DELETE FROM fixdec WHERE id = 9; + +CREATE UNIQUE INDEX fixdec_d_idx ON fixdec (d); + +SET enable_seqscan = off; + +EXPLAIN (COSTS OFF) SELECT * FROM fixdec ORDER BY d; + +SELECT * FROM fixdec ORDER BY d; + +EXPLAIN (COSTS OFF) SELECT * FROM fixdec WHERE d = '12.34'::FIXEDDECIMAL; + +SELECT * FROM fixdec WHERE d = '12.34'::FIXEDDECIMAL; + +SELECT * FROM fixdec WHERE d = '-12.34'::FIXEDDECIMAL; + +SELECT * FROM fixdec WHERE d = '123.45'::FIXEDDECIMAL; + +DROP INDEX fixdec_d_idx; + +SET client_min_messages = ERROR; +CREATE INDEX fixdec_d_idx ON fixdec USING hash (d); +RESET client_min_messages; + +EXPLAIN (COSTS OFF) SELECT * FROM fixdec WHERE d = '12.34'::FIXEDDECIMAL; + +SELECT * FROM fixdec WHERE d = '12.34'::FIXEDDECIMAL; + +SELECT * FROM fixdec WHERE d = '-12.34'::FIXEDDECIMAL; + +SELECT * FROM fixdec WHERE d = '123.45'::FIXEDDECIMAL; + +DROP TABLE fixdec; + +SET enable_seqscan = on; diff --git a/contrib/babelfishpg_money/test/sql/overflow.sql b/contrib/babelfishpg_money/test/sql/overflow.sql new file mode 100755 index 00000000000..06408cda2b9 --- /dev/null +++ b/contrib/babelfishpg_money/test/sql/overflow.sql @@ -0,0 +1,79 @@ +-- Ensure the expected extreme values can be represented +SELECT '-92233720368547758.08'::FIXEDDECIMAL as minvalue,'92233720368547758.07'::FIXEDDECIMAL as maxvalue; + +SELECT '-92233720368547758.09'::FIXEDDECIMAL; + +SELECT '92233720368547758.08'::FIXEDDECIMAL; + +-- Ensure casts from numeric to fixeddecimal work +SELECT '92233720368547758.07'::numeric::FIXEDDECIMAL; + +-- The literal below must be quoted as the parser seems to read the literal as +-- a positive number first and then us the - unary operator to make it negaive. +-- This would overflow without the quotes as this number cannot be represented +-- in a positive fixeddecimal. +SELECT '-92233720368547758.08'::numeric::FIXEDDECIMAL; + +-- Ensure casts from numeric to fixed decimal detect overflow +SELECT '92233720368547758.08'::numeric::FIXEDDECIMAL; + +SELECT '-92233720368547758.09'::numeric::FIXEDDECIMAL; + +SELECT '-92233720368547758.08'::FIXEDDECIMAL - '0.01'::FIXEDDECIMAL; + +SELECT '92233720368547758.07'::FIXEDDECIMAL + '0.01'::FIXEDDECIMAL; + +-- Should not overflow +SELECT '46116860184273879.03'::FIXEDDECIMAL * '2.00'::FIXEDDECIMAL; + +-- Ensure this overflows +SELECT '46116860184273879.04'::FIXEDDECIMAL * '2.00'::FIXEDDECIMAL; + +-- Should not overflow +SELECT '46116860184273879.03'::FIXEDDECIMAL / '0.50'::FIXEDDECIMAL; + +-- Ensure this overflows +SELECT '46116860184273879.04'::FIXEDDECIMAL / '0.50'::FIXEDDECIMAL; + +-- Ensure limits of int2 can be represented +SELECT '32767'::FIXEDDECIMAL::INT2,'-32768'::FIXEDDECIMAL::INT2; + +-- Ensure overflow of int2 is detected +SELECT '32768'::FIXEDDECIMAL::INT2; + +-- Ensure underflow of int2 is detected +SELECT '-32769'::FIXEDDECIMAL::INT2; + +-- Ensure limits of int4 can be represented +SELECT '2147483647'::FIXEDDECIMAL::INT4,'-2147483648'::FIXEDDECIMAL::INT4; + +-- Ensure overflow of int4 is detected +SELECT '2147483648'::FIXEDDECIMAL::INT4; + +-- Ensure underflow of int4 is detected +SELECT '-2147483649'::FIXEDDECIMAL::INT4; + +-- Ensure overflow is detected +SELECT SUM(a) FROM (VALUES('92233720368547758.07'::FIXEDDECIMAL),('0.01'::FIXEDDECIMAL)) a(a); + +-- Ensure underflow is detected +SELECT SUM(a) FROM (VALUES('-92233720368547758.08'::FIXEDDECIMAL),('-0.01'::FIXEDDECIMAL)) a(a); + +-- Test typmods +SELECT 12345.33::FIXEDDECIMAL(3,2); -- Fail + +SELECT 12345.33::FIXEDDECIMAL(5,2); -- Fail + +-- scale of 2 should be enforced. +SELECT 12345.44::FIXEDDECIMAL(7,0); + +-- should work. +SELECT 12345.33::FIXEDDECIMAL(7,2); + +-- error, precision limit should be 17 +SELECT 12345.33::FIXEDDECIMAL(18,2); + +CREATE TABLE fixdec (d FIXEDDECIMAL(3,2)); +INSERT INTO fixdec VALUES(12.34); -- Fail +INSERT INTO fixdec VALUES(1.23); -- Pass +DROP TABLE fixdec; diff --git a/contrib/babelfishpg_tds/Makefile b/contrib/babelfishpg_tds/Makefile new file mode 100644 index 00000000000..9ce8ba73f95 --- /dev/null +++ b/contrib/babelfishpg_tds/Makefile @@ -0,0 +1,43 @@ +# contrib/babelfishpg_tds/Makefile +MODULE_big = babelfishpg_tds +EXTENSION = babelfishpg_tds +DATA = babelfishpg_tds--1.0.0.sql +PGFILEDESC = "babelfishpg_tds - TDS Listener Extension" +#REGRESS = babelfishpg_tds + +tds_top_dir = . +tds_backend = $(tds_top_dir)/src/backend +tds_include = $(tds_top_dir)/src/include +TSQL_SRC = ../babelfishpg_tsql + +PG_CPPFLAGS += -I$(TSQL_SRC) -I$(PG_SRC) -I$(tds_top_dir) -DFAULT_INJECTOR + +# Exclude the following files from the build (sometimes these +# files are included in another c file) +tds_exclude_files = $(tds_backend)/tds/support_funcs.c \ + $(tds_backend)/tds/tds_data_map.c \ + $(tds_backend)/tds/tdsprinttup.c + +tds_temp_srcs = $(shell find $(tds_top_dir) -name "*.c") +tds_srcs = $(filter-out $(tds_exclude_files), $(tds_temp_srcs)) + +OBJS = $(patsubst %.c, %.o, $(tds_srcs)) +OBJS += $(WIN32RES) + +$(tds_include)/error_mapping.h: error_mapping.txt generate_error_mapping.pl + $(PERL) generate_error_mapping.pl $< > $@ +$(tds_backend)/tds/err_handler.o: $(tds_include)/error_mapping.h + +ifdef USE_PGXS +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/babelfishpg_tds +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif + +#include ../Makefile.common + +.DEFAULT_GOAL := all diff --git a/contrib/babelfishpg_tds/README b/contrib/babelfishpg_tds/README new file mode 100644 index 00000000000..e0c072c12f8 --- /dev/null +++ b/contrib/babelfishpg_tds/README @@ -0,0 +1,8 @@ +TDS Extension +---------------------- + +1. Introduction +2. Installation +3. Design and implementation details + + diff --git a/contrib/babelfishpg_tds/README.err b/contrib/babelfishpg_tds/README.err new file mode 100644 index 00000000000..6aa529b5872 --- /dev/null +++ b/contrib/babelfishpg_tds/README.err @@ -0,0 +1,4 @@ +This documentation should explain the PG error code to SQL Server error code +implementation that we've done. + + diff --git a/contrib/babelfishpg_tds/babelfishpg_tds--1.0.0.sql b/contrib/babelfishpg_tds/babelfishpg_tds--1.0.0.sql new file mode 100644 index 00000000000..56b3a4940fb --- /dev/null +++ b/contrib/babelfishpg_tds/babelfishpg_tds--1.0.0.sql @@ -0,0 +1,50 @@ +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION babelfishpg_tds" to load this file. \quit + +CREATE FUNCTION sys.inject_fault( + faultname text, + num_occurrences int4) +RETURNS text +AS 'MODULE_PATHNAME' +LANGUAGE C VOLATILE STRICT; + +CREATE FUNCTION sys.inject_fault( + faultname text, + num_occurrences int4, + tamper_byte int4) +RETURNS text +AS 'MODULE_PATHNAME' +LANGUAGE C VOLATILE STRICT; + +CREATE FUNCTION sys.inject_fault_status( + faultname text) +RETURNS text +AS 'MODULE_PATHNAME' +LANGUAGE C VOLATILE STRICT; + +CREATE FUNCTION trigger_test_fault() +RETURNS text +AS 'MODULE_PATHNAME' +LANGUAGE C VOLATILE STRICT; + +CREATE FUNCTION sys.inject_fault( + faultname text) +RETURNS text +AS $$ SELECT sys.inject_fault(faultname, 1) $$ +LANGUAGE SQL; + +CREATE FUNCTION sys.disable_injected_fault( + faultname text) +RETURNS text +AS $$ SELECT sys.inject_fault(faultname, 0) $$ +LANGUAGE SQL; + +CREATE FUNCTION sys.inject_fault_all() +RETURNS text +AS $$ SELECT sys.inject_fault('all', 1) $$ +LANGUAGE SQL; + +CREATE FUNCTION sys.disable_injected_fault_all() +RETURNS text +AS $$ SELECT sys.inject_fault('all', 0) $$ +LANGUAGE SQL; diff --git a/contrib/babelfishpg_tds/babelfishpg_tds.control b/contrib/babelfishpg_tds/babelfishpg_tds.control new file mode 100644 index 00000000000..1cf3a8e1688 --- /dev/null +++ b/contrib/babelfishpg_tds/babelfishpg_tds.control @@ -0,0 +1,7 @@ +# TDS extension +comment = 'TDS protocol extension' +default_version = '1.0.0' +module_pathname = '$libdir/babelfishpg_tds' +relocatable = true +superuser = true +requires = 'babelfishpg_tsql' diff --git a/contrib/babelfishpg_tds/error_mapping.txt b/contrib/babelfishpg_tds/error_mapping.txt new file mode 100644 index 00000000000..db3a3d37146 --- /dev/null +++ b/contrib/babelfishpg_tds/error_mapping.txt @@ -0,0 +1,169 @@ +# +# error_mapping.txt +# +# This file contains all possible error messages with error code +# which can be sent to end user along with their corresponding +# TSQL error code. +# Any newly added error message should be reflected here as well. +# +# File generated from this file one is: error_mapping.h +# +# Format of this file is, one error per line with following structure: +# sqlstate errcode_macro_name error_message tsql_error_code tsql_severity_level error_msg_keywords\n + +# error_msg_keywords can contain more than 1 key words concatenated by "#". +# If correct tsql error details could be identified by PG error code + error message_id (untranslated error message) +# then error_msg_keywords can be empty. + +# don't forget new line at the end. +# +# Empty line and line starts with hash are treated as comment. +# + +0A000 ERRCODE_FEATURE_NOT_SUPPORTED "mixture of ISO syntax and T-SQL extended syntax" SQL_ERROR_1049 15 +42601 ERRCODE_SYNTAX_ERROR "syntax error near %s at line %lu and character position %lu" SQL_ERROR_1051 16 "VARYING" +42601 ERRCODE_SYNTAX_ERROR "syntax error near %s at line %lu and character position %lu" SQL_ERROR_142 15 "REFERENCES" +42601 ERRCODE_SYNTAX_ERROR "syntax error near %s at line %lu and character position %lu" SQL_ERROR_10727 15 "INSERT" +42601 ERRCODE_SYNTAX_ERROR "syntax error near %s at line %lu and character position %lu" SQL_ERROR_10727 15 "DELETE" +42601 ERRCODE_SYNTAX_ERROR "syntax error near %s at line %lu and character position %lu" SQL_ERROR_10727 15 "UPDATE" +42601 ERRCODE_SYNTAX_ERROR "syntax error near %s at line %lu and character position %lu" SQL_ERROR_10733 15 "MERGE" +42601 ERRCODE_SYNTAX_ERROR "syntax error near %s at line %lu and character position %lu" SQL_ERROR_11717 15 "OVER" +42601 ERRCODE_SYNTAX_ERROR "syntax error near %s at line %lu and character position %lu" SQL_ERROR_487 15 "BEGIN" +42601 ERRCODE_SYNTAX_ERROR "syntax error near %s at line %lu and character position %lu" SQL_ERROR_11709 15 "WITH" +42601 ERRCODE_SYNTAX_ERROR "syntax error near %s at line %lu and character position %lu" SQL_ERROR_153 15 "FILEGROWTH" +42601 ERRCODE_SYNTAX_ERROR "Too many substitution parameters for RAISERROR. Cannot exceed 20 substitution parameters." SQL_ERROR_2747 16 +P0001 ERRCODE_RAISE_EXCEPTION "%s" SQL_ERROR_289 16 "Cannot construct data type datetime, some of the arguments have values which are not valid." +42601 ERRCODE_SYNTAX_ERROR "A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations" SQL_ERROR_141 15 +09000 ERRCODE_TRIGGERED_ACTION_EXCEPTION "An error was raised during trigger execution. The batch has been aborted and the user transaction, if any, has been rolled back." SQL_ERROR_3616 16 +42601 ERRCODE_SYNTAX_ERROR "duplicate declaration" SQL_ERROR_134 15 +42804 ERRCODE_DATATYPE_MISMATCH "variable \"%s\" must be of type cursor or refcursor" SQL_ERROR_16948 16 +2200N ERRCODE_INVALID_XML_CONTENT "%s" SQL_ERROR_9451 16 "invalid XML content" +2200N ERRCODE_INVALID_XML_CONTENT "%s" SQL_ERROR_9441 16 "invalid XML content#invalid XML declaration" +P0001 ERRCODE_RAISE_EXCEPTION "%s" SQL_ERROR_9809 16 "is not supported for conversions from" +22003 ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE "\"%s\" is out of range for type real" SQL_ERROR_232 16 +42809 ERRCODE_WRONG_OBJECT_TYPE "\"%s\" is not a table" SQL_ERROR_4708 16 +42601 ERRCODE_SYNTAX_ERROR "%s at or near \"%s\"" SQL_ERROR_1051 15 "VARYING" +42601 ERRCODE_SYNTAX_ERROR "%s at or near \"%s\"" SQL_ERROR_3914 16 "SAVE" +42601 ERRCODE_SYNTAX_ERROR "%s at or near \"%s\"" SQL_ERROR_1034 15 "duplicate trigger events specified" +42601 ERRCODE_SYNTAX_ERROR "%s at or near \"%s\"" SQL_ERROR_10793 15 "INDEX" +42601 ERRCODE_SYNTAX_ERROR "%s at or near \"%s\"" SQL_ERROR_11555 15 "NOT" +25P01 ERRCODE_NO_ACTIVE_SQL_TRANSACTION "%s can only be used in transaction blocks" SQL_ERROR_3902 16 "COMMIT" +25P01 ERRCODE_NO_ACTIVE_SQL_TRANSACTION "%s can only be used in transaction blocks" SQL_ERROR_3903 16 "ROLLBACK" +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 +42809 ERRCODE_WRONG_OBJECT_TYPE "\"%s\" is not a table or materialized view" SQL_ERROR_10610 16 +42809 ERRCODE_WRONG_OBJECT_TYPE "%s parameter should be of %s type" SQL_ERROR_16902 16 +22004 ERRCODE_NULL_VALUE_NOT_ALLOWED "%s parameter should not be null" SQL_ERROR_16902 16 +42601 ERRCODE_SYNTAX_ERROR "argument name \"%s\" used more than once" SQL_ERROR_8143 16 +22003 ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE "bigint out of range" SQL_ERROR_8115 16 +55006 ERRCODE_OBJECT_IN_USE "cannot %s \"%s\" because it is being used by active queries in this session" SQL_ERROR_556 16 +2BP01 ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST "cannot drop %s because %s requires it" SQL_ERROR_3723 16 +2BP01 ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST "cannot drop %s because other objects depend on it" SQL_ERROR_3732 16 "type" +2BP01 ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST "cannot drop %s because other objects depend on it" SQL_ERROR_3729 16 "function" +2BP01 ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST "cannot drop %s because other objects depend on it" SQL_ERROR_3726 16 "table" +2201E ERRCODE_INVALID_ARGUMENT_FOR_LOG "cannot take logarithm of a negative number" SQL_ERROR_3623 16 +2201F ERRCODE_INVALID_ARGUMENT_FOR_POWER_FUNCTION "cannot take square root of a negative number" SQL_ERROR_3623 16 +0A000 ERRCODE_FEATURE_NOT_SUPPORTED "cannot truncate a table referenced in a foreign key constraint" SQL_ERROR_4712 16 +22023 ERRCODE_INVALID_PARAMETER_VALUE "CACHE (%s) must be greater than zero" SQL_ERROR_11706 16 +23514 ERRCODE_CHECK_VIOLATION "check constraint \"%s\" of relation \"%s\" is violated by some row" SQL_ERROR_547 16 +2F005 ERRCODE_S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT "The transaction ended in the trigger. The batch has been aborted." SQL_ERROR_3609 16 +23502 ERRCODE_NOT_NULL_VIOLATION "column \"%s\" of relation \"%s\" contains null values" SQL_ERROR_4901 16 +42601 ERRCODE_SYNTAX_ERROR "column \"%s\" of relation \"%s\" is a generated column" SQL_ERROR_1752 16 +XX000 ERRCODE_INTERNAL_ERROR "CREATE FUNCTION failed because a column name is not specified for column %d" SQL_ERROR_4514 16 +42601 ERRCODE_SYNTAX_ERROR "CREATE VIEW specifies more column names than columns" SQL_ERROR_8159 16 +42704 ERRCODE_UNDEFINED_OBJECT "constraint \"%s\" of relation \"%s\" does not exist" SQL_ERROR_3728 16 +23505 ERRCODE_UNIQUE_VIOLATION "could not create unique index \"%s\"" SQL_ERROR_1505 16 +42883 ERRCODE_UNDEFINED_FUNCTION "could not find a function named \"%s\"" SQL_ERROR_3701 11 +42883 ERRCODE_UNDEFINED_FUNCTION "could not find a procedure named \"%s\"" SQL_ERROR_3701 11 +42883 ERRCODE_UNDEFINED_FUNCTION "could not identify an equality operator for type %s" SQL_ERROR_306 16 +42883 ERRCODE_UNDEFINED_FUNCTION "could not identify an ordering operator for type %s" SQL_ERROR_306 16 +42P03 ERRCODE_DUPLICATE_CURSOR "cursor \"%s\" already exists" SQL_ERROR_16915 16 +42704 ERRCODE_UNDEFINED_OBJECT "cursor %d doesn't exist" SQL_ERROR_16916 16 +22004 ERRCODE_NULL_VALUE_NOT_ALLOWED "cursor variable \"%s\" is null" SQL_ERROR_16950 16 +42P04 ERRCODE_DUPLICATE_DATABASE "database \"%s\" already exists" SQL_ERROR_1801 16 +3D000 ERRCODE_UNDEFINED_DATABASE "database \"%s\" does not exist" SQL_ERROR_3701 11 +22008 ERRCODE_DATETIME_VALUE_OUT_OF_RANGE "data out of range for datetime" SQL_ERROR_517 16 +40P01 ERRCODE_T_R_DEADLOCK_DETECTED "deadlock detected" SQL_ERROR_1205 13 +22012 ERRCODE_DIVISION_BY_ZERO "division by zero" SQL_ERROR_8134 16 +0A000 ERRCODE_FEATURE_NOT_SUPPORTED "Do not support BREAK outside of a WHILE loop, line %d" SQL_ERROR_135 15 +0A000 ERRCODE_FEATURE_NOT_SUPPORTED "Do not support CONTINUE outside of a WHILE loop, line %d" SQL_ERROR_136 15 +23505 ERRCODE_UNIQUE_VIOLATION "duplicate key value violates unique constraint \"%s\"" SQL_ERROR_2627 14 +42703 ERRCODE_UNDEFINED_COLUMN "Explicit value must be specified for identity column in table '%s' when IDENTITY_INSERT is set to ON" SQL_ERROR_545 16 +42804 ERRCODE_DATATYPE_MISMATCH "foreign key constraint \"%s\" cannot be implemented" SQL_ERROR_1778 16 +22013 ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE "frame ending offset must not be negative" SQL_ERROR_102 15 +22013 ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE "frame starting offset must not be negative" SQL_ERROR_102 15 +42723 ERRCODE_DUPLICATE_FUNCTION "function \"%s\" already exists with same argument types" SQL_ERROR_2714 16 +54023 ERRCODE_TOO_MANY_ARGUMENTS "functions cannot have more than %d argument" SQL_ERROR_180 15 +0A000 ERRCODE_FEATURE_NOT_SUPPORTED "GOTO target Label %s not defined" SQL_ERROR_133 15 +23001 ERRCODE_RESTRICT_VIOLATION "IDENTITY_INSERT is already ON for table \'%s.%s.%s\'" SQL_ERROR_8107 16 +22023 ERRCODE_INVALID_PARAMETER_VALUE "INCREMENT must not be zero" SQL_ERROR_11700 16 +22003 ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE "input is out of range" SQL_ERROR_3623 16 +54000 ERRCODE_PROGRAM_LIMIT_EXCEEDED "index row size %zu exceeds btree version %u maximum %zu for index \"%s\"" SQL_ERROR_1946 16 +23503 ERRCODE_FOREIGN_KEY_VIOLATION "insert or update on table \"%s\" violates foreign key constraint \"%s\"" SQL_ERROR_547 16 +22003 ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE "integer out of range" SQL_ERROR_8115 16 +42601 ERRCODE_SYNTAX_ERROR "invalid %s action for foreign key constraint containing generated column" SQL_ERROR_1715 16 "ON UPDATE" +42601 ERRCODE_SYNTAX_ERROR "invalid %s action for foreign key constraint containing generated column" SQL_ERROR_1765 16 "ON DELETE" +22003 ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE "invalid characters found: cannot cast value \"%s\" to money" SQL_ERROR_293 16 +22023 ERRCODE_INVALID_PARAMETER_VALUE "invalid cursor fetch type %X" SQL_ERROR_155 15 +22023 ERRCODE_INVALID_PARAMETER_VALUE "Invalid format specification: %s" SQL_ERROR_2787 16 +22023 ERRCODE_INVALID_PARAMETER_VALUE "invalid nrow value 0 for cursor type %X" SQL_ERROR_16902 16 +08P01 ERRCODE_PROTOCOL_VIOLATION "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." SQL_ERROR_8018 16 +22025 ERRCODE_INVALID_ESCAPE_SEQUENCE "invalid escape string" SQL_ERROR_506 16 +0A000 ERRCODE_FEATURE_NOT_SUPPORTED "Label %s not unique wihtin one procedure in line %d, previous defined in line %d" SQL_ERROR_132 15 +08004 ERRCODE_SQLSERVER_REJECTED_ESTABLISHMENT_OF_SQLCONNECTION "Login failed for user \"%s\"" SQL_ERROR_18456 14 +22023 ERRCODE_INVALID_PARAMETER_VALUE "MAXVALUE (%s) is out of range for sequence data type tinyint" SQL_ERROR_11708 16 +22023 ERRCODE_INVALID_PARAMETER_VALUE "MAXVALUE (%s) is out of range for sequence data type %s" SQL_ERROR_11708 16 +22023 ERRCODE_INVALID_PARAMETER_VALUE "MINVALUE (%s) must be less than MAXVALUE (%s)" SQL_ERROR_11705 16 +21000 ERRCODE_CARDINALITY_VIOLATION "more than one row returned by a subquery used as an expression" SQL_ERROR_512 16 +23514 ERRCODE_CHECK_VIOLATION "new row for relation \"%s\" violates check constraint \"%s\"" SQL_ERROR_547 16 +44000 ERRCODE_WITH_CHECK_OPTION_VIOLATION "new row violates check option for view \"%s\"" SQL_ERROR_550 16 +23502 ERRCODE_NOT_NULL_VIOLATION "null value in column \"%s\" of relation \"%s\" violates not-null constraint" SQL_ERROR_515 16 +22023 ERRCODE_INVALID_PARAMETER_VALUE "msg_id argument of RAISERROR should be no less than 50000" SQL_ERROR_2732 16 +42704 ERRCODE_UNDEFINED_OBJECT "Prepared statement not found: %d" SQL_ERROR_8179 16 +22004 ERRCODE_NULL_VALUE_NOT_ALLOWED "Prepared statement not found: %d" SQL_ERROR_8179 16 +42809 ERRCODE_WRONG_OBJECT_TYPE "referenced relation \"%s\" is not a table" SQL_ERROR_1768 16 +42P07 ERRCODE_DUPLICATE_TABLE "relation \"%s\" already exists" SQL_ERROR_2714 16 +3B001 ERRCODE_S_E_INVALID_SPECIFICATION "savepoint \"%s\" does not exist" SQL_ERROR_6401 16 +22023 ERRCODE_INVALID_PARAMETER_VALUE "sequence type must be smallint, integer, or bigint" SQL_ERROR_11702 16 +22003 ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE "smallint out of range" SQL_ERROR_220 16 +54001 ERRCODE_STATEMENT_TOO_COMPLEX "stack depth limit exceeded" SQL_ERROR_217 16 +0A000 ERRCODE_FEATURE_NOT_SUPPORTED "SP_PREPEXECRPC not supported yet" SQL_ERROR_16901 16 +22023 ERRCODE_INVALID_PARAMETER_VALUE "START value (%s) cannot be greater than MAXVALUE (%s)" SQL_ERROR_11703 16 +22023 ERRCODE_INVALID_PARAMETER_VALUE "START value (%s) cannot be less than MINVALUE (%s)" SQL_ERROR_11703 16 +42703 ERRCODE_UNDEFINED_COLUMN "Table '%s.%s' does not have the identity property. Cannot perform SET operation." SQL_ERROR_8106 16 +08P01 ERRCODE_PROTOCOL_VIOLATION "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." SQL_ERROR_8057 16 +2202H ERRCODE_INVALID_TABLESAMPLE_ARGUMENT "TABLESAMPLE parameter cannot be null" SQL_ERROR_477 15 +2202G ERRCODE_INVALID_TABLESAMPLE_REPEAT "TABLESAMPLE REPEATABLE parameter cannot be null" SQL_ERROR_477 15 +22023 ERRCODE_INVALID_PARAMETER_VALUE "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." SQL_ERROR_11701 16 +40000 ERRCODE_TRANSACTION_ROLLBACK "The current transaction cannot be committed and cannot support operations that write to the log file. Roll back the transaction." SQL_ERROR_3930 16 +XX000 ERRCODE_INTERNAL_ERROR "The parameter \"%s\" can not be declared READONLY since it is not a table-valued parameter." SQL_ERROR_346 15 +XX000 ERRCODE_INTERNAL_ERROR "The table-valued parameter \"%s\" must be declared with the READONLY option." SQL_ERROR_352 15 +08P01 ERRCODE_PROTOCOL_VIOLATION "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." SQL_ERROR_8016 16 +08P01 ERRCODE_PROTOCOL_VIOLATION "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." SQL_ERROR_8011 16 +08P01 ERRCODE_PROTOCOL_VIOLATION "The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. Parameter %d (\"%s\"): Data type 0x%02X is unknown." SQL_ERROR_8009 16 +08P01 ERRCODE_PROTOCOL_VIOLATION "The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. Parameter %d (\"%s\"): The chunking format is incorrect for a large object parameter of type 0x%02X." SQL_ERROR_8007 16 +08P01 ERRCODE_PROTOCOL_VIOLATION "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." SQL_ERROR_8028 16 +08P01 ERRCODE_PROTOCOL_VIOLATION "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" SQL_ERROR_8023 16 +08P01 ERRCODE_PROTOCOL_VIOLATION "The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. The RPC name is invalid." SQL_ERROR_8004 16 +08P01 ERRCODE_PROTOCOL_VIOLATION "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" SQL_ERROR_8003 16 +08P01 ERRCODE_PROTOCOL_VIOLATION "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." SQL_ERROR_8047 16 +08P01 ERRCODE_PROTOCOL_VIOLATION "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." SQL_ERROR_8050 16 +08P01 ERRCODE_PROTOCOL_VIOLATION "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." SQL_ERROR_8029 16 +08P01 ERRCODE_PROTOCOL_VIOLATION "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." SQL_ERROR_8037 16 +08P01 ERRCODE_PROTOCOL_VIOLATION "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." SQL_ERROR_8032 16 +08P01 ERRCODE_PROTOCOL_VIOLATION "The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. Table-valued parameter %d (\"%s\"), row %d, column %d: The chunking format is incorrect for a large object parameter of data type 0x%02X." SQL_ERROR_8031 16 +08P01 ERRCODE_PROTOCOL_VIOLATION "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." SQL_ERROR_8043 16 +08P01 ERRCODE_PROTOCOL_VIOLATION "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." SQL_ERROR_8058 16 +08P01 ERRCODE_PROTOCOL_VIOLATION "The minimum number of parameters should be %d" SQL_ERROR_16903 16 +42830 ERRCODE_INVALID_FOREIGN_KEY "there is no unique constraint matching given keys for referenced table \"%s\"" SQL_ERROR_1776 16 +40002 ERRCODE_T_R_INTEGRITY_CONSTRAINT_VIOLATION "Transaction count after execution indicates a mismatch number of BEGIN and COMMIT statements. Previous count %u current count %u" SQL_ERROR_266 16 +42704 ERRCODE_UNDEFINED_OBJECT "trigger \"%s\" does not exist" SQL_ERROR_3701 11 +42704 ERRCODE_UNDEFINED_OBJECT "trigger \"%s\" for table \"%s\" does not exist" SQL_ERROR_4920 16 +42710 ERRCODE_DUPLICATE_OBJECT "type \"%s\" already exists" SQL_ERROR_219 16 +23503 ERRCODE_FOREIGN_KEY_VIOLATION "update or delete on table \"%s\" violates foreign key constraint \"%s\" on table \"%s\"" SQL_ERROR_547 16 +22001 ERRCODE_STRING_DATA_RIGHT_TRUNCATION "value too long for type character(%d)" SQL_ERROR_8152 16 +22001 ERRCODE_STRING_DATA_RIGHT_TRUNCATION "value too long for type character varying(%d)" SQL_ERROR_8152 16 +23514 ERRCODE_CHECK_VIOLATION "value for domain %s violates check constraint \"%s\"" SQL_ERROR_220 16 +42P01 ERRCODE_UNDEFINED_TABLE "view \"%s\" does not exist" SQL_ERROR_3701 16 +42P01 ERRCODE_UNDEFINED_TABLE "table \"%s\" does not exist" SQL_ERROR_3701 16 diff --git a/contrib/babelfishpg_tds/generate_error_mapping.pl b/contrib/babelfishpg_tds/generate_error_mapping.pl new file mode 100644 index 00000000000..1c9c75fdbc9 --- /dev/null +++ b/contrib/babelfishpg_tds/generate_error_mapping.pl @@ -0,0 +1,35 @@ +#!/usr/bin/perl +# +# Generate the error_mapping.h header from error_mapping.txt + +use warnings; +use strict; + +print "/* autogenerated from error_mapping.txt, do not edit */\n"; + +open my $error_map_details, '<', $ARGV[0] or die; + +while (<$error_map_details>) +{ + chomp; + + # Skip comments + next if /^#/; + next if /^\s*$/; + + die unless /^([^\s]{5})\s+([^\s]+)\s(.*)(\sSQL_ERROR_)(\d{1,5})\s(\d{2})\s?(.*)?\s?/; + + (my $sqlstate, my $errcode_macro, my $error_msg, my $tsql_error_code, my $tsql_error_sev, my $error_msg_keywords) = + ($1, $2, $3, $5, $6, $7); + + next unless defined($error_msg); + + if ($error_msg_keywords eq "") + { + $error_msg_keywords="\"\""; + } + + print "{\n\t\"$sqlstate\",$error_msg, $tsql_error_code, $tsql_error_sev, $error_msg_keywords\n},\n\n"; +} + +close $error_map_details; diff --git a/contrib/babelfishpg_tds/src/backend/encoding/encoding_utils.c b/contrib/babelfishpg_tds/src/backend/encoding/encoding_utils.c new file mode 100644 index 00000000000..ec78aba183f --- /dev/null +++ b/contrib/babelfishpg_tds/src/backend/encoding/encoding_utils.c @@ -0,0 +1,121 @@ +#include "postgres.h" + +#include "access/xact.h" +#include "catalog/namespace.h" +#include "mb/pg_wchar.h" +#include "utils/builtins.h" +#include "utils/memutils.h" +#include "utils/syscache.h" + +#include "src/include/tds_int.h" + +static unsigned char *do_encoding_conversion(unsigned char *src, int len, int src_encoding, int dest_encoding); + +/* + * Convert server encoding to any encoding. + * + * See the notes about string conversion functions at the top of this file. + */ +char * +server_to_any(const char *s, int len, int encoding) +{ + if (len <= 0) + return (char *) s; /* empty string is always valid */ + + if (encoding == GetDatabaseEncoding() || + encoding == PG_SQL_ASCII) + return (char *) s; /* assume data is valid */ + + if (GetDatabaseEncoding() == PG_SQL_ASCII) + { + /* No conversion is possible, but we must validate the result */ + (void) pg_verify_mbstr(encoding, s, len, false); + return (char *) s; + } + return (char *) do_encoding_conversion((unsigned char *) s, + len, + GetDatabaseEncoding(), + encoding); +} + +/* + * Convert src string to another encoding (general case). + * + * See the notes about string conversion functions at the top of this file. + */ +static unsigned char * +do_encoding_conversion(unsigned char *src, int len, + int src_encoding, int dest_encoding) +{ + unsigned char *result; + + if (len <= 0) + return src; /* empty string is always valid */ + + if (src_encoding == dest_encoding) + return src; /* no conversion required, assume valid */ + + if (dest_encoding == PG_SQL_ASCII) + return src; /* any string is valid in SQL_ASCII */ + + if (src_encoding == PG_SQL_ASCII) + { + /* No conversion is possible, but we must validate the result */ + (void) pg_verify_mbstr(dest_encoding, (const char *) src, len, false); + return src; + } + + if (!IsTransactionState()) /* shouldn't happen */ + elog(ERROR, "cannot perform encoding conversion outside a transaction"); + /* + * Allocate space for conversion result, being wary of integer overflow. + * + * len * MAX_CONVERSION_GROWTH is typically a vast overestimate of the + * required space, so it might exceed MaxAllocSize even though the result + * would actually fit. We do not want to hand back a result string that + * exceeds MaxAllocSize, because callers might not cope gracefully --- but + * if we just allocate more than that, and don't use it, that's fine. + */ + if ((Size) len >= (MaxAllocHugeSize / (Size) MAX_CONVERSION_GROWTH)) + ereport(ERROR, + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), + errmsg("out of memory"), + errdetail("String of %d bytes is too long for encoding conversion.", + len))); + + result = (unsigned char *) + MemoryContextAllocHuge(CurrentMemoryContext, + (Size) len * MAX_CONVERSION_GROWTH + 1); + + if (dest_encoding == PG_BIG5) + utf8_to_big5(src_encoding, dest_encoding, src, result, len); + else if (dest_encoding == PG_GBK) + utf8_to_gbk(src_encoding, dest_encoding, src, result, len); + else if (dest_encoding == PG_UHC) + utf8_to_uhc(src_encoding, dest_encoding, src, result, len); + else if (dest_encoding == PG_SJIS) + utf8_to_sjis(src_encoding, dest_encoding, src, result, len); + else + utf8_to_win(src_encoding, dest_encoding, src, result, len); + + /* + * 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 + * *must* check when len * MAX_CONVERSION_GROWTH exceeds MaxAllocSize. + */ + if (len > 1000000) + { + Size resultlen = strlen((char *) result); + + if (resultlen >= MaxAllocSize) + ereport(ERROR, + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), + errmsg("out of memory"), + errdetail("String of %d bytes is too long for encoding conversion.", + len))); + + result = (unsigned char *) repalloc(result, resultlen + 1); + } + + return result; +} diff --git a/contrib/babelfishpg_tds/src/backend/fault_injection/fault_injection.c b/contrib/babelfishpg_tds/src/backend/fault_injection/fault_injection.c new file mode 100644 index 00000000000..2e4e1798b7f --- /dev/null +++ b/contrib/babelfishpg_tds/src/backend/fault_injection/fault_injection.c @@ -0,0 +1,403 @@ +/*------------------------------------------------------------------------- + * + * fault_injection.c + * Fault Injection Framework + * + * Portions Copyright (c) 2020, AWS + * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * contrib/babelfishpg_tds/src/backend/fault_injection/fault_injection.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "fmgr.h" +#include "lib/stringinfo.h" +#include "miscadmin.h" +#include "utils/builtins.h" +#include "utils/hsearch.h" +#include "utils/memutils.h" + +#include "src/include/faultinjection.h" +#include "src/include/tds_int.h" + +extern Datum inject_fault(PG_FUNCTION_ARGS); +extern Datum inject_fault_status(PG_FUNCTION_ARGS); +extern Datum trigger_test_fault(PG_FUNCTION_ARGS); +extern Datum inject_fault_status_all(PG_FUNCTION_ARGS); + +PG_FUNCTION_INFO_V1(inject_fault); +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; + +int tamperByte = INVALID_TAMPER_BYTE; + +/* + * FaultInjectionHashInit - initialize the hash + */ +static void +FaultInjectionHashInit() +{ + HASHCTL hash_ctl; + MemoryContext oldContext; + + oldContext = MemoryContextSwitchTo(TopMemoryContext); + /* Local cache */ + MemSet(&hash_ctl, 0, sizeof(hash_ctl)); + hash_ctl.keysize = FAULT_NAME_MAX_LENGTH; + hash_ctl.entrysize = sizeof(FaultInjectorEntry_s); + faultInjectorHash = hash_create("Fault Injection Cache", + 16, + &hash_ctl, + HASH_ELEM); + MemoryContextSwitchTo(oldContext); +} + +/* + * FaultInjectionInitialize - initializa the fault injection hash with enrties + */ +static void +FaultInjectionInitialize() +{ + int i = 0; + bool foundPtr; + + if (faultInjectorHash == NULL) + FaultInjectionHashInit(); + + do + { + const FaultInjectorEntry_s *entry = &Faults[i]; + FaultInjectorEntry_s *new_entry; + + if (entry->type == InvalidType) + break; + new_entry = (FaultInjectorEntry_s *) hash_search( + faultInjectorHash, + (void *) entry->faultName, //key + HASH_ENTER, + &foundPtr); + /* should not try to insert same entry multiple times */ + Assert(foundPtr == false); + + if (entry == NULL) + { + ereport(DEBUG5, + (errmsg("FaultInjectionLookupHashEntry() could not insert fault injection hash entry:'%s' ", + entry->faultName))); + } + + new_entry->type = entry->type; + new_entry->num_occurrences = 0; + new_entry->fault_callback = entry->fault_callback; + + i++; + } while(true); +} + +/* + * FaultInjectionLookupHashEntry - look for the entry + */ +static FaultInjectorEntry_s * +FaultInjectionLookupHashEntry(const char *faultName) +{ + FaultInjectorEntry_s *entry; + + if (faultInjectorHash == NULL) + FaultInjectionInitialize(); + + entry = (FaultInjectorEntry_s *) hash_search( + faultInjectorHash, + (void *) faultName, //key + HASH_FIND, + NULL); + + if (entry == NULL) + { + ereport(ERROR, + (errmsg("FaultInjectionLookupHashEntry() could not find fault injection hash entry:'%s' ", + faultName))); + } + + return entry; +} + +static void +FaultInjectionEnableTest(FaultInjectorEntry_s *entry) +{ + List *list = FaultInjectionTypes[entry->type].injected_entries; + ListCell *lc; + MemoryContext oldContext; + + + foreach(lc, list) + { + if (entry == (FaultInjectorEntry_s *) lfirst(lc)) + return; + } + + oldContext = MemoryContextSwitchTo(TopMemoryContext); + list = lappend(list, entry); + MemoryContextSwitchTo(oldContext); + + FaultInjectionTypes[entry->type].injected_entries = list; +} + +static inline void +FaultInjectionDisableTest(FaultInjectorEntry_s *entry) +{ + List *list = FaultInjectionTypes[entry->type].injected_entries; + + if (list_length(list) == 1) + { + list_free(list); + list = NIL; + } + else + list = list_delete(list, entry); + + tamperByte = INVALID_TAMPER_BYTE; + FaultInjectionTypes[entry->type].injected_entries = list; +} + +static char* +FetchFaultStatus(char *faultName) +{ + StringInfo buf = makeStringInfo(); + FaultInjectorEntry_s *entry; + + entry = FaultInjectionLookupHashEntry(faultName); + + if (entry->num_occurrences == 0) + appendStringInfo(buf, "disabled, Type: %s", + FaultInjectionTypes[entry->type].faultTypeName); + else + appendStringInfo(buf, "enabled, Type: %s, pending occurrences: %d", + FaultInjectionTypes[entry->type].faultTypeName, + entry->num_occurrences); + + return buf->data; +} + +static char * +InjectFault(const char *faultName, int num_occurrences, int tamper_byte) +{ + StringInfo buf = makeStringInfo(); + FaultInjectorEntry_s *entry; + + entry = FaultInjectionLookupHashEntry(faultName); + if (entry->num_occurrences == 0 && num_occurrences > 0) + FaultInjectionEnableTest(entry); + else if (entry->num_occurrences > 0 && num_occurrences == 0) + FaultInjectionDisableTest(entry); + + entry->num_occurrences = num_occurrences; + tamperByte = tamper_byte; + + if (entry->num_occurrences == 0) + appendStringInfo(buf, "disabled"); + else if (tamperByte != INVALID_TAMPER_BYTE) + appendStringInfo(buf, "enabled, pending occurrences: %d, tamper byte value: %d", + entry->num_occurrences, tamperByte); + else + appendStringInfo(buf, "enabled, pending occurrences: %d", entry->num_occurrences); + + return buf->data; +} + +void +TriggerFault(FaultInjectorType_e type, void *arg) +{ + 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) + return; + + TDS_DEBUG(TDS_DEBUG1, "Triggering fault type: %s", FaultInjectionTypes[type].faultTypeName); + + /* Fast Path when entry is just 1 */ + if (list_length(list) == 1) + { + FaultInjectorEntry_s *entry; + + lc = list_head(list); + entry = (FaultInjectorEntry_s *) lfirst(lc); + + /* otherwise it should have been removed */ + Assert(entry->num_occurrences > 0); + + entry->num_occurrences--; + + PG_TRY(); + { + TDS_DEBUG(TDS_DEBUG2, "Triggering fault: %s", entry->faultName); + (*(entry->fault_callback)) (arg); + } + PG_CATCH(); + { + if (entry->num_occurrences == 0) + FaultInjectionDisableTest(entry); + + PG_RE_THROW(); + } + PG_END_TRY(); + + if (entry->num_occurrences == 0) + FaultInjectionDisableTest(entry); + + return; + } + + /* + * If there is more than one entry, we've to be careful while removing + * entries from the list while traversing the same. + */ + foreach(lc, list) + { + FaultInjectorEntry_s *entry = (FaultInjectorEntry_s *) lfirst(lc); + + /* otherwise it should have been removed */ + Assert(entry->num_occurrences > 0); + + entry->num_occurrences--; + + PG_TRY(); + { + TDS_DEBUG(TDS_DEBUG2, "Triggering fault: %s", entry->faultName); + (*(entry->fault_callback)) (arg); + } + PG_CATCH(); + { + if (entry->num_occurrences == 0) + tmp_list = lappend(tmp_list, entry); + + foreach(lc, tmp_list) + { + FaultInjectorEntry_s *entry = (FaultInjectorEntry_s *) lfirst(lc); + + FaultInjectionDisableTest(entry); + } + + list_free(tmp_list); + + PG_RE_THROW(); + } + PG_END_TRY(); + + if (entry->num_occurrences == 0) + tmp_list = lappend(tmp_list, entry); + } + + foreach(lc, tmp_list) + { + FaultInjectorEntry_s *entry = (FaultInjectorEntry_s *) lfirst(lc); + + FaultInjectionDisableTest(entry); + } + + list_free(tmp_list); +} + +/* + * InjectFaultAll - inject all the faults if enable = true, disable otherwise + * + * It enables the faults with occurences as 1 + */ +static char* +InjectFaultAll(bool enable) +{ + int i = 0; + StringInfo response = makeStringInfo(); + + do + { + char *ret; + const FaultInjectorEntry_s *entry = &Faults[i]; + + if (entry->type == InvalidType) + break; + ret = InjectFault(entry->faultName, (enable) ? 1 : 0, INVALID_TAMPER_BYTE); + + if (!ret) + elog(ERROR, "failed to inject fault"); + + pfree(ret); + + i++; + } while(true); + + appendStringInfo(response, "success"); + + return response->data; +} + +Datum +inject_fault(PG_FUNCTION_ARGS) +{ + char *faultName = TextDatumGetCString(PG_GETARG_DATUM(0)); + int num_occurrences = PG_GETARG_INT32(1); + char *response; + int nargs = PG_NARGS(); + int tamper_byte = INVALID_TAMPER_BYTE; + + if (nargs > 2) + tamper_byte = PG_GETARG_INT32(2); + + if (num_occurrences < 0) + elog(ERROR, "number of occurrences cannot be negative"); + + /* check if we need to enable/disable all the tests */ + if (strcmp(faultName, "all") == 0 && num_occurrences > 0) + response = InjectFaultAll(true); + else if (strcmp(faultName, "all") == 0 && num_occurrences == 0) + response = InjectFaultAll(false); + else + response = InjectFault(faultName, num_occurrences, tamper_byte); + if (!response) + elog(ERROR, "failed to inject fault"); + + PG_RETURN_TEXT_P(cstring_to_text(response)); +} + +Datum +inject_fault_status(PG_FUNCTION_ARGS) +{ + char *faultName = TextDatumGetCString(PG_GETARG_DATUM(0)); + char *response; + + response = FetchFaultStatus(faultName); + if (!response) + elog(ERROR, "failed to fetch injected fault status"); + + PG_RETURN_TEXT_P(cstring_to_text(response)); +} + +Datum +inject_fault_status_all(PG_FUNCTION_ARGS) +{ + /* TODO */ + PG_RETURN_VOID(); +} + +Datum +trigger_test_fault(PG_FUNCTION_ARGS) +{ + StringInfo buf = makeStringInfo(); + + TriggerFault(TestType, (void *) buf); + if (!buf) + elog(ERROR, "failed to trigger fault"); + + PG_RETURN_TEXT_P(cstring_to_text(buf->data)); +} 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 new file mode 100644 index 00000000000..ec793e398c4 --- /dev/null +++ b/contrib/babelfishpg_tds/src/backend/fault_injection/fault_injection_tests.c @@ -0,0 +1,239 @@ +/*------------------------------------------------------------------------- + * + * fault_injection_tests.c + * TDS test cases for Fault Injection Framework + * + * Portions Copyright (c) 2020, AWS + * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * contrib/babelfishpg_tds/src/backend/fault_injection/fault_injection_tests.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "lib/stringinfo.h" +#include "miscadmin.h" + +#include "src/include/tds_int.h" +#include "src/include/tds_request.h" +#include "src/include/faultinjection.h" + +/* test cases */ +static void +test_fault1(void *arg) +{ + StringInfo buf = (StringInfo) arg; + + if (buf->len > 0) + appendStringInfo(buf, ", "); + + appendStringInfo(buf, "test_fault1"); +} + +static void +test_fault2(void *arg) +{ + StringInfo buf = (StringInfo) arg; + + if (buf->len > 0) + appendStringInfo(buf, ", "); + + appendStringInfo(buf, "test_fault2"); +} + +/* + * In this function, we tamper bytes of the input argument sequentially and + * call TDS parser function. The expectation is the parser code can throw and + * error, but it should not crash. + */ +static void +tamper_request_sequential(void *arg, char tamper_byte) +{ + struct TdsMessageWrapper *wrapper = (struct TdsMessageWrapper *) arg; + StringInfo buf = wrapper->message; + StringInfo tmp = makeStringInfo(); + MemoryContext oldcontext; + uint64_t offset = 0; + int i; + uint32_t tdsVersion = GetClientTDSVersion(); + + /* Skip if its an Attention Request. */ + if (wrapper->messageType == TDS_ATTENTION) + return; + oldcontext = MemoryContextSwitchTo(MessageContext); + + /* + * 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. + */ + if (tdsVersion > TDS_VERSION_7_1_1) + offset = ProcessStreamHeaders(buf);; + for (i = offset; i < buf->len; i++) + { + PG_TRY(); + { + appendBinaryStringInfoNT(tmp, buf->data, buf->len); + + tmp->data[i] = tamper_byte; + + switch (wrapper->messageType) + { + case TDS_QUERY: /* Simple SQL BATCH */ + { + (void) GetSQLBatchRequest(tmp); + } + break; + case TDS_RPC: /* Remote procedure call */ + { + (void) GetRPCRequest(tmp); + } + break; + case TDS_TXN: /* Transaction management request */ + { + (void) GetTxnMgmtRequest(tmp); + } + break; + } + } + PG_CATCH(); + { + FlushErrorState(); + } + PG_END_TRY(); + + resetStringInfo(tmp); + MemoryContextReset(MessageContext); + } + + MemoryContextSwitchTo(oldcontext); + + pfree(tmp->data); + pfree(tmp); +} + +static void +pre_parsing_tamper_request(void *arg) +{ + /* tamper byte with all 0s */ + tamper_request_sequential(arg, 0x00); + /* tamper byte with all Fs */ + tamper_request_sequential(arg, 0xFF); + /* tamper byte with a random byte value */ + tamper_request_sequential(arg, (10 * rand() % 0xFF)); +} + + +/* + * In this function, we tamper bytes at particular offset and call + * call TDS RPC parser function. The expectation is the parser code can throw and + * error, but it should not crash. + */ +static void +tamper_rpc_request(void *arg, uint64_t offset, int tamper_byte) +{ + struct TdsMessageWrapper *wrapper = (struct TdsMessageWrapper *) arg; + StringInfo buf = wrapper->message; + StringInfo tmp = makeStringInfo(); + + MemoryContext oldcontext = MemoryContextSwitchTo(MessageContext); + + PG_TRY(); + { + appendBinaryStringInfoNT(tmp, buf->data, buf->len); + + tmp->data[offset] = tamper_byte; + + (void) GetRPCRequest(tmp); + } + PG_CATCH(); + { + FlushErrorState(); + } + PG_END_TRY(); + + resetStringInfo(tmp); + MemoryContextReset(MessageContext); + + MemoryContextSwitchTo(oldcontext); + + pfree(tmp->data); + pfree(tmp); +} + +static void +pre_parsing_tamper_rpc_request_sptype(void *arg) +{ + uint64_t offset = 0; + + if (GetClientTDSVersion() > TDS_VERSION_7_1_1) + offset = ProcessStreamHeaders(((struct TdsMessageWrapper *) arg)->message); + + offset += 2; /* Skip length. */ + + if (tamperByte != INVALID_TAMPER_BYTE) + tamper_rpc_request(arg, offset, tamperByte); + else + tamper_rpc_request(arg, offset, rand() % 0xFF); + +} + +static void +parsing_tamper_rpc_parameter_datatype(void *arg) +{ + if (tamperByte != INVALID_TAMPER_BYTE) + tamper_rpc_request(arg, ((struct TdsMessageWrapper *) arg)->offset, tamperByte); + else + tamper_rpc_request(arg, ((struct TdsMessageWrapper *) arg)->offset, rand() % 0xFF); +} + +static void +throw_error(void *arg) +{ + elog(ERROR, "error triggered from fault injection"); +} + +/* + * Type declarations + * + * Format: {Enum type, Type name, Callback list} + * + * 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 declarations + * + * Format: {Test name, Type name, 0, Callback function} + * + * Test name: name of the test used to trigger this fault + * 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}, + {"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}, + {"", 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 new file mode 100644 index 00000000000..6a546a60603 --- /dev/null +++ b/contrib/babelfishpg_tds/src/backend/tds/err_handler.c @@ -0,0 +1,324 @@ +#include + +#include "postgres.h" + +#include "common/hashfn.h" +#include "miscadmin.h" +#include "nodes/bitmapset.h" +#include "utils/elog.h" +#include "utils/hsearch.h" +#include "utils/palloc.h" /* Needed for pstrdup() */ + +#include "src/include/tds_int.h" +#include "src/include/tds_response.h" +#include "src/include/err_handler.h" +#include "src/include/tds_instr.h" + +static bool is_user_defined_error(int pg_error_code); + +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" + {"00000", NULL, 0, 0, NULL} +}; + +/* + * Returns list of sql error code for which Babel does have support for. + */ +int * +get_mapped_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]); + 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.*/ + tmp = bms_add_member(tmp, error_list[i].tsql_error_code); + tmp_len += 1; + } + } + + list = palloc0((tmp_len + 1) * sizeof(int)); + list[0] = tmp_len; + i = 1; + while ((prev_idx = bms_next_member(tmp, prev_idx)) >= 0) + { + list[i] = prev_idx; + i += 1; + } + + bms_free(tmp); + return list; +} + +/* + * load_err_code_mapping() - loads error code mapping details in HASH table. + */ +void +load_error_mapping() +{ + 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 ; + + 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); + + 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)); + map_info = (error_map_info) hash_search(error_map_hash, + &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; + tmp->tsql_error_code = error_list[i].tsql_error_code; + tmp->tsql_error_severity = error_list[i].tsql_error_severity; + tmp->next = head; + map_info->head = tmp; + } + else + { + 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; + map_info->head = tmp; + } + } +} + +bool +get_tsql_error_details(ErrorData *edata, + 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; + + /* 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; + *tsql_error_state = 1; + + return true; + } + + /* + * 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.sqlerrcode = edata->sqlerrcode; + + map_info = (error_map_info) hash_search(error_map_hash, + &key_info, + HASH_FIND, + &found); + + /* For all system generated errors, error state is default to be 1 */ + *tsql_error_state = 1; + + /* TODO: Ideally we should have mapping for every error. */ + if (!found) + { + *tsql_error_code = ERRCODE_PLTSQL_ERROR_NOT_MAPPED; + *tsql_error_severity = 16; + + 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); + + return false; + } + else + { + bool flag = false; + error_map_node *tmp = map_info->head; + + while (tmp) + { + if (!tmp->error_msg_keywords) + elog(FATAL, "Error message keyword is NULL (internal error)"); + + if (strlen(tmp->error_msg_keywords) == 0) + { + flag = true; + *tsql_error_code = tmp->tsql_error_code; + *tsql_error_severity = tmp->tsql_error_severity; + } + 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); + 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(). + */ + key_word = strtok(tmp_keywords, "#"); + while (key_word != NULL) + { + if (!strcasestr(edata->message, key_word)) + { + flag = false; + break; + } + key_word = strtok(NULL, "#"); + } + if (flag) + { + *tsql_error_code = tmp->tsql_error_code; + *tsql_error_severity = tmp->tsql_error_severity; + pfree(tmp_keywords); + return true; + } + pfree(tmp_keywords); + } + tmp = tmp->next; + } + /* + * 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); + + *tsql_error_code = ERRCODE_PLTSQL_ERROR_NOT_MAPPED; + *tsql_error_severity = 16; + return false; + } + } + return true; +} + +void +emit_tds_log(ErrorData *edata) +{ + 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 + * send the error to a psql client. So, turn it off. + */ + edata->output_to_client = false; + + /* If disabled, return from here */ + if (tds_disable_error_log_hook) + return; + + /* disable further entry to this function to avoid recursion */ + tds_disable_error_log_hook = true; + + if (edata->elevel < ERROR) + { + elog(DEBUG5, "suppressing informational client message < ERROR"); + + /* reset the flag */ + tds_disable_error_log_hook = false; + return; + } + + get_tsql_error_details(edata, &tsql_error_code, &tsql_error_sev, &tsql_error_state, "TDS"); + error_lineno = 1; + if (pltsql_plugin_handler_ptr && pltsql_plugin_handler_ptr->pltsql_current_lineno && *(pltsql_plugin_handler_ptr->pltsql_current_lineno) > 0) + error_lineno = *(pltsql_plugin_handler_ptr->pltsql_current_lineno); + + TdsSendError(tsql_error_code, tsql_error_state, tsql_error_sev, + edata->message, error_lineno); + + /* + * If we've not reached the main query loop yet, flush the error message + * immediately. + */ + if (!IsNormalProcessingMode()) + { + /* + * As of now, we can only reach here if we get any error during + * prelogin and login phase. + */ + TdsSendDone(TDS_TOKEN_DONE, TDS_DONE_ERROR, 0, 0); + TdsFlush(); + } + + /* reset the flag */ + tds_disable_error_log_hook = false; +} + + +void +reset_error_mapping_cache() +{ + error_map_hash = NULL; +} + +/* + * Define whether this is a user-defined error + */ +static bool +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 new file mode 100644 index 00000000000..77649655f1d --- /dev/null +++ b/contrib/babelfishpg_tds/src/backend/tds/guc.c @@ -0,0 +1,303 @@ +/*------------------------------------------------------------------------- + * + * guc.c + * TDS configuration variables + * + * Portions Copyright (c) 2020, AWS + * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * contrib/babelfishpg_tds/src/backend/tds/guc.c + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "miscadmin.h" +#include "utils/guc.h" + +#include "src/include/tds_int.h" +#include "src/include/tds_response.h" +#include "src/include/tds_secure.h" +#include "src/include/faultinjection.h" +#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; +bool tds_enable_db_session_property = true; +#ifdef FAULT_INJECTOR +static bool TdsFaultInjectionEnabled = false; +#endif + +const struct config_enum_entry ssl_protocol_versions_info[] = { + {"", PG_TLS_ANY, false}, + {"TLSv1", PG_TLS1_VERSION, false}, + {"TLSv1.1", PG_TLS1_1_VERSION, false}, + {"TLSv1.2", PG_TLS1_2_VERSION, false}, + {NULL, 0, false} +}; + +const struct config_enum_entry tds_protocol_versions_info[] = { + {"TDSv7.0", TDS_VERSION_7_0, false}, + {"TDSv7.1", TDS_VERSION_7_1, false}, + {"TDSv7.1.1", TDS_VERSION_7_1_1, false}, + {"TDSv7.2", TDS_VERSION_7_2, false}, + {"TDSv7.3A", TDS_VERSION_7_3_A, false}, + {"TDSv7.3B", TDS_VERSION_7_3_B, false}, + {"TDSv7.4", TDS_VERSION_7_4, false}, + {"DEFAULT", TDS_DEFAULT_VERSION, false}, + {NULL, 0, false} +}; + +/* -------------------------------- + * TdsSslProtocolMinVersionCheck - check for Tds ssl min Protocol Vesion GUC + * ------------------------------- + */ +static bool +TdsSslProtocolMinVersionCheck(int *newvalue, void **extra, GucSource source) +{ + if (*newvalue <= tds_ssl_max_protocol_version) + return true; + 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); + return false; + } +} + +/* -------------------------------- + * TdsSslProtocolMaxVersionCheck - check for Tds ssl max Protocol Vesion GUC + * ------------------------------- + */ +static bool +TdsSslProtocolMaxVersionCheck(int *newvalue, void **extra, GucSource source) +{ + if (*newvalue >= tds_ssl_min_protocol_version) + return true; + 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); + return false; + } +} + +/* -------------------------------- + * TdsGucDefaultPacketSizeCheck - Using this function to Assign the + * appropriate value to the GUC. In TDS, the packet + * Size is rounded down to the nearest multiple of 4. + * ------------------------------- + */ +static bool +TdsGucDefaultPacketSizeCheck(int *newvalue, void **extra, GucSource source) +{ + *newvalue = (((int) *newvalue / 4) * 4); + return true; +} + +/* + * Define various GUCs which are part of TDS protocol + */ +void +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); + + 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); + + 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); + + 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); + + 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); + + 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); + + 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); + + 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); + + 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); + + 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); + + 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); + + 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); + + 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); + + 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); + + DefineCustomBoolVariable( + "babelfishpg_tds.set_db_session_property", + gettext_noop("Set database session property on TDS connections"), + NULL, + &tds_enable_db_session_property, + true, + PGC_SUSET, + GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE, + 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); + 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 new file mode 100644 index 00000000000..a7a49f3aa19 --- /dev/null +++ b/contrib/babelfishpg_tds/src/backend/tds/support_funcs.c @@ -0,0 +1,632 @@ +/*------------------------------------------------------------------------- + * + * support_funcs.c + * Socket related support functions for loadable protocol extensions + * + * Copyright (c) 2021, PostgreSQL Global Development Group + * + * IDENTIFICATION + * contrib/babelfishpg_tds/src/backend/tds/support_funcs.c + * + *------------------------------------------------------------------------- + */ + +/*---- Function declarations ----*/ + +static void pe_create_server_ports(void); +static int pe_create_server_port(int family, const char *hostName, + unsigned short portNumber, + const char *unixSocketDir, + ProtocolExtensionConfig *protocol_config); +static int pe_create_connection(pgsocket server_fd, Port *port); + + +#ifdef HAVE_UNIX_SOCKETS +static int Lock_AF_UNIX(const char *unixSocketDir, const char *unixSocketPath); +static int Setup_AF_UNIX(const char *sock_path); +#endif /* HAVE_UNIX_SOCKETS */ + +/* + * pe_create_server_ports - create server ports as per config + */ +static void +pe_create_server_ports(void) +{ + int status; + bool listen_addr_saved = false; + + if (ListenAddresses) + { + char *rawstring; + List *elemlist; + ListCell *l; + int success = 0; + + /* Need a modifiable copy of ListenAddresses */ + //rawstring = pstrdup(pe_listen_addrs); + rawstring = pstrdup(ListenAddresses); + + /* Parse string into list of hostnames */ + if (!SplitGUCList(rawstring, ',', &elemlist)) + { + /* syntax error in list */ + ereport(FATAL, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid list syntax in parameter \"%s\"", + "listen_addresses"))); + } + + foreach(l, elemlist) + { + char *curhost = (char *) lfirst(l); + + if (strcmp(curhost, "*") == 0) + status = pe_create_server_port(AF_UNSPEC, NULL, + (unsigned short) pe_port, + NULL, + &pe_config); + else + status = pe_create_server_port(AF_UNSPEC, curhost, + (unsigned short) pe_port, + NULL, + &pe_config); + + if (status == STATUS_OK) + { + success++; + /* record the first successful host addr in lockfile */ + if (!listen_addr_saved) + { + AddToDataDirLockFile(LOCK_FILE_LINE_LISTEN_ADDR, curhost); + listen_addr_saved = true; + } + } + else + ereport(WARNING, + (errmsg("could not create listen socket for \"%s\"", + curhost))); + } + + if (!success && elemlist != NIL) + ereport(WARNING, + (errmsg("could not create any TCP/IP sockets to accept TDS connections"))); + + list_free(elemlist); + pfree(rawstring); + } +} + + +/* + * pe_create_server_port -- open a "listening" port to accept connections. + * Implementation copied from StreamClose() in src/backend/libpq/pqcomm.c + * + * family should be AF_UNIX or AF_UNSPEC; portNumber is the port number. + * For AF_UNIX ports, hostName should be NULL and unixSocketDir must be + * specified. For TCP ports, hostName is either NULL for all interfaces or + * the interface to listen on, and unixSocketDir is ignored (can be NULL). + * + * Successfully opened sockets are added to the ListenSocket[] array (of + * length MaxListen), at the first position that isn't PGINVALID_SOCKET. + * + * RETURNS: STATUS_OK or STATUS_ERROR + * + * NOTE: This is mostly a copy of StreamServerPort() + */ + +static int +pe_create_server_port(int family, const char *hostName, + unsigned short portNumber, + const char *unixSocketDir, + ProtocolExtensionConfig *protocol_config) + +{ + pgsocket fd; + int err; + int maxconn; + int ret; + char portNumberStr[32]; + const char *familyDesc; + char familyDescBuf[64]; + const char *addrDesc; + char addrBuf[NI_MAXHOST]; + char *service; + struct addrinfo *addrs = NULL, + *addr; + struct addrinfo hint; + int added = 0; + +#ifdef HAVE_UNIX_SOCKETS + char unixSocketPath[MAXPGPATH]; +#endif +#if !defined(WIN32) || defined(IPV6_V6ONLY) + int one = 1; +#endif + + /* Initialize hint structure */ + MemSet(&hint, 0, sizeof(hint)); + hint.ai_family = family; + hint.ai_flags = AI_PASSIVE; + hint.ai_socktype = SOCK_STREAM; + +#ifdef HAVE_UNIX_SOCKETS + if (family == AF_UNIX) + { + /* + * Create unixSocketPath from portNumber and unixSocketDir and lock + * that file path + */ + UNIXSOCK_PATH(unixSocketPath, portNumber, unixSocketDir); + if (strlen(unixSocketPath) >= UNIXSOCK_PATH_BUFLEN) + { + ereport(LOG, + (errmsg("Unix-domain socket path \"%s\" is too long (maximum %d bytes)", + unixSocketPath, + (int) (UNIXSOCK_PATH_BUFLEN - 1)))); + return STATUS_ERROR; + } + if (Lock_AF_UNIX(unixSocketDir, unixSocketPath) != STATUS_OK) + return STATUS_ERROR; + service = unixSocketPath; + } + else +#endif /* HAVE_UNIX_SOCKETS */ + { + snprintf(portNumberStr, sizeof(portNumberStr), "%d", portNumber); + service = portNumberStr; + } + + ret = pg_getaddrinfo_all(hostName, service, &hint, &addrs); + if (ret || !addrs) + { + if (hostName) + ereport(LOG, + (errmsg("could not translate host name \"%s\", service \"%s\" to address: %s", + hostName, service, gai_strerror(ret)))); + else + ereport(LOG, + (errmsg("could not translate service \"%s\" to address: %s", + service, gai_strerror(ret)))); + if (addrs) + pg_freeaddrinfo_all(hint.ai_family, addrs); + return STATUS_ERROR; + } + + for (addr = addrs; addr; addr = addr->ai_next) + { + if (!IS_AF_UNIX(family) && IS_AF_UNIX(addr->ai_family)) + { + /* + * Only set up a unix domain socket when they really asked for it. + * The service/port is different in that case. + */ + continue; + } + + /* See if there is still room to add 1 more socket. */ + if (!listen_have_free_slot()) + break; + + /* set up address family name for log messages */ + switch (addr->ai_family) + { + case AF_INET: + familyDesc = _("IPv4"); + break; +#ifdef HAVE_IPV6 + case AF_INET6: + familyDesc = _("IPv6"); + break; +#endif +#ifdef HAVE_UNIX_SOCKETS + case AF_UNIX: + familyDesc = _("Unix"); + break; +#endif + default: + snprintf(familyDescBuf, sizeof(familyDescBuf), + _("unrecognized address family %d"), + addr->ai_family); + familyDesc = familyDescBuf; + break; + } + + /* set up text form of address for log messages */ +#ifdef HAVE_UNIX_SOCKETS + if (addr->ai_family == AF_UNIX) + addrDesc = unixSocketPath; + else +#endif + { + pg_getnameinfo_all((const struct sockaddr_storage *) addr->ai_addr, + addr->ai_addrlen, + addrBuf, sizeof(addrBuf), + NULL, 0, + NI_NUMERICHOST); + addrDesc = addrBuf; + } + + if ((fd = socket(addr->ai_family, SOCK_STREAM, 0)) == PGINVALID_SOCKET) + { + ereport(LOG, + (errcode_for_socket_access(), + /* translator: first %s is IPv4, IPv6, or Unix */ + errmsg("could not create %s socket for address \"%s\": %m", + familyDesc, addrDesc))); + continue; + } + +#ifndef WIN32 + + /* + * Without the SO_REUSEADDR flag, a new postmaster can't be started + * right away after a stop or crash, giving "address already in use" + * error on TCP ports. + * + * On win32, however, this behavior only happens if the + * SO_EXCLUSIVEADDRUSE is set. With SO_REUSEADDR, win32 allows + * multiple servers to listen on the same address, resulting in + * unpredictable behavior. With no flags at all, win32 behaves as Unix + * with SO_REUSEADDR. + */ + if (!IS_AF_UNIX(addr->ai_family)) + { + if ((setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, + (char *) &one, sizeof(one))) == -1) + { + ereport(LOG, + (errcode_for_socket_access(), + /* translator: first %s is IPv4, IPv6, or Unix */ + errmsg("setsockopt(SO_REUSEADDR) failed for %s address \"%s\": %m", + familyDesc, addrDesc))); + closesocket(fd); + continue; + } + } +#endif + +#ifdef IPV6_V6ONLY + if (addr->ai_family == AF_INET6) + { + if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, + (char *) &one, sizeof(one)) == -1) + { + ereport(LOG, + (errcode_for_socket_access(), + /* translator: first %s is IPv4, IPv6, or Unix */ + errmsg("setsockopt(IPV6_V6ONLY) failed for %s address \"%s\": %m", + familyDesc, addrDesc))); + closesocket(fd); + continue; + } + } +#endif + + /* + * Note: This might fail on some OS's, like Linux older than + * 2.4.21-pre3, that don't have the IPV6_V6ONLY socket option, and map + * ipv4 addresses to ipv6. It will show ::ffff:ipv4 for all ipv4 + * connections. + */ + err = bind(fd, addr->ai_addr, addr->ai_addrlen); + if (err < 0) + { + int saved_errno = errno; + + ereport(LOG, + (errcode_for_socket_access(), + /* translator: first %s is IPv4, IPv6, or Unix */ + errmsg("could not bind %s address \"%s\": %m", + familyDesc, addrDesc), + saved_errno == EADDRINUSE ? + (IS_AF_UNIX(addr->ai_family) ? + errhint("Is another postmaster already running on port %d?", + (int) portNumber) : + errhint("Is another postmaster already running on port %d?" + " If not, wait a few seconds and retry.", + (int) portNumber)) : 0)); + closesocket(fd); + continue; + } + +#ifdef HAVE_UNIX_SOCKETS + if (addr->ai_family == AF_UNIX) + { + if (Setup_AF_UNIX(service) != STATUS_OK) + { + closesocket(fd); + break; + } + } +#endif + + /* + * Select appropriate accept-queue length limit. PG_SOMAXCONN is only + * intended to provide a clamp on the request on platforms where an + * overly large request provokes a kernel error (are there any?). + */ + maxconn = MaxBackends * 2; + if (maxconn > PG_SOMAXCONN) + maxconn = PG_SOMAXCONN; + + err = listen(fd, maxconn); + if (err < 0) + { + ereport(LOG, + (errcode_for_socket_access(), + /* translator: first %s is IPv4, IPv6, or Unix */ + errmsg("could not listen on %s address \"%s\": %m", + familyDesc, addrDesc))); + closesocket(fd); + continue; + } + +#ifdef HAVE_UNIX_SOCKETS + if (addr->ai_family == AF_UNIX) + ereport(LOG, + (errmsg("listening on Unix socket \"%s\"", + addrDesc))); + else +#endif + ereport(LOG, + /* translator: first %s is IPv4 or IPv6 */ + (errmsg("listening on %s address \"%s\", port %d", + familyDesc, addrDesc, (int) portNumber))); + + listen_add_socket(fd, protocol_config); + added++; + } + + pg_freeaddrinfo_all(hint.ai_family, addrs); + + if (!added) + return STATUS_ERROR; + + return STATUS_OK; +} + +#ifdef HAVE_UNIX_SOCKETS + +/* + * Lock_AF_UNIX -- configure unix socket file path + * Implementation copied from Lock_AF_UNIX() in + * src/backend/libpq/pqcomm.c + */ +static int +Lock_AF_UNIX(const char *unixSocketDir, const char *unixSocketPath) +{ + /* no lock file for abstract sockets */ + if (unixSocketPath[0] == '@') + return STATUS_OK; + + /* + * Grab an interlock file associated with the socket file. + * + * Note: there are two reasons for using a socket lock file, rather than + * trying to interlock directly on the socket itself. First, it's a lot + * more portable, and second, it lets us remove any pre-existing socket + * file without race conditions. + */ + CreateSocketLockFile(unixSocketPath, true, unixSocketDir); + + /* + * Once we have the interlock, we can safely delete any pre-existing + * socket file to avoid failure at bind() time. + */ + (void) unlink(unixSocketPath); + + /* + * Remember socket file pathnames for later maintenance. + */ + sock_paths = lappend(sock_paths, pstrdup(unixSocketPath)); + + return STATUS_OK; +} + + +/* + * Setup_AF_UNIX -- configure unix socket permissions + * Implementation copied from Setup_AF_UNIX() in + * src/backend/libpq/pqcomm.c + */ +static int +Setup_AF_UNIX(const char *sock_path) +{ + /* no file system permissions for abstract sockets */ + if (sock_path[0] == '@') + return STATUS_OK; + + /* + * Fix socket ownership/permission if requested. Note we must do this + * before we listen() to avoid a window where unwanted connections could + * get accepted. + */ + Assert(pe_unix_socket_group); + if (pe_unix_socket_group[0] != '\0') + { +#ifdef WIN32 + elog(WARNING, "configuration item unix_socket_group is not supported on this platform"); +#else + char *endptr; + unsigned long val; + gid_t gid; + + val = strtoul(pe_unix_socket_group, &endptr, 10); + if (*endptr == '\0') + { /* numeric group id */ + gid = val; + } + else + { /* convert group name to id */ + struct group *gr; + + gr = getgrnam(pe_unix_socket_group); + if (!gr) + { + ereport(LOG, + (errmsg("group \"%s\" does not exist", + pe_unix_socket_group))); + return STATUS_ERROR; + } + gid = gr->gr_gid; + } + if (chown(sock_path, -1, gid) == -1) + { + ereport(LOG, + (errcode_for_file_access(), + errmsg("could not set group of file \"%s\": %m", + sock_path))); + return STATUS_ERROR; + } +#endif + } + + if (chmod(sock_path, pe_unix_socket_permissions) == -1) + { + ereport(LOG, + (errcode_for_file_access(), + errmsg("could not set permissions of file \"%s\": %m", + sock_path))); + return STATUS_ERROR; + } + return STATUS_OK; +} +#endif /* HAVE_UNIX_SOCKETS */ + +/* + * pe_create_connection -- create a new connection with client using + * server port. Set port->sock to the FD of the new connection. + * Implementation copied from StreamConnection() in + * src/backend/libpq/pqcomm.c + * + * ASSUME: that this doesn't need to be non-blocking because + * the Postmaster uses select() to tell when the socket is ready for + * accept(). + * + * RETURNS: STATUS_OK or STATUS_ERROR + * + * NOTE: this is mostly a copy of StreamConnection + */ +int +pe_create_connection(pgsocket server_fd, Port *port) +{ + /* accept connection and fill in the client (remote) address */ + port->raddr.salen = sizeof(port->raddr.addr); + if ((port->sock = accept(server_fd, + (struct sockaddr *) &port->raddr.addr, + &port->raddr.salen)) == PGINVALID_SOCKET) + { + ereport(LOG, + (errcode_for_socket_access(), + errmsg("could not accept new connection: %m"))); + + /* + * If accept() fails then postmaster.c will still see the server + * socket as read-ready, and will immediately try again. To avoid + * uselessly sucking lots of CPU, delay a bit before trying again. + * (The most likely reason for failure is being out of kernel file + * table slots; we can do little except hope some will get freed up.) + */ + pg_usleep(100000L); /* wait 0.1 sec */ + return STATUS_ERROR; + } + + /* fill in the server (local) address */ + port->laddr.salen = sizeof(port->laddr.addr); + if (getsockname(port->sock, + (struct sockaddr *) &port->laddr.addr, + &port->laddr.salen) < 0) + { + ereport(LOG, + (errmsg("getsockname() failed: %m"))); + return STATUS_ERROR; + } + + /* select NODELAY and KEEPALIVE options if it's a TCP connection */ + if (!IS_AF_UNIX(port->laddr.addr.ss_family)) + { + int on; +#ifdef WIN32 + int oldopt; + int optlen; + int newopt; +#endif + +#ifdef TCP_NODELAY + on = 1; + if (setsockopt(port->sock, IPPROTO_TCP, TCP_NODELAY, + (char *) &on, sizeof(on)) < 0) + { + ereport(LOG, + (errmsg("setsockopt(%s) failed: %m", "TCP_NODELAY"))); + return STATUS_ERROR; + } +#endif + on = 1; + if (setsockopt(port->sock, SOL_SOCKET, SO_KEEPALIVE, + (char *) &on, sizeof(on)) < 0) + { + ereport(LOG, + (errmsg("setsockopt(%s) failed: %m", "SO_KEEPALIVE"))); + return STATUS_ERROR; + } + +#ifdef WIN32 + + /* + * This is a Win32 socket optimization. The OS send buffer should be + * large enough to send the whole Postgres send buffer in one go, or + * performance suffers. The Postgres send buffer can be enlarged if a + * very large message needs to be sent, but we won't attempt to + * enlarge the OS buffer if that happens, so somewhat arbitrarily + * ensure that the OS buffer is at least PQ_SEND_BUFFER_SIZE * 4. + * (That's 32kB with the current default). + * + * The default OS buffer size used to be 8kB in earlier Windows + * versions, but was raised to 64kB in Windows 2012. So it shouldn't + * be necessary to change it in later versions anymore. Changing it + * unnecessarily can even reduce performance, because setting + * SO_SNDBUF in the application disables the "dynamic send buffering" + * feature that was introduced in Windows 7. So before fiddling with + * SO_SNDBUF, check if the current buffer size is already large enough + * and only increase it if necessary. + * + * See https://support.microsoft.com/kb/823764/EN-US/ and + * https://msdn.microsoft.com/en-us/library/bb736549%28v=vs.85%29.aspx + */ + optlen = sizeof(oldopt); + if (getsockopt(port->sock, SOL_SOCKET, SO_SNDBUF, (char *) &oldopt, + &optlen) < 0) + { + ereport(LOG, + (errmsg("getsockopt(%s) failed: %m", "SO_SNDBUF"))); + return STATUS_ERROR; + } + newopt = PQ_SEND_BUFFER_SIZE * 4; + if (oldopt < newopt) + { + if (setsockopt(port->sock, SOL_SOCKET, SO_SNDBUF, (char *) &newopt, + sizeof(newopt)) < 0) + { + ereport(LOG, + (errmsg("setsockopt(%s) failed: %m", "SO_SNDBUF"))); + return STATUS_ERROR; + } + } +#endif + + /* + * Also apply the current keepalive parameters. If we fail to set a + * parameter, don't error out, because these aren't universally + * supported. (Note: you might think we need to reset the GUC + * variables to 0 in such a case, but it's not necessary because the + * show hooks for these variables report the truth anyway.) + */ + (void) pq_setkeepalivesidle(tcp_keepalives_idle, port); + (void) pq_setkeepalivesinterval(tcp_keepalives_interval, port); + (void) pq_setkeepalivescount(tcp_keepalives_count, port); + (void) pq_settcpusertimeout(tcp_user_timeout, port); + } + + return STATUS_OK; +} diff --git a/contrib/babelfishpg_tds/src/backend/tds/tds-secure-openssl.c b/contrib/babelfishpg_tds/src/backend/tds/tds-secure-openssl.c new file mode 100644 index 00000000000..89de9daaaf9 --- /dev/null +++ b/contrib/babelfishpg_tds/src/backend/tds/tds-secure-openssl.c @@ -0,0 +1,1442 @@ +/*------------------------------------------------------------------------- + * + * tds-secure-openssl.c + * functions for OpenSSL support in the backend. + * + * + * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * contrib/babelfishpg_tds/src/backend/tds/tds-be-secure-openssl.c + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_NETINET_TCP_H +#include +#include +#endif + +#ifdef USE_OPENSSL +#include +#include +#include +#endif +#ifndef OPENSSL_NO_ECDH +#include +#endif + +#include "libpq/libpq.h" +#include "miscadmin.h" +#include "pgstat.h" +#include "storage/fd.h" +#include "storage/latch.h" +#include "tcop/tcopprot.h" +#include "utils/memutils.h" + +#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); +#if 0 // Register tds specific function +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 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 const char *SSLerrmessage(unsigned long ecode); + + +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 int ssl_protocol_version_to_openssl(int v, const char *guc_name, + int loglevel); +#ifndef SSL_CTX_set_min_proto_version +static int SSL_CTX_set_min_proto_version(SSL_CTX *ctx, int version); +static int SSL_CTX_set_max_proto_version(SSL_CTX *ctx, int version); +#endif + +/* ------------------------------------------------------------ */ +/* Public interface */ +/* ------------------------------------------------------------ */ +int +Tds_be_tls_init(bool isServerStart) +{ + STACK_OF(X509_NAME) *root_cert_list = NULL; + SSL_CTX *context; + + /* This stuff need be done only once. */ + if (!SSL_initialized) + { +#ifdef HAVE_OPENSSL_INIT_SSL + OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, NULL); +#else + OPENSSL_config(NULL); + SSL_library_init(); + SSL_load_error_strings(); +#endif + SSL_initialized = true; + } + + /* + * We use SSLv23_method() because it can negotiate use of the highest + * mutually supported protocol version, while alternatives like + * TLSv1_2_method() permit only one specific version. Note that we don't + * actually allow SSL v2 or v3, only TLS protocols (see below). + */ + context = SSL_CTX_new(SSLv23_method()); + if (!context) + { + ereport(isServerStart ? FATAL : LOG, + (errmsg("could not create SSL context: %s", + SSLerrmessage(ERR_get_error())))); + goto error; + } + + /* + * Disable OpenSSL's moving-write-buffer sanity check, because it causes + * unnecessary failures in nonblocking send cases. + */ + SSL_CTX_set_mode(context, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); + + /* + * Set password callback + */ + if (isServerStart) + { + if (ssl_passphrase_command[0]) + SSL_CTX_set_default_passwd_cb(context, ssl_external_passwd_cb); + } + else + { + if (ssl_passphrase_command[0] && ssl_passphrase_command_supports_reload) + SSL_CTX_set_default_passwd_cb(context, ssl_external_passwd_cb); + else + + /* + * If reloading and no external command is configured, override + * OpenSSL's default handling of passphrase-protected files, + * because we don't want to prompt for a passphrase in an + * already-running server. + */ + SSL_CTX_set_default_passwd_cb(context, dummy_ssl_passwd_cb); + } + /* used by the callback */ + ssl_is_server_start = isServerStart; + + /* + * Load and verify server's certificate and private key + */ + if (SSL_CTX_use_certificate_chain_file(context, ssl_cert_file) != 1) + { + ereport(isServerStart ? FATAL : LOG, + (errcode(ERRCODE_CONFIG_FILE_ERROR), + errmsg("could not load server certificate file \"%s\": %s", + ssl_cert_file, SSLerrmessage(ERR_get_error())))); + goto error; + } + + if (!check_ssl_key_file_permissions(ssl_key_file, isServerStart)) + goto error; + + /* + * OK, try to load the private key file. + */ + dummy_ssl_passwd_cb_called = false; + + if (SSL_CTX_use_PrivateKey_file(context, + ssl_key_file, + SSL_FILETYPE_PEM) != 1) + { + if (dummy_ssl_passwd_cb_called) + ereport(isServerStart ? FATAL : LOG, + (errcode(ERRCODE_CONFIG_FILE_ERROR), + errmsg("private key file \"%s\" cannot be reloaded because it requires a passphrase", + ssl_key_file))); + else + ereport(isServerStart ? FATAL : LOG, + (errcode(ERRCODE_CONFIG_FILE_ERROR), + errmsg("could not load private key file \"%s\": %s", + ssl_key_file, SSLerrmessage(ERR_get_error())))); + goto error; + } + + if (SSL_CTX_check_private_key(context) != 1) + { + ereport(isServerStart ? FATAL : LOG, + (errcode(ERRCODE_CONFIG_FILE_ERROR), + errmsg("check of private key failed: %s", + SSLerrmessage(ERR_get_error())))); + goto error; + } + + if (tds_ssl_min_protocol_version) + { + int ssl_ver = ssl_protocol_version_to_openssl(tds_ssl_min_protocol_version, + "ssl_min_protocol_version", + isServerStart ? FATAL : LOG); + if (ssl_ver == -1) + goto error; + if (!SSL_CTX_set_min_proto_version(context, ssl_ver)) + { + ereport(isServerStart ? FATAL : LOG, + (errmsg("could not set minimum SSL protocol version"))); + goto error; + } + } + + if (tds_ssl_max_protocol_version) + { + int ssl_ver = ssl_protocol_version_to_openssl(tds_ssl_max_protocol_version, + "tds_ssl_max_protocol_version", + isServerStart ? FATAL : LOG); + if (ssl_ver == -1) + goto error; + if (!SSL_CTX_set_max_proto_version(context, ssl_ver)) + { + ereport(isServerStart ? FATAL : LOG, + (errmsg("could not set maximum SSL protocol version"))); + goto error; + } + } + + /* disallow SSL session tickets */ +#ifdef SSL_OP_NO_TICKET /* added in OpenSSL 0.9.8f */ + SSL_CTX_set_options(context, SSL_OP_NO_TICKET); +#endif + + /* disallow SSL session caching, too */ + SSL_CTX_set_session_cache_mode(context, SSL_SESS_CACHE_OFF); + + /* set up ephemeral DH and ECDH keys */ + if (!initialize_dh(context, isServerStart)) + goto error; + if (!initialize_ecdh(context, isServerStart)) + goto error; + + /* set up the allowed cipher list */ + if (SSL_CTX_set_cipher_list(context, SSLCipherSuites) != 1) + { + ereport(isServerStart ? FATAL : LOG, + (errcode(ERRCODE_CONFIG_FILE_ERROR), + errmsg("could not set the cipher list (no valid ciphers available)"))); + goto error; + } + + /* Let server choose order */ + if (SSLPreferServerCiphers) + SSL_CTX_set_options(context, SSL_OP_CIPHER_SERVER_PREFERENCE); + + /* + * Load CA store, so we can verify client certificates if needed. + */ + if (ssl_ca_file[0]) + { + if (SSL_CTX_load_verify_locations(context, ssl_ca_file, NULL) != 1 || + (root_cert_list = SSL_load_client_CA_file(ssl_ca_file)) == NULL) + { + ereport(isServerStart ? FATAL : LOG, + (errcode(ERRCODE_CONFIG_FILE_ERROR), + errmsg("could not load root certificate file \"%s\": %s", + ssl_ca_file, SSLerrmessage(ERR_get_error())))); + goto error; + } + } + + /*---------- + * Load the Certificate Revocation List (CRL). + * http://searchsecurity.techtarget.com/sDefinition/0,,sid14_gci803160,00.html + *---------- + */ + if (ssl_crl_file[0]) + { + X509_STORE *cvstore = SSL_CTX_get_cert_store(context); + + if (cvstore) + { + /* Set the flags to check against the complete CRL chain */ + if (X509_STORE_load_locations(cvstore, ssl_crl_file, NULL) == 1) + { + /* OpenSSL 0.96 does not support X509_V_FLAG_CRL_CHECK */ +#ifdef X509_V_FLAG_CRL_CHECK + X509_STORE_set_flags(cvstore, + X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); +#else + ereport(LOG, + (errcode(ERRCODE_CONFIG_FILE_ERROR), + errmsg("SSL certificate revocation list file \"%s\" ignored", + ssl_crl_file), + errdetail("SSL library does not support certificate revocation lists."))); +#endif + } + else + { + ereport(isServerStart ? FATAL : LOG, + (errcode(ERRCODE_CONFIG_FILE_ERROR), + errmsg("could not load SSL certificate revocation list file \"%s\": %s", + ssl_crl_file, SSLerrmessage(ERR_get_error())))); + goto error; + } + } + } +#if 0 // TDS specific + /* TDS specific - TSQL doesn't support multual certificate authentication */ + if (ssl_ca_file[0]) + { + /* + * Always ask for SSL client cert, but don't fail if it's not + * presented. We might fail such connections later, depending on what + * we find in pg_hba.conf. + */ + SSL_CTX_set_verify(context, + (SSL_VERIFY_PEER | + SSL_VERIFY_CLIENT_ONCE), + verify_cb); + + /* + * Tell OpenSSL to send the list of root certs we trust to clients in + * CertificateRequests. This lets a client with a keystore select the + * appropriate client certificate to send to us. + */ + SSL_CTX_set_client_CA_list(context, root_cert_list); + } +#endif + /* + * Success! Replace any existing SSL_context. + */ + if (SSL_context) + SSL_CTX_free(SSL_context); + + SSL_context = context; + + ssl_loaded_verify_locations = false; +#if 0 // TDS specific + /* + * Set flag to remember whether CA store has been loaded into SSL_context. + */ + if (ssl_ca_file[0]) + ssl_loaded_verify_locations = true; + else + ssl_loaded_verify_locations = false; +#endif + return 0; + +error: + if (context) + SSL_CTX_free(context); + return -1; +} + +void +Tds_be_tls_destroy(void) +{ + if (SSL_context) + SSL_CTX_free(SSL_context); + SSL_context = NULL; + ssl_loaded_verify_locations = false; +} + +int +Tds_be_tls_open_server(Port *port) +{ + int r; + int err; + int waitfor; + unsigned long ecode; + + Assert(!port->ssl); + Assert(!port->peer); + + if (!SSL_context) + { + ereport(COMMERROR, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("could not initialize SSL connection: SSL context not set up"))); + return -1; + } + + if (!(port->ssl = SSL_new(SSL_context))) + { + ereport(COMMERROR, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("could not initialize SSL connection: %s", + SSLerrmessage(ERR_get_error())))); + return -1; + } + if (!my_SSL_set_fd(port, port->sock)) + { + ereport(COMMERROR, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("could not set SSL socket: %s", + SSLerrmessage(ERR_get_error())))); + return -1; + } + port->ssl_in_use = true; + +aloop: + + /* + * Prepare to call SSL_get_error() by clearing thread's OpenSSL error + * queue. In general, the current thread's error queue must be empty + * before the TLS/SSL I/O operation is attempted, or SSL_get_error() will + * not work reliably. An extension may have failed to clear the + * per-thread error queue following another call to an OpenSSL I/O + * routine. + */ + ERR_clear_error(); + r = SSL_accept(port->ssl); + if (r <= 0) + { + err = SSL_get_error(port->ssl, r); + + /* + * Other clients of OpenSSL in the backend may fail to call + * ERR_get_error(), but we always do, so as to not cause problems for + * OpenSSL clients that don't call ERR_clear_error() defensively. Be + * sure that this happens by calling now. SSL_get_error() relies on + * the OpenSSL per-thread error queue being intact, so this is the + * earliest possible point ERR_get_error() may be called. + */ + ecode = ERR_get_error(); + switch (err) + { + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: + /* not allowed during connection establishment */ + Assert(!port->noblock); + + /* + * No need to care about timeouts/interrupts here. At this + * point authentication_timeout still employs + * StartupPacketTimeoutHandler() which directly exits. + */ + if (err == SSL_ERROR_WANT_READ) + waitfor = WL_SOCKET_READABLE | WL_EXIT_ON_PM_DEATH; + else + waitfor = WL_SOCKET_WRITEABLE | WL_EXIT_ON_PM_DEATH; + + (void) WaitLatchOrSocket(MyLatch, waitfor, port->sock, 0, + WAIT_EVENT_SSL_OPEN_SERVER); + goto aloop; + case SSL_ERROR_SYSCALL: + if (r < 0) + ereport(COMMERROR, + (errcode_for_socket_access(), + errmsg("could not accept SSL connection: %m"))); + else + ereport(COMMERROR, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("could not accept SSL connection: EOF detected"))); + break; + case SSL_ERROR_SSL: + ereport(COMMERROR, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("could not accept SSL connection: %s", + SSLerrmessage(ecode)))); + break; + case SSL_ERROR_ZERO_RETURN: + ereport(COMMERROR, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("could not accept SSL connection: EOF detected"))); + break; + default: + ereport(COMMERROR, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("unrecognized SSL error code: %d", + err))); + break; + } + return -1; + } + + /* TDS specific post SSL function register */ +#ifdef HAVE_BIO_METH_NEW + BIO_meth_set_read(my_bio_methods, my_sock_read); + BIO_meth_set_write(my_bio_methods, my_sock_write); +#else + my_bio_methods->bread = my_sock_read; + my_bio_methods->bwrite = my_sock_write; +#endif + + + /* Get client certificate, if available. */ + port->peer = SSL_get_peer_certificate(port->ssl); + + /* and extract the Common Name from it. */ + port->peer_cn = NULL; + port->peer_cert_valid = false; + if (port->peer != NULL) + { + int len; + + len = X509_NAME_get_text_by_NID(X509_get_subject_name(port->peer), + NID_commonName, NULL, 0); + if (len != -1) + { + char *peer_cn; + + peer_cn = MemoryContextAlloc(TopMemoryContext, len + 1); + r = X509_NAME_get_text_by_NID(X509_get_subject_name(port->peer), + NID_commonName, peer_cn, len + 1); + peer_cn[len] = '\0'; + if (r != len) + { + /* shouldn't happen */ + pfree(peer_cn); + return -1; + } + + /* + * Reject embedded NULLs in certificate common name to prevent + * attacks like CVE-2009-4034. + */ + if (len != strlen(peer_cn)) + { + ereport(COMMERROR, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("SSL certificate's common name contains embedded null"))); + pfree(peer_cn); + return -1; + } + + port->peer_cn = peer_cn; + } + port->peer_cert_valid = true; + } + + /* set up debugging/info callback */ + SSL_CTX_set_info_callback(SSL_context, info_cb); + + return 0; +} + +void +Tds_be_tls_close(Port *port) +{ + if (port->ssl) + { + SSL_shutdown(port->ssl); + SSL_free(port->ssl); + port->ssl = NULL; + port->ssl_in_use = false; + } + + if (port->peer) + { + X509_free(port->peer); + port->peer = NULL; + } + + if (port->peer_cn) + { + pfree(port->peer_cn); + port->peer_cn = NULL; + } +} + +ssize_t +Tds_be_tls_read(Port *port, void *ptr, size_t len, int *waitfor) +{ + ssize_t n; + int err; + unsigned long ecode; + + errno = 0; + ERR_clear_error(); + n = SSL_read(port->ssl, ptr, len); + err = SSL_get_error(port->ssl, n); + ecode = (err != SSL_ERROR_NONE || n < 0) ? ERR_get_error() : 0; + switch (err) + { + case SSL_ERROR_NONE: + /* a-ok */ + break; + case SSL_ERROR_WANT_READ: + *waitfor = WL_SOCKET_READABLE; + errno = EWOULDBLOCK; + n = -1; + break; + case SSL_ERROR_WANT_WRITE: + *waitfor = WL_SOCKET_WRITEABLE; + errno = EWOULDBLOCK; + n = -1; + break; + case SSL_ERROR_SYSCALL: + /* leave it to caller to ereport the value of errno */ + if (n != -1) + { + errno = ECONNRESET; + n = -1; + } + break; + case SSL_ERROR_SSL: + ereport(COMMERROR, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("SSL error: %s", SSLerrmessage(ecode)))); + errno = ECONNRESET; + n = -1; + break; + case SSL_ERROR_ZERO_RETURN: + /* connection was cleanly shut down by peer */ + n = 0; + break; + default: + ereport(COMMERROR, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("unrecognized SSL error code: %d", + err))); + errno = ECONNRESET; + n = -1; + break; + } + + return n; +} + +ssize_t +Tds_be_tls_write(Port *port, void *ptr, size_t len, int *waitfor) +{ + ssize_t n; + int err; + unsigned long ecode; + + errno = 0; + ERR_clear_error(); + n = SSL_write(port->ssl, ptr, len); + err = SSL_get_error(port->ssl, n); + ecode = (err != SSL_ERROR_NONE || n < 0) ? ERR_get_error() : 0; + switch (err) + { + case SSL_ERROR_NONE: + /* a-ok */ + break; + case SSL_ERROR_WANT_READ: + *waitfor = WL_SOCKET_READABLE; + errno = EWOULDBLOCK; + n = -1; + break; + case SSL_ERROR_WANT_WRITE: + *waitfor = WL_SOCKET_WRITEABLE; + errno = EWOULDBLOCK; + n = -1; + break; + case SSL_ERROR_SYSCALL: + /* leave it to caller to ereport the value of errno */ + if (n != -1) + { + errno = ECONNRESET; + n = -1; + } + break; + case SSL_ERROR_SSL: + ereport(COMMERROR, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("SSL error: %s", SSLerrmessage(ecode)))); + errno = ECONNRESET; + n = -1; + break; + case SSL_ERROR_ZERO_RETURN: + + /* + * the SSL connection was closed, leave it to the caller to + * ereport it + */ + errno = ECONNRESET; + n = -1; + break; + default: + ereport(COMMERROR, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("unrecognized SSL error code: %d", + err))); + errno = ECONNRESET; + n = -1; + break; + } + + return n; +} + +/* ------------------------------------------------------------ */ +/* Internal functions */ +/* ------------------------------------------------------------ */ + +/* + * Private substitute BIO: this does the sending and receiving using send() and + * recv() instead. This is so that we can enable and disable interrupts + * just while calling recv(). We cannot have interrupts occurring while + * the bulk of OpenSSL runs, because it uses malloc() and possibly other + * non-reentrant libc facilities. We also need to call send() and recv() + * directly so it gets passed through the socket/signals layer on Win32. + * + * These functions are closely modelled on the standard socket BIO in OpenSSL; + * see sock_read() and sock_write() in OpenSSL's crypto/bio/bss_sock.c. + * XXX OpenSSL 1.0.1e considers many more errcodes than just EINTR as reasons + * to retry; do we need to adopt their logic for that? + */ + +#ifndef HAVE_BIO_GET_DATA +#define BIO_get_data(bio) (bio->ptr) +#define BIO_set_data(bio, data) (bio->ptr = data) +#endif + +static int +my_sock_read(BIO *h, char *buf, int size) +{ + int res = 0; + + if (buf != NULL) + { + res = secure_raw_read(((Port *) BIO_get_data(h)), buf, size); + BIO_clear_retry_flags(h); + if (res <= 0) + { + /* If we were interrupted, tell caller to retry */ + if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) + { + BIO_set_retry_read(h); + } + } + } + + return res; +} + +static int +my_sock_write(BIO *h, const char *buf, int size) +{ + int res = 0; + + res = secure_raw_write(((Port *) BIO_get_data(h)), buf, size); + BIO_clear_retry_flags(h); + if (res <= 0) + { + /* If we were interrupted, tell caller to retry */ + if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) + { + BIO_set_retry_write(h); + } + } + + return res; +} + +#if 0 +static BIO_METHOD * +my_BIO_s_socket(void) +{ + if (!my_bio_methods) + { + BIO_METHOD *biom = (BIO_METHOD *) BIO_s_socket(); +#ifdef HAVE_BIO_METH_NEW + int my_bio_index; + + my_bio_index = BIO_get_new_index(); + if (my_bio_index == -1) + return NULL; + my_bio_methods = BIO_meth_new(my_bio_index, "PostgreSQL backend socket"); + if (!my_bio_methods) + return NULL; + if (!BIO_meth_set_write(my_bio_methods, my_sock_write) || + !BIO_meth_set_read(my_bio_methods, my_sock_read) || + !BIO_meth_set_gets(my_bio_methods, BIO_meth_get_gets(biom)) || + !BIO_meth_set_puts(my_bio_methods, BIO_meth_get_puts(biom)) || + !BIO_meth_set_ctrl(my_bio_methods, BIO_meth_get_ctrl(biom)) || + !BIO_meth_set_create(my_bio_methods, BIO_meth_get_create(biom)) || + !BIO_meth_set_destroy(my_bio_methods, BIO_meth_get_destroy(biom)) || + !BIO_meth_set_callback_ctrl(my_bio_methods, BIO_meth_get_callback_ctrl(biom))) + { + BIO_meth_free(my_bio_methods); + my_bio_methods = NULL; + return NULL; + } +#else + my_bio_methods = malloc(sizeof(BIO_METHOD)); + if (!my_bio_methods) + return NULL; + memcpy(my_bio_methods, biom, sizeof(BIO_METHOD)); + my_bio_methods->bread = my_sock_read; + my_bio_methods->bwrite = my_sock_write; +#endif + } + return my_bio_methods; +} +#endif + +/* This should exactly match OpenSSL's SSL_set_fd except for using my BIO */ +static int +my_SSL_set_fd(Port *port, int fd) +{ + int ret = 0; + BIO *bio; + BIO_METHOD *bio_method; + + /* Tds specific SSL function register */ + bio_method = TdsBioSecureSocket(my_bio_methods); + my_bio_methods = bio_method; + + if (bio_method == NULL) + { + SSLerr(SSL_F_SSL_SET_FD, ERR_R_BUF_LIB); + goto err; + } + bio = BIO_new(bio_method); + + if (bio == NULL) + { + SSLerr(SSL_F_SSL_SET_FD, ERR_R_BUF_LIB); + goto err; + } + BIO_set_data(bio, port); + + BIO_set_fd(bio, fd, BIO_NOCLOSE); + SSL_set_bio(port->ssl, bio, bio); + ret = 1; +err: + return ret; +} + +/* + * Load precomputed DH parameters. + * + * To prevent "downgrade" attacks, we perform a number of checks + * to verify that the DBA-generated DH parameters file contains + * what we expect it to contain. + */ +static DH * +load_dh_file(char *filename, bool isServerStart) +{ + FILE *fp; + DH *dh = NULL; + int codes; + + /* attempt to open file. It's not an error if it doesn't exist. */ + if ((fp = AllocateFile(filename, "r")) == NULL) + { + ereport(isServerStart ? FATAL : LOG, + (errcode_for_file_access(), + errmsg("could not open DH parameters file \"%s\": %m", + filename))); + return NULL; + } + + dh = PEM_read_DHparams(fp, NULL, NULL, NULL); + FreeFile(fp); + + if (dh == NULL) + { + ereport(isServerStart ? FATAL : LOG, + (errcode(ERRCODE_CONFIG_FILE_ERROR), + errmsg("could not load DH parameters file: %s", + SSLerrmessage(ERR_get_error())))); + return NULL; + } + + /* make sure the DH parameters are usable */ + if (DH_check(dh, &codes) == 0) + { + ereport(isServerStart ? FATAL : LOG, + (errcode(ERRCODE_CONFIG_FILE_ERROR), + errmsg("invalid DH parameters: %s", + SSLerrmessage(ERR_get_error())))); + return NULL; + } + if (codes & DH_CHECK_P_NOT_PRIME) + { + ereport(isServerStart ? FATAL : LOG, + (errcode(ERRCODE_CONFIG_FILE_ERROR), + errmsg("invalid DH parameters: p is not prime"))); + return NULL; + } + if ((codes & DH_NOT_SUITABLE_GENERATOR) && + (codes & DH_CHECK_P_NOT_SAFE_PRIME)) + { + ereport(isServerStart ? FATAL : LOG, + (errcode(ERRCODE_CONFIG_FILE_ERROR), + errmsg("invalid DH parameters: neither suitable generator or safe prime"))); + return NULL; + } + + return dh; +} + +/* + * Load hardcoded DH parameters. + * + * To prevent problems if the DH parameters files don't even + * exist, we can load DH parameters hardcoded into this file. + */ +static DH * +load_dh_buffer(const char *buffer, size_t len) +{ + BIO *bio; + DH *dh = NULL; + + bio = BIO_new_mem_buf(unconstify(char *, buffer), len); + if (bio == NULL) + return NULL; + dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); + if (dh == NULL) + ereport(DEBUG2, + (errmsg_internal("DH load buffer: %s", + SSLerrmessage(ERR_get_error())))); + BIO_free(bio); + + return dh; +} + +/* + * Passphrase collection callback using ssl_passphrase_command + */ +static int +ssl_external_passwd_cb(char *buf, int size, int rwflag, void *userdata) +{ + /* same prompt as OpenSSL uses internally */ + const char *prompt = "Enter PEM pass phrase:"; + + Assert(rwflag == 0); + + return run_ssl_passphrase_command(prompt, ssl_is_server_start, buf, size); +} + +/* + * Dummy passphrase callback + * + * If OpenSSL is told to use a passphrase-protected server key, by default + * it will issue a prompt on /dev/tty and try to read a key from there. + * That's no good during a postmaster SIGHUP cycle, not to mention SSL context + * reload in an EXEC_BACKEND postmaster child. So override it with this dummy + * function that just returns an empty passphrase, guaranteeing failure. + */ +static int +dummy_ssl_passwd_cb(char *buf, int size, int rwflag, void *userdata) +{ + /* Set flag to change the error message we'll report */ + dummy_ssl_passwd_cb_called = true; + /* And return empty string */ + Assert(size > 0); + buf[0] = '\0'; + return 0; +} + +#if 0 +/* + * Certificate verification callback + * + * This callback allows us to log intermediate problems during + * verification, but for now we'll see if the final error message + * contains enough information. + * + * This callback also allows us to override the default acceptance + * criteria (e.g., accepting self-signed or expired certs), but + * for now we accept the default checks. + */ +static int +verify_cb(int ok, X509_STORE_CTX *ctx) +{ + return ok; +} +#endif + +/* + * This callback is used to copy SSL information messages + * into the PostgreSQL log. + */ +static void +info_cb(const SSL *ssl, int type, int args) +{ + switch (type) + { + case SSL_CB_HANDSHAKE_START: + ereport(DEBUG4, + (errmsg_internal("SSL: handshake start"))); + break; + case SSL_CB_HANDSHAKE_DONE: + ereport(DEBUG4, + (errmsg_internal("SSL: handshake done"))); + break; + case SSL_CB_ACCEPT_LOOP: + ereport(DEBUG4, + (errmsg_internal("SSL: accept loop"))); + break; + case SSL_CB_ACCEPT_EXIT: + ereport(DEBUG4, + (errmsg_internal("SSL: accept exit (%d)", args))); + break; + case SSL_CB_CONNECT_LOOP: + ereport(DEBUG4, + (errmsg_internal("SSL: connect loop"))); + break; + case SSL_CB_CONNECT_EXIT: + ereport(DEBUG4, + (errmsg_internal("SSL: connect exit (%d)", args))); + break; + case SSL_CB_READ_ALERT: + ereport(DEBUG4, + (errmsg_internal("SSL: read alert (0x%04x)", args))); + break; + case SSL_CB_WRITE_ALERT: + ereport(DEBUG4, + (errmsg_internal("SSL: write alert (0x%04x)", args))); + break; + } +} + +/* + * Set DH parameters for generating ephemeral DH keys. The + * DH parameters can take a long time to compute, so they must be + * precomputed. + * + * Since few sites will bother to create a parameter file, we also + * provide a fallback to the parameters provided by the OpenSSL + * project. + * + * These values can be static (once loaded or computed) since the + * OpenSSL library can efficiently generate random keys from the + * information provided. + */ +static bool +initialize_dh(SSL_CTX *context, bool isServerStart) +{ + DH *dh = NULL; + + SSL_CTX_set_options(context, SSL_OP_SINGLE_DH_USE); + + if (ssl_dh_params_file[0]) + dh = load_dh_file(ssl_dh_params_file, isServerStart); + if (!dh) + dh = load_dh_buffer(FILE_DH2048, sizeof(FILE_DH2048)); + if (!dh) + { + ereport(isServerStart ? FATAL : LOG, + (errcode(ERRCODE_CONFIG_FILE_ERROR), + (errmsg("DH: could not load DH parameters")))); + return false; + } + + if (SSL_CTX_set_tmp_dh(context, dh) != 1) + { + ereport(isServerStart ? FATAL : LOG, + (errcode(ERRCODE_CONFIG_FILE_ERROR), + (errmsg("DH: could not set DH parameters: %s", + SSLerrmessage(ERR_get_error()))))); + return false; + } + return true; +} + +/* + * Set ECDH parameters for generating ephemeral Elliptic Curve DH + * keys. This is much simpler than the DH parameters, as we just + * need to provide the name of the curve to OpenSSL. + */ +static bool +initialize_ecdh(SSL_CTX *context, bool isServerStart) +{ +#ifndef OPENSSL_NO_ECDH + EC_KEY *ecdh; + int nid; + + nid = OBJ_sn2nid(SSLECDHCurve); + if (!nid) + { + ereport(isServerStart ? FATAL : LOG, + (errcode(ERRCODE_CONFIG_FILE_ERROR), + errmsg("ECDH: unrecognized curve name: %s", SSLECDHCurve))); + return false; + } + + ecdh = EC_KEY_new_by_curve_name(nid); + if (!ecdh) + { + ereport(isServerStart ? FATAL : LOG, + (errcode(ERRCODE_CONFIG_FILE_ERROR), + errmsg("ECDH: could not create key"))); + return false; + } + + SSL_CTX_set_options(context, SSL_OP_SINGLE_ECDH_USE); + SSL_CTX_set_tmp_ecdh(context, ecdh); + EC_KEY_free(ecdh); +#endif + + return true; +} + +/* + * Obtain reason string for passed SSL errcode + * + * ERR_get_error() is used by caller to get errcode to pass here. + * + * Some caution is needed here since ERR_reason_error_string will + * return NULL if it doesn't recognize the error code. We don't + * want to return NULL ever. + */ +static const char * +SSLerrmessage(unsigned long ecode) +{ + const char *errreason; + static char errbuf[36]; + + if (ecode == 0) + return _("no SSL error reported"); + errreason = ERR_reason_error_string(ecode); + if (errreason != NULL) + return errreason; + snprintf(errbuf, sizeof(errbuf), _("SSL error code %lu"), ecode); + return errbuf; +} + +#if 0 +int +be_tls_get_cipher_bits(Port *port) +{ + int bits; + + if (port->ssl) + { + SSL_get_cipher_bits(port->ssl, &bits); + return bits; + } + else + return 0; +} + +bool +be_tls_get_compression(Port *port) +{ + if (port->ssl) + return (SSL_get_current_compression(port->ssl) != NULL); + else + return false; +} + +const char * +be_tls_get_version(Port *port) +{ + if (port->ssl) + return SSL_get_version(port->ssl); + else + return NULL; +} + +const char * +be_tls_get_cipher(Port *port) +{ + if (port->ssl) + return SSL_get_cipher(port->ssl); + else + return NULL; +} + +void +be_tls_get_peer_subject_name(Port *port, char *ptr, size_t len) +{ + if (port->peer) + strlcpy(ptr, X509_NAME_to_cstring(X509_get_subject_name(port->peer)), len); + else + ptr[0] = '\0'; +} + +void +be_tls_get_peer_issuer_name(Port *port, char *ptr, size_t len) +{ + if (port->peer) + strlcpy(ptr, X509_NAME_to_cstring(X509_get_issuer_name(port->peer)), len); + else + ptr[0] = '\0'; +} + +void +be_tls_get_peer_serial(Port *port, char *ptr, size_t len) +{ + if (port->peer) + { + ASN1_INTEGER *serial; + BIGNUM *b; + char *decimal; + + serial = X509_get_serialNumber(port->peer); + b = ASN1_INTEGER_to_BN(serial, NULL); + decimal = BN_bn2dec(b); + + BN_free(b); + strlcpy(ptr, decimal, len); + OPENSSL_free(decimal); + } + else + ptr[0] = '\0'; +} + +#ifdef HAVE_X509_GET_SIGNATURE_NID +char * +be_tls_get_certificate_hash(Port *port, size_t *len) +{ + X509 *server_cert; + char *cert_hash; + const EVP_MD *algo_type = NULL; + unsigned char hash[EVP_MAX_MD_SIZE]; /* size for SHA-512 */ + unsigned int hash_size; + int algo_nid; + + *len = 0; + server_cert = SSL_get_certificate(port->ssl); + if (server_cert == NULL) + return NULL; + + /* + * Get the signature algorithm of the certificate to determine the hash + * algorithm to use for the result. + */ + if (!OBJ_find_sigid_algs(X509_get_signature_nid(server_cert), + &algo_nid, NULL)) + elog(ERROR, "could not determine server certificate signature algorithm"); + + /* + * The TLS server's certificate bytes need to be hashed with SHA-256 if + * its signature algorithm is MD5 or SHA-1 as per RFC 5929 + * (https://tools.ietf.org/html/rfc5929#section-4.1). If something else + * is used, the same hash as the signature algorithm is used. + */ + switch (algo_nid) + { + case NID_md5: + case NID_sha1: + algo_type = EVP_sha256(); + break; + default: + algo_type = EVP_get_digestbynid(algo_nid); + if (algo_type == NULL) + elog(ERROR, "could not find digest for NID %s", + OBJ_nid2sn(algo_nid)); + break; + } + + /* generate and save the certificate hash */ + if (!X509_digest(server_cert, algo_type, hash, &hash_size)) + elog(ERROR, "could not generate server certificate hash"); + + cert_hash = palloc(hash_size); + memcpy(cert_hash, hash, hash_size); + *len = hash_size; + + return cert_hash; +} +#endif + +/* + * Convert an X509 subject name to a cstring. + * + */ +static char * +X509_NAME_to_cstring(X509_NAME *name) +{ + BIO *membuf = BIO_new(BIO_s_mem()); + int i, + nid, + count = X509_NAME_entry_count(name); + X509_NAME_ENTRY *e; + ASN1_STRING *v; + const char *field_name; + size_t size; + char nullterm; + char *sp; + char *dp; + char *result; + + (void) BIO_set_close(membuf, BIO_CLOSE); + for (i = 0; i < count; i++) + { + e = X509_NAME_get_entry(name, i); + nid = OBJ_obj2nid(X509_NAME_ENTRY_get_object(e)); + v = X509_NAME_ENTRY_get_data(e); + field_name = OBJ_nid2sn(nid); + if (!field_name) + field_name = OBJ_nid2ln(nid); + BIO_printf(membuf, "/%s=", field_name); + ASN1_STRING_print_ex(membuf, v, + ((ASN1_STRFLGS_RFC2253 & ~ASN1_STRFLGS_ESC_MSB) + | ASN1_STRFLGS_UTF8_CONVERT)); + } + + /* ensure null termination of the BIO's content */ + nullterm = '\0'; + BIO_write(membuf, &nullterm, 1); + size = BIO_get_mem_data(membuf, &sp); + dp = pg_any_to_server(sp, size - 1, PG_UTF8); + + result = pstrdup(dp); + if (dp != sp) + pfree(dp); + BIO_free(membuf); + + return result; +} +#endif + +/* + * Convert TLS protocol version GUC enum to OpenSSL values + * + * This is a straightforward one-to-one mapping, but doing it this way makes + * guc.c independent of OpenSSL availability and version. + * + * If a version is passed that is not supported by the current OpenSSL + * version, then we log with the given loglevel and return (if we return) -1. + * If a nonnegative value is returned, subsequent code can assume it's working + * with a supported version. + */ +static int +ssl_protocol_version_to_openssl(int v, const char *guc_name, int loglevel) +{ + switch (v) + { + case PG_TLS_ANY: + return 0; + case PG_TLS1_VERSION: + return TLS1_VERSION; + case PG_TLS1_1_VERSION: +#ifdef TLS1_1_VERSION + return TLS1_1_VERSION; +#else + break; +#endif + case PG_TLS1_2_VERSION: +#ifdef TLS1_2_VERSION + return TLS1_2_VERSION; +#else + break; +#endif + case PG_TLS1_3_VERSION: +#ifdef TLS1_3_VERSION + return TLS1_3_VERSION; +#else + break; +#endif + } + + ereport(loglevel, + (errmsg("%s setting %s not supported by this build", + guc_name, + GetConfigOption(guc_name, false, false)))); + return -1; +} + +/* + * Replacements for APIs present in newer versions of OpenSSL + */ +#ifndef SSL_CTX_set_min_proto_version + +/* + * OpenSSL versions that support TLS 1.3 shouldn't get here because they + * already have these functions. So we don't have to keep updating the below + * code for every new TLS version, and eventually it can go away. But let's + * just check this to make sure ... + */ +#ifdef TLS1_3_VERSION +#error OpenSSL version mismatch +#endif + +static int +SSL_CTX_set_min_proto_version(SSL_CTX *ctx, int version) +{ + int ssl_options = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3; + + if (version > TLS1_VERSION) + ssl_options |= SSL_OP_NO_TLSv1; + /* + * Some OpenSSL versions define TLS*_VERSION macros but not the + * corresponding SSL_OP_NO_* macro, so in those cases we have to return + * unsuccessfully here. + */ +#ifdef TLS1_1_VERSION + if (version > TLS1_1_VERSION) + { +#ifdef SSL_OP_NO_TLSv1_1 + ssl_options |= SSL_OP_NO_TLSv1_1; +#else + return 0; +#endif + } +#endif +#ifdef TLS1_2_VERSION + if (version > TLS1_2_VERSION) + { +#ifdef SSL_OP_NO_TLSv1_2 + ssl_options |= SSL_OP_NO_TLSv1_2; +#else + return 0; +#endif + } +#endif + + SSL_CTX_set_options(ctx, ssl_options); + + return 1; /* success */ +} + +static int +SSL_CTX_set_max_proto_version(SSL_CTX *ctx, int version) +{ + int ssl_options = 0; + + AssertArg(version != 0); + + /* + * Some OpenSSL versions define TLS*_VERSION macros but not the + * corresponding SSL_OP_NO_* macro, so in those cases we have to return + * unsuccessfully here. + */ +#ifdef TLS1_1_VERSION + if (version < TLS1_1_VERSION) + { +#ifdef SSL_OP_NO_TLSv1_1 + ssl_options |= SSL_OP_NO_TLSv1_1; +#else + return 0; +#endif + } +#endif +#ifdef TLS1_2_VERSION + if (version < TLS1_2_VERSION) + { +#ifdef SSL_OP_NO_TLSv1_2 + ssl_options |= SSL_OP_NO_TLSv1_2; +#else + return 0; +#endif + } +#endif + + SSL_CTX_set_options(ctx, ssl_options); + + return 1; /* success */ +} + +#endif /* !SSL_CTX_set_min_proto_version */ +#endif diff --git a/contrib/babelfishpg_tds/src/backend/tds/tds.c b/contrib/babelfishpg_tds/src/backend/tds/tds.c new file mode 100644 index 00000000000..53a162e3928 --- /dev/null +++ b/contrib/babelfishpg_tds/src/backend/tds/tds.c @@ -0,0 +1,124 @@ + +/*------------------------------------------------------------------------- + * + * tds.c + * TDS Listener extension entrypoint + * + * Portions Copyright (c) 2020, AWS + * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * contrib/babelfishpg_tds/src/backend/tds/tds.c + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "access/printtup.h" +#include "src/include/tds_int.h" +#include "src/include/tds_secure.h" +#include "src/include/tds_instr.h" +#include "commands/defrem.h" +#include "fmgr.h" +#include "miscadmin.h" +#include "libpq/libpq.h" +#include "libpq/libpq-be.h" +#include "miscadmin.h" +#include "parser/parse_expr.h" +#include "postmaster/postmaster.h" +#include "utils/elog.h" +#include "utils/pidfile.h" +#include "utils/lsyscache.h" + +#include "src/include/err_handler.h" + +PG_MODULE_MAGIC; + +extern void _PG_init(void); +extern void _PG_fini(void); + +TdsInstrPlugin **tds_instr_plugin_ptr = NULL; + +/* Hook for plugins */ +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 relname_lookup_hook_type prev_relname_lookup_hook = NULL; + +/* + * Module initialization function + */ +void +_PG_init(void) +{ + /* Be sure we do initialization only once */ + static bool inited = false; + + if (inited) + return; + + /* 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"))); + + TdsDefineGucs(); + + tds_instr_plugin_ptr = (TdsInstrPlugin **) find_rendezvous_variable("TdsInstrPlugin"); + + pe_init(); + + prev_relname_lookup_hook = relname_lookup_hook; + relname_lookup_hook = tvp_lookup; + + inited = true; +} + +/* + * Module unload function + */ +void +_PG_fini(void) +{ + pe_fin(); + relname_lookup_hook = prev_relname_lookup_hook; +} + +/* + * For table-valued parameter that's not handled by pltsql, we set up a hook so + * that we can look up a TVP's underlying table. + */ +static Oid +tvp_lookup(const char *relname, Oid relnamespace) +{ + Oid relid; + ListCell *lc; + + if (prev_relname_lookup_hook) + relid = (*prev_relname_lookup_hook) (relname, relnamespace); + else + 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. + */ + foreach (lc, tvp_lookup_list) + { + TvpLookupItem *item = (TvpLookupItem *) lfirst(lc); + + if (strcmp(relname, item->name) == 0) + { + if (OidIsValid(item->tableRelid)) + return item->tableRelid; + else + return get_relname_relid(item->tableName, relnamespace); + } + } + + return relid; +} diff --git a/contrib/babelfishpg_tds/src/backend/tds/tds_data_map.c b/contrib/babelfishpg_tds/src/backend/tds/tds_data_map.c new file mode 100644 index 00000000000..123af09c0c4 --- /dev/null +++ b/contrib/babelfishpg_tds/src/backend/tds/tds_data_map.c @@ -0,0 +1,221 @@ +#include "postgres.h" + +#include "mb/pg_wchar.h" +#include "access/attnum.h" +#include "lib/stringinfo.h" +#include "src/include/tds_typeio.h" +#include "src/include/tds_iofuncmap.h" + + +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 +}; + +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", "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}, + + /* 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} +}; + +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 new file mode 100644 index 00000000000..a98803c713f --- /dev/null +++ b/contrib/babelfishpg_tds/src/backend/tds/tds_srv.c @@ -0,0 +1,477 @@ +/*------------------------------------------------------------------------- + * + * tds_srv.c + * register wire protocol hooks for TDS + * + * Copyright (c) 2021, PostgreSQL Global Development Group + * + * IDENTIFICATION + * contrib/babelfishpg_tds/src/backend/tds/tds_srv.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include +#include +#include + +#include "commands/defrem.h" +#include "common/ip.h" +#include "miscadmin.h" +#include "parser/parse_expr.h" +#include "postmaster/postmaster.h" +#include "postmaster/protocol_extension.h" +#include "pgstat.h" +#include "storage/ipc.h" +#include "tcop/pquery.h" +#include "tcop/tcopprot.h" +#include "utils/guc.h" +#include "utils/pidfile.h" +#include "utils/portal.h" +#include "utils/ps_status.h" +#include "utils/timeout.h" +#include "utils/varlena.h" + +#include "src/include/tds_int.h" +#include "src/include/tds_secure.h" +#include "src/include/tds_protocol.h" +#include "src/include/tds_response.h" +#include "src/include/err_handler.h" +#include "src/include/guc.h" + +static listen_init_hook_type prev_listen_init; + +static bool LoadedSSL = false; + +/* Where the Unix socket files are (list of palloc'd strings) */ +static List *sock_paths = NIL; + +/* Declare the TDS context callback only once */ +static ErrorContextCallback tdserrcontext; + +TdsErrorContextData *TdsErrorContext = NULL; + +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 void pe_authenticate(Port *port, const char **username); +static void pe_mainfunc(Port *port, + int argc, char *argv[]) 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 void pe_end_command(QueryCompletion *qc, CommandDest dest); +static void socket_close(int code, Datum arg); + +/* the dest reveiver support is kept in a separate file */ +#include "tdsprinttup.c" + +static ProtocolExtensionConfig pe_config = { + pe_accept, + pe_close, + pe_tds_init, + pe_start, + pe_authenticate, + pe_mainfunc, + pe_send_message, + NULL, /* not interested in cancel key */ + NULL, + NULL, + pe_send_ready_for_query, + pe_read_command, + pe_end_command, + TdsPrintTup, + TdsPrinttupStartup, + TdsShutdown, + TdsDestroy, + pe_process_command +}; + +/* + * The generic socket support is kept in a separate file + */ +#include "support_funcs.c" + +void +pe_init(void) +{ +#ifdef USE_SSL + /* Server will be started when this extension will be loaded */ + if (EnableSSL) + if (Tds_be_tls_init(true) == 0) + LoadedSSL = true; +#endif + + /* Install hooks */ + prev_listen_init = listen_init_hook; + listen_init_hook = pe_listen_init; +} + +void +pe_fin(void) +{ + /* Uninstall hooks. */ + listen_init_hook = prev_listen_init; +} + +/* + * pe_listen_init - Create the telnet server socket(s) + */ +static void +pe_listen_init(void) +{ + pe_create_server_ports(); +} + +/* + * pe_accept - Accept a new incoming client connection + */ +static int +pe_accept(pgsocket server_fd, Port *port) +{ + return pe_create_connection(server_fd, port); +} + +/* + * pe_close - called to close server sockets in new backend + */ +static void +pe_close(pgsocket server_fd) +{ + StreamClose(server_fd); +} + +/* + * pe_init - equivalent of pq_init + */ +static void +pe_tds_init(void) +{ + PLtsql_protocol_plugin **pltsql_plugin_handler_ptr_tmp; + + /* This is client backend */ + MyBackendType = B_BACKEND; + + TdsClientInit(); + + /* + * If this is a TDS client, we install the TDS specific protocol function + * 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"); + + /* unlikely */ + if (!pltsql_plugin_handler_ptr_tmp) + elog(ERROR, "failed to setup rendezvous variable for pltsql plugin"); + + *pltsql_plugin_handler_ptr_tmp = pltsql_plugin_handler_ptr; + + memset(pltsql_plugin_handler_ptr, 0, sizeof(PLtsql_protocol_plugin)); + + pltsql_plugin_handler_ptr->send_info = &TdsSendInfo; + pltsql_plugin_handler_ptr->send_done = &TdsSendDone; + pltsql_plugin_handler_ptr->send_env_change = &TdsSendEnvChange; + pltsql_plugin_handler_ptr->get_tsql_error = &get_tsql_error_details; + pltsql_plugin_handler_ptr->stmt_beg = TDSStatementBeginCallback; + pltsql_plugin_handler_ptr->stmt_end = TDSStatementEndCallback; + pltsql_plugin_handler_ptr->stmt_exception = TDSStatementExceptionCallback; + pltsql_plugin_handler_ptr->send_column_metadata = SendColumnMetadata; + pltsql_plugin_handler_ptr->get_mapped_error_list = &get_mapped_error_code_list; + + pltsql_plugin_handler_ptr->get_login_domainname = &get_tds_login_domainname; + + /* set up process-exit hook to close the socket */ + on_proc_exit(socket_close, 0); +} + +/* + * pe_start - equivalent of ProcessStartupPacket() + * + * This function needs to communicate with the client + * at least to the point where it can fill in the + * database_name and user_name in the Port. It cannot + * do anything that would require actual database + * access. + */ +static int +pe_start(Port *port) +{ + int rc; + MemoryContext oldContext; + + /* we're ready to begin the communication with the TDS client */ + 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. + */ + oldContext = MemoryContextSwitchTo(TopMemoryContext); + TdsErrorContext = palloc(sizeof(TdsErrorContextData)); + MemoryContextSwitchTo(oldContext); + + /* Push the error context */ + tdserrcontext.callback = TdsErrorContextCallback; + tdserrcontext.arg = TdsErrorContext; + tdserrcontext.previous = error_context_stack; + error_context_stack = &tdserrcontext; + + rc = TdsProcessLogin(port, LoadedSSL); + + /* Pop the error context stack */ + error_context_stack = tdserrcontext.previous; + + return rc; +} + +static void +pe_authenticate(Port *port, const char **username) +{ + /* This should be set already, but let's make sure */ + ClientAuthInProgress = true; /* limit visibility of log messages */ + + /* + * In EXEC_BACKEND case, we didn't inherit the contents of pg_hba.conf + * etcetera from the postmaster, and have to load them ourselves. + * + * FIXME: [fork/exec] Ugh. Is there a way around this overhead? + */ +#ifdef EXEC_BACKEND + + /* + * load_hba() and load_ident() want to work within the PostmasterContext, + * so create that if it doesn't exist (which it won't). We'll delete it + * again later, in PostgresMain. + */ + if (PostmasterContext == NULL) + PostmasterContext = AllocSetContextCreate(TopMemoryContext, + MC_Postmaster, + ALLOCSET_DEFAULT_SIZES); + + if (!load_hba()) + { + /* + * It makes no sense to continue if we fail to load the HBA file, + * since there is no way to connect to the database in this case. + */ + ereport(FATAL, + (errmsg("could not load pg_hba.conf"))); + } + + if (!load_ident()) + { + /* + * It is ok to continue if we fail to load the IDENT file, although it + * means that you cannot log in using any of the authentication + * methods that need a user name mapping. load_ident() already logged + * the details of error to the log. + */ + } +#endif + + /* + * Perform authentication exchange. + */ + set_ps_display("authentication"); + + /* + * Set up a timeout in case a buggy or malicious client fails to respond + * during authentication. Since we're inside a transaction and might do + * database access, we have to use the statement_timeout infrastructure. + */ + enable_timeout_after(STATEMENT_TIMEOUT, AuthenticationTimeout * 1000); + + /* + * Now perform authentication exchange. + */ + TdsClientAuthentication(port); /* might not return, if failure */ + + /* + * Done with authentication. Disable the timeout, and log if needed. + */ + disable_timeout(STATEMENT_TIMEOUT, false); + + /* Log only if Log_connections is set. */ + if (Log_connections) + { + StringInfoData logmsg; + + initStringInfo(&logmsg); + appendStringInfo(&logmsg, _("connection authorized: user=%s,"), + port->user_name); + if (port->application_name) + appendStringInfo(&logmsg, _(" application=%s,"), + port->application_name); + + appendStringInfo(&logmsg, _(" Tds Version=0x%X."), GetClientTDSVersion()); + + ereport(LOG, errmsg_internal("%s", logmsg.data)); + pfree(logmsg.data); + } + + set_ps_display("startup"); + + ClientAuthInProgress = false; /* client_min_messages is active now */ + + *username = port->user_name; +} + +static void +pe_mainfunc(Port *port, int argc, char *argv[]) +{ + /* + * 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(argc, argv, port->database_name, + port->user_name); +} + +static void +pe_send_message(ErrorData *edata) +{ + if (edata->output_to_client) + emit_tds_log(edata); +} + +static void +pe_send_ready_for_query(CommandDest dest) +{ + /* + * If we've already sent the login ack and initialized the protocol, + * return from here. We're ready to process the next query. + */ + if (TdsRequestCtrl) + return; + + /* Push the error context */ + tdserrcontext.callback = TdsErrorContextCallback; + tdserrcontext.arg = TdsErrorContext; + tdserrcontext.previous = error_context_stack; + error_context_stack = &tdserrcontext; + + /* If first time, we should send the login ack */ + TdsSendLoginAck(MyProcPort); + + /* Pop the error context stack */ + error_context_stack = tdserrcontext.previous; +} + +static int +pe_read_command(StringInfo inBuf) +{ + int rc; + + /* Push the error context */ + tdserrcontext.callback = TdsErrorContextCallback; + tdserrcontext.arg = TdsErrorContext; + tdserrcontext.previous = error_context_stack; + error_context_stack = &tdserrcontext; + + rc = TdsSocketBackend(); + + /* Pop the error context stack */ + error_context_stack = tdserrcontext.previous; + return rc; +} + +static int +pe_process_command() +{ + int result; + + /* Push the error context */ + tdserrcontext.callback = TdsErrorContextCallback; + tdserrcontext.arg = TdsErrorContext; + tdserrcontext.previous = error_context_stack; + 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. + */ + if (!IsTransactionOrTransactionBlock()) + Cleanup_xact_PgStat(); + + /* Pop the error context stack */ + error_context_stack = tdserrcontext.previous; + return result; +} + +static void +pe_end_command(QueryCompletion *qc, CommandDest dest) +{ + /* no-op */ +} + +/* -------------------------------- + * socket_close - shutdown TDS at backend exit + * + * This is same as socket_close() in pqcomm.c, but for a TDS backend. + * -------------------------------- + */ +static void +socket_close(int code, Datum arg) +{ + /* Nothing to do in a standalone backend, where MyProcPort is NULL. */ + if (MyProcPort != NULL) + { +#ifdef ENABLE_GSS + /* + * Shutdown GSSAPI layer. This section does nothing when interrupting + * BackendInitialize(), because pg_GSS_recvauth() makes first use of + * "ctx" and "cred". + * + * Note that we don't bother to free MyProcPort->gss, since we're + * about to exit anyway. + */ + if (MyProcPort->gss) + { + OM_uint32 min_s; + + if (MyProcPort->gss->ctx != GSS_C_NO_CONTEXT) + gss_delete_sec_context(&min_s, &MyProcPort->gss->ctx, NULL); + + if (MyProcPort->gss->cred != GSS_C_NO_CREDENTIAL) + gss_release_cred(&min_s, &MyProcPort->gss->cred); + } +#endif /* ENABLE_GSS */ + + /* + * Cleanly shut down SSL layer. Nowhere else does a postmaster child + * call this, so this is safe when interrupting BackendInitialize(). + */ +#ifdef USE_SSL + if (MyProcPort->ssl_in_use) + Tds_be_tls_close(MyProcPort); +#endif + + /* + * Formerly we did an explicit close() here, but it seems better to + * leave the socket open until the process dies. This allows clients + * to perform a "synchronous close" if they care --- wait till the + * transport layer reports connection closure, and you can be sure the + * backend has exited. + * + * We do set sock to PGINVALID_SOCKET to prevent any further I/O, + * though. + */ + MyProcPort->sock = PGINVALID_SOCKET; + } +} diff --git a/contrib/babelfishpg_tds/src/backend/tds/tdsbulkload.c b/contrib/babelfishpg_tds/src/backend/tds/tdsbulkload.c new file mode 100644 index 00000000000..e5b308b96ce --- /dev/null +++ b/contrib/babelfishpg_tds/src/backend/tds/tdsbulkload.c @@ -0,0 +1,691 @@ +/*------------------------------------------------------------------------- + * + * tdsbulkload.c + * TDS Listener functions for handling Bulk Load Requests + * + * Portions Copyright (c) 2020, AWS + * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * contrib/babelfishpg_tds/src/backend/tds/tdsbulkload.c + * + *------------------------------------------------------------------------- + */ + + +#include "postgres.h" + +#include "utils/guc.h" +#include "lib/stringinfo.h" +#include "pgstat.h" + +#include "src/include/tds_instr.h" +#include "src/include/tds_int.h" +#include "src/include/tds_protocol.h" +#include "src/include/tds_request.h" +#include "src/include/tds_response.h" +#include "src/include/tds_typeio.h" + +static void SetBulkLoadRowData(TDSRequestBulkLoad request, const StringInfo message, uint64_t offset); +void ProcessBCPRequest(TDSRequest request); + +/* Check if retStatus Not OK. */ +#define CheckPLPStatusNotOK(temp, retStatus, colNum) \ +do \ +{ \ + if (retStatus != STATUS_OK) \ + { \ + 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 chunking format is incorrect for a " \ + "large object parameter of data type 0x%02X.", \ + temp->rowCount, colNum + 1, temp->colMetaData[i].columnTdsType))); \ + } \ +} while(0) + + +/* For checking the invalid length in the request. */ +#define CheckForInvalidLength(rowData, temp, colNum) \ +do \ +{ \ + if ((uint32_t)rowData->columnValues[i].len > (uint32_t)temp->colMetaData[i].maxLen) \ + 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: Data type 0x%02X has an invalid data length or metadata length.", \ + temp->rowCount, colNum + 1, temp->colMetaData[i].columnTdsType))); \ +} while(0) + +/* + * GetBulkLoadRequest - Builds the request structure associated + * with Bulk Load. + * TODO: Reuse for TVP. + */ +TDSRequest +GetBulkLoadRequest(StringInfo message) +{ + TDSRequestBulkLoad request; + uint16_t colCount; + BulkLoadColMetaData *colmetadata; + uint64_t offset = 0; + + 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; + + 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."))); + + offset++; + + memcpy(&colCount, &message->data[offset], sizeof(uint16)); + colmetadata = palloc0(colCount * sizeof(BulkLoadColMetaData)); + request->colCount = colCount; + request->colMetaData = colmetadata; + offset += sizeof(uint16); + + for (int currentColumn = 0; currentColumn < colCount; currentColumn++) + { + /* UserType */ + memcpy(&colmetadata[currentColumn].userType, &message->data[offset], sizeof(uint32_t)); + offset += sizeof(uint32_t); + + /* Flags */ + memcpy(&colmetadata[currentColumn].flags, &message->data[offset], sizeof(uint16)); + offset += sizeof(uint16); + + /* TYPE_INFO */ + colmetadata[currentColumn].columnTdsType = message->data[offset++]; + + /* Datatype specific Column Metadata. */ + switch(colmetadata[currentColumn].columnTdsType) + { + case TDS_TYPE_INTEGER: + case TDS_TYPE_BIT: + case TDS_TYPE_FLOAT: + case TDS_TYPE_MONEYN: + case TDS_TYPE_DATETIMEN: + case TDS_TYPE_UNIQUEIDENTIFIER: + colmetadata[currentColumn].maxLen = message->data[offset++]; + break; + case TDS_TYPE_DECIMALN: + case TDS_TYPE_NUMERICN: + colmetadata[currentColumn].maxLen = message->data[offset++]; + colmetadata[currentColumn].precision = message->data[offset++]; + colmetadata[currentColumn].scale = message->data[offset++]; + break; + case TDS_TYPE_CHAR: + case TDS_TYPE_VARCHAR: + case TDS_TYPE_NCHAR: + case TDS_TYPE_NVARCHAR: + { + memcpy(&colmetadata[currentColumn].maxLen, &message->data[offset], sizeof(uint16)); + offset += sizeof(uint16); + + memcpy(&colmetadata[currentColumn].collation, &message->data[offset], sizeof(uint32_t)); + offset += sizeof(uint32_t); + colmetadata[currentColumn].sortId = message->data[offset++]; + } + break; + case TDS_TYPE_TEXT: + case TDS_TYPE_NTEXT: + case TDS_TYPE_IMAGE: + { + uint16_t tableLen = 0; + 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) + { + memcpy(&colmetadata[currentColumn].collation, &message->data[offset], sizeof(uint32_t)); + offset += sizeof(uint32_t); + colmetadata[currentColumn].sortId = message->data[offset++]; + } + + memcpy(&tableLen, &message->data[offset], sizeof(uint16_t)); + offset += sizeof(uint16_t); + + /* Skip table name for now. */ + offset += tableLen * 2; + } + break; + case TDS_TYPE_XML: + { + colmetadata[currentColumn].maxLen = message->data[offset++]; + } + break; + case TDS_TYPE_DATETIME2: + { + colmetadata[currentColumn].scale = message->data[offset++]; + colmetadata[currentColumn].maxLen = 8; + } + break; + case TDS_TYPE_TIME: + { + colmetadata[currentColumn].scale = message->data[offset++]; + colmetadata[currentColumn].maxLen = 5; + } + break; + case TDS_TYPE_DATETIMEOFFSET: + { + colmetadata[currentColumn].scale = message->data[offset++]; + colmetadata[currentColumn].maxLen = 10; + } + break; + case TDS_TYPE_BINARY: + case TDS_TYPE_VARBINARY: + { + uint16 plp; + memcpy(&plp, &message->data[offset], sizeof(uint16)); + offset += sizeof(uint16); + colmetadata[currentColumn].maxLen = plp; + } + break; + case TDS_TYPE_DATE: + colmetadata[currentColumn].maxLen = 3; + break; + case TDS_TYPE_SQLVARIANT: + 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. + */ + case VARIANT_TYPE_INT: + { + 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; + case VARIANT_TYPE_BIGINT: + { + 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; + case VARIANT_TYPE_TINYINT: + { + 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; + case VARIANT_TYPE_FLOAT: + { + 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; + case VARIANT_TYPE_SMALLDATETIME: + { + 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; + case VARIANT_TYPE_SMALLMONEY: + { + colmetadata[currentColumn].columnTdsType = TDS_TYPE_MONEYN; + colmetadata[currentColumn].variantType = true; + colmetadata[currentColumn].maxLen = TDS_MAXLEN_SMALLMONEY; + } + break; + default: + ereport(ERROR, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("The incoming tabular data stream (TDS) is incorrect. " + "Data type 0x%02X is unknown.", colmetadata[currentColumn].columnTdsType))); + } + + /* Column Name */ + memcpy(&colmetadata[currentColumn].colNameLen, &message->data[offset++], sizeof(uint8_t)); + 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].colName[colmetadata[currentColumn].colNameLen * 2] = '\0'; + + offset += colmetadata[currentColumn].colNameLen * 2; + } + + SetBulkLoadRowData(request, message, offset); + + return (TDSRequest)request; +} + +/* + * SetBulkLoadRowData - Builds the row data structure associated + * with Bulk Load. + * TODO: Reuse for TVP. + */ +static void +SetBulkLoadRowData(TDSRequestBulkLoad request, const StringInfo message, uint64_t offset) +{ + BulkLoadColMetaData *colmetadata = request->colMetaData; + char *messageData = message->data; + int retStatus = 0; + request->rowCount = 0; + request->rowData = NIL; + while((uint8_t)messageData[offset] == TDS_TOKEN_ROW) /* Loop over each row. */ + { + int i = 0; /* Current Column Number. */ + BulkLoadRowData *rowData = palloc0(sizeof(BulkLoadRowData)); + request->rowCount++; + retStatus += 1; + rowData->columnValues = palloc0(request->colCount * sizeof(StringInfoData)); + rowData->isNull = palloc0(request->colCount); + offset++; + while(i != request->colCount) /* Loop over each column. */ + { + initStringInfo(&rowData->columnValues[i]); + rowData->isNull[i] = 'f'; + switch(colmetadata[i].columnTdsType) + { + case TDS_TYPE_INTEGER: + case TDS_TYPE_BIT: + case TDS_TYPE_FLOAT: + case TDS_TYPE_TIME: + case TDS_TYPE_DATE: + case TDS_TYPE_DATETIME2: + case TDS_TYPE_DATETIMEN: + case TDS_TYPE_MONEYN: + case TDS_TYPE_UNIQUEIDENTIFIER: + { + if (colmetadata[i].variantType) + { + rowData->columnValues[i].len = colmetadata[i].maxLen; + } + else + { + rowData->columnValues[i].len = messageData[offset++]; + if (rowData->columnValues[i].len == 0) /* null */ + { + rowData->isNull[i] = 'n'; + i++; + continue; + } + } + CheckForInvalidLength(rowData, request, i); + + 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; + 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))); + rowData->columnValues[i].len = messageData[offset++]; + if (rowData->columnValues[i].len == 0) /* null */ + { + rowData->isNull[i] = 'n'; + i++; + continue; + } + + CheckForInvalidLength(rowData, request, i); + + 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; + + case TDS_TYPE_CHAR: + case TDS_TYPE_VARCHAR: + case TDS_TYPE_NCHAR: + 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); + if (rowData->columnValues[i].len != 0xffff) + { + CheckForInvalidLength(rowData, request, i); + + 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; + } + else /* null */ + { + rowData->isNull[i] = 'n'; + i++; + continue; + } + } + else + { + StringInfo plpStr; + ParameterToken temp = palloc0(sizeof(ParameterTokenData)); + retStatus = ReadPlp(temp, message, &offset); + CheckPLPStatusNotOK(request, retStatus, i); + if (temp->isNull) /* null */ + { + rowData->isNull[i] = 'n'; + i++; + temp->isNull = false; + continue; + } + + plpStr = TdsGetPlpStringInfoBufferFromToken(messageData, temp); + rowData->columnValues[i] = *plpStr; + pfree(plpStr); + pfree(temp); + } + } + break; + case TDS_TYPE_TEXT: + case TDS_TYPE_NTEXT: + case TDS_TYPE_IMAGE: + { + /* Ignore the Data Text Ptr since its currently of no use. */ + uint8 dataTextPtrLen = messageData[offset++]; + if (dataTextPtrLen == 0) /* null */ + { + rowData->isNull[i] = 'n'; + i++; + continue; + } + offset += dataTextPtrLen; + offset += 8; /* TODO: Ignored the Data Text TimeStamp for now. */ + + memcpy(&rowData->columnValues[i].len, &messageData[offset], sizeof(uint32_t)); + offset += sizeof(uint32_t); + if (rowData->columnValues[i].len == 0) /* null */ + { + rowData->isNull[i] = 'n'; + i++; + continue; + } + + CheckForInvalidLength(rowData, request, i); + + 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; + case TDS_TYPE_XML: + { + StringInfo plpStr; + ParameterToken temp = palloc0(sizeof(ParameterTokenData)); + retStatus = ReadPlp(temp, message, &offset); + CheckPLPStatusNotOK(request, retStatus, i); + if (temp->isNull) /* null */ + { + rowData->isNull[i] = 'n'; + i++; + temp->isNull = false; + continue; + } + + plpStr = TdsGetPlpStringInfoBufferFromToken(messageData, temp); + rowData->columnValues[i] = *plpStr; + pfree(plpStr); + pfree(temp); + } + 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) /* null */ + { + rowData->isNull[i] = 'n'; + i++; + continue; + } + + CheckForInvalidLength(rowData, request, i); + + 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; + } + i++; + } + request->rowData = lappend(request->rowData, rowData); + } + if ((uint8_t)messageData[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. " + "Row %d, column %d, unexpected token encountered processing the request. %d", + request->rowCount, request->colCount, (uint8_t)messageData[offset]))); + offset++; +} + +/* + * ProcessBCPRequest - Processes the request and calls the bulk_load_callback + * for futher execution. + * TODO: Reuse for TVP. + */ +void +ProcessBCPRequest(TDSRequest request) +{ + int retValue = 0; + StringInfo temp = makeStringInfo(); + TDSRequestBulkLoad req = (TDSRequestBulkLoad) request; + BulkLoadColMetaData *colMetaData = req->colMetaData; + + int nargs = req->colCount * req->rowCount; + Datum *values = palloc0(nargs * sizeof(Datum)); + char *nulls = palloc0(nargs * sizeof(char)); + Oid *argtypes= palloc0(nargs * sizeof(Oid)); + + int count = 0; + ListCell *lc; + + TdsErrorContext->err_text = "Processing Bulk Load Request"; + pgstat_report_activity(STATE_RUNNING, "Processing Bulk Load Request"); + + foreach (lc, req->rowData) /* build an array of Value Datums */ + { + BulkLoadRowData *row = (BulkLoadRowData *) lfirst(lc); + TdsIoFunctionInfo tempFuncInfo; + int currentColumn = 0; + + while(currentColumn != req->colCount) + { + temp = &(row->columnValues[currentColumn]); + tempFuncInfo = TdsLookupTypeFunctionsByTdsId(colMetaData[currentColumn].columnTdsType, colMetaData[currentColumn].maxLen); + GetPgOid(argtypes[count], tempFuncInfo); + if (row->isNull[currentColumn] == 'n') /* null */ + nulls[count] = row->isNull[currentColumn]; + else + switch(colMetaData[currentColumn].columnTdsType) + { + case TDS_TYPE_CHAR: + case TDS_TYPE_VARCHAR: + case TDS_TYPE_TEXT: + values[count] = TdsTypeVarcharToDatum(temp, argtypes[count], colMetaData[currentColumn].collation); + break; + case TDS_TYPE_NCHAR: + case TDS_TYPE_NVARCHAR: + case TDS_TYPE_NTEXT: + values[count] = TdsTypeNCharToDatum(temp); + break; + case TDS_TYPE_INTEGER: + case TDS_TYPE_BIT: + values[count] = TdsTypeIntegerToDatum(temp, colMetaData[currentColumn].maxLen); + break; + case TDS_TYPE_FLOAT: + values[count] = TdsTypeFloatToDatum(temp, colMetaData[currentColumn].maxLen); + break; + case TDS_TYPE_NUMERICN: + case TDS_TYPE_DECIMALN: + values[count] = TdsTypeNumericToDatum(temp, colMetaData[currentColumn].scale); + break; + case TDS_TYPE_VARBINARY: + case TDS_TYPE_BINARY: + case TDS_TYPE_IMAGE: + values[count] = TdsTypeVarbinaryToDatum(temp); + argtypes[count] = tempFuncInfo->ttmtypeid; + break; + case TDS_TYPE_DATE: + values[count] = TdsTypeDateToDatum(temp); + break; + case TDS_TYPE_TIME: + values[count] = TdsTypeTimeToDatum(temp, colMetaData[currentColumn].scale, temp->len); + break; + case TDS_TYPE_DATETIME2: + values[count] = TdsTypeDatetime2ToDatum(temp, colMetaData[currentColumn].scale, temp->len); + break; + case TDS_TYPE_DATETIMEN: + if (colMetaData[currentColumn].maxLen == TDS_MAXLEN_SMALLDATETIME) + values[count] = TdsTypeSmallDatetimeToDatum(temp); + else + values[count] = TdsTypeDatetimeToDatum(temp); + break; + case TDS_TYPE_DATETIMEOFFSET: + values[count] = TdsTypeDatetimeoffsetToDatum(temp, colMetaData[currentColumn].scale, temp->len); + break; + case TDS_TYPE_MONEYN: + if (colMetaData[currentColumn].maxLen == TDS_MAXLEN_SMALLMONEY) + values[count] = TdsTypeSmallMoneyToDatum(temp); + else + values[count] = TdsTypeMoneyToDatum(temp); + break; + case TDS_TYPE_XML: + values[count] = TdsTypeXMLToDatum(temp); + break; + case TDS_TYPE_UNIQUEIDENTIFIER: + values[count] = TdsTypeUIDToDatum(temp); + break; + case TDS_TYPE_SQLVARIANT: + values[count] = TdsTypeSqlVariantToDatum(temp); + break; + } + count++; + currentColumn++; + } + } + + 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, argtypes, + values, nulls); + } + PG_CATCH(); + { + 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))); + + PG_RE_THROW(); + } + PG_END_TRY(); + + } + + /* 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. */ + ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("Unknown error occurred during Insert Bulk"))); + + /* + * Log immediately if dictated by log_statement. + */ + 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))); + pltsql_plugin_handler_ptr->stmt_needs_logging = false; + error_context_stack = plerrcontext; + } + + /* Free the List of Rows. */ + list_free_deep(req->rowData); + if (values) + pfree(values); + if (nulls) + pfree(nulls); + if (argtypes) + pfree(argtypes); +} diff --git a/contrib/babelfishpg_tds/src/backend/tds/tdscomm.c b/contrib/babelfishpg_tds/src/backend/tds/tdscomm.c new file mode 100644 index 00000000000..c3e92c0e3c5 --- /dev/null +++ b/contrib/babelfishpg_tds/src/backend/tds/tdscomm.c @@ -0,0 +1,953 @@ +/*------------------------------------------------------------------------- + * + * tdscomm.c + * TDS Listener communication support Postgres + * + * Portions Copyright (c) 2020, AWS + * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * contrib/babelfishpg_tds/src/backend/tds/tdscomm.c + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "libpq/libpq.h" + +#include "miscadmin.h" /* for MyProcPort */ +#include "access/xact.h" /* for IsTransactionOrTransactionBlock() */ +#include "utils/memutils.h" +#include "utils/guc.h" +#include "port/pg_bswap.h" +#include "utils/guc.h" +#include "utils/memutils.h" + +#include "src/include/tds_debug.h" +#include "src/include/tds_int.h" +#include "src/include/faultinjection.h" + +/* Globals */ +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 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); + +/* Inline functions */ + +/* -------------------------------- + * InternalPutbytes - send bytes to connection (not flushed until TdsFlush) + * + * returns 0 if OK, EOF if trouble + * -------------------------------- + */ +static inline int +InternalPutbytes(void *bytes, size_t len) +{ + size_t amount; + unsigned char *s = bytes; + + while (len > 0) + { + /* If buffer is full, then flush it out */ + if (TdsSendCur >= TdsBufferSize) + { + SocketSetNonblocking(false); + if (InternalFlush(false)) + return EOF; + } + amount = TdsBufferSize - TdsSendCur; + if (amount > len) + amount = len; + memcpy(TdsSendBuffer + TdsSendCur, s, amount); + TdsSendCur += amount; + s += amount; + len -= amount; + } + return 0; +} + + +/* -------------------------------- + * TdsSetMessageType - Set current TDS message context + * -------------------------------- + */ +void +TdsSetMessageType(uint8_t msgType) +{ + TdsSendMessageType = msgType; +} + +/* -------------------------------- + * Low-level I/O routines begin here. + * + * These routines communicate with a frontend client across a connection. + * -------------------------------- + */ + +/* -------------------------------- + * SocketSetNonblocking - set socket blocking/non-blocking + * + * Sets the socket non-blocking if nonblocking is true, or sets it + * blocking otherwise. + * -------------------------------- + */ +static void +SocketSetNonblocking(bool nonblocking) +{ + if (MyProcPort == NULL) + ereport(ERROR, + (errcode(ERRCODE_CONNECTION_DOES_NOT_EXIST), + errmsg("there is no client connection"))); + + MyProcPort->noblock = nonblocking; +} + +/* -------------------------------- + * TdsReadsocket - read data from socket + * + * Data is read in a fix size buffer. Read socket will + * issue network read for left capacity in receive buffer + * -------------------------------- + */ +static int +TdsReadsocket(void) +{ + TdsErrorContext->err_text = "Reading data from socket"; + if (TdsRecvStart > 0) + { + if (TdsRecvEnd > TdsRecvStart) + { + /* still some unread data, left-justify it in the buffer */ + memmove(TdsRecvBuffer, TdsRecvBuffer + TdsRecvStart, + TdsRecvEnd - TdsRecvStart); + TdsRecvEnd -= TdsRecvStart; + TdsRecvStart = 0; + } + else + TdsRecvStart = TdsRecvEnd = 0; + } + + /* Ensure that we're in blocking mode */ + SocketSetNonblocking(false); + + /* Can fill buffer from TdsRecvStart and upwards */ + for (;;) + { + int r; + + r = tds_secure_read(MyProcPort, TdsRecvBuffer + TdsRecvEnd, + TdsBufferSize - TdsRecvEnd); + + if (r < 0) + { + if (errno == EINTR) + continue; /* Ok if interrupted */ + + /* + * Careful: an ereport() that tries to write to the client would + * cause recursion to here, leading to stack overflow and core + * dump! This message must go *only* to the postmaster log. + */ + ereport(COMMERROR, + (errcode_for_socket_access(), + errmsg("could not receive data from client: %m"))); + return EOF; + } + if (r == 0) + { + /* + * EOF detected. We used to write a log message here, but it's + * better to expect the ultimate caller to do that. + */ + return EOF; + } + /* r contains number of bytes read, so just incr length */ + TdsRecvEnd += r; + return 0; + } + +} + +/* -------------------------------- + * TdsProcessHeader - Process TDS header + * + * TDS header is of 8 bytes and is prefixed before + * each packet in message + * -------------------------------- + */ +static int +TdsProcessHeader(void) +{ + uint16_t data16; + + FAULT_INJECT(ParseHeaderType, TdsRecvBuffer); + TdsErrorContext->err_text = "Processing TDS header"; + + if (TdsLeftInPacket != 0) + ereport(FATAL, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("New TDS packet read encountered while " + "last packet is not fully consumed"))); + /* Get atleast header worth of data */ + while (TdsRecvEnd - TdsRecvStart < TDS_PACKET_HEADER_SIZE) + { + if (TdsReadsocket()) + return EOF; + } + /* Message type */ + TdsRecvMessageType = TdsRecvBuffer[TdsRecvStart]; + /* Packet status */ + TdsRecvPacketStatus = TdsRecvBuffer[TdsRecvStart+1]; + + /* Packet length in network byte order (includes header size) */ + memcpy(&data16, TdsRecvBuffer + TdsRecvStart + 2, sizeof(data16)); + data16 = pg_ntoh16(data16); + if (data16 > TdsBufferSize) + ereport(FATAL, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("Packet length %u exceeds packet size %u", + data16, TdsBufferSize))); + + TdsLeftInPacket = data16 - TDS_PACKET_HEADER_SIZE; + TdsRecvStart += TDS_PACKET_HEADER_SIZE; + + /* [BABEL-648] TDS packet with no TDS data is valid packet.*/ + if (TdsLeftInPacket < 0) + ereport(FATAL, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("TDS packet with insufficient data"))); + + TdsDoProcessHeader = false; + TDS_DEBUG(TDS_DEBUG3, "TDS packet MessageType %d LeftInPacket %d Status %d", + TdsRecvMessageType, TdsLeftInPacket, TdsRecvPacketStatus); + TDS_DEBUG(TDS_DEBUG3, "TDS receive buffer start %d end %d", TdsRecvStart, TdsRecvEnd); + return 0; +} + +/* -------------------------------- + * TdsRecvbuf - load some bytes into the input buffer + * + * returns 0 if OK, EOF if trouble + * -------------------------------- + */ +static int +TdsRecvbuf(void) +{ + TdsErrorContext->err_text = "Loading data into input buffer"; + /* Need to process the packet header */ + if (TdsLeftInPacket == 0 && TdsRecvStart < TdsRecvEnd) + { + if (TdsProcessHeader()) + return EOF; + if (TdsLeftInPacket == 0) + return 0; + } + /* No more data in the buffer to read */ + if (TdsRecvStart == TdsRecvEnd) + { + if (TdsReadsocket()) + return EOF; + if (TdsLeftInPacket == 0) + { + if (TdsDoProcessHeader && TdsProcessHeader()) + { + return EOF; + } + /* + * Last socket read only got header worth of data and + * if something is left to read. + */ + if ((TdsRecvStart == TdsRecvEnd) && (TdsLeftInPacket > 0)) + { + if (TdsReadsocket()) + return EOF; + } + } + } + if (TdsRecvStart > TdsRecvEnd) + ereport(FATAL, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("TDS buffer start pointer %d beyond end pointer %d", + TdsRecvStart, TdsRecvEnd))); + return 0; +} + +#if 0 +/* -------------------------------- + * TdsGetbyte - get a single byte from connection, or return EOF + * -------------------------------- + */ +static int +TdsGetbyte(void) +{ + while (TdsLeftInPacket == 0 || TdsRecvStart >= TdsRecvEnd) + { + if (TdsRecvbuf()) /* If nothing in buffer, then recv some */ + return EOF; /* Failed to recv data */ + } + --TdsLeftInPacket; + return (unsigned char) TdsRecvBuffer[TdsRecvStart++]; +} +#endif + +/* -------------------------------- + * TdsFillHeader - Make TDS header for current message + * + * Header is of fix 8 byte + * -------------------------------- + */ +static void +TdsFillHeader(bool lastPacket) +{ + uint16_t net16; + /* Message type */ + TdsSendBuffer[0] = TdsSendMessageType; + /* Packet status */ + TdsSendBuffer[1] = (lastPacket) ? 0x1 : 0x0; + /* Packet length including header */ + 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 */ +} + +/* -------------------------------- + * InternalFlush - flush pending output + * + * Returns 0 if OK (meaning everything was sent, or operation would block + * and the socket is in non-blocking mode), or EOF if trouble. + * -------------------------------- + */ +static int +InternalFlush(bool lastPacket) +{ + static int lastReportedSendErrno = 0; + + char *bufptr = TdsSendBuffer + TdsSendStart; + char *bufend = TdsSendBuffer + TdsSendCur; + + TdsErrorContext->err_text = "TDS InternalFlush - Sending data to the client"; + /* Writing the packet for the first time */ + if (TdsSendStart == 0) + { + TdsFillHeader(lastPacket); + } + + if (lastPacket) + TdsSendMessageType = 0; + + while (bufptr < bufend) + { + int r; + + DebugPrintBytes("TDS InternalFlush", bufptr, bufend - bufptr); + r = tds_secure_write(MyProcPort, bufptr, bufend - bufptr); + + if (r <= 0) + { + if (errno == EINTR) + continue; /* Ok if we were interrupted */ + + /* + * Ok if no data writable without blocking, and the socket is in + * non-blocking mode. + */ + if (errno == EAGAIN || + errno == EWOULDBLOCK) + { + return 0; + } + + /* + * Careful: an ereport() that tries to write to the client would + * cause recursion to here, leading to stack overflow and core + * dump! This message must go *only* to the postmaster log. + * + * If a client disconnects while we're in the midst of output, we + * might write quite a bit of data before we get to a safe query + * abort point. So, suppress duplicate log messages. + */ + if (errno != lastReportedSendErrno) + { + lastReportedSendErrno = errno; + ereport(COMMERROR, + (errcode_for_socket_access(), + errmsg("could not send data to client: %m"))); + } + + /* + * We drop the buffered data anyway so that processing can + * continue, even though we'll probably quit soon. We also set a + * flag that'll cause the next CHECK_FOR_INTERRUPTS to terminate + * the connection. + */ + TdsSendStart = 0; + TdsSendCur = TDS_PACKET_HEADER_SIZE; + ClientConnectionLost = 1; + InterruptPending = 1; + return EOF; + } + + lastReportedSendErrno = 0; /* reset after any successful send */ + bufptr += r; + TdsSendStart += r; + } + + TdsSendStart = 0; + TdsSendCur = TDS_PACKET_HEADER_SIZE; + return 0; +} + +/* -------------------------------- + * TdsCommInit - Setup TDS comm context + * -------------------------------- + */ +void +TdsCommInit(uint32_t bufferSize, + 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. + */ + Assert(TdsMemoryContext == NULL); + TdsMemoryContext = AllocSetContextCreate(TopMemoryContext, + "TDS Listener", + ALLOCSET_DEFAULT_SIZES); + + TdsBufferSize = bufferSize; + + TdsCommReset(); +} + +/* -------------------------------- + * TdsCommReset - Reset TDS variables and allocate socket buffers + * -------------------------------- + */ +void +TdsCommReset(void) +{ + MemoryContext oldContext; + + TdsRecvMessageType = TdsSendMessageType = 0; + TdsRecvPacketStatus = 0; + TdsRecvStart = TdsRecvEnd = TdsLeftInPacket = 0; + TdsSendStart = 0; + TdsSendCur = TDS_PACKET_HEADER_SIZE; + + oldContext = MemoryContextSwitchTo(TdsMemoryContext); + TdsRecvBuffer = palloc(TdsBufferSize); + TdsSendBuffer = palloc(TdsBufferSize); + MemoryContextSwitchTo(oldContext); +} + +/* -------------------------------- + * TdsCommShutdown - Shutdown TDS comm context + * -------------------------------- + */ +void +TdsCommShutdown(void) +{ + Assert(TdsSendMessageType == 0); + /* + * 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); + + pfree(TdsSendBuffer); + pfree(TdsRecvBuffer); + if (TdsMemoryContext != NULL) + { + MemoryContextDelete(TdsMemoryContext); + TdsMemoryContext = NULL; + } +} + +/* -------------------------------- + * TdsSetBufferSize - Change network buffer size + * + * During login handshake, client might ask for different + * packet size. Adjust buffer size accordingly + * -------------------------------- + */ +void +TdsSetBufferSize(uint32_t newSize) +{ + TDS_DEBUG(TDS_DEBUG3, "TdsSetBufferSize current size %u new size %u", + TdsBufferSize, newSize); + + if (newSize == TdsBufferSize) + return; + /* + * Both send and receive buffers should not have any + * valid data at this point in time + */ + if (TdsSendStart != 0 || + TdsSendCur != TDS_PACKET_HEADER_SIZE || + TdsRecvStart != TdsRecvEnd || + 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); + ereport(FATAL, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("TDS buffers in inconsistent state"))); + } + + TdsSendBuffer = repalloc(TdsSendBuffer, newSize); + TdsRecvBuffer = repalloc(TdsRecvBuffer, newSize); + + TdsBufferSize = newSize; + TdsRecvStart = TdsRecvEnd = TdsLeftInPacket = 0; +} + +/* -------------------------------- + * TdsCheckMessageType - Check current TDS message context + * -------------------------------- + */ +bool +TdsCheckMessageType(uint8_t msgType) +{ + return (TdsRecvMessageType == msgType); +} + +#if 0 +/* -------------------------------- + * TdsPeekbyte - peek at next byte from connection + * + * Same as TdsGetbyte() except we don't advance the pointer. + * -------------------------------- + */ +int +TdsPeekbyte(void) +{ + while (TdsLeftInPacket == 0 || TdsRecvStart >= TdsRecvEnd) + { + if (TdsRecvbuf()) /* If nothing in buffer, then recv some */ + return EOF; /* Failed to recv data */ + } + return (unsigned char) TdsRecvBuffer[TdsRecvStart]; +} +#endif + +/* -------------------------------- + * TdsReadNextBuffer - reads buffer from socket + * -------------------------------- + */ +int +TdsReadNextBuffer(void) +{ + 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 */ + } + return 0; +} + +/* --------------------------------- + * TdsConsumedBytes - reduce TdsLeftInPacket by number of bytes consumed/read + * --------------------------------- + */ +static void +TdsConsumedBytes(int bytes) +{ + TdsLeftInPacket -= bytes; + if (TdsLeftInPacket == 0) + TdsDoProcessHeader = true; +} + +/* -------------------------------- + * TdsGetbytes - get a known number of bytes from connection + * + * returns 0 if OK, EOF if trouble + * -------------------------------- + */ +int +TdsGetbytes(char *s, size_t len) +{ + size_t amount; + + TDS_DEBUG(TDS_DEBUG3, "TdsGetbytes LeftInPacket %d RecvStart %d RecvEnd %d", + TdsLeftInPacket, TdsRecvStart, TdsRecvEnd); + while (len > 0) + { + while (TdsLeftInPacket == 0 || TdsRecvStart >= TdsRecvEnd) + { + if (TdsRecvbuf()) /* If nothing in buffer, then recv some */ + return EOF; /* Failed to recv data */ + } + TdsErrorContext->err_text = ""; + amount = Min(TdsLeftInPacket, TdsRecvEnd - TdsRecvStart); + if (amount > len) + amount = len; + memcpy(s, TdsRecvBuffer + TdsRecvStart, amount); + TdsRecvStart += amount; + TdsConsumedBytes(amount); + s += amount; + len -= amount; + } + return 0; +} + +/* -------------------------------- + * PAGTdsDiscardbytes - throw away a known number of bytes + * + * same as TdsGetbytes except we do not copy the data to anyplace. + * this is used for resynchronizing after read errors. + * + * returns 0 if OK, EOF if trouble + * -------------------------------- + */ +int +TdsDiscardbytes(size_t len) +{ + size_t amount; + + while (len > 0) + { + while (TdsLeftInPacket == 0 || TdsRecvStart >= TdsRecvEnd) + { + if (TdsRecvbuf()) /* If nothing in buffer, then recv some */ + return EOF; /* Failed to recv data */ + } + TdsErrorContext->err_text = ""; + amount = Min(TdsLeftInPacket, TdsRecvEnd - TdsRecvStart); + if (amount > len) + amount = len; + TdsRecvStart += amount; + TdsConsumedBytes(amount); + len -= amount; + } + return 0; +} + +/* -------------------------------- + * TdsPutbytes - send bytes to connection (not flushed until TdsFlush) + * + * returns 0 if OK, EOF if trouble + * -------------------------------- + */ +int +TdsPutbytes(void *s, size_t len) +{ + int res; + + res = InternalPutbytes(s, len); + return res; +} + +/* -------------------------------- + * TdsPutDate - send one 24-bit unsigned integer + * in LITTLE_ENDIAN + * + * returns 0 if OK, EOF if trouble + * -------------------------------- + */ +int +TdsPutDate(uint32_t value) +{ + uint32_t tmp = htoLE32(value); + + return InternalPutbytes(&tmp, 3); +} + +/* -------------------------------- + * TdsPutInt8 - send one byte + * + * returns 0 if OK, EOF if trouble + * -------------------------------- + */ +int +TdsPutInt8(int8_t value) +{ + return InternalPutbytes(&value, sizeof(value)); +} + +/* -------------------------------- + * TdsPutInt64LE - send one 64-bit integer in LITTLE_ENDIAN + * + * returns 0 if OK, EOF if trouble + * -------------------------------- + */ +int +TdsPutInt64LE(int64_t value) +{ + int64_t tmp = htoLE64(value); + + return InternalPutbytes(&tmp, sizeof(tmp)); +} + +/* -------------------------------- + * TdsPutUInt16LE - send one 16-bit unsigned integer in LITTLE_ENDIAN + * + * returns 0 if OK, EOF if trouble + * -------------------------------- + */ +int +TdsPutUInt16LE(uint16_t value) +{ + uint16_t tmp = htoLE16(value); + + return InternalPutbytes(&tmp, sizeof(tmp)); +} + +/* -------------------------------- + * TdsPutUInt8 - send one byte + * + * returns 0 if OK, EOF if trouble + * -------------------------------- + */ +int +TdsPutUInt8(uint8_t value) +{ + return InternalPutbytes(&value, sizeof(value)); +} + +/* -------------------------------- + * TdsPutInt16LE - send one 16-bit integer in LITTLE_ENDIAN + * + * returns 0 if OK, EOF if trouble + * -------------------------------- + */ +int +TdsPutInt16LE(int16_t value) +{ + int16_t tmp = htoLE16(value); + + return InternalPutbytes(&tmp, sizeof(tmp)); +} +/* -------------------------------- + * TdsPutInt32LE - send one 32-bit integer in LITTLE_ENDIAN + * + * returns 0 if OK, EOF if trouble + * -------------------------------- + */ +int +TdsPutInt32LE(int32_t value) +{ + int32_t tmp = htoLE32(value); + + return InternalPutbytes(&tmp, sizeof(tmp)); +} +/* -------------------------------- + * TdsPutUInt32LE - send one 32-bit unsigned integer in LITTLE_ENDIAN + * + * returns 0 if OK, EOF if trouble + * -------------------------------- + */ +int +TdsPutUInt32LE(uint32_t value) +{ + uint32_t tmp = htoLE32(value); + + return InternalPutbytes(&tmp, sizeof(tmp)); +} +/* -------------------------------- + * TdsPutUInt64LE - send one unsigned 64-bit integer in LITTLE_ENDIAN + * + * returns 0 if OK, EOF if trouble + * -------------------------------- + */ +int +TdsPutUInt64LE(uint64_t value) +{ + uint64_t tmp = htoLE64(value); + + return InternalPutbytes(&tmp, sizeof(tmp)); +} + +/* -------------------------------- + * TdsPutFloat4LE - send one 32-bit float in LITTLE_ENDIAN + * + * returns 0 if OK, EOF if trouble + * -------------------------------- + */ +int +TdsPutFloat4LE(float4 value) +{ + uint32 tmp; + union + { + float4 f; + int32 i; + } swap; + + swap.f = value; + tmp = htoLE32(swap.i); + + return InternalPutbytes(&tmp, sizeof(tmp)); +} + +/* -------------------------------- + * TdsPutFloat8LE - send one 64-bit float in LITTLE_ENDIAN + * + * returns 0 if OK, EOF if trouble + * -------------------------------- + */ +int +TdsPutFloat8LE(float8 value) +{ + uint64 tmp; + union + { + float8 f; + int64 i; + } swap; + + swap.f = value; + tmp = htoLE64(swap.i); + + return InternalPutbytes(&tmp, sizeof(tmp)); +} + +/* -------------------------------- + * TdsSocketFlush - flush pending output + * + * returns 0 if OK, EOF if trouble + * -------------------------------- + */ +int +TdsSocketFlush(void) +{ + SocketSetNonblocking(false); + return InternalFlush(true); +} + +/* -------------------------------- + * TdsReadNextRequest - Read new request + * + * Put message into input sting info and + * status out parameter - returns the status from first packet header + * message type in out parameter + * Return 0 for success and EOF for trouble + * -------------------------------- + */ +int +TdsReadNextRequest(StringInfo message, uint8_t *status, uint8_t *messageType) +{ + int readBytes = 0; + bool isFirst = true; + while(1) + { + if (TdsReadNextBuffer() == EOF) + return EOF; + TdsErrorContext->err_text = "Save the status from first packet header"; + /* + * If this is the first packet header for this TDS request, save the + * status. + */ + if (isFirst) + { + *messageType = TdsRecvMessageType; + *status = TdsRecvPacketStatus; + isFirst = false; + } + readBytes = TdsLeftInPacket; + enlargeStringInfo(message, readBytes); + if (TdsGetbytes(message->data + message->len, readBytes)) + return EOF; + message->len += readBytes; + /* if this is the last packet, break the loop */ + if (TdsRecvPacketStatus & TDS_PACKET_HEADER_STATUS_EOM) + { + if (TdsLeftInPacket == 0 && TdsRecvStart == TdsRecvEnd) + TdsDoProcessHeader = true; + return 0; + } + } + return 0; +} + +/* -------------------------------- + * TdsReadMessage - Read and verify given message type + * + * Put message into input sting info + * Return 0 for success and EOF for trouble + * -------------------------------- + */ +int +TdsReadMessage(StringInfo message, uint8_t messageType) +{ + uint8_t curMsgType; + uint8_t status; + + /* Make sure that last write is flushed */ + if (TdsSendStart != 0 || TdsSendCur != TDS_PACKET_HEADER_SIZE) + ereport(FATAL, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("TDS last write did not flush"))); + + if (TdsReadNextRequest(message, &status, &curMsgType)) + return EOF; + // TODO Map to proper error code for TDS client + if (messageType != curMsgType) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("Invalid message type %u, expected %u", + curMsgType, messageType))); + return 0; +} + +/* -------------------------------- + * TdsWriteMessage - Write given message type + * + * Send given message over wire + * Return 0 for success and EOF for trouble + * -------------------------------- + */ +int +TdsWriteMessage(StringInfo message, uint8_t messageType) +{ + /* No write should be active */ + if (TdsSendMessageType != 0) + ereport(FATAL, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("TDS message write %u already in progress", + TdsSendMessageType))); + + TdsSetMessageType(messageType); + if (TdsPutbytes(message->data, message->len)) + return EOF; + if (TdsSocketFlush()) + return EOF; + return 0; +} diff --git a/contrib/babelfishpg_tds/src/backend/tds/tdslogin.c b/contrib/babelfishpg_tds/src/backend/tds/tdslogin.c new file mode 100644 index 00000000000..92027c28311 --- /dev/null +++ b/contrib/babelfishpg_tds/src/backend/tds/tdslogin.c @@ -0,0 +1,2366 @@ +/*------------------------------------------------------------------------- + * + * tdslogin.c + * TDS Listener connection handshake + * + * Portions Copyright (c) 2020, AWS + * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * contrib/babelfishpg_tds/src/backend/tds/tdslogin.c + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include +#include +#include +#include +#ifdef HAVE_SYS_SELECT_H +#include +#endif + +#include "access/printtup.h" +#include "catalog/pg_type.h" /* For type translation */ +#include "commands/dbcommands.h" +#include "common/ip.h" +#include "common/md5.h" +#include "common/scram-common.h" +#include "common/string.h" +#include "commands/extension.h" +#include "commands/user.h" +#include "libpq/auth.h" +#include "libpq/crypt.h" +#include "libpq/libpq.h" +#include "libpq/pqformat.h" +#include "libpq/scram.h" +#include "miscadmin.h" +#include "replication/walsender.h" +#include "storage/ipc.h" +#include "utils/timestamp.h" + +#include "access/printtup.h" +#include "libpq/libpq.h" +#include "libpq/pqformat.h" +#include "tcop/pquery.h" +#include "parser/scansup.h" +#include "utils/guc.h" +#include "utils/acl.h" +#include "utils/lsyscache.h" +#include "utils/memdebug.h" +#include "utils/memutils.h" +#include "utils/ps_status.h" +#include "utils/snapmgr.h" +#include "utils/timestamp.h" + +#include "src/include/tds_debug.h" +#include "src/include/tds_int.h" +#include "src/include/tds_request.h" +#include "src/include/tds_response.h" +#include "src/include/guc.h" + +#include "src/include/tds_secure.h" +#include "src/include/tds_instr.h" + +#include +#ifdef USE_OPENSSL +#include +#include +#endif +#ifdef HAVE_NETINET_TCP_H +#include +#endif + +#ifdef ENABLE_SSPI +#define SECURITY_WIN32 +#if defined(WIN32) && !defined(_MSC_VER) +#include +#endif +#include +#undef SECURITY_WIN32 + +#ifndef ENABLE_GSS +/* + * Define a fake structure compatible with GSSAPI on Unix. + */ +typedef struct +{ + void *value; + int length; +} gss_buffer_desc; +#endif +#endif /* ENABLE_SSPI */ + +/*---------------------------------------------------------------- + * GSSAPI Authentication + *---------------------------------------------------------------- + */ +#ifdef ENABLE_GSS +#if defined(HAVE_GSSAPI_H) +#include +#else +#include +#endif /* HAVE_GSSAPI_H */ +/* + * GSSAPI brings in headers that set a lot of things in the global namespace on win32, + * that doesn't match the msvc build. It gives a bunch of compiler warnings that we ignore, + * but also defines a symbol that simply does not exist. Undefine it again. + */ +#ifdef _MSC_VER +#undef HAVE_GETADDRINFO +#endif + +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); +#endif /* ENABLE_GSS */ + +/* Global to store default collation info */ +int TdsDefaultLcid; +int TdsDefaultCollationFlags; +uint8_t TdsDefaultSortid; + +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 */ + + /* + * The variable length attributes are stored in the following order in the + * login packet. If a new entry has to be added in future, make sure to + * keep TDS_LOGIN_ATTR_MAX as the last index. For all fields, we always + * store null terminated strings. Hence, we don't store the lengths. + */ +#define TDS_LOGIN_ATTR_HOSTNAME 0 + char *hostname; +#define TDS_LOGIN_ATTR_USERNAME 1 + char *username; +#define TDS_LOGIN_ATTR_PASSWORD 2 + char *password; +#define TDS_LOGIN_ATTR_APPNAME 3 + char *appname; +#define TDS_LOGIN_ATTR_SERVERNAME 4 + char *servername; +#define TDS_LOGIN_ATTR_UNUSED 5 +#define TDS_LOGIN_ATTR_LIBRARY 6 + char *library; +#define TDS_LOGIN_ATTR_LANGUAGE 7 + char *language; +#define TDS_LOGIN_ATTR_DATABASE 8 + char *database; +#define TDS_LOGIN_ATTR_MAX 9 /* should be last */ + + /* the 6-byte client mac address */ + char clientId[6]; + + uint16_t sspiLen; + char *sspi; + + /* the Active Directory (AD) domain name */ + char *domainname; + + /* TODO: Feature data */ + +} LoginRequestData; + +typedef LoginRequestData *LoginRequest; + +#define SizeOfLoginRequestFixed (offsetof(LoginRequestData, clientLcid) + sizeof(uint32_t)) + +typedef struct PreLoginOption +{ + int8_t token; + uint16_t offset; + uint16_t length; + StringInfoData val; + struct PreLoginOption *next; +} PreLoginOption; + +PreLoginOption *TdsPreLoginRequest; +LoginRequest loginInfo = NULL; + +static const char *PreLoginTokenType(uint8_t token); +static void DebugPrintPreLoginStructure(PreLoginOption *request); +static int ParsePreLoginRequest(); +static void SetPreLoginResponseVal(Port *port, uint8_t token, + 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, char **logdetail); +static void SendLoginError(Port *port, char *logdetail); +static void GetLoginFlagsInstrumentation(LoginRequest loginInfo); +static void GetTDSVersionInstrumentation(uint32_t version); + +/* Macros for OptionFlags1. */ +#define LOGIN_OPTION_FLAGS1_BYTE_ORDER_68000 0x01 +#define LOGIN_OPTION_FLAGS1_CHAR_EBCDIC 0x02 +#define LOGIN_OPTION_FLAGS1_FLOAT_VAX 0x04 +#define LOGIN_OPTION_FLAGS1_FLOAT_ND5000 0x08 +#define LOGIN_OPTION_FLAGS1_DUMP_LOAD_OFF 0x10 +#define LOGIN_OPTION_FLAGS1_USE_DB_ON 0x20 +#define LOGIN_OPTION_FLAGS1_DATABASE_FATAL 0x40 +#define LOGIN_OPTION_FLAGS1_SET_LANG_ON 0x80 + +/* Macros for OptionFlags2. */ +#define LOGIN_OPTION_FLAGS2_LANGUAGE_FATAL 0x01 +#define LOGIN_OPTION_FLAGS2_ODBC 0x02 +#define LOGIN_OPTION_FLAGS2_TRAN_BOUNDARY 0x04 +#define LOGIN_OPTION_FLAGS2_CACHE_CONNECT 0x08 +#define LOGIN_OPTION_FLAGS2_USER_TYPE_SERVER 0x10 +#define LOGIN_OPTION_FLAGS2_USER_TYPE_REMUSER 0x20 +#define LOGIN_OPTION_FLAGS2_USER_TYPE_SQLREPL 0x30 +#define LOGIN_OPTION_FLAGS2_INT_SECURITY_ON 0x80 + +/* Macros for TypeFlags */ +#define LOGIN_TYPE_FLAGS_SQL_TSQL 0x01 +#define LOGIN_TYPE_FLAGS_OLEDB 0x10 +#define LOGIN_TYPE_FLAGS_READ_ONLY_INTENT 0x20 + +/* Macros for OptionFlags3. */ +#define LOGIN_OPTION_FLAGS3_CHANGE_PASSWORD 0x01 +#define LOGIN_OPTION_FLAGS3_USER_INSTANCE 0x02 +#define LOGIN_OPTION_FLAGS3_SEND_YUKON_BINARY_XML 0x04 +#define LOGIN_OPTION_FLAGS3_UNKNOWN_COLLATION_HANDLING 0x08 +#define LOGIN_OPTION_FLAGS3_EXTENSION 0x10 + +#define TEXT_SIZE_2GB 0x7FFFFFFF +#define TEXT_SIZE_INFINITE 0xFFFFFFFF + +static const char * +PreLoginTokenType(uint8_t token) +{ + const char *id = NULL; + + switch(token) + { + case TDS_PRELOGIN_VERSION: + id = "TDS_PRELOGIN_VERSION (0x00)"; + break; + case TDS_PRELOGIN_ENCRYPTION: + id = "TDS_PRELOGIN_ENCRYPTION (0x01)"; + break; + case TDS_PRELOGIN_INSTOPT: + id = "TDS_PRELOGIN_INSTOPT (0x02)"; + break; + case TDS_PRELOGIN_THREADID: + id = "TDS_PRELOGIN_THREADID (0x03)"; + break; + case TDS_PRELOGIN_MARS: + id = "TDS_PRELOGIN_MARS (0x04)"; + break; + case TDS_PRELOGIN_TRACEID: + id = "TDS_PRELOGIN_TRACEID (0x05)"; + break; + case TDS_PRELOGIN_FEDAUTHREQUIRED: + id = "TDS_PRELOGIN_FEDAUTHREQUIRED (0x06)"; + break; + case TDS_PRELOGIN_NONCEOPT: + id = "TDS_PRELOGIN_NONCEOPT (0x07)"; + break; + case TDS_PRELOGIN_TERMINATOR: + id = "TDS_PRELOGIN_TERMINATOR (0xFF)"; + break; + default: + id = "unknown"; + } + + return id; +} + +static void +DebugPrintPreLoginStructure(PreLoginOption *request) +{ + PreLoginOption *prev; + StringInfoData s; + 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]); + prev = request->next; + 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); + + for(i = 0; i < prev->length; i++) + { + appendStringInfo(&s, "%02x", (unsigned char) prev->val.data[i]); + } + + prev = prev->next; + } + + if (!TDS_DEBUG_ENABLED(TDS_DEBUG3)) + return; + if (s.len > 0) + elog(LOG, "MESSAGE: \n %s", s.data); + else + elog(LOG, "MESSAGE: "); +} + + +static int +ParsePreLoginRequest() +{ + uint16_t data16; + PreLoginOption *temp; + PreLoginOption *prev = NULL; + + TdsErrorContext->reqType = TDS_PRELOGIN; + while (1) + { + temp = palloc0(sizeof(PreLoginOption)); + if (TdsGetbytes((char *)(&temp->token), sizeof(temp->token))) + return STATUS_ERROR; + + // Terminator token + if (temp->token == -1) + { + temp->offset = 0; + temp->length = 0; + temp->next = NULL; + initStringInfo(&temp->val); + prev->next = temp; + prev = prev->next; + break; + } + if (TdsGetbytes((char *)&data16, sizeof(data16))) + return STATUS_ERROR; + temp->offset = pg_ntoh16(data16); + if (TdsGetbytes((char *)&data16, sizeof(data16))) + return STATUS_ERROR; + temp->length = pg_ntoh16(data16); + initStringInfo(&temp->val); + + temp->next = NULL; + if (prev == NULL) + { + prev = temp; + TdsPreLoginRequest = temp; + } + else + { + prev->next = temp; + prev = prev->next; + } + } + prev = TdsPreLoginRequest; + while (prev->next != NULL) + { + if (TdsGetbytes(prev->val.data, prev->length)) + return STATUS_ERROR; + prev = prev->next; + } + if (!TdsCheckMessageType(TDS_PRELOGIN)) + return STATUS_ERROR; + + DebugPrintPreLoginStructure(TdsPreLoginRequest); + + TDS_DEBUG(TDS_DEBUG1, "message_type: TDS7 Prelogin Message"); + + return 0; +} + +static void +SetPreLoginResponseVal(Port *port, uint8_t token, StringInfo val, + StringInfo reqVal, bool loadSsl, int *loadEncryption) +{ + switch(token) + { + case TDS_PRELOGIN_VERSION: + /* Major Version 0x0C */ + appendStringInfoChar(val, 0x0C); + + /* Minor Version 0x00 */ + appendStringInfoChar(val, 0x00); + + /* Micro Version 0x07d0 */ + appendStringInfoChar(val, 0x07); + appendStringInfoChar(val, 0xd0); + + /* Subbuild Version 0x0000 */ + appendStringInfoChar(val, 0x00); + 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 + */ + if (loadSsl && !IS_AF_UNIX(port->laddr.addr.ss_family)) + { + if ((reqVal->data[0] == TDS_ENCRYPT_ON) || + (reqVal->data[0] == TDS_ENCRYPT_REQ)) + { + appendStringInfoChar(val, TDS_ENCRYPT_ON); + *loadEncryption = TDS_ENCRYPT_ON; + } + else if (reqVal->data[0] == TDS_ENCRYPT_OFF) + { + if (tds_ssl_encrypt) + { + appendStringInfoChar(val, TDS_ENCRYPT_REQ); + *loadEncryption = TDS_ENCRYPT_REQ; + } + else + { + appendStringInfoChar(val, TDS_ENCRYPT_OFF); + *loadEncryption = TDS_ENCRYPT_OFF; + } + } + else if (reqVal->data[0] == TDS_ENCRYPT_NOT_SUP) + { + if (tds_ssl_encrypt) + { + appendStringInfoChar(val, TDS_ENCRYPT_REQ); + *loadEncryption = TDS_ENCRYPT_REQ; + } + else + { + appendStringInfoChar(val, TDS_ENCRYPT_NOT_SUP); + *loadEncryption = TDS_ENCRYPT_NOT_SUP; + } + } + else + elog(FATAL, "Certification 0x%02x not supported", (unsigned char) reqVal->data[0]); + } + else + { + appendStringInfoChar(val, TDS_ENCRYPT_NOT_SUP); + *loadEncryption = TDS_ENCRYPT_NOT_SUP; + } + break; + case TDS_PRELOGIN_INSTOPT: + /* + * Val 00 - To indicate client's val matches server expectation + * Val 01 - Otherwise 01 to indicate client should terminate + * TODO:- Instead of fixed value, add the logic + */ + TDSInstrumentation(INSTR_UNSUPPORTED_TDS_PRELOGIN_INSTOPT); + appendStringInfoChar(val, 0x00); + break; + case TDS_PRELOGIN_THREADID: + TDSInstrumentation(INSTR_UNSUPPORTED_TDS_PRELOGIN_THREADID); + break; + case TDS_PRELOGIN_MARS: + appendStringInfoChar(val, 0x00); + break; + case TDS_PRELOGIN_TRACEID: + 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 + */ + TDSInstrumentation(INSTR_UNSUPPORTED_TDS_PRELOGIN_FEDAUTHREQUIRED); + break; + case TDS_PRELOGIN_NONCEOPT: + /* Only used with FedAuth - Noop in our case */ + TDSInstrumentation(INSTR_UNSUPPORTED_TDS_PRELOGIN_NONCEOPT); + break; + case TDS_PRELOGIN_TERMINATOR: + break; + + } +} + +/* + * MakePreLoginResponse - Sends the PreLogin response to the client, also decides + * whether to load the encryption for the session + * + * Return Value: + * Encryption option which can be + * TDS_ENCRYPT_ON - Complete End to End Encryption + * TDS_ENCRYPT_OFF - Login7 Encryption + * TDS_ENCRYPT_NOT_SUP - No Encryption + */ +static int +MakePreLoginResponse(Port *port, bool loadSsl) +{ + uint16_t temp16; + PreLoginOption *preLoginResponse; + PreLoginOption *tempRequest, *temp, *prev = NULL; + int offset = 0; + int loadEncryption = 0; + + preLoginResponse = palloc0(sizeof(PreLoginOption)); + + /* Prepare the structure */ + tempRequest = TdsPreLoginRequest; + + while(tempRequest != NULL) + { + if (tempRequest->token != TDS_PRELOGIN_FEDAUTHREQUIRED) + { + temp = palloc0(sizeof(PreLoginOption)); + temp->token = tempRequest->token; + initStringInfo(&temp->val); + SetPreLoginResponseVal(port, temp->token, &temp->val, &tempRequest->val, + loadSsl, &loadEncryption); + temp->length = temp->val.len; + /* 1 - type, 2 - offsetlen, 2 - len */ + offset += 5; + temp->next = NULL; + if (prev == NULL) + { + preLoginResponse = temp; + prev = temp; + } + else + { + prev->next = temp; + prev = prev->next; + } + } + tempRequest = tempRequest->next; + } + /* Terminator token doesn't have offset & len */ + offset -= 4; + + /* Add all the offset val */ + prev = preLoginResponse; + while(prev != NULL) + { + prev->offset = offset; + offset += prev->length; + prev = prev->next; + } + /* Structure prepared, now print it */ + DebugPrintPreLoginStructure(preLoginResponse); + + /* Prepare the response message */ + TdsSetMessageType(TDS_RESPONSE); + prev = preLoginResponse; + while (prev->next != NULL) + { + TdsPutbytes(&(prev->token), sizeof(prev->token)); + temp16 = pg_hton16(prev->offset); + TdsPutbytes(&temp16, sizeof(temp16)); + temp16 = pg_hton16(prev->length); + TdsPutbytes(&temp16, sizeof(temp16)); + prev = prev->next; + } + // Terminator token + TdsPutbytes(&(prev->token), sizeof(prev->token)); + + prev = preLoginResponse; + while (prev != NULL) + { + TdsPutbytes(prev->val.data, prev->val.len); + prev = prev->next; + } + + // Free the PreLogin Structures + prev = TdsPreLoginRequest; + while (prev != NULL) + { + pfree(prev->val.data); + temp = prev->next; + pfree(prev); + prev = temp; + } + prev = preLoginResponse; + while (prev != NULL) + { + pfree(prev->val.data); + temp = prev->next; + pfree(prev); + prev = temp; + } + return loadEncryption; +} + +/* + * ValidateLoginRequest - Validate the login request according to the TDS + * specifications. + */ +static void +ValidateLoginRequest(LoginRequest request) +{ + /* TODO: do the sanity checks */ + + 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)) + elog(FATAL, "invalid TDS Version: %X", version); + + GetTDSVersionInstrumentation(version); + + /* TDS Version 7.0 is unsupported */ + if(version == TDS_VERSION_7_0) + elog(FATAL, "unsupported TDS Version: %X", version); + + /* + * The packet size must be greater than or equal to 512 bytes and smaller + * than or equal to 32,767 bytes. Or, the packet size can be 0 in which + * case we should use the server default. + */ + if (request->packetSize != TDS_USE_SERVER_DEFAULT_PACKET_SIZE && + (request->packetSize < 512 || request->packetSize > 32767)) + elog(FATAL, "Invalid packet size: %u, Packet size has to be zero or " + "a number between 512 and 32767.", request->packetSize); +} + +/* + * FetchLoginRequest - Fetch and parse TDS login packet + * + * RETURNS: STATUS_OK or STATUS_ERROR + */ +static int +FetchLoginRequest(LoginRequest request) +{ + 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? + */ + Assert(0); +#endif + + /* + * The client writes all other bytes except clientProVersion in + * little-endian. Hence, we can read everything at once. No endian + * conversion is needed. + */ + if (TdsGetbytes((char *) request, SizeOfLoginRequestFixed)) + return STATUS_ERROR; + + /* The length of a LOGIN7 stream MUST NOT be longer than 128K-1(byte) bytes */ + if (request->length > 128 * 1024) + return STATUS_ERROR; + + read += SizeOfLoginRequestFixed; + + /* At any point, read CANNOT be greater than length of login stream */ + if (read > request->length) + return STATUS_ERROR; + + /* Check we indeed got the correct packet */ + Assert(TdsCheckMessageType(TDS_LOGIN7)); + + /* fix the client version now */ + request->clientProVersion = pg_bswap32(request->clientProVersion); + + /* Let's read the {offset, length} array now. */ + if (TdsGetbytes((char *) attrs, TDS_LOGIN_ATTR_MAX * sizeof(uint32_t))) + return STATUS_ERROR; + + read += TDS_LOGIN_ATTR_MAX * sizeof(uint32_t); + + if (read > request->length) + return STATUS_ERROR; + + /* 6-bytes Client MAC Address */ + if (TdsGetbytes((char *) request->clientId, sizeof(request->clientId))) + return STATUS_ERROR; + + read += sizeof(request->clientId); + + if (read > request->length) + return STATUS_ERROR; + + /* SSPI data */ + if (TdsGetbytes((char *) &sspiOffsetLen, sizeof(sspiOffsetLen))) + return STATUS_ERROR; + + read += sizeof(sspiOffsetLen); + + if (read > request->length) + 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 + */ + + initStringInfo(&buf); + initStringInfo(&temp_utf8); + + /* 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); + + if (length > 0) + { + /* Skip bytes till the offset */ + if (TdsDiscardbytes(offset - read)) + { + pfree(temp_utf8.data); + pfree(buf.data); + return STATUS_ERROR; + } + + read = offset; + + /* + * The hostname, username, password, appname, servername, + * library name, language and database name MUST specify + * at most 128 characters + */ + if(length > 128) + return STATUS_ERROR; + + if (i == TDS_LOGIN_ATTR_UNUSED) + { + if (TdsDiscardbytes(length)) + { + pfree(temp_utf8.data); + pfree(buf.data); + return STATUS_ERROR; + } + + read += length; + + if (read > request->length) + return STATUS_ERROR; + + continue; + } + + /* Since, it has UTF-16 format */ + length *= 2; + + resetStringInfo(&buf); + enlargeStringInfo(&buf, length); + + if (TdsGetbytes(buf.data, length)) + { + pfree(temp_utf8.data); + pfree(buf.data); + return STATUS_ERROR; + } + + read += length; + + if (read > request->length) + return STATUS_ERROR; + + buf.len += length; + + /* + * The password field is an obfusticated unicode string. So, we've + * to handle it differently. + */ + if (i == TDS_LOGIN_ATTR_PASSWORD) + { + int j; + for (j = 0; j < length; j++) + { + uint8_t p = buf.data[j]; + + p = (((p & 0xff) ^ 0xA5) << 4) | (((p & 0xff) ^ 0xA5) >> 4); + buf.data[j] = p & 0xff; + } + + } + + TdsUTF16toUTF8StringInfo(&temp_utf8, buf.data, length); + + switch(i) + { + case TDS_LOGIN_ATTR_HOSTNAME: + request->hostname = pstrdup(temp_utf8.data); + break; + case TDS_LOGIN_ATTR_USERNAME: + request->username = pstrdup(temp_utf8.data); + break; + case TDS_LOGIN_ATTR_PASSWORD: + request->password = pstrdup(temp_utf8.data); + break; + case TDS_LOGIN_ATTR_APPNAME: + request->appname = pstrdup(temp_utf8.data); + break; + case TDS_LOGIN_ATTR_SERVERNAME: + request->servername = pstrdup(temp_utf8.data); + break; + case TDS_LOGIN_ATTR_LIBRARY: + request->library = pstrdup(temp_utf8.data); + break; + case TDS_LOGIN_ATTR_LANGUAGE: + request->language = pstrdup(temp_utf8.data); + break; + case TDS_LOGIN_ATTR_DATABASE: + request->database = pstrdup(temp_utf8.data); + break; + default: + /* shouldn't reach here */ + Assert(0); + break; + } + resetStringInfo(&temp_utf8); + } + } + + pfree(temp_utf8.data); + pfree(buf.data); + + if (sspiOffsetLen > 0) + { + uint16_t offset = (uint16_t) sspiOffsetLen; + request->sspiLen = (uint16_t) (sspiOffsetLen >> 16); + + if (request->sspiLen > 0) + { + /* XXX: large SSPI data when length==USHORT_MAX - not supported yet */ + if (request->sspiLen == -1) + { + TDSInstrumentation(INSTR_UNSUPPORTED_TDS_LOGIN_CB_SSPI_LONG); + ereport(FATAL, + (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION), + errmsg("large SSPI is not supported yet"))); + } + + + /* Skip bytes till the offset */ + if (TdsDiscardbytes(offset - read)) + { + pfree(temp_utf8.data); + pfree(buf.data); + return STATUS_ERROR; + } + + read = offset; + + request->sspi = palloc(request->sspiLen); + + if (TdsGetbytes(request->sspi, request->sspiLen)) + { + pfree(temp_utf8.data); + pfree(buf.data); + return STATUS_ERROR; + } + + read += request->sspiLen; + } + } + + /* Now, discard rest of the bytes, if any */ + if (TdsDiscardbytes((size_t) (request->length - read))) + return STATUS_ERROR; + + DebugPrintLoginMessage(request); + + TDS_DEBUG(TDS_DEBUG1, "message_type: TDS7 Login"); + + return STATUS_OK; +} + +/* + * ProcessLoginFlags -- Processes the information stored in the following Flags: + * + * 1. information stored in optionFlags1 (in least significant bit order): + * fByteOrder: 0 = ORDER_X86, 1 = ORDER_68000 + * The byte order used by client for numeric and datetime data types. + * fChar: 0 = CHARSET_ASCII, 1 = CHARSET_EBCDIC + * The character set used on the client. + * fFloat: 0 = FLOAT_IEEE_754, 1 = FLOAT_VAX, 2 = ND5000 + * The type of floating point representation used by the client. + * fDumpLoad: 0 = DUMPLOAD_ON, 1 = DUMPLOAD_OFF + * Set if dump/load or BCP capabilities are needed by the client. + * fUseDB: 0 = USE_DB_OFF, 1 = USE_DB_ON + * Set if the client requires warning messages on execution of the USE + * SQL statement. If this flag is not set, the server MUST NOT inform + * the client when the database changes, and therefore the client will + * be unaware of any accompanying collation changes. + * fDatabase: 0 = INIT_DB_WARN, 1 = INIT_DB_FATAL + * Set if the change to initial database needs to succeed if the + * connection is to succeed. + * fSetLang: 0 = SET_LANG_OFF, 1 = SET_LANG_ON + * Set if the client requires warning messages on execution of a language + * change statement. + * + * 2. information stored in optionFlags2 (in least significant bit order): + * fLanguage: 0 = INIT_LANG_WARN, 1 = INIT_LANG_FATAL + * Set if the change to initial language needs to succeed if the + * connect is to succeed. + * fODBC: 0 = ODBC_OFF, 1 = ODBC_ON + * Set if the client is the ODBC driver. This causes the server to + * set ANSI_DEFAULTS to ON, CURSOR_CLOSE_ON_COMMIT and + * IMPLICIT_TRANSACTIONS to OFF, TEXTSIZE to 0x7FFFFFFF (2GB) + * (TDS 7.2 and earlier), TEXTSIZE to infinite (introduced in + * TDS 7.3), and ROWCOUNT to infinite. + * fTransBoundary + * fCacheConnect + * fUserType: 0 = USER_NORMAL—regular logins, + * 1 = USER_SERVER—reserved, + * 2 = USER_REMUSER—Distributed Query login, + * 3 = USER_SQLREPL—replication login + * The type of user connecting to the server. + * fIntSecurity: 0 = INTEGRATED_SECURTY_OFF, 1 = INTEGRATED_SECURITY_ON + * The type of security required by the client. + * + * 3. information stored in typeFlags (in least significant bit order): + * fSQLType: 0 = SQL_DFLT, 1 = SQL_TSQL + * The type of SQL the client sends to the server. + * fOLEDB: 0 = OLEDB_OFF, 1 = OLEDB_ON + * Set if the client is the OLEDB driver. This causes the server + * to set ANSI_DEFAULTS to ON, CURSOR_CLOSE_ON_COMMIT and + * IMPLICIT_TRANSACTIONS to OFF, TEXTSIZE to 0x7FFFFFFF (2GB) + * (TDS 7.2 and earlier), TEXTSIZE to infinite (introduced in + * TDS 7.3), and ROWCOUNT to infinite.<21> + * fReadOnlyIntent: This bit was introduced in TDS 7.4; however, TDS 7.1, 7.2, + * and 7.3 clients can also use this bit in LOGIN7 to specify + * that the application intent of the connection is read-only. The + * server SHOULD ignore this bit if the highest TDS version + * supported by the server is lower than TDS 7.4. + * + * 4. information stored in optionFlags3 (in least significant bit order): + * fChangePassword: 0 = No change request. ibChangePassword MUST be 0. + * 1 = Request to change login's password. + * Specifies whether the login request SHOULD change password. + * fSendYukonBinaryXML: 1 if XML data type instances are returned as binary XML. + * fUserInstance: 1 if client is requesting separate process to be spawned + * as user instance. + * fUnknownCollationHandling: + * 0 = The server MUST restrict the collations sent + * to a specific set of collations. It MAY disconnect or + * send an error if some other value is outside the specific + * collation set. The client MUST properly support all + * collations within the collation set. + * 1 = The server MAY send any collation that fits in the + * storage space. The client MUST be able to both properly + * support collations and gracefully fail for those it does + * not support. This bit is used by the server to determine + * if a client is able to properly handle collations introduced + * after TDS 7.2. TDS 7.2 and earlier clients are encouraged + * to use this login packet bit. Servers MUST ignore this + * bit when it is sent by TDS 7.3 or 7.4 clients. See + * [MSDN-SQLCollation] and [MS-LCID] for the complete list + * of collations for a database server that supports SQL + * and LCIDs. + * fExtension: 0 = ibExtension/cbExtension fields are not used. The + * fields are treated the same as ibUnused/cchUnused. + * 1 = ibExtension/cbExtension fields are used. + * Specifies whether ibExtension/cbExtension fields are used. + */ +static void ProcessLoginFlags(LoginRequest loginInfo) +{ + GetLoginFlagsInstrumentation(loginInfo); + + /* fODBC and fOLEDB */ + if ((loginInfo->optionFlags2 & LOGIN_OPTION_FLAGS2_ODBC) || + (loginInfo->typeFlags & LOGIN_TYPE_FLAGS_OLEDB)) + { + char *textSize = psprintf("%d" , (loginInfo->tdsVersion <= TDS_VERSION_7_2) ? + TEXT_SIZE_2GB : TEXT_SIZE_INFINITE); + char *rowCount = psprintf("%d" ,INT_MAX); + + set_config_option("babelfishpg_tsql.ansi_defaults", + "ON", + PGC_USERSET, + PGC_S_CLIENT, + GUC_ACTION_SET, + true, + 0, + false); + + set_config_option("babelfishpg_tsql.implicit_transactions", + "OFF", + PGC_USERSET, + PGC_S_CLIENT, + GUC_ACTION_SET, + true, + 0, + false); + set_config_option("babelfishpg_tsql.cursor_close_on_commit", + "OFF", + PGC_USERSET, + PGC_S_CLIENT, + GUC_ACTION_SET, + true, + 0, + false); + set_config_option("babelfishpg_tsql.textsize", + textSize, + PGC_USERSET, + PGC_S_CLIENT, + GUC_ACTION_SET, + true, + 0, + false); + set_config_option("babelfishpg_tsql.rowcount", + rowCount, + PGC_USERSET, + PGC_S_CLIENT, + 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")); + } +} + +/* + * ProcessLoginInternal - internal workhorse for processing login + * request. + * + * Read a TDS client's login packet and do something according to it. + * + * Returns STATUS_OK or STATUS_ERROR, or might call ereport(FATAL) and + * not return at all. + */ +static int +ProcessLoginInternal(Port *port) +{ + MemoryContext oldContext; + LoginRequest request; + const char* gucDatabaseName = NULL; + + /* + * Only use "babelfishpg_tsql.database_name" GUC when we have + * enabled "babelfishpg_tds.set_db_session_property" GUC + */ + if (tds_enable_db_session_property) + { + 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"))); + } + + /* + * We want to keep all login related information around even after + * postmaster context gets deleted and after a connection reset. + */ + oldContext = MemoryContextSwitchTo(TopMemoryContext); + + /* We're allocating the memory in postmaster context. */ + request = palloc0(sizeof(LoginRequestData)); + + TdsErrorContext->err_text = "Fetch Login Request"; + /* fetch and parse the login packet */ + if (FetchLoginRequest(request) != STATUS_OK) + return STATUS_ERROR; + + TdsErrorContext->err_text = "Validate Login Request"; + /* validate the login request */ + ValidateLoginRequest(request); + + /* + * 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) + { + request->username = downcase_identifier(request->username, + strlen(request->username), + false, + false); + port->user_name = pstrdup(request->username); + } + if (request->database != NULL) + { + request->database = downcase_identifier(request->database, + strlen(request->database), + false, + false); + port->database_name = pstrdup(request->database); + } + + /* + * We set application name in port structure in case we want to log + * connections in future. + */ + if (request->appname != NULL) + { + char *tmpAppName = pstrdup(request->appname); + + pg_clean_ascii(tmpAppName); + + port->application_name = tmpAppName; + } + + /* + * If GUC "babelfishpg_tsql.database_name" is "none", database + * name is set as whatever is specified in login request. Else, + * database name specified in login request is overridden by + * "babelfish_pgtsql.database_name" + */ + if (gucDatabaseName == NULL || strcmp(gucDatabaseName, "none") == 0) + { + if (request->database != NULL) + port->database_name = pstrdup(request->database); + } + else + port->database_name = pstrdup(gucDatabaseName); + + if (request->sspiLen > 0) + { + 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")); + + /* The database defaults to the user name. */ + if (port->database_name == NULL || port->database_name[0] == '\0') + port->database_name = pstrdup(TSQL_DEFAULT_DB); + + /* save the login information for the entire session */ + loginInfo = request; + + /* + * Truncate given database and user names to length of a Postgres name. + * This avoids lookup failures when overlength names are given. + */ + if (strlen(port->database_name) >= NAMEDATALEN) + port->database_name[NAMEDATALEN - 1] = '\0'; + if (strlen(port->user_name) >= NAMEDATALEN) + port->user_name[NAMEDATALEN - 1] = '\0'; + + /* + * Done putting stuff in TopMemoryContext. + */ + MemoryContextSwitchTo(oldContext); + + /* + * If we're going to reject the connection due to database state, say so + * now instead of wasting cycles on an authentication exchange. (This also + * allows a pg_ping utility to be written.) + */ + switch (port->canAcceptConnections) + { + case CAC_STARTUP: + ereport(FATAL, + errcode(ERRCODE_CANNOT_CONNECT_NOW), + errmsg("the database system is starting up")); + break; + case CAC_SHUTDOWN: + ereport(FATAL, + 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")); + break; + case CAC_TOOMANY: + ereport(FATAL, + errcode(ERRCODE_TOO_MANY_CONNECTIONS), + errmsg("sorry, too many clients already")); + break; + case CAC_SUPERUSER: + /* OK for now, will check in InitPostgres */ + break; + case CAC_OK: + break; + } + + TdsErrorContext->err_text = "Process Login Flags"; + ProcessLoginFlags(loginInfo); + return STATUS_OK; +} + +/* + * Plaintext password authentication. + */ +static int +CheckAuthPassword(Port *port, char **logdetail) +{ + char *passwd; + int result; + char *shadowPass; + + passwd = loginInfo->password; + + if (passwd == NULL) + return STATUS_EOF; /* client wouldn't send password */ + + shadowPass = get_role_password(port->user_name, logdetail); + if (shadowPass) + { + result = plain_crypt_verify(port->user_name, shadowPass, passwd, + logdetail); + } + else + result = STATUS_ERROR; + + if (shadowPass) + pfree(shadowPass); + pfree(passwd); + + /* since we've freed the password, set it to NULL */ + loginInfo->password = NULL; + + return result; +} + +/*---------------------------------------------------------------- + * GSSAPI authentication system + *---------------------------------------------------------------- + */ +#ifdef ENABLE_GSS + +#if defined(WIN32) && !defined(_MSC_VER) +/* + * MIT Kerberos GSSAPI DLL doesn't properly export the symbols for MingW + * that contain the OIDs required. Redefine here, values copied + * from src/athena/auth/krb5/src/lib/gssapi/generic/gssapi_generic.c + */ +static const gss_OID_desc GSS_C_NT_USER_NAME_desc = +{10, (void *) "\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x02"}; +static GSS_DLLIMP gss_OID GSS_C_NT_USER_NAME = &GSS_C_NT_USER_NAME_desc; +#endif + + +/* + * Generate an error for GSSAPI authentication. The caller should apply + * _() to errmsg to make it translatable. + * + * This function is similar to pg_GSS_Error(). + */ +static void +SendGSSAuthError(int severity, const char *errmsg, OM_uint32 maj_stat, OM_uint32 min_stat) +{ + gss_buffer_desc gmsg; + OM_uint32 lmin_s, + msg_ctx; + char msg_major[128], + msg_minor[128]; + + /* Fetch major status message */ + msg_ctx = 0; + gss_display_status(&lmin_s, maj_stat, GSS_C_GSS_CODE, + GSS_C_NO_OID, &msg_ctx, &gmsg); + strlcpy(msg_major, gmsg.value, sizeof(msg_major)); + gss_release_buffer(&lmin_s, &gmsg); + + if (msg_ctx) + + /* + * More than one message available. XXX: Should we loop and read all + * messages? (same below) + */ + ereport(WARNING, + (errmsg_internal("incomplete GSS error report"))); + + /* Fetch mechanism minor status message */ + msg_ctx = 0; + gss_display_status(&lmin_s, min_stat, GSS_C_MECH_CODE, + GSS_C_NO_OID, &msg_ctx, &gmsg); + strlcpy(msg_minor, gmsg.value, sizeof(msg_minor)); + gss_release_buffer(&lmin_s, &gmsg); + + if (msg_ctx) + ereport(WARNING, + (errmsg_internal("incomplete GSS minor error report"))); + + /* + * errmsg_internal, since translation of the first part must be done + * before calling this function anyway. + */ + ereport(severity, + (errmsg_internal("%s", errmsg), + errdetail_internal("%s: %s", msg_major, msg_minor))); +} + +static void +SendGSSAuthResponse(Port *port, char *extradata, uint16_t extralen) +{ + /* + * If not already in RESPONSE mode, switch the TDS protocol to RESPONSE + * mode. + */ + TdsSetMessageType(TDS_RESPONSE); + + TdsPutInt8(TDS_TOKEN_SSPI); + TdsPutInt16LE(extralen); + TdsPutbytes(extradata, extralen); + + TdsFlush(); + + TDSInstrumentation(INSTR_TDS_TOKEN_SSPI); +} + +/* + * This function is similar to pg_GSS_recvauth() but to authenticate a TDS + * client. + */ +static int +CheckGSSAuth(Port *port) +{ + LoginRequest request = loginInfo; + OM_uint32 maj_stat, + min_stat, + lmin_s, + gflags; + int ret; + gss_buffer_desc gbuf; + MemoryContext oldContext; + + if (pg_krb_server_keyfile && strlen(pg_krb_server_keyfile) > 0) + { + /* + * Set default Kerberos keytab file for the Krb5 mechanism. + * + * setenv("KRB5_KTNAME", pg_krb_server_keyfile, 0); except setenv() + * not always available. + */ + if (getenv("KRB5_KTNAME") == NULL) + { + size_t kt_len = strlen(pg_krb_server_keyfile) + 14; + char *kt_path = malloc(kt_len); + + if (!kt_path || + snprintf(kt_path, kt_len, "KRB5_KTNAME=%s", + pg_krb_server_keyfile) != kt_len - 2 || + putenv(kt_path) != 0) + { + ereport(LOG, + (errcode(ERRCODE_OUT_OF_MEMORY), + errmsg("out of memory"))); + return STATUS_ERROR; + } + } + } + + /* + * We accept any service principal that's present in our keytab. This + * increases interoperability between kerberos implementations that see + * for example case sensitivity differently, while not really opening up + * any vector of attack. + */ + port->gss->cred = GSS_C_NO_CREDENTIAL; + + /* + * Initialize sequence with an empty context + */ + port->gss->ctx = GSS_C_NO_CONTEXT; + + do + { + /* Map to GSSAPI style buffer */ + gbuf.length = request->sspiLen; + gbuf.value = request->sspi; + + elog(DEBUG4, "Processing received GSS token of length %u", + (unsigned int) gbuf.length); + + maj_stat = gss_accept_sec_context( + &min_stat, + &port->gss->ctx, + port->gss->cred, + &gbuf, + GSS_C_NO_CHANNEL_BINDINGS, + &port->gss->name, + NULL, + &port->gss->outbuf, + &gflags, + NULL, + NULL); + + /* gbuf no longer used */ + pfree(request->sspi); + request->sspiLen = 0; + + elog(DEBUG4, "gss_accept_sec_context major: %d, " + "minor: %d, outlen: %u, outflags: %x", + maj_stat, min_stat, + (unsigned int) port->gss->outbuf.length, gflags); + + if (port->gss->outbuf.length != 0) + { + /* + * Negotiation generated data to be sent to the client. + */ + elog(DEBUG4, "sending GSS response token of length %u", + (unsigned int) port->gss->outbuf.length); + + SendGSSAuthResponse(port, port->gss->outbuf.value, + port->gss->outbuf.length); + + gss_release_buffer(&lmin_s, &port->gss->outbuf); + } + + if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED) + { + gss_delete_sec_context(&lmin_s, &port->gss->ctx, GSS_C_NO_BUFFER); + SendGSSAuthError(ERROR, + _("accepting GSS security context failed"), + maj_stat, min_stat); + } + + /* + * XXX: First we need a reproducible case to implement the following + * feature. + */ + if (maj_stat == GSS_S_CONTINUE_NEEDED) + { + TDSInstrumentation(INSTR_UNSUPPORTED_TDS_LOGIN_GSS_S_CONTINUE_NEEDED); + elog(FATAL, "GSS continue needed - not supported yet"); + } + + } while (maj_stat == GSS_S_CONTINUE_NEEDED); + + if (port->gss->cred != GSS_C_NO_CREDENTIAL) + { + /* + * Release service principal credentials + */ + gss_release_cred(&min_stat, &port->gss->cred); + } + + /* + * GSS_S_COMPLETE indicates that authentication is now complete. + * + * Get the name of the user that authenticated, and compare it to the pg + * username that was specified for the connection. + */ + maj_stat = gss_display_name(&min_stat, port->gss->name, &gbuf, NULL); + if (maj_stat != GSS_S_COMPLETE) + SendGSSAuthError(ERROR, + _("retrieving GSS user name failed"), + 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. + * + * 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); + pfree(port->user_name); + port->user_name = pstrdup(gbuf.value); + if (strchr(gbuf.value, '@')) + { + char *cp = strchr(gbuf.value, '@'); + cp++; + if (loginInfo) + loginInfo->domainname = pstrdup(cp); + } + MemoryContextSwitchTo(oldContext); + + ret = STATUS_OK; + gss_release_buffer(&lmin_s, &gbuf); + + return ret; +} +#endif /* ENABLE_GSS */ + +static void +SendLoginError(Port *port, char *logdetail) +{ + LoginRequest request = loginInfo; + + if (request->sspiLen > 0) + ereport(FATAL, + 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)); +} + +/* + * TdsClientAuthentication - Similar to ClientAuthentication, but specific + * to TDS client authentication + * + * TDS Client authentication starts here. If there is an error, this function + * does not return and the backend process is terminated. + * + * Note that this method should be called in postmaster context so that we can + * access the login request information. + */ +void +TdsClientAuthentication(Port *port) +{ + int status = STATUS_ERROR; + char *logdetail = NULL; +#ifdef ENABLE_GSS + StringInfoData ps_data; +#endif + + if (loginInfo->sspiLen > 0) + { +#ifdef ENABLE_GSS + + /* NTLMSSP Authentication Isn't Supported yet. */ + 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"))); + } + + /* We might or might not have the gss workspace already */ + if (port->gss == NULL) + port->gss = (pg_gssinfo *) + MemoryContextAllocZero(TopMemoryContext, + sizeof(pg_gssinfo)); + port->gss->auth = true; + + status = CheckGSSAuth(port); + + if (status == STATUS_ERROR) + SendLoginError(port, logdetail); + + if (status != STATUS_ERROR) + TDSInstrumentation(INSTR_TDS_LOGIN_ACTIVE_DIRECTORY); + + initStringInfo(&ps_data); + appendStringInfo(&ps_data, "%s ", port->user_name); + appendStringInfo(&ps_data, "%s", port->remote_host); + if (port->remote_port[0] != '\0') + appendStringInfo(&ps_data, "(%s)", port->remote_port); + + init_ps_display(ps_data.data); +#else + ereport(FATAL, + (errcode(ERRCODE_CONFIG_FILE_ERROR), + errmsg("invalid authentication method \"GSSAPI\": not supported by this build"))); +#endif + } + + /* + * Get the authentication method to use for this frontend/database + * combination. Note: we do not parse the file at this point; this has + * already been done elsewhere. hba.c dropped an error message into the + * server logfile if parsing the hba config file failed. + */ + hba_getauthmethod(port); + + CHECK_FOR_INTERRUPTS(); + + /* + * Now proceed to do the actual authentication check + * + * We only support password-based authentication. So, if we cannot trust + * the user, fall back to password based authentication. + */ + switch (port->hba->auth_method) + { + case uaReject: + + /* + * An explicit "reject" entry in pg_hba.conf. This report exposes + * the fact that there's an explicit reject entry, which is + * perhaps not so desirable from a security standpoint; but the + * message for an implicit reject could confuse the DBA a lot when + * the true situation is a match to an explicit reject. And we + * don't want to change the message for an implicit reject. As + * noted below, the additional information shown here doesn't + * expose anything not known to an attacker. + */ + { + char hostinfo[NI_MAXHOST]; + + pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen, + hostinfo, sizeof(hostinfo), + NULL, 0, + 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")))); +#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))); +#endif + break; + } + case uaImplicitReject: + + /* + * No matching entry, so tell the user we fell through. + * + * NOTE: the extra info reported here is not a security breach, + * because all that info is known at the frontend and must be + * assumed known to bad guys. We're merely helping out the less + * clueful good guys. + */ + { + char hostinfo[NI_MAXHOST]; + + pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen, + hostinfo, sizeof(hostinfo), + NULL, 0, + NI_NUMERICHOST); + +#define HOSTNAME_LOOKUP_DETAIL(port) \ + (port->remote_hostname ? \ + (port->remote_hostname_resolv == +1 ? \ + errdetail_log("Client IP address resolved to \"%s\", forward lookup matches.", \ + port->remote_hostname) : \ + port->remote_hostname_resolv == 0 ? \ + errdetail_log("Client IP address resolved to \"%s\", forward lookup not checked.", \ + port->remote_hostname) : \ + port->remote_hostname_resolv == -1 ? \ + errdetail_log("Client IP address resolved to \"%s\", forward lookup does not match.", \ + port->remote_hostname) : \ + port->remote_hostname_resolv == -2 ? \ + errdetail_log("Could not translate client host name \"%s\" to IP address: %s.", \ + port->remote_hostname, \ + gai_strerror(port->remote_hostname_errcode)) : \ + 0) \ + : (port->remote_hostname_resolv == -2 ? \ + errdetail_log("Could not resolve client IP address to a host name: %s.", \ + gai_strerror(port->remote_hostname_errcode)) : \ + 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))); +#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))); +#endif + + pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen, + hostinfo, sizeof(hostinfo), + NULL, 0, + NI_NUMERICHOST); + break; + } + case uaSSPI: + case uaPeer: + case uaIdent: + case uaSCRAM: + case uaPAM: + case uaBSD: + case uaLDAP: + case uaCert: + case uaRADIUS: + /* the above authentication methods are not supported for TDS */ + { + char hostinfo[NI_MAXHOST]; + + pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen, + hostinfo, sizeof(hostinfo), + NULL, 0, + NI_NUMERICHOST); + + ereport(FATAL, + (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION), + errmsg("pg_hba.conf entry specifies unsupported TDS authentication for host \"%s\", user \"%s\", database \"%s\"", + hostinfo, port->user_name, port->database_name), + errhint("Supported methods are trust, password, md5 and gssapi"))); + } + 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 (status != STATUS_OK) + { + char hostinfo[NI_MAXHOST]; + + pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen, + hostinfo, sizeof(hostinfo), + NULL, 0, + NI_NUMERICHOST); + + ereport(FATAL, + (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION), + errmsg("invalid TDS authentication request for host \"%s\", user \"%s\", database \"%s\"", + hostinfo, port->user_name, port->database_name), + errhint("Expected authentication request: gssapi"))); + } + break; + case uaMD5: + case uaPassword: + /* + * 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) + { + char hostinfo[NI_MAXHOST]; + + pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen, + hostinfo, sizeof(hostinfo), + NULL, 0, + NI_NUMERICHOST); + + ereport(FATAL, + (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION), + errmsg("invalid TDS authentication request for host \"%s\", user \"%s\", database \"%s\"", + hostinfo, port->user_name, port->database_name), + errhint("Expected authentication request: md5 or password"))); + } + + /* we've a password, let's verify it */ + status = CheckAuthPassword(port, &logdetail); + break; + case uaTrust: + status = STATUS_OK; + break; + } + + /* If authentication failed, tell the user. */ + if (status != STATUS_OK) + 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. + */ +} + +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. + */ +#ifndef WIN32 + 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); +} + +/* + * Attempt to negotiate secure session. + */ +static int +SecureOpenServer(Port *port) +{ + int r = 0; + +#ifdef USE_SSL + TDSInstrumentation(INSTR_TDS_LOGIN_SSL); + + r = Tds_be_tls_open_server(port); + + ereport(DEBUG2, + (errmsg("SSL connection from \"%s\"", + port->peer_cn ? port->peer_cn : "(anonymous)"))); +#endif + + return r; +} + +/* + * : Process a TDS login handshake + */ +int +TdsProcessLogin(Port *port, bool loadedSsl) +{ + int rc = 0; + int loadEncryption = 0; + + /* Set the LOGIN7 request type for error context */ + TdsErrorContext->phase = 0; + TdsErrorContext->reqType = TDS_LOGIN7; + + PG_TRY(); + { + TdsErrorContext->err_text = "Parsing PreLogin Request"; + /* Pre-Login */ + rc = ParsePreLoginRequest(); + if (rc < 0) + return rc; + + TdsErrorContext->err_text = "Make PreLogin Response"; + + loadEncryption = MakePreLoginResponse(port, loadedSsl); + TdsFlush(); + + TdsErrorContext->err_text = "Setup SSL Handshake"; + /* Setup the SSL handshake */ + if (loadEncryption == TDS_ENCRYPT_ON || + loadEncryption == TDS_ENCRYPT_OFF || + loadEncryption == TDS_ENCRYPT_REQ) + SecureOpenServer(port); + + if (loadEncryption == TDS_ENCRYPT_ON) + TDSInstrumentation(INSTR_TDS_LOGIN_END_TO_END_ENCRYPT); + + /* Login */ + rc = ProcessLoginInternal(port); + + } + PG_CATCH(); + { + PG_RE_THROW(); + } + PG_END_TRY(); + + TdsErrorContext->err_text = ""; + + if (rc < 0) + return rc; + + /* Free up the SSL strcture if TDS_ENCRYPT_OFF is set */ + if (loadEncryption == TDS_ENCRYPT_OFF) + TdsFreeSslStruct(port); + + return rc; +} + +/* + * TdsSendLoginAck - Send a login acknowledgement to the client + * + * This function should be called in postmaster context. + */ +void +TdsSendLoginAck(Port *port) +{ + uint16_t temp16; + char mbuf[1024]; + char *dbname; /* TODO: where to get this? */ + int prognameLen = pg_mbstrlen(default_server_name); + LoginRequest request; + StringInfoData buf; + uint8 temp8; + uint32_t collationInfo; + char collationBytesNew[5]; + uint32_t tdsVersion = pg_hton32(loginInfo->tdsVersion); + + /* TODO: should these version numbers be hardcoded? */ + char srvVersionBytes[] = { + 0x0C, 0x00, 0x07, 0xd0 + }; + + PG_TRY(); + { + + /* Initialize the normal TDS protocol */ + TdsProtocolInit(); + + TdsErrorContext->err_text = "Initialising Collation Info"; + + /* 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) + elog(FATAL, "babelfishpg_tsql extension is not installed"); + PopActiveSnapshot(); + CommitTransactionCommand(); + + TdsDefineDefaultCollationInfo(); + /* + * 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. + */ + collationInfo = TdsDefaultLcid | (TdsDefaultCollationFlags << 20); + collationBytesNew[0] = (char) collationInfo & 0x000000ff; + collationBytesNew[1] = (char) ((collationInfo & 0x0000ff00) >> 8); + collationBytesNew[2] = (char) ((collationInfo & 0x00ff0000) >> 16); + collationBytesNew[3] = (char) ((collationInfo & 0xff000000) >> 24); + collationBytesNew[4] = (char) TdsDefaultSortid; + + initStringInfo(&buf); + /* get the login request */ + request = loginInfo; + + 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 */ + 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. + */ + if (request->packetSize == TDS_USE_SERVER_DEFAULT_PACKET_SIZE) + { + char old[10]; + char new[10]; + + /* set the packet size as server default */ + request->packetSize = tds_default_packet_size; + + snprintf(old, sizeof(old), "%u", tds_default_packet_size); + snprintf(new, sizeof(new), "%u", request->packetSize); + TdsSendEnvChange(TDS_ENVID_BLOCKSIZE, new, old); + } + else if (request->packetSize != tds_default_packet_size) + { + 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. + */ + request->packetSize = (((int) request->packetSize / 4) * 4); + + snprintf(old, sizeof(old), "%u", tds_default_packet_size); + snprintf(new, sizeof(new), "%u", request->packetSize); + 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. */ + if (port->user_name != NULL && port->user_name[0] != '\0') + { + bool login_exist; + Oid roleid; + + StartTransactionCommand(); + roleid = get_role_oid(port->user_name, false); + login_exist = pltsql_plugin_handler_ptr->pltsql_is_login(roleid); + CommitTransactionCommand(); + + /* Throw error if this user is not one of the type mentioned above */ + if(!login_exist && !superuser_arg(roleid)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("\"%s\" is not a Babelfish user", port->user_name))); + } + + if (tds_enable_db_session_property) + { + char *useCommand = "USE "; + StringInfoData useDbCommand; + MemoryContext oldContext = CurrentMemoryContext; + + initStringInfo(&useDbCommand); + appendStringInfoString(&useDbCommand, useCommand); + + if (request->database != NULL && request->database[0] != '\0') + { + 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. + */ + StartTransactionCommand(); + db_id = pltsql_plugin_handler_ptr->pltsql_get_database_oid(request->database); + CommitTransactionCommand(); + MemoryContextSwitchTo(oldContext); + + if (!OidIsValid(db_id)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_DATABASE), + errmsg("database \"%s\" does not exist", request->database))); + + appendStringInfoString(&useDbCommand, request->database); + } + else + { + char *defaultDb = NULL; + char *temp = NULL; + + StartTransactionCommand(); + temp = pltsql_plugin_handler_ptr->pltsql_get_login_default_db(request->username ? + request->username : port->user_name); + MemoryContextSwitchTo(oldContext); + + if (temp == NULL) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_DATABASE), + errmsg("could not find default database for user \"%s\"", request->username))); + + defaultDb = pstrdup(temp); + CommitTransactionCommand(); + MemoryContextSwitchTo(oldContext); + + appendStringInfoString(&useDbCommand, defaultDb); + } + + /* + * Request has a database name provided, so we execute + * a "USE " through pgtsql inline handler + */ + StartTransactionCommand(); + ExecuteSQLBatch(useDbCommand.data); + CommitTransactionCommand(); + } + else + { + dbname = port->database_name; + snprintf(mbuf, sizeof(mbuf), "Changed database context to '%s'", + dbname); + if (strcmp(dbname, TSQL_DEFAULT_DB) != 0) + TdsSendEnvChange(TDS_ENVID_DATABASE, dbname, TSQL_DEFAULT_DB); + TdsSendInfo(5701, 1, 10, mbuf, 1); + } + + /* + * 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; + /* + * 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("babelfishpg_tsql.language", + request->language, + PGC_USERSET, + PGC_S_CLIENT, + GUC_ACTION_SET, + true /* changeVal */, + 0 /* elevel */, + false /* is_reload */); + CommitTransactionCommand(); + if (ret != 1) + { + /* TODO Error handling */ + Assert(false); + } + } + + /* Set the GUC for application_name. */ + if (request->appname != NULL) + { + 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. + */ + StartTransactionCommand(); + ret = set_config_option("application_name", + tmpAppName, + PGC_USERSET, + PGC_S_CLIENT, + GUC_ACTION_SET, + true /* changeVal */, + 0 /* elevel */, + false /* is_reload */); + CommitTransactionCommand(); + + if (ret != 1) + { + /* TODO Error handling */ + Assert(false); + } + } + + TdsSendEnvChangeBinary(TDS_ENVID_COLLATION, + collationBytesNew, sizeof(collationBytesNew), + NULL, 0); + + /* Append the LOGINACK message */ + 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); + TdsPutbytes(&temp16, sizeof(temp16)); + + temp8 = 0x01; + TdsPutbytes(&temp8, sizeof(temp8)); /* interface ??? */ + + TdsPutbytes(&tdsVersion, sizeof(tdsVersion)); + TdsPutbytes(&prognameLen, sizeof(temp8)); + + TdsUTF8toUTF16StringInfo(&buf, default_server_name, prognameLen); + TdsPutbytes(buf.data, buf.len); + + TdsPutbytes(&srvVersionBytes, sizeof(srvVersionBytes)); + + pfree(buf.data); + + /* Append the DONE message */ + TdsSendDone(TDS_TOKEN_DONE, TDS_DONE_FINAL, 2, 0); + + TdsFlush(); + + /* 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. + */ + TdsErrorContext->err_text = "Resetting the TDS Buffer size"; + TdsSetBufferSize(request->packetSize); + + } + PG_CATCH(); + { + /* Before terminating the connection, send the response to the client */ + EmitErrorReport(); + FlushErrorState(); + + TdsSendDone(TDS_TOKEN_DONE, TDS_DONE_ERROR, 0, 0); + TdsFlush(); + + TdsErrorContext->err_text = "Verifying and Sending Login Acknowledgement"; + + ereport(FATAL, + (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION), + errmsg("Login failed for user \"%s\"", port->user_name))); + + } + PG_END_TRY(); +} + +/* + * GetClientTDSVersion - exposes TDS version of client being connected. + */ +uint32_t +GetClientTDSVersion(void) +{ + /* This should not happen. */ + if (loginInfo == NULL) + ereport(FATAL, + (errcode(ERRCODE_INTERNAL_ERROR), errmsg("Login Info should not be NULL"))); + return loginInfo->tdsVersion; +} + +/* + * This function will return the AD domain name. + */ +char* +get_tds_login_domainname(void) +{ + if (loginInfo) + return loginInfo->domainname; + else + return NULL; +} + +/* + * To initialise information of default collation based on "babelfishpg_tsql.server_collation_oid" GUC. + */ +static void +TdsDefineDefaultCollationInfo(void) +{ + coll_info_t cinfo = (pltsql_plugin_handler_ptr)->lookup_collation_table_callback(InvalidOid); + if (unlikely(cinfo.oid == InvalidOid)) + elog(FATAL, "Oid of default collation is not valid, This might mean that value of server_collation_name GUC is invalid"); + + TdsDefaultLcid = cinfo.lcid; + TdsDefaultCollationFlags = cinfo.collateflags; + TdsDefaultSortid = (uint8_t) cinfo.sortid; +} + +/* + * Increment appropriate instrumentation metric for TDS version + */ +static void +GetTDSVersionInstrumentation(uint32_t version) +{ + switch (version) + { + case TDS_VERSION_7_0: + TDSInstrumentation(INSTR_TDS_VERSION_7_0); + break; + case TDS_VERSION_7_1: + TDSInstrumentation(INSTR_TDS_VERSION_7_1); + break; + case TDS_VERSION_7_1_1: + TDSInstrumentation(INSTR_TDS_VERSION_7_1_1); + break; + case TDS_VERSION_7_2: + TDSInstrumentation(INSTR_TDS_VERSION_7_2); + break; + case TDS_VERSION_7_3_A: + TDSInstrumentation(INSTR_TDS_VERSION_7_3_A); + break; + case TDS_VERSION_7_3_B: + TDSInstrumentation(INSTR_TDS_VERSION_7_3_B); + break; + case TDS_VERSION_7_4: + TDSInstrumentation(INSTR_TDS_VERSION_7_4); + break; + default: + break; + } +} + +/* + * Increment appropriate instrumentation metric for unsupported login flags + */ +static void +GetLoginFlagsInstrumentation(LoginRequest loginInfo) +{ + /* OptionFlags1 */ + if (loginInfo->optionFlags1 & LOGIN_OPTION_FLAGS1_BYTE_ORDER_68000) + TDSInstrumentation(INSTR_UNSUPPORTED_TDS_LOGIN_OPTION_FLAGS1_BYTE_ORDER_68000); + + if (loginInfo->optionFlags1 & LOGIN_OPTION_FLAGS1_CHAR_EBCDIC) + TDSInstrumentation(INSTR_UNSUPPORTED_TDS_LOGIN_OPTION_FLAGS1_CHAR_EBCDIC); + + if (loginInfo->optionFlags1 & LOGIN_OPTION_FLAGS1_FLOAT_VAX) + TDSInstrumentation(INSTR_UNSUPPORTED_TDS_LOGIN_OPTION_FLAGS1_FLOAT_VAX); + + if (loginInfo->optionFlags1 & LOGIN_OPTION_FLAGS1_FLOAT_ND5000) + TDSInstrumentation(INSTR_UNSUPPORTED_TDS_LOGIN_OPTION_FLAGS1_FLOAT_ND5000); + + if (loginInfo->optionFlags1 & LOGIN_OPTION_FLAGS1_DUMP_LOAD_OFF) + TDSInstrumentation(INSTR_UNSUPPORTED_TDS_LOGIN_OPTION_FLAGS1_DUMP_LOAD_OFF); + + if (loginInfo->optionFlags1 & LOGIN_OPTION_FLAGS1_USE_DB_ON) + TDSInstrumentation(INSTR_UNSUPPORTED_TDS_LOGIN_OPTION_FLAGS1_USE_DB_ON); + + if (loginInfo->optionFlags1 & LOGIN_OPTION_FLAGS1_DATABASE_FATAL) + TDSInstrumentation(INSTR_UNSUPPORTED_TDS_LOGIN_OPTION_FLAGS1_DATABASE_FATAL); + + if (loginInfo->optionFlags1 & LOGIN_OPTION_FLAGS1_SET_LANG_ON) + TDSInstrumentation(INSTR_UNSUPPORTED_TDS_LOGIN_OPTION_FLAGS1_SET_LANG_ON); + + /* OptionFlags2 */ + if (loginInfo->optionFlags2 & LOGIN_OPTION_FLAGS2_LANGUAGE_FATAL) + TDSInstrumentation(INSTR_UNSUPPORTED_TDS_LOGIN_OPTION_FLAGS2_LANGUAGE_FATAL); + + if ((GetClientTDSVersion() < TDS_VERSION_7_2) && (loginInfo->optionFlags2 & LOGIN_OPTION_FLAGS2_TRAN_BOUNDARY)) + TDSInstrumentation(INSTR_UNSUPPORTED_TDS_LOGIN_OPTION_FLAGS2_TRAN_BOUNDARY); + + if ((GetClientTDSVersion() < TDS_VERSION_7_2) && (loginInfo->optionFlags2 & LOGIN_OPTION_FLAGS2_CACHE_CONNECT)) + TDSInstrumentation(INSTR_UNSUPPORTED_TDS_LOGIN_OPTION_FLAGS2_CACHE_CONNECT); + + if (loginInfo->optionFlags2 & LOGIN_OPTION_FLAGS2_USER_TYPE_SERVER) + TDSInstrumentation(INSTR_UNSUPPORTED_TDS_LOGIN_OPTION_FLAGS2_USER_TYPE_SERVER); + + if (loginInfo->optionFlags2 & LOGIN_OPTION_FLAGS2_USER_TYPE_REMUSER) + TDSInstrumentation(INSTR_UNSUPPORTED_TDS_LOGIN_OPTION_FLAGS2_USER_TYPE_REMUSER); + + if (loginInfo->optionFlags2 & LOGIN_OPTION_FLAGS2_USER_TYPE_SQLREPL) + TDSInstrumentation(INSTR_UNSUPPORTED_TDS_LOGIN_OPTION_FLAGS2_USER_TYPE_SQLREPL); + + if (loginInfo->optionFlags2 & LOGIN_OPTION_FLAGS2_INT_SECURITY_ON) + TDSInstrumentation(INSTR_UNSUPPORTED_TDS_LOGIN_OPTION_FLAGS2_INT_SECURITY_ON); + + /* TypeFlags */ + if (loginInfo->typeFlags & LOGIN_TYPE_FLAGS_SQL_TSQL) + TDSInstrumentation(INSTR_UNSUPPORTED_TDS_LOGIN_TYPE_FLAGS_SQL_TSQL); + + if ((GetClientTDSVersion() == TDS_VERSION_7_4) && (loginInfo->typeFlags & LOGIN_TYPE_FLAGS_READ_ONLY_INTENT)) + TDSInstrumentation(INSTR_UNSUPPORTED_TDS_LOGIN_TYPE_FLAGS_READ_ONLY_INTENT); + + /* OptionFlags3 */ + if ((GetClientTDSVersion() >= TDS_VERSION_7_2) && (loginInfo->optionFlags3 & LOGIN_OPTION_FLAGS3_USER_INSTANCE)) + TDSInstrumentation(INSTR_UNSUPPORTED_TDS_LOGIN_OPTION_FLAGS3_USER_INSTANCE); + + if ((GetClientTDSVersion() >= TDS_VERSION_7_2) && (loginInfo->optionFlags3 & LOGIN_OPTION_FLAGS3_SEND_YUKON_BINARY_XML)) + TDSInstrumentation(INSTR_UNSUPPORTED_TDS_LOGIN_OPTION_FLAGS3_SEND_YUKON_BINARY_XML); + + if ((GetClientTDSVersion() >= TDS_VERSION_7_3_A) && (loginInfo->optionFlags3 & LOGIN_OPTION_FLAGS3_UNKNOWN_COLLATION_HANDLING)) + TDSInstrumentation(INSTR_UNSUPPORTED_TDS_LOGIN_OPTION_FLAGS3_UNKNOWN_COLLATION_HANDLING); + + if ((GetClientTDSVersion() == TDS_VERSION_7_4) && (loginInfo->optionFlags3 & LOGIN_OPTION_FLAGS3_EXTENSION)) + TDSInstrumentation(INSTR_UNSUPPORTED_TDS_LOGIN_OPTION_FLAGS3_EXTENSION); +} diff --git a/contrib/babelfishpg_tds/src/backend/tds/tdsprinttup.c b/contrib/babelfishpg_tds/src/backend/tds/tdsprinttup.c new file mode 100644 index 00000000000..4b32f8a2232 --- /dev/null +++ b/contrib/babelfishpg_tds/src/backend/tds/tdsprinttup.c @@ -0,0 +1,116 @@ +/*------------------------------------------------------------------------- + * + * tdsprinttup.c + * Routines to print out tuples to the destination (both frontend + * clients and standalone backends are supported here). + * + * + * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * contrib/babelfishpg_tds/src/backend/tds/tdsprinttup.c + * + *------------------------------------------------------------------------- + */ + +static void TdsPrinttupStartup(DestReceiver *self, int operation, + TupleDesc typeinfo); +static void TdsShutdown(DestReceiver *self); +static void TdsDestroy(DestReceiver *self); + +/* ---------------------------------------------------------------- + * tdsprinttup support + * ---------------------------------------------------------------- + */ + +/* ---------------- + * Maintain and use carefully + * + * Private state for a printtup destination object + * + * NOTE: finfo is the lookup info for either typoutput or typsend, whichever + * we are using for this column. + * ---------------- + */ +typedef struct +{ /* Per-attribute information */ + Oid typoutput; /* Oid for the type's text output fn */ + Oid typsend; /* Oid for the type's binary output fn */ + bool typisvarlena; /* is it varlena (ie possibly toastable)? */ + int16 format; /* format code for this column */ + FmgrInfo finfo; /* Precomputed call info for output fn */ +} PrinttupAttrInfo; + +typedef struct +{ + DestReceiver pub; /* publicly-known function pointers */ + Portal portal; /* the Portal we are printing from */ + bool sendDescrip; /* send RowDescription at startup? */ + TupleDesc attrinfo; /* The attr info we are set up for */ + int nattrs; + PrinttupAttrInfo *myinfo; /* Cached info about each attr */ + StringInfoData buf; /* output buffer (*not* in tmpcontext) */ + MemoryContext tmpcontext; /* Memory context for per-row workspace */ +} DR_printtup; + + +static void +TdsPrinttupStartup(DestReceiver *self, int operation, TupleDesc typeinfo) +{ + DR_printtup *myState = (DR_printtup *) self; + Portal portal = myState->portal; + + /* + * Create I/O buffer to be used for all messages. This cannot be inside + * tmpcontext, since we want to re-use it across rows. + */ + initStringInfo(&myState->buf); + + /* + * Create a temporary memory context that we can reset once per row to + * recover palloc'd memory. This avoids any problems with leaks inside + * datatype output routines, and should be faster than retail pfree's + * anyway. + */ + myState->tmpcontext = AllocSetContextCreate(CurrentMemoryContext, + "printtup", + ALLOCSET_DEFAULT_SIZES); + + TdsSendRowDescription(typeinfo, + FetchPortalTargetList(portal), + portal->formats); + return; +} + +/* ---------------- + * printtup_shutdown + * ---------------- + */ +static void +TdsShutdown(DestReceiver *self) +{ + DR_printtup *myState = (DR_printtup *) self; + + TdsPrintTupShutdown(); + + if (myState->myinfo) + pfree(myState->myinfo); + myState->myinfo = NULL; + + myState->attrinfo = NULL; + + if (myState->buf.data) + pfree(myState->buf.data); + myState->buf.data = NULL; + + if (myState->tmpcontext) + MemoryContextDelete(myState->tmpcontext); + myState->tmpcontext = NULL; +} + +static void +TdsDestroy(DestReceiver *self) +{ + pfree(self); +} diff --git a/contrib/babelfishpg_tds/src/backend/tds/tdsprotocol.c b/contrib/babelfishpg_tds/src/backend/tds/tdsprotocol.c new file mode 100644 index 00000000000..bcfd5b17aa9 --- /dev/null +++ b/contrib/babelfishpg_tds/src/backend/tds/tdsprotocol.c @@ -0,0 +1,707 @@ +/*------------------------------------------------------------------------- + * + * tdsprotocol.c + * TDS Listener tokenized protocol handling + * + * Portions Copyright (c) 2020, AWS + * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * contrib/babelfishpg_tds/src/backend/tds/tdsprotocol.c + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "access/htup_details.h" /* for GETSTRUCT() to extract tuple data */ +#include "access/printtup.h" /* for SetRemoteDestReceiverParams() */ +#include "access/table.h" +#include "access/relation.h" +#include "access/relscan.h" +#include "access/genam.h" +#include "access/xact.h" /* for IsTransactionOrTransactionBlock() */ +#include "catalog/indexing.h" +#include "catalog/pg_type.h" +#include "commands/async.h" +#include "commands/defrem.h" +#include "commands/prepare.h" +#include "executor/spi.h" +#include "fmgr.h" +#include "libpq/pqformat.h" +#include "mb/pg_wchar.h" +#include "miscadmin.h" +#include "nodes/parsenodes.h" +#include "parser/parser.h" +#include "parser/parse_coerce.h" +#include "port/pg_bswap.h" +#include "tcop/pquery.h" +#include "utils/fmgroids.h" +#include "utils/guc.h" +#include "utils/lsyscache.h" +#include "utils/memdebug.h" +#include "utils/numeric.h" +#include "utils/portal.h" +#include "utils/rel.h" +#include "utils/snapmgr.h" + +#include "src/include/tds_debug.h" +#include "src/include/tds_int.h" +#include "src/include/tds_protocol.h" +#include "src/include/tds_response.h" +#include "src/include/faultinjection.h" + +/* + * When we reset the connection, we save the required information in the following + * structure that should be restored after the reset. + */ +typedef struct ResetConnectionData +{ + StringInfo message; + uint8_t messageType; + uint8_t status; +} ResetConnectionData; +typedef ResetConnectionData* ResetConnection; + +/* + * Local structures + */ +TdsRequestCtrlData *TdsRequestCtrl = NULL; + +ResetConnection resetCon = NULL; + +/* Local functions */ +static void ResetTDSConnection(void); +static TDSRequest GetTDSRequest(bool *resetProtocol); +static void ProcessTDSRequest(TDSRequest request); + +/* + * TDSDiscardAll - copy of DiscardAll + */ +static +void TdsDiscardAll() +{ + /* + * Disallow DISCARD ALL in a transaction block. This is arguably + * inconsistent (we don't make a similar check in the command sequence + * that DISCARD ALL is equivalent to), but the idea is to catch mistakes: + * DISCARD ALL inside a transaction block would leave the transaction + * still uncommitted. + */ + PreventInTransactionBlock(true, "DISCARD ALL"); + + /* Closing portals might run user-defined code, so do that first. */ + PortalHashTableDeleteAll(); + SetPGVariable("session_authorization", NIL, false); + ResetAllOptions(); + DropAllPreparedStatements(); + Async_UnlistenAll(); + LockReleaseAll(USER_LOCKMETHOD, true); + ResetPlanCache(); + ResetTempTableNamespace(); + ResetSequenceCaches(); +} + +/* + * ResetTDSConnection - resets the TDS connection + * + * It resets the TDS connection by calling DISCARD ALL api in . Also, it + * releases the memory allocated in TDS layer and re-initializes different + * buffers and structures. Additionally, it sends an environment change token + * for RESETCON. + */ +static void +ResetTDSConnection(void) +{ + const char *isolationOld; + + Assert(TdsRequestCtrl->request == NULL); + Assert(TdsRequestCtrl->requestContext != NULL); + TdsErrorContext->err_text = "Resetting the TDS connection"; + + /* Make sure we've killed any active transaction */ + AbortOutOfAnyTransaction(); + + /* + * Save the transaction isolation level that should be restored after connection + * reset. + */ + isolationOld = GetConfigOption("default_transaction_isolation", false, false); + + /* + * Start an implicit transaction block because the internal code may need + * to access the catalog. + */ + StartTransactionCommand(); + TdsDiscardAll(); + pltsql_plugin_handler_ptr->reset_session_properties(); + CommitTransactionCommand(); + + /* + * Now reset the TDS top memory context and re-initialize everything. Also, + * restore the transaction isolation level. + */ + MemoryContextReset(TdsMemoryContext); + TdsCommReset(); + TdsProtocolInit(); + TdsResetCache(); + TdsResponseReset(); + SetConfigOption("default_transaction_isolation", isolationOld, + PGC_BACKEND, PGC_S_CLIENT); + + tvp_lookup_list = NIL; + + /* send an environement change token */ + TdsSendEnvChange(TDS_ENVID_RESETCON, NULL, NULL); +} + +/* + * GetTDSRequest - Fetch and parse a TDS packet and generate a TDS request that + * can be processed later. + * + * Note that, this method is called in TDS Request Context so that any allocation + * done here will get reset only after sending the response. + * + * resetProtocol - set to true if we've reset the connection. + */ +static TDSRequest +GetTDSRequest(bool *resetProtocol) +{ + uint8_t messageType; + uint8_t status; + TDSRequest request; + StringInfoData message; + + initStringInfo(&message); + + /* + * Setup error traceback support for ereport() + */ + TdsErrorContext->err_text = "Fetching TDS 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 (resetCon != NULL) + { + messageType = resetCon->messageType; + status = resetCon->status; + appendBinaryStringInfo(&message, resetCon->message->data, resetCon->message->len); + + /* cleanup and reset */ + pfree(resetCon->message->data); + pfree(resetCon->message); + pfree(resetCon); + resetCon = NULL; + } + 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 == NULL) + { + int ret; + + /* + * We should hold the interrupts untill we read the entire + * request. + */ + HOLD_CANCEL_INTERRUPTS(); + ret = TdsReadNextRequest(&message, &status, &messageType); + RESUME_CANCEL_INTERRUPTS(); + TdsErrorContext->err_text = "Fetching TDS Request"; + + if (ret != 0) + { + TDS_DEBUG(TDS_DEBUG1, "EOF on TDS socket"); + pfree(message.data); + return NULL; + } + TdsRequestCtrl->status = status; + } + else + RestoreRPCBatch(&message, &status, &messageType); + } + + DebugPrintMessageData("Fetched message:", message); + + TdsErrorContext->reqType = messageType; + + #ifdef FAULT_INJECTOR + { + TdsMessageWrapper wrapper; + wrapper.message = &message; + wrapper.messageType = messageType; + + FAULT_INJECT(PreParsingType, &wrapper); + } + #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 (status & TDS_PACKET_HEADER_STATUS_RESETCON) + { + MemoryContextSwitchTo(TopMemoryContext); + + if (resetCon == NULL) + resetCon = palloc(sizeof(ResetConnectionData)); + + resetCon->message = makeStringInfo(); + appendBinaryStringInfo(resetCon->message, message.data, message.len); + resetCon->messageType = messageType; + resetCon->status = (status & ~TDS_PACKET_HEADER_STATUS_RESETCON); + + ResetTDSConnection(); + 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. + */ + if (status & TDS_PACKET_HEADER_STATUS_RESETCONSKIPTRAN) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("RESETCONSKIPTRAN is not supported"))); + + /* An attention request can also have message.len = 0. */ + if (message.len == 0 && messageType != TDS_ATTENTION) + { + TDS_DEBUG(TDS_DEBUG1, "zero byte client message on TDS socket"); + pfree(message.data); + return NULL; + } + + /* Parse the packet */ + switch (messageType) + { + case TDS_QUERY: /* Simple SQL BATCH */ + { + request = GetSQLBatchRequest(&message); + + pfree(message.data); + } + break; + case TDS_RPC: /* Remote procedure call */ + { + request = GetRPCRequest(&message); + } + break; + case TDS_TXN: /* Transaction management request */ + { + request = GetTxnMgmtRequest(&message); + } + break; + case TDS_BULK_LOAD: /* Bulk Load request */ + { + request = GetBulkLoadRequest(&message); + } + break; + case TDS_ATTENTION: /* Attention request */ + { + /* Return an empty request with the attention type. */ + request = palloc0(sizeof(TDSRequest)); + request->reqType = TDS_REQUEST_ATTN; + } + break; + default: + DebugPrintMessageData("Ignored message", message); + elog(ERROR, "TDSRequest: ignoring request type 0x%02x", + message.data[0]); + } + } + PG_CATCH(); + { + PG_RE_THROW(); + } + PG_END_TRY(); + + FAULT_INJECT(PostParsingType, request); + + return request; +} + +/* + * ProcessTDSRequest - TDS specific processing of the request + * + * Note that, this method is called in MessageContext so that any allocation + * done here can be reset in next TCOP iteration. + */ +static void +ProcessTDSRequest(TDSRequest request) +{ + /* + * Setup error traceback support for ereport() + */ + TdsErrorContext->err_text = "Processing TDS 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. + */ + if (IsAbortedTransactionBlockState()) + elog(FATAL, "terminating connection due to unexpected TSQL transaction state"); + + PG_TRY(); + { + StartTransactionCommand(); + MemoryContextSwitchTo(MessageContext); + pltsql_plugin_handler_ptr->stmt_needs_logging = false; + + switch (request->reqType) + { + case TDS_REQUEST_SP_NUMBER: + { + ProcessRPCRequest(request); + } + break; + case TDS_REQUEST_SQL_BATCH: + { + ProcessSQLBatchRequest(request); + } + break; + case TDS_REQUEST_TXN_MGMT: + { + ProcessTxnMgmtRequest(request); + } + break; + case TDS_REQUEST_ATTN: + { + TdsSendDone(TDS_TOKEN_DONE, TDS_DONE_ATTN, 0xfd, 0); + } + break; + case TDS_REQUEST_BULK_LOAD: + { + ProcessBCPRequest(request); + } + break; + default: + /* GetTDSRequest() should've returned the correct request type */ + Assert(0); + break; + } + CommitTransactionCommand(); + MemoryContextSwitchTo(MessageContext); + + } + PG_CATCH(); + { + int token_type; + int command_type = TDS_CMD_UNKNOWN; + + CommitTransactionCommand(); + MemoryContextSwitchTo(MessageContext); + + EmitErrorReport(); + FlushErrorState(); + + if (request->reqType == TDS_REQUEST_SP_NUMBER) + token_type = TDS_TOKEN_DONEPROC; + else + token_type = TDS_TOKEN_DONE; + + TdsSendDone(token_type, TDS_DONE_ERROR, command_type, 0); + } + PG_END_TRY(); +} + +void +TdsProtocolInit(void) +{ + MemoryContext oldContext; + + SetConfigOption("babelfishpg_tsql.sql_dialect", "tsql", PGC_SU_BACKEND, PGC_S_OVERRIDE); + oldContext = MemoryContextSwitchTo(TdsMemoryContext); + TdsRequestCtrl = palloc(sizeof(TdsRequestCtrlData)); + TdsRequestCtrl->phase = TDS_REQUEST_PHASE_INIT; + + TdsRequestCtrl->requestContext = AllocSetContextCreate(TdsMemoryContext, + "TDS Request", + ALLOCSET_DEFAULT_SIZES); + TdsRequestCtrl->request = NULL; + TdsRequestCtrl->status = 0; + + MemoryContextSwitchTo(oldContext); +} + +void +TdsProtocolFinish(void) +{ + SetConfigOption("babelfishpg_tsql.sql_dialect", "postgres", PGC_SU_BACKEND, PGC_S_OVERRIDE); + + if (TdsRequestCtrl->requestContext) + { + MemoryContextDelete(TdsRequestCtrl->requestContext); + TdsRequestCtrl->requestContext = NULL; + } + + pfree(TdsRequestCtrl); + TdsRequestCtrl = NULL; +} + +/* + * TdsSocketBackend() Is called for frontend-backend TDS connections + * + * This function reads requests from a TDS client and executes the same. We + * leave the function only in case of an error or if connection is lost. EOF + * is returned if the connection is lost. + */ +int +TdsSocketBackend(void) +{ + bool resetProtocol; + bool loop = true; + while (loop) + { + PG_TRY(); + { + switch (TdsRequestCtrl->phase) + { + case TDS_REQUEST_PHASE_INIT: + { + MemoryContext oldContext; + resetProtocol = false; + + TdsErrorContext->phase = "TDS_REQUEST_PHASE_INIT"; + /* + * Switch to the request context. We reset this context once + * once TDSfunctionCache is loaded + */ + oldContext = MemoryContextSwitchTo(TdsMemoryContext); + + InitTDSResponse(); + StartTransactionCommand(); + PushActiveSnapshot(GetTransactionSnapshot()); + + /* + * 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 + */ + TdsLoadTypeFunctionCache(); + TdsLoadEncodingLCIDCache(); + PopActiveSnapshot(); + CommitTransactionCommand(); + + MemoryContextSwitchTo(oldContext); + + /* 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)) + elog(FATAL, "sp_executesql_callback is not initialized"); + if (!(pltsql_plugin_handler_ptr->sp_prepare_callback)) + elog(FATAL, "sp_prepare_callback is not initialized"); + if (!(pltsql_plugin_handler_ptr->sp_execute_callback)) + elog(FATAL, "sp_execute_callback is not initialized"); + if (!(pltsql_plugin_handler_ptr->sp_prepexec_callback)) + elog(FATAL, "sp_prepexec_callback is not initialized"); + if (!(pltsql_plugin_handler_ptr->sp_unprepare_callback)) + elog(FATAL, "sp_unprepare_callback is not initialized"); + if (!(pltsql_plugin_handler_ptr->pltsql_declare_var_callback)) + elog(FATAL, "pltsql_declare_var_callback is not initialized"); + if (!(pltsql_plugin_handler_ptr->pltsql_read_out_param_callback)) + elog(FATAL, "pltsql_read_out_param_callback is not initialized"); + if (!(pltsql_plugin_handler_ptr->sp_cursoropen_callback)) + elog(FATAL, "sp_cursoropen_callback is not initialized"); + if (!(pltsql_plugin_handler_ptr->sp_cursorclose_callback)) + elog(FATAL, "sp_cursorclose_callback is not initialized"); + if (!(pltsql_plugin_handler_ptr->sp_cursorfetch_callback)) + elog(FATAL, "sp_cursorfetch_callback is not initialized"); + if (!(pltsql_plugin_handler_ptr->sp_cursorexecute_callback)) + elog(FATAL, "sp_cursorexecute_callback is not initialized"); + if (!(pltsql_plugin_handler_ptr->sp_cursorprepexec_callback)) + elog(FATAL, "sp_cursorprepexec_callback is not initialized"); + if (!(pltsql_plugin_handler_ptr->sp_cursorprepare_callback)) + elog(FATAL, "sp_cursorprepare is not initialized"); + if (!(pltsql_plugin_handler_ptr->sp_cursorunprepare_callback)) + elog(FATAL, "sp_cursorunprepare is not initialized"); + if (!(pltsql_plugin_handler_ptr->send_column_metadata)) + elog(FATAL, "send_column_metadata is not initialized"); + + /* Ready to fetch the next request */ + TdsRequestCtrl->phase = TDS_REQUEST_PHASE_FETCH; + break; + } + case TDS_REQUEST_PHASE_FETCH: + { + MemoryContext oldContext; + TdsErrorContext->phase = "TDS_REQUEST_PHASE_FETCH"; + + /* + * 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. + */ + InvalidateCatalogSnapshotConditionally(); + + /* + * We should hold the interrupts untill we read the entire + * request. + */ + resetProtocol = false; + TdsRequestCtrl->request = GetTDSRequest(&resetProtocol); + + MemoryContextSwitchTo(oldContext); + + /* if we've reset the connection, break here. */ + if (resetProtocol) + { + /* the next phase should be set to init phase */ + Assert(TdsRequestCtrl->phase == TDS_REQUEST_PHASE_INIT); + break; + } + + if (TdsRequestCtrl->request == NULL) + return EOF; + + /* Switch the TDS protocol to RESPONSE mode */ + TdsSetMessageType(TDS_RESPONSE); + + /* we should be in tsql dialect */ + if (sql_dialect != SQL_DIALECT_TSQL) + elog(ERROR, "babelfishpg_tsql.sql_dialect is not set to tsql"); + + /* Now, process the request */ + TdsRequestCtrl->phase = TDS_REQUEST_PHASE_PROCESS; + + /* + * Break here. We will process the request later in + * PostgresMain function. + */ + loop = false; + break; + } + + case TDS_REQUEST_PHASE_PROCESS: + { + TdsErrorContext->phase = "TDS_REQUEST_PHASE_PROCESS"; + TdsRequestCtrl->isEmptyResponse = true; + + ProcessTDSRequest(TdsRequestCtrl->request); + + /* we should be still in MessageContext */ + Assert(CurrentMemoryContext == MessageContext); + + /* + * 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)) + TdsRequestCtrl->phase = TDS_REQUEST_PHASE_FETCH; + else + /* + * 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. + */ + loop = false; + break; + } + case TDS_REQUEST_PHASE_FLUSH: + { + TdsErrorContext->phase = "TDS_REQUEST_PHASE_FLUSH"; + /* Send the response now */ + TdsFlush(); + + /* Cleanups */ + MemoryContextReset(TdsRequestCtrl->requestContext); + + /* Reset the request */ + TdsRequestCtrl->request = NULL; + + /* Ready to fetch the next request */ + TdsRequestCtrl->phase = TDS_REQUEST_PHASE_FETCH; + + break; + } + case TDS_REQUEST_PHASE_ERROR: + 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. + * 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. + */ + + /* + * 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); + + /* We're done. Send the response. */ + TdsRequestCtrl->phase = TDS_REQUEST_PHASE_FLUSH; + break; + } + } + PG_CATCH(); + { + 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 + * action, we can do that here as a pre-processing or in + * TDS_REQUEST_PHASE_ERROR state as post-processing. + */ + PG_RE_THROW(); + } + PG_END_TRY(); + } + + return 0; +} + +int +TestGetTdsRequest(uint8_t reqType, const char *expectedStr) +{ + int res = 0; + bool resetProtocol; + TDSRequest request = GetTDSRequest(&resetProtocol); + switch(reqType) + { + case TDS_TXN: + res = TestTxnMgmtRequest(request, expectedStr); + break; + default: + return -1; + } + return res; +} diff --git a/contrib/babelfishpg_tds/src/backend/tds/tdsresponse.c b/contrib/babelfishpg_tds/src/backend/tds/tdsresponse.c new file mode 100644 index 00000000000..6cdc663b115 --- /dev/null +++ b/contrib/babelfishpg_tds/src/backend/tds/tdsresponse.c @@ -0,0 +1,2905 @@ +/*------------------------------------------------------------------------- + * + * tdsresponse.c + * TDS Listener functions for sending a TDS response + * + * Portions Copyright (c) 2020, AWS + * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * contrib/babelfishpg_tds/src/backend/tds/tdsresponse.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "access/htup_details.h" /* for GETSTRUCT() to extract tuple data */ +#include "access/printtup.h" /* for SetRemoteDestReceiverParams() */ +#include "access/xact.h" /* for IsTransactionOrTransactionBlock() */ +#include "access/genam.h" +#include "access/heapam.h" +#include "catalog/indexing.h" +#include "catalog/pg_proc.h" +#include "catalog/pg_type.h" +#include "miscadmin.h" +#include "nodes/pathnodes.h" +#include "parser/parse_coerce.h" +#include "utils/fmgroids.h" +#include "utils/lsyscache.h" +#include "utils/memdebug.h" +#include "utils/numeric.h" +#include "utils/portal.h" +#include "utils/rel.h" +#include "utils/syscache.h" + +#include "src/include/tds_instr.h" +#include "src/include/tds_int.h" +#include "src/include/tds_protocol.h" +#include "src/include/tds_response.h" +#include "src/include/guc.h" + +#define SP_FLAGS_WITHRECOMP 0x01 +#define SP_FLAGS_NOMETADATA 0x02 +#define SP_FLAGS_REUSEMETADATA 0x04 + +/* ColInfo token flags */ +#define COLUMN_STATUS_EXPRESSION 0x04 +#define COLUMN_STATUS_KEY 0x08 +#define COLUMN_STATUS_HIDDEN 0x10 +#define COLUMN_STATUS_DIFFERENT_NAME 0x20 + +/* two possible values of rowstat column */ +#define SP_CURSOR_FETCH_SUCCEEDED 0x0001 +#define SP_CURSOR_FETCH_MISSING 0x0002 + +/* Numeirc operator OID from pg_proc.dat */ +#define NUMERIC_ADD_OID 1724 +#define NUMERIC_SUB_OID 1725 +#define NUMERIC_MUL_OID 1726 +#define NUMERIC_DIV_OID 1727 +#define NUMERIC_MOD_OID 1728 +#define NUMERIC_MOD_OID2 1729 +#define NUMERIC_UPLUS_OID 1915 +#define NUMERIC_UMINUS_OID 1771 + +#define Max(x, y) ((x) > (y) ? (x) : (y)) +#define Min(x, y) ((x) < (y) ? (x) : (y)) + +/* + * Local structures and functions copied from printtup.c + */ +typedef struct +{ /* Per-attribute information */ + Oid typoutput; /* Oid for the type's text output fn */ + Oid typsend; /* Oid for the type's binary output fn */ + bool typisvarlena; /* is it varlena (ie possibly toastable)? */ + int16 format; /* format code for this column */ + FmgrInfo finfo; /* Precomputed call info for output fn */ +} PrinttupAttrInfo; + +typedef struct +{ + DestReceiver pub; /* publicly-known function pointers */ + Portal portal; /* the Portal we are printing from */ + bool sendDescrip; /* send RowDescription at startup? */ + TupleDesc attrinfo; /* The attr info we are set up for */ + int nattrs; + PrinttupAttrInfo *myinfo; /* Cached info about each attr */ + StringInfoData buf; /* output buffer (*not* in tmpcontext) */ + MemoryContext tmpcontext; /* Memory context for per-row workspace */ +} DR_printtup; + +typedef struct TdsExecutionStateData +{ + 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 uint16_t TdsPendingDoneStatus; +static uint16_t TdsPendingDoneCurCmd; +static uint64_t TdsPendingDoneRowCnt; +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 TdsColumnMetaData *colMetaData = NULL; +static List *relMetaDataInfoList = NULL; + +static void FillTabNameWithNumParts(StringInfo buf, uint8 numParts, TdsRelationMetaDataInfo relMetaDataInfo); +static void FillTabNameWithoutNumParts(StringInfo buf, uint8 numParts, TdsRelationMetaDataInfo relMetaDataInfo); +static void SetTdsEstateErrorData(void); +static void ResetTdsEstateErrorData(void); +static bool get_attnotnull(Oid relid, AttrNumber attnum); + +static inline void +SendPendingDone(bool more) +{ + /* + * If this is the last token, there better be at least one pending done + * token to send. We also call this function after sending the prelogin + * response although we don't have any done token to send. So just do + * this check once protocol code is initialized. + */ + Assert(!TdsRequestCtrl || more || TdsHavePendingDone); + + /* + * 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)); + + if (TdsHavePendingDone) + { + uint32_t tdsVersion = GetClientTDSVersion(); + TdsHavePendingDone = false; + + /* In NOCOUNT=ON mode we need to suppress the DONE_COUNT */ + if (TdsPendingDoneNocount) + TdsPendingDoneStatus &= ~TDS_DONE_COUNT; + + /* If done token follows error token then suppress DONE_COUNT */ + if (TdsPendingDoneStatus & TDS_DONE_ERROR) + TdsPendingDoneStatus &= ~TDS_DONE_COUNT; + + if (more) + { + /* Suppress non-SELECT DONEINPROC while NOCOUNT=ON */ + if (TdsPendingDoneNocount && + TdsPendingDoneToken == TDS_TOKEN_DONEINPROC && + TdsPendingDoneCurCmd != TDS_CMD_SELECT) + { + return; + } + + TdsPendingDoneStatus |= TDS_DONE_MORE; + } + + /* extra handling if this follows an error token */ + if (tds_estate && (TdsPendingDoneStatus & TDS_DONE_ERROR)) + { + /* TODO: If we've saved the error command type, send the same. */ + + /* + * 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. + */ + tds_estate->error_stack_offset = 0; + + /* + * If a statement throws an error, the row count should be + * always 0. + */ + Assert(TdsPendingDoneRowCnt == 0); + } + + TDS_DEBUG(TDS_DEBUG3, "SendPendingDone: putbytes"); + TdsPutbytes(&TdsPendingDoneToken, sizeof(TdsPendingDoneToken)); + TdsPutbytes(&TdsPendingDoneStatus, sizeof(TdsPendingDoneStatus)); + 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. + */ + if (tdsVersion <= TDS_VERSION_7_1_1) + { + uint32_t TdsPendingDoneRowCnt_32; + if (TdsPendingDoneRowCnt > PG_UINT32_MAX) + ereport(FATAL, (errmsg("Row Count execeeds UINT32_MAX"))); + else + TdsPendingDoneRowCnt_32 = (int32_t) TdsPendingDoneRowCnt; + TdsPutbytes(&TdsPendingDoneRowCnt_32, sizeof(TdsPendingDoneRowCnt_32)); + } + else + TdsPutbytes(&TdsPendingDoneRowCnt, sizeof(TdsPendingDoneRowCnt)); + } +} + +/* + * Given a relation, fetch the attributes number which are part of the primary + * key on this table. + */ +static AttrNumber * +getPkeyAttnames(Relation rel, int16 *indnkeyatts) +{ + 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; + + /* Prepare to scan pg_index for entries having indrelid = this rel. */ + indexRelation = table_open(IndexRelationId, AccessShareLock); + ScanKeyInit(&skey, + Anum_pg_index_indrelid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(RelationGetRelid(rel))); + + scan = systable_beginscan(indexRelation, IndexIndrelidIndexId, true, + NULL, 1, &skey); + + while (HeapTupleIsValid(indexTuple = systable_getnext(scan))) + { + Form_pg_index index = (Form_pg_index) GETSTRUCT(indexTuple); + + /* we're only interested if it is the primary key */ + if (index->indisprimary) + { + *indnkeyatts = index->indnkeyatts; + if (*indnkeyatts > 0) + { + result = (AttrNumber *) palloc(*indnkeyatts * sizeof(AttrNumber)); + + for (i = 0; i < *indnkeyatts; i++) + result[i] = (AttrNumber) DatumGetInt16(index->indkey.values[i]); + } + break; + } + } + + systable_endscan(scan); + table_close(indexRelation, AccessShareLock); + + return result; +} + +/* + * Fill Table Name With NumParts, a multi-part table name, which was introduced in + * TDS 7.2 for Column Metadata Token and introduced in TDS 7.1 revision 1 for TableName Token. + */ +static void +FillTabNameWithNumParts(StringInfo buf, uint8 numParts, TdsRelationMetaDataInfo relMetaDataInfo) +{ + 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'; + * + * 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. + */ + + appendBinaryStringInfo(buf, (char *) &numParts, sizeof(numParts)); + while (numParts-- > 0) + { + uint16_t partNameLen; + char *partName = relMetaDataInfo->partName[numParts]; + + resetStringInfo(&tempBuf); + TdsUTF8toUTF16StringInfo(&tempBuf, partName, strlen(partName)); + + partNameLen = htoLE16((uint16_t) pg_mbstrlen(partName)); + appendBinaryStringInfo(buf, (char *) &partNameLen, sizeof(partNameLen)); + appendBinaryStringInfo(buf, tempBuf.data, tempBuf.len); + } + + pfree(tempBuf.data); +} + +/* + * Fill Table Name Without NumParts, a single-part table name, for Protocol versions below + * TDS 7.2 for Column Metadata Token and below TDS 7.1 revision 1 for TableName Token. + */ +static void +FillTabNameWithoutNumParts(StringInfo buf, uint8 numParts, TdsRelationMetaDataInfo relMetaDataInfo) +{ + 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 + */ + + while (numParts-- > 0) + tableName = psprintf("%s.%s", tableName, relMetaDataInfo->partName[numParts]); + + if (strlen(tableName)) + tableName++; /* skip the first '.' */ + TableNameLen += htoLE16((uint16_t) pg_mbstrlen(tableName)); + + TdsUTF8toUTF16StringInfo(&tempBuf, tableName, strlen(tableName)); + appendBinaryStringInfo(buf, (char *) &TableNameLen, sizeof(TableNameLen)); + appendBinaryStringInfo(buf, tempBuf.data, tempBuf.len); + + pfree(tempBuf.data); +} + +/* + * Get the lookup info that TdsPrintTup() needs. + * Code is copied from backend/access/common/printtup.c + */ +static void +PrintTupPrepareInfo(DR_printtup *myState, TupleDesc typeinfo, int numAttrs) +{ + int16 *formats = myState->portal->formats; + int i; + + /* get rid of any old data */ + if (myState->myinfo) + pfree(myState->myinfo); + myState->myinfo = NULL; + + myState->attrinfo = typeinfo; + myState->nattrs = numAttrs; + if (numAttrs <= 0) + return; + + myState->myinfo = (PrinttupAttrInfo *) + palloc0(numAttrs * sizeof(PrinttupAttrInfo)); + + for (i = 0; i < numAttrs; i++) + { + PrinttupAttrInfo *thisState = myState->myinfo + i; + int16 format = (formats ? formats[i] : 0); + Form_pg_attribute attr = TupleDescAttr(typeinfo, i); + + thisState->format = format; + if (format == 0) + { + getTypeOutputInfo(attr->atttypid, + &thisState->typoutput, + &thisState->typisvarlena); + fmgr_info(thisState->typoutput, &thisState->finfo); + } + else if (format == 1) + { + getTypeBinaryOutputInfo(attr->atttypid, + &thisState->typsend, + &thisState->typisvarlena); + fmgr_info(thisState->typsend, &thisState->finfo); + } + else + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("unsupported format code: %d", format))); + } +} + +/* look for a typmod to return from a numeric expression */ +static int32 +resolve_numeric_typmod_from_exp(Node *expr) +{ + if (expr == NULL) + return -1; + 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; + int32 typmod1 = -1, typmod2 = -1; + uint8_t scale1, scale2, precision1, precision2; + uint8_t scale, precision; + + 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 + { + /* 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; + } + + /* + * BABEL-2048 Handling arithmetic overflow exception + * when one of the operands is of NON-numeric datatype. + * Use tds_default_numeric_precision/scale if both operands + * are without typmod which probabaly won't happen. + * If one of the operand doesn't have typmod, apply + * the same typmod as the other operand. This makes sense + * because it's equivalent to casting the operand without + * typmod to the other operand's type and typmod then + * do the operation. + */ + if (typmod1 == -1 && typmod2 == -1) + { + precision = tds_default_numeric_precision; + scale = tds_default_numeric_scale; + return ((precision << 16) | scale) + VARHDRSZ; + } + else if (typmod1 == -1) + { + precision1 = precision2; + scale1 = scale2; + } + 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 + */ + switch (op->opfuncid) + { + case NUMERIC_ADD_OID: + case NUMERIC_SUB_OID: + scale = Max(scale1, scale2); + precision = Max(precision1 - scale1, precision2 - scale2) + 1 + scale; + break; + case NUMERIC_MUL_OID: + scale = scale1 + scale2; + precision = precision1 + precision2 + 1; + break; + case NUMERIC_DIV_OID: + scale = Max(6, scale1 + precision2 + 1); + precision = precision1 - scale1 + scale2 + scale; + break; + case NUMERIC_MOD_OID: + case NUMERIC_MOD_OID2: + scale = Max(scale1, scale2); + precision = Min(precision1-scale1, precision2 -scale2) + scale; + break; + case NUMERIC_UPLUS_OID: + case NUMERIC_UMINUS_OID: + scale = scale1; + precision = precision1; + break; + default: + return -1; + } + + /* + * Mitigate precision overflow if integral precision <= 38 + * Otherwise it simply won't fit in 38 precision and let an + * overflow error be thrown in PrepareRowDescription. + */ + if (precision > TDS_MAX_NUM_PRECISION && + precision - scale <= TDS_MAX_NUM_PRECISION) + { + int delta = precision - TDS_MAX_NUM_PRECISION; + precision = TDS_MAX_NUM_PRECISION; + scale = Max(scale - delta, 0); + } + + return ((precision << 16) | scale) + VARHDRSZ; + } + case T_FuncExpr: + { + FuncExpr *func = (FuncExpr *) expr; + Oid func_oid = InvalidOid; + int rettypmod = -1; + + /* Be smart about length-coercion functions... */ + if (exprIsLengthCoercion(expr, &rettypmod)) + return rettypmod; + + /* + * Look up the return type typmod from a persistent + * store using the function oid. + */ + func_oid = func->funcid; + Assert(func_oid != InvalidOid); + + if(func->funcresulttype != VOIDOID) + rettypmod = pltsql_plugin_handler_ptr->pltsql_read_numeric_typmod(func_oid, + func->args == NIL ? 0 : func->args->length, + func->funcresulttype); + return rettypmod; + } + 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; + + Assert(nullif->args != NIL); + + 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); + } + 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); + } + 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; + + Assert(aggref->args != NIL); + + te = (TargetEntry *) linitial(aggref->args); + return resolve_numeric_typmod_from_exp((Node *) te->expr); + } + case T_PlaceHolderVar: + { + PlaceHolderVar *phv = (PlaceHolderVar *) expr; + + return resolve_numeric_typmod_from_exp((Node *) phv->phexpr); + } + case T_RelabelType: + { + 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; + } +} + +void +InitTDSResponse(void) +{ + tds_estate = palloc(sizeof(TdsExecutionStateData)); + tds_estate->current_stack = 0; + tds_estate->error_stack_offset = 0; + tds_estate->cur_error_number = -1; + tds_estate->cur_error_severity = -1; + tds_estate->cur_error_state = -1; +} + +void +TdsResponseReset(void) +{ + tds_estate = NULL; +} + +/* + * MakeEmptyParameterToken - prepare an empty parameter token + * + * In this function, we prepare a parameter token corresponding to the + * caller provided pg_type.oid and corresponding atttypmod and attcollation. + * Additionally, we assign NULL as value to the parameter. + */ +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(); + + coll_info_t cinfo = (pltsql_plugin_handler_ptr)->lookup_collation_table_callback(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"); + + initStringInfo(&(temp->paramMeta.colName)); + appendStringInfo(&(temp->paramMeta.colName), "%s", name); + + col = &(temp->paramMeta); + finfo = TdsLookupTypeFunctionsByOid(atttypid, &atttypmod); + SetParamMetadataCommonInfo(col, finfo); + + temp->paramOrdinal = -1; + temp->len = -1; + temp->maxLen = -1; + temp->isNull = true; + + switch (finfo->sendFuncId) + { + /* TODO boolean is equivalent to TSQL BIT type */ + case TDS_SEND_BIT: + SetColMetadataForFixedType(col, TDS_TYPE_BIT, TDS_MAXLEN_BIT); + temp->maxLen = 1; + break; + case TDS_SEND_TINYINT: + SetColMetadataForFixedType(col, TDS_TYPE_INTEGER, TDS_MAXLEN_TINYINT); + temp->maxLen = 1; + break; + case TDS_SEND_SMALLINT: + SetColMetadataForFixedType(col, TDS_TYPE_INTEGER, TDS_MAXLEN_SMALLINT); + temp->maxLen = 2; + break; + case TDS_SEND_INTEGER: + SetColMetadataForFixedType(col, TDS_TYPE_INTEGER, TDS_MAXLEN_INT); + temp->maxLen = 4; + break; + case TDS_SEND_BIGINT: + SetColMetadataForFixedType(col, TDS_TYPE_INTEGER, TDS_MAXLEN_BIGINT); + temp->maxLen = 8; + break; + case TDS_SEND_FLOAT4: + SetColMetadataForFixedType(col, TDS_TYPE_FLOAT, TDS_MAXLEN_FLOAT4); + temp->maxLen = 4; + break; + case TDS_SEND_FLOAT8: + SetColMetadataForFixedType(col, TDS_TYPE_FLOAT, TDS_MAXLEN_FLOAT8); + temp->maxLen = 8; + break; + case TDS_SEND_CHAR: + SetColMetadataForCharTypeHelper(col, TDS_TYPE_CHAR, + attcollation, (atttypmod - 4)); + /* if attypmod is -1, consider the datatype as CHAR(MAX) */ + if (atttypmod == -1) + temp->maxLen = 0xFFFF; + break; + case TDS_SEND_NCHAR: + SetColMetadataForCharTypeHelper(col, TDS_TYPE_NCHAR, + attcollation, (atttypmod-4) * 2); + /* if attypmod is -1, consider the datatype as NCHAR(MAX) */ + if (atttypmod == -1) + temp->maxLen = 0xFFFF; + break; + case TDS_SEND_VARCHAR: + SetColMetadataForCharTypeHelper(col, TDS_TYPE_VARCHAR, + attcollation, (atttypmod == -1) ? + atttypmod : (atttypmod - 4)); + /* if attypmod is -1, consider the datatype as VARCHAR(MAX) */ + if (atttypmod == -1) + temp->maxLen = 0xFFFF; + break; + case TDS_SEND_NVARCHAR: + SetColMetadataForCharTypeHelper(col, TDS_TYPE_NVARCHAR, + attcollation, (atttypmod == -1) ? + atttypmod : (atttypmod - 4) * 2); + /* if attypmod is -1, consider the datatype as NVARCHAR(MAX) */ + if (atttypmod == -1) + temp->maxLen = 0xFFFF; + break; + case TDS_SEND_MONEY: + SetColMetadataForFixedType(col, TDS_TYPE_MONEYN, TDS_MAXLEN_MONEY); + temp->maxLen = 8; + break; + case TDS_SEND_SMALLMONEY: + SetColMetadataForFixedType(col, TDS_TYPE_MONEYN, TDS_MAXLEN_SMALLMONEY); + temp->maxLen = 4; + break; + case TDS_SEND_TEXT: + SetColMetadataForTextTypeHelper(col, TDS_TYPE_TEXT, + attcollation, (atttypmod - 4)); + break; + case TDS_SEND_NTEXT: + SetColMetadataForTextTypeHelper(col, TDS_TYPE_NTEXT, + attcollation, (atttypmod - 4) * 2); + 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. + */ + SetColMetadataForCharTypeHelper(col, TDS_TYPE_NVARCHAR, serverCollationOid, 20); + else + { + SetColMetadataForDateType(col, TDS_TYPE_DATE); + temp->maxLen = 3; + } + break; + case TDS_SEND_DATETIME: + SetColMetadataForFixedType(col, TDS_TYPE_DATETIMEN, TDS_MAXLEN_DATETIME); + temp->maxLen = 8; + break; + case TDS_SEND_NUMERIC: + { + 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. + */ + if (atttypmod >= VARHDRSZ) + { + scale = (atttypmod - VARHDRSZ) & 0xffff; + precision = ((atttypmod - VARHDRSZ) >> 16) & 0xffff; + } + else + { + precision = tds_default_numeric_precision; + scale = tds_default_numeric_scale; + } + SetColMetadataForNumericType(col, TDS_TYPE_NUMERICN, 17, precision, scale); + temp->maxLen = 17; + } + break; + case TDS_SEND_SMALLDATETIME: + SetColMetadataForFixedType(col, TDS_TYPE_DATETIMEN, TDS_MAXLEN_SMALLDATETIME); + temp->maxLen = 4; + break; + case TDS_SEND_IMAGE: + SetColMetadataForImageType(col, TDS_TYPE_IMAGE); + break; + case TDS_SEND_BINARY: + SetColMetadataForBinaryType(col, TDS_TYPE_BINARY, atttypmod - 4); + /* if attypmod is -1, consider the datatype as BINARY(MAX) */ + if (atttypmod == -1) + temp->maxLen = 0xFFFF; + break; + case TDS_SEND_VARBINARY: + /* 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) */ + if (atttypmod == -1) + temp->maxLen = 0xFFFF; + break; + case TDS_SEND_UNIQUEIDENTIFIER: + SetColMetadataForFixedType(col, TDS_TYPE_UNIQUEIDENTIFIER, TDS_MAXLEN_UNIQUEIDENTIFIER); + temp->maxLen = 16; + 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. + */ + 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 (atttypmod == -1) + atttypmod = 6; + SetColMetadataForTimeType(col, TDS_TYPE_TIME, atttypmod); + temp->maxLen = 5; + } + 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. + */ + 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 (atttypmod == -1) + atttypmod = 6; + SetColMetadataForTimeType(col, TDS_TYPE_DATETIME2, atttypmod); + temp->maxLen = 8; + } + break; + case TDS_SEND_XML: + 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. + */ + SetColMetadataForTextTypeHelper(col, TDS_TYPE_NTEXT, + attcollation, (atttypmod - 4) * 2); + break; + case TDS_SEND_SQLVARIANT: + SetColMetadataForImageType(col, TDS_TYPE_SQLVARIANT); + 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. + */ + SetColMetadataForCharTypeHelper(col, TDS_TYPE_NVARCHAR, serverCollationOid, 64); + else + { + if (atttypmod == -1) + atttypmod = 6; + SetColMetadataForTimeType(col, TDS_TYPE_DATETIMEOFFSET, atttypmod); + temp->maxLen = 10; + } + break; + default: + /* + * TODO: Need to create a mapping table for user defined + * data types and handle it here. + */ + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("data type %d not supported as out parameter", atttypid))); + } + + temp->type = col->metaEntry.type1.tdsTypeId; + + return temp; +} + +/* + * SendColumnMetadataToken - send the COLMETADATA token + * + * natts - number of attributes + * sendRowStat - true if we need to send an additional ROWSTAT column, false + * otherwise. + * NB: The ROWSTAT columns (row status indicator) are sent as hidden columns, + * at the end of each row with the column name ROWSTAT and data type INT4. This + * ROWSTAT column has one of the values - FETCH_SUCCEEDED or FETCH_MISSING. + * Because the TDS protocol provides no way to send the trailing status column + * without sending the previous columns, dummy data is sent for missing rows + * (nullable fields set to null, fixed length fields set to 0, blank, or the + * default for that column, as appropriate). + */ +void +SendColumnMetadataToken(int natts, bool sendRowStat) +{ + 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); + TdsPutInt8(TDS_TOKEN_COLMETADATA); + TdsPutInt16LE(sendRowStat ? natts + 1 : natts); + + initStringInfo(&tempBuf); + + for (attno = 0; attno < natts; 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; + * + * 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); + else + TdsPutInt32LE(0); + /* column meta */ + TdsPutbytes(&(col->metaEntry), col->metaLen); + + if (col->sendTableName) + { + 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 + */ + if (tdsVersion > TDS_VERSION_7_1_1) + FillTabNameWithNumParts(&tempBuf, numParts, col->relinfo); + else + FillTabNameWithoutNumParts(&tempBuf, numParts, col->relinfo); + TdsPutbytes(tempBuf.data, tempBuf.len); + } + else + { + /* 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 + */ + if (tdsVersion > TDS_VERSION_7_1_1) + TdsPutbytes(&numParts, sizeof(numParts)); + TdsPutInt16LE(0); + } + } + + /* + * 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) + * + * 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) + { + temp8 = 0; + TdsPutbytes(&temp8, sizeof(temp8)); + } + else + { + + /* column length and name */ + if (col->colName.len > 0) + temp8 = (uint8_t) pg_mbstrlen(col->colName.data); + else + temp8 = 0; + + resetStringInfo(&tempBuf); + TdsUTF8toUTF16StringInfo(&tempBuf, col->colName.data, + col->colName.len); + TdsPutbytes(&temp8, sizeof(temp8)); + TdsPutbytes(tempBuf.data, tempBuf.len); + } + } + + 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. + */ + 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; + */ + if (tdsVersion <= TDS_VERSION_7_1_1) + TdsPutInt16LE(0); + else + TdsPutInt32LE(0); + + TdsPutbytes(arr, sizeof(arr)); + } + + pfree(tempBuf.data); +} + +/* + * SendTabNameToken - send the TABNAME token + * + * It sends all the table names corresponding the columns included in the target + * list. For expression columns, we don't send any table name. + */ +void +SendTabNameToken(void) +{ + StringInfoData buf; + ListCell *lc; + uint32_t tdsVersion = GetClientTDSVersion(); + + if (relMetaDataInfoList == NIL) + return; + + initStringInfo(&buf); + + foreach(lc, relMetaDataInfoList) + { + 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. + */ + if (tdsVersion > TDS_VERSION_7_1) + FillTabNameWithNumParts(&buf, numParts, relMetaDataInfo); + else + FillTabNameWithoutNumParts(&buf, numParts, relMetaDataInfo); + } + + 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); + pfree(buf.data); + + TDSInstrumentation(INSTR_TDS_TOKEN_TABNAME); +} + +/* + * SendColInfoToken - send the COLINFO token + * + * It sends some additional info for a column: + * colNum - column number in the result set + * tableNum - number of the base table that the column was derived from. The value + * is 0 for expression column. + * status - EXPRESSION (the column was the result of an expression) + * KEY (the column is part of a key for the associated table and result set) + * HIDDEN (the column was not requested, but was added because it was part + * of a key for the associated table) + * DIFFERENT_NAME (the column name is different than the requested column + * name in the case of a column alias) + * colName - The base column name. This only occurs if DIFFERENT_NAME is set in Status. + */ +void +SendColInfoToken(int natts, bool sendRowStat) +{ + StringInfoData buf; + StringInfoData tempBuf; + int attno; + + 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; + + colNum = attno + 1; + + if (col->relOid == 0) + { + status |= COLUMN_STATUS_EXPRESSION; + tableNum = 0; + } + else + { + status = 0; + tableNum = col->relinfo->tableNum; + + resetStringInfo(&tempBuf); + + if (strcmp(col->baseColName, col->colName.data) != 0) + status |= COLUMN_STATUS_DIFFERENT_NAME; + + { + int tempatt; + + for (tempatt = 0; tempatt < col->relinfo->numkeyattrs; tempatt++) + if (col->attrNum == col->relinfo->keyattrs[tempatt]) + status |= COLUMN_STATUS_KEY; + } + } + + /* 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)); + + if (status & COLUMN_STATUS_DIFFERENT_NAME) + { + Assert(col->baseColName != NULL); + temp8 = (uint8_t) pg_mbstrlen(col->baseColName); + appendBinaryStringInfo(&buf, (const char *)&temp8, sizeof(uint8)); + TdsUTF8toUTF16StringInfo(&buf, col->baseColName, strlen(col->baseColName)); + } + } + + if (sendRowStat) + { + 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)); + } + + TdsPutInt16LE((uint16_t) buf.len); + TdsPutbytes(buf.data, buf.len); + + pfree(buf.data); +} + +/* + * PrepareRowDescription - prepare the information needed to construct COLMETADATA + * token, TABNAME token and COLINFO token. + * + * extendedInfo - If false, it doesn't collect the additional information needed + * to construct the TABNAME token and COLINFO token. + * fetchPkeys - If true and extendedInfo is true, it fetches the primary keys + * for a relation. (used for keyset and dynamic cursors) + */ +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; + + relMetaDataInfoList = NIL; + + TdsErrorContext->err_text = "Preparing to Send Back the Tds response"; + + 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. + */ + 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). + */ + 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(); + TargetEntry *tle = NULL; + coll_info_t cinfo = (pltsql_plugin_handler_ptr)->lookup_collation_table_callback(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"); + + /* + * Get the IO function info from our type cache + */ + finfo = TdsLookupTypeFunctionsByOid(atttypid, &atttypmod); + // atttypid = getBaseTypeAndTypmod(atttypid, &atttypmod); +#if 0 + { + /* Test a reverse lookup */ + 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); + if (!att->attbyval) + typelen = 80; + finfo2 = TdsLookupTypeFunctionsByTdsId(typeid, typelen); + elog(LOG, "found reverse finfo for type %d,%d: Oid=%d", + typeid, typelen, finfo2->ttmtypeid); + } +#endif + + /* + * Fill in column info that is common to all data types + */ + SetParamMetadataCommonInfo(col, finfo); + initStringInfo(&(col->colName)); + appendStringInfoString(&col->colName, NameStr(att->attname)); + + /* Do we have a non-resjunk tlist item? */ + while (tlist_item && + ((TargetEntry *) lfirst(tlist_item))->resjunk) + tlist_item = lnext(targetlist, tlist_item); + if (tlist_item) + { + tle = (TargetEntry *) lfirst(tlist_item); + + col->relOid = tle->resorigtbl; + col->attrNum = tle->resorigcol; + + tlist_item = lnext(targetlist, tlist_item); + } + else + { + /* No info available, so send zeroes */ + col->relOid = 0; + col->attrNum = 0; + } + + col->attNotNull = get_attnotnull(col->relOid, col->attrNum); + 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 + */ + case TDS_SEND_BIT: + if (col->attNotNull) + SetColMetadataForFixedType(col, VARIANT_TYPE_BIT, TDS_MAXLEN_BIT); + else + SetColMetadataForFixedType(col, TDS_TYPE_BIT, TDS_MAXLEN_BIT); + break; + case TDS_SEND_TINYINT: + if (col->attNotNull) + SetColMetadataForFixedType(col, VARIANT_TYPE_TINYINT, TDS_MAXLEN_TINYINT); + else + SetColMetadataForFixedType(col, TDS_TYPE_INTEGER, TDS_MAXLEN_TINYINT); + break; + case TDS_SEND_SMALLINT: + if (col->attNotNull) + SetColMetadataForFixedType(col, VARIANT_TYPE_SMALLINT, TDS_MAXLEN_SMALLINT); + else + SetColMetadataForFixedType(col, TDS_TYPE_INTEGER, TDS_MAXLEN_SMALLINT); + break; + case TDS_SEND_INTEGER: + if (col->attNotNull) + SetColMetadataForFixedType(col, VARIANT_TYPE_INT, TDS_MAXLEN_INT); + else + SetColMetadataForFixedType(col, TDS_TYPE_INTEGER, TDS_MAXLEN_INT); + break; + case TDS_SEND_BIGINT: + if (col->attNotNull) + SetColMetadataForFixedType(col, VARIANT_TYPE_BIGINT, TDS_MAXLEN_BIGINT); + else + SetColMetadataForFixedType(col, TDS_TYPE_INTEGER, TDS_MAXLEN_BIGINT); + break; + case TDS_SEND_FLOAT4: + if (col->attNotNull) + SetColMetadataForFixedType(col, VARIANT_TYPE_REAL, TDS_MAXLEN_FLOAT4); + else + SetColMetadataForFixedType(col, TDS_TYPE_FLOAT, TDS_MAXLEN_FLOAT4); + break; + case TDS_SEND_FLOAT8: + if (col->attNotNull) + SetColMetadataForFixedType(col, VARIANT_TYPE_FLOAT, TDS_MAXLEN_FLOAT8); + else + SetColMetadataForFixedType(col, TDS_TYPE_FLOAT, TDS_MAXLEN_FLOAT8); + break; + case TDS_SEND_CHAR: + SetColMetadataForCharTypeHelper(col, TDS_TYPE_CHAR, + att->attcollation, (atttypmod - 4)); + break; + case TDS_SEND_NCHAR: + SetColMetadataForCharTypeHelper(col, TDS_TYPE_NCHAR, + att->attcollation, (atttypmod-4) * 2); + break; + case TDS_SEND_VARCHAR: + SetColMetadataForCharTypeHelper(col, TDS_TYPE_VARCHAR, + att->attcollation, (atttypmod == -1) ? + atttypmod : (atttypmod - 4)); + break; + case TDS_SEND_NVARCHAR: + SetColMetadataForCharTypeHelper(col, TDS_TYPE_NVARCHAR, + att->attcollation, (atttypmod == -1) ? + atttypmod : (atttypmod - 4) * 2); + break; + case TDS_SEND_MONEY: + if (col->attNotNull) + SetColMetadataForFixedType(col, VARIANT_TYPE_MONEY, TDS_MAXLEN_MONEY); + else + SetColMetadataForFixedType(col, TDS_TYPE_MONEYN, TDS_MAXLEN_MONEY); + break; + case TDS_SEND_SMALLMONEY: + if (col->attNotNull) + SetColMetadataForFixedType(col, VARIANT_TYPE_SMALLMONEY, TDS_MAXLEN_SMALLMONEY); + else + SetColMetadataForFixedType(col, TDS_TYPE_MONEYN, TDS_MAXLEN_SMALLMONEY); + break; + case TDS_SEND_TEXT: + SetColMetadataForTextTypeHelper(col, TDS_TYPE_TEXT, + att->attcollation, (atttypmod - 4)); + sendTableName |= col->sendTableName; + break; + case TDS_SEND_NTEXT: + SetColMetadataForTextTypeHelper(col, TDS_TYPE_NTEXT, + att->attcollation, (atttypmod - 4) * 2); + sendTableName |= col->sendTableName; + 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'). + */ + SetColMetadataForCharTypeHelper(col, TDS_TYPE_NVARCHAR, serverCollationOid, 20); + else + SetColMetadataForDateType(col, TDS_TYPE_DATE); + break; + case TDS_SEND_DATETIME: + if (col->attNotNull) + SetColMetadataForFixedType(col, VARIANT_TYPE_DATETIME, TDS_MAXLEN_DATETIME); + else + SetColMetadataForFixedType(col, TDS_TYPE_DATETIMEN, TDS_MAXLEN_DATETIME); + break; + 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. + */ + 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. + */ + if (atttypmod >= VARHDRSZ) + { + scale = (atttypmod - VARHDRSZ) & 0xffff; + 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."))); + } + } + else + { + precision = tds_default_numeric_precision; + scale = tds_default_numeric_scale; + } + SetColMetadataForNumericType(col, TDS_TYPE_NUMERICN, 17, precision, scale); + } + break; + case TDS_SEND_SMALLDATETIME: + if (col->attNotNull) + SetColMetadataForFixedType(col, VARIANT_TYPE_SMALLDATETIME, TDS_MAXLEN_SMALLDATETIME); + else + SetColMetadataForFixedType(col, TDS_TYPE_DATETIMEN, TDS_MAXLEN_SMALLDATETIME); + break; + case TDS_SEND_IMAGE: + SetColMetadataForImageType(col, TDS_TYPE_IMAGE); + sendTableName |= col->sendTableName; + break; + case TDS_SEND_BINARY: + /* 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); + } + } + SetColMetadataForBinaryType(col, TDS_TYPE_VARBINARY, (atttypmod == -1) ? + atttypmod : atttypmod - VARHDRSZ); + break; + case TDS_SEND_UNIQUEIDENTIFIER: + SetColMetadataForFixedType(col, TDS_TYPE_UNIQUEIDENTIFIER, TDS_MAXLEN_UNIQUEIDENTIFIER); + 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. + */ + 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 (atttypmod == -1) + atttypmod = 6; + SetColMetadataForTimeType(col, TDS_TYPE_TIME, atttypmod); + } + 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. + */ + 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 (atttypmod == -1) + atttypmod = 6; + SetColMetadataForTimeType(col, TDS_TYPE_DATETIME2, atttypmod); + } + break; + case TDS_SEND_XML: + 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. + */ + SetColMetadataForTextTypeHelper(col, TDS_TYPE_NTEXT, + att->attcollation, (atttypmod - 4) * 2); + sendTableName |= col->sendTableName; + } + break; + case TDS_SEND_SQLVARIANT: + SetColMetadataForImageType(col, TDS_TYPE_SQLVARIANT); + 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. + */ + SetColMetadataForCharTypeHelper(col, TDS_TYPE_NVARCHAR, serverCollationOid, 64); + else + { + if (atttypmod == -1) + atttypmod = 6; + SetColMetadataForTimeType(col, TDS_TYPE_DATETIMEOFFSET, atttypmod); + } + break; + default: + /* + * TODO: Need to create a mapping table for user defined + * data types and handle it here. + */ + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("data type %d not supported yet", atttypid))); + } + } + + MemoryContextSwitchTo(oldContext); + + if (extendedInfo || sendTableName) + { + uint8 tableNum = 0; + + oldContext = MemoryContextSwitchTo(MessageContext); + relMetaDataInfoList = NULL; + + for (attno = 0; attno < natts; attno++) + { + TdsColumnMetaData *col = &colMetaData[attno]; + ListCell *lc; + bool found = false; + + if (col->relOid == 0) + { + col->baseColName = NULL; + col->relinfo = NULL; + continue; + } + + /* fetch the actual column name */ + col->baseColName = get_attname(col->relOid, col->attrNum, false); + + /* look for a relation entry match */ + foreach(lc, relMetaDataInfoList) + { + TdsRelationMetaDataInfo relMetaDataInfo = (TdsRelationMetaDataInfo) lfirst(lc); + Oid relOid = relMetaDataInfo->relOid; + + if (relOid == col->relOid) + { + found = true; + col->relinfo = relMetaDataInfo; + break; + } + } + + /* if not found, add one */ + if (!found) + { + Relation rel; + TdsRelationMetaDataInfo relMetaDataInfo; + + relMetaDataInfo = (TdsRelationMetaDataInfo) palloc(sizeof(TdsRelationMetaDataInfoData)); + tableNum++; + + relMetaDataInfo->relOid = col->relOid; + relMetaDataInfo->tableNum = tableNum; + + rel = relation_open(col->relOid, AccessShareLock); + + /* fetch the primary key attributes if needed */ + if (fetchPkeys) + relMetaDataInfo->keyattrs = getPkeyAttnames(rel, &relMetaDataInfo->numkeyattrs); + else + { + relMetaDataInfo->keyattrs = NULL; + relMetaDataInfo->numkeyattrs = 0; + } + + /* fetch the relation name, schema name */ + relMetaDataInfo->partName[0] = RelationGetRelationName(rel); + relMetaDataInfo->partName[1] = get_namespace_name(RelationGetNamespace(rel)); + + relation_close(rel, AccessShareLock); + + relMetaDataInfoList = lappend(relMetaDataInfoList, relMetaDataInfo); + col->relinfo = relMetaDataInfo; + } + } + + MemoryContextSwitchTo(oldContext); + } +} + +/* + * SendReturnValueTokenInternal + * + * status - stored procedure (0x01) or UDF (0x02) + * forceCoercion - true if it needs datatype coercion before sending the data + */ +void +SendReturnValueTokenInternal(ParameterToken token, uint8 status, + FmgrInfo *finfo, Datum datum, bool isNull, + bool forceCoercion) +{ + 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); + 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; + * + * 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? */ + else + temp16 = token->paramOrdinal; + TdsPutbytes(&temp16, sizeof(temp16)); + + /* param name len and param name ((here column name is in UTF-8 format) */ + name = &(token->paramMeta.colName); + if (name->len > 0) + { + StringInfoData tempName; + + initStringInfo(&tempName); + TdsUTF8toUTF16StringInfo(&tempName, name->data, name->len); + + temp8 = (uint8_t) pg_mbstrlen(name->data); + TdsPutbytes(&temp8, sizeof(temp8)); + TdsPutbytes(tempName.data, tempName.len); + + pfree(tempName.data); + } + else + { + temp8 = name->len; + TdsPutbytes(&temp8, sizeof(temp8)); + } + + /* 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; + * + * 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); + else + TdsPutInt32LE(0); + + /* meta entries */ + TdsPutbytes(&(token->paramMeta.metaEntry), token->paramMeta.metaLen); + + if (isNull) + { + switch (token->paramMeta.metaEntry.type1.tdsTypeId) + { + 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). + */ + TdsPutUInt32LE(0xFFFFFFFF); + break; + case TDS_TYPE_CHAR: + case TDS_TYPE_NCHAR: + case TDS_TYPE_VARCHAR: + case TDS_TYPE_NVARCHAR: + 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). + */ + if (token->maxLen == 0xFFFF) + TdsPutUInt64LE(PLP_NULL); + else + 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) + */ + temp16 = 0; + TdsPutbytes(&temp16, token->paramMeta.sizeLen); + break; + } + + /* we're done */ + return; + } + else if (forceCoercion) + { + 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. + */ + + /* 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 (pathtype == COERCION_PATH_FUNC) + result = GetTypModForToken(token); + + /* If we found a valid attypmod, perform the casting. */ + if (result != -1) + { + datum = OidFunctionCall3(castFuncOid, datum, + Int32GetDatum(result), + BoolGetDatum(true)); + } + } + + /* should in a transaction, because we'll do a catalog lookup */ + if (!finfo && IsTransactionState()) + { + Oid typoutputfunc; + bool typIsVarlena; + Assert(token->paramMeta.pgTypeOid != InvalidOid); + getTypeOutputInfo(token->paramMeta.pgTypeOid, &typoutputfunc, &typIsVarlena); + fmgr_info(typoutputfunc, &temp); + finfo = &temp; + } + + /* send the data */ + (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; + + /* + * Forcing coercion needs catalog access. Hence, we should be in a + * transaction. + */ + 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. + */ + n = 0; + switch (token->paramMeta.metaEntry.type1.tdsTypeId) + { + case TDS_TYPE_CHAR: + case TDS_TYPE_VARCHAR: + /* We don't have to perform any length coercion for PLP data */ + if (token->maxLen == 0xFFFF) + break; + + /* it only consists of the maxlen */ + datums = (Datum *) palloc(1 * sizeof(Datum)); + + cstr = psprintf("%ld", (long) token->paramMeta.metaEntry.type2.maxSize); + datums[n++] = CStringGetDatum(cstr); + break; + case TDS_TYPE_NCHAR: + case TDS_TYPE_NVARCHAR: + /* We don't have to perform any length coercion for PLP data */ + if (token->maxLen == 0xFFFF) + break; + + /* it only consists of the maxlen */ + datums = (Datum *) palloc(1 * sizeof(Datum)); + + cstr = psprintf("%ld", (long) token->paramMeta.metaEntry.type2.maxSize / 2); + datums[n++] = CStringGetDatum(cstr); + break; + case TDS_TYPE_DECIMALN: + case TDS_TYPE_NUMERICN: + /* it consists of scale and precision */ + datums = (Datum *) palloc(2 * sizeof(Datum)); + + cstr = psprintf("%ld", (long) token->paramMeta.metaEntry.type5.precision); + datums[n++] = CStringGetDatum(cstr); + cstr = psprintf("%ld", (long) token->paramMeta.metaEntry.type5.scale); + datums[n++] = CStringGetDatum(cstr); + break; + case TDS_TYPE_TIME: + case TDS_TYPE_DATETIME2: + /* it only consists of scale */ + datums = (Datum *) palloc(1 * sizeof(Datum)); + + cstr = psprintf("%ld", (long) token->paramMeta.metaEntry.type6.scale); + datums[n++] = CStringGetDatum(cstr); + break; + case TDS_TYPE_BINARY: + case TDS_TYPE_VARBINARY: + /* We don't have to perform any length coercion for PLP data */ + if (token->maxLen == 0xFFFF) + break; + + /* it only consists of the maxlen */ + datums = (Datum *) palloc(1 * sizeof(Datum)); + cstr = psprintf("%ld", (long) token->paramMeta.metaEntry.type7.maxSize); + datums[n++] = CStringGetDatum(cstr); + break; + case TDS_TYPE_IMAGE: + ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION), + errmsg("Data type 0x22(Image) is a deprecated LOB.\ + Deprecated types are not supported as output parameters."))); + break; + default: + break; + } + + /* If we've prepared the argument, proceed. */ + if (datums) + { + /* hardwired knowledge about cstring's representation details here */ + arrtypmod = construct_array(datums, n, CSTRINGOID, + -2, false, 'c'); + + pgtypemodin = get_typmodin(token->paramMeta.pgTypeOid); + typmod = DatumGetInt32(OidFunctionCall1(pgtypemodin, + PointerGetDatum(arrtypmod))); + + /* be tidy */ + pfree(datums); + pfree(arrtypmod); + } + + return typmod; +} + +void +TdsSendEnvChange(int envid, const char *new_val, const char *old_val) +{ + StringInfoData newUtf16; + StringInfoData oldUtf16; + int16_t totalLen; + uint8 temp8; + + initStringInfo(&newUtf16); + initStringInfo(&oldUtf16); + + SendPendingDone(true); + + if (new_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; + + TDS_DEBUG(TDS_DEBUG2, "TdsSendEnvChange: token=0x%02x", TDS_TOKEN_ENVCHANGE); + temp8 = TDS_TOKEN_ENVCHANGE; + TdsPutbytes(&temp8, sizeof(temp8)); + + TdsPutbytes(&totalLen, sizeof(totalLen)); + TdsPutbytes(&envid, sizeof(temp8)); + + if (new_val) + { + temp8 = strlen(new_val); + TdsPutbytes(&temp8, sizeof(temp8)); + TdsPutbytes(newUtf16.data, newUtf16.len); + } + else + { + temp8 = 0; + TdsPutbytes(&temp8, sizeof(temp8)); + } + + if (old_val) + { + temp8 = strlen(old_val); + TdsPutbytes(&temp8, sizeof(temp8)); + TdsPutbytes(oldUtf16.data, oldUtf16.len); + } + else + { + temp8 = 0; + TdsPutbytes(&temp8, sizeof(temp8)); + } + + pfree(newUtf16.data); + pfree(oldUtf16.data); +} + +void +TdsSendEnvChangeBinary(int envid, void *new, int newNbytes, + void *old, int oldNbytes) +{ + int16_t totalLen; + uint8 temp8; + + SendPendingDone(true); + + totalLen = 1 /* envid */ + + 1 /* new len */ + + newNbytes + + 1 /* old len */ + + oldNbytes; + + TDS_DEBUG(TDS_DEBUG2, "TdsSendEnvChangeBinary: token=0x%02x", TDS_TOKEN_ENVCHANGE); + temp8 = TDS_TOKEN_ENVCHANGE; + TdsPutbytes(&temp8, sizeof(temp8)); + + TdsPutbytes(&totalLen, sizeof(totalLen)); + temp8 = envid; + TdsPutbytes(&envid, sizeof(temp8)); + + temp8 = newNbytes; + TdsPutbytes(&temp8, sizeof(temp8)); + TdsPutbytes(new, newNbytes); + + temp8 = oldNbytes; + TdsPutbytes(&temp8, sizeof(temp8)); + TdsPutbytes(old, oldNbytes); +} + +void +TdsSendInfo(int number, int state, int class, + char *message, int lineNo) +{ + TdsSendInfoOrError(TDS_TOKEN_INFO, number, state, class, + 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) +{ + /* + * If not already in RESPONSE mode, switch the TDS protocol to RESPONSE + * mode. + */ + TdsSetMessageType(TDS_RESPONSE); + + TdsSendInfoOrError(TDS_TOKEN_ERROR, number, state, class, + message, + "BABELFISH", /* TODO: where to get this? */ + "", /* TODO: where to get this? */ + lineNo); + + markErrorFlag = true; +} + +void +TdsSendInfoOrError(int token, int number, int state, int class, + 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); + int16_t messageLen_16 = pg_mbstrlen(message); + int32_t number_32 = (int32_t)number; + int32_t lineNo_32 = (int32_t)lineNo; + int16_t totalLen; + uint8 temp8; + 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. + */ + if (tdsVersion <= TDS_VERSION_7_1_1) + lineNoLen = sizeof(int16_t); + else + lineNoLen = sizeof(int32_t); + + initStringInfo(&messageUtf16); + initStringInfo(&serverNameUtf16); + initStringInfo(&procNameUtf16); + + TdsUTF8toUTF16StringInfo(&messageUtf16, message, messageLen); + TdsUTF8toUTF16StringInfo(&serverNameUtf16, serverName, serverNameLen); + TdsUTF8toUTF16StringInfo(&procNameUtf16, procName, procNameLen); + + 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); + temp8 = token; + TdsPutbytes(&temp8, sizeof(temp8)); + TdsPutbytes(&totalLen, sizeof(totalLen)); + TdsPutbytes(&number_32, sizeof(number_32)); + + temp8 = state; + TdsPutbytes(&temp8, sizeof(temp8)); + + temp8 = class; + TdsPutbytes(&temp8, sizeof(temp8)); + + TdsPutbytes(&messageLen_16, sizeof(messageLen_16)); + TdsPutbytes(messageUtf16.data, messageUtf16.len); + + temp8 = serverNameLen; + TdsPutbytes(&temp8, sizeof(temp8)); + TdsPutbytes(serverNameUtf16.data, serverNameUtf16.len); + + temp8 = procNameLen; + TdsPutbytes(&temp8, sizeof(temp8)); + TdsPutbytes(procNameUtf16.data, procNameUtf16.len); + + 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 + lineNo_16 = (int16_t) lineNo; + TdsPutbytes(&lineNo_16, lineNoLen); + } + else + TdsPutbytes(&lineNo_32, lineNoLen); + + pfree(messageUtf16.data); + pfree(serverNameUtf16.data); + pfree(procNameUtf16.data); +} + +void +TdsSendRowDescription(TupleDesc typeinfo, + List *targetlist, int16 *formats) +{ + TDSRequest request = TdsRequestCtrl->request; + + /* If we reach here, typeinfo should not be null. */ + Assert(typeinfo != NULL); + + /* Prepare the column metadata first */ + PrepareRowDescription(typeinfo, targetlist, formats, false, false); + + /* + * 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. + */ + if (request->reqType == TDS_REQUEST_SP_NUMBER) + { + 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. */ + 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); + TdsPutInt8(TDS_TOKEN_COLMETADATA); + TdsPutInt8(0xFF); + TdsPutInt8(0xFF); + return; + } + } + + SendColumnMetadataToken(typeinfo->natts, false); +} + +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; + + TdsErrorContext->err_text = "Writing the Tds response to the socket"; + if (request->reqType == TDS_REQUEST_SP_NUMBER) + { + TDSRequestSP req = (TDSRequestSP) request; + + /* ROWSTAT token is sent for sp_cursorfetch */ + if (req->spType == SP_CURSORFETCH) + sendRowStat = true; + } + + /* Set or update my derived attribute info, if needed */ + if (myState->attrinfo != typeinfo || myState->nattrs != natts) + PrintTupPrepareInfo(myState, typeinfo, natts); + + /* Make sure the tuple is fully deconstructed */ + slot_getallattrs(slot); + + /* Switch into per-row context so we can recover memory below */ + oldContext = MemoryContextSwitchTo(myState->tmpcontext); + + 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 + * 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. + */ + nullMapSize = (natts + 7) / 8; + nullMap = palloc0(nullMapSize); + MemSet(nullMap, 0, nullMapSize * sizeof(int8_t)); + for (attno = 0; attno < natts; attno++) + { + TdsColumnMetaData *col = &colMetaData[attno]; + + if (col->metaEntry.type1.flags & TDS_COLMETA_NULLABLE) + { + if (slot->tts_isnull[attno]) + { + nullMap[attno / 8] |= (0x01 << (attno & 0x07)); + switch (col->metaEntry.type1.tdsTypeId) + { + 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) + */ + simpleRowSize += 8; + else + /* + * 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) */ + simpleRowSize += 8; + else + /* 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 */ + simpleRowSize += 2; + break; + case TDS_TYPE_SQLVARIANT: + /* 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 */ + simpleRowSize += 1; + break; + } + } + } + } + + if (nullMapSize < simpleRowSize) + { + rowToken = TDS_TOKEN_NBCROW; + } + else + { + rowToken = TDS_TOKEN_ROW; + } + } + else + /* 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); + TdsPutbytes(&rowToken, sizeof(rowToken)); + + if (rowToken == TDS_TOKEN_NBCROW) + { + TdsPutbytes(nullMap, nullMapSize); + TDSInstrumentation(INSTR_TDS_TOKEN_NBCROW); + } + + if (nullMap != NULL) + pfree(nullMap); + + /* And finally send the actual column values */ + for (attno = 0; attno < natts; 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 + */ + if (rowToken == TDS_TOKEN_ROW) + { + switch (col->metaEntry.type1.tdsTypeId) + { + 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) + */ + TdsPutUInt64LE(0xffffffffffffffff); + else + /* + * 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) */ + TdsPutUInt64LE(0xffffffffffffffff); + else + /* 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)*/ + TdsPutInt16LE(0xffff); + break; + case TDS_TYPE_SQLVARIANT: + /* 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 */ + TdsPutUInt8(0); + break; + } + } + continue; + } + + thisState = myState->myinfo + attno; + attr = slot->tts_values[attno]; + + /* + * Here we catch undefined bytes in datums that are returned to the + * client without hitting disk; see comments at the related check in + * PageAddItem(). This test is most useful for uncompressed, + * non-external datums, but we're quite likely to see such here when + * testing new C functions. + */ + if (thisState->typisvarlena) + VALGRIND_CHECK_MEM_IS_DEFINED(DatumGetPointer(attr), + VARSIZE_ANY(attr)); + + /* Call the type specific output function */ + (col->sendFunc)(&thisState->finfo, attr, (void *)col); + } + + /* + * For cursor fetch operation, we need to send the row status information. + * It can be either SP_CURSOR_FETCH_SUCCEEDED or SP_CURSOR_FETCH_MISSING. + * 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. + */ + if (sendRowStat) + (void) TdsPutInt32LE(SP_CURSOR_FETCH_SUCCEEDED); + + /* Return to caller's context, and flush row's temporary memory */ + MemoryContextSwitchTo(oldContext); + MemoryContextReset(myState->tmpcontext); + + return true; +} + +void +TdsPrintTupShutdown(void) +{ + pfree(colMetaData); + colMetaData = NULL; +} + +/* -------------------------------- + * TdsSendReturnStatus - send a return status token + * -------------------------------- + */ +void +TdsSendReturnStatus(int status) +{ + 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); + temp8 = TDS_TOKEN_RETURNSTATUS; + TdsPutbytes(&temp8, sizeof(temp8)); + + tmp = htoLE32(status); + TdsPutbytes(&status, sizeof(tmp)); +} + +/* -------------------------------- + * TdsSendDone - Queue a DONE message + * + * Since we don't know for sure if this is going to be the final DONE + * message we only queue it at this point. The next time TdsPutbytes() + * or TdsFlush is called we finalize the flags and send add it to + * the output stream. + * -------------------------------- + */ +void +TdsSendDone(int token, int status, int curcmd, uint64_t nprocessed) +{ + bool gucNocount = false; + + + TdsErrorContext->err_text = "Writing Done Token"; + + if (GetConfigOption("babelfishpg_tsql.nocount", true, false) && + strcmp(GetConfigOption("babelfishpg_tsql.nocount", true, false), "on") == 0) + gucNocount = true; + + if (TdsRequestCtrl) + TdsRequestCtrl->isEmptyResponse = false; + + 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. + */ + SendPendingDone(true); + + /* Remember the DONE information as pending */ + TdsHavePendingDone = true; + TdsPendingDoneNocount = gucNocount; + TdsPendingDoneToken = token; + TdsPendingDoneStatus = status; + TdsPendingDoneCurCmd = curcmd; + TdsPendingDoneRowCnt = nprocessed; + + if (markErrorFlag) + TdsPendingDoneStatus |= TDS_DONE_ERROR; + + markErrorFlag = false; +} + +int +TdsFlush(void) +{ + SendPendingDone(false); + + /* reset flags */ + markErrorFlag = false; + + /* + * 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); + + /* reset error data */ + if (tds_estate) + ResetTdsEstateErrorData(); + + return TdsSocketFlush(); +} + +void +TDSStatementBeginCallback(PLtsql_execstate *estate, PLtsql_stmt *stmt) +{ + if(tds_estate == NULL) + return; + + TDS_DEBUG(TDS_DEBUG3, "begin %d", tds_estate->current_stack); + tds_estate->current_stack++; + + /* shouldn't have any un-handled error while begining the next statement */ + Assert(tds_estate->error_stack_offset == 0); + + if (stmt == NULL) + return; + + /* + * 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. + */ +} + +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; + + tds_estate->current_stack--; + TDS_DEBUG(TDS_DEBUG3, "end %d", tds_estate->current_stack); + toplevel = (tds_estate->current_stack == 0); + + + /* + * 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; + + /* + * Return if we are inside a function. Continue if it's a trigger. + */ + if (estate && estate->func && estate->func->fn_oid != InvalidOid && + estate->func->fn_prokind == PROKIND_FUNCTION && estate->func->fn_is_trigger == PLTSQL_NOT_TRIGGER) + return; + + if (stmt == NULL) + return; + + /* TODO: handle all the cases */ + switch(stmt->cmd_type) + { + case PLTSQL_STMT_GOTO: + case PLTSQL_STMT_RETURN: + /* Used in inline table valued functions */ + case PLTSQL_STMT_RETURN_QUERY: + /* Used in multi-statement table valued functions */ + case PLTSQL_STMT_DECL_TABLE: + case PLTSQL_STMT_RETURN_TABLE: + { + /* Done token is not expected for these commands */ + skip_done = true; + } + break; + case PLTSQL_STMT_ASSIGN: + case PLTSQL_STMT_PUSH_RESULT: + { + command_type = TDS_CMD_SELECT; + row_count_valid = true; + } + break; + case PLTSQL_STMT_EXECSQL: + { + ListCell *l; + PLtsql_expr *expr = ((PLtsql_stmt_execsql *) stmt)->sqlstmt; + + /* + * XXX: Once an error occurs, the expr and expr->plan may be + * freed. In that case, we've to save the command type in + * PLtsql_stmt_execsql before the execution. + */ + if (expr && expr->plan) + { + foreach(l, SPI_plan_get_plan_sources(expr->plan)) + { + CachedPlanSource *plansource = (CachedPlanSource *) lfirst(l); + + if (plansource->commandTag) + { + 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_valid = !estate->insert_exec && + !(markErrorFlag && + ((PLtsql_stmt_execsql *)stmt)->insert_exec); + } + else if (plansource->commandTag == CMDTAG_UPDATE) + { + command_type = TDS_CMD_UPDATE; + row_count_valid = !estate->insert_exec; + } + else if (plansource->commandTag == CMDTAG_DELETE) + { + command_type = TDS_CMD_DELETE; + row_count_valid = !estate->insert_exec; + } + /* + * [BABEL-2090] SELECT statement should show + * 'rows affected' count + */ + else if (plansource->commandTag == CMDTAG_SELECT) + { + command_type = TDS_CMD_SELECT; + row_count_valid = !estate->insert_exec; + } + } + } + } + + /* + * Done token is not expected for INSERT/UPDATE/DELETE + * statements on table variables in user-defined functions. + */ + if (((PLtsql_stmt_execsql *) stmt)->mod_stmt_tablevar && + estate->func->fn_prokind == PROKIND_FUNCTION && + estate->func->fn_is_trigger == PLTSQL_NOT_TRIGGER && + strcmp(estate->func->fn_signature, "inline_code_block") != 0) + skip_done = true; + } + break; + case PLTSQL_STMT_EXEC: + case PLTSQL_STMT_EXEC_BATCH: + case PLTSQL_STMT_EXEC_SP: + { + is_proc = true; + command_type = TDS_CMD_EXECUTE; + } + break; + default: + break; + } + + /* + * 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. + */ + if (toplevel && is_proc) + { + TDSRequest request = TdsRequestCtrl->request; + if (request->reqType == TDS_REQUEST_SP_NUMBER) + { + TDSRequestSP req = (TDSRequestSP) request; + + if (req->spType == SP_CUSTOMTYPE) + return; + } + } + + /* + * 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) + { + if (stmt->cmd_type == PLTSQL_STMT_EXEC) + { + /* + * If we're returning from a TOP-level procedure, send the return + * status token. It's possible that we've executed a scalar UDF + * with EXEC keyword. In that case, we don't have to send the + * return status token. + */ + if (!((PLtsql_stmt_exec *) stmt)->is_scalar_func) + { + Assert(pltsql_plugin_handler_ptr->pltsql_read_proc_return_status != NULL); + TdsSendReturnStatus(*(pltsql_plugin_handler_ptr->pltsql_read_proc_return_status)); + } + } + else + { + /* + * For EXEC batch, SP cursors and SP executeSQL, we just have to + * return 0 for a successful execution. Since, babelfishpg_tsql + * extension doesn't have return statement implementation for + * these cases, we've tosend it from here. + * + * TODO: Add this support in babelfishpg_tsql extension instead. + * In that case, we can remove this check. + */ + TdsSendReturnStatus(0); + } + } + + /* + * If we shouldn't send a done token for the current command, we can return + * from here. + */ + if (skip_done) + return; + + /* + * If count is valid for this command, set the count and the corresponding + * flag. + */ + if (row_count_valid) + { + nprocessed = (error ? 0 : estate->eval_processed); + flags |= TDS_DONE_COUNT; + } + + if (toplevel && is_proc) + token_type = TDS_TOKEN_DONEPROC; + else if (toplevel) + token_type = TDS_TOKEN_DONE; + else + token_type = TDS_TOKEN_DONEINPROC; + + if (toplevel) + flags |= TDS_DONE_FINAL; + else + flags |= TDS_DONE_MORE; + + TdsSendDone(token_type, flags, command_type, nprocessed); +} + +void +TDSStatementEndCallback(PLtsql_execstate *estate, PLtsql_stmt *stmt) +{ + if(tds_estate == NULL) + return; + + StatementEnd_Internal(estate, stmt, false); +} + +void +TDSStatementExceptionCallback(PLtsql_execstate *estate, PLtsql_stmt *stmt, bool terminate_batch) +{ + if(tds_estate == NULL) + return; + + TDS_DEBUG(TDS_DEBUG3, "exception %d", tds_estate->current_stack); + + SetTdsEstateErrorData(); + + /* + * 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. + */ + if (terminate_batch) + { + if (tds_estate->error_stack_offset == 0) + { + /* TODO: save the command type */ + } + + tds_estate->current_stack--; + tds_estate->error_stack_offset++; + + return; + } + + StatementEnd_Internal(estate, stmt, true); + + /* + * 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. + */ +} + +/* + * SendColumnMetadata - Api to Send the Column Metatadata, + * used in sp_prepare and called from babelfishpg_tsql extension. + */ +void +SendColumnMetadata(TupleDesc typeinfo, List *targetlist, int16 *formats) +{ + TdsSendRowDescription(typeinfo, targetlist, formats); + TdsPrintTupShutdown(); +} + +/* + * Record error data in tds_estate + */ +static void +SetTdsEstateErrorData(void) +{ + int number, severity, state; + + if (GetTdsEstateErrorData(&number, &severity, &state)) + { + tds_estate->cur_error_number = number; + tds_estate->cur_error_severity = severity; + tds_estate->cur_error_state = state; + } +} + +/* + * Reset error data in tds_estate + */ +static void +ResetTdsEstateErrorData(void) +{ + tds_estate->cur_error_number = -1; + tds_estate->cur_error_severity = -1; + tds_estate->cur_error_state = -1; +} + +/* + * Read error data in tds_estate + */ +bool +GetTdsEstateErrorData(int *number, int *severity, int *state) +{ + if (tds_estate != NULL && + tds_estate->cur_error_number != -1 && + tds_estate->cur_error_severity != -1 && + tds_estate->cur_error_state != -1) + { + if (number) + *number = tds_estate->cur_error_number; + if (severity) + *severity = tds_estate->cur_error_severity; + if (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 + */ + else + return pltsql_plugin_handler_ptr->pltsql_get_errdata(number, severity, state); +} + +/* + * get_attnotnull + * Given the relation id and the attribute number, + * return the "attnotnull" field from the attribute relation. + */ +static bool +get_attnotnull(Oid relid, AttrNumber attnum) +{ + HeapTuple tp; + Form_pg_attribute att_tup; + + tp = SearchSysCache2(ATTNUM, + ObjectIdGetDatum(relid), + Int16GetDatum(attnum)); + + if (HeapTupleIsValid(tp)) + { + bool result; + + att_tup = (Form_pg_attribute) GETSTRUCT(tp); + result = att_tup->attnotnull; + ReleaseSysCache(tp); + + return result; + } + /* Assume att is nullable if no valid heap tuple is found */ + return false; +} \ No newline at end of file diff --git a/contrib/babelfishpg_tds/src/backend/tds/tdsrpc.c b/contrib/babelfishpg_tds/src/backend/tds/tdsrpc.c new file mode 100644 index 00000000000..fe85a1a410a --- /dev/null +++ b/contrib/babelfishpg_tds/src/backend/tds/tdsrpc.c @@ -0,0 +1,3905 @@ +#include "postgres.h" + +#include "access/printtup.h" +#include "access/xact.h" /* for IsTransactionOrTransactionBlock() */ +#include "commands/prepare.h" +#include "catalog/pg_proc.h" +#include "catalog/pg_type.h" +#include "executor/spi.h" +#include "libpq/pqformat.h" +#include "lib/stringinfo.h" +#include "miscadmin.h" +#include "parser/parser.h" +#include "parser/scansup.h" +#include "pgstat.h" +#include "tcop/pquery.h" +#include "tcop/tcopprot.h" +#include "utils/builtins.h" +#include "utils/guc.h" +#include "utils/lsyscache.h" +#include "utils/snapmgr.h" + +#include "src/include/tds_debug.h" +#include "src/include/tds_int.h" +#include "src/include/tds_protocol.h" +#include "src/include/tds_response.h" +#include "src/include/tds_instr.h" +#include "src/include/faultinjection.h" + +#define SP_FLAGS_BYREFVALUE 0x01 +#define SP_FLAGS_DEFAULTVALUE 0x02 +#define SP_FLAGS_ENCRYPTED 0x08 + +/* + * sign, 10 digits, '\0' + * + * This is important for converting integer to string. Else, we've to dynamically + * allocate memory just for the conversion. + */ +#define INT32_STRLEN 12 + +/* For checking the invalid length parameters */ +#define CheckForInvalidLength(temp) \ +do \ +{ \ + if (temp->len > temp->maxLen) \ + { \ + 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.", \ + temp->paramOrdinal + 1, temp->paramMeta.colName.data, temp->type))); \ + } \ +} while(0) + +/* Check if retStatus Not OK */ +#define CheckPLPStatusNotOK(temp, retStatus) \ +do \ +{ \ + if (retStatus != STATUS_OK) \ + { \ + 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 chunking format is incorrect for a large object parameter of type 0x%02X.", \ + temp->paramOrdinal + 1, temp->paramMeta.colName.data, temp->type))); \ + } \ +} while(0) + +/* For identifying the Batch Separator. */ +#define GetRpcBatchSeparator(tdsVersion) ((tdsVersion > TDS_VERSION_7_1_1) ? 0xFF : 0x80) + +/* Different cursor options */ +#define SP_CURSOR_SCROLLOPT_KEYSET 0x0001 +#define SP_CURSOR_SCROLLOPT_DYNAMIC 0x0002 +#define SP_CURSOR_SCROLLOPT_FORWARD_ONLY 0x0004 +#define SP_CURSOR_SCROLLOPT_STATIC 0x0008 +#define SP_CURSOR_SCROLLOPT_FAST_FORWARD 0x10 +#define SP_CURSOR_SCROLLOPT_PARAMETERIZED_STMT 0x1000 +#define SP_CURSOR_SCROLLOPT_AUTO_FETCH 0x2000 +#define SP_CURSOR_SCROLLOPT_AUTO_CLOSE 0x4000 +#define SP_CURSOR_SCROLLOPT_CHECK_ACCEPTED_TYPES 0x8000 +#define SP_CURSOR_SCROLLOPT_KEYSET_ACCEPTABLE 0x10000 +#define SP_CURSOR_SCROLLOPT_DYNAMIC_ACCEPTABLE 0x20000 +#define SP_CURSOR_SCROLLOPT_FORWARD_ONLY_ACCEPTABLE 0x40000 +#define SP_CURSOR_SCROLLOPT_STATIC_ACCEPTABLE 0x80000 +#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_ALLOW_DIRECT 0x2000 +#define SP_CURSOR_CCOPT_UPDT_IN_PLACE 0x4000 +#define SP_CURSOR_CCOPT_CHECK_ACCEPTED_OPTS 0x8000 +#define SP_CURSOR_CCOPT_READ_ONLY_ACCEPTABLE 0x10000 +#define SP_CURSOR_CCOPT_SCROLL_LOCKS_ACCEPTABLE 0x20000 +#define SP_CURSOR_CCOPT_OPTIMISTIC_ACCEPTABLE 0x40000 +#define SP_CURSOR_CCOPT_OPTIMISITC_ACCEPTABLE 0x80000 + +/* different fetch options in sp_cursorfetch */ +#define SP_CURSOR_FETCH_FIRST 0x0001 +#define SP_CURSOR_FETCH_NEXT 0x0002 +#define SP_CURSOR_FETCH_PREV 0x0004 +#define SP_CURSOR_FETCH_LAST 0x0008 +#define SP_CURSOR_FETCH_ABSOLUTE 0x10 +#define SP_CURSOR_FETCH_RELATIVE 0x20 +#define SP_CURSOR_FETCH_REFRESH 0x80 +#define SP_CURSOR_FETCH_INFO 0x100 +#define SP_CURSOR_FETCH_PREV_NOADJUST 0x200 +#define SP_CURSOR_FETCH_SKIP_UPDT_CNCY 0x400 + +/* To get the datatype from the parameter */ +#define FetchDataTypeNameFromParameter(param) (param->paramMeta.metaEntry.type1.tdsTypeId) + +/* different print option in sp_cursor */ +#define PRINT_CURSOR_HANDLE 0x0001 +#define PRINT_PREPARED_CURSOR_HANDLE 0x0002 +#define PRINT_BOTH_CURSOR_HANDLE 0x0004 + +/* Local functions */ +static void GetSPHandleParameter(TDSRequestSP request); +static void GetSPCursorPreparedHandleParameter(TDSRequestSP request); +static void GetSPCursorHandleParameter(TDSRequestSP request); +static inline void FillStoredProcedureCallFromParameterToken(TDSRequestSP req, + StringInfo inBuf); +static inline void FillQueryFromParameterToken(TDSRequestSP req, + 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 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 void SPExecuteSQL(TDSRequestSP req); +static void SPPrepare(TDSRequestSP req); +static void SPExecute(TDSRequestSP req); +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* +CreateArgs(int nargs) +{ + InlineCodeBlockArgs *args; + + args = (InlineCodeBlockArgs *) palloc0(sizeof(InlineCodeBlockArgs)); + args->numargs = nargs; + + args->argtypes = (Oid *) palloc(sizeof(Oid) * args->numargs); + args->argtypmods = (int32 *) palloc(sizeof(int32) * args->numargs); + args->argnames = (char **) palloc(sizeof(char *) * args->numargs); + args->argmodes = (char *) palloc(sizeof(char) * args->numargs); + + return args; +} + +/* + * DeclareVariables - Declare TSQL variables by calling pltsql API directly + * + * We prepare the InlineCodeBlockArgs and the same as the second argument + * of fcinfo. + * If fcinfo is NULL, then don't call the pltsql API - just get the args and set + * up TVP lookup. + */ +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; + + args = (InlineCodeBlockArgs *) palloc0(sizeof(InlineCodeBlockArgs)); + args->numargs = req->nTotalParams; + args->options = options; + + if (fcinfo) + { + /* now add the same as second argument */ + (*fcinfo)->args[1].value = PointerGetDatum(args); + (*fcinfo)->args[1].isnull = false; + (*fcinfo)->nargs++; + } + + /* set variables if there is any */ + if (req->nTotalParams <= 0) + return args; + + args->argtypes = (Oid *) palloc(sizeof(Oid) * args->numargs); + 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. + */ + if (req->dataParameter->paramMeta.colName.len == 0) + { + resolveParamNames = true; + if (req->metaDataParameterValue->len) + { + tmp = pnstrdup(req->metaDataParameterValue->data, + 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: + * + * @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. + */ + fToken = strtok (tmp, " "); + if (strcmp(fToken, "@P0") == 0) + i = 0; + else if (strcmp(fToken, "@P1") == 0) + i = 1; + else + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("unexpected parameter definition %s", fToken))); + + pfree(tmp); + } + else + i = 0; + } + + /* + * 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; + Datum pval; + bool isNull; + TdsIoFunctionInfo tempFuncInfo; + + name = &(token->paramMeta.colName); + + /* + * 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 + */ + if (resolveParamNames && (name->len)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("not all Parameters have names"))); + else if(resolveParamNames) + { + char buf[10]; + + snprintf(buf, sizeof(buf), "@p%d", i); + paramName = pnstrdup(buf, strlen(buf));; + } + else + paramName = downcase_truncate_identifier(name->data, + strlen(name->data), true); + + tempFuncInfo = TdsLookupTypeFunctionsByTdsId(token->type, token->maxLen); + isNull = token->isNull; + + if (!isNull && fcinfo) + pval = tempFuncInfo->recvFuncPtr(req->messageData, token); + else + 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); + 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; + item->tableRelid = get_typ_typrelid(token->paramMeta.pgTypeOid); + item->tableName = NULL; + tvp_lookup_list = lappend(tvp_lookup_list, item); + MemoryContextSwitchTo(xactContext); + } + CommitTransactionCommand(); + MemoryContextSwitchTo(oldContext); + } + + i++; + } + + return args; +} + +/* + * SetVariables - Set TSQL variables by calling pltsql API directly + * + * For sp_execute, we only need to set the values to the associated args in + * fcinfo. In this case, param type and name are not important, hence set + * to NULL. + */ +static void +SetVariables(TDSRequestSP req, FunctionCallInfo *fcinfo) +{ + InlineCodeBlockArgs *codeblock_args; + ParameterToken token = NULL; + int i = 0, index = 0; + + /* should be only called for sp_execute */ + Assert(req->spType == SP_EXECUTE); + + codeblock_args = (InlineCodeBlockArgs *) palloc0(sizeof(InlineCodeBlockArgs)); + codeblock_args->handle = (int) req->handle; + codeblock_args->options = (BATCH_OPTION_EXEC_CACHED_PLAN | + 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 (token = req->dataParameter, index = 0; token != NULL; token = token->next, index++) + { + Datum pval; + bool isNull; + TdsIoFunctionInfo tempFuncInfo; + + + tempFuncInfo = TdsLookupTypeFunctionsByTdsId(token->type, token->maxLen); + isNull = token->isNull; + + if (!isNull) + pval = tempFuncInfo->recvFuncPtr(req->messageData, token); + else + 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); + + i++; + } + } + + /* Set the second argument as null just to satisfy the arg requirements */ + (*fcinfo)->args[1].value = PointerGetDatum(codeblock_args); + (*fcinfo)->args[1].isnull = false; + (*fcinfo)->nargs++; +} + + +/* + * errdetail_params + * + * Add an errdetail() line showing bind-parameter data, if available. + */ +static int +errdetail_params(int nTotalParams) +{ + ParamListInfo params; + params = (ParamListInfo) palloc(offsetof(ParamListInfoData, params) + + nTotalParams * sizeof(ParamExternData)); + + /* We have static list of params, so no hooks needed. */ + params->paramFetch = NULL; + params->paramFetchArg = NULL; + params->paramCompile = NULL; + params->paramCompileArg = NULL; + params->parserSetup = NULL; + params->parserSetupArg = NULL; + params->numParams = nTotalParams; + + TdsFetchInParamValues(params); + + /* We mustn't call user-defined I/O functions when in an aborted xact */ + if (params && params->numParams > 0 && !IsAbortedTransactionBlockState()) + { + StringInfoData param_str; + int paramno; + MemoryContext oldcontext; + + /* This code doesn't support dynamic param lists */ + Assert(params->paramFetch == NULL); + + /* Make sure any trash is generated in MessageContext */ + oldcontext = MemoryContextSwitchTo(MessageContext); + + initStringInfo(¶m_str); + + for (paramno = 0; paramno < params->numParams; paramno++) + { + ParamExternData *prm = ¶ms->params[paramno]; + Oid typoutput; + bool typisvarlena; + char *pstring; + char *p; + + appendStringInfo(¶m_str, "%s$%d = ", + paramno > 0 ? ", " : "", + paramno + 1); + + if (prm->isnull || !OidIsValid(prm->ptype)) + { + appendStringInfoString(¶m_str, "NULL"); + continue; + } + + getTypeOutputInfo(prm->ptype, &typoutput, &typisvarlena); + + pstring = OidOutputFunctionCall(typoutput, prm->value); + + appendStringInfoCharMacro(¶m_str, '\''); + for (p = pstring; *p; p++) + { + if (*p == '\'') /* double single quotes */ + appendStringInfoCharMacro(¶m_str, *p); + appendStringInfoCharMacro(¶m_str, *p); + } + appendStringInfoCharMacro(¶m_str, '\''); + + pfree(pstring); + } + + errdetail("Parameters: %s", param_str.data); + pfree(param_str.data); + MemoryContextSwitchTo(oldcontext); + } + + return 0; +} + +static void +SPExecuteSQL(TDSRequestSP req) +{ + StringInfoData s; + InlineCodeBlock *codeblock; + LOCAL_FCINFO(fcinfo, FUNC_MAX_ARGS); + + int paramno; + Datum retval; + Datum *values; + bool *nulls; + char *activity; + + TdsErrorContext->err_text = "Processing SP_EXECUTESQL Request"; + if ((req->nTotalParams + 2) > FUNC_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", + FUNC_MAX_ARGS))); + + TDSInstrumentation(INSTR_TDS_SP_EXECUTESQL); + + initStringInfo(&s); + FillQueryFromParameterToken(req, &s); + + activity = psprintf("SP_EXECUTESQL: %s", s.data); + pgstat_report_activity(STATE_RUNNING, activity); + pfree(activity); + + codeblock = makeNode(InlineCodeBlock); + codeblock->source_text = s.data; + codeblock->langOid = 0; /* TODO does it matter */ + codeblock->langIsTrusted = true; + codeblock->atomic = false; + + /* Just to satisfy argument requirement */ + MemSet(fcinfo, 0, SizeForFunctionCallInfo(FUNC_MAX_ARGS)); + fcinfo->nargs = 1; + fcinfo->args[0].value = PointerGetDatum(codeblock); + fcinfo->args[0].isnull = false; + + /* declare variables if there is any */ + if (req->nTotalParams > 0) + DeclareVariables(req, &fcinfo, 0); + + TDSStatementBeginCallback(NULL, NULL); + + PG_TRY(); + { + /* Now, execute the same and retrieve the composite datum */ + 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 */ + if (retval) + pltsql_plugin_handler_ptr->pltsql_read_out_param_callback(retval, &values, &nulls); + else if (req->nOutParams > 0) + elog(ERROR, "missing OUT parameter values from pltsql handler"); + } + PG_CATCH(); + { + if (TDS_DEBUG_ENABLED(TDS_DEBUG2)) + ereport(LOG, + (errmsg("sp_executesql statement: %s", s.data), + errhidestmt(true), + errdetail_params(req->nTotalParams))); + + TDSStatementExceptionCallback(NULL, NULL, false); + PG_RE_THROW(); + } + PG_END_TRY(); + + TDSStatementEndCallback(NULL, NULL); + + /* Return Status: 0 (success) or non-zero (failure) */ + TdsSendReturnStatus(0); + + /* Send OUT parameters */ + for (paramno = 0; paramno < req->nOutParams; paramno++) + SendReturnValueTokenInternal(req->idxOutParams[paramno], 0x01, NULL, + values[paramno], nulls[paramno], true); + + /* command type - execute (0xe0) */ + TdsSendDone(TDS_TOKEN_DONEPROC, TDS_DONE_FINAL, 0xe0, 0); + + /* + * Log immediately if dictated by log_statement + */ + 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_executesql statement: %s", s.data), + errhidestmt(true), + errdetail_params(req->nTotalParams))); + + pltsql_plugin_handler_ptr->stmt_needs_logging = false; + error_context_stack = plerrcontext; + } + + /* + * Print TDS log duration, if log_duration is set + */ + TDSLogDuration(s.data); + pfree(codeblock); +} + +static void +SPPrepare(TDSRequestSP req) +{ + StringInfoData s; + LOCAL_FCINFO(fcinfo, FUNC_MAX_ARGS); + + Datum retval; + Datum *values; + bool *nulls; + char *activity; + + TdsErrorContext->err_text = "Processing SP_PREPARE Request"; + TDSInstrumentation(INSTR_TDS_SP_PREPARE); + + tvp_lookup_list = NIL; + + if ((req->nTotalParams + 2) > FUNC_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", + FUNC_MAX_ARGS))); + + initStringInfo(&s); + FillQueryFromParameterToken(req, &s); + + activity = psprintf("SP_PREPARE: %s", s.data); + pgstat_report_activity(STATE_RUNNING, activity); + pfree(activity); + + MemSet(fcinfo, 0, SizeForFunctionCallInfo(FUNC_MAX_ARGS)); + + fcinfo->nargs = 3; + fcinfo->args[1].value = PointerGetDatum(cstring_to_text(req->metaDataParameterValue->data)); + if (req->metaDataParameterValue->len == 0) + fcinfo->args[1].isnull = true; + else + fcinfo->args[1].isnull = false; + + fcinfo->args[2].value = PointerGetDatum(cstring_to_text(s.data)); + if (s.len == 0) + fcinfo->args[2].isnull = true; + else + fcinfo->args[2].isnull = false; + + TDSStatementBeginCallback(NULL, NULL); + + PG_TRY(); + { + /* Now, call the prepare handler and retrieve the handle */ + 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 */ + if (retval) + pltsql_plugin_handler_ptr->pltsql_read_out_param_callback(retval, &values, &nulls); + else if (req->nOutParams > 0) + elog(ERROR, "missing OUT parameter values from pltsql handler"); + } + PG_CATCH(); + { + TDSStatementExceptionCallback(NULL, NULL, false); + tvp_lookup_list = NIL; + PG_RE_THROW(); + } + PG_END_TRY(); + + TDSStatementEndCallback(NULL, NULL); + + /* Return Status: 0 (success) or non-zero (failure) */ + TdsSendReturnStatus(0); + + /* Send the handle */ + SendReturnValueTokenInternal(req->handleParameter, 0x01, NULL, + values[0], false, false); + + /* command type - execute (0xe0) */ + TdsSendDone(TDS_TOKEN_DONEPROC, TDS_DONE_FINAL, 0xe0, 0); + + tvp_lookup_list = NIL; +} + +static void +SPExecute(TDSRequestSP req) +{ + InlineCodeBlock *codeblock; + LOCAL_FCINFO(fcinfo, FUNC_MAX_ARGS); + + int paramno; + Datum retval; + Datum *values; + bool *nulls; + + char *activity = psprintf("SP_EXECUTE Handle: %d", req->handle); + TdsErrorContext->err_text = "Processing SP_EXECUTE Request"; + pgstat_report_activity(STATE_RUNNING, activity); + pfree(activity); + TDSInstrumentation(INSTR_TDS_SP_EXECUTE); + + tvp_lookup_list = NIL; + + if ((req->nTotalParams + 2) > FUNC_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", + FUNC_MAX_ARGS))); + + codeblock = makeNode(InlineCodeBlock); + codeblock->source_text = NULL; + codeblock->langOid = 0; /* TODO does it matter */ + codeblock->langIsTrusted = true; + codeblock->atomic = false; + + /* Just to satisfy argument requirement. */ + MemSet(fcinfo, 0, SizeForFunctionCallInfo(FUNC_MAX_ARGS)); + fcinfo->nargs = 1; + fcinfo->args[0].value = PointerGetDatum(codeblock); + fcinfo->args[0].isnull = false; + + SetVariables(req, &fcinfo); + + TDSStatementBeginCallback(NULL, NULL); + + PG_TRY(); + { + /* Now, call the execute handler and retrieve the composite datum. */ + retval = pltsql_plugin_handler_ptr->sp_execute_callback (fcinfo); + MemoryContextSwitchTo(MessageContext); + + /* If sp_execute_handler does not end normally. */ + if (fcinfo->isnull) + elog(ERROR, "sp_execute_handler failed"); + + /* Read the handle retrived if the returned Datum is not NULL. */ + if (retval) + pltsql_plugin_handler_ptr->pltsql_read_out_param_callback(retval, &values, &nulls); + else if (req->nOutParams > 0) + elog(ERROR, "missing OUT parameter values from pltsql handler"); + } + PG_CATCH(); + { + if (TDS_DEBUG_ENABLED(TDS_DEBUG2)) + ereport(LOG, + (errmsg("sp_execute handle: %d", req->handle), + errhidestmt(true), + errdetail_params(req->nTotalParams))); + + TDSStatementExceptionCallback(NULL, NULL, false); + tvp_lookup_list = NIL; + PG_RE_THROW(); + } + PG_END_TRY(); + + TDSStatementEndCallback(NULL, NULL); + + /* Return Status: 0 (success) or non-zero (failure). */ + TdsSendReturnStatus(0); + + /* Send OUT parameters. */ + for (paramno = 0; paramno < req->nOutParams; paramno++) + SendReturnValueTokenInternal(req->idxOutParams[paramno], 0x01, NULL, + values[paramno], nulls[paramno], true); + + /* Command type - execute (0xe0). */ + TdsSendDone(TDS_TOKEN_DONEPROC, TDS_DONE_FINAL, 0xe0, 0); + + /* + * Log immediately if dictated by log_statement + */ + 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))); + pltsql_plugin_handler_ptr->stmt_needs_logging = false; + error_context_stack = plerrcontext; + } + + /* + * Print TDS log duration, if log_duration is set + */ + TDSLogDuration(req->messageData); + + pfree(codeblock); + tvp_lookup_list = NIL; +} + +static void +SPPrepExec(TDSRequestSP req) +{ + StringInfoData s; + InlineCodeBlock *codeblock; + InlineCodeBlockArgs* codeblock_args; + LOCAL_FCINFO(fcinfo, FUNC_MAX_ARGS); + + int paramno; + Datum retval; + Datum *values; + bool *nulls; + char *activity; + + tvp_lookup_list = NIL; + TdsErrorContext->err_text = "Processing SP_PREPEXEC Request"; + + if ((req->nTotalParams + 2) > FUNC_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", + FUNC_MAX_ARGS))); + + TDSInstrumentation(INSTR_TDS_SP_PREPEXEC); + + initStringInfo(&s); + FillQueryFromParameterToken(req, &s); + + activity = psprintf("SP_PREPEXEC: %s", s.data); + pgstat_report_activity(STATE_RUNNING, activity); + pfree(activity); + + codeblock = makeNode(InlineCodeBlock); + codeblock->source_text = s.data; + codeblock->langOid = 0; /* TODO does it matter */ + codeblock->langIsTrusted = true; + codeblock->atomic = false; + + /* Just to satisfy argument requirement */ + MemSet(fcinfo, 0, SizeForFunctionCallInfo(FUNC_MAX_ARGS)); + fcinfo->nargs = 1; + fcinfo->args[0].value = PointerGetDatum(codeblock); + fcinfo->args[0].isnull = false; + + codeblock_args = DeclareVariables(req, &fcinfo, + (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); + 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 */ + if (retval) + pltsql_plugin_handler_ptr->pltsql_read_out_param_callback(retval, &values, &nulls); + else if (req->nOutParams > 0) + elog(ERROR, "missing OUT parameter values from pltsql handler"); + } + PG_CATCH(); + { + if (TDS_DEBUG_ENABLED(TDS_DEBUG2)) + ereport(LOG, + (errmsg("sp_prepexec handle: %d, " + "statement: %s", req->handle, s.data), + errhidestmt(true), + errdetail_params(req->nTotalParams))); + + TDSStatementExceptionCallback(NULL, NULL, false); + tvp_lookup_list = NIL; + PG_RE_THROW(); + } + PG_END_TRY(); + + TDSStatementEndCallback(NULL, NULL); + + /* TODO: other values than 0? */ + TdsSendReturnStatus(0); + + /* Send the handle */ + SendReturnValueTokenInternal(req->handleParameter, 0x01, NULL, + codeblock_args->handle, false, true); + + /* Send OUT parameters */ + for (paramno = 0; paramno < req->nOutParams; paramno++) + SendReturnValueTokenInternal(req->idxOutParams[paramno], 0x01, NULL, + values[paramno], nulls[paramno], true); + + /* command type - execute (0xe0) */ + TdsSendDone(TDS_TOKEN_DONEPROC, TDS_DONE_FINAL, 0xe0, 0); + + /* + * Log immediately if dictated by log_statement + */ + 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_prepexec handle: %d, " + "statement: %s", req->handle, s.data), + errhidestmt(true), + errdetail_params(req->nTotalParams))); + pltsql_plugin_handler_ptr->stmt_needs_logging = false; + error_context_stack = plerrcontext; + } + + /* + * Print TDS log duration, if log_duration is set + */ + TDSLogDuration(s.data); + + pfree(codeblock); + tvp_lookup_list = NIL; +} + +/* + * DeclareSPVariables - declare arguments and return type of a stored procedure + * or a scalar UDF. + */ +static ParameterToken +DeclareSPVariables(TDSRequestSP req, FunctionCallInfo *fcinfo) +{ + 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. + */ + pltsql_plugin_handler_ptr->pltsql_read_procedure_info( + &req->name, + &req->isStoredProcedure, + &atttypid, + &atttypmod, + &attcollation); + + args = CreateArgs(req->nTotalParams + 1); + + /* now add the same as second argument */ + (*fcinfo)->args[1].value = PointerGetDatum(args); + (*fcinfo)->args[1].isnull = false; + (*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. + */ + 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); + index++; + + /* + * 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; + Datum pval; + bool isNull; + TdsIoFunctionInfo tempFuncInfo; + + name = &(token->paramMeta.colName); + + if (name->len == 0) + { + char buf[10]; + + snprintf(buf, sizeof(buf), "@p%d", index); + paramName = pnstrdup(buf, strlen(buf));; + } + else + paramName = downcase_truncate_identifier(name->data, + strlen(name->data), true); + + tempFuncInfo = TdsLookupTypeFunctionsByTdsId(token->type, token->maxLen); + isNull = token->isNull; + + if (!isNull) + pval = tempFuncInfo->recvFuncPtr(req->messageData, token); + 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); + } + + return returnToken; +} + +static void +SPCustomType(TDSRequestSP req) +{ + StringInfoData s; + InlineCodeBlock *codeblock; + LOCAL_FCINFO(fcinfo, FUNC_MAX_ARGS); + ParameterToken returnParamToken = NULL; + + int paramno; + Datum retval; + Datum *values; + bool *nulls; + char *activity; + + TdsErrorContext->err_text = "Processing SP_CUSTOMTYPE Request"; + if ((req->nTotalParams + 2) > FUNC_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", + FUNC_MAX_ARGS))); + + TDSInstrumentation(INSTR_TDS_USER_CUSTOM_SP); + + initStringInfo(&s); + FillStoredProcedureCallFromParameterToken(req, &s); + + activity = psprintf("SP_CUSTOMTYPE: %s", s.data); + pgstat_report_activity(STATE_RUNNING, activity); + pfree(activity); + + codeblock = makeNode(InlineCodeBlock); + codeblock->source_text = s.data; + codeblock->langOid = 0; /* TODO does it matter */ + codeblock->langIsTrusted = true; + codeblock->atomic = false; + + /* Just to satisfy argument requirement */ + MemSet(fcinfo, 0, SizeForFunctionCallInfo(FUNC_MAX_ARGS)); + fcinfo->nargs = 1; + fcinfo->args[0].value = PointerGetDatum(codeblock); + fcinfo->args[0].isnull = false; + + PG_TRY(); + { + /* declare variables if there is any */ + returnParamToken = DeclareSPVariables(req, &fcinfo); + + /* Now, execute the same and retrieve the composite datum */ + 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 */ + if (retval) + pltsql_plugin_handler_ptr->pltsql_read_out_param_callback(retval, &values, &nulls); + else if (req->nOutParams > 0) + elog(ERROR, "missing OUT parameter values from pltsql handler"); + } + PG_CATCH(); + { + if (TDS_DEBUG_ENABLED(TDS_DEBUG2)) + ereport(LOG, + (errmsg("stored procedure: %s", req->name.data), + errhidestmt(true), + errdetail_params(req->nTotalParams))); + + tvp_lookup_list = NIL; + + PG_RE_THROW(); + } + PG_END_TRY(); + + /* + * Return value is sent as ReturnStatus token for SP and ReturnValue token + * for scalar UDFs. + */ + if (req->isStoredProcedure) + { + TdsSendReturnStatus(DatumGetInt32(values[0])); + } + else + { + SendReturnValueTokenInternal(returnParamToken, 0x02, NULL, + values[0], nulls[0], true); + } + + /* + * Send OUT parameters. Please note that the first entry contains the + * return status that we've already sent. + */ + for (paramno = 0; paramno < req->nOutParams; paramno++) + SendReturnValueTokenInternal(req->idxOutParams[paramno], 0x01, NULL, + values[paramno + 1], nulls[paramno + 1], true); + + /* command type - execute (0xe0) */ + TdsSendDone(TDS_TOKEN_DONEPROC, TDS_DONE_FINAL, 0xe0, 0); + + /* + * Log immediately if dictated by log_statement + */ + 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))); + pltsql_plugin_handler_ptr->stmt_needs_logging = false; + error_context_stack = plerrcontext; + } + + /* + * Print TDS log duration, if log_duration is set + */ + TDSLogDuration(req->name.data); + pfree(codeblock); +} + +static void +SPUnprepare(TDSRequestSP req) +{ + LOCAL_FCINFO(fcinfo, FUNC_MAX_ARGS); + + char *activity = psprintf("SP_UNPREPARE Handle: %d", req->handle); + TdsErrorContext->err_text = "Processing SP_UNPREPARE Request"; + pgstat_report_activity(STATE_RUNNING, activity); + pfree(activity); + + TDSInstrumentation(INSTR_TDS_SP_UNPREPARE); + + /* Just to satisfy argument requirement */ + MemSet(fcinfo, 0, SizeForFunctionCallInfo(FUNC_MAX_ARGS)); + fcinfo->nargs = 1; + fcinfo->args[0].value = PointerGetDatum(req->handle); + fcinfo->args[0].isnull = false; + + TDSStatementBeginCallback(NULL, NULL); + + PG_TRY(); + { + /* Now, execute the unprepare handler and retrieve the composite datum */ + pltsql_plugin_handler_ptr->sp_unprepare_callback (fcinfo); + MemoryContextSwitchTo(MessageContext); + + /* If sp_unprepare_handler does not end normally. */ + if (fcinfo->isnull) + elog(ERROR, "pltsql_sp_unprepare_handler failed"); + } + PG_CATCH(); + { + TDSStatementExceptionCallback(NULL, NULL, false); + PG_RE_THROW(); + } + PG_END_TRY(); + + TDSStatementEndCallback(NULL, NULL); + + + /* Return Status: 0 (success) or non-zero (failure). */ + TdsSendReturnStatus(0); + + /* command type - execute (0xe0) */ + TdsSendDone(TDS_TOKEN_DONEPROC, TDS_DONE_FINAL, 0xe0, 0); +} + +static int +GetSetColMetadataForCharType(ParameterToken temp, StringInfo message, uint8_t tdsType, + uint64_t *mainOffset) +{ + + uint32_t collation; + uint8_t sortId; + uint64_t offset = *mainOffset; + uint16_t tempLen; + pg_enc enc; + + if ((offset + sizeof(tempLen) + + sizeof(collation) + + sizeof(sortId)) > + message->len) + return STATUS_ERROR; + + memcpy(&tempLen, &message->data[offset], sizeof(tempLen)); + temp->maxLen = tempLen; + offset += sizeof(tempLen); + memcpy(&collation, &message->data[offset], sizeof(collation)); + offset += sizeof(collation); + sortId = message->data[offset]; + offset += sizeof(sortId); + + /* If we recieve 0 value for LCID then we should treat it as a default LCID.*/ + enc = TdsGetEncoding(collation); + + /* + * TODO: we should send collation name here instead of Locale ID. + */ + 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))); + + SetColMetadataForCharType(&temp->paramMeta, tdsType, + collation & 0xFFFFF, enc, + (collation & 0xFFF00000) >> 20, + sortId, tempLen); + + *mainOffset = offset; + return STATUS_OK; +} + +static int +GetSetColMetadataForTextType(ParameterToken temp, StringInfo message, uint8_t tdsType, + uint64_t *mainOffset) +{ + + uint32_t collation; + uint8_t sortId; + uint64_t offset = *mainOffset; + pg_enc enc; + + if ((offset + sizeof(temp->maxLen) + + sizeof(collation) + + sizeof(sortId)) > message->len) + return STATUS_ERROR; + + memcpy(&temp->maxLen, &message->data[offset], sizeof(temp->maxLen)); + offset += sizeof(temp->maxLen); + memcpy(&collation, &message->data[offset], sizeof(collation)); + offset += sizeof(collation); + sortId = message->data[offset]; + offset += sizeof(sortId); + + /* If we recieve 0 value for LCID then we should treat it as a default LCID.*/ + enc = TdsGetEncoding(collation); + + /* + * TODO: we should send collation name here instead of Locale ID. + */ + 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))); + + SetColMetadataForTextType(&temp->paramMeta, tdsType, + collation & 0xFFFFF, enc, + (collation & 0xFFF00000) >> 20, + sortId, temp->maxLen); + + *mainOffset = offset; + return STATUS_OK; +} + +int +ReadPlp(ParameterToken temp, StringInfo message, uint64_t *mainOffset) +{ + + uint64_t plpTok; + Plp plpTemp, plpPrev = NULL; + unsigned long lenCheck = 0; + uint64_t offset = *mainOffset; + + memcpy(&plpTok , &message->data[offset], sizeof(plpTok)); + offset += sizeof(plpTok); + temp->plp = NULL; + + /* NULL Check */ + if (plpTok == PLP_NULL) + { + temp->isNull = true; + *mainOffset = offset; + return STATUS_OK; + } + + while (true) + { + uint32_t tempLen; + + if (offset + sizeof(tempLen) > message->len) + return STATUS_ERROR; + memcpy(&tempLen , &message->data[offset], sizeof(tempLen)); + offset += sizeof(tempLen); + + /* PLP Terminator */ + if (tempLen == PLP_TERMINATOR) + break; + plpTemp = palloc0(sizeof(PlpData)); + plpTemp->next = NULL; + plpTemp->offset = offset; + plpTemp->len = tempLen; + if (plpPrev == NULL) + { + plpPrev = plpTemp; + temp->plp = plpTemp; + } + else + { + plpPrev->next = plpTemp; + plpPrev = plpPrev->next; + } + if (offset + plpTemp->len > message->len) + return STATUS_ERROR; + + offset += plpTemp->len; + lenCheck += plpTemp->len; + } + + if (plpTok != PLP_UNKNOWN_LEN) + { + /* Length check */ + if (lenCheck != plpTok) + return STATUS_ERROR; + } + + *mainOffset = offset; + return STATUS_OK; +} + +static void +InitialiseParameterToken(TDSRequestSP request) +{ + /* Initialize */ + request->handleParameter = NULL; + request->cursorHandleParameter = NULL; + request->cursorPreparedHandleParameter = NULL; + request->queryParameter = NULL; + request->cursorExtraArg1 = NULL; + request->cursorExtraArg2 = NULL; + request->cursorExtraArg3 = NULL; + request->dataParameter = NULL; +} + +static int +ReadParameters(TDSRequestSP request, uint64_t offset, StringInfo message, int *parameterCount) +{ + ParameterToken temp, prev = NULL; + int len = 0; + TdsIoFunctionInfo tempFuncInfo; + uint16 paramOrdinal = 0; + int retStatus; + + while(offset < message->len) + { + 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((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. */ + request->messageLen = message->len; + return STATUS_OK; + } + + temp = palloc0(sizeof(ParameterTokenData)); + 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 + * temp->name->len + */ + initStringInfo(&(temp->paramMeta.colName)); + + if (len > 0) + { + /* + * FIXME: parameter name is in UTF-16 format. Fix this separately. + */ + TdsUTF16toUTF8StringInfo(&(temp->paramMeta.colName), &(message->data[offset]), 2 * len); + offset += 2 * len; + len = 0; + } + + memcpy(&temp->flags, &message->data[offset], sizeof(temp->flags)); + 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; + } +#endif + tdsType = message->data[offset++]; + + temp->type = tdsType; + temp->paramOrdinal = paramOrdinal; + paramOrdinal++; + + switch (tdsType) + { + 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; + + 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; + } + + CheckForInvalidLength(temp); + + offset += sizeof(temp->len); + temp->dataOffset = offset; + offset += temp->len; + } + break; + case TDS_TYPE_IMAGE: + case TDS_TYPE_SQLVARIANT: + { + /* Type IMAGE is a deprecated large object*/ + if((temp->flags & SP_FLAGS_BYREFVALUE) && tdsType == TDS_TYPE_IMAGE) + ereport(ERROR, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("Invalid parameter %d (\"%s\"): Data type 0x%02X is a deprecated large object, or LOB, but is marked as output parameter. " + "Deprecated types are not supported as output parameters. Use current large object types instead.", + paramOrdinal, temp->paramMeta.colName.data, tdsType))); + SetColMetadataForImageType(&temp->paramMeta, tdsType); + + memcpy(&temp->len, &message->data[offset], sizeof(temp->len)); + + /* for Null values, Len field is set to -1(0xFFFFFFFF) or 0 */ + if (temp->len == 0xFFFFFFFF || + (tdsType == TDS_TYPE_SQLVARIANT && temp->len == 0)) + { + temp->len = 0; + temp->isNull = true; + } + + if (tdsType == TDS_TYPE_SQLVARIANT && temp->len > temp->paramMeta.metaEntry.type8.maxSize) + ereport(ERROR, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. " + "Parameter %d (\"%s\"): Data type 0x%02X (sql_variant) has an invalid length for type-specific metadata.", + paramOrdinal, temp->paramMeta.colName.data, tdsType))); + + /* + * 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 + */ + uint16_t tempLen; + + 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; + } + + 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; + 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 (temp->len == 0) + temp->isNull = true; + + CheckForInvalidLength(temp); + + 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)); + + /* 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 + { + 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); + + temp->dataOffset = offset; + if (offset + temp->len > message->len) + return STATUS_ERROR; + offset += temp->len; + } + } + break; + case TDS_TYPE_DATE: + { + if ((offset + 1) > message->len) + return STATUS_ERROR; + + temp->len = message->data[offset++]; + temp->maxLen = 3; + + if (temp->len == 0) + temp->isNull = true; + + CheckForInvalidLength(temp); + + temp->dataOffset = offset; + if (offset + temp->len > message->len) + return STATUS_ERROR; + offset += temp->len; + + 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++]; + + if (temp->len == 0) + temp->isNull = true; + + 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; + + CheckForInvalidLength(temp); + + 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; + + temp->maxLen = 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. " + "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))); + + temp->len = message->data[offset++]; + + if (temp->len == 0) + temp->isNull = true; + + CheckForInvalidLength(temp); + + temp->dataOffset = offset; + + 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; + + 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; + 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))); + } + 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. + */ + 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) + { + prev = temp; + request->parameter = temp; + } + else + { + prev->next = temp; + prev = temp; + } + *parameterCount += 1; + } + /* + * 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; +} + +/* + * GetSPCursorHandleParameter - Generate or fetch the cursor handle parameter for a + * SP_CURSOR* request. + */ +static void +GetSPCursorHandleParameter(TDSRequestSP request) +{ + switch(request->spType) + { + case SP_CURSORPREPEXEC: + case SP_CURSOREXEC: + case SP_CURSOROPEN: + break; + case SP_CURSORFETCH: + case SP_CURSORCLOSE: + case SP_CURSOR: + case SP_CURSOROPTION: + { + /* Fetch the handle from the request */ + ParameterToken token = request->cursorHandleParameter; + + /* handle must exist */ + Assert(token); + + /* the token must be integer */ + Assert(token->paramMeta.metaLen == sizeof(token->paramMeta.metaEntry.type1) && + token->paramMeta.metaEntry.type1.tdsTypeId == TDS_TYPE_INTEGER); + + memcpy(&request->cursorHandle, &request->messageData[token->dataOffset], + sizeof(uint32)); + + /* 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))); + + } + break; + case SP_CURSORUNPREPARE: + case SP_CURSORPREPARE: + case SP_PREPARE: + case SP_PREPEXEC: + case SP_PREPEXECRPC: + case SP_EXECUTE: + case SP_UNPREPARE: + case SP_CUSTOMTYPE: + case SP_EXECUTESQL: + request->cursorHandle = SP_CURSOR_HANDLE_INVALID; + break; + default: + Assert(0); + } +} + +/* + * GetSPCursorPreparedHandleParameter - Generate or fetch the handle parameter + * for a SP_CURSOR_[PREPEXEC/EXEC] request. + */ +static void +GetSPCursorPreparedHandleParameter(TDSRequestSP request) +{ + switch(request->spType) + { + case SP_CURSORPREPEXEC: + case SP_CURSOROPEN: + case SP_CURSORFETCH: + case SP_CURSORCLOSE: + case SP_CURSOR: + case SP_CURSOROPTION: + case SP_CUSTOMTYPE: + case SP_EXECUTESQL: + case SP_PREPARE: + case SP_PREPEXEC: + case SP_EXECUTE: + case SP_PREPEXECRPC: + case SP_UNPREPARE: + /* handle will be retrieved from babelfishpg_tsql extension */ + request->cursorPreparedHandle = SP_CURSOR_PREPARED_HANDLE_INVALID; + break; + case SP_CURSOREXEC: + case SP_CURSORUNPREPARE: + case SP_CURSORPREPARE: + { + /* Fetch the handle from the request */ + ParameterToken token = request->cursorPreparedHandleParameter; + + /* handle must exist */ + Assert(token); + + /* the token must be integer */ + Assert(token->paramMeta.metaLen == sizeof(token->paramMeta.metaEntry.type1) && + token->paramMeta.metaEntry.type1.tdsTypeId == TDS_TYPE_INTEGER); + + memcpy(&request->cursorPreparedHandle, &request->messageData[token->dataOffset], + sizeof(uint32)); + + /* the handle must be valid */ + Assert(request->cursorPreparedHandle != SP_CURSOR_PREPARED_HANDLE_INVALID); + + } + break; + default: + Assert(0); + } +} + +/* + * GetSPHandleParameter - Generate or fetch the handle parameter for a SP_* + * request. + */ +static void +GetSPHandleParameter(TDSRequestSP request) +{ + switch(request->spType) + { + case SP_CURSORPREPARE: + case SP_CURSORPREPEXEC: + case SP_CURSOREXEC: + case SP_CURSOROPEN: + case SP_CURSORFETCH: + case SP_CURSORCLOSE: + case SP_CURSOR: + case SP_CURSOROPTION: + case SP_CURSORUNPREPARE: + case SP_CUSTOMTYPE: + case SP_EXECUTESQL: + case SP_PREPARE: + case SP_PREPEXEC: + case SP_PREPEXECRPC: + /* handle will be retrieved from babelfishpg_tsql extension */ + request->handle = SP_HANDLE_INVALID; + break; + case SP_EXECUTE: + case SP_UNPREPARE: + { + /* Fetch the handle from the request */ + ParameterToken token = request->handleParameter; + + /* handle must exist */ + Assert(token); + + /* the token must be integer */ + Assert(token->paramMeta.metaLen == sizeof(token->paramMeta.metaEntry.type1) && + token->paramMeta.metaEntry.type1.tdsTypeId == TDS_TYPE_INTEGER); + + memcpy(&request->handle, &request->messageData[token->dataOffset], + sizeof(uint32)); + + /* the handle must be valid */ + Assert(request->handle != SP_HANDLE_INVALID); + + } + break; + default: + Assert(0); + } +} + +/* + * FillStoredProcedureCallFromParameterToken - construct a query string in the + * following format: + * + * if tsql dialect, then + * EXECUTE @P0, @P1, .... + * or + * EXECUTE @param1 = @param1, @param2 = @param2, .... + * + * XXX: The format @param1 = @param1 is not currently supported for UDFs in + * Babel. Once we support that feature, we need to build the string format + * accordingly. Currently, it's commented out. + */ +static inline void +FillStoredProcedureCallFromParameterToken(TDSRequestSP req, StringInfo inBuf) +{ + int paramno; + int numParams; + ParameterToken token = NULL; + StringInfo name; + + Assert(req->queryParameter == NULL); + + numParams = req->nTotalParams; + + if (sql_dialect != SQL_DIALECT_TSQL) + elog(ERROR, "sql dialect is not set to TSQL"); + + paramno = 0; + appendStringInfo(inBuf, "EXECUTE @p%d = %s ", paramno, req->name.data); + paramno++; + + if (numParams > 0) + { + token = req->dataParameter; + name = &(token->paramMeta.colName); + + if (name->len == 0) + appendStringInfo(inBuf, "@p%d", paramno); + else + appendStringInfo(inBuf, "%s = %s", name->data, name->data); + /* If this is an OUT parameter, mark it */ + if(token->flags & SP_FLAGS_BYREFVALUE) + appendStringInfo(inBuf, " OUT"); + token = token->next; + paramno++; + } + + for (; token != NULL; token = token->next) + { + name = &(token->paramMeta.colName); + + if (name->len == 0) + appendStringInfo(inBuf, ", @P%d", paramno); + else + appendStringInfo(inBuf, ", %s = %s", name->data, name->data); + /* If this is an OUT parameter, mark it */ + if(token->flags & SP_FLAGS_BYREFVALUE) + appendStringInfo(inBuf, " OUT"); + paramno++; + } + + appendStringInfoCharMacro(inBuf, '\0'); +} + +/* + * GetQueryFromParameterToken - extract the query from parameter token + * + */ +static inline void +FillQueryFromParameterToken(TDSRequestSP req, StringInfo inBuf) +{ + ParameterToken token = req->queryParameter; + + TdsReadUnicodeDataFromTokenCommon(req->messageData, token, inBuf); + appendStringInfoCharMacro(inBuf, '\0'); +} + +/* + * InitializeDataParamTokenIndex - initialize the IN/OUT parameter index array + */ +static inline void +InitializeDataParamTokenIndex(TDSRequestSP request) +{ + ParameterToken token; + uint16 idOutParam = 0; + int32 paramCount = 0; + + request->nOutParams = 0; + request->idxOutParams = NULL; + + for (token = request->dataParameter; token != NULL; token = token->next) + { + request->nTotalParams++; + + if ((token->flags & 0x01) == 1) + request->nOutParams++; + } + + /* Allocate the memory for OUT parameter array. */ + if (request->nOutParams > 0) + request->idxOutParams = palloc(request->nOutParams + * sizeof(ParameterToken)); + + /* + * Store all OUT parameters together. + */ + for (token = request->dataParameter; token != NULL; token = token->next) + { + + if ((token->flags & 0x01) == 1) + request->idxOutParams[idOutParam++] = token; + paramCount++; + } + + Assert(request->nOutParams == idOutParam); +} + +static inline void +FillOidsFromParameterToken(TDSRequestSP req, StringInfo inBuf) +{ + ParameterToken token; + + /* store num of data params amd their oids */ + enlargeStringInfo(inBuf, sizeof(uint16) + + req->nTotalParams * sizeof(Oid)); + + pq_writeint16(inBuf, req->nTotalParams); + + for (token = req->dataParameter; token != NULL; token = token->next) + { + uint32 paramType = (uint32) token->paramMeta.pgTypeOid; + pq_writeint32(inBuf, paramType); + } +} + +static inline void +FillColumnInfoFromParameterToken(TDSRequestSP req, StringInfo inBuf) +{ + /* + * 1. store num of data params amd their formats + * + * TODO: For now, we set this to zero to indicate that there are no + * parameters or that the parameters all use the default format (text). + */ + enlargeStringInfo(inBuf, sizeof(uint16)); + + pq_writeint16(inBuf, 0); + + /* 2. store num of data params */ + enlargeStringInfo(inBuf, sizeof(uint16)); + pq_writeint16(inBuf, req->nTotalParams); +} + +static inline Portal +GetPortalFromCursorHandle(const int portalHandle, bool missingOk) +{ + Portal portal; + char cursorHandle[INT32_STRLEN]; + + sprintf(cursorHandle, "%d", portalHandle); + + portal = GetPortalByName(cursorHandle); + + if (!missingOk && !PortalIsValid(portal)) + elog(ERROR, "portal \"%s\" does not exist", cursorHandle); + + return portal; +} + +static inline void +FetchCursorOptions(TDSRequestSP req) +{ + ParameterToken token; + + token = req->cursorExtraArg1; + Assert(token); + + /* the token must be integer */ + Assert(token->paramMeta.metaLen == sizeof(token->paramMeta.metaEntry.type1) && + token->paramMeta.metaEntry.type1.tdsTypeId == TDS_TYPE_INTEGER); + + memcpy(&req->scrollopt, &req->messageData[token->dataOffset], + sizeof(uint32)); + + token = req->cursorExtraArg2; + Assert(token); + + /* the token must be integer */ + Assert(token->paramMeta.metaLen == sizeof(token->paramMeta.metaEntry.type1) && + token->paramMeta.metaEntry.type1.tdsTypeId == TDS_TYPE_INTEGER); + + memcpy(&req->ccopt, &req->messageData[token->dataOffset], + sizeof(uint32)); + +} + +static int +SetCursorOption(TDSRequestSP req) +{ + + 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. + */ + if (req->scrollopt & SP_CURSOR_SCROLLOPT_STATIC) + curoptions |= CURSOR_OPT_HOLD; + else if ((req->ccopt & SP_CURSOR_SCROLLOPT_CHECK_ACCEPTED_TYPES) && + (req->ccopt & SP_CURSOR_SCROLLOPT_STATIC_ACCEPTABLE)) + curoptions |= CURSOR_OPT_HOLD; + + if (req->scrollopt & SP_CURSOR_SCROLLOPT_FORWARD_ONLY) + curoptions |= CURSOR_OPT_NO_SCROLL; + else if ((req->ccopt & SP_CURSOR_SCROLLOPT_CHECK_ACCEPTED_TYPES) && + (req->ccopt & SP_CURSOR_SCROLLOPT_FORWARD_ONLY_ACCEPTABLE)) + curoptions |= CURSOR_OPT_NO_SCROLL; + else + curoptions |= CURSOR_OPT_SCROLL; + + return curoptions; +} + +/* + * Send the Cursor Response: + * Only for sp_cursorprepexec, we send the handle for the prepared statement + * otherwise this is common to sp_cursoropen, sp_cursorprepexec, sp_cursorexec + */ +static void +SendCursorResponse(TDSRequestSP req) +{ + 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. + */ + if (IsAbortedTransactionBlockState() && + portal->tupDesc) + elog(ERROR, "current transaction is aborted, " + "commands ignored until end of transaction block"); + + if (portal->commandTag && portal->commandTag == CMDTAG_SELECT) + { + cmd_type = TDS_CMD_SELECT; + } + else + { + elog(ERROR, "TDS: unhandled cursor completionTag '%s'", + portal->commandTag ? GetCommandTagName(portal->commandTag) : ""); + cmd_type = TDS_CMD_UNKNOWN; + } + + /* + * First get all the information needed to construct the tokens. We don't + * want to throw error in the middle of sending the response. That'll + * break the protocol. We also need to fetch the primary keys for dynamic + * 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))); + + /* Send COLMETADATA token, TABNAME token and COLINFO token */ + SendColumnMetadataToken(portal->tupDesc->natts, true /* send ROWSTAT column */); + SendTabNameToken(); + 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? + */ + TdsSendReturnStatus(0); + + /* + * Send the handle for the PrePared Plan only for the + * sp_cursorprepexec request + * + */ + if (req->spType == SP_CURSORPREPEXEC) + SendReturnValueTokenInternal(req->cursorPreparedHandleParameter, 0x01, NULL, + UInt32GetDatum(req->cursorPreparedHandle), false, false); + + /* send the cursor handle */ + SendReturnValueTokenInternal(req->cursorHandleParameter, 0x01, NULL, + 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 (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 (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. + * + * 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, + UInt32GetDatum((int) -1), false, false); + + /* + * command type - execute (0xe0) + */ + TdsSendDone(TDS_TOKEN_DONEPROC, TDS_DONE_FINAL, 0xe0, 0); +} + +static void +HandleSPCursorOpenCommon(TDSRequestSP req) +{ + int curoptions = 0; + int ret; + StringInfoData buf; + + TdsErrorContext->err_text = "Processing SP_CURSOROPEN Common Request"; + /* fetch cursor options */ + FetchCursorOptions(req); + + curoptions = SetCursorOption(req); + + TDSStatementBeginCallback(NULL, NULL); + + PG_TRY(); + { + if (req->spType == SP_CURSOREXEC) + { + 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); + } + + else + { + 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); + + 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_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) + ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("sp_cursoropen failed: %d", ret))); + + } + + MemoryContextSwitchTo(MessageContext); + } + + PG_CATCH(); + { + TDSLogStatementCursorHandler(req, buf.data, PRINT_BOTH_CURSOR_HANDLE); + TDSStatementExceptionCallback(NULL, NULL, false); + PG_RE_THROW(); + } + PG_END_TRY(); + + TDSStatementEndCallback(NULL, NULL); + + /* Send the response now */ + SendCursorResponse(req); + + /* Log immediately if dictated by log_statement and log_duration */ + TDSLogStatementCursorHandler(req, buf.data, PRINT_BOTH_CURSOR_HANDLE); +} + +/* + * TODO: can be reused this for prepare-exec + */ +static void +GenerateBindParamsData(TDSRequestSP req) +{ + uint16_t count = 0; + ParameterToken tempBindParam; + bool isNull; + TdsIoFunctionInfo tempFuncInfo; + Oid ptype; + Datum pval; + + TdsErrorContext->err_text = "Generating Bind Parameters' Data"; + tempBindParam = req->dataParameter; + + while (tempBindParam != NULL) + { + count++; + tempBindParam = tempBindParam->next; + } + + req->nTotalBindParams = count; + + /* If count == 0, then there is no bind Parameter */ + if (count == 0) + { + req->boundParamsData = NULL; + req->boundParamsNullList = NULL; + req->boundParamsOidList = NULL; + return; + } + req->boundParamsData = palloc0(sizeof(Datum) * count); + req->boundParamsNullList = palloc0(sizeof(char) * count); + req->boundParamsOidList = palloc0(sizeof(Oid) * count); + + tempBindParam = req->dataParameter; + + count = 0; + while (tempBindParam != NULL) + { + + tempFuncInfo = TdsLookupTypeFunctionsByTdsId(tempBindParam->type, + tempBindParam->maxLen); + isNull = tempBindParam->isNull; + + ptype = tempBindParam->paramMeta.pgTypeOid; + + if (!isNull) + pval = tempFuncInfo->recvFuncPtr(req->messageData, tempBindParam); + else + pval = (Datum) 0; + + req->boundParamsData[count] = pval; + req->boundParamsNullList[count] = (isNull) ? 'n' : ' '; + req->boundParamsOidList[count] = ptype; + + count++; + tempBindParam = tempBindParam->next; + } +} + +static void +FetchAndValidateCursorFetchOptions(TDSRequestSP req, int *fetchType, + int *rownum, int *howMany) +{ + ParameterToken token; + + token = req->cursorExtraArg1; + Assert(token); + + /* the token must be integer */ + Assert(token->paramMeta.metaLen == sizeof(token->paramMeta.metaEntry.type1) && + token->paramMeta.metaEntry.type1.tdsTypeId == TDS_TYPE_INTEGER); + + memcpy(fetchType, &req->messageData[token->dataOffset], sizeof(uint32)); + + switch(*fetchType) + { + case SP_CURSOR_FETCH_FIRST: + case SP_CURSOR_FETCH_NEXT: + case SP_CURSOR_FETCH_PREV: + 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. + */ + 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))); + break; + default: + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid cursor fetch type %X", *fetchType))); + } + + token = req->cursorExtraArg2; + + if (token) + { + /* the token must be integer */ + Assert(token->paramMeta.metaLen == sizeof(token->paramMeta.metaEntry.type1) && + token->paramMeta.metaEntry.type1.tdsTypeId == TDS_TYPE_INTEGER); + + 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. + */ + if (*fetchType != SP_CURSOR_FETCH_ABSOLUTE && + *fetchType != SP_CURSOR_FETCH_RELATIVE && + *fetchType != SP_CURSOR_FETCH_INFO) + *rownum = -1; + + } + else + *rownum = -1; + + token = req->cursorExtraArg3; + + if (token) + { + /* the token must be integer */ + Assert(token->paramMeta.metaLen == sizeof(token->paramMeta.metaEntry.type1) && + token->paramMeta.metaEntry.type1.tdsTypeId == TDS_TYPE_INTEGER); + + memcpy(howMany, &req->messageData[token->dataOffset], sizeof(uint32)); + + /* + * For the fetchtype values of NEXT, PREV, ABSOLUTE, RELATIVE, and + * PREV_NOADJUST, an nrow value of 0 is not valid. + */ + if (*howMany == 0) + { + if (*fetchType == SP_CURSOR_FETCH_NEXT || + *fetchType == SP_CURSOR_FETCH_PREV || + *fetchType == SP_CURSOR_FETCH_ABSOLUTE || + *fetchType == SP_CURSOR_FETCH_RELATIVE || + *fetchType == SP_CURSOR_FETCH_PREV_NOADJUST) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid nrow value 0 for cursor type %X", *fetchType))); + } + } + else + { + /* If nrows is not specified, the default value is 20 rows. */ + *howMany = 20; + } +} + +static void +HandleSPCursorFetchRequest(TDSRequestSP req) +{ + 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); + pfree(activity); + + FetchAndValidateCursorFetchOptions(req, &fetchType, &rownum, &nrows); + + TDSStatementBeginCallback(NULL, NULL); + + PG_TRY(); + { + ret = pltsql_plugin_handler_ptr->sp_cursorfetch_callback((int)req->cursorHandle, &fetchType, &rownum, &nrows); + MemoryContextSwitchTo(MessageContext); + + if (ret > 0) + ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("sp_cursorfetch failed: %d", ret))); + } + + PG_CATCH(); + { + TDSLogStatementCursorHandler(req, req->messageData, PRINT_CURSOR_HANDLE); + TDSStatementExceptionCallback(NULL, NULL, false); + PG_RE_THROW(); + } + PG_END_TRY(); + + TDSStatementEndCallback(NULL, NULL); + + TdsSendDone(TDS_TOKEN_DONEINPROC, TDS_DONE_MORE, TDS_CMD_SELECT, SPI_processed); + + /* for success, the return status is 0 */ + TdsSendReturnStatus(0); + + /* 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); +} + +static void +HandleSPCursorCloseRequest(TDSRequestSP req) +{ + 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); + pfree(activity); + TDSStatementBeginCallback(NULL, NULL); + + /* close the cursor */ + PG_TRY(); + { + ret = pltsql_plugin_handler_ptr->sp_cursorclose_callback((int)req->cursorHandle); + MemoryContextSwitchTo(MessageContext); + + if (ret > 0) + ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("sp_cursorclose failed: %d", ret))); + } + + PG_CATCH(); + { + TDSLogStatementCursorHandler(req, req->messageData, PRINT_CURSOR_HANDLE); + TDSStatementExceptionCallback(NULL, NULL, false); + PG_RE_THROW(); + } + PG_END_TRY(); + + TDSStatementEndCallback(NULL, NULL); + + /* for success, the return status is 0 */ + TdsSendReturnStatus(0); + + /* 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); +} + +static void +HandleSPCursorUnprepareRequest(TDSRequestSP req) +{ + 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); + pfree(activity); + TDSStatementBeginCallback(NULL, NULL); + + /* close the cursor */ + PG_TRY(); + { + ret = pltsql_plugin_handler_ptr->sp_cursorunprepare_callback((int)req->cursorPreparedHandle); + MemoryContextSwitchTo(MessageContext); + + if (ret > 0) + ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("sp_cursorunprepare failed: %d", ret))); + } + + PG_CATCH(); + { + TDSLogStatementCursorHandler(req, req->messageData, PRINT_CURSOR_HANDLE); + TDSStatementExceptionCallback(NULL, NULL, false); + PG_RE_THROW(); + } + PG_END_TRY(); + + TDSStatementEndCallback(NULL, NULL); + + /* for success, the return status is 0 */ + TdsSendReturnStatus(0); + + /* 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); +} + +static void +HandleSPCursorOptionRequest(TDSRequestSP req) +{ + int ret; + ParameterToken token; + int code; + int value; + + char *activity = psprintf("SP_CURSOROPTION Handle: %d", (int)req->cursorHandle); + pgstat_report_activity(STATE_RUNNING, activity); + pfree(activity); + + TDSStatementBeginCallback(NULL, NULL); + + token = req->cursorExtraArg1; + + if (token) + { + /* the token must be integer */ + Assert(token->paramMeta.metaLen == sizeof(token->paramMeta.metaEntry.type1) && + token->paramMeta.metaEntry.type1.tdsTypeId == TDS_TYPE_INTEGER); + + memcpy(&code, &req->messageData[token->dataOffset], sizeof(uint32)); + } + + token = req->cursorExtraArg2; + + if (token) + { + /* the token must be integer */ + Assert(token->paramMeta.metaLen == sizeof(token->paramMeta.metaEntry.type1) && + token->paramMeta.metaEntry.type1.tdsTypeId == TDS_TYPE_INTEGER); + + memcpy(&value, &req->messageData[token->dataOffset], sizeof(uint32)); + } + + PG_TRY(); + { + ret = pltsql_plugin_handler_ptr->sp_cursoroption_callback((int)req->cursorHandle, code, value); + MemoryContextSwitchTo(MessageContext); + + if (ret > 0) + ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("sp_cursoroption failed: %d", ret))); + } + + PG_CATCH(); + { + TDSLogStatementCursorHandler(req, req->messageData, PRINT_PREPARED_CURSOR_HANDLE); + TDSStatementExceptionCallback(NULL, NULL, false); + PG_RE_THROW(); + } + PG_END_TRY(); + + TDSStatementEndCallback(NULL, NULL); + + /* for success, the return status is 0 */ + TdsSendReturnStatus(0); + + /* 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_PREPARED_CURSOR_HANDLE); +} + +static void +HandleSPCursorRequest(TDSRequestSP req) +{ + int ret; + List *values = NIL; + int i; + ParameterToken token; + int optype; + int rownum; + + pgstat_report_activity(STATE_RUNNING, "SP_CURSOR"); + for (i = 0; i < req->nTotalBindParams; i++) + values = lappend(values, &req->boundParamsData[i]); + + TDSStatementBeginCallback(NULL, NULL); + + token = req->cursorExtraArg1; + + if (token) + { + /* the token must be integer */ + Assert(token->paramMeta.metaLen == sizeof(token->paramMeta.metaEntry.type1) && + token->paramMeta.metaEntry.type1.tdsTypeId == TDS_TYPE_INTEGER); + + memcpy(&optype, &req->messageData[token->dataOffset], sizeof(uint32)); + } + + token = req->cursorExtraArg2; + + if (token) + { + /* the token must be integer */ + Assert(token->paramMeta.metaLen == sizeof(token->paramMeta.metaEntry.type1) && + token->paramMeta.metaEntry.type1.tdsTypeId == TDS_TYPE_INTEGER); + + memcpy(&rownum, &req->messageData[token->dataOffset], sizeof(uint32)); + } + + PG_TRY(); + { + 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); + MemoryContextSwitchTo(MessageContext); + + if (ret > 0) + ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("sp_cursor failed: %d", ret))); + } + + PG_CATCH(); + { + TDSLogStatementCursorHandler(req, req->messageData, PRINT_CURSOR_HANDLE); + TDSStatementExceptionCallback(NULL, NULL, false); + PG_RE_THROW(); + } + PG_END_TRY(); + + TDSStatementEndCallback(NULL, NULL); + + /* for success, the return status is 0 */ + TdsSendReturnStatus(0); + + /* 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); +} + +TDSRequest +GetRPCRequest(StringInfo message) +{ + 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. + */ + if (tdsVersion > TDS_VERSION_7_1_1) + offset = ProcessStreamHeaders(message); + + /* Build return structure */ + 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. + */ + offset = TdsRequestCtrl->request->sp.batchSeparatorOffset; + messageLen = TdsRequestCtrl->request->sp.messageLen; + request = &TdsRequestCtrl->request->sp; + memset(request, 0, sizeof(TDSRequestSPData)); + request->messageLen = messageLen; + } + else + request = palloc0(sizeof(TDSRequestSPData)); + + 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(&request->name); + 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) + */ + if (len != 0xffff) + { + TdsUTF16toUTF8StringInfo(&request->name, &(message->data[offset]), 2 * len); + offset += 2 * len; + request->spType = SP_CUSTOMTYPE; + } + else + { + memcpy(&request->spType, &(message->data[offset]), sizeof(request->spType)); + offset += sizeof(request->spType); + } + + request->isStoredProcedure = false; + request->metaDataParameterValue = makeStringInfo(); + + memcpy(&request->spFlags, &(message->data[offset]), sizeof(request->spFlags)); + offset += sizeof(request->spFlags); + + /* + * 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*/ + InitialiseParameterToken(request); + + /* TODO: SP might need special handling, this is only for prep-exec */ + switch (request->spType) + { + case SP_CURSOROPEN: + { + 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. + */ + if (unlikely(parameterCount < 2)) + ereport(ERROR, + (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"))); + 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"))); + if (unlikely(FetchDataTypeNameFromParameter(request->parameter->next) != TDS_TYPE_NVARCHAR && + 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"))); + request->queryParameter = request->parameter->next; + + /* + * ExtraArg1 = scrollopt + * ExtraArg2 = ccopt + * ExtraArg3 = Rowcount + * dataParameter = boundparams + */ + request->cursorExtraArg1 = request->queryParameter->next; + + if (request->cursorExtraArg1) + { + request->cursorExtraArg2 = request->cursorExtraArg1->next; + + if (request->cursorExtraArg2) + { + request->cursorExtraArg3 = request->cursorExtraArg2->next; + + if (request->cursorExtraArg3->next != NULL) + { + TdsReadUnicodeDataFromTokenCommon(message->data, + request->cursorExtraArg3->next, + request->metaDataParameterValue); + request->dataParameter = request->cursorExtraArg3->next->next; + } + } + } + TDS_DEBUG(TDS_DEBUG1, "message_type: Remote Procedure Call (3) rpc_packet_type: sp_cursoropen"); + } + break; + case SP_CURSOREXEC: + { + TdsErrorContext->spType = "SP_CURSOREXEC"; + 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))); + /* + * 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"))); + 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"))); + 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"))); + request->cursorHandleParameter = request->cursorPreparedHandleParameter->next; + + if (request->cursorHandleParameter) + { + request->cursorExtraArg1 = + request->cursorHandleParameter->next; + if (request->cursorExtraArg1) + { + request->cursorExtraArg2 = + request->cursorExtraArg1->next; + if (request->cursorExtraArg2) + { + request->cursorExtraArg3 = + request->cursorExtraArg2->next; + if (request->cursorExtraArg3) + request->dataParameter = + request->cursorExtraArg3->next; + } + } + } + TDS_DEBUG(TDS_DEBUG1, "message_type: Remote Procedure Call (3) rpc_packet_type: sp_cursorexec"); + } + break; + case SP_CURSORPREPEXEC: + { + TdsErrorContext->spType = "SP_CURSORPREPEXEC"; + TDSInstrumentation(INSTR_TDS_SP_CURSOR_PREPEXEC); + + if (unlikely(parameterCount < 3)) + ereport(ERROR, + (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 + */ + + 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)) + ereport(ERROR, + (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"))); + 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. + */ + + TdsReadUnicodeDataFromTokenCommon(message->data, + 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"))); + if (unlikely(FetchDataTypeNameFromParameter(request->cursorHandleParameter->next->next) != TDS_TYPE_NVARCHAR && + 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"))); + request->queryParameter = request->cursorHandleParameter->next->next; + + if (request->queryParameter) + { + request->cursorExtraArg1 = request->queryParameter->next; + if (request->cursorExtraArg1) + { + request->cursorExtraArg2 = + request->cursorExtraArg1->next; + if (request->cursorExtraArg2) + { + request->cursorExtraArg3 = + request->cursorExtraArg2->next; + if (request->cursorExtraArg3) + request->dataParameter = + request->cursorExtraArg3->next; + } + } + } + TDS_DEBUG(TDS_DEBUG1, "message_type: Remote Procedure Call (3) rpc_packet_type: sp_cursorprepexec"); + } + break; + case SP_CURSORFETCH: + { + TdsErrorContext->spType = "SP_CURSORFETCH"; + TDSInstrumentation(INSTR_TDS_SP_CURSOR_FETCH); + if (unlikely(parameterCount < 1)) + ereport(ERROR, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("The minimum number of parameters should be %d", 1))); + + /* + * + * 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"))); + request->cursorHandleParameter = request->parameter; + + /* + * ExtraArg1 = fetch type + * ExtraArg2 = rownum + * ExtraArg3 = nrows + */ + request->cursorExtraArg1 = request->cursorHandleParameter->next; + + if (request->cursorExtraArg1) + { + request->cursorExtraArg2 = request->cursorExtraArg1->next; + + if (request->cursorExtraArg2) + request->cursorExtraArg3 = request->cursorExtraArg2->next; + } + TDS_DEBUG(TDS_DEBUG1, "message_type: Remote Procedure Call (3) rpc_packet_type: sp_cursorfetch"); + } + break; + case SP_CURSORCLOSE: + { + TdsErrorContext->spType = "SP_CURSORCLOSE"; + 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))); + + 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"))); + request->cursorHandleParameter = request->parameter; + TDS_DEBUG(TDS_DEBUG1, "message_type: Remote Procedure Call (3) rpc_packet_type: sp_cursorclose"); + } + break; + case SP_CURSORUNPREPARE: + { + TdsErrorContext->spType = "SP_CURSORUNPREPARE"; + TDSInstrumentation(INSTR_TDS_SP_CURSOR_UNPREPARE); + + if (unlikely(parameterCount < 1)) + ereport(ERROR, + (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"))); + request->cursorPreparedHandleParameter = request->parameter; + TDS_DEBUG(TDS_DEBUG1, "message_type: Remote Procedure Call (3) rpc_packet_type: sp_cursorunprepare"); + } + break; + case SP_CURSOR: + { + /* + * 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)) + 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 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"))); + + 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"))); + + /* 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)) + ereport(ERROR, + (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"))); + } + TDS_DEBUG(TDS_DEBUG1, "message_type: Remote Procedure Call (3) rpc_packet_type: sp_cursor"); + } + break; + case SP_CURSOROPTION: + { + /* + * 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)) + ereport(ERROR, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("The minimum number of parameters should be %d", 3))); + + 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"))); + 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"))); + + 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"))); + 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; + + 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)) + 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; + + 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->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"))); + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("\n Tds %s not supported yet", "SP_CURSORPREPARE"))); + } + break; + case SP_EXECUTESQL: + { + TdsErrorContext->spType = "SP_EXECUTESQL"; + if (unlikely(parameterCount < 1)) + ereport(ERROR, + (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)) + ereport(ERROR, + (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->dataParameter = + request->queryParameter->next->next; + } + TDS_DEBUG(TDS_DEBUG1, "message_type: Remote Procedure Call (3) rpc_packet_type: sp_executesql"); + } + break; + case SP_PREPARE: + { + TdsErrorContext->spType = "SP_PREPARE"; + if (unlikely(parameterCount < 2)) + ereport(ERROR, + (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"))); + 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 + */ + if (request->parameter->next && request->parameter->next->next) + { + if (request->handleParameter) + { + TdsReadUnicodeDataFromTokenCommon(message->data, + request->handleParameter->next, + request->metaDataParameterValue); + } + if (unlikely(FetchDataTypeNameFromParameter(request->parameter->next->next) != TDS_TYPE_NVARCHAR && + 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"))); + + request->queryParameter = request->parameter->next->next; + } + else + { + if (unlikely(FetchDataTypeNameFromParameter(request->parameter->next) != TDS_TYPE_NVARCHAR && + 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"))); + request->queryParameter = request->parameter->next; + } + if (request->queryParameter->next) + request->dataParameter = request->queryParameter->next; + + TDS_DEBUG(TDS_DEBUG1, "message_type: Remote Procedure Call (3) rpc_packet_type: sp_prepare"); + } + break; + case SP_EXECUTE: + { + TdsErrorContext->spType = "SP_EXECUTE"; + if (unlikely(parameterCount < 1)) + ereport(ERROR, + (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"))); + + request->handleParameter = request->parameter; + + if (request->parameter->next) + request->dataParameter = request->parameter->next; + TDS_DEBUG(TDS_DEBUG1, "message_type: Remote Procedure Call (3) rpc_packet_type: sp_execute"); + } + break; + case SP_PREPEXEC: + { + TdsErrorContext->spType = "SP_PREPEXEC"; + if (unlikely(parameterCount < 2)) + ereport(ERROR, + (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"))); + 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 + */ + if (request->parameter->next && + request->parameter->next->next) + { + if (request->handleParameter) + { + TdsReadUnicodeDataFromTokenCommon(message->data, + request->handleParameter->next, + request->metaDataParameterValue); + } + if (unlikely(FetchDataTypeNameFromParameter(request->parameter->next->next) != TDS_TYPE_NVARCHAR && + 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"))); + request->queryParameter = + request->parameter->next->next; + } + else + { + if (unlikely(FetchDataTypeNameFromParameter(request->parameter->next) != TDS_TYPE_NVARCHAR && + 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"))); + request->queryParameter = request->parameter->next; + } + if (request->queryParameter->next) + request->dataParameter = request->queryParameter->next; + TDS_DEBUG(TDS_DEBUG1, "message_type: Remote Procedure Call (3) rpc_packet_type: sp_prepexec"); + } + break; + case SP_PREPEXECRPC: + { + TdsErrorContext->spType = "SP_PREPEXECRPC"; + /* Not supported yet */ + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("SP_PREPEXECRPC not supported yet"))); + } + break; + case SP_UNPREPARE: + { + TdsErrorContext->spType = "SP_UNPREPARE"; + if (unlikely(parameterCount < 1)) + ereport(ERROR, + (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"); + } + break; + case SP_CUSTOMTYPE: + { + TdsErrorContext->spType = "SP_CUSTOMTYPE"; + request->dataParameter = request->parameter; + TDS_DEBUG(TDS_DEBUG1, "message_type: Remote Procedure Call (3) rpc_packet_type: user defined procedure"); + } + break; + default: + 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."))); + } + + /* initialize the IN/OUT parameter index array */ + InitializeDataParamTokenIndex(request); + + /* get the SP handle */ + GetSPHandleParameter(request); + + /* get the SP cursor handle */ + GetSPCursorHandleParameter(request); + + /* get the SP cursor Prepared handle */ + GetSPCursorPreparedHandleParameter(request); + + return (TDSRequest)request; +} + +void +RestoreRPCBatch(StringInfo message, uint8_t *status, uint8_t *messageType) +{ + /* Restore the common Packet for the Batch. */ + Assert(TdsRequestCtrl->request->reqType == TDS_REQUEST_SP_NUMBER); + 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. */ + *status = TdsRequestCtrl->status; +} + +void +ProcessRPCRequest(TDSRequest request) +{ + TDSRequestSP req; + + req = (TDSRequestSP) request; + + switch(req->spType) + { + case SP_CURSOR: + GenerateBindParamsData(req); + HandleSPCursorRequest(req); + break; + case SP_CURSOROPEN: + case SP_CURSORPREPARE: + case SP_CURSORPREPEXEC: + case SP_CURSOREXEC: + GenerateBindParamsData(req); + HandleSPCursorOpenCommon(req); + break; + case SP_CURSORFETCH: + HandleSPCursorFetchRequest(req); + break; + case SP_CURSORCLOSE: + HandleSPCursorCloseRequest(req); + break; + case SP_CURSORUNPREPARE: + HandleSPCursorUnprepareRequest(req); + break; + case SP_CURSOROPTION: + HandleSPCursorOptionRequest(req); + break; + case SP_PREPARE: + SPPrepare(req); + break; + case SP_PREPEXECRPC: + Assert(0); + break; + case SP_PREPEXEC: + SPPrepExec(req); + break; + case SP_EXECUTE: + SPExecute(req); + break; + case SP_EXECUTESQL: + SPExecuteSQL(req); + break; + case SP_CUSTOMTYPE: + SPCustomType(req); + break; + case SP_UNPREPARE: + SPUnprepare(req); + break; + } +} + +/* + * TdsIsSPPrepare - Returns true if sp_prepare packet is being processed + */ +bool +TdsIsSPPrepare() +{ + TDSRequestSP req; + req = (TDSRequestSP) TdsRequestCtrl->request; + if (req->spType == SP_PREPARE) + return true; + return false; +} + +/* + * TdsFetchInParamValues - fetch the IN parameters from TDS message buffer + * + * params - (OUT argument) store the actual Datums + * + * It's the responsibility of the caller allocate memory for the same. + * + * Also note that we send the OUT parameters as INOUT parameters. The TDS + * protocol sends the value of these parameters as NULL. So, we're going to + * bind NULL as values for these paramters. + */ +void +TdsFetchInParamValues(ParamListInfo params) +{ + ParameterToken token; + TDSRequest request = TdsRequestCtrl->request; + TDSRequestSP req; + int paramno = 0; + + Assert(params != NULL); + + Assert(request->reqType == TDS_REQUEST_SP_NUMBER); + req = (TDSRequestSP) request; + + for (token = req->dataParameter; token != NULL; token = token->next, paramno++) + { + Oid ptype; + Datum pval; + bool isNull; + TdsIoFunctionInfo tempFuncInfo; + + tempFuncInfo = TdsLookupTypeFunctionsByTdsId(token->type, token->maxLen); + isNull = token->isNull; + + ptype = token->paramMeta.pgTypeOid; + + if (!isNull && token->type != TDS_TYPE_TABLE) + pval = tempFuncInfo->recvFuncPtr(req->messageData, token); + else if (token->type == TDS_TYPE_TABLE) + pval = (Datum) token->tvpInfo->tvpTypeName; + else + pval = (Datum) 0; + + params->params[paramno].value = pval; + params->params[paramno].isnull = isNull; + + /* + * We mark the params as CONST. This ensures that any custom plan + * makes full use of the parameter values. + */ + params->params[paramno].pflags = PARAM_FLAG_CONST; + params->params[paramno].ptype = ptype; + } +} + +/* + * In case of SP or prep-exec, parameter names are optional. + * If client applications doesn't specify the parameter name then internally + * driver sends the default parameter name with query text. + * For ex: insert into tablenm values (@P0). + * + * Engine needs the parameter index to store the values appropriately. + * For example: index 1 for @P0, index 2 for @P1 + * + * TdsGetAndSetParamIndex function acts as a reference counter to send the + * paramter Index starting from 1 for valid param. + * For anything else, return 0. + * + * Assumption: + * 1. Parameter values will always be in the serial order in case of SP_[CURSOR]EXEC + * 2. Valid Parameter names will always start from @P + */ +int +TdsGetAndSetParamIndex(const char *name) +{ + TDSRequestSP req; + + if ((TdsRequestCtrl == NULL) || (TdsRequestCtrl->request == NULL) + || (TdsRequestCtrl->request->reqType != TDS_REQUEST_SP_NUMBER)) + { + return 0; + } + + /* + * Default parameters should always start from @P + */ + if (strlen(name) < 3 || name[0] != '@') + { + return 0; + } + + req = (TDSRequestSP) TdsRequestCtrl->request; + /* + * 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 ptr; + int qlen = strlen(source); + int nlen = strlen(name); + while (temp < qlen) + { + int j; + + /* + * If param names are not given by the application, then driver + * default params names always start with "@P" + */ + pos = strstr(source, "@P"); + + /* + * If parameter names don't match, return 0 + */ + if (pos == NULL) + { + return 0; + } + ptr = pos - source; + 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) + */ + if (tolower(source[j]) != tolower(name[j - ptr])) + { + break; + } + } + /* + * If no characters match, then return 0 + */ + if (j == ptr) + { + return 0; + } + + if (j == ptr + nlen) + return i + 1; + + temp = j; + source = &source[temp]; + i++; + } + return 0; + } + + /* + * 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. + * + * 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. + */ + Assert(req->spType == SP_EXECUTE || + req->spType == SP_CURSOREXEC); + + return ++(req->paramIndex); +} + +/* + * TdsGetParamNames - fetch TDS IN/OUT parameter names + * + * We'll follow the same IN/OUT parameter order in which we've received. Also, + * we're allocating the memory in callers memory context. So, it's + * responsibility of the caller to perform cleanups. + */ +bool +TdsGetParamNames(List **pnames) +{ + TDSRequest request; + TDSRequestSP req; + ParameterToken token; + + if ((TdsRequestCtrl == NULL) || (TdsRequestCtrl->request == NULL) + || (TdsRequestCtrl->request->reqType != TDS_REQUEST_SP_NUMBER)) + return false; + + request = TdsRequestCtrl->request; + req = (TDSRequestSP) request; + + if (req->spType == SP_EXECUTESQL + || req->spType == SP_PREPARE + || req->spType == SP_PREPEXEC + || req->spType == SP_EXECUTE) + return false; + + if (req->spType == SP_CUSTOMTYPE) + return false; + + if (req->nTotalParams == 0) + return false; + + for (token = req->dataParameter; token != NULL; token = token->next) + { + 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. + */ + if (name->len == 0) + return true; + + item->name = pnstrdup(name->data, strlen(name->data)); + item->type = (token->flags == 0) ? 0 : 1; + + *pnames = lappend(*pnames, item); + } + + return true; +} + +/* + * TDS function to log statement duration related info + */ +void +TDSLogDuration(char *query) +{ + char msec_str[32]; + + switch (check_log_duration(msec_str, false)) + { + case 1: + ereport(LOG, (errmsg("Query duration: %s ms", msec_str), + errhidestmt(true))); + break; + case 2: + ereport(LOG, (errmsg("Query: %s duration: %s ms", + query, msec_str), errhidestmt(true))); + break; + default: + break; + } + return; +} + +/* + * TDS function to log statement handler and duration detail for cursor + */ +static void +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))); + 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))); + 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))); + break; + default: + break; + } + + 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 new file mode 100644 index 00000000000..a8cdb028754 --- /dev/null +++ b/contrib/babelfishpg_tds/src/backend/tds/tdssecure.c @@ -0,0 +1,411 @@ +/*------------------------------------------------------------------------- + * + * tdssecure.c + * TDS Listener TLS connection code + * + * Portions Copyright (c) 2020, AWS + * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * contrib/babelfishpg_tds/src/backend/tds/tdssecure.c + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include +#include +#include +#include +#include +#include +#ifdef HAVE_NETINET_TCP_H +#include +#include +#endif + +#include "libpq/libpq.h" +#include "miscadmin.h" +#include "pgstat.h" +#include "tcop/tcopprot.h" +#include "utils/memutils.h" +#include "storage/ipc.h" +#include "storage/proc.h" + +#include "src/include/tds_secure.h" +#include "src/include/tds_int.h" + +int tds_ssl_min_protocol_version; +int tds_ssl_max_protocol_version; +#ifdef USE_SSL +/* + * SslRead - TDS secure read function, similar to my_sock_read + */ +static int +SslRead(BIO *h, char *buf, int size) +{ + int res = 0; + + if (buf != NULL) + { + res = secure_raw_read(((Port *) BIO_get_data(h)), buf, size); + BIO_clear_retry_flags(h); + if (res <= 0) + { + /* If we were interrupted, tell caller to retry */ + if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) + { + BIO_set_retry_read(h); + } + } + } + + return res; +} + +/* + * 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 + */ +static int +SslHandShakeRead(BIO *h, char *buf, int size) +{ + int res = 0; + + res = SslRead(h, buf, size); + + /* very first packet of prelogin SSL handshake */ + if (size > 0 && res > 0 && buf[0] == TDS_PRELOGIN) + { + + if (res < TDS_PACKET_HEADER_SIZE) + { + int remainingRead = TDS_PACKET_HEADER_SIZE - res; + char tempBuf[TDS_PACKET_HEADER_SIZE]; + res = 0; + + /* Read the complete remaining of the header and throw away the bytes */ + while(res < remainingRead) + { + res += secure_raw_read(((Port *) BIO_get_data(h)), tempBuf, + remainingRead - 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 + */ + res = secure_raw_read(((Port *) BIO_get_data(h)), buf, size); + } + else + { + 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; + + /* + * 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 + */ + + res += SslRead(h, &buf[res], TDS_PACKET_HEADER_SIZE); + } + } + + return res; +} + +/* + * SslWrite - Tds secure write function, similar to my_sock_write. + */ +static int +SslWrite(BIO *h, const char *buf, int size) +{ + int res = 0; + + res = secure_raw_write(((Port *) BIO_get_data(h)), buf, size); + BIO_clear_retry_flags(h); + if (res <= 0) + { + /* If we were interrupted, tell caller to retry */ + if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) + { + BIO_set_retry_write(h); + } + } + + return res; +} + +/* + * TdsSshHandShakeWrite - Tds secure write function, similar to my_sock_write. + * During the initial handshake add the 8 bytes header to the final data which + * is sent to client + */ +static int +SslHandShakeWrite(BIO *h, const char *buf, int size) +{ + StringInfoData str; + char tmp[2]; + uint16_t tsize; + int res = 0; + + /* Nothing to write */ + if (size < 0) + return size; + + initStringInfo(&str); + appendStringInfoChar(&str, TDS_PRELOGIN); + appendStringInfoChar(&str, TDS_PACKET_HEADER_STATUS_EOM); + tsize = pg_hton16(size + TDS_PACKET_HEADER_SIZE); + memcpy(&tmp,(char *) &tsize, 2); + + appendStringInfoChar(&str, tmp[0]); + appendStringInfoChar(&str, tmp[1]); + appendStringInfoChar(&str, 0x00); + appendStringInfoChar(&str, 0x00); + appendStringInfoChar(&str, 0x00); + appendStringInfoChar(&str, 0x00); + + appendBinaryStringInfo(&str, buf, size); + buf = str.data; + size += TDS_PACKET_HEADER_SIZE; + + /* Write the complete data */ + while (res < size) + { + res += SslWrite(h, &buf[res], size - res); + } + + return res; +} + +/* + * TdsBioSecureSocket - Similar to my_BIO_s_socket + * Used to setup, TDS listener read and write API + * for the initial SSL handshake + */ +BIO_METHOD * +TdsBioSecureSocket(BIO_METHOD *my_bio_methods) +{ + if (my_bio_methods == NULL) + { + BIO_METHOD *biom = (BIO_METHOD *) BIO_s_socket(); +#ifdef HAVE_BIO_METH_NEW + int my_bio_index; + + my_bio_index = BIO_get_new_index(); + if (my_bio_index == -1) + return NULL; + my_bio_methods = BIO_meth_new(my_bio_index, "PostgreSQL backend socket"); + if (!my_bio_methods) + return NULL; + if (!BIO_meth_set_write(my_bio_methods, SslHandShakeWrite) || + !BIO_meth_set_read(my_bio_methods, SslHandShakeRead) || + !BIO_meth_set_gets(my_bio_methods, BIO_meth_get_gets(biom)) || + !BIO_meth_set_puts(my_bio_methods, BIO_meth_get_puts(biom)) || + !BIO_meth_set_ctrl(my_bio_methods, BIO_meth_get_ctrl(biom)) || + !BIO_meth_set_create(my_bio_methods, BIO_meth_get_create(biom)) || + !BIO_meth_set_destroy(my_bio_methods, BIO_meth_get_destroy(biom)) || + !BIO_meth_set_callback_ctrl(my_bio_methods, BIO_meth_get_callback_ctrl(biom))) + { + BIO_meth_free(my_bio_methods); + my_bio_methods = NULL; + return NULL; + } +#else +#ifdef USE_SSL + my_bio_methods = malloc(sizeof(BIO_METHOD)); + if (!my_bio_methods) + return NULL; + memcpy(my_bio_methods, biom, sizeof(BIO_METHOD)); + my_bio_methods->bread = SslHandShakeRead; + my_bio_methods->bwrite = SslHandShakeWrite; +#endif +#endif + } + return my_bio_methods; +} +#endif + +/* + * Frees the strcture for the SSL + */ +void +TdsFreeSslStruct(Port *port) +{ +#ifdef USE_SSL + if (port->ssl) + { + /* + * Don't call the SSL_shutdown - + * since it shutdowns the connection + */ + SSL_free(port->ssl); + port->ssl = NULL; + port->ssl_in_use = false; + } +#endif +} + +/* + * Read data from a secure connection. + */ +ssize_t +tds_secure_read(Port *port, void *ptr, size_t len) +{ + ssize_t n; + int waitfor; + + /* Deal with any already-pending interrupt condition. */ + ProcessClientReadInterrupt(false); + +retry: +#ifdef USE_SSL + waitfor = 0; + if (port->ssl_in_use) + { + /* TDS specific TLS read */ + n = Tds_be_tls_read(port, ptr, len, &waitfor); + } + else +#endif + { + n = secure_raw_read(port, ptr, len); + waitfor = WL_SOCKET_READABLE; + } + + /* In blocking mode, wait until the socket is ready */ + if (n < 0 && !port->noblock && (errno == EWOULDBLOCK || errno == EAGAIN)) + { + WaitEvent event; + + Assert(waitfor); + + ModifyWaitEvent(FeBeWaitSet, 0, waitfor, NULL); + + WaitEventSetWait(FeBeWaitSet, -1 /* no timeout */ , &event, 1, + WAIT_EVENT_CLIENT_READ); + + /* + * If the postmaster has died, it's not safe to continue running, + * because it is the postmaster's job to kill us if some other backend + * exists uncleanly. Moreover, we won't run very well in this state; + * helper processes like walwriter and the bgwriter will exit, so + * performance may be poor. Finally, if we don't exit, pg_ctl will be + * unable to restart the postmaster without manual intervention, so no + * new connections can be accepted. Exiting clears the deck for a + * postmaster restart. + * + * (Note that we only make this check when we would otherwise sleep on + * our latch. We might still continue running for a while if the + * postmaster is killed in mid-query, or even through multiple queries + * if we never have to wait for read. We don't want to burn too many + * cycles checking for this very rare condition, and this should cause + * us to exit quickly in most cases.) + */ + if (event.events & WL_POSTMASTER_DEATH) + ereport(FATAL, + (errcode(ERRCODE_ADMIN_SHUTDOWN), + errmsg("terminating connection due to unexpected postmaster exit"))); + + /* Handle interrupt. */ + if (event.events & WL_LATCH_SET) + { + ResetLatch(MyLatch); + ProcessClientReadInterrupt(true); + + /* + * We'll retry the read. Most likely it will return immediately + * because there's still no data available, and we'll wait for the + * socket to become ready again. + */ + } + goto retry; + } + + /* + * Process interrupts that happened during a successful (or non-blocking, + * or hard-failed) read. + */ + ProcessClientReadInterrupt(false); + + return n; +} + +/* + * Write data to a secure connection. + */ +ssize_t +tds_secure_write(Port *port, void *ptr, size_t len) +{ + ssize_t n; + int waitfor; + + /* Deal with any already-pending interrupt condition. */ + ProcessClientWriteInterrupt(false); + +retry: + waitfor = 0; +#ifdef USE_SSL + if (port->ssl_in_use) + { + /* TDS specific SSL write */ + n = Tds_be_tls_write(port, ptr, len, &waitfor); + } + else +#endif + { + n = secure_raw_write(port, ptr, len); + waitfor = WL_SOCKET_WRITEABLE; + } + + if (n < 0 && !port->noblock && (errno == EWOULDBLOCK || errno == EAGAIN)) + { + WaitEvent event; + + Assert(waitfor); + + ModifyWaitEvent(FeBeWaitSet, 0, waitfor, NULL); + + WaitEventSetWait(FeBeWaitSet, -1 /* no timeout */ , &event, 1, + WAIT_EVENT_CLIENT_WRITE); + + /* See comments in secure_read. */ + if (event.events & WL_POSTMASTER_DEATH) + ereport(FATAL, + (errcode(ERRCODE_ADMIN_SHUTDOWN), + errmsg("terminating connection due to unexpected postmaster exit"))); + + /* Handle interrupt. */ + if (event.events & WL_LATCH_SET) + { + ResetLatch(MyLatch); + ProcessClientWriteInterrupt(true); + + /* + * We'll retry the write. Most likely it will return immediately + * because there's still no buffer space available, and we'll wait + * for the socket to become ready again. + */ + } + goto retry; + } + + /* + * Process interrupts that happened during a successful (or non-blocking, + * or hard-failed) write. + */ + ProcessClientWriteInterrupt(false); + + return n; +} diff --git a/contrib/babelfishpg_tds/src/backend/tds/tdssqlbatch.c b/contrib/babelfishpg_tds/src/backend/tds/tdssqlbatch.c new file mode 100644 index 00000000000..49f61da9a07 --- /dev/null +++ b/contrib/babelfishpg_tds/src/backend/tds/tdssqlbatch.c @@ -0,0 +1,139 @@ +/*------------------------------------------------------------------------- + * + * tdssqlbatch.c + * TDS Listener functions for handling SQL Batch requests + * + * Portions Copyright (c) 2020, AWS + * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * contrib/babelfishpg_tds/src/backend/tds/tdssqlbatch.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "access/htup_details.h" +#include "access/printtup.h" +#include "access/xact.h" +#include "mb/pg_wchar.h" +#include "miscadmin.h" +#include "nodes/parsenodes.h" +#include "pgstat.h" +#include "tcop/tcopprot.h" + +#include "src/include/tds_int.h" +#include "src/include/tds_protocol.h" +#include "src/include/tds_request.h" +#include "src/include/tds_response.h" + +TDSRequest +GetSQLBatchRequest(StringInfo message) +{ + 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. + */ + if (tdsVersion > TDS_VERSION_7_1_1) + query_offset = ProcessStreamHeaders(message); + query_len = message->len - query_offset; + + /* Build return structure */ + request = palloc0(sizeof(TDSRequestSQLBatchData)); + request->reqType = TDS_REQUEST_SQL_BATCH; + + initStringInfo(&(request->query)); + + TdsUTF16toUTF8StringInfo(&(request->query), + &(message->data[query_offset]), + query_len); + + return (TDSRequest)request; +} + +/* + * Helper function to execute a SQL Batch + * query using pltsql inline handler + */ +void +ExecuteSQLBatch(char *query) +{ + LOCAL_FCINFO(fcinfo,1); + InlineCodeBlock *codeblock = makeNode(InlineCodeBlock); + char *activity = psprintf("SQL_BATCH: %s", query); + + TdsErrorContext->err_text = "Processing SQL Batch Request"; + pgstat_report_activity(STATE_RUNNING, activity); + pfree(activity); + + /* Only source text matters to handler */ + codeblock->source_text = query; + codeblock->langOid = 0; /* TODO does it matter */ + codeblock->langIsTrusted = true; + codeblock->atomic = false; + + /* Just to satisfy argument requirement */ + MemSet(fcinfo, 0, SizeForFunctionCallInfo(1)); + fcinfo->args[0].value = PointerGetDatum(codeblock); + fcinfo->args[0].isnull = false; + PG_TRY(); + { + pltsql_plugin_handler_ptr->sql_batch_callback (fcinfo); + } + PG_CATCH(); + { + if (TDS_DEBUG_ENABLED(TDS_DEBUG2)) + ereport(LOG, + (errmsg("sql_batch statement: %s", query), + errhidestmt(true))); + + PG_RE_THROW(); + } + PG_END_TRY(); + + /* + * Log immediately if dictated by log_statement + */ + 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), + errhidestmt(true))); + pltsql_plugin_handler_ptr->stmt_needs_logging = false; + error_context_stack = plerrcontext; + } + + /* + * Print TDS log duration, if log_duration is set + */ + TDSLogDuration(query); + +} + +/* + * SQL batch requests directly go to pltsql + * inline block handler + */ +void +ProcessSQLBatchRequest(TDSRequest request) +{ + TDSRequestSQLBatch req = (TDSRequestSQLBatch)request; + + ExecuteSQLBatch(req->query.data); + MemoryContextSwitchTo(MessageContext); + + /* If there was an empty query, send a done token */ + if (TdsRequestCtrl->isEmptyResponse) + TdsSendDone(TDS_TOKEN_DONE, TDS_DONE_FINAL, 0xfd, 0); +} diff --git a/contrib/babelfishpg_tds/src/backend/tds/tdstimestamp.c b/contrib/babelfishpg_tds/src/backend/tds/tdstimestamp.c new file mode 100644 index 00000000000..63bce51be50 --- /dev/null +++ b/contrib/babelfishpg_tds/src/backend/tds/tdstimestamp.c @@ -0,0 +1,473 @@ +/*------------------------------------------------------------------------- + * + * tdstimestamp.c + * Handler functions for TDS timestamp datatype + * + * Portions Copyright (c) 2020, AWS + * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * contrib/babelfishpg_tds/src/backend/tds/tdstimestamp.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "utils/datetime.h" + +#include "src/include/tds_timestamp.h" + +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; + + 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"))); +} + +static inline int +CountLeapYears(struct pg_tm *t) +{ + int years = t->tm_year; + if (t->tm_mon <= 2) + years--; + + return years / 4 - years / 100 + years / 400; +} + +static inline int +GetDayDifference(struct pg_tm *t1, struct pg_tm *t2) +{ + long int n1, n2; + int i; + + n1 = t1->tm_year * 365 + t1->tm_mday; + for (i = 0; i < t1->tm_mon - 1; i++) + n1 += DaycountInMonth[i]; + n1 += CountLeapYears(t1); + + n2 = t2->tm_year * 365 + t2->tm_mday; + for (i = 0; i < t2->tm_mon - 1; i++) + n2 += DaycountInMonth[i]; + n2 += CountLeapYears(t2); + + return (n2 - n1); +} + +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; + tt->tm_mday = 1, tt->tm_mon = 1; + if (isDateType) + tt->tm_year = 1; + else + tt->tm_year = 1900; + numDays = GetDayDifference(tt, tm); + return numDays; +} + +static inline void +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)); + } + else + ereport(ERROR, + (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; + + 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"))); +} + +/* + * Get numDays elapsed between client date and 1-1-0001 + */ +uint32 +TdsDayDifference(Datum value) +{ + uint32 numDays = 0; + struct pg_tm tj, ti, *tm = &ti, *tt = &tj; + + GetDateFromDatum(value, tm); + + tt->tm_mday = 1, tt->tm_mon = 1, tt->tm_year = 1; + numDays = GetDayDifference(tt, tm); + return numDays; +} + +/* + * Decides whether the effective date to consider is the next day + * based on hour, minute, second value 23:59:59 + */ +static inline void +GetNumDaysHelper(struct pg_tm *tm) +{ + tm->tm_hour = tm->tm_min = tm->tm_sec = 0; + if (tm->tm_mday == DaycountInMonth[tm->tm_mon - 1] && + tm->tm_mon == 12) + { + tm->tm_year++; + 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++; + tm->tm_mday = 1; + } + else + tm->tm_mday++; +} + +/* + * Returns numDays and numTicks elapsed between given date + * and 1-1-1900 + */ +void +TdsTimeDifferenceSmalldatetime(Datum value, uint16 *numDays, + uint16 *numMins) +{ + 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); + + if (tm->tm_hour == 23 && tm->tm_min == 59 && tm->tm_sec == 59) + { + fsec = 0; + GetNumDaysHelper(tm); + (*numDays)++; + } + 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; +} + +/* + * Returns numDays and numTicks elapsed between given date + * and 1-1-1900 + */ +void +TdsTimeDifferenceDatetime(Datum value, uint32 *numDays, + uint32 *numTicks) +{ + uint32 milliCount = 0; + struct pg_tm tj, ti, *tm = &ti, *tt = &tj; + fsec_t fsec; + int unit = 0; + + 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 && + fsec == 999000) + { + fsec = 0; + GetNumDaysHelper(tm); + (*numDays)++; + } + else + { + unit = (fsec/1000) % 10; + if (unit == 1 || unit == 4 || unit == 8) + fsec = ((fsec/1000)-1) * 1000; + else if (unit == 2 || unit == 6 || unit == 9) + fsec = ((fsec/1000)+1) * 1000; + else if (unit == 5) + fsec = ((fsec/1000)+2) * 1000; + } + milliCount = (((tm->tm_hour * 60 + tm->tm_min) * 60 + + tm->tm_sec) * 1000 + (int)fsec/1000); + + *numTicks = (int)(milliCount/3.3333333); +} + +/* + * Given a year and days elapsed in it, outputs month and + * day of the date found by adding offset #days to day1 + */ +static inline +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++) + { + if (offset <= month[i]) + break; + offset = offset - month[i]; + } + *d = offset; + *m = i; +} + +/* + * Adds x days to specific start date(1.1.0001 or 1.1.1900) in order to + * retrieve target client date + */ +static inline +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 offset2; + if (x <= remDays) + { + *y2 = y1; + offset2 = offset1 + x; + } + else + { + x -= remDays; + *y2 = y1 + 1; + y2days = IsLeap(*y2)?366:365; + while (x >= y2days) + { + x -= y2days; + (*y2)++; + y2days = IsLeap(*y2)?366:365; + } + offset2 = x; + } + + RevoffsetDays(offset2, y2, d2, m2); +} + +/* + * Get date info(day, month, year) from numDays elapsed from + * 1-1-0001. + */ +void +TdsTimeGetDatumFromDays(uint32 numDays, uint64 *val) +{ + 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; + tm->tm_mon = m2; + tm->tm_year = y2; + + res = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday); + res -= POSTGRES_EPOCH_JDATE; + *val = (uint64)res; +} + +/* + * Get date info(day, month, year) from numDays elapsed from + * 1-1-1900. + * Get time info from number of ticks (milliseconds/3.33333333) + * elapsed. + */ +static inline +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; + + CalculateTargetDate(y1, &d2, &m2, &y2, numDays); + + numMilli = 3.33333333 * numTicks; + *fsec = (numMilli % 1000) * 1000; + numMilli /= 1000; + + /* need explicit assignment for JDBC prep-exec query + * where time datatype is sent as datetime in case + * sendTimeAsDateTime parameter is not explicitly set + * to false + */ + if (*fsec == 999000) + { + numMilli++; + *fsec = 0; + } + + sec = numMilli % 60; + numMilli /= 60; + min = numMilli % 60; + numMilli /= 60; + hour = numMilli; + + tm->tm_mday = d2; + tm->tm_mon = m2; + tm->tm_year = y2; + tm->tm_hour = hour; + tm->tm_min = min; + tm->tm_sec = sec; +} + +/* + * Get hour, min, sec, millisecond, date info from numDays elapsed from 1-1-1900 and + * numTicks (= numMilliSecond / 3.3333333) elapsed from 12AM of that day. + * Also, do necessary millisecond adjustment before storing client datetime in system. + * Ex.- 1955-12-13 23:59:59.999 is stored as 1955-12-14 0:0:0.0 + */ +void +TdsTimeGetDatumFromDatetime(uint32 numDays, uint32 numTicks, + Timestamp *timestamp) +{ + 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"))); +} + +static inline +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; + + CalculateTargetDate(y1, &d2, &m2, &y2, numDays); + + min = numMins % 60; + numMins /= 60; + hour = numMins; + + tm->tm_mday = d2; + tm->tm_mon = m2; + tm->tm_year = y2; + tm->tm_hour = hour; + tm->tm_min = min; +} + +/* + * Get hour, min, date info from numDays elapsed from 1-1-1900 + */ +void +TdsTimeGetDatumFromSmalldatetime(uint16 numDays, uint16 numMins, + Timestamp *timestamp) +{ + 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"))); +} + +void +TdsGetDayTimeFromTimestamp(Timestamp value, uint32 *numDays, uint64 *numSec, + int scale) +{ + 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"))); + + tt->tm_mday = 1, tt->tm_mon = 1, tt->tm_year = 1; + *numDays = (uint32)GetDayDifference(tt, tm); + + res = (double)(((tm->tm_hour * 60 + tm->tm_min) * 60 + tm->tm_sec) + + ((double)fsec/ 1000000)); + while (scale--) + res *= 10; + + *numSec = (uint64_t)res; +} + +void TdsGetTimestampFromDayTime(uint32 numDays, uint64 numMicro, int tz, + Timestamp *timestamp, int scale) +{ + struct pg_tm ti, *tm = &ti; + fsec_t fsec; + int y1 = 1; + int d2 = 0, m2 = 0, y2 = 0, min, hour, sec; + double result; + + CalculateTargetDate(y1, &d2, &m2, &y2, numDays); + + 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. + */ + numMicro = (result - (uint64_t)result <= 0.5) ? (uint64_t)result : (uint64_t)result + 1; + + fsec = numMicro % 1000000; + numMicro /= 1000000; + sec = numMicro % 60; + numMicro /= 60; + min = numMicro % 60; + numMicro /= 60; + hour = numMicro; + + tm->tm_mday = d2; + tm->tm_mon = m2; + tm->tm_year = y2; + tm->tm_hour = hour; + tm->tm_min = min; + tm->tm_sec = sec; + + if (tm2timestamp(tm, fsec, &tz, timestamp) != 0) + ereport(ERROR, + (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 new file mode 100644 index 00000000000..9e62027c137 --- /dev/null +++ b/contrib/babelfishpg_tds/src/backend/tds/tdstypeio.c @@ -0,0 +1,3561 @@ +/*------------------------------------------------------------------------- + * + * tdstypeio.c + * TDS Listener functions for PG-Datum <-> TDS-protocol conversion + * + * Portions Copyright (c) 2020, AWS + * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * contrib/babelfishpg_tds/src/backend/tds/tdstypeio.c + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "access/htup_details.h" +#include "access/xact.h" +#include "catalog/pg_authid.h" +#include "catalog/pg_type.h" +#include "catalog/pg_namespace.h" +#include "executor/spi.h" +#include "fmgr.h" +#include "mb/pg_wchar.h" +#include "miscadmin.h" +#include "parser/scansup.h" +#include "utils/cash.h" +#include "utils/hsearch.h" +#include "utils/builtins.h" /* for format_type_be() */ +#include "utils/guc.h" +#include "utils/lsyscache.h" /* for getTypeInputInfo() and OidInputFunctionCall()*/ +#include "utils/numeric.h" +#include "utils/snapmgr.h" +#include "utils/syscache.h" +#include "utils/uuid.h" +#include "utils/varlena.h" +#include "utils/xml.h" + +#include "src/include/tds_int.h" +#include "src/include/tds_timestamp.h" +#include "src/include/tds_typeio.h" +#include "src/include/err_handler.h" +#include "src/include/tds_instr.h" + +#include "tds_data_map.c" /* include tables that used to initialize hashmaps */ + +#define TDS_RETURN_DATUM(x) return ((Datum) (x)) + +#define VARCHAR_MAX 2147483647 + +#define GetPgOid(pgTypeOid, finfo) \ +do { \ + pgTypeOid = (finfo->ttmbasetypeid != InvalidOid) ? \ + finfo->ttmbasetypeid : finfo->ttmtypeid; \ +} while(0); + +static HTAB *functionInfoCacheByOid = NULL; +static HTAB *functionInfoCacheByTdsId = NULL; + +static HTAB *TdsEncodingInfoCacheByLCID = NULL; + +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); +static void SwapData(StringInfo buf, int st, int end); +static Datum TdsAnyToServerEncodingConversion(Oid oid, pg_enc enc, char *str, int len); +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, Oid pgTypeOid, uint32_t collation); +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); + +/* Local structures for the Function Cache by TDS Type ID */ +typedef struct FunctionCacheByTdsIdKey +{ + int32_t tdstypeid; + int32_t tdstypelen; +} FunctionCacheByTdsIdKey; + +typedef struct FunctionCacheByTdsIdEntry +{ + FunctionCacheByTdsIdKey key; + TdsIoFunctionData data; +} FunctionCacheByTdsIdEntry; + +/* + * getSendFunc - get the function pointer for type output + * + * Given the ttmsendfunc id returns the function pointer for the + * corresponding output function to call. + */ +static inline TdsSendTypeFunction +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; + } +} + +/* + * TdsRecvTypeFunction - get the function pointer for type input + * + * Given the ttmsendfunc id returns the function pointer for the + * corresponding input function to call. + */ +static inline TdsRecvTypeFunction +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; + } +} + +#ifdef USE_LIBXML + +static int +xmlChar_to_encoding(const xmlChar *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))); + return encoding; +} +#endif + +int TdsUTF16toUTF8XmlResult(StringInfo buf, void **resultPtr) +{ + char *str; + int nbytes; + StringInfoData tempBuf; + void *result; + + initStringInfo(&tempBuf); + enlargeStringInfo(&tempBuf, buf->len); + TdsUTF16toUTF8StringInfo(&tempBuf, buf->data, buf->len); + buf = &tempBuf; + + nbytes = buf->len - buf->cursor; + + str = (char *)GetMsgBytes(buf, nbytes); + + result = palloc0(nbytes + 1 + VARHDRSZ); + SET_VARSIZE(result, nbytes + VARHDRSZ); + memcpy(VARDATA(result), str, nbytes); + str = VARDATA(result); + str[nbytes] = '\0'; + + *resultPtr = result; + + return PG_UTF8; +} + +/* + * TdsAnyToServerEncodingConversion - lookup the PG Encoding based on lcid + * and convert the encoding of input str + */ +static Datum +TdsAnyToServerEncodingConversion(Oid oid, pg_enc enc, char *str, int len) +{ + Oid typinput; + Oid typioparam; + char *pstring; + Datum pval; + + getTypeInputInfo(oid, &typinput, &typioparam); + pstring = pg_any_to_server(str, len, enc); + pval = OidInputFunctionCall(typinput, pstring, typioparam, -1); + + /* Free result of encoding conversion, if any */ + if (pstring && pstring != str) + pfree(pstring); + + return pval; +} + +/* + * TdsResetTypeFunctionCache - reset the type function caches. + * + * During connection reset, this is used. + */ +void +TdsResetCache(void) +{ + functionInfoCacheByOid = NULL; + functionInfoCacheByTdsId = NULL; + TdsEncodingInfoCacheByLCID = NULL; + reset_error_mapping_cache(); +} + +void +TdsLoadEncodingLCIDCache(void) +{ + HASHCTL hashCtl; + + if (TdsEncodingInfoCacheByLCID == NULL) + { + /* 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); + /* + * Load LCID - Encoding pair into our hash table. + */ + for (int i = 0; i < TdsLCIDToEncodingMap_datasize; i++) + { + int lcid; + TdsLCIDToEncodingMapInfo mInfo; + + /* Create the hash entry for lookup by LCID*/ + lcid = TdsLCIDToEncodingMap_data[i].lcid; + mInfo = (TdsLCIDToEncodingMapInfo)hash_search(TdsEncodingInfoCacheByLCID, + &lcid, + HASH_ENTER, + NULL); + mInfo->enc = TdsLCIDToEncodingMap_data[i].enc; + } + } +} + +/* + * TdsLookupEncodingByLCID - LCID - Encoding lookup + */ +int +TdsLookupEncodingByLCID(int lcid) +{ + bool found; + TdsLCIDToEncodingMapInfo mInfo; + + mInfo = (TdsLCIDToEncodingMapInfo)hash_search(TdsEncodingInfoCacheByLCID, + &lcid, + HASH_FIND, + &found); + + /* + * TODO: which encoding by default we should consider + * if appropriate Encoding is not found. + */ + if (!found) + { + return -1; + } + return mInfo->enc; +} + +void +TdsLoadTypeFunctionCache(void) +{ + 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 */ + { + MemSet(&hashCtl, 0, sizeof(hashCtl)); + hashCtl.keysize = sizeof(Oid); + hashCtl.entrysize = sizeof(TdsIoFunctionData); + hashCtl.hcxt = TdsMemoryContext; + functionInfoCacheByOid = hash_create("IO function info cache", + SPI_processed, + &hashCtl, + HASH_ELEM | HASH_CONTEXT | HASH_BLOBS); + } + + 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); + } + /* + * 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; + + 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)); + + if (OidIsValid(typeoid)) + { + basetypeoid = getBaseType(typeoid); + 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; + finfo->ttmtdslenbytes = TdsIoFunctionRawData_data[i].ttmtdslenbytes; + finfo->sendFuncId = TdsIoFunctionRawData_data[i].ttmsendfunc; + finfo->sendFuncPtr = getSendFunc(finfo->sendFuncId); + finfo->recvFuncId = TdsIoFunctionRawData_data[i].ttmrecvfunc; + finfo->recvFuncPtr = getRecvFunc(finfo->recvFuncId); + + /* Create the hash entry for lookup by TDS' type ID */ + 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. */ + { + fc2ent = (FunctionCacheByTdsIdEntry *)hash_search(functionInfoCacheByTdsId, + &fc2key, + HASH_ENTER, + NULL); + finfo = &(fc2ent->data); + finfo->ttmtypeid = typeoid; + finfo->ttmbasetypeid = basetypeoid; + finfo->ttmtdstypeid = TdsIoFunctionRawData_data[i].ttmtdstypeid; + finfo->ttmtdstypelen = TdsIoFunctionRawData_data[i].ttmtdstypelen; + finfo->ttmtdslenbytes = TdsIoFunctionRawData_data[i].ttmtdslenbytes; + finfo->sendFuncId = TdsIoFunctionRawData_data[i].ttmsendfunc; + finfo->sendFuncPtr = getSendFunc(finfo->sendFuncId); + finfo->recvFuncId = TdsIoFunctionRawData_data[i].ttmrecvfunc; + finfo->recvFuncPtr = getRecvFunc(finfo->recvFuncId); + } + } + } + + { + /* 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); + finfo_table = &(fc2ent_table->data); + finfo_table->ttmtypeid = InvalidOid; + finfo_table->ttmbasetypeid = InvalidOid; + finfo_table->ttmtdstypeid = TDS_TYPE_TABLE; + finfo_table->ttmtdstypelen = -1; + finfo_table->ttmtdslenbytes = 1; + finfo_table->sendFuncId = -1; + finfo_table->sendFuncPtr = getSendFunc(-1); + finfo_table->recvFuncId = TDS_RECV_TABLE; + finfo_table->recvFuncPtr = getRecvFunc(TDS_RECV_TABLE); + } +} + +/* + * TdsLookupTypeFunctionsByOid - IO function cache lookup + */ +TdsIoFunctionInfo +TdsLookupTypeFunctionsByOid(Oid typeId, int32* typmod) +{ + TdsIoFunctionInfo finfo; + bool found; + Oid tmpTypeId; + + Assert(functionInfoCacheByOid != NULL); + + finfo = (TdsIoFunctionInfo)hash_search(functionInfoCacheByOid, + &typeId, + HASH_FIND, + &found); + + /* + * If an entry is not found on tds mapping table, we try to find whether + * we've an entry for its base type. If not found, we continue till the + * bottom base type. + */ + tmpTypeId = typeId; + while (!found) + { + HeapTuple tup; + Form_pg_type typTup; + + tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(tmpTypeId)); + if (!HeapTupleIsValid(tup)) + break; + + typTup = (Form_pg_type) GETSTRUCT(tup); + if (typTup->typtype != TYPTYPE_DOMAIN) + { + /* Not a domain, so stop descending */ + ReleaseSysCache(tup); + break; + } + + 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. + */ + if (*typmod == -1) + *typmod = typTup->typtypmod; + + finfo = (TdsIoFunctionInfo)hash_search(functionInfoCacheByOid, + &tmpTypeId, + HASH_FIND, + &found); + ReleaseSysCache(tup); + } + + if (!found) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("data type %s is not supported yet", format_type_be(typeId)))); + + return finfo; +} + +/* + * TdsLookupTypeFunctionsByTdsId - IO function cache lookup + */ +TdsIoFunctionInfo +TdsLookupTypeFunctionsByTdsId(int32_t typeId, int32_t typeLen) +{ + 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); + 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); + if (found) + return &(fc2ent->data); + + /* Not found either way */ + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("data type %d not supported yet", typeId))); + + return NULL; +} + +/* -------------------------------- + * CopyMsgBytes - copy raw data from a message buffer + * + * Same as above, except data is copied to caller's buffer. + * Function definition closely matches to pq_copymsgbytes + * -------------------------------- + */ +void +CopyMsgBytes(StringInfo msg, char *buf, int datalen) +{ + if (datalen < 0 || datalen > (msg->len - msg->cursor)) + ereport(FATAL, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("insufficient data left in message"))); + memcpy(buf, &msg->data[msg->cursor], datalen); + msg->cursor += datalen; +} + +/* -------------------------------- + * GetMsgByte - get a raw byte from a message buffer + * Function definition closely matches pq_getmsgbyte + * -------------------------------- + */ +int +GetMsgByte(StringInfo msg) +{ + if (msg->cursor >= msg->len) + ereport(FATAL, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("no data left in message"))); + return (unsigned char) msg->data[msg->cursor++]; +} + +/* -------------------------------- + * GetMsgBytes - get raw data from a message buffer + * + * Returns a pointer directly into the message buffer; note this + * may not have any particular alignment. + * -------------------------------- + */ +const char * +GetMsgBytes(StringInfo msg, int datalen) +{ + const char *result; + + if (datalen < 0 || datalen > (msg->len - msg->cursor)) + ereport(FATAL, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("insufficient data left in message"))); + result = &msg->data[msg->cursor]; + msg->cursor += datalen; + return result; +} + +/* -------------------------------- + * GetMsgInt - get a binary integer from a message buffer + * + * Values are treated as unsigned. + * Function definition closely matches to pq_getmsgint + * -------------------------------- + */ +unsigned int +GetMsgInt(StringInfo msg, int b) +{ + unsigned int result; + unsigned char n8; + uint16 n16; + uint32 n32; + + switch (b) + { + case 1: + CopyMsgBytes(msg, (char *) &n8, 1); + result = n8; + break; + case 2: + CopyMsgBytes(msg, (char *) &n16, 2); + result = LEtoh16(n16); + break; + case 3: + memset(&n32, 0, sizeof(n32)); + CopyMsgBytes(msg, (char *) &n32, 3); + result = LEtoh32(n32); + break; + case 4: + CopyMsgBytes(msg, (char *) &n32, 4); + result = LEtoh32(n32); + break; + default: + elog(ERROR, "unsupported integer size %d", b); + result = 0; /* keep compiler quiet */ + break; + } + return result; +} + +/* -------------------------------- + * GetMsgInt64 - get a binary 8-byte int from a message buffer + * + * It is tempting to merge this with GetMesInt, but we'd have to make the + * result int64 for all data widths --- that could be a big performance + * hit on machines where int64 isn't efficient. + * Function definition closely mateches to pg_getmsgint64 + * -------------------------------- + */ +int64 +GetMsgInt64(StringInfo msg) +{ + uint64 n64; + + CopyMsgBytes(msg, (char *) &n64, sizeof(n64)); + + return LEtoh64(n64); +} + +/* -------------------------------- + * GetMsgUInt128 - get a binary 16-byte unsigned int from a message buffer + * -------------------------------- + */ +uint128 +GetMsgUInt128(StringInfo msg) +{ + uint128 n128; + + memcpy(&n128, &msg->data[msg->cursor], sizeof(n128)); + msg->cursor += sizeof(n128); + + return LEtoh128(n128); +} + +/* -------------------------------- + * GetMsgFloat4 - get a float4 from a message buffer + * + * Function definition closely matches to pq_getmsgfloat4 + * -------------------------------- + */ +float4 +GetMsgFloat4(StringInfo msg) +{ + union + { + float4 f; + uint32 i; + } swap; + + swap.i = GetMsgInt(msg, 4); + return swap.f; + +} + +/* -------------------------------- + * GetMsgFloat8 - get a float8 from a message buffer + * + * Function definition closely matches to pq_getmsgfloat8 + * -------------------------------- + */ +float8 +GetMsgFloat8(StringInfo msg) +{ + union + { + float8 f; + int64 i; + } swap; + + swap.i = GetMsgInt64(msg); + return swap.f; +} + +/* Helper Function to convert Bit value into Datum. */ +Datum +TdsTypeBitToDatum(StringInfo buf) +{ + int ext = GetMsgByte(buf); + PG_RETURN_BOOL((ext != 0) ? true : false); +} + +/* Helper Function to convert Integer value into Datum. */ +Datum +TdsTypeIntegerToDatum(StringInfo buf, int 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_BIGINT: /* BIG INT. */ + { + 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; + } +} + +/* Helper Function to convert Float value into Datum. */ +Datum +TdsTypeFloatToDatum(StringInfo buf, int maxLen) +{ + switch(maxLen) + { + case TDS_MAXLEN_FLOAT4: + { + float4 res; + res = GetMsgFloat4(buf); + PG_RETURN_FLOAT4(res); + } + break; + case TDS_MAXLEN_FLOAT8: + { + 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; + } +} + +/* Helper Function to convert Varchar,Char and Text values into Datum. */ +Datum +TdsTypeVarcharToDatum(StringInfo buf, Oid pgTypeOid, uint32_t collation) +{ + char csave; + Datum pval; + pg_enc encoding; + + csave = buf->data[buf->len]; + buf->data[buf->len] = '\0'; + + /* If we recieve 0 value for LCID then we should treat it as a default LCID.*/ + encoding = TdsGetEncoding(collation); + + pval = TdsAnyToServerEncodingConversion(pgTypeOid, + encoding, + buf->data, buf->len); + buf->data[buf->len] = csave; + return pval; +} + +/* Helper Function to convert NVarchar, NChar and NText values into Datum. */ +Datum +TdsTypeNCharToDatum(StringInfo buf) +{ + void *result; + StringInfoData temp; + + initStringInfo(&temp); + TdsUTF16toUTF8StringInfo(&temp, buf->data, buf->len); + + result = tds_varchar_input(temp.data, temp.len, -1); + pfree(temp.data); + + PG_RETURN_VARCHAR_P(result); +} + +static inline char * +ReverseString(char *res) +{ + int lo, hi; + if (!res) + return NULL; + + lo = 0; + hi = strlen(res)-1; + + while (lo < hi) + { + res[lo] ^= res[hi]; + res[hi] ^= res[lo]; + res[lo] ^= res[hi]; + lo++; hi--; + } + return res; +} + +static inline void +Integer2String(uint128 num, char* str) +{ + int i = 0, rem = 0; + while (num) + { + rem = num % 10; + str[i++] = rem + '0'; + num = num/10; + } + str[i++] = '-'; + ReverseString(str); +} + +/* Helper Function to convert Numeric value into Datum. */ +Datum +TdsTypeNumericToDatum(StringInfo buf, int scale) +{ + Numeric res; + 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); + + /* fetch the data but ignore the sign byte now */ + { + uint128 n128 = 0; + + memcpy(&n128, &buf->data[buf->cursor], TDS_MAXLEN_NUMERIC - 1); + buf->cursor += TDS_MAXLEN_NUMERIC - 1; + + num = LEtoh128(n128); + } + + decString = (char *)palloc0(sizeof(char) * 40); + + if (num != 0) + Integer2String(num, decString); + else + decString[0] = '0'; + + len = strlen(decString); + temp1 = '.'; + + /* + * 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. + */ + if (num != 0 && scale >= len) + { + 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. + */ + decString = psprintf("-%s%s.", zeros, tempString + 1); + len = strlen(decString) - 1; + pfree(tempString); + } + if (num != 0) + { + while (scale) + { + temp2 = decString[len - scale]; + decString[len - scale] = temp1; + temp1 = temp2; + scale--; + } + decString[len++] = temp1; + } + else + { + decString[len++] = temp1; + while (scale) + { + decString[len++] = '0'; + scale--; + } + } + + if (sign == 1 && num != 0) + decString++; + + res = TdsSetVarFromStrWrapper(decString); + PG_RETURN_NUMERIC(res); +} + +/* Helper Function to convert Varbinary and Binary values into Datum. */ +Datum +TdsTypeVarbinaryToDatum(StringInfo buf) +{ + bytea *result; + int nbytes; + + nbytes = buf->len - buf->cursor; + result = (bytea *) palloc0(nbytes + VARHDRSZ); + SET_VARSIZE(result, nbytes + VARHDRSZ); + CopyMsgBytes(buf, VARDATA(result), nbytes); + + PG_RETURN_BYTEA_P(result); +} + +/* Helper Function to convert Datetime2 value into Datum. */ +Datum +TdsTypeDatetime2ToDatum(StringInfo buf, int scale, int len) +{ + uint64_t numMicro = 0; + uint32_t numDays = 0; + Timestamp timestamp; + + if (scale == 255) + scale = 6; + + memcpy(&numMicro, &buf->data[buf->cursor], len - 3); + buf->cursor += len - 3; + + memcpy(&numDays, &buf->data[buf->cursor], 3); + buf->cursor += 3; + + TdsGetTimestampFromDayTime(numDays, numMicro, 0, ×tamp, scale); + + PG_RETURN_TIMESTAMP((Timestamp)timestamp); +} + +/* Helper Function to convert Datetime value into Datum. */ +Datum +TdsTypeDatetimeToDatum(StringInfo buf) +{ + uint32 numDays, numTicks; + uint64 val; + Timestamp timestamp; + + val = (uint64)GetMsgInt64(buf); + numTicks = val >> 32; + numDays = val & 0x00000000ffffffff; + + TdsTimeGetDatumFromDatetime(numDays, numTicks, ×tamp); + + PG_RETURN_TIMESTAMP((uint64)timestamp); +} + +/* Helper Function to convert Small Datetime value into Datum. */ +Datum +TdsTypeSmallDatetimeToDatum(StringInfo buf) +{ + uint16 numDays, numMins; + uint32 val; + Timestamp timestamp; + + val = (uint32)GetMsgInt(buf, 4); + numMins = val >> 16; + numDays = val & 0x0000ffff; + + TdsTimeGetDatumFromSmalldatetime(numDays, numMins, ×tamp); + + PG_RETURN_TIMESTAMP((uint64)timestamp); +} + +/* Helper Function to convert Date value into Datum. */ +Datum +TdsTypeDateToDatum(StringInfo buf) +{ + DateADT result; + uint64 val; + result = (DateADT)GetMsgInt(buf, 3); + TdsCheckDateValidity(result); + + TdsTimeGetDatumFromDays(result, &val); + + PG_RETURN_DATEADT(val); +} + +/* Helper Function to convert Time value into Datum. */ +Datum +TdsTypeTimeToDatum(StringInfo buf, int scale, int len) +{ + double result = 0; + uint64_t numMicro = 0; + + /* + * 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 (scale == 255) + scale = 6; + + memcpy(&numMicro, &buf->data[buf->cursor], len); + buf->cursor += len; + + 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"))); + + + 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; + uint32_t numDays = 0; + int16_t timezone = 0; + tsql_datetimeoffset *tdt = (tsql_datetimeoffset *) palloc0(DATETIMEOFFSET_LEN); + TimestampTz timestamp; + /* + * if Datetimeoffset 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 (scale == 0xFF) + scale = 6; + + memcpy(&numMicro, &buf->data[buf->cursor], len - 5); + buf->cursor += len - 5; + + memcpy(&numDays, &buf->data[buf->cursor], 3); + buf->cursor += 3; + + memcpy(&timezone, &buf->data[buf->cursor], 2); + buf->cursor += 2; + + timezone *= -1; + TdsGetTimestampFromDayTime(numDays, numMicro, (int)timezone, ×tamp, scale); + + timestamp -= (timezone * SECS_PER_MINUTE * USECS_PER_SEC); + /* since reverse is done in tm2timestamp() */ + timestamp -= (timezone * USECS_PER_SEC); + + tdt->tsql_ts = timestamp; + tdt->tsql_tz = timezone; + + PG_RETURN_DATETIMEOFFSET(tdt); +} + +/* Helper Function to convert Money value into Datum. */ +Datum +TdsTypeMoneyToDatum(StringInfo buf) +{ + uint64 high, low; + uint64 val = GetMsgInt64(buf); + + high = val & 0xffffffff00000000; + low = val & 0x00000000ffffffff; + val = high >> 32 | low << 32; + + + PG_RETURN_CASH((Cash)val); +} + +/* Helper Function to convert Small Money value into Datum. */ +Datum +TdsTypeSmallMoneyToDatum(StringInfo buf) +{ + uint64 val = 0; + uint32 low = GetMsgInt(buf, 4); + + val = (uint64)low; + + PG_RETURN_CASH((Cash)val); +} + +/* Helper Function to convert XML value into Datum. */ +Datum +TdsTypeXMLToDatum(StringInfo buf) +{ + void *result; + char *str; + int nbytes; + void *doc; + int encoding = PG_UTF8; + xmlChar *encodingStr = NULL; + + /* + * Read the data in raw format. We don't know yet what the encoding is, as + * that information is embedded in the xml declaration; so we have to + * parse that before converting to server encoding. + */ + nbytes = buf->len - buf->cursor; + + str = (char *)GetMsgBytes(buf, nbytes); + + /* + * We need a null-terminated string to pass to parse_xml_decl(). Rather + * than make a separate copy, make the temporary result one byte bigger + * than it needs to be. + */ + result = palloc0(nbytes + 1 + VARHDRSZ); + SET_VARSIZE(result, nbytes + VARHDRSZ); + memcpy(VARDATA(result), str, nbytes); + str = VARDATA(result); + 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; + */ + tds_parse_xml_decl((const xmlChar *)str, NULL, NULL, &encodingStr, NULL); + encoding = encodingStr ? xmlChar_to_encoding(encodingStr) : TdsUTF16toUTF8XmlResult(buf, &result); + + /* + * Parse the data to check if it is well-formed XML data. Assume that + * xml_parse will throw ERROR if not. + */ + doc = tds_xml_parse(result, XMLOPTION_CONTENT, true, encoding); + tds_xmlFreeDoc(doc); + + PG_RETURN_XML_P(result); +} + +/* Helper Function to convert UID value into Datum. */ +Datum +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 + */ + Assert(buf->len == TDS_MAXLEN_UNIQUEIDENTIFIER); + + /* SWAP to match TSQL behaviour */ + SwapData(buf, buf->cursor + 0, buf->cursor + 3); + SwapData(buf, buf->cursor + 1, buf->cursor + 2); + SwapData(buf, buf->cursor + 4, buf->cursor + 5); + SwapData(buf, buf->cursor + 6, buf->cursor + 7); + + uuid = (pg_uuid_t *) palloc(UUID_LEN); + memcpy(uuid->data, GetMsgBytes(buf, UUID_LEN), UUID_LEN); + + PG_RETURN_POINTER(uuid); +} + +StringInfo +TdsGetPlpStringInfoBufferFromToken(const char *message, const ParameterToken token) +{ + StringInfo pbuf; + Plp plpHead = token->plp, temp; + uint64_t len = 0; + + temp = plpHead; + pbuf = makeStringInfo(); + + /* data of zero length */ + if (temp == NULL) + return pbuf; + + while(temp != NULL) + { + len += temp->len; + temp = temp->next; + } + + + /* + * Explicitly calling enlargeStringInfo. This will save + * some overhead incase the data is very large and needs + * repalloc again and again + */ + enlargeStringInfo(pbuf, len); + + temp = plpHead; + + while (temp != NULL) + { + appendBinaryStringInfo(pbuf, &message[temp->offset], temp->len); + temp = temp->next; + } + + return pbuf; +} + +StringInfo +TdsGetStringInfoBufferFromToken(const char *message, const ParameterToken token) +{ + 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. + */ + pbuf->data = (char *) pvalue; + pbuf->maxlen = token->len; + pbuf->len = token->len; + pbuf->cursor = 0; + + return pbuf; +} + +/* -------------------------------- + * TdsRevTypeBit - converts external binary format to bool + * + * The external representation is one byte. Any nonzero value is taken + * as "true". + * Function definition closely matches to get boolrecv + * -------------------------------- + */ +Datum +TdsRecvTypeBit(const char *message, const ParameterToken token) +{ + Datum res; + StringInfo buf = TdsGetStringInfoBufferFromToken(message, token); + + res = TdsTypeBitToDatum(buf); + + pfree(buf); + return res; +} + +/* -------------------------------- + * TdsRecvTypeSmallInt - converts external binary format to int2 + * -------------------------------- + */ +Datum +TdsRecvTypeTinyInt(const char *message, const ParameterToken token) +{ + StringInfo buf = TdsGetStringInfoBufferFromToken(message, token); + Datum res; + + res = TdsTypeIntegerToDatum(buf, sizeof(int8)); + + pfree(buf); + return res; +} + +/* -------------------------------- + * TdsRecvTypeSmallInt - converts external binary format to int2 + * Function definition closely matches to int2recv + * -------------------------------- + */ +Datum +TdsRecvTypeSmallInt(const char *message, const ParameterToken token) +{ + StringInfo buf = TdsGetStringInfoBufferFromToken(message, token); + Datum res; + + res = TdsTypeIntegerToDatum(buf, sizeof(int16)); + + pfree(buf); + return res; +} + +/* -------------------------------- + * TdsRecvTypeInteger - converts external binary format to int4 + * Function definition closely matches to int4recv + * -------------------------------- + */ +Datum +TdsRecvTypeInteger(const char *message, const ParameterToken token) +{ + Datum res; + StringInfo buf = TdsGetStringInfoBufferFromToken(message, token); + + res = TdsTypeIntegerToDatum(buf, sizeof(int32)); + + pfree(buf); + return res; +} + +/* -------------------------------- + * TdsRecvTypeBigInt - converts external binary format to int8 + * Function definition closely matches to int8recv + * -------------------------------- + */ +Datum +TdsRecvTypeBigInt(const char *message, const ParameterToken token) +{ + Datum res; + StringInfo buf = TdsGetStringInfoBufferFromToken(message, token); + + res = TdsTypeIntegerToDatum(buf, sizeof(int64)); + + pfree(buf); + return res; +} + +/* -------------------------------- + * TdsRecvTypeFloat4 - converts external binary format to float4 + * Function definition closely matches to float4recv + * -------------------------------- + */ +Datum +TdsRecvTypeFloat4(const char *message, const ParameterToken token) +{ + Datum res; + StringInfo buf = TdsGetStringInfoBufferFromToken(message, token); + + res = TdsTypeFloatToDatum(buf, sizeof(float4)); + + pfree(buf); + return res; +} + +/* -------------------------------- + * TdsRecvTypeFloat4 - converts external binary format to float8 + * Function definition closely matches to float8recv + * -------------------------------- + */ +Datum +TdsRecvTypeFloat8(const char *message, const ParameterToken token) +{ + Datum res; + StringInfo buf = TdsGetStringInfoBufferFromToken(message, token); + + res = TdsTypeFloatToDatum(buf, sizeof(float8)); + + pfree(buf); + return res; +} + +/* -------------------------------- + * TdsRecvTypeBinary - converts external binary format to byte data + * -------------------------------- + */ +Datum +TdsRecvTypeBinary(const char *message, const ParameterToken token) +{ + Datum result; + StringInfo buf = TdsGetStringInfoBufferFromToken(message, token); + + result = TdsTypeVarbinaryToDatum(buf); + + pfree(buf); + return result; +} + +/* -------------------------------- + * TdsRecvTypeVarbinary - converts external varbinary format to byte data + * -------------------------------- + */ +Datum +TdsRecvTypeVarbinary(const char *message, const ParameterToken token) +{ + Datum result; + StringInfo buf; + + if (token->maxLen == 0xffff) + buf = TdsGetPlpStringInfoBufferFromToken(message, token); + else + { + TDSInstrumentation(INSTR_TDS_DATATYPE_VARBINARY_MAX); + + buf = TdsGetStringInfoBufferFromToken(message, token); + } + + result = TdsTypeVarbinaryToDatum(buf); + + if (token->maxLen == 0xffff) + pfree(buf->data); + + pfree(buf); + return result; +} + +/* -------------------------------- + * TdsRecvTypeVarchar - converts external binary format to varchar + * + * Function defination closely matches to varcharrecv + * -------------------------------- + */ +Datum +TdsRecvTypeVarchar(const char *message, const ParameterToken token) +{ + StringInfo buf; + char csave; + Datum pval; + + if (token->maxLen == 0xFFFF) + { + TDSInstrumentation(INSTR_TDS_DATATYPE_VARCHAR_MAX); + + buf = TdsGetPlpStringInfoBufferFromToken(message, token); + } + else + buf = TdsGetStringInfoBufferFromToken(message, token); + + csave = buf->data[buf->len]; + buf->data[buf->len] = '\0'; + pval = TdsAnyToServerEncodingConversion(token->paramMeta.pgTypeOid, + token->paramMeta.encoding, + buf->data, buf->len); + buf->data[buf->len] = csave; + + if (token->maxLen == 0xFFFF) + pfree(buf->data); + + pfree(buf); + return pval; +} + +void +TdsReadUnicodeDataFromTokenCommon(const char *message, const ParameterToken token, StringInfo temp) +{ + 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. + */ + if ((token->type == TDS_TYPE_NVARCHAR || token->type == TDS_TYPE_VARCHAR) && + (token->maxLen == 0xFFFF)) + buf = TdsGetPlpStringInfoBufferFromToken(message, token); + else + buf = TdsGetStringInfoBufferFromToken(message, token); + + enlargeStringInfo(temp, buf->len); + + TdsUTF16toUTF8StringInfo(temp, buf->data, buf->len); + + if ((token->type == TDS_TYPE_NVARCHAR || token->type == TDS_TYPE_VARCHAR) && + (token->maxLen == 0xFFFF)) + pfree(buf->data); + + pfree(buf); +} + +/* -------------------------------- + * TdsRecvTypeNVarchar - converts external binary format to varchar + * + * Function defination closely matches to varcharrecv + * -------------------------------- + */ +Datum +TdsRecvTypeNVarchar(const char *message, const ParameterToken token) +{ + void *result; + StringInfoData temp; + + if (token->maxLen == 0xFFFF) + TDSInstrumentation(INSTR_TDS_DATATYPE_NVARCHAR_MAX); + + initStringInfo(&temp); + + TdsReadUnicodeDataFromTokenCommon(message, token, &temp); + result = tds_varchar_input(temp.data, temp.len, -1); + + pfree(temp.data); + + PG_RETURN_VARCHAR_P(result); +} + +Datum +TdsRecvTypeText(const char *message, const ParameterToken token) +{ + char csave; + Datum pval; + StringInfo buf = TdsGetStringInfoBufferFromToken(message, token); + + csave = buf->data[buf->len]; + buf->data[buf->len] = '\0'; + pval = TdsAnyToServerEncodingConversion(token->paramMeta.pgTypeOid, + token->paramMeta.encoding, buf->data, buf->len); + buf->data[buf->len] = csave; + + pfree(buf); + return pval; +} + +Datum +TdsRecvTypeNText(const char *message, const ParameterToken token) +{ + Datum result; + StringInfo buf = TdsGetStringInfoBufferFromToken(message, token); + + result = TdsTypeNCharToDatum(buf); + + pfree(buf); + return result; +} + +/* -------------------------------- + * TdsRecvTypeChar - converts external binary format to char + * + * Function defination closely matches to bpcharrecv + * -------------------------------- + */ +Datum +TdsRecvTypeChar(const char *message, const ParameterToken token) +{ + char csave; + Datum pval; + StringInfo buf = TdsGetStringInfoBufferFromToken(message, token); + + csave = buf->data[buf->len]; + buf->data[buf->len] = '\0'; + pval = TdsAnyToServerEncodingConversion(token->paramMeta.pgTypeOid, + token->paramMeta.encoding, buf->data, buf->len); + buf->data[buf->len] = csave; + + pfree(buf); + return pval; +} + +/* -------------------------------- + * TdsRecvTypeNChar - converts external binary format to nchar + * + * Function defination closely matches to bpcharrecv + * -------------------------------- + */ +Datum +TdsRecvTypeNChar(const char *message, const ParameterToken token) +{ + Datum result; + StringInfo buf = TdsGetStringInfoBufferFromToken(message, token); + + result = TdsTypeNCharToDatum(buf); + + pfree(buf); + return result; +} + +/* + * TdsRecvTypeXml - convert extenal binary format to XML Datum + * Function defination closely matches to xml_recv + * XMLChar * is equivant to char * + */ +Datum +TdsRecvTypeXml(const char *message, const ParameterToken token) +{ + Datum result; + StringInfo buf = TdsGetPlpStringInfoBufferFromToken(message, token); + + TDSInstrumentation(INSTR_TDS_DATATYPE_XML); + + result = TdsTypeXMLToDatum(buf); + + pfree(buf->data); + pfree(buf); + return result; +} + +/* -------------------------------- + * TdsRecvTypeMoney - converts external binary format to UniqueIdentifier + * + * Function defination closely matches to uuid_recv + * -------------------------------- + */ +Datum +TdsRecvTypeUniqueIdentifier(const char *message, const ParameterToken token) +{ + Datum result; + StringInfo buf = TdsGetStringInfoBufferFromToken(message, token); + + result = TdsTypeUIDToDatum(buf); + + pfree(buf); + return result; +} + +/* -------------------------------- + * TdsRecvTypeMoney - converts external binary format to uint64 for + * money data type + * Function defination closely matches to cash_recv + * -------------------------------- + */ +Datum +TdsRecvTypeMoney(const char *message, const ParameterToken token) +{ + StringInfo buf = TdsGetStringInfoBufferFromToken(message, token); + + uint64 high, low; + uint64 val = GetMsgInt64(buf); + + TDSInstrumentation(INSTR_TDS_DATATYPE_MONEY); + + high = val & 0xffffffff00000000; + low = val & 0x00000000ffffffff; + val = high >> 32 | low << 32; + + pfree(buf); + PG_RETURN_CASH((Cash)val); +} + +/* -------------------------------- + * TdsRecvTypeSmallmoney - converts external binary format to uint64 for + * Smallmoney data type + * Function defination closely matches to cash_recv + * -------------------------------- + */ +Datum +TdsRecvTypeSmallmoney(const char *message, const ParameterToken token) +{ + StringInfo buf = TdsGetStringInfoBufferFromToken(message, token); + + uint64 val = 0; + uint32 low = GetMsgInt(buf, 4); + + TDSInstrumentation(INSTR_TDS_DATATYPE_SMALLMONEY); + + val = (uint64)low; + pfree(buf); + PG_RETURN_CASH((Cash)val); +} + +/* -------------------------------- + * TdsRecvTypeSmalldatetime - converts external binary format to + * Small Datetime data type + * -------------------------------- + */ +Datum +TdsRecvTypeSmalldatetime(const char *message, const ParameterToken token) +{ + Datum result; + StringInfo buf = TdsGetStringInfoBufferFromToken(message, token); + + result = TdsTypeSmallDatetimeToDatum(buf); + + pfree(buf); + return result; +} + +/* ------------------------------- + * TdsRecvTypeDate - converts external binary format to + * Date data type + * -------------------------------- + */ +Datum +TdsRecvTypeDate(const char *message, const ParameterToken token) +{ + Datum result; + StringInfo buf = TdsGetStringInfoBufferFromToken(message, token); + + result = TdsTypeDateToDatum(buf); + + pfree(buf); + return result; +} + +/* -------------------------------- + * TdsRecvTypeDatetime - converts external binary format to + * Datetime data type + * -------------------------------- + */ +Datum +TdsRecvTypeDatetime(const char *message, const ParameterToken token) +{ + Datum result; + StringInfo buf = TdsGetStringInfoBufferFromToken(message, token); + + result = TdsTypeDatetimeToDatum(buf); + + pfree(buf); + return result; +} + +/* ------------------------------- + * TdsRecvTypeTime - converts external binary format to + * Time data type + * -------------------------------- + */ +Datum +TdsRecvTypeTime(const char *message, const ParameterToken token) +{ + Datum result; + int scale = 0; + StringInfo buf = TdsGetStringInfoBufferFromToken(message, token); + TdsColumnMetaData col = token->paramMeta; + scale = col.metaEntry.type6.scale; + + result = TdsTypeTimeToDatum(buf, scale, token->len); + + pfree(buf); + return result; +} + +Datum +TdsRecvTypeDatetime2(const char *message, const ParameterToken token) +{ + Datum result; + int scale = 0; + StringInfo buf = TdsGetStringInfoBufferFromToken(message, token); + TdsColumnMetaData col = token->paramMeta; + + scale = col.metaEntry.type6.scale; + + + result = TdsTypeDatetime2ToDatum(buf, scale, token->len); + + pfree(buf); + return result; +} + +static inline uint128 +StringToInteger(char *str) +{ + int i = 0, len = 0; + uint128 num = 0; + + if (!str) + return 0; + + len = strlen(str); + + for ( ; i < len; i++) + num = num * 10 + (str[i] - '0'); + + return num; +} + + +/* -------------------------------- + * TdsRecvTypeNumeric - converts external binary format to numeric/decimal + * Function definition closely matches to numeric_recv + * -------------------------------- + */ +Datum +TdsRecvTypeNumeric(const char *message, const ParameterToken token) +{ + Numeric res; + int scale, len, sign; + char *decString, *wholeString; + int temp1, temp2; + uint128 num = 0; + TdsColumnMetaData col = token->paramMeta; + + 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); + + /* fetch the data but ignore the sign byte now */ + { + uint128 n128 = 0; + + memcpy(&n128, &buf->data[buf->cursor], token->len - 1); + buf->cursor += token->len - 1; + + num = LEtoh128(n128); + } + + decString = (char *)palloc0(sizeof(char) * 40); + + if (num != 0) + Integer2String(num, decString); + else + decString[0] = '0'; + + + len = strlen(decString); + temp1 = '.'; + + /* + * 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. + */ + if (num != 0 && scale >= len) + { + 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. + */ + decString = psprintf("-%s%s.", zeros, tempString + 1); + len = strlen(decString) - 1; + pfree(tempString); + } + if (num != 0) + { + while (scale) + { + temp2 = decString[len - scale]; + decString[len - scale] = temp1; + temp1 = temp2; + scale--; + } + decString[len++] = temp1; + } + else + { + decString[len++] = temp1; + while (scale) + { + decString[len++] = '0'; + scale--; + } + } + /* + * We use wholeString just to free the address at decString later, + * since it gets updated later. + */ + wholeString = decString; + + if (sign == 1 && num != 0) + decString++; + + res = TdsSetVarFromStrWrapper(decString); + + if (wholeString) + pfree(wholeString); + if (buf) + pfree(buf); + PG_RETURN_NUMERIC(res); +} + +/* -------------------------------- + * TdsRecvTypeTable - creates a temp-table from the data being recevied on the wire + * and sends this temp-table's name to the engine. + * -------------------------------- + */ +Datum +TdsRecvTypeTable(const char *message, const ParameterToken token) +{ + 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; + 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()); + + /* + * We change the dialect to postgres to create temp tables + * and execute a prep/exec insert query via SPI. + */ + set_config_option("babelfishpg_tsql.sql_dialect", "postgres", + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + + /* Connect to the SPI manager. */ + if ((rc = SPI_connect()) < 0) + elog(ERROR, "SPI_connect() failed in TDS Listener " + "with return code %d", rc); + + if (!xactStarted) + StartTransactionCommand(); + PushActiveSnapshot(GetTransactionSnapshot()); + + + + query = psprintf("CREATE TEMPORARY TABLE IF NOT EXISTS %s (like %s including all)", + tableName, token->tvpInfo->tvpTypeName); + + + /* + * 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) + elog(ERROR, "Failed to create the underlying table for table-valued parameter: %d", rc); + + SPI_finish(); + PopActiveSnapshot(); + if (!xactStarted) + 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; + query = " "; + + if (!xactStarted) + StartTransactionCommand(); + PushActiveSnapshot(GetTransactionSnapshot()); + + while (row) /* Create the prep/exec query to insert the rows. */ + { + TdsIoFunctionInfo tempFuncInfo; + int currentColumn = 0; + char *currentQuery = " "; + + while(currentColumn != token->tvpInfo->colCount) + { + temp = &(row->columnValues[currentColumn]); + tempFuncInfo = TdsLookupTypeFunctionsByTdsId(colMetaData[currentColumn].columnTdsType, colMetaData[currentColumn].maxLen); + GetPgOid(argtypes[i], tempFuncInfo); + if (row->isNull[currentColumn] == 'n') + nulls[i] = row->isNull[currentColumn]; + else + switch(colMetaData[currentColumn].columnTdsType) + { + case TDS_TYPE_CHAR: + case TDS_TYPE_VARCHAR: + values[i] = TdsTypeVarcharToDatum(temp, argtypes[i], colMetaData[currentColumn].collation); + break; + case TDS_TYPE_NCHAR: + values[i] = TdsTypeNCharToDatum(temp); + break; + case TDS_TYPE_NVARCHAR: + if (!row->isNull[currentColumn]) /* NULL. */ + currentQuery = psprintf("%s,\'NULL\'", currentQuery); + else + currentQuery = psprintf("%s,\'%s\'", currentQuery, temp->data); + nargs--; + break; + case TDS_TYPE_INTEGER: + case TDS_TYPE_BIT: + values[i] = TdsTypeIntegerToDatum(temp, colMetaData[currentColumn].maxLen); + break; + case TDS_TYPE_FLOAT: + values[i] = TdsTypeFloatToDatum(temp, colMetaData[currentColumn].maxLen); + break; + case TDS_TYPE_NUMERICN: + case TDS_TYPE_DECIMALN: + values[i] = TdsTypeNumericToDatum(temp, colMetaData[currentColumn].scale); + break; + case TDS_TYPE_VARBINARY: + case TDS_TYPE_BINARY: + values[i] = TdsTypeVarbinaryToDatum(temp); + argtypes[i] = tempFuncInfo->ttmtypeid; + break; + case TDS_RECV_DATE: + values[i] = TdsTypeDateToDatum(temp); + break; + case TDS_TYPE_TIME: + values[i] = TdsTypeTimeToDatum(temp, colMetaData[currentColumn].scale, temp->len); + break; + case TDS_TYPE_DATETIMEOFFSET: + values[i] = TdsTypeDatetimeoffsetToDatum(temp, colMetaData[currentColumn].scale, temp->len); + break; + case TDS_TYPE_DATETIME2: + values[i] = TdsTypeDatetime2ToDatum(temp, colMetaData[currentColumn].scale, temp->len); + break; + case TDS_TYPE_DATETIMEN: + values[i] = TdsTypeDatetimeToDatum(temp); + break; + case TDS_TYPE_MONEYN: + values[i] = TdsTypeMoneyToDatum(temp); + break; + case TDS_TYPE_XML: + values[i] = TdsTypeXMLToDatum(temp); + break; + case TDS_TYPE_UNIQUEIDENTIFIER: + values[i] = TdsTypeUIDToDatum(temp); + break; + case TDS_TYPE_SQLVARIANT: + values[i] = TdsTypeSqlVariantToDatum(temp); + break; + } + /* Build a string for bind parameters. */ + if (colMetaData[currentColumn].columnTdsType != TDS_TYPE_NVARCHAR || row->isNull[currentColumn] == 'n') + { + currentQuery = psprintf("%s,$%d", currentQuery, i + 1); + i++; + } + currentColumn++; + } + row = row->nextRow; + 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. */ + query = psprintf("%s,(%s)", query, currentQuery); + } + + if (token->tvpInfo->rowData) /* If any row in TVP */ + { + query[1] = ' '; /* Convert the first ',' into a blank space. */ + + src = psprintf("Insert into %s values %s", tableName, query); + if ((rc = SPI_connect()) < 0) + elog(ERROR, "SPI_connect() failed in TDS Listener " + "with return code %d", rc); + + rc = SPI_execute_with_args(src, + nargs, argtypes, + values, nulls, + false, 1); + + if (rc != SPI_OK_INSERT) + elog(ERROR, "Failed to insert in the underlying table for table-valued parameter: %d", rc); + + SPI_finish(); + PopActiveSnapshot(); + if (!xactStarted) + CommitTransactionCommand(); + } + + set_config_option("babelfishpg_tsql.sql_dialect", "tsql", + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + } + + /* Free all the pointers. */ + while (token->tvpInfo->rowData) + { + TvpRowData *tempRow = token->tvpInfo->rowData; + token->tvpInfo->rowData = token->tvpInfo->rowData->nextRow; + pfree(tempRow); + } + 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); + item->tableRelid = InvalidOid; + item->tableName = finalTableName; + tvp_lookup_list = lappend(tvp_lookup_list, item); + + PG_RETURN_CSTRING(finalTableName); +} + +/* TdsRecvTypeSqlvariant - converts external binary format to byte data + * based on sqlvariant base type + * -------------------------------- + */ +Datum +TdsRecvTypeSqlvariant(const char *message, const ParameterToken token) +{ + Datum result; + StringInfo buf = TdsGetStringInfoBufferFromToken(message, token); + + TDSInstrumentation(INSTR_TDS_DATATYPE_SQLVARIANT); + + result = TdsTypeSqlVariantToDatum(buf); + + pfree(buf); + return result; +} + +int +TdsSendTypeBit(FmgrInfo *finfo, Datum value, void *vMetaData) +{ + int rc = 0; + int8_t out = DatumGetBool(value); + + /* Don't send the length if the column type is not null. */ + if (!((TdsColumnMetaData *)vMetaData)->attNotNull) + rc = TdsPutInt8(sizeof(out)); + + if (rc == 0) + rc = TdsPutInt8(out); + return rc; +} + +int +TdsSendTypeTinyint(FmgrInfo *finfo, Datum value, void *vMetaData) +{ + int rc = 0; + int8_t out = DatumGetUInt8(value); + + /* Don't send the length if the column type is not null. */ + if (!((TdsColumnMetaData *)vMetaData)->attNotNull) + rc = TdsPutInt8(sizeof(out)); + + if (rc == 0) + rc = TdsPutInt8(out); + return rc; +} +int +TdsSendTypeSmallint(FmgrInfo *finfo, Datum value, void *vMetaData) +{ + int rc = 0; + int16_t out = DatumGetInt16(value); + + /* Don't send the length if the column type is not null. */ + if (!((TdsColumnMetaData *)vMetaData)->attNotNull) + rc = TdsPutInt8(sizeof(out)); + + if (rc == 0) + rc = TdsPutInt16LE(out); + return rc; +} + +int +TdsSendTypeInteger(FmgrInfo *finfo, Datum value, void *vMetaData) +{ + int rc = 0; + int32_t out = DatumGetInt32(value); + + /* Don't send the length if the column type is not null. */ + if (!((TdsColumnMetaData *)vMetaData)->attNotNull) + rc = TdsPutInt8(sizeof(out)); + + if (rc == 0) + rc = TdsPutInt32LE(out); + return rc; +} + +int +TdsSendTypeBigint(FmgrInfo *finfo, Datum value, void *vMetaData) +{ + int rc = 0; + int64_t out = DatumGetInt64(value); + + /* Don't send the length if the column type is not null. */ + if (!((TdsColumnMetaData *)vMetaData)->attNotNull) + rc = TdsPutInt8(sizeof(out)); + + if (rc == 0) + rc = TdsPutInt64LE(out); + return rc; +} + +int +TdsSendTypeFloat4(FmgrInfo *finfo, Datum value, void *vMetaData) +{ + int rc = 0; + float4 out = DatumGetFloat4(value); + + /* Don't send the length if the column type is not null. */ + if (!((TdsColumnMetaData *)vMetaData)->attNotNull) + rc = TdsPutInt8(sizeof(out)); + + if (rc == 0) + rc = TdsPutFloat4LE(out); + return rc; +} + +int +TdsSendTypeFloat8(FmgrInfo *finfo, Datum value, void *vMetaData) +{ + int rc = 0; + float8 out = DatumGetFloat8(value); + + /* Don't send the length if the column type is not null. */ + if (!((TdsColumnMetaData *)vMetaData)->attNotNull) + rc = TdsPutInt8(sizeof(out)); + + if (rc == 0) + rc = TdsPutFloat8LE(out); + return rc; +} + +static int +TdsSendPlpDataHelper(char *data, int len) +{ + int rc; + uint32_t plpTerminator = PLP_TERMINATOR; + uint64_t tempOffset = 0; + uint32_t plpChunckLen = PLP_CHUNCK_LEN; + + if ((rc = TdsPutInt64LE(len)) == 0) + { + while (true) + { + if (plpChunckLen > (len - tempOffset)) + plpChunckLen = (len - tempOffset); + + // Either data is "0" or no more data to send + if (plpChunckLen == 0) + break; + + // need testing for "0" len + if ((rc = TdsPutUInt32LE(plpChunckLen)) == 0) + { + TdsPutbytes(&(data[tempOffset]), plpChunckLen); + } + if (rc != 0) + return rc; + + tempOffset += plpChunckLen; + Assert(tempOffset <= len); + } + rc |= TdsPutInt32LE(plpTerminator); + } + + return rc; +} + +int +TdsSendTypeXml(FmgrInfo *finfo, Datum value, void *vMetaData) +{ + int rc; + 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 (GetClientTDSVersion() <= TDS_VERSION_7_1_1) + return TdsSendTypeNText(finfo, value, vMetaData); + + TDSInstrumentation(INSTR_TDS_DATATYPE_XML); + + initStringInfo(&buf); + TdsUTF8toUTF16StringInfo(&buf, out, strlen(out)); + + rc = TdsSendPlpDataHelper(buf.data, buf.len); + + pfree(buf.data); + + return rc; +} + +int +TdsSendTypeBinary(FmgrInfo *finfo, Datum value, void *vMetaData) +{ + int rc = EOF,maxLen = 0; + bytea *vlena = DatumGetByteaPCopy(value); + bytea *buf; + TdsColumnMetaData *col = (TdsColumnMetaData *)vMetaData; + + maxLen = col->metaEntry.type7.maxSize; + buf = (bytea *)palloc0(sizeof(bytea) * maxLen); + memcpy(buf, VARDATA_ANY(vlena), VARSIZE_ANY_EXHDR(vlena)); + + if ((rc = TdsPutUInt16LE(maxLen)) == 0) + TdsPutbytes(buf, maxLen); + + pfree(buf); + return rc; +} + +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; + + len = strlen(buf); + destBuf = server_to_any(buf, len, col->encoding); + + maxLen = col->metaEntry.type2.maxSize; + actualLen = (buf != destBuf) ? strlen(destBuf) : len; + + if (maxLen != 0xffff) + { + if (unlikely(actualLen > maxLen)) + elog(ERROR, "Number of bytes for the field of varchar(n) exeeds max specified for the field."); + + if ((rc = TdsPutInt16LE(actualLen)) == 0) + rc = TdsPutbytes(destBuf, actualLen); + } + else + { + /* 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); + + rc = TdsSendPlpDataHelper(destBuf, actualLen); + } + + pfree(buf); + return rc; +} + +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; + + len = strlen(buf); + destBuf = server_to_any(buf, len, col->encoding); + + maxLen = col->metaEntry.type2.maxSize; + actualLen = (buf != destBuf) ? strlen(destBuf) : len; + if (unlikely(maxLen != actualLen)) + elog(ERROR, "Number of bytes required for the field of char(n) does not match with max bytes specified of the field"); + + if ((rc = TdsPutUInt16LE(actualLen)) == 0) + rc = TdsPutbytes(destBuf, actualLen); + + pfree(buf); + return rc; +} + +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; + + maxlen = col->metaEntry.type7.maxSize; + len = VARSIZE_ANY_EXHDR(vlena); + + if (maxlen != 0xffff) + { + if ((rc = TdsPutInt16LE(len)) == 0) + TdsPutbytes(buf, len); + } + else + { + TDSInstrumentation(INSTR_TDS_DATATYPE_VARBINARY_MAX); + + rc = TdsSendPlpDataHelper(buf, len); + } + 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 + */ + 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); + + TdsPutbytes(textptr, sizeof(textptr)); + TdsPutbytes(texttimestamp, sizeof(texttimestamp)); +} + +int +TdsSendTypeText(FmgrInfo *finfo, Datum value, void *vMetaData) +{ + int rc; + uint32_t len; + char *destBuf, *buf = OutputFunctionCall(finfo, value); + TdsColumnMetaData *col = (TdsColumnMetaData *)vMetaData; + + SendTextPtrInfo(); + + len = strlen(buf); + destBuf = server_to_any(buf, len, col->encoding); + if (destBuf != buf) + { + len = strlen(destBuf); + } + if ((rc = TdsPutUInt32LE(len)) == 0) + rc = TdsPutbytes(destBuf, len); + + pfree(buf); + return rc; +} + +int +TdsSendTypeImage(FmgrInfo *finfo, Datum value, void *vMetaData) +{ + int rc = EOF, len; + bytea *vlena = DatumGetByteaPCopy(value); + char *buf = VARDATA(vlena); + + TDSInstrumentation(INSTR_TDS_DATATYPE_IMAGE); + + SendTextPtrInfo(); + + len = VARSIZE_ANY_EXHDR(vlena); + + if ((rc = TdsPutUInt32LE(len)) == 0) + TdsPutbytes(buf, len); + return rc; +} + +int +TdsSendTypeNText(FmgrInfo *finfo, Datum value, void *vMetaData) +{ + int rc; + char *out = OutputFunctionCall(finfo, value); + StringInfoData buf; + + SendTextPtrInfo(); + + initStringInfo(&buf); + 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. + */ + /*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); + + pfree(buf.data); + return rc; +} + +int +TdsSendTypeNVarchar(FmgrInfo *finfo, Datum value, void *vMetaData) +{ + + int rc, maxlen; + char *out = OutputFunctionCall(finfo, value); + TdsColumnMetaData *col = (TdsColumnMetaData *)vMetaData; + StringInfoData buf; + + initStringInfo(&buf); + TdsUTF8toUTF16StringInfo(&buf, out, strlen(out)); + maxlen = col->metaEntry.type2.maxSize; + + 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. + */ + 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 = TdsPutInt16LE(buf.len)) == 0) + TdsPutbytes(buf.data, buf.len); + } + else + { + TDSInstrumentation(INSTR_TDS_DATATYPE_NVARCHAR_MAX); + + rc = TdsSendPlpDataHelper(buf.data, buf.len); + } + + pfree(buf.data); + return rc; +} + +int +TdsSendTypeNChar(FmgrInfo *finfo, Datum value, void *vMetaData) +{ + + 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. + */ + 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; + } + + /* + * 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) + { + appendStringInfoChar(&buf, 0x20); + appendStringInfoChar(&buf, 0x00); + len += 2; + } + + len = col->metaEntry.type2.maxSize; + + if ((rc = TdsPutInt16LE(len)) == 0) + TdsPutbytes(buf.data, len); + pfree(buf.data); + + return rc; +} + +int +TdsSendTypeMoney(FmgrInfo *finfo, Datum value, void *vMetaData) +{ + int rc = 0, length = 8; + uint32 low = 0, high = 0; + uint64 out = DatumGetUInt64(value); + + TDSInstrumentation(INSTR_TDS_DATATYPE_MONEY); + + low = out & 0xffffffff; + high = (out >> 32) & 0xffffffff; + + /* Don't send the length if the column type is not null. */ + if (!((TdsColumnMetaData *)vMetaData)->attNotNull) + rc = TdsPutInt8(length); + + if (rc == 0) + { + rc = TdsPutUInt32LE(high); + rc |= TdsPutUInt32LE(low); + } + return rc; +} + +int +TdsSendTypeSmallmoney(FmgrInfo *finfo, Datum value, void *vMetaData) +{ + int rc = 0, length = 4; + uint32 low = 0, high = 0; + uint64 out = DatumGetUInt64(value); + + TDSInstrumentation(INSTR_TDS_DATATYPE_SMALLMONEY); + + low = out & 0xffffffff; + 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!"))); + return EOF; + } + + /* Don't send the length if the column type is not null. */ + if (!((TdsColumnMetaData *)vMetaData)->attNotNull) + rc = TdsPutInt8(length); + + if (rc == 0) + rc = TdsPutUInt32LE(low); + return rc; +} + +int +TdsSendTypeSmalldatetime(FmgrInfo *finfo, Datum value, void *vMetaData) +{ + 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) + rc = TdsPutInt8(length); + + if (rc == 0) + { + rc = TdsPutUInt16LE(numDays); + rc |= TdsPutUInt16LE(numMins); + } + return rc; +} + +int +TdsSendTypeDate(FmgrInfo *finfo, Datum value, void *vMetaData) +{ + 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. + */ + return TdsSendTypeNVarchar(finfo, value, vMetaData); + + numDays = TdsDayDifference(value); + + if ((rc = TdsPutInt8(length)) == 0) + rc = TdsPutDate(numDays); + return rc; +} + +int +TdsSendTypeDatetime(FmgrInfo *finfo, Datum value, void *vMetaData) +{ + 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) + rc = TdsPutInt8(length); + + if (rc == 0) + { + rc = TdsPutUInt32LE(numDays); + rc |= TdsPutUInt32LE(numTicks); + } + return rc; +} + +/* + * TdsSendTypeNumeric() formats response for numeric + * data in TDS listener side before writing it to wire. + * Based on numeric prescision, TdsSendTypeNumeric() generates + * 4-16 byte data followed by data length and sign bytes and writes to wire. + */ +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; + + out = OutputFunctionCall(finfo, value); + if (out[0] == '-') + { + sign = 0; + out++; + } + if (out[0] == '0') + out++; + /* + * 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)); + /* While there is still digit in out and we haven't reached max_scale */ + while (*out && scale < max_scale) + { + if (*out == '.') + { + out++; + /* Start counting scale */ + scale = 0; + continue; + } + decString[precision++] = *out; + out++; + if (scale >= 0) + scale++; + } + + /* done scanning and haven't seen the decimal point, set scale to 0 */ + if (scale == -1) + scale = 0; + + /* + * Fill in the remaining 0's if the processed scale from out is less than max_scale + * This is needed because the output generated by engine may not always + * produce the same precision/scale as calculated by resolve_numeric_typmod_from_exp, + * which is the precision/scale we have sent to the client with column metadata. + */ + while (scale++ < max_scale) + { + decString[precision++] = '0'; + } + decString[precision] = '\0'; + + 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."))); + + if (precision >= 1 && precision < 10) + length = 4; + else if (precision < 20) + length = 8; + else if (precision < 29) + length = 12; + else if (precision < 39) + length = 16; + + num = StringToInteger(decString); + if (TdsPutInt8(length + 1) == 0 && TdsPutInt8(sign) == 0) + rc = TdsPutbytes(&num, length); + + pfree(decString); + return rc; +} + +static void +SwapData(StringInfo buf, int st, int end) +{ + char tempswap; + + if (buf->len < end || st > end) + return; + + tempswap = buf->data[st]; + buf->data[st] = buf->data[end]; + buf->data[end] = tempswap; +} + +int +TdsSendTypeUniqueIdentifier(FmgrInfo *finfo, Datum value, void *vMetaData) +{ + pg_uuid_t *uuid = DatumGetUUIDP(value); + int rc; + StringInfoData buf; + + initStringInfo(&buf); + resetStringInfo(&buf); + appendBinaryStringInfo(&buf, (char *) uuid->data, UUID_LEN); + + /* SWAP to match TSQL behaviour */ + SwapData(&buf, 0, 3); + SwapData(&buf, 1, 2); + SwapData(&buf, 4, 5); + SwapData(&buf, 6, 7); + + if ((rc = TdsPutInt8(UUID_LEN)) == 0) + TdsPutbytes(buf.data, UUID_LEN); + + pfree(buf.data); + return rc; +} + +int +TdsSendTypeTime(FmgrInfo *finfo, Datum value, void *vMetaData) +{ + int rc = EOF, length = 0, scale = 0; + uint64_t res = 0; + double numSec = 0; + 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. + */ + 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. However, setting default scale to 6 since + * postgres supports upto 6 digits after decimal point + */ + if (scale == 255) + scale = 6; + + if (scale >= 0 && scale < 3) + length = 3; + else if (scale >= 3 && scale < 5) + length = 4; + else if (scale >= 5 && scale <= 7) + length = 5; + + numSec = (double)value / 1000000; + while (scale--) + numSec *= 10; + + res = (uint64_t)numSec; + if ((rc = TdsPutInt8(length)) == 0) + rc = TdsPutbytes(&res, length); + return rc; +} + +int +TdsSendTypeDatetime2(FmgrInfo *finfo, Datum value, void *vMetaData) +{ + int rc = EOF, length = 0, scale = 0; + uint64 numSec = 0; + uint32 numDays = 0; + 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. + */ + 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. However, setting default scale to 6 since + * postgres supports upto 6 digits after decimal point + */ + if (scale == 255) + scale = 6; + + if (scale >= 0 && scale < 3) + length = 6; + else if (scale >= 3 && scale < 5) + length = 7; + else if (scale >= 5 && scale <= 7) + length = 8; + + TdsGetDayTimeFromTimestamp((Timestamp)value, &numDays, + &numSec, scale); + + if (TdsPutInt8(length) == 0 && + TdsPutbytes(&numSec, length - 3) == 0) + rc = TdsPutDate(numDays); + + return rc; +} + +static void +SwapByte(char *buf, int st, int end) +{ + char temp = buf[st]; + buf[st] = buf[end]; + buf[end] = temp; +} + +/* Helper Function to convert SQL_VARIANT value into Datum. */ +Datum +TdsTypeSqlVariantToDatum(StringInfo buf) +{ + 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; + DateADT date = 0; + uint64 numMicro = 0, dateval = 0; + uint16 numDays = 0, numMins = 0; + int16 timezone = 0; + uint32 numDays32 = 0, numTicks = 0; + Timestamp timestamp = 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); + + variantBaseType = buf->data[0]; + tempLen = buf->len - buf->cursor; + + pltsql_plugin_handler_ptr->sqlvariant_get_pg_base_type(variantBaseType, &pgBaseType, + tempLen, &dataLen, &variantHeaderLen); + + if (variantBaseType == VARIANT_TYPE_NCHAR || + variantBaseType == VARIANT_TYPE_NVARCHAR) + { + initStringInfo(&strbuf); + TdsUTF16toUTF8StringInfo(&strbuf, &buf->data[9], tempLen - 9); + } + + resLen = dataLen + variantHeaderLen; + /* We need an extra varlena header for varlena datatypes */ + if (variantBaseType == VARIANT_TYPE_CHAR || variantBaseType == VARIANT_TYPE_NCHAR || + variantBaseType == VARIANT_TYPE_VARCHAR || variantBaseType == VARIANT_TYPE_NVARCHAR || + variantBaseType == VARIANT_TYPE_BINARY || variantBaseType == VARIANT_TYPE_VARBINARY || + variantBaseType == VARIANT_TYPE_NUMERIC) + { + resLen += VARHDRSZ; + } + + if (resLen + VARHDRSZ_SHORT <= VARATT_SHORT_MAX) + { + resLen += VARHDRSZ_SHORT; + result = (bytea *) palloc0(resLen); + SET_VARSIZE_SHORT(result, resLen); + } + else + { + resLen += VARHDRSZ; + result = (bytea *) palloc0(resLen); + SET_VARSIZE(result, resLen); + } + + if (variantBaseType == VARIANT_TYPE_CHAR || variantBaseType == VARIANT_TYPE_NCHAR || + 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) + { + memcpy(VARDATA(READ_DATA(result, variantHeaderLen)), strbuf.data, dataLen); + } + else + { + memcpy(VARDATA(READ_DATA(result, variantHeaderLen)), &buf->data[9], dataLen); + } + } + else if (variantBaseType == VARIANT_TYPE_BINARY || variantBaseType == VARIANT_TYPE_VARBINARY) + { + SET_VARSIZE(READ_DATA(result, variantHeaderLen), VARHDRSZ + dataLen); + memcpy(&maxLen, &buf->data[2], 2); + memcpy(VARDATA(READ_DATA(result, variantHeaderLen)), &buf->data[0], dataLen); + } + else if (variantBaseType == VARIANT_TYPE_DATE) + { + memset(&date, 0, sizeof(date)); + memcpy(&date, &buf->data[2], 3); + TdsCheckDateValidity(date); + TdsTimeGetDatumFromDays(date, &dateval); + memcpy(READ_DATA(result, variantHeaderLen), &dateval, sizeof(date)); + } + else if (variantBaseType == VARIANT_TYPE_SMALLDATETIME) + { + memcpy(&numDays, &buf->data[2], 2); + memcpy(&numMins, &buf->data[4], 2); + TdsTimeGetDatumFromSmalldatetime(numDays, numMins, ×tamp); + memcpy(READ_DATA(result, variantHeaderLen), ×tamp, sizeof(timestamp)); + } + else if (variantBaseType == VARIANT_TYPE_DATETIME) + { + memcpy(&numDays32, &buf->data[2], 4); + memcpy(&numTicks, &buf->data[6], 4); + TdsTimeGetDatumFromDatetime(numDays32, numTicks, ×tamp); + memcpy(READ_DATA(result, variantHeaderLen), ×tamp, sizeof(timestamp)); + } + else if (variantBaseType == VARIANT_TYPE_TIME) + { + scale = buf->data[2]; + temp = scale; + /* postgres limitation */ + if (scale > 7 || scale < 0) + scale = 6; + + if (scale <= 2) + dataLen = 3; + else if (scale <= 4) + dataLen = 4; + else if (scale <= 7) + dataLen = 5; + + memset(&numMicro, 0, sizeof(numMicro)); + memcpy(&numMicro, &buf->data[3], dataLen); + + if (temp == 7 || temp == 0xff) + numMicro /= 10; + + while (scale < 6) + { + numMicro *= 10; + scale++; + } + scale = temp; + memcpy(READ_DATA(result, variantHeaderLen), &numMicro, sizeof(numMicro)); + } + else if (variantBaseType == VARIANT_TYPE_DATETIME2) + { + scale = buf->data[2]; + + /* postgres limitation */ + if (scale > 7 || scale == 0xff || scale < 0) + scale = 6; + + if (scale <= 2) + dataLen = 6; + else if (scale <= 4) + dataLen = 7; + else if (scale <= 7) + dataLen = 8; + + memset(&numDays32, 0, sizeof(numDays32)); + memset(&numMicro, 0, sizeof(numMicro)); + memcpy(&numDays32, &buf->data[3], 3); + memcpy(&numMicro, &buf->data[6], dataLen - 3); + TdsGetTimestampFromDayTime(numDays32, numMicro, 0, ×tamp, scale); + memcpy(READ_DATA(result, variantHeaderLen), ×tamp, sizeof(timestamp)); + } + else if (variantBaseType == VARIANT_TYPE_DATETIMEOFFSET) + { + scale = buf->data[2]; + + /* postgres limitation */ + if (scale > 7 || scale == 0xff || scale < 0) + scale = 6; + + if (scale <= 2) + dataLen = 8; + else if (scale <= 4) + 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); + memcpy(&numMicro, &buf->data[3], dataLen - 5); + memcpy(&timezone, &buf->data[dataLen + 1], 2); + + timezone *= -1; + TdsGetTimestampFromDayTime(numDays32, numMicro, (int)timezone, ×tamptz, scale); + timestamptz -= (timezone * SECS_PER_MINUTE * USECS_PER_SEC); + timestamptz -= (timezone * USECS_PER_SEC); + + tdt->tsql_ts = timestamptz; + tdt->tsql_tz = timezone; + memcpy(READ_DATA(result, variantHeaderLen), tdt, DATETIMEOFFSET_LEN); + } + else if (variantBaseType == VARIANT_TYPE_NUMERIC) + { + SET_VARSIZE(READ_DATA(result, variantHeaderLen), VARHDRSZ + dataLen); + precision = buf->data[2]; + scale = buf->data[3]; + sign = buf->data[4]; + tempScale = scale; + + dataLen = 16; + memcpy(&n128, &buf->data[5], dataLen); + num = LEtoh128(n128); + decString = (char *)palloc0(sizeof(char) * 40); + if (num != 0) + Integer2String(num, decString); + else + decString[0] = '0'; + len = strlen(decString); + temp1 = '.'; + if (num != 0) + { + while (tempScale) + { + temp2 = decString[len - tempScale]; + decString[len - tempScale] = temp1; + temp1 = temp2; + tempScale--; + } + decString[len++] = temp1; + } + else + { + decString[len++] = temp1; + while (tempScale) + { + decString[len++] = '0'; + tempScale--; + } + } + + if (sign == 1 && num != 0) + decString++; + res = TdsSetVarFromStrWrapper(decString); + memcpy(VARDATA(READ_DATA(result, variantHeaderLen)), &res, sizeof(Numeric)); + } + else + { + /* + * For all other fixed length datatypes + */ + memcpy(READ_DATA(result, variantHeaderLen), &buf->data[2], dataLen); + } + + if (variantBaseType == VARIANT_TYPE_MONEY) + { + /* + * 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); + } + + if (variantBaseType == VARIANT_TYPE_UNIQUEIDENTIFIER) + { + /* SWAP to match TSQL behaviour */ + SwapByte(READ_DATA(result, variantHeaderLen), 0, 3); + SwapByte(READ_DATA(result, variantHeaderLen), 1, 2); + SwapByte(READ_DATA(result, variantHeaderLen), 4, 5); + SwapByte(READ_DATA(result, variantHeaderLen), 6, 7); + } + + pltsql_plugin_handler_ptr->sqlvariant_set_metadata(result, + pgBaseType, scale, precision, maxLen); + + buf->cursor += tempLen; + PG_RETURN_BYTEA_P(result); +} + +int +TdsSendTypeSqlvariant(FmgrInfo *finfo, Datum value, void *vMetaData) +{ + int rc = EOF, variantBaseType = 0; + uint8_t pgBaseType = 0; + int dataLen = 0, totalLen = 0, maxLen = 0; + int metadataLen = 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; + StringInfoData strbuf; + int precision = 0, scale = -1, sign = 1, i = 0, temp = 0; + uint128 num = 0; + Timestamp timestamp = 0; + TimestampTz timestamptz = 0; + + TDSInstrumentation(INSTR_TDS_DATATYPE_SQLVARIANT); + + /* + * 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); + + pltsql_plugin_handler_ptr->sqlvariant_get_variant_base_type(pgBaseType, + &variantBaseType, &isBaseNum, &isBaseChar, + &isBaseDec, &isBaseBin, &isBaseDate, &variantHeaderLen); + + if (variantBaseType == VARIANT_TYPE_NUMERIC) + { + dataLen = VARSIZE_ANY_EXHDR(vlena) - variantHeaderLen; + buf += variantHeaderLen; + dataLen = 16; + + out = OutputFunctionCall(finfo, value); + + if (out && out[0] == '-') + { + sign = 0; + out++; + } + decString = (char *)palloc(sizeof(char) * (strlen(out) + 1)); + precision = 0, scale = -1; + while (out && *out) + { + if (*out == '.') + { + out++; + scale = 0; + continue; + } + decString[precision++] = *out; + out++; + if (scale >= 0) + scale++; + } + if (scale == -1) + scale = 0; + decString[precision] = '\0'; + num = StringToInteger(decString); + } + + dataLen = VARSIZE_ANY_EXHDR(vlena) - variantHeaderLen; + buf += variantHeaderLen; + + if (isBaseNum) + { + /* + * dataformat: totalLen(4B) + baseType(1B) + metadatalen(1B) + + * data(dataLen) + */ + if (variantBaseType == VARIANT_TYPE_TINYINT) + dataLen = 1; + + if (variantBaseType == VARIANT_TYPE_SMALLMONEY) + dataLen = 4; + + if (variantBaseType == VARIANT_TYPE_MONEY) + { + /* + * swap positions of 2 nibbles for money type + * to match SQL behaviour + */ + for (i = 0; i < 4; i++) + SwapByte(buf, i, i + 4); + } + + if (variantBaseType == VARIANT_TYPE_UNIQUEIDENTIFIER) + { + /* SWAP to match TSQL behaviour */ + SwapByte(buf, 0, 3); + SwapByte(buf, 1, 2); + SwapByte(buf, 4, 5); + SwapByte(buf, 6, 7); + } + + totalLen = dataLen + 2; + rc = TdsPutUInt32LE(totalLen); + rc |= TdsPutInt8(variantBaseType); + rc |= TdsPutInt8(metadataLen); + rc |= TdsPutbytes(buf, dataLen); + } + else if (isBaseChar) + { + /* + * dataformat: totalLen(4B) + baseType(1B) + metadatalen(1B) + + * encodingLen(5B) + dataLen(2B) + data(dataLen) + */ + dataLen -= 4; + if (variantBaseType == VARIANT_TYPE_NCHAR || + variantBaseType == VARIANT_TYPE_NVARCHAR) + { + initStringInfo(&strbuf); + TdsUTF8toUTF16StringInfo(&strbuf, buf + 4, dataLen); + dataLen *= 2; + } + + totalLen = dataLen + 9; + metadataLen = 7; + rc = TdsPutUInt32LE(totalLen); + rc |= TdsPutInt8(variantBaseType); + rc |= TdsPutInt8(metadataLen); + /* + * 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); + rc |= TdsPutInt8(208); + rc |= TdsPutInt8(0); + rc |= TdsPutInt8(52); + + rc |= TdsPutUInt16LE(dataLen); + + if (variantBaseType == VARIANT_TYPE_NCHAR || + variantBaseType == VARIANT_TYPE_NVARCHAR) + rc |= TdsPutbytes(strbuf.data, dataLen); + else + rc |= TdsPutbytes(buf + 4, dataLen); + } + else if (isBaseBin) + { + /* + * dataformat : totalLen(4B) + baseType(1B) + metadatalen(1B) + + * dataLen(2B) + data(dataLen) + */ + totalLen = dataLen; + metadataLen = 2; + + rc = TdsPutUInt32LE(totalLen); + rc |= TdsPutInt8(variantBaseType); + rc |= TdsPutInt8(metadataLen); + rc |= TdsPutUInt16LE(maxLen); + rc |= TdsPutbytes(buf + 4, maxLen); + } + else if (isBaseDec) + { + /* + * dataformat : totalLen(4B) + baseType(1B) + metadatalen(1B) + + * precision(1B) + scale(1B) + sign(1B) + data(dataLen) + */ + dataLen = 16; + totalLen = dataLen + 5; + metadataLen = 2; + rc = TdsPutUInt32LE(totalLen); + rc |= TdsPutInt8(variantBaseType); + rc |= TdsPutInt8(metadataLen); + rc |= TdsPutInt8(precision); + rc |= TdsPutInt8(scale); + rc |= TdsPutInt8(sign); + rc |= TdsPutbytes(&num, dataLen); + } + else if (isBaseDate) + { + /* + * dataformat : totalLen(4B) + baseType(1B) + metadatalen(1B) + + * data(3B) + */ + + if (variantBaseType == VARIANT_TYPE_DATE) + { + memset(&dateval, 0, sizeof(dateval)); + memcpy(&dateval, buf, sizeof(dateval)); + numDays = TdsDayDifference(dateval); + dataLen = 3; + totalLen = dataLen + 2; + rc = TdsPutUInt32LE(totalLen); + rc |= TdsPutInt8(variantBaseType); + rc |= TdsPutInt8(metadataLen); + rc |= TdsPutDate(numDays); + } + /* + * dataformat : totalLen(4B) + baseType(1B) + metadatalen(1B) + + * data(4B) + */ + else if (variantBaseType == VARIANT_TYPE_SMALLDATETIME) + { + memcpy(×tamp, buf, sizeof(timestamp)); + dataLen = 4; + totalLen = dataLen + 2; + TdsTimeDifferenceSmalldatetime(timestamp, &numDays16, &numMins); + rc = TdsPutUInt32LE(totalLen); + rc |= TdsPutInt8(variantBaseType); + rc |= TdsPutInt8(metadataLen); + rc |= TdsPutUInt16LE(numDays16); + rc |= TdsPutUInt16LE(numMins); + } + /* + * dataformat : totalLen(4B) + baseType(1B) + metadatalen(1B) + + * data(8B) + */ + else if (variantBaseType == VARIANT_TYPE_DATETIME) + { + memcpy(×tamp, buf, dataLen); + TdsTimeDifferenceDatetime(timestamp, &numDays, &numTicks); + dataLen = 8; + totalLen = dataLen + 2; + rc = TdsPutUInt32LE(totalLen); + rc |= TdsPutInt8(variantBaseType); + rc |= TdsPutInt8(metadataLen); + rc |= TdsPutUInt32LE(numDays); + rc |= TdsPutUInt32LE(numTicks); + } + else if (variantBaseType == VARIANT_TYPE_TIME) + { + /* + * dataformat : totalLen(4B) + baseType(1B) + metadatalen(1B) + + * scale(1B) + data(3B-5B) + */ + if (scale == 0xff || scale < 0 || scale > 7) + scale = 6; + + if (scale >= 0 && scale < 3) + dataLen = 3; + else if (scale >= 3 && scale < 5) + dataLen = 4; + else if (scale >= 5 && scale <= 7) + dataLen = 5; + + metadataLen = 1; + memcpy(&numMicro, buf, sizeof(numMicro)); + temp = scale; + if (scale == 7 || scale == 0xff) + numMicro *= 10; + + while (temp < 6) + { + numMicro /= 10; + temp++; + } + totalLen = dataLen + metadataLen + 2; + rc = TdsPutUInt32LE(totalLen); + rc |= TdsPutInt8(variantBaseType); + rc |= TdsPutInt8(metadataLen); + rc |= TdsPutInt8(scale); + rc = TdsPutbytes(&numMicro, dataLen); + } + else if(variantBaseType == VARIANT_TYPE_DATETIME2) + { + /* + * dataformat : totalLen(4B) + baseType(1B) + metadatalen(1B) + + * scale(1B) + data(6B-8B) + */ + if (scale == 0xff || scale < 0 || scale > 7) + scale = 6; + + if (scale >= 0 && scale < 3) + dataLen = 6; + else if (scale >= 3 && scale < 5) + dataLen = 7; + else if (scale >= 5 && scale <= 7) + dataLen = 8; + + memcpy(×tamp, buf, sizeof(timestamp)); + TdsGetDayTimeFromTimestamp((Timestamp)timestamp, &numDays, + &numMicro, scale); + + metadataLen = 1; + totalLen = dataLen + metadataLen + 2; + rc = TdsPutUInt32LE(totalLen); + rc |= TdsPutInt8(variantBaseType); + rc |= TdsPutInt8(metadataLen); + rc |= TdsPutInt8(scale); + rc |= TdsPutbytes(&numMicro, dataLen - 3); + rc |= TdsPutDate(numDays); + } + else if (variantBaseType == VARIANT_TYPE_DATETIMEOFFSET) + { + /* + * 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 = 6; + + if (scale >= 0 && scale < 3) + dataLen = 8; + else if (scale >= 3 && scale < 5) + dataLen = 9; + else if (scale >= 5 && scale <= 7) + dataLen = 10; + + TdsGetDayTimeFromTimestamp((Timestamp)timestamptz, &numDays, + &numMicro, scale); + timezone *= -1; + + metadataLen = 1; + totalLen = dataLen + metadataLen + 2; + rc = TdsPutUInt32LE(totalLen); + rc |= TdsPutInt8(variantBaseType); + rc |= TdsPutInt8(metadataLen); + rc |= TdsPutInt8(scale); + rc |= TdsPutbytes(&numMicro, dataLen - 5); + rc |= TdsPutDate(numDays); + rc |= TdsPutInt16LE(timezone); + } + } + return rc; +} + +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; + + TDSInstrumentation(INSTR_TDS_DATATYPE_DATETIME_OFFSET); + + result = TdsTypeDatetimeoffsetToDatum(buf, scale, token->len); + + pfree(buf); + return result; +} + +int +TdsSendTypeDatetimeoffset(FmgrInfo *finfo, Datum value, void *vMetaData) +{ + 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; + + 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. + */ + return TdsSendTypeNVarchar(finfo, value, vMetaData); + + TDSInstrumentation(INSTR_TDS_DATATYPE_DATETIME_OFFSET); + + timestamp = tdt->tsql_ts; + timezone = tdt->tsql_tz; + 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. However, setting default scale to 6 since + * postgres supports upto 6 digits after decimal point + */ + if (scale == 0xFF) + scale = 6; + + if (scale >= 0 && scale < 3) + length = 8; + else if (scale >= 3 && scale < 5) + length = 9; + else if (scale >= 5 && scale <= 7) + length = 10; + + + TdsGetDayTimeFromTimestamp((Timestamp)timestamp, &numDays, + &numSec, scale); + timezone *= -1; + if (TdsPutInt8(length) == 0 && + TdsPutbytes(&numSec, length - 5) == 0 && + TdsPutDate(numDays) == 0) + rc = TdsPutUInt16LE(timezone); + + return rc; +} diff --git a/contrib/babelfishpg_tds/src/backend/tds/tdsutils.c b/contrib/babelfishpg_tds/src/backend/tds/tdsutils.c new file mode 100644 index 00000000000..a60787640d0 --- /dev/null +++ b/contrib/babelfishpg_tds/src/backend/tds/tdsutils.c @@ -0,0 +1,536 @@ +/*------------------------------------------------------------------------- + * + * tdsutils.c + * TDS Listener utility functions + * + * Portions Copyright (c) 2020, AWS + * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * contrib/babelfishpg_tds/src/backend/tds/tdsutils.c + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "src/include/tds_int.h" +#include "nodes/nodes.h" +#include "nodes/parsenodes.h" +#include "parser/parser.h" +#include "parser/parse_node.h" +#include "utils/elog.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); + +/* + * GetUTF8CodePoint - extract the next Unicode code point from 1..4 + * bytes at 'in' in UTF-8 encoding. + */ +static inline int32_t +GetUTF8CodePoint(const unsigned char *in, int len, int *consumed_p) +{ + int32_t code; + int consumed; + + if (len == 0) + return EOF; + + if ((in[0] & 0x80) == 0) + { + /* 1 byte - 0xxxxxxx */ + code = in[0]; + consumed = 1; + } + else if ((in[0] & 0xE0) == 0xC0) + { + /* 2 byte - 110xxxxx 10xxxxxx */ + if (len < 2) + ereport(ERROR, + (errcode(ERRCODE_DATA_EXCEPTION), + errmsg("truncated UTF8 byte sequence starting with 0x%02x", + in[0]))); + if ((in[1] & 0xC0) != 0x80) + ereport(ERROR, + (errcode(ERRCODE_DATA_EXCEPTION), + errmsg("invalid UTF8 byte sequence starting with 0x%02x", + in[0]))); + code = ((in[0] & 0x1F) << 6) | (in[1] & 0x3F); + consumed = 2; + } + else if ((in[0] & 0xF0) == 0xE0) + { + /* 3 byte - 1110xxxx 10xxxxxx 10xxxxxx */ + if (len < 3) + ereport(ERROR, + (errcode(ERRCODE_DATA_EXCEPTION), + errmsg("truncated UTF8 byte sequence starting with 0x%02x", + in[0]))); + if ((in[1] & 0xC0) != 0x80 || (in[2] & 0xC0) != 0x80) + ereport(ERROR, + (errcode(ERRCODE_DATA_EXCEPTION), + errmsg("invalid UTF8 byte sequence starting with 0x%02x", + in[0]))); + code = ((in[0] & 0x0F) << 12) | ((in[1] & 0x3F) << 6) | (in[2] & 0x3F); + consumed = 3; + } + else if ((in[0] & 0xF8) == 0xF0) + { + /* 4 byte - 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */ + if (len < 4) + ereport(ERROR, + (errcode(ERRCODE_DATA_EXCEPTION), + errmsg("truncated UTF8 byte sequence starting with 0x%02x", + in[0]))); + if ((in[1] & 0xC0) != 0x80 || (in[2] & 0xC0) != 0x80 || + (in[3] & 0xC0) != 0x80) + ereport(ERROR, + (errcode(ERRCODE_DATA_EXCEPTION), + 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); + consumed = 4; + } + else + { + ereport(ERROR, + (errcode(ERRCODE_DATA_EXCEPTION), + errmsg("invalid UTF8 byte sequence starting with 0x%02x", + in[0]))); + } + + if (code > 0x10FFFF || (code >= 0xD800 && code < 0xE000)) + ereport(ERROR, + (errcode(ERRCODE_DATA_EXCEPTION), + errmsg("invalid UTF8 code point 0x%x", code))); + + if (consumed_p) + *consumed_p = consumed; + + return code; +} + +/* -------------------- + * GetUTF16CodePoint - Extract the next UTF-16 code point from a byte sequence + * + * The code point is extracted from 2 or 4 bytes at 'in'. The optional + * 'consumed' pointer will be set to the number of bytes actually used. + * + * Returns: next Unicode code point + * + * Will thrown an ERROR if the encoding sequence is invalid as per Unicode + * specifications. Wiki claims that some Windows clients can produce invalid + * UTF-16 encoding sequences, but any attempt to work around that is a bad + * idea. We would silently mangle the data by converting invalid codes to + * something else, that will be interpreted differently when the application + * gets the data back. It is corrupted (invalid) data we are talking about. + * Forcing a square peg into a round hole with a sledge hammer has never + * worked out well in the PostgreSQL world. + * -------------------- + */ +static inline int32_t +GetUTF16CodePoint(const unsigned char *in, int len, int *consumed) +{ + uint16_t code1; + uint16_t code2; + int32_t result; + + /* Get the first 16 bits */ + code1 = in[1] << 8 | in[0]; + if (code1 < 0xD800 || code1 >= 0xE000) + { + /* + * 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. + */ + if (code1 == 0) + ereport(ERROR, + (errcode(ERRCODE_DATA_EXCEPTION), + errmsg("invalid UTF16 byte sequence - " + "code point 0 not supported"))); + if (consumed) + *consumed = 2; + return (int32_t)code1; + } + + /* This is a surrogate pair - check that it is the high part */ + if (code1 >= 0xDC00) + ereport(ERROR, + (errcode(ERRCODE_DATA_EXCEPTION), + errmsg("invalid UTF16 byte sequence - " + "high part is (0x%02x, 0x%02x)", in[0], in[1]))); + + /* Check that there is a second surrogate half */ + if (len < 4) + ereport(ERROR, + (errcode(ERRCODE_DATA_EXCEPTION), + errmsg("invalid UTF16 byte sequence - " + "only 2 bytes (0x%02x, 0x%02x)", in[0], in[1]))); + + /* Get the second 16 bits (low part) */ + code2 = in[3] << 8 | in[2]; + if (code2 < 0xDC00 || code2 > 0xE000) + ereport(ERROR, + (errcode(ERRCODE_DATA_EXCEPTION), + errmsg("invalid UTF16 byte sequence - " + "low part is (0x%02x, 0x%02x)", in[2], in[3]))); + + /* Valid surrogate pair, convert to code point */ + result = ((code1 & 0x03FF) << 10 | (code2 & 0x03FF)) + 0x10000; + + /* Valid 32 bit surrogate code point */ + if (consumed) + *consumed = 4; + return result; +} + +/* + * AddUTF8ToStringInfo - Add Unicode code point to a StringInfo in UTF-8 + */ +static inline void +AddUTF8ToStringInfo(int32_t code, StringInfo buf) +{ + /* Check that this is a valid code point */ + if ((code > 0xD800 && code < 0xE000) || code < 0x0001 || code > 0x10FFFF) + ereport(ERROR, + (errcode(ERRCODE_DATA_EXCEPTION), + errmsg("invalid Unicode code point 0x%x", code))); + + /* Range U+0000 .. U+007F (7 bit)*/ + if (code <= 0x7F) + { + appendStringInfoChar(buf, code); + return; + } + + /* Range U+0080 .. U+07FF (11 bit) */ + if (code <= 0x7ff) + { + appendStringInfoChar(buf, 0xC0 | (code >> 6)); + appendStringInfoChar(buf, 0x80 | (code & 0x3F)); + return; + } + + /* Range U+0800 .. U+FFFF (16 bit) */ + if (code <= 0xFFFF) + { + appendStringInfoChar(buf, 0xE0 | (code >> 12)); + appendStringInfoChar(buf, 0x80 | ((code >> 6) & 0x3F)); + appendStringInfoChar(buf, 0x80 | (code & 0x3F)); + return; + } + + /* Range U+10000 .. U+10FFFF (21 bit) */ + appendStringInfoChar(buf, 0xF0 | (code >> 18)); + appendStringInfoChar(buf, 0x80 | ((code >> 12) & 0x3F)); + appendStringInfoChar(buf, 0x80 | ((code >> 6) & 0x3F)); + appendStringInfoChar(buf, 0x80 | (code & 0x3F)); +} + +/* + * AddUTF16ToStringInfo - Add Unicode code point to a StringInfo in UTF-16 + */ +static inline void +AddUTF16ToStringInfo(int32_t code, StringInfo buf) +{ + union { + uint16_t value; + uint8_t half[2]; + } temp16; + + /* Check that this is a valid code point */ + if ((code > 0xD800 && code < 0xE000) || code < 0x0001 || code > 0x10FFFF) + ereport(ERROR, + (errcode(ERRCODE_DATA_EXCEPTION), + errmsg("invalid Unicode code point 0x%x", code))); + + /* Handle single 16-bit code point */ + if (code <= 0xFFFF) + { + appendStringInfoChar(buf, code & 0xFF); + appendStringInfoChar(buf, (code >> 8) & 0xFF); + return; + } + + temp16.value = 0xD800 + (((code - 0x010000) >> 10) & 0x03FF); + appendStringInfoChar(buf, temp16.half[0]); + appendStringInfoChar(buf, temp16.half[1]); + temp16.value = 0xDC00 + ((code - 0x010000) & 0x03FF); + appendStringInfoChar(buf, temp16.half[0]); + appendStringInfoChar(buf, temp16.half[1]); +} + +/* + * TdsUTF16toUTF8StringInfo - convert UTF16 data into UTF8 and + * add it to a StringInfo. + */ +void +TdsUTF16toUTF8StringInfo(StringInfo out, void *vin, int len) +{ + unsigned char *in = vin; + int i; + int consumed; + int32_t code; + + /* UTF16 data allways comes in 16-bit units */ + if ((len & 0x0001) != 0) + ereport(ERROR, + (errcode(ERRCODE_DATA_EXCEPTION), + errmsg("invalid UTF16 byte sequence - " + "input data has odd number of bytes"))); + + for (i = 0; i < len;) + { + code = GetUTF16CodePoint(&in[i], len - i, &consumed); + AddUTF8ToStringInfo(code, out); + i += consumed; + } +} + +/* + * TdsUTF8toUTF16StringInfo - convert UTF8 data into UTF16 and + * add it to a StringInfo. + */ +void +TdsUTF8toUTF16StringInfo(StringInfo out, const void *vin, size_t len) +{ + const unsigned char *in = vin; + size_t i; + int consumed; + int32_t code; + + for (i = 0; i < len;) + { + code = GetUTF8CodePoint(&in[i], len - i, &consumed); + AddUTF16ToStringInfo(code, out); + i += consumed; + } +} + +/* + * TdsUTF8LengthInUTF16 - compute the length of a UTF8 string in number of + * 16-bit units if we were to convert it into + * UTF16 with TdsUTF8toUTF16StringInfo() + * */ +int +TdsUTF8LengthInUTF16(const void *vin, int len) +{ + const unsigned char *in = vin; + int result = 0; + int i; + int consumed; + int32_t code; + + for (i = 0; i < len;) + { + code = GetUTF8CodePoint(&in[i], len - i, &consumed); + + /* Check that this is a valid code point */ + if ((code > 0xD800 && code < 0xE000) || code < 0x0001 || code > 0x10FFFF) + ereport(ERROR, + (errcode(ERRCODE_DATA_EXCEPTION), + errmsg("invalid Unicode code point 0x%x", code))); + + if (code <= 0xFFFF) + /* This code point would result in a single 16-bit output */ + result += 1; + else + /* This code point would result in a 16-bit surrogate pair */ + result += 2; + + i += consumed; + } + + return result; +} + +/* Process the stream headers for message */ +int32_t +ProcessStreamHeaders(const StringInfo message) +{ + 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", + message->len); + + /* Skip the headers */ + memcpy(&header_len, &(message->data[0]), 4); + if (header_len > message->len) + elog(FATAL, "corrupted TDS_QUERY packet - " + "header length beyond packet end"); + return header_len; +} + +/* + * Returns the parameter number to associate with the given + * parameter name, or zero if the given name is not found. + * + * NOTE: parameter numbers start at 1, not zero, so we + * add 1 to the array index below. + */ +static int +FindMatchingParam(List *params, const char *name) +{ + ListCell *cell; + int i = 0; + + foreach(cell, params) + { + TdsParamName item = lfirst(cell); + + if (pg_strcasecmp(name, item->name) == 0) + return i + 1; + i++; + } + + return 0; +} + +/* + * Transforms the given ColumnRef to a ParamRef if the name + * of the column matches the name of one of the parameters + * found in parameter list returned by TdsGetParamNames(). + * + * If a match is found, this function returns a new ParamRef + * node, otherwise it returns NULL and the given ColumnRef + * should be treated as a ColumnRef. + */ +Node * +TdsFindParam(ParseState *pstate, ColumnRef *cref) +{ + extern int sql_dialect; + List *params = NULL; + + if (sql_dialect != SQL_DIALECT_TSQL) + return NULL; + + if (!TdsGetParamNames(¶ms)) + return NULL; + + if (pstate->p_paramref_hook == NULL) + return NULL; + + if (list_length(cref->fields) != 1) + return NULL; + else + { + char *colname = strVal(linitial(cref->fields)); + int paramNo = 0; + ParamRef *pref; + + if (params != NULL) + { + paramNo = FindMatchingParam(params, colname); + } + else + { + paramNo = TdsGetAndSetParamIndex(colname); + } + + if (paramNo == 0) + return NULL; + + pref = makeNode(ParamRef); + + pref->number = paramNo; + pref->location = cref->location; + + return TransformParamRef(pstate, pref); + } +} + +static Node * +TransformParamRef(ParseState *pstate, ParamRef *pref) +{ + Node *result; + + /* + * The core parser knows nothing about Params. If a hook is supplied, + * call it. If not, or if the hook returns NULL, throw a generic error. + */ + if (pstate->p_paramref_hook != NULL) + result = pstate->p_paramref_hook(pstate, pref); + else + result = NULL; + + if (result == NULL) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_PARAMETER), + errmsg("there is no parameter $%d", pref->number), + parser_errposition(pstate, pref->location))); + + return result; +} + +/* + * TDS Error context callback to let us supply a call-stack traceback. + */ +void +TdsErrorContextCallback(void *arg) +{ + TdsErrorContextData *tdsErrorContext = (TdsErrorContextData *) arg; + + /* + * 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 */ + { + errcontext("TDS Protocol: Message Type: TDS Login7, Phase: Login. %s", + tdsErrorContext->err_text); + } + break; + case TDS_PRELOGIN: /* Pre-login Request*/ + { + errcontext("TDS Protocol: Message Type: TDS Pre-Login, Phase: Login. %s", + tdsErrorContext->err_text); + } + break; + case TDS_QUERY: /* Simple SQL BATCH */ + { + errcontext("TDS Protocol: Message Type: SQL BATCH, Phase: %s. %s", + tdsErrorContext->phase, + tdsErrorContext->err_text); + } + break; + 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); + } + break; + 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); + } + break; + case TDS_ATTENTION: /* Attention request */ + { + errcontext("TDS Protocol: Message Type: Attention, Phase: %s. %s", + tdsErrorContext->phase, + tdsErrorContext->err_text); + } + break; + default: + errcontext("TDS Protocol: %s", + tdsErrorContext->err_text); + } +} diff --git a/contrib/babelfishpg_tds/src/backend/tds/tdsxact.c b/contrib/babelfishpg_tds/src/backend/tds/tdsxact.c new file mode 100644 index 00000000000..2ec3e8e17a8 --- /dev/null +++ b/contrib/babelfishpg_tds/src/backend/tds/tdsxact.c @@ -0,0 +1,442 @@ +/*------------------------------------------------------------------------- + * + * tdsxact.c + * TDS Listener functions for handling Transaction requests + * + * Portions Copyright (c) 2020, AWS + * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * contrib/babelfishpg_tds/src/backend/tds/tdsxact.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "access/transam.h" +#include "nodes/parsenodes.h" +#include "pgstat.h" +#include "storage/proc.h" + +#include "src/include/tds_instr.h" +#include "src/include/tds_int.h" +#include "src/include/tds_request.h" +#include "src/include/tds_response.h" + +/* Transaction management request */ + +/* Transaction command types */ +#define TDS_TM_BEGIN_XACT 5 +#define TDS_TM_COMMIT_XACT 7 +#define TDS_TM_ROLLBACK_XACT 8 +#define TDS_TM_SAVEPOINT_XACT 9 + +/* Transaction isolation level */ +#define TDS_ISOLATION_LEVEL_NONE 0 +#define TDS_ISOLATION_LEVEL_READ_UNCOMMITTED 1 +#define TDS_ISOLATION_LEVEL_READ_COMMITTED 2 +#define TDS_ISOLATION_LEVEL_REPEATABLE_READ 3 +#define TDS_ISOLATION_LEVEL_SERIALIZABLE 4 +#define TDS_ISOLATION_LEVEL_SNAPSHOT 5 + +/* [A-Za-z\200-\377_\#] */ +static bool +IsValidIdentFirstChar(char ch) +{ + if ((ch >= 'a' && ch <= 'z') || + (ch >= 'A' && ch <= 'Z') || + (ch >= 0x80 && ch <= 0xff) || + (ch == '_') || (ch == '#')) + return true; + + return false; +} + +/* [A-Za-z\200-\377_0-9\$\#] */ +static bool +IsValidIdentChar(char ch) +{ + if (IsValidIdentFirstChar(ch) || + (ch >= '0' && ch <= '9') || + (ch == '$')) + return true; + + return false; +} + +static bool +IsValidTxnName(char *txnName, int len) +{ + if (len > 0 && IsValidIdentFirstChar(txnName[0])) + { + for(int i=1; i < len; ++i) + if (!IsValidIdentChar(txnName[i])) + return false; + return true; + } + return false; +} + +/* Get transaction name from transaction management request */ +static int +GetTxnName(const StringInfo message, TDSRequestTxnMgmt request, int offset) +{ + uint8_t len; + memcpy(&len, message->data + offset, sizeof(len)); + offset += sizeof(len); + + if (len != 0) + { + if (len > TSQL_TXN_NAME_LIMIT) + ereport(ERROR, + (errcode(ERRCODE_NAME_TOO_LONG), + errmsg("Transaction name length %u above limit %u", + len, TSQL_TXN_NAME_LIMIT))); + + initStringInfo(&(request->txnName)); + TdsUTF16toUTF8StringInfo(&(request->txnName), + message->data + offset, + len); + if (!IsValidTxnName(request->txnName.data, request->txnName.len)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_NAME), + errmsg("Transaction savepoint name is not valid"))); + + offset += len; + } + return offset; +} + +/* A new transaction request -> isolation level + txn name */ +static int +GetNewTxnRequest(const StringInfo message, + TDSRequestTxnMgmt request, + int offset) +{ + /* Transaction isolation level */ + memcpy(&(request->isolationLevel), + message->data + offset, + sizeof(request->isolationLevel)); + offset += sizeof(request->isolationLevel); + + if (request->isolationLevel > TDS_ISOLATION_LEVEL_SNAPSHOT) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("Invalid isolation level %u for transaction request", + request->isolationLevel))); + + return GetTxnName(message, request, offset); +} + +static const char * +GetIsolationLevelStr(uint8_t isolationLevel) +{ + switch(isolationLevel) + { + case TDS_ISOLATION_LEVEL_READ_UNCOMMITTED: + return "READ UNCOMMITTED "; + case TDS_ISOLATION_LEVEL_READ_COMMITTED: + return "READ COMMITTED "; + case TDS_ISOLATION_LEVEL_REPEATABLE_READ: + return "REPEATABLE READ "; + case TDS_ISOLATION_LEVEL_SERIALIZABLE: + return "SERIALIZABLE "; + case TDS_ISOLATION_LEVEL_SNAPSHOT: + return "SNAPSHOT "; + default: + return "UNKNOWN "; + } +} + +static void +BuildTxnMgmtRequestQuery(TDSRequest requestParam, StringInfo cmdStr) +{ + TDSRequestTxnMgmt request = (TDSRequestTxnMgmt) requestParam; + switch (request->txnReqType) + { + case TDS_TM_BEGIN_XACT: + { + appendStringInfoString(cmdStr, "BEGIN TRANSACTION "); + if (request->txnName.len != 0) + appendStringInfoString(cmdStr, request->txnName.data); + if (request->isolationLevel != TDS_ISOLATION_LEVEL_NONE) + { + appendStringInfoString(cmdStr, "; SET TRANSACTION ISOLATION LEVEL "); + appendStringInfoString(cmdStr, + GetIsolationLevelStr( + request->isolationLevel)); + } + } + break; + case TDS_TM_COMMIT_XACT: + case TDS_TM_ROLLBACK_XACT: + { + if (request->txnReqType == TDS_TM_COMMIT_XACT) + appendStringInfoString(cmdStr, "COMMIT TRANSACTION "); + else + appendStringInfoString(cmdStr, "ROLLBACK TRANSACTION "); + if (request->txnName.len != 0) + appendStringInfoString(cmdStr, request->txnName.data); + if (request->nextTxn != NULL) + { + appendStringInfoString(cmdStr, "; BEGIN TRANSACTION "); + if (request->nextTxn->txnName.len != 0) + appendStringInfoString(cmdStr, + request->nextTxn->txnName.data); + if (request->nextTxn->isolationLevel != + TDS_ISOLATION_LEVEL_NONE) + { + appendStringInfoString(cmdStr, "; SET TRANSACTION ISOLATION LEVEL "); + appendStringInfoString(cmdStr, + GetIsolationLevelStr( + request->nextTxn->isolationLevel)); + } + } + } + break; + case TDS_TM_SAVEPOINT_XACT: + { + appendStringInfoString(cmdStr, "SAVE TRANSACTION "); + appendStringInfoString(cmdStr, request->txnName.data); + } + break; + default: + break; + } +} + +TDSRequest +GetTxnMgmtRequest(const StringInfo message) +{ + 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. + */ + if (tdsVersion > TDS_VERSION_7_1_1) + txnReqOffset = ProcessStreamHeaders(message); + + /* Build return structure */ + request = palloc0(sizeof(TDSRequestTxnMgmtData)); + request->reqType = TDS_REQUEST_TXN_MGMT; + + /* Transaction request type */ + memcpy(&(request->txnReqType), + message->data + txnReqOffset, + sizeof(request->txnReqType)); + txnReqOffset += sizeof(request->txnReqType); + + switch (request->txnReqType) + { + case TDS_TM_BEGIN_XACT: + { + TdsErrorContext->txnType = "TM_BEGIN_XACT"; + txnReqOffset = GetNewTxnRequest(message, + request, + txnReqOffset); + TDS_DEBUG(TDS_DEBUG1, "message_type: Transaction Management Request (14) txn_request_type: TM_BEGIN_XACT"); + } + break; + case TDS_TM_COMMIT_XACT: + case TDS_TM_ROLLBACK_XACT: + { + if (request->txnReqType == TDS_TM_COMMIT_XACT) + { + TdsErrorContext->txnType = "TM_COMMIT_XACT"; + TDS_DEBUG(TDS_DEBUG1, "message_type: Transaction Management Request (14) txn_request_type: TM_COMMIT_XACT"); + } + else + { + TdsErrorContext->txnType = "TM_ROLLBACK_XACT"; + TDS_DEBUG(TDS_DEBUG1, "message_type: Transaction Management Request (14) txn_request_type: TM_ROLLBACK_XACT"); + } + txnReqOffset = GetTxnName(message, request, txnReqOffset); + + /* Transaction request flags */ + memcpy(&flags, message->data + txnReqOffset, sizeof(flags)); + txnReqOffset += sizeof(flags); + + /* Next transaction request */ + if (flags & 0x1) + { + request->nextTxn = palloc0(sizeof(TDSRequestTxnMgmtData)); + txnReqOffset = GetNewTxnRequest(message, + request->nextTxn, + txnReqOffset); + } + } + break; + case TDS_TM_SAVEPOINT_XACT: + { + TdsErrorContext->txnType = "TM_SAVEPOINT_XACT"; + txnReqOffset = GetTxnName(message, request, txnReqOffset); + if (request->txnName.len == 0) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("Savepoint request with empty name"))); + TDS_DEBUG(TDS_DEBUG1, "message_type: Transaction Management Request (14) txn_request_type: TM_SAVEPOINT_XACT"); + } + break; + default: + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("Transaction management request %u not supported", + request->txnReqType))); + break; + } + + if (txnReqOffset > message->len) + elog(FATAL, + "Transaction management request is corrupt," + "request length: %u request offset: %u", + message->len, txnReqOffset); + + /* Build the internal query corresponding to the txn request */ + initStringInfo(&(request->query)); + BuildTxnMgmtRequestQuery((TDSRequest)request, &(request->query)); + + pfree(message->data); + + return (TDSRequest)request; + +} + +void +ProcessTxnMgmtRequest(TDSRequest request) +{ + 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); + + TdsErrorContext->err_text = "Processing Transaction Management Request"; + req = (TDSRequestTxnMgmt)request; + + /* Only source text matters to handler */ + codeblock->source_text = req->query.data; + codeblock->langOid = 0; /* TODO does it matter */ + codeblock->langIsTrusted = true; + codeblock->atomic = false; + + /* Just to satisfy argument requirement */ + MemSet(fcinfo, 0, SizeForFunctionCallInfo(1)); + fcinfo->args[0].value = PointerGetDatum(codeblock); + fcinfo->args[0].isnull = false; + + pltsql_plugin_handler_ptr->sp_executesql_callback (fcinfo); + MemoryContextSwitchTo(MessageContext); + + /* + * XXX: For BEGIN, COMMIT AND ROLLBACK transaction commands, we send + * environment change tokens. Ideally, the tokens should be sent from + * pltsql extension itself so that even when we execute the above commands + * as SQL batch, the tokens are sent correctly. + */ + switch (req->txnReqType) + { + case TDS_TM_BEGIN_XACT: + { + activity = psprintf("TDS_TM_BEGIN_XACT: %s", req->query.data); + pgstat_report_activity(STATE_RUNNING, activity); + pfree(activity); + + cmd_type = TDS_CMD_BEGIN; + + /* + * Client expects new transaction id as part of ENV change + * token but BEGIN does not generate new id until a write + * command is executed. So BEGIN returns 0 as new transaction + * id. This is OK as transaction id has value in the context + * of MARS only (client sends it as part of transaction stream + * header). To support MARS, fix it. + */ + TdsSendEnvChangeBinary(TDS_ENVID_BEGINTXN, + &txnId, sizeof(uint64_t), + NULL, 0); + } + break; + case TDS_TM_COMMIT_XACT: + { + activity = psprintf("TDS_TM_COMMIT_XACT: %s", req->query.data); + pgstat_report_activity(STATE_RUNNING, activity); + pfree(activity); + + cmd_type = TDS_CMD_COMMIT; + + /* + * 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 = (uint64_t) MyProc->lxid; + TdsSendEnvChangeBinary(TDS_ENVID_BEGINTXN, + &txnId, sizeof(uint64_t), + NULL, 0); + } + } + break; + case TDS_TM_ROLLBACK_XACT: + { + activity = psprintf("TDS_TM_ROLLBACK_XACT: %s", req->query.data); + pgstat_report_activity(STATE_RUNNING, activity); + pfree(activity); + + cmd_type = TDS_CMD_ROLLBACK; + + /* + * As BEGIN commands sends 0 as new transaction id, ROLLBACK + * has to do the same thing. But, we don't send the token for + * ROLLBACK TO SAVEPOINT command. So if we've rolled back the + * top transaction, send the token. + */ + if (GetTopTransactionIdIfAny() == InvalidTransactionId) + TdsSendEnvChangeBinary(TDS_ENVID_ROLLBACKTXN, NULL, 0, + &txnId, sizeof(uint64_t)); + if(req->nextTxn != NULL) + { + txnId = (uint64_t) MyProc->lxid; + TdsSendEnvChangeBinary(TDS_ENVID_BEGINTXN, + &txnId, sizeof(uint64_t), + NULL, 0); + } + } + break; + default: + break; + } + + TdsSendDone(TDS_TOKEN_DONE, TDS_DONE_FINAL, cmd_type, 0); + pfree(codeblock); +} + +int +TestTxnMgmtRequest(TDSRequest request, const char *expectedStr) +{ + int res = 0; + StringInfoData cmdStr; + + Assert(request->reqType == TDS_REQUEST_TXN_MGMT); + initStringInfo(&cmdStr); + BuildTxnMgmtRequestQuery(request, &cmdStr); + res = strncmp(cmdStr.data, + expectedStr, + Min(cmdStr.len, strlen(expectedStr))); + pfree(cmdStr.data); + + return res; +} diff --git a/contrib/babelfishpg_tds/src/backend/utils/adt/README b/contrib/babelfishpg_tds/src/backend/utils/adt/README new file mode 100644 index 00000000000..d35db6e88e4 --- /dev/null +++ b/contrib/babelfishpg_tds/src/backend/utils/adt/README @@ -0,0 +1,62 @@ +contrib/babelfishpg_tds/backend/utils/adt/README + +We have copied some files from backend PostgreSQL code to utilize +some of the APIs defined in them. We have created our own wrapper +functions in TDS extension that make use of these APIs. + +1. numeric.c + + a. init_var + + Allocate memory to NumericVar variable. We utilize this in + converting the input string to numeric value in TDS receiver + side. + + b. set_var_from_str + + Parse a string and put the number into a numeric variable. + We utilize this in converting the input string to numeric + value in TDS receiver side. + + c. make_result + + Create the packed db numeric format in palloc()'d memory from + a variable (that we got from set_var_from_str()). We utilize + this in converting the input string to numeric value in TDS + receiver side. + + d. numeric_get_typmod + + Get precision and scale from numeric value. We need to send + both the precision and scale as part of column meta data + for numeric and decimal datatypes. + + e. free_var + + Free up memory used by NumericVar variable. We utilize this in + converting the input string to numeric value in TDS receiver + side. + +2. varchar.c + + a. varchar_input + + Convert input C string to SQL varchar(n). Used at TDS side to + convert NVarchar, NChar and NText values into Datum. + +3. xml.c + + a. xmlFreeDoc + + Free up structures used by a XML document when we convert + XML data to Datum at TDS side. + + b. xml_parse + + Check if input is well-formed XML data when we convert XML + data to Datum at TDS side. + + c. parse_xml_decl + + Parse XML decalaration when we convert XML data to Datum + at TDS side. \ No newline at end of file diff --git a/contrib/babelfishpg_tds/src/backend/utils/adt/numeric.c b/contrib/babelfishpg_tds/src/backend/utils/adt/numeric.c new file mode 100644 index 00000000000..3903e515a30 --- /dev/null +++ b/contrib/babelfishpg_tds/src/backend/utils/adt/numeric.c @@ -0,0 +1,786 @@ +/*------------------------------------------------------------------------- + * + * numeric.c + * An exact numeric data type for the Postgres database system + * + * Original coding 1998, Jan Wieck. Heavily revised 2003, Tom Lane. + * + * Many of the algorithmic ideas are borrowed from David M. Smith's "FM" + * multiple-precision math library, most recently published as Algorithm + * 786: Multiple-Precision Complex Arithmetic and Functions, ACM + * Transactions on Mathematical Software, Vol. 24, No. 4, December 1998, + * pages 359-367. + * + * Copyright (c) 1998-2018, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/backend/utils/adt/numeric.c + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include +#include +#include +#include + +#include "access/hash.h" +#include "catalog/pg_type.h" +#include "common/int.h" +#include "funcapi.h" +#include "lib/hyperloglog.h" +#include "libpq/pqformat.h" +#include "miscadmin.h" +#include "nodes/nodeFuncs.h" +#include "utils/array.h" +#include "utils/builtins.h" +#include "utils/guc.h" +#include "utils/int8.h" +#include "utils/numeric.h" +#include "utils/sortsupport.h" + +#include "src/include/tds_int.h" + +/* ---------- + * Uncomment the following to enable compilation of dump_numeric() + * and dump_var() and to get a dump of any result produced by make_result(). + * ---------- +#define NUMERIC_DEBUG + */ + + +/* ---------- + * Local data types + * + * Numeric values are represented in a base-NBASE floating point format. + * Each "digit" ranges from 0 to NBASE-1. The type NumericDigit is signed + * and wide enough to store a digit. We assume that NBASE*NBASE can fit in + * an int. Although the purely calculational routines could handle any even + * NBASE that's less than sqrt(INT_MAX), in practice we are only interested + * in NBASE a power of ten, so that I/O conversions and decimal rounding + * are easy. Also, it's actually more efficient if NBASE is rather less than + * sqrt(INT_MAX), so that there is "headroom" for mul_var and div_var_fast to + * postpone processing carries. + * + * Values of NBASE other than 10000 are considered of historical interest only + * and are no longer supported in any sense; no mechanism exists for the client + * to discover the base, so every client supporting binary mode expects the + * base-10000 format. If you plan to change this, also note the numeric + * abbreviation code, which assumes NBASE=10000. + * ---------- + */ + +#if 0 +#define NBASE 10 +#define HALF_NBASE 5 +#define DEC_DIGITS 1 /* decimal digits per NBASE digit */ +#define MUL_GUARD_DIGITS 4 /* these are measured in NBASE digits */ +#define DIV_GUARD_DIGITS 8 + +typedef signed char NumericDigit; +#endif + +#if 0 +#define NBASE 100 +#define HALF_NBASE 50 +#define DEC_DIGITS 2 /* decimal digits per NBASE digit */ +#define MUL_GUARD_DIGITS 3 /* these are measured in NBASE digits */ +#define DIV_GUARD_DIGITS 6 + +typedef signed char NumericDigit; +#endif + +#if 1 +#define NBASE 10000 +#define HALF_NBASE 5000 +#define DEC_DIGITS 4 /* decimal digits per NBASE digit */ +#define MUL_GUARD_DIGITS 2 /* these are measured in NBASE digits */ +#define DIV_GUARD_DIGITS 4 + +typedef int16 NumericDigit; +#endif + +/* + * The Numeric type as stored on disk. + * + * If the high bits of the first word of a NumericChoice (n_header, or + * n_short.n_header, or n_long.n_sign_dscale) are NUMERIC_SHORT, then the + * numeric follows the NumericShort format; if they are NUMERIC_POS or + * NUMERIC_NEG, it follows the NumericLong format. If they are NUMERIC_NAN, + * it is a NaN. We currently always store a NaN using just two bytes (i.e. + * only n_header), but previous releases used only the NumericLong format, + * so we might find 4-byte NaNs on disk if a database has been migrated using + * pg_upgrade. In either case, when the high bits indicate a NaN, the + * remaining bits are never examined. Currently, we always initialize these + * to zero, but it might be possible to use them for some other purpose in + * the future. + * + * In the NumericShort format, the remaining 14 bits of the header word + * (n_short.n_header) are allocated as follows: 1 for sign (positive or + * negative), 6 for dynamic scale, and 7 for weight. In practice, most + * commonly-encountered values can be represented this way. + * + * In the NumericLong format, the remaining 14 bits of the header word + * (n_long.n_sign_dscale) represent the display scale; and the weight is + * stored separately in n_weight. + * + * NOTE: by convention, values in the packed form have been stripped of + * all leading and trailing zero digits (where a "digit" is of base NBASE). + * In particular, if the value is zero, there will be no digits at all! + * The weight is arbitrary in that case, but we normally set it to zero. + */ + +struct NumericShort +{ + uint16 n_header; /* Sign + display scale + weight */ + NumericDigit n_data[FLEXIBLE_ARRAY_MEMBER]; /* Digits */ +}; + +struct NumericLong +{ + uint16 n_sign_dscale; /* Sign + display scale */ + int16 n_weight; /* Weight of 1st digit */ + NumericDigit n_data[FLEXIBLE_ARRAY_MEMBER]; /* Digits */ +}; + +union NumericChoice +{ + uint16 n_header; /* Header word */ + struct NumericLong n_long; /* Long form (4-byte header) */ + struct NumericShort n_short; /* Short form (2-byte header) */ +}; + +struct NumericData +{ + int32 vl_len_; /* varlena header (do not touch directly!) */ + union NumericChoice choice; /* choice of format */ +}; + + +/* + * Interpretation of high bits. + */ + +#define NUMERIC_SIGN_MASK 0xC000 +#define NUMERIC_POS 0x0000 +#define NUMERIC_NEG 0x4000 +#define NUMERIC_SHORT 0x8000 +#define NUMERIC_NAN 0xC000 + +#define NUMERIC_FLAGBITS(n) ((n)->choice.n_header & NUMERIC_SIGN_MASK) +#define NUMERIC_IS_NAN(n) (NUMERIC_FLAGBITS(n) == NUMERIC_NAN) +#define NUMERIC_IS_SHORT(n) (NUMERIC_FLAGBITS(n) == NUMERIC_SHORT) + +#define NUMERIC_HDRSZ (VARHDRSZ + sizeof(uint16) + sizeof(int16)) +#define NUMERIC_HDRSZ_SHORT (VARHDRSZ + sizeof(uint16)) + +/* + * If the flag bits are NUMERIC_SHORT or NUMERIC_NAN, we want the short header; + * otherwise, we want the long one. Instead of testing against each value, we + * can just look at the high bit, for a slight efficiency gain. + */ +#define NUMERIC_HEADER_IS_SHORT(n) (((n)->choice.n_header & 0x8000) != 0) +#define NUMERIC_HEADER_SIZE(n) \ + (VARHDRSZ + sizeof(uint16) + \ + (NUMERIC_HEADER_IS_SHORT(n) ? 0 : sizeof(int16))) + +/* + * Short format definitions. + */ + +#define NUMERIC_SHORT_SIGN_MASK 0x2000 +#define NUMERIC_SHORT_DSCALE_MASK 0x1F80 +#define NUMERIC_SHORT_DSCALE_SHIFT 7 +#define NUMERIC_SHORT_DSCALE_MAX \ + (NUMERIC_SHORT_DSCALE_MASK >> NUMERIC_SHORT_DSCALE_SHIFT) +#define NUMERIC_SHORT_WEIGHT_SIGN_MASK 0x0040 +#define NUMERIC_SHORT_WEIGHT_MASK 0x003F +#define NUMERIC_SHORT_WEIGHT_MAX NUMERIC_SHORT_WEIGHT_MASK +#define NUMERIC_SHORT_WEIGHT_MIN (-(NUMERIC_SHORT_WEIGHT_MASK+1)) + +/* + * Extract sign, display scale, weight. + */ + +#define NUMERIC_DSCALE_MASK 0x3FFF + +#define NUMERIC_SIGN(n) \ + (NUMERIC_IS_SHORT(n) ? \ + (((n)->choice.n_short.n_header & NUMERIC_SHORT_SIGN_MASK) ? \ + NUMERIC_NEG : NUMERIC_POS) : NUMERIC_FLAGBITS(n)) +#define NUMERIC_DSCALE(n) (NUMERIC_HEADER_IS_SHORT((n)) ? \ + ((n)->choice.n_short.n_header & NUMERIC_SHORT_DSCALE_MASK) \ + >> NUMERIC_SHORT_DSCALE_SHIFT \ + : ((n)->choice.n_long.n_sign_dscale & NUMERIC_DSCALE_MASK)) +#define NUMERIC_WEIGHT(n) (NUMERIC_HEADER_IS_SHORT((n)) ? \ + (((n)->choice.n_short.n_header & NUMERIC_SHORT_WEIGHT_SIGN_MASK ? \ + ~NUMERIC_SHORT_WEIGHT_MASK : 0) \ + | ((n)->choice.n_short.n_header & NUMERIC_SHORT_WEIGHT_MASK)) \ + : ((n)->choice.n_long.n_weight)) + +/* ---------- + * NumericVar is the format we use for arithmetic. The digit-array part + * is the same as the NumericData storage format, but the header is more + * complex. + * + * The value represented by a NumericVar is determined by the sign, weight, + * ndigits, and digits[] array. + * + * Note: the first digit of a NumericVar's value is assumed to be multiplied + * by NBASE ** weight. Another way to say it is that there are weight+1 + * digits before the decimal point. It is possible to have weight < 0. + * + * buf points at the physical start of the palloc'd digit buffer for the + * NumericVar. digits points at the first digit in actual use (the one + * with the specified weight). We normally leave an unused digit or two + * (preset to zeroes) between buf and digits, so that there is room to store + * a carry out of the top digit without reallocating space. We just need to + * decrement digits (and increment weight) to make room for the carry digit. + * (There is no such extra space in a numeric value stored in the database, + * only in a NumericVar in memory.) + * + * If buf is NULL then the digit buffer isn't actually palloc'd and should + * not be freed --- see the constants below for an example. + * + * dscale, or display scale, is the nominal precision expressed as number + * of digits after the decimal point (it must always be >= 0 at present). + * dscale may be more than the number of physically stored fractional digits, + * implying that we have suppressed storage of significant trailing zeroes. + * It should never be less than the number of stored digits, since that would + * imply hiding digits that are present. NOTE that dscale is always expressed + * in *decimal* digits, and so it may correspond to a fractional number of + * base-NBASE digits --- divide by DEC_DIGITS to convert to NBASE digits. + * + * rscale, or result scale, is the target precision for a computation. + * Like dscale it is expressed as number of *decimal* digits after the decimal + * point, and is always >= 0 at present. + * Note that rscale is not stored in variables --- it's figured on-the-fly + * from the dscales of the inputs. + * + * While we consistently use "weight" to refer to the base-NBASE weight of + * a numeric value, it is convenient in some scale-related calculations to + * make use of the base-10 weight (ie, the approximate log10 of the value). + * To avoid confusion, such a decimal-units weight is called a "dweight". + * + * NB: All the variable-level functions are written in a style that makes it + * possible to give one and the same variable as argument and destination. + * This is feasible because the digit buffer is separate from the variable. + * ---------- + */ +typedef struct NumericVar +{ + int ndigits; /* # of digits in digits[] - can be 0! */ + int weight; /* weight of first digit */ + int sign; /* NUMERIC_POS, NUMERIC_NEG, or NUMERIC_NAN */ + int dscale; /* display scale */ + NumericDigit *buf; /* start of palloc'd space for digits[] */ + NumericDigit *digits; /* base-NBASE digits */ +} NumericVar; + + +/* ---------- + * Data for generate_series + * ---------- + */ +typedef struct +{ + NumericVar current; + NumericVar stop; + NumericVar step; +} generate_series_numeric_fctx; + + +/* ---------- + * Sort support. + * ---------- + */ +typedef struct +{ + void *buf; /* buffer for short varlenas */ + int64 input_count; /* number of non-null values seen */ + bool estimating; /* true if estimating cardinality */ + + hyperLogLogState abbr_card; /* cardinality estimator */ +} NumericSortSupport; + + +/* ---------- + * Fast sum accumulator. + * + * NumericSumAccum is used to implement SUM(), and other standard aggregates + * that track the sum of input values. It uses 32-bit integers to store the + * digits, instead of the normal 16-bit integers (with NBASE=10000). This + * way, we can safely accumulate up to NBASE - 1 values without propagating + * carry, before risking overflow of any of the digits. 'num_uncarried' + * tracks how many values have been accumulated without propagating carry. + * + * Positive and negative values are accumulated separately, in 'pos_digits' + * and 'neg_digits'. This is simpler and faster than deciding whether to add + * or subtract from the current value, for each new value (see sub_var() for + * the logic we avoid by doing this). Both buffers are of same size, and + * have the same weight and scale. In accum_sum_final(), the positive and + * negative sums are added together to produce the final result. + * + * When a new value has a larger ndigits or weight than the accumulator + * currently does, the accumulator is enlarged to accommodate the new value. + * We normally have one zero digit reserved for carry propagation, and that + * is indicated by the 'have_carry_space' flag. When accum_sum_carry() uses + * up the reserved digit, it clears the 'have_carry_space' flag. The next + * call to accum_sum_add() will enlarge the buffer, to make room for the + * extra digit, and set the flag again. + * + * To initialize a new accumulator, simply reset all fields to zeros. + * + * The accumulator does not handle NaNs. + * ---------- + */ +typedef struct NumericSumAccum +{ + int ndigits; + int weight; + int dscale; + int num_uncarried; + bool have_carry_space; + int32 *pos_digits; + int32 *neg_digits; +} NumericSumAccum; + + +/* + * We define our own macros for packing and unpacking abbreviated-key + * representations for numeric values in order to avoid depending on + * USE_FLOAT8_BYVAL. The type of abbreviation we use is based only on + * the size of a datum, not the argument-passing convention for float8. + */ +#define NUMERIC_ABBREV_BITS (SIZEOF_DATUM * BITS_PER_BYTE) +#if SIZEOF_DATUM == 8 +#define NumericAbbrevGetDatum(X) ((Datum) (X)) +#define DatumGetNumericAbbrev(X) ((int64) (X)) +#define NUMERIC_ABBREV_NAN NumericAbbrevGetDatum(PG_INT64_MIN) +#else +#define NumericAbbrevGetDatum(X) ((Datum) (X)) +#define DatumGetNumericAbbrev(X) ((int32) (X)) +#define NUMERIC_ABBREV_NAN NumericAbbrevGetDatum(PG_INT32_MIN) +#endif + +/* ---------- + * Local functions + * ---------- + */ + +#ifdef NUMERIC_DEBUG +static void dump_numeric(const char *str, Numeric num); +static void dump_var(const char *str, NumericVar *var); +#else +#define dump_numeric(s,n) +#define dump_var(s,v) +#endif + +#define digitbuf_alloc(ndigits) \ + ((NumericDigit *) palloc((ndigits) * sizeof(NumericDigit))) +#define digitbuf_free(buf) \ + do { \ + if ((buf) != NULL) \ + pfree(buf); \ + } while (0) + +#define init_var(v) MemSetAligned(v, 0, sizeof(NumericVar)) + +#define NUMERIC_DIGITS(num) (NUMERIC_HEADER_IS_SHORT(num) ? \ + (num)->choice.n_short.n_data : (num)->choice.n_long.n_data) +#define NUMERIC_NDIGITS(num) \ + ((VARSIZE(num) - NUMERIC_HEADER_SIZE(num)) / sizeof(NumericDigit)) +#define NUMERIC_CAN_BE_SHORT(scale,weight) \ + ((scale) <= NUMERIC_SHORT_DSCALE_MAX && \ + (weight) <= NUMERIC_SHORT_WEIGHT_MAX && \ + (weight) >= NUMERIC_SHORT_WEIGHT_MIN) + +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); +static Numeric make_result(const NumericVar *var); +static void strip_var(NumericVar *var); + +/* ---------------------------------------------------------------------- + * + * Local functions follow + * + * In general, these do not support NaNs --- callers must eliminate + * the possibility of NaN first. (make_result() is an exception.) + * + * ---------------------------------------------------------------------- + */ + + +/* + * alloc_var() - + * + * Allocate a digit buffer of ndigits digits (plus a spare digit for rounding) + */ +static void +alloc_var(NumericVar *var, int ndigits) +{ + digitbuf_free(var->buf); + var->buf = digitbuf_alloc(ndigits + 1); + var->buf[0] = 0; /* spare digit for rounding */ + var->digits = var->buf + 1; + var->ndigits = ndigits; +} + + +/* + * free_var() - + * + * Return the digit buffer of a variable to the free pool + */ +static void +free_var(NumericVar *var) +{ + digitbuf_free(var->buf); + var->buf = NULL; + var->digits = NULL; + var->sign = NUMERIC_NAN; +} + +/* + * set_var_from_str() + * + * Parse a string and put the number into a variable + * + * This function does not handle leading or trailing spaces, and it doesn't + * accept "NaN" either. It returns the end+1 position so that caller can + * check for trailing spaces/garbage if deemed necessary. + * + * cp is the place to actually start parsing; str is what to use in error + * reports. (Typically cp would be the same except advanced over spaces.) + */ +static const char * +set_var_from_str(const char *str, const char *cp, NumericVar *dest) +{ + bool have_dp = false; + int i; + unsigned char *decdigits; + int sign = NUMERIC_POS; + int dweight = -1; + int ddigits; + int dscale = 0; + int weight; + int ndigits; + int offset; + NumericDigit *digits; + + /* + * We first parse the string to extract decimal digits and determine the + * correct decimal weight. Then convert to NBASE representation. + */ + switch (*cp) + { + case '+': + sign = NUMERIC_POS; + cp++; + break; + + case '-': + sign = NUMERIC_NEG; + cp++; + break; + } + + if (*cp == '.') + { + have_dp = true; + cp++; + } + + if (!isdigit((unsigned char) *cp)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for type %s: \"%s\"", + "numeric", str))); + + decdigits = (unsigned char *) palloc(strlen(cp) + DEC_DIGITS * 2); + + /* leading padding for digit alignment later */ + memset(decdigits, 0, DEC_DIGITS); + i = DEC_DIGITS; + + while (*cp) + { + if (isdigit((unsigned char) *cp)) + { + decdigits[i++] = *cp++ - '0'; + if (!have_dp) + dweight++; + else + dscale++; + } + else if (*cp == '.') + { + if (have_dp) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for type %s: \"%s\"", + "numeric", str))); + have_dp = true; + cp++; + } + else + break; + } + + ddigits = i - DEC_DIGITS; + /* trailing padding for digit alignment later */ + memset(decdigits + i, 0, DEC_DIGITS - 1); + + /* Handle exponent, if any */ + if (*cp == 'e' || *cp == 'E') + { + long exponent; + char *endptr; + + cp++; + exponent = strtol(cp, &endptr, 10); + if (endptr == cp) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for type %s: \"%s\"", + "numeric", str))); + cp = endptr; + + /* + * At this point, dweight and dscale can't be more than about + * INT_MAX/2 due to the MaxAllocSize limit on string length, so + * constraining the exponent similarly should be enough to prevent + * integer overflow in this function. If the value is too large to + * fit in storage format, make_result() will complain about it later; + * for consistency use the same ereport errcode/text as make_result(). + */ + if (exponent >= INT_MAX / 2 || exponent <= -(INT_MAX / 2)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("value overflows numeric format"))); + dweight += (int) exponent; + dscale -= (int) exponent; + if (dscale < 0) + dscale = 0; + } + + /* + * Okay, convert pure-decimal representation to base NBASE. First we need + * to determine the converted weight and ndigits. offset is the number of + * decimal zeroes to insert before the first given digit to have a + * correctly aligned first NBASE digit. + */ + if (dweight >= 0) + weight = (dweight + 1 + DEC_DIGITS - 1) / DEC_DIGITS - 1; + else + weight = -((-dweight - 1) / DEC_DIGITS + 1); + offset = (weight + 1) * DEC_DIGITS - (dweight + 1); + ndigits = (ddigits + offset + DEC_DIGITS - 1) / DEC_DIGITS; + + alloc_var(dest, ndigits); + dest->sign = sign; + dest->weight = weight; + dest->dscale = dscale; + + i = DEC_DIGITS - offset; + digits = dest->digits; + + while (ndigits-- > 0) + { +#if DEC_DIGITS == 4 + *digits++ = ((decdigits[i] * 10 + decdigits[i + 1]) * 10 + + decdigits[i + 2]) * 10 + decdigits[i + 3]; +#elif DEC_DIGITS == 2 + *digits++ = decdigits[i] * 10 + decdigits[i + 1]; +#elif DEC_DIGITS == 1 + *digits++ = decdigits[i]; +#else +#error unsupported NBASE +#endif + i += DEC_DIGITS; + } + + pfree(decdigits); + + /* Strip any leading/trailing zeroes, and normalize weight if zero */ + strip_var(dest); + + /* Return end+1 position for caller */ + return cp; +} + +/* + * make_result() - + * + * Create the packed db numeric format in palloc()'d memory from + * a variable. + */ +static Numeric +make_result(const NumericVar *var) +{ + Numeric result; + NumericDigit *digits = var->digits; + int weight = var->weight; + int sign = var->sign; + int n; + Size len; + + if (sign == NUMERIC_NAN) + { + result = (Numeric) palloc(NUMERIC_HDRSZ_SHORT); + + SET_VARSIZE(result, NUMERIC_HDRSZ_SHORT); + result->choice.n_header = NUMERIC_NAN; + /* the header word is all we need */ + + dump_numeric("make_result()", result); + return result; + } + + n = var->ndigits; + + /* truncate leading zeroes */ + while (n > 0 && *digits == 0) + { + digits++; + weight--; + n--; + } + /* truncate trailing zeroes */ + while (n > 0 && digits[n - 1] == 0) + n--; + + /* If zero result, force to weight=0 and positive sign */ + if (n == 0) + { + weight = 0; + sign = NUMERIC_POS; + } + + /* Build the result */ + if (NUMERIC_CAN_BE_SHORT(var->dscale, weight)) + { + len = NUMERIC_HDRSZ_SHORT + n * sizeof(NumericDigit); + result = (Numeric) palloc(len); + SET_VARSIZE(result, len); + result->choice.n_short.n_header = + (sign == NUMERIC_NEG ? (NUMERIC_SHORT | NUMERIC_SHORT_SIGN_MASK) + : NUMERIC_SHORT) + | (var->dscale << NUMERIC_SHORT_DSCALE_SHIFT) + | (weight < 0 ? NUMERIC_SHORT_WEIGHT_SIGN_MASK : 0) + | (weight & NUMERIC_SHORT_WEIGHT_MASK); + } + else + { + len = NUMERIC_HDRSZ + n * sizeof(NumericDigit); + result = (Numeric) palloc(len); + SET_VARSIZE(result, len); + result->choice.n_long.n_sign_dscale = + sign | (var->dscale & NUMERIC_DSCALE_MASK); + result->choice.n_long.n_weight = weight; + } + + Assert(NUMERIC_NDIGITS(result) == n); + if (n > 0) + memcpy(NUMERIC_DIGITS(result), digits, n * sizeof(NumericDigit)); + + /* Check for overflow of int16 fields */ + if (NUMERIC_WEIGHT(result) != weight || + NUMERIC_DSCALE(result) != var->dscale) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("value overflows numeric format"))); + + dump_numeric("make_result()", result); + return result; +} + +/* + * strip_var + * + * Strip any leading and trailing zeroes from a numeric variable + */ +static void +strip_var(NumericVar *var) +{ + NumericDigit *digits = var->digits; + int ndigits = var->ndigits; + + /* Strip leading zeroes */ + while (ndigits > 0 && *digits == 0) + { + digits++; + var->weight--; + ndigits--; + } + + /* Strip trailing zeroes */ + while (ndigits > 0 && digits[ndigits - 1] == 0) + ndigits--; + + /* If it's zero, normalize the sign and weight */ + if (ndigits == 0) + { + var->sign = NUMERIC_POS; + var->weight = 0; + } + + var->digits = digits; + var->ndigits = ndigits; +} + +/* + * Converts input string to numeric value in TDS receiver side + */ +Numeric +TdsSetVarFromStrWrapper(const char *str) +{ + NumericVar value; + Numeric res; + init_var(&value); + set_var_from_str(str, str, &value); + res = make_result(&value); + free_var(&value); + 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; + + if (weight >= 0) + { + static const int32 timescales[DEC_DIGITS] = { + 1000, + 100, + 10, + 1, + }; + int leading_digits = NUMERIC_DIGITS(num)[0]; + precision = weight * DEC_DIGITS + scale; + + for(int i = 0; i < DEC_DIGITS; i++) + { + if(leading_digits >= timescales[i]) + { + precision += (4-i); + break; + } + } + } + else + /* weight < 0 means the integral part of the number is 0 */ + precision = 1 + scale; + + 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 new file mode 100644 index 00000000000..e9cab2f44b0 --- /dev/null +++ b/contrib/babelfishpg_tds/src/backend/utils/adt/varchar.c @@ -0,0 +1,109 @@ +/*------------------------------------------------------------------------- + * + * varchar.c + * Functions for the built-in types char(n) and varchar(n). + * + * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/utils/adt/varchar.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + + +#include "access/hash.h" +#include "catalog/pg_collation.h" +#include "libpq/pqformat.h" +#include "nodes/nodeFuncs.h" +#include "parser/parser.h" /* only needed for GUC variables */ +#include "utils/array.h" +#include "utils/builtins.h" +#include "utils/varlena.h" +#include "mb/pg_wchar.h" + +#include "src/include/tds_int.h" + +static inline void +CheckUTF16Length(const char *utf8_str, size_t len, size_t maxlen, + char *varstr) +{ + int i; + + if (sql_dialect == SQL_DIALECT_TSQL) + { + for (i = len; i > 0; i--) + if (utf8_str[i - 1] != ' ') + break; + if (TdsUTF8LengthInUTF16(utf8_str, i) > maxlen) + ereport(ERROR, + (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION), + errmsg("value too long for type character%s(%d) " + "as UTF16 output", + varstr, (int)maxlen))); + } +} + +/***************************************************************************** + * varchar - varchar(n) + * + * Note: varchar piggybacks on type text for most operations, and so has no + * C-coded functions except for I/O and typmod checking. + *****************************************************************************/ + +/* + * varchar_input -- common guts of varcharin and varcharrecv + * + * s is the input text of length len (may not be null-terminated) + * atttypmod is the typmod value to apply + * + * Note that atttypmod is measured in characters, which + * is not necessarily the same as the number of bytes. + * + * If the input string is too long, raise an error, unless the extra + * characters are spaces, in which case they're truncated. (per SQL) + * + * Uses the C string to text conversion function, which is only appropriate + * if VarChar and text are equivalent types. + */ +static VarChar * +varchar_input(const char *s, size_t len, int32 atttypmod) +{ + VarChar *result; + size_t maxlen; + + maxlen = atttypmod - VARHDRSZ; + + if (atttypmod >= (int32) VARHDRSZ && len > maxlen) + { + /* Verify that extra characters are spaces, and clip them off */ + size_t mbmaxlen = pg_mbcharcliplen(s, len, maxlen); + size_t j; + + for (j = mbmaxlen; j < len; j++) + { + if (s[j] != ' ') + ereport(ERROR, + (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION), + errmsg("value too long for type character varying(%d)", + (int) maxlen))); + } + + len = mbmaxlen; + } + + if (atttypmod >= (int32) VARHDRSZ) + CheckUTF16Length(s, len, maxlen, " varying"); + + result = (VarChar *) cstring_to_text_with_len(s, len); + return result; +} + +void * +tds_varchar_input(const char *s, size_t len, int32 atttypmod) +{ + return varchar_input(s, len, atttypmod); +} diff --git a/contrib/babelfishpg_tds/src/backend/utils/adt/xml.c b/contrib/babelfishpg_tds/src/backend/utils/adt/xml.c new file mode 100644 index 00000000000..ad1a6899929 --- /dev/null +++ b/contrib/babelfishpg_tds/src/backend/utils/adt/xml.c @@ -0,0 +1,738 @@ +/*------------------------------------------------------------------------- + * + * xml.c + * XML data type support. + * + * + * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/backend/utils/adt/xml.c + * + *------------------------------------------------------------------------- + */ + +/* + * Generally, XML type support is only available when libxml use was + * configured during the build. But even if that is not done, the + * type and all the functions are available, but most of them will + * fail. For one thing, this avoids having to manage variant catalog + * installations. But it also has nice effects such as that you can + * dump a database containing XML type data even if the server is not + * linked with libxml. Thus, make sure xml_out() works even if nothing + * else does. + */ + +/* + * Notes on memory management: + * + * Sometimes libxml allocates global structures in the hope that it can reuse + * them later on. This makes it impractical to change the xmlMemSetup + * functions on-the-fly; that is likely to lead to trying to pfree() chunks + * allocated with malloc() or vice versa. Since libxml might be used by + * loadable modules, eg libperl, our only safe choices are to change the + * functions at postmaster/backend launch or not at all. Since we'd rather + * not activate libxml in sessions that might never use it, the latter choice + * is the preferred one. However, for debugging purposes it can be awfully + * handy to constrain libxml's allocations to be done in a specific palloc + * context, where they're easy to track. Therefore there is code here that + * can be enabled in debug builds to redirect libxml's allocations into a + * special context LibxmlContext. It's not recommended to turn this on in + * a production build because of the possibility of bad interactions with + * external modules. + */ +/* #define USE_LIBXMLCONTEXT */ + +#include "postgres.h" + +#ifdef USE_LIBXML +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 + * testing the library version number. + */ +#if LIBXML_VERSION >= 20704 +#define HAVE_XMLSTRUCTUREDERRORCONTEXT 1 +#endif +#endif /* USE_LIBXML */ + +#include "access/htup_details.h" +#include "catalog/namespace.h" +#include "catalog/pg_class.h" +#include "catalog/pg_type.h" +#include "commands/dbcommands.h" +#include "executor/spi.h" +#include "executor/tablefunc.h" +#include "fmgr.h" +#include "lib/stringinfo.h" +#include "libpq/pqformat.h" +#include "mb/pg_wchar.h" +#include "miscadmin.h" +#include "nodes/execnodes.h" +#include "nodes/nodeFuncs.h" +#include "utils/array.h" +#include "utils/builtins.h" +#include "utils/date.h" +#include "utils/datetime.h" +#include "utils/lsyscache.h" +#include "utils/memutils.h" +#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; + /* strictness argument passed to pg_xml_init */ + PgXmlStrictness strictness; + /* current error status and accumulated message, if any */ + bool err_occurred; + StringInfoData err_buf; + /* previous libxml error handling state (saved by pg_xml_init) */ + xmlStructuredErrorFunc saved_errfunc; + void *saved_errcxt; + /* previous libxml entity handler (saved by pg_xml_init) */ + xmlExternalEntityLoader saved_entityfunc; +}; + +static void xml_ereport_by_code(int level, int sqlcode, + 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 bool xml_doctype_in_content(const xmlChar *str); +static xmlDocPtr xml_parse(text *data, XmlOptionType xmloption_arg, + bool preserve_whitespace, int encoding); +#endif /* USE_LIBXML */ + +/* XMLTABLE support */ +#ifdef USE_LIBXML +/* random number to identify XmlTableContext */ +#define XMLTABLE_CONTEXT_MAGIC 46922182 +typedef struct XmlTableBuilderData +{ + int magic; + int natts; + long int row_count; + PgXmlErrorContext *xmlerrcxt; + xmlParserCtxtPtr ctxt; + xmlDocPtr doc; + xmlXPathContextPtr xpathcxt; + xmlXPathCompExprPtr xpathcomp; + xmlXPathObjectPtr xpathobj; + xmlXPathCompExprPtr *xpathscomp; +} 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 + * easily by libxml. "XML content" is specified by SQL/XML as the + * production "XMLDecl? content". But libxml can only parse the + * "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) \ + (xmlIsBaseChar_ch(c) || xmlIsIdeographicQ(c) \ + || xmlIsDigit_ch(c) \ + || 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. + * version and encoding are returned as locally-palloc'd strings. + * Result is 0 if OK, an error code if not. + */ +static int +parse_xml_decl(const xmlChar *str, size_t *lenp, + xmlChar **version, xmlChar **encoding, int *standalone) +{ + const xmlChar *p; + const xmlChar *save_p; + 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 + * functions. Note that this is safe (and a no-op) if caller has already + * done pg_xml_init(). + */ + pg_xml_init_library(); + + /* Initialize output arguments to "not present" */ + if (version) + *version = NULL; + if (encoding) + *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 + * XMLDecl. + * + * We need an input length value for xmlGetUTF8Char, but there's no need + * to count the whole document size, so use strnlen not strlen. + */ + utf8len = strnlen((const char *) (p + 5), MAX_MULTIBYTE_CHAR_LEN); + utf8char = xmlGetUTF8Char(p + 5, &utf8len); + if (PG_XMLISNAMECHAR(utf8char)) + goto finished; + + p += 5; + + /* version */ + CHECK_XML_SPACE(p); + SKIP_XML_SPACE(p); + if (xmlStrncmp(p, (xmlChar *) "version", 7) != 0) + return XML_ERR_VERSION_MISSING; + p += 7; + SKIP_XML_SPACE(p); + if (*p != '=') + 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); + if (xmlStrncmp(p, (xmlChar *) "encoding", 8) == 0) + { + CHECK_XML_SPACE(save_p); + p += 8; + SKIP_XML_SPACE(p); + if (*p != '=') + 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; + } + else + return XML_ERR_MISSING_ENCODING; + } + else + { + p = save_p; + } + + /* standalone */ + save_p = p; + SKIP_XML_SPACE(p); + if (xmlStrncmp(p, (xmlChar *) "standalone", 10) == 0) + { + CHECK_XML_SPACE(save_p); + p += 10; + SKIP_XML_SPACE(p); + if (*p != '=') + return XML_ERR_STANDALONE_VALUE; + p += 1; + SKIP_XML_SPACE(p); + if (xmlStrncmp(p, (xmlChar *) "'yes'", 5) == 0 || + xmlStrncmp(p, (xmlChar *) "\"yes\"", 5) == 0) + { + if (standalone) + *standalone = 1; + p += 5; + } + else if (xmlStrncmp(p, (xmlChar *) "'no'", 4) == 0 || + xmlStrncmp(p, (xmlChar *) "\"no\"", 4) == 0) + { + if (standalone) + *standalone = 0; + p += 4; + } + else + return XML_ERR_STANDALONE_VALUE; + } + else + { + 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. + * + * The SQL/XML:2003 definition of CONTENT ("XMLDecl? content") is not + * satisfied by a document with a DTD, which is a bit of a wart, as it means + * the CONTENT type is not a proper superset of DOCUMENT. SQL/XML:2006 and + * later fix that, by redefining content with reference to the "more + * permissive" Document Node of the XQuery/XPath Data Model, such that any + * DOCUMENT value is indeed also a CONTENT value. That definition is more + * useful, as CONTENT becomes usable for parsing input of unknown form (think + * pg_restore). + * + * As used below in parse_xml when parsing for CONTENT, libxml does not give + * us the 2006+ behavior, but only the 2003; it will choke if the input has + * a DTD. But we can provide the 2006+ definition of CONTENT easily enough, + * by detecting this case first and simply doing the parse as DOCUMENT. + * + * A DTD can be found arbitrarily far in, but that would be a contrived case; + * it will ordinarily start within a few dozen characters. The only things + * that can precede it are an XMLDecl (here, the caller will have called + * parse_xml_decl already), whitespace, comments, and processing instructions. + * This function need only return true if it sees a valid sequence of such + * things leading to must follow */ + p = xmlStrstr(p + 2, (xmlChar *) "--"); + if (!p || p[2] != '>') + return false; + /* advance over comment, and keep scanning */ + p += 3; + continue; + } + + /* otherwise, if it's not a PI , 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 + * + * Note: it is caller's responsibility to xmlFreeDoc() the result, + * else a permanent memory leak will ensue! + * + * TODO maybe libxml2's xmlreader is better? (do not construct DOM, + * yet do not use SAX - see xmlreader.c) + */ +static xmlDocPtr +xml_parse(text *data, XmlOptionType xmloption_arg, bool preserve_whitespace, + int encoding) +{ + int32 len; + xmlChar *string; + xmlChar *utf8string; + 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(); + { + bool parse_as_document = false; + int res_code; + 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; + else + { + /* Parse and skip over the XML declaration, if any */ + res_code = parse_xml_decl(utf8string, + &count, &version, NULL, &standalone); + if (res_code != 0) + 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) + { + /* + * Note, that here we try to apply DTD defaults + * (XML_PARSE_DTDATTR) according to SQL/XML:2008 GR 10.16.7.d: + * 'Default values defined by internal DTD are applied'. As for + * external DTDs, we try to support them too, (see SQL/XML:2008 GR + * 10.16.7.e) + */ + doc = xmlCtxtReadDoc(ctxt, utf8string, + NULL, + "UTF-8", + XML_PARSE_NOENT | XML_PARSE_DTDATTR + | (preserve_whitespace ? 0 : XML_PARSE_NOBLANKS)); + if (doc == NULL || xmlerrcxt->err_occurred) + { + /* Use original option to decide which error code to throw */ + if (xmloption_arg == XMLOPTION_DOCUMENT) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_INVALID_XML_DOCUMENT, + "invalid XML document"); + else + xml_ereport(xmlerrcxt, ERROR, ERRCODE_INVALID_XML_CONTENT, + "invalid XML content"); + } + } + else + { + doc = xmlNewDoc(version); + Assert(doc->encoding == NULL); + doc->encoding = xmlStrdup((const xmlChar *) "UTF-8"); + doc->standalone = standalone; + + /* allow empty content */ + if (*(utf8string + count)) + { + res_code = xmlParseBalancedChunkMemory(doc, NULL, NULL, 0, + utf8string + count, NULL); + if (res_code != 0 || xmlerrcxt->err_occurred) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_INVALID_XML_CONTENT, + "invalid XML content"); + } + } + } + PG_CATCH(); + { + if (doc != NULL) + 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 + */ +static xmlChar * +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) + */ +static void +xml_memory_init(void) +{ + /* Create memory context if not there already */ + if (LibxmlContext == NULL) + 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 + */ +static void * +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) +{ + /* At least some parts of libxml assume xmlFree(NULL) is allowed */ + 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 + * standard. This function uses "code" to create a textual detail + * message. At the moment, we only need to cover those codes that we + * may raise in this file. + */ +static void +xml_ereport_by_code(int level, int sqlcode, + const char *msg, int code) +{ + const char *det; + + switch (code) + { + case XML_ERR_INVALID_CHAR: + det = gettext_noop("Invalid character value."); + break; + case XML_ERR_SPACE_REQUIRED: + det = gettext_noop("Space required."); + break; + case XML_ERR_STANDALONE_VALUE: + det = gettext_noop("standalone accepts only 'yes' or 'no'."); + break; + case XML_ERR_VERSION_MISSING: + det = gettext_noop("Malformed declaration: missing version."); + break; + case XML_ERR_MISSING_ENCODING: + det = gettext_noop("Missing encoding in text declaration."); + break; + case XML_ERR_XMLDECL_NOT_FINISHED: + det = gettext_noop("Parsing XML declaration: '?>' expected."); + break; + default: + 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) +{ + 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) +{ + return xml_parse(data, xmloption_arg, preserve_whitespace, encoding); +} + +void +tds_xmlFreeDoc(void *doc) +{ + return xmlFreeDoc(doc); +} + +int +tds_parse_xml_decl(const xmlChar *str, size_t *lenp, + xmlChar **version, xmlChar **encoding, int *standalone) +{ + return parse_xml_decl(str, lenp, version, encoding, standalone); +} diff --git a/contrib/babelfishpg_tds/src/backend/utils/mb/README b/contrib/babelfishpg_tds/src/backend/utils/mb/README new file mode 100644 index 00000000000..e69de29bb2d diff --git a/contrib/babelfishpg_tds/src/backend/utils/mb/conv.c b/contrib/babelfishpg_tds/src/backend/utils/mb/conv.c new file mode 100644 index 00000000000..814fed55ba5 --- /dev/null +++ b/contrib/babelfishpg_tds/src/backend/utils/mb/conv.c @@ -0,0 +1,361 @@ +/*------------------------------------------------------------------------- + * + * Utility functions for conversion procs. + * + * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/backend/utils/mb/conv.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" +#include "mb/pg_wchar.h" + +#include "src/include/tds_int.h" + +/* + * comparison routine for bsearch() + * this routine is intended for combined UTF8 -> local code + */ +static int +compare3(const void *p1, const void *p2) +{ + uint32 s1, + s2, + d1, + d2; + + s1 = *(const uint32 *) p1; + s2 = *((const uint32 *) p1 + 1); + d1 = ((const pg_utf_to_local_combined *) p2)->utf1; + d2 = ((const pg_utf_to_local_combined *) p2)->utf2; + return (s1 > d1 || (s1 == d1 && s2 > d2)) ? 1 : ((s1 == d1 && s2 == d2) ? 0 : -1); +} + +/* + * store 32bit character representation into multibyte stream + */ +static inline unsigned char * +store_coded_char(unsigned char *dest, uint32 code) +{ + if (code & 0xff000000) + *dest++ = code >> 24; + if (code & 0x00ff0000) + *dest++ = code >> 16; + if (code & 0x0000ff00) + *dest++ = code >> 8; + if (code & 0x000000ff) + *dest++ = code; + return dest; +} + +/* + * Convert a character using a conversion radix tree. + * + * 'l' is the length of the input character in bytes, and b1-b4 are + * the input character's bytes. + */ +static inline uint32 +pg_mb_radix_conv(const pg_mb_radix_tree *rt, + int l, + unsigned char b1, + unsigned char b2, + unsigned char b3, + unsigned char b4) +{ + if (l == 4) + { + /* 4-byte code */ + + /* check code validity */ + if (b1 < rt->b4_1_lower || b1 > rt->b4_1_upper || + b2 < rt->b4_2_lower || b2 > rt->b4_2_upper || + b3 < rt->b4_3_lower || b3 > rt->b4_3_upper || + b4 < rt->b4_4_lower || b4 > rt->b4_4_upper) + return 0; + + /* perform lookup */ + if (rt->chars32) + { + uint32 idx = rt->b4root; + + idx = rt->chars32[b1 + idx - rt->b4_1_lower]; + idx = rt->chars32[b2 + idx - rt->b4_2_lower]; + idx = rt->chars32[b3 + idx - rt->b4_3_lower]; + return rt->chars32[b4 + idx - rt->b4_4_lower]; + } + else + { + uint16 idx = rt->b4root; + + idx = rt->chars16[b1 + idx - rt->b4_1_lower]; + idx = rt->chars16[b2 + idx - rt->b4_2_lower]; + idx = rt->chars16[b3 + idx - rt->b4_3_lower]; + return rt->chars16[b4 + idx - rt->b4_4_lower]; + } + } + else if (l == 3) + { + /* 3-byte code */ + + /* check code validity */ + if (b2 < rt->b3_1_lower || b2 > rt->b3_1_upper || + b3 < rt->b3_2_lower || b3 > rt->b3_2_upper || + b4 < rt->b3_3_lower || b4 > rt->b3_3_upper) + return 0; + + /* perform lookup */ + if (rt->chars32) + { + uint32 idx = rt->b3root; + + idx = rt->chars32[b2 + idx - rt->b3_1_lower]; + idx = rt->chars32[b3 + idx - rt->b3_2_lower]; + return rt->chars32[b4 + idx - rt->b3_3_lower]; + } + else + { + uint16 idx = rt->b3root; + + idx = rt->chars16[b2 + idx - rt->b3_1_lower]; + idx = rt->chars16[b3 + idx - rt->b3_2_lower]; + return rt->chars16[b4 + idx - rt->b3_3_lower]; + } + } + else if (l == 2) + { + /* 2-byte code */ + + /* check code validity - first byte */ + if (b3 < rt->b2_1_lower || b3 > rt->b2_1_upper || + b4 < rt->b2_2_lower || b4 > rt->b2_2_upper) + return 0; + + /* perform lookup */ + if (rt->chars32) + { + uint32 idx = rt->b2root; + + idx = rt->chars32[b3 + idx - rt->b2_1_lower]; + return rt->chars32[b4 + idx - rt->b2_2_lower]; + } + else + { + uint16 idx = rt->b2root; + + idx = rt->chars16[b3 + idx - rt->b2_1_lower]; + return rt->chars16[b4 + idx - rt->b2_2_lower]; + } + } + else if (l == 1) + { + /* 1-byte code */ + + /* check code validity - first byte */ + if (b4 < rt->b1_lower || b4 > rt->b1_upper) + return 0; + + /* perform lookup */ + if (rt->chars32) + return rt->chars32[b4 + rt->b1root - rt->b1_lower]; + else + return rt->chars16[b4 + rt->b1root - rt->b1_lower]; + } + return 0; /* shouldn't happen */ +} + +/* + * UTF8 ---> local code + * + * utf: input string in UTF8 encoding (need not be null-terminated) + * len: length of input string (in bytes) + * iso: pointer to the output area (must be large enough!) + (output string will be null-terminated) + * map: conversion map for single characters + * cmap: conversion map for combined characters + * (optional, pass NULL if none) + * cmapsize: number of entries in the conversion map for combined characters + * (optional, pass 0 if none) + * conv_func: algorithmic encoding conversion function + * (optional, pass NULL if none) + * encoding: PG identifier for the local encoding + * + * 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. + * + * See pg_wchar.h for more details about the data structures used here. + */ +void +tds_UtfToLocal(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) +{ + uint32 iutf; + int l; + const pg_utf_to_local_combined *cp; + + if (!PG_VALID_ENCODING(encoding)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid encoding number: %d", encoding))); + + for (; len > 0; len -= l) + { + unsigned char b1 = 0; + unsigned char b2 = 0; + unsigned char b3 = 0; + unsigned char b4 = 0; + + /* "break" cases all represent errors */ + if (*utf == '\0') + break; + + l = pg_utf_mblen(utf); + if (len < l) + break; + + if (!pg_utf8_islegal(utf, l)) + break; + + if (l == 1) + { + /* ASCII case is easy, assume it's one-to-one conversion */ + *iso++ = *utf++; + continue; + } + + /* collect coded char of length l */ + if (l == 2) + { + b3 = *utf++; + b4 = *utf++; + } + else if (l == 3) + { + b2 = *utf++; + b3 = *utf++; + b4 = *utf++; + } + else if (l == 4) + { + b1 = *utf++; + b2 = *utf++; + b3 = *utf++; + b4 = *utf++; + } + else + { + elog(ERROR, "unsupported character length %d", l); + iutf = 0; /* keep compiler quiet */ + } + iutf = (b1 << 24 | b2 << 16 | b3 << 8 | b4); + + /* First, try with combined map if possible */ + if (cmap && len > l) + { + const unsigned char *utf_save = utf; + int len_save = len; + int l_save = l; + + /* collect next character, same as above */ + len -= l; + + l = pg_utf_mblen(utf); + if (len < l) + break; + + if (!pg_utf8_islegal(utf, l)) + break; + + /* We assume ASCII character cannot be in combined map */ + if (l > 1) + { + uint32 iutf2; + uint32 cutf[2]; + + if (l == 2) + { + iutf2 = *utf++ << 8; + iutf2 |= *utf++; + } + else if (l == 3) + { + iutf2 = *utf++ << 16; + iutf2 |= *utf++ << 8; + iutf2 |= *utf++; + } + else if (l == 4) + { + iutf2 = *utf++ << 24; + iutf2 |= *utf++ << 16; + iutf2 |= *utf++ << 8; + iutf2 |= *utf++; + } + else + { + elog(ERROR, "unsupported character length %d", l); + iutf2 = 0; /* keep compiler quiet */ + } + + cutf[0] = iutf; + cutf[1] = iutf2; + + cp = bsearch(cutf, cmap, cmapsize, + sizeof(pg_utf_to_local_combined), compare3); + + if (cp) + { + iso = store_coded_char(iso, cp->code); + continue; + } + } + + /* fail, so back up to reprocess second character next time */ + utf = utf_save; + len = len_save; + l = l_save; + } + + /* Now check ordinary map */ + if (map) + { + uint32 converted = pg_mb_radix_conv(map, l, b1, b2, b3, b4); + + if (converted) + { + iso = store_coded_char(iso, converted); + continue; + } + } + + /* if there's a conversion function, try that */ + if (conv_func) + { + uint32 converted = (*conv_func) (iutf); + + if (converted) + { + iso = store_coded_char(iso, converted); + continue; + } + } + + /* + * TSQL puts question mark '?' + * if it can not recognize the UTF8 byte or byte sequence + */ + iso = store_coded_char(iso, '?'); + } + + /* if we broke out of loop early, must be invalid input */ + if (len > 0) + report_invalid_encoding(PG_UTF8, (const char *) utf, len); + + *iso = '\0'; +} diff --git a/contrib/babelfishpg_tds/src/backend/utils/mb/conversion_procs/utf8_and_big5/utf8_and_big5.c b/contrib/babelfishpg_tds/src/backend/utils/mb/conversion_procs/utf8_and_big5/utf8_and_big5.c new file mode 100644 index 00000000000..c32423f7c6e --- /dev/null +++ b/contrib/babelfishpg_tds/src/backend/utils/mb/conversion_procs/utf8_and_big5/utf8_and_big5.c @@ -0,0 +1,42 @@ +/*------------------------------------------------------------------------- + * + * BIG5 <--> UTF8 + * + * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/backend/utils/mb/conversion_procs/utf8_and_big5/utf8_and_big5.c + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" +#include "fmgr.h" +#include "mb/pg_wchar.h" +#include "src/backend/utils/mb/Unicode/big5_to_utf8.map" +#include "src/backend/utils/mb/Unicode/utf8_to_big5.map" + +#include "src/include/tds_int.h" + +/* ---------- + * conv_proc( + * INTEGER, -- source encoding id + * INTEGER, -- destination encoding id + * CSTRING, -- source string (null terminated C string) + * CSTRING, -- destination string (null terminated C string) + * INTEGER -- source string length + * ) returns VOID; + * ---------- + */ +void +utf8_to_big5(int src_encoding, int dest_encoding, const unsigned char *src, unsigned char *dest, int len) +{ + tds_UtfToLocal(src, len, dest, + &big5_from_unicode_tree, + NULL, 0, + NULL, + PG_BIG5); + + return; +} diff --git a/contrib/babelfishpg_tds/src/backend/utils/mb/conversion_procs/utf8_and_gbk/utf8_and_gbk.c b/contrib/babelfishpg_tds/src/backend/utils/mb/conversion_procs/utf8_and_gbk/utf8_and_gbk.c new file mode 100644 index 00000000000..bb18072588b --- /dev/null +++ b/contrib/babelfishpg_tds/src/backend/utils/mb/conversion_procs/utf8_and_gbk/utf8_and_gbk.c @@ -0,0 +1,42 @@ +/*------------------------------------------------------------------------- + * + * GBK <--> UTF8 + * + * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/backend/utils/mb/conversion_procs/utf8_and_gbk/utf8_and_gbk.c + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" +#include "fmgr.h" +#include "mb/pg_wchar.h" +#include "src/backend/utils/mb/Unicode/gbk_to_utf8.map" +#include "src/backend/utils/mb/Unicode/utf8_to_gbk.map" + +#include "src/include/tds_int.h" + +/* ---------- + * conv_proc( + * INTEGER, -- source encoding id + * INTEGER, -- destination encoding id + * CSTRING, -- source string (null terminated C string) + * CSTRING, -- destination string (null terminated C string) + * INTEGER -- source string length + * ) returns VOID; + * ---------- + */ +void +utf8_to_gbk(int src_encoding, int dest_encoding, const unsigned char *src, unsigned char *dest, int len) +{ + tds_UtfToLocal(src, len, dest, + &gbk_from_unicode_tree, + NULL, 0, + NULL, + PG_GBK); + + return; +} diff --git a/contrib/babelfishpg_tds/src/backend/utils/mb/conversion_procs/utf8_and_sjis/utf8_and_sjis.c b/contrib/babelfishpg_tds/src/backend/utils/mb/conversion_procs/utf8_and_sjis/utf8_and_sjis.c new file mode 100644 index 00000000000..1c421fdb618 --- /dev/null +++ b/contrib/babelfishpg_tds/src/backend/utils/mb/conversion_procs/utf8_and_sjis/utf8_and_sjis.c @@ -0,0 +1,42 @@ +/*------------------------------------------------------------------------- + * + * SJIS <--> UTF8 + * + * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/backend/utils/mb/conversion_procs/utf8_and_sjis/utf8_and_sjis.c + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" +#include "fmgr.h" +#include "mb/pg_wchar.h" +#include "src/backend/utils/mb/Unicode/sjis_to_utf8.map" +#include "src/backend/utils/mb/Unicode/utf8_to_sjis.map" + +#include "src/include/tds_int.h" + +/* ---------- + * conv_proc( + * INTEGER, -- source encoding id + * INTEGER, -- destination encoding id + * CSTRING, -- source string (null terminated C string) + * CSTRING, -- destination string (null terminated C string) + * INTEGER -- source string length + * ) returns VOID; + * ---------- + */ +void +utf8_to_sjis(int src_encoding, int dest_encoding, const unsigned char *src, unsigned char *dest, int len) +{ + tds_UtfToLocal(src, len, dest, + &sjis_from_unicode_tree, + NULL, 0, + NULL, + PG_SJIS); + + return; +} diff --git a/contrib/babelfishpg_tds/src/backend/utils/mb/conversion_procs/utf8_and_uhc/utf8_and_uhc.c b/contrib/babelfishpg_tds/src/backend/utils/mb/conversion_procs/utf8_and_uhc/utf8_and_uhc.c new file mode 100644 index 00000000000..f910c0e10ba --- /dev/null +++ b/contrib/babelfishpg_tds/src/backend/utils/mb/conversion_procs/utf8_and_uhc/utf8_and_uhc.c @@ -0,0 +1,42 @@ +/*------------------------------------------------------------------------- + * + * UHC <--> UTF8 + * + * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/backend/utils/mb/conversion_procs/utf8_and_uhc/utf8_and_uhc.c + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" +#include "fmgr.h" +#include "mb/pg_wchar.h" +#include "src/backend/utils/mb/Unicode/uhc_to_utf8.map" +#include "src/backend/utils/mb/Unicode/utf8_to_uhc.map" + +#include "src/include/tds_int.h" + +/* ---------- + * conv_proc( + * INTEGER, -- source encoding id + * INTEGER, -- destination encoding id + * CSTRING, -- source string (null terminated C string) + * CSTRING, -- destination string (null terminated C string) + * INTEGER -- source string length + * ) returns VOID; + * ---------- + */ +void +utf8_to_uhc(int src_encoding, int dest_encoding, const unsigned char *src, unsigned char *dest, int len) +{ + tds_UtfToLocal(src, len, dest, + &uhc_from_unicode_tree, + NULL, 0, + NULL, + PG_UHC); + + return; +} diff --git a/contrib/babelfishpg_tds/src/backend/utils/mb/conversion_procs/utf8_and_win/utf8_and_win.c b/contrib/babelfishpg_tds/src/backend/utils/mb/conversion_procs/utf8_and_win/utf8_and_win.c new file mode 100644 index 00000000000..c9e913107fc --- /dev/null +++ b/contrib/babelfishpg_tds/src/backend/utils/mb/conversion_procs/utf8_and_win/utf8_and_win.c @@ -0,0 +1,98 @@ +/*------------------------------------------------------------------------- + * + * WIN <--> UTF8 + * + * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/backend/utils/mb/conversion_procs/utf8_and_win/utf8_and_win.c + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" +#include "fmgr.h" +#include "mb/pg_wchar.h" +#include "src/backend/utils/mb/Unicode/utf8_to_win1250.map" +#include "src/backend/utils/mb/Unicode/utf8_to_win1251.map" +#include "src/backend/utils/mb/Unicode/utf8_to_win1252.map" +#include "src/backend/utils/mb/Unicode/utf8_to_win1253.map" +#include "src/backend/utils/mb/Unicode/utf8_to_win1254.map" +#include "src/backend/utils/mb/Unicode/utf8_to_win1255.map" +#include "src/backend/utils/mb/Unicode/utf8_to_win1256.map" +#include "src/backend/utils/mb/Unicode/utf8_to_win1257.map" +#include "src/backend/utils/mb/Unicode/utf8_to_win1258.map" +#include "src/backend/utils/mb/Unicode/utf8_to_win866.map" +#include "src/backend/utils/mb/Unicode/utf8_to_win874.map" +#include "src/backend/utils/mb/Unicode/win1250_to_utf8.map" +#include "src/backend/utils/mb/Unicode/win1251_to_utf8.map" +#include "src/backend/utils/mb/Unicode/win1252_to_utf8.map" +#include "src/backend/utils/mb/Unicode/win1253_to_utf8.map" +#include "src/backend/utils/mb/Unicode/win1254_to_utf8.map" +#include "src/backend/utils/mb/Unicode/win1255_to_utf8.map" +#include "src/backend/utils/mb/Unicode/win1256_to_utf8.map" +#include "src/backend/utils/mb/Unicode/win1257_to_utf8.map" +#include "src/backend/utils/mb/Unicode/win866_to_utf8.map" +#include "src/backend/utils/mb/Unicode/win874_to_utf8.map" +#include "src/backend/utils/mb/Unicode/win1258_to_utf8.map" + +#include "src/include/tds_int.h" + +/* ---------- + * conv_proc( + * INTEGER, -- source encoding id + * INTEGER, -- destination encoding id + * CSTRING, -- source string (null terminated C string) + * CSTRING, -- destination string (null terminated C string) + * INTEGER -- source string length + * ) returns VOID; + * ---------- + */ + +typedef struct +{ + pg_enc encoding; + const pg_mb_radix_tree *map1; /* to UTF8 map name */ + const pg_mb_radix_tree *map2; /* from UTF8 map name */ +} pg_conv_map; + +static const pg_conv_map maps[] = { + {PG_WIN866, &win866_to_unicode_tree, &win866_from_unicode_tree}, + {PG_WIN874, &win874_to_unicode_tree, &win874_from_unicode_tree}, + {PG_WIN1250, &win1250_to_unicode_tree, &win1250_from_unicode_tree}, + {PG_WIN1251, &win1251_to_unicode_tree, &win1251_from_unicode_tree}, + {PG_WIN1252, &win1252_to_unicode_tree, &win1252_from_unicode_tree}, + {PG_WIN1253, &win1253_to_unicode_tree, &win1253_from_unicode_tree}, + {PG_WIN1254, &win1254_to_unicode_tree, &win1254_from_unicode_tree}, + {PG_WIN1255, &win1255_to_unicode_tree, &win1255_from_unicode_tree}, + {PG_WIN1256, &win1256_to_unicode_tree, &win1256_from_unicode_tree}, + {PG_WIN1257, &win1257_to_unicode_tree, &win1257_from_unicode_tree}, + {PG_WIN1258, &win1258_to_unicode_tree, &win1258_from_unicode_tree}, +}; + +void +utf8_to_win(int src_encoding, int dest_encoding, const unsigned char *src,unsigned char *dest, int len) +{ + int i; + + for (i = 0; i < lengthof(maps); i++) + { + if (dest_encoding == maps[i].encoding) + { + tds_UtfToLocal(src, len, dest, + maps[i].map2, + NULL, 0, + NULL, + dest_encoding); + return ; + } + } + + ereport(ERROR, + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("unexpected encoding ID %d for WIN character sets", + dest_encoding))); + + return ; +} diff --git a/contrib/babelfishpg_tds/src/include/.gitignore b/contrib/babelfishpg_tds/src/include/.gitignore new file mode 100644 index 00000000000..9317aeef477 --- /dev/null +++ b/contrib/babelfishpg_tds/src/include/.gitignore @@ -0,0 +1 @@ +/error_mapping.h diff --git a/contrib/babelfishpg_tds/src/include/err_handler.h b/contrib/babelfishpg_tds/src/include/err_handler.h new file mode 100644 index 00000000000..ebdd0d061c2 --- /dev/null +++ b/contrib/babelfishpg_tds/src/include/err_handler.h @@ -0,0 +1,51 @@ +#include "utils/elog.h" + +/* 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); +extern void reset_error_mapping_cache(void); +extern int* get_mapped_error_code_list(void); + +/* + * Structure to store key information for error mapping. + * 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; + +/* + * 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 + * 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 */ + struct error_map_node *next; +}error_map_node; + +/* + * Structure to store list of tsql error details for given key. + */ +typedef struct error_map{ + error_map_key key; + error_map_node *head; +}error_map; + +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; + +typedef error_map *error_map_info; diff --git a/contrib/babelfishpg_tds/src/include/faultinjection.h b/contrib/babelfishpg_tds/src/include/faultinjection.h new file mode 100644 index 00000000000..7f1f853ff6f --- /dev/null +++ b/contrib/babelfishpg_tds/src/include/faultinjection.h @@ -0,0 +1,81 @@ +/*------------------------------------------------------------------------- + * + * faultinjection.h + * This file contains definitions for structures and externs used + * internally by the Fault Injection Framework + * + * Portions Copyright (c) 2020, AWS + * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * contrib/babelfish_tds/src/include/faultinjection.h + * + *------------------------------------------------------------------------- + */ +#include "nodes/pg_list.h" + +#define FAULT_NAME_MAX_LENGTH 100 +#define INVALID_TAMPER_BYTE -1 + +typedef enum FaultInjectorType_e { + TestType = 0, + ParseHeaderType, + PreParsingType, + ParseRpcType, + PostParsingType, + InvalidType +} FaultInjectorType_e; + +typedef struct FaultInjectionType { + FaultInjectorType_e type; + 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); +} FaultInjectorEntry_s; + +extern const FaultInjectorEntry_s Faults[]; + +extern int tamperByte; + +#define TEST_LIST const FaultInjectorEntry_s Faults[] +#define TEST_TYPE_LIST FaultInjectionType FaultInjectionTypes[] + +/* + * Example of defining a Test Type + * + * TEST_TYPE_LIST = { + * {TestType, "Test", NIL} + * }; + */ + +/* + * Example of defining a test of previously defined type + * + * static void + * test_fault1(void *arg) + * { + * ... + * } + * + * TEST_LIST = { + * {"test_fault1", TestType, 0, &test_fault1}, + * {"", InvalidType, 0, NULL} -- keep this as last + * }; + */ + +extern bool trigger_fault_injection; +extern void TriggerFault(FaultInjectorType_e type, void *arg); + +#ifdef FAULT_INJECTOR +#define FAULT_INJECT(type, arg) TriggerFault(type, (void *) (arg)) +#else +#define FAULT_INJECT(type, arg) ((void)0) +#endif diff --git a/contrib/babelfishpg_tds/src/include/guc.h b/contrib/babelfishpg_tds/src/include/guc.h new file mode 100644 index 00000000000..82f69b80374 --- /dev/null +++ b/contrib/babelfishpg_tds/src/include/guc.h @@ -0,0 +1,28 @@ +/*------------------------------------------------------------------------- + * + * guc.h + * This file contains extern declarations for GUCs + * used by the TDS listener. + * + * Portions Copyright (c) 2020, AWS + * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/guc.h + * + *------------------------------------------------------------------------- + */ + +extern int pe_port; +extern char *pe_listen_addrs; +extern char *pe_unix_socket_directories; +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 int32_t tds_default_protocol_version; +extern int32_t tds_default_packet_size; +extern int tds_debug_log_level; +extern bool tds_enable_db_session_property; +extern char *default_server_name; \ No newline at end of file diff --git a/contrib/babelfishpg_tds/src/include/tds.h b/contrib/babelfishpg_tds/src/include/tds.h new file mode 100644 index 00000000000..4ba140287ce --- /dev/null +++ b/contrib/babelfishpg_tds/src/include/tds.h @@ -0,0 +1,34 @@ +/*------------------------------------------------------------------------- + * tds_instr.h + * + * Header file for BabelFish tds. Defining structures used to talk between the extensions + * + * Copyright (c) 2021, Amazon Web Services, Inc. or its affiliates. All Rights Reserved + *------------------------------------------------------------------------- + */ + + +/* + * When we load instrumentation extension, we create a rendezvous variable named + * "TdsInstrPlugin" that points to an instance of type TdsInstrPlugin. + * + * We use this rendezvous variable to safely share information with + * 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 + * TdsInstrPlugin struct shown here. + */ +typedef struct TdsInstrPlugin +{ + /* Function pointers set up by the plugin */ + void (*tds_instr_increment_metric) (int metric); +} TdsInstrPlugin; + +extern TdsInstrPlugin **tds_instr_plugin_ptr; + +#define TDSInstrumentation(metric) \ +({ 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 new file mode 100644 index 00000000000..363a9bc0595 --- /dev/null +++ b/contrib/babelfishpg_tds/src/include/tds_debug.h @@ -0,0 +1,113 @@ +/*------------------------------------------------------------------------- + * + * tds_debug.h + * Debugging functions/macros used internally in the TDS Listener + * + * Portions Copyright (c) 2020, AWS + * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/tds/tds_debug.h + * + *------------------------------------------------------------------------- + */ +#ifndef TDS_DEBUG_H +#define TDS_DEBUG_H + +#include + +#include + +#define DebugPrintBytes(_c, _s, _len) \ +do \ +{ \ + int i; \ + StringInfoData h; \ + StringInfoData a; \ + if (!TDS_DEBUG_ENABLED(TDS_DEBUG3)) \ + break; \ + initStringInfo(&h); \ + initStringInfo(&a); \ + for(i = 0; i < _len; i++) \ + { \ + if (i % 16 == 0) \ + { \ + if (i != 0) \ + { \ + /* append characters and start new line */ \ + appendStringInfo(&h, " %s\n ", a.data); \ + resetStringInfo(&a); \ + } \ + /* print the offset */ \ + appendStringInfo(&h, " %04x:", i); \ + } \ + appendStringInfo(&h, " %02x", (unsigned char)(_s)[i]); \ + if (isascii((_s)[i]) && (_s)[i] >= ' ') \ + appendStringInfoChar(&a, (_s)[i]); \ + else \ + appendStringInfoChar(&a, '.'); \ + } \ + if (i % 16 != 0) \ + { \ + while (i++ % 16 != 0) \ + appendStringInfoString(&h, " "); \ + appendStringInfo(&h, " %s", a.data); \ + } \ + if (h.len == 0) \ + appendStringInfo(&h, ""); \ + elog(LOG, "MESSAGE: %s\n %s", (_c), h.data); \ + pfree(h.data); \ + pfree(a.data); \ +} while(0) + +#define DebugPrintMessage(_c, _m) \ +do \ +{ \ + DebugPrintBytes((_c), (_m)->data, (_m->len)); \ +} while(0) + +#define DebugPrintMessageData(_c, _m) \ +do \ +{ \ + DebugPrintBytes((_c), (_m).data, (_m.len)); \ +} while(0) + +#define DebugPrintLoginMessage(_r) \ +do \ +{ \ + StringInfoData s; \ + Assert((_r) != NULL); \ + if (!TDS_DEBUG_ENABLED(TDS_DEBUG3)) \ + break; \ + initStringInfo(&s); \ + appendStringInfo(&s, "\n Login (_r) {\n"); \ + appendStringInfo(&s, " length: %u\n", (_r)->length); \ + appendStringInfo(&s, " tdsVersion: 0x%08x\n", (_r)->tdsVersion); \ + appendStringInfo(&s, " packetSize: %d\n", (_r)->packetSize); \ + appendStringInfo(&s, " optionFlags1: 0x%02x\n", (_r)->optionFlags1); \ + appendStringInfo(&s, " optionFlags2: 0x%02x\n", (_r)->optionFlags2); \ + appendStringInfo(&s, " typeFlags: 0x%02x\n", (_r)->typeFlags); \ + appendStringInfo(&s, " timezone: 0x%08x\n", (_r)->clientTimezone); \ + appendStringInfo(&s, " lcid: 0x%08x\n", (_r)->clientLcid); \ + if ((_r)->hostname != NULL) \ + appendStringInfo(&s, " hostname: %s\n", (_r)->hostname); \ + if ((_r)->username != NULL) \ + appendStringInfo(&s, " username: %s\n", (_r)->username); \ + if ((_r)->appname != NULL) \ + appendStringInfo(&s, " appname: %s\n", (_r)->appname); \ + if ((_r)->servername != NULL) \ + appendStringInfo(&s, " servername: %s\n", (_r)->servername); \ + if ((_r)->library != NULL) \ + appendStringInfo(&s, " library: %s\n", (_r)->library); \ + if ((_r)->language != NULL) \ + appendStringInfo(&s, " language: %s\n", (_r)->language); \ + if ((_r)->database != NULL) \ + appendStringInfo(&s, " database: %s\n", (_r)->database); \ + appendStringInfo(&s, "}"); \ + elog(LOG, "%s", s.data); \ + pfree(s.data); \ +} while(0) + +#endif /* TDS_DEBUG_H */ + + diff --git a/contrib/babelfishpg_tds/src/include/tds_instr.h b/contrib/babelfishpg_tds/src/include/tds_instr.h new file mode 100644 index 00000000000..b6c389b6dcf --- /dev/null +++ b/contrib/babelfishpg_tds/src/include/tds_instr.h @@ -0,0 +1,96 @@ +/*------------------------------------------------------------------------- + * tds_instr.h + * + * Header file for BabelFish Instrumentation + * + * Copyright (c) 2021, Amazon Web Services, Inc. or its affiliates. All Rights Reserved + *------------------------------------------------------------------------- + */ + +#include "src/pltsql_instr.h" +#include "tds.h" + +typedef enum BabelFishTdsInstrMetricType { + INSTR_TDS_LOGIN_SSL = INSTR_TSQL_COUNT, + INSTR_TDS_LOGIN_END_TO_END_ENCRYPT, + INSTR_TDS_LOGIN_ACTIVE_DIRECTORY, + + INSTR_UNSUPPORTED_TDS_PRELOGIN_THREADID, + INSTR_UNSUPPORTED_TDS_PRELOGIN_INSTOPT, + INSTR_UNSUPPORTED_TDS_PRELOGIN_TRACEID, + INSTR_UNSUPPORTED_TDS_PRELOGIN_FEDAUTHREQUIRED, + INSTR_UNSUPPORTED_TDS_PRELOGIN_NONCEOPT, + INSTR_UNSUPPORTED_TDS_LOGIN_CB_SSPI_LONG, + INSTR_UNSUPPORTED_TDS_LOGIN_GSS_S_CONTINUE_NEEDED, + INSTR_UNSUPPORTED_TDS_LOGIN_NTLMSSP, + + INSTR_UNSUPPORTED_TDS_LOGIN_OPTION_FLAGS1_BYTE_ORDER_68000, + INSTR_UNSUPPORTED_TDS_LOGIN_OPTION_FLAGS1_CHAR_EBCDIC, + INSTR_UNSUPPORTED_TDS_LOGIN_OPTION_FLAGS1_FLOAT_VAX, + INSTR_UNSUPPORTED_TDS_LOGIN_OPTION_FLAGS1_FLOAT_ND5000, + INSTR_UNSUPPORTED_TDS_LOGIN_OPTION_FLAGS1_DUMP_LOAD_OFF, + INSTR_UNSUPPORTED_TDS_LOGIN_OPTION_FLAGS1_USE_DB_ON, + INSTR_UNSUPPORTED_TDS_LOGIN_OPTION_FLAGS1_DATABASE_FATAL, + INSTR_UNSUPPORTED_TDS_LOGIN_OPTION_FLAGS1_SET_LANG_ON, + INSTR_UNSUPPORTED_TDS_LOGIN_OPTION_FLAGS2_LANGUAGE_FATAL, + INSTR_UNSUPPORTED_TDS_LOGIN_OPTION_FLAGS2_TRAN_BOUNDARY, + INSTR_UNSUPPORTED_TDS_LOGIN_OPTION_FLAGS2_CACHE_CONNECT, + INSTR_UNSUPPORTED_TDS_LOGIN_OPTION_FLAGS2_USER_TYPE_SERVER, + INSTR_UNSUPPORTED_TDS_LOGIN_OPTION_FLAGS2_USER_TYPE_REMUSER, + INSTR_UNSUPPORTED_TDS_LOGIN_OPTION_FLAGS2_USER_TYPE_SQLREPL, + INSTR_UNSUPPORTED_TDS_LOGIN_OPTION_FLAGS2_INT_SECURITY_ON, + INSTR_UNSUPPORTED_TDS_LOGIN_TYPE_FLAGS_SQL_TSQL, + INSTR_UNSUPPORTED_TDS_LOGIN_TYPE_FLAGS_READ_ONLY_INTENT, + INSTR_UNSUPPORTED_TDS_LOGIN_OPTION_FLAGS3_CHANGE_PASSWORD, + INSTR_UNSUPPORTED_TDS_LOGIN_OPTION_FLAGS3_USER_INSTANCE, + INSTR_UNSUPPORTED_TDS_LOGIN_OPTION_FLAGS3_SEND_YUKON_BINARY_XML, + INSTR_UNSUPPORTED_TDS_LOGIN_OPTION_FLAGS3_UNKNOWN_COLLATION_HANDLING, + INSTR_UNSUPPORTED_TDS_LOGIN_OPTION_FLAGS3_EXTENSION, + + INSTR_TDS_VERSION_7_0, + INSTR_TDS_VERSION_7_1, + INSTR_TDS_VERSION_7_1_1, + INSTR_TDS_VERSION_7_2, + INSTR_TDS_VERSION_7_3_A, + INSTR_TDS_VERSION_7_3_B, + INSTR_TDS_VERSION_7_4, + + INSTR_TDS_SP_EXECUTESQL, + INSTR_TDS_SP_PREPARE, + INSTR_TDS_SP_EXECUTE, + INSTR_TDS_SP_PREPEXEC, + INSTR_TDS_USER_CUSTOM_SP, + INSTR_TDS_SP_UNPREPARE, + INSTR_TDS_SP_CURSOR_OPEN, + INSTR_TDS_SP_CURSOR_EXEC, + INSTR_TDS_SP_CURSOR_PREPEXEC, + INSTR_TDS_SP_CURSOR_FETCH, + INSTR_TDS_SP_CURSOR_CLOSE, + INSTR_TDS_SP_CURSOR_UNPREPARE, + INSTR_UNSUPPORTED_TDS_SP_CURSOR, + INSTR_UNSUPPORTED_TDS_SP_CURSOROPTION, + INSTR_UNSUPPORTED_TDS_SP_CURSORPREPARE, + + INSTR_TDS_BULK_LOAD_REQUEST, + + INSTR_TDS_TM_REQUEST, + + INSTR_TDS_DATATYPE_VARCHAR_MAX, + INSTR_TDS_DATATYPE_NVARCHAR_MAX, + INSTR_TDS_DATATYPE_VARBINARY_MAX, + INSTR_TDS_DATATYPE_MONEY, + INSTR_TDS_DATATYPE_SMALLMONEY, + INSTR_TDS_DATATYPE_XML, + INSTR_TDS_DATATYPE_DATETIME_OFFSET, + INSTR_TDS_DATATYPE_TABLE_VALUED_PARAMETER, + INSTR_TDS_DATATYPE_SQLVARIANT, + INSTR_TDS_DATATYPE_IMAGE, + + INSTR_TDS_TOKEN_NBCROW, + INSTR_TDS_TOKEN_SSPI, + INSTR_TDS_TOKEN_TABNAME, + + INSTR_TDS_UNMAPPED_ERROR, + + INSTR_TDS_COUNT +} BabelFishTdsInstrMetricType; diff --git a/contrib/babelfishpg_tds/src/include/tds_int.h b/contrib/babelfishpg_tds/src/include/tds_int.h new file mode 100644 index 00000000000..9835ac1fa3a --- /dev/null +++ b/contrib/babelfishpg_tds/src/include/tds_int.h @@ -0,0 +1,345 @@ +/*------------------------------------------------------------------------- + * + * tds_int.h + * This file contains definitions for structures and externs used + * internally by the TDS listener. + * + * Portions Copyright (c) 2020, AWS + * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/tds/tds_int.h + * + *------------------------------------------------------------------------- + */ +#ifndef TDS_INT_H +#define TDS_INT_H + +#include "datatype/timestamp.h" +#include "fmgr.h" +#include "lib/stringinfo.h" +#include "libpq/hba.h" +#include "libpq/libpq-be.h" +#include "libpq/pqcomm.h" +#include "nodes/parsenodes.h" +#include "parser/parse_node.h" +#include "nodes/params.h" +#include "tcop/dest.h" +#include "utils/memutils.h" +#include "utils/numeric.h" +#include + +#include "tds_typeio.h" +#include "guc.h" + +#include "../../contrib/babelfishpg_tsql/src/pltsql.h" +#include "../../contrib/babelfishpg_tsql/src/pltsql-2.h" + +#define TDS_PACKET_HEADER_SIZE 8 + +/* + * Default packet size for initial hand-shake - this is used only for prelogin + * SSL handshakes and login packets. + * TODO. This will vary with the SQL clients. We need a to determine the sizes + * of prelogin, SSL handshakes and login packets by inspecting the respective + * packets.. For now, just use the default. + */ +#define TDS_DEFAULT_INIT_PACKET_SIZE 4096 + +/* + * If the client sends the following packet size, we should use server default + * packet size. + */ +#define TDS_USE_SERVER_DEFAULT_PACKET_SIZE 0 + +/* default database for TSQL */ +#define TSQL_DEFAULT_DB "master" + +/* default server name */ +#define TDS_DEFAULT_SERVER_NAME "Microsoft SQL Server" + +/* TDS packet types */ +#define TDS_QUERY 0x01 +#define TDS_RPC 0x03 +#define TDS_RESPONSE 0x04 +#define TDS_BULK_LOAD 0x07 +#define TDS_TXN 0x0E +#define TDS_LOGIN7 0x10 +#define TDS_PRELOGIN 0x12 +#define TDS_ATTENTION 0x06 + +/* various flags in TDS request packet header */ +#define TDS_PACKET_HEADER_STATUS_EOM 0x01 /* end of message */ +#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 */ + +/* TDS prelogin option types */ +#define TDS_PRELOGIN_VERSION 0x00 +#define TDS_PRELOGIN_ENCRYPTION 0x01 +#define TDS_PRELOGIN_INSTOPT 0x02 +#define TDS_PRELOGIN_THREADID 0x03 +#define TDS_PRELOGIN_MARS 0x04 +#define TDS_PRELOGIN_TRACEID 0x05 +#define TDS_PRELOGIN_FEDAUTHREQUIRED 0x06 +#define TDS_PRELOGIN_NONCEOPT 0x07 +#define TDS_PRELOGIN_TERMINATOR 0xFF + +/* TDS Encryption values */ +#define TDS_ENCRYPT_OFF 0x00 +#define TDS_ENCRYPT_ON 0x01 +#define TDS_ENCRYPT_NOT_SUP 0x02 +#define TDS_ENCRYPT_REQ 0x03 +#define TDS_ENCRYPT_CLIENT_CERT_ENCRYPT_OFF 0x80 +#define TDS_ENCRYPT_CLIENT_CERT_ENCRYPT_ON 0x81 +#define TDS_ENCRYPT_CLIENT_CERT_ENCRYPT_REQ 0x83 + +/* TDS Environment Change IDs */ +#define TDS_ENVID_DATABASE 0x01 +#define TDS_ENVID_LANGUAGE 0x02 +#define TDS_ENVID_BLOCKSIZE 0x04 +#define TDS_ENVID_COLLATION 0x07 +#define TDS_ENVID_RESETCON 0x12 + +/* TDS Environment Change IDs */ +#define TDS_ENVID_BEGINTXN 0x08 +#define TDS_ENVID_COMMITTXN 0x09 +#define TDS_ENVID_ROLLBACKTXN 0x0a + +/* + * 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. + */ +#define TDS_DEFAULT_VERSION 0 +#define TDS_VERSION_7_0 0x70000000 /* TDS version 7.0 */ +#define TDS_VERSION_7_1 0x71000000 /* TDS version 7.1 */ +#define TDS_VERSION_7_1_1 0x71000001 /* TDS version 7.1 Rev 1 */ +#define TDS_VERSION_7_2 0x72090002 /* TDS version 7.2 */ +#define TDS_VERSION_7_3_A 0x730A0003 /* TDS version 7.3A */ +#define TDS_VERSION_7_3_B 0x730B0003 /* TDS version 7.3B */ +#define TDS_VERSION_7_4 0x74000004 /* TDS version 7.4 */ + +/* + * Macros to explicitly convert host byte order to LITTLE_ENDIAN + * fashioned after the pg_hton16().. family found in port/pg_bswap.h + */ +#ifdef WORDS_BIGENDIAN + +#define htoLE16(x) pg_bswap16(x) +#define htoLE32(x) pg_bswap32(x) +#define htoLE64(x) pg_bswap64(x) +#define htoLE128(x) pg_bswap128(x) + +#define LEtoh16(x) pg_bswap16(x) +#define LEtoh32(x) pg_bswap32(x) +#define LEtoh64(x) pg_bswap64(x) +#define LEtoh128(x) pg_bswap128(x) + +#else + +#define htoLE16(x) (x) +#define htoLE32(x) (x) +#define htoLE64(x) (x) +#define htoLE128(x) (x) + +#define LEtoh16(x) (x) +#define LEtoh32(x) (x) +#define LEtoh64(x) (x) +#define LEtoh128(x) (x) + +#endif + +/* TDS type related */ +#define TDS_MAX_NUM_PRECISION 38 +#define READ_DATA(PTR, SVHDR) (VARDATA_ANY(PTR) + SVHDR) + +/* Globals */ +extern PLtsql_protocol_plugin *pltsql_plugin_handler_ptr; + +/* Globals in backend/tds/tdscomm.c */ +extern MemoryContext TdsMemoryContext; + +/* Global to store default collation info */ +extern int TdsDefaultLcid; +extern int TdsDefaultCollationFlags; +extern uint8_t TdsDefaultSortid; + +#define TDS_DEBUG1 1 +#define TDS_DEBUG2 2 +#define TDS_DEBUG3 3 + +#define TDS_DEBUG_ENABLED(level) (level <= tds_debug_log_level) + +#define TDS_DEBUG(level, ... ) do { \ +if (TDS_DEBUG_ENABLED(level)) \ + elog(LOG, __VA_ARGS__); \ +} while(0); + +#define TdsGetEncoding(collation)\ + (\ + (collation & 0xFFFFF) ? TdsLookupEncodingByLCID(collation & 0xFFFFF) : \ + TdsLookupEncodingByLCID(TdsDefaultLcid) \ + ); + +/* 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; + +typedef TdsParamNameData *TdsParamName; + +/* XXX: Should be removed */ +/* Stores mapping between TVP and underlying table */ +extern List *tvp_lookup_list; + +typedef struct TdsMessageWrapper +{ + StringInfo message; + uint8_t messageType; + uint64_t offset; +} TdsMessageWrapper; + +/* + * We store the required TDS information to gain more context if we + * encounter an error in TDS. + */ +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 */ + +} TdsErrorContextData; + +extern TdsErrorContextData *TdsErrorContext; + + +/* Socket functions */ +typedef ssize_t (*TdsSecureSocketApi)(Port *port, void *ptr, size_t len); + +/* Functions in backend/tds/tdscomm.c */ +extern void TdsSetMessageType(uint8_t msgType); +extern void TdsCommInit(uint32_t bufferSize, + 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 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 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); + +/* Functions in backend/tds/tdslogin.c */ +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 void TdsSendLoginAck(Port *port); +extern uint32_t GetClientTDSVersion(void); +extern char* get_tds_login_domainname(void); + +/* Functions in backend/tds/tdsprotocol.c */ +extern int TdsSocketBackend(void); +extern void TdsProtocolInit(void); +extern void TdsProtocolFinish(void); +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 void TDSLogDuration(char *query); + +/* Functions in backend/tds/tdsutils.c */ +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); +extern int32_t ProcessStreamHeaders(const StringInfo message); +extern Node * TdsFindParam(ParseState *pstate, ColumnRef *cref); +extern void TdsErrorContextCallback(void *arg); + +/* Functions in backend/tds/guc.c */ +extern void TdsDefineGucs(void); + +/* Functions in backend/tds/tdspostgres.c */ +extern void TDSPostgresMain(int argc, char *argv[], + const char *dbname, const Oid dboid, + const char *username) pg_attribute_noreturn(); + +/* Functions in backend/tds/tdspostinit.c */ +extern void TDSInitPostgres(const char *in_dbname, Oid dboid, const char *username, + Oid useroid, char *out_dbname, bool override_allow_connections); + +/* Functions in backend/tds/tdspostmaster.c */ +extern void TDSBackendRun(Port *port, bool loadedSSL, char *extraOptions); + +/* Functions in backend/tds/tds_srv.c */ +extern void pe_init(void); +extern void pe_fin(void); + +/* Functions in encoding/encoding_utils.c */ +extern char *server_to_any(const char *s, int len, int encoding); + +/* Functions in backend/utils/mb/conv.c */ +extern void tds_UtfToLocal(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); + +/* Functions in backend/utils/mb/conversion_procs */ +extern void utf8_to_win(int src_encoding, int dest_encoding, const unsigned char *src, unsigned char *result, int len); +extern void utf8_to_big5(int src_encoding, int dest_encoding, const unsigned char *src, unsigned char *result, int len); +extern void utf8_to_gbk(int src_encoding, int dest_encoding, const unsigned char *src, unsigned char *result, int len); +extern void utf8_to_uhc(int src_encoding, int dest_encoding, const unsigned char *src, unsigned char *result, int len); +extern void utf8_to_sjis(int src_encoding, int dest_encoding, const unsigned char *src, unsigned char *result, int len); + +/* Functions in backend/utils/adt/numeric.c */ +extern Numeric TdsSetVarFromStrWrapper(const char *str); +extern int32_t numeric_get_typmod(Numeric num); + +/* Functions in backend/utils/adt/varchar.c */ +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); + +#endif /* TDS_INT_H */ diff --git a/contrib/babelfishpg_tds/src/include/tds_iofuncmap.h b/contrib/babelfishpg_tds/src/include/tds_iofuncmap.h new file mode 100644 index 00000000000..a60395a42dc --- /dev/null +++ b/contrib/babelfishpg_tds/src/include/tds_iofuncmap.h @@ -0,0 +1,159 @@ +/*------------------------------------------------------------------------- + * + * tds_iofuncmap.h + * TDS Listener Type Input Output function numbers + * + * !!! Do not add anything but simple #define TOKEN value + * constructs to this file. It is used in the SQL input + * for the babelfishpg_tsql extension. Anything you + * might want to add here belongs into tds_typeio.h. + * + * Portions Copyright (c) 2020, AWS + * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/libpq/tds_iofuncmap.h + * + *------------------------------------------------------------------------- + */ +#ifndef TDS_IOFUNCMAP_H +#define TDS_IOFUNCMAP_H + +#define TDS_SEND_INVALID 0 + +#define TDS_SEND_BIT 1 +#define TDS_SEND_TINYINT 2 +#define TDS_SEND_SMALLINT 3 +#define TDS_SEND_INTEGER 4 +#define TDS_SEND_BIGINT 5 +#define TDS_SEND_FLOAT4 6 +#define TDS_SEND_FLOAT8 7 +#define TDS_SEND_CHAR 8 +#define TDS_SEND_NVARCHAR 9 +#define TDS_SEND_VARCHAR 10 +#define TDS_SEND_DATE 11 +#define TDS_SEND_DATETIME 12 +#define TDS_SEND_MONEY 13 +#define TDS_SEND_SMALLMONEY 14 +#define TDS_SEND_NCHAR 15 +#define TDS_SEND_TEXT 16 +#define TDS_SEND_NTEXT 17 +#define TDS_SEND_NUMERIC 18 +#define TDS_SEND_SMALLDATETIME 19 +#define TDS_SEND_BINARY 20 +#define TDS_SEND_VARBINARY 21 +#define TDS_SEND_UNIQUEIDENTIFIER 22 +#define TDS_SEND_TIME 23 +#define TDS_SEND_DATETIME2 24 +#define TDS_SEND_IMAGE 25 +#define TDS_SEND_XML 26 +#define TDS_SEND_SQLVARIANT 28 +#define TDS_SEND_DATETIMEOFFSET 29 + +#define TDS_RECV_INVALID 0 +#define TDS_RECV_BIT 1 +#define TDS_RECV_TINYINT 2 +#define TDS_RECV_SMALLINT 3 +#define TDS_RECV_INTEGER 4 +#define TDS_RECV_BIGINT 5 +#define TDS_RECV_FLOAT4 6 +#define TDS_RECV_FLOAT8 7 +#define TDS_RECV_CHAR 8 +#define TDS_RECV_NVARCHAR 9 +#define TDS_RECV_VARCHAR 10 +#define TDS_RECV_DATE 11 +#define TDS_RECV_DATETIME 12 +#define TDS_RECV_MONEY 13 +#define TDS_RECV_SMALLMONEY 14 +#define TDS_RECV_NCHAR 15 +#define TDS_RECV_TEXT 16 +#define TDS_RECV_NTEXT 17 +#define TDS_RECV_NUMERIC 18 +#define TDS_RECV_SMALLDATETIME 19 +#define TDS_RECV_BINARY 20 +#define TDS_RECV_VARBINARY 21 +#define TDS_RECV_UNIQUEIDENTIFIER 22 +#define TDS_RECV_TIME 23 +#define TDS_RECV_DATETIME2 24 +#define TDS_RECV_IMAGE 25 +#define TDS_RECV_XML 26 +#define TDS_RECV_TABLE 27 +#define TDS_RECV_SQLVARIANT 28 +#define TDS_RECV_DATETIMEOFFSET 29 + +/* + * Supported TDS data types + * + * 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_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 */ + +/* + * macros for supporting sqlvariant datatype on TDS side + */ +#define VARIANT_HEADER 12 +#define VARIANT_TYPE_TINYINT 48 +#define VARIANT_TYPE_BIT 50 +#define VARIANT_TYPE_SMALLINT 52 +#define VARIANT_TYPE_INT 56 +#define VARIANT_TYPE_BIGINT 127 +#define VARIANT_TYPE_REAL 59 +#define VARIANT_TYPE_FLOAT 62 +#define VARIANT_TYPE_NUMERIC 108 +#define VARIANT_TYPE_MONEY 60 +#define VARIANT_TYPE_SMALLMONEY 122 +#define VARIANT_TYPE_DATE 40 +#define VARIANT_TYPE_CHAR 175 +#define VARIANT_TYPE_VARCHAR 167 +#define VARIANT_TYPE_NCHAR 239 +#define VARIANT_TYPE_NVARCHAR 231 +#define VARIANT_TYPE_BINARY 173 +#define VARIANT_TYPE_VARBINARY 165 +#define VARIANT_TYPE_UNIQUEIDENTIFIER 36 +#define VARIANT_TYPE_TIME 41 +#define VARIANT_TYPE_SMALLDATETIME 58 +#define VARIANT_TYPE_DATETIME 61 +#define VARIANT_TYPE_DATETIME2 42 +#define VARIANT_TYPE_DATETIMEOFFSET 43 + +/* + * TDS Data types' max len + */ +#define TDS_MAXLEN_TINYINT 1 +#define TDS_MAXLEN_SMALLINT 2 +#define TDS_MAXLEN_INT 4 +#define TDS_MAXLEN_BIGINT 8 +#define TDS_MAXLEN_BIT 1 +#define TDS_MAXLEN_FLOAT4 4 +#define TDS_MAXLEN_FLOAT8 8 +#define TDS_MAXLEN_NUMERIC 17 +#define TDS_MAXLEN_UNIQUEIDENTIFIER 16 +#define TDS_MAXLEN_SMALLDATETIME 4 +#define TDS_MAXLEN_DATETIME 8 +#define TDS_MAXLEN_SMALLMONEY 4 +#define TDS_MAXLEN_MONEY 8 +#endif /* TDS_IOFUNCMAP_H */ diff --git a/contrib/babelfishpg_tds/src/include/tds_protocol.h b/contrib/babelfishpg_tds/src/include/tds_protocol.h new file mode 100644 index 00000000000..96f7c74b980 --- /dev/null +++ b/contrib/babelfishpg_tds/src/include/tds_protocol.h @@ -0,0 +1,81 @@ +/*------------------------------------------------------------------------- + * + * tds_protocol.h + * Definitions for TDS protocol related structures and functions + * + * Portions Copyright (c) 2020, AWS + * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/tds/tds_protocol.h + * + *------------------------------------------------------------------------- + */ + +#ifndef TDS_PROTOCOL_H +#define TDS_PROTOCOL_H + +#include "src/include/tds_request.h" + +/* + * Once the TDS login handshake is done, the backend should be in any of the + * following phasees: + * + * TDS_REQUEST_PHASE_INIT -- initial state + * TDS_REQUEST_PHASE_FETCH -- fetch a TDS packet and generate a TDSRequest + * TDS_REQUEST_PHASE_PROCESS -- process the request + * TDS_REQUEST_PHASE_FLUSH -- flush the response + * TDS_REQUEST_PHASE_ERROR -- handle error + * + * Once the login handshake is done, the backend enters the initial state. After + * that it goes into the following loop: + * + * Step INIT: Initializations. Currently, it's a no-op. + * Goto step FETCH + * + * Step Fetch: Fetch and parse a new TDS packet and generate a TDSRequest. + * Goto step ERROR in case of any error via elog() + * Goto step PROCESS otherwise + * + * Step PROCESS: Process the request and generate next libpq request (if any) + * that will be sent to the TCOP loop. + * Remain in step PROCESS if a libpq request is generated and return + * to TCOP loop + * Goto step ERROR in case of any error via elog() + * Goto step FLUSH if processing of the request is complete + * + * Step FLUSH: Flush the response (call TdsFlush), reset the request + * context and perform other cleanups (if any). Any error + * in this step will violate the TDS protocol. + * Goto step ERROR in case of any error via elog() (should be FATAL?) + * Goto step Fetch + * + * Step ERROR: Must have generated at least one error token before going + * into this phase. Generate more error tokens if required. + * Goto step FLUSH + */ +#define TDS_REQUEST_PHASE_INIT 0 +#define TDS_REQUEST_PHASE_FETCH 1 +#define TDS_REQUEST_PHASE_PROCESS 2 +#define TDS_REQUEST_PHASE_FLUSH 3 +#define TDS_REQUEST_PHASE_ERROR 4 + +/* + * We store the information required to process each phase in the following + * structure. + */ +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 */ + + /* denotes whether we've sent at least one done token */ + bool isEmptyResponse; + +} TdsRequestCtrlData; + +extern TdsRequestCtrlData *TdsRequestCtrl; + +#endif /* TDS_PROTOCOL_H */ diff --git a/contrib/babelfishpg_tds/src/include/tds_request.h b/contrib/babelfishpg_tds/src/include/tds_request.h new file mode 100644 index 00000000000..e0237088b27 --- /dev/null +++ b/contrib/babelfishpg_tds/src/include/tds_request.h @@ -0,0 +1,896 @@ +/*------------------------------------------------------------------------- + * + * tds_request.h + * This file contains definitions for structures and externs used + * for processing a TDS request. + * + * Portions Copyright (c) 2020, AWS + * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/tds/tds_request.h + * + *------------------------------------------------------------------------- + */ +#ifndef TDS_REQUEST_H +#define TDS_REQUEST_H + +#include "postgres.h" + +#include "lib/stringinfo.h" +#include "miscadmin.h" + +#include "src/include/tds_int.h" +#include "src/include/tds_typeio.h" +#include "src/collation.h" + +/* Different TDS request types returned by GetTDSRequest() */ +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_ATTN /* attention request */ +} TDSRequestType; + +/* Simple SQL batch */ +typedef struct TDSRequestSQLBatchData +{ + TDSRequestType reqType; + StringInfoData query; +} TDSRequestSQLBatchData; +typedef TDSRequestSQLBatchData *TDSRequestSQLBatch; + +/* + * TODO: Use below values as an ENUM, rather than MACRO + * Enum will flag out compile time error if any condition is missed + */ +#define SP_CURSOR 1 +#define SP_CURSOROPEN 2 +#define SP_CURSORPREPARE 3 +#define SP_CURSOREXEC 4 +#define SP_CURSORPREPEXEC 5 +#define SP_CURSORUNPREPARE 6 +#define SP_CURSORFETCH 7 +#define SP_CURSOROPTION 8 +#define SP_CURSORCLOSE 9 +#define SP_EXECUTESQL 10 +#define SP_PREPARE 11 +#define SP_EXECUTE 12 +#define SP_PREPEXEC 13 +#define SP_PREPEXECRPC 14 +#define SP_UNPREPARE 15 +#define SP_CUSTOMTYPE 16 + +/* Check if retStatus Not OK */ +#define CheckPLPStatusNotOKForTVP(temp, retStatus) \ +do \ +{ \ + if (retStatus != STATUS_OK) \ + { \ + 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 chunking format is incorrect for a " \ + "large object parameter of data type 0x%02X.", \ + temp->paramOrdinal + 1, temp->paramMeta.colName.data, temp->tvpInfo->rowCount, \ + i + 1, temp->tvpInfo->colMetaData[i].columnTdsType))); \ + } \ +} while(0) + +int ReadPlp(ParameterToken temp, StringInfo message, uint64_t *mainOffset); +/* Numbered Stored Procedure like sp_prepexec, sp_execute */ +typedef struct TDSRequestSPData +{ + 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 */ + + /* 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. + */ + 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; + + /* + * 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; + + 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). + */ + ParameterToken cursorPreparedHandleParameter; + ParameterToken cursorHandleParameter; + ParameterToken cursorExtraArg1; + ParameterToken cursorExtraArg2; + ParameterToken cursorExtraArg3; + + /* number of total dataParameters */ + uint16 nTotalParams; + + /* number of OUT dataParameters */ + uint16 nOutParams; + + /* + * cursor scorll option and concurrency control options (only valid for + * sp_cursoropen packet) + */ + int scrollopt; + int ccopt; + + /* + * TODO: Use as local variable rather than part of the structure + */ + Datum *boundParamsData; + char *boundParamsNullList; + Oid *boundParamsOidList; + + uint16 nTotalBindParams; + + /* True, if this is a stored procedure */ + bool isStoredProcedure; + + /* + * we store the OUT dataParameter pointers in the following array so that + * they can be accessed directly given their index. + */ + 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 + */ + int paramIndex; +} TDSRequestSPData; +typedef TDSRequestSPData *TDSRequestSP; + +typedef struct TDSRequestBulkLoadData +{ + TDSRequestType reqType; + int colCount; + int rowCount; + + BulkLoadColMetaData *colMetaData; /* Array of each column's metadata. */ + List *rowData; /* List holding each row. */ +} TDSRequestBulkLoadData; +typedef TDSRequestBulkLoadData *TDSRequestBulkLoad; + +/* Default handle value for a RPC request which doesn't use any handle */ +/* + * TODO: Check and correct the values for SP_HANDLE_INVALID + * and SP_CURSOR_HANDLE_INVALID + */ +#define SP_HANDLE_INVALID 0 +#define SP_CURSOR_PREPARED_HANDLE_START 1073741824 +#define SP_CURSOR_PREPARED_HANDLE_INVALID 0xFFFFFFFF +#define SP_CURSOR_HANDLE_INVALID 180150000 + +/* During parse, we should always send the base type OID if it exists. */ +#define SetParamMetadataCommonInfo(paramMeta, finfo) \ +do { \ + (paramMeta)->pgTypeOid = (finfo->ttmbasetypeid != InvalidOid) ? \ + finfo->ttmbasetypeid : finfo->ttmtypeid; \ + (paramMeta)->sendFunc = finfo->sendFuncPtr; \ +} while(0); + +#define GetPgOid(pgTypeOid, finfo) \ +do { \ + pgTypeOid = (finfo->ttmbasetypeid != InvalidOid) ? \ + finfo->ttmbasetypeid : finfo->ttmtypeid; \ +} while(0); + +/* Macro used to check if Next RPC Packet Exists. */ +#define RPCBatchExists(sp) (sp.batchSeparatorOffset < sp.messageLen) + +/* Transaction management request */ +typedef struct TDSRequestTxnMgmtData +{ + TDSRequestType reqType; + uint16_t txnReqType; + StringInfoData txnName; + uint8_t isolationLevel; + StringInfoData query; + + /* Commit/rollback requests can have optional begin transaction */ + struct TDSRequestTxnMgmtData *nextTxn; + +} TDSRequestTxnMgmtData; +typedef TDSRequestTxnMgmtData *TDSRequestTxnMgmt; + +typedef union TDSRequestData +{ + TDSRequestType reqType; + TDSRequestSQLBatchData sqlBatch; + TDSRequestSPData sp; + TDSRequestTxnMgmtData txnMgmt; +} TDSRequestData; +typedef TDSRequestData *TDSRequest; + +/* COLMETADATA flags */ +#define TDS_COLMETA_NULLABLE 0x01 +#define TDS_COLMETA_CASESEN 0x02 +#define TDS_COLMETA_UPD_RO 0x00 +#define TDS_COLMETA_UPD_RW 0x04 +#define TDS_COLMETA_UPD_UNKNOWN 0x08 +#define TDS_COLMETA_IDENTITY 0x10 +#define TDS_COLMETA_COMPUTED 0x20 + +#define TDS_COL_METADATA_DEFAULT_FLAGS TDS_COLMETA_NULLABLE | \ + TDS_COLMETA_UPD_UNKNOWN +#define TDS_COL_METADATA_NOT_NULL_FLAGS TDS_COLMETA_UPD_UNKNOWN + +/* Macro for TVP tokens. */ +#define TVP_ROW_TOKEN 0x01 +#define TVP_NULL_TOKEN 0xFFFF +#define TVP_ORDER_UNIQUE_TOKEN 0x10 +#define TVP_COLUMN_ORDERING_TOKEN 0x11 +#define TVP_END_TOKEN 0x00 + +static inline void +SetTvpRowData(ParameterToken temp, const StringInfo message, uint64_t *offset) +{ + TvpColMetaData *colmetadata = temp->tvpInfo->colMetaData; + TvpRowData *rowData = NULL; + char *messageData = message->data; + int retStatus = 0; + temp->tvpInfo->rowCount = 0; + while(messageData[*offset] == TVP_ROW_TOKEN) /* Loop over each row. */ + { + int i = 0; /* Current Column Number. */ + + if (rowData == NULL) /* First Row. */ + { + rowData = palloc0(sizeof(TvpRowData)); + temp->tvpInfo->rowData = rowData; + } + 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); + (*offset)++; + + 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) + { + case TDS_TYPE_INTEGER: + case TDS_TYPE_BIT: + case TDS_TYPE_FLOAT: + case TDS_TYPE_TIME: + case TDS_TYPE_DATE: + case TDS_TYPE_DATETIME2: + 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; + } + 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; + 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 (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; + + case TDS_TYPE_CHAR: + case TDS_TYPE_VARCHAR: + case TDS_TYPE_NCHAR: + 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) + { + 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 + { + 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; + } + } + 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; + 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; + } + 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; + } + i++; + } + } + 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, temp->tvpInfo->rowCount, temp->tvpInfo->colCount, temp->type))); + (*offset)++; +} +static inline void +SetColMetadataForTvp(ParameterToken temp,const StringInfo message, uint64_t *offset) +{ + uint8_t len; + uint16 colCount; + uint16 isTvpNull; + char *tempString; + int i = 0; + char *messageData = message->data; + StringInfo tempStringInfo = palloc( sizeof(StringInfoData)); + temp->tvpInfo->tvpTypeName = " "; + + /* Database-Name.Schema-Name.TableType-Name */ + for(; i < 3; i++) + { + len = messageData[(*offset)++]; + if (len != 0) + { + /* Database name not allowed in a TVP */ + 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))); + initStringInfo(tempStringInfo); + + tempString = palloc0(len * 2); + memcpy(tempString, &messageData[*offset], len * 2); + TdsUTF16toUTF8StringInfo(tempStringInfo, tempString,len * 2); + + *offset += len * 2; + temp->len += len; + + temp->tvpInfo->tvpTypeName = psprintf("%s.%s", temp->tvpInfo->tvpTypeName, tempStringInfo->data); + } + else if (i == 2) + { + /* Throw error if TabelType-Name is not provided */ + 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))); + } + } + temp->tvpInfo->tableName = tempStringInfo->data; + i = 0; + + temp->tvpInfo->tvpTypeName += 2; + + memcpy(&isTvpNull, &messageData[*offset], sizeof(uint16)); + if (isTvpNull != TVP_NULL_TOKEN) + { + /* + * TypeColumnMetaData = UserType Flags TYPE_INFO ColName ; + */ + TvpColMetaData *colmetadata; + memcpy(&colCount, &messageData[*offset], sizeof(uint16)); + colmetadata = palloc0(colCount * sizeof(TvpColMetaData)); + temp->tvpInfo->colCount = colCount; + *offset += sizeof(uint16); + + temp->isNull = false; + + 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))); + + /* UserType */ + memcpy(&colmetadata[i].userType, &messageData[*offset], sizeof(uint32_t)); + *offset += sizeof(uint32_t); + /* Flags */ + memcpy(&colmetadata[i].flags, &messageData[*offset], sizeof(uint32)); + *offset += sizeof(uint16); + + /* TYPE_INFO */ + colmetadata[i].columnTdsType = messageData[(*offset)++]; + switch(colmetadata[i].columnTdsType) + { + case TDS_TYPE_INTEGER: + case TDS_TYPE_BIT: + case TDS_TYPE_FLOAT: + case TDS_TYPE_MONEYN: + case TDS_TYPE_DATETIMEN: + case TDS_TYPE_UNIQUEIDENTIFIER: + colmetadata[i].maxLen = messageData[(*offset)++]; + break; + case TDS_TYPE_DECIMALN: + case TDS_TYPE_NUMERICN: + colmetadata[i].maxLen = messageData[(*offset)++]; + colmetadata[i].precision = messageData[(*offset)++]; + 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); + if (colmetadata[i].maxLen == 0xffff) + { + memcpy(&colmetadata[i].collation, &messageData[*offset], sizeof(uint32_t)); + *offset += sizeof(uint32_t); + colmetadata[i].sortId = messageData[(*offset)++]; + } + else + { + memcpy(&colmetadata[i].collation, &messageData[*offset], sizeof(uint32_t)); + *offset += sizeof(uint32_t); + colmetadata[i].sortId = messageData[(*offset)++]; + } + } + break; + case TDS_TYPE_XML: + { + colmetadata[i].maxLen = messageData[(*offset)++]; + } + break; + case TDS_TYPE_DATETIME2: + { + colmetadata[i].scale = messageData[(*offset)++]; + colmetadata[i].maxLen = 8; + } + break; + case TDS_TYPE_TIME: + { + 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; + case TDS_TYPE_DATE: + colmetadata[i].maxLen = 3; + break; + case TDS_TYPE_SQLVARIANT: + memcpy(&colmetadata[i].maxLen, &messageData[*offset], sizeof(uint32_t)); + *offset += sizeof(uint32_t); + break; + default: + 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))); + } + + if ((colmetadata[i].flags & TDS_COLMETA_COMPUTED) && ((messageData[*offset] == TVP_ORDER_UNIQUE_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))); + 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))); + i++; + (*offset)++; + } + temp->tvpInfo->colMetaData = colmetadata; /* Setting the column metadata in paramtoken. */ + + /* TODO Optional Metadata token:- [TVP_ORDER_UNIQUE] */ + if (messageData[*offset] == TVP_ORDER_UNIQUE_TOKEN) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Order unique token for TVP is not currently supported in Babelfish"))); + + /* TODO Optional Metadata token:- [TVP_COLUMN_ORDERING_TOKEN] */ + if (messageData[*offset] == TVP_COLUMN_ORDERING_TOKEN) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Column ordering token for TVP is not currently supported in Babelfish"))); + + 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))); + (*offset)++; + } + else + { + temp->isNull = true; /* If TVP is NULL. */ + (*offset) += 2; + } + SetTvpRowData(temp, message, offset); +} + +static inline void +SetColMetadataForFixedType(TdsColumnMetaData *col, uint8_t tdsType, uint8_t maxSize) +{ + col->sizeLen = 1; + + /* + * If column is Not NULL constrained then we don't want to send + * maxSize except for uniqueidentifier and xml. + * TODO: We should send TDS_COL_METADATA_NOT_NULL_FLAGS + * This needs to be done for identity contraints + */ + if (col->attNotNull && tdsType != TDS_TYPE_UNIQUEIDENTIFIER && tdsType != TDS_TYPE_XML) + { + col->metaLen = sizeof(col->metaEntry.type1) - 1; + col->metaEntry.type1.flags = TDS_COL_METADATA_NOT_NULL_FLAGS; + } + else + { + col->metaLen = sizeof(col->metaEntry.type1); + col->metaEntry.type1.flags = TDS_COL_METADATA_DEFAULT_FLAGS; + } + col->metaEntry.type1.tdsTypeId = tdsType; + col->metaEntry.type1.maxSize = maxSize; +} + +static inline void +SetColMetadataForCharType(TdsColumnMetaData *col, uint8_t tdsType, uint32_t codePage, + pg_enc encoding, uint16_t codeFlags, uint8_t sortId, + uint16_t maxSize) +{ + col->sizeLen = 2; + col->metaLen = sizeof(col->metaEntry.type2); + col->metaEntry.type2.flags = TDS_COL_METADATA_DEFAULT_FLAGS; + col->metaEntry.type2.tdsTypeId = tdsType; + col->metaEntry.type2.maxSize = maxSize; + + col->metaEntry.type2.collationInfo = codePage | (codeFlags << 20); + col->metaEntry.type2.charSet = sortId; + col->encoding = encoding; +} + +static inline void +SetColMetadataForTextType(TdsColumnMetaData *col, uint8_t tdsType, uint32_t codePage, + pg_enc encoding, uint16_t codeFlags, uint8_t sortId, + uint32_t maxSize) +{ + col->sizeLen = 3; + col->sendTableName = true; + col->metaLen = sizeof(col->metaEntry.type3); + col->metaEntry.type3.flags = TDS_COL_METADATA_DEFAULT_FLAGS; + col->metaEntry.type3.tdsTypeId = tdsType; + /* TODO: Remove the hardcoding :- BABEL-298 */ + col->metaEntry.type3.maxSize = 0x7fffffff; + + col->metaEntry.type3.collationInfo = codePage | (codeFlags << 20); + col->metaEntry.type3.charSet = sortId; + col->encoding = encoding; +} + +static inline void +SetColMetadataForImageType(TdsColumnMetaData *col, uint8_t tdsType) +{ + col->sizeLen = 1; + if (tdsType == TDS_TYPE_IMAGE) + { + col->sendTableName = true; + col->metaEntry.type8.maxSize = 0x7fffffff; + } + 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 + */ + 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; +} + +static inline void +SetColMetadataForDateType(TdsColumnMetaData *col, uint8_t tdsType) +{ + col->sizeLen = 1; + col->metaLen = sizeof(col->metaEntry.type4); + col->metaEntry.type4.flags = TDS_COL_METADATA_DEFAULT_FLAGS; + col->metaEntry.type4.tdsTypeId = tdsType; +} + +static inline void +SetColMetadataForNumericType(TdsColumnMetaData *col, uint8_t tdsType, + uint8_t maxSize, uint8_t precision, uint8_t scale) +{ + col->sizeLen = 1; + col->metaLen = sizeof(col->metaEntry.type5); + col->metaEntry.type5.flags = TDS_COL_METADATA_DEFAULT_FLAGS; + col->metaEntry.type5.tdsTypeId = tdsType; + col->metaEntry.type5.maxSize = maxSize; + col->metaEntry.type5.precision = precision; + col->metaEntry.type5.scale = scale; +} + +static inline void +SetColMetadataForBinaryType(TdsColumnMetaData *col, uint8_t tdsType, uint16_t maxSize) +{ + col->sizeLen = 1; + col->metaLen = sizeof(col->metaEntry.type7); + col->metaEntry.type7.flags = TDS_COL_METADATA_DEFAULT_FLAGS; + col->metaEntry.type7.tdsTypeId = tdsType; + col->metaEntry.type7.maxSize = maxSize; +} + +static inline void +SetColMetadataForTimeType(TdsColumnMetaData *col, uint8_t tdsType, uint8_t scale) +{ + col->sizeLen = 1; + col->metaLen = sizeof(col->metaEntry.type6); + col->metaEntry.type6.flags = TDS_COL_METADATA_DEFAULT_FLAGS; + col->metaEntry.type6.tdsTypeId = tdsType; + col->metaEntry.type6.scale = scale; +} + +/* + * SetColMetadataForCharTypeHelper - set the collation for tds char datatypes by + * doing lookup on the hashtable setup by babelfishpg_tsql extension, which maps + * postgres collation to TSQL. If no entry is found then set the default + * TSQL collation values. + */ +static inline void +SetColMetadataForCharTypeHelper(TdsColumnMetaData *col, uint8_t tdsType, + Oid collation, int32 atttypmod) +{ + coll_info_t cinfo; + pg_enc enc; + + cinfo = (pltsql_plugin_handler_ptr)->lookup_collation_table_callback(collation); + + /* + * TODO: Remove the NULL condition once all the Postgres collations are mapped + * to TSQL + */ + if (cinfo.oid == InvalidOid) + { + enc = TdsLookupEncodingByLCID(TdsDefaultLcid); + SetColMetadataForCharType(col, tdsType, + TdsDefaultLcid, /* collation lcid */ + enc, + TdsDefaultCollationFlags, /* collation flags */ + TdsDefaultSortid, /* sort id */ + atttypmod); + } + else + { + enc = TdsLookupEncodingByLCID(cinfo.lcid); + SetColMetadataForCharType(col, tdsType, + cinfo.lcid, + enc, + cinfo.collateflags, + cinfo.sortid, + atttypmod); + } +} + +/* + * SetColMetadataForTextTypeHelper - set the collation for tds text datatypes by + * doing lookup on the hashtable setup by babelfishpg_tsql extension, which maps + * postgres collation to TSQL. If no entry is found then set the default + * TSQL collation values. + */ +static inline void +SetColMetadataForTextTypeHelper(TdsColumnMetaData *col, uint8_t tdsType, + Oid collation, int32 atttypmod) +{ + coll_info_t cinfo; + pg_enc enc; + + cinfo = (pltsql_plugin_handler_ptr)->lookup_collation_table_callback(collation); + + /* + * TODO: Remove the NULL condition once all the Postgres collations are mapped + * to TSQL + */ + if (cinfo.oid == InvalidOid) + { + enc = TdsLookupEncodingByLCID(TdsDefaultLcid); + SetColMetadataForTextType(col, tdsType, + TdsDefaultLcid, /* collation lcid */ + enc, + TdsDefaultCollationFlags, /* collation flags */ + TdsDefaultSortid, /* sort id */ + atttypmod); + } + else + { + enc = TdsLookupEncodingByLCID(cinfo.lcid); + SetColMetadataForTextType(col, tdsType, + cinfo.lcid, + enc, + cinfo.collateflags, + cinfo.sortid, + atttypmod); + } +} + +/* Functions in tdssqlbatch.c */ +extern TDSRequest GetSQLBatchRequest(StringInfo message); +extern void ProcessSQLBatchRequest(TDSRequest request); +extern void ExecuteSQLBatch(char *query); + +/* Funtions in tdsrpc.c */ +extern TDSRequest GetRPCRequest(StringInfo message); +extern void RestoreRPCBatch(StringInfo message, uint8_t *status, uint8_t *messageType); +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); + +/* Functions in tdsbulkload.c */ +extern TDSRequest GetBulkLoadRequest(StringInfo message); +extern void ProcessBCPRequest(TDSRequest request); + +#endif /* TDS_REQUEST_H */ diff --git a/contrib/babelfishpg_tds/src/include/tds_response.h b/contrib/babelfishpg_tds/src/include/tds_response.h new file mode 100644 index 00000000000..9d698dfb135 --- /dev/null +++ b/contrib/babelfishpg_tds/src/include/tds_response.h @@ -0,0 +1,102 @@ +/*------------------------------------------------------------------------- + * + * tds_response.h + * This file contains definitions for structures and externs used + * by the response module of TDS listener. + * + * Portions Copyright (c) 2020, AWS + * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/libpq/tds_response.h + * + *------------------------------------------------------------------------- + */ +#ifndef TDS_H +#define TDS_H + +#include "nodes/pg_list.h" + +#include "tds_int.h" + +/* TDS token types */ +#define TDS_TOKEN_COLMETADATA 0x81 +#define TDS_TOKEN_COLINFO 0xA5 +#define TDS_TOKEN_ERROR 0xAA +#define TDS_TOKEN_INFO 0xAB +#define TDS_TOKEN_LOGINACK 0xAD +#define TDS_TOKEN_ROW 0xD1 +#define TDS_TOKEN_NBCROW 0xD2 +#define TDS_TOKEN_ENVCHANGE 0xE3 +#define TDS_TOKEN_SSPI 0xED +#define TDS_TOKEN_DONE 0xFD +#define TDS_TOKEN_DONEINPROC 0xFF +#define TDS_TOKEN_DONEPROC 0xFE +#define TDS_TOKEN_RETURNSTATUS 0x79 +#define TDS_TOKEN_RETURNVALUE 0xAC +#define TDS_TOKEN_TABNAME 0xA4 + +/* TDS done codes */ +#define TDS_DONE_FINAL 0x00 +#define TDS_DONE_MORE 0x01 +#define TDS_DONE_ERROR 0x02 +#define TDS_DONE_INXACT 0x04 +#define TDS_DONE_COUNT 0x10 +#define TDS_DONE_ATTN 0x20 + +/* TDS command types in DONE token */ +#define TDS_CMD_UNKNOWN 0x02 +#define TDS_CMD_SET 0xBE +#define TDS_CMD_SELECT 0xC1 +#define TDS_CMD_INSERT 0xC3 +#define TDS_CMD_DELETE 0xC4 +#define TDS_CMD_UPDATE 0xC5 +#define TDS_CMD_ROLLBACK 0xD2 +#define TDS_CMD_BEGIN 0xD4 +#define TDS_CMD_COMMIT 0xD5 +#define TDS_CMD_EXECUTE 0xE0 +#define TDS_CMD_INFO 0xF7 + +/* Functions in tdsresponse.c */ +extern void InitTDSResponse(void); +extern void TdsResponseReset(void); +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); +extern void TdsSendDone(int tag, int status, + 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); +extern void SendReturnValueTokenInternal(ParameterToken token, uint8 status, + 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); +extern void TdsPrepareReturnValueMetaData(TupleDesc typeinfo); +extern void TdsSendEnvChangeBinary(int envid, + 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); +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); +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, + bool terminate_batch); +extern void SendColumnMetadata(TupleDesc typeinfo, List *targetlist, int16 *formats); +extern bool GetTdsEstateErrorData(int *number, int *severity, int *state); + +#endif /* TDS_H */ diff --git a/contrib/babelfishpg_tds/src/include/tds_secure.h b/contrib/babelfishpg_tds/src/include/tds_secure.h new file mode 100644 index 00000000000..cfd9bcf6168 --- /dev/null +++ b/contrib/babelfishpg_tds/src/include/tds_secure.h @@ -0,0 +1,61 @@ +/*------------------------------------------------------------------------- + * + * tds_secure.h + * This file contains definitions for functions to register + * read and write TLS functions for Tds listener + * + * Portions Copyright (c) 2020, AWS + * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/tds/tds_secure.h + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#ifdef HAVE_NETINET_TCP_H +#include +#include +#endif + +#ifdef USE_OPENSSL +#include +#include +#include +#endif +#ifndef OPENSSL_NO_ECDH +#include +#endif + +#include "libpq/libpq.h" +#include "port/pg_bswap.h" + +#ifdef USE_SSL +#ifndef HAVE_BIO_GET_DATA +#define BIO_get_data(bio) (bio->ptr) +#define BIO_set_data(bio, data) (bio->ptr = data) +#endif +#endif + +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); +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); + +/* function defined in tdssecure.c and called from tdscomm.c */ +ssize_t +tds_secure_read(Port *port, void *ptr, size_t len); +ssize_t +tds_secure_write(Port *port, void *ptr, size_t len); + +/* function defined in tdssecure.c and called from tdslogin.c */ +void TdsFreeSslStruct(Port *port); diff --git a/contrib/babelfishpg_tds/src/include/tds_timestamp.h b/contrib/babelfishpg_tds/src/include/tds_timestamp.h new file mode 100644 index 00000000000..69c97ed2674 --- /dev/null +++ b/contrib/babelfishpg_tds/src/include/tds_timestamp.h @@ -0,0 +1,48 @@ +/*------------------------------------------------------------------------- + * + * tds_timestamp.h + * Definitions of handler functions for TDS timestamp datatype + * + * Portions Copyright (c) 2020, AWS + * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/tds/tds_timestamp.h + * + *------------------------------------------------------------------------- + */ +#include "utils/date.h" +#include "utils/timestamp.h" + +extern void TdsGetTimestampFromDayTime(uint32 numDays, uint64 numMicro, int tz, + Timestamp *timestamp, int scale); +extern void TdsGetDayTimeFromTimestamp(Timestamp value, uint32 *numDays, + uint64 *numSec, int scale); + +extern void TdsTimeDifferenceSmalldatetime(Datum value, uint16 *numDays, + uint16 *numMins); +extern void TdsTimeGetDatumFromSmalldatetime(uint16 numDays, uint16 numMins, + Timestamp *timestamp); +extern uint32 TdsDayDifference(Datum value); +extern void TdsTimeDifferenceDatetime(Datum value, uint32 *numDays, + uint32 *numTicks); +extern void TdsCheckDateValidity(DateADT result); +extern void TdsTimeGetDatumFromDays(uint32 numDays, uint64 *val); +extern void TdsTimeGetDatumFromDatetime(uint32 numDays, uint32 numTicks, + Timestamp *timestamp); +extern uint32 TdsGetDayDifferenceHelper(int day, int mon, int year, bool isDateType); + +/* + * structure for datatimeoffset support with separate time zone field + */ +typedef struct tsql_datetimeoffset +{ + int64 tsql_ts; + int16 tsql_tz; +} tsql_datetimeoffset; + +/* datetimeoffset macros */ +#define DATETIMEOFFSET_LEN MAXALIGN(sizeof(tsql_datetimeoffset)) +/* datetimeoffset default value in internal representation */ +#define DatetimeoffsetGetDatum(X) PointerGetDatum(X) +#define PG_RETURN_DATETIMEOFFSET(X) return DatetimeoffsetGetDatum(X) diff --git a/contrib/babelfishpg_tds/src/include/tds_typecode.h b/contrib/babelfishpg_tds/src/include/tds_typecode.h new file mode 100644 index 00000000000..427d3749200 --- /dev/null +++ b/contrib/babelfishpg_tds/src/include/tds_typecode.h @@ -0,0 +1,57 @@ +#ifndef TYPECODE_H +#define TYPECODE_H + +/* Persistent Type Code for SQL Variant Type */ +/* WARNING: EXISTING VALUES MUST NOT BE CHANGED */ + +#define SQLVARIANT_T 0 +#define DATETIMEOFFSET_T 1 +#define DATETIME2_T 2 +#define DATETIME_T 3 +#define SMALLDATETIME_T 4 +#define DATE_T 5 +#define TIME_T 6 +#define FLOAT_T 7 +#define REAL_T 8 +#define NUMERIC_T 9 +#define MONEY_T 10 +#define SMALLMONEY_T 11 +#define BIGINT_T 12 +#define INT_T 13 +#define SMALLINT_T 14 +#define TINYINT_T 15 +#define BIT_T 16 +#define NVARCHAR_T 17 +#define NCHAR_T 18 +#define VARCHAR_T 19 +#define CHAR_T 20 +#define VARBINARY_T 21 +#define BINARY_T 22 +#define UNIQUEIDENTIFIER_T 23 + +#define TIMESTAMP_L 8 +#define DATE_L 4 +#define DATETIMEOFFSET_L DATETIMEOFFSET_LEN +#define TIME_L 8 +#define FLOAT_L 8 +#define REAL_L 4 +#define FIXEDDECIMAL_L 8 +#define BIGINT_L 8 +#define INT_L 4 +#define SMALLINT_L 2 +#define BIT_L 1 +#define UNIQUEIDENTIFIER_L 16 + +#define IS_STRING_TYPE(t) \ + ( ((t) == NVARCHAR_T) || ((t) == NCHAR_T) \ + || ((t) == VARCHAR_T) || ((t) == CHAR_T)) + +#define IS_MONEY_TYPE(t) (((t) == MONEY_T) || ((t) == SMALLMONEY_T)) +#define IS_BINARY_TYPE(t) (((t) == VARBINARY_T) || ((t) == BINARY_T)) + +/* MACRO from fixed decimal */ +#ifndef FIXEDDECIMAL_MULTIPLIER +#define FIXEDDECIMAL_MULTIPLIER 10000LL +#endif + +#endif diff --git a/contrib/babelfishpg_tds/src/include/tds_typeio.h b/contrib/babelfishpg_tds/src/include/tds_typeio.h new file mode 100644 index 00000000000..2a50d8690e4 --- /dev/null +++ b/contrib/babelfishpg_tds/src/include/tds_typeio.h @@ -0,0 +1,474 @@ +/*------------------------------------------------------------------------- + * + * tds_typeio.h + * Definitions for PG-Datum <-> TDS-protocol conversion + * + * Portions Copyright (c) 2020, AWS + * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/tds/tds_typeio.h + * + *------------------------------------------------------------------------- + */ + +#ifndef TDS_TYPEIO_H +#define TDS_TYPEIO_H + +#include "fmgr.h" + +#include "tds_iofuncmap.h" + +/* Prototypes for Send and Receive IO functions */ + +/* Partial Length Prefixecd-bytes tokens */ +#define PLP_TERMINATOR 0x00000000 +#define PLP_NULL 0xFFFFFFFFFFFFFFFF +#define PLP_UNKNOWN_LEN 0xFFFFFFFFFFFFFFFE +#define PLP_CHUNCK_LEN 32000 + +/* + * TODO: Using a void * for the column meta data is an ugly hack. + * This is needed here now because there are circular + * dependencies with tds_int.h that I rather untangle + * in a separate CR than muddling it up into this one. + * -- Jan + * 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); + +/* COLMETADATA entry for types like INTEGER and SMALLINT */ +typedef struct __attribute__((packed)) ColMetaEntry1 +{ + uint16_t flags; + uint8_t tdsTypeId; + uint8_t maxSize; +} ColMetaEntry1; + +/* COLMETADATA entry for types like NVARCHAR */ +typedef struct __attribute__((packed)) ColMetaEntry2 +{ + uint16_t flags; + uint8_t tdsTypeId; + uint16_t maxSize; + /* + * collationInfo(32 bits): LCID/CodePage (20 bits) + + * collationFlags(8 bits) + version (4 bits) + */ + uint32_t collationInfo; + uint8_t charSet; /* sortID */ +} ColMetaEntry2; + + +/* COLMETADATA entry for types like TEXT */ +typedef struct __attribute__((packed)) ColMetaEntry3 +{ + uint16_t flags; + uint8_t tdsTypeId; + uint32_t maxSize; + /* + * collationInfo(32 bits): LCID/CodePage (20 bits) + + * collationFlags(8 bits) + version (4 bits) + */ + uint32_t collationInfo; + uint8_t charSet; /* sortID */ +} ColMetaEntry3; + +/* COLMETADATA entry for type like DATE */ +typedef struct __attribute__((packed)) ColMetaEntry4 +{ + uint16_t flags; + uint8_t tdsTypeId; +} ColMetaEntry4; + +/* COLMETADATA entry for type NUMERIC */ +typedef struct __attribute__((packed)) ColMetaEntry5 +{ + 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 +{ + uint16_t flags; + uint8_t tdsTypeId; + uint8_t scale; +} ColMetaEntry6; + +/* COLMETADATA entry for types like BINARY VARBINARY */ +typedef struct __attribute__((packed)) ColMetaEntry7 +{ + uint16_t flags; + uint8_t tdsTypeId; + uint16_t maxSize; +} ColMetaEntry7; + +/* COLMETADATA entry for type like IMAGE */ +typedef struct __attribute__((packed)) ColMetaEntry8 +{ + 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; +} ColMetaEntry; + +/* + * It stores the relation related information corresponding to + * a TdsColumnMetaData entry. We need this information to + * construct the COLMETADATA, TABNAME and COLINFO tokens. + */ +typedef struct TdsRelationMetaData +{ + 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 + */ + char *partName[4]; + + /* + * A 1-based index for this relation which is used while sending the + * COLINFO token. + */ + 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; + + /* + * 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 */ +} TdsColumnMetaData; + +/* Partial Length Prefixed-bytes */ +typedef struct PlpData +{ + unsigned long offset; + unsigned long len; + struct PlpData *next; +} PlpData; +typedef PlpData *Plp; + +typedef struct TvpColMetaData +{ + int userType; + uint16 flags; + uint8_t columnTdsType; + + /* For numeric and decimal. */ + uint8_t scale; + uint8_t precision; + + uint32_t collation; + uint8_t sortId; + + uint32_t maxLen; +} TvpColMetaData; + +typedef struct TvpRowData +{ + /* Array of length col count, holds value of each column in that row. */ + StringInfo columnValues; + + 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. */ +} TvpData; + +typedef struct BulkLoadColMetaData +{ + int userType; + uint16 flags; + uint8_t columnTdsType; + + /* For numeric and decimal. */ + uint8_t scale; + uint8_t precision; + + /* For String Datatpes. */ + uint32_t collation; + uint8_t sortId; + + uint32_t maxLen; + + uint32_t colNameLen; + char *colName; + + bool variantType; +} BulkLoadColMetaData; + +typedef struct BulkLoadRowData +{ + /* Array of length col count, holds value of each column in that row. */ + StringInfo columnValues; + + char *isNull; +} BulkLoadRowData; + +/* Map TVP to its underlying table, either by relid or by table name. */ +typedef struct TvpLookupItem +{ + char *name; + Oid tableRelid; + char *tableName; +} TvpLookupItem; + +/* parameter token in RPC */ +typedef struct ParameterTokenData +{ + 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. + */ + uint32_t maxLen; + uint32_t len; + bool isNull; + + 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. + */ + int dataOffset; + + 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. + */ + TdsColumnMetaData paramMeta; + + /* + * If this is an OUT parameter, it points to the column number in the + * result set. + */ + int outAttNo; + + TvpData *tvpInfo; + struct ParameterTokenData *next; +} ParameterTokenData; + +typedef ParameterTokenData *ParameterToken; + + +typedef Datum (*TdsRecvTypeFunction)(const char *, const ParameterToken); + +/* + * TdsCollationData - hash table structure for + * mapping Postgres - TSQL Collation + */ +typedef struct TdsCollationData +{ + Oid collationOid; + int32_t codePage; + int32_t collateFlags; + int32_t sortId; +} TdsCollationData; + +typedef TdsCollationData *TdsCollationInfo; + +/* + * TdsLCIDToEncodingMap - hash table structure to + * store LCID - Encoding pair + */ +typedef struct TdsLCIDToEncodingMap +{ + int lcid; + int enc; +} TdsLCIDToEncodingMap; + +typedef TdsLCIDToEncodingMap *TdsLCIDToEncodingMapInfo; +/* + * TdsIoFunctionData - hash table entry for IO function cache + * TdsIoFunctionRawData - Raw Table data entry for TdsIoFunctionData + */ + +typedef struct TdsIoFunctionRawData +{ + const char *typnsp; + const char *typname; + 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; +} TdsIoFunctionData; + +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 StringInfo TdsGetStringInfoBufferFromToken(const char *message, + const ParameterToken token); +extern StringInfo TdsGetPlpStringInfoBufferFromToken(const char *message, + const ParameterToken token); +extern void TdsReadUnicodeDataFromTokenCommon(const char *message, + 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 Datum TdsRecvTypeBit(const char *, const ParameterToken); +extern Datum TdsRecvTypeTinyInt(const char *, const ParameterToken); +extern Datum TdsRecvTypeSmallInt(const char *, const ParameterToken); +extern Datum TdsRecvTypeInteger(const char *, const ParameterToken); +extern Datum TdsRecvTypeBigInt(const char *, const ParameterToken); +extern Datum TdsRecvTypeFloat4(const char *, const ParameterToken); +extern Datum TdsRecvTypeFloat8(const char *, const ParameterToken); +extern Datum TdsRecvTypeVarchar(const char *, const ParameterToken); +extern Datum TdsRecvTypeNVarchar(const char *, const ParameterToken); +extern Datum TdsRecvTypeMoney(const char *, const ParameterToken); +extern Datum TdsRecvTypeSmallmoney(const char *, const ParameterToken); +extern Datum TdsRecvTypeChar(const char *, const ParameterToken); +extern Datum TdsRecvTypeNChar(const char *, const ParameterToken); +extern Datum TdsRecvTypeText(const char *message, const ParameterToken); +extern Datum TdsRecvTypeNText(const char *message, const ParameterToken); +extern Datum TdsRecvTypeDate(const char *message, const ParameterToken); +extern Datum TdsRecvTypeDatetime(const char *message, const ParameterToken); +extern Datum TdsRecvTypeNumeric(const char *message, const ParameterToken); +extern Datum TdsRecvTypeSmalldatetime(const char *, const ParameterToken); +extern Datum TdsRecvTypeImage(const char *, const ParameterToken); +extern Datum TdsRecvTypeBinary(const char *message, const ParameterToken); +extern Datum TdsRecvTypeVarbinary(const char *message, const ParameterToken); +extern Datum TdsRecvTypeUniqueIdentifier(const char *, const ParameterToken); +extern Datum TdsRecvTypeTime(const char *message, const ParameterToken); +extern Datum TdsRecvTypeDatetime2(const char *message, const ParameterToken); +extern Datum TdsRecvTypeXml(const char *, const ParameterToken); +extern Datum TdsRecvTypeTable(const char *, const ParameterToken); +extern Datum TdsRecvTypeSqlvariant(const char *message, const ParameterToken); +extern Datum TdsRecvTypeDatetimeoffset(const char *message, const ParameterToken); + +extern Datum TdsTypeBitToDatum(StringInfo buf); +extern Datum TdsTypeIntegerToDatum(StringInfo buf, int maxLen); +extern Datum TdsTypeFloatToDatum(StringInfo buf, int maxLen); +extern Datum TdsTypeVarcharToDatum(StringInfo buf, Oid pgTypeOid, uint32_t collation); +extern Datum TdsTypeNCharToDatum(StringInfo buf); +extern Datum TdsTypeNumericToDatum(StringInfo buf, int scale); +extern Datum TdsTypeVarbinaryToDatum(StringInfo buf); +extern Datum TdsTypeDatetime2ToDatum(StringInfo buf, int scale, int len); +extern Datum TdsTypeDatetimeToDatum(StringInfo buf); +extern Datum TdsTypeSmallDatetimeToDatum(StringInfo buf); +extern Datum TdsTypeDateToDatum(StringInfo buf); +extern Datum TdsTypeTimeToDatum(StringInfo buf, int scale, int len); +extern Datum TdsTypeDatetimeoffsetToDatum(StringInfo buf, int scale, int len); +extern Datum TdsTypeMoneyToDatum(StringInfo buf); +extern Datum TdsTypeSmallMoneyToDatum(StringInfo buf); +extern Datum TdsTypeXMLToDatum(StringInfo buf); +extern Datum TdsTypeUIDToDatum(StringInfo buf); +extern Datum TdsTypeSqlVariantToDatum(StringInfo buf); + +#endif /* TDS_TYPEIO_H */ diff --git a/contrib/babelfishpg_tds/src/include/tdsprinttup.h b/contrib/babelfishpg_tds/src/include/tdsprinttup.h new file mode 100644 index 00000000000..78fdf82d9d0 --- /dev/null +++ b/contrib/babelfishpg_tds/src/include/tdsprinttup.h @@ -0,0 +1,15 @@ +/*------------------------------------------------------------------------- + * + * tdsprinttup.h + * + * + * + * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/tds/tdsprinttup.h + * + *------------------------------------------------------------------------- + */ + + diff --git a/contrib/babelfishpg_tsql/Makefile b/contrib/babelfishpg_tsql/Makefile new file mode 100644 index 00000000000..e99f5ca3e11 --- /dev/null +++ b/contrib/babelfishpg_tsql/Makefile @@ -0,0 +1,235 @@ +# Note: this Makefile uses pg_config to find various header +# files and built tools. +include Version.config + +EXTENSION = babelfishpg_tsql +EXTVERSION = $(PGTSQL_MAJOR_VERSION).$(PGTSQL_MINOR_VERSION).$(PGTSQL_MICRO_VERSION) + +#subdir = contrib/babelfishpg_tsql + +# Note: +# Set PREV_EXTVERSION after release, i.e after release of 3.0.0, set PREV_EXTVERSION to 3.0.0 +# babel_upgrade test target should at the top of the src/test/regress/babel_schedule +# src/test/regress/sql/babel_upgrade.sql should be modified to include the PREV_EXTVERSION to test the upgrade path +# contrib/babelfishpg_tsql/sql/upgrades/$(EXTENSION)--$(PREV_EXTVERSION).sql should be present to test the upgrade path +PREV_EXTVERSION = 1.0.0 +MODULEPATH = $$libdir/$(EXTENSION)-$(PGTSQL_MAJOR_VERSION) +MODULE_big = $(EXTENSION) + +# $(OBJS) should contain the name of each .o file that +# we link into the extension +OBJS = src/pl_gram.o src/pl_handler.o src/pl_comp.o src/pl_exec.o +OBJS += src/pl_funcs.o src/pl_scanner.o $(WIN32RES) +OBJS += src/pl_comp-2.o +OBJS += src/properties.o +OBJS += src/databasepropertyex.o +OBJS += src/plan_inval.o +OBJS += src/procedures.o +OBJS += src/cursor.o +OBJS += src/applock.o +OBJS += src/pltsql_coerce.o +OBJS += runtime/functions.o +OBJS += src/err_handler.o +OBJS += src/pltsql_function_probin_handler.o +OBJS += src/pltsql_utils.o +OBJS += src/tablecmds.o +OBJS += src/stmt_walker.o +OBJS += src/codegen.o +OBJS += src/dynavec.o +OBJS += src/dynastack.o +OBJS += src/analyzer.o +OBJS += src/prepare.o +OBJS += src/compile_context.o +OBJS += src/collation.o src/string.o +OBJS += src/forxml.o +OBJS += src/pltsql_identity.o +OBJS += src/collationproperty.o +OBJS += src/rolecmds.o +OBJS += src/backend_parser/keywords.o +OBJS += src/backend_parser/parser.o +OBJS += src/backend_parser/scan-backend.o +OBJS += src/backend_parser/gram-backend.o +OBJS += src/backend_parser/gram_hook.o +OBJS += src/dbcmds.o +OBJS += src/session.o +OBJS += src/guc.o +OBJS += src/catalog.o +OBJS += src/schemacmds.o +OBJS += src/hooks.o +OBJS += src/tsqlNodes.o +OBJS += src/tsqlHandler.o +OBJS += src/tsqlUnsupportedFeatureHandler.o +OBJS += src/tsqlIface.o +OBJS += antlr/libantlr_tsql.a +OBJS += src/multidb.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 + +PG_CXXFLAGS += -g -Werror +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 +PG_CPPFLAGS += -I$(TSQLSRC) -I$(PG_SRC) -DFAULT_INJECTOR + +SHLIB_LINK += -L$(ANTLR4_RUNTIME_LIB_DIR) $(ANTLR4_RUNTIME_LIB) -lcrypto + +UPGRADES = $(patsubst sql/upgrades/%.sql,sql/%.sql,$(wildcard sql/upgrades/*.sql)) + +# We need the previous version to test extension upgrade scripts +ifdef PREV_EXTVERSION +DATA = sql/$(EXTENSION)--$(PREV_EXTVERSION).sql +endif + +DATA_built = \ + $(EXTENSION).control \ + sql/$(EXTENSION)--$(EXTVERSION).sql $(UPGRADES) + +#include ../Makefile.common + +# Get Postgres version, as well as major (9.4, etc) version. Remove '.' from MAJORVER. +VERSION = $(shell $(PG_CONFIG) --version | awk '{print $$2}' | sed -e 's/devel$$//') +MAJORVER = $(shell echo $(VERSION) | cut -d . -f1,2 | tr -d .) + +# Function for testing a condition +test = $(shell test $(1) $(2) $(3) && echo yes || echo no) + +GE91 = $(call test, $(MAJORVER), -ge, 91) + +ifdef USE_PGXS +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/babelfishpg_tsql +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif + +ifeq ($(GE91),yes) +all: sql/$(EXTENSION)--$(EXTVERSION).sql $(UPGRADES) +endif + +$(EXTENSION).control: $(EXTENSION).control.in + cat $< \ + | sed -e 's|@EXTVERSION@|$(EXTVERSION)|g' \ + | sed -e 's|@EXTENSION@|$(EXTENSION)|g' \ + | sed -e 's|@MODULEPATH@|$(MODULEPATH)|g' \ + > $@ + +sql/$(EXTENSION)--$(EXTVERSION).sql: sql/$(EXTENSION).in + cpp $< | sed 's/^# /-- /g' > $@ + +sql/%.sql: sql/upgrades/%.sql + cp $< $@ + + +# $(KEYWORDS) should contain the name of each keyword +# file + +#KEYWORDS = src/pl_reserved_kwlist.h +KEYWORDS = src/pl_reserved_kwlist_d.h +#KEYWORDS += src/pl_unreserved_kwlist.h +KEYWORDS += src/pl_unreserved_kwlist_d.h + +#PERL := perl + +# where to find gen_keywordlist.pl and subsidiary files +TOOLSDIR = $(PG_SRC)/src/tools +GEN_KEYWORDLIST = $(PERL) -I $(TOOLSDIR) $(TOOLSDIR)/gen_keywordlist.pl +GEN_KEYWORDLIST_DEPS = $(TOOLSDIR)/gen_keywordlist.pl $(TOOLSDIR)/PerfectHash.pm +TSQLSRC = . + +antlr/Makefile: antlr/CMakeLists.txt antlr/TSqlLexer.g4 antlr/TSqlLexer.g4 + cd antlr && $(cmake) . && cd .. + +.PHONY: antlr/libantlr_tsql.a # to allow CMake's make check the build +antlr/libantlr_tsql.a: antlr/Makefile + $(MAKE) -C $(@D) all + +# See notes in src/backend/parser/Makefile about the following two rules +src/pl_gram.h: src/pl_gram.c + touch $@ + +src/pl_gram.c: BISONFLAGS += -d -v + +# generate plerrcodes.h: from src/backend/utils/errcodes.txt +src/plerrcodes.h: $(PG_SRC)/src/backend/utils/errcodes.txt src/generate-plerrcodes.pl + echo $(top_srcdir) + $(PERL) src/generate-plerrcodes.pl $< > $@ + +# generate keyword headers for the scanner +src/pl_reserved_kwlist_d.h: src/pl_reserved_kwlist.h $(GEN_KEYWORDLIST_DEPS) + $(GEN_KEYWORDLIST) --varname ReservedPLKeywords $< + +src/pl_unreserved_kwlist_d.h: src/pl_unreserved_kwlist.h $(GEN_KEYWORDLIST_DEPS) + $(GEN_KEYWORDLIST) --varname UnreservedPLKeywords $< + +src/pl_scanner.o: src/pl_scanner.c $(KEYWORDS) + +src/pl_comp.o: src/plerrcodes.h + +src/tsqlIface.o: src/tsqlIface.cpp + +src/tsqlUnsupportedFeatureHandler.o: src/tsqlUnsupportedFeatureHandler.cpp + +## extend backend parser +BEPARSERDIR=src/backend_parser + +src/backend_parser/kwlist_d.h: src/backend_parser/kwlist.h $(GEN_KEYWORDLIST_DEPS) + $(GEN_KEYWORDLIST) --output src/backend_parser --varname pgtsql_ScanKeywords $< + +src/backend_parser/keywords.o: src/backend_parser/keywords.c src/backend_parser/kwlist_d.h + +src/backend_parser/gram-backend.y: $(PG_SRC)/src/backend/parser/gram.y $(BEPARSERDIR)/gram-tsql-prologue.y.h $(BEPARSERDIR)/gram-tsql-decl.y $(BEPARSERDIR)/gram-tsql-rule.y $(BEPARSERDIR)/gram-tsql-epilogue.y.c $(BEPARSERDIR)/include.pl + $(PERL) $(BEPARSERDIR)/include.pl $(BEPARSERDIR) gram.y < $< > $@ + +src/backend_parser/gram-backend.c: BISONFLAGS += -d + +src/backend_parser/gram-backend.c: src/backend_parser/gram-backend.y + +src/backend_parser/gram-backend.h: src/backend_parser/gram-backend.c + touch $@ + +src/backend_parser/scan-backend.l: $(PG_SRC)/src/backend/parser/scan.l $(BEPARSERDIR)/scan-tsql-prologue-top.l.h $(BEPARSERDIR)/scan-tsql-prologue.l.h $(BEPARSERDIR)/scan-tsql-decl.l $(BEPARSERDIR)/scan-tsql-rule.l $(BEPARSERDIR)/scan-tsql-epilogue.l.c + $(PERL) $(BEPARSERDIR)/include.pl $(BEPARSERDIR) scan.l < $< > $@ + +src/backend_parser/scan-backend.c: FLEXFLAGS = -CF -p -p +src/backend_parser/scan-backend.c: FLEX_NO_BACKUP=yes +src/backend_parser/scan-backend.c: FLEX_FIX_WARNING=yes + +ifneq ("$(wildcard $(FLEX))","") + FLEX_EXEC := $(FLEX) +else + FLEX_EXEC := flex # if $(FLEX) doens't exists (postgres and extension can be built in different nodes), use built-in flex +endif + +src/backend_parser/scan-backend.c: src/backend_parser/scan-backend.l + $(FLEX_EXEC) $(if $(FLEX_NO_BACKUP),-b) $(FLEXFLAGS) -o'$@' $< + @$(if $(FLEX_NO_BACKUP),if [ `wc -l &2; exit 1; fi) + $(if $(FLEX_FIX_WARNING),$(PERL) $(TOOLSDIR)/fix-old-flex-code.pl '$@') + +# 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 + +.DEFAULT_GOAL := all +.PHONY: sql/$(EXTENSION)--$(EXTVERSION).sql + +################################################################################ +## ANTLR Parser rules +################################################################################ +# ANTLR = antlr4 +# ANTLRFLAGS = -Dlanguage=Cpp -listener +# +# TSqlLexer.o : CXXFLAGS = -O -g -fpic -I/usr/local/include/antlr4-runtime -Wno-attributes -Wno-deprecated +# TSqlParser.o : CXXFLAGS = -O -g -fpic -I/usr/local/include/antlr4-runtime -Wno-attributes -Wno-deprecated +# +# TSqlParser.cpp: TSqlParser.g4 TSqlLexer.g4 +# $(ANTLR) $(ANTLRFLAGS) $< +# +# TSqlLexer.cpp: TSqlLexer.g4 +# $(ANTLR) $(ANTLRFLAGS) $< diff --git a/contrib/babelfishpg_tsql/Release.md b/contrib/babelfishpg_tsql/Release.md new file mode 100644 index 00000000000..98ad2f0c7ad --- /dev/null +++ b/contrib/babelfishpg_tsql/Release.md @@ -0,0 +1,49 @@ +How to release + +Date: 2020-12-23 + +Versioning Scheme +----------------- + +Goals +==== +* Provide frequent (weekly/bi-weekly) extension patches for pre-prod instances when we want to alter the existing database without loosing the data +* Test upgrades between patches + +Notes +==== +PgTsql release version is composed by PGTSQL_MAJOR_VERSION, +PGTSQL_MINOR_VERSION and PGTSQL_MICRO_VERSION components, all +set in Version.config. + +By default only *PGTSQL_MICRO_VERSION* is incremented between internal releases. + + +Internal release procedure by example +==== + +#### Preconditions +- Latest released version is `3.0.0`, i.e `PREV_EXTVERSION` is set to 3.0.0 +- Current development version is `3.0.1` i.e `Version.config` contains `PGTSQL_MAJOR_VERSION=3, PGTSQL_MINOR_VERSION=0 PGTSQL_MICRO_VERSION=1` +- There is an upgrade path `sql/upgrades/pgtsql--3.0.0--3.0.1.sql` +- There is an install script `sql/pgtsql--$(PREV_EXTVERSION).sql` to test upgrade path script +- babel_upgrade test is at the top of src/test/regress/babel_schedule +- `src/test/regress/sql/babel_upgrade.sql` is modified to include the `PREV_EXTVERSION` to test the upgrade path + +#### Development Procedure +- Developers alter `sql/upgrades/pgtsql--3.0.0--3.0.1.sql` with upgrade scripts. + +#### Release Procedure +- Release existing build +- set `PREV_EXTVERSION` to 3.0.1 +- Copy sql install script to sql/pgtsql--3.0.1.sql +- Alter `src/test/regress/sql/babel_upgrade.sql` with a new upgrade path test from `3.0.1` to `3.0.2` +- Increment PGTSQL_MICRO_VERSION to 2 +- Create an empty upgrade path in `sql/upgrades` from a previously released minor to a new development minor `sql/upgrades/pgtsql--3.0.1--3.0.2.sql` + + +Testing +==== + +bb installcheck-babel +* Extension upgrade test in `src/test/regress/sql/babel_upgrade.sql` \ No newline at end of file diff --git a/contrib/babelfishpg_tsql/Version.config b/contrib/babelfishpg_tsql/Version.config new file mode 100644 index 00000000000..8ed9b3dd140 --- /dev/null +++ b/contrib/babelfishpg_tsql/Version.config @@ -0,0 +1,7 @@ +# Version numbering central repository, to be included from various +# places during the build process + +PGTSQL_MAJOR_VERSION=1 +PGTSQL_MINOR_VERSION=1 +PGTSQL_MICRO_VERSION=0 + diff --git a/contrib/babelfishpg_tsql/antlr/CMakeLists.txt b/contrib/babelfishpg_tsql/antlr/CMakeLists.txt new file mode 100644 index 00000000000..4c464755328 --- /dev/null +++ b/contrib/babelfishpg_tsql/antlr/CMakeLists.txt @@ -0,0 +1,33 @@ +# minimum required CMAKE version +CMAKE_MINIMUM_REQUIRED(VERSION 3.7 FATAL_ERROR) + +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake-dir) + +# compiler must be 11 or 14 +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -O2 -ggdb -w -Wno-deprecated") +set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -fPIC -O2 -ggdb -w -Wno-deprecated") + +message(STATUS "CMAKE_C_FLAGS=${CMAKE_C_FLAGS}") + +# add antrl4cpp artifacts to project environment +#include_directories($ENV{ANTLR4_RUNTIME_INCLUDE_DIR}) +SET (MYDIR /usr/local/include/antlr4-runtime/) +include_directories(${MYDIR}) + +# set variable pointing to the antlr tool that supports C++ +# this is not required if the jar file can be found under PATH environment +set(ANTLR_EXECUTABLE ${PROJECT_SOURCE_DIR}/thirdparty/antlr/antlr-4.9.3-complete.jar) +# add macros to generate ANTLR Cpp code from grammar +find_package(ANTLR REQUIRED) + +antlr_target(SampleGrammarLexer TSqlLexer.g4 LEXER) +antlr_target(SampleGrammarParser TSqlParser.g4 PARSER LISTENER VISITOR + DEPENDS_ANTLR SampleGrammarLexer + COMPILE_FLAGS -lib ${ANTLR_SampleGrammarLexer_OUTPUT_DIR}) + +# include generated files in project environment +include_directories(${ANTLR_SampleGrammarLexer_OUTPUT_DIR}) +include_directories(${ANTLR_SampleGrammarParser_OUTPUT_DIR}) + +add_library(antlr_tsql STATIC ${ANTLR_SampleGrammarLexer_CXX_OUTPUTS} ${ANTLR_SampleGrammarParser_CXX_OUTPUTS}) diff --git a/contrib/babelfishpg_tsql/antlr/TSqlLexer.g4 b/contrib/babelfishpg_tsql/antlr/TSqlLexer.g4 new file mode 100644 index 00000000000..43fd969b9fe --- /dev/null +++ b/contrib/babelfishpg_tsql/antlr/TSqlLexer.g4 @@ -0,0 +1,1287 @@ +/* +T-SQL (Transact-SQL, MSSQL) grammar. +The MIT License (MIT). +Copyright (c) 2017, Mark Adams (madams51703@gmail.com) +Copyright (c) 2015-2017, Ivan Kochurkin (kvanttt@gmail.com), Positive Technologies. +Copyright (c) 2016, Scott Ure (scott@redstormsoftware.com). +Copyright (c) 2016, Rui Zhang (ruizhang.ccs@gmail.com). +Copyright (c) 2016, Marcus Henriksson (kuseman80@gmail.com). +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +lexer grammar TSqlLexer; + +@header +{ + extern bool pltsql_quoted_identifier; +} + +//Keywords +ABORT: A B O R T; +ABORT_AFTER_WAIT: A B O R T UNDERLINE A F T E R UNDERLINE W A I T; +ABSENT: A B S E N T; +ABSOLUTE: A B S O L U T E; +ACCENT_SENSITIVITY: A C C E N T UNDERLINE S E N S I T I V I T Y; +ACCESS: A C C E S S; +ACTION: A C T I O N; +ACTIVATION: A C T I V A T I O N; +ACTIVE: A C T I V E; +ADD: A D D; +ADDRESS: A D D R E S S; +ADMINISTER: A D M I N I S T E R; +AES: A E S; +AES_128: A E S UNDERLINE '128'; +AES_192: A E S UNDERLINE '192'; +AES_256: A E S UNDERLINE '256'; +AFFINITY: A F F I N I T Y; +AFTER: A F T E R; +AGGREGATE: A G G R E G A T E; +ALGORITHM: A L G O R I T H M; +ALL: A L L; +ALLOWED: A L L O W E D; +ALLOW_CONNECTIONS: A L L O W UNDERLINE C O N N E C T I O N S; +ALLOW_ENCRYPTED_VALUE_MODIFICATIONS: A L L O W UNDERLINE E N C R Y P T E D UNDERLINE V A L U E UNDERLINE M O D I F I C A T I O N S; +ALLOW_MULTIPLE_EVENT_LOSS: A L L O W UNDERLINE M U L T I P L E UNDERLINE E V E N T UNDERLINE L O S S; +ALLOW_SINGLE_EVENT_LOSS: A L L O W UNDERLINE S I N G L E UNDERLINE E V E N T UNDERLINE L O S S; +ALLOW_SNAPSHOT_ISOLATION: A L L O W UNDERLINE S N A P S H O T UNDERLINE I S O L A T I O N; +ALTER: A L T E R; +ALWAYS: A L W A Y S; +AND: A N D; +ANONYMOUS: A N O N Y M O U S; +ANSI_DEFAULTS: A N S I UNDERLINE D E F A U L T S; +ANSI_NULLS: A N S I UNDERLINE N U L L S; +ANSI_NULL_DEFAULT: A N S I UNDERLINE N U L L UNDERLINE D E F A U L T; +ANSI_NULL_DFLT_OFF: A N S I UNDERLINE N U L L UNDERLINE D F L T UNDERLINE O F F; +ANSI_NULL_DFLT_ON: A N S I UNDERLINE N U L L UNDERLINE D F L T UNDERLINE O N; +ANSI_PADDING: A N S I UNDERLINE P A D D I N G; +ANSI_WARNINGS: A N S I UNDERLINE W A R N I N G S; +ANY: A N Y; +APPEND: A P P E N D; +APPLICATION: A P P L I C A T I O N; +APPLICATION_LOG: A P P L I C A T I O N UNDERLINE L O G; +APPLY: A P P L Y; +ARITHABORT: A R I T H A B O R T; +ARITHIGNORE: A R I T H I G N O R E; +AS: A S; +ASC: A S C; +ASSEMBLY: A S S E M B L Y; +ASYMMETRIC: A S Y M M E T R I C; +ASYNCHRONOUS_COMMIT: A S Y N C H R O N O U S UNDERLINE C O M M I T; +ATOMIC: A T O M I C; +AT_KEYWORD: A T; +AUDIT: A U D I T; +AUDIT_GUID: A U D I T UNDERLINE G U I D; +AUTHENTICATE: A U T H E N T I C A T E; +AUTHENTICATION: A U T H E N T I C A T I O N; +AUTHORIZATION: A U T H O R I Z A T I O N; +AUTO: A U T O; +AUTOCOMMIT: A U T O C O M M I T; +AUTOGROW_ALL_FILES: A U T O G R O W UNDERLINE A L L UNDERLINE F I L E S; +AUTOGROW_SINGLE_FILE: A U T O G R O W UNDERLINE S I N G L E UNDERLINE F I L E; +AUTOMATED_BACKUP_PREFERENCE: A U T O M A T E D UNDERLINE B A C K U P UNDERLINE P R E F E R E N C E; +AUTOMATIC: A U T O M A T I C; +AUTO_CLEANUP: A U T O UNDERLINE C L E A N U P; +AUTO_CLOSE: A U T O UNDERLINE C L O S E; +AUTO_CREATE_STATISTICS: A U T O UNDERLINE C R E A T E UNDERLINE S T A T I S T I C S; +AUTO_SHRINK: A U T O UNDERLINE S H R I N K; +AUTO_UPDATE_STATISTICS: A U T O UNDERLINE U P D A T E UNDERLINE S T A T I S T I C S; +AUTO_UPDATE_STATISTICS_ASYNC: A U T O UNDERLINE U P D A T E UNDERLINE S T A T I S T I C S UNDERLINE A S Y N C; +AVAILABILITY: A V A I L A B I L I T Y; +AVAILABILITY_MODE: A V A I L A B I L I T Y UNDERLINE M O D E; +AVG: A V G; +BACKUP: B A C K U P; +BACKUP_PRIORITY: B A C K U P UNDERLINE P R I O R I T Y; +BEFORE: B E F O R E; +BEGIN: B E G I N; +BEGIN_DIALOG: B E G I N UNDERLINE D I A L O G; +BETWEEN: B E T W E E N; +BIGINT: B I G I N T; +BASE64: B A S E '64'; +BINARY_CHECKSUM: B I N A R Y UNDERLINE C H E C K S U M; +BINARY_KEYWORD: B I N A R Y; +BINDING: B I N D I N G; +BLOB_STORAGE: B L O B UNDERLINE S T O R A G E; +BLOCK: B L O C K; +BLOCKERS: B L O C K E R S; +BLOCKING_HIERARCHY: B L O C K I N G UNDERLINE H I E R A R C H Y; +BLOCKSIZE: B L O C K S I Z E; +BOUNDING_BOX: B O U N D I N G UNDERLINE B O X; +BREAK: B R E A K; +BROKER: B R O K E R; +BROKER_INSTANCE: B R O K E R UNDERLINE I N S T A N C E; +BROWSE: B R O W S E; +BUFFER: B U F F E R; +BUFFERCOUNT: B U F F E R C O U N T; +BULK: B U L K; +BULK_LOGGED: B U L K UNDERLINE L O G G E D; +BY: B Y; +CACHE: C A C H E; +CALLED: C A L L E D; +CALLER: C A L L E R; +CAP_CPU_PERCENT: C A P UNDERLINE C P U UNDERLINE P E R C E N T; +CASCADE: C A S C A D E; +CASE: C A S E; +CAST: C A S T; +CATALOG: C A T A L O G; +CATALOG_COLLATION: C A T A L O G UNDERLINE C O L L A T I O N; +CATCH: C A T C H; +CELLS_PER_OBJECT: C E L L S UNDERLINE P E R UNDERLINE O B J E C T; +CERTIFICATE: C E R T I F I C A T E; +CHANGE: C H A N G E; +CHANGES: C H A N G E S; +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; +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; +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_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; +CLEANUP_POLICY: C L E A N U P UNDERLINE P O L I C Y; +CLEAR: C L E A R; +CLOSE: C L O S E; +CLUSTER: C L U S T E R; +CLUSTERED: C L U S T E R E D; +COALESCE: C O A L E S C E; +COLLATE: C O L L A T E; +COLLECTION: C O L L E C T I O N; +COLUMN: C O L U M N; +COLUMNS: C O L U M N S; +COLUMNSTORE: C O L U M N S T O R E; +COLUMN_MASTER_KEY: C O L U M N UNDERLINE M A S T E R UNDERLINE K E Y; +COMMIT: C O M M I T; +COMMITTED: C O M M I T T E D; +COMPATIBILITY_LEVEL: C O M P A T I B I L I T Y UNDERLINE L E V E L; +COMPRESSION: C O M P R E S S I O N; +COMPUTE: C O M P U T E; +CONCAT: C O N C A T; +CONCAT_NULL_YIELDS_NULL: C O N C A T UNDERLINE N U L L UNDERLINE Y I E L D S UNDERLINE N U L L; +CONFIGURATION: C O N F I G U R A T I O N; +CONNECT: C O N N E C T; +CONNECTION: C O N N E C T I O N; +CONSTRAINT: C O N S T R A I N T; +CONTAINED: C O N T A I N E D; +CONTAINMENT: C O N T A I N M E N T; +CONTAINS: C O N T A I N S; +CONTAINSTABLE: C O N T A I N S T A B L E; +CONTENT: C O N T E N T; +CONTEXT: C O N T E X T; +CONTINUE: C O N T I N U E; +CONTINUE_AFTER_ERROR: C O N T I N U E UNDERLINE A F T E R UNDERLINE E R R O R; +CONTRACT: C O N T R A C T; +CONTRACT_NAME: C O N T R A C T UNDERLINE N A M E; +CONTROL: C O N T R O L; +CONVERSATION: C O N V E R S A T I O N; +CONVERT: C O N V E R T; +COOKIE: C O O K I E; +COPY_ONLY: C O P Y UNDERLINE O N L Y; +COUNT: C O U N T; +COUNTER: C O U N T E R; +COUNT_BIG: C O U N T UNDERLINE B I G; +CPU: C P U; +CREATE: C R E A T E; +CREATE_NEW: C R E A T E UNDERLINE N E W; +CREATION_DISPOSITION: C R E A T I O N UNDERLINE D I S P O S I T I O N; +CREDENTIAL: C R E D E N T I A L; +CROSS: C R O S S; +CRYPTOGRAPHIC: C R Y P T O G R A P H I C; +CUBE: C U B E; +CUME_DIST: C U M E UNDERLINE D I S T; +CURRENT: C U R R E N T; +CURRENT_DATE: C U R R E N T UNDERLINE D A T E; +CURRENT_TIME: C U R R E N T UNDERLINE T I M E; +CURRENT_TIMESTAMP: C U R R E N T UNDERLINE T I M E S T A M P; +CURRENT_USER: C U R R E N T UNDERLINE U S E R; +CURSOR: C U R S O R; +CURSOR_CLOSE_ON_COMMIT: C U R S O R UNDERLINE C L O S E UNDERLINE O N UNDERLINE C O M M I T; +CURSOR_DEFAULT: C U R S O R UNDERLINE D E F A U L T; +CUSTOM: C U S T O M; +CYCLE: C Y C L E; +D: [Dd]; +DATA: D A T A; +DATABASE: D A T A B A S E; +DATABASE_MIRRORING: D A T A B A S E UNDERLINE M I R R O R I N G; +DATA_COMPRESSION: D A T A UNDERLINE C O M P R E S S I O N; +DATA_CONSISTENCY_CHECK: D A T A UNDERLINE C O N S I S T E N C Y UNDERLINE C H E C K; +DATA_FLUSH_INTERVAL_SECONDS: D A T A UNDERLINE F L U S H UNDERLINE I N T E R V A L UNDERLINE S E C O N D S; +DATA_SOURCE: D A T A UNDERLINE S O U R C E; +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; +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; +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; +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; +DEALLOCATE: D E A L L O C A T E; +DECLARE: D E C L A R E; +DECRYPTION: D E C R Y P T I O N; +DEFAULT: D E F A U L T; +DEFAULT_DOUBLE_QUOTE: ["] D E F A U L T ["]; +DEFAULT_DATABASE: D E F A U L T UNDERLINE D A T A B A S E; +DEFAULT_FULLTEXT_LANGUAGE: D E F A U L T UNDERLINE F U L L T E X T UNDERLINE L A N G U A G E; +DEFAULT_LANGUAGE: D E F A U L T UNDERLINE L A N G U A G E; +DEFAULT_SCHEMA: D E F A U L T UNDERLINE S C H E M A; +DEFINITION: D E F I N I T I O N; +DELAY: D E L A Y; +DELAYED_DURABILITY: D E L A Y E D UNDERLINE D U R A B I L I T Y; +DELETE: D E L E T E; +DELETED: D E L E T E D; +DENSE_RANK: D E N S E UNDERLINE R A N K; +DENY: D E N Y; +DEPENDENTS: D E P E N D E N T S; +DES: D E S; +DESC: D E S C; +DESCRIPTION: D E S C R I P T I O N; +DESX: D E S X; +DHCP: D H C P; +DIAGNOSTICS: D I A G N O S T I C S; +DIALOG: D I A L O G; +DIFFERENTIAL: D I F F E R E N T I A L; +DIRECTORY_NAME: D I R E C T O R Y UNDERLINE N A M E; +DISABLE: D I S A B L E; +DISABLED: D I S A B L E D; +DISABLE_BROKER: D I S A B L E UNDERLINE B R O K E R; +DISK: D I S K; +DISK_DRIVE: [A-Z][:]; +DISTINCT: D I S T I N C T; +DISTRIBUTED: D I S T R I B U T E D; +DISTRIBUTED_AGG: D I S T R I B U T E D UNDERLINE A G G; +DOCUMENT: D O C U M E N T; +DOLLAR_ACTION: DOLLAR A C T I O N; +DOLLAR_EDGE_ID: DOLLAR E D G E UNDERLINE I D; // graph +DOLLAR_FROM_ID: DOLLAR F R O M UNDERLINE I D; // graph +DOLLAR_IDENTITY: DOLLAR I D E N T I T Y; +DOLLAR_NODE_ID: DOLLAR N O D E UNDERLINE I D; // graph +DOLLAR_PARTITION: DOLLAR P A R T I T I O N; +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; +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; +EDGE: E D G E; +ELEMENTS: E L E M E N T S; +ELSE: E L S E; +EMERGENCY: E M E R G E N C Y; +EMPTY: E M P T Y; +ENABLE: E N A B L E; +ENABLED: E N A B L E D; +ENABLE_BROKER: E N A B L E UNDERLINE B R O K E R; +ENCRYPTED_VALUE: E N C R Y P T E D UNDERLINE V A L U E; +ENCRYPTION: E N C R Y P T I O N; +ENCODING: E N C O D I N G; +END: E N D; +ENDPOINT: E N D P O I N T; +ENDPOINT_URL: E N D P O I N T UNDERLINE U R L; +ERRLVL: E R R L V L; +ERROR: E R R O R; +ERROR_BROKER_CONVERSATIONS: E R R O R UNDERLINE B R O K E R UNDERLINE C O N V E R S A T I O N S; +ESCAPE: E S C A P E; +EVENT: E V E N T; +EVENTDATA: E V E N T D A T A '(' ')'; +EVENT_RETENTION_MODE: E V E N T UNDERLINE R E T E N T I O N UNDERLINE M O D E; +EXCEPT: E X C E P T; +EXCLUSIVE: E X C L U S I V E; +EXEC: E X E C; +EXECUTE: E X E C U T E; +EXECUTABLE: E X E C U T A B L E; +EXECUTABLE_FILE: E X E C U T A B L E UNDERLINE F I L E; +EXECUTION_COUNT: E X E C U T I O N UNDERLINE C O U N T; +EXIST: E X I S T; +EXISTS: E X I S T S; +EXIT: E X I T; +EXPAND: E X P A N D; +EXPIREDATE: E X P I R E D A T E; +EXPIRY_DATE: E X P I R Y UNDERLINE D A T E; +EXPLICIT: E X P L I C I T; +EXTENSION: E X T E N S I O N; +EXTERNAL: E X T E R N A L; +EXTERNALPUSHDOWN: E X T E R N A L P U S H D O W N; +EXTERNAL_ACCESS: E X T E R N A L UNDERLINE A C C E S S; +EXTRACT: E X T R A C T; +FAILOVER: F A I L O V E R; +FAILOVER_MODE: F A I L O V E R UNDERLINE M O D E; +FAILURE: F A I L U R E; +FAILURECONDITIONLEVEL: F A I L U R E C O N D I T I O N L E V E L; +FAILURE_CONDITION_LEVEL: F A I L U R E UNDERLINE C O N D I T I O N UNDERLINE L E V E L; +FAIL_OPERATION: F A I L UNDERLINE O P E R A T I O N; +FAIL_UNSUPPORTED: F A I L UNDERLINE U N S U P P O R T E D; +FAN_IN: F A N UNDERLINE I N; +FALSE: F A L S E; +FAST: F A S T; +FAST_FORWARD: F A S T UNDERLINE F O R W A R D; +FETCH: F E T C H; +FIELD_TERMINATOR: F I E L D UNDERLINE T E R M I N A T O R; +FILE: F I L E; +FILEGROUP: F I L E G R O U P; +FILEGROWTH: F I L E G R O W T H; +FILENAME: F I L E N A M E; +FILEPATH: F I L E P A T H; +FILESTREAM: F I L E S T R E A M; +FILESTREAM_ON: F I L E S T R E A M UNDERLINE O N; +FILETABLE: F I L E T A B L E; +FILE_SNAPSHOT: F I L E UNDERLINE S N A P S H O T; +FILTER: F I L T E R; +FIPS_FLAGGER: F I P S UNDERLINE F L A G G E R; +FIRST: F I R S T; +FIRST_ROW: F I R S T UNDERLINE R O W; +FIRST_VALUE: F I R S T UNDERLINE V A L U E; +FMTONLY: F M T O N L Y; +FN: F N; +FOLLOWING: F O L L O W I N G; +FOR: F O R; +FORCE: F O R C E; +FORCED: F O R C E D; +FORCEPLAN: F O R C E P L A N; +FORCESEEK: F O R C E S E E K; +FORCE_FAILOVER_ALLOW_DATA_LOSS: F O R C E UNDERLINE F A I L O V E R UNDERLINE A L L O W UNDERLINE D A T A UNDERLINE L O S S; +FORCE_SERVICE_ALLOW_DATA_LOSS: F O R C E UNDERLINE S E R V I C E UNDERLINE A L L O W UNDERLINE D A T A UNDERLINE L O S S; +FOREIGN: F O R E I G N; +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; +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; +FULL: F U L L; +FULLSCAN: F U L L S C A N; +FULLTEXT: F U L L T E X T; +FUNCTION: F U N C T I O N; +GB: G B; +GENERATED: G E N E R A T E D; +GEOGRAPHY_AUTO_GRID: G E O G R A P H Y UNDERLINE A U T O UNDERLINE G R I D; +GEOGRAPHY_GRID: G E O G R A P H Y UNDERLINE G R I D; +GEOMETRY_AUTO_GRID: G E O M E T R Y UNDERLINE A U T O UNDERLINE G R I D; +GEOMETRY_GRID: G E O M E T R Y UNDERLINE G R I D; +GET: G E T; +GETANCESTOR: G E T A N C E S T O R; +GETDATE: G E T D A T E; +GETDESCENDANT: G E T D E S C E N D A N T; +GETLEVEL: G E T L E V E L; +GETREPARENTEDVALUE: G E T R E P A R E N T E D V A L U E; +GETROOT: G E T R O O T; +GETUTCDATE: G E T U T C D A T E; +GLOBAL: G L O B A L; +GOTO: G O T O; +GOVERNOR: G O V E R N O R; +GRANT: G R A N T; +GRIDS: G R I D S; +GROUP: G R O U P; +GROUPING: G R O U P I N G; +GROUPING_ID: G R O U P I N G UNDERLINE I D; +GROUP_MAX_REQUESTS: G R O U P UNDERLINE M A X UNDERLINE R E Q U E S T S; +GUID: G U I D; +HADR: H A D R; +HASH: H A S H; +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; +HIDDEN_RENAMED: H I D D E N; +HIGH: H I G H; +HINT: H I N T; +HISTORY_RETENTION_PERIOD: H I S T O R Y UNDERLINE R E T E N T I O N UNDERLINE P E R I O D; +HISTORY_TABLE: H I S T O R Y UNDERLINE T A B L E; +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; +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; +IDENTITY_VALUE: I D E N T I T Y UNDERLINE V A L U E; +IF: I F; +IGNORE_NONCLUSTERED_COLUMNSTORE_INDEX: I G N O R E UNDERLINE N O N C L U S T E R E D UNDERLINE C O L U M N S T O R E UNDERLINE I N D E X; +IIF: I I F; +IMMEDIATE: I M M E D I A T E; +IMPERSONATE: I M P E R S O N A T E; +IMPLICIT_TRANSACTIONS: I M P L I C I T UNDERLINE T R A N S A C T I O N S; +IMPORTANCE: I M P O R T A N C E; +IN: I N; +INCLUDE: I N C L U D E; +INCLUDE_NULL_VALUES: I N C L U D E UNDERLINE N U L L UNDERLINE V A L U E S; +INCREMENT: I N C R E M E N T; +INCREMENTAL: I N C R E M E N T A L; +INDEX: I N D E X; +INFINITE: I N F I N I T E; +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; +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; +INSTEAD: I N S T E A D; +INT: I N T; +INTERSECT: I N T E R S E C T; +INTERVAL: I N T E R V A L; +INTERVAL_LENGTH_MINUTES: I N T E R V A L UNDERLINE L E N G T H UNDERLINE M I N U T E S; +INTO: I N T O; +IO: I O; +IP: I P; +IS: I S; +ISDESCENDANTOF: I S D E S C E N D A N T O F; +ISNULL: I S N U L L; +ISOLATION: I S O L A T I O N; +JOB: J O B; +JOIN: J O I N; +JSON: J S O N; +KB: K B; +KEEP: K E E P; +KEEPFIXED: K E E P F I X E D; +KEEP_CDC: K E E P UNDERLINE C D C; +KEEP_REPLICATION: K E E P UNDERLINE R E P L I C A T I O N; +KERBEROS: K E R B E R O S; +KEY: K E Y; +KEYS: K E Y S; +KEYSET: K E Y S E T; +KEY_PATH: K E Y UNDERLINE P A T H; +KEY_SOURCE: K E Y UNDERLINE S O U R C E; +KEY_STORE_PROVIDER_NAME: K E Y UNDERLINE S T O R E UNDERLINE P R O V I D E R UNDERLINE N A M E; +KILL: K I L L; +LAG: L A G; +LANGUAGE: L A N G U A G E; +LAST: L A S T; +LAST_VALUE: L A S T UNDERLINE V A L U E; +LEAD: L E A D; +LEDGER: L E D G E R; +LEFT: L E F T; +LEVEL: L E V E L; +LIBRARY: L I B R A R Y; +LIFETIME: L I F E T I M E; +LIKE: L I K E; +LINENO: L I N E N O; +LINKED: L I N K E D; +LINUX: L I N U X; +LIST: L I S T; +LISTENER: L I S T E N E R; +LISTENER_IP: L I S T E N E R UNDERLINE I P; +LISTENER_PORT: L I S T E N E R UNDERLINE P O R T; +LISTENER_URL: L I S T E N E R UNDERLINE U R L; +LOAD: L O A D; +LOB_COMPACTION: L O B UNDERLINE C O M P A C T I O N; +LOCAL: L O C A L; +LOCAL_SERVICE_NAME: L O C A L UNDERLINE S E R V I C E UNDERLINE N A M E; +LOCATION: L O C A T I O N; +LOCK: L O C K; +LOCK_ESCALATION: L O C K UNDERLINE E S C A L A T I O N; +LOG: L O G; +LOGIN: L O G I N; +LOOP: L O O P; +LOW: L O W; +MANUAL: M A N U A L; +MARK: M A R K; +MASK: M A S K; +MASKED: M A S K E D; +MASTER: M A S T E R; +MATCHED: M A T C H E D; +MATERIALIZED: M A T E R I A L I Z E D; +MAX: M A X; +MAXDOP: M A X D O P; +MAXRECURSION: M A X R E C U R S I O N; +MAXSIZE: M A X S I Z E; +MAXTRANSFER: M A X T R A N S F E R; +MAXVALUE: M A X V A L U E; +MAX_CPU_PERCENT: M A X UNDERLINE C P U UNDERLINE P E R C E N T; +MAX_DISPATCH_LATENCY: M A X UNDERLINE D I S P A T C H UNDERLINE L A T E N C Y; +MAX_DOP: M A X UNDERLINE D O P; +MAX_DURATION: M A X UNDERLINE D U R A T I O N; +MAX_EVENT_SIZE: M A X UNDERLINE E V E N T UNDERLINE S I Z E; +MAX_FILES: M A X UNDERLINE F I L E S; +MAX_GRANT_PERCENT: M A X UNDERLINE G R A N T UNDERLINE P E R C E N T; +MAX_IOPS_PER_VOLUME: M A X UNDERLINE I O P S UNDERLINE P E R UNDERLINE V O L U M E; +MAX_MEMORY: M A X UNDERLINE M E M O R Y; +MAX_MEMORY_PERCENT: M A X UNDERLINE M E M O R Y UNDERLINE P E R C E N T; +MAX_OUTSTANDING_IO_PER_VOLUME: M A X UNDERLINE O U T S T A N D I N G UNDERLINE I O UNDERLINE P E R UNDERLINE V O L U M E; +MAX_PLANS_PER_QUERY: M A X UNDERLINE P L A N S UNDERLINE P E R UNDERLINE Q U E R Y; +MAX_PROCESSES: M A X UNDERLINE P R O C E S S E S; +MAX_QUEUE_READERS: M A X UNDERLINE Q U E U E UNDERLINE R E A D E R S; +MAX_ROLLOVER_FILES: M A X UNDERLINE R O L L O V E R UNDERLINE F I L E S; +MAX_SIZE: M A X UNDERLINE S I Z E; +MAX_SIZE_MB: M A X UNDERLINE S I Z E UNDERLINE M B; +MAX_STORAGE_SIZE_MB: M A X UNDERLINE S T O R A G E UNDERLINE S I Z E UNDERLINE M B; +MB: M B; +MEDIADESCRIPTION: M E D I A D E S C R I P T I O N; +MEDIANAME: M E D I A N A M E; +MEDIUM: M E D I U M; +MEMBER: M E M B E R; +MEMORY_OPTIMIZED_DATA: M E M O R Y UNDERLINE O P T I M I Z E D UNDERLINE D A T A; +MEMORY_PARTITION_MODE: M E M O R Y UNDERLINE P A R T I T I O N UNDERLINE M O D E; +MERGE: M E R G E; +MESSAGE: M E S S A G E; +MESSAGE_FORWARDING: M E S S A G E UNDERLINE F O R W A R D I N G; +MESSAGE_FORWARD_SIZE: M E S S A G E UNDERLINE F O R W A R D UNDERLINE S I Z E; +MIN: M I N; +MINUTE: M I N U T E; +MINUTES: M I N U T E S; +MINVALUE: M I N V A L U E; +MIN_ACTIVE_ROWVERSION: M I N UNDERLINE A C T I V E UNDERLINE R O W V E R S I O N; +MIN_CPU_PERCENT: M I N UNDERLINE C P U UNDERLINE P E R C E N T; +MIN_GRANT_PERCENT: M I N UNDERLINE G R A N T UNDERLINE P E R C E N T; +MIN_IOPS_PER_VOLUME: M I N UNDERLINE I O P S UNDERLINE P E R UNDERLINE V O L U M E; +MIN_MEMORY_PERCENT: M I N UNDERLINE M E M O R Y UNDERLINE P E R C E N T; +MIRROR: M I R R O R; +MIRROR_ADDRESS: M I R R O R UNDERLINE A D D R E S S; +MIXED_PAGE_ALLOCATION: M I X E D UNDERLINE P A G E UNDERLINE A L L O C A T I O N; +MODE: M O D E; +MODEL: M O D E L; +MODIFY: M O D I F Y; +MONTH: M O N T H; +MONTHS: M O N T H S; +MOVE: M O V E; +MULTI_USER: M U L T I UNDERLINE U S E R; +MUST_CHANGE: M U S T UNDERLINE C H A N G E; +NAME: N A M E; +NATIONAL: N A T I O N A L; +NATIVE_COMPILATION: N A T I V E UNDERLINE C O M P I L A T I O N; +NEGOTIATE: N E G O T I A T E; +NESTED_TRIGGERS: N E S T E D UNDERLINE T R I G G E R S; +NEW_ACCOUNT: N E W UNDERLINE A C C O U N T; +NEW_BROKER: N E W UNDERLINE B R O K E R; +NEW_PASSWORD: N E W UNDERLINE P A S S W O R D; +NEXT: N E X T; +NO: N O; +NOCHECK: N O C H E C K; +NOCOMPUTE: N O C O M P U T E; +NOCOUNT: N O C O U N T; +NODE: N O D E; +NODES: N O D E S; +NOEXEC: N O E X E C; +NOEXPAND: N O E X P A N D; +NOFORMAT: N O F O R M A T; +NOINIT: N O I N I T; +NONCLUSTERED: N O N C L U S T E R E D; +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; +NOREWIND: N O R E W I N D; +NOSKIP: N O S K I P; +NOT: N O T; +NOTIFICATION: N O T I F I C A T I O N; +NOTIFICATIONS: N O T I F I C A T I O N S; +NOUNLOAD: N O U N L O A D; +NOWAIT: N O W A I T; +NO_CHECKSUM: N O UNDERLINE C H E C K S U M; +NO_COMPRESSION: N O UNDERLINE C O M P R E S S I O N; +NO_EVENT_LOSS: N O UNDERLINE E V E N T UNDERLINE L O S S; +NO_PERFORMANCE_SPOOL: N O UNDERLINE P E R F O R M A N C E UNDERLINE S P O O L; +NO_TRUNCATE: N O UNDERLINE T R U N C A T E; +NO_WAIT: N O UNDERLINE W A I T; +NTILE: N T I L E; +NTLM: N T L M; +NULL_P: N U L L; +NULLIF: N U L L I F; +NUMANODE: N U M A N O D E; +NUMBER: N U M B E R; +NUMERIC_ROUNDABORT: N U M E R I C UNDERLINE R O U N D A B O R T; +OBJECT: O B J E C T; +OF: O F; +OFF: O F F; +OFFLINE: O F F L I N E; +OFFSET: O F F S E T; +OFFSETS: O F F S E T S; +OLD_ACCOUNT: O L D UNDERLINE A C C O U N T; +OLD_PASSWORD: O L D UNDERLINE P A S S W O R D; +ON: O N; +ONLINE: O N L I N E; +ONLY: O N L Y; +ON_FAILURE: O N UNDERLINE F A I L U R E; +OPEN: O P E N; +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; +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; +OPERATION_MODE: O P E R A T I O N UNDERLINE M O D E; +OPTIMISTIC: O P T I M I S T I C; +OPTIMIZE: O P T I M I Z E; +OPTION: O P T I O N; +OR: O R; +ORDER: O R D E R; +OUT: O U T; +OUTER: O U T E R; +OUTPUT: O U T P U T; +OVER: O V E R; +OVERRIDE: O V E R R I D E; +OWNER: O W N E R; +OWNERSHIP: O W N E R S H I P; +PAGE: P A G E; +PAGECOUNT: P A G E C O U N T; +PAGE_VERIFY: P A G E UNDERLINE V E R I F Y; +PARAM: P A R A M; +PARAMETERIZATION: P A R A M E T E R I Z A T I O N; +PARAM_NODE: P A R A M UNDERLINE N O D E; +PARSE: P A R S E; +PARSEONLY: P A R S E O N L Y; +PARTIAL: P A R T I A L; +PARTITION: P A R T I T I O N; +PARTITIONS: P A R T I T I O N S; +PARTNER: P A R T N E R; +PASSWORD: P A S S W O R D; +PATH: P A T H; +PAUSE: P A U S E; +PERCENT: P E R C E N T; +PERCENTILE_CONT: P E R C E N T I L E UNDERLINE C O N T; +PERCENTILE_DISC: P E R C E N T I L E UNDERLINE D I S C; +PERCENT_RANK: P E R C E N T UNDERLINE R A N K; +PERIOD: P E R I O D; +PERMISSION_SET: P E R M I S S I O N UNDERLINE S E T; +PERSISTED: P E R S I S T E D; +PERSIST_SAMPLE_PERCENT: P E R S I S T UNDERLINE S A M P L E UNDERLINE P E R C E N T; +PERSISTENT_LOG_BUFFER: P E R S I S T E N T UNDERLINE L O G UNDERLINE B U F F E R; +PER_CPU: P E R UNDERLINE C P U; +PER_DB: P E R UNDERLINE D B; +PER_NODE: P E R UNDERLINE N O D E; +PIVOT: P I V O T; +PLAN: P L A N; +PLATFORM: P L A T F O R M; +POISON_MESSAGE_HANDLING: P O I S O N UNDERLINE M E S S A G E UNDERLINE H A N D L I N G; +POLICY: P O L I C Y; +POOL: P O O L; +POPULATION: P O P U L A T I O N; +PORT: P O R T; +POSITION: P O S I T I O N; +PRECEDING: P R E C E D I N G; +PRECISION: P R E C I S I O N; +PREDICATE: P R E D I C A T E; +PREDICT: P R E D I C T; +PRIMARY: P R I M A R Y; +PRIMARY_ROLE: P R I M A R Y UNDERLINE R O L E; +PRINT: P R I N T; +PRIOR: P R I O R; +PRIORITY: P R I O R I T Y; +PRIORITY_LEVEL: P R I O R I T Y UNDERLINE L E V E L; +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; +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; +PROCESS: P R O C E S S; +PROFILE: P R O F I L E; +PROPERTY: P R O P E R T Y; +PROVIDER: P R O V I D E R; +PROVIDER_KEY_NAME: P R O V I D E R UNDERLINE K E Y UNDERLINE N A M E; +PUBLIC: P U B L I C; +PYTHON: P Y T H O N; +QUERY: Q U E R Y; +QUERYTRACEON: Q U E R Y T R A C E O N; +QUERY_CAPTURE_MODE: Q U E R Y UNDERLINE C A P T U R E UNDERLINE M O D E; +QUERY_CAPTURE_POLICY: Q U E R Y UNDERLINE C A P T U R E UNDERLINE P O L I C Y; +QUERY_STORE: Q U E R Y UNDERLINE S T O R E; +QUEUE: Q U E U E; +QUEUE_DELAY: Q U E U E UNDERLINE D E L A Y; +QUOTED_IDENTIFIER: Q U O T E D UNDERLINE I D E N T I F I E R; +R: [Rr]; +RAISERROR: R A I S E R R O R; +RANGE: R A N G E; +RANK: R A N K; +RAW: R A W; +RC2: R C '2'; +RC4: R C '4'; +RC4_128: R C '4' UNDERLINE '128'; +READ: R E A D; +READONLY: R E A D O N L Y; +READTEXT: R E A D T E X T; +READWRITE: R E A D W R I T E; +READ_COMMITTED_SNAPSHOT: R E A D UNDERLINE C O M M I T T E D UNDERLINE S N A P S H O T; +READ_ONLY: R E A D UNDERLINE O N L Y; +READ_ONLY_ROUTING_LIST: R E A D UNDERLINE O N L Y UNDERLINE R O U T I N G UNDERLINE L I S T; +READ_WRITE: R E A D UNDERLINE W R I T E; +READ_WRITE_FILEGROUPS: R E A D UNDERLINE W R I T E UNDERLINE F I L E G R O U P S; +REBUILD: R E B U I L D; +RECEIVE: R E C E I V E; +RECOMPILE: R E C O M P I L E; +RECONFIGURE: R E C O N F I G U R E; +RECOVERY: R E C O V E R Y; +RECURSIVE_TRIGGERS: R E C U R S I V E UNDERLINE T R I G G E R S; +REDISTRIBUTE: R E D I S T R I B U T E; +REDUCE: R E D U C E; +REFERENCES: R E F E R E N C E S; +REGENERATE: R E G E N E R A T E; +RELATED_CONVERSATION: R E L A T E D UNDERLINE C O N V E R S A T I O N; +RELATED_CONVERSATION_GROUP: R E L A T E D UNDERLINE C O N V E R S A T I O N UNDERLINE G R O U P; +RELATIVE: R E L A T I V E; +REMOTE: R E M O T E; +REMOTE_PROC_TRANSACTIONS: R E M O T E UNDERLINE P R O C UNDERLINE T R A N S A C T I O N S; +REMOTE_SERVICE_NAME: R E M O T E UNDERLINE S E R V I C E UNDERLINE N A M E; +REMOVE: R E M O V E; +REORGANIZE: R E O R G A N I Z E; +REPEATABLE: R E P E A T A B L E; +REPLACE: R E P L A C E; +REPLICA: R E P L I C A; +REPLICATE: R E P L I C A T E; +REPLICATION: R E P L I C A T I O N; +REQUEST_MAX_CPU_TIME_SEC: R E Q U E S T UNDERLINE M A X UNDERLINE C P U UNDERLINE T I M E UNDERLINE S E C; +REQUEST_MAX_MEMORY_GRANT_PERCENT: R E Q U E S T UNDERLINE M A X UNDERLINE M E M O R Y UNDERLINE G R A N T UNDERLINE P E R C E N T; +REQUEST_MEMORY_GRANT_TIMEOUT_SEC: R E Q U E S T UNDERLINE M E M O R Y UNDERLINE G R A N T UNDERLINE T I M E O U T UNDERLINE S E C; +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; +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; +RESOURCES: R E S O U R C E S; +RESOURCE_MANAGER_LOCATION: R E S O U R C E UNDERLINE M A N A G E R UNDERLINE L O C A T I O N; +RESTART: R E S T A R T; +RESTORE: R E S T O R E; +RESTRICT: R E S T R I C T; +RESTRICTED_USER: R E S T R I C T E D UNDERLINE U S E R; +RESULT: R E S U L T; +RESUME: R E S U M E; +RETAINDAYS: R E T A I N D A Y S; +RETENTION: R E T E N T I O N; +RETURN: R E T U R N; +RETURNS: R E T U R N S; +REVERT: R E V E R T; +REVOKE: R E V O K E; +REWIND: R E W I N D; +RIGHT: R I G H T; +ROBUST: R O B U S T; +ROLE: R O L E; +ROLLBACK: R O L L B A C K; +ROLLUP: R O L L U P; +ROOT: R O O T; +ROUTE: R O U T E; +ROW: R O W; +ROWCOUNT: R O W C O U N T; +ROWGUID: R O W G U I D; +ROWGUIDCOL: R O W G U I D C O L; +ROWS: R O W S; +ROW_NUMBER: R O W UNDERLINE N U M B E R; +RSA_1024: R S A UNDERLINE '1024'; +RSA_2048: R S A UNDERLINE '2048'; +RSA_3072: R S A UNDERLINE '3072'; +RSA_4096: R S A UNDERLINE '4096'; +RSA_512: R S A UNDERLINE '512'; +RULE: R U L E; +RUNTIME: R U N T I M E; +SAFE: S A F E; +SAFETY: S A F E T Y; +SAMPLE: S A M P L E; +SAVE: S A V E; +SCALEOUTEXECUTION: S C A L E O U T E X E C U T I O N; +SCHEDULER: S C H E D U L E R; +SCHEMA: S C H E M A; +SCHEMABINDING: S C H E M A B I N D I N G; +SCHEME: S C H E M E; +SCOPED: S C O P E D; +SCRIPT: S C R I P T; +SCROLL: S C R O L L; +SCROLL_LOCKS: S C R O L L UNDERLINE L O C K S; +SEARCH: S E A R C H; +SECOND: S E C O N D; +SECONDARY: S E C O N D A R Y; +SECONDARY_ONLY: S E C O N D A R Y UNDERLINE O N L Y; +SECONDARY_ROLE: S E C O N D A R Y UNDERLINE R O L E; +SECONDS: S E C O N D S; +SECRET: S E C R E T; +SECURABLES: S E C U R A B L E S; +SECURITY: S E C U R I T Y; +SECURITYAUDIT: S E C U R I T Y A U D I T; +SECURITY_LOG: S E C U R I T Y UNDERLINE L O G; +SEEDING_MODE: S E E D I N G UNDERLINE M O D E; +SELECT: S E L E C T; +SELECTIVE: S E L E C T I V E; +SELF: S E L F; +SEMANTICKEYPHRASETABLE: S E M A N T I C K E Y P H R A S E T A B L E; +SEMANTICSIMILARITYDETAILSTABLE: S E M A N T I C S I M I L A R I T Y D E T A I L S T A B L E; +SEMANTICSIMILARITYTABLE: S E M A N T I C S I M I L A R I T Y T A B L E; +SEMI_SENSITIVE: S E M I UNDERLINE S E N S I T I V E; +SEND: S E N D; +SENT: S E N T; +SEQUENCE: S E Q U E N C E; +SEQUENCE_NUMBER: S E Q U E N C E UNDERLINE N U M B E R; +SERIALIZABLE: S E R I A L I Z A B L E; +SERVER: S E R V E R; +SERVICE: S E R V I C E; +SERVICE_BROKER: S E R V I C E UNDERLINE B R O K E R; +SERVICE_NAME: S E R V I C E UNDERLINE N A M E; +SESSION: S E S S I O N; +SESSION_TIMEOUT: S E S S I O N UNDERLINE T I M E O U T; +SESSION_USER: S E S S I O N UNDERLINE U S E R; +SET: S E T; +SETERROR: S E T E R R O R; +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; +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; +SHRINKLOG: S H R I N K L O G; +SHUTDOWN: S H U T D O W N; +SID: S I D; +SIGNATURE: S I G N A T U R E; +SIMPLE: S I M P L E; +SINGLE_USER: S I N G L E UNDERLINE U S E R; +SINGLETON: S I N G L E T O N; +SIZE: S I Z E; +SIZE_BASED_CLEANUP_MODE: S I Z E UNDERLINE B A S E D UNDERLINE C L E A N U P UNDERLINE M O D E; +SKIP_KEYWORD: S K I P; +SMALLINT: S M A L L I N T; +SNAPSHOT: S N A P S H O T; +SOFTNUMA: S O F T N U M A; +SOME: S O M E; +SOURCE: S O U R C E; +SPARSE: S P A R S E; +SPATIAL: S P A T I A L; +SPATIAL_WINDOW_MAX_CELLS: S P A T I A L UNDERLINE W I N D O W UNDERLINE M A X UNDERLINE C E L L S; +SPECIFICATION: S P E C I F I C A T I O N; +SPLIT: S P L I T; +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; +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; +START: S T A R T; +STARTED: S T A R T E D; +STARTUP_STATE: S T A R T U P UNDERLINE S T A T E; +START_DATE: S T A R T UNDERLINE D A T E; +STATE: S T A T E; +STATEMENT: S T A T E M E N T; +STATIC: S T A T I C; +STATISTICAL_SEMANTICS: S T A T I S T I C A L UNDERLINE S E M A N T I C S; +STATISTICS: S T A T I S T I C S; +STATS: S T A T S; +STATS_STREAM: S T A T S UNDERLINE S T R E A M; +STATUS: S T A T U S; +STATUSONLY: S T A T U S O N L Y; +STDEV: S T D E V; +STDEVP: S T D E V P; +STOP: S T O P; +STOPAT: S T O P A T; +STOPATMARK: S T O P A T M A R K; +STOPBEFOREMARK: S T O P B E F O R E M A R K; +STOPLIST: S T O P L I S T; +STOPPED: S T O P P E D; +STOP_ON_ERROR: S T O P UNDERLINE O N UNDERLINE E R R O R; +STRING_AGG: S T R I N G UNDERLINE A G G; +STRING_DELIMITER: S T R I N G UNDERLINE D E L I M I T E R; +STUFF: S T U F F; +SUBJECT: S U B J E C T; +SUBSCRIBE: S U B S C R I B E; +SUBSCRIPTION: S U B S C R I P T I O N; +SUM: S U M; +SUPPORTED: S U P P O R T E D; +SUSPEND: S U S P E N D; +SWITCH: S W I T C H; +SYMMETRIC: S Y M M E T R I C; +SYNCHRONOUS_COMMIT: S Y N C H R O N O U S UNDERLINE C O M M I T; +SYNONYM: S Y N O N Y M; +SYSTEM: S Y S T E M; +SYSTEM_TIME: S Y S T E M UNDERLINE T I M E; +SYSTEM_USER: S Y S T E M UNDERLINE U S E R; +SYSTEM_VERSIONING: S Y S T E M UNDERLINE V E R S I O N I N G; +TABLE: T A B L E; +TABLESAMPLE: T A B L E S A M P L E; +TAKE: T A K E; +TAPE: T A P E; +TARGET: T A R G E T; +TARGET_RECOVERY_TIME: T A R G E T UNDERLINE R E C O V E R Y UNDERLINE T I M E; +T: [Tt]; +TB: T B; +TCP: T C P; +TEXTIMAGE_ON: T E X T I M A G E UNDERLINE O N; +TEXTSIZE: T E X T S I Z E; +THEN: T H E N; +THROW: T H R O W; +TIES: T I E S; +TIME: T I M E; +TIMEOUT: T I M E O U T; +TIMER: T I M E R; +TINYINT: T I N Y I N T; +TO: T O; +TOP: T O P; +TORN_PAGE_DETECTION: T O R N UNDERLINE P A G E UNDERLINE D E T E C T I O N; +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; +TRACKING: T R A C K I N G; +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; +TRANSACTION: T R A N S A C T I O N; +TRANSACTION_ID: T R A N S A C T I O N UNDERLINE I D; +TRANSFER: T R A N S F E R; +TRANSFORM_NOISE_WORDS: T R A N S F O R M UNDERLINE N O I S E UNDERLINE W O R D S; +TRIGGER: T R I G G E R; +TRIM: T R I M; +TRIPLE_DES: T R I P L E UNDERLINE D E S; +TRIPLE_DES_3KEY: T R I P L E UNDERLINE D E S UNDERLINE '3' K E Y; +TRUE: T R U E; +TRUNCATE: T R U N C A T E; +TRUSTWORTHY: T R U S T W O R T H Y; +TRY: T R Y; +TRY_CAST: T R Y UNDERLINE C A S T; +TRY_CONVERT: T R Y UNDERLINE C O N V E R T; +TRY_PARSE: T R Y UNDERLINE P A R S E; +TS: T S; +TSEQUAL: T S E Q U A L; +TSQL: T S Q L; +TWO_DIGIT_YEAR_CUTOFF: T W O UNDERLINE D I G I T UNDERLINE Y E A R UNDERLINE C U T O F F; +TYPE: T Y P E; +TYPE_WARNING: T Y P E UNDERLINE W A R N I N G; +UNBOUNDED: U N B O U N D E D; +UNCHECKED: U N C H E C K E D; +UNCOMMITTED: U N C O M M I T T E D; +UNDEFINED: U N D E F I N E D; +UNION: U N I O N; +UNIQUE: U N I Q U E; +UNKNOWN: U N K N O W N; +UNLIMITED: U N L I M I T E D; +UNLOCK: U N L O C K; +UNMASK: U N M A S K; +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; +UPDATETEXT: U P D A T E T E X T; +URL: U R L; +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; +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; +VALUE: V A L U E; +VALUES: V A L U E S; +VAR: V A R; +VARBINARY_KEYWORD: V A R B I N A R Y; +VARP: V A R P; +VARYING: V A R Y I N G; +VERBOSELOGGING: V E R B O S E L O G G I N G; +VERSION: V E R S I O N; +VIEW: V I E W; +VIEWS: V I E W S; +VIEW_METADATA: V I E W UNDERLINE M E T A D A T A; +VISIBILITY: V I S I B I L I T Y; +WAIT: W A I T; +WAITFOR: W A I T F O R; +WAIT_AT_LOW_PRIORITY: W A I T UNDERLINE A T UNDERLINE L O W UNDERLINE P R I O R I T Y; +WAIT_STATS_CAPTURE_MODE: W A I T UNDERLINE S T A T S UNDERLINE C A P T U R E UNDERLINE M O D E; +WEEK: W E E K; +WEEKS: W E E K S; +WELL_FORMED_XML: W E L L UNDERLINE F O R M E D UNDERLINE X M L; +WHEN: W H E N; +WHEN_SUPPORTED: W H E N UNDERLINE S U P P O R T E D; +WHERE: W H E R E; +WHILE: W H I L E; +WINDOWS: W I N D O W S; +WITH: W I T H; +WITHIN: W I T H I N; +WITHOUT: W I T H O U T; +WITHOUT_ARRAY_WRAPPER: W I T H O U T UNDERLINE A R R A Y UNDERLINE W R A P P E R; +WITNESS: W I T N E S S; +WORK: W O R K; +WORKLOAD: W O R K L O A D; +WRITETEXT: W R I T E T E X T; +XACT_ABORT: X A C T UNDERLINE A B O R T; +XMAX: X M A X; +XMIN: X M I N; +XML: X M L; +XMLDATA: X M L D A T A; +XMLNAMESPACES: X M L N A M E S P A C E S; +XMLSCHEMA: X M L S C H E M A; +XSINIL: X S I N I L; +XQUERY: X Q U E R Y; +YEAR: Y E A R; +YEARS: Y E A R S; +YMAX: Y M A X; +YMIN: Y M I N; +ZONE: Z O N E; + +//Build-ins: +VARCHAR: V A R C H A R; +NVARCHAR: N V A R C H A R; + + +SPACE: [ \t\r\n]+ -> skip; + +// the following are ignored by Tsql +CHAR_XA0_NBSP: '\u00a0' -> skip; // non-breaking space +CHAR_X08_BS: '\u0008' -> skip; // backspace +CHAR_X0B_VT: '\u000b' -> skip; // vertical tab +CHAR_X0C_FF: '\u000c' -> skip; // form feed + + +// https://docs.microsoft.com/en-us/sql/t-sql/language-elements/slash-star-comment-transact-sql +COMMENT: '/*' (COMMENT | .)*? '*/' -> skip; +LINE_COMMENT: '--' ~[\r\n]* -> skip; + +// The next two rules are mutually exclusive - which rule we choose depends on the +// value of QUOTED_IDENTIFIER guc, which reflects the SET QUOTED_IDENTFIER statements encountered. +// The first rule chooses to return a DOUBLE_QUOTE_ID if QUOTED_IDENTIFIER guc is true. +// The second rule chooses to return a STRING if QUOTED_IDENTIFIER guc is false +// NB: for performance reasons, put the QUOTED_IDENTIFIER guc condition at the end, not at the start. +DOUBLE_QUOTE_ID: '"' (~'"' | '""' )* '"' {pltsql_quoted_identifier == true}?; +STRING: 'N'? ('\'' (~'\'' | '\'\'')* '\'' | '"' (~'"' | '""')* '"' {pltsql_quoted_identifier == false}? ); + +SINGLE_QUOTE: '\''; +SQUARE_BRACKET_ID: '[' (~']' | ']' ']')* ']'; +LOCAL_ID: '@' ([_$@#0-9] | LETTER )*; + +DECIMAL: DEC_DIGIT+; +ID: ( [_#] | LETTER) ( [_#$@0-9] | LETTER)*; +BINARY: '0' [Xx] HEX_DIGIT*; +FLOAT: DEC_DOT_DEC; +REAL: (DECIMAL | DEC_DOT_DEC) ([Ee] ([+-]? DEC_DIGIT+)?); + +MONEY: CURRENCY_SYMBOL [ ]* ('+'|'-')? (DECIMAL | DEC_DOT_DEC); + +IPV4_ADDR: DECIMAL DOT DECIMAL DOT DECIMAL DOT DECIMAL; + +EQUAL: '='; + +GREATER: '>'; +LESS: '<'; +EXCLAMATION: '!'; + +PLUS_ASSIGN: '+='; +MINUS_ASSIGN: '-='; +MULT_ASSIGN: '*='; +DIV_ASSIGN: '/='; +MOD_ASSIGN: '%='; +AND_ASSIGN: '&='; +XOR_ASSIGN: '^='; +OR_ASSIGN: '|='; + +DOT: '.'; +UNDERLINE: '_'; +AT: '@'; +SHARP: '#'; +DOLLAR: '$'; +LR_BRACKET: '('; +RR_BRACKET: ')'; +L_CURLY: '{'; +R_CURLY: '}'; +COMMA: ','; +SEMI: ';'; +COLON: ':'; +STAR: '*'; +DIVIDE: '/'; +PERCENT_SIGN: '%'; +PLUS: '+'; +MINUS: '-'; +BIT_NOT: '~'; +BIT_OR: '|'; +BIT_AND: '&'; +BIT_XOR: '^'; + +BACKSLASH: '\\'; +DOUBLE_BACK_SLASH: '\\\\'; +DOUBLE_FORWARD_SLASH: '//'; + +fragment DEC_DOT_DEC: (DEC_DIGIT+ '.' DEC_DIGIT+ | DEC_DIGIT+ '.' | '.' DEC_DIGIT+); +fragment HEX_DIGIT: [0-9A-Fa-f]; +fragment DEC_DIGIT: [0-9]; + +// case-insensitive letters +fragment A: ('A'|'a'); +fragment B: ('B'|'b'); +fragment C: ('C'|'c'); +// fragment D: ('D'|'d'); // redundant, since already defined as token above +fragment E: ('E'|'e'); +fragment F: ('F'|'f'); +fragment G: ('G'|'g'); +fragment H: ('H'|'h'); +fragment I: ('I'|'i'); +fragment J: ('J'|'j'); +fragment K: ('K'|'k'); +fragment L: ('L'|'l'); +fragment M: ('M'|'m'); +fragment N: ('N'|'n'); +fragment O: ('O'|'o'); +fragment P: ('P'|'p'); +fragment Q: ('Q'|'q'); +// fragment R: ('R'|'r'); // redundant, since already defined as token above +fragment S: ('S'|'s'); +// fragment T: ('T'|'t'); // redundant, since already defined as token above +fragment U: ('U'|'u'); +fragment V: ('V'|'v'); +fragment W: ('W'|'w'); +fragment X: ('X'|'x'); +fragment Y: ('Y'|'y'); +fragment Z: ('Z'|'z'); + +fragment CURRENCY_SYMBOL + : '$' // Dollar + | '\u20AC' // Euro + | '\u00A2' // Cent + | '\u00A3' // Pound + | '\u00A4' // Currency Sign + | '\u00A5' // Yen / Yuan + | '\u09f2' // Bengali Rupee Mark + | '\u09f3' // Bengali Rupee Sign + | '\u20a8' // Rupee + | '\u0e3f' // Thai Baht + | '\u17db' // Khmer Riel + | '\u20a0' // Euro Currency Sign + | '\u20a1' // Colon + | '\u20a2' // Cruzeiro + | '\u20a3' // French Franc + | '\u20a4' // Lira + | '\u20a5' // Mill + | '\u20a6' // Naira + | '\u20a7' // Peseta + | '\u20a9' // Won + | '\u20aa' // New Sheqel + | '\u20ab' // Dong + | '\u20ad' // Kip + | '\u20ae' // Tugrik + | '\u20af' // Drachma + | '\u20b0' // German Penny + | '\u20b1' // Peso + | '\ufdfc' // Rial + | '\ufe69' // Small Dollar + | '\uff04' // Fullwidth Dollar + | '\uffe0' // Fullwidth Cent + | '\uffe1' // Fullwidth Pound + | '\uffe5' // Fullwidth Yen + | '\uffe6' // Fullwidth Won + ; + +// use standard alphabet + extended Latin only; add more later if desired. +fragment LETTER + : '\u0041'..'\u005a' // A-Z + | '\u0061'..'\u007a' // a-z + | '\u00c0'..'\u00d6' // Latin-1 Supplement + | '\u00d8'..'\u00f6' + | '\u00f8'..'\u00ff' + | '\u0100'..'\u017f' // Latin Extended-A + | '\u0180'..'\u024f' // Latin Extended-B +// | '\u0250'..'\u02ad' // IPA extensions +// | '\u0386' // Greek +// | '\u0388'..'\u038a' +// | '\u038c' +// | '\u038e'..'\u03a1' +// | '\u03a3'..'\u03ce' +// | '\u03d0'..'\u03d7' +// | '\u03da'..'\u03f3' +// | '\u0400'..'\u0481' // Cyrillic +// | '\u048c'..'\u04c4' +// | '\u04c7'..'\u04c8' +// | '\u04cb'..'\u04cc' +// | '\u04d0'..'\u04f5' +// | '\u04f8'..'\u04f9' +// | '\u05d0'..'\u05ea' // Hebrew +// | '\u0621'..'\u063a' // Arabic +// | '\u0641'..'\u064a' +// | '\u0660'..'\u0669' +// | '\u0671'..'\u06d3' +// | '\u06d5' +// | '\u06f0'..'\u06f9' +// | '\u06fa'..'\u06fc' +// | '\u0e01'..'\u0e5b' // Thai +// | '\u1100'..'\u1159' // Hangul/Korean +// | '\u1161'..'\u11a2' +// | '\u11a8'..'\u11f9' +// | '\u1e00'..'\u1e9b' // Latin Extended Additional +// | '\u1ea0'..'\u1ef9' +// | '\u1f00'..'\u1f15' // Greek Extended +// | '\u1f18'..'\u1f1d' +// | '\u1f20'..'\u1f45' +// | '\u1f48'..'\u1f4d' +// | '\u1f50'..'\u1f57' +// | '\u1f59' +// | '\u1f5b' +// | '\u1f5d' +// | '\u1f5f'..'\u1f7d' +// | '\u1f80'..'\u1fb4' +// | '\u1fb6'..'\u1fbc' +// | '\u1fc2'..'\u1fc4' +// | '\u1fc6'..'\u1fcc' +// | '\u1fd0'..'\u1fd3' +// | '\u1fd6'..'\u1fdb' +// | '\u1fe0'..'\u1fec' +// | '\u1ff2'..'\u1ff4' +// | '\u1ff6'..'\u1ffc' +// | '\u210a'..'\u2113' // Letter-like symbols +// | '\u2118'..'\u211d' +// | '\u212a'..'\u212d' +// | '\u212f'..'\u2131' +// | '\u2133'..'\u2138' +// | '\u2160'..'\u2183' // Roman Numeral +// | '\u2460'..'\u24ea' // Enclosed Alphanumerics +// | '\u2e80'..'\u2ef3' // CJK Radicals Supplement +// | '\u2f00'..'\u2fd5' // Kangxi Radicals +// | '\u3021'..'\u3029' // CJK +// | '\u3031'..'\u3035' +// | '\u3038'..'\u303a' +// | '\u3041'..'\u3094' // Hiragana +// | '\u309d'..'\u309e' +// | '\u30a1'..'\u30fa' // Katakana +// | '\u30fc'..'\u30fe' +// | '\u3105'..'\u312c' // Bopomofo +// | '\u3131'..'\u318e' // Hangul Compatability Jamo +// | '\u31a0'..'\u31b7' // Bopomofo Extended +// | '\ua000'..'\ua48c' // Yi Syllables +// | '\uac00' // Hangul Syllables +// | '\ud7a3' +// | '\uf900'..'\ufa2d' // CJK Compatibility Ideographs +// | '\ufb00'..'\ufb06' // Alphabetic Presentation Forms +// | '\ufb13'..'\ufb17' +// | '\ufb1d' +// | '\ufb1f'..'\ufb28' +// | '\ufb2a'..'\ufb36' +// | '\ufb38'..'\ufb3c' +// | '\ufb3e' +// | '\ufb40'..'\ufb41' +// | '\ufb43'..'\ufb44' +// | '\ufb46'..'\ufb4f' +// | '\ufb50'..'\ufbb1' // Arabic Presentation Forms-A +// | '\ufbd3'..'\ufd3d' +// | '\ufd50'..'\ufd8f' +// | '\ufd92'..'\ufdc7' +// | '\ufdf0'..'\ufdfb' +// | '\ufe70'..'\ufe72' // Arabic Presentation Forms-B +// | '\ufe74' +// | '\ufe76'..'\ufefc' +// | '\uff21'..'\uff3a' // Halfwidth and Fullwidth Forms +// | '\uff41'..'\uff5a' +// | '\uff66'..'\uffbe' +// | '\uffc2'..'\uffc7' +// | '\uffca'..'\uffcf' +// | '\uffd2'..'\uffd7' +// | '\uffda'..'\uffdc' +// | '\u10000'..'\u1F9FF' //not supporting 4-byte chars +// | '\u20000'..'\u2FA1F' + ; + +UNMATCHED_CHARACTER: . ; diff --git a/contrib/babelfishpg_tsql/antlr/TSqlParser.g4 b/contrib/babelfishpg_tsql/antlr/TSqlParser.g4 new file mode 100644 index 00000000000..61fb8789ff8 --- /dev/null +++ b/contrib/babelfishpg_tsql/antlr/TSqlParser.g4 @@ -0,0 +1,5031 @@ +// tests todo: +// roll back changes for: constant, constant_expression, primitive_expression + +//testG: +// removed primitive_expression +// removed function_call from constant_expression + + +/* +T-SQL (Transact-SQL, MSSQL) grammar. +The MIT License (MIT). +Copyright (c) 2017, Mark Adams (madams51703@gmail.com) +Copyright (c) 2015-2017, Ivan Kochurkin (kvanttt@gmail.com), Positive Technologies. +Copyright (c) 2016, Scott Ure (scott@redstormsoftware.com). +Copyright (c) 2016, Rui Zhang (ruizhang.ccs@gmail.com). +Copyright (c) 2016, Marcus Henriksson (kuseman80@gmail.com). +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +parser grammar TSqlParser; + +options { + tokenVocab = TSqlLexer; +} + +tsql_file + : batch_level_statement SEMI? EOF + // some sql_cluases may start with non-reserved keyword (i.e. THROW) + // so we should try sql_clauses first and then execute_body_batch if sql_clauses fails. + | sql_clauses* EOF + | execute_body_batch sql_clauses* EOF + ; + +batch_level_statement + : create_or_alter_function + | create_or_alter_procedure + | create_or_alter_trigger + | create_or_alter_view + | SEMI + ; + +sql_clauses + : ( dml_statement + | cfl_statement + | another_statement + | ddl_statement + | dbcc_statement + | backup_statement + | restore_statement + | checkpoint_statement + | readtext_statement + | writetext_statement + | updatetext_statement ) SEMI? + | SEMI + ; + +// Data Manipulation Language: https://msdn.microsoft.com/en-us/library/ff848766(v=sql.120).aspx +dml_statement + : merge_statement + | delete_statement + | insert_statement + | bulk_insert_statement + | select_statement_standalone + | update_statement + ; + +// Data Definition Language: https://msdn.microsoft.com/en-us/library/ff848799.aspx) +ddl_statement + : add_signature_statement + | alter_application_role + | alter_assembly + | alter_asymmetric_key + | alter_authorization + | alter_availability_group + | alter_certificate + | alter_column_encryption_key + | alter_credential + | alter_cryptographic_provider + | alter_database + | alter_database_scoped_configuration + | alter_db_role + | alter_external_data_source + | alter_external_library + | alter_external_resource_pool + | alter_fulltext_catalog + | alter_fulltext_index + | alter_fulltext_stoplist + | alter_index + | alter_login + | alter_master_key + | alter_message_type + | alter_partition_function + | alter_partition_scheme + | alter_remote_service_binding + | alter_resource_governor + | alter_schema + | alter_sequence + | alter_server_audit + | alter_server_audit_specification + | alter_server_configuration + | alter_server_role + | alter_server_role_pdw + | alter_service + | alter_service_master_key + | alter_symmetric_key + | alter_table + | alter_user + | alter_workload_group + | alter_xml_schema_collection + | create_aggregate + | create_application_role + | create_assembly + | create_asymmetric_key + | create_column_encryption_key + | create_column_master_key + | create_credential + | create_cryptographic_provider + | create_database + | create_default + | create_db_role + | create_diagnostic_session + | create_event_notification + | create_external_data_source + | create_external_file_format + | create_external_library + | create_external_resource_pool + | create_external_table + | create_fulltext_catalog + | create_fulltext_index + | create_fulltext_stoplist + | create_index + | create_login + | create_master_key + | create_or_alter_broker_priority + | create_or_alter_database_audit_specification + | create_or_alter_endpoint + | create_or_alter_event_session + | create_partition_function + | create_partition_scheme + | create_remote_service_binding + | create_resource_pool + | create_route + | create_rule + | create_schema + | create_search_property_list + | create_security_policy + | create_sequence + | create_server_audit + | create_server_audit_specification + | create_server_role + | create_service + | create_spatial_index + | create_statistics + | create_symmetric_key + | create_synonym + | create_table + | create_type + | create_user + | create_user_azure_sql_dw + | create_workload_group + | create_xml_index + | create_selective_xml_index + | create_xml_schema_collection + | drop_aggregate + | drop_application_role + | drop_assembly + | drop_asymmetric_key + | drop_availability_group + | drop_broker_priority + | drop_certificate + | drop_column_encryption_key + | drop_column_master_key + | drop_contract + | drop_credential + | drop_cryptograhic_provider + | drop_database + | drop_database_audit_specification + | drop_database_encryption_key + | drop_database_scoped_credential + | drop_db_role + | drop_default + | drop_diagnostic_session + | drop_endpoint + | drop_event_notifications + | drop_event_session + | drop_external_data_source + | drop_external_file_format + | drop_external_library + | drop_external_resource_pool + | drop_external_table + | drop_fulltext_catalog + | drop_fulltext_index + | drop_fulltext_stoplist + | drop_function + | drop_index + | drop_login + | drop_master_key + | drop_message_type + | drop_partition_function + | drop_partition_scheme + | drop_procedure + | drop_queue + | drop_remote_service_binding + | drop_resource_pool + | drop_route + | drop_rule + | drop_schema + | drop_search_property_list + | drop_security_policy + | drop_sequence + | drop_server_audit + | drop_server_audit_specification + | drop_server_role + | drop_service + | drop_signature_statement + | drop_statistics + | drop_symmetric_key + | drop_synonym + | drop_table + | drop_trigger + | drop_type + | drop_user + | drop_view + | drop_workload_group + | drop_xml_schema_collection + | disable_trigger + | enable_trigger + | lock_table + | truncate_table + | update_statistics + ; + +backup_statement + : backup_database + | backup_log + | backup_certificate + | backup_master_key + | backup_service_master_key + ; + +restore_statement + : restore_database + ; + +// Control-of-Flow Language: https://docs.microsoft.com/en-us/sql/t-sql/language-elements/control-of-flow +cfl_statement + : block_statement + | break_statement + | continue_statement + | goto_statement + | if_statement + | return_statement + | throw_statement + | try_catch_statement + | waitfor_statement + | while_statement + | print_statement + | raiseerror_statement + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/language-elements/begin-end-transact-sql +block_statement + : BEGIN SEMI? sql_clauses* END SEMI? + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/language-elements/break-transact-sql +break_statement + : BREAK SEMI? + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/language-elements/continue-transact-sql +continue_statement + : CONTINUE SEMI? + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/language-elements/goto-transact-sql +goto_statement + : GOTO id SEMI? + | id COLON SEMI? + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/language-elements/return-transact-sql +return_statement + : RETURN expression? SEMI? + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/language-elements/if-else-transact-sql +if_statement + : IF search_condition sql_clauses (ELSE sql_clauses)? SEMI? + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/language-elements/throw-transact-sql +throw_statement + : THROW (throw_error_number COMMA throw_message COMMA throw_state)? SEMI? + ; + +throw_error_number + : DECIMAL | LOCAL_ID + ; + +throw_message + : STRING | LOCAL_ID + ; + +throw_state + : DECIMAL | LOCAL_ID + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/language-elements/try-catch-transact-sql +try_catch_statement + : try_block catch_block SEMI? + ; + +try_block + : BEGIN TRY SEMI? try_clauses=sql_clauses+ END TRY + ; + +catch_block + : BEGIN CATCH SEMI? catch_clauses=sql_clauses* END CATCH + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/language-elements/waitfor-transact-sql +waitfor_statement + : WAITFOR (DELAY | TIME) expression SEMI? + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/language-elements/while-transact-sql +while_statement + : WHILE search_condition (sql_clauses | BREAK SEMI? | CONTINUE SEMI?) + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/language-elements/print-transact-sql +print_statement + : PRINT (expression | DOUBLE_QUOTE_ID) (COMMA LOCAL_ID)* SEMI? + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/language-elements/raiserror-transact-sql +raiseerror_statement + : RAISERROR LR_BRACKET msg=(DECIMAL | STRING | LOCAL_ID) COMMA severity=constant_LOCAL_ID COMMA + state=constant_LOCAL_ID (COMMA argument+=constant_LOCAL_ID)* RR_BRACKET (WITH raiseerror_option (COMMA raiseerror_option)* )? SEMI? + ; + +raiseerror_option + : (LOG | SETERROR | NOWAIT) + ; + + +empty_statement + : SEMI + ; + +another_statement + : declare_statement + | declare_xmlnamespaces_statement + | execute_statement + | cursor_statement + | conversation_statement + | create_contract + | create_queue + | alter_queue + | kill_statement + | message_statement + | security_statement + | set_statement + | transaction_statement + | use_statement + | setuser_statement + | reconfigure_statement + | shutdown_statement + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/alter-application-role-transact-sql +alter_application_role + : ALTER APPLICATION ROLE appliction_role=id WITH (COMMA? NAME EQUAL new_application_role_name=id)? (COMMA? PASSWORD EQUAL application_role_password=STRING)? (COMMA? DEFAULT_SCHEMA EQUAL app_role_default_schema=id)? + ; + +create_application_role + : CREATE APPLICATION ROLE appliction_role=id WITH (COMMA? PASSWORD EQUAL application_role_password=STRING)? (COMMA? DEFAULT_SCHEMA EQUAL app_role_default_schema=id)? + ; + +create_aggregate + : CREATE AGGREGATE func_proc_name_schema LR_BRACKET procedure_param (COMMA procedure_param)* RR_BRACKET + RETURNS data_type external_name SEMI? + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-aggregate-transact-sql +drop_aggregate + : DROP AGGREGATE if_exists? ( schema_name=id DOT )? aggregate_name=id + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-application-role-transact-sql +drop_application_role + : DROP APPLICATION ROLE rolename=id + ; + +alter_assembly + : ALTER ASSEMBLY assembly_name=id alter_assembly_clause + ; + +alter_assembly_clause + : (FROM expression)? (WITH assembly_option (COMMA assembly_option)*)? alter_assembly_drop_clause? alter_assembly_add_clause? + ; + +alter_assembly_drop_clause + : DROP FILE ((STRING|id) (COMMA (STRING|id))* | ALL) + ; + +alter_assembly_add_clause + : ADD FILE FROM alter_assembly_client_file_clause (COMMA alter_assembly_client_file_clause)* + ; + +alter_assembly_client_file_clause + : (expression|id) (AS (id|STRING))? + ; + +assembly_option + : PERMISSION_SET EQUAL (SAFE|EXTERNAL_ACCESS|UNSAFE) + | VISIBILITY EQUAL (ON | OFF) + | UNCHECKED DATA + ; + +network_file_share + : DOUBLE_BACK_SLASH computer_name=id file_path + ; + +file_path + : BACKSLASH file_path + | id + ; + +local_file + : local_drive file_path + ; + +local_drive + : DISK_DRIVE + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/create-assembly-transact-sql +create_assembly + : CREATE ASSEMBLY assembly_name=id (AUTHORIZATION owner_name=id)? + FROM (COMMA? (STRING|BINARY) )+ + (WITH PERMISSION_SET EQUAL (SAFE|EXTERNAL_ACCESS|UNSAFE) )? + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-assembly-transact-sql +drop_assembly + : DROP ASSEMBLY if_exists? (COMMA? assembly_name=id)+ + ( WITH NO DEPENDENTS )? + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/alter-asymmetric-key-transact-sql +alter_asymmetric_key + : ALTER ASYMMETRIC KEY Asym_Key_Name=id (asymmetric_key_option | REMOVE PRIVATE KEY ) + ; + +asymmetric_key_option + : WITH PRIVATE KEY LR_BRACKET asymmetric_key_password_change_option ( COMMA asymmetric_key_password_change_option)? RR_BRACKET + ; + +asymmetric_key_password_change_option + : (ENCRYPTION|DECRYPTION) BY PASSWORD EQUAL STRING + ; + +//https://docs.microsoft.com/en-us/sql/t-sql/statements/create-asymmetric-key-transact-sql +create_asymmetric_key + : CREATE ASYMMETRIC KEY Asym_Key_Nam=id + (AUTHORIZATION database_principal_name=id)? + ( FROM (FILE EQUAL STRING |EXECUTABLE_FILE EQUAL STRING|ASSEMBLY Assembly_Name=id | PROVIDER Provider_Name=id) )? + (WITH (ALGORITHM EQUAL ( RSA_4096 | RSA_3072 | RSA_2048 | RSA_1024 | RSA_512) |PROVIDER_KEY_NAME EQUAL provider_key_name=STRING | CREATION_DISPOSITION EQUAL (CREATE_NEW|OPEN_EXISTING) ) )? + (ENCRYPTION BY PASSWORD EQUAL asymmetric_key_password=STRING )? + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-asymmetric-key-transact-sql +drop_asymmetric_key + : DROP ASYMMETRIC KEY key_name=id ( REMOVE PROVIDER KEY )? + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/alter-authorization-transact-sql +alter_authorization + : ALTER AUTHORIZATION ON (object_type colon_colon)? entity=entity_name TO authorization_grantee + ; + +authorization_grantee + : principal_name=id + | SCHEMA OWNER + ; + +colon_colon + : COLON COLON + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-availability-group-transact-sql +drop_availability_group + : DROP AVAILABILITY GROUP group_name=id + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/alter-availability-group-transact-sql +alter_availability_group + : ALTER AVAILABILITY GROUP group_name=id alter_availability_group_options + ; + +alter_availability_group_options + : SET LR_BRACKET ( ( AUTOMATED_BACKUP_PREFERENCE EQUAL ( PRIMARY | SECONDARY_ONLY| SECONDARY | NONE ) | FAILURE_CONDITION_LEVEL EQUAL DECIMAL | HEALTH_CHECK_TIMEOUT EQUAL milliseconds=DECIMAL | DB_FAILOVER EQUAL ( ON | OFF ) | REQUIRED_SYNCHRONIZED_SECONDARIES_TO_COMMIT EQUAL DECIMAL ) RR_BRACKET ) + | ADD DATABASE database_name=id + | REMOVE DATABASE database_name=id + | ADD REPLICA ON server_instance=STRING (WITH LR_BRACKET ( (ENDPOINT_URL EQUAL STRING)? (COMMA? AVAILABILITY_MODE EQUAL (SYNCHRONOUS_COMMIT| ASYNCHRONOUS_COMMIT))? (COMMA? FAILOVER_MODE EQUAL (AUTOMATIC|MANUAL) )? (COMMA? SEEDING_MODE EQUAL (AUTOMATIC|MANUAL) )? (COMMA? BACKUP_PRIORITY EQUAL DECIMAL)? ( COMMA? PRIMARY_ROLE LR_BRACKET ALLOW_CONNECTIONS EQUAL ( READ_WRITE | ALL ) RR_BRACKET)? ( COMMA? SECONDARY_ROLE LR_BRACKET ALLOW_CONNECTIONS EQUAL ( READ_ONLY ) RR_BRACKET )? ) +) RR_BRACKET + |SECONDARY_ROLE LR_BRACKET (ALLOW_CONNECTIONS EQUAL (NO|READ_ONLY|ALL) | READ_ONLY_ROUTING_LIST EQUAL ( LR_BRACKET ( ( STRING) ) RR_BRACKET ) ) + |PRIMARY_ROLE LR_BRACKET (ALLOW_CONNECTIONS EQUAL (NO|READ_ONLY|ALL) | READ_ONLY_ROUTING_LIST EQUAL ( LR_BRACKET ( (COMMA? STRING)*|NONE ) RR_BRACKET ) + | SESSION_TIMEOUT EQUAL session_timeout=DECIMAL +) + | MODIFY REPLICA ON server_instance=STRING (WITH LR_BRACKET (ENDPOINT_URL EQUAL STRING| AVAILABILITY_MODE EQUAL (SYNCHRONOUS_COMMIT| ASYNCHRONOUS_COMMIT) | FAILOVER_MODE EQUAL (AUTOMATIC|MANUAL) | SEEDING_MODE EQUAL (AUTOMATIC|MANUAL) | BACKUP_PRIORITY EQUAL DECIMAL ) + |SECONDARY_ROLE LR_BRACKET (ALLOW_CONNECTIONS EQUAL (NO|READ_ONLY|ALL) | READ_ONLY_ROUTING_LIST EQUAL ( LR_BRACKET ( ( STRING) ) RR_BRACKET ) ) + |PRIMARY_ROLE LR_BRACKET (ALLOW_CONNECTIONS EQUAL (NO|READ_ONLY|ALL) | READ_ONLY_ROUTING_LIST EQUAL ( LR_BRACKET ( (COMMA? STRING)*|NONE ) RR_BRACKET ) + | SESSION_TIMEOUT EQUAL session_timeout=DECIMAL +) ) RR_BRACKET + | REMOVE REPLICA ON STRING + | JOIN + | JOIN AVAILABILITY GROUP ON (COMMA? ag_name=STRING WITH LR_BRACKET ( LISTENER_URL EQUAL STRING COMMA AVAILABILITY_MODE EQUAL (SYNCHRONOUS_COMMIT|ASYNCHRONOUS_COMMIT) COMMA FAILOVER_MODE EQUAL MANUAL COMMA SEEDING_MODE EQUAL (AUTOMATIC|MANUAL) RR_BRACKET ) )+ + | MODIFY AVAILABILITY GROUP ON (COMMA? ag_name_modified=STRING WITH LR_BRACKET (LISTENER_URL EQUAL STRING (COMMA? AVAILABILITY_MODE EQUAL (SYNCHRONOUS_COMMIT|ASYNCHRONOUS_COMMIT) )? (COMMA? FAILOVER_MODE EQUAL MANUAL )? (COMMA? SEEDING_MODE EQUAL (AUTOMATIC|MANUAL))? RR_BRACKET ) )+ + |GRANT CREATE ANY DATABASE + | DENY CREATE ANY DATABASE + | FAILOVER + | FORCE_FAILOVER_ALLOW_DATA_LOSS + | ADD LISTENER listener_name=STRING LR_BRACKET ( WITH DHCP (ON LR_BRACKET ip_v4_failover ip_v4_failover RR_BRACKET ) | WITH IP LR_BRACKET ( (COMMA? LR_BRACKET ( ip_v4_failover COMMA ip_v4_failover | ip_v6_failover ) RR_BRACKET)+ RR_BRACKET (COMMA PORT EQUAL DECIMAL)? ) ) RR_BRACKET + | MODIFY LISTENER (ADD IP LR_BRACKET (ip_v4_failover ip_v4_failover | ip_v6_failover) RR_BRACKET | PORT EQUAL DECIMAL ) + |RESTART LISTENER STRING + |REMOVE LISTENER STRING + |OFFLINE + | WITH LR_BRACKET DTC_SUPPORT EQUAL PER_DB RR_BRACKET + ; + +ip_v4_failover + : STRING + ; + +ip_v6_failover + : STRING + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/alter-broker-priority-transact-sql +// https://docs.microsoft.com/en-us/sql/t-sql/statements/create-broker-priority-transact-sql +create_or_alter_broker_priority + : (CREATE | ALTER) BROKER PRIORITY ConversationPriorityName=id FOR CONVERSATION + SET LR_BRACKET + ( CONTRACT_NAME EQUAL ( ( id) | ANY ) COMMA? )? + ( LOCAL_SERVICE_NAME EQUAL (DOUBLE_FORWARD_SLASH? id | ANY ) COMMA? )? + ( REMOTE_SERVICE_NAME EQUAL (RemoteServiceName=STRING | ANY ) COMMA? )? + ( PRIORITY_LEVEL EQUAL ( PriorityValue=DECIMAL | DEFAULT ) )? + RR_BRACKET + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-broker-priority-transact-sql +drop_broker_priority + : DROP BROKER PRIORITY ConversationPriorityName=id + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/alter-certificate-transact-sql +alter_certificate + : ALTER CERTIFICATE certificate_name=id (REMOVE PRIVATE_KEY | WITH PRIVATE KEY LR_BRACKET ( FILE EQUAL STRING COMMA? | DECRYPTION BY PASSWORD EQUAL STRING COMMA?| ENCRYPTION BY PASSWORD EQUAL STRING COMMA?)+ RR_BRACKET | WITH ACTIVE FOR BEGIN_DIALOG EQUAL ( ON | OFF ) ) + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/alter-column-encryption-key-transact-sql +alter_column_encryption_key + : ALTER COLUMN ENCRYPTION KEY column_encryption_key=id (ADD | DROP) VALUE LR_BRACKET COLUMN_MASTER_KEY EQUAL column_master_key_name=id ( COMMA ALGORITHM EQUAL algorithm_name=STRING COMMA ENCRYPTED_VALUE EQUAL BINARY)? RR_BRACKET + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/create-column-encryption-key-transact-sql +create_column_encryption_key + : CREATE COLUMN ENCRYPTION KEY column_encryption_key=id + WITH VALUES + (LR_BRACKET COMMA? COLUMN_MASTER_KEY EQUAL column_master_key_name=id COMMA + ALGORITHM EQUAL algorithm_name=STRING COMMA + ENCRYPTED_VALUE EQUAL encrypted_value=BINARY RR_BRACKET COMMA?)+ + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-certificate-transact-sql +drop_certificate + : DROP CERTIFICATE certificate_name=id + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-column-encryption-key-transact-sql +drop_column_encryption_key + : DROP COLUMN ENCRYPTION KEY key_name=id + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-column-master-key-transact-sql +drop_column_master_key + : DROP COLUMN MASTER KEY key_name=id + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-contract-transact-sql +drop_contract + : DROP CONTRACT dropped_contract_name=id + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-credential-transact-sql +drop_credential + : DROP CREDENTIAL credential_name=id + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-cryptographic-provider-transact-sql +drop_cryptograhic_provider + : DROP CRYPTOGRAPHIC PROVIDER provider_name=id + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-database-transact-sql +drop_database + : DROP DATABASE if_exists? id (COMMA id)* + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-database-audit-specification-transact-sql +drop_database_audit_specification + : DROP DATABASE AUDIT SPECIFICATION audit_specification_name=id + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-database-encryption-key-transact-sql?view=sql-server-ver15 +drop_database_encryption_key + : DROP DATABASE ENCRYPTION KEY + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-database-scoped-credential-transact-sql +drop_database_scoped_credential + : DROP DATABASE SCOPED CREDENTIAL credential_name=id + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-default-transact-sql +drop_default + : DROP DEFAULT if_exists? simple_name (COMMA simple_name)* + ; + +drop_diagnostic_session + : DROP DIAGNOSTICS SESSION session_name=ID SEMI + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-endpoint-transact-sql +drop_endpoint + : DROP ENDPOINT endPointName=id + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-external-data-source-transact-sql +drop_external_data_source + : DROP EXTERNAL DATA SOURCE external_data_source_name=id + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-external-file-format-transact-sql +drop_external_file_format + : DROP EXTERNAL FILE FORMAT external_file_format_name=id + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-external-library-transact-sql +drop_external_library + : DROP EXTERNAL LIBRARY library_name=id +( AUTHORIZATION owner_name=id )? + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-external-resource-pool-transact-sql +drop_external_resource_pool + : DROP EXTERNAL RESOURCE POOL pool_name=id + ; + +create_external_table + : CREATE EXTERNAL TABLE table_name LR_BRACKET column_definition (COMMA column_definition)* COMMA? RR_BRACKET + WITH LR_BRACKET external_table_option (COMMA external_table_option)* RR_BRACKET + SEMI? + ; + +external_table_option + : id EQUAL expression + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-external-table-transact-sql +drop_external_table + : DROP EXTERNAL TABLE table_name SEMI? + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-event-notification-transact-sql +drop_event_notifications + : DROP EVENT NOTIFICATION (COMMA? notification_name=id)+ + ON (SERVER|DATABASE|QUEUE queue_name=id) + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-event-session-transact-sql +drop_event_session + : DROP EVENT SESSION event_session_name=id + ON SERVER + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-fulltext-catalog-transact-sql +drop_fulltext_catalog + : DROP FULLTEXT CATALOG catalog_name=id + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-fulltext-index-transact-sql +drop_fulltext_index + : DROP FULLTEXT INDEX ON table_name + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-fulltext-stoplist-transact-sql +drop_fulltext_stoplist + : DROP FULLTEXT STOPLIST stoplist_name=id + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-login-transact-sql +drop_login + : DROP LOGIN login_name=id + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-master-key-transact-sql +drop_master_key + : DROP MASTER KEY + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-message-type-transact-sql +drop_message_type + : DROP MESSAGE TYPE message_type_name=id + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-partition-function-transact-sql +drop_partition_function + : DROP PARTITION FUNCTION partition_function_name=id + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-partition-scheme-transact-sql +drop_partition_scheme + : DROP PARTITION SCHEME partition_scheme_name=id + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-queue-transact-sql +drop_queue + : DROP QUEUE (database_name=id DOT)? (schema_name=id DOT)? queue_name=id + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-remote-service-binding-transact-sql +drop_remote_service_binding + : DROP REMOTE SERVICE BINDING binding_name=id + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-resource-pool-transact-sql +drop_resource_pool + : DROP RESOURCE POOL pool_name=id + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-role-transact-sql +drop_db_role + : DROP ROLE if_exists? role_name=id + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-route-transact-sql +drop_route + : DROP ROUTE route_name=id + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-rule-transact-sql +drop_rule + : DROP RULE if_exists? simple_name (COMMA simple_name)* + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-schema-transact-sql +drop_schema + : DROP SCHEMA if_exists? schema_name=id + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-search-property-list-transact-sql +drop_search_property_list + : DROP SEARCH PROPERTY LIST property_list_name=id + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-security-policy-transact-sql +drop_security_policy + : DROP SECURITY POLICY if_exists? (schema_name=id DOT )? security_policy_name=id + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-sequence-transact-sql +drop_sequence + : DROP SEQUENCE if_exists? full_object_name (COMMA full_object_name)* + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-server-audit-transact-sql +drop_server_audit + : DROP SERVER AUDIT audit_name=id + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-server-audit-specification-transact-sql +drop_server_audit_specification + : DROP SERVER AUDIT SPECIFICATION audit_specification_name=id + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-server-role-transact-sql +drop_server_role + : DROP SERVER ROLE role_name=id + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-service-transact-sql +drop_service + : DROP SERVICE dropped_service_name=id + ; + +add_signature_statement + : ADD COUNTER? SIGNATURE TO (object_type colon_colon)? full_object_name BY signature_item (COMMA signature_item)* SEMI? + ; + +signature_item + : (CERTIFICATE|ASYMMETRIC KEY) name=id (WITH PASSWORD EQUAL STRING | WITH SIGNATURE EQUAL BINARY)? + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-signature-transact-sql +drop_signature_statement + : DROP COUNTER? SIGNATURE FROM (schema_name=id DOT)? module_name=id + BY (COMMA? CERTIFICATE cert_name=id + | COMMA? ASYMMETRIC KEY Asym_key_name=id + )+ + SEMI? + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-symmetric-key-transact-sql +drop_symmetric_key + : DROP SYMMETRIC KEY symmetric_key_name=id (REMOVE PROVIDER KEY)? + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-synonym-transact-sql +drop_synonym + : DROP SYNONYM if_exists? simple_name + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-user-transact-sql +drop_user + : DROP USER if_exists? user_name=id + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-workload-group-transact-sql +drop_workload_group + : DROP WORKLOAD GROUP group_name=id + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-xml-schema-collection-transact-sql +drop_xml_schema_collection + : DROP XML SCHEMA COLLECTION simple_name + ; + +// 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) + ; + + +// 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) + ; + +lock_table + : LOCK TABLE table_name IN (SHARE | EXCLUSIVE) MODE (WAIT seconds=DECIMAL | NOWAIT)? SEMI? + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/truncate-table-transact-sql +truncate_table + : TRUNCATE TABLE table_name + ( WITH LR_BRACKET + PARTITIONS LR_BRACKET + (COMMA? ((DECIMAL|LOCAL_ID)|(DECIMAL|LOCAL_ID) TO (DECIMAL|LOCAL_ID)) )+ + RR_BRACKET + RR_BRACKET + )? + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/create-column-master-key-transact-sql +create_column_master_key + : CREATE COLUMN MASTER KEY key_name=id + WITH LR_BRACKET + KEY_STORE_PROVIDER_NAME EQUAL key_store_provider_name=STRING COMMA + KEY_PATH EQUAL key_path=STRING + RR_BRACKET + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/alter-credential-transact-sql +alter_credential + : ALTER CREDENTIAL credential_name=id + WITH IDENTITY EQUAL identity_name=STRING + ( COMMA SECRET EQUAL secret=STRING )? + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/create-credential-transact-sql +create_credential + : CREATE CREDENTIAL credential_name=id + WITH IDENTITY EQUAL identity_name=STRING + ( COMMA SECRET EQUAL secret=STRING )? + ( FOR CRYPTOGRAPHIC PROVIDER cryptographic_provider_name=id )? + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/alter-cryptographic-provider-transact-sql +alter_cryptographic_provider + : ALTER CRYPTOGRAPHIC PROVIDER provider_name=id (FROM FILE EQUAL crypto_provider_ddl_file=STRING)? (ENABLE | DISABLE)? + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/create-cryptographic-provider-transact-sql +create_cryptographic_provider + : CREATE CRYPTOGRAPHIC PROVIDER provider_name=id + FROM FILE EQUAL path_of_DLL=STRING + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/create-event-notification-transact-sql +create_event_notification + : CREATE EVENT NOTIFICATION event_notification_name=id + ON (SERVER|DATABASE|QUEUE queue_name=id) + (WITH FAN_IN)? + FOR (COMMA? event_type_or_group=id)+ + TO SERVICE broker_service=STRING COMMA + broker_service_specifier_or_current_database=STRING + ; + + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/alter-event-session-transact-sql +// https://docs.microsoft.com/en-us/sql/t-sql/statements/create-event-session-transact-sql +create_or_alter_event_session + : (CREATE | ALTER) EVENT SESSION event_session_name=id ON SERVER + (COMMA? ADD EVENT ( (event_module_guid=id DOT)? event_package_name=id DOT event_name=id) + (LR_BRACKET + (SET ( COMMA? event_customizable_attributue=id EQUAL (DECIMAL|STRING) )* )? + ( ACTION LR_BRACKET (COMMA? (event_module_guid=id DOT)? event_package_name=id DOT action_name=id)+ RR_BRACKET)+ + (WHERE event_session_predicate_expression)? + RR_BRACKET )* + )* + (COMMA? DROP EVENT (event_module_guid=id DOT)? event_package_name=id DOT event_name=id )* + + ( (ADD TARGET (event_module_guid=id DOT)? event_package_name=id DOT target_name=id ) ( LR_BRACKET SET (COMMA? target_parameter_name=id EQUAL (LR_BRACKET? DECIMAL RR_BRACKET? |STRING) )+ RR_BRACKET )* )* + (DROP TARGET (event_module_guid=id DOT)? event_package_name=id DOT target_name=id )* + + + (WITH + LR_BRACKET + (COMMA? MAX_MEMORY EQUAL max_memory=DECIMAL (KB|MB) )? + (COMMA? EVENT_RETENTION_MODE EQUAL (ALLOW_SINGLE_EVENT_LOSS | ALLOW_MULTIPLE_EVENT_LOSS | NO_EVENT_LOSS ) )? + (COMMA? MAX_DISPATCH_LATENCY EQUAL (max_dispatch_latency_seconds=DECIMAL SECONDS | INFINITE) )? + (COMMA? MAX_EVENT_SIZE EQUAL max_event_size=DECIMAL (KB|MB) )? + (COMMA? MEMORY_PARTITION_MODE EQUAL (NONE | PER_NODE | PER_CPU) )? + (COMMA? TRACK_CAUSALITY EQUAL (ON|OFF) )? + (COMMA? STARTUP_STATE EQUAL (ON|OFF) )? + RR_BRACKET + )? + (STATE EQUAL (START|STOP) )? + + ; + +event_session_predicate_expression + : ( COMMA? (AND|OR)? NOT? ( event_session_predicate_factor | LR_BRACKET event_session_predicate_expression RR_BRACKET) )+ + ; + +event_session_predicate_factor + : event_session_predicate_leaf + | LR_BRACKET event_session_predicate_expression RR_BRACKET + ; + +event_session_predicate_leaf + : (event_field_name=id | (event_field_name=id |( (event_module_guid=id DOT)? event_package_name=id DOT predicate_source_name=id ) ) (EQUAL |(LESS GREATER) | (EXCLAMATION EQUAL) | GREATER | (GREATER EQUAL)| LESS | LESS EQUAL) (DECIMAL | STRING) ) + | (event_module_guid=id DOT)? event_package_name=id DOT predicate_compare_name=id LR_BRACKET (event_field_name=id |( (event_module_guid=id DOT)? event_package_name=id DOT predicate_source_name=id ) COMMA (DECIMAL | STRING) ) RR_BRACKET + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/alter-external-data-source-transact-sql +alter_external_data_source + : ALTER EXTERNAL DATA SOURCE data_source_name=id SET + ( external_data_source_attribute | CREDENTIAL EQUAL credential_name=id )+ + | ALTER EXTERNAL DATA SOURCE data_source_name=id WITH LR_BRACKET TYPE EQUAL BLOB_STORAGE COMMA LOCATION EQUAL location=STRING (COMMA CREDENTIAL EQUAL credential_name=id )? RR_BRACKET + ; + +create_external_data_source + : CREATE EXTERNAL DATA SOURCE data_source_name=id WITH LR_BRACKET external_data_source_attribute* RR_BRACKET + ; + +external_data_source_attribute + : LOCATION EQUAL location=STRING COMMA? + | RESOURCE_MANAGER_LOCATION EQUAL resource_manager_location=STRING COMMA? + | TYPE EQUAL ID COMMA? + ; + +create_external_file_format + : CREATE EXTERNAL FILE FORMAT external_file_format_name=id WITH LR_BRACKET + FORMAT_TYPE EQUAL id + (COMMA FORMAT_OPTIONS LR_BRACKET external_file_format_option (COMMA external_file_format_option)* RR_BRACKET)? + (COMMA DATA_COMPRESSION EQUAL STRING)? + RR_BRACKET SEMI + ; + +external_file_format_option + : FIELD_TERMINATOR EQUAL STRING + | STRING_DELIMITER EQUAL STRING + | FIRST_ROW EQUAL DECIMAL + | DATE_FORMAT EQUAL STRING + | USE_TYPE_DEFAULT EQUAL (TRUE | FALSE) + | ENCODING EQUAL STRING + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/alter-external-library-transact-sql +alter_external_library + : ALTER EXTERNAL LIBRARY library_name=id (AUTHORIZATION owner_name=id)? + (SET|ADD) ( LR_BRACKET CONTENT EQUAL (client_library=STRING | BINARY | NONE) (COMMA PLATFORM EQUAL (WINDOWS|LINUX)? RR_BRACKET) WITH (COMMA? LANGUAGE EQUAL (R|PYTHON) | DATA_SOURCE EQUAL external_data_source_name=id )+ RR_BRACKET ) + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/create-external-library-transact-sql +create_external_library + : CREATE EXTERNAL LIBRARY library_name=id (AUTHORIZATION owner_name=id)? + FROM (COMMA? LR_BRACKET? (CONTENT EQUAL)? (client_library=STRING | BINARY | NONE) (COMMA PLATFORM EQUAL (WINDOWS|LINUX)? RR_BRACKET)? ) ( WITH (COMMA? LANGUAGE EQUAL (R|PYTHON) | DATA_SOURCE EQUAL external_data_source_name=id )+ RR_BRACKET )? + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/alter-external-resource-pool-transact-sql +alter_external_resource_pool + : ALTER EXTERNAL RESOURCE POOL (pool_name=id | DEFAULT_DOUBLE_QUOTE) WITH LR_BRACKET MAX_CPU_PERCENT EQUAL max_cpu_percent=DECIMAL ( COMMA? AFFINITY CPU EQUAL (AUTO|(COMMA? DECIMAL TO DECIMAL |COMMA DECIMAL )+ ) | NUMANODE EQUAL (COMMA? DECIMAL TO DECIMAL| COMMA? DECIMAL )+ ) (COMMA? MAX_MEMORY_PERCENT EQUAL max_memory_percent=DECIMAL)? (COMMA? MAX_PROCESSES EQUAL max_processes=DECIMAL)? RR_BRACKET + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/create-external-resource-pool-transact-sql +create_external_resource_pool + : CREATE EXTERNAL RESOURCE POOL pool_name=id WITH LR_BRACKET MAX_CPU_PERCENT EQUAL max_cpu_percent=DECIMAL ( COMMA? AFFINITY CPU EQUAL (AUTO|(COMMA? DECIMAL TO DECIMAL |COMMA DECIMAL )+ ) | NUMANODE EQUAL (COMMA? DECIMAL TO DECIMAL| COMMA? DECIMAL )+ ) (COMMA? MAX_MEMORY_PERCENT EQUAL max_memory_percent=DECIMAL)? (COMMA? MAX_PROCESSES EQUAL max_processes=DECIMAL)? RR_BRACKET + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/alter-fulltext-catalog-transact-sql +alter_fulltext_catalog + : ALTER FULLTEXT CATALOG catalog_name=id (REBUILD (WITH ACCENT_SENSITIVITY EQUAL (ON|OFF) )? | REORGANIZE | AS DEFAULT ) + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/create-fulltext-catalog-transact-sql +create_fulltext_catalog + : CREATE FULLTEXT CATALOG catalog_name=id + (ON FILEGROUP filegroup=id)? + (IN PATH rootpath=STRING)? + (WITH ACCENT_SENSITIVITY EQUAL (ON|OFF) )? + (AS DEFAULT)? + (AUTHORIZATION owner_name=id)? + ; + +create_fulltext_index + : CREATE FULLTEXT INDEX ON table_name (LR_BRACKET fulltext_index_column (COMMA fulltext_index_column)* RR_BRACKET)? KEY INDEX id (ON catalog_filegroup_option)? (WITH fulltext_with_option (COMMA fulltext_with_option)* )? + ; + +fulltext_index_column + : full_column_name (TYPE COLUMN full_column_name)? (LANGUAGE (STRING|DECIMAL|BINARY))? STATISTICAL_SEMANTICS? + ; + +catalog_filegroup_option + : catalog_name=id (COMMA FILEGROUP filegroup_name=id)? + | FILEGROUP filegroup_name=id (COMMA catalog_name=id)? + ; + +fulltext_with_option + : CHANGE_TRACKING EQUAL? ( MANUAL | AUTO | OFF (COMMA NO POPULATION)? ) + | STOPLIST EQUAL? ( OFF | SYSTEM | stoplist_name=id ) + | SEARCH PROPERTY LIST EQUAL? property_list_name=id + ; + +alter_fulltext_index + : ALTER FULLTEXT INDEX ON table_name alter_fulltext_index_option + ; + +alter_fulltext_index_option + : ( ENABLE | DISABLE ) + | CHANGE_TRACKING EQUAL? ( MANUAL | AUTO | OFF ) + | ADD LR_BRACKET fulltext_index_column (COMMA fulltext_index_column)* RR_BRACKET alter_fulltext_index_no_population? + | ALTER COLUMN full_column_name ( ADD | DROP ) STATISTICAL_SEMANTICS alter_fulltext_index_no_population? + | DROP LR_BRACKET full_column_name (COMMA full_column_name)* RR_BRACKET alter_fulltext_index_no_population? + | START ( FULL | INCREMENTAL | UPDATE ) POPULATION + | ( STOP | PAUSE | RESUME ) POPULATION + | SET STOPLIST EQUAL? ( OFF | SYSTEM | stoplist_name=id ) alter_fulltext_index_no_population? + | SEARCH PROPERTY LIST EQUAL? ( OFF | property_list_name=id ) alter_fulltext_index_no_population? + ; + +alter_fulltext_index_no_population + : WITH NO POPULATION + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/alter-fulltext-stoplist-transact-sql +alter_fulltext_stoplist + : ALTER FULLTEXT STOPLIST stoplist_name=id (ADD stopword=STRING LANGUAGE (STRING|DECIMAL|BINARY) | DROP ( stopword=STRING LANGUAGE (STRING|DECIMAL|BINARY) |ALL (STRING|DECIMAL|BINARY) | ALL ) ) + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/create-fulltext-stoplist-transact-sql +create_fulltext_stoplist + : CREATE FULLTEXT STOPLIST stoplist_name=id + (FROM ( (database_name=id DOT)? source_stoplist_name=id |SYSTEM STOPLIST ) )? + (AUTHORIZATION owner_name=id)? + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/alter-login-transact-sql +alter_login + : ALTER LOGIN login_name=id + ( (ENABLE|DISABLE) + | WITH alter_login_set_option (COMMA alter_login_set_option)* + | (ADD|DROP) CREDENTIAL credential_name=id ) + ; + +alter_login_set_option + : PASSWORD EQUAL ( password=STRING | password_hash=BINARY HASHED ) + ( (MUST_CHANGE|UNLOCK)+ + | OLD_PASSWORD EQUAL old_password=STRING )? + | DEFAULT_DATABASE EQUAL default_database=id + | DEFAULT_LANGUAGE EQUAL (id | STRING | DECIMAL) + | NAME EQUAL login_name=id + | CHECK_POLICY EQUAL (ON|OFF) + | CHECK_EXPIRATION EQUAL (ON|OFF) + | CREDENTIAL EQUAL credential_name=id + | NO CREDENTIAL + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/create-login-transact-sql +create_login + : CREATE LOGIN login_name=id + ( WITH PASSWORD EQUAL ( password=STRING | password_hash=BINARY HASHED ) MUST_CHANGE? (COMMA create_login_option_list)* + | FROM + ( WINDOWS (WITH create_login_windows_options (COMMA create_login_windows_options)* )? + | CERTIFICATE certname=id + | ASYMMETRIC KEY asym_key_name=id ) ) + ; + +create_login_option_list + : SID EQUAL sid=BINARY + | DEFAULT_DATABASE EQUAL default_database=id + | DEFAULT_LANGUAGE EQUAL (id | STRING | DECIMAL) + | CHECK_EXPIRATION EQUAL (ON|OFF) + | CHECK_POLICY EQUAL (ON|OFF) + | CREDENTIAL EQUAL credential_name=id + ; + +create_login_windows_options + : DEFAULT_DATABASE EQUAL default_database=id + | DEFAULT_LANGUAGE EQUAL (id | STRING | DECIMAL) + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/alter-master-key-transact-sql +alter_master_key + : ALTER MASTER KEY ( (FORCE)? REGENERATE WITH ENCRYPTION BY PASSWORD EQUAL password=STRING |(ADD|DROP) ENCRYPTION BY (SERVICE MASTER KEY | PASSWORD EQUAL encryption_password=STRING) ) + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/create-master-key-transact-sql +create_master_key + : CREATE MASTER KEY ENCRYPTION BY PASSWORD EQUAL password=STRING + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/alter-message-type-transact-sql +alter_message_type + : ALTER MESSAGE TYPE message_type_name=id VALIDATION EQUAL (NONE | EMPTY | WELL_FORMED_XML | VALID_XML WITH SCHEMA COLLECTION schema_collection_name=id) + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/alter-partition-function-transact-sql +alter_partition_function + : ALTER PARTITION FUNCTION partition_function_name=id LR_BRACKET RR_BRACKET (SPLIT|MERGE) RANGE LR_BRACKET DECIMAL RR_BRACKET + ; + +create_partition_function + : CREATE PARTITION FUNCTION partition_function_name=id LR_BRACKET data_type RR_BRACKET AS RANGE (LEFT | RIGHT)? FOR VALUES LR_BRACKET expression_list? RR_BRACKET + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/alter-partition-scheme-transact-sql +alter_partition_scheme + : ALTER PARTITION SCHEME partition_scheme_name=id NEXT USED (file_group_name=id)? + ; + +create_partition_scheme + : CREATE PARTITION SCHEME partition_scheme_name=id AS PARTITION partition_function_name=id ALL? TO LR_BRACKET id (COMMA id)* RR_BRACKET + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/alter-remote-service-binding-transact-sql +alter_remote_service_binding + : ALTER REMOTE SERVICE BINDING binding_name=id + WITH (USER EQUAL user_name=id)? + (COMMA ANONYMOUS EQUAL (ON|OFF) )? + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/create-remote-service-binding-transact-sql +create_remote_service_binding + : CREATE REMOTE SERVICE BINDING binding_name=id + (AUTHORIZATION owner_name=id)? + TO SERVICE remote_service_name=STRING + WITH (USER EQUAL user_name=id)? + (COMMA ANONYMOUS EQUAL (ON|OFF) )? + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/create-resource-pool-transact-sql +create_resource_pool + : CREATE RESOURCE POOL pool_name=id + (WITH + LR_BRACKET + (COMMA? MIN_CPU_PERCENT EQUAL DECIMAL)? + (COMMA? MAX_CPU_PERCENT EQUAL DECIMAL)? + (COMMA? CAP_CPU_PERCENT EQUAL DECIMAL)? + (COMMA? AFFINITY SCHEDULER EQUAL + (AUTO + | LR_BRACKET (COMMA? (DECIMAL|DECIMAL TO DECIMAL) )+ RR_BRACKET + | NUMANODE EQUAL LR_BRACKET (COMMA? (DECIMAL|DECIMAL TO DECIMAL) )+ RR_BRACKET + ) + )? + (COMMA? MIN_MEMORY_PERCENT EQUAL DECIMAL)? + (COMMA? MAX_MEMORY_PERCENT EQUAL DECIMAL)? + (COMMA? MIN_IOPS_PER_VOLUME EQUAL DECIMAL)? + (COMMA? MAX_IOPS_PER_VOLUME EQUAL DECIMAL)? + RR_BRACKET + )? + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/alter-resource-governor-transact-sql +alter_resource_governor + : ALTER RESOURCE GOVERNOR ( (DISABLE | RECONFIGURE) | WITH LR_BRACKET CLASSIFIER_FUNCTION EQUAL ( schema_name=id DOT function_name=id | NULL_P ) RR_BRACKET | RESET STATISTICS | WITH LR_BRACKET MAX_OUTSTANDING_IO_PER_VOLUME EQUAL max_outstanding_io_per_volume=DECIMAL RR_BRACKET ) + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/alter-role-transact-sql +alter_db_role + : ALTER ROLE role_name=id + ( (ADD|DROP) MEMBER database_principal=id + | WITH NAME EQUAL new_role_name=id ) + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/create-role-transact-sql +create_db_role + : CREATE ROLE role_name=id (AUTHORIZATION owner_name = id)? + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/create-route-transact-sql +create_route + : CREATE ROUTE route_name=id + (AUTHORIZATION owner_name=id)? + WITH + (COMMA? SERVICE_NAME EQUAL route_service_name=STRING)? + (COMMA? BROKER_INSTANCE EQUAL broker_instance_identifier=STRING)? + (COMMA? LIFETIME EQUAL DECIMAL)? + COMMA? ADDRESS EQUAL STRING + (COMMA MIRROR_ADDRESS EQUAL STRING )? + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/create-rule-transact-sql +create_rule + : CREATE RULE (schema_name=id DOT)? rule_name=id + AS search_condition + ; + +create_default + : CREATE DEFAULT (schema_name=id DOT)? default_name=id + AS expression + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/alter-schema-transact-sql +alter_schema + : ALTER SCHEMA schema_name=id TRANSFER ((OBJECT|TYPE|XML SCHEMA COLLECTION) colon_colon )? id (DOT id)? + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/create-schema-transact-sql +create_schema + : CREATE SCHEMA + (schema_name=id + |AUTHORIZATION owner_name=id + | schema_name=id AUTHORIZATION owner_name=id + ) + (create_table + |create_or_alter_view + | grant_statement + | revoke_statement + )* + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/create-search-property-list-transact-sql +create_search_property_list + : CREATE SEARCH PROPERTY LIST new_list_name=id + (FROM (database_name=id DOT)? source_list_name=id )? + (AUTHORIZATION owner_name=id)? + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/create-security-policy-transact-sql +create_security_policy + : CREATE SECURITY POLICY (schema_name=id DOT)? security_policy_name=id + (COMMA? ADD (FILTER|BLOCK)? PREDICATE tvf_schema_name=id DOT security_predicate_function_name=id + LR_BRACKET (COMMA? column_name_or_arguments=id)+ RR_BRACKET + ON table_schema_name=id DOT name=id + (COMMA? AFTER (INSERT|UPDATE) + | COMMA? BEFORE (UPDATE|DELETE) + )* + )+ + (WITH LR_BRACKET + STATE EQUAL (ON|OFF) + (SCHEMABINDING (ON|OFF) )? + RR_BRACKET + )? + for_replication? + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/alter-sequence-transact-sql +alter_sequence + : ALTER SEQUENCE (schema_name=id DOT)? sequence_name=id ( RESTART (WITH sign? DECIMAL)? )? (INCREMENT BY sign? DECIMAL )? ( MINVALUE sign? DECIMAL| NO MINVALUE)? (MAXVALUE sign? DECIMAL| NO MAXVALUE)? (CYCLE|NO CYCLE)? (CACHE DECIMAL | NO CACHE)? + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/create-sequence-transact-sql +create_sequence + : CREATE SEQUENCE (schema_name=id DOT)? sequence_name=id + (AS data_type )? + (START WITH sign? DECIMAL)? + (INCREMENT BY sign? DECIMAL)? + (MINVALUE sign? DECIMAL? | NO MINVALUE)? + (MAXVALUE sign? DECIMAL? | NO MAXVALUE)? + (CYCLE|NO CYCLE)? + (CACHE DECIMAL? | NO CACHE)? + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/alter-server-audit-transact-sql +alter_server_audit + : ALTER SERVER AUDIT audit_name=id + ( ( TO + (FILE + ( LR_BRACKET + ( COMMA? FILEPATH EQUAL filepath=STRING + | COMMA? MAXSIZE EQUAL ( DECIMAL (MB|GB|TB) + | UNLIMITED + ) + | COMMA? MAX_ROLLOVER_FILES EQUAL max_rollover_files=(DECIMAL|UNLIMITED) + | COMMA? MAX_FILES EQUAL max_files=DECIMAL + | COMMA? RESERVE_DISK_SPACE EQUAL (ON|OFF) )* + RR_BRACKET ) + | APPLICATION_LOG + | SECURITY_LOG + ) )? + ( WITH LR_BRACKET + (COMMA? QUEUE_DELAY EQUAL queue_delay=DECIMAL + | COMMA? ON_FAILURE EQUAL (CONTINUE | SHUTDOWN|FAIL_OPERATION) + |COMMA? STATE EQUAL (ON|OFF) )* + RR_BRACKET + )? + ( WHERE ( COMMA? (NOT?) event_field_name=id + (EQUAL + |(LESS GREATER) + | (EXCLAMATION EQUAL) + | GREATER + | (GREATER EQUAL) + | LESS + | LESS EQUAL + ) + (DECIMAL | STRING) + | COMMA? (AND|OR) NOT? (EQUAL + |(LESS GREATER) + | (EXCLAMATION EQUAL) + | GREATER + | (GREATER EQUAL) + | LESS + | LESS EQUAL) + (DECIMAL | STRING) ) )? + |REMOVE WHERE + | MODIFY NAME EQUAL new_audit_name=id + ) + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/create-server-audit-transact-sql +create_server_audit + : CREATE SERVER AUDIT audit_name=id + ( ( TO + (FILE + ( LR_BRACKET + ( COMMA? FILEPATH EQUAL filepath=STRING + | COMMA? MAXSIZE EQUAL ( DECIMAL (MB|GB|TB) + | UNLIMITED + ) + | COMMA? MAX_ROLLOVER_FILES EQUAL max_rollover_files=(DECIMAL|UNLIMITED) + | COMMA? MAX_FILES EQUAL max_files=DECIMAL + | COMMA? RESERVE_DISK_SPACE EQUAL (ON|OFF) )* + RR_BRACKET ) + | APPLICATION_LOG + | SECURITY_LOG + ) )? + ( WITH LR_BRACKET + (COMMA? QUEUE_DELAY EQUAL queue_delay=DECIMAL + | COMMA? ON_FAILURE EQUAL (CONTINUE | SHUTDOWN|FAIL_OPERATION) + |COMMA? STATE EQUAL (ON|OFF) + |COMMA? AUDIT_GUID EQUAL audit_guid=id + )* + + RR_BRACKET + )? + ( WHERE ( COMMA? (NOT?) event_field_name=id + (EQUAL + |(LESS GREATER) + | (EXCLAMATION EQUAL) + | GREATER + | (GREATER EQUAL) + | LESS + | LESS EQUAL + ) + (DECIMAL | STRING) + | COMMA? (AND|OR) NOT? (EQUAL + |(LESS GREATER) + | (EXCLAMATION EQUAL) + | GREATER + | (GREATER EQUAL) + | LESS + | LESS EQUAL) + (DECIMAL | STRING) ) )? + |REMOVE WHERE + | MODIFY NAME EQUAL new_audit_name=id + ) + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/alter-server-audit-specification-transact-sql +alter_server_audit_specification + : ALTER SERVER AUDIT SPECIFICATION audit_specification_name=id + (FOR SERVER AUDIT audit_name=id)? + ( (ADD|DROP) LR_BRACKET audit_action_group_name=id RR_BRACKET )* + (WITH LR_BRACKET STATE EQUAL (ON|OFF) RR_BRACKET )? + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/create-server-audit-specification-transact-sql +create_server_audit_specification + : CREATE SERVER AUDIT SPECIFICATION audit_specification_name=id + (FOR SERVER AUDIT audit_name=id)? + ( ADD LR_BRACKET audit_action_group_name=id RR_BRACKET )* + (WITH LR_BRACKET STATE EQUAL (ON|OFF) RR_BRACKET )? + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/alter-server-configuration-transact-sql +alter_server_configuration + : ALTER SERVER CONFIGURATION + SET ( (PROCESS AFFINITY (CPU EQUAL (AUTO | (COMMA? DECIMAL | COMMA? DECIMAL TO DECIMAL)+ ) | NUMANODE EQUAL ( COMMA? DECIMAL |COMMA? DECIMAL TO DECIMAL)+ ) | DIAGNOSTICS LOG (ON|OFF|PATH EQUAL (STRING | DEFAULT) |MAX_SIZE EQUAL (DECIMAL MB |DEFAULT)|MAX_FILES EQUAL (DECIMAL|DEFAULT) ) | FAILOVER CLUSTER PROPERTY (VERBOSELOGGING EQUAL (STRING|DEFAULT) |SQLDUMPERFLAGS EQUAL (STRING|DEFAULT) | SQLDUMPERPATH EQUAL (STRING|DEFAULT) | SQLDUMPERTIMEOUT (STRING|DEFAULT) | FAILURECONDITIONLEVEL EQUAL (STRING|DEFAULT) | HEALTHCHECKTIMEOUT EQUAL (DECIMAL|DEFAULT) ) | HADR CLUSTER CONTEXT EQUAL (STRING|LOCAL) | BUFFER POOL EXTENSION (ON LR_BRACKET FILENAME EQUAL STRING COMMA SIZE EQUAL DECIMAL (KB|MB|GB) RR_BRACKET | OFF ) | SET SOFTNUMA (ON|OFF) ) ) + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/alter-server-role-transact-sql +alter_server_role + : ALTER SERVER ROLE server_role_name=id + ( (ADD|DROP) MEMBER server_principal=id + | WITH NAME EQUAL new_server_role_name=id + ) + ; +// https://docs.microsoft.com/en-us/sql/t-sql/statements/create-server-role-transact-sql +create_server_role + : CREATE SERVER ROLE server_role=id (AUTHORIZATION server_principal=id)? + ; + +alter_server_role_pdw + : ALTER SERVER ROLE server_role_name=id (ADD|DROP) MEMBER login=id + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/alter-service-transact-sql +alter_service + : ALTER SERVICE modified_service_name=id (ON QUEUE (schema_name=id DOT) queue_name=id)? (COMMA? (ADD|DROP) modified_contract_name=id)* + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/create-service-transact-sql +create_service + : CREATE SERVICE create_service_name=id + (AUTHORIZATION owner_name=id)? + ON QUEUE (schema_name=id DOT)? queue_name=id + ( LR_BRACKET (COMMA? (id|DEFAULT) )+ RR_BRACKET )? + ; + + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/alter-service-master-key-transact-sql + +alter_service_master_key + : ALTER SERVICE MASTER KEY ( FORCE? REGENERATE | (WITH (OLD_ACCOUNT EQUAL acold_account_name=STRING COMMA OLD_PASSWORD EQUAL old_password=STRING | NEW_ACCOUNT EQUAL new_account_name=STRING COMMA NEW_PASSWORD EQUAL new_password=STRING)? ) ) + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/alter-symmetric-key-transact-sql + +alter_symmetric_key + : ALTER SYMMETRIC KEY key_name=id ( (ADD|DROP) ENCRYPTION BY (CERTIFICATE certificate_name=id | PASSWORD EQUAL password=STRING | SYMMETRIC KEY symmetric_key_name=id | ASYMMETRIC KEY Asym_key_name=id ) ) + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/create-symmetric-key-transact-sql +create_symmetric_key + : ALTER SYMMETRIC KEY key_name=id + (AUTHORIZATION owner_name=id)? + (FROM PROVIDER provider_name=id)? + (WITH ( (KEY_SOURCE EQUAL key_pass_phrase=STRING + | ALGORITHM EQUAL (DES | TRIPLE_DES | TRIPLE_DES_3KEY | RC2 | RC4 | RC4_128 | DESX | AES_128 | AES_192 | AES_256) + | IDENTITY_VALUE EQUAL identity_phrase=STRING + | PROVIDER_KEY_NAME EQUAL provider_key_name=STRING + | CREATION_DISPOSITION EQUAL (CREATE_NEW|OPEN_EXISTING) + ) + | ENCRYPTION BY + ( CERTIFICATE certificate_name=id + | PASSWORD EQUAL password=STRING + | SYMMETRIC KEY symmetric_key_name=id + | ASYMMETRIC KEY asym_key_name=id + ) + ) + ) + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/create-synonym-transact-sql +create_synonym + : CREATE SYNONYM (schema_name_1=id DOT )? synonym_name=id FOR full_object_name + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/alter-user-transact-sql +alter_user + : ALTER USER username=id WITH (COMMA? NAME EQUAL newusername=id | COMMA? DEFAULT_SCHEMA EQUAL ( schema_name=id |NULL_P ) | COMMA? LOGIN EQUAL loginame=id | COMMA? PASSWORD EQUAL STRING (OLD_PASSWORD EQUAL STRING)+ | COMMA? DEFAULT_LANGUAGE EQUAL (NONE| lcid=DECIMAL| language_name_or_alias=id) | COMMA? ALLOW_ENCRYPTED_VALUE_MODIFICATIONS EQUAL (ON|OFF) )+ + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/create-user-transact-sql +create_user + : CREATE USER user_name=id + ( (FOR|FROM) LOGIN login_name=id )? + ( WITH (COMMA? DEFAULT_SCHEMA EQUAL schema_name=id + |COMMA? ALLOW_ENCRYPTED_VALUE_MODIFICATIONS EQUAL (ON|OFF) + )* + )? + | CREATE USER ( windows_principal=id + (WITH + (COMMA? DEFAULT_SCHEMA EQUAL schema_name=id + |COMMA? DEFAULT_LANGUAGE EQUAL (NONE + |DECIMAL + |language_name_or_alias=id ) + |COMMA? SID EQUAL BINARY + |COMMA? ALLOW_ENCRYPTED_VALUE_MODIFICATIONS EQUAL (ON|OFF) + )* + )? + | user_name=id WITH PASSWORD EQUAL password=STRING + (COMMA? DEFAULT_SCHEMA EQUAL schema_name=id + |COMMA? DEFAULT_LANGUAGE EQUAL (NONE + |DECIMAL + |language_name_or_alias=id ) + |COMMA? SID EQUAL BINARY + |COMMA? ALLOW_ENCRYPTED_VALUE_MODIFICATIONS EQUAL (ON|OFF) + )* + | Azure_Active_Directory_principal=id FROM EXTERNAL PROVIDER + ) + | CREATE USER user_name=id + ( WITHOUT LOGIN + (COMMA? DEFAULT_SCHEMA EQUAL schema_name=id + |COMMA? ALLOW_ENCRYPTED_VALUE_MODIFICATIONS EQUAL (ON|OFF) + )* + | (FOR|FROM) CERTIFICATE cert_name=id + | (FOR|FROM) ASYMMETRIC KEY asym_key_name=id + ) + | CREATE USER user_name=id + ; + +create_user_azure_sql_dw + : CREATE USER user_name=id + ( (FOR|FROM) LOGIN login_name=id + | WITHOUT LOGIN + )? + + ( WITH DEFAULT_SCHEMA EQUAL schema_name=id)? + | CREATE USER Azure_Active_Directory_principal=id + FROM EXTERNAL PROVIDER + ( WITH DEFAULT_SCHEMA EQUAL schema_name=id)? + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/alter-workload-group-transact-sql +alter_workload_group + : ALTER WORKLOAD GROUP + (workload_group_group_name=id + |DEFAULT_DOUBLE_QUOTE + ) + (WITH LR_BRACKET + (IMPORTANCE EQUAL (LOW|MEDIUM|HIGH) + | COMMA? REQUEST_MAX_MEMORY_GRANT_PERCENT EQUAL request_max_memory_grant=DECIMAL + | COMMA? REQUEST_MAX_CPU_TIME_SEC EQUAL request_max_cpu_time_sec=DECIMAL + | REQUEST_MEMORY_GRANT_TIMEOUT_SEC EQUAL request_memory_grant_timeout_sec=DECIMAL + | MAX_DOP EQUAL max_dop=DECIMAL + | GROUP_MAX_REQUESTS EQUAL group_max_requests=DECIMAL)+ + RR_BRACKET )? + (USING (workload_group_pool_name=id | DEFAULT_DOUBLE_QUOTE) )? + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/create-workload-group-transact-sql +create_workload_group + : CREATE WORKLOAD GROUP workload_group_group_name=id + (WITH LR_BRACKET + (IMPORTANCE EQUAL (LOW|MEDIUM|HIGH) + | COMMA? REQUEST_MAX_MEMORY_GRANT_PERCENT EQUAL request_max_memory_grant=DECIMAL + | COMMA? REQUEST_MAX_CPU_TIME_SEC EQUAL request_max_cpu_time_sec=DECIMAL + | REQUEST_MEMORY_GRANT_TIMEOUT_SEC EQUAL request_memory_grant_timeout_sec=DECIMAL + | MAX_DOP EQUAL max_dop=DECIMAL + | GROUP_MAX_REQUESTS EQUAL group_max_requests=DECIMAL)+ + RR_BRACKET )? + (USING (workload_group_pool_name=id | DEFAULT_DOUBLE_QUOTE)? + (COMMA? EXTERNAL external_pool_name=id | DEFAULT_DOUBLE_QUOTE)? + )? + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/create-xml-schema-collection-transact-sql +create_xml_schema_collection + : CREATE XML SCHEMA COLLECTION simple_name AS (STRING|id|LOCAL_ID) + ; + +alter_xml_schema_collection + : ALTER XML SCHEMA COLLECTION simple_name ADD STRING + ; + +create_queue + : CREATE QUEUE (full_object_name | queue_name=id) queue_settings? + (ON filegroup=id | DEFAULT)? + ; + + +queue_settings + : WITH + (STATUS EQUAL (ON | OFF) COMMA?)? + (RETENTION EQUAL (ON | OFF) COMMA?)? + (ACTIVATION + LR_BRACKET + ( + ( + (STATUS EQUAL (ON | OFF) COMMA? )? + (PROCEDURE_NAME EQUAL func_proc_name_database_schema COMMA?)? + (MAX_QUEUE_READERS EQUAL max_readers=DECIMAL COMMA?)? + ((EXECUTE|EXEC) AS (SELF | user_name=STRING | OWNER) COMMA?)? + ) + | DROP + ) + RR_BRACKET COMMA? + )? + (POISON_MESSAGE_HANDLING + LR_BRACKET + (STATUS EQUAL (ON | OFF)) + RR_BRACKET + )? + ; + +alter_queue + : ALTER QUEUE (full_object_name | queue_name=id) + (queue_settings | queue_action) + ; + +queue_action + : REBUILD ( WITH LR_BRACKET queue_rebuild_options RR_BRACKET)? + | REORGANIZE (WITH LOB_COMPACTION EQUAL (ON | OFF))? + | MOVE TO (id | DEFAULT) + ; +queue_rebuild_options + : maxdop_option + ; + +create_contract + : CREATE CONTRACT contract_name + (AUTHORIZATION owner_name=id)? + LR_BRACKET ((message_type_name=id | DEFAULT) + SENT BY (INITIATOR | TARGET | ANY ) COMMA?)+ + RR_BRACKET + ; + +conversation_statement + : begin_conversation_timer + | begin_conversation_dialog + | end_conversation + | get_conversation + | send_conversation + | waitfor_conversation + | waitfor_receive_statement + | receive_statement + ; + +message_statement + : CREATE MESSAGE TYPE message_type_name=id + (AUTHORIZATION owner_name=id)? + (VALIDATION EQUAL (NONE + | EMPTY + | WELL_FORMED_XML + | VALID_XML WITH SCHEMA COLLECTION schema_collection_name=id)) + ; + +// DML + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/merge-transact-sql +// note that there is a limit on number of when_matches but it has to be done runtime due to different ordering of statements allowed +merge_statement + : with_expression? + MERGE (TOP LR_BRACKET expression RR_BRACKET PERCENT?)? + INTO? ddl_object with_table_hints? as_table_alias? + USING table_sources + ON search_condition + when_matches+ + output_clause? + option_clause? + SEMI /// semicolon is required! + ; + +when_matches + : (WHEN MATCHED (AND search_condition)? + THEN merge_matched)+ + | (WHEN NOT MATCHED (BY TARGET)? (AND search_condition)? + THEN merge_not_matched) + | (WHEN NOT MATCHED BY SOURCE (AND search_condition)? + THEN merge_matched)+ + ; + +merge_matched + : UPDATE SET update_elem_merge (COMMA update_elem_merge)* + | DELETE + ; + +merge_not_matched + : INSERT ( LR_BRACKET column_name_list RR_BRACKET )? + (table_value_constructor | DEFAULT VALUES) + ; + +// https://msdn.microsoft.com/en-us/library/ms189835.aspx +delete_statement + : with_expression? + DELETE (TOP LR_BRACKET expression RR_BRACKET PERCENT? | TOP DECIMAL)? + FROM? delete_statement_from + with_table_hints? + output_clause? + (FROM table_sources)? + (WHERE (search_condition | CURRENT OF (GLOBAL? cursor_name | cursor_var=LOCAL_ID)))? + option_clause? SEMI? + ; + +delete_statement_from + : ddl_object + | table_alias + | rowset_function + | table_var=LOCAL_ID + ; + +// https://msdn.microsoft.com/en-us/library/ms174335.aspx +insert_statement + : with_expression? + INSERT (TOP LR_BRACKET expression RR_BRACKET PERCENT?)? + INTO? (ddl_object | rowset_function) + with_table_hints? + ( LR_BRACKET insert_column_name_list RR_BRACKET )? + output_clause? + insert_statement_value + option_clause? SEMI? + ; + +insert_statement_value + : table_value_constructor + | derived_table + | execute_statement + | DEFAULT VALUES + ; + +bulk_insert_statement + : BULK INSERT ddl_object FROM STRING ( WITH LR_BRACKET bulk_insert_option (COMMA? bulk_insert_option)* RR_BRACKET )? SEMI? + | INSERT BULK ddl_object (LR_BRACKET (insert_bulk_column_definition (COMMA insert_bulk_column_definition)*)? column_constraint* COMMA? RR_BRACKET) + ; + +bulk_insert_option + : id (EQUAL expression)? + | ORDER LR_BRACKET order_by_expression (COMMA order_by_expression)* RR_BRACKET + ; + +// https://msdn.microsoft.com/en-us/library/ms189499.aspx +select_statement_standalone + : with_expression? + select_statement + ; + +select_statement + : query_expression order_by_clause? option_clause? for_clause? option_clause? + ; + +time + : (LOCAL_ID | constant) + ; + +// https://msdn.microsoft.com/en-us/library/ms177523.aspx +update_statement + : with_expression? + UPDATE (TOP LR_BRACKET expression RR_BRACKET PERCENT?)? + (ddl_object | rowset_function) + with_table_hints? + SET update_elem (COMMA update_elem)* + output_clause? + (FROM table_sources)? + (WHERE (search_condition | CURRENT OF (GLOBAL? cursor_name | cursor_var=LOCAL_ID)))? + option_clause? SEMI? + ; + +// https://msdn.microsoft.com/en-us/library/ms177564.aspx +output_clause + : OUTPUT output_dml_list_elem (COMMA output_dml_list_elem)* + (INTO (LOCAL_ID | table_name) ( LR_BRACKET column_name_list RR_BRACKET )? )? + ; + +output_dml_list_elem + : (output_column_name | expression) as_column_alias? // TODO: scalar_expression + ; + +output_column_name + : (DELETED | INSERTED | table_name) DOT ( STAR | id) + | DOLLAR_ACTION + ; + +readtext_statement + : READTEXT full_column_name text_ptr=(LOCAL_ID|BINARY) offset=(LOCAL_ID|DECIMAL) size=(LOCAL_ID|DECIMAL) HOLDLOCK? + ; + +writetext_statement + : WRITETEXT BULK? full_column_name text_ptr=(LOCAL_ID|BINARY) (WITH LOG)? (LOCAL_ID|STRING) + ; + +updatetext_statement + : UPDATETEXT BULK? full_column_name text_ptr=(LOCAL_ID|BINARY) (NULL_P|DECIMAL|LOCAL_ID) (NULL_P|DECIMAL|LOCAL_ID) (WITH LOG)? ((LOCAL_ID|STRING) | full_column_name text_ptr=(LOCAL_ID|BINARY) )? + ; + +// https://msdn.microsoft.com/en-ie/library/ms176061.aspx +create_database + : CREATE DATABASE (database=id) + ( CONTAINMENT EQUAL ( NONE | PARTIAL ) )? + ( ON PRIMARY? database_file_spec ( COMMA database_file_spec )* )? + ( LOG ON database_file_spec ( COMMA database_file_spec )* )? + ( COLLATE collation_name = id )? + ( WITH create_database_option ( COMMA create_database_option )* )? + ; + +// https://msdn.microsoft.com/en-us/library/ms188783.aspx +create_index + : CREATE UNIQUE? clustered? COLUMNSTORE? INDEX id ON table_name (LR_BRACKET column_name_list_with_order RR_BRACKET)? + (INCLUDE LR_BRACKET column_name_list RR_BRACKET )? + (WHERE where=search_condition)? + with_index_options? + (ON storage_partition_clause)? + SEMI? + ; + +alter_index + : ALTER INDEX (id | ALL) ON table_name alter_index_options + SEMI? + ; + +alter_index_options + : REBUILD ( PARTITION EQUAL (ALL | (DECIMAL|LOCAL_ID)) )? (WITH LR_BRACKET index_option (COMMA index_option)* RR_BRACKET )? + | DISABLE + | REORGANIZE + | SET LR_BRACKET index_option (COMMA index_option)* RR_BRACKET + | RESUME (WITH LR_BRACKET index_option (COMMA index_option)* RR_BRACKET)? + | PAUSE + | ABORT + ; + +create_xml_index + : CREATE PRIMARY? XML INDEX id ON table_name LR_BRACKET id RR_BRACKET + (USING XML INDEX id (FOR (VALUE | PATH | PROPERTY)?)?)? + with_index_options? + SEMI? + ; + +create_selective_xml_index + : CREATE SELECTIVE XML INDEX id ON table_name LR_BRACKET id RR_BRACKET + (WITH XMLNAMESPACES LR_BRACKET STRING AS id (COMMA STRING AS id)* RR_BRACKET)? + FOR LR_BRACKET promoted_node_path (COMMA promoted_node_path)* RR_BRACKET + with_index_options? + SEMI? + ; + +promoted_node_path + : pathname=ID EQUAL STRING (AS (XQUERY STRING | SQL) data_type? SINGLETON?)? + ; + +create_spatial_index + : CREATE SPATIAL INDEX id ON table_name LR_BRACKET id RR_BRACKET + spatial_grid_clause? + spatial_grid_option_clause? + (ON storage_partition_clause)? + SEMI? + ; + +spatial_grid_clause + : USING (GEOMETRY_AUTO_GRID | GEOMETRY_GRID | GEOGRAPHY_AUTO_GRID | GEOGRAPHY_GRID) + ; + +spatial_grid_option_clause + : WITH LR_BRACKET spatial_grid_option (COMMA spatial_grid_option)* RR_BRACKET + ; + +spatial_grid_option + : bounding_box + | tessellation_cells_per_object + | tessellation_grid + | spatial_index_option (COMMA spatial_index_option)* + ; + +bounding_box + : BOUNDING_BOX EQUAL LR_BRACKET (XMIN EQUAL)? expression COMMA (YMIN EQUAL)? expression COMMA (XMAX EQUAL)? expression COMMA (YMAX EQUAL)? expression RR_BRACKET + ; + +tessellation_cells_per_object + : CELLS_PER_OBJECT EQUAL (DECIMAL|LOCAL_ID) + ; + +tessellation_grid + : GRIDS EQUAL LR_BRACKET grid_level_or_size (COMMA grid_level_or_size)* RR_BRACKET + ; + +grid_level_or_size + : (id EQUAL)? (LOW | MEDIUM | HIGH) + ; + +spatial_index_option + : index_option + ; + +// https://msdn.microsoft.com/en-us/library/ms187926(v=sql.120).aspx +create_or_alter_procedure + : ((CREATE (OR ALTER)?) | ALTER) proc=(PROC | PROCEDURE) procName=func_proc_name_schema ( SEMI DECIMAL)? + ( LR_BRACKET? procedure_param (COMMA procedure_param)* RR_BRACKET?)? + (WITH procedure_option (COMMA procedure_option)*)? + for_replication? AS + ( atomic_proc_body | sql_clauses* | external_name ) + ; + +atomic_proc_body + : BEGIN atomic WITH LR_BRACKET atomic_body_options RR_BRACKET sql_clauses* END SEMI? + ; + +atomic + : ATOMIC + ; + +atomic_body_options + : atomic_body_option (COMMA atomic_body_option)* + ; + +atomic_body_option + : LANGUAGE EQUAL STRING + | TRANSACTION ISOLATION LEVEL EQUAL (SNAPSHOT | REPEATABLE READ | SERIALIZABLE) + | DATEFIRST EQUAL DECIMAL + | DATEFORMAT EQUAL id + | DELAYED_DURABILITY EQUAL on_off + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/create-trigger-transact-sql +create_or_alter_trigger + : create_or_alter_dml_trigger + | create_or_alter_ddl_trigger + ; + +create_or_alter_dml_trigger + : ((CREATE (OR ALTER)?) | ALTER) TRIGGER simple_name + ON table_name + (WITH trigger_option (COMMA trigger_option)* )? + (FOR | AFTER | INSTEAD OF) + dml_trigger_operation (COMMA dml_trigger_operation)* + (WITH APPEND)? + for_replication? + AS (sql_clauses+ | external_name) + ; + +dml_trigger_operation + : (INSERT | UPDATE | DELETE) + ; + +create_or_alter_ddl_trigger + : ((CREATE (OR ALTER)?) | ALTER) TRIGGER simple_name + ON (ALL SERVER | DATABASE) + (WITH trigger_option (COMMA trigger_option)* )? + (FOR | AFTER) ddl_trigger_operation+=ID (COMMA ddl_trigger_operation+=ID)* + AS (sql_clauses+ | external_name) + ; + +trigger_option + : ENCRYPTION + | NATIVE_COMPILATION + | SCHEMABINDING + | execute_as_clause + ; + +// https://msdn.microsoft.com/en-us/library/ms186755.aspx +create_or_alter_function + : ((CREATE (OR ALTER)?) | ALTER) FUNCTION funcName=func_proc_name_schema + (( LR_BRACKET procedure_param (COMMA procedure_param)* RR_BRACKET ) | LR_BRACKET RR_BRACKET ) //must have (), but can be empty + ( func_body_returns_select | func_body_returns_table | func_body_returns_scalar | func_body_returns_table_clr ) SEMI? + ; + +func_body_returns_select + : RETURNS TABLE + (WITH function_option (COMMA function_option)*)? + AS? + func_body_return_select_body + ; + +func_body_return_select_body + : RETURN ( LR_BRACKET select_statement_standalone RR_BRACKET | select_statement_standalone) + ; + +func_body_returns_table + : RETURNS LOCAL_ID table_type_definition + (WITH function_option (COMMA function_option)*)? + AS? + BEGIN sql_clauses* RETURN SEMI? END + ; + +func_body_returns_table_clr + : RETURNS table_type_definition + (WITH function_option (COMMA function_option)*)? + (ORDER LR_BRACKET column_name_list_with_order RR_BRACKET)? + AS? + external_name + ; + +func_body_returns_scalar + : RETURNS data_type + (WITH function_option (COMMA function_option)*)? + AS? + ( BEGIN atomic_func_body? sql_clauses* RETURN ret=expression SEMI? END | external_name ) + ; + +atomic_func_body + : atomic WITH LR_BRACKET atomic_body_options RR_BRACKET + ; + +// CREATE PROC p @p INT NULL --> this appears to be accepted syntax for non-native compiled procs, though formally not allowed +procedure_param + : LOCAL_ID AS? data_type VARYING? (NOT? NULL_P)? (EQUAL default_val=expression)? (OUT | OUTPUT | READONLY)? + ; + +// drop_procedure_param can be used in a DROP FUNCTION or DROP PROCEDURE command +drop_procedure_param + : LOCAL_ID? data_type + ; + +procedure_option + : ENCRYPTION + | NATIVE_COMPILATION + | SCHEMABINDING + | RECOMPILE + | execute_as_clause + ; + +function_option + : ENCRYPTION + | NATIVE_COMPILATION + | SCHEMABINDING + | RETURNS NULL_P ON NULL_P INPUT + | CALLED ON NULL_P INPUT + | execute_as_clause + ; + +// https://msdn.microsoft.com/en-us/library/ms188038.aspx +create_statistics + : CREATE STATISTICS id ON table_name LR_BRACKET column_name_list RR_BRACKET + (WITH (FULLSCAN | SAMPLE DECIMAL (PERCENT | ROWS) | STATS_STREAM) + (COMMA NORECOMPUTE)? (COMMA INCREMENTAL EQUAL on_off)? )? SEMI? + ; + +// UPDATE (INDEX|ALL) STATISTICS is Sybase T-SQL, not MSFT +update_statistics + : UPDATE STATISTICS table_name (table_name | LR_BRACKET column_name_list RR_BRACKET )? + (WITH update_statistics_option (COMMA? update_statistics_option)*)? + SEMI? + ; + +update_statistics_option + : FULLSCAN (COMMA? update_statistics_option_persist_pct)? + | SAMPLE expression (PERCENT|ROWS) (COMMA? update_statistics_option_persist_pct)? + | RESAMPLE (ON PARTITIONS LR_BRACKET ((DECIMAL|LOCAL_ID)|(DECIMAL|LOCAL_ID) TO (DECIMAL|LOCAL_ID)) (COMMA ((DECIMAL|LOCAL_ID)|(DECIMAL|LOCAL_ID) TO (DECIMAL|LOCAL_ID)))* RR_BRACKET )? + | update_statistics_option_stats_stream (COMMA update_statistics_option_stats_stream)* + | (ALL|COLUMNS|INDEX) + | NOCOMPUTE + | INCREMENTAL EQUAL on_off + | maxdop_option + ; + +update_statistics_option_persist_pct + : PERSIST_SAMPLE_PERCENT EQUAL on_off + ; + +update_statistics_option_stats_stream + : STATS_STREAM EQUAL BINARY + | ROWCOUNT EQUAL DECIMAL + | PAGECOUNT EQUAL DECIMAL + ; + +maxdop_option + : MAXDOP EQUAL DECIMAL + ; + +// https://msdn.microsoft.com/en-us/library/ms174979.aspx +create_table + : CREATE TABLE tabname=table_name LR_BRACKET column_def_table_constraints (COMMA? table_indices)* COMMA? RR_BRACKET create_table_options* SEMI? + | CREATE TABLE tabname=table_name (LR_BRACKET (column_definition (COMMA column_definition)*)? column_constraint* COMMA? RR_BRACKET)? graph_clause create_table_options* SEMI? + | CREATE TABLE tabname=table_name AS FILETABLE (WITH LR_BRACKET file_table_option (COMMA file_table_option)* RR_BRACKET)? SEMI? + ; + + +create_table_options + : LOCK ID + | table_options + | ON storage_partition_clause + | TEXTIMAGE_ON storage_partition_clause + | FILESTREAM_ON storage_partition_clause + ; + +graph_clause + : AS (NODE | EDGE) + ; + +table_indices + : INDEX id (UNIQUE | CLUSTERED | NONCLUSTERED)? LR_BRACKET column_name_list_with_order RR_BRACKET + (WHERE where=search_condition)? + with_index_options? + (ON storage_partition_clause)? + ; + +table_options + : WITH (LR_BRACKET index_option_list? system_versioning_options? RR_BRACKET | index_option_list ) + ; + +file_table_option + : id EQUAL expression + ; + +storage_partition_clause + : id (LR_BRACKET id RR_BRACKET)? + | STRING // can be "DEFAULT" + ; + +// https://msdn.microsoft.com/en-us/library/ms187956.aspx +create_or_alter_view + : ((CREATE (OR ALTER)?) | ALTER) VIEW simple_name (LR_BRACKET column_name_list RR_BRACKET)? + (WITH view_attribute (COMMA view_attribute)*)? + AS select_statement_standalone (WITH CHECK OPTION)? SEMI? + ; + +view_attribute + : ENCRYPTION | SCHEMABINDING | VIEW_METADATA + ; + +// https://msdn.microsoft.com/en-us/library/ms190273.aspx +alter_table + : ALTER TABLE tabname=table_name + ( (WITH (NOCHECK | CHECK))? ADD column_def_table_constraints + | ALTER COLUMN column_definition ((ADD | DROP) special_column_option)? (WITH ( LR_BRACKET ONLINE EQUAL on_off RR_BRACKET ))? + | DROP alter_table_drop (COMMA alter_table_drop)* + | (WITH (NOCHECK | CHECK))? (NOCHECK | CHECK) CONSTRAINT ( ALL | id (COMMA id)* ) + | (ENABLE | DISABLE) TRIGGER ( ALL | id (COMMA id)* ) + | (ENABLE | DISABLE) CHANGE_TRACKING (WITH LR_BRACKET TRACK_COLUMNS_UPDATED EQUAL on_off RR_BRACKET)? + | SWITCH (PARTITION (DECIMAL|LOCAL_ID))? TO table_name (PARTITION (DECIMAL|LOCAL_ID))? (WITH LR_BRACKET low_priority_lock_wait RR_BRACKET )? + | SET LR_BRACKET SYSTEM_VERSIONING EQUAL on_off system_versioning_options RR_BRACKET + | SET LR_BRACKET FILESTREAM_ON EQUAL storage_partition_clause RR_BRACKET + | SET LR_BRACKET file_table_option (COMMA file_table_option)* RR_BRACKET + | SET LR_BRACKET LOCK_ESCALATION EQUAL (AUTO | TABLE | DISABLE) RR_BRACKET + | REBUILD table_options + ) + ; + +alter_table_drop + : alter_table_drop_column + | alter_table_drop_constraint + | PERIOD FOR SYSTEM_TIME + ; + +alter_table_drop_column + : COLUMN if_exists? id (COMMA (COLUMN if_exists?)? id)* + ; + +alter_table_drop_constraint + : CONSTRAINT if_exists? alter_table_drop_constraint_id (COMMA (CONSTRAINT if_exists?)? id)* + ; + +alter_table_drop_constraint_id + : id (WITH LR_BRACKET alter_table_drop_constraint_option (COMMA alter_table_drop_constraint_option)* RR_BRACKET)? + ; + +alter_table_drop_constraint_option + : maxdop_option + | ONLINE EQUAL on_off + | MOVE TO storage_partition_clause + ; + +low_priority_lock_wait + : WAIT_AT_LOW_PRIORITY LR_BRACKET MAX_DURATION EQUAL DECIMAL MINUTES? COMMA ABORT_AFTER_WAIT EQUAL (NONE | SELF | BLOCKERS) RR_BRACKET + ; + +// https://msdn.microsoft.com/en-us/library/ms174269.aspx +alter_database + : ALTER DATABASE (database=id | CURRENT) + ( SET database_optionspec (COMMA database_optionspec)* (WITH termination)? + | COLLATE id + | MODIFY NAME EQUAL new_name=id + | ADD FILE file_spec (COMMA file_spec)* ( TO FILEGROUP filegroup=id )? + | ADD LOG FILE file_spec (COMMA file_spec)* + | REMOVE FILE filename=id + | MODIFY FILE file_spec + | ADD FILEGROUP filegroup=id ( CONTAINS FILESTREAM | CONTAINS MEMORY_OPTIMIZED_DATA )? + | REMOVE FILEGROUP filegroup=id + | MODIFY FILEGROUP filegroup=id ( filegroup_updatability_option | DEFAULT | NAME EQUAL filegroup=id | AUTOGROW_SINGLE_FILE | AUTOGROW_ALL_FILES ) + ) + SEMI? + ; + +filegroup_updatability_option + : ( READONLY | READ_ONLY | READWRITE | READ_WRITE ) + ; + +// https://msdn.microsoft.com/en-us/library/bb522682.aspx +// Runtime check. +database_optionspec + : auto_option + | change_tracking_option + | containment_option + | cursor_option + | database_mirroring_option + | date_correlation_optimization_option + | db_encryption_option + | db_state_option + | db_update_option + | db_user_access_option + | delayed_durability_option + | external_access_option + | FILESTREAM database_filestream_option + | hadr_options + | mixed_page_allocation_option + | parameterization_option + | query_store_option + | recovery_option +// | remote_data_archive_option + | service_broker_option + | snapshot_option + | sql_option + | target_recovery_time_option + | termination + ; + +alter_database_scoped_configuration + : ALTER DATABASE SCOPED CONFIGURATION ( FOR SECONDARY )? SET id EQUAL ( on_off | PRIMARY | AUTO | WHEN_SUPPORTED | FAIL_UNSUPPORTED | DECIMAL ) + | ALTER DATABASE SCOPED CONFIGURATION CLEAR PROCEDURE_CACHE BINARY + ; + +auto_option + : AUTO_CLOSE on_off + | AUTO_CREATE_STATISTICS ( OFF | ON ( INCREMENTAL EQUAL ON | OFF )? ) + | AUTO_SHRINK on_off + | AUTO_UPDATE_STATISTICS on_off + | AUTO_UPDATE_STATISTICS_ASYNC (ON | OFF ) + ; + +change_tracking_option + : CHANGE_TRACKING EQUAL ( OFF | ON (change_tracking_option_list (COMMA change_tracking_option_list)*)* ) + ; + +change_tracking_option_list + : AUTO_CLEANUP EQUAL on_off + | CHANGE_RETENTION EQUAL ( DAYS | HOURS | MINUTES ) + ; + +containment_option + : CONTAINMENT EQUAL ( NONE | PARTIAL ) + ; + +cursor_option + : CURSOR_CLOSE_ON_COMMIT on_off + | CURSOR_DEFAULT ( LOCAL | GLOBAL ) + ; + +create_or_alter_database_audit_specification + : (CREATE | ALTER) DATABASE AUDIT SPECIFICATION audit_specification_name=id + FOR SERVER AUDIT server_audit=id + ((ADD | DROP) LR_BRACKET audit_item (COMMA audit_item)* RR_BRACKET)? + WITH LR_BRACKET STATE EQUAL on_off RR_BRACKET + SEMI? + ; + +audit_item + : audit_action_group_name=ID + | audit_action_specification + ; + +audit_action_specification + : permission (COMMA permission)* ON (object_type colon_colon)? entity=entity_name BY principals + ; + +create_diagnostic_session + : CREATE DIAGNOSTICS SESSION session_name=ID AS xml=STRING SEMI + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/create-endpoint-transact-sql +// https://docs.microsoft.com/en-us/sql/t-sql/statements/alter-endpoint-transact-sql +create_or_alter_endpoint + : (CREATE | ALTER) ENDPOINT endpointname=id (AUTHORIZATION login=id)? + ( STATE EQUAL ( state=STARTED | state=STOPPED | state=DISABLED ) )? + AS TCP LR_BRACKET + LISTENER_PORT EQUAL port=DECIMAL + ( COMMA LISTENER_IP EQUAL + (ALL | LR_BRACKET IPV4_ADDR RR_BRACKET | LR_BRACKET STRING RR_BRACKET) )? + RR_BRACKET + ( FOR TSQL LR_BRACKET RR_BRACKET + | + FOR SERVICE_BROKER LR_BRACKET + AUTHENTICATION EQUAL + ( WINDOWS ( NTLM |KERBEROS | NEGOTIATE )? (CERTIFICATE cert_name=id)? + | CERTIFICATE cert_name=id WINDOWS? ( NTLM |KERBEROS | NEGOTIATE )? + ) + ( COMMA? ENCRYPTION EQUAL ( DISABLED |SUPPORTED | REQUIRED ) + ( ALGORITHM ( AES | RC4 | AES RC4 | RC4 AES ) )? + )? + + ( COMMA? MESSAGE_FORWARDING EQUAL ( ENABLED | DISABLED ) )? + ( COMMA? MESSAGE_FORWARD_SIZE EQUAL DECIMAL)? + RR_BRACKET + | + FOR DATABASE_MIRRORING LR_BRACKET + AUTHENTICATION EQUAL + ( WINDOWS ( NTLM |KERBEROS | NEGOTIATE )? (CERTIFICATE cert_name=id)? + | CERTIFICATE cert_name=id WINDOWS? ( NTLM |KERBEROS | NEGOTIATE )? + ) + + ( COMMA? ENCRYPTION EQUAL ( DISABLED |SUPPORTED | REQUIRED ) + ( ALGORITHM ( AES | RC4 | AES RC4 | RC4 AES ) )? + )? + + COMMA? ROLE EQUAL ( WITNESS | PARTNER | ALL ) + RR_BRACKET + ) + ; + +database_mirroring_option + : mirroring_set_option + ; + +mirroring_set_option + : mirroring_partner partner_option + | mirroring_witness witness_option + ; +mirroring_partner + : PARTNER + ; + +mirroring_witness + : WITNESS + ; + +witness_partner_equal + : EQUAL + ; + +partner_option + : witness_partner_equal partner_server + | FAILOVER + | FORCE_SERVICE_ALLOW_DATA_LOSS + | OFF + | RESUME + | SAFETY (FULL | OFF ) + | SUSPEND + | TIMEOUT DECIMAL + ; + +witness_option + : witness_partner_equal witness_server + | OFF + ; + +witness_server + : partner_server + ; + +partner_server + : partner_server_tcp_prefix host mirroring_host_port_seperator port_number + ; + +mirroring_host_port_seperator + : COLON + ; + +partner_server_tcp_prefix + : TCP COLON DOUBLE_FORWARD_SLASH + ; +port_number + : port=DECIMAL + ; + +host + : id (DOT host?)? + ; + +date_correlation_optimization_option + : DATE_CORRELATION_OPTIMIZATION on_off + ; + +db_encryption_option + : ENCRYPTION on_off + ; +db_state_option + : ( ONLINE | OFFLINE | EMERGENCY ) + ; + +db_update_option + : READ_ONLY | READ_WRITE + ; + +db_user_access_option + : SINGLE_USER | RESTRICTED_USER | MULTI_USER + ; +delayed_durability_option + : DELAYED_DURABILITY EQUAL ( DISABLED | ALLOWED | FORCED ) + ; + +external_access_option + : DB_CHAINING on_off + | TRUSTWORTHY on_off + | DEFAULT_LANGUAGE EQUAL ( id | STRING | DECIMAL ) + | DEFAULT_FULLTEXT_LANGUAGE EQUAL ( id | STRING | DECIMAL ) + | NESTED_TRIGGERS EQUAL ( OFF | ON ) + | TRANSFORM_NOISE_WORDS EQUAL ( OFF | ON ) + | TWO_DIGIT_YEAR_CUTOFF EQUAL DECIMAL + ; + +hadr_options + : HADR + ( ( AVAILABILITY GROUP EQUAL availability_group_name=id | OFF ) |(SUSPEND|RESUME) ) + ; + +mixed_page_allocation_option + : MIXED_PAGE_ALLOCATION ( OFF | ON ) + ; + +parameterization_option + : PARAMETERIZATION ( SIMPLE | FORCED ) + ; + +query_store_option + : QUERY_STORE EQUAL OFF ( LR_BRACKET FORCED RR_BRACKET )? + | QUERY_STORE CLEAR ALL? + | QUERY_STORE ( EQUAL ON )? ( LR_BRACKET query_store_option_item ( COMMA query_store_option_item )* RR_BRACKET )? + ; + +query_store_option_item + : CLEANUP_POLICY EQUAL LR_BRACKET STALE_QUERY_THRESHOLD_DAYS EQUAL thr_days=DECIMAL RR_BRACKET + | DATA_FLUSH_INTERVAL_SECONDS EQUAL DECIMAL + | INTERVAL_LENGTH_MINUTES EQUAL DECIMAL + | MAX_PLANS_PER_QUERY EQUAL DECIMAL + | MAX_SIZE_MB EQUAL DECIMAL + | MAX_STORAGE_SIZE_MB EQUAL DECIMAL + | OPERATION_MODE EQUAL ( READ_WRITE | READ_ONLY ) + | QUERY_CAPTURE_MODE EQUAL ( ALL | AUTO | CUSTOM | NONE ) + | QUERY_CAPTURE_POLICY EQUAL LR_BRACKET query_capture_policy_option ( COMMA query_capture_policy_option )* RR_BRACKET + | SIZE_BASED_CLEANUP_MODE EQUAL ( AUTO | OFF ) + | WAIT_STATS_CAPTURE_MODE EQUAL on_off + ; + +query_capture_policy_option + : EXECUTION_COUNT EQUAL DECIMAL + | STALE_CAPTURE_POLICY_THRESHOLD EQUAL DECIMAL ( DAYS | HOURS ) + | TOTAL_COMPILE_CPU_TIME_MS EQUAL DECIMAL + | TOTAL_EXECUTION_CPU_TIME_MS EQUAL DECIMAL + ; + +recovery_option + : RECOVERY ( FULL | BULK_LOGGED | SIMPLE ) + | TORN_PAGE_DETECTION on_off + | PAGE_VERIFY ( CHECKSUM | TORN_PAGE_DETECTION | NONE ) + ; + +service_broker_option: + ENABLE_BROKER + | DISABLE_BROKER + | NEW_BROKER + | ERROR_BROKER_CONVERSATIONS + | HONOR_BROKER_PRIORITY on_off + ; +snapshot_option + : ALLOW_SNAPSHOT_ISOLATION on_off + | READ_COMMITTED_SNAPSHOT (ON | OFF ) + | MEMORY_OPTIMIZED_ELEVATE_TO_SNAPSHOT = (ON | OFF ) + ; + +sql_option + : ANSI_NULL_DEFAULT on_off + | ANSI_NULLS on_off + | ANSI_PADDING on_off + | ANSI_WARNINGS on_off + | ARITHABORT on_off + | COMPATIBILITY_LEVEL EQUAL DECIMAL + | CONCAT_NULL_YIELDS_NULL on_off + | NUMERIC_ROUNDABORT on_off + | QUOTED_IDENTIFIER on_off + | RECURSIVE_TRIGGERS on_off + ; + +target_recovery_time_option + : TARGET_RECOVERY_TIME EQUAL DECIMAL ( SECONDS | MINUTES ) + ; + +termination + : ROLLBACK AFTER seconds = DECIMAL + | ROLLBACK IMMEDIATE + | NO_WAIT + ; + +// https://msdn.microsoft.com/en-us/library/ms176118.aspx +drop_index + : DROP INDEX if_exists? + ( drop_relational_or_xml_or_spatial_index (COMMA drop_relational_or_xml_or_spatial_index)* + | drop_backward_compatible_index (COMMA drop_backward_compatible_index)* + ) + SEMI? + ; + +drop_relational_or_xml_or_spatial_index + : index_name=id ON full_object_name + ; + +drop_backward_compatible_index + : (owner_name=id DOT)? table_or_view_name=id DOT index_name=id + ; + +// https://msdn.microsoft.com/en-us/library/ms174969.aspx +drop_procedure + : DROP proc=(PROC | PROCEDURE) if_exists? func_proc_name_schema (COMMA func_proc_name_schema)* SEMI? + | DROP proc=(PROC | PROCEDURE) if_exists? func_proc_name_schema (( LR_BRACKET drop_procedure_param (COMMA drop_procedure_param)* RR_BRACKET ) | LR_BRACKET RR_BRACKET ) SEMI? + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-trigger-transact-sql +drop_trigger + : DROP TRIGGER if_exists? simple_name (COMMA simple_name)* (ddl=ON (DATABASE | ALL SERVER))? SEMI? + ; + +// https://msdn.microsoft.com/en-us/library/ms190290.aspx +drop_function + : DROP FUNCTION if_exists? func_proc_name_schema (COMMA func_proc_name_schema)* SEMI? + | DROP FUNCTION if_exists? func_proc_name_schema (( LR_BRACKET drop_procedure_param (COMMA drop_procedure_param)* RR_BRACKET ) | LR_BRACKET RR_BRACKET ) SEMI? +; + +// https://msdn.microsoft.com/en-us/library/ms175075.aspx +drop_statistics + : DROP STATISTICS full_object_name (COMMA full_object_name)* SEMI? + ; + +// https://msdn.microsoft.com/en-us/library/ms173790.aspx +drop_table + : DROP TABLE if_exists? table_name (COMMA table_name)* SEMI? + ; + +// https://msdn.microsoft.com/en-us/library/ms173492.aspx +drop_view + : DROP VIEW if_exists? simple_name (COMMA simple_name)* SEMI? + ; + +create_type + : CREATE TYPE name = simple_name + (FROM data_type null_notnull? default_value=expression?)? + (AS TABLE LR_BRACKET column_def_table_constraints RR_BRACKET table_options? )? + ; + +drop_type: + DROP TYPE if_exists? simple_name + ; + +rowset_function + : open_xml + | open_json + | open_query + | open_datasource + | open_rowset + | change_table + | predict_function + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/functions/openxml-transact-sql +open_xml + : OPENXML LR_BRACKET expression COMMA expression (COMMA expression)? RR_BRACKET + (WITH ( table_name | LR_BRACKET schema_declaration RR_BRACKET) )? + ; + +schema_declaration + : xml_col+=column_declaration (COMMA xml_col+=column_declaration)* + ; + +open_json + : OPENJSON LR_BRACKET expression (COMMA expression)? RR_BRACKET + (WITH LR_BRACKET json_declaration RR_BRACKET )? + ; + +json_declaration + : json_col+=json_column_declaration (COMMA json_col+=json_column_declaration)* + ; + +json_column_declaration + : column_declaration (AS JSON)? + ; + +// https://msdn.microsoft.com/en-us/library/ms188427(v=sql.120).aspx +open_query + : OPENQUERY LR_BRACKET linked_server=id COMMA query=STRING RR_BRACKET + ; + +// https://msdn.microsoft.com/en-us/library/ms179856.aspx +open_datasource + : OPENDATASOURCE LR_BRACKET provider=STRING COMMA init=STRING RR_BRACKET + (DOT id)+ + ; + +// https://msdn.microsoft.com/en-us/library/ms190312.aspx +open_rowset + : OPENROWSET LR_BRACKET provider_name = STRING COMMA connectionString = STRING COMMA sql = STRING RR_BRACKET + | OPENROWSET LR_BRACKET BULK data_file=STRING COMMA (bulk_option (COMMA bulk_option)* | id) RR_BRACKET + ; + +change_table + : CHANGETABLE LR_BRACKET (change_table_changes | change_table_version) RR_BRACKET + ; + +change_table_changes + : CHANGES changetable=table_name COMMA changesid=(NULL_P | DECIMAL | LOCAL_ID) + ; +change_table_version + : VERSION versiontable=table_name COMMA pk_columns=full_column_name_list COMMA pk_values=select_list + ; + +predict_function + : PREDICT LR_BRACKET MODEL EQUAL expression COMMA DATA EQUAL (table_name | function_call) AS table_alias (RUNTIME EQUAL id)? RR_BRACKET + WITH LR_BRACKET column_definition (COMMA column_definition)* RR_BRACKET + ; + +// https://msdn.microsoft.com/en-us/library/ms188927.aspx +declare_statement + : DECLARE LOCAL_ID AS? table_type_definition SEMI? + | DECLARE loc+=declare_local (COMMA loc+=declare_local)* SEMI? + ; + +declare_xmlnamespaces_statement + : WITH XMLNAMESPACES LR_BRACKET xml_dec+=xml_declaration (COMMA xml_dec+=xml_declaration)* RR_BRACKET (select_statement | insert_statement | update_statement | delete_statement | merge_statement )? SEMI? + ; + +xml_declaration + : xml_namespace_uri=STRING AS id + | DEFAULT STRING + ; + +// https://msdn.microsoft.com/en-us/library/ms181441(v=sql.120).aspx +cursor_statement + // https://msdn.microsoft.com/en-us/library/ms175035(v=sql.120).aspx + : CLOSE GLOBAL? cursor_name SEMI? + // https://msdn.microsoft.com/en-us/library/ms188782(v=sql.120).aspx + | DEALLOCATE GLOBAL? CURSOR? cursor_name SEMI? + // https://msdn.microsoft.com/en-us/library/ms180169(v=sql.120).aspx + | declare_cursor + // https://msdn.microsoft.com/en-us/library/ms180152(v=sql.120).aspx + | fetch_cursor + // https://msdn.microsoft.com/en-us/library/ms190500(v=sql.120).aspx + | OPEN GLOBAL? cursor_name SEMI? + ; + +checkpoint_statement + : CHECKPOINT chkptduration=DECIMAL? + ; + +restore_database + : RESTORE DATABASE ( database_name=id | LOCAL_ID ) + (files_or_filegroups (COMMA files_or_filegroups)*)? + FROM (COMMA? backup_device)+ + (WITH restore_options (COMMA? restore_options)* )? + ; + +files_or_filegroups + : READ_WRITE_FILEGROUPS + | (FILE|FILEGROUP) EQUAL (STRING|LOCAL_ID) + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/backup-transact-sql +backup_database + : BACKUP DATABASE ( database_name=id | LOCAL_ID ) + (files_or_filegroups (COMMA files_or_filegroups)*)? + TO (COMMA? backup_device)+ + (MIRROR TO (COMMA? backup_device)+)? + (WITH backup_options (COMMA backup_options)* )? + ; + +backup_log + : BACKUP LOG ( database_name=id | LOCAL_ID ) + (TO (COMMA? backup_device)+)? + (MIRROR TO (COMMA? backup_device)+)? + (WITH backup_options (COMMA backup_options)* )? + ; + +backup_device + : (DISK|TAPE|URL) EQUAL (STRING|LOCAL_ID) + | LOCAL_ID + | id + ; + +backup_options + : backup_option + | backup_restore_option + ; + +restore_options + : restore_option + | backup_restore_option + ; + +backup_option + : DIFFERENTIAL + | COPY_ONLY + | (COMPRESSION|NO_COMPRESSION) + | DESCRIPTION EQUAL (STRING|id|LOCAL_ID) + | NAME EQUAL (id|LOCAL_ID) + | CREDENTIAL + | FILE_SNAPSHOT + | (EXPIREDATE EQUAL (STRING|id|LOCAL_ID) | RETAINDAYS EQUAL (DECIMAL|id|LOCAL_ID) ) + | (NOINIT|INIT) + | (NOSKIP|SKIP_KEYWORD) + | (NOFORMAT|FORMAT) + | RESTART + | ENCRYPTION LR_BRACKET ALGORITHM EQUAL ( AES_128 | AES_192 | AES_256 | TRIPLE_DES_3KEY ) + COMMA (SERVER CERTIFICATE EQUAL encryptor_name=id | SERVER ASYMMETRIC KEY EQUAL encryptor_name=id) + RR_BRACKET + // log backup options: + | (NORECOVERY| STANDBY EQUAL (STRING|LOCAL_ID)) + | NO_TRUNCATE + ; + +restore_option + : (RECOVERY | NORECOVERY | STANDBY) EQUAL (STRING |LOCAL_ID) + | MOVE (STRING|LOCAL_ID) TO (STRING|LOCAL_ID) + | REPLACE + | RESTART + | RESTRICTED_USER + | CREDENTIAL + | FILE EQUAL (STRING|LOCAL_ID) + | PASSWORD EQUAL (STRING|LOCAL_ID) + | KEEP_REPLICATION + | KEEP_CDC + | FILESTREAM LR_BRACKET DIRECTORY_NAME EQUAL (STRING|LOCAL_ID) RR_BRACKET + | ENABLE_BROKER + | ERROR_BROKER_CONVERSATIONS + | NEW_BROKER + | STOPAT EQUAL (STRING|LOCAL_ID) + | STOPATMARK EQUAL (STRING) (AFTER (STRING|LOCAL_ID))? + | STOPBEFOREMARK EQUAL (STRING) (AFTER (STRING|LOCAL_ID))? + ; + +backup_restore_option + : MEDIADESCRIPTION EQUAL (STRING|id|LOCAL_ID) + | MEDIANAME EQUAL (STRING|LOCAL_ID) + | BLOCKSIZE EQUAL (DECIMAL|id|LOCAL_ID) + | BUFFERCOUNT EQUAL (DECIMAL|id|LOCAL_ID) + | MAXTRANSFER EQUAL (DECIMAL|id|LOCAL_ID) + | (NO_CHECKSUM|CHECKSUM) + | (STOP_ON_ERROR|CONTINUE_AFTER_ERROR) + | STATS (EQUAL (DECIMAL|LOCAL_ID))? + | (REWIND|NOREWIND) + | (LOAD|NOUNLOAD) + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/backup-certificate-transact-sql +backup_certificate + : BACKUP CERTIFICATE certname=id TO FILE EQUAL cert_file=STRING + ( WITH PRIVATE KEY + LR_BRACKET + (COMMA? FILE EQUAL private_key_file=STRING + |COMMA? ENCRYPTION BY PASSWORD EQUAL encryption_password=STRING + |COMMA? DECRYPTION BY PASSWORD EQUAL decryption_pasword=STRING + )+ + RR_BRACKET + )? + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/backup-master-key-transact-sql +backup_master_key + : BACKUP MASTER KEY TO FILE EQUAL master_key_backup_file=STRING + ENCRYPTION BY PASSWORD EQUAL encryption_password=STRING + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/statements/backup-service-master-key-transact-sql +backup_service_master_key + : BACKUP SERVICE MASTER KEY TO FILE EQUAL service_master_key_backup_file=STRING + ENCRYPTION BY PASSWORD EQUAL encryption_password=STRING + ; + +kill_statement + : KILL (kill_process | kill_query_notification | kill_stats_job) + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/language-elements/kill-transact-sql +kill_process + : (session_id=(DECIMAL|STRING) | UOW) (WITH STATUSONLY)? + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/language-elements/kill-query-notification-subscription-transact-sql +kill_query_notification + : QUERY NOTIFICATION SUBSCRIPTION (ALL | subscription_id=DECIMAL) + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/language-elements/kill-stats-job-transact-sql +kill_stats_job + : STATS JOB job_id=DECIMAL + ; + +// https://msdn.microsoft.com/en-us/library/ms188332.aspx +execute_statement + : (EXECUTE|EXEC) execute_body SEMI? + ; + +execute_body_batch + : func_proc_name_server_database_schema execute_statement_arg? SEMI? + ; + +execute_body + : (return_status=LOCAL_ID EQUAL)? (func_proc_name_server_database_schema | execute_var_string) execute_statement_arg? (WITH execute_option (COMMA execute_option)* )? + | LR_BRACKET execute_var_string (PLUS execute_var_string)* RR_BRACKET (execute_var_string_option (COMMA execute_var_string_option)* )? + ; + +execute_var_string_option + : AS (LOGIN | USER) EQUAL STRING + | AT_KEYWORD linked_server=id + | AT_KEYWORD DATA_SOURCE id + ; + +execute_statement_arg + : + execute_statement_arg_unnamed (COMMA execute_statement_arg)? //Unnamed params can continue unnamed + | + execute_statement_arg_named (COMMA execute_statement_arg_named)* //Named can only be continued by unnamed + ; + +execute_statement_arg_named + : name=LOCAL_ID EQUAL value=execute_parameter + ; + +execute_statement_arg_unnamed + : value=execute_parameter + ; + +execute_parameter + : constant + | LOCAL_ID (OUTPUT | OUT)? + | id + | DEFAULT + ; + +execute_var_string + : LOCAL_ID + | STRING + ; + +execute_option + : RECOMPILE + | RESULT SETS (NONE |UNDEFINED) + | RESULT SETS LR_BRACKET LR_BRACKET schema_declaration RR_BRACKET RR_BRACKET (AS (OBJECT full_object_name | TYPE full_object_name | FOR XML) )? + ; + +security_statement + : ( execute_as_statement + | revert_statement + | grant_statement + | revoke_statement + | deny_statement + | open_key + | close_key + | create_key + | create_certificate ) SEMI? + ; + +grant_statement + : GRANT (ALL PRIVILEGES? | permissions) (ON permission_object)? TO principals (WITH GRANT OPTION)? (AS principal_id)? + ; + +revoke_statement + : REVOKE (GRANT OPTION FOR)? (ALL PRIVILEGES? | permissions) (ON permission_object)? (TO|FROM) principals CASCADE? (AS principal_id)? + ; + +deny_statement + : DENY (ALL PRIVILEGES? | permissions) (ON permission_object)? TO principals CASCADE? (AS principal_id)? + ; + +permission_object + : (object_type colon_colon)? full_object_name (LR_BRACKET column_name_list RR_BRACKET)? + ; + +principals + : principal_id (COMMA principal_id)* + ; + +permissions + : permission (COMMA permission)* + ; + +permission + : single_permission (LR_BRACKET column_name_list RR_BRACKET)? + ; + +single_permission + : (EXECUTE|EXEC) (ANY EXTERNAL SCRIPT)? + | CREATE ANY? object_type? + | ALTER ANY? object_type? + | SELECT (ALL USER SECURABLES)? + | INSERT + | UPDATE + | DELETE + | REFERENCES + | CONTROL SERVER? + | IMPERSONATE (ANY LOGIN)? + | CHECKPOINT + | CONNECT (REPLICATION | SQL | ANY DATABASE)? + | SEND + | RECEIVE + | VIEW DEFINITION + | TAKE OWNERSHIP + | VIEW ANY? object_type + | AUTHENTICATE SERVER? + | SHOWPLAN + | BACKUP (DATABASE | LOG) + | ADMINISTER DATABASE? BULK OPERATIONS + | EXTERNAL ACCESS ASSEMBLY + | SHUTDOWN + | KILL DATABASE CONNECTION + | SUBSCRIBE QUERY NOTIFICATIONS + | UNMASK + | UNSAFE ASSEMBLY + ; + +object_type + : AGGREGATE + | APPLICATION ROLE + | ASSEMBLY + | ASYMMETRIC KEY + | AVAILABILITY GROUP + | CERTIFICATE + | CHANGE TRACKING + | COLUMN ( ENCRYPTION | MASTER ) KEY DEFINITION? + | CONNECTION + | CONTRACT + | CREDENTIAL + | DATABASE (AUDIT|DDL? EVENT (NOTIFICATION|SESSION)|DDL TRIGGER|SCOPED CONFIGURATION|STATE)? + | DATASPACE + | DDL EVENT NOTIFICATION + | DEFAULT + | ENDPOINT + | EVENT ( NOTIFICATION | SESSION ) + | EXTERNAL (DATA SOURCE | FILE FORMAT | LIBRARY) + | FULLTEXT CATALOG + | FULLTEXT STOPLIST + | FUNCTION + | LINKED SERVER + | LOGIN + | MASK + | MESSAGE TYPE + | OBJECT + | PROCEDURE + | QUEUE + | REMOTE SERVICE BINDING + | RESOURCES + | ROLE + | ROUTE + | RULE + | SCHEMA + | SECURITY POLICY + | SEARCH PROPERTY LIST + | SEQUENCE + | SERVER (AUDIT|ROLE|STATE) + | SERVICE + | SETTINGS + | SYMMETRIC KEY + | SYNONYM + | TABLE + | TRACE (EVENT NOTIFICATION)? + | TYPE + | USER + | VIEW + | XML SCHEMA COLLECTION + ; + +principal_id + : id + | PUBLIC + ; + +create_certificate + : CREATE CERTIFICATE certificate_name=id (AUTHORIZATION user_name=id)? + (FROM existing_keys | generate_new_keys) + (ACTIVE FOR BEGIN DIALOG EQUAL (ON | OFF))? + ; + +existing_keys + : ASSEMBLY assembly_name=id + | EXECUTABLE? FILE EQUAL path_to_file=STRING (WITH PRIVATE KEY LR_BRACKET private_key_options RR_BRACKET )? + ; + +private_key_options + : (FILE | BINARY) EQUAL path=STRING (COMMA (DECRYPTION | ENCRYPTION) BY PASSWORD EQUAL password=STRING)? + ; + +generate_new_keys + : (ENCRYPTION BY PASSWORD EQUAL password=STRING)? + WITH SUBJECT EQUAL certificate_subject_name=STRING (COMMA date_options)* + ; + +date_options + : (START_DATE | EXPIRY_DATE) EQUAL STRING + ; + +open_key + : OPEN SYMMETRIC KEY key_name=id DECRYPTION BY decryption_mechanism + | OPEN MASTER KEY DECRYPTION BY PASSWORD EQUAL password=STRING + ; + +close_key + : CLOSE SYMMETRIC KEY key_name=id + | CLOSE ALL SYMMETRIC KEYS + | CLOSE MASTER KEY + ; + +create_key + : CREATE MASTER KEY ENCRYPTION BY PASSWORD EQUAL password=STRING + | CREATE SYMMETRIC KEY key_name=id + (AUTHORIZATION user_name=id)? + (FROM PROVIDER provider_name=id)? + WITH ((key_options | ENCRYPTION BY encryption_mechanism)COMMA?)+ + ; + +key_options + : KEY_SOURCE EQUAL pass_phrase=STRING + | ALGORITHM EQUAL algorithm + | IDENTITY_VALUE EQUAL identity_phrase=STRING + | PROVIDER_KEY_NAME EQUAL key_name_in_provider=STRING + | CREATION_DISPOSITION EQUAL (CREATE_NEW | OPEN_EXISTING) + ; + +algorithm + : DES + | TRIPLE_DES + | TRIPLE_DES_3KEY + | RC2 + | RC4 + | RC4_128 + | DESX + | AES_128 + | AES_192 + | AES_256 + ; + +encryption_mechanism + : CERTIFICATE certificate_name=id + | ASYMMETRIC KEY asym_key_name=id + | SYMMETRIC KEY decrypting_Key_name=id + | PASSWORD EQUAL STRING + ; + +decryption_mechanism + : CERTIFICATE certificate_name=id (WITH PASSWORD EQUAL STRING)? + | ASYMMETRIC KEY asym_key_name=id (WITH PASSWORD EQUAL STRING)? + | SYMMETRIC KEY decrypting_Key_name=id + | PASSWORD EQUAL STRING + ; + +// https://msdn.microsoft.com/en-us/library/ms190356.aspx +// https://msdn.microsoft.com/en-us/library/ms189484.aspx +set_statement + : SET LOCAL_ID (DOT member_name=id)? EQUAL expression SEMI? + | SET LOCAL_ID assignment_operator expression SEMI? + | SET LOCAL_ID EQUAL + CURSOR declare_cursor_options* FOR select_statement_standalone (FOR (READ ONLY | UPDATE (OF column_name_list)?))? SEMI? + // https://msdn.microsoft.com/en-us/library/ms189837.aspx + | set_special + ; + +// https://msdn.microsoft.com/en-us/library/ms174377.aspx +transaction_statement + // https://msdn.microsoft.com/en-us/library/ms188386.aspx + : BEGIN DISTRIBUTED (TRAN | TRANSACTION) (id | LOCAL_ID)? SEMI? + // https://msdn.microsoft.com/en-us/library/ms188929.aspx + | BEGIN (TRAN | TRANSACTION) ((id | LOCAL_ID) (WITH MARK STRING)?)? SEMI? + // https://msdn.microsoft.com/en-us/library/ms190295.aspx + | COMMIT (TRAN | TRANSACTION) ((id | LOCAL_ID) (WITH LR_BRACKET DELAYED_DURABILITY EQUAL (OFF | ON) RR_BRACKET )?)? SEMI? + // https://msdn.microsoft.com/en-us/library/ms178628.aspx + | COMMIT WORK? SEMI? + | COMMIT id + | ROLLBACK id + // https://msdn.microsoft.com/en-us/library/ms181299.aspx + | ROLLBACK (TRAN | TRANSACTION) (id | LOCAL_ID)? SEMI? + // https://msdn.microsoft.com/en-us/library/ms174973.aspx + | ROLLBACK WORK? SEMI? + // https://msdn.microsoft.com/en-us/library/ms188378.aspx + | SAVE (TRAN | TRANSACTION) (id | LOCAL_ID)? SEMI? + ; + +// https://msdn.microsoft.com/en-us/library/ms188366.aspx +use_statement + : USE dbname=id SEMI? + ; + +setuser_statement + : SETUSER user=STRING? + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/language-elements/reconfigure-transact-sql +reconfigure_statement + : RECONFIGURE (WITH OVERRIDE)? + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/language-elements/shutdown-transact-sql +shutdown_statement + : SHUTDOWN (WITH NOWAIT)? + ; + +dbcc_statement + : 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 + ; + +dbcc_options + : ID (COMMA ID)? + ; + +execute_as_clause + : (EXECUTE|EXEC) AS clause=(CALLER | SELF | OWNER | STRING) + ; + +execute_as_statement + : (EXECUTE|EXEC) AS ( CALLER | ( LOGIN | USER ) EQUAL STRING (WITH (NO REVERT | COOKIE INTO LOCAL_ID ))? ) + ; + +revert_statement + : REVERT (LR_BRACKET WITH COOKIE EQUAL LOCAL_ID RR_BRACKET)? + ; + +declare_local + : LOCAL_ID AS? data_type ( EQUAL expression)? + ; + +table_type_definition + : TABLE LR_BRACKET column_def_table_constraints (COMMA? table_type_indices)* RR_BRACKET + ; + +table_type_indices + : (((PRIMARY KEY | INDEX id) (CLUSTERED | NONCLUSTERED)?) | UNIQUE) LR_BRACKET column_name_list_with_order RR_BRACKET + | CHECK LR_BRACKET search_condition RR_BRACKET + ; + +xml_type_definition + : id LR_BRACKET ( CONTENT | DOCUMENT )? xml_schema_collection RR_BRACKET + ; + +xml_schema_collection + : id (DOT id)? + ; + +column_def_table_constraints + : column_def_table_constraint (COMMA? column_def_table_constraint)* + ; + +column_def_table_constraint + : column_definition + | materialized_column_definition + | table_constraint + | period_for_system_time + ; + +// https://msdn.microsoft.com/en-us/library/ms187742.aspx +// emprically found: ROWGUIDCOL can be in various locations +column_definition + : simple_column_name (data_type system_versioning_column? | AS expression PERSISTED? ) ( special_column_option | (COLLATE id) | null_notnull )* + ( column_constraint? IDENTITY (LR_BRACKET sign? seed=DECIMAL COMMA sign? increment=DECIMAL RR_BRACKET)? )? for_replication? ROWGUIDCOL? + column_constraint* column_inline_index? + ; + +// 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* column_inline_index? + ; + +column_inline_index + : INDEX id (CLUSTERED | NONCLUSTERED)? + (WHERE where=search_condition)? + with_index_options? + (ON storage_partition_clause)? + (FILESTREAM_ON storage_partition_clause)? + ; + +materialized_column_definition + : id (COMPUTE | AS) expression (MATERIALIZED | NOT MATERIALIZED)? + ; + +special_column_option + : FILESTREAM + | SPARSE + | ROWGUIDCOL + | HIDDEN_RENAMED + | PERSISTED + | MASKED ( WITH LR_BRACKET FUNCTION EQUAL STRING RR_BRACKET )? + | for_replication + ; + +system_versioning_column + : GENERATED ALWAYS AS (ROW|TRANSACTION_ID|SEQUENCE_NUMBER) (START|END) HIDDEN_RENAMED? + ; + +period_for_system_time + : PERIOD FOR SYSTEM_TIME LR_BRACKET id COMMA id RR_BRACKET + ; + +system_versioning_options + : LR_BRACKET system_versioning_option (COMMA system_versioning_option)* RR_BRACKET + ; + +system_versioning_option + : SYSTEM_VERSIONING EQUAL on_off + | LEDGER EQUAL on_off sub_options? + | DATA_CONSISTENCY_CHECK EQUAL on_off + | HISTORY_RETENTION_PERIOD EQUAL ( INFINITE | DECIMAL (DAY|DAYS|WEEK|WEEKS|MONTH|MONTHS|YEAR|YEARS) ) + ; + +history_table_option + : HISTORY_TABLE EQUAL table_name + | LR_BRACKET history_table_option RR_BRACKET + ; + +for_system_time + : FOR SYSTEM_TIME for_system_time_range + ; + +for_system_time_range + : ALL + | AS OF (STRING|LOCAL_ID) + | BETWEEN (STRING|LOCAL_ID) AND (STRING|LOCAL_ID) + | CONTAINED IN LR_BRACKET (STRING|LOCAL_ID) COMMA (STRING|LOCAL_ID) RR_BRACKET + | FROM (STRING|LOCAL_ID) TO (STRING|LOCAL_ID) + ; + +for_replication + : (NOT? FOR REPLICATION) + ; + +// https://msdn.microsoft.com/en-us/library/ms186712.aspx +column_constraint + :(CONSTRAINT constraint=id)? + ((PRIMARY KEY | UNIQUE) clustered? with_index_options? + | CHECK for_replication? LR_BRACKET search_condition RR_BRACKET + | (FOREIGN KEY)? REFERENCES table_name (LR_BRACKET pk = column_name_list RR_BRACKET)? (on_update | on_delete)* + | DEFAULT expression + | null_notnull + | WITH VALUES + | CONNECTION LR_BRACKET table_name TO table_name (COMMA table_name TO table_name)* RR_BRACKET + ) + ; + +// https://msdn.microsoft.com/en-us/library/ms188066.aspx +table_constraint + : (CONSTRAINT constraint=id)? + ((PRIMARY KEY | UNIQUE) clustered? LR_BRACKET column_name_list_with_order RR_BRACKET with_index_options? (ON storage_partition_clause)? + | CHECK for_replication? LR_BRACKET search_condition RR_BRACKET + | DEFAULT expression (FOR id)? // (COLLATE id)? (WITH VALUES)? + | FOREIGN KEY LR_BRACKET fk = column_name_list RR_BRACKET REFERENCES table_name (LR_BRACKET pk = column_name_list RR_BRACKET)? (on_update | on_delete)* ) for_replication? + ; + +on_update + : ON UPDATE (NO ACTION | CASCADE | SET NULL_P | SET DEFAULT) + ; + +on_delete + : ON DELETE (NO ACTION | CASCADE | SET NULL_P | SET DEFAULT) + ; + +with_index_options + : WITH index_option_list + | WITH LR_BRACKET index_option_list RR_BRACKET + ; + +index_option_list + : index_option (COMMA index_option)* + ; + +// https://msdn.microsoft.com/en-us/library/ms186869.aspx +// Id runtime checking. Id in (PAD_INDEX, FILLFACTOR, IGNORE_DUP_KEY, STATISTICS_NORECOMPUTE, ALLOW_ROW_LOCKS, +// ALLOW_PAGE_LOCKS, SORT_IN_TEMPDB, ONLINE, MAXDOP, DATA_COMPRESSION, ONLINE). +index_option + : (id | keyword) (EQUAL (id | keyword | on_off | DECIMAL))? sub_options? + ; + +sub_options + : LR_BRACKET sub_option (sub_options? | (COMMA sub_option)*) RR_BRACKET + ; + +sub_option + : (id|keyword) EQUAL expression keyword? // keyword is for cases like 'RETENTION_PERIOD = 1 WEEKS' + ; + +// https://msdn.microsoft.com/en-us/library/ms180169.aspx +declare_cursor + : DECLARE cursor_name INSENSITIVE? SCROLL? CURSOR declare_cursor_options* + FOR select_statement_standalone (FOR (READ ONLY | UPDATE (OF full_column_name_list)?))? + ; + +declare_cursor_options + : (LOCAL | GLOBAL) + | (FORWARD_ONLY | SCROLL) + | (STATIC | KEYSET | DYNAMIC | FAST_FORWARD) + | (READ_ONLY | SCROLL_LOCKS | OPTIMISTIC) + | TYPE_WARNING + ; + +fetch_cursor + : FETCH ((NEXT | PRIOR | FIRST | LAST | (ABSOLUTE | RELATIVE) expression)? FROM)? + GLOBAL? cursor_name (INTO LOCAL_ID (COMMA LOCAL_ID)*)? SEMI? + ; + +// https://msdn.microsoft.com/en-us/library/ms190356.aspx +// Runtime check. +set_special + : SET set_on_off_option (COMMA set_on_off_option)* on_off + | SET id (id | constant_LOCAL_ID | on_off) SEMI? + | SET STATISTICS (IO | TIME | XML | PROFILE) on_off SEMI? + | SET ROWCOUNT (LOCAL_ID | DECIMAL) SEMI? + // https://msdn.microsoft.com/en-us/library/ms173763.aspx + | SET (TRAN | TRANSACTION) ISOLATION LEVEL (READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SNAPSHOT | SERIALIZABLE | DECIMAL) SEMI? + // https://msdn.microsoft.com/en-us/library/ms188059.aspx + | SET IDENTITY_INSERT table_name on_off SEMI? + | SET TEXTSIZE DECIMAL SEMI? + | SET xml_modify_method + ; + +set_on_off_option + : ANSI_DEFAULTS + | ANSI_NULLS + | ANSI_NULL_DFLT_OFF + | ANSI_NULL_DFLT_ON + | ANSI_PADDING + | ANSI_WARNINGS + | ARITHABORT + | ARITHIGNORE + | AUTOCOMMIT + | CONCAT_NULL_YIELDS_NULL + | CURSOR_CLOSE_ON_COMMIT + | FIPS_FLAGGER + | FMTONLY + | FORCEPLAN + | IMPLICIT_TRANSACTIONS + | NOCOUNT + | NOEXEC + | NUMERIC_ROUNDABORT + | OFFSETS set_offsets_keyword (COMMA set_offsets_keyword)* + | PARSEONLY + | QUOTED_IDENTIFIER + | REMOTE_PROC_TRANSACTIONS + | SHOWPLAN_ALL + | SHOWPLAN_TEXT + | SHOWPLAN_XML + | STATISTICS set_statistics_keyword (COMMA set_statistics_keyword)* + | XACT_ABORT + ; + +set_statistics_keyword + : IO + | PROFILE + | TIME + | XML + ; + +set_offsets_keyword + : SELECT + | FROM + | ORDER + | TABLE + | PROCEDURE + | STATEMENT + | PARAM + | (EXECUTE|EXEC) + ; + +constant_LOCAL_ID + : constant + | LOCAL_ID + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/language-elements/expressions-transact-sql +// Operator precendence: https://docs.microsoft.com/en-us/sql/t-sql/language-elements/operator-precedence-transact-sql +expression + : local_id (DOT calls+=method_call)* + | subquery (DOT calls+=method_call)* + | bracket_expression (DOT calls+=method_call)* + | function_call (DOT calls+=method_call)* + | expression COLLATE id + | expression time_zone + | unary_operator_expression + | expression op=(STAR | DIVIDE | PERCENT_SIGN ) expression + | expression op=(PLUS | MINUS | BIT_AND | BIT_XOR | BIT_OR ) expression + | full_column_name +// | primitive_expression + | constant + | DEFAULT + | case_expression + | hierarchyid_coloncolon_methods + | over_clause + | odbc_literal + | DOLLAR_ACTION + ; + +method_call + : xml_methods + | hierarchyid_methods + | spatial_methods + ; + +time_zone + : AT_KEYWORD TIME ZONE expression + ; + +//primitive_expression +// : DEFAULT | constant +// ; + +// https://docs.microsoft.com/en-us/sql/t-sql/language-elements/case-transact-sql +case_expression + : CASE caseExpr=expression switch_section+ (ELSE elseExpr=expression)? END + | CASE switch_search_condition_section+ (ELSE elseExpr=expression)? END + ; + +unary_operator_expression + : BIT_NOT expression + | op=(PLUS | MINUS) expression + ; + +bracket_expression + : LR_BRACKET expression RR_BRACKET + ; + +constant_expression + : constant + | LOCAL_ID + | LR_BRACKET constant_expression RR_BRACKET + ; + +subquery + : LR_BRACKET select_statement RR_BRACKET + ; + +// https://msdn.microsoft.com/en-us/library/ms175972.aspx +with_expression + : WITH ctes+=common_table_expression (COMMA ctes+=common_table_expression)* + ; + +common_table_expression + : expression_name=id ( LR_BRACKET columns=column_name_list RR_BRACKET )? AS LR_BRACKET cte_query=select_statement RR_BRACKET + ; + +update_elem + : LOCAL_ID EQUAL full_column_name ( EQUAL | assignment_operator) expression //Combined variable and column update + | (full_column_name | LOCAL_ID) ( EQUAL | assignment_operator) expression + | udt_column_name=id DOT method_name=id LR_BRACKET expression_list RR_BRACKET + //| full_column_name DOT WRITE (expression, ) + ; + +update_elem_merge + : (full_column_name | LOCAL_ID) ( EQUAL | assignment_operator) expression + | udt_column_name=id DOT method_name=id LR_BRACKET expression_list RR_BRACKET + //| full_column_name DOT WRITE (expression, ) + ; + +search_condition + : pred+=predicate_br (log=(OR | AND) pred+=predicate_br)* + ; + +predicate_br + : NOT* predicate + | NOT* LR_BRACKET search_condition RR_BRACKET + ; + +predicate + : EXISTS subquery + | freetext_predicate + | expression comparison_operator expression + | expression comparison_operator (ALL | SOME | ANY) subquery + | expression NOT? IN subquery + | expression NOT? BETWEEN expression AND expression + | expression NOT? IN LR_BRACKET expression_list RR_BRACKET + | expression NOT? LIKE expression (ESCAPE expression)? + | expression IS null_notnull + | trigger_column_updated + ; + +query_expression + : (query_specification order_by_clause? | LR_BRACKET query_expression order_by_clause? RR_BRACKET ) sql_union* + ; + +// this accepts ORDER BY also when it is not in the last part of the UNION +sql_union + : union_keyword (query_specification order_by_clause? | LR_BRACKET query_expression order_by_clause? RR_BRACKET ) + ; + +union_keyword + : (UNION ALL? | EXCEPT | INTERSECT) + ; + +query_specification + : SELECT allOrDistinct=(ALL | DISTINCT)? top=top_clause? + columns=select_list + // https://msdn.microsoft.com/en-us/library/ms188029.aspx + (INTO into=table_name)? + (FROM from=table_sources)? + (WHERE where=search_condition)? + // https://msdn.microsoft.com/en-us/library/ms177673.aspx + (GROUP BY groupByAll=ALL? group_by_item (COMMA group_by_item)* with_rollup_cube? )? + (HAVING having=search_condition)? + ; + +// https://msdn.microsoft.com/en-us/library/ms189463.aspx +top_clause + : TOP (top_percent | top_count) (WITH TIES)? + ; + +top_percent + : percent_constant=(REAL | FLOAT | DECIMAL) PERCENT + | LR_BRACKET topper_expression=expression RR_BRACKET PERCENT + ; + +top_count + : count_constant=DECIMAL + | LR_BRACKET topcount_expression=expression RR_BRACKET + | subquery + ; + +// https://msdn.microsoft.com/en-us/library/ms188385.aspx +order_by_clause + : ORDER BY order_bys+=order_by_expression (COMMA order_bys+=order_by_expression)* + (OFFSET offset_exp=expression offset_rows=(ROW | ROWS) (FETCH fetch_offset=(FIRST | NEXT) fetch_exp=expression fetch_rows=(ROW | ROWS) ONLY)?)? + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/queries/select-for-clause-transact-sql +for_clause + : FOR BROWSE + | FOR XML (RAW ( LR_BRACKET STRING RR_BRACKET )? | AUTO) + ( xml_common_directives | (COMMA (XMLDATA | XMLSCHEMA ( LR_BRACKET STRING RR_BRACKET )?)) | (COMMA ELEMENTS (XSINIL | ABSENT)?) )* + | FOR XML EXPLICIT ( xml_common_directives | COMMA XMLDATA)* + | FOR XML PATH ( LR_BRACKET STRING RR_BRACKET )? (xml_common_directives | COMMA ELEMENTS (XSINIL | ABSENT)?)* + + | FOR JSON (AUTO | PATH) + ( (COMMA ROOT ( LR_BRACKET STRING RR_BRACKET )?) + | (COMMA INCLUDE_NULL_VALUES) + | (COMMA WITHOUT_ARRAY_WRAPPER) + )* + ; + +xml_common_directives + : COMMA (BINARY_KEYWORD BASE64 | TYPE | ROOT ( LR_BRACKET STRING RR_BRACKET )?) + ; + +order_by_expression + : order_by=expression (ascending=ASC | descending=DESC)? + ; + +group_by_item + : expression + | full_column_name with_distributed_agg + | group_rollup_spec + | group_cube_spec + | grouping_sets_spec + | group_grand_total_spec + ; + +group_rollup_spec + : ROLLUP LR_BRACKET expression_list RR_BRACKET + ; + +group_cube_spec + : CUBE LR_BRACKET expression_list RR_BRACKET + ; + +grouping_sets_spec + : GROUPING SETS LR_BRACKET grouping_set_expression_list RR_BRACKET + ; + +grouping_set_expression_list + : LR_BRACKET grouping_set_expression_list RR_BRACKET (COMMA grouping_set_expression)* + | grouping_set_expression (COMMA grouping_set_expression)* + ; + +grouping_set_expression + : expression + | group_rollup_spec + | group_cube_spec + | group_grand_total_spec + ; + +group_grand_total_spec + : LR_BRACKET RR_BRACKET + ; + +with_rollup_cube + : WITH (CUBE | ROLLUP) + ; + +with_distributed_agg + : WITH LR_BRACKET DISTRIBUTED_AGG RR_BRACKET + ; + +option_clause + // https://msdn.microsoft.com/en-us/library/ms181714.aspx + : OPTION LR_BRACKET options+=option (COMMA options+=option)* RR_BRACKET + ; + +// these are query hints: +option + : ( HASH | ORDER ) GROUP + | ( MERGE | HASH | CONCAT ) UNION + | ( LOOP | MERGE | HASH ) JOIN + | ( FORCE | DISABLE ) EXTERNALPUSHDOWN + | ( FORCE | DISABLE ) SCALEOUTEXECUTION + | ( KEEP | KEEPFIXED ) PLAN + | EXPAND VIEWS + | FAST number_rows=DECIMAL + | FORCE ORDER + | IGNORE_NONCLUSTERED_COLUMNSTORE_INDEX + | MAX_GRANT_PERCENT EQUAL expression + | MIN_GRANT_PERCENT EQUAL expression + | MAXDOP number_of_processors=DECIMAL + | MAXRECURSION number_recursion=DECIMAL + | NO_PERFORMANCE_SPOOL + | OPTIMIZE FOR LR_BRACKET optimize_for_arg (COMMA optimize_for_arg)* RR_BRACKET + | OPTIMIZE FOR UNKNOWN + | PARAMETERIZATION (SIMPLE | FORCED) + | QUERYTRACEON traceflag=DECIMAL + | RECOMPILE + | ROBUST PLAN + | TABLE HINT LR_BRACKET table_name COMMA table_hint (COMMA table_hint)* RR_BRACKET + | USE PLAN STRING + | USE HINT LR_BRACKET STRING (COMMA STRING)* RR_BRACKET + ; + +optimize_for_arg + : LOCAL_ID (UNKNOWN | EQUAL constant) + ; + +// https://msdn.microsoft.com/en-us/library/ms176104.aspx +select_list + : selectElement+=select_list_elem (COMMA selectElement+=select_list_elem)* + ; + +// https://docs.microsoft.com/ru-ru/sql/t-sql/queries/select-clause-transact-sql +asterisk + : (table_name DOT)? STAR + ; + +column_elem + : (full_column_name | DOLLAR_IDENTITY | DOLLAR_ROWGUID | NULL_P) as_column_alias? + ; + +expression_elem + : leftAlias=column_alias eq= EQUAL leftAssignment=expression + | expressionAs=expression as_column_alias? + ; + +select_list_elem + : asterisk + | column_elem + | LOCAL_ID (assignment_operator | EQUAL ) expression + | expression_elem + ; + +table_sources + : table_source_item (COMMA table_source_item)* + ; + +table_source_item + : table_source_item (INNER join_hint?)? JOIN table_source_item ON search_condition + | table_source_item (LEFT|RIGHT|FULL) OUTER? join_hint? JOIN table_source_item ON search_condition + | table_source_item CROSS JOIN table_source_item + | table_source_item (CROSS|OUTER) APPLY table_source_item + | table_source_item PIVOT pivot_clause as_table_alias? + | table_source_item UNPIVOT unpivot_clause as_table_alias? + | table_source_item for_system_time as_table_alias? + | full_object_name (as_table_alias|with_table_hints)* + | local_id (as_table_alias|with_table_hints)* + | derived_table (as_table_alias column_alias_list?)? + | subquery as_table_alias? + | rowset_function as_table_alias? + | xml_nodes_method (as_table_alias column_alias_list?)? + | (LOCAL_ID DOT)? function_call (as_table_alias column_alias_list?)? + | LR_BRACKET table_source_item RR_BRACKET + | colon_colon function_call as_table_alias? // Built-in function (old syntax) + ; + +join_hint + : LOOP + | HASH + | MERGE + | REMOTE + | REDUCE + | REDISTRIBUTE + | REPLICATE + ; + +pivot_clause + : LR_BRACKET aggregate_windowed_function FOR full_column_name IN column_alias_list RR_BRACKET + ; + +unpivot_clause + : LR_BRACKET unpivot_exp=expression FOR full_column_name IN LR_BRACKET full_column_name_list RR_BRACKET RR_BRACKET + ; + +column_declaration + : id data_type (COLLATE id)? STRING? + ; + +full_column_name_list + : column+=full_column_name (COMMA column+=full_column_name)* + ; + +table_name_with_hint + : table_name with_table_hints? + ; + +// runtime check. +bulk_option + : id EQUAL bulk_option_value=(DECIMAL | STRING) + ; + +derived_table + : select_statement + | subquery + | table_value_constructor + | LR_BRACKET table_value_constructor RR_BRACKET + | LR_BRACKET derived_table RR_BRACKET + ; + +function_call + : ranking_windowed_function #RANKING_WINDOWED_FUNC + | aggregate_windowed_function #AGGREGATE_WINDOWED_FUNC + | analytic_windowed_function #ANALYTIC_WINDOWED_FUNC + | func_proc_name_server_database_schema LR_BRACKET function_arg_list? RR_BRACKET #SCALAR_FUNCTION + | built_in_functions #BUILT_IN_FUNC + | freetext_function #FREE_TEXT + | NEXT VALUE FOR full_object_name #nextvaluefor + | L_CURLY FN odbc_scalar_function R_CURLY #odbcscalar + | partition_function_call #ptn_function + ; + +partition_function_call + : (db_name=id DOT)? DOLLAR_PARTITION DOT func_name=id LR_BRACKET function_arg_list RR_BRACKET + ; + +freetext_function + : (CONTAINSTABLE | FREETEXTTABLE) LR_BRACKET table_name COMMA (full_column_name | LR_BRACKET full_column_name (COMMA full_column_name)* RR_BRACKET | STAR ) COMMA expression (COMMA LANGUAGE expression)? (COMMA expression)? RR_BRACKET + | (SEMANTICSIMILARITYTABLE | SEMANTICKEYPHRASETABLE) LR_BRACKET table_name COMMA (full_column_name | LR_BRACKET full_column_name (COMMA full_column_name)* RR_BRACKET | STAR ) COMMA expression RR_BRACKET + | SEMANTICSIMILARITYDETAILSTABLE LR_BRACKET table_name COMMA full_column_name COMMA expression COMMA full_column_name COMMA expression RR_BRACKET + ; + +freetext_predicate + : CONTAINS LR_BRACKET (full_column_name | LR_BRACKET full_column_name (COMMA full_column_name)* RR_BRACKET | 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 | STAR ) COMMA expression (COMMA LANGUAGE expression)? RR_BRACKET + ; + +// these are functions with a different call syntax than regular functions; +built_in_functions + : bif_cast_parse + | bif_convert + | bif_other + | bif_no_brackets=( + CURRENT_TIMESTAMP + // https://msdn.microsoft.com/en-us/library/ms176050.aspx + | CURRENT_USER + // https://msdn.microsoft.com/en-us/library/ms177587.aspx + | SESSION_USER + // https://msdn.microsoft.com/en-us/library/ms179930.aspx + | SYSTEM_USER + | USER + ) + ; + +bif_cast_parse + : bif=(CAST | TRY_CAST | PARSE | TRY_PARSE) LR_BRACKET expression AS data_type RR_BRACKET + ; + +bif_convert + : bif=(CONVERT | TRY_CONVERT) LR_BRACKET convert_data_type=data_type COMMA convert_expression=expression (COMMA style=expression)? RR_BRACKET + ; + +bif_other + // https://docs.microsoft.com/en-us/sql/t-sql/functions/logical-functions-iif-transact-sql + : IIF LR_BRACKET cond=search_condition COMMA left=expression COMMA right=expression RR_BRACKET # IIF + | TRIM LR_BRACKET (expression trim_from)? expression RR_BRACKET #TRIM + | STRING_AGG LR_BRACKET expr=expression COMMA separator=expression RR_BRACKET (WITHIN GROUP LR_BRACKET order_by_clause RR_BRACKET )? #STRING_AGG + ; + +// ODBC scalar functions/literals are called 'escape sequences' in the docs +odbc_scalar_function + : CONVERT LR_BRACKET expression COMMA data_type RR_BRACKET + | EXTRACT LR_BRACKET (YEAR | MONTH | DAY | HOUR | MINUTE | SECOND) FROM expression RR_BRACKET + | INSERT LR_BRACKET expression (COMMA expression)+ RR_BRACKET + | POSITION LR_BRACKET expression IN expression RR_BRACKET + | TRUNCATE LR_BRACKET (COMMA expression)+ RR_BRACKET + | id (LR_BRACKET (COMMA? expression)* RR_BRACKET)? + ; + +odbc_literal + : L_CURLY ( D | T | TS | GUID) STRING R_CURLY + | L_CURLY INTERVAL sign? STRING id (LR_BRACKET expression RR_BRACKET)? (TO id (LR_BRACKET expression RR_BRACKET)?)? R_CURLY // {INTERVAL '163' HOUR(3)}, {INTERVAL '163 12' DAY(3) TO HOUR} + ; + +trigger_column_updated + : UPDATE LR_BRACKET full_column_name RR_BRACKET + ; + +spatial_methods // we could expand the entire list here, but it is very long + : ( id ) LR_BRACKET expression_list? RR_BRACKET + | NULL_P // no bracket + ; + +hierarchyid_methods + : ( GETANCESTOR | GETDESCENDANT | GETLEVEL | ISDESCENDANTOF | PARSE | READ | GETREPARENTEDVALUE | TOSTRING ) LR_BRACKET expression_list? RR_BRACKET + ; + +hierarchyid_coloncolon_methods + : id colon_colon ( GETROOT | PARSE ) LR_BRACKET RR_BRACKET + ; + +xml_data_type_methods + : xml_value_method + | xml_query_method + | xml_exist_method + | xml_modify_method + ; + +xml_methods + : xml_value_call + | xml_query_call + | xml_exist_call + | xml_modify_call + ; + +xml_value_method + : (loc_id=LOCAL_ID | value_id=id | eventdata=EVENTDATA | query=xml_query_method | subquery) DOT call=xml_value_call + ; + +xml_value_call + : VALUE LR_BRACKET xquery=STRING COMMA sqltype=STRING RR_BRACKET + ; + +xml_query_method + : (loc_id=LOCAL_ID | value_id=id | table=full_object_name | subquery) DOT call=xml_query_call + ; + +xml_query_call + : QUERY LR_BRACKET xquery=STRING RR_BRACKET + ; + +xml_exist_method + : (loc_id=LOCAL_ID | value_id=id | subquery) DOT call=xml_exist_call + ; + +xml_exist_call + : EXIST LR_BRACKET xquery=STRING RR_BRACKET + ; + +xml_modify_method + : (loc_id=LOCAL_ID | value_id=id | subquery) DOT call=xml_modify_call + ; + +xml_modify_call + : MODIFY LR_BRACKET xml_dml=STRING RR_BRACKET + ; + +xml_nodes_method + : (loc_id=LOCAL_ID | value_id=id | subquery) DOT NODES LR_BRACKET xquery=STRING RR_BRACKET + ; + +switch_section + : WHEN expression THEN expression + ; + +switch_search_condition_section + : WHEN search_condition THEN expression + ; + +as_column_alias + : AS? column_alias + ; + +as_table_alias + : AS? table_alias + ; + +table_alias + : id with_table_hints? + ; + +// https://msdn.microsoft.com/en-us/library/ms187373.aspx +with_table_hints + : LR_BRACKET hint+=table_hint RR_BRACKET // without WITH, one hint can be specified + | WITH LR_BRACKET hint+=table_hint (COMMA? hint+=table_hint)* RR_BRACKET + | sample_clause + ; + +sample_clause + : TABLESAMPLE SYSTEM? LR_BRACKET expression (PERCENT|ROWS) RR_BRACKET (REPEATABLE LR_BRACKET PLUS? DECIMAL RR_BRACKET)? + ; + +// Id runtime check. Id can be (FORCESCAN, HOLDLOCK, NOLOCK, NOWAIT, PAGLOCK, READCOMMITTED, +// READCOMMITTEDLOCK, READPAST, READUNCOMMITTED, REPEATABLEREAD, ROWLOCK, TABLOCK, TABLOCKX +// UPDLOCK, XLOCK) +table_hint + : NOEXPAND? ( INDEX (LR_BRACKET index_value (COMMA index_value)* RR_BRACKET | index_value (COMMA index_value)*) ) + | INDEX EQUAL index_value + | NOEXPAND + | FORCESEEK ( LR_BRACKET index_value LR_BRACKET ID (COMMA ID)* RR_BRACKET RR_BRACKET )? + | SERIALIZABLE + | SNAPSHOT + | SPATIAL_WINDOW_MAX_CELLS EQUAL DECIMAL + | NOWAIT + | HOLDLOCK + | ID + ; + +index_value + : id | DECIMAL + ; + +column_alias_list + : LR_BRACKET alias+=column_alias (COMMA alias+=column_alias)* RR_BRACKET + ; + +column_alias + : id + | STRING + ; + +table_value_constructor + : VALUES LR_BRACKET exps+=expression_list RR_BRACKET (COMMA LR_BRACKET exps+=expression_list RR_BRACKET )* + ; + +function_arg_list + : ( STAR | expression ) (COMMA exp+=expression)* + ; + +expression_list + : exp+=expression (COMMA exp+=expression)* + ; + +// https://msdn.microsoft.com/en-us/library/ms189798.aspx +ranking_windowed_function + : agg_func=(RANK | DENSE_RANK | ROW_NUMBER) LR_BRACKET RR_BRACKET over_clause + | NTILE LR_BRACKET expression RR_BRACKET over_clause + ; + +// https://msdn.microsoft.com/en-us/library/ms173454.aspx +aggregate_windowed_function + : agg_func=(AVG | MAX | MIN | SUM | STDEV | STDEVP | VAR | VARP) LR_BRACKET all_distinct_expression RR_BRACKET over_clause? + | cnt=(COUNT | COUNT_BIG) LR_BRACKET ( STAR | all_distinct_expression) RR_BRACKET over_clause? + | CHECKSUM_AGG LR_BRACKET all_distinct_expression RR_BRACKET + | GROUPING LR_BRACKET expression RR_BRACKET + | GROUPING_ID LR_BRACKET expression_list RR_BRACKET + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/functions/analytic-functions-transact-sql +analytic_windowed_function + : first_last=(FIRST_VALUE | LAST_VALUE) LR_BRACKET expression RR_BRACKET over_clause + | lag_lead=(LAG | LEAD) LR_BRACKET expression (COMMA expression (COMMA expression)? )? RR_BRACKET over_clause + | rank=(CUME_DIST | PERCENT_RANK) LR_BRACKET RR_BRACKET OVER LR_BRACKET (PARTITION BY expression_list)? order_by_clause RR_BRACKET + | pct=(PERCENTILE_CONT | PERCENTILE_DISC) LR_BRACKET expression RR_BRACKET WITHIN GROUP LR_BRACKET ORDER BY expression (ASC | DESC)? RR_BRACKET over_clause + ; + +all_distinct_expression + : (ALL | DISTINCT)? expression + ; + +// https://msdn.microsoft.com/en-us/library/ms189461.aspx +over_clause + : OVER LR_BRACKET (PARTITION BY expression_list)? order_by_clause? row_or_range_clause? RR_BRACKET + ; + +row_or_range_clause + : (ROWS | RANGE) window_frame_extent + ; + +window_frame_extent + : window_frame_preceding + | BETWEEN window_frame_bound AND window_frame_bound + ; + +window_frame_bound + : window_frame_preceding + | window_frame_following + ; + +window_frame_preceding + : UNBOUNDED PRECEDING + | DECIMAL PRECEDING + | CURRENT ROW + ; + +window_frame_following + : UNBOUNDED FOLLOWING + | DECIMAL FOLLOWING + ; + +create_database_option + : FILESTREAM ( database_filestream_option (COMMA database_filestream_option)* ) + | DEFAULT_LANGUAGE EQUAL ( id | STRING | DECIMAL ) + | DEFAULT_FULLTEXT_LANGUAGE EQUAL ( id | STRING | DECIMAL ) + | NESTED_TRIGGERS EQUAL ( OFF | ON ) + | TRANSFORM_NOISE_WORDS EQUAL ( OFF | ON ) + | TWO_DIGIT_YEAR_CUTOFF EQUAL DECIMAL + | DB_CHAINING ( OFF | ON ) + | TRUSTWORTHY ( OFF | ON ) + | CATALOG_COLLATION EQUAL id + | PERSISTENT_LOG_BUFFER EQUAL ON LR_BRACKET DIRECTORY_NAME EQUAL STRING RR_BRACKET + ; + +database_filestream_option + : LR_BRACKET + ( + ( NON_TRANSACTED_ACCESS EQUAL ( OFF | READ_ONLY | FULL ) ) + | + ( DIRECTORY_NAME EQUAL STRING ) + ) + RR_BRACKET + ; + +database_file_spec + : file_group | file_spec + ; + +file_group + : FILEGROUP id + ( CONTAINS FILESTREAM )? + ( DEFAULT )? + ( CONTAINS MEMORY_OPTIMIZED_DATA )? + file_spec ( COMMA file_spec )* + ; +file_spec + : LR_BRACKET + NAME EQUAL ( id | STRING ) COMMA? + ( FILENAME EQUAL file = STRING COMMA? )? + ( SIZE EQUAL file_size COMMA? )? + ( MAXSIZE EQUAL (file_size | UNLIMITED )COMMA? )? + ( FILEGROWTH EQUAL file_size COMMA? )? + RR_BRACKET + ; + +if_exists + : IF EXISTS + ; + +trim_from + : FROM + ; + +on_off + : ON + | OFF + ; + +clustered + : CLUSTERED + | NONCLUSTERED + ; + +null_notnull + : NOT? NULL_P + ; + +begin_conversation_timer + : BEGIN CONVERSATION TIMER LR_BRACKET LOCAL_ID RR_BRACKET TIMEOUT EQUAL time SEMI? + ; + +begin_conversation_dialog + : BEGIN DIALOG (CONVERSATION)? dialog_handle=LOCAL_ID + FROM SERVICE initiator_service_name=service_name + TO SERVICE target_service_name=service_name (COMMA service_broker_guid=STRING)? + ON CONTRACT contract_name + (WITH + ((RELATED_CONVERSATION | RELATED_CONVERSATION_GROUP) EQUAL LOCAL_ID COMMA?)? + (LIFETIME EQUAL (DECIMAL | LOCAL_ID) COMMA?)? + (ENCRYPTION EQUAL (ON | OFF))? )? + SEMI? + ; + +contract_name + : (id | expression) + ; + +service_name + : (id | expression) + ; + +end_conversation + : END CONVERSATION conversation_handle=LOCAL_ID SEMI? + (WITH (ERROR EQUAL faliure_code=(LOCAL_ID | STRING) DESCRIPTION EQUAL failure_text=(LOCAL_ID | STRING))? CLEANUP? )? + ; + +waitfor_conversation + : WAITFOR? LR_BRACKET get_conversation RR_BRACKET (COMMA? TIMEOUT timeout=time)? SEMI? + ; + +get_conversation + :GET CONVERSATION GROUP conversation_group_id=(STRING | LOCAL_ID) FROM queue=queue_id SEMI? + ; + +// https://docs.microsoft.com/en-us/sql/t-sql/language-elements/waitfor-transact-sql +waitfor_receive_statement + : WAITFOR receive_statement? (COMMA TIMEOUT time)? SEMI? + ; + +receive_statement + : RECEIVE (ALL | DISTINCT | top_clause | STAR)? + ((LOCAL_ID EQUAL)? expression COMMA?)* FROM full_object_name + (INTO table_variable=LOCAL_ID)? (WHERE where=search_condition)? SEMI? + | LR_BRACKET receive_statement RR_BRACKET SEMI? + ; + +queue_id + : database_name=id (DOT schema_name=id DOT name=id)? + ; + +send_conversation + : SEND ON CONVERSATION conversation_handle=(STRING | LOCAL_ID) + MESSAGE TYPE message_type_name=expression + ( LR_BRACKET message_body_expression=(STRING | LOCAL_ID) RR_BRACKET )? + SEMI? + ; + +// https://msdn.microsoft.com/en-us/library/ms187752.aspx +data_type + : ext_type=simple_name LR_BRACKET scale=DECIMAL COMMA prec=DECIMAL RR_BRACKET + | NATIONAL? ext_type=simple_name VARYING? LR_BRACKET scale=(DECIMAL|MAX) RR_BRACKET + | ext_type=simple_name IDENTITY (LR_BRACKET sign? seed=DECIMAL COMMA sign? inc=DECIMAL RR_BRACKET)? + | cursor_type=CURSOR + | double_prec=DOUBLE PRECISION? + | NATIONAL? unscaled_type=simple_name VARYING? + | xml_type_definition + ; + +// https://msdn.microsoft.com/en-us/library/ms179899.aspx +constant + : STRING // string, datetime or uniqueidentifier + | BINARY + | NULL_P + | sign? (REAL | MONEY | DECIMAL | FLOAT) + ; + +sign + : PLUS + | MINUS + ; + +keyword + : ABORT_AFTER_WAIT + | ABSENT + | ABSOLUTE + | ACCENT_SENSITIVITY + | ACCESS + | ACTION + | ACTIVATION + | ACTIVE + | ADDRESS + | ADMINISTER + | AES + | AES_128 + | AES_192 + | AES_256 + | AFFINITY + | AFTER + | AGGREGATE + | ALGORITHM + | ALLOWED + | ALLOW_CONNECTIONS + | ALLOW_ENCRYPTED_VALUE_MODIFICATIONS + | ALLOW_MULTIPLE_EVENT_LOSS + | ALLOW_SINGLE_EVENT_LOSS + | ALLOW_SNAPSHOT_ISOLATION + | ALWAYS + | ANONYMOUS + | ANSI_DEFAULTS + | ANSI_NULLS + | ANSI_NULL_DEFAULT + | ANSI_NULL_DFLT_OFF + | ANSI_NULL_DFLT_ON + | ANSI_PADDING + | ANSI_WARNINGS + | APPEND + | APPLICATION + | APPLICATION_LOG + | APPLY + | ARITHABORT + | ASSEMBLY + | ASYMMETRIC + | ASYNCHRONOUS_COMMIT + | ATOMIC + | AT_KEYWORD + | AUDIT + | AUDIT_GUID + | AUTHENTICATE + | AUTHENTICATION + | AUTO + | AUTOMATED_BACKUP_PREFERENCE + | AUTOMATIC + | AUTO_CLEANUP + | AUTO_CLOSE + | AUTO_CREATE_STATISTICS + | AUTO_SHRINK + | AUTO_UPDATE_STATISTICS + | AUTO_UPDATE_STATISTICS_ASYNC + | AUTOCOMMIT + | AVAILABILITY + | AVAILABILITY_MODE + | AVG + | BACKUP_PRIORITY + | BEFORE + | BEGIN_DIALOG + | BIGINT + | BASE64 + | BINARY_CHECKSUM + | BINDING + | BLOB_STORAGE + | BLOCK + | BLOCKERS + | BLOCKING_HIERARCHY + | BLOCKSIZE + | BOUNDING_BOX + | BROKER + | BROKER_INSTANCE + | BUFFER + | BUFFERCOUNT + | BULK_LOGGED + | CACHE + | CALLED + | CALLER + | CAP_CPU_PERCENT + | CAST + | CATALOG + | CATALOG_COLLATION + | CATCH + | CELLS_PER_OBJECT + | CERTIFICATE + | CHANGE + | CHANGES + | CHANGETABLE + | CHANGE_RETENTION + | CHANGE_TRACKING + | CHECKSUM + | CHECKSUM_AGG + | CHECK_EXPIRATION + | CHECK_POLICY + | CLASSIFIER_FUNCTION + | CLEANUP + | CLEANUP_POLICY + | CLEAR + | CLUSTER + | COALESCE + | COLLECTION + | COLUMNS + | COLUMNSTORE + | COLUMN_MASTER_KEY + | COMMITTED + | COMPATIBILITY_LEVEL + | COMPRESSION + | CONCAT + | CONCAT_NULL_YIELDS_NULL + | CONFIGURATION + | CONNECTION + | CONTAINED + | CONTAINMENT + | CONTENT + | CONTEXT + | CONTINUE_AFTER_ERROR + | CONTRACT + | CONTRACT_NAME + | CONTROL + | CONVERSATION + | COOKIE + | COPY_ONLY + | COUNT + | COUNTER + | COUNT_BIG + | CPU + | CREATE_NEW + | CREATION_DISPOSITION + | CREDENTIAL + | CRYPTOGRAPHIC + | CUBE + | CUME_DIST + | CURSOR_CLOSE_ON_COMMIT + | CURSOR_DEFAULT + | CUSTOM + | CYCLE + | D + | DATA + | DATABASE_MIRRORING + | DATASPACE + | DATA_COMPRESSION + | DATA_CONSISTENCY_CHECK + | DATA_FLUSH_INTERVAL_SECONDS + | DATA_SOURCE + | DATEADD + | DATEDIFF + | DATEFIRST + | DATEFORMAT + | DATENAME + | DATEPART + | DATE_CORRELATION_OPTIMIZATION + | DATE_FORMAT + | DAY + | DAYS + | DB_CHAINING + | DB_FAILOVER + | DDL + | DECRYPTION + | DEFAULT_DATABASE + | DEFAULT_DOUBLE_QUOTE + | DEFAULT_FULLTEXT_LANGUAGE + | DEFAULT_LANGUAGE + | DEFAULT_SCHEMA + | DEFINITION + | DELAY + | DELAYED_DURABILITY + | DELETED + | DENSE_RANK + | DEPENDENTS + | DES + | DESCRIPTION + | DESX + | DHCP + | DIAGNOSTICS + | DIALOG + | DIFFERENTIAL + | DIRECTORY_NAME + | DISABLE + | DISABLED + | DISABLE_BROKER + | DISK + | DISK_DRIVE + | DISTRIBUTED_AGG + | DOCUMENT + | DTC_SUPPORT + | DYNAMIC + | ELEMENTS + | EMERGENCY + | EMPTY + | ENABLE + | ENABLED + | ENABLE_BROKER + | ENCODING + | ENCRYPTED_VALUE + | ENCRYPTION + | ENDPOINT + | ENDPOINT_URL + | ERROR + | ERROR_BROKER_CONVERSATIONS + | EVENT + | EVENTDATA + | EVENT_RETENTION_MODE + | EXCLUSIVE + | EXECUTABLE + | EXECUTABLE_FILE + | EXECUTION_COUNT + | EXIST + | EXPAND + | EXPIREDATE + | EXPIRY_DATE + | EXPLICIT + | EXTENSION + | EXTERNAL_ACCESS + | EXTRACT + | FAILOVER + | FAILOVER_MODE + | FAILURE + | FAILURECONDITIONLEVEL + | FAILURE_CONDITION_LEVEL + | FAIL_OPERATION + | FALSE + | FAN_IN + | FAST + | FAST_FORWARD + | FIELD_TERMINATOR + | FILEGROUP + | FILEGROWTH + | FILENAME + | FILEPATH + | FILESTREAM + | FILETABLE + | FILE_SNAPSHOT + | FILTER + | FIPS_FLAGGER + | FIRST + | FIRST_ROW + | FIRST_VALUE + | FMTONLY + | FN + | FOLLOWING + | FORCE + | FORCED + | FORCESEEK + | FORCE_FAILOVER_ALLOW_DATA_LOSS + | FORCE_SERVICE_ALLOW_DATA_LOSS + | FORMAT + | FORMAT_OPTIONS + | FORMAT_TYPE + | FORWARD_ONLY + | FULLSCAN + | FULLTEXT + | GB + | GENERATED + | GEOGRAPHY_AUTO_GRID + | GEOGRAPHY_GRID + | GEOMETRY_AUTO_GRID + | GEOMETRY_GRID + | GET + | GETANCESTOR + | GETDATE + | GETDESCENDANT + | GETLEVEL + | GETREPARENTEDVALUE + | GETROOT + | GETUTCDATE + | GLOBAL + | GOVERNOR + | GRIDS + | GROUPING + | GROUPING_ID + | GROUP_MAX_REQUESTS + | GUID + | HADR + | HASH + | HASHED + | HEALTHCHECKTIMEOUT + | HEALTH_CHECK_TIMEOUT + | HIDDEN_RENAMED + | HIGH + | HINT + | HISTORY_RETENTION_PERIOD + | HISTORY_TABLE + | HOLDLOCK + | HONOR_BROKER_PRIORITY + | HOUR + | HOURS + | IDENTITY + | IDENTITYCOL + | IDENTITY_VALUE + | IGNORE_NONCLUSTERED_COLUMNSTORE_INDEX + | IIF + | IMMEDIATE + | IMPERSONATE + | IMPORTANCE + | INCLUDE + | INCLUDE_NULL_VALUES + | INCREMENT + | INCREMENTAL + | INFINITE + | INIT + | INITIATOR + | INPUT + | INSENSITIVE + | INSERTED + | INSTEAD + | INT + | INTERVAL + | INTERVAL_LENGTH_MINUTES + | IO + | IP + | ISDESCENDANTOF + | ISNULL + | ISOLATION + | JOB + | JSON + | KB + | KEEP + | KEEPFIXED + | KEEP_CDC + | KEEP_REPLICATION + | KERBEROS + | KEYS + | KEYSET + | KEY_PATH + | KEY_SOURCE + | KEY_STORE_PROVIDER_NAME + | LAG + | LANGUAGE + | LAST + | LAST_VALUE + | LEAD + | LEDGER + | LEFT + | LEVEL + | LIBRARY + | LIFETIME + | LINKED + | LINUX + | LIST + | LISTENER + | LISTENER_IP + | LISTENER_PORT + | LISTENER_URL + | LOB_COMPACTION + | LOCAL + | LOCAL_SERVICE_NAME + | LOCATION + | LOCK + | LOCK_ESCALATION + | LOG + | LOGIN + | LOOP + | LOW + | MANUAL + | MARK + | MASK + | MASKED + | MASTER + | MATCHED + | MATERIALIZED + | MAX + | MAXDOP + | MAXRECURSION + | MAXSIZE + | MAXTRANSFER + | MAXVALUE + | MAX_CPU_PERCENT + | MAX_DISPATCH_LATENCY + | MAX_DOP + | MAX_DURATION + | MAX_EVENT_SIZE + | MAX_FILES + | MAX_GRANT_PERCENT + | MAX_IOPS_PER_VOLUME + | MAX_MEMORY + | MAX_MEMORY_PERCENT + | MAX_OUTSTANDING_IO_PER_VOLUME + | MAX_PLANS_PER_QUERY + | MAX_PROCESSES + | MAX_QUEUE_READERS + | MAX_ROLLOVER_FILES + | MAX_SIZE + | MAX_SIZE_MB + | MAX_STORAGE_SIZE_MB + | MB + | MEDIADESCRIPTION + | MEDIANAME + | MEDIUM + | MEMBER + | MEMORY_OPTIMIZED_DATA + | MEMORY_PARTITION_MODE + | MESSAGE + | MESSAGE_FORWARDING + | MESSAGE_FORWARD_SIZE + | MIN + | MINUTE + | MINUTES + | MINVALUE + | MIN_ACTIVE_ROWVERSION + | MIN_CPU_PERCENT + | MIN_GRANT_PERCENT + | MIN_IOPS_PER_VOLUME + | MIN_MEMORY_PERCENT + | MIRROR + | MIRROR_ADDRESS + | MIXED_PAGE_ALLOCATION + | MODE + | MODEL + | MODIFY + | MONTH + | MONTHS + | MOVE + | MULTI_USER + | MUST_CHANGE + | NAME + | NATIVE_COMPILATION + | NESTED_TRIGGERS + | NEW_ACCOUNT + | NEW_BROKER + | NEW_PASSWORD + | NEXT + | NO + | NOCOMPUTE + | NOCOUNT + | NODE + | NODES + | NOEXEC + | NOEXPAND + | NOFORMAT + | NOINIT + | NONE + | NON_TRANSACTED_ACCESS + | NORECOMPUTE + | NORECOVERY + | NOREWIND + | NOSKIP + | NOTIFICATION + | NOTIFICATIONS + | NOUNLOAD + | NOWAIT + | NO_CHECKSUM + | NO_COMPRESSION + | NO_EVENT_LOSS + | NO_TRUNCATE + | NO_WAIT + | NTILE + | NTLM + | NULLIF + | NUMANODE + | NUMBER + | NUMERIC_ROUNDABORT + | OBJECT + | OFFLINE + | OFFSET + | OLD_ACCOUNT + | OLD_PASSWORD + | ONLINE + | ONLY + | ON_FAILURE + | OPENJSON + | OPEN_EXISTING + | OPERATIONS + | OPERATION_MODE + | OPTIMISTIC + | OPTIMIZE + | OUT + | OUTPUT + | OVERRIDE + | OWNER + | OWNERSHIP + | PAGE + | PAGECOUNT + | PAGE_VERIFY + | PARAM + | PARAMETERIZATION + | PARAM_NODE + | PARSEONLY + | PARTIAL + | PARTITION + | PARTITIONS + | PARTNER + | PASSWORD + | PATH + | PERCENTILE_CONT + | PERCENTILE_DISC + | PERCENT_RANK + | PERIOD + | PERMISSION_SET + | PERSISTED + | PERSIST_SAMPLE_PERCENT + | PERSISTENT_LOG_BUFFER + | PER_CPU + | PER_DB + | PER_NODE + | PLATFORM + | POISON_MESSAGE_HANDLING + | POLICY + | POOL + | PORT + | POSITION + | PRECEDING + | PREDICATE + | PREDICT + | PRIMARY_ROLE + | PRIOR + | PRIORITY + | PRIORITY_LEVEL + | PRIVATE + | PRIVATE_KEY + | PRIVILEGES + | PROCEDURE_NAME + | PROCESS + | PROFILE + | PROPERTY + | PROVIDER + | PROVIDER_KEY_NAME + | PYTHON + | QUERY + | QUERY_CAPTURE_MODE + | QUERY_CAPTURE_POLICY + | QUERY_STORE + | QUEUE + | QUEUE_DELAY + | QUOTED_IDENTIFIER + | R + | RANGE + | RANK + | RC2 + | RC4 + | RC4_128 + | READONLY + | READ_COMMITTED_SNAPSHOT + | READ_ONLY + | READ_ONLY_ROUTING_LIST + | READ_WRITE + | READ_WRITE_FILEGROUPS + | REBUILD + | RECEIVE + | RECOMPILE + | RECOVERY + | RECURSIVE_TRIGGERS + | REDISTRIBUTE + | REDUCE + | REGENERATE + | RELATED_CONVERSATION + | RELATED_CONVERSATION_GROUP + | RELATIVE + | REMOTE + | REMOTE_PROC_TRANSACTIONS + | REMOTE_SERVICE_NAME + | REMOVE + | REORGANIZE + | REPEATABLE + | REPLACE + | REPLICA + | REPLICATE + | REQUEST_MAX_CPU_TIME_SEC + | REQUEST_MAX_MEMORY_GRANT_PERCENT + | REQUEST_MEMORY_GRANT_TIMEOUT_SEC + | REQUIRED + | REQUIRED_SYNCHRONIZED_SECONDARIES_TO_COMMIT + | RESAMPLE + | RESERVE_DISK_SPACE + | RESET + | RESOURCE + | RESOURCES + | RESOURCE_MANAGER_LOCATION + | RESTART + | RESTRICTED_USER + | RESULT + | RESUME + | RETAINDAYS + | RETENTION + | RETURNS + | REWIND + | RIGHT + | ROBUST + | ROLE + | ROLLUP + | ROOT + | ROUTE + | ROW + | ROWGUID + | ROWS + | ROW_NUMBER + | RSA_1024 + | RSA_2048 + | RSA_3072 + | RSA_4096 + | RSA_512 + | RUNTIME + | SAFE + | SAFETY + | SAMPLE + | SCHEDULER + | SCHEMABINDING + | SCHEME + | SCOPED + | SCRIPT + | SCROLL + | SCROLL_LOCKS + | SEARCH + | SECOND + | SECONDARY + | SECONDARY_ONLY + | SECONDARY_ROLE + | SECONDS + | SECRET + | SECURABLES + | SECURITY + | SECURITY_LOG + | SEEDING_MODE + | SELF + | SELECTIVE + | SEMI_SENSITIVE + | SEND + | SENT + | SEQUENCE + | SEQUENCE_NUMBER + | SERIALIZABLE + | SERVER + | SERVICE + | SERVICE_BROKER + | SERVICE_NAME + | SESSION + | SESSION_TIMEOUT + | SETERROR + | SETS + | SETTINGS + | SHARE + | SHOWPLAN + | SHOWPLAN_ALL + | SHOWPLAN_TEXT + | SHOWPLAN_XML + | SID + | SIGNATURE + | SIMPLE + | SINGLETON + | SINGLE_USER + | SIZE + | SIZE_BASED_CLEANUP_MODE + | SKIP_KEYWORD + | SMALLINT + | SNAPSHOT + | SOFTNUMA + | SOURCE + | SPARSE + | SPATIAL + | SPATIAL_WINDOW_MAX_CELLS + | SPECIFICATION + | SPLIT + | SQL + | SQLDUMPERFLAGS + | SQLDUMPERPATH + | SQLDUMPERTIMEOUT + | STALE_CAPTURE_POLICY_THRESHOLD + | STANDBY + | START + | STARTED + | STARTUP_STATE + | START_DATE + | STATE + | STATEMENT + | STATIC + | STATS + | STATS_STREAM + | STATUS + | STATUSONLY + | STDEV + | STDEVP + | STOP + | STOPAT + | STOPATMARK + | STOPBEFOREMARK + | STOPLIST + | STOPPED + | STOP_ON_ERROR + | STRING_AGG + | STRING_DELIMITER + | STUFF + | SUBJECT + | SUBSCRIBE + | SUBSCRIPTION + | SUM + | SUPPORTED + | SUSPEND + | SWITCH + | SYMMETRIC + | SYNCHRONOUS_COMMIT + | SYNONYM + | SYSTEM + | SYSTEM_TIME + | SYSTEM_VERSIONING + | T + | TAKE + | TAPE + | TARGET + | TARGET_RECOVERY_TIME + | TB + | TCP + | TEXTIMAGE_ON + | THROW + | TIES + | TIME + | TIMEOUT + | TIMER + | TINYINT + | TORN_PAGE_DETECTION + | TOSTRING + | TOTAL_COMPILE_CPU_TIME_MS + | TOTAL_EXECUTION_CPU_TIME_MS + | TRACE + | TRACKING + | TRACK_CAUSALITY + | TRACK_COLUMNS_UPDATED + | TRANSACTION_ID + | TRANSFER + | TRANSFORM_NOISE_WORDS + | TRIM + | TRIPLE_DES + | TRIPLE_DES_3KEY + | TRUE + | TRUSTWORTHY + | TRY + | TRY_CAST + | TS + | TSQL + | TWO_DIGIT_YEAR_CUTOFF + | TYPE + | TYPE_WARNING + | UNBOUNDED + | UNCHECKED + | UNCOMMITTED + | UNKNOWN + | UNLIMITED + | UNLOCK + | UNMASK + | UNSAFE + | UOW + | URL + | USED + | USE_TYPE_DEFAULT + | USING + | VALIDATION + | VALID_XML + | VALUE + | VAR + | VARP + | VERBOSELOGGING + | VERSION + | VIEWS + | VIEW_METADATA + | VISIBILITY + | XACT_ABORT + | WAIT + | WAIT_AT_LOW_PRIORITY + | WAIT_STATS_CAPTURE_MODE + | WEEK + | WEEKS + | WELL_FORMED_XML + | WINDOWS + | WITHOUT + | WITHOUT_ARRAY_WRAPPER + | WITNESS + | WORK + | WORKLOAD + | XMAX + | XMIN + | XML + | XMLDATA + | XMLNAMESPACES + | XMLSCHEMA + | XQUERY + | XSINIL + | YEAR + | YEARS + | YMAX + | YMIN + | ZONE + //Built-ins: + | VARCHAR + | NVARCHAR + | BINARY_KEYWORD + | VARBINARY_KEYWORD + | PRECISION //For some reason this is possible to use as ID + ; + +entity_name + : (((server=id DOT database=id DOT)? schema=id | database=id DOT schema=id?) DOT)? table=id + ; + +full_object_name + : (((server=id? DOT)? database=id? DOT)? schema=id? DOT)? object_name=id + ; + +table_name + : ((database=id? DOT)? schema=id? DOT)? table=id + ; + +simple_name + : DOT? (schema=id? DOT)? name=id + ; + +func_proc_name_schema + : DOT? ((schema=id)? DOT)? procedure=id + ; + +func_proc_name_database_schema + : DOT? database=id? DOT schema=id? DOT procedure=id + | (schema=id? DOT)? procedure=id + ; + +func_proc_name_server_database_schema + : (server=id? DOT)? database=id? DOT schema=id? DOT procedure=id + | (schema=id? DOT)? procedure=id + ; + +ddl_object + : full_object_name + | local_id + ; + +external_name + : EXTERNAL NAME full_object_name + ; + +full_column_name + : (((server=id? DOT)? schema=id? DOT)? tablename=id? DOT)? column_name=id + ; + +column_name_list_with_order + : simple_column_name (ASC | DESC)? (COMMA simple_column_name (ASC | DESC)?)* + ; + +//For some reason, tsql allows any number of prefixes: Here, h is the column: a.b.c.d.e.f.g.h +insert_column_name_list + : col+=insert_column_id (COMMA col+=insert_column_id)* + ; + +insert_column_id + : (ignore+=id? DOT )* id + ; + +column_name_list + : col+=simple_column_name (COMMA col+=simple_column_name)* + ; + +cursor_name + : id + | LOCAL_ID + ; + +simple_column_name + : id + ; + +// https://msdn.microsoft.com/en-us/library/ms175874.aspx +id + : ID + | DOUBLE_QUOTE_ID + | SQUARE_BRACKET_ID + | keyword + | id colon_colon id + ; + +local_id + : LOCAL_ID + ; + +// https://msdn.microsoft.com/en-us/library/ms188074.aspx +// Spaces are allowed for comparison operators. +comparison_operator + : EQUAL | GREATER | LESS | LESS EQUAL | GREATER EQUAL | LESS GREATER | EXCLAMATION EQUAL | EXCLAMATION GREATER | EXCLAMATION LESS + ; + +assignment_operator + : PLUS_ASSIGN | MINUS_ASSIGN | MULT_ASSIGN | DIV_ASSIGN | MOD_ASSIGN | AND_ASSIGN | XOR_ASSIGN| OR_ASSIGN + ; + +file_size + : DECIMAL( KB | MB | GB | TB | PERCENT_SIGN )? + ; + +// +// end of file +// diff --git a/contrib/babelfishpg_tsql/antlr/cmake-dir/FindANTLR.cmake b/contrib/babelfishpg_tsql/antlr/cmake-dir/FindANTLR.cmake new file mode 100644 index 00000000000..968feded7a8 --- /dev/null +++ b/contrib/babelfishpg_tsql/antlr/cmake-dir/FindANTLR.cmake @@ -0,0 +1,128 @@ +#find_package(Java QUIET COMPONENTS Runtime) + +if(NOT ANTLR_EXECUTABLE) + find_program(ANTLR_EXECUTABLE + NAMES antlr.jar antlr4.jar antlr-4.jar antlr-4.9.3-complete.jar) +endif() + +set(Java_JAVA_EXECUTABLE $ENV{ANTLR4_JAVA_BIN}) + +message(STATUS "java executable=${Java_JAVA_EXECUTABLE}") + +if(ANTLR_EXECUTABLE AND Java_JAVA_EXECUTABLE) + execute_process( + COMMAND ${Java_JAVA_EXECUTABLE} -jar ${ANTLR_EXECUTABLE} + OUTPUT_VARIABLE ANTLR_COMMAND_OUTPUT + ERROR_VARIABLE ANTLR_COMMAND_ERROR + RESULT_VARIABLE ANTLR_COMMAND_RESULT + OUTPUT_STRIP_TRAILING_WHITESPACE) + + if(ANTLR_COMMAND_RESULT EQUAL 0) + string(REGEX MATCH "Version [0-9]+(\\.[0-9])*" ANTLR_VERSION ${ANTLR_COMMAND_OUTPUT}) + string(REPLACE "Version " "" ANTLR_VERSION ${ANTLR_VERSION}) + else() + message( + SEND_ERROR + "Command '${Java_JAVA_EXECUTABLE} -jar ${ANTLR_EXECUTABLE}' " + "failed with the output '${ANTLR_COMMAND_ERROR}'") + endif() + + macro(ANTLR_TARGET Name InputFile) + set(ANTLR_OPTIONS LEXER PARSER LISTENER VISITOR) + set(ANTLR_ONE_VALUE_ARGS PACKAGE OUTPUT_DIRECTORY DEPENDS_ANTLR) + set(ANTLR_MULTI_VALUE_ARGS COMPILE_FLAGS DEPENDS) + cmake_parse_arguments(ANTLR_TARGET + "${ANTLR_OPTIONS}" + "${ANTLR_ONE_VALUE_ARGS}" + "${ANTLR_MULTI_VALUE_ARGS}" + ${ARGN}) + + set(ANTLR_${Name}_INPUT ${InputFile}) + + get_filename_component(ANTLR_INPUT ${InputFile} NAME_WE) + + if(ANTLR_TARGET_OUTPUT_DIRECTORY) + set(ANTLR_${Name}_OUTPUT_DIR ${ANTLR_TARGET_OUTPUT_DIRECTORY}) + else() + set(ANTLR_${Name}_OUTPUT_DIR + ${CMAKE_CURRENT_BINARY_DIR}/antlr4cpp_generated_src/${ANTLR_INPUT}) + endif() + + unset(ANTLR_${Name}_CXX_OUTPUTS) + + if((ANTLR_TARGET_LEXER AND NOT ANTLR_TARGET_PARSER) OR + (ANTLR_TARGET_PARSER AND NOT ANTLR_TARGET_LEXER)) + list(APPEND ANTLR_${Name}_CXX_OUTPUTS + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}.h + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}.cpp) + set(ANTLR_${Name}_OUTPUTS + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}.interp + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}.tokens) + else() + list(APPEND ANTLR_${Name}_CXX_OUTPUTS + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}Lexer.h + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}Lexer.cpp + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}Parser.h + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}Parser.cpp) + list(APPEND ANTLR_${Name}_OUTPUTS + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}Lexer.interp + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}Lexer.tokens) + endif() + + if(ANTLR_TARGET_LISTENER) + list(APPEND ANTLR_${Name}_CXX_OUTPUTS + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}BaseListener.h + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}BaseListener.cpp + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}Listener.h + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}Listener.cpp) + list(APPEND ANTLR_TARGET_COMPILE_FLAGS -listener) + endif() + + if(ANTLR_TARGET_VISITOR) + list(APPEND ANTLR_${Name}_CXX_OUTPUTS + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}BaseVisitor.h + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}BaseVisitor.cpp + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}Visitor.h + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}Visitor.cpp) + list(APPEND ANTLR_TARGET_COMPILE_FLAGS -visitor) + endif() + + if(ANTLR_TARGET_PACKAGE) + list(APPEND ANTLR_TARGET_COMPILE_FLAGS -package ${ANTLR_TARGET_PACKAGE}) + endif() + + list(APPEND ANTLR_${Name}_OUTPUTS ${ANTLR_${Name}_CXX_OUTPUTS}) + + if(ANTLR_TARGET_DEPENDS_ANTLR) + if(ANTLR_${ANTLR_TARGET_DEPENDS_ANTLR}_INPUT) + list(APPEND ANTLR_TARGET_DEPENDS + ${ANTLR_${ANTLR_TARGET_DEPENDS_ANTLR}_INPUT}) + list(APPEND ANTLR_TARGET_DEPENDS + ${ANTLR_${ANTLR_TARGET_DEPENDS_ANTLR}_OUTPUTS}) + else() + message(SEND_ERROR + "ANTLR target '${ANTLR_TARGET_DEPENDS_ANTLR}' not found") + endif() + endif() + + add_custom_command( + OUTPUT ${ANTLR_${Name}_OUTPUTS} + COMMAND ${Java_JAVA_EXECUTABLE} -jar ${ANTLR_EXECUTABLE} + ${InputFile} + -o ${ANTLR_${Name}_OUTPUT_DIR} + -no-listener + -Dlanguage=Cpp + ${ANTLR_TARGET_COMPILE_FLAGS} + DEPENDS ${InputFile} + ${ANTLR_TARGET_DEPENDS} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMENT "Building ${Name} with ANTLR ${ANTLR_VERSION}") + endmacro(ANTLR_TARGET) + +endif(ANTLR_EXECUTABLE AND Java_JAVA_EXECUTABLE) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args( + ANTLR + REQUIRED_VARS ANTLR_EXECUTABLE Java_JAVA_EXECUTABLE + VERSION_VAR ANTLR_VERSION) diff --git a/contrib/babelfishpg_tsql/antlr/cmake-dir/README.md b/contrib/babelfishpg_tsql/antlr/cmake-dir/README.md new file mode 100644 index 00000000000..0ebe1dd51e5 --- /dev/null +++ b/contrib/babelfishpg_tsql/antlr/cmake-dir/README.md @@ -0,0 +1,157 @@ +## Getting started with Antlr4Cpp + +Here is how you can use this external project to create the antlr4cpp demo to start your project off. + +1. Create your project source folder somewhere. e.g. ~/srcfolder/ + 1. Make a subfolder cmake + 2. Copy the files in this folder to srcfolder/cmake + 3. Cut below and use it to create srcfolder/CMakeLists.txt + 4. Copy main.cpp, TLexer.g4 and TParser.g4 to ./srcfolder/ from [here](https://github.com/antlr/antlr4/tree/master/runtime/Cpp/demo) +2. Make a build folder e.g. ~/buildfolder/ +3. From the buildfolder, run `cmake ~/srcfolder; make` + +```cmake +# minimum required CMAKE version +CMAKE_MINIMUM_REQUIRED(VERSION 3.7 FATAL_ERROR) + +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) + +# compiler must be 11 or 14 +set(CMAKE_CXX_STANDARD 11) + +# required if linking to static library +add_definitions(-DANTLR4CPP_STATIC) + +# using /MD flag for antlr4_runtime (for Visual C++ compilers only) +set(ANTLR4_WITH_STATIC_CRT OFF) +# add external build for antlrcpp +include(ExternalAntlr4Cpp) +# add antrl4cpp artifacts to project environment +include_directories(${ANTLR4_INCLUDE_DIRS}) + +# set variable pointing to the antlr tool that supports C++ +# this is not required if the jar file can be found under PATH environment +set(ANTLR_EXECUTABLE /home/user/antlr-4.9.3-complete.jar) +# add macros to generate ANTLR Cpp code from grammar +find_package(ANTLR REQUIRED) + +# Call macro to add lexer and grammar to your build dependencies. +antlr_target(SampleGrammarLexer TLexer.g4 LEXER + PACKAGE antlrcpptest) +antlr_target(SampleGrammarParser TParser.g4 PARSER + PACKAGE antlrcpptest + DEPENDS_ANTLR SampleGrammarLexer + COMPILE_FLAGS -lib ${ANTLR_SampleGrammarLexer_OUTPUT_DIR}) + +# include generated files in project environment +include_directories(${ANTLR_SampleGrammarLexer_OUTPUT_DIR}) +include_directories(${ANTLR_SampleGrammarParser_OUTPUT_DIR}) + +# add generated grammar to demo binary target +add_executable(demo main.cpp + ${ANTLR_SampleGrammarLexer_CXX_OUTPUTS} + ${ANTLR_SampleGrammarParser_CXX_OUTPUTS}) +target_link_libraries(demo antlr4_static) +``` + +## Documentation for FindANTLR + +The module defines the following variables: + +``` +ANTLR_FOUND - true is ANTLR jar executable is found +ANTLR_EXECUTABLE - the path to the ANTLR jar executable +ANTLR_VERSION - the version of ANTLR +``` + +If ANTLR is found, the module will provide the macros: + +``` +ANTLR_TARGET( + [PACKAGE namespace] + [OUTPUT_DIRECTORY dir] + [DEPENDS_ANTLR ] + [COMPILE_FLAGS [args...]] + [DEPENDS [depends...]] + [LEXER] + [PARSER] + [LISTENER] + [VISITOR]) +``` + +which creates a custom command to generate C++ files from ``. Running the macro defines the following variables: + +``` +ANTLR_${name}_INPUT - the ANTLR input used for the macro +ANTLR_${name}_OUTPUTS - the outputs generated by ANTLR +ANTLR_${name}_CXX_OUTPUTS - the C++ outputs generated by ANTLR +ANTLR_${name}_OUTPUT_DIR - the output directory for ANTLR +``` + +The options are: + +* `PACKAGE` - defines a namespace for the generated C++ files +* `OUTPUT_DIRECTORY` - the output directory for the generated files. By default it uses `${CMAKE_CURRENT_BINARY_DIR}` +* `DEPENDS_ANTLR` - the dependent target generated from antlr_target for the current call +* `COMPILE_FLAGS` - additional compile flags for ANTLR tool +* `DEPENDS` - specify the files on which the command depends. It works the same way `DEPENDS` in [`add_custom_command()`](https://cmake.org/cmake/help/v3.11/command/add_custom_command.html) +* `LEXER` - specify that the input file is a lexer grammar +* `PARSER` - specify that the input file is a parser grammar +* `LISTENER` - tell ANTLR tool to generate a parse tree listener +* `VISITOR` - tell ANTLR tool to generate a parse tree visitor + +### Examples + +To generate C++ files from an ANTLR input file T.g4, which defines both lexer and parser grammar one may call: + +```cmake +find_package(ANTLR REQUIRED) +antlr_target(Sample T.g4) +``` + +Note that this command will do nothing unless the outputs of `Sample`, i.e. `ANTLR_Sample_CXX_OUTPUTS` gets used by some target. + +## Documentation for ExternalAntlr4Cpp + +Including ExternalAntlr4Cpp will add `antlr4_static` and `antlr4_shared` as an optional target. It will also define the following variables: + +``` +ANTLR4_INCLUDE_DIRS - the include directory that should be included when compiling C++ source file +ANTLR4_STATIC_LIBRARIES - path to antlr4 static library +ANTLR4_SHARED_LIBRARIES - path to antlr4 shared library +ANTLR4_RUNTIME_LIBRARIES - path to antlr4 shared runtime library (such as DLL, DYLIB and SO file) +ANTLR4_TAG - branch/tag used for building antlr4 library +``` + +`ANTLR4_TAG` is set to master branch by default to keep antlr4 updated. However, it will be required to rebuild after every `clean` is called. Set `ANTLR4_TAG` to a desired commit hash value to avoid rebuilding after every `clean` and keep the build stable, at the cost of not automatically update to latest commit. + +The ANTLR C++ runtime source is downloaded from GitHub by default. However, users may specify `ANTLR4_ZIP_REPOSITORY` to list the zip file from [ANTLR downloads](http://www.antlr.org/download.html) (under *C++ Target*). This variable can list a zip file included in the project directory; this is useful for maintaining a canonical source for each new build. + +Visual C++ compiler users may want to additionally define `ANTLR4_WITH_STATIC_CRT` before including the file. Set `ANTLR4_WITH_STATIC_CRT` to true if ANTLR4 C++ runtime library should be compiled with `/MT` flag, otherwise will be compiled with `/MD` flag. This variable has a default value of `OFF`. Changing `ANTLR4_WITH_STATIC_CRT` after building the library may require reinitialization of CMake or `clean` for the library to get rebuilt. + +You may need to modify your local copy of ExternalAntlr4Cpp.cpp to modify some build settings. For example, to specify the C++ standard to use when building the runtime, add `-DCMAKE_CXX_STANDARD:STRING=17` to `CMAKE_CACHE_ARGS`. + +### Examples + +To build and link ANTLR4 static library to a target one may call: + +```cmake +include(ExternalAntlr4Cpp) +include_directories(${ANTLR4_INCLUDE_DIRS}) +add_executable(output main.cpp) +target_link_libraries(output antlr4_static) +``` + +It may also be a good idea to copy the runtime libraries (DLL, DYLIB or SO file) to the executable for it to run properly after build. i.e. To build and link antlr4 shared library to a target one may call: + +```cmake +include(ExternalAntlr4Cpp) +include_directories(${ANTLR4_INCLUDE_DIRS}) +add_executable(output main.cpp) +target_link_libraries(output antlr4_shared) +add_custom_command(TARGET output + POST_BUILD + COMMAND ${CMAKE_COMMAND} + -E copy ${ANTLR4_RUNTIME_LIBRARIES} . + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) +``` diff --git a/contrib/babelfishpg_tsql/antlr/thirdparty/antlr/antlr-4.9.3-complete.jar b/contrib/babelfishpg_tsql/antlr/thirdparty/antlr/antlr-4.9.3-complete.jar new file mode 100644 index 0000000000000000000000000000000000000000..749296fe7b9021346079968d5d0b0ada93d48716 GIT binary patch literal 3508089 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\T=1W(x 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%0DGg7?QM;_fStX z6mR_wPyscceu70mJwc~4P9F!=dT6W~@~ZJ*U5f~E2OoJlCXw@LQD|?h<;SkgKXT*3 zZx!)mJ2{ny>0^m2Xtqi_6R+~Ls188W3?C|Z=Rc2pbmU|ZSDLT;gN_rcKJYrspRg}W zo}f<08T-v*RJFsV&ByKxQ8FH({QO=id2mS5$TzvLk$1pg;nho@*rmJG!eR0HXSS9s zq%2uxH?DIsQbImIT$sjlQLnYspibCsPEpaI(2%Nim&p!gertEdD#i}x@Y`&$7dESg z{|1NchO5<=i6q6{CU}~?_luwSZIC}#d6*r64z*ra8T3%ku;e}*K59W+)O$0cT|Om` zHh!T9yR+6*T&anD!#KRA_tjXyNq{q3<3z|fQG7c?Qd!zKEXob*{K?=AN_lcQ?53!T z-)T$c*=u+bSKNf+albcT4BXV@yxaDOzH9bXs$n%2tFBvf)(RF}_iEcjPydv(lTj$* zwI%ZDWBsLmd@>H6c~?*I#k;g{LW-vL`t~6_*8C!g$zPHiJ=U@(^^1|LRw4afW16rO z;@PLzGb|(ge90ogHR2)fqAB@>gs*O+2&`!gGQuZu47Vc%<@mX&WOb~ODne2dafy`? zR>(v&M0=h_5~lI8L6Ty+NH=t&QKdg%FY`W1OPzmrVs4dFe>d$+H+4=4#THk>uxk=Z zQ1zrL_~Y$#8y>PQSVBNUJACkSJtWTlSfsEQqI z2x%V5un7*ABh+Y^md`~-euI^aw)*Tof|XE>bK(e11Nw5zF(tsaH#b6f$dvuPe>@lH z%m3!x7Y`?za0!R+H0_ZPRG1hueGP8=KtZ6miV9r~H72*aln_CX=wyW zkI;X{yhf>@ETV`e=vwK4M>(|6?)(Hrr1-k30QBW=pZoM<)edTA&hw43t22QsC12~! z{5FXmUjOl`MjC*pMZ>J1t5zBPcWHEmuxlc)KKWeR)<#XICcROZ`sfY(Coh1fHPFqb zF-jy^_$sDiaByOg{Yp|sw(VBi2_oAwf+1Txw}bs=d6)1pyaP4fA@yz1ByT6bbCUe- z&f5?=DPN0Sy&v26IU<`s-PP9NKI*xo5d{|P%D=xb8eb~x_LK1v8Rb|b3yUw=?pk|i zfkRn4xhYO}mjh&XYmKDue3la2>wK}u35ukP3?fiVgungW&snVmH0gYK=`RG{zCyL; zh+=)G^Oe{cK^S7mu~FRdxu2Lq5c@WG#glz1LHFr1c4#%7js9KyF;B4kt@jSW5S`7R zMA7^Uf}htqH3%oSCCM=qdl8b5@2b&mk;w;)MWZ^37L|Mnk}kQ)lDr^~RXpJ8*8f6{ zv9*RXx|~+`!3#T*CuK?>+FBx#i_PBAx7&?CFO5XjJsHj3RJN0S5dP2ND6C2Cmt~+& z&-xGd>Ae5W?$$KY02W7u-zsQ;gJAXBRAFvp#gUO<^~I_py9iQqq4^>#f6&8`k-y8i z2*j_MbRtTU9y9|`M@Ri6 z?$%*}-YLmP?_agME&brB<;WzB(cb7DYPZn2eQ!$q=3l7=Q+V^1Rt)ZjxDDq+6MIZYByT_2u4D?sK^(I&J*?)1kZu`H zIiii2u4&B9Xk?&82@K?^*8;3m<@uy<5&Vm>OB(VmP{vVS4!>5V8rf-x@nv)su;M5d zd$r%#LJh_}69BB^(Fmj%Njg;}>!36oz$iW@tM{HI{nSZhd1lSi8xoDxKmpIBVU*1L zjMR$b)y|h;^{uWklFkQ^S_!OXEN6O~Ua-pmNz&3)>C* zf(R1hp2Y4kqv)2$&ZC2pr)1Y&>{6;{4Smif&9U5II_EP!l(|o)kO(Sik@K&uM3kt!db@1eq(&MgL7y!11sf|LP1dC~ zlvPSK{13Mf#=+mVmD}a%=Kl|*)|>xEYW-`;ry$gsDVn|n0oX1GZMFePVV1)~N^;u0 z`5mZVN_4*dhey&4AhrH4I1-ru#*vt`wLQSILlFq$cGAW|$&g#sDz6ba{F0y7e8NPK zA2`<oVZsi8j5Q#R|+V5WiUQftkA1Vcmr@Gy#r0 z!Na0nhh^7VQ%$Bht8DL@)GnX2yOvTc>LJw;)G%tdNPUaBAFD4HunKPRFdDSal@!L6 zMvBi~!P*bxN(?S6;k2}Fwm6Pm4mn87^8j-TgPG;4)p>QY<-=jM*mYc?6zd>G6;NL1 znNQbQlkCk3MaU> z0}g~fpDEW`%v2{8X+6@I$;3k&KYJSeP@pN_%BF`yD0kdRMf)=`P+_CZK~<$_=d+xkBRH8XlQxnqI&w#W{ZoFH^qc&~ zuScjX<*8k84M7TAgL&T-hRFwrKnc40h?D|cjA%du$t_)hq+%8%S%I6i>&G#q0HjeHPal4|)4AE1<1bIaj_Dts z0!D4X(>ySveE1K~C>&h>?#h4}<-fbKdswOGu1pFg4*^HK5(}77LPQqp7@iA=L3#Ne z1K=r$O^lJRgygUHji_DKS%#;%vFgbt*_;mJpUsfIo^XeceoEmbpaL)? z7%>I_hUC|GJfAsty1sJm!w+lCyJ$BfN(q!r`vUXfd+AodSC~|Z_8$z%r)LZasYTPe zqs=phWM0lzYW^1}p$-uIE^PZ>5HN&mXOECK43;Pr9S|R)*TaALG2r#@@_7Kk)a{QJ z;W|1YEp_M{*W27}rR6$g8Y?U4RB?t!9+XY$%!!Qhsr9|_fbE|^qhu6He+e%Be|pwvy&9e50hlHF8P*}=Gfc}D<#)pf`|a`pb=+o?-URZ2n&)``4H`^w`!kB< z{Ul!s500MSp2bc;4?`ocz3TF84cC4brgv8;yb%C9?bO3PbK=3Z6owXHyRM}3K57lH; z{7BvsPI(ngPY=zL`CRgJ}5h#9vua~B_5oI}20dtNtjdBQbV017DS zKU_fE{Qp`w(fkLr{eR!DMgowIfA_2359VO}`rV5~`#S4&&!3~?)+ZS9$|dI(A^vp} zSE2bqG?w+C%wO36A^1penZNmNZ=}!Sg@ta~X!J)c@DBDETSo#6a)_#=Bn>=AcZ3;o zy>l~&T1gd@!X7O+gadRktma@b=iW**C*>fMC`TkD=9#xfVzO_TAAB4GWxS?l;^ne= zhLkzn0Q16Uolh`M)6M{EjYP0i&^SOOYbxtn(=g~$CG(;ld*UUD)_XhLq3L z*re(a4h!lIJ~OswrYHTol)glvXsd5mW!2uE&VKEU63EVU6H^`m<^57;SoFA~KhsqV zdSBzFEN{ZeXLB8T3W{f2=cMB7j6~WI{wUUKq!^u%3_wXH1E0YP(!I=E07~KH#o7CQ zV=GUE<;5kgmc;{Zs|+f#pFsTpXoa+6-EM3`WFcIjidZ&|TRdq!B>bzs7Z(e`h}_k_ zkdk|yx6J^-&C`7J=`-`$wM}en!7ecHDV%(xD5K&O>sh$eclGXjsc)%(!hBk0acf!2 z#&9+OSfFEyi#w^4exKquqFcwa`MV-7{BA1c9&Pd|qk=*0w;LLhM3hgRRa@?QmmvzN zs&a%>?JYgn_RBzsvOA9q_Xkbozt=T?z!;0Hl*fG-Fjt4U*bxADgl6(^^ETPulUX>+h3RoZiJCy^gWbeFRc_gQMr1SCHbQ zxN7B&M*ZM@uHp3WXM~tHI|nMnUsqf7hkZjzIiUBG@LCmohbqc$e61&+ml7%945#Cq zYPI-Y9zPDYCk>nVsTn<#Sk8{SgZ2GqF%axFwr%$feK_i2Pfs#?Q^8KaLFoBktQ_qz zPumJmM5+JbBI0`Uul)zje|2%sSUCio2`E7I=~R+LrT>T8i0E&M?htDFObV6=6gRoY zd7gzZjx|U~*~oJav7?{Kjby{hp2Nm=2ZQ{d16uEpOp)9;cSjlW$&9d?x=h)`1_zfp z3ALn2gt6XPYOW;fvJUQqXa_&aqnWA}U9U14c0`7jVo4MJ>{FaSrz7aJ^^2n9+=QTo z>jSE(yT&1{F8_WVz~0kR!s)h2{it$ z6QKQxZ!UUXCvdRS9sED6y#-L5?Upr4g1a^D4hin=4#5fT4vj-_2=4Cg?(QzZ-GW=t z;O@8cotddQb7cOiJG^u^g*4Eswy$TepQdT94TD}h6J8sNVX^up+o|KeJc5<1)|+D1=@)Pj|&i;>6!NC_4TuA zp(n}JN7zNkq#9M~k*99)O-G}|SnC6b%$3~&J-@Brw06d=>?JkENw=FWCWGiP?55;v zigs91AiCAKuo?Elxtvm)5G0w{N$(6OG4cEP> z2({O3sP1S?2vKG{lXqv)?VWrMZD`Q0tXy$k!8>z}h|i zmXh<_!30j}LIE@}3hBoxi|Sa=rqs*>r?3`@T%F^YnigGLG06on?n8YuN0ofVTl3I2 zjfQ^ufy1`aVAnpFP*})*n!g$aCVaLiE4j%ia&wyW8IM!u1uiB&;AwVA6||-uC@*0h zB=(tN{KOsjQQ~s=E2^SZtlPig-i$nS!A?+{mFN zU4oN7Vu(M@-|#fAHc`jkd-UJTh;x~y*Mh!gfB52 z*ZsX77-bDPSqZgKM61p@+o_Zg~7pYM0HS-JDGdB8u!~=r~;cN$rdz5~ATe zA=eKTP$Zy5Hb)@fY<7|YBK$1YOtCo=L4{HN7Sfq?imDy5BSKtycV;~YJla0S+7G_~ zXgJW}lI>VOu|ou-cO9;{gW?KFvFR)z5XUW=M8DfuVFAeQmi9s*{GgHTjIUc{7}WY1 z?yrqMWFnMq9Yoyo;vn${%%zL32)Z?uhN*vvKZM4sD1ETHl?}CQDwlXndXV!P_GVGc z1TW{ZcgFQGK2}P&#-Cd$=;76B)|;!`rf)?m`>`J9o{vS+xHu?;|GN`_|uOH|N_9D8zFEb6066e*f?%spG9%B>htr{a??+S(&;1lSuNP++9i7?XLhK z1$YN3Ay^JnTF|Df#GJpis?Euugh5pik{3J?qz`CyJ@^AeR8%sR{aQR`FsLYc;YG zN!^hsvj@*dvysL&D#>63l}3gz<)Iis!x8ap*vC$D?1aCXmJsh@^_qv#=Q0tRzqVL~ zo#(Oabc4FqPhv|ynY4XuxzpL!Vsq`GC`?v^c#Q0)Sj>OaoVDQLHhYaNe3NL%ur>{m z(4t?~IJ=&7h#(iCn=*}F`(T-9@f_4XMkiEed!ClgG|$$Sp2nFGRB z9wd@i@8!5U-SmYazc5VQLS%qF@pyHWYnD@Uh{Yaicn<(Fpm-+U>Ud@%Z2g!yxycD^ z$0D#wfuat*tMV*`=K3z^F2RKJB21pL<0#5{FjkwbZ~t%>)WWYEJH;K(u~5QWKy{ z_-AFe+qCb-h+^c>eEc7>Ra84lu~pHB9au7QN_2#SLm9HM;jcGcV&>Vp!kqF}g?9Vh zIiVYgeNfsxVs&*Xr-m0+S3v`8n2#YBmYkTOs`z=#UN9DKpuYq{qwrn~iI^ylyQo8G z;)CV$MlO9s@v{)6-!U_J-V+?xJ7S};(c`)K#JeExJG#iDo)Fv@p~+M8eu^hcF%~hM zT=Jd48@Trs-zRGBx1yz>K6EY!5Sv$26GjcZHPal{7!-&c{xcBesLd1Xfeb0*|2hyc z{uc>eM;=`Wz&Dp* zai*l6+plXqEpXte?6O-$eo~Oi2$veGjs0#xC0QHBA$0C;z0(#eRj!&VKhfT}Hyws& zt=%zQ*jsJKoY%48^;SQKI4sf8JkMb6gzNY5didx~8|5a86M>{sdT zWFFZLIl?nLe3HC2y@5Iu1yX^KCiqMRQh`v^YjrKLZwocM1H}Av`wta}f~x2VkCy#(pne~!ue3G@3@)<#h~=4`TuN_GIIOMo@btO< zCs{hb?h0Y&Ps;X2I+X3SEw?G>(fP;c-R@Sik{ z$*63FuEm>#9O!SXn+1IXvyM7*;d{Ux2o|H;3nxq&ge`4D{LhSQMY+;uqKp5u;4FoS z_z($V$ihN^^fB6+IIJvbTH@WrbrJ%oPIDaek%=ycxjvQOz|8ET{>VVAKU!n_O$Oro z^6t60n~Ls%E|@?aca*(ckfLeyCJlGTre9W}l^Hg!L{rdUSkErO;!gfR+W;HW$And=36 zh{;jV0Etyf1?n{<)YR0(I_~FUVc&_xVo6JKNOJ%p&u9H!cRbZy2R!G`_WLgn@88Zd zd01TbC)eW{&Z}3AvBg#Gf6`%wTHDmB16{%hZ2IZHtsojrs`S~QXS>4+2_qQ*3@8mS zw_W<2`@qq&F~}mwWEq*{QGN$t`^9fjDimHzqe!EFLL;Q$6~`8K&8o?)3AYOp#7cA7 z9Psp4h*JoiPMJ<(jAKly$*A$GiK~gK$*Kvp^S#Iqg*1V|36K?56=wU$X5Nb)5ENh< zfEj=V+Yc)PGX~=n30V$f1&ar(1+xm%jZ%eTgJP5Vz?;taUC{b5W98~mK0qcw57ucY z6M%jn4`UJVEx;Rs``)`M6q*$mc@~z{8yOd+4ebfd{E$##0(rch0^wSpgs@NCHG?sg zF_AI;0@Z+ho4yy{-hfAhxDg9woC!tlIxC!56{DccFB&b2w1MP?B7!)AgqEs;vVx?7 zN&!-zDuGmmScPg2^$L~@R^>wlIgs)<2|h7CIX<&*B8)1GDy$0pBKbUp0>h<8pGKcs z9|MG?Z^7c&4;ZJK0)G>5VN3&Jl4L=?=wjWWC8}wX%Sf2{qX$9=v7D-*YS2&Za-cS$ zeM^y47gra{u|+>zg?M7$*80fCEcyzwKsiq`Pd2?Etl|}d3(yo)msFQk7tWCuVQt$6 z2rCM6`-*eO=4%B6mBK{IpqBB+a%W0r$`!~_@e7$tKBU?C*~MKD_!bH7aG^^%O~q#f zaQX!cTFaG*ZVEFhqWxhpQ5$>#S+ zO1q?8$XJaNM4ZYLb`2L?pL+GRn;8hgfzYJK+fU(?RerPc`S@k4-w2igof5T#DEP>R zph&|dK+`>7c8QgKGlO)RlPH=h0A}8A7xcahiw?UA!x|ek2gfPYyhFa=5VqnOHuMJg z5~JMUE{8~=z#`WvoMX?=7G5(yfWv)CyFOGO8bB`0BrGNDhJIkqI;l8uV9}bSuruMB3Dn zc|g^iXt!LyTjpeo6w4*$M0a{O>Y>egheVF8t)iOkjQpr2*RvWx+=UROb$$oPvE@ugv0rpW2-4rCJ{QC}IZa8TR zFac3y3SNOu?eL{t!fCaEH+!GfGk(9g?|Um30VNDL zv&K*3DIx@~e`i!AL4tdj{A!H8!PWQn15x`WpqwK1OyaMDqh8GFf?>#(xfxs(zUsc! zKzThG|5BZ-_=I2^pOI0~K?N-ugfPM!U9!TtcJpt9=Xq6JMxV?-GL%*5OjXR_ z9j)_N4acCFj?c1@h7)D%_^D|F1h@y~bua5% z$RkGI&sRoER_A zf;D-&b*Cfsf7{p#W*O-iX+kuy!LDh~B(=T=l9$6Uy8-DzX@rPgSEG=?9dW5s7TgqN;8T4dwG)vEv#=j zeao>H8k8Ek9b0n&OpB&pc_T&W)-gg=2!+(vF?f|?61l$>Ld&97+{dcOtrbJ5Pc7g4 zthy7dOlrhIRl#qynMx_zy~0)r%gpvVV`<;h(m+)~Z?V(TAldM=v@THe=wPj_ z9mj2Xqpd~K(LkP2ZrNB$S=cp0aJb|mw5+nmWm z+Sx*I+!vF!xTFroNpEd{KBo=Ug6x;hlMH(Xztv?aWn!lXeXp0K@*&y)QwGGmhax06BKDz0^f?Kl%m!Fo&}vW4_*ycy&m_Y7Y}@+EomOw7W{&}Zb0_SxZw!;mNl%d z&1C%6DTJ<#oXEx9hjYgy){p0s7grbTQ0Lg72Y$$n$gOp=k-05C7+pfqYf`M9F>5P0 ze!K_5`U0GXW4~yLVy*{VU(f^OgQj1!mVOcc)^2#y$4%^u)5Zd}hdbZsWK+Bg0+w(J z>s}Z9m(-*Na372dwZ;Oz2P^;Vb9v~CC1`=E=BO=O$hX2Ir;qOr7d{43W*4>)?=~`R z-`|NL`jVUi1<@eNG-eS$vW*)`xxmb`hEwnnDdPh zO@`t+MVoZv*CP(|yP<#s;+sf~AB9&>Mr!Y9lCdvWvY+Qnm;PjmK7q`WFBgViCaoLP zco4LQdK}_@q2F558w%}rV)-sJ5>8A%1}$bVzg^;CYdn}<8k7tJDI^F1h@b0m+A+9$ zDl$;M8Ax%qulgZaC_6R>LguUiMOw@d!Ym{RNqZukANtm^KfC!khcj_?ThJ1c^L&z`Waxz`$S$ zr)cq^g+b(mutDiZ_>u1B4D&Y4C>VbrFRG379oUIc53{BvPYN6u1u}>js!CRj+`*AA z`VRc~sT()|74ty8$|(s%2rd3OBog;QilhlPCILoD3W!cZ0~yC%(+MS&Io`((8<(K5 zOevx?KnqkRF6AJ!_OF+T+JjM zYGh%e?~a{(i5-5GCq^494zH#Yenei_!Kdk-n2RV*qOKEp#E969ebq_w4Gt75vAi!lN+B7lyR9tQ`jN(`#tVvugZLNbDz79>!2AU8nq;9txC!zi ziY6Yk^f#NgfD`&04ykhWZ%H&L=d z0#AtfP-m5YE{eFr*4J2nzfm$ZScN$<0evs*?3j?dSkpvI)`z3Ut!?;>CQZi*zsgT-)U_b-11OL%6?_E=gwA>4F*V?U!9Xan^F94sasjUr zGC3upu+6Q~GVu-j6RrYN8*a4VprXPh!s?PjDS=AZMt8n~MVrQQlu)5Su2KWtreKhU zw;2x-jtdFd(>m;Mgzxy_IxlSMQH(~?DZu!v-#9{(ElEAIvG~%cON<6O^GQu+(D+l# zBjM_O3>P|czT**s@nq2WVTJ&Fs!Ohe6JLh^C{~U%+^Sni9F%I_{W)|=UhZf(aNmF| zcT}k!w(G8HZe)!@2U2vxm+vYCT}DTP~FmCmVeuw^*Yr0%z4)3ZI;NqUT! z`TZB4hjPQOZ4bqf4?Z7?5glyKM1Po6oAJ~+@I*w-AKT_0GIC;i@g+fUd_xb{Cq2MR z37CO?`XW1YsK3^y;u&ylE!&@$@!sb|JJgC2Zsa7i-W!LlBj-}fDvmYBM;rc&bMwcQ zy6-i3MMz==@U3sWM|Se#XCsVB_KL6t&edA(#jW2x60yz9sQ!%?Op~?hcy7`#REvY| z8M_zu6;nS05o4M^ZVyq#H1lou1}%rwW8oPYP4aufW$*v~LAjjZ2$pW(I4K15rQ-r` z>RZe}UDel`L|ZlRn7my6z~dm-BR8C01Y=pmr{?nk=`v!wz1+arvcDtRov1f! zi1GX|UWH_@?sB-}r@Ntz45D8CltC`UXG4KWu}hrs{fwyBOO44vJ20d@ZG1<@WJg&1 z0DrFJ0p2}{HtN8~l&Mx$OkxIDMX2ol1FqyjgJEQTMI^m}WX|Lt+r!AXiXS9)s3$S( zS);bKVSntXPvSfkZmxeBO1<=xK$M8(8908VX%Blf7Uv3=yu&;x zzw7Yg=ZLQD`gEb_VExE~4d#tnlwGa1Ogp&mJ4BjKH=w~9{Jzz7u%qpi?{{kEL<1G}z%^?mWKVf90{v3fS55c0bq&gC`^?^r8GR{wRz z^A_^(YVmMi_ygHN*8}>MOwM7j0GaLl4o*izGMCvd!*I1+p1@mB$7Pt=rOO_j5<*Y8 zYvQ$FN6-@2!4}a2)q!@0F9#=bU%G4jHE6%%%M}$U7{3j=!C>wXOg_3|JqCUOZ1L@# zN+AqFD`C@4Ns$z6HPc^q0KU=S1N#d?Vo8%uA!#y{25LL017+YiR%Mi2K`ve!t{Tu0 z7>cU&Fww`Z6!sk;)TF5N9WczU2}dKwyNXSNRh6Pix1C23PVDVij76 zmqtva2}g-Fj$c8%HV=)&&eNJfs?A0m>8%C;9nsgcU0BejWsCGEqVR zxo8I(hw;9{4zdQf~B zMPBYoU_~^mJB??(d^pwpoy@xMfYr`PY~kP~+$273(WEsERr%b&3)#Xd!&{8h}Zp&{g&t^eD?tDbGS3Q*BzVcnW_#*05JX zL=h-!}Ju|Y6yp^Q^ePq7WPAMs$hR>heIUgfF+uRntmbj03%YCWWQ?y+@ zFLA-QKh}}(bDvU_?K~e=m?LnWhmNAO49d?>J36f7cS2Ai;tDF)hyqRhc6DxRjiR0g zYGo(vfl7`9&-2Am=*KKS#Mq|nbtYVR72pj!j;~Wh8ySldGy%%0bWx?%NdpZEGDdA> zCQPsMS1F#iV&mqGq^4n-IM=?K7%cLYQ5vO-13+afqb{Wr!!G3$Bl=QACXR(6_4XA2 zo=Uor@e(+W)c^9fwZ%4dDZ&9;JRaH&RP3VIdqjv!**JJpjB&A zYm<5VNzS*Ht~sWvG44fYEuQsS?n#1boioFg)5&>47rs+xjwOB?eDJee?n7@4 z|K~4}XBwJqSSPOcP?=kAO2KPXPRpC}y&wz}rXs-4r^a`$>?He27SGlEJhSE>_<&hwMBjn=j#msIcZcEzQ; zvjyjlA5J>wTsl+F>E3J4$yMj!Gl-r!*%yV!R9+^|B6`m2!%Ko3ca78Xk8Ov=UK(wo zwly}#cvb0-l!yCW&Cc+f!1dW?$>yudg-S0TXS_{=^+gxW=4+kVQ!frD=p z>=K@5nPd95(YEsLsICM4yz!H#Mh$_n@<1*`*%O2Pgb*iQHq| zs`s}<)2}a7w=8er+^arc?(a9}rl7Rl1&M`_5eiN+1jRD(N(!MNagTa^*|`~}MUY{Q zPhJFl>0u%kMZn{49ewX_uYFtH)%8=oNoo|kv6svB;PB`A!4GaidTiZ|w;1?7VdqOg z3q`{g9oP2OJ^j*mewD8A^=4ZZj)wm>v+J+nE^Jqmg$-J64KFtx?`L~5()-h0+AcN= zSG!yf`E1@60{Mi)zxYH>cPL1lJ`&-d;U)Q2hCC+hMb0nhLqIeuu`6?Ebg6p7ad~@t`H=J^>gnRe z+||vG@!s*q{-*k>^TO)I{buy)^`hiO=^f9H*R7WwE>Jl2c02}~dCLInbz2Sl_|zQ0^d#MP@^l}7e7g`3_@vp#?Zsyh{YJKp z_iEM$=|#5P)`i1-QyHVTiBx#lE&R*Lproh^-Lm35XywEsSNF-=JjNRZ7nMmko|Kf8 z&k%khd|9NNG-^6ZQua`ioZX3i2SF!vAn;6F+rVXjfFA8KKt`-%+Y(jpAv8o_jT;T- zJ_4d2oD{{I#Bci&6~~(jjVKFU3T8@KJ`hX1Z#yxTblW+0;KEmOw!gb17(vT5S5dYC z;{<`MV^$JyG6*FS61k|i`q=&@2sHvd{rz74mL}+S>ZS8?da(PgaHA%a4*A`^TeTvu zdp3QO9_@KRy8rbrvGInD09r6yFfe=C|Ksy^|C0k`Ap=e_jfrBL6Y@tXZ;y0TtoA<^ zDS(wmwvGi@eF4NrhCk$!$2j?ikXWwe7M% zlotV4o#H`yU-92$v7_1xSwK`eFBc_-WnLNHC-*^mrffu3!*OYIvsUd19dYaJCfm05 zakPRV_Ei)2-h(6?yQ$(oyzb-aA~sW7*o|#>-Ddq~&mZ$HEy)YYsuc}1hV3V}7}so( zbBMf-RNpgnh(!}k>WdB#74|~|ASg}&YZa~IkmffrS4_UuJG6$M@!xzP@{6z;HNQVipqEO=Vd(CkKqktZ3isn$k#FrSr6ZuCY*<-@-&XpZ+>!mjaUe zdYT=PHcl7cAgPgH_~0~)iz)X8sdH2Hm3<2^8KXKNtLDEM1KL3L=?1oULSObBW9~fx zMLK!9;R<#8%g4mXnQ8ts8S^8BjXYX`N{8s z0`H+x-U@Pg=^<@)um^ToUG6lAgqom*O8-IW{&UKXuY@-jjl7p?A@nawck~}hH^)rl z3gWN7DBV01Ekg^S@odDuB`pYmfq~gNm@ydGH~}3PzOgdc88|qaFbK)1$SNuP`OtwJ zXkcgpG%=PnaW!!e1DaTy*f{Aqm^e8**!+zJlo`7&jW2`}D1RQk8x`N8@t#Nd!5`(e zuZxi*4<@_>#((r|$NEqwd_qz_`sOAix{w&EV;Fqz3q-b11x_ILQoxp&nwna6^$Fnh z!L_9RsC{`79CKAO{ZW8!a*hir^E@{nT1PXouS*3a*elI^f7bfFcoKgC=$~Mq zeVcOKrRDirENyA>{aUdmo~mWb|aX`#m5ej{(flR1+`Vo zhpY6)RC`6)D_={KG|j-0bs4$k(PAH$UVIX7#J9^tx!{C5X%4c#sd22e}UWp=p<|5`1dd; zDy~ZR3!?C?hSxH!Xf|#@7V2X-5#4-2l@>zvlg9H*wAQwiPD_{=I#)u0Bzgf8kj^OZ zTMRn{F;jkJq_T{ktX{)^=c`B?&Q}sdx~5Ep1ebwI!g0`)8mTb|F6$S|@fx(fZ$%Qx z4wt+}r*P-XJ*GSOZt!~=p4V$2rqWsmtr1lhz0usmmp9zQx)gurjz+mjMC~D2*iGss zcKisB!7v4_tEp2`kEYZJgHgR$h*-5BOOd>EGC1%iFpRu9o9o*(slBRmihNl_)Vy4q zXk*iDGMg!AIaRaYGwI>Q^*6P)v{}>75s9CpJ4LOJ#)j7+fCl)G@J5WZviU&$K!XE4 zB^-8v%TGuROYxrHfkR!uqMRhWJByc<^UPW~s_{7;9KJYFb{T#eax0~QBYDfmQ>q#d z2j&#X+=Pk*gIHTcuoO`mYf+iV7^0ZgXYnjNisWO_EF2O6(&x;Vxjh6^Wu9QtSIPwk z^#K6f`5#1mfDH}yAVk~$Eu#N$-25Mn7=);agN=cc#W$0`Gu}kS5ovHC6tB!drd@Nx zi06-C`a8YiJ6}-!a$tlgV08=8(>a;v(B0h~054>aiWgg;O;Cmt)GeZ-$T~V>9;($P z2gyIEz*K2hh7CUjBNSOPvtaJij1YH@Cokj1Hf^0H^cRJJhUi zoM3F&{j~I(xnL|&IqwYeKy+eBha#G^o6cFLfo~LWA|&BjEZlDYk~N+J&ry(e5iu`~ z-OMo6z#97%VKP@q>D-MJfx@6nZ}27niK3dI@i;Pmd7<2&Pcm~Mu_%$YUbE`OBonQd zUQEwUzJy-DMsGAKw_zQDbUpUjrlRe_;H?&JnX_h;%wj;2RL5riY8>6F; zA7_##yZ3fvagD04t#D!AEIvnArJgih%%6E>(VBSuC-jB;Y z6_K<<4#WCuMT`apqkXI*L*_I%n4f%Y>~kZEAAeDD2yNM;;&xRBp2O>uEi_}hH|hLJ zBM7>=8imdMwG}b#IjDNYc!j65B-Wolsz6~5cP?tq!QYL=vcHCi6I4j$RXSe9{B*1$ zgKjang-=c4{1e@PTB_l3VIpukcdxMDz0e)Mxa~m%{mQJdppF^AHLUkl4CS!vjgV%R&oFsnYzW{dGTNsXC z5LK~)!rC)9yT3~*CYqS#VA0$QH%xP=lbR_)FXrnStJ?5iSBMkVBQ4z7VZk5Gi~@V5 zCXY0)qkq6GJ+Zxz;n1c=kK+vEJ!M}vVGRASw*hj$&@dDQyPrKk z0FVA#fSLZeJC<-Tu(mdEP;oFZ`D)>4;biMTE-Eg>@}C;D3G06dgM(8F1x@sYJH(&7 zD?(NI0 zBFj2wh%i2xeFR(sL^MISnc$Y;2uoszgMZnGt=@#~r`?m63dP1W=Fj3Msy|#lPDM;7 zDgJQwWAarp&GvXxH*H$$DLr~AxVnv__rO?kE1Hn}rkc}w$T$1Zn&QX8wN|6E_1Ag# z#EiQ*wXX}RCisNsX%qO`TRrpR16wuU*$&!P0Oh0iY(Kr8Wfsv-i_E0c#4&x(d=4-q zRh<|MU+e7I!GAbH8dGYy=QXKzm90s8bAed2+mmA(Ni-)o!6Ghak<(KiwD@AhfkrJB z+q7+T5eB?bT9}lK7P-UBgUl1m{u=Pj8vE*JHEX{@(Z=|a+>#(^HCv*^e5ph@s<7y> zfU1ZM_NrSzt9E^}-_ST7c@4rj_uyWha-%*O0@>(iT^D{TvdtR#~o zUyt|Q33#X9UJI;bC}S6il6O8V7{VG10tu8AHP_Q&9n3cb)s_N zAr|kqbksd%RrA_Wa$>X}mg%)m52o2_x zq(CK=`lSF9E^QS8atbIGpMpgiy2GAaV()fQh&PEzHc2Tqg+>XSM(z)jh+-0nn1}@o zB)x}HUi>T`F{mt}b>#h&MMFZ+!$S`D#Yd)c%{bhMRI|bxiQIm2HU-i>(pj1<6uYdl zZF?4A*#%j~?UTQnWr|Pq1v3@C$bh_{ z*U{2SW0NN2l%L<7J`yHFSh61}0NMIyd4co%uuapr=`-?+P!C%8CAO*)DNywA6RTWh{hMrVn@yqx_wC?6W;qEMVRE zML;N;mU{N}*_4?aV8>qfDq_+ayXm!k_oA0p7M^XM4EX8hokcwNetoF$nw{))uu5b~ zvLnCHmUrx+Zg3;pR394S@t0kKwuXYC$fwQwMObl)Q{#B3sZ?WgJO!cIc zP!P3&bYJ)!kP8#0P}We`99LOe1+1q?KXs%D@x$W(j!ZFG<=2RDNg6*g{%-OX(|n(- z2KKDp7(3{RghRUwz@$r{rTtrCk&kWm1O+zuz-iq4xu z^QCp(-8ZTiXOGRgFl+7w|A{#gf5n_L6PK)BLTV|JY{^n}hi!#3PdG+jVF%Psa|mzI zV{e$Ge7juXi{CIW0XK{QWDf=z6dLOyNUrTh4W6d1@q>FX`HsVPBb2w#9 zOr4ZWjGP@DK}n(#$dJ?wfL5UT&(;}~Itu-Z{IO7xPv%el=<&$uD4u^=UW=+^4%a*_ zhssI{6D)>Cx;(s(?|fT_b$55>qXCQgmvOm34UnoYcci*qo9_2|dUkb!bM}~ihx_VP z@u-eve#lzju~aN6xCS#H-8ge5np4-#fmU)C$Ae}bxH7HEjuTH%W6CZOkKBdQH{2T#} z#=p`QSz!popN?y|lcONSjf*?w!XvLb?%!vtRHc>l-`A4Z-Mx=}T+gOpXOWYay)U8#-a#42qUb2i_!nP%lnV)?;l(qs8;hz_a0bmSoq|M z321=6*9YxarJ)wSoKDg<(Sp{IVmGNf^0_o~MdN({e^J~aha=S;&`C+X-=F9**xb<5 z{eW-O9*OHt!Y*=yk!H52;Zvo+!x@2boc}us;BIts*d}=}z``OQa1>o1C}r5+G@xg^ zzPYNMD+61&_ktMDuuLPWHi;UI7Joqg8gD=3vcj2NqlCX5WJvT}`gf4K~2MB=LG}7j@Ri4$|Ys*Llz<&9(?i5RB z68sNDVqE?u3{9H1Zr7p^56e!NiRM(gLzal#3J+v*iXd4kzG$ zV*e55eH0!DhfUD!|5xn!6ZHS?g^!HYk@+YD2->{NpRkr;d4BsYEJ=|T-uC$;YM9_B zm5y*+>zYJoHB+-!9Z1D#F@YQ+j7%MWS+cei7PCpWY_4<0bE0ZnFr*p_($GQxnmRj8 z1-3d%&1B59v~*BrSuwYE%Zj3>-EiXpm-a(iHqFcltZEfU6m}74P4OZX!liJnl=)yg z8LLjCjvMNYrV^XzSgv%_abw^dU=(ReZ!n;%*((SKgY!yUihw$~m)k|B^i$M@m()aO zHvN$BULm`=dAUQ?gu01RJD_=r48*nCRXz3 zi{47AjV8USxRo#6nsRQ&!;9|tAv~2a z^)Wn#c3@;x!&Jh2>=jOh$Y!$T6b7i6t-D;1Q7cinI##UzDiEsNxVGfifn!~oK0-bA zYg8|YCboi%9?~UnbN@$WR0CV$gg6R~))`OjL0_@jl3{J2&>k&9PmRJri7!{s?R%Sv z`lF!Ap4E@|4yr1NstT&SAW(kZ+jl-uE9sM3h-}(0j4{ai%Q!Aiib~GIGg-$AqCKBH zFjrJs>;xC{*H`)P27owmRy88e==oEQhaw_+6sg z@$am+Fm6*CPY5v7JwmhuY-U?9pYy@Oh&>cL5I)BZz&57|fTMKPqFgo7&dh|Zujh~4 z`rJT_*>M3}@2eb|6-{j6{q zC8^(Owl4W;w=w>peO9ZyaJ1uPMN`tbQVEq47)aGS#B-Cc)zxj_+YP(_WjV2~I8WTu;F0 z7jxY6%8;4Y6?n1iH=vHRjnSF?Z#HaVRXb;R*vdMuo7qIA0|_0@+aq%XjW@*d}!!gXZ?o)847nQmDn6mPq6Bu}TztI}R#U+F?tUw&--YvtvbInr(f2>a`Qi#^vr z$Ns<92*Cd~LHK*fGh;U`LG26>_TB!j{D=O=Pvs^f%55sPiP zxw^QKBS;JCj)gOkRMOE2i1pWBYWMhqLj{%Ru<9hzNSWy$%|{9sVIY1C#qiC4k_u6^ zeQ$EC0t(m7;eC59*05|&ayAIwNLXVeGPf#r&W=r^yt5AS>DgN?b|RS2}y#*WQ6c`hyTrpJ}tab&-|+I+nX z6KEV4pmVKdiV~arNhOgjA9w$|s^b}chldK1cf3%$VhS`o7>9HXaNhtOU;gfsb8(9F z;*475g6&-g_AYu!-|_p`$22$3Fx+$g&BP1*XvI#bKQ@j=kemgvM+ZF$1r%%FMa83mOQwU;6VGvRi{H$~Z084lux zxFx0J1g@pofE6RVC|>#FIy50-*qU3Nk;G}=y~15k8xl9rz0nrzs7`ZsewXFz633f^ zq_4j942Cvr^`Jbi^-ornCM)lf^sAo8oBgiewBq{E{llEte!ukb-QeL72H!1A)St-@ zr&(+yt_T}&KWRh?H5U1ZJtun;MVdSfvU<_wOQa1`(olvPTaR)+mLzX@g0&YC`^I8R z5B`S756dJ3%O4)}KP>xjMS#ZPwYMbXP$jw-`r(Q%?sYGlok}6(l)P@w`nV9(W;WjV ztId3Qc**7rg0<`4!YcmHVf`oR?*BFpEL7|TWxWVqb2jbYD!-N!yQ2RoK5{t32J%R0 z30G#zWmj{^>gy?Zv|i}s{{UUTNoHEUB?Qq6OMXt_CZ(^tnXLzgug@opQHfGcvI2K& zv>PFySaNoTh~a0$P7?Ul5MKxDD8w~K;w$qhIi3~IJW%>A5#c3s1cSYjFt$)i7daG3$#IEg-={~b>F@|GE=(?H1Xy8Z*AkcpSYS#m8kQ=BH`XEeOO zD)puB+Xkc{RBk}Ge{F17{}UAzTU+4YrmmHq(4H!)nD?y|ZY=RwFgSjovzo+oBPe2` zh<;EoDQpn3q}X0!820N zcgM~25pvn@uU%6_t><0OXMFc-b5orzp7uY;qS0r1pP*&1gvFi(O)4 zML(B_@^2@~j~3HDHbi?~;Y52TWl!1HPEchhcQ@_9uicAPdrEZyN7Ou>N<0&_y!#uM zJol2PE>3J)A2KC?y9X!Q9le9;+8u*~=dBOmSU!6@^4c8}gFMa-4|{f8)*R$%nc~5%#|HSP)bl z=!CYfMQ%pCn|1sYQ+$`G=U^?Fg@y7znF=Allx*{ zty~$AJ99lNwshpZLO<@XXsujEjoK6H?bg1lbi%J$4u5P|c*_?gfp<*>_01cKQ}JM< zFr8;g(z0@}n`*>Kd8V7v^$H4t^H;z8@i5-G=udH5?SRUnpIbxr%&;&))~LV5t6FLH zxNYX}A4%P+2}#ZB0<8-yLjCHp(@Gom9OG4{NN&BHNjTp)!-N*K+5`uSNY3g|I`z}y z&DUcNccfVz$I3%LxAJVrapi}0a{|>)o(m2liM z;vq3)n6Pxq{jdVL)*Z3pM%=2l;Hw%s7iD>zxzDoj(D`Wf~<2%+=GG5R0-77H}Gqf*U2>pN8?H$N4 z)ZJHBFSBpm=>&AA?;DKD_3Wr{zMeUD?cjPxs~f!Q)dH5}3EWvHH|f(mmL-3TLj=nm zOlNBDDmRz$y)P76dP}eGt2&n%yC3s(CcCeV)o#qWUc8t7&7?1aryxoGvE>Lp8+^f4 z-zA8IjWgvOtSyU#3$v(=169Q8S|s0=UPb<*4!#TJ0w1}73O>r-yNXfldsKm^5})Xp za{8xOMYM6twm0pvL)Y|;6I9@*uF`-jRM90^y)LWD3_p`hpDf?5fnSAeHEVoNxCuUS z$PsVv@$^ATy$=FBO7bON9IvicC-!_9vgb^|BXu>5YP}cMO;} z{dASBbWZ{KTx#9JjD${CpmqLZEr?k(gxVL30?g`PY0@7Jh|jH)Dg|CkKW&f$vMbOTF|@gb8gs#XXM|fBgCmZU5obi-j^A`41!#-e-z? zPEQE=Oj;zrR*M0?U|g@ol2^BpzI-<2k|~lkcUJrJ3&m-Y|GwEScID$)Ev8R+_8Q6~ zxO%cGklfmz_a?CSb?cFQd5CNw*xoIM-nG`?@X-<6~3ALFhGwV#MRc}qA~m!K0>DtsjjAZvtdA4(U(<2ifvC_9Z!** zIiZWGzks3OF$8=cWKfW>hTd94^Jv4j6)dro z#lW#BuL|_$+6m7PGvy+%jvYE|@CrG{u+?SZO_nn9>B11x2+K*1L-5AUDHdACWNn*@ zq#Jo5hOIWeBR5Y>PWM`Gj52>}(3%8BXv`!DwD!_AQ;22{!bk|Z({iezU&qo$29Jx7 z+)PgL(rp{YUgE-hCAZ{`sY{R)3PJAnS)z}lheRdLiz${xQMYHc(12Rle?|FyXqYMA zVV@C6M|YMQ(=uZK;uga1tO)YbC{s50*9kYBaCA%0cF11AhRo;C0 zEQMfSz5$07zaz%)hR0Z3-rt=*rFH|~GINn|0{7ZVTBH2fLN2|5HCKUOB6MPYdF%;z{Aq^1SM+;Q6TMJIQuCgTqQi)o0REZ7Q zUS`g)Z1~|63kz_!MYzll{HV-`VRP*1MbHxL#W~E&e0&sEyW5qqAaHcf&NapGU^8*; z*`!6U)gYC=C^AaAsphd z$1(st7x8e`$%&zwqdSm?LM+npgPbFZ^+b`9a=q*9si#S~)th1gc)#Ox`<`c*jEAnl zhmkoM8C~C1q&Tf6t2uM=c1GuP%0WlQtFRf`ZDQ${;2?_-Fpif9H1(q@Xd-$W|HMn~ zQLL3<|9W(B^`Dw5&Q8xKvHGD)Klwe?hx8!-x!c?~46YWwpPtMAi z(spC|DW6_`>>i@n+}h^QFa~?9!2kY@>*mcd+uCX%(G(^W!_9z` z#Y~0Hl#2Lt*qz(!i(N_AFCNN@2~=}|4FRK5&-($eB)B4g zbTk78nF~wFFC&@D3di#BQYKkhNQ#|;rz~_QK)A&>iLM~X!9c-uMs08oYdk<6Ba(aT)er96Ol=xszBf1ne>GO3lUt-QU9}d|kllgR5dfXss*)MTdMF+* zjUUEa!qDEyvCOTwg6&F()WjXJ=S$ac&7|2 zbHxHozl9FA!TgUj7Wqn~0>v?p$ITCj4(@9Qh$H9w##`Aqb1M3|H^h6X4k2?h9`fd|QdspdtcTMZAS-s-4Ux4;#$LtS%D?94}c2 zynojsq7)1$nXgkd4oftQFQD4_*XKjkUf}C*yd&|CV;}-ywoB|d#Nc9AFCVDrZVe4j zfBL{;wz@Qg$85H@g~srP`|x10x|P;iM$6LkPpvdP&L?&#>C%~UW>|t8tq#*|7 zy9$x@rZ!!LPtNUhSI?pVZ3cQUrPNJNc>3`Z(13hchD%fS#z5XhuqH3yD;|Bv%fq(J z(R-4S%>xJt@1A_C^F#Y>pz8~8AL3A;`T`RK|00LxM`-}UgX_Q2q;m>g&WDUh1G~uv zm)zQnv(ogP-4$gB|3-n*R;Wj0w~c!#?^JrqTbk&XfX!I!Et5-)ZHx2F+RY~}T|dTv z`lrgNO1hx;4JH#IX9C#iTBM%_cag45U7Fl_CQ`Cy_vFf@!i;sF_BP&XH1lhhJ2G0k zZk5l;mGY=7fB-%_HTG`7cqTo8nU$pxyh{*W7~=Y*K1tB9m4BJQejH@EAt zp8l?`>O!Y3#Gh+=28k;^u;X=J-pQ+L`*UP~fT5w$CF~QU-TKI)Az6Owu?+SmxRl|C zYBzat!Zw?(VGU!j`>tw_#ii_%c~|VDz5lNsmAQb-9qLwK7@+s76_Pdv3p zcTfKU=Y~&O*Y-lSy?;uN_S`N1Uz)p;*0pyH|D4*@dj75Q1p0Uai}i*#KrTi3;P;ia z`v{gZiuL*Cesaf)ogKF}f$=4;mg>#YGN4Cx$M&+*Tf5f`v_9SNCJ77eOcmG8|4+~C zN^i(SwC%8aSN;e1Rqv?X&I)4vKsSkF!?7Q9@f}f4GM>UnsFP9u@R(ufZQv_I9h&C) zJ&bp0E#ZMeJ}HXD*XFHv#HgmzODqZB;LANo+k!s63=a;NeOQh zkS+f5s4f5ETF&!n!1a=D($e}nvVU}K=i0fz2+ns!0Nl7vE16nJd^Sy4iKqYuTsIGk8cP8}*RrQ7EN4qm(DdBW{wsIK;`|hO&N5+`{>xUk_qSp5lk9=MZf}iY!*Lu6nopW| z$rzM({V&uKC)v3p?_&YoABkRwz++Iga#0iW%OWk==E}}d$M%Tn&B1N^-b28*!$Ot~ zL@ah1D{XvronuXbtDL#~;bSqajSWrpT|ZBU%}DG7POM+vA$(5jKxbih;coMzF5tWS zJGAu2>QeB$_3byqy2iCAN7Ve`G_^w~{cHv%QG4?f?_al{DFbVx30z)~YqKCgm&5>6 z_aug|lVK&nWeO!5OXBu2r-tlbwULgY6BWwqdGTKr#9lN;p0amb@kfL?^iPv|j843tIqTUQUG z-IwAQ<1H^~s*4-#taftLz5SP?1c`5?&Ly9vWU{g4Ac^I{>)`uE1l?wGTYo*`r&9@_x3!htT@{4i~(LI9zif;pi7ShoMSQClhb6Esbh%AAG4 zd@CL;Kn#<(LK@gQ_|0;!f9=4?rl5@N%q|cdlh^Wx$IQV3FIU5(7;QhEyyhV3kxcC9YU-ObSh0QlHZ?qh^(7TNgRC6aZJ%gjM)+&K1Pl=d2YCY< zfDcPryTyq070q6ni5S=z`@&Db&WKl&9|*vm*#R;zdC^nE!XuAwYAc*7MV9%Fhj(cp z4-{x0ztTAxXBGd%RH7|0IR9%Q!!X?JGV42gv~SUo+<(yH!;Itvx~1GG zgqByt`hE;#|J{!5m}|r=qAQPJJR?ok)5`K}Og=;lR5q?`zc@0RL`YXFmi;A@NnFwi zMoKa5Ay4KU5z4@}5y{5Jyont_sL7XI1aTZkd*>5(;o)>%IcN^A&SqiaI2bKyb~=z# zA}5QN3F#a$;NS1{wif>`Y!xh?oh^14?hYgt&p3qXdLUU734A62G*ek%#V#^DM~D4K z#FXZU6j@Yrh8X)hq|rQWkY$6_BNms*_tLvHms1w;@GLe@YM;OIk8Q{x@_*a^g#L2l zR3l&Xo%H2V!A#vf6jGm?+rCPBkqY4H0iEaUj&vr{zz zx2-ACsq1apN}A>EII4FdLr8ZNzKNd)^VChB?Jm2S5?iX^|EVpMLyP5Q8(fcYZn`N_TRQI@i5H_kPBvbC*-5;D0#9J-R&Q#Oh<2Uvi1&#qR#pbkKm1i6l6XRi;|j6tSObiEV;+ z;)O^oX#_X6^+uKr+uWP{oHuNtqeF28NHW8;OpLE8HR1zeHMegpDp zZBsGJZ%5A%M`1}!quvFOC8;QyZ7?OgUeiy2!1W)`wZ`b zWyz#9-bdF8fzo-xBg2X0r?Q9K&R(fG-Ln%J?VP+ZsH@X#@1--|MDmQ1`u>Zxve zuRuUmJQ(=8*i}_A-cJUzHYM+9H#$AN1rb??Z;hb+4okujNLEHg*{IIi)=b^?GOKo6nG>I;%5R{a`Bg1l?qU}Ub@?>Y39PyX{z!`v3*BbZ zOrO71&#y;&hk9N3bNrRKmv_p9^L+<-W>1^Bcn^oJV+8h(VEIec{Zlf1Yh{` zi!w-Q-=ZG-+Q(n(!d?yk$Qg_GSQQO)|Cp)OjNS!4lR9xAqw`JIK-|4=l$*FNv_;=|{a9eeEyt`?U&i{ADh!xP@9>KmsxV)VG(X-7>(%7}l`T}!1x|gTp9Y!2}#?z>Tc;&VGHAmNG!Jnulj}k{jL>JGU>937ZCLZ1j4ycZ-p8GpVlE6eUcbn4z@3ZKb*ENZrAuNPu_=c zwj8UOw{C%A8Jj*buBoM-LX58CItB~dD~B7J9;!HJ#jWF~9lhV=ow2+@ z?t5($?R*T0CYRaV>_{PTd$7zyrE_C4cPRwJW|WBJIM2Z;*DLwuDAAre`#S@v@Xk&Z4ASjXZwT zl7rGq8s>MNKG%NaV?~3%DiJFg?SzFOmWL#6DoMxM=gBy5yV0Mzlq+XZ(#|Qf!~LBd z1KzVh5Bg?7VYDbKGVs?|sFt8MI7MOxN&V>Jy8!VKU-X?nXqx+9HV*;tHmlK>N|=6^ z!+efT1)S09C+!>lz2p8ne*wD(0*>wlt?jey*AE^q-Vq;Ni}-;VZM^(HjLN!~0llOC zJGS`-J@29AC$`EbZ$X>izd!uO_#kidNFV$~|G3+u<-m1K7p1f{k{^BydhOB>2zMtk zGL&u-(qm1XPE;fe!zIK}-X2Ro>Pu$3%)L8dMui{HlU2tM8p?Y}Q&yrZOXH;FCd;RG zMhApPEKBFF7u5)76$T z@dh3!db`nmV%|(RVOd|6BD}3yLD(`UWK#;%GS3vKM8N>Svp$qker68n|C;@V}gE+ zE?Qewv;7vK0`;~OGH1WnM?u4|Eh8zT)BQmGa!e)tuzI~!QReVF+68|uL2*Jk#U559lmge8H+VB;Qiqw!<3vf@O#`slt zm1*yGldGALFAY(ysYvdbNR@AZ$0(&$ZfBg%o3fW3<#JuwcUk;wOEpp9XHnZ(iO=?y z^r(GVyFS~W;2gl*=Q>@nsZiIU<~$W2jt1_8aX$DA-&R674TD}}lI{4V+MM422h0Ph z=>{rGIe+kI{v7`m^mQ}kZ8M*#PgOx#IS(=aGIV97g3!a9y4hu%8wsiIP>2ibSNu+i z4HR6=eS{m71^wEtRjYN4kqV0P$D+eA)rxL4r~dki~ZjGvMj5%L`XQ9=P)^^NuGogwr}q z)l}UTU1j3?VD>cF>7*ln)|QFH9XlL3AwzHqa04TTV|9<^*RWPi9wpl>$<Z7PV)xQOulJoba%e(hU(OpCV3EofWb8!9&SAMd+(6)Ky`KM8|=~u z^J6kOggS4D%lxd?4SLJQ|61S80s7MSOKD71eq704g)(o*Cbn#uZ7iv@o>Z2cPU@0# zu4qofCItHTH*UpxrRdze`_Y5aX)`eXIDKKzjtnw5D)56t5Ix2KFeXSFxveVAnkj(r(>K{cd9Y`E5S3jORlJK54GMcJ)E4_P zEQ!Cp(INUvJ4$$Sx@SxOSe@j-xeC#qDg$98pfPz)rtJL_*0*Hs9;f^YLL*CAK-?tE z&?s(LacB{u(Ua#!%vlq|$ZV=pzkQffPDFhNpwu%&AQX^COQ=~=-lGB|8I@?uD*cLK zXtAZ!<}!YQWVDiGaT!Y>UV{fg zdJg`oR1K6ap(Az1Gw7@+f&A&{f?(4Q&a^q^usIl|;HlkPV`tl~{IO%7MkxHjKIRV2 zwO8v0X^HzQgrLc>n5FNAA(heeYsR9{M9z*iFLc7<-CG*S;!00d5V0iGtsvp%)Syx&Hp1(Tp`S}^TL`nR2qY4v)qR1HNP3v) zKwS0Z@K2qX{DQulv*{dh%Z;-<(J`>*@4hIHSC%qnbH9jDRWp8An7n?u+xHJC*; zkM)y{!-fc_`}{QD3C0k(({XEuVV-rHFXr~h?y8gBoOG+_gB>zF#4Jx=wKVQ#msSMIPMz1vHW+Y6J-NZCl%Kb=YKwV0XVzQ^%lPZl z2+$sx_=n;}6&Gwh^9PAQ304RH#(K_ogdd;)pf0g_C4o86&X*%mT{-7R)XmOYN|wK@ zQ9H1L;iEpN2;XjzoCR|yK-nbupvoKL<3&IHiq?S284Ee!5N74?< zmOovnbV=NT?CQ+LnC!QDSa4sW0!>69H2E?;?s?6Y6f8z}f$Gtj+E3joJQ>sPxt%P0 zrD=%AYbTTgh!ET*<3T_#xsmYGN04I9B4>wB{N5s5U-NZXF?ydwK6CULPdXdEUzN+p zS2Gz0#k>3ljoSgHv>R9UT9-aei~|B6**V_>JjCGHXA21ZiX_e2+QE+kEJDe~D@zhb z9~K<;?YjiH;4_&=^j5@h2rqHWdZ@N$C+`frOXz6vPP#^~hu9m(J8r%O5WP_Qc%dKH zZNFI%VFs*fiFffk?o8Ao<&Z1rfM^g|vbKQJMeeQCK0@u0GE)Eb$s{mO+LlO4-FioY zlNTxL_nsr;-J_j2y!E{(`7G+n-L&o{=`@8m&Ogm#GD8?F$>Koi{Mz9hnna$u6SKvkvil|2n=nkD8 z%}}-J6{5bk6#c;Wwc=+1{MI(3pGKe7V`2JM%XYuCqom~27~L=hqZ|6?QJ`k4ypixr z_PLx9nZutEav&Hz>g$-uxnxUHZL;5lz^qFc0hw~Fun0MMLT4e$?T|%>DkkpHQ1+=2 zES(i`-=&34e7dYfjaanen3NuyZnSs>QQ#T*&QU6mfxhI@4EweMTjb_Y(Pm2`6lriF2qtK_SLRdapq>gvweDw`A4P{~3 zuacCb!ir-o`-8p-Y;Sp=BjfWV!%|6u6oR+3YFo~v?obHb`&%_KbQTylp>Ks~Rl#CG z!}4C90=bG~H36htBD?bby$JE1ZBNU*$GaH?Ps$?vuBQigoBJ=hu@Cw67c%5g?oH3e z+^$bl0?*A;R=SwOcJX2G;kp9q?Qo~ol>Ck~n_I69DJ%K0wApcD()^l%k^cG#0o6TS z(Lqq|xoXQekaVo5X~ZL$XCasJTgjE zC52Mud#O-M=8dnjL5W;Wr;!rSXy(rk0V7N?Agdmnzg=YV|K<#+!Qzn{=AXde8$836 z+i;<%PTbqe<=FgnA}?Tj#(~_PrJ(1Gd89RwKTBvCMBf2v-i;0b)Z4GJW?n>Gs0CL( zS1SDUopCoUCeR`!X>b>cE6QprvOo|+4>)`Z%fvsvgN%V7 zVdSxjJ^Q}~9!JM)M(xLeZs$Oub%s{QHz4F>nWXdC2N~K1pwiaSMr49;LVb@D(bet;s9tr zRtXzb#-UP#_)-Y2bO;Urs5IFXvzo`wq+PiM$1aMqNM}qUbVxE3e;mn#4VTZS+`IW` zf5!&U&i-CKUVjAeMF^w{MtpGX-dZxVwPZ<*t&eEU{*Ew%7o&|>S!ClL4O>uL=$9Cy z^TB=}^tm?fDdB#X=aKr6m|^c%LHNoE1c8r77}9IWg~aWzF4@XcGvzQ=DV&5XV}Z2* z<^di=+7dR6ldcW5-D%InPWt?+J9?zv(zKo9`@L zvdf>0Vd40flvtfJoMBa=el3r6*fWF(q6?mNpD)0XX`S1w2fblSB^mx^9Ywq0xP=(> z#Zz~hdI-Sup9`Y%f%P9#fe?PDO5BtV++XWX`JQ;j{u>yrqoM5I7aAGT8YZQ>dV>tiNoM;+-zhmGjtrewQdWFmPae`6I{Cp~K!RtSVn-+eyQ1XWi83;VKX=U>I#M&Obz2uq z*5WdoumLEo8$LeupK=;+(0{z_O8L5w`r0zuWBEvRheF;Xe79D;(9C0xAv(_m(|ZRW zy}DA%qwaIP8z~!+l5HU7sv-z&2;n=T3oI&wi1~Vo2*sYHb?Sq;=Ykq&Es3VkK(6x~o^xE^P z+AVneHLt0EwYM9i`V-#T6%kV0hKo>stwwd*mpBt3n6^Fy=dLDY5Q6S3W$h@0LG_V`56j9wyZuuC z>;&MGB9$Og-;{*Kj>{ocUsV~CO5Uttxv4RvJuNJAO5p)d@ z=?DnTcNu1T?IW}bLM)9vEgzC8x=0iA-RvvG)wKG!u z3SRmt^X=!Vb#GC*$U&&MFNAvk1Iud7FI*GV5ND{?;Y!<#U=;n&oZg zlb^fuKx985v~K&GU)s_hrAHyDRekLzfk_*Y0ORc#2mS|I`{Izv&p(E!Pj)`FS$&Tl38Aji&hwy+gW3!gFGm_{bX{=Mkct zXtyNc_EYYgVCN~}G4C^l=nZf?<|!8Z*~BH)LmQuT6NU38pwfpp9Cc6X-18aJCjYIz zMJ$N?GCn&b@y0n%{=<-;Vi=il)H`%~FH7cS81?6Ni?}yMB!D#SQ{(;kMZ#23)DA;L z#n|_Nm5@k3BY*YgIZ@Le7GqxUya@#! zfN$$iP~xf1Js-yxNH91rTad$hlt z0FsEg+w z>lXXF9yr$HlK@iq^o*Ct-a4U@y&=P!&Isg|%D<7&YKL>DQYpg0K2k+f!kJL%r%t$T z_AzU_SLjmsT^7y6ItcEI<(d9fJVE!%R5%q9i{CbIaq6b$M(ha9)MeULVK!>i)9R3A zO{HH+^!nx+Jn177)!Jg%lWb`=i)vNwm8pmuPDp=qvAv}1%G-YfYxu@>aU8~jQ*vkm z?ao(^#gIwIYH2pcy{FkBk@6w~*AhGK4`jEfDHUx|2*8WIFjt?g&2i9hsDOoJ=CTML zVM1o2z70&N-n6KN*L|z0LWK!$Cg$t^MJrjyZg1c|R+SV=Eeq09XH%OlL%z_8RK}NA zd9cpr$*)oeU9S3trV%&Bt5AfnEOuIn(IMATDsIaqcFBV}SrEA)PH`1mZhKl{%O7ui z^hANz2`8}hrXxYgtpq16natU1IFnG%097FI_#isTe|<6zNrC+eln3^M2&1?D-Yt7Y z`V!vu%U3whxMt4=`?zw^Du^dEyt2tEl_!CsO4cg6gN~l>YoS_@%CuCnOw*^NbAkFi z4WampRRczqrBB~d86a-+ZD_z{5rJ||GFq~&dQQPSai{bP_Dy1if_dXkm5I}|!*T2t zi~5(9zJ6Yki=~}U3AtY^bn{etB=n$KI0Gw9wZ58xhr724C(Vd_{FO(F-^ql4N~ZwJ z=n@FGV$JEcqt!N7ETJU%$vKk0VR&U-G4Tb2)wRu@FKXQ2gOR(dk1w=2&P|kc7bT7- zsr>X_95%?vI9I$0)p%YeRT^z}({XCl%X7UZXK6x~q%jBJ-V&oz_A$m;YX_o-`H-&B z3{+h$gHJ$Qe%tX3-_3740F~>;l?2iLdgtiDbp%4$htvCuq&eN?%cP67i*J;1VrwuR zPrz|{BRlHt*Rp>{qPIU-7~vs zl=M|#MXN!TT64!v!$xF2nvoI{1V zP%(pK|MnBkoWauyMH^y(4LHbMY4HnV9ua$a*<~=M?|`|GV_TVQ0aZL>CbL#)^sH{Z zumI8E3(zs0m)MJaUx^kz+A4jaC*|MoSW5mN6$0&+YDprNlJ5FA%alMl%KC}HHiDST zNGHFhN4ml!SV(T1Hs^57>JkE3=W@_)ul&VCE}zElTw_ds9abry z&T)u&A0Ai8nYHE}X4ILQs{tbEUX}=EGdbzf(X`MC#PB1NBhqDwmfy%Gwdbu_kXPh@+@&E-N!|egi z1g-XB8ZAi-YPiF1+sS5lEYm`3O5oDjqQyxTY4g?x${h%Hy*rWq2+|)^V}*a&0M0RO zNVCY1GF8O5n2DO7AhR*?Fi3x^+pvtsFnII@<#vAli`k(KBDCT14@v0Y`rpMC{~x?4 zQ%5s%OLGTCH)9t|b2mm&RV!l`C$;~2A^V>dxN)gpii<*6qrIaeGL~t?uOX2nMDg-e zG(DuzTt;p1gE(`qq1+?pscu&;S4`j9I735XKR`cJhpwebo>tiaPsN_ue@*A@r`NN) z1--z0LgEp@o7QJo(u-#bIHF@0SmFwj1fK4(#(EJ^(C{w{kG%yH<Ek$PF zR&F~Upv3yuVh^q=Z2Z__O>WD!5(tZFoV3C%q-n;nW&YQ>MP)2GH{Q3_z&WdY`vs ztG$V7*lUJ=swYfWXYwhv;78>qgbDm69oSo^Sx(76WpX1F(=j6xSw$wzLnk(GSI7s2 z)JGeIlT|xmU{9F%eFOIEsZ`qExzvUpllGyYM&wQ3dW6PLCr`UBF}U!Dtl5R^+9~(i z-0II=y5f&)Y4>+MN6CvezT|)#m;rkj)1#8|i&&?I$`+S@6kJE6xO{ISKl_zw%BvR7 zR)?Dmvk+zh!Ub- zO_dY0W{^{fRcwCs8UK*X@x5T;+F^<4C2n(ZeL~v%tjs>nyU5B@W(`RL#;noPsF`|X ziyOqHgq%j2)=Fg!hdZu#O~RbWvXTR?9pt!uvm@yfyiNcv{0me$ zuZNG}@p3r3uyzrZvL%f>T&MGuirdl`2yuvDG}er$nFu#(hT~hdq@sD~ zV)P49>H?l*^)GP_Unj`zuSJ-6x9G+6_AP=&DRI-Z!TSUHMl?(5GY<|Cdb;j#p4rAY zw63MO49|qq#(~w`+9~Cvqrz?lb@FjTf=TLfGfA;#K{$i zn}gIR&+RA%JxmCME3{%xrBN^RNsx~p0Lt1s&!x+ydq#<;SmU%)7H$WfyK?R`*ZBKx zY<)EGH@wji=OC2k=WPW`eA+gSW>Mtq+Fm@}OW)WE>5wROmJuF(Hc21ZYMdu<*&N;5 zI?5^2plx0|F`W@k%YPwMf*3(&P5-666aU*BKJWjY`2Jsd+W%WZ?HEn1+#PHg)f{cj z9h6)goy=X_yjA|;4y_&B{wIrD`G2quty}f=tCuf^b9O$dAe8Tvkj0S0#D~%i$mI_? zIHqN$Fut_^Pt@TKS|J6~!^yGy$*-=!t{&jEL75PibQ3lcI##uW=H>6qeKXQ&{gGc! zBX@TK8QzBG6ZgpGgC8$V`r&7(LvT-Oy6)PsJ`?U@ zvq+0luGDgxT=*A`Ecc*aeNL~ddfZfh6Fu(>8#NhvHD?6%t2c4&{bLI0{xzAp;_Skq zlln}6$qMH8B{n|{NW0gC_Ac*^T!+=+kf>oHe4FPQdtM0C6pQs@U=+(QQfpLp5OLhz zt#~|u|IIRjW*!b>sTV5Zv4E=eA7_%K%>2#0be0@+BCScHSK!7N0P-Je^-_zr{U>}+ z^Z#Fp|8VmDuS&SOIXeB{r8r-;sjbss+<82aWClk^L>ERA))Lb>S6^UrD7FTatQQIX zFJDnE=a4Lc{eypXjdvx!B&>4&qaRimMW#VLK~=-0nf|kaG1s;XONNVax3iy1pZSVr zWuu?e`fX2gxM$a7sUYQ=%=NIC6R91Jmi^+2M@FHWgh@EpyoUbqV7?1yk!55hWfoc) zZ7#wSr}jN4zXjL3Z5`gxb8xF`ah*Pg%8X#k^7hr5Wif`R^1I}}oNEvEgv4Vibb0_^ zaN)+d3+3`JgzuF=+)m668>+%7r&q>9xM}T=`X~^89j#an_;Rhni{!OFN#4#l%zDcZ za51#%)L?Ry;Y`xzJMuxkJfmm~rD9nS9Wwo3C%!9#Z?OMJk)&u=_8%#z|63{e{y(|G z&D`sMv&H|=LNWh8TA+!CMH596(UAZiX{>Qt8>}@<080hO(zknvw~|pQ7xKt9AgqoC zJ7xxBAETGJLH;%B%0n_?K4I$N6Agfk0;XIC@+{f*`W-F-fjySXYBgA}sN zj77C+A?Q%|ST&D03v|Fky$*FZcgN@QTXf&;E}V^#83E>x=Q3>RMBWSQME3fdYqZp8Z9I5)9KECUcwj7htdasf+>bNGb3sj7JT-yPH z{lmlH2UKGFvF=QM)Cv6aD1eF9FKhH2rpcF5n3;m70Cb2`7vf1G17B^lh2AlQK-Jd? z2vsZPOqHk}_>Eb!{PVd>#GT13wDxAyByh*SC9C+z$r+zG#@&k-)Ut|hEa zGAE?x@<*8cWL>P}#t%1Fm<`TJdD_dQC8MVZP}{UQb^QCUCmsmpV_4}ilv{$H&?zeixZkZk3CU4xbtf%6*k1f-57Po!MA(K(nti~ zvir+UGF-0(A9MKs2W8*jr1`RJ+cT|c+wN)Gwr$(CZQHhO+xE0=+wRwUpL65IefQiQ z@xDKx;)}}4RjV@dx0Y^vGR;omeq*?%Rt{pg2UAMst!G42v$IpTPm^-|bjsU+FDt`~ z#;&+|b9t^R@bab8=`|D(=^HI8G`FId+`eCB{04f)m|wRr+(9_~XgEh!_zdvA zY^km8Q>{l?ckI>fcW2q$pFrElkH1p}Fmxqw5eCy;$RiXDfZm)?oo}LYE(2*0@NUv{ zF2fIeBOZPsc91u0h2w{7Ai5&vx!}MI*5T!o3=pE>jF5!WN8_Uo2lKU%?$t&_qw=j4 z6&|@t8l#S1-g;K4t}`{{9i=tJ8llo^XqDSKU#Li`PA1o37;admL`~9Y*gZP1kCV44 zvX%V#9BI?Eb{q6p8$1yMQI=S{r-Mv&S+s?UT+2EzdlOe%Seb*`SOk}hj@l2YUvycp zU-!Q^r3j_-cSv>^5nOC|@Tgas-GHxF;c_Y-tE6+5>~#)|Yu0B%MSf+k1asD0!e;|l z+Priz7STW@0i;JIa)00)u5EbBoQNGVDKu46$M;k(SB#z$Dv`UPk0M~(VdnfZXV)P` zOtGhrmQ527UZiVZeG*rGN>8x!wHJbzS){%o7)uIAjMR+>NtV)I46Zeh5HXGD z0Zo;kw@uiqjAWrJ*4v=sU_qV&H&0PiQbfFseLV#I12G8_nAtX*Pq7A2eyGZiQw6cv z58VP7`V=zx6D!1zdYeunTVA8=tMv!D2oI77IyeUd+9CD)`+W4#>5HXy$@!_`=|FDQ z>I^{E^;y=XU0UQHPOl-<&=ake96H7MnNF*88i_#!V=3)(ZsyW3PIto9eDxd;>--k2 zk??WpCveBuMX5~Gs_)O2Bt9-Dbu;@{v3+tGb1@hEI;__>0 zas8{S(;W z{xjGZ80uS41Ac=Q==UlB0N*#&-@pGIy#9yV$$ux*f3Np9pH^_SF%Cs+;P z+oi{2=KjBxTfu96A^|c1(jhD93llGB?;qpF_BBk@QMot|R2h?6=iiH(;#alc$Y1g6 z6H^CAJ5#{5er4YIGKwA9I*)8;#|PtyB_u65vc?f1<@+T_$rWC7x&6`TXRxLp?(Ru-`k5@5W;!#olQGBzuzIjJK zcIQ}I63xl`jvd2kd)B$7*F+Asl2R|ZfQ@sRo5cgf9sd|Fhp_-l<+pqQA>W!kM$!oo zlp1e3wyjB`2lh@$YvePvIkKWPy;17qO?V6PkLY>A&uBCH^Tpg@>^qtjNbC*(%y2St%$`DGvU zrLW%5yhM>)hXUU$C1T>l!fuY|1O%LNqV^u) z&y#03&@sn8k@mWSVTUF!OM6(D^x()y4&)eJmKS>c zpng{S?jwfJJH-X6CR1*TRTQCMkQ983aDw`R4XKZp)yqwC70WN+QsX)Kkywft6cSl2 zH1U!dV6%7^ws9Uma1yyj)JhoxGG5zi232v<%GhX|?`{ahejY65yve?>Y zihY231%ZY7!ffZmF8v6?2QtKsjkB+oj+!2Q7(e?%@1t3POzT(3k#wh`J906uvWnhs zxUy6$m2|?8K`1ieZVDHJP2$v+A%I z7KCGogUuQ3zWNmi8X3Q_E^4=UUljuW9^_ef@NauQRXXMmMxy>*og}X#dg%)Y=dWU& zOX*|X$)aRPC)ad4U1kvp6@zt z7kHDe1sFpi&qe_dal=sVAYNjbn5K@I^?pV918SUhOz>x9hj1*s@+trP(R&G*@le!{ zVPA#C&CFEytJb3_&aXlkq}|#QRsFD%r{$TiEdHV5 zRO@GLX`or;Q9KES!EEVat*@A4&7A;Bhm1O{ycdTfPzL|@2H{nT{W_>JX1S+jv@M1j zNJegh=cs4krrx7gc`54K>w!AT_puWd5#B2mNX-9oY9+G*y(@F29-KrL%;+22JZv7F z5HWA0u>r#v){HGkr&S5mm}ap2F1k?dFo^s18K>~n#qvfj&GB~0c);wgv-*qG5( zC~7-sBpr^#awp6vhaoq(Lv<2)hy(QIi-SqR?d&o|Bm3t9!=PMFR+Jt3xdMWv zz(qKyux>Yt0|99hJAUeOmC~HRasU2u3b3^t(%P7uLeRHtnBZ%z9dFXf$)MECtpq5# z-0=W~rAnU}xjJLfISF&U(u{L6u~kOe_Syzq*-;gyzvV#pm$7Aq>&Q-1FuTgrHK12R z>{E@eUvPWMJx!n_47YBaXFHSEV@+UQ&%h|8!)idVt;Da14{On11ngHrI;Vit!a2-^ zhF+fmbqXIbl~Nq50AI~ zS&Y;p^9_H1)(pXbC5NxY0C?XUXkS-kt1`lx`gGQuMSm)-;+M-;#-L}aQ=NCW?pthtI;9?C!Gy&nJB4Huea?+9Sxnw#ljN%%Ws}*acb=AB zIg{DSJHgMfDBe5$(Kl%*-Y0|FC-2e?t{cHh?+xhI+tr=VsnDN8;oT3rR~^r-DBah) zSDnwG)Ltip)g8~mfYz@qC)o`z#(-bD{g@pElihAN)~}x9!P(Z;_hr_anx-~1Hz+eV+S!`}R-K$1EG!V7`QQ3L`z32_I;u;@Yx8fq68&f^LtW;; zhBGU7RL0;Ho>q1~KWjGNE{{wglP!wrk?QC4wHdf#>=uRfmE>r+CaDhu^d)mm=J1-! zs!X&w&I>H&rqF6T%o?5<+YEg)i`SZ31g#Jgo(l8)#(WFJatHP|2PQW{Ka?`y$uZe6 zWeMH$cDh{fPXvBvJgD7>%fuR@TWvmilxq5-=)V;S^%TPUu0Kx4O+0`$F~SGYF)UB57lRU_kN~n{lGWidT=P+;$5kREi<#p*b;kt7hP^6tg$i5 z@BtusVKXeT0Cx)IDDl%NFro+o_0)qzrS`rH2($1rggHg4(kV>F$p$)3cnRt*^ZND) z%OGr4Q`S=#Qz57C7 zo6xy=OHBRqCuV$O;xDb@J@4{ko9f1qP|j&U z?C2+bJROE23=*c=S0c7h~ zLV2O!bwVAuOu3M9`H=rOdTKESJs%)Okhn%pPS49vU##8+94FIgt0n5EQ)67To6O9PW-SF%S#vY^oEm`_)jdvE1EAqQ^4e ze2W6fMU1-M1oH+N#TI0m12rrcKPz1(Kh+E+5c-8>1c&k}G>Vcj#onDdj!y10iNiIr zm=Mt0#c@;h#c#1xDdWPqL~*f1jld~91Q;@}q9}@1bNN}+vry6{u!VA)SnDyN6B>hf z()0s2dA7pv(D4MTl|D=vHXVr-GUi`DQON5l=qq=gJ&0lTNg-hW_}b9za>gYr^&(DLGVq!mgcM+uQ~k|uC+fQdTdytRsK@XYi?)5E}Hboj^t_d<9Ai4 zX)s+NbNa0hhsu~repw_b%;+!_tKL}uEtotPX*8@93Mo6{M(nTq_IO_{{69q8eU5Q? z45vVk@Qod#MX!}D@e@Wy$(q>Vqk`7fkdF|XoTw9pRk9tPFv&hn!*%_x_kv{hO0;%n zTM5M~S_w_VdP>?Xi}17R_SmBRCRrCZ{vCZMcFfUMtgiEa5?*EE-(*ZzD=atlxURns za|c?odQ;_eO@-5C(t4(gUaaYp*|e<0g_`pFq+IEtS#BbS;{}8ous%e#@~gzj30f^D zU>UH7vZ5NO+)m2j#dVJl60u=TN{+02Duvi!rxZS?V9tCbk%p>H_+_V>(erX>fkisa zSQLbFk#Va%9c9)JhaV|s;3E*)V2Wu5^k5E`f>UvxEYE$TRr6UQZhtb`WDy4+BP7q5 zBDM>Gr^jY7!nw1`_7*2EF4fh;58vDHd%Jb+5eJ`CI(HN%Mg>JJ7l{V5@j(FDKE})_ zEE9IsIY*Bvlipekda3_3AJK%YJ+Q?B+J+XSldCjTNmrw)x;QT)87ioy0$=Spev{O= zfrJW4@VH<#|JDls5<6+f{LP6CUOY(qrmU1d!dJKwO;cK)7Eh%s%E+}wwb>|q`K~2Z zW>6OpRn_D|x4jayNdc}wNE%AJpIceu0%`JxNjYLD`cHjXpPd12btB5Nuq#`7@4(2@ z@1OEnGsP3P@EYuuB6-wOAuEEn5k)XWHGV%Q+%)|Z#f6U|a$?5rp^SlhdCJ|2|xF`)s!s|>D=-#F&dY7Z3w4+rl9_wh0NbV*cX(+n02x9(F0-^ zuUSBe75CgBw)L_QfWMJ|vrx;P+Y;K4z~C}zHNEi{A$5}Nq4=Z*)X4)ucEdZ~D}hYz z&xhfBdBGl;SxdF0yK|)5QZV|^F`{_I{$1T~;6gse z3aG011zGUPFxJHFe_Om$YAl~C`EA|<#qX|VS=MlKqS5#`5k!v^o&N|l^gIl$o8dKV z+=cMWsnylimFqP6=Xy(#=wwsi(F|jXBkIa_xtF)b<5&C;D9&KOtMzT78+iPb)AAk%M1*lr9RcFgx_1fY#ab_6Yk%a?tZY7n^lC7+R4 zy8>yZbfW>_Zt{f7X2|zuiREDvQN@USbz%dmNmG0aqvl~ z$*;0{UV3BGVd37I5jaJ`9UeG|G^as23DPQkuPud(-9H4ErWt#e)z->0DWfU>i{xX$&0fp|4O$E=m&G6RR(V}$gc(vkBl>Cx`9ight2}; z5cW&sWe%TTSgZcQsUY0EPh5So#i%sdhrV7A#MfvX!P9gsT*5t{On|$0a-q~Tuw5jL zE(%3^w5tBYg@Do{&>W<29-{E5i0ODm+iu_DH2Oq^ICu)kv;{au)BIiHB$dek?nv=y zY0)`h9K$lV#VcpqU=7NWo8hH`)E?k<60nkqne$@eJ&-GW8(hUnF;wUesJT;a!kjp{ z5pUN-T+!4rm;TR$T_X!(W1qkXJy$*3qR@M^r$>VbsXmhCw*>sSlNZkR>sePUO3LmpcFyG^6C1DTRffALf|O(9JmbRlL6~z?eDw&C|%u$bx31FkPed z@*k@u0b@j_0j|L>S^+w$R!V5QB4=bJxOnyUDEJ^dq4}&}^*2)SEaqlkuJ(VPk#K;U zZ^>$)b3{%?)SLy+pkeYYsXAo$AQLH3DP!7)D;&@=Yek@JL&=R}EHg*zc|^Hkl=_$L zKjJ2%(lJvh@J56V@-OGIfue=52iKfYSlR8>?3OG_mrR5#+!#;N3$KqpCe2rBeMMns*@BklO#LojctvhUuO8>;m4{@PWST z%-PjTz%_8pDoT-Mbk8x)X^g5p4d*$HK!Ihm^^YB=bs7Bf=TZ zma&Uz8$-@;rg0v=CV!sX$~oxOy7q>=H|~E^7t!{Gr@s&OWS3ZoGl5tn6yb^D2$DsJ zxy2jrOMkS@9!zIHL@+(zT)Wz14>A?yim|tZ{`_cxQpk1dnN|Fy??G%2=I-mE?cnZx z+x=H7<6;|eDjx;_z!mSGS|il|?{nYb+YN&H-xeM6hL*Zk4yO9{l7{y7y2k%iv6IvM z%O{xgj}?2N#gCV=LZ3XjH(pi5O*08dS^hc&eGDxLiK1}_v}G8&jkxFIt(!?uz58Ba zoOjvNjlmQll2amf`^!xCt9AQBueZ+^2p>y}quBlnFq;a=UFgf9W37lqeTAKtX<5S& zE;-*YZ2FGU)m$e^IDxFDDW?h&NY1m;#oWs-&P2*Ll?F%S1PT>h znc+bLVhg41x92UnaSb&n;LaE_zmU*8dH-0W0;-+o!D!QU{5Un7ehT=TCmLp4ER7yX zB%ydF_=Q}tz4D9^i39#l#(DUk04034$o#3S(+sv?WGbUnqq7 zlza^YNsF|a8pB=Q2yDIZ+{bA-+6t{G&$-LhYA?`)YS|dwL+M%6FnvV5nlC!lFIM68 zL|G1g$P+Wm==&#le>jbt{Egqa+ChLwr8LVBR6iw+2SORszA$&Acd$m&iap~ho@ion zJLRky#D|1yUWZuaCaXyn)3alYSc2j5B_itnl2MCaBs4J1EKY+U(Sc)@5kO=9wwecK zTWKu`Bb6X-R-)mjrQp5K5+O9ns`~?`R^Z`(%gg=7YeTj467n2_&!Wt zf|CAA_P5q`4hp_OvP-o&;oxPGL;ITzwg&*tSc^FkEiGEe{md1ecF~FT;oaE>Ab{Hp z)HaEaet=Le{RJGAwD96&fJCQl-Z6xAB^=$|Zto~TtQD#xsBwNPMF9<6X6VhG#-Nvv zO+6oEq$~MN(LLldvo2~ z9-FE}hTDrbvaafo@JJVp+&jbyT4fQTLUo19V5s~7ye83fTII+gmD1BHNx)~GhjPnWs88whp<||L15%C&0R-Pz_9v;FYH2|@e9byD;!+Wyr1=0 zRxBpM0Yejs`WD)}qciR}s4HQKI`3Qx?f+`bZ|eQCWf z3Mmgf1eNc;_=E$$mrg>@9LpVCV~E0Vd#v}q9=lAQWVKgL@rHHU%!4=KT51rAs5Y2B z)&#&y@g+~x&XYm_Dp?59Fp zA4;`x#0~y7#e!t^=NlP_-wOu8mE)IkkLVKqA@=e`;*wBTw2cKOq^OTzK_v|S3!YtY zL)`ibQatT?RsiicomQ%&WRD$3;oJ|)w*kt`MvT?|RMv0*i{x*aZK* zdRB5?)B5Tu0_h& zXpJAx(1Ic9XE6a0rzSGI2$a1?q&-h7DfU)r&lW-D7mG6mtyMB*4$#b zP9GO8ss@CW2S!NLC+wEO$I|G#ix`LB!K{{L$n;y)w% ze^~S{pGIAW|G&lmhd12+_K*K-abqjTZzMBrRFJh^V}bN~s>Xe-Yob}*fNlxap!U%x z54DNPjNf+}q|vFWY#6d2ui1Bcc@idrUafp``>{(x^m6ki61J55!$VdYeF~Y*x2e=Y z`=q}5$AFPHYT7U{=+OeO$LsSA%yT=34~^TGCMawprAvJvuR15k*(=#Ep5wM!D-&#? zr4;P3uAo^n6So>8OtOnD4hBzFOdaE(si5n*7GfIzFUEX`9D2uk^RhTtJ`zwUcTR^$ z`?jDDovd_pn9EX!=b4bXro+M$oLoB34Vf4y4~60l3ZJbiFFeEEb14fl`TQ*ttS}qG zI)Z`QUXFOvIUE2lx4jw$yj6^F#XbNaSIJ|;j|mWYCCe2Dw-)g2Kko1;=aN`b1Txy3 z__bgDpqLM?8LJBV#qP>ks}7M^G$vR%n?d3zI{V-vBPnV4-^g8j7lKxy@d65$? zHOD7iQ0^7_HKD*LCGlZAGn3k_DT&9*?t{Wz`SvYaOBW>KMu6s@Iih1z;gvnk@^zJ_ znIzCQ)ISGj4UGr+O*zGmFE%`3WJoL=4zih_J2|#W&Fnn$V-5{?n*a@lUo7x_4~34= zT$EPFb!8JW@#I?icI8@t((^ew^+`?-fPRKy<>vu)aoelB;nMc=xFo0B{=|x%I zg2wBWMm9&q9y_HfsBX(=^2ehb!5D6w*}aqd%)$}Lb5~cG;7eCq2MC6c!$?TgUe&C9v__e~IFr>&C%4;aPx) z(4+y!)c_fw#o&l5eqJvY+OBs(9KQj_z_fR0T*OvUcuw`-~g<8ivZ~-v0^nRXgOp z3lc2rk{XvScS|4Hy$jMT`%yNeoxioj_!)!|gq~?l8zDI zZT{{_`~_;rowLtx_CiefHTNuRl_GKWx(p@%(p`ETI>hbR5BZbZ|0~gq>(BF%Rf^<> z6x$0a^TbZ~(lZMBm1FGOK86+i~`<3z*m1zBOrwjHW*L8OC)+xp&g*IUe=e?nI z*^|)^;Zk0tYJI?s&GIIomS%vKLIM*g@(gGj6XoT2MUe@`Gj=J=$_tP(BpdEcb}{iS zkdVqsr6Y;VfC-)++Xm%oCrD2jWTiJSetqE=t6ULDPhG1RV*z9(=>BdBNOAr%5C_k;_i z6Rm{@I zAi}^#Xol|c-oT3axu_sSx9oV{Q2x9o!K=YAoLla*mhab>dIUZN*|Du_OmkU>$_^uD zxGBKk5?+CqZrw?6S*7gy{Rr#RNwvS>IneV)%DQbtx{G_z#%Mb-2|u8l_7OsqWlNuY zoSXKMfN2wY6_zisZ*01Iq``8TLX=h92O)LC$vloi-8T3%Xe*gvQ!in_lSJyZjmYf~ zh66VjGWI2Ngd=~8pqHM^cq5Mj{g$fU;YVQHx~o|1B8gDlzQS@7M6~Hp54L+`bpydW zCed+#*zFLe%{o|}xyvkdqh9=sr5N7@Z!OQ)Ci)&5=ge?JO#IeE`YBQ9oViPVFRmu> zzCijZ)a_lo?^*l|N(=Y+K129P`gwqe!#X&e_RI{}S=YI-)LOED0r~0&8AMr1US362 zuC6Vstlrtxm0MM3H2RuWcWMVxs(9qu>?W?(c|l3|kSpcwK8^{(j|{x(k7w;}64=~0 z9-K*Lu9TptNTszU<1XbI$x274q1xP0wqAiTw{rpc%4W{a=M~VSQ}UyeeBYX~^eGUw zp?q^|?h?w;5r3I>w$lDBj}AxpxU$QVDJC>ivy!Vkp-n-urG{~)VX#c1G!JgpQIw%# zs(G|*hToU6%c-1YU`?P^vH74XdXw`r`p*YRUubOxxUx>HmV&`qMq6Ypq+<)xUMQ0biWRm_0>obpNeO{9 zruxbw&C6SeatW~)n@j=J9lfyrH?~1K{G;%It!+HG3QAi(`S1&Uw%FOtk-Z{oHB(iO zG2N5ObFe2qAAf#kejd1>)8rQ?D>`++S)Yk?x7GE&5SXTD4E}VycJ{oN`1pz41TtohJHZMtstv)eZ z6LBz39I4=C)K28yKf7;QTu}>To}bbYU}(4=(pMK%<)6d^?!n+ghPIEc23Eyh8rZJ* zbZxHV+&8~*oC<}}kPT^buzF}hkJ~smzXgT6-VLK8cBsVvC54x zP!W@>dOq1e1)~2(BcWl*HV=?P!wf>S!-s77nAdBcMsRPtWp!@>t)!5cJ;PD*m@n*&s$i0eC zX|#zD`cns?&>SLiRV`l^s|pwgM`=mR=@ z9WT3aIc74PppoX|%D^Z@+d0N@>Fs{$Xg1#N461$KR?BpU^&W7$@er}H&2e34>_F|g zPky7|3_o&tjxZsg8GLJBi&4{mqrjPCXiYpeMfxfY8jd*S`CN-yL%F1rzda-M;oxSP z%=F-plvXshK*H(ea$WLOD4=R7t3?d!Jxf#oe=!NV?=)ge-!aC%^}RzjR5rlFPfeJ# z;!#!w1WZA4Ee(i5-qXG+gV-R9W#sO})BzU{M=4$XLZ2$jCoG8Y=@-w7pfmKL&xp%# z=}ADLgHr_M|HNL@1{J6%-+&f3zX^=ckmcC9goz?5%8To(Juc2EBTsQ*lNMSF$nwmw zXZJ_l@6^oYNoU@tq~-f{uBm&U!4FY+jsjQ^IkydY2qPu(28yVp4MNY7h*Dga+R(GO z*tMP#264G}#Ma*tI46J{t~<1FZvN1i1A`LbwDQVGQ=EMMV$Tp2dqE09=vl*(X`UGb zaoV0{kiUq{7!kEG>tgFqAWO&qB78Bz6KqB^0|vq49#0*z7Ii!##h@cHg$%*FsC!>I zSW{k42@9#}E2gEv@teL7*8MH*C*{Q_gy$hhaquWImSuRPW;(^!&|*W)_||Gg1utKX z`S(PCorW7~W7rfAM(SD+4`ZO#k+ZA%NBVo0QJM&XA!5QS->epXY|Yee&5f-o3QW5a z_Z&gv)n~4Ne&Hl=lz9R9sQ2aB(6$oE@A6Q43meG!1|>lKIk=tDxjxMq^%Ii^D`q#N zn3SR36*#(tWf{!Ik;4Xjfj_~FL{Ra+MRJI$LP5ox$gmP;P9U5b@$u$%@8?{=FMU1X ze$6awE)wlSTD=@u&?TL93Fe40a{kmEc-)$8p5x{02h?Tq zGMTx`duA+RAYIC*A^^VJCJiT~p-Ls+hm<^8-j=$lyhg#GY|-!|asLiI{2ngzij6FV z4X-&!x@b-s`WA3g+P8B1{Me3s=}r)+{;_zSrO{M1$6)19sa^K5s3JyjqF6U-6lSRI zh(bqHr9yRRIOD81v4t7(LUM12%Txs?q(dM+lc;qV({GRhLXmzZ>aaJN{`y8V+EwNV zIl8^&0Wm|wNH|#{^iVT@`Nh*G5Kt^I{E=K<``_e0GeK(UA;|VXBdPkN9t5QaQ|x8; zXM&H7D(LA=&}7VbdWe3&gZ1RqP)Z7(p_*)jxu^%vL!N@5&uj4`xh`^kld$B+BAVpXpV->3t+utG`ZGV$D?e( z0XDc!^884wy%0@$V1hXl77TTG*Y}#lVbHWufG8&|`9;MzICTL-1>RsOKx9gU2fn(@ zQ8nG1miKBTUym!Ki^Ph*>xh9ufOL4k+j+7%7P4lfQ5PT_M%i_7Dn+E=?{2*@N`WR| z!`^b844eSRu!EfKG$ZD1QXdKuRN$Oz7WUAb`23ncSFd3W#CgU*qHb*B+0RkgkHI%H zf=RVb-i^k21mytD*PF`qrB7@kR!a*Pv#)28G@N>SFQzHe zGF-OJAMaoJaB@zEp0+Rz7Cc2|Z0_JhNT@t(u_R+hDd~!};29aFUAzu; zE|j@3VI=?^BBCg%Y<@Q9lRcuZ={!4zGc!QUw#Fk&lW$44EanVVX_!f=Y1#D{!|2CL zHRj=^jzW~)sqXo*=~0+*>u+Z5-~`sLV0^ahrb#zCJ2+RUgL7g*Sw6oa6x6^a(lB+I zTx>E8Sx=u`;~o(=?6@efmwtjLA(qW<0mAy>hrtf~Lmad7<)c5{afGqP9dz4fF$2$tQ8c zV=|aH1Wrn?1H!L|Wul)+~mnaL+~!bK-^%7=l#G_Si# z$-nnSBoEK*5-=;rY3(Td_f?9e;`ba_wWMZJvn>}_@D?k_e@1=wjrhIq{Z>AurCWV^z9cX{8uzTd>-4rvq$%|+$h*RADqTzukol4M zK~!P;x+#BR7nC77iq@792(*p24)4W9xYi1>QmFgkW|mbsF2_pT(ddLxHQp)^&2_Az(4Sw${czd!Ra^Q5P3i|FTGO0sEBYf63^WH5l)Z6%01_fC(bs{Z3jn zCH|rTBB*@`4X7FDVeM|;H3jiP01~LZ3lHeegeaa6LB<-$+p8mdT9;R1pj{B{Et6t)aHWDUv#X?98hv1!-X?8Z@8Rk*y1S;p^Dt3zVLLEl=bI~3wkoK{a}&$t zj{12lx3{3A=_=^e+gG+Kc(jj_pvbr%-A~g#@6n^FxFVyati))$D*yt~H8=BKCkU0; z$Ozt-stv{G>H09&b~^|z@X&)>Hm01oR4L4J7HRsXE&E9TT>Z!mIvuclkK>PeS^iq7 zt)Qf6DCJlG{ORxV<$QQzjLaB26=*R>fKHXYF5p%H{5$5)w+{92WZV7tokMG&MNj5C zm0gmWex^THFbYFmCC)JN#g|Xk7z6rx)u;~@`!bB_>z(5Ysca9QfodCxDpB+4?ay28 z*I8L3l1g#9y>pT^%yPF0V$$?uUtwkAnQlc+)42mD*IXj%xr4!dLv5cfM(;T8!g2BE zO%m_Q?jE@#-l(v>iaL+NZ_VY{ZG!I6wJaPH>y51L*<|Yg{>hhg8EN;)t`sPC)EA?3 zF3}^-_x7|7h2-SXanQMgV-$)gprDeysu*Ru5fu$B*(S`^;q3}RUixx`%9+m)x#uh6kFH%AfgEM z_8fWNFGw!F!V~Kd$FkQ*+|sAWv<}f^=HLDGW=j4_kp4gJ_%ZKY(jfI!t;@yfHa%t- zV{Bdb2(Ajp*Z7hxHj9X~X;co@#GC~}QBibMWG^gFA&)K4%4b!v2pm1_&kNfsmsY@k?(v-elw?yE^--3MT;G3aKCOr)Q7cu z4PgDiWE8a2cY&EiQKO|*>rmCtuAxJPcT@>2k4hlt-x0Mv|pRgCPN# z>ALrbytJ4lEIx`&yrKF$U*bPql0x1XSLg4(ERsPzd zkR(AhLEAYa<1>2XX?`tky>>1cZaU2=p9cHF)xyB|p)*epeMVWmIE#j>I&^G{3#5#I zp4R43y-{#^MLfiM`d!S*1e^*BHqK6KdH%J2p0c)P^RzI8WFOc~Z*mRCS{7s_23fB} ztSQU>ft+sqeF+7xWG{BEU{uJS6Rs^t-(!eC;1HJzRcBj~{@Ly5H>!CRzcfF`y6V|V zd|_iRSATsmk`&xtC=r308@}OEfbr-1J$80#b~Xb=t}X$sWcV<*%JvG<{|-R^+SWAv z%o=o`CJkWs+TECqu;jN&TL>C8^r~RV{e&2s3QE{Ev~IpjGYP)eq)j`V$AjXTpS+!~ zTzc=<6*#~5?9zc8jbs3u8N+4GUU?WGrLC@09&MGHFsXdigV2;F9TOx-yNkbvJ?2uD ztqI#L=qb#{VSJ-@Uyrs1kI;dI#pOn*%u%vb9}C*i3LFk%<`ndECmFi+CaYmp>nC&W zBgJpqKCf^QkjiKWgnoPn=+4BDN6W1z8u|l?`P?5hogF{k;i3xWk$Bn&HE*Bpy>jB;oQ>JzKp2)BxT_p`DZSBO)w#wD^zuW!2}2q}yjw5E0T>1&=_&EmEFRCv7L zokDzLsLjH^4H(+{6}~Gp(yL&exkoYc5EX|mWy!xpM8Z`%Q~`u-qRo#t>;aR%Ie_~& ztyt_8MaYKP1pqo2o~zyIq9p>51_Dwh|| z_641%EMqKH9D*gvD1*VbX|z{xq7Sw)T562f1&ycYDHOWyT#Jhn(bOmVYJ@XCAg6uF zr5V%=igmt*Ry}`!uvcuRI+VYAtGgql1^RLk=>;XYCJ@s3SY5?Vgmg7zLZ{$H%0Vw zPQkceA;qsq`78_OfwB9kvImd?n@pkC(~{a9^~C8Df4omNWSv`@Q@T8%U;TvkmFzmN zVG6%`{;FvhJ2tkb+xtGQjjtKr zM)#)9AH$v8rfB-R`tPwp?yNP;PQBaz{+YLBFnB$>oqfsvCwRtr{qH=ahf6DDOGC*I z<_-k4ZmgA?_3-w~mbOG#skl&?iIlZD>#luU*8czwlkeNyTGLy<_q15-2;5U-4?ut!W$$E@j^lvw?z1m`hFxFgUE71L*&|Lv|%k%ukdBK3)9zb z!=Ms`6x?vaM^GA(@j{ps;FjEpWgrR!L)@@%;%!Xw-B2tE@2~%wO+!xFEkDMNmat-N)3Ln*k-*aIaSEszGVHLJ+RD*ubi8jic}ua zenXT6mC*QFPJo&3tqI1^*t9d;cIi;){E1N&{H)358!7(4!g`20>4Eyol)1lXra4~B zg*&H4h_W{(UJy+uy1EHZZlAkFt6`}fQYTak&V|CpXv&msf-ks6_%L#m?4gJB0%n2> z`Ms`za#ba7LkUuFs1lr18mfC!$niDMu}r6 z%f|HKYAkT_I51@ii4eDwpunMsTocWpqw6r)syP^%Uto_SuaUBirYY#(Kq{* z`ai8KIy^%A)8k9LP`xn-_i3gO{Bt2;z`1 zL(cQy*^?*qCOAV(Zk|V5o@#MQ3%Wnh+B5B^rs+L{7tC#GdWakiG`j@u7#riYA)6PN ztd<55l(V;Ff}abIAj`$;F}5Ht_DUa0sgj;XU|`_jZrj#h*_XF?oIo1Lp-?Bw@qBwL z{f1!S$uH-0YZ{AH5>cC0UfVWWZJaTJ!c^iWXvXVtr|y+8dG7Ue7myWA5y-g=UIpqu z0=3U)m7$bkqYmzq%B@yhYET~@f%2&-<=L3^gcTjDievhHc$sa9W&y$%0g;{2p&~-E zybx#zv!Cd0cqRho0!(Jl-ej=YWvh{`w7ejn_MF$8oC7Jl%*i(6W5NpippLa^xHBO5 zq3X8tun6)$6|`+|!f^4q+yT*vYEy#jQJz#yba)m`>8lEIcuGNu&-YD? z`nGAOE&LIj&08^l+nZnVcN$}*RjZ;Y zGRXn6j~}or<2y!mJ*ZDOS5N0VW)3^{-7p?adHpIG+tXXYMHlI5`;9P_N~*!p?$cV$ zK2zdkddDP74&+-lP^@1vKP<8T#yxiceD@bOB}>$aqMaeb0Aq0dD2v;6w;c|$0eoEvXLo_XkU@P*<#-H1Ak8(!qM}@bB4aYWE-UH>3u>cC69rZ zzPdF$>KhSG1#!e1hG=UKCA$hVtrep8(2_62rSe^Y?&Zc+Uh-N+;rSDXSU{|fBFK_rQ|Ed2S$Cm?PqUY2HVKUu_)if)rpMkR?U zuq<#$rFW2pD9oadEEl5bg)w8g$q0oI5!VaRUWPt4%=RdGuM;Dy!k<~08vJ8^0{(3T(W?!^`` zEK`s%{To7%{HPJHd~a(QFU0lX_A^LlY?j@k5y?`9PR616_pgmy*gdk7HnlR~;ARKI zr1<{#Mv@$Jj@cY%*o?%{^F;wXJp)N3WC z9KL@c3kIW1aC(8(jB|+A7AfVGi%PQyb3f159b8m6X8iAbV|yl9mgt zwW8M>;9Cn3k8ZrncMuf&)BBmbz?N=)?i^Mb(FkDCAD+`17$d%+O8l%o>@|L3dT(88 z(V4VEb7XlJr79G41qi6Er@?E~Pmgrhw@g~XIjjR5ANn{Yp`nnj%O70O*?TeyZ&(1o zYKh|%8dZ)y7c&WlpKpcF)2cGR9lrrp0l`6Y3w1pr68o(`PjhDE{Hf zPU_8RU>%9M5;wlR2p|6CihjPh`k;$xkm!Us?ZEzy1f})QHAB5Oj4bJrp=FhZ-!DHY zK*Rmx^h&BU4>A;yof*kzMZz9~H?EURd7*61g@Iq8Gpf0%{#WPLRk|3=YdVhN$Q}M< z;9qAXLy}Z3EmD5cX&@d!XjCVh`5hc>95?(sM07YoA~ij8eOJg{o{^Z?6B|+ErsFX|^}YJ_m0!*v&Tz~O zzdk(7KUB&6bYakLc#3-(Tf|{ixb^QAW~1?jh;TQ^*7m3l%`OK#W(>bUBjcCc3Z6RF zLF!|D$uX(F??#SCc;P-z2RC|&i5;d2Q}X{-8=!RHToMMU=7~%;QEAyW`Pg=}%cXJ^dcqFPtCPdzkk)B6+4U9 zW{9_zMqjFtlZP_8Y4bqRjMRjti=Zz>R+WIQWGDnX?GHqKr8T9sC-u;woohlt7L9%wh4atY&t_J z9wO)`LvK0-Z^P~R_5D{J||11tZRlU zx*FT#j|1^##ocw;$&NqIpjiT?h{&Rlb5v-jsSvNm0NJ7KOcE#@G5QU%yB#GaR06aj zT9?F7p)#RXar7yplj!+RUL&O&rI=u(8$7Yz`U;M>rs)Ntup}`0U%tV^Cyoey^PT0GCTJaY*+smnOej=)Lec0X zV$p^Lz;I_K>@*XvxD50CeCwEyCGB$qvzh>GLL;Xc#l+pkDZDpqcasOckoF;EZpgvy z0|L)Zlx3;ThXZ0y>LEK67rRdj=NHeEt_+sl3nser&c5T_Q~Z1%*o5Bs&6^xP&8;Tz zwkR@^70P5&Z$fkk{pw@pVz;h0-jb!yBY3QUp4@<7^#A0;QW0Gg?AVJAdq zX^aU}HcUQerVK#;a8lCXhNphM>MO5I!_+=nJ7wWm%DiMU>?;}CJ0a;6utm|T!&yG^6+LGF0l}#vd}L&8<@c$ zL0|x3R)~Tb!-nagAX>p7geR3xL)S_3YRWH$@;6yQZP-*EsB%?ngghsd9n9J<#|Kly z#($}@0Eq39V->l8XBoJv7hCe96ZRV*$!GE$ibN!l$up+=n`s<=TmTg(*|HCKFf@z< ziBQq~*mQLKK!scmLy_Wma^_Pu1V@KvP>qhOmu2mxo`ugEq*x)*&eyYT0XD#5Ux4$Y zaTKGv?O_9oxbi{zPtxU7=8cqxVX`J;4(d~J*;;?SXM@M9BpMA&l@TeJ)ESw-mG#t& zV2cQd6PEwdt>5G|#Yv#y_69S-P7Sj_>Qkb|BnUi4?AL0OE*4_DdTRg(=rofwwe%{Y z1S%EwAHl@8vb*r+4Ih*KDw^@8>oL1^{K0`f%bAj%X^EcYR3Q2HeH1{|*+UW5m)sWy zAjT0%PloK@hVPGZ-kZMnA*-nCzY(6`%4|bL>4IgOWMj|Ao-H6(pBt{Bc(9^yO&5&Z zW+7gi{WA+WYF40OUt?PeBiQ;-W*e`!SHlkIfGFwcZ&(L(OZBX!c(ppHnLWgNX^ z_nnfheid%ybY>uKwb9Bkbi^O|{)tQ$9Wl${^`mjH)iB%>y~K$_m#hn+HF9{z{Weq% z$D+YP@t#w0S$Bx$b@lAWfv`WKPSMIcVhRq<#z5S$fRPoex1N!8Wdo6q5i#e)%`Xj` zPVvDdN+V2lU&zxu;Jwax`Y#UiEcpBJrGkqRQK0E*^{r9P@1`LYS-W@j`!~JY` zOKT@uuEm*&NFP&#$IuA=Xp#OdxrWL8)9}2#8x1;4hS(Qafh>vN?Gd{e4w>eLpyX0~In{S%G-6VW~YnHddHbu21|x)@0}8gRggkQIu` z-te1id<^4P;A{r@p`$HG-<-kpBTlIgP;E($&fveo zYntq1mv6n@FrQI3rf^TFd-vGD#cM}x#CG^$MARmfEImD1WJjq0qchi8?x+E`P+s=! z81rtK_7mk9_c3UU10rP^b;JgIQnPxpx|IIVQhO37g`KAJ|B7fQ1;#pEC4*VJg7-Q` zN<`?zU0}n0suS4`IF~2^XKqWIGAPs++motJbsyC9HQ-Zi7!~a&@uMn7X8rgl zMSJOwC^Eoc80tBW8HT0Fi2;x>F-l<-mcyr5QaSQh6EEF@xmP6?F4U#L^G0q(xo>v{ zAB!2oz-cs8WO|lD>78^O4v1;{Kzx3*bKUv`nIGV(7yO5^;4OweT) z6A5eo!5`;4CEm3r`r+%6cYmUMgb+=v9CJsq{!0S-P|P-I*R&G}W{)tDm_HEj*61JU z4;#39bP_x*qVYuPY<~oSf(jEFj_dMSN>key$&-3)Cuh(|*w zQW8U2NKmjEr}nxo*^?$?NgEvsh2v4Q#AGsKuS8&r$5cmtVjC#gE^B4K*k!Gl4`HoO zXf}Mb&&`Ifn6C_|55hac?{Q$>;zDUPf((sEDU$Iq%3$WIyDsO6yK-pi-sDF;PT-BV z0N(S=E(6l+z7)#!rqBMIOV5t1GK!{=wA>qJXCt8?|97Z8f!7|wE(PY&);7th zKy5WK9;s%~7tW%Ge0FW(qd_woaI8*`&zg3O0H*zsUtov*qZuP4e2E*{vI+{JhR)Y5 z3}+VFmtvlL4$T_m3KR$+4bqilz63$Lxn_Qo`xwk!NaJhZAaEu{A2A1}(lJWC*~Pz` z>NxI$DD_yqxzpg)Zx6>6RM9>fUI$#V3qkxqE#h6>`trjQa{=9AB3eLkuSO`(fo9`m zT)6itgK=xXmO>y`CQsOa_*MMpCv@o$z3nA#OGeeP$O4LUJz=EShfwE^E3(Lkpzadk zfE~Dq>n(j38#_n|R$?n&c&l;ym9Y=V7z3mJ>AZlYIaqn)p2;Khbnnwehykj%%AZ}0 z23%*ZwgZfh;UW5Lqd#tb4QvyC`Vofc8gDNFO}twN>roZmTPbh2kH?=Q#b@-g`rsyq zzZr$}p$NSA&}Doi`7#Y8uWvEHV2FmD2YaxzT6OLxXwb205GThSOcvMZZV9#SV}2@j zypaD>UMFRVwpd^67oBE$!53@j-UhYzc56X9f8&?X#kSsRJGv?_0 ziyMw!5fK>+`&Ys^H+}R^5Aii*YbR9WAz}u-M<1RSgE#VXFXSsoHYH&w`)eXb#Z(aL zQ?>Un2ma-_*^$g&_p5$x#rE+<89olyCW{x0QZ_=EUm>}lH#AJBZWTp^?L$?a3cX^K zef0hq-D|$ zsM?W|)H1a8AKtYUk(-iS7!lw5e5*J~>H0{7K>^H?`fYILm}wnNo6}RW=q!)$e5AL; zfUL`@nX)v*(WS-+bc^x+o4U+e_;l_pcfFeVu%4@}h$gdx4SQlTlP9GN+GpX+4X8zD zf$E+~9ZDo2L4u&HLyuj0FLZ*w%d4d6ez-dbPU3DT29sAeFED@lfcz(OH04gHxmUIk zGm)JiWOp{J_?ElZ!4S4|-H3cCSw=8E*w5ipRNKq~U77F-H+8dOsHwg3pKktq_F`-s z6An8Zg@!eOHZO8#L6h8Vq1&-s5sw+-zi%Bv*I(#X#CiN^EdK(k$Sg0iTuBEV7GLbn zetqE+ZI49xY{yiy6g%*=%&5rv^YFnL1Eu~lTKD)*oE_&ck2t-}W(D6+9pLAG22tJj zV3KF)T9z|z*Qbw>C=mZ`d$EL)9Z#zu^yu$KculUz%XkeXcxg_`Js}95mj1nWbFO2x zLcb0Ucx9&kohRJ!5BoqS7UHn#B()n6?hv@qjtx4c`5u>>ozQY(VJl z9e$Pus(8X5Wpl^$lQTfrDvR<}g@W=Qnh#~NWJb2)C6^Eq0h2y!v;70M zU#pvLx$8CPP<%glxgK_zD4uyEYfwQgQH||Nxm9UgC20S&w)JN%Y1Yrne2yLO7H~II zm&AClT=I*+)zvkow3$g(Z@ekReb@f5l3Ls4dw4Y|`<8QniyI5aX|8>mWK=B$y)rbu zp-7^1ar?sf!4~YgpCNv+$ z-UPPgquPJRf9spxQn%$^i^LW8s(OZAYk(ooN@nasy$B6r)>SIpbME;DZ_7;BTM-u7 z>9isIPC%KBg`&(6y#1w8%(bO-{i;rFHyZ~_+RJr~CK*#6Dl%dj@rt4oDHE&~Or}r> zi1p0DHy1%_BrB3$A5MN&WS0=jK=*A-1xPuP6;;Rtu}a{?I-0KNg08<4e#SoT34tlN zkm7vb?kH7Bj2R#a);&Kpui!cH+Rh$gO)KrPKMgkeGXU0Wp zs4lc;r!_umG{YHZ??&pmxN%eu%cq69=c7%ZFoTg#jR=syGbe3$1&j;yh`Tk-4u(an zWI&&nKU2lq>TWtpx*Zh6FoB8lhzAWb;h1v|^?(g)a;`HWrtu7gEHm{w102bh#_A3w zUYpu}6L6*r3@21@h{?R(+tMWagVOFYBsMfW1S`4xu4qbBt~kgINa(h-U$Hxa(ol)@ z0i-CKV3h1Bg~!=E%oGj{w}r%$=&CZ&SN;g+q3HJTM zkDUiohw>}v@pOW*q$JR-WbXjYK%E@KU13SJh_I_4C}*Et@cxO`yqaI(zqNHf~Z$5@vSo^AHuAhA?bcT^XE&Z;jzih z;iI*DBY%C_?br7e-}T_*bxbaSPRV)e3k$fX1_-N*3BT$I#m>q$M?xJ_8v1y9x>jw{ zp$lzSZ;&a$x_X@FT1*c+sg5Xxk+CnFT$5&C?f@=b4 zGLdSHiQBmG@Xi2u&YvPB^Z}tcBSvn0RE(cGmY?!$0fZRxxj8$*e2$R`Vtg%x0hIZ_ z>H4;fPlL;DJrLVI|4R&4tzt8^=6B*9Vf6p1R~!F-Zc?2EX*U>=J zK>ws@4Kfv^#zIijxhBRk!6<}~woyVx2*RNrw23f8Zb3>UTrb8nx=I0n9RgrH2$kz01Wj$k}Y_1|Jn6n|V z4DnQ&L9xW1MmaACP#f(vq!s#E4# z>%kOjv$VmY9kUBnNAx;s$z4C}(qPz(+m^UOEb%H>%o|XX2jDNY{<&jTC`NNkwt1(Y zShOumQfXzCJ2;pay2BC7{K_{>{JX?7FX(wxFL(yP7gPhP5o6WfW#Ko-?Xeg6-e=B{ zfu$%F;qiIe+bK`^$ipvFeq*ar>z{HkJb6mIdxpPwbAFmxXpDAsEO$&9{a#in*81}O zX&%pSU{PhksW@9_31V>s%pf_tzGAM%^LjueitQ$xWb!C2EbQ zdd)$zP10x!j(Fva%?QhByVFErP4MRuKtT2vQp z&T>#_U8Oao#tT*X7f&+XU*S;+Q5MA8{Q-q+*^mC_)ElA{`o>|gr?!#UmlpT*&k^eEjSg2ph7NCEjqtX_n@2Q_A_vgB6LNOtVH z#W|e(t8>qODH)v7-^k0yX(+og*CkUck zHa{J~|Aa13z=(T?%o@ro&Rq2;KyMy=-ELRBLl3LKzdAqA-0bgkw7G^BYTHpVpE#M^7h#?Q|~WqLEZ2Pu4s@xvnr7|M{GF8 zZQPpn9qmKbr69MyFlM%e)I29)_M;XOu=8j%VJAR-Td1}MD63v|#$Zu8{P}lj+}uMp z(CSK4IwLjo=9uecU80)%R7e3-9}ZDD=Lk z?+4n|-le*cARv)WCaAyX{1@vqoiuct#+TbGBu-F^KZvmWIpp_DQR5D=^X zr8~#}%SQjdx$`in{a2SB(QlU?vj3h8CuC}B=FG{-`CnP^Q*~W=UJ+fdjP8eU8-^IV zsvtcTkO~WhE`LOfMhKgl^JKmt4nQHtEfqaKeWP*%3JcryO!E(x5dRrwu)qwD5$U+m z|{n-AVdvG$>4nQTt;yJ=n9C0h@SmL6ilv#SzHwt!BUe&BHXJMUNNy<-0B`tB%uG*DkHV8g5t1xb^j5 zkNV{0$@Q*Gw&v>7lHaD-G-lA-Ptty28<|6+)VZfLf)wU3O1r1cyIy|iUc6I8W!ars z>}j%~YtHhokv$qSQS1;(%}fva^7%VVxssB=j3IcDub-;0FIo@^x3YcN!N(aEiJcD< zg=!RR9?1}!cp}NDTa+WtQq*pK0#d-I9qO1fq-{itpP#cd zb_%-DL-)&UcHZom!4x6tn8rEw#+(x;Y6)E_i&|LwGrU7CxOzE)^gS`gGLqV0wk@G_ zSA;d<)}A3!RB%_w5fud#7a8Y=k{4-YY;16>p0u|;f_-Bx9lcYZgJ-kZpb;^U)-{I<`x zhrKV~$K}(p0r<(FHToqWt`OXWd#DI{UmEb@62Eh81Y?5Qm2y)R+D&FF<0)02lOjk_ z6&T8bN(<8x3JO#7Lv0haR=SOxSms7XzE36i*!lWiE0}JyMPKqou5TPj!C0|xjV_mw z>_``FH9*>?AC65{*!I1fkTIAYufu(W-Av4|4?zlVRArY`U`mqZj9rPUKlE2iQ^)CJ zeM=-@3d7@vXRL{NA4N zn!Cc5;;%ed%aydnepO}h?WJs!&eUA<)6t*ZgD1jvAo(w6OJXX6><}c#=ifl=7k%@e zh?u5mtIwx7PIt|}7r8rY=$ss}#41-j5WVAEAkJpV&mChvo2-2FEQ`Ba5l0LF#1#^Z zu1RL|IkSJ8KU6~5BSS|ZEa#}SXXQ2&;bubkJ0wa97msG3y+lCZj1dfoJJH#HL+fP$ zrRaZVXmja_>04W4xMH-MTT{widMBNiwwPP5l9a_=XRbYq5fq6D{902O%U9DWeG#VZP_*gc^I5FbKQaCq2JuxC-evrvb?M1bWUbDxo zL76bR<+O49Oh(E#3{{H zCGo%&Sg%ODrpT~1OTs-vI%TBkN23zTGsm1tQEQFbsA*KJGxb>y0C~uVH2(lBum&*LDJWKAGfbQMjHQ?c(+1g& zBCXP}ZVUCTQH-Us#Rce-+0&FFWZGn-u@$w~yx5@!NC0mdkqC<2$#RTZxa(#8$l)<- zcm)c-7l=r?6!v)wzy3>tn7(81k;JzpU+@3YfaZVyTgA-8_CJ#zA=Hs38dwg|UYuX7 zD;5I`HYA4@fq?Skwj&J>50z5JN}Cw zD(jO~L{qMsMbtc}vv;OAtL3(>Er)G`lGi4Qyp)H_zQ$!4{k@TCubY)G{0L)tl}R_i zfg+D%BWc$OlH6`RoX5s#n&o7m{HiSrr`2zK(S5kN(C#QwLWgG3W#gD{5kM6#o;yvL z3BJHR|AgR?t`n@fz4u3#=B>2kwDfrXl>)S7Z>B)a-T`*&Q(C{(^8Ki#z%EN)UM9VP zIsC@1D%Qc_7&sI~om;^oSX%l``u6NyFTP^lOw&Xb`PoVA`%(})e$3azZ_)>;LohWn zyXJk99@Ab%k}9JQKYWWtjB2M0V`GpHh6VP@Bu&+``euEnq2i(|w^JHAfzXerJSV*_iN{!Hg@r&8^}O>% z_=_*6@?D+2Wtjl>+%^P53e#wu3xGOr6+k(Jodub z`Wcx2VZEg^WA=Yz{SKY*do%PdZ=8}5t*;Pn&CfYd-5&C9)-RbIFMqQhi}ns>H_nk3 zwTerW)dkw>7TlTxx>24m7Eh30)KAtcBpjR-u}ee+pzsV%9()E%R`>?neuEIlIt;r# ztMn4&xl1Vy+YJU|7j#7Ly2pIUJtMELAtl;LTlY{0XIU%uY~Ymx^h*+9>>Z{ShTGLf zwnw6eG*Wsz(X)&A2lbyy*$06}Z~dF~>Hnu$&&Blr)Q^=6IPnT5vcm>dVsNrLeJ})i zj3qJkfAr%hzaCj(H7BKsg!g=E7M|wR!<#)mwQ6(u`yr#58cMnEYRJ4TefkrZT5_v zYNgB8c>xjVn5^$PV{q)t2eVsjuTp@@t2 zybS(ezB1Aph>m?HsvMQ6IJl`|UaF_x3yO_c$xk(#M6#j!qiMXgZl~TX#+#hfR~k9Y z+;Ss2pn`2>3n%%{147E2&W!>?#4m~Ngi9fC+MiNTY3_8z>~1Br+$^BqNi!@O$CRGo z$Ef<2s0;vc=u^?9wWmI>J3jd#CrB^Z>Y!fY4VrmAq1rtbJmN|q9B z1tFskm z1ybCXLY2IAg?I7@`L{BOV478|FfFe#USYRk=zLF#m`38lgdXO#YYBVQbj!5%{%$&c z%BmAi#suZv5WbN{d6L~$L<^Qi$LA126QGutPeRJiYKdvoJwR-hC0cYB3@2z%{?_FD zJ|rc<4c7$}z#|rQGlm!RaSp+uX#z!Ugy4~t1cn^ZS}i$53*hH~i4J@{Z`~+F8&cX? zpooQ^5S7TBc{3za68yS1oVAOgv$$f@=OD%1|B(-F9ih(J{|}`yJJ@5h>IilQkvK~UNhQS?f{G#2hK?%+fd<&EM;ZzLM?U-!3c&)_i?dKS1$fg>%p&8Q zh7?VdK8?rkQyx=SpP%<1Sb3j^8j{RKAjVC${p1dX4mP~R2 zyKZZZ_UVXUOv&&$yy;bcXv*zMFLAH9T7Ojdk4?9$-^j_#%T1R(qJXxX&lK|6=Rt4H zitD!;z8_^4{ve}ef7^^&BKb*kRLjxYGrG&BHhqsC||hgy?AS{QkQ2R#N4sVr5#%}T99RHAxo zJijA(WS-zt3Q(@(6M`p!r!{W{><%liMPYBf~p$s<8sWAJ~ODvftj7i z@XmCIImT6~y&$)CF%+Pam%mRi6^WYbvRR`{&A2|9qU2`XD4IcewAR#hh$ktI59d9> zJBCv&;(D}>`qXM3r-z@(K@IW@hK@vlNfu;@qa|Hue!>WXdxOr;8mf0pTbdQwmUaWR z-$m5YvOU$lvABaAnF{qM@kEbBaGlW+2kMEBA0dS%K&#FTi;y>`%`TA#2>HN_y>Phx zaPm|d6-(p`6g8y+mLQ0ZKBc-oq_;3?t_`_bl_iTZpgiuNTj-6q)L-{t>lvNAK1Q(?<TPM-IW?|`DXo7%pi65d8^o%y?9<7;-Au!!=GZ4P9iO|R-0FGm@FlJkf-{IDpJ$_2FY z*C?5SN;kD=`x#5^xO+vW(a|krqV8j+{&b=|L0*LV@2z2p&QX>RjFdw>o^Bb^YW~Bi z_!L!TaGDRokL$H>A^FsAhi4jT}@=+p{_8t~MDG1)FEL z^~L&xVv>_=UNd6!=oRAoXSb*yO_maRC;55O=>K3ydMHuJg4}Vmf^0>uHGVu2e_DN-8YX8LsOc@-(MICVibh z*VX+%Kw5&70rU&ie^Zrjj6*#gX44%YUyD<$bkZ$ltyBGh=l=(G0H*>|4b%ybzW^LM zTcaF>Fdv|wD4)#$R~CS^+br}3_a9ANdH+1Q{?=6W|6xtBv;B7vWx=$`Eq;AXYkP3- z^Bp%W<&?2(_)Pr`kAW|Nr&5kqCL?PPpAgY4R1%X)E>2dBHm&=OCX7xlmCP)mtVAu% zaWDJzc(#c4Glb!` zL;1yrihjA14u}=kdC1JXoq#F~Q?wvn5i$pB1{edTMkwivWro~gjWLlrn9w@}#5Q7@ zk&a1`!U3dVrE#Poqp=_i+KIxIgMuA&W zw9kL;q*yxnI}TWRVwv%GTw^Hcw&^h|^y!SpGK)YHMS8&NJCU?pbWFQ0kUtef8mt8D zkUI4UNT*mUei}H3a!8+g3p|dkhffs;YUIm`Wrj23njwy1qTf3Y-7>{vaq91Q23<=q znX$`7e!r6_XHwWMW;0e;{;WId|4dY4kg1bE9VK@hsX<-k+pYyM;JT7~(GJhtjkPwH zGu# zUKd`7aD_XA9g@MOjj2SU3bms`xZE20@m&{H3-@Y!w_x8IYjqN%MkZkAZA=5mxg%^2$=CxA62aRn)J^~~ zjAK|*fMW&^YYw4F_wvIGf9x2TL3kmw8WUUusMml{7YBiLPbd!wW|7`8Mb-4X{V_(C zItrZ5=Zy*OS2vW1f&gl|7%fpyIGsodNFzh|7#KgHQdU>T1Y~b92>IB z*I!)69vDt>Jt}Dz8J-{QpmD*Pg(dNJk|V8?*I~oTA9oTe`AhUBr98JL{c}Y}f?eVz zJkLrf;uC-(M}ja&O_(SD!a<*)COp>R@1i68!$asp@nt~@@v;S`djnga30toM>o|hd zEY^!jeG+ts4(l!kig*~zA|8FSN|OC9#`zp`RwCzvp>_H5&91e@kV zN8BO9wk$GESg*tYHQ$VyV&R9Y!}l}r;&Yh)d7)=xDC~z(wT;#FEl}ImtC1?!?^M-y zRXJ+c2!m^fz1H+STElI1LTIelWUNKc``gf^b^$ZS)h~K$R>*WH^JRs4)vRd{A8Oi6 zZTl@+cNy2i7uUi!n=aduE0dhuLgwL(CmCHFk$5*bHsq;K+a2#y^Xb1 zRER83O8J4Dl{lUTBM;;Ls{xFAT-qUywvCHEHg^upe>&OzK8{|SA%5)^K-k(SA4j>3 zkjZ8!i75izktbd|Qvv>#ZhBb$7Q*H1500Xp$~(09mAn}z#63SKCpxZ3n^7Ux-y$#T z#CQx56BIG{U07m8ogu+h(?-ov{W5X?Mim*~aeS*Gmv3=w(|<8aqmzd#hX>~>hw$lz zuyjFUb>h$(AhalckICP_Ht41Nlm$Z=>lu0L`W?0tVYU@nwv}`?&M@nlRBK1YUBaJbz(MJp{IeaRycG!{B*S z9u*k&=k|p21%0}sX5Ev~Yg0P0IH9gzleMf#*`}xPC^`lSL{WI$RVS%%hRg46U7)KU zEs%=Ko6wg@6d3-N-#4+iX=Q2q%n{n=4vF)F%;O88^MX8{$fQ(qT*~d`7l={F9;BQy zI@6^jZR0XOE-RW4Ts=9Id2NL6+8EC}{{AlB-2MCq&ha(VuW`Gm|B3RoGQ51F!2GfX z|4HRi!a>MsYv?9(BwbOy7}l<=gLJ)~&>nmVg?R39e^T)GJ?=tx(I@g%teJ4D%vv(N zG6_8Cba>$m6kLKyqkMm4m-H>Jn!rPDyX!+-f2)|v<#inacgex@oLH?${E@|j)mp&U z^y^KnzcM1WTA?>1(Y<>ClHBXlhJVNamm+Lzo ztgHDWzmiGqQ9=U=Pr3V}M``islgNC@sjdCArPAo*_V3}>=T=ftgc=gwTHWVNP|@3h zgM^pcS;X|wKcA1GIL9;3*MQEl*DsQBb2_>B&q{v3w>TU%bLp*oP!}&A1VX+>h3*z` zrumufg-(K_>*M=Z8~;!0fVg(!uY0(EzW86XA$8C9)31<6(O-4eQL6#F$GETQ*uE)w z0fXJ3nSLvcug6)zBqOL2!%w1rY2Sc{k9MT!Ue^1R=9|AY6O&CbqTpV{oa zyXSXj_8T9L!bCG~%0It*FH{k(d8BZMHWFpz2uqVxHEwn>-4CA$(qVXLz82$BGf5G( z&an|A$y+sQ-T01KvAnZyxetCen)q-_PT1~Y)VKEwZG6rq>pJ>eG(w>BcN+YmGV9|_ zg#^n>Tg9Qi-g>3k_;BHWa!O-oB7HryI{6RXKMq!ND-6#^Bfp^YqKqj$1tvH_ zsCTni`D;^)zn9h_pVZ&VjyOu)JDzWPyl<8Z#0^jHdvkxb5w9b=1X|PZ_ROvx$iKgK zHq~g$&~vKri4|xuY(wdBW?b=PGE}iu-RbhnpkAQ<6&a~k7+2iL@%dLc?A(VN6rcV0 zQXH2)M)r0>0*)uq{+L$%IO3Z)98b8NA!>gabk*N7u1s^gW`SGhfuO>gcgMWcDss1f z$FePo0UXyydgv$;U74(PA+Y){b0JY!_t6O;$l6WBLqW`A2opBnB^bzJa2S^nhk)Vo zrM-tJ3L&*3GRD+Lqcixp5im+VL*Snj5S{#2D@f>L;#imz)ASxsG10V8bhD5;@4IGq zm^dFX73f}zUpwn!d}yC zz+~yB<9LAByO)aS3s8mBI4`_SYT1kfPBE&?c**MM{e#Njb{{iiJnpk~5Jo8yq87>c!P>K8ZZZ$$%ABeorB+_5K#kMq@|_#Px_)!XS` zF!p;tC2ot9An#rQ`QUg^b)$Y2d=~huNggg8;1b=YK+_q~1`J>UuTvb0V;}ud-yvD~ zxK^fmKwv{FgZRPLEu#%u*Evqb^YEn!ittZP04?FKB&>yU6K_R2e7>=wIV3nb{VzYh z4Ze-@Apfxt_EE6<4*ANP|Ae?Jv)qUujNO)6pkj`I%gF4Xf7y@OpTcAA*JNBciE;b0 z31q`*2%?0EWSt8X*3#EX=a|TPfBr{sdf)v=NP4-~N(q<KNm z+@jGMGv&S3aa=q*ejipi{?zNWdh&aL1a`u3Qd(u&{#E+hrFKp6Jhvkmx_w2J#iRixDF2DVnG|%zF3OPt&zd`aCE{f+aft+wSDR`g_N6$UcfyuJ16I_lk~V-DOH@ky zmeR2ot+IzwLnUzuK9wu}=lz7oM6JO~0 za~y$q{_<}nrn+95e1{qKsZizO0(r8BsL)GzQ#3@OZ=!Z&h}6ADKgB!J$AbY`)U^b! zM9}d&TvRSvRH0;cf<)!2TLT1Ct5l&lb`lVWkUD%md3)MW5)n$I==%OmcPZ)Wo1f(0{8F^sz5ceK&C#V*;v_LH;SVA5n>YE*7P^YoGnvgUKwr!b;iw0u(`uuug!q!m+~zp=-(UQsjCIo6880pRa4f~!ov`D;d+;i1 z2aC=`VI5Fn`=NoEq~QLBo`fTAKvKC+VO^0oBzp%y7lswvN5vL3K&oe?aVAaY8^P(Y zb&IXCT)YD;`J(rXJux4C%R{FfT|yb}{J~L-PO@oFnD?i9)D96HTU5yxWwqkbrI7rc zM|1@-C5Fl)#XI@LCA4}6Q5$IqI*JLT1K%OC`0Fo-7-DELqh_$w_`-hheH;*JeU`heZ61N#VQYW4a#)yJPA z1nVAvTQ=&r<4dahBwqZ15r9_p6V2F$%3=JHXGD3~R-77fkUHWLviLy&X8-CEm6LPS zC@wsU%1L`Ob~J^mqhOQ}F0Dm%4V?ahr;o*HOtq_-K@6v+>d59Lf=^Kue;QPzV)BS0 z0*Fv^HYoaYXvE z%9=onyb7!mU*OM#3aS!ofW|(PK$Ih8yurgKyZ9Bis0zFiC4f{uFWJ-$P=hN+1t7&# zqD!j+lp-y$Ot7O`c8?mRgYqbkahNd;z9%kuK4<{U(#eQ;PiWU%(%=<;4a`zE!u|v! zF0r8cCZb@(Vkb%Uji(CtlVUtQ^=zyeo!!$Cjrbg#4C>kF_knMsDr5)8|7esDP>IU@ zNE{G~HZzPD<8mhYltslQY@Y&{qp)lK*)UACkM-2T-<&qyH|qUNVYX6@#2}i=8v7GA z6$=E~$bs{zSlLw36>pFo+(}|b3lN7_Fk$e%t_1qt@jXPJa+C!D;-q$`@mj!brQ{`; zHTfqos%oG!{wFRy4HwBS0*yO84V{6ySOelRo#57Y)116zJ$x>>WxgL!IeGI6yTrWS z77crdtgd!~}@|Zzv$gS!#qOUU_mY6i7i(k-w zb;=%jCm(3a>u-`*tY`Bk%JEUgW%R#${DhHzp(Z$K+J@` z!3x&pt4DF2BOio1goCm6Y@R8c0gO67i0GVA8D(LngGc-V+Eg+)ndBd)EB^*muwwq~ z`W4UQegwwK5M+9P@RFVSt=ECY&q$*k@l{2yBj1tJs4hao;hh|IrppI}j_`qc#S&Jg z&VzQ;S3y1X8|w=?qr-O^QX`+n^n^$7re^f&vG(X`v?GJSdTAHt2TT>Ft9VmJ6_|)I zQ%!pH#Hdn3fjolqI&p%d zMzqg{hJF2NP-~sGnaf@{DdH{b>nx%~K$$HyaJ|O8DVFNHRfsW^ctpj9c5%QddS0b& zwDgP>E=g9J@{q?H}%MzpK?xMDXv7$OF48-fn2>cR7 zR7o?~IY}zRq@?cca4N%j%*_% zvbRBw3GEusQ!fe~g?8}1XC-D0?6$or$$UFk^am3~MzCy^u~vmeqn>I$p*6#Xug?E_ z*a7a8&U2gN;&%1s@-zM^g(a=s*$sv%_%ug?WvnQPEJHzzXxx1KuL4o78|9_-{6~uz zK+})Hj8Ohg(x31~-;y}*RA^B`;eh$m`6QbG^FUd~p4i`CSd?wo4|aN~?qZq}-RbUz zur$K?2uP$v8?@~jKBUv#Xpqr=|B7yTB($S7B%TyJ1kv!IE>#vQYfGH6BP(l5xWOyP zUhsRWv!uJrwt>BV!0DeD7t>@C&c#lh`udROcWjgNf*?C>njzZqslxM{7?};?6Hr+n zZTg^L#)<$psl)0;&-;!1>P1Sss(`F%xkRUdli#6sodJc@H$!CWHAQj>j6<3k_vYht zK8J4z2Opo1l!a3_#r_uROPr7Sz1No@8TH-#;6s4Y^ZPK!IQ{p-KmI3KZ|C~u27g6; zPdjL6h*8;1k(78_tV(nAY>(t9qjMSW6t+7iJ=pEN|H!9jaOES1;r+b-wr9Ex@$ z^i$L{&ya>fxtO0u2rsM03qcc7wEf`s__Ua&$>#!d@w&XBIyLk~2Iy|H?U2BijDtZ6 z4zhmwu2i;qXv6|mJh;9tvJCKL@}YupS8Z(x(Yg96>h<)dKU4eQN0Xae5s^T>nD#r4Sp0!Gy<7dLC-#?GHPbIM^z{{ zlF=%^8e2jH#&aS9wW(CVr#XN`^{wn=@z8FgMy;{Yh=3d@kXG4qtRGKbQRG!rg_Vd? zRE1*WLm_7ZcmtK)11fpwbjjJy%ZU6DIn40Sw7`UY{{;^q%6ryAb*@5o+Dt z`ya9Cj)Z3AXl60LWYM;VEn(lkB^D}!=dO8J~rgG3h*WheHC9M>^afcKb|D%7Pr7P_U6{xEK- zVeiiE^4nC?-rZdXr6J<&ty$s%63yPlrR_5jImI<+^$^S<7Li<0ZQKWO<^ARk?14gk zx@)0-L0r|pw+6Hk@Wm4r&^~}^kxim)*)D2FbxcY_RZYd6y>kLjKX^<^U6o-}o1slp zm3!19>wscxl%Qj*A&;0d{gwaND9Lp#;vAMd4$C_T)=>2u)xPM_qVmnE`HBY*H1`-A z1q3pVp*7~xM!V7Mw93}teUJa9{0L%BLs%pN?)Fa_%;JiXxWp5ebb(kfYZp2%%tD|G z%p%0ZBp{*EJC6tF`v)0w44%}6SA$u!QEH7(5zA^&{wH&I`f_8#>ZLawXlaq7u5+`BFH92Wn2P$Ku`5jL0au9Ht z(;HA8n2G6`M2d)|NTZ`W^B=LXQRMX^&BMLJZDHV61tUPLPBbRK+TEF!h%EefE}@QdFe9}AOEfW8~yKuEUAnKsISy^~kT zvid;YH4lPgsks0VrS12aJ95iI(@#+ZO^WS~@vJkZLu-yGfG6L3MdiKn)e(`p@)lgg zAKNkeJ^|%QTmC?KFR7q^ZxDoF|D~{wO+d%*qa#frZK_(>3r(+)Ra1>ZE{uo+Qpock z(P%1OPc5xS*pq%?Q?nJE_!v6_EC>fph{viW$Y$BU9>7SsCWd3AQ|}X=SyCT9M_V|F zb1ZqD>6R_Jza5#HS8w{fmRcIlJ&_e9o!V=YtBvQ+dgtxbN}f+q5fc6E7s27x4db*c zOZ)E~ma;`&Op(3}dzb!tz)#S`T!i%fedaSuTpdEw`xXp6Y`?R2Y9(0myb+vsC2#+I zVOh4w{C4DTn|c$|TIw&4?BRP!Huq}^r-LHtl|Dn}o9(lC+*_9aSm{XX=>@s+KJoP~ zu!l?3j^%&Cn<$y-N3tGjX9dsRP43bXtqPn9ZkYl3d}6q-+R~8oRae} zc|)fkN%&vj-;{lFK0F`|Lk#Etm&cr0dh2XGg#$JmA$cc8@Swu{?a$e#qzC?#F)s(6 zV+>aT z{~vOt$=tM=ddUGFW|s_Q_^np6+K04~bh=)`?s9HG0lWxe}E*Y@qrxz}|qziI01FZxgDc4x~_>y+BC zx~w^wIzN+eQ%0AF>NK$*Vgt;ZL8HtExvu1%Jy3GriKcfQ43=N4In24NY%MN3{Vchx z`^-wMMrxerSLYnJ+J+lK_GPmgh8tDqp3i;lEb?t&f4N*sXdb=~G;xy|XK!JDWmtQ1 zK)lG*u?JOQcLXGBnJQ6Qus2ihG&t_g+}*N;Ret}M7XtZtEHCjmSmr4WjOb% zM@!)!nOdiihI3X97wv7@+U;u}7lQERpvYfyNg-wDG`1cSo4;zauVq~r9%h1Ki<<1q zp=R|Tq2~2v%C+-`d*0hD!Z_NsGADeG#>ZiHQY|CXF+;oB` zej+~B);bB)xH%P>|C(tvm!1x5_WQ`z+N&<@@>fH*&97W@|JPZ33s289TIi17#RGjl zhk@kRa!gm(aLmM+-%N8fUzF>%hG`Tz-Q~-!O2K+jXmDulxeJs`)j)O^ZZarCKe=_-}rKbRUv`-M&}7UM4i^57l}TWW~QTW(3rQ82zG2vtZ7L_47)nV*l2vP)5a62>UbVMVRO@~&;F}j7ySHguFLmQz@#{{mQs|y*kKzG5E4F63 zjDuel{6TSO*2z z{X1N_3hc-)&M(*UnKO1xqD8$?uyGNwXHCV-S&JIvlilViqX)%@6Rb#8`&8pnks`g> z98uKHxWw%Hah1K^@if%JxVE#^7Q1iwmcqIG7T@{HC&n^#bbISBm1SsZ%7+Q_s@0+; zsz#!$XMcYVM#a2r$$b=}B}1M6v5>6yBR9U=xzRDMm}I+x4BM@$HZi;2Bwku&B``Zk zJfresY$D3L_@{GFMP-mI%4CAb*F-obsG3oU3#C~cH#`1=?%c~UE0^BlgAK8uX_L}E zs=C;1ujPmAc~FJw1hKWAM}%n)aiFsh2=&6TW+lpHHe{z_yvhMYWRoHtJ~6{anp2RVv^5$22WnZI*iCSZDMd@NR>eIoe zy?_haJ>?5BUyji_aP;k9eQK+8vsBE#&Ry(SUwGS=Lqub^6 z_1QP44}m(~1qknGor&F=8Lyz-vwWZwmqU%;w$_ire5apzqLw#a436R74cJD_OGUlK zcVB*YXZtGo0k|E{Aj#M~?z>;J^thmaWlFNc*Voh`uD3co|f=hY#Wb%tea zlK03yVu?>GU)oU3YkSx6kdy73b(yBO#7^T9n^a+!E{_-G{=X&BPEKLt`LCqAKLb@d zb!=km^5)G0tweX~uYi`Hd%SZ;NT}HsI_wMlGuinV zxPO)zXnAHF80_2B9o-qYLcGkmT4uR*b3S_=*l8S=)63l#*(=`H;a(6P?Vi4BZkxTT z**3vZQa{O2?J-*P;nyGC8HugQIf*~QKmML(?@?U4oMFPNoC#ic`HtM;qUUb8(5<(m zoraN?{z9YEZH&r3*-@S7)Toc0E($EmwI50kZGI@Nnm>`ht*JlVS~b@;6m{Y{lUy79qZg3>GvJ%*vg=nuOO8CkEf$a1I(XTC=_F#L}Q3&(OONPg0rEEABf* zPl-D_&+t2g6Gxe*E6+Qx6Yn6ClYMmNhX2{Y2IYD6knPTVqW|uEQuvg2V%olh#`~}) zP{no@-F_h0_skM(x_1qp-*3}&pC{EoJ63Pn)M~I#b#5}bWp|gX@_jlRKwO@8fs1xk zz`xEn5O+c9W47oXL{gB`LV0%V>G{969bs}y%JoETa{^!5_9zGZ_bI<9omU;>2Kip` z-RWO}?>w&rd$?~4??JZ-HY_VOa^&Il^RW*4Va&g|V3c=dTU zoFd3@Q|HbY`r%&6t7wHar=m@{aNd&3W5*5de||CQ+{5*+Y=!CCB%JnI`zSFV)m6%e z{>8f^Gu3b}WKnsknzwsY`uB`-O8P8qDlEv>Cu4;p)aZdO)Z~FR)R-gQ`A*ZP>|PAr zaWB|u$dPT%Fa5xwmk1xNJEDl=!OFQY-}H&?`W2FppT~8|MI&*o2Fe{ zZGw^t41%%?ETk561lSzPvt^weGJ0QjX>R{4oE~azJA3`h6rK53`0hJJ279BZrtYuL zjnAZwxZQY@ewNhq3VyR#Fn=SlxcFxIAiwe6&wbHRy8ggZy6-@;>%)O>SHl5YSH*!+ zSNj2J7t%GGP3UGQHG{3K)YE=sL!s-LjcfMM{=&&srXOcmk2QPWa$Wr8Czqk47MBr@ zPy2&KpZ14sKMDNKvKGGYwU)cjSqAhj_df1jb$|5m&7H2#Q9|eHfIA`N=AUv$s7gt~ z^0TR*y&|5~p~f5TUFLQb%P&qMmN`!{mPJkwp}re}UB(+SH@Sm67cB`Be*1%$etCl& z7rqHie!u>a-Jt)u-n{!~&}Du7<|5^f=`V>)|At@Lt4{vB9FD72VMU>u*UDY5uTL*( z|9C94W%jxF^V_=l3q4Ht_S{-_XIlrTSw35*GAINWg7EWT7dsAJN?8#7yr*i z8G*xwqq-f3%c@6jOpRYSU)H^MJg*A)dT9A{`Op;8JKfmEn}^fMA}_1%4L;N4z6r*5 zEBYDh>!ppaL+v{EGrXPlT~2Dt}0H`e|;!=p?3}x7xfP{Ux%&-!tX0*yF%FS z)A_y6>3b2AzJU+_m6 zV}0~+ZBzJgdUF>nJ2`^x&JMK>u01cbzsWpju@;&qzwOSh|0CUv!K3iU9-Vd4T+I^; z%~wAFti_sl_>kprS+#+#q4U?JesYNg!o3LfoRtnWR-&Z3ogX9zFb8E3TY#et{-s8 zZdldC;iKhCj4AE&A*In-pLT<|!CL`;pPuPzg7W9&nqY+rKi|dRqPIzC#KXa)#N}_x zq^IA4@(1Wyhcizg?b)WsDb?*%rV_w)RqLUPy0FM*QYVRN1*8Z3?Wg*Uk5+d~#5X;O zze3L~3_p5r{o}GuLy=YD8!#fJ;b<_JvfE(Ia& z&h8=eDX%?+RV^Z8ntUD-e6Yu!15cIVUhrJb^{&D!$aCXKDI_J_54dg-NDF_9XTxE@ zY`{&EI+Rp;xnb75kkN)qQ&)6}sWjOidzu?r1lQrRRvsWmH_+SCg7Ty48K<8k31RkJ z6Dk92XMzd?9oNU!au-`8kvFSK1G2ZzZ68+O;j|xMTU}u3h{eAq-uR-hRJ$e(X@B$C z7_wl)-wRLlKwc;ebX7{j-hvH1$1AU_h^(LaFw(fccI2OC0EIknrX{`;J|mqzg0x=% zLm1taozr5z;XT*v*Z=$!*#|q81j2p@;;qo@at^`mIg9s+^W*vz5^doPT#;Mv2eZ ziKTVFs7(_9*LP-Gf$IolPW$lmi3OS&*#c369k-CNsuK9+M6$plEwdsg9M)KvH~{P1 z4z6kg5(A5n9n`BAeXo|fpP;=T9odVk4H&``+~El)fT%iFPp&}tk4ml`6#NNI=W9Gl zGrW1QmoyCpZxn9gOG9d(fl&iwG-Q?YEx=AfM zM(M;!70)PrtG=DbNC#L$8n2KJo$a^JPq)|JdLJ*dvf5Ixce1|lkz9B~A)Xl>J^tDF z8`HaIG{mK^DGE#T8R2h9BzGh`c2FJ9n;)U|T){LH5`GlK^Ho1zfLIlLS#5onR`=TJ z=Ubi{#Yix(CrS)px2P^sFuFdsC_Vnk>$9f+{DXce>}^%)@p!VL!z1I!7hXlACEkhnrTy8wRwCntp)Z5A^{qu&KrgL(o4L--^CO<&dN;xwo>vJ9YKIpQH z>kpu~?dVJFa-73k4)@=(WcWA72S+3MjU1M;5!8nfl^qK}QeuZdqBu{Y(trA_t51FA zUQ;6A+HjQ@$B$=cIed9|wkeACEOo5&R-%ux*6;##LMUAs3~o2u<6uaz&alP|w# zbMRsKy=rbX)8q|1&Mz8@4rTD)IU@J58D%IJKUpTrYvIlVb(?3lbJm&s(Jh6LA$ z{v(S2@oLpuJmdG0)eSxT$&1DdHuS1<{AUeSy09mYjEf~+4NVBiB%Oh2boObafLYZc zC)A+kxs`ZmRzm$Z6%kIg?29!7zcgR^>`D66$Ea|8(g0Fu9oS(vOa2*8qJ_ z_3QVICB!L-!`aEKu4ul_U-xa=o`Ig{53Z$5-uOvzWS&B{F0-PI$PmZHn2o0kPTTrJ zw24W>*=ekXsKCv3uhS5I@wpZZA`%1Tetr>r*LP_t-ir*`3{^@xWRY}#t54`$eWMp5 z@q2Y!!l_1dWcXo9_w+#}eZt~B!`)CcAtjqcT_;oE9eVuFUmK}j*W(|4T%V?X^o@73 zw;pX}<=O6d7Le$vwmt+1DZ0 zqdlCg5d-1pr=quQbT;eTeWy))x0G^nBM;Czf``=`dv1TX&%^Hpc{{y-R1`;l%Sp7@PLUuoH9$bdo2C< z=dP3#mywm617&Tu=jeWaDK|0g%JJ7ebV;+~y8doi|HZ{>T*yS`xX@`=*YD5QlPnYW zZV8>)*(r~i+zCuhyzUytO8IUAhzW$!$6 zI6ef8Wsc1M^A)qj|&&>%>cdqw6$sAq_iN^SEezf{UPNa1;EW%@x zBQLyXXX@hHIlC{oqy3w)8^y7NtQUAG9gCP2_-b0p)b28v2Kb5@^uljKCkoH)?S#&| zm~yhZMLt-=kG0&t?~rJM`2#%>(0LScr42zJBH1VF|M z1BB|~3e(1xS3t>;egWY;JI&Qcrm zf?`w`NBdEW3UfQ*qXka3rP9xLRe~b@cfFB<18XY;hcd0Bc#}T3mdgF7bOH81IZ0nk zMmV$zHhykG^)u)n*F0-bp$J&Pr4%b5Ej(Yl{=x9{IE0|EwsjPDl5uU(Jt^ckguL*s zl^1JL;W)%0$$3rE?q$;6nj~={hnpu`KwZ@Qn*p9_T8dR*0SD-JG6pzL6Jwz>0xJQBnt-LrMF2}7+Dxt@ISRQJY@BO+W z+NuSaquN*k#{Au}j(P}MpU6;P9qCyv5v>sROHVMQe3oABXRv=PO71#^*WEM0tK zjnPuFS6QTBZlr$;<{a%W6X3)+eudFZ34TBu%fg1q@gbgYpoiu$2H~l1*^G0femp&} zO0eR+R@M(?W^N74xHo65K0h%r)0l zZd4jWFYT39bn{%nXNN*$OD}GSb^rVqhT%Q(-rm-B+K@X;&*(#x`qf-Q88JZ4BWg<@ z+*OSFeF%#PirB~%W%@6ZBLxo$R!`URT#^dcg2(z9dipOLBL%fCN&6k*U_WHmf^kDU zewI*T_QS0HYTY62Jzu*SWw`6VB)*bu8tPfQ8NjIER{FD=r3h9?*JrhIDBy}BDyHxZ#$#mSlwCgt(T;SmBJvGyhWY z!i6ymPPpx{p$`*z*o>6m(WB!u{0BVCCBpl1GFN?^dk4&!_qT>GB4PX;7MVw`SCgxKXeJQzw4(WT5!RtbE1-m1>xb$kV9lh zA{hb4oRuShhOZGBfv(Zml_S6gYMeZX40hxs@EE_62Y3v|^F!ofM}`t0H>jS!l-E#L zdxRGTDg(Y{zzK&n0*)E+tdWILFGY!30b;aKcYvMobtfWOdwFLDJPrxKIT>CHcI6_K z6;vLB@e>jUh!IAy0C&cBB#FZ8<@W-K!rbNe@QDs%*5;90ipNxVeO%|9cxej9{FQ;Q zpDPh4O;`{IG8HVwVX(~%3t}>m69Jr)Aj96s?-@hxC=3e38RZ?Tu`A~R&E$&G5W$!q zIz*CO!EDNexCTk`KG>c-l@ju2B7l}hgE9oj6}%~o4;uqb`9X4sApTR@!5L&$q?wca zo*)2ooQpf0S}VBMPt(BuXrodfFaBSed#}O*7=E~ zUti;i7?MLmNpj3#yUBkNvi?~qfgR!R4jzL@-LMW z1+{~!ts;_M*&_WXHk>9t1A!*t{0-bVYoq1-h9Q??%34aP^M9j8{i&`CQSPIOiY645 zGBC0J2$Td&48QRs;wPy&Nh9mzPeSukz_-QHJJ>k|RPv53q9zUaEoW6>^pI>Z)i#`T z(Gc*9X&X2yOSza02_>B3rgGERd!j6@*eqIk1Z0k@n7N^j4kR#+Z5kp@;;&m%w@ zd^onoHE`#(a*_Xv8=FT42`oPL#x;=Tz5N-H!9ha#2u32mu8(V=P%+Q8H`Uu@R3R}L zVMMf75EsCQ*%gcD<$g2%CwCvNqP7~!hY$F+_~w?%1fLT;&u{Ama$Fc+A0E`EQ=G$E>rIg zwn}Op)h+}#{1oU(T!2#XsnAt^sRSKp8(jguipHGA67UdkBR++R(bd(`K2s@V#xiBR zq~d2erR~GhRj>m*{!^Ts1u|OrfT=tcJ ze54&<(OUV_Bjt+%yM{+vex^^A^-y;H39sy)FD?%fJw+TG+GRY__M?2Nswd>&pG31h z7*SYaq<1$QlyIZMwAeHBT)`8z%=J}8axru;K;b0uoSt?Nukj{eWyQjD|sK=*|Sca3@_3IyaWbU*iAK5;v~#+%vssFyoO01m~Iw z&!ykRU+L++>1U_sNJxRoaf>HRKy?{8k_4f0LbB9Fh`X38ExkYA3+ala>7V2QTZz#@ zcAlTCU3n}Mgom=BE}xWsFk&|i>a1@jln)Ah$~(xhOS^h^P(Ea%a9ub-b5nrMmEodD z^cX7?q##Cny_!t?5>+KGuEt8OQx~YiN;@(ZW|L1P2fK@U&bRX|WrAKVp=c~jKcA)# zCZn6r(1*A~Jm(7I3hu3-(isjg&!=}73sboTR#3dEPxRiJS85Hby{oD1y}*jc^T)G#C)cy{-!+V=>s3nF#f<{O(qbMjuRq zde$p>=N9NI%%x_Qle}{ZlzJ?Gyv?N1bu53WO{bA{EdSs#68aP~r+~kukB>!gXqW(U z(s3mqCd&~hHH5W;ymKiO^B{6V90cJSy|}ew>po(55-3CBkDF#MgZCBoBB1`7bLl9Bu^@HTRiXpSu|s%rFZBX& z49yHf>okTDASpEc>ai=2!27~E>C$NsalJ-612r%U2-A9+y0|i?b@pu6_fVac7r;d# zjJmF)p`{>iuWj|QVaOJAk^?M&sgZM07m4{N<7S3QaV>(z^2yM7P)a6P70k5}yK)tr$C;CEIH_^bfSFK0d6=0tADRZa;H{Jc z2WyF-Q<4j^4?J-V!qqP@_9R8fV3rgmP*F07u?9o7794FUBABC6rO{Xp%2VG%Ky@|6 zlTdHQ3gNEemEoXZ6A>OtTlj$_u7N2y*rt)ubx8X|o&eKb)<_QYlnj#7aEX9s6a+>= zg*8>LbMgRJRnUy$Km@d&2_^#cEQZ#nYhWLXnqY%H0o#|4k5)*VC^RX9 zIGfwi;BYG}LE+TRfIA@fgZgzIA^4p-Iy50q&l%@;Fj9+GtQaODL74D4%}YWeayCZ# z>&gM?B3f(Wp_{$9d!@!sT1_ol6x0G3;Q*KQCW$!(OB`23R<`gQxiL?2y5 z75HSwAZ(l4C$ChKsc;@1V8%D%O*=Yqf_ywl3T7V_MQWKz5F#37g%JS&0Z0zOg92oX z-5oiItL}>>0bFGr^+vkG0`Mvs*0{0Xa|INlQfSfuvjj^>TyH#KSf~01HPRw7Z}Vj; zz?gIiMCiS<urg{*5GkpV&rcLq{VXnS zMncqsZ(@D@?EIUhy0_KyS=w81r&QAN`d2F!xxWW03)kF`l7Rd@;uVuzuFn|uFH#aO zzc=yv?{vFNIZ0Go_VARXF;#c;v$}~&`!%*QPkS9>oFh=mjaL;-fP)ijmSJZ95o}mR z(wMkA>6y;hu0YNzUkb}V90Thz&lftr*nOJJroW9CkKL!+naevP{IiE=pU>iV$33eX zt`u7H*Zggj-&+)@>y)2_sVP|fKejy3<3Dzy{|G+Z@qCu7JMG!wAg1-uGEacc>OyzX zGm8Jld8zSRKEJmkFx-hX-caT=={>stQ*vq@#1Oktvx3e)Xm<$F<-S;KDvL=BXX zo=iF|1RVTRZ`^@mS|#7~{(O$p^kJ%caYdA%Go6TnU^WK%5^;d1)OWJYWi3k5^^6Bb zAU=pz_$f)#~29rUIL^yMY;p_qT$}GWMfu6L_w!~6zXy6-23di_yNd91Ld17p~ z=8|ib*;PQoFHL&VB7mpTE@_b*hE#^F(}LZ3XN5x$gMvtOtQ@cBOoiP#rTP*#Iwf5< ztNrO&>|{A)i3B~oZ3q^+r!t__v^so+{HSiVMvY{Lwl0$=0aoDbL7C4^Up=a#mRoavB)8*C{V+HCG;DNM;J&~Ga@(+fe|1?`dBP>cCbyT%BDWR96}HsE zA2!g!cOUJdc8lEqb(L0Ev?14VpZqXxbz=CK>LK>ckZ#ld@4iOW6VV#uTZuWa&1dv* zxC7UQ!{XHy$HCN<X;!*hy{#w22?Zij>{6ktVV&va#go6-c^A0s;aCV(^*=sz0N`AD%B10J@jB!mHh@= zm5CjPv9xD39Um_P=at}$so8YY~!X%VS{1z$%%`v(#ES<-V;V&%;ufh z=X?sw8FU8P2rtxxdW-Q4GS8?9DP9#gZM~O;ysuK3cJy_bR-P5v^_=B*YV8!Tpg!i*(LwHg3^Gt1cJ%Xtn5~wS6H~25jkuM&+B&W+f$Um*G~rzUuBD54GIuJGobD z4>j14o#5=M!?ASZG-%nOPGNNrx3EbM!nAs2%n~It)@4+*$yMd?k7-u8Lt{B_!{p9T z1Qn67=loJb$vA)7fLvp@grNM)P{}~GvY3x{wjqNDb(|sTto&6`Oyo^0b7rG{iq2y3 zFp|~avMk>K%*SX{DXpL4OX}Mvt()1gU+HxRzPvw6cPTD5+hZ$pAY1vdW3p21h0u8gPX+s_@~n@p+j)C=LeRjBj?C_E zv3&qRWxGR-L1Cpv@Z&duTb1Q6G*McU%;(M9hGO5E)MS23ezXtfM>Q3Gb55PFEF+CmCuy=*zoTRmbhQMwd*_VemYuI#Hb zd-0t!kJ!!&J)$lC{;FHKWHWLJk*jR!J#{W9s;0aJwyYFY%bv{}v)pRWs@-2Wm-dza z+~g<`zxjq5xp#6-3jc^6l(P-pv;8Q0T5o81XF0ol-{Xu4Jc}L(H*veP)wdf|L_q@U>hCC;euz)7E7i7>dq@t(c!xAO%wSg>I}Nv#t2RVqbt z?RE7t`99Yx>!s|Rg};0!#avUDiqBH@`*YTwazhdtxS(4=mTK_-XnV`pxE3s0(;Ty7 zW@ct)W@cu_n3-K>W@ct)J7ym zRerEyMSh6OV&#s=y{uCh5B^4lKLXHq7976lIG|cZ;%V@nccNmc`hF6>DCfq|+V#TP z+Q*Z>ruUw@W}q*1UdT{}sFqr3y0~45s;++G>PGFB)|JC!_@3M)rZ25uTUX|=T(^jy zRZ6hPcMp`0`KwV?8Ba?RbScBUPWYBZ!+ac#G|k$z82n)$0)xUA3;K?kw`#47aX6+L|5-@~)Dr5*|tVZkDTx z+r*Mb3{865)aA!@^Yb3xI=iy^~k=d%wYNNm%K zm(wkmEcL6BEI*$&oku)|;V1VC%ggFh7R>1rRg@JhA(R#@C6wjAu%u`{InT;!FsEoqx6;hAd}_(k zcD#!Hdf$vqd7l&G^3vHLD@cfVf;p(n -|kL6Hw7`A?#KFELfc185=>{;Va&Zpjw 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�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Ν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 z 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%0D`&hq0|nV{2mB+k@+eO~KSk>@?Vn2z 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

C<+N$VkE|3OkBJrz?&fJ;?~yv11ZDdHb_#=g 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

d(g3vN7qdzOb*`iDvs{q*`UlA;#Lkqwj-?% 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%0DF^&)k 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%0Dc@bqQouD$0-qL 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

8T^jM2 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μy4qI<0Yn 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

Dj@TEcovYS5%Erg z%t~VJMVQA1U+}Rm484&^p451S!gv<&+|?)vsq-WUldlfW zAVodazzVVRu!2m3;bDiF<;6q^Fb@xk5RKf|Focr6E~yDAdRhI*!;Udai`mCdyD&sXM15Hj5)$TNg_5s{*(XffHcUVozpJ4LHF;LU&0FSSMVx_PhiuRLH}MJZ*rN9%L34GcKZZ zVCWcr0cyKvCF$sGMO#)CGcLG(U-Mkj&eQm-9=%P0r!jVJaZp0c*V_t-qB+*P!eMJR7w}t*TajBGwF2U7~F7RoRvRo~=-78JF8NRQ6I? zp;px^yCqfjlC4s<&!}u;X$DyWuc%XY1O8eJykbdZn+15YMrF6k%HC5eRGxX2?O9;4 zuCjgK2%W88egyy)#^qPbjnKB$%5M3Uz3En{8&>64$H4Cm%dc7*p?^0iKXGXWO*Sbv z1FHZ&02QzbV6}z72e3xfF)zOYen$tqIHQGO~lk{UK(=tm(XUq@(p@4*1?##ivPh9PRCgFejEMN z4f*uN`M^86qU}1lcp!Uta(-g%g5SJY+~$1a@G|9I-Cx{p1L5#OKe?i9g6AE($jaw7 zm_Wi=;+}=C?s(+)9Eo>Pd9P>JfNY$kJ=&vOx}*(-F`4O0y8o3q&(y4PxuxOlZ+Q{OY3TmN*EhA4ZFVC0PHFRl{hB$an3{4^ka^U&fWS2N@hd~)hzs{*t~9Rb3W8ztl3 z&TfIIXNDV#D|pb~5(l=*nY?*nx2GZNTh+ahU1hPqus6rgQ@~b*X~6O)OX|BL@F#?- zdjY#j^Z?5a6s^|h-+7UTfv{OHc!6~ica(OqVXUd--v&n&Tdsqf}||I zSuBMen|;I{+AmXCCH_ER)gTRtip%dC7=hB?HR4w*%D_n`LJyRVHP%Po53d$?pxI&S zRl&>-_BQvzen`63Tv`kd^3Lz=?NsipzEsj$k}We`nzZ0sqO(w2`fY)-L(L>GPQO}8 z$)u2J*{HghE`LHhTMQ4tnL9P9f0;Wgfltrm(qS5yU5~scPRrzGH$k7YVw$MyJv(9V zJ3D9@JG*F^Kig*4d${8=eYkn+J3D{wKSMrXcn$6cy!QqJ-ur6DzUniL`RR|2KULR_ z^Xo6B2lQPqg#>o!!Na|F|3G_4XJ50jB~86H$pcuE0+_~)>UyOZ*iuUmRG7xwSEbmp zS(wHU#*q$U4#a-jMBfag<#z;(Gi=lxsM+SSPiWehcr2!=Z@`ROT~;2rU4CU6e9d6* zd5vSAevM$KSTj5b9t0%xg#Z+L>&DuzFc0Rg_Dy`A%uV>8&>S_M#t-hUyiN3<>P+OH zI8E%I77rr7(VL1qjj1EOk1Zo%9%O`aIob$?vD4)ZWZ=~-Ya!ZKw$Sgu*Aee9ILiMi zH!=T%ey|g2co6RrXQJNbXX4%_e=y?$eo*T&I=+7{!$h@W%^+*hw5m0IK~Pt_9&s?@ zf|sUz?!#P8D7@sRH$RCn=J?@r82Ko;xa8Z#V}8rZLV_Fd6&7XylUN^J=~7NotKYColi2bHEf#L*y!43&3?Gw zu07zTA2xi>bMaEnwBwgGx$7&Hxyvh6x!ccqIZ7%uxQhcLd#0p(Y&7p7HAR%$N(bpa z-rabPcf33=I#uQi=HtGXhL+<*6YkoG{RGUcD z&qa#X_>A6(W8kuy-Y%+>`B2050cwh_*lf#B?4jm3R;b7cU-iBd&flKd!I&8TnkJDKuwnn?C>>FMdW`&p7Y zI(XS%&h+|4(CXNY=uH(s4Mx_zmv;u>(&9+|!RI$dr zgX2Jf%4D$w9X0O!NAh;UW}PRL>Je|rbJEi{B?=V~*4x_O&Ib--3K%L3h0v9 zPchl#whNO!gtv-xP z%;TMfb?szJ;CU^bjaTKCZNTDeMh)2>be?A1fkG7+!V^8;s38-`HPlR&-eU}d?`5S# zN18kLF8R1`jJT0lR`_GIDn2&8ki0BXd$Z;XPmmW;kmaLTbJ(x!ww*12F42%sM3N{_ zCTDHSU9`i{M+@8_j4NPGg6>fiyyBh-xRT9OOqJPzy{TVyO6dV1jrIJO z43_x1h^Yrq25agcWw7}Fp77sj|5@o909hLe|BWDBp&Yj)P>{|${WlYX2NtR%5(;yW z<{w%MWTim8xWM{aaR}|@RTxLlXI&NlAl_~~k_q7+0hk``RKVjwN2dPfhOW+6r|NY+ zO#8s`Z!|$GfO}Rg^2C_vLFgnM4x*rDTkiFP;XpSdQkhg0-b^euRx6k{VU^y1aTJ#f zKy3bUVSb=jvmrFQXV5{^;~#F*+DIXn4cTWMY`h<*{iRvh6Jok`;@|s-NU>JOf)f#Z zyerG6FpAh^k4Mn*U45}+amRa^<@s59lLa2}W>Ho)Z6>^{p^ouswbdY7@_Q86GKw74 z53XeMt7GE5yzLXUmK6=8V|5I2R(ygz;`0K<3@Y(=xhurh-%xUBm8W$z2b?P;Y{Y&C z!VTXe{G~`naj_Tl1BhZDc>H&TIiSV+---eLk6^PmH~NnVi;B~h1mQ;s-n_PST%GCc z3Xl+kNsDNu0znGrqn>Mzl84k(ceQkB+*C#c*S-UNk)K{>sb=ntV0S#ocm&+S-(EjI zz;7X9lg6t_5&4lM^w#<*gIdBuRTda6(R!Bk1(oCU<3%?=aD~9=-a3+aaOZ|Myf6r! z{Bg1N9zmQ$#|lhtXUzrFo{vaOSxP9QONUU_8UH592$pkk`=BMgt2}2)eRO#h5yv4< z>1nmoE|rMB@)qxS-z2>Vydj}eIoUr^PAyyeMZzW`dg5WklR_71=$mDveU0Btv1chPaG0Sf8wEN)R4Jl&@V{W1VJrQ%1A_eh zk8#ER{}1y&GUtC_&5T?9OI0)Y^KNU!d0yl6`Af3@JdC4!he9ABxq!U6q%AOWR-Kth zvYt9pg!-fN{6Zj^umNvCMWSN_NPXDeAh>&b`h1n^Pm7{Ha2(R>DFUX=}szY^!0OG-NaRr5DE-s#@Qpeh#4S6D;HDu;0b!PeS&(mV2ILZ{XXN_VtpoKnra zUHL*egw|e5nE#VF1?4?vQbsZ!qp(XPX`~BK102f|=R~u<35u6>T)Mmngv2jSXxtA7 zXPn%~Y7gbkCln>YDpgs%8y64`+x)5A%97*u*=UK=7Bp_d6l$f4SzmJh813V%S?c-e z06(C|p32|TODTAd7mUfuOMyeN`x1|E7d4a+B{X*i;mug{;puBNRcvxxj7h^N!XVB5 zTwpc}Y;sQ3N304a(UgcskL4XjCY+be2o8R-e>SpTUw zMUkA;9)9*;dGmWwtmnU4MzB-^Q+FWW@qgqi^!I%KCU4p~7~4A=TL}VNM<)koL#O|2 zBMarFB?W-0#J670Nyepxt9dzEcW4dYpeX_gV?j`x7*>>!Co$WYCO_v1{n6fk`6xND z5E1(0LtLym{yf|OeY`(^2Jfb|a1SKkj}>4KNP<-XuU$;b=%Sa<>o7hhjUO09iFzco zwf-S~n6DV$ms_wa^T>zqT@v*G=Qp?DB8zXeLe+?-xl(d#w4^$h^qvY(7=<@lODG_7 z6AAuM;q+Sxo%7DyDPoyWWW2hFPm~?{hB6T;KNnf(7@j1$NfbrQeh(;?l(?^--Iy7$ z1!cGEG(^TKLFR^%dp}-pNibCBgIESRh@HrxoO;?+@q1bPA`!VLi0aNNg6zr}rtDdE z3VRkRX#HW1z3>F|*O9;4&8drabR1_`5$(o_{msii*H7dRDf0COIocP@IFKLwHWCI; z;v+(Fe5Rh((0=5`UcLv!;qtG@Bng{&5(AQB|3`9Me^2gz_Gzq)-HaUsZGq~yHb%m3 zb`Jj;obtnesjqrx_A~67?O?gefzU#}=7i>a<5vpIi3daC5+gI;87d&Vy9>=O#D~Ux z`@$+qlN@-!W9UtA<*K)e}%`gp~5L#`ZO?ugLY^3Gd_T*cPB2(q0M9EAxHT;nd| z-XuP396*R_aDY^u7R8|Dvq8k;CZ)q`dHtl>dvS@&BZ3`fq(>MLT1|{{Wl> z3`wA9tM}^fC5(oJm-nyXIrm$H_eI|dbG{WyXnG`BYgrIWkC@DE{)Lw-;)BdS9@>H` zFT|UZ^LAql`(gk58j269oOC92lrYFW0VvrT?`IsGsG`7VrQ|)o-8);g^X^^cy}3^~ z^(GW%qgvvS@7^8D?!+aE$3WZ^K@+d?CK)fIj3c|yYol3KWY(5Atm>`VOp}{&^d2X5 zOhuNXVLDYao$wG8&!L1H;C$k)psa-i7XP#G(!@gmJU+#8+~S=Jdj7x+!NJt2z-D07 z$_D+jR>se4F^{g9svX#2)s@s#T(Nq}t=+FdZkh1LY{QPDi6pQj0PX8#zJXA|c=)hR z(LYtp7m(%D9)>*gI2!SgvRLwop{{t}z&X9kG=DJ^39&*Vr65fSB<=XQ4g`A(1j`Sy z%fKSR(??hj0VahH#Jr06|4WEo8A~!IlV&ZhK5oP`Iv*B=SD#( za6Ofr1-3lEuNp56uzJz`w{|j#Oxad0x;?tdL5I7o=~B#Olj|4JC5zl(mq3}oDgif} z%zJd`hWCIlfsSn6SOHHxob}}8L^rFVQu=lNtW+n1C6%X;idQmCawq7U6bj?LH|_+w zWr{y+6G)GWiYUbKv-}e=D?hVqv+zy<+x~Yf>C{YICV62r6_f6+$AwHm3*>a{xm21_ zYdWkrJn1cA@}fk&MZLqkWE6KknOYpSOfxz^T5I7(6N6#a$%jpAhc>bY^dSAbT%CbE zRe1w)F*^FGqYi-%F(mwW3>Bk8cq)a#O%Ue7vKPyU=4j<%nq%;#*tIv1zaWgxS4Uw1 zAuI!r|K3xj{=XqO8Us_MlewWI9lw*4gSmmTld+(gv7x2ozjbpf)nL3d=iNW?G;gBz z(tq0S1R{pCzp+Aze}R-j859SrwW21`JF>IQz}6H>jwCJ~USOd*m1vupj#>nVJwdgV{A?rxW(Y^J~KT@G{dY4->+|FAAJrpF1|e9pJk@jIUK51&@oCe_%Z0h$C5r}FJ%aHyOw!(k$%6i zpCEbD?8I<4Q-f_sUNwEZus7r2HfaVQufo-yy>mb0OYlN(@LsMdb&$nBiTm)N?hWyr7^3#g}%HQpJT8r#)0zj}RwZ7gbVN>UB$4 z!fH=8S8kiJzj>;oT*fOf3rtxc9!ZZz}1E9u;6e={V zVROvS+%hObt|YS*hb3WT0P2#ULud-flxTRI?k)o{SXC%BDqELO^KQ(@KRZz)Og5Kq zZu1Dgm2sIOJf!j{6GxD*3s|bRu%Z;G3B1a_weQYQ3p9B2#SsgG8GV72hB` z_i>e?c@vGytA8htMYO`Bu*S{rksQYOZzVuSm9A%`c}uL+~-PMLP;wc=~m+Sdq< zGGSBk$h~loYVh7^In}^JvAb(?P0&Pc8g7gjV@8ARS}#qAN~IN-OM)H7Foq@s_3NdJ z)DB5}`6UgU*6|ffmi|g1-2@`98>;jdT15&^HeFVvWEd`4YJ%0lO`qPhMy66FwRP1j8f+SJU*!+{S}qORbT-wwyyUva(~S|l<)@Nmqu zgQOX`n+)J$L~3Gkriz(X2+`@QBTAly7oKfM-L)42xcq)PO|+q!*inAZq}MkgX*~8U z4J}MyTp{UMCqY-y9ZDRY)oDpu!mD*zxgM`|cmFEVv4YkFc_vge8-9#}lEN;sCMCKk zM=H{(#?jaC{G2<{=F;c=&fc!78(NhNR{;k7A?83nZ)qDAmeX=b94r!NX@LHa-VC)) zYBNAXx)HR=WKZQG)sCGkE~*?%$xwsbQADYXE9fq*Tm&m9&6Fhjj5%0DsajN8RE}8z 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 z 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�iZcChg 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

Gaenzy8AQXNg`y-9sY-C4#s zt9(DL2gKAN9u75k46}<*aC~?O<2Xv`&S^A*l22Gno3%3z14BIK33&F%;&JnS)*Us<7iz$C#F0-@A*<OY!YFgI$_FkF$5SZkBvuZr)4 zYHUqJobz1q@ljTRsceBOW%y}t0Y3gBg zkw49(7`5}VMHvg)%nzUm#F~HXQ${rnoHrL_txB8$*6edkHCSBN--tDc4`8Fd1f0pS z;zq1w<+C^gn!j;fxIr}P;znZ$^YRI6y+schGe!FfIV01=3XlX{fRPkj1YEfn{y1%2 z3#Dzw=(d3;-NeWXd6jp-Z=V(DpmU91l0}@+PEmhd0&8B(|ETG*OX^*LNZ&O?&J(qx zhI0GQGSF1w^;8!h{->=IST0*<^EY~v@!v*o{_ochCj;mIT0iNK&L|>lp;cvO*O=*B zQ-%2kriL(t`bbE>Oh8B=184+eM4ZH5i^85U5(E_#6$AxUJ5XRD5fNQJK~#PqH9@|; zmWce8yaF)@yTE>3R^_MIo%iYEl*e4s%lVVCn~K}q#B?lkRx1=?BWxY1YvfSsU((*Y zaC%yU$U134RT={xs$Yc3D1LMj(p;=zv;m4#cJfD*(mxDH7-JSg7NcNHiD)TI%4n8R z60kV$3*?9;o=FS#BEUl+Q6l1D^C|PWv+42Q_k**Ev)PmWlX11dRnqGv)TqEHZ!~DM z8^#!hpJevF6W>yB!o;4!?33XUV<^KYBN;=j*&SzI1mi)pBpAHQs=l>}wb5O`?2Z1F zf%o`pxP!k#yhFM}@I7wP2FfUS5oSpAO!OM*GxR8eD4!9e5v38P5$7T0DAXu(^h)$8 zCN?I|@;7btb#xoa_{bf@ucTL0Sk!2AB-%6@E?PDkM-*KYUQ|vLe^ek;n_=i=sa{Re zyE&;L%R#j;vrOKG>9u`@P&7DUSlpDwtXbcfaf4xl@fD`>4W_b-(UZ}W`JL&V5sU$h z@s*|0qoy*9F_c-9sn#Ug;18w|X7}vMAto{=X*34$Z2Dli;nr~aYR-BE6K}JK+YyDj*8y^06n>3D&Ce_Jv0;a} z^80Y)PMo^#LZ1W!>iI?tHe7PI1^(6fx*>RFmn-+Pd)zT5+uH;d+~|TW=~dwOK}+ zkFiT{dNAvhVzC(EXecNtY2;JPbJHxrtnJlAs`ATC>EJT2o6}1kpZ@hDH~#K=S8RV4 z{rCk0K8bw)h3^6#xZQ^l(tW8l9qr434O2R75P!pj_YGrq6n=R4X^tX z!VDR40EJp`@P<l9lxB_emdXIrDc-*)bEBIr6UDohz)WOlHj%PhKPlgya+lpvd2+G0vR)~ z_pTuUoTk%vRRPj>1#b#N0%4{rDh5nnGEQazaq5gt6xH8>JHeI23gXlfodDIp0bNpc zBupRcuU1$Dnbzz7RFP0(kej6FfY5F-N!EtBfwGrVNrdRN>Sq^~V7|iz$;*|4@Xni} zfDB5ZEg}I@)xso|(1!)LDo&K@$NK#S^RuYmuO?Bdz_&Fz5vBYmF*@-?{)b?B4O}Kf zUqDm>8p1VAArWlAmq}7nh(S(Nf*JxYNx=~lL~MdWB22#_IuQmUb&6slSRWLmD!Dmy z4+fJ|13{ajhy*(@Zj!VG&v=>-TZM7SJMi3QO2Q^pF=7!w0)g zQk+8a zh_(=WZqg!xEe+9$7KGUZ1tzS)9)jv!`B4FNJjvbEH9_@G-|0exTo?nNhEX97xcxUt zC<1T#;4})#;5$i7QV|411jdx;pm1m+JkmqLgCKEWQe=Wf2%?x26yajXKS(Lk!QvQ1 z5|XuH;*HUXNa4lf6d521%9x}j2ogc#CX$l`iGT^Kl4Qap*hIL=TL1~N2n%+VjN#g# zh&^D(2$&FvU!_=K<2ab4sPW5CiBIz>@yUP^8Iq;_q_lg9ETl?=Z(QPhmBmntKunUQ zf|@vsR4H2!7T_kyTOc*YPupJ1+Nxwl#$3hpzyAj4;=K3@RD?F6P=A<3HejZZ=+=z* zbyd+#oA`A+CT`0vTqbnk6C@iqffFW7ngd+>`A*j6+`4O7^Bw@rwQElBMi67x zB{uZN!T1%aO`dTq2#uwdZBUIiA=mA6w<756&N(r7Pv<`Hp0lMd-RAka4&p*9V?w(~~d)ZIpYfxlPPA5QL|CuiS0 zx)Ev@-$1SdwVi$8+x1;HR`uYzB_Ens5iV=5q}^Cvm)}g!1HGMfL)uqmAD&lnz|MZ4 z;0FZT?D}|ct3JeV0|lLSgWfo$AEw=4VVB=jvHgghb^{3S8>>@#n=?nS#LUU=P^S9uw|?$NqcUf}J)X6L_zvm=;Y zcEj5CuRCwYxb0JKf}0##Z`gJs+%CQmX9qYt{i2;5YH#xPc(Thr0K1`Y7r&Icu`hE! zgWTbFsy+z2;cu6|n6>?(oqur94}`Yi55L^|ZuItmU;S_N4uW3uZ}j$sU+Zu54vAmG zZ+7>Hw5vZ5wFBcWzG>-3I$v^c?-;$cUv3>Z>DIm|_yXiEzJd8dsGWZh^F~uTe}d=s zsJ5%_HMDC!=3a65>OL5~0ri%@IBEx4I)B}fuZ=h4_PDi6U+CI#b!Xqyw*4`kKcQLn zO*egqRqY}#{Pxtnr5_UBxK=-$>jbU;wrN`7)9|Hsrftr(>322=?E2kSBi+`bUNmh{ zxTP7bWvX%C|%exmrzBqCmA~zQ$+nP z45N!{M?o%3mF3-x$o?_h6jVi%E-$%7dX{DOO6G9JJ5wJ`zJW7?ER%id--$LA zBYvU8Ns_Wi8QUpa=XOWfjXhqm#_X*{>mz&TlF2WQ z9B9Ucbdg65Yx~$z%&p6F-g}LpbBs0f#zjZ&rK5BaXbrb{zQzB>jkX9}yXstUP1JMz z9~Gs>O|4G}G#ON%Nq?4FZ#nL01HdF))` z<{2g7O}kFCyy9ZsQ|DT{k54&v$Ue7TS+VbY#rWQN3vsy9>{6UK^?W zbI%`Qn}9!mx^nv#Yj5)`z`q`^L4Js^KdG&s>RPa0+csdoxPJ$?Hf^td7JK{kZ1m3f zP1qsZuS)@&>7iJf=;4ajBLZ4on*`XoQO@kbfIX6t#@mvBjIN}BLR=m57kitZt0G4S z5y#OH?-O3t!}~ED3SR%;`DlEXO$oF}(7QaGX*jguPZj zTP4hmd~ek8!!#&)(?3IA{`@CJ78e%)CJqh&zy$NZJ2Uz}vS$CEXGV++tjzzb=uP&s zS6)FKo9n@LZL-r#>;acrg%-l z-$=Ezu+mD|hy{Hc+L)EMUTN@KbinyOTfVQ;%#Iks&oMobHk;(A=`p)45*~CezKy&6 z$acEnJ^lVZ?DKo!1E2{yrTq)#gJvD{4bhGkOn?sLUX)UzGqpZNlV{EePNRVKoKy8m zrcrC*!92BCbjIcmXrTNy~~$Q`Iu;L?eDxP(KD%sFJbO2p2>-KDMad%GNxwCydt_P$W z<|b|(z2mO?HB@$PQ$WhA^>7@%9$rJgeb@9B8w@i5y1L};zhXSflpS4?jx!4R<6WVS zyYuk0a`9;0eLCem%iio9CuKKfB)I-@WPg8O`X;eopib8EpB%X?x|_~pIxQBN(C5v% zmoT~QIj}wb#jld96Ij4S194&cks=mEL~Lhge2$a za2drct(~Sy+VDKZ!U3wvIV|5gv3q5+`VJkTI{{*Q?h|4+-o^WK>gf!G2Hly1jQ%!6 z;2_i8q?V4J!ff1ea>M%(v1135fJ~pZx@<3JA$UxNmhPlMa$EK}InV+Q*|PnUfKtDI zw93rXG#a~if}dJ_f^79P{Ao@=iWRrFuiF}Z*OZi1eS&Ve4?UTOWFy!G=Ga=unR|rH zK4wl0Of5U(+r27F!bOe>dT{^2=`mcn&7ra!Sw zK_}Hy36lkmlb!-%587e@G|$H=QU9t&bxUSE7vVlF3(6k z@uOdhqBmc-d0^k615JP z7$hE3IZ=^Gpjc%|rYwU{q12+GvS}6FUfEM^$jY(5QvsCU1>aj<(eH}5agy0QU%*;h(a6G#2DH-z^NY80(NSM zI||!cAjHA}Z+1Wv^mxx!&E5`xUB93Yh5XmJ9yg28!k(~o?-~q!ANQ~2oosfD6UN~wSlWS3``b|5vZ zZtUAp6)?4ZOKl^2R@Vc~AS-)ZSInznFZ-T>mUh5f)^<4d1G3R5``y&tp%Yynxtlqf z%1!`y?O@x_jXHxV&~X}1a6FiSAv?9&v|fH7gQQ-5&hP~QmU-WFDZF9}gkQMkO&QNs zzJYx?04UWUAy&YlGk|Ooe4P^HP9ambRFQqe=-!+&0$-7sLE`AX-cx%0S-g4vP+<%n zy3`ruf{55K8W$B_0eOg&+^^9PP3#QQAu$)V?3~jfG&bVVSz9|F`2gNo(OY~jD()QA zA*7e~TXYxkr}%afAt$lri8mu3-2}UbWa-JLBUE$RpjC zC~iUSIO-|VJ483d?40!tn~Qk2EN?>Usq+*0OZz*-myo|G`!jndKIuv74W0`-a=v3y zOA%ht7p}>G{c1sOhJrdJ&wtX=HR{`ZsD7OUsZjsje)NBT2Fv*WY)8tMzda0uZ&@uYh=Epr zcVLmD#6YC@D04s&gqlAl6npu7vYQw|gy$p{4RiZRd+^mj5nxlY^ht`dp zA3h(~H=KRGejkwfVAxD_d#TYFp`_8{5Jt+Q7|M_mm7(1S zP&p|K|@tDHyQ_BH_;%s zw0VTR=N+I!(38|}-TN|gGYk|KV~pJ@Ss%TE+@{WJ%&a#ctz{{uErmwM;bNN=>#TTp z`>N3>L!h~H>{}|!a8r;lb;CCQ(YrueiwrQa>O2N-<|pfC)7fYq!Bx78WqtG%A+Lvn zx$b{(((H^)Vf`rI)`psa%$2vk_wpEzMyh;m*#b4m9 zxJTU{7#zrf1S4#QOwk?&3i*P{1E3I-Emh*Lr(7Rw0tt`GGYBPYw)$P)Y-1AR&;8r8 zP#?(*CWl(RR~}>rwcs&J|GvFR7`9xuwhVrz>asfm3XT7W6;xR|Kk~5r>tC+wJM!qB zfrWM4YYrr#x_eOrQ*m^jai*Zr$2L;RP?eaGdBDW>6FlmmQDQ9`Er#aYssr6Bjn zYXEwNQVl%P6L(`G{BY@=ctyETdQT%(A_BDb25)g>S?Yp$JrpBE)`=KSyWt_R2<01!WeVC^`0IAcR>n*w^=k~i6%d7CuIXnd)TD0 zG5yl>j{M=*nD23m>f}e26gyP zffZfQ6&ESNLtYx+p|Qsl5!e(`_=M1OCT@k~J-i&9-2rv&%*tQ!yevh*ns#8L4_lx+ zr8AX2B!L6JNV$)nBUq81Iq zUqili>FMkT6ZBfM)f`d-68EJkU7gBLzT0KRI5`cC2E^*@USE@%>y)TToU~OB^;(b& zZ8EWpKkYm1CdEFfjWXOF`^Q72qrzlIqq?Eo*X>4*0g<)ooLBZKx_69XN-P6<*_1Wg?w(O|-+vCmPsa z$#U=x6HkMkXBjG*yit|iqmX#U2GI^Iwc64P{VC5oVPV_V`?lkV1U8fMQ7lV-Q_n0j z-$Qn(WIoMEZV_{;8@Echv~__l%_#CaDEN2Jm&o6 zqc1+Z=nnB1Av9kKZULh{!vQ+NEZH)$n@O+_dk9{x(A0X1U)5X(M{_=-O| zhGI_JuUQv8FE$v?6`+GNAg4_st&J~AZqrKA`r!Z(9&EXZfiL+Et4iW1UqGQr^n3*o zy(__>*j{s77$f}hk9k7(*=F|AnD{%ja^iJL(tMO~h#!$&To~q>(@f zB?BQOz!k9w|D`Wk@(B?>41xb3XomjUKovmP{t< zB7i7bXnzk?_(6@VL`uRyc(4+Hc^z%s4q!54j8iuVL1`A5SKCi8A=OG}luE+muv*&P z1Drou2nmfzoH)4O<~VY(A6pO~DYlwN(3f)XTR7TmA}@ck?p|gRiq2)8;^Wl%H>OYH zUF@%O1tr$o^~>q3-y*Csm+%5l1lVmkH}zZ9SY~nW&T`0~qdh(gu}ef21RUL3T!1t! zHv0DS@23(kJU)>uMRr+Pwf}i;>{j|-!`*0=v&Q?6c+Rle)#hONTADV;Vpd&EV!TFo z%ge(x?o=9S@c|cK0r}4a^4J8SA)-2WUZiQ~Hd(>QmpfwlE1rAJ6cWc`g?@~~VodDh z1}6u4u3O-ADyM?^3HO5YCI2YjM*WRYZ+H6se)nZ7?MLx8b1DU&(iH{(b{eBv$Rhpe za#6`oc#{4k@WI%7dgK{_gqRw23f)Pn9 zO8Xq0RsRU^(cXI-Yez7PP*oSg>ZFxA-|H+I@t?{;z>~g`Uu7RV9Ip4pm6`O23zR$36~;id95gErTRz+2U~m$HqVU8 zu~^|u$f$@raRL9#dYHa$Q5~VH@;oA10`)lW`w}$U;9udKQ9e%!_OEb0FVYGq=KWqv z%y2@uQJE9}uPp)E`doCC)X25|gbOuxz-IaxcNU-LNXO>i~xAo<3E`klDmodJ>8*6T_TN z;`UNu2O1ciTdE8Upmfjx19@)UbMUw4%^i+g=z)8NNu=in;Oaq6L&Rge9)A7$>-Y-2 zyZO;B+I+E@lLf`JZrWTVpx@1zr=hd6h-mP>(9Aqsa;suR?XW&UJvtbu?o4w0C2n&! ztu6yMf%9C3lCq3m=K7qnOGWo2pv`7;g?8o#5SJdTbt;W~xACW8rCGB{->NaN>)$6| zzJ`PjwPEFkzzb2P!YG+#Ah>U!j`3k757Yq;N29ma+ zgm&w}n|bhevzPA{e6RwqMG$f_lttJy2H=I-cV@#z6eni!ZG|7j>fSbuEaZh2EuwXc zC+NJLa|fFo7Fug#X_nA74#6(Rd@1wYUc4rS8K~!MTQ2IB@@?&D<&#}G$z0quf@pFS zUp-^34yc)@InESZEz@NROjcKZl+WUdOXXWeK9J1J9$SBV_0Q3XCN@fag)jm-iD*BdUw5YJ>TS7awuPKYs%qJo=C_heL0{ zq&r2be+Xo45#`7&j)+TE98whsGt~cLZCOICe_0#8&^fFsF|0s^batF^@V1d|EnHDm zg#Cgawf{e_osp?v+&Lg_qW)XlaQu%QTb%zkoTNc}V5lt(U)pA@telyl~Xnb zZwm7Tg%5mZ6W&RI#6k#$;J`ykpv=$zo*($V(6}HHgGSg3{ZHU8MMzL_jF7Y?s4f1s zrAt(wuA}>Lm)xz7kA{YpDOV6D(sRP!sB+ zaOP0vyldJ$=phBPs9y+CN=Zst^?!XBfxSlz6}{#C#}mh6nvRlmCFijXt z2u#3DSWWOup!aC^G6#M}Ma!UdmoVEWwdzOOwlGC+0hTCqsc_23*9W7O&^|!Oaua$i zCoHEd2U~-jLY?GEHA50eP`i`sbxG$_o$|!MbVPWEaE7=fU`@#OLLpiK3xIXFc@s8M zF#z+B`jFd@{*WK6ZO?YWj^~g&npq~ZHj6f^GfrFdMKobFj0sFpd~ed1wNPOMLVGPj z`<2b;FdRCZDjYlEI663dl|MVk$9_#}j&5^~UE>{i_Kw{KrWlNGXHYE~&L@`7 z1oy&cB@dR5TlQ|xQf-Vn;&e(%cS?@l13I}z-I*`UCyXYNqz*Qf+gjLim2ju2W2R-Y zCbw^)-h1LTBAC-V@Fz|+Muy=I4lHdmr#-}XrTmA8B?OAXuc=MIOh`>=O<;p8{E|EP z#!lS>-S3MBrHsj0X;~|o_YsYh*m_pT-ztBlZNG`mm@5X}Y->x?<5S2DD^+Od?!DnRNCs_Xo8BeK`p$8z_Xd zXGF|m)KqoEi8_464&zoFJz1e+!J8u^|mV_3*Gw9x2byB$-G}>HjXfZLibKU;r ztF09zVCV2~q)KDR*qGw`u=mbzMc@s6ko9kti&s!ugOHx@rkq+E^Hu1vAyu2d#au)o z`rltaJ(JfOZ{ds+j;|cMY?(+b6g@n+s<=|q@=}sCFp|o`S}Wv3Zi=UN0t41h&p97) z8NP%cAV!!Xj?$f^E$Fu_Q1s<7_}}hJAicW;#@PQU8x*ws=}EU@tlMhPEv2NiFeKN| zfVgw1tcib)-9{I;Ci^trch6Mk+SMne1f_yE4!*=iW!0KUuXG>fwEF-zX| zdo?|jns@v{{bjyXcRGn~2slDQ!fcoCp`ccmU>3FB9mlMtNAbE0tM0%lV_DX<;ZzMj z+w|M(fgejEF0#4+% zJMF~Rvy;UThb)~fOTRg^ZxQ0Ra8P3bgK#czk|R2ly5xe|{Ck%~;}dQ7Dn4=RY)GEy z$PB4A^W=M%GI#!8Rt=CNT%QemvbF_V9Ir8HfO0`8{j>FmhC|GKU(?q}nX^Q;XX1PG zjuPm3*j@g5jjosHOm(8z$I+rMo|YitMOh&oWowAFcocneC1ud-1ZFAi*z2Obw;mN) z+ZhO(fD-!v_o!;+#{l=NYGnnc-VT*ixSQ%n(+Xk*Z=#8KIF580!_A^Vq6q;*tV$H< zLnbCcbrO(6W~R6*6o^~;^sRCfd;+Tfl}2=zcXSVIy`Em{ywf}R(3NY5uY&F(5i zsOr;gx-t>1D~fUD0{o}SG35fjCl=F+c$hAp?b8Ag$g6v>EhWsv9(V0jxKTs+A6ZrL zU~V!$TvVkXd9lyrX^R6k5YJ+0RUy0^=rQfVz3G;rRi&U`QI_+{6=Bb&dp<-%#tgSW zx-ZJ$o^%2Y9#t^k+P0VEG{8U2uTB>$gFaCP{!FhUIWd@3#DhB3kjQh!!#cI0EXjr7 zqAY>$-Yr{;tgDC5)hq;Ztz;7F*oD6$fVBtkpp1kFX<+^&b`*rTbNos20|2(BRt_JK zgECXI5Y$5g<5Mi+3*!UVYfj7d-B3o0mMz%O2Ij;MSC|Pqa6`=!p_dS4y-EZf<|1sH z1T$0Q3LNGHz5)QD08HUwW{P%JyU{j&f5Hzps1uP1--5aJR<(q@h9*uf7qNk%5G@aY za~CR4pvPPlDvzMYya-lgg+WvcAXX)pfrJ(rM8T~P(SeBxn9;<%2%PcIqHPSCA=jc^ zM=Tgc(Jm74hN(#^>ElPC4VbaVBAPiG+4qHG_$UC$fu**)F^r7XOq2w?T5v zrK(xo_pWF}L;eT#?t3v-ysmyoZhSVxD00OW2zeL@cWGZxJRff2aQO^;;;`@y9Hy7( z4VD(|8+>AmXe8m3X#8&&WvLK>_}^H{P!%Yl$vDOIN(GF?oscvZYRAwtN5ls|;oeCO z;EGSaMG0A>OYv9tfk?e8row@f+$Ymx5{Ayh$9pM-@JaoGs1U4Tf>Ev$Ibp|y5eYy}Ka_*$~ z8Vo0{C@JJt3dcM$6?(=^iy`_Db*v_UFV~nHD@3&Vl}K1{h=w2n6oJ+kV^7K7H%{c) ztn!XoY(8zkl0NDM{u@H7q;Es?AY8g?CGn6EOQ|JMTt#~6yHj;IW|KnC8WZsLXmxN( zlR_V@ruZwmCT5kDKU&q^`6`tOl(}_YAp4Kfhq517i;Ev@i@o&cD$IDN)_I}#Ke`_N z0R1JF{!n%DYzyAGZ6j(L1>wYe*H8Un#} zz?j_|;>t9XEs7Z8%QU4gq>5(0E3VI>#0#^Gyr$qc%PuR6sbX6=D730Yk#jHk%~~s) zxnnKHswXzx&NJ&$yLs1XgEHwHlfP0MaTjPqIqCFE)lEVG zS-VtSt6zb}1|@@ITEWu#pS$)Bj$b?W5)SQavm)*q+WSaz#_pgDPH}}L7o&|6{85|E z-4f#)bjNm&l-fI+GC=#%4DI7m2U$~^y$*kKOpB~uc!s%oG|$RU3$GqL2fBGr&3fn3H4fX%yl#4| zp2`*YZX&E++DSooy8jk-kmT7v7Z3a8c^BZ$MQ|;jU$hATnim9o_w~LKc`waTZR*`s zJi_=M^2_IWcNZ~sE*;Cvi5p}H^O&pW@0nxr7%dhgnXB-a@wl#@Nf~4z&j46OEGCWa zVz@J>GE|N`xud?M!yoIoaQj-==SLmdzije}q)nLI1$hSevDN)H8_&Ha(sGjcE6guOuDD|?DDdw-q`lp>e&t6jo->Bvrf=$QXPb41u zQ%pr@MC-=6=G#>;+=D9_;CqOvBi zJ6|8it@Qv&wbpeqe~%~6?>|#{w+u1BURqSA20H0jYsaiO`g>syR1!c zw~^ZShK^D9qq#6~nGtEEtW#G>7#|~SzhTShUbTGdRVW-HkL#v8F1bSF-Sca3?_;&o z9D0ciK7;Srn_{QI3!Bvl^qh%t+|}nl{(rvRJTF>A5D;gq|FHJN$^O4@G1gL{fJ=1M zH!yMfc%b&Aa3Dipm{N{_iGLT?(1?m9+DA?!pVv>-OQiYj4%CMd`qx_D-yOztJ!jjB z_Z0u*=7xdfmLC|-;Lk|)b#+wHuflbaOfRZ;q8jn)sDs~iq11pIbO{9Z-ku+ksOvVR zGt7{CaFjTOtbM4x_@bH$b*y46_Pxg88GZHo819@5mzZ0PqjTo%p7wPv3L}>$7UauV z0-`>HE|2t#)C?GKshlj_Q~72D!#6A(kG@fE(V4X^W{y-p_)YvLsCh^g_=dC>zTA8- zJ7F#bXnPho?$+jWz*7C_^tG2!b_u(5DZ+tSV+tXf`ACP*ak84Db#Eqj@Moyga0RQk z0d(|Dx)3pg3=_9(!?QbxAQR z5YsYfUh(M{PD!*eb_lQDx0v(yyS|(`HlE%Ka9>V#VODE*Zu7WB9BTQK4O=)hLFx@45BAnW4eMY0QZ6|$XP6Rwf~ez z+-y35((S|iS&4tOx2>>`m_QKsCgeeuEk%-$$w-z+S7h|eTZjiynI4oN%9c7iU+O1u zOVZd|X9>G^FHC_g?FJ5)Kp?#K5yZ7pY#Ips$RvX#Jn_Gyh+_ zM4Zh329OP~tr>-%lL0YURaw<%JBX7;O_>l(n@|L`W+KA;xNABt7LioTS;Z!>x4!Wj2WyVYXVM5ywlet|y1!V$El( zels%Up)by@Cw}?vSK>if%7XFiP1)~T6$I<4Zw!K`SHwS#N2>okLqoZX4s*s@#Qe0u zhFM&$UHe9OlfV&=Ad1Y0HU0K&{mU96!)H1#L}foz|UwhUTT~+DD_RWdf!Pjx)Rn57Y4qlwC@x2=*HRDaOx=0;q!A=P!yLb z?}1H5@T%w8PtwBqyOe0OY~(nhU(6Mm!#n}-w1j)G{l_Jya8J>Z;`F1M>h*zT2m~EA zGAj&#D%!>Pl=|9T0Ea1`#x)ps=$}sqf{Ln?i2_O-hX>>ukr84~A{-DuoGGcf$}JEJm+dl>(Z@E!d+Tah3}I7{5|+ zR`eIouBFcTY-hXl^2y(B`s=xiF|sNVHw6wI(8-#|8Jkq?oP7B+%)j{Qt(qkwxNXLQ z?CmRL*|lfZ{t;{4jlO@7@}np~B;rWLL%iTpj*qy>`UJR&Fsd4AFSMgCIR;ge4z;2> zis?(g0j*9bD^ZqC4Eo}12I9k2m*MBA(YB?9WyjTpRT|IH7b@iyb>Wgf=(bC6eTY`{ z5q7cc=QIR+ANP<@*X zbz?C48Yrz@8n=UYhj|5E2oz%Lc6qsS?fwyBpX)6iO{X7o)^ZK}yMQo2QW1xKQ5Bo1 zGbDy7{ZL08$cH0vf)u62Ko~#BjeNzi3Y`svkWh;@>cm9%$Tw8(6%D2R- z&nP!DtcUPD@(FVe$qi2e)*o(bm9m-Ono~#!O^Rr-+ooS}nG+Gt`Lg(xG!%8{*Rbsq zjwmYH#-rA$pVT**7^cf!3D9gO3uI2$r=&M~z4TiQUl((k9_SfOimf%RNbEXJ_UO*@ z2DnywSY1Fz_VG!q`I1m`mn3tk&=9OwX<7mGrqVMb6(f?sNrD${eJqw-@aO}EsFJRJ zB_)c+itvsdsoXbho!)N(slYa|MLM(@{IcyWdJYZS6Z{0pRig>^6zY0a9efmZNJr3uX`l4 z1qz3VM%yt;e3yQ@?5AI*Pl5g-x=8r*-EWcJo@Um^-Mgoq@BV9Luuo#E+5|%AKb^v4{=bLFzaaGc9~MTuDFoV9oL`($ zg{25F`&Bg*4(X+Tr8xm=?(Y!sh4X(R=R(3zBb_5p&1kVk(#eEVKX zYJ=8B#PlHKi1hgH9L%J)T6wBcwzU^a}0|8Kcro{LRzzg%;_R=B8Bn$60UMGdb6zGpmhC zTrbwv%Ij3iZL;llwOS!ejU!OZQb&(#d1VuZjlqhO^;}tAGJA#lEs__S38)fc zJu`z4EQd^ty8+Q*#FYs$75i84ELipAy9v?5nx#U&56cFv3k0iIev+65*kmXr=UbyRI0NQ+}bxsD~UBa@3f4}AVY zr-2e-<`fO=^X=+-5y-$&zBUNCj6b3JK;P|&a>fYTPxwkAzmG3~w+7m<$#k~aOc{)x z6nRnt1tkK1Q%5qEr;=!)%IMU46$p12)p<&=FiVD_8kv{S2hkDq;p3~lb72ZBc{g~{ zgjx9un7`dF!^hJ(hSctnf7au^qWlt@4-#JQk<-3cq4s5i+t)$-(e921(~`L8_1(AJ zFMtJNii$1#HUSx%FSrWR=uT?(brt>(<6rc+vTD_>{QsfEa{ZSQ`~N^sf(_i)NDSaj zvOr4;T3`pjdsAaQ#J|9UwCm&;oklB zdZ8H9eNNbE%>i8>1WRKKbYyu7j z2$UTLxGTC@2G9UA-XeGytI!g`FZ*t;M>K29qjM!IR_6B1!`ru+tlQ_fwcoGWO^&_| z(|s{xX=i1{#wMm>ka16yJ8b8vNnf<3s$v;uCHN*-i$zZ+$9H1BP|FmD$Z0|j;rdgy z^rAMu8IW4W`#P~-yh^xcVcp9rtH!Duw;0B?+%6Zzk)CqUX%f>Z-+L3CU3-YYSwm@~ zNs}}Dz;Qx%c#3P0<#DJ0nxRQ9mQga-eu|`WSf36;V}_mG*k$cFbA@`4gl{n9DP|gs zipu1{5)h4-jt;yO!ho_cQlaYn1SDvh7*0Av1oTSk-YX%=x!!}FdZ_MZ^d{m1{D7*~ zzi1;TgiC+9JWS~Ox*&TJ^kQnEpx_PW^B@BnnJ6ovpwh=9R&pg1+aEbUP3+={ELDFa zVq-2P7UvKF#Luw1XGfJc9?$r4s#dXHHQ&)xK$5C*lQl!kb*Mygkx!gv7xTfGU!nRd zhsxU>+ou#;GW7v>XiCWdpH73pT(8lWkXYK`{z7dRppA}gU)X}%ARl*GL?XE!aY%x>1gg$ErfI}zE1V-G zmoQ1^H19(Gf2g2jx=|S4YsqJ2#Q0kS;ajB|{JxgNNdy>I!K#1iLG{%XH{}`glK=j?>e<(I}Ty z%61u)iUoI0$FD5(`?qs4p>ByLOdtaWJZTr@G#Y}moPMtt@kwpuqi-Sg=27%ixf=8^ zU>G22@gzBTO*H(VTGz22ep?Z;U<&d~j<}lQ4($Qug7l2yjBH)Oq${u3&;-qdw2zoM64+jbJ($ca#f~b(#D>WtO1IacI=%VOu>sJ)1Q@0c!y5j_v3J&N>b%I^@1f4svEG}TN@8kuk`Li!~u z=agU+qVW3Cn9Vcz}HAe z74zxPtAX#vu|C2Z|SK)sEo5o#rWW0Tt{+mHHyQ&2=2gX?U&cF z;5%$Js>8kr^FE{@{+g)FM*U^K$LBJS*WhhZ^PHW|jt4zYwZ73O zRAu#3omM5}M70HfP3ewcd$-!+_AyDB0cF#aj~=pJPQ5{6^jD?0r0@Z#`JQYKrY_NQ zT)GOvnrot0O+Cjm6}knPs<<)DRANNeKt@)$REc0|Div23O9j z@_6=V8q8lAHcWUBzY^oJPiyQ~J1DuK)CT{Z{ApN2twxis_}wedLr~SUS-P$sS^UCW znprwwKYreWZ9l!T#;OZK!#q=2@rGTx+R0b%TBDbR6t_HUwmBw+8OQ}%!*s;<{7iOS z^Q15P0P}`+SK<3b>+~pBk}ak*fO*;%4`w`Lwg201O~E z0W@}`wXwIYb&HxH6^86QP~zeuI|clZ+(y9nfNSOhPXJ5@ybu|^C;d4ud%(^@qMQHl zLWUc7RiqX8ZhcL{79N)`=YycPi++rmCnDto6}0QZW#9vv7R9)Ob&Yw3ZqUC+3Q4w$ z=b_~T4?W<175hXefF{_(xhwgk_crizaC(Bu&nRiIu3F-42zTJJS`FWLe2}PG=WUcD zqI((3DV>7iM^0k>Mq&eANz{3Y)){KXWNs?=8O0y-x^Z1M#l!l?k}zM2+ZD#&<8AcY zkk0sw2_Zh2ch_3Kwhz1_f0?Y>Gu>y zX?(h~#|%;q-Vn8Vw^ArSb=7Z(4%qxO)!TG;`O|b3TYY{ms*%6fYHOtl1VsjPtQ+-q|qb@3wiq`@D3y0oSQe3-_76sT1`{JFgVbNqdTt0K8? zFBN#?@R$Ehm=+Z10P_>N!2Wne8E^;;5EvL3knIR_6`+aezrO$Z0)mapDPP&vDELv;Fzsme|za6c||>qrne{SF$HpF4r8~ z75v^m9?*r*bkM%+#0JAih(}Aq80+>yV4ym|8p+<6eeKg*KOJzzRwXB&*!JTLnTkwD zXJ#bsv|SGErX?;Pc!UU6meoi`;1Uf9J@(@i2w{QP;{;bMa8FyE- zP55XyDW&1Q4;TRX2eGlzkSNN+atM(6nE~iDF|VbDOsbV48WwlHTDzS3j?tv1Gww!2 zV=VrCJq7&pdNNVznegX~S6!sFP-2|d&{COx1_PT401=li+ry?YK`&H)V_!1EJh4jm z>_jfs_AF~+r5~J*70>&9v6r-Y{^uih>L%7s%`!2iWu4n6_v?vCQ4Q?oe7bYyB_v%_ zscsgHwYwo_zk}jySV=0Hna|P>_~i6U%PGlrzKNn4rvqC}U7I-4;@nieV}Z0W)gnmX z4E<++jWE|u0rmlbx*Y_YD8!pmE!1ps0}nQQhbBZ+V|2lGdtBz;<_D7Ilu|t)*@5~N z(Fyv~rGNY&Gr6k-mEW}=Lwxxpofd@cu3Ml zu#_ou{3Mv#707#O0Lk1yxM#T5TqOmwkl1@`%xSA|2gz5nc=Z6|Q`p7s4Y0zT;--vk z;uD2(I3W3B*aZWUzqswMayT1AFC9oi{~~`OqpCN{K=POLA0~e+-2YXeruWbOx&>IE z_FWl6NfGp~jrAF&7c7!k8+J^wS2*vB9er>74Ef;B;OzC@MqVH?Py>Q~vU!7y^%ixq z1VB&pZ(tM;4E`mYtgl{ zP^DWo5A|qF0p}g|-PDUnFtyxXIV<25s$sX=a&&K{kh+)a>Te2k(9X2?5;%9jFqA>E z(>`>Qzj{cyZHHXrY(cOazhlv^3{K$?vz2M<+Bg@DF~Q_ZD*G-gk6zfv3h2LWr@0ji z6qe_O2=8<)*R;k4I<_JNkJHWy3VjvrvnC&PWk!`I6M~XYxHnU?kgPK zvWpWlHBYQWTpOkN$67{O##NA@fI%c}>8L#wV9A+!VdG_{TP)fw!G@W!{(ro;IM=#gVUHT_{b##=%siBpJp7g;A(thlk7xN2EcJXTkMc?_}5eZYvoKIw_^ z7}fk`kbEdLgPlvL)`F+MIX%p33mZH;9hXSE?GzuKUn{D`V@Mcu#!)#|ag<8@h) zW0sXlCzlEP2z}XBs7J<{Y^=+<9^INv>$jKhUfNU zj8ixAICX3Lf(IG@+7D$yOd%(};0OK_uN%twBzu+{6TiSzzB>Oj673gc(JVJvO}`&j z&Wz6BF7Cf=J>`RL(rwPaIctzNH9vjf)JfROOhuPy z>{j^B@Y-k<;+;i$nKIQWJRX&8x3=!q7pleIQ@OHh>rd7FD@Qa|MbFb*0Yr-yy>JW< zkryGX;-;P%s^qXGF!a|p%uFBZ;Sxkwq!B^|R}@KT)TKiHF1)JgL{)1PWM~3bj)bP#P^^k8yneP|fRu1o2+Mza*t=7&;bfTJ`!N$9I4C*kg*sws{B_E0b}1F$9`V zZ>auq^(d;@OB7Ni-!CvvgzT*2qO%}{HhlH%tjUqXM>~zP1n6X&=&Q4llUZFy7qc*U z22tA~kM+e+gm*5ot}3jthu$OZJTmg35ii-=RS{Kl?*;QDN(^xL4oPrPKI5MO_K3)T zj?MO->I)ZqBjdezPx7NW=SXABqxaC>%Pb{DTZKLgg~O?0lGCM_vWqyA)FrB1@3D*Z zlUh^vTg`Wcu{8-E;opLXcV7X$$8aEcVCjJR9Ue7siAyN zcuJ&vuaNeq@KaB_v)vtSuRcO!EIYdQ*~R?XUijFkr=@Yf*_<_}@W;1rLvlwLp+33 zOH~4q*U__}2rtdBavGmZn0LSz%0QNrNwyv8Pq4q#kwkA?NEI9egcnF3|KF)2JCH;= zI9o6p*}K|0GrF-c{vWF#IR6dXEf;h(;H6#XBsq>XHg9+aI4L+#v`Sm0;)Qu*n!p5* zCM%;#g*DTf@#3s0bCt3^!R;)CE><2j41dJ|Wko}uZ`s$g!2O4rMBbgS?<}g$^oCuN z^l-sNHuod%(Z%}|zo1*UW|t>kj|o@Zt}qU5bCE_b38oPrF4UL%q?c2|3bU+vxU>`A zimtR1=n6lCpz{}X+Eqh$4XJlmaf-2iI6@5)N3lu)%y$pcP^!HV6QMyB9NBH^Ty>`6 zZ5&b89yeQuc#`bN9Fy(-rpUn={YHXQSrf0{&chRcH@i>{9AOWs*1J+PBdC zaGk7rT?hMe<@$92sG4oAR9;>7({E7^$e1=4$woZ-3+(2|c!zGpx)< z&_lE;s<|VW?Rj$#rZUwEWiT1j8%k%d&MK7}PYHi*e2I{-zWZJN2bd~;%`$069BwFM zFj=ili|M1)7)`X`&0@{U(i*>zlF1H`Q#^!@P+}i9tJ0soyMIVjs$^gP`K>QCx#Al) zQSuq?gK=3X!Sd*j*N;2gP$%79R$TdQ^8QV^1L{9{3yM81aPn5vyKJK6s_Kps{aVq~ z9{T;%U*U$>qJu(vp7PEMJKw&lRXhx>jKZt06u~s5;rv_?A!*6@S)=qcNa(ER66=M- ze){tw+2Uc)*e2M=ehS2Hh!4K8GZ ztmpGKGz&lJSG}-*-$Ab;JqM#E7Quvujj&jnHA*1qN?Ha8!E{JTmLzqH4}&mxfNqS; zRE`-TAvM&E;1xFUHr-?Oq3@_trf7jN$~h7^oTNWGiN$rw@9vco%Edov&Zd~@X;g!r{_Keku&Xj-B3##mU}I6k_RNr%wgZ(<@C&miHU(N zQx=lq_7p1yqxHC=JzqOC|@%)7MA%y+lXn*2e?q}@Xz9gOA>X-Hdn7sL> zzkzeTiFS?&_Sw9_ZEnN2j@0e4eBwmC;R+n(ZOg#jv3JLI_`nL@;yvYT4e$#n6nz4s zZguEK9U9oW_c(u`lbjfGJ{SqI)5Y42kV-P}p|H7stAmyryt)!hst4~C1x@c1w84!= zA-oPdAbxlf?X~QBsmD9n`upqHGi4T82L3wk|Jz^3|NPa-$@T9N8C4*02IjxkQcHtD zARGM(z-|%(6OB=4Zb$;TqLl!&Tqkphwd^>F@`<~5qg%nq;XFLP50c!Qc2U6S$I;Ro9)=KqE{t95trWLd5pBVzp=!(tx$|)*xw2C>DbB zK0Qb+$T@^-&$Xt0@zC!eN`U_i^t<=*{W~{Cj z@X-Cx%amXu^;CGso#`nvK;yS1%#Xtl%7{lpxr(ODE9I16ViQAwJ5xIB^OzfNY`< zzLK2gYVTtXx9 z-pbHnO%tHVP?+#jyBUA1``Xw-LvyFTBDKeC>j<+_CL5Y14WsL0(e{3%L?NwN!J%o? z{v1ZEmBypjB?sR3tMjrz6`Qi983J|~UVq{Fz^5Z_5UO;twC^FSnauJUd*qMk4-UE(NjTO3!&e=f+ zCnJ_glF7)u)&xcQ#fAqoER{NW%CBVtF+dBo#R{#9%G#q;@4@dXRmfyfEy03X1FITO zNcwD!sm4xY3{Si{zng+_enQQ~y@V44NE0rSlZyc2ccEbQBJ&aEY&=j;i2efN_#p^oauBb=`{z&oU4enS47MTG-VOy z&cj8UJF-@2w7OL0991M>3aRk3u8nKkYU|#0lgdO<1988~03( z`gdLCxqN)SwY-0vWVnE6*Kl&(U$f6dpo=%mLwCF_yEp(7_res1mT+|9Yi-DR{<=VtI(+p4;X7^$Y^R;Of( z+vME~+;i*PJ@MV1ChH8RKE-K&ZgmFx-$dH4%F_WI zf)ZIY^nv9ALrz zg$0Zgs7N}AX^860Fq4X*96=BL1gf{HTVp%^%U4TLkPg!cz9>h9bXSR&U87_(uQ4eD z;g?mAw4|=IJ73URV&85}(AanZv6lc4jYPlrJ9lu~aM8=Cl5nnXiFXZ=;U)%&A2FnA z#r|}uq)NXT<3EZ>7m5ui-y=zJ0mLS4r0k}y2~JX|InhO?_!`Bj#@^HqNu*GNepoW7 zh0A7<@0H=w>eyQEk@E>^v;CV-&WXxA?ovfvvT}En7X#O1{eHp z@Z|CoL^NRV=K0odV2CR?K>tB%vm2&G=O0nC&DbFS0k<|`V20!$gZYfwoYXxP`h<7J zBsdm(&AB4&7oD@~P(SAb&D$T>aQg<)(X(Za{md&ozDPDO6^>;$q&u5?#0<;OD$aIZ zQ<)>#H3=U5l^L|CVFu)$4i75Hse!o&rSHv<4=bMr2b_|UHe@CIUq=X<>TQ@)AV5IC zVg9>U#Q!|f%JFXtXevCgP7W~K{kkg00e|-FF_QHwc=Fb7UwGfh*h8Gy2%Ll@;0nez zkwQz#ZSMjKrWExmqP%HQl1?4t1dnF9QnShAbbjhMdR6-yPYG*^a1CaWW|cY}@Z`!; z?6zxThJ)Yh>(;Nwb#FpWZ+))YaRbmEgr^YX=H7dOWh73I9SI_wD_`*KD4z&c)FDcV zvVj%)A+aG-3CNOXKy?)~NbCV81!zp1@F0v}kmHG!;OB zIoF79_^D>V2CIMk3Yd|VU>;(kWT9j|WEumcM0-Zl4v|VA7R4$tUh@bJogzzhUX$)o z3~5COU-aeoZoeYQ8!bmyL|aAc0&}3rN<-;`+f+FFR5-dlniJ*b^k(xcsjTWuPs~uB z)leGDnE)HWDF6=#Rf4W4XSR2F;@FrRU^T=cK~$8-+_OBo+`l}&Jlq=Q6yLi+v=58p zliu4e@IfcJx1I{xV$m13JuJ`){$SRdbA`^heh~7G>p^RL zt=X;&PR7_R4enx8$Y0qT?nqClx45=}D_0xc=r&4*Bi|_Ao=G~2WAT`uaS>gzzw&KV zOo1)qB5P}tP;QETw#R@VPBIC;gS0|bHCGW=o}4$5^x9S9r=^XSk^|o&rGv_Rxj+@^ zpOMDfOzI^=&EjA0RYmLO=JdI-lr0kNra=K$ha-zpN)9}WY8bI4zi;kP*H!gIa#e{U z+^_V2#Lwm@XKw5_$*6XdisnM=mYPs%1Kz{+sr!4Mh2D&#jj~-{HZ6S`or%cCCUKPt zD^{7vDE2FMa<3%2S#f52)~hCag`>mwA9!w01;}oeO!sSRkNq2tao9*tJH&6QK{M_r zL>ED?zplO$5eA3tpDjrI&e8W+Mh@FXWyF8zpWY6~j(yotdTN6j{JhK_twoGc zPs9H#JgCVkva>?G8=yqIxv8wW?H-@;T^N}8KCM7W=IczzpMVkf>&$v{_3GK3diwKF z87IU2gIRx7tHQEf0M|-kpyS2#=yvg{ce~}AvV1OY${=6T|Dx?3gDc^;Zr|>7td4El z>Nr`kZQEAIwr$%sI<{?fY<0(dSNb`7pZA`7>#aJc_NmI(RAqe_ng2EC7{5Vub@sa= z>OS*j1aKxcRkyYBqh{hsH!+7<2=2s)W{VJ?CJU0hd32dHK0f8}r`KKm>-CfB&5Qk% z;|O|diE8xhd8aM>>>r%Q8hroUSL0RqS5x1q3PhGxsbZq1vQgQJ9jKWYiP=2exqgT& zkHKPiIk{I~V z`;E}v`kpkAvPu|a+<3dAa{8^1(Q!q6kcc$E9vD;*A`aPPXhF~lqcUG2HG0XQI3f(h zUKdo6upM|rrA??vwB9qJYZ26+(mIH}`&3#4{-Q9aK)o0;K2$=_3%dZJQVMy%3x{xXm0;b-WlE7?*vJ-n zJ-%X|k`W)FWDq9N3#vL*V%YgU5im=L9zL^4`FC(n1?QOER0Hrl$RoWtc*G)d>lxFN+on$NP|j;mgg#ToCuvnbe{&hqc?S1ILb^$0Hz(_-)={9*u4BUgaRCqUZ*q}hQ4F_PjSiZyuyuT zy6R`&xt2O_1+Y$09@}k&G%`bWWPaTdIRdO4Wd=iJ#_TX2;a_7P8M>`Lk>j}X`nhJw z?jj#CPujf~fn`oNiBF+x_}$rBC*KvR9AwU_aF{lsfmp+suer=MRgBEokSVUqCcA`k zuO<9k%r1ewP##-&m*Bnd8k^%K@3}0}f2P2yUS|=^k@?(}8Q2{tXImKOP8~Ie%%X8s z!uX8W&fgO?bP8df=^Z$9Ha!FS29{phBam>Pz@pA4t$5Fj!csrNHZ-S1EVL>@Db0MS zFaoIw2JRQlp;(KXYC)>k>yi zLut~;QOFQ2ahbLYcORN3lZAJ7lPH^46lau$v;M_0izZ9${C#iXVpYI?+ShTeA;X>9 z<3wRvI`JMScVVX44E8vCQ?DP@u4n_~BB;&|Rg0EgWVw_!;bpVwlOOEL-S*p(ketsU z%>`Of$L*ymb>xn`H+o9mKZJUnDU1!Zn%>)Td9x2>;y+?*Aah!^rrr zH=NSuzZi^I3g-MbUr}Ro5~(Qph&1>u|K@mn6}#-45Z8Sn zvmV1d*7jyx@NQ&|E)C=_7v3Enw{O3XY(EtP@8y)RqsK$aQ2k8)7;%i@j8N&340{IH zDRDoVWVB-RK-wco$T}E;%%PZ(Y#0KMXxDGiG5s|>0|*oC!^r?KyC`nv0Uc=DG-;Lw z1D6im zwK#`-fnY6h*t5|igs?kGYZ))DB-13^Z{$CGPq6M{o^ zJi}zZDUxLL5@OV?A(4TkV882VcK!T;8&at^AL1~}Dqm8Iuy-fNb()Xp0%}09al=i5 z(j7wnQb6O`EmafS1kWt|UUe6P265ru#r$kV)7n6w>-XXwiA-Ezg<9HDHq8DHdzP|{ zs7o?oOXUl*PV&wTV6LaJ^u+HWvsJPRqO2I{z;n62g@SRLF_YaXqE)oIK%+x*!|VY` zaXArUbKfDzf~BM>0iwE<3$85O)h_;&{rZFS{FxKa zM}R}NmxLH`P4wt95zj4z(*;1>Q;;Rplqig!HjFpk5o6%HR&EOmsXgLb;!u%@|3kw# zeS1L6ua4{g z>bUvqxK51tn^%wv1_9<3zF8B)1^>+}z~_Ma=q&=JB9DVh|26mW#5g$F{>LjvhSik! zHc%^5N849?pHqK?2QnY0AoTf$3P5?oiem&55m6C_B6degv<9C|Vp#fxrv}<@m=(>m zhKeI9g7`NC8@t^B*^5q+{Ccxfryzpq`X@2a9_E{?dgck-7wK90hiHzl@7m7boteAP zkTu_2bX+_41lcOM_UG+CJIvKPna&zjSIkF4O}e-!nS3uUxEx;eH#Q0t-K<<8J*@K+ zi462*rpc&k8!x2|J~)};W&T#yJpL<9;~G|R5q7!YjS#-sWWLzhs5MC3JE4m9%)KTgadFI4tQz> z-GGUME`ozG<|-hQh=&&oSE3+B)}x}rbRKNQFj^69`6MKH`|e_K66d+~Abh5tSJhluR@B4|EL11bMu5wWsz{OkJozXIf7 zfVMSA;YMGgP?dZpCA%5?sktE}sf3RM!nfDek{|e?K=5yOP{IDNB**_3BKJ>jfkcJG zX|FyIA)hE1m|LLH2MrHR4I~hGVj$avu5LEygrnL+BD1T?5-brS5t4#|oWe@porJlj zu7msRC(KpxPi}$gu*K;JYMtpLw*XB3F#MBSu*L@F7Rn9LorbAtjT+h$#3mqP6_bm& zBFG%Ivs9!kniGJIWnl7$tLUHPkNYAWV~lVHV>}3_I-91es@yv4_i7@2sI>o)gh+KuvU8FAP5k$_l_W( z?B%IKo6?vTm-|TaAErGhxfEqe=OjUu0Hv{>9ga#NZ8)YBSAQq!=_Zq4qx0jTW0iC- z&zhEw_Lky?O6xSzwed0LOB@avQs?@m6%JcVp>GqvV^OgbtIw${T5WkIr{(Tqi~wPC z!0^vEi4T$~D=z+_!f~ww3r#UAFn%oxz;nun5iXyNbZ8U;9uf7?!H->_{P?^dA3wrB zX%Z>~>rBt^-8|3Nc^N|luE{<5A>9Y3Aenub^+?+rO*`yAAL67zd3$?KVnXHJzaog? z=Ncan`)7bsSs40xHR9z~NxDb;@)|L`n%y0q?~dXdI4{H#nrFpIlw=r|1+TX zgkC(>LoI%fB>$Ce7iVg|GDqR0Kt6ZH!hg{R-OrBNyo!7!o?W~T=lK-ob9 z<6UGv44{%eN-LAcQ^?7{>`(Ek`d;=$+Gr@)kY$~uo_$j4kzmowR6kHqopOP6r>4szBFIlYeo$_M-!xjwy}4>gM!x8> zf~N?RtzVwL>)y!M*Q;W^);LsYJ;kLqeuhFby|TEd-9K4g2CbrTRF~ECgnGA#Q*!2J z0u2A8k_)97H?*Jqio2Dcqbs`bPgn#7Hn4c&pCExE!ehjg9{|12mLk{(2Z|`s9!6-< zr<~^7Yh~oOiHKI(eRwo6u^~^^6uO@+XgI@Lt}ST7G-F~0;se^4azSlyb1Z`70MpXq1A(~$7Qk9U1-N;xo9yZ(5yH-~jqbSejkqT8kJ)_kmtTX# z?^@{d6GA!dz|igDy4%Gi(1CL(87vtX|H+R^v{cqZACoNw1v)@kN5Lq9$u}YzybYYh zXW!PK{)x}o6C(0%{$EfK+rQ&KDG*Ldi@!pq)4a(O>e&&*Ad%clp%{rU_~rc|0{sw9 z1Tp#`{bB=A7^svH%!%ee1^B@zi9q#r!&y33O3@Zdu7$t^`0wR|{;Yl*{)41t%cHxb zz3thHmKZV7j7v-NG7E(rJTBvI;*6A=spBK zL^fm+q&^yX2n~aT*@St4iHoU?p^a&XVH~-QfsU%O23s~ePqYW< zN9FVyTeezFst=(CHEm+Np)A?2a?*8hXT}Xv7$h>dfu?*1O&Q0mVf@7m&jioxc9>E_ zy%B0Mz!j8;CxW$aBZ6s&WmxRLuNmAf&1uPW%5ZAODyLEdS0 zpS(VS%j2CI=#bW1LSB#@ufpqZ^z)25zYMcbqwkD>Ki-}pz3Yzg*gT_A*@w>G-k<}P zpYG9um^Xf;nM5{2AGs+V5u;W+D5@$e!V_Y^i@+04a11@B_)8g;e$DE)7%`hj9Y~!> z?M)qYi>_1Z^@+bh-p2xDxrhp}26J9Sb2eZ)qF~V((I|)=vCl0Iae*H(-lEdkcS)A( zOhjRO-*mKIqMklbQ)0}~ffd^|&&tTroKt}|Rp{4I zXuYJyKuRX!BxdKsp~3yep>@x1W|vLX8|j}Zr&A**PiLxlOof@ONh2)vJKw+0PF`HS zgAmXsOsmlpPc%cx$EW3_t5e#_QE9P}EicEy@-0y}UNw=MleUe8k6rX3VMDQJ3!e&V zv8yS{i85ah5d12yHCvvPp^HR^g*&z{!yFtU5)v;d>2Md%><}TT^k!yL>ETztK%B^z z_+oA6*dtu@MA}B&KT7Nv;TX@A)?DA`X?s3-M@{`|7)=Z0Kt61nF?Cg0Fd~eNLZPEC zD-+9#%V)$X%V{JcU&f9{4ZWHlPPV@Ja!`9ihF%SRRakhx!UZ)djJzE?_Kl1q5bo+> zm0au`@U0}F_ApNJjZ9K5x;{*4ghKln(p9g)KQ!uAQ;8P~RUfRng%-@X`~qhw0X) zko#aCp07#qHnjW1c=9-OCy4NHlq1vBilQ84_~>NsE$ZcPEH7z&9Z=#vmo=89*N23v zIAl%J(b?*+vuzJi_Zi6)6@?V+KBZV{;sPSQ7!PGos1=%LrN(o*e@jMlB82jvp&SIS@qOybkSPlv<%^6Ss1_?a;%IRWByjc$^Fv_DYB-9x zbE!jf2BuFJr%g4saoU8E%4=kM@CSyuf*NY(F%vqKTkD_O4K6|Cb@FTwG6bxu?7oIx z5V$C{q7T?y8>zN_*f?VZ^Kxas5l4hY=@7NhQwaH-V>#6PXhA1w+;RaYtbvUx0M39@ zaOx`O0ARwPltn7!RL-1cAbXbZv%xfA(blQ-v$Cv!a)V8az#_FAtwuo(7u3zZb1B@-JmHp;2E-mZz?u29U9JmXX*(CdQ`(J-G{Juc5HuBISj6HN zoShaJf5sSK32K+jy%fhy z7vT8}C*dp>41Sk8%8ILyJL)WUb3B8i;29fV3ZN=v@lWJ(ZpBrY%X`AXoy&a!5o3k% zfhc72Ux?;x^j)|-o!gZW!v!rfS)e6!<}9>X$U`l>^kYeZcNIv7m?Jxhg*Q*gGX~&l z0LF)6v-1GhVqXQ9u{j%qaszV#AsvLr{<&#DzTXgZ_cCaQA98ADmltx% ze@6=!2%YqFKAFMuhaqg041q`3fa&!)ok8^97QBYQegE8>FhiRQAU{R}+nktk4z?*E zm@fmMk2nE}zj0y4t|Br`il0NL^)D6y5SZ>3iU8~*6CsrzPRH=-zsn^?jkGJ#&P9>?j_hGjjwDOEaIx4(o{m{$35hA3=-7 z%>(F;M60C0zY$>T)s`*cgKzudF#AIgmQcg;im|7qy!x$BI*#? zmNfjOfq#>NRq*o*mkCR;o@13E1FG%vGefa{`Vv#;7fmxS(5r!D4g5hBx0Iz}23$=` z+z9L1swI0j_H;!iy!AX@Vgj-qFSnkXuoXNmjGRE+8~h>sVVRZHN27Cp%%KuJRah(^ zkPdy{KML!^~X7s8~GlaAs zQHvsqts7~0t-n95kI8G`3B?;8gQ**CXrFm=WX~@ts3HViiVA{%C&)X9czH`c9Cy3F0U?E5DBTy`+=H_Nj_RYR_OY#TP7=$Aj1 zqppUsTE`#pHljQtuLipwgKyZcr9HnzFdW z$^9|x?zLqPGbD*--x`t~?;5A})++~^WAXNCpTSmjg=PYXlEFjQSmam=tnAU@kZ>tT z>dk5~guWS&z#+!SsYw-u3~*ynsmw6kP#uKhvS@XR5)UAbArG4ua!5YyVWEmeKpWFU z#XFaZ70cCG0Z8kalg74KG~n|X9Z+~^hUL>T1!6`_PvqO;@e(r3DmSF}e}=H=cncu^ z{LLb-lPeA{5W_`eUQe7|%z-t79LCZAbn^VjcJPRvIIq4*ouO7X6pJ)hN z@>S-Q;0ih7*v>IWzp*UeuueK==08P8H2yfr50c3>&1#t?GBwmVw-TTJwmy$!`c>m} zqWCE5d*g(<$at3Q4D^wfdv9B&j#G6>O6IzG(Ve!&0k;%ASIn%%(RAa`_oStE&&Da` zARYU~;)iM@_r=9@wpPwr5mkCB*Mk`{Rl=@AEXfS*dGiQM!niZidhLV8#ioenHs0Ke z>S^KVG043`c=vzQLf3+Lq$_KnFCX;(}4@y)m`m*2Ur8()sKe>1pG zYfD{q4A1iZW_kX>6T|C7Ul6lld1Ck*?RlUpuobf&E-r zp1Aw85-hLFGJvjI`mDSx_4C|(cK5B(+;aBkds$gJuYJlQTOQ<-R8utE-!%C?-&N*Z zvmH2hSH-tIwo351MUO?N897hB0ZO=2PRMIAWIX()+$?9Nw}PFPJRq{}nhWl>s_!FO z=(VqdPgJico+r7I-!HO6(7WzV;$6YCe^r-IZ&^DnzOZTE;pJ|3>CQV}iMQ{*O``Fd zOX?P0To10w=<=)|SlV=WSzE=_BwRc^G4?7y)LwPns@{9qjBcXoC|4e=Hd(CSuPk=yTpX*mX=*{Plbq^&bcJfQLSvV+~BhIQ1$x)dK2{@~MGK@(K(=H5f0*sa%=+(m z!@tU1Km}V-g;5s#fvXXPOJG3--9O1b{8RvNHG)Kjo;ZEY<=F=zgzM#E*XbFz&zr~b z5scl{`e=8l>H7T*qKD7>GlTDUOy}cR`4|}}ZTTH*3E1dJ3MEW&C&}YDdA~D*R>A^w z4KRhIV?dA8dw?=9-xr7oRRDWnSZw`_3@gvtHi3}ga0?EovRNDI*K?e-!@pyVpt0W^ zwYN;`C|*I2Wc(9!!ni=&I+eWp%#{G_7lVh5VxYiWXWO8R@W>V*2X`9QUTy`(W1D$O z!J5;E@vKkmvJZJ}=?BG_7p^_uM{x30(wl8t*Ef&~pTV~eHFh$Ri!-uik1WAf`~e|o zZC!M39l$z_AHOE00qZPXnaPxT#&EmqYL&L8XJY$yP}3`z1oOy&rPo?h*PSlm+(`zp z4Kh22k?M-ROSp<#)Yqsi1p)#%aIn@Tz=E+bO{6*KA%>|Ld$J@DZ^2&cjW~v~9lBx) zW6Py+`>dDZF3!6(-K;okTRJo1q7RlM_(m~*2EUbDH$YeE&O--CP1t~(7ixfaGw z74@Yui{qiyOD!donsj)k*r!{<0q_~&r?~24;nYgc#M+7Zl~?J%IKd9N+V8?`zWyF* zQsg;FUXbj9ENiELZ=ccpd|;-;llIY-)CvXVZgNW44Fp9o_u56fU;$ms^_Rax&*zBz z?^u#y46jk68dc!G?tswE(nM_0ar6*c3UM3OO@~$s?bo@j@{TpU#2)hI83YkfKV+}q z{q#~AOmZ#V0!U9oEQs6~u}2EYY5NH&LBs~wmgarK^AvTw{t~uB{v4pI4;iIDQDxR^ zyvAA()>*B95GLpr@<+q39lG%it_Cbb*9srl^Fm~fs0DM-yl+4eQ7#%|iTuy0Yk)bF z`(sO=`5)fWGco@=+V@Ym{J)m-p^+X?jR_+PQ3De_9LHY|8>0{=iayX>AEz#Y)8j9X za>v=pQ!`BPsraS||76RjpS*70(0%PIM_TXIOCm1!7E>qWA*O|iEE}N5% zmJuGskG#$z{yg)hp*0>hv)BH&f_ZvwhWm!F5<~W|wzGTPwlmT8n-4C)a=zpeTq!fs z;R)oJX7wgX?wz+N3}#qWw>&vVAl6QboT2lJ4U~dc4!&I#N-9u1-uy3yAXb}2(%2iT zsGWd^PMuLGsr4DF`Dx2E#gA^Jj?;&v2-YY?IPQiN-^?^}p`fF?;H%$?hbJrnna+|r zTWV}zX0MUAh<-IY;7HJWVhs1%Qn@>X#iZN{*BC;qc9cNvsPy6-{%t{mA>lIh${bG) z=c?ddSywMmxcl+o32a89F%a)_1RHlF+%58l)nSZ$cO@3LF7iiv5YimKz<%;2{OPSH zwfJ*v|w!T=IdRno{byvQ@V z(8~(Fvzysz(=+6zZ>w$%yvCAN^P5B18umz7-&4z|<=L*KOjD3xv^L*_LPB3qI7_p? zN}fgm_lqhi5LssiVHPY^+4Qq~5iUzXI_-uA2(lQ2jJX6*_eF8WMi~mah@6Ef2%Nx{ zq!MS~p-Z(K+YWVkbj)Bt7TEW~F66>=i@bYbM-(J}rqPa$FIj za8e9x>0|9Z?cw6@Olw?1Iv05e!wCRJW69}+7zOR{tCa(1m4#cZ(0}%P3?V6N!Oai2 zP{w~)Ka9-(j>!P8TtGgmxrE{zza~ErF#MAkjC2qr|1TZ#Z%bdhv?A>Paw^Wl`TfiA z@0qwY!|F1-!PNB%2)28n|Ac8Zc06c}X&)($kwR!7I7FfZMTvhW= z$7EtpFOuhobVy1A8A_ubjamtbu($v`U8QTXfDJg0GwLeC!xaAxMzy-VKdJ6L*FIE# z?Kpvjz^BpWHyC#uFGg2VjS!yCm^1>V_%_Vg#hUTdEzZT%es*Cw0c9o2l|D}uZHy4p zJYRc8qi2|fq5iq6Qq8LEtaLLOIdu!M;ai#akLXktC>qUqTE5&jd-&#qxnk?XbH}Yw z7oD0t(51XGT#fF$gLJj;3B&NsXBEksSm>N?$#kF6v56nO^kQ@4f}`h&)Uh)k2q+2KbZ;Ze9j=4185O2GFN>S0nN;ZeFpDoYgV`Dp31 zr0%Nw34>h&HB}qz3?++dwUZWj1nuBPsQ0T!Q|$U-ZFK?e!g==x3&>}}77~7C$F>Dw z=vDvH6raUAwWM||ecmh36P4|=EZEhB)!t)OE-%j|!){EgjLKt9mn0K)ui-3WAX`|5 z4Ljq|TDrXCNvGbyW9*?UKRCqY_7&FoeWW>w0^cpULH48H(mQ{@-xE4ZZaTQ=eu_fy z)O;McnQs$h)liyF{;*bD^g(XY*m*`8)lH9K_4wRjM`k<03xp!*V;zY*83wBw0W*!#7W)S3hOZ|AK@}o5(&N&A#H= z{?_sGGW}ck6ImVIKJ?{isJ>cXXe5J(ail;}Y$D=dD~1Bo<-PzH8D}mbEpb3d778b+ zzD6G`z-h~&QZJ6MlB@-jXxwJjDD))Ru$vAaP3nr4e&y%Ml6JuQ`bNV*C$JV4|DzUm zw~cfjCORctcz)c-1T!&nKXt2q(rddAHQ_@!8-JBEH}+RK$_>=qJN;D{>cP~VYF4ck zrMQ2U(*g!mPE4x`{6EThVEo*?JC`qgc@DExXQESc{%_@+s(n`+_{Dn0MaRlA)p$Lj z3&PYP77EP{JO4X`^3Ew;V5-A-nqip+SPNU=DG02E_4}t579E))bucqf6dEs}RD`Zb z;m0(!+K+r-|7*5E*qSZ_8ry^N$FMOJ?ko3aU{;f}#qq%YV&e;{u<&E6V|mCoLV=dq}eJ-?ROhGmo1al(B` zb*XKq&I|w!oA<@_G_*;nQqw1$8wJO)#V#Rhc|1oTWfy1W! zW7t#yhs|OlMAp7S8qkgOuVEw5uK0J@)Da3GnH2+v&H7Lek&_@k;r$E-stj?A&a;XI z%s<2CZ@Cz7*l+@eO_rSjgRm`FoF|y|86UzXp`5s^u*|HEfN0ArSXPOg!uAa6P)C9V zo&Px-3DLU0ffcb#^RipaXF~|U5M6O(mj#lS&_YB9@bSxnovZY0ZiJ#KS^Mh>9>JEp zDhl*P-h&90p?5faAc#T)60fhRoS{AaSmh$%^{=I(Bj~zm3MiTXzFX}7Ad|`TZ^=yB zZU~|LnY=W~;+Qfj3F6P=rxZW4&Xrl4Yy9~|P(rWFuUs+!q$F$^R2AF9*dxGU=aV1~ z)j-~|PAtOSh6%Eh<-0S1``7u(Pzs0R6kKT98(HeF#Xsm z29%3a5P&(I#UpHh4Z`zui)!-gqj1{-$v7SRt&yX^klzw}WYK*SfqrRbSV1y=iDg4n zFup8KnqIAi{_(J*bQ%focO2&ex79fPwaBbRLm4hu?(+T2@nuD(r2frsWSFg1ENqkN zOWg!gZ*IzL&ho!IwUT7G;L@Y9NhqJbo*J1FIdD?<8*Bg8Gu>>(E$$7!sss%?T3~Zn z^upy@Sl!mJY#83xb}n{_b#Mq~(wMt@CBZDtiiu)OeJI8Cc=yarP-%AZRy%5`h3FFm z^Vk1#0i%}s1L_MoEjKt7YkdKo^D`yPd@AF0YY;iZxE{$?BXz;Zj|8+syRjdNXookA zex@`F*EIc)e@vp+#tAHupr&9XkG$xODTHd6R$Qu7Hle&TD47;a_tmNq(~Q&1KuWb= zP+L0sjGSM%&zn1}-3MNf`FPI8MNrt5%>pk{n(VhP+DSmzA93cbpgk5S7m2={01ZnSfF?)gssE_D1Oqv$jt9CEnh!NoW>&fI#onAhq zS9dbikrT(>o)OgB=lCrx!j>A)o;YeRf8g)`)?x(fA${D|P#2vx54t64GHNX-vOLxn z-KM*Pey-`odIS9;-0AcUAlSkwd%?f?!}l4@W5E?eo}IC}d${rWGwTB}+Jfx$!n9eL z?sf1pD*A%0Tg)qcIiH>QTiEYKS}l1WV>viP9P}H4%igX+ZK5B)_IN?g-r+Fre7=54 z(lIbf25yN;7K!j8-%Kx6$hV6F2Vv zd^B3yB8wt;FS&T$9Qb#o`1S@F5d27M)DjfT zRxW=8$c2HI|1u;kRU*7e^O?0p4P9L?498V2ESa6)?%-nPqW7rT>UqTdfr932hqI)= z7aCl^SzlYP_exqfyFNgr$Z5e*tgj{dIY<0gTl9V{1f%>95}D(lM(&X0j0L-i!Sk?B z>h#y~--0WZI|gGlA=l{wP6BCnw~^w=FP|@$<7agowj(efA1Ji!3ktcmZ8~Ou{#-x_ zn1uvk*SHqO>2NYygDNoA1P#Mqt(bQqzt;G<)Lr%yEH1Q;R^}8|c-F?YlDY?sUTnim z`SEAtPi};YzDts9TP~eUu`ef=?qVS}p?c~fyldFsPC>(d&otq?+mG8+zF4%+xv1KP zZze^tm_F}K*z_BFMRUVPsEkMLGk$*vg97iubjeTl7){WT%!ucs`-1TZS^zG>FlKkX zj|l7O$BcCfZepLjd)+*jczFct8Rm#}2$wkwa}(K-M{|ryeC@%>@Qzd^YRzh6|;% zXQ0=eLl)V39o>tTE;qxEgf8}wg?Li9Bw$yYh4^h3)irk~MJ&b?iNk5zUI(7jwXh9q zqEL6K%9KPrXSb~;PM7%ZV3>};m2p?xe0ulY@KY^@ZmL7_2foQBGcIr@_^tnT% z0yCaVlDLPkBk{m(?B)*3VX_E^zLQ+y;j<36c;e}I9d6;oQ!M&-fyC2*&R25z@|4@o zS9JOw75@DLb|L7Qx)vd5l*eq&I1tVn&uMBt3Wfn{J|s%L>n>&?XxKZiKM0hy0jkJE zVBww5$Thqwxkm7*UnCApwkD_-Sy&YlPO-pi-oyKlP$gW49H$u?!TWK%!*QqOaD1W_ z(6&cFOy)o?iJsWu_2_>gx`%8&qP&y^Ez<*k-46Oeqh*`?c>!EnJM>(H`H&VC((jZr$*1~q+ zgzUp*%8`yp%_6_AQYA+wH{u3A25sm1{OIw;M`3;b@`^b0LaNjKP;t|VOJX$;`hnBQ z>^{2XKI-&(dwHV%1i?tA|HVbpOt2)B4ocoha^;J(kcc3T$5Vxsp z8+z?XCg;a>%~GF#I1-g0o#%kvTc&PSE);rR zJoQe0s&tf&6(|o#lA!)&u~BIJQp`0xhN8q+yoxhV-L1R?H-6XlL1)nDW+z)gb*Q=2E^28($i-@i%c6p3jG!B zBMwUk3#cl7Tpd9fSp`u6{HSvGw=s=yh7b`&jd8vloNAy;;dzSzS340Lg!?2Spe!gd zxb%?`9Hhh{^F&i47=!AFM@B#Gb@;dcv_#JYB_@?YJr|9dHyp!+a=3z;Y4GN#fAygz z6kHP3N|{t--k;cqBWPTcF5vCgGr8clS~#`#98=6b(PdK~tsB2%8C-+2k@^Ee_F&tV zqrN4jteJHMl2Jwb4TsFa@u!8~cJ}kv09F)Kppm|$lmTd@_i(aJ6|LS}(`bp5zZyKM zEQW6%Z$RBU4sA}(?}=|-3uJjyP5+TYLF7pwfFL$+j&5eV@`4g4j6}2|cE!OCZd)5> z)aL$)c15sbK(zgorqn1Z_98FdGwfJMNt|kwbO0Kek+f(eZvjZiccK_n=FUeQ%U^5f zr%pt+z_QSQHYTkucGdvG#^zhhm6HO~!Dy>#^7PNa_K=n8&F%-X3F-ok8tyU5$YVXS z^BBX=A_x`WjZ^pGw}^lnF3D@Wi(ZI(P<(ri$3U%X%>7>U4d`wI&PVW!skUC%jj!H% zgpXkmy*07^D*h)1=*{|E=D)*2+0F@&Tki%;&t~++h08 zw7ICD)SszQahybs;zb~X1H~0^yc54Z`<515J>)!+7EK;Fhs2ZD;<2HAz5_cJnqxGjC)%eZ0cZ|^wR8B z!-2e8jLX1sY^?Da+7-~74MXg|V|Tg?j;^_iJ|$gdgA&#K zw$Q-+v#aSF6YSCVI=7$E^=vCPW=|a(h`B>(+XwEHjkue&0kKo;VMgC$;AtIQ0Xtij zLl2TRX11Eo&A6%V)$tX2VJp8Zygj%?afU7I$fjeNn58jMZPHZ`?iCIKlsdGoCA!Tg zSBcE;7!O^Ayup_3&-bM>I-KNc~eG=S|iweb5GlnFhRK0`3aRMS`xM=DLH zX5b1YwqFqn2Iv8hP*b>u{T`h6CmUxrLgR1-;okI2GZ~Xz%8g0gqLay9$EKuepG_s@w~qZo6lDnn@h z%tCrF6XaUW_hGweh0(qrZ~JsJfQXC@6%6k_FU~yY{HBZWA|wKvB1RU}Fkzo&b#VQu zIya$_#-$wz$n|5KyBoz1tr=Vl)Nu7R(x=Unu<$ZkEQ2ejsrbw!i%?OGFmMoadW{E4dlBMJNuP`ZkI-2TZ@RIF;@L`-MfRD*xE znVV6u^|!z;m;?XqHuHZ!>Cf`-W#+Ukwlc!|l1t~5JMxP)p}09-YJ8&$h&Y;J6P@rmut{=yfeu3vpQzB_$o`difj z2BM|C?&<8zFNYcIcawK-qU={dxq*Sn3aHwFe#h*G&gVb`!xIQiMBpNEp@X>zLGTeJ z-0Y?qP$luc3w$IAmyr`PwGbs7k;kN`nz2&|O+ks=Jpk1)ALbxK$?P*is@Y@3RAkag zLCC4K8qY~Ym^?%y9VpHUrzBKvw7S#sa$W_(V8@kj&4f#=l+fXpkzD#Q@A&GuIeCsa zS?3>?OQ=xiadG2v(X7^;N-Bbn(wugLX6;p-`hQhace9l*TUSV#-v`;{FnSi$fEj2B zhRBzlyMvi@0Ec6Ti4qipcBfG#ru$|~x%=#`CucU2oFhDLI{P_l+=H8=N{h|QQh8a8 zhK@QtORYq4=!FHHO;@w#&S)|>GK4Qq4#_~FJY7ciGCODdw4|Jb%qDF{39Vn+mg28i zU)9;K)%oaJeY3;+6{$m!k?cyDLm5cVUzG}deI$iH+m3S-bs>kNXJA>95+VWgrtR!(ZKnWoca8s{yt<4ug6M1yV%V6j0bGW(r)hIKYzuyHMP zR5o+&F}MV~-}V+@N3nj29FTP{<+H^?6|JpZ(mUBrotZX_D!#xPIst>H?qb{BAX4=- z){BDJ9~Ttw#!!Vnl%b(?t39rh7x5%B`;>|ou`7REcm7_hRmUpP8C~o#b62%kCTh6) zM*BQneBn$8@BxStc*_e7&m_E0)R3WERA3gt;D&(_oDfEQE#}&N- z{@?Kb3L?<^0@t+y;%xBeFTnN{2f&ePMz*P`y3q; zGfdHm{?*Z`Rm+Q}-@He6SHE*UN$E)oP*+og=IRdl`V)Yo!U`lHsv->4s)?Xz4K|5H zvI&R^0z2X|D4i6B5+lu_cE8QDy@5dq&~}p&HlF`%4Gh&^dlk^9@81-qF^nsjw5y+3 zGpMHQrk;xZvvE%%w5&}&t=-d_I&SakX(H&KUT=L#r#W%QagoY^<0@*}Y}@wyUZ_($ zNpo|YVcgN@xuhEtmpC)#&{p0NxMsA*>-sy5R4hundHNp6&~4WTGIV1gYn?;btQkB+ zui+POKNz~dTf0r&)p?YAB^(jg)hlXJYb-LW_tUt*j2!$Bl#?eNrq4=%Bx)!LU$Y6uN=&`Nn3Ck=1Y)QKE{xPRN`V;a z8deY*R(NhCivf5_0fj~d0SN}*=`M_LdFAcmT&N`Kd>J2zl! z@fJL@_gj59#<|3`Az~^HiZ7h;Xpp(aQ1fQ%Sgo}QouMIqh~-j$ot;_Hkc>& za6?hnM~M&Luk-Blr*6mfyR+$*oKHh~WoCewa13|U`=H*1ZK}RwRegdyJ^mnnfwm2K zdvrh)Lk2@6B5DDK6&rPDSe!UG?Eyz$#<=4)x|89ALs#Z#7Qt28 z%f3l(9rJ);HSYL#yz6ZDND=_`v`NJ&lSRS>Xy5wLcX5l0YcCr#5H4GdX8f5qHmK&k zxgzDupZ^q++JShergk*vFe;)}HpVvNHr=59E@uQ5l1gQLVfqFL#hNw>y!st`)ZY)R zk)w6PtkaX6SqU5YC?vIaZdh3|97T8?Z(WUCjvN>7z#O;G;(FaJ&jP4hlo?5(2zm ztO)67)Ce^{^N;%UzA%+#;>$;k+|5$CsTi4z>kwFh4zNaU6}`87M}2t|y(}$?T>+Di z8dxJ&RNr4;eK927P1>z`=FnDEx|i3~=qdET7tcy50g-+2bENJ^(?-m_cdKl%*N}Nb zpt7y77%i*!Ou`nmTr^qKKghjugc3~TfLCA}=@zJQybPJRNIj4tEeO#FwM$ebUq;i_ zPr7C~j6UO6L8836iMlUa2ses}_T+ahq84);N6b!*bI+>G) zn{Rwgt)kY-N^0ysk-b-oYg;;sx*Vw~dP^W;9ryg;+c{VM)}8#^tqu*df$ zc5-X;f3*32)RD&aGoxN$$j$nBK!Yp8>Z|pJhNB(dCMYw8*P&dt7~mjN!AdpjL(fAy zK$~F1!!%olNW$9lbo9rnJ%sz`%{OY_)O*%azb<<&6H2z6sBf(9cGE698xpY1uYF{(kD8wOZPN{^U7L@No}OCZcEURMEDbFOKynVfsVJVp)_&Y76y zu~54HjsXbRSC$EbX#Haa5YpSu;1IV$f*SqL5wH?^v^K4S{JrtP#@s5k`MXdmsFmh! z;m*Njf9S9%BkB+2-lJ4IUizSArR70XJ#$n`>BR9yv=knJEu^c&IXt>+cwMVx9Zj?d zyU9Dk)6P^2QO{iF=N%Ll<-%Po^7`%f4W9IFl-mdn3+PJqD=q?C{)bVX0Y3$g*DvwF z(Asz{|JER+2i*D)e?vO^hL6DSOba#i85(3h>KpK&dhDAy# zAqWD`3D>@^{k*^IXWaMLFJq0tUvP}`_|9X_&%_?~(tmN1&YJ_cxjJc{wxyJDZQGf? zD0pyl)u08Q^LUEK3%qRjB<^l+JvC@^n`+^Y^Wso-)sMlSpU-u^5x-#?pmK}M3$&ss?Sl3TKx85 z9?l~@?C2uU9=9?IF|@m$suJvVDZzh33K|7(0&k9vKcBo<3xaEnRYB7Oani(~;ilk) zW+sEMWTX`(Nm$Kn=*Kp_`FH$*8~Vo69Xf(GYFfIN8sfg6n^b}f#MKp!&{1oJ7^K9t z`JG_a+jeWNW{rWdB7tpMR&$&lDqSu@Qg?DQB{N0<+rzlKO_P<>nUPI=VyStf&T#Au zQwa24_&5aWxaR&5hE)49N2Yk%o6I}zw_`B^EmL7enj**Zp+m6KnrlLqOfdL1k&?T1 z^Dpb;Pzi;@Xpz*?nAm#F%u$W=;IDByDPgY8;&hjngqT#q3!HU^&S=Jm>jrIzR?b;C zbT#@sA}+KkDiuibNEMqzab78w(23!E*bgpeYEHU{*5IwdE3RW2HX!DSLS6n@DSGRN z5*O7=g8@3ygnG%^wL*tZvxh=O);VdQ5+wei5@gs?O8h#gU3T;PMMEXRV)d<5$sPu( zz%u|%AXd<({L>KUBKdtQXSF6%{}^nRseVMbGleEY=mqAjVnqVB&j9xyr?51NrK&GK zSY1AGyCumxm^EhEua365rvsHBEfvNE^xxghD|()*>_!?JMWX||7z(h9?M*PXfq-3% zWjjD$@dUETU&?{q*0+s5%UqrNFT)n%t!nYQ8V;OT0ySFG%rLrD``7oVxl>9{Zkr-L zX;Jn)=^TwiXpK3rVi21iU!UBqtPG6eq4Lhf611$OtNqr+LR%Ul>21LPB2*2iahZu;Z6} zhdINl?nu`QZ7~wB$!TiFqmYH6%~HFH6{#2pzieHnubX{~2JDY7lkXmp=xeS*Ws|@+ zB;vokhjH`#vxoid8ZHIue3^?2iMEn8skdnX!&a{n12a&k80f0H6xEvu`m}z|{f8g` z*ut=Xlu%qMJaCQ8sV1y<4?q4|d|hyMa0x77<@JnoAvC0UB+OirzO{nhc1x3%sEOQ zIT-McS?q-nE!af+HjRJp=nE8Eh)S}w+uc5m7L;~+7#!?}E)bJ9Js*4cIaK&X3nqLX z-Z4*|T!D8?{MWO#kfWT}5zV>;?ttR#Ic?WShd_tG#&gvmch)E=>bWmxm`j}D0# zksRwp4Au2?$WZwcm0V3RnjeJc#Yz%*CYT7jfMq!LHJ&>F!s!8d(g3zcjov_!#1EzG zH0cW7)7Kw9jD_J{Dm!w3lp-qx}>8FXC2*6O{^_5;#9jGYWOha{s{! z%b;AUQkScK{}$|(uUKVU+hL%wta`z-Mz;1ITkw#B^|e(awX-HH!Pq3`VTObW9%e|c zO?sJb-r}Oh$k64SwzRoTV9)dfCACEG;;%km#?rly`{7r`QBlZ9z|LjQ!=0TY+fD5* zAB)O4v%n7N1-04NYGbdX*8#3!qW6M9w6CN)Z0esyIm@NgTg`y8F@_R#yXm@A5;^=C zy%B$t)GBOqFUC*h|Bi`gHl>V6LaicCj8c3{Q97;a!8KgSPa?%iGNcW{jhLc@E+>c? zSC~BaA3k72N~(IRcRPSa;kS#65M+P&FlT8fAq{`oaB_ z?qQSw;HwjODJPiEG5GL|!G5i(>fL=JoH71>?Lm8&Rg`7pA$5vU+QSZ&p-H#S8Vmk0 zH?SGCT>_EwWw%h5MewYrx5C^|5RITC>D3|y-ZMP{`3k!(2?J8nMgw=~eWlB53Qxh)RlQTS%__fY_$NV1|;M(pEjW z*{RJ#@Ys*>h=h;AM{T#cz~cgjE9zoIx;f21aVT=>r^bP7|7!EwpiXIyQDXMu;a8Q#B(7vI=c56U3ZbdcB%S|jUsPX zz_6d&4{JEuUQ*ka(bC@(n?;SDWUDE~hkGZKLA->R>lwiny3lmpI`SfE+j~ZJP&5nL z47%w$gVf2#27({l=r&*`3)5aUc96WOjlq?m~s2f)q5b3Svbidw%3g$lj-lB;C+>YEIdZ}V*Jg3*nu{P0YsTuJw z`S(?rMu+Dvf+W_%bDs#=Va1xWyfxZlvn6*WzZ@QUSf3(@%(BS>mNCW{doA<5(UY^oJ&w5a5gs$Po)R_bAd&?njsjB!D*`k$%qWsnoPO&r<0KFwZ^VWn#9X`h>Zg$L zV0hFkT1F)43aq6cwn*V=18u>>9Vs(NJPr}HYm+Y4o|iPE`diVjRMQO(#(1xMzLEYc zAkPmjC!GH_XVMMI7~MY}Cg>euS(;n%i}lM_6^8N*t!O{gy|r=I?KsgXiF`Nw%n2&E z(6*#U;`v~F+(TJ7N7nqlU3hG>H2br6X7(kP(k$j=#cdpg<6x0W_1NlG$8B1N^XjiS z4wDtGj+$&%%Q7#jCBrN;iyP{pXx99Fd~rrwG!2_?HOGFUr2)SB!KvP-&bnqi0(LV+ zW03%P%DZVeszgTo@+Tr!xvPn^CX~kpV1FXA%A=@(8Mb9WLDIlSt*MiV4w<40?Qq1nt%cgHg)Lf z#o&cp<)p;R@UTzG70 zv4&#D$Yv=mIqbnyJon`frp~>*ZYuLpdqk%~9}pff{qoa->g_KUxqduDF9Moby}d&G z&b$gT6;`>&wqNg}l;bR$A50LOXDX-yGLPV?@gCyvUwaJUGflFeW&*-={WFxvU6FT( z6$4sF0q_+0=B54?N+0=#FTJUjG>=Jm>p5jTR%p#EGTlvLOl9n7fkt;iMDKe$OxUz( zVYrq_u)MYlP1XreRps0z*ZwJ1^$bCFJRu}}PTYf7$Th!faavY`SV7v>z;xe?c#1&k z(#(&NSu}|jFcoW;67`i)uTbS;eJMVkK3YWH$9}Nmi%B8LYyxAH_g@|(e%}APD-rlK zeF0i4#EsNTV+@m&fU<1kkHOkFwbDoGoVr0A0OipB3vd_CA7bixrtftK#998X$$s%G z_pv6s8SoS*kOdn!D(v+KqFF#WV9pX&|=}&<}s$MT18oJS*|P6ug%+ku@{gTX6+=@G+rY$Av`^Cpv^wXyzlVY z6~m!CI&J3DiTUd{OxwEg7?dKTdcn%Ic*SGrNGo1)ET>kQ!KsaGsuF9!=xiD9%utxg zVrr1$N+UsxRjD69Y*eGZ@Wo{9n&}j84F0Z@Z+bG#QF92=BL1li72=Z?$*7MerZpWI zUQY|ox<95U(|ew!prXD;MX`^h7Cd>!EUv+oHK6l-KD1I#^hn?^Je$;t)8$E7b-(2>h5kU9;$9)!Nj_+GpXMm?^2gP5F{1EH8YQfnPIj+LN+m=Qi}k zNdmNCTK`>)IOnq{=*V>D&;@H-^BdYsCU}h;^jsQk8K3TRLQ&hqimsCRgxeW^<6K`v z8rsze<57#s<}iydu#ckj4mX)~o&AO!X4npiQLxs?oK~53#J7BqC4#v;o1VBJpAh+| zbKRbPyMPc@#0i!rh6B21rop(&l}w5*grbdMiGRJ1VlD+sA88?9%s?p2ci-~r ziK)=BLJzRyfdw0HtW#D**N*c8ZZ7uOf>SazrbDR+Yxi_qjb$j9HhZcI+(2Hr(#Q1C z&0xHvj51$^m-h@T`PF-2MTKUAs+jWNO3j`k0@X4wWQKLZoIb3PnVCe#HJ(P$0g$kv zIP+&7n9&L?FTt)e9I@YXe>m2we{@!oI0=<&o=nX7wQN0#q07WdI7&`JLh*7cCf?F7 zMQ7uND3HslZMB#tx9~eDo0RN${V2g)X56_9Zd4tI1UhEBbXkK%!e+S>(}xa1jj}?6 zvwD48S&k3Y5%xDBo{1afCf9bd0(NvS4f1E-OLAKC(OM2i9!oZ z82ZGk%pRnOlBHsnel>^IC?)iA9%CrsrirIw%5Ka=%+b=o@>)wOo@r-NFzdmzKRf1nK+$r;iNWJ2U3c8th z_};pEpE)@DIdUiWVeT%%G5z9Ap;;ZWSGRRMRM*5R4txG#H`YEL*E<38gYLKK z{rkmTLpDmM0=!+!U(+fHe488P$uW#)0u@mduD1M@*S@FolXq^d&mM)vpSs66c*?FB z7IzalHAW*hzP%GYjiF;?BEUR4_YCKuTlsnhSKoq2A|&sSgnQ$f*u=W)zp{a1U|G6m z_3?Ss_OD7>>eqc4Z+Xoh|Z^K=g#uO=+u z4^e*RAaZ|2bBh_de_UEYtPP>tqxF`X_mew`hx67whixf4>C&-L&}k(@F&m4&AP^2>$WP8U=)!aUyA0rI6$T z4Zl!g;{RW*OV@M6W|Tvt32q`wM3DgPEpXUo^7wbxS)PY?_n*5Tq&+fk7*KU;TQ<*>iysfB{4nisX0kTb|t17>y-PxtNp$^kVm>grFZuAJRbQ{H! zm{Lo!<-&BBV7pG&Z(y)HjXKqce!n4-OtzS0wI`e<-m8M8)j9}rWevgeGwgR-)<~QM zg&80-e6Z0IF=Ni0aV5Sa7<<*4fP@rFMr9stao8OzJHqfB zGqvd#Dc)bhsr<?gn_fJp7`6_hM?I_HgT?y>Y%WFS+9YoJ@nYs_;^K_ z@@}2soHFVW`@A9;7ms_L9C^*aut+AbK7sz6Ux(L_BW^nbG>4qf2icBjH#axuEO6Hg zQ0+2KoK~efdoJ+G@acnImuMP4Dcb?0K=%Hma@}$G+e3 z*)cbDs*>pBuG$}lWwHmDbpr7t%v!XLIIy}9fLX^rfy;2)DQ65NI)LX)=YkA!ZZM>U~nSJE1=ARt{PC4=6t!x51fe(~nx&2x90tVdhdf%5X# zw%C{gMP&(z=|A*)X))21(DTi+EcWgr6)uof*r)W*x8t0+ce%rJRghJbfJ*HBJv3=h zq~QGa4bLj`<$!$Uo1-#~&mhtl?KE+QWonLowYJx6jFZCN76rcyU(@6s?WQT2-a(+9uEaMd!8vM~FJCD6Le}y%=j=Vf1Bv z0)ki~zx4IHbF7Vv4`dqE@i^mka@q=M@YRa7y44750Hv$pL%e$X72$|b(pOT1Bq?Jd z$xgDHs0gV_go0@jsD}g<`f!c{(^N=KDlbU2iE@wrx(+s=XuBd_Lna!8A6s-T9pCd5 zo-KS;{MUw|I${YGy&K_Qx&ogsGQ|uqIC1~w4~n3`KMx|ny{=C3X2SWcW(bx{2bZfj zieeUZC;~yna4EA}jKmAdwit#I2B*jkJyMnMkkGYT!kcG|(92Ydg(%#d9plyfOTYX} z_iNbv9Zj$X`-q)f0Yu=M0dp8t3Jc*y`yhy&E=~eXiYwby3$w)vQ|eWpJU3S>N6NiE z#<96^p9va1WZP580+RQCqpipQp-=nt#`H)H}32|LqXXjZgE8_X+P(Bt;eSJ-)r%ZRz=^#kow~W{xo5COx?` zy5lqLhp$Q+aqQ5}laJpT0%uk>86>LSpK;Ws1y+~tr|-`E=7VeAnkph*HpTBixOk|L zuf@_@`XC}TI{yK^{KrvEg3IeO0q9TU{CC{qHnyl58xa=%rZK4r5YRAE#Ua^FE`#`z znzR`E4?<&!$WTNf690RZLUX)JdMiR@i|nEkWexNzQl!hD;(av$;ysCV4FuUY=FBMa z_AOlp@6d~AfD$^wE6|AwxvlQneF-cQKjO_wyzXjqCKHny_8Tg!`WZ+9Nm6?JTHOl8 z9f<>Nn|tD@(8~_n$)e+qU=JVudRiIYyGWaDujZJ>U_~zGm%{})*DL}=4;yTDONDw! zkIU*0#5?UWB#7%ua_AXfZ6yQj}d)Nq6c?Fv z(fmaltJB0KS>%XB%z4D|6qDP_CT5P1nBe^Fz?Hc&0G)?qX@NYAE!9s?w$_?VNGjhocq>R%X znb}GW;aeop$6+)wNyTY-^eglPwWW51zpIAzF2J90IV`@@DF}ai5OZi8Xly6l0ovY(z!<>S*Z`(Ef@_-7TU#~y)tv9TiKA-rM-Q5K%6E`m0s(2sOtMd%{+s=Cg`|hiD^arAuoR-OR2Yibl$rFwc--(>d}&B z9Xcldg&_M-54nrRJu<~+jyb|GXSIZkN&e<0K7Q^GZ4C&Ys9gMF9E37dUNfe(6p`yL zO`%nj@)&n^VO{og;vqY=VjtUrerGc(Y(M+3A>k|E*UxttAxH8f?Rrtvq2KaHYq%(% z2%MVY!mEBU-x!Ir`xUTg{ib2r#djuMr#g-Z`XvHPTxgwpo-T zZ13ncTDeP-;>@S*><=&@Hp!e0X~tFhsxw^1wRGNt{>|zaRiMFghqDlaw{@ehyC+*4 zB^|Wry~};DY02+;HUL*ieB@62^`OF+aB3Gp)fSheW?EPBKI<+a>(|pCVPpcH_Jmsm z6&AHNOY}WL3zhdoc{Vc(Yek*L{DLROmvC2YfvSy->o`~KZMTY!8nilFU`0$ex8`BV z&k1QFnpW@N16dO}+_TUz-}NNOc!xJ!r&`0uYtJP%C?;_c9%}V!(ietGvFgX@j~r`x zv*2m}N^DTVHF|rkT}goUZYmMzRobrV&`R?mFOf`prnPNG)~`W$QAO*FS(aNivJXOL zwe5D#=Z5MNiWT+QLNwl0QR+~Fp#p>kb+pwGjWXIH?NV)_8VB#{>_BLxF7J(w$~!~p zS?{XFFRl*SN90w%K7bu`Jm1Bn%i`!vs}gdQ&2EqoAP5V2vYLf!POUC|@z7uU5R=5f6wb1%P|QyjQ<^x6x+9boZoNIQZA zD48rudPxNU$Zl@57T5+9;+AXkfi%apt(OR3^ByYe+}I)-_;KAqqd zAl}^w2s?9y44%Gjz*WOTX}MB%dW$u< z8?~RofpyS({g`oDyI0{w0NmET=>Ms-=YQ@PlTOIDVJaA^+ z>i_>VFyknvOfWv&S<#;1czKq;zhfS12kLrAQO2bBUN>ImzMfcFF?(>kfubwO7Qux@ z2tL}F4gkF@1{aG1w8d6yL12lt>@+9}c?C+c??*hY&eR5%QH!1Us{5hN z*O&+~S6A7vYk@b5xUEkllS?Vz5I=oO4&PGXD-RaO1I(uS8W>ntyXL!ZC@&KJ{R)q!uGc8T{dk7(&GJ(< zNgafYx8~O0m2#23D6y{j+Va|3&Da_(S@H~RIXhwawthBPysziy(nJI zhBzu`xMiORve}R;)*WLw7+A3}sY#qAIEHN*GgG)^pkoA%-piu|Bc%#C=Bg+ejT?l2 zT~$ZP`}{ImB%61_@LX+1HF8Q$PYPuVUq;%QGtoFZi-(n`8S+MAD^ZMguiVENneAj+ zYR%sXj&lP&E_*ruVoOcuuLfrD%gL^iZ7jIK+WH0Dua@*}MlYmVLct)H2sVaw|nlcY(efn*BN&S7MAGc~cOE`=G)E_1Q(ZrhRQ@mp_OGEKkcFMtU? zm++uQC;rRswgp;=$SAsndsw_^>yYqj|DP(r|9m2N`TvRH{^g) zM-~8AhE7Y81}>+LaznzOvKk-^2eU-50IPf<{*1{~k~%0Xa)m&M$fUF>h{@k zo*BJ9ujSIR%0vF3Hj|g4rI356#rW1&_4zlOc;EAtHWN!Ra;G7A#n!&l-{tKQi`GE? zAmJf@Amu%Fp8Qw-pccpZY84m z6QGrOKhVky2GMn`MKpdAu%J;!zD;xDgk{C>%vp)()yHFz=CE@4(pcZH?ynMMIIdMUI`VY{bSC{ZwrE?Iv3;tcQ+`3?tWd_Qa0` zR%)I$nQ}$2#or%Vr>SJ*MLGPYz?|uovPz4;ADVb*;^N%k(uddx8ALk{ zZRsJZ?$HH{k@fc(C=?ZR&0fPB4|+AkEKJ8e`rY!dZ>3#dkfaRl*V3le7F!;m^xYt` zl4})ddFoEjRtHF2vV48#vWK>Lq`*Ne;Z4q!R92)rhr_UBW-z2~jX;;CGN!}zksdh; zQ1AdinH`_>JIpW48jhm9*8rfbDW!=IpF;W;O@{_e?41nYcMD&~HLgZ0$%*Eig<}qS z92&RFLGdYIXkz~3Yvq4FG=l$j7Ca0MiRi;;z*=x; z_$A6h5;%$GiY2H$DbY7ShYN`9ih{Ltjy*8`K3n;8ANoxE=4|i2&;0`r3L!+(b2XDB zK%hltKm^lUkiuKBHlHt<#upD0{C?>q}hotYv4+7ssH1~6fZ z%^NoCJATMVnNvV&#~N_EeZMO;Y*NYd{TjE}IuO7&6$55lM<3lK-(huVx4(&KpJZ39 zI%)_kCkmX=PH4`zD<0)0#EUvDo#=w(@m(MfEo!-HG)s(ea;Y=y4|GV-d*BIkui*(Bu z2bjs~2I*Z}@5AU+#-?E}XSOmcj_7ulvY1XiI7PA8c$DgX;in0GNP<;VTnssC#kfDX z+~~)AfPfAq#ZJ;eqWdbxyN|$K)Hda*(CAy*Z97B3f4QmA+VmcsqN}NeICf=Un5P!_ zP7y*7vJn9{HHcsLsax8PyAwiPQHE@Ei`U9;HUk8n@+H73N(hO3z0X0Hx`aO1UwwY+ zN9x2@f$D-AQW+N!kHb>ZsU##lgu69u>52UFuCOW=|B_B}V2xU@tE9y}Tr8W3)ta7d zh@?8#yx!fAa8_ynZMk1%xmYK;^kReWbDI{i@r@60l#Jaf&T`};KC9GvuB6rnxYG@^ zy`c+-LQj)vl_i9~N<>z*!iXO*nFaslArb)n-+6O!g2y5HXBR_51?m%V2P_~X>b)8T z>7FS4;iZia@wXFKiWhhA59tGCvs;aLpP5Zyj#{z59jEi57o zBwKWqk?D?r!>l6tGKDDhrhzO1oZL5SW87bfjBm+7GUP>w&&o(hZ%Z+Wwo5P&ci0v> z5NfuLzQ{2IOHf)OHx{ub=QI%FShG16!jCteheZEK!)KO%kJ>#fqo4nrpf!_AO( zaH^-YNtYbrpuwjstg@e5EzzPGBJuf4s|} zQF{P)nTLf8xXX+#eC&AG$K2`dt`i^5GBEZpLW@bdQ$8XgG2}w!u3Ei4(TIv$_LMEI zMlz~Hm^Or!A)-0YG1LZgtIk7pST3n55@IYH6G$H@Jfsg+i(~IDzQX}+RoT4X@_BdpaY+*6?!^P1MMthppXUZA z&&j{U{w}7O2c&Y2imbQT&IR(1WPz)URB&a7RMjaJWg7Odwpd?fKnyB3Vz%V-i4Boj zp{O75ZPBMMIWoVmGEnFBZFl#2mI&e9sM9BCGSSPDCT{wpnZy)g&b;y^TYNOFnPMlk z)c^mmj|u$SD)9HU5>YZyle4(^uT1FUwX!yRRJ~WCAf4}J=A&uN4CeCSR}<>`iV_s{ zyz8Kn&cFFFmE*VI@yqJ+X2R>mQMVtqIY}%R?Oxh6qK+gFDq|4Ns4c0)IoeUIe%Hv} z5b)u#9wxzwWu%MfCBvM>8;*j!BB|~7f+)1oY%oe)v;x~1y_9-f9angHUQ_Q>VNP>> z;x|M7<;Z{)S|w>8&1J*wI+kAymcv0d{+JsK^WXT4UkInEk{>Tjp@t=YaO%%%ZrvsI ze5voVj1{-kwe28GX9(rf8YrnH*v7o{(_@g$-5^k_z#c>TYB=)?%O}z(RC{ep*m(4+ zyllT5keQJmWoBz<7u3~NcT;}Lo1OF`rz}%NrPL3}5v@yxRA$~c)X-`4{Ga&ZP$o2u zjd!UVekNOf>`-c^JV*|gjS3u@7{Tx09z9no4)pBlz9~PEkWc~O=){~kz!7nbFT=9# z!j{=b3AjUTTr(t2HSy1u`54AnTO)7q@X)EuRYU8{sW33Z?o9;I-zRd##uReYxsb6G z(5#DCtItZ)`X~RP6enm9+inw48m!sLXMXawT5OsP@Vl1WPL=8|O2^Iv3}(k4O_oLm z4i*>nAa4p{2Eq^8lbMw^CH|Q%`7Rml#&(QV9_9=zvK6Ot9qcj+YrIET?qfclyMii! z8Pp-c|J+dfeTR(vh4q^$Y8P8(Im_?U1h?Gwkt%zIk>zNc7_`(vcs!I%GxA)?I)U$T z78n?UXPR^|Ebqt{<@I7vT#=9Ht*2+oMxPIpQ44BZJnj8xPEYV|q)6x!QH*>NS<$w- z@FmeHS;+kUZILLm;8!`-PU(KCzT5ZHBm*TYp=zN`_`K5Blz#-5;w<5gC8NVxF_CAeG#>&OKKzZh{-Go)CIN3fa5T{-;x=H_U7>(K+M zypa{|L6SHXCV?x3R}6#{LN#!+!v!=0$Ws!bM~KIsFDcr>F&WzczcKC%?J;`P(z}KaD-c9(yT!WxXJ5^dg z^fc2H?J(JS;Y|;vz;c_?Gbd2RFkJ$l+%HyD^An@%uA?0Px{$P%Ru?mmnAuaeY;F#> zoe6*=OFiIhlbwEo?e;wj@`U9?S7gTUqoBj7^eIdv7&5AEMPGzUA|M(HAzj7?v%$oG z!ZtCjYzi?p%cp0wL{=gLbPlt>zWniCW!)JaYm#Ok(eG=BA_NjXteer0iea?OKle{H zlP$ItzhVSB`Al*lz~NrzJy99m*0g1Tfu;5T$V^)5e7Dd2-GQCj^b2Yim#FeFVbHI3 z7An_1+7gNtOK4o7U1l+7>QUlvnEe$hYsB4A5#!CZilOUVPBB5?CESp;n^Ac|y`)_n zu>MUoDGI4><4xf~e}FsX^x}%9Y&G$-7Dg)1kO%Wx&75g*5YbU78tbjH|07q36ELqW zQ7eR44J{B$KUFA#pW&R3YYkQcTx;W4k!k=>h@A-r&@ZDIXG;yG*t_wyuEoBfUp$q0 zTMU&Ft*b|wE zi~MkH!WP-J86DH~W5^)Aa z7;Wi`2SH%Mf3NYOs5k6Cj?4f2Z3E{2$2I*I2Iybyh~472EPx;oK#b1(toScMp!bs# zohc?-N~w9lAKW{5aoP76N`YPTU!>C)wOv-MjhWdl3f|nRRA{tOUwFj*JWv;|tCE zb^2px%8OtNf#bRfAOUyLuh40CCh~L7NT+=Sc-llIrB6+uzt!?V`uKLKYoCfsDUs~; zVdB0_fl*tpXu&Tz#Dxf{9KNhhHs8qaek;XCXMtL4yQZd-Uq3VexRJVfJt2Wvft4Qa zAhh9gTAC{M0)A1KU@kRA24;hby`6DhPVo}k)CBYZ!g*XRTp4A_`$0rjo5W;r^~8J97-Etz^&tDB|>y zCR;8?xU~QbPwIbpc=*8oylD3>>gpckF4zFNeI<+MU z^>>V;;n^)kl8Uwewy7Z2PP1$qKqr-6xnJsQ6W5-;oDoM8GLstU=9Z?|_{nrwwmv?jIG68t2ojy!ve@W|#CWmU`&dZ2ymZ3x^r z{sDQgoIT|~?MeeHkDl!Z#3CAb?@gh%@H4ms@xIS#31nk~)NGeQq)FLWN?l%i1-vz8 zfJT$$zta+j0^R`FyVM^YRGMPSi?gLEK3Xq(lM9pRlCTv5u!wPIr(&3;E713VQS|IxnF3*5sZ!n#fa%Plr2OQmckMz!rMA*I>a0;IWRKy!RMK=wy zpW_;^9BPL_Okbs7t?i)&$pHJCE&A7~2RoV&iz2J-r?#@i=I?U9(|zj<-QRtz{2nq} z+9Ch(#ikC6;&q+1OEN&V%j5Tq1Uv$P*KRGD1_v_oDmp@YhP$V!B?`B`F?U%_C5)ca z!uTP7LQ#kB04jkuGEkw>7IKLSRA>Y@@apiDGZ?S!mb}DiS)kW>ozb+|2cK=zuDS&{&Cs--E|F|YKWTN6v3Y+ zg(kxzO`p=FCRkuT=mS9nPiV=MDxzp+-$D`?{V;yL{QpGifJNq1A` zq=%14R(5h>-4dSdH52oHF@@*2W(KU^HB;l4IYa2iWpBG5;?7jtY3%hZ=YX~>84|> z`F0LyZfNg#B1|44QO}%(FHE=txjO{fb1TizWUm5kyjxbiuKLRdvWymq6HdlvVcwtHtL1 zC}7;&Z>W57J+l&+f2O9AhRN9md~z)M#_&Iv{`jaTTOubkZM@`M3*<(d$6^H~#3me7#hvk79^`eLWKC$gDWQX6s`!RkV zjQTv$(oae1Nrb3kDv_Xt-G=MG8MV?TwFl~|Q*irL>X(zjPdOr#DeyB>S>Ch}wt(q2 z;=>Ih_Hu#YfS1x&aRE!G=O*_~73DPltZC2#EfaT`Co#PfmT`7+nqLYP`T5YgnyJcWDmI~%rn+@oxoEmL1K1~AXjt0!5 z4s9WCluEY;S)kxS7TCTquKt%SaQ76h`FN@v%lQQL0o~E^@@6N$=qSrnV|2FuG$QKA z`KunsvsbzHn_0prR^A~vgr@9d`TX)(fT`Ji^ti`$` zJd%%_n&d;Z3~9s!!1{mA+?s#_q(Vgo@N}BYJ9EsceQh-Q8bamtlK`hC{uaH6&Ij~7 zi_PxWa`0ir249hn{4C~~uQ6$MvBIi$-1pD4e~{2t-V`64vVP45fkv?2umN8HUulO%BFENh0#aD7|DUfxFaC!~YMEkve^rh`&dHkm^% zYA1oZ_Kl2V4mIpre+%an*Dz&7u8FcZ@Q_=m&({yfing*&g0>3Psv7CYDkVMKlr18a zaHy04g~by^@UjG3Z@-#Yl)x)5S$=k=`t|??4~+Roj_; zh{Aa^th4G-81$K*H* z>1KpC$mS%F25|`um|KaeA#!tKOGz-vI=;}aZ)IBPF?{whCO?IV>XqB;{O#mRZA&YX zY~P{}mhtKblxi{NdF?S@-;B(E(n*bf^-Yy|KcEpl=W>4v{!*8~C5XXA{k*i1wMK_& z%;+1Jt}64|uaPUoSHj?UouA5w2wdDUQOJ|KG9sRwHuVW_H8@vNLt{MtO+Q2hxcHC2;x?RSn(+vqN7ck_o!a-y345N(mZbre&Fe(f$Ubx4mT zPivlC9_JsLXJwGflaWc_*!e12b(i!`UPBc*zD2UH)a7P!AN^;d@y%GLvwizwY$6$( z=TxmJn`S(8yz{}r>7A2U+)_^XJ(jL~5&tW9QzH--n9scqUqI$~DIjlI%Qcc=SMjkv z@JXa=xQz*~@3-Gb2A1DBlmeszSn`$WUp1@eEQNX>uzgQQZCIs}ca&U{l=^ZN1y$j} z3Xt`nxa6m0i1|*!Q|ymq(j|*OuJ9W<@03IHlrm!bMqcuD=_hg%0mXJz&%}8*yd>7q zrMr2ormq_V&-_dl?(mGvV-j@2iTXb?FH=#(_Z5Gi##n;8<$ur!kQHZXwtzt@`j3Mo z{N%|K7kAs|7S5iI?$5n>o_jglTe?_TKiB!|zqEy?1--hvi>tM}r=NtQy@iLhhlG`t zwfkS`0nbI9F^aeM%|D4cnU6VzkIx{J>&M4W-x4vW5-n~X|NHNLE${Mh{P^?7&pyct z$D&tO*uOppopkste6W!5`4c6$c4Pv2IdSPv9KUDswLNo{Vdk9k$b_%h$L|E)Ur%+Z zy~>BT6DTxLIuY`ppJ@+SjXQTP_Tla{+FMaP;qz~qX%Ab?J3lV=;qQFCx1w|+=6^Z! zI(RkgoT~T|)G4!wrZ?9AF zgxCN5%IKL~tb?+oO+b$pA?M>-OpsTJl0>!E-(O zz=;g<5j@wcPi!d)xd8L^EZ|tuLE^xCy$b}E+>mi_bI$^vB|TJ^#K;oTM-o?$1#Ko- zvVin1P+6it>PduOLi$M(>hYlyB={i4m&$z$NS1n#6_EGP0)nL)q!aWDx`1M72Dt_O z8WMN{6NiL>oVd{{6(9Wd6Bfb4?uhkW5+GLQ_ADbyDUrURJ=nGX3Pz*HbDpjD_Z3d{s@30fVx zdIFPzB!I-ASBNkz$RtQ?=n5XD1bGkYf?grRj36hVuAwV9m>i@4^agr`1k;18f!+*V zA;8oi-Jm<@6$;D@au15Mcsi7e>ES-c0;(9uMfY$}237P@ga~r%cxKL6P6P|m?I>q* zTTX-uvh6r#Hd;=E2r}&$XL?vpgb6<13CKLN~*bs-Rs^-*1G4<}?yW8<#>+Xs(!)5n1QyzNp1bGLcvZbjxd{6HUa{ zMY_GT(n%&#>nFPTwQPwdqU!?P_FA?i6UlXsZXK;YqKWvrM0c=OAIU^|{a81Eh>>9 zzAn`rtwkjfq}PvjvuH^ZV?@?@yRT?TlVT*+S-XK+g~S-Kb0rpq#fb`HMNld8)- zL~vfe)019tWC-ERerL0k<1~L45nm>8TDXg}R(1@_qee_BJWo%f!V&bPV zF|1HA>6VB;FV><=h;&QBpB1ZEmP5QH<}Zr%Da#?oMn2%Q4xQBtaX_lX;i|W9jjh;*)#A-h3=3t_Pg`g z?ZD&;$srN!a#>iDSaOB@kO6kp+4#IF~}OI;FiWM(j%g*x=IMRwM4E7%Y3KMoTSV$rEc;s?l1@vGf3|R$9_h%eHhM z>t9;ZTFbQ*g%vLiYN=&ix{Gx!4Qj3BTnfV)m#(zbvM&W;qf1v>Yq^)=uq>rgEm44_ zJJ>6wQms)OOE4_3w4f!5ZRsA?x3r)&ifbtnD_rW)62-dYgLNwPXpQ1r3dQP|PP9a^ zF9l-5OD9^RxR+wF+@)qMyMQGxtZk`T>n_JqFjlj)p=FnC$sY?TZD`%)T8hR>m&Ud1 zvM%{z!KHDnyPQkmSo6|@mRS;=vYukK$9B+v>p;9Z3-^b!zcojrO59lsdI~a7KqxbW4X@JlLZHDWRpqtsdOb zu@ufy{gw$pv=_y?RKInCBRZI(URu>6g{l|a8v6OB^okecalQIh*iWz0s`iPa(Wkf4 ze$JM*dr{--b+%4WP(QOu!<#1rqxC7{W%Q;A{%B1~eHp!ZLO9x-vR}sCWX7{6LwQ`r z-E1bXcZNbLOK&pc+f$~zDNAoQ6WTMN%$C_Unepx^P_oKwo6Q9G&Qb=-`kD^Y&!480 zm-RK92_I&jS})UVYT((Eqa>GUHa7_DX;Zq&a7_(-d#aS;GF)?m(4G-xsSMK8z`LhJ z$t#02Hwfqz!)80buOBX#(DyA8^x zx|4LodnpFNQ{5;X;a;-A`c!waj&v`>fPLyTvYf|;yS+&Zc3MKby%`2Gk&p&9vBKog zBEV)#SOQcVEm72@0#ikc6*b?38KIxRgqmFhe6`T6u$(3rK3^5|J6KM$i;%A&dLHK3 zY@i>LrpIHzUt@-*if^Ju&*h46Q6GRXDPILV)uwL8hg&M3fo?3rt((wT@)7-(RHzsEgnp|eu?HGVK33K88R}0y zRn@u-6>f7s5pG9rg$lR39}Bl6zk}wsxt|JmAnk)%zpIJc~bA_9%*i;+O+BD@OjakEm$?mXl(zs+eH`x?MCytAUOOs<^ zbkevq{RsIujGJgGLgyi0gmIHhCFlUMJS?4PDn=I}d%@C4rc(41WPX?}(NvT!K(>e3 zl1wG(9Aq6>AJJ5tEBq?IFim2;2%V2?1=A$eOVHWKYA_tJUW_hA_J`p} z^-}axWN{dTST9N!BD=yMqMzOX`4tQ7quSr`T;#){Gf$xbjZDOQrsN!Eu=5@W^blH_pMBq>&! zew@q=Gbiqg(D})>Fmuwr1f89%32P+oi_yi&5LhE=Uy9B`mWIKJ`=WGVG8hIY?Mu?R z$>uO7abKJ+O@_mmB=H1&35YhKWA%Mg9v?)N@Nu;%?-b<3#FvPHY3p?T;}aEMJu{5$+?cuO1`t zXcCiG`3M3KfF`MHm5soMBNnfU5rl9gR}ly=!D3a2S&J<^y2 zgq@(idU+=BNtNz|GU0o~*i>M0mE?p7VR<#INj$kqe!_sT8eu%WoT7geA~&HxaHoZ} zj&VZ538u8ImN9k+gb+*HY8~T-zzN4`TrI``>TSYB8ds|^2NguojWrp6H1X&Nnc0IDa!il)(8 z$3cBSP@|Q!)Ui?T6Z~l+7q=pfUX)7&t?9?DaG;O7| zj++`sV4+F1L<6XI2v=xQtxNwd?_?UIbg3S?eALHJG4DYiQYHqxusdw1(C_ zE^0JEnikix$4d1jfN629dz{p8f;sJ=WsjW-A;4(|t$W;Xkpn2Bg9dCbJO;nY_(&^i zV}Xk?c((^;Y!l5*4>-1UX8PjIbq-E%m(TPim>VBRYzNQuJu%lmFxg(8=}R;}{AcMl z`;2D%BuSrU9m77^7EW`I;ht>grd?zJ%-d{f_6%7Dhk3gu&5FU+*ao4wGPvM(7#1|) zRxk$~#!#f?wt(5-_ZU93+*U9bJdz=!p|s&v zFgHAw!Aa9^nFPSS7}hlX)=3U{FhiYI)gp~*6g(K(enY!53whkAeh{|pMXPF`JPJR3 zkhVQbYoDdYH|iXmV4$|MXyMJ1f^dDt_$s|=k{_O$itLlB(G{VHwrMd8C|Qmrba%dDx-K6*W4(?G-52RLYf+RnM#bj zRY-HAAXASqwn}YkQ<@EjlxVb#@?!Q6P$-B%Sc?6ZiWjmwHWQIg-viirV68I zwXhj3#580qtb&{1yi7$#?kcz$F38kn46jZ$!TFi$jH=biX1FlZltEuLZ({N=Lp~KS+I>X=GeWIMF`|26- zX3B|Ro^H!C!p-CphfkeWXQZ1MC)jyTgGzbMr#H!*VLg2;uSpilYI3YlMh3tthj=a{ z3t~+GXd}?CWRzJ|5ieiK`mq`zp0EnZIzPLug=l5Xk#Wwvt%7*Rnj`C+bK4Lx&*~`S zoN-$bkzsXC7cs~>B;%ZQTOCosIwb3yd)pMT$*L#w^XYAQL@KME?9XSnbr3zQ zl`=mwZ!0uAo^a()krS~l>j)Bn3uu6t0wLZ2(v%Dm zrkoM8fHa`Nqp3@XEP#!Y!IP<*hyj2N(BSdZHAFd}SIHo8$_=p&=ml0koVtKG+{#s{ zI)3T~q6?q_tVT>-MHB-{l&TY^ZXuQcCBW)OQ;)D5nFB)i0 z$HcGmYn-c=nZ6Kjdg1Xmg)e}>3yI$pHvqB3hi4R00A9rSGl~*&-GE>sqErD3@Fyme zDpCN#N^bE`J7Oz980dz8S`yy@a+TZ?pf1FDKrYbj5!8a14RBI&djfSJ4g#EjZjYhX z#0tQ$l3OCwowx}Y29h5_FA`G$`by+@s6DX8x17my8V~UzE4RD}ng$@sv!=_LyrhW`y;#%bO$ulyi2SU!awacm0z`XOTX~aw z8V6B_wNK6@k0wD3X6=(VDWn}Eva@Q+5uVfdh*qqc@&q)Eji|^WNz`YZl#9uuNfN_ZC*@-b zX~&7&tmblz=QMtzEvvaa15INmYO*%UF<#Qdi4fLCc}4+^g(%Gmmt(x32@?<9ygVbH z#!WP5J#>_LG-)E7l_@WF`7GK`8`FV$FY_|fPZjeKCG#@D@5J{nmj-yPZO|paQ8{wAUiyh* zd{8;^w+j4DVgyl+a<^Xi31S>jj`Fwi{WvkYs3Eyqd47_ZP}Gq8twO)!7*3R)+~{*Z zevCCrPkt2b$Bt1)UFHk4_@et=8T0+p7*C+p7s>A;m}OL$jF{CI`R@jp)l0^_%h%36 z@{{|nfN@8LDUPQ4g=0*STMDDeeh^G7a!YYE-4BjAj^t7>LN4CMTtspy8l@~kG4jYX z1*4=zKa3YLP0=WAF#^Mnv^h*Vv*?YnN7^VFr7nhGbdbFYM#+l-m|$eDqEY%{42B)4 zp-_ul^u$;pH56-879U{LkR=MWNsIR}{>T!=+O)+ej5sn#p%%4x7vqWyQmjo~48s^B zR}^ZK7lSa-$Q8xf^u;&~3sOoU3b}X(a|J1-7?rXJ!vK*53Q!Ab#Yl`W z(nBE%wdjL!LV74hr7nhI^pO(^QOS#em~iBTVpRHKEQT9trm%}#^upL8%@lW27K1UG z$OeVoq(y%W1lgdto36UW7zRM=Ys}e22e0>%s z`l}`_>wJAzOw3o0wXpMP9&Wy^hqU%g{;3p(boWgE3FJavoIx5W*&yv_WM@(gfEq}v znWSo^Af)R|TEv|h3#723M@j^2MiH5-;E@z@Z^j3itLTvy5ji7>bW-p@Mfl7(Ae|IF zQX@iVbdkdf9?21bGoi>~MUV7|*cncwzQP1D!fVDFsjqk#nFr6PBdZjoEDr8a>d5q$gHG8&wW`=}HmodxSR-So-N|!au**2J&McK-jWo#?V zWT9+j&9b-8&J3XXWX!U*PtTO2`ee;=w@qf&QJOLhPq*b}l2Mwn4bQf2 zTXrT9B`q8GY+Gxl9aSh3m$|JnQ-ms%jmz0KoLNADW#Tfn6=!l$VA;6rZQYq+)TB&Y z*0%ag6>3s8E_d5>hK@3qIe5A)Ka-9!mpyp)ujmxjD07gxtu}*0HOe03Y#Yx|QE-`q zjBVgdAqp;gkiD%xGl^o#9As^4&NQN!vIn`_=9zaCNR~?SFVNm>nJSj=rcC_w52;33hYl$gYZ0- z=`Au^mZ$mhT4Z6CCVYhoGOU(zna>quEiDrcmlL4h%BWbXX1;tYd(YA+^NFR9tjjZR zt;|--92u8PZE*aj6nc0?(vM$-)x|xHPLozOh3C}YtEQe%W za=lG6H!byKMxJ`hXQo=}$&Nhp*2(O#tdtqa^j7F_RB+8okrTDXb9PiJjAf+Ajud#a zWR@uyXQs%D+T!^;dKLIVN}1Q>MxJ;(WsZZwfFqB+Z8PgZTS_B|-r&rA&=%0};oP~* z#~>~x!}z)DnIsSw&=4^P%6tP#Q!-4LbIzOvr2!2e&0WgO0@)}TKAF3jIRLT&8a|%8 zmRSz!RWeMRbIV)@^#W@i&Rxh%25BhO#LwNx>;h>3YY=l+GmAkbN;L^{w=$PNCBT|T zbC)yoKtW11Pv#sm$3Q{An#XfCnRTEQrJBS!kIX&L3NZ5F-1*Ezkd#tn{G458J4gx` ziI}s@ECLlMMJCL-WG;XTfRT^pEHZOJ9!il<<{UDIK_0-!$8*-1RiFu_$izAKOgd-+ zxbtxCVrDwXOlc>6&OWmbWCq+p%vojPKn+Se33INQR8RwO=h57i%tBC{($14Pr_4!E z9B}9HoNZ<$Las6BH9WRw+{0**tV@s-Becpytf3zi4zP@ndXg`akv|Q}-4c`7MmeTUE=nd9>pk<+4Y*Y)H z`o2%OPqj~_Pfb%-qOk%T*O^~0sBScR*fI88j}}>1wvhwyL%&YY@-@XGf##j=lmjVQ%s%Lp&3H@&9`= zx1;gefzO&|7W@UHYYwc$)ZY0^{Z-;WXA@nGZU^&gnz`^AM%O%8gZW@5_b>HViT{*M zIDKura3HvbdkTNTP@4nGGTC{I~J#bjVWx}%=#dBaqrs|H9X{H6XX@t?Da&PKLU9<0W^wKM#e`m4l$ z%qBV-Z4N@$a9Qwt#?l-Z$TZp+{!9I%5-Sfs)*UZe;Sw`DTm#;oBCd09b(*9^XKW^N z=Xt(ZeRG*xTCeNVY?YK@*nS3oTMGF;Wid3HX`1(C{5gu0*i-o{e$_a&;LN@BcWr5+ zhOmv6cb8MeOz&)${&p18588GQp50jYQ=K&@&R3a(?#nC z6TNA^u-|9F3?5;+ZJH17_gOQ8$CzZe&%{6CJKX0VFar1a2Moe}{sH4~pMSsr+~*%K z2KV^~48wi?pFnTSE~oD~oH;vHz*)U;e5LhawBeKoXZ7&$m7a&u##3guA$tFa!wdca zTDKwp0K?mme}L|7$UngJHsl|ma~tvxFuo1>2k761{GUK&+HDOzf+>vD7MZHoapD8I z-ku)o88C$|to*Q?7$0%ZR=DVzIhZ+Gu<~T|%gvlm4xjqfOI_<}LQ=EZjXrk|Uv1&J zFJ8=^@KK2Q^v7IPyIOm(MN>z9=ItwjiZX<)GY_$LtU<2H>BM%@5iswR+OZgmhd2OD z@aX@Bq%T)| zs~(FvbTfbHe`_K_bKuxkJryH(ydmi*xb-2Uz%ux$3O4t!+Re( zNPoL@H2zqO0MDz3JSQ(H%UnLn%63i>g2~jk>&W{sXMJ-`Ni~u`n}E7Hap~VQYc~3N z$N$|a_T~fWZ1NRFx?RVAFPfZF|Ysn^-8?+I9S2iVs?# z)_?K;T7h_xG#(PKr@;k|E68bpmV|7Ad<*n{J90rjVV#$>gPe|Oftq<5NNb_fMS8Dr z{H6b`$x+YhBU)|`MKsQF2+Jg}^N>y=r;oKj|I+`~L@t4ym-GZVeW3*^>sigC<%Sf| zxWpm+m;NtJcs;8DT5jTNAkiD_+t&Cb~YOgrjgMk?MQj1mS`Y$f=rpA)O zer4CVuh6)0Eoisy*T7`{LBaZh1_cG0VaAo>!w<-t`B?$Dfr;N}Z&HAX2pbi5Wub38 z#>|YuG3J_eFcFcNTKBjC@KX%At(G-iIxuM*NJUFEib3^^oCGg!KBp(-#Tt zJc==K(#Nm9&T23F>ZL0#ne%3)(7dX2bYw}&w|?u_+_pm^6>7ij@slbQ((a}O#3<1( zsaFmg&z5n33z6dEB9w4&xP|PRxglS+=BE#nBm9c$O#WQYSX$-bf;&Upefd7W+xu$~ zMC#B$TsT=U{8nde^Z~i`%HwI6-mhEmK>mf3d?<+7pRHm`i#hSSaTw0Nwz$ldNOrwB zyV-Ldt{_%1X6^^^zG(MLIsl0+i5cm;{AT5RV|kyxY>d#*ZZsy89D%v>EBxv`i+VSE z_!JrU;mMQDpvE7tcgf%)8=)RO9bS*Joao^b7U_bo;Z zOL6}2$Xop&bJIocgpp#8E8cj`+Wl8!3rgTv)fMlGU~PfV2ERBac)9Fki^l^XKeOpu zX{Ckc;rEuuU`366K5DxNiwd&76`BP7O~p zUUqB?-C3D^UFlvWtLhJ1m%H{WAIPU3`Ib**%%|x7M22qgYR5;U>cRS-0SA}!;|G`K z4tfV1>`ZgxCwmRV)84gnT^Xfvcmt;}J!Q!(?SE|Q6nD32U)0||SrH8;R)rpr1G&hO zLr+$c!gkzlz8%o$j65LMZ#JI~x8-=baM8}!O*fx^P-Vge-k{WZr@h=S=3ef;-|3f> z0ujaNL=1cd)*j}%MEsRR6W-rT?znw=@3|D4aKrWC@T&6I11G!Q{N^QCbm*C!)ZNGV z4t7t+dui21PZxf=rod!dTan|CF*d%DxQ~Ap@Pgiy_OMkJP3}6+m_@GG)pwO{A|IC+ zn(Uvo=vE^Vx$qZNEYYY_F3xv;mks<521X4`mpvbYu+=S!c?zAO_j-ZGX*0IMXs2JcFxVwQkzX z?`*kw$AD6YP=EvP`n`_&6b3mnT@_hAXsC}b!+^kvcR^^J&4;|G49%PulT z!WPak9*HQ}?wLHhi5nH#+&#ybX0>XHT^T;DzPG{?Z$PP5Dmj~~3|%BbwJ-Sbpk>Etz`TjYdB>hV~Ao>3mNXaLz& znwYHQ@l?9=<=Qmn!FoU2FwZ@?Cl1C-`Ti6`bA&wo;y%;0I<@&QZ|SN3Gt#qVKJck4 zl2YH)9%q$tWmP7}Wa!JSJkwMwy7oXD@#V0VARO=wHZ8%ZtnzbGrDRxjl%p|3TT&s= zX}iCVtL64Wo1}D@!w39fty7oo?pEu33oj1H-G1;&b!zoCw%Bn*W6k27SXf#J@{2o< za6_+YL5vqZtI}$Q`0ZQv9TJMwD-R$pWt+C0_N%}U!HQ zoA0!n{%lzeYy>fUYy2bh^}lMDxqmUm zrh`J_MZbi;1kRpal3pk1(HSxWFI2~#EU+YMlZs}qg)8~gtr38CRqtd6ZpTD?V#fvu z7jW0bY=TwBPQo%&!YJ1V^cs+P3$F&I3%D}%jzT>PrZ3fvlr^yW9De$E0s4G& zt?|ElO5&Qq+?j#!!yDa^6TjeGs~5l56GYFJ;vZGg$S=c|Wn;|`SM-hsp^~33md8c! z4Bl2&I%%lY8#}oC=XCZm3%DbOJE~UwOQ2K8>xrpzn;nmqvjX^YEel=YCAx;>VbAlU zhdU*NgB^*@YWA!FbuGDAW=_`+v6tG1)(~Z?qG8jG9Ini^*ZRyE(Si$44^8U~d!)%P z`mO5d;l<8{tS-IQW=49}B>^$NyDm=}c2E2{byE)(`KERvs7?P(P(h$@czH?0C0<#u zly_~B@|a?S@H zG`*zMZBMXra7E2T-g*0rU4G|XY9i??S7OGRh%0wP9l>7m`jcW+gfE@*uDiu5wi|D?dbD=Z53RFTG2F_qp%Y^$4$g zf0s02qHUl2FPpw`Us_V^V~?K7Ksb;jzXNgQTQj^lQnFYOiM_zx1HDmc6(d?vr7b$d z9EvYn?i`vv_wZZ6{YRfCt_xp3th4q3W=!fiQF)APb5{xMGmCod1x!d=+ir`Bd1JCW zbkX$I$ZKF=u%@;=CVM$w_{LV_Vp>S9LuCy(O{tcnGc3}lpBe(@u2%ZhaIobn`5_<} z45yEWk6s*Uph$1BKn8zkQC@z094PE`&56NK7|<^cz_5%2y)J!Z@wG%Ocd01aNZhCH zt8n(8kjVr}@zYqrH9}QUdoJERYQi5U5td%vG&cD>$*wYaEFYpEgt}kIVO>$a%m&t$ zWpfah*hme?tt>Vke|%si^h0&EWy8a#u3K0Kt#|5i!y~?qG4a{7hESip$;FU(izE9V z70w;~=5FW_)!$VHX2HcLy z#P^t%I~N~j@A7e1+|xg8tvV*yfV@Mt%isA10{GOee=#2w51Y?B71!Ix747-Qp4T?u z(w({n-OeaR)N7vk)YP>E(*&=qnlIz(zGebd$`CK$VRq}b%B~q=c~L>|q)17I-pFT< z5Jd_+HlWmP@gXpc;lBMvTb^@J{-@L#kr@P!j3e~2)AEA z9EQWQq{47LzgAzZ2{#yYgOCzbwe!Oxez^?26&_#7)|51SGup;vN@fFw!@1 z*W_Tq<5tbb0H>XPb3a_j{F{NbrE69v5644{XXl%MVDXDO?#g4v;y0uqX&Xoi))dHp*tpsq>y$xTOSaglDrwd$@0 z36c1ll{LV6l#pd-m~TyC>U_D)J+YWDgYC9+Qezrx^Ptzv>)gi=TkqYi=xkA~Ta9QSlR5k(rCyXN z2j;rYbS(OvHN1iN78dO@n;b(m211>x@OV_>0*i|_R~FCo zN9Kpp6W2y!qoICx!T0KVA*vqXV?@PYcAGr924|Lw0%E@R$3bti$J{OuU7OO~^E@}U zjZv~X+5;3Se6qaq>z=+b-^H?e-Ht6Tpd@>Lp3ueYWmRzPmhQK%`irsbonfm!L%Bk$ zm+lk_zg_O^d@Zu}#w!$3>@FYkZ28Zpr@3#o)-qy}b?8{*AyoGAQ2E7zmQmw&7u@hf zMphwm%VEKI9jzXCI3?!I-Gkekpgm#+jdxGFmH_Cl#{Y0C08E#=(v30T;Oa_n^r)~- z8qdUTeG=5lwQgkM1?^G~jNPn?UCSma-)raCI({=u+hs4T`zF;J6DyQ2@+Wrwfr?9U zCe|SrtH|8>J%rzd24`nE4|9qWaT_d*Yl;t)W5opustg?l>sG%&8n+#e2^VZF>wm%m zO@g3G7Pv&)JvC3|us!q>eg*JIns?S>RV?1}ORU{qW$qs1lT-bmfc1;UM)bnZ8vFQp z>MbAV6~e|Bh{uBaG|y~x%e^0YV`{2T9suC$4VJs&i8Os&+S^80ck+Fx$5V~3SD_}C zW`Bm)<6&4Ua_GU(jfv2eXLo)D7IEp=*xlRRe2G09DBQ3c_PZvQ$immg~f9B>)7a4}~*#rj`y)`UWQ3}5fAo_k*f8T5`?;*;Id zealg%QNq3_=Q8*tGzspop1^SO5qtxx9}QHi0u?sC%{dI`>8g8I-8WU21R~)zc*2`? z$DzLX!h>s0>ujaMe9tMacjc;~azxUpw{q-IPvPHmKlhtM$I+!hAx_yOAUqvjR=t zGA6C%ep|wXTet8RNNgMP|GGQUo)pI&dV2HpS?!~vDy>)U$tGn$9jKS>kQLIL36WEe z@#oY|F}JTxJEpku#OqF*6oHyYm!v`;Q0wsD?;ne&Ik3wZTWj{?m*T8%_S{?*Ld@-SRthQfZ#B>i?dTPr=7W&%ty3)fC4a6}wUp*2J6D^p z&v5Mo($gfE4$OBif9AiIz+VGAhKv=HD4%0GWcPxbuiQ-ZPT6{iIBNe!&{m}*&Dbjg z=4zsl|5MJXUN}T>OsVmX+RvzQH76Wr4ROB~E+YlJa;s$CrXZu+_o%MC=rD%!-je2g zltJtP_Oq~F%Gu)`VV@$R2di_^H9Axlrp8KE(%N7H+hgAN`uPVZM<)8WP_z!=v@cG^ zTh^e7gHNBgPX(B|>C;_AP&KY>=?D%!-CVfcQ{7x+9PRT<&B*n`gkq6TqES0gV_Yo~ z=8^S=sUW^2YB`?06g=7M(pk6nX>2LYHuS@%TBocykI??Ir_7?9wiTu-&b8Ix)@4nD zarc{vHZB{xr6TQ53$fZ-vne|-qC5uQ*WR->FKJiTcN4y9qe3aR+kR>JcD(Szx6TL8 z?Rv{3mJuoM_mE%IU&rGK;LuGI^3wC~H#cgPX6N#0wP~4qZrY!{oo^Tm1uhwmjL)To zKz~-MjcrF>-Ym+b21*7mbs^~P;xz)aZ!LYfUj>Oz3~osi)FUimH@5_It2gKICFk$) zpM>eSOND9c7S<)NuG9qH`rw26$#_yqzaMo$7V(_1ell|T^OdMI&7FF1%KT|dt$_*M z<6CkKv0JL!Cf!~)`)%2oBY4V&Eq=m(ou~X&?S&QCa6V=HVe5sS-+T4$pUy5X4-Ptc zT-v;Z9mgY278(boRJwgo^nG<<{)=k%z{?wke=?#L-j)w%AHUF9Lyo-S#9;-fF|eEL zF?GE-|CH{KR5czOr}OD}wpBY%_OgcV)9mFaq}IKh%&%JaByx9ZuHo+0e3I(?V#U!t z^gCP>m$LLlUr9bqo#k#TJx=kxcZ_Kkz+`w;p}>F7dU>ghP=ZoxPt6mme$be1MVR*l z739hryDE;1ytEFh^lrYN`0-_{H1Q6W2#?viuF<{AaDFbC((U#7i^g2~nkq?rWtOm3 zYoFq^?)qu7FQMqqNIw=^{fTK^qhYm!6>@YNM7Y*m68{q_i07=>PwKYR{PcX-<=%p1 zk58{ysLI(D7ZbI_m|O3^Tu?LS6`p%+?FuuBCV#UvPa8HBZ5OCph!?Q0`t;HDOeniR z@yX=Dmle(r_Dcw5YqPEH!O`;%rE`M#Oyf__o&ELA_WP14uy<(sm8LHzJ@hAezzpY{ z4dED(`}4XM>%eK;;G|`B%Ns_P77U7v7}e;*NOW{y96B+&Rzm6{?wg|$BkmRX;I&1c zvwsxR!`z0c+z+N<0}WS{O|I7Jz9}wS3@s9AADYk|_wRl)A3Elm(syNw*McpY|2JRO zu>P9epCp9FJT1i>*S?T{yuB58w_eQBK3Cw_A5@J}Q!379aP@=4Br6Y31=(=XJGQ>O z`P|JB`>#nc?=qhW)?`iQym)8(C-4Of#Z%{THNjb!zx>vV`H6i=MOn3jVTS?c1G%8z z!7je~*4$9WO19^GMFgs@F|*p~2ha61?)!=7&+{dlm60cx*0cjQPl0S7-thd95OX~b zp-<)L{xlOkuUuJBf4@>MU_v{Yuyc~-{@cTGMizQl_>;1GX0zpP{x8D^-PB|3eHm@O zWgEYg;ipTYn2QvBi+4rddu^_!imL4w4)_K{-&y=?5cj?*Sncs0!wlzpN<{0k?-V-$ z1HUiXXr)=JiM6_W0>xW5pZorPripjGj!~gkFT{NKDToI$*QP#(7gXHAOtU3Zy-9*G zB`UAJ_)|*6F<;D*E$%Ix4IJEie5=Fx12XT{N*zQr$mKV6SMRD0SoY}xoru4v+bB#B zaiff0IH@tDa$+>O_xh%B&(Mum*`}@b)4z1q`#nY@Uj6h*y#LDCcRFkE>ipp`4lK^T zfgikzAFTB*Ub9&Xy}SO&0&8Cx@9taqYOE{jjKP9`wSd9GimQ#EhVzPm=lp^6a7#(U zRnK0@Yumr4U)A?S%Lyz95mp3ep?4V`WS&HKlXtM@TFq58BdVlG7KO$5twmsV2EQ(`ujC zV_?DgT-P6eDrHs<-annLx`w*w0{JzNl)oEP!=JP_b2H@Qil2$dyy-P#+`^p;N$EdG zMJ|a&x6T_oCoTEJT}|>&OlhRHP3jvoEnS`~3g2AqsxBFOx)tQq;KUb+bDlZJ0j4Tk69XGgR?2L|orvPQ{s`SX&` zXsCWM{#GgB>zB6TP7M{aEUO-8j*bf7KQ7iICx<&yFD%crb9aP>9;MH_#hfmEud$J^ zr|UFX7!`SagJ7RlRD8!HHvO!;WtiWv*GF0){!DEN^hWtcgoonU-leVC4;`TTbIQBp z8Z8fWdYu>}@9k_3IYk!<)8&u4Dp!7Lv^2Yjud$CiJI>xz- zR%98w={&NmL~(^@b4fw`ll>2tiQ@MIYC83`-bU9N3$%;hFE6Rg!ZI2uQh9wdol#CZ zqAuW9u=16gjSEg(8L#44>lq(hr9*JP9_Ji@>>~!j9D9J6Q))-7NvOHFXBmbj%5xs9 z2Rua;JI1(b$E%0O-RRZ|jKwDpL!8B@FiS(Z@T-1?a?AQjv;bf`ej#7%>s_YR+Sm)S zgX~zZLCO7(?~>p>S2gB6LN1K6@K5N!_gr-8Gl2ZMqi5D)|^h57Z}Y#s0qkQRj2-&oc_Tte$EF zE7tyKwkQ`~+>ITwbKFexevZ3@*NB@^IrQz^CMR)ATnbA^ZyfQN53dsFN|UJZyQ*O@ zl>Gj!JC{oxz@6J=DTh7!lhs42YHu;?8QYEJimU(#+WgY#`9AvmtF^8tg!9D{g$4T$ zUO)8PS&OVtYBI7=`#Hak7sM_Fh4vtJCl&WqUnwod#frsB=SFrs^+?xbcGX543|Qd@ z8AXy#Ba<4?#`lN^RePsv93ykwilcMfvIa9CbuYs`j;nfi3Pbz+W%O+f%YLfMutx=z zNp;_El{}s_m=q^GIL4_X@YcZu+>yPtwsUp#DtY+Rbc3TQy~6vmp*Y*&DJa$TohhqO z)zyRbt#=);qroZdk{($<`!=GJV?Lu|M4b;G6!O`l=|B7z5W@~>Ug4&0_Ph`D6OF7U z290!vuUyN?4%AyK!_7n&zT*)#oP|7HGmr{?{}lx1F_w2LN%~Q|wD}3Nyhe$#w9CaL z{$$~bMpoj9}xKSLPKr;{x>Ju;Y@7L^2q;PWOQIe$ioyC*(`6;P4&6Z&%0FUJ26J{4CUEDj-jE1-dL>&qd-S z`u2J3A~H*hXXm_J-M@1C+usCFb@&46J1opE`VEKr@|KV!6&vf`Ij=auD(o+FY1PLj zn6q}cYv1=N#dkrX?=NH>R2E58rNHA7k|Mz_vs8}vSKc*m_*FJho|f5%?vEE(&bwQEKyLXoJp8iQ;h(>7LFb*Hvw|f~=k!-G5lUMMg zNMYF5vgL^Qhq+=U0cG!zVAe|H-cqF*FS?l^762`tnn&i>2oKnm}Qj|f^Qb~Yzp%eVHvpYd^a8dTM;_cVY@XpM;hLmtC-%k-3HyP`*XPe^A#Z9aAGJ5 zU9QCbJ1o=)7K_u!H(M>qgt|;Bg2xfRs|-Tv)fj39j_wZMR3z41tU9=LnCQ86uh{g` zfOX}YOjOtL;bDmvPGE7(P06**k|k=vvjwGy694JQk3t*2-{qrT`NUZ-gk>-5dfclh zIxYR$=7$HrV0EKrbgkfN)Ch#$q$?Jr1O%i>RisPrHPS*40-=NeQGo!VNhh@2 z{Nmoe?uYMPLPJ@u;Yh+n zS3X6QfU;NU$uc!%X?Sc{x500^9_Zs#h#6n*XeeBmz{TdTj4U=ZSU4pRtdeZFN8ftJ z6nNqbDu|Lx0Y)h?W1gSobj%?Ino%q15*|)fy`&r109=|~JHppy^JxxV%ATaP6h8!R z&@!moIDDjMN=_YBv7VO38xx9n?r4TDI99pQ|LHxIUs%*Ee7q0q-0L}FT+11TH-@_V z^|Ko)u;lGMCgewy|5O=F)8O)G+lkdNVr@TJ^1(mPXPSfK@o0ax0cBG1psxD#zS6R3 z)h_Gs=6Z99H?FUDN3rgwV| zvv=&$$1u%R2M0otuwUah{KlDehRHw0$_~~Yo0bqqBw`J4E97Fu%dlg1%8BD7?{*K_ zJ(BxGH!>AEu*E6qJJ~~N7=ZPS{md1{0(* za`)1Qur`y}8#RWT*q>G<*sy8tb{+!-dnudAj)kVhwtB;@(mk=F*((=s1iasSfDiV@ zsZ?>qOACQL`5A3#;G{ahauQ(-S zb$ZE2cIl~@J6UB4ZD=UotI)o2&pbZEaLdh8)_`H+!^dwjqq9jD6|!H=EQRsRn!^$1 zSdZytBP`cA!l2&foSu^o_Mo=(%Ibj;rP-B3fi7pq>ry;uAr3M_92|yAKpYSFTcf`| z?FHX7syqir+}y`)FzcAyw07RT%pu;k^vY~#Fe~7XmTC4Rdr7y7#9trSRDAA!bY!jY zaBe~m@6jp1KY>?H@86&BLweGKjlk}b2NPAP9>z!W?;FASZBtz83Rc|eM1+GDBzF#~ ziD%CdMcA`#B;WxL*S<_7W$_Gq>!pDoE}`(Pcl3WAZ|wM;<=+ug?5ADa-5KJq$C~icJ(= zk`$UT-`1R8oc67dQ$F=Dz~i0M>stMdZ}^W7UeB3otAOWTYe~8j*nWCu4;BRB5f%d> zJ^b0qBep*i;yR_I5;iAMLTY0GSau+8LDgZc@Up;SHv zzF~*k;?Ch!g7c0#lTp({-U}9Ujz1jl`8>H^=?NJKx^M1zIdS;mANoOJlnx8@djiETikcln&plRQ)a@3({9Ck?t-?*xdipSyZ~uL5#h zXX3jh>}0OLf~@1g32uMTlMGDu`$S9tNIiC>&Cwp%{0fVjsy6^eh_V_4jknwX|}ci|4g zzXfB)IT2{T)mG1RC%Np12a{K2%Z=EE?}K}!MUfi2U>BE_?uJr0`L30Ddw0>pea!f# zMHX`duI<)sYj}6d?(?qg?kV><8b@&_ z)oUoNo;G!}tpOME9Ysr=@T9FMEOXR>aV#|vOkx%(e%gnZqb_#K)*A&m* zqDPZ1*nr+fMf+^GdrXzfDGI%-d2`vVchbMH#;=n_xM*WOy%qxW4Vo{deg5)~@yV0YA; zyO!T>Yg7fxU0&p{ZCLs7(dFgDnIS1XVR&PrkxQfX0`he2AFm4-YhPef>Gq^e>!h0G zkDQm}eWtHwvONg%AZKVi|bx@t#8s zM{NAV##o=+d)Ua7zHDnf6P_I#yAScP&7>U2uB`dSjd>hE-s9!z=su5vQM4_@E*iNcQcfxuRgXgJ}pBPT}q+B?vc>bd&xyE~H8Z14c1%7H; z!!7gVpc-uKUGpphgTKK^87<#VRBsNvC1KEbr8WF`-T8gT&g^}o{x3(RVC5;V37Jjn z&$gP@M~9uvL#p7~88%{7GbhV}_B8ujCbw1F#&Td;{u!5<$4m6fWbyUkBVnaHU#t$4 zU?LhNe`FhaIZ}W4%Eie^%ScgjB>ORY6mRTsTGZ4!hpcL)-!qkZsg#e;bXoMc zA_mho9tqIRW_^LT`j_@7zjKM*42HL|AuA?2u`J_dcC(4OT;|@C@Mkf+{NWH+9~-;Z zB5A42k?n(FN?uN51r0aPw8t@F-j2*{bHOJMy1LZXXM?n4q#V*%>gHP=HIW*chz}R> zUKV?Lmh_s7PwW=Ig>Y#ixnxQ*a!V`)Jmn=kf3|97p*2%R=gUW@%lR}M)LqA-vnu&y z9PaDkqmwH?=Q`ZiG#j~BGD|f-?r2FxxvVy=iJf`u&N!WepXY`{M8(qs523%u7`Evs8{a0VxC8X)m~8wnq7 zUaKsit2`uq!F@RM41V*(NS@W{N`D}xgH0GuK8be8rdz)-JB`2H?8=I#TyM*RrnDd=2Ja~9TJUTigm;A zC6j!S6dq&D<)1@M)A~h&sgoiG@fvTs%dDguTD82~-ymcxs};Gz%lxWdKLZ;tEv|x+ zqD;04lL`v+zreD?y0y^Z%35iEPS+}aE9JaG){x8@CI9djxDsvFdV%;4*vu)8G;w(4 zvrVySyI*4n86DHFMuA$^!Xgzo&tP8#?eVh$d5q7nLz|aH)HlVnx$23xJT?!XUXI-Q ziO4JfW9&I~eYN%#)h1bumq*%1^;XW=JB7sz9n1^{7!u-2C2l8!IjX@g3m+J4r)jAk z^XMDU_3HCsoC@&Y1qV3gDdpUvi14@#xmxZbvqh=>2fM*ci4dD#<3Y;^lM>8Y6@0t&aW!DwDgH+&)`F+eMukY9I@a-GsxQ>43IvAbgN$SczO zW4Yp^DMvnZ!1nWO^oMYdk?#w>L$dLkw(AA=3qjWF;VMnJDDGUWUx8$(yl#sEGK2q^ z|F&O&0i)>Cgy_S2*|Rh4vERnr?%AO$9UnJ>_3sYN=GUs=Sg$mUU4kuKYTGp9!zSD4 z#AsHXfbl#Gn{uqqzyAgFvIuEsnP3{=alguaW!hd}_KQtM%RuF_-PzqfvQh63^8IY6 z1igYHc~_^xx!%>uj=lB@dDqtT?$%79C!bXx>_92MK=vV|PU67UIF zenwt7Z=>W(-jt^P#8127r`^viCSPH5CKVJGq8umEu}pvHfs~l8G#Y@E6mP{=GWjWL zM^;A$zwA84W32n@9A&jv3Axg1QEE-D=eJPnF3^3V)e%koiC&lDQg9rvd+So8a0||$ ztA0r4VWN7sh0MF_v!G{#3b0*DiLuPdAMll=y#SfMsg=^L^?<#Qx49PMf^APYTLZ^(C*S2>vaK;bh2=EU7b~|f zxzu}WHKvw7z{c)@5qtLw0oj7mSf8(Dhqrq+_8h#u#*Z;@XF`o;H#PQE2VCn|5|+Yl z#p_p>$1huF49Xa6e?nv~O4Z8x+CIJ!sm}dnrK_ZaT3l}kci@1oU8=~0yzvl`+>D*z zknq@kT_9&IoH-$>L9JUxTRwI5lgr^C9cSmN;7obUQhxI183Vpw#TmQxm2r-4*@ON1 z83?bgCZBZED6#U48Z|ObE8Fd3;gdkLRaVwh3ogCiNB)&|UYu9<}Dj z!_NY#2zRMV=y?|SoR!{oTwx;?KFD^S?kJ~5?Pq#HBFK^cjuRr40l zL}>9J_}AFwKa^aEq-gaWp%n9LNy=zVYJq68j2C=UCzQq1&ev`>?&|{hu5zG^ia8n|)Q-+? z+LF!7id9etUxd4GhoNq9S`~sDFU!h)@E%{rT75las)Z}35hk>t{czX+E$dgb1^ zMzh6QwQ-&wNaI?HMTqC!FUuSF5;yoovy^)`%_G*PAz3BWig5sue+#eKEgX2A@AfCt z*r!z{^mb{sk`J@Lb&d3h96IiX!47r5y0666gJln4Tamjjs}3xtXR?LFVNP|2WO(VF z4G%6;la=a2&$~~>0>U2pHP)_X;vCOBv%B638(t+ZR;umKjI6b&T~SgOI5*-u1f8qr z{xyQT6AG7oT`hSjux8#{{z9sdmso%3A*gZE>wtdkG=t*nkKouskw!)5gM85-#!g9h zahFYoKw|3hW3{q^K?H|-#Z_+GTAY&Vx!z~uHxBwgEMNEYu=icUD_mi*TV5;ypMw?E z9X8z0jZ5>(v{>8BS_t&Hy6sZql2({k?dRdtg1c;>R-DUZ+(^7*xK{tv_^6Vy6F-Q#!yTyhUIl^!k!_mc~#j{u;~(o5 zuwc@2%~+Xh>KjohA*5}{61p@Vr8ub%IL?-6ZdC8^V5&adaW}Q}YxuFdkg;wmI`NuJ z+B(B$w8$~(}mb+^*#$!^S z;<`tIP(=p^pD44t0Xs&&2t$W;d=!o`it_#Q^Fl;>BsK;zY!1hY3{8ZBd0MfU?a`dw}B$%vfIo7F73ee`}FZFr-) zSftvSs;o8{*vk2zABrAXbcwpN>m1{-7G;S`^08uLzqQpHgkE_4O+Nt1-@M~P{X7ba zF=TP~IO<}0<8_DAX4_m6D;0c|`W2rYnEu|cfYr_U>pWdKrowBl{LLJkJOx%J_3es%J(uXyg1Oi4>MRcgcP9OclV3J(a_MaO?(plo)jNT{J{HLz z_1*GJeN5U_KaQFC`}DfhNC`0ftTxaj8}Dt7XEHTQ{mADvQ?_;-N`=_HlylnYZ*fWF z%H~IZkS`|IPU*IzlAI?qlY(dIyYSA+RuTE{d<5B$vtZA$ubonk!{n&lVO7#Xr|ItL z0M^5M%ju}-ItC?rvT5Sf8;6_=lbSihTu<)S)eo#wV+G$&`UUsTZ5^)eu{|_&V-oNV z*eE{(mFFhvf9k80da=NnChx=NRiiW&kgA!Vdh-RSVQ|Xtne;_E#PQ6~L6>>RhQlkp z#sa#9fzaa*eytzFI84@_o#-L|!q>;wwEq~Jz8m0E(OFS?d}%y&BjutPoMJy4acPG! zLfuZKxGB4(q5eAZ6FqBf(yDAPd3?yj=SaSFN6baOGm;xOyOXsG#G6lf$o{1MusY;q zf$j;pHxR|ltf;y!)%Peo5-H596 z7U8Pz@&H-n|Y-g)&RlOe)E8;?^oQA^w?*WCiy3ldC=a)AyJEFQbPbEBO0 zTPE80-QfLH#1*fG>l^bE4+iQya`hf*2=d(hK=BF?%qb3RDDJ)@Qrr5&fk8zS+_TG-+ zOJ9h`@3S6u$6zk^eR4jLB~p-lwn(nf!qyl!8nwH7<0fd-GQw>)4&tAnhgwU-vO$C= zJ`NVOn#@g?c{rZyCx>pxn})D;EXez-Aytrq)9-4%`&0vJtDlNXZ{yC z@w4|c3SORm`>if0L&{w?URJC})9mHPsj<#CZJoJ#&i;DNHPLxfo=F^!M~)C#0{xeEVSXC0|9OHbavqyY-3 zot?Hmd$#xPHsi;=*WYFphU+{gYI{oZE4xrGKQPH&AEcUEnLjUwo0p4A4*9tc zQ#N4!eXAPodU(^N_s4t8vt=UN40m)~?F97w--G&U|~PkSQ8C8m&4l zTUa7YNK0|QG+@GWiKA6wdmA6oEyL9pHSg=qRLEWRG(TJSO6JQIM5|%_<^4ArHhn#1 z6TAyDkrJ3IUYNlb5Y3dB;~KBxbuWv`7BntY^0a-& z)?d0yPmsQPHw~Krojc7mLC@uHkyg<8@^1gH)YykZcSYQAZaW&2gX^py2hFu~)TMg# z@_MbJnkYw`Zd+^I61eWYyFcEw)@v=*Ilwg)%d090ZmF*}OT0bb@^IJO zm4_;eib{JG(Y0s3|CZ#4b>XQ`jhv2h8|KqWcYBIuzN01@%ZnQij#Q$Ia*k)l{6q-I zdvITNJ6PmbB|B}q8qVL87H&R4uURyd{Z&Tl=XdA%_f_?8BE+lSgb%n1dv3vI&peW@ z7Evv2dFjWWcL@|9zw^}ro*ys2EvP`R|LIF-6__z1|7J{>z^fQP*Sqk#8QmCV+@~p0 z9AT*8{cL8U%M*-NH&5JW#bXPu8&8vnbETh+%fYkHZ^<3jSLa^3u*CwsS;|^P5D90fX4>bevzM{ zJ{723!1C>N-QQvhe2{bRo$Rb6PXYG5J)h`^nrV%JT~|ePyuI}s=vW8qs$r6vv*&JJ zMwfm~Q+L;(f$AoEerKa=^gJo2rrWOej6g~;p+H4jYWGTH#ujdtxe*VcXF2RDA8pe+ zm2Hg?V9D#jZBak%B0g`9%)a+fmDOx{rv1F8`p2_^53j#J5E#_07GT#bXoXj@yk3g2 zEgAapdQjZoMmW*|n!;Y^9Py*P9yV$K$1`QO4Xa+%6i!g={-xF@GwK|7OG8S-t@74% z)<@jHj^o9^%3Cjz_!C4l=CV$~)mdw7Kj8*i9X~v)ycLqfpD3b1%DN9%yXy!|$L$`e zIe2cfKtH{8>_Y+1J3Q0V%7EMdTN90VrhVM*ikhuA74YmhLVv**=>My! zYs(FMWfR7vVF|gcUOM9Uw)~oR+wcc$9J*~~nHHR}*%l)=av!lw=Z;F~<(0n^N)ch( zCdsqa*{JDP-wi~|Z7@po71~Z`MA$u?&RD!9qC9~^@@P;%O}#`ICT$P5y&Lm*4Tf2V z9deTw^k%aR2iH8!G!WaU5op5tcGe3Hspm&UD-WI-A+qTd6WHSoBjyLWv(NaM&g(f1 z>sr{KumC3?N-sH%^iC9NIVIt`P!6u+sb+_qAbXtT@Y-qQ3^$X^67?Spdcj(##}hBJ zC%-s+nc=*+;Ok+ecvIK9x6)SYYTG(*Hn9P*Zk8&u!kPan-ZQ@*C#hleUMqJ0&qi|M z)||X#BnFyvv0-OXUc#6BOJ0(xFHHmKn3@VrWY>c#My|Kd=HA~}UzZLHIGo2`TRyh2 zQR`>3pgS5MEm7<9D)qw>#5fqS7n|G9$kear7HBT_2VODdqA65GOC-fRf?KYyAHru> z8}b3de^rXPH=)Cel?>r$7{AvP9&$%YN80jJhsOEd1VK;MHVD7k_`S~X5M3!9S>vm& zzQ=n+OC2g_9)IZdKTP#$ z=_bC3hgX|VWMmVHX~Ro<9v0+tijqt}^mwd8wSEk`!76J+`%?G5u<`P=wiA{7@&vC# zLwqB>g`dq<^EM0cnjt^%csZ}Gs;L`sKmT*BS}VD|D+}{dWaZNEt_MM67<}4Y-~WLgsx(KxY+Hg{l%GP&`WDDf-DyLu*~>EWng!C z;6nJ;2>z{3%$Ex81^%c?>Sx+n2hYe0kmdG=(#FmzWCLq=tu@%R!hJlGPWj~LjI(P` z0}r-9$tmOeH_G(z>0Yw_V*FbS!O4p`N`ZCfv*>+gI@b!-nnzrtXG|MbKhKFU{W^Dl z$4K*PRheOoyiZ~DuT4#v2Rt84HOmSIe^u;Dtv%VdWAT3Q>d)qpx|y40oONqZ``y6d zypYtSrPY~xa=UM2*qtUdT1UwgeO z-`u_yvRW~2qjKJmv=&v^tt!E1)X!)1e7kc~NEViSHY;@p({!^S%enGo#DE zFW1PWe-&0qe@QyERIc&i#A?<;QQardHm)?Zd&Ia9HLvLk?NJ z+21U{WEopdjgjy0{m3_tlC#KTOK1Ql@CGOT<$$Z?Uk%^gomMg$t)dX91Kf9qM zx_))sMbc>Ez|mKD;VgOHH(`m(18wv%s(Qvyz_L;CRg~n6IgfPA3yhVs0l%N%x5tT# z^VD~2g$wule3;&U*b*sd3tpYDoBAI7Hv6D}&35k(Rm7P`M|R0>hSpY7yQ}5Lb)9N_ zzSb>$cCQZ<*JIy}TF{hXTB2}c?j3YnCu-vY-94?O2*#3$3wx(9&!O{3bW6y%@^#ia z#g(a7vJ1lENKg6JelL0p$Hr^C>I`yo<%YW(YIzw^y$;!L$ z$S$rM08JAq*$dnj##Mhz)9BM~H@PvLp%54vL;W4honK9}`yU?>4onl3HEyr_>X)mn z|1nfHJdjuV(D?K-!zW5kZx$cQ38Pn!gx2rB(I5F$*k&&tu>6KxReNv{(g~9bIKkU} z?8Fzz(-~9QA6Z7|4=-3(MxO$+rs@hO`jpoTL-J1ToU;+1i@eA9tMe$MkjwJwJoetw zP=vf2DnWNIKvJQ`pygTJdo$k_yBRt(pK+joZM zacaGEa+Yu2e>^|>`bOAC=W`0nm%?;@o_3LVD>SL?C%=T6kEjiA*y?+~lXL1BleI;} zYMqeYMUKV3XgjT%%AVqf2Q?%LbC-o)+GpWD>6j2x9>J{50T5qS#j&`qx0Cs@m97WB z7U#CO*;5`4uUo!PPjn#d~A9-FeW(qn=@Ahvgq@Z)^N< z<7?q@`Z4?0ol&5lQTG2rRW_wrI)u zpN3DYgr2CqJV5;%>axl(&uT9CXOo?g4QmR{Dz2wdo>M62i|A;4-V@lTAlx+c5&i>e zJB*cj(m~R5bkurEUDB+0H5v&kU1bBosQXJ-gG*L}%T`s3`)#Hot#~b`*g(FB#j<|$ zDG3lg;!NS$kg?6%>sw!KR8{J7k?1Lo(q(G=( zBs2sGO+-RpBcZWKC=v-xK|)_5p)p8k7!sO){BO3>w;mhIXQ% zZD?pO8rp(}cB7%~XlNfA^%afkK%-jGs2((`8I9^fqtIv+290V$qdL*3HZ-aijcP%o zy3we1G^!6B_!YfkIW>aYVZ!ZDyB~?$(Hh;+!tL~pJ|S1Nt~rIw5LmiVd~t#5Hz;wB z4n<1#jV=C9C)OVwdf%YP#|3hCLnCL>+SmFl$+IQ<{|x`b$^R3AurJ>K=j;C>1N)R$ z4cGd*tH_AuRk&MsWqbMMu;#98l0kBBahtqg3U!xLE(m5GUe3PoSJ zs)p{6*Akicm~#u5+}>W0#>6|U|GKd^vetKq!274{c{c~L?n^cO^YVXzgCmEGzhKWP zNB23tqyC`K?TCI2{AcJNCjQ$r!F(9@3-*d~b)Vx0>Lf*ZN3=QcpP_%4_;1t1sYCT& zupkP{e*AaTaSGp#Xj9-nL;o=G-=+!3zEn%#KQI4q@IRyj#{H_Vf&aYx!@>WM4utos zngjoN`GU(!?{ zpP;NSuxZI0ymy1`mHUpbV+S=+l$jNuY`tZFQiEt<9qgJHym9^dw!+MGU8?K0T(VyQ zew>WOTY$DHgvc>2kXFr-gI2?KL!bXgM$^SR9QEIqM;~K+2ZjPyUoN}trY!rcNody0 zW-bX(eo7SvMB)#BUi0>Rxv&($h1#VYaDWd2_Z>`DHU*3O?zDs*#=$I5w zx8_a_N92;`&VC1vB*dlf8rm-nvYz_*0`4~l*+~ehIf2KG*s9>h zjoyC+nVo-oM!zi^qCkXZr*g-%FwB_8!9TA}wj;NWUFxHTcoh1l#%yc$k+ z!kD=CnS|dw*?+-pRl)5PdQsY~Q(=7}yi?jOSHaB|J)KNOD!6f?&nMR`rjj+#?~`lB zQ)}ccg)k=Oef#W|b{G?vK9dl!Gw{NCctDbv2)wWqUf7io0YR0)3(*Ow5JLiFOmiY=B{AtHQ5x=8 z3wP{FD03y+_!5cXG9b8P3EZ(W0Y>a8*y<_Zbo0a{m%<%e5?H0(@Ct5n=;W7>?Bzr} zg!mTXH45>v>S;}sTS}CJ@H-R1zQn@tkmMSCY7NMe1-{$}Uv5fBglvyPwk>*^69>0? z8aSzmHWb`=(1_%kl~l4RIynZijfZT*dupWDpDV22Mkgmhn8qMXHa$ho#4EnUE8#Lx z5T*$Tsy$)dnYg{(({jPh3?uK?C!Z`P;6h~fB}Rpl^)d2xeexf~W~X{Aw|Xo&-2yQ3 zj(z(_ECY~`NCG6VBZ1MGc#7Li9Dew;Pd-YFW4b41t0#uj?FvTTx=%hEy0+?+2us2c@LlTdcDGWc6iM-cq$5R_B8=E z+mp7G$RSSDP4@0j^%k=P_a??KCdS_+N=dH|D6H$EP2NC6@eonV9&4HPHHCFo^gch_ ztORb>l+f)$?Az{1gAmt}y=PLr*(?jcCZa|mMK(QD%}V$ZE5d88!p*ASW_=05F2pmw zL}Yl4IQ7R);gdZH1Y(czR*x~K8ylwHp|2h(W;oM>-|msSur8PEJ)25aN1GraD`Suq zo1P(=bwgjGLU_#y_@Pfb!Hw9$?RE^~XVtgQYw6gL80pi4lwL1USl0@#5rZo(i%I?H5!mX1 zLWo((Ka3$e_X=oVfh0asiR%XTI* za=U>relC6ca+Z$WiK5;;OVaBz3hO-KGO-ZYY69MkNIhrv;WfwLjmu(Q(>+pKJyM)* z0vNw;%jKR#r>GflgHFEHPYIs0vg0C~No!dWz_a>%!_sr81<$d{|lUFF@l~fO}aHVaT+p`mQS7*OH_L7UQ zElL;9a8)@dOlOF%O-onH5K@_dX;-K#+}1|wh-7dJ=3p|pujNb%ZaIfpBi>&$C0z;H z<;%dd<^(g4dcd2$L9$^wi~SsoGlCul@jeOZ7#pl8g!CgwwoYB)j<&#sHtz6}^O3r$ z;7vg#4HY^S1tabLOm5yBD{N0rJA<7|Zu==aiBJV;OOMN$n0ehu4s1=htW?IKwl?ag zuGTqhh)PMj-52O*thXsCBuKV12WE|pIqsnt?^BwNaXRlihh|V!GyR&GDwGq0ti7C( z%AdnngXLi)HLH}Ux_>I5&lqCOR???`TU&hDPw#8)-{<GbX_~b+uTz;~r8O%a|N51`;=TGd`#`TgUzVPtzdT-pomn9AA)!Y{sFQ z_O?sz_DNEsO21e*iXD4kLTU)AMd>g-!4giAUVt~Nf_&cTxWAfOIlg%=-X|@c+wMHq z)H76i03q|xOq&T38sX}9TRYM@H}D*m7wL08Ls2kCwGJD6eDgxa+=Y%{x=rc$-M8t7 zUvt_aBp$lWU=@WIIy`Jxo*HcX@y&Y~sjWGIEZ7*N4?~6`I4Aq!<}DTfJKBK=>>%f6 zUy#omojxn90Nv(|jMUy7ty3f!@TO>x55VX&jBZmtV@|s>n{LxDWA0HW>J+Ij{L@Rm zG-hm=38^f|r$ooSdfF|>Cs*CyOj{HZdN#~YNxSG~XheXYj&_lIZXgFXKYW)_#s9u` zk!P+bBS}J~za)xs4!b}N!wX}^g2F##@WR-zNhT!wAfGZFCv)rw-KIhO?wj;U8!Vo4 zQ$wktC9{z)$Lpf9s#c>&ju)qLuvQ~)4$3umg@L4?av+h>D3G&Vi`}N%lv3$$isd;; zS}`F72l=GwtiZ96$2YgZo0dxcUvmPVV6~2KD#h<=DfxHgFhNMCmHb;X1B7w{Z;>*> zcSV)_doly~a{|RlQ{lT#O8(7)k{?{%A84oDBI$*Xog%@)cMVmngLcbx5TnzA99Vex z?u`rvC4Wp#A0+QQmct~E1*==de=9UG@wWC4YQozGbO!vb@(wutFG2KV^S7s~eV%Xuf7yc2zZ>W^^BkkW@

|V&SOKs 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ΠZgA}fmi68+eza?Ku}b9ke%;c6 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%0AqJvwL>0>x_-s|dvl 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 ~3$g#KBi|yVBg_>SL%jpl#Euu*MDGWE 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 TX~DzTL# zJGGL8OuL5@MP7nFoV&vDc<*W>eySBt$aQA&mXBn3&yvU)aVC4&u!)O)eX?px`zoT{ zT85p3w6L;wk(eB}G~btf?I85t+ed8l-P^~EyeqFGnk`t?2K948A$UbSPAN}81BZfT zGzf1BEUg;ul3=i9;u_PKEIuH!)ZrUY(I~8!ooMlM-I1?j+jpzJK)ImZB+Q^z?3&O*S z?X-yz9m>LKFI^arTK8g%nyGmWlDNeZu($fRwC>Y?ppw_L{`y!DMzOqNMR<|q<6yJA zF3v5eFE1=&f|nwRgk|L>9z$;Wp)NHO`9ETX4NLBAH4n`!bE4yyyjW z5%SDhK1OkY_J|ej8u;BuVfd_KOVjPGU{Zrz7?%yqtD!~P#I6fQjf~P+pjh2sfzBCB zCj@_#VZMfGXMeBaNB#pco((xMvk@)LgUuQ;?b8IzQw*%0DYM-O%I~zrWK{c;y}HLb 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%0DPuHnXcXWQ?5cl6Hr} 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

k8s${f1S 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%0DKqPmW4PCM%Yv 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

1ZGVd^05)E{M)w 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 &i*y9|rJ1;#pxki|%| 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

SSs0 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�v`oB7*x*|C#== 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 z

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�d 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

s5Sr5nWP!zf;bQllMBU5`uSl2dH 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 +zA2z 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

M4KsLGLYF`T=mtL%TdshXO6;g4yQm# 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

%lTDCYypAz5|ZgHH#59pi8)Nw1#}d+p zT+BR?$Pk#X+$R;n2GxLhAelB<`>hW*BpCUCi6(&|R==*iBAJthVhuAzEN$8@BM2N; zl8nYkja(n8-vKHTOC}Z3ghPn7Dd-udKeT~hs)&ufk&U3Q_>->X<57?Gy(XxT%B!Xl zTyyUMt64I$s?KT9!*8}nIfX)AJhW201H~&uz4FIkD!vLql24H~W`|T7+%@t=n4`}HN7@O+ ziu?#_pakH5L;h=hEf-oC6aZ>&1LhkPR_3f@IPKyIC3o$?t{;i`rSj{<)To(gXoEHB0#6AoF)RcJ2a1#bUboI66K{AWg zK4xy8y%*qzfG1c`a7N5e)|34GmTLg=ZV_1D>vk-O<0Ql6M$D;?nH(bOyv5-N)3yJb z-eFlF&^ON`AX?TWiZj6(w(*4?aasyn40D$%olig5{jdU#*T}0voE;DCC*FT_XF9ML8LAs)0l}(w8%U}>HLfqEASO8i ztleUnlPHQm7-ccZm|H=EGiE|#RCQuF>kjfN50>%-%XYaMFo_zXi9YI)|JgKAzJPs` zKvQ4xN%%#AXq_pg(J{fi2S8xRzpzrAIC`_H$` zf4(OE-68o`{E?}>T|E)=o>2acW0{bXj5uiUn_hUYcBjOpnw5r!M@ml4yDTsQG?72< z4d_kbK!!Yh4CM8%h5Kur1?rQ}`z>Ffhg$4{@FiN7D{`Y-ww?~4aS*u6FtE)>MfQ|2 zkKLm2swF4@0O@I-P~d_{VXH|rS5w&aySJotXoC4#7s3F#`yXpV}jdyI42=oK4<~Nd}5boz&_gBP07Lx-fz=10r8M!9Fo?TQnG<>tLOcpfvZd?sTpI6bO zUT9_`ByF5As6Ze5-qf{q`Qr1w&A&7KlAS(kl1Sb|(B^qK#kuu-@jS)r`upuO#~Z!} z`i(jW;x6=8Sf(V0XDDn-kRA0VR*yAsCv_0eCfkoK-$l3Ty0@W}-r>}(QV!0h-i`Va;oZ1*ES_Y%fH*h~5G6Q>X) z55|t3Hpzn9^8`6_pbh|jaZJcZ(j}X;BhEvXmkYOZ zObD^}9MqbP+Atk#2VF8~FJ~eokOj4q4wRGpqaTDpD`0vThKMJ$0oaSt?+^{lb0TP_ zngR}ddy)5r?Db~)tt3r&ikNX$@Ik6 z)`Eq4&r>G42t!gpk};ki*@y zBlsf9xM=SV)RA;nAr|k7aDlI-ifkHhF_P_6848O6Bee`OIBRO~f%WIuN!_fp)iCk4 z%y4={hlL6DWZIrs%PWO^$}C2)Rt#Aqn@1@fbpc1FL@kG!z(V!IX8%h#5V<^u3EA9w zm-f78u(;x>jk({oihb!}$(HV6;6;c-<;)4~<%UBysi&gkOFD#}t!dji_yghm@2 z%3*KqxQW@aWled+lg4_N2}F+e1LaMoUb$-%r;#f%G}=~y!PFV4b7e1ZRLkwJ<0-;@ zM++!8XPZ_Dt!+1k&oNtLLzU@aIL&z%`&f3MqI;#Hq;u(FOquq?qEz^dit)x+B`tgf zJ0e+%*UD-;1H7fr_hmbl95p+qPoh9uO4qbTN>+WDs1qGeqjGuLf>~2$IoDBXIT~le z!lz=FUrqJz5+ZDOLx8#pcZ|JK?`~$*CQ+A!7pw8=KJY7nx@vYH&6KZ&-ohMOG~=b% z7E?nt2=Yy;F*K7p-U%wq1RKCkRq_kdA#**$IaK&Cn55KYiZavp#1-Y{(X4emsyGIf zNNZI^5ImIAn9kyda|z4z+O5JVN4^^nlqy~;o|*i(Q&W$~-!Xl12kMr)mVA@Ie9!PE zW=d#|3L9LFsQj^Qd!>m+iFA5izp_>K#H%BJ4XOT2qC-T#nDX;mZ&JH4iN;G)`Ht+9 zBapBBwdxzKUw6e5*xBC9=`sIW~QO#=tt8u9H!cOo)_gdw(ejxcqBO9(JRFjIW{NL zO5sJu=A-)eV-!p#VT~MQ9-P5DJ4(7N9^S$YGbwm>*Goo&DG^6Co6}czESY)LWIS0a zHrba1EvzxPGZ14u=3c|xlyS?604McZlYV9Ywrs@>hq_;bp3xsN{qZnGt8faWJJ#46S>xZygu?lE zX}Y8&DqXoVBQnJMwUw{*?n#L>6yB7?*C2)$5;Kedt9qEZ4AI54@E1DgzrR{pc6;qs z=Hv;t=mYb!;5;Mg0Ew(Jnnq}`zR@O~#&;{W^-)I{;^Z#cdqevQX;=?tL^un{$y}L3 zuX3W#L6i=g#4z(vTlK2+WJ9&@7&yDBjY$qr9dy8~X0-{W6`*B_3Y?3h!WSH29>5j4 z4KsjnhakeH!V)WucMBxJ3-EGB)#Eh@eXXI-64@>LZl6e=7$G3V9erg_Q%R34YCP3p zG4H7|gJ_b)8=n5%{)$wG-GFht<;(N|pwg=Hyt%d-LLV9>rH%;cEh?HsVSW35tUo`UqliCz%+SE?lP5J~q`#nAZ3P z5K#~OwYtEav%T_=9aZr>2EP`tE0tin8sdP0_+g+;2>6Zz+Bp{0^$nl=Mn(f*U&*Fb zGMyhZxK&AUICk8=uC2l(Ip#4slr}fV$zvtJRp9Mwp%)~qD>7{=+%4sCWTmv6(bS?d zTaq!StsX>4sZv4Hp6Q~sxYrS z4lw*;7N}NvEv3SrzSc-_!za+ePU z@?^Q5k-*0$EFv;?eeW2T{u7UkV=tg0rwO4eY?X|D%n7jxbT@5Nyx3KnZcaGnc-+Po zBIe77JZjD_=+Q-M7MNS?$pkH5^^8+(4L5b0vZ;HsiQCrITeS~Zm9LlsV^`&jh}-OY zo89u8uhy20rKTN|uQn+UygVk42H+QlHSGkhzx_Lt@UC4cJz??))g1lL#o}YleSI_6 z$3UoVZrOt@he|HL&biVcv=SpM)8{(DI|U**9%m#@TM6>PO)*>H3_tCQki)vwe5C$QJ+4BeAm0j z&3nL=eV=!H%RJegBK3zWYVsMGTIY5=+Npc6#WzbY^9w=}rS7m-$6vKZr-7R(HED~g&nW|uJsEDiFMMq^qX z2RLTFGPDpZ>^ae?+4Y1%X4r*l^6`Q)^)|OvXIN_XvzcG+9x|>W-;d(-W@}+xgL*N- zrTNXC~Aq8H2RsUp7PvM`}&`TpX?o?siX}1IpSw zyq>>#B@LmpCokYR4CS@DaH5A4BFSc&;}|F^X6-FpwK3RRTp=f*~{;J7QD$i8NR4B;vDr zD%bNX%cW@oYe&jJLYcy{N(;=Cb4nf#$!Ro7eV?)hP1u0dDT`W(GQAws%G(9Lttf-u zS|MrOhKh&*BelrA4Xo=k2JP>4wof1`tzT6GrGVzqA3?(Qf0?jLLM@WnKhvnXVP(-Yq z_~7u9@L)-+mNQ8p=2AptBFK35y@l|g>66wV#!~|3#Ho5=Qi%tldY zB{`)MJDWsVX9rJB+DK_Rxxz9-yuzUHR4~-ADpl7IJM7O-@8KhCE91EQOZ=4@#_AN$ z(?t)H-<%uS`Bz~lVotABmet2XO4W_o+cR8`yc(D7_aYZ%aB?LIu;baZx>^?6PCo@j zR2|oM0BzLhsMJyB4waP+`nzyOy;(~#(XPMPNsPCN=ayNSQMdV)4riSTPGr%?bX~7Q zYQ75g3bgq~%CPZx1~ML9Ld4=Zb(diH6t~->s3$uW7Z3Xio3sLUv&cr*52O9_$~r>s z*u7Tn`hDvNoA?&I)bi zs0tflOZVZHV~5R*?%eq0*-XZ-<{V)v2W*HiZPIX`K)a~Tuv($EsNSGHm04za;;ude z^v<~4Ky3uY!MH$Mez|}~JJ$8G1|j!Wh`B(h%&-g?>N}%Ns@4_;B2*iOs-1)fYx1bf z0X4;CKWt9nSCBpVvaH9>H|hcRCpHk=P}{;x!#jHD%%)GFPj8O>9>yX2Aj7Oh^LRya z!q-A&5cL*P)Td*J)x*WwTQ%QSqShGgrMk7y#P{u25d8ePOQd!${B56_Nl=|k$e(No z?$-DZt4^NQ9-VAI@iU!yZm0v6*p{&cV7wtI3pw87*J5@0SY*;jp_)*)*(Ak`zf^$a z`}o^+Ns0M>ui%f{j}5YG;zRS2eG?VSD4n?*kDyEaAg!YtD)ap_s>??91wjN1+=HS2 zuFB&6+bU~hY~XB45Bi7w2lyi(02cG->)#_~%z)q9I+)S}#P0w<(*I@v(YvtF|Kop& zxaeE`w~>g53&5%Lzlt{isO$%rA~ILX;V^NqD9*>sUE)N7=rW+ybPG8%{ZtSSV4^r#v&vQu zb@>YhoeVj?Ql8~r_PJAv_;3hZr7xhgs7W^9%jq&1Cwmx1-6yYb^a1P^Es0 zAJN3V{6HrY%oq)JE%Z@umIgJNo}u`Uan8!Ux`=v-i+wxY=O$eIuie!XLZGp*JSIos z89s!V2bMm|bl;hrI-604{l|ZN&8?MGLUmSd?)`P?YV<4Kc~nT9bB_qLg6ZyE z@SPC2Av5N19*#75!5IdW{uKD|d_w}kn_BHg86*nX8VmjPL~m3^I#tUM+8(%0--N*(S9{ogek z73IqV964#2L((WDn5>K;@*y*k-Y#4*YsmTGC2l5q{R8ACQda&4@$ZOGj~gle800zz zn)%#CmhM~%C>sjy!M$>A1V?wt;pPA?uFh>5>1%8bdo;-m=~wHr=Yv&26)pUk`H&CJ zE{KJ59Y0JDbIA=NuDan^b5eDDus%!1O100}%g=BZ3V|xqnrm201*Guo);-bFR~!tt z#9i%CZgb@toocPFD6AJlp}W^vy^~o=Y^BHQ_p}E}4Xk0X70sl!B-0UuwL`s!SuBNz zJ*?S>c`T+}=X=r>q!+&)5M?@I1Q_qHNRiQ$g6Bs3HoNe7B!lBlMQMs$3hNRmyis(w zo>gGW9}zh%ha;n8)cVGuW2@GKeFyHPpO;p&m z7V0O8+*Q&0wY6Da|KRP0nLY7FfYi2C)Ee??$^TOC%Z?b;FX?$qw#%QM(;i@pIW-t%~PMXX1zGkCz31+bbL zlLR@O;5siY+7bo+aPxueAu({`j4yZ^?{jw(#8Ob_{KO^>?HP{0q=ro57@eSk=MRvk z*s;f7qJM>a6N-_HmiVIloN!cU{fHrm^46p>s*y5m@dNZ3aTV&cd)78bgxt&RD->K;lej(+rp z&DBV2K7T{B%{?_V?y2*_A(~6I?DWHBI_At3JJ(C^Ke(%YYHTALpq}9TZ9Vxcg@YlB3A(#(916BY9gKXjJ*+1;(-X5$oMTA;@b5a)+rk= zdT+8BV&W{<0FQ~NL#c{zR7RWn!-+PZt%>yKkKJ*0Aj{=3f$wCIlr*(!QihbFs8m?% zhT6vR<9So7BYK?Q#Z4fnD^*v_>soV%0$CQp6uLH&K|F4kFV<2_U-3=}p|!gkC>ds2 zem-ekIiIRElR(SZv~}U|Vw5fpSq{UTga$2q!L?AeYVTT)?V!c#s?*E?`Lf#VY8Fbj zMq*0kahmf*Z4%%;Mp14{+QB;=Q?#Jlg1ZvIy%@85CX8x17{7ilnVW80peH7z*RIlS zX4n=;2)}ldJkG&v$g9#O+)smV(Hdb6x5Plg;Mp}3xqOd{1ueA_QwY74Y0NiuULNAi zV{n~zlxFN4vu4GQG?Hl?+lstC2Komo;VK(d(;Mg=|yv@J*-VU6)cgW4OV}4dKo<<&d8D`Kntmo-V zKg6SLm7OCR;FE#=ROnBMAPu)9zDal*c1C(!U=N{BlS{0hRwCx35Y8@sa!2O}Jqm7A z7Y34I7s<1)k9A-8Fk#0I_^1FbcgmGo$qv7Gm_0d_aE=29^jk|^uI)<*~KyoHz2SZ8pC#S)@ zFUPSJwYL<1v>EdB4Nl#3+XW}*K$d<2{($@pRoyXXf7T);pB(j^^2~9}xy@?k_wnV1 zi0ds6vB9KLz~<6(5)3ViPhVgNeeNj=grVl36}DF;8R12Xq`F}Ks;rN(#W3LL>9Wy0 z)~s27)6w;~NSE}?BxE#bk5@NFh*f3{;Xb*x4a>_pyr0=5;s5$f7*CXP8{y)<_K@9U z3vOI@s)SXUb(mUNeudXU>So++1!J>-QH7^dnq0{`{i8xdo+GD2=de1j8nB5nhr_tb zT(wlHJDzLUhPqNnoQe#bN6;uqqo2SRYV)FE zR_1TylyEHEo)8_M8Z1nax5NX&++Dc4k5p6>*DY5G>TN`_{Z9HadNQdsz=*g=x}oXJ zqz_4G!IsB@$k`eso74YY_8JPdX}BVne!FCC$NZD_jmWs7m*;?J52B!LCAw`_*<3tk zypSM1D{?%&G9hm)dqs>Gc@F#N#ZOF-(~Z7CmV)2(hg6RmG&j7wtX{|qrV_u%x-`u% z_i!H)V3!^I(h=K-$m#ZQB2PFUtRYx&F)H;$KoeTG`qW{K}M3gQOkATdZ7`06a3RVZf$8A3t5^VmM~5T?D-+=^jqkKtXe^ z$xzQ+#|wbB>|v)>4&UdiE>PqXXQ;SW(jXY!jRR$5?6o+0t^sA_c9-_vQW#`shw0V3#)517~NB~{r8X<)=k@!)*riUxxR&kQ?Fd7-3zt(+uZ&{ z&yfW4B-CN$nJR>Y79gUPw{L362J(d6?Z(!c#={P4`yQyvHlE^yjw>$bX6kxftta5; z4yEwKE7y3`3H#?T`x!W*DQijh#fRfRu-^~ZjwZ{O59)_Mb~b_v@+qIaTdsT|x%xQ~N^z+byg)L>iP09nNYSDfw_o zjthYrLMlmZA2IM*QEPgPW*pByUhSg>oT}2bjHTwz9!F_jI+?isih(Sz?(CWLMe2YD z9sB@Zo5+79(8|(=6tvrx(=iMhIxW;%z@|r7>@o+_F274An1}BuN@IZB-HxB_XN>GV z!q@_4gQx20Sa#C31k3ZIs)xLI}znq)BM7K8%^T8i|dkr_Z|Gn$o z`svGa=1kI!^Yg)(`$htVopo{%%-hGGRMedqD*8sQJo_N#0Ze)mcC+LjR(v{6G~~g! zfrarItdFM1C7uE1Seq24Y&eash`?}`=A5u8@D83SScxdx<5yra%sYb7q*qFh?$|D5 zV@{ChDQ*>ch+H4$0c8%jRv)L*(UyLS_aMGJDfd_5eyMAQj1n~zXj()GssSDaXvRdA zDP;WbJK($-GjfY|GQSXjFJu`BdU=87isSR zo!QcE3wP{vY}>YN+qP}nHaku_w(X>2+cr8K=Vtf*zW@H`-m~{P`<^lKj%2Jc-dZbF zbJg?IQ?uq2oiU}n&Z}#?M);%dsVf})67?x;L-)5T(%7G?XlY?3erj};)R+^nsNROM~gSm1nId_Yo{loPVu1XEl4B8oQ{ z3eRec1h*hHIL4jK6!6GbHmkSdld!~7kiekygt#`nU0>Z?iBMY;FvXx(Y+I+VXqJZd zS>+pwh{NIznbZZzlu_QE4jh@jmh9ZmT5g^*b6Q-vwA;B}+*cLPso(#+djrC-G4Bat zQ6lnF$=EO>?MQ`SmWp7^ipPf`1s{8AK4~^@SvoQHqF1*vhWsoaWAqxDc86&&%#W4< z>R(&djU-Xswlj%z$Vu`~;EUQ-qRMj{HkLA22_qUJH^O$j5m>|yMy5b%H)_038C1Q)|LL82233W(G9H+@ytSSg1QNmFMS4I%Tfda z?#)IkQJfApXx)gcLYWInfT1R*Zv+Q!1FlPmFv8>8!HI}6Q!fP;3t;NzCvd4DVxQpa z#&4O6+Vh<++2t!#53F0%w16%QYiAWgA)%EDtCf)f8li>|?=9N}OAt>-uo!9D4gm@I z4owyDQ!|t>xe1>wItyq9+WsD~cpEbck5~##uCEB^;9U0?yuH+r$M$XuBe2A%Byj2o zG5Z(gj1gpiWKdf%NMgJ6wMJVXY9)9QhqdM}V~s?u>pL!RS{&{l!+USK`>VnXR|D7y zoCV@z4Mh!l9@aC7%*ts1-zwPn!F~YZg9LA%Lr@63Rc%A2<6{ttK_`F!3QF@KroQoy z>WMPp9{c@xRHnIU3Bx1v0feEzgkV2ae(FVvPfB^C1XZH(zoY-FkL_pM1(vubVT z1>4Zt(Rr7qZd_gvTUo2m@`m%mC^8My&>TfpEcT0hHc40jRyk%--j%o@U!X_T2J7)a zt>bBj+i8qGQx%kmR=kVhg>IbMjL>R9#}tE@xAJVreKv#2{GR+j|j>% z5g!+6O!O03T~Dq;28a%GPUH5Wa3snUN+m!i^=QOMWkeUdj z7<+8po{jKX8hb?RW<)ychd2(gQL=5$wwcEnC>-l!pQ2^HK5Q{zZ!GKeCxb=x9 ztZBivoSk?U1N2yPP?}pX6QTuBAe28kQ~TTc-q9!5;-%Zz>B>5ce!2M#_Fh0zzN&3s zeXlDo;TCY!)T!N`JM>)juAVCDEP?n+b+z8t+?GYH84=%kY~fm7`gOQ8OVpWBONcrU z64+2fBAPUrqDS~xB=BAur6#nnbj*AY8iXI@E52>V+IpXn`-ai8qjWwW(ted9Pxzu{zqd|GBE#FCq~td89P#|#y*^{ z1=(>}iDnp+CY4kiGgi1uq?MPx^1GK0-bxMJxX;KsQ!C)EEJ^m09xd$-)$RP3SuRXX zQJ2=oMqTL@o!8O#IMBl4#3EiJxC5A{14cBe? zZYsFUig}rOdG!%7)OyT`RNU2;PLAd)%9FrZA90$mw34DQ$;l_g;HW#@#F-z2ez_M9 za&gZJLcQ!Sx2>7xxoQ2%jY@Z}y^kKo zfz7VB#6bt~WA(5;-!Z19eXS+G2CuKhJBA5p*&4UgH_5ewas2q=SnVi>>!I)K4%&$h za3N^l?3gjw?d|0o*=&Dm`x+CvcZS#X_}f7$L!}e4{Ij+z`?ou2l>eQ{-_GGvDb~Ts z+}KgkMRr1xT7pVkT3+nC(zP^|E;E>;Kv2?`ZpfT%<9y zbuj)%ca!=b-|dgk{J%%X`9~*YA06D6ZEjin={K?06S-p|6|F2U|5q(Ty#2m(q?d<) z_B*gGy8;0NOb|QH8li@TXVe`DcJJw*2n-ABh7=ZRM7@Em(}ZY@Cv!$3En2yD(}xu- z39h>gnDcH*@-0iAX`lJ{$Z`U?BMttQ^c$mtFpJwv?E0Gn3Z8G}oqu6L5@8Rr-FEdz#A&DB> zt9Cv%;f2k`J6+Z!y=GxUx1f)1U`|qL^R=!$v&d|-3&Qj)PFf3YwZU> zjl6!oE4eP&#$!wC@Y+e|?L07|7O%H%)Bq_r?A$rt-lls!n>&EPGa4b4q8LE1vQ6C= zI$e;=!4qa%>+N7ItW7Z|zHij|(oK3Zj+)#`wntvD9#V*2Dfh4<9R;yL#@nwM z@>Yhg5~x~m&Z+J}?!MoMA@iq2=zD^{)ryBW8;nB5Z?g*lfk6unNHh+eU_sR2*jn^J zH19)~4P)Js8*|QQ+ex0NnsMJa8@x)AcIoehz{@4*k<>OcW2O_Y2ECmhu5&(YDJqGb zOIKZ6?Aq^0cWo2Lvt_%bF6dl=$=zEHF3IR%@KHt?|2mF(PMBJN%z{?HQt04g5@P?E z8Vc5%J!Xcj1V&1%0Kq`%6ahTRPBej{E(*0#&)j`LLclP3j@_7u(4oa=j>JfIK{Y=a z;^Ny9BMe~*JyO*0HH?6Z*;c(H4Bc&wnfG&SuOYt};3vhZR#j)}%ZUTk*LYO{Eq zb8pwbdLQUS7QqfF&+n${)Q)VCtip&|SdAZAL!w>B`6zm{=ofzGTi2C$4}su0JtX!5 zeA=3{zf(lNaI145ZquH=c!ko}M}5Q})9@O3b(XEe3)0q3u)1@BWZsGc7eb7A0qXo_ z7T|{g#9Y)**AHj5@0!QQ^w}7?1)aCvS9cR&yT)pHNaXuZUDlNu_{cZU?9_hFff>9p z0efGLjid$zz9R)Nh#`PueT_@q(lGjYU$v?Nz zoC{mcI7C~*BHN+g^h5}wzCPKSJ8|-T-aDJ?EODKh0_|0{2093!inm~$-Bf&Om;%s; zgbFdc9;(^^fJ2OTo(#6o@5TVzy3+J05+o=V*@#*=phph^w3RpIZF^r#TIPF{y1yK0h8n&!XRc0IPF~bmLL6FH_cI0d_$hZwBu)Aq zTfw-JiF@;7Uci2<;E^aBoZN;G4YTxX2!SY%t@z%Y&yPV^Nu%G3%uI?Dxj{x*M++%x zSkZvkDYU>1suRxJ|JMABGpz)UqxF53Y0Fz2z22heoD<{)$Ge1$Fn&G$0L{LqF)p4x z#arJwZ}uK*N}eB?j%4AWLRy#3En>&x)oN~aWkfm#5is^y9#vC%RSceR~ugnLhp z5{eS(H}y@rS+7GY7D{X!Wq0?`$vIljc^ICe-2(VwNDKl50>zldOmDIq9<2Yve2*x; ziR}0|szf}>f;U%4<;9c)1r5O%A83a$Dv7I^Tr-HGjsiA#SWmSO$!BHnqREVrN;!GU z$xWLn8SzoT?Nu$!uDB0`^zlk!CnrV>|) zg(XbpkONom2U#o!+Ic|L+h8A0G~-56v{_} zsnR7Vk5yJEP~Nk~-@o^EVqdmr6iFJ3Z6a_ypu$YFoJz2&8KSid2p81|F7$$>PU0yO zGT;R9I7b{f^s76qg5^dO#jBg+`xwAP-wn8H^4v z^b6oBv5;J^4{5L0$BPUNm9nTCp@n#o>W8s%5sOQ)=(aE&sJ!tp0U~hy^z~T19uLL5 z@V@!(x+$rxm0ME%DN879$X#L#xG&nyQ~oy6!ULP_k7Tn=g60rZJaRUE>gV0p!)|~J zK_8VUEmX^z#Opt5^G*PoU!pRU_7wHV4xPA@;Y*upDP??)035+ z%_X?Ik9$BeN_f(Odmu#^4rW9f)KS8Julx*Y$Z9w=8OJ3|0hj{s-wVEc0}f5x1s~yT z#_k#o3u@VZ0~=ydqDR_&)EEZr7AZM3!fT8v=c_gbIKnA&MkI z5l7*5u1`v+A}%7n=}w6MEzyB%+;L@%ff8<{?J#xOezfU%xpv|6{`?HYhu%nJ#I;xx zMhwCZGLA7z=BOx7UnO7DhfYaB!d~@##6e4ue()wdpagoh%6H%!%WD%lN7wK-ThAQi zdF{K$WeyWHt4Dur2F;X<)V`iNt-Au;;G(vx3r-iLu)9xBgoq7 zr)t#Aurf$ZMwz+Wje`95Ru*>StQlV0+f6}Xt2b@&JxzvpYkkM&q?m^t`Gz*E}xldeZ@R5vnWq zNOUW+Vocqtwn6&);HaH`eEYt~bLbRhC@@UKs%}$E*GtDjmfKWx@r*;BPKHDq-89G1 zu!>)n-Py(3zj}a)?5Wjx3Wj5)y+Jld8DIR1qAPw+1E6n|$K-`=ke++uDkzO1A#I47 zZhthBct3U#LBew`!}t`_pf)UISoS6C{`0^R)`Y8N$*otLGjTTH@5H( zD6Jlt-fu;s5b4qDzg>f_!(Op1Kasrmw@CgsC-d*;NneSbYIgl1 zYL>CgP-~svE7uMVq{|gAr@b?iCJ-W_3Le3MA8QyPeNIQ^=`f;<2O_vY>P%ad;f~dQ zFgoJ;=;w7(8b-EX%^)u$8Zq1>n;+H8Ds6{;`YBHRu^!J90b+Xqbh6xa5&f9PiI3Xl$ci>2*Xk~tp>uiSphXN%&vfpi%S*XnXR0#hFj>4b z*YU%BbFgMMQJksp3~#<~Q7bZ(JX`dY6(WH55ureYZ5j6aQ{5Nd$f>uY%)v1 z=AZ>=O0{u2Y~_h^a}@wgG8rnUpU|weg)_4%^7T}_Pl+Vmxd3r>{>m%@N1n0E1wUv*?Z-DjuOoD!a;|68uKQ-4{ zf#+^Ksa!QkI9beJS&Umgokm0a3}!A%`N5dCqD{kn7aRFB3Gx(GxdP4~jWb_kcCXC^ zj{%kX#4Kx#Q1L0?UxzAlFx8$Nz4FTuCU37p-eYix90DSor$tKXCVScgrVIg`cwd0C??1L_(etVjRjNnkKTzL6~*ZPoL6Z-d+4uwhw86pUZu|xf{3ldAHSr2 zR}%j0oZz?(nLa+a;3)!yCqyB#Qy??(u;^xq7J74o*)V{r4o$r>Vwg-TR0Q1#DBPY< z2ANN5;f&?N6(3KN$@IykU&Ew+oLcHFHFl$VAOc^D=Aora_Glk7+TnFUFZJr+6yJK} zu!4IN&XN(JkxLkHDDiU+q~eso4Rx>C1;^RX&pQ~DvbEj&8tHtzpbA#>-usf(6pp1u zOq*2KuAk2|iglNl6Nm#7nIr9g76$JolBIWB#-z&6u8n$A*rKru)}l}pCo7%ILMeAB zqg8!`%l@*++&NUC+&{jXpT2mr_!Y|XMs+kRRyD8WrZ052BHm1@?C|)iU3G6gD-bAw z+~P$5cw#Y|AAN|U#5n(p5E2@iohUZhluaP#F^wz~ur@d`DRO`~NwEq})jq=^x}|H_ z)U41;W}PX0^FkHs;n3>ica4WYAu?I;b71EF7P_o|H#mQe3XzbrwcUS+lK%>h^1U{Q z^hj94Yb5GT;)x0x--@V_%BT>^BY?mtX!ym%vi(xxhF;)bB0XPwG~Pu!g~1k9hP!yv5%cMCBOzPl z0=@Cx_()PGaLk3tR_^qklUI3PNLF&YE_J~776)xLP@{d}gRVOsj+sH6-7uM?atYKw zIjUVdbG!f|I8R7CdqGJ(HNK*@numruyOtSFMiZp$qirp6DKUZ0fjhn;J#{RZoT|cR z%p`cLZfWiroHj))zxfb7!APIdI+~SS2e&1CQitE`<2UTeWY(d=Jfd3AkeK41`xtlA zljK6cOP-t8IqS9;Dly$>6F{;H{56hfnNL9c>&adBsxua2)+Q%R|KaIa3hMZ$wj4Uv zj3Uc%EjtGfd|u2~*GZ2fDO+c;SU(+mr7&IgZpP8rp}Rs25dTYIz5a z%`zJn*{}vx?{|$V|*g9D2TbX+p8_C%^ zn*Z+u*q=_!wzHr4zYRIvD#Nl9qV6zKo>O9kHr;i8kW>-buvY z#f*yOrTYy=x_uAs{1MwoI|yNe!O_(c`}Wf9D7-E}i#Yl{Bp-*VPX`;lm(8v;+K;i1a zjWgXhZ*DAc*UT5QdoNv}BO0&5EO?gXNAN;WIFjP$rPCzc1&IN1>qHZOL=cX<qUW zXyP4gkPh+_3L%#u!I%SeG$1)%A9+7LoDzw03=LjukQq-vK`J~hNl_lpDo!lRIh(2< zW<6`{Qq=g1`Wd6r^D-;Z3+@z=;%$PphyuO13x#qET)4TdwnS!x`5a?Iv~OY2M%wJd zv3Ej+jWUUnjdQ^K)}DJ1ktcLCH#;lNn-!M_6AlVKd(Hqm|ECwT9yLd#8gco|2H=~$ z%C}e0Kf=p=V&csor_b~LHXS1VuMzs^d^N!Z;g+S`c(m^O@WiN|(ZJ}0-%v!9SZJnP|(v3on+<#_oq^=3+fi1FyQ$y}#@ofmm5NPy%nhPPy^2;@a&_ z;E)Y}bvP2#=>W0)*(3ByC)jN7*p7I$9Un_~$mzacpwj`x`zeg9(*gF??FMgie8QXS zzz3CQyEk@^wB=456~|!UtH%w#S6XKOI`;md;yPE~M8UdO#u4w3ly6Ah6vO+J{T*Ak zcVD=y$F_o3L}rP5AH0uiQXaldjJ;!4rfCa%@5E8-6CkVZ{-NZ$S9)f(onu0#zD?KI z#8M0UpqMPkAk3RBx4!PXpey=&Z=YX4 zHa^D#xbAwKIrh7EI4uZMHAp_^gSp!Pr0?@k`mgA$A3FoNp5HKaw+~Tq#CFh!8>_RD zKiH&-@(_Jb{LunUZcT$BfIbT0DY(SXxVSR;w*=nuG?{T{g|eN zeoKY=7%BbO@8#Y5T$)3<>KMkqCm+2|1o{s9wp@2>KXP>Ez4PAac3f9Tewlzf?n6n1 z!^wldoPl>Kv2#0qL%(Fp?hBS%WvFTQHRoEyzCafXQkZdr=C_R=BnU6^&NE_25F)dT zC3OjX&cBLssthMB7{bz|fDgx0Y8*u5{+Tx^CfkuC`YiCW2UPa_6PPBJ^l^qn^pLP+ zN!ZgMZ=Nq8MVo8L7;2Gm9p@_Ihprgem;o^LT580Af+fNY_e_--U|t(t)dRdDL@%*n zcBW_xSr%p9N$}17NPNl!Mt=jBM9$|4KdEp0CwT&a zuJ{;cSB2}siXRZ6G~pUHZfJsbD-Oy9-k9oXT!}16gXuXHI>W`n+pYIL2*{rDiwxW`Omb!NIQ}c+OiGr zPH!rC%Mx|9`$%(PNHRB|jTv}q5j667p>YbgSXGoRiu951meI~mGjK~vP3DMMblz9# zEszaqk91o}h69(AV?;Jc##ek5_ZeH=-I3cGk|P-NcAQQ*jYgP5jf&C5$H{H?@%052 z-DpKQT6tKfw8>Jp4En+l}#sBb!n5DHjIkb5e(m=K*DjmB@`53 z^+V`jJfFxkC9QDrmq>rRK|B$<{}PslD8N8k+^0-U6iMr=-x6JMxce-1EQ#^728DMA z^WscLth8eJ_u}OO(%l;*OgvgANLFj+In0GGj$zVMQb(`+n&Sk65aP4u#2i3x+IdM1 zhY%pZ8?y?X@g0m(E(qdQDso`LMV%ov*qz1x%g;uyO{7s(DZ6eL$4rFI_9-&Zg*FCM zf*uT`cJplfnPm8;(AD(@-gPzV4H71M-r6B57dx9~xWPJ}x$(Gh4_1<6sw*S}s>tN@ z@R9>vvCn69iIJ7xlch)b_sZFr^;D~7GJB&;h$hg3*^)S?NUDTtH-8{9LO!YEAN8Rn zj@*`6nL3hEN1-D3sQC?vH2Ddrhi}!iGnL=(Nt^sidto-2HE4r0DPeF#i#63lja-y6 z7YAVoMj4yV+8_GCNDlmK+P0bkB+al6Ry9?Cd90YtZ-C%ML1baagig`c&W!Hv4DAW8 zzmIIN{ar5LwLeUJ57KB`z7-#MZAi#M>Kusy^(bdid1jd}LGsJ!!KuxxrM+q)C)0Fl z(L^K^gIe5)Rp8xa%vE>=<}s7ResOaP>IqCtCrQCWr{(kG2_2e=BR%-^^1Ne>`J-}a zH*XHzZgFb=T$`DxF4LkQ*{=!~`zv$iFGo2GB-s(Vu-cRZIRF+20B+{+X%nS*; zJSmR2(wov84v=5Ni`nO_qtj;`lLWqhl*obdsi4Gpi!8q4I0ZEb#l@>2o=TwXkD~ zI#viSLi_sO42yCVk2{K1?nAl|LBp=ZR z2PSZvNVyIXct%Gp$}xXuHbtC>G~U@1b4#^vDyVZLJUaB>cpK`0MKom6=_cX#sgH3% zUe)%?TXe*3FOF@Qi=W57|L%)d)WI1GCmlA_W@JNtf#FWhbVMyD3^yth#J7kOhDMxC z420Be3{z8kT~$vp+uX92To86wsekvN$yV{25SmHqA)x;qCt=QXB7?Z{Ol#P(s&k-A zeX(z)qsE8d}_wyG67xU(djiD*6dE=`Z~<7V>{aQBP1Q| z<7;PaBzd6E7)ixyy6ukL1+z7?1Mt|Q_~;~0CE+9w$vY>E&bn9X4~D+fZ#P0d22U}C z-0iGIOX0)@9VkPu6RNs%)Ru<#+6EqW=R_|rm4BY%>oq-SL@ykAMIU(-DN)kGhpOoQ z%tXIIPBT9UZ6B|wbdsNehQcpj&_8}HK_aPoi6d4_!AY15MO&VAfYjJlipc2f2ICWB zr*jzvlI(q2Q_x?sLtj!#T6`=;W)i-_;e~=Tw?l4&b94w{le2&L@z^a{~SZf~b<>{rST4a<3F>#>WQeE0Jn6#rt|@GDHF|Pi=~*sfeKY zUH()(vlAM#9!{*p8FqzR9qY#3sEIh<;R;b!Ze%~GVER;$AgZCxX*+m>luj&~)7j=xvz8tN$$C*p@2HYx@= z&5U*g$MxNwvtmQK<0mg2`St6?0adTarraEO9cR{&cys!bW4ZP{@;Cm^ILXd2*n=c(Ow|#r!tMjhm-Y z7u$TgC|p2cngoQhbvPIEXl>bBP}?kNurk7A6ff|@OkBraUil0yc8PIF1<;{4-YPPv zEgI^pdvQTMwZH;EJ{U^#bAV9Eo@l+hzz6G zfwHD|8#8mKX16C8RTcEgWa(=a?JVa#B44Rh+8j%eu8h5cA#O`J@4ThB(JD&YvE6e3 zPHok99tFDPcnDl)WPzEOlF!ZRXDy&4e2KO*l$aFRHrboe_u8jtqa0-g*VvqZNZn*s ziDpWzw6y{_tl;{XVrZ-rNW{*2e;13g`c^glowam}GQZYti%)f6+sK=%9%QrSH9!hs z!k&O#3@Y+21UkMU)J61mLx%q3lz9%DoE2FYekBz@1@%V-2>GCFQ_?R|Mfiw*;wN>d zq_mZY8arrMTWTqZ3=&MtW9-4#a68najCKBho=ZM)omdGhUBA^ zE;Ow#t^$x>#*TfRfWHI*%_G{yJv(8@y}gvlI(MJ?2KYGH#9ap--r?Up)p(`Yt5+ZT zMm#G4jM-BZEj*f*eymiyAC-Q%ZN8A+KFc2d%pKGGa8mgI{~2rYGxXS%s{8|b9?=Vs zNA?=ktT5d}OxE+-d>V(859s{`I}{7LH??#j8sggc5t3W>FbaBZj_*|&;{_v&!f!Dp zmgSvfI;R*HdswPL^Mw5P#JGWZxOWn8L^vmDWEgW!Y9HDgs7w4x_OJs}ip-im2t6HJ;e8RH7a(H*-^lI9Qn31RNV!@1U$I&xR$@hJ;~Lz9#5avJ?6o_5Sg$!Ia3%|Iju$LXTH{?jR#qm>)$2>dB}!t| z@Hb7rO>Xsju815{VD8xbqtSxUYoJGc0K}h%na4Y<`uV*1Tj*{%n{=x>a|Xq9t9wp- z!A%*T{>u8-)BUc?Nr#3JIiiz3NjbTbtD8uP#b9GQ!`FvkXUT%I9~mB#wy-fX%8$35@85)Zv35Yk;jH0A}% zNnN1!h;!pwkIJ6Q6iv*}pd7;QNs{qZe!Ff+As92MYn8d})v1dHRv+ZK4$zxFzASzjs#u_lL7P*jteZk2>2ix5oQv+whZ7Baz}g(!OK2w?zM%ug-4yZ z<_wUiqjK)9n}1`c-}wdH3G7Rk+`gjJTZkyPxpP+=r)I}Z1(PB-1*f!+d3~o2%4Hq| zAgeIug|0)N+#2O_P+Y4CaqzfD=g)8vNSDLeWw^}?3jmPmr3x*;{#BX-_6S0N;f74A zEntDCbw=l+IniWjbjhb(i%~dGI!lerA!mx+C1#}z$qtK#&&&ZdYgnJcc5P~!3Bv&d zs7kykTaeEC`aCiv05i-PFCI0%hBP6KQoN#GTq9ty>9`W}T};CHMkG1kRym?8x#l$;m?6^+o$|03w9hTf>%9=&1_sMK z*idb!2I&zsKu2-2bsd@+hj?}PcHWsqQacC!bPSkjznv2CsIho>D#xuFU2%+t3zU%r zG`3GTlz~v0sgH@&q-;FmJI^HcF%T|_AaRNbNWh8&Q+*L%9Z;{8F{iI;t!H<7BMCyS z#jLFyf~K-3Bv+$Qg4>O{k@0zNvQQH>Ww5jo5oyNib$rzaz(;ms9|?uKELOabZm4g@ z`M^k$^*vSmxsteI1-_yeL2M|qoD}_!-8`WixqPbpAUC$8e!=kFJfhH0-3Ai$uZt#n5PNZG-wA(U_ zTRqt>@ti+9vo8m7fgr;QeXIz=6UCmlRN~#BA`0JOgc1nip*t!GW}qUB7MF$UVuk8H ztdYg#`Qv|h0L6D?3f<;3D-&gPL*u|IX1L5cQlt{q2R6^VdL8y?hX zq^nR;m(Z5z21ACwnFv%jK$6^nvzf|)6618J@#z$Wx|$qZNDNvRjb4mqx%QuCCwz+v z*xSNFO^w>$y=?Z6gg9okl&9S>;SLGkUXL=@UDa{LP+2=%O^aNuAehCe$rRpa3TX** zy6*EU=yM5#iS6a;M*y438SQsP!l;z6qEK~u#A_W9lnePP2!azLf)%9vNUjzb+XL$* zW#fQv-5M_=rX|Wj*4kj;CqcyWRW%d1pXlKV+QH@br`u2fDubLC~jydBBav7`_r{;ik*0d*FSH<(wp%Qop zDRGNj!T6Rb>)7&1g^C+3L8YSLek|I89_qR_|FDNIMDB_yh& zY`-o8u|2Hln^ zNqQRlzFwgMv`A)weGL!4E=_}$4I{r+mWS9vM(vpzU~&_d5`{xGC`X8NI2D2JqmuXy^Ip-v<$HpNotnscS^2 z0<8_$wa95yizJzU#B=PLwJCzsWEcB@oX4%AGC5Lm;rFW)JJG8YFO2Co&Ppsfp17JH z9tTy=YNZT0t_b(@hy>Ez&s>P;3;LPI>3X>ys3Zn}WLcI^SIY#A< zL+Y%N71}|uM_%Wj@*Jdb|b$oB;c#WB$lqv~#4C{+xBMSrDcp`Akn%h#cIIAE$z}Yzf_A z9_*^NBTd=SO1eanWvd3bl9x$Az(>snY{@fyyr22ndZ`zDLDo?)LpZ2~Y%?FNdD>XG zlE62bSaV62^m5@-venMSV)EZ&iwhKWwh=# zx5kTpKpjn;5^@x@RGW@R3Ua<=2T_Ee@;u(6wCOGDud5%~@gmcMO#-%X%|+9Xe7M01 zh8~#6WN$Eyt8!n7HwPJ}x-G#tA_Q&-AI&R9vEqRNTbF9f`9+vi&vO{=9Iu-jKoz0k z4&2Ik0XGybVV2`bF|4fa5~Hk^R?rPO8@CN^^#p#$-v(09`4y&r@~dhABOl7zUNdGc z)%yC`PtIr@U#NABVb>d<=B@EVc3|Xm#G#GX+3%41m5q-CW$%)7(q14b;fYBkA^M4r z6lE`#aPTE$3Rxj%gY`)GT{7^ynF`70)z&o{IRxOe4SJYW1jOfl<6>47LEt|IUCM%p zl*IkpcRbi+A=jbC^$4qmTt{|qdn;ayP&)lny*JYuRVEa+8tkyceYkDtI@|n9Sc4bO1-=)3Yf>!; zs~dE9`jt?~-@%80Nnnjt0Qk-Zyp4|G4PY@qtC#XfY#fc6C;keF5~S!}W@^c55dd_-KMQX!76)yY*A)(7m)B{UXu!8lub}@CX}xsP{gwcDp;vpC zt<-M4+RiHgFs62vW5YVZrD3Ha!=})l2f8(oxzU-ZyZr7lgo(9!_gFt zbi^nNFYqRj{VsIjHPGVy&ElPOp1eHJN7Jr+bTxKl;Hj&mvUsuOnH%ICG47a5a<%JA z8EmD?20a>D0JrW~yO&utqoJg5c07!glA2smo$K|vZN*0Ru*I}QPkFLHkqYdD21v#9 zP``wAz^XMP_N08V+pfSxJ52Lv_okj%yTsArYeNQa#i6gvMDy%DtinKY%iOD*Q}$D3 zr$qzWst7Z@wGsxm_0Vegt4X0YI6x%^&1`^rGmkRK6aa@jCRgqcch-tcdf$MLhec>w zt)Sb5NFTrl_?tIr7wf8mKKduPB(QUUwYlrb0=tP~Oe{9H2ja`FvoBUq%j2691pw`> zr4M8sM`T)(hQ>?sf*WVCy`B&pkXL)*Tymb!HjiwN<`>aJ8aQ+&@+IeQhu`e|p8?+G z9HDIz0)>7a0?}oXcu%Jds6tK_T;uDwMl$a+gxVbBW%y|$eAvAQCp+_`l}>_b#mY2Y z7_GHhU!Oyz477_|e47AmUi@Obij^icWxlFaHzTPZ!}4{tL1bBK%31^Q-s}#)irUZB z9BK!&5*^k|awky(iYuQwu%z+e+Wo?Tt+LY3){=5Zbd|zQ+fp>O38QlrBiY4?0v71@ zVb^)ONcfgJyhcUXkRTz#SGze2` zM_2`;PrEo-#Ef~XJjn#TKt!O6n%7DTjCl2@y6RZbn72gjlwJy+iIkD|2-Sp_GI2t? zbV6ni2}~22Sn}S5k*X_JaO{3!JAl*05Y_n9Gq_PgeOOwqkAxOle~Wlwj*9X7t)wxc296PkWDD(P5}}!>+GFjPzjbT0now6 z?(EO&xj_Ie8L<6vR4}}#uR9o_FTTI&FO*zwGpC=&c-O@Lj+=z@SDVM?f9NyW=v)0G z$~EDC*_yMH`9Ev&FKMg)-vj<`@{^w9qy}YqB0FXB zx?Vd~1A{OU3qn+4A_rD&lC`oqb%t!_XNs<1RcRuBPn-xl6U__Z-~s7}S5DK(r%B$G z)~+XS2)(bE01|EreRE&fE0V9N_+$@{UK@AhMGcB5}n}1&p&AM2_j4B|<~P?Nx-T zq}8IH8J?dPhk``z8W`cWgi3?M`>X251}=VtVPJa`Op|vL^7>Roz!_y#A;xq9ZxA)c zdsTPT7V*xxcx!@0k|8#kgniW*S2JshgDtYZ>Jq(OFB^CqLk)^<9kUwQVh}jvm60l) za1-tHzc2H+(>)p@iFj>(O$2ja!vfL?t{7;m;Rb!%jm5&TqcRyKp}?X{1fl~ zm^+Mx9fbn>bgxfs0L36?vnv>2*Xs zZ1MczJ+c1g+3JN{*EQVy2b)1~U{^N&lW)`Vw|twwBzOMD@wU)+(f>!#{7Z`Bf6}g% zzRf?=oRj_U;r{nS|889T^X1YvurgNud>x1sK2HodI2!-^+Mi^NO2to^<4>E)y+UUL zsV$h`Te9gCA~9xTf8cO}Jc2@SC^(pn*nTppgH7G1n_}?uiFK1OD=qgahHhRC!734fsK^I=qSFl8WsU!sC1?Qc)&!+^sVd1$6!myhv`4NE$ z+v+=zEcLKwr0kml@9Ya#A|RY!9XtlsL%}ft%E7EL`4odvM!4k^?Ksz-TA!4wM=9`d~IXXOC}a)i5blLHq)n|EJGdDX2WEQt6O@nLI-C-&O8&mk}KyGrazik z62;jV_A{B%D{b@{qnm3JZs!Vyy{Y=2f4iXyEOwtfe!eN?f6M#f{hxsDPmpCRtbKwE zj$5;Y-d=iEbL?$aK~58&3a3|IhXR>^D$Wd}caH=+xH2kw@l4`C@iF2y=u7w?D67XL zD1w!3+~?k0VK<$MI{KB1+x>-Wu>Xtmx>g_c`hz{GUuZkemow1;F#A=D}QtV3D? z-|{%a>`NIHBn9v(b~5=K^0kW#7+~YuYg(d4_}H=Ylf76QZ(b$IlUOlOS@OmQ)Z!1Y zK@9tZGkc;?rb)tra0U02R1yVr-HcHtifD-fM0bh;C6hg~(}S@7T0YN0af}ScXERcJ ztYH}?{oM^Cogfeka$HC%)j1Frnhc&7Cg#nmeV6CAmhqsWJPgy>qzp$`j<+L5)GqX# z>5+kr@8u9beHV-Kd-Zir;jzg)@5Zct%2JUF0r|&Hz-hYSO}9JIHd9hJ^sNC-(NK?Y zS1!^{cc}3+cgy9DPRPpYS-+RS)PxJ;$h}bUEnB#2?`jW_p`rfj;`eeM#;#6L-brqBu>@H_?=&UEB$ugdq#nhA#OH!QGKw(8#Kpb{ zBVFxUWwp7SHolZdyuqU?l{HJOQ?z{h&Ml{`AxCL1SV>{Sjc>mj0JrW@+9J2PEZIch z$=5gQd3V^!YJ2Ft74_k9yC(hREls5sCnZXoLPO7fq1u4;!LCuYm*)~)?z%XDALIoY zOOCEkPi;^WP5!zmKt6|kXbzTQq+BgjkO6j_tq%{Ty$ds%uEE696fMZhZd3o5tgXwD z>b+(^XwGGnFjfb8tcleylqPp6TcBZE1zjYPU#<2$K@p;Y%n57iohpoQ{3jvlz4cTC z;Zi-yMXdFB{ab``v_NV|nGu_KEk5W?0b5w0nSWl%C`4wCXg1_-%{i7my8?E! z&5K)A2+Z7Dk6nm+Dd#PJ- zDd3BI*?!Noc{@PG{cUf{4PFFJ_twOXLJ{&c^>0=i&5q@u}8qkP6Lfy5=L zn`xa8ZG9iG80cH6mnA-%X=XArVus|n)a!#^0FoD0-n9k)0OY}H%N)MQUGJ9y56 zoM?{Z=*ze6e&O1X)fKY{!8oTKNS9g8k7bSx2dzJjygrI905j`n7RF0F+#)7mnHRU8 z*wzC^L@{brM@h$D7coF`Lh_Vg6hp+~+zM*^K+#3_vuPeuT3fmjMA25Zvc9;gXtANJ zTB5R`xQnAv1crXj8T}$;IlP*N&@_y7+MbW$Cv<8U@0?|&ZK0%EI zK_bW5iRb8(67X&~2N_*YAd!NL`$?+ztI3g{yU?~o>fW-y)m{}`o1G#)=N7zA&#=Fq zU;asU^^cbT|0KKm-T3cJ%E{K@|H`gDul*~#Qu?>ptQ9Tgfr=0uyzoWSr`A1WrI3Jt zf_0qOL2t8pb`tTLc3rB-t2B>UKK~_8)E#B&>Z&vMcP{i)wO0_qqw`f zYmneB!QI{6-Q8j1?(XgyG{K$V5*&huKyZh9KWT(0))-^u&I zB&!kcnf?8fMTYl{ZpmQ6DrXkfov#Gbq+Wu0-J*1M3a>5){lJ=O#;62~%qpme@!IPL zy(YB*v@ZW@#vHu*>^^#MPSj{qySd74T1Af&6w*lOtd5%z$}eFpwd5qdPJ|lM+3S* z#*~re)A#(iOFSrwj&V{Ck0FVEqG_9RD^xlrsw-_^#i+XSb0u*kK-Zk6UWsxegIwEP z2SRMYv|4u!M|O+ARSo*?*jV;_?bAF8FJRC7^tnx@Nm2|e8ZNI&bAS~SmoHsdt)b2s z{OX;wrlOO^K??3W4RMAID_3}L&yZFG@)r#B)Vd4Wl8Sz&?0QS=00xz}I4090?^}Xd z4%_@q+spRyy0<$(yWEy1+#uJBagr!c{p@EU1airQydj!nlRYa^dAtO=XAnA!=<*2W z95SK-4~kF9Bymnj7s@=g-HO9d;l?@4}-#-+{eS>1pKaQTdHRkjoIgsoM^GZVN zN6L-);<|&6R*qwQzn;xYAi5OnWu38@$vJ+kKvLMa@pj=`VDhV!z~@Z?5CWr#K?rp?P4>h-ZP4$KwoH@yQPhRPvopd@ zgfsx-fx9rC8&9051X6?KPYZ4UTeteD1YSgY$X4z-Z0uPPi3+T9&y-A$V8**u-7&6L zse|iW3ZymI6q}1UM{pTBQoc=iGCQe!z~g!|83X_KJi&`stAhP3uHzrPK4QbA2-!of2+ccgCZ%y3NJ@w63QHGAAd z*q@!A9p-SpULI0_qW=V~l}r}RM=sd-26vm3Qa*Z+yayU(8tn&C#w@bgOD`Q7l|7vx zXFbfz!YP{IS4P4sIzvFl#1!szxi6Rrd6{Z@O4cJYW`zrRNoB-R!h?K;|10{%J?BRH z75(!5t)KQkyQ%+UknT^S)ZeEs3*5W-OU?by$xi?$$1wN@sxQScd*swf=l5B>%l^q_~vI4eaxF)Ci|U|282C65C?3WpY283`hF`C*ogrQ|ZX z9u>*>tF>DUO6xo^IYB?X(oUw0yhYvETsCoGSeWd>l+5KPA6a0RXkTKAW2PVb-V$Lu(<#+T42%zqxid*{-l%_I)JJ*6D z59wW?2p1+y10zj|gyuX)$qwgk#vAboW!(`J?GTFJs0rxy$J zyXA9YLC~DOBqYMat5Fl-^3U*)x`UMVawi%6Z24b~+GDg3HQ00)naW8HdE)8~3m)fu z?bNf%HY(PudraK|w1r*^7aQb0@3TNYUN%jvBsGuUi-$bi$)$h2-oH@3D=)U1g_6ld zDW0_yi{kif&aOdgxOho(FuTdD^J%fh@%>{1Mr_7P-m&deQZNBMq|Gjhwa^fbKP#S-#x-4hOVwJS4GoC#=DPlqTt-AeDq6rrX z@LxB-ckAX-mrC53R?a>1(3k1wM@|vRIR~3q8NIpYbzO&q7OazckGjoJ7Homkzl(jj zKC@5^%~SDI+aCv+s@!w_6kQ{Pkl31iz>detcCufuIBt@k_#oL#e>)Q(7~9L@>?zuf zd0P6_a68s-1sR5}0D0tAd{1A=89BiXC0zK7UOfRV@;)uHV z;DzVPK#Mzs#6W|B2zS`!3byIzke1I15CKH9N(nr0Txm1FU-$YFBTh~71sGubcwT8y z1np+e3@z)tdreYDRe?kZx|A(A!X50=>f+nH`s8!fG(Ay!m;@!VHYPa8$W3VPG{P=T z#cLxh)h-tqXRAu8m}jZScqp~vMbz~hJ_*U~p29G`cY0vd)!)6;YlpjW4D`X;MF=Xc zvc{!|)DN|kEFzu5qr^+Hj4&P75ni&Al7(B(8tgeHWr~c3i}|*y#uw6T%y;)Y-Q!6{ zU=|8A3thl%M1SoV{ACFL`>KnYnH#y;y8g+OYOcDT%e*)SKfX?y-QEYp(9RDwB(-)* zMHHcP!*Tc{jBG=Q2p2zlWh6MF6%|WjngEw8hp&MG*U;CE4D$%N?qz}nf>rZfQDodr z77<=wySh5>a$E!{p0?gzAEA5Ei1w6vv9)RrlqATbTM5|M_Ag6ym-gqzcl>Pktd_s* z(DS_er0gUyqz7P4>-g9=B=cp1F`zHk4{FJXi_pNqOMz>{oY27#Zp}r_SFYUN(|CqM zFa61GWPK~$pR+U10oOcVCy&(k3*l8NCx-Z%OaAK8407;6e9?D`URT?Rjs3b6KGg!_ zWP6=R9e@rss5}5wsLZIV&5}iPQQqR6)48ao&tQVR%2Y*!-rBy-z=pt`kNH+%cF~|a zQRXLx=^Zm|zUE5D=;UKSzk3W)fHe}KQ%sg}HZRhh^*KxvGo^a*GWq+j$KJ_~>E*R4 zvf70tR@2(L>xB4Ku5QiZE~zdLcVxCS#RAyz+~LK*{S6+I*kwBzb!O}5=Rbog;Dx%Pj%i zFQMG8bxsscZhUJ8p;0}#RI|6wZJgK8&v6VA6>L`WSQOEK=zGA9^W}unCgEAMbAEcZ z&Au4s9h>U~!$9d^`CdjgV4kaZhra`ZxqJsqV5WgGJ-WSQN8kVls|?@#(VHT=&++ER zqG7v$SU9fzClO*?W#AqFS@R~nKEGvGBo}guoor=a_n$Gyc^`eF^&d{YC8|5XZ@JfQ z-%PZ0#83t2eGI3&u6-Y9gk@Dlx0vBi7u7TwR4SdEn>a*OokWb8y)@zam`$eI3nZbj;AxWBR|U`EKQiRltgD|6I0 zV-%@0F_Fl-R9#u0{0{0tQ!8%{nrIipI|wY7O}d2~QoH0sG=^niaE1o{&I{Kbd!$Ac zJ<7RFPL}L?`3yCv6L%n^=wMhxI||x}Ygoh?x~g!ePbf7i<_j{-XK}Vn5<|{{3|`j= z8VuD+cv}d~$Urw;Y6n=`WVx{3Op2cqs6UE(^LNEz+COw<29n)&VtL^vrVHsu_pvd~ zZm`$`yjn+_67*jfgx*9x5Zio4n_TteplfFbWy}tJx)61&R6Mk3CtR6!67bA6KYG7N z|D`tlNMVUy`g`fy?`S-j`XF))s48;)R#p7v%<})KD*nnTP}ftzH^cDfFn}MsoNWnh zo5^|?Mwy?cz6v%+25AEe3LhM(&N;@R1%tnCTeWb}-xwhLKG*3a44cQK@JM!q*Zi4U z{{ea7>Wr}~8(Gn(@5yQNN?_XMi;sNT*4yJgWFQ^Q$71O7pY7P8&@Muv2|LWhp~Nny z6cd0j6s!xz_$Q%N`bMKntxc2aRE`>`3xTE8hA%Prq!1UNyblQ@;6%humgyfot~X+o z7r9+6I7%gyJIm^3?pd)a)s4!ut*DXK zBnM5Sgvil|>J!`RYfhuwc^o0mW##T2=x!x)syQ)YuB|A@#+HZV?F#*Ko1< zn2y=3;b~^>wGO1Z<=@ytv zVAyfhR~X;0W}=%h60f3EvZ!$V7)Su|Ur`Pn$GJb#smWZgkrW`mfH4;3Ll^EjhKX4C zF~CIZCI#}rftjvjID&IZ#b2o_mEx(vDz}JH*aQ7o>ZG zrys#%6}~S?7l>9R+IEa{C(0=o^mg+J2zq7gysZx`PbA76));FNf+3jdY0U2KI+OC641@6zCr8g_+JQd8L>uR`RukfC^u&LhL@16!$28 z=x&FcM{pK0FUTX!PVj4u(Y>W^!SoA4C$mf;1KuPm`hc-{HAK=NtEvapss$}CsFik) z{F^3lEje?y2!^fBGsq7jE>h?i!!*56(rl*CM5z7*xzR5K{nag<08aY;dQ0=jQ*z-= zif6>Whe6WdM!(R!{&YtO2*hpn@t00gGHd--v1=_dp4lL!cVO|PBNu3P^(jAw;07_= zb8Q#S(i#}((ETn}h(gb2?956ALhAdTBs1>90h4=rnO0crsvhd^hcKAL=^m{bAfBaG zP8&5$F8EymU3tl&5VfBgR|d-S@QZS4%#y>8T2I(*aww32+X>k-xq7XTNtIwC+pS!z ztxn%GX$2SBk#BLjxQSi2_bz4De;b=={B z^1c@R$ZvX4X?yd!oUs+i_IIls8O|0G87^&2rR{NU~( zm=D+0;57fsQ~WTam+bLt4&E#C*G~fQruZe8$y=ZO6!W5{pqDsJUzX8KpOH>E05_Gn5NuZ#iU z5iP-r0aZonMinfS_Oe0?7?qI_*?}4D_}k{~sb4aVOWUS*`ooa7=Q36n+JA!j(tPUx zADWvR9G-d*+~VHqVEyd>b`M(+VT^&gj$}d`#oLZA&JoPyEPbSe=7l(ccV^W-jpF;> zyJ@<&3ZYN{TiqZ@39BsubNrx6t!D~F)5SZ-sE*Ng6UW}IeT{_|Jc{B(ewm;}PJv9kcvT}~kzKp7z>Yh}L&Do9{0bv+Hgu9@6>oq@Te9QAIK zut>7V)E5*#K**L?$L;7!E=W6NSV%e`@RwfiZKA23Z_8U^lb=3sXQ2jmRx=CJX&^ z4My8uogI>R@-l%=XIVd@$5Z#yZKcg@da{qpUccNi+}gWiyY&(U0WcmSUr8G8>v#$b zkvY&Pbh)IfJwFmb$<XWsj}SSG9Ul!lCT@^^zuAdWLA_-4nc*vbumM#9Y5h(ZbUG2H>@5=7 ze07R~-2PnhI@x|*;*SBhCi_VOOdbL2Z=WR|hSdR^y2mFsw2`psx(T{t!n1Gw1L=M$6khY4NM|R=fHVSu99#ib zf~1S=@SH-(#3;B|Z$}IwB$S=XQJVZ7qG#79lbQNsr3n;KqmW~Kn?HbS?;Pd0t|MvZ zT&hqIAZVl#-cb`vRV8B02qjRld{hqYFK@9sTo%+SaOsa6M2H=SEvD@(qTPuq$j>#I zk)hzyDSYXBII?yO48`{)yCmRI7z<`n+A9bh0;8LuRnwl6s+_WnZxiI==4T(cQ|ZH@ z5jR>t2@AvX%9)wM2PkP zOG=gv0Ez>^pgXM4#xN?s)%`9^C@~vjR9dDwH4sDJAMY6?BJZlIIW0OI>d*&I949~! z=90@A{$43)Ucpn`bZ``*`3O$ZkzWA*CIm`vIMlT)#~ZmSxWrXj1-_ptKNTd%91LbG zD5xTkvUr?6sL9@ptsKwhN$+y}X0fig zd8}>-yPAR^BN(r3aa{l)&?Hgb!TTy41vw=NpsKcpYM4kOO0mkQML^%tNXLx*;f(~f zyO4nB0_UmDEs2^suqDzK$nH9^OW&D8rVGNU!e_MYoMVRN1J{i$(@cRLkzqEHY7eQ; zCYz_+&$53CwhX^7n;A%(4-@*d!EYK8ytB|+FG`!J=?uZ)B3Dkwin!m~Lcm!^6cg%t zZKXWB5oPEVf5!DC@hQVUVh9W{nnKJ}* zyoHV}kbX9?qe$`Ea=C?ajGR25S3Wo<+dvFLoub77@{b{3uqJK!KEVbz5Q=z$RYOOf z3e%IWfy-60ZZLK6X2ZsK<1=-l0yl2kYlNEOUsvZA%NY@dTY*s~%40x(&B^VKzu4Z*PqoW{|>I0;`w7n_+v2623w1kOEpbs0$OC zE!ljD{jiC$E_NzjUiM?1X+Azk&ei>pciA5;p5gR&Q9&I1jgM0$zhi!YIjRBo$k z)wQg%7?;%$DHxia8oRLxiJC1-QiH>sti~YUPcgi=aSzq=I8E2`X3y6xPEM;_B%4G0 z;e~aGa=vT|B07egw>LISjv;m7lDQJXPgP0>%5(jjM*+DvZ)Zy^A|K2AkP`kdXnGQ5 z9?@_^QJw1UsH>NPob>o=wQ>U*f{L6>b?aLD#%v+vMsJK90yC!kHnyN+id(Z?nH(ah z+K-ek(vfcA?1Z=>JslGa+1rB3aat@xvVBcUTWjIIgO~1V38BJ9xDt!Y?q0=0m>OHp z_MZeib>1S1-4E>}WHRg#hb@Qryn9tua0Hy`3bi$Y_ZDHVYSfZ)lRPPTj5g#R#|aMaTqhWtB2$hmbn|3 zmVp$jNSi9NmM<0n7C39R8Lw4=P`u^&k-MbYM4qwv55x7b;f zLKsXePEasRLfOHiZq3+Jb}OyXbs>;s*l-|v-NTUgB{yy0W)gvl&t?-UTd>%g@$|dM z3%!Z`l1%Ku0lOsI`&=ZNQ;-b!?{V3mC{Ajc3^42nlZiG+*miC+=fdTyccuYlU?mGK z!%ScsNDAR2<~NmX$mN*CRQm`$mH8?n1@{p zHpXigjJ#NPwZV9=RF-!tMy-D?s{ z;A_UH8v5NpS376Yp4SjFrk|eHgMQS0^eo}B?jaw%Al^vFtGvC?zX zH@uIg@bb0EOs`oznjN&pZC|75?l(QS%G~#x4Hys*6pFv|oPb>^AisUe|H_>N#&`et z)_?7Z{$dsX;~)P1sx;7({YTqc>R08355S&tC{x3j@!cr+_8o+GLMRx}PT=b+N{-7+ z;t1>%Dx}5A`zH5z>c_EbVd?sw`{4Hw0zn#Sho;6fLzoQG!r-zToVuz6cZQ|Y!e6*3~6ih&Gatx9-3!O>oVK^V8{^G(DZAU zP>@wB$67&IbYE0d4A&~mvcH9udd>HkO&(g7SuKp=b!ZK=-t%YFT;%CYfW;O^55s>; z{nUQC@`#ue6PV^EH^54b=<(GRxLeIX#-97J#fp!8LzV}Q!3U#fuURaZz*`_Qk^ue>J_1VR%xh9Jb0Q>(w$FPo&y)6>ak`t=;TRNTl-5rNsDhdqp=_ z!Zqq^j=g;kC%>2p+O_%8fbA+h--OLV7&5p#tqI?@gQ+WQUp8(uF6Ui-4LiVcovs6g zOF4h>Caq+IlM~xfAU9{@ftwxrQk*_7$V{eb%flsm+=@(AyhHn){#(jW;K7l$(T^K; z8v_;^Ov{SPsA}7+Vz)YyT%3jrSJUh=W1e)~Wz7!V2Itp1OS#(JBG6Jj*~#}=TJQH( z)m<84z&>L48Ir9BEO$P|qwleGH-gn%N`2viyySIXXR21o7{ZJ38)=fK;D(b+`28YM#<{Rp% zfULG6mQ{k9A&OYmke%0JjB;BLHtfwPYB(d8`24w3q2lB|@Wi7~qE;~AegCqNAQFUc zbyj`i!y)shSdMFX6?Hc0?2W%x6*PhG$sX$b=vH%o)eE|UbS{%2Uva4>2BjE% z0B>t-q``&nY`J$N*kBd-@%5jrd_b{i>!>A^e@* z_*H`cw`(lq>}=%q$6a<){-ci~WMy1MQL*|Z9>oVQg zomfB zm(YcFtd=ryW1p0%aO8_{X{x8cG9iwq5O)@GG7~XmQ)%SAzvr+vtSDv3FKogKD{Q2N z?|4NfX9D(V*^JFtO4s|e?f*}s2f|y@3*fa?DQnUNa=l7ljH7!FW%epp_@l;baMe|rSD>FGs z+jMHw5N5VKKRF}4j#yVYB{N-K5qW{}WqmLS!LNMMHGN@ka($2>>Bj3IwWJK(4CYv6 z<|jqXU~~f-cE5BH46P9~pv}Na9*I1p8;Z2G4aaFWKP5Fw7feM+@-rg99|JP9rI{)y zBL)GDivUiwA2Y{5J0<5NEi-w1lqAX?KqQGx9>PXsgM$l!G6ucN%OMUW4n+lpvTX!P zr2vHm1;sQ4SNgSpjW^{Wa4ttN3trkK#EJ+?pC%t!`YOZ<6iTQ7F$O{SLsFy=4lw5c z4da+!q6-g17Uyq~CI3%k{{gBvu!Y3I`5#x~U)cJ)L+QIi35Y}O>=i8xCaJ!a)GX|w zmCsG)q%4q$LqQ_S{co^?iu$t>guMciXDNTBQX)xw@(}v0Cq+zV78nxQaL>%x#Gu5WNKl9jEgakoTumIDKsGvX{0wu8 zZIE#nFtbdY_CR`jrfBHjpoLkDdhh*$1PI(;CvJX?&;6Sk5%V-LbNm+vuv@~EJQy=Z zn1WG;lBlBVO#57JuoK!x68z#wb5qh#Kiup>2p)6)lx1hJ-G1nwg)tw)wu#-HR(*WV zJrtf^FCL+`34FvfS7w{O_qr*XH0UUgwM=ajJ(0f-_AqM{F3Xuz_8&;)_jSe)L5K{c zOS?9WeHi2yz)>kXkpLyW^P+d_mef90q(XoOu-}MFm2~SQRa=n|so+*pg|MPZ^^1hu zvnCaO>L2|m>wqIM?VaJI0ppp5GNz~1r+6x^MG#?QMeye6T*fO+)4QZ>zVbHB+H)A~ zpI@meKX{2IF*+Z9k_tZ0r5s+wF~q(4!`lSv*7$5$GMZ|wXdJ#~zLKN9=owJBLSvMS zlclELU~eg&=U%?al}mbu?=B%n2+o_6&S3NftV{vZ78lqC*7XScOJpyDD_~iG$YcF& z9~J(8qA%}eXZ$}T^KOYU3czl-uxXIC?r6BEdVX8W-L%{y*ukUV!LTl?%oL7!jy9D6 z2bY~+oxSe|Kmdb7lj+=dlO0$0uMf{)j?wt|=^S;ox~vNWzF9P=rn)RC&;y(R>x>Ew zM)<-oS`iyMzMA%W9BUT2;2x9VnN8Z^T~DI|7cujgm%g90yTt3U9on59U6&b!K875) zv0~bu%BT2p93AL8;mql8`&lge>S{b1S{V=v#^00pVAo@%kz~5Dbq^4F`tmQMv0)8j zZ*=IrK6NW#FH{I9L{DPJ7nX#vPR#FhMDQoZF5%M}#irsXo}EP_`~L-T1!HTo|CzgtO_~69o&tT~*{qf9+Vmywtw?O9ZRrS@PLy}r*pS#8auX=Z zWsxPgvl=ct;P;BVW3CITXfQ#~lbLVdbPs&}djdeXMuK7q@w+%~ZBJPj_)xdx2DW*k z?(ql4W?wQsJ4#&kx;#4VLFf6@h}3_{u>DfMY*vAP>%@gsoUzja!^c{Fl$V7drkaqK zsd7E3nZV%$V3`%%Gh*b%Hf|qf!V+Z|Uq-YPt*tTD1GtNKXX~m)bi<0!dM1bxTtC0Ol7>Gux&igCNrYqKrSGJyBs zhgpnRD_4W3H{ThDSjB5}{Q@ z)Nu5-QgW`+F_(Ww9)bg)^(OI)L14MJH8w^0z(qhdFg)5j+B*mW#z)^vKhoRZ3sR<4 z$cCR{9zI8)n1wFwB4lOHG&Rr*zkelU<>O9Imp1hhVqEX*)}G+4sI8RBCAF+TlU zjQ>Q%D4QAm)6+1E=ZE{Xs$t90nC%riI2c+I58Jj@v;jp(vBBUQ87yg#9GN#eJo0wo z;8zHI26J<-^RtYM(Tegz4 z16Fg%F!w^o1a-6!+7Q|ov^QbD1=P9XG>33aVHBP{NXQG8gdr{P#Au!1+fUOTCSlu7X^vFq)@#Wmacy6o zdHHSeG#7{wMu8&500iZ)E#999-5-GbFE7DQzE2vQ86#(*)yAgQ`(jT^8yV5F){_>4 zE^2!hdJxAXjh*&u%~8GAuO{S+ALd3v(k`R22UD_})91^af$#)nT$0S@I8ybZipbJ@ zbkj_^>j%4fj^8{}4(7%0x4n+(KNnUn;+p4rm@TV~f~ob`!Rk67iOwdyGYEUHwjCXz zQ#Gs|7S{Y;y#Car5+{y&cCy+K&Yyb86wg##2lbu8RrA}`#65lJVh$Fw`t)=?4cnyd zeyMg=url>VxeRH@Rem$ikYlG)qhzBE7pTm<<>3JpL=A!@yD*SKXE#ea!7 zx;T)q;y)lB@ax(>ou9wI1S0tHZxQ?xk@{l4iOIU`>Im_gq)50879uQu z+{Ok^NF*9R55v2Z5GU1r)+Bi55IAt~yJ2a?7a?gJ2+1$g^4CK3CvFrF5;qf9H)pdy zQ2CeJDen%&;SS~Q4uvERRk!^-SG1@4aWV(!H zE6j&XnUhGgFhv28IzFU0DEJ+Q%bA&&8k!n{8Jk0)0Dprf$s*MJ zz7c#*epybymrnwI{`%z!fPeirA5h)M*3FE9`Hxo*Q;~B34%zx;yL}sUn}1hA%AhEH zEFoaI?#v)8i76>&#a%KL1i#u|J=nKG*``G24`LDb98M4@f&d8 zo0)reJ9YZFeD1IXx;~Nz3ZAV+Zz40&7DVrU(AQ|9SVEwXicrO4&2z?FLd=ziE?~O7 zFC8t!dp%7#U_5ZKCv{!L@Kj#(Lz!ahr`=AQ=vJg3=0blRI#XaD-zDEyL02&p$*2@O z{tIzk?VjGdnsT<*Q2eo}7x3}ZQKk#|dd8ACJ;3RT*$Rz@xyT5&XkuDD`OX~k#6HDW z=dk6*yjGt%B;?46(L2#SfrX41%9WJ)?{{q zw^>ko@2m&dJ;h?7mrEaNxINE9Jsi_2?rV7cd|(`(7cGQ6eoQ+xOLDQtkYF}DzH4~{ zze3HTJUW{rAB+~wmR$@%zk|1{ArwaIs29{aE$Nrj?@ryYiX-!)xPqOMTjbVyi~bA_ zw@BKuiu|)a!vu$ne;a&tAJ&8s)gP8nWAG=35o6p;6nC4tQ%Ji56^%Ms@?#y+nuf3& z8c(P|#@wU5aJ9gaH~x3HPu1Ie`I(GYFAynoG$XkbHsBt~yCxS8rX@#2yYEHb=p-&? z$A3q@9~VXu34xC8*56v9zZ5f;e-kq~pqL3_%q3valwxEdmZ zD#?|yjYGYIvS%u>=gvdlFy9_hPA2u*&X)$1W_=rbdMRhXWfPq!m25ls7`BEHRP0MA zE3QXv3KHVB=f%S1D25{)g<;Kqq1)ZyQ+WRM&e9t0bR-vbk+XfF&BlgN=M=+H1)`9ioxOFyAd6xVxO z=;xz{S6dO~s%C@d&iSa=TNNgwsiBAXIGB^aAq?0*Zo*l5+h7IG8uRg)uG|~AG|Eg5 zmB8;`ryN)&cwS8Y^@;_xi8?@H{w01U zOH0e9{lhx82?kw)l;3jr#)2>+P|TQtV&)}W&AjA|i;wrIc!w`LkMZgdBE^PgB$dks zUE|ws>b)%=nk({&%>3JU;^*c+SOuoZ1%v*7h#Bkuh}j>!6v2fe~6htSimTlCPW`tAKD;x;62FFDeCeUnkZq2v;()pJl4Z?+<=Fd zSMWgm6%Io~@(@bhS*OJhP}wfqD{M5%QJv0sn1pJC%Q(s(ZI_W8Sbr*aj1~OwrcN>{ zwC}pCcq^fNF`0FyNvig-+hGfHkg)ls&j^3%Ge^DSa~?7n3bCl0JWr}Tot|EoTAu~> zu=#X+P7j)9@&Qk`=Uvs4730yEbcFAvm$pY-;WWyZRt8+IlghO6Z3H{+HBZ1+q;TGS z=)EDE8?vzgJC;dK;aPuQ8u`>PR}F}bM60S^P)Ol=)W^0pqft6$@+hSgni#NiHb#Ivnh&Rd+NR}FpJ`4HwKX>R^93ic$0YOgFUwk8^FFZkOmDp=D>g`vJ_ z&4Nt=N<&l&lpgq|vR-z`rA?9xYq%#juyQnlW?8&#suGFs-ChHNy4&rP5q}t29&_xKE|q zeCc^@4>n-qm?__sb6Vpj8XqKm8SP;^!;fUE>X_z&YBtMY4)Dh|Kd#%e6sH$B4`WDb>(b%!iU@ zGkZ{8uwOB7BXME@$o`iSxcNR-DCA&vmpOSp`G@OQ>po9c%jxGJX$e=tgHgyI9d(2? z`}K$cj`3mbF-F94RGPz8G0XrP7BGbK2^@=z6jalUB<4OxJ@E)5?S633Gu6U`IY`e5 z@m4det{ z-x35aOR2wS27@$e(wJH1+Db3N4Eai_K}yc=r)ZB`f>Grg2>ZvQHnCtv>XYfoF6%4d z^H-T=KP;W4X}!nOQNv4Y|8ighI)TcFUX6F_E^D*I;KNJQquHTQs}^JZwL(XBMhVl- zWZBf^jV9?T)J$iJ9aO}EJ|jAIp*XV7VGUeZ?SIJxjKE?756^is6PeVH%je z2q%QWVhQ7vvcGZ2c@!wuel;~GLE~SXIarF*vP#+sYNm(L;&1VxzR$TT=3IL;A?A?nE-W(CtOO)oo2WPsmK?Ml#hlb8`` zgTe1>pL%J5;&iDo(hi_H~k z@s{HZdo{^x%x3}0g880H-d~aW^x-FF(I#~V5-D--M5MxANizD-loU4g29dls*M&^Z zweuXc%iQ!>;2W32%zHobGwb=Vr6CR;_Kgkk^fI5-qgmI=Sbe$lwWDQMK}1ArXp~!p z+xN2mK^UD0rHn-Li~>U}(rlLqUfqN6CyV>nZK2r&>CFA|AsC|TeW`n+zt>w5!JFj| z0&fM^-!|m^NonHuefUHF`u!?RD5CIV!-Z+1Le4&dh^ekf4weo|L{MZwp?gsbhTTUf0@k5+rvEkUS#%HtRX=kyDrZ zxoCinhw78N%4b8Elx8OG&j?!$X5_Lp9`EEft8wL`$)sD?&RaddV#u2od5~nyVX0Vft0sn( zkwpz@(L!R%G=C+>WbPX-Z$y~giml5g+;qlGdV9kF7|yP7O5z*E*)Ji>O-iIuQC%<{ z6dI5j(SwJ=)+hqE*cjt3jS7Sz@5&(d*>7#*_X>uJsv8Dwqp)Zdg7(*=c=X6ygqDEF zH@#oDO&;eQy#ppIN#yFKDD7Wmi_0MtWbw%HcaVQYcp%3K2;RU@CK`B(e;pD0Nrb22 zYz3rz`r`=A61spbi8x`?Th&W4-?t04>!Lw5s8I<-9Z_86WfIbiN!#@Gr}}`&;6aKZ zvG6zdFC(OTH~xH}lQUPdH>i&hFnwxerJ9ms=b?R`$rtdS8&7p}R|XO z&ZP$p1C==I-$r+2|EcExfaA|n2ELUx%S+lfb1Ktw-b~xAyQPX1n%6a_wLONByHTLR9EIy4tG~Kh#(&w^ZK>mM4-TrQ$Ms`K&4tR!^y4cGcg+CE>@XS!VYd813|0Pl0&`&?E zfB<#;EriJb8$uUHtN*Isf%HGW{;P4}fA3^1)v(dQ7sK$UhTsS#p;YuPOl`rGqoL5G zPm8A6pMw(qAS@ze*JYd5z;-%31;|c6nf_^Tgk5p#wJ`lk?Z?N8pENZDagxsM@}>K{ zW6IRxa#`^63(_``|Mf0Q653LaXB47=v-^rQdQGY7( zL+6%ZBwTxq)o%cHhrOGH^}-@^hN&4?&#$1)t2!(I`pb56@XNHcND5UK1C@mgO|k@; zW}HsKz>3nWCbOTdd6ygnX4BfUdYMamy%;;h&l)*nop##`iFmkd=B?E9T3#I#7GnBn zw-iUa^meTG7%Hg@ZekoR-OvLS{_p51X2yo6Y1fP+p%6ibQX0H>F`@P4v@Q zFS~0LX(bSfg(M^XDV3RN#V zE4AD@RVfnl8_{gI9oWxOlGjucMH&rE4u5D+rsfR4X=Gb-(GyTT?JP#5liS0E5xI_4+ zdi21no;}gUH&qwBVgqh@bBVW^${!sOmvOzn`&JxRpN0h0ARB~WY=jfg6JM@aw3}oc zJ7yV>tZCa*Pd*q?b9SarNpk(%L6Hz3aFH&U4I6cAEutBjJIXxlw z7RMT;+SZ2p-On)VlO6svqwIIQN)h{?AhG$=K>^>7`Y@9;q+EoAsn?$^#MAVfViHU# zvZ3Ys{81C|*}SE|;34z|<+2`ZQ8vYh$J8MlC)|6zVdq8LOtE$AXIr=&!8}gSfTKhA zus_(WjPB9v@?Yj`Jky{QX2x4fIW51EU0h?C5`HJOm6{Mv|xpft|%mXCtCqyrDyqw?}rAU^lhiu z*(?f0!gfC{-6gbihm4h#)>*$>WKIA7U zI!dDwdUd6h^JU2hrjy$`OKdp9iEz83@B&C@G@ntWE%Qbt_2fh@Y?GiuII)~2pVA&C zz(xGRnoH#^3W_ycx>~d0A1J7l%}Rqwx8kUHFqY@q`R@njD>E5LpqE3*M1E{d8?6}3 z;mz*CNQ}-cXQzU)x<(PH$yKqobh!mU-I`A?(;V1+lmZrwRn&8Ys98<@`-v=%X8Vy2n;<7;jHu|0CbZYv=J$Vl*CislGQU=pfB0M9jPn2O zVE#!Fm7=4t#)L8Q1|>aSO6M9gyU}iz{WK?;oWb_PYQ3tdvf45X;{7N_eTj7Pm=ou{ zHQy=t&%!e9Gtglu?T9kIXIqIw5BXDcgJ-@s&~3zbNV?GP3A>$tW)-fiZ&-i4L(cBH z5%1cpU``RZ8RXo7Bs=wHsC{mD$}4O@4Qs?I+(hsDaL|Wq{)x_DA`MGAK;UF7&RlaJ z6W{mbW|!vLxVGfThu2&;xlmPDV!VCnehYVQ5VIcLUr{=TdG8c%U_>Y8Gdy}S1D{&n zs$QFqhOdR5zQGZ?!^ZiN2t$|h3-wyr>AfFnNmEbHkoq)UdosHttIf7hRxj)tajXyu z)7}qHIzDsHk!DWlA@kKsL6dWrdqxE}F5m})QK9t$_?haEM;SWcB-l^oXMI9L_ghBxy-dLK*pR?-NLsB~W=#+b zwPGEyV2M`?yE~u4>ZUAv&{%LzWQAp!?xi=(R)|hhz~qR=<~*MMCV+dyuppBPLR~^# zV!Y7ldux=z?zJd=pGK9g+5=nk!xzwfAzJtZsu!*ApNbD*&n<1zn!{vj{hxjjfwrkbs>b3xm>Q7SK;~qmf^yj zN~m_CP)5!V5M~?wgY1%+Q~UL0{Vl)$)3%NrB}3?gFYz-YZKmc49)LZ>0IGum1_Z{1 zU&K8GE{G5hBs0bqnni8i^96z0U^F(pzk-_b+E@gpa}@iLPo8wwTSA6tittFrmWEZY zuUTcpI0l@%iq`X2iUAPu3#7+i$Z85zXFh$JzTjeiJ=Hn$otn#JNerb_J4pq|7As#wln%`J^aV+ zNG4VR>Wlvh{Zv?B%x~wPd6*YegYZNs1DC5ECy%@ete#u*JO#j^T#pGnHsF0e!G6xE zc?0eR`~}ef!C;_JCt)>oQa8~?_Pn7ZsJ?z*x>2Xpvq_S6rs0}W|7{gvU;4XGUrD=3 zKPP6Rqzi#e)lzr7n#3ymrmzv6;d5uCUsSDQpm|aGAc3Uku(VEd;>CSV~?2 z3t;;s(L(As=m!`&t#+GZ9*IK190oe= z=JWUHlTBHKgD8tTpZ6<|O{eKBF1?#bxP35F<><0h*nD^=m|s}3U}L2X zBY~lS#~E0LlP%0JjC7XaOmr3)hTT;LsT>ss!5$hyfgB|SW1abiD)`1Ij4%D3q&YLG zK$owvmy4kNQL#oHPN)^C4OT$6KYuhC@krV%mCKf^y4hH9H3@&J(X^O$IAA6fm#S7L zuaWpvok#0dH_xH-ukM@}?&>f)~^gm}km3(?fYjbXiJQ>aav zN}RU6bo~TG(_ORFZpQ=?a)Vbb_Zul^Zf%MezVjy-*M8`xK^Xgi!?m)yUAq<7q>zWI za;)irZ%;y?R7ClsA&v3ec5O|X4E{$KlNOCeGRp*wlOkQizWN61hVO(Vj&yRCqmSn9 zDITkibhU!>yFnT!491bnNI9GK_@Pv-KnA5s=dRS7p-V{}k4v0oiN#y4f=w%lSKg$H zsBe3;lQ%}eZ=mlX4&WZB&a`!(C9ntIpbVt<6Tr#l@P+||q7C8*rs)UiC+Yj+^u_b_ zc4up*X5X~Sm2oI*x#BlhPRECT=vzV5zSRv;*2X5lId*jg>k%}EN{!)bb4X}k?Vs&&G^Vx!VGuxa&>IW%d zXc?=+Dt!}aI}DSglvud=B?cnRBLZkTyTMPv&UNfhb{Tm0NH}gGy6lCz?p%#4!l0JX zJ>aW7rsf;a?>DI5Ev$L%q%EW+x?>l-Ym;R1Qk9r^`2Jee@x(3BS-)^*n!jDu{|5;1 zUzVSL%*B7Q8wwMDs`Yq|SniPImF1lU!UJLwTV0HVWkL~{2^{vSrPK3_ixV4x_cpZu z2C40)r|?krzh5CW--OHa#U= zNfCDmzm4fQjR`l> zQf9m&7>!qp0zP%TZ>;P`_xoQV!C#!q;ZFe*`QPSZ6#qZ#<9`pcadVOb^eCZn$JSe! zP93+PAZ5B3h>KB?_(6TbY3kno7)CN>W8z8COu*I%cZI{E(r0p(+2BcxFqiUj;lI{eOSIFu-cP{osnz04pUkae(Viy6f%D=;}t zHZ2=AYsi5%{N8I~kuX?@ev1MDfpE%afhezf1lF)8T=NuX8&_5qPX#wf@DUqjLpH8XOA*oVN8nuZX#jn zX%LD+r4N!pOrDGcvV`J80}4tXIA8B~Br`Sw2-TkxS7~cZCzCL5FApDp`p{CK#tb|F zs7ydpmZ=N$GjVP{QDU*z3`tftzB71JuBTq67@(}zsbs-ckVatyEf?;xjU%->@x}{B zx(l7*KqFRHztwbY=u5*ss;20*ow(l`H`?lgIC~r@m`KfSgTQ0M6AQ7LGUM{@!tOBP z1sQog8-I2b3RHa^%ucdT50)|W_mXR7Sqspofcg`Q)bjpTT&5%sDn_IXS9#HfPMPxO zj@@4WHP{cIpW$a_o>Q$9%+7~(xkTVHxgw!UA83R0??L1keA$vbu0+GkuUi^T0Vc0{ z8n1SZzH>NvFnio!r_}P!UoDvYbLw8eOv`$C+)Aan;wN$5>tq4Igm{7_rQa49#B1Wr zF^Gssw7_mmbd#3UuLI{!;*Fkq~KH}~twC;TnN2KP0^>>SPL{?&p1 z{~|Al{Qvp&UrkT{FNYxe-wz?^VrpvQC~s$HEn#E-PxZ=VWvf3lpYL?DqG}|4H6tHLuMuThg=P(1H6SPz&N>wXTqCP@vm0Bt$<1`9-PCrb#SIg5daVu5XNwd|b znCQa@2H~rqW6M<{EonyAw3o9ya?qIe&beN*q z7MsJ25Nvcd=G+wsy3Ez1Hz2E2TNeun5W!gB*Kh+ z*38Vh^=0j|Ff!J=_tW3c&@eUT9H;ASEV7);&^MW82Fw?gYLG@$8y!y*~=pHfn z{t9p~*@qcD5j?!Q@QJ|ZP!&kHQ`A;oGnan>>jHvLeEqAkTA;3TX5njjuK8QmkL!P*Cw~y5 zzZ#SNS=0Mxwh;g4m;ahOS!x>gC@LsCcFoh1%#gv<#sWYQri>9Vw7H~TJzzjViT)B0 zU@Oyw$ehlm{r51zt^3{AZ-G#j$to07`Tp^aWp^WYLhpA{?~YWTi*yy#<8SR=>3Jm$ zyCa>xKG!}cS5FV#KF5hO0NRm8fQv#8MzF{42qkljDg= zfZd_vmlGXrQD$t+MFae;+=d7T8pcFS^zeRKS<A1j+%dwthQq6FfWj6n|gc*Vwi%p1T)W{xL zWlW1BW0a(n;C4{Qjju09B+y-kJ4v}WDIDy!wGgaf#UfnPFxID*Xxb&XAYa&)m-Yh- z-xd%dmXZi+3CqNs7$QLL41As~onv^k_YmdF$$v0bSt2LU303RxFM*u)G*L&U9POC4 zsWl$;W)omX&&kWoBTpO`>7YKu5KM8M9q&wFJnLAH6s-|k!Em6uJVo31AyA>Bop^!K zekX~~S!gn^NXX;|J~Jl}(5=jx71x2ni%_0X&tW?+t37hrt}^%w1K}3P zoN;L#t4wL0(If0_R?oZ&mlKiBkiS=oP?}kG!ms1N!o>#oZodd&7z^soI4&5 z4^PLwLwn|>h(rw8^^9csa8z@xv4@*yL08wDKxlgiHl5prqW6@p`r)M!U5>VHC-_UK zfyt=Bx*78CL_t2e1FoWY?E^xl0GInNC3rAE+N8Vf+;@@ttRq39E~Sjw?j&CWX5^|6 z*SFKNVl#G3ezADxS8fk}I-khhs+IfK~^v?@w;I%CX zo#Ps#vWLFqnWE{Ucl+B7hu(F^DjJAus-hoIHlCw3=K1h)_r*T#0l6=}|Jp-cyXDmd z_%1r_?e5F9T>`x;;_@xlji$?if^HY#M3L&6^F*@^zXwA@5=*-jWq@zIc{g|ASO zT^VxsLf(LLxZ9AcV~W%J52T*5;OqTU(lp$GN?Jg!aM^*4vG4mDNhr(bPtebG$X&9& z)LB<$S=j^M@xt$j);_*!oaZ!m!MDhZ&j-HHXosbVcCFZgdmVS4g+>io?5BH+B-m`h zmlIVQWn{P;rmCJemmWo-Pf^*ASkz}CJB&q*=Ebz;=hH)4nAGOyy;pP+AXoIWW9@5{ zh)55@TQY?Y!s}1o8gUpjVZ-mJ5jLix6L(r=ckHT}!pS^MpNB=wlk+O3MUP;c*7?;e zV(BOB<(DD8q;{zul?I|aV82-0ieN+9(9Lbz`(-+*E%xRtxMQ%!Eo^=>tHQA&x4xm! zp4vjr7^2DqXe=@?=M0`VL{gFi>Wh#Y`X)61SZW|xrKYA_i7GiDsuBbkD5}f0ghV5@ z{t$gJOSKTJI7^VDWAoyVJ#5==(7rXOxr*HQMh-Q6f5NK`;l1>^U z9NJNLa7s4hO=(Bu1JPfGP!6`mZF3}(qpjh=FnFd^al(;&#ZB6PeC7Jzka*+l)AH)+G9*KpFkSN8ShMuyJrgBp7SiM!G-xJvvy_lI zX!6ZqL)S;6IZHwvL$e{$5WU-Dyh9({66?(a7$;Or4LOMWp`N^Ae>B*z^Cz zsRdPX34zizy=fH6d14<5jAl=sM|zNFKvY0>KqBxyMDPM5)KJcVb3S{ZvtGzsK`I%z z#1V!H{74E*BTMj!Y|jyG;Fa5=Onq@=>qD~j+Nz}{(L#I0sylC!scEt*PezxmxL}%> z%5zT;By7ePCnf)43!Nm$p{h(!LT1`1VYF7D+{tVJiJw=4&vwIiov0*=pC77_XnJeqJBL1ZXiUYQvs>g{%svf~cBikO7Z zy*i-b_2i%{X%Zw9;fEPJx^?Sy_1fv}p3G#OkaDN7HD&1>Mv>9G4GnUB8#o8C$joJT zR0kBC*XG4_RSZ}$(T=I)xuWW{tLXcXz_5=}1B>54I;1?Sz(a}I|!+gwJwMz zn@Qk)wEUO(Qr2uDPpk6D+~tBRJ3>GYCIO!5ce}bQXy;0m*adx_WH-D(*CV0{Rj4=V z-0rXecxby~AnrZlYh;SLfrlX6;=N|_5d_$^bnrikb_;->QPp-~WqTEXc%^#n+JSl~ z{q>N0abAL~v;*B(imkgj!eH629nHb#NN?7Exto}hI@)g_8Iy4*-;iqG#zJ-;h`4*D z$nOQSiMTtcbs_^@7xreLT~tA`ZihWFB!#JeVkA%Wny~IhIp0IB6u=|vgU7H9EYRis z(uIt>8 zid2qXcRQnhVRyq+sT-Ix{%tfqtH3Eoj0eqH%3_kPD1N}Gym*oK_E`M48?Zdt&Ze%woO?2 z9oHhUvDDAF9NmQ~S@~F~@$+P+wecC_kl}>DH{nNrxP38f5tr=zbn@wS_&%ZZJ}E~S zuBrS&E><59*W5k6KPXr~almG8n$bUwne+Hp{0*?RMR>dU#!y@5x zYAlAqCUM@;8rxjL$sfz14-_(aT|6F&0vwdmp-lqEjc6p+8a%!QD54yK_%DlubyZoJ z!tpy#*QZb4>&aEW&-Yj0U5@NB`CIWJIM)U7gSu~bP>;&Q3i9&Gd81|$0vdhDp~@R| zT>ZxC7S1o|)$ra1XJnmv2I6cX7EXS4jYRZ-Bi{Mik$euHn5yH13uU6 zXalkX4l-MfttT$QZq;r)Bg-Cor(#5i1ZCy5A%4AablO6C+$Q3SnM^{s>Z`*W0yQSB zcpek^$<_lFP8UfXg3|>)wEcc`wI zzr_a;-oxSzIrv+p<8I3@!1|BxA|0gYjA=JRkqmkySGB;xC6u7#E{ z+ii|%k9*n4$vNy6W--21?&}7_(ZXWhT&#_R5i$^{E1pkgoi~UvunX{Il%X&q*X@9X zsW`arM`yC0UUa}R3P(Rguji#znyRBF3^7^|t2MrV{fMIs`}U4TiD8Q`iYdR3Lbm{q zG5|GI28Kd*TKv=e1Wg3boKAE``V6V^9=Q&BQ0fSpxEp-c6aUAk6c&}SHc5usYHo52 z!l2D2V4!%n|C|f@6X6?rxDtqYPyBD~*MLD1#U0VnUp~=5z2miy_ z_J2u?{#hgPpG5P&24u4G#UE$ek7D%YWk)J?1OWxw<_Qy26cEZ4kRTKS3d2D?skI+N z^&8eDlz!guIsQGV;^M@&fAnM1)@&r8VM%0WGM!wfpR&?^U4Fbjy}|oKQish2Mj)g! zP)tG_=u)Oa5rtcT*7VEM(*$DfO+nbHx;H=_qY$HZnwnFvgPn|M#acKlj5E~ggce8J zn8-kBDuunG>rgo`)!3YdaD>XQPik<|aexizKP(htAG=VM6mb9^A1``PLS84=YYeQ_ zUvdxdkGnc*($=6yX*9U!;-J|`EkGAHYp)5D$Ve(!1h3YcblvOxQcya#eVS{=8jR5NO1# z80Mr+x?Mhq(UvJNvzTHJosN-2hDpTjwy?tcmWVyAElAqkh9M#gDz=mrrS(qv#Mro` z%EVmKmi;1KHI5wTj$ukG!79}$zi$D#fsnjI>)^n*0z_YU!QY_~HJ=8&MS-QQ<**Ve zj#?9*SHg=R!E1JdN^!$-;S*oHge#{#_hN5TUETiW12~3JQJm_f$5R&_wGYwGfG2>0 zgV>nI6Nu4{vB;Uekw9k(DxC}A59)bst7zeIolh?XL(~$-Qg(2co8c8E8hYjQ96IrI zZgJ&6uv$iSXDxp==Gksu>3y{}L0)p;(>hjd!IWyg@T{$~A35u}kgWCHUD$Wf3#}-7eCr|c2}5o)GW!uyK^eBRXZJJU6f_V|Y!p7T z;0&Y+U4DEoYvD@=70Fel8O3RWiUxMpE-o8BzNQylOO2iyGiQ4equdl`h0%7=AezVl zr{J6c?Ns!=5w0y7C&6LysMRZwRpM+YUUS-JZ0#CInLUhKb}vRhiSur?Ly`6kW4No# z3MC>&fbb@398o*pFX8kmH4wL*i&WuJ+H>afFXHK&Eo9EOFGTzh{O_jTA3o&YM1udE zdVe8p|7_umQTF;mrcpk(Y$`XX=@C34A{B9?#z6q_@E!E~4A>?$=|lafb+#glbk<>S zkzZQUF^pjFdf`pD&C+8*yotMdMlRb74I5(&{ad&KTZngjqY`R$#>;0lx*kS<=d%qq_^`WLOzE$;D zxwm|&uW6}#4K?aeVS)IquaT=|m%fZ$UfLCkD}rC}R@Gb2_HCMBbjfBt8z)tUj~thE zQ)60;r8N8KHSb_a(zW4Ajb!sjTna;&2PV&HvI9CaBU&9X{p$&m@#aD88w@-KE+aKl zrM`gvIK1Ucx>e|&6dKR>M}bK7*ED|y`I&-N}qeJvTlBfokHcVhb{ zAO5UxCh#QQqC~Mui;0M|&FsgghY=2I|wyx%)YHVWX z0!3=O1oG>o@N0fE{&sbzclIup)~FhpAt1h zGErt!Rn&k&J~o>}7zmqe7yC`!&As-R6Os~>$s8snRuxMresZ;l*n4_Dx|A#lag3OmH3W5)Ch$IbOe*Qi>IGj4H zOs8cuWCWPdq5s}))gq{*q}00MZ!O&L2yj1tz7gRrOfxDrI{VeNmWJ!Dv@D-b4%gp^Y2})HfI|B&7S|lZf0sO#^bleu)Wquw#DQ zH(7ROvApXvwr|y-3zehr=?4*7F+*m-_iYCpbD({dG(_CzNJ*iey$`==Mvz+;9OOXU zRA-K)>y9>lY%~FhWuHipU~z6{uitcubKg3hM=fRiYE!8?kOS7z=9sU(|E__j@%=|E zHJo!{-nn`}^?n>#y)=%Xz-wyt5$vR^9kI16W|UlLT;XpghsOb^F*y@)^Z{nVOkHDd-Kc1;9Ql0!j1Pg>j{1T3ncVObHh**> zkAo}I@{d}q3gppTn9KS}UXx0px4%GtM82w5!!LI3$JbN*_bCAV|Lqf0GP3)RX1L_9 zX1H~E6yItTO-V%XXc^~gYhdrP_O=v#i0E2SA^f`O;GYAEb&Cn}=|CUV5o6lT*0;ZW z7wesjDZq@wlz>eq#eK`> z;xYS5qw~2nX!n#SXrx-XB%+ym1PcXIafP|&=rNp!z0rKX)-)}a7sFGTBJK##qQd6; z*bt=c66Rxbv4RdUX8kc-SM%-mzNeBJqnd{YXv<54B*p3=6=DtM9ou!jKA;^6_h3O? z1VJ@^pA3>i=-LGEETr{DwUA-L+UB7B)O+{Yp6H1x{*!Ne4F5lcH# zgL6*sJU2R2oLsa|!dn~j4or3c{nail#xW!h=}ZbY&|74h6G%6Lp?D(fOC9jIUhh7; zA2QR&ia3zqm)!da0=vO6(jKnH5h3i;ZSVI5w1gv)WyD-?gkMroW)NAw!)OzD=VQry zWxGO@&kVM1Ht9Bt2E>V6S z?({nJ6b6uU2Fq}hF$6gLG7D~<*+<)t43NZ!l7IDYut|g?dn7Me>ryl z0qQkrf@^D!%;k8fZ99BBwanZ+(^I3n?LaLYpWErH$PAS2Do?c2y0=f#uH>$~mtRrglb=k$k} z>tkL@kMBMN0LosNX)A(}N+ud;O2HBg)UZe&C`Qe`GZO~G4=N^g;@Z?PLse!{L!^`h zjlxuk!tzv8FskWeNzN!3rs=*m%4sErg=n%}Z>GsXP=!MLC>4_m^Mm7WOojTiY$pyb z1n^U43J5VF>VrjwXe88^O;KwqYY)sM<{MB{#|*1l%RA^W zFYbDxZoGIf_FTz32r*ao#%Qk6akH12fjnf;n|nslel9x3{zF#}q8BIxTC4>!AVZHSg~3ZVPWkV4C{XJXp< zt%iQj&Ap$h?104WTwimF5ognJp^bB(XB%flW$SUi^=k9>)&aFf@wS6fw`!k-nIN#J z@5s^J^6gScD3$=EY5DSw)74$26RmG{{Rr22)=6jMZW=21a9HWGWaF2PtedY|&KA?* z&GE`>_LrvwcKQZq239)PiW*yW#dW2QMprYcz?ym#eUP4nkeSs$=<9UzdHS%Y?~1>E zwUzqZ?DCrG&L&oABlC*V5IL&t7U$-|!A+$@#~b1?OFK{3OILKu2*+ZI-+A0dvK^lD z@d^khBF2I1_l1iae085VNQaKb*^bp}gYP4Ica~Hl>KL};D#WVnqs*=~8w>RGt2t#4 zC73Wmx?U@+!R$MS1G;8@zF7y22H;&$mM)L&Ker9w*Qz-0-}miGEGVW*3WgGYy0s$2 z{WQ`3>CDk3g*aX>n1U8yQollUYPGcmVyjuOaAb~)yLx`pxYqKhB;{SuF|pmVedXY& zW3}k@mN^*pf=EEt8AYbw1mguB)>WnZeSjB%f<4PC)z#SanFC=N&*rfJiAk`FG^}D` z>(cpQ{_61_9{vF_i5l?GIS~~J$P!!g+|8K-tV^~f>SnN!5jp*5kReTE`5=29Zj)Ch zjh38?^PJ4)23dphx|Kd9|XA&AY3b9dA`sud)cE>~%f-=#>nnj5P}V)O;Vl zNieFx{kI%br|%1MJ6+q`d_Plnjc$lx<0lQ--%pV%BaMML3H#xyqs;Ab`p*kAjeD;y zCu$rXS>uEr6QV>I4<>Jfh!m7gP95P^-@c2*_?f#aS%;6JU>`c0!_S(w<^b86sNTrq z5@F*aiVCUaH1uqIcNs@<24QD9bBBORgx&7dKkyF4*%KF7t%93MqU%8_j+!tv5IRmyR)%ZK8?8EUXq~Rw9SEdp zAhv~QSXYa*1=|ax$3}q0gR1aa7`J<>wfG%tKK1%%`4sK&3_5H+`Ib)bo}NC&5P3dw zxXPzg#p;qB0dj(W`PIBCxQbv>VuUru&S437H)-q{IszBSYuol@{F0C;5m&tg;amr_ zjn951IKc#w5`*Jkm{>dI;)3jvv#N03y-Lc#-)p>Qe|xil;|QWCnY3J0r*hh}xHtOl z+TQLVK$){_wJDTev{KaX2HCe??MpMn(9#~pqZ4~1`1Mqn~U0= zj0W(!9~+^*Cw^c$mx9`zZF@leL%+{!4;1>tzvPXH+c4m>|AcbetWSsCFo0pzETBi8 z?ir}Nargb%AM^v(PySW_nl~6;>n7}(Uhoy9#aqC>Z9~Wxqwo?jJzJD-d>?n3gy*MF zD6SVDlg@QM@NnSwTS43~E9zG4r}EaBz=Br2jl@}f+WPzUlTxch6XARyUKpO zdHoKj@dkL5x!h|=1I;Hdin{9pr zmQZySP1!nf^kQn}EM45WKApC2XVkumrsdnwBhGwAqIykY#nwCa@c`9p+Wqd(1L_x8 zbNk^d3P|J}!7||N-%xV_1qDU@tn@{Ip?PEP)aAlGfZ+LA_3bbOS6I~SaX#i)X=u;r&ZtdxLZR+7?Rq`)f~I%o z_b1#XMDEuoKtcQZx5&4~4i1rBCh&dA@`=WkT*wIT6(IDXDTrNef8%4R$x9VeJ2Y+I zQ=E+a$x5C$$B~rtVDswKn&mXv0smI$lOcR<-Cc(6ckzaL5s~GMND_nxYMy9hKDs@z zgK1h_YFDkNwY6N|?BsFKzMPx|OOy3rwUR(&@jTQ(!!H#Wd-pw{Mv22dYmwy~fOe=4!&THb? zlP(>cuCEO#GZ@<>{hnUEwtw)92p4rdw4|9LnqgZ92PdhT)pfZ=inPD*TDj;eX-T3Wn5)~O}R-Tspb6q*e6_*wdJhZocQgOgzW&NXZ{xZw)hJn`NI2wQ_^~tt= z_cVT9?4!j1j6)g_qqq%332^HHt5FCtYd-oJy1MyJZzEWs@tO^)VDCCRdE7f`>JEUL zlr|;6#8)`gi3r2Y*2}C}+(Z;s96PZAf19_E172s}Ep7M91zwtuhW?$|J=Ik<9*Jt- z?kVZkD$;eH-8aP&JLIgnOCL7`lSto&8-j^zSYLJ8SKRx~;k+Wud_I}Kzz@H}n%IM( zNmuexZ8l@V{BeRHM7`hKbUt$-oaKAJQ6PcJz|gabe7ef2O&)sEl_fpgobqPfcYKUT z!FgNpZBR&Xf+8U+jG)E$xJTpNCR=pkSIP#vAoVMDu(Nq16h`Z1CNTrJE>?#WV0tyc z816AF4_qRh?xM*O93Vm`m^qFtacxnMYEq`9h3T5&F21zz4WY#&6Af>SAT*(2sT?Az zwUVmCw{!tD*~-K2S}KBtX{%3GakIoT|4oumZIUeQLy-9tAv;Ql4afdNHtsXHS$&dd zpte~3q8Pc76(hh>GKH9qk%%crQGx|iok4qC=viuA^9TH~uu)m~h2jr-aXD>%xy)kl zm&jZhKLQKm=@U`Y2<>IQy7ja}K!6U5CNJ}*g2wfC;k!C~y>VFcnWaXjGyLSFhzG`8 zp%HNM7okc>sNj!MU| zef{>u-rr}tRVr2WXGKf?hQobpn$SLnA& z3@D>!!EHg6ygwi?_M!U)-lB8g!*YEDX1jxto+%+TH30s+Fa^8>f_?~QtmgMe9o&nG z$)W1zYjxJ}%g}-MFJdy|h-Gw+;*X$*3PeH;=EBX-L6GG_ahO9v8F>H}dgSdT$UH^D zht+4NpRNwH0e%xPaQGRzp9w4<$gFnO4{oCSOy-ZlpBx7;E7H?-?-k*DJ$r5R`p$Af zL2i|=uDvabDGe&cQW7v=9qC-Jv$i!~AUl)q)qLq0)WhMf~5er3CT?%d_Zh>g)k_MZr} zhP#$Wx>`ae?J4fhMGVGSuHRs-w`rdCwHqA@T;saoqHrj3h}8zfRTCD<9L`Q1&e9w* zSm|?QqiEm`+TLX!uf8u1D$#O-DLek$L>Lk6x#4o9dxx99c9|;s6z!RD8mr6T=(99H zuSz}4k^sD}M0&d8cmhwS+m;ndNuZlwWx3pB+T8(r6rSpV1^i@PPl*2d41KyzZu_|d zmJy8%&KIE><+#=tvuL@Y-tQ9-07HLRtqm<>%Vbp9?Y*Bq|ttWtwGp6rSqb_qUIC25*g!VqP%Vgo zCw;(e+(JICTt2P&ZG?9`%U8R_`;~7(pFn!+9r~8*QZgQi0b?|n*QEMS2(@qc@NV(H zcI0?}^CR@81N34^I502|y_1g$OA?b3=2t?S<%>a#6$BfzrJ2tt$lP0(M)2~&yW#`#qPw=0GofMihUN%J@kLbH5J{qUMm2&mbh7gxAdoA$B8xln?`y2+ynF zWeTsyk<#cKQM))+pY!$T+}<>(7Orn%9(rxob3OOkH;5k@+=XjQ4utm4$!V))#Ov0(I2&L zdhr6kfHj;5%EYgTe;Zk^;pFoYCC~zI%7-iXn=b(K6GrtnH1WP(&^@Wlwk#EkFV-w$ zIf;A)nTDW}M+M)?#q4UKPsaxR?WJvjcSpgo`RmX(e;Myf!SP>rx%f8(Gbs-~60R>$ z$NTJ)Y6y2IJSgN)D3qM)`55}ihA=lp^rr>e=lJ&uxj81b2{WF(eibW>6|lyh$Q0(y z8Yc-p;d~|3b2KtiUEoynetJ!Oou6?Z`-U z^8_x13k&~!d%q{lL?hpG zhFxvvs`r%+3N#|Y-;O(rE1UASGeVaq374uS=(i=nSS7)js~z{Enb5K)dCZnj`-h=o zM^kXv%Z~-2CxzV9D+1V2hTKpUVel$S?mkIk{#K$0n@N&fq==d=r5<)RfmEfsZ58A| z%t*4#8`7j#z)y$vBhgbO0Cb`_>56L22w%H#qr@ctG4)j>@i}XOA%q_7r-%(+aLgaO z1oN2?jv%8J%>}GCVJbAK#thIC$}UWu`T)8(Jl^x!n?G}OG0?NeG^M7S$JxSMT)YJg zJNZOJoZr5n*fG+pQ9L6dBQtBa=W2@^qSV$txGaE5d7}saI8Jvwx|Lhc78CtlMqMLQ zxC}T*5xybmD6XgypG*T1RT6lSqC&rD9-<C0a2eyB^d zE{?FMCyK>;XXp#C(asy~|IN^)3Jo-uEsqNApjLo2TtIO-1cadomU^7CmhzHbjDtg5Z&wheTW2`J9_%-tEAtSZqok0W znB?!~4t!6xdpr$BASNZ-uvC<544BiFX#aG<5RzzW7b$vHOvc2})8AUDoM6?6;Zl%` zEztp5yCsaTkUv=;JxrK9#K{IJUHi8|UnJR3sCeYd?gb0>gJH*6Pm8s3Kd;H>m>;QZ z!oCG8aqL=2=$-IqJw7@_;9FWt(}>9TwhF_M9RvXQHZ{Bb-l9B*Yb(ycteGC^6L@J@ z67J-sxoJWB@RIPv7oKoYyA3RdL4K1BQ$B*ZyT*yj`x&f#G}$X_3=(qOnLBF@q+=N) zY|8X0h5@^&N|PozOC!4to1GN$l<@GNh1(6`VEo&TK+BJad|U=a-!{}j`H@Olzn#6| z+fnIg&UGW-jW;AzJul9=&+DuVvV(9pebZzv6%*+WoT(KqPnXKrt&p3LM}1R=pM_)k zQY+C^qmfj)!N?C=PW*C5TE=KH4A&qw0loTZJ2N`Jmj%8SF12;UF!3be`;_q4V9^K4q5N&cktPgQ4>Nr6b+hsQRAvn&iDty z6s-w~YJ@gLoy2uc962VGE0@XBx3hi(eg28eWLsW=5sGx8a>Oo3G!(^zs@nH2M!Ad9s)gpun z{%{rYK}sk>)d++Nd=I$AqW+U;VSrplwarg-%p)8{Ldu;5vb-NREYo2Q;!6w z>qNPUO;q>N=K|M*dHsZsIeVMGkp^ z-envYqb)f>B_kDrZSK1mCa(;m+;lRW{{;F|1_C1*84l#A#6UXP=EKk6%|KBQols3;W%gT% z6e)xx;Tib1!a0Wx5qojn+VorJ2~Wxix6j-A$ci1n@eOkjuXM>=6ecTY#v76;lenSg z@V6TH)yWBW@`Lzj&}|w?b;*zDY?veN<3SThDkN3VLbl|T>cKqP+dZ8SF2FFw&{9*ZKq4sfwESheB!uznvp}9@vWUF>73rkBlQm~z$Rr%)Mij5 z?5k{wI2tGOiaIM+y)SzW4@d2lZPs+OYa+9LzFO{p4U-m)m5b&*kGCIg2#W2aCJhe8 z$ao}$8Zqtvhq7-BuC>d$jcwbuot)UVZQHhO+qP{xIk9naq7(b3-|o6!cirl@zFWKY zpI!CTu2s)kbIvu#m}5LG%Y1dm@oUo}Owo9-3+^Q3@oM=QPxeZ|O;teOSB3CHY_nx| z;(2=9r)1*Jh?-c`Pp58Lu1=$)-Qk^)un&=RgA751u16cH>z6mZHl>`N-Dqsz4flM|*sZ1_GEi9Q_JV$8|#^?mxq8I>;{EJ9&!>}FztJWxp2kRe2 zKq5v+kZ|ls0LBn^e_JHUL^r6m!d0%7lk(z6(1y4^trDP9PkBv9;KD`cvM#bQ?xZ|7 zncgK<&V`KbpR5_S;>qu^UX2G<2-|uiyhM8htYMx90Tfv-jTU-xIMZ$ zXRP=Si3$V~L%Jdxw@ZGZJ2}3_LweY2e8g@zH(YhBQjfaweb0Y6n^7L<4uyZ?ve$o$ z%l<>)=)Y`l851Wb12Yq+f6ZB_y?LRiVfvD{;jV%X3JL;2f<(GVv}Q?$C<+)iaYIU( zxgB1CL9CBXm^Naje}k_YSd|Zv?7wO(Rk~HQP+N5KTjE<&b(eK1G^_fatG+_#4v)E+ zo4AvXqy_VMGC1FSu07`7a_+uA9k;uuwZQ8^ec%hxa}m$p0D2GyQO}C;(dfcFIKyeT zsEB%~x2%YI=(pkFcHz&Z;dT-3%EN6U-eSXUBHAdoyokH#x4?)$P;QA4<076L!t=u2 zwTF?3e5nr1hc7U7fTnW#g_;g_^LH$TqTv)doTQ{6FR{`WUE>gszIhSnV zs!=fmlT(ZNv!~!$ykeP%$iv?hqPyb|*yxa;P(?sErAIy<#yhj8|QrbbSlQdB7yDZe-*f(tl(z8$M5V3v-A z6v(BPj(lL1`2Cp#gt?oTxCwbNj)GmJJ-01Z%;_Hx>;$M6LAn%7gEN3nf_xROs#F=k z0_BcsRV3>~mCU;jMEsB<$&yM{SB;+MrPa!f=q}q3fqqpnO{%;}l;Q+!?b+y(u=U~w zceeJy37gHqTAA660*Eum7@>-U;$-oX!^X>vvv#a10+TS{b~=67BqfH~^5*<7VqXnY zz-Dj>$HO$ay;2!eA9CsB&R8BdMr21e`h~>Ki_}S+sHuwL7({swF+;Vfmg5HdAuTmI zzNnVTM;h=IP9l?H?e6#)8JH=f7vh-ddyZeXv`#p4B~Z0RQ!d5E8dwDn(o!MBKa2f0 ziE|s8lFB5~<}#I|MzcHBtAfzyFW};*V__#)oJ~1W46v9SGEZ#d{H2Mq@KQ(}ac9gX z+H#0(rRjQ79T}%zp`t9A~4*#mbQ!1eZdz*5@6W)S1lkjr|;7cc(+g&%>BN zBWn~An-~sQhl4gMp!67LVM$HIq(PQbk~eCk$saN*t;VX_Z1eaHr%}`fdiDTdEfDpA zYkY*{_1oJJ-e1f*r;E#^#ovo)O6_Ht_C)Z`xb_9py-~Zv_dJqH@EH=cNj9mPoSv3N8uGX6XrenWeJjNx;fB zl#PMHE9G(h9jcrmENUO@?g!dY3c>X#pJB6AH}`2;xrT#i#RAWIWjg@+&>JLOxB@7y z1okc;^aq$dRIoQ<#&(FA@CsC-Z5FefHAbk#RlBSJwUo+~ImJ%tk?gznreZ}4 zCFvrhtW~R(3{i7Du^i)!!+=QB&RDv&g7Z#IqMD{kP9u4ND;FIl(HO@dW9g<66(f@n zWoNI>)Tq(l*|mvLxRcK5_U4pXEQ7<+F1e|;RV77qVhiUed0gm4It5Kr{b-L#-M?F= zf1Yw+-<2yg)->34c?&M zEgI<%RogbeCz<}~FSjay9khABizkqc7TfaGQd0r2>WR6<*^B7n?y<@sj(YPyNY0rQ z$pY3@!f4wD*m%F@kDmtk)fz_`n~KNloS7Ta!flcT%o0OmCaVRb*4T9HD4d)uGhByo z+k`cL6oK9gbErA2ZTBvVh;>>lXVGMO8Z&+cyyVI9QqwYC{#;Q-b6Zr?VfN8qeCcn@ z)#N_QtAxbH7UkZ9W>)0{a7P-qRiYJ6~kg!mXds8=+n^43WGqoR9=(BT0CQ74H_~=9n?YLtrBm<2)Lg=ila2v zLe`qqJ6}B{V?D`ia2LnblTwfCLDcjo>@`F=X|6Q`NXJZG5W+~Cfu@dv|G8VONM)M_@jxU z(L8&_g?fco(;D#V)UosPeiOmUH?=-^TIP%Z%R*+6V^^hVYzURK|3D+Ijv+y{sA{@t#{|mSMlcV)XSC|2-cW4mi{z`*C znstsHI_>kR&iu_5EJk;PAPYe218<|e->UfDW$_t|vNOQ8TjJX$TKH@hvqb7x$31HD zK!(b~?oju=2yt8X^$jFNicO;^CS5cqUH#>a#Ab$!y3@t{1>P0x#-iY3*W8Zy+6)Ul z0(UhV$ZF7yZm&n~u$5YB_0*Q=g=U@7DHo)k(ykDC_>RM~Jxg{Uox!#J;_DyRfbAQl z-j#3XXjt^Wy9V(5_d4mHCW3zv!2dC(DrjLQY+__#V_^O7?t(cAI#NIaD7;OzwzgWT znH6>d@RswU@Q5h9#t@^6QVrKdGF%P#4OO4DfrWnt@aN+quYN}&VF!x>L6a7GOqAfk9+RL>zmP?$P& zpb>XD2v*p=qIRc04EW$D)8bU}8S}e;Oa)yy`^oquYFRxZvYlM9jNP}r)(t79AlF=y z+5FtJ5b#HxLB1tkBzFJVuZi*Zr-kwOGBzFD`Iz&ofT!e2B2`Rl0IK01E4F61a=f+ynfrFF=& zUTL(Fl;!gD6z25fK);ek!37c%e+7}oq(3v*teH4;MQzpy97e&9(ib5jLy98n$-GOC zx|?z}m#l`vb8|bLyni~`{_ypA0n^81XCaA~BZ>`Fk93%}3g4>?1;ucn8EqIwaNU#v zQ#G8oY;Cbzy(DwPAe-8J=VZ_1S!cR(zGTNV{D-lLEwiv=iFb-GweFBHheE5)oo|;0 z^9QW1(|97Cm&=uMhh0M|J&pX;7q%m?= ztEqJ|J0SwxFGZ)Z4BkS12MgDz*wW*uv!RZ6;?UqrFqNxj8H;=vrLfShu5LUA65P2K zPrM75BAqBlObd6L$nMi-$&N>;lHX-cFMTW2%2xA3DgJADJBQqjFw5XjbT?E1c3o&f zC-JWBR+zX|h-V}$G+_IzSYxcXPVKY$?`9U5 zrk@hygYz`e4~_9X2=^c{6L~)k62O=Ql&}OfNeJAMfj^S&6^8S#yE$R!$vPyG#<)SBKvPax?tINa+a{19%m>MU3Y3ST6j>f-p|%7 z=3gB|6TymzLgyi11>-*rEYR_|@U*j`g_d6@lE#hQ0VoDkcF(zOOG^4opoxj-qBG#mJLtiBW`6!c)I9qN0wv{rgoem zBsL41pu`|RmwIAV{DL-T5QmB=wKi$HrsCiLis3R6%ZsXl3qx{D{1M(P$K?R zvlG7A46nH@yB~Z$fbyamL6K6(^7a}u9-yGGkSMG)Mj`{Kpj9vqb!!ItDquBN>ldm+ z=k{p^v(|TETW2@*CR;eqb&SQe+_}g*`r=1bAu=1Q@1-O5)6P5>vUN&rfnD8KiR4DF zuvfN!`Vn1^q=RY8rs8W|edg|YyW;fcsdLRht>~^@X(Q8Qe$>Nir9b7^PMIrp5;AD6ocCHwPxhifEfqeAGF^K>LM=o1C>Q4Y7d$4$;UAT=x_R z-<2*RjK(7#Pa(VTcM1MjfmY0r#SUKrHy;76KX~Ueyf(RV&|G3_6heMW=g8dy(Qra3 zvNp^CJ(8$jdRII$9_}ErF_h@WwJ#|?tvH&0TL=%@K`SFJ7SKhMLi<7RXbbah4U&!H z-}D9M>r3(sr7(h9N$n5cEa zcQECJ5+^kaLkZPQGEJ>`&DwHfD!i#ZoJYcYdYp4Qp*YY>T%{lITSPnjidIae>Yy}E z{4!>xhg-1?>vpuBWGyN^;d<<-Sep0^`5!5l^0Wof;(If<{cUUFzi5H|Bgg(v%Kc|^ zB1Uya4O<1}tB1rmkpV=KlD3(sL>*XJQ2`NJ^++lRuvtF&l@n5kiDi1;I8ga3=@Z!Y z=Gh@O-!WDU-L})=a5M&+-FB;eq3G1T+wCMFcml+8Z~Mu`ukUTA=V^Ol=&Sbwt{;Lg zcAscR-kv%XAQiQG7-7%`vc*0)Ds{D`NYJSx zqwy&$lOw4Os?!9{<`#qG%Mn?Icq48aVM~h+2Kf}{b}b#0Gr1!0xr~k2<^zy8r+I1{ zh;Zb}33gS4M}YC*Pgz?FS3U{2f~j-P4V!4ojRhzZF5j{r@iw#B`c9=gr7(k#Y}_A! zK#WC47<87Pi<=Jze=WQtVO_p2v5Xy zsgJk2p)Z~$H3JlXWjosoFgs0@Oqb@ijQwO4pl+I&P;Zk^X!*@^y7Cgr7{0#RsKYXi zvwd<_2p85hIiTJ;Ia1AMR=+uiC%12~s@r_aGLevP*p^9k3ua zw4xRS*H>($7&X!w=|zA|x=uBTp>)d=g|5EU-yR8xMt@Kmi7Q?C96v&LRh2%3F*3e3 zN2NPZMTJ&RVgIu11l{Z*RIx`Kkek#LDhaOwU#q5!TYh1w4D9_#WtZ}ZQieohQ@=XR zUqn86Ej)|WlT_)b6!D9sqP$gwH@rV%qr#hee`FI{si_UbQ_hbB*B7fm_q9?RL>AzY<5?_*NxIi znp-pr@QOZ`dtfg7e9CtAdtNT|^vex)4*L2y=#^#bGG+k3g}J#t%8oAqoG-5T9=foj zQ-w%8ppV!5zO{HV>>{|Z@I@jY#CQ1J;|`vWHGDpQQnB9HvGVI8;E;+(okFz2Z&h^u zO9#uP_Na`B+ONOH@bJ5&P6NIpS_$;uT_kw_dy4)KJLdm;pZMpm|AR4nYqu$5t6+TE zBBj#+H#f^`or_vv1F>m#LFoVtC;~4xIxA>}F%%081G5j4yb4 zpL6CG@x2uDb>QzVlgEjDTu+mbBt-=C9nI!^eSSS%e;xUL&WYs#sK>E?ln>RzS0Nlu zA^xC^^hX2~104p9b_~SwM~CdiMz)Xs(E4qW5O*^veh|VIq zfQX4GMruE~c6dnG-0^{M%%cZ`%J%~q9FB$gEu1^FQHL@?Hl%oKo_ z?S?GJ=fLt!ef6aT$pK6i5hN{I>_~~Rqq+nh<4Xx6=~kuzQNp6Bh|2vX40aG(QzSwi zzWz-!X{hm4a^d85#e#swMH1Mda78ppp`thcBFd*NBJV3A>4g03ueqs9fFbMLbqCIu?QkW zkzQA@Q#-gv+QeJQVkt~37hEts$ogSyP64)VJe$bYq*UBIkxgpDghrXuuqC!=F~JH- zYI9}lpiiTitN>Bf2)7|8e9WjLQSM9zH!-A0Rf{b_I_Bv@>6!eip8_5Wd>O{rrc4sB z){&_t$#N=SX96DMOjhV-!X(ehNW2=l1=m;l}Mo?0bwyTW~ohD|6u zt=(UYVm(7GbVFZPF?y*J23};Cx~h|HfjVjIj@Gw{J6yPwNAjfA2`;qf@$h6zx03n! zWM08r+v7pFlMM|Fcj;UbPcDqAnuO++Pi7%z(K%-RoTw{w`u39sSqm(wlT74+v(={{ z_0JQTqNehd{Ij;k0Z00(g9ak3yY#SSHKIaXeE8Tc24C;QguCqUox8wr6bI!VDdL+$|Dv57Kc}K zp5yVQwzj?;&Bh|qMJYKsH$Rd=hB-P(VnM#t!~=;<1j&m7=HfCJH!m&xp~#T$YY)g}{>!K*=ygmh?O*h_= ziArF|YC4t>eRkzlY~L#A-s^!i&a?KYnNa*G8wGsXppl}&fD{9854SY(EQwJ39+&cY zGe9EDGl3fh0-zkpc2K@x-0LAU_55Ho@t~`g0WnB%bYmBzg1rFaiKc|)wz$Y`B$ zR+M@n8fQ|7f7PczsvoyzmF|(F6pZ#E7wk(uiI0-<;}oT!#{==#jBxqPq_YT@V41^& z22HEkTV1uaSzNMn>s$RCkhWPjaPE@2VcmxxEQ-^SI}OTcU+Zf1rvAjM5Pm;vh}2zY zm`5YRJ6a%Tvn>IZj|nZcV(^?$2t&+5&DCsQi%da${pPNnOjbX9G@{12ScGAtsH%d^zhuZCg zk!iD`kSPFtMF?gAEF_?Z9_fuwolot}N2S~}&9aq9iU)@W1wlbjMnOS96}}y>8%$WT zoLj)>9Qz@e-R0FKktu^LCs*cnJv(jYdbQQj_VxaDst3?|5CII!p&RWP%_W|_C%A7Y zJ=hK`g=o(|0)j3;N7galo=!C?5!{}BLPSG&z>iXfV^5?SxQ1{V7lB0LkoorGuwNtl z@BkPRpG!XG4vCJV9&1d>9ueQ+Qc7Dp)m~(942jQx;v!OPkk?4*mwTZT7nWf>_mBbW zDw^Vf1M6)4?`9;)%CKY#p$1#&dhWYRyhFy~;Go`5 zVQFaatow|nUP_=>4wrB*TT8MZu?5PnxBgc>V#SKsw#xZ zq@K(TXcwmI2Xy>>4-tZTXp!V!)XWW9xWBDjN5PUC5N4F0i4P^s#Um`Z|RTd9K=YGbXIB+vYqPcAW9H5j<=I*oExQ*~Zw zyQ*n7@3dOAv|^9ia11Ce<;RA1j$A=NU9E9Y!aAY9hhpv~UBUeV@PGu!;> zOdgFU6tdx4$pt#2ZAf>l)qma)nX&LYA7E7Oa%v~aF}bZrijfmV>b_#i9PcQn`s0^V zK$0m9lVP*0+4dtbI;QH4 zb?4cVrfU<;mTV|W&V*%<_z)s?662cyBoMzFies|~k>IsADn_~$?|_`=aLb9VXYUXd zMPDIq;vJI1Wb5Pr&Rs#LxbSE3GRAzF*$~%kY{gtKYCht*CECtj?TNMsJ?-q<_r+T`6o42B!}^7MikUNqKyxSq*ne1X$Z5f(@OAgQ^!d6vm{*a-8- zt-bH44wzd31=#7Jih+8Q`iH4H2B&FxGZhh4Ote#mET!8a5wvM`w5W240Bb^~(M<=m z^?Rs*Qme=;o2}+@dsCL<#?}0I_%~jeT(~mXOX%(|-r^SQEq{#Nxsc|`?yriiR=UtBOt5YA$`$uy zrbItt4bnuQ8_gwEVJnzuy|!t?xP%wAEtZ66KLw0(ZF?V_M@*dw=?d{T{;=$byIm8t zD-3j@#^l^zjF5RYWr)7H$n@`L0N%Ol<)3BL_JtT@T9Z5t#+srS;d|dJo0uQMc0-;K zU!}}yb?(|B^Tj3LwpHJ_o9W+KX9jE^l6DN=Wu12gb_3O@2eSQHkX3Lw`@DdaTJi(k z8Fc+KCB|K!RLyCTMi7(4yH+PlK4Wms5JN((Pmbw~ctfB%m6)(ZqaN_dl0FsOA)OwjZwIZegs0ws`Ws>(7RfqYpBS|N5n^2z z5F3f14DhZtBZN4~D0#@?AbRmx7;DIaDVuCaBHDCd-HhqCXZ2n5t46XqBhawC1&;#2 zA?|?r#DM*rV5^}t;vq?l5GaEtXps!VRk*gw-03gC$h@L^%2YnFpFGp4U{OfFQBt(4 z{S&Ro)xQ)7iKWACq!B^{#OY@@&_}`Jx z%OiJ$OKJ<^(v^`G4hXZQN0{etdx(<^f~i)BE##0#N-{&GxuB>?=oV4bDxt7bL}q~s zFC<}t>QoD(sFhE;mMH&WkHpY!E_=H_*_M-I`d~HPVmW9Kr=a?-oC%0K9V6WhiKtyfc}#LStMPIN zup)!zZknrG_Q#o-$whbD#dfZio&hb-ZPO>kax&t$nDJc-L8H8t=i}-60)J3M&YrWP z7pKyTLz#O&3k~uW{_@Oz-2aI!M=*KLs#D`c{Hq#44&oM?(03+aJ>ZE6aqK?lmTxsE z&-^|Qj?@6x^7Ahw!JD#lb?iGuc77YW{dYpx-=xTYdV~BwvT!LWR!U3!D51NTw9U=h zm7o>u2*bMZd!X{r$BM!i%KYC9=Nlo-MI|x}Nc1)M zRr{fY@~f>-OC}lAITHD#440IZZ)=q27(k*VRg$Jl37Mrox;l;JR3xe*MV927Ey+?y zCCZnpm5q(W)>J|#0&SH?DydkpP)i&r@K~K?l7B_E??4er=u0f1Fi$b$oDuSMjO|UG zgEPsgFC5jF){tQ17bi;QnhVfN{mM0_@V?^kIVo7w7k3HjBWxnZg#EdmJXvasb86+1 ztJH2io=CYV1>*$y)*eaMn^pq+bDV^B3_WX+fwFTI?68cfnm@EamU8Hwldf(h%XDE; zZ|0r?OQ^ak)u4-e+12uh7T+& z?QScL8Alro#%d^aXd~PT1~5jHQC4lU^!8@1j$A3HEo=L`MA<8%0wMOPZYvwwxSgXD zRH4E(y!=jHzo^aGTXK3Yx!Cl9tUX>V?!Kh#+R9=z=a`Lpx!RQ(qs~&*{pJ?YxQ{#s z%7>lhuCGlBUdOSmSO3+6+LpF3hu5B1|4LjuVGogc_jKQ%FEo=;L8CxEMi>Pt3Rpcw ztnj>HN@e;L_&3@8S(17EPcwQ)~VKDAL@i>RHNg}hR}#(GW}S$uoynJ`>jEG z#HewR*#mufvOZzgC;@e}&i;e`F>Kn!AyIp9S6uD4Quc!6bk~7d{k-7p=X+51W+x@5 z{vlZn9zHqUv{CG~Vy*7LaB*>^_IW7TJeToll$qD~JVN$Ad?Mw^o7Yo~>p@`;0FhJ^ zC5p{siiEA;o+)|l$WMwwAU6TwMtg6XQ|6+j_&##-<>+2`hO1lp%tz)v{?fdW&M=W`)T_d`sF`Q+h2W>e+h4eL@Rt-B_jx%wP4kNLhJG`*ahhdpr8m3AP-|L zrKXE3@@C`X^$SH%`o0{~aZmM6d-dSU0XUJsL=%z?gL^q;XrpQ(fnnRt=yK3+zdEig zDQ_ODJO14wl+x7 z%bm(p1yR&j?u@|?>s^M4HXvdif?t5!{EdZTR_biLd@mLpB2_5)qx8GhKK=gw_rj*!wB z5L%yI2^O_}06z-#xx53Ge2C{%O6O4Se#qp=&TUsCl&%CX{LJV&&Gx$T=zGdu`+9#t z_vd@x6GaEpY2LCwWU+NLACKV(-4@p$4#6Yg;%+nXis0&X)rrkA`=p@ZD7u-raXji#F0mJ zF=F08f<4-3SuLy<(}n*( z)6rXe=HXExjAB=*{q3mRSnIe&#?{UVV<@L49Ei-|gIz%GVuLH)gWl53`%dul6(o=zSC`CUM5;`kyax|Ic zDS)Zuffb8ydbSUUv_GVQn0LSor-SGKmIu*JZix5!E-!-5j`_Sklgq%jfpvcRvso@;P^3`@_%}f>qbaxe1#BAhgM)qg?bzP=FEUYXt+;rMmz< z|LQV-@owd?0J}`V+uF|)=%EC!(<#^TPhy3%ESLQOlUw0PXDrP5lVd4aVk*y~M}>fD z<7{i$8k2b|ppf-9YVLFc)a%goV|DE28JL&NZWwN!F z4*X)`t^L-o#Sjyjc0!Xeli5Xu8m_mBbG}!Zk^;L_^TdR#Jak(<3s}IiM)nuyqmRpF zA4y9D0etBX+}c)3Q-byE+8 zFMv2_nii40mKOow;&zWAlw?pWJC?KO64Ti3^P5q;iGhL+A>HWb^0g5^$QA*)kKNXyl->#`w_);%i9!oI!evjXgq5W)K&nwZNkhla4C` z|9Hbm8ds23?+W2ZOpssKvve8p=*R|@2lMudD!XV2#|L610Z0MEH>(9(b)@pf8RFK6*(NvZJ%jjVZWGSm=aBws+Qvf zSB3?DtRY(IpDcVXSCGl_@2+{&-*(OaMvV90BH@1o!5Bpuxy^6ox+D$^ZD2ZlR6SZq zkWBaruwhtbLeO~saH5ujUWvAWgeK8effp@a0us1)fUEbM$e%KB1S-Seab~W&SsCn2 za$k6OfWPxk`Ule>*{a~6C^poa8f5E}f0u!DAyzEAUqvV~*#;9y7z>uO7quU{IX{z& z*S^~#QGO-QgoGnw=H1s0{fX}q!;q>AEbbOj$Cp{U`QQgVcN;V%1@85nxMVBbO=Q@H zN#^N0Z!vzCY8K?nun@ID)Q#krzrC4XysR&dm7ePuDAKA>#KsN|ba2_WY@)Um@snqe zFrxIV`;`i7J2y%O7~Di-V~Vlfx{!EbXVE0HK0Zvy@uMiKoi+}b*7lKhFKcywaHJR- z9KZQ#MKnZyrkg*oEa|yG9`{SEih7f$hRVR^KHU8flLX-pYE3r_l9akfUAf9pnD$;+ z&Y>L)vj3^Y3eNFMbXfmp=7D({ag2lI1NV{T)A$!_wZ+h3$pI#w*4i^1-!E-6h9HkK zXmscy>9FZZE7clb_*cKw0|3Tx!)}qQi0HOplclLh1K&}OuQUw10+7u~12mIqT$%&q zv71r7zp~>CF3L>XH>IcJZ_TQh|5w>j*3Q=CKlVk9>NgT7hVo@ifWw)ZXn3n-6NSJ^ zA`W0RKdLDhjTQ}<1W>ZNA*DSe&~9`k8`|n8_!akQjjNU6TKduBCusJna`7zY%;n?N zLB>$D!^p+n^tN+#y3;$i`Q-X^>eu&$*iWLW(jCBzXt|@p=-))On6BsmcS_6=@${|i zI0K4$eOMR>uUsyp%oa#EEv_s(K#J01lr2gs40Q)8FYI-CklrA5b%ar3MPm1u2uhx`Ye=UXS*D# zs!#=+Wl@j8O4CT9$+^NSC}$BjG`G+qJllf9aMNI~DU`4}TU&D8c+&59z4mLuN*7%= zVfa0j0S9yqW3ZOOA{u42nbxMuV#JlEz~(m-nv;Vu(eLz&L3w%O@bU9VWlYh$(wlzJz)>xHNit)2V+H zdnX9(!}jlck)jQT@plKQa*Ok48IJP2U?TP?MNM$@`!HkQ3MojNHD%UaX?SHPoJr+7 z-q3(eHuCX9p{Dbn-MvQ-K2@KR)r(u2Y@p0YLh7}=U`Emk8>wS!d!)TmC_5$xs~UIs zdSpSJOD-oo&LGRIRTf1)n(*diw}h3fUdbeJ8NUFcO7U_L1SY;Z2h^;q~2x_i0ITz7U>Dt&A~ zPZ;9pK>|Bl=`U39kWN|-i05fJ_vDn++*kq3759yjCz`-3Jj7lUa!=Zz69nwrOBZfu z8q>l^ezeD7oExo!=wfR{f=Ad8ICXrKF{>%#7) zB`l%=X0^$Mu#gMv`=6W^6#6c1cS@6#DM35WMrV`^)zRBo;Uew&QC*S!SLT z^2&VuU#oHmJ$FlP5o169@)bdLNdcVx4iwl>e^*NX4gc@o639QX*8dC_YBKgp|L_;t zyeFlvD?urzRfdqymoZ#Iqx?gRu(+luo|ITTqKK$BRMeeF#_BNw^!Ziz+~gFBiEdjB z&AyI!c2K4K~yyj&(I))xtggSeOvuEX(bAc^BdRM|XK`D$1g8U2?*0XJP{a3qN$l&G+o z@-#OgOs)b$X`zJs^p9MmzT!CUrxHrn>-Hp8&nU`%r$Gsr`A3jKPKsOc)nyo6wl z&n#853u3FN)62xX@hAn#tY(N)L4_b4HrM1#eFA;@%fNZYG#}fpoeAw5fPq&R@LQ~c zpbUvy=$a;KOQWf^tLNZ!S#$)96;@G4a{?yopVYIoWL6-!0y;iMlhR9ZI;$)vHUaEu z(;07J8q+`aZpST~SGWD+EfPzy4dr?aO|5|vfl`q~$+2h24g=}buaxT^OX<2NwK5wG z&}li`cBZJ=#O}lPlFpC=Zv_d5tE7+eR}E>M#Wuxr@R-a@#*d}_ME>^E5|X&WJG6JY ztZSs1wu5Y9PU+YaTh@Fwk6MPrt6Ns{lt{$}+^**4Lu`bXOZA{ysL~c3anXSmuo_1! z(|e$>9w;p9XQbZ)b?z*9+$9ER=q%mgoUrH%Mf*setlFbfSl?t1DBYzSt{sA4)%F&w zonbAk9W>}(Vzl4YzX`JEu+h`TTe_?Ebr^;oW5q;~78;)G@t|K5$HWF9dq~QVf*Jzy z>Dic^)#X5ZDu%=H?jOR6By=c>6yWY7!+-O3*X>vGKMZWMz`%xh+zTzZ#G&Kn5IHN4 zYK2xNlYrtQwkng+4qRtvX#?XRgw%HweiMAe%Vq=%YTBYSIQGg_m3c&@74%54`7$(S z& z$&wixlM0G++8UGKqr=A@I+{6+v^W#!MyQf&6MsFz^-6DP8%cHFCC|+%s=7r&Xg9ti z8p4Z2nnWjmre1E_HcZ|W{pocM_-zki0y%*fa1;zoQi7ohAg26W;_n5KhQDyEpsO#^ zv5;6{PvpYo`&^DE5s_7_&6v?Y(qK=7h<8Xh5hc!&yPW2r#bmVXQK}j$yJF;HVoj$J z_Cl&e(;vJFjw|LX&iV%$uKWOB&y8Ows2xB<>DvY#{^h{-bVuMPxau1)yZkZyJgxGZ zm2LhBHD^bVmI~HZD7s(&T;iyb2N2L%aQm0gyJPa~8FzayZN+DuLJP#2%(7@yVI#m3 z4<95={~hPA5W4wty1}<0rm21z^R>MbxosD=>O8T0j?T(w3w7gU8lR|9#@ilH&EZUB zXm#r8wHab}{5vv>*#utIX1iWpka;42o8^Z)bHvQWdl74jjTWe`OskvMDo#SZ{;}4$ zw0*mG`gc(4%(Q^it+(I+>Gp9$H0<^sV0!YpjLQ0m%6)QlR|VR~q(FuahhQEIVpPmO zhM~_30xs=>56{V}`^=g#^cJ*e=D5DaWbeW=&mo#O)HeNg%aOYl#GfSipM^8+LR!bN ztf+29%}TnuKIEPrb*@t%N?)OR14=SE-&`=?mP$7M?pVq0v%`v&_nHTAjyWmg@{}w; ztfn;}hSe9MD&?|{F#mZN#A#e%X3 zFE}VWs)nj74*Wp5bO&Gk{-VKv8{f9jezR1IVE!&1|BcVnzr|xEX9FXvf8mVE-#lyu zgwI*mP1;MeNs(@7m3Uo$8_GxmEaCwW#RZU{gf1nGnw+Hk9QZQ5W9n3hO2k z=Ec~^0=+myR3DJ%x0$>(qx6ld&$S)?}c6|Iv?Ip z1=z20$ThR^dX(nZ;9gDLH|4~8McyaqxE`Nd5>H*Rp$Ji1DJY5ZUn2-^Frj+$p?4`B zae<#5AefN(9}!cefE@Xio9JGpvk>)nVL>Eb)+67M9FJD`V(F*nga(TPdw~T>C_Taw zCbu!5US*5OWQ?8+H;TTl1ziYQdtsWL zfW%x&fFKH#fRw;g5_fpSWXx5|PkfHIJ)1=hg}%f);x@$u zVsuh4DwjJ8O{GCaW3dv|8Am=99-JBLFyu+L#x$OLeGE4H=>brMNNpm-+R z>ABEtX(@fa=xKh zAM=}K-;2ROih|k=E)@_%Cpob%?@WxXH)Ad$#$LgL14>#=;f`OmwFVBgF+V%s=+<4F zL1*H4+pS9Q-jxY;bwCV>PyGzy19i2p6x!NDvCZ&XvB6w3wv|KWXrC|zYMbH}qwuS7 z98)l^EWq~X01tz3_gZ`K9LB7w91bf2yvxwMrb^_WI#Z@hn=txEd4<(*?9ur9W&3W{ z&}k+WjV!SRUY-vexioN`TKFAPS7-3{tM)c#_g|<3?vBpB#-5(Wv4p>6L{6xb)W{DS zGI;gVIO?swDBHVCg!nWoClDNW2)11}w{^FF^@d)=$;B{ca|)X!$`+fxgqw@UNS7Th z-Q8wUa@l%2>z={ld(M)3RQ>L?7%Lp*2f%8~Op>=DPgSDj8+Z;W!FDu{+D#x_33v?`x6-csXY^6-~1q%3{xePxI@$1qp68p zpW+CE-V;hU4Y1lb0|^dMK0<$HLtGc0NyDH;Ziyq<7Bf#Pe?v@QLevh+KJyMHep+Y; zHK}z%7JJEa!P(^hX!WD57iIeZ5@RL=>?OWe1#HgwfD9KCU518WEu^1$=(`fhIb9X zDWbnYCgF1CU8MqA(%fH!SCyNNLfLFA<6BeOM#GvIY1)hvc{T_s=xi*QhakkYe<%Xt zlot}0<8_zxwA40{57cu_5tGO)s*Q2B_2=d6pf!Pfg7J3CkPL~~rp7=)3k^Q0YA5Qg z+wbO3r$tqVF*p!D^Vs417B;xJJHxddBt0Nj7OQ)~K%)$4y8mFa4g#7TlnpP(s9>??B zKRmQ?y5>FIe%tX;yLtbj;|0&h{d#QjkOR#cEB2^kxlTIy@clgiuIxPzj~Z9yJ{Sk( zEj|+VQ9dlD?7bXE#Y2~fuXOA1qw*FKH81(I8lTm@5va#qGE+|C&SK#;I&$vS0Z#5s zA#QHs?5@#UR}|g&KAJ@@{=A7P^T7!2j;V)YiC)r4LLa^OB~iMs`hXKPP2_~yw|TFs zF-MB3myBBPiP+z+{JAvJuHv~h@|waQh&EXo>pV9&cLD@E*lbDY}$Qg zPZ|cYcJhOa+x`h@Dol>?llt6QjPv;;<-!59D*|#YUiZkD$ZO;`Q!#cIA1b`FTt0_EaeUblBwQI{C`m8HF<4Nm!P{cQj9ebm z;;;uJ$lB##B}QJx!m>lAHgu_`!`tXU?6lpic&RLD6lHWrrM(}iMGC{(fNG$)vuHvS z73aU>G5PA=?njcKR=YIi<(X*p+`2Nj5~Ih?3UrC5m~rJ|bt>G8A;_H=Csx+m-AS;| z8a(T)r(#GHAj|ZX9E^Crr_1#-16yKbQq2YBVnM4{;4W-O$X*{Pxr0}3rNhxpXllr- z-JRZIWW+G(HlQX*_gRLK5$Eo)$dBAHBbZM*B?Igw^C=wSQ#r3=;~uaYo{MK0R%wya zmz(|%XYU+bY1^$2Ch6Eo$4)vncARu<+qP}nwr$(CZFFqgJ^8-x)SNRjb>8~bR6SL@ z_Fubd*R$?>t!rJ_2R?=oQ%o;s;Kr7jo7=GJtGM3HhgDh*3(p=KH^xCh55+yN6UOCq4YuaIf`!g{Zj0+ko7bX;!O8z}eR{HSWp4Q?4+mD*qo(bNp z+&}B39^$}PO*Nqz&7$HnL}oTFb~TRLKjIg*Zk)I!mpSn4aC*&sc~qSoHN<+l*sdaw zUj%bA(XAE04q z5K^Ngn|ZugH-o!(JkAS*)a2p-=65~3T;t)0}gaWFp z+Gh&scimr|#9aXLWB~R^i%_OSYx)A^O)1Z_aN}^hOjr0?1nBXv){XetBuk_hc?y-F zqGeJ^DpMNNa`2)-j&L=4eRFr{2O1!Yx zHYT_+&^&A6zE6ezx;M1JJ_qmt*KYg5sY7E^B0j)#BO~{k;%_wp9x#)<4^;uFV*4rY z7Fe`$M`-O3W9p~)H3K9=RhlA(49i7a-btP zOvnL?)jDN}jA%;oz+LU0=UAj>L;x!&h^zi0@L~AYKgNKHgaktf#C2~1>X`fr z3g(a7)%~NZvPxtL{FcR`(x)DRVnpMIWkSPME84JJKY2A(`z>a-I$H$mc7wW>?6Cz?ai*ieaCXUnaoBAUc09-?D4zvbX$eD zeL`fGSiQE$9w|QpE1feo!aHoZv6DwST;+*ijHW7};XKZp$`4GSR4{*}Ue=^XLTK0u zRI)_KMQJghN!#T8FlKBGdU3g#P=mkz)l2eb1vqdX* z5ok%3H^v~wbBph=WCEPgVODfR zQ`zvs${loe1EQXfUYBrM@puQOpircdVI^Xts||kC<{VamewdR|hXg}94ZdDZtd6!& ztgV%OuJi(5&Q>HB*yCsU(qSekFKBg-<1B=R7~0%;)fu`a$!RsM{6RYOSN5sL&8&ze zMcLe~{)!dY;?}$~c-}}g0KyeZynMn9Pur#d%+e&uuE8iMyPal6!N@frwfHW;wIIU2 zjP;OpcZznLWIORse}f5y%k2FgP*dCCi6z4YTykiUbu`{yLdopxfNKT}Ob#nr%+6&s zb$Dq<-3g0Y=a1_~I54x)LB>IJVLMjCt}zv?_CLQPV$unpcD0I+I$om#oCLuV+&jkH z@ZVEv%Uvnn;h!kqHP-$Nd;63j-09G@++UXK{}F@fs+9N7dX$t)Vp~vq_W2i|BshuD zap9XtvxoUlBji5>NXgn8IXb%iKjQ5E(=cTvYp8s4Nk;yX@j^172?n{F4V9A&N-UzO zgOwr1f-~gmmb&7`i(!ZwpBU!Pz7K8F;pfwNHCZ$nSN(qY@i6hwRZ(%dO*TRpA?XOK z_Tg|;+2!-j=rMgTf zcdeV!UebWPaofzDuTg+e!XbC^v)XUn*Vw~f$uVlb^H zOE3QlHe)LQ5tu7)(;Gs!8koD>#hjQPxd*FK9LFq5dNChk++S};!lyg7Z|62q3)=N- ztDrDZ+v1nR5tHdDj`>B0n7SFEXk~u}OwP-a} zcVYNlj%pD2qluvH&14ja+Rpb#YMe={l8x%m(jYS#` zY$+$~>o$5De!MiLtH+7xQeCB5S!5*EZKeSl0HyY6i3{R1k@kH3xqig&lk2EfT5zJO z>m-%>az8^yBND%SLnLx(6l%pEw&b>G(NCgV#+rKPPU3SEe_)qTT*ddYD_O`nDDUkH zd-Km=2vzM=Y~$IixSP&9K5$8y{hTGM)?5q3_hINOUg(xASp%GoJk*bfF1FWoafy2_ zVXU&<7tV6{w0KCxg>c8BZk zVH~X==X5~->~%oW-d;Vw5c;>cB^lG(X9ve0iEHw)nQGY#-yF5jMmz6ovreKGx_t)A}NnVXYy_vZ4 z9Mf9F_E>PXaHr7NcCq0#*RM4O)-|`Ji{IkS1>)0;ZT|G1*Q%9Ja{{LznC(Go&?P@< zL$nVp;{TNJgS`OB0^8f4_-!Z0{b1<-8#t}%a=_sH8)fhK@7JE1S=@^?JGKRY39MW< zsz1#d75JhLl$#Z&Pz5Zl@Gm^*7a#9O)YgILSQI-21PV%-Kf1ow?ub3=cKU=lbw;D$ zEe>Ugrh;&Z#&BW;j^gMOrS*HLjqE)JwMcj7sj1TR@e()WFudaI<)s#GaxNz|-{j7Bj8x$n8z8jf)4>?kWICc@gy*Y>7E+nyhgXiXS#EbdeIJEX?8!yLCbDl+w1Ca=2Rt9uI8)rB!?-NE#k^S)?@qn z9(*b15t&%!dIuZ?x$Pin-TQCZR%{tbmju_%2g!CN-K{PdLpm(%#0|%+SdGzjdZlDq#+bhA4lH zTqN30`RUZDQOQkYI>_atmnmsjy9#-&P#Lz0Hxe(6$Bbbfflv{+ZjOX`1!a4YaGQoW zqDLU3_j3ZHuO;TUq@E5^=S~3`o^IFA+t2Ub*IqhbAIBj%KwNpWeOu0`UAkhPJZu9VjHddU_f8Z(U!$81M+=yM))as!;Aju@_chSj_gR%ft{y zRcQeYfC4K1rVB z9vLY3aqnUTDj+e!!iefc%7nVvL`5_;?)1nJUyKJ23JvxXn@Tg%)YGl>lW$L&cI+i| z2$z-%gm861l0+J%wO&KcEcpz)0??}QWP%PVziG&{d>iJrd|DCnU0%ZpeJCUMp4g|VI9FV_oRMkKgw@HRII}7}`ILQg z`h3ws!TVTBs3ZB__sE}naHCemyT$31}kk1D*t#;a*a(cUzYkPhmmHrmnlX&@;E zLW=UW@r(ZWqS-1z#hgZMoZH*>DzTdY@##`23KoCrEo|hc7HVAV1RG~H_v4XtAu6V$-glBJ0h~NE zh6T&)WbJ;!m}rf3a)<#9V)H~2r7#hYWy?&^0X?z$mN0>KJ!hzt!Q~1iD9}+2W&cFy zY5?;5@B;~T<~ZjSfhtDC8ozA3=!k;1BCKHHG#`h((&Lbck$P=|OK4V?3Tc{9^8NVt zESd=HCd=b`wx&eF&ePs6ozPiS2l20cM=)Kd>`8##q$nlur;+8)7ycJGWPrr%~+nCb}nZ2ut`AIM7;tJEBYOm8+ooV^&8aB@-6~>s z2fmpOu=U5S<^QWd$z*fdgyAp5M|S+}s!<+EbA>kc{QDCV>U8JZixg#U=_ zd}_}aH6q*~i~FO&8V!QBS_F|TmFGtW*^EwdQV?@fax&mSM)OI_od*3&5|D;QEC%%>#z@*etKKE4 zo!{wBYBpP$jQXC=mV0o6R68Xlga`bjTkr)Kz=;N+5r~D<0)y{(>6PM(rh+5n;Pk}_ z^+{azaUmn8RRLUEfO#oF)LEWiLqo=BMbw7!%F&m_BcA&GH>QLZ0|p6V&3+wHE4-t` zi#LV_k?TYUD1W2axtbkXWW`X9TP34iVyzHpjQtPBONd>1wCvxR$Xi25bFi$Vaj$g2 z!Jc==1Y5uV{QC>r5Jp8G{4!={%^=(>+u*Z5VI_aDy{1_o+j^^KemyuQ0_-9coiiWY z;u~$lAKcRGxdbY+Nw~8LNH}EPI(gqZUwW30Y3sef_qLvDgDOL4>Yr<=Ks}P&S5p=T zy7TdzqvpSkwx4Rf-FJT_!;LYgdgPfPM|i*u(bQ2{b6F!i2tM;d1%zQFkqRf_?vE5= zc%Nywj2STR*9}ka(}BKI-M(PozHr{U24KAHZ{Lw8gr8)LPUc*iO%7=(DCV1ZCE;b- zfqtNh_-e$2wTfDEBTJqDMMa&s^!;ZKp4NKD$^`)g^p5sVBiTQwiR6v+zAxneubL>) z>)VhFaX80H0^zKwle`oa6{U_lRzVRZf_NTuXc1jd^us};c_jW^%fW^Dt_l#R3%LF9 zk{8+Fl9FF!Wu88LH9dX5(Ums#_4fHm=4-??Mi9UcE`;$5qtBl)0_)0)1OKG?3SSf?+Cu+;^CHIwBQ*>6@4(}VRFzbs1<2C3X^lj1_uxgjaCDU@w zQ)ZbPUO^4mA^wN9dFEd#Wf&a4o#YpfUF%FM6$WY@$JgxBt9%*BTniAW32}qRs)>Tp zx6I-e2yHHXJ-Q($?Ez2hA`t?ZcU_0D>=K}dwOY-YS~>Qd+T_`%>95i{Gumr*8ro8p z;z~uHEArG7MbS`Pvp2FM&_|9Zqh}ZcYy*~m!YRArf6E`$F;>6^@n!g)xwxORE(ypL z97wuM=~U{AqA9vaXM20DHCZ8xujGN_phX$m3cl*9vM9UOw~ zV!))&6!4FiJj`>8)-C`QHj_%qe?|Nxv(0vnlLL#Z#Rm<4h=#_lRhLcO`LqPh2oxG5$s>Qc}ME5Wq)^tP#y3_-u=kR=}ve zMW@{uHnIa-V7M~J&s+}k*#6-Hw_>m<8CfCA7!Nq&-_#$(zB*9i-_Yzz5AD7tw(1HHv zb^o7oo~T4CnFZNz=m8ykYd99F)VGvN5l>N-mlsTMm>hHseCj!d7y}SD0+=&vxdY_-^ItQ6T|BP2OP;r%MrLe8fWR5B1+mwElnRLW zYLXRD?~)3jOR!2HNYG8tByUi=sJ^Mbkq8pQLO+b19t-nLkS$udDQqb{A4sh<8@BA6 zoF#vxe&nCEw*R8)XjeikRZaVO6Jt@VhZzLrH=eys0<1GReG1}aH!z>TsbSHcAh#lE zUKX>FZcbYk-RHTfns*J=ILxj!s8|&xIxl@~`id#Q>JYxaI-SaE)t+lUQ(C@<;m+x& zyS{A)@EYD>$7*d%tUhuyv9{Q_I36nn8k(2fV6Kb`)E?bnhjJl-4Y5Ud7HAE9L&Vbs z1TsXzG-hV;1cq!{`5z)p5KAN)g_8_3PUY(=<}Nt15MdXewVwxP#N2=gd(+9_A^P%~ zPS-n<4RbrG5NKBG>RBnQn7VDuWQq4j@`~71h{s51puRd(lt&vpR-0ehc3)+0C%wG> zGJCX`Pcx-#z>+G;p8&c03m0!mW};fI#)aZ2&R-;kR*Xkg2fHf|$W~HbNL$pjUmh@I zVJIpzb&yCEGeQ;D@lP}5s&b8qUvt$Y$R#e3IlG&ony45v^?$d$7b{-&Ny4@+Kp>OE zkB4NvjnjqT!I~AlMeZY{90SJh=Ew0uz{}rb(n-?Uxu@|AwCN6A3RE&mgshl2Axj*` zAb3b&5XJbt)Diru_>6d8_SH1$$Ec$VkM{c0A5!*IMK*}kF+W0|_48LSMf7Y~R&l8= zl36$=SCBA6h*c{JjH_P?%JVIj4LRNp&9+?SpppCM*&b16ewv@t_`F~p)KuYCHui1i zUR&g`eKwV=^&ba_Y>(?UwDyqM7r}ld;xD4HhCp-cqB_*p;ByqORz4117w)DdhM>=f z73}^|!+W}aA$F})E&6N!s+aGn?SChI{KIDRzw6~cKwXilg{|TtruXzw{n{ZhFC-!X zZ>*v{35fQrDgiMJH7RgBVyODQn0-98rStxp7Oi@XD&1rFI;Ff-6$*8gJq02Nk#dEi z#)kBW8Rx!a$>)9}&-%3E`f22VXwEaI3G0|Kt5^w7w@c52$7}Yp+st!T1HO;j6)w=k zZ5;Z$d%MWUXpU=OT-bzm1pua>r}?wF&X;9>yj;O6S#kmALYyj{%X zh10$@o$)HubL;IR&gS_LH3Lqs7ts~^IRuxgA4C_x)fD<^S1;{7_yI3&yMPEUVRwK2 zz4#&fW=D*RWX}xq_piM*iq)87K`y#IFr+`ow^m4W?YHsR5Sy-RQ2|)Fe9s~L#Y*S^ zA|$4KLXX~BqT(VwJAu`+s;i{eY~I2ecM)Qo@@>&NHHw#a2!CcQd+LRgYJ?C;xb-Tm z&aAp@yoGffc!&j8dT@{>i=W~Tv0e@YD52H!wq9lf@CGSzxR5HW3uR_YlKtJ4QUb5Oqn>=#LK8rYNSnog(ww(;j42Rp*uBZ8MYiYo*XTSc!Y8rja-3+NdZIdi7Z|x zvbDl7d_#owQ6!u>-Q4o8@TO#=izQh$Wtl2jnhGk6=-AUp`94oAGx4sbI$l{<$?Kuo zA5-EbvAE97T%4D|TUpL1aQ7oyfx+0r7xT{X&KY4CFvF~dSkCDlhibBc5K*!=%xbWK z?iQP_Nn{KARZpFfbGE{L2)4?7NEQp#c+#&?u3?wk z;OHvTm0JM@YAFLYN~vZem@7j)k|L%$9yqrz*~LbF;o4ObH9d(DxwXp}LCXPWT%O?! zj_rO1*64FKzXT3%A`3EG@ewmW2k;R?w$gp-;6j(_sC$m>VKCh5(AH2Frw>rS$X z>xh@MPy|6wa_AJnJZ5gffrr~gENQoo*Yq^dnl<(vG?|lX!!&H372Bo3nAg%?=eoEr z05H~+=-^3Gg^6`TP4o83CLs@Q6Wraxww%hw>`ujs><-s;0cGmPRaWRz=Db;<>!t)ccx%~&VQW8+~ag@WC z?8wQLw3A{pW?yRBQ6$c9J+3Zefb@O6VxXih4>MvJtH%LzFYMJLOrWK^V%DDgU%}W!N z9a41!&&~8xRm?b)5?Yv@o+F$~%$A~YM`H0Qo;-^s4$Qwp#;lbKZJClg3@aMhNRP{PTuXq%U%R^_uSX~1{5;#%Ucz?bHzIpp?Z<9c28JVI)GJn*VuiGHonHwW z@9u4zR21Qf_5q9&R5HKL1MO?o(@f;6^EIPRRR?PP)Wzuw8IMhAa^0OuOB_zccvGN{ zu~{{p+ijf^A7PITTAj@Ls|MZ}c3IeV{YRC(p+y2KumUyql!`)I{N`uAgxx!YhNxOD zf8IiWKV@xlLsW`!Ol%%7Sec{W%Dqa=!;)ABAh+XPGai_0f?`eT8LlWCX_IU}Zy?t7 zuFc@^gi+2&%+13^=V>E2{dIz3{A0&%Ztj6JT8zQT{bPm-Zl5OtXgWsGV1HS7xJ{gP0aw7{gTK9r+0+mVn|2IaLXv0S4}Tkf8U$=iD;fA_%v3n<8Wg6};_MJFPBboMo4i?}1R`dz(puq+eHt`M1R3 zlry?t^96T~AJDSD?N^iQU)S7Mog2EQoii^%Hi`-dnUxgb^!#8pqIcQ~Ioc>1^rekG z8I<)xwAcdmndhv&nee=R4US8QXcZ(qOmd8YHKk!mhR0{ECD8E6gAg#3!LsFIHNIVp zaKG?seyQBa+pY$%C&t8&jg0Q@bFpRX9_1Jo{T`z93a;IAA7vLIa zvk74v-38+cmU2V+`v_vN#1*c`#QiH&;Drf(pU(Bi--C*`p4Vd9M$L&un~{muq!}x4 z?mr{YFIZ4xBRPsvqKDdIII=3X5FDcYXiDsDt&xwF(QQHtN74&UGEe9?t)_i+5E<$z zDcSX7>UGN)WGWL*qgF(1N>KKGJ?szSpVfvI1|2z8JQ)W^KbvQ8y2v+<#Q+Ht;)D%c z0`^|yX{XfH#zQLjcB$4}{vMQ+KO0p_hj{&;(r%gWw9A&U_L+#g#ite(6)BIbMwA%U zk@0CNOL6+;RWjet<~Ds^V^B6V$n&{|sqsQQ4^eiAWkwXZlB9o4%8*9jOT5z$inEPS zx?s2PeG7a3CX`XH)OYl`=cz>Q~_JPm^4I*%-$Kz!s1z`(B_Xlty4H6fF7H;eeM0noD`<@bj zU>pyKMQ82_48xs%dGSa)yhtK4r5-l0^Gx4eI)EI3Wt!Y*Cru~?5ds=$b&?c})ToN< zi>u9t1tGFRc0H>n{TbZ`HY0oWF{ZXvI72ZMH}S z1gIT~E6v?OpN18-jBaVVItU=u@*YgbJ2RyhpO|^$2Bm^q7EeJu*C!%ykbWG*TPB`$ zcNpBl3WZB2Ob9C!P9H5Nb+TjW5H^WhdwC>YN{RCgQB!aXWFI-;ifl9#XZ8T7Y*zgq zGLnQ%H%W{V{0_zDi7BD9MvM+H`Z@Jkl$0jGgz$^v^&pL@l(=goD>Cg?o?h^GlZpCW z)duk{Q0qcTki1UNZ^A>_kPl2JCe+1=;@Kp>K1ObdlIw`}l!yf@_ds6h0f52270~Y( zAdZs*q=y9b3MC}=QP|IzDh%*4_C^qL%C4B{q9h(lLmlT`Pva|Mfj|2RbjR)JX$EVm;kC;}8Moy- zwAsC@P&`lXGjQis#@O|4#-U|Mk6*8BK#oH@%{1Z`Fq_C)YRRfG#WD<Jdiw zGKa){CKl*0#d->)h{=~N)nlbescu`1^6**r6N}%YA;V^`U`ifaLUoM)fux!1vw+SZ zEwc)^?1l-_)ERgums3^r{ARlIW47e&ij05EwEFAh?X#x7;3|Fiv8JMDSn?>V@oeie zbXplblXnI_@0fAS2#|dUjWRig(2~mK;O=(~fnRREuMwWL9aHoTDC0J638nb%U*O{y z`54qI?D@FRyM`cN_m?VF8Muy%BmTOg&gMe;LjTv%_G;{=5&X?%_5Vl1lYamNzmGO2 z14k!&qyLaviT}&>Bueq$Fp2jS%d!<(YA7QjQc*8j5)??c@1UPhpLJ}LF02mqmJ`)- z@&ni{`s)~ixqc+W2ar$V?WP$A^0CDHd*|l264C71tjFuGJ%}zm6}x7?DjFlLiC7ej zhtRiw87U|^2q~B(R4STmqHMfvR$k#r&E>4Q(v-kqFBfA>Qb4aml9a#JLRjm(@ctB` ziRgtDy!eqRF*sm`F-vQqCFn16+Rg}U zLHcU>MXGg!=KaH{dDX_IS!wt6s|0M9yQw-|S^g82J4$fol~DK4id9?zLHU9JPksOB z@kTMet&gx_A*JGqeP^$8h7w+LXK)}k@;IY016cvWC!@8V_Am$o>``Tv~$#kLj$k3Pv zcFC^3lhE;nz9&qpV=J2?#J@wSUZKhsmo*Br8?DkUWk$pe7jQEOshqwIe~Jwp4DUVQ^6(6iQP5ERg)99jGZNJeC~3?L}vxLJ#KRG zI!}foe1dLS8!YB-J+1vQ>0M96)$Qo z(^vfp!^{d)gHr)$8ilU@7O*i}SZ|&Twpp1Z$$^=05%SBcuvEdFuz{SWpBpyPK6Rdy znsJ)+XslFk0;i)!1a#BHzCz%R*wRt#cR}=S0vXK;ZPcU1z$3pK?18g&aKMH)NAP#}vy{aD-NSwQ!k*gAsd z4Z~8pVx3xyK{Q>aE-|mJw7LtIA?Uhb5e)j%WYqk_sy{oP;0JeWUY@Ql9xEKqfE^qR z`1D?;-+im##ic%@EeK|CU4R8XhjxLsOVG@U%31wx^ZDjl*-bmws6;TyA27HUjN-o? zl>j+heg5axb>>ZDpaH|?1!?IDG4rW53`c-jNP*51R={DAD`LGarLX46WvIfQ&ceNes`DbTHtDR+VuXhe|1mRDTl8`XKhsUC9F zEWtfJ__u~DQC+a5>boMk{}Ik(`#-OU|47mQM@bYZYd9<@BYrK{(TF4q(6{lmv6480 ztOjcI5dz?VL8SRdh-n&UDUWu@F~)w4rO|(o;OPeUf*OnGyz9Kp-}OpRcti&okmdhe zzdgxpIRAXQyF82Z_W66J0#xu)^pn$0S_JDjfn1k53Hxb4{GtK5$`Kep~ugMUC5p_odr;EfQmMwnL39RS2g+y zCpnB`{1A;ekUYB0(AisFTb9!*ZKzv@iRKTx{_IKPht0iu^7o(%5JHaA&3z!w@MId} za|HAtj|I(2=+gy?j3uyzra~O@g0J|YLsD#baifyqaRs4~ssqaSi1*}{Mx_s0SGq9bN5|xGvwy=LAlKthr^1z*Pe%=H99%V^KGQ5QT3}B;1G{UwQbn3#z_dPc zq=+N~$?nyD?^U~=R6;6|J`a{c_L%WvKoSKu_8c47qLz$hSSL^P--F-3a_yQQ^*oSa zv&hFOJ(Z+nwrilJ(2V`z4b9m{Hrs)@V6H_Vfn$Z6G~gR}2KVlz`Oz_3u-oiMXb5X) zCqEDqs6|MO^#Vl(wUwd3U@LOw(XYx-i|qj^fSu~LQL$nkeIDWA!2D{h9?jjPj>ha3 zOL1g`Hh^`7EXw7c58;lSTj+m%NLLr6$$K+-poW%X-}(psxr zs_#hIR_bA#*1^3 zp1WGOt}niIE64rdZS`#f!u#4DP)@gjSK#xuo_pBn%_s*4;jJGq4{4gwb_zt}Kwr z`pWefySX9(f>`MWQt&bN6d|6n^W+wW^EEK~y8zjuv~Lp%zklrQ82``9|9=#IlG48usJ@C@Xe8p~ zb2mE`iC59YfooJ{CBTLjCFBZc~qe@h63fg+HTiK!=IzqOaRP%cKJsWAK5 zvCl*GM9C10Z?OrrlzLMA0>QK8#-=P*A7hGXgtGJ%nR>OQm>)*>T0t5%iQ&@8s&k5{ zU6rcov)l%~+e=umeeveYVo{cu;4RSY^QN|pbSP34$yHEJA{H0M&sfEAUeXd{&FSS^ zjV~5M=C&5Yb~AB4Q5$=ml_yg9*fPc89^>8iwnwL#i1j*6t@;jhSH|_6v`%xN{_oZY zFFkwkiIzfM@BC$)aIrU`z_4kCHGawV`D5JyLcxyLzhUjiEY&IhEDElSbmXE5_9I2= zCh8T^ymlHk!2}n~V3)XrT98blJXKo7%G@Plq5Sf>fFC*X@wi|o$RbKd~D z34wx#K$YJdB?bOhWV@;MFO7}X>|L3^Pro#x&1-fitv)x%)T7Gt|wqHTiv2GXLYInEL;?R{pDFRDIV$ zSwa1)t%~973`?osD?%&|rAuUPt{+eeQ`ufmoeYK|6+Xa7TQG5D?4rB~Fv|d#O;(6) z5Su3e%&3Zmv5Aq07fs*9Gn!ACr2bqVTXY5B z2%;~IFhj1g{Q``?144`@2jsN91^WwV6ZaUhy)(Fys?Twj#PSoRBH1lUOS zjXa}*q#d52T}+5GlWv?aTl8unYwlc9I~+EnMpZ)!khK$T+5_*Ag~14NU4J3bY@;au zgrXtbF+bm`0gK|L$65e2bm6MTYlZ-OQh_Gjx1-UAth^K2&ud4VxLWx6>Gb|{PISxp z3`Cd<6A*7_6@n#WdMmC_pRGs?yEIE2iFC?tdRF>yse(`*LcJD37Yzq*2hpbsG5drwv=c+`wly>Q*r(H*YFWIJGt+-jra721%X=-K_FkH|j<$+4kWREL7(^Q9gq^zjXfiJV6Tw`=(b-WgIaPJYAKF>hcbW?K zz?dyHuDUlw*^ilh*n^`-?NkKSvQOEsiCx@e5gP4UxfYHFn%0&zniWNo{t-?Sg*>a? zfT|N^GpqwNxoBV-8{UGD+460}fxL9+MU%L*YzLW^X;cHcJ1qGWx=K~?hUP-)#_H%3 z-W}C5rL1MHWXD6&3;!LZGhhPQJ9j7KCC=YvZ4kdes9y%a|IucIN&q8 zmW8(@wO))5;|H|&@E*_c6}qd;&XGkK6ZF$QH<(Mn?rdY{dW22_v2jmO7# zzA4H_TFWiE@C%iT&;C@3)SBlw<@jS6#b)Z_fLCS_NmksCxD(yN{>XmleOpNj*&COS zfDRwZ7j%3fC2QaI^%BQ6udM8BUXhL!8Mi!H644@yc7G$W10yEYS#jlZ!fsRa3)>b5 zu1jtWZrtQIJQePl&PLT$-&pR922F++V2Nbt2A74+MbT$r*!#xy~yylI}nuV{Ijb##AmM$AoRVH`p z$B3?RL*x47OL~U>G%v_tx<5+rJ-uXjtYfu&d$NzJ%*-ndD>6Fzr{VP#!kAv>!1K^}+JY01L_G`pX+&{Xdz2L| z;aj#NXjmCtZPps?-VcUEO(MA0Vj7s!WAxDq#@D9A&h|*}#>F_BHM}AI`pZ`g=5-@8 z_Ngb`8Y`I`E14*;E`p!!jyN!2)8C;DJs@u!Z}mToIBJCe3Bi?PzQm6art(5I)}cl! z1j#0Rn?j*mfvqOag9LYV{;M*f9E5nO zxD0}kXnT}Q(%1Rf0DKlgV8Xt!`E0_0DTzlXa!xgeX4`F-D?5 z$Ozb_`{H~^jmnF-)AG6~2Lz#_!Ky!|ESJ64L%^CAf+;I-hwgsbO6h_XsUMPzcOWnv z*^0L%8H$KbaVHu+=Yu{Q0VQdjM(E2+#E8HMYBur;vRim!OIWNu+vM%AW&SGV2e>j;I*?26Lxr6&){ALgExb7Yt-sU_9d1B^&0SmX@zlaZWg4-dB#d0WZFT!C2k z_$mhkZg%u2heRkw@bXH1P~^CTD`NJ=xcpLXP_+9N*kVk+d6f;W_#-Euo;ZK|9A1EC zV4&zi-CX4ocMabf1>J_tlz7)j2=9P%ki6nVvI0%{#Owy-kH?E5*h}>jM8cAcOXVe0 zbg0gxO+W)`mnJ@LTEPAk-Rv?OfI2np=ZajAFIRF{Egx1j%a4JV7C2KiZImr3YzS6` zW&W1DDrN~;2QjxO+Y-MVNbERoC$q&Cy1KkyiP`&=0OS&x?+uGRKc)#r_Gt2*qC7w4 z7=0DFGAlW~5zNs3I$Y)|J^P#1_~LtgmwrfzDRh2c#k1})|Io|VZt;?17gSgQoT?E> z^v2@%7jA{O{Z&UD?uN~<9fC#g{m8yElJG;%;q~vorwoD+Yl5Bc31j5vKf!MQpz>3+ zu`seWb2qXl{#T0PzrX!g_oS@xuK>lb;7!u8M$mQrGE=G|W~fEEJPgSbg|i4 zO88Sm{sBRUyypm)DvQ?(8{1c11q-chKohcPcM_4u4i_W87QC6 z`|}(i@S7-fY3g@dOck!wryVc+_PYK72(E(rTFQcv2&e;3!RmVb(GvrsC^2nep8fVn z;9>trzU)n1d#Pc>1fm2f%mGPBQWDHxlD`e_;v(-Q$0aElh0_$%77ZgA*7WVQhQWrh z@ir58qKxFtS=umUV!3rF(oW}@2NH89(~9MyQ6I&JN<~lPBn~}^XB?|!)nY7TO$v9l zTa6Msuq-wGWjYeWiuaUNRjA8IX*5+s#ceH47d7>hBL$81II`n+Bug0W>{G+avGSPW zD27v9X{ zP+~&UG!y7iQ9Qy>oS5+E$`Ae1@DXsSB`Va%PlrglG^+7+QP)x3*asm}_ zEV~n|Hnj-?h3058;IV6HX19w?$V8#hDo=74mh_vcbxJvAhp!?S|MS)8&)It3#|^dn zX(CG>@eZxXB}*SI24VCmJj z45^`0@049tvx;SOZqYov+U^?~IM9JG8W4iaq2u}Tz;GB&k^p~L>ZPU}d2kjSw_m~j zm~RkE-`TJ+n8DPoa(zu3%inUjROGo4o*Z2~Pc?S>>PkHo6OucpNSR(FcH32B*~8DW z$|akOQJ#WROdKBM z1o~fGZq@u>4XzVU_`(UYpCUW3e?eB5*xdLQs=*upl*!mfx6P>~zl-ApH2r?i(o%13 z-J)FCUjKCMAIX#<;4v38FERjmY|Ln1lkwW*$DNdunN!b}3Z=2OnV(xN{waoJ5H~C# zx+Ww7*@mU^Lgt!H_q-czuNBpcHSa;4?Bi;E+w%Px*B9TU+Ai$vnO))&z_fAZw7BcQ z74(+@g%HPn*=`j%JqXcO49yCuami}omp|U)qTM7#APZq9@rvCh@_LXh(N6Wgk;EzD zI2Ew^LwQjq%6J)2mHU)DN02?oPF2CgxT7$+$&W?E8Vzw-@;u)^)g(BwUj#u<`KD^? zybZ}tOLO@~6pu(W5~u5p)J3K%^_o%;z-DAnq8G%uh9;2Y0hpq8EC2TW*FG-+TVGNE08Tdo26jJhVgo(=kZ;zYmcA_c8dN!>>ve$}@4P>2Ho2 z<5-GVYHT1cDI_GnCTpH`i+~z|LmZA<*81J0sA}RI3Jvu#~G6JK9B; z3bi_Yz(u%=+k}@}B|EkL?+vmcIpnUqeMn$DN;kRQpJ`8c^V>5`&$Ul@bK3>bcnUYI z^Vzf8KIE?R0VS}Bd+6fc>a3o_0XkTvy<2!(=Y0;~Uq5>oW&bbE&IFvQuI=MWlp@L$ zkxa=H$1xqGgedc@GIZh?BJ&t2mCBq95tGm`?v2k-fOM@x_96p%@VVjcA}a1q+PLPciGf-)5+ZR+1sSqvrkXn@W)O) z$X&?%YGyQfNz+%)_Gj<&iKxyA8le}*+7>UYKPx^d*`?EUcDmb?_Q%+B^L0mRd*6PJ z8KSu3;Qu(QNR}Zza9!_|wn?`MlQFkbf)Sr+tEoAMjd5G9`p(0xtu1f21W70-ZF%0e zV3YAESFgqWVy|g*e08o^D}9zpLIOx{vt<)SyCTLv+fUC)?V%W3roANp(g2Ta=YvaY zhx01$G>B46+w6PO+3>xmutT2A=!@D+-7Rtx{ky&az1xX_&BHny?x2PSNvGidSyq}CgJUgAF)ZtN)C z#-2@6bzwUP#HWJv9G7gxs9cYjdluG5Nf@yl%WZa}u-G*t4skZblJT8matcGDNS1U zr=$8*JKwX6WLmS`KX+2~%l7euk|U{^&C^~Yp6&K7hw45x+MC`m>CyGyZK_o1bSWt+ zPjqC0!$1=`_Hu2x+?II=;7D_A1vQCrd(@dqCsbLE@iw!NZoOOj<0;}(mQ&DwnM zoeV|6#psCRp4KV-duyV~S<;*sLNwGDEpJ;nolI=&_|W+{&Yv-?<&uo}Va143OeJnI z+#feo;WoOzj7lsL-fFyEckld)9cLRSG;nV2EB7M zpU-c+k<%EwD`E7xkJ*yQj}hffhTb`>p=Nmk#!20-8?#<8iJXqAs&Dq zixTED3+@-bI+Tx_nPkuG(Vmnlo~Zl?K3Ln$u`x`bP_@kOeu-MXRB}me-nWRa@`g_8 z&zT>-7d)=DZUQ^+S2L{ITIAqL>zx-|9&BfjDw$!;kiwNI6Vb6Y$2h91nuD`qoZ^^X zN8~NJp4p&HAKwXg?07X9q#{;wjrWpDZb?rxTXUI_l=-M@|7v?yY@X1Ic6-EL?7%*;TC;d;cJ9c(g*TywA0*>N1~b?ojRX@*nu#IDA^rD#PA3%g(r_d^(#@o^ivV z{!3=4hCk)rErVGP95x%1dumvmNeVE^xIZ8-T%W#{ZBJU3`Ju6s#s=oELu`c8(j4{g z;>8}VXQ4?q6xu9~O<%`)-O2c=@4Sn~61}`~DdQb4xz;rIfb5j1g#C)0ZTn{yp1%Cz zZ#BJJ@Vn(_wWK_^%Dd*;vhmFK`XfraoRV{8m^L|Z*M=0>ye>Gn%S3C~Tf#lH(pWa{ zl$~Bn;UTrmM+L1+6EqkVD~f3UJv(+?=pUJP=e}AuD*SCu_G4F}rlVp})uFggpOrj3 zXFLp!yi9R3e@|!J#Bkr1>Rnd$5kn2`I^j%NozHAjL9vUrFBh#tcAM!Oj=^86lg;6g z;0_WKP{!7(#u$v>@segbsg=rNxTECg#V4~b-WB4sLIaKn9lL(uA+UL10|Gs$=N9VaIcM%g-2`$JU!6>Myo` z;`%9Me_)R!H%Mo0?7O{pie0^2W2h%2km>A2+_kQ zaX%oZitR>{zlDnW&1Buq1Pb1#1qtaM-3*cC>wbFlwH1e6+io1YUNM}zX?;|v~elsu1b_UIAnc;(q- zY8>V>)IIT5Vqfwxzl*|i7?Ik};&bb#XvR|fzu}oTPu42vZgzItwm3!K5zd|JT|0Dc zIQCGlluNh=W#IcHs#B4&(nax06gt?k+{>be6BJ|lR6c#7{=_g9R@)~$K2Ue_A~%~~ z7kP=f?4>cm6(!|?l!1?F`A#1ywvxtNuIR!m{S4*F^4#OJhi&3R;QWIwIiowH zObiT9DL=JSP3)ZBXo_9m?NaB;{M3=~km2dOOx~NB0iSD`O@^cVEyAgLkKQ$TRI?=G zsMR*-{Eg^4K;&QH;ehab#K1#oDweu3*J8KDYBd87kta*FEdZd znOBK)^A_KoFk8AL(OBD4A$X!&B8FPz&=#}n!(NI4ld?D($GGPYukP`Q4F9}|W$m7< z>U+c6pDbqQkU4)%=xaS76}yJ((KwlNFr&QTxrC4o&Wwn)GZWm>%9liSn6?a5ub`%E-aKG#Yw}`Tv1H);(N3M#7o!K}zc6gsh(X{~<4Nia0h|qmW>n89UgLMtc?J#+j z!8c}7E*9m=fCB{Hpsx{@-_1B_a%*5J8CopC|-$E zf&ad+HmfXhxN-pJG&X*1oJ!L$?Bu=7tucow-ZEqSC&{hClXhFunAVMWuN@t5k(txK zR56^P{hEpPBrm+2`vb0p3+tX!GhRGn5H#gJ)qC*9tOrZD zEP?B5HP0AdsrfGO{V|I0YH>O46fb|ym};>>*OpUOLmi=qJi<4t?)u8ybl!%|rKS^C z%K7lX-i_QvZzR@5U{vDd*%p`{S`5lRxXb`8Uh9IV@|Yge`=2lT!l z`an=Rd^j$Rni6~k;;kI{hmaxPxPTlN0nMJ_SOHh>8;6Jopbnq z7~ednrruv;JH4r1FG-;PJPv!S>UiFVx$lk1JHY2}rJN%(Ro*mm$EK=OG;&`{Rq1Ht zzPZzuRky#G5ES0xu*2nkr|(H4<#8tMtB=w;xlS5sjGw%3DxAMbyC{YF62X|u-6qOa zU1QKVmseshU)nIsAq}k@iM`vssio_8=!~9A9hJLy;QeB*))(_zDV`tqwaA_rW@mYI zmge2V2v$kwcB_+x*H{a*%iq77bbaSUBVn@mvu9toi|?z_vF7;e9DOo}rC&A^dNwmG zoH-&ZS~G#IBTsA!-$QRW?CicxAu}f9)xmwV`?Rvuv?dIey4jv3h@ao0+n8fIpnkS( zy00&wOju@Y z{cFSA_}Qro(ubxlDyZwr+0yaNv|ASN7fEcoDRw1|O}+h8N`>WdlX`n{su#T5BX~L0 zuWeS3)TC5owu=>gU`cPNdU4(XE2+xB-gsfh6FT!K>8u#x;->|NGwmY@E;;XNQyO`$ z9}4z8)Lea?kZ8icz3-&$^=#GaCfr+|7@qF4YZPp8eecmw8h~|-Ot-wu;%1Q{nsZ@~ zT9#_9cV#sPSK58wS+CcZrTd(xU-xp>ybBI`eR}atLhb&R$#{=#DVeh++>GQG8?;Zq zV|zB+sjA<>@>HF&F{|44Ri974wUy&Ky^C8~Cs_SU6whwX{ZMv-oiT4$)}o(Hps``U z=WO|StHhP*aXGQ}h%?(5GuMlj3q1*~s2{N2+x=b1Tl?&`=*;z)^d&OQy(e-x%8eS; zOAQ(@&ZjT6mXAG?(fBIH(izP4A$<4+A!EZp?V0=6%c(CdMvBmKJbLy%HP}!)ExS8C z^+cv^igMOKA=fL}pyFM$S)V?)=pMOzgdmh-&b??55bvDHRWSBd;OF>;1%vSQ3mA=@ zb~ZQm3R}U}+Ba`G>pb><)QTg&|Ja=ILr~(63w4|QGA}1&9C^pEr#<0dk=5E3vPh-4 zrYzfQAIG)4tLR&u`MQKs>2}3`kBt||ixEv%+|jrFvvqakWt%6L zs+<73o@zUuZl9BRw5>pA&&(k;%9$O6HK(^(hgHl8y${y&;FG9%PZs$&?X7IA&_wFE z-sxh>h3O^3>20NoJ|o{-qBkCTaemxpAkm%Kmo21}Wz9?}E!HINr2Wd-K4yHSX|5fhv2(CGB*J%nOrSk{eo-enC?#!ST~yhNt7Z70;@3s<6S4Kz zpR-KU-YlhkBg7#_b2h3t>E86g`2uf_*H#_I*>q2Yk@;A=epEv{Q7J)%tc3xb>PKJ6i6 zy4Ta0t1YkRt&K3AQk8`ik8hL~(mZZIX1~+4Ja_+N8_~zHIxch)*n_PW zY~OZk3ifZj=EHFOa-#0WH{r6|Xu-k#m3e0of)^kn1pj=%#ciy=KUr6(7gIL;{eji~-) zQ1|8P_b-{G5p2+@v@E>(0l(#xVSUT!iI@}bg|bglkyFPX%}Bo7f@g6zs}UPXNIt{Y zG>1+Vs#)s;~?uFl`_(k6zZi*EA!KO^loUc8jBo zO#SvX#m!0VL(gJGdtcZbk*nhjRe7PlVMaQb?}%LeiEEsCu47LLVs4pZBe&e@2MrZ{ z(xn8c*+*k+M>{-eF5P+Lc<(~hC5QMn8BgK%jQfvxhV7qH4ldd;d}6RX-cJ4GfqC}! z&o_F-w^16gwY;ml^x50Jw*9Tg-m2!=)RYo=oDxX0L^$RfgU@B)x0Ah8TKwwj4NrO2 zo^+vhufYie8c)S+$=$lf&L>Y>=y?iHu~F*zR!whvXE;d^JC;>Roi1g7RYvOk#%(p69WHr0_4#X`UAM`(8+=Pq$5X%jcA|^nnXXx! zfz^-?^P6j7uPconM`48W*HG%jzsP6r{6d`tZencGC6p&omyGx4ol1Q^*uSvn!^GYZ z-%@?~$Cc%8jf*<#Gi6JUVVQ(69j<=D@X%~RDw_soxO zroJAL+|a~OJ&}CNe68uMIyqlVya)CjzG;Yh%SLJtahg=k@UK{lMQ{>v|LNyxvR@@}5 zrDTwa!-e9@&*^XsTrH{*3}>RN-|7vd>~=K}TfET3S9hSAq3aBF5u$7L@a)}^QO_`J*zM~ApZ?2df$7mX$C-85yFxn_;XhH=L7 z$L;7Tf1Wc)|GCaI*XnpkN~F&|*Lvn={|^dGhrMExj8D^qD4eEYYcf`;!%v$&ICEL& zmie6ji?Va(^FLz9n<>+z&hbWJ>Ya|pvouCe#^$fR`Ov||K1_>3>vCqx{Ls=d(_>G1 zx%iycKj-xKpEucaT+Z!g7a5V_H;a;N{FM)RkE7=18j zGhq7R(4?*5xrXY)A+A7$15Y`}3$LxAk2rUYEb!{N3W{LOw+yyV+eSv#ncRK**7@Zb z=5OrZ_R>|{ddbY;JB9xd;61Gs`*CU4P1p3N!|z4qohHVQeM^`*1HL?^KUMp)baBly z#<{L=x)Xll7Kar&!o^}YZuN^Q&q(I;oH{;rweLc~`6!Mx34Ist&AsFIlgvE+GQ7w+ zoFm;y#PK8ZesazAPWyIre+oIj-g}XA$B&og<#KW_%0H6ZR3xogBEQEd$FzU%4x`C+ zueGLo?=i^L-?^nTDfIgF)WD2PCi$#)N41RR6zHraZFe)$gjh?6YNAdDP8ry@O z?eb(CKiKi`+eVY7zWuz(VLHb!w~oHp@bM}uM@wdTDvMpa1W)(4csPB`4KwbnZ}(DP zx{Y3uWJ*eGGsE7kyd+-R{qb{Z%T3V@lVQQ+R!-Lh(;f+M#GgAWM4oi9NG>B;cTJ^* zV4rc~L$~&uIC~c7_A4qB4=7IwyWG`MQ$3n1V`ebP8lAU)(Iu8G$7ox6o%)Bhqrr=G zg;^KBMeDNc3COa%llAUV537Ke>GSPToN*!Z0`x(~MZNnTGGKHaAMVoTDiwC{0BPk(%4ocZwC{$-w*xcczzjdp^2D$RBY zz1mZH728tKFB`ACs5 zbEpr0V5f15LqW7_v*Re{2 z!lSqSj*Q$iRu4akd0JD@CBgodz5xG{u{f#6w75!gB7Kg`RX`r3%~uhSf5|5xUumr$ zQrVc)BQ0+bo%j|O2WEi0!*!=50=EVoj2dgX|H^7HMi7& z`uJ6Wd>i%$g^Z8WuDCpy3wYOf_?vE}r}5TSKOG6z?&JwgzuWl73PyvH%{@O{eJ<7R zF55z7FZ4ceC|b95typHt?IdRc?e~wJ4gvL9r5F9qoEA${o~J)PGr9kDM3%n}F4SXo zvzz-E2g~@_(D-;Go#~NyaHMBC6PBV(a`23rk${ zJ?;TdZNdSyucJ)`W0bSXpF(Rno@~G-p3+iicRtz_^hTA*bgK8=wW|44nY+5~HRk%x zwc<^TgH7}2sa?Jr4T^4y`lxMy+m0(6_Rz@=8~Lh`I6M9JM78&8HX*L*TYM=Y@rGrR z%6^{AYG%WS%Ow};>@V%#RD8czQ^mX{zhlwntJC9aWoa~xWB2xr+;&^Y&Xd{CL=ay* zedg;YV(<Pdwv(_Kpq z>T`*$TI=?@RPL{-X5|SOT-*FS{r0ivp$DF8+`hB8_D+4*OtpJ>h2OKvE|u0eyPew> zSfho4_nF7Y-&lNPNoDCo;Y3%m)o7<$jC{+Nhl0Vqr`6Q9v`96{T~&TkI4a(MPA%@j zY>|SWGDW~0_O$O?*K*&XxS#CeG%D2Wvg7>67cIrFiq1X2WeiwaN#%TewRMZ=X)QyEO@)oi?5R+R6OuFd5P-iohD&cJ}aFQ zk_!Ct{@kL&8gb9IWvEkryM66z__ccnb6M_gJ?_rMGR~Dez9GWG{Xuu;cai4Z(qB1D zaswoX^G7F{^7l-{?dvNE@OET0uHZe=cfof0%jS7y`(E>QTj#WQmOErsL(iJ((>TVk z@*N7*OMXe6<}8INx;)pRX7ZW)&Aq_)Eb2Y@jsO+WP!;USv6LTfvIhgzuPo>v4UG$7 z#U|$-jHX)!hPGR)k?w8oDpH5dPQ`TG6bQH#K7m>@~m^sW{P4gsN)3x4+zJBpbZ7kO9{q(nUJz8+<$`p8Iw>Iho_`W;nz?U*Zzd>#Dj;G%_ z$9BzrndAF>|Nas?6y;fJDXE%(2#;sWY7@3N=_t>@!PdgjlAuIzBUrdWcg`JFgm=+~ zqpsjvBR?~Fy#wg{s;i$LbgASH6t-Xx<&@l&oS(B@$3p6O5k+H9eqMoPpQ*}G|3uHm zi^Y+RR*mnHsqnE@V&!=rx}xNXlO;b7EZ%7v{^mPjdArOtKUb*=pL%m@??lVq!H)MI zKX)uqJ~Q*BdnUQ$LViM;y&JS}5N0 z5zpKFn$lVf5lx<)C`0-rAtuVx6BJ+Uq9V;8v3(eX1rgNtl z*~(pZg_yjZ?dZRyx}Ks)(cVe*p=02eZ<{>SL@SFjpJT=3$36x459vGKxU1)OM9r-= zZ)o4E*t8S!wkh=#G*9EjBsN=RX1J=B$9&aQ$l$ZBXHM+Z>=GYXkl7{fwSFuw?T(+c zT^x7i6MpPIEA{?rDw=kFZYg}-4NPKzAI_iReVJ(= zRJu7nEY2mjS>2r{RmkI$d(#`bSWKe7OLN56utn1{`NaDEg?=Wvaoux#cJbf5cCeeM z#?5Fp7x0X|+kyL9^H#V@{%cR6MREh1#DIa$gKx8j*9`+{j|!dt@W^o2bweGmGJlDC zLW++2-rrK+*p9s(O{u=+(LLUj1o4WqqS3C7@=hIl2J{BB4IM;0ZV9#t&#!l;3tykZ z5l-Put*9`ISD`C=foIRAaAvbmn7wVJ*d$Y#Tl>Ovw?yxTaDlf;uPSWn>ITPs$4o9g zsR+4i;h9qFU6ByNg6*ua`0AE%+vS>@8EsFMm#$*VIsB0Vy;Fr&IfA>kHsuCm<6=i* zjc?NSke$BZWqi_0H7wCZZg-W(*qeun1`*hdxQncvZ|`DdIvtra-SEQh&a=s3Qs?Jb zy53D0(mD3BKM4wKEb#a;g@S&&HCJo(mt7tv_@Lx?9>W z&2H}Vr@gS@#I|^6hJ8Huo>+!(+%doDc!FG7z2$b-)$LpgyV=Z_L?-uSKglqtyCop? z{Mz}^)Pqd9mKonK_}jfYb|+^-hGQvH;(BbX+TISNzFjKOZ)3_fRXKE9M4)EjO!8X0@~%x5=C`NLO)yC&Y@j&mo8Ic>6VOi< z@5JKwE~kI3tk;FLmve4+bII$yN!rtQByURY&;rBw&D8g{T@yS7FRpS>&qmz6Y#a8B z`d9*9_EGWpkp(%$aHeCnO)fW?UTfdrGd#|AS*M{#`G<_O*2o!M4osu9mw&{qaz?pu z!r>IE%U*AdT7!7P?sph zkucl$Yt5N5Z%Zx~o}`F4^?EH5ceq;O>fxbuWAuZBwgHJLX9}YX_ zMmSDA?rUee>M6}I(errevv1v<`E?vlY<{7mh3DeuXnttE+Be1dBlP2^J@Ur-4y|V~8S39HdB@%kZS}pG9ua&$+^piI&7f4oETesKz+|9-czPg1zuPS3j@AhS z+_kZgizQMIl~cAG4qqw}_}HL2D|1wUziLbOJYVXPwV!;<+bh{~{PQ`fE-PWiit%HQ4+6 zZlTp($ZPv-zVs_OLUZy!`fe~2Q_-w86El;ZiSbUhBILg=ri1@Z2JPBF59$>-Wafao zl@-B7+tJbf_X=D&tYqU0(QV2TMvF=AZ;YJmn91eOQy5V^Ptl`3be1}l2YmSeH%BHP z6|3IW|Lha>x0y2~YsMbdJ*>V;-xKjMSw*Lrk@JzRT)P=sN3)0lMuDORYsq3cpbTIBTwHhhm!+s(H69=6=y%<3L-Bx9zOT(dh_7)nL$>c z%2V7z=>bJ}Hx?4oy6t%)+vJ-? zD&lRr6Q&xab(f*jC4`)<{EV07n|^wA8Ye;d=VjsHM+`R!3wgfGeKK9YR&PUnyE^wa z{_wtV{U{yUF2je6T?YPGoGs_x$;4;}zSxj;F{k;=1b9y-Eb0~pq)i`U;0)6CZqFCR zCqEB-<0hfW<3Tgrj=4^`uYOVbf&0~(xwscXUrbIOHgZi=VaIr7T(i3yPZi6<@r-L@ zmt*9+lp|SD`9GkKJX~OYKCnBDMo1(q$jY_Yr^>x?_*ACzeX1!i8$~~eM#)>db z*_Kv(@=2Lqt2KV~rObMotKJOECn{6MPf_3(l%Dg8nXdo&STCjVDMKK(aew1mE9sHP zjxY9-@y3K6D{q=E-RqI?Ch`rw(I+SYUo6b7{-|R6mTc*61NZ$S# zNHbo(!IWZmmL~!G(Ja=;bEHxs_lsVS`{T*}^X*FyBK<9m%Qo$OqsFOth3RDf@pB^8 z$KP0daQ1JqcyIRX!&xZOAC*eF-3~^EoL`#JHES8j7|1qk*g)1DXr%`Y7Jml~Dl#A} zC3-ZJ^%aBJ)v{+V`2Bx>s-d8H=%BKm{vM5k zD=k2O@)u5w)&@2mU97>*A~AFMUx07kFMBTj`3t;*o4w1be+Nd{Wlt&5-+73y`lsLv z6U&~(m4AB5*3|;`_jfM{Yt@3x2s7Y)p)WuG^Xvt_Lr(sFWq|(m_sXsocqf7$!P%YQ zVDT&64On0O9*|cn4UlPj*<%52N)VaGySq7_!n@&NuV)hf#C8U}$P#!(XvF;INkg=u zps#6Y>uUSIuk5b&UX1@31iwv!Z&?z(m;3L9Bji?h(27CAk2gt}I|0yi+ z8;%t<1i=wr#md$};79_@5d}a+=ZF~gPoAiiEmS|`_JkV%#DgJ`xZ*>V(L!)iQlv|3 z+FJGOH{i)bm?u_hs38&vO*mA8#}W_DT%^E_a^fm^p@|xTBkjnx7z(COz>!3lBbRm2 zGQ=biAnPOR+M%S-(J)B80a}QpI6{?prSqSq0i`trgKRp27J|Vb^pbu}bLJ-CNf-=r z#sn=y42$52PBVuF)VL~OkbHBr5NVtQ>5AvWhxxn*kXRUGiv?N;Rsx~8QW)hoJO&VD z03jY9)vVA$FrpX)S9*3j47>&u_)u?Si<*K2!N!;teFTs=Sa~JbqlJh`OOvjYhB|7g z&j6AEgLFHhg-D4bjKbKGTUx1LaLfiF4{@bnUC}}?qS6R`UR3MBS*U%5!d%&R1}#Ng z8lk5o3f$fH20%h!5btwnAs8u1(v@QIDerzi$x6w(fEFSxhEVhC?%a6Q2_W$9IClvx zL=1!ANg-c<%m_(OWP;E_q@@s=*R;pQ%rY2g&3<)uW(i(2?Y3Kr_bqChC^b^rS#6=MxOw2J+J3(oEhC#01MhlS=M;M0bj(rfi z1Rw-ZCB((WmW&!AiclwJvXo>kBwO(M`)DEJq6m%aO1cm=H}C{n(hz&1n2r_##xBww z{*ugH>0y%Hq&5pJL|Ou&;^z{Ae`0|rOt3m($wdp1l0X=QRkB1V(*PtB2Fb}s4G}{K zxWDJ{Td{iLVhAB*(A43DHUPN}Ys2<$&_fVLNCMxh{ZL1N z*L->tT8J3ZFq|GJF$V1jhQmCWY(@*gi6IQb=b!e6lipkrZ9@yeh#|~cg;Lwf=YS_A zu;z856Ey@Qia_}`Rq+*CHg>?u>sdEiiZoIiws><>1_~i>z#w9MXdzf>1W%qX#hF1J z1s+2B4x)vKV-VV~-S?B%p^gIYjZa2ULy(q@g=Cx|9RLymE3Ub5v=A{d1W#W35#GK7 z5O_zyO`(P0#1IDieRN^Uf!oQ*$}lUpa9n25Lr703<3{aD(5~7oSZSHltwFh~hQlIE zDEw>B_&~E39Fk6t8X}G`p=3U5WQNu!xxf?R4X-ICv=F4_Nsy!j85GCc5UONxLc9~|CGh^v&Vv>r zE{@Q+p2Vs>+Xlv9_#()V4=qFrDI~IaZ9N0k34Drg5NXplpQPUogQ zXdz;f2!qO0OOGhDO9Xuxop=$Xg+U9E#v# zk_{;EIJHL#Ekz24u+$=>J2nJuKf`6UBUx3OBK14cMp@txxW?I%$cS1Xz(5jJm^vbeD3lT$#Btm$(?V3qKChbu} zkS1XEJ^@@YFZejZ{*~d1pc7gM7NOo5>9fm7JE9hYmLY{hSUGt8JX)HLB_lg+xYChJ zai}2(;Wim~K!yBzz^?7GC%S$G!wK)=N`T1*id(vvwgFj2Gx(8P_UB||t)va8xZqEn z!n^3Z5D0%H4LtS)FM^A%yFJ0&g#f-d#JdvPMaRzb&6b7*ysc%Rd*VI?n{qt!gCl^RNVz21v;QH&M zNvpc?MOym%VL;LXBv84_p3p|pBz?^T?zZ+oR>1?@IA!aAw_g=dW;~$j3;=}yAhygr z7zf{x1}t;M(FrQERqccCzfubU`)h%H1tR-Ypb-$s1%5Xfb%K?fF2Tax#nsk>09CUQ z-rf#);{tv?VDD&Qw<>P5fp!!uGsr+SkjW6?l3PgPNHj24_Y)9oRn8UZP&EfIS|ZNjIv3q3Y@#;I&7=kK!_eWMsXatD0QaHwa!9gkN={ig&QIC%CNY z!vVe>`aa+c(HCfG_=$inA4vigpsH7gx*w0yK?N*ARPc<7>JH>b2l$aEGOIL9(kzK8 zI003(9?-kmdade0M{CV}HNb&)kA@MFEFg{g+dY0W2yUwap!WwY_t!%#l{!7P0svjO zu_idc#yse6|C(U?ZRyYdmLZvN!@F1$++ddccWrVw4=T%mlZ;G&$kL{9gqQhaNySnB zmr2qs&rWvp)o!qKYXG*1C2;-U5$yiHFs=byw*Ql5fwXDpE&nD#zCdTKfv+Tu^x6BO*-{{1~c=`MQ&)~))U z7B=nBssZSDVjN^Yfj=%s<>U(c35|Nj2x2ki>; z*6y~jR!6b-#Mw{a?HWO?2@?JJJ~|SA{yV55c!J?v`IM8J_aO^MgsF-5e%Q|KAc|tP zA|vA@GVHx|Rl}qkEM(!Yn?S#^?CDilVa^TQc7XZG*E>hm1^g@oeiFwlya!1A{r@Hy zyo0Niqsu96TPK3OtpkAvA(S2?dzbDGUN8Yn@Wk#~D3P+Sjz2-LM{YEbe}CO&TIMVn z8J`L%b9h(y&|fF`y3Gg}*$4VK5O^+oP9fUR{}cZy0CBg4J>J!IWpm^Fxm1|CnT%{0 zIJs+?Nis5)!$>dorz{a|LT3ItOFY}rA0cJajd04z9`8nQh1K$MOFTqxXZ|mi{>~&T z{atR6c>a9!A1&&6+FHRYr}lKj(Q+;_GTGpjK|0OR)qVc^roZj}`rkdSZq_SbJT2wR zu^XUNcYx(K;4FJEVAq0Z7X77B2bJVx!=ni%QqmQ#%N4Td2_n}K(EErhe*3u<_WmbK z2a%ID_1OHejnP1;{%1`U2_KH2twi<^)Ql zWBtm_g=kPQL=EuojR8ctzc|7UuZKewW&o50eDl>d4=qCy={!1lURsE>dM*!WT+ulq zjdY`+P^eP47PQsxU~xsfJ4RlF79xSP>#h)ZYkvWN%mWDVIUDvlS_sndDy7BC2j782 z&j4)l5<8+%g_eOsl4D<~GVX`=!{POw4UT%yRS8xKVGGWHhB|=`ijhHy5qt6(Y~rAU zNJ$|a9NmAUst9ep!q3?(fP?5D;z-AmM=E&kZw6gaAJ!G`fE`(M5TuRjjkHZCA>A*0 zqnf@4Edz&iS!K{(+ZU>LxIjPy$Slw~f{{Sjj1au=QUKa=hwCXqhR{N=NXOCnlv=96 zVA?whx(e~>LH#IN2u4%_Ve|E!m2VFu4S|o3gfzk+9NYbjP7L%DF5nKaD~n&y zLNFL44fBA1MIRZU)WdpX=2JmD9$RgO~I=v=9j-afsMu3Lak2fN8+SKJk2VawA%ZI6`kE zW1z{+0#%{_tM?g3)C{Ci7$l5qg2Z$1129S!v=A)PxI%9KsIm`0;JWgIY^WhfGoyOF zT>=ET2`jE}4zv()B<-Afj-ljQ(1PI#lvXaZ5GhH774@8*juSN2!zC5_cAds z+$o`u%mv<0^ySb(us8(ik(J%Od=N5_#lwm#b{|>@1}V4`XJ2RX3^d_9FliA7cOMU+ zg-9W(f*6#V+9!Y~@abfo3R;LX(yc+YEZTce#lzLb#)r{D#F6xjN6Y7TkPf`!G|)oC zkOoLLnzX%;C-AFwt=ecIl1K;ZvUHzqRofO?(u;y3W*vGvfU z82I3&Z-kbDl|oRUsQZ!EL5hk6@)C~1_`1&{eCR&I%(yCF&`C%orVG8dkwRg}$q{I=H z4o=e)Qcu9aD}HcF;Ra# zT8OkbLd`!_RT}>eAe^whsG+xLAxMG5TJ!ugC`^SXw>Z>{mVuE(xClP^Z(i3$Au@2(- zFr-dI2#EL=t`|cJWVk>ycKd%d52-_4fFx@*{qabIwJTKR&;@SMKL@NVdQJq3Rbl&Y&nc3ws3>ldu;mr? zuR7sv4FOxcfg4bZCXT-?c>mS98zf!)cMoc9Hur`A26T_`08wMu&qtE+OGXXE5c)2E z1W`Z%_NQL7eyN9DS1qxvyh$?tfCq)+Kyt9`k>e-HTV7(n)cb$N%+)bdLsJs&00ZUb z6JG`aDe(pW8wRxNRUK(L_X*Dh2(#elAQ53vh$MkTdqz7I99g@+%>|5}4z8g05-}t8 ztYGT@FVpWzLCjdn{d>@TcR>($6Avz`)+>zsRT%vd0xRkP9gNd&F))(c=A6jd*Wf-9 z*;P>R#8cy=lL*%J9Nk?k2r2{zeHUA6Yl4d_516(7)0k4muUH7xfdGI(pRD@lxnPd~ z`z;XuExi4u*IX`>1qvn7yLb^=mZ=bk9|qbCg#1K%g@4OzIq1L3aRcM_-he>D07QH_ zB+l_afM6cE0a+?(muijKY;FOPC};}2{}defjn{cqlAgDN1!Z`kb^QNz83TDKUn*p$X5y2CS4Ak z=c^4h0iXZ?i2H!H_rJd`xZ4BO8q{W>&`pH^T`59_`6M2f^aC&pP>;|@4gYyI`K${2 zJzC@Ke+}rQ9SJJvqp$*Y)xl6f9I^NNuCNVBikE4E4e>6&H1o<{;3kwC=wlwXNP@ZX zZia>=S~4)hosb=qgH3`Y6 z@osP}qB5?R8LR}!bUp0xMJ{l~ZcYuehuostz z^8+fN?LLR~=93@MLJ-wCJ~V=+qy-dAeP|(KNU1otXLB5b4k6*iWjKfyf{GX=RO1wi*^;Q|WA185y$a+IB%9O{hF5jSzg4}((*be>?4 z&bvDDXUGx&WFLSK@9gkvp@xVemDl1^ot8MDCrGh$Z+bzafM2%*dYhnQjPg_ePIIv6%TYX;Q_yxRBpqGjN42#0D} zW1$YDPti}FMGL_orM;loohJYZ%%CWacu+|_j}{`0lt3$5x7ZL${Rcma8V^7V!6JR^ zqPX|?DLzo|KVY6n1)_yWBc)L~axC*35Ck-GK4^g^M(7NZc+OG>8Y*-Ukd_{S;(M!-fpj1d8iST1g>?G7v6@y1(tg3y z*|mY#0;MZRp4{dyJOEV+Jdj`mN9!md5(r&B!Tp?zF<6`20_!Q_N;!5LHAECi{l%np zL>W@fJb?8SmiuTaVn`X0%M;Figu;5bn(1UZT8Jdl0%h-{s4!_ATWJnUom82 z07cyJn*W-E8X}Dl3{MR`2$=Z63lzB2=vg0Hh#1nX;PfC}Q%E!g?~exb`&i{5^1S5AMou;G3Y48unG9~XS5IuqW-IpYIq82!|*8b#TT>` zDWv7Y<;NY5p{NMHy|Qs0Ed+yf(=~NTi4Iz$z~@HwCA1JMlB~4-#!x7zI8U-^j^ zf#pX6Tug!p|Ku5 zc%{;#g-9YLb@OZ(DuH51IAj=n`~+Q8BrT1wdI%nID2B#*ct7D`MGL_p_4t;lLtT)p z1g^+2V_yM56#o62uw>`dn+R9HfQ!GRIR2G^2VVkRRkjlSzV|(JhzSx6u1HU^0W>tC zy7=t@3E2ub*wg}FR|Z)ES4Z)3$+`hdKByI9FpC|%KdLm@`8581J*3O%RB<7I6^BZkTQzrxA;N9#Tq&DR)w58RV;{3EkK?lAtIAJ zA}dV()%^U?Nh#r7+*V7OsHJPdKn-5D4~*`_`Vc1E>Xr}VJ@9|@SJ1C|ZXl_WwJyN{ zWNbyszEkulbKNdbDwAL(N4z8r2jA-=>V<#Z_$^&hSI2-{M=rnhegLyd0>pZu`HRe; zjwygs#EKf0{i`y5>#!i1%da$OAXOph^Kp|?3ui?DKpg;x6Y@qV{1*TuxkfbZL*<+e z(!i5}G+rxY2keTg8iyo0Kso|)@>(8rcleb8nDpz6O>S6E!0_ifb-uh9=S?H$|=@{XIYR1Ah4L$bLd z?;Git4dzMxMh7aV6Rb6e(|I;rTw(ZM&+rj8ErlLD`~Ypg!WRJwSI{EFkrrkRyCXW% zz!l6EFl-Pn0=z-eAfnOxU;U5}L+~W{lEevczl%%^>|YU25tr|wg&-x2@R_x%AuZXd zNk_|&LONRCes8}A>8oW_*=Qk>NPBSS4+<7SvAH~K8LOF#79x%GdGR&lSXyWq3*RIm z6T)g3{&3hW;67 zmjr%l*gJ@pB8`+%hYK$`0A(kDmlxY8T8Jdle$RPUns<;qzY*5FtUsfLNFaTy#zt#P zD70q@PZ;rG3N1to={zq&+nj~;-U90vv=C`5!j=A}JI}C?C-6ixrgLZ^Vo1A*?pa@G zO+bAVf~k*q6u!BL79xRkbI~&Tur0XwO!f`z_YjZ5=4;lY9O{v>9DU;8{|0?;_8jae zB#HtpLjviF`c+p!185WmXWT1Fiz)_zTEd-pmAmqOA zd!tGNowdP-mD#OmDH2E;(7w~uTInG6GX*O&;?{*>LJPqmebV@Sx{|;RFm%Nwfs_Z1)3j+f zwD}qgt9UmoT8KE3N`T65L5B26NR}j82nI5Ftmr3{QvpNEGM<~C>{SR_yCOlVvC00bzSR&>Xkc4#5uNOG-( z7>o7`pb?*jH)0305D;@C$lEG6)s>U}3gsIYv=nKi$x&n0IGl8+=k`Dg5km@#4i-x0 zodcD!1ZH94?r7qT76Q~R2+M4ieYeg)!#(^=`hYK53Kr?>->HdpS^x@F z;aPP;@1TWb*Age&=jfZ_`7yW=M@UKwzJwQznMLNT` zjj<_(B0RX-v^obs-W9ZB8@Gie$2rUGMlp}~iY|Twb^-u~x#Fv;2M^`}L5)tU+ z^_UP=LC| z%@N@s?l{FO9Q1uaX;2jVm%S+&*}@ts;Z_Sn zG7=yvI{~Uy8UK?)kS?VW&1j`UP)bl14n88g8q}-W{oRU48=V_~25SFg3o!fh$MI}5gn>&IQfBzT`puks8kKz2!Jmw zLXM+_h#~EaNHNR5fz;>leWYp&v=A)P(&BK$^Cu7_9@bAbSfhoAAstF>uIUQ>1|S6h zLcEWpdJ-)JX=TB1KFc4<(+c0>Njim=fkoQlaaMS$Bm-nRuYpX5*pWdev=F2_rM>=) z??~qe3J5{VkVMKG(b-2Q2&E-~>rTqU(L!)Y7gvkw(~o}vdppJ8NQ$_$Xd}@=kTN=i z&?hpi0ka7_0ftRHT80$TB{m;A+%0J51uh6_xQP~mMOuH`USg<)wkzPbCm8Rdg-9Ze z^ObuTd7xebAA*fi&_ZxXXKUET@SYY>CqQDdVup{uj}`(FKqJg1EY?(wP9V~;Ijp)hXZU(+yb9GCw4@L7cD~^>9DhAL$_`ta0D)+cqoh(B7qb>K29=j`@scrZGw!s z#C>s46g33lGM>Rqgb*YOfM2{mq>q+?MY`Q>%*J-M4ulYCU_+5u<9*QxEd)VUs(6h0 z{S@%y32bnDL_mv>K)QqZ-moA5T9U#$B9$##$p2Ax7T{4{OCJyJ(BQ5?izMrdhX@WK z39gY%vXErMW)lKM3KT0|T#6Nk;!vF86n72o?rwKxlU#E4ytB#d^W^s4@A*2v_xL$; z{%6KW1wp7jZ&3#23=dwBT!?|Xi5iqIbK!@DAqF69gT*6!M@!m}KzK?M3CY#bab>kc zLYREzIpsjZS_@FNEK4Ys4o{onmg0@{3Ws!i zmVCOdGnNZ6QjIcO9c14{$ldFg32X>8J?09||48`=zhM#=qN37nHt~*!1B`*c5k46R@b|0~Z{R z^5$;QaxO(pZMg3|_<1*GKllxbBCfx8|K>udbl)Fq-57OmqERT$P|9S zsQjwG+(s@#PYHC6J#8C{l{HXm_b!{c5a?aRk#VHKZDn8!oti6PPHcw)@<=F4lFr;)6k5HEGjyMmn90a zIyete^5-+R?!N#G9bj-APW8)~SrMjGFqS> zsx)J}G||q!)(-&tpfut#7M@KJk~-9eJ)(!bcuorvp6S=Rk9@$Bx5V+j+b4%2L!ri$ zk9CDkW%vi%0+)MHc`&NAqUF?IA7qcdke=u#MfOHqSptYBaD6RSQm;0O7%KZ2NZQ!%T_(N@a5T@l+RM5(VlHlF=SI6>!`7iM0Fd$O> zriKvaLHiVLvemMOZV9oPW0Ir9xTQCiOZ%{_J%&TXn4;qy2Vc=J0x6Y9dGNLE;XbYu z^d*eoA|?gw>=LKeTVn7NNH(YZ z(Jw8HRNdgCcfdzCPG!`^rQHgrW>f2pB5i@TnRq*5gaUA2&LC=R5F`9u_dY8nnGeLD@4nI|8#2@{a)C@x63FHf#mB@CJbabaJ#dU{AfSH-_ zC)Uq{%Sz@j;7Xe~%o2rDB^h=FKMZQz{uAY32d*fY{gKEiWp?xH3!#3Z)spyi{o@^X z8p2J=rJjyEi1LX{%Si;K{79|-ZSnUv7*Tbgi7O=+Bk3OpKPW*`E5)d382|m0DuJuH zRKH@MbGfwi3G}Sdw3TnIsGxXLv{Y*R|4#Xri>3NkU0gcI|1w;R)r1y`v^q6YRxmT) znHjq=jbv@Jwq)H%uwsEfG3DCJbXbeAMAeM3S|EU)&1{Nw%-A)(Ywjiep~R4B#$gw< z<%>fL*p+oYu^~Y*5QVCDoGCiQgyRfCb-BSH1}UZ+-TkZm(cI-{Xyj*r5&dbizdK;k z7TbAHE}|h@OX*RvBKy;7WXdg`8`7kxwZvnzm&0F=e*_Tu=|HcnT!?}4*V+cwd5xzZ z`OaZ$4lYDZU6wwov9A*&2ox(sLmY`Ga_gW|(((*K_Dxd8ML!sm-P6DY@vJ zdbvxyfTC=a#-d*XF2qQM@-M%>hzq)*G#*HNh?cYL@IgFDf^ z8Xhvyat(TK3H45Kp^F3MR%_|rrf{s1aT=UDjb?_;Lb%G08(EX zj?F^35CbI(s~hjAEm7-Ij*yo(F*aHj-u z`L-PSH9MSAFxQ;8nOK#`rRb=sWz6D_t1vF5yz4G;lMB&M4ukjIr+vYxMSdXArE<{VUN%Q!AR%K7o(hppShI)RouSxz==<|}_1U>r9 zg{Y`tEb|^m%|)H9>{!!%=R*h=OCJ|&2#ynZFb>U_hv|njQsKQ$&pN5Y8B(6?_hjKh z)Ks?5#)WD;e-Dt|(w;j<4lcyQol-3QyKu%-tS{Lm6_%SzF;F_lY*){P;y{@w6=hLA zE(G>PgwLSI2mcWm>|q4t4i~Tc6Z3N^RIt#_Bi86~G-64_A^)rxm!YD%*RgG#8@~gH ze9m?+#f5088FIuqOCubO3#F2bF3W{zsJVW|qxtLcf(f!%IaJrh3S5Yu3W1n^S&4jj zY?PPAgvwlqhLR5s{-Z>q7D`e=D#?awT!@wulhl1WdjdXpkmr?FHMtNqwH@wQVfxR? zp=c+2a3LPlt-!WO(`MzM_NO&mh=FpgwZHYDr*c5>G6pV0E6D4&H1nl15`_eJ({!#SQe<-;Kd(SQd4z_vAt})Nc5JJs~7vsA8v?*NZW^_9ITmtxcsjbg2FKiCtB0y)MUW-oIKE<{Id?Ay+n z-5VV_a--z)<3hC5vgO`;%~?D+%GZtF0bGcRdii@TPxZzKkxMeT9T(z3-D!Gl%3Nm; zK%%ALxU(Z0;z5b)m)|R2c|B0-OWo^U7cNClg;w=y`C$WkZoQZ#co1q)+)AE`QpBaMMJ!Bmwmhe0%KYutd=!q#2>_Q{6d?)~ z7-o(Rij3^*6&Vy4>%0c9?W&{4aE16tOiT`^?yX33ERxj}=Cn9RzjewTuUKbUW77nL zTZ2F*ZbhYxQ%J6BwMX>^$Yv-71Z_|CyJ<@k5^b@8h|#J2o|`;lo5JOME(k&h*>Y0- z*2O#6|DmrHV;d^ppG^509bPnti%Tg8S5YmMSr?bUK@NsfBxqhqF$n$4F{Vg!G!axx zRk`X7l)pZPwa`qI|XgcM$%inZ~f>{8Im5D!N86Yl(WjMxzN_ z+h{YEC`lm|t6V$r4ZW{oEX6utS}a9l$mA|WT1cs#v|=gRXE#DVd1TD+D&+xJ6>#Ev zgT(Raz~LN{@_ZT68FsfpoIT}ol^@-vc6opVfS*$wbm0@7f)J4;uy&r(@I=U*Y2BeD zy8!~Py;J=jO>zo=XV-xid)7V_-70_mvRq4FKs-&|Vf8tWyHMkDA+}lyWZ`i>w zi?)@-u4Q~xPw-F@13qWCa7guwyW(IzO{t}FKR(v)K{EQpG_a1 zR@+gqA_t*5b&Ctp8;Co(QuimHO?faU-pmxb$Av(^BjRTH%;zEv(C;WmGWUDPrRb>W z^8G!pF24&9`Pei52^&I12J5$@S14XD%A(Xu&$$pib++o3H(T+l(1B%1L5dUA#C_1{PvNs2oLw-R_+%4@+#Kx8rrjAH}&4DlnLFzN;EzzRK4bMZLKU4=RYj z=Fc^5VfT`QnEEy5Ley06@_F>{8idG8B_wzn-O*y#|PUF>|^l7owp84tBg= zz||kzD*mC4?Ov@77ea-IG9R`rPI(g|cHkRhxeP6JjaB!Wdv_EK%1*SHiCl<*3IX}( z)901>U{<*V%U_Sx;9bylzvxv*k zP@9!%qwY4z3k7)!ATjJ*_7!Xhac-~;+1M8Xwm&H2SdPA{xCkwE$!~7|YfCpMM|NrH zZNHlf0o@oOcOI4SbP;yoG15@HxsOXRQi{RuUmHw54MjnDxVVcbdx#5x>m?!??2OeN z%AuN1mRNQ;%B83%frn9-BN#7Y<;8dY2{wcZe-b;}wg~6PM5$4(pXNezlm>nNN>#TN zx#5lh+zaAh3^>n)7^z@wV++0ivoDmy1T8N@LT+;*dMd=3&13sC%o`*}Rr0*gg&3)s z{@S{cx0REzkAK94=qLg2_dyHmD6hWfo^m02>RwU%e8D_r!QkT;T!?`>o{X>I`$5@N z;P!?KQB&fy_Y*u{_`-4Vo~zWm-g6;ZO1VAiec{*WT9IeSyczQ`kBoZCvyxEcqmS|< z*(O=I5Ce6>Zo4Ua*ckAuPOsotUDL92Ax7%?->!fUb5NBiXCNF|iVM-|h+}D%M{h2C z2gn|2f;?N64WW{Y+fKSaQ4Z*DaN|PsRLri#bsrlYhF7>o@NkOTuK3Da2o=CK&X_ri z1t#If(j>glo6FFsi7V?qzwP*fjwo5fnb3p_F;ecE46_=aQErmW&AAXArK=s0{bfnq zZp%mCcdfV(6_r~&L(|B5SY7hzq>euuLOlu?^y|-s@FkGEF#gh(3(-;Ws;{(oSN$bG z)=6XWKnE_wNQIVtwE9IyWq)nSE?kJ7dMf$bzFF@Pf*~NqZE8$+E(DzD#7m88F>b|i zBO$BC_6Kt*YU<^3Oqqu7aR+%vYLr}IT!_|#P}xng-hKEMN+Nq!2AR1Kje)4H2D$z` ziy_BkfzqW&F2sZKqMMr?^TsWaJbC4c;X;g*L!#c%{t38|kbMQ-v0R9X5{ka4d13f= z$aM1tB5H~2$-sCngj%yI%|AF1_0;m*HRlg5LrbkEO-Eikt1J+{F@+0JQIA0i96wW_ zJlqG@0r7=cTP0_3A=K7xLG}hiE5nYfAh-v`BhZ3{T!xN%aI(X_W-w}O@VZ}gdel7R z0Fl*Qs7p#)`ZO?b#oYivgaJYns$@H?h=|u`WQq89uxi*gX$_qA+dU z5kls!K-O3dnz(WU0io~pSoGm8K25~t}k?n&bNy+WDW(8km0?XB4brCg*@oxyrL!t8Aon9o40{KLDeQAn{W2FKj3;$G zO8C}#_xj+rAo}_PayeB>We&0)7j-a*Dm|DYQ_Ja;KQhE}<@eW6vFo8?#W^`sSp}OY zrW2xg$_b5~XEN^G@_pb}=+c+r09H{bLs)qSo?UX66k!u{B%5u0m5Z>T=N}7?Ks|SY zsu5L&n<^@qw0GX*kjs8SWg`IKD zxND#C6SBX%av?g(8E-cA$%c>N%0NF6tLs(|E<{TuzI_+d>2yu#FRegWCA!TTYEsVI8}b0HA!fKX6Rtv$M^@)PTt!?+X!bsv7R zQ6}}~uuSNeE&4s9_ceV*#{z27>cSh=vmx#p z;_kIx)Rgt8tCNe8?;kEjOKEw&-d!DzU08ku&|)hWqM}}Ad>`W^N_WON&VjsHnN?Mse5S%2$@X4sszLRQ~35 z%XUX7-|((D%!L@JtaV$SuWNuMk>9aAJjR6>sX(Glo~nMryhU=GR6WIosHwQVK_i>z z!MkcX22|u(E<{CTxL>}0k`=S4w1MrH*oD_#;6gNNVp>Ve_4E!-D{^(^Pvk<>)S`8D zh2QPwcxHlI0CB(4`Z^cl;X%!id+KlL8U`EUTTox3OUvaRmqJaD55HtNjB}SPoj?4D z%TQ6f;e~?_m6{ELp}G|u8$QP~E<{5qP%WDi>MQHCb7pd7p0+%w>Y8vO*OX^aUF)S; zxN%l4L`%JyXlpDQhI5x3(`aT6E<~dzw%mvQI(Y>5UGgpR#oSzo2c_Q2n#1)XI)&sH zOa*@8LJU-!?7H}0opLa($j6|V0$hle3h|j(zx-8S7>A{$W8=HRTnLPK;`wFgdM!$) z?6}2wWkG2+#a%@l9uDgAmBf2@Iqci@a%>8vbG9`QJJ8_clIkMx4+W?VQt!N_`qN84wW$84_6?HbU zm}gU6F2qQU#cbnhw?zN`QK?N{G+;w0k>JM+wx*?^;U7s5e=jaXOKHxHU*gC2gTWpN zIv8OVtAsT9T*ZQwH)(z0R_DPP9pE`3PI_eY@S}NN? zRBFplS*mvDLiCgz{6gz2>o6iy0*n)J`5ha~g+SbM!UO$NUBapuTSNNtIUfr)u{dfjPn3c+2aoCdncQAM-K@+_1KBxhN5Llulu zS=0D!Cli|kqy>DxC<~f+OcCPwqet=lqBkJ9VN-p4 za_zK^v6&%nsnbfT`s~gy)Xd3o0}GT?0$0ZXZZ))tD8QLh zN)eY@vf110JWG1!>A~SBpOiCm_bQX7aiPwfmZ9RP(;u1u#t3EbPSvYiT$-0t#3)o5 zWS50Zn30%P)*h+bKm&d_!j-tjU zRUA-1q?7*_bJzok60yWu)GoOU^HUasl}e2LRz>e%IYlayENb+MiE*y`I<`F&_8+)5VB9)ED^r%p622}VF z_^T{b{FD#}<0-kt1ECe6)5M!$=b>!$b1uIpPoUS^U_gnozM-KCMg#gn2*oI0OSBED z!3t3Xm91VbJ?d8@oFR%AckCnkBNVLS2Ifb!!^Rk+5l57=?E^c$J;Yb)&0+H;_P3Q9NtICcJdVIMz~DT0(`0cC$`vf2;d<| zxroSzjV+SIuVF}8(~R;iE^8M%j*$%g(rvV{MM>B@qGyPla|l)IZ=QZ$s8J+RKZlc+M2ebXcU<3jWr!U0}m(m&;u^9%r}^gOTXNTjn)M8!8>;CSBUJ;xj#ewoZkqd#;c|`Z>JMzIG)SSqE;)t#Ia zjn`4KOLypPF2q1-PX1Xrbr~M}Y0j+ZCi4!o?Y;I}UTK<9y(Nb!1mrao+I{@To31WD|h3KiL_-$TPZlWwb zc>A6Wq2~I&{?Yb4TJnCy|1%e&qjd4@Cv`5c1RB1nH00-g<3b<_5fOLgzx%E?PXk51 zk6M|bfVjg=dw)mmikcQ&>OT{7xHaKzxj1{>&di3mQ}K+lhzgas5G|z#+1q#8El7jxvZAPCeeJEvg+S92d(|-?a+brUpCoOI4(PZP z6*aR|eEz%{?z(01{Z}I!LS28{$v4ddw?!+Yl6ckQLbOy;u!_BcFQV#1UQ#ABoX~2bvi4rpmqzpn|=( z^tp1o6D%j?BthoZmRtzPvxsd`)*I_GqQp=Z=JgBYQZ$sPc>2rd{|*Ak7dX0$bL2nm zxe#~;MWjldQ?})SPvF-{09mGZKAqi(OVLn~&lVK8aS11uu~O524&y?!)B`xL%@6OO zW=@vrsCsfCDk@g?g@)ma2f}RMMcT4NM{yx~O5*RItKuSMNoJegT!@N_9yDs^*X50% zB*md5V)q(j<3b>YDskYNIjKbv94WFgUX#G3s3~RMeQkjWSYPtG)%zDNL`5YV{KMyn zJq5EYmRvcI3o%d=%PAMlNvtk;^Yv^n7ow$}M7SheYN)K1{COA`qM_anjn5xmE*r$D zxKq|~UWpvZh3Kf`>8c*NS}8A%7iX~{)XA|#k@yw3i?137`DfExJ49uSKw7HLq~0j&KBt3uM)fq-vpV$ zL`cMKF2v|gEL#44mG=Y}c5(Tql4EVXe$0hX&(E9ZoLB-y#qt(%OU8oCW44BRo)q)c zw?{G9+;xYESgftrS-21#CG>9IPaBE>dgXn6Z&xnFKzWA;Z9cNkzcJin&2tR=u%n;@ z#8IE6JhuPHaCZl4Tn@vRi!(@%F3JW|>4H*AL7YllqB@>GsVq2Y&@D|$(2wX@KG8O7 zU#Fz;2Rgo-=j!6}1V*`d(O0pDBFP>}ElH%MTtoRQe5``XDOm+n#Hwg9wOA(o=|XqB zT6Y44Q?iKVL#!f3LBwKF6z0yi1`p3s%!55+No4}Q{D6;6**Mamy zofBY+3W~OwL!77mT$W+_*7N0I`tWr$J#n;yX$N^usu&f8m4TZ7y?TcD)5!yUh-?6k$y|qjOO)##+_+xDE&UZrB0A6rAdJc^g4&2hnt3 zLLq!iWivcofiEfGZMTEL+`AkMCW&HxtQN{GFmP0%cU0 zJIiAyXWay4?g5`EDveqtDp|x(Uw)BsvG!?|4EQynNb%o_Lfc`gQt>-GU8k%%w}_1a zpK1Sz-?{IWlEoh(#8Rd-zb1Z?YG?Bw{V)Al*2SgwSVv`8$=eL8P5hK}I~g8Ze;Nzl zj47JRCx3dL&Zl{;>x*0a0f z0bG8`U$e3UCCwWt6?N@Zs+3Fa@t_kmfmTu6Do0o2LX6b4M8`G%45$W!WhxxN#rg_1 zav^YOPaIo2&$(P4y{&RUl~)be6bf>tOr3N1yi-;NRQ2LQG}NxYvPWnJWk+a~FBhVs zUfCZy{#$X3NGxkYmNw-=v{ag>y0_-`s|IIQD;z7u1Ne;=TnKdued(~Oqw+Y3?!;wy zP_LK9HW;%1PpB=FPKjN3RaZ8|o$@6_PtvSVj&-uO2bZFw0yWvx9am#`1zE}XCWH&| zph_~K!QRZ+D6(Tu70!idsWc`>L+8)$4D(7CnBm3A%i5C*(NK=6VgCibLf^FPWmom) zLOdu<=KJ!UXQ6^d&Zld!aUm+o0bZ`_k%ob=!$4oCSX~?Xa3Ol?LHF%Yk46^(@)jWC z=_cwIHbi-0eDH2;#+6W6ve0blAU1-^vAA(aP&}u(`s%2- ze|68kDBKPFh81A5D^8E=N3bEpP3PT-lY0FJwG}JPTyYb*40zN_P-6Csu8tje8c@XQ zS~!_ap&mhB96jU&9ya8e>)|vmL`x|TdY5ypuPpSgHH!;TQI6@_i_TWG!MeB?)`LR8ef$IfHZ3ZU0mZuk@H zxDXF2n##6eFE$vWt79judj+i`2cz)a$E6r3Uw&A(6=(l} zqF{yuaUTBjAQwVObV?s>asda5ESuVVgv(G-SDmi;@7>1ZiF{`KaGVR#QI8eIWuO0- z^7>o%G#8?$md5KbwHKX$k_?9hMQoCm=eQ7RsxR_2&ko#f%Q+T*y~t&#sQ?az%jO>Y z93Z=-m2oe)rFa_&y^aVLP~R(y4+c7sC7(sEb0Hp-_Wt+x#)Y^t%IitDTU>~q(l+eh zQezLg!QM*Sm3eo$5DyRPlays`x6!xDYkT--=-7Hx#a7e{2Frd$Z< z@(6v_ocq&VasMUzR5P{WQnb_pnQwagZs_imJ&`_bxDXZfuE#x_`a8}oa!G~+av>Tj zEPdxw6EZvm$TDeTw7oqSqNetE_YRlv{05M15+rA5E<{WDSPu2-YbypKf<*WelP*Se zbATkNz!bDXArV2*(Wb~W#X{pN4DFTx92_&EdgoPlMOJG0lS8&e=TV8q4~eK}0n$bw ziD7Ea2Bk^DOr_4vck6oc(m*gTE8P}^q-ox+bW2Zwpi`Qmg_;6I4nj8Eq)hn{ge*2L z7>nUl-}Y@;&uKNl{#W=Do4!`KqJ4#?x7g!&wF`=jbI$72I&d<^Rk{U#4Ta11LlNm^ zrC%oY(OfeMJGCr;^Xr*j8dhIYlpm*+7}R&s0My#ai9OHuN-v7lwKH$7{`n!)Am;fM zqvr%gDFXdXv3;XM0xdq#p{>JEBV|{1C|`egPCc{K3WoQ=xDn4{OQIExryik6dMhM2 zt+CDDUjOt8E+#IPbQDAlh;d+~Qr7j23bsH@vdBnN2pRO|Xv4>)v%oT0CZD6_|N1#t zPEnyG$GvJ66d#ln_)586mKYZ#EP?nLl{z^F)T=U-u$(FZDTGq9S@F{e&BwPgXNqDD z&pEKni^+m({6$z#R_&ok)87B+;8W zI@FY)Twz{Si#|{Rsx6?z0E$hQqyyz|vf1YpQYv_2TDiSg6dl-aAj~IMmZrnLRFvc; zOt~v5 z%@|(SZ}cCV1@>n>K_*a9_)62i4o2lTTgnB`-Di*G3>5qj6kNRJ-mzcFWb&#EIyI9O zVmHEnVw>TdLq?~&ee{((UPWzzYeF$)=j($?2viv+WBe_a^d%OpBGktDV@h^qRUiZ) zlvIJ)3TL0^S>DCP72>*yD_+gx>9-1&l~jR#-eIf#VKsUKk98q>LaN`<7Y@dMq`y>d zxTiDw{5}t+iJP$eh?`FHCkInO3er7Gv^O*!y}Eg18t9F2Jx@db6^C;~#-gGJK*@Z( zeID{eFo+M`JOct+dnuQrzJCKxJvd{dK>jYe8ggcF0HrBU(7O|X5q^4-C-Ec9r{=Pb zkj4495F@1&+U=2h&srEpr=)Ad%oVs02yjh!O%?`JdeIS77B3*BtXN+qDsw4D$}u-? z`|Bg9PmnK2F6p@t6%~DYlUu~^=rxf8MwO|lIX7_Qfa)m$qr`@P?9GK3sh8`%Ir5k=qK_B!VG*Kk!iDIm%wAot zPG5r;$f%7LAupP9Au1|lL7%?^E@1|Xe?i_XE^O|txe&q;Kjz@3X&6v%36w)TzkKh+ zMNkg8Ew&3e>w@V2awW&Q3hc&aP>+|F9Nb?;S>yONmJ2ab4<`M$ZybVyL>`ISK3s^J zQl)$;{_fB#Sh7}0{>%7&TnGrXiSUCNww-u^u0>fRc6<<*qN3h@X1elv%4`^h{hx!O5If7=c-?|8hhb3USSuZ;aUmX*7)d>OW-jGB z*C{i(5Cb&@Z!0%->;mY$pQI^x#h+XVu^Y;>Xj0rMs4O|&#+qeZgr2%~^V-t*U`m<{ zalN{?k_+*mDyyx}qiuNMx>V|0W!7*ZYD)a?IV|GhN0=T1;S3^P@0izfArLc$=)v31 z2fAUS$PpwCZRS$6RD6;;g?9d&TX8IY+s1}ayT@6VJ>xDyeXWJ%L~MD>E-nNvsFf$- z7T?;B!T|curIug0j|(wSaeQ1$)y{>_rng9tDu=ib9kpbc{mXSO4<-2~K?WS*LbOzT zlHi6{?kLCp&3u9j(Wr?V${r=JSHrUjYAnRXx5#NOgqnljpA34A8zNbk(D59bL1|mZ z=2*BFR})!qJo6$KqSg?{>vs{w?qM_+SzL4e3KwF~5yJeQ{d+G_Ua~4(=R)+1xC7AzpO52L>pmXId?AV1bcyl4pg^5O~ac}9|GvKQ& z3ch}E?o#`6DOBo4lk1^OI6um2(4HY&hJkvST(QW7Z!ZBNE07k4aUp8zp<<zL>cXJ>?+k^xMZ7m!TxGitb@F7owroto1>`Pd1cyamg-4YpY`ALa2Lyy)S3I zdIANJQ-(C0!ewZv=W4q~JwA;J4SXacCia;)-2sxM*GjF>NFzy|@1iqD|CKkoM{{ zAxUbiw4-+Q8y>v*SAd`lw_&O)Pta;;6(M%XkYm)Y;OMZF|GQJckKyW-`@3OgzYlq? zeimqD^$s)#SNXe*F1DPobrt*IH9x1elhsvZyq=*SY97iC{Z9+qRZ+XOxsy}F zEn0XaB|!~}Od3Vz=x|URMiM!~G~3>k>J9tVyWqVQr4?1WJLN!3IzOw4NX6H=^xKZ8 zUd$zRnCGERt=c6*|BoF;M-A&aHE)HnV0*A>lQq^2LQXoJ z9Tz`YmUk|E{7aZ;DhMAxH`)Q>pmQP)wdYG{YOV!CZ{V-0U~s(E!C;ak38QcZS}c(% zIUJQM<8|*2r+b6Bq3|bG^0Zhbv#1$DAyTr^nT$=Av*yIPQ=ozuOY>|Gn=`vGjgU66 z)L_#76RV(UA0?Zz4haRJk`U?ZIn4gn#bExmq9cLp_{;?xjhtj--EFnC@WEiDD=cqC$pQlsmPkh~2YS8^d9?na`myQrEzpACoFPT(^U54KUOxfCjP*!kNJ zb9{x89G0pp>KK=ybtg{f8)kYfQ+`Ez;v^eFg)iA#cy{gvFe+-pq$4(b=CfRgfy%gf zYe0*tc$JT06wxWS^a2+G0o94Ss&93cAH{vD9Q)z@WiCZU1+iGScV8!r0kBAFdCfI0 zL``|&4{y4;9UW$PF(TI2FE_amQ0oy&kzQ2_^u~!renz|f4ws^)UTIG%e|75$fV7c{ z@(oTwyub_)C55=;8S&}HpErP_;9-2srchx&u5WK|MUk8A{0n@>h3Kd`@?1mTNqD&@ z--*qB$%UvWzg(ZT%?34uLEk_c^w-~TA$n?#w3SQnQ67%Jec(boC_&2m9abYQDf0XL z-JiJ-1Lc?V_0`|9LRFz;Pn;vqe&a%Pl$h?w-x2fCe=SSUR%9u`94I;}FHiqQqpK~0 zQdEXridd4D*|`us^{n~T$WsgVL+`2whY)f0`d*L=fgw-ag0CIia13fv7E2RxwPIX~ zhI)89ZNc@9sN9mD(Ar9JAx0`jXorq-j^XMk-%zhC!-W_q-Ak{}(NlIpgVcbB4&tup zQ+X~#L+rd7=MUI`{%cukT=HiwL+wGV^6t3`dLl%gAUoIOLUbAe(&WnL`jOCu+es7T zOb<4My14lL`px5iRdR88=jGTWy|i42ktj&ml18Tw!3cQ^9v`vUtzEbbN?~p?#77Q> z$_ke%Yfdnip`}Cvv;W@m5I4g^pfF-VehcG5D4E;Fp7)NTmQEh+o6TH?N=*bW(dM~( zM|nf^GLj2{D_7#EwbS-*OI+Pw!jV**=rhJ}DMm{5(qmb^+)n^f99-IBn=Fp!LzK_e zN2b<#R0}#6Mz$6glXnBS3<&x_R9DYICEHI2XW}exN6P5IY>K;%cz4(6lV(wGQ0sX~ zkxND`=TbD(j;O}Y<0o+gDeqFdujfM4R95Xv(+X_C*ah-PS+I!<@u0#YEx5DK6*Xw` z?eWzuT!?{clf@0@PdN?{Ieb{@9b5=>FJfg}aD8}(AaMNdlCF>a|K(Ej)XLZ@L_6UV z6h-#o6y48;P}{EkYbsiB`9=M#IOh8t;zFp0J_|e9JkJ3`?p+&?a2ZBw^{ur_+Yz-1 zvbW&*aW2Gz66ODOQ9l5KNXf^OpHFik2Fg!#vy#UsJeQ((MV#xs&v7AoN)UQ}$AZLT z0FmRij=9K%cu>ca4li=%`2rBR2k*SXg&3(^n~6E%eNd~}5vogEQOaEBLcj}2D67Vd zo;3sWB*=YOcZ*G-_7W?WKih;yY}xG*b(afKQ=t!E@ALnPk?iGZc=-b^L`CV$-L5`A zcn=`*v%3e6xey(-QFR|S?iv`LR#TD=tJwo#qBCa*f*r zyRL4KP(ba%#*OqYb3$`RehHeU%~$l;C*8byYz+j2`Ms!6{=-f@814UHkHb9ZVLQK>ah_Q+Rw zC+xH|`{!-FPyi4I;ZI!Hr|K0E3Z+4{l~YL7@vk1wf&*3<^jh&YJFn3h1g@MtLxW<- z5JVq4`>n#JKmnQoy3T~8Nia1tOL_-J2k7!NU#%aWA`ZO$}(|5QrUIqoIEZiKIYUW@!MHFTi zR`~{Dgp9t*gDu-1cYXhb8TA-Adqo9N@8*QjBX zxwn8S=mk}66h3rTm{X&6c~#OVvWM|OX$~#2^8esz8VZkV0{S#DBbD@5?>`@}j27Z}mRDjC60PqR| zcyAN|P7VS^c!tYADtQCLc$EdUir6vrF%Aap;;7`c#V-gx)|x8Bl5!_n8FKe!CivV@ zupbiTk-3H{Sx*&L2^JO~tJPv{1p`3YxHgaZ!%nD&@6ZV1xa~De$@mXZQs~EoD{u2u@c9e5Q$|Q~ArhpKuIR^4lHqQWgw+p&t&z{}o z#;CA>M{QcpY6U_6+#?*r&pqKA|G`lz$J(w1kHkYgsbR7fNAse^C0$zj1bWtJ+RC?9 zR8YJrx)xl=*RwHsuzrF{H~$d@vxpFlKFbFqo#s$v_E%>i!fvRoQ9zWE&S^q(msEFJ&!`XH0w& zC~ie6@8UwV)N8#1v88un+79^fL_P`LG3)wEP8SYfLhvhFa?9UD*xgZUc;+MG; z0~OP`Pu=XTF^qc`sVF0^av_i$gjh0WkMHdk`+>u zlzGl(P%42hnF_j~<6Rce-FVG~=&103&%JEL@rj#!g;3=^7ow*kaKz4S)*&UIq&Te@ zKXDp6LEU|Wg2QDY`r1`OOb}mFkZHY=w3aj=2Ao8Q>s9ao#k#bo+aBb;GW)JAYMI={NZ~_-XT^74cD{N5K7r+07%g|C;qpS7HH4g8JWm&GzATC5j z?dmI!i0IfHe3rA|>7jVg8Z(3o@u1qh>-h!IxF?c@<#nfUAu4JtuAP4^J5G@D(P7kd zHiXLV8ow^O9tN9zBAn^@e#^9E_zlav`v-S9T1y_ZfNfKcYA2rK zG19QOW`*qHLST(2&JMfl)qe32C`Y80U%7`%(NJ$mo_y`t0_#hjymB7kLe$i}GV^%7 ztQH9IzW^>q#Fh{Ej|(xn6O!2~%_n5P4<(U>E|u?cAqL9dRc>T#Yuwh$t5)m-E<{cB z;f~hQWl+Z~J3jt-%!OzuPp4a}=ksy>#VA-}AO7%+3js$bp_Biw<&J19iafD2e8r`x zs0Db$?u=cZ!Xdj3WZe)qcZ1(@AyjO=_tnpM=74?IRcSDu{?27+sgSb+Tiu*I6d(!G z0i|K4(oAO*Dbnjw=0G>)7m!u5aUlj3amJ45bF(kLgTvQ1V(+SxlM8`IE5wkmdF z^?_Sev43gYxDZ(9iB~?s!#bWrVW2EVi>~ZIk>k?Et8I`cEjrBvqTgOk8iiRTWp!PX zs)`T=X&}VoF4t$LYr-9oD2=FFQxSuqf$S)|{!V$rI`hvB zgUi9Ue}caz$@-C`e+=9pSi((i^gyrq)Nrj5|t;IiiFgg~h*hEQQ4x^%d&mRd`Q#VMOP5-h*`PW4Nat!{& zrXN>Z5u{LkNvct&JuLLW-p~cFqa}ttKD8VL$%o-jq%`$Z zq$rdLYtQ+({9N$HGz|PG3&r;|Qlz9Vi+%b`yCjAwciog3v%S+~U=h-h5O-ePO${GH zIhMc{u(U80#QQohaAt8!3WBFRt&CQO?l=I7u?OCcYP}Ur9Blm%AKMc*Lex8ubeTiE zB1|E@2qCQ2wabzW&~pOeMo1iWCrl33Q`Buqirds8Rr`e1(h_SU)vA`A!#w?O$!y;jk)*bzLCV zxm66>>1(DEwXV4Tu5~G>>l|QPeD;tx-l<)?kT-cMb1vf5c6nF2Gnl^)y;1!1aedN8 z(AwRzmsdAD51$?im0eM&XwQBQc2l&w$r4%vrOK_^v;Q*{n5z$+0!C)4U(f!8Nk14N zNwQFgjR=}weCNyl%KmaKseCnU8}DE{ZCNX& zJ2VwJun|u+@;%j-Ke!ORhB%)+I_S3medF@|_p2#fh=w{jt-aQ9WJ=gGaUQQZg9}kn z7nFzZEi9!RA0c`+7edA(>odwlgW?@IedyY`T!`9(=(#_aYI+GDGRw-a_Y1fX1LebN zcKP6fHHwfti`fuL3+nZ*TrYGh$`X$9%eW9V^*l4dwT&x|6Zv6o$Vx6mN974{ieJ#}G1dfwQFlCA3FL`ymO19rbXsO;*kvWW{(Q}_5i%3j!m zmxp+E6-#2?!i9KHDPf|rmuY}^B64K4zqWHB8tS@Y-f1lV?gGQNiER>dfD6%40Z~e8yq}^&S-ulFd6*0Fpx$Dv zdVYEl21MB_^{(v4*$~P#QewvWpPxf@m5{0{{1g|Wqhul>s_jI!f^p zKA=Z!<*B~k3ogWiN`71_@Wl;`jv(JpZg|awXsC<)TNU>d!_A%iX6f5IE<{aTP!@UD zeHh+M%K{SzN`2uO=S1!arsanld-K%03md_^-UCJApWv9XaUljO_VbHM19QFth^%|~CnpzTq$Gj)-<7GX ze00d0mkTjaqSp3t4MK7G#hXKMBjM)Ch3Kd=V`A&)H}O%Y-0(vSav?^lOMT|!i5;9P@RMO8JeDlO~g4+>xs_wJSDgg4|0aQHe<{SJO$xSLZmdUz^1rU!}0Tq z0@L0BMV?rOR^n3h)D+pVVxKLsAVZob$&jv9KBfDaK$;!h`K3s^A@~#~4 zo?i7ua{m$=<#`h>1Vq!s1J#Oc@`U7tt=C0qJo>cYQgqbwg0DW0j?~5Nu(ZG1+?op^ z!*#lQjOeYr9qt&wg{Y_}A5XJ~=P3rIm;`DRar&CwjtkLHZ=>A3W4Gb0%U>|?MXgiu zu3QM^E~waPP{mcyBwM5=IUU4hXesZCp~-J6lpP;;OA@g z=f}j6TnH%%%scUy>3G(X?;Vbg_=2J_Y zjKc%4{Jfyq8ZJdeMN{mu%Rd%nQwm|y*K;A1TkY}7`wwu-Eg$GMZsIcZ)Rz0dQT|VH zFv|O`7hAXxBQ+RH&k7l#yt%8jgA376GyRf&o*(wY+&D{mGaT_R7eYm#xO4vNoNBPd z=Yb_&?7`y?vl;GGV36N)9UOZJC|{+GM497Uik9kKy=Ru|q1+~2PjewgYGM4G<5<*R z5WJ{<1;@E->Nz%q@_4ycHny6P4^EAc?Nyv0=RD#`t(4pB~xA3mU-iDEf9Zs)&W6^$zh z%j`NsyROkG>iH4(Q8qxy@?4+qim24;GQ09C(uVpKr;xG<2U?E-2=0i*;FqN{lofqm zNv)!!$BZ@E(j)!b;`i4s41S40hsC_Bg)=F#QWwZxX(+WwyW*xl%X=3CdZL7;uAsa4 zm|2lSwUK99z2RBg6Bn_GWC7s7tcoO|M3#`C$g~B3`Tvg1jtPk69@j3rB154x>C_s2 z&1`Of4TNi^SaFwgD58Yopd2e%INd5J%DGZ|^TdZ8G5p~-AbAT-v@4ebDMiPZ9QD($ zuPwq7txgL2>6Y}r0w5YxN38D=`cBXPbi#+P`HZu31V{MYln=+%Icu%Q{EJC1M@1V zKXH=CT+pfcWZ7bbITlB5st}~zLu?7ktTq3bckM+MY}iFV!{kEgU_nOdR+i`%IJD@@ z(x(djd07vPW>6lny0#T@%J70P!f{qpD^r5aiB9tQMenE8;hb3tt|vvIR-0l@%?Fx5 zac6?ut&!$vBBJDD*KKzO!KdSsFj2F1skBqusbbo;4(@3RA>tdhe;ClG9enpsaLN$p z=*?xF+D~2pe66P5ai-`Hvne(?HnMUv7hZXwu?JNDC@6;*|1`e30|zCJ%~0nFVOuQ_ z(i1XFhncNWtwGGz$7;3_71ej#)g@Emz_%0vFH{wVMD|(^0K5E9lJqHm_vu?>%5H$~ z?g2Z?DuUU!dL^?cLJWYZ%f4!nO2h&?&mYAE^9P~Ry9rjm*QTuc2StaQNQ*OXl>N2` zzB2>3>naKsJ?l{xla$M($v6E6f6D_VPs2x+7fiNmNSSP9v61%T`+8Ph4xiVcg5xM$ z-$=>c5BX)vlHe5+QwuwWqWZFMqv<8KLY?9{pq%iz+nXtwPf=eIPyU*Z3C-~c%uNMz zH3W0}TR52ezxon3mdWv>-I~C2B1);8!KLxmEKsRhs0?xYowK!r=`_WcIx29Qc4CRk z^`X-q1t+mMui65*5GoMo+oer9;!#+385QotWvHl-0UPGTT*Dii?J&cNwbiyO7hx~2yg0+}I+N6J6t^?Ij%?DTgmUBSCaML0ss27{!PH8-^^=}rR9|*t7Hysu(MNg?F_E%VZ@=PTc zm#&_UBc(t*7eeL3Sw4T3J#?Df^3DEaGpG;?O=`Io$7m6<7Hh;jE<{CzPV@G8R1O{9 zvfuN>UtEZqifv^~)EB_(0XdFgo+Vs}j%xRQL5bV3x@0M|_i`>oO^Lca7rXUAVWg~J z8uK?7qM}k@{hLs0&k@-B_(EI)aWEcR!-c?zCvKmzogDiKPl~d}^V=3Sg_)~OSYPtQQuh)UqNAc){V{XC7e1W1A#GR&Byu4}J#mFPuIsQ%zK300wi+@yWQ_2? znKndu_g?buA3g9+OAgZWWJNjA+m+@{OGS-~V>yrij=LaPZt1?73(;tZCl$wQMFpTP z3hy(;E^ArGg+RP$LTKCUicy7kzbGISH;uzLaw(M9qjcMPzwUw)X9nRhO5kZ!g&p>IurkcM&5|93#gxs{57;QBgruazs>^`UxN# zq*-^+2QEZU?S4;pIJpj$qw>RzYoECgwT^gG(fZ&4FT9qOcUr~2b0Hc^3Kxvzx<_X;ey;+UVFg-bC~`?=c1yw4}XE+{YDY>AVXsstB8 zEmDuBjJ<_wUb#)IZd`^3b#&hq{&cl+;G}hxxez@SmaBTf?q{_yd6k37OKg(;)wmD? z^*W^7`{ipdRBRGAv$U^7dAN8q*&PgoP*q!Vs(Ae zupv~Noay*(qq6wt0XFW zu_=@uuJ(ajO_g_E-F*2FqIO}P*wwY{spIqqBybf-v-a~2x#_-o$*vQ1j$3%2J%wA9*o za_{Rh==+y9kqMo+5Iwb`+-=Yy3j46U^P1R|3o%d!xDrRY4XF&>>zh!cj)61=V4tm7XmRD2|w+5pP1a}w2=>|y?b*h8Z9wJmJ0sxsSgriaRaSix|3sF-W)v`r~wo@+2_JLf8jylSh z`A}yP4is4nnQ;ggqNTF5oWAmQ{yzZmlKQZ57#9MvcS4_f##Cq@K9iSQzTHSJMMq8c zrAptej^1DyGIul=qM_7~R||cpfUiJh5B>ddT!@~!1~^u}-L!#l4(gfL@f_sw2Ny!k z^(N0-c`@54Ue1V?=Bc4^e+5)rn2wi(m7F)pdhC+C4`t_FyLWht0gYRDQ;M|m){2i zO4d9+xT=T~By~Z-rbtt0dbE{^EwrDD0!P+7p1Q8cQ7D#OC75PF*O?LVCzOM%2HZ?9 zDaNi6iUcK3tj!u1;=IM;fA2kdTQe7z##)?X zvly~Z$u-_PUX0x6wS{X9E4MI;N#=#YOCy*qWe4If_#?xw1x zvg_hP7kisyV=%U2OA}~ULzOGOQ08X; z;-%eta43nwyWycu8Io|#H!j*9ja8Xbxkl}~ZJ-?Up@HiPbu_Z4Q;t0>B8*sDiukdy z$p(6SI*Q@ry`}#>4W#j~Vv8zEuSf@yLlnb6tI32(wcA^RVjyX~azWPr)@;*G7+E0= z9hWy-w1auO!0-PPUUD2^KXZ(U)>*!HeD^z3$?^}?o|Mu&K33%pPf}uS;f`s$t8M+`O$Hdm^8r#x=%i=o zIERFqVn7D2WOM1Bk)~gvIs&1_-2|Ie|5CDPUqzg@p;^~x`2)DQ%u>v;2Yz0rWU*14 zIWpAS{(+#7?fd_zn#xURTamZIM39(1?BUpio|_!3|6g#Jv=RCtJ5;uOvR<~K7#&3R z!dJiUU^&fOa03;p=fdm}w@`>6J7xyn;zB&Ah>~}jElR}mW@G8Rx$7<);!d5?^4!d2 z!lR%Z;U@6`m!hTuom4uvbu4-sT=q-~Y3-*1-g=naEagjx)nek36pHyAzKXM^jJ>il2 zHm`hDWgkGxuUv>;OQdbQ9dW5G?k-lto>4rXPlL(OVhyhap|>Ngwc<6k(j4+|J|`$+ zt|XSl>pi?Y7Q5H9tXztU3MRU@^J;IruafUy?&aV@j8y!>DejMb(c>%kVYfV7h@QIS zdAd2lpnMw|@e>zfpnS38o|YPb*HyCb`kw+^h=z)+khRjn1L$UuZ${o1=0Xg5;v%WF zf1PI-{7rV6g~j_EnwGC6r5$^K=CWZg}@9+T)eridvoe76lIk(P%>8J zQZy>UO&XSch~3pMufScZa3KatjjwrjteUbmVcO4Jh@MJ&S9w60T!)~lGQjL5&MV7n zav@skhC0KGp8sTk$zHy$x}f1g3{=CnJ-2lh#(R_ni1iFyh=#gxJ#c#Tx_eNPjM5f; zNF6RjOHE$CpX;$5XGr<2$FT-nh>8+GJUa1q8g3=z$;;J?3sF-7h!*{e>=_2pxt73V zadF7|`*IgN1NQou+t0x;miQQhl35~%!F}dacwQ?aU>XlFCD;52e_uN_IxeyO3TAt7B z-WhR~pD)ezK7H8`>h!Rpyx&2LQY=4^nB1QW(NPg`C&f;yi+gT)@;W+*3sF(A^4?6j z)b{F%mm& z{p!0*QFtm}=ieR2WoW3*<=dj!4ctP?m*D08;6gm86UwTpo{MlS%G>&&DO`w=S{ZBI z=n#VUZt_Wf-gGWRM{Oa;Hk{uFhlzZWzdwr$QR|3{vc*Mje?u)&BbZghMXTIgE(C7c z2?A8*=si(rrFLjN^0WYs7Rqt{kMoNiv-e*;=deHEBrG_^@;6gOid$Izxit2HV zM^~pftK@pZg+N|gV!$7o*KIFSXE^le>O~e z2#^(W_j=2PXsOLzld3~2;>svjSD}wwh{2sWGnNT+$*b&K3H-u_P@<~wANF;`+YNc9 z5C6`FPz^sNtn{xKD-Wwn?8B=wR^+*NchZr%ctu%XW%EyK1sN?U@ zuC=qihmvfUM&qyoT!@}pfQPJ^SmaND$h+a2g}D$9cdEWzt40K%^G+V~cZzW-dMebx z>+MB)WpQ1&c0)b!a=xj$B{Q%@iT2R9Z=STiXXk_DW7DPY4ax`C7cOMPxBB0)gSs>RnUgW+RZR_TO zyJkH^pAZG-O*%Q)PZ833o5F(PB5kPxDkcYcQ!c@TG2Lh9fQ!rFAe0xw5jPDc2q{wC z)S*t5jgQ$8Klwg9q%Q>?lya%69F!iBgmGu;-=>#Wxz&W)ZUJ3U{MNfe2y>~`zxJ@3 z{-!YETSq?cUlELJ!ML~{#Qc^HX3~OJu)0znAGmW5aMS*n2;Z9*m^EIt8 zp4KCAVMQ=}01S)D%DtnU8U~FqOq%xTl=$Q>?ZP`i{Vas~5tpz=W1U*ID|0cxYO*?) zmgEL6xO340J>6tdQo5zoKCw-1AwsUY;j{eL+acF_6~ z({Ag8d)_smB7T9XT^#rM7dseqs_v!6eNL}cy~~3ATrgvm7e09IQYHKLIG(WV1q3QL z9-07i_Mh0_@~u#^_d^z&GOc(8L1&86>$eugh>Kg+RK^yC>%vah6!#g9(; zc9=_2{SF;>_;zbtw9Oo4lD=~K<{if{zD^<7g^Qyi&k4drBTP+hwOXtYy%~0t;eFGt z*y5=^&BdkoX~J@pIW|Q4Le~#(v$cV*djiW-HNj4(Q#&mz;VpxrgTg5pI+{wUJn{ST zTq3^D2J&|4`%>E}i~r;QzxGb;B*4pp2+7*%s)rt<_Pz`ZA2HhXl5|+>;0HGC4`}QS zghvWfG*tn0maH!}7>0dWxaJhsj5}AHRscTQLZyGw9!$CQ4|}Pe-T>ouq}g`Qb;3A? zAh$%@!!twAG6h8`TXqdBUi&N5aRq3+O8>8G{4ZZ_6PDAoIU~M6gAe~}?K;4sI=(#` zyV!e4Y*-Lm>=gw8H7XDmH5%Ij3$DU0!Y+bci7m$7yGEn2MNQEp_THn$9!u;s_TJxb z?iTj!&dj~O_wM)Y-#owP@64Pzea_4Pff=sK1hf5h8KyLTU^or|L!-INH~WSFRBthP zNJQ1kKOHL#oODP8^)6RsFu@6lmbCCBLyS=gH0>US&(fR=3N^k5p<9UsqX!P7Zp%ih zpu+?Nr|9F`m}1R*^tQideH#bl^H5@nzWS~NT@mA!)?{4eZ*ygQ^q8~jH+BJgDu6u{ zJ?Vi29a&_M0e4ax_3_63NF)Ts^%0@fuKk6T3j%jqxU3*d(PKHfE(5zIPQ-+pjV4?X z?x4q?%i&GiVsHhv z=r~yV!ef4mfLhB#YU;lbAiKmm>?91rs!*#y&A0vdRg=*`&joaP&Zgcg0eTx8aZ17o zMf|S|AwH`|$BvtP9MH`nl+>$~ej|Wayi1n-5&0SHSIk;KvCJ+Mh^beC|rL5byByio3G88O1R$rUaPM`t`zN3-;0s zpH{-2Mhkugt$UzVozPmCM@CC=I_&&c8yq9#L*Kssyn{bfbuf5D)pboi8FZxm0U0^^ zz^2vOz6bg?oNo>x18-YcfbLYzmWbkPe#gi8cMSuLmW;pW&*(_Q_Fr5CEoLHU`n zfMzG$ey@*;H%Oi$NGPJe5d}onk3y~fqmlwt<~;0XUS}{R8!g5Zqa{sjmw!81V#j5y za2)(UjeOUamXJV_Vob&nYB6wF-twpBVC;iEMD<}=32=t9Y7Y_efpG{h#n>m*UZ2S4 ze*F)*r~UyR4MRFWgP0fPCA3_UBk;*=;)7@UYI)~3SXwq2YCH2(l7KTk(^<@k65Cnn zkG|O+0C_5qYY;(=sw_da)$~whut>1W^t@GUBEqf>*o>eV*y<`0Y@HziM@fv)c8>c5 zga+}s(*0pjj>lm6OR$_;=6SUw_=-OdHz%^il{s|A4WKI@)u;P)DtWaJjtr>YCN!jG zfe<;-C_IOv$489InVZjWhjT^0aQ*x>S{+#G$+(ZO^9~~e_MZN zh2aqPAaI=yId>xgN9@id-eMGr_T|x`;aeadn>?)W)usYecZ)Adq8W1?JT7lzwf%qJ z`pck^vcS1|#;7^Wx*M-C)R7n}6^YR1TJR!K4r@b*EN~<)qPC-KaYv~hf81-UBG1;Y5`%noaT|G z0N(~frH*)PgaBSC%xXx_7mRs-b{b%l5CBny$P_7n4mEc)GPecG9PGGAgU{U-dtVGq z1o+P|5p*}?Nk;*=&3oAcWo6GoG0cMHdv(6`n>Y}t0Rq%A@9Hce;Mfk4*!*^7d+%D} zjrtN!sMEUgh^`W3JdqS@#HsW+Bo;bjf>ly-8yfV*$V^z&Gx*V+oUuj;g@7nrxuK7? z*xV$d@(d>N7h%+(3KOP*#y;=~WkZ+mX>SP~MK)b$;e+`|+|7`{F;hyG^YZ#E+`W?h zFkV2$R;uNXI%P(==vkQ6BmVkq4*$F4CaisF*bKV%?N%h9kyfXxg(Gtw*t_F-z55ux(O-}lVm6271j1{Tu%ea|id4cqw5)}&|wPi{wb zo>Uxoc@ezOM78A}0jA;t*hYw~jFz@A^O9bO5Ie)6QeOYEPk7~{foJ|D7Q z8#Fl#fff#4x@8vq{t;j^^ADqg;4{`3Csg1zpM4c_3=DpQMWoqdncH$;QtT0IT~up* zWJ^c5!%Hy#G;j{RD?zszOr^>eoN9=+3in#Z{?{kP zL|%az`UC4)o~W?tiG%?7&R@qZ-?jer5oC`YeG4FX3*X4`oa^Z0a9g&&k(%da!-9S| z1u~t%AIg8P4+3(E=@0H}MHSDIh5~Y;9$ONky{;FrURS0;a>BqOs-E@X4#-)0M;f8v zMUJ$CfOgS)hpqLo|3?^Z`_YRN>6!sqXTQR#_Vv))@zjX&^-a)TvI5(+=j0%f!GlCE- zgSd~v`{valeJ~NW>jF3I@$W}V>YgQV{5Ib0m z@q#pN)BJ~Pc4H+sV4yUOdm1Ezv{%a!nMDgq2DP7^d0G^fb3R-bUB^PL1jveAZiCPj z>z9HkR>Lmm_VqpY?#KAqQ1XjH;%peEo>SIxD7R#Tw8l?QSn4=Ewn@ zGqMNheEYCDe!$Fjn35S&qV{fKgn&v$$w9v1TsU_%-%nr@s$vpUBwIxapzR^JNLvq# zEIPCpyl>v(?jC(^M**Vh&d}5ji@#;or5hMfnTUDzo+3;`v^mbC>>~<7OLMEQ6KY`E zyRq#-T~w7QIVf|gD%F;KefE6GP5|YAtWz!eB~}2Am{N=LOCOouy90Q!3g|Q%_Z2Ie5BTizQ@RB)tB(Y~o!Oiy-;M$KL-OC*0(f4~*T$4=NU{XP!d8X}_GNZwoiVv>K7>u>-35OATmdD; z{e;9DQjMrFvP3~x8Smci;hc1+=1Tm0iHde#B>-29yK{e%zp%}IFLkFXxYG>Wi6XEK zSIb~U2G&slaaKKo%!XvtlHj+KtqFz@l$4~V_|HS-Uc3blQLXbTOUCo~C&73WLEz7> z?5Xz^c0;W69?4Y z3d@i9Q5Q1kkbo#+1z8>B_z$OkDGiOgf;cINF!|+S0it`Y0{g|RYN0g^4O~_F>I{s( z1gKISA9+kd5k{|%zL!BC6O4^7)YC-mHc6((zcv8$DolvhBL^Or!Ltj#+n8eTM~r&c z&DOr%hv&r{j^jrQF~v_yh=j*mlbP|3Lfod5)%c>dY2arYvjh1b{HWXc=8OcL>6xZF zNw0$u`I%fW(Ew{!Qb1V6)gi{g>sHT{2KM(HVj)G!S_F95a$-HuKwK0myMG&8V1 zdLJw)-7y$`K?X}};yx&=*}_{#qoYKYsPje};<4|c9t8l@xzp6g~gj3fS1P2>EF+-Y#nue#HtKQK@Mf>KgvTYHeh8 zZv)nVW)olL5O*#d!c;JZrs~J@2&gz6LPp_-&-CL}I{r2m zTHFs>Oj~6i7ZzaiW?&0u0u8aKI*6vxI!(7I3CwzjsnBWMDkdQ1ECQ+ZJ1l?Lvtbmb zQ5VyowSe`dB-kEhfR=h}x9~Z2zR&ed+aN~g;i_rPXTWC?5;_!;;tdwF$%7W3O!g@K zJXTU12TjlsSNeSg37HIZ&%U3J^Q>ok-0xEw^SpuqQ1d&mvSa`mcAY=39c@?M_X1?r z{O<1Pfu8_2$f%DqnUm2@qd^thO~}=)6C{8gf`+wn`NHZ5@D+=jdZw3U&ZY((iI`WyzGQC>%{G=&np&BPHmpm@aM&uhqf(oe2yn z0)_+=L1{Qa0?Mfy`PfPuN`fWbJnS{|?YVLw`5r$SDwV)x{M^kwwg$FdO?g9Qr&kU9 z+2P8vSOl6;O`9x%c5kS(?U9LM?^V&229Ae>-Y)B2#H%t@K*Z(*R12E_-fetx3wqq1 z!tBs&C;uV=vSR#|c6yxb5bnl5X*(syc?jim>|)TUsPaY`uzi`O%lUe7)uM&K@20?~ zQBjX=GHkc{k&kk6pRcu5`rT}u0*+6HO`v=^xkEt0-Qx3svtJx@XbGhL4t_KnSaL)L ztV=Ul^r?|(q2c518uPBu8DO&G`LuAb@Td&eS@@R+3BHA*4(tQ`d;BWmm+_rGCV=l~ zj@Cz^*DXnK2GFp3?o}ODaWz(v+VsbN3n1MclK5oHn$kaMJaV9PJSVjDXlx$>1;kEB&$n zlNl*x0mT)cGoN>EH45?RFR1KMMpU{fLG`dt5&S`S_HLYwMb#lt^FT6a?*|_Nk1#*l z5QFzq47Pw@c&_NthrBg+VqMvTfpj`EpGfF+!W%8o`lJ{&hqutX=1y-*TIE>p@g7JOjc5vI^5y$#g`Oi8MkAx7 zTfBSaf1aJhOdjTNPp7hH(Spt#s=QUwd-p+~!ce%{=vAbi!#{_Bf)d6k9yL)ppvGT_ zKb}ua*n{Q0l-oTRTbWM)?AoNr2R%Km+rB`^OITTVyS}H005rn6p~;6_UC}3{AZ%FH zGVZqV>k0zMj0j!O3vg)3shZg!gyZn5M$F9ingUE_8y&}yB++R4ku|khSL-AXFI4Vx z2{LwS5c;T@lS>6x4T!*!T?U6~5OkuB1l-N|^4a`;ShIsWzzSwjXdp4Xkpx?jHQ6>` zpJJP8cL$~wOrcg}Zet0qlEjJK(6dwD|J@z2)La}-q*@)`RDx<7t!meNwWH+%lfjFA z_|g2?`zv3~$AZ`ap2Q?Gy45U3gU2<54-d7>#d;s=gD;hc2wnvZZVutFuEHR>(YFu3 zS^})A_))P=?;^ldY+a_jbRoC=F$UMpBOd z5hZ|i7*S_?7#}$-IJ3W9wUa0!$t@-AbUng(AkYQCVhMw4#x9GU9aEK?Mz8#K>Vms+J>rVkq?dhV)GHBA=SBF3B8OML@!ot3s9@x5Rnz3v1vA>DQKjRQ0 zj_C-(X-qI=h5%dXn^IB|*#>n=$9kU}LO8P>>qy0U$wC3JVw8f+R`gM{HKYmKD85<$ zA&gz~_6qKc)@u(e5g?1gK56MQ^g#COC!j0cztXknL4L!GUtR_zD54Vv4YBj!qa^T(|8nQ{}S|y6!O5 zbqEK#ZWADf;FcZ7i4&wsD#>c`2YpL1o3}BayP{9uEg;~QX!BW8q0#sLs~~(!A=xxp z`r?oP*TxcTO<-G4UT~Oj@lic?0nMi@lqOu!9Tk8x+ouE!;a2nqVI^f@&Sy7oEo}g< zCt&c@LDoGX!FLPIl#@TkXkohAZ19JA0f6t9?w+n5J0qcDV-qW*%1;Z%PVbOwFjlsC zes{alw?I{XOv0F?4t(|Cq9$9wd4Grut+2H&E&z4}I}TwF(p&Tq=tvQ{iChC_>R5yO z?=UbllQ)(XkWdVa)4^jin}uqE>e7g7{dcgdL+^qF4LFNb&;&0Hd}`kBIea~&lSvQV zl^f+FKvyJF`zhJWY1TfsG5#i?Lha3hDgp{_N-OF^(O2<3;0wv0g!QF<|4LN>a)j-I zFuZiFXUi%u2Y(h^FcOQ|2Bjbxu|?Mu;AWHv#g~Gd3OIfAD25vf7uSjyf)@1zuueu~ z1XyUpvL7G*yuOB3vcL0ZPGd)7dt*K{&=}EJK-6h{Y*t5Hnw)#{z^a#+$Rw;T<a>v1Q`A7$ z$CxNH&S^&mT)~6fUWMDa3x8@$2{yB9DpC5={dv}wgGwFousS{B1jveE%eXKOr<$V8 zNrLy@1BUf&H5m(V2#hI97UAFC0(hl%$k(X-FOQdCmnc>DumM}+1!#(SPlz(&K1SK~ zF4g)U+RKW1#h_T!yZ&jCAlr(wE}4bM#`HdS@V5_4f8d-b{@X-Ve0Wo}M8NOaUvHy< zUmD9ubBwPo5`3k4r?TfcsMp*&RL^H&eK`6gaUil4>pl7VL_`KLp`m7)JV&H5mmkxaA zNC~u~ET__}T5RROcdT7#OhNZR{?=#-I;?=LGl;KLe~*g(b1T;NGl(W_b3Zsyf(mxH z?@*`->4@ehP9}ph*)a#|M4nEOP*N-;b00DbIXv5i2@S#d7MKZ*o_5ZVU^}`Bl$}pW zRg}p+kd+VIclo-^a)oysg>}F5=Ki8ib@E~AtD&EjUH&x+fZTtt=~Q~wY->&r!KhLI zN)tP;dAvbsOQ9ow|2H)lL)`~d>W)t?5Te=wTUlnl=VZkvDG;$)dE8<9E*8Q95N&lb z*c`PV_--xk<&_^vMJ2*m{}nt~c9uu2U>|?4@~Q7&AZDWwgo{mFzAtxjF^#PD&DXBX z6+Wy?MF6-CWAt-D0uzpKv9w+raI^Zx?_L9N0EE6g0e*d!2b>Z5@dx^C)SlumfWtab zsDuWcljBL$X7K&{%gaNK!oA͙TQLD_pZ#%M_h5I!=#UOL3+I1;f6WZGG-a1k@^ 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 xC6{rb<Z?z@GSy_d{67X#5A^^5 literal 0 HcmV?d00001 diff --git a/contrib/babelfishpg_tsql/babelfishpg_tsql.control.in b/contrib/babelfishpg_tsql/babelfishpg_tsql.control.in new file mode 100644 index 00000000000..2cc456730cd --- /dev/null +++ b/contrib/babelfishpg_tsql/babelfishpg_tsql.control.in @@ -0,0 +1,7 @@ +# babelfishpg_tsql extension +comment = 'Transact SQL compatibility' +default_version = '@EXTVERSION@' +module_pathname = '@MODULEPATH@' +relocatable = true +superuser = true +requires = 'uuid-ossp, babelfishpg_common' diff --git a/contrib/babelfishpg_tsql/runtime/basic.sql b/contrib/babelfishpg_tsql/runtime/basic.sql new file mode 100644 index 00000000000..37cf9748a9a --- /dev/null +++ b/contrib/babelfishpg_tsql/runtime/basic.sql @@ -0,0 +1,16 @@ +CREATE EXTENSION "babelfishpg_tsql"; + +CREATE SCHEMA IF NOT EXISTS dbo; +ALTER SYSTEM SET search_path = dbo, "$user", public; +SELECT pg_reload_conf(); + +CREATE OR REPLACE FUNCTION dbo.stuff(src text, start int, len int, replacement text) + RETURNS text AS + $$ SELECT overlay($1 PLACING $4 FROM $2 FOR $3) $$ + LANGUAGE 'sql'; + + +CREATE FUNCTION dbo.len(arg text) + RETURNS integer AS + $$ SELECT pg_catalog.length($1); $$ + LANGUAGE 'sql'; diff --git a/contrib/babelfishpg_tsql/runtime/functions.c b/contrib/babelfishpg_tsql/runtime/functions.c new file mode 100644 index 00000000000..6ccc2c39ee8 --- /dev/null +++ b/contrib/babelfishpg_tsql/runtime/functions.c @@ -0,0 +1,542 @@ +#include "postgres.h" +#include "port.h" + +#include "access/detoast.h" +#include "access/htup_details.h" +#include "access/table.h" +#include "access/xact.h" +#include "catalog/namespace.h" +#include "catalog/pg_database.h" +#include "catalog/pg_namespace.h" +#include "catalog/pg_type.h" +#include "commands/dbcommands.h" +#include "miscadmin.h" +#include "utils/acl.h" +#include "utils/builtins.h" +#include "utils/elog.h" +#include "utils/guc.h" +#include "utils/lsyscache.h" +#include "utils/memutils.h" +#include "utils/rel.h" +#include "utils/syscache.h" +#include "utils/varlena.h" +#include "utils/queryenvironment.h" +#include "utils/float.h" +#include + +#include "../src/babelfish_version.h" +#include "../src/datatypes.h" +#include "../src/pltsql.h" +#include "../src/pltsql_instr.h" +#include "../src/multidb.h" +#include "../src/session.h" +#include "../src/catalog.h" + +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(int_floor); +PG_FUNCTION_INFO_V1(int_ceiling); +PG_FUNCTION_INFO_V1(bit_floor); +PG_FUNCTION_INFO_V1(bit_ceiling); +PG_FUNCTION_INFO_V1(servername); +PG_FUNCTION_INFO_V1(xact_state); +PG_FUNCTION_INFO_V1(get_enr_list); +PG_FUNCTION_INFO_V1(tsql_random); +PG_FUNCTION_INFO_V1(is_member); +PG_FUNCTION_INFO_V1(schema_id); +PG_FUNCTION_INFO_V1(schema_name); +PG_FUNCTION_INFO_V1(datefirst); +PG_FUNCTION_INFO_V1(options); +PG_FUNCTION_INFO_V1(default_domain); +PG_FUNCTION_INFO_V1(tsql_exp); + +/* Not supported -- only syntax support */ +PG_FUNCTION_INFO_V1(procid); + +void* get_servername_internal(void); +extern bool canCommitTransaction(void); + +extern int pltsql_datefirst; +extern bool pltsql_implicit_transactions; +extern bool pltsql_cursor_close_on_commit; +extern bool pltsql_ansi_warnings; +extern bool pltsql_ansi_padding; +extern bool pltsql_ansi_nulls; +extern bool pltsql_arithabort; +extern bool pltsql_arithignore; +extern bool pltsql_quoted_identifier; +extern bool pltsql_nocount; +extern bool pltsql_ansi_null_dflt_on; +extern bool pltsql_ansi_null_dflt_off; +extern bool pltsql_concat_null_yields_null; +extern bool pltsql_numeric_roundabort; +extern bool pltsql_xact_abort; + +char *bbf_servername = "BABELFISH"; + +Datum +trancount(PG_FUNCTION_ARGS) +{ + PG_RETURN_UINT32(NestedTranCount); +} + +Datum +procid(PG_FUNCTION_ARGS) +{ + PG_RETURN_OID(procid_var); +} + +/* + * This function will return following version string + * Babelfish for PostgreSQL with SQL Server Compatibility - 12.0.2000.8 + * + * Copyright (c) Amazon Web Services + * PostgreSQL xx.xx on + */ +Datum +version(PG_FUNCTION_ARGS) +{ + StringInfoData temp; + void *info; + + initStringInfo(&temp); + + if (pg_strcasecmp(pltsql_version, "default") == 0) + { + char *pg_version = pstrdup(PG_VERSION_STR); + char *temp_str = pg_version; + + temp_str = strstr(temp_str, ", compiled by"); + *temp_str = '\0'; + + appendStringInfo(&temp, + "Babelfish for PostgreSQL with SQL Server Compatibility - %s" + "\n%s %s\nCopyright (c) Amazon Web Services\n%s", + BABEL_COMPATIBILITY_VERSION, + __DATE__, __TIME__, pg_version); + } + else + appendStringInfoString(&temp, pltsql_version); + + /* + * TODO: Return Build number with version string as well. + */ + + info = tsql_varchar_input(temp.data, temp.len, -1); + pfree(temp.data); + PG_RETURN_VARCHAR_P(info); +} + +void* get_servername_internal() +{ + StringInfoData temp; + void* info; + + initStringInfo(&temp); + appendStringInfoString(&temp, bbf_servername); + + info = tsql_varchar_input(temp.data, temp.len, -1); + pfree(temp.data); + return info; +} + +/* + * This function will return the servername. + */ +Datum +servername(PG_FUNCTION_ARGS) +{ + PG_RETURN_VARCHAR_P(get_servername_internal()); +} + +Datum +error(PG_FUNCTION_ARGS) +{ + 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(tsql_varchar_input((error_sqlstate), strlen(error_sqlstate), -1)); +} + + +/* returns data length of one Datum + * this function is very similar to pg_column_size, but returns untoasted data without header sizes for bytea objects +*/ +Datum +datalength(PG_FUNCTION_ARGS) +{ + Datum value = PG_GETARG_DATUM(0); + int32 result; + int typlen; + + /* On first call, get the input type's typlen, and save at *fn_extra */ + if (fcinfo->flinfo->fn_extra == NULL) + { + /* Lookup the datatype of the supplied argument */ + Oid argtypeid = get_fn_expr_argtype(fcinfo->flinfo, 0); + + typlen = get_typlen(argtypeid); + if (typlen == 0) /* should not happen */ + elog(ERROR, "cache lookup failed for type %u", argtypeid); + + fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt, + sizeof(int)); + *((int *) fcinfo->flinfo->fn_extra) = typlen; + } + else + typlen = *((int *) fcinfo->flinfo->fn_extra); + + if (typlen == -1) + { + /* varlena type, untoasted and without header*/ + result = toast_raw_datum_size(value) - VARHDRSZ; + } + else if (typlen == -2) + { + /* cstring */ + result = strlen(DatumGetCString(value)) + 1; + } + else + { + /* ordinary fixed-width type */ + result = typlen; + } + + 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 +* 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); +} + +Datum +int_ceiling(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + /* Ceiling of an integer is the integer itself */ + PG_RETURN_INT64(arg1); +} + +/* +* 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. +*/ +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); +} + +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) +{ + if (NestedTranCount == 0) + { + PG_RETURN_INT16(0); + } + else if (canCommitTransaction()) + { + PG_RETURN_INT16(1); + } + else + { + PG_RETURN_INT16(-1); + } +} + +Datum +get_enr_list(PG_FUNCTION_ARGS) +{ + ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; + TupleDesc tupdesc; + Tuplestorestate *tupstore; + MemoryContext per_query_ctx; + MemoryContext oldcontext; + List *enr_list = get_namedRelList(); + ListCell *lc; + + /* check to see if caller supports us returning a tuplestore */ + if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("set-valued function called in context that cannot accept a set"))); + if (!(rsinfo->allowedModes & SFRM_Materialize)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("materialize mode required, but it is not " \ + "allowed in this context"))); + + /* need to build tuplestore in query context */ + per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; + oldcontext = MemoryContextSwitchTo(per_query_ctx); + + /* build tupdesc for result tuples. */ + tupdesc = CreateTemplateTupleDesc(2); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "reloid", + INT4OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 2, "relname", + TEXTOID, -1, 0); + + tupstore = + tuplestore_begin_heap(rsinfo->allowedModes & SFRM_Materialize_Random, + false, 1024); + /* generate junk in short-term context */ + MemoryContextSwitchTo(oldcontext); + + /* scan all the variables in top estate */ + foreach(lc, enr_list) + { + Datum values[2]; + bool nulls[2]; + + MemSet(nulls, 0, sizeof(nulls)); + + values[0] = ((EphemeralNamedRelationMetadata)lfirst(lc))->reliddesc; + values[1] = CStringGetTextDatum(((EphemeralNamedRelationMetadata)lfirst(lc))->name); + + 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(); +} + +Datum +tsql_random(PG_FUNCTION_ARGS) +{ + LOCAL_FCINFO(fcinfo1, 0); + int seed = PG_GETARG_INT32(0); + Datum result; + + /* set the seed first */ + DirectFunctionCall1(setseed, Float8GetDatum((double) seed / 2147483649)); + + /* call PG's random function */ + InitFunctionCallInfoData(*fcinfo1, NULL, 0, InvalidOid, NULL, NULL); + result = drandom(fcinfo1); + + return result; +} + +Datum +is_member(PG_FUNCTION_ARGS) +{ + const char *role = text_to_cstring(PG_GETARG_TEXT_P(0)); + Oid role_oid = get_role_oid(role, true); + + if (!OidIsValid(role_oid)) + { + PG_RETURN_NULL(); + } + + if (is_member_of_role(GetUserId(), role_oid)) + { + PG_RETURN_INT32(1); + } + else + { + PG_RETURN_INT32(0); + } +} + +Datum +schema_name(PG_FUNCTION_ARGS) +{ + Oid oid = PG_GETARG_OID(0); + HeapTuple tup; + Form_pg_namespace nspform; + NameData name; + const char *logical_name; + + VarChar *result; + + if (!OidIsValid(oid)) + { + PG_RETURN_NULL(); + } + + tup = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(oid)); + + if (!HeapTupleIsValid(tup)) + { + PG_RETURN_NULL(); + } + + nspform = (Form_pg_namespace) GETSTRUCT(tup); + name = nspform->nspname; + + logical_name = get_logical_schema_name(name.data, true); + if (logical_name) + result = tsql_varchar_input(logical_name, strlen(logical_name), -1); + else + result = tsql_varchar_input(name.data, strlen(name.data), -1); + + ReleaseSysCache(tup); + PG_RETURN_VARCHAR_P(result); +} + +Datum +schema_id(PG_FUNCTION_ARGS) +{ + const char *name = text_to_cstring(PG_GETARG_TEXT_P(0)); + int id; + HeapTuple tup; + Oid nspOid; + Form_pg_namespace nspform; + const char *physical_name = get_physical_schema_name(get_cur_db_name(), name); + + tup = SearchSysCache1(NAMESPACENAME, CStringGetDatum(physical_name)); + + if (!HeapTupleIsValid(tup)) + { + PG_RETURN_NULL(); + } + + nspform = (Form_pg_namespace) GETSTRUCT(tup); + nspOid = nspform->oid; + id = (int) nspOid; + + ReleaseSysCache(tup); + PG_RETURN_INT32(id); +} + +Datum +datefirst(PG_FUNCTION_ARGS) +{ + PG_RETURN_UINT32(pltsql_datefirst); +} + +/* @@OPTIONS returns a bitmap of the current boolean SET options */ +Datum +options(PG_FUNCTION_ARGS) +{ + int options = 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; + + /* 3rd bit: CURSOR_CLOSE_ON_COMMIT */ + if (pltsql_cursor_close_on_commit) + options += 4; + + /* 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; + + /* 6th bit: ANSI_NULLS */ + if (pltsql_ansi_nulls) + options += 32; + + /* 7th bit: ARITHABORT */ + if (pltsql_arithabort) + options += 64; + + /* 8th bit: ARITHIGNORE */ + if (pltsql_arithignore) + options += 128; + + /* 9th bit: QUOTED_IDENTIFIER */ + if (pltsql_quoted_identifier) + options += 256; + + /* 10th bit: NOCOUNT */ + if (pltsql_nocount) + options += 512; + + /* 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; + + /* 13th bit: CONCAT_NULL_YIELDS_NULL */ + if (pltsql_concat_null_yields_null) + options += 4096; + + /* 14th bit: NUMERIC_ROUNDABORT */ + if (pltsql_numeric_roundabort) + options += 8192; + + /* 15th bit: XACT_ABORT */ + if (pltsql_xact_abort) + options += 16384; + + PG_RETURN_UINT32(options); +} + +/* This function will return the default AD domain name */ +Datum +default_domain(PG_FUNCTION_ARGS) +{ + 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(tsql_varchar_input(login_domainname, strlen(login_domainname), -1)); + else + PG_RETURN_NULL(); +} + +/* + * tsql_exp - returns the exponential function of arg1 + */ +Datum +tsql_exp(PG_FUNCTION_ARGS) +{ + float8 arg1 = PG_GETARG_FLOAT8(0); + float8 result; + + errno = 0; + result = exp(arg1); + if (errno == ERANGE && result != 0 && !isinf(result)) + result = get_float8_infinity(); + + if (unlikely(isinf(result)) && !isinf(arg1)) + float_overflow_error(); + PG_RETURN_FLOAT8(result); +} diff --git a/contrib/babelfishpg_tsql/sql/babelfishpg_tsql--1.0.0.sql b/contrib/babelfishpg_tsql/sql/babelfishpg_tsql--1.0.0.sql new file mode 100644 index 00000000000..801002a81a0 --- /dev/null +++ b/contrib/babelfishpg_tsql/sql/babelfishpg_tsql--1.0.0.sql @@ -0,0 +1,16610 @@ +-- 1 "sql/babelfishpg_tsql.in" +-- 1 "" +-- 1 "" +-- 1 "sql/babelfishpg_tsql.in" + + + + +SELECT set_config('search_path', 'sys, '||current_setting('search_path'), false); + +-- 1 "sql/datatype.sql" 1 +-- Types with different default typmod behavior +SET enable_domain_typmod = TRUE; + +CREATE DOMAIN sys.CURSOR AS REFCURSOR; + +RESET enable_domain_typmod; +-- 8 "sql/babelfishpg_tsql.in" 2 +-- 1 "sql/datatype_string_operators.sql" 1 +CREATE OR REPLACE FUNCTION sys.hashbytes(IN alg VARCHAR, IN data VARCHAR) RETURNS sys.bbf_varbinary +AS 'babelfishpg_tsql', 'hashbytes' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; +GRANT EXECUTE ON FUNCTION sys.hashbytes(IN VARCHAR, IN VARCHAR) TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.hashbytes(IN alg VARCHAR, IN data sys.bbf_varbinary) RETURNS sys.bbf_varbinary +AS 'babelfishpg_tsql', 'hashbytes' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; +GRANT EXECUTE ON FUNCTION sys.hashbytes(IN VARCHAR, IN sys.bbf_varbinary) TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.quotename(IN input_string VARCHAR, IN delimiter char default '[') RETURNS +sys.nvarchar AS 'babelfishpg_tsql', 'quotename' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; +GRANT EXECUTE ON FUNCTION sys.quotename(IN VARCHAR, IN char) TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.unicode(IN str VARCHAR) returns INTEGER +as +$BODY$ + select ascii(str); +$BODY$ +LANGUAGE SQL IMMUTABLE STRICT PARALLEL SAFE; +GRANT EXECUTE ON FUNCTION sys.unicode(IN VARCHAR) TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.string_split(IN string VARCHAR, IN separator VARCHAR, OUT value VARCHAR) RETURNS SETOF VARCHAR AS +$body$ +BEGIN + if length(separator) != 1 then + RAISE EXCEPTION 'Invalid separator: %', separator USING HINT = + 'Separator must be length 1'; +else + RETURN QUERY(SELECT cast(unnest(string_to_array(string, separator)) as varchar)); +end if; +END +$body$ +LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE; +GRANT EXECUTE ON FUNCTION sys.string_split(IN VARCHAR, IN VARCHAR, OUT VARCHAR) TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.string_escape(IN str sys.NVARCHAR, IN type TEXT) RETURNS sys.NVARCHAR +AS 'babelfishpg_tsql', 'string_escape' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; +GRANT EXECUTE ON FUNCTION sys.string_escape(IN sys.NVARCHAR, IN TEXT) TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.formatmessage(IN message_str TEXT) RETURNS sys.nvarchar +AS 'babelfishpg_tsql', 'formatmessage' LANGUAGE C IMMUTABLE PARALLEL SAFE; +GRANT EXECUTE ON FUNCTION sys.formatmessage(IN TEXT) TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.formatmessage(IN message_str VARCHAR) RETURNS sys.nvarchar +AS 'babelfishpg_tsql', 'formatmessage' LANGUAGE C IMMUTABLE PARALLEL SAFE; +GRANT EXECUTE ON FUNCTION sys.formatmessage(IN VARCHAR) TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.formatmessage(IN message_str TEXT, VARIADIC "any") RETURNS sys.nvarchar +AS 'babelfishpg_tsql', 'formatmessage' LANGUAGE C IMMUTABLE PARALLEL SAFE; +GRANT EXECUTE ON FUNCTION sys.formatmessage(IN TEXT, VARIADIC "any") TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.formatmessage(IN message_str VARCHAR, VARIADIC "any") RETURNS sys.nvarchar +AS 'babelfishpg_tsql', 'formatmessage' LANGUAGE C IMMUTABLE PARALLEL SAFE; +GRANT EXECUTE ON FUNCTION sys.formatmessage(IN VARCHAR, VARIADIC "any") TO PUBLIC; +-- 9 "sql/babelfishpg_tsql.in" 2 +-- 1 "sql/sys.sql" 1 + +CREATE FUNCTION sys.sysdatetime() RETURNS datetime2 + AS $$select clock_timestamp()::datetime2;$$ + LANGUAGE SQL; +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; +GRANT EXECUTE ON FUNCTION sys.sysdatetimeoffset() TO PUBLIC; + + +CREATE FUNCTION sys.sysutcdatetime() RETURNS sys.datetime2 + AS $$select (clock_timestamp() AT TIME ZONE 'UTC')::sys.datetime2;$$ + LANGUAGE SQL; +GRANT EXECUTE ON FUNCTION sys.sysutcdatetime() TO PUBLIC; + + +CREATE FUNCTION sys.getdate() RETURNS sys.datetime + AS $$select date_trunc('millisecond', clock_timestamp()::timestamp)::sys.datetime;$$ + LANGUAGE SQL; +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 FUNCTION sys.isnull(text,text) RETURNS text AS $$ + SELECT COALESCE($1,$2); +$$ +LANGUAGE SQL; +GRANT EXECUTE ON FUNCTION sys.isnull(text,text) TO PUBLIC; + +CREATE FUNCTION sys.isnull(boolean,boolean) RETURNS boolean AS $$ + SELECT COALESCE($1,$2); +$$ +LANGUAGE SQL; +GRANT EXECUTE ON FUNCTION sys.isnull(boolean,boolean) TO PUBLIC; + +CREATE FUNCTION sys.isnull(smallint,smallint) RETURNS smallint AS $$ + SELECT COALESCE($1,$2); +$$ +LANGUAGE SQL; +GRANT EXECUTE ON FUNCTION sys.isnull(smallint,smallint) TO PUBLIC; + +CREATE FUNCTION sys.isnull(integer,integer) RETURNS integer AS $$ + SELECT COALESCE($1,$2); +$$ +LANGUAGE SQL; +GRANT EXECUTE ON FUNCTION sys.isnull(integer,integer) TO PUBLIC; + +CREATE FUNCTION sys.isnull(bigint,bigint) RETURNS bigint AS $$ + SELECT COALESCE($1,$2); +$$ +LANGUAGE SQL; +GRANT EXECUTE ON FUNCTION sys.isnull(bigint,bigint) TO PUBLIC; + +CREATE FUNCTION sys.isnull(real,real) RETURNS real AS $$ + SELECT COALESCE($1,$2); +$$ +LANGUAGE SQL; +GRANT EXECUTE ON FUNCTION sys.isnull(real,real) TO PUBLIC; + +CREATE FUNCTION sys.isnull(double precision, double precision) RETURNS double precision AS $$ + SELECT COALESCE($1,$2); +$$ +LANGUAGE SQL; +GRANT EXECUTE ON FUNCTION sys.isnull(double precision, double precision) TO PUBLIC; + +CREATE FUNCTION sys.isnull(numeric,numeric) RETURNS numeric AS $$ + SELECT COALESCE($1,$2); +$$ +LANGUAGE SQL; +GRANT EXECUTE ON FUNCTION sys.isnull(numeric,numeric) TO PUBLIC; + +CREATE FUNCTION sys.isnull(date, date) RETURNS date AS $$ + SELECT COALESCE($1,$2); +$$ +LANGUAGE SQL; +GRANT EXECUTE ON FUNCTION sys.isnull(date,date) TO PUBLIC; + +CREATE FUNCTION sys.isnull(timestamp,timestamp) RETURNS timestamp AS $$ + SELECT COALESCE($1,$2); +$$ +LANGUAGE SQL; +GRANT EXECUTE ON FUNCTION sys.isnull(timestamp,timestamp) TO PUBLIC; + +CREATE FUNCTION sys.isnull(timestamp with time zone,timestamp with time zone) RETURNS timestamp with time zone AS $$ + SELECT COALESCE($1,$2); +$$ +LANGUAGE SQL; +GRANT EXECUTE ON FUNCTION sys.isnull(timestamp with time zone,timestamp with time zone) TO PUBLIC; + + +CREATE TABLE IF NOT EXISTS sys.service_settings +( + service character varying(50) NOT NULL + ,setting character varying(100) NOT NULL + ,value character varying +); +GRANT SELECT ON sys.service_settings TO PUBLIC; + +comment on table sys.service_settings is 'Settings for Extension Pack services'; +comment on column sys.service_settings.service is 'Service name'; +comment on column sys.service_settings.setting is 'Setting name'; +comment on column sys.service_settings.value is 'Setting value'; + +CREATE TABLE sys.versions +( + extpackcomponentname VARCHAR(256) NOT NULL, + componentversion VARCHAR(256) +); +GRANT SELECT ON sys.versions TO PUBLIC; + +CREATE TABLE sys.syslanguages ( + lang_id SMALLINT, + lang_name_pg VARCHAR(30), + lang_alias_pg VARCHAR(30), + lang_name_mssql VARCHAR(30), + lang_alias_mssql VARCHAR(30), + territory VARCHAR(50), + spec_culture VARCHAR(10), + lang_data_jsonb JSONB +) WITH (OIDS = FALSE); +GRANT SELECT ON sys.syslanguages TO PUBLIC; +-- 10 "sql/babelfishpg_tsql.in" 2 +-- 1 "sql/sys_languages.sql" 1 + +INSERT INTO sys.syslanguages + VALUES (1, + 'ENGLISH', + 'ENGLISH (AUSTRALIA)', + NULL, + NULL, + 'AUSTRALIA', + 'EN-AU', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (2, + 'ENGLISH', + 'ENGLISH (BELGIUM)', + NULL, + NULL, + 'BELGIUM', + 'EN-BE', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (3, + 'ENGLISH', + 'ENGLISH (BELIZE)', + NULL, + NULL, + 'BELIZE', + 'EN-BZ', + jsonb_build_object('date_format', 'MDY', + 'date_first', 1, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (4, + 'ENGLISH', + 'ENGLISH (BOTSWANA)', + NULL, + NULL, + 'BOTSWANA', + 'EN-BW', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (5, + 'ENGLISH', + 'ENGLISH (CAMEROON)', + NULL, + NULL, + 'CAMEROON', + 'EN-CM', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (6, + 'ENGLISH', + 'ENGLISH (CANADA)', + NULL, + NULL, + 'CANADA', + 'EN-CA', + jsonb_build_object('date_format', 'YMD', + 'date_first', 1, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (7, + 'ENGLISH', + 'ENGLISH (ERITREA)', + NULL, + NULL, + 'ERITREA', + 'EN-ER', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (8, + 'ENGLISH', + 'ENGLISH (INDIA)', + NULL, + NULL, + 'INDIA', + 'EN-IN', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (9, + 'ENGLISH', + 'ENGLISH (IRELAND)', + NULL, + NULL, + 'IRELAND', + 'EN-IE', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (10, + 'ENGLISH', + 'ENGLISH (JAMAICA)', + NULL, + NULL, + 'JAMAICA', + 'EN-IM', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (11, + 'ENGLISH', + 'ENGLISH (KENYA)', + NULL, + NULL, + 'KENYA', + 'EN-KE', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (12, + 'ENGLISH', + 'ENGLISH (MALAYSIA)', + NULL, + NULL, + 'MALAYSIA', + 'EN-MY', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (13, + 'ENGLISH', + 'ENGLISH (MALTA)', + NULL, + NULL, + 'MALTA', + 'EN-MT', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (14, + 'ENGLISH', + 'ENGLISH (NEW ZEALAND)', + NULL, + NULL, + 'NEW ZEALAND', + 'EN-NZ', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (15, + 'ENGLISH', + 'ENGLISH (NIGERIA)', + NULL, + NULL, + 'NIGERIA', + 'EN-NG', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (16, + 'ENGLISH', + 'ENGLISH (PAKISTAN)', + NULL, + NULL, + 'PAKISTAN', + 'EN-PK', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (17, + 'ENGLISH', + 'ENGLISH (PHILIPPINES)', + NULL, + NULL, + 'PHILIPPINES', + 'EN-PH', + jsonb_build_object('date_format', 'MDY', + 'date_first', 1, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (18, + 'ENGLISH', + 'ENGLISH (PUERTO RICO)', + NULL, + NULL, + 'PUERTO RICO', + 'EN-PR', + jsonb_build_object('date_format', 'MDY', + 'date_first', 1, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (19, + 'ENGLISH', + 'ENGLISH (SINGAPORE)', + NULL, + NULL, + 'SINGAPORE', + 'EN-SG', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (20, + 'ENGLISH', + 'ENGLISH (SOUTH AFRICA)', + NULL, + NULL, + 'SOUTH AFRICA', + 'EN-ZA', + jsonb_build_object('date_format', 'YMD', + 'date_first', 1, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (21, + 'ENGLISH', + 'ENGLISH (TRINIDAD & TOBAGO)', + NULL, + NULL, + 'TRINIDAD & TOBAGO', + 'EN-TT', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (22, + 'ENGLISH', + 'ENGLISH (GREAT BRITAIN)', + 'BRITISH', + 'BRITISH ENGLISH', + 'GREAT BRITAIN', + 'EN-GB', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (23, + 'ENGLISH', + 'ENGLISH (UNITED KINGDOM)', + NULL, + NULL, + 'UNITED KINGDOM', + 'EN-UK', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (24, + 'ENGLISH', + 'ENGLISH (ENGLAND)', + NULL, + NULL, + 'ENGLAND', + 'EN-EN', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (25, + 'ENGLISH', + 'ENGLISH (UNITED STATES)', + 'US_ENGLISH', + 'ENGLISH', + 'UNITED STATES', + 'EN-US', + jsonb_build_object('date_format', 'MDY', + 'date_first', 7, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (26, + 'ENGLISH', + 'ENGLISH (ZIMBABWE)', + NULL, + NULL, + 'ZIMBABWE', + 'EN-ZW', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (27, + 'GERMAN', + 'GERMAN (AUSTRIA)', + NULL, + NULL, + 'AUSTRIA', + 'DE-AT', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'), + 'days_names', jsonb_build_array('Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag', 'Sonntag'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (28, + 'GERMAN', + 'GERMAN (BELGIUM)', + NULL, + NULL, + 'BELGIUM', + 'DE-BE', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'), + 'days_names', jsonb_build_array('Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag', 'Sonntag'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (29, + 'GERMAN', + 'GERMAN (GERMANY)', + 'DEUTSCH', + 'GERMAN', + 'GERMANY', + 'DE-DE', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag', 'Sonntag'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (30, + 'GERMAN', + 'GERMAN (LIECHTENSTEIN)', + NULL, + NULL, + 'LIECHTENSTEIN', + 'DE-LI', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'), + 'days_names', jsonb_build_array('Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag', 'Sonntag'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (31, + 'GERMAN', + 'GERMAN (LUXEMBOURG)', + NULL, + NULL, + 'LUXEMBOURG', + 'DE-LU', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'), + 'days_names', jsonb_build_array('Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag', 'Sonntag'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (32, + 'GERMAN', + 'GERMAN (SWITZERLAND)', + NULL, + NULL, + 'SWITZERLAND', + 'DE-CH', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'), + 'days_names', jsonb_build_array('Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag', 'Sonntag'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (33, + 'FRENCH', + 'FRENCH (ALGERIA)', + NULL, + NULL, + 'ALGERIA', + 'FR-DZ', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'), + 'months_shortnames', jsonb_build_array('janv', 'févr', 'mars', 'avr', 'mai', 'juin', 'juil', 'août', 'sept', 'oct', 'nov', 'déc'), + 'days_names', jsonb_build_array('lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi', 'dimanche'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (34, + 'FRENCH', + 'FRENCH (BELGIUM)', + NULL, + NULL, + 'BELGIUM', + 'FR-BE', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'), + 'months_shortnames', jsonb_build_array('janv', 'févr', 'mars', 'avr', 'mai', 'juin', 'juil', 'août', 'sept', 'oct', 'nov', 'déc'), + 'days_names', jsonb_build_array('lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi', 'dimanche'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (35, + 'FRENCH', + 'FRENCH (CAMEROON)', + NULL, + NULL, + 'CAMEROON', + 'FR-CM', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'), + 'months_shortnames', jsonb_build_array('janv', 'févr', 'mars', 'avr', 'mai', 'juin', 'juil', 'août', 'sept', 'oct', 'nov', 'déc'), + 'days_names', jsonb_build_array('lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi', 'dimanche'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (36, + 'FRENCH', + 'FRENCH (CANADA)', + NULL, + NULL, + 'CANADA', + 'FR-CA', + jsonb_build_object('date_format', 'YMD', + 'date_first', 1, + 'months_names', jsonb_build_array('janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'), + 'months_shortnames', jsonb_build_array('janv', 'févr', 'mars', 'avr', 'mai', 'juin', 'juil', 'août', 'sept', 'oct', 'nov', 'déc'), + 'days_names', jsonb_build_array('lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi', 'dimanche'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (37, + 'FRENCH', + 'FRENCH (FRANCE)', + 'FRANÇAIS', + 'FRENCH', + 'FRANCE', + 'FR-FR', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'), + 'months_shortnames', jsonb_build_array('janv', 'févr', 'mars', 'avr', 'mai', 'juin', 'juil', 'août', 'sept', 'oct', 'nov', 'déc'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi', 'dimanche'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (38, + 'FRENCH', + 'FRENCH (HAITI)', + NULL, + NULL, + 'HAITI', + 'FR-HT', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'), + 'months_shortnames', jsonb_build_array('janv', 'févr', 'mars', 'avr', 'mai', 'juin', 'juil', 'août', 'sept', 'oct', 'nov', 'déc'), + 'days_names', jsonb_build_array('lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi', 'dimanche'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (39, + 'FRENCH', + 'FRENCH (LUXEMBOURG)', + NULL, + NULL, + 'LUXEMBOURG', + 'FR-LU', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'), + 'months_shortnames', jsonb_build_array('janv', 'févr', 'mars', 'avr', 'mai', 'juin', 'juil', 'août', 'sept', 'oct', 'nov', 'déc'), + 'days_names', jsonb_build_array('lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi', 'dimanche'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (40, + 'FRENCH', + 'FRENCH (MALI)', + NULL, + NULL, + 'MALI', + 'FR-ML', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'), + 'months_shortnames', jsonb_build_array('janv', 'févr', 'mars', 'avr', 'mai', 'juin', 'juil', 'août', 'sept', 'oct', 'nov', 'déc'), + 'days_names', jsonb_build_array('lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi', 'dimanche'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (41, + 'FRENCH', + 'FRENCH (MONACO)', + NULL, + NULL, + 'MONACO', + 'FR-MC', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'), + 'months_shortnames', jsonb_build_array('janv', 'févr', 'mars', 'avr', 'mai', 'juin', 'juil', 'août', 'sept', 'oct', 'nov', 'déc'), + 'days_names', jsonb_build_array('lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi', 'dimanche'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (42, + 'FRENCH', + 'FRENCH (MOROCCO)', + NULL, + NULL, + 'MOROCCO', + 'FR-MA', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'), + 'months_shortnames', jsonb_build_array('janv', 'févr', 'mars', 'avr', 'mai', 'juin', 'juil', 'août', 'sept', 'oct', 'nov', 'déc'), + 'days_names', jsonb_build_array('lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi', 'dimanche'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (43, + 'FRENCH', + 'FRENCH (SENEGAL)', + NULL, + NULL, + 'SENEGAL', + 'FR-SN', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'), + 'months_shortnames', jsonb_build_array('janv', 'févr', 'mars', 'avr', 'mai', 'juin', 'juil', 'août', 'sept', 'oct', 'nov', 'déc'), + 'days_names', jsonb_build_array('lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi', 'dimanche'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (44, + 'FRENCH', + 'FRENCH (SWITZERLAND)', + NULL, + NULL, + 'SWITZERLAND', + 'FR-CH', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'), + 'months_shortnames', jsonb_build_array('janv', 'févr', 'mars', 'avr', 'mai', 'juin', 'juil', 'août', 'sept', 'oct', 'nov', 'déc'), + 'days_names', jsonb_build_array('lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi', 'dimanche'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (45, + 'FRENCH', + 'FRENCH (SYRIA)', + NULL, + NULL, + 'SYRIA', + 'FR-SY', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'), + 'months_shortnames', jsonb_build_array('janv', 'févr', 'mars', 'avr', 'mai', 'juin', 'juil', 'août', 'sept', 'oct', 'nov', 'déc'), + 'days_names', jsonb_build_array('lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi', 'dimanche'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (46, + 'FRENCH', + 'FRENCH (TUNISIA)', + NULL, + NULL, + 'TUNISIA', + 'FR-TN', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'), + 'months_shortnames', jsonb_build_array('janv', 'févr', 'mars', 'avr', 'mai', 'juin', 'juil', 'août', 'sept', 'oct', 'nov', 'déc'), + 'days_names', jsonb_build_array('lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi', 'dimanche'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (47, + 'JAPANESE', + 'JAPANESE (JAPAN)', + '日本語', + 'JAPANESE', + 'JAPAN', + 'JA-JP', + jsonb_build_object('date_format', 'YMD', + 'date_first', 7, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('月曜日', '火曜日', '水曜日', '木曜日', '金曜日', '土曜日', '日曜日'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (48, + 'DANISH', + 'DANISH (DENMARK)', + 'DANSK', + 'DANISH', + 'DENMARK', + 'DA-DK', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('januar', 'februar', 'marts', 'april', 'maj', 'juni', 'juli', 'august', 'september', 'oktober', 'november', 'december'), + 'months_shortnames', jsonb_build_array('jan', 'feb', 'mar', 'apr', 'maj', 'jun', 'jul', 'aug', 'sep', 'okt', 'nov', 'dec'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('mandag', 'tirsdag', 'onsdag', 'torsdag', 'fredag', 'lørdag', 'søndag'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (49, + 'DANISH', + 'DANISH (GREENLAND)', + NULL, + NULL, + 'GREENLAND', + 'DA-GL', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('januar', 'februar', 'marts', 'april', 'maj', 'juni', 'juli', 'august', 'september', 'oktober', 'november', 'december'), + 'months_shortnames', jsonb_build_array('jan', 'feb', 'mar', 'apr', 'maj', 'jun', 'jul', 'aug', 'sep', 'okt', 'nov', 'dec'), + 'days_names', jsonb_build_array('mandag', 'tirsdag', 'onsdag', 'torsdag', 'fredag', 'lørdag', 'søndag'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (50, + 'SPANISH', + 'SPANISH (ARGENTINA)', + NULL, + NULL, + 'ARGENTINA', + 'ES-AR', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'), + 'months_shortnames', jsonb_build_array('Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'), + 'days_names', jsonb_build_array('Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (51, + 'SPANISH', + 'SPANISH (BOLIVIA)', + NULL, + NULL, + 'BOLIVIA', + 'ES-BO', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'), + 'months_shortnames', jsonb_build_array('Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'), + 'days_names', jsonb_build_array('Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (52, + 'SPANISH', + 'SPANISH (CHILE)', + NULL, + NULL, + 'CHILE', + 'ES-CL', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'), + 'months_shortnames', jsonb_build_array('Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'), + 'days_names', jsonb_build_array('Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (53, + 'SPANISH', + 'SPANISH (COLOMBIA)', + NULL, + NULL, + 'COLOMBIA', + 'ES-CO', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'), + 'months_shortnames', jsonb_build_array('Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'), + 'days_names', jsonb_build_array('Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (54, + 'SPANISH', + 'SPANISH (COSTA RICA)', + NULL, + NULL, + 'COSTA RICA', + 'ES-CR', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'), + 'months_shortnames', jsonb_build_array('Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'), + 'days_names', jsonb_build_array('Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (55, + 'SPANISH', + 'SPANISH (CUBA)', + NULL, + NULL, + 'CUBA', + 'ES-CU', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'), + 'months_shortnames', jsonb_build_array('Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'), + 'days_names', jsonb_build_array('Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (56, + 'SPANISH', + 'SPANISH (DOMINICAN REPUBLIC)', + NULL, + NULL, + 'DOMINICAN REPUBLIC', + 'ES-DO', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'), + 'months_shortnames', jsonb_build_array('Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'), + 'days_names', jsonb_build_array('Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (57, + 'SPANISH', + 'SPANISH (ECUADOR)', + NULL, + NULL, + 'ECUADOR', + 'ES-EC', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'), + 'months_shortnames', jsonb_build_array('Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'), + 'days_names', jsonb_build_array('Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (58, + 'SPANISH', + 'SPANISH (EL SALVADOR)', + NULL, + NULL, + 'EL SALVADOR', + 'ES-SV', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'), + 'months_shortnames', jsonb_build_array('Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'), + 'days_names', jsonb_build_array('Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (59, + 'SPANISH', + 'SPANISH (GUATEMALA)', + NULL, + NULL, + 'GUATEMALA', + 'ES-GT', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'), + 'months_shortnames', jsonb_build_array('Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'), + 'days_names', jsonb_build_array('Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (60, + 'SPANISH', + 'SPANISH (HONDURASALA)', + NULL, + NULL, + 'HONDURAS', + 'ES-HN', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'), + 'months_shortnames', jsonb_build_array('Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'), + 'days_names', jsonb_build_array('Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (61, + 'SPANISH', + 'SPANISH (MEXICO)', + NULL, + NULL, + 'MEXICO', + 'ES-MX', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'), + 'months_shortnames', jsonb_build_array('Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'), + 'days_names', jsonb_build_array('Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (62, + 'SPANISH', + 'SPANISH (NICARAGUA)', + NULL, + NULL, + 'NICARAGUA', + 'ES-NI', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'), + 'months_shortnames', jsonb_build_array('Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'), + 'days_names', jsonb_build_array('Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (63, + 'SPANISH', + 'SPANISH (PANAMA)', + NULL, + NULL, + 'PANAMA', + 'ES-PA', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'), + 'months_shortnames', jsonb_build_array('Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'), + 'days_names', jsonb_build_array('Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (64, + 'SPANISH', + 'SPANISH (PARAGUAY)', + NULL, + NULL, + 'PARAGUAY', + 'ES-PY', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'), + 'months_shortnames', jsonb_build_array('Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'), + 'days_names', jsonb_build_array('Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (65, + 'SPANISH', + 'SPANISH (PERU)', + NULL, + NULL, + 'PERU', + 'ES-PE', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'), + 'months_shortnames', jsonb_build_array('Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'), + 'days_names', jsonb_build_array('Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (66, + 'SPANISH', + 'SPANISH (PHILIPPINES)', + NULL, + NULL, + 'PHILIPPINES', + 'ES-PH', + jsonb_build_object('date_format', 'MDY', + 'date_first', 1, + 'months_names', jsonb_build_array('Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'), + 'months_shortnames', jsonb_build_array('Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'), + 'days_names', jsonb_build_array('Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (67, + 'SPANISH', + 'SPANISH (PUERTO RICO)', + NULL, + NULL, + 'PUERTO RICO', + 'ES-PR', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'), + 'months_shortnames', jsonb_build_array('Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'), + 'days_names', jsonb_build_array('Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (68, + 'SPANISH', + 'SPANISH (SPAIN)', + 'ESPAÑOL', + 'SPANISH', + 'SPAIN', + 'ES-ES', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'), + 'months_shortnames', jsonb_build_array('Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (69, + 'SPANISH', + 'SPANISH (UNITED STATES)', + NULL, + NULL, + 'UNITED STATES', + 'ES-US', + jsonb_build_object('date_format', 'MDY', + 'date_first', 1, + 'months_names', jsonb_build_array('Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'), + 'months_shortnames', jsonb_build_array('Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'), + 'days_names', jsonb_build_array('Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (70, + 'SPANISH', + 'SPANISH (URUGUAY)', + NULL, + NULL, + 'URUGUAY', + 'ES-UY', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'), + 'months_shortnames', jsonb_build_array('Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'), + 'days_names', jsonb_build_array('Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (71, + 'SPANISH', + 'SPANISH (VENEZUELA)', + NULL, + NULL, + 'VENEZUELA', + 'ES-VE', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'), + 'months_shortnames', jsonb_build_array('Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'), + 'days_names', jsonb_build_array('Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (72, + 'ITALIAN', + 'ITALIAN (ITALY)', + 'ITALIANO', + 'ITALIAN', + 'ITALY', + 'IT-IT', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('gennaio', 'febbraio', 'marzo', 'aprile', 'maggio', 'giugno', 'luglio', 'agosto', 'settembre', 'ottobre', 'novembre', 'dicembre'), + 'months_shortnames', jsonb_build_array('gen', 'feb', 'mar', 'apr', 'mag', 'giu', 'lug', 'ago', 'set', 'ott', 'nov', 'dic'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('lunedì', 'martedì', 'mercoledì', 'giovedì', 'venerdì', 'sabato', 'domenica'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (73, + 'ITALIAN', + 'ITALIAN (SWITZERLAND)', + NULL, + NULL, + 'SWITZERLAND', + 'IT-CH', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('gennaio', 'febbraio', 'marzo', 'aprile', 'maggio', 'giugno', 'luglio', 'agosto', 'settembre', 'ottobre', 'novembre', 'dicembre'), + 'months_shortnames', jsonb_build_array('gen', 'feb', 'mar', 'apr', 'mag', 'giu', 'lug', 'ago', 'set', 'ott', 'nov', 'dic'), + 'days_names', jsonb_build_array('lunedì', 'martedì', 'mercoledì', 'giovedì', 'venerdì', 'sabato', 'domenica'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (74, + 'DUTCH', + 'DUTCH (BELGIUM)', + NULL, + NULL, + 'BELGIUM', + 'NL-BE', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('januari', 'februari', 'maart', 'april', 'mei', 'juni', 'juli', 'augustus', 'september', 'oktober', 'november', 'december'), + 'months_shortnames', jsonb_build_array('jan', 'feb', 'mrt', 'apr', 'mei', 'jun', 'jul', 'aug', 'sep', 'okt', 'nov', 'dec'), + 'days_names', jsonb_build_array('maandag', 'dinsdag', 'woensdag', 'donderdag', 'vrijdag', 'zaterdag', 'zondag'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (75, + 'DUTCH', + 'DUTCH (NETHERLANDS)', + 'NEDERLANDS', + 'DUTCH', + 'NETHERLANDS', + 'NL-NL', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('januari', 'februari', 'maart', 'april', 'mei', 'juni', 'juli', 'augustus', 'september', 'oktober', 'november', 'december'), + 'months_shortnames', jsonb_build_array('jan', 'feb', 'mrt', 'apr', 'mei', 'jun', 'jul', 'aug', 'sep', 'okt', 'nov', 'dec'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('maandag', 'dinsdag', 'woensdag', 'donderdag', 'vrijdag', 'zaterdag', 'zondag'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (76, + 'NORWEGIAN', + 'NORWEGIAN (NORWAY)', + NULL, + NULL, + 'NORWAY', + 'NO-NO', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('januar', 'februar', 'mars', 'april', 'mai', 'juni', 'juli', 'august', 'september', 'oktober', 'november', 'desember'), + 'months_shortnames', jsonb_build_array('jan', 'feb', 'mar', 'apr', 'mai', 'jun', 'jul', 'aug', 'sep', 'okt', 'nov', 'des'), + 'days_names', jsonb_build_array('mandag', 'tirsdag', 'onsdag', 'torsdag', 'fredag', 'lørdag', 'søndag'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (77, + 'NORWEGIAN (MS SQL)', + 'NORWEGIAN NYNORSK (NORWAY)', + 'NORSK', + 'NORWEGIAN', + 'NORWAY', + 'NN-NO', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('januar', 'februar', 'mars', 'april', 'mai', 'juni', 'juli', 'august', 'september', 'oktober', 'november', 'desember'), + 'months_shortnames', jsonb_build_array('jan', 'feb', 'mar', 'apr', 'mai', 'jun', 'jul', 'aug', 'sep', 'okt', 'nov', 'des'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('mandag', 'tirsdag', 'onsdag', 'torsdag', 'fredag', 'lørdag', 'søndag'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (78, + 'PORTUGUESE', + 'PORTUGUESE (BRAZIL)', + 'PORTUGUESE', + 'BRAZILIAN', + 'BRAZIL', + 'PT-BR', + jsonb_build_object('date_format', 'DMY', + 'date_first', 7, + 'months_names', jsonb_build_array('janeiro', 'fevereiro', 'março', 'abril', 'maio', 'junho', 'julho', 'agosto', 'setembro', 'outubro', 'novembro', 'dezembro'), + 'months_shortnames', jsonb_build_array('jan', 'fev', 'mar', 'abr', 'mai', 'jun', 'jul', 'ago', 'set', 'out', 'nov', 'dez'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('segunda-feira', 'terça-feira', 'quarta-feira', 'quinta-feira', 'sexta-feira', 'sábado', 'domingo'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (79, + 'PORTUGUESE', + 'PORTUGUESE (PORTUGAL)', + 'PORTUGUÊS', + 'PORTUGUESE', + 'PORTUGAL', + 'PT-PT', + jsonb_build_object('date_format', 'DMY', + 'date_first', 7, + 'months_names', jsonb_build_array('janeiro', 'fevereiro', 'março', 'abril', 'maio', 'junho', 'julho', 'agosto', 'setembro', 'outubro', 'novembro', 'dezembro'), + 'months_shortnames', jsonb_build_array('jan', 'fev', 'mar', 'abr', 'mai', 'jun', 'jul', 'ago', 'set', 'out', 'nov', 'dez'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('segunda-feira', 'terça-feira', 'quarta-feira', 'quinta-feira', 'sexta-feira', 'sábado', 'domingo'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (80, + 'FINNISH', + 'FINNISH (FINLAND)', + NULL, + NULL, + 'FINLAND', + 'FI-FI', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('tammikuuta', 'helmikuuta', 'maaliskuuta', 'huhtikuuta', 'toukokuuta', 'kesäkuuta', 'heinäkuuta', 'elokuuta', 'syyskuuta', 'lokakuuta', 'marraskuuta', 'joulukuuta'), + 'months_shortnames', jsonb_build_array('tammi', 'helmi', 'maalis', 'huhti', 'touko', 'kesä', 'heinä', 'elo', 'syys', 'loka', 'marras', 'joulu'), + 'days_names', jsonb_build_array('maanantai', 'tiistai', 'keskiviikko', 'torstai', 'perjantai', 'lauantai', 'sunnuntai'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (81, + 'FINNISH (MS SQL)', + 'FINNISH (FINLAND)', + 'SUOMI', + 'FINNISH', + 'FINLAND', + 'FI', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('tammikuuta', 'helmikuuta', 'maaliskuuta', 'huhtikuuta', 'toukokuuta', 'kesäkuuta', 'heinäkuuta', 'elokuuta', 'syyskuuta', 'lokakuuta', 'marraskuuta', 'joulukuuta'), + 'months_shortnames', jsonb_build_array('tammi', 'helmi', 'maalis', 'huhti', 'touko', 'kesä', 'heinä', 'elo', 'syys', 'loka', 'marras', 'joulu'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('maanantai', 'tiistai', 'keskiviikko', 'torstai', 'perjantai', 'lauantai', 'sunnuntai'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (82, + 'SWEDISH', + 'SWEDISH (FINLAND)', + NULL, + NULL, + 'FINLAND', + 'SV-FI', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('januari', 'februari', 'mars', 'april', 'maj', 'juni', 'juli', 'augusti', 'september', 'oktober', 'november', 'december'), + 'months_shortnames', jsonb_build_array('jan', 'feb', 'mar', 'apr', 'maj', 'jun', 'jul', 'aug', 'sep', 'okt', 'nov', 'dec'), + 'days_names', jsonb_build_array('måndag', 'tisdag', 'onsdag', 'torsdag', 'fredag', 'lördag', 'söndag'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (83, + 'SWEDISH', + 'SWEDISH (SWEDEN)', + 'SVENSKA', + 'SWEDISH', + 'SWEDEN', + 'SV-SE', + jsonb_build_object('date_format', 'YMD', + 'date_first', 1, + 'months_names', jsonb_build_array('januari', 'februari', 'mars', 'april', 'maj', 'juni', 'juli', 'augusti', 'september', 'oktober', 'november', 'december'), + 'months_shortnames', jsonb_build_array('jan', 'feb', 'mar', 'apr', 'maj', 'jun', 'jul', 'aug', 'sep', 'okt', 'nov', 'dec'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('måndag', 'tisdag', 'onsdag', 'torsdag', 'fredag', 'lördag', 'söndag'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (84, + 'CZECH', + 'CZECH (CZECH REPUBLIC)', + 'ČEŠTINA', + 'CZECH', + 'CZECHIA', + 'CS-CZ', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('leden', 'únor', 'březen', 'duben', 'květen', 'červen', 'červenec', 'srpen', 'září', 'říjen', 'listopad', 'prosinec'), + 'months_shortnames', jsonb_build_array('I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX', 'X', 'XI', 'XII'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('pondělí', 'úterý', 'středa', 'čtvrtek', 'pátek', 'sobota', 'neděle'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (85, + 'HUNGARIAN', + 'HUNGARIAN (HUNGARY)', + 'MAGYAR', + 'HUNGARIAN', + 'HUNGARY', + 'HU-HU', + jsonb_build_object('date_format', 'YMD', + 'date_first', 1, + 'months_names', jsonb_build_array('január', 'február', 'március', 'április', 'május', 'június', 'július', 'augusztus', 'szeptember', 'október', 'november', 'december'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'days_names', jsonb_build_array('hétfő', 'kedd', 'szerda', 'csütörtök', 'péntek', 'szombat', 'vasárnap'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (86, + 'POLISH', + 'POLISH (POLAND)', + 'POLSKI', + 'POLISH', + 'POLAND', + 'PL-PL', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('styczeń', 'luty', 'marzec', 'kwiecień', 'maj', 'czerwiec', 'lipiec', 'sierpień', 'wrzesień', 'październik', 'listopad', 'grudzień'), + 'months_shortnames', jsonb_build_array('I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX', 'X', 'XI', 'XII'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('poniedziałek', 'wtorek', 'środa', 'czwartek', 'piątek', 'sobota', 'niedziela'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (87, + 'ROMANIAN', + 'ROMANIAN (MOLDOVA)', + NULL, + NULL, + 'MOLDOVA', + 'RO-MD', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('ianuarie', 'februarie', 'martie', 'aprilie', 'mai', 'iunie', 'iulie', 'august', 'septembrie', 'octombrie', 'noiembrie', 'decembrie'), + 'months_shortnames', jsonb_build_array('Ian', 'Feb', 'Mar', 'Apr', 'Mai', 'Iun', 'Iul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('luni', 'marţi', 'miercuri', 'joi', 'vineri', 'sîmbătă', 'duminică'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (88, + 'ROMANIAN', + 'ROMANIAN (ROMANIA)', + 'ROMÂNĂ', + 'ROMANIAN', + 'ROMANIA', + 'RO-RO', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('ianuarie', 'februarie', 'martie', 'aprilie', 'mai', 'iunie', 'iulie', 'august', 'septembrie', 'octombrie', 'noiembrie', 'decembrie'), + 'months_shortnames', jsonb_build_array('Ian', 'Feb', 'Mar', 'Apr', 'Mai', 'Iun', 'Iul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('luni', 'marţi', 'miercuri', 'joi', 'vineri', 'sîmbătă', 'duminică'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (89, + 'CROATIAN', + 'CROATIAN (CROATIA)', + 'HRVATSKI', + 'CROATIAN', + 'CROATIA', + 'HR-HR', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('siječanj', 'veljača', 'ožujak', 'travanj', 'svibanj', 'lipanj', 'srpanj', 'kolovoz', 'rujan', 'listopad', 'studeni', 'prosinac'), + 'months_shortnames', jsonb_build_array('sij', 'vel', 'ožu', 'tra', 'svi', 'lip', 'srp', 'kol', 'ruj', 'lis', 'stu', 'pro'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('ponedjeljak', 'utorak', 'srijeda', 'četvrtak', 'petak', 'subota', 'nedjelja'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (90, + 'SLOVAK', + 'SLOVAK (SLOVAKIA)', + 'SLOVENČINA', + 'SLOVAK', + 'SLOVAKIA', + 'SK-SK', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('január', 'február', 'marec', 'apríl', 'máj', 'jún', 'júl', 'august', 'september', 'október', 'november', 'december'), + 'months_shortnames', jsonb_build_array('I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX', 'X', 'XI', 'XII'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('pondelok', 'utorok', 'streda', 'štvrtok', 'piatok', 'sobota', 'nedeľa'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (91, + 'SLOVENIAN', + 'SLOVENIAN (SLOVENIA)', + 'SLOVENSKI', + 'SLOVENIAN', + 'SLOVENIA', + 'SL-SI', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('januar', 'februar', 'marec', 'april', 'maj', 'junij', 'julij', 'avgust', 'september', 'oktober', 'november', 'december'), + 'months_shortnames', jsonb_build_array('jan', 'feb', 'mar', 'apr', 'maj', 'jun', 'jul', 'avg', 'sept', 'okt', 'nov', 'dec'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('ponedeljek', 'torek', 'sreda', 'četrtek', 'petek', 'sobota', 'nedelja'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (92, + 'GREEK', + 'GREEK (GREECE)', + 'ΕΛΛΗΝΙΚΆ', + 'GREEK', + 'GREECE', + 'EL-GR', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Ιανουαρίου', 'Φεβρουαρίου', 'Μαρτίου', 'Απριλίου', 'Μα_ου', 'Ιουνίου', 'Ιουλίου', 'Αυγούστου', 'Σεπτεμβρίου', 'Οκτωβρίου', 'Νοεμβρίου', 'Δεκεμβρίου'), + 'months_shortnames', jsonb_build_array('Ιαν', 'Φεβ', 'Μαρ', 'Απρ', 'Μαϊ', 'Ιουν', 'Ιουλ', 'Αυγ', 'Σεπ', 'Οκτ', 'Νοε', 'Δεκ'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Δευτέρα', 'Τρίτη', 'Τετάρτη', 'Πέμπτη', 'Παρασκευή', 'Σάββατο', 'Κυριακή'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (93, + 'BULGARIAN', + 'BULGARIAN (BULGARIA)', + 'БЪЛГАРСКИ', + 'BULGARIAN', + 'BULGARIA', + 'BG-BG', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('януари', 'февруари', 'март', 'април', 'май', 'юни', 'юли', 'август', 'септември', 'октомври', 'ноември', 'декември'), + 'months_shortnames', jsonb_build_array('януари', 'февруари', 'март', 'април', 'май', 'юни', 'юли', 'август', 'септември', 'октомври', 'ноември', 'декември'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('понеделник', 'вторник', 'сряда', 'четвъртък', 'петък', 'събота', 'неделя'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (94, + 'RUSSIAN', + 'RUSSIAN (BELARUS)', + NULL, + NULL, + 'BELARUS', + 'RU-BY', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь'), + 'months_shortnames', jsonb_build_array('янв', 'фев', 'мар', 'апр', 'май', 'июн', 'июл', 'авг', 'сен', 'окт', 'ноя', 'дек'), + 'days_names', jsonb_build_array('понедельник', 'вторник', 'среда', 'четверг', 'пятница', 'суббота', 'воскресенье'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (95, + 'RUSSIAN', + 'RUSSIAN (KAZAKHSTAN)', + NULL, + NULL, + 'KAZAKHSTAN', + 'RU-KZ', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь'), + 'months_shortnames', jsonb_build_array('янв', 'фев', 'мар', 'апр', 'май', 'июн', 'июл', 'авг', 'сен', 'окт', 'ноя', 'дек'), + 'days_names', jsonb_build_array('понедельник', 'вторник', 'среда', 'четверг', 'пятница', 'суббота', 'воскресенье'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (96, + 'RUSSIAN', + 'RUSSIAN (KYRGYZSTAN)', + NULL, + NULL, + 'KYRGYZSTAN', + 'RU-KG', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь'), + 'months_shortnames', jsonb_build_array('янв', 'фев', 'мар', 'апр', 'май', 'июн', 'июл', 'авг', 'сен', 'окт', 'ноя', 'дек'), + 'days_names', jsonb_build_array('понедельник', 'вторник', 'среда', 'четверг', 'пятница', 'суббота', 'воскресенье'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (97, + 'RUSSIAN', + 'RUSSIAN (MOLDOVA)', + NULL, + NULL, + 'MOLDOVA', + 'RU-MD', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь'), + 'months_shortnames', jsonb_build_array('янв', 'фев', 'мар', 'апр', 'май', 'июн', 'июл', 'авг', 'сен', 'окт', 'ноя', 'дек'), + 'days_names', jsonb_build_array('понедельник', 'вторник', 'среда', 'четверг', 'пятница', 'суббота', 'воскресенье'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (98, + 'RUSSIAN', + 'RUSSIAN (RUSSIA)', + 'РУССКИЙ', + 'RUSSIAN', + 'RUSSIA', + 'RU-RU', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь'), + 'months_shortnames', jsonb_build_array('янв', 'фев', 'мар', 'апр', 'май', 'июн', 'июл', 'авг', 'сен', 'окт', 'ноя', 'дек'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('понедельник', 'вторник', 'среда', 'четверг', 'пятница', 'суббота', 'воскресенье'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (99, + 'RUSSIAN', + 'RUSSIAN (UKRAINE)', + NULL, + NULL, + 'UKRAINE', + 'RU-UA', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь'), + 'months_shortnames', jsonb_build_array('янв', 'фев', 'мар', 'апр', 'май', 'июн', 'июл', 'авг', 'сен', 'окт', 'ноя', 'дек'), + 'days_names', jsonb_build_array('понедельник', 'вторник', 'среда', 'четверг', 'пятница', 'суббота', 'воскресенье'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (100, + 'TURKISH', + 'TURKISH (TURKEY)', + 'TÜRKÇE', + 'TURKISH', + 'TURKEY', + 'TR-TR', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Ocak', 'Şubat', 'Mart', 'Nisan', 'Mayıs', 'Haziran', 'Temmuz', 'Ağustos', 'Eylül', 'Ekim', 'Kasım', 'Aralık'), + 'months_shortnames', jsonb_build_array('Oca', 'Şub', 'Mar', 'Nis', 'May', 'Haz', 'Tem', 'Ağu', 'Eyl', 'Eki', 'Kas', 'Ara'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Pazartesi', 'Salı', 'Çarşamba', 'Perşembe', 'Cuma', 'Cumartesi', 'Pazar'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (101, + 'ESTONIAN', + 'ESTONIAN (ESTONIA)', + 'EESTI', + 'ESTONIAN', + 'ESTONIA', + 'ET-EE', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('jaanuar', 'veebruar', 'märts', 'aprill', 'mai', 'juuni', 'juuli', 'august', 'september', 'oktoober', 'november', 'detsember'), + 'months_shortnames', jsonb_build_array('jaan', 'veebr', 'märts', 'apr', 'mai', 'juuni', 'juuli', 'aug', 'sept', 'okt', 'nov', 'dets'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('esmaspäev', 'teisipäev', 'kolmapäev', 'neljapäev', 'reede', 'laupäev', 'pühapäev'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (102, + 'LATVIAN', + 'LATVIAN (LATVIA)', + 'LATVIEŠU', + 'LATVIAN', + 'LATVIA', + 'LV-LV', + jsonb_build_object('date_format', 'YMD', + 'date_first', 1, + 'months_names', jsonb_build_array('janvāris', 'februāris', 'marts', 'aprīlis', 'maijs', 'jūnijs', 'jūlijs', 'augusts', 'septembris', 'oktobris', 'novembris', 'decembris'), + 'months_shortnames', jsonb_build_array('jan', 'feb', 'mar', 'apr', 'mai', 'jūn', 'jūl', 'aug', 'sep', 'okt', 'nov', 'dec'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('pirmdiena', 'otrdiena', 'trešdiena', 'ceturtdiena', 'piektdiena', 'sestdiena', 'svētdiena'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (103, + 'LITHUANIAN', + 'LITHUANIAN (LITHUANIA)', + 'LIETUVIŲ', + 'LITHUANIAN', + 'LITHUANIA', + 'LT-LT', + jsonb_build_object('date_format', 'YMD', + 'date_first', 1, + 'months_names', jsonb_build_array('sausis', 'vasaris', 'kovas', 'balandis', 'gegužė', 'birželis', 'liepa', 'rugpjūtis', 'rugsėjis', 'spalis', 'lapkritis', 'gruodis'), + 'months_shortnames', jsonb_build_array('sau', 'vas', 'kov', 'bal', 'geg', 'bir', 'lie', 'rgp', 'rgs', 'spl', 'lap', 'grd'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('pirmadienis', 'antradienis', 'trečiadienis', 'ketvirtadienis', 'penktadienis', 'šeštadienis', 'sekmadienis'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (104, + 'CHINESE (TRADITIONAL)', + 'CHINESE (TRADITIONAL, CHINA)', + '繁體中文', + 'TRADITIONAL CHINESE', + 'CHINA', + 'ZH-TW', + jsonb_build_object('date_format', 'YMD', + 'date_first', 7, + 'months_names', jsonb_build_array('一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'), + 'months_shortnames', jsonb_build_array('01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期日'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (105, + 'KOREAN', + 'KOREAN (NORTH KOREA)', + NULL, + NULL, + 'NORTH KOREA', + 'KO-KP', + jsonb_build_object('date_format', 'YMD', + 'date_first', 7, + 'months_names', jsonb_build_array('01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'), + 'months_shortnames', jsonb_build_array('01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'), + 'days_names', jsonb_build_array('월요일', '화요일', '수요일', '목요일', '금요일', '토요일', '일요일'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (106, + 'KOREAN', + 'KOREAN (SOUTH KOREA)', + '한국어', + 'KOREAN', + 'KOREA', + 'KO-KR', + jsonb_build_object('date_format', 'YMD', + 'date_first', 7, + 'months_names', jsonb_build_array('01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'), + 'months_shortnames', jsonb_build_array('01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('월요일', '화요일', '수요일', '목요일', '금요일', '토요일', '일요일'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (107, + 'CHINESE (SIMPLIFIED)', + 'CHINESE (SIMPLIFIED, CHINA)', + '简体中文', + 'SIMPLIFIED CHINESE', + 'CHINA', + 'ZH-CN', + jsonb_build_object('date_format', 'YMD', + 'date_first', 7, + 'months_names', jsonb_build_array('01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'), + 'months_shortnames', jsonb_build_array('01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期日'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (108, + 'ARABIC (MS SQL)', + 'ARABIC (ARABIC)', + 'GENERAL ARABIC', + 'GENERAL ARABIC', + 'ARABIC', + 'AR', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Muharram', 'Safar', 'Rabie I', 'Rabie II', 'Jumada I', 'Jumada II', 'Rajab', 'Shaaban', 'Ramadan', 'Shawwal', 'Thou Alqadah', 'Thou Alhajja'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (109, + 'ARABIC', + 'ARABIC (ALGERIA)', + NULL, + NULL, + 'ALGERIA', + 'AR-DZ', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Muharram', 'Safar', 'Rabie I', 'Rabie II', 'Jumada I', 'Jumada II', 'Rajab', 'Shaaban', 'Ramadan', 'Shawwal', 'Thou Alqadah', 'Thou Alhajja'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (110, + 'ARABIC', + 'ARABIC (BAHRAIN)', + NULL, + NULL, + 'BAHRAIN', + 'AR-BH', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Muharram', 'Safar', 'Rabie I', 'Rabie II', 'Jumada I', 'Jumada II', 'Rajab', 'Shaaban', 'Ramadan', 'Shawwal', 'Thou Alqadah', 'Thou Alhajja'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (111, + 'ARABIC', + 'ARABIC (EGYPT)', + NULL, + NULL, + 'EGYPT', + 'AR-EG', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Muharram', 'Safar', 'Rabie I', 'Rabie II', 'Jumada I', 'Jumada II', 'Rajab', 'Shaaban', 'Ramadan', 'Shawwal', 'Thou Alqadah', 'Thou Alhajja'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (112, + 'ARABIC', + 'ARABIC (ERITREA)', + NULL, + NULL, + 'ERITREA', + 'AR-ER', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Muharram', 'Safar', 'Rabie I', 'Rabie II', 'Jumada I', 'Jumada II', 'Rajab', 'Shaaban', 'Ramadan', 'Shawwal', 'Thou Alqadah', 'Thou Alhajja'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (113, + 'ARABIC', + 'ARABIC (IRAQ)', + NULL, + NULL, + 'IRAQ', + 'AR-IQ', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Muharram', 'Safar', 'Rabie I', 'Rabie II', 'Jumada I', 'Jumada II', 'Rajab', 'Shaaban', 'Ramadan', 'Shawwal', 'Thou Alqadah', 'Thou Alhajja'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (114, + 'ARABIC', + 'ARABIC (ISRAEL)', + NULL, + NULL, + 'ISRAEL', + 'AR-IL', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Muharram', 'Safar', 'Rabie I', 'Rabie II', 'Jumada I', 'Jumada II', 'Rajab', 'Shaaban', 'Ramadan', 'Shawwal', 'Thou Alqadah', 'Thou Alhajja'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (115, + 'ARABIC', + 'ARABIC (JORDAN)', + NULL, + NULL, + 'JORDAN', + 'AR-JO', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Muharram', 'Safar', 'Rabie I', 'Rabie II', 'Jumada I', 'Jumada II', 'Rajab', 'Shaaban', 'Ramadan', 'Shawwal', 'Thou Alqadah', 'Thou Alhajja'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (116, + 'ARABIC', + 'ARABIC (KUWAIT)', + NULL, + NULL, + 'KUWAIT', + 'AR-KW', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Muharram', 'Safar', 'Rabie I', 'Rabie II', 'Jumada I', 'Jumada II', 'Rajab', 'Shaaban', 'Ramadan', 'Shawwal', 'Thou Alqadah', 'Thou Alhajja'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (117, + 'ARABIC', + 'ARABIC (LEBANON)', + NULL, + NULL, + 'LEBANON', + 'AR-LB', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Muharram', 'Safar', 'Rabie I', 'Rabie II', 'Jumada I', 'Jumada II', 'Rajab', 'Shaaban', 'Ramadan', 'Shawwal', 'Thou Alqadah', 'Thou Alhajja'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (118, + 'ARABIC', + 'ARABIC (LIBYA)', + NULL, + NULL, + 'LIBYA', + 'AR-LY', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Muharram', 'Safar', 'Rabie I', 'Rabie II', 'Jumada I', 'Jumada II', 'Rajab', 'Shaaban', 'Ramadan', 'Shawwal', 'Thou Alqadah', 'Thou Alhajja'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (119, + 'ARABIC', + 'ARABIC (MOROCCO)', + NULL, + NULL, + 'MOROCCO', + 'AR-MA', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Muharram', 'Safar', 'Rabie I', 'Rabie II', 'Jumada I', 'Jumada II', 'Rajab', 'Shaaban', 'Ramadan', 'Shawwal', 'Thou Alqadah', 'Thou Alhajja'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (120, + 'ARABIC', + 'ARABIC (OMAN)', + NULL, + NULL, + 'OMAN', + 'AR-OM', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Muharram', 'Safar', 'Rabie I', 'Rabie II', 'Jumada I', 'Jumada II', 'Rajab', 'Shaaban', 'Ramadan', 'Shawwal', 'Thou Alqadah', 'Thou Alhajja'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (121, + 'ARABIC', + 'ARABIC (QATAR)', + NULL, + NULL, + 'QATAR', + 'AR-QA', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Muharram', 'Safar', 'Rabie I', 'Rabie II', 'Jumada I', 'Jumada II', 'Rajab', 'Shaaban', 'Ramadan', 'Shawwal', 'Thou Alqadah', 'Thou Alhajja'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (122, + 'ARABIC', + 'ARABIC (SAUDI ARABIA)', + 'ARABIC', + 'ARABIC', + 'SAUDI ARABIA', + 'AR-SA', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Muharram', 'Safar', 'Rabie I', 'Rabie II', 'Jumada I', 'Jumada II', 'Rajab', 'Shaaban', 'Ramadan', 'Shawwal', 'Thou Alqadah', 'Thou Alhajja'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (123, + 'ARABIC', + 'ARABIC (SOMALIA)', + NULL, + NULL, + 'SOMALIA', + 'AR-SO', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Muharram', 'Safar', 'Rabie I', 'Rabie II', 'Jumada I', 'Jumada II', 'Rajab', 'Shaaban', 'Ramadan', 'Shawwal', 'Thou Alqadah', 'Thou Alhajja'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (124, + 'ARABIC', + 'ARABIC (SYRIA)', + NULL, + NULL, + 'SYRIA', + 'AR-SY', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Muharram', 'Safar', 'Rabie I', 'Rabie II', 'Jumada I', 'Jumada II', 'Rajab', 'Shaaban', 'Ramadan', 'Shawwal', 'Thou Alqadah', 'Thou Alhajja'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (125, + 'ARABIC', + 'ARABIC (TUNISIA)', + NULL, + NULL, + 'TUNISIA', + 'AR-TN', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Muharram', 'Safar', 'Rabie I', 'Rabie II', 'Jumada I', 'Jumada II', 'Rajab', 'Shaaban', 'Ramadan', 'Shawwal', 'Thou Alqadah', 'Thou Alhajja'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (126, + 'ARABIC', + 'ARABIC (UNITED ARAB EMIRATES)', + NULL, + NULL, + 'UNITED ARAB EMIRATES', + 'AR-AE', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Muharram', 'Safar', 'Rabie I', 'Rabie II', 'Jumada I', 'Jumada II', 'Rajab', 'Shaaban', 'Ramadan', 'Shawwal', 'Thou Alqadah', 'Thou Alhajja'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (127, + 'ARABIC', + 'ARABIC (YEMEN)', + NULL, + NULL, + 'YEMEN', + 'AR-YE', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Muharram', 'Safar', 'Rabie I', 'Rabie II', 'Jumada I', 'Jumada II', 'Rajab', 'Shaaban', 'Ramadan', 'Shawwal', 'Thou Alqadah', 'Thou Alhajja'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (128, + 'THAI', + 'THAI (THAILAND)', + 'ไทย', + 'THAI', + 'THAILAND', + 'TH-TH', + jsonb_build_object('date_format', 'DMY', + 'date_first', 7, + 'months_names', jsonb_build_array('มกราคม', 'กุมภาพันธ์', 'มีนาคม', 'เมษายน', 'พฤษภาคม', 'มิถุนายน', 'กรกฎาคม', 'สิงหาคม', 'กันยายน', 'ตุลาคม', 'พฤศจิกายน', 'ธันวาคม'), + 'months_shortnames', jsonb_build_array('ม.ค.', 'ก.พ.', 'มี.ค.', 'เม.ย.', 'พ.ค.', 'มิ.ย.', 'ก.ค.', 'ส.ค.', 'ก.ย.', 'ต.ค.', 'พ.ย.', 'ธ.ค.'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('จันทร์', 'อังคาร', 'พุธ', 'พฤหัสบดี', 'ศุกร์', 'เสาร์', 'อาทิตย์'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (129, + 'HIJRI', + 'HIJRI (ISLAMIC)', + 'HIJRI', + 'ISLAMIC', + 'ISLAMIC', + 'HI-IS', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('محرم', 'صفر', 'ربيع الاول', 'ربيع الثاني', 'جمادى الاولى', 'جمادى الثانية', 'رجب', 'شعبان', 'رمضان', 'شوال', 'ذو القعدة', 'ذو الحجة'), + 'months_shortnames', jsonb_build_array('محرم', 'صفر', 'ربيع الاول', 'ربيع الثاني', 'جمادى الاولى', 'جمادى الثانية', 'رجب', 'شعبان', 'رمضان', 'شوال', 'ذو القعدة', 'ذو الحجة'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); +-- 11 "sql/babelfishpg_tsql.in" 2 +-- 1 "sql/sys_function_helpers.sql" 1 + + + +CREATE OR REPLACE FUNCTION sys.babelfish_get_last_identity() +RETURNS INT8 +AS 'babelfishpg_tsql', 'get_last_identity' +LANGUAGE C; + +CREATE OR REPLACE FUNCTION sys.bbf_get_current_physical_schema_name(IN schemaname TEXT) +RETURNS TEXT +AS 'babelfishpg_tsql', 'get_current_physical_schema_name' +LANGUAGE C STABLE STRICT; + +CREATE OR REPLACE FUNCTION sys.babelfish_set_role(IN role_name TEXT) +RETURNS INT4 +AS 'babelfishpg_tsql', 'babelfish_set_role' +LANGUAGE C STRICT; + +CREATE OR REPLACE FUNCTION sys.babelfish_get_last_identity_numeric() +RETURNS numeric(38,0) AS +$BODY$ + SELECT sys.babelfish_get_last_identity()::numeric(38,0); +$BODY$ +LANGUAGE SQL; + +CREATE OR REPLACE FUNCTION sys.get_min_id_from_table(IN id_colname TEXT, + IN schemaname TEXT, + IN tablename TEXT, + OUT result INT8) +AS +$BODY$ +BEGIN + EXECUTE FORMAT('SELECT MIN(%I) FROM %I.%I', id_colname, schemaname, tablename) INTO result; +END +$BODY$ +LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION sys.get_max_id_from_table(IN id_colname TEXT, + IN schemaname TEXT, + IN tablename TEXT, + OUT result INT8) +AS +$BODY$ +BEGIN + EXECUTE FORMAT('SELECT MAX(%I) FROM %I.%I', id_colname, schemaname, tablename) INTO result; +END +$BODY$ +LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION sys.user_name_sysname() +RETURNS sys.SYSNAME AS +$BODY$ + SELECT COALESCE(sys.user_name(), ''); +$BODY$ +LANGUAGE SQL; + +CREATE OR REPLACE FUNCTION sys.babelfish_get_identity_param(IN tablename TEXT, IN optionname TEXT) +RETURNS INT8 +AS 'babelfishpg_tsql', 'get_identity_param' +LANGUAGE C STRICT; + +CREATE OR REPLACE FUNCTION sys.babelfish_get_identity_current(IN tablename TEXT) +RETURNS INT8 +AS 'babelfishpg_tsql', 'get_identity_current' +LANGUAGE C STRICT; + +create or replace function sys.babelfish_get_id_by_name(object_name text) +returns bigint as +$BODY$ +declare res bigint; +begin + execute 'select x''' || substring(encode(digest(object_name, 'sha1'), 'hex'), 1, 8) || '''::bigint' into res; + return res; +end; +$BODY$ +language plpgsql returns null on null input; + +create or replace function sys.babelfish_get_sequence_value(in sequence_name character varying) +returns bigint as +$BODY$ +declare + v_res bigint; +begin + execute 'select last_value from '|| sequence_name into v_res; + return v_res; +end; +$BODY$ +language plpgsql returns null on null input; + +CREATE OR REPLACE FUNCTION sys.babelfish_get_login_default_db(IN login_name TEXT) +RETURNS TEXT +AS 'babelfishpg_tsql', 'bbf_get_login_default_db' +LANGUAGE C STRICT; + +CREATE OR REPLACE FUNCTION sys.babelfish_conv_date_to_string(IN p_datatype TEXT, + IN p_dateval DATE, + IN p_style NUMERIC DEFAULT 20) +RETURNS TEXT +AS +$BODY$ +DECLARE + v_day VARCHAR; + v_dateval DATE; + v_style SMALLINT; + v_month SMALLINT; + v_resmask VARCHAR; + v_datatype VARCHAR; + v_language VARCHAR; + v_monthname VARCHAR; + v_resstring VARCHAR; + v_lengthexpr VARCHAR; + v_maxlength SMALLINT; + v_res_length SMALLINT; + v_err_message VARCHAR; + v_res_datatype VARCHAR; + v_lang_metadata_json JSONB; + VARCHAR_MAX CONSTANT SMALLINT := 8000; + NVARCHAR_MAX CONSTANT SMALLINT := 4000; + CONVERSION_LANG CONSTANT VARCHAR := ''; + DATATYPE_REGEXP CONSTANT VARCHAR := '^\s*(CHAR|NCHAR|VARCHAR|NVARCHAR|CHARACTER VARYING)\s*$'; + DATATYPE_MASK_REGEXP CONSTANT VARCHAR := '^\s*(?:CHAR|NCHAR|VARCHAR|NVARCHAR|CHARACTER VARYING)\s*\(\s*(\d+|MAX)\s*\)\s*$'; +BEGIN + v_datatype := upper(trim(p_datatype)); + v_style := floor(p_style)::SMALLINT; + + IF (scale(p_style) > 0) THEN + RAISE most_specific_type_mismatch; + ELSIF (NOT ((v_style BETWEEN 0 AND 13) OR + (v_style BETWEEN 20 AND 25) OR + (v_style BETWEEN 100 AND 113) OR + v_style IN (120, 121, 126, 127, 130, 131))) + THEN + RAISE invalid_parameter_value; + ELSIF (v_style IN (8, 24, 108)) THEN + RAISE invalid_datetime_format; + END IF; + + IF (v_datatype ~* DATATYPE_MASK_REGEXP) THEN + v_res_datatype := rtrim(split_part(v_datatype, '(', 1)); + + v_maxlength := CASE + WHEN (v_res_datatype IN ('CHAR', 'VARCHAR')) THEN VARCHAR_MAX + ELSE NVARCHAR_MAX + END; + + v_lengthexpr := substring(v_datatype, DATATYPE_MASK_REGEXP); + + IF (v_lengthexpr <> 'MAX' AND char_length(v_lengthexpr) > 4) THEN + RAISE interval_field_overflow; + END IF; + + v_res_length := CASE v_lengthexpr + WHEN 'MAX' THEN v_maxlength + ELSE v_lengthexpr::SMALLINT + END; + ELSIF (v_datatype ~* DATATYPE_REGEXP) THEN + v_res_datatype := v_datatype; + ELSE + RAISE datatype_mismatch; + END IF; + + v_dateval := CASE + WHEN (v_style NOT IN (130, 131)) THEN p_dateval + ELSE sys.babelfish_conv_greg_to_hijri(p_dateval) + 1 + END; + + v_day := ltrim(to_char(v_dateval, 'DD'), '0'); + v_month := to_char(v_dateval, 'MM')::SMALLINT; + + v_language := CASE + WHEN (v_style IN (130, 131)) THEN 'HIJRI' + ELSE CONVERSION_LANG + END; + BEGIN + v_lang_metadata_json := sys.babelfish_get_lang_metadata_json(v_language); + EXCEPTION + WHEN OTHERS THEN + RAISE invalid_character_value_for_cast; + END; + + v_monthname := (v_lang_metadata_json -> 'months_shortnames') ->> v_month - 1; + + v_resmask := CASE + WHEN (v_style IN (1, 22)) THEN 'MM/DD/YY' + WHEN (v_style = 101) THEN 'MM/DD/YYYY' + WHEN (v_style = 2) THEN 'YY.MM.DD' + WHEN (v_style = 102) THEN 'YYYY.MM.DD' + WHEN (v_style = 3) THEN 'DD/MM/YY' + WHEN (v_style = 103) THEN 'DD/MM/YYYY' + WHEN (v_style = 4) THEN 'DD.MM.YY' + WHEN (v_style = 104) THEN 'DD.MM.YYYY' + WHEN (v_style = 5) THEN 'DD-MM-YY' + WHEN (v_style = 105) THEN 'DD-MM-YYYY' + WHEN (v_style = 6) THEN 'DD $mnme$ YY' + WHEN (v_style IN (13, 106, 113)) THEN 'DD $mnme$ YYYY' + WHEN (v_style = 7) THEN '$mnme$ DD, YY' + WHEN (v_style = 107) THEN '$mnme$ DD, YYYY' + WHEN (v_style = 10) THEN 'MM-DD-YY' + WHEN (v_style = 110) THEN 'MM-DD-YYYY' + WHEN (v_style = 11) THEN 'YY/MM/DD' + WHEN (v_style = 111) THEN 'YYYY/MM/DD' + WHEN (v_style = 12) THEN 'YYMMDD' + WHEN (v_style = 112) THEN 'YYYYMMDD' + WHEN (v_style IN (20, 21, 23, 25, 120, 121, 126, 127)) THEN 'YYYY-MM-DD' + WHEN (v_style = 130) THEN 'DD $mnme$ YYYY' + WHEN (v_style = 131) THEN format('%s/MM/YYYY', lpad(v_day, 2, ' ')) + WHEN (v_style IN (0, 9, 100, 109)) THEN format('$mnme$ %s YYYY', lpad(v_day, 2, ' ')) + END; + + v_resstring := to_char(v_dateval, v_resmask); + v_resstring := replace(v_resstring, '$mnme$', v_monthname); + + v_resstring := substring(v_resstring, 1, coalesce(v_res_length, char_length(v_resstring))); + v_res_length := coalesce(v_res_length, + CASE v_res_datatype + WHEN 'CHAR' THEN 30 + ELSE 60 + END); + RETURN CASE + WHEN (v_res_datatype NOT IN ('CHAR', 'NCHAR')) THEN v_resstring + ELSE rpad(v_resstring, v_res_length, ' ') + END; +EXCEPTION + WHEN most_specific_type_mismatch THEN + RAISE USING MESSAGE := 'Argument data type NUMERIC is invalid for argument 3 of convert 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 := format('%s is not a valid style number when converting from DATE to a character string.', v_style), + DETAIL := 'Use of incorrect "style" parameter value during conversion process.', + HINT := 'Change "style" parameter to the proper value and try again.'; + + WHEN invalid_datetime_format THEN + RAISE USING MESSAGE := format('Error converting data type DATE to %s.', trim(p_datatype)), + 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 interval_field_overflow THEN + RAISE USING MESSAGE := format('The size (%s) given to the convert specification ''%s'' exceeds the maximum allowed for any data type (%s).', + v_lengthexpr, + lower(v_res_datatype), + v_maxlength), + DETAIL := 'Use of incorrect size value of data type parameter during conversion process.', + HINT := 'Change size component of data type parameter to the allowable value and try again.'; + + WHEN datatype_mismatch THEN + RAISE USING MESSAGE := 'Data type should be one of these values: ''CHAR(n|MAX)'', ''NCHAR(n|MAX)'', ''VARCHAR(n|MAX)'', ''NVARCHAR(n|MAX)''.', + DETAIL := 'Use of incorrect "datatype" parameter value during conversion process.', + HINT := 'Change "datatype" parameter to the proper value and try again.'; + + WHEN invalid_character_value_for_cast THEN + RAISE USING MESSAGE := 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 := format('Error while trying to convert "%s" value to SMALLINT (or INTEGER) data type.', + v_err_message), + DETAIL := 'Supplied value contains illegal characters.', + HINT := 'Correct supplied value, remove all illegal characters.'; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_conv_datetime_to_string(IN p_datatype TEXT, + IN p_src_datatype TEXT, + IN p_datetimeval TIMESTAMP(6) WITHOUT TIME ZONE, + IN p_style NUMERIC DEFAULT -1) +RETURNS TEXT +AS +$BODY$ +DECLARE + v_day VARCHAR; + v_hour VARCHAR; + v_month SMALLINT; + v_style SMALLINT; + v_scale SMALLINT; + v_resmask VARCHAR; + v_language VARCHAR; + v_datatype VARCHAR; + v_fseconds VARCHAR; + v_fractsep VARCHAR; + v_monthname VARCHAR; + v_resstring VARCHAR; + v_lengthexpr VARCHAR; + v_maxlength SMALLINT; + v_res_length SMALLINT; + v_err_message VARCHAR; + v_src_datatype VARCHAR; + v_res_datatype VARCHAR; + v_lang_metadata_json JSONB; + VARCHAR_MAX CONSTANT SMALLINT := 8000; + NVARCHAR_MAX CONSTANT SMALLINT := 4000; + CONVERSION_LANG CONSTANT VARCHAR := ''; + DATATYPE_REGEXP CONSTANT VARCHAR := '^\s*(CHAR|NCHAR|VARCHAR|NVARCHAR|CHARACTER VARYING)\s*$'; + SRCDATATYPE_MASK_REGEXP VARCHAR := '^(?:DATETIME|SMALLDATETIME|DATETIME2)\s*(?:\s*\(\s*(\d+)\s*\)\s*)?$'; + DATATYPE_MASK_REGEXP CONSTANT VARCHAR := '^\s*(?:CHAR|NCHAR|VARCHAR|NVARCHAR|CHARACTER VARYING)\s*\(\s*(\d+|MAX)\s*\)\s*$'; + v_datetimeval TIMESTAMP(6) WITHOUT TIME ZONE; +BEGIN + v_datatype := upper(trim(p_datatype)); + v_src_datatype := upper(trim(p_src_datatype)); + v_style := floor(p_style)::SMALLINT; + + IF (v_src_datatype ~* SRCDATATYPE_MASK_REGEXP) + THEN + v_scale := substring(v_src_datatype, SRCDATATYPE_MASK_REGEXP)::SMALLINT; + + v_src_datatype := rtrim(split_part(v_src_datatype, '(', 1)); + + IF (v_src_datatype <> 'DATETIME2' AND v_scale IS NOT NULL) THEN + RAISE invalid_indicator_parameter_value; + ELSIF (v_scale NOT BETWEEN 0 AND 7) THEN + RAISE invalid_regular_expression; + END IF; + + v_scale := coalesce(v_scale, 7); + ELSE + RAISE most_specific_type_mismatch; + END IF; + + IF (scale(p_style) > 0) THEN + RAISE escape_character_conflict; + 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 (-1, 120, 121, 126, 127, 130, 131))) + THEN + RAISE invalid_parameter_value; + END IF; + + IF (v_datatype ~* DATATYPE_MASK_REGEXP) THEN + v_res_datatype := rtrim(split_part(v_datatype, '(', 1)); + + v_maxlength := CASE + WHEN (v_res_datatype IN ('CHAR', 'VARCHAR')) THEN VARCHAR_MAX + ELSE NVARCHAR_MAX + END; + + v_lengthexpr := substring(v_datatype, DATATYPE_MASK_REGEXP); + + IF (v_lengthexpr <> 'MAX' AND char_length(v_lengthexpr) > 4) + THEN + RAISE interval_field_overflow; + END IF; + + v_res_length := CASE v_lengthexpr + WHEN 'MAX' THEN v_maxlength + ELSE v_lengthexpr::SMALLINT + END; + ELSIF (v_datatype ~* DATATYPE_REGEXP) THEN + v_res_datatype := v_datatype; + ELSE + RAISE datatype_mismatch; + END IF; + + v_datetimeval := CASE + WHEN (v_style NOT IN (130, 131)) THEN p_datetimeval + ELSE sys.babelfish_conv_greg_to_hijri(p_datetimeval) + INTERVAL '1 day' + END; + + v_day := ltrim(to_char(v_datetimeval, 'DD'), '0'); + v_hour := ltrim(to_char(v_datetimeval, 'HH12'), '0'); + v_month := to_char(v_datetimeval, 'MM')::SMALLINT; + + v_language := CASE + WHEN (v_style IN (130, 131)) THEN 'HIJRI' + ELSE CONVERSION_LANG + END; + BEGIN + v_lang_metadata_json := sys.babelfish_get_lang_metadata_json(v_language); + EXCEPTION + WHEN OTHERS THEN + RAISE invalid_character_value_for_cast; + END; + + v_monthname := (v_lang_metadata_json -> 'months_shortnames') ->> v_month - 1; + + IF (v_src_datatype IN ('DATETIME', 'SMALLDATETIME')) THEN + v_fseconds := sys.babelfish_round_fractseconds(to_char(v_datetimeval, 'MS')); + + IF (v_fseconds::INTEGER = 1000) THEN + v_fseconds := '000'; + v_datetimeval := v_datetimeval + INTERVAL '1 second'; + ELSE + v_fseconds := lpad(v_fseconds, 3, '0'); + END IF; + ELSE + v_fseconds := sys.babelfish_get_microsecs_from_fractsecs(to_char(v_datetimeval, 'US'), v_scale); + + IF (v_scale = 7) THEN + v_fseconds := concat(v_fseconds, '0'); + END IF; + END IF; + + v_fractsep := CASE v_src_datatype + WHEN 'DATETIME2' THEN '.' + ELSE ':' + END; + + IF ((v_style = -1 AND v_src_datatype <> 'DATETIME2') OR + v_style IN (0, 9, 100, 109)) + THEN + v_resmask := format('$mnme$ %s YYYY %s:MI%s', + lpad(v_day, 2, ' '), + lpad(v_hour, 2, ' '), + CASE + WHEN (v_style IN (-1, 0, 100)) THEN 'AM' + ELSE format(':SS:%sAM', v_fseconds) + END); + ELSIF (v_style = 1) THEN + v_resmask := 'MM/DD/YY'; + ELSIF (v_style = 101) THEN + v_resmask := 'MM/DD/YYYY'; + ELSIF (v_style = 2) THEN + v_resmask := 'YY.MM.DD'; + ELSIF (v_style = 102) THEN + v_resmask := 'YYYY.MM.DD'; + ELSIF (v_style = 3) THEN + v_resmask := 'DD/MM/YY'; + ELSIF (v_style = 103) THEN + v_resmask := 'DD/MM/YYYY'; + ELSIF (v_style = 4) THEN + v_resmask := 'DD.MM.YY'; + ELSIF (v_style = 104) THEN + v_resmask := 'DD.MM.YYYY'; + ELSIF (v_style = 5) THEN + v_resmask := 'DD-MM-YY'; + ELSIF (v_style = 105) THEN + v_resmask := 'DD-MM-YYYY'; + ELSIF (v_style = 6) THEN + v_resmask := 'DD $mnme$ YY'; + ELSIF (v_style = 106) THEN + v_resmask := 'DD $mnme$ YYYY'; + ELSIF (v_style = 7) THEN + v_resmask := '$mnme$ DD, YY'; + ELSIF (v_style = 107) THEN + v_resmask := '$mnme$ DD, YYYY'; + ELSIF (v_style IN (8, 24, 108)) THEN + v_resmask := 'HH24:MI:SS'; + ELSIF (v_style = 10) THEN + v_resmask := 'MM-DD-YY'; + ELSIF (v_style = 110) THEN + v_resmask := 'MM-DD-YYYY'; + ELSIF (v_style = 11) THEN + v_resmask := 'YY/MM/DD'; + ELSIF (v_style = 111) THEN + v_resmask := 'YYYY/MM/DD'; + ELSIF (v_style = 12) THEN + v_resmask := 'YYMMDD'; + ELSIF (v_style = 112) THEN + v_resmask := 'YYYYMMDD'; + ELSIF (v_style IN (13, 113)) THEN + v_resmask := format('DD $mnme$ YYYY HH24:MI:SS%s%s', v_fractsep, v_fseconds); + ELSIF (v_style IN (14, 114)) THEN + v_resmask := format('HH24:MI:SS%s%s', v_fractsep, v_fseconds); + ELSIF (v_style IN (20, 120)) THEN + v_resmask := 'YYYY-MM-DD HH24:MI:SS'; + ELSIF ((v_style = -1 AND v_src_datatype = 'DATETIME2') OR + v_style IN (21, 25, 121)) + THEN + v_resmask := format('YYYY-MM-DD HH24:MI:SS.%s', v_fseconds); + ELSIF (v_style = 22) THEN + v_resmask := format('MM/DD/YY %s:MI:SS AM', lpad(v_hour, 2, ' ')); + ELSIF (v_style = 23) THEN + v_resmask := 'YYYY-MM-DD'; + ELSIF (v_style IN (126, 127)) THEN + v_resmask := CASE v_src_datatype + WHEN 'SMALLDATETIME' THEN 'YYYY-MM-DDT$rem$HH24:MI:SS' + ELSE format('YYYY-MM-DDT$rem$HH24:MI:SS.%s', v_fseconds) + END; + ELSIF (v_style IN (130, 131)) THEN + v_resmask := concat(CASE p_style + WHEN 131 THEN format('%s/MM/YYYY ', lpad(v_day, 2, ' ')) + ELSE format('%s $mnme$ YYYY ', lpad(v_day, 2, ' ')) + END, + format('%s:MI:SS%s%sAM', lpad(v_hour, 2, ' '), v_fractsep, v_fseconds)); + END IF; + + v_resstring := to_char(v_datetimeval, v_resmask); + v_resstring := replace(v_resstring, '$mnme$', v_monthname); + v_resstring := replace(v_resstring, '$rem$', ''); + + v_resstring := substring(v_resstring, 1, coalesce(v_res_length, char_length(v_resstring))); + v_res_length := coalesce(v_res_length, + CASE v_res_datatype + WHEN 'CHAR' THEN 30 + ELSE 60 + END); + RETURN CASE + WHEN (v_res_datatype NOT IN ('CHAR', 'NCHAR')) THEN v_resstring + ELSE rpad(v_resstring, v_res_length, ' ') + END; +EXCEPTION + WHEN most_specific_type_mismatch THEN + RAISE USING MESSAGE := 'Source data type should be one of these values: ''DATETIME'', ''SMALLDATETIME'', ''DATETIME2'' or ''DATETIME2(n)''.', + DETAIL := 'Use of incorrect "src_datatype" parameter value during conversion process.', + HINT := 'Change "srcdatatype" parameter to the proper value and try again.'; + + WHEN invalid_regular_expression THEN + RAISE USING MESSAGE := format('The source data type scale (%s) given to the convert specification exceeds the maximum allowable value (7).', + v_scale), + DETAIL := 'Use of incorrect scale value of source data type parameter during conversion process.', + HINT := 'Change scale component of source data type parameter to the allowable value and try again.'; + + WHEN invalid_indicator_parameter_value THEN + RAISE USING MESSAGE := format('Invalid attributes specified for data type %s.', v_src_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 escape_character_conflict THEN + RAISE USING MESSAGE := 'Argument data type NUMERIC is invalid for argument 4 of convert 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 := format('%s is not a valid style number when converting from %s to a character string.', + v_style, v_src_datatype), + DETAIL := 'Use of incorrect "style" parameter value during conversion process.', + HINT := 'Change "style" parameter to the proper value and try again.'; + + WHEN interval_field_overflow THEN + RAISE USING MESSAGE := format('The size (%s) given to the convert specification ''%s'' exceeds the maximum allowed for any data type (%s).', + v_lengthexpr, lower(v_res_datatype), v_maxlength), + DETAIL := 'Use of incorrect size value of data type parameter during conversion process.', + HINT := 'Change size component of data type parameter to the allowable value and try again.'; + + WHEN datatype_mismatch THEN + RAISE USING MESSAGE := 'Data type should be one of these values: ''CHAR(n|MAX)'', ''NCHAR(n|MAX)'', ''VARCHAR(n|MAX)'', ''NVARCHAR(n|MAX)''.', + DETAIL := 'Use of incorrect "datatype" parameter value during conversion process.', + HINT := 'Change "datatype" parameter to the proper value and try again.'; + + WHEN invalid_character_value_for_cast THEN + RAISE USING MESSAGE := 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 := format('Error while trying to convert "%s" value to SMALLINT data type.', + v_err_message), + DETAIL := 'Supplied value contains illegal characters.', + HINT := 'Correct supplied value, remove all illegal characters.'; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_conv_greg_to_hijri(IN p_dateval DATE) +RETURNS DATE +AS +$BODY$ +BEGIN + RETURN sys.babelfish_conv_greg_to_hijri(extract(day from p_dateval)::NUMERIC, + extract(month from p_dateval)::NUMERIC, + extract(year from p_dateval)::NUMERIC); +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_conv_greg_to_hijri(IN p_day NUMERIC, + IN p_month NUMERIC, + IN p_year NUMERIC) +RETURNS DATE +AS +$BODY$ +DECLARE + v_day SMALLINT; + v_month SMALLINT; + v_year INTEGER; + v_jdnum DOUBLE PRECISION; + v_lnum DOUBLE PRECISION; + v_inum DOUBLE PRECISION; + v_nnum DOUBLE PRECISION; + v_jnum DOUBLE PRECISION; +BEGIN + v_day := floor(p_day)::SMALLINT; + v_month := floor(p_month)::SMALLINT; + v_year := floor(p_year)::INTEGER; + + IF ((sign(v_day) = -1) OR (sign(v_month) = -1) OR (sign(v_year) = -1)) + THEN + RAISE invalid_character_value_for_cast; + ELSIF (v_year = 0) THEN + RAISE null_value_not_allowed; + END IF; + + IF ((p_year > 1582) OR ((p_year = 1582) AND (p_month > 10)) OR ((p_year = 1582) AND (p_month = 10) AND (p_day > 14))) + THEN + v_jdnum := sys.babelfish_get_int_part((1461 * (p_year + 4800 + sys.babelfish_get_int_part((p_month - 14) / 12))) / 4) + + sys.babelfish_get_int_part((367 * (p_month - 2 - 12 * (sys.babelfish_get_int_part((p_month - 14) / 12)))) / 12) - + sys.babelfish_get_int_part((3 * (sys.babelfish_get_int_part((p_year + 4900 + + sys.babelfish_get_int_part((p_month - 14) / 12)) / 100))) / 4) + p_day - 32075; + ELSE + v_jdnum := 367 * p_year - sys.babelfish_get_int_part((7 * (p_year + 5001 + + sys.babelfish_get_int_part((p_month - 9) / 7))) / 4) + + sys.babelfish_get_int_part((275 * p_month) / 9) + p_day + 1729777; + END IF; + + v_lnum := v_jdnum - 1948440 + 10632; + v_nnum := sys.babelfish_get_int_part((v_lnum - 1) / 10631); + v_lnum := v_lnum - 10631 * v_nnum + 354; + v_jnum := (sys.babelfish_get_int_part((10985 - v_lnum) / 5316)) * (sys.babelfish_get_int_part((50 * v_lnum) / 17719)) + + (sys.babelfish_get_int_part(v_lnum / 5670)) * (sys.babelfish_get_int_part((43 * v_lnum) / 15238)); + v_lnum := v_lnum - (sys.babelfish_get_int_part((30 - v_jnum) / 15)) * (sys.babelfish_get_int_part((17719 * v_jnum) / 50)) - + (sys.babelfish_get_int_part(v_jnum / 16)) * (sys.babelfish_get_int_part((15238 * v_jnum) / 43)) + 29; + + v_month := sys.babelfish_get_int_part((24 * v_lnum) / 709); + v_day := v_lnum - sys.babelfish_get_int_part((709 * v_month) / 24); + v_year := 30 * v_nnum + v_jnum - 30; + + RETURN to_date(concat_ws('.', v_day, v_month, v_year), 'DD.MM.YYYY'); +EXCEPTION + WHEN invalid_character_value_for_cast THEN + RAISE USING MESSAGE := 'Could not convert Gregorian to Hijri date if any part of the date is negative.', + DETAIL := 'Some of the supplied date parts (day, month, year) is negative.', + HINT := 'Change the value of the date part (day, month, year) wich was found to be negative.'; + + WHEN null_value_not_allowed THEN + RAISE USING MESSAGE := 'Could not convert Gregorian to Hijri date if year value is equal to zero.', + DETAIL := 'Supplied year value is equal to zero.', + HINT := 'Change the value of the year so that it is greater than zero.'; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_conv_greg_to_hijri(IN p_day TEXT, + IN p_month TEXT, + IN p_year TEXT) +RETURNS DATE +AS +$BODY$ +BEGIN + RETURN sys.babelfish_conv_greg_to_hijri(p_day::NUMERIC, + p_month::NUMERIC, + p_year::NUMERIC); +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_conv_greg_to_hijri(IN p_datetimeval TIMESTAMP WITHOUT TIME ZONE) +RETURNS TIMESTAMP WITHOUT TIME ZONE +AS +$BODY$ +DECLARE + v_hijri_date DATE; +BEGIN + v_hijri_date := sys.babelfish_conv_greg_to_hijri(extract(day from p_datetimeval)::SMALLINT, + extract(month from p_datetimeval)::SMALLINT, + extract(year from p_datetimeval)::INTEGER); + + RETURN to_timestamp(format('%s %s', to_char(v_hijri_date, 'DD.MM.YYYY'), + to_char(p_datetimeval, ' HH24:MI:SS.US')), + 'DD.MM.YYYY HH24:MI:SS.US'); +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_conv_hijri_to_greg(IN p_dateval DATE) +RETURNS DATE +AS +$BODY$ +BEGIN + RETURN sys.babelfish_conv_hijri_to_greg(extract(day from p_dateval)::NUMERIC, + extract(month from p_dateval)::NUMERIC, + extract(year from p_dateval)::NUMERIC); +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_conv_hijri_to_greg(IN p_day NUMERIC, + IN p_month NUMERIC, + IN p_year NUMERIC) +RETURNS DATE +AS +$BODY$ +DECLARE + v_day SMALLINT; + v_month SMALLINT; + v_year INTEGER; + v_err_message VARCHAR; + v_jdnum DOUBLE PRECISION; + v_lnum DOUBLE PRECISION; + v_inum DOUBLE PRECISION; + v_nnum DOUBLE PRECISION; + v_jnum DOUBLE PRECISION; + v_knum DOUBLE PRECISION; +BEGIN + v_day := floor(p_day)::SMALLINT; + v_month := floor(p_month)::SMALLINT; + v_year := floor(p_year)::INTEGER; + + IF ((sign(v_day) = -1) OR (sign(v_month) = -1) OR (sign(v_year) = -1)) + THEN + RAISE invalid_character_value_for_cast; + ELSIF (v_year = 0) THEN + RAISE null_value_not_allowed; + END IF; + + v_jdnum = sys.babelfish_get_int_part((11 * v_year + 3) / 30) + 354 * v_year + 30 * v_month - + sys.babelfish_get_int_part((v_month - 1) / 2) + v_day + 1948440 - 385; + + IF (v_jdnum > 2299160) + THEN + v_lnum := v_jdnum + 68569; + v_nnum := sys.babelfish_get_int_part((4 * v_lnum) / 146097); + v_lnum := v_lnum - sys.babelfish_get_int_part((146097 * v_nnum + 3) / 4); + v_inum := sys.babelfish_get_int_part((4000 * (v_lnum + 1)) / 1461001); + v_lnum := v_lnum - sys.babelfish_get_int_part((1461 * v_inum) / 4) + 31; + v_jnum := sys.babelfish_get_int_part((80 * v_lnum) / 2447); + v_day := v_lnum - sys.babelfish_get_int_part((2447 * v_jnum) / 80); + v_lnum := sys.babelfish_get_int_part(v_jnum / 11); + v_month := v_jnum + 2 - 12 * v_lnum; + v_year := 100 * (v_nnum - 49) + v_inum + v_lnum; + ELSE + v_jnum := v_jdnum + 1402; + v_knum := sys.babelfish_get_int_part((v_jnum - 1) / 1461); + v_lnum := v_jnum - 1461 * v_knum; + v_nnum := sys.babelfish_get_int_part((v_lnum - 1) / 365) - sys.babelfish_get_int_part(v_lnum / 1461); + v_inum := v_lnum - 365 * v_nnum + 30; + v_jnum := sys.babelfish_get_int_part((80 * v_inum) / 2447); + v_day := v_inum-sys.babelfish_get_int_part((2447 * v_jnum) / 80); + v_inum := sys.babelfish_get_int_part(v_jnum / 11); + v_month := v_jnum + 2 - 12 * v_inum; + v_year := 4 * v_knum + v_nnum + v_inum - 4716; + END IF; + + RETURN to_date(concat_ws('.', v_day, v_month, v_year), 'DD.MM.YYYY'); +EXCEPTION + WHEN invalid_character_value_for_cast THEN + RAISE USING MESSAGE := 'Could not convert Hijri to Gregorian date if any part of the date is negative.', + DETAIL := 'Some of the supplied date parts (day, month, year) is negative.', + HINT := 'Change the value of the date part (day, month, year) wich was found to be negative.'; + + WHEN null_value_not_allowed THEN + RAISE USING MESSAGE := 'Could not convert Hijri to Gregorian date if year value is equal to zero.', + DETAIL := 'Supplied year value is equal to zero.', + HINT := 'Change the value of the year so that it is greater than zero.'; + + 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 := format('Error while trying to convert "%s" value to SMALLINT data type.', v_err_message), + DETAIL := 'Supplied value contains illegal characters.', + HINT := 'Correct supplied value, remove all illegal characters.'; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_conv_hijri_to_greg(IN p_day TEXT, + IN p_month TEXT, + IN p_year TEXT) +RETURNS DATE +AS +$BODY$ +BEGIN + RETURN sys.babelfish_conv_hijri_to_greg(p_day::NUMERIC, + p_month::NUMERIC, + p_year::NUMERIC); +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_conv_hijri_to_greg(IN p_datetimeval TIMESTAMP WITHOUT TIME ZONE) +RETURNS TIMESTAMP WITHOUT TIME ZONE +AS +$BODY$ +DECLARE + v_hijri_date DATE; +BEGIN + v_hijri_date := sys.babelfish_conv_hijri_to_greg(extract(day from p_dateval)::NUMERIC, + extract(month from p_dateval)::NUMERIC, + extract(year from p_dateval)::NUMERIC); + + RETURN to_timestamp(format('%s %s', to_char(v_hijri_date, 'DD.MM.YYYY'), + to_char(p_datetimeval, ' HH24:MI:SS.US')), + 'DD.MM.YYYY HH24:MI:SS.US'); +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_conv_string_to_date(IN p_datestring TEXT, + IN p_style NUMERIC DEFAULT 0) +RETURNS DATE +AS +$BODY$ +DECLARE + v_day VARCHAR; + v_year VARCHAR; + v_month VARCHAR; + v_hijridate DATE; + v_style SMALLINT; + v_leftpart VARCHAR; + v_middlepart VARCHAR; + v_rightpart VARCHAR; + v_fractsecs VARCHAR; + v_datestring VARCHAR; + v_err_message VARCHAR; + v_date_format VARCHAR; + v_regmatch_groups TEXT[]; + v_lang_metadata_json JSONB; + v_compmonth_regexp VARCHAR; + CONVERSION_LANG CONSTANT VARCHAR := ''; + DATE_FORMAT CONSTANT VARCHAR := ''; + DAYMM_REGEXP CONSTANT VARCHAR := '(\d{1,2})'; + FULLYEAR_REGEXP CONSTANT VARCHAR := '(\d{4})'; + SHORTYEAR_REGEXP CONSTANT VARCHAR := '(\d{1,2})'; + COMPYEAR_REGEXP CONSTANT VARCHAR := '(\d{1,2}|\d{4})'; + AMPM_REGEXP CONSTANT VARCHAR := '(?:[AP]M)'; + TIMEUNIT_REGEXP CONSTANT VARCHAR := '\s*\d{1,2}\s*'; + FRACTSECS_REGEXP CONSTANT VARCHAR := '\s*\d{1,9}'; + HHMMSSFS_PART_REGEXP CONSTANT VARCHAR := concat('(', TIMEUNIT_REGEXP, AMPM_REGEXP, '|', + TIMEUNIT_REGEXP, '\:', TIMEUNIT_REGEXP, '|', + TIMEUNIT_REGEXP, '\:', TIMEUNIT_REGEXP, '\:', TIMEUNIT_REGEXP, '|', + TIMEUNIT_REGEXP, '\:', TIMEUNIT_REGEXP, '\:', TIMEUNIT_REGEXP, '(?:\.|\:)', FRACTSECS_REGEXP, + ')\s*', AMPM_REGEXP, '?'); + HHMMSSFS_DOTPART_REGEXP CONSTANT VARCHAR := concat('(', TIMEUNIT_REGEXP, AMPM_REGEXP, '|', + TIMEUNIT_REGEXP, '\:', TIMEUNIT_REGEXP, '|', + TIMEUNIT_REGEXP, '\:', TIMEUNIT_REGEXP, '\:', TIMEUNIT_REGEXP, '|', + TIMEUNIT_REGEXP, '\:', TIMEUNIT_REGEXP, '\:', TIMEUNIT_REGEXP, '\.', FRACTSECS_REGEXP, + ')\s*', AMPM_REGEXP, '?'); + HHMMSSFS_REGEXP CONSTANT VARCHAR := concat('^', HHMMSSFS_PART_REGEXP, '$'); + HHMMSSFS_DOT_REGEXP CONSTANT VARCHAR := concat('^', HHMMSSFS_DOTPART_REGEXP, '$'); + v_defmask1_regexp VARCHAR := concat('^($comp_month$)\s*', DAYMM_REGEXP, '\s+', COMPYEAR_REGEXP, '$'); + v_defmask2_regexp VARCHAR := concat('^', DAYMM_REGEXP, '\s*($comp_month$)\s*', COMPYEAR_REGEXP, '$'); + v_defmask3_regexp VARCHAR := concat('^', FULLYEAR_REGEXP, '\s*($comp_month$)\s*', DAYMM_REGEXP, '$'); + v_defmask4_regexp VARCHAR := concat('^', FULLYEAR_REGEXP, '\s+', DAYMM_REGEXP, '\s*($comp_month$)$'); + v_defmask5_regexp VARCHAR := concat('^', DAYMM_REGEXP, '\s+', COMPYEAR_REGEXP, '\s*($comp_month$)$'); + v_defmask6_regexp VARCHAR := concat('^($comp_month$)\s*', FULLYEAR_REGEXP, '\s+', DAYMM_REGEXP, '$'); + v_defmask7_regexp VARCHAR := concat('^($comp_month$)\s*', DAYMM_REGEXP, '\s*\,\s*', COMPYEAR_REGEXP, '$'); + v_defmask8_regexp VARCHAR := concat('^', FULLYEAR_REGEXP, '\s*($comp_month$)$'); + v_defmask9_regexp VARCHAR := concat('^($comp_month$)\s*', FULLYEAR_REGEXP, '$'); + v_defmask10_regexp VARCHAR := concat('^', DAYMM_REGEXP, '\s*(?:\.|/|-)\s*($comp_month$)\s*(?:\.|/|-)\s*', COMPYEAR_REGEXP, '$'); + DOT_SHORTYEAR_REGEXP CONSTANT VARCHAR := concat('^', DAYMM_REGEXP, '\s*\.\s*', DAYMM_REGEXP, '\s*\.\s*', SHORTYEAR_REGEXP, '$'); + DOT_FULLYEAR_REGEXP CONSTANT VARCHAR := concat('^', DAYMM_REGEXP, '\s*\.\s*', DAYMM_REGEXP, '\s*\.\s*', FULLYEAR_REGEXP, '$'); + SLASH_SHORTYEAR_REGEXP CONSTANT VARCHAR := concat('^', DAYMM_REGEXP, '\s*/\s*', DAYMM_REGEXP, '\s*/\s*', SHORTYEAR_REGEXP, '$'); + SLASH_FULLYEAR_REGEXP CONSTANT VARCHAR := concat('^', DAYMM_REGEXP, '\s*/\s*', DAYMM_REGEXP, '\s*/\s*', FULLYEAR_REGEXP, '$'); + DASH_SHORTYEAR_REGEXP CONSTANT VARCHAR := concat('^', DAYMM_REGEXP, '\s*-\s*', DAYMM_REGEXP, '\s*-\s*', SHORTYEAR_REGEXP, '$'); + DASH_FULLYEAR_REGEXP CONSTANT VARCHAR := concat('^', DAYMM_REGEXP, '\s*-\s*', DAYMM_REGEXP, '\s*-\s*', FULLYEAR_REGEXP, '$'); + DOT_SLASH_DASH_YEAR_REGEXP CONSTANT VARCHAR := concat('^', DAYMM_REGEXP, '\s*(?:\.|/|-)\s*', DAYMM_REGEXP, '\s*(?:\.|/|-)\s*', COMPYEAR_REGEXP, '$'); + YEAR_DOTMASK_REGEXP CONSTANT VARCHAR := concat('^', FULLYEAR_REGEXP, '\s*\.\s*', DAYMM_REGEXP, '\s*\.\s*', DAYMM_REGEXP, '$'); + YEAR_SLASHMASK_REGEXP CONSTANT VARCHAR := concat('^', FULLYEAR_REGEXP, '\s*/\s*', DAYMM_REGEXP, '\s*/\s*', DAYMM_REGEXP, '$'); + YEAR_DASHMASK_REGEXP CONSTANT VARCHAR := concat('^', FULLYEAR_REGEXP, '\s*-\s*', DAYMM_REGEXP, '\s*-\s*', DAYMM_REGEXP, '$'); + YEAR_DOT_SLASH_DASH_REGEXP CONSTANT VARCHAR := concat('^', FULLYEAR_REGEXP, '\s*(?:\.|/|-)\s*', DAYMM_REGEXP, '\s*(?:\.|/|-)\s*', DAYMM_REGEXP, '$'); + DIGITMASK1_REGEXP CONSTANT VARCHAR := '^\d{6}$'; + DIGITMASK2_REGEXP CONSTANT VARCHAR := '^\d{8}$'; +BEGIN + v_style := floor(p_style)::SMALLINT; + v_datestring := trim(p_datestring); + + 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))) + THEN + RAISE invalid_parameter_value; + END IF; + + IF (v_datestring ~* HHMMSSFS_PART_REGEXP AND v_datestring !~* HHMMSSFS_REGEXP) + THEN + v_datestring := trim(regexp_replace(v_datestring, HHMMSSFS_PART_REGEXP, '', 'gi')); + END IF; + + BEGIN + v_lang_metadata_json := sys.babelfish_get_lang_metadata_json(CONVERSION_LANG); + EXCEPTION + WHEN OTHERS THEN + RAISE invalid_character_value_for_cast; + 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'))), '|'); + + v_defmask1_regexp := replace(v_defmask1_regexp, '$comp_month$', v_compmonth_regexp); + v_defmask2_regexp := replace(v_defmask2_regexp, '$comp_month$', v_compmonth_regexp); + v_defmask3_regexp := replace(v_defmask3_regexp, '$comp_month$', v_compmonth_regexp); + v_defmask4_regexp := replace(v_defmask4_regexp, '$comp_month$', v_compmonth_regexp); + v_defmask5_regexp := replace(v_defmask5_regexp, '$comp_month$', v_compmonth_regexp); + v_defmask6_regexp := replace(v_defmask6_regexp, '$comp_month$', v_compmonth_regexp); + v_defmask7_regexp := replace(v_defmask7_regexp, '$comp_month$', v_compmonth_regexp); + v_defmask8_regexp := replace(v_defmask8_regexp, '$comp_month$', v_compmonth_regexp); + v_defmask9_regexp := replace(v_defmask9_regexp, '$comp_month$', v_compmonth_regexp); + v_defmask10_regexp := replace(v_defmask10_regexp, '$comp_month$', v_compmonth_regexp); + + IF (v_datestring ~* v_defmask1_regexp OR + v_datestring ~* v_defmask2_regexp OR + v_datestring ~* v_defmask3_regexp OR + v_datestring ~* v_defmask4_regexp OR + v_datestring ~* v_defmask5_regexp OR + v_datestring ~* v_defmask6_regexp OR + v_datestring ~* v_defmask7_regexp OR + v_datestring ~* v_defmask8_regexp OR + v_datestring ~* v_defmask9_regexp OR + v_datestring ~* v_defmask10_regexp) + THEN + IF (v_style IN (130, 131)) THEN + RAISE invalid_datetime_format; + END IF; + + IF (v_datestring ~* v_defmask1_regexp) + THEN + v_regmatch_groups := regexp_matches(v_datestring, v_defmask1_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 ~* v_defmask2_regexp) + THEN + v_regmatch_groups := regexp_matches(v_datestring, v_defmask2_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 ~* v_defmask3_regexp) + THEN + v_regmatch_groups := regexp_matches(v_datestring, v_defmask3_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 ~* v_defmask4_regexp) + THEN + v_regmatch_groups := regexp_matches(v_datestring, v_defmask4_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 ~* v_defmask5_regexp) + THEN + v_regmatch_groups := regexp_matches(v_datestring, v_defmask5_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 ~* v_defmask6_regexp) + THEN + v_regmatch_groups := regexp_matches(v_datestring, v_defmask6_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 ~* v_defmask7_regexp) + THEN + v_regmatch_groups := regexp_matches(v_datestring, v_defmask7_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 ~* v_defmask8_regexp) + THEN + v_regmatch_groups := regexp_matches(v_datestring, v_defmask8_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 ~* v_defmask9_regexp) + THEN + v_regmatch_groups := regexp_matches(v_datestring, v_defmask9_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]; + ELSE + v_regmatch_groups := regexp_matches(v_datestring, v_defmask10_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]); + END IF; + ELSEIF (v_datestring ~* DOT_SHORTYEAR_REGEXP OR + v_datestring ~* DOT_FULLYEAR_REGEXP OR + v_datestring ~* SLASH_SHORTYEAR_REGEXP OR + v_datestring ~* SLASH_FULLYEAR_REGEXP OR + v_datestring ~* DASH_SHORTYEAR_REGEXP OR + v_datestring ~* DASH_FULLYEAR_REGEXP) + THEN + IF (v_style IN (6, 7, 8, 9, 12, 13, 14, 24, 100, 106, 107, 108, 109, 112, 113, 114, 130)) THEN + RAISE invalid_regular_expression; + ELSIF (v_style IN (20, 21, 23, 25, 102, 111, 120, 121, 126, 127)) THEN + RAISE invalid_datetime_format; + END IF; + + v_regmatch_groups := regexp_matches(v_datestring, DOT_SLASH_DASH_YEAR_REGEXP, 'gi'); + v_leftpart := v_regmatch_groups[1]; + v_middlepart := v_regmatch_groups[2]; + v_rightpart := v_regmatch_groups[3]; + + IF (v_datestring ~* DOT_SHORTYEAR_REGEXP OR + v_datestring ~* SLASH_SHORTYEAR_REGEXP OR + v_datestring ~* DASH_SHORTYEAR_REGEXP) + THEN + IF ((v_style IN (1, 10, 22) AND v_date_format <> 'MDY') OR + ((v_style IS NULL OR v_style IN (0, 1, 10, 22)) AND v_date_format NOT IN ('YDM', 'YMD', 'DMY', 'DYM', 'MYD'))) + 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 IS NULL 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 IS NULL 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 IS NULL OR 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 IS NULL OR 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 IS NULL OR v_style = 0) AND v_date_format = 'YDM') THEN + RAISE character_not_in_repertoire; + ELSIF (v_style IN (101, 103, 104, 105, 110, 131)) THEN + RAISE invalid_datetime_format; + END IF; + ELSE + v_year := v_rightpart; + + IF (v_leftpart::SMALLINT <= 12) + THEN + IF ((v_style IN (103, 104, 105, 131) AND v_date_format <> 'DMY') OR + ((v_style IS NULL OR v_style IN (0, 103, 104, 105, 131)) AND v_date_format = 'DMY')) + THEN + v_day := v_leftpart; + v_month := v_middlepart; + ELSIF ((v_style IN (101, 110) AND v_date_format IN ('YDM', 'DMY', 'DYM')) OR + ((v_style IS NULL OR v_style IN (0, 101, 110)) AND v_date_format NOT IN ('YDM', 'DMY', 'DYM'))) + THEN + v_day := v_middlepart; + v_month := v_leftpart; + ELSIF ((v_style IN (1, 2, 3, 4, 5, 10, 11, 22) AND v_date_format <> 'YDM') OR + ((v_style IS NULL OR v_style IN (0, 1, 2, 3, 4, 5, 10, 11, 22)) AND v_date_format = 'YDM')) + THEN + RAISE invalid_datetime_format; + END IF; + ELSE + IF ((v_style IN (103, 104, 105, 131) AND v_date_format <> 'DMY') OR + ((v_style IS NULL OR v_style IN (0, 103, 104, 105, 131)) AND v_date_format = 'DMY')) + THEN + v_day := v_leftpart; + v_month := v_middlepart; + ELSIF ((v_style IN (1, 2, 3, 4, 5, 10, 11, 22, 101, 110) AND v_date_format = 'DMY') OR + ((v_style IS NULL OR v_style IN (0, 1, 2, 3, 4, 5, 10, 11, 22, 101, 110)) AND v_date_format <> 'DMY')) + THEN + RAISE invalid_datetime_format; + END IF; + END IF; + END IF; + ELSIF (v_datestring ~* YEAR_DOTMASK_REGEXP OR + v_datestring ~* YEAR_SLASHMASK_REGEXP OR + v_datestring ~* YEAR_DASHMASK_REGEXP) + THEN + IF (v_style IN (6, 7, 8, 9, 12, 13, 14, 24, 100, 106, 107, 108, 109, 112, 113, 114, 130)) THEN + RAISE invalid_regular_expression; + ELSIF (v_style IN (1, 2, 3, 4, 5, 10, 11, 22, 101, 103, 104, 105, 110, 131)) THEN + RAISE invalid_datetime_format; + END IF; + + v_regmatch_groups := regexp_matches(v_datestring, YEAR_DOT_SLASH_DASH_REGEXP, 'gi'); + v_day := v_regmatch_groups[3]; + v_month := v_regmatch_groups[2]; + v_year := v_regmatch_groups[1]; + + ELSIF (v_datestring ~* DIGITMASK1_REGEXP OR + v_datestring ~* DIGITMASK2_REGEXP) + THEN + IF (v_datestring ~* DIGITMASK1_REGEXP) + THEN + v_day := substring(v_datestring, 5, 2); + v_month := substring(v_datestring, 3, 2); + v_year := sys.babelfish_get_full_year(substring(v_datestring, 1, 2)); + ELSE + v_day := substring(v_datestring, 7, 2); + v_month := substring(v_datestring, 5, 2); + v_year := substring(v_datestring, 1, 4); + END IF; + ELSIF (v_datestring ~* HHMMSSFS_REGEXP) + THEN + v_fractsecs := coalesce(sys.babelfish_get_timeunit_from_string(v_datestring, 'FRACTSECONDS'), ''); + IF (v_datestring !~* HHMMSSFS_DOT_REGEXP AND char_length(v_fractsecs) > 3) THEN + RAISE invalid_datetime_format; + END IF; + + v_day := '01'; + v_month := '01'; + v_year := '1900'; + ELSE + RAISE invalid_datetime_format; + END IF; + + IF (((v_datestring ~* HHMMSSFS_REGEXP OR v_datestring ~* DIGITMASK1_REGEXP OR v_datestring ~* DIGITMASK2_REGEXP) AND v_style IN (130, 131)) OR + ((v_datestring ~* DOT_FULLYEAR_REGEXP OR v_datestring ~* SLASH_FULLYEAR_REGEXP OR v_datestring ~* DASH_FULLYEAR_REGEXP) AND v_style = 131)) + THEN + IF ((v_day::SMALLINT NOT BETWEEN 1 AND 29) OR + (v_month::SMALLINT NOT BETWEEN 1 AND 12)) + THEN + RAISE invalid_datetime_format; + END IF; + + v_hijridate := sys.babelfish_conv_hijri_to_greg(v_day, v_month, v_year) - 1; + v_datestring := to_char(v_hijridate, 'DD.MM.YYYY'); + + v_day := split_part(v_datestring, '.', 1); + v_month := split_part(v_datestring, '.', 2); + v_year := split_part(v_datestring, '.', 3); + END IF; + + RETURN to_date(concat_ws('.', v_day, v_month, v_year), 'DD.MM.YYYY'); +EXCEPTION + WHEN most_specific_type_mismatch THEN + RAISE USING MESSAGE := 'Argument data type NUMERIC is invalid for argument 2 of conv_string_to_date 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 := format('The style %s is not supported for conversions from VARCHAR to DATE.', v_style), + 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 := 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 invalid_datetime_format THEN + RAISE USING MESSAGE := 'Conversion failed when converting date from character string.', + 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 character_not_in_repertoire THEN + RAISE USING MESSAGE := 'The YDM date format isn''t supported when converting from this string format to date.', + 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_character_value_for_cast THEN + RAISE USING MESSAGE := 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 := 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 +VOLATILE +RETURNS NULL ON NULL INPUT; + +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; + v_year VARCHAR; + v_month VARCHAR; + v_style SMALLINT; + v_scale SMALLINT; + v_hours VARCHAR; + v_hijridate DATE; + v_minutes VARCHAR; + v_seconds VARCHAR; + v_fseconds VARCHAR; + v_datatype VARCHAR; + v_timepart VARCHAR; + v_leftpart VARCHAR; + v_middlepart VARCHAR; + v_rightpart VARCHAR; + v_datestring VARCHAR; + v_err_message VARCHAR; + v_date_format VARCHAR; + v_res_datatype VARCHAR; + v_datetimestring VARCHAR; + v_datatype_groups TEXT[]; + v_regmatch_groups TEXT[]; + v_lang_metadata_json JSONB; + v_compmonth_regexp VARCHAR; + v_resdatetime TIMESTAMP(6) WITHOUT TIME ZONE; + CONVERSION_LANG CONSTANT VARCHAR := ''; + DATE_FORMAT CONSTANT VARCHAR := ''; + DAYMM_REGEXP CONSTANT VARCHAR := '(\d{1,2})'; + FULLYEAR_REGEXP CONSTANT VARCHAR := '(\d{4})'; + SHORTYEAR_REGEXP CONSTANT VARCHAR := '(\d{1,2})'; + COMPYEAR_REGEXP CONSTANT VARCHAR := '(\d{1,2}|\d{4})'; + AMPM_REGEXP CONSTANT VARCHAR := '(?:[AP]M)'; + MASKSEP_REGEXP CONSTANT VARCHAR := '(?:\.|-|/)'; + TIMEUNIT_REGEXP CONSTANT VARCHAR := '\s*\d{1,2}\s*'; + FRACTSECS_REGEXP CONSTANT VARCHAR := '\s*\d{1,9}\s*'; + DATATYPE_REGEXP CONSTANT VARCHAR := '^(DATETIME|SMALLDATETIME|DATETIME2)\s*(?:\()?\s*((?:-)?\d+)?\s*(?:\))?$'; + HHMMSSFS_PART_REGEXP CONSTANT VARCHAR := 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 := 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 := concat('^(', HHMMSSFS_PART_REGEXP, ')$'); + DEFMASK1_0_REGEXP CONSTANT VARCHAR := 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 := concat('^', MASKSEP_REGEXP, '?\s*($comp_month$)\s*', DAYMM_REGEXP, '\s+', COMPYEAR_REGEXP, '$'); + DEFMASK1_2_REGEXP CONSTANT VARCHAR := concat('^', MASKSEP_REGEXP, '\s*($comp_month$)\s*', DAYMM_REGEXP, '\s+', COMPYEAR_REGEXP, '$'); + DEFMASK2_0_REGEXP CONSTANT VARCHAR := 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 := concat('^', DAYMM_REGEXP, '\s*', MASKSEP_REGEXP, '?\s*($comp_month$)\s*', COMPYEAR_REGEXP, '$'); + DEFMASK2_2_REGEXP CONSTANT VARCHAR := concat('^', DAYMM_REGEXP, '\s*', MASKSEP_REGEXP, '\s*($comp_month$)\s*', COMPYEAR_REGEXP, '$'); + DEFMASK3_0_REGEXP CONSTANT VARCHAR := 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 := concat('^', FULLYEAR_REGEXP, '\s*', MASKSEP_REGEXP, '?\s*($comp_month$)\s*', DAYMM_REGEXP, '$'); + DEFMASK3_2_REGEXP CONSTANT VARCHAR := concat('^', FULLYEAR_REGEXP, '\s*', MASKSEP_REGEXP, '\s*($comp_month$)\s*', DAYMM_REGEXP, '$'); + DEFMASK4_0_REGEXP CONSTANT VARCHAR := 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 := concat('^', FULLYEAR_REGEXP, '\s+', DAYMM_REGEXP, '\s*', MASKSEP_REGEXP, '?\s*($comp_month$)$'); + DEFMASK4_2_REGEXP CONSTANT VARCHAR := concat('^', FULLYEAR_REGEXP, '\s+', DAYMM_REGEXP, '\s*', MASKSEP_REGEXP, '\s*($comp_month$)$'); + DEFMASK5_0_REGEXP CONSTANT VARCHAR := 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 := concat('^', DAYMM_REGEXP, '\s+', COMPYEAR_REGEXP, '\s*', MASKSEP_REGEXP, '?\s*($comp_month$)$'); + DEFMASK5_2_REGEXP CONSTANT VARCHAR := concat('^', DAYMM_REGEXP, '\s+', COMPYEAR_REGEXP, '\s*', MASKSEP_REGEXP, '\s*($comp_month$)$'); + DEFMASK6_0_REGEXP CONSTANT VARCHAR := 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 := concat('^', MASKSEP_REGEXP, '?\s*($comp_month$)\s*', FULLYEAR_REGEXP, '\s+', DAYMM_REGEXP, '$'); + DEFMASK6_2_REGEXP CONSTANT VARCHAR := concat('^', MASKSEP_REGEXP, '\s*($comp_month$)\s*', FULLYEAR_REGEXP, '\s+', DAYMM_REGEXP, '$'); + DEFMASK7_0_REGEXP CONSTANT VARCHAR := 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 := concat('^', MASKSEP_REGEXP, '?\s*($comp_month$)\s*', DAYMM_REGEXP, '\s*,\s*', COMPYEAR_REGEXP, '$'); + DEFMASK7_2_REGEXP CONSTANT VARCHAR := concat('^', MASKSEP_REGEXP, '\s*($comp_month$)\s*', DAYMM_REGEXP, '\s*,\s*', COMPYEAR_REGEXP, '$'); + DEFMASK8_0_REGEXP CONSTANT VARCHAR := concat('^(', HHMMSSFS_PART_REGEXP, ')?\s*', + FULLYEAR_REGEXP, '\s*', MASKSEP_REGEXP, '*\s*($comp_month$)', + '\s*(', HHMMSSFS_PART_REGEXP, ')?$'); + DEFMASK8_1_REGEXP CONSTANT VARCHAR := concat('^', FULLYEAR_REGEXP, '\s*', MASKSEP_REGEXP, '?\s*($comp_month$)$'); + DEFMASK8_2_REGEXP CONSTANT VARCHAR := concat('^', FULLYEAR_REGEXP, '\s*', MASKSEP_REGEXP, '\s*($comp_month$)$'); + DEFMASK9_0_REGEXP CONSTANT VARCHAR := concat('^(', HHMMSSFS_PART_REGEXP, ')?\s*', + MASKSEP_REGEXP, '*\s*($comp_month$)\s*', FULLYEAR_REGEXP, + '\s*(', HHMMSSFS_PART_REGEXP, ')?$'); + DEFMASK9_1_REGEXP CONSTANT VARCHAR := concat('^', MASKSEP_REGEXP, '?\s*($comp_month$)\s*', FULLYEAR_REGEXP, '$'); + DEFMASK9_2_REGEXP CONSTANT VARCHAR := concat('^', MASKSEP_REGEXP, '\s*($comp_month$)\s*', FULLYEAR_REGEXP, '$'); + DEFMASK10_0_REGEXP CONSTANT VARCHAR := 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 := concat('^', DAYMM_REGEXP, '\s*', MASKSEP_REGEXP, '\s*($comp_month$)\s*', MASKSEP_REGEXP, '\s*', COMPYEAR_REGEXP, '$'); + DOT_SLASH_DASH_COMPYEAR1_0_REGEXP CONSTANT VARCHAR := 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 := concat('^', DAYMM_REGEXP, '\s*', MASKSEP_REGEXP, '\s*', DAYMM_REGEXP, '\s*', MASKSEP_REGEXP, '\s*', COMPYEAR_REGEXP, '$'); + DOT_SLASH_DASH_SHORTYEAR_REGEXP CONSTANT VARCHAR := concat('^', DAYMM_REGEXP, '\s*', MASKSEP_REGEXP, '\s*', DAYMM_REGEXP, '\s*', MASKSEP_REGEXP, '\s*', SHORTYEAR_REGEXP, '$'); + DOT_SLASH_DASH_FULLYEAR1_0_REGEXP CONSTANT VARCHAR := 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 := concat('^', DAYMM_REGEXP, '\s*', MASKSEP_REGEXP, '\s*', DAYMM_REGEXP, '\s*', MASKSEP_REGEXP, '\s*', FULLYEAR_REGEXP, '$'); + FULLYEAR_DOT_SLASH_DASH1_0_REGEXP CONSTANT VARCHAR := 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 := concat('^', FULLYEAR_REGEXP, '\s*', MASKSEP_REGEXP, '\s*', DAYMM_REGEXP, '\s*', MASKSEP_REGEXP, '\s*', DAYMM_REGEXP, '$'); + SHORT_DIGITMASK1_0_REGEXP CONSTANT VARCHAR := concat('^(', HHMMSSFS_PART_REGEXP, ')?\s*\d{6}\s*(', HHMMSSFS_PART_REGEXP, ')?$'); + FULL_DIGITMASK1_0_REGEXP CONSTANT VARCHAR := 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 ~* replace(DEFMASK1_0_REGEXP, '$comp_month$', v_compmonth_regexp) OR + v_datetimestring ~* replace(DEFMASK2_0_REGEXP, '$comp_month$', v_compmonth_regexp) OR + v_datetimestring ~* replace(DEFMASK3_0_REGEXP, '$comp_month$', v_compmonth_regexp) OR + v_datetimestring ~* replace(DEFMASK4_0_REGEXP, '$comp_month$', v_compmonth_regexp) OR + v_datetimestring ~* replace(DEFMASK5_0_REGEXP, '$comp_month$', v_compmonth_regexp) OR + v_datetimestring ~* replace(DEFMASK6_0_REGEXP, '$comp_month$', v_compmonth_regexp) OR + v_datetimestring ~* replace(DEFMASK7_0_REGEXP, '$comp_month$', v_compmonth_regexp) OR + v_datetimestring ~* replace(DEFMASK8_0_REGEXP, '$comp_month$', v_compmonth_regexp) OR + v_datetimestring ~* replace(DEFMASK9_0_REGEXP, '$comp_month$', v_compmonth_regexp) OR + v_datetimestring ~* 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 ~* replace(DEFMASK1_2_REGEXP, '$comp_month$', v_compmonth_regexp) OR + v_datestring ~* replace(DEFMASK2_2_REGEXP, '$comp_month$', v_compmonth_regexp) OR + v_datestring ~* replace(DEFMASK3_2_REGEXP, '$comp_month$', v_compmonth_regexp) OR + v_datestring ~* replace(DEFMASK4_2_REGEXP, '$comp_month$', v_compmonth_regexp) OR + v_datestring ~* replace(DEFMASK5_2_REGEXP, '$comp_month$', v_compmonth_regexp) OR + v_datestring ~* replace(DEFMASK6_2_REGEXP, '$comp_month$', v_compmonth_regexp) OR + v_datestring ~* replace(DEFMASK7_2_REGEXP, '$comp_month$', v_compmonth_regexp) OR + v_datestring ~* replace(DEFMASK8_2_REGEXP, '$comp_month$', v_compmonth_regexp) OR + v_datestring ~* replace(DEFMASK9_2_REGEXP, '$comp_month$', v_compmonth_regexp)) AND + v_res_datatype = 'DATETIME2') + THEN + RAISE invalid_datetime_format; + END IF; + + IF (v_datestring ~* replace(DEFMASK1_1_REGEXP, '$comp_month$', v_compmonth_regexp)) + THEN + v_regmatch_groups := regexp_matches(v_datestring, 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 ~* replace(DEFMASK2_1_REGEXP, '$comp_month$', v_compmonth_regexp)) + THEN + v_regmatch_groups := regexp_matches(v_datestring, 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 ~* replace(DEFMASK3_1_REGEXP, '$comp_month$', v_compmonth_regexp)) + THEN + v_regmatch_groups := regexp_matches(v_datestring, 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 ~* replace(DEFMASK4_1_REGEXP, '$comp_month$', v_compmonth_regexp)) + THEN + v_regmatch_groups := regexp_matches(v_datestring, 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 ~* replace(DEFMASK5_1_REGEXP, '$comp_month$', v_compmonth_regexp)) + THEN + v_regmatch_groups := regexp_matches(v_datestring, 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 ~* replace(DEFMASK6_1_REGEXP, '$comp_month$', v_compmonth_regexp)) + THEN + v_regmatch_groups := regexp_matches(v_datestring, 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 ~* replace(DEFMASK7_1_REGEXP, '$comp_month$', v_compmonth_regexp)) + THEN + v_regmatch_groups := regexp_matches(v_datestring, 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 ~* replace(DEFMASK8_1_REGEXP, '$comp_month$', v_compmonth_regexp)) + THEN + v_regmatch_groups := regexp_matches(v_datestring, 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 ~* replace(DEFMASK9_1_REGEXP, '$comp_month$', v_compmonth_regexp)) + THEN + v_regmatch_groups := regexp_matches(v_datestring, 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 ~* replace(DEFMASK10_1_REGEXP, '$comp_month$', v_compmonth_regexp)) + THEN + v_regmatch_groups := regexp_matches(v_datestring, 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'; + 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 := 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 := 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 := 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 := 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 := 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 := 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 +VOLATILE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_conv_string_to_time(IN p_datatype TEXT, + IN p_timestring TEXT, + IN p_style NUMERIC DEFAULT 0) +RETURNS TIME WITHOUT TIME ZONE +AS +$BODY$ +DECLARE + v_hours SMALLINT; + v_style SMALLINT; + v_scale SMALLINT; + v_daypart VARCHAR; + v_seconds VARCHAR; + v_minutes SMALLINT; + v_fseconds VARCHAR; + v_datatype VARCHAR; + v_timestring VARCHAR; + v_err_message VARCHAR; + v_src_datatype VARCHAR; + v_timeunit_mask VARCHAR; + v_datatype_groups TEXT[]; + v_regmatch_groups TEXT[]; + AMPM_REGEXP CONSTANT VARCHAR := '\s*([AP]M)'; + TIMEUNIT_REGEXP CONSTANT VARCHAR := '\s*(\d{1,2})\s*'; + FRACTSECS_REGEXP CONSTANT VARCHAR := '\s*(\d{1,9})'; + HHMMSSFS_REGEXP CONSTANT VARCHAR := concat('^', TIMEUNIT_REGEXP, + '\:', TIMEUNIT_REGEXP, + '\:', TIMEUNIT_REGEXP, + '(?:\.|\:)', FRACTSECS_REGEXP, '$'); + HHMMSS_REGEXP CONSTANT VARCHAR := concat('^', TIMEUNIT_REGEXP, '\:', TIMEUNIT_REGEXP, '\:', TIMEUNIT_REGEXP, '$'); + HHMMFS_REGEXP CONSTANT VARCHAR := concat('^', TIMEUNIT_REGEXP, '\:', TIMEUNIT_REGEXP, '\.', FRACTSECS_REGEXP, '$'); + HHMM_REGEXP CONSTANT VARCHAR := concat('^', TIMEUNIT_REGEXP, '\:', TIMEUNIT_REGEXP, '$'); + HH_REGEXP CONSTANT VARCHAR := concat('^', TIMEUNIT_REGEXP, '$'); + DATATYPE_REGEXP CONSTANT VARCHAR := '^(TIME)\s*(?:\()?\s*((?:-)?\d+)?\s*(?:\))?$'; +BEGIN + v_datatype := trim(regexp_replace(p_datatype, 'DATETIME', 'TIME', 'gi')); + v_timestring := upper(trim(p_timestring)); + v_style := floor(p_style)::SMALLINT; + + v_datatype_groups := regexp_matches(v_datatype, DATATYPE_REGEXP, 'gi'); + + v_src_datatype := upper(v_datatype_groups[1]); + v_scale := v_datatype_groups[2]::SMALLINT; + + IF (v_src_datatype IS NULL) THEN + RAISE datatype_mismatch; + 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))) + THEN + RAISE invalid_parameter_value; + END IF; + + v_daypart := substring(v_timestring, 'AM|PM'); + v_timestring := trim(regexp_replace(v_timestring, coalesce(v_daypart, ''), '')); + + v_timeunit_mask := + CASE + WHEN (v_timestring ~* HHMMSSFS_REGEXP) THEN HHMMSSFS_REGEXP + WHEN (v_timestring ~* HHMMSS_REGEXP) THEN HHMMSS_REGEXP + WHEN (v_timestring ~* HHMMFS_REGEXP) THEN HHMMFS_REGEXP + WHEN (v_timestring ~* HHMM_REGEXP) THEN HHMM_REGEXP + WHEN (v_timestring ~* HH_REGEXP) THEN HH_REGEXP + END; + + IF (v_timeunit_mask IS NULL) THEN + RAISE invalid_datetime_format; + END IF; + + v_regmatch_groups := regexp_matches(v_timestring, v_timeunit_mask, 'gi'); + + v_hours := v_regmatch_groups[1]::SMALLINT; + v_minutes := v_regmatch_groups[2]::SMALLINT; + + IF (v_timestring ~* HHMMFS_REGEXP) THEN + v_fseconds := v_regmatch_groups[3]; + ELSE + v_seconds := v_regmatch_groups[3]; + v_fseconds := v_regmatch_groups[4]; + END IF; + + IF (v_daypart IS NOT NULL) THEN + IF ((v_daypart = 'AM' AND v_hours NOT BETWEEN 0 AND 12) OR + (v_daypart = 'PM' AND v_hours NOT BETWEEN 1 AND 23)) + THEN + RAISE numeric_value_out_of_range; + ELSIF (v_daypart = 'PM' AND v_hours < 12) THEN + v_hours := v_hours + 12; + ELSIF (v_daypart = 'AM' AND v_hours = 12) THEN + v_hours := v_hours - 12; + END IF; + END IF; + + v_fseconds := sys.babelfish_get_microsecs_from_fractsecs(v_fseconds, v_scale); + v_seconds := concat_ws('.', v_seconds, v_fseconds); + + RETURN make_time(v_hours, v_minutes, v_seconds::NUMERIC); +EXCEPTION + WHEN most_specific_type_mismatch THEN + RAISE USING MESSAGE := 'Argument data type NUMERIC is invalid for argument 3 of conv_string_to_time 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 := format('The style %s is not supported for conversions from VARCHAR to TIME.', v_style), + DETAIL := 'Use of incorrect "style" parameter value during conversion process.', + HINT := 'Change "style" parameter to the proper value and try again.'; + + WHEN datatype_mismatch THEN + RAISE USING MESSAGE := 'Source data type should be ''TIME'' or ''TIME(n)''.', + DETAIL := 'Use of incorrect "datatype" parameter value during conversion process.', + HINT := 'Change "datatype" parameter to the proper value and try again.'; + + WHEN interval_field_overflow THEN + RAISE USING MESSAGE := 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 numeric_value_out_of_range THEN + RAISE USING MESSAGE := 'Could not extract correct hour value due to it''s inconsistency with AM|PM day part mark.', + DETAIL := 'Extracted hour value doesn''t fall in correct day part mark range: 0..12 for "AM" or 1..23 for "PM".', + HINT := 'Correct a hour value in the source string or remove AM|PM day part mark out of it.'; + + WHEN invalid_datetime_format THEN + RAISE USING MESSAGE := 'Conversion failed when converting time from character string.', + 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_text_representation THEN + GET STACKED DIAGNOSTICS v_err_message = MESSAGE_TEXT; + v_err_message := substring(lower(v_err_message), 'integer\:\s\"(.*)\"'); + + RAISE USING MESSAGE := format('Error while trying to convert "%s" value to SMALLINT data type.', + v_err_message), + DETAIL := 'Supplied value contains illegal characters.', + HINT := 'Correct supplied value, remove all illegal characters.'; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_conv_time_to_string(IN p_datatype TEXT, + IN p_src_datatype TEXT, + IN p_timeval TIME(6) WITHOUT TIME ZONE, + IN p_style NUMERIC DEFAULT 25) +RETURNS TEXT +AS +$BODY$ +DECLARE + v_hours VARCHAR; + v_style SMALLINT; + v_scale SMALLINT; + v_resmask VARCHAR; + v_fseconds VARCHAR; + v_datatype VARCHAR; + v_resstring VARCHAR; + v_lengthexpr VARCHAR; + v_res_length SMALLINT; + v_res_datatype VARCHAR; + v_src_datatype VARCHAR; + v_res_maxlength SMALLINT; + VARCHAR_MAX CONSTANT SMALLINT := 8000; + NVARCHAR_MAX CONSTANT SMALLINT := 4000; + -- We use the regex below to make sure input p_datatype is one of them + DATATYPE_REGEXP CONSTANT VARCHAR := '^\s*(CHAR|NCHAR|VARCHAR|NVARCHAR|CHARACTER VARYING)\s*$'; + -- We use the regex below to get the length of the datatype, if specified + -- For example, to get the '10' out of 'varchar(10)' + DATATYPE_MASK_REGEXP CONSTANT VARCHAR := '^\s*(?:CHAR|NCHAR|VARCHAR|NVARCHAR|CHARACTER VARYING)\s*\(\s*(\d+|MAX)\s*\)\s*$'; + SRCDATATYPE_MASK_REGEXP VARCHAR := '^\s*(?:TIME)\s*(?:\s*\(\s*(\d+)\s*\)\s*)?\s*$'; +BEGIN + v_datatype := upper(trim(p_datatype)); + v_src_datatype := upper(trim(p_src_datatype)); + v_style := floor(p_style)::SMALLINT; + + IF (v_src_datatype ~* SRCDATATYPE_MASK_REGEXP) + THEN + v_scale := coalesce(substring(v_src_datatype, SRCDATATYPE_MASK_REGEXP)::SMALLINT, 7); + + IF (v_scale NOT BETWEEN 0 AND 7) THEN + RAISE invalid_regular_expression; + END IF; + ELSE + RAISE most_specific_type_mismatch; + END IF; + + IF (v_datatype ~* DATATYPE_MASK_REGEXP) + THEN + v_res_datatype := rtrim(split_part(v_datatype, '(', 1)); + + v_res_maxlength := CASE + WHEN (v_res_datatype IN ('CHAR', 'VARCHAR')) THEN VARCHAR_MAX + ELSE NVARCHAR_MAX + END; + + v_lengthexpr := substring(v_datatype, DATATYPE_MASK_REGEXP); + + IF (v_lengthexpr <> 'MAX' AND char_length(v_lengthexpr) > 4) THEN + RAISE interval_field_overflow; + END IF; + + v_res_length := CASE v_lengthexpr + WHEN 'MAX' THEN v_res_maxlength + ELSE v_lengthexpr::SMALLINT + END; + ELSIF (v_datatype ~* DATATYPE_REGEXP) THEN + v_res_datatype := v_datatype; + ELSE + RAISE datatype_mismatch; + END IF; + + IF (scale(p_style) > 0) THEN + RAISE escape_character_conflict; + 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))) + THEN + RAISE invalid_parameter_value; + ELSIF ((v_style BETWEEN 1 AND 7) OR + (v_style BETWEEN 10 AND 12) OR + (v_style BETWEEN 101 AND 107) OR + (v_style BETWEEN 110 AND 112) OR + v_style = 23) + THEN + RAISE invalid_datetime_format; + END IF; + + v_hours := ltrim(to_char(p_timeval, 'HH12'), '0'); + v_fseconds := sys.babelfish_get_microsecs_from_fractsecs(to_char(p_timeval, 'US'), v_scale); + + IF (v_scale = 7) THEN + v_fseconds := concat(v_fseconds, '0'); + END IF; + + IF (v_style IN (0, 100)) + THEN + v_resmask := concat(v_hours, ':MIAM'); + ELSIF (v_style IN (8, 20, 24, 108, 120)) + THEN + v_resmask := 'HH24:MI:SS'; + ELSIF (v_style IN (9, 109)) + THEN + v_resmask := CASE + WHEN (char_length(v_fseconds) = 0) THEN concat(v_hours, ':MI:SSAM') + ELSE format('%s:MI:SS.%sAM', v_hours, v_fseconds) + END; + ELSIF (v_style IN (13, 14, 21, 25, 113, 114, 121, 126, 127)) + THEN + v_resmask := CASE + WHEN (char_length(v_fseconds) = 0) THEN 'HH24:MI:SS' + ELSE concat('HH24:MI:SS.', v_fseconds) + END; + ELSIF (v_style = 22) + THEN + v_resmask := format('%s:MI:SS AM', lpad(v_hours, 2, ' ')); + ELSIF (v_style IN (130, 131)) + THEN + v_resmask := CASE + WHEN (char_length(v_fseconds) = 0) THEN concat(lpad(v_hours, 2, ' '), ':MI:SSAM') + ELSE format('%s:MI:SS.%sAM', lpad(v_hours, 2, ' '), v_fseconds) + END; + END IF; + + v_resstring := to_char(p_timeval, v_resmask); + + v_resstring := substring(v_resstring, 1, coalesce(v_res_length, char_length(v_resstring))); + v_res_length := coalesce(v_res_length, + CASE v_res_datatype + WHEN 'CHAR' THEN 30 + ELSE 60 + END); + RETURN CASE + WHEN (v_res_datatype NOT IN ('CHAR', 'NCHAR')) THEN v_resstring + ELSE rpad(v_resstring, v_res_length, ' ') + END; +EXCEPTION + WHEN most_specific_type_mismatch THEN + RAISE USING MESSAGE := 'Source data type should be ''TIME'' or ''TIME(n)''.', + DETAIL := 'Use of incorrect "src_datatype" parameter value during conversion process.', + HINT := 'Change "src_datatype" parameter to the proper value and try again.'; + + WHEN invalid_regular_expression THEN + RAISE USING MESSAGE := format('The source data type scale (%s) given to the convert specification exceeds the maximum allowable value (7).', + v_scale), + DETAIL := 'Use of incorrect scale value of source data type parameter during conversion process.', + HINT := 'Change scale component of source data type parameter to the allowable value and try again.'; + + WHEN interval_field_overflow THEN + RAISE USING MESSAGE := format('The size (%s) given to the convert specification ''%s'' exceeds the maximum allowed for any data type (%s).', + v_lengthexpr, lower(v_res_datatype), v_res_maxlength), + DETAIL := 'Use of incorrect size value of target data type parameter during conversion process.', + HINT := 'Change size component of data type parameter to the allowable value and try again.'; + + WHEN escape_character_conflict THEN + RAISE USING MESSAGE := 'Argument data type NUMERIC is invalid for argument 4 of convert 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 := format('%s is not a valid style number when converting from TIME to a character string.', v_style), + DETAIL := 'Use of incorrect "style" parameter value during conversion process.', + HINT := 'Change "style" parameter to the proper value and try again.'; + + WHEN datatype_mismatch THEN + RAISE USING MESSAGE := 'Data type should be one of these values: ''CHAR(n|MAX)'', ''NCHAR(n|MAX)'', ''VARCHAR(n|MAX)'', ''NVARCHAR(n|MAX)''.', + DETAIL := 'Use of incorrect "datatype" parameter value during conversion process.', + HINT := 'Change "datatype" parameter to the proper value and try again.'; + + WHEN invalid_datetime_format THEN + RAISE USING MESSAGE := format('Error converting data type TIME to %s.', + rtrim(split_part(trim(p_datatype), '(', 1))), + 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.'; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + +create or replace function sys.babelfish_dbts() +returns bigint as +$BODY$ +declare + v_res bigint; +begin + SELECT last_value INTO v_res FROM sys_data.inc_seq_rowversion; + return v_res; +end; +$BODY$ +language plpgsql; + +CREATE OR REPLACE FUNCTION sys.babelfish_get_full_year(IN p_short_year TEXT, + IN p_base_century TEXT DEFAULT '', + IN p_year_cutoff NUMERIC DEFAULT 49) +RETURNS VARCHAR +AS +$BODY$ +DECLARE + v_err_message VARCHAR; + v_full_year SMALLINT; + v_short_year SMALLINT; + v_base_century SMALLINT; + v_result_param_set JSONB; + v_full_year_res_jsonb JSONB; +BEGIN + v_short_year := p_short_year::SMALLINT; + + BEGIN + v_full_year_res_jsonb := nullif(current_setting('sys.full_year_res_json'), '')::JSONB; + EXCEPTION + WHEN undefined_object THEN + v_full_year_res_jsonb := NULL; + END; + + SELECT result + INTO v_full_year + FROM jsonb_to_recordset(v_full_year_res_jsonb) AS result_set (param1 SMALLINT, + param2 TEXT, + param3 NUMERIC, + result VARCHAR) + WHERE param1 = v_short_year + AND param2 = p_base_century + AND param3 = p_year_cutoff; + + IF (v_full_year IS NULL) + THEN + IF (v_short_year <= 99) + THEN + v_base_century := CASE + WHEN (p_base_century ~ '^\s*([1-9]{1,2})\s*$') THEN concat(trim(p_base_century), '00')::SMALLINT + ELSE trunc(extract(year from current_date)::NUMERIC, -2) + END; + + v_full_year = v_base_century + v_short_year; + v_full_year = CASE + WHEN (v_short_year > p_year_cutoff) THEN v_full_year - 100 + ELSE v_full_year + END; + ELSE v_full_year := v_short_year; + END IF; + + v_result_param_set := jsonb_build_object('param1', v_short_year, + 'param2', p_base_century, + 'param3', p_year_cutoff, + 'result', v_full_year); + v_full_year_res_jsonb := CASE + WHEN (v_full_year_res_jsonb IS NULL) THEN jsonb_build_array(v_result_param_set) + ELSE v_full_year_res_jsonb || v_result_param_set + END; + + PERFORM set_config('sys.full_year_res_json', + v_full_year_res_jsonb::TEXT, + FALSE); + END IF; + + RETURN v_full_year; +EXCEPTION + 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 := format('Error while trying to convert "%s" value to SMALLINT data type.', + v_err_message), + DETAIL := 'Supplied value contains illegal characters.', + HINT := 'Correct supplied value, remove all illegal characters.'; +END; +$BODY$ +LANGUAGE plpgsql +STABLE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_get_int_part(IN p_srcnumber DOUBLE PRECISION) +RETURNS DOUBLE PRECISION +AS +$BODY$ +BEGIN + RETURN CASE + WHEN (p_srcnumber < -0.0000001) THEN ceil(p_srcnumber - 0.0000001) + ELSE floor(p_srcnumber + 0.0000001) + END; +END; +$BODY$ +LANGUAGE plpgsql +STABLE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_get_jobs () +RETURNS table( job integer, what text, search_path varchar ) +AS +$body$ +DECLARE + var_job integer; + var_what text; + var_search_path varchar; +BEGIN + + SELECT js.job_step_id, js.command, '' + FROM sys.sysjobschedules s + INNER JOIN sys.sysjobs j on j.job_id = s.job_id + INNER JOIN sys.sysjobsteps js ON js.job_id = j.job_id + INTO var_job, var_what, var_search_path + WHERE (s.next_run_date + s.next_run_time) <= now()::timestamp + AND j.enabled = 1 + ORDER BY (s.next_run_date + s.next_run_time) ASC + LIMIT 1; + + IF var_job > 0 + THEN + return query select var_job, var_what, var_search_path; + END IF; + +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION sys.babelfish_get_lang_metadata_json(IN p_lang_spec_culture TEXT) +RETURNS JSONB +AS +$BODY$ +DECLARE + v_locale_parts TEXT[]; + v_lang_data_jsonb JSONB; + v_lang_spec_culture VARCHAR; + v_is_cached BOOLEAN := FALSE; +BEGIN + v_lang_spec_culture := upper(trim(p_lang_spec_culture)); + + IF (char_length(v_lang_spec_culture) > 0) + THEN + BEGIN + v_lang_data_jsonb := nullif(current_setting(format('sys.lang_metadata_json.%s', + v_lang_spec_culture)), '')::JSONB; + EXCEPTION + WHEN undefined_object THEN + v_lang_data_jsonb := NULL; + END; + + IF (v_lang_data_jsonb IS NULL) + THEN + IF (v_lang_spec_culture IN ('AR', 'FI') OR + v_lang_spec_culture ~ '-') + THEN + SELECT lang_data_jsonb + INTO STRICT v_lang_data_jsonb + FROM sys.syslanguages + WHERE spec_culture = v_lang_spec_culture; + ELSE + SELECT lang_data_jsonb + INTO STRICT v_lang_data_jsonb + FROM sys.syslanguages + WHERE lang_name_mssql = v_lang_spec_culture + OR lang_alias_mssql = v_lang_spec_culture; + END IF; + ELSE + v_is_cached := TRUE; + END IF; + ELSE + v_lang_spec_culture := current_setting('LC_TIME'); + + v_lang_spec_culture := CASE + WHEN (v_lang_spec_culture !~ '\.') THEN v_lang_spec_culture + ELSE substring(v_lang_spec_culture, '(.*)(?:\.)') + END; + + v_lang_spec_culture := upper(regexp_replace(v_lang_spec_culture, '_|,\s*', '-', 'gi')); + + BEGIN + v_lang_data_jsonb := nullif(current_setting(format('sys.lang_metadata_json.%s', + v_lang_spec_culture)), '')::JSONB; + EXCEPTION + WHEN undefined_object THEN + v_lang_data_jsonb := NULL; + END; + + IF (v_lang_data_jsonb IS NULL) + THEN + BEGIN + IF (char_length(v_lang_spec_culture) = 5) + THEN + SELECT lang_data_jsonb + INTO STRICT v_lang_data_jsonb + FROM sys.syslanguages + WHERE spec_culture = v_lang_spec_culture; + ELSE + v_locale_parts := string_to_array(v_lang_spec_culture, '-'); + + SELECT lang_data_jsonb + INTO STRICT v_lang_data_jsonb + FROM sys.syslanguages + WHERE lang_name_pg = v_locale_parts[1] + AND territory = v_locale_parts[2]; + END IF; + EXCEPTION + WHEN OTHERS THEN + v_lang_spec_culture := 'EN-US'; + + SELECT lang_data_jsonb + INTO v_lang_data_jsonb + FROM sys.syslanguages + WHERE spec_culture = v_lang_spec_culture; + END; + ELSE + v_is_cached := TRUE; + END IF; + END IF; + + IF (NOT v_is_cached) THEN + PERFORM set_config(format('sys.lang_metadata_json.%s', + v_lang_spec_culture), + v_lang_data_jsonb::TEXT, + FALSE); + END IF; + + RETURN v_lang_data_jsonb; +EXCEPTION + WHEN invalid_text_representation THEN + RAISE USING MESSAGE := format('The language metadata JSON value extracted from chache is not a valid JSON object.', + p_lang_spec_culture), + HINT := 'Drop the current session, fix the appropriate record in "sys.syslanguages" table, and try again after reconnection.'; + + WHEN OTHERS THEN + RAISE USING MESSAGE := format('"%s" is not a valid special culture or language name parameter.', + p_lang_spec_culture), + DETAIL := 'Use of incorrect "lang_spec_culture" parameter value during conversion process.', + HINT := 'Change "lang_spec_culture" parameter to the proper value and try again.'; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE; + +CREATE OR REPLACE FUNCTION sys.babelfish_get_microsecs_from_fractsecs(IN p_fractsecs TEXT, + IN p_scale NUMERIC DEFAULT 7) +RETURNS VARCHAR +AS +$BODY$ +DECLARE + v_scale SMALLINT; + v_decplaces INTEGER; + v_fractsecs VARCHAR; + v_pureplaces VARCHAR; + v_rnd_fractsecs INTEGER; + v_fractsecs_len INTEGER; + v_pureplaces_len INTEGER; + v_err_message VARCHAR; +BEGIN + v_fractsecs := trim(p_fractsecs); + v_fractsecs_len := char_length(v_fractsecs); + v_scale := floor(p_scale)::SMALLINT; + + IF (v_fractsecs_len < 7) THEN + v_fractsecs := rpad(v_fractsecs, 7, '0'); + v_fractsecs_len := char_length(v_fractsecs); + END IF; + + v_pureplaces := trim(leading '0' from v_fractsecs); + v_pureplaces_len := char_length(v_pureplaces); + + v_decplaces := v_fractsecs_len - v_pureplaces_len; + + v_rnd_fractsecs := round(v_fractsecs::INTEGER, (v_pureplaces_len - (v_scale - (v_fractsecs_len - v_pureplaces_len))) * (-1)); + + v_fractsecs := concat(replace(rpad('', v_decplaces), ' ', '0'), v_rnd_fractsecs); + + RETURN substring(v_fractsecs, 1, CASE + WHEN (v_scale >= 7) THEN 6 + ELSE v_scale + END); +EXCEPTION + 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 := format('Error while trying to convert "%s" value to SMALLINT data type.', v_err_message), + DETAIL := 'Supplied value contains illegal characters.', + HINT := 'Correct supplied value, remove all illegal characters.'; +END; +$BODY$ +LANGUAGE plpgsql +STABLE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_get_monthnum_by_name(IN p_monthname TEXT, + IN p_lang_metadata_json JSONB) +RETURNS VARCHAR +AS +$BODY$ +DECLARE + v_monthname TEXT; + v_monthnum SMALLINT; +BEGIN + v_monthname := lower(trim(p_monthname)); + + v_monthnum := array_position(ARRAY(SELECT lower(jsonb_array_elements_text(p_lang_metadata_json -> 'months_shortnames'))), v_monthname); + + v_monthnum := coalesce(v_monthnum, + array_position(ARRAY(SELECT lower(jsonb_array_elements_text(p_lang_metadata_json -> 'months_names'))), v_monthname)); + + v_monthnum := coalesce(v_monthnum, + array_position(ARRAY(SELECT lower(jsonb_array_elements_text(p_lang_metadata_json -> 'months_extrashortnames'))), v_monthname)); + + v_monthnum := coalesce(v_monthnum, + array_position(ARRAY(SELECT lower(jsonb_array_elements_text(p_lang_metadata_json -> 'months_extranames'))), v_monthname)); + + IF (v_monthnum IS NULL) THEN + RAISE datetime_field_overflow; + END IF; + + RETURN v_monthnum; +EXCEPTION + WHEN datetime_field_overflow THEN + RAISE USING MESSAGE := format('Can not convert value "%s" to a correct month number.', + trim(p_monthname)), + DETAIL := 'Supplied month name is not valid.', + HINT := 'Correct supplied month name value and try again.'; +END; +$BODY$ +LANGUAGE plpgsql +IMMUTABLE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_get_service_setting ( + IN p_service sys.service_settings.service%TYPE + , IN p_setting sys.service_settings.setting%TYPE +) +RETURNS sys.service_settings.value%TYPE +AS +$BODY$ +DECLARE + settingValue sys.service_settings.value%TYPE; +BEGIN + SELECT value + INTO settingValue + FROM sys.service_settings + WHERE service = p_service + AND setting = p_setting; + + RETURN settingValue; +END; +$BODY$ +LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION sys.babelfish_get_timeunit_from_string(IN p_timepart TEXT, + IN p_timeunit TEXT) +RETURNS VARCHAR +AS +$BODY$ +DECLARE + v_hours VARCHAR; + v_minutes VARCHAR; + v_seconds VARCHAR; + v_fractsecs VARCHAR; + v_daypart VARCHAR; + v_timepart VARCHAR; + v_timeunit VARCHAR; + v_err_message VARCHAR; + v_timeunit_mask VARCHAR; + v_regmatch_groups TEXT[]; + AMPM_REGEXP CONSTANT VARCHAR := '\s*([AP]M)'; + TIMEUNIT_REGEXP CONSTANT VARCHAR := '\s*(\d{1,2})\s*'; + FRACTSECS_REGEXP CONSTANT VARCHAR := '\s*(\d{1,9})'; + HHMMSSFS_REGEXP CONSTANT VARCHAR := concat('^', TIMEUNIT_REGEXP, + '\:', TIMEUNIT_REGEXP, + '\:', TIMEUNIT_REGEXP, + '(?:\.|\:)', FRACTSECS_REGEXP, '$'); + HHMMSS_REGEXP CONSTANT VARCHAR := concat('^', TIMEUNIT_REGEXP, '\:', TIMEUNIT_REGEXP, '\:', TIMEUNIT_REGEXP, '$'); + HHMMFS_REGEXP CONSTANT VARCHAR := concat('^', TIMEUNIT_REGEXP, '\:', TIMEUNIT_REGEXP, '\.', FRACTSECS_REGEXP, '$'); + HHMM_REGEXP CONSTANT VARCHAR := concat('^', TIMEUNIT_REGEXP, '\:', TIMEUNIT_REGEXP, '$'); + HH_REGEXP CONSTANT VARCHAR := concat('^', TIMEUNIT_REGEXP, '$'); +BEGIN + v_timepart := upper(trim(p_timepart)); + v_timeunit := upper(trim(p_timeunit)); + + v_daypart := substring(v_timepart, 'AM|PM'); + v_timepart := trim(regexp_replace(v_timepart, coalesce(v_daypart, ''), '')); + + v_timeunit_mask := + CASE + WHEN (v_timepart ~* HHMMSSFS_REGEXP) THEN HHMMSSFS_REGEXP + WHEN (v_timepart ~* HHMMSS_REGEXP) THEN HHMMSS_REGEXP + WHEN (v_timepart ~* HHMMFS_REGEXP) THEN HHMMFS_REGEXP + WHEN (v_timepart ~* HHMM_REGEXP) THEN HHMM_REGEXP + WHEN (v_timepart ~* HH_REGEXP) THEN HH_REGEXP + END; + + v_regmatch_groups := regexp_matches(v_timepart, v_timeunit_mask, 'gi'); + + v_hours := v_regmatch_groups[1]; + v_minutes := v_regmatch_groups[2]; + + IF (v_timepart ~* HHMMFS_REGEXP) THEN + v_fractsecs := v_regmatch_groups[3]; + ELSE + v_seconds := v_regmatch_groups[3]; + v_fractsecs := v_regmatch_groups[4]; + END IF; + + IF (v_timeunit = 'HOURS' AND v_daypart IS NOT NULL) + THEN + IF ((v_daypart = 'AM' AND v_hours::SMALLINT NOT BETWEEN 0 AND 12) OR + (v_daypart = 'PM' AND v_hours::SMALLINT NOT BETWEEN 1 AND 23)) + THEN + RAISE numeric_value_out_of_range; + ELSIF (v_daypart = 'PM' AND v_hours::SMALLINT < 12) THEN + v_hours := (v_hours::SMALLINT + 12)::VARCHAR; + ELSIF (v_daypart = 'AM' AND v_hours::SMALLINT = 12) THEN + v_hours := (v_hours::SMALLINT - 12)::VARCHAR; + END IF; + END IF; + + RETURN CASE v_timeunit + WHEN 'HOURS' THEN v_hours + WHEN 'MINUTES' THEN v_minutes + WHEN 'SECONDS' THEN v_seconds + WHEN 'FRACTSECONDS' THEN v_fractsecs + END; +EXCEPTION + WHEN numeric_value_out_of_range THEN + RAISE USING MESSAGE := 'Could not extract correct hour value due to it''s inconsistency with AM|PM day part mark.', + DETAIL := 'Extracted hour value doesn''t fall in correct day part mark range: 0..12 for "AM" or 1..23 for "PM".', + HINT := 'Correct a hour value in the source string or remove AM|PM day part mark out of it.'; + + 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 := format('Error while trying to convert "%s" value to SMALLINT data type.', v_err_message), + DETAIL := 'Supplied value contains illegal characters.', + HINT := 'Correct supplied value, remove all illegal characters.'; +END; +$BODY$ +LANGUAGE plpgsql +IMMUTABLE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_get_version(pComponentName VARCHAR(256)) + RETURNS VARCHAR(256) AS +$BODY$ +DECLARE + lComponentVersion VARCHAR(256); +BEGIN + SELECT componentversion + INTO lComponentVersion + FROM sys.versions + WHERE extpackcomponentname = pComponentName; + + RETURN lComponentVersion; +END; +$BODY$ +LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION sys.babelfish_get_weekdaynum_by_name(IN p_weekdayname TEXT, + IN p_lang_metadata_json JSONB) +RETURNS SMALLINT +AS +$BODY$ +DECLARE + v_weekdayname TEXT; + v_weekdaynum SMALLINT; +BEGIN + v_weekdayname := lower(trim(p_weekdayname)); + + v_weekdaynum := array_position(ARRAY(SELECT lower(jsonb_array_elements_text(p_lang_metadata_json -> 'days_names'))), v_weekdayname); + + v_weekdaynum := coalesce(v_weekdaynum, + array_position(ARRAY(SELECT lower(jsonb_array_elements_text(p_lang_metadata_json -> 'days_shortnames'))), v_weekdayname)); + + v_weekdaynum := coalesce(v_weekdaynum, + array_position(ARRAY(SELECT lower(jsonb_array_elements_text(p_lang_metadata_json -> 'days_extrashortnames'))), v_weekdayname)); + + IF (v_weekdaynum IS NULL) THEN + RAISE datetime_field_overflow; + END IF; + + RETURN v_weekdaynum; +EXCEPTION + WHEN datetime_field_overflow THEN + RAISE USING MESSAGE := format('Can not convert value "%s" to a correct weekday number.', + trim(p_weekdayname)), + DETAIL := 'Supplied weekday name is not valid.', + HINT := 'Correct supplied weekday name value and try again.'; +END; +$BODY$ +LANGUAGE plpgsql +IMMUTABLE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_is_ossp_present() +RETURNS BOOLEAN AS +$BODY$ +DECLARE + result SMALLINT; +BEGIN + select + case when exists + (select 1 from pg_extension where extname = 'uuid-ossp') + then 1 + else 0 end + INTO result; + + RETURN (result = 1); +END; +$BODY$ +LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION sys.babelfish_is_spatial_present() +RETURNS BOOLEAN AS +$BODY$ +DECLARE + result SMALLINT; +BEGIN + select + case when exists + (select 1 from pg_extension where extname = 'postgis') + then 1 + else 0 end + INTO result; + + RETURN (result = 1); +END; +$BODY$ +LANGUAGE plpgsql; + +create or replace function sys.babelfish_istime(v text) +returns boolean +as +$body$ +begin + perform v::time; + return true; +exception + when others then + return false; +end +$body$ +language 'plpgsql'; + +-- Remove closing square brackets at both ends, otherwise do nothing. +CREATE OR REPLACE FUNCTION sys.babelfish_single_unbracket_name(IN name TEXT) +RETURNS TEXT AS +$BODY$ +BEGIN + IF length(name) >= 2 AND left(name, 1) = '[' AND right(name, 1) = ']' THEN + IF length(name) = 2 THEN + RETURN ''; + ELSE + RETURN substring(name from 2 for length(name)-2); + END IF; + END IF; + RETURN name; +END; +$BODY$ +LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION sys.babelfish_openxml(IN DocHandle BIGINT) + RETURNS TABLE (XmlData XML) +AS +$BODY$ +DECLARE + XmlDocument$data XML; +BEGIN + + SELECT t.XmlData + INTO STRICT XmlDocument$data + FROM sys$openxml t + WHERE t.DocID = DocHandle; + + RETURN QUERY SELECT XmlDocument$data; + + EXCEPTION + WHEN SQLSTATE '42P01' OR SQLSTATE 'P0002' THEN + RAISE EXCEPTION '%','Could not find prepared statement with handle '||CASE + WHEN DocHandle IS NULL THEN 'null' + ELSE DocHandle::TEXT + END; +END; +$BODY$ +LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION sys.babelfish_parse_to_date(IN p_datestring TEXT, + IN p_culture TEXT DEFAULT '') +RETURNS DATE +AS +$BODY$ +DECLARE + v_day VARCHAR; + v_year SMALLINT; + v_month VARCHAR; + v_res_date DATE; + v_hijridate DATE; + v_culture VARCHAR; + v_dayparts TEXT[]; + v_resmask VARCHAR; + v_raw_year VARCHAR; + v_left_part VARCHAR; + v_right_part VARCHAR; + v_resmask_fi VARCHAR; + v_datestring VARCHAR; + v_timestring VARCHAR; + v_correctnum VARCHAR; + v_weekdaynum SMALLINT; + v_err_message VARCHAR; + v_date_format VARCHAR; + v_weekdaynames TEXT[]; + v_hours SMALLINT := 0; + v_minutes SMALLINT := 0; + v_seconds NUMERIC := 0; + v_found BOOLEAN := TRUE; + v_compday_regexp VARCHAR; + v_regmatch_groups TEXT[]; + v_compmonth_regexp VARCHAR; + v_lang_metadata_json JSONB; + v_resmask_cnt SMALLINT := 10; + DAYMM_REGEXP CONSTANT VARCHAR := '(\d{1,2})'; + FULLYEAR_REGEXP CONSTANT VARCHAR := '(\d{3,4})'; + SHORTYEAR_REGEXP CONSTANT VARCHAR := '(\d{1,2})'; + COMPYEAR_REGEXP CONSTANT VARCHAR := '(\d{1,4})'; + AMPM_REGEXP CONSTANT VARCHAR := '(?:[AP]M|ص|م)'; + TIMEUNIT_REGEXP CONSTANT VARCHAR := '\s*\d{1,2}\s*'; + MASKSEPONE_REGEXP CONSTANT VARCHAR := '\s*(?:/|-)?'; + MASKSEPTWO_REGEXP CONSTANT VARCHAR := '\s*(?:\s|/|-|\.|,)'; + MASKSEPTWO_FI_REGEXP CONSTANT VARCHAR := '\s*(?:\s|/|-|,)'; + MASKSEPTHREE_REGEXP CONSTANT VARCHAR := '\s*(?:/|-|\.|,)'; + TIME_MASKSEP_REGEXP CONSTANT VARCHAR := '(?:\s|\.|,)*'; + TIME_MASKSEP_FI_REGEXP CONSTANT VARCHAR := '(?:\s|,)*'; + WEEKDAYAMPM_START_REGEXP CONSTANT VARCHAR := '(^|[[:digit:][:space:]\.,])'; + WEEKDAYAMPM_END_REGEXP CONSTANT VARCHAR := '([[:digit:][:space:]\.,]|$)(?=[^/-]|$)'; + CORRECTNUM_REGEXP CONSTANT VARCHAR := '(?:([+-]\d{1,4})(?:[[:space:]\.,]|[AP]M|ص|م|$))'; + ANNO_DOMINI_REGEXP VARCHAR := '(AD|A\.D\.)'; + ANNO_DOMINI_COMPREGEXP VARCHAR := concat(WEEKDAYAMPM_START_REGEXP, ANNO_DOMINI_REGEXP, WEEKDAYAMPM_END_REGEXP); + HHMMSSFS_PART_REGEXP CONSTANT VARCHAR := + concat(TIMEUNIT_REGEXP, AMPM_REGEXP, '|', + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, TIMEUNIT_REGEXP, '\:', TIME_MASKSEP_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, TIMEUNIT_REGEXP, '(?!\d)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?|', + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, TIMEUNIT_REGEXP, '\:', TIME_MASKSEP_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, TIMEUNIT_REGEXP, '\:', TIME_MASKSEP_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, TIMEUNIT_REGEXP, '(?!\d)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?|', + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, TIMEUNIT_REGEXP, '\:', TIME_MASKSEP_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, TIMEUNIT_REGEXP, '\:', TIME_MASKSEP_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\s*\d{1,2}\.\d+(?!\d)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?|', + AMPM_REGEXP, '?'); + HHMMSSFS_PART_FI_REGEXP CONSTANT VARCHAR := + concat(TIMEUNIT_REGEXP, AMPM_REGEXP, '|', + AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, TIMEUNIT_REGEXP, '[\:\.]', TIME_MASKSEP_FI_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, TIMEUNIT_REGEXP, '(?!\d)', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?\.?|', + AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, TIMEUNIT_REGEXP, '[\:\.]', TIME_MASKSEP_FI_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, TIMEUNIT_REGEXP, '[\:\.]', TIME_MASKSEP_FI_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, TIMEUNIT_REGEXP, '(?!\d)', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?|', + AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, TIMEUNIT_REGEXP, '[\:\.]', TIME_MASKSEP_FI_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, TIMEUNIT_REGEXP, '[\:\.]', TIME_MASKSEP_FI_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, '\s*\d{1,2}\.\d+(?!\d)\.?', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?|', + AMPM_REGEXP, '?'); + v_defmask1_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, + '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, + CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + TIME_MASKSEP_REGEXP, '(?:[\.|,]+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)', TIME_MASKSEP_REGEXP, '$'); + v_defmask1_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, CORRECTNUM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, + '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_FI_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:', MASKSEPTWO_FI_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, + CORRECTNUM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:[,]+', AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, CORRECTNUM_REGEXP, '?))', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + TIME_MASKSEP_FI_REGEXP, '(?:[\.|,]+', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask2_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, + '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, + AMPM_REGEXP, TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + TIME_MASKSEP_REGEXP, '(?:(?:[\.|,]+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?)|', + CORRECTNUM_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, '$'); + v_defmask2_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, CORRECTNUM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, + '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + CORRECTNUM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_FI_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_FI_REGEXP, CORRECTNUM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, + AMPM_REGEXP, TIME_MASKSEP_FI_REGEXP, CORRECTNUM_REGEXP, '?))', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + TIME_MASKSEP_FI_REGEXP, '(?:(?:[\.|,]+', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, TIME_MASKSEP_FI_REGEXP, CORRECTNUM_REGEXP, '?)|', + CORRECTNUM_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask3_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, ')|', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + TIME_MASKSEP_REGEXP, '(', TIME_MASKSEP_REGEXP, AMPM_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask3_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + TIME_MASKSEP_FI_REGEXP, '[\./]?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)', + FULLYEAR_REGEXP, + TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask4_0_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, '\s*(', AMPM_REGEXP, ')', + TIME_MASKSEP_REGEXP, '$'); + v_defmask4_1_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:\s|,)+', + DAYMM_REGEXP, '\s*(', AMPM_REGEXP, ')', + TIME_MASKSEP_REGEXP, '$'); + v_defmask4_2_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '\s*[\.]+', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, '\s*(', AMPM_REGEXP, ')', + TIME_MASKSEP_REGEXP, '$'); + v_defmask5_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask5_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_FI_REGEXP, + FULLYEAR_REGEXP, + TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask6_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '((?:(?:\s|\.|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_REGEXP, '))?', TIME_MASKSEP_REGEXP, '$'); + v_defmask6_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:\s*[\.])?', + '((?:(?:\s|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_FI_REGEXP, '))?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask7_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '((?:(?:\s|\.|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_REGEXP, '))?', TIME_MASKSEP_REGEXP, '$'); + v_defmask7_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_FI_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '((?:(?:\s|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_FI_REGEXP, '))?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask8_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:[\.|,]+', AMPM_REGEXP, ')?', + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask8_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_FI_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:[,]+', AMPM_REGEXP, '))', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:[,]+', AMPM_REGEXP, '))', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:(?:[\,]+|\s*/\s*)', AMPM_REGEXP, ')?', + TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask9_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', + HHMMSSFS_PART_REGEXP, + ')', TIME_MASKSEP_REGEXP, '$'); + v_defmask9_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, '(', + HHMMSSFS_PART_FI_REGEXP, + ')', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask10_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)?', TIME_MASKSEP_REGEXP, + '($comp_month$)', + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask10_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)?', TIME_MASKSEP_REGEXP, + '($comp_month$)', + TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask11_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask11_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '((?:(?:\s|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_FI_REGEXP, '))?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask12_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask12_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask13_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$'); + v_defmask13_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask14_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + '($comp_month$)' + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)', TIME_MASKSEP_REGEXP, + COMPYEAR_REGEXP, + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask14_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + '($comp_month$)' + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)', TIME_MASKSEP_FI_REGEXP, + COMPYEAR_REGEXP, + '((?:(?:\s|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_FI_REGEXP, '))?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask15_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + COMPYEAR_REGEXP, + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask15_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + COMPYEAR_REGEXP, + '((?:(?:\s|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_FI_REGEXP, '))?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask16_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)', TIME_MASKSEP_REGEXP, + COMPYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask16_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)', TIME_MASKSEP_REGEXP, + COMPYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask17_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask17_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '((?:(?:\s|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_FI_REGEXP, '))?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask18_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask18_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask19_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '((?:(?:\s|\.|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_REGEXP, '))?', TIME_MASKSEP_REGEXP, '$'); + v_defmask19_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '((?:(?:\s|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_FI_REGEXP, '))?', TIME_MASKSEP_FI_REGEXP, '$'); + CONVERSION_LANG CONSTANT VARCHAR := ''; + DATE_FORMAT CONSTANT VARCHAR := ''; +BEGIN + v_datestring := upper(trim(p_datestring)); + v_culture := coalesce(nullif(upper(trim(p_culture)), ''), 'EN-US'); + + v_dayparts := ARRAY(SELECT upper(array_to_string(regexp_matches(v_datestring, '[AP]M|ص|م', 'gi'), ''))); + + IF (array_length(v_dayparts, 1) > 1) THEN + RAISE invalid_datetime_format; + END IF; + + BEGIN + v_lang_metadata_json := sys.babelfish_get_lang_metadata_json(coalesce(nullif(CONVERSION_LANG, ''), p_culture)); + EXCEPTION + WHEN OTHERS THEN + RAISE invalid_parameter_value; + END; + + v_compday_regexp := array_to_string(array_cat(array_cat(ARRAY(SELECT jsonb_array_elements_text(v_lang_metadata_json -> 'days_names')), + ARRAY(SELECT jsonb_array_elements_text(v_lang_metadata_json -> 'days_shortnames'))), + ARRAY(SELECT jsonb_array_elements_text(v_lang_metadata_json -> 'days_extrashortnames'))), '|'); + + v_weekdaynames := ARRAY(SELECT array_to_string(regexp_matches(v_datestring, v_compday_regexp, 'gi'), '')); + + IF (array_length(v_weekdaynames, 1) > 1) THEN + RAISE invalid_datetime_format; + END IF; + + IF (v_weekdaynames[1] IS NOT NULL AND + v_datestring ~* concat(WEEKDAYAMPM_START_REGEXP, '(', v_compday_regexp, ')', WEEKDAYAMPM_END_REGEXP)) + THEN + v_datestring := replace(v_datestring, v_weekdaynames[1], ' '); + END IF; + + IF (v_datestring ~* ANNO_DOMINI_COMPREGEXP) + THEN + IF (v_culture !~ 'EN[-_]US|DA[-_]DK|SV[-_]SE|EN[-_]GB|HI[-_]IS') THEN + RAISE invalid_datetime_format; + END IF; + + v_datestring := regexp_replace(v_datestring, + ANNO_DOMINI_COMPREGEXP, + regexp_replace(array_to_string(regexp_matches(v_datestring, ANNO_DOMINI_COMPREGEXP, 'gi'), ''), + ANNO_DOMINI_REGEXP, ' ', 'gi'), + 'gi'); + END IF; + + v_date_format := coalesce(nullif(upper(trim(DATE_FORMAT)), ''), v_lang_metadata_json ->> 'date_format'); + + v_compmonth_regexp := + array_to_string(array_cat(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'))), + array_cat(ARRAY(SELECT jsonb_array_elements_text(v_lang_metadata_json -> 'months_extrashortnames')), + ARRAY(SELECT jsonb_array_elements_text(v_lang_metadata_json -> 'months_extranames'))) + ), '|'); + + IF ((v_datestring ~* v_defmask1_regexp AND v_culture <> 'FI') OR + (v_datestring ~* v_defmask1_fi_regexp AND v_culture = 'FI')) + THEN + IF (v_datestring ~ concat(CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d+\s*(?:\.)+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, + CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}|', + '\d+\s*(?:\.)+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, + CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$') AND + v_culture ~ 'DE[-_]DE|NN[-_]NO|CS[-_]CZ|PL[-_]PL|RO[-_]RO|SK[-_]SK|SL[-_]SI|BG[-_]BG|RU[-_]RU|TR[-_]TR|ET[-_]EE|LV[-_]LV') + THEN + RAISE invalid_datetime_format; + END IF; + + v_regmatch_groups := regexp_matches(v_datestring, CASE v_culture + WHEN 'FI' THEN v_defmask1_fi_regexp + ELSE v_defmask1_regexp + END, 'gi'); + v_timestring := v_regmatch_groups[2]; + v_correctnum := coalesce(v_regmatch_groups[1], v_regmatch_groups[3], + v_regmatch_groups[5], v_regmatch_groups[6]); + + IF (v_date_format = 'DMY' OR + v_culture IN ('SV-SE', 'SV_SE', 'LV-LV', 'LV_LV')) + THEN + v_day := v_regmatch_groups[4]; + v_month := v_regmatch_groups[7]; + ELSE + v_day := v_regmatch_groups[7]; + v_month := v_regmatch_groups[4]; + END IF; + + IF (v_culture IN ('AR', 'AR-SA', 'AR_SA')) + THEN + IF (v_day::SMALLINT > 30 OR + v_month::SMALLINT > 12) THEN + RAISE invalid_datetime_format; + END IF; + + v_raw_year := to_char(sys.babelfish_conv_greg_to_hijri(current_date + 1), 'YYYY'); + v_hijridate := sys.babelfish_conv_hijri_to_greg(v_day, v_month, v_raw_year) - 1; + + v_day := to_char(v_hijridate, 'DD'); + v_month := to_char(v_hijridate, 'MM'); + v_year := to_char(v_hijridate, 'YYYY')::SMALLINT; + ELSE + v_year := to_char(current_date, 'YYYY')::SMALLINT; + END IF; + + ELSIF ((v_datestring ~* v_defmask6_regexp AND v_culture <> 'FI') OR + (v_datestring ~* v_defmask6_fi_regexp AND v_culture = 'FI')) + THEN + IF (v_culture IN ('AR', 'AR-SA', 'AR_SA') OR + (v_datestring ~ concat('\s*\d{1,2}\.\s*(?:\.|\d+(?!\d)\s*\.)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{3,4}', + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, '\d{1,2}|', + '\d{3,4}', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}', MASKSEPTWO_REGEXP, + TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}\s*(?:\.)+|', + '\d+\s*(?:\.)+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$') AND + v_culture ~ 'DE[-_]DE|NN[-_]NO|CS[-_]CZ|PL[-_]PL|RO[-_]RO|SK[-_]SK|SL[-_]SI|BG[-_]BG|RU[-_]RU|TR[-_]TR|ET[-_]EE|LV[-_]LV')) + THEN + RAISE invalid_datetime_format; + END IF; + + v_regmatch_groups := regexp_matches(v_datestring, CASE v_culture + WHEN 'FI' THEN v_defmask6_fi_regexp + ELSE v_defmask6_regexp + END, 'gi'); + v_timestring := concat(v_regmatch_groups[1], v_regmatch_groups[5]); + v_day := v_regmatch_groups[4]; + v_month := v_regmatch_groups[3]; + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN v_regmatch_groups[2]::SMALLINT - 543 + ELSE v_regmatch_groups[2]::SMALLINT + END; + + ELSIF ((v_datestring ~* v_defmask2_regexp AND v_culture <> 'FI') OR + (v_datestring ~* v_defmask2_fi_regexp AND v_culture = 'FI')) + THEN + IF (v_culture IN ('AR', 'AR-SA', 'AR_SA') OR + (v_datestring ~ concat('\s*\d{1,2}\.\s*(?:\.|\d+(?!\d)\s*\.)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{3,4}', + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, + AMPM_REGEXP, TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?))', TIME_MASKSEP_REGEXP, '\d{1,2}|', + '\d+\s*(?:\.)+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$') AND + v_culture ~ 'DE[-_]DE|NN[-_]NO|CS[-_]CZ|PL[-_]PL|RO[-_]RO|SK[-_]SK|SL[-_]SI|BG[-_]BG|RU[-_]RU|TR[-_]TR|ET[-_]EE|LV[-_]LV')) + THEN + RAISE invalid_datetime_format; + END IF; + + v_regmatch_groups := regexp_matches(v_datestring, CASE v_culture + WHEN 'FI' THEN v_defmask2_fi_regexp + ELSE v_defmask2_regexp + END, 'gi'); + v_timestring := v_regmatch_groups[2]; + v_correctnum := coalesce(v_regmatch_groups[1], v_regmatch_groups[3], v_regmatch_groups[5], + v_regmatch_groups[6], v_regmatch_groups[8], v_regmatch_groups[9]); + v_day := '01'; + v_month := v_regmatch_groups[7]; + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN v_regmatch_groups[4]::SMALLINT - 543 + ELSE v_regmatch_groups[4]::SMALLINT + END; + + ELSIF (v_datestring ~* v_defmask4_1_regexp OR + (v_datestring ~* v_defmask4_2_regexp AND v_culture !~ 'DE[-_]DE|NN[-_]NO|CS[-_]CZ|PL[-_]PL|RO[-_]RO|SK[-_]SK|SL[-_]SI|BG[-_]BG|RU[-_]RU|TR[-_]TR|ET[-_]EE|LV[-_]LV') OR + (v_datestring ~* v_defmask9_regexp AND v_culture <> 'FI') OR + (v_datestring ~* v_defmask9_fi_regexp AND v_culture = 'FI')) + THEN + IF (v_datestring ~ concat('\d+\s*\.?(?:,+|,*', AMPM_REGEXP, ')', TIME_MASKSEP_FI_REGEXP, '\.+', TIME_MASKSEP_REGEXP, '$|', + '\d+\s*\.', TIME_MASKSEP_FI_REGEXP, '\.', TIME_MASKSEP_FI_REGEXP, '$') AND + v_culture = 'FI') + THEN + RAISE invalid_datetime_format; + END IF; + + IF (v_datestring ~* v_defmask4_0_regexp) THEN + v_timestring := (regexp_matches(v_datestring, v_defmask4_0_regexp, 'gi'))[1]; + ELSE + v_timestring := v_datestring; + END IF; + + v_res_date := current_date; + v_day := to_char(v_res_date, 'DD'); + v_month := to_char(v_res_date, 'MM'); + v_year := to_char(v_res_date, 'YYYY')::SMALLINT; + + ELSIF ((v_datestring ~* v_defmask3_regexp AND v_culture <> 'FI') OR + (v_datestring ~* v_defmask3_fi_regexp AND v_culture = 'FI')) + THEN + IF (v_culture IN ('AR', 'AR-SA', 'AR_SA') OR + (v_datestring ~ concat('\s*\d{1,2}\.\s*(?:\.|\d+(?!\d)\s*\.)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', + TIME_MASKSEP_REGEXP, '\d{1,2}', MASKSEPTWO_REGEXP, '|', + '\d+\s*(?:\.)+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$') AND + v_culture ~ 'DE[-_]DE|NN[-_]NO|CS[-_]CZ|PL[-_]PL|RO[-_]RO|SK[-_]SK|SL[-_]SI|BG[-_]BG|RU[-_]RU|TR[-_]TR|ET[-_]EE|LV[-_]LV')) + THEN + RAISE invalid_datetime_format; + END IF; + + v_regmatch_groups := regexp_matches(v_datestring, CASE v_culture + WHEN 'FI' THEN v_defmask3_fi_regexp + ELSE v_defmask3_regexp + END, 'gi'); + v_timestring := v_regmatch_groups[1]; + v_day := '01'; + v_month := v_regmatch_groups[2]; + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN v_regmatch_groups[3]::SMALLINT - 543 + ELSE v_regmatch_groups[3]::SMALLINT + END; + + ELSIF ((v_datestring ~* v_defmask5_regexp AND v_culture <> 'FI') OR + (v_datestring ~* v_defmask5_fi_regexp AND v_culture = 'FI')) + THEN + IF (v_culture IN ('AR', 'AR-SA', 'AR_SA') OR + (v_datestring ~ concat('\s*\d{1,2}\.\s*(?:\.|\d+(?!\d)\s*\.)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}', MASKSEPTWO_REGEXP, + TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}', MASKSEPTWO_REGEXP, + TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{3,4}', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$|', + '\d{1,2}', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{3,4}\s*(?:\.)+|', + '\d+\s*(?:\.)+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$') AND + v_culture ~ 'DE[-_]DE|NN[-_]NO|CS[-_]CZ|PL[-_]PL|RO[-_]RO|SK[-_]SK|SL[-_]SI|BG[-_]BG|RU[-_]RU|TR[-_]TR|ET[-_]EE|LV[-_]LV')) + THEN + RAISE invalid_datetime_format; + END IF; + + v_regmatch_groups := regexp_matches(v_datestring, v_defmask5_regexp, 'gi'); + v_timestring := concat(v_regmatch_groups[1], v_regmatch_groups[5]); + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN v_regmatch_groups[4]::SMALLINT - 543 + ELSE v_regmatch_groups[4]::SMALLINT + END; + + IF (v_date_format = 'DMY' OR + v_culture IN ('LV-LV', 'LV_LV')) + THEN + v_day := v_regmatch_groups[2]; + v_month := v_regmatch_groups[3]; + ELSE + v_day := v_regmatch_groups[3]; + v_month := v_regmatch_groups[2]; + END IF; + + ELSIF ((v_datestring ~* v_defmask7_regexp AND v_culture <> 'FI') OR + (v_datestring ~* v_defmask7_fi_regexp AND v_culture = 'FI')) + THEN + IF (v_culture IN ('AR', 'AR-SA', 'AR_SA') OR + (v_datestring ~ concat('\s*\d{1,2}\.\s*(?:\.|\d+(?!\d)\s*\.)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}', + MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{3,4}|', + '\d{3,4}', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}\s*(?:\.)+|', + '\d+\s*(?:\.)+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$') AND + v_culture ~ 'DE[-_]DE|NN[-_]NO|CS[-_]CZ|PL[-_]PL|RO[-_]RO|SK[-_]SK|SL[-_]SI|BG[-_]BG|RU[-_]RU|TR[-_]TR|ET[-_]EE|LV[-_]LV')) + THEN + RAISE invalid_datetime_format; + END IF; + + v_regmatch_groups := regexp_matches(v_datestring, CASE v_culture + WHEN 'FI' THEN v_defmask7_fi_regexp + ELSE v_defmask7_regexp + END, 'gi'); + v_timestring := concat(v_regmatch_groups[1], v_regmatch_groups[5]); + v_day := v_regmatch_groups[4]; + v_month := v_regmatch_groups[2]; + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN v_regmatch_groups[3]::SMALLINT - 543 + ELSE v_regmatch_groups[3]::SMALLINT + END; + + ELSIF ((v_datestring ~* v_defmask8_regexp AND v_culture <> 'FI') OR + (v_datestring ~* v_defmask8_fi_regexp AND v_culture = 'FI')) + THEN + IF (v_datestring ~ concat('\s*\d{1,2}\.\s*(?:\.|\d+(?!\d)\s*\.)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}', + MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}', MASKSEPTWO_REGEXP, + TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}|', + '\d{1,2}', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}', MASKSEPTWO_REGEXP, + TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}\s*(?:\.)+|', + '\d+\s*(?:\.)+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$') AND + v_culture ~ 'FI|DE[-_]DE|NN[-_]NO|CS[-_]CZ|PL[-_]PL|RO[-_]RO|SK[-_]SK|SL[-_]SI|BG[-_]BG|RU[-_]RU|TR[-_]TR|ET[-_]EE|LV[-_]LV') + THEN + RAISE invalid_datetime_format; + END IF; + + v_regmatch_groups := regexp_matches(v_datestring, CASE v_culture + WHEN 'FI' THEN v_defmask8_fi_regexp + ELSE v_defmask8_regexp + END, 'gi'); + v_timestring := concat(v_regmatch_groups[1], v_regmatch_groups[5]); + + IF (v_date_format = 'DMY' OR + v_culture IN ('LV-LV', 'LV_LV')) + THEN + v_day := v_regmatch_groups[2]; + v_month := v_regmatch_groups[3]; + v_raw_year := v_regmatch_groups[4]; + ELSIF (v_date_format = 'YMD') + THEN + v_day := v_regmatch_groups[4]; + v_month := v_regmatch_groups[3]; + v_raw_year := v_regmatch_groups[2]; + ELSE + v_day := v_regmatch_groups[3]; + v_month := v_regmatch_groups[2]; + v_raw_year := v_regmatch_groups[4]; + END IF; + + IF (v_culture IN ('AR', 'AR-SA', 'AR_SA')) + THEN + IF (v_day::SMALLINT > 30 OR + v_month::SMALLINT > 12) THEN + RAISE invalid_datetime_format; + END IF; + + v_raw_year := sys.babelfish_get_full_year(v_raw_year, '14'); + v_hijridate := sys.babelfish_conv_hijri_to_greg(v_day, v_month, v_raw_year) - 1; + + v_day := to_char(v_hijridate, 'DD'); + v_month := to_char(v_hijridate, 'MM'); + v_year := to_char(v_hijridate, 'YYYY')::SMALLINT; + + ELSIF (v_culture IN ('TH-TH', 'TH_TH')) THEN + v_year := sys.babelfish_get_full_year(v_raw_year)::SMALLINT - 43; + ELSE + v_year := sys.babelfish_get_full_year(v_raw_year, '', 29)::SMALLINT; + END IF; + ELSE + v_found := FALSE; + END IF; + + WHILE (NOT v_found AND v_resmask_cnt < 20) + LOOP + v_resmask := replace(CASE v_resmask_cnt + WHEN 10 THEN v_defmask10_regexp + WHEN 11 THEN v_defmask11_regexp + WHEN 12 THEN v_defmask12_regexp + WHEN 13 THEN v_defmask13_regexp + WHEN 14 THEN v_defmask14_regexp + WHEN 15 THEN v_defmask15_regexp + WHEN 16 THEN v_defmask16_regexp + WHEN 17 THEN v_defmask17_regexp + WHEN 18 THEN v_defmask18_regexp + WHEN 19 THEN v_defmask19_regexp + END, + '$comp_month$', v_compmonth_regexp); + + v_resmask_fi := replace(CASE v_resmask_cnt + WHEN 10 THEN v_defmask10_fi_regexp + WHEN 11 THEN v_defmask11_fi_regexp + WHEN 12 THEN v_defmask12_fi_regexp + WHEN 13 THEN v_defmask13_fi_regexp + WHEN 14 THEN v_defmask14_fi_regexp + WHEN 15 THEN v_defmask15_fi_regexp + WHEN 16 THEN v_defmask16_fi_regexp + WHEN 17 THEN v_defmask17_fi_regexp + WHEN 18 THEN v_defmask18_fi_regexp + WHEN 19 THEN v_defmask19_fi_regexp + END, + '$comp_month$', v_compmonth_regexp); + + IF ((v_datestring ~* v_resmask AND v_culture <> 'FI') OR + (v_datestring ~* v_resmask_fi AND v_culture = 'FI')) + THEN + v_found := TRUE; + v_regmatch_groups := regexp_matches(v_datestring, CASE v_culture + WHEN 'FI' THEN v_resmask_fi + ELSE v_resmask + END, 'gi'); + v_timestring := CASE + WHEN v_resmask_cnt IN (10, 11, 12, 13) THEN concat(v_regmatch_groups[1], v_regmatch_groups[4]) + ELSE concat(v_regmatch_groups[1], v_regmatch_groups[5]) + END; + + IF (v_resmask_cnt = 10) + THEN + IF (v_regmatch_groups[3] = 'MAR' AND + v_culture IN ('IT-IT', 'IT_IT')) + THEN + RAISE invalid_datetime_format; + END IF; + + IF (v_date_format = 'YMD' AND v_culture NOT IN ('SV-SE', 'SV_SE', 'LV-LV', 'LV_LV')) + THEN + v_day := '01'; + v_year := sys.babelfish_get_full_year(v_regmatch_groups[2], '', 29)::SMALLINT; + ELSE + v_day := v_regmatch_groups[2]; + v_year := to_char(current_date, 'YYYY')::SMALLINT; + END IF; + + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[3], v_lang_metadata_json); + v_raw_year := to_char(sys.babelfish_conv_greg_to_hijri(current_date + 1), 'YYYY'); + + ELSIF (v_resmask_cnt = 11) + THEN + IF (v_date_format IN ('YMD', 'MDY') AND v_culture NOT IN ('SV-SE', 'SV_SE')) + THEN + v_day := v_regmatch_groups[3]; + v_year := to_char(current_date, 'YYYY')::SMALLINT; + ELSE + v_day := '01'; + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN sys.babelfish_get_full_year(v_regmatch_groups[3])::SMALLINT - 43 + ELSE sys.babelfish_get_full_year(v_regmatch_groups[3], '', 29)::SMALLINT + END; + END IF; + + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[2], v_lang_metadata_json); + v_raw_year := sys.babelfish_get_full_year(substring(v_year::TEXT, 3, 2), '14'); + + ELSIF (v_resmask_cnt = 12) + THEN + v_day := '01'; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[3], v_lang_metadata_json); + v_raw_year := v_regmatch_groups[2]; + + ELSIF (v_resmask_cnt = 13) + THEN + v_day := '01'; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[2], v_lang_metadata_json); + v_raw_year := v_regmatch_groups[3]; + + ELSIF (v_resmask_cnt IN (14, 15, 16)) + THEN + IF (v_resmask_cnt = 14) + THEN + v_left_part := v_regmatch_groups[4]; + v_right_part := v_regmatch_groups[3]; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[2], v_lang_metadata_json); + ELSIF (v_resmask_cnt = 15) + THEN + v_left_part := v_regmatch_groups[4]; + v_right_part := v_regmatch_groups[2]; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[3], v_lang_metadata_json); + ELSE + v_left_part := v_regmatch_groups[3]; + v_right_part := v_regmatch_groups[2]; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[4], v_lang_metadata_json); + END IF; + + IF (char_length(v_left_part) <= 2) + THEN + IF (v_date_format = 'YMD' AND v_culture NOT IN ('LV-LV', 'LV_LV')) + THEN + v_day := v_left_part; + v_raw_year := sys.babelfish_get_full_year(v_right_part, '14'); + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN sys.babelfish_get_full_year(v_right_part)::SMALLINT - 43 + ELSE sys.babelfish_get_full_year(v_right_part, '', 29)::SMALLINT + END; + BEGIN + v_res_date := make_date(v_year, v_month::SMALLINT, v_day::SMALLINT); + EXCEPTION + WHEN OTHERS THEN + v_day := v_right_part; + v_raw_year := sys.babelfish_get_full_year(v_left_part, '14'); + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN sys.babelfish_get_full_year(v_left_part)::SMALLINT - 43 + ELSE sys.babelfish_get_full_year(v_left_part, '', 29)::SMALLINT + END; + END; + END IF; + + IF (v_date_format IN ('MDY', 'DMY') OR v_culture IN ('LV-LV', 'LV_LV')) + THEN + v_day := v_right_part; + v_raw_year := sys.babelfish_get_full_year(v_left_part, '14'); + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN sys.babelfish_get_full_year(v_left_part)::SMALLINT - 43 + ELSE sys.babelfish_get_full_year(v_left_part, '', 29)::SMALLINT + END; + BEGIN + v_res_date := make_date(v_year, v_month::SMALLINT, v_day::SMALLINT); + EXCEPTION + WHEN OTHERS THEN + v_day := v_left_part; + v_raw_year := sys.babelfish_get_full_year(v_right_part, '14'); + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN sys.babelfish_get_full_year(v_right_part)::SMALLINT - 43 + ELSE sys.babelfish_get_full_year(v_right_part, '', 29)::SMALLINT + END; + END; + END IF; + ELSE + v_day := v_right_part; + v_raw_year := v_left_part; + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN v_left_part::SMALLINT - 543 + ELSE v_left_part::SMALLINT + END; + END IF; + + ELSIF (v_resmask_cnt = 17) + THEN + v_day := v_regmatch_groups[4]; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[3], v_lang_metadata_json); + v_raw_year := v_regmatch_groups[2]; + + ELSIF (v_resmask_cnt = 18) + THEN + v_day := v_regmatch_groups[3]; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[4], v_lang_metadata_json); + v_raw_year := v_regmatch_groups[2]; + + ELSIF (v_resmask_cnt = 19) + THEN + v_day := v_regmatch_groups[4]; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[2], v_lang_metadata_json); + v_raw_year := v_regmatch_groups[3]; + END IF; + + IF (v_resmask_cnt NOT IN (10, 11, 14, 15, 16)) + THEN + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN v_raw_year::SMALLINT - 543 + ELSE v_raw_year::SMALLINT + END; + END IF; + + IF (v_culture IN ('AR', 'AR-SA', 'AR_SA')) + THEN + IF (v_day::SMALLINT > 30 OR + (v_resmask_cnt NOT IN (10, 11, 14, 15, 16) AND v_year NOT BETWEEN 1318 AND 1501) OR + (v_resmask_cnt IN (14, 15, 16) AND v_raw_year::SMALLINT NOT BETWEEN 1318 AND 1501)) + THEN + RAISE invalid_datetime_format; + END IF; + + v_hijridate := sys.babelfish_conv_hijri_to_greg(v_day, v_month, v_raw_year) - 1; + + v_day := to_char(v_hijridate, 'DD'); + v_month := to_char(v_hijridate, 'MM'); + v_year := to_char(v_hijridate, 'YYYY')::SMALLINT; + END IF; + END IF; + + v_resmask_cnt := v_resmask_cnt + 1; + END LOOP; + + IF (NOT v_found) THEN + RAISE invalid_datetime_format; + END IF; + + IF (char_length(v_timestring) > 0 AND v_timestring NOT IN ('AM', 'ص', 'PM', 'م')) + THEN + IF (v_culture = 'FI') THEN + v_timestring := translate(v_timestring, '.,', ': '); + + IF (char_length(split_part(v_timestring, ':', 4)) > 0) THEN + v_timestring := regexp_replace(v_timestring, ':(?=\s*\d+\s*:?\s*(?:[AP]M|ص|م)?\s*$)', '.'); + END IF; + END IF; + + v_timestring := replace(regexp_replace(v_timestring, '\.?[AP]M|ص|م|\s|\,|\.\D|[\.|:]$', '', 'gi'), ':.', ':'); + BEGIN + v_hours := coalesce(split_part(v_timestring, ':', 1)::SMALLINT, 0); + + IF ((v_dayparts[1] IN ('AM', 'ص') AND v_hours NOT BETWEEN 0 AND 12) OR + (v_dayparts[1] IN ('PM', 'م') AND v_hours NOT BETWEEN 1 AND 23)) + THEN + RAISE invalid_datetime_format; + END IF; + + v_minutes := coalesce(nullif(split_part(v_timestring, ':', 2), '')::SMALLINT, 0); + v_seconds := coalesce(nullif(split_part(v_timestring, ':', 3), '')::NUMERIC, 0); + EXCEPTION + WHEN OTHERS THEN + RAISE invalid_datetime_format; + END; + ELSIF (v_dayparts[1] IN ('PM', 'م')) + THEN + v_hours := 12; + END IF; + + v_res_date := make_timestamp(v_year, v_month::SMALLINT, v_day::SMALLINT, + v_hours, v_minutes, v_seconds); + + IF (v_weekdaynames[1] IS NOT NULL) THEN + v_weekdaynum := sys.babelfish_get_weekdaynum_by_name(v_weekdaynames[1], v_lang_metadata_json); + + IF (CASE date_part('dow', v_res_date)::SMALLINT + WHEN 0 THEN 7 + ELSE date_part('dow', v_res_date)::SMALLINT + END <> v_weekdaynum) + THEN + RAISE invalid_datetime_format; + END IF; + END IF; + + RETURN v_res_date; +EXCEPTION + WHEN invalid_datetime_format OR datetime_field_overflow THEN + RAISE USING MESSAGE := format('Error converting string value ''%s'' into data type DATE using culture ''%s''.', + p_datestring, p_culture), + 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_parameter_value THEN + RAISE USING MESSAGE := CASE char_length(coalesce(CONVERSION_LANG, '')) + WHEN 0 THEN format('The culture parameter ''%s'' provided in the function call is not supported.', + p_culture) + ELSE format('Invalid CONVERSION_LANG constant value - ''%s''. Allowed values are: ''English'', ''Deutsch'', etc.', + CONVERSION_LANG) + END, + DETAIL := 'Passed incorrect value for "p_culture" parameter or compiled incorrect CONVERSION_LANG constant value in function''s body.', + HINT := 'Check "p_culture" input parameter value, correct it if needed, and try again. Also check CONVERSION_LANG constant value.'; + + 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 := format('Error while trying to convert "%s" value to SMALLINT data type.', + v_err_message), + DETAIL := 'Supplied value contains illegal characters.', + HINT := 'Correct supplied value, remove all illegal characters.'; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_parse_to_datetime(IN p_datatype TEXT, + IN p_datetimestring TEXT, + IN p_culture TEXT DEFAULT '') +RETURNS TIMESTAMP WITHOUT TIME ZONE +AS +$BODY$ +DECLARE + v_day VARCHAR; + v_year SMALLINT; + v_month VARCHAR; + v_res_date DATE; + v_scale SMALLINT; + v_hijridate DATE; + v_culture VARCHAR; + v_dayparts TEXT[]; + v_resmask VARCHAR; + v_datatype VARCHAR; + v_raw_year VARCHAR; + v_left_part VARCHAR; + v_right_part VARCHAR; + v_resmask_fi VARCHAR; + v_timestring VARCHAR; + v_correctnum VARCHAR; + v_weekdaynum SMALLINT; + v_err_message VARCHAR; + v_date_format VARCHAR; + v_weekdaynames TEXT[]; + v_hours SMALLINT := 0; + v_minutes SMALLINT := 0; + v_res_datatype VARCHAR; + v_error_message VARCHAR; + v_found BOOLEAN := TRUE; + v_compday_regexp VARCHAR; + v_regmatch_groups TEXT[]; + v_datatype_groups TEXT[]; + v_datetimestring VARCHAR; + v_seconds VARCHAR := '0'; + v_fseconds VARCHAR := '0'; + v_compmonth_regexp VARCHAR; + v_lang_metadata_json JSONB; + v_resmask_cnt SMALLINT := 10; + v_res_datetime TIMESTAMP(6) WITHOUT TIME ZONE; + DAYMM_REGEXP CONSTANT VARCHAR := '(\d{1,2})'; + FULLYEAR_REGEXP CONSTANT VARCHAR := '(\d{3,4})'; + SHORTYEAR_REGEXP CONSTANT VARCHAR := '(\d{1,2})'; + COMPYEAR_REGEXP CONSTANT VARCHAR := '(\d{1,4})'; + AMPM_REGEXP CONSTANT VARCHAR := '(?:[AP]M|ص|م)'; + TIMEUNIT_REGEXP CONSTANT VARCHAR := '\s*\d{1,2}\s*'; + MASKSEPONE_REGEXP CONSTANT VARCHAR := '\s*(?:/|-)?'; + MASKSEPTWO_REGEXP CONSTANT VARCHAR := '\s*(?:\s|/|-|\.|,)'; + MASKSEPTWO_FI_REGEXP CONSTANT VARCHAR := '\s*(?:\s|/|-|,)'; + MASKSEPTHREE_REGEXP CONSTANT VARCHAR := '\s*(?:/|-|\.|,)'; + TIME_MASKSEP_REGEXP CONSTANT VARCHAR := '(?:\s|\.|,)*'; + TIME_MASKSEP_FI_REGEXP CONSTANT VARCHAR := '(?:\s|,)*'; + WEEKDAYAMPM_START_REGEXP CONSTANT VARCHAR := '(^|[[:digit:][:space:]\.,])'; + WEEKDAYAMPM_END_REGEXP CONSTANT VARCHAR := '([[:digit:][:space:]\.,]|$)(?=[^/-]|$)'; + CORRECTNUM_REGEXP CONSTANT VARCHAR := '(?:([+-]\d{1,4})(?:[[:space:]\.,]|[AP]M|ص|م|$))'; + DATATYPE_REGEXP CONSTANT VARCHAR := '^(DATETIME|SMALLDATETIME|DATETIME2)\s*(?:\()?\s*((?:-)?\d+)?\s*(?:\))?$'; + ANNO_DOMINI_REGEXP VARCHAR := '(AD|A\.D\.)'; + ANNO_DOMINI_COMPREGEXP VARCHAR := concat(WEEKDAYAMPM_START_REGEXP, ANNO_DOMINI_REGEXP, WEEKDAYAMPM_END_REGEXP); + HHMMSSFS_PART_REGEXP CONSTANT VARCHAR := + concat(TIMEUNIT_REGEXP, AMPM_REGEXP, '|', + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, TIMEUNIT_REGEXP, '\:', TIME_MASKSEP_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, TIMEUNIT_REGEXP, '(?!\d)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?|', + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, TIMEUNIT_REGEXP, '\:', TIME_MASKSEP_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, TIMEUNIT_REGEXP, '\:', TIME_MASKSEP_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, TIMEUNIT_REGEXP, '(?!\d)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?|', + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, TIMEUNIT_REGEXP, '\:', TIME_MASKSEP_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, TIMEUNIT_REGEXP, '\:', TIME_MASKSEP_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\s*\d{1,2}\.\d+(?!\d)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?|', + AMPM_REGEXP, '?'); + HHMMSSFS_PART_FI_REGEXP CONSTANT VARCHAR := + concat(TIMEUNIT_REGEXP, AMPM_REGEXP, '|', + AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, TIMEUNIT_REGEXP, '[\:\.]', TIME_MASKSEP_FI_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, TIMEUNIT_REGEXP, '(?!\d)', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?\.?|', + AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, TIMEUNIT_REGEXP, '[\:\.]', TIME_MASKSEP_FI_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, TIMEUNIT_REGEXP, '[\:\.]', TIME_MASKSEP_FI_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, TIMEUNIT_REGEXP, '(?!\d)', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?|', + AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, TIMEUNIT_REGEXP, '[\:\.]', TIME_MASKSEP_FI_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, TIMEUNIT_REGEXP, '[\:\.]', TIME_MASKSEP_FI_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, '\s*\d{1,2}\.\d+(?!\d)\.?', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?|', + AMPM_REGEXP, '?'); + v_defmask1_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, + '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, + CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + TIME_MASKSEP_REGEXP, '(?:[\.|,]+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)', TIME_MASKSEP_REGEXP, '$'); + v_defmask1_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, CORRECTNUM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, + '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_FI_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:', MASKSEPTWO_FI_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, + CORRECTNUM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:[,]+', AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, CORRECTNUM_REGEXP, '?))', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + TIME_MASKSEP_FI_REGEXP, '(?:[\.|,]+', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask2_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, + '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, + AMPM_REGEXP, TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + TIME_MASKSEP_REGEXP, '(?:(?:[\.|,]+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?)|', + CORRECTNUM_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, '$'); + v_defmask2_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, CORRECTNUM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, + '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + CORRECTNUM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_FI_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_FI_REGEXP, CORRECTNUM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, + AMPM_REGEXP, TIME_MASKSEP_FI_REGEXP, CORRECTNUM_REGEXP, '?))', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + TIME_MASKSEP_FI_REGEXP, '(?:(?:[\.|,]+', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, TIME_MASKSEP_FI_REGEXP, CORRECTNUM_REGEXP, '?)|', + CORRECTNUM_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask3_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, ')|', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + TIME_MASKSEP_REGEXP, '(', TIME_MASKSEP_REGEXP, AMPM_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask3_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + TIME_MASKSEP_FI_REGEXP, '[\./]?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)', + FULLYEAR_REGEXP, + TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask4_0_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, '\s*(', AMPM_REGEXP, ')', + TIME_MASKSEP_REGEXP, '$'); + v_defmask4_1_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:\s|,)+', + DAYMM_REGEXP, '\s*(', AMPM_REGEXP, ')', + TIME_MASKSEP_REGEXP, '$'); + v_defmask4_2_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '\s*[\.]+', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, '\s*(', AMPM_REGEXP, ')', + TIME_MASKSEP_REGEXP, '$'); + v_defmask5_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask5_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_FI_REGEXP, + FULLYEAR_REGEXP, + TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask6_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '((?:(?:\s|\.|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_REGEXP, '))?', TIME_MASKSEP_REGEXP, '$'); + v_defmask6_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:\s*[\.])?', + '((?:(?:\s|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_FI_REGEXP, '))?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask7_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '((?:(?:\s|\.|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_REGEXP, '))?', TIME_MASKSEP_REGEXP, '$'); + v_defmask7_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_FI_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '((?:(?:\s|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_FI_REGEXP, '))?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask8_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:[\.|,]+', AMPM_REGEXP, ')?', + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask8_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_FI_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:[,]+', AMPM_REGEXP, '))', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:[,]+', AMPM_REGEXP, '))', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:(?:[\,]+|\s*/\s*)', AMPM_REGEXP, ')?', + TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask9_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', + HHMMSSFS_PART_REGEXP, + ')', TIME_MASKSEP_REGEXP, '$'); + v_defmask9_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, '(', + HHMMSSFS_PART_FI_REGEXP, + ')', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask10_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)?', TIME_MASKSEP_REGEXP, + '($comp_month$)', + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask10_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)?', TIME_MASKSEP_REGEXP, + '($comp_month$)', + TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask11_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask11_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '((?:(?:\s|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_FI_REGEXP, '))?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask12_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask12_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask13_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$'); + v_defmask13_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask14_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + '($comp_month$)' + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)', TIME_MASKSEP_REGEXP, + COMPYEAR_REGEXP, + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask14_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + '($comp_month$)' + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)', TIME_MASKSEP_FI_REGEXP, + COMPYEAR_REGEXP, + '((?:(?:\s|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_FI_REGEXP, '))?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask15_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + COMPYEAR_REGEXP, + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask15_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + COMPYEAR_REGEXP, + '((?:(?:\s|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_FI_REGEXP, '))?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask16_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)', TIME_MASKSEP_REGEXP, + COMPYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask16_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)', TIME_MASKSEP_REGEXP, + COMPYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask17_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask17_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '((?:(?:\s|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_FI_REGEXP, '))?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask18_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask18_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask19_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '((?:(?:\s|\.|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_REGEXP, '))?', TIME_MASKSEP_REGEXP, '$'); + v_defmask19_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '((?:(?:\s|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_FI_REGEXP, '))?', TIME_MASKSEP_FI_REGEXP, '$'); + CONVERSION_LANG CONSTANT VARCHAR := ''; + DATE_FORMAT CONSTANT VARCHAR := ''; +BEGIN + v_datatype := trim(p_datatype); + v_datetimestring := upper(trim(p_datetimestring)); + v_culture := coalesce(nullif(upper(trim(p_culture)), ''), 'EN-US'); + + 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; + + v_dayparts := ARRAY(SELECT upper(array_to_string(regexp_matches(v_datetimestring, '[AP]M|ص|م', 'gi'), ''))); + + IF (array_length(v_dayparts, 1) > 1) THEN + RAISE invalid_datetime_format; + END IF; + + BEGIN + v_lang_metadata_json := sys.babelfish_get_lang_metadata_json(coalesce(nullif(CONVERSION_LANG, ''), p_culture)); + EXCEPTION + WHEN OTHERS THEN + RAISE invalid_parameter_value; + END; + + v_compday_regexp := array_to_string(array_cat(array_cat(ARRAY(SELECT jsonb_array_elements_text(v_lang_metadata_json -> 'days_names')), + ARRAY(SELECT jsonb_array_elements_text(v_lang_metadata_json -> 'days_shortnames'))), + ARRAY(SELECT jsonb_array_elements_text(v_lang_metadata_json -> 'days_extrashortnames'))), '|'); + + v_weekdaynames := ARRAY(SELECT array_to_string(regexp_matches(v_datetimestring, v_compday_regexp, 'gi'), '')); + + IF (array_length(v_weekdaynames, 1) > 1) THEN + RAISE invalid_datetime_format; + END IF; + + IF (v_weekdaynames[1] IS NOT NULL AND + v_datetimestring ~* concat(WEEKDAYAMPM_START_REGEXP, '(', v_compday_regexp, ')', WEEKDAYAMPM_END_REGEXP)) + THEN + v_datetimestring := replace(v_datetimestring, v_weekdaynames[1], ' '); + END IF; + + IF (v_datetimestring ~* ANNO_DOMINI_COMPREGEXP) + THEN + IF (v_culture !~ 'EN[-_]US|DA[-_]DK|SV[-_]SE|EN[-_]GB|HI[-_]IS') THEN + RAISE invalid_datetime_format; + END IF; + + v_datetimestring := regexp_replace(v_datetimestring, + ANNO_DOMINI_COMPREGEXP, + regexp_replace(array_to_string(regexp_matches(v_datetimestring, ANNO_DOMINI_COMPREGEXP, 'gi'), ''), + ANNO_DOMINI_REGEXP, ' ', 'gi'), + 'gi'); + END IF; + + v_date_format := coalesce(nullif(upper(trim(DATE_FORMAT)), ''), v_lang_metadata_json ->> 'date_format'); + + v_compmonth_regexp := + array_to_string(array_cat(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'))), + array_cat(ARRAY(SELECT jsonb_array_elements_text(v_lang_metadata_json -> 'months_extrashortnames')), + ARRAY(SELECT jsonb_array_elements_text(v_lang_metadata_json -> 'months_extranames'))) + ), '|'); + + IF ((v_datetimestring ~* v_defmask1_regexp AND v_culture <> 'FI') OR + (v_datetimestring ~* v_defmask1_fi_regexp AND v_culture = 'FI')) + THEN + IF (v_datetimestring ~ concat(CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d+\s*(?:\.)+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, + CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}|', + '\d+\s*(?:\.)+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, + CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$') AND + v_culture ~ 'DE[-_]DE|NN[-_]NO|CS[-_]CZ|PL[-_]PL|RO[-_]RO|SK[-_]SK|SL[-_]SI|BG[-_]BG|RU[-_]RU|TR[-_]TR|ET[-_]EE|LV[-_]LV') + THEN + RAISE invalid_datetime_format; + END IF; + + v_regmatch_groups := regexp_matches(v_datetimestring, CASE v_culture + WHEN 'FI' THEN v_defmask1_fi_regexp + ELSE v_defmask1_regexp + END, 'gi'); + v_timestring := v_regmatch_groups[2]; + v_correctnum := coalesce(v_regmatch_groups[1], v_regmatch_groups[3], + v_regmatch_groups[5], v_regmatch_groups[6]); + + IF (v_date_format = 'DMY' OR + v_culture IN ('SV-SE', 'SV_SE', 'LV-LV', 'LV_LV')) + THEN + v_day := v_regmatch_groups[4]; + v_month := v_regmatch_groups[7]; + ELSE + v_day := v_regmatch_groups[7]; + v_month := v_regmatch_groups[4]; + END IF; + + IF (v_culture IN ('AR', 'AR-SA', 'AR_SA')) + THEN + IF (v_day::SMALLINT > 30 OR + v_month::SMALLINT > 12) THEN + RAISE invalid_datetime_format; + END IF; + + v_raw_year := to_char(sys.babelfish_conv_greg_to_hijri(current_date + 1), 'YYYY'); + v_hijridate := sys.babelfish_conv_hijri_to_greg(v_day, v_month, v_raw_year) - 1; + + v_day := to_char(v_hijridate, 'DD'); + v_month := to_char(v_hijridate, 'MM'); + v_year := to_char(v_hijridate, 'YYYY')::SMALLINT; + ELSE + v_year := to_char(current_date, 'YYYY')::SMALLINT; + END IF; + + ELSIF ((v_datetimestring ~* v_defmask6_regexp AND v_culture <> 'FI') OR + (v_datetimestring ~* v_defmask6_fi_regexp AND v_culture = 'FI')) + THEN + IF (v_culture IN ('AR', 'AR-SA', 'AR_SA') OR + (v_datetimestring ~ concat('\s*\d{1,2}\.\s*(?:\.|\d+(?!\d)\s*\.)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{3,4}', + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, '\d{1,2}|', + '\d{3,4}', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}', MASKSEPTWO_REGEXP, + TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}\s*(?:\.)+|', + '\d+\s*(?:\.)+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$') AND + v_culture ~ 'DE[-_]DE|NN[-_]NO|CS[-_]CZ|PL[-_]PL|RO[-_]RO|SK[-_]SK|SL[-_]SI|BG[-_]BG|RU[-_]RU|TR[-_]TR|ET[-_]EE|LV[-_]LV')) + THEN + RAISE invalid_datetime_format; + END IF; + + v_regmatch_groups := regexp_matches(v_datetimestring, CASE v_culture + WHEN 'FI' THEN v_defmask6_fi_regexp + ELSE v_defmask6_regexp + END, 'gi'); + v_timestring := concat(v_regmatch_groups[1], v_regmatch_groups[5]); + v_day := v_regmatch_groups[4]; + v_month := v_regmatch_groups[3]; + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN v_regmatch_groups[2]::SMALLINT - 543 + ELSE v_regmatch_groups[2]::SMALLINT + END; + + ELSIF ((v_datetimestring ~* v_defmask2_regexp AND v_culture <> 'FI') OR + (v_datetimestring ~* v_defmask2_fi_regexp AND v_culture = 'FI')) + THEN + IF (v_culture IN ('AR', 'AR-SA', 'AR_SA') OR + (v_datetimestring ~ concat('\s*\d{1,2}\.\s*(?:\.|\d+(?!\d)\s*\.)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{3,4}', + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, + AMPM_REGEXP, TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?))', TIME_MASKSEP_REGEXP, '\d{1,2}|', + '\d+\s*(?:\.)+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$') AND + v_culture ~ 'DE[-_]DE|NN[-_]NO|CS[-_]CZ|PL[-_]PL|RO[-_]RO|SK[-_]SK|SL[-_]SI|BG[-_]BG|RU[-_]RU|TR[-_]TR|ET[-_]EE|LV[-_]LV')) + THEN + RAISE invalid_datetime_format; + END IF; + + v_regmatch_groups := regexp_matches(v_datetimestring, CASE v_culture + WHEN 'FI' THEN v_defmask2_fi_regexp + ELSE v_defmask2_regexp + END, 'gi'); + v_timestring := v_regmatch_groups[2]; + v_correctnum := coalesce(v_regmatch_groups[1], v_regmatch_groups[3], v_regmatch_groups[5], + v_regmatch_groups[6], v_regmatch_groups[8], v_regmatch_groups[9]); + v_day := '01'; + v_month := v_regmatch_groups[7]; + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN v_regmatch_groups[4]::SMALLINT - 543 + ELSE v_regmatch_groups[4]::SMALLINT + END; + + ELSIF (v_datetimestring ~* v_defmask4_1_regexp OR + (v_datetimestring ~* v_defmask4_2_regexp AND v_culture !~ 'DE[-_]DE|NN[-_]NO|CS[-_]CZ|PL[-_]PL|RO[-_]RO|SK[-_]SK|SL[-_]SI|BG[-_]BG|RU[-_]RU|TR[-_]TR|ET[-_]EE|LV[-_]LV') OR + (v_datetimestring ~* v_defmask9_regexp AND v_culture <> 'FI') OR + (v_datetimestring ~* v_defmask9_fi_regexp AND v_culture = 'FI')) + THEN + IF (v_datetimestring ~ concat('\d+\s*\.?(?:,+|,*', AMPM_REGEXP, ')', TIME_MASKSEP_FI_REGEXP, '\.+', TIME_MASKSEP_REGEXP, '$|', + '\d+\s*\.', TIME_MASKSEP_FI_REGEXP, '\.', TIME_MASKSEP_FI_REGEXP, '$') AND + v_culture = 'FI') + THEN + RAISE invalid_datetime_format; + END IF; + + IF (v_datetimestring ~* v_defmask4_0_regexp) THEN + v_timestring := (regexp_matches(v_datetimestring, v_defmask4_0_regexp, 'gi'))[1]; + ELSE + v_timestring := v_datetimestring; + END IF; + + v_res_date := current_date; + v_day := to_char(v_res_date, 'DD'); + v_month := to_char(v_res_date, 'MM'); + v_year := to_char(v_res_date, 'YYYY')::SMALLINT; + + ELSIF ((v_datetimestring ~* v_defmask3_regexp AND v_culture <> 'FI') OR + (v_datetimestring ~* v_defmask3_fi_regexp AND v_culture = 'FI')) + THEN + IF (v_culture IN ('AR', 'AR-SA', 'AR_SA') OR + (v_datetimestring ~ concat('\s*\d{1,2}\.\s*(?:\.|\d+(?!\d)\s*\.)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', + TIME_MASKSEP_REGEXP, '\d{1,2}', MASKSEPTWO_REGEXP, '|', + '\d+\s*(?:\.)+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$') AND + v_culture ~ 'DE[-_]DE|NN[-_]NO|CS[-_]CZ|PL[-_]PL|RO[-_]RO|SK[-_]SK|SL[-_]SI|BG[-_]BG|RU[-_]RU|TR[-_]TR|ET[-_]EE|LV[-_]LV')) + THEN + RAISE invalid_datetime_format; + END IF; + + v_regmatch_groups := regexp_matches(v_datetimestring, CASE v_culture + WHEN 'FI' THEN v_defmask3_fi_regexp + ELSE v_defmask3_regexp + END, 'gi'); + v_timestring := v_regmatch_groups[1]; + v_day := '01'; + v_month := v_regmatch_groups[2]; + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN v_regmatch_groups[3]::SMALLINT - 543 + ELSE v_regmatch_groups[3]::SMALLINT + END; + + ELSIF ((v_datetimestring ~* v_defmask5_regexp AND v_culture <> 'FI') OR + (v_datetimestring ~* v_defmask5_fi_regexp AND v_culture = 'FI')) + THEN + IF (v_culture IN ('AR', 'AR-SA', 'AR_SA') OR + (v_datetimestring ~ concat('\s*\d{1,2}\.\s*(?:\.|\d+(?!\d)\s*\.)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}', MASKSEPTWO_REGEXP, + TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}', MASKSEPTWO_REGEXP, + TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{3,4}', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$|', + '\d{1,2}', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{3,4}\s*(?:\.)+|', + '\d+\s*(?:\.)+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$') AND + v_culture ~ 'DE[-_]DE|NN[-_]NO|CS[-_]CZ|PL[-_]PL|RO[-_]RO|SK[-_]SK|SL[-_]SI|BG[-_]BG|RU[-_]RU|TR[-_]TR|ET[-_]EE|LV[-_]LV')) + THEN + RAISE invalid_datetime_format; + END IF; + + v_regmatch_groups := regexp_matches(v_datetimestring, v_defmask5_regexp, 'gi'); + v_timestring := concat(v_regmatch_groups[1], v_regmatch_groups[5]); + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN v_regmatch_groups[4]::SMALLINT - 543 + ELSE v_regmatch_groups[4]::SMALLINT + END; + + IF (v_date_format = 'DMY' OR + v_culture IN ('LV-LV', 'LV_LV')) + THEN + v_day := v_regmatch_groups[2]; + v_month := v_regmatch_groups[3]; + ELSE + v_day := v_regmatch_groups[3]; + v_month := v_regmatch_groups[2]; + END IF; + + ELSIF ((v_datetimestring ~* v_defmask7_regexp AND v_culture <> 'FI') OR + (v_datetimestring ~* v_defmask7_fi_regexp AND v_culture = 'FI')) + THEN + IF (v_culture IN ('AR', 'AR-SA', 'AR_SA') OR + (v_datetimestring ~ concat('\s*\d{1,2}\.\s*(?:\.|\d+(?!\d)\s*\.)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}', + MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{3,4}|', + '\d{3,4}', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}\s*(?:\.)+|', + '\d+\s*(?:\.)+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$') AND + v_culture ~ 'DE[-_]DE|NN[-_]NO|CS[-_]CZ|PL[-_]PL|RO[-_]RO|SK[-_]SK|SL[-_]SI|BG[-_]BG|RU[-_]RU|TR[-_]TR|ET[-_]EE|LV[-_]LV')) + THEN + RAISE invalid_datetime_format; + END IF; + + v_regmatch_groups := regexp_matches(v_datetimestring, CASE v_culture + WHEN 'FI' THEN v_defmask7_fi_regexp + ELSE v_defmask7_regexp + END, 'gi'); + v_timestring := concat(v_regmatch_groups[1], v_regmatch_groups[5]); + v_day := v_regmatch_groups[4]; + v_month := v_regmatch_groups[2]; + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN v_regmatch_groups[3]::SMALLINT - 543 + ELSE v_regmatch_groups[3]::SMALLINT + END; + + ELSIF ((v_datetimestring ~* v_defmask8_regexp AND v_culture <> 'FI') OR + (v_datetimestring ~* v_defmask8_fi_regexp AND v_culture = 'FI')) + THEN + IF (v_datetimestring ~ concat('\s*\d{1,2}\.\s*(?:\.|\d+(?!\d)\s*\.)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}', + MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}', MASKSEPTWO_REGEXP, + TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}|', + '\d{1,2}', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}', MASKSEPTWO_REGEXP, + TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}\s*(?:\.)+|', + '\d+\s*(?:\.)+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$') AND + v_culture ~ 'FI|DE[-_]DE|NN[-_]NO|CS[-_]CZ|PL[-_]PL|RO[-_]RO|SK[-_]SK|SL[-_]SI|BG[-_]BG|RU[-_]RU|TR[-_]TR|ET[-_]EE|LV[-_]LV') + THEN + RAISE invalid_datetime_format; + END IF; + + v_regmatch_groups := regexp_matches(v_datetimestring, CASE v_culture + WHEN 'FI' THEN v_defmask8_fi_regexp + ELSE v_defmask8_regexp + END, 'gi'); + v_timestring := concat(v_regmatch_groups[1], v_regmatch_groups[5]); + + IF (v_date_format = 'DMY' OR + v_culture IN ('LV-LV', 'LV_LV')) + THEN + v_day := v_regmatch_groups[2]; + v_month := v_regmatch_groups[3]; + v_raw_year := v_regmatch_groups[4]; + ELSIF (v_date_format = 'YMD') + THEN + v_day := v_regmatch_groups[4]; + v_month := v_regmatch_groups[3]; + v_raw_year := v_regmatch_groups[2]; + ELSE + v_day := v_regmatch_groups[3]; + v_month := v_regmatch_groups[2]; + v_raw_year := v_regmatch_groups[4]; + END IF; + + IF (v_culture IN ('AR', 'AR-SA', 'AR_SA')) + THEN + IF (v_day::SMALLINT > 30 OR + v_month::SMALLINT > 12) THEN + RAISE invalid_datetime_format; + END IF; + + v_raw_year := sys.babelfish_get_full_year(v_raw_year, '14'); + v_hijridate := sys.babelfish_conv_hijri_to_greg(v_day, v_month, v_raw_year) - 1; + + v_day := to_char(v_hijridate, 'DD'); + v_month := to_char(v_hijridate, 'MM'); + v_year := to_char(v_hijridate, 'YYYY')::SMALLINT; + + ELSIF (v_culture IN ('TH-TH', 'TH_TH')) THEN + v_year := sys.babelfish_get_full_year(v_raw_year)::SMALLINT - 43; + ELSE + v_year := sys.babelfish_get_full_year(v_raw_year, '', 29)::SMALLINT; + END IF; + ELSE + v_found := FALSE; + END IF; + + WHILE (NOT v_found AND v_resmask_cnt < 20) + LOOP + v_resmask := replace(CASE v_resmask_cnt + WHEN 10 THEN v_defmask10_regexp + WHEN 11 THEN v_defmask11_regexp + WHEN 12 THEN v_defmask12_regexp + WHEN 13 THEN v_defmask13_regexp + WHEN 14 THEN v_defmask14_regexp + WHEN 15 THEN v_defmask15_regexp + WHEN 16 THEN v_defmask16_regexp + WHEN 17 THEN v_defmask17_regexp + WHEN 18 THEN v_defmask18_regexp + WHEN 19 THEN v_defmask19_regexp + END, + '$comp_month$', v_compmonth_regexp); + + v_resmask_fi := replace(CASE v_resmask_cnt + WHEN 10 THEN v_defmask10_fi_regexp + WHEN 11 THEN v_defmask11_fi_regexp + WHEN 12 THEN v_defmask12_fi_regexp + WHEN 13 THEN v_defmask13_fi_regexp + WHEN 14 THEN v_defmask14_fi_regexp + WHEN 15 THEN v_defmask15_fi_regexp + WHEN 16 THEN v_defmask16_fi_regexp + WHEN 17 THEN v_defmask17_fi_regexp + WHEN 18 THEN v_defmask18_fi_regexp + WHEN 19 THEN v_defmask19_fi_regexp + END, + '$comp_month$', v_compmonth_regexp); + + IF ((v_datetimestring ~* v_resmask AND v_culture <> 'FI') OR + (v_datetimestring ~* v_resmask_fi AND v_culture = 'FI')) + THEN + v_found := TRUE; + v_regmatch_groups := regexp_matches(v_datetimestring, CASE v_culture + WHEN 'FI' THEN v_resmask_fi + ELSE v_resmask + END, 'gi'); + v_timestring := CASE + WHEN v_resmask_cnt IN (10, 11, 12, 13) THEN concat(v_regmatch_groups[1], v_regmatch_groups[4]) + ELSE concat(v_regmatch_groups[1], v_regmatch_groups[5]) + END; + + IF (v_resmask_cnt = 10) + THEN + IF (v_regmatch_groups[3] = 'MAR' AND + v_culture IN ('IT-IT', 'IT_IT')) + THEN + RAISE invalid_datetime_format; + END IF; + + IF (v_date_format = 'YMD' AND v_culture NOT IN ('SV-SE', 'SV_SE', 'LV-LV', 'LV_LV')) + THEN + v_day := '01'; + v_year := sys.babelfish_get_full_year(v_regmatch_groups[2], '', 29)::SMALLINT; + ELSE + v_day := v_regmatch_groups[2]; + v_year := to_char(current_date, 'YYYY')::SMALLINT; + END IF; + + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[3], v_lang_metadata_json); + v_raw_year := to_char(sys.babelfish_conv_greg_to_hijri(current_date + 1), 'YYYY'); + + ELSIF (v_resmask_cnt = 11) + THEN + IF (v_date_format IN ('YMD', 'MDY') AND v_culture NOT IN ('SV-SE', 'SV_SE')) + THEN + v_day := v_regmatch_groups[3]; + v_year := to_char(current_date, 'YYYY')::SMALLINT; + ELSE + v_day := '01'; + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN sys.babelfish_get_full_year(v_regmatch_groups[3])::SMALLINT - 43 + ELSE sys.babelfish_get_full_year(v_regmatch_groups[3], '', 29)::SMALLINT + END; + END IF; + + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[2], v_lang_metadata_json); + v_raw_year := sys.babelfish_get_full_year(substring(v_year::TEXT, 3, 2), '14'); + + ELSIF (v_resmask_cnt = 12) + THEN + v_day := '01'; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[3], v_lang_metadata_json); + v_raw_year := v_regmatch_groups[2]; + + ELSIF (v_resmask_cnt = 13) + THEN + v_day := '01'; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[2], v_lang_metadata_json); + v_raw_year := v_regmatch_groups[3]; + + ELSIF (v_resmask_cnt IN (14, 15, 16)) + THEN + IF (v_resmask_cnt = 14) + THEN + v_left_part := v_regmatch_groups[4]; + v_right_part := v_regmatch_groups[3]; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[2], v_lang_metadata_json); + ELSIF (v_resmask_cnt = 15) + THEN + v_left_part := v_regmatch_groups[4]; + v_right_part := v_regmatch_groups[2]; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[3], v_lang_metadata_json); + ELSE + v_left_part := v_regmatch_groups[3]; + v_right_part := v_regmatch_groups[2]; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[4], v_lang_metadata_json); + END IF; + + IF (char_length(v_left_part) <= 2) + THEN + IF (v_date_format = 'YMD' AND v_culture NOT IN ('LV-LV', 'LV_LV')) + THEN + v_day := v_left_part; + v_raw_year := sys.babelfish_get_full_year(v_right_part, '14'); + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN sys.babelfish_get_full_year(v_right_part)::SMALLINT - 43 + ELSE sys.babelfish_get_full_year(v_right_part, '', 29)::SMALLINT + END; + BEGIN + v_res_date := make_date(v_year, v_month::SMALLINT, v_day::SMALLINT); + EXCEPTION + WHEN OTHERS THEN + v_day := v_right_part; + v_raw_year := sys.babelfish_get_full_year(v_left_part, '14'); + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN sys.babelfish_get_full_year(v_left_part)::SMALLINT - 43 + ELSE sys.babelfish_get_full_year(v_left_part, '', 29)::SMALLINT + END; + END; + END IF; + + IF (v_date_format IN ('MDY', 'DMY') OR v_culture IN ('LV-LV', 'LV_LV')) + THEN + v_day := v_right_part; + v_raw_year := sys.babelfish_get_full_year(v_left_part, '14'); + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN sys.babelfish_get_full_year(v_left_part)::SMALLINT - 43 + ELSE sys.babelfish_get_full_year(v_left_part, '', 29)::SMALLINT + END; + BEGIN + v_res_date := make_date(v_year, v_month::SMALLINT, v_day::SMALLINT); + EXCEPTION + WHEN OTHERS THEN + v_day := v_left_part; + v_raw_year := sys.babelfish_get_full_year(v_right_part, '14'); + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN sys.babelfish_get_full_year(v_right_part)::SMALLINT - 43 + ELSE sys.babelfish_get_full_year(v_right_part, '', 29)::SMALLINT + END; + END; + END IF; + ELSE + v_day := v_right_part; + v_raw_year := v_left_part; + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN v_left_part::SMALLINT - 543 + ELSE v_left_part::SMALLINT + END; + END IF; + + ELSIF (v_resmask_cnt = 17) + THEN + v_day := v_regmatch_groups[4]; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[3], v_lang_metadata_json); + v_raw_year := v_regmatch_groups[2]; + + ELSIF (v_resmask_cnt = 18) + THEN + v_day := v_regmatch_groups[3]; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[4], v_lang_metadata_json); + v_raw_year := v_regmatch_groups[2]; + + ELSIF (v_resmask_cnt = 19) + THEN + v_day := v_regmatch_groups[4]; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[2], v_lang_metadata_json); + v_raw_year := v_regmatch_groups[3]; + END IF; + + IF (v_resmask_cnt NOT IN (10, 11, 14, 15, 16)) + THEN + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN v_raw_year::SMALLINT - 543 + ELSE v_raw_year::SMALLINT + END; + END IF; + + IF (v_culture IN ('AR', 'AR-SA', 'AR_SA')) + THEN + IF (v_day::SMALLINT > 30 OR + (v_resmask_cnt NOT IN (10, 11, 14, 15, 16) AND v_year NOT BETWEEN 1318 AND 1501) OR + (v_resmask_cnt IN (14, 15, 16) AND v_raw_year::SMALLINT NOT BETWEEN 1318 AND 1501)) + THEN + RAISE invalid_datetime_format; + END IF; + + v_hijridate := sys.babelfish_conv_hijri_to_greg(v_day, v_month, v_raw_year) - 1; + + v_day := to_char(v_hijridate, 'DD'); + v_month := to_char(v_hijridate, 'MM'); + v_year := to_char(v_hijridate, 'YYYY')::SMALLINT; + END IF; + END IF; + + v_resmask_cnt := v_resmask_cnt + 1; + END LOOP; + + IF (NOT v_found) THEN + RAISE invalid_datetime_format; + END IF; + + IF (char_length(v_timestring) > 0 AND v_timestring NOT IN ('AM', 'ص', 'PM', 'م')) + THEN + IF (v_culture = 'FI') THEN + v_timestring := translate(v_timestring, '.,', ': '); + + IF (char_length(split_part(v_timestring, ':', 4)) > 0) THEN + v_timestring := regexp_replace(v_timestring, ':(?=\s*\d+\s*:?\s*(?:[AP]M|ص|م)?\s*$)', '.'); + END IF; + END IF; + + v_timestring := replace(regexp_replace(v_timestring, '\.?[AP]M|ص|م|\s|\,|\.\D|[\.|:]$', '', 'gi'), ':.', ':'); + BEGIN + v_hours := coalesce(split_part(v_timestring, ':', 1)::SMALLINT, 0); + + IF ((v_dayparts[1] IN ('AM', 'ص') AND v_hours NOT BETWEEN 0 AND 12) OR + (v_dayparts[1] IN ('PM', 'م') AND v_hours NOT BETWEEN 1 AND 23)) + THEN + RAISE invalid_datetime_format; + ELSIF (v_dayparts[1] = 'PM' AND v_hours < 12) THEN + v_hours := v_hours + 12; + ELSIF (v_dayparts[1] = 'AM' AND v_hours = 12) THEN + v_hours := v_hours - 12; + END IF; + + v_minutes := coalesce(nullif(split_part(v_timestring, ':', 2), '')::SMALLINT, 0); + v_seconds := coalesce(nullif(split_part(v_timestring, ':', 3), ''), '0'); + + IF (v_seconds ~ '\.') THEN + v_fseconds := split_part(v_seconds, '.', 2); + v_seconds := split_part(v_seconds, '.', 1); + END IF; + EXCEPTION + WHEN OTHERS THEN + RAISE invalid_datetime_format; + END; + ELSIF (v_dayparts[1] IN ('PM', 'م')) + THEN + v_hours := 12; + END IF; + + BEGIN + IF (v_res_datatype IN ('DATETIME', 'SMALLDATETIME')) + THEN + v_res_datetime := sys.datetimefromparts(v_year, v_month::SMALLINT, v_day::SMALLINT, + v_hours, v_minutes, v_seconds::SMALLINT, + rpad(v_fseconds, 3, '0')::NUMERIC); + IF (v_res_datatype = 'SMALLDATETIME' AND + to_char(v_res_datetime, 'SS') <> '00') + THEN + IF (to_char(v_res_datetime, 'SS')::SMALLINT >= 30) THEN + v_res_datetime := v_res_datetime + INTERVAL '1 minute'; + END IF; + + v_res_datetime := to_timestamp(to_char(v_res_datetime, 'DD.MM.YYYY.HH24.MI'), 'DD.MM.YYYY.HH24.MI'); + END IF; + ELSE + v_fseconds := sys.babelfish_get_microsecs_from_fractsecs(rpad(v_fseconds, 9, '0'), v_scale); + v_seconds := concat_ws('.', v_seconds, v_fseconds); + + v_res_datetime := make_timestamp(v_year, v_month::SMALLINT, v_day::SMALLINT, + v_hours, v_minutes, v_seconds::NUMERIC); + END IF; + EXCEPTION + WHEN OTHERS THEN + GET STACKED DIAGNOSTICS v_err_message = MESSAGE_TEXT; + + IF (v_err_message ~* 'Cannot construct data type') THEN + RAISE invalid_datetime_format; + END IF; + END; + + IF (v_weekdaynames[1] IS NOT NULL) THEN + v_weekdaynum := sys.babelfish_get_weekdaynum_by_name(v_weekdaynames[1], v_lang_metadata_json); + + IF (CASE date_part('dow', v_res_date)::SMALLINT + WHEN 0 THEN 7 + ELSE date_part('dow', v_res_date)::SMALLINT + END <> v_weekdaynum) + THEN + RAISE invalid_datetime_format; + END IF; + END IF; + + RETURN v_res_datetime; +EXCEPTION + WHEN invalid_datetime_format OR datetime_field_overflow THEN + RAISE USING MESSAGE := format('Error converting string value ''%s'' into data type %s using culture ''%s''.', + p_datetimestring, v_res_datatype, p_culture), + 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 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 := 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 := 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_parameter_value THEN + RAISE USING MESSAGE := CASE char_length(coalesce(CONVERSION_LANG, '')) + WHEN 0 THEN format('The culture parameter ''%s'' provided in the function call is not supported.', + p_culture) + ELSE format('Invalid CONVERSION_LANG constant value - ''%s''. Allowed values are: ''English'', ''Deutsch'', etc.', + CONVERSION_LANG) + END, + DETAIL := 'Passed incorrect value for "p_culture" parameter or compiled incorrect CONVERSION_LANG constant value in function''s body.', + HINT := 'Check "p_culture" input parameter value, correct it if needed, and try again. Also check CONVERSION_LANG constant value.'; + + 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 := format('Error while trying to convert "%s" value to SMALLINT data type.', + v_err_message), + DETAIL := 'Supplied value contains illegal characters.', + HINT := 'Correct supplied value, remove all illegal characters.'; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_parse_to_time(IN p_datatype TEXT, + IN p_srctimestring TEXT, + IN p_culture TEXT DEFAULT '') +RETURNS TIME WITHOUT TIME ZONE +AS +$BODY$ +DECLARE + v_day VARCHAR; + v_year SMALLINT; + v_month VARCHAR; + v_res_date DATE; + v_scale SMALLINT; + v_hijridate DATE; + v_culture VARCHAR; + v_dayparts TEXT[]; + v_resmask VARCHAR; + v_datatype VARCHAR; + v_raw_year VARCHAR; + v_left_part VARCHAR; + v_right_part VARCHAR; + v_resmask_fi VARCHAR; + v_timestring VARCHAR; + v_correctnum VARCHAR; + v_weekdaynum SMALLINT; + v_err_message VARCHAR; + v_date_format VARCHAR; + v_weekdaynames TEXT[]; + v_hours SMALLINT := 0; + v_srctimestring VARCHAR; + v_minutes SMALLINT := 0; + v_res_datatype VARCHAR; + v_error_message VARCHAR; + v_found BOOLEAN := TRUE; + v_compday_regexp VARCHAR; + v_regmatch_groups TEXT[]; + v_datatype_groups TEXT[]; + v_seconds VARCHAR := '0'; + v_fseconds VARCHAR := '0'; + v_compmonth_regexp VARCHAR; + v_lang_metadata_json JSONB; + v_resmask_cnt SMALLINT := 10; + v_res_time TIME WITHOUT TIME ZONE; + DAYMM_REGEXP CONSTANT VARCHAR := '(\d{1,2})'; + FULLYEAR_REGEXP CONSTANT VARCHAR := '(\d{3,4})'; + SHORTYEAR_REGEXP CONSTANT VARCHAR := '(\d{1,2})'; + COMPYEAR_REGEXP CONSTANT VARCHAR := '(\d{1,4})'; + AMPM_REGEXP CONSTANT VARCHAR := '(?:[AP]M|ص|م)'; + TIMEUNIT_REGEXP CONSTANT VARCHAR := '\s*\d{1,2}\s*'; + MASKSEPONE_REGEXP CONSTANT VARCHAR := '\s*(?:/|-)?'; + MASKSEPTWO_REGEXP CONSTANT VARCHAR := '\s*(?:\s|/|-|\.|,)'; + MASKSEPTWO_FI_REGEXP CONSTANT VARCHAR := '\s*(?:\s|/|-|,)'; + MASKSEPTHREE_REGEXP CONSTANT VARCHAR := '\s*(?:/|-|\.|,)'; + TIME_MASKSEP_REGEXP CONSTANT VARCHAR := '(?:\s|\.|,)*'; + TIME_MASKSEP_FI_REGEXP CONSTANT VARCHAR := '(?:\s|,)*'; + WEEKDAYAMPM_START_REGEXP CONSTANT VARCHAR := '(^|[[:digit:][:space:]\.,])'; + WEEKDAYAMPM_END_REGEXP CONSTANT VARCHAR := '([[:digit:][:space:]\.,]|$)(?=[^/-]|$)'; + CORRECTNUM_REGEXP CONSTANT VARCHAR := '(?:([+-]\d{1,4})(?:[[:space:]\.,]|[AP]M|ص|م|$))'; + DATATYPE_REGEXP CONSTANT VARCHAR := '^(TIME)\s*(?:\()?\s*((?:-)?\d+)?\s*(?:\))?$'; + ANNO_DOMINI_REGEXP VARCHAR := '(AD|A\.D\.)'; + ANNO_DOMINI_COMPREGEXP VARCHAR := concat(WEEKDAYAMPM_START_REGEXP, ANNO_DOMINI_REGEXP, WEEKDAYAMPM_END_REGEXP); + HHMMSSFS_PART_REGEXP CONSTANT VARCHAR := + concat(TIMEUNIT_REGEXP, AMPM_REGEXP, '|', + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, TIMEUNIT_REGEXP, '\:', TIME_MASKSEP_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, TIMEUNIT_REGEXP, '(?!\d)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?|', + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, TIMEUNIT_REGEXP, '\:', TIME_MASKSEP_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, TIMEUNIT_REGEXP, '\:', TIME_MASKSEP_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, TIMEUNIT_REGEXP, '(?!\d)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?|', + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, TIMEUNIT_REGEXP, '\:', TIME_MASKSEP_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, TIMEUNIT_REGEXP, '\:', TIME_MASKSEP_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\s*\d{1,2}\.\d+(?!\d)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?|', + AMPM_REGEXP, '?'); + HHMMSSFS_PART_FI_REGEXP CONSTANT VARCHAR := + concat(TIMEUNIT_REGEXP, AMPM_REGEXP, '|', + AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, TIMEUNIT_REGEXP, '[\:\.]', TIME_MASKSEP_FI_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, TIMEUNIT_REGEXP, '(?!\d)', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?\.?|', + AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, TIMEUNIT_REGEXP, '[\:\.]', TIME_MASKSEP_FI_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, TIMEUNIT_REGEXP, '[\:\.]', TIME_MASKSEP_FI_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, TIMEUNIT_REGEXP, '(?!\d)', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?|', + AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, TIMEUNIT_REGEXP, '[\:\.]', TIME_MASKSEP_FI_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, TIMEUNIT_REGEXP, '[\:\.]', TIME_MASKSEP_FI_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, '\s*\d{1,2}\.\d+(?!\d)\.?', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?|', + AMPM_REGEXP, '?'); + v_defmask1_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, + '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, + CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + TIME_MASKSEP_REGEXP, '(?:[\.|,]+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)', TIME_MASKSEP_REGEXP, '$'); + v_defmask1_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, CORRECTNUM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, + '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_FI_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:', MASKSEPTWO_FI_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, + CORRECTNUM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:[,]+', AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, CORRECTNUM_REGEXP, '?))', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + TIME_MASKSEP_FI_REGEXP, '(?:[\.|,]+', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask2_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, + '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, + AMPM_REGEXP, TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + TIME_MASKSEP_REGEXP, '(?:(?:[\.|,]+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?)|', + CORRECTNUM_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, '$'); + v_defmask2_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, CORRECTNUM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, + '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + CORRECTNUM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_FI_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_FI_REGEXP, CORRECTNUM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, + AMPM_REGEXP, TIME_MASKSEP_FI_REGEXP, CORRECTNUM_REGEXP, '?))', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + TIME_MASKSEP_FI_REGEXP, '(?:(?:[\.|,]+', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, TIME_MASKSEP_FI_REGEXP, CORRECTNUM_REGEXP, '?)|', + CORRECTNUM_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask3_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, ')|', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + TIME_MASKSEP_REGEXP, '(', TIME_MASKSEP_REGEXP, AMPM_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask3_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + TIME_MASKSEP_FI_REGEXP, '[\./]?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)', + FULLYEAR_REGEXP, + TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask4_0_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, '\s*(', AMPM_REGEXP, ')', + TIME_MASKSEP_REGEXP, '$'); + v_defmask4_1_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:\s|,)+', + DAYMM_REGEXP, '\s*(', AMPM_REGEXP, ')', + TIME_MASKSEP_REGEXP, '$'); + v_defmask4_2_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '\s*[\.]+', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, '\s*(', AMPM_REGEXP, ')', + TIME_MASKSEP_REGEXP, '$'); + v_defmask5_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask5_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_FI_REGEXP, + FULLYEAR_REGEXP, + TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask6_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '((?:(?:\s|\.|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_REGEXP, '))?', TIME_MASKSEP_REGEXP, '$'); + v_defmask6_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:\s*[\.])?', + '((?:(?:\s|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_FI_REGEXP, '))?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask7_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '((?:(?:\s|\.|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_REGEXP, '))?', TIME_MASKSEP_REGEXP, '$'); + v_defmask7_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_FI_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '((?:(?:\s|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_FI_REGEXP, '))?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask8_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:[\.|,]+', AMPM_REGEXP, ')?', + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask8_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_FI_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:[,]+', AMPM_REGEXP, '))', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:[,]+', AMPM_REGEXP, '))', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:(?:[\,]+|\s*/\s*)', AMPM_REGEXP, ')?', + TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask9_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', + HHMMSSFS_PART_REGEXP, + ')', TIME_MASKSEP_REGEXP, '$'); + v_defmask9_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, '(', + HHMMSSFS_PART_FI_REGEXP, + ')', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask10_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)?', TIME_MASKSEP_REGEXP, + '($comp_month$)', + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask10_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)?', TIME_MASKSEP_REGEXP, + '($comp_month$)', + TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask11_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask11_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '((?:(?:\s|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_FI_REGEXP, '))?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask12_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask12_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask13_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$'); + v_defmask13_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask14_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + '($comp_month$)' + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)', TIME_MASKSEP_REGEXP, + COMPYEAR_REGEXP, + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask14_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + '($comp_month$)' + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)', TIME_MASKSEP_FI_REGEXP, + COMPYEAR_REGEXP, + '((?:(?:\s|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_FI_REGEXP, '))?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask15_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + COMPYEAR_REGEXP, + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask15_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + COMPYEAR_REGEXP, + '((?:(?:\s|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_FI_REGEXP, '))?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask16_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)', TIME_MASKSEP_REGEXP, + COMPYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask16_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)', TIME_MASKSEP_REGEXP, + COMPYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask17_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask17_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '((?:(?:\s|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_FI_REGEXP, '))?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask18_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask18_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask19_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '((?:(?:\s|\.|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_REGEXP, '))?', TIME_MASKSEP_REGEXP, '$'); + v_defmask19_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '((?:(?:\s|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_FI_REGEXP, '))?', TIME_MASKSEP_FI_REGEXP, '$'); + CONVERSION_LANG CONSTANT VARCHAR := ''; + DATE_FORMAT CONSTANT VARCHAR := ''; +BEGIN + v_datatype := trim(p_datatype); + v_srctimestring := upper(trim(p_srctimestring)); + v_culture := coalesce(nullif(upper(trim(p_culture)), ''), 'EN-US'); + + 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 (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; + + v_dayparts := ARRAY(SELECT upper(array_to_string(regexp_matches(v_srctimestring, '[AP]M|ص|م', 'gi'), ''))); + + IF (array_length(v_dayparts, 1) > 1) THEN + RAISE invalid_datetime_format; + END IF; + + BEGIN + v_lang_metadata_json := sys.babelfish_get_lang_metadata_json(coalesce(nullif(CONVERSION_LANG, ''), p_culture)); + EXCEPTION + WHEN OTHERS THEN + RAISE invalid_parameter_value; + END; + + v_compday_regexp := array_to_string(array_cat(array_cat(ARRAY(SELECT jsonb_array_elements_text(v_lang_metadata_json -> 'days_names')), + ARRAY(SELECT jsonb_array_elements_text(v_lang_metadata_json -> 'days_shortnames'))), + ARRAY(SELECT jsonb_array_elements_text(v_lang_metadata_json -> 'days_extrashortnames'))), '|'); + + v_weekdaynames := ARRAY(SELECT array_to_string(regexp_matches(v_srctimestring, v_compday_regexp, 'gi'), '')); + + IF (array_length(v_weekdaynames, 1) > 1) THEN + RAISE invalid_datetime_format; + END IF; + + IF (v_weekdaynames[1] IS NOT NULL AND + v_srctimestring ~* concat(WEEKDAYAMPM_START_REGEXP, '(', v_compday_regexp, ')', WEEKDAYAMPM_END_REGEXP)) + THEN + v_srctimestring := replace(v_srctimestring, v_weekdaynames[1], ' '); + END IF; + + IF (v_srctimestring ~* ANNO_DOMINI_COMPREGEXP) + THEN + IF (v_culture !~ 'EN[-_]US|DA[-_]DK|SV[-_]SE|EN[-_]GB|HI[-_]IS') THEN + RAISE invalid_datetime_format; + END IF; + + v_srctimestring := regexp_replace(v_srctimestring, + ANNO_DOMINI_COMPREGEXP, + regexp_replace(array_to_string(regexp_matches(v_srctimestring, ANNO_DOMINI_COMPREGEXP, 'gi'), ''), + ANNO_DOMINI_REGEXP, ' ', 'gi'), + 'gi'); + END IF; + + v_date_format := coalesce(nullif(upper(trim(DATE_FORMAT)), ''), v_lang_metadata_json ->> 'date_format'); + + v_compmonth_regexp := + array_to_string(array_cat(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'))), + array_cat(ARRAY(SELECT jsonb_array_elements_text(v_lang_metadata_json -> 'months_extrashortnames')), + ARRAY(SELECT jsonb_array_elements_text(v_lang_metadata_json -> 'months_extranames'))) + ), '|'); + + IF ((v_srctimestring ~* v_defmask1_regexp AND v_culture <> 'FI') OR + (v_srctimestring ~* v_defmask1_fi_regexp AND v_culture = 'FI')) + THEN + IF (v_srctimestring ~ concat(CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d+\s*(?:\.)+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, + CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}|', + '\d+\s*(?:\.)+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, + CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$') AND + v_culture ~ 'DE[-_]DE|NN[-_]NO|CS[-_]CZ|PL[-_]PL|RO[-_]RO|SK[-_]SK|SL[-_]SI|BG[-_]BG|RU[-_]RU|TR[-_]TR|ET[-_]EE|LV[-_]LV') + THEN + RAISE invalid_datetime_format; + END IF; + + v_regmatch_groups := regexp_matches(v_srctimestring, CASE v_culture + WHEN 'FI' THEN v_defmask1_fi_regexp + ELSE v_defmask1_regexp + END, 'gi'); + v_timestring := v_regmatch_groups[2]; + v_correctnum := coalesce(v_regmatch_groups[1], v_regmatch_groups[3], + v_regmatch_groups[5], v_regmatch_groups[6]); + + IF (v_date_format = 'DMY' OR + v_culture IN ('SV-SE', 'SV_SE', 'LV-LV', 'LV_LV')) + THEN + v_day := v_regmatch_groups[4]; + v_month := v_regmatch_groups[7]; + ELSE + v_day := v_regmatch_groups[7]; + v_month := v_regmatch_groups[4]; + END IF; + + IF (v_culture IN ('AR', 'AR-SA', 'AR_SA')) + THEN + IF (v_day::SMALLINT > 30 OR + v_month::SMALLINT > 12) THEN + RAISE invalid_datetime_format; + END IF; + + v_raw_year := to_char(sys.babelfish_conv_greg_to_hijri(current_date + 1), 'YYYY'); + v_hijridate := sys.babelfish_conv_hijri_to_greg(v_day, v_month, v_raw_year) - 1; + + v_day := to_char(v_hijridate, 'DD'); + v_month := to_char(v_hijridate, 'MM'); + v_year := to_char(v_hijridate, 'YYYY')::SMALLINT; + ELSE + v_year := to_char(current_date, 'YYYY')::SMALLINT; + END IF; + + ELSIF ((v_srctimestring ~* v_defmask6_regexp AND v_culture <> 'FI') OR + (v_srctimestring ~* v_defmask6_fi_regexp AND v_culture = 'FI')) + THEN + IF (v_culture IN ('AR', 'AR-SA', 'AR_SA') OR + (v_srctimestring ~ concat('\s*\d{1,2}\.\s*(?:\.|\d+(?!\d)\s*\.)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{3,4}', + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, '\d{1,2}|', + '\d{3,4}', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}', MASKSEPTWO_REGEXP, + TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}\s*(?:\.)+|', + '\d+\s*(?:\.)+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$') AND + v_culture ~ 'DE[-_]DE|NN[-_]NO|CS[-_]CZ|PL[-_]PL|RO[-_]RO|SK[-_]SK|SL[-_]SI|BG[-_]BG|RU[-_]RU|TR[-_]TR|ET[-_]EE|LV[-_]LV')) + THEN + RAISE invalid_datetime_format; + END IF; + + v_regmatch_groups := regexp_matches(v_srctimestring, CASE v_culture + WHEN 'FI' THEN v_defmask6_fi_regexp + ELSE v_defmask6_regexp + END, 'gi'); + v_timestring := concat(v_regmatch_groups[1], v_regmatch_groups[5]); + v_day := v_regmatch_groups[4]; + v_month := v_regmatch_groups[3]; + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN v_regmatch_groups[2]::SMALLINT - 543 + ELSE v_regmatch_groups[2]::SMALLINT + END; + + ELSIF ((v_srctimestring ~* v_defmask2_regexp AND v_culture <> 'FI') OR + (v_srctimestring ~* v_defmask2_fi_regexp AND v_culture = 'FI')) + THEN + IF (v_culture IN ('AR', 'AR-SA', 'AR_SA') OR + (v_srctimestring ~ concat('\s*\d{1,2}\.\s*(?:\.|\d+(?!\d)\s*\.)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{3,4}', + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, + AMPM_REGEXP, TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?))', TIME_MASKSEP_REGEXP, '\d{1,2}|', + '\d+\s*(?:\.)+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$') AND + v_culture ~ 'DE[-_]DE|NN[-_]NO|CS[-_]CZ|PL[-_]PL|RO[-_]RO|SK[-_]SK|SL[-_]SI|BG[-_]BG|RU[-_]RU|TR[-_]TR|ET[-_]EE|LV[-_]LV')) + THEN + RAISE invalid_datetime_format; + END IF; + + v_regmatch_groups := regexp_matches(v_srctimestring, CASE v_culture + WHEN 'FI' THEN v_defmask2_fi_regexp + ELSE v_defmask2_regexp + END, 'gi'); + v_timestring := v_regmatch_groups[2]; + v_correctnum := coalesce(v_regmatch_groups[1], v_regmatch_groups[3], v_regmatch_groups[5], + v_regmatch_groups[6], v_regmatch_groups[8], v_regmatch_groups[9]); + v_day := '01'; + v_month := v_regmatch_groups[7]; + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN v_regmatch_groups[4]::SMALLINT - 543 + ELSE v_regmatch_groups[4]::SMALLINT + END; + + ELSIF (v_srctimestring ~* v_defmask4_1_regexp OR + (v_srctimestring ~* v_defmask4_2_regexp AND v_culture !~ 'DE[-_]DE|NN[-_]NO|CS[-_]CZ|PL[-_]PL|RO[-_]RO|SK[-_]SK|SL[-_]SI|BG[-_]BG|RU[-_]RU|TR[-_]TR|ET[-_]EE|LV[-_]LV') OR + (v_srctimestring ~* v_defmask9_regexp AND v_culture <> 'FI') OR + (v_srctimestring ~* v_defmask9_fi_regexp AND v_culture = 'FI')) + THEN + IF (v_srctimestring ~ concat('\d+\s*\.?(?:,+|,*', AMPM_REGEXP, ')', TIME_MASKSEP_FI_REGEXP, '\.+', TIME_MASKSEP_REGEXP, '$|', + '\d+\s*\.', TIME_MASKSEP_FI_REGEXP, '\.', TIME_MASKSEP_FI_REGEXP, '$') AND + v_culture = 'FI') + THEN + RAISE invalid_datetime_format; + END IF; + + IF (v_srctimestring ~* v_defmask4_0_regexp) THEN + v_timestring := (regexp_matches(v_srctimestring, v_defmask4_0_regexp, 'gi'))[1]; + ELSE + v_timestring := v_srctimestring; + END IF; + + v_res_date := current_date; + v_day := to_char(v_res_date, 'DD'); + v_month := to_char(v_res_date, 'MM'); + v_year := to_char(v_res_date, 'YYYY')::SMALLINT; + + ELSIF ((v_srctimestring ~* v_defmask3_regexp AND v_culture <> 'FI') OR + (v_srctimestring ~* v_defmask3_fi_regexp AND v_culture = 'FI')) + THEN + IF (v_culture IN ('AR', 'AR-SA', 'AR_SA') OR + (v_srctimestring ~ concat('\s*\d{1,2}\.\s*(?:\.|\d+(?!\d)\s*\.)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', + TIME_MASKSEP_REGEXP, '\d{1,2}', MASKSEPTWO_REGEXP, '|', + '\d+\s*(?:\.)+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$') AND + v_culture ~ 'DE[-_]DE|NN[-_]NO|CS[-_]CZ|PL[-_]PL|RO[-_]RO|SK[-_]SK|SL[-_]SI|BG[-_]BG|RU[-_]RU|TR[-_]TR|ET[-_]EE|LV[-_]LV')) + THEN + RAISE invalid_datetime_format; + END IF; + + v_regmatch_groups := regexp_matches(v_srctimestring, CASE v_culture + WHEN 'FI' THEN v_defmask3_fi_regexp + ELSE v_defmask3_regexp + END, 'gi'); + v_timestring := v_regmatch_groups[1]; + v_day := '01'; + v_month := v_regmatch_groups[2]; + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN v_regmatch_groups[3]::SMALLINT - 543 + ELSE v_regmatch_groups[3]::SMALLINT + END; + + ELSIF ((v_srctimestring ~* v_defmask5_regexp AND v_culture <> 'FI') OR + (v_srctimestring ~* v_defmask5_fi_regexp AND v_culture = 'FI')) + THEN + IF (v_culture IN ('AR', 'AR-SA', 'AR_SA') OR + (v_srctimestring ~ concat('\s*\d{1,2}\.\s*(?:\.|\d+(?!\d)\s*\.)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}', MASKSEPTWO_REGEXP, + TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}', MASKSEPTWO_REGEXP, + TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{3,4}', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$|', + '\d{1,2}', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{3,4}\s*(?:\.)+|', + '\d+\s*(?:\.)+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$') AND + v_culture ~ 'DE[-_]DE|NN[-_]NO|CS[-_]CZ|PL[-_]PL|RO[-_]RO|SK[-_]SK|SL[-_]SI|BG[-_]BG|RU[-_]RU|TR[-_]TR|ET[-_]EE|LV[-_]LV')) + THEN + RAISE invalid_datetime_format; + END IF; + + v_regmatch_groups := regexp_matches(v_srctimestring, v_defmask5_regexp, 'gi'); + v_timestring := concat(v_regmatch_groups[1], v_regmatch_groups[5]); + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN v_regmatch_groups[4]::SMALLINT - 543 + ELSE v_regmatch_groups[4]::SMALLINT + END; + + IF (v_date_format = 'DMY' OR + v_culture IN ('LV-LV', 'LV_LV')) + THEN + v_day := v_regmatch_groups[2]; + v_month := v_regmatch_groups[3]; + ELSE + v_day := v_regmatch_groups[3]; + v_month := v_regmatch_groups[2]; + END IF; + + ELSIF ((v_srctimestring ~* v_defmask7_regexp AND v_culture <> 'FI') OR + (v_srctimestring ~* v_defmask7_fi_regexp AND v_culture = 'FI')) + THEN + IF (v_culture IN ('AR', 'AR-SA', 'AR_SA') OR + (v_srctimestring ~ concat('\s*\d{1,2}\.\s*(?:\.|\d+(?!\d)\s*\.)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}', + MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{3,4}|', + '\d{3,4}', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}\s*(?:\.)+|', + '\d+\s*(?:\.)+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$') AND + v_culture ~ 'DE[-_]DE|NN[-_]NO|CS[-_]CZ|PL[-_]PL|RO[-_]RO|SK[-_]SK|SL[-_]SI|BG[-_]BG|RU[-_]RU|TR[-_]TR|ET[-_]EE|LV[-_]LV')) + THEN + RAISE invalid_datetime_format; + END IF; + + v_regmatch_groups := regexp_matches(v_srctimestring, CASE v_culture + WHEN 'FI' THEN v_defmask7_fi_regexp + ELSE v_defmask7_regexp + END, 'gi'); + v_timestring := concat(v_regmatch_groups[1], v_regmatch_groups[5]); + v_day := v_regmatch_groups[4]; + v_month := v_regmatch_groups[2]; + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN v_regmatch_groups[3]::SMALLINT - 543 + ELSE v_regmatch_groups[3]::SMALLINT + END; + + ELSIF ((v_srctimestring ~* v_defmask8_regexp AND v_culture <> 'FI') OR + (v_srctimestring ~* v_defmask8_fi_regexp AND v_culture = 'FI')) + THEN + IF (v_srctimestring ~ concat('\s*\d{1,2}\.\s*(?:\.|\d+(?!\d)\s*\.)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}', + MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}', MASKSEPTWO_REGEXP, + TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}|', + '\d{1,2}', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}', MASKSEPTWO_REGEXP, + TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}\s*(?:\.)+|', + '\d+\s*(?:\.)+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$') AND + v_culture ~ 'FI|DE[-_]DE|NN[-_]NO|CS[-_]CZ|PL[-_]PL|RO[-_]RO|SK[-_]SK|SL[-_]SI|BG[-_]BG|RU[-_]RU|TR[-_]TR|ET[-_]EE|LV[-_]LV') + THEN + RAISE invalid_datetime_format; + END IF; + + v_regmatch_groups := regexp_matches(v_srctimestring, CASE v_culture + WHEN 'FI' THEN v_defmask8_fi_regexp + ELSE v_defmask8_regexp + END, 'gi'); + v_timestring := concat(v_regmatch_groups[1], v_regmatch_groups[5]); + + IF (v_date_format = 'DMY' OR + v_culture IN ('LV-LV', 'LV_LV')) + THEN + v_day := v_regmatch_groups[2]; + v_month := v_regmatch_groups[3]; + v_raw_year := v_regmatch_groups[4]; + ELSIF (v_date_format = 'YMD') + THEN + v_day := v_regmatch_groups[4]; + v_month := v_regmatch_groups[3]; + v_raw_year := v_regmatch_groups[2]; + ELSE + v_day := v_regmatch_groups[3]; + v_month := v_regmatch_groups[2]; + v_raw_year := v_regmatch_groups[4]; + END IF; + + IF (v_culture IN ('AR', 'AR-SA', 'AR_SA')) + THEN + IF (v_day::SMALLINT > 30 OR + v_month::SMALLINT > 12) THEN + RAISE invalid_datetime_format; + END IF; + + v_raw_year := sys.babelfish_get_full_year(v_raw_year, '14'); + v_hijridate := sys.babelfish_conv_hijri_to_greg(v_day, v_month, v_raw_year) - 1; + + v_day := to_char(v_hijridate, 'DD'); + v_month := to_char(v_hijridate, 'MM'); + v_year := to_char(v_hijridate, 'YYYY')::SMALLINT; + + ELSIF (v_culture IN ('TH-TH', 'TH_TH')) THEN + v_year := sys.babelfish_get_full_year(v_raw_year)::SMALLINT - 43; + ELSE + v_year := sys.babelfish_get_full_year(v_raw_year, '', 29)::SMALLINT; + END IF; + ELSE + v_found := FALSE; + END IF; + + WHILE (NOT v_found AND v_resmask_cnt < 20) + LOOP + v_resmask := replace(CASE v_resmask_cnt + WHEN 10 THEN v_defmask10_regexp + WHEN 11 THEN v_defmask11_regexp + WHEN 12 THEN v_defmask12_regexp + WHEN 13 THEN v_defmask13_regexp + WHEN 14 THEN v_defmask14_regexp + WHEN 15 THEN v_defmask15_regexp + WHEN 16 THEN v_defmask16_regexp + WHEN 17 THEN v_defmask17_regexp + WHEN 18 THEN v_defmask18_regexp + WHEN 19 THEN v_defmask19_regexp + END, + '$comp_month$', v_compmonth_regexp); + + v_resmask_fi := replace(CASE v_resmask_cnt + WHEN 10 THEN v_defmask10_fi_regexp + WHEN 11 THEN v_defmask11_fi_regexp + WHEN 12 THEN v_defmask12_fi_regexp + WHEN 13 THEN v_defmask13_fi_regexp + WHEN 14 THEN v_defmask14_fi_regexp + WHEN 15 THEN v_defmask15_fi_regexp + WHEN 16 THEN v_defmask16_fi_regexp + WHEN 17 THEN v_defmask17_fi_regexp + WHEN 18 THEN v_defmask18_fi_regexp + WHEN 19 THEN v_defmask19_fi_regexp + END, + '$comp_month$', v_compmonth_regexp); + + IF ((v_srctimestring ~* v_resmask AND v_culture <> 'FI') OR + (v_srctimestring ~* v_resmask_fi AND v_culture = 'FI')) + THEN + v_found := TRUE; + v_regmatch_groups := regexp_matches(v_srctimestring, CASE v_culture + WHEN 'FI' THEN v_resmask_fi + ELSE v_resmask + END, 'gi'); + v_timestring := CASE + WHEN v_resmask_cnt IN (10, 11, 12, 13) THEN concat(v_regmatch_groups[1], v_regmatch_groups[4]) + ELSE concat(v_regmatch_groups[1], v_regmatch_groups[5]) + END; + + IF (v_resmask_cnt = 10) + THEN + IF (v_regmatch_groups[3] = 'MAR' AND + v_culture IN ('IT-IT', 'IT_IT')) + THEN + RAISE invalid_datetime_format; + END IF; + + IF (v_date_format = 'YMD' AND v_culture NOT IN ('SV-SE', 'SV_SE', 'LV-LV', 'LV_LV')) + THEN + v_day := '01'; + v_year := sys.babelfish_get_full_year(v_regmatch_groups[2], '', 29)::SMALLINT; + ELSE + v_day := v_regmatch_groups[2]; + v_year := to_char(current_date, 'YYYY')::SMALLINT; + END IF; + + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[3], v_lang_metadata_json); + v_raw_year := to_char(sys.babelfish_conv_greg_to_hijri(current_date + 1), 'YYYY'); + + ELSIF (v_resmask_cnt = 11) + THEN + IF (v_date_format IN ('YMD', 'MDY') AND v_culture NOT IN ('SV-SE', 'SV_SE')) + THEN + v_day := v_regmatch_groups[3]; + v_year := to_char(current_date, 'YYYY')::SMALLINT; + ELSE + v_day := '01'; + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN sys.babelfish_get_full_year(v_regmatch_groups[3])::SMALLINT - 43 + ELSE sys.babelfish_get_full_year(v_regmatch_groups[3], '', 29)::SMALLINT + END; + END IF; + + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[2], v_lang_metadata_json); + v_raw_year := sys.babelfish_get_full_year(substring(v_year::TEXT, 3, 2), '14'); + + ELSIF (v_resmask_cnt = 12) + THEN + v_day := '01'; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[3], v_lang_metadata_json); + v_raw_year := v_regmatch_groups[2]; + + ELSIF (v_resmask_cnt = 13) + THEN + v_day := '01'; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[2], v_lang_metadata_json); + v_raw_year := v_regmatch_groups[3]; + + ELSIF (v_resmask_cnt IN (14, 15, 16)) + THEN + IF (v_resmask_cnt = 14) + THEN + v_left_part := v_regmatch_groups[4]; + v_right_part := v_regmatch_groups[3]; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[2], v_lang_metadata_json); + ELSIF (v_resmask_cnt = 15) + THEN + v_left_part := v_regmatch_groups[4]; + v_right_part := v_regmatch_groups[2]; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[3], v_lang_metadata_json); + ELSE + v_left_part := v_regmatch_groups[3]; + v_right_part := v_regmatch_groups[2]; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[4], v_lang_metadata_json); + END IF; + + IF (char_length(v_left_part) <= 2) + THEN + IF (v_date_format = 'YMD' AND v_culture NOT IN ('LV-LV', 'LV_LV')) + THEN + v_day := v_left_part; + v_raw_year := sys.babelfish_get_full_year(v_right_part, '14'); + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN sys.babelfish_get_full_year(v_right_part)::SMALLINT - 43 + ELSE sys.babelfish_get_full_year(v_right_part, '', 29)::SMALLINT + END; + BEGIN + v_res_date := make_date(v_year, v_month::SMALLINT, v_day::SMALLINT); + EXCEPTION + WHEN OTHERS THEN + v_day := v_right_part; + v_raw_year := sys.babelfish_get_full_year(v_left_part, '14'); + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN sys.babelfish_get_full_year(v_left_part)::SMALLINT - 43 + ELSE sys.babelfish_get_full_year(v_left_part, '', 29)::SMALLINT + END; + END; + END IF; + + IF (v_date_format IN ('MDY', 'DMY') OR v_culture IN ('LV-LV', 'LV_LV')) + THEN + v_day := v_right_part; + v_raw_year := sys.babelfish_get_full_year(v_left_part, '14'); + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN sys.babelfish_get_full_year(v_left_part)::SMALLINT - 43 + ELSE sys.babelfish_get_full_year(v_left_part, '', 29)::SMALLINT + END; + BEGIN + v_res_date := make_date(v_year, v_month::SMALLINT, v_day::SMALLINT); + EXCEPTION + WHEN OTHERS THEN + v_day := v_left_part; + v_raw_year := sys.babelfish_get_full_year(v_right_part, '14'); + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN sys.babelfish_get_full_year(v_right_part)::SMALLINT - 43 + ELSE sys.babelfish_get_full_year(v_right_part, '', 29)::SMALLINT + END; + END; + END IF; + ELSE + v_day := v_right_part; + v_raw_year := v_left_part; + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN v_left_part::SMALLINT - 543 + ELSE v_left_part::SMALLINT + END; + END IF; + + ELSIF (v_resmask_cnt = 17) + THEN + v_day := v_regmatch_groups[4]; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[3], v_lang_metadata_json); + v_raw_year := v_regmatch_groups[2]; + + ELSIF (v_resmask_cnt = 18) + THEN + v_day := v_regmatch_groups[3]; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[4], v_lang_metadata_json); + v_raw_year := v_regmatch_groups[2]; + + ELSIF (v_resmask_cnt = 19) + THEN + v_day := v_regmatch_groups[4]; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[2], v_lang_metadata_json); + v_raw_year := v_regmatch_groups[3]; + END IF; + + IF (v_resmask_cnt NOT IN (10, 11, 14, 15, 16)) + THEN + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN v_raw_year::SMALLINT - 543 + ELSE v_raw_year::SMALLINT + END; + END IF; + + IF (v_culture IN ('AR', 'AR-SA', 'AR_SA')) + THEN + IF (v_day::SMALLINT > 30 OR + (v_resmask_cnt NOT IN (10, 11, 14, 15, 16) AND v_year NOT BETWEEN 1318 AND 1501) OR + (v_resmask_cnt IN (14, 15, 16) AND v_raw_year::SMALLINT NOT BETWEEN 1318 AND 1501)) + THEN + RAISE invalid_datetime_format; + END IF; + + v_hijridate := sys.babelfish_conv_hijri_to_greg(v_day, v_month, v_raw_year) - 1; + + v_day := to_char(v_hijridate, 'DD'); + v_month := to_char(v_hijridate, 'MM'); + v_year := to_char(v_hijridate, 'YYYY')::SMALLINT; + END IF; + END IF; + + v_resmask_cnt := v_resmask_cnt + 1; + END LOOP; + + IF (NOT v_found) THEN + RAISE invalid_datetime_format; + END IF; + + v_res_date := make_date(v_year, v_month::SMALLINT, v_day::SMALLINT); + + IF (v_weekdaynames[1] IS NOT NULL) THEN + v_weekdaynum := sys.babelfish_get_weekdaynum_by_name(v_weekdaynames[1], v_lang_metadata_json); + + IF (date_part('dow', v_res_date)::SMALLINT <> v_weekdaynum) THEN + RAISE invalid_datetime_format; + END IF; + END IF; + + IF (char_length(v_timestring) > 0 AND v_timestring NOT IN ('AM', 'ص', 'PM', 'م')) + THEN + IF (v_culture = 'FI') THEN + v_timestring := translate(v_timestring, '.,', ': '); + + IF (char_length(split_part(v_timestring, ':', 4)) > 0) THEN + v_timestring := regexp_replace(v_timestring, ':(?=\s*\d+\s*:?\s*(?:[AP]M|ص|م)?\s*$)', '.'); + END IF; + END IF; + + v_timestring := replace(regexp_replace(v_timestring, '\.?[AP]M|ص|م|\s|\,|\.\D|[\.|:]$', '', 'gi'), ':.', ':'); + + BEGIN + v_hours := coalesce(split_part(v_timestring, ':', 1)::SMALLINT, 0); + + IF ((v_dayparts[1] IN ('AM', 'ص') AND v_hours NOT BETWEEN 0 AND 12) OR + (v_dayparts[1] IN ('PM', 'م') AND v_hours NOT BETWEEN 1 AND 23)) + THEN + RAISE invalid_datetime_format; + ELSIF (v_dayparts[1] = 'PM' AND v_hours < 12) THEN + v_hours := v_hours + 12; + ELSIF (v_dayparts[1] = 'AM' AND v_hours = 12) THEN + v_hours := v_hours - 12; + END IF; + + v_minutes := coalesce(nullif(split_part(v_timestring, ':', 2), '')::SMALLINT, 0); + v_seconds := coalesce(nullif(split_part(v_timestring, ':', 3), ''), '0'); + + IF (v_seconds ~ '\.') THEN + v_fseconds := split_part(v_seconds, '.', 2); + v_seconds := split_part(v_seconds, '.', 1); + END IF; + EXCEPTION + WHEN OTHERS THEN + RAISE invalid_datetime_format; + END; + ELSIF (v_dayparts[1] IN ('PM', 'م')) + THEN + v_hours := 12; + END IF; + + v_fseconds := sys.babelfish_get_microsecs_from_fractsecs(rpad(v_fseconds, 9, '0'), v_scale); + v_seconds := concat_ws('.', v_seconds, v_fseconds); + + v_res_time := make_time(v_hours, v_minutes, v_seconds::NUMERIC); + + RETURN v_res_time; +EXCEPTION + WHEN invalid_datetime_format OR datetime_field_overflow THEN + RAISE USING MESSAGE := format('Error converting string value ''%s'' into data type %s using culture ''%s''.', + p_srctimestring, v_res_datatype, p_culture), + 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 datatype_mismatch THEN + RAISE USING MESSAGE := 'Source data type should be ''TIME'' or ''TIME(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 := 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 := 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_parameter_value THEN + RAISE USING MESSAGE := CASE char_length(coalesce(CONVERSION_LANG, '')) + WHEN 0 THEN format('The culture parameter ''%s'' provided in the function call is not supported.', + p_culture) + ELSE format('Invalid CONVERSION_LANG constant value - ''%s''. Allowed values are: ''English'', ''Deutsch'', etc.', + CONVERSION_LANG) + END, + DETAIL := 'Passed incorrect value for "p_culture" parameter or compiled incorrect CONVERSION_LANG constant value in function''s body.', + HINT := 'Check "p_culture" input parameter value, correct it if needed, and try again. Also check CONVERSION_LANG constant value.'; + + 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 := format('Error while trying to convert "%s" value to SMALLINT data type.', + v_err_message), + DETAIL := 'Supplied value contains illegal characters.', + HINT := 'Correct supplied value, remove all illegal characters.'; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + + + + + +create or replace function sys.babelfish_ROUND3(x in numeric, y in int, z in int)returns numeric +AS +$body$ +BEGIN + + + + if z = 0 or z is null then + return round(x,y); + else + return trunc(x,y); + end if; +END; +$body$ +language plpgsql; + +CREATE OR REPLACE FUNCTION sys.babelfish_round_fractseconds(IN p_fractseconds NUMERIC) +RETURNS INTEGER +AS +$BODY$ +DECLARE + v_modpart INTEGER; + v_decpart INTEGER; + v_fractseconds INTEGER; +BEGIN + v_fractseconds := floor(p_fractseconds)::INTEGER; + v_modpart := v_fractseconds % 10; + v_decpart := v_fractseconds - v_modpart; + + RETURN CASE + WHEN (v_modpart BETWEEN 0 AND 1) THEN v_decpart + WHEN (v_modpart BETWEEN 2 AND 4) THEN v_decpart + 3 + WHEN (v_modpart BETWEEN 5 AND 8) THEN v_decpart + 7 + ELSE v_decpart + 10 -- 9 + END; +END; +$BODY$ +LANGUAGE plpgsql +IMMUTABLE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_round_fractseconds(IN p_fractseconds TEXT) +RETURNS INTEGER +AS +$BODY$ +BEGIN + RETURN sys.babelfish_round_fractseconds(p_fractseconds::NUMERIC); +EXCEPTION + WHEN invalid_text_representation THEN + RAISE USING MESSAGE := format('Error while trying to convert "%s" value to NUMERIC data type.', trim(p_fractseconds)), + DETAIL := 'Passed argument value contains illegal characters.', + HINT := 'Correct passed argument value, remove all illegal characters.'; + + +END; +$BODY$ +LANGUAGE plpgsql +IMMUTABLE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_set_version(pComponentVersion VARCHAR(256),pComponentName VARCHAR(256)) + RETURNS void AS +$BODY$ +DECLARE + rowcount smallint; +BEGIN + UPDATE sys.versions SET componentversion = pComponentVersion + WHERE extpackcomponentname = pComponentName; + GET DIAGNOSTICS rowcount = ROW_COUNT; + + IF rowcount < 1 THEN + INSERT INTO sys.versions(extpackcomponentname,componentversion) + VALUES (pComponentName,pComponentVersion); + END IF; +END; +$BODY$ +LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_add_job ( + par_job_name varchar, + par_enabled smallint = 1, + par_description varchar = NULL::character varying, + par_start_step_id integer = 1, + par_category_name varchar = NULL::character varying, + par_category_id integer = NULL::integer, + par_owner_login_name varchar = NULL::character varying, + par_notify_level_eventlog integer = 2, + par_notify_level_email integer = 0, + par_notify_level_netsend integer = 0, + par_notify_level_page integer = 0, + par_notify_email_operator_name varchar = NULL::character varying, + par_notify_netsend_operator_name varchar = NULL::character varying, + par_notify_page_operator_name varchar = NULL::character varying, + par_delete_level integer = 0, + inout par_job_id integer = NULL::integer, + par_originating_server varchar = NULL::character varying, + out returncode integer +) +RETURNS record AS +$body$ +DECLARE + var_retval INT DEFAULT 0; + var_notify_email_operator_id INT DEFAULT 0; + var_notify_email_operator_name VARCHAR(128); + var_notify_netsend_operator_id INT DEFAULT 0; + var_notify_page_operator_id INT DEFAULT 0; + var_owner_sid CHAR(85) ; + var_originating_server_id INT DEFAULT 0; +BEGIN + + SELECT UPPER(LTRIM(RTRIM(par_originating_server))) INTO par_originating_server; + SELECT LTRIM(RTRIM(par_job_name)) INTO par_job_name; + SELECT LTRIM(RTRIM(par_description)) INTO par_description; + SELECT '[Uncategorized (Local)]' INTO par_category_name; + SELECT 0 INTO par_category_id; + SELECT LTRIM(RTRIM(par_notify_email_operator_name)) INTO par_notify_email_operator_name; + SELECT LTRIM(RTRIM(par_notify_netsend_operator_name)) INTO par_notify_netsend_operator_name; + SELECT LTRIM(RTRIM(par_notify_page_operator_name)) INTO par_notify_page_operator_name; + SELECT NULL INTO var_originating_server_id; + SELECT NULL INTO par_job_id; + + IF (par_originating_server = '') + THEN + SELECT NULL INTO par_originating_server; + END IF; + + IF (par_description = '') + THEN + SELECT NULL INTO par_description; + END IF; + + IF (par_category_name = '') + THEN + SELECT NULL INTO par_category_name; + END IF; + + IF (par_notify_email_operator_name = '') + THEN + SELECT NULL INTO par_notify_email_operator_name; + END IF; + + IF (par_notify_netsend_operator_name = '') + THEN + SELECT NULL INTO par_notify_netsend_operator_name; + END IF; + + IF (par_notify_page_operator_name = '') + THEN + SELECT NULL INTO par_notify_page_operator_name; + END IF; + + + SELECT t.par_owner_sid + , t.par_notify_level_email + , t.par_notify_level_netsend + , t.par_notify_level_page + , t.par_category_id + , t.par_notify_email_operator_id + , t.par_notify_netsend_operator_id + , t.par_notify_page_operator_id + , t.par_originating_server + , t.returncode + FROM sys.babelfish_sp_verify_job( + par_job_id + , par_job_name + , par_enabled + , par_start_step_id + , par_category_name + , var_owner_sid + , par_notify_level_eventlog + , par_notify_level_email + , par_notify_level_netsend + , par_notify_level_page + , par_notify_email_operator_name + , par_notify_netsend_operator_name + , par_notify_page_operator_name + , par_delete_level + , par_category_id + , var_notify_email_operator_id + , var_notify_netsend_operator_id + , var_notify_page_operator_id + , par_originating_server + ) t + INTO var_owner_sid + , par_notify_level_email + , par_notify_level_netsend + , par_notify_level_page + , par_category_id + , var_notify_email_operator_id + , var_notify_netsend_operator_id + , var_notify_page_operator_id + , par_originating_server + , var_retval; + + IF (var_retval <> 0) + THEN + returncode := 1; + RETURN; + END IF; + + var_notify_email_operator_name := par_notify_email_operator_name; + + + IF (par_description IS NULL) + THEN + SELECT 'No description available.' INTO par_description; + END IF; + + var_originating_server_id := 0; + var_owner_sid := ''; + + INSERT + INTO sys.sysjobs ( + originating_server_id + , name + , enabled + , description + , start_step_id + , category_id + , owner_sid + , notify_level_eventlog + , notify_level_email + , notify_level_netsend + , notify_level_page + , notify_email_operator_id + , notify_email_operator_name + , notify_netsend_operator_id + , notify_page_operator_id + , delete_level + , version_number + ) + VALUES ( + var_originating_server_id + , par_job_name + , par_enabled + , par_description + , par_start_step_id + , par_category_id + , var_owner_sid + , par_notify_level_eventlog + , par_notify_level_email + , par_notify_level_netsend + , par_notify_level_page + , var_notify_email_operator_id + , var_notify_email_operator_name + , var_notify_netsend_operator_id + , var_notify_page_operator_id + , par_delete_level + , 1); + + + SELECT LASTVAL() INTO par_job_id; + + + + + returncode := var_retval; + RETURN; + +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_add_jobschedule ( + par_job_id integer = NULL::integer, + par_job_name varchar = NULL::character varying, + par_name varchar = NULL::character varying, + par_enabled smallint = 1, + par_freq_type integer = 1, + par_freq_interval integer = 0, + par_freq_subday_type integer = 0, + par_freq_subday_interval integer = 0, + par_freq_relative_interval integer = 0, + par_freq_recurrence_factor integer = 0, + par_active_start_date integer = 20000101, + par_active_end_date integer = 99991231, + par_active_start_time integer = 0, + par_active_end_time integer = 235959, + inout par_schedule_id integer = NULL::integer, + par_automatic_post smallint = 1, + inout par_schedule_uid char = NULL::bpchar, + out returncode integer +) +AS +$body$ +DECLARE + var_retval INT; + var_owner_login_name VARCHAR(128); +BEGIN + + -- Check that we can uniquely identify the job + SELECT t.par_job_name + , t.par_job_id + , t.returncode + FROM sys.babelfish_sp_verify_job_identifiers ( + '@job_name' + , '@job_id' + , par_job_name + , par_job_id + , 'TEST'::character varying + , NULL::bpchar + ) t + INTO par_job_name + , par_job_id + , var_retval; + + IF (var_retval <> 0) + THEN + returncode := 1; + RETURN; + END IF; + + + SELECT t.par_schedule_uid + , t.par_schedule_id + , t.returncode + FROM sys.babelfish_sp_add_schedule( + par_name + , par_enabled + , par_freq_type + , par_freq_interval + , par_freq_subday_type + , par_freq_subday_interval + , par_freq_relative_interval + , par_freq_recurrence_factor + , par_active_start_date + , par_active_end_date + , par_active_start_time + , par_active_end_time + , var_owner_login_name + , par_schedule_uid + , par_schedule_id + , NULL + ) t + INTO par_schedule_uid + , par_schedule_id + , var_retval; + + IF (var_retval <> 0) THEN + returncode := 1; + RETURN; + END IF; + + SELECT t.returncode + FROM sys.babelfish_sp_attach_schedule( + par_job_id := par_job_id + , par_job_name := NULL + , par_schedule_id := par_schedule_id + , par_schedule_name := NULL + , par_automatic_post := par_automatic_post + ) t + INTO var_retval; + + IF (var_retval <> 0) THEN + returncode := 1; + RETURN; + END IF; + + SELECT t.returncode + FROM sys.babelfish_sp_aws_add_jobschedule(par_job_id, par_schedule_id) t + INTO var_retval; + + IF (var_retval <> 0) THEN + returncode := 1; + RETURN; + END IF; + + + returncode := (var_retval); + RETURN; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_add_jobstep ( + par_job_id integer = NULL::integer, + par_job_name varchar = NULL::character varying, + par_step_id integer = NULL::integer, + par_step_name varchar = NULL::character varying, + par_subsystem varchar = 'TSQL'::bpchar, + par_command text = NULL::text, + par_additional_parameters text = NULL::text, + par_cmdexec_success_code integer = 0, + par_on_success_action smallint = 1, + par_on_success_step_id integer = 0, + par_on_fail_action smallint = 2, + par_on_fail_step_id integer = 0, + par_server varchar = NULL::character varying, + par_database_name varchar = NULL::character varying, + par_database_user_name varchar = NULL::character varying, + par_retry_attempts integer = 0, + par_retry_interval integer = 0, + par_os_run_priority integer = 0, + par_output_file_name varchar = NULL::character varying, + par_flags integer = 0, + par_proxy_id integer = NULL::integer, + par_proxy_name varchar = NULL::character varying, + inout par_step_uid char = NULL::bpchar, + out returncode integer +) +AS +$body$ +DECLARE + var_retval INT; + var_max_step_id INT; + var_step_id INT; +BEGIN + + SELECT t.par_job_name + , t.par_job_id + , t.returncode + FROM sys.babelfish_sp_verify_job_identifiers ( + '@job_name' + , '@job_id' + , par_job_name + , par_job_id + , 'TEST'::character varying + , NULL::bpchar + ) t + INTO par_job_name + , par_job_id + , var_retval; + + IF (var_retval <> 0) THEN + returncode := 1; + RETURN; + END IF; + + -- Default step id (if not supplied) + IF (par_step_id IS NULL) + THEN + SELECT COALESCE(MAX(step_id), 0) + 1 + INTO var_step_id + FROM sys.sysjobsteps + WHERE (job_id = par_job_id); + ELSE + var_step_id := par_step_id; + END IF; + + -- Get current maximum step id + SELECT COALESCE(MAX(step_id), 0) + INTO var_max_step_id + FROM sys.sysjobsteps + WHERE (job_id = par_job_id); + + + SELECT t.returncode + FROM sys.babelfish_sp_verify_jobstep( + par_job_id + , var_step_id --par_step_id + , par_step_name + , par_subsystem + , par_command + , par_server + , par_on_success_action + , par_on_success_step_id + , par_on_fail_action + , par_on_fail_step_id + , par_os_run_priority + , par_flags + , par_output_file_name + , par_proxy_id + ) t + INTO var_retval; + + IF (var_retval <> 0) + THEN + returncode := 1; + RETURN; + END IF; + + + + UPDATE sys.sysjobs + SET version_number = version_number + 1 + --, date_modified = GETDATE() + WHERE (job_id = par_job_id); + + + + IF (var_step_id <= var_max_step_id) + THEN + UPDATE sys.sysjobsteps + SET step_id = step_id + 1 + WHERE (step_id >= var_step_id) AND (job_id = par_job_id); + + + UPDATE sys.sysjobsteps + SET on_success_step_id = on_success_step_id + 1 + WHERE (on_success_step_id >= var_step_id) AND (job_id = par_job_id); + + UPDATE sys.sysjobsteps + SET on_fail_step_id = on_fail_step_id + 1 + WHERE (on_fail_step_id >= var_step_id) AND (job_id = par_job_id); + + UPDATE sys.sysjobsteps + SET on_success_step_id = 0 + , on_success_action = 1 + WHERE (on_success_step_id = var_step_id) + AND (job_id = par_job_id); + + UPDATE sys.sysjobsteps + SET on_fail_step_id = 0 + , on_fail_action = 2 + WHERE (on_fail_step_id = var_step_id) + AND (job_id = par_job_id); + END IF; + + + SELECT uuid_in(md5(random()::text || clock_timestamp()::text)::cstring) INTO par_step_uid; + + + INSERT + INTO sys.sysjobsteps ( + job_id + , step_id + , step_name + , subsystem + , command + , flags + , additional_parameters + , cmdexec_success_code + , on_success_action + , on_success_step_id + , on_fail_action + , on_fail_step_id + , server + , database_name + , database_user_name + , retry_attempts + , retry_interval + , os_run_priority + , output_file_name + , last_run_outcome + , last_run_duration + , last_run_retries + , last_run_date + , last_run_time + , proxy_id + , step_uid + ) + VALUES ( + par_job_id + , var_step_id + , par_step_name + , par_subsystem + , par_command + , par_flags + , par_additional_parameters + , par_cmdexec_success_code + , par_on_success_action + , par_on_success_step_id + , par_on_fail_action + , par_on_fail_step_id + , par_server + , par_database_name + , par_database_user_name + , par_retry_attempts + , par_retry_interval + , par_os_run_priority + , par_output_file_name + , 0 + , 0 + , 0 + , 0 + , 0 + , par_proxy_id + , par_step_uid + ); + + --PERFORM sys.sp_jobstep_create_proc (par_step_uid); + + returncode := var_retval; + RETURN; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_add_schedule ( + par_schedule_name varchar, + par_enabled smallint = 1, + par_freq_type integer = 0, + par_freq_interval integer = 0, + par_freq_subday_type integer = 0, + par_freq_subday_interval integer = 0, + par_freq_relative_interval integer = 0, + par_freq_recurrence_factor integer = 0, + par_active_start_date integer = NULL::integer, + par_active_end_date integer = 99991231, + par_active_start_time integer = 0, + par_active_end_time integer = 235959, + par_owner_login_name varchar = NULL::character varying, + inout par_schedule_uid char = NULL::bpchar, + inout par_schedule_id integer = NULL::integer, + par_originating_server varchar = NULL::character varying, + out returncode integer +) +AS +$body$ +DECLARE + var_retval INT; + var_owner_sid CHAR(85); + var_orig_server_id INT; +BEGIN + + SELECT LTRIM(RTRIM(par_schedule_name)) + , LTRIM(RTRIM(par_owner_login_name)) + , UPPER(LTRIM(RTRIM(par_originating_server))) + , 0 + INTO par_schedule_name + , par_owner_login_name + , par_originating_server + , par_schedule_id; + + + SELECT t.par_freq_interval + , t.par_freq_subday_type + , t.par_freq_subday_interval + , t.par_freq_relative_interval + , t.par_freq_recurrence_factor + , t.par_active_start_date + , t.par_active_start_time + , t.par_active_end_date + , t.par_active_end_time + , t.returncode + FROM sys.babelfish_sp_verify_schedule( + NULL::integer + , par_schedule_name + , par_enabled + , par_freq_type + , par_freq_interval + , par_freq_subday_type + , par_freq_subday_interval + , par_freq_relative_interval + , par_freq_recurrence_factor + , par_active_start_date + , par_active_start_time + , par_active_end_date + , par_active_end_time + , var_owner_sid + ) t + INTO par_freq_interval + , par_freq_subday_type + , par_freq_subday_interval + , par_freq_relative_interval + , par_freq_recurrence_factor + , par_active_start_date + , par_active_start_time + , par_active_end_date + , par_active_end_time + , var_retval ; + + IF (var_retval <> 0) THEN + returncode := 1; + RETURN; + END IF; + + IF (par_schedule_uid IS NULL) + THEN + + SELECT uuid_in(md5(random()::text || clock_timestamp()::text)::cstring) INTO par_schedule_uid; + END IF; + + var_orig_server_id := 0; + var_owner_sid := uuid_in(md5(random()::text || clock_timestamp()::text)::cstring); + + + INSERT + INTO sys.sysschedules ( + schedule_uid + , originating_server_id + , name + , owner_sid + , enabled + , freq_type + , freq_interval + , freq_subday_type + , freq_subday_interval + , freq_relative_interval + , freq_recurrence_factor + , active_start_date + , active_end_date + , active_start_time + , active_end_time + ) + VALUES ( + par_schedule_uid + , var_orig_server_id + , par_schedule_name + , var_owner_sid + , par_enabled + , par_freq_type + , par_freq_interval + , par_freq_subday_type + , par_freq_subday_interval + , par_freq_relative_interval + , par_freq_recurrence_factor + , par_active_start_date + , par_active_end_date + , par_active_start_time + , par_active_end_time + ); + + + SELECT 0 , LASTVAL() + INTO var_retval, par_schedule_id; + + + returncode := var_retval; + RETURN; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_attach_schedule ( + par_job_id integer = NULL::integer, + par_job_name varchar = NULL::character varying, + par_schedule_id integer = NULL::integer, + par_schedule_name varchar = NULL::character varying, + par_automatic_post smallint = 1, + out returncode integer +) +RETURNS integer AS +$body$ +DECLARE + var_retval INT; + var_sched_owner_sid CHAR(85); + var_job_owner_sid CHAR(85); +BEGIN + + SELECT t.par_job_name + , t.par_job_id + , t.par_owner_sid + , t.returncode + FROM sys.babelfish_sp_verify_job_identifiers( + '@job_name' + , '@job_id' + , par_job_name + , par_job_id + , 'TEST' + , var_job_owner_sid) t + INTO par_job_name + , par_job_id + , var_job_owner_sid + , var_retval; + + IF (var_retval <> 0) THEN + returncode := 1; + RETURN; + END IF; + + + SELECT t.par_schedule_name + , t.par_schedule_id + , t.par_owner_sid + --, t.par_orig_server_id + , t.returncode + FROM sys.babelfish_sp_verify_schedule_identifiers( + '@schedule_name'::character varying + , '@schedule_id'::character varying + , par_schedule_name + , par_schedule_id + , var_sched_owner_sid + , NULL::integer + , NULL::integer) t + INTO par_schedule_name + , par_schedule_id + , var_sched_owner_sid + , var_retval ; + + IF (var_retval <> 0) THEN + returncode := 1; + RETURN; + END IF + + ; + IF ( + NOT EXISTS ( + SELECT 1 + FROM sys.sysjobschedules + WHERE (schedule_id = par_schedule_id) + AND (job_id = par_job_id))) + THEN + INSERT + INTO sys.sysjobschedules (schedule_id, job_id) + VALUES (par_schedule_id, par_job_id); + + SELECT 0 INTO var_retval; + END IF; + + + PERFORM sys.babelfish_sp_set_next_run (par_job_id, par_schedule_id); + + + returncode := var_retval; + RETURN; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_aws_add_jobschedule ( + par_job_id integer = NULL::integer, + par_schedule_id integer = NULL::integer, + out returncode integer +) +AS +$body$ +DECLARE + var_retval INT; + proc_name_mask VARCHAR(100); + var_owner_login_name VARCHAR(128); + var_xml TEXT DEFAULT ''; + var_cron_expression VARCHAR(50); + var_job_cmd VARCHAR(255); + lambda_arn VARCHAR(255); + return_message text; + var_schedule_name VARCHAR(255); + + var_job_name VARCHAR(128); + var_start_step_id INTEGER; + var_notify_level_email INTEGER; + var_notify_email_operator_id INTEGER; + var_notify_email_operator_name VARCHAR(128); + notify_email_sender VARCHAR(128); + var_delete_level INTEGER; +BEGIN + + IF (EXISTS ( + SELECT 1 + FROM sys.sysjobschedules + WHERE (schedule_id = par_schedule_id) + AND (job_id = par_job_id))) + THEN + SELECT cron_expression + FROM sys.babelfish_sp_schedule_to_cron (par_job_id, par_schedule_id) + INTO var_cron_expression; + + SELECT name + FROM sys.sysschedules + WHERE schedule_id = par_schedule_id + INTO var_schedule_name; + + SELECT name + , start_step_id + , COALESCE(notify_level_email,0) + , COALESCE(notify_email_operator_id,0) + , COALESCE(notify_email_operator_name,'') + , COALESCE(delete_level,0) + FROM sys.sysjobs + WHERE job_id = par_job_id + INTO var_job_name + , var_start_step_id + , var_notify_level_email + , var_notify_email_operator_id + , var_notify_email_operator_name + , var_delete_level; + + proc_name_mask := 'sys_data.sql_agent$job_%s_step_%s'; + var_job_cmd := format(proc_name_mask, par_job_id, '1'); + notify_email_sender := 'aws_test_email_sender@dbbest.com'; + + + var_xml := CONCAT(var_xml, '{'); + var_xml := CONCAT(var_xml, '"mode": "add_job",'); + var_xml := CONCAT(var_xml, '"parameters": {'); + var_xml := CONCAT(var_xml, '"vendor": "postgresql",'); + var_xml := CONCAT(var_xml, '"job_name": "',var_schedule_name,'",'); + var_xml := CONCAT(var_xml, '"job_frequency": "',var_cron_expression,'",'); + var_xml := CONCAT(var_xml, '"job_cmd": "',var_job_cmd,'",'); + var_xml := CONCAT(var_xml, '"notify_level_email": ',var_notify_level_email,','); + var_xml := CONCAT(var_xml, '"delete_level": ',var_delete_level,','); + var_xml := CONCAT(var_xml, '"uid": "',par_job_id,'",'); + var_xml := CONCAT(var_xml, '"callback": "sys.babelfish_sp_job_log",'); + var_xml := CONCAT(var_xml, '"notification": {'); + var_xml := CONCAT(var_xml, '"notify_email_sender": "',notify_email_sender,'",'); + var_xml := CONCAT(var_xml, '"notify_email_recipient": "',var_notify_email_operator_name,'"'); + var_xml := CONCAT(var_xml, '}'); + var_xml := CONCAT(var_xml, '}'); + var_xml := CONCAT(var_xml, '}'); + + -- RAISE NOTICE '%', var_xml; + + + SELECT sys.babelfish_get_service_setting ('JOB', 'LAMBDA_ARN') + INTO lambda_arn; + + SELECT sys.awslambda_fn (lambda_arn, var_xml) INTO return_message; + returncode := 0; + ELSE + returncode := 1; + RAISE 'Job not fount' USING ERRCODE := '50000'; + END IF; + +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_aws_del_jobschedule ( + par_job_id integer = NULL::integer, + par_schedule_id integer = NULL::integer, + out returncode integer +) +AS +$body$ +DECLARE + var_retval INT; + proc_name_mask VARCHAR(100); + var_owner_login_name VARCHAR(128); + var_xml TEXT DEFAULT ''; + var_cron_expression VARCHAR(50); + var_job_cmd VARCHAR(255); + lambda_arn VARCHAR(255); + return_message text; + var_schedule_name VARCHAR(255); +BEGIN + + IF (EXISTS ( + SELECT 1 + FROM sys.sysjobschedules + WHERE (schedule_id = par_schedule_id) + AND (job_id = par_job_id))) + THEN + SELECT name + FROM sys.sysschedules + WHERE schedule_id = par_schedule_id + INTO var_schedule_name; + + var_xml := CONCAT(var_xml, '{'); + var_xml := CONCAT(var_xml, '"mode": "del_schedule",'); + var_xml := CONCAT(var_xml, '"parameters": {'); + var_xml := CONCAT(var_xml, '"schedule_name": "',var_schedule_name,'",'); + var_xml := CONCAT(var_xml, '"force_delete": "TRUE"'); + var_xml := CONCAT(var_xml, '}'); + var_xml := CONCAT(var_xml, '}'); + + SELECT sys.babelfish_get_service_setting ('JOB', 'LAMBDA_ARN') + INTO lambda_arn; + + SELECT sys.awslambda_fn (lambda_arn, var_xml) INTO return_message; + returncode := 0; + ELSE + returncode := 1; + RAISE 'Job not fount' USING ERRCODE := '50000'; + END IF; + +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_delete_job ( + par_job_id integer = NULL::integer, + par_job_name varchar = NULL::character varying, + par_originating_server varchar = NULL::character varying, + par_delete_history smallint = 1, + par_delete_unused_schedule smallint = 1, + out returncode integer +) +RETURNS integer AS +$body$ +DECLARE + var_retval INT; + var_category_id INT; + var_job_owner_sid CHAR(85); + var_err INT; + var_schedule_id INT; +BEGIN + IF ((par_job_id IS NOT NULL) OR (par_job_name IS NOT NULL)) + THEN + SELECT t.par_job_name + , t.par_job_id + , t.par_owner_sid + , t.returncode + FROM sys.babelfish_sp_verify_job_identifiers( + '@job_name' + , '@job_id' + , par_job_name + , par_job_id + , 'TEST' + , var_job_owner_sid + ) t + INTO par_job_name + , par_job_id + , var_job_owner_sid + , var_retval; + + IF (var_retval <> 0) THEN + returncode := (1); + RETURN; + END IF; + END IF; + + + + + SELECT category_id + INTO var_category_id + FROM sys.sysjobs + WHERE job_id = par_job_id; + + + IF (par_job_id IS NOT NULL) + THEN + --CREATE TEMPORARY TABLE "#temp_schedules_to_delete" (schedule_id INT NOT NULL); + + -- Delete all traces of the job + -- BEGIN TRANSACTION + -- Get the schedules to delete before deleting records from sysjobschedules + + + + --IF (par_delete_unused_schedule = 1) + --THEN + -- ZZZ optimize + -- Get the list of schedules to delete + --INSERT INTO "#temp_schedules_to_delete" + --SELECT DISTINCT schedule_id + -- FROM sys.sysschedules + -- WHERE schedule_id IN (SELECT schedule_id + -- FROM sys.sysjobschedules + -- WHERE job_id = par_job_id); + --INSERT INTO "#temp_schedules_to_delete" + SELECT schedule_id + FROM sys.sysjobschedules + WHERE job_id = par_job_id + INTO var_schedule_id; + + PERFORM sys.babelfish_sp_aws_del_jobschedule (par_job_id := par_job_id, par_schedule_id := var_schedule_id); + + +-- END IF; + + + --DELETE FROM sys.sysschedules + -- WHERE schedule_id IN (SELECT schedule_id FROM sys.sysjobschedules WHERE job_id = par_job_id); + + DELETE FROM sys.sysjobschedules + WHERE job_id = par_job_id; + + DELETE FROM sys.sysjobsteps + WHERE job_id = par_job_id; + + DELETE FROM sys.sysjobs + WHERE job_id = par_job_id; + + SELECT 0 INTO var_err; + + + IF (par_delete_unused_schedule = 1) + THEN + + DELETE FROM sys.sysschedules + WHERE schedule_id = var_schedule_id; --IN (SELECT schedule_id FROM "#temp_schedules_to_delete"); + + --DELETE FROM sys.sysschedules + -- WHERE schedule_id IN (SELECT schedule_id + -- FROM "#temp_schedules_to_delete" AS sdel + -- WHERE NOT EXISTS (SELECT * + -- FROM sys.sysjobschedules AS js + -- WHERE js.schedule_id = sdel.schedule_id)); + END IF; + + + IF (par_delete_history = 1) + THEN + DELETE FROM sys.sysjobhistory + WHERE job_id = par_job_id; + END IF; + + + + --DROP TABLE "#temp_schedules_to_delete"; + END IF; + + + returncode := 0; + RETURN; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_delete_jobschedule ( + par_job_id integer = NULL::integer, + par_job_name varchar = NULL::character varying, + par_name varchar = NULL::character varying, + par_keep_schedule integer = 0, + par_automatic_post smallint = 1, + out returncode integer +) +RETURNS integer AS +$body$ +DECLARE + var_retval INT; + var_sched_count INT; + var_schedule_id INT; + var_job_owner_sid CHAR(85); +BEGIN + + SELECT LTRIM(RTRIM(par_name)) INTO par_name; + + + SELECT t.par_job_name + , t.par_job_id + , t.par_owner_sid + , t.returncode + FROM sys.babelfish_sp_verify_job_identifiers( + '@job_name' + , '@job_id' + , par_job_name + , par_job_id + , 'TEST' + , var_job_owner_sid + ) t + INTO par_job_name + , par_job_id + , var_job_owner_sid + , var_retval; + + IF (var_retval <> 0) THEN + returncode := 1; + RETURN; + END IF; + + IF (LOWER(UPPER(par_name)) = LOWER('ALL')) + THEN + SELECT - 1 INTO var_schedule_id; + + + + CREATE TEMPORARY TABLE "#temp_schedules_to_delete" (schedule_id INT NOT NULL) + + ; + + IF (par_keep_schedule = 0) + THEN + + INSERT INTO "#temp_schedules_to_delete" + SELECT DISTINCT schedule_id + FROM sys.sysschedules + WHERE (schedule_id IN (SELECT schedule_id + FROM sys.sysjobschedules + WHERE (job_id = par_job_id))); + + IF (EXISTS (SELECT * + FROM sys.sysjobschedules + WHERE (job_id <> par_job_id) + AND (schedule_id IN (SELECT schedule_id + FROM "#temp_schedules_to_delete")))) + THEN + RAISE 'One or more schedules were not deleted because they are being used by at least one other job. Use "sp_detach_schedule" to remove schedules from a job.' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + END IF; + + + DELETE FROM sys.sysjobschedules + WHERE (job_id = par_job_id); + + + DELETE FROM sys.sysschedules + WHERE schedule_id IN (SELECT schedule_id FROM "#temp_schedules_to_delete"); + ELSE ---- IF (LOWER(UPPER(par_name)) = LOWER('ALL')) + + -- Need to use sp_detach_schedule to remove this ambiguous schedule name + IF(var_sched_count > 1) + THEN + RAISE 'More than one schedule named "%" is attached to job "%". Use "sp_detach_schedule" to remove schedules from a job.', par_name, par_job_name USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + --If user requests that the schedule be removed (the legacy behavoir) + --make sure it isnt being used by another job + IF (par_keep_schedule = 0) + THEN + IF(EXISTS(SELECT * + FROM sys.sysjobschedules + WHERE (schedule_id = var_schedule_id) + AND (job_id <> par_job_id))) + THEN + RAISE 'Schedule "%" was not deleted because it is being used by at least one other job. Use "sp_detach_schedule" to remove schedules from a job.', par_name USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + END IF; + + + DELETE FROM sys.sysjobschedules + WHERE (job_id = par_job_id) + AND (schedule_id = var_schedule_id); + + + IF (par_keep_schedule = 0) + THEN + + DELETE FROM sys.sysschedules + WHERE (schedule_id = var_schedule_id); + END IF; + + SELECT t.returncode + FROM sys.babelfish_sp_aws_del_jobschedule(par_job_id, var_schedule_id) t + INTO var_retval; + + + END IF; + + + UPDATE sys.sysjobs + SET version_number = version_number + 1 + -- , date_modified = GETDATE() / + WHERE job_id = par_job_id; + + DROP TABLE IF EXISTS "#temp_schedules_to_delete"; + + + + returncode := var_retval; + RETURN; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_delete_jobstep ( + par_job_id integer = NULL::integer, + par_job_name varchar = NULL::character varying, + par_step_id integer = NULL::integer, + out returncode integer +) +RETURNS integer AS +$body$ +DECLARE + var_retval INT; + var_max_step_id INT; + var_valid_range VARCHAR(50); + var_job_owner_sid CHAR(85); +BEGIN + SELECT t.par_job_name + , t.par_job_id + , t.par_owner_sid + , t.returncode + FROM sys.babelfish_sp_verify_job_identifiers( + '@job_name' + , '@job_id' + , par_job_name + , par_job_id + , 'TEST' + , var_job_owner_sid + ) t + INTO par_job_name + , par_job_id + , var_job_owner_sid + , var_retval; + + IF (var_retval <> 0) THEN + returncode := 1; + RETURN; + END IF; + + + SELECT COALESCE(MAX(step_id), 0) + INTO var_max_step_id + FROM sys.sysjobsteps + WHERE (job_id = par_job_id); + + + IF (par_step_id < 0) OR (par_step_id > var_max_step_id) + THEN + SELECT CONCAT('0 (all steps) ..', CAST (var_max_step_id AS VARCHAR(1))) + INTO var_valid_range; + RAISE 'The specified "%" is invalid (valid values are: %).', 'step_id', var_valid_range USING ERRCODE := '50000'; + returncode := 1; + RETURN; + + END IF; + + + + IF (par_step_id = 0) + THEN + DELETE FROM sys.sysjobsteps + WHERE (job_id = par_job_id); + ELSE + DELETE FROM sys.sysjobsteps + WHERE (job_id = par_job_id) AND (step_id = par_step_id); + END IF; + + IF (par_step_id <> 0) + THEN + + UPDATE sys.sysjobsteps + SET step_id = step_id - 1 + WHERE (step_id > par_step_id) + AND (job_id = par_job_id); + + + UPDATE sys.sysjobsteps + SET on_success_step_id = on_success_step_id - 1 + WHERE (on_success_step_id > par_step_id) AND (job_id = par_job_id); + + UPDATE sys.sysjobsteps + SET on_fail_step_id = on_fail_step_id - 1 + WHERE (on_fail_step_id > par_step_id) AND (job_id = par_job_id); + + + UPDATE sys.sysjobsteps + SET on_success_step_id = 0 + , on_success_action = 1 + WHERE (on_success_step_id = par_step_id) + AND (job_id = par_job_id); + + + UPDATE sys.sysjobsteps + SET on_fail_step_id = 0 + , on_fail_action = 2 + WHERE (on_fail_step_id = par_step_id) AND (job_id = par_job_id); + END IF; + + + UPDATE sys.sysjobs + SET version_number = version_number + 1 + --, date_modified = GETDATE() / + WHERE (job_id = par_job_id); + + + + + returncode := 0; + RETURN; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_delete_schedule ( + par_schedule_id integer = NULL::integer, + par_schedule_name varchar = NULL::character varying, + par_force_delete smallint = 0, + par_automatic_post smallint = 1, + out returncode integer +) +RETURNS integer AS +$body$ +DECLARE + var_retval INT; + var_job_count INT; +BEGIN + + SELECT COUNT(*) + INTO var_job_count + FROM sys.sysjobschedules + WHERE (schedule_id = par_schedule_id); + + + IF ((par_force_delete = 0) AND (var_job_count > 0)) + THEN + RAISE 'The schedule was not deleted because it is being used by one or more jobs.' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + + DELETE FROM sys.sysjobschedules + WHERE schedule_id = par_schedule_id; + + + DELETE FROM sys.sysschedules + WHERE schedule_id = par_schedule_id; + + + returncode := var_retval; + RETURN; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_detach_schedule ( + par_job_id integer = NULL::integer, + par_job_name varchar = NULL::character varying, + par_schedule_id integer = NULL::integer, + par_schedule_name varchar = NULL::character varying, + par_delete_unused_schedule smallint = 0, + par_automatic_post smallint = 1, + out returncode integer +) +RETURNS integer AS +$body$ +DECLARE + var_retval INT; + var_sched_owner_sid CHAR(85); + var_job_owner_sid CHAR(85); +BEGIN + + SELECT t.par_job_name + , t.par_job_id + , t.par_owner_sid + , t.returncode + FROM sys.babelfish_sp_verify_job_identifiers( + '@job_name' + , '@job_id' + , par_job_name + , par_job_id + , 'TEST' + , var_job_owner_sid + ) t + INTO par_job_name + , par_job_id + , var_job_owner_sid + , var_retval; + + IF (var_retval <> 0) THEN + returncode := 1; + RETURN; + END IF; + + + SELECT t.par_schedule_name + , t.par_schedule_id + , t.par_owner_sid + , t.par_orig_server_id + , t.returncode + FROM sys.babelfish_sp_verify_schedule_identifiers( + '@schedule_name' + , '@schedule_id' + , par_schedule_name + , par_schedule_id + , var_sched_owner_sid + , NULL + , par_job_id + ) t + INTO par_schedule_name + , par_schedule_id + , var_sched_owner_sid + , var_retval; + -- job_id_filter + + IF (var_retval <> 0) THEN + returncode := 1; + RETURN; + END IF; + + + IF (NOT EXISTS ( + SELECT * + FROM sys.sysjobschedules + WHERE (schedule_id = par_schedule_id) + AND (job_id = par_job_id))) + THEN + RAISE 'The specified schedule name "%s" is not associated with the job "%s".', par_schedule_name, par_job_name USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + SELECT t.returncode + FROM sys.babelfish_sp_aws_del_jobschedule(par_job_id, par_schedule_id) t + INTO var_retval; + + DELETE FROM sys.sysjobschedules + WHERE (job_id = par_job_id) + AND (schedule_id = par_schedule_id); + + SELECT 0 -- ZZZ + INTO var_retval; + + + IF (var_retval = 0 AND par_delete_unused_schedule = 1) + THEN + IF (NOT EXISTS ( + SELECT * + FROM sys.sysjobschedules + WHERE (schedule_id = par_schedule_id))) + THEN + DELETE FROM sys.sysschedules + WHERE (schedule_id = par_schedule_id); + END IF; + END IF; +-- 7268 "sql/sys_function_helpers.sql" + -- PERFORM sys.babelfish_sp_delete_job (par_job_id := par_job_id); + + + returncode := var_retval; + RETURN; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_job_log ( + IN pid INTEGER + , IN pstatus INTEGER + , IN pmessage VARCHAR(255)) +RETURNS void AS +$BODY$ +BEGIN + PERFORM sys.babelfish_update_job (pid, pmessage); + + -- INSERT INTO ms_test.jobs_log(id, t, status, message) + -- VALUES (pid, CURRENT_TIMESTAMP, pstatus, pmessage); +END; +$BODY$ +LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_schedule_to_cron ( + par_job_id integer, + par_schedule_id integer, + out cron_expression varchar +) +RETURNS VARCHAR AS +$body$ +DECLARE + var_enabled INTEGER; + var_freq_type INTEGER; + var_freq_interval INTEGER; + var_freq_subday_type INTEGER; + var_freq_subday_interval INTEGER; + var_freq_relative_interval INTEGER; + var_freq_recurrence_factor INTEGER; + var_active_start_date INTEGER; + var_active_end_date INTEGER; + var_active_start_time INTEGER; + var_active_end_time INTEGER; + + var_next_run_date date; + var_next_run_time time; + var_next_run_dt timestamp; + + var_tmp_interval varchar(50); + var_current_dt timestamp; + var_next_dt timestamp; +BEGIN + + SELECT enabled + , freq_type + , freq_interval + , freq_subday_type + , freq_subday_interval + , freq_relative_interval + , freq_recurrence_factor + , active_start_date + , active_end_date + , active_start_time + , active_end_time + FROM sys.sysschedules + INTO var_enabled + , var_freq_type + , var_freq_interval + , var_freq_subday_type + , var_freq_subday_interval + , var_freq_relative_interval + , var_freq_recurrence_factor + , var_active_start_date + , var_active_end_date + , var_active_start_time + , var_active_end_time + WHERE schedule_id = par_schedule_id; + + + CASE var_freq_type + WHEN 1 THEN + NULL; + + WHEN 4 THEN + BEGIN + cron_expression := + CASE + + + WHEN var_freq_subday_type = 4 THEN format('cron(*/%s * * * ? *)', var_freq_subday_interval::character varying) + WHEN var_freq_subday_type = 8 THEN format('cron(0 */%s * * ? *)', var_freq_subday_interval::character varying) + ELSE '' + END; + END; + + WHEN 8 THEN + NULL; + + WHEN 16 THEN + NULL; + + WHEN 32 THEN + NULL; + + WHEN 64 THEN + NULL; + + WHEN 128 THEN + NULL; + + END CASE; + + -- return cron_expression; + +END; +$body$ +LANGUAGE 'plpgsql'; + +create or replace function sys.babelfish_sp_sequence_get_range( + in par_sequence_name text, + in par_range_size bigint, + out par_range_first_value bigint, + out par_range_last_value bigint, + out par_range_cycle_count bigint, + out par_sequence_increment bigint, + out par_sequence_min_value bigint, + out par_sequence_max_value bigint +) as +$body$ +declare + v_is_cycle character varying(3); + v_current_value bigint; +begin + select s.minimum_value, s.maximum_value, s.increment, s.cycle_option + from information_schema.sequences s + where s.sequence_name = $1 + into par_sequence_min_value, par_sequence_max_value, par_sequence_increment, v_is_cycle; + + par_range_first_value := sys.babelfish_get_sequence_value(par_sequence_name); + + if par_range_first_value > par_sequence_min_value then + par_range_first_value := par_range_first_value + 1; + end if; + + if v_is_cycle = 'YES' then + par_range_cycle_count := 0; + end if; + + for i in 1..$2 loop + select nextval(par_sequence_name) into v_current_value; + if (v_is_cycle = 'YES') and (v_current_value = par_sequence_min_value) and (par_range_first_value <> v_current_value) then + par_range_cycle_count := par_range_cycle_count + 1; + end if; + end loop; + + par_range_last_value := sys.babelfish_get_sequence_value(par_sequence_name); +end; +$body$ +language plpgsql; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_set_next_run ( + par_job_id integer, + par_schedule_id integer +) +RETURNS void AS +$body$ +DECLARE + var_enabled INTEGER; + var_freq_type INTEGER; + var_freq_interval INTEGER; + var_freq_subday_type INTEGER; + var_freq_subday_interval INTEGER; + var_freq_relative_interval INTEGER; + var_freq_recurrence_factor INTEGER; + var_active_start_date INTEGER; + var_active_end_date INTEGER; + var_active_start_time INTEGER; + var_active_end_time INTEGER; + + var_next_run_date date; + var_next_run_time time; + var_next_run_dt timestamp; + + var_tmp_interval varchar(50); + var_current_dt timestamp; + var_next_dt timestamp; +BEGIN + + SELECT enabled + , freq_type + , freq_interval + , freq_subday_type + , freq_subday_interval + , freq_relative_interval + , freq_recurrence_factor + , active_start_date + , active_end_date + , active_start_time + , active_end_time + FROM sys.sysschedules + INTO var_enabled + , var_freq_type + , var_freq_interval + , var_freq_subday_type + , var_freq_subday_interval + , var_freq_relative_interval + , var_freq_recurrence_factor + , var_active_start_date + , var_active_end_date + , var_active_start_time + , var_active_end_time + WHERE schedule_id = par_schedule_id; + + SELECT next_run_date + , next_run_time + FROM sys.sysjobschedules + INTO var_next_run_date + , var_next_run_time + WHERE schedule_id = par_schedule_id + AND job_id = par_job_id; + + + CASE var_freq_type + WHEN 1 THEN + NULL; + + WHEN 4 THEN + BEGIN + + + IF (var_next_run_date IS NULL OR var_next_run_time IS NULL) + THEN + var_current_dt := now()::timestamp; + + UPDATE sys.sysjobschedules + SET next_run_date = var_current_dt::date + , next_run_time = var_current_dt::time + WHERE schedule_id = par_schedule_id + AND job_id = par_job_id; + RETURN; + ELSE + var_tmp_interval := + CASE + + WHEN var_freq_subday_type = 2 THEN var_freq_subday_interval::character varying || ' second' + WHEN var_freq_subday_type = 4 THEN var_freq_subday_interval::character varying || ' minute' + WHEN var_freq_subday_type = 8 THEN var_freq_subday_interval::character varying || ' hour' + ELSE '' + END; + + var_next_dt := (var_next_run_date::date + var_next_run_time::time)::timestamp + var_tmp_interval::INTERVAL; + UPDATE sys.sysjobschedules + SET next_run_date = var_next_dt::date + , next_run_time = var_next_dt::time + WHERE schedule_id = par_schedule_id + AND job_id = par_job_id; + RETURN; + END IF; + END; + + WHEN 8 THEN + NULL; + + WHEN 16 THEN + NULL; + + WHEN 32 THEN + NULL; + + WHEN 64 THEN + NULL; + + WHEN 128 THEN + NULL; + + END CASE; + +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_update_job ( + par_job_id integer = NULL::integer, + par_job_name varchar = NULL::character varying, + par_new_name varchar = NULL::character varying, + par_enabled smallint = NULL::smallint, + par_description varchar = NULL::character varying, + par_start_step_id integer = NULL::integer, + par_category_name varchar = NULL::character varying, + par_owner_login_name varchar = NULL::character varying, + par_notify_level_eventlog integer = NULL::integer, + par_notify_level_email integer = NULL::integer, + par_notify_level_netsend integer = NULL::integer, + par_notify_level_page integer = NULL::integer, + par_notify_email_operator_name varchar = NULL::character varying, + par_notify_netsend_operator_name varchar = NULL::character varying, + par_notify_page_operator_name varchar = NULL::character varying, + par_delete_level integer = NULL::integer, + par_automatic_post smallint = 1, + out returncode integer +) +RETURNS integer AS +$body$ +DECLARE + var_retval INT; + var_category_id INT; + var_notify_email_operator_id INT; + var_notify_netsend_operator_id INT; + var_notify_page_operator_id INT; + var_owner_sid CHAR(85); + var_alert_id INT; + var_cached_attribute_modified INT; + var_is_sysadmin INT; + var_current_owner VARCHAR(128); + var_enable_only_used INT; + var_x_new_name VARCHAR(128); + var_x_enabled SMALLINT; + var_x_description VARCHAR(512); + var_x_start_step_id INT; + var_x_category_name VARCHAR(128); + var_x_category_id INT; + var_x_owner_sid CHAR(85); + var_x_notify_level_eventlog INT; + var_x_notify_level_email INT; + var_x_notify_level_netsend INT; + var_x_notify_level_page INT; + var_x_notify_email_operator_name VARCHAR(128); + var_x_notify_netsnd_operator_name VARCHAR(128); + var_x_notify_page_operator_name VARCHAR(128); + var_x_delete_level INT; + var_x_originating_server_id INT; + var_x_master_server SMALLINT; +BEGIN + + + SELECT + LTRIM(RTRIM(par_job_name)) + INTO par_job_name; + SELECT + LTRIM(RTRIM(par_new_name)) + INTO par_new_name; + SELECT + LTRIM(RTRIM(par_description)) + INTO par_description; + SELECT + LTRIM(RTRIM(par_category_name)) + INTO par_category_name; + SELECT + LTRIM(RTRIM(par_notify_email_operator_name)) + INTO par_notify_email_operator_name; + SELECT + LTRIM(RTRIM(par_notify_netsend_operator_name)) + INTO par_notify_netsend_operator_name; + SELECT + LTRIM(RTRIM(par_notify_page_operator_name)) + INTO par_notify_page_operator_name + ; + + IF ((par_new_name IS NOT NULL) OR (par_enabled IS NOT NULL) OR (par_start_step_id IS NOT NULL) OR (par_owner_login_name IS NOT NULL) OR (par_notify_level_eventlog IS NOT NULL) OR (par_notify_level_email IS NOT NULL) OR (par_notify_level_netsend IS NOT NULL) OR (par_notify_level_page IS NOT NULL) OR (par_notify_email_operator_name IS NOT NULL) OR (par_notify_netsend_operator_name IS NOT NULL) OR (par_notify_page_operator_name IS NOT NULL) OR (par_delete_level IS NOT NULL)) THEN + SELECT + 1 + INTO var_cached_attribute_modified; + ELSE + SELECT + 0 + INTO var_cached_attribute_modified; + END IF + ; + + IF ((par_enabled IS NOT NULL) AND (par_new_name IS NULL) AND (par_description IS NULL) AND (par_start_step_id IS NULL) AND (par_category_name IS NULL) AND (par_owner_login_name IS NULL) AND (par_notify_level_eventlog IS NULL) AND (par_notify_level_email IS NULL) AND (par_notify_level_netsend IS NULL) AND (par_notify_level_page IS NULL) AND (par_notify_email_operator_name IS NULL) AND (par_notify_netsend_operator_name IS NULL) AND (par_notify_page_operator_name IS NULL) AND (par_delete_level IS NULL)) THEN + SELECT + 1 + INTO var_enable_only_used; + ELSE + SELECT + 0 + INTO var_enable_only_used; + END IF; + + IF (par_new_name = '') THEN + SELECT + NULL + INTO par_new_name; + END IF + ; + + IF (par_new_name IS NULL) THEN + SELECT + var_x_new_name + INTO par_new_name; + END IF; + + IF (par_enabled IS NULL) THEN + SELECT + var_x_enabled + INTO par_enabled; + END IF; + + IF (par_description IS NULL) THEN + SELECT + var_x_description + INTO par_description; + END IF; + + IF (par_start_step_id IS NULL) THEN + SELECT + var_x_start_step_id + INTO par_start_step_id; + END IF; + + IF (par_category_name IS NULL) THEN + SELECT + var_x_category_name + INTO par_category_name; + END IF; + + IF (var_owner_sid IS NULL) THEN + SELECT + var_x_owner_sid + INTO var_owner_sid; + END IF; + + IF (par_notify_level_eventlog IS NULL) THEN + SELECT + var_x_notify_level_eventlog + INTO par_notify_level_eventlog; + END IF; + + IF (par_notify_level_email IS NULL) THEN + SELECT + var_x_notify_level_email + INTO par_notify_level_email; + END IF; + + IF (par_notify_level_netsend IS NULL) THEN + SELECT + var_x_notify_level_netsend + INTO par_notify_level_netsend; + END IF; + + IF (par_notify_level_page IS NULL) THEN + SELECT + var_x_notify_level_page + INTO par_notify_level_page; + END IF; + + IF (par_notify_email_operator_name IS NULL) THEN + SELECT + var_x_notify_email_operator_name + INTO par_notify_email_operator_name; + END IF; + + IF (par_notify_netsend_operator_name IS NULL) THEN + SELECT + var_x_notify_netsnd_operator_name + INTO par_notify_netsend_operator_name; + END IF; + + IF (par_notify_page_operator_name IS NULL) THEN + SELECT + var_x_notify_page_operator_name + INTO par_notify_page_operator_name; + END IF; + + IF (par_delete_level IS NULL) THEN + SELECT + var_x_delete_level + INTO par_delete_level; + END IF + ; + + IF (LOWER(par_description) = LOWER('')) THEN + SELECT + NULL + INTO par_description; + END IF; + + IF (par_category_name = '') THEN + SELECT + NULL + INTO par_category_name; + END IF; + + IF (par_notify_email_operator_name = '') THEN + SELECT + NULL + INTO par_notify_email_operator_name; + END IF; + + IF (par_notify_netsend_operator_name = '') THEN + SELECT + NULL + INTO par_notify_netsend_operator_name; + END IF; + + IF (par_notify_page_operator_name = '') THEN + SELECT + NULL + INTO par_notify_page_operator_name; + END IF + ; + SELECT + t.par_owner_sid, t.par_notify_level_email, t.par_notify_level_netsend, t.par_notify_level_page, + t.par_category_id, t.par_notify_email_operator_id, t.par_notify_netsend_operator_id, t.par_notify_page_operator_id, t.par_originating_server, t.ReturnCode + FROM sys.babelfish_sp_verify_job(par_job_id, par_new_name, par_enabled, par_start_step_id, par_category_name, var_owner_sid, par_notify_level_eventlog, par_notify_level_email, par_notify_level_netsend, par_notify_level_page, par_notify_email_operator_name, par_notify_netsend_operator_name, par_notify_page_operator_name, par_delete_level, var_category_id, var_notify_email_operator_id, var_notify_netsend_operator_id, var_notify_page_operator_id, NULL) t + INTO var_owner_sid, par_notify_level_email, par_notify_level_netsend, par_notify_level_page, var_category_id, var_notify_email_operator_id, var_notify_netsend_operator_id, var_notify_page_operator_id, var_retval; + + IF (var_retval <> 0) THEN + ReturnCode := (1); + RETURN; + END IF + + + ; + + IF (par_owner_login_name IS NOT NULL) THEN + IF (EXISTS (SELECT + 1 + FROM sys.sysjobsteps + WHERE (job_id = par_job_id) AND (LOWER(subsystem) = LOWER('TSQL')))) THEN + + UPDATE sys.sysjobsteps + SET database_user_name = NULL + WHERE (job_id = par_job_id) AND (LOWER(subsystem) = LOWER('TSQL')); + END IF; + END IF; + UPDATE sys.sysjobs + SET name = par_new_name, enabled = par_enabled, description = par_description, start_step_id = par_start_step_id, category_id = var_category_id + , owner_sid = var_owner_sid, notify_level_eventlog = par_notify_level_eventlog, notify_level_email = par_notify_level_email, notify_level_netsend = par_notify_level_netsend, notify_level_page = par_notify_level_page, notify_email_operator_id = var_notify_email_operator_id + , notify_netsend_operator_id = var_notify_netsend_operator_id + , notify_page_operator_id = var_notify_page_operator_id + , delete_level = par_delete_level, version_number = version_number + 1 + + + WHERE (job_id = par_job_id); + SELECT + 0 + INTO var_retval + + ; + ReturnCode := (var_retval); + RETURN + ; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_update_jobschedule ( + par_job_id integer = NULL::integer, + par_job_name varchar = NULL::character varying, + par_name varchar = NULL::character varying, + par_new_name varchar = NULL::character varying, + par_enabled smallint = NULL::smallint, + par_freq_type integer = NULL::integer, + par_freq_interval integer = NULL::integer, + par_freq_subday_type integer = NULL::integer, + par_freq_subday_interval integer = NULL::integer, + par_freq_relative_interval integer = NULL::integer, + par_freq_recurrence_factor integer = NULL::integer, + par_active_start_date integer = NULL::integer, + par_active_end_date integer = NULL::integer, + par_active_start_time integer = NULL::integer, + par_active_end_time integer = NULL::integer, + par_automatic_post smallint = 1, + out returncode integer +) +RETURNS integer AS +$body$ +DECLARE + var_retval INT; + var_sched_count INT; + var_schedule_id INT; + var_job_owner_sid CHAR(85); + var_enable_only_used INT; + var_x_name VARCHAR(128); + var_x_enabled SMALLINT; + var_x_freq_type INT; + var_x_freq_interval INT; + var_x_freq_subday_type INT; + var_x_freq_subday_interval INT; + var_x_freq_relative_interval INT; + var_x_freq_recurrence_factor INT; + var_x_active_start_date INT; + var_x_active_end_date INT; + var_x_active_start_time INT; + var_x_active_end_time INT; + var_owner_sid CHAR(85); +BEGIN + + SELECT + LTRIM(RTRIM(par_name)) + INTO par_name; + SELECT + LTRIM(RTRIM(par_new_name)) + INTO par_new_name + ; + + IF (par_new_name = '') THEN + SELECT + NULL + INTO par_new_name; + END IF + ; + SELECT + t.par_job_name, t.par_job_id, t.par_owner_sid, t.ReturnCode + FROM sys.babelfish_sp_verify_job_identifiers('@job_name', '@job_id', par_job_name, par_job_id, 'TEST', var_job_owner_sid) t + INTO par_job_name, par_job_id, var_job_owner_sid, var_retval; + + IF (var_retval <> 0) THEN + ReturnCode := (1); + RETURN; + END IF + + ; + + IF ((par_enabled IS NOT NULL) AND (par_name IS NULL) AND (par_new_name IS NULL) AND (par_freq_type IS NULL) AND (par_freq_interval IS NULL) AND (par_freq_subday_type IS NULL) AND (par_freq_subday_interval IS NULL) AND (par_freq_relative_interval IS NULL) AND (par_freq_recurrence_factor IS NULL) AND (par_active_start_date IS NULL) AND (par_active_end_date IS NULL) AND (par_active_start_time IS NULL) AND (par_active_end_time IS NULL)) THEN + SELECT + 1 + INTO var_enable_only_used; + ELSE + SELECT + 0 + INTO var_enable_only_used; + END IF; + + IF (par_new_name IS NULL) THEN + SELECT + var_x_name + INTO par_new_name; + END IF; + + IF (par_enabled IS NULL) THEN + SELECT + var_x_enabled + INTO par_enabled; + END IF; + + IF (par_freq_type IS NULL) THEN + SELECT + var_x_freq_type + INTO par_freq_type; + END IF; + + IF (par_freq_interval IS NULL) THEN + SELECT + var_x_freq_interval + INTO par_freq_interval; + END IF; + + IF (par_freq_subday_type IS NULL) THEN + SELECT + var_x_freq_subday_type + INTO par_freq_subday_type; + END IF; + + IF (par_freq_subday_interval IS NULL) THEN + SELECT + var_x_freq_subday_interval + INTO par_freq_subday_interval; + END IF; + + IF (par_freq_relative_interval IS NULL) THEN + SELECT + var_x_freq_relative_interval + INTO par_freq_relative_interval; + END IF; + + IF (par_freq_recurrence_factor IS NULL) THEN + SELECT + var_x_freq_recurrence_factor + INTO par_freq_recurrence_factor; + END IF; + + IF (par_active_start_date IS NULL) THEN + SELECT + var_x_active_start_date + INTO par_active_start_date; + END IF; + + IF (par_active_end_date IS NULL) THEN + SELECT + var_x_active_end_date + INTO par_active_end_date; + END IF; + + IF (par_active_start_time IS NULL) THEN + SELECT + var_x_active_start_time + INTO par_active_start_time; + END IF; + + IF (par_active_end_time IS NULL) THEN + SELECT + var_x_active_end_time + INTO par_active_end_time; + END IF + ; + SELECT + t.par_freq_interval, t.par_freq_subday_type, t.par_freq_subday_interval, t.par_freq_relative_interval, t.par_freq_recurrence_factor, t.par_active_start_date, t.par_active_start_time, + t.par_active_end_date, t.par_active_end_time, t.ReturnCode + FROM sys.babelfish_sp_verify_schedule(var_schedule_id + , par_new_name + , par_enabled + , par_freq_type + , par_freq_interval + , par_freq_subday_type + , par_freq_subday_interval + , par_freq_relative_interval + , par_freq_recurrence_factor + , par_active_start_date + , par_active_start_time + , par_active_end_date + , par_active_end_time + , var_owner_sid) t + INTO par_freq_interval, par_freq_subday_type, par_freq_subday_interval, par_freq_relative_interval, par_freq_recurrence_factor, par_active_start_date, par_active_start_time, par_active_end_date, par_active_end_time, var_retval ; + + IF (var_retval <> 0) THEN + ReturnCode := (1); + RETURN; + END IF + + ; + UPDATE sys.sysschedules + SET name = par_new_name, enabled = par_enabled, freq_type = par_freq_type, freq_interval = par_freq_interval, freq_subday_type = par_freq_subday_type, freq_subday_interval = par_freq_subday_interval, freq_relative_interval = par_freq_relative_interval, freq_recurrence_factor = par_freq_recurrence_factor, active_start_date = par_active_start_date, active_end_date = par_active_end_date, active_start_time = par_active_start_time, active_end_time = par_active_end_time + , version_number = version_number + 1 + WHERE (schedule_id = var_schedule_id); + SELECT + 0 + INTO var_retval + + ; + UPDATE sys.sysjobs + SET version_number = version_number + 1 + + WHERE (job_id = par_job_id); + ReturnCode := (var_retval); + RETURN + ; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_update_jobstep ( + par_job_id integer = NULL::integer, + par_job_name varchar = NULL::character varying, + par_step_id integer = NULL::integer, + par_step_name varchar = NULL::character varying, + par_subsystem varchar = NULL::character varying, + par_command text = NULL::text, + par_additional_parameters text = NULL::text, + par_cmdexec_success_code integer = NULL::integer, + par_on_success_action smallint = NULL::smallint, + par_on_success_step_id integer = NULL::integer, + par_on_fail_action smallint = NULL::smallint, + par_on_fail_step_id integer = NULL::integer, + par_server varchar = NULL::character varying, + par_database_name varchar = NULL::character varying, + par_database_user_name varchar = NULL::character varying, + par_retry_attempts integer = NULL::integer, + par_retry_interval integer = NULL::integer, + par_os_run_priority integer = NULL::integer, + par_output_file_name varchar = NULL::character varying, + par_flags integer = NULL::integer, + par_proxy_id integer = NULL::integer, + par_proxy_name varchar = NULL::character varying, + out returncode integer +) +RETURNS integer AS +$body$ +DECLARE + var_retval INT; + var_os_run_priority_code INT; + var_step_id_as_char VARCHAR(10); + var_new_step_name VARCHAR(128); + var_x_step_name VARCHAR(128); + var_x_subsystem VARCHAR(40); + var_x_command TEXT; + var_x_flags INT; + var_x_cmdexec_success_code INT; + var_x_on_success_action SMALLINT; + var_x_on_success_step_id INT; + var_x_on_fail_action SMALLINT; + var_x_on_fail_step_id INT; + var_x_server VARCHAR(128); + var_x_database_name VARCHAR(128); + var_x_database_user_name VARCHAR(128); + var_x_retry_attempts INT; + var_x_retry_interval INT; + var_x_os_run_priority INT; + var_x_output_file_name VARCHAR(200); + var_x_proxy_id INT; + var_x_last_run_outcome SMALLINT; + var_x_last_run_duration INT; + var_x_last_run_retries INT; + var_x_last_run_date INT; + var_x_last_run_time INT; + var_new_proxy_id INT; + var_subsystem_id INT; + var_auto_proxy_name VARCHAR(128); + var_job_owner_sid CHAR(85); + var_step_uid CHAR(85); +BEGIN + SELECT NULL INTO var_new_proxy_id; + + SELECT LTRIM(RTRIM(par_step_name)) INTO par_step_name; + SELECT LTRIM(RTRIM(par_subsystem)) INTO par_subsystem; + SELECT LTRIM(RTRIM(par_command)) INTO par_command; + SELECT LTRIM(RTRIM(par_server)) INTO par_server; + SELECT LTRIM(RTRIM(par_database_name)) INTO par_database_name; + SELECT LTRIM(RTRIM(par_database_user_name)) INTO par_database_user_name; + SELECT LTRIM(RTRIM(par_output_file_name)) INTO par_output_file_name; + SELECT LTRIM(RTRIM(par_proxy_name)) INTO par_proxy_name; + + + + + + SELECT + t.par_job_name, t.par_job_id, t.par_owner_sid, t.ReturnCode + FROM sys.babelfish_sp_verify_job_identifiers('@job_name' + , '@job_id' + , par_job_name + , par_job_id + , 'TEST' + , var_job_owner_sid) + INTO par_job_name, par_job_id, var_job_owner_sid, var_retval + ; + + IF (var_retval <> 0) THEN + ReturnCode := (1); + RETURN; + END IF; + + + + IF (NOT EXISTS (SELECT + * + FROM sys.sysjobsteps + WHERE (job_id = par_job_id) AND (step_id = par_step_id))) THEN + SELECT + CAST (par_step_id AS VARCHAR(10)) + INTO var_step_id_as_char; + RAISE 'Error %, severity %, state % was raised. Message: %. Argument: %. Argument: %', '50000', 0, 0, 'The specified %s ("%s") does not exist.', '@step_id', var_step_id_as_char USING ERRCODE := '50000'; + ReturnCode := (1); + RETURN; + + END IF; + + SELECT + step_name, subsystem, command, flags, cmdexec_success_code, on_success_action, on_success_step_id, on_fail_action, on_fail_step_id, server, database_name, database_user_name, retry_attempts, retry_interval, os_run_priority, output_file_name, proxy_id, last_run_outcome, last_run_duration, last_run_retries, last_run_date, last_run_time + INTO var_x_step_name, var_x_subsystem, var_x_command, var_x_flags, var_x_cmdexec_success_code, var_x_on_success_action, var_x_on_success_step_id, var_x_on_fail_action, var_x_on_fail_step_id, var_x_server, var_x_database_name, var_x_database_user_name, var_x_retry_attempts, var_x_retry_interval, var_x_os_run_priority, var_x_output_file_name, var_x_proxy_id, var_x_last_run_outcome, var_x_last_run_duration, var_x_last_run_retries, var_x_last_run_date, var_x_last_run_time + FROM sys.sysjobsteps + WHERE (job_id = par_job_id) AND (step_id = par_step_id); + + IF ((par_step_name IS NOT NULL) AND (par_step_name <> var_x_step_name)) THEN + SELECT + par_step_name + INTO var_new_step_name; + END IF; + + + IF (par_step_name IS NULL) THEN + SELECT var_x_step_name INTO par_step_name; + END IF; + + IF (par_subsystem IS NULL) THEN + SELECT var_x_subsystem INTO par_subsystem; + END IF; + + IF (par_command IS NULL) THEN + SELECT var_x_command INTO par_command; + END IF; + + IF (par_flags IS NULL) THEN + SELECT var_x_flags INTO par_flags; + END IF; + + IF (par_cmdexec_success_code IS NULL) THEN + SELECT var_x_cmdexec_success_code INTO par_cmdexec_success_code; + END IF; + + IF (par_on_success_action IS NULL) THEN + SELECT var_x_on_success_action INTO par_on_success_action; + END IF; + + IF (par_on_success_step_id IS NULL) THEN + SELECT var_x_on_success_step_id INTO par_on_success_step_id; + END IF; + + IF (par_on_fail_action IS NULL) THEN + SELECT var_x_on_fail_action INTO par_on_fail_action; + END IF; + + IF (par_on_fail_step_id IS NULL) THEN + SELECT var_x_on_fail_step_id INTO par_on_fail_step_id; + END IF; + + IF (par_server IS NULL) THEN + SELECT var_x_server INTO par_server; + END IF; + + IF (par_database_name IS NULL) THEN + SELECT var_x_database_name INTO par_database_name; + END IF; + + IF (par_database_user_name IS NULL) THEN + SELECT var_x_database_user_name INTO par_database_user_name; + END IF; + + IF (par_retry_attempts IS NULL) THEN + SELECT var_x_retry_attempts INTO par_retry_attempts; + END IF; + + IF (par_retry_interval IS NULL) THEN + SELECT var_x_retry_interval INTO par_retry_interval; + END IF; + + IF (par_os_run_priority IS NULL) THEN + SELECT var_x_os_run_priority INTO par_os_run_priority; + END IF; + + IF (par_output_file_name IS NULL) THEN + SELECT var_x_output_file_name INTO par_output_file_name; + END IF; + + IF (par_proxy_id IS NULL) THEN + SELECT var_x_proxy_id INTO var_new_proxy_id; + END IF; + + + IF par_proxy_name = '' THEN + SELECT NULL INTO var_new_proxy_id; + END IF; + + + IF (LOWER(par_command) = LOWER('')) THEN + SELECT NULL INTO par_command; + END IF; + + IF (par_server = '') THEN + SELECT NULL INTO par_server; + END IF; + + IF (par_database_name = '') THEN + SELECT NULL INTO par_database_name; + END IF; + + IF (par_database_user_name = '') THEN + SELECT NULL INTO par_database_user_name; + END IF; + + IF (LOWER(par_output_file_name) = LOWER('')) THEN + SELECT NULL INTO par_output_file_name; + END IF + ; + SELECT + t.par_database_name, t.par_database_user_name, t.ReturnCode + FROM sys.babelfish_sp_verify_jobstep(par_job_id, par_step_id, var_new_step_name, par_subsystem, par_command, par_server, par_on_success_action, par_on_success_step_id, par_on_fail_action, par_on_fail_step_id, par_os_run_priority, par_database_name, par_database_user_name, par_flags, par_output_file_name, var_new_proxy_id) t + INTO par_database_name, par_database_user_name, var_retval; + + IF (var_retval <> 0) THEN + ReturnCode := (1); + RETURN; + END IF + + ; + UPDATE sys.sysjobs + SET version_number = version_number + 1 + + WHERE (job_id = par_job_id) + ; + UPDATE sys.sysjobsteps + SET step_name = par_step_name, subsystem = par_subsystem, command = par_command, flags = par_flags, additional_parameters = par_additional_parameters, cmdexec_success_code = par_cmdexec_success_code, on_success_action = par_on_success_action, on_success_step_id = par_on_success_step_id, on_fail_action = par_on_fail_action, on_fail_step_id = par_on_fail_step_id, server = par_server, database_name = par_database_name, database_user_name = par_database_user_name, retry_attempts = par_retry_attempts, retry_interval = par_retry_interval, os_run_priority = par_os_run_priority, output_file_name = par_output_file_name, last_run_outcome = var_x_last_run_outcome, last_run_duration = var_x_last_run_duration, last_run_retries = var_x_last_run_retries, last_run_date = var_x_last_run_date, last_run_time = var_x_last_run_time, proxy_id = var_new_proxy_id + WHERE (job_id = par_job_id) AND (step_id = par_step_id); + + SELECT step_uid + FROM sys.sysjobsteps + WHERE job_id = par_job_id AND step_id = par_step_id + INTO var_step_uid; + + -- PERFORM sys.sp_jobstep_create_proc (var_step_uid); + + ReturnCode := (0); + RETURN + ; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_update_schedule ( + par_schedule_id integer = NULL::integer, + par_name varchar = NULL::character varying, + par_new_name varchar = NULL::character varying, + par_enabled smallint = NULL::smallint, + par_freq_type integer = NULL::integer, + par_freq_interval integer = NULL::integer, + par_freq_subday_type integer = NULL::integer, + par_freq_subday_interval integer = NULL::integer, + par_freq_relative_interval integer = NULL::integer, + par_freq_recurrence_factor integer = NULL::integer, + par_active_start_date integer = NULL::integer, + par_active_end_date integer = NULL::integer, + par_active_start_time integer = NULL::integer, + par_active_end_time integer = NULL::integer, + par_owner_login_name varchar = NULL::character varying, + par_automatic_post smallint = 1, + out returncode integer +) +RETURNS integer AS +$body$ +DECLARE + var_retval INT; + var_owner_sid CHAR(85); + var_cur_owner_sid CHAR(85); + var_x_name VARCHAR(128); + var_enable_only_used INT; + var_x_enabled SMALLINT; + var_x_freq_type INT; + var_x_freq_interval INT; + var_x_freq_subday_type INT; + var_x_freq_subday_interval INT; + var_x_freq_relative_interval INT; + var_x_freq_recurrence_factor INT; + var_x_active_start_date INT; + var_x_active_end_date INT; + var_x_active_start_time INT; + var_x_active_end_time INT; + var_schedule_uid CHAR(38); +BEGIN + + SELECT + LTRIM(RTRIM(par_name)) + INTO par_name; + SELECT + LTRIM(RTRIM(par_new_name)) + INTO par_new_name; + SELECT + LTRIM(RTRIM(par_owner_login_name)) + INTO par_owner_login_name + ; + + IF (par_new_name = '') THEN + SELECT + NULL + INTO par_new_name; + END IF + ; + SELECT + t.par_schedule_name, t.par_schedule_id, t.par_owner_sid, t.par_orig_server_id, t.ReturnCode + FROM sys.babelfish_sp_verify_schedule_identifiers('@name' + , '@schedule_id' + , par_name + , par_schedule_id + , var_cur_owner_sid + , NULL + , NULL) t + INTO par_name, par_schedule_id, var_cur_owner_sid, var_retval + ; + + IF (var_retval <> 0) THEN + ReturnCode := (1); + RETURN; + END IF + + ; + + IF ((par_enabled IS NOT NULL) AND (par_new_name IS NULL) AND (par_freq_type IS NULL) AND (par_freq_interval IS NULL) AND (par_freq_subday_type IS NULL) AND (par_freq_subday_interval IS NULL) AND (par_freq_relative_interval IS NULL) AND (par_freq_recurrence_factor IS NULL) AND (par_active_start_date IS NULL) AND (par_active_end_date IS NULL) AND (par_active_start_time IS NULL) AND (par_active_end_time IS NULL) AND (par_owner_login_name IS NULL)) THEN + SELECT + 1 + INTO var_enable_only_used; + ELSE + SELECT + 0 + INTO var_enable_only_used; + END IF + ; + + IF (var_owner_sid IS NULL) THEN + SELECT + var_cur_owner_sid + INTO var_owner_sid; + END IF + ; + SELECT + name, enabled, freq_type, freq_interval, freq_subday_type, freq_subday_interval, freq_relative_interval, freq_recurrence_factor, active_start_date, active_end_date, active_start_time, active_end_time + INTO var_x_name, var_x_enabled, var_x_freq_type, var_x_freq_interval, var_x_freq_subday_type, var_x_freq_subday_interval, var_x_freq_relative_interval, var_x_freq_recurrence_factor, var_x_active_start_date, var_x_active_end_date, var_x_active_start_time, var_x_active_end_time + FROM sys.sysschedules + WHERE (schedule_id = par_schedule_id) + ; + + IF (par_new_name IS NULL) THEN + SELECT + var_x_name + INTO par_new_name; + END IF; + + IF (par_enabled IS NULL) THEN + SELECT + var_x_enabled + INTO par_enabled; + END IF; + + IF (par_freq_type IS NULL) THEN + SELECT + var_x_freq_type + INTO par_freq_type; + END IF; + + IF (par_freq_interval IS NULL) THEN + SELECT + var_x_freq_interval + INTO par_freq_interval; + END IF; + + IF (par_freq_subday_type IS NULL) THEN + SELECT + var_x_freq_subday_type + INTO par_freq_subday_type; + END IF; + + IF (par_freq_subday_interval IS NULL) THEN + SELECT + var_x_freq_subday_interval + INTO par_freq_subday_interval; + END IF; + + IF (par_freq_relative_interval IS NULL) THEN + SELECT + var_x_freq_relative_interval + INTO par_freq_relative_interval; + END IF; + + IF (par_freq_recurrence_factor IS NULL) THEN + SELECT + var_x_freq_recurrence_factor + INTO par_freq_recurrence_factor; + END IF; + + IF (par_active_start_date IS NULL) THEN + SELECT + var_x_active_start_date + INTO par_active_start_date; + END IF; + + IF (par_active_end_date IS NULL) THEN + SELECT + var_x_active_end_date + INTO par_active_end_date; + END IF; + + IF (par_active_start_time IS NULL) THEN + SELECT + var_x_active_start_time + INTO par_active_start_time; + END IF; + + IF (par_active_end_time IS NULL) THEN + SELECT + var_x_active_end_time + INTO par_active_end_time; + END IF + ; + SELECT + t.par_freq_interval, t.par_freq_subday_type, t.par_freq_subday_interval, t.par_freq_relative_interval, t.par_freq_recurrence_factor, t.par_active_start_date, + t.par_active_start_time, t.par_active_end_date, t.par_active_end_time, t.ReturnCode + FROM sys.babelfish_sp_verify_schedule(par_schedule_id + , par_new_name + , par_enabled + , par_freq_type + , par_freq_interval + , par_freq_subday_type + , par_freq_subday_interval + , par_freq_relative_interval + , par_freq_recurrence_factor + , par_active_start_date + , par_active_start_time + , par_active_end_date + , par_active_end_time + , var_owner_sid) t + INTO par_freq_interval, par_freq_subday_type, par_freq_subday_interval, par_freq_relative_interval, par_freq_recurrence_factor, par_active_start_date, par_active_start_time, par_active_end_date, par_active_end_time, var_retval ; + + IF (var_retval <> 0) THEN + ReturnCode := (1); + RETURN; + END IF + + ; + UPDATE sys.sysschedules + SET name = par_new_name, owner_sid = var_owner_sid, enabled = par_enabled, freq_type = par_freq_type, freq_interval = par_freq_interval, freq_subday_type = par_freq_subday_type, freq_subday_interval = par_freq_subday_interval, freq_relative_interval = par_freq_relative_interval, freq_recurrence_factor = par_freq_recurrence_factor, active_start_date = par_active_start_date, active_end_date = par_active_end_date, active_start_time = par_active_start_time, active_end_time = par_active_end_time + , version_number = version_number + 1 + WHERE (schedule_id = par_schedule_id); + SELECT + 0 + INTO var_retval; + + ReturnCode := (var_retval); + RETURN + ; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_verify_job ( + par_job_id integer, + par_name varchar, + par_enabled smallint, + par_start_step_id integer, + par_category_name varchar, + inout par_owner_sid char, + par_notify_level_eventlog integer, + inout par_notify_level_email integer, + inout par_notify_level_netsend integer, + inout par_notify_level_page integer, + par_notify_email_operator_name varchar, + par_notify_netsend_operator_name varchar, + par_notify_page_operator_name varchar, + par_delete_level integer, + inout par_category_id integer, + inout par_notify_email_operator_id integer, + inout par_notify_netsend_operator_id integer, + inout par_notify_page_operator_id integer, + inout par_originating_server varchar, + out returncode integer +) +RETURNS record AS +$body$ +DECLARE + var_job_type INT; + var_retval INT; + var_current_date INT; + var_res_valid_range VARCHAR(200); + var_max_step_id INT; + var_valid_range VARCHAR(50); +BEGIN + + SELECT LTRIM(RTRIM(par_name)) INTO par_name; + SELECT LTRIM(RTRIM(par_category_name)) INTO par_category_name; + SELECT UPPER(LTRIM(RTRIM(par_originating_server))) INTO par_originating_server; + + IF ( + EXISTS ( + SELECT * + FROM sys.sysjobs AS job + WHERE (name = par_name) + + ) + ) + THEN + RAISE 'The specified % ("%") already exists.', 'par_name', par_name USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + + IF (par_enabled <> 0) AND (par_enabled <> 1) THEN + RAISE 'The specified "%" is invalid (valid values are: %).', 'par_enabled', '0, 1' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + + + IF (par_job_id IS NULL) THEN + IF (par_start_step_id <> 1) THEN + RAISE 'The specified "%" is invalid (valid values are: %).', 'par_start_step_id', '1' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + ELSE + + SELECT COALESCE(MAX(step_id), 0) + INTO var_max_step_id + FROM sys.sysjobsteps + WHERE (job_id = par_job_id); + + IF (par_start_step_id < 1) OR (par_start_step_id > var_max_step_id + 1) THEN + SELECT '1..' || CAST (var_max_step_id + 1 AS VARCHAR(1)) + INTO var_valid_range; + RAISE 'The specified "%" is invalid (valid values are: %).', 'par_start_step_id', var_valid_range USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + END IF; + + + SELECT NULL INTO par_category_id; + + IF (par_category_name = '[DEFAULT]') + THEN + SELECT + CASE COALESCE(var_job_type, 1) + WHEN 1 THEN 0 + WHEN 2 THEN 2 + END + INTO par_category_id; + ELSE + SELECT 0 INTO par_category_id; + END IF; + + returncode := (0); + RETURN; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_verify_job_date ( + par_date integer, + par_date_name varchar = 'date'::character varying, + out returncode integer +) +RETURNS integer AS +$body$ +BEGIN + + SELECT LTRIM(RTRIM(par_date_name)) INTO par_date_name; + + + returncode := 0; + RETURN; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_verify_job_identifiers ( + par_name_of_name_parameter varchar, + par_name_of_id_parameter varchar, + inout par_job_name varchar, + inout par_job_id integer, + par_sqlagent_starting_test varchar = 'TEST'::character varying, + inout par_owner_sid char = NULL::bpchar, + out returncode integer +) +RETURNS record AS +$body$ +DECLARE + var_retval INT; + var_job_id_as_char VARCHAR(36); +BEGIN + + SELECT LTRIM(RTRIM(par_name_of_name_parameter)) INTO par_name_of_name_parameter; + SELECT LTRIM(RTRIM(par_name_of_id_parameter)) INTO par_name_of_id_parameter; + SELECT LTRIM(RTRIM(par_job_name)) INTO par_job_name; + + IF (par_job_name = '') + THEN + SELECT NULL INTO par_job_name; + END IF; + + IF ((par_job_name IS NULL) AND (par_job_id IS NULL)) OR ((par_job_name IS NOT NULL) AND (par_job_id IS NOT NULL)) + THEN + RAISE 'Supply either % or % to identify the job.', par_name_of_id_parameter, par_name_of_name_parameter USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + + IF (par_job_id IS NOT NULL) + THEN + SELECT name + , owner_sid + INTO par_job_name + , par_owner_sid + FROM sys.sysjobs + WHERE (job_id = par_job_id); + + + IF (par_job_name IS NULL) + THEN + SELECT CAST (par_job_id AS VARCHAR(36)) + INTO var_job_id_as_char; + + RAISE 'The specified % ("%") does not exist.', 'job_id', var_job_id_as_char USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + ELSE + + IF (par_job_name IS NOT NULL) + THEN + + IF (SELECT COUNT(*) FROM sys.sysjobs WHERE name = par_job_name) > 1 + THEN + RAISE 'There are two or more jobs named "%". Specify % instead of % to uniquely identify the job.', par_job_name, par_name_of_id_parameter, par_name_of_name_parameter USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + + SELECT job_id + , owner_sid + INTO par_job_id + , par_owner_sid + FROM sys.sysjobs + WHERE (name = par_job_name); + + + IF (par_job_id IS NULL) + THEN + RAISE 'The specified % ("%") does not exist.', 'job_name', par_job_name USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + END IF; + END IF; + + + returncode := 0; + RETURN; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_verify_job_time ( + par_time integer, + par_time_name varchar = 'time'::character varying, + out returncode integer +) +RETURNS integer AS +$body$ +DECLARE + var_hour INT; + var_minute INT; + var_second INT; +BEGIN + + SELECT LTRIM(RTRIM(par_time_name)) INTO par_time_name; + + IF ((par_time < 0) OR (par_time > 235959)) + THEN + RAISE 'The specified "%" is invalid (valid values are: %).', par_time_name, '000000..235959' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + SELECT (par_time / 10000) INTO var_hour; + SELECT (par_time % 10000) / 100 INTO var_minute; + SELECT (par_time % 100) INTO var_second; + + + IF (var_hour > 23) THEN + RAISE 'The "%" supplied has an invalid %.', par_time_name, 'hour' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + + IF (var_minute > 59) THEN + RAISE 'The "%" supplied has an invalid %.', par_time_name, 'minute' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + + IF (var_second > 59) THEN + RAISE 'The "%" supplied has an invalid %.', par_time_name, 'second' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + returncode := 0; + RETURN; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_verify_jobstep ( + par_job_id integer, + par_step_id integer, + par_step_name varchar, + par_subsystem varchar, + par_command text, + par_server varchar, + par_on_success_action smallint, + par_on_success_step_id integer, + par_on_fail_action smallint, + par_on_fail_step_id integer, + par_os_run_priority integer, + par_flags integer, + par_output_file_name varchar, + par_proxy_id integer, + out returncode integer +) +AS +$body$ +DECLARE + var_max_step_id INT; + var_retval INT; + var_valid_values VARCHAR(50); + var_database_name_temp VARCHAR(258); + var_database_user_name_temp VARCHAR(256); + var_temp_command TEXT; + var_iPos INT; + var_create_count INT; + var_destroy_count INT; + var_is_olap_subsystem SMALLINT; + var_owner_sid CHAR(85); + var_owner_name VARCHAR(128); +BEGIN + + SELECT LTRIM(RTRIM(par_subsystem)) INTO par_subsystem; + SELECT LTRIM(RTRIM(par_server)) INTO par_server; + SELECT LTRIM(RTRIM(par_output_file_name)) INTO par_output_file_name; + + + SELECT COALESCE(MAX(step_id), 0) + INTO var_max_step_id + FROM sys.sysjobsteps + WHERE (job_id = par_job_id); + + + IF (par_step_id < 1) OR (par_step_id > var_max_step_id + 1) + THEN + SELECT '1..' || CAST (var_max_step_id + 1 AS VARCHAR(1)) INTO var_valid_values; + RAISE 'The specified "%" is invalid (valid values are: %).', '@step_id', var_valid_values USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + + IF ( + EXISTS ( + SELECT * + FROM sys.sysjobsteps + WHERE (job_id = par_job_id) AND (step_name = par_step_name) + ) + ) + THEN + RAISE 'The specified % ("%") already exists.', 'step_name', par_step_name USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + + IF (par_on_success_action <> 1) + AND (par_on_success_action <> 2) + AND (par_on_success_action <> 3) + AND (par_on_success_action <> 4) + THEN + RAISE 'The specified "%" is invalid (valid values are: %).', 'on_success_action', '1, 2, 3, 4' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + IF (par_on_success_action = 4) AND ((par_on_success_step_id < 1) OR (par_on_success_step_id = par_step_id)) + THEN + RAISE 'The specified "%" is invalid (valid values are greater than 0 but excluding %ld).', 'on_success_step', par_step_id USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + + IF (par_on_fail_action <> 1) + AND (par_on_fail_action <> 2) + AND (par_on_fail_action <> 3) + AND (par_on_fail_action <> 4) + THEN + RAISE 'The specified "%" is invalid (valid values are: %).', 'on_failure_action', '1, 2, 3, 4' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + IF (par_on_fail_action = 4) AND ((par_on_fail_step_id < 1) OR (par_on_fail_step_id = par_step_id)) + THEN + RAISE 'The specified "%" is invalid (valid values are greater than 0 but excluding %).', 'on_failure_step', par_step_id USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + + IF ((par_on_success_action = 4) AND (par_on_success_step_id > var_max_step_id)) + THEN + RAISE 'Warning: Non-existent step referenced by %.', 'on_success_step_id' USING ERRCODE := '50000'; + END IF; + + IF ((par_on_fail_action = 4) AND (par_on_fail_step_id > var_max_step_id)) + THEN + RAISE 'Warning: Non-existent step referenced by %.', '@on_fail_step_id' USING ERRCODE := '50000'; + END IF; + + + + IF (par_os_run_priority NOT IN (- 15, - 1, 0, 1, 15)) + THEN + RAISE 'The specified "%" is invalid (valid values are: %).', '@os_run_priority', '-15, -1, 0, 1, 15' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + + IF ((par_flags < 0) OR (par_flags > 114)) THEN + RAISE 'The specified "%" is invalid (valid values are: %).', '@flags', '0..114' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + IF (LOWER(UPPER(par_subsystem)) <> LOWER('TSQL')) THEN + RAISE 'The specified "%" is invalid (valid values are: %).', '@subsystem', 'TSQL' USING ERRCODE := '50000'; + returncode := (1); + RETURN; + END IF; + + + returncode := 0; + RETURN; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_verify_schedule ( + par_schedule_id integer, + par_name varchar, + par_enabled smallint, + par_freq_type integer, + inout par_freq_interval integer, + inout par_freq_subday_type integer, + inout par_freq_subday_interval integer, + inout par_freq_relative_interval integer, + inout par_freq_recurrence_factor integer, + inout par_active_start_date integer, + inout par_active_start_time integer, + inout par_active_end_date integer, + inout par_active_end_time integer, + par_owner_sid char, + out returncode integer +) +RETURNS record AS +$body$ +DECLARE + var_return_code INT; + var_isAdmin INT; +BEGIN + + SELECT LTRIM(RTRIM(par_name)) INTO par_name; + + + SELECT COALESCE(par_freq_interval, 0) INTO par_freq_interval; + SELECT COALESCE(par_freq_subday_type, 0) INTO par_freq_subday_type; + SELECT COALESCE(par_freq_subday_interval, 0) INTO par_freq_subday_interval; + SELECT COALESCE(par_freq_relative_interval, 0) INTO par_freq_relative_interval; + SELECT COALESCE(par_freq_recurrence_factor, 0) INTO par_freq_recurrence_factor; + SELECT COALESCE(par_active_start_date, 0) INTO par_active_start_date; + SELECT COALESCE(par_active_start_time, 0) INTO par_active_start_time; + SELECT COALESCE(par_active_end_date, 0) INTO par_active_end_date; + SELECT COALESCE(par_active_end_time, 0) INTO par_active_end_time; + + + SELECT 0 INTO var_isAdmin; + + IF ( + EXISTS ( + SELECT * + FROM sys.sysschedules + WHERE (name = par_name) + ) + ) + THEN + RAISE 'The specified % ("%") already exists.', 'par_name', par_name USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + IF (UPPER(par_name) = 'ALL') + THEN + RAISE 'The specified "%" is invalid.', 'name' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + + IF (par_enabled <> 0) AND (par_enabled <> 1) + THEN + RAISE 'The specified "%" is invalid (valid values are: %).', '@enabled', '0, 1' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + + IF (par_freq_type = 2) + THEN + RAISE 'Frequency Type 0x2 (OnDemand) is no longer supported.' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + IF (par_freq_type NOT IN (1, 4, 8, 16, 32, 64, 128)) + THEN + RAISE 'The specified "%" is invalid (valid values are: %).', 'freq_type', '1, 4, 8, 16, 32, 64, 128' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + + IF (par_freq_subday_type <> 0) AND (par_freq_subday_type NOT IN (1, 2, 4, 8)) + THEN + RAISE 'The specified "%" is invalid (valid values are: %).', 'freq_subday_type', '1, 2, 4, 8' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + + IF (par_active_start_date = 0) + THEN + SELECT date_part('year', NOW()::TIMESTAMP) * 10000 + date_part('month', NOW()::TIMESTAMP) * 100 + date_part('day', NOW()::TIMESTAMP) + INTO par_active_start_date; + END IF; + + + IF (par_active_end_date = 0) + THEN + + SELECT 99991231 INTO par_active_end_date; + END IF; + + IF (par_active_start_time = 0) + THEN + + SELECT 000000 INTO par_active_start_time; + END IF; + + IF (par_active_end_time = 0) + THEN + + SELECT 235959 INTO par_active_end_time; + END IF; + + + IF (par_active_end_date = 0) + THEN + SELECT 99991231 INTO par_active_end_date; + END IF; + + SELECT t.returncode + FROM sys.babelfish_sp_verify_job_date(par_active_end_date, 'active_end_date') t + INTO var_return_code; + + IF (var_return_code <> 0) + THEN + returncode := 1; + RETURN; + END IF; + + SELECT t.returncode + FROM sys.babelfish_sp_verify_job_date(par_active_start_date, '@active_start_date') t + INTO var_return_code; + + IF (var_return_code <> 0) + THEN + returncode := 1; + RETURN; + END IF; + + IF (par_active_end_date < par_active_start_date) + THEN + RAISE '% cannot be before %.', 'active_end_date', 'active_start_date' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + SELECT t.returncode + FROM sys.babelfish_sp_verify_job_time(par_active_end_time, '@active_end_time') t + INTO var_return_code; + + IF (var_return_code <> 0) + THEN + returncode := 1; + RETURN; + END IF; + + SELECT t.returncode + FROM sys.babelfish_sp_verify_job_time(par_active_start_time, '@active_start_time') t + INTO var_return_code; + + IF (var_return_code <> 0) + THEN + returncode := 1; + RETURN; + END IF; + + IF (par_active_start_time = par_active_end_time AND (par_freq_subday_type IN (2, 4, 8))) + THEN + RAISE 'The specified "%" is invalid (valid values are: %).', 'active_end_time', 'before or after active_start_time' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + IF ((par_freq_type = 1) + OR (par_freq_type = 64) + OR (par_freq_type = 128)) + THEN + SELECT 0 INTO par_freq_interval; + SELECT 0 INTO par_freq_subday_type; + SELECT 0 INTO par_freq_subday_interval; + SELECT 0 INTO par_freq_relative_interval; + SELECT 0 INTO par_freq_recurrence_factor; + + returncode := 0; + RETURN; + END IF; + + IF (par_freq_subday_type = 0) + THEN + SELECT 1 INTO par_freq_subday_type; + END IF; + + IF ((par_freq_subday_type <> 1) + AND (par_freq_subday_type <> 2) + AND (par_freq_subday_type <> 4) + AND (par_freq_subday_type <> 8)) + THEN + RAISE 'The schedule for this job is invalid (reason: The specified @freq_subday_type is invalid (valid values are: 0x1, 0x2, 0x4, 0x8).).' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + IF ((par_freq_subday_type <> 1) AND (par_freq_subday_interval < 1)) + OR ((par_freq_subday_type = 2) AND (par_freq_subday_interval < 10)) + THEN + RAISE 'The schedule for this job is invalid (reason: The specified @freq_subday_interval is invalid).' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + IF (par_freq_type = 4) + THEN + SELECT 0 INTO par_freq_recurrence_factor; + + IF (par_freq_interval < 1) THEN + RAISE 'The schedule for this job is invalid (reason: @freq_interval must be at least 1 for a daily job.).' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + END IF; + + IF (par_freq_type = 8) + THEN + IF (par_freq_interval < 1) OR (par_freq_interval > 127) + THEN + RAISE 'The schedule for this job is invalid (reason: @freq_interval must be a valid day of the week bitmask [Sunday = 1 .. Saturday = 64] for a weekly job.).' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + END IF; + + IF (par_freq_type = 16) + THEN + IF (par_freq_interval < 1) OR (par_freq_interval > 31) + THEN + RAISE 'The schedule for this job is invalid (reason: @freq_interval must be between 1 and 31 for a monthly job.).' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + END IF; + + IF (par_freq_type = 32) + THEN + IF (par_freq_relative_interval <> 1) + AND (par_freq_relative_interval <> 2) + AND (par_freq_relative_interval <> 4) + AND (par_freq_relative_interval <> 8) + AND (par_freq_relative_interval <> 16) + THEN + RAISE 'The schedule for this job is invalid (reason: @freq_relative_interval must be one of 1st (0x1), 2nd (0x2), 3rd [0x4], 4th (0x8) or Last (0x10).).' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + END IF; + + IF (par_freq_type = 32) + THEN + IF (par_freq_interval <> 1) + AND (par_freq_interval <> 2) + AND (par_freq_interval <> 3) + AND (par_freq_interval <> 4) + AND (par_freq_interval <> 5) + AND (par_freq_interval <> 6) + AND (par_freq_interval <> 7) + AND (par_freq_interval <> 8) + AND (par_freq_interval <> 9) + AND (par_freq_interval <> 10) + THEN + RAISE 'The schedule for this job is invalid (reason: @freq_interval must be between 1 and 10 (1 = Sunday .. 7 = Saturday, 8 = Day, 9 = Weekday, 10 = Weekend-day) for a monthly-relative job.).' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + END IF; + + IF ((par_freq_type = 8) + OR (par_freq_type = 16) + OR (par_freq_type = 32)) + AND (par_freq_recurrence_factor < 1) + THEN + RAISE 'The schedule for this job is invalid (reason: @freq_recurrence_factor must be at least 1.).' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + returncode := 0; + RETURN; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_verify_schedule_identifiers ( + par_name_of_name_parameter varchar, + par_name_of_id_parameter varchar, + inout par_schedule_name varchar, + inout par_schedule_id integer, + inout par_owner_sid char, + inout par_orig_server_id integer, + par_job_id_filter integer = NULL::integer, + out returncode integer +) +AS +$body$ +DECLARE + var_retval INT; + var_schedule_id_as_char VARCHAR(36); + var_sch_name_count INT; +BEGIN + + SELECT LTRIM(RTRIM(par_name_of_name_parameter)) INTO par_name_of_name_parameter; + SELECT LTRIM(RTRIM(par_name_of_id_parameter)) INTO par_name_of_id_parameter; + SELECT LTRIM(RTRIM(par_schedule_name)) INTO par_schedule_name; + SELECT 0 INTO var_sch_name_count; + + IF (par_schedule_name = '') + THEN + SELECT NULL INTO par_schedule_name; + END IF; + + IF ((par_schedule_name IS NULL) AND (par_schedule_id IS NULL)) OR ((par_schedule_name IS NOT NULL) AND (par_schedule_id IS NOT NULL)) + THEN + RAISE 'Supply either % or % to identify the schedule.', par_name_of_id_parameter, par_name_of_name_parameter USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + + IF (par_schedule_id IS NOT NULL) + THEN + + SELECT name + , owner_sid + , originating_server_id + INTO par_schedule_name + , par_owner_sid + , par_orig_server_id + FROM sys.sysschedules + WHERE (schedule_id = par_schedule_id); + + IF (par_schedule_name IS NULL) + THEN + SELECT CAST (par_schedule_id AS VARCHAR(36)) + INTO var_schedule_id_as_char; + + RAISE 'The specified % ("%") does not exist.', 'schedule_id', var_schedule_id_as_char USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + ELSE + IF (par_schedule_name IS NOT NULL) + THEN + + IF (SELECT COUNT(*) FROM sys.sysschedules WHERE name = par_schedule_name) > 1 + THEN + RAISE 'There are two or more sysschedules named "%". Specify % instead of % to uniquely identify the sysschedules.', par_job_name, par_name_of_id_parameter, par_name_of_name_parameter USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + + SELECT schedule_id + , owner_sid + INTO par_schedule_id, par_owner_sid + FROM sys.sysschedules + WHERE (name = par_schedule_name); + + + IF (par_schedule_id IS NULL) + THEN + RAISE 'The specified % ("%") does not exist.', 'par_schedule_name', par_schedule_name USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + END IF; + END IF; + + + returncode := 0; + RETURN; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_xml_preparedocument(IN XmlDocument TEXT,OUT DocHandle BIGINT) +AS +$BODY$ +DECLARE + XmlDocument$data XML; +BEGIN + + CREATE TEMPORARY SEQUENCE IF NOT EXISTS sys$seq_openmxl_id MINVALUE 1 MAXVALUE 9223372036854775807 START WITH 1 INCREMENT BY 1 CACHE 5; + + CREATE TEMPORARY TABLE IF NOT EXISTS sys$openxml + (DocID BigInt NOT NULL DEFAULT NEXTVAL('sys$seq_openmxl_id'), + XmlData XML not NULL, + CONSTRAINT pk_sys$doc_id PRIMARY KEY(DocID) + ) ON COMMIT PRESERVE ROWS; + + IF xml_is_well_formed(XmlDocument) THEN + XmlDocument$data := XmlDocument::XML; + ELSE + RAISE EXCEPTION '%','The XML parse error occurred'; + END IF; + + INSERT INTO sys$openxml(XmlData) + VALUES (XmlDocument$data) + RETURNING DocID INTO DocHandle; +END; +$BODY$ +LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_xml_removedocument(IN DocHandle BIGINT) RETURNS VOID +AS +$BODY$ +DECLARE + lt_error_text TEXT := 'Could not find prepared statement with handle '||CASE + WHEN DocHandle IS NULL THEN 'null' + ELSE DocHandle::TEXT + END; +BEGIN + DELETE FROM sys$openxml t + WHERE t.DocID = DocHandle; + + IF NOT FOUND THEN + RAISE EXCEPTION '%', lt_error_text; + END IF; + + EXCEPTION + WHEN SQLSTATE '42P01' THEN + RAISE EXCEPTION '%',lt_error_text; +END; +$BODY$ +LANGUAGE plpgsql; + + + + + +create or replace function sys.babelfish_STRPOS3(p_str text, p_substr text, p_loc int)returns int +AS +$body$ +DECLARE + v_loc int := case when p_loc > 0 then p_loc else 1 end; + v_cnt int := length(p_str) - v_loc + 1; +BEGIN + + + + if v_cnt > 0 then + return case when 0!= strpos(substr(p_str, v_loc, v_cnt), p_substr) + then strpos(substr(p_str, v_loc, v_cnt), p_substr) + v_loc - 1 + else strpos(substr(p_str, v_loc, v_cnt), p_substr) + end; + else + return 0; + end if; +END; +$body$ +language plpgsql; + +CREATE OR REPLACE FUNCTION sys.babelfish_tomsbit(in_str NUMERIC) +RETURNS SMALLINT +AS +$BODY$ +BEGIN + CASE + WHEN in_str < 0 OR in_str > 0 THEN RETURN 1; + ELSE RETURN 0; + END CASE; +END; +$BODY$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_tomsbit(in_str VARCHAR) +RETURNS SMALLINT +AS +$BODY$ +BEGIN + CASE + WHEN LOWER(in_str) = 'true' OR in_str = '1' THEN RETURN 1; + WHEN LOWER(in_str) = 'false' OR in_str = '0' THEN RETURN 0; + ELSE RETURN 0; + END CASE; +END; +$BODY$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_try_conv_date_to_string(IN p_datatype TEXT, + IN p_dateval DATE, + IN p_style NUMERIC DEFAULT 20) +RETURNS TEXT +AS +$BODY$ +BEGIN + RETURN sys.babelfish_conv_date_to_string(p_datatype, + p_dateval, + p_style); +EXCEPTION + WHEN OTHERS THEN + RETURN NULL; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_try_conv_datetime_to_string(IN p_datatype TEXT, + IN p_src_datatype TEXT, + IN p_datetimeval TIMESTAMP WITHOUT TIME ZONE, + IN p_style NUMERIC DEFAULT -1) +RETURNS TEXT +AS +$BODY$ +BEGIN + RETURN sys.babelfish_conv_datetime_to_string(p_datatype, + p_src_datatype, + p_datetimeval, + p_style); +EXCEPTION + WHEN OTHERS THEN + RETURN NULL; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_try_conv_string_to_date(IN p_datestring TEXT, + IN p_style NUMERIC DEFAULT 0) +RETURNS DATE +AS +$BODY$ +BEGIN + RETURN sys.babelfish_conv_string_to_date(p_datestring, + p_style); +EXCEPTION + WHEN OTHERS THEN + RETURN NULL; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_try_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$ +BEGIN + RETURN sys.babelfish_conv_string_to_datetime(p_datatype, + p_datetimestring , + p_style); +EXCEPTION + WHEN OTHERS THEN + RETURN NULL; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_try_conv_string_to_time(IN p_datatype TEXT, + IN p_timestring TEXT, + IN p_style NUMERIC DEFAULT 0) +RETURNS TIME WITHOUT TIME ZONE +AS +$BODY$ +BEGIN + RETURN sys.babelfish_conv_string_to_time(p_datatype, + p_timestring, + p_style); +EXCEPTION + WHEN OTHERS THEN + RETURN NULL; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_try_conv_time_to_string(IN p_datatype TEXT, + IN p_src_datatype TEXT, + IN p_timeval TIME WITHOUT TIME ZONE, + IN p_style NUMERIC DEFAULT 25) +RETURNS TEXT +AS +$BODY$ +BEGIN + RETURN sys.babelfish_conv_time_to_string(p_datatype, + p_src_datatype, + p_timeval, + p_style); +EXCEPTION + WHEN OTHERS THEN + RETURN NULL; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + +-- convertion to date +CREATE OR REPLACE FUNCTION sys.babelfish_conv_helper_to_date(IN arg TEXT, + IN try BOOL, + IN p_style NUMERIC DEFAULT 0) +RETURNS DATE +AS +$BODY$ +BEGIN + IF try THEN + RETURN sys.babelfish_try_conv_string_to_date(arg, p_style); + ELSE + RETURN sys.babelfish_conv_string_to_date(arg, p_style); + END IF; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE; + +CREATE OR REPLACE FUNCTION sys.babelfish_conv_helper_to_date(IN arg anyelement, + IN try BOOL, + IN p_style NUMERIC DEFAULT 0) +RETURNS DATE +AS +$BODY$ +BEGIN + IF try THEN + RETURN sys.babelfish_try_conv_to_date(arg); + ELSE + RETURN CAST(arg AS DATE); + END IF; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE; + +CREATE OR REPLACE FUNCTION sys.babelfish_try_conv_to_date(IN arg anyelement) +RETURNS DATE +AS +$BODY$ +BEGIN + RETURN CAST(arg AS DATE); + EXCEPTION + WHEN OTHERS THEN + RETURN NULL; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE; + +-- convertion to time +CREATE OR REPLACE FUNCTION sys.babelfish_conv_helper_to_time(IN arg TEXT, + IN try BOOL, + IN p_style NUMERIC DEFAULT 0) +RETURNS TIME +AS +$BODY$ +BEGIN + IF try THEN + RETURN sys.babelfish_try_conv_string_to_time('TIME', arg, p_style); + ELSE + RETURN sys.babelfish_conv_string_to_time('TIME', arg, p_style); + END IF; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE; + +CREATE OR REPLACE FUNCTION sys.babelfish_conv_helper_to_time(IN arg anyelement, + IN try BOOL, + IN p_style NUMERIC DEFAULT 0) +RETURNS TIME +AS +$BODY$ +BEGIN + IF try THEN + RETURN sys.babelfish_try_conv_to_time(arg); + ELSE + RETURN CAST(arg AS TIME); + END IF; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE; + +CREATE OR REPLACE FUNCTION sys.babelfish_try_conv_to_time(IN arg anyelement) +RETURNS TIME +AS +$BODY$ +BEGIN + RETURN CAST(arg AS TIME); + EXCEPTION + WHEN OTHERS THEN + RETURN NULL; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE; + +-- convertion to datetime +CREATE OR REPLACE FUNCTION sys.babelfish_conv_helper_to_datetime(IN arg TEXT, + IN try BOOL, + IN p_style NUMERIC DEFAULT 0) +RETURNS TIMESTAMP +AS +$BODY$ +BEGIN + IF try THEN + RETURN sys.babelfish_try_conv_string_to_datetime('DATETIME', arg, p_style); + ELSE + RETURN sys.babelfish_conv_string_to_datetime('DATETIME', arg, p_style); + END IF; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE; + +CREATE OR REPLACE FUNCTION sys.babelfish_conv_helper_to_datetime(IN arg anyelement, + IN try BOOL, + IN p_style NUMERIC DEFAULT 0) +RETURNS TIMESTAMP +AS +$BODY$ +BEGIN + IF try THEN + RETURN sys.babelfish_try_conv_to_datetime(arg); + ELSE + RETURN CAST(arg AS TIMESTAMP); + END IF; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE; + + +CREATE OR REPLACE FUNCTION sys.babelfish_try_conv_to_datetime(IN arg anyelement) +RETURNS TIMESTAMP +AS +$BODY$ +BEGIN + RETURN CAST(arg AS TIMESTAMP); + EXCEPTION + WHEN OTHERS THEN + RETURN NULL; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE; + +-- convertion to varchar +CREATE OR REPLACE FUNCTION sys.babelfish_conv_helper_to_varchar(IN typename TEXT, + IN arg TEXT, + IN try BOOL, + IN p_style NUMERIC DEFAULT 0) +RETURNS sys.VARCHAR +AS +$BODY$ +BEGIN + IF try THEN + RETURN sys.babelfish_try_conv_to_varchar(typename, arg, p_style); + ELSE + RETURN sys.babelfish_conv_to_varchar(typename, arg, p_style); + END IF; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE; + +CREATE OR REPLACE FUNCTION sys.babelfish_conv_helper_to_varchar(IN typename TEXT, + IN arg ANYELEMENT, + IN try BOOL, + IN p_style NUMERIC DEFAULT 0) +RETURNS sys.VARCHAR +AS +$BODY$ +BEGIN + IF try THEN + RETURN sys.babelfish_try_conv_to_varchar(typename, arg, p_style); + ELSE + RETURN sys.babelfish_conv_to_varchar(typename, arg, p_style); + END IF; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE; + +CREATE OR REPLACE FUNCTION sys.babelfish_conv_to_varchar(IN typename TEXT, + IN arg TEXT, + IN p_style NUMERIC DEFAULT 0) +RETURNS sys.VARCHAR +AS +$BODY$ +BEGIN + RETURN CAST(arg AS sys.VARCHAR); +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE; + +CREATE OR REPLACE FUNCTION sys.babelfish_conv_to_varchar(IN typename TEXT, + IN arg anyelement, + IN p_style NUMERIC DEFAULT 0) +RETURNS sys.VARCHAR +AS +$BODY$ +BEGIN + CASE pg_typeof(arg) + WHEN 'date'::regtype THEN + RETURN sys.babelfish_try_conv_date_to_string(typename, arg, p_style); + WHEN 'time'::regtype THEN + RETURN sys.babelfish_try_conv_time_to_string(typename, 'TIME', arg, p_style); + WHEN 'sys.datetime'::regtype THEN + RETURN sys.babelfish_try_conv_datetime_to_string(typename, 'DATETIME', arg::timestamp, p_style); + WHEN 'float'::regtype THEN + RETURN sys.babelfish_try_conv_float_to_string(typename, arg, p_style); + WHEN 'sys.money'::regtype THEN + RETURN sys.babelfish_try_conv_money_to_string(typename, arg::numeric(19,4)::pg_catalog.money, p_style); + ELSE + RETURN CAST(arg AS sys.VARCHAR); + END CASE; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE; + +CREATE OR REPLACE FUNCTION sys.babelfish_try_conv_to_varchar(IN typename TEXT, + IN arg TEXT, + IN p_style NUMERIC DEFAULT 0) +RETURNS sys.VARCHAR +AS +$BODY$ +BEGIN + RETURN sys.babelfish_conv_to_varchar(typename, arg, p_style); + EXCEPTION + WHEN OTHERS THEN + RETURN NULL; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE; + +CREATE OR REPLACE FUNCTION sys.babelfish_try_conv_to_varchar(IN typename TEXT, + IN arg anyelement, + IN p_style NUMERIC DEFAULT 0) +RETURNS sys.VARCHAR +AS +$BODY$ +BEGIN + RETURN sys.babelfish_conv_to_varchar(typename, arg, p_style); + EXCEPTION + WHEN OTHERS THEN + RETURN NULL; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE; + +CREATE OR REPLACE FUNCTION sys.babelfish_parse_helper_to_date(IN arg TEXT, IN try BOOL, IN culture TEXT DEFAULT '') +RETURNS DATE +AS +$BODY$ +BEGIN + IF try THEN + RETURN sys.babelfish_try_parse_to_date(arg, culture); + ELSE + RETURN sys.babelfish_parse_to_date(arg, culture); + END IF; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE; + +CREATE OR REPLACE FUNCTION sys.babelfish_parse_helper_to_time(IN arg TEXT, IN try BOOL, IN culture TEXT DEFAULT '') +RETURNS TIME WITHOUT TIME ZONE +AS +$BODY$ +BEGIN + IF try THEN + RETURN sys.babelfish_try_parse_to_time('TIME', arg, culture); + ELSE + RETURN sys.babelfish_parse_to_time('TIME', arg, culture); + END IF; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE; + +CREATE OR REPLACE FUNCTION sys.babelfish_parse_helper_to_datetime(IN arg TEXT, IN try BOOL, IN culture TEXT DEFAULT '') +RETURNS TIMESTAMP WITHOUT TIME ZONE +AS +$BODY$ +BEGIN + IF try THEN + RETURN sys.babelfish_try_parse_to_datetime('DATETIME', arg, culture); + ELSE + RETURN sys.babelfish_parse_to_datetime('DATETIME', arg, culture); + END IF; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE; + +CREATE OR REPLACE FUNCTION sys.babelfish_try_conv_money_to_string(IN p_datatype TEXT, + IN p_moneyval PG_CATALOG.MONEY, + IN p_style NUMERIC DEFAULT 0) +RETURNS TEXT +AS +$BODY$ +DECLARE + v_style SMALLINT; + v_format VARCHAR; + v_moneyval NUMERIC(19,4) := p_moneyval::NUMERIC(19,4); + v_moneysign NUMERIC(19,4) := sign(v_moneyval); + v_moneyabs NUMERIC(19,4) := abs(v_moneyval); + v_digits SMALLINT; + v_integral_digits SMALLINT; + v_decimal_digits SMALLINT; + v_res_length SMALLINT; + MASK_REGEXP CONSTANT VARCHAR := '^\s*(?:character varying)\s*\(\s*(\d+|MAX)\s*\)\s*$'; + v_result TEXT; +BEGIN + v_style := floor(p_style)::SMALLINT; + v_digits := length(v_moneyabs::TEXT); + v_decimal_digits := scale(v_moneyabs); + IF (v_decimal_digits > 0) THEN + v_integral_digits := v_digits - v_decimal_digits - 1; + ELSE + v_integral_digits := v_digits; + END IF; + IF (v_style = 0) THEN + v_format := (pow(10, v_integral_digits)-1)::TEXT || 'D99'; + v_result := to_char(v_moneyval, v_format); + ELSIF (v_style = 1) THEN + IF (v_moneysign::SMALLINT = 1) THEN + v_result := substring(p_moneyval::TEXT, 2); + ELSE + v_result := substring(p_moneyval::TEXT, 1, 1) || substring(p_moneyval::TEXT, 3); + END IF; + ELSIF (v_style = 2) THEN + v_format := (pow(10, v_integral_digits)-1)::TEXT || 'D9999'; + v_result := to_char(v_moneyval, v_format); + ELSE + RAISE invalid_parameter_value; + END IF; + v_res_length := substring(p_datatype, MASK_REGEXP)::SMALLINT; + IF v_res_length IS NULL THEN + RETURN v_result; + ELSE + RETURN rpad(v_result, v_res_length, ' '); + END IF; +EXCEPTION + WHEN invalid_parameter_value THEN + RAISE USING MESSAGE := format('%s is not a valid style number when converting from MONEY to a character string.', v_style), + DETAIL := 'Use of incorrect "style" parameter value during conversion process.', + HINT := 'Change "style" parameter to the proper value and try again.'; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_try_conv_float_to_string(IN p_datatype TEXT, + IN p_floatval FLOAT, + IN p_style NUMERIC DEFAULT 0) +RETURNS TEXT +AS +$BODY$ +DECLARE + v_style SMALLINT; + v_format VARCHAR; + v_floatval NUMERIC := abs(p_floatval); + v_digits SMALLINT; + v_integral_digits SMALLINT; + v_decimal_digits SMALLINT; + v_sign SMALLINT := sign(p_floatval); + v_result TEXT; + v_res_length SMALLINT; + MASK_REGEXP CONSTANT VARCHAR := '^\s*(?:character varying)\s*\(\s*(\d+|MAX)\s*\)\s*$'; +BEGIN + v_style := floor(p_style)::SMALLINT; + IF (v_style = 0) THEN + v_digits := length(v_floatval::NUMERIC::TEXT); + v_decimal_digits := scale(v_floatval); + IF (v_decimal_digits > 0) THEN + v_integral_digits := v_digits - v_decimal_digits - 1; + ELSE + v_integral_digits := v_digits; + END IF; + IF (v_floatval >= 999999.5) THEN + v_format := '9D99999EEEE'; + v_result := to_char(v_sign * ceiling(v_floatval), v_format); + v_result := to_char(substring(v_result, 1, 8)::NUMERIC, 'FM9D99999')::NUMERIC::TEXT || substring(v_result, 9); + ELSE + if (6 - v_integral_digits < v_decimal_digits) THEN + v_decimal_digits := 6 - v_integral_digits; + END IF; + v_format := (pow(10, v_integral_digits)-1)::TEXT || 'D'; + IF (v_decimal_digits > 0) THEN + v_format := v_format || (pow(10, v_decimal_digits)-1)::TEXT; + END IF; + v_result := to_char(p_floatval, v_format); + END IF; + ELSIF (v_style = 1) THEN + v_format := '9D9999999EEEE'; + v_result := to_char(p_floatval, v_format); + ELSIF (v_style = 2) THEN + v_format := '9D999999999999999EEEE'; + v_result := to_char(p_floatval, v_format); + ELSIF (v_style = 3) THEN + v_format := '9D9999999999999999EEEE'; + v_result := to_char(p_floatval, v_format); + ELSE + RAISE invalid_parameter_value; + END IF; + + v_res_length := substring(p_datatype, MASK_REGEXP)::SMALLINT; + IF v_res_length IS NULL THEN + RETURN v_result; + ELSE + RETURN rpad(v_result, v_res_length, ' '); + END IF; +EXCEPTION + WHEN invalid_parameter_value THEN + RAISE USING MESSAGE := format('%s is not a valid style number when converting from FLOAT to a character string.', v_style), + DETAIL := 'Use of incorrect "style" parameter value during conversion process.', + HINT := 'Change "style" parameter to the proper value and try again.'; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_try_parse_to_date(IN p_datestring TEXT, + IN p_culture TEXT DEFAULT NULL) +RETURNS DATE +AS +$BODY$ +BEGIN + RETURN sys.babelfish_parse_to_date(p_datestring, p_culture); + EXCEPTION + WHEN OTHERS THEN + RETURN NULL; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_try_parse_to_datetime(IN p_datatype TEXT, + IN p_datetimestring TEXT, + IN p_culture TEXT DEFAULT '') +RETURNS TIMESTAMP WITHOUT TIME ZONE +AS +$BODY$ +BEGIN + RETURN sys.babelfish_parse_to_datetime(p_datatype, p_datetimestring, p_culture); + EXCEPTION + WHEN OTHERS THEN + RETURN NULL; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_try_parse_to_time(IN p_datatype TEXT, + IN p_srctimestring TEXT, + IN p_culture TEXT DEFAULT '') +RETURNS TIME WITHOUT TIME ZONE +AS +$BODY$ +BEGIN + RETURN sys.babelfish_parse_to_time(p_datatype, p_srctimestring, p_culture); + EXCEPTION + WHEN OTHERS THEN + RETURN NULL; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_update_job ( + p_job integer, + p_error_message varchar +) +RETURNS void AS +$body$ +DECLARE + var_enabled smallint; + var_freq_type integer; + var_freq_interval integer; + var_freq_subday_type integer; + var_freq_subday_interval integer; + var_freq_relative_interval integer; + var_freq_recurrence_factor integer; + var_tmp_interval varchar(50); + var_job_id integer; + var_schedule_id integer; + var_job_step_id integer; + var_step_id integer; + var_step_name VARCHAR(128); +BEGIN +-- 9994 "sql/sys_function_helpers.sql" + INSERT + INTO sys.sysjobhistory ( + job_id + , step_id + , step_name + , sql_message_id + , sql_severity + , message + , run_status + , run_date + , run_time + , run_duration + , operator_id_emailed + , operator_id_netsent + , operator_id_paged + , retries_attempted + , server) + VALUES ( + p_job + , 0 -- var_step_id + , ''--var_step_name + , 0 + , 0 + , p_error_message + , 0 + , now()::date + , now()::time + , 0 + , 0 + , 0 + , 0 + , 0 + , ''::character varying); + + -- PERFORM sys.babelfish_sp_set_next_run (var_job_id, var_schedule_id); + +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_waitfor_delay(time_to_pass TEXT) +RETURNS void AS +$BODY$ + SELECT pg_sleep(EXTRACT(HOUR FROM $1::time)*60*60 + + EXTRACT(MINUTE FROM $1::time)*60 + + TRUNC(EXTRACT(SECOND FROM $1::time)) + + sys.babelfish_round_fractseconds( + ( + EXTRACT(MILLISECONDS FROM $1::time) + - TRUNC(EXTRACT(SECOND FROM $1::time)) * 1000 + )::numeric + )/1000::numeric); +$BODY$ +LANGUAGE SQL; + +CREATE OR REPLACE FUNCTION sys.babelfish_waitfor_delay(time_to_pass TIMESTAMP WITHOUT TIME ZONE) +RETURNS void AS +$BODY$ + SELECT pg_sleep(EXTRACT(HOUR FROM $1::time)*60*60 + + EXTRACT(MINUTE FROM $1::time)*60 + + TRUNC(EXTRACT(SECOND FROM $1::time)) + + sys.babelfish_round_fractseconds( + ( + EXTRACT(MILLISECONDS FROM $1::time) + - TRUNC(EXTRACT(SECOND FROM $1::time)) * 1000 + )::numeric + )/1000::numeric); +$BODY$ +LANGUAGE SQL; + +-- internal table function for sp_cursor_list and sp_decribe_cursor +CREATE OR REPLACE FUNCTION sys.babelfish_cursor_list(cursor_source integer) +RETURNS table ( + reference_name text, + cursor_name text, + cursor_scope smallint, + status smallint, + model smallint, + concurrency smallint, + scrollable smallint, + open_status smallint, + cursor_rows bigint, + fetch_status smallint, + column_count smallint, + row_count bigint, + last_operation smallint, + cursor_handle int, + cursor_source smallint +) AS 'babelfishpg_tsql', 'cursor_list' LANGUAGE C; + +CREATE OR REPLACE FUNCTION sys.babelfish_get_datetimeoffset_tzoffset(SYS.DATETIMEOFFSET) +RETURNS SMALLINT +AS 'babelfishpg_common', 'get_datetimeoffset_tzoffset_internal' +LANGUAGE C IMMUTABLE STRICT; + +-- internal table function for querying the registered ENRs +CREATE OR REPLACE FUNCTION sys.babelfish_get_enr_list() +RETURNS table ( + reloid int, + relname text +) AS 'babelfishpg_tsql', 'get_enr_list' LANGUAGE C; + +-- internal table function for collation_list +CREATE OR REPLACE FUNCTION sys.babelfish_collation_list() +RETURNS table ( + oid int, + collation_name text, + l1_priority int, + l2_priority int, + l3_priority int, + l4_priority int, + l5_priority int +) AS 'babelfishpg_tsql', 'collation_list' LANGUAGE C; + +-- internal function to truncate long identifier +CREATE OR REPLACE FUNCTION sys.babelfish_truncate_identifier(IN object_name TEXT) +RETURNS text +AS 'babelfishpg_tsql', 'pltsql_truncate_identifier_func' LANGUAGE C IMMUTABLE STRICT; + +-- internal functions for debuggig/testing purpose +CREATE OR REPLACE FUNCTION sys.babelfish_pltsql_cursor_show_textptr_only_column_indexes(cursor_handle INT) +RETURNS text +AS 'babelfishpg_tsql', 'pltsql_cursor_show_textptr_only_column_indexes' LANGUAGE C; + +CREATE OR REPLACE FUNCTION sys.babelfish_pltsql_get_last_cursor_handle() +RETURNS INT +AS 'babelfishpg_tsql', 'pltsql_get_last_cursor_handle' LANGUAGE C; + +CREATE OR REPLACE FUNCTION sys.babelfish_pltsql_get_last_stmt_handle() +RETURNS INT +AS 'babelfishpg_tsql', 'pltsql_get_last_stmt_handle' LANGUAGE C; + +CREATE OR REPLACE FUNCTION sys.get_babel_server_collation_oid() RETURNS OID +LANGUAGE C +AS 'babelfishpg_tsql', 'get_server_collation_oid'; +-- 12 "sql/babelfishpg_tsql.in" 2 +-- 1 "sql/sys_functions.sql" 1 +-- Helper functions to support the FOR XML clause +CREATE OR REPLACE FUNCTION sys.tsql_query_to_xml(query text, mode int, element_name text, + binary_base64 boolean, root_name text) +RETURNS xml +AS 'babelfishpg_tsql', 'tsql_query_to_xml' +LANGUAGE C IMMUTABLE STRICT COST 100; + +CREATE OR REPLACE FUNCTION sys.tsql_query_to_xml_text(query text, mode int, element_name text, + binary_base64 boolean, root_name text) +RETURNS ntext +AS 'babelfishpg_tsql', 'tsql_query_to_xml_text' +LANGUAGE C IMMUTABLE STRICT COST 100; + +-- User and Login Functions +CREATE OR REPLACE FUNCTION sys.user_name(IN id OID DEFAULT NULL) +RETURNS sys.NVARCHAR(128) +AS 'babelfishpg_tsql', 'user_name' +LANGUAGE C IMMUTABLE PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.user_id(IN user_name TEXT DEFAULT NULL) +RETURNS OID +AS 'babelfishpg_tsql', 'user_id' +LANGUAGE C IMMUTABLE PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.suser_name(IN server_user_id OID DEFAULT NULL) +RETURNS sys.NVARCHAR(128) +AS 'babelfishpg_tsql', 'suser_name' +LANGUAGE C IMMUTABLE PARALLEL RESTRICTED; + +CREATE OR REPLACE FUNCTION sys.suser_id(IN login TEXT DEFAULT NULL) +RETURNS OID +AS 'babelfishpg_tsql', 'suser_id' +LANGUAGE C IMMUTABLE PARALLEL RESTRICTED; + +-- Matches and returns object name to Oid +CREATE OR REPLACE FUNCTION sys.OBJECT_NAME(IN object_id INT, IN database_id INT DEFAULT NULL) +RETURNS sys.SYSNAME AS +$BODY$ +DECLARE + object_name TEXT; + object_oid Oid; + cur_dat_id Oid; +BEGIN + IF database_id is not NULL THEN + SELECT Oid INTO cur_dat_id FROM pg_database WHERE datname = current_database(); + IF database_id::Oid != cur_dat_id THEN + RAISE EXCEPTION 'Can only do lookup in current database.'; + END IF; + END IF; + + SELECT CAST(object_id AS Oid) INTO object_oid; + + -- First check for tables, sequences, views, etc. + SELECT relname INTO object_name FROM pg_class WHERE Oid = object_oid; + IF object_name IS NOT NULL THEN + RETURN object_name::sys.SYSNAME; + END IF; + + -- Check ENR for any matches + SELECT relname INTO object_name FROM sys.babelfish_get_enr_list() WHERE reloid = object_oid; + IF object_name IS NOT NULL THEN + RETURN object_name::sys.SYSNAME; + END IF; + + -- Next check for functions + SELECT proname INTO object_name FROM pg_proc WHERE Oid = object_oid; + IF object_name IS NOT NULL THEN + RETURN object_name::sys.SYSNAME; + END IF; + + -- Next check for types + SELECT typname INTO object_name FROM pg_type WHERE Oid = object_oid; + IF object_name IS NOT NULL THEN + RETURN object_name::sys.SYSNAME; + END IF; + + -- Apparently SYSNAME cannot be null so returning empty string + RETURN ''; +END; +$BODY$ +LANGUAGE plpgsql +IMMUTABLE; + +CREATE OR REPLACE FUNCTION sys.scope_identity() +RETURNS numeric(38,0) AS +$BODY$ + SELECT sys.babelfish_get_last_identity_numeric()::numeric(38,0); +$BODY$ +LANGUAGE SQL; + +CREATE OR REPLACE FUNCTION sys.ident_seed(IN tablename TEXT) +RETURNS numeric(38,0) AS +$BODY$ + SELECT sys.babelfish_get_identity_param(tablename, 'start'::text)::numeric(38,0); +$BODY$ +LANGUAGE SQL; + +CREATE OR REPLACE FUNCTION sys.ident_incr(IN tablename TEXT) +RETURNS numeric(38,0) AS +$BODY$ + SELECT sys.babelfish_get_identity_param(tablename, 'increment'::text)::numeric(38,0); +$BODY$ +LANGUAGE SQL; + +CREATE OR REPLACE FUNCTION sys.ident_current(IN tablename TEXT) +RETURNS numeric(38,0) AS +$BODY$ + SELECT sys.babelfish_get_identity_current(tablename)::numeric(38,0); +$BODY$ +LANGUAGE SQL; + +CREATE OR REPLACE FUNCTION sys.checksum(IN _input TEXT) RETURNS INTEGER +AS +$BODY$ + SELECT ('x'||SUBSTR(MD5(_input),1,8))::pg_catalog.BIT(32)::INTEGER; +$BODY$ +LANGUAGE SQL IMMUTABLE; + +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 TIMESTAMP 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_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) > p_precision)) + THEN + RAISE invalid_datetime_format; + ELSIF (v_precision NOT BETWEEN 0 AND 7) THEN + RAISE invalid_parameter_value; + END IF; + + v_calc_seconds := format('%s.%s', + floor(p_seconds)::SMALLINT, + substring(rpad(lpad(v_fractions, v_precision, '0'), 7, '0'), 1, 6))::NUMERIC; + + RETURN 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); +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 := 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 := format('Error while trying to cast to %s data type.', v_err_message), + 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 +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.datetime2fromparts(IN p_year TEXT, + IN p_month TEXT, + IN p_day TEXT, + IN p_hour TEXT, + IN p_minute TEXT, + IN p_seconds TEXT, + IN p_fractions TEXT, + IN p_precision TEXT) +RETURNS TIMESTAMP WITHOUT TIME ZONE +AS +$BODY$ +DECLARE + v_err_message VARCHAR; +BEGIN + RETURN sys.datetime2fromparts(p_year::NUMERIC, p_month::NUMERIC, p_day::NUMERIC, + p_hour::NUMERIC, p_minute::NUMERIC, p_seconds::NUMERIC, + p_fractions::NUMERIC, p_precision::NUMERIC); +EXCEPTION + WHEN invalid_text_representation THEN + GET STACKED DIAGNOSTICS v_err_message = MESSAGE_TEXT; + v_err_message := substring(lower(v_err_message), 'numeric\:\s\"(.*)\"'); + + RAISE USING MESSAGE := format('Error while trying to convert "%s" value to NUMERIC data type.', v_err_message), + DETAIL := 'Supplied string value contains illegal characters.', + HINT := 'Correct supplied value, remove all illegal characters and try again.'; +END; +$BODY$ +LANGUAGE plpgsql +IMMUTABLE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.datetimefromparts(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_milliseconds NUMERIC) +RETURNS TIMESTAMP WITHOUT TIME ZONE +AS +$BODY$ +DECLARE + v_err_message VARCHAR; + v_calc_seconds NUMERIC; + v_milliseconds SMALLINT; + v_resdatetime TIMESTAMP WITHOUT TIME ZONE; +BEGIN + -- Check if arguments are out of range + IF ((floor(p_year)::SMALLINT NOT BETWEEN 1753 AND 9999) OR + (floor(p_month)::SMALLINT NOT BETWEEN 1 AND 12) OR + (floor(p_day)::SMALLINT NOT BETWEEN 1 AND 31) OR + (floor(p_hour)::SMALLINT NOT BETWEEN 0 AND 23) OR + (floor(p_minute)::SMALLINT NOT BETWEEN 0 AND 59) OR + (floor(p_seconds)::SMALLINT NOT BETWEEN 0 AND 59) OR + (floor(p_milliseconds)::SMALLINT NOT BETWEEN 0 AND 999)) + THEN + RAISE invalid_datetime_format; + END IF; + + v_milliseconds := sys.babelfish_round_fractseconds(p_milliseconds::INTEGER); + + v_calc_seconds := format('%s.%s', + floor(p_seconds)::SMALLINT, + CASE v_milliseconds + WHEN 1000 THEN '0' + ELSE lpad(v_milliseconds::VARCHAR, 3, '0') + END)::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); + RETURN CASE + WHEN (v_milliseconds != 1000) THEN v_resdatetime + ELSE v_resdatetime + INTERVAL '1 second' + END; +EXCEPTION + WHEN invalid_datetime_format THEN + RAISE USING MESSAGE := 'Cannot construct data type datetime, 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 := format('Error while trying to cast to %s data type.', v_err_message), + 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 +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.datetimefromparts(IN p_year TEXT, + IN p_month TEXT, + IN p_day TEXT, + IN p_hour TEXT, + IN p_minute TEXT, + IN p_seconds TEXT, + IN p_milliseconds TEXT) +RETURNS TIMESTAMP WITHOUT TIME ZONE +AS +$BODY$ +DECLARE + v_err_message VARCHAR; +BEGIN + RETURN sys.datetimefromparts(p_year::NUMERIC, p_month::NUMERIC, p_day::NUMERIC, + p_hour::NUMERIC, p_minute::NUMERIC, + p_seconds::NUMERIC, p_milliseconds::NUMERIC); +EXCEPTION + WHEN invalid_text_representation THEN + GET STACKED DIAGNOSTICS v_err_message = MESSAGE_TEXT; + v_err_message := substring(lower(v_err_message), 'numeric\:\s\"(.*)\"'); + + RAISE USING MESSAGE := format('Error while trying to convert "%s" value to NUMERIC data type.', v_err_message), + DETAIL := 'Supplied string value contains illegal characters.', + HINT := 'Correct supplied value, remove all illegal characters and try again.'; +END; +$BODY$ +LANGUAGE plpgsql +IMMUTABLE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.isnumeric(IN expr ANYELEMENT) RETURNS INTEGER AS +$BODY$ +DECLARE + x NUMERIC; + y MONEY; +BEGIN + IF (expr IS NULL) THEN + RETURN 0; + END IF; + IF ($1::VARCHAR ~ '^\s*$') THEN + RETURN 0; + END IF; + IF pg_typeof(expr) IN ('bigint'::regtype, 'int'::regtype, 'smallint'::regtype,'sys.tinyint'::regtype, + 'numeric'::regtype, 'float'::regtype, 'real'::regtype, 'sys.money'::regtype) + THEN + RETURN 1; + END IF; + x = $1::NUMERIC; + RETURN 1; +EXCEPTION WHEN others THEN + BEGIN + y = $1::sys.MONEY; + RETURN 1; + EXCEPTION WHEN others THEN + RETURN 0; + END; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE CALLED ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.isnumeric(IN expr TEXT) RETURNS INTEGER AS +$BODY$ +DECLARE + x NUMERIC; + y MONEY; +BEGIN + IF (expr IS NULL) THEN + RETURN 0; + END IF; + IF ($1::VARCHAR ~ '^\s*$') THEN + RETURN 0; + END IF; + IF pg_typeof(expr) IN ('bigint'::regtype, 'int'::regtype, 'smallint'::regtype,'sys.tinyint'::regtype, + 'numeric'::regtype, 'float'::regtype, 'real'::regtype, 'sys.money'::regtype) + THEN + RETURN 1; + END IF; + x = $1::NUMERIC; + RETURN 1; +EXCEPTION WHEN others THEN + BEGIN + y = $1::sys.MONEY; + RETURN 1; + EXCEPTION WHEN others THEN + RETURN 0; + END; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE CALLED ON NULL INPUT; + +-- Return the object ID given the object name. Can specify optional type. +CREATE OR REPLACE FUNCTION sys.object_id(IN object_name TEXT, IN object_type char(2) DEFAULT '') +RETURNS INTEGER AS +$BODY$ +DECLARE + id oid; + lower_object_name text; + names text[2]; + counter int; + cur_pos int; + db_name text; + input_schema_name text; + schema_name text; + schema_oid oid; + obj_name text; + is_temp_object boolean; +BEGIN + id = null; + lower_object_name = lower(trim(object_name)); + counter = 1; + cur_pos = position('.' in lower_object_name); + schema_oid = NULL; + + -- Parse user input into names split by '.' + WHILE cur_pos > 0 LOOP + IF counter > 3 THEN + -- Too many names provided + RETURN NULL; + END IF; + names[counter] = sys.babelfish_single_unbracket_name(left(lower_object_name, cur_pos - 1)); + lower_object_name = substring(lower_object_name from cur_pos + 1); + counter = counter + 1; + cur_pos = position('.' in lower_object_name); + END LOOP; + + -- Assign each name accordingly + obj_name = sys.babelfish_truncate_identifier(sys.babelfish_single_unbracket_name(lower_object_name)); + CASE counter + WHEN 1 THEN + db_name = NULL; + schema_name = NULL; + WHEN 2 THEN + db_name = NULL; + input_schema_name = sys.babelfish_truncate_identifier(names[1]); + schema_name = sys.bbf_get_current_physical_schema_name(input_schema_name); + WHEN 3 THEN + db_name = sys.babelfish_truncate_identifier(names[1]); + input_schema_name = sys.babelfish_truncate_identifier(names[2]); + schema_name = sys.bbf_get_current_physical_schema_name(input_schema_name); + ELSE + RETURN NULL; + END CASE; + + -- Check if looking for temp object. + is_temp_object = left(obj_name, 1) = '#'; + + -- Can only search in current database. Allowing tempdb for temp objects. + IF db_name IS NOT NULL AND db_name <> current_database() AND db_name <> 'tempdb' THEN + RAISE EXCEPTION 'Can only do lookup in current database.'; + END IF; + + IF schema_name IS NOT NULL AND schema_name <> '' THEN + -- Searching within a schema. Get schema oid. + schema_oid = (SELECT oid FROM pg_namespace WHERE nspname = schema_name); + IF schema_oid IS NULL THEN + RETURN NULL; + END IF; + + if object_type <> '' then + case + -- Schema does not apply as much to temp objects. + when upper(object_type) in ('S', 'U', 'V', 'IT', 'ET', 'SO') and is_temp_object then + id := (select reloid from sys.babelfish_get_enr_list() where lower(relname) = obj_name limit 1); + + when upper(object_type) in ('S', 'U', 'V', 'IT', 'ET', 'SO') and not is_temp_object then + id := (select oid from pg_class where lower(relname) = obj_name + and relnamespace = schema_oid limit 1); + + when upper(object_type) in ('C', 'D', 'F', 'PK', 'UQ') then + id := (select oid from pg_constraint where lower(conname) = obj_name + and connamespace = schema_oid limit 1); + + when upper(object_type) in ('AF', 'FN', 'FS', 'FT', 'IF', 'P', 'PC', 'TF', 'RF', 'X') then + id := (select oid from pg_proc where lower(proname) = obj_name + and pronamespace = schema_oid limit 1); + + when upper(object_type) in ('TR', 'TA') then + id := (select oid from pg_trigger where lower(tgname) = obj_name limit 1); + + -- Throwing exception as a reminder to add support in the future. + when upper(object_type) in ('R', 'EC', 'PG', 'SN', 'SQ', 'TT') then + RAISE EXCEPTION 'Object type currently unsupported.'; + + -- unsupported object_type + else id := null; + end case; + else + if not is_temp_object then id := ( + select oid from pg_class where lower(relname) = obj_name + and relnamespace = schema_oid + union + select oid from pg_constraint where lower(conname) = obj_name + and connamespace = schema_oid + union + select oid from pg_proc where lower(proname) = obj_name + and pronamespace = schema_oid + union + select oid from pg_trigger where lower(tgname) = obj_name + limit 1); + else + -- temp object without "object_type" in-argument + id := (select reloid from sys.babelfish_get_enr_list() where lower(relname) = obj_name limit 1); + end if; + end if; + ELSE + -- Schema not specified. + if object_type <> '' then + case + when upper(object_type) in ('S', 'U', 'V', 'IT', 'ET', 'SO') and is_temp_object then + id := (select reloid from sys.babelfish_get_enr_list() where lower(relname) = obj_name limit 1); + + when upper(object_type) in ('S', 'U', 'V', 'IT', 'ET', 'SO') and not is_temp_object then + id := (select oid from pg_class where lower(relname) = obj_name limit 1); + + when upper(object_type) in ('C', 'D', 'F', 'PK', 'UQ') then + id := (select oid from pg_constraint where lower(conname) = obj_name limit 1); + + when upper(object_type) in ('AF', 'FN', 'FS', 'FT', 'IF', 'P', 'PC', 'TF', 'RF', 'X') then + id := (select oid from pg_proc where lower(proname) = obj_name limit 1); + + when upper(object_type) in ('TR', 'TA') then + id := (select oid from pg_trigger where lower(tgname) = obj_name limit 1); + + -- Throwing exception as a reminder to add support in the future. + when upper(object_type) in ('R', 'EC', 'PG', 'SN', 'SQ', 'TT') then + RAISE EXCEPTION 'Object type currently unsupported.'; + + -- unsupported object_type + else id := null; + end case; + else + if not is_temp_object then id := ( + select oid from pg_class where lower(relname) = obj_name + union + select oid from pg_constraint where lower(conname) = obj_name + union + select oid from pg_proc where lower(proname) = obj_name + union + select oid from pg_trigger where lower(tgname) = obj_name + limit 1); + else + -- temp object without "object_type" in-argument + id := (select reloid from sys.babelfish_get_enr_list() where lower(relname) = obj_name limit 1); + end if; + end if; + END IF; + + RETURN id::integer; +END; +$BODY$ +LANGUAGE plpgsql STABLE RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.parsename ( + object_name VARCHAR + ,object_piece INT + ) +RETURNS VARCHAR AS $$ + + + +SELECT CASE + WHEN char_length($1) < char_length(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.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) > p_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 := format('%s.%s', + floor(p_seconds)::SMALLINT, + substring(rpad(lpad(v_fractions, v_precision, '0'), 7, '0'), 1, 6))::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 := 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 := format('Error while trying to cast to %s data type.', v_err_message), + 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 +VOLATILE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.timefromparts(IN p_hour TEXT, + IN p_minute TEXT, + IN p_seconds TEXT, + IN p_fractions TEXT, + IN p_precision TEXT) +RETURNS TIME WITHOUT TIME ZONE +AS +$BODY$ +DECLARE + v_err_message VARCHAR; +BEGIN + RETURN sys.timefromparts(p_hour::NUMERIC, p_minute::NUMERIC, + p_seconds::NUMERIC, p_fractions::NUMERIC, + p_precision::NUMERIC); +EXCEPTION + WHEN invalid_text_representation THEN + GET STACKED DIAGNOSTICS v_err_message = MESSAGE_TEXT; + v_err_message := substring(lower(v_err_message), 'numeric\:\s\"(.*)\"'); + + RAISE USING MESSAGE := format('Error while trying to convert "%s" value to NUMERIC data type.', v_err_message), + DETAIL := 'Supplied string value contains illegal characters.', + HINT := 'Correct supplied value, remove all illegal characters and try again.'; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.has_dbaccess(database_name PG_CATALOG.TEXT) RETURNS INTEGER AS $$ +DECLARE has_access BOOLEAN; +BEGIN + has_access = has_database_privilege(database_name, 'CONNECT'); + IF has_access THEN + RETURN 1; + ELSE + RETURN 0; + END IF; +EXCEPTION WHEN others THEN + RETURN NULL; +END; +$$ +STRICT +LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION sys.is_srvrolemember(role PG_CATALOG.TEXT, login PG_CATALOG.TEXT DEFAULT CURRENT_USER) RETURNS INTEGER AS $$ +DECLARE has_role BOOLEAN; +BEGIN + has_role = pg_has_role(login, role, 'MEMBER'); + IF has_role THEN + return 1; + ELSE + RETURN 0; + END IF; +EXCEPTION WHEN others THEN + RETURN NULL; +END; +$$ +STRICT +LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION sys.datefromparts(IN year INT, IN month INT, IN day INT) +RETURNS DATE AS +$BODY$ +SELECT make_date(year, month, day); +$BODY$ +STRICT +LANGUAGE SQL IMMUTABLE; + +CREATE OR REPLACE FUNCTION sys.charindex(expressionToFind PG_CATALOG.TEXT, + expressionToSearch PG_CATALOG.TEXT, + start_location INTEGER DEFAULT 0) +RETURNS INTEGER AS +$BODY$ +SELECT +CASE +WHEN start_location <= 0 THEN + strpos(expressionToSearch, expressionToFind) +ELSE + CASE + WHEN strpos(substr(expressionToSearch, start_location), expressionToFind) = 0 THEN + 0 + ELSE + strpos(substr(expressionToSearch, start_location), expressionToFind) + start_location - 1 + END +END; +$BODY$ +STRICT +LANGUAGE SQL 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 +$BODY$ +SELECT +CASE +WHEN start <= 0 or start > length(expr) or length < 0 THEN + NULL +WHEN replace_expr is NULL THEN + overlay (expr placing '' from start for length) +ELSE + overlay (expr placing replace_expr from start for length) +END; +$BODY$ +LANGUAGE SQL; + +CREATE OR REPLACE FUNCTION sys.stuff(expr ANYELEMENT, start INTEGER, length INTEGER, replace_expr ANYELEMENT) +RETURNS ANYELEMENT AS +$BODY$ +SELECT +CASE +WHEN start <= 0 or start > length(expr) or length < 0 THEN + NULL +WHEN replace_expr is NULL THEN + overlay (expr placing '' from start for length) +ELSE + overlay (expr placing replace_expr from start for length) +END; +$BODY$ +LANGUAGE SQL; + +CREATE OR REPLACE FUNCTION sys.len(expr TEXT) RETURNS INTEGER AS +$BODY$ +SELECT length(trim(trailing from expr)); +$BODY$ +STRICT +LANGUAGE SQL IMMUTABLE; + +-- DATALENGTH +CREATE OR REPLACE FUNCTION sys.datalength(ANYELEMENT) RETURNS INTEGER +AS 'babelfishpg_tsql', 'datalength' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; +-- provide both additional functions here to avoid implicit casting between string literals with/without N'' +CREATE OR REPLACE FUNCTION sys.datalength(text) RETURNS INTEGER +AS 'babelfishpg_tsql', 'datalength' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; +CREATE OR REPLACE FUNCTION sys.datalength(char) RETURNS INTEGER +AS 'babelfishpg_tsql', 'datalength' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; +-- TODO: in MSSQL datalength against varchar(max) will return BIGINT instead of INTEGER. However in PG we ignore typmods in functions. +-- However this is not a critical issue so we will just leave it. We may come back to this difference later once we find out solution to typmods. + +CREATE OR REPLACE FUNCTION sys.round(number PG_CATALOG.NUMERIC, length INTEGER) +RETURNS NUMERIC AS 'babelfishpg_common', 'tsql_numeric_round' LANGUAGE C IMMUTABLE PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.round(number PG_CATALOG.NUMERIC, length INTEGER, function INTEGER) +RETURNS NUMERIC AS 'babelfishpg_common', 'tsql_numeric_trunc' LANGUAGE C IMMUTABLE PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.day(date ANYELEMENT) +RETURNS INTEGER AS +$BODY$ +SELECT sys.datepart('day', date); +$BODY$ +STRICT +LANGUAGE SQL IMMUTABLE; + +CREATE OR REPLACE FUNCTION sys.month(date ANYELEMENT) +RETURNS INTEGER AS +$BODY$ +SELECT sys.datepart('month', date); +$BODY$ +STRICT +LANGUAGE SQL IMMUTABLE; + +CREATE OR REPLACE FUNCTION sys.year(date ANYELEMENT) +RETURNS INTEGER AS +$BODY$ +SELECT sys.datepart('year', date); +$BODY$ +STRICT +LANGUAGE SQL IMMUTABLE; + +CREATE OR REPLACE FUNCTION sys.space(IN number INTEGER, OUT result SYS.VARCHAR) AS $$ +-- sys.varchar has default length of 1, so we have to pass in 'number' to be the +-- type modifier. +BEGIN + EXECUTE format(E'SELECT repeat(\' \', %s)::SYS.VARCHAR(%s)', number, number) INTO result; +END; +$$ +STRICT +LANGUAGE plpgsql; + +create or replace function sys.isdate(v text) +returns integer +as +$body$ +begin + if v is NULL THEN + return 0; + else + perform v::date; + return 1; + end if; + EXCEPTION WHEN others THEN + RETURN 0; +end +$body$ +language 'plpgsql'; + +create or replace function sys.PATINDEX(in pattern character varying, in expression character varying) returns bigint as +$body$ +declare + v_find_result character varying; + v_pos bigint; + v_regexp_pattern character varying; +begin + v_pos := null; + if left(pattern, 1) = '%' then + v_regexp_pattern := regexp_replace(pattern, '^%', '%#"'); + else + v_regexp_pattern := '#"' || pattern; + end if; + + if right(pattern, 1) = '%' then + v_regexp_pattern := regexp_replace(v_regexp_pattern, '%$', '#"%'); + else + v_regexp_pattern := v_regexp_pattern || '#"'; + end if; + v_find_result := substring(expression from v_regexp_pattern for '#'); + if v_find_result <> '' then + v_pos := strpos(expression, v_find_result); + end if; + return v_pos; +end; +$body$ +language plpgsql returns null on null input; + +create or replace function sys.RAND(x in int)returns double precision +AS 'babelfishpg_tsql', 'tsql_random' +LANGUAGE C IMMUTABLE STRICT COST 1 PARALLEL RESTRICTED; + +CREATE OR REPLACE FUNCTION sys.datepart(IN datepart PG_CATALOG.TEXT, IN arg anyelement) RETURNS INTEGER +AS +$body$ +BEGIN + IF pg_typeof(arg) = 'sys.DATETIMEOFFSET'::regtype THEN + return sys.datepart_internal(datepart, arg::timestamp, + sys.babelfish_get_datetimeoffset_tzoffset(arg)::integer); + ELSE + return sys.datepart_internal(datepart, arg); + END IF; +END; +$body$ +LANGUAGE plpgsql IMMUTABLE; + +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, enddate); +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, enddate); +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_df(datepart, startdate, enddate); +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, enddate); +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, enddate); +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; + +CREATE OR REPLACE FUNCTION sys.dateadd(IN datepart PG_CATALOG.TEXT, IN num INTEGER, IN startdate ANYELEMENT) RETURNS ANYELEMENT +AS +$body$ +BEGIN + IF pg_typeof(startdate) = 'sys.DATETIMEOFFSET'::regtype THEN + return sys.dateadd_internal_df(datepart, num, + startdate); + ELSE + return sys.dateadd_internal(datepart, num, + startdate); + END IF; +END; +$body$ +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; +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 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_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 * 0.001); + WHEN 'microsecond' THEN + RETURN startdate OPERATOR(sys.+) make_interval(secs => num * 0.000001); + WHEN 'nanosecond' THEN + -- Best we can do - Postgres does not support nanosecond precision + RETURN startdate; + ELSE + RAISE EXCEPTION '"%" is not a recognized dateadd option.', datepart; + END CASE; +END; +$$ +STRICT +LANGUAGE plpgsql IMMUTABLE; + +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; + 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 * 0.001); + WHEN 'microsecond' THEN + RETURN startdate + make_interval(secs => num * 0.000001); + WHEN 'nanosecond' THEN + -- Best we can do - Postgres does not support nanosecond precision + RETURN startdate; + 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 INTEGER AS $$ +DECLARE + result INTEGER; + year_diff INTEGER; + month_diff INTEGER; + day_diff INTEGER; + hour_diff INTEGER; + minute_diff INTEGER; + second_diff INTEGER; + millisecond_diff INTEGER; + microsecond_diff INTEGER; +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 + day_diff = sys.datepart('day', enddate OPERATOR(sys.-) startdate); + result = day_diff; + WHEN 'week' THEN + day_diff = sys.datepart('day', enddate OPERATOR(sys.-) startdate); + result = day_diff / 7; + WHEN 'hour' THEN + day_diff = sys.datepart('day', enddate OPERATOR(sys.-) startdate); + hour_diff = sys.datepart('hour', enddate OPERATOR(sys.-) 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 don't 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 don't 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(IN datepart PG_CATALOG.TEXT, IN startdate anyelement, IN enddate anyelement) RETURNS INTEGER AS $$ +DECLARE + result INTEGER; + year_diff INTEGER; + month_diff INTEGER; + day_diff INTEGER; + hour_diff INTEGER; + minute_diff INTEGER; + second_diff INTEGER; + millisecond_diff INTEGER; + microsecond_diff INTEGER; +BEGIN + CASE datepart + WHEN 'year' THEN + year_diff = date_part('year', enddate)::INTEGER - date_part('year', startdate)::INTEGER; + result = year_diff; + WHEN 'quarter' THEN + year_diff = date_part('year', enddate)::INTEGER - date_part('year', startdate)::INTEGER; + month_diff = date_part('month', enddate)::INTEGER - date_part('month', startdate)::INTEGER; + result = (year_diff * 12 + month_diff) / 3; + WHEN 'month' THEN + year_diff = date_part('year', enddate)::INTEGER - date_part('year', startdate)::INTEGER; + month_diff = date_part('month', enddate)::INTEGER - date_part('month', startdate)::INTEGER; + result = year_diff * 12 + month_diff; + WHEN 'doy', 'y' THEN + day_diff = date_part('day', enddate OPERATOR(sys.-) startdate)::INTEGER; + result = day_diff; + WHEN 'day' THEN + day_diff = date_part('day', enddate OPERATOR(sys.-) startdate)::INTEGER; + result = day_diff; + WHEN 'week' THEN + day_diff = date_part('day', enddate OPERATOR(sys.-) startdate)::INTEGER; + result = day_diff / 7; + WHEN 'hour' THEN + day_diff = date_part('day', enddate OPERATOR(sys.-) startdate)::INTEGER; + hour_diff = date_part('hour', enddate OPERATOR(sys.-) startdate)::INTEGER; + result = day_diff * 24 + hour_diff; + WHEN 'minute' THEN + day_diff = date_part('day', enddate OPERATOR(sys.-) startdate)::INTEGER; + hour_diff = date_part('hour', enddate OPERATOR(sys.-) startdate)::INTEGER; + minute_diff = date_part('minute', enddate OPERATOR(sys.-) startdate)::INTEGER; + result = (day_diff * 24 + hour_diff) * 60 + minute_diff; + WHEN 'second' THEN + day_diff = date_part('day', enddate OPERATOR(sys.-) startdate)::INTEGER; + hour_diff = date_part('hour', enddate OPERATOR(sys.-) startdate)::INTEGER; + minute_diff = date_part('minute', enddate OPERATOR(sys.-) startdate)::INTEGER; + 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 don't need to add second_diff again + day_diff = date_part('day', enddate OPERATOR(sys.-) startdate)::INTEGER; + hour_diff = date_part('hour', enddate OPERATOR(sys.-) startdate)::INTEGER; + minute_diff = date_part('minute', enddate OPERATOR(sys.-) startdate)::INTEGER; + 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 don't need to add second_diff and millisecond_diff again + day_diff = date_part('day', enddate OPERATOR(sys.-) startdate)::INTEGER; + hour_diff = date_part('hour', enddate OPERATOR(sys.-) startdate)::INTEGER; + minute_diff = date_part('minute', enddate OPERATOR(sys.-) startdate)::INTEGER; + 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)::INTEGER; + hour_diff = date_part('hour', enddate OPERATOR(sys.-) startdate)::INTEGER; + minute_diff = date_part('minute', enddate OPERATOR(sys.-) startdate)::INTEGER; + 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; +END; +$$ +STRICT +LANGUAGE plpgsql IMMUTABLE; + +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') + -- '1969-12-28' is a Sunday + WHEN dp = 'dow'::text THEN + to_char(arg::date, 'TMDay') + ELSE + sys.datepart(dp, arg)::TEXT + END +$BODY$ +STRICT +LANGUAGE sql IMMUTABLE; + +CREATE OR REPLACE FUNCTION sys.GETUTCDATE() RETURNS sys.DATETIME AS +$BODY$ +SELECT CAST(CURRENT_TIMESTAMP AT TIME ZONE 'UTC' AS sys.DATETIME); +$BODY$ +LANGUAGE SQL PARALLEL SAFE; + +-- These come from the built-in pg_catalog.count in pg_aggregate.dat +CREATE AGGREGATE sys.count(*) +( + sfunc = int8inc, + combinefunc = int8pl, + msfunc = int8inc, + minvfunc = int8dec, + stype = int8, + mstype = int8, + initcond = 0, + minitcond = 0, + finalfunc = int4, + mfinalfunc = int4, + parallel = safe +); + +CREATE AGGREGATE sys.count("any") +( + sfunc = int8inc_any, + combinefunc = int8pl, + msfunc = int8inc_any, + minvfunc = int8dec_any, + stype = int8, + mstype = int8, + initcond = 0, + minitcond = 0, + finalfunc = int4, + mfinalfunc = int4, + parallel = safe +); + +CREATE AGGREGATE sys.count_big(*) +( + sfunc = int8inc, + combinefunc = int8pl, + msfunc = int8inc, + minvfunc = int8dec, + stype = int8, + mstype = int8, + initcond = 0, + minitcond = 0, + parallel = safe +); + +CREATE AGGREGATE sys.count_big("any") +( + sfunc = int8inc_any, + combinefunc = int8pl, + msfunc = int8inc_any, + minvfunc = int8dec_any, + stype = int8, + mstype = int8, + initcond = 0, + minitcond = 0, + parallel = safe +); + +CREATE OR REPLACE FUNCTION sys.REPLICATE(string TEXT, number INTEGER) +RETURNS VARCHAR AS +$BODY$ +SELECT + CASE + WHEN number >= 0 THEN repeat(string, number) + ELSE null + END; +$BODY$ +LANGUAGE SQL IMMUTABLE STRICT PARALLEL SAFE; + +-- @@ functions +CREATE OR REPLACE FUNCTION sys.rowcount() +RETURNS INT AS 'babelfishpg_tsql' LANGUAGE C; + +CREATE OR REPLACE FUNCTION sys.error() + RETURNS INT AS 'babelfishpg_tsql' LANGUAGE C; + +CREATE OR REPLACE FUNCTION sys.pgerror() + RETURNS VARCHAR AS 'babelfishpg_tsql' LANGUAGE C; + +CREATE OR REPLACE FUNCTION sys.trancount() + RETURNS INT AS 'babelfishpg_tsql' LANGUAGE C; + +CREATE OR REPLACE FUNCTION sys.datefirst() + RETURNS INT AS 'babelfishpg_tsql' LANGUAGE C; + +CREATE OR REPLACE FUNCTION sys.options() + RETURNS INT AS 'babelfishpg_tsql' LANGUAGE C; + +CREATE OR REPLACE FUNCTION sys.version() + RETURNS sys.NVARCHAR(255) AS 'babelfishpg_tsql' LANGUAGE C; + +CREATE OR REPLACE FUNCTION sys.servername() + RETURNS sys.NVARCHAR(128) AS 'babelfishpg_tsql' LANGUAGE C; + +-- 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() +RETURNS sys.TINYINT AS +$$ +BEGIN + RETURN 38; +END; +$$ +LANGUAGE plpgsql; + +-- not supported, only syntax support +CREATE OR REPLACE FUNCTION sys.PROCID() + RETURNS INT AS 'babelfishpg_tsql' LANGUAGE C; + +CREATE OR REPLACE FUNCTION sys.spid() +RETURNS INTEGER AS +$BODY$ +SELECT pg_backend_pid(); +$BODY$ +STRICT +LANGUAGE SQL; + +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) - 2; + IF result < 0 THEN + RAISE EXCEPTION 'Invalid output, check stack trace %', stack; + ELSE + RETURN result; + END IF; +END; +$$ +LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION sys.fetch_status() +RETURNS INT AS 'babelfishpg_tsql' LANGUAGE C; + +CREATE OR REPLACE FUNCTION sys.cursor_rows() +RETURNS INT AS 'babelfishpg_tsql' LANGUAGE C; + +CREATE OR REPLACE FUNCTION sys.cursor_status(text, text) +RETURNS INT AS 'babelfishpg_tsql' LANGUAGE C; + +-- Floor for bit +CREATE OR REPLACE FUNCTION sys.floor(sys.bit) RETURNS DOUBLE PRECISION +AS 'babelfishpg_tsql', 'bit_floor' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- Floor overloading for all int types +CREATE OR REPLACE FUNCTION sys.floor(bigint) RETURNS BIGINT +AS 'babelfishpg_tsql', 'int_floor' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.floor(int) RETURNS INT +AS 'babelfishpg_tsql', 'int_floor' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.floor(smallint) RETURNS SMALLINT +AS 'babelfishpg_tsql', 'int_floor' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.floor(tinyint) RETURNS TINYINT +AS 'babelfishpg_tsql', 'int_floor' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- Ceiling for bit +CREATE OR REPLACE FUNCTION sys.ceiling(sys.bit) RETURNS DOUBLE PRECISION +AS 'babelfishpg_tsql', 'bit_ceiling' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- Ceiling overloading for all int types +CREATE OR REPLACE FUNCTION sys.ceiling(bigint) RETURNS BIGINT +AS 'babelfishpg_tsql', 'int_ceiling' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.ceiling(int) RETURNS INT +AS 'babelfishpg_tsql', 'int_ceiling' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.ceiling(smallint) RETURNS SMALLINT +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 OR REPLACE FUNCTION sys.microsoftversion() +RETURNS INTEGER AS +$BODY$ + SELECT NULL::INTEGER; +$BODY$ +LANGUAGE SQL IMMUTABLE STRICT PARALLEL SAFE; +CREATE OR REPLACE FUNCTION sys.APPLOCK_MODE(IN "@dbprincipal" varchar(32), + IN "@resource" varchar(255), + IN "@lockowner" varchar(32) DEFAULT 'TRANSACTION') +RETURNS TEXT +AS 'babelfishpg_tsql', 'APPLOCK_MODE' LANGUAGE C; + +CREATE OR REPLACE FUNCTION sys.APPLOCK_TEST(IN "@dbprincipal" varchar(32), + IN "@resource" varchar(255), + IN "@lockmode" varchar(32), + IN "@lockowner" varchar(32) DEFAULT 'TRANSACTION') +RETURNS SMALLINT +AS 'babelfishpg_tsql', 'APPLOCK_TEST' LANGUAGE C; + +-- Error handling functions +CREATE OR REPLACE FUNCTION sys.xact_state() +RETURNS SMALLINT +AS 'babelfishpg_tsql', 'xact_state' LANGUAGE C; + +CREATE OR REPLACE FUNCTION sys.error_line() +RETURNS INT +AS 'babelfishpg_tsql', 'pltsql_error_line' LANGUAGE C; + +CREATE OR REPLACE FUNCTION sys.error_message() +RETURNS sys.NVARCHAR(4000) +AS 'babelfishpg_tsql', 'pltsql_error_message' LANGUAGE C; + +CREATE OR REPLACE FUNCTION sys.error_number() +RETURNS INT +AS 'babelfishpg_tsql', 'pltsql_error_number' LANGUAGE C; + +CREATE OR REPLACE FUNCTION sys.error_procedure() +RETURNS sys.NVARCHAR(128) +AS 'babelfishpg_tsql', 'pltsql_error_procedure' LANGUAGE C; + +CREATE OR REPLACE FUNCTION sys.error_severity() +RETURNS INT +AS 'babelfishpg_tsql', 'pltsql_error_severity' LANGUAGE C; + +CREATE OR REPLACE FUNCTION sys.error_state() +RETURNS INT +AS 'babelfishpg_tsql', 'pltsql_error_state' LANGUAGE C; + +CREATE OR REPLACE FUNCTION sys.rand() RETURNS FLOAT AS +$$ + SELECT random(); +$$ +LANGUAGE SQL VOLATILE STRICT PARALLEL RESTRICTED; + +CREATE OR REPLACE FUNCTION sys.DEFAULT_DOMAIN() +RETURNS TEXT +AS 'babelfishpg_tsql', 'default_domain' LANGUAGE C; + +CREATE OR REPLACE FUNCTION sys.db_id(sys.nvarchar(128)) RETURNS SMALLINT +AS 'babelfishpg_tsql', 'babelfish_db_id' +LANGUAGE C PARALLEL SAFE IMMUTABLE; + +CREATE OR REPLACE FUNCTION sys.db_id() RETURNS SMALLINT +AS 'babelfishpg_tsql', 'babelfish_db_id' +LANGUAGE C PARALLEL SAFE IMMUTABLE; + +CREATE OR REPLACE FUNCTION sys.db_name(int) RETURNS sys.nvarchar(128) +AS 'babelfishpg_tsql', 'babelfish_db_name' +LANGUAGE C PARALLEL SAFE IMMUTABLE; + +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, '')) = '') or + ((SELECT coalesce(property_name, '')) = 'COLUMN')) THEN + IF (((SELECT coalesce(level0_object_type, '')) = 'schema') and + ((SELECT coalesce(level1_object_type, '')) = 'table') and + ((SELECT coalesce(level2_object_type, '')) = '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 = t3.table_name and + t2.relname = (SELECT coalesce(level1_object_name, '')) and + t3.column_name = (SELECT coalesce(level2_object_name, '')); + END IF; +END IF; +RETURN; +end; +$$ +LANGUAGE plpgsql; +GRANT EXECUTE ON FUNCTION sys.fn_listextendedproperty( + varchar(128), varchar(128), varchar(128), varchar(128), varchar(128), varchar(128), varchar(128) +) TO PUBLIC; +-- 13 "sql/babelfishpg_tsql.in" 2 +-- 1 "sql/sys_cast.sql" 1 +-- CAST and related functions. +-- Duplicate functions with arg TEXT since ANYELEMNT cannot handle type unknown. + + +CREATE OR REPLACE FUNCTION sys.babelfish_cast_floor_smallint(IN arg TEXT) +RETURNS SMALLINT +AS $BODY$ BEGIN + RETURN CAST(arg AS SMALLINT); +END; $BODY$ +LANGUAGE plpgsql; + + +CREATE OR REPLACE FUNCTION sys.babelfish_cast_floor_smallint(IN arg ANYELEMENT) +RETURNS SMALLINT +AS $BODY$ BEGIN + CASE pg_typeof(arg) + WHEN 'numeric'::regtype, 'double precision'::regtype, 'real'::regtype THEN + RETURN CAST(TRUNC(arg) AS SMALLINT); + WHEN 'sys.money'::regtype, 'sys.smallmoney'::regtype THEN + RETURN CAST(ROUND(arg) AS BIGINT); + ELSE + RETURN CAST(arg AS SMALLINT); + END CASE; +END; $BODY$ +LANGUAGE plpgsql; + + +CREATE OR REPLACE FUNCTION sys.babelfish_cast_floor_int(IN arg TEXT) +RETURNS INT +AS $BODY$ BEGIN + RETURN CAST(arg AS INT); +END; $BODY$ +LANGUAGE plpgsql; + + +CREATE OR REPLACE FUNCTION sys.babelfish_cast_floor_int(IN arg ANYELEMENT) +RETURNS INT +AS $BODY$ BEGIN + CASE pg_typeof(arg) + WHEN 'numeric'::regtype, 'double precision'::regtype, 'real'::regtype THEN + RETURN CAST(TRUNC(arg) AS INT); + WHEN 'sys.money'::regtype, 'sys.smallmoney'::regtype THEN + RETURN CAST(ROUND(arg) AS BIGINT); + ELSE + RETURN CAST(arg AS INT); + END CASE; +END; $BODY$ +LANGUAGE plpgsql; + + +CREATE OR REPLACE FUNCTION sys.babelfish_cast_floor_bigint(IN arg TEXT) +RETURNS BIGINT +AS $BODY$ BEGIN + RETURN CAST(arg AS BIGINT); +END; $BODY$ +LANGUAGE plpgsql; + + +CREATE OR REPLACE FUNCTION sys.babelfish_cast_floor_bigint(IN arg ANYELEMENT) +RETURNS BIGINT +AS $BODY$ BEGIN + CASE pg_typeof(arg) + WHEN 'numeric'::regtype, 'double precision'::regtype, 'real'::regtype THEN + RETURN CAST(TRUNC(arg) AS BIGINT); + WHEN 'sys.money'::regtype, 'sys.smallmoney'::regtype THEN + RETURN CAST(ROUND(arg) AS BIGINT); + ELSE + RETURN CAST(arg AS BIGINT); + END CASE; +END; $BODY$ +LANGUAGE plpgsql; + + +-- TRY_CAST helper functions +CREATE OR REPLACE FUNCTION sys.babelfish_try_cast_floor_smallint(IN arg TEXT) RETURNS SMALLINT +AS $BODY$ BEGIN + RETURN sys.babelfish_cast_floor_smallint(arg); + EXCEPTION WHEN OTHERS THEN RETURN NULL; +END; $BODY$ +LANGUAGE plpgsql; + + +CREATE OR REPLACE FUNCTION sys.babelfish_try_cast_floor_smallint(IN arg ANYELEMENT) RETURNS SMALLINT +AS $BODY$ BEGIN + RETURN sys.babelfish_cast_floor_smallint(arg); + EXCEPTION WHEN OTHERS THEN RETURN NULL; +END; $BODY$ +LANGUAGE plpgsql; + + +CREATE OR REPLACE FUNCTION sys.babelfish_try_cast_floor_int(IN arg TEXT) RETURNS INT +AS $BODY$ BEGIN + RETURN sys.babelfish_cast_floor_int(arg); + EXCEPTION WHEN OTHERS THEN RETURN NULL; +END; $BODY$ +LANGUAGE plpgsql; + + +CREATE OR REPLACE FUNCTION sys.babelfish_try_cast_floor_int(IN arg ANYELEMENT) RETURNS INT +AS $BODY$ BEGIN + RETURN sys.babelfish_cast_floor_int(arg); + EXCEPTION WHEN OTHERS THEN RETURN NULL; +END; $BODY$ +LANGUAGE plpgsql; + + +CREATE OR REPLACE FUNCTION sys.babelfish_try_cast_floor_bigint(IN arg TEXT) RETURNS BIGINT +AS $BODY$ BEGIN + RETURN sys.babelfish_cast_floor_bigint(arg); + EXCEPTION WHEN OTHERS THEN RETURN NULL; +END; $BODY$ +LANGUAGE plpgsql; + + +CREATE OR REPLACE FUNCTION sys.babelfish_try_cast_floor_bigint(IN arg ANYELEMENT) RETURNS BIGINT +AS $BODY$ BEGIN + RETURN sys.babelfish_cast_floor_bigint(arg); + EXCEPTION WHEN OTHERS THEN RETURN NULL; +END; $BODY$ +LANGUAGE plpgsql; + + +CREATE OR REPLACE FUNCTION sys.babelfish_try_cast_to_any(IN arg TEXT, INOUT output ANYELEMENT, IN typmod INT) +RETURNS ANYELEMENT +AS $BODY$ BEGIN + EXECUTE format('SELECT CAST(%L AS %s)', arg, format_type(pg_typeof(output), typmod)) INTO output; + EXCEPTION + WHEN OTHERS THEN + -- Do nothing. Output carries NULL. +END; $BODY$ +LANGUAGE plpgsql; +-- 14 "sql/babelfishpg_tsql.in" 2 +-- 1 "sql/coerce.sql" 1 +-- Manually initialize translation table +CREATE OR REPLACE PROCEDURE babel_coercion_initializer() +LANGUAGE C +AS 'babelfishpg_tsql', 'init_tsql_coerce_hash_tab'; +CALL babel_coercion_initializer(); + +-- Manually initialize translation table +CREATE OR REPLACE PROCEDURE babel_datatype_precedence_initializer() +LANGUAGE C +AS 'babelfishpg_tsql', 'init_tsql_datatype_precedence_hash_tab'; +CALL babel_datatype_precedence_initializer(); +-- 15 "sql/babelfishpg_tsql.in" 2 +-- 1 "sql/sys_views.sql" 1 + +create or replace view sys.tables as +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'::varchar(2) as type + , 'USER_TABLE'::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 + , case reltoastrelid when 0 then 0 else 1 end as lob_data_space_id + , null::integer as filestream_data_space_id + , relnatts as max_column_id_used + , 0 as lock_on_bulk_load + , 1 as uses_ansi_nulls + , 0 as is_replicated + , 0 as has_replication_filter + , 0 as is_merge_published + , 0 as is_sync_tran_subscribed + , 0 as has_unchecked_assembly_data + , 0 as text_in_row_limit + , 0 as large_value_types_out_of_row + , 0 as is_tracked_by_cdc + , 0 as lock_escalation + , 'TABLE'::varchar(60) as lock_escalation_desc + , 0 as is_filetable + , 0 as durability + , 'SCHEMA_AND_DATA'::varchar(60) as durability_desc + , 0 as is_memory_optimized + , case relpersistence when 't' then 2 else 0 end as temporal_type + , case relpersistence when 't' then 'SYSTEM_VERSIONED_TEMPORAL_TABLE' else 'NON_TEMPORAL_TABLE' end as temporal_type_desc + , null::integer as history_table_id + , 0 as is_remote_data_archive_enabled + , 0 as is_external +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 has_table_privilege(quote_ident(s.nspname) ||'.'||quote_ident(t.relname), 'SELECT,INSERT,UPDATE,DELETE,TRUNCATE,TRIGGER') +and s.nspname not in ('information_schema', 'pg_catalog'); +GRANT SELECT ON sys.tables TO PUBLIC; + +create or replace view sys.views as +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 + , 0 as with_check_option + , 0 as is_date_correlation_view + , 0 as is_tracked_by_cdc +from pg_class t inner join pg_namespace s on s.oid = t.relnamespace +where t.relkind = 'v' +and has_table_privilege(quote_ident(s.nspname) ||'.'||quote_ident(t.relname), 'SELECT,INSERT,UPDATE,DELETE,TRUNCATE,TRIGGER') +and s.nspname not in ('information_schema', 'pg_catalog'); +GRANT SELECT ON sys.views TO PUBLIC; + +create or replace view sys.all_columns as +select c.oid as object_id + , a.attname as name + , a.attnum as column_id + , t.oid as system_type_id + , t.oid as user_type_id + , a.attlen as max_length + , null::integer as precision + , null::integer as scale + , coll.collname as collation_name + , case when a.attnotnull then 0 else 1 end as is_nullable + , 0 as is_ansi_padded + , 0 as is_rowguidcol + , 0 as is_identity + , 0 as is_computed + , 0 as is_filestream + , 0 as is_replicated + , 0 as is_non_sql_subscribed + , 0 as is_merge_published + , 0 as is_dts_replicated + , 0 as is_xml_document + , 0 as xml_collection_id + , coalesce(d.oid, 0) as default_object_id + , coalesce((select oid from pg_constraint where conrelid = t.oid and contype = 'c' and a.attnum = any(conkey) limit 1), 0) as rule_object_id + , 0 as is_sparse + , 0 as is_column_set + , 0 as generated_always_type + , 'NOT_APPLICABLE'::varchar(60) as generated_always_type_desc + , null::integer as encryption_type + , null::varchar(64) as encryption_type_desc + , null::varchar as encryption_algorithm_name + , null::integer as column_encryption_key_id + , null::varchar as column_encryption_key_database_name + , 0 as is_hidden + , 0 as is_masked +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 pg_attrdef d on c.oid = d.adrelid and a.attnum = d.adnum +left join pg_collation coll on coll.oid = t.typcollation +where not a.attisdropped +-- 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_column_privilege(quote_ident(s.nspname) ||'.'||quote_ident(c.relname), a.attname, 'SELECT,INSERT,UPDATE,REFERENCES'); +GRANT SELECT ON sys.all_columns TO PUBLIC; + +create or replace view sys.all_views as +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 + , 0 as with_check_option + , 0 as is_date_correlation_view + , 0 as is_tracked_by_cdc +from pg_class t inner join pg_namespace s on s.oid = t.relnamespace +where t.relkind = 'v' +and has_table_privilege(quote_ident(s.nspname) ||'.'||quote_ident(t.relname), 'SELECT,INSERT,UPDATE,DELETE,TRUNCATE,TRIGGER'); +GRANT SELECT ON sys.all_views TO PUBLIC; + +create or replace view sys.columns as +select c.oid as object_id + , a.attname as name + , a.attnum as column_id + , t.oid as system_type_id + , t.oid as user_type_id + , a.attlen as max_length + , null::integer as precision + , null::integer as scale + , coll.collname as collation_name + , case when a.attnotnull then 0 else 1 end as is_nullable + , 0 as is_ansi_padded + , 0 as is_rowguidcol + , 0 as is_identity + , 0 as is_computed + , 0 as is_filestream + , 0 as is_replicated + , 0 as is_non_sql_subscribed + , 0 as is_merge_published + , 0 as is_dts_replicated + , 0 as is_xml_document + , 0 as xml_collection_id + , coalesce(d.oid, 0) as default_object_id + , coalesce((select oid from pg_constraint where conrelid = t.oid and contype = 'c' and a.attnum = any(conkey) limit 1), 0) as rule_object_id + , 0 as is_sparse + , 0 as is_column_set + , 0 as generated_always_type + , 'NOT_APPLICABLE'::varchar(60) as generated_always_type_desc + , null::integer as encryption_type + , null::varchar(64) as encryption_type_desc + , null::varchar as encryption_algorithm_name + , null::integer as column_encryption_key_id + , null::varchar as column_encryption_key_database_name + , 0 as is_hidden + , 0 as is_masked +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 pg_attrdef d on c.oid = d.adrelid and a.attnum = d.adnum +left join pg_collation coll on coll.oid = t.typcollation +where not a.attisdropped +-- 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 s.nspname not in ('information_schema', 'pg_catalog') +and has_column_privilege(quote_ident(s.nspname) ||'.'||quote_ident(c.relname), a.attname, 'SELECT,INSERT,UPDATE,REFERENCES'); +GRANT SELECT ON sys.columns TO PUBLIC; + +create or replace view sys.foreign_key_columns as +select distinct + c.oid as constraint_object_id + , c.confkey as constraint_column_id + , c.conrelid as parent_object_id + , a_con.attnum as parent_column_id + , c.confrelid as referenced_object_id + , a_conf.attnum as referenced_column_id +from pg_constraint c +inner join pg_attribute a_con on a_con.attrelid = c.conrelid and a_con.attnum = any(c.conkey) +inner join pg_attribute a_conf on a_conf.attrelid = c.confrelid and a_conf.attnum = any(c.confkey) +where c.contype = 'f'; +GRANT SELECT ON sys.foreign_key_columns TO PUBLIC; + +create or replace view sys.foreign_keys as +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'::varchar(2) as type + , 'FOREIGN_KEY_CONSTRAINT'::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 + , c.confrelid as referenced_object_id + , c.confkey as key_index_id + , 0 as is_disabled + , 0 as is_not_for_replication + , 0 as is_not_trusted + , case c.confdeltype + when 'a' then 0 + when 'r' then 0 + when 'c' then 1 + when 'n' then 2 + when 'd' then 3 + end as delete_referential_action + , case c.confdeltype + when 'a' then 'NO_ACTION' + when 'r' then 'NO_ACTION' + when 'c' then 'CASCADE' + when 'n' then 'SET_NULL' + when 'd' then 'SET_DEFAULT' + end as delete_referential_action_desc + , case c.confupdtype + when 'a' then 0 + when 'r' then 0 + when 'c' then 1 + when 'n' then 2 + when 'd' then 3 + end as update_referential_action + , case c.confupdtype + when 'a' then 'NO_ACTION' + when 'r' then 'NO_ACTION' + when 'c' then 'CASCADE' + when 'n' then 'SET_NULL' + when 'd' then 'SET_DEFAULT' + end as update_referential_action_desc + , 1 as is_system_named +from pg_constraint c +inner join pg_namespace s on s.oid = c.connamespace +where c.contype = 'f' +and s.nspname not in ('information_schema', 'pg_catalog'); +GRANT SELECT ON sys.foreign_keys TO PUBLIC; + +create or replace view sys.identity_columns as +select + sys.babelfish_get_id_by_name(c.oid::text||a.attname) as object_id + , a.attname as name + , a.attnum as column_id + , t.oid as system_type_id + , t.oid as user_type_id + , a.attlen as max_length + , null::integer as precision + , null::integer as scale + , coll.collname as collation_name + , case when a.attnotnull then 0 else 1 end as is_nullable + , 0 as is_ansi_padded + , 0 as is_rowguidcol + , 1 as is_identity + , 0 as is_computed + , 0 as is_filestream + , 0 as is_replicated + , 0 as is_non_sql_subscribed + , 0 as is_merge_published + , 0 as is_dts_replicated + , 0 as is_xml_document + , 0 as xml_collection_id + , coalesce(d.oid, 0) as default_object_id + , coalesce((select oid from pg_constraint where conrelid = t.oid and contype = 'c' and a.attnum = any(conkey) limit 1), 0) as rule_object_id + , 0 as is_sparse + , 0 as is_column_set + , 0 as generated_always_type + , 'NOT_APPLICABLE'::varchar(60) as generated_always_type_desc + , null::integer as encryption_type + , null::varchar(64) as encryption_type_desc + , null::varchar as encryption_algorithm_name + , null::integer as column_encryption_key_id + , null::varchar as column_encryption_key_database_name + , 0 as is_hidden + , 0 as is_masked + , null::bigint as seed_value + , null::bigint as increment_value + , sys.babelfish_get_sequence_value(pg_get_serial_sequence(quote_ident(s.nspname)||'.'||quote_ident(c.relname), a.attname)) as last_value +from pg_attribute a +left join pg_attrdef d on a.attrelid = d.adrelid and a.attnum = d.adnum +inner join pg_class c on c.oid = a.attrelid +inner join pg_namespace s on s.oid = c.relnamespace +left join pg_type t on t.oid = a.atttypid +left join pg_collation coll on coll.oid = t.typcollation +where not a.attisdropped +and pg_get_serial_sequence(quote_ident(s.nspname)||'.'||quote_ident(c.relname), a.attname) is not null +and s.nspname not in ('information_schema', 'pg_catalog') +and has_sequence_privilege(pg_get_serial_sequence(quote_ident(s.nspname)||'.'||quote_ident(c.relname), a.attname), 'USAGE,SELECT,UPDATE'); +GRANT SELECT ON sys.identity_columns TO PUBLIC; + +create or replace view sys.indexes as +select + i.indrelid as object_id + , c.relname as name + , case when i.indisclustered then 1 else 2 end as type + , case when i.indisclustered then 'CLUSTERED'::varchar(60) else 'NONCLUSTERED'::varchar(60) end as type_desc + , case when i.indisunique then 1 else 0 end as is_unique + , c.reltablespace as data_space_id + , 0 as ignore_dup_key + , case when i.indisprimary then 1 else 0 end as is_primary_key + , case when constr.oid is null then 0 else 1 end as is_unique_constraint + , 0 as fill_factor + , case when i.indpred is null then 0 else 1 end as is_padded + , case when i.indisready then 0 else 1 end is_disabled + , 0 as is_hypothetical + , 1 as allow_row_locks + , 1 as allow_page_locks + , 0 as has_filter + , null::varchar as filter_definition + , 0 as auto_created +from pg_class c +inner join pg_namespace s on s.oid = c.relnamespace +inner join pg_index i on i.indexrelid = c.oid +left join pg_constraint constr on constr.conindid = c.oid +where c.relkind = 'i' and i.indislive +and s.nspname not in ('information_schema', 'pg_catalog'); +GRANT SELECT ON sys.indexes TO PUBLIC; + +create or replace view sys.key_constraints as +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 + , case contype + when 'p' then 'PK'::varchar(2) + when 'u' then 'UQ'::varchar(2) + end as type + , case contype + when 'p' then 'PRIMARY_KEY_CONSTRAINT'::varchar(60) + when 'u' then 'UNIQUE_CONSTRAINT'::varchar(60) + end as type_desc + , null::timestamp as create_date + , null::timestamp as modify_date + , c.conindid as unique_index_id + , 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 c.contype = 'p'; +GRANT SELECT ON sys.key_constraints TO PUBLIC; + +create or replace view sys.procedures as +select + p.proname as name + , p.oid as object_id + , null::integer as principal_id + , s.oid as schema_id + , 0 as parent_object_id + , case format_type(p.prorettype, null) + when 'void' then 'P'::varchar(2) + else + case format_type(p.prorettype, null) when 'trigger' + then 'TR'::varchar(2) + else 'FN'::varchar(2) + end + end as type + , case format_type(p.prorettype, null) + when 'void' then 'SQL_STORED_PROCEDURE'::varchar(60) + else + case format_type(p.prorettype, null) when 'trigger' + then 'SQL_TRIGGER'::varchar(60) + 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 +where s.nspname not in ('information_schema', 'pg_catalog') +and has_function_privilege(p.oid, 'EXECUTE'); +GRANT SELECT ON sys.procedures TO PUBLIC; + +create or replace view sys.sql_modules as +select + p.oid as object_id + , pg_get_functiondef(p.oid) as definition + , 1 as uses_ansi_nulls + , 1 as uses_quoted_identifier + , 0 as is_schema_bound + , 0 as uses_database_collation + , 0 as is_recompiled + , case when p.proisstrict then 1 else 0 end as null_on_null_input + , null::integer as execute_as_principal_id + , 0 as uses_native_compilation +from pg_proc p +inner join pg_namespace s on s.oid = p.pronamespace +inner join pg_type t on t.oid = p.prorettype +left join pg_collation c on c.oid = t.typcollation +where s.nspname not in ('information_schema', 'pg_catalog') +and has_function_privilege(p.oid, 'EXECUTE'); +GRANT SELECT ON sys.sql_modules TO PUBLIC; + +create or replace view sys.sysforeignkeys as +select + c.conname as name + , c.oid as object_id + , c.conrelid as fkeyid + , c.confrelid as rkeyid + , a_con.attnum as fkey + , a_conf.attnum as rkey + , a_conf.attnum as keyno +from pg_constraint c +inner join pg_namespace s on s.oid = c.connamespace +inner join pg_attribute a_con on a_con.attrelid = c.conrelid and a_con.attnum = any(c.conkey) +inner join pg_attribute a_conf on a_conf.attrelid = c.confrelid and a_conf.attnum = any(c.confkey) +where c.contype = 'f' +and s.nspname not in ('information_schema', 'pg_catalog'); +GRANT SELECT ON sys.sysforeignkeys TO PUBLIC; + +create or replace view sys.sysindexes as +select + i.object_id as id + , null::integer as status + , null::oid as first + , i.type as indid + , null::oid as root + , 0 as minlen + , 1 as keycnt + , 0 as groupid + , 0 as dpages + , 0 as reserved + , 0 as used + , 0 as rowcnt + , 0 as rowmodctr + , 0 as reserved3 + , 0 as reserved4 + , 0 as xmaxlen + , null::integer as maxirow + , 0 as OrigFillFactor + , 0 as StatVersion + , 0 as reserved2 + , null::integer as FirstIAM + , 0 as impid + , 0 as lockflags + , 0 as pgmodctr + , null::bytea as keys + , i.name + , null::bytea as statblob + , 800 as maxlen + , 0 as rows +from sys.indexes i; +GRANT SELECT ON sys.sysindexes 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 + , a.datid 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 + , a.client_hostname 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 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; +GRANT SELECT ON sys.sysprocesses TO PUBLIC; + +create or replace view sys.types As +select format_type(t.oid, null) as name + , t.oid as system_type_id + , t.oid as user_type_id + , s.oid as schema_id + , null::integer as principal_id + , t.typlen as max_length + , 0 as precision + , 0 as scale + , c.collname as collation_name + , case when typnotnull then 0 else 1 end as is_nullable + , case typcategory when 'U' then 1 else 0 end 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; +GRANT SELECT ON sys.types TO PUBLIC; + +create view sys.objects as +select + t.name + , t.object_id + , t.principal_id + , t.schema_id + , t.parent_object_id + , 'U' as type + , 'USER_TABLE' as type_desc + , t.create_date + , t.modify_date + , t.is_ms_shipped + , t.is_published + , t.is_schema_published +from sys.tables t +where has_schema_privilege(t.schema_id, 'USAGE') +union all +select + v.name + , v.object_id + , v.principal_id + , v.schema_id + , v.parent_object_id + , 'V' as type + , 'VIEW' as type_desc + , v.create_date + , v.modify_date + , v.is_ms_shipped + , v.is_published + , v.is_schema_published +from sys.views v +where has_schema_privilege(v.schema_id, 'USAGE') +union all +select + f.name + , f.object_id + , f.principal_id + , f.schema_id + , f.parent_object_id + , 'F' as type + , 'FOREIGN_KEY_CONSTRAINT' + , f.create_date + , f.modify_date + , f.is_ms_shipped + , f.is_published + , f.is_schema_published + from sys.foreign_keys f +where has_schema_privilege(f.schema_id, 'USAGE') + union all +select + p.name + , p.object_id + , p.principal_id + , p.schema_id + , p.parent_object_id + , 'PK' as type + , 'PRIMARY_KEY_CONSTRAINT' as type_desc + , p.create_date + , p.modify_date + , p.is_ms_shipped + , p.is_published + , p.is_schema_published + from sys.key_constraints p +where has_schema_privilege(p.schema_id, 'USAGE') +union all +select + pr.name + , pr.object_id + , pr.principal_id + , pr.schema_id + , pr.parent_object_id + , pr.type + , pr.type_desc + , pr.create_date + , pr.modify_date + , pr.is_ms_shipped + , pr.is_published + , pr.is_schema_published + from sys.procedures pr +where has_schema_privilege(pr.schema_id, 'USAGE') +union all +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 s.nspname not in ('information_schema', 'pg_catalog') +and p.relkind = 'S' +and has_schema_privilege(s.oid, 'USAGE'); +GRANT SELECT ON sys.objects TO PUBLIC; + +create or replace view sys.sysobjects as +select + s.name + , s.object_id as id + , s.type as xtype + , s.schema_id as uid + , 0 as info + , 0 as status + , 0 as base_schema_ver + , 0 as replinfo + , s.parent_object_id as parent_obj + , s.create_date as crdate + , 0 as ftcatid + , 0 as schema_ver + , 0 as stats_schema_ver + , s.type + , 0 as userstat + , 0 as sysstat + , 0 as indexdel + , s.modify_date as refdate + , 0 as version + , 0 as deltrig + , 0 as instrig + , 0 as updtrig + , 0 as seltrig + , 0 as category + , 0 as cache +from sys.objects s; +GRANT SELECT ON sys.sysobjects TO PUBLIC; + +create view sys.all_objects as +select + t.name + , t.object_id + , t.principal_id + , t.schema_id + , t.parent_object_id + , 'U' as type + , 'USER_TABLE' as type_desc + , t.create_date + , t.modify_date + , t.is_ms_shipped + , t.is_published + , t.is_schema_published +from sys.tables t +union all +select + v.name + , v.object_id + , v.principal_id + , v.schema_id + , v.parent_object_id + , 'V' as type + , 'VIEW' as type_desc + , v.create_date + , v.modify_date + , v.is_ms_shipped + , v.is_published + , v.is_schema_published +from sys.all_views v +union all +select + f.name + , f.object_id + , f.principal_id + , f.schema_id + , f.parent_object_id + , 'F' as type + , 'FOREIGN_KEY_CONSTRAINT' + , f.create_date + , f.modify_date + , f.is_ms_shipped + , f.is_published + , f.is_schema_published + from sys.foreign_keys f + union all +select + p.name + , p.object_id + , p.principal_id + , p.schema_id + , p.parent_object_id + , 'PK' as type + , 'PRIMARY_KEY_CONSTRAINT' as type_desc + , p.create_date + , p.modify_date + , p.is_ms_shipped + , p.is_published + , p.is_schema_published + from sys.key_constraints p +union all +select + pr.name + , pr.object_id + , pr.principal_id + , pr.schema_id + , pr.parent_object_id + , pr.type + , pr.type_desc + , pr.create_date + , pr.modify_date + , pr.is_ms_shipped + , pr.is_published + , pr.is_schema_published + from sys.procedures pr +union all +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'; +GRANT SELECT ON sys.all_objects TO PUBLIC; + +create or replace view sys.system_objects as +select * from sys.all_objects o +inner join pg_namespace s on s.oid = o.schema_id +where s.nspname in ('information_schema', 'pg_catalog'); +GRANT SELECT ON sys.system_objects TO PUBLIC; + +CREATE VIEW sys.syscharsets +AS +SELECT 1001 as type, + 1 as id, + 0 as csid, + 0 as status, + NULL::nvarchar(128) as name, + NULL::nvarchar(255) as description , + NULL::varbinary(6000) binarydefinition , + NULL::image definition; +GRANT SELECT ON sys.syscharsets TO PUBLIC; +-- 16 "sql/babelfishpg_tsql.in" 2 +-- 1 "sql/collation.sql" 1 +-- create babelfish collations + +CREATE COLLATION IF NOT EXISTS sys.Arabic_CS_AS (provider = icu, locale = 'ar_SA'); +CREATE COLLATION sys.Arabic_CI_AS (provider = icu, locale = 'ar_SA@colStrength=secondary', deterministic = false); +CREATE COLLATION sys.Arabic_CI_AI (provider = icu, locale = 'ar_SA@colStrength=primary', deterministic = false); + +CREATE COLLATION sys.BBF_Unicode_BIN2 FROM "C"; + +CREATE COLLATION sys.BBF_Unicode_General_CI_AS (provider = icu, locale = '@colStrength=secondary', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_General_CI_AI (provider = icu, locale = '@colStrength=primary', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_General_CS_AI (provider = icu, locale = '@colStrength=primary;colCaseLevel=yes;colCaseFirst=upper', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_General_CS_AS (provider = icu, locale = '@colStrength=tertiary', deterministic = true); +CREATE COLLATION sys.BBF_Unicode_General_Pref_CS_AS (provider = icu, locale = '@colStrength=tertiary;colCaseFirst=upper', deterministic = true); + +CREATE COLLATION sys.BBF_Unicode_CP1_CI_AS (provider = icu, locale = '@colStrength=secondary', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1_CI_AI (provider = icu, locale = '@colStrength=primary', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1_CS_AI (provider = icu, locale = '@colStrength=primary;colCaseLevel=yes;colCaseFirst=upper', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1_CS_AS (provider = icu, locale = '@colStrength=tertiary', deterministic = true); +CREATE COLLATION sys.BBF_Unicode_Pref_CP1_CS_AS (provider = icu, locale = '@colStrength=tertiary;colCaseFirst=upper', deterministic = true); + +CREATE COLLATION sys.BBF_Unicode_CP1250_CI_AS (provider = icu, locale = '@colStrength=secondary', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1250_CI_AI (provider = icu, locale = '@colStrength=primary', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1250_CS_AI (provider = icu, locale = '@colStrength=primary;colCaseLevel=yes;colCaseFirst=upper', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1250_CS_AS (provider = icu, locale = '@colStrength=tertiary', deterministic = true); +CREATE COLLATION sys.BBF_Unicode_Pref_CP1250_CS_AS (provider = icu, locale = '@colStrength=tertiary;colCaseFirst=upper', deterministic = true); + +CREATE COLLATION sys.BBF_Unicode_CP1251_CI_AS (provider = icu, locale = '@colStrength=secondary', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1251_CI_AI (provider = icu, locale = '@colStrength=primary', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1251_CS_AI (provider = icu, locale = '@colStrength=primary;colCaseLevel=yes;colCaseFirst=upper', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1251_CS_AS (provider = icu, locale = '@colStrength=tertiary', deterministic = true); +CREATE COLLATION sys.BBF_Unicode_Pref_CP1251_CS_AS (provider = icu, locale = '@colStrength=tertiary;colCaseFirst=upper', deterministic = true); + +CREATE COLLATION sys.BBF_Unicode_CP1253_CI_AS (provider = icu, locale = '@colStrength=secondary', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1253_CI_AI (provider = icu, locale = '@colStrength=primary', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1253_CS_AI (provider = icu, locale = '@colStrength=primary;colCaseLevel=yes;colCaseFirst=upper', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1253_CS_AS (provider = icu, locale = '@colStrength=tertiary', deterministic = true); +CREATE COLLATION sys.BBF_Unicode_Pref_CP1253_CS_AS (provider = icu, locale = '@colStrength=tertiary;colCaseFirst=upper', deterministic = true); + +CREATE COLLATION sys.BBF_Unicode_CP1254_CI_AS (provider = icu, locale = '@colStrength=secondary', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1254_CI_AI (provider = icu, locale = '@colStrength=primary', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1254_CS_AI (provider = icu, locale = '@colStrength=primary;colCaseLevel=yes;colCaseFirst=upper', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1254_CS_AS (provider = icu, locale = '@colStrength=tertiary', deterministic = true); +CREATE COLLATION sys.BBF_Unicode_Pref_CP1254_CS_AS (provider = icu, locale = '@colStrength=tertiary;colCaseFirst=upper', deterministic = true); + +CREATE COLLATION sys.BBF_Unicode_CP1255_CI_AS (provider = icu, locale = '@colStrength=secondary', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1255_CI_AI (provider = icu, locale = '@colStrength=primary', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1255_CS_AI (provider = icu, locale = '@colStrength=primary;colCaseLevel=yes;colCaseFirst=upper', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1255_CS_AS (provider = icu, locale = '@colStrength=tertiary', deterministic = true); +CREATE COLLATION sys.BBF_Unicode_Pref_CP1255_CS_AS (provider = icu, locale = '@colStrength=tertiary;colCaseFirst=upper', deterministic = true); + +CREATE COLLATION sys.BBF_Unicode_CP1256_CI_AS (provider = icu, locale = '@colStrength=secondary', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1256_CI_AI (provider = icu, locale = '@colStrength=primary', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1256_CS_AI (provider = icu, locale = '@colStrength=primary;colCaseLevel=yes;colCaseFirst=upper', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1256_CS_AS (provider = icu, locale = '@colStrength=tertiary', deterministic = true); +CREATE COLLATION sys.BBF_Unicode_Pref_CP1256_CS_AS (provider = icu, locale = '@colStrength=tertiary;colCaseFirst=upper', deterministic = true); + +CREATE COLLATION sys.BBF_Unicode_CP1257_CI_AS (provider = icu, locale = '@colStrength=secondary', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1257_CI_AI (provider = icu, locale = '@colStrength=primary', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1257_CS_AI (provider = icu, locale = '@colStrength=primary;colCaseLevel=yes;colCaseFirst=upper', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1257_CS_AS (provider = icu, locale = '@colStrength=tertiary', deterministic = true); +CREATE COLLATION sys.BBF_Unicode_Pref_CP1257_CS_AS (provider = icu, locale = '@colStrength=tertiary;colCaseFirst=upper', deterministic = true); + +CREATE COLLATION sys.BBF_Unicode_CP1258_CI_AS (provider = icu, locale = '@colStrength=secondary', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1258_CI_AI (provider = icu, locale = '@colStrength=primary', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1258_CS_AI (provider = icu, locale = '@colStrength=primary;colCaseLevel=yes;colCaseFirst=upper', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1258_CS_AS (provider = icu, locale = '@colStrength=tertiary', deterministic = true); +CREATE COLLATION sys.BBF_Unicode_Pref_CP1258_CS_AS (provider = icu, locale = '@colStrength=tertiary;colCaseFirst=upper', deterministic = true); + +CREATE COLLATION sys.BBF_Unicode_CP874_CI_AS (provider = icu, locale = '@colStrength=secondary', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP874_CI_AI (provider = icu, locale = '@colStrength=primary', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP874_CS_AI (provider = icu, locale = '@colStrength=primary;colCaseLevel=yes;colCaseFirst=upper', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP874_CS_AS (provider = icu, locale = '@colStrength=tertiary', deterministic = true); +CREATE COLLATION sys.BBF_Unicode_Pref_CP874_CS_AS (provider = icu, locale = '@colStrength=tertiary;colCaseFirst=upper', deterministic = true); + +CREATE COLLATION IF NOT EXISTS sys.Chinese_PRC_CS_AS (provider = icu, locale = 'zh_CN'); +CREATE COLLATION sys.Chinese_PRC_CI_AS (provider = icu, locale = 'zh_CN@colStrength=secondary', deterministic = false); +CREATE COLLATION sys.Chinese_PRC_CI_AI (provider = icu, locale = 'zh_CN@colStrength=primary', deterministic = false); + +CREATE COLLATION IF NOT EXISTS sys.Cyrillic_General_CS_AS (provider = icu, locale='ru_RU'); +CREATE COLLATION sys.Cyrillic_General_CI_AS (provider = icu, locale='ru_RU@colStrength=secondary', deterministic = false); +CREATE COLLATION sys.Cyrillic_General_CI_AI (provider = icu, locale='ru_RU@colStrength=primary', deterministic = false); + +CREATE COLLATION sys.Estonian_CS_AS (provider = icu, locale='et_EE'); +CREATE COLLATION sys.Estonian_CI_AI (provider = icu, locale='et_EE@colStrength=primary', deterministic = false); +CREATE COLLATION sys.Estonian_CI_AS (provider = icu, locale='et_EE@colStrength=secondary', deterministic = false); + +CREATE COLLATION IF NOT EXISTS sys.Finnish_Swedish_CS_AS (provider = icu, locale = 'sv_SE'); +CREATE COLLATION sys.Finnish_Swedish_CI_AI (provider = icu, locale = 'sv_SE@colStrength=primary', deterministic = false); +CREATE COLLATION sys.Finnish_Swedish_CI_AS (provider = icu, locale = 'sv_SE@colStrength=secondary', deterministic = false); + +CREATE COLLATION IF NOT EXISTS sys.French_CS_AS (provider = icu, locale = 'fr_FR'); +CREATE COLLATION sys.French_CI_AI (provider = icu, locale = 'fr_FR@colStrength=primary', deterministic = false); +CREATE COLLATION sys.French_CI_AS (provider = icu, locale = 'fr_FR@colStrength=secondary', deterministic = false); + +CREATE COLLATION sys.Greek_CS_AS (provider = icu, locale = 'el_GR'); +CREATE COLLATION sys.Greek_CI_AI (provider = icu, locale = 'el_GR@colStrength=primary', deterministic = false); +CREATE COLLATION sys.Greek_CI_AS (provider = icu, locale = 'el_GR@colStrength=secondary', deterministic = false); + +CREATE COLLATION sys.Hebrew_CS_AS (provider = icu, locale = 'he_IL'); +CREATE COLLATION sys.Hebrew_CI_AI (provider = icu, locale = 'he_IL@colStrength=primary', deterministic = false); +CREATE COLLATION sys.Hebrew_CI_AS (provider = icu, locale = 'he_IL@colStrength=secondary', deterministic = false); + +CREATE COLLATION sys.Korean_Wansung_CS_AS (provider = icu, locale = 'ko_KR'); +CREATE COLLATION sys.Korean_Wansung_CI_AI (provider = icu, locale = 'ko_KR@colStrength=primary', deterministic = false); +CREATE COLLATION sys.Korean_Wansung_CI_AS (provider = icu, locale = 'ko_KR@colStrength=secondary', deterministic = false); + +CREATE COLLATION sys.Modern_Spanish_CS_AS (provider = icu, locale = 'en_ES'); +CREATE COLLATION sys.Modern_Spanish_CI_AI (provider = icu, locale='es_ES@colStrength=primary', deterministic = false); +CREATE COLLATION sys.Modern_Spanish_CI_AS (provider = icu, locale='es_ES@colStrength=secondary', deterministic = false); + +CREATE COLLATION sys.Mongolian_CS_AS (provider = icu, locale = 'mn_MN'); +CREATE COLLATION sys.Mongolian_CI_AI (provider = icu, locale = 'mn_MN@colStrength=primary', deterministic = false); +CREATE COLLATION sys.Mongolian_CI_AS (provider = icu, locale = 'mn_MN@colStrength=secondary', deterministic = false); + +CREATE COLLATION IF NOT EXISTS sys.Polish_CS_AS (provider = icu, locale = 'pl_PL'); +CREATE COLLATION sys.Polish_CI_AI (provider = icu, locale = 'pl_PL@colStrength=primary', deterministic = false); +CREATE COLLATION sys.Polish_CI_AS (provider = icu, locale = 'pl_PL@colStrength=secondary', deterministic = false); + +CREATE COLLATION IF NOT EXISTS sys.Thai_CS_AS (provider = icu, locale = 'th_TH'); +CREATE COLLATION sys.Thai_CI_AI (provider = icu, locale = 'th_TH@colStrength=primary', deterministic = false); +CREATE COLLATION sys.Thai_CI_AS (provider = icu, locale = 'th_TH@colStrength=secondary', deterministic = false); + +CREATE COLLATION IF NOT EXISTS sys.Traditional_Spanish_CS_AS (provider = icu, locale = 'es_TRADITIONAL'); +CREATE COLLATION sys.Traditional_Spanish_CI_AI (provider = icu, locale = 'es_TRADITIONAL@colStrength=primary', deterministic = false); +CREATE COLLATION sys.Traditional_Spanish_CI_AS (provider = icu, locale = 'es_TRADITIONAL@colStrength=secondary', deterministic = false); + +CREATE COLLATION IF NOT EXISTS sys.Turkish_CS_AS (provider = icu, locale = 'tr_TR'); +CREATE COLLATION sys.Turkish_CI_AI (provider = icu, locale = 'tr_TR@colStrength=primary', deterministic = false); +CREATE COLLATION sys.Turkish_CI_AS (provider = icu, locale = 'tr_TR@colStrength=secondary', deterministic = false); + +CREATE COLLATION IF NOT EXISTS sys.Ukrainian_CS_AS (provider = icu, locale = 'uk_UA'); +CREATE COLLATION sys.Ukrainian_CI_AI (provider = icu, locale = 'uk_UA@colStrength=primary', deterministic = false); +CREATE COLLATION sys.Ukrainian_CI_AS (provider = icu, locale = 'uk_UA@colStrength=secondary', deterministic = false); + +CREATE COLLATION IF NOT EXISTS sys.Vietnamese_CS_AS (provider = icu, locale = 'vi_VN'); +CREATE COLLATION sys.Vietnamese_CI_AI (provider = icu, locale = 'vi_VN@colStrength=primary', deterministic = false); +CREATE COLLATION sys.Vietnamese_CI_AS (provider = icu, locale = 'vi_VN@colStrength=secondary', deterministic = false); + +-- collation catalog +create table sys.babelfish_helpcollation( + Name VARCHAR(128) NOT NULL, + Description VARCHAR(1000) NOT NULL +); +GRANT SELECT ON sys.babelfish_helpcollation TO PUBLIC; + +create or replace function sys.fn_helpcollations() +returns table (Name VARCHAR(128), Description VARCHAR(1000)) +AS +$$ +BEGIN + return query select * from sys.babelfish_helpcollation; +END +$$ +LANGUAGE 'plpgsql'; +INSERT INTO sys.babelfish_helpcollation VALUES (N'arabic_cs_as', N'Arabic, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'arabic_ci_ai', N'Arabic, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'arabic_ci_as', N'Arabic, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_bin2', N'Unicode-General, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1250_ci_ai', N'Default locale, code page 1250, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1250_ci_as', N'Default locale, code page 1250, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1250_cs_ai', N'Default locale, code page 1250, case-sensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1250_cs_as', N'Default locale, code page 1250, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_pref_cp1250_cs_as', N'Default locale, code page 1250, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive, uppercase-first'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1251_ci_ai', N'Default locale, code page 1251, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1251_ci_as', N'Default locale, code page 1251, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1251_cs_ai', N'Default locale, code page 1251, case-sensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1251_cs_as', N'Default locale, code page 1251, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_pref_cp1251_cs_as', N'Default locale, code page 1251, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive, uppercase-first'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1253_ci_ai', N'Default locale, code page 1253, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1253_ci_as', N'Default locale, code page 1253, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1253_cs_ai', N'Default locale, code page 1253, case-sensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1253_cs_as', N'Default locale, code page 1253, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_pref_cp1253_cs_as', N'Default locale, code page 1253, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive, uppercase-first'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1254_ci_ai', N'Default locale, code page 1254, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1254_ci_as', N'Default locale, code page 1254, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1254_cs_ai', N'Default locale, code page 1254, case-sensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1254_cs_as', N'Default locale, code page 1254, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_pref_cp1254_cs_as', N'Default locale, code page 1254, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive, uppercase-first'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1255_ci_ai', N'Default locale, code page 1255, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1255_ci_as', N'Default locale, code page 1255, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1255_cs_ai', N'Default locale, code page 1255, case-sensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1255_cs_as', N'Default locale, code page 1255, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_pref_cp1255_cs_as', N'Default locale, code page 1255, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive, uppercase-first'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1256_ci_ai', N'Default locale, code page 1256, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1256_ci_as', N'Default locale, code page 1256, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1256_cs_ai', N'Default locale, code page 1256, case-sensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1256_cs_as', N'Default locale, code page 1256, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_pref_cp1256_cs_as', N'Default locale, code page 1256, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive, uppercase-first'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1257_ci_ai', N'Default locale, code page 1257, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1257_ci_as', N'Default locale, code page 1257, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1257_cs_ai', N'Default locale, code page 1257, case-sensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1257_cs_as', N'Default locale, code page 1257, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_pref_cp1257_cs_as', N'Default locale, code page 1257, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive, uppercase-first'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1258_ci_ai', N'Default locale, code page 1258, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1258_ci_as', N'Default locale, code page 1258, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1258_cs_ai', N'Default locale, code page 1258, case-sensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1258_cs_as', N'Default locale, code page 1258, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_pref_cp1258_cs_as', N'Default locale, code page 1258, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive, uppercase-first'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1_ci_ai', N'Default locale, code page 1252, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1_ci_as', N'Default locale, code page 1252, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1_cs_ai', N'Default locale, code page 1252, case-sensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1_cs_as', N'Default locale, code page 1252, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_pref_cp1_cs_as', N'Default locale, code page 1252, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive, uppercase-first'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp847_ci_ai', N'Default locale, code page 847, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp847_ci_as', N'Default locale, code page 847, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp847_cs_ai', N'Default locale, code page 847, case-sensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp847_cs_as', N'Default locale, code page 847, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_pref_cp847_cs_as', N'Default locale, code page 847, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive, uppercase-first'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_general_ci_ai', N'Default locale, default code page, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_general_ci_as', N'Default locale, default code page, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_general_cs_ai', N'Default locale, default code page, case-sensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_general_cs_as', N'Default locale, default code page, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_general_pref_cs_as', N'Default locale, default code page, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive, uppercase-first'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'chinese_prc_cs_as', N'Chinese-PRC, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'chinese_prc_ci_ai', N'Chinese-PRC, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'chinese_prc_ci_as', N'Chinese-PRC, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'cyrillic_general_cs_as', N'Cyrillic-General, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'cyrillic_general_ci_ai', N'Cyrillic-General, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'cyrillic_general_ci_as', N'Cyrillic-General, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'finnish_swedish_cs_as', N'Finnish-Swedish, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'finnish_swedish_ci_as', N'Finnish-Swedish, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'finnish_swedish_ci_ai', N'Finnish-Swedish, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'french_cs_as', N'French, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'french_ci_as', N'French, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'french_ci_ai', N'French, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'korean_wansung_cs_as', N'Korean-Wansung, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'korean_wansung_ci_as', N'Korean-Wansung, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'korean_wansung_ci_ai', N'Korean-Wansung, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'latin1_general_bin2', N'Virtual, Unicode-General, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'latin1_general_90_bin2', N'Virtual, Unicode-General, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'latin1_general_100_bin2', N'Virtual, Unicode-General, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'latin1_general_140_bin2', N'Virtual, Unicode-General, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'latin1_general_ci_ai', N'Virtual, default locale, code page 1252, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'latin1_general_ci_as', N'Virtual, default locale, code page 1252, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'latin1_general_cs_ai', N'Virtual, default locale, code page 1252, case-sensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'latin1_general_cs_as', N'Virtual, default locale, code page 1252, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'modern_spanish_cs_as', N'Traditional-Spanish, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'modern_spanish_ci_as', N'Traditional-Spanish, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'modern_spanish_ci_ai', N'Traditional-Spanish, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'polish_cs_as', N'Polish, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'polish_ci_as', N'Polish, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'polish_ci_ai', N'Polish, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'sql_latin1_general_cp1250_ci_as', N'Virtual, default locale, code page 1250, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'sql_latin1_general_cp1250_cs_as', N'Virtual, default locale, code page 1250, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'sql_latin1_general_cp1251_ci_as', N'Virtual, default locale, code page 1251, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'sql_latin1_general_cp1251_cs_as', N'Virtual, default locale, code page 1251, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'sql_latin1_general_cp1_ci_ai', N'Virtual, default locale, code page 1252, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'sql_latin1_general_cp1_ci_as', N'Virtual, default locale, code page 1252, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'sql_latin1_general_cp1_ci_ai', N'Virtual, default locale, code page 1252, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'sql_latin1_general_cp1_cs_as', N'Virtual, default locale, code page 1252, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'sql_latin1_general_pref_cp1_cs_as', N'Virtual, default locale, code page 1252, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive, uppercase-first'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'sql_latin1_general_cp1253_ci_as', N'Virtual, default locale, code page 1253, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'sql_latin1_general_cp1253_cs_as', N'Virtual, default locale, code page 1253, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'sql_latin1_general_cp1254_ci_as', N'Virtual, default locale, code page 1254, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'sql_latin1_general_cp1254_cs_as', N'Virtual, default locale, code page 1255, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'sql_latin1_general_cp1255_ci_as', N'Virtual, default locale, code page 1255, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'sql_latin1_general_cp1255_cs_as', N'Virtual, default locale, code page 1255, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'sql_latin1_general_cp1256_ci_as', N'Virtual, default locale, code page 1256, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'sql_latin1_general_cp1256_cs_as', N'Virtual, default locale, code page 1256, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'sql_latin1_general_cp1257_ci_as', N'Virtual, default locale, code page 1257, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'sql_latin1_general_cp1257_cs_as', N'Virtual, default locale, code page 1257, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'sql_latin1_general_cp1258_ci_as', N'Virtual, default locale, code page 1258, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'sql_latin1_general_cp1258_cs_as', N'Virtual, default locale, code page 1258, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'thai_cs_as', N'Thai, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'thai_ci_as', N'Thai, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'thai_ci_ai', N'Thai, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'traditional_spanish_cs_as', N'Traditional-Spanish, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'traditional_spanish_ci_as', N'Traditional-Spanish, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'traditional_spanish_ci_ai', N'Traditional-Spanish, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'turkish_cs_as', N'Turkish, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'turkish_ci_as', N'Turkish, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'turkish_ci_ai', N'Turkish, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'ukrainian_cs_as', N'Ukrainian, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'ukrainian_ci_as', N'Ukrainian, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'ukrainian_ci_ai', N'Ukrainian, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'vietnamese_cs_as', N'Vietnamese, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'vietnamese_ci_as', N'Vietnamese, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'vietnamese_ci_ai', N'Vietnamese, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); + +DROP FUNCTION IF EXISTS sys.get_babel_server_collation_oid; +CREATE OR REPLACE FUNCTION sys.get_babel_server_collation_oid() RETURNS OID +LANGUAGE C +AS 'babelfishpg_tsql', 'get_server_collation_oid'; + +DROP PROCEDURE IF EXISTS sys.init_database_collation_oid; +CREATE OR REPLACE PROCEDURE sys.init_server_collation_oid() +AS $$ +DECLARE + server_colloid OID; +BEGIN + server_colloid = sys.get_babel_server_collation_oid(); + perform pg_catalog.set_config('babelfishpg_tsql.server_collation_oid', server_colloid::text, false); + execute format('ALTER DATABASE %I SET babelfishpg_tsql.server_collation_oid FROM CURRENT', current_database()); +END; +$$ +LANGUAGE plpgsql; + +CALL sys.init_server_collation_oid(); + +-- Fill in the oids in coll_infos +CREATE OR REPLACE PROCEDURE sys.babel_collation_initializer() +LANGUAGE C +AS 'babelfishpg_tsql', 'init_collid_trans_tab'; +CALL sys.babel_collation_initializer(); +DROP PROCEDURE sys.babel_collation_initializer; + +-- Manually initialize like mapping table +CREATE OR REPLACE PROCEDURE sys.babel_like_ilike_info_initializer() +LANGUAGE C +AS 'babelfishpg_tsql', 'init_like_ilike_table'; +CALL sys.babel_like_ilike_info_initializer(); +DROP PROCEDURE sys.babel_like_ilike_info_initializer; +-- 17 "sql/babelfishpg_tsql.in" 2 +-- 1 "sql/sys_procedures.sql" 1 +CREATE PROCEDURE sys.sp_unprepare(IN prep_handle INTEGER) +AS 'babelfishpg_tsql', 'sp_unprepare' +LANGUAGE C; +GRANT EXECUTE ON PROCEDURE sys.sp_unprepare(IN INTEGER) TO PUBLIC; + +CREATE PROCEDURE sys.sp_prepare(INOUT prep_handle INTEGER, IN params varchar(8000), + IN stmt varchar(8000), IN options int default 1) +AS 'babelfishpg_tsql', 'sp_prepare' +LANGUAGE C; +GRANT EXECUTE ON PROCEDURE sys.sp_prepare( + INOUT INTEGER, IN varchar(8000), IN varchar(8000), IN int +) TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.sp_getapplock_function (IN "@resource" varchar(255), + IN "@lockmode" varchar(32), + IN "@lockowner" varchar(32) DEFAULT 'TRANSACTION', + IN "@locktimeout" INTEGER DEFAULT -99, + IN "@dbprincipal" varchar(32) DEFAULT 'dbo') +RETURNS INTEGER +AS 'babelfishpg_tsql', 'sp_getapplock_function' LANGUAGE C; +GRANT EXECUTE ON FUNCTION sys.sp_getapplock_function( + IN varchar(255), IN varchar(32), IN varchar(32), IN INTEGER, IN varchar(32) +) TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.sp_releaseapplock_function(IN "@resource" varchar(255), + IN "@lockowner" varchar(32) DEFAULT 'TRANSACTION', + IN "@dbprincipal" varchar(32) DEFAULT 'dbo') +RETURNS INTEGER +AS 'babelfishpg_tsql', 'sp_releaseapplock_function' LANGUAGE C; +GRANT EXECUTE ON FUNCTION sys.sp_releaseapplock_function( + IN varchar(255), IN varchar(32), IN varchar(32) +) TO PUBLIC; + +CREATE OR REPLACE PROCEDURE sys.sp_cursor_list (INOUT "@cursor_return" refcursor, + IN "@cursor_scope" INTEGER) +AS $$ +DECLARE + cur refcursor; +BEGIN + IF "@cursor_scope" >= 1 AND "@cursor_scope" <= 3 THEN + OPEN cur FOR EXECUTE 'SELECT reference_name::name, cursor_name::name, cursor_scope::smallint, status::smallint, model::smallint, concurrency::smallint, scrollable::smallint, open_status::smallint, cursor_rows::numeric(10,0), fetch_status::smallint, column_count::smallint, row_count::numeric(10,0), last_operation::smallint, cursor_handle::int FROM sys.babelfish_cursor_list($1)' USING "@cursor_scope"; + ELSE + RAISE 'invalid @cursor_scope: %', "@cursor_scope"; + END IF; + + -- PG cursor evaluates the query at first fetch. We need to evaluate table function now because cursor_list() depeneds on "current" tsql_estate(). + -- Running MOVE fowrard and backward to force evaluating sys.babelfish_cursor_list() now. + MOVE NEXT FROM cur; + MOVE PRIOR FROM cur; + SELECT cur INTO "@cursor_return"; +END; +$$ LANGUAGE plpgsql; +GRANT EXECUTE ON PROCEDURE sys.sp_cursor_list(INOUT refcursor, IN INTEGER) TO PUBLIC; + +CREATE OR REPLACE PROCEDURE sys.sp_describe_cursor (INOUT "@cursor_return" refcursor, + IN "@cursor_source" nvarchar(30), + IN "@cursor_identity" nvarchar(30)) +AS $$ +DECLARE + cur refcursor; + cursor_source int; +BEGIN + IF lower("@cursor_source") = 'local' THEN + cursor_source := 1; + ELSIF lower("@cursor_source") = 'global' THEN + cursor_source := 2; + ELSIF lower("@cursor_source") = 'variable' THEN + cursor_source := 3; + ELSE + RAISE 'invalid @cursor_source: %', "@cursor_source"; + END IF; + + OPEN cur FOR EXECUTE 'SELECT reference_name::name, cursor_name::name, cursor_scope::smallint, status::smallint, model::smallint, concurrency::smallint, scrollable::smallint, open_status::smallint, cursor_rows::numeric(10,0), fetch_status::smallint, column_count::smallint, row_count::numeric(10,0), last_operation::smallint, cursor_handle::int FROM sys.babelfish_cursor_list($1) WHERE cursor_source = $1 and reference_name = $2' USING cursor_source, "@cursor_identity"; + + -- PG cursor evaluates the query at first fetch. We need to evaluate table function now because cursor_list() depeneds on "current" tsql_estate(). + -- Running MOVE fowrard and backward to force evaluating sys.babelfish_cursor_list() now. + MOVE NEXT FROM cur; + MOVE PRIOR FROM cur; + SELECT cur INTO "@cursor_return"; +END; +$$ LANGUAGE plpgsql; +GRANT EXECUTE ON PROCEDURE sys.sp_describe_cursor( + INOUT refcursor, IN nvarchar(30), IN nvarchar(30) +) TO PUBLIC; + +CREATE OR REPLACE PROCEDURE sys.sp_babelfish_configure() +AS 'babelfishpg_tsql', 'sp_babelfish_configure' +LANGUAGE C; +GRANT EXECUTE ON PROCEDURE sys.sp_babelfish_configure() TO PUBLIC; + +CREATE OR REPLACE PROCEDURE sys.sp_babelfish_configure(IN "@option_name" varchar(128)) +AS 'babelfishpg_tsql', 'sp_babelfish_configure' +LANGUAGE C; +GRANT EXECUTE ON PROCEDURE sys.sp_babelfish_configure(IN varchar(128)) TO PUBLIC; + +CREATE OR REPLACE PROCEDURE sys.sp_babelfish_configure(IN "@option_name" varchar(128), IN "@option_value" varchar(128)) +AS $$ +BEGIN + CALL sys.sp_babelfish_configure("@option_name", "@option_value", ''); +END; +$$ LANGUAGE plpgsql; +GRANT EXECUTE ON PROCEDURE sys.sp_babelfish_configure(IN varchar(128), IN varchar(128)) 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)) +AS $$ +DECLARE + normalized_name varchar(256); + cnt int; + cur refcursor; + eh_name varchar(256); + server boolean := false; + prev_user text; +BEGIN + IF lower("@option_name") like 'babelfishpg_tsql.%' THEN + SELECT "@option_name" INTO normalized_name; + ELSE + SELECT concat('babelfishpg_tsql.',"@option_name") INTO normalized_name; + END IF; + + IF lower("@option_scope") = 'server' THEN + server := true; + ELSIF btrim("@option_scope") != '' THEN + RAISE EXCEPTION 'invalid option: %', "@option_scope"; + END IF; + + SELECT COUNT(*) INTO cnt FROM pg_catalog.pg_settings WHERE name like normalized_name and name like '%escape_hatch%'; + IF cnt = 0 THEN + RAISE EXCEPTION 'unknown configuration: %', normalized_name; + END IF; + + OPEN cur FOR SELECT name FROM pg_catalog.pg_settings WHERE name like normalized_name and name like '%escape_hatch%'; + + LOOP + FETCH NEXT FROM cur into eh_name; + exit when not found; + + PERFORM pg_catalog.set_config(eh_name, "@option_value", 'false'); + IF server THEN + SELECT current_user INTO prev_user; + PERFORM sys.babelfish_set_role(session_user); + -- store the setting in PG master database so that it can be applied to all bbf databases + EXECUTE format('ALTER DATABASE %s SET %s = %s', CURRENT_DATABASE(), eh_name, "@option_value"); + PERFORM sys.babelfish_set_role(prev_user); + END IF; + END LOOP; + + CLOSE cur; + +END; +$$ LANGUAGE plpgsql; +GRANT EXECUTE ON PROCEDURE sys.sp_babelfish_configure( + IN varchar(128), IN varchar(128), IN varchar(128) +) TO PUBLIC; +-- 18 "sql/babelfishpg_tsql.in" 2 +-- 1 "sql/ownership.sql" 1 +-- BBF_SYSDATABASES +-- Note: change here requires change in FormData_sysdatabases too +CREATE TABLE sys.babelfish_sysdatabases ( + dbid SMALLINT NOT NULL UNIQUE, + status INT NOT NULL, + status2 INT NOT NULL, + owner NAME NOT NULL, + default_collation NAME NOT NULL, + name TEXT NOT NULL COLLATE "C", + crdate timestamptz NOT NULL, + properties TEXT NOT NULL COLLATE "C", + PRIMARY KEY (name) +); + +GRANT SELECT on sys.babelfish_sysdatabases TO PUBLIC; + +-- BABELFISH_NAMESPACE_EXT +CREATE TABLE sys.babelfish_namespace_ext ( + nspname NAME NOT NULL, + dbid SMALLINT NOT NULL, + orig_name sys.NVARCHAR(128) NOT NULL, + properties TEXT NOT NULL COLLATE "C", + PRIMARY KEY (nspname) +); +GRANT SELECT ON sys.babelfish_namespace_ext TO PUBLIC; + +-- SYSDATABASES +CREATE OR REPLACE VIEW sys.sysdatabases AS +SELECT +t.name, +sys.db_id(t.name) AS dbid, +CAST(CAST(r.oid AS int) AS SYS.VARBINARY(85)) AS sid, +CAST(0 AS SMALLINT) AS mode, +t.status, +t.status2, +CAST(t.crdate AS SYS.DATETIME) AS crdate, +CAST('1900-01-01 00:00:00.000' AS SYS.DATETIME) AS reserved, +CAST(0 AS INT) AS category, +CAST(NULL AS SYS.TINYINT) AS cmptlevel, +CAST(NULL AS SYS.NVARCHAR(260)) AS filename, +CAST(NULL AS SMALLINT) AS version +FROM sys.babelfish_sysdatabases AS t +LEFT OUTER JOIN pg_catalog.pg_roles r on r.rolname = t.owner; + +GRANT SELECT ON sys.sysdatabases TO PUBLIC; + +-- PG_NAMESPACE_EXT +CREATE VIEW sys.pg_namespace_ext AS +SELECT BASE.* , DB.name as dbname FROM +pg_catalog.pg_namespace AS base +LEFT OUTER JOIN sys.babelfish_namespace_ext AS EXT on BASE.nspname = EXT.nspname +INNER JOIN sys.babelfish_sysdatabases AS DB ON EXT.dbid = DB.dbid; + +GRANT SELECT ON sys.pg_namespace_ext TO PUBLIC; + +-- Logical Schema Views +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 base.nspname not in ('information_schema', 'pg_catalog', 'pg_toast', 'sys', 'public') +and ext.dbid = cast(sys.db_id() as oid); +GRANT SELECT ON sys.schemas TO PUBLIC; +CREATE SEQUENCE sys.babelfish_db_seq MAXVALUE 32767 CYCLE; + +-- CATALOG INITIALIZER +CREATE OR REPLACE PROCEDURE babel_catalog_initializer() +LANGUAGE C +AS 'babelfishpg_tsql', 'init_catalog'; + +CALL babel_catalog_initializer(); + +CREATE OR REPLACE PROCEDURE babel_create_builtin_dbs(IN login TEXT) +LANGUAGE C +AS 'babelfishpg_tsql', 'create_builtin_dbs'; + +CREATE OR REPLACE PROCEDURE sys.babel_drop_all_dbs() +LANGUAGE C +AS 'babelfishpg_tsql', 'drop_all_dbs'; + +CREATE OR REPLACE PROCEDURE sys.babel_initialize_logins(IN login TEXT) +LANGUAGE C +AS 'babelfishpg_tsql', 'initialize_logins'; + +CREATE OR REPLACE PROCEDURE sys.babel_drop_all_logins() +LANGUAGE C +AS 'babelfishpg_tsql', 'drop_all_logins'; + +CREATE OR REPLACE PROCEDURE initialize_babelfish ( sa_name VARCHAR(128) ) +LANGUAGE plpgsql +AS $$ +DECLARE + reserved_roles varchar[] := ARRAY['sysadmin', 'master_dbo', 'master_guest', 'master_db_owner', 'tempdb_dbo', 'tempdb_guest', 'tempdb_db_owner']; + user_id oid := -1; + db_name name := NULL; + role_name varchar; + dba_name varchar; +BEGIN + -- check reserved roles + FOREACH role_name IN ARRAY reserved_roles LOOP + BEGIN + SELECT oid INTO user_id FROM pg_roles WHERE rolname = role_name; + IF user_id > 0 THEN + SELECT datname INTO db_name FROM pg_shdepend AS s INNER JOIN pg_database AS d ON s.dbid = d.oid WHERE s.refobjid = user_id; + IF db_name IS NOT NULL THEN + RAISE E'Could not initialize babelfish in current database: Reserved role % used in database %.\nIf babelfish was initialized in %, please remove babelfish and try again.', role_name, db_name, db_name; + ELSE + RAISE E'Could not initialize babelfish in current database: Reserved role % exists. \nPlease rename or drop existing role and try again ', role_name; + END IF; + END IF; + END; + END LOOP; + + SELECT pg_get_userbyid(datdba) INTO dba_name FROM pg_database WHERE datname = CURRENT_DATABASE(); + IF sa_name <> dba_name THEN + RAISE E'Could not initialize babelfish with given role name: % is not the DB owner of current database.', sa_name; + END IF; + + EXECUTE format('CREATE ROLE sysadmin CREATEDB CREATEROLE INHERIT ROLE %I', sa_name); + EXECUTE format('GRANT USAGE, SELECT ON SEQUENCE sys.babelfish_db_seq TO sysadmin WITH GRANT OPTION'); + EXECUTE format('GRANT CREATE, CONNECT, TEMPORARY ON DATABASE %s TO sysadmin WITH GRANT OPTION', CURRENT_DATABASE()); + EXECUTE format('ALTER DATABASE %s SET babelfishpg_tsql.enable_ownership_structure = true', CURRENT_DATABASE()); + EXECUTE 'SET babelfishpg_tsql.enable_ownership_structure = true'; + CALL sys.babel_initialize_logins(sa_name); + CALL sys.babel_create_builtin_dbs(sa_name); +END +$$; + +CREATE OR REPLACE PROCEDURE remove_babelfish () +LANGUAGE plpgsql +AS $$ +BEGIN + CALL sys.babel_drop_all_dbs(); + CALL sys.babel_drop_all_logins(); + EXECUTE format('ALTER DATABASE %s SET babelfishpg_tsql.enable_ownership_structure = false', CURRENT_DATABASE()); + EXECUTE 'ALTER SEQUENCE sys.babelfish_db_seq RESTART'; + DROP OWNED BY sysadmin; + DROP ROLE sysadmin; +END +$$; + +-- LOGIN EXT +-- Note: change here requires change in FormData_authid_login_ext too +CREATE TABLE sys.babelfish_authid_login_ext ( +rolname NAME NOT NULL, -- pg_authid.rolname +is_disabled INT NOT NULL DEFAULT 0, -- to support enable/disable login +type CHAR(1) NOT NULL DEFAULT 'S', +credential_id INT NOT NULL, +owning_principal_id INT NOT NULL, +is_fixed_role INT NOT NULL DEFAULT 0, +create_date timestamptz NOT NULL, +modify_date timestamptz NOT NULL, +default_database_name SYS.NVARCHAR(128) NOT NULL, +default_language_name SYS.NVARCHAR(128) NOT NULL, +properties JSONB, +PRIMARY KEY (rolname)); +GRANT SELECT ON sys.babelfish_authid_login_ext TO PUBLIC; + +SELECT pg_catalog.pg_extension_config_dump('sys.babelfish_sysdatabases', ''); +SELECT pg_catalog.pg_extension_config_dump('sys.babelfish_db_seq', ''); +SELECT pg_catalog.pg_extension_config_dump('sys.babelfish_namespace_ext', ''); +SELECT pg_catalog.pg_extension_config_dump('sys.babelfish_authid_login_ext', ''); + +-- SERVER_PRINCIPALS +CREATE VIEW sys.server_principals +AS SELECT +CAST(Base.rolname 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, +Ext.type, +CAST(CASE WHEN Ext.type = 'S' THEN 'SQL_LOGIN' ELSE NULL END AS NVARCHAR(60)) AS type_desc, +Ext.is_disabled, +Ext.create_date, +Ext.modify_date, +Ext.default_database_name, +Ext.default_language_name, +Ext.credential_id, +Ext.owning_principal_id, +CAST(Ext.is_fixed_role AS sys.BIT) AS is_fixed_role +FROM pg_catalog.pg_authid AS Base INNER JOIN sys.babelfish_authid_login_ext AS Ext ON Base.rolname = Ext.rolname; + +GRANT SELECT ON sys.server_principals TO PUBLIC; + +-- internal table function for sp_helpdb with no arguments +CREATE OR REPLACE FUNCTION sys.babelfish_helpdb() +RETURNS table ( + name varchar(128), + db_size varchar(13), + owner varchar(128), + dbid int, + created varchar(11), + status varchar(600), + compatibility_level smallint +) AS 'babelfishpg_tsql', 'babelfish_helpdb' LANGUAGE C; + +-- internal table function for helpdb with dbname as input +CREATE OR REPLACE FUNCTION sys.babelfish_helpdb(varchar) +RETURNS table ( + name varchar(128), + db_size varchar(13), + owner varchar(128), + dbid int, + created varchar(11), + status varchar(600), + compatibility_level smallint +) AS 'babelfishpg_tsql', 'babelfish_helpdb' LANGUAGE C; + +create or replace view sys.databases as +select + d.name as name + , sys.db_id(d.name) as database_id + , null::integer as source_database_id + , cast(cast(r.oid as int) as varbinary(85)) as owner_sid + , CAST(d.crdate AS SYS.DATETIME) as create_date + , CAST(NULL AS SYS.TINYINT) as compatibility_level + , c.collname::sys.nvarchar(128) as collation_name + , 0 as user_access + , 'MULTI_USER'::varchar(60) as user_access_desc + , 0 as is_read_only + , 0 as is_auto_close_on + , 0 as is_auto_shrink_on + , 0 as state + , 'ONLINE'::varchar(60) as state_desc + , CASE + WHEN pg_is_in_recovery() is false THEN 0 + WHEN pg_is_in_recovery() is true THEN 1 + END as is_in_standby + , 0 as is_cleanly_shutdown + , 0 as is_supplemental_logging_enabled + , 1 as snapshot_isolation_state + , 'ON'::varchar(60) as snapshot_isolation_state_desc + , 1 as is_read_committed_snapshot_on + , 1 as recovery_model + , 'FULL'::varchar(60) as recovery_model_desc + , 0 as page_verify_option + , null::varchar(60) as page_verify_option_desc + , 1 as is_auto_create_stats_on + , 0 as is_auto_create_stats_incremental_on + , 0 as is_auto_update_stats_on + , 0 as is_auto_update_stats_async_on + , 0 as is_ansi_null_default_on + , 0 as is_ansi_nulls_on + , 0 as is_ansi_padding_on + , 0 as is_ansi_warnings_on + , 0 as is_arithabort_on + , 0 as is_concat_null_yields_null_on + , 0 as is_numeric_roundabort_on + , 0 as is_quoted_identifier_on + , 0 as is_recursive_triggers_on + , 0 as is_cursor_close_on_commit_on + , 0 as is_local_cursor_default + , 0 as is_fulltext_enabled + , 0 as is_trustworthy_on + , 0 as is_db_chaining_on + , 0 as is_parameterization_forced + , 0 as is_master_key_encrypted_by_server + , 0 as is_query_store_on + , 0 as is_published + , 0 as is_subscribed + , 0 as is_merge_published + , 0 as is_distributor + , 0 as is_sync_with_backup + , null::sys.UNIQUEIDENTIFIER as service_broker_guid + , 0 as is_broker_enabled + , 0 as log_reuse_wait + , 'NOTHING'::varchar(60) as log_reuse_wait_desc + , 0 as is_date_correlation_on + , 0 as is_cdc_enabled + , 0 as is_encrypted + , 0 as is_honor_broker_priority_on + , null::sys.UNIQUEIDENTIFIER as replica_id + , null::sys.UNIQUEIDENTIFIER as group_database_id + , null::int as resource_pool_id + , null::smallint as default_language_lcid + , null::sys.nvarchar(128) as default_language_name + , null::int as default_fulltext_language_lcid + , null::sys.nvarchar(128) as default_fulltext_language_name + , null::sys.bit as is_nested_triggers_on + , null::sys.bit as is_transform_noise_words_on + , null::smallint as two_digit_year_cutoff + , 0 as containment + , 'NONE'::varchar(60) as containment_desc + , 0 as target_recovery_time_in_seconds + , 0 as delayed_durability + , null::sys.nvarchar(60) as delayed_durability_desc + , 0 as is_memory_optimized_elevate_to_snapshot_on + , 0 as is_federation_member + , 0 as is_remote_data_archive_enabled + , 0 as is_mixed_page_allocation_on + , 0 as is_temporal_history_retention_enabled + , 0 as catalog_collation_type + , 'Not Applicable'::sys.nvarchar(60) as catalog_collation_type_desc + , null::sys.nvarchar(128) as physical_database_name + , 0 as is_result_set_caching_on + , 0 as is_accelerated_database_recovery_on + , 0 as is_tempdb_spill_to_remote_store + , 0 as is_stale_page_detection_on + , 0 as is_memory_optimized_enabled + , 0 as is_ledger_on + from sys.babelfish_sysdatabases d LEFT OUTER JOIN pg_catalog.pg_collation c ON d.default_collation = c.collname + LEFT OUTER JOIN pg_catalog.pg_roles r on r.rolname = d.owner; + +GRANT SELECT ON sys.databases TO PUBLIC; + +-- Babelfish Specific Metadata Consistency Check +CREATE OR REPLACE FUNCTION sys.babelfish_inconsistent_metadata() +RETURNS table ( + object_type varchar(32), + schema_name varchar(128), + object_name varchar(128), + detail text +) AS 'babelfishpg_tsql', 'babelfish_inconsistent_metadata' LANGUAGE C; +-- 19 "sql/babelfishpg_tsql.in" 2 +-- 1 "sql/import_export_compatibility.sql" 1 +CREATE TABLE sys.assemblies( + name VARCHAR(255), + principal_id int, + assembly_id int, + is_nullable int, + is_fixed_length int, + max_length int +); +GRANT SELECT ON sys.assemblies TO PUBLIC; + +CREATE TABLE sys.assembly_types ( + assembly_id int, + assembly_class VARCHAR(255) +); +GRANT SELECT ON sys.assembly_types TO PUBLIC; + +-- Cannot be implemented without a full implementation of assemblies. +-- However, a full implementation isn't needed for import-export support yet +CREATE OR REPLACE FUNCTION assemblyproperty(IN a VARCHAR, IN b VARCHAR) RETURNS sys.sql_variant +AS +$body$ + SELECT CAST('' AS sys.sql_variant); +$body$ +LANGUAGE SQL IMMUTABLE STRICT; +GRANT EXECUTE ON FUNCTION assemblyproperty(IN VARCHAR, IN VARCHAR) TO PUBLIC; + +CREATE OR REPLACE FUNCTION is_member(IN a VARCHAR) RETURNS INT +AS 'babelfishpg_tsql', 'is_member' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; +GRANT EXECUTE ON FUNCTION is_member(IN VARCHAR) TO PUBLIC; + +CREATE OR REPLACE FUNCTION schema_id(IN schema_name VARCHAR) RETURNS INT +AS 'babelfishpg_tsql', 'schema_id' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; +GRANT EXECUTE ON FUNCTION schema_id(IN VARCHAR) TO PUBLIC; + +CREATE OR REPLACE FUNCTION schema_name(IN id oid) RETURNS VARCHAR +AS 'babelfishpg_tsql', 'schema_name' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; +GRANT EXECUTE ON FUNCTION schema_name(IN oid) TO PUBLIC; +-- 20 "sql/babelfishpg_tsql.in" 2 +-- 1 "sql/babelfishpg_tsql.sql" 1 +CREATE FUNCTION pltsql_call_handler () + RETURNS language_handler AS 'babelfishpg_tsql' LANGUAGE C; + +CREATE FUNCTION pltsql_validator (oid) + RETURNS void AS 'babelfishpg_tsql' LANGUAGE C; + +CREATE FUNCTION pltsql_inline_handler(internal) + RETURNS void AS 'babelfishpg_tsql' LANGUAGE C; + +-- language +CREATE TRUSTED LANGUAGE pltsql + HANDLER pltsql_call_handler + INLINE pltsql_inline_handler + VALIDATOR pltsql_validator; +GRANT USAGE ON LANGUAGE pltsql TO public; + +COMMENT ON LANGUAGE pltsql IS 'PL/TSQL procedural language'; + +CREATE FUNCTION serverproperty (TEXT) + RETURNS sys.SQL_VARIANT AS 'babelfishpg_tsql', 'serverproperty' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION databasepropertyex (TEXT, TEXT) + RETURNS sys.SQL_VARIANT AS 'babelfishpg_tsql', 'databasepropertyex' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION connectionproperty (TEXT) + RETURNS sys.SQL_VARIANT AS 'babelfishpg_tsql', 'connectionproperty' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION collationproperty (TEXT, TEXT) + RETURNS sys.SQL_VARIANT AS 'babelfishpg_tsql', 'collationproperty' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sessionproperty (TEXT) + RETURNS sys.SQL_VARIANT AS 'babelfishpg_tsql', 'sessionproperty' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; +-- The procedures below requires return code as a RETURN statement which is +-- only possible in pltsql. Therefore, we create them here and call into the +-- corresponding internal functions. +CREATE OR REPLACE PROCEDURE sys.sp_getapplock(IN "@resource" varchar(255), + IN "@lockmode" varchar(32), + IN "@lockowner" varchar(32) DEFAULT 'TRANSACTION', + IN "@locktimeout" INTEGER DEFAULT -99, + IN "@dbprincipal" varchar(32) DEFAULT 'dbo') +LANGUAGE 'pltsql' +AS $$ +begin + declare @ret int; + select @ret = sp_getapplock_function(@resource, @lockmode, @lockowner, @locktimeout, @dbprincipal); + return @ret; +end; +$$; + +CREATE OR REPLACE PROCEDURE sys.sp_releaseapplock(IN "@resource" varchar(255), + IN "@lockowner" varchar(32) DEFAULT 'TRANSACTION', + IN "@dbprincipal" varchar(32) DEFAULT 'dbo') +LANGUAGE 'pltsql' +AS $$ +begin + declare @ret int; + select @ret = sp_releaseapplock_function(@resource, @lockowner, @dbprincipal); + return @ret; +end; +$$; + +-- sys.sp_oledb_ro_usrname is needed for TDS v7.2 +-- In tsql, sp_oledb_ro_usrname stored procedure returns the database read only status. +-- Return values: +-- 1. RO status (VARCHAR(1)) - "N" or "Y", "N" for not read only, "Y" for read only +-- 2. user_name (sysname or NVARCHAR(128)) - The current database user +CREATE OR REPLACE PROCEDURE sys.sp_oledb_ro_usrname() +LANGUAGE 'pltsql' +AS $$ +BEGIN + SELECT CAST((SELECT CASE WHEN pg_is_in_recovery() = 'f' THEN 'N' ELSE 'Y' END) AS VARCHAR(1)) RO, CAST(current_user as NVARCHAR(128)); +END ; +$$; + +CREATE OR REPLACE PROCEDURE sys.sp_helpdb() +LANGUAGE 'pltsql' +AS $$ +BEGIN + SELECT + CAST(name AS sys.nvarchar(128)), + CAST(db_size AS sys.nvarchar(13)), + CAST(owner AS sys.nvarchar(128)), + CAST(dbid AS sys.int), + CAST(created AS sys.nvarchar(11)), + CAST(status AS sys.nvarchar(600)), + CAST(compatibility_level AS sys.tinyint) + FROM sys.babelfish_helpdb(); + + RETURN 0; +END; +$$; + +CREATE OR REPLACE PROCEDURE sys.sp_helpdb(IN "@dbname" VARCHAR(32)) +LANGUAGE 'pltsql' +AS $$ +BEGIN + SELECT + CAST(name AS sys.nvarchar(128)), + CAST(db_size AS sys.nvarchar(13)), + CAST(owner AS sys.nvarchar(128)), + CAST(dbid AS sys.int), + CAST(created AS sys.nvarchar(11)), + CAST(status AS sys.nvarchar(600)), + CAST(compatibility_level AS sys.tinyint) + FROM sys.babelfish_helpdb("@dbname"); + + SELECT + CAST(NULL AS sys.nchar(128)) AS name, + CAST(NULL AS smallint) AS fileid, + CAST(NULL AS sys.nchar(260)) AS filename, + CAST(NULL AS sys.nvarchar(128)) AS filegroup, + CAST(NULL AS sys.nvarchar(18)) AS size, + CAST(NULL AS sys.nvarchar(18)) AS maxsize, + CAST(NULL AS sys.nvarchar(18)) AS growth, + CAST(NULL AS sys.varchar(9)) AS usage; + + RETURN 0; +END; +$$; + +-- BABEL-1643 +CREATE TABLE sys.spt_datatype_info_table +(TYPE_NAME VARCHAR(20), DATA_TYPE INT, PRECISION BIGINT, +LITERAL_PREFIX VARCHAR(20), LITERAL_SUFFIX VARCHAR(20), +CREATE_PARAMS CHAR(20), NULLABLE INT, CASE_SENSITIVE INT, +SEARCHABLE INT, UNSIGNED_ATTRIBUTE INT, MONEY INT, +AUTO_INCREMENT INT, LOCAL_TYPE_NAME VARCHAR(20), +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 SYS.TINYINT, +-- below column is added in order to join PG's information_schema.columns for sys.sp_columns_100_view +PG_TYPE_NAME VARCHAR(20) +); +GRANT SELECT ON sys.spt_datatype_info_table TO PUBLIC; + +INSERT INTO sys.spt_datatype_info_table VALUES (N'datetimeoffset', -155, 34, N'''', N'''', N'scale ', 1, 0, 3, NULL, 0, NULL, N'datetimeoffset', 0, 7, -155, 0, NULL, NULL, 0, 68, 0, 'datetimeoffset'); +INSERT INTO sys.spt_datatype_info_table VALUES (N'time', -154, 16, N'''', N'''', N'scale ', 1, 0, 3, NULL, 0, NULL, N'time', 0, 7, -154, 0, NULL, NULL, 0, 32, 0, 'time'); +INSERT INTO sys.spt_datatype_info_table VALUES (N'xml', -152, 0, N'N''', N'''', NULL, 1, 1, 0, NULL, 0, NULL, N'xml', NULL, NULL, -152, NULL, NULL, NULL, 0, 2147483646, 0, N'xml'); +INSERT INTO sys.spt_datatype_info_table VALUES (N'sql_variant', -150, 8000, NULL, NULL, NULL, 1, 0, 2, NULL, 0, NULL, N'sql_variant', 0, 0, -150, NULL, 10, NULL, 0, 8000, 39, 'sql_variant'); +INSERT INTO sys.spt_datatype_info_table VALUES (N'uniqueidentifier', -11, 36, N'''', N'''', NULL, 1, 0, 2, NULL, 0, NULL, N'uniqueidentifier', NULL, NULL, -11, NULL, NULL, NULL, 0, 16, 37, 'uniqueidentifier'); +INSERT INTO sys.spt_datatype_info_table VALUES (N'ntext', -10, 1073741823, N'N''', N'''', NULL, 1, 1, 1, NULL, 0, NULL, N'ntext', NULL, NULL, -10, NULL, NULL, NULL, 0, 2147483646, 35, NULL); +INSERT INTO sys.spt_datatype_info_table VALUES (N'nvarchar', -9, 4000, N'N''', N'''', N'max length ', 1, 1, 3, NULL, 0, NULL, N'nvarchar', NULL, NULL, -9, NULL, NULL, NULL, 0, 2, 39, NULL); +INSERT INTO sys.spt_datatype_info_table VALUES (N'sysname', -9, 128, N'N''', N'''', NULL, 0, 1, 3, NULL, 0, NULL, N'sysname', NULL, NULL, -9, NULL, NULL, NULL, 18, 256, 39, NULL); +INSERT INTO sys.spt_datatype_info_table VALUES (N'nchar', -8, 4000, N'N''', N'''', N'length ', 1, 1, 3, NULL, 0, NULL, N'nchar', NULL, NULL, -8, NULL, NULL, NULL, 0, 2, 39, NULL); +INSERT INTO sys.spt_datatype_info_table VALUES (N'bit', -7, 1, NULL, NULL, NULL, 1, 0, 2, NULL, 0, NULL, N'bit', 0, 0, -7, NULL, NULL, NULL, 16, 1, 50, 'bit'); +INSERT INTO sys.spt_datatype_info_table VALUES (N'tinyint', -6, 3, NULL, NULL, NULL, 1, 0, 2, 1, 0, 0, N'tinyint', 0, 0, -6, NULL, 10, NULL, 5, 1, 38, NULL); +INSERT INTO sys.spt_datatype_info_table VALUES (N'tinyint identity', -6, 3, NULL, NULL, NULL, 0, 0, 2, 1, 0, 1, N'tinyint identity', 0, 0, -6, NULL, 10, NULL, 5, 1, 38, NULL); +INSERT INTO sys.spt_datatype_info_table VALUES (N'bigint', -5, 19, NULL, NULL, NULL, 1, 0, 2, 0, 0, 0, N'bigint', 0, 0, -5, NULL, 10, NULL, 0, 8, 108, 'int8'); +INSERT INTO sys.spt_datatype_info_table VALUES (N'bigint identity', -5, 19, NULL, NULL, NULL, 0, 0, 2, 0, 0, 1, N'bigint identity', 0, 0, -5, NULL, 10, NULL, 0, 8, 108, NULL); +INSERT INTO sys.spt_datatype_info_table VALUES (N'image', -4, 2147483647, N'0x', NULL, NULL, 1, 0, 0, NULL, 0, NULL, N'image', NULL, NULL, -4, NULL, NULL, NULL, 20, 2147483647, 34, NULL); +INSERT INTO sys.spt_datatype_info_table VALUES (N'varbinary', -3, 8000, N'0x', NULL, N'max length ', 1, 0, 2, NULL, 0, NULL, N'varbinary', NULL, NULL, -3, NULL, NULL, NULL, 4, 1, 37, NULL); +INSERT INTO sys.spt_datatype_info_table VALUES (N'binary', -2, 8000, N'0x', NULL, N'length ', 1, 0, 2, NULL, 0, NULL, N'binary', NULL, NULL, -2, NULL, NULL, NULL, 3, 1, 37, NULL); +INSERT INTO sys.spt_datatype_info_table VALUES (N'timestamp', -2, 8, N'0x', NULL, NULL, 0, 0, 2, NULL, 0, NULL, N'timestamp', NULL, NULL, -2, NULL, NULL, NULL, 80, 8, 45, 'timestamp'); +INSERT INTO sys.spt_datatype_info_table VALUES (N'text', -1, 2147483647, N'''', N'''', NULL, 1, 1, 1, NULL, 0, NULL, N'text', NULL, NULL, -1, NULL, NULL, NULL, 19, 2147483647, 35, NULL); +INSERT INTO sys.spt_datatype_info_table VALUES (N'char', 1, 8000, N'''', N'''', N'length ', 1, 1, 3, NULL, 0, NULL, N'char', NULL, NULL, 1, NULL, NULL, NULL, 1, 1, 39, N'bpchar'); +INSERT INTO sys.spt_datatype_info_table VALUES (N'numeric', 2, 38, NULL, NULL, N'precision,scale ', 1, 0, 2, 0, 0, 0, N'numeric', 0, 38, 2, NULL, 10, NULL, 10, 20, 108, 'numeric'); +INSERT INTO sys.spt_datatype_info_table VALUES (N'numeric() identity', 2, 38, NULL, NULL, N'precision ', 0, 0, 2, 0, 0, 1, N'numeric() identity', 0, 0, 2, NULL, 10, NULL, 10, 20, 108, NULL); +INSERT INTO sys.spt_datatype_info_table VALUES (N'decimal', 3, 38, NULL, NULL, N'precision,scale ', 1, 0, 2, 0, 0, 0, N'decimal', 0, 38, 3, NULL, 10, NULL, 24, 20, 106, NULL); +INSERT INTO sys.spt_datatype_info_table VALUES (N'money', 3, 19, N'$', NULL, NULL, 1, 0, 2, 0, 1, 0, N'money', 4, 4, 3, NULL, 10, NULL, 11, 21, 110, NULL); +INSERT INTO sys.spt_datatype_info_table VALUES (N'smallmoney', 3, 10, N'$', NULL, NULL, 1, 0, 2, 0, 1, 0, N'smallmoney', 4, 4, 3, NULL, 10, NULL, 21, 12, 110, NULL); +INSERT INTO sys.spt_datatype_info_table VALUES (N'decimal() identity', 3, 38, NULL, NULL, N'precision ', 0, 0, 2, 0, 0, 1, N'decimal() identity', 0, 0, 3, NULL, 10, NULL, 24, 20, 106, NULL); +INSERT INTO sys.spt_datatype_info_table VALUES (N'int', 4, 10, NULL, NULL, NULL, 1, 0, 2, 0, 0, 0, N'int', 0, 0, 4, NULL, 10, NULL, 7, 4, 38, N'int4'); +INSERT INTO sys.spt_datatype_info_table VALUES (N'int identity', 4, 10, NULL, NULL, NULL, 0, 0, 2, 0, 0, 1, N'int identity', 0, 0, 4, NULL, 10, NULL, 7, 4, 38, N''); +INSERT INTO sys.spt_datatype_info_table VALUES (N'smallint', 5, 5, NULL, NULL, NULL, 1, 0, 2, 0, 0, 0, N'smallint', 0, 0, 5, NULL, 10, NULL, 6, 2, 38, 'int2'); +INSERT INTO sys.spt_datatype_info_table VALUES (N'smallint identity', 5, 5, NULL, NULL, NULL, 0, 0, 2, 0, 0, 1, N'smallint identity', 0, 0, 5, NULL, 10, NULL, 6, 2, 38, NULL); +INSERT INTO sys.spt_datatype_info_table VALUES (N'float', 6, 53, NULL, NULL, NULL, 1, 0, 2, 0, 0, 0, N'float', NULL, NULL, 6, NULL, 2, NULL, 8, 8, 109, 'float8'); +INSERT INTO sys.spt_datatype_info_table VALUES (N'real', 7, 24, NULL, NULL, NULL, 1, 0, 2, 0, 0, 0, N'real', NULL, NULL, 7, NULL, 2, NULL, 23, 4, 109, 'float4'); +INSERT INTO sys.spt_datatype_info_table VALUES (N'varchar', 12, 8000, N'''', N'''', N'max length ', 1, 1, 3, NULL, 0, NULL, N'varchar', NULL, NULL, 12, NULL, NULL, NULL, 2, 1, 39, NULL); +INSERT INTO sys.spt_datatype_info_table VALUES (N'date', 91, 10, N'''', N'''', NULL, 1, 0, 3, NULL, 0, NULL, N'date', NULL, 0, 9, 1, NULL, NULL, 0, 20, 0, 'date'); +INSERT INTO sys.spt_datatype_info_table VALUES (N'datetime2', 93, 27, N'''', N'''', N'scale ', 1, 0, 3, NULL, 0, NULL, N'datetime2', 0, 7, 9, 3, NULL, NULL, 0, 54, 0, 'datetime2'); +INSERT INTO sys.spt_datatype_info_table VALUES (N'datetime', 93, 23, N'''', N'''', NULL, 1, 0, 3, NULL, 0, NULL, N'datetime', 3, 3, 9, 3, NULL, NULL, 12, 16, 111, 'datetime'); +INSERT INTO sys.spt_datatype_info_table VALUES (N'smalldatetime', 93, 16, N'''', N'''', NULL, 1, 0, 3, NULL, 0, NULL, N'smalldatetime', 0, 0, 9, 3, NULL, NULL, 22, 16, 111, 'smalldatetime'); + +-- ODBCVer ignored for now +CREATE OR REPLACE PROCEDURE sys.sp_datatype_info ( + "@data_type" int = 0, + "@odbcver" smallint = 2) +AS $$ +BEGIN + select TYPE_NAME, DATA_TYPE, PRECISION, LITERAL_PREFIX, LITERAL_SUFFIX, + CREATE_PARAMS, NULLABLE, CASE_SENSITIVE, SEARCHABLE, + UNSIGNED_ATTRIBUTE, MONEY, AUTO_INCREMENT, LOCAL_TYPE_NAME, + MINIMUM_SCALE, MAXIMUM_SCALE, SQL_DATA_TYPE, SQL_DATETIME_SUB, + NUM_PREC_RADIX, INTERVAL_PRECISION, USERTYPE + from sys.spt_datatype_info_table where @data_type = 0 or data_type = @data_type; +END; +$$ +LANGUAGE 'pltsql'; +-- same as sp_datatype_info +CREATE OR REPLACE PROCEDURE sys.sp_datatype_info_100 ( + "@data_type" int = 0, + "@odbcver" smallint = 2) +AS $$ +BEGIN + select TYPE_NAME, DATA_TYPE, PRECISION, LITERAL_PREFIX, LITERAL_SUFFIX, + CREATE_PARAMS, NULLABLE, CASE_SENSITIVE, SEARCHABLE, + UNSIGNED_ATTRIBUTE, MONEY, AUTO_INCREMENT, LOCAL_TYPE_NAME, + MINIMUM_SCALE, MAXIMUM_SCALE, SQL_DATA_TYPE, SQL_DATETIME_SUB, + NUM_PREC_RADIX, INTERVAL_PRECISION, USERTYPE + from sys.spt_datatype_info_table where @data_type = 0 or data_type = @data_type; +END; +$$ +LANGUAGE 'pltsql'; + + +-- BABEL-1784: support for sp_columns/sp_columns_100 +CREATE VIEW sys.sp_columns_100_view AS +SELECT +CAST(t2.dbname AS sys.sysname) AS TABLE_QUALIFIER, +CAST(t3.rolname 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(t5.data_type AS smallint) AS DATA_TYPE, +CAST(t5.type_name AS sys.sysname) AS TYPE_NAME, +CAST(t4.numeric_precision AS INT) AS PRECISION, +CAST(t5.length AS int) AS LENGTH, +CAST(t4.numeric_scale AS smallint) AS SCALE, +CAST(t4.numeric_precision_radix 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, +CAST(t4.character_octet_length AS int) AS CHAR_OCTET_LENGTH, +CAST(t4.dtd_identifier 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, +case + when t4.is_generated = 'NEVER' then CAST(0 AS smallint) + else CAST(1 AS smallint) +end AS SS_IS_COMPUTED, +case + when t4.is_identity = 'YES' then CAST(1 AS smallint) + else CAST(0 AS smallint) +end 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 + JOIN information_schema.columns t4 ON t1.relname = t4.table_name, + sys.spt_datatype_info_table AS t5 +WHERE (t4.data_type = t5.pg_type_name + OR ((SELECT coalesce(t4.domain_name, '') != 'tinyint') AND (SELECT coalesce(t4.domain_name, '') != 'nchar') AND t5.pg_type_name = t4.udt_name) + OR (t4.domain_schema = 'sys' AND t5.type_name = t4.domain_name)); +GRANT SELECT on sys.sp_columns_100_view TO PUBLIC; + +-- internal function in order to workaround BABEL-1597 for BABEL-1784 +drop function if exists sys.sp_columns_100_internal( + in_table_name sys.nvarchar(384), + in_table_owner sys.nvarchar(384), + in_table_qualifier sys.nvarchar(384), + in_column_name sys.nvarchar(384), + in_NameScope int, + in_ODBCVer int, + in_fusepattern smallint); +create function sys.sp_columns_100_internal( + in_table_name sys.nvarchar(384), + in_table_owner sys.nvarchar(384) = '', + in_table_qualifier sys.nvarchar(384) = '', + in_column_name sys.nvarchar(384) = '', + in_NameScope int = 0, + in_ODBCVer int = 2, + in_fusepattern smallint = 1) +returns table ( + out_table_qualifier sys.sysname, + out_table_owner sys.sysname, + out_table_name sys.sysname, + out_column_name sys.sysname, + out_data_type smallint, + out_type_name sys.sysname, + out_precision int, + out_length int, + out_scale smallint, + out_radix smallint, + out_nullable smallint, + out_remarks varchar(254), + out_column_def sys.nvarchar(4000), + out_sql_data_type smallint, + out_sql_datetime_sub smallint, + out_char_octet_length int, + out_ordinal_position int, + out_is_nullable varchar(254), + out_ss_is_sparse smallint, + out_ss_is_column_set smallint, + out_ss_is_computed smallint, + out_ss_is_identity smallint, + out_ss_udt_catalog_name varchar(254), + out_ss_udt_schema_name varchar(254), + out_ss_udt_assembly_type_name varchar(254), + out_ss_xml_schemacollection_catalog_name varchar(254), + out_ss_xml_schemacollection_schema_name varchar(254), + out_ss_xml_schemacollection_name varchar(254), + out_ss_data_type sys.tinyint +) +as $$ +begin + IF in_fusepattern = 1 THEN + return query + select table_qualifier, + table_owner, + table_name, + column_name, + data_type, + type_name, + precision, + length, + scale, + radix, + nullable, + remarks, + column_def, + sql_data_type, + sql_datetime_sub, + char_octet_length, + ordinal_position, + is_nullable, + ss_is_sparse, + ss_is_column_set, + ss_is_computed, + ss_is_identity, + ss_udt_catalog_name, + ss_udt_schema_name, + ss_udt_assembly_type_name, + ss_xml_schemacollection_catalog_name, + ss_xml_schemacollection_schema_name, + ss_xml_schemacollection_name, + ss_data_type + from sys.sp_columns_100_view + where table_name like in_table_name + and ((SELECT coalesce(in_table_owner,'')) = '' or table_owner like in_table_owner) + and ((SELECT coalesce(in_table_qualifier,'')) = '' or table_qualifier like in_table_qualifier) + and ((SELECT coalesce(in_column_name,'')) = '' or column_name like in_column_name) + order by table_qualifier, table_owner, table_name; + ELSE + return query + select table_qualifier, precision from sys.sp_columns_100_view + where in_table_name = table_name + and ((SELECT coalesce(in_table_owner,'')) = '' or table_owner = in_table_owner) + and ((SELECT coalesce(in_table_qualifier,'')) = '' or table_qualifier = in_table_qualifier) + and ((SELECT coalesce(in_column_name,'')) = '' or column_name = in_column_name) + order by table_qualifier, table_owner, table_name; + END IF; +end; +$$ +LANGUAGE plpgsql; + +CREATE OR REPLACE PROCEDURE sys.sp_columns ( + "@table_name" sys.nvarchar(384), + "@table_owner" sys.nvarchar(384) = '', + "@table_qualifier" sys.nvarchar(384) = '', + "@column_name" sys.nvarchar(384) = '', + "@namescope" int = 0, + "@odbcver" int = 2, + "@fusepattern" smallint = 1) +AS $$ +BEGIN + select out_table_qualifier as table_qualifier, + out_table_owner as table_owner, + out_table_name as table_name, + out_column_name as column_name, + out_data_type as data_type, + out_type_name as type_name, + out_precision as precision, + out_length as length, + out_scale as scale, + out_radix as radix, + out_nullable as nullable, + out_remarks as remarks, + out_column_def as column_def, + out_sql_data_type as sql_data_type, + out_sql_datetime_sub as sql_datetime_sub, + out_char_octet_length as char_octet_length, + out_ordinal_position as ordinal_position, + out_is_nullable as is_nullable, + out_ss_data_type as ss_data_type + from sys.sp_columns_100_internal(@table_name, @table_owner,@table_qualifier, @column_name, @NameScope,@ODBCVer, @fusepattern); +END; +$$ +LANGUAGE 'pltsql'; +GRANT ALL on PROCEDURE sys.sp_columns TO PUBLIC; + +CREATE OR REPLACE PROCEDURE sys.sp_columns_100 ( + "@table_name" sys.nvarchar(384), + "@table_owner" sys.nvarchar(384) = '', + "@table_qualifier" sys.nvarchar(384) = '', + "@column_name" sys.nvarchar(384) = '', + "@namescope" int = 0, + "@odbcver" int = 2, + "@fusepattern" smallint = 1) +AS $$ +BEGIN + select out_table_qualifier as table_qualifier, + out_table_owner as table_owner, + out_table_name as table_name, + out_column_name as column_name, + out_data_type as data_type, + out_type_name as type_name, + out_precision as precision, + out_length as length, + out_scale as scale, + out_radix as radix, + out_nullable as nullable, + out_remarks as remarks, + out_column_def as column_def, + out_sql_data_type as sql_data_type, + out_sql_datetime_sub as sql_datetime_sub, + out_char_octet_length as char_octet_length, + out_ordinal_position as ordinal_position, + out_is_nullable as is_nullable, + out_ss_is_sparse as ss_is_sparse, + out_ss_is_column_set as ss_is_column_set, + out_ss_is_computed as ss_is_computed, + out_ss_is_identity as ss_is_identity, + out_ss_udt_catalog_name as ss_udt_catalog_name, + out_ss_udt_schema_name as ss_udt_schema_name, + out_ss_udt_assembly_type_name as ss_udt_assembly_type_name, + out_ss_xml_schemacollection_catalog_name as ss_xml_schemacollection_catalog_name, + out_ss_xml_schemacollection_schema_name as ss_xml_schemacollection_schema_name, + out_ss_xml_schemacollection_name as ss_xml_schemacollection_name, + out_ss_data_type as ss_data_type + from sys.sp_columns_100_internal(@table_name, @table_owner,@table_qualifier, @column_name, @NameScope,@ODBCVer, @fusepattern); +END; +$$ +LANGUAGE 'pltsql'; +GRANT ALL on PROCEDURE sys.sp_columns_100 TO PUBLIC; + +-- BABEL-1785: initial support of sp_describe_first_result_set +-- sys.sp_describe_first_result_set_internal: internal function +-- used to workaround BABEL-1597 +create function sys.sp_describe_first_result_set_internal( + tsqlquery varchar(384), + params varchar(384) = NULL, + browseMode sys.tinyint = 0 +) +returns table ( + is_hidden sys.bit, + column_ordinal int, + name sys.sysname, + is_nullable sys.bit, + system_type_id int, + system_type_name sys.nvarchar(256), + max_length smallint, + "precision" sys.tinyint, + scale sys.tinyint, + collation_name sys.sysname, + user_type_id int, + user_type_database sys.sysname, + user_type_schema sys.sysname, + user_type_name sys.sysname, + assembly_qualified_type_name sys.nvarchar(4000), + xml_collection_id int, + xml_collection_database sys.sysname, + xml_collection_schema sys.sysname, + xml_collection_name sys.sysname, + is_xml_document sys.bit, + is_case_sensitive sys.bit, + is_fixed_length_clr_type sys.bit, + source_server sys.sysname, + source_database sys.sysname, + source_schema sys.sysname, + source_table sys.sysname, + source_column sys.sysname, + is_identity_column sys.bit, + is_part_of_unique_key sys.bit, + is_updateable sys.bit, + is_computed_column sys.bit, + is_sparse_column_set sys.bit, + ordinal_in_order_by_list smallint, + order_by_list_length smallint, + order_by_is_descending smallint, + tds_type_id int, + tds_length int, + tds_collation_id int, + ss_data_type sys.tinyint +) +as $$ + declare _args text[]; -- placeholder: parse @params and feed the tsqlquery +begin + IF tsqlquery ILIKE 'select %' THEN + DROP VIEW IF EXISTS sp_describe_first_result_set_view; + EXECUTE 'create temp view sp_describe_first_result_set_view as ' || tsqlquery USING _args; + RETURN query + SELECT + CAST(0 AS sys.bit) AS is_hidden, + CAST(t1.dtd_identifier AS int) AS column_ordinal, + CAST(t1.column_name AS sys.sysname) AS name, + case + when t1.is_nullable = 'Y' then CAST(1 AS sys.bit) + else CAST(0 AS sys.bit) + end as is_nullable, + 0 as system_type_id, + CAST('' as sys.nvarchar(256)) as system_type_name, + CAST(t2.length AS smallint) AS max_length, + CAST(t1.numeric_precision AS sys.tinyint) AS precision, + CAST(t1.numeric_scale AS sys.tinyint) AS scale, + CAST((SELECT coalesce(t1.collation_name, '')) AS sys.sysname) as collation_name, + CAST(NULL as int) as user_type_id, + CAST('' as sys.sysname) as user_type_database, + CAST('' as sys.sysname) as user_type_schema, + CAST('' as sys.sysname) as user_type_name, + CAST('' as sys.nvarchar(4000)) as assembly_qualified_type_name, + CAST(NULL as int) as xml_collection_id, + CAST('' as sys.sysname) as xml_collection_database, + CAST('' as sys.sysname) as xml_collection_schema, + CAST('' as sys.sysname) as xml_collection_name, + case + when t1.data_type = 'xml' then CAST(1 AS sys.bit) + else CAST(0 AS sys.bit) + end as is_xml_document, + case + when t1.udt_name = 'citext' then CAST(0 AS sys.bit) + else CAST(1 AS sys.bit) + end as is_case_sensitive, + CAST(0 as sys.bit) as is_fixed_length_clr_type, + CAST('' as sys.sysname) as source_server, + CAST('' as sys.sysname) as source_database, + CAST('' as sys.sysname) as source_schema, + CAST('' as sys.sysname) as source_table, + CAST('' as sys.sysname) as source_column, + case + when t1.is_identity = '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 = 'YES' then CAST(1 AS sys.bit) + else CAST(0 AS sys.bit) + end as is_updateable, + case + when t1.is_generated = '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(NULL as int) as tds_type_id, + CAST(NULL as int) as tds_length, + CAST(NULL as int) as tds_collation_id, + CAST(1 AS sys.tinyint) AS tds_collation_sort_id + FROM information_schema.columns t1, sys.spt_datatype_info_table t2 + WHERE table_name = 'sp_describe_first_result_set_view' + AND (t1.data_type = t2.pg_type_name + OR ((SELECT coalesce(t1.domain_name, '') != 'tinyint') + AND (SELECT coalesce(t1.domain_name, '') != 'nchar') + AND t2.pg_type_name = t1.udt_name) + OR (t1.domain_schema = 'sys' AND t2.type_name = t1.domain_name)); + DROP VIEW sp_describe_first_result_set_view; + END IF; +end; +$$ +LANGUAGE plpgsql; +GRANT ALL on FUNCTION sys.sp_describe_first_result_set_internal TO PUBLIC; + +CREATE PROCEDURE sys.sp_describe_first_result_set ( + "@tsql" varchar(384), + "@params" varchar(384) = NULL, + "@browse_information_mode" sys.tinyint = 0) +AS $$ +BEGIN + select * from sys.sp_describe_first_result_set_internal(@tsql, @params, @browse_information_mode); +END; +$$ +LANGUAGE 'pltsql'; +GRANT ALL on PROCEDURE sys.sp_describe_first_result_set 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, + c.name 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) + WHERE + c.is_sparse = 0; +GRANT SELECT ON sys.spt_tablecollations_view TO PUBLIC; + +-- We are limited by what postgres procedures can return here, but IEW may not +-- need it for initial compatibility +CREATE OR REPLACE PROCEDURE sys.sp_tablecollations_100 +( + IN "@object" nvarchar(4000) +) +AS $$ +BEGIN + select + s_tcv.colid AS colid, + s_tcv.name AS name, + s_tcv.tds_collation_100 AS tds_collation_100, + s_tcv.collation_100 AS collation + from + sys.spt_tablecollations_view s_tcv + where + s_tcv.object_id = sys.object_id("@object") AND + s_tcv.name NOT IN ('cmin', 'cmax', 'xmin', 'xmax', 'ctid', 'tableoid') + order by colid; +END; +$$ +LANGUAGE 'pltsql'; + +CREATE VIEW sys.spt_columns_view_managed AS +SELECT + o.object_id AS OBJECT_ID, + isc.table_catalog AS TABLE_CATALOG, + isc.table_schema AS TABLE_SCHEMA, + o.name AS TABLE_NAME, + c.name AS COLUMN_NAME, + isc.ordinal_position AS ORDINAL_POSITION, + isc.column_default AS COLUMN_DEFAULT, + isc.is_nullable AS IS_NULLABLE, + isc.data_type AS DATA_TYPE, + isc.character_maximum_length AS CHARACTER_MAXIMUM_LENGTH, + isc.character_octet_length AS CHARACTER_OCTET_LENGTH, + isc.numeric_precision AS NUMERIC_PRECISION, + isc.numeric_precision_radix AS NUMERIC_PRECISION_RADIX, + isc.numeric_scale AS NUMERIC_SCALE, + isc.datetime_precision AS DATETIME_PRECISION, + isc.character_set_catalog AS CHARACTER_SET_CATALOG, + isc.character_set_schema AS CHARACTER_SET_SCHEMA, + isc.character_set_name AS CHARACTER_SET_NAME, + isc.collation_catalog AS COLLATION_CATALOG, + isc.collation_schema AS COLLATION_SCHEMA, + c.collation_name AS COLLATION_NAME, + isc.domain_catalog AS DOMAIN_CATALOG, + isc.domain_schema AS DOMAIN_SCHEMA, + isc.domain_name AS DOMAIN_NAME, + c.is_sparse AS IS_SPARSE, + c.is_column_set AS IS_COLUMN_SET, + c.is_filestream AS IS_FILESTREAM +FROM + sys.objects o JOIN sys.columns c ON + ( + c.object_id = o.object_id and + o.type in ('U', 'V') -- limit columns to tables and views + ) + LEFT JOIN information_schema.columns isc ON + ( + sys.schema_name(o.schema_id) = isc.table_schema and + o.name = isc.table_name and + c.name = isc.column_name + ) + WHERE CAST(column_name AS sys.nvarchar(128)) NOT IN ('cmin', 'cmax', 'xmin', 'xmax', 'ctid', 'tableoid'); + +CREATE FUNCTION sys.sp_columns_managed_internal( + in_catalog sys.nvarchar(128), + in_owner sys.nvarchar(128), + in_table sys.nvarchar(128), + in_column sys.nvarchar(128), + in_schematype int) +RETURNS TABLE ( + out_table_catalog sys.nvarchar(128), + out_table_schema sys.nvarchar(128), + out_table_name sys.nvarchar(128), + out_column_name sys.nvarchar(128), + out_ordinal_position int, + out_column_default sys.nvarchar(4000), + out_is_nullable sys.nvarchar(3), + out_data_type sys.nvarchar, + out_character_maximum_length int, + out_character_octet_length int, + out_numeric_precision int, + out_numeric_precision_radix int, + out_numeric_scale int, + out_datetime_precision int, + out_character_set_catalog sys.nvarchar(128), + out_character_set_schema sys.nvarchar(128), + out_character_set_name sys.nvarchar(128), + out_collation_catalog sys.nvarchar(128), + out_is_sparse int, + out_is_column_set int, + out_is_filestream int + ) +AS +$$ +BEGIN + RETURN QUERY + SELECT CAST(table_catalog AS sys.nvarchar(128)), + CAST(table_schema AS sys.nvarchar(128)), + CAST(table_name AS sys.nvarchar(128)), + CAST(column_name AS sys.nvarchar(128)), + CAST(ordinal_position AS int), + CAST(column_default AS sys.nvarchar(4000)), + CAST(is_nullable AS sys.nvarchar(3)), + CAST(data_type AS sys.nvarchar), + CAST(character_maximum_length AS int), + CAST(character_octet_length AS int), + CAST(numeric_precision AS int), + CAST(numeric_precision_radix AS int), + CAST(numeric_scale AS int), + CAST(datetime_precision AS int), + CAST(character_set_catalog AS sys.nvarchar(128)), + CAST(character_set_schema AS sys.nvarchar(128)), + CAST(character_set_name AS sys.nvarchar(128)), + CAST(collation_catalog AS sys.nvarchar(128)), + CAST(is_sparse AS int), + CAST(is_column_set AS int), + CAST(is_filestream AS int) + FROM sys.spt_columns_view_managed s_cv + WHERE + (in_catalog IS NULL OR s_cv.TABLE_CATALOG LIKE in_catalog) AND + (in_owner IS NULL OR s_cv.TABLE_SCHEMA LIKE in_owner) AND + (in_table IS NULL OR s_cv.TABLE_NAME LIKE in_table) AND + (in_column IS NULL OR s_cv.COLUMN_NAME LIKE in_column) AND + (in_schematype = 0 AND (s_cv.IS_SPARSE = 0) OR in_schematype = 1 OR in_schematype = 2 AND (s_cv.IS_SPARSE = 1)); +END; +$$ +language plpgsql; + +CREATE PROCEDURE sys.sp_columns_managed +( + "@Catalog" nvarchar(128) = NULL, + "@Owner" nvarchar(128) = NULL, + "@Table" nvarchar(128) = NULL, + "@Column" nvarchar(128) = NULL, + "@SchemaType" nvarchar(128) = 0) -- 0 = 'select *' behavior (default), 1 = all columns, 2 = columnset columns +AS +$$ +BEGIN + SELECT + out_TABLE_CATALOG AS TABLE_CATALOG, + out_TABLE_SCHEMA AS TABLE_SCHEMA, + out_TABLE_NAME AS TABLE_NAME, + out_COLUMN_NAME AS COLUMN_NAME, + out_ORDINAL_POSITION AS ORDINAL_POSITION, + out_COLUMN_DEFAULT AS COLUMN_DEFAULT, + out_IS_NULLABLE AS IS_NULLABLE, + out_DATA_TYPE AS DATA_TYPE, + out_CHARACTER_MAXIMUM_LENGTH AS CHARACTER_MAXIMUM_LENGTH, + out_CHARACTER_OCTET_LENGTH AS CHARACTER_OCTET_LENGTH, + out_NUMERIC_PRECISION AS NUMERIC_PRECISION, + out_NUMERIC_PRECISION_RADIX AS NUMERIC_PRECISION_RADIX, + out_NUMERIC_SCALE AS NUMERIC_SCALE, + out_DATETIME_PRECISION AS DATETIME_PRECISION, + out_CHARACTER_SET_CATALOG AS CHARACTER_SET_CATALOG, + out_CHARACTER_SET_SCHEMA AS CHARACTER_SET_SCHEMA, + out_CHARACTER_SET_NAME AS CHARACTER_SET_NAME, + out_COLLATION_CATALOG AS COLLATION_CATALOG, + out_IS_SPARSE AS IS_SPARSE, + out_IS_COLUMN_SET AS IS_COLUMN_SET, + out_IS_FILESTREAM AS IS_FILESTREAM + FROM + sys.sp_columns_managed_internal(@Catalog, @Owner, "@Table", "@Column", @SchemaType) s_cv + ORDER BY TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME, IS_NULLABLE; +END; +$$ +LANGUAGE 'pltsql'; +GRANT ALL on PROCEDURE sys.sp_columns_managed TO PUBLIC; + +-- BABEL-1797: initial support of sp_describe_undeclared_parameters +-- sys.sp_describe_undeclared_parameters_internal: internal function +-- For the result rows, can we create a template table for it? +create function sys.sp_describe_undeclared_parameters_internal( + tsqlquery varchar(384), + params varchar(384) = NULL +) +returns table ( + parameter_ordinal int, -- NOT NULL + name sys.sysname, -- NOT NULL + suggested_system_type_id int, -- NOT NULL + suggested_system_type_name sys.nvarchar(256), + suggested_max_length smallint, -- NOT NULL + suggested_precision sys.tinyint, -- NOT NULL + suggested_scale sys.tinyint, -- NOT NULL + suggested_user_type_id int, -- NOT NULL + suggested_user_type_database sys.sysname, + suggested_user_type_schema sys.sysname, + suggested_user_type_name sys.sysname, + suggested_assembly_qualified_type_name sys.nvarchar(4000), + suggested_xml_collection_id int, + suggested_xml_collection_database sys.sysname, + suggested_xml_collection_schema sys.sysname, + suggested_xml_collection_name sys.sysname, + suggested_is_xml_document sys.bit, -- NOT NULL + suggested_is_case_sensitive sys.bit, -- NOT NULL + suggested_is_fixed_length_clr_type sys.bit, -- NOT NULL + suggested_is_input sys.bit, -- NOT NULL + suggested_is_output sys.bit, -- NOT NULL + formal_parameter_name sys.sysname, + suggested_tds_type_id int, -- NOT NULL + suggested_tds_length int -- NOT NULL +) +AS 'babelfishpg_tsql', 'sp_describe_undeclared_parameters_internal' +LANGUAGE C; +GRANT ALL on FUNCTION sys.sp_describe_undeclared_parameters_internal TO PUBLIC; + +CREATE PROCEDURE sys.sp_describe_undeclared_parameters ( + "@tsql" varchar(384), + "@params" varchar(384) = NULL) +AS $$ +BEGIN + select * from sys.sp_describe_undeclared_parameters_internal(@tsql, @params); + return 1; +END; +$$ +LANGUAGE 'pltsql'; +GRANT ALL on PROCEDURE sys.sp_describe_undeclared_parameters TO PUBLIC; + +-- BABEL-1782 +CREATE VIEW sys.sp_tables_view AS +SELECT +t2.dbname AS TABLE_QUALIFIER, +t3.rolname AS TABLE_OWNER, +t1.relname AS TABLE_NAME, +case + when t1.relkind = 'v' then 'VIEW' + else 'TABLE' +end AS TABLE_TYPE, +CAST(NULL AS varchar(254)) AS remarks +FROM pg_catalog.pg_class AS t1, sys.pg_namespace_ext AS t2, pg_catalog.pg_roles AS t3 +WHERE t1.relowner = t3.oid AND t1.relnamespace = t2.oid; +GRANT SELECT on sys.sp_tables_view TO PUBLIC; + +CREATE OR REPLACE PROCEDURE sys.sp_tables ( + "@table_name" sys.nvarchar(384), + "@table_owner" sys.nvarchar(384) = '', + "@table_qualifier" sys.sysname = '', + "@table_type" sys.nvarchar(100) = '', + "@fusepattern" sys.bit = '1') +AS $$ +BEGIN + DECLARE @_opt_view varchar(16) = '' + DECLARE @_opt_table varchar(16) = '' + IF (select count(*) from STRING_SPLIT(@table_type, ',') where trim(value) = 'VIEW') = 1 + BEGIN + SET @_opt_view = 'VIEW' + END + IF (select count(*) from STRING_SPLIT(@table_type, ',') where trim(value) = 'TABLE') = 1 + BEGIN + SET @_opt_table = 'TABLE' + END + IF @fUsePattern = '1' + BEGIN + select * from sys.sp_tables_view where + (@table_name = '' or table_name like @table_name) + and (@table_owner = '' or table_owner like @table_owner) + and (@table_qualifier = '' or table_qualifier like @table_qualifier) + and (@table_type = '' or table_type = @_opt_table or table_type = @_opt_view); + END + ELSE + BEGIN + select * from sys.sp_tables_view where + (@table_name = '' or table_name = @table_name) + and (@table_owner = '' or table_owner = @table_owner) + and (@table_qualifier = '' or table_qualifier = @table_qualifier) + and (@table_type = '' or table_type = @_opt_table or table_type = @_opt_view); + END +END; +$$ +LANGUAGE 'pltsql'; +GRANT ALL on PROCEDURE sys.sp_tables TO PUBLIC; + +CREATE FUNCTION sys.fn_mapped_system_error_list () +returns table (sql_error_code int) +AS 'babelfishpg_tsql', 'babel_list_mapped_error' +LANGUAGE C IMMUTABLE STRICT; +GRANT ALL on FUNCTION sys.fn_mapped_system_error_list TO PUBLIC; +-- 21 "sql/babelfishpg_tsql.in" 2 + + + + + + +SELECT set_config('search_path', trim(leading 'sys, ' from current_setting('search_path')), false); +RESET client_min_messages; diff --git a/contrib/babelfishpg_tsql/sql/babelfishpg_tsql.in b/contrib/babelfishpg_tsql/sql/babelfishpg_tsql.in new file mode 100644 index 00000000000..8ae289bf27e --- /dev/null +++ b/contrib/babelfishpg_tsql/sql/babelfishpg_tsql.in @@ -0,0 +1,28 @@ +/* + * All objects created by the included files will be created in sys + */ + +SELECT set_config('search_path', 'sys, '||current_setting('search_path'), false); + +#include "datatype.sql" +#include "datatype_string_operators.sql" +#include "sys.sql" +#include "sys_languages.sql" +#include "sys_function_helpers.sql" +#include "sys_functions.sql" +#include "sys_cast.sql" +#include "coerce.sql" +#include "sys_views.sql" +#include "collation.sql" +#include "sys_procedures.sql" +#include "ownership.sql" +#include "import_export_compatibility.sql" +#include "babelfishpg_tsql.sql" + +/* + * Remove schema sys from search_path otherwise it causes BABEL-257 for some reason + * Notice schema sys will be automatically added to implicitly-searched namespaces by + * recomputeNamespacePath() in tsql dialect + */ +SELECT set_config('search_path', trim(leading 'sys, ' from current_setting('search_path')), false); +RESET client_min_messages; diff --git a/contrib/babelfishpg_tsql/sql/babelfishpg_tsql.sql b/contrib/babelfishpg_tsql/sql/babelfishpg_tsql.sql new file mode 100644 index 00000000000..e26107124ca --- /dev/null +++ b/contrib/babelfishpg_tsql/sql/babelfishpg_tsql.sql @@ -0,0 +1,1146 @@ +CREATE FUNCTION pltsql_call_handler () + RETURNS language_handler AS 'babelfishpg_tsql' LANGUAGE C; + +CREATE FUNCTION pltsql_validator (oid) + RETURNS void AS 'babelfishpg_tsql' LANGUAGE C; + +CREATE FUNCTION pltsql_inline_handler(internal) + RETURNS void AS 'babelfishpg_tsql' LANGUAGE C; + +-- language +CREATE TRUSTED LANGUAGE pltsql + HANDLER pltsql_call_handler + INLINE pltsql_inline_handler + VALIDATOR pltsql_validator; +GRANT USAGE ON LANGUAGE pltsql TO public; + +COMMENT ON LANGUAGE pltsql IS 'PL/TSQL procedural language'; + +CREATE FUNCTION serverproperty (TEXT) + RETURNS sys.SQL_VARIANT AS 'babelfishpg_tsql', 'serverproperty' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION databasepropertyex (TEXT, TEXT) + RETURNS sys.SQL_VARIANT AS 'babelfishpg_tsql', 'databasepropertyex' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION connectionproperty (TEXT) + RETURNS sys.SQL_VARIANT AS 'babelfishpg_tsql', 'connectionproperty' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION collationproperty (TEXT, TEXT) + RETURNS sys.SQL_VARIANT AS 'babelfishpg_tsql', 'collationproperty' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION sessionproperty (TEXT) + RETURNS sys.SQL_VARIANT AS 'babelfishpg_tsql', 'sessionproperty' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- The procedures below requires return code as a RETURN statement which is +-- only possible in pltsql. Therefore, we create them here and call into the +-- corresponding internal functions. +CREATE OR REPLACE PROCEDURE sys.sp_getapplock(IN "@resource" varchar(255), + IN "@lockmode" varchar(32), + IN "@lockowner" varchar(32) DEFAULT 'TRANSACTION', + IN "@locktimeout" INTEGER DEFAULT -99, + IN "@dbprincipal" varchar(32) DEFAULT 'dbo') +LANGUAGE 'pltsql' +AS $$ +begin + declare @ret int; + select @ret = sp_getapplock_function(@resource, @lockmode, @lockowner, @locktimeout, @dbprincipal); + return @ret; +end; +$$; + +CREATE OR REPLACE PROCEDURE sys.sp_releaseapplock(IN "@resource" varchar(255), + IN "@lockowner" varchar(32) DEFAULT 'TRANSACTION', + IN "@dbprincipal" varchar(32) DEFAULT 'dbo') +LANGUAGE 'pltsql' +AS $$ +begin + declare @ret int; + select @ret = sp_releaseapplock_function(@resource, @lockowner, @dbprincipal); + return @ret; +end; +$$; + +-- sys.sp_oledb_ro_usrname is needed for TDS v7.2 +-- In tsql, sp_oledb_ro_usrname stored procedure returns the database read only status. +-- Return values: +-- 1. RO status (VARCHAR(1)) - "N" or "Y", "N" for not read only, "Y" for read only +-- 2. user_name (sysname or NVARCHAR(128)) - The current database user +CREATE OR REPLACE PROCEDURE sys.sp_oledb_ro_usrname() +LANGUAGE 'pltsql' +AS $$ +BEGIN + SELECT CAST((SELECT CASE WHEN pg_is_in_recovery() = 'f' THEN 'N' ELSE 'Y' END) AS VARCHAR(1)) RO, CAST(current_user as NVARCHAR(128)); +END ; +$$; + +CREATE OR REPLACE PROCEDURE sys.sp_helpdb() +LANGUAGE 'pltsql' +AS $$ +BEGIN + SELECT + CAST(name AS sys.nvarchar(128)), + CAST(db_size AS sys.nvarchar(13)), + CAST(owner AS sys.nvarchar(128)), + CAST(dbid AS sys.int), + CAST(created AS sys.nvarchar(11)), + CAST(status AS sys.nvarchar(600)), + CAST(compatibility_level AS sys.tinyint) + FROM sys.babelfish_helpdb(); + + RETURN 0; +END; +$$; + +CREATE OR REPLACE PROCEDURE sys.sp_helpdb(IN "@dbname" VARCHAR(32)) +LANGUAGE 'pltsql' +AS $$ +BEGIN + SELECT + CAST(name AS sys.nvarchar(128)), + CAST(db_size AS sys.nvarchar(13)), + CAST(owner AS sys.nvarchar(128)), + CAST(dbid AS sys.int), + CAST(created AS sys.nvarchar(11)), + CAST(status AS sys.nvarchar(600)), + CAST(compatibility_level AS sys.tinyint) + FROM sys.babelfish_helpdb("@dbname"); + + SELECT + CAST(NULL AS sys.nchar(128)) AS name, + CAST(NULL AS smallint) AS fileid, + CAST(NULL AS sys.nchar(260)) AS filename, + CAST(NULL AS sys.nvarchar(128)) AS filegroup, + CAST(NULL AS sys.nvarchar(18)) AS size, + CAST(NULL AS sys.nvarchar(18)) AS maxsize, + CAST(NULL AS sys.nvarchar(18)) AS growth, + CAST(NULL AS sys.varchar(9)) AS usage; + + RETURN 0; +END; +$$; + +-- BABEL-1643 +CREATE TABLE sys.spt_datatype_info_table +(TYPE_NAME VARCHAR(20), DATA_TYPE INT, PRECISION BIGINT, +LITERAL_PREFIX VARCHAR(20), LITERAL_SUFFIX VARCHAR(20), +CREATE_PARAMS CHAR(20), NULLABLE INT, CASE_SENSITIVE INT, +SEARCHABLE INT, UNSIGNED_ATTRIBUTE INT, MONEY INT, +AUTO_INCREMENT INT, LOCAL_TYPE_NAME VARCHAR(20), +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 SYS.TINYINT, +-- below column is added in order to join PG's information_schema.columns for sys.sp_columns_100_view +PG_TYPE_NAME VARCHAR(20) +); +GRANT SELECT ON sys.spt_datatype_info_table TO PUBLIC; + +INSERT INTO sys.spt_datatype_info_table VALUES (N'datetimeoffset', -155, 34, N'''', N'''', N'scale ', 1, 0, 3, NULL, 0, NULL, N'datetimeoffset', 0, 7, -155, 0, NULL, NULL, 0, 68, 0, 'datetimeoffset'); +INSERT INTO sys.spt_datatype_info_table VALUES (N'time', -154, 16, N'''', N'''', N'scale ', 1, 0, 3, NULL, 0, NULL, N'time', 0, 7, -154, 0, NULL, NULL, 0, 32, 0, 'time'); +INSERT INTO sys.spt_datatype_info_table VALUES (N'xml', -152, 0, N'N''', N'''', NULL, 1, 1, 0, NULL, 0, NULL, N'xml', NULL, NULL, -152, NULL, NULL, NULL, 0, 2147483646, 0, N'xml'); +INSERT INTO sys.spt_datatype_info_table VALUES (N'sql_variant', -150, 8000, NULL, NULL, NULL, 1, 0, 2, NULL, 0, NULL, N'sql_variant', 0, 0, -150, NULL, 10, NULL, 0, 8000, 39, 'sql_variant'); +INSERT INTO sys.spt_datatype_info_table VALUES (N'uniqueidentifier', -11, 36, N'''', N'''', NULL, 1, 0, 2, NULL, 0, NULL, N'uniqueidentifier', NULL, NULL, -11, NULL, NULL, NULL, 0, 16, 37, 'uniqueidentifier'); +INSERT INTO sys.spt_datatype_info_table VALUES (N'ntext', -10, 1073741823, N'N''', N'''', NULL, 1, 1, 1, NULL, 0, NULL, N'ntext', NULL, NULL, -10, NULL, NULL, NULL, 0, 2147483646, 35, NULL); +INSERT INTO sys.spt_datatype_info_table VALUES (N'nvarchar', -9, 4000, N'N''', N'''', N'max length ', 1, 1, 3, NULL, 0, NULL, N'nvarchar', NULL, NULL, -9, NULL, NULL, NULL, 0, 2, 39, NULL); +INSERT INTO sys.spt_datatype_info_table VALUES (N'sysname', -9, 128, N'N''', N'''', NULL, 0, 1, 3, NULL, 0, NULL, N'sysname', NULL, NULL, -9, NULL, NULL, NULL, 18, 256, 39, NULL); +INSERT INTO sys.spt_datatype_info_table VALUES (N'nchar', -8, 4000, N'N''', N'''', N'length ', 1, 1, 3, NULL, 0, NULL, N'nchar', NULL, NULL, -8, NULL, NULL, NULL, 0, 2, 39, NULL); +INSERT INTO sys.spt_datatype_info_table VALUES (N'bit', -7, 1, NULL, NULL, NULL, 1, 0, 2, NULL, 0, NULL, N'bit', 0, 0, -7, NULL, NULL, NULL, 16, 1, 50, 'bit'); +INSERT INTO sys.spt_datatype_info_table VALUES (N'tinyint', -6, 3, NULL, NULL, NULL, 1, 0, 2, 1, 0, 0, N'tinyint', 0, 0, -6, NULL, 10, NULL, 5, 1, 38, NULL); +INSERT INTO sys.spt_datatype_info_table VALUES (N'tinyint identity', -6, 3, NULL, NULL, NULL, 0, 0, 2, 1, 0, 1, N'tinyint identity', 0, 0, -6, NULL, 10, NULL, 5, 1, 38, NULL); +INSERT INTO sys.spt_datatype_info_table VALUES (N'bigint', -5, 19, NULL, NULL, NULL, 1, 0, 2, 0, 0, 0, N'bigint', 0, 0, -5, NULL, 10, NULL, 0, 8, 108, 'int8'); +INSERT INTO sys.spt_datatype_info_table VALUES (N'bigint identity', -5, 19, NULL, NULL, NULL, 0, 0, 2, 0, 0, 1, N'bigint identity', 0, 0, -5, NULL, 10, NULL, 0, 8, 108, NULL); +INSERT INTO sys.spt_datatype_info_table VALUES (N'image', -4, 2147483647, N'0x', NULL, NULL, 1, 0, 0, NULL, 0, NULL, N'image', NULL, NULL, -4, NULL, NULL, NULL, 20, 2147483647, 34, NULL); +INSERT INTO sys.spt_datatype_info_table VALUES (N'varbinary', -3, 8000, N'0x', NULL, N'max length ', 1, 0, 2, NULL, 0, NULL, N'varbinary', NULL, NULL, -3, NULL, NULL, NULL, 4, 1, 37, NULL); +INSERT INTO sys.spt_datatype_info_table VALUES (N'binary', -2, 8000, N'0x', NULL, N'length ', 1, 0, 2, NULL, 0, NULL, N'binary', NULL, NULL, -2, NULL, NULL, NULL, 3, 1, 37, NULL); +INSERT INTO sys.spt_datatype_info_table VALUES (N'timestamp', -2, 8, N'0x', NULL, NULL, 0, 0, 2, NULL, 0, NULL, N'timestamp', NULL, NULL, -2, NULL, NULL, NULL, 80, 8, 45, 'timestamp'); +INSERT INTO sys.spt_datatype_info_table VALUES (N'text', -1, 2147483647, N'''', N'''', NULL, 1, 1, 1, NULL, 0, NULL, N'text', NULL, NULL, -1, NULL, NULL, NULL, 19, 2147483647, 35, NULL); +INSERT INTO sys.spt_datatype_info_table VALUES (N'char', 1, 8000, N'''', N'''', N'length ', 1, 1, 3, NULL, 0, NULL, N'char', NULL, NULL, 1, NULL, NULL, NULL, 1, 1, 39, N'bpchar'); +INSERT INTO sys.spt_datatype_info_table VALUES (N'numeric', 2, 38, NULL, NULL, N'precision,scale ', 1, 0, 2, 0, 0, 0, N'numeric', 0, 38, 2, NULL, 10, NULL, 10, 20, 108, 'numeric'); +INSERT INTO sys.spt_datatype_info_table VALUES (N'numeric() identity', 2, 38, NULL, NULL, N'precision ', 0, 0, 2, 0, 0, 1, N'numeric() identity', 0, 0, 2, NULL, 10, NULL, 10, 20, 108, NULL); +INSERT INTO sys.spt_datatype_info_table VALUES (N'decimal', 3, 38, NULL, NULL, N'precision,scale ', 1, 0, 2, 0, 0, 0, N'decimal', 0, 38, 3, NULL, 10, NULL, 24, 20, 106, NULL); +INSERT INTO sys.spt_datatype_info_table VALUES (N'money', 3, 19, N'$', NULL, NULL, 1, 0, 2, 0, 1, 0, N'money', 4, 4, 3, NULL, 10, NULL, 11, 21, 110, NULL); +INSERT INTO sys.spt_datatype_info_table VALUES (N'smallmoney', 3, 10, N'$', NULL, NULL, 1, 0, 2, 0, 1, 0, N'smallmoney', 4, 4, 3, NULL, 10, NULL, 21, 12, 110, NULL); +INSERT INTO sys.spt_datatype_info_table VALUES (N'decimal() identity', 3, 38, NULL, NULL, N'precision ', 0, 0, 2, 0, 0, 1, N'decimal() identity', 0, 0, 3, NULL, 10, NULL, 24, 20, 106, NULL); +INSERT INTO sys.spt_datatype_info_table VALUES (N'int', 4, 10, NULL, NULL, NULL, 1, 0, 2, 0, 0, 0, N'int', 0, 0, 4, NULL, 10, NULL, 7, 4, 38, N'int4'); +INSERT INTO sys.spt_datatype_info_table VALUES (N'int identity', 4, 10, NULL, NULL, NULL, 0, 0, 2, 0, 0, 1, N'int identity', 0, 0, 4, NULL, 10, NULL, 7, 4, 38, N''); +INSERT INTO sys.spt_datatype_info_table VALUES (N'smallint', 5, 5, NULL, NULL, NULL, 1, 0, 2, 0, 0, 0, N'smallint', 0, 0, 5, NULL, 10, NULL, 6, 2, 38, 'int2'); +INSERT INTO sys.spt_datatype_info_table VALUES (N'smallint identity', 5, 5, NULL, NULL, NULL, 0, 0, 2, 0, 0, 1, N'smallint identity', 0, 0, 5, NULL, 10, NULL, 6, 2, 38, NULL); +INSERT INTO sys.spt_datatype_info_table VALUES (N'float', 6, 53, NULL, NULL, NULL, 1, 0, 2, 0, 0, 0, N'float', NULL, NULL, 6, NULL, 2, NULL, 8, 8, 109, 'float8'); +INSERT INTO sys.spt_datatype_info_table VALUES (N'real', 7, 24, NULL, NULL, NULL, 1, 0, 2, 0, 0, 0, N'real', NULL, NULL, 7, NULL, 2, NULL, 23, 4, 109, 'float4'); +INSERT INTO sys.spt_datatype_info_table VALUES (N'varchar', 12, 8000, N'''', N'''', N'max length ', 1, 1, 3, NULL, 0, NULL, N'varchar', NULL, NULL, 12, NULL, NULL, NULL, 2, 1, 39, NULL); +INSERT INTO sys.spt_datatype_info_table VALUES (N'date', 91, 10, N'''', N'''', NULL, 1, 0, 3, NULL, 0, NULL, N'date', NULL, 0, 9, 1, NULL, NULL, 0, 20, 0, 'date'); +INSERT INTO sys.spt_datatype_info_table VALUES (N'datetime2', 93, 27, N'''', N'''', N'scale ', 1, 0, 3, NULL, 0, NULL, N'datetime2', 0, 7, 9, 3, NULL, NULL, 0, 54, 0, 'datetime2'); +INSERT INTO sys.spt_datatype_info_table VALUES (N'datetime', 93, 23, N'''', N'''', NULL, 1, 0, 3, NULL, 0, NULL, N'datetime', 3, 3, 9, 3, NULL, NULL, 12, 16, 111, 'datetime'); +INSERT INTO sys.spt_datatype_info_table VALUES (N'smalldatetime', 93, 16, N'''', N'''', NULL, 1, 0, 3, NULL, 0, NULL, N'smalldatetime', 0, 0, 9, 3, NULL, NULL, 22, 16, 111, 'smalldatetime'); + +-- ODBCVer ignored for now +CREATE OR REPLACE PROCEDURE sys.sp_datatype_info ( + "@data_type" int = 0, + "@odbcver" smallint = 2) +AS $$ +BEGIN + select TYPE_NAME, DATA_TYPE, PRECISION, LITERAL_PREFIX, LITERAL_SUFFIX, + CREATE_PARAMS, NULLABLE, CASE_SENSITIVE, SEARCHABLE, + UNSIGNED_ATTRIBUTE, MONEY, AUTO_INCREMENT, LOCAL_TYPE_NAME, + MINIMUM_SCALE, MAXIMUM_SCALE, SQL_DATA_TYPE, SQL_DATETIME_SUB, + NUM_PREC_RADIX, INTERVAL_PRECISION, USERTYPE + from sys.spt_datatype_info_table where @data_type = 0 or data_type = @data_type; +END; +$$ +LANGUAGE 'pltsql'; +-- same as sp_datatype_info +CREATE OR REPLACE PROCEDURE sys.sp_datatype_info_100 ( + "@data_type" int = 0, + "@odbcver" smallint = 2) +AS $$ +BEGIN + select TYPE_NAME, DATA_TYPE, PRECISION, LITERAL_PREFIX, LITERAL_SUFFIX, + CREATE_PARAMS, NULLABLE, CASE_SENSITIVE, SEARCHABLE, + UNSIGNED_ATTRIBUTE, MONEY, AUTO_INCREMENT, LOCAL_TYPE_NAME, + MINIMUM_SCALE, MAXIMUM_SCALE, SQL_DATA_TYPE, SQL_DATETIME_SUB, + NUM_PREC_RADIX, INTERVAL_PRECISION, USERTYPE + from sys.spt_datatype_info_table where @data_type = 0 or data_type = @data_type; +END; +$$ +LANGUAGE 'pltsql'; + + +-- BABEL-1784: support for sp_columns/sp_columns_100 +CREATE VIEW sys.sp_columns_100_view AS +SELECT +CAST(t2.dbname AS sys.sysname) AS TABLE_QUALIFIER, +CAST(t3.rolname 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(t5.data_type AS smallint) AS DATA_TYPE, +CAST(t5.type_name AS sys.sysname) AS TYPE_NAME, +CAST(t4.numeric_precision AS INT) AS PRECISION, +CAST(t5.length AS int) AS LENGTH, +CAST(t4.numeric_scale AS smallint) AS SCALE, +CAST(t4.numeric_precision_radix 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, +CAST(t4.character_octet_length AS int) AS CHAR_OCTET_LENGTH, +CAST(t4.dtd_identifier 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, +case + when t4.is_generated = 'NEVER' then CAST(0 AS smallint) + else CAST(1 AS smallint) +end AS SS_IS_COMPUTED, +case + when t4.is_identity = 'YES' then CAST(1 AS smallint) + else CAST(0 AS smallint) +end 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 + JOIN information_schema.columns t4 ON t1.relname = t4.table_name, + sys.spt_datatype_info_table AS t5 +WHERE (t4.data_type = t5.pg_type_name + OR ((SELECT coalesce(t4.domain_name, '') != 'tinyint') AND (SELECT coalesce(t4.domain_name, '') != 'nchar') AND t5.pg_type_name = t4.udt_name) + OR (t4.domain_schema = 'sys' AND t5.type_name = t4.domain_name)); +GRANT SELECT on sys.sp_columns_100_view TO PUBLIC; + +-- internal function in order to workaround BABEL-1597 for BABEL-1784 +drop function if exists sys.sp_columns_100_internal( + in_table_name sys.nvarchar(384), + in_table_owner sys.nvarchar(384), + in_table_qualifier sys.nvarchar(384), + in_column_name sys.nvarchar(384), + in_NameScope int, + in_ODBCVer int, + in_fusepattern smallint); +create function sys.sp_columns_100_internal( + in_table_name sys.nvarchar(384), + in_table_owner sys.nvarchar(384) = '', + in_table_qualifier sys.nvarchar(384) = '', + in_column_name sys.nvarchar(384) = '', + in_NameScope int = 0, + in_ODBCVer int = 2, + in_fusepattern smallint = 1) +returns table ( + out_table_qualifier sys.sysname, + out_table_owner sys.sysname, + out_table_name sys.sysname, + out_column_name sys.sysname, + out_data_type smallint, + out_type_name sys.sysname, + out_precision int, + out_length int, + out_scale smallint, + out_radix smallint, + out_nullable smallint, + out_remarks varchar(254), + out_column_def sys.nvarchar(4000), + out_sql_data_type smallint, + out_sql_datetime_sub smallint, + out_char_octet_length int, + out_ordinal_position int, + out_is_nullable varchar(254), + out_ss_is_sparse smallint, + out_ss_is_column_set smallint, + out_ss_is_computed smallint, + out_ss_is_identity smallint, + out_ss_udt_catalog_name varchar(254), + out_ss_udt_schema_name varchar(254), + out_ss_udt_assembly_type_name varchar(254), + out_ss_xml_schemacollection_catalog_name varchar(254), + out_ss_xml_schemacollection_schema_name varchar(254), + out_ss_xml_schemacollection_name varchar(254), + out_ss_data_type sys.tinyint +) +as $$ +begin + IF in_fusepattern = 1 THEN + return query + select table_qualifier, + table_owner, + table_name, + column_name, + data_type, + type_name, + precision, + length, + scale, + radix, + nullable, + remarks, + column_def, + sql_data_type, + sql_datetime_sub, + char_octet_length, + ordinal_position, + is_nullable, + ss_is_sparse, + ss_is_column_set, + ss_is_computed, + ss_is_identity, + ss_udt_catalog_name, + ss_udt_schema_name, + ss_udt_assembly_type_name, + ss_xml_schemacollection_catalog_name, + ss_xml_schemacollection_schema_name, + ss_xml_schemacollection_name, + ss_data_type + from sys.sp_columns_100_view + where table_name like in_table_name + and ((SELECT coalesce(in_table_owner,'')) = '' or table_owner like in_table_owner) + and ((SELECT coalesce(in_table_qualifier,'')) = '' or table_qualifier like in_table_qualifier) + and ((SELECT coalesce(in_column_name,'')) = '' or column_name like in_column_name) + order by table_qualifier, table_owner, table_name; + ELSE + return query + select table_qualifier, precision from sys.sp_columns_100_view + where in_table_name = table_name + and ((SELECT coalesce(in_table_owner,'')) = '' or table_owner = in_table_owner) + and ((SELECT coalesce(in_table_qualifier,'')) = '' or table_qualifier = in_table_qualifier) + and ((SELECT coalesce(in_column_name,'')) = '' or column_name = in_column_name) + order by table_qualifier, table_owner, table_name; + END IF; +end; +$$ +LANGUAGE plpgsql; + +CREATE OR REPLACE PROCEDURE sys.sp_columns ( + "@table_name" sys.nvarchar(384), + "@table_owner" sys.nvarchar(384) = '', + "@table_qualifier" sys.nvarchar(384) = '', + "@column_name" sys.nvarchar(384) = '', + "@namescope" int = 0, + "@odbcver" int = 2, + "@fusepattern" smallint = 1) +AS $$ +BEGIN + select out_table_qualifier as table_qualifier, + out_table_owner as table_owner, + out_table_name as table_name, + out_column_name as column_name, + out_data_type as data_type, + out_type_name as type_name, + out_precision as precision, + out_length as length, + out_scale as scale, + out_radix as radix, + out_nullable as nullable, + out_remarks as remarks, + out_column_def as column_def, + out_sql_data_type as sql_data_type, + out_sql_datetime_sub as sql_datetime_sub, + out_char_octet_length as char_octet_length, + out_ordinal_position as ordinal_position, + out_is_nullable as is_nullable, + out_ss_data_type as ss_data_type + from sys.sp_columns_100_internal(@table_name, @table_owner,@table_qualifier, @column_name, @NameScope,@ODBCVer, @fusepattern); +END; +$$ +LANGUAGE 'pltsql'; +GRANT ALL on PROCEDURE sys.sp_columns TO PUBLIC; + +CREATE OR REPLACE PROCEDURE sys.sp_columns_100 ( + "@table_name" sys.nvarchar(384), + "@table_owner" sys.nvarchar(384) = '', + "@table_qualifier" sys.nvarchar(384) = '', + "@column_name" sys.nvarchar(384) = '', + "@namescope" int = 0, + "@odbcver" int = 2, + "@fusepattern" smallint = 1) +AS $$ +BEGIN + select out_table_qualifier as table_qualifier, + out_table_owner as table_owner, + out_table_name as table_name, + out_column_name as column_name, + out_data_type as data_type, + out_type_name as type_name, + out_precision as precision, + out_length as length, + out_scale as scale, + out_radix as radix, + out_nullable as nullable, + out_remarks as remarks, + out_column_def as column_def, + out_sql_data_type as sql_data_type, + out_sql_datetime_sub as sql_datetime_sub, + out_char_octet_length as char_octet_length, + out_ordinal_position as ordinal_position, + out_is_nullable as is_nullable, + out_ss_is_sparse as ss_is_sparse, + out_ss_is_column_set as ss_is_column_set, + out_ss_is_computed as ss_is_computed, + out_ss_is_identity as ss_is_identity, + out_ss_udt_catalog_name as ss_udt_catalog_name, + out_ss_udt_schema_name as ss_udt_schema_name, + out_ss_udt_assembly_type_name as ss_udt_assembly_type_name, + out_ss_xml_schemacollection_catalog_name as ss_xml_schemacollection_catalog_name, + out_ss_xml_schemacollection_schema_name as ss_xml_schemacollection_schema_name, + out_ss_xml_schemacollection_name as ss_xml_schemacollection_name, + out_ss_data_type as ss_data_type + from sys.sp_columns_100_internal(@table_name, @table_owner,@table_qualifier, @column_name, @NameScope,@ODBCVer, @fusepattern); +END; +$$ +LANGUAGE 'pltsql'; +GRANT ALL on PROCEDURE sys.sp_columns_100 TO PUBLIC; + +-- BABEL-1785: initial support of sp_describe_first_result_set +-- sys.sp_describe_first_result_set_internal: internal function +-- used to workaround BABEL-1597 +create function sys.sp_describe_first_result_set_internal( + tsqlquery varchar(384), + params varchar(384) = NULL, + browseMode sys.tinyint = 0 +) +returns table ( + is_hidden sys.bit, + column_ordinal int, + name sys.sysname, + is_nullable sys.bit, + system_type_id int, + system_type_name sys.nvarchar(256), + max_length smallint, + "precision" sys.tinyint, + scale sys.tinyint, + collation_name sys.sysname, + user_type_id int, + user_type_database sys.sysname, + user_type_schema sys.sysname, + user_type_name sys.sysname, + assembly_qualified_type_name sys.nvarchar(4000), + xml_collection_id int, + xml_collection_database sys.sysname, + xml_collection_schema sys.sysname, + xml_collection_name sys.sysname, + is_xml_document sys.bit, + is_case_sensitive sys.bit, + is_fixed_length_clr_type sys.bit, + source_server sys.sysname, + source_database sys.sysname, + source_schema sys.sysname, + source_table sys.sysname, + source_column sys.sysname, + is_identity_column sys.bit, + is_part_of_unique_key sys.bit, + is_updateable sys.bit, + is_computed_column sys.bit, + is_sparse_column_set sys.bit, + ordinal_in_order_by_list smallint, + order_by_list_length smallint, + order_by_is_descending smallint, + tds_type_id int, + tds_length int, + tds_collation_id int, + ss_data_type sys.tinyint +) +as $$ + declare _args text[]; -- placeholder: parse @params and feed the tsqlquery +begin + IF tsqlquery ILIKE 'select %' THEN + DROP VIEW IF EXISTS sp_describe_first_result_set_view; + EXECUTE 'create temp view sp_describe_first_result_set_view as ' || tsqlquery USING _args; + RETURN query + SELECT + CAST(0 AS sys.bit) AS is_hidden, + CAST(t1.dtd_identifier AS int) AS column_ordinal, + CAST(t1.column_name AS sys.sysname) AS name, + case + when t1.is_nullable = 'Y' then CAST(1 AS sys.bit) + else CAST(0 AS sys.bit) + end as is_nullable, + 0 as system_type_id, + CAST('' as sys.nvarchar(256)) as system_type_name, + CAST(t2.length AS smallint) AS max_length, + CAST(t1.numeric_precision AS sys.tinyint) AS precision, + CAST(t1.numeric_scale AS sys.tinyint) AS scale, + CAST((SELECT coalesce(t1.collation_name, '')) AS sys.sysname) as collation_name, + CAST(NULL as int) as user_type_id, + CAST('' as sys.sysname) as user_type_database, + CAST('' as sys.sysname) as user_type_schema, + CAST('' as sys.sysname) as user_type_name, + CAST('' as sys.nvarchar(4000)) as assembly_qualified_type_name, + CAST(NULL as int) as xml_collection_id, + CAST('' as sys.sysname) as xml_collection_database, + CAST('' as sys.sysname) as xml_collection_schema, + CAST('' as sys.sysname) as xml_collection_name, + case + when t1.data_type = 'xml' then CAST(1 AS sys.bit) + else CAST(0 AS sys.bit) + end as is_xml_document, + case + when t1.udt_name = 'citext' then CAST(0 AS sys.bit) + else CAST(1 AS sys.bit) + end as is_case_sensitive, + CAST(0 as sys.bit) as is_fixed_length_clr_type, + CAST('' as sys.sysname) as source_server, + CAST('' as sys.sysname) as source_database, + CAST('' as sys.sysname) as source_schema, + CAST('' as sys.sysname) as source_table, + CAST('' as sys.sysname) as source_column, + case + when t1.is_identity = '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 = 'YES' then CAST(1 AS sys.bit) + else CAST(0 AS sys.bit) + end as is_updateable, + case + when t1.is_generated = '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(NULL as int) as tds_type_id, + CAST(NULL as int) as tds_length, + CAST(NULL as int) as tds_collation_id, + CAST(1 AS sys.tinyint) AS tds_collation_sort_id + FROM information_schema.columns t1, sys.spt_datatype_info_table t2 + WHERE table_name = 'sp_describe_first_result_set_view' + AND (t1.data_type = t2.pg_type_name + OR ((SELECT coalesce(t1.domain_name, '') != 'tinyint') + AND (SELECT coalesce(t1.domain_name, '') != 'nchar') + AND t2.pg_type_name = t1.udt_name) + OR (t1.domain_schema = 'sys' AND t2.type_name = t1.domain_name)); + DROP VIEW sp_describe_first_result_set_view; + END IF; +end; +$$ +LANGUAGE plpgsql; +GRANT ALL on FUNCTION sys.sp_describe_first_result_set_internal TO PUBLIC; + +CREATE PROCEDURE sys.sp_describe_first_result_set ( + "@tsql" varchar(384), + "@params" varchar(384) = NULL, + "@browse_information_mode" sys.tinyint = 0) +AS $$ +BEGIN + select * from sys.sp_describe_first_result_set_internal(@tsql, @params, @browse_information_mode); +END; +$$ +LANGUAGE 'pltsql'; +GRANT ALL on PROCEDURE sys.sp_describe_first_result_set 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 split_part(p.attoptions[1], '=', 2) + ELSE c.name 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) + WHERE + c.is_sparse = 0 AND p.attnum >= 0; +GRANT SELECT ON sys.spt_tablecollations_view TO PUBLIC; + +-- We are limited by what postgres procedures can return here, but IEW may not +-- need it for initial compatibility +CREATE OR REPLACE PROCEDURE sys.sp_tablecollations_100 +( + IN "@object" nvarchar(4000) +) +AS $$ +BEGIN + select + s_tcv.colid AS colid, + s_tcv.name AS name, + s_tcv.tds_collation_100 AS tds_collation, + s_tcv.collation_100 AS collation + from + sys.spt_tablecollations_view s_tcv + where + s_tcv.object_id = sys.object_id(@object) + order by colid; +END; +$$ +LANGUAGE 'pltsql'; + +CREATE VIEW sys.spt_columns_view_managed AS +SELECT + o.object_id AS OBJECT_ID, + isc.table_catalog AS TABLE_CATALOG, + isc.table_schema AS TABLE_SCHEMA, + o.name AS TABLE_NAME, + c.name AS COLUMN_NAME, + isc.ordinal_position AS ORDINAL_POSITION, + isc.column_default AS COLUMN_DEFAULT, + isc.is_nullable AS IS_NULLABLE, + isc.data_type AS DATA_TYPE, + isc.character_maximum_length AS CHARACTER_MAXIMUM_LENGTH, + isc.character_octet_length AS CHARACTER_OCTET_LENGTH, + isc.numeric_precision AS NUMERIC_PRECISION, + isc.numeric_precision_radix AS NUMERIC_PRECISION_RADIX, + isc.numeric_scale AS NUMERIC_SCALE, + isc.datetime_precision AS DATETIME_PRECISION, + isc.character_set_catalog AS CHARACTER_SET_CATALOG, + isc.character_set_schema AS CHARACTER_SET_SCHEMA, + isc.character_set_name AS CHARACTER_SET_NAME, + isc.collation_catalog AS COLLATION_CATALOG, + isc.collation_schema AS COLLATION_SCHEMA, + c.collation_name AS COLLATION_NAME, + isc.domain_catalog AS DOMAIN_CATALOG, + isc.domain_schema AS DOMAIN_SCHEMA, + isc.domain_name AS DOMAIN_NAME, + c.is_sparse AS IS_SPARSE, + c.is_column_set AS IS_COLUMN_SET, + c.is_filestream AS IS_FILESTREAM +FROM + sys.objects o JOIN sys.columns c ON + ( + c.object_id = o.object_id and + o.type in ('U', 'V') -- limit columns to tables and views + ) + LEFT JOIN information_schema.columns isc ON + ( + sys.schema_name(o.schema_id) = isc.table_schema and + o.name = isc.table_name and + c.name = isc.column_name + ) + WHERE CAST(column_name AS sys.nvarchar(128)) NOT IN ('cmin', 'cmax', 'xmin', 'xmax', 'ctid', 'tableoid'); + +CREATE FUNCTION sys.sp_columns_managed_internal( + in_catalog sys.nvarchar(128), + in_owner sys.nvarchar(128), + in_table sys.nvarchar(128), + in_column sys.nvarchar(128), + in_schematype int) +RETURNS TABLE ( + out_table_catalog sys.nvarchar(128), + out_table_schema sys.nvarchar(128), + out_table_name sys.nvarchar(128), + out_column_name sys.nvarchar(128), + out_ordinal_position int, + out_column_default sys.nvarchar(4000), + out_is_nullable sys.nvarchar(3), + out_data_type sys.nvarchar, + out_character_maximum_length int, + out_character_octet_length int, + out_numeric_precision int, + out_numeric_precision_radix int, + out_numeric_scale int, + out_datetime_precision int, + out_character_set_catalog sys.nvarchar(128), + out_character_set_schema sys.nvarchar(128), + out_character_set_name sys.nvarchar(128), + out_collation_catalog sys.nvarchar(128), + out_is_sparse int, + out_is_column_set int, + out_is_filestream int + ) +AS +$$ +BEGIN + RETURN QUERY + SELECT CAST(table_catalog AS sys.nvarchar(128)), + CAST(table_schema AS sys.nvarchar(128)), + CAST(table_name AS sys.nvarchar(128)), + CAST(column_name AS sys.nvarchar(128)), + CAST(ordinal_position AS int), + CAST(column_default AS sys.nvarchar(4000)), + CAST(is_nullable AS sys.nvarchar(3)), + CAST(data_type AS sys.nvarchar), + CAST(character_maximum_length AS int), + CAST(character_octet_length AS int), + CAST(numeric_precision AS int), + CAST(numeric_precision_radix AS int), + CAST(numeric_scale AS int), + CAST(datetime_precision AS int), + CAST(character_set_catalog AS sys.nvarchar(128)), + CAST(character_set_schema AS sys.nvarchar(128)), + CAST(character_set_name AS sys.nvarchar(128)), + CAST(collation_catalog AS sys.nvarchar(128)), + CAST(is_sparse AS int), + CAST(is_column_set AS int), + CAST(is_filestream AS int) + FROM sys.spt_columns_view_managed s_cv + WHERE + (in_catalog IS NULL OR s_cv.TABLE_CATALOG LIKE in_catalog) AND + (in_owner IS NULL OR s_cv.TABLE_SCHEMA LIKE in_owner) AND + (in_table IS NULL OR s_cv.TABLE_NAME LIKE in_table) AND + (in_column IS NULL OR s_cv.COLUMN_NAME LIKE in_column) AND + (in_schematype = 0 AND (s_cv.IS_SPARSE = 0) OR in_schematype = 1 OR in_schematype = 2 AND (s_cv.IS_SPARSE = 1)); +END; +$$ +language plpgsql; + +CREATE PROCEDURE sys.sp_columns_managed +( + "@Catalog" nvarchar(128) = NULL, + "@Owner" nvarchar(128) = NULL, + "@Table" nvarchar(128) = NULL, + "@Column" nvarchar(128) = NULL, + "@SchemaType" nvarchar(128) = 0) -- 0 = 'select *' behavior (default), 1 = all columns, 2 = columnset columns +AS +$$ +BEGIN + SELECT + out_TABLE_CATALOG AS TABLE_CATALOG, + out_TABLE_SCHEMA AS TABLE_SCHEMA, + out_TABLE_NAME AS TABLE_NAME, + out_COLUMN_NAME AS COLUMN_NAME, + out_ORDINAL_POSITION AS ORDINAL_POSITION, + out_COLUMN_DEFAULT AS COLUMN_DEFAULT, + out_IS_NULLABLE AS IS_NULLABLE, + out_DATA_TYPE AS DATA_TYPE, + out_CHARACTER_MAXIMUM_LENGTH AS CHARACTER_MAXIMUM_LENGTH, + out_CHARACTER_OCTET_LENGTH AS CHARACTER_OCTET_LENGTH, + out_NUMERIC_PRECISION AS NUMERIC_PRECISION, + out_NUMERIC_PRECISION_RADIX AS NUMERIC_PRECISION_RADIX, + out_NUMERIC_SCALE AS NUMERIC_SCALE, + out_DATETIME_PRECISION AS DATETIME_PRECISION, + out_CHARACTER_SET_CATALOG AS CHARACTER_SET_CATALOG, + out_CHARACTER_SET_SCHEMA AS CHARACTER_SET_SCHEMA, + out_CHARACTER_SET_NAME AS CHARACTER_SET_NAME, + out_COLLATION_CATALOG AS COLLATION_CATALOG, + out_IS_SPARSE AS IS_SPARSE, + out_IS_COLUMN_SET AS IS_COLUMN_SET, + out_IS_FILESTREAM AS IS_FILESTREAM + FROM + sys.sp_columns_managed_internal(@Catalog, @Owner, "@Table", "@Column", @SchemaType) s_cv + ORDER BY TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME, IS_NULLABLE; +END; +$$ +LANGUAGE 'pltsql'; +GRANT ALL on PROCEDURE sys.sp_columns_managed TO PUBLIC; + +-- BABEL-1797: initial support of sp_describe_undeclared_parameters +-- sys.sp_describe_undeclared_parameters_internal: internal function +-- For the result rows, can we create a template table for it? +create function sys.sp_describe_undeclared_parameters_internal( + tsqlquery varchar(384), + params varchar(384) = NULL +) +returns table ( + parameter_ordinal int, -- NOT NULL + name sys.sysname, -- NOT NULL + suggested_system_type_id int, -- NOT NULL + suggested_system_type_name sys.nvarchar(256), + suggested_max_length smallint, -- NOT NULL + suggested_precision sys.tinyint, -- NOT NULL + suggested_scale sys.tinyint, -- NOT NULL + suggested_user_type_id int, -- NOT NULL + suggested_user_type_database sys.sysname, + suggested_user_type_schema sys.sysname, + suggested_user_type_name sys.sysname, + suggested_assembly_qualified_type_name sys.nvarchar(4000), + suggested_xml_collection_id int, + suggested_xml_collection_database sys.sysname, + suggested_xml_collection_schema sys.sysname, + suggested_xml_collection_name sys.sysname, + suggested_is_xml_document sys.bit, -- NOT NULL + suggested_is_case_sensitive sys.bit, -- NOT NULL + suggested_is_fixed_length_clr_type sys.bit, -- NOT NULL + suggested_is_input sys.bit, -- NOT NULL + suggested_is_output sys.bit, -- NOT NULL + formal_parameter_name sys.sysname, + suggested_tds_type_id int, -- NOT NULL + suggested_tds_length int -- NOT NULL +) +AS 'babelfishpg_tsql', 'sp_describe_undeclared_parameters_internal' +LANGUAGE C; +GRANT ALL on FUNCTION sys.sp_describe_undeclared_parameters_internal TO PUBLIC; + +CREATE PROCEDURE sys.sp_describe_undeclared_parameters ( + "@tsql" varchar(384), + "@params" varchar(384) = NULL) +AS $$ +BEGIN + select * from sys.sp_describe_undeclared_parameters_internal(@tsql, @params); + return 1; +END; +$$ +LANGUAGE 'pltsql'; +GRANT ALL on PROCEDURE sys.sp_describe_undeclared_parameters TO PUBLIC; + +-- BABEL-1782 +CREATE VIEW sys.sp_tables_view AS +SELECT +t2.dbname AS TABLE_QUALIFIER, +t3.rolname AS TABLE_OWNER, +t1.relname AS TABLE_NAME, +case + when t1.relkind = 'v' then 'VIEW' + else 'TABLE' +end AS TABLE_TYPE, +CAST(NULL AS varchar(254)) AS remarks +FROM pg_catalog.pg_class AS t1, sys.pg_namespace_ext AS t2, pg_catalog.pg_roles AS t3 +WHERE t1.relowner = t3.oid AND t1.relnamespace = t2.oid; +GRANT SELECT on sys.sp_tables_view TO PUBLIC; + +CREATE OR REPLACE PROCEDURE sys.sp_tables ( + "@table_name" sys.nvarchar(384), + "@table_owner" sys.nvarchar(384) = '', + "@table_qualifier" sys.sysname = '', + "@table_type" sys.nvarchar(100) = '', + "@fusepattern" sys.bit = '1') +AS $$ +BEGIN + DECLARE @_opt_view varchar(16) = '' + DECLARE @_opt_table varchar(16) = '' + IF (select count(*) from STRING_SPLIT(@table_type, ',') where trim(value) = 'VIEW') = 1 + BEGIN + SET @_opt_view = 'VIEW' + END + IF (select count(*) from STRING_SPLIT(@table_type, ',') where trim(value) = 'TABLE') = 1 + BEGIN + SET @_opt_table = 'TABLE' + END + IF @fUsePattern = '1' + BEGIN + select * from sys.sp_tables_view where + (@table_name = '' or table_name like @table_name) + and (@table_owner = '' or table_owner like @table_owner) + and (@table_qualifier = '' or table_qualifier like @table_qualifier) + and (@table_type = '' or table_type = @_opt_table or table_type = @_opt_view); + END + ELSE + BEGIN + select * from sys.sp_tables_view where + (@table_name = '' or table_name = @table_name) + and (@table_owner = '' or table_owner = @table_owner) + and (@table_qualifier = '' or table_qualifier = @table_qualifier) + and (@table_type = '' or table_type = @_opt_table or table_type = @_opt_view); + END +END; +$$ +LANGUAGE 'pltsql'; +GRANT ALL on PROCEDURE sys.sp_tables TO PUBLIC; + +CREATE FUNCTION sys.fn_mapped_system_error_list () +returns table (sql_error_code int) +AS 'babelfishpg_tsql', 'babel_list_mapped_error' +LANGUAGE C IMMUTABLE STRICT; +GRANT ALL on FUNCTION sys.fn_mapped_system_error_list TO PUBLIC; + +-- BABEL-2259: Support sp_databases System Stored Procedure +-- Lists databases that either reside in an instance of the SQL Server or +-- are accessible through a database gateway +DROP VIEW IF EXISTS sys.sp_databases_view CASCADE; + +CREATE OR REPLACE VIEW sys.sp_databases_view AS + SELECT CAST(database_name AS sys.SYSNAME), + -- DATABASE_SIZE returns a NULL value for databases larger than 2.15 TB + CASE WHEN (sum(table_size)/1024.0) > 2.15 * 1024.0 * 1024.0 * 1024.0 THEN NULL + ELSE CAST((sum(table_size)/1024.0) AS int) END as database_size, + CAST(NULL AS sys.VARCHAR(254)) as remarks + FROM ( + SELECT pg_catalog.pg_namespace.oid as schema_oid, + pg_catalog.pg_namespace.nspname as schema_name, + INT.name AS database_name, + coalesce(pg_relation_size(pg_catalog.pg_class.oid), 0) as table_size + FROM + sys.babelfish_namespace_ext EXT + JOIN sys.babelfish_sysdatabases INT ON EXT.dbid = INT.dbid + JOIN pg_catalog.pg_namespace ON pg_catalog.pg_namespace.nspname = EXT.nspname + LEFT JOIN pg_catalog.pg_class ON relnamespace = pg_catalog.pg_namespace.oid + ) t + GROUP BY database_name + ORDER BY database_name; +GRANT SELECT on sys.sp_databases_view TO PUBLIC; + +CREATE OR REPLACE PROCEDURE sys.sp_databases () +AS $$ +BEGIN + SELECT database_name as "DATABASE_NAME", + database_size as "DATABASE_SIZE", + remarks as "REMARKS" from sys.sp_databases_view; +END; +$$ +LANGUAGE 'pltsql'; +GRANT EXECUTE on PROCEDURE sys.sp_databases TO PUBLIC; + +CREATE VIEW sys.sp_pkeys_view AS +SELECT +CAST(t2.dbname AS sys.sysname) AS TABLE_QUALIFIER, +CAST(t3.rolname 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 + JOIN information_schema.columns t4 ON t1.relname = t4.table_name + 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.dtd_identifier AS smallint) = ANY (t5.conkey) + AND CAST(t4.dtd_identifier AS smallint) = t5.conkey[seq]; + +GRANT SELECT on sys.sp_pkeys_view TO PUBLIC; + +-- internal function in order to workaround BABEL-1597 +create function sys.sp_pkeys_internal( + in_table_name sys.nvarchar(384), + in_table_owner sys.nvarchar(384) = '', + in_table_qualifier sys.nvarchar(384) = '' +) +returns table( + out_table_qualifier sys.sysname, + out_table_owner sys.sysname, + out_table_name sys.sysname, + out_column_name sys.sysname, + out_key_seq smallint, + out_pk_name sys.sysname +) +as $$ +begin + return query + select * from sys.sp_pkeys_view + where in_table_name = table_name + and ((SELECT coalesce(in_table_owner,'')) = '' or table_owner = in_table_owner) + and ((SELECT coalesce(in_table_qualifier,'')) = '' or table_qualifier = in_table_qualifier) + order by table_qualifier, table_owner, table_name, key_seq; +end; +$$ +LANGUAGE plpgsql; + +CREATE OR REPLACE PROCEDURE sys.sp_pkeys( + "@table_name" sys.nvarchar(384), + "@table_owner" sys.nvarchar(384) = '', + "@table_qualifier" sys.nvarchar(384) = '' +) +AS $$ +BEGIN + select out_table_qualifier as table_qualifier, + out_table_owner as table_owner, + out_table_name as table_name, + out_column_name as column_name, + out_key_seq as key_seq, + out_pk_name as pk_name + from sys.sp_pkeys_internal(@table_name, @table_owner, @table_qualifier); +END; +$$ +LANGUAGE 'pltsql'; +GRANT ALL on PROCEDURE sys.sp_pkeys TO PUBLIC; + +CREATE VIEW sys.sp_statistics_view AS +SELECT +CAST(t2.dbname AS sys.sysname) AS TABLE_QUALIFIER, +CAST(t3.rolname AS sys.sysname) AS TABLE_OWNER, +CAST(t1.relname 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 t7.starelid > 0 THEN CAST(0 AS smallint) +ELSE + CASE + WHEN t5.indisclustered = 't' THEN CAST(1 AS smallint) + ELSE CAST(3 AS smallint) + END +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.stadistinct 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.pg_namespace_ext t2 ON t1.relnamespace = t2.oid + JOIN pg_catalog.pg_roles t3 ON t1.relowner = t3.oid + JOIN information_schema.columns t4 ON t1.relname = t4.table_name + JOIN (pg_catalog.pg_index t5 JOIN + pg_catalog.pg_class t6 ON t5.indexrelid = t6.oid) ON t1.oid = t5.indrelid + LEFT JOIN pg_catalog.pg_statistic t7 ON t1.oid = t7.starelid + 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.dtd_identifier AS smallint) = ANY (t5.indkey) + AND CAST(t4.dtd_identifier AS smallint) = t5.indkey[seq]; +GRANT SELECT on sys.sp_statistics_view TO PUBLIC; + +create function sys.sp_statistics_internal( + in_table_name sys.sysname, + in_table_owner sys.sysname = '', + in_table_qualifier sys.sysname = '', + in_index_name sys.sysname = '', + in_is_unique char = 'N', + in_accuracy char = 'Q' +) +returns table( + out_table_qualifier sys.sysname, + out_table_owner sys.sysname, + out_table_name sys.sysname, + out_non_unique smallint, + out_index_qualifier sys.sysname, + out_index_name sys.sysname, + out_type smallint, + out_seq_in_index smallint, + out_column_name sys.sysname, + out_collation sys.varchar(1), + out_cardinality int, + out_pages int, + out_filter_condition sys.varchar(128) +) +as $$ +begin + return query + select * from sys.sp_statistics_view + where in_table_name = table_name + and ((SELECT coalesce(in_table_owner,'')) = '' or table_owner = in_table_owner) + and ((SELECT coalesce(in_table_qualifier,'')) = '' or table_qualifier = in_table_qualifier) + and ((SELECT coalesce(in_index_name,'')) = '' or index_name like in_index_name) + and ((in_is_unique = 'N') or (in_is_unique = 'Y' and non_unique = 0)) + order by non_unique, type, index_name, seq_in_index; +end; +$$ +LANGUAGE plpgsql; + +CREATE OR REPLACE PROCEDURE sys.sp_statistics( + "@table_name" sys.sysname, + "@table_owner" sys.sysname = '', + "@table_qualifier" sys.sysname = '', + "@index_name" sys.sysname = '', + "@is_unique" char = 'N', + "@accuracy" char = 'Q' +) +AS $$ +BEGIN + select out_table_qualifier as table_qualifier, + out_table_owner as table_owner, + out_table_name as table_name, + out_non_unique as non_unique, + out_index_qualifier as index_qualifier, + out_index_name as index_name, + out_type as type, + out_seq_in_index as seq_in_index, + out_column_name as column_name, + out_collation as collation, + out_cardinality as cardinality, + out_pages as pages, + out_filter_condition as filter_condition + from sys.sp_statistics_internal(@table_name, @table_owner, @table_qualifier, @index_name, @is_unique, @accuracy); +END; +$$ +LANGUAGE 'pltsql'; +GRANT ALL on PROCEDURE sys.sp_statistics TO PUBLIC; + +-- same as sp_statistics +CREATE OR REPLACE PROCEDURE sys.sp_statistics_100( + "@table_name" sys.sysname, + "@table_owner" sys.sysname = '', + "@table_qualifier" sys.sysname = '', + "@index_name" sys.sysname = '', + "@is_unique" char = 'N', + "@accuracy" char = 'Q' +) +AS $$ +BEGIN + select out_table_qualifier as table_qualifier, + out_table_owner as table_owner, + out_table_name as table_name, + out_non_unique as non_unique, + out_index_qualifier as index_qualifier, + out_index_name as index_name, + out_type as type, + out_seq_in_index as seq_in_index, + out_column_name as column_name, + out_collation as collation, + out_cardinality as cardinality, + out_pages as pages, + out_filter_condition as filter_condition + from sys.sp_statistics_internal(@table_name, @table_owner, @table_qualifier, @index_name, @is_unique, @accuracy); +END; +$$ +LANGUAGE 'pltsql'; +GRANT ALL on PROCEDURE sys.sp_statistics_100 TO PUBLIC; + +CREATE OR REPLACE PROCEDURE sys.printarg(IN "@message" TEXT) +AS $$ +BEGIN + PRINT @message; +END; +$$ LANGUAGE pltsql; +GRANT EXECUTE ON PROCEDURE sys.printarg(IN "@message" TEXT) TO PUBLIC; + +CREATE OR REPLACE PROCEDURE sys.sp_updatestats(IN "@resample" VARCHAR(8) DEFAULT 'NO') +AS $$ +BEGIN + IF sys.user_name() != 'dbo' THEN + RAISE EXCEPTION 'user does not have permission'; + END IF; + + IF lower("@resample") = 'resample' THEN + RAISE NOTICE 'ignoring resample option'; + ELSIF lower("@resample") != 'no' THEN + RAISE EXCEPTION 'Invalid option name %', "@resample"; + END IF; + + ANALYZE VERBOSE; + + CALL printarg('Statistics for all tables have been updated. Refer logs for details.'); +END; +$$ LANGUAGE plpgsql; +GRANT EXECUTE on PROCEDURE sys.sp_updatestats(IN "@resample" VARCHAR(8)) TO PUBLIC; diff --git a/contrib/babelfishpg_tsql/sql/coerce.sql b/contrib/babelfishpg_tsql/sql/coerce.sql new file mode 100644 index 00000000000..430a23fa60d --- /dev/null +++ b/contrib/babelfishpg_tsql/sql/coerce.sql @@ -0,0 +1,11 @@ +-- Manually initialize translation table +CREATE OR REPLACE PROCEDURE babel_coercion_initializer() +LANGUAGE C +AS 'babelfishpg_tsql', 'init_tsql_coerce_hash_tab'; +CALL babel_coercion_initializer(); + +-- Manually initialize translation table +CREATE OR REPLACE PROCEDURE babel_datatype_precedence_initializer() +LANGUAGE C +AS 'babelfishpg_tsql', 'init_tsql_datatype_precedence_hash_tab'; +CALL babel_datatype_precedence_initializer(); diff --git a/contrib/babelfishpg_tsql/sql/collation.sql b/contrib/babelfishpg_tsql/sql/collation.sql new file mode 100644 index 00000000000..ecd2070a565 --- /dev/null +++ b/contrib/babelfishpg_tsql/sql/collation.sql @@ -0,0 +1,347 @@ +-- create babelfish collations + +CREATE COLLATION IF NOT EXISTS sys.Arabic_CS_AS (provider = icu, locale = 'ar_SA'); +CREATE COLLATION sys.Arabic_CI_AS (provider = icu, locale = 'ar_SA@colStrength=secondary', deterministic = false); +CREATE COLLATION sys.Arabic_CI_AI (provider = icu, locale = 'ar_SA@colStrength=primary', deterministic = false); + +CREATE COLLATION sys.BBF_Unicode_BIN2 FROM "C"; + +CREATE COLLATION sys.BBF_Unicode_General_CI_AS (provider = icu, locale = '@colStrength=secondary', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_General_CI_AI (provider = icu, locale = '@colStrength=primary', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_General_CS_AI (provider = icu, locale = '@colStrength=primary;colCaseLevel=yes;colCaseFirst=upper', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_General_CS_AS (provider = icu, locale = '@colStrength=tertiary', deterministic = true); +CREATE COLLATION sys.BBF_Unicode_General_Pref_CS_AS (provider = icu, locale = '@colStrength=tertiary;colCaseFirst=upper', deterministic = true); + +CREATE COLLATION sys.BBF_Unicode_CP1_CI_AS (provider = icu, locale = '@colStrength=secondary', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1_CI_AI (provider = icu, locale = '@colStrength=primary', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1_CS_AI (provider = icu, locale = '@colStrength=primary;colCaseLevel=yes;colCaseFirst=upper', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1_CS_AS (provider = icu, locale = '@colStrength=tertiary', deterministic = true); +CREATE COLLATION sys.BBF_Unicode_Pref_CP1_CS_AS (provider = icu, locale = '@colStrength=tertiary;colCaseFirst=upper', deterministic = true); + +CREATE COLLATION sys.BBF_Unicode_CP1250_CI_AS (provider = icu, locale = '@colStrength=secondary', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1250_CI_AI (provider = icu, locale = '@colStrength=primary', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1250_CS_AI (provider = icu, locale = '@colStrength=primary;colCaseLevel=yes;colCaseFirst=upper', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1250_CS_AS (provider = icu, locale = '@colStrength=tertiary', deterministic = true); +CREATE COLLATION sys.BBF_Unicode_Pref_CP1250_CS_AS (provider = icu, locale = '@colStrength=tertiary;colCaseFirst=upper', deterministic = true); + +CREATE COLLATION sys.BBF_Unicode_CP1251_CI_AS (provider = icu, locale = '@colStrength=secondary', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1251_CI_AI (provider = icu, locale = '@colStrength=primary', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1251_CS_AI (provider = icu, locale = '@colStrength=primary;colCaseLevel=yes;colCaseFirst=upper', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1251_CS_AS (provider = icu, locale = '@colStrength=tertiary', deterministic = true); +CREATE COLLATION sys.BBF_Unicode_Pref_CP1251_CS_AS (provider = icu, locale = '@colStrength=tertiary;colCaseFirst=upper', deterministic = true); + +CREATE COLLATION sys.BBF_Unicode_CP1253_CI_AS (provider = icu, locale = '@colStrength=secondary', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1253_CI_AI (provider = icu, locale = '@colStrength=primary', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1253_CS_AI (provider = icu, locale = '@colStrength=primary;colCaseLevel=yes;colCaseFirst=upper', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1253_CS_AS (provider = icu, locale = '@colStrength=tertiary', deterministic = true); +CREATE COLLATION sys.BBF_Unicode_Pref_CP1253_CS_AS (provider = icu, locale = '@colStrength=tertiary;colCaseFirst=upper', deterministic = true); + +CREATE COLLATION sys.BBF_Unicode_CP1254_CI_AS (provider = icu, locale = '@colStrength=secondary', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1254_CI_AI (provider = icu, locale = '@colStrength=primary', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1254_CS_AI (provider = icu, locale = '@colStrength=primary;colCaseLevel=yes;colCaseFirst=upper', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1254_CS_AS (provider = icu, locale = '@colStrength=tertiary', deterministic = true); +CREATE COLLATION sys.BBF_Unicode_Pref_CP1254_CS_AS (provider = icu, locale = '@colStrength=tertiary;colCaseFirst=upper', deterministic = true); + +CREATE COLLATION sys.BBF_Unicode_CP1255_CI_AS (provider = icu, locale = '@colStrength=secondary', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1255_CI_AI (provider = icu, locale = '@colStrength=primary', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1255_CS_AI (provider = icu, locale = '@colStrength=primary;colCaseLevel=yes;colCaseFirst=upper', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1255_CS_AS (provider = icu, locale = '@colStrength=tertiary', deterministic = true); +CREATE COLLATION sys.BBF_Unicode_Pref_CP1255_CS_AS (provider = icu, locale = '@colStrength=tertiary;colCaseFirst=upper', deterministic = true); + +CREATE COLLATION sys.BBF_Unicode_CP1256_CI_AS (provider = icu, locale = '@colStrength=secondary', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1256_CI_AI (provider = icu, locale = '@colStrength=primary', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1256_CS_AI (provider = icu, locale = '@colStrength=primary;colCaseLevel=yes;colCaseFirst=upper', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1256_CS_AS (provider = icu, locale = '@colStrength=tertiary', deterministic = true); +CREATE COLLATION sys.BBF_Unicode_Pref_CP1256_CS_AS (provider = icu, locale = '@colStrength=tertiary;colCaseFirst=upper', deterministic = true); + +CREATE COLLATION sys.BBF_Unicode_CP1257_CI_AS (provider = icu, locale = '@colStrength=secondary', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1257_CI_AI (provider = icu, locale = '@colStrength=primary', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1257_CS_AI (provider = icu, locale = '@colStrength=primary;colCaseLevel=yes;colCaseFirst=upper', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1257_CS_AS (provider = icu, locale = '@colStrength=tertiary', deterministic = true); +CREATE COLLATION sys.BBF_Unicode_Pref_CP1257_CS_AS (provider = icu, locale = '@colStrength=tertiary;colCaseFirst=upper', deterministic = true); + +CREATE COLLATION sys.BBF_Unicode_CP1258_CI_AS (provider = icu, locale = '@colStrength=secondary', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1258_CI_AI (provider = icu, locale = '@colStrength=primary', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1258_CS_AI (provider = icu, locale = '@colStrength=primary;colCaseLevel=yes;colCaseFirst=upper', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP1258_CS_AS (provider = icu, locale = '@colStrength=tertiary', deterministic = true); +CREATE COLLATION sys.BBF_Unicode_Pref_CP1258_CS_AS (provider = icu, locale = '@colStrength=tertiary;colCaseFirst=upper', deterministic = true); + +CREATE COLLATION sys.BBF_Unicode_CP874_CI_AS (provider = icu, locale = '@colStrength=secondary', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP874_CI_AI (provider = icu, locale = '@colStrength=primary', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP874_CS_AI (provider = icu, locale = '@colStrength=primary;colCaseLevel=yes;colCaseFirst=upper', deterministic = false); +CREATE COLLATION sys.BBF_Unicode_CP874_CS_AS (provider = icu, locale = '@colStrength=tertiary', deterministic = true); +CREATE COLLATION sys.BBF_Unicode_Pref_CP874_CS_AS (provider = icu, locale = '@colStrength=tertiary;colCaseFirst=upper', deterministic = true); + +CREATE COLLATION IF NOT EXISTS sys.Chinese_PRC_CS_AS (provider = icu, locale = 'zh_CN'); +CREATE COLLATION sys.Chinese_PRC_CI_AS (provider = icu, locale = 'zh_CN@colStrength=secondary', deterministic = false); +CREATE COLLATION sys.Chinese_PRC_CI_AI (provider = icu, locale = 'zh_CN@colStrength=primary', deterministic = false); + +CREATE COLLATION IF NOT EXISTS sys.Cyrillic_General_CS_AS (provider = icu, locale='ru_RU'); +CREATE COLLATION sys.Cyrillic_General_CI_AS (provider = icu, locale='ru_RU@colStrength=secondary', deterministic = false); +CREATE COLLATION sys.Cyrillic_General_CI_AI (provider = icu, locale='ru_RU@colStrength=primary', deterministic = false); + +CREATE COLLATION sys.Estonian_CS_AS (provider = icu, locale='et_EE'); +CREATE COLLATION sys.Estonian_CI_AI (provider = icu, locale='et_EE@colStrength=primary', deterministic = false); +CREATE COLLATION sys.Estonian_CI_AS (provider = icu, locale='et_EE@colStrength=secondary', deterministic = false); + +CREATE COLLATION IF NOT EXISTS sys.Finnish_Swedish_CS_AS (provider = icu, locale = 'sv_SE'); +CREATE COLLATION sys.Finnish_Swedish_CI_AI (provider = icu, locale = 'sv_SE@colStrength=primary', deterministic = false); +CREATE COLLATION sys.Finnish_Swedish_CI_AS (provider = icu, locale = 'sv_SE@colStrength=secondary', deterministic = false); + +CREATE COLLATION IF NOT EXISTS sys.French_CS_AS (provider = icu, locale = 'fr_FR'); +CREATE COLLATION sys.French_CI_AI (provider = icu, locale = 'fr_FR@colStrength=primary', deterministic = false); +CREATE COLLATION sys.French_CI_AS (provider = icu, locale = 'fr_FR@colStrength=secondary', deterministic = false); + +CREATE COLLATION sys.Greek_CS_AS (provider = icu, locale = 'el_GR'); +CREATE COLLATION sys.Greek_CI_AI (provider = icu, locale = 'el_GR@colStrength=primary', deterministic = false); +CREATE COLLATION sys.Greek_CI_AS (provider = icu, locale = 'el_GR@colStrength=secondary', deterministic = false); + +CREATE COLLATION sys.Hebrew_CS_AS (provider = icu, locale = 'he_IL'); +CREATE COLLATION sys.Hebrew_CI_AI (provider = icu, locale = 'he_IL@colStrength=primary', deterministic = false); +CREATE COLLATION sys.Hebrew_CI_AS (provider = icu, locale = 'he_IL@colStrength=secondary', deterministic = false); + +CREATE COLLATION sys.Korean_Wansung_CS_AS (provider = icu, locale = 'ko_KR'); +CREATE COLLATION sys.Korean_Wansung_CI_AI (provider = icu, locale = 'ko_KR@colStrength=primary', deterministic = false); +CREATE COLLATION sys.Korean_Wansung_CI_AS (provider = icu, locale = 'ko_KR@colStrength=secondary', deterministic = false); + +CREATE COLLATION sys.Modern_Spanish_CS_AS (provider = icu, locale = 'en_ES'); +CREATE COLLATION sys.Modern_Spanish_CI_AI (provider = icu, locale='es_ES@colStrength=primary', deterministic = false); +CREATE COLLATION sys.Modern_Spanish_CI_AS (provider = icu, locale='es_ES@colStrength=secondary', deterministic = false); + +CREATE COLLATION sys.Mongolian_CS_AS (provider = icu, locale = 'mn_MN'); +CREATE COLLATION sys.Mongolian_CI_AI (provider = icu, locale = 'mn_MN@colStrength=primary', deterministic = false); +CREATE COLLATION sys.Mongolian_CI_AS (provider = icu, locale = 'mn_MN@colStrength=secondary', deterministic = false); + +CREATE COLLATION IF NOT EXISTS sys.Polish_CS_AS (provider = icu, locale = 'pl_PL'); +CREATE COLLATION sys.Polish_CI_AI (provider = icu, locale = 'pl_PL@colStrength=primary', deterministic = false); +CREATE COLLATION sys.Polish_CI_AS (provider = icu, locale = 'pl_PL@colStrength=secondary', deterministic = false); + +CREATE COLLATION IF NOT EXISTS sys.Thai_CS_AS (provider = icu, locale = 'th_TH'); +CREATE COLLATION sys.Thai_CI_AI (provider = icu, locale = 'th_TH@colStrength=primary', deterministic = false); +CREATE COLLATION sys.Thai_CI_AS (provider = icu, locale = 'th_TH@colStrength=secondary', deterministic = false); + +CREATE COLLATION IF NOT EXISTS sys.Traditional_Spanish_CS_AS (provider = icu, locale = 'es_TRADITIONAL'); +CREATE COLLATION sys.Traditional_Spanish_CI_AI (provider = icu, locale = 'es_TRADITIONAL@colStrength=primary', deterministic = false); +CREATE COLLATION sys.Traditional_Spanish_CI_AS (provider = icu, locale = 'es_TRADITIONAL@colStrength=secondary', deterministic = false); + +CREATE COLLATION IF NOT EXISTS sys.Turkish_CS_AS (provider = icu, locale = 'tr_TR'); +CREATE COLLATION sys.Turkish_CI_AI (provider = icu, locale = 'tr_TR@colStrength=primary', deterministic = false); +CREATE COLLATION sys.Turkish_CI_AS (provider = icu, locale = 'tr_TR@colStrength=secondary', deterministic = false); + +CREATE COLLATION IF NOT EXISTS sys.Ukrainian_CS_AS (provider = icu, locale = 'uk_UA'); +CREATE COLLATION sys.Ukrainian_CI_AI (provider = icu, locale = 'uk_UA@colStrength=primary', deterministic = false); +CREATE COLLATION sys.Ukrainian_CI_AS (provider = icu, locale = 'uk_UA@colStrength=secondary', deterministic = false); + +CREATE COLLATION IF NOT EXISTS sys.Vietnamese_CS_AS (provider = icu, locale = 'vi_VN'); +CREATE COLLATION sys.Vietnamese_CI_AI (provider = icu, locale = 'vi_VN@colStrength=primary', deterministic = false); +CREATE COLLATION sys.Vietnamese_CI_AS (provider = icu, locale = 'vi_VN@colStrength=secondary', deterministic = false); + +-- collation catalog +create table sys.babelfish_helpcollation( + Name VARCHAR(128) NOT NULL, + Description VARCHAR(1000) NOT NULL +); +GRANT SELECT ON sys.babelfish_helpcollation TO PUBLIC; + +create or replace function sys.fn_helpcollations() +returns table (Name VARCHAR(128), Description VARCHAR(1000)) +AS +$$ +BEGIN + return query select * from sys.babelfish_helpcollation; +END +$$ +LANGUAGE 'plpgsql'; +INSERT INTO sys.babelfish_helpcollation VALUES (N'arabic_cs_as', N'Arabic, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'arabic_ci_ai', N'Arabic, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'arabic_ci_as', N'Arabic, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_bin2', N'Unicode-General, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1250_ci_ai', N'Default locale, code page 1250, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1250_ci_as', N'Default locale, code page 1250, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1250_cs_ai', N'Default locale, code page 1250, case-sensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1250_cs_as', N'Default locale, code page 1250, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_pref_cp1250_cs_as', N'Default locale, code page 1250, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive, uppercase-first'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1251_ci_ai', N'Default locale, code page 1251, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1251_ci_as', N'Default locale, code page 1251, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1251_cs_ai', N'Default locale, code page 1251, case-sensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1251_cs_as', N'Default locale, code page 1251, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_pref_cp1251_cs_as', N'Default locale, code page 1251, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive, uppercase-first'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1253_ci_ai', N'Default locale, code page 1253, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1253_ci_as', N'Default locale, code page 1253, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1253_cs_ai', N'Default locale, code page 1253, case-sensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1253_cs_as', N'Default locale, code page 1253, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_pref_cp1253_cs_as', N'Default locale, code page 1253, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive, uppercase-first'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1254_ci_ai', N'Default locale, code page 1254, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1254_ci_as', N'Default locale, code page 1254, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1254_cs_ai', N'Default locale, code page 1254, case-sensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1254_cs_as', N'Default locale, code page 1254, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_pref_cp1254_cs_as', N'Default locale, code page 1254, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive, uppercase-first'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1255_ci_ai', N'Default locale, code page 1255, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1255_ci_as', N'Default locale, code page 1255, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1255_cs_ai', N'Default locale, code page 1255, case-sensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1255_cs_as', N'Default locale, code page 1255, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_pref_cp1255_cs_as', N'Default locale, code page 1255, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive, uppercase-first'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1256_ci_ai', N'Default locale, code page 1256, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1256_ci_as', N'Default locale, code page 1256, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1256_cs_ai', N'Default locale, code page 1256, case-sensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1256_cs_as', N'Default locale, code page 1256, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_pref_cp1256_cs_as', N'Default locale, code page 1256, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive, uppercase-first'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1257_ci_ai', N'Default locale, code page 1257, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1257_ci_as', N'Default locale, code page 1257, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1257_cs_ai', N'Default locale, code page 1257, case-sensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1257_cs_as', N'Default locale, code page 1257, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_pref_cp1257_cs_as', N'Default locale, code page 1257, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive, uppercase-first'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1258_ci_ai', N'Default locale, code page 1258, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1258_ci_as', N'Default locale, code page 1258, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1258_cs_ai', N'Default locale, code page 1258, case-sensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1258_cs_as', N'Default locale, code page 1258, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_pref_cp1258_cs_as', N'Default locale, code page 1258, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive, uppercase-first'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1_ci_ai', N'Default locale, code page 1252, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1_ci_as', N'Default locale, code page 1252, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1_cs_ai', N'Default locale, code page 1252, case-sensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp1_cs_as', N'Default locale, code page 1252, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_pref_cp1_cs_as', N'Default locale, code page 1252, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive, uppercase-first'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp847_ci_ai', N'Default locale, code page 847, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp847_ci_as', N'Default locale, code page 847, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp847_cs_ai', N'Default locale, code page 847, case-sensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_cp847_cs_as', N'Default locale, code page 847, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_pref_cp847_cs_as', N'Default locale, code page 847, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive, uppercase-first'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_general_ci_ai', N'Default locale, default code page, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_general_ci_as', N'Default locale, default code page, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_general_cs_ai', N'Default locale, default code page, case-sensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_general_cs_as', N'Default locale, default code page, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'bbf_unicode_general_pref_cs_as', N'Default locale, default code page, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive, uppercase-first'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'chinese_prc_cs_as', N'Chinese-PRC, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'chinese_prc_ci_ai', N'Chinese-PRC, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'chinese_prc_ci_as', N'Chinese-PRC, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'cyrillic_general_cs_as', N'Cyrillic-General, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'cyrillic_general_ci_ai', N'Cyrillic-General, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'cyrillic_general_ci_as', N'Cyrillic-General, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'finnish_swedish_cs_as', N'Finnish-Swedish, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'finnish_swedish_ci_as', N'Finnish-Swedish, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'finnish_swedish_ci_ai', N'Finnish-Swedish, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'french_cs_as', N'French, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'french_ci_as', N'French, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'french_ci_ai', N'French, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'korean_wansung_cs_as', N'Korean-Wansung, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'korean_wansung_ci_as', N'Korean-Wansung, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'korean_wansung_ci_ai', N'Korean-Wansung, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'latin1_general_bin2', N'Virtual, Unicode-General, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'latin1_general_90_bin2', N'Virtual, Unicode-General, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'latin1_general_100_bin2', N'Virtual, Unicode-General, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'latin1_general_140_bin2', N'Virtual, Unicode-General, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'latin1_general_ci_ai', N'Virtual, default locale, code page 1252, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'latin1_general_ci_as', N'Virtual, default locale, code page 1252, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'latin1_general_cs_ai', N'Virtual, default locale, code page 1252, case-sensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'latin1_general_cs_as', N'Virtual, default locale, code page 1252, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'modern_spanish_cs_as', N'Traditional-Spanish, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'modern_spanish_ci_as', N'Traditional-Spanish, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'modern_spanish_ci_ai', N'Traditional-Spanish, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'polish_cs_as', N'Polish, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'polish_ci_as', N'Polish, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'polish_ci_ai', N'Polish, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'sql_latin1_general_cp1250_ci_as', N'Virtual, default locale, code page 1250, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'sql_latin1_general_cp1250_cs_as', N'Virtual, default locale, code page 1250, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'sql_latin1_general_cp1251_ci_as', N'Virtual, default locale, code page 1251, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'sql_latin1_general_cp1251_cs_as', N'Virtual, default locale, code page 1251, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'sql_latin1_general_cp1_ci_ai', N'Virtual, default locale, code page 1252, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'sql_latin1_general_cp1_ci_as', N'Virtual, default locale, code page 1252, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'sql_latin1_general_cp1_ci_ai', N'Virtual, default locale, code page 1252, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'sql_latin1_general_cp1_cs_as', N'Virtual, default locale, code page 1252, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'sql_latin1_general_pref_cp1_cs_as', N'Virtual, default locale, code page 1252, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive, uppercase-first'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'sql_latin1_general_cp1253_ci_as', N'Virtual, default locale, code page 1253, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'sql_latin1_general_cp1253_cs_as', N'Virtual, default locale, code page 1253, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'sql_latin1_general_cp1254_ci_as', N'Virtual, default locale, code page 1254, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'sql_latin1_general_cp1254_cs_as', N'Virtual, default locale, code page 1255, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'sql_latin1_general_cp1255_ci_as', N'Virtual, default locale, code page 1255, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'sql_latin1_general_cp1255_cs_as', N'Virtual, default locale, code page 1255, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'sql_latin1_general_cp1256_ci_as', N'Virtual, default locale, code page 1256, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'sql_latin1_general_cp1256_cs_as', N'Virtual, default locale, code page 1256, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'sql_latin1_general_cp1257_ci_as', N'Virtual, default locale, code page 1257, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'sql_latin1_general_cp1257_cs_as', N'Virtual, default locale, code page 1257, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'sql_latin1_general_cp1258_ci_as', N'Virtual, default locale, code page 1258, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'sql_latin1_general_cp1258_cs_as', N'Virtual, default locale, code page 1258, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'thai_cs_as', N'Thai, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'thai_ci_as', N'Thai, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'thai_ci_ai', N'Thai, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'traditional_spanish_cs_as', N'Traditional-Spanish, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'traditional_spanish_ci_as', N'Traditional-Spanish, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'traditional_spanish_ci_ai', N'Traditional-Spanish, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'turkish_cs_as', N'Turkish, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'turkish_ci_as', N'Turkish, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'turkish_ci_ai', N'Turkish, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'ukrainian_cs_as', N'Ukrainian, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'ukrainian_ci_as', N'Ukrainian, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'ukrainian_ci_ai', N'Ukrainian, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); + +INSERT INTO sys.babelfish_helpcollation VALUES (N'vietnamese_cs_as', N'Vietnamese, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'vietnamese_ci_as', N'Vietnamese, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive'); +INSERT INTO sys.babelfish_helpcollation VALUES (N'vietnamese_ci_ai', N'Vietnamese, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive'); + +DROP FUNCTION IF EXISTS sys.get_babel_server_collation_oid; +CREATE OR REPLACE FUNCTION sys.get_babel_server_collation_oid() RETURNS OID +LANGUAGE C +AS 'babelfishpg_tsql', 'get_server_collation_oid'; + +DROP PROCEDURE IF EXISTS sys.init_database_collation_oid; +CREATE OR REPLACE PROCEDURE sys.init_server_collation_oid() +AS $$ +DECLARE + server_colloid OID; +BEGIN + server_colloid = sys.get_babel_server_collation_oid(); + perform pg_catalog.set_config('babelfishpg_tsql.server_collation_oid', server_colloid::text, false); + execute format('ALTER DATABASE %I SET babelfishpg_tsql.server_collation_oid FROM CURRENT', current_database()); +END; +$$ +LANGUAGE plpgsql; + +CALL sys.init_server_collation_oid(); + +-- Fill in the oids in coll_infos +CREATE OR REPLACE PROCEDURE sys.babel_collation_initializer() +LANGUAGE C +AS 'babelfishpg_tsql', 'init_collid_trans_tab'; +CALL sys.babel_collation_initializer(); +DROP PROCEDURE sys.babel_collation_initializer; + +-- Manually initialize like mapping table +CREATE OR REPLACE PROCEDURE sys.babel_like_ilike_info_initializer() +LANGUAGE C +AS 'babelfishpg_tsql', 'init_like_ilike_table'; +CALL sys.babel_like_ilike_info_initializer(); +DROP PROCEDURE sys.babel_like_ilike_info_initializer; diff --git a/contrib/babelfishpg_tsql/sql/datatype.sql b/contrib/babelfishpg_tsql/sql/datatype.sql new file mode 100644 index 00000000000..925b3c42bab --- /dev/null +++ b/contrib/babelfishpg_tsql/sql/datatype.sql @@ -0,0 +1,6 @@ +-- Types with different default typmod behavior +SET enable_domain_typmod = TRUE; + +CREATE DOMAIN sys.CURSOR AS REFCURSOR; + +RESET enable_domain_typmod; diff --git a/contrib/babelfishpg_tsql/sql/datatype_string_operators.sql b/contrib/babelfishpg_tsql/sql/datatype_string_operators.sql new file mode 100644 index 00000000000..77c0b599b3b --- /dev/null +++ b/contrib/babelfishpg_tsql/sql/datatype_string_operators.sql @@ -0,0 +1,53 @@ +CREATE OR REPLACE FUNCTION sys.hashbytes(IN alg VARCHAR, IN data VARCHAR) RETURNS sys.bbf_varbinary +AS 'babelfishpg_tsql', 'hashbytes' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; +GRANT EXECUTE ON FUNCTION sys.hashbytes(IN VARCHAR, IN VARCHAR) TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.hashbytes(IN alg VARCHAR, IN data sys.bbf_varbinary) RETURNS sys.bbf_varbinary +AS 'babelfishpg_tsql', 'hashbytes' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; +GRANT EXECUTE ON FUNCTION sys.hashbytes(IN VARCHAR, IN sys.bbf_varbinary) TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.quotename(IN input_string VARCHAR, IN delimiter char default '[') RETURNS +sys.nvarchar AS 'babelfishpg_tsql', 'quotename' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; +GRANT EXECUTE ON FUNCTION sys.quotename(IN VARCHAR, IN char) TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.unicode(IN str VARCHAR) returns INTEGER +as +$BODY$ + select ascii(str); +$BODY$ +LANGUAGE SQL IMMUTABLE STRICT PARALLEL SAFE; +GRANT EXECUTE ON FUNCTION sys.unicode(IN VARCHAR) TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.string_split(IN string VARCHAR, IN separator VARCHAR, OUT value VARCHAR) RETURNS SETOF VARCHAR AS +$body$ +BEGIN + if length(separator) != 1 then + RAISE EXCEPTION 'Invalid separator: %', separator USING HINT = + 'Separator must be length 1'; +else + RETURN QUERY(SELECT cast(unnest(string_to_array(string, separator)) as varchar)); +end if; +END +$body$ +LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE; +GRANT EXECUTE ON FUNCTION sys.string_split(IN VARCHAR, IN VARCHAR, OUT VARCHAR) TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.string_escape(IN str sys.NVARCHAR, IN type TEXT) RETURNS sys.NVARCHAR +AS 'babelfishpg_tsql', 'string_escape' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; +GRANT EXECUTE ON FUNCTION sys.string_escape(IN sys.NVARCHAR, IN TEXT) TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.formatmessage(IN message_str TEXT) RETURNS sys.nvarchar +AS 'babelfishpg_tsql', 'formatmessage' LANGUAGE C IMMUTABLE PARALLEL SAFE; +GRANT EXECUTE ON FUNCTION sys.formatmessage(IN TEXT) TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.formatmessage(IN message_str VARCHAR) RETURNS sys.nvarchar +AS 'babelfishpg_tsql', 'formatmessage' LANGUAGE C IMMUTABLE PARALLEL SAFE; +GRANT EXECUTE ON FUNCTION sys.formatmessage(IN VARCHAR) TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.formatmessage(IN message_str TEXT, VARIADIC "any") RETURNS sys.nvarchar +AS 'babelfishpg_tsql', 'formatmessage' LANGUAGE C IMMUTABLE PARALLEL SAFE; +GRANT EXECUTE ON FUNCTION sys.formatmessage(IN TEXT, VARIADIC "any") TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.formatmessage(IN message_str VARCHAR, VARIADIC "any") RETURNS sys.nvarchar +AS 'babelfishpg_tsql', 'formatmessage' LANGUAGE C IMMUTABLE PARALLEL SAFE; +GRANT EXECUTE ON FUNCTION sys.formatmessage(IN VARCHAR, VARIADIC "any") TO PUBLIC; diff --git a/contrib/babelfishpg_tsql/sql/import_export_compatibility.sql b/contrib/babelfishpg_tsql/sql/import_export_compatibility.sql new file mode 100644 index 00000000000..2b99499e7cd --- /dev/null +++ b/contrib/babelfishpg_tsql/sql/import_export_compatibility.sql @@ -0,0 +1,37 @@ +CREATE TABLE sys.assemblies( + name VARCHAR(255), + principal_id int, + assembly_id int, + is_nullable int, + is_fixed_length int, + max_length int +); +GRANT SELECT ON sys.assemblies TO PUBLIC; + +CREATE TABLE sys.assembly_types ( + assembly_id int, + assembly_class VARCHAR(255) +); +GRANT SELECT ON sys.assembly_types TO PUBLIC; + +-- Cannot be implemented without a full implementation of assemblies. +-- However, a full implementation isn't needed for import-export support yet +CREATE OR REPLACE FUNCTION assemblyproperty(IN a VARCHAR, IN b VARCHAR) RETURNS sys.sql_variant +AS +$body$ + SELECT CAST('' AS sys.sql_variant); +$body$ +LANGUAGE SQL IMMUTABLE STRICT; +GRANT EXECUTE ON FUNCTION assemblyproperty(IN VARCHAR, IN VARCHAR) TO PUBLIC; + +CREATE OR REPLACE FUNCTION is_member(IN a VARCHAR) RETURNS INT +AS 'babelfishpg_tsql', 'is_member' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; +GRANT EXECUTE ON FUNCTION is_member(IN VARCHAR) TO PUBLIC; + +CREATE OR REPLACE FUNCTION schema_id(IN schema_name VARCHAR) RETURNS INT +AS 'babelfishpg_tsql', 'schema_id' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; +GRANT EXECUTE ON FUNCTION schema_id(IN VARCHAR) TO PUBLIC; + +CREATE OR REPLACE FUNCTION schema_name(IN id oid) RETURNS VARCHAR +AS 'babelfishpg_tsql', 'schema_name' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; +GRANT EXECUTE ON FUNCTION schema_name(IN oid) TO PUBLIC; diff --git a/contrib/babelfishpg_tsql/sql/ownership.sql b/contrib/babelfishpg_tsql/sql/ownership.sql new file mode 100644 index 00000000000..ef52fc77670 --- /dev/null +++ b/contrib/babelfishpg_tsql/sql/ownership.sql @@ -0,0 +1,314 @@ +-- BBF_SYSDATABASES +-- Note: change here requires change in FormData_sysdatabases too +CREATE TABLE sys.babelfish_sysdatabases ( + dbid SMALLINT NOT NULL UNIQUE, + status INT NOT NULL, + status2 INT NOT NULL, + owner NAME NOT NULL, + default_collation NAME NOT NULL, + name TEXT NOT NULL COLLATE "C", + crdate timestamptz NOT NULL, + properties TEXT NOT NULL COLLATE "C", + PRIMARY KEY (name) +); + +GRANT SELECT on sys.babelfish_sysdatabases TO PUBLIC; + +-- BABELFISH_NAMESPACE_EXT +CREATE TABLE sys.babelfish_namespace_ext ( + nspname NAME NOT NULL, + dbid SMALLINT NOT NULL, + orig_name sys.NVARCHAR(128) NOT NULL, + properties TEXT NOT NULL COLLATE "C", + PRIMARY KEY (nspname) +); +GRANT SELECT ON sys.babelfish_namespace_ext TO PUBLIC; + +-- SYSDATABASES +CREATE OR REPLACE VIEW sys.sysdatabases AS +SELECT +t.name, +sys.db_id(t.name) AS dbid, +CAST(CAST(r.oid AS int) AS SYS.VARBINARY(85)) AS sid, +CAST(0 AS SMALLINT) AS mode, +t.status, +t.status2, +CAST(t.crdate AS SYS.DATETIME) AS crdate, +CAST('1900-01-01 00:00:00.000' AS SYS.DATETIME) AS reserved, +CAST(0 AS INT) AS category, +CAST(NULL AS SYS.TINYINT) AS cmptlevel, +CAST(NULL AS SYS.NVARCHAR(260)) AS filename, +CAST(NULL AS SMALLINT) AS version +FROM sys.babelfish_sysdatabases AS t +LEFT OUTER JOIN pg_catalog.pg_roles r on r.rolname = t.owner; + +GRANT SELECT ON sys.sysdatabases TO PUBLIC; + +-- PG_NAMESPACE_EXT +CREATE VIEW sys.pg_namespace_ext AS +SELECT BASE.* , DB.name as dbname FROM +pg_catalog.pg_namespace AS base +LEFT OUTER JOIN sys.babelfish_namespace_ext AS EXT on BASE.nspname = EXT.nspname +INNER JOIN sys.babelfish_sysdatabases AS DB ON EXT.dbid = DB.dbid; + +GRANT SELECT ON sys.pg_namespace_ext TO PUBLIC; + +-- Logical Schema Views +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 base.nspname not in ('information_schema', 'pg_catalog', 'pg_toast', 'sys', 'public') +and ext.dbid = cast(sys.db_id() as oid); +GRANT SELECT ON sys.schemas TO PUBLIC; +CREATE SEQUENCE sys.babelfish_db_seq MAXVALUE 32767 CYCLE; + +-- CATALOG INITIALIZER +CREATE OR REPLACE PROCEDURE babel_catalog_initializer() +LANGUAGE C +AS 'babelfishpg_tsql', 'init_catalog'; + +CALL babel_catalog_initializer(); + +CREATE OR REPLACE PROCEDURE babel_create_builtin_dbs(IN login TEXT) +LANGUAGE C +AS 'babelfishpg_tsql', 'create_builtin_dbs'; + +CREATE OR REPLACE PROCEDURE sys.babel_drop_all_dbs() +LANGUAGE C +AS 'babelfishpg_tsql', 'drop_all_dbs'; + +CREATE OR REPLACE PROCEDURE sys.babel_initialize_logins(IN login TEXT) +LANGUAGE C +AS 'babelfishpg_tsql', 'initialize_logins'; + +CREATE OR REPLACE PROCEDURE sys.babel_drop_all_logins() +LANGUAGE C +AS 'babelfishpg_tsql', 'drop_all_logins'; + +CREATE OR REPLACE PROCEDURE initialize_babelfish ( sa_name VARCHAR(128) ) +LANGUAGE plpgsql +AS $$ +DECLARE + reserved_roles varchar[] := ARRAY['sysadmin', 'master_dbo', 'master_guest', 'master_db_owner', 'tempdb_dbo', 'tempdb_guest', 'tempdb_db_owner']; + user_id oid := -1; + db_name name := NULL; + role_name varchar; + dba_name varchar; +BEGIN + -- check reserved roles + FOREACH role_name IN ARRAY reserved_roles LOOP + BEGIN + SELECT oid INTO user_id FROM pg_roles WHERE rolname = role_name; + IF user_id > 0 THEN + SELECT datname INTO db_name FROM pg_shdepend AS s INNER JOIN pg_database AS d ON s.dbid = d.oid WHERE s.refobjid = user_id; + IF db_name IS NOT NULL THEN + RAISE E'Could not initialize babelfish in current database: Reserved role % used in database %.\nIf babelfish was initialized in %, please remove babelfish and try again.', role_name, db_name, db_name; + ELSE + RAISE E'Could not initialize babelfish in current database: Reserved role % exists. \nPlease rename or drop existing role and try again ', role_name; + END IF; + END IF; + END; + END LOOP; + + SELECT pg_get_userbyid(datdba) INTO dba_name FROM pg_database WHERE datname = CURRENT_DATABASE(); + IF sa_name <> dba_name THEN + RAISE E'Could not initialize babelfish with given role name: % is not the DB owner of current database.', sa_name; + END IF; + + EXECUTE format('CREATE ROLE sysadmin CREATEDB CREATEROLE INHERIT ROLE %I', sa_name); + EXECUTE format('GRANT USAGE, SELECT ON SEQUENCE sys.babelfish_db_seq TO sysadmin WITH GRANT OPTION'); + EXECUTE format('GRANT CREATE, CONNECT, TEMPORARY ON DATABASE %s TO sysadmin WITH GRANT OPTION', CURRENT_DATABASE()); + EXECUTE format('ALTER DATABASE %s SET babelfishpg_tsql.enable_ownership_structure = true', CURRENT_DATABASE()); + EXECUTE 'SET babelfishpg_tsql.enable_ownership_structure = true'; + CALL sys.babel_initialize_logins(sa_name); + CALL sys.babel_create_builtin_dbs(sa_name); +END +$$; + +CREATE OR REPLACE PROCEDURE remove_babelfish () +LANGUAGE plpgsql +AS $$ +BEGIN + CALL sys.babel_drop_all_dbs(); + CALL sys.babel_drop_all_logins(); + EXECUTE format('ALTER DATABASE %s SET babelfishpg_tsql.enable_ownership_structure = false', CURRENT_DATABASE()); + EXECUTE 'ALTER SEQUENCE sys.babelfish_db_seq RESTART'; + DROP OWNED BY sysadmin; + DROP ROLE sysadmin; +END +$$; + +-- LOGIN EXT +-- Note: change here requires change in FormData_authid_login_ext too +CREATE TABLE sys.babelfish_authid_login_ext ( +rolname NAME NOT NULL, -- pg_authid.rolname +is_disabled INT NOT NULL DEFAULT 0, -- to support enable/disable login +type CHAR(1) NOT NULL DEFAULT 'S', +credential_id INT NOT NULL, +owning_principal_id INT NOT NULL, +is_fixed_role INT NOT NULL DEFAULT 0, +create_date timestamptz NOT NULL, +modify_date timestamptz NOT NULL, +default_database_name SYS.NVARCHAR(128) NOT NULL, +default_language_name SYS.NVARCHAR(128) NOT NULL, +properties JSONB, +PRIMARY KEY (rolname)); +GRANT SELECT ON sys.babelfish_authid_login_ext TO PUBLIC; + +SELECT pg_catalog.pg_extension_config_dump('sys.babelfish_sysdatabases', ''); +SELECT pg_catalog.pg_extension_config_dump('sys.babelfish_db_seq', ''); +SELECT pg_catalog.pg_extension_config_dump('sys.babelfish_namespace_ext', ''); +SELECT pg_catalog.pg_extension_config_dump('sys.babelfish_authid_login_ext', ''); + +-- SERVER_PRINCIPALS +CREATE VIEW sys.server_principals +AS SELECT +CAST(Base.rolname 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, +Ext.type, +CAST(CASE WHEN Ext.type = 'S' THEN 'SQL_LOGIN' ELSE NULL END AS NVARCHAR(60)) AS type_desc, +Ext.is_disabled, +Ext.create_date, +Ext.modify_date, +Ext.default_database_name, +Ext.default_language_name, +Ext.credential_id, +Ext.owning_principal_id, +CAST(Ext.is_fixed_role AS sys.BIT) AS is_fixed_role +FROM pg_catalog.pg_authid AS Base INNER JOIN sys.babelfish_authid_login_ext AS Ext ON Base.rolname = Ext.rolname; + +GRANT SELECT ON sys.server_principals TO PUBLIC; + +-- internal table function for sp_helpdb with no arguments +CREATE OR REPLACE FUNCTION sys.babelfish_helpdb() +RETURNS table ( + name varchar(128), + db_size varchar(13), + owner varchar(128), + dbid int, + created varchar(11), + status varchar(600), + compatibility_level smallint +) AS 'babelfishpg_tsql', 'babelfish_helpdb' LANGUAGE C; + +-- internal table function for helpdb with dbname as input +CREATE OR REPLACE FUNCTION sys.babelfish_helpdb(varchar) +RETURNS table ( + name varchar(128), + db_size varchar(13), + owner varchar(128), + dbid int, + created varchar(11), + status varchar(600), + compatibility_level smallint +) AS 'babelfishpg_tsql', 'babelfish_helpdb' LANGUAGE C; + +create or replace view sys.databases as +select + d.name as name + , sys.db_id(d.name) as database_id + , null::integer as source_database_id + , cast(cast(r.oid as int) as varbinary(85)) as owner_sid + , CAST(d.crdate AS SYS.DATETIME) as create_date + , CAST(NULL AS SYS.TINYINT) as compatibility_level + , c.collname::sys.nvarchar(128) as collation_name + , 0 as user_access + , 'MULTI_USER'::varchar(60) as user_access_desc + , 0 as is_read_only + , 0 as is_auto_close_on + , 0 as is_auto_shrink_on + , 0 as state + , 'ONLINE'::varchar(60) as state_desc + , CASE + WHEN pg_is_in_recovery() is false THEN 0 + WHEN pg_is_in_recovery() is true THEN 1 + END as is_in_standby + , 0 as is_cleanly_shutdown + , 0 as is_supplemental_logging_enabled + , 1 as snapshot_isolation_state + , 'ON'::varchar(60) as snapshot_isolation_state_desc + , 1 as is_read_committed_snapshot_on + , 1 as recovery_model + , 'FULL'::varchar(60) as recovery_model_desc + , 0 as page_verify_option + , null::varchar(60) as page_verify_option_desc + , 1 as is_auto_create_stats_on + , 0 as is_auto_create_stats_incremental_on + , 0 as is_auto_update_stats_on + , 0 as is_auto_update_stats_async_on + , 0 as is_ansi_null_default_on + , 0 as is_ansi_nulls_on + , 0 as is_ansi_padding_on + , 0 as is_ansi_warnings_on + , 0 as is_arithabort_on + , 0 as is_concat_null_yields_null_on + , 0 as is_numeric_roundabort_on + , 0 as is_quoted_identifier_on + , 0 as is_recursive_triggers_on + , 0 as is_cursor_close_on_commit_on + , 0 as is_local_cursor_default + , 0 as is_fulltext_enabled + , 0 as is_trustworthy_on + , 0 as is_db_chaining_on + , 0 as is_parameterization_forced + , 0 as is_master_key_encrypted_by_server + , 0 as is_query_store_on + , 0 as is_published + , 0 as is_subscribed + , 0 as is_merge_published + , 0 as is_distributor + , 0 as is_sync_with_backup + , null::sys.UNIQUEIDENTIFIER as service_broker_guid + , 0 as is_broker_enabled + , 0 as log_reuse_wait + , 'NOTHING'::varchar(60) as log_reuse_wait_desc + , 0 as is_date_correlation_on + , 0 as is_cdc_enabled + , 0 as is_encrypted + , 0 as is_honor_broker_priority_on + , null::sys.UNIQUEIDENTIFIER as replica_id + , null::sys.UNIQUEIDENTIFIER as group_database_id + , null::int as resource_pool_id + , null::smallint as default_language_lcid + , null::sys.nvarchar(128) as default_language_name + , null::int as default_fulltext_language_lcid + , null::sys.nvarchar(128) as default_fulltext_language_name + , null::sys.bit as is_nested_triggers_on + , null::sys.bit as is_transform_noise_words_on + , null::smallint as two_digit_year_cutoff + , 0 as containment + , 'NONE'::varchar(60) as containment_desc + , 0 as target_recovery_time_in_seconds + , 0 as delayed_durability + , null::sys.nvarchar(60) as delayed_durability_desc + , 0 as is_memory_optimized_elevate_to_snapshot_on + , 0 as is_federation_member + , 0 as is_remote_data_archive_enabled + , 0 as is_mixed_page_allocation_on + , 0 as is_temporal_history_retention_enabled + , 0 as catalog_collation_type + , 'Not Applicable'::sys.nvarchar(60) as catalog_collation_type_desc + , null::sys.nvarchar(128) as physical_database_name + , 0 as is_result_set_caching_on + , 0 as is_accelerated_database_recovery_on + , 0 as is_tempdb_spill_to_remote_store + , 0 as is_stale_page_detection_on + , 0 as is_memory_optimized_enabled + , 0 as is_ledger_on + from sys.babelfish_sysdatabases d LEFT OUTER JOIN pg_catalog.pg_collation c ON d.default_collation = c.collname + LEFT OUTER JOIN pg_catalog.pg_roles r on r.rolname = d.owner; + +GRANT SELECT ON sys.databases TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.babelfish_inconsistent_metadata() +RETURNS table ( + object_type varchar(32), + schema_name varchar(128), + object_name varchar(128), + detail text +) AS 'babelfishpg_tsql', 'babelfish_inconsistent_metadata' LANGUAGE C; + diff --git a/contrib/babelfishpg_tsql/sql/sys.sql b/contrib/babelfishpg_tsql/sql/sys.sql new file mode 100644 index 00000000000..e670e557492 --- /dev/null +++ b/contrib/babelfishpg_tsql/sql/sys.sql @@ -0,0 +1,129 @@ +/* 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 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; +GRANT EXECUTE ON FUNCTION sys.sysdatetimeoffset() TO PUBLIC; + + +CREATE FUNCTION sys.sysutcdatetime() RETURNS sys.datetime2 + AS $$select (clock_timestamp() AT TIME ZONE 'UTC')::sys.datetime2;$$ + LANGUAGE SQL; +GRANT EXECUTE ON FUNCTION sys.sysutcdatetime() TO PUBLIC; + + +CREATE FUNCTION sys.getdate() RETURNS sys.datetime + AS $$select date_trunc('millisecond', clock_timestamp()::timestamp)::sys.datetime;$$ + LANGUAGE SQL; +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 FUNCTION sys.isnull(text,text) RETURNS text AS $$ + SELECT COALESCE($1,$2); +$$ +LANGUAGE SQL; +GRANT EXECUTE ON FUNCTION sys.isnull(text,text) TO PUBLIC; + +CREATE FUNCTION sys.isnull(boolean,boolean) RETURNS boolean AS $$ + SELECT COALESCE($1,$2); +$$ +LANGUAGE SQL; +GRANT EXECUTE ON FUNCTION sys.isnull(boolean,boolean) TO PUBLIC; + +CREATE FUNCTION sys.isnull(smallint,smallint) RETURNS smallint AS $$ + SELECT COALESCE($1,$2); +$$ +LANGUAGE SQL; +GRANT EXECUTE ON FUNCTION sys.isnull(smallint,smallint) TO PUBLIC; + +CREATE FUNCTION sys.isnull(integer,integer) RETURNS integer AS $$ + SELECT COALESCE($1,$2); +$$ +LANGUAGE SQL; +GRANT EXECUTE ON FUNCTION sys.isnull(integer,integer) TO PUBLIC; + +CREATE FUNCTION sys.isnull(bigint,bigint) RETURNS bigint AS $$ + SELECT COALESCE($1,$2); +$$ +LANGUAGE SQL; +GRANT EXECUTE ON FUNCTION sys.isnull(bigint,bigint) TO PUBLIC; + +CREATE FUNCTION sys.isnull(real,real) RETURNS real AS $$ + SELECT COALESCE($1,$2); +$$ +LANGUAGE SQL; +GRANT EXECUTE ON FUNCTION sys.isnull(real,real) TO PUBLIC; + +CREATE FUNCTION sys.isnull(double precision, double precision) RETURNS double precision AS $$ + SELECT COALESCE($1,$2); +$$ +LANGUAGE SQL; +GRANT EXECUTE ON FUNCTION sys.isnull(double precision, double precision) TO PUBLIC; + +CREATE FUNCTION sys.isnull(numeric,numeric) RETURNS numeric AS $$ + SELECT COALESCE($1,$2); +$$ +LANGUAGE SQL; +GRANT EXECUTE ON FUNCTION sys.isnull(numeric,numeric) TO PUBLIC; + +CREATE FUNCTION sys.isnull(date, date) RETURNS date AS $$ + SELECT COALESCE($1,$2); +$$ +LANGUAGE SQL; +GRANT EXECUTE ON FUNCTION sys.isnull(date,date) TO PUBLIC; + +CREATE FUNCTION sys.isnull(timestamp,timestamp) RETURNS timestamp AS $$ + SELECT COALESCE($1,$2); +$$ +LANGUAGE SQL; +GRANT EXECUTE ON FUNCTION sys.isnull(timestamp,timestamp) TO PUBLIC; + +CREATE FUNCTION sys.isnull(timestamp with time zone,timestamp with time zone) RETURNS timestamp with time zone AS $$ + SELECT COALESCE($1,$2); +$$ +LANGUAGE SQL; +GRANT EXECUTE ON FUNCTION sys.isnull(timestamp with time zone,timestamp with time zone) TO PUBLIC; + +/* Tsql tables */ +CREATE TABLE IF NOT EXISTS sys.service_settings +( + service character varying(50) NOT NULL + ,setting character varying(100) NOT NULL + ,value character varying +); +GRANT SELECT ON sys.service_settings TO PUBLIC; + +comment on table sys.service_settings is 'Settings for Extension Pack services'; +comment on column sys.service_settings.service is 'Service name'; +comment on column sys.service_settings.setting is 'Setting name'; +comment on column sys.service_settings.value is 'Setting value'; + +CREATE TABLE sys.versions +( + extpackcomponentname VARCHAR(256) NOT NULL, + componentversion VARCHAR(256) +); +GRANT SELECT ON sys.versions TO PUBLIC; + +CREATE TABLE sys.syslanguages ( + lang_id SMALLINT, + lang_name_pg VARCHAR(30), + lang_alias_pg VARCHAR(30), + lang_name_mssql VARCHAR(30), + lang_alias_mssql VARCHAR(30), + territory VARCHAR(50), + spec_culture VARCHAR(10), + lang_data_jsonb JSONB +) WITH (OIDS = FALSE); +GRANT SELECT ON sys.syslanguages TO PUBLIC; diff --git a/contrib/babelfishpg_tsql/sql/sys_cast.sql b/contrib/babelfishpg_tsql/sql/sys_cast.sql new file mode 100644 index 00000000000..1f5998841c6 --- /dev/null +++ b/contrib/babelfishpg_tsql/sql/sys_cast.sql @@ -0,0 +1,131 @@ +-- CAST and related functions. +-- Duplicate functions with arg TEXT since ANYELEMNT cannot handle type unknown. + + +CREATE OR REPLACE FUNCTION sys.babelfish_cast_floor_smallint(IN arg TEXT) +RETURNS SMALLINT +AS $BODY$ BEGIN + RETURN CAST(arg AS SMALLINT); +END; $BODY$ +LANGUAGE plpgsql; + + +CREATE OR REPLACE FUNCTION sys.babelfish_cast_floor_smallint(IN arg ANYELEMENT) +RETURNS SMALLINT +AS $BODY$ BEGIN + CASE pg_typeof(arg) + WHEN 'numeric'::regtype, 'double precision'::regtype, 'real'::regtype THEN + RETURN CAST(TRUNC(arg) AS SMALLINT); + WHEN 'sys.money'::regtype, 'sys.smallmoney'::regtype THEN + RETURN CAST(ROUND(arg) AS BIGINT); + ELSE + RETURN CAST(arg AS SMALLINT); + END CASE; +END; $BODY$ +LANGUAGE plpgsql; + + +CREATE OR REPLACE FUNCTION sys.babelfish_cast_floor_int(IN arg TEXT) +RETURNS INT +AS $BODY$ BEGIN + RETURN CAST(arg AS INT); +END; $BODY$ +LANGUAGE plpgsql; + + +CREATE OR REPLACE FUNCTION sys.babelfish_cast_floor_int(IN arg ANYELEMENT) +RETURNS INT +AS $BODY$ BEGIN + CASE pg_typeof(arg) + WHEN 'numeric'::regtype, 'double precision'::regtype, 'real'::regtype THEN + RETURN CAST(TRUNC(arg) AS INT); + WHEN 'sys.money'::regtype, 'sys.smallmoney'::regtype THEN + RETURN CAST(ROUND(arg) AS BIGINT); + ELSE + RETURN CAST(arg AS INT); + END CASE; +END; $BODY$ +LANGUAGE plpgsql; + + +CREATE OR REPLACE FUNCTION sys.babelfish_cast_floor_bigint(IN arg TEXT) +RETURNS BIGINT +AS $BODY$ BEGIN + RETURN CAST(arg AS BIGINT); +END; $BODY$ +LANGUAGE plpgsql; + + +CREATE OR REPLACE FUNCTION sys.babelfish_cast_floor_bigint(IN arg ANYELEMENT) +RETURNS BIGINT +AS $BODY$ BEGIN + CASE pg_typeof(arg) + WHEN 'numeric'::regtype, 'double precision'::regtype, 'real'::regtype THEN + RETURN CAST(TRUNC(arg) AS BIGINT); + WHEN 'sys.money'::regtype, 'sys.smallmoney'::regtype THEN + RETURN CAST(ROUND(arg) AS BIGINT); + ELSE + RETURN CAST(arg AS BIGINT); + END CASE; +END; $BODY$ +LANGUAGE plpgsql; + + +-- TRY_CAST helper functions +CREATE OR REPLACE FUNCTION sys.babelfish_try_cast_floor_smallint(IN arg TEXT) RETURNS SMALLINT +AS $BODY$ BEGIN + RETURN sys.babelfish_cast_floor_smallint(arg); + EXCEPTION WHEN OTHERS THEN RETURN NULL; +END; $BODY$ +LANGUAGE plpgsql; + + +CREATE OR REPLACE FUNCTION sys.babelfish_try_cast_floor_smallint(IN arg ANYELEMENT) RETURNS SMALLINT +AS $BODY$ BEGIN + RETURN sys.babelfish_cast_floor_smallint(arg); + EXCEPTION WHEN OTHERS THEN RETURN NULL; +END; $BODY$ +LANGUAGE plpgsql; + + +CREATE OR REPLACE FUNCTION sys.babelfish_try_cast_floor_int(IN arg TEXT) RETURNS INT +AS $BODY$ BEGIN + RETURN sys.babelfish_cast_floor_int(arg); + EXCEPTION WHEN OTHERS THEN RETURN NULL; +END; $BODY$ +LANGUAGE plpgsql; + + +CREATE OR REPLACE FUNCTION sys.babelfish_try_cast_floor_int(IN arg ANYELEMENT) RETURNS INT +AS $BODY$ BEGIN + RETURN sys.babelfish_cast_floor_int(arg); + EXCEPTION WHEN OTHERS THEN RETURN NULL; +END; $BODY$ +LANGUAGE plpgsql; + + +CREATE OR REPLACE FUNCTION sys.babelfish_try_cast_floor_bigint(IN arg TEXT) RETURNS BIGINT +AS $BODY$ BEGIN + RETURN sys.babelfish_cast_floor_bigint(arg); + EXCEPTION WHEN OTHERS THEN RETURN NULL; +END; $BODY$ +LANGUAGE plpgsql; + + +CREATE OR REPLACE FUNCTION sys.babelfish_try_cast_floor_bigint(IN arg ANYELEMENT) RETURNS BIGINT +AS $BODY$ BEGIN + RETURN sys.babelfish_cast_floor_bigint(arg); + EXCEPTION WHEN OTHERS THEN RETURN NULL; +END; $BODY$ +LANGUAGE plpgsql; + + +CREATE OR REPLACE FUNCTION sys.babelfish_try_cast_to_any(IN arg TEXT, INOUT output ANYELEMENT, IN typmod INT) +RETURNS ANYELEMENT +AS $BODY$ BEGIN + EXECUTE format('SELECT CAST(%L AS %s)', arg, format_type(pg_typeof(output), typmod)) INTO output; + EXCEPTION + WHEN OTHERS THEN + -- Do nothing. Output carries NULL. +END; $BODY$ +LANGUAGE plpgsql; diff --git a/contrib/babelfishpg_tsql/sql/sys_function_helpers.sql b/contrib/babelfishpg_tsql/sql/sys_function_helpers.sql new file mode 100644 index 00000000000..c61ddd2d233 --- /dev/null +++ b/contrib/babelfishpg_tsql/sql/sys_function_helpers.sql @@ -0,0 +1,10128 @@ +/* Tsql functions + */ + +CREATE OR REPLACE FUNCTION sys.babelfish_get_last_identity() +RETURNS INT8 +AS 'babelfishpg_tsql', 'get_last_identity' +LANGUAGE C; + +CREATE OR REPLACE FUNCTION sys.bbf_get_current_physical_schema_name(IN schemaname TEXT) +RETURNS TEXT +AS 'babelfishpg_tsql', 'get_current_physical_schema_name' +LANGUAGE C STABLE STRICT; + +CREATE OR REPLACE FUNCTION sys.babelfish_set_role(IN role_name TEXT) +RETURNS INT4 +AS 'babelfishpg_tsql', 'babelfish_set_role' +LANGUAGE C STRICT; + +CREATE OR REPLACE FUNCTION sys.babelfish_get_last_identity_numeric() +RETURNS numeric(38,0) AS +$BODY$ + SELECT sys.babelfish_get_last_identity()::numeric(38,0); +$BODY$ +LANGUAGE SQL; + +CREATE OR REPLACE FUNCTION sys.get_min_id_from_table(IN id_colname TEXT, + IN schemaname TEXT, + IN tablename TEXT, + OUT result INT8) +AS +$BODY$ +BEGIN + EXECUTE FORMAT('SELECT MIN(%I) FROM %I.%I', id_colname, schemaname, tablename) INTO result; +END +$BODY$ +LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION sys.get_max_id_from_table(IN id_colname TEXT, + IN schemaname TEXT, + IN tablename TEXT, + OUT result INT8) +AS +$BODY$ +BEGIN + EXECUTE FORMAT('SELECT MAX(%I) FROM %I.%I', id_colname, schemaname, tablename) INTO result; +END +$BODY$ +LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION sys.user_name_sysname() +RETURNS sys.SYSNAME AS +$BODY$ + SELECT COALESCE(sys.user_name(), ''); +$BODY$ +LANGUAGE SQL; + +CREATE OR REPLACE FUNCTION sys.babelfish_get_identity_param(IN tablename TEXT, IN optionname TEXT) +RETURNS INT8 +AS 'babelfishpg_tsql', 'get_identity_param' +LANGUAGE C STRICT; + +CREATE OR REPLACE FUNCTION sys.babelfish_get_identity_current(IN tablename TEXT) +RETURNS INT8 +AS 'babelfishpg_tsql', 'get_identity_current' +LANGUAGE C STRICT; + +create or replace function sys.babelfish_get_id_by_name(object_name text) +returns bigint as +$BODY$ +declare res bigint; +begin + execute 'select x''' || substring(encode(digest(object_name, 'sha1'), 'hex'), 1, 8) || '''::bigint' into res; + return res; +end; +$BODY$ +language plpgsql returns null on null input; + +create or replace function sys.babelfish_get_sequence_value(in sequence_name character varying) +returns bigint as +$BODY$ +declare + v_res bigint; +begin + execute 'select last_value from '|| sequence_name into v_res; + return v_res; +end; +$BODY$ +language plpgsql returns null on null input; + +CREATE OR REPLACE FUNCTION sys.babelfish_get_login_default_db(IN login_name TEXT) +RETURNS TEXT +AS 'babelfishpg_tsql', 'bbf_get_login_default_db' +LANGUAGE C STRICT; + +CREATE OR REPLACE FUNCTION sys.babelfish_conv_date_to_string(IN p_datatype TEXT, + IN p_dateval DATE, + IN p_style NUMERIC DEFAULT 20) +RETURNS TEXT +AS +$BODY$ +DECLARE + v_day VARCHAR; + v_dateval DATE; + v_style SMALLINT; + v_month SMALLINT; + v_resmask VARCHAR; + v_datatype VARCHAR; + v_language VARCHAR; + v_monthname VARCHAR; + v_resstring VARCHAR; + v_lengthexpr VARCHAR; + v_maxlength SMALLINT; + v_res_length SMALLINT; + v_err_message VARCHAR; + v_res_datatype VARCHAR; + v_lang_metadata_json JSONB; + VARCHAR_MAX CONSTANT SMALLINT := 8000; + NVARCHAR_MAX CONSTANT SMALLINT := 4000; + CONVERSION_LANG CONSTANT VARCHAR := ''; + DATATYPE_REGEXP CONSTANT VARCHAR := '^\s*(CHAR|NCHAR|VARCHAR|NVARCHAR|CHARACTER VARYING)\s*$'; + DATATYPE_MASK_REGEXP CONSTANT VARCHAR := '^\s*(?:CHAR|NCHAR|VARCHAR|NVARCHAR|CHARACTER VARYING)\s*\(\s*(\d+|MAX)\s*\)\s*$'; +BEGIN + v_datatype := upper(trim(p_datatype)); + v_style := floor(p_style)::SMALLINT; + + IF (scale(p_style) > 0) THEN + RAISE most_specific_type_mismatch; + ELSIF (NOT ((v_style BETWEEN 0 AND 13) OR + (v_style BETWEEN 20 AND 25) OR + (v_style BETWEEN 100 AND 113) OR + v_style IN (120, 121, 126, 127, 130, 131))) + THEN + RAISE invalid_parameter_value; + ELSIF (v_style IN (8, 24, 108)) THEN + RAISE invalid_datetime_format; + END IF; + + IF (v_datatype ~* DATATYPE_MASK_REGEXP) THEN + v_res_datatype := rtrim(split_part(v_datatype, '(', 1)); + + v_maxlength := CASE + WHEN (v_res_datatype IN ('CHAR', 'VARCHAR')) THEN VARCHAR_MAX + ELSE NVARCHAR_MAX + END; + + v_lengthexpr := substring(v_datatype, DATATYPE_MASK_REGEXP); + + IF (v_lengthexpr <> 'MAX' AND char_length(v_lengthexpr) > 4) THEN + RAISE interval_field_overflow; + END IF; + + v_res_length := CASE v_lengthexpr + WHEN 'MAX' THEN v_maxlength + ELSE v_lengthexpr::SMALLINT + END; + ELSIF (v_datatype ~* DATATYPE_REGEXP) THEN + v_res_datatype := v_datatype; + ELSE + RAISE datatype_mismatch; + END IF; + + v_dateval := CASE + WHEN (v_style NOT IN (130, 131)) THEN p_dateval + ELSE sys.babelfish_conv_greg_to_hijri(p_dateval) + 1 + END; + + v_day := ltrim(to_char(v_dateval, 'DD'), '0'); + v_month := to_char(v_dateval, 'MM')::SMALLINT; + + v_language := CASE + WHEN (v_style IN (130, 131)) THEN 'HIJRI' + ELSE CONVERSION_LANG + END; + BEGIN + v_lang_metadata_json := sys.babelfish_get_lang_metadata_json(v_language); + EXCEPTION + WHEN OTHERS THEN + RAISE invalid_character_value_for_cast; + END; + + v_monthname := (v_lang_metadata_json -> 'months_shortnames') ->> v_month - 1; + + v_resmask := CASE + WHEN (v_style IN (1, 22)) THEN 'MM/DD/YY' + WHEN (v_style = 101) THEN 'MM/DD/YYYY' + WHEN (v_style = 2) THEN 'YY.MM.DD' + WHEN (v_style = 102) THEN 'YYYY.MM.DD' + WHEN (v_style = 3) THEN 'DD/MM/YY' + WHEN (v_style = 103) THEN 'DD/MM/YYYY' + WHEN (v_style = 4) THEN 'DD.MM.YY' + WHEN (v_style = 104) THEN 'DD.MM.YYYY' + WHEN (v_style = 5) THEN 'DD-MM-YY' + WHEN (v_style = 105) THEN 'DD-MM-YYYY' + WHEN (v_style = 6) THEN 'DD $mnme$ YY' + WHEN (v_style IN (13, 106, 113)) THEN 'DD $mnme$ YYYY' + WHEN (v_style = 7) THEN '$mnme$ DD, YY' + WHEN (v_style = 107) THEN '$mnme$ DD, YYYY' + WHEN (v_style = 10) THEN 'MM-DD-YY' + WHEN (v_style = 110) THEN 'MM-DD-YYYY' + WHEN (v_style = 11) THEN 'YY/MM/DD' + WHEN (v_style = 111) THEN 'YYYY/MM/DD' + WHEN (v_style = 12) THEN 'YYMMDD' + WHEN (v_style = 112) THEN 'YYYYMMDD' + WHEN (v_style IN (20, 21, 23, 25, 120, 121, 126, 127)) THEN 'YYYY-MM-DD' + WHEN (v_style = 130) THEN 'DD $mnme$ YYYY' + WHEN (v_style = 131) THEN format('%s/MM/YYYY', lpad(v_day, 2, ' ')) + WHEN (v_style IN (0, 9, 100, 109)) THEN format('$mnme$ %s YYYY', lpad(v_day, 2, ' ')) + END; + + v_resstring := to_char(v_dateval, v_resmask); + v_resstring := replace(v_resstring, '$mnme$', v_monthname); + + v_resstring := substring(v_resstring, 1, coalesce(v_res_length, char_length(v_resstring))); + v_res_length := coalesce(v_res_length, + CASE v_res_datatype + WHEN 'CHAR' THEN 30 + ELSE 60 + END); + RETURN CASE + WHEN (v_res_datatype NOT IN ('CHAR', 'NCHAR')) THEN v_resstring + ELSE rpad(v_resstring, v_res_length, ' ') + END; +EXCEPTION + WHEN most_specific_type_mismatch THEN + RAISE USING MESSAGE := 'Argument data type NUMERIC is invalid for argument 3 of convert 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 := format('%s is not a valid style number when converting from DATE to a character string.', v_style), + DETAIL := 'Use of incorrect "style" parameter value during conversion process.', + HINT := 'Change "style" parameter to the proper value and try again.'; + + WHEN invalid_datetime_format THEN + RAISE USING MESSAGE := format('Error converting data type DATE to %s.', trim(p_datatype)), + 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 interval_field_overflow THEN + RAISE USING MESSAGE := format('The size (%s) given to the convert specification ''%s'' exceeds the maximum allowed for any data type (%s).', + v_lengthexpr, + lower(v_res_datatype), + v_maxlength), + DETAIL := 'Use of incorrect size value of data type parameter during conversion process.', + HINT := 'Change size component of data type parameter to the allowable value and try again.'; + + WHEN datatype_mismatch THEN + RAISE USING MESSAGE := 'Data type should be one of these values: ''CHAR(n|MAX)'', ''NCHAR(n|MAX)'', ''VARCHAR(n|MAX)'', ''NVARCHAR(n|MAX)''.', + DETAIL := 'Use of incorrect "datatype" parameter value during conversion process.', + HINT := 'Change "datatype" parameter to the proper value and try again.'; + + WHEN invalid_character_value_for_cast THEN + RAISE USING MESSAGE := 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 := format('Error while trying to convert "%s" value to SMALLINT (or INTEGER) data type.', + v_err_message), + DETAIL := 'Supplied value contains illegal characters.', + HINT := 'Correct supplied value, remove all illegal characters.'; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_conv_datetime_to_string(IN p_datatype TEXT, + IN p_src_datatype TEXT, + IN p_datetimeval TIMESTAMP(6) WITHOUT TIME ZONE, + IN p_style NUMERIC DEFAULT -1) +RETURNS TEXT +AS +$BODY$ +DECLARE + v_day VARCHAR; + v_hour VARCHAR; + v_month SMALLINT; + v_style SMALLINT; + v_scale SMALLINT; + v_resmask VARCHAR; + v_language VARCHAR; + v_datatype VARCHAR; + v_fseconds VARCHAR; + v_fractsep VARCHAR; + v_monthname VARCHAR; + v_resstring VARCHAR; + v_lengthexpr VARCHAR; + v_maxlength SMALLINT; + v_res_length SMALLINT; + v_err_message VARCHAR; + v_src_datatype VARCHAR; + v_res_datatype VARCHAR; + v_lang_metadata_json JSONB; + VARCHAR_MAX CONSTANT SMALLINT := 8000; + NVARCHAR_MAX CONSTANT SMALLINT := 4000; + CONVERSION_LANG CONSTANT VARCHAR := ''; + DATATYPE_REGEXP CONSTANT VARCHAR := '^\s*(CHAR|NCHAR|VARCHAR|NVARCHAR|CHARACTER VARYING)\s*$'; + SRCDATATYPE_MASK_REGEXP VARCHAR := '^(?:DATETIME|SMALLDATETIME|DATETIME2)\s*(?:\s*\(\s*(\d+)\s*\)\s*)?$'; + DATATYPE_MASK_REGEXP CONSTANT VARCHAR := '^\s*(?:CHAR|NCHAR|VARCHAR|NVARCHAR|CHARACTER VARYING)\s*\(\s*(\d+|MAX)\s*\)\s*$'; + v_datetimeval TIMESTAMP(6) WITHOUT TIME ZONE; +BEGIN + v_datatype := upper(trim(p_datatype)); + v_src_datatype := upper(trim(p_src_datatype)); + v_style := floor(p_style)::SMALLINT; + + IF (v_src_datatype ~* SRCDATATYPE_MASK_REGEXP) + THEN + v_scale := substring(v_src_datatype, SRCDATATYPE_MASK_REGEXP)::SMALLINT; + + v_src_datatype := rtrim(split_part(v_src_datatype, '(', 1)); + + IF (v_src_datatype <> 'DATETIME2' AND v_scale IS NOT NULL) THEN + RAISE invalid_indicator_parameter_value; + ELSIF (v_scale NOT BETWEEN 0 AND 7) THEN + RAISE invalid_regular_expression; + END IF; + + v_scale := coalesce(v_scale, 7); + ELSE + RAISE most_specific_type_mismatch; + END IF; + + IF (scale(p_style) > 0) THEN + RAISE escape_character_conflict; + 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 (-1, 120, 121, 126, 127, 130, 131))) + THEN + RAISE invalid_parameter_value; + END IF; + + IF (v_datatype ~* DATATYPE_MASK_REGEXP) THEN + v_res_datatype := rtrim(split_part(v_datatype, '(', 1)); + + v_maxlength := CASE + WHEN (v_res_datatype IN ('CHAR', 'VARCHAR')) THEN VARCHAR_MAX + ELSE NVARCHAR_MAX + END; + + v_lengthexpr := substring(v_datatype, DATATYPE_MASK_REGEXP); + + IF (v_lengthexpr <> 'MAX' AND char_length(v_lengthexpr) > 4) + THEN + RAISE interval_field_overflow; + END IF; + + v_res_length := CASE v_lengthexpr + WHEN 'MAX' THEN v_maxlength + ELSE v_lengthexpr::SMALLINT + END; + ELSIF (v_datatype ~* DATATYPE_REGEXP) THEN + v_res_datatype := v_datatype; + ELSE + RAISE datatype_mismatch; + END IF; + + v_datetimeval := CASE + WHEN (v_style NOT IN (130, 131)) THEN p_datetimeval + ELSE sys.babelfish_conv_greg_to_hijri(p_datetimeval) + INTERVAL '1 day' + END; + + v_day := ltrim(to_char(v_datetimeval, 'DD'), '0'); + v_hour := ltrim(to_char(v_datetimeval, 'HH12'), '0'); + v_month := to_char(v_datetimeval, 'MM')::SMALLINT; + + v_language := CASE + WHEN (v_style IN (130, 131)) THEN 'HIJRI' + ELSE CONVERSION_LANG + END; + BEGIN + v_lang_metadata_json := sys.babelfish_get_lang_metadata_json(v_language); + EXCEPTION + WHEN OTHERS THEN + RAISE invalid_character_value_for_cast; + END; + + v_monthname := (v_lang_metadata_json -> 'months_shortnames') ->> v_month - 1; + + IF (v_src_datatype IN ('DATETIME', 'SMALLDATETIME')) THEN + v_fseconds := sys.babelfish_round_fractseconds(to_char(v_datetimeval, 'MS')); + + IF (v_fseconds::INTEGER = 1000) THEN + v_fseconds := '000'; + v_datetimeval := v_datetimeval + INTERVAL '1 second'; + ELSE + v_fseconds := lpad(v_fseconds, 3, '0'); + END IF; + ELSE + v_fseconds := sys.babelfish_get_microsecs_from_fractsecs(to_char(v_datetimeval, 'US'), v_scale); + + IF (v_scale = 7) THEN + v_fseconds := concat(v_fseconds, '0'); + END IF; + END IF; + + v_fractsep := CASE v_src_datatype + WHEN 'DATETIME2' THEN '.' + ELSE ':' + END; + + IF ((v_style = -1 AND v_src_datatype <> 'DATETIME2') OR + v_style IN (0, 9, 100, 109)) + THEN + v_resmask := format('$mnme$ %s YYYY %s:MI%s', + lpad(v_day, 2, ' '), + lpad(v_hour, 2, ' '), + CASE + WHEN (v_style IN (-1, 0, 100)) THEN 'AM' + ELSE format(':SS:%sAM', v_fseconds) + END); + ELSIF (v_style = 1) THEN + v_resmask := 'MM/DD/YY'; + ELSIF (v_style = 101) THEN + v_resmask := 'MM/DD/YYYY'; + ELSIF (v_style = 2) THEN + v_resmask := 'YY.MM.DD'; + ELSIF (v_style = 102) THEN + v_resmask := 'YYYY.MM.DD'; + ELSIF (v_style = 3) THEN + v_resmask := 'DD/MM/YY'; + ELSIF (v_style = 103) THEN + v_resmask := 'DD/MM/YYYY'; + ELSIF (v_style = 4) THEN + v_resmask := 'DD.MM.YY'; + ELSIF (v_style = 104) THEN + v_resmask := 'DD.MM.YYYY'; + ELSIF (v_style = 5) THEN + v_resmask := 'DD-MM-YY'; + ELSIF (v_style = 105) THEN + v_resmask := 'DD-MM-YYYY'; + ELSIF (v_style = 6) THEN + v_resmask := 'DD $mnme$ YY'; + ELSIF (v_style = 106) THEN + v_resmask := 'DD $mnme$ YYYY'; + ELSIF (v_style = 7) THEN + v_resmask := '$mnme$ DD, YY'; + ELSIF (v_style = 107) THEN + v_resmask := '$mnme$ DD, YYYY'; + ELSIF (v_style IN (8, 24, 108)) THEN + v_resmask := 'HH24:MI:SS'; + ELSIF (v_style = 10) THEN + v_resmask := 'MM-DD-YY'; + ELSIF (v_style = 110) THEN + v_resmask := 'MM-DD-YYYY'; + ELSIF (v_style = 11) THEN + v_resmask := 'YY/MM/DD'; + ELSIF (v_style = 111) THEN + v_resmask := 'YYYY/MM/DD'; + ELSIF (v_style = 12) THEN + v_resmask := 'YYMMDD'; + ELSIF (v_style = 112) THEN + v_resmask := 'YYYYMMDD'; + ELSIF (v_style IN (13, 113)) THEN + v_resmask := format('DD $mnme$ YYYY HH24:MI:SS%s%s', v_fractsep, v_fseconds); + ELSIF (v_style IN (14, 114)) THEN + v_resmask := format('HH24:MI:SS%s%s', v_fractsep, v_fseconds); + ELSIF (v_style IN (20, 120)) THEN + v_resmask := 'YYYY-MM-DD HH24:MI:SS'; + ELSIF ((v_style = -1 AND v_src_datatype = 'DATETIME2') OR + v_style IN (21, 25, 121)) + THEN + v_resmask := format('YYYY-MM-DD HH24:MI:SS.%s', v_fseconds); + ELSIF (v_style = 22) THEN + v_resmask := format('MM/DD/YY %s:MI:SS AM', lpad(v_hour, 2, ' ')); + ELSIF (v_style = 23) THEN + v_resmask := 'YYYY-MM-DD'; + ELSIF (v_style IN (126, 127)) THEN + v_resmask := CASE v_src_datatype + WHEN 'SMALLDATETIME' THEN 'YYYY-MM-DDT$rem$HH24:MI:SS' + ELSE format('YYYY-MM-DDT$rem$HH24:MI:SS.%s', v_fseconds) + END; + ELSIF (v_style IN (130, 131)) THEN + v_resmask := concat(CASE p_style + WHEN 131 THEN format('%s/MM/YYYY ', lpad(v_day, 2, ' ')) + ELSE format('%s $mnme$ YYYY ', lpad(v_day, 2, ' ')) + END, + format('%s:MI:SS%s%sAM', lpad(v_hour, 2, ' '), v_fractsep, v_fseconds)); + END IF; + + v_resstring := to_char(v_datetimeval, v_resmask); + v_resstring := replace(v_resstring, '$mnme$', v_monthname); + v_resstring := replace(v_resstring, '$rem$', ''); + + v_resstring := substring(v_resstring, 1, coalesce(v_res_length, char_length(v_resstring))); + v_res_length := coalesce(v_res_length, + CASE v_res_datatype + WHEN 'CHAR' THEN 30 + ELSE 60 + END); + RETURN CASE + WHEN (v_res_datatype NOT IN ('CHAR', 'NCHAR')) THEN v_resstring + ELSE rpad(v_resstring, v_res_length, ' ') + END; +EXCEPTION + WHEN most_specific_type_mismatch THEN + RAISE USING MESSAGE := 'Source data type should be one of these values: ''DATETIME'', ''SMALLDATETIME'', ''DATETIME2'' or ''DATETIME2(n)''.', + DETAIL := 'Use of incorrect "src_datatype" parameter value during conversion process.', + HINT := 'Change "srcdatatype" parameter to the proper value and try again.'; + + WHEN invalid_regular_expression THEN + RAISE USING MESSAGE := format('The source data type scale (%s) given to the convert specification exceeds the maximum allowable value (7).', + v_scale), + DETAIL := 'Use of incorrect scale value of source data type parameter during conversion process.', + HINT := 'Change scale component of source data type parameter to the allowable value and try again.'; + + WHEN invalid_indicator_parameter_value THEN + RAISE USING MESSAGE := format('Invalid attributes specified for data type %s.', v_src_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 escape_character_conflict THEN + RAISE USING MESSAGE := 'Argument data type NUMERIC is invalid for argument 4 of convert 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 := format('%s is not a valid style number when converting from %s to a character string.', + v_style, v_src_datatype), + DETAIL := 'Use of incorrect "style" parameter value during conversion process.', + HINT := 'Change "style" parameter to the proper value and try again.'; + + WHEN interval_field_overflow THEN + RAISE USING MESSAGE := format('The size (%s) given to the convert specification ''%s'' exceeds the maximum allowed for any data type (%s).', + v_lengthexpr, lower(v_res_datatype), v_maxlength), + DETAIL := 'Use of incorrect size value of data type parameter during conversion process.', + HINT := 'Change size component of data type parameter to the allowable value and try again.'; + + WHEN datatype_mismatch THEN + RAISE USING MESSAGE := 'Data type should be one of these values: ''CHAR(n|MAX)'', ''NCHAR(n|MAX)'', ''VARCHAR(n|MAX)'', ''NVARCHAR(n|MAX)''.', + DETAIL := 'Use of incorrect "datatype" parameter value during conversion process.', + HINT := 'Change "datatype" parameter to the proper value and try again.'; + + WHEN invalid_character_value_for_cast THEN + RAISE USING MESSAGE := 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 := format('Error while trying to convert "%s" value to SMALLINT data type.', + v_err_message), + DETAIL := 'Supplied value contains illegal characters.', + HINT := 'Correct supplied value, remove all illegal characters.'; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_conv_greg_to_hijri(IN p_dateval DATE) +RETURNS DATE +AS +$BODY$ +BEGIN + RETURN sys.babelfish_conv_greg_to_hijri(extract(day from p_dateval)::NUMERIC, + extract(month from p_dateval)::NUMERIC, + extract(year from p_dateval)::NUMERIC); +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_conv_greg_to_hijri(IN p_day NUMERIC, + IN p_month NUMERIC, + IN p_year NUMERIC) +RETURNS DATE +AS +$BODY$ +DECLARE + v_day SMALLINT; + v_month SMALLINT; + v_year INTEGER; + v_jdnum DOUBLE PRECISION; + v_lnum DOUBLE PRECISION; + v_inum DOUBLE PRECISION; + v_nnum DOUBLE PRECISION; + v_jnum DOUBLE PRECISION; +BEGIN + v_day := floor(p_day)::SMALLINT; + v_month := floor(p_month)::SMALLINT; + v_year := floor(p_year)::INTEGER; + + IF ((sign(v_day) = -1) OR (sign(v_month) = -1) OR (sign(v_year) = -1)) + THEN + RAISE invalid_character_value_for_cast; + ELSIF (v_year = 0) THEN + RAISE null_value_not_allowed; + END IF; + + IF ((p_year > 1582) OR ((p_year = 1582) AND (p_month > 10)) OR ((p_year = 1582) AND (p_month = 10) AND (p_day > 14))) + THEN + v_jdnum := sys.babelfish_get_int_part((1461 * (p_year + 4800 + sys.babelfish_get_int_part((p_month - 14) / 12))) / 4) + + sys.babelfish_get_int_part((367 * (p_month - 2 - 12 * (sys.babelfish_get_int_part((p_month - 14) / 12)))) / 12) - + sys.babelfish_get_int_part((3 * (sys.babelfish_get_int_part((p_year + 4900 + + sys.babelfish_get_int_part((p_month - 14) / 12)) / 100))) / 4) + p_day - 32075; + ELSE + v_jdnum := 367 * p_year - sys.babelfish_get_int_part((7 * (p_year + 5001 + + sys.babelfish_get_int_part((p_month - 9) / 7))) / 4) + + sys.babelfish_get_int_part((275 * p_month) / 9) + p_day + 1729777; + END IF; + + v_lnum := v_jdnum - 1948440 + 10632; + v_nnum := sys.babelfish_get_int_part((v_lnum - 1) / 10631); + v_lnum := v_lnum - 10631 * v_nnum + 354; + v_jnum := (sys.babelfish_get_int_part((10985 - v_lnum) / 5316)) * (sys.babelfish_get_int_part((50 * v_lnum) / 17719)) + + (sys.babelfish_get_int_part(v_lnum / 5670)) * (sys.babelfish_get_int_part((43 * v_lnum) / 15238)); + v_lnum := v_lnum - (sys.babelfish_get_int_part((30 - v_jnum) / 15)) * (sys.babelfish_get_int_part((17719 * v_jnum) / 50)) - + (sys.babelfish_get_int_part(v_jnum / 16)) * (sys.babelfish_get_int_part((15238 * v_jnum) / 43)) + 29; + + v_month := sys.babelfish_get_int_part((24 * v_lnum) / 709); + v_day := v_lnum - sys.babelfish_get_int_part((709 * v_month) / 24); + v_year := 30 * v_nnum + v_jnum - 30; + + RETURN to_date(concat_ws('.', v_day, v_month, v_year), 'DD.MM.YYYY'); +EXCEPTION + WHEN invalid_character_value_for_cast THEN + RAISE USING MESSAGE := 'Could not convert Gregorian to Hijri date if any part of the date is negative.', + DETAIL := 'Some of the supplied date parts (day, month, year) is negative.', + HINT := 'Change the value of the date part (day, month, year) wich was found to be negative.'; + + WHEN null_value_not_allowed THEN + RAISE USING MESSAGE := 'Could not convert Gregorian to Hijri date if year value is equal to zero.', + DETAIL := 'Supplied year value is equal to zero.', + HINT := 'Change the value of the year so that it is greater than zero.'; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_conv_greg_to_hijri(IN p_day TEXT, + IN p_month TEXT, + IN p_year TEXT) +RETURNS DATE +AS +$BODY$ +BEGIN + RETURN sys.babelfish_conv_greg_to_hijri(p_day::NUMERIC, + p_month::NUMERIC, + p_year::NUMERIC); +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_conv_greg_to_hijri(IN p_datetimeval TIMESTAMP WITHOUT TIME ZONE) +RETURNS TIMESTAMP WITHOUT TIME ZONE +AS +$BODY$ +DECLARE + v_hijri_date DATE; +BEGIN + v_hijri_date := sys.babelfish_conv_greg_to_hijri(extract(day from p_datetimeval)::SMALLINT, + extract(month from p_datetimeval)::SMALLINT, + extract(year from p_datetimeval)::INTEGER); + + RETURN to_timestamp(format('%s %s', to_char(v_hijri_date, 'DD.MM.YYYY'), + to_char(p_datetimeval, ' HH24:MI:SS.US')), + 'DD.MM.YYYY HH24:MI:SS.US'); +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_conv_hijri_to_greg(IN p_dateval DATE) +RETURNS DATE +AS +$BODY$ +BEGIN + RETURN sys.babelfish_conv_hijri_to_greg(extract(day from p_dateval)::NUMERIC, + extract(month from p_dateval)::NUMERIC, + extract(year from p_dateval)::NUMERIC); +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_conv_hijri_to_greg(IN p_day NUMERIC, + IN p_month NUMERIC, + IN p_year NUMERIC) +RETURNS DATE +AS +$BODY$ +DECLARE + v_day SMALLINT; + v_month SMALLINT; + v_year INTEGER; + v_err_message VARCHAR; + v_jdnum DOUBLE PRECISION; + v_lnum DOUBLE PRECISION; + v_inum DOUBLE PRECISION; + v_nnum DOUBLE PRECISION; + v_jnum DOUBLE PRECISION; + v_knum DOUBLE PRECISION; +BEGIN + v_day := floor(p_day)::SMALLINT; + v_month := floor(p_month)::SMALLINT; + v_year := floor(p_year)::INTEGER; + + IF ((sign(v_day) = -1) OR (sign(v_month) = -1) OR (sign(v_year) = -1)) + THEN + RAISE invalid_character_value_for_cast; + ELSIF (v_year = 0) THEN + RAISE null_value_not_allowed; + END IF; + + v_jdnum = sys.babelfish_get_int_part((11 * v_year + 3) / 30) + 354 * v_year + 30 * v_month - + sys.babelfish_get_int_part((v_month - 1) / 2) + v_day + 1948440 - 385; + + IF (v_jdnum > 2299160) + THEN + v_lnum := v_jdnum + 68569; + v_nnum := sys.babelfish_get_int_part((4 * v_lnum) / 146097); + v_lnum := v_lnum - sys.babelfish_get_int_part((146097 * v_nnum + 3) / 4); + v_inum := sys.babelfish_get_int_part((4000 * (v_lnum + 1)) / 1461001); + v_lnum := v_lnum - sys.babelfish_get_int_part((1461 * v_inum) / 4) + 31; + v_jnum := sys.babelfish_get_int_part((80 * v_lnum) / 2447); + v_day := v_lnum - sys.babelfish_get_int_part((2447 * v_jnum) / 80); + v_lnum := sys.babelfish_get_int_part(v_jnum / 11); + v_month := v_jnum + 2 - 12 * v_lnum; + v_year := 100 * (v_nnum - 49) + v_inum + v_lnum; + ELSE + v_jnum := v_jdnum + 1402; + v_knum := sys.babelfish_get_int_part((v_jnum - 1) / 1461); + v_lnum := v_jnum - 1461 * v_knum; + v_nnum := sys.babelfish_get_int_part((v_lnum - 1) / 365) - sys.babelfish_get_int_part(v_lnum / 1461); + v_inum := v_lnum - 365 * v_nnum + 30; + v_jnum := sys.babelfish_get_int_part((80 * v_inum) / 2447); + v_day := v_inum-sys.babelfish_get_int_part((2447 * v_jnum) / 80); + v_inum := sys.babelfish_get_int_part(v_jnum / 11); + v_month := v_jnum + 2 - 12 * v_inum; + v_year := 4 * v_knum + v_nnum + v_inum - 4716; + END IF; + + RETURN to_date(concat_ws('.', v_day, v_month, v_year), 'DD.MM.YYYY'); +EXCEPTION + WHEN invalid_character_value_for_cast THEN + RAISE USING MESSAGE := 'Could not convert Hijri to Gregorian date if any part of the date is negative.', + DETAIL := 'Some of the supplied date parts (day, month, year) is negative.', + HINT := 'Change the value of the date part (day, month, year) wich was found to be negative.'; + + WHEN null_value_not_allowed THEN + RAISE USING MESSAGE := 'Could not convert Hijri to Gregorian date if year value is equal to zero.', + DETAIL := 'Supplied year value is equal to zero.', + HINT := 'Change the value of the year so that it is greater than zero.'; + + 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 := format('Error while trying to convert "%s" value to SMALLINT data type.', v_err_message), + DETAIL := 'Supplied value contains illegal characters.', + HINT := 'Correct supplied value, remove all illegal characters.'; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_conv_hijri_to_greg(IN p_day TEXT, + IN p_month TEXT, + IN p_year TEXT) +RETURNS DATE +AS +$BODY$ +BEGIN + RETURN sys.babelfish_conv_hijri_to_greg(p_day::NUMERIC, + p_month::NUMERIC, + p_year::NUMERIC); +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_conv_hijri_to_greg(IN p_datetimeval TIMESTAMP WITHOUT TIME ZONE) +RETURNS TIMESTAMP WITHOUT TIME ZONE +AS +$BODY$ +DECLARE + v_hijri_date DATE; +BEGIN + v_hijri_date := sys.babelfish_conv_hijri_to_greg(extract(day from p_dateval)::NUMERIC, + extract(month from p_dateval)::NUMERIC, + extract(year from p_dateval)::NUMERIC); + + RETURN to_timestamp(format('%s %s', to_char(v_hijri_date, 'DD.MM.YYYY'), + to_char(p_datetimeval, ' HH24:MI:SS.US')), + 'DD.MM.YYYY HH24:MI:SS.US'); +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_conv_string_to_date(IN p_datestring TEXT, + IN p_style NUMERIC DEFAULT 0) +RETURNS DATE +AS +$BODY$ +DECLARE + v_day VARCHAR; + v_year VARCHAR; + v_month VARCHAR; + v_hijridate DATE; + v_style SMALLINT; + v_leftpart VARCHAR; + v_middlepart VARCHAR; + v_rightpart VARCHAR; + v_fractsecs VARCHAR; + v_datestring VARCHAR; + v_err_message VARCHAR; + v_date_format VARCHAR; + v_regmatch_groups TEXT[]; + v_lang_metadata_json JSONB; + v_compmonth_regexp VARCHAR; + CONVERSION_LANG CONSTANT VARCHAR := ''; + DATE_FORMAT CONSTANT VARCHAR := ''; + DAYMM_REGEXP CONSTANT VARCHAR := '(\d{1,2})'; + FULLYEAR_REGEXP CONSTANT VARCHAR := '(\d{4})'; + SHORTYEAR_REGEXP CONSTANT VARCHAR := '(\d{1,2})'; + COMPYEAR_REGEXP CONSTANT VARCHAR := '(\d{1,2}|\d{4})'; + AMPM_REGEXP CONSTANT VARCHAR := '(?:[AP]M)'; + TIMEUNIT_REGEXP CONSTANT VARCHAR := '\s*\d{1,2}\s*'; + FRACTSECS_REGEXP CONSTANT VARCHAR := '\s*\d{1,9}'; + HHMMSSFS_PART_REGEXP CONSTANT VARCHAR := concat('(', TIMEUNIT_REGEXP, AMPM_REGEXP, '|', + TIMEUNIT_REGEXP, '\:', TIMEUNIT_REGEXP, '|', + TIMEUNIT_REGEXP, '\:', TIMEUNIT_REGEXP, '\:', TIMEUNIT_REGEXP, '|', + TIMEUNIT_REGEXP, '\:', TIMEUNIT_REGEXP, '\:', TIMEUNIT_REGEXP, '(?:\.|\:)', FRACTSECS_REGEXP, + ')\s*', AMPM_REGEXP, '?'); + HHMMSSFS_DOTPART_REGEXP CONSTANT VARCHAR := concat('(', TIMEUNIT_REGEXP, AMPM_REGEXP, '|', + TIMEUNIT_REGEXP, '\:', TIMEUNIT_REGEXP, '|', + TIMEUNIT_REGEXP, '\:', TIMEUNIT_REGEXP, '\:', TIMEUNIT_REGEXP, '|', + TIMEUNIT_REGEXP, '\:', TIMEUNIT_REGEXP, '\:', TIMEUNIT_REGEXP, '\.', FRACTSECS_REGEXP, + ')\s*', AMPM_REGEXP, '?'); + HHMMSSFS_REGEXP CONSTANT VARCHAR := concat('^', HHMMSSFS_PART_REGEXP, '$'); + HHMMSSFS_DOT_REGEXP CONSTANT VARCHAR := concat('^', HHMMSSFS_DOTPART_REGEXP, '$'); + v_defmask1_regexp VARCHAR := concat('^($comp_month$)\s*', DAYMM_REGEXP, '\s+', COMPYEAR_REGEXP, '$'); + v_defmask2_regexp VARCHAR := concat('^', DAYMM_REGEXP, '\s*($comp_month$)\s*', COMPYEAR_REGEXP, '$'); + v_defmask3_regexp VARCHAR := concat('^', FULLYEAR_REGEXP, '\s*($comp_month$)\s*', DAYMM_REGEXP, '$'); + v_defmask4_regexp VARCHAR := concat('^', FULLYEAR_REGEXP, '\s+', DAYMM_REGEXP, '\s*($comp_month$)$'); + v_defmask5_regexp VARCHAR := concat('^', DAYMM_REGEXP, '\s+', COMPYEAR_REGEXP, '\s*($comp_month$)$'); + v_defmask6_regexp VARCHAR := concat('^($comp_month$)\s*', FULLYEAR_REGEXP, '\s+', DAYMM_REGEXP, '$'); + v_defmask7_regexp VARCHAR := concat('^($comp_month$)\s*', DAYMM_REGEXP, '\s*\,\s*', COMPYEAR_REGEXP, '$'); + v_defmask8_regexp VARCHAR := concat('^', FULLYEAR_REGEXP, '\s*($comp_month$)$'); + v_defmask9_regexp VARCHAR := concat('^($comp_month$)\s*', FULLYEAR_REGEXP, '$'); + v_defmask10_regexp VARCHAR := concat('^', DAYMM_REGEXP, '\s*(?:\.|/|-)\s*($comp_month$)\s*(?:\.|/|-)\s*', COMPYEAR_REGEXP, '$'); + DOT_SHORTYEAR_REGEXP CONSTANT VARCHAR := concat('^', DAYMM_REGEXP, '\s*\.\s*', DAYMM_REGEXP, '\s*\.\s*', SHORTYEAR_REGEXP, '$'); + DOT_FULLYEAR_REGEXP CONSTANT VARCHAR := concat('^', DAYMM_REGEXP, '\s*\.\s*', DAYMM_REGEXP, '\s*\.\s*', FULLYEAR_REGEXP, '$'); + SLASH_SHORTYEAR_REGEXP CONSTANT VARCHAR := concat('^', DAYMM_REGEXP, '\s*/\s*', DAYMM_REGEXP, '\s*/\s*', SHORTYEAR_REGEXP, '$'); + SLASH_FULLYEAR_REGEXP CONSTANT VARCHAR := concat('^', DAYMM_REGEXP, '\s*/\s*', DAYMM_REGEXP, '\s*/\s*', FULLYEAR_REGEXP, '$'); + DASH_SHORTYEAR_REGEXP CONSTANT VARCHAR := concat('^', DAYMM_REGEXP, '\s*-\s*', DAYMM_REGEXP, '\s*-\s*', SHORTYEAR_REGEXP, '$'); + DASH_FULLYEAR_REGEXP CONSTANT VARCHAR := concat('^', DAYMM_REGEXP, '\s*-\s*', DAYMM_REGEXP, '\s*-\s*', FULLYEAR_REGEXP, '$'); + DOT_SLASH_DASH_YEAR_REGEXP CONSTANT VARCHAR := concat('^', DAYMM_REGEXP, '\s*(?:\.|/|-)\s*', DAYMM_REGEXP, '\s*(?:\.|/|-)\s*', COMPYEAR_REGEXP, '$'); + YEAR_DOTMASK_REGEXP CONSTANT VARCHAR := concat('^', FULLYEAR_REGEXP, '\s*\.\s*', DAYMM_REGEXP, '\s*\.\s*', DAYMM_REGEXP, '$'); + YEAR_SLASHMASK_REGEXP CONSTANT VARCHAR := concat('^', FULLYEAR_REGEXP, '\s*/\s*', DAYMM_REGEXP, '\s*/\s*', DAYMM_REGEXP, '$'); + YEAR_DASHMASK_REGEXP CONSTANT VARCHAR := concat('^', FULLYEAR_REGEXP, '\s*-\s*', DAYMM_REGEXP, '\s*-\s*', DAYMM_REGEXP, '$'); + YEAR_DOT_SLASH_DASH_REGEXP CONSTANT VARCHAR := concat('^', FULLYEAR_REGEXP, '\s*(?:\.|/|-)\s*', DAYMM_REGEXP, '\s*(?:\.|/|-)\s*', DAYMM_REGEXP, '$'); + DIGITMASK1_REGEXP CONSTANT VARCHAR := '^\d{6}$'; + DIGITMASK2_REGEXP CONSTANT VARCHAR := '^\d{8}$'; +BEGIN + v_style := floor(p_style)::SMALLINT; + v_datestring := trim(p_datestring); + + 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))) + THEN + RAISE invalid_parameter_value; + END IF; + + IF (v_datestring ~* HHMMSSFS_PART_REGEXP AND v_datestring !~* HHMMSSFS_REGEXP) + THEN + v_datestring := trim(regexp_replace(v_datestring, HHMMSSFS_PART_REGEXP, '', 'gi')); + END IF; + + BEGIN + v_lang_metadata_json := sys.babelfish_get_lang_metadata_json(CONVERSION_LANG); + EXCEPTION + WHEN OTHERS THEN + RAISE invalid_character_value_for_cast; + 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'))), '|'); + + v_defmask1_regexp := replace(v_defmask1_regexp, '$comp_month$', v_compmonth_regexp); + v_defmask2_regexp := replace(v_defmask2_regexp, '$comp_month$', v_compmonth_regexp); + v_defmask3_regexp := replace(v_defmask3_regexp, '$comp_month$', v_compmonth_regexp); + v_defmask4_regexp := replace(v_defmask4_regexp, '$comp_month$', v_compmonth_regexp); + v_defmask5_regexp := replace(v_defmask5_regexp, '$comp_month$', v_compmonth_regexp); + v_defmask6_regexp := replace(v_defmask6_regexp, '$comp_month$', v_compmonth_regexp); + v_defmask7_regexp := replace(v_defmask7_regexp, '$comp_month$', v_compmonth_regexp); + v_defmask8_regexp := replace(v_defmask8_regexp, '$comp_month$', v_compmonth_regexp); + v_defmask9_regexp := replace(v_defmask9_regexp, '$comp_month$', v_compmonth_regexp); + v_defmask10_regexp := replace(v_defmask10_regexp, '$comp_month$', v_compmonth_regexp); + + IF (v_datestring ~* v_defmask1_regexp OR + v_datestring ~* v_defmask2_regexp OR + v_datestring ~* v_defmask3_regexp OR + v_datestring ~* v_defmask4_regexp OR + v_datestring ~* v_defmask5_regexp OR + v_datestring ~* v_defmask6_regexp OR + v_datestring ~* v_defmask7_regexp OR + v_datestring ~* v_defmask8_regexp OR + v_datestring ~* v_defmask9_regexp OR + v_datestring ~* v_defmask10_regexp) + THEN + IF (v_style IN (130, 131)) THEN + RAISE invalid_datetime_format; + END IF; + + IF (v_datestring ~* v_defmask1_regexp) + THEN + v_regmatch_groups := regexp_matches(v_datestring, v_defmask1_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 ~* v_defmask2_regexp) + THEN + v_regmatch_groups := regexp_matches(v_datestring, v_defmask2_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 ~* v_defmask3_regexp) + THEN + v_regmatch_groups := regexp_matches(v_datestring, v_defmask3_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 ~* v_defmask4_regexp) + THEN + v_regmatch_groups := regexp_matches(v_datestring, v_defmask4_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 ~* v_defmask5_regexp) + THEN + v_regmatch_groups := regexp_matches(v_datestring, v_defmask5_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 ~* v_defmask6_regexp) + THEN + v_regmatch_groups := regexp_matches(v_datestring, v_defmask6_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 ~* v_defmask7_regexp) + THEN + v_regmatch_groups := regexp_matches(v_datestring, v_defmask7_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 ~* v_defmask8_regexp) + THEN + v_regmatch_groups := regexp_matches(v_datestring, v_defmask8_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 ~* v_defmask9_regexp) + THEN + v_regmatch_groups := regexp_matches(v_datestring, v_defmask9_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]; + ELSE + v_regmatch_groups := regexp_matches(v_datestring, v_defmask10_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]); + END IF; + ELSEIF (v_datestring ~* DOT_SHORTYEAR_REGEXP OR + v_datestring ~* DOT_FULLYEAR_REGEXP OR + v_datestring ~* SLASH_SHORTYEAR_REGEXP OR + v_datestring ~* SLASH_FULLYEAR_REGEXP OR + v_datestring ~* DASH_SHORTYEAR_REGEXP OR + v_datestring ~* DASH_FULLYEAR_REGEXP) + THEN + IF (v_style IN (6, 7, 8, 9, 12, 13, 14, 24, 100, 106, 107, 108, 109, 112, 113, 114, 130)) THEN + RAISE invalid_regular_expression; + ELSIF (v_style IN (20, 21, 23, 25, 102, 111, 120, 121, 126, 127)) THEN + RAISE invalid_datetime_format; + END IF; + + v_regmatch_groups := regexp_matches(v_datestring, DOT_SLASH_DASH_YEAR_REGEXP, 'gi'); + v_leftpart := v_regmatch_groups[1]; + v_middlepart := v_regmatch_groups[2]; + v_rightpart := v_regmatch_groups[3]; + + IF (v_datestring ~* DOT_SHORTYEAR_REGEXP OR + v_datestring ~* SLASH_SHORTYEAR_REGEXP OR + v_datestring ~* DASH_SHORTYEAR_REGEXP) + THEN + IF ((v_style IN (1, 10, 22) AND v_date_format <> 'MDY') OR + ((v_style IS NULL OR v_style IN (0, 1, 10, 22)) AND v_date_format NOT IN ('YDM', 'YMD', 'DMY', 'DYM', 'MYD'))) + 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 IS NULL 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 IS NULL 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 IS NULL OR 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 IS NULL OR 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 IS NULL OR v_style = 0) AND v_date_format = 'YDM') THEN + RAISE character_not_in_repertoire; + ELSIF (v_style IN (101, 103, 104, 105, 110, 131)) THEN + RAISE invalid_datetime_format; + END IF; + ELSE + v_year := v_rightpart; + + IF (v_leftpart::SMALLINT <= 12) + THEN + IF ((v_style IN (103, 104, 105, 131) AND v_date_format <> 'DMY') OR + ((v_style IS NULL OR v_style IN (0, 103, 104, 105, 131)) AND v_date_format = 'DMY')) + THEN + v_day := v_leftpart; + v_month := v_middlepart; + ELSIF ((v_style IN (101, 110) AND v_date_format IN ('YDM', 'DMY', 'DYM')) OR + ((v_style IS NULL OR v_style IN (0, 101, 110)) AND v_date_format NOT IN ('YDM', 'DMY', 'DYM'))) + THEN + v_day := v_middlepart; + v_month := v_leftpart; + ELSIF ((v_style IN (1, 2, 3, 4, 5, 10, 11, 22) AND v_date_format <> 'YDM') OR + ((v_style IS NULL OR v_style IN (0, 1, 2, 3, 4, 5, 10, 11, 22)) AND v_date_format = 'YDM')) + THEN + RAISE invalid_datetime_format; + END IF; + ELSE + IF ((v_style IN (103, 104, 105, 131) AND v_date_format <> 'DMY') OR + ((v_style IS NULL OR v_style IN (0, 103, 104, 105, 131)) AND v_date_format = 'DMY')) + THEN + v_day := v_leftpart; + v_month := v_middlepart; + ELSIF ((v_style IN (1, 2, 3, 4, 5, 10, 11, 22, 101, 110) AND v_date_format = 'DMY') OR + ((v_style IS NULL OR v_style IN (0, 1, 2, 3, 4, 5, 10, 11, 22, 101, 110)) AND v_date_format <> 'DMY')) + THEN + RAISE invalid_datetime_format; + END IF; + END IF; + END IF; + ELSIF (v_datestring ~* YEAR_DOTMASK_REGEXP OR + v_datestring ~* YEAR_SLASHMASK_REGEXP OR + v_datestring ~* YEAR_DASHMASK_REGEXP) + THEN + IF (v_style IN (6, 7, 8, 9, 12, 13, 14, 24, 100, 106, 107, 108, 109, 112, 113, 114, 130)) THEN + RAISE invalid_regular_expression; + ELSIF (v_style IN (1, 2, 3, 4, 5, 10, 11, 22, 101, 103, 104, 105, 110, 131)) THEN + RAISE invalid_datetime_format; + END IF; + + v_regmatch_groups := regexp_matches(v_datestring, YEAR_DOT_SLASH_DASH_REGEXP, 'gi'); + v_day := v_regmatch_groups[3]; + v_month := v_regmatch_groups[2]; + v_year := v_regmatch_groups[1]; + + ELSIF (v_datestring ~* DIGITMASK1_REGEXP OR + v_datestring ~* DIGITMASK2_REGEXP) + THEN + IF (v_datestring ~* DIGITMASK1_REGEXP) + THEN + v_day := substring(v_datestring, 5, 2); + v_month := substring(v_datestring, 3, 2); + v_year := sys.babelfish_get_full_year(substring(v_datestring, 1, 2)); + ELSE + v_day := substring(v_datestring, 7, 2); + v_month := substring(v_datestring, 5, 2); + v_year := substring(v_datestring, 1, 4); + END IF; + ELSIF (v_datestring ~* HHMMSSFS_REGEXP) + THEN + v_fractsecs := coalesce(sys.babelfish_get_timeunit_from_string(v_datestring, 'FRACTSECONDS'), ''); + IF (v_datestring !~* HHMMSSFS_DOT_REGEXP AND char_length(v_fractsecs) > 3) THEN + RAISE invalid_datetime_format; + END IF; + + v_day := '01'; + v_month := '01'; + v_year := '1900'; + ELSE + RAISE invalid_datetime_format; + END IF; + + IF (((v_datestring ~* HHMMSSFS_REGEXP OR v_datestring ~* DIGITMASK1_REGEXP OR v_datestring ~* DIGITMASK2_REGEXP) AND v_style IN (130, 131)) OR + ((v_datestring ~* DOT_FULLYEAR_REGEXP OR v_datestring ~* SLASH_FULLYEAR_REGEXP OR v_datestring ~* DASH_FULLYEAR_REGEXP) AND v_style = 131)) + THEN + IF ((v_day::SMALLINT NOT BETWEEN 1 AND 29) OR + (v_month::SMALLINT NOT BETWEEN 1 AND 12)) + THEN + RAISE invalid_datetime_format; + END IF; + + v_hijridate := sys.babelfish_conv_hijri_to_greg(v_day, v_month, v_year) - 1; + v_datestring := to_char(v_hijridate, 'DD.MM.YYYY'); + + v_day := split_part(v_datestring, '.', 1); + v_month := split_part(v_datestring, '.', 2); + v_year := split_part(v_datestring, '.', 3); + END IF; + + RETURN to_date(concat_ws('.', v_day, v_month, v_year), 'DD.MM.YYYY'); +EXCEPTION + WHEN most_specific_type_mismatch THEN + RAISE USING MESSAGE := 'Argument data type NUMERIC is invalid for argument 2 of conv_string_to_date 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 := format('The style %s is not supported for conversions from VARCHAR to DATE.', v_style), + 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 := 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 invalid_datetime_format THEN + RAISE USING MESSAGE := 'Conversion failed when converting date from character string.', + 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 character_not_in_repertoire THEN + RAISE USING MESSAGE := 'The YDM date format isn''t supported when converting from this string format to date.', + 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_character_value_for_cast THEN + RAISE USING MESSAGE := 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 := 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 +VOLATILE +RETURNS NULL ON NULL INPUT; + +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; + v_year VARCHAR; + v_month VARCHAR; + v_style SMALLINT; + v_scale SMALLINT; + v_hours VARCHAR; + v_hijridate DATE; + v_minutes VARCHAR; + v_seconds VARCHAR; + v_fseconds VARCHAR; + v_datatype VARCHAR; + v_timepart VARCHAR; + v_leftpart VARCHAR; + v_middlepart VARCHAR; + v_rightpart VARCHAR; + v_datestring VARCHAR; + v_err_message VARCHAR; + v_date_format VARCHAR; + v_res_datatype VARCHAR; + v_datetimestring VARCHAR; + v_datatype_groups TEXT[]; + v_regmatch_groups TEXT[]; + v_lang_metadata_json JSONB; + v_compmonth_regexp VARCHAR; + v_resdatetime TIMESTAMP(6) WITHOUT TIME ZONE; + CONVERSION_LANG CONSTANT VARCHAR := ''; + DATE_FORMAT CONSTANT VARCHAR := ''; + DAYMM_REGEXP CONSTANT VARCHAR := '(\d{1,2})'; + FULLYEAR_REGEXP CONSTANT VARCHAR := '(\d{4})'; + SHORTYEAR_REGEXP CONSTANT VARCHAR := '(\d{1,2})'; + COMPYEAR_REGEXP CONSTANT VARCHAR := '(\d{1,2}|\d{4})'; + AMPM_REGEXP CONSTANT VARCHAR := '(?:[AP]M)'; + MASKSEP_REGEXP CONSTANT VARCHAR := '(?:\.|-|/)'; + TIMEUNIT_REGEXP CONSTANT VARCHAR := '\s*\d{1,2}\s*'; + FRACTSECS_REGEXP CONSTANT VARCHAR := '\s*\d{1,9}\s*'; + DATATYPE_REGEXP CONSTANT VARCHAR := '^(DATETIME|SMALLDATETIME|DATETIME2)\s*(?:\()?\s*((?:-)?\d+)?\s*(?:\))?$'; + HHMMSSFS_PART_REGEXP CONSTANT VARCHAR := 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 := 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 := concat('^(', HHMMSSFS_PART_REGEXP, ')$'); + DEFMASK1_0_REGEXP CONSTANT VARCHAR := 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 := concat('^', MASKSEP_REGEXP, '?\s*($comp_month$)\s*', DAYMM_REGEXP, '\s+', COMPYEAR_REGEXP, '$'); + DEFMASK1_2_REGEXP CONSTANT VARCHAR := concat('^', MASKSEP_REGEXP, '\s*($comp_month$)\s*', DAYMM_REGEXP, '\s+', COMPYEAR_REGEXP, '$'); + DEFMASK2_0_REGEXP CONSTANT VARCHAR := 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 := concat('^', DAYMM_REGEXP, '\s*', MASKSEP_REGEXP, '?\s*($comp_month$)\s*', COMPYEAR_REGEXP, '$'); + DEFMASK2_2_REGEXP CONSTANT VARCHAR := concat('^', DAYMM_REGEXP, '\s*', MASKSEP_REGEXP, '\s*($comp_month$)\s*', COMPYEAR_REGEXP, '$'); + DEFMASK3_0_REGEXP CONSTANT VARCHAR := 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 := concat('^', FULLYEAR_REGEXP, '\s*', MASKSEP_REGEXP, '?\s*($comp_month$)\s*', DAYMM_REGEXP, '$'); + DEFMASK3_2_REGEXP CONSTANT VARCHAR := concat('^', FULLYEAR_REGEXP, '\s*', MASKSEP_REGEXP, '\s*($comp_month$)\s*', DAYMM_REGEXP, '$'); + DEFMASK4_0_REGEXP CONSTANT VARCHAR := 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 := concat('^', FULLYEAR_REGEXP, '\s+', DAYMM_REGEXP, '\s*', MASKSEP_REGEXP, '?\s*($comp_month$)$'); + DEFMASK4_2_REGEXP CONSTANT VARCHAR := concat('^', FULLYEAR_REGEXP, '\s+', DAYMM_REGEXP, '\s*', MASKSEP_REGEXP, '\s*($comp_month$)$'); + DEFMASK5_0_REGEXP CONSTANT VARCHAR := 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 := concat('^', DAYMM_REGEXP, '\s+', COMPYEAR_REGEXP, '\s*', MASKSEP_REGEXP, '?\s*($comp_month$)$'); + DEFMASK5_2_REGEXP CONSTANT VARCHAR := concat('^', DAYMM_REGEXP, '\s+', COMPYEAR_REGEXP, '\s*', MASKSEP_REGEXP, '\s*($comp_month$)$'); + DEFMASK6_0_REGEXP CONSTANT VARCHAR := 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 := concat('^', MASKSEP_REGEXP, '?\s*($comp_month$)\s*', FULLYEAR_REGEXP, '\s+', DAYMM_REGEXP, '$'); + DEFMASK6_2_REGEXP CONSTANT VARCHAR := concat('^', MASKSEP_REGEXP, '\s*($comp_month$)\s*', FULLYEAR_REGEXP, '\s+', DAYMM_REGEXP, '$'); + DEFMASK7_0_REGEXP CONSTANT VARCHAR := 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 := concat('^', MASKSEP_REGEXP, '?\s*($comp_month$)\s*', DAYMM_REGEXP, '\s*,\s*', COMPYEAR_REGEXP, '$'); + DEFMASK7_2_REGEXP CONSTANT VARCHAR := concat('^', MASKSEP_REGEXP, '\s*($comp_month$)\s*', DAYMM_REGEXP, '\s*,\s*', COMPYEAR_REGEXP, '$'); + DEFMASK8_0_REGEXP CONSTANT VARCHAR := concat('^(', HHMMSSFS_PART_REGEXP, ')?\s*', + FULLYEAR_REGEXP, '\s*', MASKSEP_REGEXP, '*\s*($comp_month$)', + '\s*(', HHMMSSFS_PART_REGEXP, ')?$'); + DEFMASK8_1_REGEXP CONSTANT VARCHAR := concat('^', FULLYEAR_REGEXP, '\s*', MASKSEP_REGEXP, '?\s*($comp_month$)$'); + DEFMASK8_2_REGEXP CONSTANT VARCHAR := concat('^', FULLYEAR_REGEXP, '\s*', MASKSEP_REGEXP, '\s*($comp_month$)$'); + DEFMASK9_0_REGEXP CONSTANT VARCHAR := concat('^(', HHMMSSFS_PART_REGEXP, ')?\s*', + MASKSEP_REGEXP, '*\s*($comp_month$)\s*', FULLYEAR_REGEXP, + '\s*(', HHMMSSFS_PART_REGEXP, ')?$'); + DEFMASK9_1_REGEXP CONSTANT VARCHAR := concat('^', MASKSEP_REGEXP, '?\s*($comp_month$)\s*', FULLYEAR_REGEXP, '$'); + DEFMASK9_2_REGEXP CONSTANT VARCHAR := concat('^', MASKSEP_REGEXP, '\s*($comp_month$)\s*', FULLYEAR_REGEXP, '$'); + DEFMASK10_0_REGEXP CONSTANT VARCHAR := 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 := concat('^', DAYMM_REGEXP, '\s*', MASKSEP_REGEXP, '\s*($comp_month$)\s*', MASKSEP_REGEXP, '\s*', COMPYEAR_REGEXP, '$'); + DOT_SLASH_DASH_COMPYEAR1_0_REGEXP CONSTANT VARCHAR := 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 := concat('^', DAYMM_REGEXP, '\s*', MASKSEP_REGEXP, '\s*', DAYMM_REGEXP, '\s*', MASKSEP_REGEXP, '\s*', COMPYEAR_REGEXP, '$'); + DOT_SLASH_DASH_SHORTYEAR_REGEXP CONSTANT VARCHAR := concat('^', DAYMM_REGEXP, '\s*', MASKSEP_REGEXP, '\s*', DAYMM_REGEXP, '\s*', MASKSEP_REGEXP, '\s*', SHORTYEAR_REGEXP, '$'); + DOT_SLASH_DASH_FULLYEAR1_0_REGEXP CONSTANT VARCHAR := 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 := concat('^', DAYMM_REGEXP, '\s*', MASKSEP_REGEXP, '\s*', DAYMM_REGEXP, '\s*', MASKSEP_REGEXP, '\s*', FULLYEAR_REGEXP, '$'); + FULLYEAR_DOT_SLASH_DASH1_0_REGEXP CONSTANT VARCHAR := 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 := concat('^', FULLYEAR_REGEXP, '\s*', MASKSEP_REGEXP, '\s*', DAYMM_REGEXP, '\s*', MASKSEP_REGEXP, '\s*', DAYMM_REGEXP, '$'); + SHORT_DIGITMASK1_0_REGEXP CONSTANT VARCHAR := concat('^(', HHMMSSFS_PART_REGEXP, ')?\s*\d{6}\s*(', HHMMSSFS_PART_REGEXP, ')?$'); + FULL_DIGITMASK1_0_REGEXP CONSTANT VARCHAR := 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 ~* replace(DEFMASK1_0_REGEXP, '$comp_month$', v_compmonth_regexp) OR + v_datetimestring ~* replace(DEFMASK2_0_REGEXP, '$comp_month$', v_compmonth_regexp) OR + v_datetimestring ~* replace(DEFMASK3_0_REGEXP, '$comp_month$', v_compmonth_regexp) OR + v_datetimestring ~* replace(DEFMASK4_0_REGEXP, '$comp_month$', v_compmonth_regexp) OR + v_datetimestring ~* replace(DEFMASK5_0_REGEXP, '$comp_month$', v_compmonth_regexp) OR + v_datetimestring ~* replace(DEFMASK6_0_REGEXP, '$comp_month$', v_compmonth_regexp) OR + v_datetimestring ~* replace(DEFMASK7_0_REGEXP, '$comp_month$', v_compmonth_regexp) OR + v_datetimestring ~* replace(DEFMASK8_0_REGEXP, '$comp_month$', v_compmonth_regexp) OR + v_datetimestring ~* replace(DEFMASK9_0_REGEXP, '$comp_month$', v_compmonth_regexp) OR + v_datetimestring ~* 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 ~* replace(DEFMASK1_2_REGEXP, '$comp_month$', v_compmonth_regexp) OR + v_datestring ~* replace(DEFMASK2_2_REGEXP, '$comp_month$', v_compmonth_regexp) OR + v_datestring ~* replace(DEFMASK3_2_REGEXP, '$comp_month$', v_compmonth_regexp) OR + v_datestring ~* replace(DEFMASK4_2_REGEXP, '$comp_month$', v_compmonth_regexp) OR + v_datestring ~* replace(DEFMASK5_2_REGEXP, '$comp_month$', v_compmonth_regexp) OR + v_datestring ~* replace(DEFMASK6_2_REGEXP, '$comp_month$', v_compmonth_regexp) OR + v_datestring ~* replace(DEFMASK7_2_REGEXP, '$comp_month$', v_compmonth_regexp) OR + v_datestring ~* replace(DEFMASK8_2_REGEXP, '$comp_month$', v_compmonth_regexp) OR + v_datestring ~* replace(DEFMASK9_2_REGEXP, '$comp_month$', v_compmonth_regexp)) AND + v_res_datatype = 'DATETIME2') + THEN + RAISE invalid_datetime_format; + END IF; + + IF (v_datestring ~* replace(DEFMASK1_1_REGEXP, '$comp_month$', v_compmonth_regexp)) + THEN + v_regmatch_groups := regexp_matches(v_datestring, 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 ~* replace(DEFMASK2_1_REGEXP, '$comp_month$', v_compmonth_regexp)) + THEN + v_regmatch_groups := regexp_matches(v_datestring, 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 ~* replace(DEFMASK3_1_REGEXP, '$comp_month$', v_compmonth_regexp)) + THEN + v_regmatch_groups := regexp_matches(v_datestring, 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 ~* replace(DEFMASK4_1_REGEXP, '$comp_month$', v_compmonth_regexp)) + THEN + v_regmatch_groups := regexp_matches(v_datestring, 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 ~* replace(DEFMASK5_1_REGEXP, '$comp_month$', v_compmonth_regexp)) + THEN + v_regmatch_groups := regexp_matches(v_datestring, 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 ~* replace(DEFMASK6_1_REGEXP, '$comp_month$', v_compmonth_regexp)) + THEN + v_regmatch_groups := regexp_matches(v_datestring, 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 ~* replace(DEFMASK7_1_REGEXP, '$comp_month$', v_compmonth_regexp)) + THEN + v_regmatch_groups := regexp_matches(v_datestring, 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 ~* replace(DEFMASK8_1_REGEXP, '$comp_month$', v_compmonth_regexp)) + THEN + v_regmatch_groups := regexp_matches(v_datestring, 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 ~* replace(DEFMASK9_1_REGEXP, '$comp_month$', v_compmonth_regexp)) + THEN + v_regmatch_groups := regexp_matches(v_datestring, 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 ~* replace(DEFMASK10_1_REGEXP, '$comp_month$', v_compmonth_regexp)) + THEN + v_regmatch_groups := regexp_matches(v_datestring, 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'; + 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 := 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 := 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 := 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 := 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 := 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 := 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 +VOLATILE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_conv_string_to_time(IN p_datatype TEXT, + IN p_timestring TEXT, + IN p_style NUMERIC DEFAULT 0) +RETURNS TIME WITHOUT TIME ZONE +AS +$BODY$ +DECLARE + v_hours SMALLINT; + v_style SMALLINT; + v_scale SMALLINT; + v_daypart VARCHAR; + v_seconds VARCHAR; + v_minutes SMALLINT; + v_fseconds VARCHAR; + v_datatype VARCHAR; + v_timestring VARCHAR; + v_err_message VARCHAR; + v_src_datatype VARCHAR; + v_timeunit_mask VARCHAR; + v_datatype_groups TEXT[]; + v_regmatch_groups TEXT[]; + AMPM_REGEXP CONSTANT VARCHAR := '\s*([AP]M)'; + TIMEUNIT_REGEXP CONSTANT VARCHAR := '\s*(\d{1,2})\s*'; + FRACTSECS_REGEXP CONSTANT VARCHAR := '\s*(\d{1,9})'; + HHMMSSFS_REGEXP CONSTANT VARCHAR := concat('^', TIMEUNIT_REGEXP, + '\:', TIMEUNIT_REGEXP, + '\:', TIMEUNIT_REGEXP, + '(?:\.|\:)', FRACTSECS_REGEXP, '$'); + HHMMSS_REGEXP CONSTANT VARCHAR := concat('^', TIMEUNIT_REGEXP, '\:', TIMEUNIT_REGEXP, '\:', TIMEUNIT_REGEXP, '$'); + HHMMFS_REGEXP CONSTANT VARCHAR := concat('^', TIMEUNIT_REGEXP, '\:', TIMEUNIT_REGEXP, '\.', FRACTSECS_REGEXP, '$'); + HHMM_REGEXP CONSTANT VARCHAR := concat('^', TIMEUNIT_REGEXP, '\:', TIMEUNIT_REGEXP, '$'); + HH_REGEXP CONSTANT VARCHAR := concat('^', TIMEUNIT_REGEXP, '$'); + DATATYPE_REGEXP CONSTANT VARCHAR := '^(TIME)\s*(?:\()?\s*((?:-)?\d+)?\s*(?:\))?$'; +BEGIN + v_datatype := trim(regexp_replace(p_datatype, 'DATETIME', 'TIME', 'gi')); + v_timestring := upper(trim(p_timestring)); + v_style := floor(p_style)::SMALLINT; + + v_datatype_groups := regexp_matches(v_datatype, DATATYPE_REGEXP, 'gi'); + + v_src_datatype := upper(v_datatype_groups[1]); + v_scale := v_datatype_groups[2]::SMALLINT; + + IF (v_src_datatype IS NULL) THEN + RAISE datatype_mismatch; + 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))) + THEN + RAISE invalid_parameter_value; + END IF; + + v_daypart := substring(v_timestring, 'AM|PM'); + v_timestring := trim(regexp_replace(v_timestring, coalesce(v_daypart, ''), '')); + + v_timeunit_mask := + CASE + WHEN (v_timestring ~* HHMMSSFS_REGEXP) THEN HHMMSSFS_REGEXP + WHEN (v_timestring ~* HHMMSS_REGEXP) THEN HHMMSS_REGEXP + WHEN (v_timestring ~* HHMMFS_REGEXP) THEN HHMMFS_REGEXP + WHEN (v_timestring ~* HHMM_REGEXP) THEN HHMM_REGEXP + WHEN (v_timestring ~* HH_REGEXP) THEN HH_REGEXP + END; + + IF (v_timeunit_mask IS NULL) THEN + RAISE invalid_datetime_format; + END IF; + + v_regmatch_groups := regexp_matches(v_timestring, v_timeunit_mask, 'gi'); + + v_hours := v_regmatch_groups[1]::SMALLINT; + v_minutes := v_regmatch_groups[2]::SMALLINT; + + IF (v_timestring ~* HHMMFS_REGEXP) THEN + v_fseconds := v_regmatch_groups[3]; + ELSE + v_seconds := v_regmatch_groups[3]; + v_fseconds := v_regmatch_groups[4]; + END IF; + + IF (v_daypart IS NOT NULL) THEN + IF ((v_daypart = 'AM' AND v_hours NOT BETWEEN 0 AND 12) OR + (v_daypart = 'PM' AND v_hours NOT BETWEEN 1 AND 23)) + THEN + RAISE numeric_value_out_of_range; + ELSIF (v_daypart = 'PM' AND v_hours < 12) THEN + v_hours := v_hours + 12; + ELSIF (v_daypart = 'AM' AND v_hours = 12) THEN + v_hours := v_hours - 12; + END IF; + END IF; + + v_fseconds := sys.babelfish_get_microsecs_from_fractsecs(v_fseconds, v_scale); + v_seconds := concat_ws('.', v_seconds, v_fseconds); + + RETURN make_time(v_hours, v_minutes, v_seconds::NUMERIC); +EXCEPTION + WHEN most_specific_type_mismatch THEN + RAISE USING MESSAGE := 'Argument data type NUMERIC is invalid for argument 3 of conv_string_to_time 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 := format('The style %s is not supported for conversions from VARCHAR to TIME.', v_style), + DETAIL := 'Use of incorrect "style" parameter value during conversion process.', + HINT := 'Change "style" parameter to the proper value and try again.'; + + WHEN datatype_mismatch THEN + RAISE USING MESSAGE := 'Source data type should be ''TIME'' or ''TIME(n)''.', + DETAIL := 'Use of incorrect "datatype" parameter value during conversion process.', + HINT := 'Change "datatype" parameter to the proper value and try again.'; + + WHEN interval_field_overflow THEN + RAISE USING MESSAGE := 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 numeric_value_out_of_range THEN + RAISE USING MESSAGE := 'Could not extract correct hour value due to it''s inconsistency with AM|PM day part mark.', + DETAIL := 'Extracted hour value doesn''t fall in correct day part mark range: 0..12 for "AM" or 1..23 for "PM".', + HINT := 'Correct a hour value in the source string or remove AM|PM day part mark out of it.'; + + WHEN invalid_datetime_format THEN + RAISE USING MESSAGE := 'Conversion failed when converting time from character string.', + 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_text_representation THEN + GET STACKED DIAGNOSTICS v_err_message = MESSAGE_TEXT; + v_err_message := substring(lower(v_err_message), 'integer\:\s\"(.*)\"'); + + RAISE USING MESSAGE := format('Error while trying to convert "%s" value to SMALLINT data type.', + v_err_message), + DETAIL := 'Supplied value contains illegal characters.', + HINT := 'Correct supplied value, remove all illegal characters.'; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_conv_time_to_string(IN p_datatype TEXT, + IN p_src_datatype TEXT, + IN p_timeval TIME(6) WITHOUT TIME ZONE, + IN p_style NUMERIC DEFAULT 25) +RETURNS TEXT +AS +$BODY$ +DECLARE + v_hours VARCHAR; + v_style SMALLINT; + v_scale SMALLINT; + v_resmask VARCHAR; + v_fseconds VARCHAR; + v_datatype VARCHAR; + v_resstring VARCHAR; + v_lengthexpr VARCHAR; + v_res_length SMALLINT; + v_res_datatype VARCHAR; + v_src_datatype VARCHAR; + v_res_maxlength SMALLINT; + VARCHAR_MAX CONSTANT SMALLINT := 8000; + NVARCHAR_MAX CONSTANT SMALLINT := 4000; + -- We use the regex below to make sure input p_datatype is one of them + DATATYPE_REGEXP CONSTANT VARCHAR := '^\s*(CHAR|NCHAR|VARCHAR|NVARCHAR|CHARACTER VARYING)\s*$'; + -- We use the regex below to get the length of the datatype, if specified + -- For example, to get the '10' out of 'varchar(10)' + DATATYPE_MASK_REGEXP CONSTANT VARCHAR := '^\s*(?:CHAR|NCHAR|VARCHAR|NVARCHAR|CHARACTER VARYING)\s*\(\s*(\d+|MAX)\s*\)\s*$'; + SRCDATATYPE_MASK_REGEXP VARCHAR := '^\s*(?:TIME)\s*(?:\s*\(\s*(\d+)\s*\)\s*)?\s*$'; +BEGIN + v_datatype := upper(trim(p_datatype)); + v_src_datatype := upper(trim(p_src_datatype)); + v_style := floor(p_style)::SMALLINT; + + IF (v_src_datatype ~* SRCDATATYPE_MASK_REGEXP) + THEN + v_scale := coalesce(substring(v_src_datatype, SRCDATATYPE_MASK_REGEXP)::SMALLINT, 7); + + IF (v_scale NOT BETWEEN 0 AND 7) THEN + RAISE invalid_regular_expression; + END IF; + ELSE + RAISE most_specific_type_mismatch; + END IF; + + IF (v_datatype ~* DATATYPE_MASK_REGEXP) + THEN + v_res_datatype := rtrim(split_part(v_datatype, '(', 1)); + + v_res_maxlength := CASE + WHEN (v_res_datatype IN ('CHAR', 'VARCHAR')) THEN VARCHAR_MAX + ELSE NVARCHAR_MAX + END; + + v_lengthexpr := substring(v_datatype, DATATYPE_MASK_REGEXP); + + IF (v_lengthexpr <> 'MAX' AND char_length(v_lengthexpr) > 4) THEN + RAISE interval_field_overflow; + END IF; + + v_res_length := CASE v_lengthexpr + WHEN 'MAX' THEN v_res_maxlength + ELSE v_lengthexpr::SMALLINT + END; + ELSIF (v_datatype ~* DATATYPE_REGEXP) THEN + v_res_datatype := v_datatype; + ELSE + RAISE datatype_mismatch; + END IF; + + IF (scale(p_style) > 0) THEN + RAISE escape_character_conflict; + 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))) + THEN + RAISE invalid_parameter_value; + ELSIF ((v_style BETWEEN 1 AND 7) OR + (v_style BETWEEN 10 AND 12) OR + (v_style BETWEEN 101 AND 107) OR + (v_style BETWEEN 110 AND 112) OR + v_style = 23) + THEN + RAISE invalid_datetime_format; + END IF; + + v_hours := ltrim(to_char(p_timeval, 'HH12'), '0'); + v_fseconds := sys.babelfish_get_microsecs_from_fractsecs(to_char(p_timeval, 'US'), v_scale); + + IF (v_scale = 7) THEN + v_fseconds := concat(v_fseconds, '0'); + END IF; + + IF (v_style IN (0, 100)) + THEN + v_resmask := concat(v_hours, ':MIAM'); + ELSIF (v_style IN (8, 20, 24, 108, 120)) + THEN + v_resmask := 'HH24:MI:SS'; + ELSIF (v_style IN (9, 109)) + THEN + v_resmask := CASE + WHEN (char_length(v_fseconds) = 0) THEN concat(v_hours, ':MI:SSAM') + ELSE format('%s:MI:SS.%sAM', v_hours, v_fseconds) + END; + ELSIF (v_style IN (13, 14, 21, 25, 113, 114, 121, 126, 127)) + THEN + v_resmask := CASE + WHEN (char_length(v_fseconds) = 0) THEN 'HH24:MI:SS' + ELSE concat('HH24:MI:SS.', v_fseconds) + END; + ELSIF (v_style = 22) + THEN + v_resmask := format('%s:MI:SS AM', lpad(v_hours, 2, ' ')); + ELSIF (v_style IN (130, 131)) + THEN + v_resmask := CASE + WHEN (char_length(v_fseconds) = 0) THEN concat(lpad(v_hours, 2, ' '), ':MI:SSAM') + ELSE format('%s:MI:SS.%sAM', lpad(v_hours, 2, ' '), v_fseconds) + END; + END IF; + + v_resstring := to_char(p_timeval, v_resmask); + + v_resstring := substring(v_resstring, 1, coalesce(v_res_length, char_length(v_resstring))); + v_res_length := coalesce(v_res_length, + CASE v_res_datatype + WHEN 'CHAR' THEN 30 + ELSE 60 + END); + RETURN CASE + WHEN (v_res_datatype NOT IN ('CHAR', 'NCHAR')) THEN v_resstring + ELSE rpad(v_resstring, v_res_length, ' ') + END; +EXCEPTION + WHEN most_specific_type_mismatch THEN + RAISE USING MESSAGE := 'Source data type should be ''TIME'' or ''TIME(n)''.', + DETAIL := 'Use of incorrect "src_datatype" parameter value during conversion process.', + HINT := 'Change "src_datatype" parameter to the proper value and try again.'; + + WHEN invalid_regular_expression THEN + RAISE USING MESSAGE := format('The source data type scale (%s) given to the convert specification exceeds the maximum allowable value (7).', + v_scale), + DETAIL := 'Use of incorrect scale value of source data type parameter during conversion process.', + HINT := 'Change scale component of source data type parameter to the allowable value and try again.'; + + WHEN interval_field_overflow THEN + RAISE USING MESSAGE := format('The size (%s) given to the convert specification ''%s'' exceeds the maximum allowed for any data type (%s).', + v_lengthexpr, lower(v_res_datatype), v_res_maxlength), + DETAIL := 'Use of incorrect size value of target data type parameter during conversion process.', + HINT := 'Change size component of data type parameter to the allowable value and try again.'; + + WHEN escape_character_conflict THEN + RAISE USING MESSAGE := 'Argument data type NUMERIC is invalid for argument 4 of convert 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 := format('%s is not a valid style number when converting from TIME to a character string.', v_style), + DETAIL := 'Use of incorrect "style" parameter value during conversion process.', + HINT := 'Change "style" parameter to the proper value and try again.'; + + WHEN datatype_mismatch THEN + RAISE USING MESSAGE := 'Data type should be one of these values: ''CHAR(n|MAX)'', ''NCHAR(n|MAX)'', ''VARCHAR(n|MAX)'', ''NVARCHAR(n|MAX)''.', + DETAIL := 'Use of incorrect "datatype" parameter value during conversion process.', + HINT := 'Change "datatype" parameter to the proper value and try again.'; + + WHEN invalid_datetime_format THEN + RAISE USING MESSAGE := format('Error converting data type TIME to %s.', + rtrim(split_part(trim(p_datatype), '(', 1))), + 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.'; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + +create or replace function sys.babelfish_dbts() +returns bigint as +$BODY$ +declare + v_res bigint; +begin + SELECT last_value INTO v_res FROM sys_data.inc_seq_rowversion; + return v_res; +end; +$BODY$ +language plpgsql; + +CREATE OR REPLACE FUNCTION sys.babelfish_get_full_year(IN p_short_year TEXT, + IN p_base_century TEXT DEFAULT '', + IN p_year_cutoff NUMERIC DEFAULT 49) +RETURNS VARCHAR +AS +$BODY$ +DECLARE + v_err_message VARCHAR; + v_full_year SMALLINT; + v_short_year SMALLINT; + v_base_century SMALLINT; + v_result_param_set JSONB; + v_full_year_res_jsonb JSONB; +BEGIN + v_short_year := p_short_year::SMALLINT; + + BEGIN + v_full_year_res_jsonb := nullif(current_setting('sys.full_year_res_json'), '')::JSONB; + EXCEPTION + WHEN undefined_object THEN + v_full_year_res_jsonb := NULL; + END; + + SELECT result + INTO v_full_year + FROM jsonb_to_recordset(v_full_year_res_jsonb) AS result_set (param1 SMALLINT, + param2 TEXT, + param3 NUMERIC, + result VARCHAR) + WHERE param1 = v_short_year + AND param2 = p_base_century + AND param3 = p_year_cutoff; + + IF (v_full_year IS NULL) + THEN + IF (v_short_year <= 99) + THEN + v_base_century := CASE + WHEN (p_base_century ~ '^\s*([1-9]{1,2})\s*$') THEN concat(trim(p_base_century), '00')::SMALLINT + ELSE trunc(extract(year from current_date)::NUMERIC, -2) + END; + + v_full_year = v_base_century + v_short_year; + v_full_year = CASE + WHEN (v_short_year > p_year_cutoff) THEN v_full_year - 100 + ELSE v_full_year + END; + ELSE v_full_year := v_short_year; + END IF; + + v_result_param_set := jsonb_build_object('param1', v_short_year, + 'param2', p_base_century, + 'param3', p_year_cutoff, + 'result', v_full_year); + v_full_year_res_jsonb := CASE + WHEN (v_full_year_res_jsonb IS NULL) THEN jsonb_build_array(v_result_param_set) + ELSE v_full_year_res_jsonb || v_result_param_set + END; + + PERFORM set_config('sys.full_year_res_json', + v_full_year_res_jsonb::TEXT, + FALSE); + END IF; + + RETURN v_full_year; +EXCEPTION + 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 := format('Error while trying to convert "%s" value to SMALLINT data type.', + v_err_message), + DETAIL := 'Supplied value contains illegal characters.', + HINT := 'Correct supplied value, remove all illegal characters.'; +END; +$BODY$ +LANGUAGE plpgsql +STABLE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_get_int_part(IN p_srcnumber DOUBLE PRECISION) +RETURNS DOUBLE PRECISION +AS +$BODY$ +BEGIN + RETURN CASE + WHEN (p_srcnumber < -0.0000001) THEN ceil(p_srcnumber - 0.0000001) + ELSE floor(p_srcnumber + 0.0000001) + END; +END; +$BODY$ +LANGUAGE plpgsql +STABLE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_get_jobs () +RETURNS table( job integer, what text, search_path varchar ) +AS +$body$ +DECLARE + var_job integer; + var_what text; + var_search_path varchar; +BEGIN + + SELECT js.job_step_id, js.command, '' + FROM sys.sysjobschedules s + INNER JOIN sys.sysjobs j on j.job_id = s.job_id + INNER JOIN sys.sysjobsteps js ON js.job_id = j.job_id + INTO var_job, var_what, var_search_path + WHERE (s.next_run_date + s.next_run_time) <= now()::timestamp + AND j.enabled = 1 + ORDER BY (s.next_run_date + s.next_run_time) ASC + LIMIT 1; + + IF var_job > 0 + THEN + return query select var_job, var_what, var_search_path; + END IF; + +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION sys.babelfish_get_lang_metadata_json(IN p_lang_spec_culture TEXT) +RETURNS JSONB +AS +$BODY$ +DECLARE + v_locale_parts TEXT[]; + v_lang_data_jsonb JSONB; + v_lang_spec_culture VARCHAR; + v_is_cached BOOLEAN := FALSE; +BEGIN + v_lang_spec_culture := upper(trim(p_lang_spec_culture)); + + IF (char_length(v_lang_spec_culture) > 0) + THEN + BEGIN + v_lang_data_jsonb := nullif(current_setting(format('sys.lang_metadata_json.%s', + v_lang_spec_culture)), '')::JSONB; + EXCEPTION + WHEN undefined_object THEN + v_lang_data_jsonb := NULL; + END; + + IF (v_lang_data_jsonb IS NULL) + THEN + IF (v_lang_spec_culture IN ('AR', 'FI') OR + v_lang_spec_culture ~ '-') + THEN + SELECT lang_data_jsonb + INTO STRICT v_lang_data_jsonb + FROM sys.syslanguages + WHERE spec_culture = v_lang_spec_culture; + ELSE + SELECT lang_data_jsonb + INTO STRICT v_lang_data_jsonb + FROM sys.syslanguages + WHERE lang_name_mssql = v_lang_spec_culture + OR lang_alias_mssql = v_lang_spec_culture; + END IF; + ELSE + v_is_cached := TRUE; + END IF; + ELSE + v_lang_spec_culture := current_setting('LC_TIME'); + + v_lang_spec_culture := CASE + WHEN (v_lang_spec_culture !~ '\.') THEN v_lang_spec_culture + ELSE substring(v_lang_spec_culture, '(.*)(?:\.)') + END; + + v_lang_spec_culture := upper(regexp_replace(v_lang_spec_culture, '_|,\s*', '-', 'gi')); + + BEGIN + v_lang_data_jsonb := nullif(current_setting(format('sys.lang_metadata_json.%s', + v_lang_spec_culture)), '')::JSONB; + EXCEPTION + WHEN undefined_object THEN + v_lang_data_jsonb := NULL; + END; + + IF (v_lang_data_jsonb IS NULL) + THEN + BEGIN + IF (char_length(v_lang_spec_culture) = 5) + THEN + SELECT lang_data_jsonb + INTO STRICT v_lang_data_jsonb + FROM sys.syslanguages + WHERE spec_culture = v_lang_spec_culture; + ELSE + v_locale_parts := string_to_array(v_lang_spec_culture, '-'); + + SELECT lang_data_jsonb + INTO STRICT v_lang_data_jsonb + FROM sys.syslanguages + WHERE lang_name_pg = v_locale_parts[1] + AND territory = v_locale_parts[2]; + END IF; + EXCEPTION + WHEN OTHERS THEN + v_lang_spec_culture := 'EN-US'; + + SELECT lang_data_jsonb + INTO v_lang_data_jsonb + FROM sys.syslanguages + WHERE spec_culture = v_lang_spec_culture; + END; + ELSE + v_is_cached := TRUE; + END IF; + END IF; + + IF (NOT v_is_cached) THEN + PERFORM set_config(format('sys.lang_metadata_json.%s', + v_lang_spec_culture), + v_lang_data_jsonb::TEXT, + FALSE); + END IF; + + RETURN v_lang_data_jsonb; +EXCEPTION + WHEN invalid_text_representation THEN + RAISE USING MESSAGE := format('The language metadata JSON value extracted from chache is not a valid JSON object.', + p_lang_spec_culture), + HINT := 'Drop the current session, fix the appropriate record in "sys.syslanguages" table, and try again after reconnection.'; + + WHEN OTHERS THEN + RAISE USING MESSAGE := format('"%s" is not a valid special culture or language name parameter.', + p_lang_spec_culture), + DETAIL := 'Use of incorrect "lang_spec_culture" parameter value during conversion process.', + HINT := 'Change "lang_spec_culture" parameter to the proper value and try again.'; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE; + +CREATE OR REPLACE FUNCTION sys.babelfish_get_microsecs_from_fractsecs(IN p_fractsecs TEXT, + IN p_scale NUMERIC DEFAULT 7) +RETURNS VARCHAR +AS +$BODY$ +DECLARE + v_scale SMALLINT; + v_decplaces INTEGER; + v_fractsecs VARCHAR; + v_pureplaces VARCHAR; + v_rnd_fractsecs INTEGER; + v_fractsecs_len INTEGER; + v_pureplaces_len INTEGER; + v_err_message VARCHAR; +BEGIN + v_fractsecs := trim(p_fractsecs); + v_fractsecs_len := char_length(v_fractsecs); + v_scale := floor(p_scale)::SMALLINT; + + IF (v_fractsecs_len < 7) THEN + v_fractsecs := rpad(v_fractsecs, 7, '0'); + v_fractsecs_len := char_length(v_fractsecs); + END IF; + + v_pureplaces := trim(leading '0' from v_fractsecs); + v_pureplaces_len := char_length(v_pureplaces); + + v_decplaces := v_fractsecs_len - v_pureplaces_len; + + v_rnd_fractsecs := round(v_fractsecs::INTEGER, (v_pureplaces_len - (v_scale - (v_fractsecs_len - v_pureplaces_len))) * (-1)); + + v_fractsecs := concat(replace(rpad('', v_decplaces), ' ', '0'), v_rnd_fractsecs); + + RETURN substring(v_fractsecs, 1, CASE + WHEN (v_scale >= 7) THEN 6 + ELSE v_scale + END); +EXCEPTION + 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 := format('Error while trying to convert "%s" value to SMALLINT data type.', v_err_message), + DETAIL := 'Supplied value contains illegal characters.', + HINT := 'Correct supplied value, remove all illegal characters.'; +END; +$BODY$ +LANGUAGE plpgsql +STABLE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_get_monthnum_by_name(IN p_monthname TEXT, + IN p_lang_metadata_json JSONB) +RETURNS VARCHAR +AS +$BODY$ +DECLARE + v_monthname TEXT; + v_monthnum SMALLINT; +BEGIN + v_monthname := lower(trim(p_monthname)); + + v_monthnum := array_position(ARRAY(SELECT lower(jsonb_array_elements_text(p_lang_metadata_json -> 'months_shortnames'))), v_monthname); + + v_monthnum := coalesce(v_monthnum, + array_position(ARRAY(SELECT lower(jsonb_array_elements_text(p_lang_metadata_json -> 'months_names'))), v_monthname)); + + v_monthnum := coalesce(v_monthnum, + array_position(ARRAY(SELECT lower(jsonb_array_elements_text(p_lang_metadata_json -> 'months_extrashortnames'))), v_monthname)); + + v_monthnum := coalesce(v_monthnum, + array_position(ARRAY(SELECT lower(jsonb_array_elements_text(p_lang_metadata_json -> 'months_extranames'))), v_monthname)); + + IF (v_monthnum IS NULL) THEN + RAISE datetime_field_overflow; + END IF; + + RETURN v_monthnum; +EXCEPTION + WHEN datetime_field_overflow THEN + RAISE USING MESSAGE := format('Can not convert value "%s" to a correct month number.', + trim(p_monthname)), + DETAIL := 'Supplied month name is not valid.', + HINT := 'Correct supplied month name value and try again.'; +END; +$BODY$ +LANGUAGE plpgsql +IMMUTABLE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_get_service_setting ( + IN p_service sys.service_settings.service%TYPE + , IN p_setting sys.service_settings.setting%TYPE +) +RETURNS sys.service_settings.value%TYPE +AS +$BODY$ +DECLARE + settingValue sys.service_settings.value%TYPE; +BEGIN + SELECT value + INTO settingValue + FROM sys.service_settings + WHERE service = p_service + AND setting = p_setting; + + RETURN settingValue; +END; +$BODY$ +LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION sys.babelfish_get_timeunit_from_string(IN p_timepart TEXT, + IN p_timeunit TEXT) +RETURNS VARCHAR +AS +$BODY$ +DECLARE + v_hours VARCHAR; + v_minutes VARCHAR; + v_seconds VARCHAR; + v_fractsecs VARCHAR; + v_daypart VARCHAR; + v_timepart VARCHAR; + v_timeunit VARCHAR; + v_err_message VARCHAR; + v_timeunit_mask VARCHAR; + v_regmatch_groups TEXT[]; + AMPM_REGEXP CONSTANT VARCHAR := '\s*([AP]M)'; + TIMEUNIT_REGEXP CONSTANT VARCHAR := '\s*(\d{1,2})\s*'; + FRACTSECS_REGEXP CONSTANT VARCHAR := '\s*(\d{1,9})'; + HHMMSSFS_REGEXP CONSTANT VARCHAR := concat('^', TIMEUNIT_REGEXP, + '\:', TIMEUNIT_REGEXP, + '\:', TIMEUNIT_REGEXP, + '(?:\.|\:)', FRACTSECS_REGEXP, '$'); + HHMMSS_REGEXP CONSTANT VARCHAR := concat('^', TIMEUNIT_REGEXP, '\:', TIMEUNIT_REGEXP, '\:', TIMEUNIT_REGEXP, '$'); + HHMMFS_REGEXP CONSTANT VARCHAR := concat('^', TIMEUNIT_REGEXP, '\:', TIMEUNIT_REGEXP, '\.', FRACTSECS_REGEXP, '$'); + HHMM_REGEXP CONSTANT VARCHAR := concat('^', TIMEUNIT_REGEXP, '\:', TIMEUNIT_REGEXP, '$'); + HH_REGEXP CONSTANT VARCHAR := concat('^', TIMEUNIT_REGEXP, '$'); +BEGIN + v_timepart := upper(trim(p_timepart)); + v_timeunit := upper(trim(p_timeunit)); + + v_daypart := substring(v_timepart, 'AM|PM'); + v_timepart := trim(regexp_replace(v_timepart, coalesce(v_daypart, ''), '')); + + v_timeunit_mask := + CASE + WHEN (v_timepart ~* HHMMSSFS_REGEXP) THEN HHMMSSFS_REGEXP + WHEN (v_timepart ~* HHMMSS_REGEXP) THEN HHMMSS_REGEXP + WHEN (v_timepart ~* HHMMFS_REGEXP) THEN HHMMFS_REGEXP + WHEN (v_timepart ~* HHMM_REGEXP) THEN HHMM_REGEXP + WHEN (v_timepart ~* HH_REGEXP) THEN HH_REGEXP + END; + + v_regmatch_groups := regexp_matches(v_timepart, v_timeunit_mask, 'gi'); + + v_hours := v_regmatch_groups[1]; + v_minutes := v_regmatch_groups[2]; + + IF (v_timepart ~* HHMMFS_REGEXP) THEN + v_fractsecs := v_regmatch_groups[3]; + ELSE + v_seconds := v_regmatch_groups[3]; + v_fractsecs := v_regmatch_groups[4]; + END IF; + + IF (v_timeunit = 'HOURS' AND v_daypart IS NOT NULL) + THEN + IF ((v_daypart = 'AM' AND v_hours::SMALLINT NOT BETWEEN 0 AND 12) OR + (v_daypart = 'PM' AND v_hours::SMALLINT NOT BETWEEN 1 AND 23)) + THEN + RAISE numeric_value_out_of_range; + ELSIF (v_daypart = 'PM' AND v_hours::SMALLINT < 12) THEN + v_hours := (v_hours::SMALLINT + 12)::VARCHAR; + ELSIF (v_daypart = 'AM' AND v_hours::SMALLINT = 12) THEN + v_hours := (v_hours::SMALLINT - 12)::VARCHAR; + END IF; + END IF; + + RETURN CASE v_timeunit + WHEN 'HOURS' THEN v_hours + WHEN 'MINUTES' THEN v_minutes + WHEN 'SECONDS' THEN v_seconds + WHEN 'FRACTSECONDS' THEN v_fractsecs + END; +EXCEPTION + WHEN numeric_value_out_of_range THEN + RAISE USING MESSAGE := 'Could not extract correct hour value due to it''s inconsistency with AM|PM day part mark.', + DETAIL := 'Extracted hour value doesn''t fall in correct day part mark range: 0..12 for "AM" or 1..23 for "PM".', + HINT := 'Correct a hour value in the source string or remove AM|PM day part mark out of it.'; + + 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 := format('Error while trying to convert "%s" value to SMALLINT data type.', v_err_message), + DETAIL := 'Supplied value contains illegal characters.', + HINT := 'Correct supplied value, remove all illegal characters.'; +END; +$BODY$ +LANGUAGE plpgsql +IMMUTABLE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_get_version(pComponentName VARCHAR(256)) + RETURNS VARCHAR(256) AS +$BODY$ +DECLARE + lComponentVersion VARCHAR(256); +BEGIN + SELECT componentversion + INTO lComponentVersion + FROM sys.versions + WHERE extpackcomponentname = pComponentName; + + RETURN lComponentVersion; +END; +$BODY$ +LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION sys.babelfish_get_weekdaynum_by_name(IN p_weekdayname TEXT, + IN p_lang_metadata_json JSONB) +RETURNS SMALLINT +AS +$BODY$ +DECLARE + v_weekdayname TEXT; + v_weekdaynum SMALLINT; +BEGIN + v_weekdayname := lower(trim(p_weekdayname)); + + v_weekdaynum := array_position(ARRAY(SELECT lower(jsonb_array_elements_text(p_lang_metadata_json -> 'days_names'))), v_weekdayname); + + v_weekdaynum := coalesce(v_weekdaynum, + array_position(ARRAY(SELECT lower(jsonb_array_elements_text(p_lang_metadata_json -> 'days_shortnames'))), v_weekdayname)); + + v_weekdaynum := coalesce(v_weekdaynum, + array_position(ARRAY(SELECT lower(jsonb_array_elements_text(p_lang_metadata_json -> 'days_extrashortnames'))), v_weekdayname)); + + IF (v_weekdaynum IS NULL) THEN + RAISE datetime_field_overflow; + END IF; + + RETURN v_weekdaynum; +EXCEPTION + WHEN datetime_field_overflow THEN + RAISE USING MESSAGE := format('Can not convert value "%s" to a correct weekday number.', + trim(p_weekdayname)), + DETAIL := 'Supplied weekday name is not valid.', + HINT := 'Correct supplied weekday name value and try again.'; +END; +$BODY$ +LANGUAGE plpgsql +IMMUTABLE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_is_ossp_present() +RETURNS BOOLEAN AS +$BODY$ +DECLARE + result SMALLINT; +BEGIN + select + case when exists + (select 1 from pg_extension where extname = 'uuid-ossp') + then 1 + else 0 end + INTO result; + + RETURN (result = 1); +END; +$BODY$ +LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION sys.babelfish_is_spatial_present() +RETURNS BOOLEAN AS +$BODY$ +DECLARE + result SMALLINT; +BEGIN + select + case when exists + (select 1 from pg_extension where extname = 'postgis') + then 1 + else 0 end + INTO result; + + RETURN (result = 1); +END; +$BODY$ +LANGUAGE plpgsql; + +create or replace function sys.babelfish_istime(v text) +returns boolean +as +$body$ +begin + perform v::time; + return true; +exception + when others then + return false; +end +$body$ +language 'plpgsql'; + +-- Remove closing square brackets at both ends, otherwise do nothing. +CREATE OR REPLACE FUNCTION sys.babelfish_single_unbracket_name(IN name TEXT) +RETURNS TEXT AS +$BODY$ +BEGIN + IF length(name) >= 2 AND left(name, 1) = '[' AND right(name, 1) = ']' THEN + IF length(name) = 2 THEN + RETURN ''; + ELSE + RETURN substring(name from 2 for length(name)-2); + END IF; + END IF; + RETURN name; +END; +$BODY$ +LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION sys.babelfish_openxml(IN DocHandle BIGINT) + RETURNS TABLE (XmlData XML) +AS +$BODY$ +DECLARE + XmlDocument$data XML; +BEGIN + + SELECT t.XmlData + INTO STRICT XmlDocument$data + FROM sys$openxml t + WHERE t.DocID = DocHandle; + + RETURN QUERY SELECT XmlDocument$data; + + EXCEPTION + WHEN SQLSTATE '42P01' OR SQLSTATE 'P0002' THEN + RAISE EXCEPTION '%','Could not find prepared statement with handle '||CASE + WHEN DocHandle IS NULL THEN 'null' + ELSE DocHandle::TEXT + END; +END; +$BODY$ +LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION sys.babelfish_parse_to_date(IN p_datestring TEXT, + IN p_culture TEXT DEFAULT '') +RETURNS DATE +AS +$BODY$ +DECLARE + v_day VARCHAR; + v_year SMALLINT; + v_month VARCHAR; + v_res_date DATE; + v_hijridate DATE; + v_culture VARCHAR; + v_dayparts TEXT[]; + v_resmask VARCHAR; + v_raw_year VARCHAR; + v_left_part VARCHAR; + v_right_part VARCHAR; + v_resmask_fi VARCHAR; + v_datestring VARCHAR; + v_timestring VARCHAR; + v_correctnum VARCHAR; + v_weekdaynum SMALLINT; + v_err_message VARCHAR; + v_date_format VARCHAR; + v_weekdaynames TEXT[]; + v_hours SMALLINT := 0; + v_minutes SMALLINT := 0; + v_seconds NUMERIC := 0; + v_found BOOLEAN := TRUE; + v_compday_regexp VARCHAR; + v_regmatch_groups TEXT[]; + v_compmonth_regexp VARCHAR; + v_lang_metadata_json JSONB; + v_resmask_cnt SMALLINT := 10; + DAYMM_REGEXP CONSTANT VARCHAR := '(\d{1,2})'; + FULLYEAR_REGEXP CONSTANT VARCHAR := '(\d{3,4})'; + SHORTYEAR_REGEXP CONSTANT VARCHAR := '(\d{1,2})'; + COMPYEAR_REGEXP CONSTANT VARCHAR := '(\d{1,4})'; + AMPM_REGEXP CONSTANT VARCHAR := '(?:[AP]M|ص|م)'; + TIMEUNIT_REGEXP CONSTANT VARCHAR := '\s*\d{1,2}\s*'; + MASKSEPONE_REGEXP CONSTANT VARCHAR := '\s*(?:/|-)?'; + MASKSEPTWO_REGEXP CONSTANT VARCHAR := '\s*(?:\s|/|-|\.|,)'; + MASKSEPTWO_FI_REGEXP CONSTANT VARCHAR := '\s*(?:\s|/|-|,)'; + MASKSEPTHREE_REGEXP CONSTANT VARCHAR := '\s*(?:/|-|\.|,)'; + TIME_MASKSEP_REGEXP CONSTANT VARCHAR := '(?:\s|\.|,)*'; + TIME_MASKSEP_FI_REGEXP CONSTANT VARCHAR := '(?:\s|,)*'; + WEEKDAYAMPM_START_REGEXP CONSTANT VARCHAR := '(^|[[:digit:][:space:]\.,])'; + WEEKDAYAMPM_END_REGEXP CONSTANT VARCHAR := '([[:digit:][:space:]\.,]|$)(?=[^/-]|$)'; + CORRECTNUM_REGEXP CONSTANT VARCHAR := '(?:([+-]\d{1,4})(?:[[:space:]\.,]|[AP]M|ص|م|$))'; + ANNO_DOMINI_REGEXP VARCHAR := '(AD|A\.D\.)'; + ANNO_DOMINI_COMPREGEXP VARCHAR := concat(WEEKDAYAMPM_START_REGEXP, ANNO_DOMINI_REGEXP, WEEKDAYAMPM_END_REGEXP); + HHMMSSFS_PART_REGEXP CONSTANT VARCHAR := + concat(TIMEUNIT_REGEXP, AMPM_REGEXP, '|', + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, TIMEUNIT_REGEXP, '\:', TIME_MASKSEP_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, TIMEUNIT_REGEXP, '(?!\d)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?|', + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, TIMEUNIT_REGEXP, '\:', TIME_MASKSEP_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, TIMEUNIT_REGEXP, '\:', TIME_MASKSEP_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, TIMEUNIT_REGEXP, '(?!\d)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?|', + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, TIMEUNIT_REGEXP, '\:', TIME_MASKSEP_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, TIMEUNIT_REGEXP, '\:', TIME_MASKSEP_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\s*\d{1,2}\.\d+(?!\d)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?|', + AMPM_REGEXP, '?'); + HHMMSSFS_PART_FI_REGEXP CONSTANT VARCHAR := + concat(TIMEUNIT_REGEXP, AMPM_REGEXP, '|', + AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, TIMEUNIT_REGEXP, '[\:\.]', TIME_MASKSEP_FI_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, TIMEUNIT_REGEXP, '(?!\d)', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?\.?|', + AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, TIMEUNIT_REGEXP, '[\:\.]', TIME_MASKSEP_FI_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, TIMEUNIT_REGEXP, '[\:\.]', TIME_MASKSEP_FI_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, TIMEUNIT_REGEXP, '(?!\d)', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?|', + AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, TIMEUNIT_REGEXP, '[\:\.]', TIME_MASKSEP_FI_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, TIMEUNIT_REGEXP, '[\:\.]', TIME_MASKSEP_FI_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, '\s*\d{1,2}\.\d+(?!\d)\.?', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?|', + AMPM_REGEXP, '?'); + v_defmask1_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, + '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, + CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + TIME_MASKSEP_REGEXP, '(?:[\.|,]+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)', TIME_MASKSEP_REGEXP, '$'); + v_defmask1_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, CORRECTNUM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, + '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_FI_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:', MASKSEPTWO_FI_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, + CORRECTNUM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:[,]+', AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, CORRECTNUM_REGEXP, '?))', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + TIME_MASKSEP_FI_REGEXP, '(?:[\.|,]+', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask2_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, + '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, + AMPM_REGEXP, TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + TIME_MASKSEP_REGEXP, '(?:(?:[\.|,]+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?)|', + CORRECTNUM_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, '$'); + v_defmask2_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, CORRECTNUM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, + '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + CORRECTNUM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_FI_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_FI_REGEXP, CORRECTNUM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, + AMPM_REGEXP, TIME_MASKSEP_FI_REGEXP, CORRECTNUM_REGEXP, '?))', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + TIME_MASKSEP_FI_REGEXP, '(?:(?:[\.|,]+', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, TIME_MASKSEP_FI_REGEXP, CORRECTNUM_REGEXP, '?)|', + CORRECTNUM_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask3_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, ')|', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + TIME_MASKSEP_REGEXP, '(', TIME_MASKSEP_REGEXP, AMPM_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask3_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + TIME_MASKSEP_FI_REGEXP, '[\./]?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)', + FULLYEAR_REGEXP, + TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask4_0_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, '\s*(', AMPM_REGEXP, ')', + TIME_MASKSEP_REGEXP, '$'); + v_defmask4_1_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:\s|,)+', + DAYMM_REGEXP, '\s*(', AMPM_REGEXP, ')', + TIME_MASKSEP_REGEXP, '$'); + v_defmask4_2_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '\s*[\.]+', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, '\s*(', AMPM_REGEXP, ')', + TIME_MASKSEP_REGEXP, '$'); + v_defmask5_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask5_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_FI_REGEXP, + FULLYEAR_REGEXP, + TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask6_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '((?:(?:\s|\.|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_REGEXP, '))?', TIME_MASKSEP_REGEXP, '$'); + v_defmask6_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:\s*[\.])?', + '((?:(?:\s|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_FI_REGEXP, '))?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask7_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '((?:(?:\s|\.|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_REGEXP, '))?', TIME_MASKSEP_REGEXP, '$'); + v_defmask7_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_FI_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '((?:(?:\s|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_FI_REGEXP, '))?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask8_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:[\.|,]+', AMPM_REGEXP, ')?', + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask8_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_FI_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:[,]+', AMPM_REGEXP, '))', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:[,]+', AMPM_REGEXP, '))', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:(?:[\,]+|\s*/\s*)', AMPM_REGEXP, ')?', + TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask9_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', + HHMMSSFS_PART_REGEXP, + ')', TIME_MASKSEP_REGEXP, '$'); + v_defmask9_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, '(', + HHMMSSFS_PART_FI_REGEXP, + ')', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask10_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)?', TIME_MASKSEP_REGEXP, + '($comp_month$)', + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask10_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)?', TIME_MASKSEP_REGEXP, + '($comp_month$)', + TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask11_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask11_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '((?:(?:\s|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_FI_REGEXP, '))?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask12_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask12_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask13_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$'); + v_defmask13_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask14_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + '($comp_month$)' + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)', TIME_MASKSEP_REGEXP, + COMPYEAR_REGEXP, + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask14_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + '($comp_month$)' + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)', TIME_MASKSEP_FI_REGEXP, + COMPYEAR_REGEXP, + '((?:(?:\s|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_FI_REGEXP, '))?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask15_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + COMPYEAR_REGEXP, + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask15_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + COMPYEAR_REGEXP, + '((?:(?:\s|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_FI_REGEXP, '))?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask16_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)', TIME_MASKSEP_REGEXP, + COMPYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask16_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)', TIME_MASKSEP_REGEXP, + COMPYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask17_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask17_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '((?:(?:\s|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_FI_REGEXP, '))?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask18_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask18_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask19_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '((?:(?:\s|\.|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_REGEXP, '))?', TIME_MASKSEP_REGEXP, '$'); + v_defmask19_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '((?:(?:\s|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_FI_REGEXP, '))?', TIME_MASKSEP_FI_REGEXP, '$'); + CONVERSION_LANG CONSTANT VARCHAR := ''; + DATE_FORMAT CONSTANT VARCHAR := ''; +BEGIN + v_datestring := upper(trim(p_datestring)); + v_culture := coalesce(nullif(upper(trim(p_culture)), ''), 'EN-US'); + + v_dayparts := ARRAY(SELECT upper(array_to_string(regexp_matches(v_datestring, '[AP]M|ص|م', 'gi'), ''))); + + IF (array_length(v_dayparts, 1) > 1) THEN + RAISE invalid_datetime_format; + END IF; + + BEGIN + v_lang_metadata_json := sys.babelfish_get_lang_metadata_json(coalesce(nullif(CONVERSION_LANG, ''), p_culture)); + EXCEPTION + WHEN OTHERS THEN + RAISE invalid_parameter_value; + END; + + v_compday_regexp := array_to_string(array_cat(array_cat(ARRAY(SELECT jsonb_array_elements_text(v_lang_metadata_json -> 'days_names')), + ARRAY(SELECT jsonb_array_elements_text(v_lang_metadata_json -> 'days_shortnames'))), + ARRAY(SELECT jsonb_array_elements_text(v_lang_metadata_json -> 'days_extrashortnames'))), '|'); + + v_weekdaynames := ARRAY(SELECT array_to_string(regexp_matches(v_datestring, v_compday_regexp, 'gi'), '')); + + IF (array_length(v_weekdaynames, 1) > 1) THEN + RAISE invalid_datetime_format; + END IF; + + IF (v_weekdaynames[1] IS NOT NULL AND + v_datestring ~* concat(WEEKDAYAMPM_START_REGEXP, '(', v_compday_regexp, ')', WEEKDAYAMPM_END_REGEXP)) + THEN + v_datestring := replace(v_datestring, v_weekdaynames[1], ' '); + END IF; + + IF (v_datestring ~* ANNO_DOMINI_COMPREGEXP) + THEN + IF (v_culture !~ 'EN[-_]US|DA[-_]DK|SV[-_]SE|EN[-_]GB|HI[-_]IS') THEN + RAISE invalid_datetime_format; + END IF; + + v_datestring := regexp_replace(v_datestring, + ANNO_DOMINI_COMPREGEXP, + regexp_replace(array_to_string(regexp_matches(v_datestring, ANNO_DOMINI_COMPREGEXP, 'gi'), ''), + ANNO_DOMINI_REGEXP, ' ', 'gi'), + 'gi'); + END IF; + + v_date_format := coalesce(nullif(upper(trim(DATE_FORMAT)), ''), v_lang_metadata_json ->> 'date_format'); + + v_compmonth_regexp := + array_to_string(array_cat(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'))), + array_cat(ARRAY(SELECT jsonb_array_elements_text(v_lang_metadata_json -> 'months_extrashortnames')), + ARRAY(SELECT jsonb_array_elements_text(v_lang_metadata_json -> 'months_extranames'))) + ), '|'); + + IF ((v_datestring ~* v_defmask1_regexp AND v_culture <> 'FI') OR + (v_datestring ~* v_defmask1_fi_regexp AND v_culture = 'FI')) + THEN + IF (v_datestring ~ concat(CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d+\s*(?:\.)+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, + CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}|', + '\d+\s*(?:\.)+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, + CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$') AND + v_culture ~ 'DE[-_]DE|NN[-_]NO|CS[-_]CZ|PL[-_]PL|RO[-_]RO|SK[-_]SK|SL[-_]SI|BG[-_]BG|RU[-_]RU|TR[-_]TR|ET[-_]EE|LV[-_]LV') + THEN + RAISE invalid_datetime_format; + END IF; + + v_regmatch_groups := regexp_matches(v_datestring, CASE v_culture + WHEN 'FI' THEN v_defmask1_fi_regexp + ELSE v_defmask1_regexp + END, 'gi'); + v_timestring := v_regmatch_groups[2]; + v_correctnum := coalesce(v_regmatch_groups[1], v_regmatch_groups[3], + v_regmatch_groups[5], v_regmatch_groups[6]); + + IF (v_date_format = 'DMY' OR + v_culture IN ('SV-SE', 'SV_SE', 'LV-LV', 'LV_LV')) + THEN + v_day := v_regmatch_groups[4]; + v_month := v_regmatch_groups[7]; + ELSE + v_day := v_regmatch_groups[7]; + v_month := v_regmatch_groups[4]; + END IF; + + IF (v_culture IN ('AR', 'AR-SA', 'AR_SA')) + THEN + IF (v_day::SMALLINT > 30 OR + v_month::SMALLINT > 12) THEN + RAISE invalid_datetime_format; + END IF; + + v_raw_year := to_char(sys.babelfish_conv_greg_to_hijri(current_date + 1), 'YYYY'); + v_hijridate := sys.babelfish_conv_hijri_to_greg(v_day, v_month, v_raw_year) - 1; + + v_day := to_char(v_hijridate, 'DD'); + v_month := to_char(v_hijridate, 'MM'); + v_year := to_char(v_hijridate, 'YYYY')::SMALLINT; + ELSE + v_year := to_char(current_date, 'YYYY')::SMALLINT; + END IF; + + ELSIF ((v_datestring ~* v_defmask6_regexp AND v_culture <> 'FI') OR + (v_datestring ~* v_defmask6_fi_regexp AND v_culture = 'FI')) + THEN + IF (v_culture IN ('AR', 'AR-SA', 'AR_SA') OR + (v_datestring ~ concat('\s*\d{1,2}\.\s*(?:\.|\d+(?!\d)\s*\.)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{3,4}', + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, '\d{1,2}|', + '\d{3,4}', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}', MASKSEPTWO_REGEXP, + TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}\s*(?:\.)+|', + '\d+\s*(?:\.)+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$') AND + v_culture ~ 'DE[-_]DE|NN[-_]NO|CS[-_]CZ|PL[-_]PL|RO[-_]RO|SK[-_]SK|SL[-_]SI|BG[-_]BG|RU[-_]RU|TR[-_]TR|ET[-_]EE|LV[-_]LV')) + THEN + RAISE invalid_datetime_format; + END IF; + + v_regmatch_groups := regexp_matches(v_datestring, CASE v_culture + WHEN 'FI' THEN v_defmask6_fi_regexp + ELSE v_defmask6_regexp + END, 'gi'); + v_timestring := concat(v_regmatch_groups[1], v_regmatch_groups[5]); + v_day := v_regmatch_groups[4]; + v_month := v_regmatch_groups[3]; + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN v_regmatch_groups[2]::SMALLINT - 543 + ELSE v_regmatch_groups[2]::SMALLINT + END; + + ELSIF ((v_datestring ~* v_defmask2_regexp AND v_culture <> 'FI') OR + (v_datestring ~* v_defmask2_fi_regexp AND v_culture = 'FI')) + THEN + IF (v_culture IN ('AR', 'AR-SA', 'AR_SA') OR + (v_datestring ~ concat('\s*\d{1,2}\.\s*(?:\.|\d+(?!\d)\s*\.)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{3,4}', + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, + AMPM_REGEXP, TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?))', TIME_MASKSEP_REGEXP, '\d{1,2}|', + '\d+\s*(?:\.)+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$') AND + v_culture ~ 'DE[-_]DE|NN[-_]NO|CS[-_]CZ|PL[-_]PL|RO[-_]RO|SK[-_]SK|SL[-_]SI|BG[-_]BG|RU[-_]RU|TR[-_]TR|ET[-_]EE|LV[-_]LV')) + THEN + RAISE invalid_datetime_format; + END IF; + + v_regmatch_groups := regexp_matches(v_datestring, CASE v_culture + WHEN 'FI' THEN v_defmask2_fi_regexp + ELSE v_defmask2_regexp + END, 'gi'); + v_timestring := v_regmatch_groups[2]; + v_correctnum := coalesce(v_regmatch_groups[1], v_regmatch_groups[3], v_regmatch_groups[5], + v_regmatch_groups[6], v_regmatch_groups[8], v_regmatch_groups[9]); + v_day := '01'; + v_month := v_regmatch_groups[7]; + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN v_regmatch_groups[4]::SMALLINT - 543 + ELSE v_regmatch_groups[4]::SMALLINT + END; + + ELSIF (v_datestring ~* v_defmask4_1_regexp OR + (v_datestring ~* v_defmask4_2_regexp AND v_culture !~ 'DE[-_]DE|NN[-_]NO|CS[-_]CZ|PL[-_]PL|RO[-_]RO|SK[-_]SK|SL[-_]SI|BG[-_]BG|RU[-_]RU|TR[-_]TR|ET[-_]EE|LV[-_]LV') OR + (v_datestring ~* v_defmask9_regexp AND v_culture <> 'FI') OR + (v_datestring ~* v_defmask9_fi_regexp AND v_culture = 'FI')) + THEN + IF (v_datestring ~ concat('\d+\s*\.?(?:,+|,*', AMPM_REGEXP, ')', TIME_MASKSEP_FI_REGEXP, '\.+', TIME_MASKSEP_REGEXP, '$|', + '\d+\s*\.', TIME_MASKSEP_FI_REGEXP, '\.', TIME_MASKSEP_FI_REGEXP, '$') AND + v_culture = 'FI') + THEN + RAISE invalid_datetime_format; + END IF; + + IF (v_datestring ~* v_defmask4_0_regexp) THEN + v_timestring := (regexp_matches(v_datestring, v_defmask4_0_regexp, 'gi'))[1]; + ELSE + v_timestring := v_datestring; + END IF; + + v_res_date := current_date; + v_day := to_char(v_res_date, 'DD'); + v_month := to_char(v_res_date, 'MM'); + v_year := to_char(v_res_date, 'YYYY')::SMALLINT; + + ELSIF ((v_datestring ~* v_defmask3_regexp AND v_culture <> 'FI') OR + (v_datestring ~* v_defmask3_fi_regexp AND v_culture = 'FI')) + THEN + IF (v_culture IN ('AR', 'AR-SA', 'AR_SA') OR + (v_datestring ~ concat('\s*\d{1,2}\.\s*(?:\.|\d+(?!\d)\s*\.)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', + TIME_MASKSEP_REGEXP, '\d{1,2}', MASKSEPTWO_REGEXP, '|', + '\d+\s*(?:\.)+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$') AND + v_culture ~ 'DE[-_]DE|NN[-_]NO|CS[-_]CZ|PL[-_]PL|RO[-_]RO|SK[-_]SK|SL[-_]SI|BG[-_]BG|RU[-_]RU|TR[-_]TR|ET[-_]EE|LV[-_]LV')) + THEN + RAISE invalid_datetime_format; + END IF; + + v_regmatch_groups := regexp_matches(v_datestring, CASE v_culture + WHEN 'FI' THEN v_defmask3_fi_regexp + ELSE v_defmask3_regexp + END, 'gi'); + v_timestring := v_regmatch_groups[1]; + v_day := '01'; + v_month := v_regmatch_groups[2]; + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN v_regmatch_groups[3]::SMALLINT - 543 + ELSE v_regmatch_groups[3]::SMALLINT + END; + + ELSIF ((v_datestring ~* v_defmask5_regexp AND v_culture <> 'FI') OR + (v_datestring ~* v_defmask5_fi_regexp AND v_culture = 'FI')) + THEN + IF (v_culture IN ('AR', 'AR-SA', 'AR_SA') OR + (v_datestring ~ concat('\s*\d{1,2}\.\s*(?:\.|\d+(?!\d)\s*\.)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}', MASKSEPTWO_REGEXP, + TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}', MASKSEPTWO_REGEXP, + TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{3,4}', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$|', + '\d{1,2}', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{3,4}\s*(?:\.)+|', + '\d+\s*(?:\.)+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$') AND + v_culture ~ 'DE[-_]DE|NN[-_]NO|CS[-_]CZ|PL[-_]PL|RO[-_]RO|SK[-_]SK|SL[-_]SI|BG[-_]BG|RU[-_]RU|TR[-_]TR|ET[-_]EE|LV[-_]LV')) + THEN + RAISE invalid_datetime_format; + END IF; + + v_regmatch_groups := regexp_matches(v_datestring, v_defmask5_regexp, 'gi'); + v_timestring := concat(v_regmatch_groups[1], v_regmatch_groups[5]); + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN v_regmatch_groups[4]::SMALLINT - 543 + ELSE v_regmatch_groups[4]::SMALLINT + END; + + IF (v_date_format = 'DMY' OR + v_culture IN ('LV-LV', 'LV_LV')) + THEN + v_day := v_regmatch_groups[2]; + v_month := v_regmatch_groups[3]; + ELSE + v_day := v_regmatch_groups[3]; + v_month := v_regmatch_groups[2]; + END IF; + + ELSIF ((v_datestring ~* v_defmask7_regexp AND v_culture <> 'FI') OR + (v_datestring ~* v_defmask7_fi_regexp AND v_culture = 'FI')) + THEN + IF (v_culture IN ('AR', 'AR-SA', 'AR_SA') OR + (v_datestring ~ concat('\s*\d{1,2}\.\s*(?:\.|\d+(?!\d)\s*\.)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}', + MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{3,4}|', + '\d{3,4}', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}\s*(?:\.)+|', + '\d+\s*(?:\.)+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$') AND + v_culture ~ 'DE[-_]DE|NN[-_]NO|CS[-_]CZ|PL[-_]PL|RO[-_]RO|SK[-_]SK|SL[-_]SI|BG[-_]BG|RU[-_]RU|TR[-_]TR|ET[-_]EE|LV[-_]LV')) + THEN + RAISE invalid_datetime_format; + END IF; + + v_regmatch_groups := regexp_matches(v_datestring, CASE v_culture + WHEN 'FI' THEN v_defmask7_fi_regexp + ELSE v_defmask7_regexp + END, 'gi'); + v_timestring := concat(v_regmatch_groups[1], v_regmatch_groups[5]); + v_day := v_regmatch_groups[4]; + v_month := v_regmatch_groups[2]; + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN v_regmatch_groups[3]::SMALLINT - 543 + ELSE v_regmatch_groups[3]::SMALLINT + END; + + ELSIF ((v_datestring ~* v_defmask8_regexp AND v_culture <> 'FI') OR + (v_datestring ~* v_defmask8_fi_regexp AND v_culture = 'FI')) + THEN + IF (v_datestring ~ concat('\s*\d{1,2}\.\s*(?:\.|\d+(?!\d)\s*\.)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}', + MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}', MASKSEPTWO_REGEXP, + TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}|', + '\d{1,2}', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}', MASKSEPTWO_REGEXP, + TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}\s*(?:\.)+|', + '\d+\s*(?:\.)+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$') AND + v_culture ~ 'FI|DE[-_]DE|NN[-_]NO|CS[-_]CZ|PL[-_]PL|RO[-_]RO|SK[-_]SK|SL[-_]SI|BG[-_]BG|RU[-_]RU|TR[-_]TR|ET[-_]EE|LV[-_]LV') + THEN + RAISE invalid_datetime_format; + END IF; + + v_regmatch_groups := regexp_matches(v_datestring, CASE v_culture + WHEN 'FI' THEN v_defmask8_fi_regexp + ELSE v_defmask8_regexp + END, 'gi'); + v_timestring := concat(v_regmatch_groups[1], v_regmatch_groups[5]); + + IF (v_date_format = 'DMY' OR + v_culture IN ('LV-LV', 'LV_LV')) + THEN + v_day := v_regmatch_groups[2]; + v_month := v_regmatch_groups[3]; + v_raw_year := v_regmatch_groups[4]; + ELSIF (v_date_format = 'YMD') + THEN + v_day := v_regmatch_groups[4]; + v_month := v_regmatch_groups[3]; + v_raw_year := v_regmatch_groups[2]; + ELSE + v_day := v_regmatch_groups[3]; + v_month := v_regmatch_groups[2]; + v_raw_year := v_regmatch_groups[4]; + END IF; + + IF (v_culture IN ('AR', 'AR-SA', 'AR_SA')) + THEN + IF (v_day::SMALLINT > 30 OR + v_month::SMALLINT > 12) THEN + RAISE invalid_datetime_format; + END IF; + + v_raw_year := sys.babelfish_get_full_year(v_raw_year, '14'); + v_hijridate := sys.babelfish_conv_hijri_to_greg(v_day, v_month, v_raw_year) - 1; + + v_day := to_char(v_hijridate, 'DD'); + v_month := to_char(v_hijridate, 'MM'); + v_year := to_char(v_hijridate, 'YYYY')::SMALLINT; + + ELSIF (v_culture IN ('TH-TH', 'TH_TH')) THEN + v_year := sys.babelfish_get_full_year(v_raw_year)::SMALLINT - 43; + ELSE + v_year := sys.babelfish_get_full_year(v_raw_year, '', 29)::SMALLINT; + END IF; + ELSE + v_found := FALSE; + END IF; + + WHILE (NOT v_found AND v_resmask_cnt < 20) + LOOP + v_resmask := replace(CASE v_resmask_cnt + WHEN 10 THEN v_defmask10_regexp + WHEN 11 THEN v_defmask11_regexp + WHEN 12 THEN v_defmask12_regexp + WHEN 13 THEN v_defmask13_regexp + WHEN 14 THEN v_defmask14_regexp + WHEN 15 THEN v_defmask15_regexp + WHEN 16 THEN v_defmask16_regexp + WHEN 17 THEN v_defmask17_regexp + WHEN 18 THEN v_defmask18_regexp + WHEN 19 THEN v_defmask19_regexp + END, + '$comp_month$', v_compmonth_regexp); + + v_resmask_fi := replace(CASE v_resmask_cnt + WHEN 10 THEN v_defmask10_fi_regexp + WHEN 11 THEN v_defmask11_fi_regexp + WHEN 12 THEN v_defmask12_fi_regexp + WHEN 13 THEN v_defmask13_fi_regexp + WHEN 14 THEN v_defmask14_fi_regexp + WHEN 15 THEN v_defmask15_fi_regexp + WHEN 16 THEN v_defmask16_fi_regexp + WHEN 17 THEN v_defmask17_fi_regexp + WHEN 18 THEN v_defmask18_fi_regexp + WHEN 19 THEN v_defmask19_fi_regexp + END, + '$comp_month$', v_compmonth_regexp); + + IF ((v_datestring ~* v_resmask AND v_culture <> 'FI') OR + (v_datestring ~* v_resmask_fi AND v_culture = 'FI')) + THEN + v_found := TRUE; + v_regmatch_groups := regexp_matches(v_datestring, CASE v_culture + WHEN 'FI' THEN v_resmask_fi + ELSE v_resmask + END, 'gi'); + v_timestring := CASE + WHEN v_resmask_cnt IN (10, 11, 12, 13) THEN concat(v_regmatch_groups[1], v_regmatch_groups[4]) + ELSE concat(v_regmatch_groups[1], v_regmatch_groups[5]) + END; + + IF (v_resmask_cnt = 10) + THEN + IF (v_regmatch_groups[3] = 'MAR' AND + v_culture IN ('IT-IT', 'IT_IT')) + THEN + RAISE invalid_datetime_format; + END IF; + + IF (v_date_format = 'YMD' AND v_culture NOT IN ('SV-SE', 'SV_SE', 'LV-LV', 'LV_LV')) + THEN + v_day := '01'; + v_year := sys.babelfish_get_full_year(v_regmatch_groups[2], '', 29)::SMALLINT; + ELSE + v_day := v_regmatch_groups[2]; + v_year := to_char(current_date, 'YYYY')::SMALLINT; + END IF; + + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[3], v_lang_metadata_json); + v_raw_year := to_char(sys.babelfish_conv_greg_to_hijri(current_date + 1), 'YYYY'); + + ELSIF (v_resmask_cnt = 11) + THEN + IF (v_date_format IN ('YMD', 'MDY') AND v_culture NOT IN ('SV-SE', 'SV_SE')) + THEN + v_day := v_regmatch_groups[3]; + v_year := to_char(current_date, 'YYYY')::SMALLINT; + ELSE + v_day := '01'; + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN sys.babelfish_get_full_year(v_regmatch_groups[3])::SMALLINT - 43 + ELSE sys.babelfish_get_full_year(v_regmatch_groups[3], '', 29)::SMALLINT + END; + END IF; + + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[2], v_lang_metadata_json); + v_raw_year := sys.babelfish_get_full_year(substring(v_year::TEXT, 3, 2), '14'); + + ELSIF (v_resmask_cnt = 12) + THEN + v_day := '01'; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[3], v_lang_metadata_json); + v_raw_year := v_regmatch_groups[2]; + + ELSIF (v_resmask_cnt = 13) + THEN + v_day := '01'; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[2], v_lang_metadata_json); + v_raw_year := v_regmatch_groups[3]; + + ELSIF (v_resmask_cnt IN (14, 15, 16)) + THEN + IF (v_resmask_cnt = 14) + THEN + v_left_part := v_regmatch_groups[4]; + v_right_part := v_regmatch_groups[3]; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[2], v_lang_metadata_json); + ELSIF (v_resmask_cnt = 15) + THEN + v_left_part := v_regmatch_groups[4]; + v_right_part := v_regmatch_groups[2]; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[3], v_lang_metadata_json); + ELSE + v_left_part := v_regmatch_groups[3]; + v_right_part := v_regmatch_groups[2]; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[4], v_lang_metadata_json); + END IF; + + IF (char_length(v_left_part) <= 2) + THEN + IF (v_date_format = 'YMD' AND v_culture NOT IN ('LV-LV', 'LV_LV')) + THEN + v_day := v_left_part; + v_raw_year := sys.babelfish_get_full_year(v_right_part, '14'); + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN sys.babelfish_get_full_year(v_right_part)::SMALLINT - 43 + ELSE sys.babelfish_get_full_year(v_right_part, '', 29)::SMALLINT + END; + BEGIN + v_res_date := make_date(v_year, v_month::SMALLINT, v_day::SMALLINT); + EXCEPTION + WHEN OTHERS THEN + v_day := v_right_part; + v_raw_year := sys.babelfish_get_full_year(v_left_part, '14'); + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN sys.babelfish_get_full_year(v_left_part)::SMALLINT - 43 + ELSE sys.babelfish_get_full_year(v_left_part, '', 29)::SMALLINT + END; + END; + END IF; + + IF (v_date_format IN ('MDY', 'DMY') OR v_culture IN ('LV-LV', 'LV_LV')) + THEN + v_day := v_right_part; + v_raw_year := sys.babelfish_get_full_year(v_left_part, '14'); + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN sys.babelfish_get_full_year(v_left_part)::SMALLINT - 43 + ELSE sys.babelfish_get_full_year(v_left_part, '', 29)::SMALLINT + END; + BEGIN + v_res_date := make_date(v_year, v_month::SMALLINT, v_day::SMALLINT); + EXCEPTION + WHEN OTHERS THEN + v_day := v_left_part; + v_raw_year := sys.babelfish_get_full_year(v_right_part, '14'); + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN sys.babelfish_get_full_year(v_right_part)::SMALLINT - 43 + ELSE sys.babelfish_get_full_year(v_right_part, '', 29)::SMALLINT + END; + END; + END IF; + ELSE + v_day := v_right_part; + v_raw_year := v_left_part; + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN v_left_part::SMALLINT - 543 + ELSE v_left_part::SMALLINT + END; + END IF; + + ELSIF (v_resmask_cnt = 17) + THEN + v_day := v_regmatch_groups[4]; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[3], v_lang_metadata_json); + v_raw_year := v_regmatch_groups[2]; + + ELSIF (v_resmask_cnt = 18) + THEN + v_day := v_regmatch_groups[3]; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[4], v_lang_metadata_json); + v_raw_year := v_regmatch_groups[2]; + + ELSIF (v_resmask_cnt = 19) + THEN + v_day := v_regmatch_groups[4]; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[2], v_lang_metadata_json); + v_raw_year := v_regmatch_groups[3]; + END IF; + + IF (v_resmask_cnt NOT IN (10, 11, 14, 15, 16)) + THEN + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN v_raw_year::SMALLINT - 543 + ELSE v_raw_year::SMALLINT + END; + END IF; + + IF (v_culture IN ('AR', 'AR-SA', 'AR_SA')) + THEN + IF (v_day::SMALLINT > 30 OR + (v_resmask_cnt NOT IN (10, 11, 14, 15, 16) AND v_year NOT BETWEEN 1318 AND 1501) OR + (v_resmask_cnt IN (14, 15, 16) AND v_raw_year::SMALLINT NOT BETWEEN 1318 AND 1501)) + THEN + RAISE invalid_datetime_format; + END IF; + + v_hijridate := sys.babelfish_conv_hijri_to_greg(v_day, v_month, v_raw_year) - 1; + + v_day := to_char(v_hijridate, 'DD'); + v_month := to_char(v_hijridate, 'MM'); + v_year := to_char(v_hijridate, 'YYYY')::SMALLINT; + END IF; + END IF; + + v_resmask_cnt := v_resmask_cnt + 1; + END LOOP; + + IF (NOT v_found) THEN + RAISE invalid_datetime_format; + END IF; + + IF (char_length(v_timestring) > 0 AND v_timestring NOT IN ('AM', 'ص', 'PM', 'م')) + THEN + IF (v_culture = 'FI') THEN + v_timestring := translate(v_timestring, '.,', ': '); + + IF (char_length(split_part(v_timestring, ':', 4)) > 0) THEN + v_timestring := regexp_replace(v_timestring, ':(?=\s*\d+\s*:?\s*(?:[AP]M|ص|م)?\s*$)', '.'); + END IF; + END IF; + + v_timestring := replace(regexp_replace(v_timestring, '\.?[AP]M|ص|م|\s|\,|\.\D|[\.|:]$', '', 'gi'), ':.', ':'); + BEGIN + v_hours := coalesce(split_part(v_timestring, ':', 1)::SMALLINT, 0); + + IF ((v_dayparts[1] IN ('AM', 'ص') AND v_hours NOT BETWEEN 0 AND 12) OR + (v_dayparts[1] IN ('PM', 'م') AND v_hours NOT BETWEEN 1 AND 23)) + THEN + RAISE invalid_datetime_format; + END IF; + + v_minutes := coalesce(nullif(split_part(v_timestring, ':', 2), '')::SMALLINT, 0); + v_seconds := coalesce(nullif(split_part(v_timestring, ':', 3), '')::NUMERIC, 0); + EXCEPTION + WHEN OTHERS THEN + RAISE invalid_datetime_format; + END; + ELSIF (v_dayparts[1] IN ('PM', 'م')) + THEN + v_hours := 12; + END IF; + + v_res_date := make_timestamp(v_year, v_month::SMALLINT, v_day::SMALLINT, + v_hours, v_minutes, v_seconds); + + IF (v_weekdaynames[1] IS NOT NULL) THEN + v_weekdaynum := sys.babelfish_get_weekdaynum_by_name(v_weekdaynames[1], v_lang_metadata_json); + + IF (CASE date_part('dow', v_res_date)::SMALLINT + WHEN 0 THEN 7 + ELSE date_part('dow', v_res_date)::SMALLINT + END <> v_weekdaynum) + THEN + RAISE invalid_datetime_format; + END IF; + END IF; + + RETURN v_res_date; +EXCEPTION + WHEN invalid_datetime_format OR datetime_field_overflow THEN + RAISE USING MESSAGE := format('Error converting string value ''%s'' into data type DATE using culture ''%s''.', + p_datestring, p_culture), + 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_parameter_value THEN + RAISE USING MESSAGE := CASE char_length(coalesce(CONVERSION_LANG, '')) + WHEN 0 THEN format('The culture parameter ''%s'' provided in the function call is not supported.', + p_culture) + ELSE format('Invalid CONVERSION_LANG constant value - ''%s''. Allowed values are: ''English'', ''Deutsch'', etc.', + CONVERSION_LANG) + END, + DETAIL := 'Passed incorrect value for "p_culture" parameter or compiled incorrect CONVERSION_LANG constant value in function''s body.', + HINT := 'Check "p_culture" input parameter value, correct it if needed, and try again. Also check CONVERSION_LANG constant value.'; + + 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 := format('Error while trying to convert "%s" value to SMALLINT data type.', + v_err_message), + DETAIL := 'Supplied value contains illegal characters.', + HINT := 'Correct supplied value, remove all illegal characters.'; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_parse_to_datetime(IN p_datatype TEXT, + IN p_datetimestring TEXT, + IN p_culture TEXT DEFAULT '') +RETURNS TIMESTAMP WITHOUT TIME ZONE +AS +$BODY$ +DECLARE + v_day VARCHAR; + v_year SMALLINT; + v_month VARCHAR; + v_res_date DATE; + v_scale SMALLINT; + v_hijridate DATE; + v_culture VARCHAR; + v_dayparts TEXT[]; + v_resmask VARCHAR; + v_datatype VARCHAR; + v_raw_year VARCHAR; + v_left_part VARCHAR; + v_right_part VARCHAR; + v_resmask_fi VARCHAR; + v_timestring VARCHAR; + v_correctnum VARCHAR; + v_weekdaynum SMALLINT; + v_err_message VARCHAR; + v_date_format VARCHAR; + v_weekdaynames TEXT[]; + v_hours SMALLINT := 0; + v_minutes SMALLINT := 0; + v_res_datatype VARCHAR; + v_error_message VARCHAR; + v_found BOOLEAN := TRUE; + v_compday_regexp VARCHAR; + v_regmatch_groups TEXT[]; + v_datatype_groups TEXT[]; + v_datetimestring VARCHAR; + v_seconds VARCHAR := '0'; + v_fseconds VARCHAR := '0'; + v_compmonth_regexp VARCHAR; + v_lang_metadata_json JSONB; + v_resmask_cnt SMALLINT := 10; + v_res_datetime TIMESTAMP(6) WITHOUT TIME ZONE; + DAYMM_REGEXP CONSTANT VARCHAR := '(\d{1,2})'; + FULLYEAR_REGEXP CONSTANT VARCHAR := '(\d{3,4})'; + SHORTYEAR_REGEXP CONSTANT VARCHAR := '(\d{1,2})'; + COMPYEAR_REGEXP CONSTANT VARCHAR := '(\d{1,4})'; + AMPM_REGEXP CONSTANT VARCHAR := '(?:[AP]M|ص|م)'; + TIMEUNIT_REGEXP CONSTANT VARCHAR := '\s*\d{1,2}\s*'; + MASKSEPONE_REGEXP CONSTANT VARCHAR := '\s*(?:/|-)?'; + MASKSEPTWO_REGEXP CONSTANT VARCHAR := '\s*(?:\s|/|-|\.|,)'; + MASKSEPTWO_FI_REGEXP CONSTANT VARCHAR := '\s*(?:\s|/|-|,)'; + MASKSEPTHREE_REGEXP CONSTANT VARCHAR := '\s*(?:/|-|\.|,)'; + TIME_MASKSEP_REGEXP CONSTANT VARCHAR := '(?:\s|\.|,)*'; + TIME_MASKSEP_FI_REGEXP CONSTANT VARCHAR := '(?:\s|,)*'; + WEEKDAYAMPM_START_REGEXP CONSTANT VARCHAR := '(^|[[:digit:][:space:]\.,])'; + WEEKDAYAMPM_END_REGEXP CONSTANT VARCHAR := '([[:digit:][:space:]\.,]|$)(?=[^/-]|$)'; + CORRECTNUM_REGEXP CONSTANT VARCHAR := '(?:([+-]\d{1,4})(?:[[:space:]\.,]|[AP]M|ص|م|$))'; + DATATYPE_REGEXP CONSTANT VARCHAR := '^(DATETIME|SMALLDATETIME|DATETIME2)\s*(?:\()?\s*((?:-)?\d+)?\s*(?:\))?$'; + ANNO_DOMINI_REGEXP VARCHAR := '(AD|A\.D\.)'; + ANNO_DOMINI_COMPREGEXP VARCHAR := concat(WEEKDAYAMPM_START_REGEXP, ANNO_DOMINI_REGEXP, WEEKDAYAMPM_END_REGEXP); + HHMMSSFS_PART_REGEXP CONSTANT VARCHAR := + concat(TIMEUNIT_REGEXP, AMPM_REGEXP, '|', + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, TIMEUNIT_REGEXP, '\:', TIME_MASKSEP_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, TIMEUNIT_REGEXP, '(?!\d)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?|', + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, TIMEUNIT_REGEXP, '\:', TIME_MASKSEP_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, TIMEUNIT_REGEXP, '\:', TIME_MASKSEP_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, TIMEUNIT_REGEXP, '(?!\d)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?|', + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, TIMEUNIT_REGEXP, '\:', TIME_MASKSEP_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, TIMEUNIT_REGEXP, '\:', TIME_MASKSEP_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\s*\d{1,2}\.\d+(?!\d)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?|', + AMPM_REGEXP, '?'); + HHMMSSFS_PART_FI_REGEXP CONSTANT VARCHAR := + concat(TIMEUNIT_REGEXP, AMPM_REGEXP, '|', + AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, TIMEUNIT_REGEXP, '[\:\.]', TIME_MASKSEP_FI_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, TIMEUNIT_REGEXP, '(?!\d)', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?\.?|', + AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, TIMEUNIT_REGEXP, '[\:\.]', TIME_MASKSEP_FI_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, TIMEUNIT_REGEXP, '[\:\.]', TIME_MASKSEP_FI_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, TIMEUNIT_REGEXP, '(?!\d)', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?|', + AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, TIMEUNIT_REGEXP, '[\:\.]', TIME_MASKSEP_FI_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, TIMEUNIT_REGEXP, '[\:\.]', TIME_MASKSEP_FI_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, '\s*\d{1,2}\.\d+(?!\d)\.?', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?|', + AMPM_REGEXP, '?'); + v_defmask1_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, + '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, + CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + TIME_MASKSEP_REGEXP, '(?:[\.|,]+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)', TIME_MASKSEP_REGEXP, '$'); + v_defmask1_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, CORRECTNUM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, + '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_FI_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:', MASKSEPTWO_FI_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, + CORRECTNUM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:[,]+', AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, CORRECTNUM_REGEXP, '?))', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + TIME_MASKSEP_FI_REGEXP, '(?:[\.|,]+', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask2_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, + '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, + AMPM_REGEXP, TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + TIME_MASKSEP_REGEXP, '(?:(?:[\.|,]+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?)|', + CORRECTNUM_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, '$'); + v_defmask2_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, CORRECTNUM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, + '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + CORRECTNUM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_FI_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_FI_REGEXP, CORRECTNUM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, + AMPM_REGEXP, TIME_MASKSEP_FI_REGEXP, CORRECTNUM_REGEXP, '?))', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + TIME_MASKSEP_FI_REGEXP, '(?:(?:[\.|,]+', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, TIME_MASKSEP_FI_REGEXP, CORRECTNUM_REGEXP, '?)|', + CORRECTNUM_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask3_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, ')|', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + TIME_MASKSEP_REGEXP, '(', TIME_MASKSEP_REGEXP, AMPM_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask3_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + TIME_MASKSEP_FI_REGEXP, '[\./]?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)', + FULLYEAR_REGEXP, + TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask4_0_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, '\s*(', AMPM_REGEXP, ')', + TIME_MASKSEP_REGEXP, '$'); + v_defmask4_1_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:\s|,)+', + DAYMM_REGEXP, '\s*(', AMPM_REGEXP, ')', + TIME_MASKSEP_REGEXP, '$'); + v_defmask4_2_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '\s*[\.]+', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, '\s*(', AMPM_REGEXP, ')', + TIME_MASKSEP_REGEXP, '$'); + v_defmask5_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask5_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_FI_REGEXP, + FULLYEAR_REGEXP, + TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask6_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '((?:(?:\s|\.|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_REGEXP, '))?', TIME_MASKSEP_REGEXP, '$'); + v_defmask6_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:\s*[\.])?', + '((?:(?:\s|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_FI_REGEXP, '))?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask7_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '((?:(?:\s|\.|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_REGEXP, '))?', TIME_MASKSEP_REGEXP, '$'); + v_defmask7_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_FI_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '((?:(?:\s|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_FI_REGEXP, '))?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask8_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:[\.|,]+', AMPM_REGEXP, ')?', + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask8_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_FI_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:[,]+', AMPM_REGEXP, '))', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:[,]+', AMPM_REGEXP, '))', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:(?:[\,]+|\s*/\s*)', AMPM_REGEXP, ')?', + TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask9_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', + HHMMSSFS_PART_REGEXP, + ')', TIME_MASKSEP_REGEXP, '$'); + v_defmask9_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, '(', + HHMMSSFS_PART_FI_REGEXP, + ')', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask10_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)?', TIME_MASKSEP_REGEXP, + '($comp_month$)', + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask10_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)?', TIME_MASKSEP_REGEXP, + '($comp_month$)', + TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask11_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask11_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '((?:(?:\s|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_FI_REGEXP, '))?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask12_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask12_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask13_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$'); + v_defmask13_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask14_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + '($comp_month$)' + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)', TIME_MASKSEP_REGEXP, + COMPYEAR_REGEXP, + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask14_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + '($comp_month$)' + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)', TIME_MASKSEP_FI_REGEXP, + COMPYEAR_REGEXP, + '((?:(?:\s|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_FI_REGEXP, '))?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask15_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + COMPYEAR_REGEXP, + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask15_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + COMPYEAR_REGEXP, + '((?:(?:\s|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_FI_REGEXP, '))?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask16_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)', TIME_MASKSEP_REGEXP, + COMPYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask16_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)', TIME_MASKSEP_REGEXP, + COMPYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask17_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask17_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '((?:(?:\s|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_FI_REGEXP, '))?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask18_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask18_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask19_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '((?:(?:\s|\.|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_REGEXP, '))?', TIME_MASKSEP_REGEXP, '$'); + v_defmask19_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '((?:(?:\s|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_FI_REGEXP, '))?', TIME_MASKSEP_FI_REGEXP, '$'); + CONVERSION_LANG CONSTANT VARCHAR := ''; + DATE_FORMAT CONSTANT VARCHAR := ''; +BEGIN + v_datatype := trim(p_datatype); + v_datetimestring := upper(trim(p_datetimestring)); + v_culture := coalesce(nullif(upper(trim(p_culture)), ''), 'EN-US'); + + 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; + + v_dayparts := ARRAY(SELECT upper(array_to_string(regexp_matches(v_datetimestring, '[AP]M|ص|م', 'gi'), ''))); + + IF (array_length(v_dayparts, 1) > 1) THEN + RAISE invalid_datetime_format; + END IF; + + BEGIN + v_lang_metadata_json := sys.babelfish_get_lang_metadata_json(coalesce(nullif(CONVERSION_LANG, ''), p_culture)); + EXCEPTION + WHEN OTHERS THEN + RAISE invalid_parameter_value; + END; + + v_compday_regexp := array_to_string(array_cat(array_cat(ARRAY(SELECT jsonb_array_elements_text(v_lang_metadata_json -> 'days_names')), + ARRAY(SELECT jsonb_array_elements_text(v_lang_metadata_json -> 'days_shortnames'))), + ARRAY(SELECT jsonb_array_elements_text(v_lang_metadata_json -> 'days_extrashortnames'))), '|'); + + v_weekdaynames := ARRAY(SELECT array_to_string(regexp_matches(v_datetimestring, v_compday_regexp, 'gi'), '')); + + IF (array_length(v_weekdaynames, 1) > 1) THEN + RAISE invalid_datetime_format; + END IF; + + IF (v_weekdaynames[1] IS NOT NULL AND + v_datetimestring ~* concat(WEEKDAYAMPM_START_REGEXP, '(', v_compday_regexp, ')', WEEKDAYAMPM_END_REGEXP)) + THEN + v_datetimestring := replace(v_datetimestring, v_weekdaynames[1], ' '); + END IF; + + IF (v_datetimestring ~* ANNO_DOMINI_COMPREGEXP) + THEN + IF (v_culture !~ 'EN[-_]US|DA[-_]DK|SV[-_]SE|EN[-_]GB|HI[-_]IS') THEN + RAISE invalid_datetime_format; + END IF; + + v_datetimestring := regexp_replace(v_datetimestring, + ANNO_DOMINI_COMPREGEXP, + regexp_replace(array_to_string(regexp_matches(v_datetimestring, ANNO_DOMINI_COMPREGEXP, 'gi'), ''), + ANNO_DOMINI_REGEXP, ' ', 'gi'), + 'gi'); + END IF; + + v_date_format := coalesce(nullif(upper(trim(DATE_FORMAT)), ''), v_lang_metadata_json ->> 'date_format'); + + v_compmonth_regexp := + array_to_string(array_cat(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'))), + array_cat(ARRAY(SELECT jsonb_array_elements_text(v_lang_metadata_json -> 'months_extrashortnames')), + ARRAY(SELECT jsonb_array_elements_text(v_lang_metadata_json -> 'months_extranames'))) + ), '|'); + + IF ((v_datetimestring ~* v_defmask1_regexp AND v_culture <> 'FI') OR + (v_datetimestring ~* v_defmask1_fi_regexp AND v_culture = 'FI')) + THEN + IF (v_datetimestring ~ concat(CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d+\s*(?:\.)+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, + CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}|', + '\d+\s*(?:\.)+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, + CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$') AND + v_culture ~ 'DE[-_]DE|NN[-_]NO|CS[-_]CZ|PL[-_]PL|RO[-_]RO|SK[-_]SK|SL[-_]SI|BG[-_]BG|RU[-_]RU|TR[-_]TR|ET[-_]EE|LV[-_]LV') + THEN + RAISE invalid_datetime_format; + END IF; + + v_regmatch_groups := regexp_matches(v_datetimestring, CASE v_culture + WHEN 'FI' THEN v_defmask1_fi_regexp + ELSE v_defmask1_regexp + END, 'gi'); + v_timestring := v_regmatch_groups[2]; + v_correctnum := coalesce(v_regmatch_groups[1], v_regmatch_groups[3], + v_regmatch_groups[5], v_regmatch_groups[6]); + + IF (v_date_format = 'DMY' OR + v_culture IN ('SV-SE', 'SV_SE', 'LV-LV', 'LV_LV')) + THEN + v_day := v_regmatch_groups[4]; + v_month := v_regmatch_groups[7]; + ELSE + v_day := v_regmatch_groups[7]; + v_month := v_regmatch_groups[4]; + END IF; + + IF (v_culture IN ('AR', 'AR-SA', 'AR_SA')) + THEN + IF (v_day::SMALLINT > 30 OR + v_month::SMALLINT > 12) THEN + RAISE invalid_datetime_format; + END IF; + + v_raw_year := to_char(sys.babelfish_conv_greg_to_hijri(current_date + 1), 'YYYY'); + v_hijridate := sys.babelfish_conv_hijri_to_greg(v_day, v_month, v_raw_year) - 1; + + v_day := to_char(v_hijridate, 'DD'); + v_month := to_char(v_hijridate, 'MM'); + v_year := to_char(v_hijridate, 'YYYY')::SMALLINT; + ELSE + v_year := to_char(current_date, 'YYYY')::SMALLINT; + END IF; + + ELSIF ((v_datetimestring ~* v_defmask6_regexp AND v_culture <> 'FI') OR + (v_datetimestring ~* v_defmask6_fi_regexp AND v_culture = 'FI')) + THEN + IF (v_culture IN ('AR', 'AR-SA', 'AR_SA') OR + (v_datetimestring ~ concat('\s*\d{1,2}\.\s*(?:\.|\d+(?!\d)\s*\.)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{3,4}', + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, '\d{1,2}|', + '\d{3,4}', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}', MASKSEPTWO_REGEXP, + TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}\s*(?:\.)+|', + '\d+\s*(?:\.)+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$') AND + v_culture ~ 'DE[-_]DE|NN[-_]NO|CS[-_]CZ|PL[-_]PL|RO[-_]RO|SK[-_]SK|SL[-_]SI|BG[-_]BG|RU[-_]RU|TR[-_]TR|ET[-_]EE|LV[-_]LV')) + THEN + RAISE invalid_datetime_format; + END IF; + + v_regmatch_groups := regexp_matches(v_datetimestring, CASE v_culture + WHEN 'FI' THEN v_defmask6_fi_regexp + ELSE v_defmask6_regexp + END, 'gi'); + v_timestring := concat(v_regmatch_groups[1], v_regmatch_groups[5]); + v_day := v_regmatch_groups[4]; + v_month := v_regmatch_groups[3]; + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN v_regmatch_groups[2]::SMALLINT - 543 + ELSE v_regmatch_groups[2]::SMALLINT + END; + + ELSIF ((v_datetimestring ~* v_defmask2_regexp AND v_culture <> 'FI') OR + (v_datetimestring ~* v_defmask2_fi_regexp AND v_culture = 'FI')) + THEN + IF (v_culture IN ('AR', 'AR-SA', 'AR_SA') OR + (v_datetimestring ~ concat('\s*\d{1,2}\.\s*(?:\.|\d+(?!\d)\s*\.)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{3,4}', + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, + AMPM_REGEXP, TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?))', TIME_MASKSEP_REGEXP, '\d{1,2}|', + '\d+\s*(?:\.)+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$') AND + v_culture ~ 'DE[-_]DE|NN[-_]NO|CS[-_]CZ|PL[-_]PL|RO[-_]RO|SK[-_]SK|SL[-_]SI|BG[-_]BG|RU[-_]RU|TR[-_]TR|ET[-_]EE|LV[-_]LV')) + THEN + RAISE invalid_datetime_format; + END IF; + + v_regmatch_groups := regexp_matches(v_datetimestring, CASE v_culture + WHEN 'FI' THEN v_defmask2_fi_regexp + ELSE v_defmask2_regexp + END, 'gi'); + v_timestring := v_regmatch_groups[2]; + v_correctnum := coalesce(v_regmatch_groups[1], v_regmatch_groups[3], v_regmatch_groups[5], + v_regmatch_groups[6], v_regmatch_groups[8], v_regmatch_groups[9]); + v_day := '01'; + v_month := v_regmatch_groups[7]; + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN v_regmatch_groups[4]::SMALLINT - 543 + ELSE v_regmatch_groups[4]::SMALLINT + END; + + ELSIF (v_datetimestring ~* v_defmask4_1_regexp OR + (v_datetimestring ~* v_defmask4_2_regexp AND v_culture !~ 'DE[-_]DE|NN[-_]NO|CS[-_]CZ|PL[-_]PL|RO[-_]RO|SK[-_]SK|SL[-_]SI|BG[-_]BG|RU[-_]RU|TR[-_]TR|ET[-_]EE|LV[-_]LV') OR + (v_datetimestring ~* v_defmask9_regexp AND v_culture <> 'FI') OR + (v_datetimestring ~* v_defmask9_fi_regexp AND v_culture = 'FI')) + THEN + IF (v_datetimestring ~ concat('\d+\s*\.?(?:,+|,*', AMPM_REGEXP, ')', TIME_MASKSEP_FI_REGEXP, '\.+', TIME_MASKSEP_REGEXP, '$|', + '\d+\s*\.', TIME_MASKSEP_FI_REGEXP, '\.', TIME_MASKSEP_FI_REGEXP, '$') AND + v_culture = 'FI') + THEN + RAISE invalid_datetime_format; + END IF; + + IF (v_datetimestring ~* v_defmask4_0_regexp) THEN + v_timestring := (regexp_matches(v_datetimestring, v_defmask4_0_regexp, 'gi'))[1]; + ELSE + v_timestring := v_datetimestring; + END IF; + + v_res_date := current_date; + v_day := to_char(v_res_date, 'DD'); + v_month := to_char(v_res_date, 'MM'); + v_year := to_char(v_res_date, 'YYYY')::SMALLINT; + + ELSIF ((v_datetimestring ~* v_defmask3_regexp AND v_culture <> 'FI') OR + (v_datetimestring ~* v_defmask3_fi_regexp AND v_culture = 'FI')) + THEN + IF (v_culture IN ('AR', 'AR-SA', 'AR_SA') OR + (v_datetimestring ~ concat('\s*\d{1,2}\.\s*(?:\.|\d+(?!\d)\s*\.)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', + TIME_MASKSEP_REGEXP, '\d{1,2}', MASKSEPTWO_REGEXP, '|', + '\d+\s*(?:\.)+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$') AND + v_culture ~ 'DE[-_]DE|NN[-_]NO|CS[-_]CZ|PL[-_]PL|RO[-_]RO|SK[-_]SK|SL[-_]SI|BG[-_]BG|RU[-_]RU|TR[-_]TR|ET[-_]EE|LV[-_]LV')) + THEN + RAISE invalid_datetime_format; + END IF; + + v_regmatch_groups := regexp_matches(v_datetimestring, CASE v_culture + WHEN 'FI' THEN v_defmask3_fi_regexp + ELSE v_defmask3_regexp + END, 'gi'); + v_timestring := v_regmatch_groups[1]; + v_day := '01'; + v_month := v_regmatch_groups[2]; + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN v_regmatch_groups[3]::SMALLINT - 543 + ELSE v_regmatch_groups[3]::SMALLINT + END; + + ELSIF ((v_datetimestring ~* v_defmask5_regexp AND v_culture <> 'FI') OR + (v_datetimestring ~* v_defmask5_fi_regexp AND v_culture = 'FI')) + THEN + IF (v_culture IN ('AR', 'AR-SA', 'AR_SA') OR + (v_datetimestring ~ concat('\s*\d{1,2}\.\s*(?:\.|\d+(?!\d)\s*\.)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}', MASKSEPTWO_REGEXP, + TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}', MASKSEPTWO_REGEXP, + TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{3,4}', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$|', + '\d{1,2}', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{3,4}\s*(?:\.)+|', + '\d+\s*(?:\.)+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$') AND + v_culture ~ 'DE[-_]DE|NN[-_]NO|CS[-_]CZ|PL[-_]PL|RO[-_]RO|SK[-_]SK|SL[-_]SI|BG[-_]BG|RU[-_]RU|TR[-_]TR|ET[-_]EE|LV[-_]LV')) + THEN + RAISE invalid_datetime_format; + END IF; + + v_regmatch_groups := regexp_matches(v_datetimestring, v_defmask5_regexp, 'gi'); + v_timestring := concat(v_regmatch_groups[1], v_regmatch_groups[5]); + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN v_regmatch_groups[4]::SMALLINT - 543 + ELSE v_regmatch_groups[4]::SMALLINT + END; + + IF (v_date_format = 'DMY' OR + v_culture IN ('LV-LV', 'LV_LV')) + THEN + v_day := v_regmatch_groups[2]; + v_month := v_regmatch_groups[3]; + ELSE + v_day := v_regmatch_groups[3]; + v_month := v_regmatch_groups[2]; + END IF; + + ELSIF ((v_datetimestring ~* v_defmask7_regexp AND v_culture <> 'FI') OR + (v_datetimestring ~* v_defmask7_fi_regexp AND v_culture = 'FI')) + THEN + IF (v_culture IN ('AR', 'AR-SA', 'AR_SA') OR + (v_datetimestring ~ concat('\s*\d{1,2}\.\s*(?:\.|\d+(?!\d)\s*\.)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}', + MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{3,4}|', + '\d{3,4}', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}\s*(?:\.)+|', + '\d+\s*(?:\.)+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$') AND + v_culture ~ 'DE[-_]DE|NN[-_]NO|CS[-_]CZ|PL[-_]PL|RO[-_]RO|SK[-_]SK|SL[-_]SI|BG[-_]BG|RU[-_]RU|TR[-_]TR|ET[-_]EE|LV[-_]LV')) + THEN + RAISE invalid_datetime_format; + END IF; + + v_regmatch_groups := regexp_matches(v_datetimestring, CASE v_culture + WHEN 'FI' THEN v_defmask7_fi_regexp + ELSE v_defmask7_regexp + END, 'gi'); + v_timestring := concat(v_regmatch_groups[1], v_regmatch_groups[5]); + v_day := v_regmatch_groups[4]; + v_month := v_regmatch_groups[2]; + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN v_regmatch_groups[3]::SMALLINT - 543 + ELSE v_regmatch_groups[3]::SMALLINT + END; + + ELSIF ((v_datetimestring ~* v_defmask8_regexp AND v_culture <> 'FI') OR + (v_datetimestring ~* v_defmask8_fi_regexp AND v_culture = 'FI')) + THEN + IF (v_datetimestring ~ concat('\s*\d{1,2}\.\s*(?:\.|\d+(?!\d)\s*\.)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}', + MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}', MASKSEPTWO_REGEXP, + TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}|', + '\d{1,2}', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}', MASKSEPTWO_REGEXP, + TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}\s*(?:\.)+|', + '\d+\s*(?:\.)+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$') AND + v_culture ~ 'FI|DE[-_]DE|NN[-_]NO|CS[-_]CZ|PL[-_]PL|RO[-_]RO|SK[-_]SK|SL[-_]SI|BG[-_]BG|RU[-_]RU|TR[-_]TR|ET[-_]EE|LV[-_]LV') + THEN + RAISE invalid_datetime_format; + END IF; + + v_regmatch_groups := regexp_matches(v_datetimestring, CASE v_culture + WHEN 'FI' THEN v_defmask8_fi_regexp + ELSE v_defmask8_regexp + END, 'gi'); + v_timestring := concat(v_regmatch_groups[1], v_regmatch_groups[5]); + + IF (v_date_format = 'DMY' OR + v_culture IN ('LV-LV', 'LV_LV')) + THEN + v_day := v_regmatch_groups[2]; + v_month := v_regmatch_groups[3]; + v_raw_year := v_regmatch_groups[4]; + ELSIF (v_date_format = 'YMD') + THEN + v_day := v_regmatch_groups[4]; + v_month := v_regmatch_groups[3]; + v_raw_year := v_regmatch_groups[2]; + ELSE + v_day := v_regmatch_groups[3]; + v_month := v_regmatch_groups[2]; + v_raw_year := v_regmatch_groups[4]; + END IF; + + IF (v_culture IN ('AR', 'AR-SA', 'AR_SA')) + THEN + IF (v_day::SMALLINT > 30 OR + v_month::SMALLINT > 12) THEN + RAISE invalid_datetime_format; + END IF; + + v_raw_year := sys.babelfish_get_full_year(v_raw_year, '14'); + v_hijridate := sys.babelfish_conv_hijri_to_greg(v_day, v_month, v_raw_year) - 1; + + v_day := to_char(v_hijridate, 'DD'); + v_month := to_char(v_hijridate, 'MM'); + v_year := to_char(v_hijridate, 'YYYY')::SMALLINT; + + ELSIF (v_culture IN ('TH-TH', 'TH_TH')) THEN + v_year := sys.babelfish_get_full_year(v_raw_year)::SMALLINT - 43; + ELSE + v_year := sys.babelfish_get_full_year(v_raw_year, '', 29)::SMALLINT; + END IF; + ELSE + v_found := FALSE; + END IF; + + WHILE (NOT v_found AND v_resmask_cnt < 20) + LOOP + v_resmask := replace(CASE v_resmask_cnt + WHEN 10 THEN v_defmask10_regexp + WHEN 11 THEN v_defmask11_regexp + WHEN 12 THEN v_defmask12_regexp + WHEN 13 THEN v_defmask13_regexp + WHEN 14 THEN v_defmask14_regexp + WHEN 15 THEN v_defmask15_regexp + WHEN 16 THEN v_defmask16_regexp + WHEN 17 THEN v_defmask17_regexp + WHEN 18 THEN v_defmask18_regexp + WHEN 19 THEN v_defmask19_regexp + END, + '$comp_month$', v_compmonth_regexp); + + v_resmask_fi := replace(CASE v_resmask_cnt + WHEN 10 THEN v_defmask10_fi_regexp + WHEN 11 THEN v_defmask11_fi_regexp + WHEN 12 THEN v_defmask12_fi_regexp + WHEN 13 THEN v_defmask13_fi_regexp + WHEN 14 THEN v_defmask14_fi_regexp + WHEN 15 THEN v_defmask15_fi_regexp + WHEN 16 THEN v_defmask16_fi_regexp + WHEN 17 THEN v_defmask17_fi_regexp + WHEN 18 THEN v_defmask18_fi_regexp + WHEN 19 THEN v_defmask19_fi_regexp + END, + '$comp_month$', v_compmonth_regexp); + + IF ((v_datetimestring ~* v_resmask AND v_culture <> 'FI') OR + (v_datetimestring ~* v_resmask_fi AND v_culture = 'FI')) + THEN + v_found := TRUE; + v_regmatch_groups := regexp_matches(v_datetimestring, CASE v_culture + WHEN 'FI' THEN v_resmask_fi + ELSE v_resmask + END, 'gi'); + v_timestring := CASE + WHEN v_resmask_cnt IN (10, 11, 12, 13) THEN concat(v_regmatch_groups[1], v_regmatch_groups[4]) + ELSE concat(v_regmatch_groups[1], v_regmatch_groups[5]) + END; + + IF (v_resmask_cnt = 10) + THEN + IF (v_regmatch_groups[3] = 'MAR' AND + v_culture IN ('IT-IT', 'IT_IT')) + THEN + RAISE invalid_datetime_format; + END IF; + + IF (v_date_format = 'YMD' AND v_culture NOT IN ('SV-SE', 'SV_SE', 'LV-LV', 'LV_LV')) + THEN + v_day := '01'; + v_year := sys.babelfish_get_full_year(v_regmatch_groups[2], '', 29)::SMALLINT; + ELSE + v_day := v_regmatch_groups[2]; + v_year := to_char(current_date, 'YYYY')::SMALLINT; + END IF; + + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[3], v_lang_metadata_json); + v_raw_year := to_char(sys.babelfish_conv_greg_to_hijri(current_date + 1), 'YYYY'); + + ELSIF (v_resmask_cnt = 11) + THEN + IF (v_date_format IN ('YMD', 'MDY') AND v_culture NOT IN ('SV-SE', 'SV_SE')) + THEN + v_day := v_regmatch_groups[3]; + v_year := to_char(current_date, 'YYYY')::SMALLINT; + ELSE + v_day := '01'; + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN sys.babelfish_get_full_year(v_regmatch_groups[3])::SMALLINT - 43 + ELSE sys.babelfish_get_full_year(v_regmatch_groups[3], '', 29)::SMALLINT + END; + END IF; + + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[2], v_lang_metadata_json); + v_raw_year := sys.babelfish_get_full_year(substring(v_year::TEXT, 3, 2), '14'); + + ELSIF (v_resmask_cnt = 12) + THEN + v_day := '01'; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[3], v_lang_metadata_json); + v_raw_year := v_regmatch_groups[2]; + + ELSIF (v_resmask_cnt = 13) + THEN + v_day := '01'; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[2], v_lang_metadata_json); + v_raw_year := v_regmatch_groups[3]; + + ELSIF (v_resmask_cnt IN (14, 15, 16)) + THEN + IF (v_resmask_cnt = 14) + THEN + v_left_part := v_regmatch_groups[4]; + v_right_part := v_regmatch_groups[3]; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[2], v_lang_metadata_json); + ELSIF (v_resmask_cnt = 15) + THEN + v_left_part := v_regmatch_groups[4]; + v_right_part := v_regmatch_groups[2]; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[3], v_lang_metadata_json); + ELSE + v_left_part := v_regmatch_groups[3]; + v_right_part := v_regmatch_groups[2]; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[4], v_lang_metadata_json); + END IF; + + IF (char_length(v_left_part) <= 2) + THEN + IF (v_date_format = 'YMD' AND v_culture NOT IN ('LV-LV', 'LV_LV')) + THEN + v_day := v_left_part; + v_raw_year := sys.babelfish_get_full_year(v_right_part, '14'); + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN sys.babelfish_get_full_year(v_right_part)::SMALLINT - 43 + ELSE sys.babelfish_get_full_year(v_right_part, '', 29)::SMALLINT + END; + BEGIN + v_res_date := make_date(v_year, v_month::SMALLINT, v_day::SMALLINT); + EXCEPTION + WHEN OTHERS THEN + v_day := v_right_part; + v_raw_year := sys.babelfish_get_full_year(v_left_part, '14'); + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN sys.babelfish_get_full_year(v_left_part)::SMALLINT - 43 + ELSE sys.babelfish_get_full_year(v_left_part, '', 29)::SMALLINT + END; + END; + END IF; + + IF (v_date_format IN ('MDY', 'DMY') OR v_culture IN ('LV-LV', 'LV_LV')) + THEN + v_day := v_right_part; + v_raw_year := sys.babelfish_get_full_year(v_left_part, '14'); + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN sys.babelfish_get_full_year(v_left_part)::SMALLINT - 43 + ELSE sys.babelfish_get_full_year(v_left_part, '', 29)::SMALLINT + END; + BEGIN + v_res_date := make_date(v_year, v_month::SMALLINT, v_day::SMALLINT); + EXCEPTION + WHEN OTHERS THEN + v_day := v_left_part; + v_raw_year := sys.babelfish_get_full_year(v_right_part, '14'); + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN sys.babelfish_get_full_year(v_right_part)::SMALLINT - 43 + ELSE sys.babelfish_get_full_year(v_right_part, '', 29)::SMALLINT + END; + END; + END IF; + ELSE + v_day := v_right_part; + v_raw_year := v_left_part; + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN v_left_part::SMALLINT - 543 + ELSE v_left_part::SMALLINT + END; + END IF; + + ELSIF (v_resmask_cnt = 17) + THEN + v_day := v_regmatch_groups[4]; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[3], v_lang_metadata_json); + v_raw_year := v_regmatch_groups[2]; + + ELSIF (v_resmask_cnt = 18) + THEN + v_day := v_regmatch_groups[3]; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[4], v_lang_metadata_json); + v_raw_year := v_regmatch_groups[2]; + + ELSIF (v_resmask_cnt = 19) + THEN + v_day := v_regmatch_groups[4]; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[2], v_lang_metadata_json); + v_raw_year := v_regmatch_groups[3]; + END IF; + + IF (v_resmask_cnt NOT IN (10, 11, 14, 15, 16)) + THEN + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN v_raw_year::SMALLINT - 543 + ELSE v_raw_year::SMALLINT + END; + END IF; + + IF (v_culture IN ('AR', 'AR-SA', 'AR_SA')) + THEN + IF (v_day::SMALLINT > 30 OR + (v_resmask_cnt NOT IN (10, 11, 14, 15, 16) AND v_year NOT BETWEEN 1318 AND 1501) OR + (v_resmask_cnt IN (14, 15, 16) AND v_raw_year::SMALLINT NOT BETWEEN 1318 AND 1501)) + THEN + RAISE invalid_datetime_format; + END IF; + + v_hijridate := sys.babelfish_conv_hijri_to_greg(v_day, v_month, v_raw_year) - 1; + + v_day := to_char(v_hijridate, 'DD'); + v_month := to_char(v_hijridate, 'MM'); + v_year := to_char(v_hijridate, 'YYYY')::SMALLINT; + END IF; + END IF; + + v_resmask_cnt := v_resmask_cnt + 1; + END LOOP; + + IF (NOT v_found) THEN + RAISE invalid_datetime_format; + END IF; + + IF (char_length(v_timestring) > 0 AND v_timestring NOT IN ('AM', 'ص', 'PM', 'م')) + THEN + IF (v_culture = 'FI') THEN + v_timestring := translate(v_timestring, '.,', ': '); + + IF (char_length(split_part(v_timestring, ':', 4)) > 0) THEN + v_timestring := regexp_replace(v_timestring, ':(?=\s*\d+\s*:?\s*(?:[AP]M|ص|م)?\s*$)', '.'); + END IF; + END IF; + + v_timestring := replace(regexp_replace(v_timestring, '\.?[AP]M|ص|م|\s|\,|\.\D|[\.|:]$', '', 'gi'), ':.', ':'); + BEGIN + v_hours := coalesce(split_part(v_timestring, ':', 1)::SMALLINT, 0); + + IF ((v_dayparts[1] IN ('AM', 'ص') AND v_hours NOT BETWEEN 0 AND 12) OR + (v_dayparts[1] IN ('PM', 'م') AND v_hours NOT BETWEEN 1 AND 23)) + THEN + RAISE invalid_datetime_format; + ELSIF (v_dayparts[1] = 'PM' AND v_hours < 12) THEN + v_hours := v_hours + 12; + ELSIF (v_dayparts[1] = 'AM' AND v_hours = 12) THEN + v_hours := v_hours - 12; + END IF; + + v_minutes := coalesce(nullif(split_part(v_timestring, ':', 2), '')::SMALLINT, 0); + v_seconds := coalesce(nullif(split_part(v_timestring, ':', 3), ''), '0'); + + IF (v_seconds ~ '\.') THEN + v_fseconds := split_part(v_seconds, '.', 2); + v_seconds := split_part(v_seconds, '.', 1); + END IF; + EXCEPTION + WHEN OTHERS THEN + RAISE invalid_datetime_format; + END; + ELSIF (v_dayparts[1] IN ('PM', 'م')) + THEN + v_hours := 12; + END IF; + + BEGIN + IF (v_res_datatype IN ('DATETIME', 'SMALLDATETIME')) + THEN + v_res_datetime := sys.datetimefromparts(v_year, v_month::SMALLINT, v_day::SMALLINT, + v_hours, v_minutes, v_seconds::SMALLINT, + rpad(v_fseconds, 3, '0')::NUMERIC); + IF (v_res_datatype = 'SMALLDATETIME' AND + to_char(v_res_datetime, 'SS') <> '00') + THEN + IF (to_char(v_res_datetime, 'SS')::SMALLINT >= 30) THEN + v_res_datetime := v_res_datetime + INTERVAL '1 minute'; + END IF; + + v_res_datetime := to_timestamp(to_char(v_res_datetime, 'DD.MM.YYYY.HH24.MI'), 'DD.MM.YYYY.HH24.MI'); + END IF; + ELSE + v_fseconds := sys.babelfish_get_microsecs_from_fractsecs(rpad(v_fseconds, 9, '0'), v_scale); + v_seconds := concat_ws('.', v_seconds, v_fseconds); + + v_res_datetime := make_timestamp(v_year, v_month::SMALLINT, v_day::SMALLINT, + v_hours, v_minutes, v_seconds::NUMERIC); + END IF; + EXCEPTION + WHEN OTHERS THEN + GET STACKED DIAGNOSTICS v_err_message = MESSAGE_TEXT; + + IF (v_err_message ~* 'Cannot construct data type') THEN + RAISE invalid_datetime_format; + END IF; + END; + + IF (v_weekdaynames[1] IS NOT NULL) THEN + v_weekdaynum := sys.babelfish_get_weekdaynum_by_name(v_weekdaynames[1], v_lang_metadata_json); + + IF (CASE date_part('dow', v_res_date)::SMALLINT + WHEN 0 THEN 7 + ELSE date_part('dow', v_res_date)::SMALLINT + END <> v_weekdaynum) + THEN + RAISE invalid_datetime_format; + END IF; + END IF; + + RETURN v_res_datetime; +EXCEPTION + WHEN invalid_datetime_format OR datetime_field_overflow THEN + RAISE USING MESSAGE := format('Error converting string value ''%s'' into data type %s using culture ''%s''.', + p_datetimestring, v_res_datatype, p_culture), + 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 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 := 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 := 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_parameter_value THEN + RAISE USING MESSAGE := CASE char_length(coalesce(CONVERSION_LANG, '')) + WHEN 0 THEN format('The culture parameter ''%s'' provided in the function call is not supported.', + p_culture) + ELSE format('Invalid CONVERSION_LANG constant value - ''%s''. Allowed values are: ''English'', ''Deutsch'', etc.', + CONVERSION_LANG) + END, + DETAIL := 'Passed incorrect value for "p_culture" parameter or compiled incorrect CONVERSION_LANG constant value in function''s body.', + HINT := 'Check "p_culture" input parameter value, correct it if needed, and try again. Also check CONVERSION_LANG constant value.'; + + 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 := format('Error while trying to convert "%s" value to SMALLINT data type.', + v_err_message), + DETAIL := 'Supplied value contains illegal characters.', + HINT := 'Correct supplied value, remove all illegal characters.'; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_parse_to_time(IN p_datatype TEXT, + IN p_srctimestring TEXT, + IN p_culture TEXT DEFAULT '') +RETURNS TIME WITHOUT TIME ZONE +AS +$BODY$ +DECLARE + v_day VARCHAR; + v_year SMALLINT; + v_month VARCHAR; + v_res_date DATE; + v_scale SMALLINT; + v_hijridate DATE; + v_culture VARCHAR; + v_dayparts TEXT[]; + v_resmask VARCHAR; + v_datatype VARCHAR; + v_raw_year VARCHAR; + v_left_part VARCHAR; + v_right_part VARCHAR; + v_resmask_fi VARCHAR; + v_timestring VARCHAR; + v_correctnum VARCHAR; + v_weekdaynum SMALLINT; + v_err_message VARCHAR; + v_date_format VARCHAR; + v_weekdaynames TEXT[]; + v_hours SMALLINT := 0; + v_srctimestring VARCHAR; + v_minutes SMALLINT := 0; + v_res_datatype VARCHAR; + v_error_message VARCHAR; + v_found BOOLEAN := TRUE; + v_compday_regexp VARCHAR; + v_regmatch_groups TEXT[]; + v_datatype_groups TEXT[]; + v_seconds VARCHAR := '0'; + v_fseconds VARCHAR := '0'; + v_compmonth_regexp VARCHAR; + v_lang_metadata_json JSONB; + v_resmask_cnt SMALLINT := 10; + v_res_time TIME WITHOUT TIME ZONE; + DAYMM_REGEXP CONSTANT VARCHAR := '(\d{1,2})'; + FULLYEAR_REGEXP CONSTANT VARCHAR := '(\d{3,4})'; + SHORTYEAR_REGEXP CONSTANT VARCHAR := '(\d{1,2})'; + COMPYEAR_REGEXP CONSTANT VARCHAR := '(\d{1,4})'; + AMPM_REGEXP CONSTANT VARCHAR := '(?:[AP]M|ص|م)'; + TIMEUNIT_REGEXP CONSTANT VARCHAR := '\s*\d{1,2}\s*'; + MASKSEPONE_REGEXP CONSTANT VARCHAR := '\s*(?:/|-)?'; + MASKSEPTWO_REGEXP CONSTANT VARCHAR := '\s*(?:\s|/|-|\.|,)'; + MASKSEPTWO_FI_REGEXP CONSTANT VARCHAR := '\s*(?:\s|/|-|,)'; + MASKSEPTHREE_REGEXP CONSTANT VARCHAR := '\s*(?:/|-|\.|,)'; + TIME_MASKSEP_REGEXP CONSTANT VARCHAR := '(?:\s|\.|,)*'; + TIME_MASKSEP_FI_REGEXP CONSTANT VARCHAR := '(?:\s|,)*'; + WEEKDAYAMPM_START_REGEXP CONSTANT VARCHAR := '(^|[[:digit:][:space:]\.,])'; + WEEKDAYAMPM_END_REGEXP CONSTANT VARCHAR := '([[:digit:][:space:]\.,]|$)(?=[^/-]|$)'; + CORRECTNUM_REGEXP CONSTANT VARCHAR := '(?:([+-]\d{1,4})(?:[[:space:]\.,]|[AP]M|ص|م|$))'; + DATATYPE_REGEXP CONSTANT VARCHAR := '^(TIME)\s*(?:\()?\s*((?:-)?\d+)?\s*(?:\))?$'; + ANNO_DOMINI_REGEXP VARCHAR := '(AD|A\.D\.)'; + ANNO_DOMINI_COMPREGEXP VARCHAR := concat(WEEKDAYAMPM_START_REGEXP, ANNO_DOMINI_REGEXP, WEEKDAYAMPM_END_REGEXP); + HHMMSSFS_PART_REGEXP CONSTANT VARCHAR := + concat(TIMEUNIT_REGEXP, AMPM_REGEXP, '|', + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, TIMEUNIT_REGEXP, '\:', TIME_MASKSEP_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, TIMEUNIT_REGEXP, '(?!\d)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?|', + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, TIMEUNIT_REGEXP, '\:', TIME_MASKSEP_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, TIMEUNIT_REGEXP, '\:', TIME_MASKSEP_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, TIMEUNIT_REGEXP, '(?!\d)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?|', + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, TIMEUNIT_REGEXP, '\:', TIME_MASKSEP_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, TIMEUNIT_REGEXP, '\:', TIME_MASKSEP_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\s*\d{1,2}\.\d+(?!\d)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?|', + AMPM_REGEXP, '?'); + HHMMSSFS_PART_FI_REGEXP CONSTANT VARCHAR := + concat(TIMEUNIT_REGEXP, AMPM_REGEXP, '|', + AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, TIMEUNIT_REGEXP, '[\:\.]', TIME_MASKSEP_FI_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, TIMEUNIT_REGEXP, '(?!\d)', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?\.?|', + AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, TIMEUNIT_REGEXP, '[\:\.]', TIME_MASKSEP_FI_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, TIMEUNIT_REGEXP, '[\:\.]', TIME_MASKSEP_FI_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, TIMEUNIT_REGEXP, '(?!\d)', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?|', + AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, TIMEUNIT_REGEXP, '[\:\.]', TIME_MASKSEP_FI_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, TIMEUNIT_REGEXP, '[\:\.]', TIME_MASKSEP_FI_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, '\s*\d{1,2}\.\d+(?!\d)\.?', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?|', + AMPM_REGEXP, '?'); + v_defmask1_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, + '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, + CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + TIME_MASKSEP_REGEXP, '(?:[\.|,]+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)', TIME_MASKSEP_REGEXP, '$'); + v_defmask1_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, CORRECTNUM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, + '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_FI_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:', MASKSEPTWO_FI_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, + CORRECTNUM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:[,]+', AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, CORRECTNUM_REGEXP, '?))', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + TIME_MASKSEP_FI_REGEXP, '(?:[\.|,]+', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask2_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, + '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, + AMPM_REGEXP, TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + TIME_MASKSEP_REGEXP, '(?:(?:[\.|,]+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?)|', + CORRECTNUM_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, '$'); + v_defmask2_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, CORRECTNUM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, + '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + CORRECTNUM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_FI_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_FI_REGEXP, CORRECTNUM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, + AMPM_REGEXP, TIME_MASKSEP_FI_REGEXP, CORRECTNUM_REGEXP, '?))', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + TIME_MASKSEP_FI_REGEXP, '(?:(?:[\.|,]+', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, TIME_MASKSEP_FI_REGEXP, CORRECTNUM_REGEXP, '?)|', + CORRECTNUM_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask3_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, ')|', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + TIME_MASKSEP_REGEXP, '(', TIME_MASKSEP_REGEXP, AMPM_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask3_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + TIME_MASKSEP_FI_REGEXP, '[\./]?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)', + FULLYEAR_REGEXP, + TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask4_0_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, '\s*(', AMPM_REGEXP, ')', + TIME_MASKSEP_REGEXP, '$'); + v_defmask4_1_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:\s|,)+', + DAYMM_REGEXP, '\s*(', AMPM_REGEXP, ')', + TIME_MASKSEP_REGEXP, '$'); + v_defmask4_2_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '\s*[\.]+', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, '\s*(', AMPM_REGEXP, ')', + TIME_MASKSEP_REGEXP, '$'); + v_defmask5_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask5_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_FI_REGEXP, + FULLYEAR_REGEXP, + TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask6_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '((?:(?:\s|\.|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_REGEXP, '))?', TIME_MASKSEP_REGEXP, '$'); + v_defmask6_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:\s*[\.])?', + '((?:(?:\s|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_FI_REGEXP, '))?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask7_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '((?:(?:\s|\.|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_REGEXP, '))?', TIME_MASKSEP_REGEXP, '$'); + v_defmask7_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_FI_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '((?:(?:\s|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_FI_REGEXP, '))?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask8_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:[\.|,]+', AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:[\.|,]+', AMPM_REGEXP, ')?', + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask8_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_FI_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:[,]+', AMPM_REGEXP, '))', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)|', + '(?:[,]+', AMPM_REGEXP, '))', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:(?:[\,]+|\s*/\s*)', AMPM_REGEXP, ')?', + TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask9_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', + HHMMSSFS_PART_REGEXP, + ')', TIME_MASKSEP_REGEXP, '$'); + v_defmask9_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, '(', + HHMMSSFS_PART_FI_REGEXP, + ')', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask10_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)?', TIME_MASKSEP_REGEXP, + '($comp_month$)', + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask10_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)?', TIME_MASKSEP_REGEXP, + '($comp_month$)', + TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask11_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask11_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '((?:(?:\s|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_FI_REGEXP, '))?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask12_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask12_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask13_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$'); + v_defmask13_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask14_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + '($comp_month$)' + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)', TIME_MASKSEP_REGEXP, + COMPYEAR_REGEXP, + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask14_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + '($comp_month$)' + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_FI_REGEXP, AMPM_REGEXP, '?)', TIME_MASKSEP_FI_REGEXP, + COMPYEAR_REGEXP, + '((?:(?:\s|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_FI_REGEXP, '))?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask15_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + COMPYEAR_REGEXP, + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask15_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + COMPYEAR_REGEXP, + '((?:(?:\s|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_FI_REGEXP, '))?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask16_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)', TIME_MASKSEP_REGEXP, + COMPYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask16_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + DAYMM_REGEXP, + '(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)', TIME_MASKSEP_REGEXP, + COMPYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask17_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask17_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '((?:(?:\s|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_FI_REGEXP, '))?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask18_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, '$'); + v_defmask18_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, '(?:', AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))?)|', + '(?:(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '(?=(?:[[:space:]\.,])+))))', TIME_MASKSEP_REGEXP, + '($comp_month$)', + TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, '$'); + v_defmask19_regexp VARCHAR := concat('^', TIME_MASKSEP_REGEXP, '(', HHMMSSFS_PART_REGEXP, ')?', TIME_MASKSEP_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '((?:(?:\s|\.|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_REGEXP, '))?', TIME_MASKSEP_REGEXP, '$'); + v_defmask19_fi_regexp VARCHAR := concat('^', TIME_MASKSEP_FI_REGEXP, '(', HHMMSSFS_PART_FI_REGEXP, ')?', TIME_MASKSEP_FI_REGEXP, + '($comp_month$)', + '(?:', MASKSEPTHREE_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)?', TIME_MASKSEP_REGEXP, + FULLYEAR_REGEXP, + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, + DAYMM_REGEXP, + '((?:(?:\s|,)+|', AMPM_REGEXP, ')(?:', HHMMSSFS_PART_FI_REGEXP, '))?', TIME_MASKSEP_FI_REGEXP, '$'); + CONVERSION_LANG CONSTANT VARCHAR := ''; + DATE_FORMAT CONSTANT VARCHAR := ''; +BEGIN + v_datatype := trim(p_datatype); + v_srctimestring := upper(trim(p_srctimestring)); + v_culture := coalesce(nullif(upper(trim(p_culture)), ''), 'EN-US'); + + 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 (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; + + v_dayparts := ARRAY(SELECT upper(array_to_string(regexp_matches(v_srctimestring, '[AP]M|ص|م', 'gi'), ''))); + + IF (array_length(v_dayparts, 1) > 1) THEN + RAISE invalid_datetime_format; + END IF; + + BEGIN + v_lang_metadata_json := sys.babelfish_get_lang_metadata_json(coalesce(nullif(CONVERSION_LANG, ''), p_culture)); + EXCEPTION + WHEN OTHERS THEN + RAISE invalid_parameter_value; + END; + + v_compday_regexp := array_to_string(array_cat(array_cat(ARRAY(SELECT jsonb_array_elements_text(v_lang_metadata_json -> 'days_names')), + ARRAY(SELECT jsonb_array_elements_text(v_lang_metadata_json -> 'days_shortnames'))), + ARRAY(SELECT jsonb_array_elements_text(v_lang_metadata_json -> 'days_extrashortnames'))), '|'); + + v_weekdaynames := ARRAY(SELECT array_to_string(regexp_matches(v_srctimestring, v_compday_regexp, 'gi'), '')); + + IF (array_length(v_weekdaynames, 1) > 1) THEN + RAISE invalid_datetime_format; + END IF; + + IF (v_weekdaynames[1] IS NOT NULL AND + v_srctimestring ~* concat(WEEKDAYAMPM_START_REGEXP, '(', v_compday_regexp, ')', WEEKDAYAMPM_END_REGEXP)) + THEN + v_srctimestring := replace(v_srctimestring, v_weekdaynames[1], ' '); + END IF; + + IF (v_srctimestring ~* ANNO_DOMINI_COMPREGEXP) + THEN + IF (v_culture !~ 'EN[-_]US|DA[-_]DK|SV[-_]SE|EN[-_]GB|HI[-_]IS') THEN + RAISE invalid_datetime_format; + END IF; + + v_srctimestring := regexp_replace(v_srctimestring, + ANNO_DOMINI_COMPREGEXP, + regexp_replace(array_to_string(regexp_matches(v_srctimestring, ANNO_DOMINI_COMPREGEXP, 'gi'), ''), + ANNO_DOMINI_REGEXP, ' ', 'gi'), + 'gi'); + END IF; + + v_date_format := coalesce(nullif(upper(trim(DATE_FORMAT)), ''), v_lang_metadata_json ->> 'date_format'); + + v_compmonth_regexp := + array_to_string(array_cat(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'))), + array_cat(ARRAY(SELECT jsonb_array_elements_text(v_lang_metadata_json -> 'months_extrashortnames')), + ARRAY(SELECT jsonb_array_elements_text(v_lang_metadata_json -> 'months_extranames'))) + ), '|'); + + IF ((v_srctimestring ~* v_defmask1_regexp AND v_culture <> 'FI') OR + (v_srctimestring ~* v_defmask1_fi_regexp AND v_culture = 'FI')) + THEN + IF (v_srctimestring ~ concat(CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d+\s*(?:\.)+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, + CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, + AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}|', + '\d+\s*(?:\.)+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, + CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$') AND + v_culture ~ 'DE[-_]DE|NN[-_]NO|CS[-_]CZ|PL[-_]PL|RO[-_]RO|SK[-_]SK|SL[-_]SI|BG[-_]BG|RU[-_]RU|TR[-_]TR|ET[-_]EE|LV[-_]LV') + THEN + RAISE invalid_datetime_format; + END IF; + + v_regmatch_groups := regexp_matches(v_srctimestring, CASE v_culture + WHEN 'FI' THEN v_defmask1_fi_regexp + ELSE v_defmask1_regexp + END, 'gi'); + v_timestring := v_regmatch_groups[2]; + v_correctnum := coalesce(v_regmatch_groups[1], v_regmatch_groups[3], + v_regmatch_groups[5], v_regmatch_groups[6]); + + IF (v_date_format = 'DMY' OR + v_culture IN ('SV-SE', 'SV_SE', 'LV-LV', 'LV_LV')) + THEN + v_day := v_regmatch_groups[4]; + v_month := v_regmatch_groups[7]; + ELSE + v_day := v_regmatch_groups[7]; + v_month := v_regmatch_groups[4]; + END IF; + + IF (v_culture IN ('AR', 'AR-SA', 'AR_SA')) + THEN + IF (v_day::SMALLINT > 30 OR + v_month::SMALLINT > 12) THEN + RAISE invalid_datetime_format; + END IF; + + v_raw_year := to_char(sys.babelfish_conv_greg_to_hijri(current_date + 1), 'YYYY'); + v_hijridate := sys.babelfish_conv_hijri_to_greg(v_day, v_month, v_raw_year) - 1; + + v_day := to_char(v_hijridate, 'DD'); + v_month := to_char(v_hijridate, 'MM'); + v_year := to_char(v_hijridate, 'YYYY')::SMALLINT; + ELSE + v_year := to_char(current_date, 'YYYY')::SMALLINT; + END IF; + + ELSIF ((v_srctimestring ~* v_defmask6_regexp AND v_culture <> 'FI') OR + (v_srctimestring ~* v_defmask6_fi_regexp AND v_culture = 'FI')) + THEN + IF (v_culture IN ('AR', 'AR-SA', 'AR_SA') OR + (v_srctimestring ~ concat('\s*\d{1,2}\.\s*(?:\.|\d+(?!\d)\s*\.)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{3,4}', + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '))', TIME_MASKSEP_REGEXP, '\d{1,2}|', + '\d{3,4}', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}', MASKSEPTWO_REGEXP, + TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}\s*(?:\.)+|', + '\d+\s*(?:\.)+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$') AND + v_culture ~ 'DE[-_]DE|NN[-_]NO|CS[-_]CZ|PL[-_]PL|RO[-_]RO|SK[-_]SK|SL[-_]SI|BG[-_]BG|RU[-_]RU|TR[-_]TR|ET[-_]EE|LV[-_]LV')) + THEN + RAISE invalid_datetime_format; + END IF; + + v_regmatch_groups := regexp_matches(v_srctimestring, CASE v_culture + WHEN 'FI' THEN v_defmask6_fi_regexp + ELSE v_defmask6_regexp + END, 'gi'); + v_timestring := concat(v_regmatch_groups[1], v_regmatch_groups[5]); + v_day := v_regmatch_groups[4]; + v_month := v_regmatch_groups[3]; + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN v_regmatch_groups[2]::SMALLINT - 543 + ELSE v_regmatch_groups[2]::SMALLINT + END; + + ELSIF ((v_srctimestring ~* v_defmask2_regexp AND v_culture <> 'FI') OR + (v_srctimestring ~* v_defmask2_fi_regexp AND v_culture = 'FI')) + THEN + IF (v_culture IN ('AR', 'AR-SA', 'AR_SA') OR + (v_srctimestring ~ concat('\s*\d{1,2}\.\s*(?:\.|\d+(?!\d)\s*\.)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{3,4}', + '(?:(?:', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?)|', + '(?:', TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?', TIME_MASKSEP_REGEXP, + AMPM_REGEXP, TIME_MASKSEP_REGEXP, CORRECTNUM_REGEXP, '?))', TIME_MASKSEP_REGEXP, '\d{1,2}|', + '\d+\s*(?:\.)+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$') AND + v_culture ~ 'DE[-_]DE|NN[-_]NO|CS[-_]CZ|PL[-_]PL|RO[-_]RO|SK[-_]SK|SL[-_]SI|BG[-_]BG|RU[-_]RU|TR[-_]TR|ET[-_]EE|LV[-_]LV')) + THEN + RAISE invalid_datetime_format; + END IF; + + v_regmatch_groups := regexp_matches(v_srctimestring, CASE v_culture + WHEN 'FI' THEN v_defmask2_fi_regexp + ELSE v_defmask2_regexp + END, 'gi'); + v_timestring := v_regmatch_groups[2]; + v_correctnum := coalesce(v_regmatch_groups[1], v_regmatch_groups[3], v_regmatch_groups[5], + v_regmatch_groups[6], v_regmatch_groups[8], v_regmatch_groups[9]); + v_day := '01'; + v_month := v_regmatch_groups[7]; + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN v_regmatch_groups[4]::SMALLINT - 543 + ELSE v_regmatch_groups[4]::SMALLINT + END; + + ELSIF (v_srctimestring ~* v_defmask4_1_regexp OR + (v_srctimestring ~* v_defmask4_2_regexp AND v_culture !~ 'DE[-_]DE|NN[-_]NO|CS[-_]CZ|PL[-_]PL|RO[-_]RO|SK[-_]SK|SL[-_]SI|BG[-_]BG|RU[-_]RU|TR[-_]TR|ET[-_]EE|LV[-_]LV') OR + (v_srctimestring ~* v_defmask9_regexp AND v_culture <> 'FI') OR + (v_srctimestring ~* v_defmask9_fi_regexp AND v_culture = 'FI')) + THEN + IF (v_srctimestring ~ concat('\d+\s*\.?(?:,+|,*', AMPM_REGEXP, ')', TIME_MASKSEP_FI_REGEXP, '\.+', TIME_MASKSEP_REGEXP, '$|', + '\d+\s*\.', TIME_MASKSEP_FI_REGEXP, '\.', TIME_MASKSEP_FI_REGEXP, '$') AND + v_culture = 'FI') + THEN + RAISE invalid_datetime_format; + END IF; + + IF (v_srctimestring ~* v_defmask4_0_regexp) THEN + v_timestring := (regexp_matches(v_srctimestring, v_defmask4_0_regexp, 'gi'))[1]; + ELSE + v_timestring := v_srctimestring; + END IF; + + v_res_date := current_date; + v_day := to_char(v_res_date, 'DD'); + v_month := to_char(v_res_date, 'MM'); + v_year := to_char(v_res_date, 'YYYY')::SMALLINT; + + ELSIF ((v_srctimestring ~* v_defmask3_regexp AND v_culture <> 'FI') OR + (v_srctimestring ~* v_defmask3_fi_regexp AND v_culture = 'FI')) + THEN + IF (v_culture IN ('AR', 'AR-SA', 'AR_SA') OR + (v_srctimestring ~ concat('\s*\d{1,2}\.\s*(?:\.|\d+(?!\d)\s*\.)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', + TIME_MASKSEP_REGEXP, '\d{1,2}', MASKSEPTWO_REGEXP, '|', + '\d+\s*(?:\.)+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$') AND + v_culture ~ 'DE[-_]DE|NN[-_]NO|CS[-_]CZ|PL[-_]PL|RO[-_]RO|SK[-_]SK|SL[-_]SI|BG[-_]BG|RU[-_]RU|TR[-_]TR|ET[-_]EE|LV[-_]LV')) + THEN + RAISE invalid_datetime_format; + END IF; + + v_regmatch_groups := regexp_matches(v_srctimestring, CASE v_culture + WHEN 'FI' THEN v_defmask3_fi_regexp + ELSE v_defmask3_regexp + END, 'gi'); + v_timestring := v_regmatch_groups[1]; + v_day := '01'; + v_month := v_regmatch_groups[2]; + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN v_regmatch_groups[3]::SMALLINT - 543 + ELSE v_regmatch_groups[3]::SMALLINT + END; + + ELSIF ((v_srctimestring ~* v_defmask5_regexp AND v_culture <> 'FI') OR + (v_srctimestring ~* v_defmask5_fi_regexp AND v_culture = 'FI')) + THEN + IF (v_culture IN ('AR', 'AR-SA', 'AR_SA') OR + (v_srctimestring ~ concat('\s*\d{1,2}\.\s*(?:\.|\d+(?!\d)\s*\.)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}', MASKSEPTWO_REGEXP, + TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}', MASKSEPTWO_REGEXP, + TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{3,4}', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$|', + '\d{1,2}', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{3,4}\s*(?:\.)+|', + '\d+\s*(?:\.)+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$') AND + v_culture ~ 'DE[-_]DE|NN[-_]NO|CS[-_]CZ|PL[-_]PL|RO[-_]RO|SK[-_]SK|SL[-_]SI|BG[-_]BG|RU[-_]RU|TR[-_]TR|ET[-_]EE|LV[-_]LV')) + THEN + RAISE invalid_datetime_format; + END IF; + + v_regmatch_groups := regexp_matches(v_srctimestring, v_defmask5_regexp, 'gi'); + v_timestring := concat(v_regmatch_groups[1], v_regmatch_groups[5]); + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN v_regmatch_groups[4]::SMALLINT - 543 + ELSE v_regmatch_groups[4]::SMALLINT + END; + + IF (v_date_format = 'DMY' OR + v_culture IN ('LV-LV', 'LV_LV')) + THEN + v_day := v_regmatch_groups[2]; + v_month := v_regmatch_groups[3]; + ELSE + v_day := v_regmatch_groups[3]; + v_month := v_regmatch_groups[2]; + END IF; + + ELSIF ((v_srctimestring ~* v_defmask7_regexp AND v_culture <> 'FI') OR + (v_srctimestring ~* v_defmask7_fi_regexp AND v_culture = 'FI')) + THEN + IF (v_culture IN ('AR', 'AR-SA', 'AR_SA') OR + (v_srctimestring ~ concat('\s*\d{1,2}\.\s*(?:\.|\d+(?!\d)\s*\.)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}', + MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{3,4}|', + '\d{3,4}', MASKSEPTWO_REGEXP, '?', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}\s*(?:\.)+|', + '\d+\s*(?:\.)+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$') AND + v_culture ~ 'DE[-_]DE|NN[-_]NO|CS[-_]CZ|PL[-_]PL|RO[-_]RO|SK[-_]SK|SL[-_]SI|BG[-_]BG|RU[-_]RU|TR[-_]TR|ET[-_]EE|LV[-_]LV')) + THEN + RAISE invalid_datetime_format; + END IF; + + v_regmatch_groups := regexp_matches(v_srctimestring, CASE v_culture + WHEN 'FI' THEN v_defmask7_fi_regexp + ELSE v_defmask7_regexp + END, 'gi'); + v_timestring := concat(v_regmatch_groups[1], v_regmatch_groups[5]); + v_day := v_regmatch_groups[4]; + v_month := v_regmatch_groups[2]; + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN v_regmatch_groups[3]::SMALLINT - 543 + ELSE v_regmatch_groups[3]::SMALLINT + END; + + ELSIF ((v_srctimestring ~* v_defmask8_regexp AND v_culture <> 'FI') OR + (v_srctimestring ~* v_defmask8_fi_regexp AND v_culture = 'FI')) + THEN + IF (v_srctimestring ~ concat('\s*\d{1,2}\.\s*(?:\.|\d+(?!\d)\s*\.)', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}', + MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}', MASKSEPTWO_REGEXP, + TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}|', + '\d{1,2}', MASKSEPTWO_REGEXP, TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}', MASKSEPTWO_REGEXP, + TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '\d{1,2}\s*(?:\.)+|', + '\d+\s*(?:\.)+', TIME_MASKSEP_REGEXP, AMPM_REGEXP, '?', TIME_MASKSEP_REGEXP, '$') AND + v_culture ~ 'FI|DE[-_]DE|NN[-_]NO|CS[-_]CZ|PL[-_]PL|RO[-_]RO|SK[-_]SK|SL[-_]SI|BG[-_]BG|RU[-_]RU|TR[-_]TR|ET[-_]EE|LV[-_]LV') + THEN + RAISE invalid_datetime_format; + END IF; + + v_regmatch_groups := regexp_matches(v_srctimestring, CASE v_culture + WHEN 'FI' THEN v_defmask8_fi_regexp + ELSE v_defmask8_regexp + END, 'gi'); + v_timestring := concat(v_regmatch_groups[1], v_regmatch_groups[5]); + + IF (v_date_format = 'DMY' OR + v_culture IN ('LV-LV', 'LV_LV')) + THEN + v_day := v_regmatch_groups[2]; + v_month := v_regmatch_groups[3]; + v_raw_year := v_regmatch_groups[4]; + ELSIF (v_date_format = 'YMD') + THEN + v_day := v_regmatch_groups[4]; + v_month := v_regmatch_groups[3]; + v_raw_year := v_regmatch_groups[2]; + ELSE + v_day := v_regmatch_groups[3]; + v_month := v_regmatch_groups[2]; + v_raw_year := v_regmatch_groups[4]; + END IF; + + IF (v_culture IN ('AR', 'AR-SA', 'AR_SA')) + THEN + IF (v_day::SMALLINT > 30 OR + v_month::SMALLINT > 12) THEN + RAISE invalid_datetime_format; + END IF; + + v_raw_year := sys.babelfish_get_full_year(v_raw_year, '14'); + v_hijridate := sys.babelfish_conv_hijri_to_greg(v_day, v_month, v_raw_year) - 1; + + v_day := to_char(v_hijridate, 'DD'); + v_month := to_char(v_hijridate, 'MM'); + v_year := to_char(v_hijridate, 'YYYY')::SMALLINT; + + ELSIF (v_culture IN ('TH-TH', 'TH_TH')) THEN + v_year := sys.babelfish_get_full_year(v_raw_year)::SMALLINT - 43; + ELSE + v_year := sys.babelfish_get_full_year(v_raw_year, '', 29)::SMALLINT; + END IF; + ELSE + v_found := FALSE; + END IF; + + WHILE (NOT v_found AND v_resmask_cnt < 20) + LOOP + v_resmask := replace(CASE v_resmask_cnt + WHEN 10 THEN v_defmask10_regexp + WHEN 11 THEN v_defmask11_regexp + WHEN 12 THEN v_defmask12_regexp + WHEN 13 THEN v_defmask13_regexp + WHEN 14 THEN v_defmask14_regexp + WHEN 15 THEN v_defmask15_regexp + WHEN 16 THEN v_defmask16_regexp + WHEN 17 THEN v_defmask17_regexp + WHEN 18 THEN v_defmask18_regexp + WHEN 19 THEN v_defmask19_regexp + END, + '$comp_month$', v_compmonth_regexp); + + v_resmask_fi := replace(CASE v_resmask_cnt + WHEN 10 THEN v_defmask10_fi_regexp + WHEN 11 THEN v_defmask11_fi_regexp + WHEN 12 THEN v_defmask12_fi_regexp + WHEN 13 THEN v_defmask13_fi_regexp + WHEN 14 THEN v_defmask14_fi_regexp + WHEN 15 THEN v_defmask15_fi_regexp + WHEN 16 THEN v_defmask16_fi_regexp + WHEN 17 THEN v_defmask17_fi_regexp + WHEN 18 THEN v_defmask18_fi_regexp + WHEN 19 THEN v_defmask19_fi_regexp + END, + '$comp_month$', v_compmonth_regexp); + + IF ((v_srctimestring ~* v_resmask AND v_culture <> 'FI') OR + (v_srctimestring ~* v_resmask_fi AND v_culture = 'FI')) + THEN + v_found := TRUE; + v_regmatch_groups := regexp_matches(v_srctimestring, CASE v_culture + WHEN 'FI' THEN v_resmask_fi + ELSE v_resmask + END, 'gi'); + v_timestring := CASE + WHEN v_resmask_cnt IN (10, 11, 12, 13) THEN concat(v_regmatch_groups[1], v_regmatch_groups[4]) + ELSE concat(v_regmatch_groups[1], v_regmatch_groups[5]) + END; + + IF (v_resmask_cnt = 10) + THEN + IF (v_regmatch_groups[3] = 'MAR' AND + v_culture IN ('IT-IT', 'IT_IT')) + THEN + RAISE invalid_datetime_format; + END IF; + + IF (v_date_format = 'YMD' AND v_culture NOT IN ('SV-SE', 'SV_SE', 'LV-LV', 'LV_LV')) + THEN + v_day := '01'; + v_year := sys.babelfish_get_full_year(v_regmatch_groups[2], '', 29)::SMALLINT; + ELSE + v_day := v_regmatch_groups[2]; + v_year := to_char(current_date, 'YYYY')::SMALLINT; + END IF; + + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[3], v_lang_metadata_json); + v_raw_year := to_char(sys.babelfish_conv_greg_to_hijri(current_date + 1), 'YYYY'); + + ELSIF (v_resmask_cnt = 11) + THEN + IF (v_date_format IN ('YMD', 'MDY') AND v_culture NOT IN ('SV-SE', 'SV_SE')) + THEN + v_day := v_regmatch_groups[3]; + v_year := to_char(current_date, 'YYYY')::SMALLINT; + ELSE + v_day := '01'; + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN sys.babelfish_get_full_year(v_regmatch_groups[3])::SMALLINT - 43 + ELSE sys.babelfish_get_full_year(v_regmatch_groups[3], '', 29)::SMALLINT + END; + END IF; + + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[2], v_lang_metadata_json); + v_raw_year := sys.babelfish_get_full_year(substring(v_year::TEXT, 3, 2), '14'); + + ELSIF (v_resmask_cnt = 12) + THEN + v_day := '01'; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[3], v_lang_metadata_json); + v_raw_year := v_regmatch_groups[2]; + + ELSIF (v_resmask_cnt = 13) + THEN + v_day := '01'; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[2], v_lang_metadata_json); + v_raw_year := v_regmatch_groups[3]; + + ELSIF (v_resmask_cnt IN (14, 15, 16)) + THEN + IF (v_resmask_cnt = 14) + THEN + v_left_part := v_regmatch_groups[4]; + v_right_part := v_regmatch_groups[3]; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[2], v_lang_metadata_json); + ELSIF (v_resmask_cnt = 15) + THEN + v_left_part := v_regmatch_groups[4]; + v_right_part := v_regmatch_groups[2]; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[3], v_lang_metadata_json); + ELSE + v_left_part := v_regmatch_groups[3]; + v_right_part := v_regmatch_groups[2]; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[4], v_lang_metadata_json); + END IF; + + IF (char_length(v_left_part) <= 2) + THEN + IF (v_date_format = 'YMD' AND v_culture NOT IN ('LV-LV', 'LV_LV')) + THEN + v_day := v_left_part; + v_raw_year := sys.babelfish_get_full_year(v_right_part, '14'); + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN sys.babelfish_get_full_year(v_right_part)::SMALLINT - 43 + ELSE sys.babelfish_get_full_year(v_right_part, '', 29)::SMALLINT + END; + BEGIN + v_res_date := make_date(v_year, v_month::SMALLINT, v_day::SMALLINT); + EXCEPTION + WHEN OTHERS THEN + v_day := v_right_part; + v_raw_year := sys.babelfish_get_full_year(v_left_part, '14'); + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN sys.babelfish_get_full_year(v_left_part)::SMALLINT - 43 + ELSE sys.babelfish_get_full_year(v_left_part, '', 29)::SMALLINT + END; + END; + END IF; + + IF (v_date_format IN ('MDY', 'DMY') OR v_culture IN ('LV-LV', 'LV_LV')) + THEN + v_day := v_right_part; + v_raw_year := sys.babelfish_get_full_year(v_left_part, '14'); + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN sys.babelfish_get_full_year(v_left_part)::SMALLINT - 43 + ELSE sys.babelfish_get_full_year(v_left_part, '', 29)::SMALLINT + END; + BEGIN + v_res_date := make_date(v_year, v_month::SMALLINT, v_day::SMALLINT); + EXCEPTION + WHEN OTHERS THEN + v_day := v_left_part; + v_raw_year := sys.babelfish_get_full_year(v_right_part, '14'); + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN sys.babelfish_get_full_year(v_right_part)::SMALLINT - 43 + ELSE sys.babelfish_get_full_year(v_right_part, '', 29)::SMALLINT + END; + END; + END IF; + ELSE + v_day := v_right_part; + v_raw_year := v_left_part; + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN v_left_part::SMALLINT - 543 + ELSE v_left_part::SMALLINT + END; + END IF; + + ELSIF (v_resmask_cnt = 17) + THEN + v_day := v_regmatch_groups[4]; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[3], v_lang_metadata_json); + v_raw_year := v_regmatch_groups[2]; + + ELSIF (v_resmask_cnt = 18) + THEN + v_day := v_regmatch_groups[3]; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[4], v_lang_metadata_json); + v_raw_year := v_regmatch_groups[2]; + + ELSIF (v_resmask_cnt = 19) + THEN + v_day := v_regmatch_groups[4]; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[2], v_lang_metadata_json); + v_raw_year := v_regmatch_groups[3]; + END IF; + + IF (v_resmask_cnt NOT IN (10, 11, 14, 15, 16)) + THEN + v_year := CASE + WHEN v_culture IN ('TH-TH', 'TH_TH') THEN v_raw_year::SMALLINT - 543 + ELSE v_raw_year::SMALLINT + END; + END IF; + + IF (v_culture IN ('AR', 'AR-SA', 'AR_SA')) + THEN + IF (v_day::SMALLINT > 30 OR + (v_resmask_cnt NOT IN (10, 11, 14, 15, 16) AND v_year NOT BETWEEN 1318 AND 1501) OR + (v_resmask_cnt IN (14, 15, 16) AND v_raw_year::SMALLINT NOT BETWEEN 1318 AND 1501)) + THEN + RAISE invalid_datetime_format; + END IF; + + v_hijridate := sys.babelfish_conv_hijri_to_greg(v_day, v_month, v_raw_year) - 1; + + v_day := to_char(v_hijridate, 'DD'); + v_month := to_char(v_hijridate, 'MM'); + v_year := to_char(v_hijridate, 'YYYY')::SMALLINT; + END IF; + END IF; + + v_resmask_cnt := v_resmask_cnt + 1; + END LOOP; + + IF (NOT v_found) THEN + RAISE invalid_datetime_format; + END IF; + + v_res_date := make_date(v_year, v_month::SMALLINT, v_day::SMALLINT); + + IF (v_weekdaynames[1] IS NOT NULL) THEN + v_weekdaynum := sys.babelfish_get_weekdaynum_by_name(v_weekdaynames[1], v_lang_metadata_json); + + IF (date_part('dow', v_res_date)::SMALLINT <> v_weekdaynum) THEN + RAISE invalid_datetime_format; + END IF; + END IF; + + IF (char_length(v_timestring) > 0 AND v_timestring NOT IN ('AM', 'ص', 'PM', 'م')) + THEN + IF (v_culture = 'FI') THEN + v_timestring := translate(v_timestring, '.,', ': '); + + IF (char_length(split_part(v_timestring, ':', 4)) > 0) THEN + v_timestring := regexp_replace(v_timestring, ':(?=\s*\d+\s*:?\s*(?:[AP]M|ص|م)?\s*$)', '.'); + END IF; + END IF; + + v_timestring := replace(regexp_replace(v_timestring, '\.?[AP]M|ص|م|\s|\,|\.\D|[\.|:]$', '', 'gi'), ':.', ':'); + + BEGIN + v_hours := coalesce(split_part(v_timestring, ':', 1)::SMALLINT, 0); + + IF ((v_dayparts[1] IN ('AM', 'ص') AND v_hours NOT BETWEEN 0 AND 12) OR + (v_dayparts[1] IN ('PM', 'م') AND v_hours NOT BETWEEN 1 AND 23)) + THEN + RAISE invalid_datetime_format; + ELSIF (v_dayparts[1] = 'PM' AND v_hours < 12) THEN + v_hours := v_hours + 12; + ELSIF (v_dayparts[1] = 'AM' AND v_hours = 12) THEN + v_hours := v_hours - 12; + END IF; + + v_minutes := coalesce(nullif(split_part(v_timestring, ':', 2), '')::SMALLINT, 0); + v_seconds := coalesce(nullif(split_part(v_timestring, ':', 3), ''), '0'); + + IF (v_seconds ~ '\.') THEN + v_fseconds := split_part(v_seconds, '.', 2); + v_seconds := split_part(v_seconds, '.', 1); + END IF; + EXCEPTION + WHEN OTHERS THEN + RAISE invalid_datetime_format; + END; + ELSIF (v_dayparts[1] IN ('PM', 'م')) + THEN + v_hours := 12; + END IF; + + v_fseconds := sys.babelfish_get_microsecs_from_fractsecs(rpad(v_fseconds, 9, '0'), v_scale); + v_seconds := concat_ws('.', v_seconds, v_fseconds); + + v_res_time := make_time(v_hours, v_minutes, v_seconds::NUMERIC); + + RETURN v_res_time; +EXCEPTION + WHEN invalid_datetime_format OR datetime_field_overflow THEN + RAISE USING MESSAGE := format('Error converting string value ''%s'' into data type %s using culture ''%s''.', + p_srctimestring, v_res_datatype, p_culture), + 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 datatype_mismatch THEN + RAISE USING MESSAGE := 'Source data type should be ''TIME'' or ''TIME(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 := 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 := 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_parameter_value THEN + RAISE USING MESSAGE := CASE char_length(coalesce(CONVERSION_LANG, '')) + WHEN 0 THEN format('The culture parameter ''%s'' provided in the function call is not supported.', + p_culture) + ELSE format('Invalid CONVERSION_LANG constant value - ''%s''. Allowed values are: ''English'', ''Deutsch'', etc.', + CONVERSION_LANG) + END, + DETAIL := 'Passed incorrect value for "p_culture" parameter or compiled incorrect CONVERSION_LANG constant value in function''s body.', + HINT := 'Check "p_culture" input parameter value, correct it if needed, and try again. Also check CONVERSION_LANG constant value.'; + + 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 := format('Error while trying to convert "%s" value to SMALLINT data type.', + v_err_message), + DETAIL := 'Supplied value contains illegal characters.', + HINT := 'Correct supplied value, remove all illegal characters.'; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + +/* *********************************************** +EXTENSION PACK function ROUND3(arg1, arg2, arg3) +schema sys +**************************************************/ +create or replace function sys.babelfish_ROUND3(x in numeric, y in int, z in int)returns numeric +AS +$body$ +BEGIN +/*************************************************************** +EXTENSION PACK function ROUND3(arg1, arg2, arg3) +***************************************************************/ + if z = 0 or z is null then + return round(x,y); + else + return trunc(x,y); + end if; +END; +$body$ +language plpgsql; + +CREATE OR REPLACE FUNCTION sys.babelfish_round_fractseconds(IN p_fractseconds NUMERIC) +RETURNS INTEGER +AS +$BODY$ +DECLARE + v_modpart INTEGER; + v_decpart INTEGER; + v_fractseconds INTEGER; +BEGIN + v_fractseconds := floor(p_fractseconds)::INTEGER; + v_modpart := v_fractseconds % 10; + v_decpart := v_fractseconds - v_modpart; + + RETURN CASE + WHEN (v_modpart BETWEEN 0 AND 1) THEN v_decpart + WHEN (v_modpart BETWEEN 2 AND 4) THEN v_decpart + 3 + WHEN (v_modpart BETWEEN 5 AND 8) THEN v_decpart + 7 + ELSE v_decpart + 10 -- 9 + END; +END; +$BODY$ +LANGUAGE plpgsql +IMMUTABLE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_round_fractseconds(IN p_fractseconds TEXT) +RETURNS INTEGER +AS +$BODY$ +BEGIN + RETURN sys.babelfish_round_fractseconds(p_fractseconds::NUMERIC); +EXCEPTION + WHEN invalid_text_representation THEN + RAISE USING MESSAGE := format('Error while trying to convert "%s" value to NUMERIC data type.', trim(p_fractseconds)), + DETAIL := 'Passed argument value contains illegal characters.', + HINT := 'Correct passed argument value, remove all illegal characters.'; + + +END; +$BODY$ +LANGUAGE plpgsql +IMMUTABLE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_set_version(pComponentVersion VARCHAR(256),pComponentName VARCHAR(256)) + RETURNS void AS +$BODY$ +DECLARE + rowcount smallint; +BEGIN + UPDATE sys.versions SET componentversion = pComponentVersion + WHERE extpackcomponentname = pComponentName; + GET DIAGNOSTICS rowcount = ROW_COUNT; + + IF rowcount < 1 THEN + INSERT INTO sys.versions(extpackcomponentname,componentversion) + VALUES (pComponentName,pComponentVersion); + END IF; +END; +$BODY$ +LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_add_job ( + par_job_name varchar, + par_enabled smallint = 1, + par_description varchar = NULL::character varying, + par_start_step_id integer = 1, + par_category_name varchar = NULL::character varying, + par_category_id integer = NULL::integer, + par_owner_login_name varchar = NULL::character varying, + par_notify_level_eventlog integer = 2, + par_notify_level_email integer = 0, + par_notify_level_netsend integer = 0, + par_notify_level_page integer = 0, + par_notify_email_operator_name varchar = NULL::character varying, + par_notify_netsend_operator_name varchar = NULL::character varying, + par_notify_page_operator_name varchar = NULL::character varying, + par_delete_level integer = 0, + inout par_job_id integer = NULL::integer, + par_originating_server varchar = NULL::character varying, + out returncode integer +) +RETURNS record AS +$body$ +DECLARE + var_retval INT DEFAULT 0; + var_notify_email_operator_id INT DEFAULT 0; + var_notify_email_operator_name VARCHAR(128); + var_notify_netsend_operator_id INT DEFAULT 0; + var_notify_page_operator_id INT DEFAULT 0; + var_owner_sid CHAR(85) ; + var_originating_server_id INT DEFAULT 0; +BEGIN + /* Remove any leading/trailing spaces from parameters (except @owner_login_name) */ + SELECT UPPER(LTRIM(RTRIM(par_originating_server))) INTO par_originating_server; + SELECT LTRIM(RTRIM(par_job_name)) INTO par_job_name; + SELECT LTRIM(RTRIM(par_description)) INTO par_description; + SELECT '[Uncategorized (Local)]' INTO par_category_name; + SELECT 0 INTO par_category_id; + SELECT LTRIM(RTRIM(par_notify_email_operator_name)) INTO par_notify_email_operator_name; + SELECT LTRIM(RTRIM(par_notify_netsend_operator_name)) INTO par_notify_netsend_operator_name; + SELECT LTRIM(RTRIM(par_notify_page_operator_name)) INTO par_notify_page_operator_name; + SELECT NULL INTO var_originating_server_id; /* Turn [nullable] empty string parameters into NULLs */ + SELECT NULL INTO par_job_id; + + IF (par_originating_server = '') + THEN + SELECT NULL INTO par_originating_server; + END IF; + + IF (par_description = '') + THEN + SELECT NULL INTO par_description; + END IF; + + IF (par_category_name = '') + THEN + SELECT NULL INTO par_category_name; + END IF; + + IF (par_notify_email_operator_name = '') + THEN + SELECT NULL INTO par_notify_email_operator_name; + END IF; + + IF (par_notify_netsend_operator_name = '') + THEN + SELECT NULL INTO par_notify_netsend_operator_name; + END IF; + + IF (par_notify_page_operator_name = '') + THEN + SELECT NULL INTO par_notify_page_operator_name; + END IF; + + /* Check parameters */ + SELECT t.par_owner_sid + , t.par_notify_level_email + , t.par_notify_level_netsend + , t.par_notify_level_page + , t.par_category_id + , t.par_notify_email_operator_id + , t.par_notify_netsend_operator_id + , t.par_notify_page_operator_id + , t.par_originating_server + , t.returncode + FROM sys.babelfish_sp_verify_job( + par_job_id /* NULL::integer */ + , par_job_name + , par_enabled + , par_start_step_id + , par_category_name + , var_owner_sid /* par_owner_sid */ + , par_notify_level_eventlog + , par_notify_level_email + , par_notify_level_netsend + , par_notify_level_page + , par_notify_email_operator_name + , par_notify_netsend_operator_name + , par_notify_page_operator_name + , par_delete_level + , par_category_id + , var_notify_email_operator_id /* par_notify_email_operator_id */ + , var_notify_netsend_operator_id /* par_notify_netsend_operator_id */ + , var_notify_page_operator_id /* par_notify_page_operator_id */ + , par_originating_server + ) t + INTO var_owner_sid + , par_notify_level_email + , par_notify_level_netsend + , par_notify_level_page + , par_category_id + , var_notify_email_operator_id + , var_notify_netsend_operator_id + , var_notify_page_operator_id + , par_originating_server + , var_retval; + + IF (var_retval <> 0) /* Failure */ + THEN + returncode := 1; + RETURN; + END IF; + + var_notify_email_operator_name := par_notify_email_operator_name; + + /* Default the description (if not supplied) */ + IF (par_description IS NULL) + THEN + SELECT 'No description available.' INTO par_description; + END IF; + + var_originating_server_id := 0; + var_owner_sid := ''; + + INSERT + INTO sys.sysjobs ( + originating_server_id + , name + , enabled + , description + , start_step_id + , category_id + , owner_sid + , notify_level_eventlog + , notify_level_email + , notify_level_netsend + , notify_level_page + , notify_email_operator_id + , notify_email_operator_name + , notify_netsend_operator_id + , notify_page_operator_id + , delete_level + , version_number + ) + VALUES ( + var_originating_server_id + , par_job_name + , par_enabled + , par_description + , par_start_step_id + , par_category_id + , var_owner_sid + , par_notify_level_eventlog + , par_notify_level_email + , par_notify_level_netsend + , par_notify_level_page + , var_notify_email_operator_id + , var_notify_email_operator_name + , var_notify_netsend_operator_id + , var_notify_page_operator_id + , par_delete_level + , 1); + + /* scope_identity() */ + SELECT LASTVAL() INTO par_job_id; + + /* Version number 1 */ + /* SELECT @retval = @@error */ + /* 0 means success */ + returncode := var_retval; + RETURN; + +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_add_jobschedule ( + par_job_id integer = NULL::integer, + par_job_name varchar = NULL::character varying, + par_name varchar = NULL::character varying, + par_enabled smallint = 1, + par_freq_type integer = 1, + par_freq_interval integer = 0, + par_freq_subday_type integer = 0, + par_freq_subday_interval integer = 0, + par_freq_relative_interval integer = 0, + par_freq_recurrence_factor integer = 0, + par_active_start_date integer = 20000101, + par_active_end_date integer = 99991231, + par_active_start_time integer = 0, + par_active_end_time integer = 235959, + inout par_schedule_id integer = NULL::integer, + par_automatic_post smallint = 1, + inout par_schedule_uid char = NULL::bpchar, + out returncode integer +) +AS +$body$ +DECLARE + var_retval INT; + var_owner_login_name VARCHAR(128); +BEGIN + + -- Check that we can uniquely identify the job + SELECT t.par_job_name + , t.par_job_id + , t.returncode + FROM sys.babelfish_sp_verify_job_identifiers ( + '@job_name' + , '@job_id' + , par_job_name + , par_job_id + , 'TEST'::character varying + , NULL::bpchar + ) t + INTO par_job_name + , par_job_id + , var_retval; + + IF (var_retval <> 0) + THEN /* Failure */ + returncode := 1; + RETURN; + END IF; + + /* Add the schedule first */ + SELECT t.par_schedule_uid + , t.par_schedule_id + , t.returncode + FROM sys.babelfish_sp_add_schedule( + par_name + , par_enabled + , par_freq_type + , par_freq_interval + , par_freq_subday_type + , par_freq_subday_interval + , par_freq_relative_interval + , par_freq_recurrence_factor + , par_active_start_date + , par_active_end_date + , par_active_start_time + , par_active_end_time + , var_owner_login_name + , par_schedule_uid + , par_schedule_id + , NULL + ) t + INTO par_schedule_uid + , par_schedule_id + , var_retval; + + IF (var_retval <> 0) THEN /* Failure */ + returncode := 1; + RETURN; + END IF; + + SELECT t.returncode + FROM sys.babelfish_sp_attach_schedule( + par_job_id := par_job_id + , par_job_name := NULL + , par_schedule_id := par_schedule_id + , par_schedule_name := NULL + , par_automatic_post := par_automatic_post + ) t + INTO var_retval; + + IF (var_retval <> 0) THEN /* Failure */ + returncode := 1; + RETURN; + END IF; + + SELECT t.returncode + FROM sys.babelfish_sp_aws_add_jobschedule(par_job_id, par_schedule_id) t + INTO var_retval; + + IF (var_retval <> 0) THEN /* Failure */ + returncode := 1; + RETURN; + END IF; + + /* 0 means success */ + returncode := (var_retval); + RETURN; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_add_jobstep ( + par_job_id integer = NULL::integer, + par_job_name varchar = NULL::character varying, + par_step_id integer = NULL::integer, + par_step_name varchar = NULL::character varying, + par_subsystem varchar = 'TSQL'::bpchar, + par_command text = NULL::text, + par_additional_parameters text = NULL::text, + par_cmdexec_success_code integer = 0, + par_on_success_action smallint = 1, + par_on_success_step_id integer = 0, + par_on_fail_action smallint = 2, + par_on_fail_step_id integer = 0, + par_server varchar = NULL::character varying, + par_database_name varchar = NULL::character varying, + par_database_user_name varchar = NULL::character varying, + par_retry_attempts integer = 0, + par_retry_interval integer = 0, + par_os_run_priority integer = 0, + par_output_file_name varchar = NULL::character varying, + par_flags integer = 0, + par_proxy_id integer = NULL::integer, + par_proxy_name varchar = NULL::character varying, + inout par_step_uid char = NULL::bpchar, + out returncode integer +) +AS +$body$ +DECLARE + var_retval INT; + var_max_step_id INT; + var_step_id INT; +BEGIN + + SELECT t.par_job_name + , t.par_job_id + , t.returncode + FROM sys.babelfish_sp_verify_job_identifiers ( + '@job_name' + , '@job_id' + , par_job_name + , par_job_id + , 'TEST'::character varying + , NULL::bpchar + ) t + INTO par_job_name + , par_job_id + , var_retval; + + IF (var_retval <> 0) THEN + returncode := 1; + RETURN; + END IF; + + -- Default step id (if not supplied) + IF (par_step_id IS NULL) + THEN + SELECT COALESCE(MAX(step_id), 0) + 1 + INTO var_step_id + FROM sys.sysjobsteps + WHERE (job_id = par_job_id); + ELSE + var_step_id := par_step_id; + END IF; + + -- Get current maximum step id + SELECT COALESCE(MAX(step_id), 0) + INTO var_max_step_id + FROM sys.sysjobsteps + WHERE (job_id = par_job_id); + + /* Check parameters */ + SELECT t.returncode + FROM sys.babelfish_sp_verify_jobstep( + par_job_id + , var_step_id --par_step_id + , par_step_name + , par_subsystem + , par_command + , par_server + , par_on_success_action + , par_on_success_step_id + , par_on_fail_action + , par_on_fail_step_id + , par_os_run_priority + , par_flags + , par_output_file_name + , par_proxy_id + ) t + INTO var_retval; + + IF (var_retval <> 0) + THEN /* Failure */ + returncode := 1; + RETURN; + END IF; + + /* Modify database. */ + /* Update the job's version/last-modified information */ + UPDATE sys.sysjobs + SET version_number = version_number + 1 + --, date_modified = GETDATE() + WHERE (job_id = par_job_id); + + /* Adjust step id's (unless the new step is being inserted at the 'end') */ + /* NOTE: We MUST do this before inserting the step. */ + IF (var_step_id <= var_max_step_id) + THEN + UPDATE sys.sysjobsteps + SET step_id = step_id + 1 + WHERE (step_id >= var_step_id) AND (job_id = par_job_id); + + /* Clean up OnSuccess/OnFail references */ + UPDATE sys.sysjobsteps + SET on_success_step_id = on_success_step_id + 1 + WHERE (on_success_step_id >= var_step_id) AND (job_id = par_job_id); + + UPDATE sys.sysjobsteps + SET on_fail_step_id = on_fail_step_id + 1 + WHERE (on_fail_step_id >= var_step_id) AND (job_id = par_job_id); + + UPDATE sys.sysjobsteps + SET on_success_step_id = 0 + , on_success_action = 1 /* Quit With Success */ + WHERE (on_success_step_id = var_step_id) + AND (job_id = par_job_id); + + UPDATE sys.sysjobsteps + SET on_fail_step_id = 0 + , on_fail_action = 2 /* Quit With Failure */ + WHERE (on_fail_step_id = var_step_id) + AND (job_id = par_job_id); + END IF; + + /* uuid without extensions uuid-ossp (cheat) */ + SELECT uuid_in(md5(random()::text || clock_timestamp()::text)::cstring) INTO par_step_uid; + + /* Insert the step */ + INSERT + INTO sys.sysjobsteps ( + job_id + , step_id + , step_name + , subsystem + , command + , flags + , additional_parameters + , cmdexec_success_code + , on_success_action + , on_success_step_id + , on_fail_action + , on_fail_step_id + , server + , database_name + , database_user_name + , retry_attempts + , retry_interval + , os_run_priority + , output_file_name + , last_run_outcome + , last_run_duration + , last_run_retries + , last_run_date + , last_run_time + , proxy_id + , step_uid + ) + VALUES ( + par_job_id + , var_step_id + , par_step_name + , par_subsystem + , par_command + , par_flags + , par_additional_parameters + , par_cmdexec_success_code + , par_on_success_action + , par_on_success_step_id + , par_on_fail_action + , par_on_fail_step_id + , par_server + , par_database_name + , par_database_user_name + , par_retry_attempts + , par_retry_interval + , par_os_run_priority + , par_output_file_name + , 0 + , 0 + , 0 + , 0 + , 0 + , par_proxy_id + , par_step_uid + ); + + --PERFORM sys.sp_jobstep_create_proc (par_step_uid); + + returncode := var_retval; + RETURN; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_add_schedule ( + par_schedule_name varchar, + par_enabled smallint = 1, + par_freq_type integer = 0, + par_freq_interval integer = 0, + par_freq_subday_type integer = 0, + par_freq_subday_interval integer = 0, + par_freq_relative_interval integer = 0, + par_freq_recurrence_factor integer = 0, + par_active_start_date integer = NULL::integer, + par_active_end_date integer = 99991231, + par_active_start_time integer = 0, + par_active_end_time integer = 235959, + par_owner_login_name varchar = NULL::character varying, + inout par_schedule_uid char = NULL::bpchar, + inout par_schedule_id integer = NULL::integer, + par_originating_server varchar = NULL::character varying, + out returncode integer +) +AS +$body$ +DECLARE + var_retval INT; + var_owner_sid CHAR(85); + var_orig_server_id INT; +BEGIN + /* Remove any leading/trailing spaces from parameters */ + SELECT LTRIM(RTRIM(par_schedule_name)) + , LTRIM(RTRIM(par_owner_login_name)) + , UPPER(LTRIM(RTRIM(par_originating_server))) + , 0 + INTO par_schedule_name + , par_owner_login_name + , par_originating_server + , par_schedule_id; + + /* Check schedule (frequency and owner) parameters */ + SELECT t.par_freq_interval + , t.par_freq_subday_type + , t.par_freq_subday_interval + , t.par_freq_relative_interval + , t.par_freq_recurrence_factor + , t.par_active_start_date + , t.par_active_start_time + , t.par_active_end_date + , t.par_active_end_time + , t.returncode + FROM sys.babelfish_sp_verify_schedule( + NULL::integer /* @schedule_id -- schedule_id does not exist for the new schedule */ + , par_schedule_name /* @name */ + , par_enabled /* @enabled */ + , par_freq_type /* @freq_type */ + , par_freq_interval /* @freq_interval */ + , par_freq_subday_type /* @freq_subday_type */ + , par_freq_subday_interval /* @freq_subday_interval */ + , par_freq_relative_interval /* @freq_relative_interval */ + , par_freq_recurrence_factor /* @freq_recurrence_factor */ + , par_active_start_date /* @active_start_date */ + , par_active_start_time /* @active_start_time */ + , par_active_end_date /* @active_end_date */ + , par_active_end_time /* @active_end_time */ + , var_owner_sid + ) t + INTO par_freq_interval + , par_freq_subday_type + , par_freq_subday_interval + , par_freq_relative_interval + , par_freq_recurrence_factor + , par_active_start_date + , par_active_start_time + , par_active_end_date + , par_active_end_time + , var_retval /* @owner_sid */; + + IF (var_retval <> 0) THEN /* Failure */ + returncode := 1; + RETURN; + END IF; + + IF (par_schedule_uid IS NULL) + THEN /* Assign the GUID */ + /* uuid without extensions uuid-ossp (cheat) */ + SELECT uuid_in(md5(random()::text || clock_timestamp()::text)::cstring) INTO par_schedule_uid; + END IF; + + var_orig_server_id := 0; + var_owner_sid := uuid_in(md5(random()::text || clock_timestamp()::text)::cstring); + + + INSERT + INTO sys.sysschedules ( + schedule_uid + , originating_server_id + , name + , owner_sid + , enabled + , freq_type + , freq_interval + , freq_subday_type + , freq_subday_interval + , freq_relative_interval + , freq_recurrence_factor + , active_start_date + , active_end_date + , active_start_time + , active_end_time + ) + VALUES ( + par_schedule_uid + , var_orig_server_id + , par_schedule_name + , var_owner_sid + , par_enabled + , par_freq_type + , par_freq_interval + , par_freq_subday_type + , par_freq_subday_interval + , par_freq_relative_interval + , par_freq_recurrence_factor + , par_active_start_date + , par_active_end_date + , par_active_start_time + , par_active_end_time + ); + + /* ZZZ */ + SELECT 0 /* @@ERROR, */, LASTVAL() + INTO var_retval, par_schedule_id; + + /* 0 means success */ + returncode := var_retval; + RETURN; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_attach_schedule ( + par_job_id integer = NULL::integer, + par_job_name varchar = NULL::character varying, + par_schedule_id integer = NULL::integer, + par_schedule_name varchar = NULL::character varying, + par_automatic_post smallint = 1, + out returncode integer +) +RETURNS integer AS +$body$ +DECLARE + var_retval INT; + var_sched_owner_sid CHAR(85); + var_job_owner_sid CHAR(85); +BEGIN + /* Check that we can uniquely identify the job */ + SELECT t.par_job_name + , t.par_job_id + , t.par_owner_sid + , t.returncode + FROM sys.babelfish_sp_verify_job_identifiers( + '@job_name' + , '@job_id' + , par_job_name /* @job_name */ + , par_job_id /* @job_id */ + , 'TEST' /* @sqlagent_starting_test */ + , var_job_owner_sid) t + INTO par_job_name + , par_job_id + , var_job_owner_sid + , var_retval; + + IF (var_retval <> 0) THEN /* Failure */ + returncode := 1; + RETURN; + END IF; + + /* Check that we can uniquely identify the schedule */ + SELECT t.par_schedule_name + , t.par_schedule_id + , t.par_owner_sid + --, t.par_orig_server_id + , t.returncode + FROM sys.babelfish_sp_verify_schedule_identifiers( + '@schedule_name'::character varying /* @name_of_name_parameter */ + , '@schedule_id'::character varying /* @name_of_id_parameter */ + , par_schedule_name /* @schedule_name */ + , par_schedule_id /* @schedule_id */ + , var_sched_owner_sid /* @owner_sid */ + , NULL::integer /* @orig_server_id */ + , NULL::integer) t + INTO par_schedule_name + , par_schedule_id + , var_sched_owner_sid + , var_retval /* @job_id_filter */; + + IF (var_retval <> 0) THEN /* Failure */ + returncode := 1; + RETURN; + END IF + + /* If the record doesn't already exist create it */; + IF ( + NOT EXISTS ( + SELECT 1 + FROM sys.sysjobschedules + WHERE (schedule_id = par_schedule_id) + AND (job_id = par_job_id))) + THEN + INSERT + INTO sys.sysjobschedules (schedule_id, job_id) + VALUES (par_schedule_id, par_job_id); + + SELECT 0 INTO var_retval; /* @@ERROR */ + END IF; + + + PERFORM sys.babelfish_sp_set_next_run (par_job_id, par_schedule_id); + + /* 0 means success */ + returncode := var_retval; + RETURN; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_aws_add_jobschedule ( + par_job_id integer = NULL::integer, + par_schedule_id integer = NULL::integer, + out returncode integer +) +AS +$body$ +DECLARE + var_retval INT; + proc_name_mask VARCHAR(100); + var_owner_login_name VARCHAR(128); + var_xml TEXT DEFAULT ''; + var_cron_expression VARCHAR(50); + var_job_cmd VARCHAR(255); + lambda_arn VARCHAR(255); + return_message text; + var_schedule_name VARCHAR(255); + + var_job_name VARCHAR(128); + var_start_step_id INTEGER; + var_notify_level_email INTEGER; + var_notify_email_operator_id INTEGER; + var_notify_email_operator_name VARCHAR(128); + notify_email_sender VARCHAR(128); + var_delete_level INTEGER; +BEGIN + + IF (EXISTS ( + SELECT 1 + FROM sys.sysjobschedules + WHERE (schedule_id = par_schedule_id) + AND (job_id = par_job_id))) + THEN + SELECT cron_expression + FROM sys.babelfish_sp_schedule_to_cron (par_job_id, par_schedule_id) + INTO var_cron_expression; + + SELECT name + FROM sys.sysschedules + WHERE schedule_id = par_schedule_id + INTO var_schedule_name; + + SELECT name + , start_step_id + , COALESCE(notify_level_email,0) + , COALESCE(notify_email_operator_id,0) + , COALESCE(notify_email_operator_name,'') + , COALESCE(delete_level,0) + FROM sys.sysjobs + WHERE job_id = par_job_id + INTO var_job_name + , var_start_step_id + , var_notify_level_email + , var_notify_email_operator_id + , var_notify_email_operator_name + , var_delete_level; + + proc_name_mask := 'sys_data.sql_agent$job_%s_step_%s'; + var_job_cmd := format(proc_name_mask, par_job_id, '1'); + notify_email_sender := 'aws_test_email_sender@dbbest.com'; + + + var_xml := CONCAT(var_xml, '{'); + var_xml := CONCAT(var_xml, '"mode": "add_job",'); + var_xml := CONCAT(var_xml, '"parameters": {'); + var_xml := CONCAT(var_xml, '"vendor": "postgresql",'); + var_xml := CONCAT(var_xml, '"job_name": "',var_schedule_name,'",'); + var_xml := CONCAT(var_xml, '"job_frequency": "',var_cron_expression,'",'); + var_xml := CONCAT(var_xml, '"job_cmd": "',var_job_cmd,'",'); + var_xml := CONCAT(var_xml, '"notify_level_email": ',var_notify_level_email,','); + var_xml := CONCAT(var_xml, '"delete_level": ',var_delete_level,','); + var_xml := CONCAT(var_xml, '"uid": "',par_job_id,'",'); + var_xml := CONCAT(var_xml, '"callback": "sys.babelfish_sp_job_log",'); + var_xml := CONCAT(var_xml, '"notification": {'); + var_xml := CONCAT(var_xml, '"notify_email_sender": "',notify_email_sender,'",'); + var_xml := CONCAT(var_xml, '"notify_email_recipient": "',var_notify_email_operator_name,'"'); + var_xml := CONCAT(var_xml, '}'); + var_xml := CONCAT(var_xml, '}'); + var_xml := CONCAT(var_xml, '}'); + + -- RAISE NOTICE '%', var_xml; + + + SELECT sys.babelfish_get_service_setting ('JOB', 'LAMBDA_ARN') + INTO lambda_arn; + + SELECT sys.awslambda_fn (lambda_arn, var_xml) INTO return_message; + returncode := 0; + ELSE + returncode := 1; + RAISE 'Job not fount' USING ERRCODE := '50000'; + END IF; + +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_aws_del_jobschedule ( + par_job_id integer = NULL::integer, + par_schedule_id integer = NULL::integer, + out returncode integer +) +AS +$body$ +DECLARE + var_retval INT; + proc_name_mask VARCHAR(100); + var_owner_login_name VARCHAR(128); + var_xml TEXT DEFAULT ''; + var_cron_expression VARCHAR(50); + var_job_cmd VARCHAR(255); + lambda_arn VARCHAR(255); + return_message text; + var_schedule_name VARCHAR(255); +BEGIN + + IF (EXISTS ( + SELECT 1 + FROM sys.sysjobschedules + WHERE (schedule_id = par_schedule_id) + AND (job_id = par_job_id))) + THEN + SELECT name + FROM sys.sysschedules + WHERE schedule_id = par_schedule_id + INTO var_schedule_name; + + var_xml := CONCAT(var_xml, '{'); + var_xml := CONCAT(var_xml, '"mode": "del_schedule",'); + var_xml := CONCAT(var_xml, '"parameters": {'); + var_xml := CONCAT(var_xml, '"schedule_name": "',var_schedule_name,'",'); + var_xml := CONCAT(var_xml, '"force_delete": "TRUE"'); + var_xml := CONCAT(var_xml, '}'); + var_xml := CONCAT(var_xml, '}'); + + SELECT sys.babelfish_get_service_setting ('JOB', 'LAMBDA_ARN') + INTO lambda_arn; + + SELECT sys.awslambda_fn (lambda_arn, var_xml) INTO return_message; + returncode := 0; + ELSE + returncode := 1; + RAISE 'Job not fount' USING ERRCODE := '50000'; + END IF; + +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_delete_job ( + par_job_id integer = NULL::integer, + par_job_name varchar = NULL::character varying, + par_originating_server varchar = NULL::character varying, + par_delete_history smallint = 1, + par_delete_unused_schedule smallint = 1, + out returncode integer +) +RETURNS integer AS +$body$ +DECLARE + var_retval INT; + var_category_id INT; + var_job_owner_sid CHAR(85); + var_err INT; + var_schedule_id INT; +BEGIN + IF ((par_job_id IS NOT NULL) OR (par_job_name IS NOT NULL)) + THEN + SELECT t.par_job_name + , t.par_job_id + , t.par_owner_sid + , t.returncode + FROM sys.babelfish_sp_verify_job_identifiers( + '@job_name' + , '@job_id' + , par_job_name + , par_job_id + , 'TEST' + , var_job_owner_sid + ) t + INTO par_job_name + , par_job_id + , var_job_owner_sid + , var_retval; + + IF (var_retval <> 0) THEN /* Failure */ + returncode := (1); + RETURN; + END IF; + END IF; + + /* Get category to see if it is a misc. replication agent. @category_id will be */ + /* NULL if there is no @job_id. */ + + SELECT category_id + INTO var_category_id + FROM sys.sysjobs + WHERE job_id = par_job_id; + + /* Do the delete (for a specific job) */ + IF (par_job_id IS NOT NULL) + THEN + --CREATE TEMPORARY TABLE "#temp_schedules_to_delete" (schedule_id INT NOT NULL); + + -- Delete all traces of the job + -- BEGIN TRANSACTION + -- Get the schedules to delete before deleting records from sysjobschedules + + + + --IF (par_delete_unused_schedule = 1) + --THEN + -- ZZZ optimize + -- Get the list of schedules to delete + --INSERT INTO "#temp_schedules_to_delete" + --SELECT DISTINCT schedule_id + -- FROM sys.sysschedules + -- WHERE schedule_id IN (SELECT schedule_id + -- FROM sys.sysjobschedules + -- WHERE job_id = par_job_id); + --INSERT INTO "#temp_schedules_to_delete" + SELECT schedule_id + FROM sys.sysjobschedules + WHERE job_id = par_job_id + INTO var_schedule_id; + + PERFORM sys.babelfish_sp_aws_del_jobschedule (par_job_id := par_job_id, par_schedule_id := var_schedule_id); + + +-- END IF; + + + --DELETE FROM sys.sysschedules + -- WHERE schedule_id IN (SELECT schedule_id FROM sys.sysjobschedules WHERE job_id = par_job_id); + + DELETE FROM sys.sysjobschedules + WHERE job_id = par_job_id; + + DELETE FROM sys.sysjobsteps + WHERE job_id = par_job_id; + + DELETE FROM sys.sysjobs + WHERE job_id = par_job_id; + + SELECT 0 /* @@ERROR */ INTO var_err; + + /* Delete the schedule(s) if requested to and it isn't being used by other jobs */ + IF (par_delete_unused_schedule = 1) + THEN + /* Now OK to delete the schedule */ + DELETE FROM sys.sysschedules + WHERE schedule_id = var_schedule_id; --IN (SELECT schedule_id FROM "#temp_schedules_to_delete"); + + --DELETE FROM sys.sysschedules + -- WHERE schedule_id IN (SELECT schedule_id + -- FROM "#temp_schedules_to_delete" AS sdel + -- WHERE NOT EXISTS (SELECT * + -- FROM sys.sysjobschedules AS js + -- WHERE js.schedule_id = sdel.schedule_id)); + END IF; + + /* Delete the job history if requested */ + IF (par_delete_history = 1) + THEN + DELETE FROM sys.sysjobhistory + WHERE job_id = par_job_id; + END IF; + + /* All done */ + /* COMMIT TRANSACTION */ + --DROP TABLE "#temp_schedules_to_delete"; + END IF; + + /* 0 means success */ + returncode := 0; + RETURN; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_delete_jobschedule ( + par_job_id integer = NULL::integer, + par_job_name varchar = NULL::character varying, + par_name varchar = NULL::character varying, + par_keep_schedule integer = 0, + par_automatic_post smallint = 1, + out returncode integer +) +RETURNS integer AS +$body$ +DECLARE + var_retval INT; + var_sched_count INT; + var_schedule_id INT; + var_job_owner_sid CHAR(85); +BEGIN + /* Remove any leading/trailing spaces from parameters */ + SELECT LTRIM(RTRIM(par_name)) INTO par_name; + + /* Check that we can uniquely identify the job */ + SELECT t.par_job_name + , t.par_job_id + , t.par_owner_sid + , t.returncode + FROM sys.babelfish_sp_verify_job_identifiers( + '@job_name' + , '@job_id' + , par_job_name + , par_job_id + , 'TEST' + , var_job_owner_sid + ) t + INTO par_job_name + , par_job_id + , var_job_owner_sid + , var_retval; + + IF (var_retval <> 0) THEN /* Failure */ + returncode := 1; + RETURN; + END IF; + + IF (LOWER(UPPER(par_name)) = LOWER('ALL')) + THEN + SELECT - 1 INTO var_schedule_id; + + /* We use this in the call to sp_sqlagent_notify */ + /* Delete the schedule(s) if it isn't being used by other jobs */ + CREATE TEMPORARY TABLE "#temp_schedules_to_delete" (schedule_id INT NOT NULL) + /* If user requests that the schedules be removed (the legacy behavoir) */ + /* make sure it isnt being used by other jobs */; + + IF (par_keep_schedule = 0) + THEN + /* Get the list of schedules to delete */ + INSERT INTO "#temp_schedules_to_delete" + SELECT DISTINCT schedule_id + FROM sys.sysschedules + WHERE (schedule_id IN (SELECT schedule_id + FROM sys.sysjobschedules + WHERE (job_id = par_job_id))); + /* make sure no other jobs use these schedules */ + IF (EXISTS (SELECT * + FROM sys.sysjobschedules + WHERE (job_id <> par_job_id) + AND (schedule_id IN (SELECT schedule_id + FROM "#temp_schedules_to_delete")))) + THEN /* Failure */ + RAISE 'One or more schedules were not deleted because they are being used by at least one other job. Use "sp_detach_schedule" to remove schedules from a job.' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + END IF; + + /* OK to delete the jobschedule */ + DELETE FROM sys.sysjobschedules + WHERE (job_id = par_job_id); + + /* OK to delete the schedule - temp_schedules_to_delete is empty if @keep_schedule <> 0 */ + DELETE FROM sys.sysschedules + WHERE schedule_id IN (SELECT schedule_id FROM "#temp_schedules_to_delete"); + ELSE ---- IF (LOWER(UPPER(par_name)) = LOWER('ALL')) + + -- Need to use sp_detach_schedule to remove this ambiguous schedule name + IF(var_sched_count > 1) /* Failure */ + THEN + RAISE 'More than one schedule named "%" is attached to job "%". Use "sp_detach_schedule" to remove schedules from a job.', par_name, par_job_name USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + --If user requests that the schedule be removed (the legacy behavoir) + --make sure it isnt being used by another job + IF (par_keep_schedule = 0) + THEN + IF(EXISTS(SELECT * + FROM sys.sysjobschedules + WHERE (schedule_id = var_schedule_id) + AND (job_id <> par_job_id))) + THEN /* Failure */ + RAISE 'Schedule "%" was not deleted because it is being used by at least one other job. Use "sp_detach_schedule" to remove schedules from a job.', par_name USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + END IF; + + /* Delete the job schedule link first */ + DELETE FROM sys.sysjobschedules + WHERE (job_id = par_job_id) + AND (schedule_id = var_schedule_id); + + /* Delete schedule if required */ + IF (par_keep_schedule = 0) + THEN + /* Now delete the schedule if required */ + DELETE FROM sys.sysschedules + WHERE (schedule_id = var_schedule_id); + END IF; + + SELECT t.returncode + FROM sys.babelfish_sp_aws_del_jobschedule(par_job_id, var_schedule_id) t + INTO var_retval; + + + END IF; + + /* Update the job's version/last-modified information */ + UPDATE sys.sysjobs + SET version_number = version_number + 1 + -- , date_modified = GETDATE() / + WHERE job_id = par_job_id; + + DROP TABLE IF EXISTS "#temp_schedules_to_delete"; + + + /* 0 means success */ + returncode := var_retval; + RETURN; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_delete_jobstep ( + par_job_id integer = NULL::integer, + par_job_name varchar = NULL::character varying, + par_step_id integer = NULL::integer, + out returncode integer +) +RETURNS integer AS +$body$ +DECLARE + var_retval INT; + var_max_step_id INT; + var_valid_range VARCHAR(50); + var_job_owner_sid CHAR(85); +BEGIN + SELECT t.par_job_name + , t.par_job_id + , t.par_owner_sid + , t.returncode + FROM sys.babelfish_sp_verify_job_identifiers( + '@job_name' + , '@job_id' + , par_job_name + , par_job_id + , 'TEST' + , var_job_owner_sid + ) t + INTO par_job_name + , par_job_id + , var_job_owner_sid + , var_retval; + + IF (var_retval <> 0) THEN /* Failure */ + returncode := 1; + RETURN; + END IF; + + /* Get current maximum step id */ + SELECT COALESCE(MAX(step_id), 0) + INTO var_max_step_id + FROM sys.sysjobsteps + WHERE (job_id = par_job_id); + + /* Check step id */ + IF (par_step_id < 0) OR (par_step_id > var_max_step_id) + THEN + SELECT CONCAT('0 (all steps) ..', CAST (var_max_step_id AS VARCHAR(1))) + INTO var_valid_range; + RAISE 'The specified "%" is invalid (valid values are: %).', 'step_id', var_valid_range USING ERRCODE := '50000'; + returncode := 1; + RETURN; + /* Failure */ + END IF; + + /* BEGIN TRANSACTION */ + /* Delete either the specified step or ALL the steps (if step id is 0) */ + IF (par_step_id = 0) + THEN + DELETE FROM sys.sysjobsteps + WHERE (job_id = par_job_id); + ELSE + DELETE FROM sys.sysjobsteps + WHERE (job_id = par_job_id) AND (step_id = par_step_id); + END IF; + + IF (par_step_id <> 0) + THEN + /* Adjust step id's */ + UPDATE sys.sysjobsteps + SET step_id = step_id - 1 + WHERE (step_id > par_step_id) + AND (job_id = par_job_id); + + /* Clean up OnSuccess/OnFail references */ + UPDATE sys.sysjobsteps + SET on_success_step_id = on_success_step_id - 1 + WHERE (on_success_step_id > par_step_id) AND (job_id = par_job_id); + + UPDATE sys.sysjobsteps + SET on_fail_step_id = on_fail_step_id - 1 + WHERE (on_fail_step_id > par_step_id) AND (job_id = par_job_id); + + /* Quit With Success */ + UPDATE sys.sysjobsteps + SET on_success_step_id = 0 + , on_success_action = 1 + WHERE (on_success_step_id = par_step_id) + AND (job_id = par_job_id); + + /* Quit With Failure */ + UPDATE sys.sysjobsteps + SET on_fail_step_id = 0 + , on_fail_action = 2 + WHERE (on_fail_step_id = par_step_id) AND (job_id = par_job_id); + END IF; + + /* Update the job's version/last-modified information */ + UPDATE sys.sysjobs + SET version_number = version_number + 1 + --, date_modified = GETDATE() / + WHERE (job_id = par_job_id); + + /* COMMIT TRANSACTION */ + + /* Success */ + returncode := 0; + RETURN; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_delete_schedule ( + par_schedule_id integer = NULL::integer, + par_schedule_name varchar = NULL::character varying, + par_force_delete smallint = 0, + par_automatic_post smallint = 1, + out returncode integer +) +RETURNS integer AS +$body$ +DECLARE + var_retval INT; + var_job_count INT; +BEGIN + /* check if there are jobs using this schedule */ + SELECT COUNT(*) + INTO var_job_count + FROM sys.sysjobschedules + WHERE (schedule_id = par_schedule_id); + + /* If we aren't force deleting the schedule make sure no jobs are using it */ + IF ((par_force_delete = 0) AND (var_job_count > 0)) + THEN /* Failure */ + RAISE 'The schedule was not deleted because it is being used by one or more jobs.' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + /* OK to delete the job - schedule link */ + DELETE FROM sys.sysjobschedules + WHERE schedule_id = par_schedule_id; + + /* OK to delete the schedule */ + DELETE FROM sys.sysschedules + WHERE schedule_id = par_schedule_id; + + /* 0 means success */ + returncode := var_retval; + RETURN; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_detach_schedule ( + par_job_id integer = NULL::integer, + par_job_name varchar = NULL::character varying, + par_schedule_id integer = NULL::integer, + par_schedule_name varchar = NULL::character varying, + par_delete_unused_schedule smallint = 0, + par_automatic_post smallint = 1, + out returncode integer +) +RETURNS integer AS +$body$ +DECLARE + var_retval INT; + var_sched_owner_sid CHAR(85); + var_job_owner_sid CHAR(85); +BEGIN + /* Check that we can uniquely identify the job */ + SELECT t.par_job_name + , t.par_job_id + , t.par_owner_sid + , t.returncode + FROM sys.babelfish_sp_verify_job_identifiers( + '@job_name' + , '@job_id' + , par_job_name + , par_job_id + , 'TEST' + , var_job_owner_sid + ) t + INTO par_job_name + , par_job_id + , var_job_owner_sid + , var_retval; + + IF (var_retval <> 0) THEN /* Failure */ + returncode := 1; + RETURN; + END IF; + + /* Check that we can uniquely identify the schedule */ + SELECT t.par_schedule_name + , t.par_schedule_id + , t.par_owner_sid + , t.par_orig_server_id + , t.returncode + FROM sys.babelfish_sp_verify_schedule_identifiers( + '@schedule_name' /* @name_of_name_parameter */ + , '@schedule_id' /* @name_of_id_parameter */ + , par_schedule_name /* @schedule_name */ + , par_schedule_id /* @schedule_id */ + , var_sched_owner_sid /* @owner_sid */ + , NULL /* @orig_server_id */ + , par_job_id + ) t + INTO par_schedule_name + , par_schedule_id + , var_sched_owner_sid + , var_retval; + -- job_id_filter + + IF (var_retval <> 0) THEN /* Failure */ + returncode := 1; + RETURN; + END IF; + + /* If the record doesn't exist raise an error */ + IF (NOT EXISTS ( + SELECT * + FROM sys.sysjobschedules + WHERE (schedule_id = par_schedule_id) + AND (job_id = par_job_id))) + THEN /* Failure */ + RAISE 'The specified schedule name "%s" is not associated with the job "%s".', par_schedule_name, par_job_name USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + SELECT t.returncode + FROM sys.babelfish_sp_aws_del_jobschedule(par_job_id, par_schedule_id) t + INTO var_retval; + + DELETE FROM sys.sysjobschedules + WHERE (job_id = par_job_id) + AND (schedule_id = par_schedule_id); + + SELECT /* @@ERROR */ 0 -- ZZZ + INTO var_retval; + + /* delete the schedule if requested and it isn't referenced */ + IF (var_retval = 0 AND par_delete_unused_schedule = 1) + THEN + IF (NOT EXISTS ( + SELECT * + FROM sys.sysjobschedules + WHERE (schedule_id = par_schedule_id))) + THEN + DELETE FROM sys.sysschedules + WHERE (schedule_id = par_schedule_id); + END IF; + END IF; + + /* Update the job's version/last-modified information */ + /* + UPDATE sys.sysjobs + SET version_number = version_number + 1 + -- , date_modified = GETDATE() + WHERE (job_id = par_job_id); + */ + + -- PERFORM sys.babelfish_sp_delete_job (par_job_id := par_job_id); + + /* 0 means success */ + returncode := var_retval; + RETURN; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_job_log ( + IN pid INTEGER + , IN pstatus INTEGER + , IN pmessage VARCHAR(255)) +RETURNS void AS +$BODY$ +BEGIN + PERFORM sys.babelfish_update_job (pid, pmessage); + + -- INSERT INTO ms_test.jobs_log(id, t, status, message) + -- VALUES (pid, CURRENT_TIMESTAMP, pstatus, pmessage); +END; +$BODY$ +LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_schedule_to_cron ( + par_job_id integer, + par_schedule_id integer, + out cron_expression varchar +) +RETURNS VARCHAR AS +$body$ +DECLARE + var_enabled INTEGER; + var_freq_type INTEGER; + var_freq_interval INTEGER; + var_freq_subday_type INTEGER; + var_freq_subday_interval INTEGER; + var_freq_relative_interval INTEGER; + var_freq_recurrence_factor INTEGER; + var_active_start_date INTEGER; + var_active_end_date INTEGER; + var_active_start_time INTEGER; + var_active_end_time INTEGER; + + var_next_run_date date; + var_next_run_time time; + var_next_run_dt timestamp; + + var_tmp_interval varchar(50); + var_current_dt timestamp; + var_next_dt timestamp; +BEGIN + + SELECT enabled + , freq_type + , freq_interval + , freq_subday_type + , freq_subday_interval + , freq_relative_interval + , freq_recurrence_factor + , active_start_date + , active_end_date + , active_start_time + , active_end_time + FROM sys.sysschedules + INTO var_enabled + , var_freq_type + , var_freq_interval + , var_freq_subday_type + , var_freq_subday_interval + , var_freq_relative_interval + , var_freq_recurrence_factor + , var_active_start_date + , var_active_end_date + , var_active_start_time + , var_active_end_time + WHERE schedule_id = par_schedule_id; + + /* if enabled = 0 return */ + CASE var_freq_type + WHEN 1 THEN + NULL; + + WHEN 4 THEN + BEGIN + cron_expression := + CASE + /* WHEN var_freq_subday_type = 1 THEN var_freq_subday_interval::character varying || ' At the specified time' -- start time */ + /* WHEN var_freq_subday_type = 2 THEN var_freq_subday_interval::character varying || ' second' -- ADD var_freq_subday_interval SECOND */ + WHEN var_freq_subday_type = 4 THEN format('cron(*/%s * * * ? *)', var_freq_subday_interval::character varying) /* ADD var_freq_subday_interval MINUTE */ + WHEN var_freq_subday_type = 8 THEN format('cron(0 */%s * * ? *)', var_freq_subday_interval::character varying) /* ADD var_freq_subday_interval HOUR */ + ELSE '' + END; + END; + + WHEN 8 THEN + NULL; + + WHEN 16 THEN + NULL; + + WHEN 32 THEN + NULL; + + WHEN 64 THEN + NULL; + + WHEN 128 THEN + NULL; + + END CASE; + + -- return cron_expression; + +END; +$body$ +LANGUAGE 'plpgsql'; + +create or replace function sys.babelfish_sp_sequence_get_range( + in par_sequence_name text, + in par_range_size bigint, + out par_range_first_value bigint, + out par_range_last_value bigint, + out par_range_cycle_count bigint, + out par_sequence_increment bigint, + out par_sequence_min_value bigint, + out par_sequence_max_value bigint +) as +$body$ +declare + v_is_cycle character varying(3); + v_current_value bigint; +begin + select s.minimum_value, s.maximum_value, s.increment, s.cycle_option + from information_schema.sequences s + where s.sequence_name = $1 + into par_sequence_min_value, par_sequence_max_value, par_sequence_increment, v_is_cycle; + + par_range_first_value := sys.babelfish_get_sequence_value(par_sequence_name); + + if par_range_first_value > par_sequence_min_value then + par_range_first_value := par_range_first_value + 1; + end if; + + if v_is_cycle = 'YES' then + par_range_cycle_count := 0; + end if; + + for i in 1..$2 loop + select nextval(par_sequence_name) into v_current_value; + if (v_is_cycle = 'YES') and (v_current_value = par_sequence_min_value) and (par_range_first_value <> v_current_value) then + par_range_cycle_count := par_range_cycle_count + 1; + end if; + end loop; + + par_range_last_value := sys.babelfish_get_sequence_value(par_sequence_name); +end; +$body$ +language plpgsql; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_set_next_run ( + par_job_id integer, + par_schedule_id integer +) +RETURNS void AS +$body$ +DECLARE + var_enabled INTEGER; + var_freq_type INTEGER; + var_freq_interval INTEGER; + var_freq_subday_type INTEGER; + var_freq_subday_interval INTEGER; + var_freq_relative_interval INTEGER; + var_freq_recurrence_factor INTEGER; + var_active_start_date INTEGER; + var_active_end_date INTEGER; + var_active_start_time INTEGER; + var_active_end_time INTEGER; + + var_next_run_date date; + var_next_run_time time; + var_next_run_dt timestamp; + + var_tmp_interval varchar(50); + var_current_dt timestamp; + var_next_dt timestamp; +BEGIN + + SELECT enabled + , freq_type + , freq_interval + , freq_subday_type + , freq_subday_interval + , freq_relative_interval + , freq_recurrence_factor + , active_start_date + , active_end_date + , active_start_time + , active_end_time + FROM sys.sysschedules + INTO var_enabled + , var_freq_type + , var_freq_interval + , var_freq_subday_type + , var_freq_subday_interval + , var_freq_relative_interval + , var_freq_recurrence_factor + , var_active_start_date + , var_active_end_date + , var_active_start_time + , var_active_end_time + WHERE schedule_id = par_schedule_id; + + SELECT next_run_date + , next_run_time + FROM sys.sysjobschedules + INTO var_next_run_date + , var_next_run_time + WHERE schedule_id = par_schedule_id + AND job_id = par_job_id; + + /* if enabled = 0 return */ + CASE var_freq_type + WHEN 1 THEN + NULL; + + WHEN 4 THEN + BEGIN + /* NULL start date & time or now */ + /* start date + start time or now() */ + IF (var_next_run_date IS NULL OR var_next_run_time IS NULL) + THEN + var_current_dt := now()::timestamp; + + UPDATE sys.sysjobschedules + SET next_run_date = var_current_dt::date + , next_run_time = var_current_dt::time + WHERE schedule_id = par_schedule_id + AND job_id = par_job_id; + RETURN; + ELSE + var_tmp_interval := + CASE + /* WHEN var_freq_subday_type = 1 THEN var_freq_subday_interval::character varying || ' At the specified time' -- start time */ + WHEN var_freq_subday_type = 2 THEN var_freq_subday_interval::character varying || ' second' /* ADD var_freq_subday_interval SECOND */ + WHEN var_freq_subday_type = 4 THEN var_freq_subday_interval::character varying || ' minute' /* ADD var_freq_subday_interval MINUTE */ + WHEN var_freq_subday_type = 8 THEN var_freq_subday_interval::character varying || ' hour' /* ADD var_freq_subday_interval HOUR */ + ELSE '' + END; + + var_next_dt := (var_next_run_date::date + var_next_run_time::time)::timestamp + var_tmp_interval::INTERVAL; + UPDATE sys.sysjobschedules + SET next_run_date = var_next_dt::date + , next_run_time = var_next_dt::time + WHERE schedule_id = par_schedule_id + AND job_id = par_job_id; + RETURN; + END IF; + END; + + WHEN 8 THEN + NULL; + + WHEN 16 THEN + NULL; + + WHEN 32 THEN + NULL; + + WHEN 64 THEN + NULL; + + WHEN 128 THEN + NULL; + + END CASE; + +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_update_job ( + par_job_id integer = NULL::integer, + par_job_name varchar = NULL::character varying, + par_new_name varchar = NULL::character varying, + par_enabled smallint = NULL::smallint, + par_description varchar = NULL::character varying, + par_start_step_id integer = NULL::integer, + par_category_name varchar = NULL::character varying, + par_owner_login_name varchar = NULL::character varying, + par_notify_level_eventlog integer = NULL::integer, + par_notify_level_email integer = NULL::integer, + par_notify_level_netsend integer = NULL::integer, + par_notify_level_page integer = NULL::integer, + par_notify_email_operator_name varchar = NULL::character varying, + par_notify_netsend_operator_name varchar = NULL::character varying, + par_notify_page_operator_name varchar = NULL::character varying, + par_delete_level integer = NULL::integer, + par_automatic_post smallint = 1, + out returncode integer +) +RETURNS integer AS +$body$ +DECLARE + var_retval INT; + var_category_id INT; + var_notify_email_operator_id INT; + var_notify_netsend_operator_id INT; + var_notify_page_operator_id INT; + var_owner_sid CHAR(85); + var_alert_id INT; + var_cached_attribute_modified INT; + var_is_sysadmin INT; + var_current_owner VARCHAR(128); + var_enable_only_used INT; + var_x_new_name VARCHAR(128); + var_x_enabled SMALLINT; + var_x_description VARCHAR(512); + var_x_start_step_id INT; + var_x_category_name VARCHAR(128); + var_x_category_id INT; + var_x_owner_sid CHAR(85); + var_x_notify_level_eventlog INT; + var_x_notify_level_email INT; + var_x_notify_level_netsend INT; + var_x_notify_level_page INT; + var_x_notify_email_operator_name VARCHAR(128); + var_x_notify_netsnd_operator_name VARCHAR(128); + var_x_notify_page_operator_name VARCHAR(128); + var_x_delete_level INT; + var_x_originating_server_id INT; + var_x_master_server SMALLINT; +BEGIN + /* Not updatable */ + /* Remove any leading/trailing spaces from parameters (except @owner_login_name) */ + SELECT + LTRIM(RTRIM(par_job_name)) + INTO par_job_name; + SELECT + LTRIM(RTRIM(par_new_name)) + INTO par_new_name; + SELECT + LTRIM(RTRIM(par_description)) + INTO par_description; + SELECT + LTRIM(RTRIM(par_category_name)) + INTO par_category_name; + SELECT + LTRIM(RTRIM(par_notify_email_operator_name)) + INTO par_notify_email_operator_name; + SELECT + LTRIM(RTRIM(par_notify_netsend_operator_name)) + INTO par_notify_netsend_operator_name; + SELECT + LTRIM(RTRIM(par_notify_page_operator_name)) + INTO par_notify_page_operator_name + /* Are we modifying an attribute which tsql agent caches? */; + + IF ((par_new_name IS NOT NULL) OR (par_enabled IS NOT NULL) OR (par_start_step_id IS NOT NULL) OR (par_owner_login_name IS NOT NULL) OR (par_notify_level_eventlog IS NOT NULL) OR (par_notify_level_email IS NOT NULL) OR (par_notify_level_netsend IS NOT NULL) OR (par_notify_level_page IS NOT NULL) OR (par_notify_email_operator_name IS NOT NULL) OR (par_notify_netsend_operator_name IS NOT NULL) OR (par_notify_page_operator_name IS NOT NULL) OR (par_delete_level IS NOT NULL)) THEN + SELECT + 1 + INTO var_cached_attribute_modified; + ELSE + SELECT + 0 + INTO var_cached_attribute_modified; + END IF + /* Is @enable the only parameter used beside jobname and jobid? */; + + IF ((par_enabled IS NOT NULL) AND (par_new_name IS NULL) AND (par_description IS NULL) AND (par_start_step_id IS NULL) AND (par_category_name IS NULL) AND (par_owner_login_name IS NULL) AND (par_notify_level_eventlog IS NULL) AND (par_notify_level_email IS NULL) AND (par_notify_level_netsend IS NULL) AND (par_notify_level_page IS NULL) AND (par_notify_email_operator_name IS NULL) AND (par_notify_netsend_operator_name IS NULL) AND (par_notify_page_operator_name IS NULL) AND (par_delete_level IS NULL)) THEN + SELECT + 1 + INTO var_enable_only_used; + ELSE + SELECT + 0 + INTO var_enable_only_used; + END IF; + + IF (par_new_name = '') THEN + SELECT + NULL + INTO par_new_name; + END IF + /* Fill out the values for all non-supplied parameters from the existing values */; + + IF (par_new_name IS NULL) THEN + SELECT + var_x_new_name + INTO par_new_name; + END IF; + + IF (par_enabled IS NULL) THEN + SELECT + var_x_enabled + INTO par_enabled; + END IF; + + IF (par_description IS NULL) THEN + SELECT + var_x_description + INTO par_description; + END IF; + + IF (par_start_step_id IS NULL) THEN + SELECT + var_x_start_step_id + INTO par_start_step_id; + END IF; + + IF (par_category_name IS NULL) THEN + SELECT + var_x_category_name + INTO par_category_name; + END IF; + + IF (var_owner_sid IS NULL) THEN + SELECT + var_x_owner_sid + INTO var_owner_sid; + END IF; + + IF (par_notify_level_eventlog IS NULL) THEN + SELECT + var_x_notify_level_eventlog + INTO par_notify_level_eventlog; + END IF; + + IF (par_notify_level_email IS NULL) THEN + SELECT + var_x_notify_level_email + INTO par_notify_level_email; + END IF; + + IF (par_notify_level_netsend IS NULL) THEN + SELECT + var_x_notify_level_netsend + INTO par_notify_level_netsend; + END IF; + + IF (par_notify_level_page IS NULL) THEN + SELECT + var_x_notify_level_page + INTO par_notify_level_page; + END IF; + + IF (par_notify_email_operator_name IS NULL) THEN + SELECT + var_x_notify_email_operator_name + INTO par_notify_email_operator_name; + END IF; + + IF (par_notify_netsend_operator_name IS NULL) THEN + SELECT + var_x_notify_netsnd_operator_name + INTO par_notify_netsend_operator_name; + END IF; + + IF (par_notify_page_operator_name IS NULL) THEN + SELECT + var_x_notify_page_operator_name + INTO par_notify_page_operator_name; + END IF; + + IF (par_delete_level IS NULL) THEN + SELECT + var_x_delete_level + INTO par_delete_level; + END IF + /* Turn [nullable] empty string parameters into NULLs */; + + IF (LOWER(par_description) = LOWER('')) THEN + SELECT + NULL + INTO par_description; + END IF; + + IF (par_category_name = '') THEN + SELECT + NULL + INTO par_category_name; + END IF; + + IF (par_notify_email_operator_name = '') THEN + SELECT + NULL + INTO par_notify_email_operator_name; + END IF; + + IF (par_notify_netsend_operator_name = '') THEN + SELECT + NULL + INTO par_notify_netsend_operator_name; + END IF; + + IF (par_notify_page_operator_name = '') THEN + SELECT + NULL + INTO par_notify_page_operator_name; + END IF + /* Check new values */; + SELECT + t.par_owner_sid, t.par_notify_level_email, t.par_notify_level_netsend, t.par_notify_level_page, + t.par_category_id, t.par_notify_email_operator_id, t.par_notify_netsend_operator_id, t.par_notify_page_operator_id, t.par_originating_server, t.ReturnCode + FROM sys.babelfish_sp_verify_job(par_job_id, par_new_name, par_enabled, par_start_step_id, par_category_name, var_owner_sid, par_notify_level_eventlog, par_notify_level_email, par_notify_level_netsend, par_notify_level_page, par_notify_email_operator_name, par_notify_netsend_operator_name, par_notify_page_operator_name, par_delete_level, var_category_id, var_notify_email_operator_id, var_notify_netsend_operator_id, var_notify_page_operator_id, NULL) t + INTO var_owner_sid, par_notify_level_email, par_notify_level_netsend, par_notify_level_page, var_category_id, var_notify_email_operator_id, var_notify_netsend_operator_id, var_notify_page_operator_id, var_retval; + + IF (var_retval <> 0) THEN + ReturnCode := (1); + RETURN; + END IF + /* Failure */ + /* BEGIN TRANSACTION */ + /* If the job is being re-assigned, modify sysjobsteps.database_user_name as necessary */; + + IF (par_owner_login_name IS NOT NULL) THEN + IF (EXISTS (SELECT + 1 + FROM sys.sysjobsteps + WHERE (job_id = par_job_id) AND (LOWER(subsystem) = LOWER('TSQL')))) THEN + /* The job is being re-assigned to an non-SA */ + UPDATE sys.sysjobsteps + SET database_user_name = NULL + WHERE (job_id = par_job_id) AND (LOWER(subsystem) = LOWER('TSQL')); + END IF; + END IF; + UPDATE sys.sysjobs + SET name = par_new_name, enabled = par_enabled, description = par_description, start_step_id = par_start_step_id, category_id = var_category_id + /* Returned from sp_verify_job */, owner_sid = var_owner_sid, notify_level_eventlog = par_notify_level_eventlog, notify_level_email = par_notify_level_email, notify_level_netsend = par_notify_level_netsend, notify_level_page = par_notify_level_page, notify_email_operator_id = var_notify_email_operator_id + /* Returned from sp_verify_job */, notify_netsend_operator_id = var_notify_netsend_operator_id + /* Returned from sp_verify_job */, notify_page_operator_id = var_notify_page_operator_id + /* Returned from sp_verify_job */, delete_level = par_delete_level, version_number = version_number + 1 + /* , -- Update the job's version */ + /* date_modified = GETDATE() -- Update the job's last-modified information */ + WHERE (job_id = par_job_id); + SELECT + 0 + INTO var_retval + /* @@error */ + /* COMMIT TRANSACTION */; + ReturnCode := (var_retval); + RETURN + /* 0 means success */; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_update_jobschedule ( + par_job_id integer = NULL::integer, + par_job_name varchar = NULL::character varying, + par_name varchar = NULL::character varying, + par_new_name varchar = NULL::character varying, + par_enabled smallint = NULL::smallint, + par_freq_type integer = NULL::integer, + par_freq_interval integer = NULL::integer, + par_freq_subday_type integer = NULL::integer, + par_freq_subday_interval integer = NULL::integer, + par_freq_relative_interval integer = NULL::integer, + par_freq_recurrence_factor integer = NULL::integer, + par_active_start_date integer = NULL::integer, + par_active_end_date integer = NULL::integer, + par_active_start_time integer = NULL::integer, + par_active_end_time integer = NULL::integer, + par_automatic_post smallint = 1, + out returncode integer +) +RETURNS integer AS +$body$ +DECLARE + var_retval INT; + var_sched_count INT; + var_schedule_id INT; + var_job_owner_sid CHAR(85); + var_enable_only_used INT; + var_x_name VARCHAR(128); + var_x_enabled SMALLINT; + var_x_freq_type INT; + var_x_freq_interval INT; + var_x_freq_subday_type INT; + var_x_freq_subday_interval INT; + var_x_freq_relative_interval INT; + var_x_freq_recurrence_factor INT; + var_x_active_start_date INT; + var_x_active_end_date INT; + var_x_active_start_time INT; + var_x_active_end_time INT; + var_owner_sid CHAR(85); +BEGIN + /* Remove any leading/trailing spaces from parameters */ + SELECT + LTRIM(RTRIM(par_name)) + INTO par_name; + SELECT + LTRIM(RTRIM(par_new_name)) + INTO par_new_name + /* Turn [nullable] empty string parameters into NULLs */; + + IF (par_new_name = '') THEN + SELECT + NULL + INTO par_new_name; + END IF + /* Check that we can uniquely identify the job */; + SELECT + t.par_job_name, t.par_job_id, t.par_owner_sid, t.ReturnCode + FROM sys.babelfish_sp_verify_job_identifiers('@job_name', '@job_id', par_job_name, par_job_id, 'TEST', var_job_owner_sid) t + INTO par_job_name, par_job_id, var_job_owner_sid, var_retval; + + IF (var_retval <> 0) THEN + ReturnCode := (1); + RETURN; + END IF + /* Failure */ + /* Is @enable the only parameter used beside jobname and jobid? */; + + IF ((par_enabled IS NOT NULL) AND (par_name IS NULL) AND (par_new_name IS NULL) AND (par_freq_type IS NULL) AND (par_freq_interval IS NULL) AND (par_freq_subday_type IS NULL) AND (par_freq_subday_interval IS NULL) AND (par_freq_relative_interval IS NULL) AND (par_freq_recurrence_factor IS NULL) AND (par_active_start_date IS NULL) AND (par_active_end_date IS NULL) AND (par_active_start_time IS NULL) AND (par_active_end_time IS NULL)) THEN + SELECT + 1 + INTO var_enable_only_used; + ELSE + SELECT + 0 + INTO var_enable_only_used; + END IF; + + IF (par_new_name IS NULL) THEN + SELECT + var_x_name + INTO par_new_name; + END IF; + + IF (par_enabled IS NULL) THEN + SELECT + var_x_enabled + INTO par_enabled; + END IF; + + IF (par_freq_type IS NULL) THEN + SELECT + var_x_freq_type + INTO par_freq_type; + END IF; + + IF (par_freq_interval IS NULL) THEN + SELECT + var_x_freq_interval + INTO par_freq_interval; + END IF; + + IF (par_freq_subday_type IS NULL) THEN + SELECT + var_x_freq_subday_type + INTO par_freq_subday_type; + END IF; + + IF (par_freq_subday_interval IS NULL) THEN + SELECT + var_x_freq_subday_interval + INTO par_freq_subday_interval; + END IF; + + IF (par_freq_relative_interval IS NULL) THEN + SELECT + var_x_freq_relative_interval + INTO par_freq_relative_interval; + END IF; + + IF (par_freq_recurrence_factor IS NULL) THEN + SELECT + var_x_freq_recurrence_factor + INTO par_freq_recurrence_factor; + END IF; + + IF (par_active_start_date IS NULL) THEN + SELECT + var_x_active_start_date + INTO par_active_start_date; + END IF; + + IF (par_active_end_date IS NULL) THEN + SELECT + var_x_active_end_date + INTO par_active_end_date; + END IF; + + IF (par_active_start_time IS NULL) THEN + SELECT + var_x_active_start_time + INTO par_active_start_time; + END IF; + + IF (par_active_end_time IS NULL) THEN + SELECT + var_x_active_end_time + INTO par_active_end_time; + END IF + /* Check schedule (frequency and owner) parameters */; + SELECT + t.par_freq_interval, t.par_freq_subday_type, t.par_freq_subday_interval, t.par_freq_relative_interval, t.par_freq_recurrence_factor, t.par_active_start_date, t.par_active_start_time, + t.par_active_end_date, t.par_active_end_time, t.ReturnCode + FROM sys.babelfish_sp_verify_schedule(var_schedule_id + /* @schedule_id */, par_new_name + /* @name */, par_enabled + /* @enabled */, par_freq_type + /* @freq_type */, par_freq_interval + /* @freq_interval */, par_freq_subday_type + /* @freq_subday_type */, par_freq_subday_interval + /* @freq_subday_interval */, par_freq_relative_interval + /* @freq_relative_interval */, par_freq_recurrence_factor + /* @freq_recurrence_factor */, par_active_start_date + /* @active_start_date */, par_active_start_time + /* @active_start_time */, par_active_end_date + /* @active_end_date */, par_active_end_time + /* @active_end_time */, var_owner_sid) t + INTO par_freq_interval, par_freq_subday_type, par_freq_subday_interval, par_freq_relative_interval, par_freq_recurrence_factor, par_active_start_date, par_active_start_time, par_active_end_date, par_active_end_time, var_retval /* @owner_sid */; + + IF (var_retval <> 0) THEN + ReturnCode := (1); + RETURN; + END IF + /* Failure */ + /* Update the JobSchedule */; + UPDATE sys.sysschedules + SET name = par_new_name, enabled = par_enabled, freq_type = par_freq_type, freq_interval = par_freq_interval, freq_subday_type = par_freq_subday_type, freq_subday_interval = par_freq_subday_interval, freq_relative_interval = par_freq_relative_interval, freq_recurrence_factor = par_freq_recurrence_factor, active_start_date = par_active_start_date, active_end_date = par_active_end_date, active_start_time = par_active_start_time, active_end_time = par_active_end_time + /* date_modified = GETDATE(), */, version_number = version_number + 1 + WHERE (schedule_id = var_schedule_id); + SELECT + 0 + INTO var_retval + /* @@error */ + /* Update the job's version/last-modified information */; + UPDATE sys.sysjobs + SET version_number = version_number + 1 + /* date_modified = GETDATE() */ + WHERE (job_id = par_job_id); + ReturnCode := (var_retval); + RETURN + /* 0 means success */; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_update_jobstep ( + par_job_id integer = NULL::integer, + par_job_name varchar = NULL::character varying, + par_step_id integer = NULL::integer, + par_step_name varchar = NULL::character varying, + par_subsystem varchar = NULL::character varying, + par_command text = NULL::text, + par_additional_parameters text = NULL::text, + par_cmdexec_success_code integer = NULL::integer, + par_on_success_action smallint = NULL::smallint, + par_on_success_step_id integer = NULL::integer, + par_on_fail_action smallint = NULL::smallint, + par_on_fail_step_id integer = NULL::integer, + par_server varchar = NULL::character varying, + par_database_name varchar = NULL::character varying, + par_database_user_name varchar = NULL::character varying, + par_retry_attempts integer = NULL::integer, + par_retry_interval integer = NULL::integer, + par_os_run_priority integer = NULL::integer, + par_output_file_name varchar = NULL::character varying, + par_flags integer = NULL::integer, + par_proxy_id integer = NULL::integer, + par_proxy_name varchar = NULL::character varying, + out returncode integer +) +RETURNS integer AS +$body$ +DECLARE + var_retval INT; + var_os_run_priority_code INT; + var_step_id_as_char VARCHAR(10); + var_new_step_name VARCHAR(128); + var_x_step_name VARCHAR(128); + var_x_subsystem VARCHAR(40); + var_x_command TEXT; + var_x_flags INT; + var_x_cmdexec_success_code INT; + var_x_on_success_action SMALLINT; + var_x_on_success_step_id INT; + var_x_on_fail_action SMALLINT; + var_x_on_fail_step_id INT; + var_x_server VARCHAR(128); + var_x_database_name VARCHAR(128); + var_x_database_user_name VARCHAR(128); + var_x_retry_attempts INT; + var_x_retry_interval INT; + var_x_os_run_priority INT; + var_x_output_file_name VARCHAR(200); + var_x_proxy_id INT; + var_x_last_run_outcome SMALLINT; + var_x_last_run_duration INT; + var_x_last_run_retries INT; + var_x_last_run_date INT; + var_x_last_run_time INT; + var_new_proxy_id INT; + var_subsystem_id INT; + var_auto_proxy_name VARCHAR(128); + var_job_owner_sid CHAR(85); + var_step_uid CHAR(85); +BEGIN + SELECT NULL INTO var_new_proxy_id; + /* Remove any leading/trailing spaces from parameters */ + SELECT LTRIM(RTRIM(par_step_name)) INTO par_step_name; + SELECT LTRIM(RTRIM(par_subsystem)) INTO par_subsystem; + SELECT LTRIM(RTRIM(par_command)) INTO par_command; + SELECT LTRIM(RTRIM(par_server)) INTO par_server; + SELECT LTRIM(RTRIM(par_database_name)) INTO par_database_name; + SELECT LTRIM(RTRIM(par_database_user_name)) INTO par_database_user_name; + SELECT LTRIM(RTRIM(par_output_file_name)) INTO par_output_file_name; + SELECT LTRIM(RTRIM(par_proxy_name)) INTO par_proxy_name; + /* Make sure Dts is translated into new subsystem's name SSIS */ + /* IF (@subsystem IS NOT NULL AND UPPER(@subsystem collate SQL_Latin1_General_CP1_CS_AS) = N'DTS') */ + /* BEGIN */ + /* SET @subsystem = N'SSIS' */ + /* END */ + SELECT + t.par_job_name, t.par_job_id, t.par_owner_sid, t.ReturnCode + FROM sys.babelfish_sp_verify_job_identifiers('@job_name' + /* @name_of_name_parameter */, '@job_id' + /* @name_of_id_parameter */, par_job_name + /* @job_name */, par_job_id + /* @job_id */, 'TEST' + /* @sqlagent_starting_test */, var_job_owner_sid) + INTO par_job_name, par_job_id, var_job_owner_sid, var_retval + /* @owner_sid */; + + IF (var_retval <> 0) THEN + ReturnCode := (1); + RETURN; + END IF; + /* Failure */ + /* Check that the step exists */ + + IF (NOT EXISTS (SELECT + * + FROM sys.sysjobsteps + WHERE (job_id = par_job_id) AND (step_id = par_step_id))) THEN + SELECT + CAST (par_step_id AS VARCHAR(10)) + INTO var_step_id_as_char; + RAISE 'Error %, severity %, state % was raised. Message: %. Argument: %. Argument: %', '50000', 0, 0, 'The specified %s ("%s") does not exist.', '@step_id', var_step_id_as_char USING ERRCODE := '50000'; + ReturnCode := (1); + RETURN; + /* Failure */ + END IF; + /* Set the x_ (existing) variables */ + SELECT + step_name, subsystem, command, flags, cmdexec_success_code, on_success_action, on_success_step_id, on_fail_action, on_fail_step_id, server, database_name, database_user_name, retry_attempts, retry_interval, os_run_priority, output_file_name, proxy_id, last_run_outcome, last_run_duration, last_run_retries, last_run_date, last_run_time + INTO var_x_step_name, var_x_subsystem, var_x_command, var_x_flags, var_x_cmdexec_success_code, var_x_on_success_action, var_x_on_success_step_id, var_x_on_fail_action, var_x_on_fail_step_id, var_x_server, var_x_database_name, var_x_database_user_name, var_x_retry_attempts, var_x_retry_interval, var_x_os_run_priority, var_x_output_file_name, var_x_proxy_id, var_x_last_run_outcome, var_x_last_run_duration, var_x_last_run_retries, var_x_last_run_date, var_x_last_run_time + FROM sys.sysjobsteps + WHERE (job_id = par_job_id) AND (step_id = par_step_id); + + IF ((par_step_name IS NOT NULL) AND (par_step_name <> var_x_step_name)) THEN + SELECT + par_step_name + INTO var_new_step_name; + END IF; + /* Fill out the values for all non-supplied parameters from the existing values */ + + IF (par_step_name IS NULL) THEN + SELECT var_x_step_name INTO par_step_name; + END IF; + + IF (par_subsystem IS NULL) THEN + SELECT var_x_subsystem INTO par_subsystem; + END IF; + + IF (par_command IS NULL) THEN + SELECT var_x_command INTO par_command; + END IF; + + IF (par_flags IS NULL) THEN + SELECT var_x_flags INTO par_flags; + END IF; + + IF (par_cmdexec_success_code IS NULL) THEN + SELECT var_x_cmdexec_success_code INTO par_cmdexec_success_code; + END IF; + + IF (par_on_success_action IS NULL) THEN + SELECT var_x_on_success_action INTO par_on_success_action; + END IF; + + IF (par_on_success_step_id IS NULL) THEN + SELECT var_x_on_success_step_id INTO par_on_success_step_id; + END IF; + + IF (par_on_fail_action IS NULL) THEN + SELECT var_x_on_fail_action INTO par_on_fail_action; + END IF; + + IF (par_on_fail_step_id IS NULL) THEN + SELECT var_x_on_fail_step_id INTO par_on_fail_step_id; + END IF; + + IF (par_server IS NULL) THEN + SELECT var_x_server INTO par_server; + END IF; + + IF (par_database_name IS NULL) THEN + SELECT var_x_database_name INTO par_database_name; + END IF; + + IF (par_database_user_name IS NULL) THEN + SELECT var_x_database_user_name INTO par_database_user_name; + END IF; + + IF (par_retry_attempts IS NULL) THEN + SELECT var_x_retry_attempts INTO par_retry_attempts; + END IF; + + IF (par_retry_interval IS NULL) THEN + SELECT var_x_retry_interval INTO par_retry_interval; + END IF; + + IF (par_os_run_priority IS NULL) THEN + SELECT var_x_os_run_priority INTO par_os_run_priority; + END IF; + + IF (par_output_file_name IS NULL) THEN + SELECT var_x_output_file_name INTO par_output_file_name; + END IF; + + IF (par_proxy_id IS NULL) THEN + SELECT var_x_proxy_id INTO var_new_proxy_id; + END IF; + /* if an empty proxy_name is supplied the proxy is removed */ + + IF par_proxy_name = '' THEN + SELECT NULL INTO var_new_proxy_id; + END IF; + /* Turn [nullable] empty string parameters into NULLs */ + + IF (LOWER(par_command) = LOWER('')) THEN + SELECT NULL INTO par_command; + END IF; + + IF (par_server = '') THEN + SELECT NULL INTO par_server; + END IF; + + IF (par_database_name = '') THEN + SELECT NULL INTO par_database_name; + END IF; + + IF (par_database_user_name = '') THEN + SELECT NULL INTO par_database_user_name; + END IF; + + IF (LOWER(par_output_file_name) = LOWER('')) THEN + SELECT NULL INTO par_output_file_name; + END IF + /* Check new values */; + SELECT + t.par_database_name, t.par_database_user_name, t.ReturnCode + FROM sys.babelfish_sp_verify_jobstep(par_job_id, par_step_id, var_new_step_name, par_subsystem, par_command, par_server, par_on_success_action, par_on_success_step_id, par_on_fail_action, par_on_fail_step_id, par_os_run_priority, par_database_name, par_database_user_name, par_flags, par_output_file_name, var_new_proxy_id) t + INTO par_database_name, par_database_user_name, var_retval; + + IF (var_retval <> 0) THEN + ReturnCode := (1); + RETURN; + END IF + /* Failure */ + /* Update the job's version/last-modified information */; + UPDATE sys.sysjobs + SET version_number = version_number + 1 + /* date_modified = GETDATE() */ + WHERE (job_id = par_job_id) + /* Update the step */; + UPDATE sys.sysjobsteps + SET step_name = par_step_name, subsystem = par_subsystem, command = par_command, flags = par_flags, additional_parameters = par_additional_parameters, cmdexec_success_code = par_cmdexec_success_code, on_success_action = par_on_success_action, on_success_step_id = par_on_success_step_id, on_fail_action = par_on_fail_action, on_fail_step_id = par_on_fail_step_id, server = par_server, database_name = par_database_name, database_user_name = par_database_user_name, retry_attempts = par_retry_attempts, retry_interval = par_retry_interval, os_run_priority = par_os_run_priority, output_file_name = par_output_file_name, last_run_outcome = var_x_last_run_outcome, last_run_duration = var_x_last_run_duration, last_run_retries = var_x_last_run_retries, last_run_date = var_x_last_run_date, last_run_time = var_x_last_run_time, proxy_id = var_new_proxy_id + WHERE (job_id = par_job_id) AND (step_id = par_step_id); + + SELECT step_uid + FROM sys.sysjobsteps + WHERE job_id = par_job_id AND step_id = par_step_id + INTO var_step_uid; + + -- PERFORM sys.sp_jobstep_create_proc (var_step_uid); + + ReturnCode := (0); + RETURN + /* Success */; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_update_schedule ( + par_schedule_id integer = NULL::integer, + par_name varchar = NULL::character varying, + par_new_name varchar = NULL::character varying, + par_enabled smallint = NULL::smallint, + par_freq_type integer = NULL::integer, + par_freq_interval integer = NULL::integer, + par_freq_subday_type integer = NULL::integer, + par_freq_subday_interval integer = NULL::integer, + par_freq_relative_interval integer = NULL::integer, + par_freq_recurrence_factor integer = NULL::integer, + par_active_start_date integer = NULL::integer, + par_active_end_date integer = NULL::integer, + par_active_start_time integer = NULL::integer, + par_active_end_time integer = NULL::integer, + par_owner_login_name varchar = NULL::character varying, + par_automatic_post smallint = 1, + out returncode integer +) +RETURNS integer AS +$body$ +DECLARE + var_retval INT; + var_owner_sid CHAR(85); + var_cur_owner_sid CHAR(85); + var_x_name VARCHAR(128); + var_enable_only_used INT; + var_x_enabled SMALLINT; + var_x_freq_type INT; + var_x_freq_interval INT; + var_x_freq_subday_type INT; + var_x_freq_subday_interval INT; + var_x_freq_relative_interval INT; + var_x_freq_recurrence_factor INT; + var_x_active_start_date INT; + var_x_active_end_date INT; + var_x_active_start_time INT; + var_x_active_end_time INT; + var_schedule_uid CHAR(38); +BEGIN + /* Remove any leading/trailing spaces from parameters */ + SELECT + LTRIM(RTRIM(par_name)) + INTO par_name; + SELECT + LTRIM(RTRIM(par_new_name)) + INTO par_new_name; + SELECT + LTRIM(RTRIM(par_owner_login_name)) + INTO par_owner_login_name + /* Turn [nullable] empty string parameters into NULLs */; + + IF (par_new_name = '') THEN + SELECT + NULL + INTO par_new_name; + END IF + /* Check that we can uniquely identify the schedule. This only returns a schedule that is visible to this user */; + SELECT + t.par_schedule_name, t.par_schedule_id, t.par_owner_sid, t.par_orig_server_id, t.ReturnCode + FROM sys.babelfish_sp_verify_schedule_identifiers('@name' + /* @name_of_name_parameter */, '@schedule_id' + /* @name_of_id_parameter */, par_name + /* @schedule_name */, par_schedule_id + /* @schedule_id */, var_cur_owner_sid + /* @owner_sid */, NULL + /* @orig_server_id */, NULL) t + INTO par_name, par_schedule_id, var_cur_owner_sid, var_retval + /* @job_id_filter */; + + IF (var_retval <> 0) THEN + ReturnCode := (1); + RETURN; + END IF + /* Failure */ + /* Is @enable the only parameter used beside jobname and jobid? */; + + IF ((par_enabled IS NOT NULL) AND (par_new_name IS NULL) AND (par_freq_type IS NULL) AND (par_freq_interval IS NULL) AND (par_freq_subday_type IS NULL) AND (par_freq_subday_interval IS NULL) AND (par_freq_relative_interval IS NULL) AND (par_freq_recurrence_factor IS NULL) AND (par_active_start_date IS NULL) AND (par_active_end_date IS NULL) AND (par_active_start_time IS NULL) AND (par_active_end_time IS NULL) AND (par_owner_login_name IS NULL)) THEN + SELECT + 1 + INTO var_enable_only_used; + ELSE + SELECT + 0 + INTO var_enable_only_used; + END IF + /* If the param @owner_login_name is null or doesn't get resolved by SUSER_SID() set it to the current owner of the schedule */; + + IF (var_owner_sid IS NULL) THEN + SELECT + var_cur_owner_sid + INTO var_owner_sid; + END IF + /* Set the x_ (existing) variables */; + SELECT + name, enabled, freq_type, freq_interval, freq_subday_type, freq_subday_interval, freq_relative_interval, freq_recurrence_factor, active_start_date, active_end_date, active_start_time, active_end_time + INTO var_x_name, var_x_enabled, var_x_freq_type, var_x_freq_interval, var_x_freq_subday_type, var_x_freq_subday_interval, var_x_freq_relative_interval, var_x_freq_recurrence_factor, var_x_active_start_date, var_x_active_end_date, var_x_active_start_time, var_x_active_end_time + FROM sys.sysschedules + WHERE (schedule_id = par_schedule_id) + /* Fill out the values for all non-supplied parameters from the existing values */; + + IF (par_new_name IS NULL) THEN + SELECT + var_x_name + INTO par_new_name; + END IF; + + IF (par_enabled IS NULL) THEN + SELECT + var_x_enabled + INTO par_enabled; + END IF; + + IF (par_freq_type IS NULL) THEN + SELECT + var_x_freq_type + INTO par_freq_type; + END IF; + + IF (par_freq_interval IS NULL) THEN + SELECT + var_x_freq_interval + INTO par_freq_interval; + END IF; + + IF (par_freq_subday_type IS NULL) THEN + SELECT + var_x_freq_subday_type + INTO par_freq_subday_type; + END IF; + + IF (par_freq_subday_interval IS NULL) THEN + SELECT + var_x_freq_subday_interval + INTO par_freq_subday_interval; + END IF; + + IF (par_freq_relative_interval IS NULL) THEN + SELECT + var_x_freq_relative_interval + INTO par_freq_relative_interval; + END IF; + + IF (par_freq_recurrence_factor IS NULL) THEN + SELECT + var_x_freq_recurrence_factor + INTO par_freq_recurrence_factor; + END IF; + + IF (par_active_start_date IS NULL) THEN + SELECT + var_x_active_start_date + INTO par_active_start_date; + END IF; + + IF (par_active_end_date IS NULL) THEN + SELECT + var_x_active_end_date + INTO par_active_end_date; + END IF; + + IF (par_active_start_time IS NULL) THEN + SELECT + var_x_active_start_time + INTO par_active_start_time; + END IF; + + IF (par_active_end_time IS NULL) THEN + SELECT + var_x_active_end_time + INTO par_active_end_time; + END IF + /* Check schedule (frequency and owner) parameters */; + SELECT + t.par_freq_interval, t.par_freq_subday_type, t.par_freq_subday_interval, t.par_freq_relative_interval, t.par_freq_recurrence_factor, t.par_active_start_date, + t.par_active_start_time, t.par_active_end_date, t.par_active_end_time, t.ReturnCode + FROM sys.babelfish_sp_verify_schedule(par_schedule_id + /* @schedule_id */, par_new_name + /* @name */, par_enabled + /* @enabled */, par_freq_type + /* @freq_type */, par_freq_interval + /* @freq_interval */, par_freq_subday_type + /* @freq_subday_type */, par_freq_subday_interval + /* @freq_subday_interval */, par_freq_relative_interval + /* @freq_relative_interval */, par_freq_recurrence_factor + /* @freq_recurrence_factor */, par_active_start_date + /* @active_start_date */, par_active_start_time + /* @active_start_time */, par_active_end_date + /* @active_end_date */, par_active_end_time + /* @active_end_time */, var_owner_sid) t + INTO par_freq_interval, par_freq_subday_type, par_freq_subday_interval, par_freq_relative_interval, par_freq_recurrence_factor, par_active_start_date, par_active_start_time, par_active_end_date, par_active_end_time, var_retval /* @owner_sid */; + + IF (var_retval <> 0) THEN + ReturnCode := (1); + RETURN; + END IF + /* Failure */ + /* Update the sysschedules table */; + UPDATE sys.sysschedules + SET name = par_new_name, owner_sid = var_owner_sid, enabled = par_enabled, freq_type = par_freq_type, freq_interval = par_freq_interval, freq_subday_type = par_freq_subday_type, freq_subday_interval = par_freq_subday_interval, freq_relative_interval = par_freq_relative_interval, freq_recurrence_factor = par_freq_recurrence_factor, active_start_date = par_active_start_date, active_end_date = par_active_end_date, active_start_time = par_active_start_time, active_end_time = par_active_end_time + /* date_modified = GETDATE(), */, version_number = version_number + 1 + WHERE (schedule_id = par_schedule_id); + SELECT + 0 + INTO var_retval; + + ReturnCode := (var_retval); + RETURN + /* 0 means success */; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_verify_job ( + par_job_id integer, + par_name varchar, + par_enabled smallint, + par_start_step_id integer, + par_category_name varchar, + inout par_owner_sid char, + par_notify_level_eventlog integer, + inout par_notify_level_email integer, + inout par_notify_level_netsend integer, + inout par_notify_level_page integer, + par_notify_email_operator_name varchar, + par_notify_netsend_operator_name varchar, + par_notify_page_operator_name varchar, + par_delete_level integer, + inout par_category_id integer, + inout par_notify_email_operator_id integer, + inout par_notify_netsend_operator_id integer, + inout par_notify_page_operator_id integer, + inout par_originating_server varchar, + out returncode integer +) +RETURNS record AS +$body$ +DECLARE + var_job_type INT; + var_retval INT; + var_current_date INT; + var_res_valid_range VARCHAR(200); + var_max_step_id INT; + var_valid_range VARCHAR(50); +BEGIN + /* Remove any leading/trailing spaces from parameters */ + SELECT LTRIM(RTRIM(par_name)) INTO par_name; + SELECT LTRIM(RTRIM(par_category_name)) INTO par_category_name; + SELECT UPPER(LTRIM(RTRIM(par_originating_server))) INTO par_originating_server; + + IF ( + EXISTS ( + SELECT * + FROM sys.sysjobs AS job + WHERE (name = par_name) + /* AND (job_id <> ISNULL(@job_id, 0x911)))) -- When adding a new job @job_id is NULL */ + ) + ) + THEN /* Failure */ + RAISE 'The specified % ("%") already exists.', 'par_name', par_name USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + /* Check enabled state */ + IF (par_enabled <> 0) AND (par_enabled <> 1) THEN /* Failure */ + RAISE 'The specified "%" is invalid (valid values are: %).', 'par_enabled', '0, 1' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + /* Check start step */ + + IF (par_job_id IS NULL) THEN /* New job */ + IF (par_start_step_id <> 1) THEN /* Failure */ + RAISE 'The specified "%" is invalid (valid values are: %).', 'par_start_step_id', '1' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + ELSE /* Existing job */ + /* Get current maximum step id */ + SELECT COALESCE(MAX(step_id), 0) + INTO var_max_step_id + FROM sys.sysjobsteps + WHERE (job_id = par_job_id); + + IF (par_start_step_id < 1) OR (par_start_step_id > var_max_step_id + 1) THEN /* Failure */ + SELECT '1..' || CAST (var_max_step_id + 1 AS VARCHAR(1)) + INTO var_valid_range; + RAISE 'The specified "%" is invalid (valid values are: %).', 'par_start_step_id', var_valid_range USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + END IF; + + /* Get the category_id, handling any special-cases as appropriate */ + SELECT NULL INTO par_category_id; + + IF (par_category_name = '[DEFAULT]') /* User wants to revert to the default job category */ + THEN + SELECT + CASE COALESCE(var_job_type, 1) + WHEN 1 THEN 0 /* [Uncategorized (Local)] */ + WHEN 2 THEN 2 /* [Uncategorized (Multi-Server)] */ + END + INTO par_category_id; + ELSE + SELECT 0 INTO par_category_id; + END IF; + + returncode := (0); /* Success */ + RETURN; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_verify_job_date ( + par_date integer, + par_date_name varchar = 'date'::character varying, + out returncode integer +) +RETURNS integer AS +$body$ +BEGIN + /* Remove any leading/trailing spaces from parameters */ + SELECT LTRIM(RTRIM(par_date_name)) INTO par_date_name; + + /* Success */ + returncode := 0; + RETURN; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_verify_job_identifiers ( + par_name_of_name_parameter varchar, + par_name_of_id_parameter varchar, + inout par_job_name varchar, + inout par_job_id integer, + par_sqlagent_starting_test varchar = 'TEST'::character varying, + inout par_owner_sid char = NULL::bpchar, + out returncode integer +) +RETURNS record AS +$body$ +DECLARE + var_retval INT; + var_job_id_as_char VARCHAR(36); +BEGIN + /* Remove any leading/trailing spaces from parameters */ + SELECT LTRIM(RTRIM(par_name_of_name_parameter)) INTO par_name_of_name_parameter; + SELECT LTRIM(RTRIM(par_name_of_id_parameter)) INTO par_name_of_id_parameter; + SELECT LTRIM(RTRIM(par_job_name)) INTO par_job_name; + + IF (par_job_name = '') + THEN + SELECT NULL INTO par_job_name; + END IF; + + IF ((par_job_name IS NULL) AND (par_job_id IS NULL)) OR ((par_job_name IS NOT NULL) AND (par_job_id IS NOT NULL)) + THEN /* Failure */ + RAISE 'Supply either % or % to identify the job.', par_name_of_id_parameter, par_name_of_name_parameter USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + /* Check job id */ + IF (par_job_id IS NOT NULL) + THEN + SELECT name + , owner_sid + INTO par_job_name + , par_owner_sid + FROM sys.sysjobs + WHERE (job_id = par_job_id); + + /* the view would take care of all the permissions issues. */ + IF (par_job_name IS NULL) + THEN /* Failure */ + SELECT CAST (par_job_id AS VARCHAR(36)) + INTO var_job_id_as_char; + + RAISE 'The specified % ("%") does not exist.', 'job_id', var_job_id_as_char USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + ELSE + /* Check job name */ + IF (par_job_name IS NOT NULL) + THEN + /* Check if the job name is ambiguous */ + IF (SELECT COUNT(*) FROM sys.sysjobs WHERE name = par_job_name) > 1 + THEN /* Failure */ + RAISE 'There are two or more jobs named "%". Specify % instead of % to uniquely identify the job.', par_job_name, par_name_of_id_parameter, par_name_of_name_parameter USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + /* The name is not ambiguous, so get the corresponding job_id (if the job exists) */ + SELECT job_id + , owner_sid + INTO par_job_id + , par_owner_sid + FROM sys.sysjobs + WHERE (name = par_job_name); + + /* the view would take care of all the permissions issues. */ + IF (par_job_id IS NULL) + THEN /* Failure */ + RAISE 'The specified % ("%") does not exist.', 'job_name', par_job_name USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + END IF; + END IF; + + /* Success */ + returncode := 0; + RETURN; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_verify_job_time ( + par_time integer, + par_time_name varchar = 'time'::character varying, + out returncode integer +) +RETURNS integer AS +$body$ +DECLARE + var_hour INT; + var_minute INT; + var_second INT; +BEGIN + /* Remove any leading/trailing spaces from parameters */ + SELECT LTRIM(RTRIM(par_time_name)) INTO par_time_name; + + IF ((par_time < 0) OR (par_time > 235959)) + THEN + RAISE 'The specified "%" is invalid (valid values are: %).', par_time_name, '000000..235959' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + SELECT (par_time / 10000) INTO var_hour; + SELECT (par_time % 10000) / 100 INTO var_minute; + SELECT (par_time % 100) INTO var_second; + + /* Check hour range */ + IF (var_hour > 23) THEN + RAISE 'The "%" supplied has an invalid %.', par_time_name, 'hour' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + /* Check minute range */ + IF (var_minute > 59) THEN + RAISE 'The "%" supplied has an invalid %.', par_time_name, 'minute' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + /* Check second range */ + IF (var_second > 59) THEN + RAISE 'The "%" supplied has an invalid %.', par_time_name, 'second' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + returncode := 0; + RETURN; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_verify_jobstep ( + par_job_id integer, + par_step_id integer, + par_step_name varchar, + par_subsystem varchar, + par_command text, + par_server varchar, + par_on_success_action smallint, + par_on_success_step_id integer, + par_on_fail_action smallint, + par_on_fail_step_id integer, + par_os_run_priority integer, + par_flags integer, + par_output_file_name varchar, + par_proxy_id integer, + out returncode integer +) +AS +$body$ +DECLARE + var_max_step_id INT; + var_retval INT; + var_valid_values VARCHAR(50); + var_database_name_temp VARCHAR(258); + var_database_user_name_temp VARCHAR(256); + var_temp_command TEXT; + var_iPos INT; + var_create_count INT; + var_destroy_count INT; + var_is_olap_subsystem SMALLINT; + var_owner_sid CHAR(85); + var_owner_name VARCHAR(128); +BEGIN + /* Remove any leading/trailing spaces from parameters */ + SELECT LTRIM(RTRIM(par_subsystem)) INTO par_subsystem; + SELECT LTRIM(RTRIM(par_server)) INTO par_server; + SELECT LTRIM(RTRIM(par_output_file_name)) INTO par_output_file_name; + + /* Get current maximum step id */ + SELECT COALESCE(MAX(step_id), 0) + INTO var_max_step_id + FROM sys.sysjobsteps + WHERE (job_id = par_job_id); + + /* Check step id */ + IF (par_step_id < 1) OR (par_step_id > var_max_step_id + 1) /* Failure */ + THEN + SELECT '1..' || CAST (var_max_step_id + 1 AS VARCHAR(1)) INTO var_valid_values; + RAISE 'The specified "%" is invalid (valid values are: %).', '@step_id', var_valid_values USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + /* Check step name */ + IF ( + EXISTS ( + SELECT * + FROM sys.sysjobsteps + WHERE (job_id = par_job_id) AND (step_name = par_step_name) + ) + ) + THEN /* Failure */ + RAISE 'The specified % ("%") already exists.', 'step_name', par_step_name USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + /* Check on-success action/step */ + IF (par_on_success_action <> 1) /* Quit Qith Success */ + AND (par_on_success_action <> 2) /* Quit Qith Failure */ + AND (par_on_success_action <> 3) /* Goto Next Step */ + AND (par_on_success_action <> 4) /* Goto Step */ + THEN /* Failure */ + RAISE 'The specified "%" is invalid (valid values are: %).', 'on_success_action', '1, 2, 3, 4' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + IF (par_on_success_action = 4) AND ((par_on_success_step_id < 1) OR (par_on_success_step_id = par_step_id)) + THEN /* Failure */ + RAISE 'The specified "%" is invalid (valid values are greater than 0 but excluding %ld).', 'on_success_step', par_step_id USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + /* Check on-fail action/step */ + IF (par_on_fail_action <> 1) /* Quit With Success */ + AND (par_on_fail_action <> 2) /* Quit With Failure */ + AND (par_on_fail_action <> 3) /* Goto Next Step */ + AND (par_on_fail_action <> 4) /* Goto Step */ + THEN /* Failure */ + RAISE 'The specified "%" is invalid (valid values are: %).', 'on_failure_action', '1, 2, 3, 4' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + IF (par_on_fail_action = 4) AND ((par_on_fail_step_id < 1) OR (par_on_fail_step_id = par_step_id)) + THEN /* Failure */ + RAISE 'The specified "%" is invalid (valid values are greater than 0 but excluding %).', 'on_failure_step', par_step_id USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + /* Warn the user about forward references */ + IF ((par_on_success_action = 4) AND (par_on_success_step_id > var_max_step_id)) + THEN + RAISE 'Warning: Non-existent step referenced by %.', 'on_success_step_id' USING ERRCODE := '50000'; + END IF; + + IF ((par_on_fail_action = 4) AND (par_on_fail_step_id > var_max_step_id)) + THEN + RAISE 'Warning: Non-existent step referenced by %.', '@on_fail_step_id' USING ERRCODE := '50000'; + END IF; + + /* Check run priority: must be a valid value to pass to SetThreadPriority: */ + /* [-15 = IDLE, -1 = BELOW_NORMAL, 0 = NORMAL, 1 = ABOVE_NORMAL, 15 = TIME_CRITICAL] */ + IF (par_os_run_priority NOT IN (- 15, - 1, 0, 1, 15)) + THEN /* Failure */ + RAISE 'The specified "%" is invalid (valid values are: %).', '@os_run_priority', '-15, -1, 0, 1, 15' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + /* Check flags */ + IF ((par_flags < 0) OR (par_flags > 114)) THEN /* Failure */ + RAISE 'The specified "%" is invalid (valid values are: %).', '@flags', '0..114' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + IF (LOWER(UPPER(par_subsystem)) <> LOWER('TSQL')) THEN /* Failure */ + RAISE 'The specified "%" is invalid (valid values are: %).', '@subsystem', 'TSQL' USING ERRCODE := '50000'; + returncode := (1); + RETURN; + END IF; + + /* Success */ + returncode := 0; + RETURN; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_verify_schedule ( + par_schedule_id integer, + par_name varchar, + par_enabled smallint, + par_freq_type integer, + inout par_freq_interval integer, + inout par_freq_subday_type integer, + inout par_freq_subday_interval integer, + inout par_freq_relative_interval integer, + inout par_freq_recurrence_factor integer, + inout par_active_start_date integer, + inout par_active_start_time integer, + inout par_active_end_date integer, + inout par_active_end_time integer, + par_owner_sid char, + out returncode integer +) +RETURNS record AS +$body$ +DECLARE + var_return_code INT; + var_isAdmin INT; +BEGIN + /* Remove any leading/trailing spaces from parameters */ + SELECT LTRIM(RTRIM(par_name)) INTO par_name; + + /* Make sure that NULL input/output parameters - if NULL - are initialized to 0 */ + SELECT COALESCE(par_freq_interval, 0) INTO par_freq_interval; + SELECT COALESCE(par_freq_subday_type, 0) INTO par_freq_subday_type; + SELECT COALESCE(par_freq_subday_interval, 0) INTO par_freq_subday_interval; + SELECT COALESCE(par_freq_relative_interval, 0) INTO par_freq_relative_interval; + SELECT COALESCE(par_freq_recurrence_factor, 0) INTO par_freq_recurrence_factor; + SELECT COALESCE(par_active_start_date, 0) INTO par_active_start_date; + SELECT COALESCE(par_active_start_time, 0) INTO par_active_start_time; + SELECT COALESCE(par_active_end_date, 0) INTO par_active_end_date; + SELECT COALESCE(par_active_end_time, 0) INTO par_active_end_time; + + /* Verify name (we disallow schedules called 'ALL' since this has special meaning in sp_delete_jobschedules) */ + SELECT 0 INTO var_isAdmin; + + IF ( + EXISTS ( + SELECT * + FROM sys.sysschedules + WHERE (name = par_name) + ) + ) + THEN /* Failure */ + RAISE 'The specified % ("%") already exists.', 'par_name', par_name USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + IF (UPPER(par_name) = 'ALL') + THEN /* Failure */ + RAISE 'The specified "%" is invalid.', 'name' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + /* Verify enabled state */ + IF (par_enabled <> 0) AND (par_enabled <> 1) + THEN /* Failure */ + RAISE 'The specified "%" is invalid (valid values are: %).', '@enabled', '0, 1' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + /* Verify frequency type */ + IF (par_freq_type = 2) /* OnDemand is no longer supported */ + THEN /* Failure */ + RAISE 'Frequency Type 0x2 (OnDemand) is no longer supported.' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + IF (par_freq_type NOT IN (1, 4, 8, 16, 32, 64, 128)) + THEN /* Failure */ + RAISE 'The specified "%" is invalid (valid values are: %).', 'freq_type', '1, 4, 8, 16, 32, 64, 128' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + /* Verify frequency sub-day type */ + IF (par_freq_subday_type <> 0) AND (par_freq_subday_type NOT IN (1, 2, 4, 8)) + THEN /* Failure */ + RAISE 'The specified "%" is invalid (valid values are: %).', 'freq_subday_type', '1, 2, 4, 8' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + /* Default active start/end date/times (if not supplied, or supplied as NULLs or 0) */ + IF (par_active_start_date = 0) + THEN + SELECT date_part('year', NOW()::TIMESTAMP) * 10000 + date_part('month', NOW()::TIMESTAMP) * 100 + date_part('day', NOW()::TIMESTAMP) + INTO par_active_start_date; + END IF; + + /* This is an ISO format: "yyyymmdd" */ + IF (par_active_end_date = 0) + THEN + /* December 31st 9999 */ + SELECT 99991231 INTO par_active_end_date; + END IF; + + IF (par_active_start_time = 0) + THEN + /* 12:00:00 am */ + SELECT 000000 INTO par_active_start_time; + END IF; + + IF (par_active_end_time = 0) + THEN + /* 11:59:59 pm */ + SELECT 235959 INTO par_active_end_time; + END IF; + + /* Verify active start/end dates */ + IF (par_active_end_date = 0) + THEN + SELECT 99991231 INTO par_active_end_date; + END IF; + + SELECT t.returncode + FROM sys.babelfish_sp_verify_job_date(par_active_end_date, 'active_end_date') t + INTO var_return_code; + + IF (var_return_code <> 0) + THEN /* Failure */ + returncode := 1; + RETURN; + END IF; + + SELECT t.returncode + FROM sys.babelfish_sp_verify_job_date(par_active_start_date, '@active_start_date') t + INTO var_return_code; + + IF (var_return_code <> 0) + THEN /* Failure */ + returncode := 1; + RETURN; + END IF; + + IF (par_active_end_date < par_active_start_date) + THEN /* Failure */ + RAISE '% cannot be before %.', 'active_end_date', 'active_start_date' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + SELECT t.returncode + FROM sys.babelfish_sp_verify_job_time(par_active_end_time, '@active_end_time') t + INTO var_return_code; + + IF (var_return_code <> 0) + THEN /* Failure */ + returncode := 1; + RETURN; + END IF; + + SELECT t.returncode + FROM sys.babelfish_sp_verify_job_time(par_active_start_time, '@active_start_time') t + INTO var_return_code; + + IF (var_return_code <> 0) + THEN /* Failure */ + returncode := 1; + RETURN; + END IF; + + IF (par_active_start_time = par_active_end_time AND (par_freq_subday_type IN (2, 4, 8))) + THEN /* Failure */ + RAISE 'The specified "%" is invalid (valid values are: %).', 'active_end_time', 'before or after active_start_time' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + IF ((par_freq_type = 1) /* FREQTYPE_ONETIME */ + OR (par_freq_type = 64) /* FREQTYPE_AUTOSTART */ + OR (par_freq_type = 128)) /* FREQTYPE_ONIDLE */ + THEN /* Set standard defaults for non-required parameters */ + SELECT 0 INTO par_freq_interval; + SELECT 0 INTO par_freq_subday_type; + SELECT 0 INTO par_freq_subday_interval; + SELECT 0 INTO par_freq_relative_interval; + SELECT 0 INTO par_freq_recurrence_factor; + /* Success */ + returncode := 0; + RETURN; + END IF; + + IF (par_freq_subday_type = 0) /* FREQSUBTYPE_ONCE */ + THEN + SELECT 1 INTO par_freq_subday_type; + END IF; + + IF ((par_freq_subday_type <> 1) /* FREQSUBTYPE_ONCE */ + AND (par_freq_subday_type <> 2) /* FREQSUBTYPE_SECOND */ + AND (par_freq_subday_type <> 4) /* FREQSUBTYPE_MINUTE */ + AND (par_freq_subday_type <> 8)) /* FREQSUBTYPE_HOUR */ + THEN /* Failure */ + RAISE 'The schedule for this job is invalid (reason: The specified @freq_subday_type is invalid (valid values are: 0x1, 0x2, 0x4, 0x8).).' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + IF ((par_freq_subday_type <> 1) AND (par_freq_subday_interval < 1)) /* FREQSUBTYPE_ONCE and less than 1 interval */ + OR ((par_freq_subday_type = 2) AND (par_freq_subday_interval < 10)) /* FREQSUBTYPE_SECOND and less than 10 seconds (see MIN_SCHEDULE_GRANULARITY in SqlAgent source code) */ + THEN /* Failure */ + RAISE 'The schedule for this job is invalid (reason: The specified @freq_subday_interval is invalid).' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + IF (par_freq_type = 4) /* FREQTYPE_DAILY */ + THEN + SELECT 0 INTO par_freq_recurrence_factor; + + IF (par_freq_interval < 1) THEN /* Failure */ + RAISE 'The schedule for this job is invalid (reason: @freq_interval must be at least 1 for a daily job.).' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + END IF; + + IF (par_freq_type = 8) /* FREQTYPE_WEEKLY */ + THEN + IF (par_freq_interval < 1) OR (par_freq_interval > 127) /* (2^7)-1 [freq_interval is a bitmap (Sun=1..Sat=64)] */ + THEN /* Failure */ + RAISE 'The schedule for this job is invalid (reason: @freq_interval must be a valid day of the week bitmask [Sunday = 1 .. Saturday = 64] for a weekly job.).' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + END IF; + + IF (par_freq_type = 16) /* FREQTYPE_MONTHLY */ + THEN + IF (par_freq_interval < 1) OR (par_freq_interval > 31) + THEN /* Failure */ + RAISE 'The schedule for this job is invalid (reason: @freq_interval must be between 1 and 31 for a monthly job.).' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + END IF; + + IF (par_freq_type = 32) /* FREQTYPE_MONTHLYRELATIVE */ + THEN + IF (par_freq_relative_interval <> 1) /* RELINT_1ST */ + AND (par_freq_relative_interval <> 2) /* RELINT_2ND */ + AND (par_freq_relative_interval <> 4) /* RELINT_3RD */ + AND (par_freq_relative_interval <> 8) /* RELINT_4TH */ + AND (par_freq_relative_interval <> 16) /* RELINT_LAST */ + THEN /* Failure */ + RAISE 'The schedule for this job is invalid (reason: @freq_relative_interval must be one of 1st (0x1), 2nd (0x2), 3rd [0x4], 4th (0x8) or Last (0x10).).' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + END IF; + + IF (par_freq_type = 32) /* FREQTYPE_MONTHLYRELATIVE */ + THEN + IF (par_freq_interval <> 1) /* RELATIVE_SUN */ + AND (par_freq_interval <> 2) /* RELATIVE_MON */ + AND (par_freq_interval <> 3) /* RELATIVE_TUE */ + AND (par_freq_interval <> 4) /* RELATIVE_WED */ + AND (par_freq_interval <> 5) /* RELATIVE_THU */ + AND (par_freq_interval <> 6) /* RELATIVE_FRI */ + AND (par_freq_interval <> 7) /* RELATIVE_SAT */ + AND (par_freq_interval <> 8) /* RELATIVE_DAY */ + AND (par_freq_interval <> 9) /* RELATIVE_WEEKDAY */ + AND (par_freq_interval <> 10) /* RELATIVE_WEEKENDDAY */ + THEN /* Failure */ + RAISE 'The schedule for this job is invalid (reason: @freq_interval must be between 1 and 10 (1 = Sunday .. 7 = Saturday, 8 = Day, 9 = Weekday, 10 = Weekend-day) for a monthly-relative job.).' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + END IF; + + IF ((par_freq_type = 8) /* FREQTYPE_WEEKLY */ + OR (par_freq_type = 16) /* FREQTYPE_MONTHLY */ + OR (par_freq_type = 32)) /* FREQTYPE_MONTHLYRELATIVE */ + AND (par_freq_recurrence_factor < 1) + THEN /* Failure */ + RAISE 'The schedule for this job is invalid (reason: @freq_recurrence_factor must be at least 1.).' USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + /* Success */ + returncode := 0; + RETURN; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_verify_schedule_identifiers ( + par_name_of_name_parameter varchar, + par_name_of_id_parameter varchar, + inout par_schedule_name varchar, + inout par_schedule_id integer, + inout par_owner_sid char, + inout par_orig_server_id integer, + par_job_id_filter integer = NULL::integer, + out returncode integer +) +AS +$body$ +DECLARE + var_retval INT; + var_schedule_id_as_char VARCHAR(36); + var_sch_name_count INT; +BEGIN + /* Remove any leading/trailing spaces from parameters */ + SELECT LTRIM(RTRIM(par_name_of_name_parameter)) INTO par_name_of_name_parameter; + SELECT LTRIM(RTRIM(par_name_of_id_parameter)) INTO par_name_of_id_parameter; + SELECT LTRIM(RTRIM(par_schedule_name)) INTO par_schedule_name; + SELECT 0 INTO var_sch_name_count; + + IF (par_schedule_name = '') + THEN + SELECT NULL INTO par_schedule_name; + END IF; + + IF ((par_schedule_name IS NULL) AND (par_schedule_id IS NULL)) OR ((par_schedule_name IS NOT NULL) AND (par_schedule_id IS NOT NULL)) + THEN /* Failure */ + RAISE 'Supply either % or % to identify the schedule.', par_name_of_id_parameter, par_name_of_name_parameter USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + /* Check schedule id */ + IF (par_schedule_id IS NOT NULL) + THEN + /* Look at all schedules */ + SELECT name + , owner_sid + , originating_server_id + INTO par_schedule_name + , par_owner_sid + , par_orig_server_id + FROM sys.sysschedules + WHERE (schedule_id = par_schedule_id); + + IF (par_schedule_name IS NULL) + THEN /* Failure */ + SELECT CAST (par_schedule_id AS VARCHAR(36)) + INTO var_schedule_id_as_char; + + RAISE 'The specified % ("%") does not exist.', 'schedule_id', var_schedule_id_as_char USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + ELSE + IF (par_schedule_name IS NOT NULL) + THEN + /* Check if the schedule name is ambiguous */ + IF (SELECT COUNT(*) FROM sys.sysschedules WHERE name = par_schedule_name) > 1 + THEN /* Failure */ + RAISE 'There are two or more sysschedules named "%". Specify % instead of % to uniquely identify the sysschedules.', par_job_name, par_name_of_id_parameter, par_name_of_name_parameter USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + + /* The name is not ambiguous, so get the corresponding job_id (if the job exists) */ + SELECT schedule_id + , owner_sid + INTO par_schedule_id, par_owner_sid + FROM sys.sysschedules + WHERE (name = par_schedule_name); + + /* the view would take care of all the permissions issues. */ + IF (par_schedule_id IS NULL) + THEN /* Failure */ + RAISE 'The specified % ("%") does not exist.', 'par_schedule_name', par_schedule_name USING ERRCODE := '50000'; + returncode := 1; + RETURN; + END IF; + END IF; + END IF; + + /* Success */ + returncode := 0; + RETURN; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_xml_preparedocument(IN XmlDocument TEXT,OUT DocHandle BIGINT) +AS +$BODY$ +DECLARE + XmlDocument$data XML; +BEGIN + /*Create temporary structure for xmldocument saving*/ + CREATE TEMPORARY SEQUENCE IF NOT EXISTS sys$seq_openmxl_id MINVALUE 1 MAXVALUE 9223372036854775807 START WITH 1 INCREMENT BY 1 CACHE 5; + + CREATE TEMPORARY TABLE IF NOT EXISTS sys$openxml + (DocID BigInt NOT NULL DEFAULT NEXTVAL('sys$seq_openmxl_id'), + XmlData XML not NULL, + CONSTRAINT pk_sys$doc_id PRIMARY KEY(DocID) + ) ON COMMIT PRESERVE ROWS; + + IF xml_is_well_formed(XmlDocument) THEN + XmlDocument$data := XmlDocument::XML; + ELSE + RAISE EXCEPTION '%','The XML parse error occurred'; + END IF; + + INSERT INTO sys$openxml(XmlData) + VALUES (XmlDocument$data) + RETURNING DocID INTO DocHandle; +END; +$BODY$ +LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION sys.babelfish_sp_xml_removedocument(IN DocHandle BIGINT) RETURNS VOID +AS +$BODY$ +DECLARE + lt_error_text TEXT := 'Could not find prepared statement with handle '||CASE + WHEN DocHandle IS NULL THEN 'null' + ELSE DocHandle::TEXT + END; +BEGIN + DELETE FROM sys$openxml t + WHERE t.DocID = DocHandle; + + IF NOT FOUND THEN + RAISE EXCEPTION '%', lt_error_text; + END IF; + + EXCEPTION + WHEN SQLSTATE '42P01' THEN + RAISE EXCEPTION '%',lt_error_text; +END; +$BODY$ +LANGUAGE plpgsql; + +/* *********************************************** +EXTENSION PACK function STRPOS3(x) +schema sys +**************************************************/ +create or replace function sys.babelfish_STRPOS3(p_str text, p_substr text, p_loc int)returns int +AS +$body$ +DECLARE + v_loc int := case when p_loc > 0 then p_loc else 1 end; + v_cnt int := length(p_str) - v_loc + 1; +BEGIN +/*************************************************************** +EXTENSION PACK function STRPOS3(x) +***************************************************************/ + if v_cnt > 0 then + return case when 0!= strpos(substr(p_str, v_loc, v_cnt), p_substr) + then strpos(substr(p_str, v_loc, v_cnt), p_substr) + v_loc - 1 + else strpos(substr(p_str, v_loc, v_cnt), p_substr) + end; + else + return 0; + end if; +END; +$body$ +language plpgsql; + +CREATE OR REPLACE FUNCTION sys.babelfish_tomsbit(in_str NUMERIC) +RETURNS SMALLINT +AS +$BODY$ +BEGIN + CASE + WHEN in_str < 0 OR in_str > 0 THEN RETURN 1; + ELSE RETURN 0; + END CASE; +END; +$BODY$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_tomsbit(in_str VARCHAR) +RETURNS SMALLINT +AS +$BODY$ +BEGIN + CASE + WHEN LOWER(in_str) = 'true' OR in_str = '1' THEN RETURN 1; + WHEN LOWER(in_str) = 'false' OR in_str = '0' THEN RETURN 0; + ELSE RETURN 0; + END CASE; +END; +$BODY$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_try_conv_date_to_string(IN p_datatype TEXT, + IN p_dateval DATE, + IN p_style NUMERIC DEFAULT 20) +RETURNS TEXT +AS +$BODY$ +BEGIN + RETURN sys.babelfish_conv_date_to_string(p_datatype, + p_dateval, + p_style); +EXCEPTION + WHEN OTHERS THEN + RETURN NULL; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_try_conv_datetime_to_string(IN p_datatype TEXT, + IN p_src_datatype TEXT, + IN p_datetimeval TIMESTAMP WITHOUT TIME ZONE, + IN p_style NUMERIC DEFAULT -1) +RETURNS TEXT +AS +$BODY$ +BEGIN + RETURN sys.babelfish_conv_datetime_to_string(p_datatype, + p_src_datatype, + p_datetimeval, + p_style); +EXCEPTION + WHEN OTHERS THEN + RETURN NULL; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_try_conv_string_to_date(IN p_datestring TEXT, + IN p_style NUMERIC DEFAULT 0) +RETURNS DATE +AS +$BODY$ +BEGIN + RETURN sys.babelfish_conv_string_to_date(p_datestring, + p_style); +EXCEPTION + WHEN OTHERS THEN + RETURN NULL; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_try_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$ +BEGIN + RETURN sys.babelfish_conv_string_to_datetime(p_datatype, + p_datetimestring , + p_style); +EXCEPTION + WHEN OTHERS THEN + RETURN NULL; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_try_conv_string_to_time(IN p_datatype TEXT, + IN p_timestring TEXT, + IN p_style NUMERIC DEFAULT 0) +RETURNS TIME WITHOUT TIME ZONE +AS +$BODY$ +BEGIN + RETURN sys.babelfish_conv_string_to_time(p_datatype, + p_timestring, + p_style); +EXCEPTION + WHEN OTHERS THEN + RETURN NULL; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_try_conv_time_to_string(IN p_datatype TEXT, + IN p_src_datatype TEXT, + IN p_timeval TIME WITHOUT TIME ZONE, + IN p_style NUMERIC DEFAULT 25) +RETURNS TEXT +AS +$BODY$ +BEGIN + RETURN sys.babelfish_conv_time_to_string(p_datatype, + p_src_datatype, + p_timeval, + p_style); +EXCEPTION + WHEN OTHERS THEN + RETURN NULL; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + +-- convertion to date +CREATE OR REPLACE FUNCTION sys.babelfish_conv_helper_to_date(IN arg TEXT, + IN try BOOL, + IN p_style NUMERIC DEFAULT 0) +RETURNS DATE +AS +$BODY$ +BEGIN + IF try THEN + RETURN sys.babelfish_try_conv_string_to_date(arg, p_style); + ELSE + RETURN sys.babelfish_conv_string_to_date(arg, p_style); + END IF; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE; + +CREATE OR REPLACE FUNCTION sys.babelfish_conv_helper_to_date(IN arg anyelement, + IN try BOOL, + IN p_style NUMERIC DEFAULT 0) +RETURNS DATE +AS +$BODY$ +BEGIN + IF try THEN + RETURN sys.babelfish_try_conv_to_date(arg); + ELSE + RETURN CAST(arg AS DATE); + END IF; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE; + +CREATE OR REPLACE FUNCTION sys.babelfish_try_conv_to_date(IN arg anyelement) +RETURNS DATE +AS +$BODY$ +BEGIN + RETURN CAST(arg AS DATE); + EXCEPTION + WHEN OTHERS THEN + RETURN NULL; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE; + +-- convertion to time +CREATE OR REPLACE FUNCTION sys.babelfish_conv_helper_to_time(IN arg TEXT, + IN try BOOL, + IN p_style NUMERIC DEFAULT 0) +RETURNS TIME +AS +$BODY$ +BEGIN + IF try THEN + RETURN sys.babelfish_try_conv_string_to_time('TIME', arg, p_style); + ELSE + RETURN sys.babelfish_conv_string_to_time('TIME', arg, p_style); + END IF; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE; + +CREATE OR REPLACE FUNCTION sys.babelfish_conv_helper_to_time(IN arg anyelement, + IN try BOOL, + IN p_style NUMERIC DEFAULT 0) +RETURNS TIME +AS +$BODY$ +BEGIN + IF try THEN + RETURN sys.babelfish_try_conv_to_time(arg); + ELSE + RETURN CAST(arg AS TIME); + END IF; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE; + +CREATE OR REPLACE FUNCTION sys.babelfish_try_conv_to_time(IN arg anyelement) +RETURNS TIME +AS +$BODY$ +BEGIN + RETURN CAST(arg AS TIME); + EXCEPTION + WHEN OTHERS THEN + RETURN NULL; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE; + +-- convertion to datetime +CREATE OR REPLACE FUNCTION sys.babelfish_conv_helper_to_datetime(IN arg TEXT, + IN try BOOL, + IN p_style NUMERIC DEFAULT 0) +RETURNS TIMESTAMP +AS +$BODY$ +BEGIN + IF try THEN + RETURN sys.babelfish_try_conv_string_to_datetime('DATETIME', arg, p_style); + ELSE + RETURN sys.babelfish_conv_string_to_datetime('DATETIME', arg, p_style); + END IF; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE; + +CREATE OR REPLACE FUNCTION sys.babelfish_conv_helper_to_datetime(IN arg anyelement, + IN try BOOL, + IN p_style NUMERIC DEFAULT 0) +RETURNS TIMESTAMP +AS +$BODY$ +BEGIN + IF try THEN + RETURN sys.babelfish_try_conv_to_datetime(arg); + ELSE + RETURN CAST(arg AS TIMESTAMP); + END IF; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE; + + +CREATE OR REPLACE FUNCTION sys.babelfish_try_conv_to_datetime(IN arg anyelement) +RETURNS TIMESTAMP +AS +$BODY$ +BEGIN + RETURN CAST(arg AS TIMESTAMP); + EXCEPTION + WHEN OTHERS THEN + RETURN NULL; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE; + +-- convertion to varchar +CREATE OR REPLACE FUNCTION sys.babelfish_conv_helper_to_varchar(IN typename TEXT, + IN arg TEXT, + IN try BOOL, + IN p_style NUMERIC DEFAULT 0) +RETURNS sys.VARCHAR +AS +$BODY$ +BEGIN + IF try THEN + RETURN sys.babelfish_try_conv_to_varchar(typename, arg, p_style); + ELSE + RETURN sys.babelfish_conv_to_varchar(typename, arg, p_style); + END IF; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE; + +CREATE OR REPLACE FUNCTION sys.babelfish_conv_helper_to_varchar(IN typename TEXT, + IN arg ANYELEMENT, + IN try BOOL, + IN p_style NUMERIC DEFAULT 0) +RETURNS sys.VARCHAR +AS +$BODY$ +BEGIN + IF try THEN + RETURN sys.babelfish_try_conv_to_varchar(typename, arg, p_style); + ELSE + RETURN sys.babelfish_conv_to_varchar(typename, arg, p_style); + END IF; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE; + +CREATE OR REPLACE FUNCTION sys.babelfish_conv_to_varchar(IN typename TEXT, + IN arg TEXT, + IN p_style NUMERIC DEFAULT 0) +RETURNS sys.VARCHAR +AS +$BODY$ +BEGIN + RETURN CAST(arg AS sys.VARCHAR); +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE; + +CREATE OR REPLACE FUNCTION sys.babelfish_conv_to_varchar(IN typename TEXT, + IN arg anyelement, + IN p_style NUMERIC DEFAULT 0) +RETURNS sys.VARCHAR +AS +$BODY$ +BEGIN + CASE pg_typeof(arg) + WHEN 'date'::regtype THEN + RETURN sys.babelfish_try_conv_date_to_string(typename, arg, p_style); + WHEN 'time'::regtype THEN + RETURN sys.babelfish_try_conv_time_to_string(typename, 'TIME', arg, p_style); + WHEN 'sys.datetime'::regtype THEN + RETURN sys.babelfish_try_conv_datetime_to_string(typename, 'DATETIME', arg::timestamp, p_style); + WHEN 'float'::regtype THEN + RETURN sys.babelfish_try_conv_float_to_string(typename, arg, p_style); + WHEN 'sys.money'::regtype THEN + RETURN sys.babelfish_try_conv_money_to_string(typename, arg::numeric(19,4)::pg_catalog.money, p_style); + ELSE + RETURN CAST(arg AS sys.VARCHAR); + END CASE; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE; + +CREATE OR REPLACE FUNCTION sys.babelfish_try_conv_to_varchar(IN typename TEXT, + IN arg TEXT, + IN p_style NUMERIC DEFAULT 0) +RETURNS sys.VARCHAR +AS +$BODY$ +BEGIN + RETURN sys.babelfish_conv_to_varchar(typename, arg, p_style); + EXCEPTION + WHEN OTHERS THEN + RETURN NULL; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE; + +CREATE OR REPLACE FUNCTION sys.babelfish_try_conv_to_varchar(IN typename TEXT, + IN arg anyelement, + IN p_style NUMERIC DEFAULT 0) +RETURNS sys.VARCHAR +AS +$BODY$ +BEGIN + RETURN sys.babelfish_conv_to_varchar(typename, arg, p_style); + EXCEPTION + WHEN OTHERS THEN + RETURN NULL; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE; + +CREATE OR REPLACE FUNCTION sys.babelfish_parse_helper_to_date(IN arg TEXT, IN try BOOL, IN culture TEXT DEFAULT '') +RETURNS DATE +AS +$BODY$ +BEGIN + IF try THEN + RETURN sys.babelfish_try_parse_to_date(arg, culture); + ELSE + RETURN sys.babelfish_parse_to_date(arg, culture); + END IF; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE; + +CREATE OR REPLACE FUNCTION sys.babelfish_parse_helper_to_time(IN arg TEXT, IN try BOOL, IN culture TEXT DEFAULT '') +RETURNS TIME WITHOUT TIME ZONE +AS +$BODY$ +BEGIN + IF try THEN + RETURN sys.babelfish_try_parse_to_time('TIME', arg, culture); + ELSE + RETURN sys.babelfish_parse_to_time('TIME', arg, culture); + END IF; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE; + +CREATE OR REPLACE FUNCTION sys.babelfish_parse_helper_to_datetime(IN arg TEXT, IN try BOOL, IN culture TEXT DEFAULT '') +RETURNS TIMESTAMP WITHOUT TIME ZONE +AS +$BODY$ +BEGIN + IF try THEN + RETURN sys.babelfish_try_parse_to_datetime('DATETIME', arg, culture); + ELSE + RETURN sys.babelfish_parse_to_datetime('DATETIME', arg, culture); + END IF; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE; + +CREATE OR REPLACE FUNCTION sys.babelfish_try_conv_money_to_string(IN p_datatype TEXT, + IN p_moneyval PG_CATALOG.MONEY, + IN p_style NUMERIC DEFAULT 0) +RETURNS TEXT +AS +$BODY$ +DECLARE + v_style SMALLINT; + v_format VARCHAR; + v_moneyval NUMERIC(19,4) := p_moneyval::NUMERIC(19,4); + v_moneysign NUMERIC(19,4) := sign(v_moneyval); + v_moneyabs NUMERIC(19,4) := abs(v_moneyval); + v_digits SMALLINT; + v_integral_digits SMALLINT; + v_decimal_digits SMALLINT; + v_res_length SMALLINT; + MASK_REGEXP CONSTANT VARCHAR := '^\s*(?:character varying)\s*\(\s*(\d+|MAX)\s*\)\s*$'; + v_result TEXT; +BEGIN + v_style := floor(p_style)::SMALLINT; + v_digits := length(v_moneyabs::TEXT); + v_decimal_digits := scale(v_moneyabs); + IF (v_decimal_digits > 0) THEN + v_integral_digits := v_digits - v_decimal_digits - 1; + ELSE + v_integral_digits := v_digits; + END IF; + IF (v_style = 0) THEN + v_format := (pow(10, v_integral_digits)-1)::TEXT || 'D99'; + v_result := to_char(v_moneyval, v_format); + ELSIF (v_style = 1) THEN + IF (v_moneysign::SMALLINT = 1) THEN + v_result := substring(p_moneyval::TEXT, 2); + ELSE + v_result := substring(p_moneyval::TEXT, 1, 1) || substring(p_moneyval::TEXT, 3); + END IF; + ELSIF (v_style = 2) THEN + v_format := (pow(10, v_integral_digits)-1)::TEXT || 'D9999'; + v_result := to_char(v_moneyval, v_format); + ELSE + RAISE invalid_parameter_value; + END IF; + v_res_length := substring(p_datatype, MASK_REGEXP)::SMALLINT; + IF v_res_length IS NULL THEN + RETURN v_result; + ELSE + RETURN rpad(v_result, v_res_length, ' '); + END IF; +EXCEPTION + WHEN invalid_parameter_value THEN + RAISE USING MESSAGE := format('%s is not a valid style number when converting from MONEY to a character string.', v_style), + DETAIL := 'Use of incorrect "style" parameter value during conversion process.', + HINT := 'Change "style" parameter to the proper value and try again.'; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_try_conv_float_to_string(IN p_datatype TEXT, + IN p_floatval FLOAT, + IN p_style NUMERIC DEFAULT 0) +RETURNS TEXT +AS +$BODY$ +DECLARE + v_style SMALLINT; + v_format VARCHAR; + v_floatval NUMERIC := abs(p_floatval); + v_digits SMALLINT; + v_integral_digits SMALLINT; + v_decimal_digits SMALLINT; + v_sign SMALLINT := sign(p_floatval); + v_result TEXT; + v_res_length SMALLINT; + MASK_REGEXP CONSTANT VARCHAR := '^\s*(?:character varying)\s*\(\s*(\d+|MAX)\s*\)\s*$'; +BEGIN + v_style := floor(p_style)::SMALLINT; + IF (v_style = 0) THEN + v_digits := length(v_floatval::NUMERIC::TEXT); + v_decimal_digits := scale(v_floatval); + IF (v_decimal_digits > 0) THEN + v_integral_digits := v_digits - v_decimal_digits - 1; + ELSE + v_integral_digits := v_digits; + END IF; + IF (v_floatval >= 999999.5) THEN + v_format := '9D99999EEEE'; + v_result := to_char(v_sign * ceiling(v_floatval), v_format); + v_result := to_char(substring(v_result, 1, 8)::NUMERIC, 'FM9D99999')::NUMERIC::TEXT || substring(v_result, 9); + ELSE + if (6 - v_integral_digits < v_decimal_digits) THEN + v_decimal_digits := 6 - v_integral_digits; + END IF; + v_format := (pow(10, v_integral_digits)-1)::TEXT || 'D'; + IF (v_decimal_digits > 0) THEN + v_format := v_format || (pow(10, v_decimal_digits)-1)::TEXT; + END IF; + v_result := to_char(p_floatval, v_format); + END IF; + ELSIF (v_style = 1) THEN + v_format := '9D9999999EEEE'; + v_result := to_char(p_floatval, v_format); + ELSIF (v_style = 2) THEN + v_format := '9D999999999999999EEEE'; + v_result := to_char(p_floatval, v_format); + ELSIF (v_style = 3) THEN + v_format := '9D9999999999999999EEEE'; + v_result := to_char(p_floatval, v_format); + ELSE + RAISE invalid_parameter_value; + END IF; + + v_res_length := substring(p_datatype, MASK_REGEXP)::SMALLINT; + IF v_res_length IS NULL THEN + RETURN v_result; + ELSE + RETURN rpad(v_result, v_res_length, ' '); + END IF; +EXCEPTION + WHEN invalid_parameter_value THEN + RAISE USING MESSAGE := format('%s is not a valid style number when converting from FLOAT to a character string.', v_style), + DETAIL := 'Use of incorrect "style" parameter value during conversion process.', + HINT := 'Change "style" parameter to the proper value and try again.'; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_try_parse_to_date(IN p_datestring TEXT, + IN p_culture TEXT DEFAULT NULL) +RETURNS DATE +AS +$BODY$ +BEGIN + RETURN sys.babelfish_parse_to_date(p_datestring, p_culture); + EXCEPTION + WHEN OTHERS THEN + RETURN NULL; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_try_parse_to_datetime(IN p_datatype TEXT, + IN p_datetimestring TEXT, + IN p_culture TEXT DEFAULT '') +RETURNS TIMESTAMP WITHOUT TIME ZONE +AS +$BODY$ +BEGIN + RETURN sys.babelfish_parse_to_datetime(p_datatype, p_datetimestring, p_culture); + EXCEPTION + WHEN OTHERS THEN + RETURN NULL; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_try_parse_to_time(IN p_datatype TEXT, + IN p_srctimestring TEXT, + IN p_culture TEXT DEFAULT '') +RETURNS TIME WITHOUT TIME ZONE +AS +$BODY$ +BEGIN + RETURN sys.babelfish_parse_to_time(p_datatype, p_srctimestring, p_culture); + EXCEPTION + WHEN OTHERS THEN + RETURN NULL; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.babelfish_update_job ( + p_job integer, + p_error_message varchar +) +RETURNS void AS +$body$ +DECLARE + var_enabled smallint; + var_freq_type integer; + var_freq_interval integer; + var_freq_subday_type integer; + var_freq_subday_interval integer; + var_freq_relative_interval integer; + var_freq_recurrence_factor integer; + var_tmp_interval varchar(50); + var_job_id integer; + var_schedule_id integer; + var_job_step_id integer; + var_step_id integer; + var_step_name VARCHAR(128); +BEGIN + /* + var_job_step_id := p_job; + + SELECT jst.job_id, jsc.schedule_id, jst.step_name, jst.step_id + FROM sys.sysjobsteps jst + INNER JOIN sys.sysjobschedules jsc + ON jsc.job_id = jst.job_id + INTO var_job_id, var_schedule_id, var_step_name, var_step_id + WHERE jst.job_step_id = var_job_step_id; + */ + INSERT + INTO sys.sysjobhistory ( + job_id + , step_id + , step_name + , sql_message_id + , sql_severity + , message + , run_status + , run_date + , run_time + , run_duration + , operator_id_emailed + , operator_id_netsent + , operator_id_paged + , retries_attempted + , server) + VALUES ( + p_job + , 0 -- var_step_id + , ''--var_step_name + , 0 + , 0 + , p_error_message + , 0 + , now()::date + , now()::time + , 0 + , 0 + , 0 + , 0 + , 0 + , ''::character varying); + + -- PERFORM sys.babelfish_sp_set_next_run (var_job_id, var_schedule_id); + +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION sys.babelfish_waitfor_delay(time_to_pass TEXT) +RETURNS void AS +$BODY$ + SELECT pg_sleep(EXTRACT(HOUR FROM $1::time)*60*60 + + EXTRACT(MINUTE FROM $1::time)*60 + + TRUNC(EXTRACT(SECOND FROM $1::time)) + + sys.babelfish_round_fractseconds( + ( + EXTRACT(MILLISECONDS FROM $1::time) + - TRUNC(EXTRACT(SECOND FROM $1::time)) * 1000 + )::numeric + )/1000::numeric); +$BODY$ +LANGUAGE SQL; + +CREATE OR REPLACE FUNCTION sys.babelfish_waitfor_delay(time_to_pass TIMESTAMP WITHOUT TIME ZONE) +RETURNS void AS +$BODY$ + SELECT pg_sleep(EXTRACT(HOUR FROM $1::time)*60*60 + + EXTRACT(MINUTE FROM $1::time)*60 + + TRUNC(EXTRACT(SECOND FROM $1::time)) + + sys.babelfish_round_fractseconds( + ( + EXTRACT(MILLISECONDS FROM $1::time) + - TRUNC(EXTRACT(SECOND FROM $1::time)) * 1000 + )::numeric + )/1000::numeric); +$BODY$ +LANGUAGE SQL; + +-- internal table function for sp_cursor_list and sp_decribe_cursor +CREATE OR REPLACE FUNCTION sys.babelfish_cursor_list(cursor_source integer) +RETURNS table ( + reference_name text, + cursor_name text, + cursor_scope smallint, + status smallint, + model smallint, + concurrency smallint, + scrollable smallint, + open_status smallint, + cursor_rows bigint, + fetch_status smallint, + column_count smallint, + row_count bigint, + last_operation smallint, + cursor_handle int, + cursor_source smallint +) AS 'babelfishpg_tsql', 'cursor_list' LANGUAGE C; + +CREATE OR REPLACE FUNCTION sys.babelfish_get_datetimeoffset_tzoffset(SYS.DATETIMEOFFSET) +RETURNS SMALLINT +AS 'babelfishpg_common', 'get_datetimeoffset_tzoffset_internal' +LANGUAGE C IMMUTABLE STRICT; + +-- internal table function for querying the registered ENRs +CREATE OR REPLACE FUNCTION sys.babelfish_get_enr_list() +RETURNS table ( + reloid int, + relname text +) AS 'babelfishpg_tsql', 'get_enr_list' LANGUAGE C; + +-- internal table function for collation_list +CREATE OR REPLACE FUNCTION sys.babelfish_collation_list() +RETURNS table ( + oid int, + collation_name text, + l1_priority int, + l2_priority int, + l3_priority int, + l4_priority int, + l5_priority int +) AS 'babelfishpg_tsql', 'collation_list' LANGUAGE C; + +-- internal function to truncate long identifier +CREATE OR REPLACE FUNCTION sys.babelfish_truncate_identifier(IN object_name TEXT) +RETURNS text +AS 'babelfishpg_tsql', 'pltsql_truncate_identifier_func' LANGUAGE C IMMUTABLE STRICT; + +-- internal functions for debuggig/testing purpose +CREATE OR REPLACE FUNCTION sys.babelfish_pltsql_cursor_show_textptr_only_column_indexes(cursor_handle INT) +RETURNS text +AS 'babelfishpg_tsql', 'pltsql_cursor_show_textptr_only_column_indexes' LANGUAGE C; + +CREATE OR REPLACE FUNCTION sys.babelfish_pltsql_get_last_cursor_handle() +RETURNS INT +AS 'babelfishpg_tsql', 'pltsql_get_last_cursor_handle' LANGUAGE C; + +CREATE OR REPLACE FUNCTION sys.babelfish_pltsql_get_last_stmt_handle() +RETURNS INT +AS 'babelfishpg_tsql', 'pltsql_get_last_stmt_handle' LANGUAGE C; + +CREATE OR REPLACE FUNCTION sys.get_babel_server_collation_oid() RETURNS OID +LANGUAGE C +AS 'babelfishpg_tsql', 'get_server_collation_oid'; diff --git a/contrib/babelfishpg_tsql/sql/sys_functions.sql b/contrib/babelfishpg_tsql/sql/sys_functions.sql new file mode 100644 index 00000000000..7f7bf45e42b --- /dev/null +++ b/contrib/babelfishpg_tsql/sql/sys_functions.sql @@ -0,0 +1,1879 @@ +-- Helper functions to support the FOR XML clause +CREATE OR REPLACE FUNCTION sys.tsql_query_to_xml(query text, mode int, element_name text, + binary_base64 boolean, root_name text) +RETURNS xml +AS 'babelfishpg_tsql', 'tsql_query_to_xml' +LANGUAGE C IMMUTABLE STRICT COST 100; + +CREATE OR REPLACE FUNCTION sys.tsql_query_to_xml_text(query text, mode int, element_name text, + binary_base64 boolean, root_name text) +RETURNS ntext +AS 'babelfishpg_tsql', 'tsql_query_to_xml_text' +LANGUAGE C IMMUTABLE STRICT COST 100; + +-- User and Login Functions +CREATE OR REPLACE FUNCTION sys.user_name(IN id OID DEFAULT NULL) +RETURNS sys.NVARCHAR(128) +AS 'babelfishpg_tsql', 'user_name' +LANGUAGE C IMMUTABLE PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.user_id(IN user_name TEXT DEFAULT NULL) +RETURNS OID +AS 'babelfishpg_tsql', 'user_id' +LANGUAGE C IMMUTABLE PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.suser_name(IN server_user_id OID DEFAULT NULL) +RETURNS sys.NVARCHAR(128) +AS 'babelfishpg_tsql', 'suser_name' +LANGUAGE C IMMUTABLE PARALLEL RESTRICTED; + +CREATE OR REPLACE FUNCTION sys.suser_id(IN login TEXT DEFAULT NULL) +RETURNS OID +AS 'babelfishpg_tsql', 'suser_id' +LANGUAGE C IMMUTABLE PARALLEL RESTRICTED; + +-- Matches and returns object name to Oid +CREATE OR REPLACE FUNCTION sys.OBJECT_NAME(IN object_id INT, IN database_id INT DEFAULT NULL) +RETURNS sys.SYSNAME AS +$BODY$ +DECLARE + object_name TEXT; + object_oid Oid; + cur_dat_id Oid; +BEGIN + IF database_id is not NULL THEN + SELECT Oid INTO cur_dat_id FROM pg_database WHERE datname = current_database(); + IF database_id::Oid != cur_dat_id THEN + RAISE EXCEPTION 'Can only do lookup in current database.'; + END IF; + END IF; + + SELECT CAST(object_id AS Oid) INTO object_oid; + + -- First check for tables, sequences, views, etc. + SELECT relname INTO object_name FROM pg_class WHERE Oid = object_oid; + IF object_name IS NOT NULL THEN + RETURN object_name::sys.SYSNAME; + END IF; + + -- Check ENR for any matches + SELECT relname INTO object_name FROM sys.babelfish_get_enr_list() WHERE reloid = object_oid; + IF object_name IS NOT NULL THEN + RETURN object_name::sys.SYSNAME; + END IF; + + -- Next check for functions + SELECT proname INTO object_name FROM pg_proc WHERE Oid = object_oid; + IF object_name IS NOT NULL THEN + RETURN object_name::sys.SYSNAME; + END IF; + + -- Next check for types + SELECT typname INTO object_name FROM pg_type WHERE Oid = object_oid; + IF object_name IS NOT NULL THEN + RETURN object_name::sys.SYSNAME; + END IF; + + -- Apparently SYSNAME cannot be null so returning empty string + RETURN ''; +END; +$BODY$ +LANGUAGE plpgsql +IMMUTABLE; + +CREATE OR REPLACE FUNCTION sys.scope_identity() +RETURNS numeric(38,0) AS +$BODY$ + SELECT sys.babelfish_get_last_identity_numeric()::numeric(38,0); +$BODY$ +LANGUAGE SQL; + +CREATE OR REPLACE FUNCTION sys.ident_seed(IN tablename TEXT) +RETURNS numeric(38,0) AS +$BODY$ + SELECT sys.babelfish_get_identity_param(tablename, 'start'::text)::numeric(38,0); +$BODY$ +LANGUAGE SQL; + +CREATE OR REPLACE FUNCTION sys.ident_incr(IN tablename TEXT) +RETURNS numeric(38,0) AS +$BODY$ + SELECT sys.babelfish_get_identity_param(tablename, 'increment'::text)::numeric(38,0); +$BODY$ +LANGUAGE SQL; + +CREATE OR REPLACE FUNCTION sys.ident_current(IN tablename TEXT) +RETURNS numeric(38,0) AS +$BODY$ + SELECT sys.babelfish_get_identity_current(tablename)::numeric(38,0); +$BODY$ +LANGUAGE SQL; + +CREATE OR REPLACE FUNCTION sys.checksum(IN _input TEXT) RETURNS INTEGER +AS +$BODY$ + SELECT ('x'||SUBSTR(MD5(_input),1,8))::pg_catalog.BIT(32)::INTEGER; +$BODY$ +LANGUAGE SQL IMMUTABLE; + +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 TIMESTAMP 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_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) > p_precision)) + THEN + RAISE invalid_datetime_format; + ELSIF (v_precision NOT BETWEEN 0 AND 7) THEN + RAISE invalid_parameter_value; + END IF; + + v_calc_seconds := format('%s.%s', + floor(p_seconds)::SMALLINT, + substring(rpad(lpad(v_fractions, v_precision, '0'), 7, '0'), 1, 6))::NUMERIC; + + RETURN 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); +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 := 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 := format('Error while trying to cast to %s data type.', v_err_message), + 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 +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.datetime2fromparts(IN p_year TEXT, + IN p_month TEXT, + IN p_day TEXT, + IN p_hour TEXT, + IN p_minute TEXT, + IN p_seconds TEXT, + IN p_fractions TEXT, + IN p_precision TEXT) +RETURNS TIMESTAMP WITHOUT TIME ZONE +AS +$BODY$ +DECLARE + v_err_message VARCHAR; +BEGIN + RETURN sys.datetime2fromparts(p_year::NUMERIC, p_month::NUMERIC, p_day::NUMERIC, + p_hour::NUMERIC, p_minute::NUMERIC, p_seconds::NUMERIC, + p_fractions::NUMERIC, p_precision::NUMERIC); +EXCEPTION + WHEN invalid_text_representation THEN + GET STACKED DIAGNOSTICS v_err_message = MESSAGE_TEXT; + v_err_message := substring(lower(v_err_message), 'numeric\:\s\"(.*)\"'); + + RAISE USING MESSAGE := format('Error while trying to convert "%s" value to NUMERIC data type.', v_err_message), + DETAIL := 'Supplied string value contains illegal characters.', + HINT := 'Correct supplied value, remove all illegal characters and try again.'; +END; +$BODY$ +LANGUAGE plpgsql +IMMUTABLE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.datetimefromparts(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_milliseconds NUMERIC) +RETURNS TIMESTAMP WITHOUT TIME ZONE +AS +$BODY$ +DECLARE + v_err_message VARCHAR; + v_calc_seconds NUMERIC; + v_milliseconds SMALLINT; + v_resdatetime TIMESTAMP WITHOUT TIME ZONE; +BEGIN + -- Check if arguments are out of range + IF ((floor(p_year)::SMALLINT NOT BETWEEN 1753 AND 9999) OR + (floor(p_month)::SMALLINT NOT BETWEEN 1 AND 12) OR + (floor(p_day)::SMALLINT NOT BETWEEN 1 AND 31) OR + (floor(p_hour)::SMALLINT NOT BETWEEN 0 AND 23) OR + (floor(p_minute)::SMALLINT NOT BETWEEN 0 AND 59) OR + (floor(p_seconds)::SMALLINT NOT BETWEEN 0 AND 59) OR + (floor(p_milliseconds)::SMALLINT NOT BETWEEN 0 AND 999)) + THEN + RAISE invalid_datetime_format; + END IF; + + v_milliseconds := sys.babelfish_round_fractseconds(p_milliseconds::INTEGER); + + v_calc_seconds := format('%s.%s', + floor(p_seconds)::SMALLINT, + CASE v_milliseconds + WHEN 1000 THEN '0' + ELSE lpad(v_milliseconds::VARCHAR, 3, '0') + END)::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); + RETURN CASE + WHEN (v_milliseconds != 1000) THEN v_resdatetime + ELSE v_resdatetime + INTERVAL '1 second' + END; +EXCEPTION + WHEN invalid_datetime_format THEN + RAISE USING MESSAGE := 'Cannot construct data type datetime, 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 := format('Error while trying to cast to %s data type.', v_err_message), + 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 +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.datetimefromparts(IN p_year TEXT, + IN p_month TEXT, + IN p_day TEXT, + IN p_hour TEXT, + IN p_minute TEXT, + IN p_seconds TEXT, + IN p_milliseconds TEXT) +RETURNS TIMESTAMP WITHOUT TIME ZONE +AS +$BODY$ +DECLARE + v_err_message VARCHAR; +BEGIN + RETURN sys.datetimefromparts(p_year::NUMERIC, p_month::NUMERIC, p_day::NUMERIC, + p_hour::NUMERIC, p_minute::NUMERIC, + p_seconds::NUMERIC, p_milliseconds::NUMERIC); +EXCEPTION + WHEN invalid_text_representation THEN + GET STACKED DIAGNOSTICS v_err_message = MESSAGE_TEXT; + v_err_message := substring(lower(v_err_message), 'numeric\:\s\"(.*)\"'); + + RAISE USING MESSAGE := format('Error while trying to convert "%s" value to NUMERIC data type.', v_err_message), + DETAIL := 'Supplied string value contains illegal characters.', + HINT := 'Correct supplied value, remove all illegal characters and try again.'; +END; +$BODY$ +LANGUAGE plpgsql +IMMUTABLE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.isnumeric(IN expr ANYELEMENT) RETURNS INTEGER AS +$BODY$ +DECLARE + x NUMERIC; + y MONEY; +BEGIN + IF (expr IS NULL) THEN + RETURN 0; + END IF; + IF ($1::VARCHAR ~ '^\s*$') THEN + RETURN 0; + END IF; + IF pg_typeof(expr) IN ('bigint'::regtype, 'int'::regtype, 'smallint'::regtype,'sys.tinyint'::regtype, + 'numeric'::regtype, 'float'::regtype, 'real'::regtype, 'sys.money'::regtype) + THEN + RETURN 1; + END IF; + x = $1::NUMERIC; + RETURN 1; +EXCEPTION WHEN others THEN + BEGIN + y = $1::sys.MONEY; + RETURN 1; + EXCEPTION WHEN others THEN + RETURN 0; + END; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE CALLED ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.isnumeric(IN expr TEXT) RETURNS INTEGER AS +$BODY$ +DECLARE + x NUMERIC; + y MONEY; +BEGIN + IF (expr IS NULL) THEN + RETURN 0; + END IF; + IF ($1::VARCHAR ~ '^\s*$') THEN + RETURN 0; + END IF; + IF pg_typeof(expr) IN ('bigint'::regtype, 'int'::regtype, 'smallint'::regtype,'sys.tinyint'::regtype, + 'numeric'::regtype, 'float'::regtype, 'real'::regtype, 'sys.money'::regtype) + THEN + RETURN 1; + END IF; + x = $1::NUMERIC; + RETURN 1; +EXCEPTION WHEN others THEN + BEGIN + y = $1::sys.MONEY; + RETURN 1; + EXCEPTION WHEN others THEN + RETURN 0; + END; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE CALLED ON NULL INPUT; + +-- Return the object ID given the object name. Can specify optional type. +CREATE OR REPLACE FUNCTION sys.object_id(IN object_name TEXT, IN object_type char(2) DEFAULT '') +RETURNS INTEGER AS +$BODY$ +DECLARE + id oid; + lower_object_name text; + names text[2]; + counter int; + cur_pos int; + db_name text; + input_schema_name text; + schema_name text; + schema_oid oid; + obj_name text; + is_temp_object boolean; +BEGIN + id = null; + lower_object_name = lower(trim(object_name)); + counter = 1; + cur_pos = position('.' in lower_object_name); + schema_oid = NULL; + + -- Parse user input into names split by '.' + WHILE cur_pos > 0 LOOP + IF counter > 3 THEN + -- Too many names provided + RETURN NULL; + END IF; + names[counter] = sys.babelfish_single_unbracket_name(left(lower_object_name, cur_pos - 1)); + lower_object_name = substring(lower_object_name from cur_pos + 1); + counter = counter + 1; + cur_pos = position('.' in lower_object_name); + END LOOP; + + -- Assign each name accordingly + obj_name = sys.babelfish_truncate_identifier(sys.babelfish_single_unbracket_name(lower_object_name)); + CASE counter + WHEN 1 THEN + db_name = NULL; + schema_name = NULL; + WHEN 2 THEN + db_name = NULL; + input_schema_name = sys.babelfish_truncate_identifier(names[1]); + schema_name = sys.bbf_get_current_physical_schema_name(input_schema_name); + WHEN 3 THEN + db_name = sys.babelfish_truncate_identifier(names[1]); + input_schema_name = sys.babelfish_truncate_identifier(names[2]); + schema_name = sys.bbf_get_current_physical_schema_name(input_schema_name); + ELSE + RETURN NULL; + END CASE; + + -- Check if looking for temp object. + is_temp_object = left(obj_name, 1) = '#'; + + -- Can only search in current database. Allowing tempdb for temp objects. + IF db_name IS NOT NULL AND db_name <> current_database() AND db_name <> 'tempdb' THEN + RAISE EXCEPTION 'Can only do lookup in current database.'; + END IF; + + IF schema_name IS NOT NULL AND schema_name <> '' THEN + -- Searching within a schema. Get schema oid. + schema_oid = (SELECT oid FROM pg_namespace WHERE nspname = schema_name); + IF schema_oid IS NULL THEN + RETURN NULL; + END IF; + + if object_type <> '' then + case + -- Schema does not apply as much to temp objects. + when upper(object_type) in ('S', 'U', 'V', 'IT', 'ET', 'SO') and is_temp_object then + id := (select reloid from sys.babelfish_get_enr_list() where lower(relname) = obj_name limit 1); + + when upper(object_type) in ('S', 'U', 'V', 'IT', 'ET', 'SO') and not is_temp_object then + id := (select oid from pg_class where lower(relname) = obj_name + and relnamespace = schema_oid limit 1); + + when upper(object_type) in ('C', 'D', 'F', 'PK', 'UQ') then + id := (select oid from pg_constraint where lower(conname) = obj_name + and connamespace = schema_oid limit 1); + + when upper(object_type) in ('AF', 'FN', 'FS', 'FT', 'IF', 'P', 'PC', 'TF', 'RF', 'X') then + id := (select oid from pg_proc where lower(proname) = obj_name + and pronamespace = schema_oid limit 1); + + when upper(object_type) in ('TR', 'TA') then + id := (select oid from pg_trigger where lower(tgname) = obj_name limit 1); + + -- Throwing exception as a reminder to add support in the future. + when upper(object_type) in ('R', 'EC', 'PG', 'SN', 'SQ', 'TT') then + RAISE EXCEPTION 'Object type currently unsupported.'; + + -- unsupported object_type + else id := null; + end case; + else + if not is_temp_object then id := ( + select oid from pg_class where lower(relname) = obj_name + and relnamespace = schema_oid + union + select oid from pg_constraint where lower(conname) = obj_name + and connamespace = schema_oid + union + select oid from pg_proc where lower(proname) = obj_name + and pronamespace = schema_oid + union + select oid from pg_trigger where lower(tgname) = obj_name + limit 1); + else + -- temp object without "object_type" in-argument + id := (select reloid from sys.babelfish_get_enr_list() where lower(relname) = obj_name limit 1); + end if; + end if; + ELSE + -- Schema not specified. + if object_type <> '' then + case + when upper(object_type) in ('S', 'U', 'V', 'IT', 'ET', 'SO') and is_temp_object then + id := (select reloid from sys.babelfish_get_enr_list() where lower(relname) = obj_name limit 1); + + when upper(object_type) in ('S', 'U', 'V', 'IT', 'ET', 'SO') and not is_temp_object then + id := (select oid from pg_class where lower(relname) = obj_name limit 1); + + when upper(object_type) in ('C', 'D', 'F', 'PK', 'UQ') then + id := (select oid from pg_constraint where lower(conname) = obj_name limit 1); + + when upper(object_type) in ('AF', 'FN', 'FS', 'FT', 'IF', 'P', 'PC', 'TF', 'RF', 'X') then + id := (select oid from pg_proc where lower(proname) = obj_name limit 1); + + when upper(object_type) in ('TR', 'TA') then + id := (select oid from pg_trigger where lower(tgname) = obj_name limit 1); + + -- Throwing exception as a reminder to add support in the future. + when upper(object_type) in ('R', 'EC', 'PG', 'SN', 'SQ', 'TT') then + RAISE EXCEPTION 'Object type currently unsupported.'; + + -- unsupported object_type + else id := null; + end case; + else + if not is_temp_object then id := ( + select oid from pg_class where lower(relname) = obj_name + union + select oid from pg_constraint where lower(conname) = obj_name + union + select oid from pg_proc where lower(proname) = obj_name + union + select oid from pg_trigger where lower(tgname) = obj_name + limit 1); + else + -- temp object without "object_type" in-argument + id := (select reloid from sys.babelfish_get_enr_list() where lower(relname) = obj_name limit 1); + end if; + end if; + END IF; + + RETURN id::integer; +END; +$BODY$ +LANGUAGE plpgsql STABLE RETURNS NULL ON NULL INPUT; + +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(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.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) > p_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 := format('%s.%s', + floor(p_seconds)::SMALLINT, + substring(rpad(lpad(v_fractions, v_precision, '0'), 7, '0'), 1, 6))::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 := 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 := format('Error while trying to cast to %s data type.', v_err_message), + 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 +VOLATILE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.timefromparts(IN p_hour TEXT, + IN p_minute TEXT, + IN p_seconds TEXT, + IN p_fractions TEXT, + IN p_precision TEXT) +RETURNS TIME WITHOUT TIME ZONE +AS +$BODY$ +DECLARE + v_err_message VARCHAR; +BEGIN + RETURN sys.timefromparts(p_hour::NUMERIC, p_minute::NUMERIC, + p_seconds::NUMERIC, p_fractions::NUMERIC, + p_precision::NUMERIC); +EXCEPTION + WHEN invalid_text_representation THEN + GET STACKED DIAGNOSTICS v_err_message = MESSAGE_TEXT; + v_err_message := substring(lower(v_err_message), 'numeric\:\s\"(.*)\"'); + + RAISE USING MESSAGE := format('Error while trying to convert "%s" value to NUMERIC data type.', v_err_message), + DETAIL := 'Supplied string value contains illegal characters.', + HINT := 'Correct supplied value, remove all illegal characters and try again.'; +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.has_dbaccess(database_name PG_CATALOG.TEXT) RETURNS INTEGER AS $$ +DECLARE has_access BOOLEAN; +BEGIN + has_access = has_database_privilege(database_name, 'CONNECT'); + IF has_access THEN + RETURN 1; + ELSE + RETURN 0; + END IF; +EXCEPTION WHEN others THEN + RETURN NULL; +END; +$$ +STRICT +LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION sys.is_srvrolemember(role PG_CATALOG.TEXT, login PG_CATALOG.TEXT DEFAULT CURRENT_USER) RETURNS INTEGER AS $$ +DECLARE has_role BOOLEAN; +BEGIN + has_role = pg_has_role(login, role, 'MEMBER'); + IF has_role THEN + return 1; + ELSE + RETURN 0; + END IF; +EXCEPTION WHEN others THEN + RETURN NULL; +END; +$$ +STRICT +LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION sys.datefromparts(IN year INT, IN month INT, IN day INT) +RETURNS DATE AS +$BODY$ +SELECT make_date(year, month, day); +$BODY$ +STRICT +LANGUAGE SQL IMMUTABLE; + +CREATE OR REPLACE FUNCTION sys.charindex(expressionToFind PG_CATALOG.TEXT, + expressionToSearch PG_CATALOG.TEXT, + start_location INTEGER DEFAULT 0) +RETURNS INTEGER AS +$BODY$ +SELECT +CASE +WHEN start_location <= 0 THEN + strpos(expressionToSearch, expressionToFind) +ELSE + CASE + WHEN strpos(substr(expressionToSearch, start_location), expressionToFind) = 0 THEN + 0 + ELSE + strpos(substr(expressionToSearch, start_location), expressionToFind) + start_location - 1 + END +END; +$BODY$ +STRICT +LANGUAGE SQL 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 +$BODY$ +SELECT +CASE +WHEN start <= 0 or start > length(expr) or length < 0 THEN + NULL +WHEN replace_expr is NULL THEN + overlay (expr placing '' from start for length) +ELSE + overlay (expr placing replace_expr from start for length) +END; +$BODY$ +LANGUAGE SQL; + +CREATE OR REPLACE FUNCTION sys.stuff(expr ANYELEMENT, start INTEGER, length INTEGER, replace_expr ANYELEMENT) +RETURNS ANYELEMENT AS +$BODY$ +SELECT +CASE +WHEN start <= 0 or start > length(expr) or length < 0 THEN + NULL +WHEN replace_expr is NULL THEN + overlay (expr placing '' from start for length) +ELSE + overlay (expr placing replace_expr from start for length) +END; +$BODY$ +LANGUAGE SQL; + +CREATE OR REPLACE FUNCTION sys.len(expr TEXT) RETURNS INTEGER AS +$BODY$ +SELECT length(trim(trailing from expr)); +$BODY$ +STRICT +LANGUAGE SQL IMMUTABLE; + +-- DATALENGTH +CREATE OR REPLACE FUNCTION sys.datalength(ANYELEMENT) RETURNS INTEGER +AS 'babelfishpg_tsql', 'datalength' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; +-- provide both additional functions here to avoid implicit casting between string literals with/without N'' +CREATE OR REPLACE FUNCTION sys.datalength(text) RETURNS INTEGER +AS 'babelfishpg_tsql', 'datalength' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; +CREATE OR REPLACE FUNCTION sys.datalength(char) RETURNS INTEGER +AS 'babelfishpg_tsql', 'datalength' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; +-- TODO: in MSSQL datalength against varchar(max) will return BIGINT instead of INTEGER. However in PG we ignore typmods in functions. +-- However this is not a critical issue so we will just leave it. We may come back to this difference later once we find out solution to typmods. + +CREATE OR REPLACE FUNCTION sys.round(number PG_CATALOG.NUMERIC, length INTEGER) +RETURNS NUMERIC AS 'babelfishpg_common', 'tsql_numeric_round' LANGUAGE C IMMUTABLE PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.round(number PG_CATALOG.NUMERIC, length INTEGER, function INTEGER) +RETURNS NUMERIC AS 'babelfishpg_common', 'tsql_numeric_trunc' LANGUAGE C IMMUTABLE PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.day(date ANYELEMENT) +RETURNS INTEGER AS +$BODY$ +SELECT sys.datepart('day', date); +$BODY$ +STRICT +LANGUAGE SQL IMMUTABLE; + +CREATE OR REPLACE FUNCTION sys.month(date ANYELEMENT) +RETURNS INTEGER AS +$BODY$ +SELECT sys.datepart('month', date); +$BODY$ +STRICT +LANGUAGE SQL IMMUTABLE; + +CREATE OR REPLACE FUNCTION sys.year(date ANYELEMENT) +RETURNS INTEGER AS +$BODY$ +SELECT sys.datepart('year', date); +$BODY$ +STRICT +LANGUAGE SQL IMMUTABLE; + +CREATE OR REPLACE FUNCTION sys.space(IN number INTEGER, OUT result SYS.VARCHAR) AS $$ +-- sys.varchar has default length of 1, so we have to pass in 'number' to be the +-- type modifier. +BEGIN + EXECUTE format(E'SELECT repeat(\' \', %s)::SYS.VARCHAR(%s)', number, number) INTO result; +END; +$$ +STRICT +LANGUAGE plpgsql; + +create or replace function sys.isdate(v text) +returns integer +as +$body$ +begin + if v is NULL THEN + return 0; + else + perform v::date; + return 1; + end if; + EXCEPTION WHEN others THEN + RETURN 0; +end +$body$ +language 'plpgsql'; + +create or replace function sys.PATINDEX(in pattern character varying, in expression character varying) returns bigint as +$body$ +declare + v_find_result character varying; + v_pos bigint; + v_regexp_pattern character varying; +begin + v_pos := null; + if left(pattern, 1) = '%' then + v_regexp_pattern := regexp_replace(pattern, '^%', '%#"'); + else + v_regexp_pattern := '#"' || pattern; + end if; + + if right(pattern, 1) = '%' then + v_regexp_pattern := regexp_replace(v_regexp_pattern, '%$', '#"%'); + else + v_regexp_pattern := v_regexp_pattern || '#"'; + end if; + v_find_result := substring(expression from v_regexp_pattern for '#'); + if v_find_result <> '' then + v_pos := strpos(expression, v_find_result); + end if; + return v_pos; +end; +$body$ +language plpgsql returns null on null input; + +create or replace function sys.RAND(x in int)returns double precision +AS 'babelfishpg_tsql', 'tsql_random' +LANGUAGE C IMMUTABLE STRICT COST 1 PARALLEL RESTRICTED; + +create or replace function sys.square(in x double precision) returns double precision +AS +$BODY$ +DECLARE + res double precision; +BEGIN + res = pow(x, 2::float); + return res; +END; +$BODY$ +LANGUAGE plpgsql PARALLEL SAFE IMMUTABLE RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.datepart(IN datepart PG_CATALOG.TEXT, IN arg anyelement) RETURNS INTEGER +AS +$body$ +BEGIN + IF pg_typeof(arg) = 'sys.DATETIMEOFFSET'::regtype THEN + return sys.datepart_internal(datepart, arg::timestamp, + sys.babelfish_get_datetimeoffset_tzoffset(arg)::integer); + ELSE + return sys.datepart_internal(datepart, arg); + END IF; +END; +$body$ +LANGUAGE plpgsql IMMUTABLE; + +-- Duplicate function with arg TEXT since ANYELEMENT cannot handle type unknown. +CREATE OR REPLACE FUNCTION sys.datepart(IN datepart PG_CATALOG.TEXT, IN arg TEXT) RETURNS INTEGER +AS +$body$ +BEGIN + IF pg_typeof(arg) = 'sys.DATETIMEOFFSET'::regtype THEN + return sys.datepart_internal(datepart, arg::timestamp, + sys.babelfish_get_datetimeoffset_tzoffset(arg)::integer); + ELSE + return sys.datepart_internal(datepart, arg); + END IF; +END; +$body$ +LANGUAGE plpgsql IMMUTABLE; + +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, enddate); +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, enddate); +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_df(datepart, startdate, enddate); +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, enddate); +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, enddate); +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; + + -- Duplicate functions with arg TEXT since ANYELEMENT cannot handle type unknown. +CREATE OR REPLACE FUNCTION sys.dateadd(IN datepart PG_CATALOG.TEXT, IN num INTEGER, IN startdate TEXT) RETURNS DATETIME +AS +$body$ +BEGIN + IF pg_typeof(startdate) = 'sys.DATETIMEOFFSET'::regtype THEN + return sys.dateadd_internal_df(datepart, num, + startdate); + ELSE + return sys.dateadd_internal(datepart, num, + startdate); + END IF; +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$ +BEGIN + IF pg_typeof(startdate) = 'sys.DATETIMEOFFSET'::regtype THEN + return sys.dateadd_internal_df(datepart, num, + startdate); + ELSE + return sys.dateadd_internal(datepart, num, + startdate); + END IF; +END; +$body$ +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; +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 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_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 * 0.001); + WHEN 'microsecond' THEN + RETURN startdate OPERATOR(sys.+) make_interval(secs => num * 0.000001); + WHEN 'nanosecond' THEN + -- Best we can do - Postgres does not support nanosecond precision + RETURN startdate; + ELSE + RAISE EXCEPTION '"%" is not a recognized dateadd option.', datepart; + END CASE; +END; +$$ +STRICT +LANGUAGE plpgsql IMMUTABLE; + +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; + 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 * 0.001); + WHEN 'microsecond' THEN + RETURN startdate + make_interval(secs => num * 0.000001); + WHEN 'nanosecond' THEN + -- Best we can do - Postgres does not support nanosecond precision + RETURN startdate; + 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 INTEGER AS $$ +DECLARE + result INTEGER; + year_diff INTEGER; + month_diff INTEGER; + day_diff INTEGER; + hour_diff INTEGER; + minute_diff INTEGER; + second_diff INTEGER; + millisecond_diff INTEGER; + microsecond_diff INTEGER; +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 + day_diff = sys.datepart('day', enddate OPERATOR(sys.-) startdate); + result = day_diff; + WHEN 'week' THEN + day_diff = sys.datepart('day', enddate OPERATOR(sys.-) startdate); + result = day_diff / 7; + WHEN 'hour' THEN + day_diff = sys.datepart('day', enddate OPERATOR(sys.-) startdate); + hour_diff = sys.datepart('hour', enddate OPERATOR(sys.-) 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 don't 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 don't 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(IN datepart PG_CATALOG.TEXT, IN startdate anyelement, IN enddate anyelement) RETURNS INTEGER AS $$ +DECLARE + result INTEGER; + year_diff INTEGER; + month_diff INTEGER; + day_diff INTEGER; + hour_diff INTEGER; + minute_diff INTEGER; + second_diff INTEGER; + millisecond_diff INTEGER; + microsecond_diff INTEGER; +BEGIN + CASE datepart + WHEN 'year' THEN + year_diff = date_part('year', enddate)::INTEGER - date_part('year', startdate)::INTEGER; + result = year_diff; + WHEN 'quarter' THEN + year_diff = date_part('year', enddate)::INTEGER - date_part('year', startdate)::INTEGER; + month_diff = date_part('month', enddate)::INTEGER - date_part('month', startdate)::INTEGER; + result = (year_diff * 12 + month_diff) / 3; + WHEN 'month' THEN + year_diff = date_part('year', enddate)::INTEGER - date_part('year', startdate)::INTEGER; + month_diff = date_part('month', enddate)::INTEGER - date_part('month', startdate)::INTEGER; + result = year_diff * 12 + month_diff; + WHEN 'doy', 'y' THEN + day_diff = date_part('day', enddate OPERATOR(sys.-) startdate)::INTEGER; + result = day_diff; + WHEN 'day' THEN + day_diff = date_part('day', enddate OPERATOR(sys.-) startdate)::INTEGER; + result = day_diff; + WHEN 'week' THEN + day_diff = date_part('day', enddate OPERATOR(sys.-) startdate)::INTEGER; + result = day_diff / 7; + WHEN 'hour' THEN + day_diff = date_part('day', enddate OPERATOR(sys.-) startdate)::INTEGER; + hour_diff = date_part('hour', enddate OPERATOR(sys.-) startdate)::INTEGER; + result = day_diff * 24 + hour_diff; + WHEN 'minute' THEN + day_diff = date_part('day', enddate OPERATOR(sys.-) startdate)::INTEGER; + hour_diff = date_part('hour', enddate OPERATOR(sys.-) startdate)::INTEGER; + minute_diff = date_part('minute', enddate OPERATOR(sys.-) startdate)::INTEGER; + result = (day_diff * 24 + hour_diff) * 60 + minute_diff; + WHEN 'second' THEN + day_diff = date_part('day', enddate OPERATOR(sys.-) startdate)::INTEGER; + hour_diff = date_part('hour', enddate OPERATOR(sys.-) startdate)::INTEGER; + minute_diff = date_part('minute', enddate OPERATOR(sys.-) startdate)::INTEGER; + 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 don't need to add second_diff again + day_diff = date_part('day', enddate OPERATOR(sys.-) startdate)::INTEGER; + hour_diff = date_part('hour', enddate OPERATOR(sys.-) startdate)::INTEGER; + minute_diff = date_part('minute', enddate OPERATOR(sys.-) startdate)::INTEGER; + 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 don't need to add second_diff and millisecond_diff again + day_diff = date_part('day', enddate OPERATOR(sys.-) startdate)::INTEGER; + hour_diff = date_part('hour', enddate OPERATOR(sys.-) startdate)::INTEGER; + minute_diff = date_part('minute', enddate OPERATOR(sys.-) startdate)::INTEGER; + 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)::INTEGER; + hour_diff = date_part('hour', enddate OPERATOR(sys.-) startdate)::INTEGER; + minute_diff = date_part('minute', enddate OPERATOR(sys.-) startdate)::INTEGER; + 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; +END; +$$ +STRICT +LANGUAGE plpgsql IMMUTABLE; + +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') + -- '1969-12-28' is a Sunday + WHEN dp = 'dow'::text THEN + to_char(arg::date, 'TMDay') + ELSE + sys.datepart(dp, arg)::TEXT + END +$BODY$ +STRICT +LANGUAGE sql IMMUTABLE; + +-- Duplicate functions with arg TEXT since ANYELEMENT cannot handle type unknown. +CREATE OR REPLACE FUNCTION sys.datename(IN dp PG_CATALOG.TEXT, IN arg TEXT) RETURNS TEXT AS +$BODY$ +SELECT + CASE + WHEN dp = 'month'::text THEN + to_char(arg::date, 'TMMonth') + -- '1969-12-28' is a Sunday + WHEN dp = 'dow'::text THEN + to_char(arg::date, 'TMDay') + ELSE + sys.datepart(dp, arg)::TEXT + END +$BODY$ +STRICT +LANGUAGE sql IMMUTABLE; + +CREATE OR REPLACE FUNCTION sys.GETUTCDATE() RETURNS sys.DATETIME AS +$BODY$ +SELECT CAST(CURRENT_TIMESTAMP AT TIME ZONE 'UTC' AS sys.DATETIME); +$BODY$ +LANGUAGE SQL PARALLEL SAFE; + +-- These come from the built-in pg_catalog.count in pg_aggregate.dat +CREATE AGGREGATE sys.count(*) +( + sfunc = int8inc, + combinefunc = int8pl, + msfunc = int8inc, + minvfunc = int8dec, + stype = int8, + mstype = int8, + initcond = 0, + minitcond = 0, + finalfunc = int4, + mfinalfunc = int4, + parallel = safe +); + +CREATE AGGREGATE sys.count("any") +( + sfunc = int8inc_any, + combinefunc = int8pl, + msfunc = int8inc_any, + minvfunc = int8dec_any, + stype = int8, + mstype = int8, + initcond = 0, + minitcond = 0, + finalfunc = int4, + mfinalfunc = int4, + parallel = safe +); + +CREATE AGGREGATE sys.count_big(*) +( + sfunc = int8inc, + combinefunc = int8pl, + msfunc = int8inc, + minvfunc = int8dec, + stype = int8, + mstype = int8, + initcond = 0, + minitcond = 0, + parallel = safe +); + +CREATE AGGREGATE sys.count_big("any") +( + sfunc = int8inc_any, + combinefunc = int8pl, + msfunc = int8inc_any, + minvfunc = int8dec_any, + stype = int8, + mstype = int8, + initcond = 0, + minitcond = 0, + parallel = safe +); + +CREATE OR REPLACE FUNCTION sys.REPLICATE(string TEXT, number INTEGER) +RETURNS VARCHAR AS +$BODY$ +SELECT + CASE + WHEN number >= 0 THEN repeat(string, number) + ELSE null + END; +$BODY$ +LANGUAGE SQL IMMUTABLE STRICT PARALLEL SAFE; + +-- @@ functions +CREATE OR REPLACE FUNCTION sys.rowcount() +RETURNS INT AS 'babelfishpg_tsql' LANGUAGE C; + +CREATE OR REPLACE FUNCTION sys.error() + RETURNS INT AS 'babelfishpg_tsql' LANGUAGE C; + +CREATE OR REPLACE FUNCTION sys.pgerror() + RETURNS VARCHAR AS 'babelfishpg_tsql' LANGUAGE C; + +CREATE OR REPLACE FUNCTION sys.trancount() + RETURNS INT AS 'babelfishpg_tsql' LANGUAGE C; + +CREATE OR REPLACE FUNCTION sys.datefirst() + RETURNS INT AS 'babelfishpg_tsql' LANGUAGE C; + +CREATE OR REPLACE FUNCTION sys.options() + RETURNS INT AS 'babelfishpg_tsql' LANGUAGE C; + +CREATE OR REPLACE FUNCTION sys.version() + RETURNS sys.NVARCHAR(255) AS 'babelfishpg_tsql' LANGUAGE C; + +CREATE OR REPLACE FUNCTION sys.servername() + RETURNS sys.NVARCHAR(128) AS 'babelfishpg_tsql' LANGUAGE C; + +-- 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() +RETURNS sys.TINYINT AS +$$ +BEGIN + RETURN 38; +END; +$$ +LANGUAGE plpgsql; + +-- not supported, only syntax support +CREATE OR REPLACE FUNCTION sys.PROCID() + RETURNS INT AS 'babelfishpg_tsql' LANGUAGE C; + +CREATE OR REPLACE FUNCTION sys.spid() +RETURNS INTEGER AS +$BODY$ +SELECT pg_backend_pid(); +$BODY$ +STRICT +LANGUAGE SQL; + +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) - 2; + IF result < 0 THEN + RAISE EXCEPTION 'Invalid output, check stack trace %', stack; + ELSE + RETURN result; + END IF; +END; +$$ +LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION sys.fetch_status() +RETURNS INT AS 'babelfishpg_tsql' LANGUAGE C; + +CREATE OR REPLACE FUNCTION sys.cursor_rows() +RETURNS INT AS 'babelfishpg_tsql' LANGUAGE C; + +CREATE OR REPLACE FUNCTION sys.cursor_status(text, text) +RETURNS INT AS 'babelfishpg_tsql' LANGUAGE C; + +-- Floor for bit +CREATE OR REPLACE FUNCTION sys.floor(sys.bit) RETURNS DOUBLE PRECISION +AS 'babelfishpg_tsql', 'bit_floor' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- Floor overloading for all int types +CREATE OR REPLACE FUNCTION sys.floor(bigint) RETURNS BIGINT +AS 'babelfishpg_tsql', 'int_floor' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.floor(int) RETURNS INT +AS 'babelfishpg_tsql', 'int_floor' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.floor(smallint) RETURNS SMALLINT +AS 'babelfishpg_tsql', 'int_floor' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.floor(tinyint) RETURNS TINYINT +AS 'babelfishpg_tsql', 'int_floor' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- Ceiling for bit +CREATE OR REPLACE FUNCTION sys.ceiling(sys.bit) RETURNS DOUBLE PRECISION +AS 'babelfishpg_tsql', 'bit_ceiling' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- Ceiling overloading for all int types +CREATE OR REPLACE FUNCTION sys.ceiling(bigint) RETURNS BIGINT +AS 'babelfishpg_tsql', 'int_ceiling' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.ceiling(int) RETURNS INT +AS 'babelfishpg_tsql', 'int_ceiling' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.ceiling(smallint) RETURNS SMALLINT +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 OR REPLACE FUNCTION sys.microsoftversion() +RETURNS INTEGER AS +$BODY$ + SELECT 201332885::INTEGER; +$BODY$ +LANGUAGE SQL IMMUTABLE STRICT PARALLEL SAFE; +CREATE OR REPLACE FUNCTION sys.APPLOCK_MODE(IN "@dbprincipal" varchar(32), + IN "@resource" varchar(255), + IN "@lockowner" varchar(32) DEFAULT 'TRANSACTION') +RETURNS TEXT +AS 'babelfishpg_tsql', 'APPLOCK_MODE' LANGUAGE C; + +CREATE OR REPLACE FUNCTION sys.APPLOCK_TEST(IN "@dbprincipal" varchar(32), + IN "@resource" varchar(255), + IN "@lockmode" varchar(32), + IN "@lockowner" varchar(32) DEFAULT 'TRANSACTION') +RETURNS SMALLINT +AS 'babelfishpg_tsql', 'APPLOCK_TEST' LANGUAGE C; + +-- Error handling functions +CREATE OR REPLACE FUNCTION sys.xact_state() +RETURNS SMALLINT +AS 'babelfishpg_tsql', 'xact_state' LANGUAGE C; + +CREATE OR REPLACE FUNCTION sys.error_line() +RETURNS INT +AS 'babelfishpg_tsql', 'pltsql_error_line' LANGUAGE C; + +CREATE OR REPLACE FUNCTION sys.error_message() +RETURNS sys.NVARCHAR(4000) +AS 'babelfishpg_tsql', 'pltsql_error_message' LANGUAGE C; + +CREATE OR REPLACE FUNCTION sys.error_number() +RETURNS INT +AS 'babelfishpg_tsql', 'pltsql_error_number' LANGUAGE C; + +CREATE OR REPLACE FUNCTION sys.error_procedure() +RETURNS sys.NVARCHAR(128) +AS 'babelfishpg_tsql', 'pltsql_error_procedure' LANGUAGE C; + +CREATE OR REPLACE FUNCTION sys.error_severity() +RETURNS INT +AS 'babelfishpg_tsql', 'pltsql_error_severity' LANGUAGE C; + +CREATE OR REPLACE FUNCTION sys.error_state() +RETURNS INT +AS 'babelfishpg_tsql', 'pltsql_error_state' LANGUAGE C; + +CREATE OR REPLACE FUNCTION sys.rand() RETURNS FLOAT AS +$$ + SELECT random(); +$$ +LANGUAGE SQL VOLATILE STRICT PARALLEL RESTRICTED; + +CREATE OR REPLACE FUNCTION sys.DEFAULT_DOMAIN() +RETURNS TEXT +AS 'babelfishpg_tsql', 'default_domain' LANGUAGE C; + +CREATE OR REPLACE FUNCTION sys.db_id(sys.nvarchar(128)) RETURNS SMALLINT +AS 'babelfishpg_tsql', 'babelfish_db_id' +LANGUAGE C PARALLEL SAFE IMMUTABLE; + +CREATE OR REPLACE FUNCTION sys.db_id() RETURNS SMALLINT +AS 'babelfishpg_tsql', 'babelfish_db_id' +LANGUAGE C PARALLEL SAFE IMMUTABLE; + +CREATE OR REPLACE FUNCTION sys.db_name(int) RETURNS sys.nvarchar(128) +AS 'babelfishpg_tsql', 'babelfish_db_name' +LANGUAGE C PARALLEL SAFE IMMUTABLE; + +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, '')) = '') or + ((SELECT coalesce(property_name, '')) = 'COLUMN')) THEN + IF (((SELECT coalesce(level0_object_type, '')) = 'schema') and + ((SELECT coalesce(level1_object_type, '')) = 'table') and + ((SELECT coalesce(level2_object_type, '')) = '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 = t3.table_name and + t2.relname = (SELECT coalesce(level1_object_name, '')) and + t3.column_name = (SELECT coalesce(level2_object_name, '')); + END IF; +END IF; +RETURN; +end; +$$ +LANGUAGE plpgsql; +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' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; +GRANT EXECUTE ON FUNCTION sys.exp(DOUBLE PRECISION) TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.exp(IN arg NUMERIC) +RETURNS DOUBLE PRECISION +AS +$BODY$ +SELECT sys.exp(arg::DOUBLE PRECISION); +$BODY$ +LANGUAGE SQL IMMUTABLE PARALLEL SAFE; +GRANT EXECUTE ON FUNCTION sys.exp(NUMERIC) TO PUBLIC; + +-- For numeric/decimal and float/double precision there is already inbuilt functions, +-- Following sign functions are for remaining datatypes +CREATE OR REPLACE FUNCTION sys.sign(IN arg INT) RETURNS INT AS +$BODY$ +SELECT + CASE + WHEN arg > 0 THEN 1::INT + WHEN arg < 0 THEN -1::INT + ELSE 0::INT + END; +$BODY$ +STRICT +LANGUAGE SQL IMMUTABLE PARALLEL SAFE; +GRANT EXECUTE ON FUNCTION sys.sign(INT) TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.sign(IN arg SMALLINT) RETURNS INT AS +$BODY$ +SELECT sys.sign(arg::INT); +$BODY$ +LANGUAGE SQL IMMUTABLE PARALLEL SAFE; +GRANT EXECUTE ON FUNCTION sys.sign(SMALLINT) TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.sign(IN arg SYS.TINYINT) RETURNS INT AS +$BODY$ +SELECT sys.sign(arg::INT); +$BODY$ +LANGUAGE SQL IMMUTABLE PARALLEL SAFE; +GRANT EXECUTE ON FUNCTION sys.sign(SYS.TINYINT) TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.sign(IN arg BIGINT) RETURNS BIGINT AS +$BODY$ +SELECT + CASE + WHEN arg > 0::BIGINT THEN 1::BIGINT + WHEN arg < 0::BIGINT THEN -1::BIGINT + ELSE 0::BIGINT + END; +$BODY$ +LANGUAGE SQL IMMUTABLE PARALLEL SAFE; +GRANT EXECUTE ON FUNCTION sys.sign(BIGINT) TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.sign(IN arg SYS.MONEY) RETURNS SYS.MONEY AS +$BODY$ +SELECT + CASE + WHEN arg > 0::SYS.MONEY THEN 1::SYS.MONEY + WHEN arg < 0::SYS.MONEY THEN -1::SYS.MONEY + ELSE 0::SYS.MONEY + END; +$BODY$ +LANGUAGE SQL IMMUTABLE PARALLEL SAFE; +GRANT EXECUTE ON FUNCTION sys.sign(SYS.MONEY) TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.sign(IN arg SYS.SMALLMONEY) RETURNS SYS.MONEY AS +$BODY$ +SELECT sys.sign(arg::SYS.MONEY); +$BODY$ +LANGUAGE SQL IMMUTABLE PARALLEL SAFE; +GRANT EXECUTE ON FUNCTION sys.sign(SYS.SMALLMONEY) TO PUBLIC; + +-- To handle remaining input datatypes +CREATE OR REPLACE FUNCTION sys.sign(IN arg ANYELEMENT) RETURNS SYS.FLOAT AS +$BODY$ +SELECT + sign(arg::SYS.FLOAT); +$BODY$ +LANGUAGE SQL IMMUTABLE PARALLEL SAFE; +GRANT EXECUTE ON FUNCTION sys.sign(ANYELEMENT) TO PUBLIC; + +-- Duplicate functions with arg TEXT since ANYELEMNT cannot handle type unknown. +CREATE OR REPLACE FUNCTION sys.sign(IN arg TEXT) RETURNS SYS.FLOAT AS +$BODY$ +SELECT + sign(arg::SYS.FLOAT); +$BODY$ +LANGUAGE SQL IMMUTABLE PARALLEL SAFE; +GRANT EXECUTE ON FUNCTION sys.sign(TEXT) TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.lock_timeout() +RETURNS integer +LANGUAGE plpgsql +STRICT +AS $$ +declare return_value integer; +begin + return_value := (select s.setting FROM pg_catalog.pg_settings s where name = 'lock_timeout'); + RETURN return_value; +EXCEPTION + WHEN others THEN + RETURN NULL; +END; +$$; +GRANT EXECUTE ON FUNCTION sys.lock_timeout() TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.max_connections() +RETURNS integer +LANGUAGE plpgsql +STRICT +AS $$ +declare return_value integer; +begin + return_value := (select s.setting FROM pg_catalog.pg_settings s where name = 'max_connections'); + RETURN return_value; +EXCEPTION + WHEN others THEN + RETURN NULL; +END; +$$; +GRANT EXECUTE ON FUNCTION sys.max_connections() TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.trigger_nestlevel() +RETURNS integer +LANGUAGE plpgsql +STRICT +AS $$ +declare return_value integer; +begin + return_value := (select pg_trigger_depth()); + RETURN return_value; +EXCEPTION + WHEN others THEN + RETURN NULL; +END; +$$; +GRANT EXECUTE ON FUNCTION sys.trigger_nestlevel() TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.schema_name() +RETURNS sys.sysname +LANGUAGE plpgsql +STRICT +AS $function$ +begin + RETURN (select orig_name from sys.babelfish_namespace_ext ext + where ext.nspname = (select current_schema()) and ext.dbid::oid = sys.db_id()::oid)::sys.sysname; +EXCEPTION + WHEN others THEN + RETURN NULL; +END; +$function$ +; +GRANT EXECUTE ON FUNCTION sys.schema_name() TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.original_login() +RETURNS sys.sysname +LANGUAGE plpgsql +STRICT +AS $$ +declare return_value text; +begin + RETURN (select session_user)::sys.sysname; +EXCEPTION + WHEN others THEN + RETURN NULL; +END; +$$; +GRANT EXECUTE ON FUNCTION sys.original_login() TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.columnproperty(object_id oid, property name, property_name text) +RETURNS integer +LANGUAGE plpgsql +STRICT +AS $$ + +declare extra_bytes CONSTANT integer := 4; +declare return_value integer; +begin + return_value := ( + select + case LOWER(property_name) + when 'charmaxlen' then + (select CASE WHEN a.atttypmod > 0 THEN a.atttypmod - extra_bytes ELSE NULL END from pg_catalog.pg_attribute a where a.attrelid = object_id and a.attname = property) + when 'allowsnull' then + (select CASE WHEN a.attnotnull THEN 0 ELSE 1 END from pg_catalog.pg_attribute a where a.attrelid = object_id and a.attname = property) + else + null + end + ); + + RETURN return_value::integer; +EXCEPTION + WHEN others THEN + RETURN NULL; +END; +$$; +GRANT EXECUTE ON FUNCTION sys.columnproperty(object_id oid, property name, property_name text) TO PUBLIC; + +COMMENT ON FUNCTION sys.columnproperty +IS 'This function returns column or parameter information. Currently only works with "charmaxlen", and "allowsnull" otherwise returns 0.'; + +-- substring -- +CREATE OR REPLACE FUNCTION sys.substring(string TEXT, i INTEGER, j INTEGER) +RETURNS sys.VARCHAR +AS 'babelfishpg_tsql', 'tsql_varchar_substr' LANGUAGE C IMMUTABLE PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.substring(string sys.VARCHAR, i INTEGER, j INTEGER) +RETURNS sys.VARCHAR +AS 'babelfishpg_tsql', 'tsql_varchar_substr' LANGUAGE C IMMUTABLE PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.substring(string sys.VARCHAR, i INTEGER, j INTEGER) +RETURNS sys.VARCHAR +AS 'babelfishpg_tsql', 'tsql_varchar_substr' LANGUAGE C IMMUTABLE PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.substring(string sys.NVARCHAR, i INTEGER, j INTEGER) +RETURNS sys.NVARCHAR +AS 'babelfishpg_tsql', 'tsql_varchar_substr' LANGUAGE C IMMUTABLE PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.substring(string sys.NCHAR, i INTEGER, j INTEGER) +RETURNS sys.NVARCHAR +AS 'babelfishpg_tsql', 'tsql_varchar_substr' LANGUAGE C IMMUTABLE PARALLEL SAFE; diff --git a/contrib/babelfishpg_tsql/sql/sys_languages.sql b/contrib/babelfishpg_tsql/sql/sys_languages.sql new file mode 100644 index 00000000000..6fcdfbcb5f5 --- /dev/null +++ b/contrib/babelfishpg_tsql/sql/sys_languages.sql @@ -0,0 +1,2025 @@ +/* Tsql DMLs*/ +INSERT INTO sys.syslanguages + VALUES (1, + 'ENGLISH', + 'ENGLISH (AUSTRALIA)', + NULL, + NULL, + 'AUSTRALIA', + 'EN-AU', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (2, + 'ENGLISH', + 'ENGLISH (BELGIUM)', + NULL, + NULL, + 'BELGIUM', + 'EN-BE', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (3, + 'ENGLISH', + 'ENGLISH (BELIZE)', + NULL, + NULL, + 'BELIZE', + 'EN-BZ', + jsonb_build_object('date_format', 'MDY', + 'date_first', 1, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (4, + 'ENGLISH', + 'ENGLISH (BOTSWANA)', + NULL, + NULL, + 'BOTSWANA', + 'EN-BW', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (5, + 'ENGLISH', + 'ENGLISH (CAMEROON)', + NULL, + NULL, + 'CAMEROON', + 'EN-CM', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (6, + 'ENGLISH', + 'ENGLISH (CANADA)', + NULL, + NULL, + 'CANADA', + 'EN-CA', + jsonb_build_object('date_format', 'YMD', + 'date_first', 1, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (7, + 'ENGLISH', + 'ENGLISH (ERITREA)', + NULL, + NULL, + 'ERITREA', + 'EN-ER', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (8, + 'ENGLISH', + 'ENGLISH (INDIA)', + NULL, + NULL, + 'INDIA', + 'EN-IN', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (9, + 'ENGLISH', + 'ENGLISH (IRELAND)', + NULL, + NULL, + 'IRELAND', + 'EN-IE', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (10, + 'ENGLISH', + 'ENGLISH (JAMAICA)', + NULL, + NULL, + 'JAMAICA', + 'EN-IM', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (11, + 'ENGLISH', + 'ENGLISH (KENYA)', + NULL, + NULL, + 'KENYA', + 'EN-KE', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (12, + 'ENGLISH', + 'ENGLISH (MALAYSIA)', + NULL, + NULL, + 'MALAYSIA', + 'EN-MY', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (13, + 'ENGLISH', + 'ENGLISH (MALTA)', + NULL, + NULL, + 'MALTA', + 'EN-MT', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (14, + 'ENGLISH', + 'ENGLISH (NEW ZEALAND)', + NULL, + NULL, + 'NEW ZEALAND', + 'EN-NZ', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (15, + 'ENGLISH', + 'ENGLISH (NIGERIA)', + NULL, + NULL, + 'NIGERIA', + 'EN-NG', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (16, + 'ENGLISH', + 'ENGLISH (PAKISTAN)', + NULL, + NULL, + 'PAKISTAN', + 'EN-PK', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (17, + 'ENGLISH', + 'ENGLISH (PHILIPPINES)', + NULL, + NULL, + 'PHILIPPINES', + 'EN-PH', + jsonb_build_object('date_format', 'MDY', + 'date_first', 1, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (18, + 'ENGLISH', + 'ENGLISH (PUERTO RICO)', + NULL, + NULL, + 'PUERTO RICO', + 'EN-PR', + jsonb_build_object('date_format', 'MDY', + 'date_first', 1, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (19, + 'ENGLISH', + 'ENGLISH (SINGAPORE)', + NULL, + NULL, + 'SINGAPORE', + 'EN-SG', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (20, + 'ENGLISH', + 'ENGLISH (SOUTH AFRICA)', + NULL, + NULL, + 'SOUTH AFRICA', + 'EN-ZA', + jsonb_build_object('date_format', 'YMD', + 'date_first', 1, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (21, + 'ENGLISH', + 'ENGLISH (TRINIDAD & TOBAGO)', + NULL, + NULL, + 'TRINIDAD & TOBAGO', + 'EN-TT', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (22, + 'ENGLISH', + 'ENGLISH (GREAT BRITAIN)', + 'BRITISH', + 'BRITISH ENGLISH', + 'GREAT BRITAIN', + 'EN-GB', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (23, + 'ENGLISH', + 'ENGLISH (UNITED KINGDOM)', + NULL, + NULL, + 'UNITED KINGDOM', + 'EN-UK', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (24, + 'ENGLISH', + 'ENGLISH (ENGLAND)', + NULL, + NULL, + 'ENGLAND', + 'EN-EN', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (25, + 'ENGLISH', + 'ENGLISH (UNITED STATES)', + 'US_ENGLISH', + 'ENGLISH', + 'UNITED STATES', + 'EN-US', + jsonb_build_object('date_format', 'MDY', + 'date_first', 7, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (26, + 'ENGLISH', + 'ENGLISH (ZIMBABWE)', + NULL, + NULL, + 'ZIMBABWE', + 'EN-ZW', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (27, + 'GERMAN', + 'GERMAN (AUSTRIA)', + NULL, + NULL, + 'AUSTRIA', + 'DE-AT', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'), + 'days_names', jsonb_build_array('Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag', 'Sonntag'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (28, + 'GERMAN', + 'GERMAN (BELGIUM)', + NULL, + NULL, + 'BELGIUM', + 'DE-BE', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'), + 'days_names', jsonb_build_array('Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag', 'Sonntag'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (29, + 'GERMAN', + 'GERMAN (GERMANY)', + 'DEUTSCH', + 'GERMAN', + 'GERMANY', + 'DE-DE', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag', 'Sonntag'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (30, + 'GERMAN', + 'GERMAN (LIECHTENSTEIN)', + NULL, + NULL, + 'LIECHTENSTEIN', + 'DE-LI', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'), + 'days_names', jsonb_build_array('Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag', 'Sonntag'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (31, + 'GERMAN', + 'GERMAN (LUXEMBOURG)', + NULL, + NULL, + 'LUXEMBOURG', + 'DE-LU', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'), + 'days_names', jsonb_build_array('Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag', 'Sonntag'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (32, + 'GERMAN', + 'GERMAN (SWITZERLAND)', + NULL, + NULL, + 'SWITZERLAND', + 'DE-CH', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'), + 'days_names', jsonb_build_array('Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag', 'Sonntag'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (33, + 'FRENCH', + 'FRENCH (ALGERIA)', + NULL, + NULL, + 'ALGERIA', + 'FR-DZ', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'), + 'months_shortnames', jsonb_build_array('janv', 'févr', 'mars', 'avr', 'mai', 'juin', 'juil', 'août', 'sept', 'oct', 'nov', 'déc'), + 'days_names', jsonb_build_array('lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi', 'dimanche'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (34, + 'FRENCH', + 'FRENCH (BELGIUM)', + NULL, + NULL, + 'BELGIUM', + 'FR-BE', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'), + 'months_shortnames', jsonb_build_array('janv', 'févr', 'mars', 'avr', 'mai', 'juin', 'juil', 'août', 'sept', 'oct', 'nov', 'déc'), + 'days_names', jsonb_build_array('lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi', 'dimanche'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (35, + 'FRENCH', + 'FRENCH (CAMEROON)', + NULL, + NULL, + 'CAMEROON', + 'FR-CM', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'), + 'months_shortnames', jsonb_build_array('janv', 'févr', 'mars', 'avr', 'mai', 'juin', 'juil', 'août', 'sept', 'oct', 'nov', 'déc'), + 'days_names', jsonb_build_array('lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi', 'dimanche'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (36, + 'FRENCH', + 'FRENCH (CANADA)', + NULL, + NULL, + 'CANADA', + 'FR-CA', + jsonb_build_object('date_format', 'YMD', + 'date_first', 1, + 'months_names', jsonb_build_array('janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'), + 'months_shortnames', jsonb_build_array('janv', 'févr', 'mars', 'avr', 'mai', 'juin', 'juil', 'août', 'sept', 'oct', 'nov', 'déc'), + 'days_names', jsonb_build_array('lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi', 'dimanche'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (37, + 'FRENCH', + 'FRENCH (FRANCE)', + 'FRANÇAIS', + 'FRENCH', + 'FRANCE', + 'FR-FR', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'), + 'months_shortnames', jsonb_build_array('janv', 'févr', 'mars', 'avr', 'mai', 'juin', 'juil', 'août', 'sept', 'oct', 'nov', 'déc'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi', 'dimanche'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (38, + 'FRENCH', + 'FRENCH (HAITI)', + NULL, + NULL, + 'HAITI', + 'FR-HT', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'), + 'months_shortnames', jsonb_build_array('janv', 'févr', 'mars', 'avr', 'mai', 'juin', 'juil', 'août', 'sept', 'oct', 'nov', 'déc'), + 'days_names', jsonb_build_array('lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi', 'dimanche'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (39, + 'FRENCH', + 'FRENCH (LUXEMBOURG)', + NULL, + NULL, + 'LUXEMBOURG', + 'FR-LU', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'), + 'months_shortnames', jsonb_build_array('janv', 'févr', 'mars', 'avr', 'mai', 'juin', 'juil', 'août', 'sept', 'oct', 'nov', 'déc'), + 'days_names', jsonb_build_array('lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi', 'dimanche'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (40, + 'FRENCH', + 'FRENCH (MALI)', + NULL, + NULL, + 'MALI', + 'FR-ML', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'), + 'months_shortnames', jsonb_build_array('janv', 'févr', 'mars', 'avr', 'mai', 'juin', 'juil', 'août', 'sept', 'oct', 'nov', 'déc'), + 'days_names', jsonb_build_array('lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi', 'dimanche'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (41, + 'FRENCH', + 'FRENCH (MONACO)', + NULL, + NULL, + 'MONACO', + 'FR-MC', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'), + 'months_shortnames', jsonb_build_array('janv', 'févr', 'mars', 'avr', 'mai', 'juin', 'juil', 'août', 'sept', 'oct', 'nov', 'déc'), + 'days_names', jsonb_build_array('lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi', 'dimanche'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (42, + 'FRENCH', + 'FRENCH (MOROCCO)', + NULL, + NULL, + 'MOROCCO', + 'FR-MA', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'), + 'months_shortnames', jsonb_build_array('janv', 'févr', 'mars', 'avr', 'mai', 'juin', 'juil', 'août', 'sept', 'oct', 'nov', 'déc'), + 'days_names', jsonb_build_array('lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi', 'dimanche'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (43, + 'FRENCH', + 'FRENCH (SENEGAL)', + NULL, + NULL, + 'SENEGAL', + 'FR-SN', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'), + 'months_shortnames', jsonb_build_array('janv', 'févr', 'mars', 'avr', 'mai', 'juin', 'juil', 'août', 'sept', 'oct', 'nov', 'déc'), + 'days_names', jsonb_build_array('lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi', 'dimanche'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (44, + 'FRENCH', + 'FRENCH (SWITZERLAND)', + NULL, + NULL, + 'SWITZERLAND', + 'FR-CH', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'), + 'months_shortnames', jsonb_build_array('janv', 'févr', 'mars', 'avr', 'mai', 'juin', 'juil', 'août', 'sept', 'oct', 'nov', 'déc'), + 'days_names', jsonb_build_array('lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi', 'dimanche'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (45, + 'FRENCH', + 'FRENCH (SYRIA)', + NULL, + NULL, + 'SYRIA', + 'FR-SY', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'), + 'months_shortnames', jsonb_build_array('janv', 'févr', 'mars', 'avr', 'mai', 'juin', 'juil', 'août', 'sept', 'oct', 'nov', 'déc'), + 'days_names', jsonb_build_array('lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi', 'dimanche'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (46, + 'FRENCH', + 'FRENCH (TUNISIA)', + NULL, + NULL, + 'TUNISIA', + 'FR-TN', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'), + 'months_shortnames', jsonb_build_array('janv', 'févr', 'mars', 'avr', 'mai', 'juin', 'juil', 'août', 'sept', 'oct', 'nov', 'déc'), + 'days_names', jsonb_build_array('lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi', 'dimanche'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (47, + 'JAPANESE', + 'JAPANESE (JAPAN)', + '日本語', + 'JAPANESE', + 'JAPAN', + 'JA-JP', + jsonb_build_object('date_format', 'YMD', + 'date_first', 7, + 'months_names', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('月曜日', '火曜日', '水曜日', '木曜日', '金曜日', '土曜日', '日曜日'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (48, + 'DANISH', + 'DANISH (DENMARK)', + 'DANSK', + 'DANISH', + 'DENMARK', + 'DA-DK', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('januar', 'februar', 'marts', 'april', 'maj', 'juni', 'juli', 'august', 'september', 'oktober', 'november', 'december'), + 'months_shortnames', jsonb_build_array('jan', 'feb', 'mar', 'apr', 'maj', 'jun', 'jul', 'aug', 'sep', 'okt', 'nov', 'dec'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('mandag', 'tirsdag', 'onsdag', 'torsdag', 'fredag', 'lørdag', 'søndag'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (49, + 'DANISH', + 'DANISH (GREENLAND)', + NULL, + NULL, + 'GREENLAND', + 'DA-GL', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('januar', 'februar', 'marts', 'april', 'maj', 'juni', 'juli', 'august', 'september', 'oktober', 'november', 'december'), + 'months_shortnames', jsonb_build_array('jan', 'feb', 'mar', 'apr', 'maj', 'jun', 'jul', 'aug', 'sep', 'okt', 'nov', 'dec'), + 'days_names', jsonb_build_array('mandag', 'tirsdag', 'onsdag', 'torsdag', 'fredag', 'lørdag', 'søndag'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (50, + 'SPANISH', + 'SPANISH (ARGENTINA)', + NULL, + NULL, + 'ARGENTINA', + 'ES-AR', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'), + 'months_shortnames', jsonb_build_array('Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'), + 'days_names', jsonb_build_array('Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (51, + 'SPANISH', + 'SPANISH (BOLIVIA)', + NULL, + NULL, + 'BOLIVIA', + 'ES-BO', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'), + 'months_shortnames', jsonb_build_array('Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'), + 'days_names', jsonb_build_array('Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (52, + 'SPANISH', + 'SPANISH (CHILE)', + NULL, + NULL, + 'CHILE', + 'ES-CL', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'), + 'months_shortnames', jsonb_build_array('Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'), + 'days_names', jsonb_build_array('Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (53, + 'SPANISH', + 'SPANISH (COLOMBIA)', + NULL, + NULL, + 'COLOMBIA', + 'ES-CO', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'), + 'months_shortnames', jsonb_build_array('Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'), + 'days_names', jsonb_build_array('Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (54, + 'SPANISH', + 'SPANISH (COSTA RICA)', + NULL, + NULL, + 'COSTA RICA', + 'ES-CR', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'), + 'months_shortnames', jsonb_build_array('Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'), + 'days_names', jsonb_build_array('Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (55, + 'SPANISH', + 'SPANISH (CUBA)', + NULL, + NULL, + 'CUBA', + 'ES-CU', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'), + 'months_shortnames', jsonb_build_array('Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'), + 'days_names', jsonb_build_array('Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (56, + 'SPANISH', + 'SPANISH (DOMINICAN REPUBLIC)', + NULL, + NULL, + 'DOMINICAN REPUBLIC', + 'ES-DO', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'), + 'months_shortnames', jsonb_build_array('Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'), + 'days_names', jsonb_build_array('Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (57, + 'SPANISH', + 'SPANISH (ECUADOR)', + NULL, + NULL, + 'ECUADOR', + 'ES-EC', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'), + 'months_shortnames', jsonb_build_array('Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'), + 'days_names', jsonb_build_array('Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (58, + 'SPANISH', + 'SPANISH (EL SALVADOR)', + NULL, + NULL, + 'EL SALVADOR', + 'ES-SV', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'), + 'months_shortnames', jsonb_build_array('Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'), + 'days_names', jsonb_build_array('Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (59, + 'SPANISH', + 'SPANISH (GUATEMALA)', + NULL, + NULL, + 'GUATEMALA', + 'ES-GT', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'), + 'months_shortnames', jsonb_build_array('Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'), + 'days_names', jsonb_build_array('Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (60, + 'SPANISH', + 'SPANISH (HONDURASALA)', + NULL, + NULL, + 'HONDURAS', + 'ES-HN', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'), + 'months_shortnames', jsonb_build_array('Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'), + 'days_names', jsonb_build_array('Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (61, + 'SPANISH', + 'SPANISH (MEXICO)', + NULL, + NULL, + 'MEXICO', + 'ES-MX', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'), + 'months_shortnames', jsonb_build_array('Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'), + 'days_names', jsonb_build_array('Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (62, + 'SPANISH', + 'SPANISH (NICARAGUA)', + NULL, + NULL, + 'NICARAGUA', + 'ES-NI', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'), + 'months_shortnames', jsonb_build_array('Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'), + 'days_names', jsonb_build_array('Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (63, + 'SPANISH', + 'SPANISH (PANAMA)', + NULL, + NULL, + 'PANAMA', + 'ES-PA', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'), + 'months_shortnames', jsonb_build_array('Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'), + 'days_names', jsonb_build_array('Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (64, + 'SPANISH', + 'SPANISH (PARAGUAY)', + NULL, + NULL, + 'PARAGUAY', + 'ES-PY', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'), + 'months_shortnames', jsonb_build_array('Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'), + 'days_names', jsonb_build_array('Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (65, + 'SPANISH', + 'SPANISH (PERU)', + NULL, + NULL, + 'PERU', + 'ES-PE', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'), + 'months_shortnames', jsonb_build_array('Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'), + 'days_names', jsonb_build_array('Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (66, + 'SPANISH', + 'SPANISH (PHILIPPINES)', + NULL, + NULL, + 'PHILIPPINES', + 'ES-PH', + jsonb_build_object('date_format', 'MDY', + 'date_first', 1, + 'months_names', jsonb_build_array('Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'), + 'months_shortnames', jsonb_build_array('Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'), + 'days_names', jsonb_build_array('Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (67, + 'SPANISH', + 'SPANISH (PUERTO RICO)', + NULL, + NULL, + 'PUERTO RICO', + 'ES-PR', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'), + 'months_shortnames', jsonb_build_array('Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'), + 'days_names', jsonb_build_array('Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (68, + 'SPANISH', + 'SPANISH (SPAIN)', + 'ESPAÑOL', + 'SPANISH', + 'SPAIN', + 'ES-ES', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'), + 'months_shortnames', jsonb_build_array('Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (69, + 'SPANISH', + 'SPANISH (UNITED STATES)', + NULL, + NULL, + 'UNITED STATES', + 'ES-US', + jsonb_build_object('date_format', 'MDY', + 'date_first', 1, + 'months_names', jsonb_build_array('Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'), + 'months_shortnames', jsonb_build_array('Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'), + 'days_names', jsonb_build_array('Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (70, + 'SPANISH', + 'SPANISH (URUGUAY)', + NULL, + NULL, + 'URUGUAY', + 'ES-UY', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'), + 'months_shortnames', jsonb_build_array('Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'), + 'days_names', jsonb_build_array('Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (71, + 'SPANISH', + 'SPANISH (VENEZUELA)', + NULL, + NULL, + 'VENEZUELA', + 'ES-VE', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'), + 'months_shortnames', jsonb_build_array('Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'), + 'days_names', jsonb_build_array('Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (72, + 'ITALIAN', + 'ITALIAN (ITALY)', + 'ITALIANO', + 'ITALIAN', + 'ITALY', + 'IT-IT', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('gennaio', 'febbraio', 'marzo', 'aprile', 'maggio', 'giugno', 'luglio', 'agosto', 'settembre', 'ottobre', 'novembre', 'dicembre'), + 'months_shortnames', jsonb_build_array('gen', 'feb', 'mar', 'apr', 'mag', 'giu', 'lug', 'ago', 'set', 'ott', 'nov', 'dic'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('lunedì', 'martedì', 'mercoledì', 'giovedì', 'venerdì', 'sabato', 'domenica'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (73, + 'ITALIAN', + 'ITALIAN (SWITZERLAND)', + NULL, + NULL, + 'SWITZERLAND', + 'IT-CH', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('gennaio', 'febbraio', 'marzo', 'aprile', 'maggio', 'giugno', 'luglio', 'agosto', 'settembre', 'ottobre', 'novembre', 'dicembre'), + 'months_shortnames', jsonb_build_array('gen', 'feb', 'mar', 'apr', 'mag', 'giu', 'lug', 'ago', 'set', 'ott', 'nov', 'dic'), + 'days_names', jsonb_build_array('lunedì', 'martedì', 'mercoledì', 'giovedì', 'venerdì', 'sabato', 'domenica'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (74, + 'DUTCH', + 'DUTCH (BELGIUM)', + NULL, + NULL, + 'BELGIUM', + 'NL-BE', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('januari', 'februari', 'maart', 'april', 'mei', 'juni', 'juli', 'augustus', 'september', 'oktober', 'november', 'december'), + 'months_shortnames', jsonb_build_array('jan', 'feb', 'mrt', 'apr', 'mei', 'jun', 'jul', 'aug', 'sep', 'okt', 'nov', 'dec'), + 'days_names', jsonb_build_array('maandag', 'dinsdag', 'woensdag', 'donderdag', 'vrijdag', 'zaterdag', 'zondag'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (75, + 'DUTCH', + 'DUTCH (NETHERLANDS)', + 'NEDERLANDS', + 'DUTCH', + 'NETHERLANDS', + 'NL-NL', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('januari', 'februari', 'maart', 'april', 'mei', 'juni', 'juli', 'augustus', 'september', 'oktober', 'november', 'december'), + 'months_shortnames', jsonb_build_array('jan', 'feb', 'mrt', 'apr', 'mei', 'jun', 'jul', 'aug', 'sep', 'okt', 'nov', 'dec'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('maandag', 'dinsdag', 'woensdag', 'donderdag', 'vrijdag', 'zaterdag', 'zondag'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (76, + 'NORWEGIAN', + 'NORWEGIAN (NORWAY)', + NULL, + NULL, + 'NORWAY', + 'NO-NO', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('januar', 'februar', 'mars', 'april', 'mai', 'juni', 'juli', 'august', 'september', 'oktober', 'november', 'desember'), + 'months_shortnames', jsonb_build_array('jan', 'feb', 'mar', 'apr', 'mai', 'jun', 'jul', 'aug', 'sep', 'okt', 'nov', 'des'), + 'days_names', jsonb_build_array('mandag', 'tirsdag', 'onsdag', 'torsdag', 'fredag', 'lørdag', 'søndag'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (77, + 'NORWEGIAN (MS SQL)', + 'NORWEGIAN NYNORSK (NORWAY)', + 'NORSK', + 'NORWEGIAN', + 'NORWAY', + 'NN-NO', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('januar', 'februar', 'mars', 'april', 'mai', 'juni', 'juli', 'august', 'september', 'oktober', 'november', 'desember'), + 'months_shortnames', jsonb_build_array('jan', 'feb', 'mar', 'apr', 'mai', 'jun', 'jul', 'aug', 'sep', 'okt', 'nov', 'des'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('mandag', 'tirsdag', 'onsdag', 'torsdag', 'fredag', 'lørdag', 'søndag'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (78, + 'PORTUGUESE', + 'PORTUGUESE (BRAZIL)', + 'PORTUGUESE', + 'BRAZILIAN', + 'BRAZIL', + 'PT-BR', + jsonb_build_object('date_format', 'DMY', + 'date_first', 7, + 'months_names', jsonb_build_array('janeiro', 'fevereiro', 'março', 'abril', 'maio', 'junho', 'julho', 'agosto', 'setembro', 'outubro', 'novembro', 'dezembro'), + 'months_shortnames', jsonb_build_array('jan', 'fev', 'mar', 'abr', 'mai', 'jun', 'jul', 'ago', 'set', 'out', 'nov', 'dez'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('segunda-feira', 'terça-feira', 'quarta-feira', 'quinta-feira', 'sexta-feira', 'sábado', 'domingo'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (79, + 'PORTUGUESE', + 'PORTUGUESE (PORTUGAL)', + 'PORTUGUÊS', + 'PORTUGUESE', + 'PORTUGAL', + 'PT-PT', + jsonb_build_object('date_format', 'DMY', + 'date_first', 7, + 'months_names', jsonb_build_array('janeiro', 'fevereiro', 'março', 'abril', 'maio', 'junho', 'julho', 'agosto', 'setembro', 'outubro', 'novembro', 'dezembro'), + 'months_shortnames', jsonb_build_array('jan', 'fev', 'mar', 'abr', 'mai', 'jun', 'jul', 'ago', 'set', 'out', 'nov', 'dez'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('segunda-feira', 'terça-feira', 'quarta-feira', 'quinta-feira', 'sexta-feira', 'sábado', 'domingo'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (80, + 'FINNISH', + 'FINNISH (FINLAND)', + NULL, + NULL, + 'FINLAND', + 'FI-FI', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('tammikuuta', 'helmikuuta', 'maaliskuuta', 'huhtikuuta', 'toukokuuta', 'kesäkuuta', 'heinäkuuta', 'elokuuta', 'syyskuuta', 'lokakuuta', 'marraskuuta', 'joulukuuta'), + 'months_shortnames', jsonb_build_array('tammi', 'helmi', 'maalis', 'huhti', 'touko', 'kesä', 'heinä', 'elo', 'syys', 'loka', 'marras', 'joulu'), + 'days_names', jsonb_build_array('maanantai', 'tiistai', 'keskiviikko', 'torstai', 'perjantai', 'lauantai', 'sunnuntai'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (81, + 'FINNISH (MS SQL)', + 'FINNISH (FINLAND)', + 'SUOMI', + 'FINNISH', + 'FINLAND', + 'FI', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('tammikuuta', 'helmikuuta', 'maaliskuuta', 'huhtikuuta', 'toukokuuta', 'kesäkuuta', 'heinäkuuta', 'elokuuta', 'syyskuuta', 'lokakuuta', 'marraskuuta', 'joulukuuta'), + 'months_shortnames', jsonb_build_array('tammi', 'helmi', 'maalis', 'huhti', 'touko', 'kesä', 'heinä', 'elo', 'syys', 'loka', 'marras', 'joulu'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('maanantai', 'tiistai', 'keskiviikko', 'torstai', 'perjantai', 'lauantai', 'sunnuntai'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (82, + 'SWEDISH', + 'SWEDISH (FINLAND)', + NULL, + NULL, + 'FINLAND', + 'SV-FI', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('januari', 'februari', 'mars', 'april', 'maj', 'juni', 'juli', 'augusti', 'september', 'oktober', 'november', 'december'), + 'months_shortnames', jsonb_build_array('jan', 'feb', 'mar', 'apr', 'maj', 'jun', 'jul', 'aug', 'sep', 'okt', 'nov', 'dec'), + 'days_names', jsonb_build_array('måndag', 'tisdag', 'onsdag', 'torsdag', 'fredag', 'lördag', 'söndag'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (83, + 'SWEDISH', + 'SWEDISH (SWEDEN)', + 'SVENSKA', + 'SWEDISH', + 'SWEDEN', + 'SV-SE', + jsonb_build_object('date_format', 'YMD', + 'date_first', 1, + 'months_names', jsonb_build_array('januari', 'februari', 'mars', 'april', 'maj', 'juni', 'juli', 'augusti', 'september', 'oktober', 'november', 'december'), + 'months_shortnames', jsonb_build_array('jan', 'feb', 'mar', 'apr', 'maj', 'jun', 'jul', 'aug', 'sep', 'okt', 'nov', 'dec'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('måndag', 'tisdag', 'onsdag', 'torsdag', 'fredag', 'lördag', 'söndag'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (84, + 'CZECH', + 'CZECH (CZECH REPUBLIC)', + 'ČEŠTINA', + 'CZECH', + 'CZECHIA', + 'CS-CZ', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('leden', 'únor', 'březen', 'duben', 'květen', 'červen', 'červenec', 'srpen', 'září', 'říjen', 'listopad', 'prosinec'), + 'months_shortnames', jsonb_build_array('I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX', 'X', 'XI', 'XII'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('pondělí', 'úterý', 'středa', 'čtvrtek', 'pátek', 'sobota', 'neděle'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (85, + 'HUNGARIAN', + 'HUNGARIAN (HUNGARY)', + 'MAGYAR', + 'HUNGARIAN', + 'HUNGARY', + 'HU-HU', + jsonb_build_object('date_format', 'YMD', + 'date_first', 1, + 'months_names', jsonb_build_array('január', 'február', 'március', 'április', 'május', 'június', 'július', 'augusztus', 'szeptember', 'október', 'november', 'december'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'days_names', jsonb_build_array('hétfő', 'kedd', 'szerda', 'csütörtök', 'péntek', 'szombat', 'vasárnap'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (86, + 'POLISH', + 'POLISH (POLAND)', + 'POLSKI', + 'POLISH', + 'POLAND', + 'PL-PL', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('styczeń', 'luty', 'marzec', 'kwiecień', 'maj', 'czerwiec', 'lipiec', 'sierpień', 'wrzesień', 'październik', 'listopad', 'grudzień'), + 'months_shortnames', jsonb_build_array('I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX', 'X', 'XI', 'XII'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('poniedziałek', 'wtorek', 'środa', 'czwartek', 'piątek', 'sobota', 'niedziela'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (87, + 'ROMANIAN', + 'ROMANIAN (MOLDOVA)', + NULL, + NULL, + 'MOLDOVA', + 'RO-MD', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('ianuarie', 'februarie', 'martie', 'aprilie', 'mai', 'iunie', 'iulie', 'august', 'septembrie', 'octombrie', 'noiembrie', 'decembrie'), + 'months_shortnames', jsonb_build_array('Ian', 'Feb', 'Mar', 'Apr', 'Mai', 'Iun', 'Iul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('luni', 'marţi', 'miercuri', 'joi', 'vineri', 'sîmbătă', 'duminică'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (88, + 'ROMANIAN', + 'ROMANIAN (ROMANIA)', + 'ROMÂNĂ', + 'ROMANIAN', + 'ROMANIA', + 'RO-RO', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('ianuarie', 'februarie', 'martie', 'aprilie', 'mai', 'iunie', 'iulie', 'august', 'septembrie', 'octombrie', 'noiembrie', 'decembrie'), + 'months_shortnames', jsonb_build_array('Ian', 'Feb', 'Mar', 'Apr', 'Mai', 'Iun', 'Iul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('luni', 'marţi', 'miercuri', 'joi', 'vineri', 'sîmbătă', 'duminică'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (89, + 'CROATIAN', + 'CROATIAN (CROATIA)', + 'HRVATSKI', + 'CROATIAN', + 'CROATIA', + 'HR-HR', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('siječanj', 'veljača', 'ožujak', 'travanj', 'svibanj', 'lipanj', 'srpanj', 'kolovoz', 'rujan', 'listopad', 'studeni', 'prosinac'), + 'months_shortnames', jsonb_build_array('sij', 'vel', 'ožu', 'tra', 'svi', 'lip', 'srp', 'kol', 'ruj', 'lis', 'stu', 'pro'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('ponedjeljak', 'utorak', 'srijeda', 'četvrtak', 'petak', 'subota', 'nedjelja'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (90, + 'SLOVAK', + 'SLOVAK (SLOVAKIA)', + 'SLOVENČINA', + 'SLOVAK', + 'SLOVAKIA', + 'SK-SK', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('január', 'február', 'marec', 'apríl', 'máj', 'jún', 'júl', 'august', 'september', 'október', 'november', 'december'), + 'months_shortnames', jsonb_build_array('I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX', 'X', 'XI', 'XII'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('pondelok', 'utorok', 'streda', 'štvrtok', 'piatok', 'sobota', 'nedeľa'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (91, + 'SLOVENIAN', + 'SLOVENIAN (SLOVENIA)', + 'SLOVENSKI', + 'SLOVENIAN', + 'SLOVENIA', + 'SL-SI', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('januar', 'februar', 'marec', 'april', 'maj', 'junij', 'julij', 'avgust', 'september', 'oktober', 'november', 'december'), + 'months_shortnames', jsonb_build_array('jan', 'feb', 'mar', 'apr', 'maj', 'jun', 'jul', 'avg', 'sept', 'okt', 'nov', 'dec'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('ponedeljek', 'torek', 'sreda', 'četrtek', 'petek', 'sobota', 'nedelja'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (92, + 'GREEK', + 'GREEK (GREECE)', + 'ΕΛΛΗΝΙΚΆ', + 'GREEK', + 'GREECE', + 'EL-GR', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Ιανουαρίου', 'Φεβρουαρίου', 'Μαρτίου', 'Απριλίου', 'Μα_ου', 'Ιουνίου', 'Ιουλίου', 'Αυγούστου', 'Σεπτεμβρίου', 'Οκτωβρίου', 'Νοεμβρίου', 'Δεκεμβρίου'), + 'months_shortnames', jsonb_build_array('Ιαν', 'Φεβ', 'Μαρ', 'Απρ', 'Μαϊ', 'Ιουν', 'Ιουλ', 'Αυγ', 'Σεπ', 'Οκτ', 'Νοε', 'Δεκ'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Δευτέρα', 'Τρίτη', 'Τετάρτη', 'Πέμπτη', 'Παρασκευή', 'Σάββατο', 'Κυριακή'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (93, + 'BULGARIAN', + 'BULGARIAN (BULGARIA)', + 'БЪЛГАРСКИ', + 'BULGARIAN', + 'BULGARIA', + 'BG-BG', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('януари', 'февруари', 'март', 'април', 'май', 'юни', 'юли', 'август', 'септември', 'октомври', 'ноември', 'декември'), + 'months_shortnames', jsonb_build_array('януари', 'февруари', 'март', 'април', 'май', 'юни', 'юли', 'август', 'септември', 'октомври', 'ноември', 'декември'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('понеделник', 'вторник', 'сряда', 'четвъртък', 'петък', 'събота', 'неделя'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (94, + 'RUSSIAN', + 'RUSSIAN (BELARUS)', + NULL, + NULL, + 'BELARUS', + 'RU-BY', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь'), + 'months_shortnames', jsonb_build_array('янв', 'фев', 'мар', 'апр', 'май', 'июн', 'июл', 'авг', 'сен', 'окт', 'ноя', 'дек'), + 'days_names', jsonb_build_array('понедельник', 'вторник', 'среда', 'четверг', 'пятница', 'суббота', 'воскресенье'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (95, + 'RUSSIAN', + 'RUSSIAN (KAZAKHSTAN)', + NULL, + NULL, + 'KAZAKHSTAN', + 'RU-KZ', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь'), + 'months_shortnames', jsonb_build_array('янв', 'фев', 'мар', 'апр', 'май', 'июн', 'июл', 'авг', 'сен', 'окт', 'ноя', 'дек'), + 'days_names', jsonb_build_array('понедельник', 'вторник', 'среда', 'четверг', 'пятница', 'суббота', 'воскресенье'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (96, + 'RUSSIAN', + 'RUSSIAN (KYRGYZSTAN)', + NULL, + NULL, + 'KYRGYZSTAN', + 'RU-KG', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь'), + 'months_shortnames', jsonb_build_array('янв', 'фев', 'мар', 'апр', 'май', 'июн', 'июл', 'авг', 'сен', 'окт', 'ноя', 'дек'), + 'days_names', jsonb_build_array('понедельник', 'вторник', 'среда', 'четверг', 'пятница', 'суббота', 'воскресенье'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (97, + 'RUSSIAN', + 'RUSSIAN (MOLDOVA)', + NULL, + NULL, + 'MOLDOVA', + 'RU-MD', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь'), + 'months_shortnames', jsonb_build_array('янв', 'фев', 'мар', 'апр', 'май', 'июн', 'июл', 'авг', 'сен', 'окт', 'ноя', 'дек'), + 'days_names', jsonb_build_array('понедельник', 'вторник', 'среда', 'четверг', 'пятница', 'суббота', 'воскресенье'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (98, + 'RUSSIAN', + 'RUSSIAN (RUSSIA)', + 'РУССКИЙ', + 'RUSSIAN', + 'RUSSIA', + 'RU-RU', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь'), + 'months_shortnames', jsonb_build_array('янв', 'фев', 'мар', 'апр', 'май', 'июн', 'июл', 'авг', 'сен', 'окт', 'ноя', 'дек'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('понедельник', 'вторник', 'среда', 'четверг', 'пятница', 'суббота', 'воскресенье'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (99, + 'RUSSIAN', + 'RUSSIAN (UKRAINE)', + NULL, + NULL, + 'UKRAINE', + 'RU-UA', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь'), + 'months_shortnames', jsonb_build_array('янв', 'фев', 'мар', 'апр', 'май', 'июн', 'июл', 'авг', 'сен', 'окт', 'ноя', 'дек'), + 'days_names', jsonb_build_array('понедельник', 'вторник', 'среда', 'четверг', 'пятница', 'суббота', 'воскресенье'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (100, + 'TURKISH', + 'TURKISH (TURKEY)', + 'TÜRKÇE', + 'TURKISH', + 'TURKEY', + 'TR-TR', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Ocak', 'Şubat', 'Mart', 'Nisan', 'Mayıs', 'Haziran', 'Temmuz', 'Ağustos', 'Eylül', 'Ekim', 'Kasım', 'Aralık'), + 'months_shortnames', jsonb_build_array('Oca', 'Şub', 'Mar', 'Nis', 'May', 'Haz', 'Tem', 'Ağu', 'Eyl', 'Eki', 'Kas', 'Ara'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Pazartesi', 'Salı', 'Çarşamba', 'Perşembe', 'Cuma', 'Cumartesi', 'Pazar'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (101, + 'ESTONIAN', + 'ESTONIAN (ESTONIA)', + 'EESTI', + 'ESTONIAN', + 'ESTONIA', + 'ET-EE', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('jaanuar', 'veebruar', 'märts', 'aprill', 'mai', 'juuni', 'juuli', 'august', 'september', 'oktoober', 'november', 'detsember'), + 'months_shortnames', jsonb_build_array('jaan', 'veebr', 'märts', 'apr', 'mai', 'juuni', 'juuli', 'aug', 'sept', 'okt', 'nov', 'dets'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('esmaspäev', 'teisipäev', 'kolmapäev', 'neljapäev', 'reede', 'laupäev', 'pühapäev'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (102, + 'LATVIAN', + 'LATVIAN (LATVIA)', + 'LATVIEŠU', + 'LATVIAN', + 'LATVIA', + 'LV-LV', + jsonb_build_object('date_format', 'YMD', + 'date_first', 1, + 'months_names', jsonb_build_array('janvāris', 'februāris', 'marts', 'aprīlis', 'maijs', 'jūnijs', 'jūlijs', 'augusts', 'septembris', 'oktobris', 'novembris', 'decembris'), + 'months_shortnames', jsonb_build_array('jan', 'feb', 'mar', 'apr', 'mai', 'jūn', 'jūl', 'aug', 'sep', 'okt', 'nov', 'dec'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('pirmdiena', 'otrdiena', 'trešdiena', 'ceturtdiena', 'piektdiena', 'sestdiena', 'svētdiena'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (103, + 'LITHUANIAN', + 'LITHUANIAN (LITHUANIA)', + 'LIETUVIŲ', + 'LITHUANIAN', + 'LITHUANIA', + 'LT-LT', + jsonb_build_object('date_format', 'YMD', + 'date_first', 1, + 'months_names', jsonb_build_array('sausis', 'vasaris', 'kovas', 'balandis', 'gegužė', 'birželis', 'liepa', 'rugpjūtis', 'rugsėjis', 'spalis', 'lapkritis', 'gruodis'), + 'months_shortnames', jsonb_build_array('sau', 'vas', 'kov', 'bal', 'geg', 'bir', 'lie', 'rgp', 'rgs', 'spl', 'lap', 'grd'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('pirmadienis', 'antradienis', 'trečiadienis', 'ketvirtadienis', 'penktadienis', 'šeštadienis', 'sekmadienis'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (104, + 'CHINESE (TRADITIONAL)', + 'CHINESE (TRADITIONAL, CHINA)', + '繁體中文', + 'TRADITIONAL CHINESE', + 'CHINA', + 'ZH-TW', + jsonb_build_object('date_format', 'YMD', + 'date_first', 7, + 'months_names', jsonb_build_array('一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'), + 'months_shortnames', jsonb_build_array('01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期日'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (105, + 'KOREAN', + 'KOREAN (NORTH KOREA)', + NULL, + NULL, + 'NORTH KOREA', + 'KO-KP', + jsonb_build_object('date_format', 'YMD', + 'date_first', 7, + 'months_names', jsonb_build_array('01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'), + 'months_shortnames', jsonb_build_array('01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'), + 'days_names', jsonb_build_array('월요일', '화요일', '수요일', '목요일', '금요일', '토요일', '일요일'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (106, + 'KOREAN', + 'KOREAN (SOUTH KOREA)', + '한국어', + 'KOREAN', + 'KOREA', + 'KO-KR', + jsonb_build_object('date_format', 'YMD', + 'date_first', 7, + 'months_names', jsonb_build_array('01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'), + 'months_shortnames', jsonb_build_array('01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('월요일', '화요일', '수요일', '목요일', '금요일', '토요일', '일요일'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (107, + 'CHINESE (SIMPLIFIED)', + 'CHINESE (SIMPLIFIED, CHINA)', + '简体中文', + 'SIMPLIFIED CHINESE', + 'CHINA', + 'ZH-CN', + jsonb_build_object('date_format', 'YMD', + 'date_first', 7, + 'months_names', jsonb_build_array('01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'), + 'months_shortnames', jsonb_build_array('01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期日'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'), + 'days_extrashortnames', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))); + +INSERT INTO sys.syslanguages + VALUES (108, + 'ARABIC (MS SQL)', + 'ARABIC (ARABIC)', + 'GENERAL ARABIC', + 'GENERAL ARABIC', + 'ARABIC', + 'AR', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Muharram', 'Safar', 'Rabie I', 'Rabie II', 'Jumada I', 'Jumada II', 'Rajab', 'Shaaban', 'Ramadan', 'Shawwal', 'Thou Alqadah', 'Thou Alhajja'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (109, + 'ARABIC', + 'ARABIC (ALGERIA)', + NULL, + NULL, + 'ALGERIA', + 'AR-DZ', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Muharram', 'Safar', 'Rabie I', 'Rabie II', 'Jumada I', 'Jumada II', 'Rajab', 'Shaaban', 'Ramadan', 'Shawwal', 'Thou Alqadah', 'Thou Alhajja'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (110, + 'ARABIC', + 'ARABIC (BAHRAIN)', + NULL, + NULL, + 'BAHRAIN', + 'AR-BH', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Muharram', 'Safar', 'Rabie I', 'Rabie II', 'Jumada I', 'Jumada II', 'Rajab', 'Shaaban', 'Ramadan', 'Shawwal', 'Thou Alqadah', 'Thou Alhajja'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (111, + 'ARABIC', + 'ARABIC (EGYPT)', + NULL, + NULL, + 'EGYPT', + 'AR-EG', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Muharram', 'Safar', 'Rabie I', 'Rabie II', 'Jumada I', 'Jumada II', 'Rajab', 'Shaaban', 'Ramadan', 'Shawwal', 'Thou Alqadah', 'Thou Alhajja'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (112, + 'ARABIC', + 'ARABIC (ERITREA)', + NULL, + NULL, + 'ERITREA', + 'AR-ER', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Muharram', 'Safar', 'Rabie I', 'Rabie II', 'Jumada I', 'Jumada II', 'Rajab', 'Shaaban', 'Ramadan', 'Shawwal', 'Thou Alqadah', 'Thou Alhajja'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (113, + 'ARABIC', + 'ARABIC (IRAQ)', + NULL, + NULL, + 'IRAQ', + 'AR-IQ', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Muharram', 'Safar', 'Rabie I', 'Rabie II', 'Jumada I', 'Jumada II', 'Rajab', 'Shaaban', 'Ramadan', 'Shawwal', 'Thou Alqadah', 'Thou Alhajja'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (114, + 'ARABIC', + 'ARABIC (ISRAEL)', + NULL, + NULL, + 'ISRAEL', + 'AR-IL', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Muharram', 'Safar', 'Rabie I', 'Rabie II', 'Jumada I', 'Jumada II', 'Rajab', 'Shaaban', 'Ramadan', 'Shawwal', 'Thou Alqadah', 'Thou Alhajja'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (115, + 'ARABIC', + 'ARABIC (JORDAN)', + NULL, + NULL, + 'JORDAN', + 'AR-JO', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Muharram', 'Safar', 'Rabie I', 'Rabie II', 'Jumada I', 'Jumada II', 'Rajab', 'Shaaban', 'Ramadan', 'Shawwal', 'Thou Alqadah', 'Thou Alhajja'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (116, + 'ARABIC', + 'ARABIC (KUWAIT)', + NULL, + NULL, + 'KUWAIT', + 'AR-KW', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Muharram', 'Safar', 'Rabie I', 'Rabie II', 'Jumada I', 'Jumada II', 'Rajab', 'Shaaban', 'Ramadan', 'Shawwal', 'Thou Alqadah', 'Thou Alhajja'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (117, + 'ARABIC', + 'ARABIC (LEBANON)', + NULL, + NULL, + 'LEBANON', + 'AR-LB', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Muharram', 'Safar', 'Rabie I', 'Rabie II', 'Jumada I', 'Jumada II', 'Rajab', 'Shaaban', 'Ramadan', 'Shawwal', 'Thou Alqadah', 'Thou Alhajja'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (118, + 'ARABIC', + 'ARABIC (LIBYA)', + NULL, + NULL, + 'LIBYA', + 'AR-LY', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Muharram', 'Safar', 'Rabie I', 'Rabie II', 'Jumada I', 'Jumada II', 'Rajab', 'Shaaban', 'Ramadan', 'Shawwal', 'Thou Alqadah', 'Thou Alhajja'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (119, + 'ARABIC', + 'ARABIC (MOROCCO)', + NULL, + NULL, + 'MOROCCO', + 'AR-MA', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Muharram', 'Safar', 'Rabie I', 'Rabie II', 'Jumada I', 'Jumada II', 'Rajab', 'Shaaban', 'Ramadan', 'Shawwal', 'Thou Alqadah', 'Thou Alhajja'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (120, + 'ARABIC', + 'ARABIC (OMAN)', + NULL, + NULL, + 'OMAN', + 'AR-OM', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Muharram', 'Safar', 'Rabie I', 'Rabie II', 'Jumada I', 'Jumada II', 'Rajab', 'Shaaban', 'Ramadan', 'Shawwal', 'Thou Alqadah', 'Thou Alhajja'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (121, + 'ARABIC', + 'ARABIC (QATAR)', + NULL, + NULL, + 'QATAR', + 'AR-QA', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Muharram', 'Safar', 'Rabie I', 'Rabie II', 'Jumada I', 'Jumada II', 'Rajab', 'Shaaban', 'Ramadan', 'Shawwal', 'Thou Alqadah', 'Thou Alhajja'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (122, + 'ARABIC', + 'ARABIC (SAUDI ARABIA)', + 'ARABIC', + 'ARABIC', + 'SAUDI ARABIA', + 'AR-SA', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Muharram', 'Safar', 'Rabie I', 'Rabie II', 'Jumada I', 'Jumada II', 'Rajab', 'Shaaban', 'Ramadan', 'Shawwal', 'Thou Alqadah', 'Thou Alhajja'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (123, + 'ARABIC', + 'ARABIC (SOMALIA)', + NULL, + NULL, + 'SOMALIA', + 'AR-SO', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Muharram', 'Safar', 'Rabie I', 'Rabie II', 'Jumada I', 'Jumada II', 'Rajab', 'Shaaban', 'Ramadan', 'Shawwal', 'Thou Alqadah', 'Thou Alhajja'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (124, + 'ARABIC', + 'ARABIC (SYRIA)', + NULL, + NULL, + 'SYRIA', + 'AR-SY', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Muharram', 'Safar', 'Rabie I', 'Rabie II', 'Jumada I', 'Jumada II', 'Rajab', 'Shaaban', 'Ramadan', 'Shawwal', 'Thou Alqadah', 'Thou Alhajja'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (125, + 'ARABIC', + 'ARABIC (TUNISIA)', + NULL, + NULL, + 'TUNISIA', + 'AR-TN', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Muharram', 'Safar', 'Rabie I', 'Rabie II', 'Jumada I', 'Jumada II', 'Rajab', 'Shaaban', 'Ramadan', 'Shawwal', 'Thou Alqadah', 'Thou Alhajja'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (126, + 'ARABIC', + 'ARABIC (UNITED ARAB EMIRATES)', + NULL, + NULL, + 'UNITED ARAB EMIRATES', + 'AR-AE', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Muharram', 'Safar', 'Rabie I', 'Rabie II', 'Jumada I', 'Jumada II', 'Rajab', 'Shaaban', 'Ramadan', 'Shawwal', 'Thou Alqadah', 'Thou Alhajja'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (127, + 'ARABIC', + 'ARABIC (YEMEN)', + NULL, + NULL, + 'YEMEN', + 'AR-YE', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('Muharram', 'Safar', 'Rabie I', 'Rabie II', 'Jumada I', 'Jumada II', 'Rajab', 'Shaaban', 'Ramadan', 'Shawwal', 'Thou Alqadah', 'Thou Alhajja'), + 'months_shortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (128, + 'THAI', + 'THAI (THAILAND)', + 'ไทย', + 'THAI', + 'THAILAND', + 'TH-TH', + jsonb_build_object('date_format', 'DMY', + 'date_first', 7, + 'months_names', jsonb_build_array('มกราคม', 'กุมภาพันธ์', 'มีนาคม', 'เมษายน', 'พฤษภาคม', 'มิถุนายน', 'กรกฎาคม', 'สิงหาคม', 'กันยายน', 'ตุลาคม', 'พฤศจิกายน', 'ธันวาคม'), + 'months_shortnames', jsonb_build_array('ม.ค.', 'ก.พ.', 'มี.ค.', 'เม.ย.', 'พ.ค.', 'มิ.ย.', 'ก.ค.', 'ส.ค.', 'ก.ย.', 'ต.ค.', 'พ.ย.', 'ธ.ค.'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('จันทร์', 'อังคาร', 'พุธ', 'พฤหัสบดี', 'ศุกร์', 'เสาร์', 'อาทิตย์'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); + +INSERT INTO sys.syslanguages + VALUES (129, + 'HIJRI', + 'HIJRI (ISLAMIC)', + 'HIJRI', + 'ISLAMIC', + 'ISLAMIC', + 'HI-IS', + jsonb_build_object('date_format', 'DMY', + 'date_first', 1, + 'months_names', jsonb_build_array('محرم', 'صفر', 'ربيع الاول', 'ربيع الثاني', 'جمادى الاولى', 'جمادى الثانية', 'رجب', 'شعبان', 'رمضان', 'شوال', 'ذو القعدة', 'ذو الحجة'), + 'months_shortnames', jsonb_build_array('محرم', 'صفر', 'ربيع الاول', 'ربيع الثاني', 'جمادى الاولى', 'جمادى الثانية', 'رجب', 'شعبان', 'رمضان', 'شوال', 'ذو القعدة', 'ذو الحجة'), + 'months_extranames', jsonb_build_array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), + 'months_extrashortnames', jsonb_build_array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + 'days_names', jsonb_build_array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'), + 'days_shortnames', jsonb_build_array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))); diff --git a/contrib/babelfishpg_tsql/sql/sys_procedures.sql b/contrib/babelfishpg_tsql/sql/sys_procedures.sql new file mode 100644 index 00000000000..fe4d054dafd --- /dev/null +++ b/contrib/babelfishpg_tsql/sql/sys_procedures.sql @@ -0,0 +1,153 @@ +CREATE PROCEDURE sys.sp_unprepare(IN prep_handle INTEGER) +AS 'babelfishpg_tsql', 'sp_unprepare' +LANGUAGE C; +GRANT EXECUTE ON PROCEDURE sys.sp_unprepare(IN INTEGER) TO PUBLIC; + +CREATE PROCEDURE sys.sp_prepare(INOUT prep_handle INTEGER, IN params varchar(8000), + IN stmt varchar(8000), IN options int default 1) +AS 'babelfishpg_tsql', 'sp_prepare' +LANGUAGE C; +GRANT EXECUTE ON PROCEDURE sys.sp_prepare( + INOUT INTEGER, IN varchar(8000), IN varchar(8000), IN int +) TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.sp_getapplock_function (IN "@resource" varchar(255), + IN "@lockmode" varchar(32), + IN "@lockowner" varchar(32) DEFAULT 'TRANSACTION', + IN "@locktimeout" INTEGER DEFAULT -99, + IN "@dbprincipal" varchar(32) DEFAULT 'dbo') +RETURNS INTEGER +AS 'babelfishpg_tsql', 'sp_getapplock_function' LANGUAGE C; +GRANT EXECUTE ON FUNCTION sys.sp_getapplock_function( + IN varchar(255), IN varchar(32), IN varchar(32), IN INTEGER, IN varchar(32) +) TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.sp_releaseapplock_function(IN "@resource" varchar(255), + IN "@lockowner" varchar(32) DEFAULT 'TRANSACTION', + IN "@dbprincipal" varchar(32) DEFAULT 'dbo') +RETURNS INTEGER +AS 'babelfishpg_tsql', 'sp_releaseapplock_function' LANGUAGE C; +GRANT EXECUTE ON FUNCTION sys.sp_releaseapplock_function( + IN varchar(255), IN varchar(32), IN varchar(32) +) TO PUBLIC; + +CREATE OR REPLACE PROCEDURE sys.sp_cursor_list (INOUT "@cursor_return" refcursor, + IN "@cursor_scope" INTEGER) +AS $$ +DECLARE + cur refcursor; +BEGIN + IF "@cursor_scope" >= 1 AND "@cursor_scope" <= 3 THEN + OPEN cur FOR EXECUTE 'SELECT reference_name::name, cursor_name::name, cursor_scope::smallint, status::smallint, model::smallint, concurrency::smallint, scrollable::smallint, open_status::smallint, cursor_rows::numeric(10,0), fetch_status::smallint, column_count::smallint, row_count::numeric(10,0), last_operation::smallint, cursor_handle::int FROM sys.babelfish_cursor_list($1)' USING "@cursor_scope"; + ELSE + RAISE 'invalid @cursor_scope: %', "@cursor_scope"; + END IF; + + -- PG cursor evaluates the query at first fetch. We need to evaluate table function now because cursor_list() depeneds on "current" tsql_estate(). + -- Running MOVE fowrard and backward to force evaluating sys.babelfish_cursor_list() now. + MOVE NEXT FROM cur; + MOVE PRIOR FROM cur; + SELECT cur INTO "@cursor_return"; +END; +$$ LANGUAGE plpgsql; +GRANT EXECUTE ON PROCEDURE sys.sp_cursor_list(INOUT refcursor, IN INTEGER) TO PUBLIC; + +CREATE OR REPLACE PROCEDURE sys.sp_describe_cursor (INOUT "@cursor_return" refcursor, + IN "@cursor_source" nvarchar(30), + IN "@cursor_identity" nvarchar(30)) +AS $$ +DECLARE + cur refcursor; + cursor_source int; +BEGIN + IF lower("@cursor_source") = 'local' THEN + cursor_source := 1; + ELSIF lower("@cursor_source") = 'global' THEN + cursor_source := 2; + ELSIF lower("@cursor_source") = 'variable' THEN + cursor_source := 3; + ELSE + RAISE 'invalid @cursor_source: %', "@cursor_source"; + END IF; + + OPEN cur FOR EXECUTE 'SELECT reference_name::name, cursor_name::name, cursor_scope::smallint, status::smallint, model::smallint, concurrency::smallint, scrollable::smallint, open_status::smallint, cursor_rows::numeric(10,0), fetch_status::smallint, column_count::smallint, row_count::numeric(10,0), last_operation::smallint, cursor_handle::int FROM sys.babelfish_cursor_list($1) WHERE cursor_source = $1 and reference_name = $2' USING cursor_source, "@cursor_identity"; + + -- PG cursor evaluates the query at first fetch. We need to evaluate table function now because cursor_list() depeneds on "current" tsql_estate(). + -- Running MOVE fowrard and backward to force evaluating sys.babelfish_cursor_list() now. + MOVE NEXT FROM cur; + MOVE PRIOR FROM cur; + SELECT cur INTO "@cursor_return"; +END; +$$ LANGUAGE plpgsql; +GRANT EXECUTE ON PROCEDURE sys.sp_describe_cursor( + INOUT refcursor, IN nvarchar(30), IN nvarchar(30) +) TO PUBLIC; + +CREATE OR REPLACE PROCEDURE sys.sp_babelfish_configure() +AS 'babelfishpg_tsql', 'sp_babelfish_configure' +LANGUAGE C; +GRANT EXECUTE ON PROCEDURE sys.sp_babelfish_configure() TO PUBLIC; + +CREATE OR REPLACE PROCEDURE sys.sp_babelfish_configure(IN "@option_name" varchar(128)) +AS 'babelfishpg_tsql', 'sp_babelfish_configure' +LANGUAGE C; +GRANT EXECUTE ON PROCEDURE sys.sp_babelfish_configure(IN varchar(128)) TO PUBLIC; + +CREATE OR REPLACE PROCEDURE sys.sp_babelfish_configure(IN "@option_name" varchar(128), IN "@option_value" varchar(128)) +AS $$ +BEGIN + CALL sys.sp_babelfish_configure("@option_name", "@option_value", ''); +END; +$$ LANGUAGE plpgsql; +GRANT EXECUTE ON PROCEDURE sys.sp_babelfish_configure(IN varchar(128), IN varchar(128)) 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)) +AS $$ +DECLARE + normalized_name varchar(256); + cnt int; + cur refcursor; + eh_name varchar(256); + server boolean := false; + prev_user text; +BEGIN + IF lower("@option_name") like 'babelfishpg_tsql.%' THEN + SELECT "@option_name" INTO normalized_name; + ELSE + SELECT concat('babelfishpg_tsql.',"@option_name") INTO normalized_name; + END IF; + + IF lower("@option_scope") = 'server' THEN + server := true; + ELSIF btrim("@option_scope") != '' THEN + RAISE EXCEPTION 'invalid option: %', "@option_scope"; + END IF; + + SELECT COUNT(*) INTO cnt FROM pg_catalog.pg_settings WHERE name like normalized_name and name like '%escape_hatch%'; + IF cnt = 0 THEN + RAISE EXCEPTION 'unknown configuration: %', normalized_name; + END IF; + + OPEN cur FOR SELECT name FROM pg_catalog.pg_settings WHERE name like normalized_name and name like '%escape_hatch%'; + + LOOP + FETCH NEXT FROM cur into eh_name; + exit when not found; + + PERFORM pg_catalog.set_config(eh_name, "@option_value", 'false'); + IF server THEN + SELECT current_user INTO prev_user; + PERFORM sys.babelfish_set_role(session_user); + -- store the setting in PG master database so that it can be applied to all bbf databases + EXECUTE format('ALTER DATABASE %s SET %s = %s', CURRENT_DATABASE(), eh_name, "@option_value"); + PERFORM sys.babelfish_set_role(prev_user); + END IF; + END LOOP; + + CLOSE cur; + +END; +$$ LANGUAGE plpgsql; +GRANT EXECUTE ON PROCEDURE sys.sp_babelfish_configure( + IN varchar(128), IN varchar(128), IN varchar(128) +) TO PUBLIC; diff --git a/contrib/babelfishpg_tsql/sql/sys_views.sql b/contrib/babelfishpg_tsql/sql/sys_views.sql new file mode 100644 index 00000000000..953cbbd8c80 --- /dev/null +++ b/contrib/babelfishpg_tsql/sql/sys_views.sql @@ -0,0 +1,1100 @@ +/* Tsql system catalog views */ +create or replace view sys.tables as +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'::varchar(2) as type + , 'USER_TABLE'::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 + , case reltoastrelid when 0 then 0 else 1 end as lob_data_space_id + , null::integer as filestream_data_space_id + , relnatts as max_column_id_used + , 0 as lock_on_bulk_load + , 1 as uses_ansi_nulls + , 0 as is_replicated + , 0 as has_replication_filter + , 0 as is_merge_published + , 0 as is_sync_tran_subscribed + , 0 as has_unchecked_assembly_data + , 0 as text_in_row_limit + , 0 as large_value_types_out_of_row + , 0 as is_tracked_by_cdc + , 0 as lock_escalation + , 'TABLE'::varchar(60) as lock_escalation_desc + , 0 as is_filetable + , 0 as durability + , 'SCHEMA_AND_DATA'::varchar(60) as durability_desc + , 0 as is_memory_optimized + , case relpersistence when 't' then 2 else 0 end as temporal_type + , case relpersistence when 't' then 'SYSTEM_VERSIONED_TEMPORAL_TABLE' else 'NON_TEMPORAL_TABLE' end as temporal_type_desc + , null::integer as history_table_id + , 0 as is_remote_data_archive_enabled + , 0 as is_external +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 has_table_privilege(quote_ident(s.nspname) ||'.'||quote_ident(t.relname), 'SELECT,INSERT,UPDATE,DELETE,TRUNCATE,TRIGGER') +and s.nspname not in ('information_schema', 'pg_catalog'); +GRANT SELECT ON sys.tables TO PUBLIC; + +create or replace view sys.views as +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 + , 0 as with_check_option + , 0 as is_date_correlation_view + , 0 as is_tracked_by_cdc +from pg_class t inner join pg_namespace s on s.oid = t.relnamespace +where t.relkind = 'v' +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 s.nspname not in ('information_schema', 'pg_catalog'); +GRANT SELECT ON sys.views TO PUBLIC; + +create or replace view sys.all_columns as +select c.oid as object_id + , a.attname as name + , a.attnum as column_id + , t.oid as system_type_id + , t.oid as user_type_id + , a.attlen as max_length + , null::integer as precision + , null::integer as scale + , coll.collname as collation_name + , case when a.attnotnull then 0 else 1 end as is_nullable + , 0 as is_ansi_padded + , 0 as is_rowguidcol + , 0 as is_identity + , 0 as is_computed + , 0 as is_filestream + , 0 as is_replicated + , 0 as is_non_sql_subscribed + , 0 as is_merge_published + , 0 as is_dts_replicated + , 0 as is_xml_document + , 0 as xml_collection_id + , coalesce(d.oid, 0) as default_object_id + , coalesce((select oid from pg_constraint where conrelid = t.oid and contype = 'c' and a.attnum = any(conkey) limit 1), 0) as rule_object_id + , 0 as is_sparse + , 0 as is_column_set + , 0 as generated_always_type + , 'NOT_APPLICABLE'::varchar(60) as generated_always_type_desc + , null::integer as encryption_type + , null::varchar(64) as encryption_type_desc + , null::varchar as encryption_algorithm_name + , null::integer as column_encryption_key_id + , null::varchar as column_encryption_key_database_name + , 0 as is_hidden + , 0 as is_masked +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 pg_attrdef d on c.oid = d.adrelid and a.attnum = d.adnum +left join pg_collation coll on coll.oid = a.attcollation +where not a.attisdropped +-- 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_column_privilege(quote_ident(s.nspname) ||'.'||quote_ident(c.relname), a.attname, 'SELECT,INSERT,UPDATE,REFERENCES') +and has_schema_privilege(s.oid, 'USAGE') +and a.attnum > 0; +GRANT SELECT ON sys.all_columns TO PUBLIC; + +create or replace view sys.all_views as +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 + , 0 as with_check_option + , 0 as is_date_correlation_view + , 0 as is_tracked_by_cdc +from pg_class t inner join pg_namespace s on s.oid = t.relnamespace +where t.relkind = 'v' +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'); +GRANT SELECT ON sys.all_views TO PUBLIC; + +-- internal function in order to workaround BABEL-1597 +CREATE FUNCTION sys.columns_internal() +RETURNS TABLE ( + out_object_id int, + out_name sys.sysname, + out_column_id int, + out_system_type_id int, + out_user_type_id int, + out_max_length smallint, + out_precision sys.tinyint, + out_scale sys.tinyint, + out_collation_name sys.sysname, + out_collation_id int, + out_offset smallint, + out_is_nullable sys.bit, + out_is_ansi_padded sys.bit, + out_is_rowguidcol sys.bit, + out_is_identity sys.bit, + out_is_computed sys.bit, + out_is_filestream sys.bit, + out_is_replicated sys.bit, + out_is_non_sql_subscribed sys.bit, + out_is_merge_published sys.bit, + out_is_dts_replicated sys.bit, + out_is_xml_document sys.bit, + out_xml_collection_id int, + out_default_object_id int, + out_rule_object_id int, + out_is_sparse sys.bit, + out_is_column_set sys.bit, + out_generated_always_type sys.tinyint, + out_generated_always_type_desc sys.nvarchar(60), + out_encryption_type int, + out_encryption_type_desc sys.nvarchar(64), + out_encryption_algorithm_name sys.sysname, + out_column_encryption_key_id int, + out_column_encryption_key_database_name sys.sysname, + out_is_hidden sys.bit, + out_is_masked sys.bit, + out_graph_type int, + out_graph_type_desc sys.nvarchar(60) +) +AS +$$ +BEGIN + RETURN QUERY + SELECT CAST(c.oid AS int), + CAST(a.attname AS sys.sysname), + CAST(a.attnum AS int), + CAST(t.oid AS int), + CAST(t.oid AS int), + CAST(a.attlen AS smallint), + CAST(case when isc.datetime_precision is null then coalesce(isc.numeric_precision, 0) else isc.datetime_precision end AS sys.tinyint), + CAST(coalesce(isc.numeric_scale, 0) AS sys.tinyint), + CAST(coll.collname AS sys.sysname), + CAST(a.attcollation AS int), + CAST(a.attnum AS smallint), + CAST(case when a.attnotnull then 0 else 1 end AS sys.bit), + CAST(case when t.typname in ('bpchar', 'nchar', 'binary') then 1 else 0 end AS sys.bit), + CAST(0 AS sys.bit), + CAST(case when a.attidentity <> ''::"char" then 1 else 0 end AS sys.bit), + CAST(case when a.attgenerated <> ''::"char" then 1 else 0 end AS sys.bit), + CAST(0 AS sys.bit), + CAST(0 AS sys.bit), + CAST(0 AS sys.bit), + CAST(0 AS sys.bit), + CAST(0 AS sys.bit), + CAST(0 AS sys.bit), + CAST(0 AS int), + CAST(coalesce(d.oid, 0) AS int), + CAST(coalesce((select oid from pg_constraint where conrelid = t.oid + and contype = 'c' and a.attnum = any(conkey) limit 1), 0) AS int), + CAST(0 AS sys.bit), + CAST(0 AS sys.bit), + CAST(0 AS sys.tinyint), + CAST('NOT_APPLICABLE' AS sys.nvarchar(60)), + CAST(null AS int), + CAST(null AS sys.nvarchar(64)), + CAST(null AS sys.sysname), + CAST(null AS int), + CAST(null AS sys.sysname), + CAST(0 AS sys.bit), + CAST(0 AS sys.bit), + CAST(null AS int), + CAST(null AS sys.nvarchar(60)) + 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 + INNER JOIN information_schema.columns isc ON c.relname = isc.table_name AND s.nspname = isc.table_schema AND a.attname = isc.column_name + 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 + WHERE NOT a.attisdropped + AND a.attnum > 0 + -- 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 s.nspname NOT IN ('information_schema', 'pg_catalog', 'sys') + 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'); +END; +$$ +language plpgsql; + +create or replace view sys.columns AS +select out_object_id::oid as object_id + , out_name::name as name + , out_column_id::smallint as column_id + , out_system_type_id::oid as system_type_id + , out_user_type_id::oid as user_type_id + , out_max_length::smallint as max_length + , out_precision::integer as precision + , out_scale::integer as scale + , out_collation_name::name as collation_name + , out_is_nullable::integer as is_nullable + , out_is_ansi_padded::integer as is_ansi_padded + , out_is_rowguidcol::integer as is_rowguidcol + , out_is_identity::integer as is_identity + , out_is_computed::integer as is_computed + , out_is_filestream::integer as is_filestream + , out_is_replicated::integer as is_replicated + , out_is_non_sql_subscribed::integer as is_non_sql_subscribed + , out_is_merge_published::integer as is_merge_published + , out_is_dts_replicated::integer as is_dts_replicated + , out_is_xml_document::integer as is_xml_document + , out_xml_collection_id::integer as xml_collection_id + , out_default_object_id::oid as default_object_id + , out_rule_object_id::oid as rule_object_id + , out_is_sparse::integer as is_sparse + , out_is_column_set::integer as is_column_set + , out_generated_always_type::integer as generated_always_type + , out_generated_always_type_desc::varchar(60) as generated_always_type_desc + , out_encryption_type::integer as encryption_type + , out_encryption_type_desc::varchar(64) as encryption_type_desc + , out_encryption_algorithm_name::varchar as encryption_algorithm_name + , out_column_encryption_key_id::integer as column_encryption_key_id + , out_column_encryption_key_database_name::varchar as column_encryption_key_database_name + , out_is_hidden::integer as is_hidden + , out_is_masked::integer as is_masked + , out_graph_type as graph_type + , out_graph_type_desc as graph_type_desc +from sys.columns_internal(); +GRANT SELECT ON sys.columns TO PUBLIC; + +create or replace view sys.foreign_key_columns as +select distinct + c.oid as constraint_object_id + , c.confkey as constraint_column_id + , c.conrelid as parent_object_id + , a_con.attnum as parent_column_id + , c.confrelid as referenced_object_id + , a_conf.attnum as referenced_column_id +from pg_constraint c +inner join pg_attribute a_con on a_con.attrelid = c.conrelid and a_con.attnum = any(c.conkey) +inner join pg_attribute a_conf on a_conf.attrelid = c.confrelid and a_conf.attnum = any(c.confkey) +where c.contype = 'f'; +GRANT SELECT ON sys.foreign_key_columns TO PUBLIC; + +create or replace view sys.foreign_keys as +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'::varchar(2) as type + , 'FOREIGN_KEY_CONSTRAINT'::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 + , c.confrelid as referenced_object_id + , c.confkey as key_index_id + , 0 as is_disabled + , 0 as is_not_for_replication + , 0 as is_not_trusted + , case c.confdeltype + when 'a' then 0 + when 'r' then 0 + when 'c' then 1 + when 'n' then 2 + when 'd' then 3 + end as delete_referential_action + , case c.confdeltype + when 'a' then 'NO_ACTION' + when 'r' then 'NO_ACTION' + when 'c' then 'CASCADE' + when 'n' then 'SET_NULL' + when 'd' then 'SET_DEFAULT' + end as delete_referential_action_desc + , case c.confupdtype + when 'a' then 0 + when 'r' then 0 + when 'c' then 1 + when 'n' then 2 + when 'd' then 3 + end as update_referential_action + , case c.confupdtype + when 'a' then 'NO_ACTION' + when 'r' then 'NO_ACTION' + when 'c' then 'CASCADE' + when 'n' then 'SET_NULL' + when 'd' then 'SET_DEFAULT' + end as update_referential_action_desc + , 1 as is_system_named +from pg_constraint c +inner join pg_namespace s on s.oid = c.connamespace +where c.contype = 'f' +and s.nspname not in ('information_schema', 'pg_catalog'); +GRANT SELECT ON sys.foreign_keys TO PUBLIC; + +create or replace view sys.identity_columns as +select + sys.babelfish_get_id_by_name(c.oid::text||a.attname) as object_id + , a.attname as name + , a.attnum as column_id + , t.oid as system_type_id + , t.oid as user_type_id + , a.attlen as max_length + , null::integer as precision + , null::integer as scale + , coll.collname as collation_name + , case when a.attnotnull then 0 else 1 end as is_nullable + , 0 as is_ansi_padded + , 0 as is_rowguidcol + , 1 as is_identity + , 0 as is_computed + , 0 as is_filestream + , 0 as is_replicated + , 0 as is_non_sql_subscribed + , 0 as is_merge_published + , 0 as is_dts_replicated + , 0 as is_xml_document + , 0 as xml_collection_id + , coalesce(d.oid, 0) as default_object_id + , coalesce((select oid from pg_constraint where conrelid = t.oid and contype = 'c' and a.attnum = any(conkey) limit 1), 0) as rule_object_id + , 0 as is_sparse + , 0 as is_column_set + , 0 as generated_always_type + , 'NOT_APPLICABLE'::varchar(60) as generated_always_type_desc + , null::integer as encryption_type + , null::varchar(64) as encryption_type_desc + , null::varchar as encryption_algorithm_name + , null::integer as column_encryption_key_id + , null::varchar as column_encryption_key_database_name + , 0 as is_hidden + , 0 as is_masked + , null::bigint as seed_value + , null::bigint as increment_value + , sys.babelfish_get_sequence_value(pg_get_serial_sequence(quote_ident(s.nspname)||'.'||quote_ident(c.relname), a.attname)) as last_value +from pg_attribute a +left join pg_attrdef d on a.attrelid = d.adrelid and a.attnum = d.adnum +inner join pg_class c on c.oid = a.attrelid +inner join pg_namespace s on s.oid = c.relnamespace +left join pg_type t on t.oid = a.atttypid +left join pg_collation coll on coll.oid = t.typcollation +where not a.attisdropped +and pg_get_serial_sequence(quote_ident(s.nspname)||'.'||quote_ident(c.relname), a.attname) is not null +and s.nspname not in ('information_schema', 'pg_catalog') +and has_schema_privilege(s.oid, 'USAGE') +and has_sequence_privilege(pg_get_serial_sequence(quote_ident(s.nspname)||'.'||quote_ident(c.relname), a.attname), 'USAGE,SELECT,UPDATE'); +GRANT SELECT ON sys.identity_columns TO PUBLIC; + +create or replace view sys.indexes as +select + i.indrelid as object_id + , c.relname as name + , case when i.indisclustered then 1 else 2 end as type + , case when i.indisclustered then 'CLUSTERED'::varchar(60) else 'NONCLUSTERED'::varchar(60) end as type_desc + , case when i.indisunique then 1 else 0 end as is_unique + , c.reltablespace as data_space_id + , 0 as ignore_dup_key + , case when i.indisprimary then 1 else 0 end as is_primary_key + , case when constr.oid is null then 0 else 1 end as is_unique_constraint + , 0 as fill_factor + , case when i.indpred is null then 0 else 1 end as is_padded + , case when i.indisready then 0 else 1 end is_disabled + , 0 as is_hypothetical + , 1 as allow_row_locks + , 1 as allow_page_locks + , 0 as has_filter + , null::varchar as filter_definition + , 0 as auto_created + , c.oid as index_id +from pg_class c +inner join pg_namespace s on s.oid = c.relnamespace +inner join pg_index i on i.indexrelid = c.oid +left join pg_constraint constr on constr.conindid = c.oid +where c.relkind = 'i' and i.indislive +and s.nspname not in ('information_schema', 'pg_catalog'); +GRANT SELECT ON sys.indexes TO PUBLIC; + +create or replace view sys.key_constraints as +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 + , case contype + when 'p' then 'PK'::varchar(2) + when 'u' then 'UQ'::varchar(2) + end as type + , case contype + when 'p' then 'PRIMARY_KEY_CONSTRAINT'::varchar(60) + when 'u' then 'UNIQUE_CONSTRAINT'::varchar(60) + end as type_desc + , null::timestamp as create_date + , null::timestamp as modify_date + , c.conindid as unique_index_id + , 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 c.contype = 'p'; +GRANT SELECT ON sys.key_constraints TO PUBLIC; + +create or replace view sys.procedures as +select + p.proname as name + , p.oid as object_id + , null::integer as principal_id + , s.oid as schema_id + , 0 as parent_object_id + , case format_type(p.prorettype, null) + when 'void' then 'P'::varchar(2) + else + case format_type(p.prorettype, null) when 'trigger' + then 'TR'::varchar(2) + else 'FN'::varchar(2) + end + end as type + , case format_type(p.prorettype, null) + when 'void' then 'SQL_STORED_PROCEDURE'::varchar(60) + else + case format_type(p.prorettype, null) when 'trigger' + then 'SQL_TRIGGER'::varchar(60) + 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 +where s.nspname not in ('information_schema', 'pg_catalog') +and has_function_privilege(p.oid, 'EXECUTE'); +GRANT SELECT ON sys.procedures TO PUBLIC; + +create or replace view sys.sql_modules as +select + p.oid as object_id + , pg_get_functiondef(p.oid) as definition + , 1 as uses_ansi_nulls + , 1 as uses_quoted_identifier + , 0 as is_schema_bound + , 0 as uses_database_collation + , 0 as is_recompiled + , case when p.proisstrict then 1 else 0 end as null_on_null_input + , null::integer as execute_as_principal_id + , 0 as uses_native_compilation +from pg_proc p +inner join pg_namespace s on s.oid = p.pronamespace +inner join pg_type t on t.oid = p.prorettype +left join pg_collation c on c.oid = t.typcollation +where s.nspname not in ('information_schema', 'pg_catalog') +and has_function_privilege(p.oid, 'EXECUTE'); +GRANT SELECT ON sys.sql_modules TO PUBLIC; + +create or replace view sys.sysforeignkeys as +select + c.conname as name + , c.oid as object_id + , c.conrelid as fkeyid + , c.confrelid as rkeyid + , a_con.attnum as fkey + , a_conf.attnum as rkey + , a_conf.attnum as keyno +from pg_constraint c +inner join pg_namespace s on s.oid = c.connamespace +inner join pg_attribute a_con on a_con.attrelid = c.conrelid and a_con.attnum = any(c.conkey) +inner join pg_attribute a_conf on a_conf.attrelid = c.confrelid and a_conf.attnum = any(c.confkey) +where c.contype = 'f' +and s.nspname not in ('information_schema', 'pg_catalog'); +GRANT SELECT ON sys.sysforeignkeys TO PUBLIC; + +create or replace view sys.sysindexes as +select + i.object_id::integer as id + , null::integer as status + , null::binary(6) as first + , i.type::smallint as indid + , null::binary(6) as root + , 0::smallint as minlen + , 1::smallint as keycnt + , null::smallint as groupid + , 0 as dpages + , 0 as reserved + , 0 as used + , 0::bigint as rowcnt + , 0 as rowmodctr + , 0 as reserved3 + , 0 as reserved4 + , 0::smallint as xmaxlen + , null::smallint as maxirow + , 90::sys.tinyint as "OrigFillFactor" + , 0::sys.tinyint as "StatVersion" + , 0 as reserved2 + , null::binary(6) as "FirstIAM" + , 0::smallint as impid + , 0::smallint as lockflags + , 0 as pgmodctr + , null::sys.varbinary(816) as keys + , i.name::sys.sysname as name + , null::sys.image as statblob + , 0 as maxlen + , 0 as rows +from sys.indexes i; +GRANT SELECT ON sys.sysindexes 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 + , a.datid 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 + , a.client_hostname 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 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; +GRANT SELECT ON sys.sysprocesses TO PUBLIC; + +create or replace view sys.types As +select format_type(t.oid, null) as name + , t.oid as system_type_id + , t.oid as user_type_id + , s.oid as schema_id + , null::integer as principal_id + , t.typlen as max_length + , 0 as precision + , 0 as scale + , c.collname as collation_name + , case when typnotnull then 0 else 1 end as is_nullable + , case typcategory when 'U' then 1 else 0 end 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; +GRANT SELECT ON sys.types TO PUBLIC; + +create view sys.objects as +select + t.name + , t.object_id + , t.principal_id + , t.schema_id + , t.parent_object_id + , 'U' as type + , 'USER_TABLE' as type_desc + , t.create_date + , t.modify_date + , t.is_ms_shipped + , t.is_published + , t.is_schema_published +from sys.tables t +where has_schema_privilege(t.schema_id, 'USAGE') +union all +select + v.name + , v.object_id + , v.principal_id + , v.schema_id + , v.parent_object_id + , 'V' as type + , 'VIEW' as type_desc + , v.create_date + , v.modify_date + , v.is_ms_shipped + , v.is_published + , v.is_schema_published +from sys.views v +where has_schema_privilege(v.schema_id, 'USAGE') +union all +select + f.name + , f.object_id + , f.principal_id + , f.schema_id + , f.parent_object_id + , 'F' as type + , 'FOREIGN_KEY_CONSTRAINT' + , f.create_date + , f.modify_date + , f.is_ms_shipped + , f.is_published + , f.is_schema_published + from sys.foreign_keys f +where has_schema_privilege(f.schema_id, 'USAGE') + union all +select + p.name + , p.object_id + , p.principal_id + , p.schema_id + , p.parent_object_id + , 'PK' as type + , 'PRIMARY_KEY_CONSTRAINT' as type_desc + , p.create_date + , p.modify_date + , p.is_ms_shipped + , p.is_published + , p.is_schema_published + from sys.key_constraints p +where has_schema_privilege(p.schema_id, 'USAGE') +union all +select + pr.name + , pr.object_id + , pr.principal_id + , pr.schema_id + , pr.parent_object_id + , pr.type + , pr.type_desc + , pr.create_date + , pr.modify_date + , pr.is_ms_shipped + , pr.is_published + , pr.is_schema_published + from sys.procedures pr +where has_schema_privilege(pr.schema_id, 'USAGE') +union all +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 s.nspname not in ('information_schema', 'pg_catalog') +and p.relkind = 'S' +and has_schema_privilege(s.oid, 'USAGE'); +GRANT SELECT ON sys.objects TO PUBLIC; + +create or replace view sys.sysobjects as +select + s.name + , s.object_id as id + , s.type as xtype + , s.schema_id as uid + , 0 as info + , 0 as status + , 0 as base_schema_ver + , 0 as replinfo + , s.parent_object_id as parent_obj + , s.create_date as crdate + , 0 as ftcatid + , 0 as schema_ver + , 0 as stats_schema_ver + , s.type + , 0 as userstat + , 0 as sysstat + , 0 as indexdel + , s.modify_date as refdate + , 0 as version + , 0 as deltrig + , 0 as instrig + , 0 as updtrig + , 0 as seltrig + , 0 as category + , 0 as cache +from sys.objects s; +GRANT SELECT ON sys.sysobjects TO PUBLIC; + +create view sys.all_objects as +select + t.name + , t.object_id + , t.principal_id + , t.schema_id + , t.parent_object_id + , 'U' as type + , 'USER_TABLE' as type_desc + , t.create_date + , t.modify_date + , t.is_ms_shipped + , t.is_published + , t.is_schema_published +from sys.tables t +where has_schema_privilege(t.schema_id, 'USAGE') +union all +select + v.name + , v.object_id + , v.principal_id + , v.schema_id + , v.parent_object_id + , 'V' as type + , 'VIEW' as type_desc + , v.create_date + , v.modify_date + , v.is_ms_shipped + , v.is_published + , v.is_schema_published +from sys.all_views v +where has_schema_privilege(v.schema_id, 'USAGE') +union all +select + f.name + , f.object_id + , f.principal_id + , f.schema_id + , f.parent_object_id + , 'F' as type + , 'FOREIGN_KEY_CONSTRAINT' + , f.create_date + , f.modify_date + , f.is_ms_shipped + , f.is_published + , f.is_schema_published + from sys.foreign_keys f + where has_schema_privilege(f.schema_id, 'USAGE') + union all +select + p.name + , p.object_id + , p.principal_id + , p.schema_id + , p.parent_object_id + , 'PK' as type + , 'PRIMARY_KEY_CONSTRAINT' as type_desc + , p.create_date + , p.modify_date + , p.is_ms_shipped + , p.is_published + , p.is_schema_published + from sys.key_constraints p + where has_schema_privilege(p.schema_id, 'USAGE') +union all +select + pr.name + , pr.object_id + , pr.principal_id + , pr.schema_id + , pr.parent_object_id + , pr.type + , pr.type_desc + , pr.create_date + , pr.modify_date + , pr.is_ms_shipped + , pr.is_published + , pr.is_schema_published + from sys.procedures pr + where has_schema_privilege(pr.schema_id, 'USAGE') +union all +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 has_schema_privilege(s.oid, 'USAGE'); +GRANT SELECT ON sys.all_objects TO PUBLIC; + +create or replace view sys.system_objects as +select * from sys.all_objects o +inner join pg_namespace s on s.oid = o.schema_id +where s.nspname in ('information_schema', 'pg_catalog'); +GRANT SELECT ON sys.system_objects TO PUBLIC; + +CREATE VIEW sys.syscharsets +AS +SELECT 1001 as type, + 1 as id, + 0 as csid, + 0 as status, + NULL::nvarchar(128) as name, + NULL::nvarchar(255) as description , + NULL::varbinary(6000) binarydefinition , + NULL::image definition; +GRANT SELECT ON sys.syscharsets TO PUBLIC; + +create or replace view sys.default_constraints +AS +select CAST(('DF_' || o.relname || '_' || d.oid) as 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 modified_date + , 0::sys.bit as is_ms_shipped + , 0::sys.bit as is_published + , 0::sys.bit as is_schema_published + , d.adnum::int as parent_column_id + , pg_get_expr(d.adbin, d.adrelid) as definition + , 1::sys.bit as is_system_named +from pg_catalog.pg_attrdef as d +inner join pg_catalog.pg_class as o on (d.adrelid = o.oid); +GRANT SELECT ON sys.default_constraints TO PUBLIC; + +CREATE OR REPLACE VIEW sys.computed_columns +AS +SELECT out_object_id as object_id + , out_name as name + , out_column_id as column_id + , out_system_type_id as system_type_id + , out_user_type_id as user_type_id + , out_max_length as max_length + , out_precision as precision + , out_scale as scale + , out_collation_name as collation_name + , out_is_nullable as is_nullable + , out_is_ansi_padded as is_ansi_padded + , out_is_rowguidcol as is_rowguidcol + , out_is_identity as is_identity + , out_is_computed as is_computed + , out_is_filestream as is_filestream + , out_is_replicated as is_replicated + , out_is_non_sql_subscribed as is_non_sql_subscribed + , out_is_merge_published as is_merge_published + , out_is_dts_replicated as is_dts_replicated + , out_is_xml_document as is_xml_document + , out_xml_collection_id as xml_collection_id + , out_default_object_id as default_object_id + , out_rule_object_id as rule_object_id + , out_is_sparse as is_sparse + , out_is_column_set as is_column_set + , out_generated_always_type as generated_always_type + , out_generated_always_type_desc as generated_always_type_desc + , out_encryption_type as encryption_type + , out_encryption_type_desc as encryption_type_desc + , out_encryption_algorithm_name as encryption_algorithm_name + , out_column_encryption_key_id as column_encryption_key_id + , out_column_encryption_key_database_name as column_encryption_key_database_name + , out_is_hidden as is_hidden + , out_is_masked as is_masked + , out_graph_type as graph_type + , out_graph_type_desc as graph_type_desc + , substring(pg_get_expr(d.adbin, d.adrelid), 1, 4000)::sys.nvarchar(4000) AS definition + , 1::sys.bit AS uses_database_collation + , 0::sys.bit AS is_persisted +FROM sys.columns_internal() sc +INNER JOIN pg_attribute a ON sc.out_name = a.attname AND sc.out_column_id = a.attnum +INNER JOIN pg_attrdef d ON d.adrelid = a.attrelid AND d.adnum = a.attnum +WHERE a.attgenerated = 's' AND sc.out_is_computed::integer = 1; +GRANT SELECT ON sys.computed_columns TO PUBLIC; + +create or replace view sys.index_columns +as +select i.indrelid::integer as object_id + , i.indexrelid::integer as index_id + , a.attrelid::integer as index_column_id + , a.attnum::integer as column_id + , a.attnum::sys.tinyint as key_ordinal + , 0::sys.tinyint as partition_ordinal + , 0::sys.bit as is_descending_key + , 1::sys.bit as is_included_column +from pg_index as i +inner join pg_catalog.pg_attribute a on i.indexrelid = a.attrelid; +GRANT SELECT ON sys.index_columns TO PUBLIC; + +CREATE or replace VIEW sys.check_constraints AS +SELECT CAST(c.conname as sys.sysname) as name + , oid::integer as object_id + , c.connamespace::integer as principal_id + , c.connamespace::integer as schema_id + , 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::sys.bit as is_ms_shipped + , 0::sys.bit as is_published + , 0::sys.bit as is_schema_published + , 0::sys.bit as is_disabled + , 0::sys.bit as is_not_for_replication + , 0::sys.bit as is_not_trusted + , c.conkey[1]::integer AS parent_column_id + , substring(pg_get_constraintdef(c.oid) from 7) AS definition + , 1::sys.bit as uses_database_collation + , 0::sys.bit as is_system_named +FROM pg_catalog.pg_constraint as c +WHERE c.contype = 'c' and c.conrelid != 0; +GRANT SELECT ON sys.check_constraints TO PUBLIC; + +-- internal function that returns relevant info needed +-- by sys.syscolumns view for all procedure parameters. +-- This separate function was needed to workaround BABEL-1597 +CREATE FUNCTION sys.proc_param_helper() +RETURNS TABLE ( + name sys.sysname, + id int, + xtype int, + colid smallint, + collationid int, + prec smallint, + scale int, + isoutparam int, + collation sys.sysname +) +AS +$$ +BEGIN +RETURN QUERY +select params.parameter_name::sys.sysname + , pgproc.oid::int + , CAST(case when pgproc.proallargtypes is null then split_part(pgproc.proargtypes::varchar, ' ', params.ordinal_position) + else split_part(btrim(pgproc.proallargtypes::text,'{}'), ',', params.ordinal_position) end AS int) + , params.ordinal_position::smallint + , coll.oid::int + , params.numeric_precision::smallint + , params.numeric_scale::int + , case params.parameter_mode when 'OUT' then 1 when 'INOUT' then 1 else 0 end + , params.collation_name::sys.sysname +from information_schema.routines routine +left join information_schema.parameters params + on routine.specific_schema = params.specific_schema + and routine.specific_name = params.specific_name +left join pg_collation coll on coll.collname = params.collation_name +/* assuming routine.specific_name is constructed by concatenating procedure name and oid */ +left join pg_proc pgproc on routine.specific_name = nameconcatoid(pgproc.proname, pgproc.oid) +where routine.routine_schema not in ('pg_catalog', 'information_schema') + and routine.routine_type = 'PROCEDURE'; +END; +$$ +LANGUAGE plpgsql; + +CREATE OR REPLACE VIEW sys.syscolumns AS +SELECT out_name as name + , out_object_id as id + , out_system_type_id as xtype + , 0::sys.tinyint as typestat + , (case when out_user_type_id < 32767 then out_user_type_id else null end)::smallint as xusertype + , out_max_length as length + , 0::sys.tinyint as xprec + , 0::sys.tinyint as xscale + , out_column_id::smallint as colid + , 0::smallint as xoffset + , 0::sys.tinyint as bitpos + , 0::sys.tinyint as reserved + , 0::smallint as colstat + , out_default_object_id::int as cdefault + , out_rule_object_id::int as domain + , 0::smallint as number + , 0::smallint as colorder + , null::sys.varbinary(8000) as autoval + , out_offset as offset + , out_collation_id as collationid + , (case out_is_nullable::int when 1 then 8 else 0 end + + case out_is_identity::int when 1 then 128 else 0 end)::sys.tinyint as status + , out_system_type_id as type + , (case when out_user_type_id < 32767 then out_user_type_id else null end)::smallint as usertype + , null::varchar(255) as printfmt + , out_precision::smallint as prec + , out_scale::int as scale + , out_is_computed::int as iscomputed + , 0::int as isoutparam + , out_is_nullable::int as isnullable + , out_collation_name::sys.sysname as collation +FROM sys.columns_internal() +union all +SELECT p.name + , p.id + , p.xtype + , 0::sys.tinyint as typestat + , (case when p.xtype < 32767 then p.xtype else null end)::smallint as xusertype + , null as length + , 0::sys.tinyint as xprec + , 0::sys.tinyint as xscale + , p.colid + , 0::smallint as xoffset + , 0::sys.tinyint as bitpos + , 0::sys.tinyint as reserved + , 0::smallint as colstat + , null::int as cdefault + , null::int as domain + , 0::smallint as number + , 0::smallint as colorder + , null::sys.varbinary(8000) as autoval + , 0::smallint as offset + , collationid + , (case p.isoutparam when 1 then 64 else 0 end)::sys.tinyint as status + , p.xtype as type + , (case when p.xtype < 32767 then p.xtype else null end)::smallint as usertype + , null::varchar(255) as printfmt + , p.prec + , p.scale + , 0::int as iscomputed + , p.isoutparam + , 1::int as isnullable + , p.collation +FROM sys.proc_param_helper() as p; +GRANT SELECT ON sys.syscolumns TO PUBLIC; diff --git a/contrib/babelfishpg_tsql/sql/upgrades/.gitignore b/contrib/babelfishpg_tsql/sql/upgrades/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--1.0.0--1.1.0.sql b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--1.0.0--1.1.0.sql new file mode 100644 index 00000000000..c64e9eb27e7 --- /dev/null +++ b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--1.0.0--1.1.0.sql @@ -0,0 +1,1282 @@ +-- complain if script is sourced in psql, rather than via ALTER EXTENSION +\echo Use "ALTER EXTENSION ""babelfishpg_tsql"" UPDATE TO '1.1.0'" to load this file. \quit + +SELECT set_config('search_path', 'sys, '||current_setting('search_path'), false); + +/* Caution: Be careful while dropping an object in a minor version upgrade + * script as the object might be getting used in some user defined + * objects and dropping it here might result in upgrade failure or + * even user defined objects getting dropped. + * The following sys.sysindexes view was not working previously, so dropping + * it here is ok. + */ +DROP VIEW IF EXISTS sys.sysindexes; + +CREATE FUNCTION sys.columns_internal() +RETURNS TABLE ( + out_object_id int, + out_name sys.sysname, + out_column_id int, + out_system_type_id int, + out_user_type_id int, + out_max_length smallint, + out_precision sys.tinyint, + out_scale sys.tinyint, + out_collation_name sys.sysname, + out_collation_id int, + out_offset smallint, + out_is_nullable sys.bit, + out_is_ansi_padded sys.bit, + out_is_rowguidcol sys.bit, + out_is_identity sys.bit, + out_is_computed sys.bit, + out_is_filestream sys.bit, + out_is_replicated sys.bit, + out_is_non_sql_subscribed sys.bit, + out_is_merge_published sys.bit, + out_is_dts_replicated sys.bit, + out_is_xml_document sys.bit, + out_xml_collection_id int, + out_default_object_id int, + out_rule_object_id int, + out_is_sparse sys.bit, + out_is_column_set sys.bit, + out_generated_always_type sys.tinyint, + out_generated_always_type_desc sys.nvarchar(60), + out_encryption_type int, + out_encryption_type_desc sys.nvarchar(64), + out_encryption_algorithm_name sys.sysname, + out_column_encryption_key_id int, + out_column_encryption_key_database_name sys.sysname, + out_is_hidden sys.bit, + out_is_masked sys.bit, + out_graph_type int, + out_graph_type_desc sys.nvarchar(60) +) +AS +$$ +BEGIN + RETURN QUERY + SELECT CAST(c.oid AS int), + CAST(a.attname AS sys.sysname), + CAST(a.attnum AS int), + CAST(t.oid AS int), + CAST(t.oid AS int), + CAST(a.attlen AS smallint), + CAST(case when isc.datetime_precision is null then coalesce(isc.numeric_precision, 0) else isc.datetime_precision end AS sys.tinyint), + CAST(coalesce(isc.numeric_scale, 0) AS sys.tinyint), + CAST(coll.collname AS sys.sysname), + CAST(a.attcollation AS int), + CAST(a.attnum AS smallint), + CAST(case when a.attnotnull then 0 else 1 end AS sys.bit), + CAST(case when t.typname in ('bpchar', 'nchar', 'binary') then 1 else 0 end AS sys.bit), + CAST(0 AS sys.bit), + CAST(case when a.attidentity <> ''::"char" then 1 else 0 end AS sys.bit), + CAST(case when a.attgenerated <> ''::"char" then 1 else 0 end AS sys.bit), + CAST(0 AS sys.bit), + CAST(0 AS sys.bit), + CAST(0 AS sys.bit), + CAST(0 AS sys.bit), + CAST(0 AS sys.bit), + CAST(0 AS sys.bit), + CAST(0 AS int), + CAST(coalesce(d.oid, 0) AS int), + CAST(coalesce((select oid from pg_constraint where conrelid = t.oid + and contype = 'c' and a.attnum = any(conkey) limit 1), 0) AS int), + CAST(0 AS sys.bit), + CAST(0 AS sys.bit), + CAST(0 AS sys.tinyint), + CAST('NOT_APPLICABLE' AS sys.nvarchar(60)), + CAST(null AS int), + CAST(null AS sys.nvarchar(64)), + CAST(null AS sys.sysname), + CAST(null AS int), + CAST(null AS sys.sysname), + CAST(0 AS sys.bit), + CAST(0 AS sys.bit), + CAST(null AS int), + CAST(null AS sys.nvarchar(60)) + 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 + INNER JOIN information_schema.columns isc ON c.relname = isc.table_name AND s.nspname = isc.table_schema AND a.attname = isc.column_name + 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 + WHERE NOT a.attisdropped + AND a.attnum > 0 + -- 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 s.nspname NOT IN ('information_schema', 'pg_catalog', 'sys') + 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'); +END; +$$ +language plpgsql; + +create or replace view sys.columns AS +select out_object_id::oid as object_id + , out_name::name as name + , out_column_id::smallint as column_id + , out_system_type_id::oid as system_type_id + , out_user_type_id::oid as user_type_id + , out_max_length::smallint as max_length + , out_precision::integer as precision + , out_scale::integer as scale + , out_collation_name::name as collation_name + , out_is_nullable::integer as is_nullable + , out_is_ansi_padded::integer as is_ansi_padded + , out_is_rowguidcol::integer as is_rowguidcol + , out_is_identity::integer as is_identity + , out_is_computed::integer as is_computed + , out_is_filestream::integer as is_filestream + , out_is_replicated::integer as is_replicated + , out_is_non_sql_subscribed::integer as is_non_sql_subscribed + , out_is_merge_published::integer as is_merge_published + , out_is_dts_replicated::integer as is_dts_replicated + , out_is_xml_document::integer as is_xml_document + , out_xml_collection_id::integer as xml_collection_id + , out_default_object_id::oid as default_object_id + , out_rule_object_id::oid as rule_object_id + , out_is_sparse::integer as is_sparse + , out_is_column_set::integer as is_column_set + , out_generated_always_type::integer as generated_always_type + , out_generated_always_type_desc::varchar(60) as generated_always_type_desc + , out_encryption_type::integer as encryption_type + , out_encryption_type_desc::varchar(64) as encryption_type_desc + , out_encryption_algorithm_name::varchar as encryption_algorithm_name + , out_column_encryption_key_id::integer as column_encryption_key_id + , out_column_encryption_key_database_name::varchar as column_encryption_key_database_name + , out_is_hidden::integer as is_hidden + , out_is_masked::integer as is_masked + , out_graph_type as graph_type + , out_graph_type_desc as graph_type_desc +from sys.columns_internal(); +GRANT SELECT ON sys.columns TO PUBLIC; + +create or replace view sys.views as +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 + , 0 as with_check_option + , 0 as is_date_correlation_view + , 0 as is_tracked_by_cdc +from pg_class t inner join pg_namespace s on s.oid = t.relnamespace +where t.relkind = 'v' +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 s.nspname not in ('information_schema', 'pg_catalog'); +GRANT SELECT ON sys.views TO PUBLIC; + +create or replace view sys.all_columns as +select c.oid as object_id + , a.attname as name + , a.attnum as column_id + , t.oid as system_type_id + , t.oid as user_type_id + , a.attlen as max_length + , null::integer as precision + , null::integer as scale + , coll.collname as collation_name + , case when a.attnotnull then 0 else 1 end as is_nullable + , 0 as is_ansi_padded + , 0 as is_rowguidcol + , 0 as is_identity + , 0 as is_computed + , 0 as is_filestream + , 0 as is_replicated + , 0 as is_non_sql_subscribed + , 0 as is_merge_published + , 0 as is_dts_replicated + , 0 as is_xml_document + , 0 as xml_collection_id + , coalesce(d.oid, 0) as default_object_id + , coalesce((select oid from pg_constraint where conrelid = t.oid and contype = 'c' and a.attnum = any(conkey) limit 1), 0) as rule_object_id + , 0 as is_sparse + , 0 as is_column_set + , 0 as generated_always_type + , 'NOT_APPLICABLE'::varchar(60) as generated_always_type_desc + , null::integer as encryption_type + , null::varchar(64) as encryption_type_desc + , null::varchar as encryption_algorithm_name + , null::integer as column_encryption_key_id + , null::varchar as column_encryption_key_database_name + , 0 as is_hidden + , 0 as is_masked +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 pg_attrdef d on c.oid = d.adrelid and a.attnum = d.adnum +left join pg_collation coll on coll.oid = a.attcollation +where not a.attisdropped +-- 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_column_privilege(quote_ident(s.nspname) ||'.'||quote_ident(c.relname), a.attname, 'SELECT,INSERT,UPDATE,REFERENCES') +and has_schema_privilege(s.oid, 'USAGE') +and a.attnum > 0; +GRANT SELECT ON sys.all_columns TO PUBLIC; + +create or replace view sys.all_views as +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 + , 0 as with_check_option + , 0 as is_date_correlation_view + , 0 as is_tracked_by_cdc +from pg_class t inner join pg_namespace s on s.oid = t.relnamespace +where t.relkind = 'v' +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'); +GRANT SELECT ON sys.all_views TO PUBLIC; + +create or replace view sys.identity_columns as +select + sys.babelfish_get_id_by_name(c.oid::text||a.attname) as object_id + , a.attname as name + , a.attnum as column_id + , t.oid as system_type_id + , t.oid as user_type_id + , a.attlen as max_length + , null::integer as precision + , null::integer as scale + , coll.collname as collation_name + , case when a.attnotnull then 0 else 1 end as is_nullable + , 0 as is_ansi_padded + , 0 as is_rowguidcol + , 1 as is_identity + , 0 as is_computed + , 0 as is_filestream + , 0 as is_replicated + , 0 as is_non_sql_subscribed + , 0 as is_merge_published + , 0 as is_dts_replicated + , 0 as is_xml_document + , 0 as xml_collection_id + , coalesce(d.oid, 0) as default_object_id + , coalesce((select oid from pg_constraint where conrelid = t.oid and contype = 'c' and a.attnum = any(conkey) limit 1), 0) as rule_object_id + , 0 as is_sparse + , 0 as is_column_set + , 0 as generated_always_type + , 'NOT_APPLICABLE'::varchar(60) as generated_always_type_desc + , null::integer as encryption_type + , null::varchar(64) as encryption_type_desc + , null::varchar as encryption_algorithm_name + , null::integer as column_encryption_key_id + , null::varchar as column_encryption_key_database_name + , 0 as is_hidden + , 0 as is_masked + , null::bigint as seed_value + , null::bigint as increment_value + , sys.babelfish_get_sequence_value(pg_get_serial_sequence(quote_ident(s.nspname)||'.'||quote_ident(c.relname), a.attname)) as last_value +from pg_attribute a +left join pg_attrdef d on a.attrelid = d.adrelid and a.attnum = d.adnum +inner join pg_class c on c.oid = a.attrelid +inner join pg_namespace s on s.oid = c.relnamespace +left join pg_type t on t.oid = a.atttypid +left join pg_collation coll on coll.oid = t.typcollation +where not a.attisdropped +and pg_get_serial_sequence(quote_ident(s.nspname)||'.'||quote_ident(c.relname), a.attname) is not null +and s.nspname not in ('information_schema', 'pg_catalog') +and has_schema_privilege(s.oid, 'USAGE') +and has_sequence_privilege(pg_get_serial_sequence(quote_ident(s.nspname)||'.'||quote_ident(c.relname), a.attname), 'USAGE,SELECT,UPDATE'); +GRANT SELECT ON sys.identity_columns TO PUBLIC; + +create or replace view sys.all_objects as +select + t.name + , t.object_id + , t.principal_id + , t.schema_id + , t.parent_object_id + , 'U' as type + , 'USER_TABLE' as type_desc + , t.create_date + , t.modify_date + , t.is_ms_shipped + , t.is_published + , t.is_schema_published +from sys.tables t +where has_schema_privilege(t.schema_id, 'USAGE') +union all +select + v.name + , v.object_id + , v.principal_id + , v.schema_id + , v.parent_object_id + , 'V' as type + , 'VIEW' as type_desc + , v.create_date + , v.modify_date + , v.is_ms_shipped + , v.is_published + , v.is_schema_published +from sys.all_views v +where has_schema_privilege(v.schema_id, 'USAGE') +union all +select + f.name + , f.object_id + , f.principal_id + , f.schema_id + , f.parent_object_id + , 'F' as type + , 'FOREIGN_KEY_CONSTRAINT' + , f.create_date + , f.modify_date + , f.is_ms_shipped + , f.is_published + , f.is_schema_published + from sys.foreign_keys f + where has_schema_privilege(f.schema_id, 'USAGE') + union all +select + p.name + , p.object_id + , p.principal_id + , p.schema_id + , p.parent_object_id + , 'PK' as type + , 'PRIMARY_KEY_CONSTRAINT' as type_desc + , p.create_date + , p.modify_date + , p.is_ms_shipped + , p.is_published + , p.is_schema_published + from sys.key_constraints p + where has_schema_privilege(p.schema_id, 'USAGE') +union all +select + pr.name + , pr.object_id + , pr.principal_id + , pr.schema_id + , pr.parent_object_id + , pr.type + , pr.type_desc + , pr.create_date + , pr.modify_date + , pr.is_ms_shipped + , pr.is_published + , pr.is_schema_published + from sys.procedures pr + where has_schema_privilege(pr.schema_id, 'USAGE') +union all +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 has_schema_privilege(s.oid, 'USAGE'); +GRANT SELECT ON sys.all_objects TO PUBLIC; + +create or replace function sys.square(in x double precision) returns double precision +AS +$BODY$ +DECLARE + res double precision; +BEGIN + res = pow(x, 2::float); + return res; +END; +$BODY$ +LANGUAGE plpgsql PARALLEL SAFE IMMUTABLE RETURNS NULL ON NULL INPUT; + +create or replace view sys.sysindexes as +select + i.object_id::integer as id + , null::integer as status + , null::binary(6) as first + , i.type::smallint as indid + , null::binary(6) as root + , 0::smallint as minlen + , 1::smallint as keycnt + , null::smallint as groupid + , 0 as dpages + , 0 as reserved + , 0 as used + , 0::bigint as rowcnt + , 0 as rowmodctr + , 0 as reserved3 + , 0 as reserved4 + , 0::smallint as xmaxlen + , null::smallint as maxirow + , 90::sys.tinyint as "OrigFillFactor" + , 0::sys.tinyint as "StatVersion" + , 0 as reserved2 + , null::binary(6) as "FirstIAM" + , 0::smallint as impid + , 0::smallint as lockflags + , 0 as pgmodctr + , null::sys.varbinary(816) as keys + , i.name::sys.sysname as name + , null::sys.image as statblob + , 0 as maxlen + , 0 as rows +from sys.indexes i; +GRANT SELECT ON sys.sysindexes TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.exp(IN arg DOUBLE PRECISION) +RETURNS DOUBLE PRECISION +AS 'babelfishpg_tsql', 'tsql_exp' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; +GRANT EXECUTE ON FUNCTION sys.exp(DOUBLE PRECISION) TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.exp(IN arg NUMERIC) +RETURNS DOUBLE PRECISION +AS +$BODY$ +SELECT sys.exp(arg::DOUBLE PRECISION); +$BODY$ +LANGUAGE SQL IMMUTABLE PARALLEL SAFE; +GRANT EXECUTE ON FUNCTION sys.exp(NUMERIC) TO PUBLIC; + +-- BABEL-2259: Support sp_databases System Stored Procedure +-- Lists databases that either reside in an instance of the SQL Server or +-- are accessible through a database gateway + +CREATE OR REPLACE VIEW sys.sp_databases_view AS + SELECT CAST(database_name AS sys.SYSNAME), + -- DATABASE_SIZE returns a NULL value for databases larger than 2.15 TB + CASE WHEN (sum(table_size)/1024.0) > 2.15 * 1024.0 * 1024.0 * 1024.0 THEN NULL + ELSE CAST((sum(table_size)/1024.0) AS int) END as database_size, + CAST(NULL AS sys.VARCHAR(254)) as remarks + FROM ( + SELECT pg_catalog.pg_namespace.oid as schema_oid, + pg_catalog.pg_namespace.nspname as schema_name, + INT.name AS database_name, + coalesce(pg_relation_size(pg_catalog.pg_class.oid), 0) as table_size + FROM + sys.babelfish_namespace_ext EXT + JOIN sys.babelfish_sysdatabases INT ON EXT.dbid = INT.dbid + JOIN pg_catalog.pg_namespace ON pg_catalog.pg_namespace.nspname = EXT.nspname + LEFT JOIN pg_catalog.pg_class ON relnamespace = pg_catalog.pg_namespace.oid + ) t + GROUP BY database_name + ORDER BY database_name; +GRANT SELECT on sys.sp_databases_view TO PUBLIC; + +CREATE OR REPLACE PROCEDURE sys.sp_databases () +AS $$ +BEGIN + SELECT database_name as "DATABASE_NAME", + database_size as "DATABASE_SIZE", + remarks as "REMARKS" from sys.sp_databases_view; +END; +$$ +LANGUAGE 'pltsql'; +GRANT EXECUTE on PROCEDURE sys.sp_databases TO PUBLIC; + +-- For numeric/decimal and float/double precision there is already inbuilt functions, +-- Following sign functions are for remaining datatypes +CREATE OR REPLACE FUNCTION sys.sign(IN arg INT) RETURNS INT AS +$BODY$ +SELECT + CASE + WHEN arg > 0 THEN 1::INT + WHEN arg < 0 THEN -1::INT + ELSE 0::INT + END; +$BODY$ +STRICT +LANGUAGE SQL IMMUTABLE PARALLEL SAFE; +GRANT EXECUTE ON FUNCTION sys.sign(INT) TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.sign(IN arg SMALLINT) RETURNS INT AS +$BODY$ +SELECT sys.sign(arg::INT); +$BODY$ +LANGUAGE SQL IMMUTABLE PARALLEL SAFE; +GRANT EXECUTE ON FUNCTION sys.sign(SMALLINT) TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.sign(IN arg SYS.TINYINT) RETURNS INT AS +$BODY$ +SELECT sys.sign(arg::INT); +$BODY$ +LANGUAGE SQL IMMUTABLE PARALLEL SAFE; +GRANT EXECUTE ON FUNCTION sys.sign(SYS.TINYINT) TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.sign(IN arg BIGINT) RETURNS BIGINT AS +$BODY$ +SELECT + CASE + WHEN arg > 0::BIGINT THEN 1::BIGINT + WHEN arg < 0::BIGINT THEN -1::BIGINT + ELSE 0::BIGINT + END; +$BODY$ +LANGUAGE SQL IMMUTABLE PARALLEL SAFE; +GRANT EXECUTE ON FUNCTION sys.sign(BIGINT) TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.sign(IN arg SYS.MONEY) RETURNS SYS.MONEY AS +$BODY$ +SELECT + CASE + WHEN arg > 0::SYS.MONEY THEN 1::SYS.MONEY + WHEN arg < 0::SYS.MONEY THEN -1::SYS.MONEY + ELSE 0::SYS.MONEY + END; +$BODY$ +LANGUAGE SQL IMMUTABLE PARALLEL SAFE; +GRANT EXECUTE ON FUNCTION sys.sign(SYS.MONEY) TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.sign(IN arg SYS.SMALLMONEY) RETURNS SYS.MONEY AS +$BODY$ +SELECT sys.sign(arg::SYS.MONEY); +$BODY$ +LANGUAGE SQL IMMUTABLE PARALLEL SAFE; +GRANT EXECUTE ON FUNCTION sys.sign(SYS.SMALLMONEY) TO PUBLIC; + +-- To handle remaining input datatypes +CREATE OR REPLACE FUNCTION sys.sign(IN arg ANYELEMENT) RETURNS SYS.FLOAT AS +$BODY$ +SELECT + sign(arg::SYS.FLOAT); +$BODY$ +LANGUAGE SQL IMMUTABLE PARALLEL SAFE; +GRANT EXECUTE ON FUNCTION sys.sign(ANYELEMENT) TO PUBLIC; + +-- Duplicate functions with arg TEXT since ANYELEMNT cannot handle type unknown. +CREATE OR REPLACE FUNCTION sys.sign(IN arg TEXT) RETURNS SYS.FLOAT AS +$BODY$ +SELECT + sign(arg::SYS.FLOAT); +$BODY$ +LANGUAGE SQL IMMUTABLE PARALLEL SAFE; +GRANT EXECUTE ON FUNCTION sys.sign(TEXT) TO PUBLIC; +CREATE OR REPLACE FUNCTION sys.lock_timeout() + RETURNS integer + LANGUAGE plpgsql + STRICT + AS $$ + declare return_value integer; + begin + return_value := (select s.setting FROM pg_catalog.pg_settings s where name = 'lock_timeout'); + RETURN return_value; + EXCEPTION + WHEN others THEN + RETURN NULL; + END; + $$; + GRANT EXECUTE ON FUNCTION sys.lock_timeout() TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.max_connections() +RETURNS integer +LANGUAGE plpgsql +STRICT +AS $$ +declare return_value integer; +begin + return_value := (select s.setting FROM pg_catalog.pg_settings s where name = 'max_connections'); + RETURN return_value; +EXCEPTION + WHEN others THEN + RETURN NULL; +END; +$$; +GRANT EXECUTE ON FUNCTION sys.max_connections() TO PUBLIC; + + CREATE OR REPLACE FUNCTION sys.trigger_nestlevel() + RETURNS integer + LANGUAGE plpgsql + STRICT + AS $$ + declare return_value integer; + begin + return_value := (select pg_trigger_depth()); + RETURN return_value; + EXCEPTION + WHEN others THEN + RETURN NULL; + END; + $$; + GRANT EXECUTE ON FUNCTION sys.trigger_nestlevel() TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.schema_name() +RETURNS sys.sysname +LANGUAGE plpgsql +STRICT +AS $function$ +begin + RETURN (select orig_name from sys.babelfish_namespace_ext ext + where ext.nspname = (select current_schema()) and ext.dbid::oid = sys.db_id()::oid)::sys.sysname; +EXCEPTION + WHEN others THEN + RETURN NULL; +END; +$function$ +; +GRANT EXECUTE ON FUNCTION sys.schema_name() TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.original_login() +RETURNS sys.sysname +LANGUAGE plpgsql +STRICT +AS $$ +declare return_value text; +begin + RETURN (select session_user)::sys.sysname; +EXCEPTION + WHEN others THEN + RETURN NULL; +END; +$$; +GRANT EXECUTE ON FUNCTION sys.original_login() TO PUBLIC; + + CREATE OR REPLACE FUNCTION sys.columnproperty(object_id oid, property name, property_name text) + RETURNS integer + LANGUAGE plpgsql + STRICT + AS $$ + declare extra_bytes CONSTANT integer := 4; + declare return_value integer; + begin + return_value := ( + select + case LOWER(property_name) + when 'charmaxlen' then + (select CASE WHEN a.atttypmod > 0 THEN a.atttypmod - extra_bytes ELSE NULL END from pg_catalog.pg_attribute a where a.attrelid = object_id and a.attname = property) + when 'allowsnull' then + (select CASE WHEN a.attnotnull THEN 0 ELSE 1 END from pg_catalog.pg_attribute a where a.attrelid = object_id and a.attname = property) + else + null + end + ); + + RETURN return_value::integer; + EXCEPTION + WHEN others THEN + RETURN NULL; + END; + $$; + GRANT EXECUTE ON FUNCTION sys.columnproperty(object_id oid, property name, property_name text) TO PUBLIC; + + COMMENT ON FUNCTION sys.columnproperty + IS 'This function returns column or parameter information. Currently only works with "charmaxlen", and "allowsnull" otherwise returns 0.'; + +create or replace view sys.default_constraints +AS +select CAST(('DF_' || o.relname || '_' || d.oid) as 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 modified_date + , 0::sys.bit as is_ms_shipped + , 0::sys.bit as is_published + , 0::sys.bit as is_schema_published + , d.adnum::int as parent_column_id + , pg_get_expr(d.adbin, d.adrelid) as definition + , 1::sys.bit as is_system_named +from pg_catalog.pg_attrdef as d +inner join pg_catalog.pg_class as o on (d.adrelid = o.oid); +GRANT SELECT ON sys.default_constraints TO PUBLIC; + +CREATE OR REPLACE VIEW sys.computed_columns +AS +SELECT out_object_id as object_id + , out_name as name + , out_column_id as column_id + , out_system_type_id as system_type_id + , out_user_type_id as user_type_id + , out_max_length as max_length + , out_precision as precision + , out_scale as scale + , out_collation_name as collation_name + , out_is_nullable as is_nullable + , out_is_ansi_padded as is_ansi_padded + , out_is_rowguidcol as is_rowguidcol + , out_is_identity as is_identity + , out_is_computed as is_computed + , out_is_filestream as is_filestream + , out_is_replicated as is_replicated + , out_is_non_sql_subscribed as is_non_sql_subscribed + , out_is_merge_published as is_merge_published + , out_is_dts_replicated as is_dts_replicated + , out_is_xml_document as is_xml_document + , out_xml_collection_id as xml_collection_id + , out_default_object_id as default_object_id + , out_rule_object_id as rule_object_id + , out_is_sparse as is_sparse + , out_is_column_set as is_column_set + , out_generated_always_type as generated_always_type + , out_generated_always_type_desc as generated_always_type_desc + , out_encryption_type as encryption_type + , out_encryption_type_desc as encryption_type_desc + , out_encryption_algorithm_name as encryption_algorithm_name + , out_column_encryption_key_id as column_encryption_key_id + , out_column_encryption_key_database_name as column_encryption_key_database_name + , out_is_hidden as is_hidden + , out_is_masked as is_masked + , out_graph_type as graph_type + , out_graph_type_desc as graph_type_desc + , substring(pg_get_expr(d.adbin, d.adrelid), 1, 4000)::sys.nvarchar(4000) AS definition + , 1::sys.bit AS uses_database_collation + , 0::sys.bit AS is_persisted +FROM sys.columns_internal() sc +INNER JOIN pg_attribute a ON sc.out_name = a.attname AND sc.out_column_id = a.attnum +INNER JOIN pg_attrdef d ON d.adrelid = a.attrelid AND d.adnum = a.attnum +WHERE a.attgenerated = 's' AND sc.out_is_computed::integer = 1; +GRANT SELECT ON sys.computed_columns TO PUBLIC; + +create or replace view sys.index_columns +as +select i.indrelid::integer as object_id + , i.indexrelid::integer as index_id + , a.attrelid::integer as index_column_id + , a.attnum::integer as column_id + , a.attnum::sys.tinyint as key_ordinal + , 0::sys.tinyint as partition_ordinal + , 0::sys.bit as is_descending_key + , 1::sys.bit as is_included_column +from pg_index as i +inner join pg_catalog.pg_attribute a on i.indexrelid = a.attrelid; +GRANT SELECT ON sys.index_columns TO PUBLIC; + +CREATE or replace VIEW sys.check_constraints AS +SELECT CAST(c.conname as sys.sysname) as name + , oid::integer as object_id + , c.connamespace::integer as principal_id + , c.connamespace::integer as schema_id + , 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::sys.bit as is_ms_shipped + , 0::sys.bit as is_published + , 0::sys.bit as is_schema_published + , 0::sys.bit as is_disabled + , 0::sys.bit as is_not_for_replication + , 0::sys.bit as is_not_trusted + , c.conkey[1]::integer AS parent_column_id + , substring(pg_get_constraintdef(c.oid) from 7) AS definition + , 1::sys.bit as uses_database_collation + , 0::sys.bit as is_system_named +FROM pg_catalog.pg_constraint as c +WHERE c.contype = 'c' and c.conrelid != 0; +GRANT SELECT ON sys.check_constraints TO PUBLIC; + +create or replace view sys.indexes as +select + i.indrelid as object_id + , c.relname as name + , case when i.indisclustered then 1 else 2 end as type + , case when i.indisclustered then 'CLUSTERED'::varchar(60) else 'NONCLUSTERED'::varchar(60) end as type_desc + , case when i.indisunique then 1 else 0 end as is_unique + , c.reltablespace as data_space_id + , 0 as ignore_dup_key + , case when i.indisprimary then 1 else 0 end as is_primary_key + , case when constr.oid is null then 0 else 1 end as is_unique_constraint + , 0 as fill_factor + , case when i.indpred is null then 0 else 1 end as is_padded + , case when i.indisready then 0 else 1 end is_disabled + , 0 as is_hypothetical + , 1 as allow_row_locks + , 1 as allow_page_locks + , 0 as has_filter + , null::varchar as filter_definition + , 0 as auto_created + , c.oid as index_id +from pg_class c +inner join pg_namespace s on s.oid = c.relnamespace +inner join pg_index i on i.indexrelid = c.oid +left join pg_constraint constr on constr.conindid = c.oid +where c.relkind = 'i' and i.indislive +and s.nspname not in ('information_schema', 'pg_catalog'); +GRANT SELECT ON sys.indexes TO PUBLIC; + +-- substring -- +CREATE OR REPLACE FUNCTION sys.substring(string TEXT, i INTEGER, j INTEGER) +RETURNS sys.VARCHAR +AS 'babelfishpg_tsql', 'tsql_varchar_substr' LANGUAGE C IMMUTABLE PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.substring(string sys.VARCHAR, i INTEGER, j INTEGER) +RETURNS sys.VARCHAR +AS 'babelfishpg_tsql', 'tsql_varchar_substr' LANGUAGE C IMMUTABLE PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.substring(string sys.VARCHAR, i INTEGER, j INTEGER) +RETURNS sys.VARCHAR +AS 'babelfishpg_tsql', 'tsql_varchar_substr' LANGUAGE C IMMUTABLE PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.substring(string sys.NVARCHAR, i INTEGER, j INTEGER) +RETURNS sys.NVARCHAR +AS 'babelfishpg_tsql', 'tsql_varchar_substr' LANGUAGE C IMMUTABLE PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.substring(string sys.NCHAR, i INTEGER, j INTEGER) +RETURNS sys.NVARCHAR +AS 'babelfishpg_tsql', 'tsql_varchar_substr' LANGUAGE C IMMUTABLE PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.microsoftversion() +RETURNS INTEGER AS +$BODY$ + SELECT 201332885::INTEGER; +$BODY$ +LANGUAGE SQL IMMUTABLE STRICT PARALLEL SAFE; +CREATE VIEW sys.sp_pkeys_view AS +SELECT +CAST(t2.dbname AS sys.sysname) AS TABLE_QUALIFIER, +CAST(t3.rolname 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 + JOIN information_schema.columns t4 ON t1.relname = t4.table_name + 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.dtd_identifier AS smallint) = ANY (t5.conkey) + AND CAST(t4.dtd_identifier AS smallint) = t5.conkey[seq]; + +GRANT SELECT on sys.sp_pkeys_view TO PUBLIC; + +-- internal function in order to workaround BABEL-1597 +create function sys.sp_pkeys_internal( + in_table_name sys.nvarchar(384), + in_table_owner sys.nvarchar(384) = '', + in_table_qualifier sys.nvarchar(384) = '' +) +returns table( + out_table_qualifier sys.sysname, + out_table_owner sys.sysname, + out_table_name sys.sysname, + out_column_name sys.sysname, + out_key_seq smallint, + out_pk_name sys.sysname +) +as $$ +begin + return query + select * from sys.sp_pkeys_view + where in_table_name = table_name + and ((SELECT coalesce(in_table_owner,'')) = '' or table_owner = in_table_owner) + and ((SELECT coalesce(in_table_qualifier,'')) = '' or table_qualifier = in_table_qualifier) + order by table_qualifier, table_owner, table_name, key_seq; +end; +$$ +LANGUAGE plpgsql; + +CREATE OR REPLACE PROCEDURE sys.sp_pkeys( + "@table_name" sys.nvarchar(384), + "@table_owner" sys.nvarchar(384) = '', + "@table_qualifier" sys.nvarchar(384) = '' +) +AS $$ +BEGIN + select out_table_qualifier as table_qualifier, + out_table_owner as table_owner, + out_table_name as table_name, + out_column_name as column_name, + out_key_seq as key_seq, + out_pk_name as pk_name + from sys.sp_pkeys_internal(@table_name, @table_owner, @table_qualifier); +END; +$$ +LANGUAGE 'pltsql'; +GRANT ALL on PROCEDURE sys.sp_pkeys TO PUBLIC; + +CREATE VIEW sys.sp_statistics_view AS +SELECT +CAST(t2.dbname AS sys.sysname) AS TABLE_QUALIFIER, +CAST(t3.rolname AS sys.sysname) AS TABLE_OWNER, +CAST(t1.relname 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 t7.starelid > 0 THEN CAST(0 AS smallint) +ELSE + CASE + WHEN t5.indisclustered = 't' THEN CAST(1 AS smallint) + ELSE CAST(3 AS smallint) + END +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.stadistinct 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.pg_namespace_ext t2 ON t1.relnamespace = t2.oid + JOIN pg_catalog.pg_roles t3 ON t1.relowner = t3.oid + JOIN information_schema.columns t4 ON t1.relname = t4.table_name + JOIN (pg_catalog.pg_index t5 JOIN + pg_catalog.pg_class t6 ON t5.indexrelid = t6.oid) ON t1.oid = t5.indrelid + LEFT JOIN pg_catalog.pg_statistic t7 ON t1.oid = t7.starelid + 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.dtd_identifier AS smallint) = ANY (t5.indkey) + AND CAST(t4.dtd_identifier AS smallint) = t5.indkey[seq]; +GRANT SELECT on sys.sp_statistics_view TO PUBLIC; + +create function sys.sp_statistics_internal( + in_table_name sys.sysname, + in_table_owner sys.sysname = '', + in_table_qualifier sys.sysname = '', + in_index_name sys.sysname = '', + in_is_unique char = 'N', + in_accuracy char = 'Q' +) +returns table( + out_table_qualifier sys.sysname, + out_table_owner sys.sysname, + out_table_name sys.sysname, + out_non_unique smallint, + out_index_qualifier sys.sysname, + out_index_name sys.sysname, + out_type smallint, + out_seq_in_index smallint, + out_column_name sys.sysname, + out_collation sys.varchar(1), + out_cardinality int, + out_pages int, + out_filter_condition sys.varchar(128) +) +as $$ +begin + return query + select * from sys.sp_statistics_view + where in_table_name = table_name + and ((SELECT coalesce(in_table_owner,'')) = '' or table_owner = in_table_owner) + and ((SELECT coalesce(in_table_qualifier,'')) = '' or table_qualifier = in_table_qualifier) + and ((SELECT coalesce(in_index_name,'')) = '' or index_name like in_index_name) + and ((in_is_unique = 'N') or (in_is_unique = 'Y' and non_unique = 0)) + order by non_unique, type, index_name, seq_in_index; +end; +$$ +LANGUAGE plpgsql; + +CREATE OR REPLACE PROCEDURE sys.sp_statistics( + "@table_name" sys.sysname, + "@table_owner" sys.sysname = '', + "@table_qualifier" sys.sysname = '', + "@index_name" sys.sysname = '', + "@is_unique" char = 'N', + "@accuracy" char = 'Q' +) +AS $$ +BEGIN + select out_table_qualifier as table_qualifier, + out_table_owner as table_owner, + out_table_name as table_name, + out_non_unique as non_unique, + out_index_qualifier as index_qualifier, + out_index_name as index_name, + out_type as type, + out_seq_in_index as seq_in_index, + out_column_name as column_name, + out_collation as collation, + out_cardinality as cardinality, + out_pages as pages, + out_filter_condition as filter_condition + from sys.sp_statistics_internal(@table_name, @table_owner, @table_qualifier, @index_name, @is_unique, @accuracy); +END; +$$ +LANGUAGE 'pltsql'; +GRANT ALL on PROCEDURE sys.sp_statistics TO PUBLIC; + +-- same as sp_statistics +CREATE OR REPLACE PROCEDURE sys.sp_statistics_100( + "@table_name" sys.sysname, + "@table_owner" sys.sysname = '', + "@table_qualifier" sys.sysname = '', + "@index_name" sys.sysname = '', + "@is_unique" char = 'N', + "@accuracy" char = 'Q' +) +AS $$ +BEGIN + select out_table_qualifier as table_qualifier, + out_table_owner as table_owner, + out_table_name as table_name, + out_non_unique as non_unique, + out_index_qualifier as index_qualifier, + out_index_name as index_name, + out_type as type, + out_seq_in_index as seq_in_index, + out_column_name as column_name, + out_collation as collation, + out_cardinality as cardinality, + out_pages as pages, + out_filter_condition as filter_condition + from sys.sp_statistics_internal(@table_name, @table_owner, @table_qualifier, @index_name, @is_unique, @accuracy); +END; +$$ +LANGUAGE 'pltsql'; +GRANT ALL on PROCEDURE sys.sp_statistics_100 TO PUBLIC; + +-- Duplicate function with arg TEXT since ANYELEMENT cannot handle type unknown. +CREATE OR REPLACE FUNCTION sys.datepart(IN datepart PG_CATALOG.TEXT, IN arg TEXT) RETURNS INTEGER +AS +$body$ +BEGIN + IF pg_typeof(arg) = 'sys.DATETIMEOFFSET'::regtype THEN + return sys.datepart_internal(datepart, arg::timestamp, + sys.babelfish_get_datetimeoffset_tzoffset(arg)::integer); + ELSE + return sys.datepart_internal(datepart, arg); + END IF; +END; +$body$ +LANGUAGE plpgsql IMMUTABLE; + + -- Duplicate functions with arg TEXT since ANYELEMENT cannot handle type unknown. +CREATE OR REPLACE FUNCTION sys.dateadd(IN datepart PG_CATALOG.TEXT, IN num INTEGER, IN startdate TEXT) RETURNS DATETIME +AS +$body$ +BEGIN + IF pg_typeof(startdate) = 'sys.DATETIMEOFFSET'::regtype THEN + return sys.dateadd_internal_df(datepart, num, + startdate); + ELSE + return sys.dateadd_internal(datepart, num, + startdate); + END IF; +END; +$body$ +LANGUAGE plpgsql IMMUTABLE; + +-- Duplicate functions with arg TEXT since ANYELEMENT cannot handle type unknown. +CREATE OR REPLACE FUNCTION sys.datename(IN dp PG_CATALOG.TEXT, IN arg TEXT) RETURNS TEXT AS +$BODY$ +SELECT + CASE + WHEN dp = 'month'::text THEN + to_char(arg::date, 'TMMonth') + -- '1969-12-28' is a Sunday + WHEN dp = 'dow'::text THEN + to_char(arg::date, 'TMDay') + ELSE + sys.datepart(dp, arg)::TEXT + END +$BODY$ +STRICT +LANGUAGE sql IMMUTABLE; + +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 split_part(p.attoptions[1], '=', 2) + ELSE c.name 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) + WHERE + c.is_sparse = 0 AND p.attnum >= 0; +GRANT SELECT ON sys.spt_tablecollations_view TO PUBLIC; + +CREATE OR REPLACE PROCEDURE sys.sp_tablecollations_100 +( + IN "@object" nvarchar(4000) +) +AS $$ +BEGIN + select + s_tcv.colid AS colid, + s_tcv.name AS name, + s_tcv.tds_collation_100 AS tds_collation, + s_tcv.collation_100 AS collation + from + sys.spt_tablecollations_view s_tcv + where + s_tcv.object_id = sys.object_id(@object) + order by colid; +END; +$$ +LANGUAGE 'pltsql'; + +CREATE OR REPLACE PROCEDURE sys.printarg(IN "@message" TEXT) +AS $$ +BEGIN + PRINT @message; +END; +$$ LANGUAGE pltsql; +GRANT EXECUTE ON PROCEDURE sys.printarg(IN "@message" TEXT) TO PUBLIC; + +CREATE OR REPLACE PROCEDURE sys.sp_updatestats(IN "@resample" VARCHAR(8) DEFAULT 'NO') +AS $$ +BEGIN + IF sys.user_name() != 'dbo' THEN + RAISE EXCEPTION 'user does not have permission'; + END IF; + + IF lower("@resample") = 'resample' THEN + RAISE NOTICE 'ignoring resample option'; + ELSIF lower("@resample") != 'no' THEN + RAISE EXCEPTION 'Invalid option name %', "@resample"; + END IF; + + ANALYZE VERBOSE; + + CALL printarg('Statistics for all tables have been updated. Refer logs for details.'); +END; +$$ LANGUAGE plpgsql; +GRANT EXECUTE on PROCEDURE sys.sp_updatestats(IN "@resample" VARCHAR(8)) TO PUBLIC; + +-- internal function that returns relevant info needed +-- by sys.syscolumns view for all procedure parameters. +-- This separate function was needed to workaround BABEL-1597 +CREATE FUNCTION sys.proc_param_helper() +RETURNS TABLE ( + name sys.sysname, + id int, + xtype int, + colid smallint, + collationid int, + prec smallint, + scale int, + isoutparam int, + collation sys.sysname +) +AS +$$ +BEGIN +RETURN QUERY +select params.parameter_name::sys.sysname + , pgproc.oid::int + , CAST(case when pgproc.proallargtypes is null then split_part(pgproc.proargtypes::varchar, ' ', params.ordinal_position) + else split_part(btrim(pgproc.proallargtypes::text,'{}'), ',', params.ordinal_position) end AS int) + , params.ordinal_position::smallint + , coll.oid::int + , params.numeric_precision::smallint + , params.numeric_scale::int + , case params.parameter_mode when 'OUT' then 1 when 'INOUT' then 1 else 0 end + , params.collation_name::sys.sysname +from information_schema.routines routine +left join information_schema.parameters params + on routine.specific_schema = params.specific_schema + and routine.specific_name = params.specific_name +left join pg_collation coll on coll.collname = params.collation_name +/* assuming routine.specific_name is constructed by concatenating procedure name and oid */ +left join pg_proc pgproc on routine.specific_name = nameconcatoid(pgproc.proname, pgproc.oid) +where routine.routine_schema not in ('pg_catalog', 'information_schema') + and routine.routine_type = 'PROCEDURE'; +END; +$$ +LANGUAGE plpgsql; + +CREATE OR REPLACE VIEW sys.syscolumns AS +SELECT out_name as name + , out_object_id as id + , out_system_type_id as xtype + , 0::sys.tinyint as typestat + , (case when out_user_type_id < 32767 then out_user_type_id else null end)::smallint as xusertype + , out_max_length as length + , 0::sys.tinyint as xprec + , 0::sys.tinyint as xscale + , out_column_id::smallint as colid + , 0::smallint as xoffset + , 0::sys.tinyint as bitpos + , 0::sys.tinyint as reserved + , 0::smallint as colstat + , out_default_object_id::int as cdefault + , out_rule_object_id::int as domain + , 0::smallint as number + , 0::smallint as colorder + , null::sys.varbinary(8000) as autoval + , out_offset as offset + , out_collation_id as collationid + , (case out_is_nullable::int when 1 then 8 else 0 end + + case out_is_identity::int when 1 then 128 else 0 end)::sys.tinyint as status + , out_system_type_id as type + , (case when out_user_type_id < 32767 then out_user_type_id else null end)::smallint as usertype + , null::varchar(255) as printfmt + , out_precision::smallint as prec + , out_scale::int as scale + , out_is_computed::int as iscomputed + , 0::int as isoutparam + , out_is_nullable::int as isnullable + , out_collation_name::sys.sysname as collation +FROM sys.columns_internal() +union all +SELECT p.name + , p.id + , p.xtype + , 0::sys.tinyint as typestat + , (case when p.xtype < 32767 then p.xtype else null end)::smallint as xusertype + , null as length + , 0::sys.tinyint as xprec + , 0::sys.tinyint as xscale + , p.colid + , 0::smallint as xoffset + , 0::sys.tinyint as bitpos + , 0::sys.tinyint as reserved + , 0::smallint as colstat + , null::int as cdefault + , null::int as domain + , 0::smallint as number + , 0::smallint as colorder + , null::sys.varbinary(8000) as autoval + , 0::smallint as offset + , collationid + , (case p.isoutparam when 1 then 64 else 0 end)::sys.tinyint as status + , p.xtype as type + , (case when p.xtype < 32767 then p.xtype else null end)::smallint as usertype + , null::varchar(255) as printfmt + , p.prec + , p.scale + , 0::int as iscomputed + , p.isoutparam + , 1::int as isnullable + , p.collation +FROM sys.proc_param_helper() as p; +GRANT SELECT ON sys.syscolumns TO PUBLIC; + +-- 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 new file mode 100644 index 00000000000..340d7747075 --- /dev/null +++ b/contrib/babelfishpg_tsql/src/analyzer.c @@ -0,0 +1,318 @@ +#include "postgres.h" +#include "analyzer.h" +#include "dynastack.h" +#include "stmt_walker.h" + +#define ANALYZER_INITIAL_STACK_SIZE 8 + +/*********************************************************************************** + * VISITOR ACTIONS DEFINITIONS + **********************************************************************************/ +static bool analyzer_try_catch_act(Walker_context *ctx, PLtsql_stmt_try_catch *stmt); +static bool analyzer_goto_act(Walker_context *ctx, PLtsql_stmt_goto *stmt); +static bool analyzer_label_act(Walker_context *ctx, PLtsql_stmt_label *stmt); +static bool analyzer_while_act(Walker_context *ctx, PLtsql_stmt_while *stmt); +static bool analyzer_exit_act(Walker_context *ctx, PLtsql_stmt_exit *stmt); +static bool analyzer_return_act(Walker_context *ctx, PLtsql_stmt_return *stmt); + +/*********************************************************************************** + * ANALYZER CONTEXT + **********************************************************************************/ +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 +{ + /* 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; +} AnalyzerContext; + +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; +} + +static void destroy_analyzer_context(void *ctx) +{ + AnalyzerContext *analyzer_ctx = (AnalyzerContext *) ctx; + + destroy_vector(analyzer_ctx->trycatch_info_stack); + destroy_vector(analyzer_ctx->loop_stack); + destroy_vector(analyzer_ctx->gotos); + + pfree(analyzer_ctx); +} + +/*********************************************************************************** + * VISITOR ACTIONS IMPLEMENTATION + **********************************************************************************/ +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); +} + +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; + + 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 */ + + 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 */ + + vec_pop_back(analyzer_ctx->trycatch_info_stack); + + return false; +} + +static bool analyzer_goto_act(Walker_context *ctx, PLtsql_stmt_goto *stmt) +{ + 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); +} + +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); +} + +static bool analyzer_while_act(Walker_context *ctx, PLtsql_stmt_while *stmt) +{ + AnalyzerContext *analyzer_ctx = (AnalyzerContext*) ctx->extra_ctx; + ListCell *s; + + 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); + + vec_pop_back(analyzer_ctx->loop_stack); + return false; +} + +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); +} + +static bool analyzer_return_act(Walker_context *ctx, PLtsql_stmt_return *stmt) +{ + AnalyzerContext *analyzer_ctx = (AnalyzerContext*) ctx->extra_ctx; + + save_scope((PLtsql_stmt*) stmt, analyzer_ctx); + return stmt_walker((PLtsql_stmt*)stmt, &general_walker_func, ctx); +} + +/*********************************************************************************** + * 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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 new file mode 100644 index 00000000000..0ba543a702b --- /dev/null +++ b/contrib/babelfishpg_tsql/src/analyzer.h @@ -0,0 +1,8 @@ +#ifndef ANALYZER_H +#define ANALYZER_H +#include "pltsql.h" +#include "compile_context.h" + +void analyze(PLtsql_function *func, CompileContext *cmpl_ctx); + +#endif /* ANALYZE_H */ diff --git a/contrib/babelfishpg_tsql/src/antlrTests/decl.sql b/contrib/babelfishpg_tsql/src/antlrTests/decl.sql new file mode 100644 index 00000000000..a009a5d1984 --- /dev/null +++ b/contrib/babelfishpg_tsql/src/antlrTests/decl.sql @@ -0,0 +1,14 @@ +DO $$ +DECLARE @X INT = 42 +DECLARE @Y INT = @X * 2 + +PRINT @X +PRINT @Y + +BEGIN + DECLARE @INNER INT = @Y - 1 + PRINT @INNER +END + + PRINT @INNER +$$ LANGUAGE 'pltsql' diff --git a/contrib/babelfishpg_tsql/src/antlrTests/ifelse.sql b/contrib/babelfishpg_tsql/src/antlrTests/ifelse.sql new file mode 100644 index 00000000000..314284fe3f2 --- /dev/null +++ b/contrib/babelfishpg_tsql/src/antlrTests/ifelse.sql @@ -0,0 +1,17 @@ +DO $$ + +DECLARE @X INT = 4 + +IF (@X = 3) + PRINT '3' +ELSE IF (@X = 4) + BEGIN + PRINT 'the answer is: ' + PRINT '4' + END +ELSE IF (@X = 5) + PRINT '5' +ELSE + PRINT 'unknown' + +$$LANGUAGE 'pltsql' diff --git a/contrib/babelfishpg_tsql/src/antlrTests/inval.sql b/contrib/babelfishpg_tsql/src/antlrTests/inval.sql new file mode 100644 index 00000000000..34bc8caee01 --- /dev/null +++ b/contrib/babelfishpg_tsql/src/antlrTests/inval.sql @@ -0,0 +1,23 @@ +DROP TABLE foo +GO + +DROP FUNCTION needs_foo() +GO + +CREATE TABLE foo(pkey int) +GO + +CREATE FUNCTION needs_foo() RETURNS bool AS +$$ +DECLARE + x foo%ROWTYPE; +BEGIN + + FOR x IN SELECT * FROM foo LOOP + x.pkey := 4; + END LOOP; + + RETURN true; + +END; +$$ LANGUAGE plpgsql; diff --git a/contrib/babelfishpg_tsql/src/antlrTests/nestedBlocks.sql b/contrib/babelfishpg_tsql/src/antlrTests/nestedBlocks.sql new file mode 100644 index 00000000000..d015c69179f --- /dev/null +++ b/contrib/babelfishpg_tsql/src/antlrTests/nestedBlocks.sql @@ -0,0 +1,15 @@ +DO $$ + PRINT 'line 1' + BEGIN + PRINT 2 + END + + BEGIN + PRINT 3 * 1 + PRINT [upper]('four score and seven years ago') + BEGIN + PRINT 4 + END + END + +$$ LANGUAGE 'pltsql' diff --git a/contrib/babelfishpg_tsql/src/antlrTests/oneBlock.sql b/contrib/babelfishpg_tsql/src/antlrTests/oneBlock.sql new file mode 100644 index 00000000000..ecbaa5332df --- /dev/null +++ b/contrib/babelfishpg_tsql/src/antlrTests/oneBlock.sql @@ -0,0 +1,6 @@ +DO $$ +BEGIN + PRINT 1 + PRINT 2 +END +$$ LANGUAGE 'pltsql' diff --git a/contrib/babelfishpg_tsql/src/antlrTests/print.sql b/contrib/babelfishpg_tsql/src/antlrTests/print.sql new file mode 100644 index 00000000000..bd6e5f1f233 --- /dev/null +++ b/contrib/babelfishpg_tsql/src/antlrTests/print.sql @@ -0,0 +1,14 @@ +DO $$ +PRINT 1 +PRINT 2 +PRINT 3 +PRINT 4 +PRINT 5 +-- IF (@X < 10) +--BEGIN +-- PRINT 6 +-- PRINT 7 +-- PRINT 8 +-- END +PRINT 9 +$$ LANGUAGE 'pltsql' diff --git a/contrib/babelfishpg_tsql/src/antlrTests/print2.sql b/contrib/babelfishpg_tsql/src/antlrTests/print2.sql new file mode 100644 index 00000000000..35d1b054512 --- /dev/null +++ b/contrib/babelfishpg_tsql/src/antlrTests/print2.sql @@ -0,0 +1,13 @@ +DO $$ +BEGIN + PRINT 1 + PRINT 2 + + BEGIN + PRINT 3 + PRINT 4 + END + + DROP TABLE [foo] +END +$$ LANGUAGE 'pltsql' diff --git a/contrib/babelfishpg_tsql/src/antlrTests/proc_simple.sql b/contrib/babelfishpg_tsql/src/antlrTests/proc_simple.sql new file mode 100644 index 00000000000..0cd9187663b --- /dev/null +++ b/contrib/babelfishpg_tsql/src/antlrTests/proc_simple.sql @@ -0,0 +1,6 @@ +DO $$ +CREATE FUNCTION RETURN_42() RETURNS INT AS +BEGIN + RETURN 42 +END +$$ LANGUAGE 'pltsql' diff --git a/contrib/babelfishpg_tsql/src/antlrTests/returnsTable.sql b/contrib/babelfishpg_tsql/src/antlrTests/returnsTable.sql new file mode 100644 index 00000000000..0ed02b892c7 --- /dev/null +++ b/contrib/babelfishpg_tsql/src/antlrTests/returnsTable.sql @@ -0,0 +1,5 @@ +DO $$ +CREATE FUNCTION CLASSES (@MINPAGES AS INT) RETURNS TABLE AS + RETURN (SELECT 42 AS VALUE) + -- RELNAME, RELPAGES FROM PG_CLASS WHERE RELPAGES > @MINPAGES +$$ LANGUAGE 'pltsql' diff --git a/contrib/babelfishpg_tsql/src/antlrTests/series.sql b/contrib/babelfishpg_tsql/src/antlrTests/series.sql new file mode 100644 index 00000000000..688830a973d --- /dev/null +++ b/contrib/babelfishpg_tsql/src/antlrTests/series.sql @@ -0,0 +1,11 @@ +DO $$ + + PRINT 'line 1' + + INSERT INTO [foo] VALUES(1,2,3*4) + + THROW + + RETURN 42 + +$$ LANGUAGE 'pltsql' diff --git a/contrib/babelfishpg_tsql/src/antlrTests/simple.sql b/contrib/babelfishpg_tsql/src/antlrTests/simple.sql new file mode 100644 index 00000000000..cbef5f9255c --- /dev/null +++ b/contrib/babelfishpg_tsql/src/antlrTests/simple.sql @@ -0,0 +1,6 @@ +DO $$ + PRINT 'line 1' + PRINT 2 + PRINT 3 * 2 + +$$ LANGUAGE 'pltsql' diff --git a/contrib/babelfishpg_tsql/src/antlrTests/simple2.sql b/contrib/babelfishpg_tsql/src/antlrTests/simple2.sql new file mode 100644 index 00000000000..0ba7d4da539 --- /dev/null +++ b/contrib/babelfishpg_tsql/src/antlrTests/simple2.sql @@ -0,0 +1,10 @@ +DO $$ + PRINT 'line 1' + BEGIN + PRINT 'nested' + PRINT 'block' + END + PRINT 2 + PRINT 3 * 2 + +$$ LANGUAGE 'pltsql' diff --git a/contrib/babelfishpg_tsql/src/antlrTests/single.sql b/contrib/babelfishpg_tsql/src/antlrTests/single.sql new file mode 100644 index 00000000000..7239907898a --- /dev/null +++ b/contrib/babelfishpg_tsql/src/antlrTests/single.sql @@ -0,0 +1,3 @@ +DO $$ + PRINT 'line 1' +$$ LANGUAGE 'pltsql' diff --git a/contrib/babelfishpg_tsql/src/antlrTests/throw.sql b/contrib/babelfishpg_tsql/src/antlrTests/throw.sql new file mode 100644 index 00000000000..41cb6ef035e --- /dev/null +++ b/contrib/babelfishpg_tsql/src/antlrTests/throw.sql @@ -0,0 +1,3 @@ +DO $$ +THROW 52000, 'error message goes here', 200 +$$ LANGUAGE 'pltsql' diff --git a/contrib/babelfishpg_tsql/src/antlrTests/tryCatch.sql b/contrib/babelfishpg_tsql/src/antlrTests/tryCatch.sql new file mode 100644 index 00000000000..f83878f940a --- /dev/null +++ b/contrib/babelfishpg_tsql/src/antlrTests/tryCatch.sql @@ -0,0 +1,26 @@ +DO $$ + DECLARE @VAL INT + + BEGIN TRY + PRINT 'inside try' + + SET @VAL = @VAL / 0 + + PRINT 'never reached' + + END TRY + BEGIN CATCH + PRINT 'inside catch' + END CATCH + + PRINT 'between' + + BEGIN TRY + PRINT 'inside second try' + END TRY + BEGIN CATCH + PRINT 'never reached' + END CATCH + + PRINT 'final' +$$ LANGUAGE 'pltsql' diff --git a/contrib/babelfishpg_tsql/src/antlrTests/while.sql b/contrib/babelfishpg_tsql/src/antlrTests/while.sql new file mode 100644 index 00000000000..82efcc2fd50 --- /dev/null +++ b/contrib/babelfishpg_tsql/src/antlrTests/while.sql @@ -0,0 +1,23 @@ +DO $$ +DECLARE @X INT = 0 + +WHILE( @X < 10 ) +BEGIN + PRINT @X + SET @X = @X + 1 + + IF @X = 5 + BEGIN + PRINT 'skipping 5' + CONTINUE + END + + IF @X = 7 + BREAK + +END + +PRINT 'yyy' + +$$ LANGUAGE 'pltsql' + diff --git a/contrib/babelfishpg_tsql/src/applock.c b/contrib/babelfishpg_tsql/src/applock.c new file mode 100644 index 00000000000..df09465706d --- /dev/null +++ b/contrib/babelfishpg_tsql/src/applock.c @@ -0,0 +1,889 @@ +/*------------------------------------------------------------------------- + * + * applock.c + * Application Lock Functionality for Babelfish + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "access/xact.h" +#include "executor/spi.h" +#include "fmgr.h" +#include "miscadmin.h" +#include "parser/parser.h" +#include "pltsql.h" +#include "storage/lmgr.h" +#include "utils/builtins.h" +#include "utils/guc.h" +#include "utils/timeout.h" +#include "datatypes.h" + + +PG_FUNCTION_INFO_V1(sp_getapplock_function); +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 + * 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; + +/* Max length of applock resource name string (including the ending '\0') */ +#define APPLOCK_MAX_RESOURCE_LENGTH 256 +/* + * 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 + * 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]; /* 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 */ +typedef struct +{ + slist_node sn; + short mode; +} AppLockModeNode; + +/* + * Applock modes + * + * Table of compatibility ('Yes' indicates compatible): + * + * mode IS S U IX X + * Intent shared (IS) Yes Yes Yes Yes No + * Shared (S) Yes Yes Yes No No + * Update (U) Yes Yes No No No + * Intent exclusive (IX) Yes No No Yes No + * Exclusive (X) No No No No No + * + * Note that APPLOCKMODE_SHAREDINTENTEXCLUSIVE and + * APPLOCKMODE_UPDATEINTENTEXCLUSIVE are special lockmodes that + * are NOT acquirable by sp_getapplock but can be returned by + * APPLOCK_MODE(). See comments for APPLOCK_MODE(). + */ +typedef enum { + APPLOCKMODE_NOLOCK, + APPLOCKMODE_INTENTEXCLUSIVE, + APPLOCKMODE_INTENTSHARED, + APPLOCKMODE_SHARED, + APPLOCKMODE_UPDATE, + APPLOCKMODE_EXCLUSIVE, + APPLOCKMODE_SHAREDINTENTEXCLUSIVE, + APPLOCKMODE_UPDATEINTENTEXCLUSIVE +} Applock_All_Lockmode; + +/* + * Strings for Applock modes. The order MUST match the mode enum in + * Applock_All_Lockmode. + */ +static const char *AppLockModeStrings[] = +{ + "NoLock", + "IntentExclusive", + "IntentShared", + "Shared", + "Update", + "Exclusive", + "SharedIntentExclusive", + "UpdateIntentExclusive" +}; + +static void ApplockPrintMessage(const char *fmt, ...) { + char msg[128]; + va_list args; + + va_start(args, fmt); + vsprintf(msg, fmt, args); + + ereport(WARNING, errmsg_internal("%s", msg)); + if (*pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->send_info) + ((*pltsql_protocol_plugin_ptr)->send_info) (0, 1, 0, msg, 0); + + va_end (args); +} + +/* Helper macro to validate and get a string argument */ +#define ApplockGetStringArg(argnum, OUT) \ + do { \ + if (fcinfo->args[argnum].isnull) { \ + ApplockPrintMessage("parameter cannot be null"); \ + return -999; \ + } \ + OUT = text_to_cstring(DatumGetVarCharPP(PG_GETARG_DATUM(argnum))); \ + } while (0); + +#define SET_LOCKTAG_APPLOCK(locktag,id1,id2,id3,id4) \ + ((locktag).locktag_field1 = (id1), \ + (locktag).locktag_field2 = (id2), \ + (locktag).locktag_field3 = (id3), \ + (locktag).locktag_field4 = (id4), \ + (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). + * We use 2 to avoid conflict with it. + */ +#define ApplockSetLocktag(tag, key64) \ + SET_LOCKTAG_APPLOCK(tag, \ + MyDatabaseId, \ + (uint32) ((key64) >> 32), \ + (uint32) (key64), \ + 2) + +#define AppLockCacheInsert(ID, ENTRY) \ + do { \ + bool found; \ + (ENTRY) = (AppLockCacheEnt*) hash_search(appLockCacheLocal, \ + (void *) &(ID), \ + HASH_ENTER, &found); \ + if (!found) { \ + (ENTRY)->refcount = 0; \ + strcpy((ENTRY)->resource, ""); \ + slist_init(&(ENTRY)->mode_head); \ + } \ +} while(0) + +#define AppLockCacheLookup(ID, ENTRY) \ + do { \ + (ENTRY) = (AppLockCacheEnt *) hash_search(appLockCacheLocal, \ + (void *) &(ID), \ + HASH_FIND, NULL); \ +} while(0) + +#define AppLockCacheDelete(ID) \ + do { \ + AppLockCacheEnt *hentry; \ + hentry = (AppLockCacheEnt *) hash_search(appLockCacheLocal, \ + (void *) &(ID), \ + HASH_REMOVE, NULL); \ + if (hentry == NULL) \ + ApplockPrintMessage("failed to delete app lock entry for key %ld", ID); \ +} while(0) + +#define ApplockSetLockTimeout(val) \ + do { \ + if (timeout != -99) { \ + char timeout_str[16]; \ + sprintf(timeout_str, "%d", val); \ + SetConfigOption("lock_timeout", timeout_str, \ + PGC_USERSET, PGC_S_OVERRIDE); \ + } \ +} while (0); + +#define ApplockCheckParallelMode(suppress_warning) \ + do { \ + if (IsInParallelMode()) { \ + if (!suppress_warning) \ + ApplockPrintMessage("cannot use advisory locks during a parallel operation"); \ + return -999; \ + } \ + } while (0); + +#define ApplockCheckLockmode(IN, OUT, suppress_warning) \ + do { \ + if (pg_strcasecmp(IN, "IntentShared") == 0) \ + (OUT) = APPLOCKMODE_INTENTSHARED; \ + else if (pg_strcasecmp(IN, "Shared") == 0) \ + (OUT) = APPLOCKMODE_SHARED; \ + else if (pg_strcasecmp(IN, "Update") == 0) \ + (OUT) = APPLOCKMODE_UPDATE; \ + else if (pg_strcasecmp(IN, "IntentExclusive") == 0) \ + (OUT) = APPLOCKMODE_INTENTEXCLUSIVE; \ + else if (pg_strcasecmp(IN, "Exclusive") == 0) \ + (OUT) = APPLOCKMODE_EXCLUSIVE; \ + else { \ + if (!suppress_warning) \ + ApplockPrintMessage("Option \'%s\' not recognized for \'@LockMode\' parameter", IN); \ + return -999; \ + } \ + } while (0) + +#define ApplockCheckLockowner(IN, OUT, suppress_warning) \ + do { \ + if (pg_strcasecmp(IN, "Session") == 0) \ + (OUT) = true; \ + else if (pg_strcasecmp(IN, "Transaction") == 0) \ + (OUT) = false; \ + else { \ + if (!suppress_warning) \ + ApplockPrintMessage("Option \'%s\' not recognized for \'@LockOwner\' parameter", IN); \ + return -999; \ + } \ + } while (0) + +/* + * We accept any input of dbprincipal until we decide otherwise. + * Also a placeholder to escape unused variable error for dbprincipal. + */ +#define ApplockCheckDbPrincipal(IN) \ + do { \ + if (pg_strcasecmp((IN), "dbo")) \ + ; \ + } while (0); + +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. + * See https://cp-algorithms.com/string/string-hashing.html + */ +static int64 +applock_simple_hash(char *str) +{ + const int p = 31; + const int64 m = INT64_MAX; + uint64 hash_value = 0; + int64 p_pow = 1; + char c; + + c = *str; + while (c) { + hash_value = (hash_value + (c - 'a' + 1) * p_pow) % m; + p_pow = (p_pow * p) % m; + c = *++str; + } + return hash_value; +} + +/* + * Get PG Lock mode for corresponding Applock mode. + * See AppLockConflicts[] defined in backend/storage/lmgr/lock.c. + */ +static short getPGLockMode(short applockmode) +{ + short mode = 0; + + if (applockmode == APPLOCKMODE_EXCLUSIVE) + mode = ExclusiveLock; + else if (applockmode == APPLOCKMODE_SHARED) + mode = ShareLock; + else if (applockmode == APPLOCKMODE_UPDATE) + mode = ShareUpdateExclusiveLock; + else if (applockmode == APPLOCKMODE_INTENTSHARED) + mode = RowShareLock; + else if (applockmode == APPLOCKMODE_INTENTEXCLUSIVE) + mode = RowExclusiveLock; + else + ApplockPrintMessage("wrong application lock mode %d", applockmode); + + return mode; +} + +/* Initialize both local and global hashmaps */ +static void initApplockCache() +{ + 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); + + /* 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); + LWLockRelease(AddinShmemInitLock); + + /* + * Init this function handler to be called when PG implicitly + * release locks at the end of transaction/session. + */ + applock_release_func_handler = (void*) ApplockRemoveCache; +} + +/* Search a key corresponding to a resource name in local hashmap. */ +static int64 AppLockSearchKeyLocal(char *resource) +{ + AppLockCacheEnt *entry; + 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); + if (entry && strcmp(entry->resource, resource) == 0) + return key; + /* be mindful of overflow */ + key = (key % INT64_MAX) + 1; + } + + return -1; +} + +/* Search a key corresponding to a resource name in global hashmap. */ +static int64 AppLockSearchKeyGlobal(char *resource) +{ + AppLockCacheEnt *entry; + 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) { + LWLockRelease(TsqlApplockSyncLock); + return key; + } + /* be mindful of overflow */ + key = (key % INT64_MAX) + 1; + } + + LWLockRelease(TsqlApplockSyncLock); + return -1; +} + +/* + * Un-reference an entry in the appLockCacheGlobal. + * Delete it if its refcount is reduced to 0. + */ +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, + (void *) &key, + HASH_REMOVE, NULL); + strcpy(entry->resource, ""); + } + LWLockRelease(TsqlApplockSyncLock); +} + +/* + * 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) +{ + int64 key, usable_key; + bool found; + AppLockCacheEnt *entry; + int try_search = 0; + + /* 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->refcount; + LWLockRelease(TsqlApplockSyncLock); + return key; + } + LWLockRelease(TsqlApplockSyncLock); + } + + /* Otherwise, try generating a new key for this resource */ + + /* convert resource string to key integer */ + key = applock_simple_hash(resource); + usable_key = -1; + + 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. + * + * 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); + /* Someone might've just inserted an entry for this resource. */ + if (entry && strcmp(entry->resource, resource) == 0) { + entry->refcount++; + LWLockRelease(TsqlApplockSyncLock); + return key; + } + /* Key usable, record it if not done so. */ + if (!entry && usable_key == -1) + usable_key = key; + + /* Keep searching, be mindful of overflow */ + key = (key % INT64_MAX) + 1; + } + + 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); + + entry->key = usable_key; + entry->refcount = 1; + strcpy(entry->resource, resource); + } + + LWLockRelease(TsqlApplockSyncLock); + return usable_key; +} + +/* + * Common function for sp_getapplock_function() and APPLOCK_TEST(). + * + * Returns: + * 0: lock acquired successfully. + * -999: lock request attempt failed. + * 1: lock acquired successfully but after waiting. + * -1: timed out. + * -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) +{ + int32_t cur_timeout; + int64 key; + LOCKTAG tag; + short mode; + bool is_session; + bool lock_timeout_occurred = false; + bool no_wait = false; + AppLockCacheEnt *entry; + volatile TimestampTz start_time; + AppLockModeNode *node; + + /* a few sanity checks */ + ApplockCheckParallelMode(suppress_warning); + ApplockCheckLockmode(lockmode, mode, suppress_warning); + ApplockCheckLockowner(lockowner, is_session, suppress_warning); + ApplockCheckDbPrincipal(dbprincipal); + + if (pg_strcasecmp(lockowner, "Transaction") == 0 && !IsTransactionBlockActive()) + { + if (!suppress_warning) + ApplockPrintMessage("You attempted to acquire a transactional application lock without an active transaction."); + return -999; + } + if ((key = ApplockGetUsableKey(resource)) < 0) + { + if (!suppress_warning) + 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(). + */ + 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.*/ + PG_TRY(); + { + /* 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))); + } + 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. + * Therefore, we unfortunately can't print PG's nice deadlock report. + */ + + /* Un-referencing the global cache entry associated with this key. */ + ApplockUnrefGlobalCache(key); + + /* + * 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. + */ + 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); + + if (lock_timeout_occurred) + { + if (!suppress_warning) + ApplockPrintMessage("Applock request for \'%s\' timed out", resource); + return -1; + } + /* Not timed out, but it's still due to lock unavailable. */ + else if (geterrcode() == ERRCODE_LOCK_NOT_AVAILABLE) + { + if (!suppress_warning) + ApplockPrintMessage("Applock resource \'%s\' unavailable", resource); + return -999; + } + /* Did deadlock occur? */ + else if (geterrcode() == ERRCODE_T_R_DEADLOCK_DETECTED) + { + if (!suppress_warning) + 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); + return -2; + } + } + PG_END_TRY(); + + ApplockSetLockTimeout(cur_timeout); + + /* lock aquired, we can insert or update the local cache entry now. */ + AppLockCacheInsert(key, entry); + strcpy(entry->resource, resource); + entry->refcount++; + node = malloc(sizeof(AppLockModeNode)); + node->mode = mode; + slist_push_head(&entry->mode_head, &node->sn); + entry->is_session = is_session; + + return 0; +} + +/* + * Common function for sp_releaseapplock_function() and APPLOCK_TEST(). + * + * Returns: + * 0: lock released successfully. + * -999: lock release attempt failed. + */ +static int _sp_releaseapplock_internal(char *resource, char *lockowner, + char *dbprincipal, bool suppress_warning) +{ + int64 key; + LOCKTAG tag; + short mode; + bool is_session; + AppLockCacheEnt *entry; + AppLockModeNode *node; + + /* a few sanity checks */ + ApplockCheckParallelMode(suppress_warning); + ApplockCheckLockowner(lockowner, is_session, suppress_warning); + ApplockCheckDbPrincipal(dbprincipal); + + /* Search in the global cache for the key. */ + if ((key = AppLockSearchKeyGlobal(resource)) == -1) { + if (!suppress_warning) + ApplockPrintMessage("No lock resource \'%s\' acquired before.", resource); + LWLockRelease(TsqlApplockSyncLock); + return -999; + } + + /* verify the key in the local cache, and if the lock owner matches */ + AppLockCacheLookup(key, entry); + if (entry == NULL) { + if (!suppress_warning) + ApplockPrintMessage("No lock resource \'%s\' acquired before.", resource); + return -999; + } + 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"); + return -999; + } + + /* Set tag according to key. */ + ApplockSetLocktag(tag, key); + + /* get the same lock mode as recorded */ + 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); + free(node); + if (--entry->refcount == 0) + AppLockCacheDelete(key); + + /* Un-referencing the global cache entry associated with this key. */ + ApplockUnrefGlobalCache(key); + + return 0; +} + +/* + * Get application lock function, to be called by procedure sp_getapplock + */ +Datum +sp_getapplock_function(PG_FUNCTION_ARGS) +{ + char *resource, *lockmode, *lockowner, *dbprincipal; + int32_t timeout; + int ret; + + /* Init applock hash table if we haven't done so. */ + if (!appLockCacheLocal) + initApplockCache(); + + ApplockGetStringArg(0, resource); + ApplockGetStringArg(1, lockmode); + ApplockGetStringArg(2, lockowner); + timeout = DatumGetInt32(PG_GETARG_DATUM(3)); + ApplockGetStringArg(4, dbprincipal); + + ret = _sp_getapplock_internal(resource, lockmode, lockowner, timeout, dbprincipal, false); + + PG_RETURN_INT32(ret); +} + +/* + * Release application lock function, to be called by procedure sp_releaseapplock + */ +Datum +sp_releaseapplock_function(PG_FUNCTION_ARGS) +{ + char *resource, *lockowner, *dbprincipal; + int ret; + + /* Init applock hash table if we haven't done so. */ + if (!appLockCacheLocal) + initApplockCache(); + + ApplockGetStringArg(0, resource); + ApplockGetStringArg(1, lockowner); + ApplockGetStringArg(2, dbprincipal); + + ret = _sp_releaseapplock_internal(resource, lockowner, dbprincipal, false); + + PG_RETURN_INT32(ret); +} + +/* + * 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 + * different return modes depending on what's the other mode being held: + * 1. IntentExclusive + IntentExclusive = IntentExclusive + * 2. IntentExclusive + IntentShared = SharedIntentExclusive + * 3. IntentExclusive + Update = UpdateIntentExclusive + */ +Datum +APPLOCK_MODE(PG_FUNCTION_ARGS) +{ + char *resource; + 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) + initApplockCache(); + + ApplockGetStringArg(1, resource); + + /* If we don't own the lock, just return NoLock */ + if ((key = AppLockSearchKeyLocal(resource)) < 0) + PG_RETURN_VARCHAR_P(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 + * correct string to return. + */ + AppLockCacheLookup(key, entry); + high_mode = APPLOCKMODE_NOLOCK; + has_intent_exc = false; + 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) + high_mode = node->mode; + } + if (has_intent_exc && high_mode == APPLOCKMODE_INTENTSHARED) + ret_mode = APPLOCKMODE_SHAREDINTENTEXCLUSIVE; + else if (has_intent_exc && high_mode == APPLOCKMODE_UPDATE) + ret_mode = APPLOCKMODE_UPDATEINTENTEXCLUSIVE; + else + ret_mode = high_mode; + + PG_RETURN_VARCHAR_P(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 + * 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 + * memory management. + * + * Returns: + * 1 - the lock is grantable. + * 0 - the lock is not grantable. + */ +Datum +APPLOCK_TEST(PG_FUNCTION_ARGS) +{ + char *resource, *lockmode, *lockowner, *dbprincipal; + + /* Init applock hash table if not yet done. */ + if (!appLockCacheLocal) + initApplockCache(); + + ApplockGetStringArg(0, dbprincipal); + ApplockGetStringArg(1, resource); + ApplockGetStringArg(2, lockmode); + ApplockGetStringArg(3, lockowner); + + 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."))); + + /* + * 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 + * 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 + * 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.", + 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 + * or transaction+session too. + * + * @release_session: if we remove session locks as well as transaction locks. + */ +static void +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. + */ + if (sql_dialect != SQL_DIALECT_TSQL || !appLockCacheLocal) + return; + + hash_seq_init(&hash_seq, appLockCacheLocal); + + while ((entry = hash_seq_search(&hash_seq)) != NULL) + { + int i; + if (!release_session && entry->is_session) + continue; + + /* unreferencing my entries in global hashmap */ + for (i = 0; i < entry->refcount; i++) + ApplockUnrefGlobalCache(entry->key); + + /* free allocated space, and the entry itself. */ + hash_search(appLockCacheLocal, (void *) &entry->key, HASH_REMOVE, NULL); + } + + /* Release all applocks too. */ + LockReleaseAll(APPLOCK_LOCKMETHOD, release_session); +} diff --git a/contrib/babelfishpg_tsql/src/babelfish_version.h b/contrib/babelfishpg_tsql/src/babelfish_version.h new file mode 100644 index 00000000000..5c1561828a5 --- /dev/null +++ b/contrib/babelfishpg_tsql/src/babelfish_version.h @@ -0,0 +1,15 @@ +/*------------------------------------------------------------------------- + * + * babelfish_version.h + * Defines the Babelfish version string. + * Defines the Babel Compatibility version string. + * Defines the Babel Compatibility major version string. + * + *------------------------------------------------------------------------- + */ + +#define BABELFISH_VERSION_STR "1.1.0" +#define BABELFISH_INTERNAL_VERSION_STR "Babelfish 13.5.0.9" +#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 new file mode 100644 index 00000000000..f427085ae86 --- /dev/null +++ b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-decl.y @@ -0,0 +1,110 @@ +%expect 1 + +%debug +%verbose + +%initial-action +{ + yydebug = false; + + YYDPRINTF((stderr, "starting base SQL parser\n")); + + YYDPRINTF((stderr, " %s\n", pg_yyget_extra(yyscanner)->core_yy_extra.scanbuf)); +} + +%type tsql_stmt + +%type tsql_CreateFunctionStmt tsql_VariableSetStmt tsql_CreateTrigStmt tsql_TransactionStmt tsql_UpdateStmt tsql_DeleteStmt tsql_IndexStmt +%type tsql_DropIndexStmt tsql_InsertStmt +%type tsql_CreateLoginStmt tsql_AlterLoginStmt tsql_DropLoginStmt +%type tsql_nchar +%type tsql_login_option_list1 tsql_login_option_list2 +%type tsql_alter_login_option_list +%type tsql_login_option_elem tsql_alter_login_option_elem +%type tsql_enable_disable +%type tsql_createfunc_options tsql_createfunc_opt_list tsql_IsolationLevel +%type tsql_func_name +%type tsql_func_opt_item + +%type tsql_qualified_func_name + +%type tsql_opt_arg_dflt +%type tsql_opt_null_keyword +%type tsql_proc_arg tsql_func_arg +%type tsql_proc_args_list tsql_func_args_list + +%type tsql_ExecStmt tsql_output_ExecStmt +%type tsql_actual_args +%type tsql_actual_arg +%type tsql_opt_output tsql_opt_readonly + +%type tsql_OptTranName tsql_IsolationLevelStr + +%type tsql_without_login + +%type tsql_alter_table_cmd + +%type tsql_TriggerActionTime +%type tsql_TriggerEvents tsql_TriggerOneEvent + +%type tsql_stmtmulti +%type columnListWithOptAscDesc + +%type tsql_cluster tsql_opt_cluster + +%type tsql_OptParenthesizedIdentList tsql_IdentList + +%type TSQL_computed_column +%type columnElemWithOptAscDesc + +%type tsql_ColConstraint tsql_ColConstraintElem + +%type TSQL_Typename TSQL_SimpleTypename TSQL_GenericType + +%type datepart_arg datediff_arg dateadd_arg +%type tsql_type_function_name +%type tsql_createproc_args tsql_createfunc_args +%type tsql_triggername + +%type tsql_top_clause opt_top_clause + +%type tokens_remaining +%type tsql_table_hint_kw_no_with +%type tsql_table_hint_expr tsql_opt_table_hint_expr tsql_table_hint_list +%type tsql_table_hint +%type tsql_for_clause tsql_xml_common_directive +%type tsql_xml_common_directives + +%type tsql_output_insert_rest tsql_output_insert_rest_no_paren + +%type tsql_output_simple_select tsql_values_clause +%type tsql_output_clause tsql_output_into_target_columns +%type tsql_alter_server_role + +%token TSQL_ATAT TSQL_ALLOW_SNAPSHOT_ISOLATION + TSQL_CALLER TSQL_CHOOSE TSQL_CLUSTERED TSQL_COLUMNSTORE TSQL_CONVERT + TSQL_DATENAME TSQL_DATEPART TSQL_DATEDIFF TSQL_DATEADD 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_MICROSECOND TSQL_MILLISECOND TSQL_MM TSQL_MS + TSQL_N TSQL_NANOSECOND TSQL_NONCLUSTERED TSQL_NS TSQL_OUTPUT TSQL_OUT TSQL_PARSE TSQL_Q + TSQL_QQ TSQL_QUARTER TSQL_READONLY TSQL_ROWGUIDCOL TSQL_S + TSQL_SAVE TSQL_SS TSQL_TRAN TSQL_TRY_CAST TSQL_TRY_CONVERT TSQL_TRY_PARSE + TSQL_TEXTIMAGE_ON TSQL_TZ TSQL_TZOFFSET TSQL_WEEK TSQL_WEEKDAY TSQL_WK TSQL_WW TSQL_YY TSQL_YYYY + TSQL_SCHEMABINDING TSQL_IDENTITY_INSERT + TSQL_EXEC TSQL_PROC TSQL_IIF TSQL_REPLICATION TSQL_SUBSTRING TSQL_PERSISTED + 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 + 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 + +/* + * WITH_paren is added to support table hints syntax WITH ( [[,]...n]), + * otherwise the parser cannot tell between 'WITH' and 'WITH (' and thus + * lead to a shift/reduce conflict. + */ +%token WITH_paren TSQL_HINT_START_BRACKET 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 new file mode 100644 index 00000000000..e6c7743dc98 --- /dev/null +++ b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-epilogue.y.c @@ -0,0 +1,1307 @@ +void +pgtsql_parser_init(base_yy_extra_type *yyext) +{ + parser_init(yyext); +} + +static void +pgtsql_base_yyerror(YYLTYPE *yylloc, core_yyscan_t yyscanner, const char *msg) +{ + base_yyerror(yylloc, yyscanner, msg); +} + +static Node * +makeTSQLHexStringConst(char *str, int location) +{ + A_Const *n = makeNode(A_Const); + + n->val.type = T_TSQL_HexString; + n->val.val.str = str; + n->location = location; + + return (Node *)n; +} + +/* tsql_completeDefaultValues + * fill NULL as default value for any trailing params + * following the first param with default value + */ +static void +tsql_completeDefaultValues(List *parameters) +{ + ListCell *i; + bool fill = false; + foreach(i, parameters) + { + FunctionParameter *p = (FunctionParameter *) lfirst(i); + if (p->defexpr) + fill = true; + + if (fill && !p->defexpr) + p->defexpr = makeNullAConst(0); /* no location available */ + } +} + +/* TsqlSystemFuncName() + * Build a properly-qualified reference to a tsql built-in function. + */ +List * +TsqlSystemFuncName(char *name) +{ + return list_make2(makeString("sys"), makeString(name)); +} + +/* TsqlSystemFuncName2() + * Build a properly-qualified reference to a tsql built-in function. + */ +List * +TsqlSystemFuncName2(char *name) +{ + return list_make2(makeString("sys"), makeString(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; + + 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); + if (unlikely(!success)) { /* OOM */ + ereport( + ERROR, + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg( + "constructing unique index name failed: index = \"%s\", relation = \"%s\", ", + index_name, + relation_name + ) + ) + ); + } + + 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; +} + +/* + * Convert a list of (dotted) names for a table type to a RangeVar. + * This differs from makeRangeVarFromAnyName in that it only allows 1 prefix, + * instead of 2. + */ +static RangeVar * +makeRangeVarFromAnyNameForTableType(List *names, int position, core_yyscan_t yyscanner) +{ + RangeVar *r = makeNode(RangeVar); + + switch (list_length(names)) + { + case 1: + r->catalogname = NULL; + r->schemaname = NULL; + r->relname = strVal(linitial(names)); + break; + case 2: + r->catalogname = NULL; + r->schemaname = strVal(linitial(names)); + r->relname = strVal(lsecond(names)); + break; + default: + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("The type name '%s' contains more than the maximum number of prefixes. The maximum is 1.", + NameListToString(names)), + parser_errposition(position))); + break; + } + + r->relpersistence = RELPERSISTENCE_PERMANENT; + r->location = position; + + return r; +} + +Node +*TsqlFunctionChoose(Node *int_expr, List *choosable, int location) +{ + 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)"); + + foreach(lc, choosable) + { + CaseWhen *w = makeNode(CaseWhen); + w->expr = (Expr *) makeIntConst(i, location); + w->result = (Expr *) lfirst(lc); + w->location = location; + c->args = lappend(c->args, w); + i++; + } + + c->casetype = InvalidOid; + c->arg = (Expr *) makeTypeCast(int_expr, SystemTypeName("int4"), -1); + c->location = location; + + return (Node *) c; +} + + +/* TsqlFunctionConvert -- Implements the CONVERT and TRY_CONVERT functions. + * Takes in target type, expression, style, try boolean, location. + * + * Converts any input type to any type with different styles. + * Uses try boolean to determine returning an error or null if cast fails. + */ +Node * +TsqlFunctionConvert(TypeName *typename, Node *arg, Node *style, bool try, int location) +{ + Node *result; + List *args; + int32 typmod; + Oid type_oid; + char *typename_string; + + /* For handling try boolean logic on babelfishpg_tsql side */ + Node *try_const = makeBoolAConst(try, location); + if (style) + args = list_make3(arg, try_const, style); + else + args = list_make2(arg, try_const); + + typenameTypeIdAndMod(NULL, typename, &type_oid, &typmod); + typename_string = TypeNameToString(typename); + + TSQLInstrumentation(INSTR_TSQL_FUNCTION_CONVERT); + + if (type_oid == DATEOID) + result = (Node *) makeFuncCall(TsqlSystemFuncName("babelfish_conv_helper_to_date"), args, location); + else if (type_oid == TIMEOID) + result = (Node *) makeFuncCall(TsqlSystemFuncName("babelfish_conv_helper_to_time"), args, location); + else if (type_oid == typenameTypeId(NULL, makeTypeName("datetime"))) + result = (Node *) makeFuncCall(TsqlSystemFuncName("babelfish_conv_helper_to_datetime"), args, location); + else if (strcmp(typename_string, "varchar") == 0) + { + 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, 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) + { + result = TsqlFunctionTryCast(arg, typename, location); + } + else + { + result = makeTypeCast(arg, typename, location); + } + } + + return result; +} + +/* TsqlFunctionParse -- Implements the PARSE and TRY_PARSE functions. + * Takes in expression, target type, regional culture, try boolean, location. + * + * Parses text input to date/time and number types. Uses try boolean to determine returning + * an error or null if cast fails. + */ +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, location); + else if (type_oid == TIMEOID) + result = (Node *) makeFuncCall(TsqlSystemFuncName("babelfish_parse_helper_to_time"), args, location); + else if (type_oid == typenameTypeId(NULL, makeTypeName("datetime"))) + result = (Node *) makeFuncCall(TsqlSystemFuncName("babelfish_parse_helper_to_datetime"), args, location); + else + { + if (try) + result = TsqlFunctionTryCast(arg, typename, location); + else + result = makeTypeCast(arg, typename, location); + } + + return result; +} + +/* TsqlFunctionTryCast -- Implements the TRY_CAST function. + * Takes in expression, target type, location. + * + * Behaves like CAST except return NULL instead of error in most cases. + */ +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), location); + else if (type_oid == INT4OID) + result = (Node *) makeFuncCall(TsqlSystemFuncName("babelfish_try_cast_floor_int"), list_make1(arg), location); + else if (type_oid == INT8OID) + result = (Node *) makeFuncCall(TsqlSystemFuncName("babelfish_try_cast_floor_bigint"), list_make1(arg), location); + else + { + Node *arg_const = makeTypeCast(arg, SystemTypeName("text"), location); + + /* Cast null to typename to take advantage of polymorphic types in Postgres. */ + Node *null_const = makeTypeCast(makeNullAConst(location), typename, location); + + List *args = list_make3(arg_const, null_const, makeIntConst(typmod, location)); + result = (Node *) makeFuncCall(TsqlSystemFuncName("babelfish_try_cast_to_any"), args, location); + } + + return result; +} + +Node * +TsqlFunctionIIF(Node *bool_expr, Node *arg1, Node *arg2, int location) +{ + CaseExpr *c = makeNode(CaseExpr); + CaseWhen *w = makeNode(CaseWhen); + + TSQLInstrumentation(INSTR_TSQL_FUNCTION_IIF); + + w->expr = (Expr *) bool_expr; + w->result = (Expr *) arg1; + w->location = location; + + c->casetype = InvalidOid; + c->arg = NULL; + c->args = list_make1((Node *) w); + c->defresult = (Expr *) arg2; + c->location = location; + + return (Node *) c; +} + +/* tsql_check_param_readonly --- check the usage of READONLY on parameter + * + * READONLY Indicates that the parameter cannot be updated or modified + * within the definition of the function. READONLY is required for + * user-defined table type parameters (TVPs), and cannot be used for + * any other parameter type. + * + * It's easiest to do the check here, to avoid having to add a field + * to the FunctionParameter struct. + */ +static void +tsql_check_param_readonly(const char *paramname, TypeName *typename, bool readonly) +{ + TypeName *typeclone = copyObjectImpl(typename); + + /* work on the cloned object to avoid double rewriting */ + rewrite_plain_name(typeclone->names); + if (typeidTypeRelid(typenameTypeId(NULL, typeclone)) == InvalidOid) + { + /* Not table-valued parameter - must not be READONLY */ + if (readonly) + elog(ERROR, + "The parameter \"%s\" can not be declared READONLY since it is not a table-valued parameter.", + paramname); + } + else + { + /* Table-valued parameter - must be READONLY */ + if (!readonly) + elog(ERROR, + "The table-valued parameter \"%s\" must be declared with the READONLY option.", + paramname); + } +} + +/* + * Make a function call to tsql_query_to_xml for FOR XML clause. + * For example, it does the following transformation: + * select a from t for xml path => + * select tsql_query_to_xml('select a from t', ... ) + * The first argument of the function is the query string without the for xml clause. + * The rest of the arguments passe in options and directives allowed by tsql. + * + * If the for xml clause has TSQL variables/identifiers that needs to be binded + * (e.g. @varName that's used as a procedure parameter) during parse analysis, + * we transform the query to use PG's function FORMAT in order to support the + * variable binding, for example: + * select a from t where id = @pid for xml path => + * select tsql_query_toxml(FORMAT('select a from t where id = %s', @pid) ... ) + */ +ResTarget * +TsqlForXMLMakeFuncCall(TSQL_ForClause* forclause, char* src_query, size_t start_location, core_yyscan_t yyscanner) +{ + ResTarget *rt = makeNode(ResTarget); + FuncCall *fc; + size_t len = (forclause)->location - start_location; + char *query = palloc(len + 1); + List *func_name; + List *func_args; + int begin_index; + int end_index; + char *begin_param; + char *end_param; + StringInfo format_query = makeStringInfo(); + List *params = NIL; + bool binary_base64 = false; + bool return_xml_type = false; + char* root_name = NULL; + Node* arg1; + + /* Resolve the XML common directive list if provided */ + if (forclause->commonDirectives != NIL) + { + ListCell *lc; + foreach (lc, forclause->commonDirectives) + { + Node *myNode = lfirst(lc); + A_Const *myConst; + + /* commonDirective is either integer const or string const */ + Assert(IsA(myNode, A_Const)); + myConst = (A_Const *)myNode; + Assert(myConst->val.type == T_Integer || myConst->val.type == T_String); + if (myConst->val.type == T_Integer) + { + if (myConst->val.val.ival == TSQL_XML_DIRECTIVE_BINARY_BASE64) + binary_base64 = true; + else if (myConst->val.val.ival == TSQL_XML_DIRECTIVE_TYPE) + return_xml_type = true; + } + else if (myConst->val.type == T_String) + { + root_name = myConst->val.val.str; + } + } + } + + query = memcpy(query, + src_query + start_location, + len); + query[len] = '\0'; + + /* + * Transform query with tsql identifiers (@pname) to PG's FORMAT function so + * variable binding still works. + * For example: + * select a from t where id = @pid for xml path => + * select tsql_query_toxml(FORMAT('select a from t where id = %s', @pid) ... ) + * Notice the tsql identifiers in the query string has already been + * processed by the babelfishpg_tsql parser at this point and is surrounded by quote + * such as in \"@pid"\. + * + * We achieve the above transformation by extacting all parameters starting + * with \"@ from the query string, and replace them with %s. The StringInfo + * variable format_query is used to assemble the new query in this process. + * end_param points the remaiming query string after the parameter, initially + * we set it to the query string. begin_param points to the begining of a + * parameter or tsql identifer, starting from left to right in the query string. + */ + end_param = query; + while ((begin_param = strstr(end_param, "\"@")) != NULL) + { + char *before_param; + + begin_index = begin_param - end_param; + before_param = palloc(begin_index + 1); + before_param = memcpy(before_param, end_param, begin_index); + before_param[begin_index] = '\0'; + if ((end_param = strstr(begin_param+2, "\"")) != NULL) + { + char *param; + + end_index = (end_param - begin_param) + begin_index; + appendStringInfoString(format_query, before_param); + appendStringInfoString(format_query, "%L"); + param = palloc(end_index - begin_index); + param = memcpy(param, begin_param + 1, end_index - begin_index - 1); + param[end_index - begin_index - 1] = '\0'; + params = lappend(params, makeColumnRef(param, NIL, -1, yyscanner)); + /* Move end_param pass the \", so it points to the rest of the query */ + end_param++; + } + else + { + /* + * Unmatched quote around the tsql identification, it shouldn't happen + * because proper quoting is done in babelfishpg_tsql parser. + * But just in case report an error. + */ + ereport(ERROR, + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("Unmatched quote around TSQL identifier"))); + } + } + + /* + * Make a function call to Function FORMAT if format_query is built from the + * above process. + */ + if (format_query->len > 0) + { + FuncCall *format_fc; + List *format_func_args; + appendStringInfoString(format_query, end_param); + format_func_args = list_concat(list_make1(makeStringConst(format_query->data, -1)), + params); + format_fc = makeFuncCall(list_make1(makeString("format")), format_func_args, -1); + arg1 = (Node *) format_fc; + } + else + arg1 = makeStringConst(query, -1); + + /* + * Finally make funtion call to tsql_query_to_xml or tsql_query_to_xml_text + * 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_query_to_xml + * returns XML type, tsql_query_to_xml_text returns text type. + */ + if (return_xml_type) + func_name= list_make2(makeString("sys"), makeString("tsql_query_to_xml")); + else + func_name= list_make2(makeString("sys"), makeString("tsql_query_to_xml_text")); + func_args = list_make4(arg1, + makeIntConst(forclause->mode, -1), + forclause->elementName ? makeStringConst(forclause->elementName, -1) : + makeStringConst("row", -1), + makeBoolAConst(binary_base64, -1)); + func_args = lappend(func_args, root_name ? makeStringConst(root_name, -1) : makeStringConst("", -1)); + fc = makeFuncCall(func_name, func_args, -1); + + rt->name = NULL; + rt->indirection = NIL; + rt->val = (Node *) fc; + rt->location = -1; + return rt; +} + +/* + * helper macro to compare relname in + * function tsql_update_delete_stmt_with_join + */ +#define TSQL_COMP_REL_NAME(l, r) \ + (r != NULL && strcmp(l->relname, r->relation->relname) == 0 \ + && ( (!r->relation->schemaname && !l->schemaname) \ + || (l->schemaname && r->relation->schemaname && \ + strcmp(l->schemaname, r->relation->schemaname) == 0))\ + && ( (!r->relation->catalogname && !l->catalogname)\ + || (l->catalogname && r->relation->catalogname && \ + 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, + 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; + SelectStmt *selectstmt; + ResTarget *resTarget; + /* use queue to go over all join expr and find target table */ + List* queue = list_make1(jexpr); + ListCell *queue_item; + if(IsA(n, DeleteStmt)) + n_d = (DeleteStmt*)n; + else + n_u = (UpdateStmt*)n; + + foreach(queue_item, queue) + { + jexpr = (JoinExpr*)lfirst(queue_item); + if(IsA(jexpr->larg, JoinExpr)) + { + queue = lappend(queue, jexpr->larg); + } + else if(IsA(jexpr->larg, RangeVar)) + { + larg = (RangeVar*)(jexpr->larg); + } + if(IsA(jexpr->rarg, JoinExpr)) + { + queue = lappend(queue, jexpr->rarg); + } + else if(IsA(jexpr->rarg, RangeVar)) + { + rarg = (RangeVar*)(jexpr->rarg); + } + 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))) + { + target_table = rarg; + break; + } + 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) + { + /* + * 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) + { + n_d -> usingClause = from_clause; + n_d -> whereClause = tsql_update_delete_stmt_with_top(top_clause, + relation, where_clause, yyscanner); + return (Node*)n_d; + } + else + { + n_u -> fromClause = from_clause; + n_u -> whereClause = tsql_update_delete_stmt_with_top(top_clause, + relation, where_clause, yyscanner); + return (Node*)n_u; + } + } + /* construct select statment->target */ + resTarget = makeNode(ResTarget); + resTarget->name = NULL; + resTarget->indirection = NIL; + indirect = list_make1((Node *) makeString("ctid")); + if(target_table->alias) + { + resTarget->val = makeColumnRef(target_table->alias->aliasname, + indirect,-1,yyscanner); + } + else + { + resTarget->val = makeColumnRef(target_table->relname, + indirect,-1,yyscanner); + } + + selectstmt = makeNode(SelectStmt); + selectstmt->targetList = list_make1(resTarget); + /* assign fromClause and whereClause from JoinExpr */ + selectstmt->fromClause = from_clause; + selectstmt->whereClause = where_clause; + /* if we end up createing a subquery for JOIN, attach TOP clause to it */ + 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; + if(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); + } + 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; +} + +static Node * +tsql_insert_output_into_cte_transformation(WithClause *opt_with_clause, RangeVar *insert_target, + List *insert_column_list, List *tsql_output_clause, RangeVar *output_target, List *tsql_output_into_target_columns, + InsertStmt *tsql_output_insert_rest, int select_location) +{ + + CommonTableExpr *cte = makeNode(CommonTableExpr); + WithClause *w = makeNode(WithClause); + SelectStmt *n = makeNode(SelectStmt); + InsertStmt *i = makeNode(InsertStmt); + char* internal_ctename = NULL; + char ctename[NAMEDATALEN]; + ListCell *expr; + char col_alias_arr[NAMEDATALEN]; + char *col_alias = NULL; + List *output_list = NIL, *queue = NIL; + ListCell *lc; + Node *field1; + char *qualifier = NULL; + + sprintf(ctename, "internal_output_cte##sys_gen##%p", (void*) i); + internal_ctename = pstrdup(ctename); + + // PreparableStmt inside CTE + i->cols = NIL; + i->selectStmt = tsql_output_insert_rest->selectStmt; + 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. + */ + 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); + 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)) + { + snprintf(col_alias_arr, NAMEDATALEN, "sys_gen##%pins_%s", (void*) tsql_output_clause, strVal(llast(cref->fields))); + col_alias = pstrdup(col_alias_arr); + } + else + cref->fields = list_delete_first(cref->fields); + } + if (col_alias) + cref->fields = list_make1(makeString(col_alias)); + } + } + else if(IsA(node, A_Expr)) + { + 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)) + { + FuncCall *func_call = (FuncCall*) node; + if (func_call->args) + queue = list_concat(queue, func_call->args); + } + } + } + + // 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; + tsql_output_insert_rest->relation = output_target; + tsql_output_insert_rest->onConflictClause = NULL; + tsql_output_insert_rest->returningList = NULL; + if (tsql_output_into_target_columns == NIL) + tsql_output_insert_rest->cols = insert_column_list; + else + tsql_output_insert_rest->cols = tsql_output_into_target_columns; + + // CTE + cte->ctename = internal_ctename; + cte->aliascolnames = NULL; + cte->ctematerialized = CTEMaterializeDefault; + cte->ctequery = (Node *) i; + cte->location = 1; + + if(opt_with_clause) + { + opt_with_clause->ctes = lappend(opt_with_clause->ctes, (Node*) cte); + tsql_output_insert_rest->withClause = opt_with_clause; + } + else + { + w->ctes = list_make1((Node *) cte); + w->recursive = false; + w->location = 1; + tsql_output_insert_rest->withClause = w; + } + 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) +{ + 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; + + sprintf(ctename, "internal_output_cte##sys_gen##%p", (void*) i); + internal_ctename = pstrdup(ctename); + + // PreparableStmt inside CTE + d->relation = relation_expr_opt_alias; + 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; + } + 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->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 *. + */ + 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); + 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 (IsA((Node*) llast(cref->fields), String)) + { + snprintf(col_alias_arr, NAMEDATALEN, "sys_gen##%pdel_%s", (void*) tsql_output_clause, strVal(llast(cref->fields))); + col_alias = pstrdup(col_alias_arr); + } + else + cref->fields = list_delete_first(cref->fields); + } + if (col_alias) + cref->fields = list_make1(makeString(col_alias)); + } + } + else if(IsA(node, A_Expr)) + { + 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)) + { + FuncCall *func_call = (FuncCall*) node; + if (func_call->args) + queue = list_concat(queue, func_call->args); + } + } + } + + // 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; + i->relation = insert_target; + i->onConflictClause = NULL; + i->returningList = NULL; + i->cols = tsql_output_into_target_columns; + + // CTE + cte->ctename = internal_ctename; + cte->aliascolnames = NULL; + cte->ctematerialized = CTEMaterializeDefault; + cte->ctequery = (Node *) d; + cte->location = 1; + + if(opt_with_clause) + { + opt_with_clause->ctes = lappend(opt_with_clause->ctes, (Node*) cte); + i->withClause = opt_with_clause; + } + else + { + w->ctes = list_make1((Node *) cte); + w->recursive = false; + w->location = 1; + i->withClause = w; + } + return (Node *) i; +} + +static void +tsql_check_update_output_transformation(List *tsql_output_clause) +{ + 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. + */ + 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")) + { + deleted = true; + break; + } + } + } + if (deleted) + output_update_transformation = true; +} + +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) +{ + 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; + + sprintf(ctename, "internal_output_cte##sys_gen##%p", (void*) i); + internal_ctename = pstrdup(ctename); + + // PreparableStmt inside CTE + u->relation = relation_expr_opt_alias; + 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); + } + else + { + u->fromClause = from_clause; + u->whereClause = where_or_current_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 *. + */ + 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); + 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 (IsA((Node*) llast(cref->fields), String)) + { + snprintf(col_alias_arr, NAMEDATALEN, "sys_gen##%pdel_%s", (void*) tsql_output_clause, strVal(llast(cref->fields))); + col_alias = pstrdup(col_alias_arr); + } + else + cref->fields = list_delete_first(cref->fields); + } + else if (!strcmp(qualifier, "inserted")) + { + if (IsA((Node*) llast(cref->fields), String)) + { + snprintf(col_alias_arr, NAMEDATALEN, "sys_gen##%pins_%s", (void*) tsql_output_clause, strVal(llast(cref->fields))); + col_alias = pstrdup(col_alias_arr); + } + else + cref->fields = list_delete_first(cref->fields); + } + if (col_alias) + cref->fields = list_make1(makeString(col_alias)); + } + } + else if(IsA(node, A_Expr)) + { + 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)) + { + FuncCall *func_call = (FuncCall*) node; + if (func_call->args) + queue = list_concat(queue, func_call->args); + } + } + } + + // 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; + i->relation = insert_target; + i->onConflictClause = NULL; + i->returningList = NULL; + i->cols = tsql_output_into_target_columns; + + // CTE + cte->ctename = internal_ctename; + cte->aliascolnames = NULL; + cte->ctematerialized = CTEMaterializeDefault; + cte->ctequery = (Node *) u; + cte->location = 1; + + if(opt_with_clause) + { + opt_with_clause->ctes = lappend(opt_with_clause->ctes, (Node*) cte); + i->withClause = opt_with_clause; + } + else + { + w->ctes = list_make1((Node *) cte); + w->recursive = false; + w->location = 1; + i->withClause = w; + } + 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 +* 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; + PLtsql_execstate *estate; + 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); + queue = NIL; + queue = list_make1(res->val); + + foreach(expr, queue) + { + Node *node = (Node *) lfirst(expr); + if (IsA(node, ColumnRef)) + { + ResTarget *target = makeNode(ResTarget); + ColumnRef *cref = (ColumnRef *) node; + + if(!strcmp(strVal(linitial(cref->fields)), "deleted") && list_length(cref->fields) >= 2) + { + 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))); + 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)) + ins_star = true; + + } + else if(!strcmp(strVal(linitial(cref->fields)), "inserted") && list_length(cref->fields) >= 2) + { + 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))); + 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)) + del_star = true; + } + else + { + local_variable = false; + 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)) + { + local_variable = true; + break; + } + } + } + } + if (ins_star && del_star) + ereport( + ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("OUTPUT INTO does not support both inserted.* and deleted.* in target list") + ) + ); + if (!local_variable) + { + target->val = (Node*) cref; + transformed_returning_list = lappend(transformed_returning_list, target); + } + } + else if(IsA(node, A_Expr)) + { + 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)) + { + FuncCall *func_call = (FuncCall*) node; + if (func_call->args) + queue = list_concat(queue, func_call->args); + } + } + } + return transformed_returning_list; +} + +/* +* 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 +* 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; + + if (existing_colnames == NIL) + return false; + + foreach(name, existing_colnames) + { + char *colname = (char*) lfirst(name); + if (!strcmp(colname, current_colname)) + { + is_duplicate = true; + break; + } + } + return is_duplicate; +} \ No newline at end of file diff --git a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-nonassoc-ident-tokens b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-nonassoc-ident-tokens new file mode 100644 index 00000000000..8310e24409a --- /dev/null +++ b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-nonassoc-ident-tokens @@ -0,0 +1 @@ +IDENTITY_P TSQL_PERSISTED TSQL_ROWGUIDCOL /* these tokens can follow b_expr. To resolve ambiguity, we need to assign the same priority with IDENT. please see the comment in gram.y for details */ 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 new file mode 100644 index 00000000000..d40ee683fb5 --- /dev/null +++ b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-prologue.y.h @@ -0,0 +1,70 @@ +/***************************************************************************** + * + * Start of T-SQL specific prologue (will be moved to separate file) + * + *****************************************************************************/ + +#include "access/htup_details.h" +#include "catalog/pg_type.h" +#include "parser/parse_type.h" +#include "parser/scansup.h" +#include "utils/builtins.h" +#include "common/md5.h" + +#include "src/backend_parser/gramparse.h" +#include "src/pltsql_instr.h" +#include "src/multidb.h" + +#define MD5_HASH_LEN 32 + +static void pgtsql_base_yyerror(YYLTYPE *yylloc, core_yyscan_t yyscanner, const char *msg); + +List *TsqlSystemFuncName(char *name); +List *TsqlSystemFuncName2(char *name); + +/* 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 */ +} TSQL_ForClause; + +extern bool output_update_transformation; +extern PLtsql_execstate *get_current_tsql_estate(void); + +static Node *makeTSQLHexStringConst(char *str, int location); +static RangeVar *makeRangeVarFromAnyNameForTableType(List *names, int position, core_yyscan_t yyscanner); + +static Node *TsqlFunctionTryCast(Node *arg, TypeName *typename, int location); +static Node *TsqlFunctionConvert(TypeName *typename, Node *arg, Node *style, bool try, int location); +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 *TsqlFunctionChoose(Node *int_expr, List *choosable, int location); +static void tsql_check_param_readonly(const char* paramname, TypeName *typename, bool readonly); +static void tsql_completeDefaultValues(List *parameters); +static ResTarget *TsqlForXMLMakeFuncCall(TSQL_ForClause *forclause, char *src_query, size_t start_location, core_yyscan_t yyscanner); + +char * construct_unique_index_name(char *index_name, char *relation_name); + +static Node *tsql_update_delete_stmt_with_join(Node *n, List* from_clause, Node* + where_clause, Node *top_clause, RangeVar *relation, + core_yyscan_t yyscanner); +static Node *tsql_update_delete_stmt_with_top(Node *top_clause, RangeVar + *relation, Node *where_clause, core_yyscan_t yyscanner); +static Node *tsql_insert_output_into_cte_transformation(WithClause *opt_with_clause, RangeVar *insert_target, + List *insert_column_list, List *tsql_output_clause, RangeVar *output_target, List *tsql_output_into_target_columns, + InsertStmt *tsql_output_insert_rest, int select_location); +static Node *tsql_delete_output_into_cte_transformation(WithClause *opt_with_clause, Node *opt_top_clause, + RangeVar *relation_expr_opt_alias, List *tsql_output_clause, RangeVar *insert_target, + List *tsql_output_into_target_columns, List *from_clause, Node *where_or_current_clause, + core_yyscan_t yyscanner); +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); +static List *get_transformed_output_list(List *tsql_output_clause); +static bool returning_list_has_column_name(List *existing_colnames, char *current_colname); diff --git a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y new file mode 100644 index 00000000000..c238d2f5321 --- /dev/null +++ b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y @@ -0,0 +1,3763 @@ +/* + * Please note that this file is appended to gram.y so that existing PG backend parser rule can be extended + * because if there are multiple rules with the same name then they can be ORed into one rule. + * i.e. + * ruleX: XXX {} + * ruleX: XXX_TSQL {} + * <=> + * ruleX: XXX {} + * | XXX_TSQL {} + */ + +/* Start of exsiting grammar rule in gram.y */ + +stmtblock: + DIALECT_TSQL tsql_stmtmulti + { + pg_yyget_extra(yyscanner)->parsetree = $2; + } + ; + +tsql_CreateLoginStmt: + CREATE TSQL_LOGIN RoleId FROM tsql_login_sources + { + CreateRoleStmt *n = makeNode(CreateRoleStmt); + n->stmt_type = ROLESTMT_USER; + n->role = $3; + n->options = list_make1(makeDefElem("islogin", + (Node *)makeInteger(true), + @1)); /* Must be first */ + n->options = lappend(n->options, + makeDefElem("createdb", + (Node *)makeInteger(true), + @1)); + n->options = lappend(n->options, + makeDefElem("createrole", + (Node *)makeInteger(true), + @1)); + n->options = lappend(n->options, + makeDefElem("inherit", + (Node *)makeInteger(true), + @1)); + n->options = lappend(n->options, + makeDefElem("canlogin", + (Node *)makeInteger(true), + @1)); + $$ = (Node *)n; + } + | CREATE TSQL_LOGIN RoleId tsql_login_option_list1 + { + CreateRoleStmt *n = makeNode(CreateRoleStmt); + n->stmt_type = ROLESTMT_USER; + n->role = $3; + n->options = list_make1(makeDefElem("islogin", + (Node *)makeInteger(true), + @1)); /* Must be first */ + n->options = lappend(n->options, + makeDefElem("createdb", + (Node *)makeInteger(true), + @1)); + n->options = lappend(n->options, + makeDefElem("createrole", + (Node *)makeInteger(true), + @1)); + n->options = lappend(n->options, + makeDefElem("inherit", + (Node *)makeInteger(true), + @1)); + n->options = lappend(n->options, + makeDefElem("canlogin", + (Node *)makeInteger(true), + @1)); + n->options = list_concat(n->options, $4); + $$ = (Node *)n; + } + ; + +tsql_login_option_list1: + WITH PASSWORD '=' tsql_nchar opt_must_change + { + $$ = list_make1(makeDefElem("password", $4, @1)); + } + | WITH PASSWORD '=' tsql_nchar opt_must_change tsql_login_option_list2 + { + $$ = lcons(makeDefElem("password", $4, @1), $6); + } + | WITH PASSWORD '=' TSQL_XCONST TSQL_HASHED opt_must_change + { + $$ = list_make1(makeDefElem("password", NULL, @1)); + } + | WITH PASSWORD '=' TSQL_XCONST TSQL_HASHED opt_must_change tsql_login_option_list2 + { + $$ = lcons(makeDefElem("password", NULL, @1), $7); + } + ; + +tsql_login_option_list2: + ',' tsql_login_option_elem + { + if ($2 != NULL) + $$ = list_make1($2); + else + $$ = NIL; + } + | tsql_login_option_list2 ',' tsql_login_option_elem + { + if ($3 != NULL) + $$ = lappend($1, $3); + } + ; + +tsql_login_option_elem: + TSQL_SID '=' TSQL_XCONST + { + $$ = NULL; + } + | TSQL_DEFAULT_DATABASE '=' NonReservedWord + { + $$ = makeDefElem("default_database", + (Node *)makeString($3), + @1); + } + | TSQL_DEFAULT_LANGUAGE '=' NonReservedWord + { + $$ = NULL; + } + | TSQL_CHECK_EXPIRATION '=' opt_boolean_or_string + { + $$ = NULL; + } + | TSQL_CHECK_POLICY '=' opt_boolean_or_string + { + $$ = NULL; + } + | TSQL_CREDENTIAL '=' NonReservedWord + { + $$ = NULL; + } + ; + +opt_must_change: + TSQL_MUST_CHANGE + | /*EMPTY*/ + ; + +tsql_login_sources: + TSQL_WINDOWS + | TSQL_WINDOWS WITH tsql_windows_options_list + | TSQL_CERTIFICATE NonReservedWord + | ASYMMETRIC KEY NonReservedWord + ; + +tsql_windows_options_list: + tsql_windows_options + | tsql_windows_options_list ',' tsql_windows_options + ; + +tsql_windows_options: + TSQL_DEFAULT_DATABASE '=' NonReservedWord + | TSQL_DEFAULT_LANGUAGE '=' NonReservedWord + ; + +CreateUserStmt: + CREATE USER RoleId tsql_without_login opt_with OptRoleList + { + CreateRoleStmt *n = makeNode(CreateRoleStmt); + n->stmt_type = ROLESTMT_USER; + n->role = $3; + n->options = $6; + if ($4) + { + if ($6) + { + n->options = lappend(n->options, + list_make1(makeDefElem("canlogin", (Node *)makeInteger(false), @1))); + } + else + { + n->options = list_make1(makeDefElem("canlogin", (Node *)makeInteger(false), @1)); + } + } + $$ = (Node *)n; + } + ; + +tsql_AlterLoginStmt: + ALTER TSQL_LOGIN RoleSpec tsql_enable_disable + { + AlterRoleStmt *n = makeNode(AlterRoleStmt); + n->role = $3; + n->action = +1; /* add, if there are members */ + n->options = list_make1(makeDefElem("islogin", + (Node *)makeInteger(true), + @1)); /* Must be first */ + if ($4) + n->options = lappend(n->options, + makeDefElem("canlogin", + (Node *)makeInteger(true), + @1)); + else + n->options = lappend(n->options, + makeDefElem("canlogin", + (Node *)makeInteger(false), + @1)); + $$ = (Node *)n; + } + | ALTER TSQL_LOGIN RoleSpec WITH tsql_alter_login_option_list + { + AlterRoleStmt *n = makeNode(AlterRoleStmt); + n->role = $3; + n->action = +1; /* add, if there are members */ + n->options = list_make1(makeDefElem("islogin", + (Node *)makeInteger(true), + @1)); /* Must be first */ + if ($5 != NIL) + n->options = list_concat(n->options, $5); + $$ = (Node *)n; + } + | ALTER TSQL_LOGIN RoleSpec add_drop TSQL_CREDENTIAL NonReservedWord + { + AlterRoleStmt *n = makeNode(AlterRoleStmt); + n->role = $3; + n->action = +1; /* add, if there are members */ + n->options = list_make1(makeDefElem("islogin", + (Node *)makeInteger(true), + @1)); /* Must be first */ + $$ = (Node *)n; + } + ; + +tsql_enable_disable: + ENABLE_P + { + $$ = true; + } + | DISABLE_P + { + $$ = false; + } + ; + +tsql_alter_login_option_list: + tsql_alter_login_option_elem + { + if ($1 != NULL) + $$ = list_make1($1); + else + $$ = NIL; + } + | tsql_alter_login_option_list ',' tsql_alter_login_option_elem + { + if ($3 != NULL) + $$ = lappend($1, $3); + } + ; + +tsql_alter_login_option_elem: + PASSWORD '=' tsql_nchar tsql_alter_login_password_option1 + { + $$ = makeDefElem("password", $3, @1); + } + | PASSWORD '=' TSQL_XCONST TSQL_HASHED tsql_alter_login_password_option1 + { + $$ = makeDefElem("password", NULL, @1); + } + | TSQL_DEFAULT_DATABASE '=' NonReservedWord + { + $$ = makeDefElem("default_database", + (Node *)makeString($3), + @1);; + } + | TSQL_DEFAULT_LANGUAGE '=' NonReservedWord + { + $$ = NULL; + } + | NAME_P '=' RoleSpec + { + $$ = NULL; + } + | TSQL_CHECK_EXPIRATION '=' opt_boolean_or_string + { + $$ = NULL; + } + | TSQL_CHECK_POLICY '=' opt_boolean_or_string + { + $$ = NULL; + } + | TSQL_CREDENTIAL '=' NonReservedWord + { + $$ = NULL; + } + | NO TSQL_CREDENTIAL + { + $$ = NULL; + } + ; + +tsql_alter_login_password_option1: + TSQL_OLD_PASSWORD '=' tsql_nchar + | tsql_alter_login_password_option2_list + | /*EMPTY*/ + ; + +tsql_alter_login_password_option2_list: + tsql_alter_login_password_option2 + | tsql_alter_login_password_option2_list tsql_alter_login_password_option2 + ; + +tsql_alter_login_password_option2: + TSQL_MUST_CHANGE + | TSQL_UNLOCK + ; + +tsql_DropLoginStmt: + DROP TSQL_LOGIN role_list + { + DropRoleStmt *n = makeNode(DropRoleStmt); + n->missing_ok = false; + n->roles = $3; + $$ = (Node *)n; + } + ; + +tsql_nchar: + TSQL_NVARCHAR Sconst { $$ = (Node *)makeString($2); } + | Sconst { $$ = (Node *)makeString($1); } + ; + +AlterOptRoleElem: + PASSWORD '=' Sconst + { + if (sql_dialect != SQL_DIALECT_TSQL) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("This syntax is only valid when babelfishpg_tsql.sql_dialect is TSQL"), + parser_errposition(@2))); + $$ = makeDefElem("password", + (Node *)makeString($3), @1); + } + ; + +alter_table_cmds: /* extend it allow to consume nullable (tsql_alter_table_cmd) + /* alter_table_cmd */ + /* | alter_table_cmds ',' alter_table_cmd */ + tsql_alter_table_cmd { $$ = (($1 != NULL) ? list_make1($1) : NIL); } + | alter_table_cmds ',' tsql_alter_table_cmd { $$ = (($3 != NULL) ? lappend($1, $3) : $1); } + ; + +opt_reloptions: + WITH_paren reloptions { $$ = $2; } + ; + +PartitionBoundSpec: + /* a HASH partition */ + FOR TSQL_VALUES WITH_paren '(' hash_partbound ')' + { + ListCell *lc; + PartitionBoundSpec *n = makeNode(PartitionBoundSpec); + + n->strategy = PARTITION_STRATEGY_HASH; + n->modulus = n->remainder = -1; + + foreach (lc, $5) + { + DefElem *opt = lfirst_node(DefElem, lc); + + if (strcmp(opt->defname, "modulus") == 0) + { + if (n->modulus != -1) + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("modulus for hash partition provided more than once"), + parser_errposition(opt->location))); + n->modulus = defGetInt32(opt); + } + else if (strcmp(opt->defname, "remainder") == 0) + { + if (n->remainder != -1) + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("remainder for hash partition provided more than once"), + parser_errposition(opt->location))); + n->remainder = defGetInt32(opt); + } + else + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("unrecognized hash partition bound specification \"%s\"", + opt->defname), + parser_errposition(opt->location))); + } + + if (n->modulus == -1) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("modulus for hash partition must be specified"))); + if (n->remainder == -1) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("remainder for hash partition must be specified"))); + + n->location = @3; + + $$ = n; + } + ; + +CopyStmt: COPY opt_binary qualified_name opt_column_list + copy_from opt_program copy_file_name copy_delimiter WITH_paren + copy_options where_clause + { + CopyStmt *n = makeNode(CopyStmt); + n->relation = $3; + n->query = NULL; + n->attlist = $4; + n->is_from = $5; + n->is_program = $6; + n->filename = $7; + n->whereClause = $11; + + if (n->is_program && n->filename == NULL) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("STDIN/STDOUT not allowed with PROGRAM"), + parser_errposition(@8))); + + if (!n->is_from && n->whereClause != NULL) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("WHERE clause not allowed with COPY TO"), + parser_errposition(@11))); + + n->options = NIL; + /* Concatenate user-supplied flags */ + if ($2) + n->options = lappend(n->options, $2); + if ($8) + n->options = lappend(n->options, $8); + if ($10) + n->options = list_concat(n->options, $10); + $$ = (Node *)n; + } + | COPY '(' PreparableStmt ')' TO opt_program + copy_file_name WITH_paren copy_options + { + CopyStmt *n = makeNode(CopyStmt); + n->relation = NULL; + n->query = $3; + n->attlist = NIL; + n->is_from = false; + n->is_program = $6; + n->filename = $7; + n->options = $9; + + if (n->is_program && n->filename == NULL) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("STDIN/STDOUT not allowed with PROGRAM"), + parser_errposition(@5))); + + $$ = (Node *)n; + } + ; + +OptTableElementList: + TableElementList ',' { $$ = $1; } /* For TSQL compatibility */ + ; + +columnDef: + ColId TSQL_computed_column ColQualList + { + ColumnDef *n = makeNode(ColumnDef); + + if (sql_dialect != SQL_DIALECT_TSQL) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("This syntax is only valid when babelfishpg_tsql.sql_dialect is TSQL"), + parser_errposition(@2))); + + TSQLInstrumentation(INSTR_TSQL_COMPUTED_COLUMN); + n->colname = $1; + + /* + * For computed columns, user doesn't provide a datatype. + * But, PG expects a datatype. Hence, we just assign a + * valid datatype temporarily. Later, we'll evaluate + * expression to detect the actual datatype. + */ + n->typeName = makeTypeName("varchar"); + 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->fdwoptions = NULL; + n->location = @1; + + $3 = lappend($3, $2); + + SplitColQualList($3, &n->constraints, &n->collClause, + yyscanner); + + $$ = (Node *)n; + } + ; + +ColQualList: /* extend it allow to consume nullable (tsql_ColConstraint) */ + /* ColQualList ColConstraint */ + /* | EMPTY */ + ColQualList tsql_ColConstraint { $$ = (($2 != NULL) ? lappend($1, $2) : $1); } + ; +ConstraintElem: + UNIQUE tsql_cluster '(' columnList ')' opt_c_include opt_definition OptConsTableSpace + ConstraintAttributeSpec tsql_opt_on_filegroup + { + Constraint *n = makeNode(Constraint); + n->contype = CONSTR_UNIQUE; + n->location = @1; + n->keys = $4; + n->including = $6; + n->options = $7; + n->indexname = NULL; + n->indexspace = $8; + processCASbits($9, @9, "UNIQUE", + &n->deferrable, &n->initdeferred, NULL, + NULL, yyscanner); + $$ = (Node *)n; + } + | UNIQUE tsql_cluster '(' columnListWithOptAscDesc ')' opt_c_include opt_definition OptConsTableSpace + ConstraintAttributeSpec tsql_opt_on_filegroup + { + Constraint *n = makeNode(Constraint); + n->contype = CONSTR_UNIQUE; + n->location = @1; + n->keys = $4; + n->including = $6; + n->options = $7; + n->indexname = NULL; + n->indexspace = $8; + processCASbits($9, @9, "UNIQUE", + &n->deferrable, &n->initdeferred, NULL, + NULL, yyscanner); + $$ = (Node *)n; + } + | UNIQUE '(' columnListWithOptAscDesc ')' opt_c_include opt_definition OptConsTableSpace + ConstraintAttributeSpec tsql_opt_on_filegroup + { + Constraint *n = makeNode(Constraint); + n->contype = CONSTR_UNIQUE; + n->location = @1; + n->keys = $3; + n->including = $5; + n->options = $6; + n->indexname = NULL; + n->indexspace = $7; + processCASbits($8, @8, "UNIQUE", + &n->deferrable, &n->initdeferred, NULL, + NULL, yyscanner); + $$ = (Node *)n; + } + | UNIQUE '(' columnList ')' opt_c_include opt_definition OptConsTableSpace + ConstraintAttributeSpec tsql_on_filegroup + { + Constraint *n = makeNode(Constraint); + n->contype = CONSTR_UNIQUE; + n->location = @1; + n->keys = $3; + n->including = $5; + n->options = $6; + n->indexname = NULL; + n->indexspace = $7; + processCASbits($8, @8, "UNIQUE", + &n->deferrable, &n->initdeferred, NULL, + NULL, yyscanner); + $$ = (Node *)n; + } + | UNIQUE tsql_cluster ExistingIndex ConstraintAttributeSpec + { + Constraint *n = makeNode(Constraint); + n->contype = CONSTR_UNIQUE; + n->location = @1; + n->keys = NIL; + n->including = NIL; + n->options = NIL; + n->indexname = $3; + n->indexspace = NULL; + processCASbits($4, @4, "UNIQUE", + &n->deferrable, &n->initdeferred, NULL, + NULL, yyscanner); + $$ = (Node *)n; + } + | PRIMARY KEY tsql_cluster '(' columnList ')' opt_c_include opt_definition OptConsTableSpace + ConstraintAttributeSpec tsql_opt_on_filegroup + { + Constraint *n = makeNode(Constraint); + n->contype = CONSTR_PRIMARY; + n->location = @1; + n->keys = $5; + n->including = $7; + n->options = $8; + n->indexname = NULL; + n->indexspace = $9; + processCASbits($10, @10, "PRIMARY KEY", + &n->deferrable, &n->initdeferred, NULL, + NULL, yyscanner); + $$ = (Node *)n; + } + | PRIMARY KEY tsql_cluster '(' columnListWithOptAscDesc ')' opt_c_include opt_definition OptConsTableSpace + ConstraintAttributeSpec tsql_opt_on_filegroup + { + Constraint *n = makeNode(Constraint); + n->contype = CONSTR_PRIMARY; + n->location = @1; + n->keys = $5; + n->including = $7; + n->options = $8; + n->indexname = NULL; + n->indexspace = $9; + processCASbits($10, @10, "PRIMARY KEY", + &n->deferrable, &n->initdeferred, NULL, + NULL, yyscanner); + $$ = (Node *)n; + } + | PRIMARY KEY '(' columnListWithOptAscDesc ')' opt_c_include opt_definition OptConsTableSpace + ConstraintAttributeSpec tsql_opt_on_filegroup + { + Constraint *n = makeNode(Constraint); + n->contype = CONSTR_PRIMARY; + n->location = @1; + n->keys = $4; + n->including = $6; + n->options = $7; + n->indexname = NULL; + n->indexspace = $8; + processCASbits($9, @9, "PRIMARY KEY", + &n->deferrable, &n->initdeferred, NULL, + NULL, yyscanner); + $$ = (Node *)n; + } + | PRIMARY KEY '(' columnList ')' opt_c_include opt_definition OptConsTableSpace + ConstraintAttributeSpec tsql_on_filegroup + { + Constraint *n = makeNode(Constraint); + n->contype = CONSTR_PRIMARY; + n->location = @1; + n->keys = $4; + n->including = $6; + n->options = $7; + n->indexname = NULL; + n->indexspace = $8; + processCASbits($9, @9, "PRIMARY KEY", + &n->deferrable, &n->initdeferred, NULL, + NULL, yyscanner); + $$ = (Node *)n; + } + | PRIMARY KEY tsql_cluster ExistingIndex ConstraintAttributeSpec + { + Constraint *n = makeNode(Constraint); + n->contype = CONSTR_PRIMARY; + n->location = @1; + n->keys = NIL; + n->including = NIL; + n->options = NIL; + n->indexname = $4; + n->indexspace = NULL; + processCASbits($5, @5, "PRIMARY KEY", + &n->deferrable, &n->initdeferred, NULL, + NULL, yyscanner); + $$ = (Node *)n; + } + ; + +OptWith: + WITH_paren reloptions { $$ = $2; } + ; + +OnCommitOption: + OptFileGroup { $$ = ONCOMMIT_NOOP; } + | OptFileGroup OptFileGroup { $$ = ONCOMMIT_NOOP; } + ; + +DefineStmt: + /* + * TSQL supports table type, and we handle it by creating a template + * table so that later when variables of this type are created, they + * are created like the template table. + */ + CREATE TYPE_P any_name AS TABLE '(' OptTableElementList ')' + { + CreateStmt *n = makeNode(CreateStmt); + if (sql_dialect != SQL_DIALECT_TSQL) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("This syntax is only valid when babelfishpg_tsql.sql_dialect is TSQL"), + parser_errposition(@1))); + TSQLInstrumentation(INSTR_TSQL_CREATE_TEMP_TABLE); + n->relation = makeRangeVarFromAnyNameForTableType($3, @3, yyscanner); + n->tableElts = $7; + n->inhRelations = NIL; + n->partspec = NULL; + n->ofTypename = NULL; + n->constraints = NIL; + n->options = NIL; + n->oncommit = ONCOMMIT_NOOP; + n->tablespacename = NULL; + n->if_not_exists = false; + n->tsql_tabletype = true; + $$ = (Node *)n; + } + | CREATE TYPE_P any_name FROM Typename + { + CreateDomainStmt *n = makeNode(CreateDomainStmt); + n->domainname = $3; + n->typeName = $5; + n->constraints = NIL; + + $$ = (Node *)n; + } + | CREATE TYPE_P any_name FROM Typename NOT NULL_P + { + CreateDomainStmt *n = makeNode(CreateDomainStmt); + Constraint *c = makeNode(Constraint); + + n->domainname = $3; + n->typeName = $5; + n->constraints = list_make1(c); + + c->contype = CONSTR_NOTNULL; + c->location = @6; + + $$ = (Node *)n; + + } + | CREATE TYPE_P any_name FROM Typename NULL_P + { + CreateDomainStmt *n = makeNode(CreateDomainStmt); + Constraint *c = makeNode(Constraint); + + n->domainname = $3; + n->typeName = $5; + n->constraints = list_make1(c); + + c->contype = CONSTR_NULL; + c->location = @6; + + $$ = (Node *)n; + + } + ; + +func_arg: + param_name func_type arg_class + { + FunctionParameter *n = makeNode(FunctionParameter); + n->name = $1; + n->argType = $2; + n->mode = $3; + n->defexpr = NULL; + $$ = n; + } + ; + +arg_class: + TSQL_OUT { $$ = FUNC_PARAM_OUT; } + | TSQL_OUTPUT { $$ = FUNC_PARAM_INOUT; } + | IN_P TSQL_OUT { $$ = FUNC_PARAM_INOUT; } + ; + +/* Note: any simple identifier will be returned as a type name! + * TSQL support for and : + * CREATE TABLE... WITH () + * CREATE INDEX... WITH () + */ +def_arg: func_type tsql_on_ident_partitions_list { $$ = (Node *)$1; } + | reserved_keyword tsql_paren_extra_relopt_list { $$ = (Node *)makeString(pstrdup($1)); } + | NumericOnly tsql_ident { $$ = (Node *)$1; } + | NONE tsql_on_ident_partitions_list { $$ = (Node *)makeString(pstrdup($1)); } + | ROW tsql_opt_on_partitions_list { $$ = (Node *)makeString(pstrdup($1)); } + ; + +DropStmt: + DROP drop_type_name_on_any_name tsql_triggername + { + DropStmt *n = makeNode(DropStmt); + + if(sql_dialect != SQL_DIALECT_TSQL || $2 != OBJECT_TRIGGER) + { + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("This syntax is only valid when babelfishpg_tsql.sql_dialect is TSQL for DROP TRIGGER"), + parser_errposition(@1))); + } + n->removeType = OBJECT_TRIGGER; + n->objects = list_make1($3); + n->behavior = DROP_CASCADE; + n->missing_ok = false; + n->concurrent = false; + $$ = (Node *) n; + } + | DROP drop_type_name_on_any_name IF_P EXISTS tsql_triggername + { + DropStmt *n = makeNode(DropStmt); + + if(sql_dialect != SQL_DIALECT_TSQL || $2 != OBJECT_TRIGGER) + { + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("This syntax is only valid when babelfishpg_tsql.sql_dialect is TSQL for DROP TRIGGER"), + parser_errposition(@1))); + } + n->removeType = OBJECT_TRIGGER; + n->objects = list_make1($5); + n->behavior = DROP_CASCADE; + n->missing_ok = true; + n->concurrent = false; + $$ = (Node *) n; + } + ; + +tsql_DropIndexStmt: + DROP drop_type_any_name index_name ON name_list + { + DropStmt *n = makeNode(DropStmt); + if(sql_dialect != SQL_DIALECT_TSQL) + { + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("This syntax is only valid when babelfishpg_tsql.sql_dialect is TSQL"), + parser_errposition(@1))); + } + if($2 != OBJECT_INDEX) + { + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("This syntax is only valid for DROP INDEX ... on ..."), + parser_errposition(@2))); + } + n->removeType = $2; + n->missing_ok = false; + n->objects = list_make1(list_make1(makeString(construct_unique_index_name($3, makeRangeVarFromAnyName($5, @5, yyscanner)->relname)))); + n->behavior = DROP_CASCADE; + n->concurrent = false; + $$ = (Node *)n; + } + | DROP drop_type_any_name IF_P EXISTS index_name ON name_list + { + DropStmt *n = makeNode(DropStmt); + if(sql_dialect != SQL_DIALECT_TSQL) + { + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("This syntax is only valid when babelfishpg_tsql.sql_dialect is TSQL"), + parser_errposition(@1))); + } + if($2 != OBJECT_INDEX) + { + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("This syntax is only valid for DROP INDEX ... on ..."), + parser_errposition(@2))); + } + n->removeType = $2; + n->missing_ok = true; + n->objects = list_make1(list_make1(makeString(construct_unique_index_name($5, makeRangeVarFromAnyName($7, @5, yyscanner)->relname)))); + n->behavior = DROP_CASCADE; + n->concurrent = false; + $$ = (Node *)n; + } + ; + +opt_definition: + WITH_paren definition { $$ = $2; } + | WITH IDENT '=' NumericOnly + { + if (sql_dialect != SQL_DIALECT_TSQL) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("This syntax is only valid when babelfishpg_tsql.sql_dialect is TSQL"), + parser_errposition(@1))); + $$ = NIL; + } + ; + +RemoveFuncStmt: + DROP TSQL_PROC function_with_argtypes_list opt_drop_behavior + { + DropStmt *n = makeNode(DropStmt); + n->removeType = OBJECT_PROCEDURE; + n->objects = $3; + n->behavior = $4; + n->missing_ok = false; + n->concurrent = false; + $$ = (Node *)n; + } + | DROP TSQL_PROC IF_P EXISTS function_with_argtypes_list opt_drop_behavior + { + DropStmt *n = makeNode(DropStmt); + n->removeType = OBJECT_PROCEDURE; + n->objects = $5; + n->behavior = $6; + n->missing_ok = true; + n->concurrent = false; + $$ = (Node *)n; + } + ; + +DeleteStmt: opt_with_clause DELETE_P FROM relation_expr_opt_alias + tsql_table_hint_expr using_clause where_or_current_clause + returning_clause + { + DeleteStmt *n = makeNode(DeleteStmt); + n->relation = $4; + n->usingClause = $6; + n->whereClause = $7; + n->returningList = $8; + n->withClause = $1; + $$ = (Node *)n; + } + ; + +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; + if ($6 != NULL && IsA(linitial($6), JoinExpr)) + { + n = (UpdateStmt*)tsql_update_delete_stmt_with_join( + (Node*)n, $6, $7, NULL, $3, + yyscanner); + } + else + { + 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_opt_table_hint_expr + SET set_clause_list + from_clause + where_or_current_clause + returning_clause + { + UpdateStmt *n = makeNode(UpdateStmt); + n->relation = $4; + 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->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; + 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; + 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 + tsql_opt_table_hint_expr + SET set_clause_list + tsql_output_clause + from_clause + where_or_current_clause + { + UpdateStmt *n = makeNode(UpdateStmt); + n->relation = $4; + n->targetList = $7; + if ($8 != NULL && IsA(linitial($8), JoinExpr)) + { + n = (UpdateStmt*)tsql_update_delete_stmt_with_join( + (Node*)n, $9, $10, $3, $4, + yyscanner); + } + else + { + n->fromClause = $8; + n->whereClause = tsql_update_delete_stmt_with_top($3, + $4, $10, yyscanner); + } + tsql_check_update_output_transformation($8); + n->returningList = $8; + n->withClause = $1; + $$ = (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 + tsql_opt_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, $3, $4, $7, $8, $10, + $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 + tsql_opt_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, $3, $4, $7, $8, $10, + NIL, $11, $12, yyscanner); + } + ; + +select_no_parens: + select_clause tsql_for_clause + { + base_yy_extra_type *yyextra = pg_yyget_extra(yyscanner); + char *src_query = yyextra->core_yy_extra.scanbuf; + /* + * We can free the SelectStmt because we will process the transformed + * FOR XML query by calling function tsql_query_to_xml(). + */ + pfree($1); + $1 = (Node *) makeNode(SelectStmt); + ((SelectStmt *)$1)->targetList = list_make1(TsqlForXMLMakeFuncCall((TSQL_ForClause *) $2, src_query, @1, yyscanner)); + $$ = $1; + } + | select_clause sort_clause tsql_for_clause + { + if ($3 == NULL) + insertSelectOptions((SelectStmt *) $1, $2, NIL, + NULL, NULL, + yyscanner); + else + { + base_yy_extra_type *yyextra = pg_yyget_extra(yyscanner); + char *src_query = yyextra->core_yy_extra.scanbuf; + /* + * We can free the SelectStmt because we will process the transformed + * FOR XML query by calling function tsql_query_to_xml(). + */ + pfree($1); + $1 = (Node *) makeNode(SelectStmt); + ((SelectStmt *)$1)->targetList = list_make1(TsqlForXMLMakeFuncCall((TSQL_ForClause *) $3, src_query, @1, yyscanner)); + } + $$ = $1; + } + | with_clause select_clause tsql_for_clause + { + if ($3 == NULL) + insertSelectOptions((SelectStmt *) $2, NULL, NIL, + NULL, + $1, + yyscanner); + else + { + base_yy_extra_type *yyextra = pg_yyget_extra(yyscanner); + char *src_query = yyextra->core_yy_extra.scanbuf; + /* + * We can free the SelectStmt because we will process the transformed + * FOR XML query by calling function tsql_query_to_xml(). + */ + pfree($2); + $2 = (Node *) makeNode(SelectStmt); + ((SelectStmt *)$2)->targetList = list_make1(TsqlForXMLMakeFuncCall((TSQL_ForClause *) $3, src_query, @1, yyscanner)); + } + $$ = $2; + } + | with_clause select_clause sort_clause tsql_for_clause + { + if ($4 == NULL) + insertSelectOptions((SelectStmt *) $2, $3, NIL, + NULL, + $1, + yyscanner); + else + { + base_yy_extra_type *yyextra = pg_yyget_extra(yyscanner); + char *src_query = yyextra->core_yy_extra.scanbuf; + /* + * We can free the SelectStmt because we will process the transformed + * FOR XML query by calling function tsql_query_to_xml(). + */ + pfree($2); + $2 = (Node *) makeNode(SelectStmt); + ((SelectStmt *)$2)->targetList = list_make1(TsqlForXMLMakeFuncCall((TSQL_ForClause *) $4, src_query, @1, yyscanner)); + } + $$ = $2; + } + ; + +simple_select: + SELECT opt_all_clause tsql_top_clause opt_target_list + into_clause from_clause where_clause + group_clause having_clause window_clause + { + SelectStmt *n = makeNode(SelectStmt); + + n->limitCount = $3; + n->targetList = $4; + 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->fromClause = $6; + n->whereClause = $7; + n->groupClause = $8; + n->havingClause = $9; + n->windowClause = $10; + $$ = (Node *)n; + } + | SELECT distinct_clause tsql_top_clause target_list + into_clause from_clause where_clause + group_clause having_clause window_clause + { + SelectStmt *n = makeNode(SelectStmt); + + n->distinctClause = $2; + n->limitCount = $3; + n->targetList = $4; + 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->fromClause = $6; + n->whereClause = $7; + n->groupClause = $8; + n->havingClause = $9; + n->windowClause = $10; + $$ = (Node *)n; + } + ; + +table_ref: relation_expr tsql_table_hint_expr + { + $$ = (Node *) $1; + } + | relation_expr alias_clause tsql_table_hint_expr + { + $1->alias = $2; + $$ = (Node *) $1; + } + | relation_expr tsql_table_hint_expr alias_clause + { + $1->alias = $3; + $$ = (Node *) $1; + } + | relation_expr opt_alias_clause tablesample_clause tsql_table_hint_expr + { + RangeTableSample *n = (RangeTableSample *) $3; + $1->alias = $2; + /* relation_expr goes inside the RangeTableSample node */ + n->relation = (Node *) $1; + $$ = (Node *) n; + } + ; + +func_expr_common_subexpr: + TSQL_TRY_CAST '(' a_expr AS Typename ')' + { + $$ = TsqlFunctionTryCast($3, $5, @1); + } + | TSQL_CONVERT '(' Typename ',' a_expr ')' + { + $$ = TsqlFunctionConvert($3, $5, NULL, false, @1); + } + | TSQL_CHOOSE '(' a_expr ',' expr_list ')' + { + $$ = TsqlFunctionChoose($3, $5, @1); + } + | TSQL_CONVERT '(' Typename ',' a_expr ',' a_expr ')' + { + $$ = TsqlFunctionConvert($3, $5, $7, false, @1); + } + | TSQL_TRY_CONVERT '(' Typename ',' a_expr ')' + { + $$ = TsqlFunctionConvert($3, $5, NULL, true, @1); + } + | TSQL_TRY_CONVERT '(' Typename ',' a_expr ',' a_expr ')' + { + TSQLInstrumentation(INSTR_TSQL_TRY_CONVERT); + $$ = TsqlFunctionConvert($3, $5, $7, true, @1); + } + | TSQL_DATEADD '(' dateadd_arg ',' a_expr ',' a_expr ')' + { + $$ = (Node *) makeFuncCall(TsqlSystemFuncName2("dateadd"), + list_make3(makeStringConst($3, @3), + $5, $7), + @1); + } + | TSQL_PARSE '(' a_expr AS Typename ')' + { + TSQLInstrumentation(INSTR_TSQL_PARSE); + $$ = TsqlFunctionParse($3, $5, NULL, false, @1); + } + | TSQL_PARSE '(' a_expr AS Typename USING a_expr ')' + { + TSQLInstrumentation(INSTR_TSQL_PARSE); + $$ = TsqlFunctionParse($3, $5, $7, false, @1); + } + | TSQL_TRY_PARSE '(' a_expr AS Typename ')' + { + $$ = TsqlFunctionParse($3, $5, NULL, true, @1); + } + | TSQL_TRY_PARSE '(' a_expr AS Typename USING a_expr ')' + { + $$ = TsqlFunctionParse($3, $5, $7, true, @1); + } + | TSQL_DATEDIFF '(' datediff_arg ',' a_expr ',' a_expr ')' + { + $$ = (Node *) makeFuncCall(TsqlSystemFuncName2("datediff"), + list_make3(makeStringConst($3, @3), $5, $7), + @1); + } + | TSQL_DATEPART '(' datepart_arg ',' a_expr ')' + { + $$ = (Node *) makeFuncCall(TsqlSystemFuncName2("datepart"), + list_make2(makeStringConst($3, @3), $5), + @1); + } + | TSQL_DATENAME '(' datepart_arg ',' a_expr ')' + { + $$ = (Node *) makeFuncCall(TsqlSystemFuncName2("datename"), + list_make2(makeStringConst($3, @3), $5), + @1); + } + | TSQL_ISNULL '(' a_expr ',' a_expr ')' + { + CoalesceExpr *c = makeNode(CoalesceExpr); + c->args=list_make2($3, $5); + c->location = @1; + $$ = (Node *)c; + } + | TSQL_IIF '(' a_expr ',' a_expr ',' a_expr ')' + { + $$ = TsqlFunctionIIF($3, $5, $7, @1); + } + | TSQL_ATAT IDENT + { + $$ = (Node *) makeFuncCall(TsqlSystemFuncName2($2), NIL, @1); + } + | TSQL_ATAT VERSION_P + { + $$ = (Node *) makeFuncCall(TsqlSystemFuncName2("version"),NIL, @1); + } + | TSQL_ATAT IDENTITY_P + { + $$ = (Node *) makeFuncCall(TsqlSystemFuncName("babelfish_get_last_identity_numeric"), NIL, @1); + } + ; + +target_el: + a_expr AS Sconst + { + $$ = makeNode(ResTarget); + if (strlen($3) >= NAMEDATALEN) + { + char *name = pstrdup($3); + truncate_identifier(name, strlen(name), true); + $$->name = downcaseIfTsqlAndCaseInsensitive(name); + } + else + $$->name = downcaseIfTsqlAndCaseInsensitive($3); + $$->name_location = @3; + $$->indirection = NIL; + $$->val = (Node *)$1; + $$->location = @1; + } + | a_expr AS TSQL_NVARCHAR Sconst + /* + * This rule is to support SELECT 1 AS N'col' query in Babelfish. + * For vanilla PG, the syntax is valid as well + */ + { + $$ = makeNode(ResTarget); + if (strlen($4) >= NAMEDATALEN) + { + char *name = pstrdup($4); + truncate_identifier(name, strlen(name), true); + $$->name = downcaseIfTsqlAndCaseInsensitive(name); + } + else + $$->name = downcaseIfTsqlAndCaseInsensitive($4); + $$->name_location = @4; + $$->indirection = NIL; + $$->val = (Node *)$1; + $$->location = @1; + } + ; + +AexprConst: + TSQL_XCONST + { + $$ = makeTSQLHexStringConst($1, @1); + } + | TSQL_NVARCHAR Sconst + { + /* This is to support N'str' in various locations */ + TypeName *t = makeTypeNameFromNameList(list_make2(makeString("sys"), makeString("nvarchar"))); + t->location = @1; + t->typmods = list_make1(makeIntConst(TSQLMaxTypmod, -1)); + $$ = makeStringConstCast($2, @2, t); + } + ; + + +/* Start of T-SQL specific grammar rule. */ + +tsql_stmtmulti: tsql_stmtmulti ';' tsql_stmt + { + if ($1 != NIL) + { + /* update length of previous stmt */ + updateRawStmtEnd(llast_node(RawStmt, $1), @2); + } + if ($3 != NULL) + $$ = lappend($1, makeRawStmt($3, @2 + 1)); + else + $$ = $1; + } + | tsql_stmt + { + if ($1 != NULL) + $$ = list_make1(makeRawStmt($1, 0)); + else + $$ = NIL; + } + ; + +/* --------------------------------- */ +/* Rules for OUTPUT clause support */ +tsql_output_insert_rest: + tsql_output_simple_select opt_sort_clause + { + SelectStmt *s = makeNode(SelectStmt); + $$ = makeNode(InsertStmt); + $$->cols = NIL; + s = (SelectStmt*) $1; + s->sortClause = $2; + $$->selectStmt = (Node*) s; + } + | '(' tsql_output_simple_select opt_sort_clause ')' + { + SelectStmt *s = makeNode(SelectStmt); + $$ = makeNode(InsertStmt); + $$->cols = NIL; + s = (SelectStmt*) $2; + s->sortClause = $3; + $$->selectStmt = (Node*) s; + } + | tsql_ExecStmt + { + $$ = makeNode(InsertStmt); + $$->cols = NIL; + $$->selectStmt = NULL; + $$->execStmt = $1; + } + ; + +tsql_output_insert_rest_no_paren: + tsql_output_simple_select + { + $$ = makeNode(InsertStmt); + $$->cols = NIL; + $$->selectStmt = $1; + } + | tsql_output_ExecStmt + { + $$ = makeNode(InsertStmt); + $$->cols = NIL; + $$->selectStmt = NULL; + $$->execStmt = $1; + } + ; + +tsql_output_simple_select: + SELECT opt_all_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; + n->havingClause = $8; + n->windowClause = $9; + $$ = (Node *)n; + } + | SELECT distinct_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; + n->havingClause = $8; + n->windowClause = $9; + $$ = (Node *)n; + } + | tsql_values_clause { $$ = $1; } + | tsql_output_simple_select UNION all_or_distinct tsql_output_simple_select + { + $$ = makeSetOp(SETOP_UNION, $3, $1, $4); + } + | tsql_output_simple_select INTERSECT all_or_distinct tsql_output_simple_select + { + $$ = makeSetOp(SETOP_INTERSECT, $3, $1, $4); + } + | tsql_output_simple_select EXCEPT all_or_distinct tsql_output_simple_select + { + $$ = makeSetOp(SETOP_EXCEPT, $3, $1, $4); + } + + ; + +tsql_values_clause: + TSQL_VALUES '(' expr_list ')' + { + SelectStmt *n = makeNode(SelectStmt); + n->valuesLists = list_make1($3); + $$ = (Node *) n; + } + | tsql_values_clause ',' '(' expr_list ')' + { + SelectStmt *n = (SelectStmt *) $1; + n->valuesLists = lappend(n->valuesLists, $4); + $$ = (Node *) n; + } + ; + +tsql_output_clause: + TSQL_OUTPUT target_list { $$ = $2; } + ; + +tsql_output_into_target_columns: + '(' insert_column_list ')' { $$ = $2; } + ; + +tsql_output_ExecStmt: + TSQL_EXEC tsql_opt_return tsql_func_name tsql_actual_args + { + List *name = $3; + List *args = $4; + CallStmt *n; + ListCell *lc; + + foreach(lc, args) + { + Node *node = lfirst(lc); + if (node->type == T_RowExpr) + { + RowExpr *row_expr = (RowExpr *) node; + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("Row Expression argument not supported"), + parser_errposition(row_expr->location))); + } + } + + n = makeNode(CallStmt); + n->funccall = makeFuncCall(name, args, @1); + + $$ = (Node *) n; + } + ; + +/* END rules for OUTPUT clause support */ +/* --------------------------------- */ + +tsql_stmt : + AlterEventTrigStmt + | AlterCollationStmt + | AlterDatabaseStmt + | AlterDatabaseSetStmt + | AlterDefaultPrivilegesStmt + | AlterDomainStmt + | AlterEnumStmt + | AlterExtensionStmt + | AlterExtensionContentsStmt + | AlterFdwStmt + | AlterForeignTableStmt + | AlterFunctionStmt + | AlterGroupStmt + | tsql_AlterLoginStmt + | AlterObjectDependsStmt + | AlterObjectSchemaStmt + | AlterOwnerStmt + | AlterOperatorStmt + | AlterPolicyStmt + | AlterSeqStmt + | AlterSystemStmt + | AlterTableStmt + | AlterTblSpcStmt + | AlterCompositeTypeStmt + | AlterPublicationStmt + | AlterRoleSetStmt + | AlterRoleStmt + | AlterSubscriptionStmt + | AlterTSConfigurationStmt + | AlterTSDictionaryStmt + | AlterUserMappingStmt + | AnalyzeStmt + | CallStmt + | CheckPointStmt + | ClosePortalStmt + | ClusterStmt + | CommentStmt + | ConstraintsSetStmt + | CopyStmt + | CreateAmStmt + | CreateAsStmt + | CreateCastStmt + | CreateConversionStmt + | CreateDomainStmt + | CreateExtensionStmt + | CreateFdwStmt + | CreateForeignServerStmt + | CreateForeignTableStmt + | tsql_CreateFunctionStmt + | CreateGroupStmt + | tsql_CreateLoginStmt + | CreateMatViewStmt + | CreateOpClassStmt + | CreateOpFamilyStmt + | CreatePublicationStmt + | AlterOpFamilyStmt + | CreatePolicyStmt + | CreatePLangStmt + | CreateSchemaStmt + | CreateSeqStmt + | CreateStmt + | CreateSubscriptionStmt + | CreateStatsStmt + | CreateTableSpaceStmt + | CreateTransformStmt + | tsql_CreateTrigStmt + | CreateEventTrigStmt + | CreateRoleStmt + | CreateUserStmt + | CreateUserMappingStmt + | CreatedbStmt + | DeallocateStmt + | DeclareCursorStmt + | DefineStmt + | tsql_DeleteStmt + | DiscardStmt + | DoStmt + | DropCastStmt + | tsql_DropLoginStmt + | DropOpClassStmt + | DropOpFamilyStmt + | DropOwnedStmt + | DropPLangStmt + | tsql_DropIndexStmt + | DropStmt + | DropSubscriptionStmt + | DropTableSpaceStmt + | DropTransformStmt + | DropRoleStmt + | DropUserMappingStmt + | DropdbStmt + | tsql_ExecStmt + | ExplainStmt + | FetchStmt + | GrantStmt + | GrantRoleStmt + | ImportForeignSchemaStmt + | tsql_IndexStmt + | tsql_InsertStmt + | ListenStmt + | RefreshMatViewStmt + | LoadStmt + | LockStmt + | NotifyStmt + | PrepareStmt + | ReassignOwnedStmt + | ReindexStmt + | RemoveAggrStmt + | RemoveFuncStmt + | RemoveOperStmt + | RenameStmt + | RevokeStmt + | RevokeRoleStmt + | RuleStmt + | SecLabelStmt + | SelectStmt + | tsql_TransactionStmt + | TruncateStmt + | UnlistenStmt + | tsql_UpdateStmt + | VacuumStmt + | VariableResetStmt + | tsql_VariableSetStmt + | VariableShowStmt + | ViewStmt + | tsql_alter_server_role + | /*EMPTY*/ + { $$ = NULL; } + ; + +tsql_opt_INTO: + INTO + | /* empty */ + ; + +tsql_InsertStmt: + opt_with_clause INSERT 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; + } + | opt_with_clause INSERT 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; + } + | opt_with_clause INSERT tsql_opt_INTO insert_target tsql_opt_table_hint_expr DEFAULT TSQL_VALUES + { + InsertStmt *i = makeNode(InsertStmt); + i->relation = $4; + i->onConflictClause = NULL; + i->returningList = NULL; + i->withClause = $1; + i->cols = NIL; + i->selectStmt = NULL; + i->execStmt = NULL; + $$ = (Node *) i; + } + /* OUTPUT syntax */ + | opt_with_clause INSERT 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) + 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; + } + | opt_with_clause INSERT tsql_opt_INTO insert_target tsql_opt_table_hint_expr tsql_output_clause tsql_output_insert_rest_no_paren + { + if ($7->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; + } + /* 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 + { + InsertStmt *i = makeNode(InsertStmt); + i->relation = $4; + i->onConflictClause = NULL; + i->returningList = $6; + i->withClause = $1; + i->cols = NIL; + i->selectStmt = NULL; + i->execStmt = NULL; + $$ = (Node *) i; + } + */ + /* 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 ')' + tsql_output_clause INTO insert_target tsql_output_into_target_columns tsql_output_insert_rest + { + if ($13->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); + } + | opt_with_clause INSERT 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) + 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); + } + | opt_with_clause INSERT 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); + i->relation = NULL; + i->onConflictClause = NULL; + i->returningList = NULL; + i->withClause = NULL; + i->cols = NIL; + i->selectStmt = NULL; + i->execStmt = NULL; + $$ = tsql_insert_output_into_cte_transformation($1, $4, NULL, $6, $8, $9, i, 4); + } + /* Without OUTPUT target column list */ + | opt_with_clause INSERT 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) + 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); + } + | opt_with_clause INSERT 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) + 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); + } + /* + | opt_with_clause INSERT tsql_opt_INTO insert_target tsql_opt_table_hint_expr tsql_output_clause + INTO insert_target DEFAULT VALUES + { + InsertStmt *i = makeNode(InsertStmt); + i->relation = NULL; + i->onConflictClause = NULL; + i->returningList = NULL; + i->withClause = NULL; + i->cols = NIL; + i->selectStmt = NULL; + i->execStmt = NULL; + $$ = tsql_insert_output_into_cte_transformation($1, $4, NULL, $6, $8, NIL, i, 4); + } + */ + ; + +tsql_ExecStmt: + TSQL_EXEC tsql_opt_return tsql_func_name tsql_actual_args + { + List *name = $3; + List *args = $4; + CallStmt *n; + ListCell *lc; + + foreach(lc, args) + { + Node *node = lfirst(lc); + if (node->type == T_RowExpr) + { + RowExpr *row_expr = (RowExpr *) node; + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("Row Expression argument not supported"), + parser_errposition(row_expr->location))); + } + } + + n = makeNode(CallStmt); + n->funccall = makeFuncCall(name, args, @1); + + $$ = (Node *) n; + } + | EXECUTE tsql_opt_return tsql_func_name tsql_actual_args + { + List *name = $3; + List *args = $4; + CallStmt *n; + ListCell *lc; + + foreach(lc, args) + { + Node *node = lfirst(lc); + if (node->type == T_RowExpr) + { + RowExpr *row_expr = (RowExpr *) node; + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("Row Expression argument not supported"), + parser_errposition(row_expr->location))); + } + } + + n = makeNode(CallStmt); + n->funccall = makeFuncCall(name, args, @1); + + $$ = (Node *) n; + } + | TSQL_EXEC '(' Sconst ')' + { + DoStmt *n = makeNode(DoStmt); + n->args = list_make1(makeDefElem("as", + (Node *)makeString($3), + @3)); + $$ = (Node *) n; + } + | EXECUTE '(' Sconst ')' + { + DoStmt *n = makeNode(DoStmt); + n->args = list_make1(makeDefElem("as", + (Node *)makeString($3), + @3)); + $$ = (Node *) n; + } + ; + +tsql_opt_return: + PARAM '=' + | /* EMPTY */ + ; + +tsql_actual_args: tsql_actual_arg + { + $$ = list_make1($1); + } + | tsql_actual_args ',' tsql_actual_arg + { + $$ = lappend($1, $3); + } + | /* EMPTY */ + { + $$ = NIL; + } + ; + +tsql_opt_output: + TSQL_OUTPUT { $$ = true; } + | TSQL_OUT { $$ = true; } + | /* EMPTY */ { $$ = false; } + ; + +tsql_opt_readonly: TSQL_READONLY { $$ = true; } + | /* EMPTY */ { $$ = false; } + ; + +tsql_actual_arg: ColId '=' a_expr tsql_opt_output + { + NamedArgExpr *na = makeNode(NamedArgExpr); + + na->name = $1; /* FIXME: record $4 somewhere - probably need a new Node type */ + na->arg = (Expr *) $3; + na->argnumber = -1; /* until determined */ + na->location = @1; + $$ = (Node *) na; + } + | a_expr tsql_opt_output + { + $$ = $1; /* FIXME: record $2 somewhere - probably need a new Node type */ + } + ; + +tsql_without_login: WITHOUT TSQL_LOGIN { $$ = true; } + ; + +tsql_constraint_check: + CHECK + | TSQL_NOCHECK + ; + +tsql_opt_constraint_name: + CONSTRAINT name + | /* EMPTY */ + ; + +/* + * Computed columns uses b_expr not a_expr to avoid conflict with general NOT + * (used in constraints). Besides, it seems TSQL doesn't allow AND, NOT, IS + * IN clauses in the computed column expression. So, there shouldn't be + * any issues. + */ +TSQL_computed_column: + AS b_expr + { + Constraint *n = makeNode(Constraint); + + n->contype = CONSTR_GENERATED; + n->generated_when = ATTRIBUTE_IDENTITY_ALWAYS; + n->raw_expr = $2; + n->cooked_expr = NULL; + n->location = @1; + + $$ = (Node *)n; + } + | AS b_expr TSQL_PERSISTED + { + Constraint *n = makeNode(Constraint); + + n->contype = CONSTR_GENERATED; + n->generated_when = ATTRIBUTE_IDENTITY_ALWAYS; + n->raw_expr = $2; + n->cooked_expr = NULL; + n->location = @1; + + $$ = (Node *)n; + } + ; + +columnElemWithOptAscDesc: + columnElem ASC + { + IndexElem * n = makeNode(IndexElem); + + if (sql_dialect != SQL_DIALECT_TSQL) + ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("This syntax is only valid when babelfishpg_tsql.sql_dialect is TSQL"), parser_errposition(@1))); + + n->name = strVal($1); + n->expr = NULL; + n->indexcolname = NULL; + n->collation = NULL; + n->opclass = NULL; + n->ordering = SORTBY_ASC; + n->nulls_ordering = SORTBY_NULLS_DEFAULT; + + $$ = (Node *)n; + } + | columnElem DESC + { + IndexElem * n = makeNode(IndexElem); + + if (sql_dialect != SQL_DIALECT_TSQL) + ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("This syntax is only valid when babelfishpg_tsql.sql_dialect is TSQL"), parser_errposition(@1))); + + n->name = strVal($1); + n->expr = NULL; + n->indexcolname = NULL; + n->collation = NULL; + n->opclass = NULL; + n->ordering = SORTBY_DESC; + n->nulls_ordering = SORTBY_NULLS_DEFAULT; + + $$ = (Node *)n; + } + ; + +columnListWithOptAscDesc: + columnElemWithOptAscDesc + { + $$ = list_make1($1); + } + | columnListWithOptAscDesc ',' columnElem + { + $$ = lappend($1, $3); + } + | columnListWithOptAscDesc ',' columnElemWithOptAscDesc + { + $$ = lappend($1, $3); + } + | columnList ',' columnElemWithOptAscDesc + { + $$ = lappend($1, $3); + } + ; + +/* + * NOTE: the OptFileGroup production doesn't really belong here. We accept OptFileGroup + * for TSQL compatibility, but that syntax is used to place a table on + * a filegroup (analogous to a tablespace). For now, we just accept the + * filegroup specification and ignore it. This makes it impossible to + * write an ON COMMIT option and an ON filegroup clause in the same + * statement, but that would be illegal syntax anyway. + */ + +OptFileGroup: ON name {} + | TSQL_TEXTIMAGE_ON name + { + TSQLInstrumentation(INSTR_UNSUPPORTED_TSQL_TEXTIMAGE_ON); + } + ; + +tsql_OptParenthesizedIdentList: + '(' tsql_IdentList ')' { $$ = $2; } + | /*EMPTY*/ { $$ = NIL; } + ; + +tsql_IdentList: + NumericOnly ',' opt_plus Iconst + { + $$ = list_make3(makeDefElem("start", (Node *)$1, @1), + makeDefElem("increment", (Node *)makeInteger($4), @1), + makeDefElem("minvalue", (Node *)$1, @1)); + } + | NumericOnly ',' '-' Iconst + { + $$ = list_make3(makeDefElem("start", (Node *)$1, @1), + makeDefElem("increment", (Node *)makeInteger(- $4), @1), + makeDefElem("maxvalue", (Node *)$1, @1)); + } + ; + +opt_plus: + '+' {} + | /* empty */ {} + ; + +/* + * FOR XML clause can have 4 modes: RAW, AUTO, PATH and EXPLICIT. + * Map the mode to the corresponding ENUM. + */ +tsql_for_clause: + TSQL_FOR XML_P TSQL_RAW '(' Sconst ')' tsql_xml_common_directives + { + TSQL_ForClause *n = (TSQL_ForClause *) palloc(sizeof(TSQL_ForClause)); + n->location = @1; + n->mode = TSQL_FORXML_RAW; + n->elementName = $5; + n->commonDirectives = $7; + $$ = (Node *) n; + } + | TSQL_FOR XML_P TSQL_RAW tsql_xml_common_directives + { + TSQL_ForClause *n = (TSQL_ForClause *) palloc(sizeof(TSQL_ForClause)); + n->mode = TSQL_FORXML_RAW; + n->elementName = NULL; + n->commonDirectives = $4; + n->location = @1; + $$ = (Node *) n; + } + | TSQL_FOR XML_P TSQL_AUTO tsql_xml_common_directives + { + TSQL_ForClause *n = (TSQL_ForClause *) palloc(sizeof(TSQL_ForClause)); + TSQLInstrumentation(INSTR_UNSUPPORTED_TSQL_XML_OPTION_AUTO); + n->mode = TSQL_FORXML_AUTO; + n->elementName = NULL; + n->commonDirectives = $4; + n->location = @1; + $$ = (Node *) n; + } + | TSQL_FOR XML_P TSQL_PATH '(' Sconst ')' tsql_xml_common_directives + { + TSQL_ForClause *n = (TSQL_ForClause *) palloc(sizeof(TSQL_ForClause)); + n->mode = TSQL_FORXML_PATH; + n->elementName = $5; + n->commonDirectives = $7; + n->location = @1; + $$ = (Node *) n; + } + | TSQL_FOR XML_P TSQL_PATH tsql_xml_common_directives + { + TSQL_ForClause *n = (TSQL_ForClause *) palloc(sizeof(TSQL_ForClause)); + n->mode = TSQL_FORXML_PATH; + n->elementName = NULL; + n->commonDirectives = $4; + n->location = @1; + $$ = (Node *) n; + } + | TSQL_FOR XML_P TSQL_EXPLICIT tsql_xml_common_directives + { + TSQL_ForClause *n = (TSQL_ForClause *) palloc(sizeof(TSQL_ForClause)); + TSQLInstrumentation(INSTR_UNSUPPORTED_TSQL_XML_OPTION_EXPLICIT); + n->mode = TSQL_FORXML_EXPLICIT; + n->elementName = NULL; + n->commonDirectives = $4; + n->location = @1; + $$ = (Node *) n; + } + ; + +tsql_alter_server_role: + ALTER TSQL_SERVER ROLE ColId ADD_P TSQL_MEMBER RoleSpec + { + GrantRoleStmt *n = makeNode(GrantRoleStmt); + AccessPriv *ap = makeNode(AccessPriv); + + if (0 != strcmp($4, "sysadmin")) + ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("only sysadmin role is supported in ALTER SERVER ROLE statement"), + parser_errposition(@4))); + + ap->priv_name = $4; + n->is_grant = true; + n->granted_roles = list_make1(ap); + n->grantee_roles = list_make1($7); + n->admin_opt = false; + n->grantor = NULL; + $$ = (Node *) n; + } + | ALTER TSQL_SERVER ROLE ColId DROP TSQL_MEMBER RoleSpec + { + GrantRoleStmt *n = makeNode(GrantRoleStmt); + AccessPriv *ap = makeNode(AccessPriv); + + if (0 != strcmp($4, "sysadmin")) + ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("only sysadmin role is supported in ALTER SERVER ROLE statement"), + parser_errposition(@4))); + + ap->priv_name = $4; + n->is_grant = false; + n->granted_roles = list_make1(ap); + n->grantee_roles = list_make1($7); + n->admin_opt = false; + n->grantor = NULL; + $$ = (Node *) n; + } + +tsql_xml_common_directives: + tsql_xml_common_directives ',' tsql_xml_common_directive + { + $$ = lappend($1, $3); + } + | /*EMPTY*/ { $$ = NIL; } + ; + +/* + * FOR XML clause can have 3 directives: BINARY BASE64, TYPE and ROOT. + * Map them to ENUM TSQLXMLDirective and String of the ROOT name respectively. + */ +tsql_xml_common_directive: + BINARY TSQL_BASE64 { $$ = makeIntConst(TSQL_XML_DIRECTIVE_BINARY_BASE64, -1); } + | TYPE_P { $$ = makeIntConst(TSQL_XML_DIRECTIVE_TYPE, -1); } + | TSQL_ROOT { $$ = makeStringConst("root", -1); } + | TSQL_ROOT '(' Sconst ')' { $$ = makeStringConst($3, -1); } + ; + + +/* Create Function and Create Trigger in one statement */ +tsql_CreateTrigStmt: + CREATE TRIGGER tsql_triggername ON qualified_name + tsql_TriggerActionTime tsql_TriggerEvents tsql_opt_not_for_replication + AS tokens_remaining + { + CreateTrigStmt *n1 = makeNode(CreateTrigStmt); + CreateFunctionStmt *n2 = makeNode(CreateFunctionStmt); + TriggerTransition *nt_inserted = NULL; + TriggerTransition *nt_deleted = NULL; + DefElem *lang = makeDefElem("language", (Node *) makeString("pltsql"), @1); + DefElem *body = makeDefElem("as", (Node *) list_make1(makeString($10)), @10); + DefElem *trigStmt = makeDefElem("trigStmt", (Node *) n1, @1); + + n1->trigname = ((Value *)list_nth($3,0))->val.str; + n1->relation = $5; + /* + * Function with the same name as the + * trigger will be created as part of + * this create trigger command. + */ + n1->funcname = list_make1(makeString(n1->trigname)); + if (list_length($3) > 1){ + n1->trigname = ((Value *)list_nth($3,1))->val.str; + /* + * Used a hack way to pass the schema name from args, in CR-58614287 + * Args will be set back to NIL in pl_handler pltsql_pre_parse_analyze() + * before calling backend functios + */ + n1->args = list_make1(makeString(((Value *)list_nth($3,0))->val.str)); + }else{ + n1->args = NIL; + } + /* TSQL only support statement level triggers as part of the + * syntax, n1->row is false for AFTER, BEFORE and INSTEAD OF + * triggers. + */ + n1->row = false; + n1->timing = $6; + n1->events = intVal(linitial($7)); + n1->columns = NIL; + n1->whenClause = NULL; + n1->isconstraint = false; + n1->deferrable = false; + n1->initdeferred = false; + n1->constrrel = NULL; + n1->transitionRels = NIL; + + if((n1->events & TRIGGER_TYPE_INSERT) == TRIGGER_TYPE_INSERT || + (n1->events & TRIGGER_TYPE_UPDATE) == TRIGGER_TYPE_UPDATE) + { + nt_inserted = makeNode(TriggerTransition); + nt_inserted->name = "inserted"; + nt_inserted->isNew = true; + nt_inserted->isTable = true; + n1->transitionRels = lappend(n1->transitionRels, nt_inserted); + } + if((n1->events & TRIGGER_TYPE_DELETE) == TRIGGER_TYPE_DELETE || + (n1->events & TRIGGER_TYPE_UPDATE) == TRIGGER_TYPE_UPDATE) + { + nt_deleted = makeNode(TriggerTransition); + nt_deleted->name = "deleted"; + nt_deleted->isNew = false; + nt_deleted->isTable = true; + n1->transitionRels = lappend(n1->transitionRels, nt_deleted); + } + + n2->is_procedure = false; + n2->replace = true; + n2->funcname = list_make1(makeString(n1->trigname));; + n2->parameters = NIL; + n2->returnType = makeTypeName("trigger"); + n2->options = list_make3(lang, body, trigStmt); + + $$ = (Node *) n2; + } + ; + + tsql_triggername: + ColId { $$ = list_make1(makeString($1)); }; + | ColId '.' ColId { $$ = list_make2(makeString($1),makeString($3)); }; + +tsql_TriggerActionTime: + TriggerActionTime + | FOR { $$ = TRIGGER_TYPE_AFTER; } + ; + +/* + * Support ',' separator in tsql_TriggerEvents + */ +tsql_TriggerEvents: + tsql_TriggerOneEvent + { $$ = $1; } + | tsql_TriggerEvents ',' tsql_TriggerOneEvent + { + int events1 = intVal(linitial($1)); + int events2 = intVal(linitial($3)); + List *columns1 = (List *) lsecond($1); + List *columns2 = (List *) lsecond($3); + + if (events1 & events2) + parser_yyerror("duplicate trigger events specified"); + /* + * concat'ing the columns lists loses information about + * which columns went with which event, but so long as + * only UPDATE carries columns and we disallow multiple + * UPDATE items, it doesn't matter. Command execution + * should just ignore the columns for non-UPDATE events. + */ + $$ = list_make2(makeInteger(events1 | events2), + list_concat(columns1, columns2)); + } + ; + +tsql_TriggerOneEvent: + INSERT + { $$ = list_make2(makeInteger(TRIGGER_TYPE_INSERT), NIL); } + | DELETE_P + { $$ = list_make2(makeInteger(TRIGGER_TYPE_DELETE), NIL); } + | UPDATE + { $$ = list_make2(makeInteger(TRIGGER_TYPE_UPDATE), NIL); } + | TRUNCATE + { $$ = list_make2(makeInteger(TRIGGER_TYPE_TRUNCATE), NIL); } + ; + +/* + * NOTE: Only supporting the syntax for now + */ +tsql_opt_not_for_replication: + NOT FOR TSQL_REPLICATION {} + | /*EMPTY*/ {} + ; + +opt_from: FROM {} + | /* EMPTY */ {} + ; + +tsql_IndexStmt: + CREATE opt_unique tsql_opt_cluster tsql_opt_columnstore + INDEX opt_concurrently opt_index_name + ON relation_expr access_method_clause '(' index_params ')' + opt_include where_clause opt_reloptions + tsql_opt_on_filegroup + { + IndexStmt *n = makeNode(IndexStmt); + n->unique = $2; + n->concurrent = $6; + n->idxname = $7; + n->relation = $9; + n->accessMethod = $10; + n->indexParams = $12; + n->indexIncludingParams = $14; + n->whereClause = $15; + n->options = $16; + n->excludeOpNames = NIL; + n->idxcomment = NULL; + n->indexOid = InvalidOid; + n->oldNode = InvalidOid; + n->primary = false; + n->isconstraint = false; + n->deferrable = false; + n->initdeferred = false; + n->transformed = false; + n->if_not_exists = false; + $$ = (Node *)n; + } + ; + +tsql_cluster: + TSQL_CLUSTERED + { + TSQLInstrumentation(INSTR_TSQL_OPTION_CLUSTERED); + $$ = true; + } + | TSQL_NONCLUSTERED + { + TSQLInstrumentation(INSTR_TSQL_OPTION_NON_CLUSTERED); + $$ = false; + } + ; + +tsql_opt_cluster: + tsql_cluster { $$ = $1; } + | /*EMPTY*/ { $$ = false; } + ; + +tsql_opt_columnstore: + TSQL_COLUMNSTORE + { + ereport(NOTICE, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("The COLUMNSTORE option is currently ignored"))); + } + | /*EMPTY*/ + ; + +/* + * NOTE: Only supporting the syntax for now + */ +tsql_on_filegroup: ON name {} + ; + +tsql_opt_on_filegroup: + tsql_on_filegroup {} + | /*EMPTY*/ {} + ; + +/* + * TSQL support for DATA_COMPRESSION in and : + * DATA_COMPRESSION = {NONE | ROW | PAGE} [ON PARTITIONS ( [,...n])] + * eg. ON PARTITIONS (2), ON PARTITIONS (1, 5), ON PARTITIONS (2, 4, 6 TO 8) + */ +tsql_on_ident_partitions_list: + ON IDENT '(' tsql_on_partitions_list ')' + { + if (sql_dialect != SQL_DIALECT_TSQL) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("This syntax is only valid when babelfishpg_tsql.sql_dialect is TSQL"), + parser_errposition(@1))); + } + ; + +tsql_opt_on_partitions_list: + tsql_on_ident_partitions_list {} + | /*EMPTY*/ {} + ; + +tsql_on_partitions_list: + tsql_on_partitions {} + | tsql_on_partitions_list ',' tsql_on_partitions {} + ; + +tsql_on_partitions: + Iconst {} + | Iconst TO Iconst {} + ; + +/* + * TSQL support for options in : + * SYSTEM_VERSIONING, REMOTE_DATA_ARCHIVE, DATA_DELETION + */ +tsql_paren_extra_relopt_list: + '(' tsql_extra_relopt_list ')' + { + if (sql_dialect != SQL_DIALECT_TSQL) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("This syntax is only valid when babelfishpg_tsql.sql_dialect is TSQL"), + parser_errposition(@1))); + } + ; + +tsql_extra_relopt_list: + tsql_extra_relopt {} + | tsql_extra_relopt_list ',' tsql_extra_relopt {} + ; + +tsql_extra_relopt: + IDENT '=' tsql_extra_def_arg {} + ; + +tsql_extra_def_arg: + ColId {} + | ON {} + | NULL_P {} + | NumericOnly datepart_arg {} + | IDENT '.' IDENT {} + ; + +/* + * TSQL support for MAX_DURATION option in : + * MAX_DURATION = t2_a1t2_a22t2_a1t2_a23t2_a1t2_a2 +~~END~~ + + +-- Test 2 levels of for xml nesting, without TYPE option, expect special character escaping +select id, (select a from t2 for xml path) as col from t1 for xml path; +go +~~START~~ +ntext +1<row><a>t2_a1</a></row><row><a>t2_a2</a></row><row/>2<row><a>t2_a1</a></row><row><a>t2_a2</a></row><row/>3<row><a>t2_a1</a></row><row><a>t2_a2</a></row><row/> +~~END~~ + + +-- Test 3 levels of for xml nesting with TYPE option +select id, (select id, (select a from t2 for xml path, type) as col1 from t1 for xml path, type) as col2 from t1 for xml path, type; +go +~~START~~ +xml +11t2_a1t2_a22t2_a1t2_a23t2_a1t2_a221t2_a1t2_a22t2_a1t2_a23t2_a1t2_a231t2_a1t2_a22t2_a1t2_a23t2_a1t2_a2 +~~END~~ + + +-- Test simple for xml path in procedure +create table employees( +pers_id int, +fname nvarchar(20), +lname nvarchar(20), +sal money); +insert into employees values (1, 'John', 'Johnson', 123.1234); +insert into employees values (2, 'Max', 'Welch', 200.1234); +go +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +create procedure p_employee_select as +begin + select * from employees for xml path; +end; +go + +execute p_employee_select; +go +~~START~~ +ntext +1JohnJohnson123.12342MaxWelch200.1234 +~~END~~ + +drop procedure p_employee_select; +go + +-- Test for xml in procedure with parameters +create procedure p_employee_select @minsal MONEY, @maxsal MONEY as +begin + select * from employees where sal > @minsal and sal < @maxsal + for xml path('Employee'); +end; +go + +execute p_employee_select 150, 300; +go +~~START~~ +ntext +2MaxWelch200.1234 +~~END~~ + + +-- Test for xml in create view +create view v1 (col1) as select * from t1 for xml raw, type; +go + +select * from v1; +go +~~START~~ +xml + +~~END~~ + + +-- Test for xml on view with xml column +select * from v1 for xml path; +go +~~START~~ +ntext + +~~END~~ + + +-- Test for xml on pure relational view +create view v2 (col1, col2) as select * from t1; +go + +select * from v2 for xml path; +go +~~START~~ +ntext +1t1_a12t1_a23 +~~END~~ + + +drop view v1, v2; +go + +-- Test for xml and union all +select a from t1 UNION ALL select a from t2 for xml raw ('myrow'); +go +~~START~~ +ntext + +~~END~~ + + +-- Test invalid syntax when FOR XML is on both sides of UNION ALL, this is SQL Server behavior +select a from t1 for xml raw ('t1') UNION ALL select a from t2 for xml raw ('t2'); +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error near 'UNION' at line 2 and character position 36)~~ + + +-- For xml can access CTE from same query block +with cte as (select a from t1) +select * from cte for xml raw; +go +~~START~~ +ntext + +~~END~~ + + +-- BABEL-1202: For xml subquery can't access CTE from outer query block +with cte as (select a from t1) +select * from t2, (select * from cte for xml raw) as t3(colxml); +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "cte" does not exist)~~ + + +with cte as (select a from t1) +select (select * from cte for xml raw) as colxml, * from t2; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "cte" does not exist)~~ + + +with +cte1 as (select * from t1), +cte2 as (select a from cte1 for xml raw) +select * from cte2; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "cte1" does not exist)~~ + + + +-- Test for xml and recursive CTE +CREATE TABLE employees2 ( + id serial, + name varchar(255), + manager_id int +); +INSERT INTO employees2 VALUES (1, 'Mark', null); +INSERT INTO employees2 VALUES (2, 'John', 1); +INSERT INTO employees2 VALUES (3, 'Dan', 2); +INSERT INTO employees2 VALUES (4, 'Clark', 1); +INSERT INTO employees2 VALUES (5, 'Linda', 2); +INSERT INTO employees2 VALUES (6, 'Willy', 2); +INSERT INTO employees2 VALUES (7, 'Barack', 2); +INSERT INTO employees2 VALUES (8, 'Elen', 2); +INSERT INTO employees2 VALUES (9, 'Kate', 3); +INSERT INTO employees2 VALUES (10, 'Terry', 4); +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~~ + + +WITH managertree AS ( + SELECT id, name, manager_id + FROM employees2 + WHERE id = 2 + UNION ALL + SELECT e.id, e.name, e.manager_id + FROM employees2 e + INNER JOIN managertree mtree ON mtree.id = e.manager_id +) +SELECT * +FROM managertree mt; +GO +~~START~~ +int#!#varchar#!#int +2#!#John#!#1 +3#!#Dan#!#2 +5#!#Linda#!#2 +6#!#Willy#!#2 +7#!#Barack#!#2 +8#!#Elen#!#2 +9#!#Kate#!#3 +~~END~~ + + +WITH managertree AS ( + SELECT id, name, manager_id + FROM employees2 + WHERE id = 2 + UNION ALL + SELECT e.id, e.name, e.manager_id + FROM employees2 e + INNER JOIN managertree mtree ON mtree.id = e.manager_id +) +SELECT * +FROM managertree mt WHERE mt.name = 'Linda' FOR XML RAW ('managertree'); +GO +~~START~~ +ntext + +~~END~~ + + +-- BABEL-1178, data type of variable is lost during variable binding in FORMAT +-- function +create procedure test_forxml @pid int as +declare @a int, @b smallint; +set @a = 1; +set @b = 1; +select a, datalength(@a), datalength(@b) from t1 where id = @pid for xml raw; +go + +-- datalength(@b) should be 2. But the data type of @b is lost during the +-- query transformation for FOR XML, so we end up getting a wrong length. +exec test_forxml 1; +go +~~START~~ +ntext + +~~END~~ + + +-- test string variable can be binded with for xml query +create procedure test_forxml_strvar @pid int, @str varchar(10) as +select * from t1 where id = @pid and a = @str for xml raw; +go +exec test_forxml_strvar 1, 't1_a1'; +go +~~START~~ +ntext + +~~END~~ + +-- test NULL parameter +exec test_forxml_strvar 1, NULL; +go +~~START~~ +ntext + +~~END~~ + + +-- clean up +drop table t1; +drop table t2; +drop table MyTable; +drop table employees; +drop procedure p_employee_select; +drop table employees2; +drop procedure test_forxml; +drop procedure test_forxml_strvar; +go diff --git a/contrib/test/JDBC/expected/TestInt.out b/contrib/test/JDBC/expected/TestInt.out new file mode 100644 index 00000000000..8a0c9319a57 --- /dev/null +++ b/contrib/test/JDBC/expected/TestInt.out @@ -0,0 +1,111 @@ +CREATE TABLE INT_dt(a INT); +prepst#!#INSERT INTO INT_dt(a) values(?) #!#INT|-|a|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#INT|-|a|-|-10 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#INT|-|a|-|10 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#INT|-|a|-|-12234 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#INT|-|a|-|22 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#INT|-|a|-|003 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#INT|-|a|-|9864 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#INT|-|a|-|-01625 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#INT|-|a|-|-2147483648 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#INT|-|a|-|2147483647 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#INT|-|a|-| +~~ROW COUNT: 1~~ + + +SELECT * FROM INT_dt; +~~START~~ +int +0 +-10 +10 +-12234 +22 +3 +9864 +-1625 +-2147483648 +2147483647 + +~~END~~ + + +INSERT INTO INT_dt(a) values(0) +~~ROW COUNT: 1~~ + +INSERT INTO INT_dt(a) values(-10) +~~ROW COUNT: 1~~ + +INSERT INTO INT_dt(a) values(10) +~~ROW COUNT: 1~~ + +INSERT INTO INT_dt(a) values(-12345) +~~ROW COUNT: 1~~ + +INSERT INTO INT_dt(a) values(22) +~~ROW COUNT: 1~~ + +INSERT INTO INT_dt(a) values(004) +~~ROW COUNT: 1~~ + +INSERT INTO INT_dt(a) values(-01645) +~~ROW COUNT: 1~~ + +INSERT INTO INT_dt(a) values(-2147483648) +~~ROW COUNT: 1~~ + +INSERT INTO INT_dt(a) values(2147483647) +~~ROW COUNT: 1~~ + +INSERT INTO INT_dt(a) values(NULL) +~~ROW COUNT: 1~~ + + +SELECT * FROM INT_dt; +~~START~~ +int +0 +-10 +10 +-12234 +22 +3 +9864 +-1625 +-2147483648 +2147483647 + +0 +-10 +10 +-12345 +22 +4 +-1645 +-2147483648 +2147483647 + +~~END~~ + + +DROP TABLE INT_dt; diff --git a/contrib/test/JDBC/expected/TestInteropProcedures.out b/contrib/test/JDBC/expected/TestInteropProcedures.out new file mode 100644 index 00000000000..1bfa54f1806 --- /dev/null +++ b/contrib/test/JDBC/expected/TestInteropProcedures.out @@ -0,0 +1,220 @@ +-- tsql +CREATE PROCEDURE tsql_interop_proc1 +AS +UPDATE procTab1 SET c1=10 where c2='b'; +INSERT INTO procTab1 values(1,'a'); +INSERT INTO procTab1 values(2,'b'); +EXEC psql_interop_proc2; +GO + +-- psql currentSchema=master_dbo,public +CREATE PROCEDURE psql_interop_proc1() +AS +$$ +BEGIN + CREATE TABLE procTab1(c1 int); + INSERT INTO procTab1 values (5); + ALTER TABLE procTab1 ADD c2 char; + CALL tsql_interop_proc1(); +END +$$ LANGUAGE PLPGSQL; +GO + +CREATE PROCEDURE psql_interop_proc2() +AS +$$ +BEGIN + INSERT INTO procTab1(c1,c2) values (3,'c'); + UPDATE procTab1 SET c1=10 where c2='b'; + INSERT INTO procTab1(c1,c2) values (4,'d'); + DELETE FROM procTab1 where c2='a'; +END +$$ LANGUAGE PLPGSQL; +GO + +-- tsql +EXEC psql_interop_proc1 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +SELECT * FROM procTab1 order by c1 +GO +~~START~~ +int#!#char +3#!#c +4#!#d +5#!# +10#!#b +~~END~~ + + +-- psql currentSchema=master_dbo,public +CALL tsql_interop_proc1() +GO +SELECT DISTINCT c1 FROM procTab1 +GO +~~START~~ +int4 +3 +5 +4 +10 +~~END~~ + + +-- tsql +DROP TABLE procTab1 +GO +DROP PROCEDURE tsql_interop_proc1 +GO + +-- tsql +CREATE PROCEDURE tsql_interop_proc1 +AS +DECLARE @SQLString NVARCHAR(100); +SET @SQLString = N'ALTER TABLE procTab1 ALTER COLUMN c2 varchar(10);'; +EXEC sp_executesql @SQLString; +INSERT INTO procTab1(c1,c2) values(11,'abc'); +UPDATE procTab1 SET c1=c1+1 WHERE c2 IS NULL OR c2='a'; +EXEC psql_interop_proc3; +GO + +-- psql currentSchema=master_dbo,public +CREATE PROCEDURE psql_interop_proc3() +AS +$$ +DECLARE myvar varchar(10) = 'def'; +BEGIN +UPDATE procTab1 SET c2=myvar WHERE c1 BETWEEN 2 AND 10; +INSERT INTO procTab1(c1,c2) values(12,'xyz'); +END +$$ LANGUAGE PLPGSQL; +GO + +-- tsql +EXEC psql_interop_proc1 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +SELECT * FROM procTab1 WHERE c2 LIKE 'a%' +GO +~~START~~ +int#!#varchar +11#!#abc +~~END~~ + +DROP TABLE procTab1 +GO + +-- tsql +CREATE PROCEDURE tsql_interop_proc +AS +DECLARE @handle int; +EXEC SP_PREPARE @handle OUT, NULL, 'SELECT ''OK''' +EXEC SP_EXECUTE @handle +EXEC SP_UNPREPARE @handle +GO + +-- psql currentSchema=master_dbo,public +CREATE PROCEDURE psql_interop_proc() +AS +$$ +BEGIN +CALL tsql_interop_proc(); +END +$$ LANGUAGE PLPGSQL; +GO + +-- tsql +EXEC psql_interop_proc; +GO +~~START~~ +varchar +~~END~~ + +~~START~~ +varchar +OK +~~END~~ + +DROP PROCEDURE tsql_interop_proc +GO + +-- tsql +CREATE PROCEDURE tsql_interop_proc +AS +CREATE TABLE cursorTab(a INT, b SMALLINT, c BIGINT, d TINYINT, e BIT); +INSERT INTO cursorTab values(0, 0, 0, 0, 0); +INSERT INTO cursorTab values(1, 2, 3, 4, 1); +DECLARE @cursor_handle int; +EXEC sp_cursoropen @cursor_handle OUTPUT, 'select a,b,c,d from cursorTab', 2, 1; +EXEC sp_cursorfetch @cursor_handle, 2, 0, 2; +EXEC sp_cursoroption @cursor_handle, 1, 2; +EXEC sp_cursor @cursor_handle, 40, 1, ''; +EXEC sp_cursorclose @cursor_handle; +GO + +EXEC psql_interop_proc; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#smallint#!#bigint#!#tinyint +0#!#0#!#0#!#0 +1#!#2#!#3#!#4 +~~END~~ + +~~START~~ +int#!#smallint#!#bigint#!#tinyint +0#!#0#!#0#!#0 +1#!#2#!#3#!#4 +~~END~~ + +DROP TABLE cursorTab +GO +DROP PROCEDURE tsql_interop_proc +GO + +-- tsql +CREATE PROCEDURE tsql_interop_proc +AS +BEGIN TRY + SELECT 1/0; +END TRY +BEGIN CATCH + SELECT 1; +END CATCH +GO + +-- tsql +EXEC psql_interop_proc +GO +~~START~~ +int +1 +~~END~~ + +DROP PROCEDURE tsql_interop_proc +GO + +-- psql currentSchema=master_dbo,public +DROP PROCEDURE psql_interop_proc1 +GO +DROP PROCEDURE psql_interop_proc2 +GO +DROP PROCEDURE psql_interop_proc3 +GO + +-- tsql +DROP PROCEDURE tsql_interop_proc1 +GO + +-- psql currentSchema=master_dbo,public +DROP PROCEDURE psql_interop_proc +GO diff --git a/contrib/test/JDBC/expected/TestIsolationLevels.out b/contrib/test/JDBC/expected/TestIsolationLevels.out new file mode 100644 index 00000000000..0d5e21740cb --- /dev/null +++ b/contrib/test/JDBC/expected/TestIsolationLevels.out @@ -0,0 +1,104 @@ +set transaction isolation level read uncommitted; +go + +set transaction isolation level read committed; +go + +set transaction isolation level repeatable read; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: REPEATABLE READ isolation level is not supported)~~ + + +set transaction isolation level snapshot; +go + +set transaction isolation level serializable; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: SERIALIZABLE isolation level is not supported)~~ + + +select set_config('default_transaction_isolation', 'read uncommitted', false); +go +~~START~~ +text +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: set_config not allowed for option default_transaction_isolation)~~ + +select set_config('default_transaction_isolation', 'read committed', false); +go +~~START~~ +text +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: set_config not allowed for option default_transaction_isolation)~~ + +select set_config('default_transaction_isolation', 'repeatable read', false); +go +~~START~~ +text +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: set_config not allowed for option default_transaction_isolation)~~ + +select set_config('default_transaction_isolation', 'snapshot', false); +go +~~START~~ +text +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: set_config not allowed for option default_transaction_isolation)~~ + +select set_config('default_transaction_isolation', 'serializable', false); +go +~~START~~ +text +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: set_config not allowed for option default_transaction_isolation)~~ + + +select set_config('transaction_isolation', 'read uncommitted', false); +go +~~START~~ +text +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: set_config not allowed for option transaction_isolation)~~ + +select set_config('transaction_isolation', 'read committed', false); +go +~~START~~ +text +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: set_config not allowed for option transaction_isolation)~~ + +select set_config('transaction_isolation', 'repeatable read', false); +go +~~START~~ +text +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: set_config not allowed for option transaction_isolation)~~ + +select set_config('transaction_isolation', 'snapshot', false); +go +~~START~~ +text +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: set_config not allowed for option transaction_isolation)~~ + +select set_config('transaction_isolation', 'serializable', false); +go +~~START~~ +text +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: set_config not allowed for option transaction_isolation)~~ + diff --git a/contrib/test/JDBC/expected/TestMoney.out b/contrib/test/JDBC/expected/TestMoney.out new file mode 100644 index 00000000000..39e3cb83337 --- /dev/null +++ b/contrib/test/JDBC/expected/TestMoney.out @@ -0,0 +1,111 @@ +CREATE TABLE money_dt(a smallmoney, b money); + +prepst#!#INSERT INTO money_dt(a, b) VALUES (?, ?) #!#smallmoney|-|a|-|100.5#!#money|-|b|-|10.05 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#smallmoney|-|a|-|10#!#money|-|b|-|10 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#smallmoney|-|a|-|-10.05 #!#money|-|b|-|-10.0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#smallmoney|-|a|-|-214748.3648#!#money|-|b|-|-922337203685477.5808 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#smallmoney|-|a|-|214748.3647#!#money|-|b|-|22337203685477.5807 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#smallmoney|-|a|-|214748.3647#!#money|-|b|-|22337203685477.5807 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#smallmoney|-|a|-|-214,748.3648#!#money|-|b|-|-922,337,203,685,477.5808 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#smallmoney|-|a|-|214,748.3647#!#money|-|b|-|922,337,203,685,477.5807 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#smallmoney|-|a|-|214,748.3647#!#money|-|b|-|922,337,203,685,477.5807 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#smallmoney|-|a|-|#!#money|-|b|-| +~~ROW COUNT: 1~~ + + +SELECT * FROM money_dt; +~~START~~ +smallmoney#!#money +100.5000#!#10.0500 +10.0000#!#10.0000 +-10.0500#!#-10.0000 +-214748.3648#!#-922337203685477.5808 +214748.3647#!#22337203685477.5807 +214748.3647#!#22337203685477.5807 +-214748.3648#!#-922337203685477.5808 +214748.3647#!#922337203685477.5807 +214748.3647#!#922337203685477.5807 +#!# +~~END~~ + + +INSERT INTO money_dt(a,b) values(100.5,10.05); +~~ROW COUNT: 1~~ + +INSERT INTO money_dt(a,b) values('$10','$10'); +~~ROW COUNT: 1~~ + +INSERT INTO money_dt(a,b) values('-10.05','-10.0'); +~~ROW COUNT: 1~~ + +INSERT INTO money_dt(a,b) values('10.05','10.0'); +~~ROW COUNT: 1~~ + +INSERT INTO money_dt(a,b) values(-214748.3648,'-10.0'); +~~ROW COUNT: 1~~ + +INSERT INTO money_dt(a,b) values(14748.3647,-922337203685477.5808); +~~ROW COUNT: 1~~ + +INSERT INTO money_dt(a,b) values('$214748.3647','$22337203685477.5807'); +~~ROW COUNT: 1~~ + +INSERT INTO money_dt(a,b) values('-214,748.3648','-922,337,203,685,477.5808'); +~~ROW COUNT: 1~~ + +INSERT INTO money_dt(a,b) values('214,748.3647','922,337,203,685,477.5807'); +~~ROW COUNT: 1~~ + +INSERT INTO money_dt(a,b) values('$214,748.3647','$922,337,203,685,477.5807'); +~~ROW COUNT: 1~~ + +INSERT INTO money_dt(a,b) values(NULL,NULL); +~~ROW COUNT: 1~~ + + + +SELECT * FROM money_dt; +~~START~~ +smallmoney#!#money +100.5000#!#10.0500 +10.0000#!#10.0000 +-10.0500#!#-10.0000 +-214748.3648#!#-922337203685477.5808 +214748.3647#!#22337203685477.5807 +214748.3647#!#22337203685477.5807 +-214748.3648#!#-922337203685477.5808 +214748.3647#!#922337203685477.5807 +214748.3647#!#922337203685477.5807 +#!# +100.5000#!#10.0500 +10.0000#!#10.0000 +-10.0500#!#-10.0000 +10.0500#!#10.0000 +-214748.3648#!#-10.0000 +14748.3647#!#-922337203685477.5808 +214748.3647#!#22337203685477.5807 +-214748.3648#!#-922337203685477.5808 +214748.3647#!#922337203685477.5807 +214748.3647#!#922337203685477.5807 +#!# +~~END~~ + +DROP TABLE money_dt; diff --git a/contrib/test/JDBC/expected/TestNotNull.out b/contrib/test/JDBC/expected/TestNotNull.out new file mode 100644 index 00000000000..0a678ff6da5 --- /dev/null +++ b/contrib/test/JDBC/expected/TestNotNull.out @@ -0,0 +1,832 @@ +# int +Create table sourceTable(a int, b int not null) +prepst#!# INSERT INTO sourceTable(a, b) values(?, ?) #!#int|-|a|-|2#!#int|-|b|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#int|-|a|-|#!#int|-|b|-|3 +~~ROW COUNT: 1~~ + +Select * from sourceTable +~~START~~ +int#!#int +2#!#2 +#!#3 +~~END~~ + +Insert into sourceTable values (1, 1); +~~ROW COUNT: 1~~ + +Insert into sourceTable values (NULL, 1); +~~ROW COUNT: 1~~ + +Select * from sourceTable +~~START~~ +int#!#int +2#!#2 +#!#3 +1#!#1 +#!#1 +~~END~~ + +drop table sourceTable + +# smallint +Create table sourceTable(a smallint, b smallint not null) +prepst#!# INSERT INTO sourceTable(a, b) values(?, ?) #!#smallint|-|a|-|2#!#smallint|-|b|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#smallint|-|a|-|#!#smallint|-|b|-|3 +~~ROW COUNT: 1~~ + +Select * from sourceTable +~~START~~ +smallint#!#smallint +2#!#2 +#!#3 +~~END~~ + +Insert into sourceTable values (1, 1); +~~ROW COUNT: 1~~ + +Insert into sourceTable values (NULL, 1); +~~ROW COUNT: 1~~ + +Select * from sourceTable +~~START~~ +smallint#!#smallint +2#!#2 +#!#3 +1#!#1 +#!#1 +~~END~~ + +drop table sourceTable + +# bigint +Create table sourceTable(a bigint, b bigint not null) +prepst#!# INSERT INTO sourceTable(a, b) values(?, ?) #!#bigint|-|a|-|2#!#bigint|-|b|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#bigint|-|a|-|#!#bigint|-|b|-|3 +~~ROW COUNT: 1~~ + +Select * from sourceTable +~~START~~ +bigint#!#bigint +2#!#2 +#!#3 +~~END~~ + +Insert into sourceTable values (1, 1); +~~ROW COUNT: 1~~ + +Insert into sourceTable values (NULL, 1); +~~ROW COUNT: 1~~ + +Select * from sourceTable +~~START~~ +bigint#!#bigint +2#!#2 +#!#3 +1#!#1 +#!#1 +~~END~~ + +drop table sourceTable + +# bit +Create table sourceTable(a bit, b bit not null) +prepst#!# INSERT INTO sourceTable(a, b) values(?, ?) #!#bit|-|a|-|true#!#bit|-|b|-|false +~~ROW COUNT: 1~~ + +prepst#!#exec#!#bit|-|a|-|#!#bit|-|b|-|true +~~ROW COUNT: 1~~ + +Select * from sourceTable +~~START~~ +bit#!#bit +1#!#0 +#!#1 +~~END~~ + +Insert into sourceTable values (1, 1); +~~ROW COUNT: 1~~ + +Insert into sourceTable values (NULL, 1); +~~ROW COUNT: 1~~ + +Select * from sourceTable +~~START~~ +bit#!#bit +1#!#0 +#!#1 +1#!#1 +#!#1 +~~END~~ + +drop table sourceTable + +# float +Create table sourceTable(a float, b float not null) +prepst#!# INSERT INTO sourceTable(a, b) values(?, ?) #!#float|-|a|-|2.00#!#float|-|b|-|2.01 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#float|-|a|-|#!#float|-|b|-|2.20 +~~ROW COUNT: 1~~ + +Select * from sourceTable +~~START~~ +float#!#float +2.0#!#2.01 +#!#2.2 +~~END~~ + +Insert into sourceTable values (1.1101, 0.00010); +~~ROW COUNT: 1~~ + +Insert into sourceTable values (NULL, 1); +~~ROW COUNT: 1~~ + +Select * from sourceTable +~~START~~ +float#!#float +2.0#!#2.01 +#!#2.2 +1.1101#!#1.0E-4 +#!#1.0 +~~END~~ + +drop table sourceTable + +# real +Create table sourceTable(a real, b real not null) +prepst#!# INSERT INTO sourceTable(a, b) values(?, ?) #!#real|-|a|-|2.00#!#real|-|b|-|2.01 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#real|-|a|-|#!#real|-|b|-|2.20 +~~ROW COUNT: 1~~ + +Select * from sourceTable +~~START~~ +real#!#real +2.0#!#2.01 +#!#2.2 +~~END~~ + +Insert into sourceTable values (1.1101, 0.00010); +~~ROW COUNT: 1~~ + +Insert into sourceTable values (NULL, 1); +~~ROW COUNT: 1~~ + +Select * from sourceTable +~~START~~ +real#!#real +2.0#!#2.01 +#!#2.2 +1.1101#!#1.0E-4 +#!#1.0 +~~END~~ + +drop table sourceTable + +# char +Create table sourceTable(a char(10), b char(10) not null) +prepst#!# INSERT INTO sourceTable(a, b) values(?, ?) #!#char|-|a|-|hello#!#char|-|b|-|jello +~~ROW COUNT: 1~~ + +prepst#!#exec#!#char|-|a|-|#!#char|-|b|-|mellow +~~ROW COUNT: 1~~ + +Select * from sourceTable +~~START~~ +char#!#char +hello #!#jello +#!#mellow +~~END~~ + +Insert into sourceTable values ('hello', 'jello'); +~~ROW COUNT: 1~~ + +Insert into sourceTable values (NULL, 'jello'); +~~ROW COUNT: 1~~ + +Select * from sourceTable +~~START~~ +char#!#char +hello #!#jello +#!#mellow +hello #!#jello +#!#jello +~~END~~ + +drop table sourceTable + +# nchar +Create table sourceTable(a nchar(10), b nchar(10) not null) +prepst#!# INSERT INTO sourceTable(a, b) values(?, ?) #!#nchar|-|a|-|hello#!#nchar|-|b|-|jello +~~ROW COUNT: 1~~ + +prepst#!#exec#!#nchar|-|a|-|#!#nchar|-|b|-|mellow +~~ROW COUNT: 1~~ + +Select * from sourceTable +~~START~~ +nchar#!#nchar +hello #!#jello +#!#mellow +~~END~~ + +Insert into sourceTable values ('hello', 'jello'); +~~ROW COUNT: 1~~ + +Insert into sourceTable values (NULL, 'jello'); +~~ROW COUNT: 1~~ + +Select * from sourceTable +~~START~~ +nchar#!#nchar +hello #!#jello +#!#mellow +hello #!#jello +#!#jello +~~END~~ + +drop table sourceTable + +# varchar +Create table sourceTable(a varchar(10), b varchar(10) not null) +prepst#!# INSERT INTO sourceTable(a, b) values(?, ?) #!#varchar|-|a|-|hello#!#varchar|-|b|-|jello +~~ROW COUNT: 1~~ + +prepst#!#exec#!#varchar|-|a|-|#!#varchar|-|b|-|mellow +~~ROW COUNT: 1~~ + +Select * from sourceTable +~~START~~ +varchar#!#varchar +hello#!#jello +#!#mellow +~~END~~ + +Insert into sourceTable values ('hello', 'jello'); +~~ROW COUNT: 1~~ + +Insert into sourceTable values (NULL, 'jello'); +~~ROW COUNT: 1~~ + +Select * from sourceTable +~~START~~ +varchar#!#varchar +hello#!#jello +#!#mellow +hello#!#jello +#!#jello +~~END~~ + +drop table sourceTable + +# nvarchar +Create table sourceTable(a nvarchar(10), b nvarchar(10) not null) +prepst#!# INSERT INTO sourceTable(a, b) values(?, ?) #!#nvarchar|-|a|-|hello#!#nvarchar|-|b|-|jello +~~ROW COUNT: 1~~ + +prepst#!#exec#!#nvarchar|-|a|-|#!#nvarchar|-|b|-|mellow +~~ROW COUNT: 1~~ + +Select * from sourceTable +~~START~~ +nvarchar#!#nvarchar +hello#!#jello +#!#mellow +~~END~~ + +Insert into sourceTable values ('hello', 'jello'); +~~ROW COUNT: 1~~ + +Insert into sourceTable values (NULL, 'jello'); +~~ROW COUNT: 1~~ + +Select * from sourceTable +~~START~~ +nvarchar#!#nvarchar +hello#!#jello +#!#mellow +hello#!#jello +#!#jello +~~END~~ + +drop table sourceTable + +# text +Create table sourceTable(a text, b text not null) +prepst#!# INSERT INTO sourceTable(a, b) values(?, ?) #!#text|-|a|-|utils/sample.txt#!#text|-|b|-|utils/sample.txt +~~ROW COUNT: 1~~ + +prepst#!#exec#!#text|-|a|-|#!#text|-|b|-|utils/sample.txt +~~ROW COUNT: 1~~ + +Select * from sourceTable +~~START~~ +text#!#text +AAAAAAAAAAAAAAAAAAAABBBBBBBBBBCCCCCbadksjvbajsdcbvjadssejvhsdbfjhcgvasdhgcvsj21639812365091264#!#AAAAAAAAAAAAAAAAAAAABBBBBBBBBBCCCCCbadksjvbajsdcbvjadssejvhsdbfjhcgvasdhgcvsj21639812365091264 +#!#AAAAAAAAAAAAAAAAAAAABBBBBBBBBBCCCCCbadksjvbajsdcbvjadssejvhsdbfjhcgvasdhgcvsj21639812365091264 +~~END~~ + +Insert into sourceTable values ('hello', 'jello'); +~~ROW COUNT: 1~~ + +Insert into sourceTable values (NULL, 'jello'); +~~ROW COUNT: 1~~ + +Select * from sourceTable +~~START~~ +text#!#text +AAAAAAAAAAAAAAAAAAAABBBBBBBBBBCCCCCbadksjvbajsdcbvjadssejvhsdbfjhcgvasdhgcvsj21639812365091264#!#AAAAAAAAAAAAAAAAAAAABBBBBBBBBBCCCCCbadksjvbajsdcbvjadssejvhsdbfjhcgvasdhgcvsj21639812365091264 +#!#AAAAAAAAAAAAAAAAAAAABBBBBBBBBBCCCCCbadksjvbajsdcbvjadssejvhsdbfjhcgvasdhgcvsj21639812365091264 +hello#!#jello +#!#jello +~~END~~ + +drop table sourceTable + +# ntext +Create table sourceTable(a ntext, b ntext not null) +prepst#!# INSERT INTO sourceTable(a, b) values(?, ?) #!#ntext|-|a|-|utils/sample.txt#!#ntext|-|b|-|utils/sample.txt +~~ROW COUNT: 1~~ + +prepst#!#exec#!#ntext|-|a|-|#!#ntext|-|b|-|utils/sample.txt +~~ROW COUNT: 1~~ + +Select * from sourceTable +~~START~~ +ntext#!#ntext +AAAAAAAAAAAAAAAAAAAABBBBBBBBBBCCCCCbadksjvbajsdcbvjadssejvhsdbfjhcgvasdhgcvsj21639812365091264#!#AAAAAAAAAAAAAAAAAAAABBBBBBBBBBCCCCCbadksjvbajsdcbvjadssejvhsdbfjhcgvasdhgcvsj21639812365091264 +#!#AAAAAAAAAAAAAAAAAAAABBBBBBBBBBCCCCCbadksjvbajsdcbvjadssejvhsdbfjhcgvasdhgcvsj21639812365091264 +~~END~~ + +Insert into sourceTable values ('hello', 'jello'); +~~ROW COUNT: 1~~ + +Insert into sourceTable values (NULL, 'jello'); +~~ROW COUNT: 1~~ + +Select * from sourceTable +~~START~~ +ntext#!#ntext +AAAAAAAAAAAAAAAAAAAABBBBBBBBBBCCCCCbadksjvbajsdcbvjadssejvhsdbfjhcgvasdhgcvsj21639812365091264#!#AAAAAAAAAAAAAAAAAAAABBBBBBBBBBCCCCCbadksjvbajsdcbvjadssejvhsdbfjhcgvasdhgcvsj21639812365091264 +#!#AAAAAAAAAAAAAAAAAAAABBBBBBBBBBCCCCCbadksjvbajsdcbvjadssejvhsdbfjhcgvasdhgcvsj21639812365091264 +hello#!#jello +#!#jello +~~END~~ + +drop table sourceTable + +# binary +Create table sourceTable(a binary(10), b binary(10) not null) +prepst#!# INSERT INTO sourceTable(a, b) values(?, ?) #!#binary|-|a|-|0x31323334#!#binary|-|b|-|0x9241 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#binary|-|a|-|#!#binary|-|b|-|0x9241 +~~ROW COUNT: 1~~ + +Select * from sourceTable +~~START~~ +binary#!#binary +30783331333233333334#!#30783932343100000000 +#!#30783932343100000000 +~~END~~ + +Insert into sourceTable values (0x31323334, 0x9241); +~~ROW COUNT: 1~~ + +Insert into sourceTable values (NULL, 0x9241); +~~ROW COUNT: 1~~ + +Select * from sourceTable +~~START~~ +binary#!#binary +30783331333233333334#!#30783932343100000000 +#!#30783932343100000000 +31323334000000000000#!#92410000000000000000 +#!#92410000000000000000 +~~END~~ + +drop table sourceTable + +# varbinary +Create table sourceTable(a varbinary(10), b varbinary(10) not null) +prepst#!# INSERT INTO sourceTable(a, b) values(?, ?) #!#varbinary|-|a|-|0x31323334#!#varbinary|-|b|-|0x9241 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#varbinary|-|a|-|#!#varbinary|-|b|-|0x9241 +~~ROW COUNT: 1~~ + +Select * from sourceTable +~~START~~ +varbinary#!#varbinary +30783331333233333334#!#307839323431 +#!#307839323431 +~~END~~ + +Insert into sourceTable values (0x31323334, 0x9241); +~~ROW COUNT: 1~~ + +Insert into sourceTable values (NULL, 0x9241); +~~ROW COUNT: 1~~ + +Select * from sourceTable +~~START~~ +varbinary#!#varbinary +30783331333233333334#!#307839323431 +#!#307839323431 +31323334#!#9241 +#!#9241 +~~END~~ + +drop table sourceTable + +# numeric +Create table sourceTable(a numeric(38, 22), b numeric(38, 22) not null) +prepst#!# INSERT INTO sourceTable(a, b) values(?, ?) #!#numeric|-|a|-|1.1101#!#numeric|-|b|-|1.1101 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a|-|#!#numeric|-|b|-|0.00 +~~ROW COUNT: 1~~ + +Select * from sourceTable +~~START~~ +numeric#!#numeric +1.1101000000000000000000#!#1.1101000000000000000000 +#!#0E-22 +~~END~~ + +Insert into sourceTable values (1.1101, 0.00010); +~~ROW COUNT: 1~~ + +Insert into sourceTable values (NULL, 0.00010); +~~ROW COUNT: 1~~ + +Select * from sourceTable +~~START~~ +numeric#!#numeric +1.1101000000000000000000#!#1.1101000000000000000000 +#!#0E-22 +1.1101000000000000000000#!#0.0001000000000000000000 +#!#0.0001000000000000000000 +~~END~~ + +drop table sourceTable + +# decimal +Create table sourceTable(a decimal(38, 22), b decimal(38, 22) not null) +prepst#!# INSERT INTO sourceTable(a, b) values(?, ?) #!#decimal|-|a|-|1.1101#!#decimal|-|b|-|1.1101 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a|-|#!#decimal|-|b|-|1.1101 +~~ROW COUNT: 1~~ + +Select * from sourceTable +~~START~~ +numeric#!#numeric +1.1101000000000000000000#!#1.1101000000000000000000 +#!#1.1101000000000000000000 +~~END~~ + +Insert into sourceTable values (1.1101, 0.00010); +~~ROW COUNT: 1~~ + +Insert into sourceTable values (NULL, 0.00010); +~~ROW COUNT: 1~~ + +Select * from sourceTable +~~START~~ +numeric#!#numeric +1.1101000000000000000000#!#1.1101000000000000000000 +#!#1.1101000000000000000000 +1.1101000000000000000000#!#0.0001000000000000000000 +#!#0.0001000000000000000000 +~~END~~ + +drop table sourceTable + +# money +Create table sourceTable(a money, b money not null) +prepst#!# INSERT INTO sourceTable(a, b) values(?, ?) #!#money|-|a|-|100.11#!#money|-|b|-|100.11 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#money|-|a|-|#!#money|-|b|-|100.11 +~~ROW COUNT: 1~~ + +Select * from sourceTable +~~START~~ +money#!#money +100.1100#!#100.1100 +#!#100.1100 +~~END~~ + +Insert into sourceTable values (100.11, 0.10); +~~ROW COUNT: 1~~ + +Insert into sourceTable values (NULL, 0.10); +~~ROW COUNT: 1~~ + +Select * from sourceTable +~~START~~ +money#!#money +100.1100#!#100.1100 +#!#100.1100 +100.1100#!#0.1000 +#!#0.1000 +~~END~~ + +drop table sourceTable + +# smallmoney +Create table sourceTable(a smallmoney, b smallmoney not null) +prepst#!# INSERT INTO sourceTable(a, b) values(?, ?) #!#smallmoney|-|a|-|0.10#!#smallmoney|-|b|-|0.10 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#smallmoney|-|a|-|#!#smallmoney|-|b|-|0.10 +~~ROW COUNT: 1~~ + +Select * from sourceTable +~~START~~ +smallmoney#!#smallmoney +0.1000#!#0.1000 +#!#0.1000 +~~END~~ + +Insert into sourceTable values (100.11, 0.10); +~~ROW COUNT: 1~~ + +Insert into sourceTable values (NULL, 0.10); +~~ROW COUNT: 1~~ + +Select * from sourceTable +~~START~~ +smallmoney#!#smallmoney +0.1000#!#0.1000 +#!#0.1000 +100.1100#!#0.1000 +#!#0.1000 +~~END~~ + +drop table sourceTable + +# uniqueidentifier +Create table sourceTable(a uniqueidentifier, b uniqueidentifier not null) +prepst#!# INSERT INTO sourceTable(a, b) values(?, ?) #!#uniqueidentifier|-|a|-|51f178a6-53c7-472c-9be1-1c08942342d7#!#uniqueidentifier|-|b|-|51f178a6-53c7-472c-9be1-1c08942342d7 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#uniqueidentifier|-|a|-|#!#uniqueidentifier|-|b|-|51f178a6-53c7-472c-9be1-1c08942342d7 +~~ROW COUNT: 1~~ + +Select * from sourceTable +~~START~~ +uniqueidentifier#!#uniqueidentifier +51F178A6-53C7-472C-9BE1-1C08942342D7#!#51F178A6-53C7-472C-9BE1-1C08942342D7 +#!#51F178A6-53C7-472C-9BE1-1C08942342D7 +~~END~~ + +Insert into sourceTable values ('51f178a6-53c7-472c-9be1-1c08942342d7', 'dd8cb046-461d-411e-be40-d219252ce849'); +~~ROW COUNT: 1~~ + +Insert into sourceTable values (NULL, 'dd8cb046-461d-411e-be40-d219252ce849'); +~~ROW COUNT: 1~~ + +Select * from sourceTable +~~START~~ +uniqueidentifier#!#uniqueidentifier +51F178A6-53C7-472C-9BE1-1C08942342D7#!#51F178A6-53C7-472C-9BE1-1C08942342D7 +#!#51F178A6-53C7-472C-9BE1-1C08942342D7 +51F178A6-53C7-472C-9BE1-1C08942342D7#!#DD8CB046-461D-411E-BE40-D219252CE849 +#!#DD8CB046-461D-411E-BE40-D219252CE849 +~~END~~ + +drop table sourceTable + +# date +Create table sourceTable(a date, b date not null) +prepst#!# INSERT INTO sourceTable(a, b) values(?, ?) #!#date|-|a|-|2000-02-28#!#date|-|b|-|2000-02-28 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#date|-|a|-|#!#date|-|b|-|2000-02-28 +~~ROW COUNT: 1~~ + +Select * from sourceTable +~~START~~ +date#!#date +2000-02-28#!#2000-02-28 +#!#2000-02-28 +~~END~~ + +Insert into sourceTable values ('2000-02-28', '0001-01-01'); +~~ROW COUNT: 1~~ + +Insert into sourceTable values (NULL, '0001-01-01'); +~~ROW COUNT: 1~~ + +Select * from sourceTable +~~START~~ +date#!#date +2000-02-28#!#2000-02-28 +#!#2000-02-28 +2000-02-28#!#0001-01-01 +#!#0001-01-01 +~~END~~ + +drop table sourceTable + +# time +Create table sourceTable(a time(6), b time(6) not null) +prepst#!# INSERT INTO sourceTable(a, b) values(?, ?) #!#time|-|a|-|12:45:37.123#!#time|-|b|-|12:45:37.123 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#time|-|a|-|#!#time|-|b|-|12:45:37.123 +~~ROW COUNT: 1~~ + +Select * from sourceTable +~~START~~ +time#!#time +12:45:37.000000#!#12:45:37.000000 +#!#12:45:37.000000 +~~END~~ + +Insert into sourceTable values ('12:45:37.123', '12:45:37.12'); +~~ROW COUNT: 1~~ + +Insert into sourceTable values (NULL, '12:45:37.12'); +~~ROW COUNT: 1~~ + +Select * from sourceTable +~~START~~ +time#!#time +12:45:37.000000#!#12:45:37.000000 +#!#12:45:37.000000 +12:45:37.123000#!#12:45:37.120000 +#!#12:45:37.120000 +~~END~~ + +drop table sourceTable + +# datetime +Create table sourceTable(a datetime, b datetime not null) +prepst#!# INSERT INTO sourceTable(a, b) values(?, ?) #!#datetime|-|a|-|2000-12-13 12:58:23.123#!#datetime|-|b|-|2000-12-13 12:58:23.123 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#datetime|-|a|-|#!#datetime|-|b|-|2000-12-13 12:58:23.123 +~~ROW COUNT: 1~~ + +Select * from sourceTable +~~START~~ +datetime#!#datetime +2000-12-13 12:58:23.123#!#2000-12-13 12:58:23.123 +#!#2000-12-13 12:58:23.123 +~~END~~ + +Insert into sourceTable values ('2000-12-13 12:58:23.123', '1900-02-28 23:59:59.989'); +~~ROW COUNT: 1~~ + +Insert into sourceTable values (NULL, '1900-02-28 23:59:59.989'); +~~ROW COUNT: 1~~ + +Select * from sourceTable +~~START~~ +datetime#!#datetime +2000-12-13 12:58:23.123#!#2000-12-13 12:58:23.123 +#!#2000-12-13 12:58:23.123 +2000-12-13 12:58:23.123#!#1900-02-28 23:59:59.99 +#!#1900-02-28 23:59:59.99 +~~END~~ + +drop table sourceTable + +# smalldatetime +Create table sourceTable(a smalldatetime, b smalldatetime not null) +prepst#!# INSERT INTO sourceTable(a, b) values(?, ?) #!#smalldatetime|-|a|-|2007-05-08 12:35:29#!#smalldatetime|-|b|-|2007-05-08 12:35:29 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#smalldatetime|-|a|-|#!#smalldatetime|-|b|-|2007-05-08 12:35:29 +~~ROW COUNT: 1~~ + +Select * from sourceTable +~~START~~ +smalldatetime#!#smalldatetime +2007-05-08 12:35:00.0#!#2007-05-08 12:35:00.0 +#!#2007-05-08 12:35:00.0 +~~END~~ + +Insert into sourceTable values ('2007-05-08 12:35:29', '2000-12-13 12:58:23'); +~~ROW COUNT: 1~~ + +Insert into sourceTable values (NULL, '2000-12-13 12:58:23'); +~~ROW COUNT: 1~~ + +Select * from sourceTable +~~START~~ +smalldatetime#!#smalldatetime +2007-05-08 12:35:00.0#!#2007-05-08 12:35:00.0 +#!#2007-05-08 12:35:00.0 +2007-05-08 12:35:00.0#!#2000-12-13 12:58:00.0 +#!#2000-12-13 12:58:00.0 +~~END~~ + +drop table sourceTable + +# datetime2 +Create table sourceTable(a Datetime2(6), b Datetime2(6) not null) +prepst#!# INSERT INTO sourceTable(a, b) values(?, ?) #!#Datetime2|-|a|-|2016-10-23 12:45:37.123|-|6#!#Datetime2|-|b|-|2016-10-23 12:45:37.123|-|6 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Datetime2|-|a|-|#!#Datetime2|-|b|-|2016-10-23 12:45:37.123|-|6 +~~ROW COUNT: 1~~ + +Select * from sourceTable +~~START~~ +datetime2#!#datetime2 +2016-10-23 12:45:37.123000#!#2016-10-23 12:45:37.123000 +#!#2016-10-23 12:45:37.123000 +~~END~~ + +Insert into sourceTable values ('2016-10-23 12:45:37.123', '2016-10-23 12:45:37.123'); +~~ROW COUNT: 1~~ + +Insert into sourceTable values (NULL, '2016-10-23 12:45:37.123'); +~~ROW COUNT: 1~~ + +Select * from sourceTable +~~START~~ +datetime2#!#datetime2 +2016-10-23 12:45:37.123000#!#2016-10-23 12:45:37.123000 +#!#2016-10-23 12:45:37.123000 +2016-10-23 12:45:37.123000#!#2016-10-23 12:45:37.123000 +#!#2016-10-23 12:45:37.123000 +~~END~~ + +drop table sourceTable + +# datetimeoffset +Create table sourceTable(a datetimeoffset(6), b datetimeoffset(6) not null) +prepst#!# INSERT INTO sourceTable(a, b) values(?, ?) #!#datetimeoffset|-|a|-|2016-10-23 12:24:32|-|6#!#datetimeoffset|-|b|-|2016-10-23 12:24:32|-|6 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#datetimeoffset|-|a|-|#!#datetimeoffset|-|b|-|2016-10-23 12:24:32|-|6 +~~ROW COUNT: 1~~ + +Select * from sourceTable +~~START~~ +datetimeoffset#!#datetimeoffset +2016-10-23 12:24:32.000000 +00:00#!#2016-10-23 12:24:32.000000 +00:00 +#!#2016-10-23 12:24:32.000000 +00:00 +~~END~~ + +Insert into sourceTable values ('2016-10-23 12:24:32 +10:0', '2016-10-23 12:24:32 +10:0'); +~~ROW COUNT: 1~~ + +Insert into sourceTable values (NULL, '2016-10-23 12:24:32 +10:0'); +~~ROW COUNT: 1~~ + +Select * from sourceTable +~~START~~ +datetimeoffset#!#datetimeoffset +2016-10-23 12:24:32.000000 +00:00#!#2016-10-23 12:24:32.000000 +00:00 +#!#2016-10-23 12:24:32.000000 +00:00 +2016-10-23 12:24:32.000000 +10:00#!#2016-10-23 12:24:32.000000 +10:00 +#!#2016-10-23 12:24:32.000000 +10:00 +~~END~~ + +drop table sourceTable + +# sql_variant +Create table sourceTable(a sql_variant, b sql_variant not null) +prepst#!# INSERT INTO sourceTable(a, b) values(?, ?) #!#bit|-|a|-|#!#int|-|b|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#bit|-|a|-|0#!#bit|-|b|-|1 +~~ROW COUNT: 1~~ + +Select * from sourceTable +~~START~~ +sql_variant#!#sql_variant +#!#2 +false#!#false +~~END~~ + +Insert into sourceTable values (cast (1 as int), cast ('abc' as varchar(10))); +~~ROW COUNT: 1~~ + +Insert into sourceTable values (NULL, cast ('abc' as varchar(10))); +~~ROW COUNT: 1~~ + +Select * from sourceTable +~~START~~ +sql_variant#!#sql_variant +#!#2 +false#!#false +1#!#abc +#!#abc +~~END~~ + +drop table sourceTable + diff --git a/contrib/test/JDBC/expected/TestNumeric.out b/contrib/test/JDBC/expected/TestNumeric.out new file mode 100644 index 00000000000..2627f4272ef --- /dev/null +++ b/contrib/test/JDBC/expected/TestNumeric.out @@ -0,0 +1,734 @@ +CREATE TABLE numeric_table(num numeric(5, 2)); + +prepst#!#INSERT INTO numeric_table(num) VALUES(?) #!#numeric|-|a|-|3|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a|-|123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a|-|123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a|-|123|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a|-|123.45|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a|-||-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a|-|-123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a|-|-123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a|-|-123|-|5|-|2 +~~ROW COUNT: 1~~ + +#prepst#!#exec#!#numeric|-|a|-|0|-|5|-|2 +prepst#!#exec#!#numeric|-|a|-|-1|-|3|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a|-|-123|-|9|-|2 +~~ROW COUNT: 1~~ + + +SELECT * FROM numeric_table; +~~START~~ +numeric +3.00 +123.46 +123.40 +123.00 +123.45 + +-123.46 +-123.40 +-123.00 +-1.00 +-123.00 +~~END~~ + + +DROP TABLE numeric_table; + +CREATE TABLE numeric_table(num numeric(38, 3)); + +prepst#!#INSERT INTO numeric_table(num) VALUES(?) #!#numeric|-|a1|-|3|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a1|-|123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a1|-|123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a1|-|123|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a1|-|123.45|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a1|-||-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a1|-|-123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a1|-|-123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a1|-|-123|-|5|-|2 +~~ROW COUNT: 1~~ + +#prepst#!#exec#!#numeric|-|a1|-|0|-|5|-|2 +prepst#!#exec#!#numeric|-|a1|-|-1|-|3|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a1|-|-123|-|9|-|2 +~~ROW COUNT: 1~~ + + +prepst#!#exec#!#numeric|-|a1|-|2147483647|-|10|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a1|-|-2147483647|-|10|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a1|-|2147483646|-|10|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a1|-|-2147483646|-|10|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a1|-|2147483648|-|10|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a1|-|-2147483648|-|10|-|0 +~~ROW COUNT: 1~~ + + +SELECT * FROM numeric_table; +~~START~~ +numeric +3.000 +123.456 +123.400 +123.000 +123.450 + +-123.456 +-123.400 +-123.000 +-1.000 +-123.000 +2147483647.000 +-2147483647.000 +2147483646.000 +-2147483646.000 +2147483648.000 +-2147483648.000 +~~END~~ + + +DROP TABLE numeric_table; + +# JIRA 507, WORKING FOR BABEL +#CREATE TABLE numeric_table(num numeric(39, 20)); + +CREATE TABLE numeric_table(num numeric(38, 20)); + +prepst#!#INSERT INTO numeric_table(num) VALUES(?) #!#numeric|-|a2|-|3|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a2|-|123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a2|-|123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a2|-|123|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a2|-|123.45|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a2|-||-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a2|-|-123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a2|-|-123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a2|-|-123|-|5|-|2 +~~ROW COUNT: 1~~ + +#prepst#!#exec#!#numeric|-|a2|-|0|-|5|-|2 +prepst#!#exec#!#numeric|-|a2|-|-1|-|3|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a2|-|-123|-|9|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a2|-|2147483647|-|10|-|0 +~~ROW COUNT: 1~~ + +SELECT * FROM numeric_table; +~~START~~ +numeric +3.00000000000000000000 +123.45600000000000000000 +123.40000000000000000000 +123.00000000000000000000 +123.45000000000000000000 + +-123.45600000000000000000 +-123.40000000000000000000 +-123.00000000000000000000 +-1.00000000000000000000 +-123.00000000000000000000 +2147483647.00000000000000000000 +~~END~~ + + +DROP TABLE numeric_table; + +CREATE TABLE numeric_table(num numeric(38, 20)); +prepst#!#INSERT INTO numeric_table(num) VALUES(?) #!#numeric|-|a3|-|3|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a3|-|123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a3|-|123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a3|-|123|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a3|-|123.45|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a3|-||-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a3|-|-123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a3|-|-123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a3|-|-123|-|5|-|2 +~~ROW COUNT: 1~~ + +#prepst#!#exec#!#numeric|-|a3|-|0|-|5|-|2 +prepst#!#exec#!#numeric|-|a3|-|-1|-|3|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a3|-|-123|-|9|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a3|-|2147483647|-|10|-|0 +~~ROW COUNT: 1~~ + +SELECT * FROM numeric_table; +~~START~~ +numeric +3.00000000000000000000 +123.45600000000000000000 +123.40000000000000000000 +123.00000000000000000000 +123.45000000000000000000 + +-123.45600000000000000000 +-123.40000000000000000000 +-123.00000000000000000000 +-1.00000000000000000000 +-123.00000000000000000000 +2147483647.00000000000000000000 +~~END~~ + + +DROP TABLE numeric_table; + +CREATE TABLE numeric_table(num numeric(38, 21)); +prepst#!#INSERT INTO numeric_table(num) VALUES(?) #!#numeric|-|a4|-|3|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a4|-|123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a4|-|123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a4|-|123|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a4|-|123.45|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a4|-||-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a4|-|-123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a4|-|-123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a4|-|-123|-|5|-|2 +~~ROW COUNT: 1~~ + +#prepst#!#exec#!#numeric|-|a4|-|0|-|5|-|2 +prepst#!#exec#!#numeric|-|a4|-|-1|-|3|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a4|-|-123|-|9|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a4|-|2147483647|-|10|-|0 +~~ROW COUNT: 1~~ + +SELECT * FROM numeric_table; +~~START~~ +numeric +3.000000000000000000000 +123.456000000000000000000 +123.400000000000000000000 +123.000000000000000000000 +123.450000000000000000000 + +-123.456000000000000000000 +-123.400000000000000000000 +-123.000000000000000000000 +-1.000000000000000000000 +-123.000000000000000000000 +2147483647.000000000000000000000 +~~END~~ + + +DROP TABLE numeric_table; + +CREATE TABLE numeric_table(num numeric(38, 22)); +prepst#!#INSERT INTO numeric_table(num) VALUES(?) #!#numeric|-|a5|-|3|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a5|-|123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a5|-|123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a5|-|123|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a5|-|123.45|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a5|-||-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a5|-|-123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a5|-|-123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a5|-|-123|-|5|-|2 +~~ROW COUNT: 1~~ + +#prepst#!#exec#!#numeric|-|a5|-|0|-|5|-|2 +prepst#!#exec#!#numeric|-|a5|-|-1|-|3|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a5|-|-123|-|9|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a5|-|2147483647|-|10|-|0 +~~ROW COUNT: 1~~ + +SELECT * FROM numeric_table; +~~START~~ +numeric +3.0000000000000000000000 +123.4560000000000000000000 +123.4000000000000000000000 +123.0000000000000000000000 +123.4500000000000000000000 + +-123.4560000000000000000000 +-123.4000000000000000000000 +-123.0000000000000000000000 +-1.0000000000000000000000 +-123.0000000000000000000000 +2147483647.0000000000000000000000 +~~END~~ + + +DROP TABLE numeric_table; + +CREATE TABLE numeric_table(num numeric(38, 23)); +prepst#!#INSERT INTO numeric_table(num) VALUES(?) #!#numeric|-|a6|-|3|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a6|-|123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a6|-|123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a6|-|123|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a6|-|123.45|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a6|-||-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a6|-|-123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a6|-|-123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a6|-|-123|-|5|-|2 +~~ROW COUNT: 1~~ + +#prepst#!#exec#!#numeric|-|a6|-|0|-|5|-|2 +prepst#!#exec#!#numeric|-|a6|-|-1|-|3|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a6|-|-123|-|9|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a6|-|2147483647|-|10|-|0 +~~ROW COUNT: 1~~ + +SELECT * FROM numeric_table; +~~START~~ +numeric +3.00000000000000000000000 +123.45600000000000000000000 +123.40000000000000000000000 +123.00000000000000000000000 +123.45000000000000000000000 + +-123.45600000000000000000000 +-123.40000000000000000000000 +-123.00000000000000000000000 +-1.00000000000000000000000 +-123.00000000000000000000000 +2147483647.00000000000000000000000 +~~END~~ + + +DROP TABLE numeric_table; + +CREATE TABLE numeric_table(num numeric(38, 25)); +prepst#!#INSERT INTO numeric_table(num) VALUES(?) #!#numeric|-|a7|-|3|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a7|-|123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a7|-|123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a7|-|123|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a7|-|123.45|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a7|-||-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a7|-|-123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a7|-|-123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a7|-|-123|-|5|-|2 +~~ROW COUNT: 1~~ + +#prepst#!#exec#!#numeric|-|a7|-|0|-|5|-|2 +prepst#!#exec#!#numeric|-|a7|-|-1|-|3|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a7|-|-123|-|9|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a7|-|247483647|-|10|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a7|-|-247483647|-|10|-|0 +~~ROW COUNT: 1~~ + +SELECT * FROM numeric_table; +~~START~~ +numeric +3.0000000000000000000000000 +123.4560000000000000000000000 +123.4000000000000000000000000 +123.0000000000000000000000000 +123.4500000000000000000000000 + +-123.4560000000000000000000000 +-123.4000000000000000000000000 +-123.0000000000000000000000000 +-1.0000000000000000000000000 +-123.0000000000000000000000000 +247483647.0000000000000000000000000 +-247483647.0000000000000000000000000 +~~END~~ + + +DROP TABLE numeric_table; + + +CREATE TABLE numeric_table(num numeric(38, 25)); + +insert into numeric_table values (2147483647) +~~ROW COUNT: 1~~ + +insert into numeric_table values (-2147483647) +~~ROW COUNT: 1~~ + + +insert into numeric_table values (2147483646) +~~ROW COUNT: 1~~ + +insert into numeric_table values (-2147483646) +~~ROW COUNT: 1~~ + + +insert into numeric_table values (2147483648) +~~ROW COUNT: 1~~ + +insert into numeric_table values (-2147483648) +~~ROW COUNT: 1~~ + + +#insert into numeric_table values(123456789123456789.1234567891234567891234567); +#insert into numeric_table values(1234567891234567891.1234567891234567891234567); +#insert into numeric_table values(123456789123456789.12345678912345678912345678); +insert into numeric_table values(0.0); +~~ROW COUNT: 1~~ + +insert into numeric_table values(0.0000000000000000000000000); +~~ROW COUNT: 1~~ + +insert into numeric_table values(0.00000000000000000000000000); +~~ROW COUNT: 1~~ + + +SELECT * FROM numeric_table; +~~START~~ +numeric +2147483647.0000000000000000000000000 +-2147483647.0000000000000000000000000 +2147483646.0000000000000000000000000 +-2147483646.0000000000000000000000000 +2147483648.0000000000000000000000000 +-2147483648.0000000000000000000000000 +0E-25 +0E-25 +0E-25 +~~END~~ + + +DROP TABLE numeric_table; + +# BABEL-1459 +declare @numvar numeric(5,4); set @numvar=-0.010; SELECT @numvar as N'@var'; +~~START~~ +numeric +-0.0100 +~~END~~ + +declare @numvar numeric(4,4); set @numvar=-0.010; SELECT @numvar as N'@var'; +~~START~~ +numeric +-0.0100 +~~END~~ + +declare @numvar numeric(5,4); set @numvar=1.01; SELECT @numvar as N'@var'; +~~START~~ +numeric +1.0100 +~~END~~ + +declare @numvar numeric(4,4); set @numvar=0.01; SELECT @numvar as N'@var'; +~~START~~ +numeric +0.0100 +~~END~~ + +declare @numvar numeric(4,4); set @numvar=0; SELECT @numvar as N'@var'; +~~START~~ +numeric +0.0000 +~~END~~ + + +# BABEL-2048 +CREATE TABLE babel_2048_t1(a int, b NUMERIC(19,4), c NUMERIC(20, 9), d FLOAT); +INSERT INTO babel_2048_t1 VALUES (1, 2.3, 3.123456789, 4.123456789); +~~ROW COUNT: 1~~ + +select b - 1 from babel_2048_t1; +~~START~~ +numeric +1.3000 +~~END~~ + +select b - a from babel_2048_t1; +~~START~~ +numeric +1.3000 +~~END~~ + +select a - b from babel_2048_t1; +~~START~~ +numeric +-1.3000 +~~END~~ + +select a + b from babel_2048_t1; +~~START~~ +numeric +3.3000 +~~END~~ + +select a * b from babel_2048_t1; +~~START~~ +numeric +2.3000000 +~~END~~ + +select a / b from babel_2048_t1; +~~START~~ +numeric +0.4347826086956521739 +~~END~~ + +select b / a from babel_2048_t1; +~~START~~ +numeric +2.3000000000000000000 +~~END~~ + +select b * NULL from babel_2048_t1; +~~START~~ +numeric + +~~END~~ + +select b / NULL from babel_2048_t1; +~~START~~ +numeric + +~~END~~ + +select b - NULL from babel_2048_t1; +~~START~~ +numeric + +~~END~~ + +select b + NULL from babel_2048_t1; +~~START~~ +numeric + +~~END~~ + +select SQRT(a / b) from babel_2048_t1; +~~START~~ +numeric +0.65938047 +~~END~~ + +select ROUND(a / b, 3) from babel_2048_t1; +~~START~~ +numeric +0.43500000 +~~END~~ + +select SQRT(7); +~~START~~ +float +2.6457513110645907 +~~END~~ + +select ROUND(10.1234567, 5); +~~START~~ +numeric +10.12346 +~~END~~ + + +# test operation between int and numeric(20, 9) +select a+c, a-c, a*c, a/c, a%c, a%NULL from babel_2048_t1; +~~START~~ +numeric#!#numeric#!#numeric#!#numeric#!#numeric#!#int +4.123456789#!#-2.123456789#!#3.123456789000000#!#0.320158102881954100#!#1.000000000#!# +~~END~~ + +# test operation between numeric and numeric +select b+c, b-c, b*c, b/c, b%c, b%NULL from babel_2048_t1; +~~START~~ +numeric#!#numeric#!#numeric#!#numeric#!#numeric#!#numeric +5.423456789#!#-0.823456789#!#7.18395061470#!#0.73636363662849#!#2.300000000#!# +~~END~~ + +# test operation between numeric and float +select c+d, c-d, c*d, c/d, c%d, c%NULL from babel_2048_t1; +~~START~~ +float#!#float#!#float#!#float#!#numeric#!#numeric +7.246913577999999#!#-0.9999999999999996#!#12.879439101750188#!#0.7574850298740454#!#3.123456789#!# +~~END~~ + + +# test NULLIF with numeric args +select nullif(c, b) from babel_2048_t1; +~~START~~ +numeric +3.123456789 +~~END~~ + + +# test Coalesce with numeric args +select coalesce(NULL, NULL, b) from babel_2048_t1; +~~START~~ +numeric +2.3000 +~~END~~ + + +# test Case expression with numeric args +INSERT INTO babel_2048_t1 VALUES (2, 3.7, 4.123456789, 5.123456789); +~~ROW COUNT: 1~~ + +select case when a <= 1 then b - a when a > 1 then c - a end from babel_2048_t1; +~~START~~ +numeric +1.300000000 +2.123456789 +~~END~~ + + +# test Max() and Min() with numeric args +select Max(c-b), Min(c-b) from babel_2048_t1; +~~START~~ +numeric#!#numeric +0.823456789#!#0.423456789 +~~END~~ + + +drop table babel_2048_t1; diff --git a/contrib/test/JDBC/expected/TestPrepareExec.out b/contrib/test/JDBC/expected/TestPrepareExec.out new file mode 100644 index 00000000000..ebeeddbea21 --- /dev/null +++ b/contrib/test/JDBC/expected/TestPrepareExec.out @@ -0,0 +1,55 @@ +#single parameter bind in target list +prepst#!#SELECT ?#!#INT|-|a|-|1 +~~START~~ +int +1 +~~END~~ + +prepst#!#exec#!#INT|-|a|-|1 +~~START~~ +int +1 +~~END~~ + +prepst#!#exec#!#INT|-|a|-|1 +~~START~~ +int +1 +~~END~~ + +prepst#!#exec#!#INT|-|a|-|1 +~~START~~ +int +1 +~~END~~ + +#no parameter bind +prepst#!#SELECT 1#!# +~~START~~ +int +1 +~~END~~ + +prepst#!#exec#!# +~~START~~ +int +1 +~~END~~ + +prepst#!#exec#!# +~~START~~ +int +1 +~~END~~ + +prepst#!#exec#!# +~~START~~ +int +1 +~~END~~ + +#empty query +prepst#!# #!# +prepst#!#exec#!# +prepst#!#exec#!# +prepst#!#exec#!# diff --git a/contrib/test/JDBC/expected/TestProcedureWithErrorHandling.out b/contrib/test/JDBC/expected/TestProcedureWithErrorHandling.out new file mode 100644 index 00000000000..c59fe9fdf9d --- /dev/null +++ b/contrib/test/JDBC/expected/TestProcedureWithErrorHandling.out @@ -0,0 +1,499 @@ +-- tsql +CREATE PROCEDURE tsql_interop_proc +AS +CREATE TABLE procTab1(c1 money, c2 char); +BEGIN TRY + SELECT xact_state(); + INSERT INTO procTab1 values($1,'a'); + INSERT INTO procTab1 values('i','a'); +END TRY +BEGIN CATCH + SELECT xact_state(); + SELECT @@trancount; +END CATCH +GO + +-- psql +CREATE PROCEDURE psql_interop_proc() +AS +$$ +BEGIN + CALL master_dbo.tsql_interop_proc(); +END +$$ LANGUAGE PLPGSQL; +GO + +-- tsql +EXEC [public].psql_interop_proc +GO +~~START~~ +smallint +0 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +smallint +0 +~~END~~ + +~~START~~ +int +0 +~~END~~ + +SELECT * FROM procTab1 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "proctab1" does not exist)~~ + +EXEC tsql_interop_proc +GO +~~START~~ +smallint +0 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +smallint +0 +~~END~~ + +~~START~~ +int +0 +~~END~~ + +SELECT * FROM procTab1 +GO +~~START~~ +money#!#char +1.0000#!#a +~~END~~ + +DROP TABLE procTab1 +GO +BEGIN TRANSACTION +GO +EXEC [public].psql_interop_proc +GO +~~START~~ +smallint +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +smallint +1 +~~END~~ + +~~START~~ +int +1 +~~END~~ + +SELECT * FROM procTab1 +GO +~~START~~ +money#!#char +1.0000#!#a +~~END~~ + +COMMIT +GO +DROP TABLE procTab1 +GO + + +-- tsql +/* TODO: BABEL-2377 */ +/* -- psql */ +/* CALL psql_interop_proc(); */ +/* GO */ +/* SELECT * FROM procTab1; */ +/* GO */ +SET IMPLICIT_TRANSACTIONS ON +GO +EXEC [public].psql_interop_proc +GO +~~START~~ +smallint +0 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +smallint +0 +~~END~~ + +~~START~~ +int +0 +~~END~~ + +SELECT * FROM procTab1 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "proctab1" does not exist)~~ + +IF @@TRANCOUNT > 0 ROLLBACK; +GO +SET IMPLICIT_TRANSACTIONS OFF +GO +DROP PROCEDURE tsql_interop_proc +GO + +-- tsql +CREATE PROCEDURE tsql_interop_proc +AS +CREATE TABLE procTab1(c1 money, c2 char); +BEGIN TRY + SELECT xact_state(); + INSERT INTO procTab1 values($1,'a'); + EXEC psql_interop_proc1; +END TRY +BEGIN CATCH + SELECT xact_state(); + SELECT @@TRANCOUNT; +END CATCH +GO + +-- psql +CREATE PROCEDURE psql_interop_proc1() +AS +$$ +BEGIN + INSERT INTO procTab1(c1,c2) values('i','a'); +END +$$ LANGUAGE PLPGSQL; +GO + + +-- tsql +/* -- psql */ +/* CALL psql_interop_proc(); */ +/* GO */ +/* SELECT * FROM procTab1; */ +/* GO */ +EXEC [public].psql_interop_proc; +GO +~~START~~ +smallint +0 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +smallint +0 +~~END~~ + +~~START~~ +int +0 +~~END~~ + +SELECT * FROM procTab1 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "proctab1" does not exist)~~ + +DROP PROCEDURE tsql_interop_proc +GO + +-- psql +DROP PROCEDURE psql_interop_proc1 +GO + +-- tsql +CREATE PROCEDURE tsql_interop_proc +AS +BEGIN TRY + RAISERROR ('raiserror 16', 16, 1); +END TRY +BEGIN CATCH + SELECT 'CATCH in Procedure 1'; + SELECT + ERROR_LINE() AS line, + ERROR_MESSAGE() AS msg, + ERROR_NUMBER() AS num, + ERROR_PROCEDURE() AS proc_, + ERROR_SEVERITY() AS sev, + ERROR_STATE() AS state; + THROW; +END CATCH +GO +EXEC [public].psql_interop_proc; +GO +~~START~~ +varchar +CATCH in Procedure 1 +~~END~~ + +~~START~~ +int#!#nvarchar#!#int#!#nvarchar#!#int#!#int +4#!#raiserror 16#!#50000#!#tsql_interop_proc#!#16#!#1 +~~END~~ + +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: raiserror 16)~~ + + + +/* -- psql */ +/* CALL psql_interop_proc(); */ +/* GO */ +DROP PROCEDURE tsql_interop_proc +GO + +-- tsql + +CREATE PROCEDURE tsql_interop_proc2 +AS +BEGIN TRY + RAISERROR ('raiserror 16', 16, 1); +END TRY +BEGIN CATCH + SELECT 'CATCH in Procedure 1'; + SELECT + ERROR_LINE() AS line, + ERROR_MESSAGE() AS msg, + ERROR_NUMBER() AS num, + ERROR_PROCEDURE() AS proc_, + ERROR_SEVERITY() AS sev, + ERROR_STATE() AS state; + THROW; +END CATCH +GO + +CREATE PROCEDURE tsql_interop_proc +AS +BEGIN TRY + EXEC tsql_interop_proc2; +END TRY +BEGIN CATCH + SELECT 'CATCH in Procedure 2'; + SELECT + ERROR_NUMBER() AS num, + ERROR_PROCEDURE() AS proc_, + ERROR_SEVERITY() AS sev, + ERROR_STATE() AS state; + THROW; +END CATCH +GO + +EXEC [public].psql_interop_proc; +GO +~~START~~ +varchar +CATCH in Procedure 1 +~~END~~ + +~~START~~ +int#!#nvarchar#!#int#!#nvarchar#!#int#!#int +4#!#raiserror 16#!#50000#!#tsql_interop_proc2#!#16#!#1 +~~END~~ + +~~START~~ +varchar +CATCH in Procedure 2 +~~END~~ + +~~START~~ +int#!#nvarchar#!#int#!#int +50000#!#tsql_interop_proc2#!#16#!#1 +~~END~~ + +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: raiserror 16)~~ + + + +/* -- psql */ +/* CALL psql_interop_proc(); */ +/* GO */ +DROP PROCEDURE tsql_interop_proc2 +GO + +-- tsql +CREATE PROCEDURE tsql_interop_proc2 +AS + EXEC [public].psql_interop_proc2; +GO + +-- psql +CREATE PROCEDURE psql_interop_proc2() +AS +$$ +BEGIN + SELECT 100/0; +END +$$ LANGUAGE PLPGSQL; +GO + +-- tsql +EXEC [public].psql_interop_proc; +GO +~~START~~ +varchar +CATCH in Procedure 2 +~~END~~ + +~~START~~ +int#!#nvarchar#!#int#!#int +8134#!##!#16#!#1 +~~END~~ + +~~ERROR (Code: 8134)~~ + +~~ERROR (Message: division by zero)~~ + + + +-- psql +/* -- psql */ +/* CALL psql_interop_proc(); */ +/* GO */ +DROP PROCEDURE psql_interop_proc2 +GO + +-- tsql +DROP PROCEDURE tsql_interop_proc +GO +DROP PROCEDURE tsql_interop_proc2 +GO + +-- tsql +CREATE PROCEDURE tsql_interop_proc +AS +BEGIN TRY + SELECT 100/0; + RAISERROR('Hello %s', 16, 1, 'World'); +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH +GO + +-- tsql +EXEC [public].psql_interop_proc; +GO +~~START~~ +smallint +0 +~~END~~ + + + +-- tsql +/* -- psql */ +/* CALL psql_interop_proc(); */ +/* GO */ +SET XACT_ABORT OFF; +GO +EXEC [public].psql_interop_proc +GO +~~START~~ +smallint +0 +~~END~~ + +SET XACT_ABORT ON; +GO +DROP PROCEDURE tsql_interop_proc +GO + +-- tsql +CREATE PROCEDURE tsql_interop_proc +AS + RAISERROR('Hello %s', 16, 1, 'World'); + SELECT xact_state(); + SELECT @@trancount; +GO + +-- tsql +EXEC [public].psql_interop_proc +GO +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: Hello World)~~ + + +-- psql +CALL psql_interop_proc(); +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Hello World + Where: PL/tsql function master_dbo.tsql_interop_proc() line 1 at RAISERROR +SQL statement "CALL master_dbo.tsql_interop_proc()" +PL/pgSQL function psql_interop_proc() line 3 at CALL + Server SQLState: YY000)~~ + + +-- tsql +SET XACT_ABORT OFF; +GO +SET IMPLICIT_TRANSACTIONS ON +GO +EXEC [public].psql_interop_proc +GO +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: Hello World)~~ + +EXEC tsql_interop_proc +GO +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: Hello World)~~ + +~~START~~ +smallint +0 +~~END~~ + +~~START~~ +int +0 +~~END~~ + + +-- psql +CALL psql_interop_proc(); +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Hello World + Where: PL/tsql function master_dbo.tsql_interop_proc() line 1 at RAISERROR +SQL statement "CALL master_dbo.tsql_interop_proc()" +PL/pgSQL function psql_interop_proc() line 3 at CALL + Server SQLState: YY000)~~ + + +-- tsql +SET IMPLICIT_TRANSACTIONS OFF +GO +SET XACT_ABORT ON; +GO + +-- psql +DROP PROCEDURE psql_interop_proc +GO + +-- tsql +DROP PROCEDURE tsql_interop_proc +GO diff --git a/contrib/test/JDBC/expected/TestProcedureWithTransactions.out b/contrib/test/JDBC/expected/TestProcedureWithTransactions.out new file mode 100644 index 00000000000..48ae9ee9865 --- /dev/null +++ b/contrib/test/JDBC/expected/TestProcedureWithTransactions.out @@ -0,0 +1,748 @@ +-- tsql +CREATE PROCEDURE tsql_interop_proc1 +AS +UPDATE procTab1 SET c1=10 where c2='b'; +INSERT INTO procTab1 values(1,'a'); +INSERT INTO procTab1 values(2,'b'); +EXEC psql_interop_proc2; +GO + +-- psql currentSchema=master_dbo,public +CREATE PROCEDURE psql_interop_proc1() +AS +$$ +BEGIN + CREATE TABLE procTab1(c1 int); + ALTER TABLE procTab1 OWNER TO master_dbo; + INSERT INTO procTab1 values (5); + ALTER TABLE procTab1 ADD c2 char; + CALL tsql_interop_proc1(); +END +$$ LANGUAGE PLPGSQL; +GO + +CREATE PROCEDURE psql_interop_proc2() +AS +$$ +BEGIN + INSERT INTO procTab1(c1,c2) values (3,'c'); + UPDATE procTab1 SET c1=10 where c2='b'; + INSERT INTO procTab1(c1,c2) values (4,'d'); + DELETE FROM procTab1 where c2='a'; +END +$$ LANGUAGE PLPGSQL; +GO + +-- tsql +BEGIN TRANSACTION +GO +EXEC psql_interop_proc1 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +COMMIT +GO +SELECT * FROM procTab1 order by c1 +GO +~~START~~ +int#!#char +3#!#c +4#!#d +5#!# +10#!#b +~~END~~ + + +-- psql currentSchema=master_dbo,public +BEGIN TRANSACTION +GO +CALL tsql_interop_proc1() +GO +COMMIT +GO +SELECT * FROM procTab1 +GO +~~START~~ +int4#!#bpchar +5#!# +3#!#c +4#!#d +3#!#c +10#!#b +10#!#b +4#!#d +~~END~~ + + +-- psql currentSchema=master_dbo,public +BEGIN TRANSACTION +GO +CALL tsql_interop_proc1() +GO +ROLLBACK +GO +SELECT * FROM procTab1 +GO +~~START~~ +int4#!#bpchar +5#!# +3#!#c +4#!#d +3#!#c +10#!#b +10#!#b +4#!#d +~~END~~ + + +-- tsql +BEGIN TRANSACTION +GO +SAVE TRANSACTION sp1 +GO +EXEC tsql_interop_proc1 +GO +~~ROW COUNT: 2~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +INSERT INTO procTab1(c1,c2) values(11,'e') +GO +~~ROW COUNT: 1~~ + +ROLLBACK TRANSACTION sp1 +GO +SELECT * FROM procTab1 +GO +~~START~~ +int#!#char +5#!# +3#!#c +4#!#d +3#!#c +10#!#b +10#!#b +4#!#d +~~END~~ + +ROLLBACK +GO +SELECT * FROM procTab1 +GO +~~START~~ +int#!#char +5#!# +3#!#c +4#!#d +3#!#c +10#!#b +10#!#b +4#!#d +~~END~~ + + +-- tsql +DROP TABLE procTab1 +GO + +-- psql currentSchema=master_dbo,public +DROP PROCEDURE psql_interop_proc2 +GO + +-- psql currentSchema=master_dbo,public +CREATE PROCEDURE psql_interop_proc2() +AS +$$ +DECLARE myvar varchar(1) = 'f'; +BEGIN + UPDATE procTab1 SET c2=myvar WHERE c1 BETWEEN 2 AND 10; + INSERT INTO procTab1(c1,c2) values(12,'x'); + COMMIT; +END +$$ LANGUAGE PLPGSQL; +GO + +-- tsql +BEGIN TRANSACTION +GO +EXEC psql_interop_proc1 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: invalid transaction termination)~~ + +SELECT * FROM procTab1 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "proctab1" does not exist)~~ + +DROP PROCEDURE psql_interop_proc2 +GO + +-- psql currentSchema=master_dbo,public +CREATE PROCEDURE psql_interop_proc2() +AS +$$ +BEGIN + UPDATE procTab1 SET c1=c1+2 WHERE c1 BETWEEN 2 AND 10; + SAVEPOINT sp1; + INSERT INTO procTab1(c1,c2) values(13,'w'); + EXECUTE "ROLLBACK TO $1" USING sp1; + ROLLBACK; +END +$$ LANGUAGE PLPGSQL; +GO + +-- tsql +BEGIN TRANSACTION +GO +EXEC psql_interop_proc1 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: unsupported transaction command in PL/pgSQL)~~ + +SELECT * FROM procTab1 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "proctab1" does not exist)~~ + + +-- psql currentSchema=master_dbo,public +DROP PROCEDURE psql_interop_proc2 +GO + +-- psql currentSchema=master_dbo,public +CREATE PROCEDURE psql_interop_proc2() +AS +$$ +BEGIN + UPDATE procTab1 SET c1=c1+2 WHERE c1 BETWEEN 2 AND 10; + INSERT INTO procTab1(c1,c2) values(13,'w'); + ROLLBACK; +END +$$ LANGUAGE PLPGSQL; +GO + +-- tsql +BEGIN TRANSACTION +GO +EXEC psql_interop_proc1 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: invalid transaction termination)~~ + +SELECT * FROM procTab1 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "proctab1" does not exist)~~ + + +-- tsql +BEGIN TRANSACTION +GO +SAVE TRANSACTION sp1; +GO +EXEC psql_interop_proc1 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: invalid transaction termination)~~ + +SELECT * FROM procTab1 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "proctab1" does not exist)~~ + + +-- tsql +BEGIN TRANSACTION +GO +EXEC psql_interop_proc1 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: invalid transaction termination)~~ + +SELECT * FROM procTab1 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "proctab1" does not exist)~~ + + +-- psql currentSchema=master_dbo,public +DROP PROCEDURE psql_interop_proc2 +GO + +-- tsql +DROP PROCEDURE tsql_interop_proc1 +GO + +-- tsql +CREATE PROCEDURE tsql_interop_proc1 +AS +BEGIN TRANSACTION; +UPDATE procTab1 SET c1=10 where c2='b'; +INSERT INTO procTab1 values(1,'a'); +INSERT INTO procTab1 values(2,'b'); +EXEC psql_interop_proc2; +GO + +-- psql currentSchema=master_dbo,public +CREATE PROCEDURE psql_interop_proc2() +AS +$$ +BEGIN + UPDATE procTab1 SET c1=c1+2 WHERE c1 BETWEEN 2 AND 10; + SAVEPOINT sp1; + INSERT INTO procTab1(c1,c2) values(13,'w'); + EXECUTE "ROLLBACK TO $1" USING sp1; + COMMIT; +END +$$ LANGUAGE PLPGSQL; +GO + +-- tsql +EXEC psql_interop_proc1 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: invalid transaction command)~~ + +SELECT * FROM procTab1 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "proctab1" does not exist)~~ + + +-- psql currentSchema=master_dbo,public +DROP PROCEDURE psql_interop_proc2 +GO + +-- tsql +DROP PROCEDURE tsql_interop_proc1 +GO + +-- tsql +CREATE PROCEDURE tsql_interop_proc1 +AS +BEGIN TRANSACTION; +UPDATE procTab1 SET c1=10 where c2='b'; +SAVE TRANSACTION sp1; +INSERT INTO procTab1 values(1,'a'); +ROLLBACK TRANSACTION sp1; +INSERT INTO procTab1 values(2,'b'); +EXEC psql_interop_proc2; +GO + +-- psql currentSchema=master_dbo,public +CREATE PROCEDURE psql_interop_proc2() +AS +$$ +BEGIN + UPDATE procTab1 SET c1=c1+2 WHERE c1 BETWEEN 2 AND 10; + SAVEPOINT sp2; + INSERT INTO procTab1(c1,c2) values(13,'w'); + EXECUTE "ROLLBACK TO $1" USING sp2; + COMMIT; +END +$$ LANGUAGE PLPGSQL; +GO + +-- tsql +EXEC psql_interop_proc1 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: invalid transaction command)~~ + +SELECT * FROM procTab1 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "proctab1" does not exist)~~ + + +-- psql currentSchema=master_dbo,public +DROP PROCEDURE psql_interop_proc2 +GO + +-- psql currentSchema=master_dbo,public +CREATE PROCEDURE psql_interop_proc2() +AS +$$ +BEGIN + UPDATE procTab1 SET c1=c1+2 WHERE c1 BETWEEN 2 AND 10; + INSERT INTO procTab1(c1,c2) values(13,'w'); + COMMIT; +END +$$ LANGUAGE PLPGSQL; +GO + +-- tsql +EXEC psql_interop_proc1 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: invalid transaction command)~~ + +SELECT * FROM procTab1 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "proctab1" does not exist)~~ + +DROP PROCEDURE tsql_interop_proc1 +GO + +-- tsql +CREATE PROCEDURE tsql_interop_proc1 +AS +DECLARE @dt DATETIME = '2019-12-31 14:43:35.863'; +CREATE TABLE procTab1(c1 int, c2 char); +SELECT CONVERT(varchar(30), @dt, 1); +INSERT INTO procTab1 values(1,'a'); +ROLLBACK TRANSACTION sp1; +INSERT INTO procTab1 values(2,'b'); +SELECT CONVERT(varchar(30), CAST('2017-08-25' AS date), 102); +GO + +-- psql currentSchema=master_dbo,public +BEGIN TRANSACTION +GO +SAVEPOINT sp1 +GO +CALL tsql_interop_proc1() +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: invalid transaction command + Where: PL/tsql function tsql_interop_proc1() line 5 at SQL statement + Server SQLState: 2D000)~~ + +COMMIT +GO +SELECT * FROM procTab1 +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: relation "proctab1" does not exist + Position: 15 + Server SQLState: 42P01)~~ + + +-- tsql +BEGIN TRANSACTION +GO +SAVE TRANSACTION sp1 +GO +EXEC tsql_interop_proc1 +GO +~~START~~ +varchar +12/31/19 +~~END~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "proctab1" does not exist)~~ + +ROLLBACK +GO +~~ERROR (Code: 3903)~~ + +~~ERROR (Message: ROLLBACK can only be used in transaction blocks)~~ + +SELECT * FROM procTab1 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "proctab1" does not exist)~~ + + +-- tsql +CREATE PROCEDURE tsql_interop_proc +AS +DECLARE @handle int; +EXEC SP_PREPEXEC @handle OUT, NULL, 'SELECT ''OK''' +EXEC SP_EXECUTE @handle +EXEC SP_EXECUTE @handle +EXEC SP_UNPREPARE @handle +EXEC ('select datetimefromparts(2016, 12, 26, 23, 30, 5, 32);') +GO + +-- psql currentSchema=master_dbo,public +CREATE PROCEDURE psql_interop_proc() +AS +$$ +BEGIN +CALL tsql_interop_proc(); +END +$$ LANGUAGE PLPGSQL; +GO + +-- tsql +BEGIN TRANSACTION +GO +EXEC psql_interop_proc; +GO +~~START~~ +varchar +OK +~~END~~ + +~~START~~ +varchar +OK +~~END~~ + +~~START~~ +varchar +OK +~~END~~ + +~~START~~ +datetime +2016-12-26 23:30:05.033 +~~END~~ + +COMMIT +GO +DROP PROCEDURE tsql_interop_proc +GO + +-- tsql +CREATE PROCEDURE tsql_interop_proc +AS +DECLARE @handle INT; +DECLARE @batch VARCHAR(500); +SET @batch = 'begin transaction; insert into t1 values(1); commit;' +EXEC sp_prepare @handle OUT, NULL, @batch +EXEC sp_execute @handle +BEGIN TRANSACTION; +EXEC sp_execute @handle +ROLLBACK; +EXEC SP_UNPREPARE @handle; +GO + +-- tsql +CREATE TABLE t1 (a INT); +GO +EXEC psql_interop_proc; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: invalid transaction command)~~ + +SELECT count(*) FROM t1; +GO +~~START~~ +int +0 +~~END~~ + +DROP PROCEDURE tsql_interop_proc +GO +DROP TABLE t1 +GO + +-- tsql +CREATE PROCEDURE tsql_interop_proc +AS +DECLARE @handle int; +DECLARE @inner_handle int; +DECLARE @batch VARCHAR(500); +SET @batch = 'EXEC SP_PREPARE @inner_handle OUT, NULL, ''SELECT 1'' ' +EXEC SP_PREPARE @handle out, '@inner_handle int OUT', @batch +EXEC SP_EXECUTE @handle, @inner_handle OUT +BEGIN TRANSACTION; +EXEC SP_EXECUTE @inner_handle +ROLLBACK; +EXEC SP_UNPREPARE @inner_handle -- unprepare inner first +EXEC SP_UNPREPARE @handle +GO + +-- tsql +EXEC psql_interop_proc; +GO +~~START~~ +int +~~END~~ + +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: invalid transaction command)~~ + +DROP PROCEDURE tsql_interop_proc +GO + +-- tsql +CREATE PROCEDURE tsql_interop_proc +AS +CREATE TABLE cursorTab(a INT, b SMALLINT, c BIGINT, d TINYINT, e BIT); +INSERT INTO cursorTab values(0, 0, 0, 0, 0); +INSERT INTO cursorTab values(1, 2, 3, 4, 1); +INSERT INTO cursorTab values(4, 5, 6, 7, 4); +DECLARE @cursor_handle int; +EXEC sp_cursoropen @cursor_handle OUTPUT, 'select a,b,c,d from cursorTab', 2, 1; +EXEC sp_cursorfetch @cursor_handle, 2, 0, 2; +EXEC sp_cursoroption @cursor_handle, 1, 2; +BEGIN TRANSACTION; +EXEC sp_cursor @cursor_handle, 40, 1, ''; +COMMIT; +EXEC sp_cursorclose @cursor_handle; +GO + +EXEC psql_interop_proc; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#smallint#!#bigint#!#tinyint +0#!#0#!#0#!#0 +1#!#2#!#3#!#4 +~~END~~ + +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: invalid transaction command)~~ + +DROP PROCEDURE tsql_interop_proc +GO + +-- tsql +CREATE PROCEDURE tsql_interop_proc +AS +SELECT DATEPART(weekday, CAST( '2021-12-31' as DATE)); +SELECT DATENAME(year, cast('2002-05-23 23:41:29.998' as smalldatetime)); +SELECT @@DATEFIRST; +SELECT dateadd(year, 2, CAST('20060830' AS datetime)); +SELECT + lower(cast('A ' as char(5))), + left(cast('a ' as char(5)), 2), + charindex(cast('a ' as char(5)), 'a '), + ascii(cast('a ' as char(5))), + datalength(cast('123 ' as char(5))), + length(cast('123 ' as char(5))), + len(cast('123 ' as char(5))); +BEGIN TRANSACTION; +SELECT cast(cast('2021-08-15 ' as char(11)) as sys.smalldatetime); +COMMIT; +GO + +EXEC tsql_interop_proc; +GO +~~START~~ +int +6 +~~END~~ + +~~START~~ +text +2002 +~~END~~ + +~~START~~ +int +7 +~~END~~ + +~~START~~ +datetime +2008-08-30 00:00:00.0 +~~END~~ + +~~START~~ +text#!#text#!#int#!#int#!#int#!#int#!#int +a #!#a #!#0#!#97#!#5#!#5#!#3 +~~END~~ + +~~START~~ +smalldatetime +2021-08-15 00:00:00.0 +~~END~~ + +EXEC psql_interop_proc; +GO +~~START~~ +int +6 +~~END~~ + +~~START~~ +text +2002 +~~END~~ + +~~START~~ +int +7 +~~END~~ + +~~START~~ +datetime +2008-08-30 00:00:00.0 +~~END~~ + +~~START~~ +text#!#text#!#int#!#int#!#int#!#int#!#int +a #!#a #!#0#!#97#!#5#!#5#!#3 +~~END~~ + +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: invalid transaction command)~~ + +DROP PROCEDURE tsql_interop_proc +GO + +-- psql currentSchema=master_dbo,public +DROP PROCEDURE psql_interop_proc1 +GO +DROP PROCEDURE psql_interop_proc2 +GO + +-- tsql +DROP PROCEDURE tsql_interop_proc1 +GO + +-- psql currentSchema=master_dbo,public +DROP PROCEDURE psql_interop_proc +GO diff --git a/contrib/test/JDBC/expected/TestProcedureWithTriggers.out b/contrib/test/JDBC/expected/TestProcedureWithTriggers.out new file mode 100644 index 00000000000..c3f0a8ab8cd --- /dev/null +++ b/contrib/test/JDBC/expected/TestProcedureWithTriggers.out @@ -0,0 +1,1402 @@ +-- psql currentSchema=master_dbo,public +CREATE PROCEDURE psql_interop_proc1() +AS +$$ +BEGIN + CREATE TABLE triggerTab1(c1 int, c2 varchar(30)); + CREATE TABLE triggerTab2(c1 int); + INSERT INTO triggerTab1 VALUES(1, 'first'); + INSERT INTO triggerTab2 VALUES(1); +END +$$ LANGUAGE PLPGSQL; +GO + +-- tsql +EXEC psql_interop_proc1 +GO + +CREATE TRIGGER txnTrig1 ON triggerTab1 AFTER INSERT AS +INSERT INTO triggerTab2 VALUES(4); +UPDATE triggerTab2 set c1 = c1+2; +GO + +CREATE TRIGGER txnTrig2 ON triggerTab2 FOR UPDATE AS +INSERT INTO triggerTab2 VALUES(2); +UPDATE triggerTab1 set c1 = c1+2; +DELETE FROM triggerTab2; +INSERT INTO triggerTab2 values(2); +GO + +-- psql currentSchema=master_dbo,public +CREATE PROCEDURE psql_interop_proc2() +AS +$$ +BEGIN + INSERT INTO triggerTab1 VALUES(2, 'second'); + INSERT INTO triggerTab1 VALUES(3, 'third'); +END +$$ LANGUAGE PLPGSQL; +GO + +-- tsql +CREATE PROCEDURE tsql_interop_proc +AS +INSERT INTO triggerTab1 VALUES(2, 'second'); +INSERT INTO triggerTab1 VALUES(3, 'third'); +GO + +-- tsql +EXEC tsql_interop_proc +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 2~~ + +~~ROW COUNT: 3~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 2~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 3~~ + +~~ROW COUNT: 3~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 2~~ + +~~ROW COUNT: 1~~ + +SELECT * from triggerTab1 ORDER BY c1; +GO +~~START~~ +int#!#varchar +5#!#first +5#!#third +6#!#second +~~END~~ + + +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~~ + +~~ROW COUNT: 2~~ + +SELECT * from triggerTab2 ORDER BY c1; +GO +~~START~~ +int +2 +~~END~~ + + +-- psql currentSchema=master_dbo,public +CALL tsql_interop_proc(); +GO +SELECT * from triggerTab1 ORDER BY c1; +GO +~~START~~ +int4#!#varchar +5#!#third +6#!#second +9#!#third +10#!#second +13#!#first +13#!#third +14#!#second +~~END~~ + + +CALL psql_interop_proc2(); +GO +SELECT * from triggerTab2 ORDER BY c1; +GO +~~START~~ +int4 +2 +~~END~~ + + +-- tsql +BEGIN TRANSACTION +GO +EXEC tsql_interop_proc +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 10~~ + +~~ROW COUNT: 3~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 2~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 11~~ + +~~ROW COUNT: 3~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 2~~ + +~~ROW COUNT: 1~~ + +SELECT * from triggerTab1 ORDER BY c1; +GO +~~START~~ +int#!#varchar +5#!#third +6#!#second +9#!#third +10#!#second +13#!#third +14#!#second +17#!#third +18#!#second +21#!#first +21#!#third +22#!#second +~~END~~ + +COMMIT +GO + +-- psql currentSchema=master_dbo,public +BEGIN TRANSACTION +GO +CALL tsql_interop_proc(); +GO +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~~ + +ROLLBACK +GO + +-- tsql +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~~ + +~~ROW COUNT: 2~~ + +SELECT * from triggerTab2 ORDER BY c1; +GO +~~START~~ +int +2 +~~END~~ + +ROLLBACK +GO + +-- psql currentSchema=master_dbo,public +BEGIN TRANSACTION +GO +CALL psql_interop_proc2(); +GO +SELECT * from triggerTab2 ORDER BY c1; +GO +~~START~~ +int4 +2 +~~END~~ + +COMMIT +GO + +-- tsql +BEGIN TRANSACTION +GO +SAVE TRANSACTION sp1; +GO +EXEC psql_interop_proc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~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~~ + +ROLLBACK TRANSACTION sp1; +GO +SELECT * from triggerTab1 ORDER BY c1; +GO +~~START~~ +int#!#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~~ + +COMMIT +GO + +-- tsql +BEGIN TRANSACTION +GO +SAVE TRANSACTION sp1; +GO +EXEC tsql_interop_proc +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 14~~ + +~~ROW COUNT: 3~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 2~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 15~~ + +~~ROW COUNT: 3~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 2~~ + +~~ROW COUNT: 1~~ + +ROLLBACK TRANSACTION sp1; +GO +SELECT * from triggerTab2 ORDER BY c1; +GO +~~START~~ +int +2 +~~END~~ + +COMMIT +GO + +-- psql currentSchema=master_dbo,public +BEGIN TRANSACTION +GO +SAVEPOINT sp1; +GO +CALL tsql_interop_proc(); +GO +ROLLBACK TO sp1; +GO +SELECT * from triggerTab2 ORDER BY c1; +GO +~~START~~ +int4 +2 +~~END~~ + +COMMIT +GO + +-- tsql +DROP PROCEDURE tsql_interop_proc; +GO + +CREATE PROCEDURE tsql_interop_proc +AS +BEGIN TRANSACTION; +INSERT INTO triggerTab1 VALUES(2, 'second'); +COMMIT; +GO + +-- tsql +EXEC tsql_interop_proc +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 14~~ + +~~ROW COUNT: 3~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 2~~ + +~~ROW COUNT: 1~~ + +SELECT * from triggerTab1 ORDER BY c1; +GO +~~START~~ +int#!#varchar +4#!#second +7#!#third +8#!#second +11#!#third +12#!#second +15#!#third +16#!#second +19#!#third +20#!#second +23#!#third +24#!#second +27#!#first +27#!#third +28#!#second +~~END~~ + + +-- psql currentSchema=master_dbo,public +CALL tsql_interop_proc(); +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: invalid transaction command + Where: PL/tsql function tsql_interop_proc() line 1 at SQL statement + Server SQLState: 2D000)~~ + +SELECT * from triggerTab2 ORDER BY c1; +GO +~~START~~ +int4 +2 +~~END~~ + + +-- tsql +DROP PROCEDURE tsql_interop_proc; +GO + +CREATE PROCEDURE tsql_interop_proc +AS +BEGIN TRANSACTION; +INSERT INTO triggerTab1 VALUES(2, 'second'); +ROLLBACK; +INSERT INTO triggerTab1 VALUES(3, 'third'); +GO + +-- tsql +EXEC tsql_interop_proc +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 15~~ + +~~ROW COUNT: 3~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 2~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 15~~ + +~~ROW COUNT: 3~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 2~~ + +~~ROW COUNT: 1~~ + +SELECT * from triggerTab1 ORDER BY c1; +GO +~~START~~ +int#!#varchar +5#!#third +6#!#second +9#!#third +10#!#second +13#!#third +14#!#second +17#!#third +18#!#second +21#!#third +22#!#second +25#!#third +26#!#second +29#!#first +29#!#third +30#!#second +~~END~~ + + +-- psql currentSchema=master_dbo,public +CALL tsql_interop_proc(); +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: invalid transaction command + Where: PL/tsql function tsql_interop_proc() line 1 at SQL statement + Server SQLState: 2D000)~~ + +SELECT * from triggerTab2 ORDER BY c1; +GO +~~START~~ +int4 +2 +~~END~~ + + +-- tsql +DROP PROCEDURE tsql_interop_proc; +GO + +CREATE PROCEDURE tsql_interop_proc +AS +BEGIN TRANSACTION; +INSERT INTO triggerTab1 VALUES(2, 'second'); +SAVE TRANSACTION sp1; +INSERT INTO triggerTab1 VALUES(3, 'third'); +ROLLBACK TRANSACTION sp1; +COMMIT; +GO + +-- tsql +EXEC tsql_interop_proc +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 16~~ + +~~ROW COUNT: 3~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 2~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 17~~ + +~~ROW COUNT: 3~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 2~~ + +~~ROW COUNT: 1~~ + +SELECT * FROM triggerTab1 ORDER BY c1; +GO +~~START~~ +int#!#varchar +4#!#second +7#!#third +8#!#second +11#!#third +12#!#second +15#!#third +16#!#second +19#!#third +20#!#second +23#!#third +24#!#second +27#!#third +28#!#second +31#!#first +31#!#third +32#!#second +~~END~~ + + +-- psql currentSchema=master_dbo,public +CALL tsql_interop_proc(); +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: invalid transaction command + Where: PL/tsql function tsql_interop_proc() line 1 at SQL statement + Server SQLState: 2D000)~~ + +SELECT * FROM triggerTab2 ORDER BY c1; +GO +~~START~~ +int4 +2 +~~END~~ + + +-- tsql +DROP TRIGGER txnTrig1; +GO +DROP TRIGGER txnTrig2; +GO +DROP TABLE triggerTab1; +GO +DROP TABLE triggerTab2; +GO +CREATE PROCEDURE tsql_create_table +AS + CREATE TABLE triggerTab1(c1 int, c2 varchar(30)); + CREATE TABLE triggerTab2(c1 int); + INSERT INTO triggerTab1 VALUES(1, 'first'); + INSERT INTO triggerTab2 VALUES(1); +GO +EXEC tsql_create_table; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +-- psql currentSchema=master_dbo,public +CREATE FUNCTION trigger_txnTrig3() + RETURNS TRIGGER + LANGUAGE PLPGSQL +AS $$ +BEGIN + UPDATE triggerTab1 set c1 = c1/2; + DELETE FROM triggerTab2; + RETURN NEW; +END; +$$ +GO + +CREATE TRIGGER txnTrig3 +AFTER DELETE ON triggerTab1 +FOR EACH ROW +EXECUTE PROCEDURE trigger_txnTrig3(); +GO + +-- tsql +CREATE TRIGGER txnTrig1 ON triggerTab1 AFTER INSERT AS +INSERT INTO triggerTab2 VALUES(4); +UPDATE triggerTab2 set c1 = c1+2; +GO + +CREATE TRIGGER txnTrig2 ON triggerTab2 FOR UPDATE AS +INSERT INTO triggerTab2 VALUES(2); +UPDATE triggerTab1 set c1 = c1+2; +DELETE FROM triggerTab2; +INSERT INTO triggerTab2 values(2); +GO + +-- psql currentSchema=master_dbo,public +CALL psql_interop_proc2(); +GO +SELECT * FROM triggerTab1 ORDER BY c1; +GO +~~START~~ +int4#!#"sys"."varchar" +5#!#first +5#!#third +6#!#second +~~END~~ + + +-- tsql +BEGIN TRANSACTION +GO +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~~ + +~~ROW COUNT: 2~~ + +SELECT * FROM triggerTab2 ORDER BY c1; +GO +~~START~~ +int +2 +~~END~~ + +COMMIT +GO + +-- tsql +DROP TRIGGER txnTrig1; +GO +DROP TRIGGER txnTrig2; +GO +DROP TRIGGER txnTrig3; +GO +DROP FUNCTION trigger_txnTrig3; +GO + +-- tsql +CREATE TRIGGER txnTrig1 ON triggerTab1 AFTER INSERT AS +SELECT * FROM inserted; +UPDATE triggerTab2 set c1 = c1+2; +COMMIT; +GO + +CREATE TRIGGER txnTrig2 ON triggerTab2 FOR UPDATE AS +INSERT INTO triggerTab2 VALUES(2); +SELECT * FROM deleted; +DELETE FROM triggerTab1; +GO + +DROP PROCEDURE tsql_interop_proc +GO +CREATE PROCEDURE tsql_interop_proc +AS +BEGIN TRANSACTION; +INSERT INTO triggerTab1 VALUES(3, 'third'); +GO + +-- tsql +EXEC tsql_interop_proc +GO +~~START~~ +int#!#varchar +3#!#third +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +2 +~~END~~ + +~~ROW COUNT: 6~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 3609)~~ + +~~ERROR (Message: The transaction ended in the trigger. The batch has been aborted.)~~ + +SELECT * from triggerTab1 ORDER BY c1; +GO +~~START~~ +int#!#varchar +~~END~~ + + +-- psql currentSchema=master_dbo,public +CALL tsql_interop_proc(); +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: invalid transaction command + Where: PL/tsql function tsql_interop_proc() line 1 at SQL statement + Server SQLState: 2D000)~~ + +SELECT * from triggerTab1 ORDER BY c1; +GO +~~START~~ +int4#!#"sys"."varchar" +~~END~~ + + +-- tsql +DROP TRIGGER txnTrig1; +GO +CREATE TRIGGER txnTrig1 ON triggerTab1 AFTER INSERT AS +BEGIN TRANSACTION; +UPDATE triggerTab2 set c1 = c1+2; +COMMIT; +GO + +DROP PROCEDURE tsql_interop_proc; +GO +CREATE PROCEDURE tsql_interop_proc +AS +INSERT INTO triggerTab1 VALUES(2, 'second'); +GO + +-- tsql +EXEC tsql_interop_proc +GO +~~ROW COUNT: 1~~ + +~~START~~ +int +4 +2 +~~END~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 2~~ + +~~ROW COUNT: 1~~ + +SELECT * from triggerTab2 ORDER BY c1; +GO +~~START~~ +int +2 +4 +6 +~~END~~ + + +-- psql currentSchema=master_dbo,public +CALL tsql_interop_proc(); +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: invalid transaction command + Where: PL/tsql function txntrig1() line 1 at SQL statement +PL/tsql function tsql_interop_proc() line 1 at SQL statement + Server SQLState: 2D000)~~ + +SELECT * from triggerTab2 ORDER BY c1; +GO +~~START~~ +int4 +2 +4 +6 +~~END~~ + + +-- tsql +DROP TRIGGER txnTrig1; +GO + +CREATE TRIGGER txnTrig1 ON triggerTab1 AFTER INSERT AS +BEGIN TRANSACTION; +SELECT * FROM inserted; +UPDATE triggerTab2 set c1 = c1+2; +GO + +DROP PROCEDURE tsql_interop_proc; +GO +CREATE PROCEDURE tsql_interop_proc +AS +INSERT INTO triggerTab1 VALUES(3, 'third'); +SAVE TRANSACTION sp1; +INSERT INTO triggerTab2 VALUES(3); +ROLLBACK TRANSACTION sp1; +COMMIT; +GO + +-- tsql +EXEC tsql_interop_proc +GO +~~START~~ +int#!#varchar +3#!#third +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +6 +4 +2 +~~END~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 3~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +SELECT * from triggerTab2 ORDER BY c1; +GO +~~START~~ +int +2 +4 +6 +8 +~~END~~ + + +-- psql currentSchema=master_dbo,public +CALL tsql_interop_proc(); +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: invalid transaction command + Where: PL/tsql function txntrig1() line 1 at SQL statement +PL/tsql function tsql_interop_proc() line 1 at SQL statement + Server SQLState: 2D000)~~ + +SELECT * from triggerTab1 ORDER BY c1; +GO +~~START~~ +int4#!#"sys"."varchar" +~~END~~ + + +-- tsql +DROP TRIGGER txnTrig1; +GO + +CREATE TRIGGER txnTrig1 ON triggerTab1 AFTER INSERT AS +SAVE TRANSACTION sp1; +SELECT * FROM inserted; +UPDATE triggerTab2 set c1 = c1+2; +GO + +DROP PROCEDURE tsql_interop_proc; +GO +CREATE PROCEDURE tsql_interop_proc +AS +BEGIN TRANSACTION; +INSERT INTO triggerTab1 VALUES(3, 'third'); +INSERT INTO triggerTab2 VALUES(3); +ROLLBACK TRANSACTION sp1; +COMMIT; +GO + +-- tsql +EXEC tsql_interop_proc +GO +~~START~~ +int#!#varchar +3#!#third +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +8 +6 +4 +2 +~~END~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 4~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +SELECT * from triggerTab2 ORDER BY c1; +GO +~~START~~ +int +2 +4 +6 +8 +~~END~~ + + +-- psql currentSchema=master_dbo,public +CALL tsql_interop_proc(); +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: invalid transaction command + Where: PL/tsql function tsql_interop_proc() line 1 at SQL statement + Server SQLState: 2D000)~~ + +SELECT * from triggerTab1 ORDER BY c1; +GO +~~START~~ +int4#!#"sys"."varchar" +3#!#third +~~END~~ + + +-- tsql +DROP TRIGGER txnTrig1; +GO + +CREATE TRIGGER txnTrig1 ON triggerTab1 AFTER INSERT AS +ROLLBACK TRANSACTION sp1; +UPDATE triggerTab2 set c1 = c1+2; +GO + +DROP PROCEDURE tsql_interop_proc; +GO +CREATE PROCEDURE tsql_interop_proc +AS +BEGIN TRANSACTION; +SAVE TRANSACTION sp1; +INSERT INTO triggerTab1 VALUES(3, 'third'); +INSERT INTO triggerTab2 VALUES(3); +COMMIT; +GO + +-- tsql +EXEC tsql_interop_proc +GO +~~ROW COUNT: 1~~ + +~~START~~ +int +8 +6 +4 +2 +~~END~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 4~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +SELECT * from triggerTab2 ORDER BY c1; +GO +~~START~~ +int +2 +3 +4 +6 +8 +10 +~~END~~ + + +-- psql currentSchema=master_dbo,public +CALL tsql_interop_proc(); +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: invalid transaction command + Where: PL/tsql function tsql_interop_proc() line 1 at SQL statement + Server SQLState: 2D000)~~ + +SELECT * from triggerTab1 ORDER BY c1; +GO +~~START~~ +int4#!#"sys"."varchar" +~~END~~ + + +-- tsql +DROP TRIGGER txnTrig1; +GO + +CREATE TRIGGER txnTrig1 ON triggerTab1 AFTER INSERT AS +SELECT * FROM inserted; +SAVE TRANSACTION sp1; +UPDATE triggerTab2 set c1 = c1+2; +ROLLBACK TRANSACTION sp1; +GO + +DROP PROCEDURE tsql_interop_proc; +GO +CREATE PROCEDURE tsql_interop_proc +AS +BEGIN TRANSACTION; +INSERT INTO triggerTab1 VALUES(3, 'third'); +INSERT INTO triggerTab2 VALUES(3); +COMMIT; +GO + +-- tsql +EXEC tsql_interop_proc +GO +~~START~~ +int#!#varchar +3#!#third +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +10 +8 +6 +4 +2 +3 +~~END~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 6~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +SELECT * from triggerTab2 ORDER BY c1; +GO +~~START~~ +int +2 +3 +3 +4 +6 +8 +10 +~~END~~ + + +-- psql currentSchema=master_dbo,public +CALL tsql_interop_proc(); +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: invalid transaction command + Where: PL/tsql function tsql_interop_proc() line 1 at SQL statement + Server SQLState: 2D000)~~ + +SELECT * from triggerTab1 ORDER BY c1; +GO +~~START~~ +int4#!#"sys"."varchar" +3#!#third +~~END~~ + + +-- tsql +DROP TRIGGER txnTrig1; +GO + +CREATE TRIGGER txnTrig1 ON triggerTab1 AFTER INSERT AS +SELECT * FROM inserted; +SAVE TRANSACTION sp1; +UPDATE triggerTab2 set c1 = c1+2; +COMMIT; +GO + +DROP PROCEDURE tsql_interop_proc; +GO +CREATE PROCEDURE tsql_interop_proc +AS +BEGIN TRANSACTION; +INSERT INTO triggerTab1 VALUES(3, 'third'); +INSERT INTO triggerTab2 VALUES(3); +GO + +-- tsql +EXEC tsql_interop_proc +GO +~~START~~ +int#!#varchar +3#!#third +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +10 +8 +6 +4 +2 +3 +3 +~~END~~ + +~~ROW COUNT: 2~~ + +~~ROW COUNT: 7~~ + +~~ERROR (Code: 3609)~~ + +~~ERROR (Message: The transaction ended in the trigger. The batch has been aborted.)~~ + +SELECT * from triggerTab2 ORDER BY c1; +GO +~~START~~ +int +2 +4 +5 +5 +6 +8 +10 +12 +~~END~~ + + +-- psql currentSchema=master_dbo,public +CALL tsql_interop_proc(); +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: invalid transaction command + Where: PL/tsql function tsql_interop_proc() line 1 at SQL statement + Server SQLState: 2D000)~~ + +SELECT * from triggerTab1 ORDER BY c1; +GO +~~START~~ +int4#!#"sys"."varchar" +~~END~~ + + +-- tsql +DROP TRIGGER txnTrig1; +GO +DROP TRIGGER txnTrig2; +GO + +CREATE TRIGGER txnTrig1 ON triggerTab1 AFTER INSERT AS +SELECT * FROM inserted; +SAVE TRANSACTION sp1; +SELECT dateadd(year, 2, CAST('20060830' AS datetime)); +UPDATE triggerTab2 set c1 = c1+2; +GO + +CREATE TRIGGER txnTrig2 ON triggerTab2 FOR UPDATE AS +SELECT * FROM inserted; +INSERT INTO triggerTab2 VALUES(2); +SELECT * FROM deleted; +EXEC tsql_interop_proc1; +SELECT * FROM table_interop('tsql_interop','psql_interop'); +ROLLBACK TRANSACTION sp1; +DELETE FROM triggerTab1; +GO + +CREATE PROCEDURE tsql_interop_proc1 +AS +SELECT datepart(week, CAST('2007-04-21' AS date)), datepart(weekday, CAST('2007-04-21' AS date)); +GO + +DROP PROCEDURE tsql_interop_proc; +GO +CREATE PROCEDURE tsql_interop_proc +AS +BEGIN TRANSACTION; +INSERT INTO triggerTab1 VALUES(3, 'third'); +INSERT INTO triggerTab2 VALUES(3); +COMMIT; +GO + +CREATE FUNCTION table_interop (@arg1 varchar(5), @arg2 varchar(10)) +RETURNS TABLE AS RETURN +(SELECT @arg1 as a, @arg2 as b) +GO + +-- tsql +EXEC tsql_interop_proc +GO +~~START~~ +int#!#varchar +3#!#third +~~END~~ + +~~START~~ +datetime +2008-08-30 00:00:00.0 +~~END~~ + +~~START~~ +int +14 +12 +10 +8 +6 +7 +7 +4 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +12 +10 +8 +6 +4 +5 +5 +2 +~~END~~ + +~~START~~ +int#!#int +16#!#7 +~~END~~ + +~~START~~ +varchar#!#varchar +tsql_#!#psql_inter +~~END~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 8~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +SELECT * from triggerTab2 ORDER BY c1; +GO +~~START~~ +int +2 +3 +4 +5 +5 +6 +8 +10 +12 +~~END~~ + +DROP TRIGGER txnTrig1; +GO +DROP TRIGGER txnTrig2; +GO + +-- psql currentSchema=master_dbo,public +DROP PROCEDURE psql_interop_proc1; +GO +DROP PROCEDURE psql_interop_proc2; +GO + +-- tsql +DROP FUNCTION table_interop; +GO +DROP PROCEDURE tsql_create_table; +GO +DROP PROCEDURE tsql_interop_proc; +GO +DROP PROCEDURE tsql_interop_proc1; +GO +DROP TABLE triggerTab1; +GO +DROP TABLE triggerTab2; +GO diff --git a/contrib/test/JDBC/expected/TestRaiserror.out b/contrib/test/JDBC/expected/TestRaiserror.out new file mode 100644 index 00000000000..855c9d2bfe3 --- /dev/null +++ b/contrib/test/JDBC/expected/TestRaiserror.out @@ -0,0 +1,754 @@ +CREATE TABLE raiserrorTable (a INT); +go + +CREATE PROC raiserrorProc1 AS +BEGIN + INSERT INTO raiserrorTable VALUES (1); + RAISERROR ('raiserror 16', 16, 1); + INSERT INTO raiserrorTable VALUES (2); +END +go + +CREATE PROC raiserrorProc2 AS +BEGIN + INSERT INTO raiserrorTable VALUES (111); + EXEC raiserrorProc1; + INSERT INTO raiserrorTable VALUES (222); +END +go + +CREATE PROC raiserrorProc3 AS +BEGIN + BEGIN TRY + RAISERROR ('raiserror 16', 16, 1); + END TRY + BEGIN CATCH + INSERT INTO raiserrorTable VALUES (11); + RAISERROR ('raiserror 16', 16, 1); + INSERT INTO raiserrorTable VALUES (12); + END CATCH +END +go + + + + + +/* XACT_ABORT OFF */ +/* 1. Not in TRY...CATCH block, terminates nothing */ +/* Not in TRY...CATCH block */ +RAISERROR('raiserror 0', 0, 1); +DECLARE @m1 NVARCHAR(10); +DECLARE @m2 VARCHAR(10); +DECLARE @m3 NCHAR(10); +DECLARE @m4 CHAR(10); +SET @m1 = 'raiserror 0'; +SET @m2 = 'raiserror 0'; +SET @m3 = 'raiserror 0'; +SET @m4 = 'raiserror 0'; +RAISERROR(@m1, 0, 1); +RAISERROR(@m2, 0, 2); +RAISERROR(@m3, 0, 3); +RAISERROR(@m4, 0, 4); +go + +DECLARE @msg_id INT; +DECLARE @severity INT; +DECLARE @state INT; +SET @msg_id = 51000; +SET @severity = 0; +SET @state = 1; +RAISERROR(@msg_id, @severity, @state) WITH LOG, NOWAIT, SETERROR; +go + +BEGIN TRANSACTION + INSERT INTO raiserrorTable VALUES (3); + RAISERROR('raiserror 16', 16, 1); + INSERT INTO raiserrorTable VALUES (4); +go +~~ROW COUNT: 1~~ + +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: raiserror 16)~~ + +~~ROW COUNT: 1~~ + +SELECT xact_state(); +SELECT @@trancount; +SELECT * FROM raiserrorTable; +IF @@trancount > 0 ROLLBACK TRANSACTION; +go +~~START~~ +smallint +1 +~~END~~ + +~~START~~ +int +1 +~~END~~ + +~~START~~ +int +3 +4 +~~END~~ + +TRUNCATE TABLE raiserrorTable +go + +/* Nested procedure call */ +BEGIN TRANSACTION + EXEC raiserrorProc2; +go +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: raiserror 16)~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +SELECT xact_state(); +SELECT @@trancount; +SELECT * FROM raiserrorTable; +IF @@trancount > 0 ROLLBACK TRANSACTION; +go +~~START~~ +smallint +1 +~~END~~ + +~~START~~ +int +1 +~~END~~ + +~~START~~ +int +111 +1 +2 +222 +~~END~~ + +TRUNCATE TABLE raiserrorTable +go + +/* 2. In TRY...CATCH block, catchable */ +/* RAISERROR in TRY...CATCH */ +BEGIN TRY + BEGIN TRANSACTION + RAISERROR('raiserror 10', 10, 1); + INSERT INTO raiserrorTable VALUES (3); + RAISERROR('raiserror 16', 16, 1); + INSERT INTO raiserrorTable VALUES (4); + COMMIT TRANSACTION +END TRY +BEGIN CATCH + SELECT xact_state(); + SELECT @@trancount; + SELECT * FROM raiserrorTable; + IF @@trancount > 0 ROLLBACK TRANSACTION; +END CATCH +go +~~ROW COUNT: 1~~ + +~~START~~ +smallint +1 +~~END~~ + +~~START~~ +int +1 +~~END~~ + +~~START~~ +int +3 +~~END~~ + +TRUNCATE TABLE raiserrorTable +go + +/* Procedure call in TRY...CATCH */ +BEGIN TRY + BEGIN TRANSACTION + SELECT xact_state(); + EXEC raiserrorProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); + SELECT @@trancount; + SELECT * FROM raiserrorTable; + IF @@trancount > 0 ROLLBACK TRANSACTION; +END CATCH +go +~~START~~ +smallint +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +smallint +1 +~~END~~ + +~~START~~ +int +1 +~~END~~ + +~~START~~ +int +1 +~~END~~ + +TRUNCATE TABLE raiserrorTable +go + +/* Error in both TRY...CATCH */ +BEGIN TRY + BEGIN TRANSACTION + INSERT INTO raiserrorTable VALUES(1); + RAISERROR('raiserror 16', 16, 1); + INSERT INTO raiserrorTable VALUES(3); +END TRY +BEGIN CATCH + INSERT INTO raiserrorTable VALUES (5); + RAISERROR('raiserror 16', 16, 1); + INSERT INTO raiserrorTable VALUES (7); + SELECT * FROM raiserrorTable + IF @@trancount > 0 ROLLBACK TRANSACTION; +END CATCH +go +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: raiserror 16)~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +1 +5 +7 +~~END~~ + +TRUNCATE TABLE raiserrorTable +go + +/* Error in nested CATCH */ +BEGIN TRY + BEGIN TRANSACTION + INSERT INTO raiserrorTable VALUES(1); + EXEC raiserrorProc3; + INSERT INTO raiserrorTable VALUES(3); +END TRY +BEGIN CATCH + INSERT INTO raiserrorTable VALUES (5); + RAISERROR('raiserror 16', 16, 1); + INSERT INTO raiserrorTable VALUES (7); + SELECT * FROM raiserrorTable + IF @@trancount > 0 ROLLBACK TRANSACTION; +END CATCH +go +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: raiserror 16)~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +1 +11 +5 +7 +~~END~~ + +TRUNCATE TABLE raiserrorTable +go + +/* Error in CATCH chain */ +BEGIN TRY + BEGIN TRANSACTION + INSERT INTO raiserrorTable VALUES(1); + RAISERROR('raiserror 16', 16, 1); + INSERT INTO raiserrorTable VALUES(3); +END TRY +BEGIN CATCH + INSERT INTO raiserrorTable VALUES (5); + EXEC raiserrorProc3; + INSERT INTO raiserrorTable VALUES (7); + SELECT * FROM raiserrorTable + IF @@trancount > 0 ROLLBACK TRANSACTION; +END CATCH +go +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: raiserror 16)~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +1 +5 +11 +12 +7 +~~END~~ + +TRUNCATE TABLE raiserrorTable +go + + +/* Nested TRY..CATCH, test 1 */ +BEGIN TRY + BEGIN TRY + INSERT INTO raiserrorTable VALUES (3); + RAISERROR('raiserror 16', 16, 1); + INSERT INTO raiserrorTable VALUES (4); + END TRY + BEGIN CATCH + INSERT INTO raiserrorTable VALUES (5); + END CATCH +END TRY +BEGIN CATCH + INSERT INTO raiserrorTable VALUES (6); +END CATCH +go +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +SELECT * FROM raiserrorTable +go +~~START~~ +int +3 +5 +~~END~~ + +TRUNCATE TABLE raiserrorTable +go + +/* Nested TRY...CATCH, test 2 */ +BEGIN TRY + BEGIN TRY + SELECT 100/0; + END TRY + BEGIN CATCH + INSERT INTO raiserrorTable VALUES (3); + RAISERROR('raiserror 16', 16, 1); + INSERT INTO raiserrorTable VALUES (4); + END CATCH +END TRY +BEGIN CATCH + INSERT INTO raiserrorTable VALUES (5); +END CATCH +go +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +SELECT * FROM raiserrorTable +go +~~START~~ +int +3 +5 +~~END~~ + +TRUNCATE TABLE raiserrorTable +go + +/* Nested TRY...CATCH, test 3 */ +BEGIN TRY + SELECT 100/0; +END TRY +BEGIN CATCH + BEGIN TRY + INSERT INTO raiserrorTable VALUES (3); + RAISERROR('raiserror 16', 16, 1); + INSERT INTO raiserrorTable VALUES (4); + END TRY + BEGIN CATCH + INSERT INTO raiserrorTable VALUES (5); + END CATCH +END CATCH +go +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +SELECT * FROM raiserrorTable +go +~~START~~ +int +3 +5 +~~END~~ + +TRUNCATE TABLE raiserrorTable +go + +/* XACT_ABORT ON, RAISERROR does not honor XACT_ABORT */ +SET XACT_ABORT ON; +go + +/* 1. Not in TRY...CATCH block, terminates nothing */ +/* Not in TRY...CATCH block */ +BEGIN TRANSACTION + INSERT INTO raiserrorTable VALUES (3); + RAISERROR('raiserror 16', 16, 1); + INSERT INTO raiserrorTable VALUES (4); +go +~~ROW COUNT: 1~~ + +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: raiserror 16)~~ + +~~ROW COUNT: 1~~ + +SELECT xact_state(); +SELECT @@trancount; +SELECT * FROM raiserrorTable; +IF @@trancount > 0 ROLLBACK TRANSACTION; +go +~~START~~ +smallint +1 +~~END~~ + +~~START~~ +int +1 +~~END~~ + +~~START~~ +int +3 +4 +~~END~~ + +TRUNCATE TABLE raiserrorTable +go + +/* Nested procedure call */ +BEGIN TRANSACTION + EXEC raiserrorProc2; +go +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: raiserror 16)~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +SELECT xact_state(); +SELECT @@trancount; +SELECT * FROM raiserrorTable; +IF @@trancount > 0 ROLLBACK TRANSACTION; +go +~~START~~ +smallint +1 +~~END~~ + +~~START~~ +int +1 +~~END~~ + +~~START~~ +int +111 +1 +2 +222 +~~END~~ + +TRUNCATE TABLE raiserrorTable +go + +/* 2. In TRY...CATCH block, catchable */ +/* RAISERROR in TRY...CATCH */ +BEGIN TRY + BEGIN TRANSACTION + RAISERROR('raiserror 10', 10, 1); + INSERT INTO raiserrorTable VALUES (3); + RAISERROR('raiserror 16', 16, 1); + INSERT INTO raiserrorTable VALUES (4); + COMMIT TRANSACTION +END TRY +BEGIN CATCH + SELECT xact_state(); + SELECT @@trancount; + SELECT * FROM raiserrorTable; + IF @@trancount > 0 ROLLBACK TRANSACTION; +END CATCH +go +~~ROW COUNT: 1~~ + +~~START~~ +smallint +-1 +~~END~~ + +~~START~~ +int +1 +~~END~~ + +~~START~~ +int +3 +~~END~~ + +TRUNCATE TABLE raiserrorTable +go + +/* Procedure call in TRY...CATCH */ +BEGIN TRY + BEGIN TRANSACTION + SELECT xact_state(); + EXEC raiserrorProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); + SELECT @@trancount; + SELECT * FROM raiserrorTable; + IF @@trancount > 0 ROLLBACK TRANSACTION; +END CATCH +go +~~START~~ +smallint +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +smallint +-1 +~~END~~ + +~~START~~ +int +1 +~~END~~ + +~~START~~ +int +1 +~~END~~ + +TRUNCATE TABLE raiserrorTable +go + +/* Nested TRY..CATCH, test 1 */ +BEGIN TRY + BEGIN TRY + INSERT INTO raiserrorTable VALUES (3); + RAISERROR('raiserror 16', 16, 1); + INSERT INTO raiserrorTable VALUES (4); + END TRY + BEGIN CATCH + INSERT INTO raiserrorTable VALUES (5); + END CATCH +END TRY +BEGIN CATCH + INSERT INTO raiserrorTable VALUES (6); +END CATCH +go +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +SELECT * FROM raiserrorTable +go +~~START~~ +int +3 +5 +~~END~~ + +TRUNCATE TABLE raiserrorTable +go + +/* Nested TRY...CATCH, test 2 */ +BEGIN TRY + BEGIN TRY + SELECT 100/0; + END TRY + BEGIN CATCH + INSERT INTO raiserrorTable VALUES (3); + RAISERROR('raiserror 16', 16, 1); + INSERT INTO raiserrorTable VALUES (4); + END CATCH +END TRY +BEGIN CATCH + INSERT INTO raiserrorTable VALUES (5); +END CATCH +go +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +SELECT * FROM raiserrorTable +TRUNCATE TABLE raiserrorTable +go +~~START~~ +int +3 +5 +~~END~~ + + +/* Nested TRY...CATCH, test 3 */ +BEGIN TRY + SELECT 100/0; +END TRY +BEGIN CATCH + BEGIN TRY + INSERT INTO raiserrorTable VALUES (3); + RAISERROR('raiserror 16', 16, 1); + INSERT INTO raiserrorTable VALUES (4); + END TRY + BEGIN CATCH + INSERT INTO raiserrorTable VALUES (5); + END CATCH +END CATCH +go +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +SELECT * FROM raiserrorTable +go +~~START~~ +int +3 +5 +~~END~~ + +TRUNCATE TABLE raiserrorTable +go + +/* + * SETERROR option + * 1. Outside TRY...CATCH, SETERROR would set @@ERROR to specified msg_id + * or 50000, regardless of the severity level + * 2. Inside TRY...CATCH, @@ERROR is always set to the captured error number + * with or without SETERROR + * TODO: After full support, @@ERROR should return user defined error number + */ +DECLARE @err INT; +RAISERROR(51000, 10, 1); +SET @err = @@ERROR; IF @err = 0 SELECT 0 ELSE SELECT 1; +RAISERROR(51000, 10, 2) WITH SETERROR; +SET @err = @@ERROR; IF @err = 0 SELECT 0 ELSE SELECT 1; +RAISERROR('raiserror 16', 16, 1); +SET @err = @@ERROR; IF @err = 0 SELECT 0 ELSE SELECT 1; +RAISERROR('raiserror 16', 16, 2) WITH SETERROR; +SET @err = @@ERROR; IF @err = 0 SELECT 0 ELSE SELECT 1; +go +~~START~~ +int +0 +~~END~~ + +~~START~~ +int +1 +~~END~~ + +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: raiserror 16)~~ + +~~START~~ +int +1 +~~END~~ + +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: raiserror 16)~~ + +~~START~~ +int +1 +~~END~~ + + +DECLARE @err INT; +BEGIN TRY + BEGIN TRY + RAISERROR(51000, 16, 1); + END TRY + BEGIN CATCH + SET @err = @@ERROR; IF @err = 0 SELECT 0 ELSE SELECT 1; + RAISERROR(51000, 16, 2) WITH SETERROR; + END CATCH +END TRY +BEGIN CATCH + SET @err = @@ERROR; IF @err = 0 SELECT 0 ELSE SELECT 1; +END CATCH +go +~~START~~ +int +1 +~~END~~ + +~~START~~ +int +1 +~~END~~ + + +/* Clean up */ +SET XACT_ABORT OFF; +go +DROP PROC raiserrorProc1; +go +DROP PROC raiserrorProc2; +go +DROP PROC raiserrorProc3; +go +DROP TABLE raiserrorTable; +go diff --git a/contrib/test/JDBC/expected/TestRaiserrorFormat.out b/contrib/test/JDBC/expected/TestRaiserrorFormat.out new file mode 100644 index 00000000000..9e2946a3bb7 --- /dev/null +++ b/contrib/test/JDBC/expected/TestRaiserrorFormat.out @@ -0,0 +1,113 @@ +RAISERROR('%s', 16, 1, 'Hi'); +go +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: Hi)~~ + + +RAISERROR('Hello %s', 16, 1, 'World'); +go +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: Hello World)~~ + + +DECLARE @str VARCHAR(20) = 'Multiple variable inputs'; +DECLARE @p1 TINYINT = 1; +DECLARE @p2 SMALLINT = 2; +DECLARE @p3 INT = 3; +DECLARE @p4 CHAR(5) = 'four'; +DECLARE @p5 VARCHAR(5) = 'five'; +DECLARE @p6 NCHAR(5) = 'six'; +DECLARE @p7 NVARCHAR(5) = 'seven'; +RAISERROR('%s: %d%d%d%s%s%s%s', 16, 1, @str, @p1, @p2, @p3, @p4, @p5, @p6, @p7); +go +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: Multiple variable in: 123four fivesix seven)~~ + + +RAISERROR('More than 20 args', 16, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21); +go +~~ERROR (Code: 2747)~~ + +~~ERROR (Message: Too many substitution parameters for RAISERROR. Cannot exceed 20 substitution parameters.)~~ + + +RAISERROR('Signed integer i: %i, %i', 16, 1, 5, -5); +go +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: Signed integer i: 5, -5)~~ + + +RAISERROR('Unsigned integer u: %u, %u', 16, 1, 5, -5); +go +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: Unsigned integer u: 5, 4294967291)~~ + + +RAISERROR('Unsigned octal o: %o, %o', 16, 1, 5, -5); +go +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: Unsigned octal o: 5, 37777777773)~~ + + +RAISERROR('Unsigned hexadecimal x: %x, %X, %X, %X, %x', 16, 1, 11, 11, -11, 50, -50); +go +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: Unsigned hexadecimal x: b, B, FFFFFFF5, 32, ffffffce)~~ + + +RAISERROR('Not enough args: %d, %d', 16, 1, 1, 2, 3, 4); +go +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: Not enough args: 1, 2)~~ + + +RAISERROR('No arg for placeholder: %s', 16, 1); +go +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: No arg for placeholder: (null))~~ + + +RAISERROR('Invalid placeholder: %m', 16, 1, 0); +go +~~ERROR (Code: 2787)~~ + +~~ERROR (Message: Invalid format specification: %m)~~ + + +RAISERROR('Null arg for placeholder: %s', 16, 1, NULL); +go +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: Null arg for placeholder: (null))~~ + + +-- Datatype mismatch +RAISERROR('Mismatch datatype: %d', 16, 1, 'string'); +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Param 1 expected format type %d but received type "varchar")~~ + + +RAISERROR('Mismatch datatype: %o', 16, 1, N'string'); +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Param 1 expected format type %o but received type nvarchar)~~ + + +RAISERROR('Mismatch datatype: %s', 16, 1, 123); +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Param 1 expected format type %s but received type integer)~~ + diff --git a/contrib/test/JDBC/expected/TestReal.out b/contrib/test/JDBC/expected/TestReal.out new file mode 100644 index 00000000000..57aa13fc6a6 --- /dev/null +++ b/contrib/test/JDBC/expected/TestReal.out @@ -0,0 +1,102 @@ +CREATE TABLE REAL_dt (a REAL) +prepst#!# INSERT INTO REAL_dt(a) values(?) #!#REAL|-|a|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#REAL|-|a|-|1.050 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#REAL|-|a|-|01.05 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#REAL|-|a|-|0001202 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#REAL|-|a|-|-024112329 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#REAL|-|a|-|-02.5 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#REAL|-|a|-|0000000000000000086 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#REAL|-|a|-|-3.40E+38 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#REAL|-|a|-|3.40E+38 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#REAL|-|a|-| +~~ROW COUNT: 1~~ + +SELECT * FROM REAL_dt; +~~START~~ +real +0.0 +1.05 +1.05 +1202.0 +-2.4112328E7 +-2.5 +86.0 +-3.4E38 +3.4E38 + +~~END~~ + +INSERT INTO REAL_dt(a) values(0) +~~ROW COUNT: 1~~ + +INSERT INTO REAL_dt(a) values(1.050) +~~ROW COUNT: 1~~ + +INSERT INTO REAL_dt(a) values(01.05) +~~ROW COUNT: 1~~ + +INSERT INTO REAL_dt(a) values(-004) +~~ROW COUNT: 1~~ + +INSERT INTO REAL_dt(a) values(-0122455324.5) +~~ROW COUNT: 1~~ + +INSERT INTO REAL_dt(a) values(-000002) +~~ROW COUNT: 1~~ + +INSERT INTO REAL_dt(a) values(0000000000000000086) +~~ROW COUNT: 1~~ + +INSERT INTO REAL_dt(a) values(-3.40E+38) +~~ROW COUNT: 1~~ + +INSERT INTO REAL_dt(a) values(3.40E+38) +~~ROW COUNT: 1~~ + +INSERT INTO REAL_dt(a) values(NULL) +~~ROW COUNT: 1~~ + +SELECT * FROM REAL_dt; +~~START~~ +real +0.0 +1.05 +1.05 +1202.0 +-2.4112328E7 +-2.5 +86.0 +-3.4E38 +3.4E38 + +0.0 +1.05 +1.05 +-4.0 +-1.22455328E8 +-2.0 +86.0 +-3.4E38 +3.4E38 + +~~END~~ + +DROP TABLE REAL_dt; diff --git a/contrib/test/JDBC/expected/TestRunTimeErrorWithDefaultBehave.out b/contrib/test/JDBC/expected/TestRunTimeErrorWithDefaultBehave.out new file mode 100644 index 00000000000..6b2248cc3d1 --- /dev/null +++ b/contrib/test/JDBC/expected/TestRunTimeErrorWithDefaultBehave.out @@ -0,0 +1,295 @@ +-- This file contains test cases to test un-mapped runtime error against Babelfish server. +GO + +CREATE SCHEMA error_mapping; +GO + +-- Example 1 +GO + +CREATE TABLE t257(c1 binary(10)); +GO +DECLARE @a binary(10); +SET @a = CAST('21' AS char(10)); +SELECT @a +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Implicit conversion from data type char to binary is not allowed. Use the CONVERT function to run this query.)~~ + +DROP TABLE t257; +GO + +begin transaction +GO +--Pre +CREATE TABLE t257(c1 binary(10)); +GO + +DECLARE @a binary(10); +SET @a = CAST('21' AS char(10)); +SELECT @a +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Implicit conversion from data type char to binary is not allowed. Use the CONVERT function to run this query.)~~ + + +if (@@trancount > 0) select cast('txn is not rolledback' as text) else select cast('txn is rolledback' as text) +GO +~~START~~ +text +txn is rolledback +~~END~~ + + +if (@@trancount > 0) rollback tran +GO + +DROP TABLE t257; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: table "t257" does not exist)~~ + + +SET XACT_ABORT ON; +GO + +begin transaction +GO +--Pre +CREATE TABLE t257(c1 binary(10)); +GO + +DECLARE @a binary(10); +SET @a = CAST('21' AS char(10)); +SELECT @a +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Implicit conversion from data type char to binary is not allowed. Use the CONVERT function to run this query.)~~ + + +if (@@trancount > 0) select cast('txn is not rolledback' as text) else select cast('txn is rolledback' as text) +GO +~~START~~ +text +txn is rolledback +~~END~~ + + +if (@@trancount > 0) rollback tran +GO + +DROP TABLE t257; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: table "t257" does not exist)~~ + + +SET XACT_ABORT OFF; +GO + + +CREATE TABLE t257(c1 binary(10)); +GO + +create procedure error_mapping.ErrorHandling1 as +begin + begin try + select 1 + DECLARE @a binary(10); + SET @a = CAST('21' AS char(10)); + SELECT @a + end try + begin catch + select xact_state(); + end catch + select @@trancount; +end +GO + +if @@error > 0 select cast('Compile time error' as text); +GO + +begin transaction; +GO + +exec error_mapping.ErrorHandling1; +GO +~~START~~ +int +1 +~~END~~ + +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Implicit conversion from data type char to binary is not allowed. Use the CONVERT function to run this query.)~~ + + +if @@trancount > 0 select cast('Txn is not rolledback') +GO + +if @@trancount > 0 rollback transaction; +GO + + +set xact_abort ON; +GO + +exec error_mapping.ErrorHandling1; +GO +~~START~~ +int +1 +~~END~~ + +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Implicit conversion from data type char to binary is not allowed. Use the CONVERT function to run this query.)~~ + + +if @@trancount > 0 select cast('Txn is not rolledback') +GO + +if @@trancount > 0 rollback transaction; +GO + +set xact_abort OFF; +GO + +drop procedure error_mapping.ErrorHandling1; +GO + +DROP TABLE t257; +GO + +-- Example 2 +GO + +SELECT DATEPART(xyz, CAST('2012-12-12' AS date)); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'xyz' is not a recognized datepart option)~~ + + +begin transaction +GO + +SELECT DATEPART(xyz, CAST('2012-12-12' AS date)); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'xyz' is not a recognized datepart option)~~ + + +if (@@trancount > 0) select cast('txn is not rolledback' as text) else select cast('txn is rolledback' as text) +GO +~~START~~ +text +txn is rolledback +~~END~~ + + +if (@@trancount > 0) rollback tran +GO + +SET XACT_ABORT ON; +GO + +begin transaction +GO + +SELECT DATEPART(xyz, CAST('2012-12-12' AS date)); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'xyz' is not a recognized datepart option)~~ + + +if (@@trancount > 0) select cast('txn is not rolledback' as text) else select cast('txn is rolledback' as text) +GO +~~START~~ +text +txn is rolledback +~~END~~ + + +if (@@trancount > 0) rollback tran +GO + +SET XACT_ABORT OFF; +GO + +create procedure error_mapping.ErrorHandling1 as +begin + begin try + select 1 + SELECT DATEPART(xyz, CAST('2012-12-12' AS date)); + end try + begin catch + select xact_state(); + end catch + select @@trancount; +end +GO + +if @@error > 0 select cast('Compile time error' as text) +GO + +begin transaction; +GO + +exec error_mapping.ErrorHandling1; +GO +~~START~~ +int +1 +~~END~~ + +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'xyz' is not a recognized datepart option)~~ + + +if @@trancount > 0 select cast('txn is not rolledback' as text) +GO + +if @@trancount > 0 rollback tran; +GO + +set xact_abort ON; +GO + +begin transaction; +GO + +exec error_mapping.ErrorHandling1; +GO +~~START~~ +int +1 +~~END~~ + +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'xyz' is not a recognized datepart option)~~ + + +if @@trancount > 0 select cast('txn is not rolledback' as text) +GO + +if @@trancount > 0 rollback tran; +GO + +set xact_abort OFF; +GO + +drop procedure error_mapping.ErrorHandling1; +GO + +DROP SCHEMA error_mapping; +GO diff --git a/contrib/test/JDBC/expected/TestSPExecutesql.out b/contrib/test/JDBC/expected/TestSPExecutesql.out new file mode 100644 index 00000000000..1bfdb9cc94c --- /dev/null +++ b/contrib/test/JDBC/expected/TestSPExecutesql.out @@ -0,0 +1,285 @@ +CREATE TABLE spExecutesqlTable1 (a INT, b VARCHAR(10)); +CREATE TABLE spExecutesqlTable2 (a INT, b INT, c INT, d INT); +go + +/* 1. Execute a string of statement */ +DECLARE @SQLString NVARCHAR(100); +SET @SQLString = N'SELECT N''hello world'';'; +EXEC sp_executesql @SQLString; +go +~~START~~ +nvarchar +hello world +~~END~~ + + + +/* 2. Execute a statement string with parameters */ +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'INSERT INTO spExecutesqlTable1 VALUES (@a, @b);'; +SET @ParamDef = N'@a INT, @b VARCHAR(10)'; +DECLARE @p INT = 1; +EXEC sp_executesql @SQLString, @ParamDef, @p, @b = N'hello'; +SELECT * FROM spExecutesqlTable1; +go +~~ROW COUNT: 1~~ + +~~START~~ +int#!#varchar +1#!#hello +~~END~~ + + +TRUNCATE TABLE spExecutesqlTable1; +go + + +/* 3. Execute a statement string with both unnamed params and named params */ +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'INSERT INTO spExecutesqlTable2 VALUES (@a, @b, @c, @d);'; +SET @ParamDef = N'@a INT, @b INT, @c INT, @d INT'; +EXEC sp_executesql @SQLString, @ParamDef, 1, 2, @d = 4, @c = 3; +SELECT * FROM spExecutesqlTable2; +go +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int#!#int#!#int +1#!#2#!#3#!#4 +~~END~~ + + +TRUNCATE TABLE spExecutesqlTable2; +go + +/* 4. Nested sp_executesql */ +DECLARE @SQLString1 NVARCHAR(100); +DECLARE @SQLString2 NVARCHAR(max); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString1 = N'INSERT INTO spExecutesqlTable1 VALUES (@a, @b);' +SET @SQLString2 = @SQLString1 + N'EXEC sp_executesql N''INSERT INTO spExecutesqlTable1 VALUES (@c + @c, @d + @d);'', N''@c INT, @d VARCHAR(10)'', @a, @b;' +SET @ParamDef = N'@a INT, @b VARCHAR(10)'; +EXEC sp_executesql @SQLString2, @ParamDef, @a = 10, @b = N'str'; +SELECT * FROM spExecutesqlTable1; +go +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#varchar +10#!#str +20#!#strstr +~~END~~ + + +TRUNCATE TABLE spExecutesqlTable1; +go + +-- Nested with param name collision +DECLARE @SQLString1 NVARCHAR(100); +DECLARE @SQLString2 NVARCHAR(max); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString1 = N'INSERT INTO spExecutesqlTable1 VALUES (@a, @b);' +SET @SQLString2 = @SQLString1 + N'EXEC sp_executesql N''INSERT INTO spExecutesqlTable1 VALUES (@a + @a, @b + @b);'', N''@a INT, @b VARCHAR(10)'', @a, @b;' +SET @ParamDef = N'@a INT, @b VARCHAR(10)'; +EXEC sp_executesql @SQLString2, @ParamDef, @a = 11, @b = N'rts'; +SELECT * FROM spExecutesqlTable1; +go +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#varchar +11#!#rts +22#!#rtsrts +~~END~~ + + +TRUNCATE TABLE spExecutesqlTable1; +go + + +/* 5. Execute a statement string with OUT/INOUT param */ +DECLARE @SQLString1 NVARCHAR(100); +DECLARE @SQLString2 NVARCHAR(max); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString1 = N'SET @a = @b + @b'; +SET @SQLString2 = N'EXEC sp_executesql N''SET @a = @b + @b'', N''@a INT OUT, @b INT'', @a OUT, @b;'; +SET @ParamDef = N'@a INT OUTPUT, @b INT'; +DECLARE @p INT; +DECLARE @a INT; +-- OUT param +EXEC sp_executesql @SQLString1, @ParamDef, @a = @p OUT, @b = 10; +-- Nested with OUT param name collision +EXEC sp_executesql @SQLString2, @ParamDef, @a = @a OUT, @b = 11; +SELECT @p, @a; +go +~~START~~ +int#!#int +20#!#22 +~~END~~ + + + +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'SET @a = @a + 1;'; +SET @ParamDef = N'@a INT OUT'; +DECLARE @p1 INT = 1; +DECLARE @p2 INT = 1; +-- Declared as INOUT and called as OUT +EXEC sp_executesql @SQLString, @ParamDef, @a = @p1 OUT; +-- Declared as INOUT and called as IN +EXEC sp_executesql @SQLString, @ParamDef, @a = @p2; +SELECT @p1, @p2; +go +~~START~~ +int#!#int +2#!#1 +~~END~~ + + + +/* 6. Implicit cast for IN param */ +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'SET @b = @a;'; +SET @ParamDef = N'@a FLOAT, @b FLOAT OUT'; +DECLARE @p FLOAT; +DECLARE @a MONEY = 3.14; +EXEC sp_executesql @SQLString, @ParamDef, @a = @a, @b = @p OUTPUT; +SELECT @p; +go +~~START~~ +float +3.14 +~~END~~ + + + +/* 7. Implicit cast for OUT param */ +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'SET @a = CAST(''2020-01-01'' AS DATE); SET @b = @a;'; +SET @ParamDef = N'@a DATE OUT, @b DATETIME OUT'; +DECLARE @p1 DATETIME; +DECLARE @p2 DATETIME; +EXEC sp_executesql @SQLString, @ParamDef, @a = @p1 OUT, @b = @p2 OUT; +SELECT @p1, @p2; +go +~~START~~ +datetime#!#datetime +2020-01-01 00:00:00.0#!#2020-01-01 00:00:00.0 +~~END~~ + + +/* Exceptions */ +/* 1. Wrong order of named/unnamed params */ +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'INSERT INTO spExecutesqlTable2 VALUES (@a, @b, @c, @d);'; +SET @ParamDef = N'@a INT, @b INT, @c INT, @d INT'; +EXEC sp_executesql @SQLString, @ParamDef, @b = 2, @c = 3, 1, @d = 4; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error near '1' at line 7 and character position 58)~~ + + +/* 2. Number mismatch of param defs and given params */ +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'INSERT INTO spExecutesqlTable2 VALUES (@a, @b, @c, @d);'; +SET @ParamDef = N'@a INT, @b INT, @c INT, @d INT'; +EXEC sp_executesql @SQLString, @ParamDef, 1, 2, 3; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: param definition mismatches with inputs)~~ + + +/* 3. Invalid param name */ +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'INSERT INTO spExecutesqlTable2 VALUES (@a, @b, @c, @d);'; +SET @ParamDef = N'@a INT, @b INT, @c INT, @d INT'; +EXEC sp_executesql @SQLString, @ParamDef, @a = 1, @b = 2, @c = 3, @e = 4; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: param "@e" not defined)~~ + + +/* 4. Invalid param def */ +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'INSERT INTO spExecutesqlTable2 VALUES (@a, @b, @c, @d);'; +SET @ParamDef = N'@a INT, @b INT, @c, @d INT'; +EXEC sp_executesql @SQLString, @ParamDef, 1, 2, 3, 4; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error at or near ",")~~ + + +/* 5. Unsupported implicit cast */ +-- IN param +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'INSERT INTO spExecutesqlTable2 VALUES (@a, @b, @c, @d);'; +SET @ParamDef = N'@a INT, @b INT, @c INT, @d INT'; +EXEC sp_executesql @SQLString, @ParamDef, 1, 3.14, 'hello', 4; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: invalid input syntax for type integer: "hello")~~ + + + +-- OUT param +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'SET @a = CAST(''abc'' AS VARCHAR(3));'; +SET @ParamDef = N'@a FLOAT OUT'; +DECLARE @p FLOAT; +EXEC sp_executesql @SQLString, @ParamDef, @a = @p OUT; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: invalid input syntax for type double precision: "abc")~~ + + +/* 6. Invalid OUT param */ +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'SET @a = 20'; +SET @ParamDef = N'@a INT OUT'; +EXEC sp_executesql @SQLString, @ParamDef, @a = 10 OUT; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error near ';' at line 6 and character position 53)~~ + + + +/* 7. Param declared as IN but called as OUT */ +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'SET @a = 20'; +SET @ParamDef = N'@a INT'; +DECLARE @p INT; +EXEC sp_executesql @SQLString, @ParamDef, @a = @p OUT; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: param @a defined as mode i but received mode b)~~ + + +/* Clean up */ +DROP TABLE spExecutesqlTable1; +DROP TABLE spExecutesqlTable2; +go diff --git a/contrib/test/JDBC/expected/TestSPPrepare.out b/contrib/test/JDBC/expected/TestSPPrepare.out new file mode 100644 index 00000000000..f4d1215a142 --- /dev/null +++ b/contrib/test/JDBC/expected/TestSPPrepare.out @@ -0,0 +1,720 @@ +--- Simple SP_PREPARE +DECLARE @handle int; +EXEC SP_PREPARE @handle OUT, NULL, 'SELECT ''OK''' +EXEC SP_EXECUTE @handle +EXEC SP_EXECUTE @handle +EXEC SP_EXECUTE @handle +EXEC SP_UNPREPARE @handle +GO +~~START~~ +varchar +~~END~~ + +~~START~~ +varchar +OK +~~END~~ + +~~START~~ +varchar +OK +~~END~~ + +~~START~~ +varchar +OK +~~END~~ + + +--- Simple SP_PREPEXEC +DECLARE @handle int; +EXEC SP_PREPEXEC @handle OUT, NULL, 'SELECT ''OK''' +EXEC SP_EXECUTE @handle +EXEC SP_EXECUTE @handle +EXEC SP_EXECUTE @handle +EXEC SP_UNPREPARE @handle +GO +~~START~~ +varchar +OK +~~END~~ + +~~START~~ +varchar +OK +~~END~~ + +~~START~~ +varchar +OK +~~END~~ + +~~START~~ +varchar +OK +~~END~~ + + +--- Basic SP_PREPARE with args +DECLARE @handle int; +EXEC SP_PREPARE @handle out, N'@a int, @b int', N'select @a, @b', 10; +EXEC SP_EXECUTE @handle, 1, 2 +EXEC SP_EXECUTE @handle, 1, 2 +EXEC SP_EXECUTE @handle, 1, 2 +EXEC SP_UNPREPARE @handle; +GO +~~START~~ +int#!#int +~~END~~ + +~~START~~ +int#!#int +1#!#2 +~~END~~ + +~~START~~ +int#!#int +1#!#2 +~~END~~ + +~~START~~ +int#!#int +1#!#2 +~~END~~ + + +--- Basic SP_PREPARE with args +DECLARE @handle int; +EXEC SP_PREPEXEC @handle out, N'@a int, @b int', N'select @a, @b', 1, 2; +EXEC SP_EXECUTE @handle, 1, 2 +EXEC SP_EXECUTE @handle, 1, 2 +EXEC SP_EXECUTE @handle, 1, 2 +EXEC SP_UNPREPARE @handle; +GO +~~START~~ +int#!#int +1#!#2 +~~END~~ + +~~START~~ +int#!#int +1#!#2 +~~END~~ + +~~START~~ +int#!#int +1#!#2 +~~END~~ + +~~START~~ +int#!#int +1#!#2 +~~END~~ + + +--- SP_PREPARE Batch Support +DECLARE @handle int; +DECLARE @batch nvarchar(500); +DECLARE @paramdef nvarchar(500); +DECLARE @var int; +SET @batch = 'IF (@cond > 0) SELECT @o = @a ELSE SELECT @o = @b' +SET @paramdef = '@cond int, @a int, @b int, @o int OUTPUT' +EXEC SP_PREPARE @handle OUT, @paramdef, @batch +EXEC SP_EXECUTE @handle, -1, 10, 20, @var OUTPUT +SELECT @var +EXEC SP_EXECUTE @handle, 1, 10, 20, @var OUTPUT +SELECT @var +EXEC SP_UNPREPARE @handle; +GO +~~START~~ +int +20 +~~END~~ + +~~START~~ +int +10 +~~END~~ + + +--- SP_PREPEXEC Batch Support +DECLARE @handle int; +DECLARE @batch nvarchar(500); +DECLARE @paramdef nvarchar(500); +DECLARE @var int; +SET @batch = 'IF (@cond > 0) SELECT @o = @a ELSE SELECT @o = @b' +SET @paramdef = '@cond int, @a int, @b int, @o int OUTPUT' +EXEC SP_PREPEXEC @handle out, @paramdef, @batch, 1, 30, 40, @var OUTPUT +SELECT @var +EXEC SP_EXECUTE @handle, -1, 10, 20, @var OUTPUT +SELECT @var +EXEC SP_EXECUTE @handle, 1, 10, 20, @var OUTPUT +SELECT @var +EXEC SP_UNPREPARE @handle; +GO +~~START~~ +int +30 +~~END~~ + +~~START~~ +int +20 +~~END~~ + +~~START~~ +int +10 +~~END~~ + + +--- Parsing specific +DECLARE @handle int; +EXEC SP_PREPEXEC @handle + 1 OUTPUT, NULL, 'SELECT 1' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error near '+' at line 3 and character position 25)~~ + + +DECLARE @handle VARCHAR(20) +EXEC SP_PREPEXEC @handle OUTPUT, NULL, 'SELECT 1' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: invalid prepared_handle param datatype)~~ + + +DECLARE @handle int; +EXEC SP_PREPEXEC @handle, NULL, 'SELECT 1' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: prepared_handle param is not specified as OUTPUT)~~ + + +--- Corner case 1: empty batch +DECLARE @handle int; +EXEC SP_PREPARE @handle out, NULL, NULL +EXEC SP_EXECUTE @handle +EXEC SP_UNPREPARE @handle +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: query argument of sp_prepare is null)~~ + + +DECLARE @handle int; +EXEC SP_PREPEXEC @handle out, NULL, NULL +EXEC SP_EXECUTE @handle +EXEC SP_UNPREPARE @handle +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: batch string argument of sp_prepexec is null)~~ + + +--- Corner case 2: nested prepare +DECLARE @handle int; +DECLARE @inner_handle int; +DECLARE @batch VARCHAR(500); +SET @batch = 'EXEC SP_PREPARE @inner_handle OUT, NULL, ''SELECT 1'' ' +EXEC SP_PREPARE @handle out, '@inner_handle int OUT', @batch +EXEC SP_EXECUTE @handle, @inner_handle OUT +EXEC SP_EXECUTE @inner_handle +EXEC SP_UNPREPARE @inner_handle -- unprepare inner first +EXEC SP_UNPREPARE @handle +GO +~~START~~ +int +~~END~~ + +~~START~~ +int +1 +~~END~~ + + +DECLARE @handle int; +DECLARE @inner_handle int; +DECLARE @batch VARCHAR(500); +SET @batch = 'EXEC SP_PREPARE @inner_handle OUT, NULL, ''SELECT 1'' ' +EXEC SP_PREPARE @handle out, '@inner_handle int OUT', @batch +EXEC SP_EXECUTE @handle, @inner_handle OUT +EXEC SP_EXECUTE @inner_handle +EXEC SP_UNPREPARE @handle --unprepare outer first +EXEC SP_EXECUTE @inner_handle +EXEC SP_UNPREPARE @inner_handle +GO +~~START~~ +int +~~END~~ + +~~START~~ +int +1 +~~END~~ + +~~START~~ +int +1 +~~END~~ + + +--- Corner case 3: mismatch paramdef and params +DECLARE @handle int; +DECLARE @var int; +DECLARE @batch VARCHAR(500); +DECLARE @paramdef VARCHAR(500); +SET @batch = 'SELECT @a'; +SET @paramdef = '@a int'; +EXEC SP_PREPARE @handle OUT, @paramdef, @batch +EXEC SP_EXECUTE @handle, 100 +EXEC SP_EXECUTE @handle, @var OUT +EXEC SP_UNPREPARE @handle +GO +~~START~~ +int +~~END~~ + +~~START~~ +int +100 +~~END~~ + +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: param 1 defined as mode i but received mode b)~~ + + +--- Prepare DML statement +CREATE TABLE t1 (a int, b int); +GO + +DECLARE @handle int; +DECLARE @batch VARCHAR(500); +DECLARE @paramdef VARCHAR(500); +SET @batch = ' +INSERT INTO t1 VALUES (@v1, @v2) +INSERT INTO t1 VALUES (@v3, @v4) +' +SET @paramdef = '@v1 int, @v2 int, @v3 int, @v4 int' +EXEC SP_PREPARE @handle OUT, @paramdef, @batch +EXEC SP_EXECUTE @handle, 1, 2, 2, 3 +EXEC SP_EXECUTE @handle, 3, 4, 4, 5 +SELECT * FROM t1 ORDER BY 1, 2; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +1#!#2 +2#!#3 +3#!#4 +4#!#5 +~~END~~ + + + +DECLARE @handle int; +DECLARE @batch VARCHAR(500); +DECLARE @paramdef VARCHAR(500); +SET @batch = ' +UPDATE t1 SET a = a * 10, b = b *10 where a = @var1; +UPDATE t1 SET a = a * 10, b = b *10 where a = @var2; +' +SET @paramdef = '@var1 int, @var2 int' +EXEC SP_PREPARE @handle OUT, @paramdef, @batch +EXEC SP_EXECUTE @handle, 1, 2 +EXEC SP_EXECUTE @handle, 3, 4 +SELECT * FROM t1 ORDER BY 1, 2; +EXEC SP_UNPREPARE @handle +DROP TABLE t1; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +10#!#20 +20#!#30 +30#!#40 +40#!#50 +~~END~~ + + +--- Transaction with SP_EXECUTE +CREATE TABLE t1 (a int, b int); +GO + + + + + +DECLARE @handle int; +DECLARE @batch VARCHAR(500); +DECLARE @paramdef VARCHAR(500); +SET @batch = ' +INSERT INTO t1 VALUES (@v1, @v2); +INSERT INTO t1 VALUES (@v3, @v4); +' +SET @paramdef = '@v1 int, @v2 int, @v3 int, @v4 int' +EXEC SP_PREPARE @handle OUT, @paramdef, @batch +BEGIN TRANSACTION; +EXEC SP_EXECUTE @handle, 1, 2, 2, 3 +SELECT * FROM t1 ORDER BY 1, 2; +COMMIT; +SELECT * FROM t1 ORDER BY 1, 2; +BEGIN TRANSACTION; +EXEC SP_EXECUTE @handle, 3, 4, 4, 5 +SELECT * FROM t1 ORDER BY 1, 2; +ROLLBACK; +SELECT * FROM t1 ORDER BY 1, 2; +EXEC SP_UNPREPARE @handle +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +1#!#2 +2#!#3 +~~END~~ + +~~START~~ +int#!#int +1#!#2 +2#!#3 +~~END~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +1#!#2 +2#!#3 +3#!#4 +4#!#5 +~~END~~ + +~~START~~ +int#!#int +1#!#2 +2#!#3 +~~END~~ + + +DROP TABLE t1; +GO + +--- PREPARE Batch with Transaction +CREATE TABLE t1 (a int, b int); +GO + + +DECLARE @handle int; +DECLARE @batch VARCHAR(500); +DECLARE @paramdef VARCHAR(500); +SET @batch = ' +BEGIN TRANSACTION +INSERT INTO t1 VALUES (@v1, @v2); +INSERT INTO t1 VALUES (@v3, @v4); +SELECT * FROM t1 ORDER BY 1, 2; +IF (@v1 = 10) + COMMIT; +ELSE + ROLLBACK; +' +SET @paramdef = '@v1 int, @v2 int, @v3 int, @v4 int' +EXEC SP_PREPARE @handle OUT, @paramdef, @batch +EXEC SP_EXECUTE @handle, 10, 20, 30, 40 +SELECT * FROM t1 ORDER BY 1, 2; +EXEC SP_EXECUTE @handle, 50, 60, 70, 80 +SELECT * FROM t1 ORDER BY 1, 2; +EXEC SP_UNPREPARE @handle +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +10#!#20 +30#!#40 +~~END~~ + +~~START~~ +int#!#int +10#!#20 +30#!#40 +~~END~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +10#!#20 +30#!#40 +50#!#60 +70#!#80 +~~END~~ + +~~START~~ +int#!#int +10#!#20 +30#!#40 +~~END~~ + + +DROP TABLE t1; +GO + +-- Test Save Point +CREATE TABLE t1 ( a int, b int); +GO + +DECLARE @handle int; +DECLARE @batch VARCHAR(500); +SET @batch = ' +DECLARE @handle int; +BEGIN TRANSACTION; +INSERT INTO t1 VALUES (1, 2); +SAVE TRANSACTION my_savept; +EXEC SP_PREPEXEC @handle OUT, NULL, +''INSERT INTO t1 VALUES (3, 4); + SELECT * FROM t1 ORDER BY 1, 2; + ROLLBACK TRANSACTION my_savept; + SELECT * FROM t1 ORDER BY 1, 2; +''; +SELECT * FROM t1 ORDER BY 1, 2; +ROLLBACK; +SELECT * FROM t1 ORDER BY 1, 2; +EXEC SP_UNPREPARE @handle; +' +EXEC SP_PREPARE @handle OUT, NULL, @batch; +PRINT @handle +EXEC SP_EXECUTE @handle; +EXEC SP_UNPREPARE @handle; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +1#!#2 +3#!#4 +~~END~~ + +~~START~~ +int#!#int +1#!#2 +~~END~~ + +~~START~~ +int#!#int +1#!#2 +~~END~~ + +~~START~~ +int#!#int +~~END~~ + + +DROP TABLE t1; +GO + +--- Test string type +CREATE TABLE t1 ( a VARCHAR(10), b VARCHAR(10)); +GO + +DECLARE @handle int; +EXEC SP_PREPEXEC @handle OUT, '@v1 VARCHAR(10), @v2 VARCHAR(10)', 'INSERT INTO t1 VALUES (@v1,@v2)', 'abc', 'efg' +EXEC SP_EXECUTE @handle, 'lmn', 'opq' +EXEC SP_UNPREPARE @handle +SELECT * FROM t1 ORDER BY 1, 2; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +varchar#!#varchar +abc#!#efg +lmn#!#opq +~~END~~ + + +DROP TABLE t1; +GO + +-- Test transaction begins outside the batch and commited/rollbacked inside the batch +CREATE TABLE t1 (a INT); +GO + +BEGIN TRAN; +GO +DECLARE @handle INT; +DECLARE @batch VARCHAR(500); +SET @batch = 'insert into t1 values(1); commit; begin tran;' +EXEC sp_prepare @handle OUT, NULL, @batch +EXEC sp_execute @handle +EXEC sp_execute @handle +EXEC SP_UNPREPARE @handle; +COMMIT; +SELECT COUNT(*) FROM t1; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +2 +~~END~~ + + +BEGIN TRAN; +GO +DECLARE @handle INT; +DECLARE @batch VARCHAR(500); +SET @batch = 'insert into t1 values(1); rollback tran; begin tran;' +EXEC sp_prepare @handle OUT, NULL, @batch +EXEC sp_execute @handle +EXEC sp_execute @handle +EXEC SP_UNPREPARE @handle; +COMMIT; +SELECT COUNT(*) FROM t1; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +2 +~~END~~ + + +DROP TABLE t1; +GO + +-- prepare time error 1 +DECLARE @handle int; +EXEC SP_PREPARE @handle OUT, NULL, 'SELECT * FROM t1' +SELECT (case when @handle IS NOT NULL then 'true' else 'false' end) as 'Prepared' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "t1" does not exist)~~ + + +-- prepare time error 1-2 +DECLARE @handle int; +EXEC SP_PREPARE @handle OUT, NULL, 'DECLARE @var int; SELECT * FROM t1 WHERE c = @var' +SELECT (case when @handle IS NOT NULL then 'true' else 'false' end) as 'Prepared' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "t1" does not exist)~~ + + +-- prepare time error 2 +DECLARE @handle int; +EXEC SP_PREPARE @handle OUT, NULL, 'EXEC my_proc' +SELECT (case when @handle IS NOT NULL then 'true' else 'false' end) as 'Prepared' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: procedure my_proc() does not exist)~~ + + +-- prepare time error 2-2 +DECLARE @handle int; +EXEC SP_PREPARE @handle OUT, NULL, 'DECLARE @var int; EXEC my_proc @var' +SELECT (case when @handle IS NOT NULL then 'true' else 'false' end) as 'Prepared' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: procedure my_proc(integer) does not exist)~~ + + +-- runtime error 1 +DECLARE @handle int; +EXEC SP_PREPARE @handle OUT, NULL, 'SELECT * FROM t1; SELECT * FROM t1;' +SELECT (case when @handle IS NOT NULL then 'true' else 'false' end) as 'Prepared' +EXEC SP_EXECUTE @handle +GO +~~START~~ +text +true +~~END~~ + +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "t1" does not exist)~~ + + +-- runtime error 2 +DECLARE @handle int; +EXEC SP_PREPARE @handle OUT, NULL, 'EXEC my_proc; EXEC my_proc;' +SELECT (case when @handle IS NOT NULL then 'true' else 'false' end) as 'Prepared' +EXEC SP_EXECUTE @handle +GO +~~START~~ +text +true +~~END~~ + +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: procedure my_proc() does not exist)~~ + + +-- runtime error 3 +DECLARE @handle int; +EXEC SP_PREPARE @handle OUT, NULL, 'IF (1=1) SELECT * FROM t1;' +SELECT (case when @handle IS NOT NULL then 'true' else 'false' end) as 'Prepared' +EXEC SP_EXECUTE @handle +GO +~~START~~ +text +true +~~END~~ + +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "t1" does not exist)~~ + + +-- runtime error 4 +DECLARE @handle int; +EXEC SP_PREPARE @handle OUT, NULL, 'DECLARE @var int; SET @var = 1; select * from t1 where c = @var' +SELECT (case when @handle IS NOT NULL then 'true' else 'false' end) as 'Prepared' +EXEC SP_EXECUTE @handle +GO +~~START~~ +text +true +~~END~~ + +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "t1" does not exist)~~ + diff --git a/contrib/test/JDBC/expected/TestSQLQueries.out b/contrib/test/JDBC/expected/TestSQLQueries.out new file mode 100644 index 00000000000..fe4649c3f0a --- /dev/null +++ b/contrib/test/JDBC/expected/TestSQLQueries.out @@ -0,0 +1,839 @@ +#1 CREATE TABLE with primary and unique keyword +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_unique_constraint', 'ignore'; +CREATE TABLE tmp(a int PRIMARY KEY, b int UNIQUE); +INSERT INTO tmp(a,b) values(1,1); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) values(2,2); +~~ROW COUNT: 1~~ + +SELECT * FROM tmp; +~~START~~ +int#!#int +1#!#1 +2#!#2 +~~END~~ + +DROP TABLE tmp; + +#2 2 table with foreign key relation +#CREATE TABLE tmp1(b int PRIMARY KEY); +#CREATE TABLE tmp2(a int PRIMARY KEY, b int FOREIGN KEY REFERENCES tmp1(b)); +#INSERT INTO tmp1(b) VALUES (1); +#INSERT INTO tmp2(a,b) values(1,1); +#SELECT * FROM tmp1; +#SELECT * FROM tmp2; +#DROP TABLE tmp2; +#DROP TABLE tmp1; + +#3 Repeated #2 with CONSTRAINT keyword +#CREATE TABLE tmp1(b int PRIMARY KEY); +#CREATE TABLE tmp2(a int, b int, PRIMARY KEY(a), CONSTRAINT FK_tmp FOREIGN KEY (b) REFERENCES tmp1(b)); +#INSERT INTO tmp1(b) VALUES (1); +#INSERT INTO tmp2(a,b) values(1,1); +#SELECT * FROM tmp1; +#SELECT * FROM tmp2; +#DROP TABLE tmp2; +#DROP TABLE tmp1; + +#4 CREATE TABLE with NOT NULL column +CREATE TABLE tmp(a int PRIMARY KEY,b int NOT NULL); +INSERT INTO tmp(a,b) values(1,1); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) values(2,1); +~~ROW COUNT: 1~~ + +#INSERT INTO tmp(a,b) values(2,NULL); +SELECT * FROM tmp; +~~START~~ +int#!#int +1#!#1 +2#!#1 +~~END~~ + +DROP TABLE tmp; + +#5 INSERTION and DELETION +CREATE TABLE tmp(a int PRIMARY KEY); +INSERT INTO tmp(a) VALUES(1); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a) VALUES(2); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a) VALUES(3); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a) VALUES(4); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a) VALUES(5); +~~ROW COUNT: 1~~ + +SELECT * FROM tmp; +~~START~~ +int +1 +2 +3 +4 +5 +~~END~~ + +DELETE FROM tmp WHERE a>2; +~~ROW COUNT: 3~~ + +SELECT * FROM tmp; +~~START~~ +int +1 +2 +~~END~~ + +DROP TABLE tmp; + +#6 IS NOT NULL condition in WHERE clause +CREATE TABLE tmp(a int PRIMARY KEY,b int); +INSERT INTO tmp(a,b) values(1,1); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) values(2,1); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) values(3,NULL); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) values(4,NULL); +~~ROW COUNT: 1~~ + +SELECT * FROM tmp WHERE b IS NOT NULL; +~~START~~ +int#!#int +1#!#1 +2#!#1 +~~END~~ + +DROP TABLE tmp; + +#7 Add new column using ALTER TABLE +CREATE TABLE tmp(a int PRIMARY KEY); +INSERT INTO tmp(a) VALUES(1); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a) VALUES(2); +~~ROW COUNT: 1~~ + +SELECT * FROM tmp; +~~START~~ +int +1 +2 +~~END~~ + +ALTER TABLE tmp ADD b VARCHAR(20) NULL; +SELECT * FROM tmp; +~~START~~ +int#!#varchar +1#!# +2#!# +~~END~~ + +INSERT INTO tmp(a,b) VALUES(4,'Dipesh'); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(5,' Dipesh'); +~~ROW COUNT: 1~~ + +SELECT * FROM tmp; +~~START~~ +int#!#varchar +1#!# +2#!# +4#!#Dipesh +5#!# Dipesh +~~END~~ + +DROP TABLE tmp; + +#8 Repeated #8 with default value for newly added col +CREATE TABLE tmp(a int PRIMARY KEY); +INSERT INTO tmp(a) VALUES(1); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a) VALUES(2); +~~ROW COUNT: 1~~ + +SELECT * FROM tmp; +~~START~~ +int +1 +2 +~~END~~ + +ALTER TABLE tmp ADD b VARCHAR(20) DEFAULT 'Dipesj'; +SELECT * FROM tmp; +~~START~~ +int#!#varchar +1#!#Dipesj +2#!#Dipesj +~~END~~ + +INSERT INTO tmp(a,b) VALUES(4,'Dipesh'); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(5,' Dipesh'); +~~ROW COUNT: 1~~ + +SELECT * FROM tmp; +~~START~~ +int#!#varchar +1#!#Dipesj +2#!#Dipesj +4#!#Dipesh +5#!# Dipesh +~~END~~ + +DROP TABLE tmp; + +#9 Change datatype of existing column using ALTER TABLE +CREATE TABLE tmp(a int PRIMARY KEY,b int); +INSERT INTO tmp(a,b) VALUES(1,1); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(2,2); +~~ROW COUNT: 1~~ + +SELECT * FROM tmp; +~~START~~ +int#!#int +1#!#1 +2#!#2 +~~END~~ + +ALTER TABLE tmp ALTER COLUMN b VARCHAR(10); +SELECT * FROM tmp; +~~START~~ +int#!#varchar +1#!#1 +2#!#2 +~~END~~ + +INSERT INTO tmp(a,b) VALUES(4,'Dipesh'); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(5,' Dipesh'); +~~ROW COUNT: 1~~ + +SELECT * FROM tmp; +~~START~~ +int#!#varchar +1#!#1 +2#!#2 +4#!#Dipesh +5#!# Dipesh +~~END~~ + +DROP TABLE tmp; + +#10 UPDATE TABLE with fancy condition +CREATE TABLE tmp(a int PRIMARY KEY,b int); +INSERT INTO tmp(a,b) VALUES(1,1); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(2,2); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(3,3); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(4,4); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(5,5); +~~ROW COUNT: 1~~ + +SELECT * FROM tmp; +~~START~~ +int#!#int +1#!#1 +2#!#2 +3#!#3 +4#!#4 +5#!#5 +~~END~~ + +UPDATE tmp SET b=b+1 WHERE b>2; +~~ROW COUNT: 3~~ + +SELECT * FROM tmp; +~~START~~ +int#!#int +1#!#1 +2#!#2 +3#!#4 +4#!#5 +5#!#6 +~~END~~ + +DROP TABLE tmp; + +#11 DROP some column using ALTER TABLE +CREATE TABLE tmp(a int PRIMARY KEY,b int); +INSERT INTO tmp(a,b) VALUES(1,1); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(2,2); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(3,3); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(4,4); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(5,5); +~~ROW COUNT: 1~~ + +SELECT * FROM tmp; +~~START~~ +int#!#int +1#!#1 +2#!#2 +3#!#3 +4#!#4 +5#!#5 +~~END~~ + +#ALTER TABLE tmp DROP COLUMN b; +#INSERT INTO tmp(a) values (6); +#SELECT * FROM tmp; +DROP TABLE tmp; + +#12 CREATE TABLE with fancy constraint +CREATE TABLE tmp(a int PRIMARY KEY CHECK (a>10),b int); +INSERT INTO tmp(a,b) VALUES(11,1); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(12,2); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(13,3); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(14,4); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(15,5); +~~ROW COUNT: 1~~ + +SELECT * FROM tmp; +~~START~~ +int#!#int +11#!#1 +12#!#2 +13#!#3 +14#!#4 +15#!#5 +~~END~~ + +DROP TABLE tmp; + +#CREATE PROCEDURE tmp AS +#BEGIN +# CREATE TABLE dip(a int PRIMARY KEY CHECK (a>10),b int); +# INSERT INTO dip(a,b) VALUES(11,1); +# INSERT INTO dip(a,b) VALUES(12,2); +# INSERT INTO dip(a,b) VALUES(13,3); +# INSERT INTO dip(a,b) VALUES(14,4); +# INSERT INTO dip(a,b) VALUES(15,5); +# SELECT * FROM dip; +# DROP TABLE dip; +#END; + +#13 invoke simple stored procedure using EXECUTE +EXECUTE tmp; +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: procedure tmp() does not exist)~~ + + +#14 invoke simple stored procedure using EXEC +EXEC tmp; +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: procedure tmp() does not exist)~~ + + +#DROP PROCEDURE tmp; + +#15 UPDATE rows in existing table +CREATE TABLE tmp(a int PRIMARY KEY,b int); +INSERT INTO tmp(a,b) VALUES(1,1),(2,2),(3,3),(4,4),(5,5); +~~ROW COUNT: 5~~ + +SELECT * FROM tmp; +~~START~~ +int#!#int +1#!#1 +2#!#2 +3#!#3 +4#!#4 +5#!#5 +~~END~~ + +UPDATE tmp SET b=b*2+1 WHERE (a>2); +~~ROW COUNT: 3~~ + +SELECT * FROM tmp; +~~START~~ +int#!#int +1#!#1 +2#!#2 +3#!#7 +4#!#9 +5#!#11 +~~END~~ + +DROP TABLE tmp; + +#16 TRUNCATE table +CREATE TABLE tmp(a int PRIMARY KEY,b int); +INSERT INTO tmp(a,b) VALUES(1,1),(2,2),(3,3),(4,4),(5,5); +~~ROW COUNT: 5~~ + +SELECT * FROM tmp; +~~START~~ +int#!#int +1#!#1 +2#!#2 +3#!#3 +4#!#4 +5#!#5 +~~END~~ + +TRUNCATE TABLE tmp; +SELECT * FROM tmp; +~~START~~ +int#!#int +~~END~~ + +DROP TABLE tmp; + +CREATE TABLE temp1 (i INT,j INT,t TEXT); + +CREATE TABLE temp2 ( i INT,k INT); + +INSERT INTO temp1 VALUES (1, 4, 'one'); +~~ROW COUNT: 1~~ + +INSERT INTO temp1 VALUES (2, 3, 'two'); +~~ROW COUNT: 1~~ + +INSERT INTO temp1 VALUES (3, 2, 'three'); +~~ROW COUNT: 1~~ + +INSERT INTO temp1 VALUES (4, 1, 'four'); +~~ROW COUNT: 1~~ + +INSERT INTO temp1 VALUES (5, 0, 'five'); +~~ROW COUNT: 1~~ + +INSERT INTO temp1 VALUES (6, 6, 'six'); +~~ROW COUNT: 1~~ + +INSERT INTO temp1 VALUES (7, 7, 'seven'); +~~ROW COUNT: 1~~ + +INSERT INTO temp1 VALUES (8, 8, 'eight'); +~~ROW COUNT: 1~~ + +INSERT INTO temp1 VALUES (0, NULL, 'zero'); +~~ROW COUNT: 1~~ + +INSERT INTO temp1 VALUES (NULL, NULL, NULL); +~~ROW COUNT: 1~~ + +INSERT INTO temp1 VALUES (NULL, 0, 'zero'); +~~ROW COUNT: 1~~ + + +INSERT INTO temp2 VALUES (1, -1); +~~ROW COUNT: 1~~ + +INSERT INTO temp2 VALUES (2, 2); +~~ROW COUNT: 1~~ + +INSERT INTO temp2 VALUES (3, -3); +~~ROW COUNT: 1~~ + +INSERT INTO temp2 VALUES (2, 4); +~~ROW COUNT: 1~~ + +INSERT INTO temp2 VALUES (5, -5); +~~ROW COUNT: 1~~ + +INSERT INTO temp2 VALUES (5, -5); +~~ROW COUNT: 1~~ + +INSERT INTO temp2 VALUES (0, NULL); +~~ROW COUNT: 1~~ + +INSERT INTO temp2 VALUES (NULL, NULL); +~~ROW COUNT: 1~~ + +INSERT INTO temp2 VALUES (NULL, 0); +~~ROW COUNT: 1~~ + + +#17 CROSS JOIN +SELECT * FROM temp1 CROSS JOIN temp2; +~~START~~ +int#!#int#!#text#!#int#!#int +1#!#4#!#one#!#1#!#-1 +2#!#3#!#two#!#1#!#-1 +3#!#2#!#three#!#1#!#-1 +4#!#1#!#four#!#1#!#-1 +5#!#0#!#five#!#1#!#-1 +6#!#6#!#six#!#1#!#-1 +7#!#7#!#seven#!#1#!#-1 +8#!#8#!#eight#!#1#!#-1 +0#!##!#zero#!#1#!#-1 +#!##!##!#1#!#-1 +#!#0#!#zero#!#1#!#-1 +1#!#4#!#one#!#2#!#2 +2#!#3#!#two#!#2#!#2 +3#!#2#!#three#!#2#!#2 +4#!#1#!#four#!#2#!#2 +5#!#0#!#five#!#2#!#2 +6#!#6#!#six#!#2#!#2 +7#!#7#!#seven#!#2#!#2 +8#!#8#!#eight#!#2#!#2 +0#!##!#zero#!#2#!#2 +#!##!##!#2#!#2 +#!#0#!#zero#!#2#!#2 +1#!#4#!#one#!#3#!#-3 +2#!#3#!#two#!#3#!#-3 +3#!#2#!#three#!#3#!#-3 +4#!#1#!#four#!#3#!#-3 +5#!#0#!#five#!#3#!#-3 +6#!#6#!#six#!#3#!#-3 +7#!#7#!#seven#!#3#!#-3 +8#!#8#!#eight#!#3#!#-3 +0#!##!#zero#!#3#!#-3 +#!##!##!#3#!#-3 +#!#0#!#zero#!#3#!#-3 +1#!#4#!#one#!#2#!#4 +2#!#3#!#two#!#2#!#4 +3#!#2#!#three#!#2#!#4 +4#!#1#!#four#!#2#!#4 +5#!#0#!#five#!#2#!#4 +6#!#6#!#six#!#2#!#4 +7#!#7#!#seven#!#2#!#4 +8#!#8#!#eight#!#2#!#4 +0#!##!#zero#!#2#!#4 +#!##!##!#2#!#4 +#!#0#!#zero#!#2#!#4 +1#!#4#!#one#!#5#!#-5 +2#!#3#!#two#!#5#!#-5 +3#!#2#!#three#!#5#!#-5 +4#!#1#!#four#!#5#!#-5 +5#!#0#!#five#!#5#!#-5 +6#!#6#!#six#!#5#!#-5 +7#!#7#!#seven#!#5#!#-5 +8#!#8#!#eight#!#5#!#-5 +0#!##!#zero#!#5#!#-5 +#!##!##!#5#!#-5 +#!#0#!#zero#!#5#!#-5 +1#!#4#!#one#!#5#!#-5 +2#!#3#!#two#!#5#!#-5 +3#!#2#!#three#!#5#!#-5 +4#!#1#!#four#!#5#!#-5 +5#!#0#!#five#!#5#!#-5 +6#!#6#!#six#!#5#!#-5 +7#!#7#!#seven#!#5#!#-5 +8#!#8#!#eight#!#5#!#-5 +0#!##!#zero#!#5#!#-5 +#!##!##!#5#!#-5 +#!#0#!#zero#!#5#!#-5 +1#!#4#!#one#!#0#!# +2#!#3#!#two#!#0#!# +3#!#2#!#three#!#0#!# +4#!#1#!#four#!#0#!# +5#!#0#!#five#!#0#!# +6#!#6#!#six#!#0#!# +7#!#7#!#seven#!#0#!# +8#!#8#!#eight#!#0#!# +0#!##!#zero#!#0#!# +#!##!##!#0#!# +#!#0#!#zero#!#0#!# +1#!#4#!#one#!##!# +2#!#3#!#two#!##!# +3#!#2#!#three#!##!# +4#!#1#!#four#!##!# +5#!#0#!#five#!##!# +6#!#6#!#six#!##!# +7#!#7#!#seven#!##!# +8#!#8#!#eight#!##!# +0#!##!#zero#!##!# +#!##!##!##!# +#!#0#!#zero#!##!# +1#!#4#!#one#!##!#0 +2#!#3#!#two#!##!#0 +3#!#2#!#three#!##!#0 +4#!#1#!#four#!##!#0 +5#!#0#!#five#!##!#0 +6#!#6#!#six#!##!#0 +7#!#7#!#seven#!##!#0 +8#!#8#!#eight#!##!#0 +0#!##!#zero#!##!#0 +#!##!##!##!#0 +#!#0#!#zero#!##!#0 +~~END~~ + + +#18 INNER JOIN +SELECT temp1.i, temp1.j, temp1.t, temp2.k FROM temp1 INNER JOIN temp2 ON temp1.i=temp2.i; +~~START~~ +int#!#int#!#text#!#int +0#!##!#zero#!# +1#!#4#!#one#!#-1 +2#!#3#!#two#!#2 +2#!#3#!#two#!#4 +3#!#2#!#three#!#-3 +5#!#0#!#five#!#-5 +5#!#0#!#five#!#-5 +~~END~~ + +SELECT temp1.i, temp1.j, temp1.t, temp2.k FROM temp1 JOIN temp2 ON temp1.i=temp2.i; +~~START~~ +int#!#int#!#text#!#int +0#!##!#zero#!# +1#!#4#!#one#!#-1 +2#!#3#!#two#!#2 +2#!#3#!#two#!#4 +3#!#2#!#three#!#-3 +5#!#0#!#five#!#-5 +5#!#0#!#five#!#-5 +~~END~~ + + +#19 LEFT JOIN +SELECT * FROM temp1 LEFT OUTER JOIN temp2 ON temp1.i=temp2.k; +~~START~~ +int#!#int#!#text#!#int#!#int +0#!##!#zero#!##!#0 +1#!#4#!#one#!##!# +2#!#3#!#two#!#2#!#2 +3#!#2#!#three#!##!# +4#!#1#!#four#!#2#!#4 +5#!#0#!#five#!##!# +6#!#6#!#six#!##!# +7#!#7#!#seven#!##!# +8#!#8#!#eight#!##!# +#!##!##!##!# +#!#0#!#zero#!##!# +~~END~~ + + +#20 RIGHT JOIN +SELECT * FROM temp1 RIGHT OUTER JOIN temp2 ON temp1.i=temp2.i; +~~START~~ +int#!#int#!#text#!#int#!#int +0#!##!#zero#!#0#!# +1#!#4#!#one#!#1#!#-1 +2#!#3#!#two#!#2#!#2 +2#!#3#!#two#!#2#!#4 +3#!#2#!#three#!#3#!#-3 +5#!#0#!#five#!#5#!#-5 +5#!#0#!#five#!#5#!#-5 +#!##!##!##!# +#!##!##!##!#0 +~~END~~ + + +#21 FULL OUTER JOIN +SELECT * FROM temp1,temp2; +~~START~~ +int#!#int#!#text#!#int#!#int +1#!#4#!#one#!#1#!#-1 +2#!#3#!#two#!#1#!#-1 +3#!#2#!#three#!#1#!#-1 +4#!#1#!#four#!#1#!#-1 +5#!#0#!#five#!#1#!#-1 +6#!#6#!#six#!#1#!#-1 +7#!#7#!#seven#!#1#!#-1 +8#!#8#!#eight#!#1#!#-1 +0#!##!#zero#!#1#!#-1 +#!##!##!#1#!#-1 +#!#0#!#zero#!#1#!#-1 +1#!#4#!#one#!#2#!#2 +2#!#3#!#two#!#2#!#2 +3#!#2#!#three#!#2#!#2 +4#!#1#!#four#!#2#!#2 +5#!#0#!#five#!#2#!#2 +6#!#6#!#six#!#2#!#2 +7#!#7#!#seven#!#2#!#2 +8#!#8#!#eight#!#2#!#2 +0#!##!#zero#!#2#!#2 +#!##!##!#2#!#2 +#!#0#!#zero#!#2#!#2 +1#!#4#!#one#!#3#!#-3 +2#!#3#!#two#!#3#!#-3 +3#!#2#!#three#!#3#!#-3 +4#!#1#!#four#!#3#!#-3 +5#!#0#!#five#!#3#!#-3 +6#!#6#!#six#!#3#!#-3 +7#!#7#!#seven#!#3#!#-3 +8#!#8#!#eight#!#3#!#-3 +0#!##!#zero#!#3#!#-3 +#!##!##!#3#!#-3 +#!#0#!#zero#!#3#!#-3 +1#!#4#!#one#!#2#!#4 +2#!#3#!#two#!#2#!#4 +3#!#2#!#three#!#2#!#4 +4#!#1#!#four#!#2#!#4 +5#!#0#!#five#!#2#!#4 +6#!#6#!#six#!#2#!#4 +7#!#7#!#seven#!#2#!#4 +8#!#8#!#eight#!#2#!#4 +0#!##!#zero#!#2#!#4 +#!##!##!#2#!#4 +#!#0#!#zero#!#2#!#4 +1#!#4#!#one#!#5#!#-5 +2#!#3#!#two#!#5#!#-5 +3#!#2#!#three#!#5#!#-5 +4#!#1#!#four#!#5#!#-5 +5#!#0#!#five#!#5#!#-5 +6#!#6#!#six#!#5#!#-5 +7#!#7#!#seven#!#5#!#-5 +8#!#8#!#eight#!#5#!#-5 +0#!##!#zero#!#5#!#-5 +#!##!##!#5#!#-5 +#!#0#!#zero#!#5#!#-5 +1#!#4#!#one#!#5#!#-5 +2#!#3#!#two#!#5#!#-5 +3#!#2#!#three#!#5#!#-5 +4#!#1#!#four#!#5#!#-5 +5#!#0#!#five#!#5#!#-5 +6#!#6#!#six#!#5#!#-5 +7#!#7#!#seven#!#5#!#-5 +8#!#8#!#eight#!#5#!#-5 +0#!##!#zero#!#5#!#-5 +#!##!##!#5#!#-5 +#!#0#!#zero#!#5#!#-5 +1#!#4#!#one#!#0#!# +2#!#3#!#two#!#0#!# +3#!#2#!#three#!#0#!# +4#!#1#!#four#!#0#!# +5#!#0#!#five#!#0#!# +6#!#6#!#six#!#0#!# +7#!#7#!#seven#!#0#!# +8#!#8#!#eight#!#0#!# +0#!##!#zero#!#0#!# +#!##!##!#0#!# +#!#0#!#zero#!#0#!# +1#!#4#!#one#!##!# +2#!#3#!#two#!##!# +3#!#2#!#three#!##!# +4#!#1#!#four#!##!# +5#!#0#!#five#!##!# +6#!#6#!#six#!##!# +7#!#7#!#seven#!##!# +8#!#8#!#eight#!##!# +0#!##!#zero#!##!# +#!##!##!##!# +#!#0#!#zero#!##!# +1#!#4#!#one#!##!#0 +2#!#3#!#two#!##!#0 +3#!#2#!#three#!##!#0 +4#!#1#!#four#!##!#0 +5#!#0#!#five#!##!#0 +6#!#6#!#six#!##!#0 +7#!#7#!#seven#!##!#0 +8#!#8#!#eight#!##!#0 +0#!##!#zero#!##!#0 +#!##!##!##!#0 +#!#0#!#zero#!##!#0 +~~END~~ + + +DROP TABLE temp1; +DROP TABLE temp2; + +#22 dropping all columns +CREATE TABLE tmp(a int PRIMARY KEY,b int); +INSERT INTO tmp(a,b) VALUES(1,1); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(2,2); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(3,3); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(4,4); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(5,5); +~~ROW COUNT: 1~~ + +SELECT * FROM tmp; +~~START~~ +int#!#int +1#!#1 +2#!#2 +3#!#3 +4#!#4 +5#!#5 +~~END~~ + +#ALTER TABLE tmp DROP COLUMN b; +#ALTER TABLE tmp DROP COLUMN a; +#SELECT * FROM tmp; +DROP TABLE tmp; + +#23 +CREATE TABLE DATE_dt (a DATE); +INSERT INTO DATE_dt(a) values('2000-12-13'); +~~ROW COUNT: 1~~ + +INSERT INTO DATE_dt(a) values('1900-02-28'); +~~ROW COUNT: 1~~ + +INSERT INTO DATE_dt(a) values('0001-01-01'); +~~ROW COUNT: 1~~ + +INSERT INTO DATE_dt(a) values('9999-12-31'); +~~ROW COUNT: 1~~ + +INSERT INTO DATE_dt(a) values(NULL); +~~ROW COUNT: 1~~ + +SELECT * FROM DATE_dt; +~~START~~ +date +2000-12-13 +1900-02-28 +0001-01-01 +9999-12-31 + +~~END~~ + +ALTER TABLE DATE_dt ALTER COLUMN a DATETIME; +~~ERROR (Code: 517)~~ + +~~ERROR (Message: data out of range for datetime)~~ + +SELECT * FROM DATE_dt; +~~START~~ +date +2000-12-13 +1900-02-28 +0001-01-01 +9999-12-31 + +~~END~~ + +DROP TABLE DATE_dt; +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_unique_constraint', 'strict'; diff --git a/contrib/test/JDBC/expected/TestSmallDatetime.out b/contrib/test/JDBC/expected/TestSmallDatetime.out new file mode 100644 index 00000000000..b29b9fa7ec3 --- /dev/null +++ b/contrib/test/JDBC/expected/TestSmallDatetime.out @@ -0,0 +1,148 @@ +CREATE TABLE SMALLDATETIME_dt (a SMALLDATETIME) +prepst#!# INSERT INTO SMALLDATETIME_dt(a) values(?) #!#SMALLDATETIME|-|a|-|2000-12-13 12:58:23 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLDATETIME|-|a|-|2007-05-08 12:35:29 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLDATETIME|-|a|-|2007-05-08 12:35:30 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLDATETIME|-|a|-|2007-05-08 12:59:59.998 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLDATETIME|-|a|-|2000-02-28 23:59:59.999 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLDATETIME|-|a|-|1900-02-28 23:59:59.999 +~~ROW COUNT: 1~~ + +#prepst#!#exec#!#SMALLDATETIME|-|a|-|2000-02-28 23:45:29.999 +prepst#!#exec#!#SMALLDATETIME|-|a|-|2000-02-28 23:45:30 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLDATETIME|-|a|-|2000-02-28 23:45:29 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLDATETIME|-|a|-|1900-02-28 23:45:30 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLDATETIME|-|a|-|1900-02-28 23:45:29 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLDATETIME|-|a|-|2000-12-13 12:58:30 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLDATETIME|-|a|-|2000-02-28 23:45:29.998 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLDATETIME|-|a|-|1900-01-01 00:00:00 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLDATETIME|-|a|-|2079-06-06 23:59:29 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLDATETIME|-|a|-| +~~ROW COUNT: 1~~ + +SELECT * FROM SMALLDATETIME_dt; +~~START~~ +smalldatetime +2000-12-13 12:58:00.0 +2007-05-08 12:35:00.0 +2007-05-08 12:36:00.0 +2007-05-08 13:00:00.0 +2000-02-29 00:00:00.0 +1900-03-01 00:00:00.0 +2000-02-28 23:46:00.0 +2000-02-28 23:45:00.0 +1900-02-28 23:46:00.0 +1900-02-28 23:45:00.0 +2000-12-13 12:59:00.0 +2000-02-28 23:45:00.0 +1900-01-01 00:00:00.0 +2079-06-06 23:59:00.0 + +~~END~~ + +INSERT INTO SMALLDATETIME_dt(a) values('2000-12-13 12:58:23'); +~~ROW COUNT: 1~~ + +INSERT INTO SMALLDATETIME_dt(a) values('2007-05-08 12:35:29'); +~~ROW COUNT: 1~~ + +INSERT INTO SMALLDATETIME_dt(a) values('2007-05-08 12:35:30'); +~~ROW COUNT: 1~~ + +INSERT INTO SMALLDATETIME_dt(a) values('2007-05-08 12:59:59.998'); +~~ROW COUNT: 1~~ + +INSERT INTO SMALLDATETIME_dt(a) values('2000-02-28 23:59:59.999'); +~~ROW COUNT: 1~~ + +INSERT INTO SMALLDATETIME_dt(a) values('1900-02-28 23:59:59.999'); +~~ROW COUNT: 1~~ + +INSERT INTO SMALLDATETIME_dt(a) values('2000-02-28 23:45:29.999'); +~~ROW COUNT: 1~~ + +INSERT INTO SMALLDATETIME_dt(a) values('2000-02-28 23:45:30'); +~~ROW COUNT: 1~~ + +INSERT INTO SMALLDATETIME_dt(a) values('2000-02-28 23:45:29'); +~~ROW COUNT: 1~~ + +INSERT INTO SMALLDATETIME_dt(a) values('1900-02-28 23:45:29'); +~~ROW COUNT: 1~~ + +INSERT INTO SMALLDATETIME_dt(a) values('1900-12-13 12:58:30'); +~~ROW COUNT: 1~~ + +INSERT INTO SMALLDATETIME_dt(a) values('2000-02-28 23:45:29.998'); +~~ROW COUNT: 1~~ + +INSERT INTO SMALLDATETIME_dt(a) values('1900-01-01 00:00:00'); +~~ROW COUNT: 1~~ + +INSERT INTO SMALLDATETIME_dt(a) values('2079-06-06 23:59:29'); +~~ROW COUNT: 1~~ + +INSERT INTO SMALLDATETIME_dt(a) values(NULL); +~~ROW COUNT: 1~~ + +SELECT * FROM SMALLDATETIME_dt; +~~START~~ +smalldatetime +2000-12-13 12:58:00.0 +2007-05-08 12:35:00.0 +2007-05-08 12:36:00.0 +2007-05-08 13:00:00.0 +2000-02-29 00:00:00.0 +1900-03-01 00:00:00.0 +2000-02-28 23:46:00.0 +2000-02-28 23:45:00.0 +1900-02-28 23:46:00.0 +1900-02-28 23:45:00.0 +2000-12-13 12:59:00.0 +2000-02-28 23:45:00.0 +1900-01-01 00:00:00.0 +2079-06-06 23:59:00.0 + +2000-12-13 12:58:00.0 +2007-05-08 12:35:00.0 +2007-05-08 12:36:00.0 +2007-05-08 13:00:00.0 +2000-02-29 00:00:00.0 +1900-03-01 00:00:00.0 +2000-02-28 23:46:00.0 +2000-02-28 23:46:00.0 +2000-02-28 23:45:00.0 +1900-02-28 23:45:00.0 +1900-12-13 12:59:00.0 +2000-02-28 23:45:00.0 +1900-01-01 00:00:00.0 +2079-06-06 23:59:00.0 + +~~END~~ + +DROP TABLE SMALLDATETIME_dt; diff --git a/contrib/test/JDBC/expected/TestSmallInt.out b/contrib/test/JDBC/expected/TestSmallInt.out new file mode 100644 index 00000000000..41e35be86e1 --- /dev/null +++ b/contrib/test/JDBC/expected/TestSmallInt.out @@ -0,0 +1,102 @@ +CREATE TABLE SMALLINT_dt (a SMALLINT) +prepst#!# INSERT INTO SMALLINT_dt(a) values(?) #!#SMALLINT|-|a|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLINT|-|a|-|-10 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLINT|-|a|-|100 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLINT|-|a|-|002 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLINT|-|a|-|-029 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLINT|-|a|-|-1234 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLINT|-|a|-|876 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLINT|-|a|-|-32768 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLINT|-|a|-|32767 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLINT|-|a|-| +~~ROW COUNT: 1~~ + +SELECT * FROM SMALLINT_dt; +~~START~~ +smallint +0 +-10 +100 +2 +-29 +-1234 +876 +-32768 +32767 + +~~END~~ + +INSERT INTO SMALLINT_dt(a) values(0) +~~ROW COUNT: 1~~ + +INSERT INTO SMALLINT_dt(a) values(-10) +~~ROW COUNT: 1~~ + +INSERT INTO SMALLINT_dt(a) values(100) +~~ROW COUNT: 1~~ + +INSERT INTO SMALLINT_dt(a) values(002) +~~ROW COUNT: 1~~ + +INSERT INTO SMALLINT_dt(a) values(-029) +~~ROW COUNT: 1~~ + +INSERT INTO SMALLINT_dt(a) values(-1234) +~~ROW COUNT: 1~~ + +INSERT INTO SMALLINT_dt(a) values(876) +~~ROW COUNT: 1~~ + +INSERT INTO SMALLINT_dt(a) values(-32768) +~~ROW COUNT: 1~~ + +INSERT INTO SMALLINT_dt(a) values(32767) +~~ROW COUNT: 1~~ + +INSERT INTO SMALLINT_dt(a) values(NULL) +~~ROW COUNT: 1~~ + +SELECT * FROM SMALLINT_dt; +~~START~~ +smallint +0 +-10 +100 +2 +-29 +-1234 +876 +-32768 +32767 + +0 +-10 +100 +2 +-29 +-1234 +876 +-32768 +32767 + +~~END~~ + +DROP TABLE SMALLINT_dt; diff --git a/contrib/test/JDBC/expected/TestStoredProcedures.out b/contrib/test/JDBC/expected/TestStoredProcedures.out new file mode 100644 index 00000000000..976dea8e415 --- /dev/null +++ b/contrib/test/JDBC/expected/TestStoredProcedures.out @@ -0,0 +1,241 @@ +# PROCEDURE WITH NO BODY +#create procedure sp_test AS BEGIN END; +# PROCEDURE WITH NO PARAMS +create table temp_sp2(a int); +CREATE PROCEDURE sp_test AS BEGIN insert into temp_sp2 values(1); END; +storedproc#!#prep#!#sp_test#!# +~~ROW COUNT: 1~~ + +SELECT * FROM temp_sp2; +~~START~~ +int +1 +~~END~~ + +drop table temp_sp2; +drop Procedure sp_test; +# PROCEDURE WITH INPUT PARAMETER +#drop table temp_sp; +create table temp_sp(a int); +Create Procedure stored_proc1 (@a int) As Begin insert into temp_sp values(@a) End; +# NOT WORKING FOR BABEL,RAISED JIRA 444 +storedproc#!#prep#!#stored_proc1#!#int|-|a|-|-100|-|input +~~ROW COUNT: 1~~ + +# MISMATCH IN RETURN VALUES +exec stored_proc1 -200 +~~ROW COUNT: 1~~ + +exec stored_proc1 0 +~~ROW COUNT: 1~~ + +exec stored_proc1 -1 +~~ROW COUNT: 1~~ + +exec stored_proc1 2 +~~ROW COUNT: 1~~ + +# filed Jira on this, doesnt work for babel +#exec stored_proc1 2.2 +SELECT * FROM temp_sp; +~~START~~ +int +-100 +-200 +0 +-1 +2 +~~END~~ + +DROP table temp_sp; +DROP Procedure stored_proc1 +# input parameter +CREATE PROCEDURE sp_test1 (@a INT) AS BEGIN SET @a=100; Select @a as a; END; +exec sp_test1 2 +~~START~~ +int +100 +~~END~~ + +Declare @a int;Set @a=1; exec sp_test1 @a;select @a as a; +~~START~~ +int +100 +~~END~~ + +~~START~~ +int +1 +~~END~~ + +storedproc#!#prep#!#sp_test1#!#int|-|a|-|1|-|input +~~START~~ +int +100 +~~END~~ + +storedproc#!#prep#!#sp_test1#!#int|-|a|-|10|-|input +~~START~~ +int +100 +~~END~~ + +DROP PROCEDURE sp_test1 +# TESTING OUT PARAMETERS FOR ALL THE DATATYPES +# int +CREATE PROCEDURE sp_test1 (@a INT OUTPUT) AS BEGIN SET @a=100; Select @a as a; END; +#Declare @a int;Set @a=1; exec sp_test1 @a;select @a as a; +storedproc#!#prep#!#sp_test1#!#int|-|a|-|1|-|output +~~START~~ +int +100 +~~END~~ + +storedproc#!#prep#!#sp_test1#!#int|-|a|-|1|-|inputoutput +~~START~~ +int +100 +~~END~~ + +DROP PROCEDURE sp_test1 +# smallint +CREATE PROCEDURE sp_test2 (@a SMALLINT OUTPUT) AS BEGIN SET @a=100; Select @a as a; END; +#Declare @a smallint;Set @a=1; exec sp_test2 @a;select @a as a; +storedproc#!#prep#!#sp_test2#!#smallint|-|a|-|10|-|output +~~START~~ +smallint +100 +~~END~~ + +storedproc#!#prep#!#sp_test2#!#smallint|-|a|-|10|-|inputoutput +~~START~~ +smallint +100 +~~END~~ + +DROP PROCEDURE sp_test2 +# bigint +CREATE PROCEDURE sp_test3 (@a BIGINT OUTPUT) AS BEGIN SET @a=100; Select @a as a; END; +storedproc#!#prep#!#sp_test3#!#bigint|-|a|-|10|-|output +~~START~~ +bigint +100 +~~END~~ + +storedproc#!#prep#!#sp_test3#!#bigint|-|a|-|10|-|inputoutput +~~START~~ +bigint +100 +~~END~~ + +DROP PROCEDURE sp_test3 +# tinyint +#CREATE PROCEDURE sp_test4 (@a tinyint OUTPUT) AS BEGIN SET @a=100; Select @a as a; END; +#storedproc#!#prep#!#sp_test4#!#tinyint|-|a|-|10|-|output +#storedproc#!#prep#!#sp_test4#!#tinyint|-|a|-|10|-|inputoutput +#DROP PROCEDURE sp_test4 +# float +CREATE PROCEDURE sp_test5 (@a float OUTPUT) AS BEGIN SET @a=100.12; Select @a as a; END; +#Declare @a float;Set @a=1.1; exec sp_test5 @a;select @a as a; +storedproc#!#prep#!#sp_test5#!#float|-|a|-|10.1|-|output +~~START~~ +float +100.12 +~~END~~ + +storedproc#!#prep#!#sp_test5#!#float|-|a|-|10.1|-|inputoutput +~~START~~ +float +100.12 +~~END~~ + +DROP PROCEDURE sp_test5 +# varchar +#CREATE PROCEDURE sp_test6 (@a varchar OUTPUT) AS BEGIN SET @a='helloworld'; Select @a as a; END; +#storedproc#!#prep#!#sp_test6#!#varchar|-|a|-|hello|-|output +#storedproc#!#prep#!#sp_test6#!#varchar|-|a|-|hello|-|inputoutput +#DROP PROCEDURE sp_test6 +# char BABEL-705 +#CREATE PROCEDURE sp_test7 (@a char OUTPUT) AS BEGIN SET @a='b'; Select @a as a; END; +#Declare @a varchar;Set @a='h'; exec sp_test7 @a;select @a as a; +#storedproc#!#prep#!#sp_test7#!#char|-|a|-|t|-|output +#storedproc#!#prep#!#sp_test7#!#char|-|a|-|t|-|inputoutput +#DROP PROCEDURE sp_test7 +# nvarchar +#CREATE PROCEDURE sp_test9 (@a nvarchar OUTPUT) AS BEGIN SET @a='helloworld'; Select @a as a; END; +#Declare @a nvarchar;Set @a='hello'; exec sp_test9 @a;select @a as a; +#storedproc#!#prep#!#sp_test9#!#varchar|-|a|-|hello|-|output +#storedproc#!#prep#!#sp_test9#!#varchar|-|a|-|hello|-|inputoutput +#DROP PROCEDURE sp_test9 +# numeric +CREATE PROCEDURE sp_test10 (@a numeric(10,4) OUTPUT) AS BEGIN SET @a=100.41; Select @a as a; END; +#Declare @a numeric(10,4);Set @a=10.04; exec sp_test10 @a;select @a as a; +#storedproc#!#prep#!#sp_test10#!#numeric|-|a|-|123|-|10|-|3|-|output +#storedproc#!#prep#!#sp_test10#!#numeric|-|a|-|123|-|10|-|2|-|inputoutput +DROP PROCEDURE sp_test10 +# decimal +CREATE PROCEDURE sp_test11 (@a decimal(10,4) OUTPUT) AS BEGIN SET @a=100.41; Select @a as a; END; +#Declare @a decimal(10,4);Set @a=10.04; exec sp_test11 @a;select @a as a; +#storedproc#!#prep#!#sp_test11#!#decimal|-|a|-|123|-|10|-|3|-|output +#storedproc#!#prep#!#sp_test11#!#decimal|-|a|-|123|-|10|-|2|-|inputoutput +DROP PROCEDURE sp_test11 +# binary +#CREATE PROCEDURE sp_test12 (@a binary OUTPUT) AS BEGIN SET @a=0x121; Select @a as a; END; +#exec sp_test12 0x122 +#Declare @a binary;Set @a=0x121; exec sp_test12 @a;select @a as a; +#storedproc#!#prep#!#sp_test12#!#binary|-|a|-|0x122|-|output +#storedproc#!#prep#!#sp_test12#!#binary|-|a|-|0x122|-|inputoutput +#DROP PROCEDURE sp_test12 +# varbinary BABEL-701 +#CREATE PROCEDURE sp_test13 (@a varbinary OUTPUT) AS BEGIN SET @a=0x121; Select @a as a; END; +#exec sp_test13 0x122 +#Declare @a varbinary;Set @a=0x122; exec sp_test13 @a;select @a as a; +#storedproc#!#prep#!#sp_test13#!#varbinary|-|a|-|0x122|-|output +#storedproc#!#prep#!#sp_test13#!#varbinary|-|a|-|0x122|-|inputoutput +#DROP PROCEDURE sp_test13 +# date +CREATE PROCEDURE sp_test14 (@a date output) AS BEGIN SET @a='1999-1-3'; Select @a as a; END; +#Declare @a DATE;Set @a='9999-12-31'; exec sp_test14 @a;select @a as a; +storedproc#!#prep#!#sp_test14#!#DATE|-|a|-|9999-12-31|-|output +~~START~~ +date +1999-01-03 +~~END~~ + +storedproc#!#prep#!#sp_test14#!#DATE|-|a|-|9999-12-31|-|inputoutput +~~START~~ +date +1999-01-03 +~~END~~ + +DROP PROCEDURE sp_test14 +# time +#CREATE PROCEDURE sp_test15 (@a time(4) OUTPUT) AS BEGIN SET @a='11:25:07.123'; Select @a as a; END; +#Declare @a Time;Set @a='12:45:37.123'; exec sp_test15 @a;select @a as a; +#storedproc#!#prep#!#sp_test15#!#Time|-|a|-|12:45:37.123|-|3|-|output +#storedproc#!#prep#!#sp_test15#!#Time|-|a|-|12:45:37.123|-|3|-|inputoutput +#DROP PROCEDURE sp_test15 +# dateime BABEL-694 +#CREATE PROCEDURE sp_test16 (@a datetime output) AS BEGIN SET @a='2004-05-18 13:59:59.995'; Select @a as a; END; +#Declare @a DATETIME;Set @a='2000-02-28 23:59:59.995'; exec sp_test16 @a;select @a as a; +#storedproc#!#prep#!#sp_test16#!#DATETIME|-|a|-|2000-02-28 23:59:59.995|-|output +#storedproc#!#prep#!#sp_test16#!#DATETIME|-|a|-|2000-02-28 23:59:59.995|-|inputoutput +#DROP PROCEDURE sp_test16 +# datetime2 +#CREATE PROCEDURE sp_test17 (@a datetime2(5) OUTPUT) AS BEGIN SET @a='2014-10-2 1:45:37.123456'; Select @a as a; END; +#Declare @a Datetime2;Set @a='2016-10-23 12:45:37.123456'; exec sp_test17 @a;select @a as a; +#storedproc#!#prep#!#sp_test17#!#Datetime2|-|a|-|2016-10-23 12:45:37.123456|-|5|-|output +#storedproc#!#prep#!#sp_test17#!#Datetime2|-|a|-|2016-10-23 12:45:37.123456|-|5|-|inputoutput +#DROP PROCEDURE sp_test17 +# smalldatetime BABEL-694 +#CREATE PROCEDURE sp_test18 (@a smalldatetime output) AS BEGIN SET @a='2010-02-03 12:58:23'; Select @a as a; END; +#Declare @a SMALLDATETIME;Set @a='2000-12-13 12:58:23'; exec sp_test18 @a;select @a as a; +#storedproc#!#prep#!#sp_test18#!#SMALLDATETIME|-|a|-|2000-12-13 12:58:23|-|output +#storedproc#!#prep#!#sp_test18#!#SMALLDATETIME|-|a|-|2000-12-13 12:58:23|-|inputoutput +#DROP PROCEDURE sp_test18 +# UID +#CREATE PROCEDURE sp_test19 (@a uniqueidentifier OUTPUT) AS BEGIN SET @a='ce8af10a-2709-43b0-9e4e-a02753929d17'; Select @a as a; END; +#Declare @a uniqueidentifier;Set @a='5b7c2e8d-6d90-411d-8e19-9a81067e6f6c'; exec sp_test19 @a;select @a as a; +#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 diff --git a/contrib/test/JDBC/expected/TestText.out b/contrib/test/JDBC/expected/TestText.out new file mode 100644 index 00000000000..2fa7afe5f33 --- /dev/null +++ b/contrib/test/JDBC/expected/TestText.out @@ -0,0 +1,32 @@ +CREATE TABLE TEXT_dt (a text, b ntext) +#path to file should be with respect to root of test suite +prepst#!# INSERT INTO TEXT_dt(a, b) values(?, ?) #!#TEXT|-|a|-|utils/sample.txt#!#NTEXT|-|b|-|utils/sample.txt +~~ROW COUNT: 1~~ + +prepst#!#exec#!#TEXT|-|a|-|utils/blank.txt#!#NTEXT|-|b|-|utils/blank.txt +~~ROW COUNT: 1~~ + +prepst#!#exec#!#TEXT|-|a|-|#!#NTEXT|-|b|-| +~~ROW COUNT: 1~~ + +prepst#!#exec#!#TEXT|-|a|-|#!#NTEXT|-|b|-|utils/utf16.txt +~~ROW COUNT: 1~~ + +prepst#!#exec#!#TEXT|-|a|-|#!#NTEXT|-|b|-|utils/emojisText.txt +~~ROW COUNT: 1~~ + +prepst#!#exec#!#TEXT|-|a|-|#!#NTEXT|-|b|-|utils/devanagari.txt +~~ROW COUNT: 1~~ + +SELECT * FROM TEXT_dt; +~~START~~ +text#!#ntext +AAAAAAAAAAAAAAAAAAAABBBBBBBBBBCCCCCbadksjvbajsdcbvjadssejvhsdbfjhcgvasdhgcvsj21639812365091264#!#AAAAAAAAAAAAAAAAAAAABBBBBBBBBBCCCCCbadksjvbajsdcbvjadssejvhsdbfjhcgvasdhgcvsj21639812365091264 +#!# +#!# +#!# !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƻƼƽƾƿǀǁǂǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴǵǶǷǸǹǺǻǼǽǾǿȀȁȂȃȄȅȆȇȈȉȊȋȌȍȎȏȐȑȒȓȔȕȖȗȘșȚțȜȝȞȟȠȡȢȣȤȥȦȧȨȩȪȫȬȭȮȯȰȱȲȳȴȵȶȷȸȹȺȻȼȽȾȿɀɁɂɃɄɅɆɇɈɉɊɋɌɍɎɏɐɑɒɓɔɕɖɗɘəɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯʰʱʲʳʴʵʶʷʸʹʺʻʼʽʾʿˀˁ˂˃˄˅ˆˇˈˉˊˋˌˍˎˏːˑ˒˓˔˕˖˗˘˙˚˛˜˝˞˟ˠˡˢˣˤ˥˦˧˨˩˪˫ˬ˭ˮ˯˰˱˲˳˴˵˶˷˸˹˺˻˼˽˾˿̴̵̶̷̸̡̢̧̨̛̖̗̘̙̜̝̞̟̠̣̤̥̦̩̪̫̬̭̮̯̰̱̲̳̹̺̻̼͇͈͉͍͎̀́̂̃̄̅̆̇̈̉̊̋̌̍̎̏̐̑̒̓̔̽̾̿̀́͂̓̈́͆͊͋͌̕̚ͅ͏͓͔͕͖͙͚͐͑͒͗͛ͣͤͥͦͧͨͩͪͫͬͭͮͯ͘͜͟͢͝͞͠͡ͰͱͲͳʹ͵Ͷͷͺͻͼͽ;΄΅Ά·ΈΉΊΌΎΏΐΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩΪΫάέήίΰαβγδεζηθικλμνξοπρςστυφχψωϊϋόύώϏϐϑϒϓϔϕϖϗϘϙϚϛϜϝϞϟϠϡϢϣϤϥϦϧϨϩϪϫϬϭϮϯϰϱϲϳϴϵ϶ϷϸϹϺϻϼϽϾϿЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяѐёђѓєѕіїјљњћќѝўџѠѡѢѣѤѥѦѧѨѩѪѫѬѭѮѯѰѱѲѳѴѵѶѷѸѹѺѻѼѽѾѿҀҁ҂҃҄҅҆҇҈҉ҊҋҌҍҎҏҐґҒғҔҕҖҗҘҙҚқҜҝҞҟҠҡҢңҤҥҦҧҨҩҪҫҬҭҮүҰұҲҳҴҵҶҷҸҹҺһҼҽҾҿӀӁӂӃӄӅӆӇӈӉӊӋӌӍӎӏӐӑӒӓӔӕӖӗӘәӚӛӜӝӞӟӠӡӢӣӤӥӦӧӨөӪӫӬӭӮӯӰӱӲӳӴӵӶӷӸӹӺӻӼӽӾӿԀԁԂԃԄԅԆԇԈԉԊԋԌԍԎԏԐԑԒԓԔԕԖԗԘԙԚԛԜԝԞԟԠԡԢԣԤԥԦԧԱԲԳԴԵԶԷԸԹԺԻԼԽԾԿՀՁՂՃՄՅՆՇՈՉՊՋՌՍՎՏՐՑՒՓՔՕՖՙ՚՛՜՝՞՟աբգդեզէըթժիլխծկհձղճմյնշոչպջռսվտրցւփքօֆև։֊֏ְֱֲֳִֵֶַָֹֺֻּֽ֑֖֛֢֣֤֥֦֧֪֚֭֮֒֓֔֕֗֘֙֜֝֞֟֠֡֨֩֫֬֯־ֿ׀ׁׂ׃ׅׄ׆ׇאבגדהוזחטיךכלםמןנסעףפץצקרשתװױײ׳״؀؁؂؃؄؆؇؈؉؊؋،؍؎؏ؘؙؚؐؑؒؓؔؕؖؗ؛؞؟ؠءآأؤإئابةتثجحخدذرزسشصضطظعغػؼؽؾؿـفقكلمنهوىيًٌٍَُِّْٕٖٜٟٓٔٗ٘ٙٚٛٝٞ٠١٢٣٤٥٦٧٨٩٪٫٬٭ٮٯٰٱٲٳٴٵٶٷٸٹٺٻټٽپٿڀځڂڃڄڅچڇڈډڊڋڌڍڎڏڐڑڒړڔڕږڗژڙښڛڜڝڞڟڠڡڢڣڤڥڦڧڨکڪګڬڭڮگڰڱڲڳڴڵڶڷڸڹںڻڼڽھڿۀہۂۃۄۅۆۇۈۉۊۋیۍێۏېۑےۓ۔ەۖۗۘۙۚۛۜ۝۞ۣ۟۠ۡۢۤۥۦۧۨ۩۪ۭ۫۬ۮۯ۰۱۲۳۴۵۶۷۸۹ۺۻۼ۽۾ۿ܀܁܂܃܄܅܆܇܈܉܊܋܌܍܏ܐܑܒܓܔܕܖܗܘܙܚܛܜܝܞܟܠܡܢܣܤܥܦܧܨܩܪܫܬܭܮܯܱܴܷܸܹܻܼܾ݂݄݆݈ܰܲܳܵܶܺܽܿ݀݁݃݅݇݉݊ݍݎݏݐݑݒݓݔݕݖݗݘݙݚݛݜݝݞݟݠݡݢݣݤݥݦݧݨݩݪݫݬݭݮݯݰݱݲݳݴݵݶݷݸݹݺݻݼݽݾݿހށނރބޅކއވމފދތލގޏސޑޒޓޔޕޖޗޘޙޚޛޜޝޞޟޠޡޢޣޤޥަާިީުޫެޭޮޯްޱ߀߁߂߃߄߅߆߇߈߉ߊߋߌߍߎߏߐߑߒߓߔߕߖߗߘߙߚߛߜߝߞߟߠߡߢߣߤߥߦߧߨߩߪ߲߫߬߭߮߯߰߱߳ߴߵ߶߷߸߹ߺࠀࠁࠂࠃࠄࠅࠆࠇࠈࠉࠊࠋࠌࠍࠎࠏࠐࠑࠒࠓࠔࠕࠖࠗ࠘࠙ࠚࠛࠜࠝࠞࠟࠠࠡࠢࠣࠤࠥࠦࠧࠨࠩࠪࠫࠬ࠭࠰࠱࠲࠳࠴࠵࠶࠷࠸࠹࠺࠻࠼࠽࠾ࡀࡁࡂࡃࡄࡅࡆࡇࡈࡉࡊࡋࡌࡍࡎࡏࡐࡑࡒࡓࡔࡕࡖࡗࡘ࡙࡚࡛࡞ࢠࢢࢣࢤࢥࢦࢧࢨࢩࢪࢫࢬࣰࣱࣲࣦࣩ࣭࣮࣯ࣶࣹࣺࣤࣥࣧࣨ࣪࣫࣬ࣳࣴࣵࣷࣸࣻࣼࣽࣾऀँंःऄअआइईउऊऋऌऍऎएऐऑऒओऔकखगघङचछजझञटठडढणतथदधनऩपफबभमयरऱलळऴवशषसहऺऻ़ऽािीुूृॄॅॆेैॉॊोौ्ॎॏॐ॒॑॓॔ॕॖॗक़ख़ग़ज़ड़ढ़फ़य़ॠॡॢॣ।॥०१२३४५६७८९॰ॱॲॳॴॵॶॷॹॺॻॼॽॾॿঁংঃঅআইঈউঊঋঌএঐওঔকখগঘঙচছজঝঞটঠডঢণতথদধনপফবভমযরলশষসহ়ঽািীুূৃৄেৈোৌ্ৎৗড়ঢ়য়ৠৡৢৣ০১২৩৪৫৬৭৮৯ৰৱ৲৳৴৵৶৷৸৹৺৻ਁਂਃਅਆਇਈਉਊਏਐਓਔਕਖਗਘਙਚਛਜਝਞਟਠਡਢਣਤਥਦਧਨਪਫਬਭਮਯਰਲਲ਼ਵਸ਼ਸਹ਼ਾਿੀੁੂੇੈੋੌ੍ੑਖ਼ਗ਼ਜ਼ੜਫ਼੦੧੨੩੪੫੬੭੮੯ੰੱੲੳੴੵઁંઃઅઆઇઈઉઊઋઌઍએઐઑઓઔકખગઘઙચછજઝઞટઠડઢણતથદધનપફબભમયરલળવશષસહ઼ઽાિીુૂૃૄૅેૈૉોૌ્ૐૠૡૢૣ૦૧૨૩૪૫૬૭૮૯૰૱ଁଂଃଅଆଇଈଉଊଋଌଏଐଓଔକଖଗଘଙଚଛଜଝଞଟଠଡଢଣତଥଦଧନପଫବଭମଯରଲଳଵଶଷସହ଼ଽାିୀୁୂୃୄେୈୋୌ୍ୖୗଡ଼ଢ଼ୟୠୡୢୣ୦୧୨୩୪୫୬୭୮୯୰ୱ୲୳୴୵୶୷ஂஃஅஆஇஈஉஊஎஏஐஒஓஔகஙசஜஞடணதநனபமயரறலளழவஶஷஸஹாிீுூெேைொோௌ்ௐௗ௦௧௨௩௪௫௬௭௮௯௰௱௲௳௴௵௶௷௸௹௺ఁంఃఅఆఇఈఉఊఋఌఎఏఐఒఓఔకఖగఘఙచఛజఝఞటఠడఢణతథదధనపఫబభమయరఱలళవశషసహఽాిీుూృౄెేైొోౌ్ౕౖౘౙౠౡౢౣ౦౧౨౩౪౫౬౭౮౯౸౹౺౻౼౽౾౿ಂಃಅಆಇಈಉಊಋಌಎಏಐಒಓಔಕಖಗಘಙಚಛಜಝಞಟಠಡಢಣತಥದಧನಪಫಬಭಮಯರಱಲಳವಶಷಸಹ಼ಽಾಿೀುೂೃೄೆೇೈೊೋೌ್ೕೖೞೠೡೢೣ೦೧೨೩೪೫೬೭೮೯ೱೲംഃഅആഇഈഉഊഋഌഎഏഐഒഓഔകഖഗഘങചഛജഝഞടഠഡഢണതഥദധനഩപഫബഭമയരറലളഴവശഷസഹഺഽാിീുൂൃൄെേൈൊോൌ്ൎൗൠൡൢൣ൦൧൨൩൪൫൬൭൮൯൰൱൲൳൴൵൹ൺൻർൽൾൿංඃඅආඇඈඉඊඋඌඍඎඏඐඑඒඓඔඕඖකඛගඝඞඟචඡජඣඤඥඦටඨඩඪණඬතථදධනඳපඵබභමඹයරලවශෂසහළෆ්ාැෑිීුූෘෙේෛොෝෞෟෲෳ෴กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำิีึืฺุู฿เแโใไๅๆ็่้๊๋์ํ๎๏๐๑๒๓๔๕๖๗๘๙๚๛ກຂຄງຈຊຍດຕຖທນບປຜຝພຟມຢຣລວສຫອຮຯະັາຳິີຶືຸູົຼຽເແໂໃໄໆ່້໊໋໌ໍ໐໑໒໓໔໕໖໗໘໙ໜໝໞໟༀ༁༂༃༄༅༆༇༈༉༊་༌།༎༏༐༑༒༓༔༕༖༗༘༙༚༛༜༝༞༟༠༡༢༣༤༥༦༧༨༩༪༫༬༭༮༯༰༱༲༳༴༵༶༷༸༹༺༻༼༽༾༿ཀཁགགྷངཅཆཇཉཊཋཌཌྷཎཏཐདདྷནཔཕབབྷམཙཚཛཛྷཝཞཟའཡརལཤཥསཧཨཀྵཪཫཬཱཱཱིིུུྲྀཷླྀཹེཻོཽཾཿ྄ཱྀྀྂྃ྅྆྇ྈྉྊྋྌྍྎྏྐྑྒྒྷྔྕྖྗྙྚྛྜྜྷྞྟྠྡྡྷྣྤྥྦྦྷྨྩྪྫྫྷྭྮྯྰྱྲླྴྵྶྷྸྐྵྺྻྼ྾྿࿀࿁࿂࿃࿄࿅࿆࿇࿈࿉࿊࿋࿌࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚ကခဂဃငစဆဇဈဉညဋဌဍဎဏတထဒဓနပဖဗဘမယရလဝသဟဠအဢဣဤဥဦဧဨဩဪါာိီုူေဲဳဴဵံ့း္်ျြွှဿ၀၁၂၃၄၅၆၇၈၉၊။၌၍၎၏ၐၑၒၓၔၕၖၗၘၙၚၛၜၝၞၟၠၡၢၣၤၥၦၧၨၩၪၫၬၭၮၯၰၱၲၳၴၵၶၷၸၹၺၻၼၽၾၿႀႁႂႃႄႅႆႇႈႉႊႋႌႍႎႏ႐႑႒႓႔႕႖႗႘႙ႚႛႜႝ႞႟ႠႡႢႣႤႥႦႧႨႩႪႫႬႭႮႯႰႱႲႳႴႵႶႷႸႹႺႻႼႽႾႿჀჁჂჃჄჅჇჍაბგდევზთიკლმნოპჟრსტუფქღყშჩცძწჭხჯჰჱჲჳჴჵჶჷჸჹჺ჻ჼჽჾჿᄀᄁᄂᄃᄄᄅᄆᄇᄈᄉᄊᄋᄌᄍᄎᄏᄐᄑᄒᄓᄔᄕᄖᄗᄘᄙᄚᄛᄜᄝᄞᄟᄠᄡᄢᄣᄤᄥᄦᄧᄨᄩᄪᄫᄬᄭᄮᄯᄰᄱᄲᄳᄴᄵᄶᄷᄸᄹᄺᄻᄼᄽᄾᄿᅀᅁᅂᅃᅄᅅᅆᅇᅈᅉᅊᅋᅌᅍᅎᅏᅐᅑᅒᅓᅔᅕᅖᅗᅘᅙᅚᅛᅜᅝᅞᅟᅠᅡᅢᅣᅤᅥᅦᅧᅨᅩᅪᅫᅬᅭᅮᅯᅰᅱᅲᅳᅴᅵᅶᅷᅸᅹᅺᅻᅼᅽᅾᅿᆀᆁᆂᆃᆄᆅᆆᆇᆈᆉᆊᆋᆌᆍᆎᆏᆐᆑᆒᆓᆔᆕᆖᆗᆘᆙᆚᆛᆜᆝᆞᆟᆠᆡᆢᆣᆤᆥᆦᆧᆨᆩᆪᆫᆬᆭᆮᆯᆰᆱᆲᆳᆴᆵᆶᆷᆸᆹᆺᆻᆼᆽᆾᆿᇀᇁᇂᇃᇄᇅᇆᇇᇈᇉᇊᇋᇌᇍᇎᇏᇐᇑᇒᇓᇔᇕᇖᇗᇘᇙᇚᇛᇜᇝᇞᇟᇠᇡᇢᇣᇤᇥᇦᇧᇨᇩᇪᇫᇬᇭᇮᇯᇰᇱᇲᇳᇴᇵᇶᇷᇸᇹᇺᇻᇼᇽᇾᇿሀሁሂሃሄህሆሇለሉሊላሌልሎሏሐሑሒሓሔሕሖሗመሙሚማሜምሞሟሠሡሢሣሤሥሦሧረሩሪራሬርሮሯሰሱሲሳሴስሶሷሸሹሺሻሼሽሾሿቀቁቂቃቄቅቆቇቈቊቋቌቍቐቑቒቓቔቕቖቘቚቛቜቝበቡቢባቤብቦቧቨቩቪቫቬቭቮቯተቱቲታቴትቶቷቸቹቺቻቼችቾቿኀኁኂኃኄኅኆኇኈኊኋኌኍነኑኒናኔንኖኗኘኙኚኛኜኝኞኟአኡኢኣኤእኦኧከኩኪካኬክኮኯኰኲኳኴኵኸኹኺኻኼኽኾዀዂዃዄዅወዉዊዋዌውዎዏዐዑዒዓዔዕዖዘዙዚዛዜዝዞዟዠዡዢዣዤዥዦዧየዩዪያዬይዮዯደዱዲዳዴድዶዷዸዹዺዻዼዽዾዿጀጁጂጃጄጅጆጇገጉጊጋጌግጎጏጐጒጓጔጕጘጙጚጛጜጝጞጟጠጡጢጣጤጥጦጧጨጩጪጫጬጭጮጯጰጱጲጳጴጵጶጷጸጹጺጻጼጽጾጿፀፁፂፃፄፅፆፇፈፉፊፋፌፍፎፏፐፑፒፓፔፕፖፗፘፙፚ፝፞፟፠፡።፣፤፥፦፧፨፩፪፫፬፭፮፯፰፱፲፳፴፵፶፷፸፹፺፻፼ᎀᎁᎂᎃᎄᎅᎆᎇᎈᎉᎊᎋᎌᎍᎎᎏ᎐᎑᎒᎓᎔᎕᎖᎗᎘᎙ᎠᎡᎢᎣᎤᎥᎦᎧᎨᎩᎪᎫᎬᎭᎮᎯᎰᎱᎲᎳᎴᎵᎶᎷᎸᎹᎺᎻᎼᎽᎾᎿᏀᏁᏂᏃᏄᏅᏆᏇᏈᏉᏊᏋᏌᏍᏎᏏᏐᏑᏒᏓᏔᏕᏖᏗᏘᏙᏚᏛᏜᏝᏞᏟᏠᏡᏢᏣᏤᏥᏦᏧᏨᏩᏪᏫᏬᏭᏮᏯᏰᏱᏲᏳᏴ᐀ᐁᐂᐃᐄᐅᐆᐇᐈᐉᐊᐋᐌᐍᐎᐏᐐᐑᐒᐓᐔᐕᐖᐗᐘᐙᐚᐛᐜᐝᐞᐟᐠᐡᐢᐣᐤᐥᐦᐧᐨᐩᐪᐫᐬᐭᐮᐯᐰᐱᐲᐳᐴᐵᐶᐷᐸᐹᐺᐻᐼᐽᐾᐿᑀᑁᑂᑃᑄᑅᑆᑇᑈᑉᑊᑋᑌᑍᑎᑏᑐᑑᑒᑓᑔᑕᑖᑗᑘᑙᑚᑛᑜᑝᑞᑟᑠᑡᑢᑣᑤᑥᑦᑧᑨᑩᑪᑫᑬᑭᑮᑯᑰᑱᑲᑳᑴᑵᑶᑷᑸᑹᑺᑻᑼᑽᑾᑿᒀᒁᒂᒃᒄᒅᒆᒇᒈᒉᒊᒋᒌᒍᒎᒏᒐᒑᒒᒓᒔᒕᒖᒗᒘᒙᒚᒛᒜᒝᒞᒟᒠᒡᒢᒣᒤᒥᒦᒧᒨᒩᒪᒫᒬᒭᒮᒯᒰᒱᒲᒳᒴᒵᒶᒷᒸᒹᒺᒻᒼᒽᒾᒿᓀᓁᓂᓃᓄᓅᓆᓇᓈᓉᓊᓋᓌᓍᓎᓏᓐᓑᓒᓓᓔᓕᓖᓗᓘᓙᓚᓛᓜᓝᓞᓟᓠᓡᓢᓣᓤᓥᓦᓧᓨᓩᓪᓫᓬᓭᓮᓯᓰᓱᓲᓳᓴᓵᓶᓷᓸᓹᓺᓻᓼᓽᓾᓿᔀᔁᔂᔃᔄᔅᔆᔇᔈᔉᔊᔋᔌᔍᔎᔏᔐᔑᔒᔓᔔᔕᔖᔗᔘᔙᔚᔛᔜᔝᔞᔟᔠᔡᔢᔣᔤᔥᔦᔧᔨᔩᔪᔫᔬᔭᔮᔯᔰᔱᔲᔳᔴᔵᔶᔷᔸᔹᔺᔻᔼᔽᔾᔿᕀᕁᕂᕃᕄᕅᕆᕇᕈᕉᕊᕋᕌᕍᕎᕏᕐᕑᕒᕓᕔᕕᕖᕗᕘᕙᕚᕛᕜᕝᕞᕟᕠᕡᕢᕣᕤᕥᕦᕧᕨᕩᕪᕫᕬᕭᕮᕯᕰᕱᕲᕳᕴᕵᕶᕷᕸᕹᕺᕻᕼᕽᕾᕿᖀᖁᖂᖃᖄᖅᖆᖇᖈᖉᖊᖋᖌᖍᖎᖏᖐᖑᖒᖓᖔᖕᖖᖗᖘᖙᖚᖛᖜᖝᖞᖟᖠᖡᖢᖣᖤᖥᖦᖧᖨᖩᖪᖫᖬᖭᖮᖯᖰᖱᖲᖳᖴᖵᖶᖷᖸᖹᖺᖻᖼᖽᖾᖿᗀᗁᗂᗃᗄᗅᗆᗇᗈᗉᗊᗋᗌᗍᗎᗏᗐᗑᗒᗓᗔᗕᗖᗗᗘᗙᗚᗛᗜᗝᗞᗟᗠᗡᗢᗣᗤᗥᗦᗧᗨᗩᗪᗫᗬᗭᗮᗯᗰᗱᗲᗳᗴᗵᗶᗷᗸᗹᗺᗻᗼᗽᗾᗿᘀᘁᘂᘃᘄᘅᘆᘇᘈᘉᘊᘋᘌᘍᘎᘏᘐᘑᘒᘓᘔᘕᘖᘗᘘᘙᘚᘛᘜᘝᘞᘟᘠᘡᘢᘣᘤᘥᘦᘧᘨᘩᘪᘫᘬᘭᘮᘯᘰᘱᘲᘳᘴᘵᘶᘷᘸᘹᘺᘻᘼᘽᘾᘿᙀᙁᙂᙃᙄᙅᙆᙇᙈᙉᙊᙋᙌᙍᙎᙏᙐᙑᙒᙓᙔᙕᙖᙗᙘᙙᙚᙛᙜᙝᙞᙟᙠᙡᙢᙣᙤᙥᙦᙧᙨᙩᙪᙫᙬ᙭᙮ᙯᙰᙱᙲᙳᙴᙵᙶᙷᙸᙹᙺᙻᙼᙽᙾᙿ ᚁᚂᚃᚄᚅᚆᚇᚈᚉᚊᚋᚌᚍᚎᚏᚐᚑᚒᚓᚔᚕᚖᚗᚘᚙᚚ᚛᚜ᚠᚡᚢᚣᚤᚥᚦᚧᚨᚩᚪᚫᚬᚭᚮᚯᚰᚱᚲᚳᚴᚵᚶᚷᚸᚹᚺᚻᚼᚽᚾᚿᛀᛁᛂᛃᛄᛅᛆᛇᛈᛉᛊᛋᛌᛍᛎᛏᛐᛑᛒᛓᛔᛕᛖᛗᛘᛙᛚᛛᛜᛝᛞᛟᛠᛡᛢᛣᛤᛥᛦᛧᛨᛩᛪ᛫᛬᛭ᛮᛯᛰᜀᜁᜂᜃᜄᜅᜆᜇᜈᜉᜊᜋᜌᜎᜏᜐᜑᜒᜓ᜔ᜠᜡᜢᜣᜤᜥᜦᜧᜨᜩᜪᜫᜬᜭᜮᜯᜰᜱᜲᜳ᜴᜵᜶ᝀᝁᝂᝃᝄᝅᝆᝇᝈᝉᝊᝋᝌᝍᝎᝏᝐᝑᝒᝓᝠᝡᝢᝣᝤᝥᝦᝧᝨᝩᝪᝫᝬᝮᝯᝰᝲᝳកខគឃងចឆជឈញដឋឌឍណតថទធនបផពភមយរលវឝឞសហឡអឣឤឥឦឧឨឩឪឫឬឭឮឯឰឱឲឳ឴឵ាិីឹឺុូួើឿៀេែៃោៅំះៈ៉៊់៌៍៎៏័៑្៓។៕៖ៗ៘៙៚៛ៜ៝០១២៣៤៥៦៧៨៩៰៱៲៳៴៵៶៷៸៹᠀᠁᠂᠃᠄᠅᠆᠇᠈᠉᠊᠋᠌᠍᠎᠐᠑᠒᠓᠔᠕᠖᠗᠘᠙ᠠᠡᠢᠣᠤᠥᠦᠧᠨᠩᠪᠫᠬᠭᠮᠯᠰᠱᠲᠳᠴᠵᠶᠷᠸᠹᠺᠻᠼᠽᠾᠿᡀᡁᡂᡃᡄᡅᡆᡇᡈᡉᡊᡋᡌᡍᡎᡏᡐᡑᡒᡓᡔᡕᡖᡗᡘᡙᡚᡛᡜᡝᡞᡟᡠᡡᡢᡣᡤᡥᡦᡧᡨᡩᡪᡫᡬᡭᡮᡯᡰᡱᡲᡳᡴᡵᡶᡷᢀᢁᢂᢃᢄᢅᢆᢇᢈᢉᢊᢋᢌᢍᢎᢏᢐᢑᢒᢓᢔᢕᢖᢗᢘᢙᢚᢛᢜᢝᢞᢟᢠᢡᢢᢣᢤᢥᢦᢧᢨᢩᢪᢰᢱᢲᢳᢴᢵᢶᢷᢸᢹᢺᢻᢼᢽᢾᢿᣀᣁᣂᣃᣄᣅᣆᣇᣈᣉᣊᣋᣌᣍᣎᣏᣐᣑᣒᣓᣔᣕᣖᣗᣘᣙᣚᣛᣜᣝᣞᣟᣠᣡᣢᣣᣤᣥᣦᣧᣨᣩᣪᣫᣬᣭᣮᣯᣰᣱᣲᣳᣴᣵᤀᤁᤂᤃᤄᤅᤆᤇᤈᤉᤊᤋᤌᤍᤎᤏᤐᤑᤒᤓᤔᤕᤖᤗᤘᤙᤚᤛᤜᤠᤡᤢᤣᤤᤥᤦᤧᤨᤩᤪᤫᤰᤱᤲᤳᤴᤵᤶᤷᤸ᤻᤹᤺᥀᥄᥅᥆᥇᥈᥉᥊᥋᥌᥍᥎᥏ᥐᥑᥒᥓᥔᥕᥖᥗᥘᥙᥚᥛᥜᥝᥞᥟᥠᥡᥢᥣᥤᥥᥦᥧᥨᥩᥪᥫᥬᥭᥰᥱᥲᥳᥴᦀᦁᦂᦃᦄᦅᦆᦇᦈᦉᦊᦋᦌᦍᦎᦏᦐᦑᦒᦓᦔᦕᦖᦗᦘᦙᦚᦛᦜᦝᦞᦟᦠᦡᦢᦣᦤᦥᦦᦧᦨᦩᦪᦫᦰᦱᦲᦳᦴᦵᦶᦷᦸᦹᦺᦻᦼᦽᦾᦿᧀᧁᧂᧃᧄᧅᧆᧇᧈᧉ᧐᧑᧒᧓᧔᧕᧖᧗᧘᧙᧚᧞᧟᧠᧡᧢᧣᧤᧥᧦᧧᧨᧩᧪᧫᧬᧭᧮᧯᧰᧱᧲᧳᧴᧵᧶᧷᧸᧹᧺᧻᧼᧽᧾᧿ᨀᨁᨂᨃᨄᨅᨆᨇᨈᨉᨊᨋᨌᨍᨎᨏᨐᨑᨒᨓᨔᨕᨖᨘᨗᨙᨚᨛ᨞᨟ᨠᨡᨢᨣᨤᨥᨦᨧᨨᨩᨪᨫᨬᨭᨮᨯᨰᨱᨲᨳᨴᨵᨶᨷᨸᨹᨺᨻᨼᨽᨾᨿᩀᩁᩂᩃᩄᩅᩆᩇᩈᩉᩊᩋᩌᩍᩎᩏᩐᩑᩒᩓᩔᩕᩖᩗᩘᩙᩚᩛᩜᩝᩞ᩠ᩡᩢᩣᩤᩥᩦᩧᩨᩩᩪᩫᩬᩭᩮᩯᩰᩱᩲᩳᩴ᩿᩵᩶᩷᩸᩹᩺᩻᩼᪀᪁᪂᪃᪄᪅᪆᪇᪈᪉᪐᪑᪒᪓᪔᪕᪖᪗᪘᪙᪠᪡᪢᪣᪤᪥᪦ᪧ᪨᪩᪪᪫᪬᪭ᬀᬁᬂᬃᬄᬅᬆᬇᬈᬉᬊᬋᬌᬍᬎᬏᬐᬑᬒᬓᬔᬕᬖᬗᬘᬙᬚᬛᬜᬝᬞᬟᬠᬡᬢᬣᬤᬥᬦᬧᬨᬩᬪᬫᬬᬭᬮᬯᬰᬱᬲᬳ᬴ᬵᬶᬷᬸᬹᬺᬻᬼᬽᬾᬿᭀᭁᭂᭃ᭄ᭅᭆᭇᭈᭉᭊᭋ᭐᭑᭒᭓᭔᭕᭖᭗᭘᭙᭚᭛᭜᭝᭞᭟᭠᭡᭢᭣᭤᭥᭦᭧᭨᭩᭪᭬᭫᭭᭮᭯᭰᭱᭲᭳᭴᭵᭶᭷᭸᭹᭺᭻᭼ᮀᮁᮂᮃᮄᮅᮆᮇᮈᮉᮊᮋᮌᮍᮎᮏᮐᮑᮒᮓᮔᮕᮖᮗᮘᮙᮚᮛᮜᮝᮞᮟᮠᮡᮢᮣᮤᮥᮦᮧᮨᮩ᮪᮫ᮬᮭᮮᮯ᮰᮱᮲᮳᮴᮵᮶᮷᮸᮹ᮺᮻᮼᮽᮾᮿᯀᯁᯂᯃᯄᯅᯆᯇᯈᯉᯊᯋᯌᯍᯎᯏᯐᯑᯒᯓᯔᯕᯖᯗᯘᯙᯚᯛᯜᯝᯞᯟᯠᯡᯢᯣᯤᯥ᯦ᯧᯨᯩᯪᯫᯬᯭᯮᯯᯰᯱ᯲᯳᯼᯽᯾᯿ᰀᰁᰂᰃᰄᰅᰆᰇᰈᰉᰊᰋᰌᰍᰎᰏᰐᰑᰒᰓᰔᰕᰖᰗᰘᰙᰚᰛᰜᰝᰞᰟᰠᰡᰢᰣᰤᰥᰦᰧᰨᰩᰪᰫᰬᰭᰮᰯᰰᰱᰲᰳᰴᰵᰶ᰷᰻᰼᰽᰾᰿᱀᱁᱂᱃᱄᱅᱆᱇᱈᱉ᱍᱎᱏ᱐᱑᱒᱓᱔᱕᱖᱗᱘᱙ᱚᱛᱜᱝᱞᱟᱠᱡᱢᱣᱤᱥᱦᱧᱨᱩᱪᱫᱬᱭᱮᱯᱰᱱᱲᱳᱴᱵᱶᱷᱸᱹᱺᱻᱼᱽ᱾᱿᳀᳁᳂᳃᳄᳅᳆᳇᳐᳑᳒᳓᳔᳕᳖᳗᳘᳙᳜᳝᳞᳟᳚᳛᳠᳡᳢᳣᳤᳥᳦᳧᳨ᳩᳪᳫᳬ᳭ᳮᳯᳰᳱᳲᳳ᳴ᳵᳶᴀᴁᴂᴃᴄᴅᴆᴇᴈᴉᴊᴋᴌᴍᴎᴏᴐᴑᴒᴓᴔᴕᴖᴗᴘᴙᴚᴛᴜᴝᴞᴟᴠᴡᴢᴣᴤᴥᴦᴧᴨᴩᴪᴫᴬᴭᴮᴯᴰᴱᴲᴳᴴᴵᴶᴷᴸᴹᴺᴻᴼᴽᴾᴿᵀᵁᵂᵃᵄᵅᵆᵇᵈᵉᵊᵋᵌᵍᵎᵏᵐᵑᵒᵓᵔᵕᵖᵗᵘᵙᵚᵛᵜᵝᵞᵟᵠᵡᵢᵣᵤᵥᵦᵧᵨᵩᵪᵫᵬᵭᵮᵯᵰᵱᵲᵳᵴᵵᵶᵷᵸᵹᵺᵻᵼᵽᵾᵿᶀᶁᶂᶃᶄᶅᶆᶇᶈᶉᶊᶋᶌᶍᶎᶏᶐᶑᶒᶓᶔᶕᶖᶗᶘᶙᶚᶛᶜᶝᶞᶟᶠᶡᶢᶣᶤᶥᶦᶧᶨᶩᶪᶫᶬᶭᶮᶯᶰᶱᶲᶳᶴᶵᶶᶷᶸᶹᶺᶻᶼᶽᶾᶿ᷐᷎᷂᷊᷏᷽᷿᷀᷁᷃᷄᷅᷆᷇᷈᷉᷋᷌᷑᷒ᷓᷔᷕᷖᷗᷘᷙᷚᷛᷜᷝᷞᷟᷠᷡᷢᷣᷤᷥᷦ᷾᷼᷍ḀḁḂḃḄḅḆḇḈḉḊḋḌḍḎḏḐḑḒḓḔḕḖḗḘḙḚḛḜḝḞḟḠḡḢḣḤḥḦḧḨḩḪḫḬḭḮḯḰḱḲḳḴḵḶḷḸḹḺḻḼḽḾḿṀṁṂṃṄṅṆṇṈṉṊṋṌṍṎṏṐṑṒṓṔṕṖṗṘṙṚṛṜṝṞṟṠṡṢṣṤṥṦṧṨṩṪṫṬṭṮṯṰṱṲṳṴṵṶṷṸṹṺṻṼṽṾṿẀẁẂẃẄẅẆẇẈẉẊẋẌẍẎẏẐẑẒẓẔẕẖẗẘẙẚẛẜẝẞẟẠạẢảẤấẦầẨẩẪẫẬậẮắẰằẲẳẴẵẶặẸẹẺẻẼẽẾếỀềỂểỄễỆệỈỉỊịỌọỎỏỐốỒồỔổỖỗỘộỚớỜờỞởỠỡỢợỤụỦủỨứỪừỬửỮữỰựỲỳỴỵỶỷỸỹỺỻỼỽỾỿἀἁἂἃἄἅἆἇἈἉἊἋἌἍἎἏἐἑἒἓἔἕἘἙἚἛἜἝἠἡἢἣἤἥἦἧἨἩἪἫἬἭἮἯἰἱἲἳἴἵἶἷἸἹἺἻἼἽἾἿὀὁὂὃὄὅὈὉὊὋὌὍὐὑὒὓὔὕὖὗὙὛὝὟὠὡὢὣὤὥὦὧὨὩὪὫὬὭὮὯὰάὲέὴήὶίὸόὺύὼώᾀᾁᾂᾃᾄᾅᾆᾇᾈᾉᾊᾋᾌᾍᾎᾏᾐᾑᾒᾓᾔᾕᾖᾗᾘᾙᾚᾛᾜᾝᾞᾟᾠᾡᾢᾣᾤᾥᾦᾧᾨᾩᾪᾫᾬᾭᾮᾯᾰᾱᾲᾳᾴᾶᾷᾸᾹᾺΆᾼ᾽ι᾿῀῁ῂῃῄῆῇῈΈῊΉῌ῍῎῏ῐῑῒΐῖῗῘῙῚΊ῝῞῟ῠῡῢΰῤῥῦῧῨῩῪΎῬ῭΅`ῲῳῴῶῷῸΌῺΏῼ´῾           ​‌‍‎‏‐‑‒–—―‖‗‘’‚‛“”„‟†‡•‣․‥…‧

‪‭‮ ‰‱′″‴‵‶‷‸‹›※‼‽‾‿⁀⁁⁂⁃⁄⁅⁆⁇⁈⁉⁊⁋⁌⁍⁎⁏⁐⁑⁒⁓⁔⁕⁖⁗⁘⁙⁚⁛⁜⁝⁞ ⁠⁡⁢⁣⁤⁰ⁱ⁴⁵⁶⁷⁸⁹⁺⁻⁼⁽⁾ⁿ₀₁₂₃₄₅₆₇₈₉₊₋₌₍₎ₐₑₒₓₔₕₖₗₘₙₚₛₜ₠₡₢₣₤₥₦₧₨₩₪₫€₭₮₯₰₱₲₳₴₵₶₷₸₹₺₻₼₽₾₿⃒⃓⃘⃙⃚⃐⃑⃔⃕⃖⃗⃛⃜⃝⃞⃟⃠⃡⃢⃣⃤⃥⃦⃪⃫⃨⃬⃭⃮⃯⃧⃩⃰℀℁ℂ℃℄℅℆ℇ℈℉ℊℋℌℍℎℏℐℑℒℓ℔ℕ№℗℘ℙℚℛℜℝ℞℟℠℡™℣ℤ℥Ω℧ℨ℩KÅℬℭ℮ℯℰℱℲℳℴℵℶℷℸℹ℺℻ℼℽℾℿ⅀⅁⅂⅃⅄ⅅⅆⅇⅈⅉ⅊⅋⅌⅍ⅎ⅏⅐⅑⅒⅓⅔⅕⅖⅗⅘⅙⅚⅛⅜⅝⅞⅟ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫⅬⅭⅮⅯⅰⅱⅲⅳⅴⅵⅶⅷⅸⅹⅺⅻⅼⅽⅾⅿↀↁↂↃↄↅↆↇↈ↉←↑→↓↔↕↖↗↘↙↚↛↜↝↞↟↠↡↢↣↤↥↦↧↨↩↪↫↬↭↮↯↰↱↲↳↴↵↶↷↸↹↺↻↼↽↾↿⇀⇁⇂⇃⇄⇅⇆⇇⇈⇉⇊⇋⇌⇍⇎⇏⇐⇑⇒⇓⇔⇕⇖⇗⇘⇙⇚⇛⇜⇝⇞⇟⇠⇡⇢⇣⇤⇥⇦⇧⇨⇩⇪⇫⇬⇭⇮⇯⇰⇱⇲⇳⇴⇵⇶⇷⇸⇹⇺⇻⇼⇽⇾⇿∀∁∂∃∄∅∆∇∈∉∊∋∌∍∎∏∐∑−∓∔∕∖∗∘∙√∛∜∝∞∟∠∡∢∣∤∥∦∧∨∩∪∫∬∭∮∯∰∱∲∳∴∵∶∷∸∹∺∻∼∽∾∿≀≁≂≃≄≅≆≇≈≉≊≋≌≍≎≏≐≑≒≓≔≕≖≗≘≙≚≛≜≝≞≟≠≡≢≣≤≥≦≧≨≩≪≫≬≭≮≯≰≱≲≳≴≵≶≷≸≹≺≻≼≽≾≿⊀⊁⊂⊃⊄⊅⊆⊇⊈⊉⊊⊋⊌⊍⊎⊏⊐⊑⊒⊓⊔⊕⊖⊗⊘⊙⊚⊛⊜⊝⊞⊟⊠⊡⊢⊣⊤⊥⊦⊧⊨⊩⊪⊫⊬⊭⊮⊯⊰⊱⊲⊳⊴⊵⊶⊷⊸⊹⊺⊻⊼⊽⊾⊿⋀⋁⋂⋃⋄⋅⋆⋇⋈⋉⋊⋋⋌⋍⋎⋏⋐⋑⋒⋓⋔⋕⋖⋗⋘⋙⋚⋛⋜⋝⋞⋟⋠⋡⋢⋣⋤⋥⋦⋧⋨⋩⋪⋫⋬⋭⋮⋯⋰⋱⋲⋳⋴⋵⋶⋷⋸⋹⋺⋻⋼⋽⋾⋿⌀⌁⌂⌃⌄⌅⌆⌇⌈⌉⌊⌋⌌⌍⌎⌏⌐⌑⌒⌓⌔⌕⌖⌗⌘⌙⌚⌛⌜⌝⌞⌟⌠⌡⌢⌣⌤⌥⌦⌧⌨〈〉⌫⌬⌭⌮⌯⌰⌱⌲⌳⌴⌵⌶⌷⌸⌹⌺⌻⌼⌽⌾⌿⍀⍁⍂⍃⍄⍅⍆⍇⍈⍉⍊⍋⍌⍍⍎⍏⍐⍑⍒⍓⍔⍕⍖⍗⍘⍙⍚⍛⍜⍝⍞⍟⍠⍡⍢⍣⍤⍥⍦⍧⍨⍩⍪⍫⍬⍭⍮⍯⍰⍱⍲⍳⍴⍵⍶⍷⍸⍹⍺⍻⍼⍽⍾⍿⎀⎁⎂⎃⎄⎅⎆⎇⎈⎉⎊⎋⎌⎍⎎⎏⎐⎑⎒⎓⎔⎕⎖⎗⎘⎙⎚⎛⎜⎝⎞⎟⎠⎡⎢⎣⎤⎥⎦⎧⎨⎩⎪⎫⎬⎭⎮⎯⎰⎱⎲⎳⎴⎵⎶⎷⎸⎹⎺⎻⎼⎽⎾⎿⏀⏁⏂⏃⏄⏅⏆⏇⏈⏉⏊⏋⏌⏍⏎⏏⏐⏑⏒⏓⏔⏕⏖⏗⏘⏙⏚⏛⏜⏝⏞⏟⏠⏡⏢⏣⏤⏥⏦⏧⏨⏩⏪⏫⏬⏭⏮⏯⏰⏱⏲⏳␀␁␂␃␄␅␆␇␈␉␊␋␌␍␎␏␐␑␒␓␔␕␖␗␘␙␚␛␜␝␞␟␠␡␢␣␤␥␦⑀⑁⑂⑃⑄⑅⑆⑇⑈⑉⑊①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳⑴⑵⑶⑷⑸⑹⑺⑻⑼⑽⑾⑿⒀⒁⒂⒃⒄⒅⒆⒇⒈⒉⒊⒋⒌⒍⒎⒏⒐⒑⒒⒓⒔⒕⒖⒗⒘⒙⒚⒛⒜⒝⒞⒟⒠⒡⒢⒣⒤⒥⒦⒧⒨⒩⒪⒫⒬⒭⒮⒯⒰⒱⒲⒳⒴⒵ⒶⒷⒸⒹⒺⒻⒼⒽⒾⒿⓀⓁⓂⓃⓄⓅⓆⓇⓈⓉⓊⓋⓌⓍⓎⓏⓐⓑⓒⓓⓔⓕⓖⓗⓘⓙⓚⓛⓜⓝⓞⓟⓠⓡⓢⓣⓤⓥⓦⓧⓨⓩ⓪⓫⓬⓭⓮⓯⓰⓱⓲⓳⓴⓵⓶⓷⓸⓹⓺⓻⓼⓽⓾⓿─━│┃┄┅┆┇┈┉┊┋┌┍┎┏┐┑┒┓└┕┖┗┘┙┚┛├┝┞┟┠┡┢┣┤┥┦┧┨┩┪┫┬┭┮┯┰┱┲┳┴┵┶┷┸┹┺┻┼┽┾┿╀╁╂╃╄╅╆╇╈╉╊╋╌╍╎╏═║╒╓╔╕╖╗╘╙╚╛╜╝╞╟╠╡╢╣╤╥╦╧╨╩╪╫╬╭╮╯╰╱╲╳╴╵╶╷╸╹╺╻╼╽╾╿▀▁▂▃▄▅▆▇█▉▊▋▌▍▎▏▐░▒▓▔▕▖▗▘▙▚▛▜▝▞▟■□▢▣▤▥▦▧▨▩▪▫▬▭▮▯▰▱▲△▴▵▶▷▸▹►▻▼▽▾▿◀◁◂◃◄◅◆◇◈◉◊○◌◍◎●◐◑◒◓◔◕◖◗◘◙◚◛◜◝◞◟◠◡◢◣◤◥◦◧◨◩◪◫◬◭◮◯◰◱◲◳◴◵◶◷◸◹◺◻◼◽◾◿☀☁☂☃☄★☆☇☈☉☊☋☌☍☎☏☐☑☒☓☔☕☖☗☘☙☚☛☜☝☞☟☠☡☢☣☤☥☦☧☨☩☪☫☬☭☮☯☰☱☲☳☴☵☶☷☸☹☺☻☼☽☾☿♀♁♂♃♄♅♆♇♈♉♊♋♌♍♎♏♐♑♒♓♔♕♖♗♘♙♚♛♜♝♞♟♠♡♢♣♤♥♦♧♨♩♪♫♬♭♮♯♰♱♲♳♴♵♶♷♸♹♺♻♼♽♾♿⚀⚁⚂⚃⚄⚅⚆⚇⚈⚉⚊⚋⚌⚍⚎⚏⚐⚑⚒⚓⚔⚕⚖⚗⚘⚙⚚⚛⚜⚝⚞⚟⚠⚡⚢⚣⚤⚥⚦⚧⚨⚩⚪⚫⚬⚭⚮⚯⚰⚱⚲⚳⚴⚵⚶⚷⚸⚹⚺⚻⚼⚽⚾⚿⛀⛁⛂⛃⛄⛅⛆⛇⛈⛉⛊⛋⛌⛍⛎⛏⛐⛑⛒⛓⛔⛕⛖⛗⛘⛙⛚⛛⛜⛝⛞⛟⛠⛡⛢⛣⛤⛥⛦⛧⛨⛩⛪⛫⛬⛭⛮⛯⛰⛱⛲⛳⛴⛵⛶⛷⛸⛹⛺⛻⛼⛽⛾⛿✁✂✃✄✅✆✇✈✉✊✋✌✍✎✏✐✑✒✓✔✕✖✗✘✙✚✛✜✝✞✟✠✡✢✣✤✥✦✧✨✩✪✫✬✭✮✯✰✱✲✳✴✵✶✷✸✹✺✻✼✽✾✿❀❁❂❃❄❅❆❇❈❉❊❋❌❍❎❏❐❑❒❓❔❕❖❗❘❙❚❛❜❝❞❟❠❡❢❣❤❥❦❧❨❩❪❫❬❭❮❯❰❱❲❳❴❵❶❷❸❹❺❻❼❽❾❿➀➁➂➃➄➅➆➇➈➉➊➋➌➍➎➏➐➑➒➓➔➕➖➗➘➙➚➛➜➝➞➟➠➡➢➣➤➥➦➧➨➩➪➫➬➭➮➯➰➱➲➳➴➵➶➷➸➹➺➻➼➽➾➿⟀⟁⟂⟃⟄⟅⟆⟇⟈⟉⟊⟋⟌⟍⟎⟏⟐⟑⟒⟓⟔⟕⟖⟗⟘⟙⟚⟛⟜⟝⟞⟟⟠⟡⟢⟣⟤⟥⟦⟧⟨⟩⟪⟫⟬⟭⟮⟯⟰⟱⟲⟳⟴⟵⟶⟷⟸⟹⟺⟻⟼⟽⟾⟿⠀⠁⠂⠃⠄⠅⠆⠇⠈⠉⠊⠋⠌⠍⠎⠏⠐⠑⠒⠓⠔⠕⠖⠗⠘⠙⠚⠛⠜⠝⠞⠟⠠⠡⠢⠣⠤⠥⠦⠧⠨⠩⠪⠫⠬⠭⠮⠯⠰⠱⠲⠳⠴⠵⠶⠷⠸⠹⠺⠻⠼⠽⠾⠿⡀⡁⡂⡃⡄⡅⡆⡇⡈⡉⡊⡋⡌⡍⡎⡏⡐⡑⡒⡓⡔⡕⡖⡗⡘⡙⡚⡛⡜⡝⡞⡟⡠⡡⡢⡣⡤⡥⡦⡧⡨⡩⡪⡫⡬⡭⡮⡯⡰⡱⡲⡳⡴⡵⡶⡷⡸⡹⡺⡻⡼⡽⡾⡿⢀⢁⢂⢃⢄⢅⢆⢇⢈⢉⢊⢋⢌⢍⢎⢏⢐⢑⢒⢓⢔⢕⢖⢗⢘⢙⢚⢛⢜⢝⢞⢟⢠⢡⢢⢣⢤⢥⢦⢧⢨⢩⢪⢫⢬⢭⢮⢯⢰⢱⢲⢳⢴⢵⢶⢷⢸⢹⢺⢻⢼⢽⢾⢿⣀⣁⣂⣃⣄⣅⣆⣇⣈⣉⣊⣋⣌⣍⣎⣏⣐⣑⣒⣓⣔⣕⣖⣗⣘⣙⣚⣛⣜⣝⣞⣟⣠⣡⣢⣣⣤⣥⣦⣧⣨⣩⣪⣫⣬⣭⣮⣯⣰⣱⣲⣳⣴⣵⣶⣷⣸⣹⣺⣻⣼⣽⣾⣿⤀⤁⤂⤃⤄⤅⤆⤇⤈⤉⤊⤋⤌⤍⤎⤏⤐⤑⤒⤓⤔⤕⤖⤗⤘⤙⤚⤛⤜⤝⤞⤟⤠⤡⤢⤣⤤⤥⤦⤧⤨⤩⤪⤫⤬⤭⤮⤯⤰⤱⤲⤳⤴⤵⤶⤷⤸⤹⤺⤻⤼⤽⤾⤿⥀⥁⥂⥃⥄⥅⥆⥇⥈⥉⥊⥋⥌⥍⥎⥏⥐⥑⥒⥓⥔⥕⥖⥗⥘⥙⥚⥛⥜⥝⥞⥟⥠⥡⥢⥣⥤⥥⥦⥧⥨⥩⥪⥫⥬⥭⥮⥯⥰⥱⥲⥳⥴⥵⥶⥷⥸⥹⥺⥻⥼⥽⥾⥿⦀⦁⦂⦃⦄⦅⦆⦇⦈⦉⦊⦋⦌⦍⦎⦏⦐⦑⦒⦓⦔⦕⦖⦗⦘⦙⦚⦛⦜⦝⦞⦟⦠⦡⦢⦣⦤⦥⦦⦧⦨⦩⦪⦫⦬⦭⦮⦯⦰⦱⦲⦳⦴⦵⦶⦷⦸⦹⦺⦻⦼⦽⦾⦿⧀⧁⧂⧃⧄⧅⧆⧇⧈⧉⧊⧋⧌⧍⧎⧏⧐⧑⧒⧓⧔⧕⧖⧗⧘⧙⧚⧛⧜⧝⧞⧟⧠⧡⧢⧣⧤⧥⧦⧧⧨⧩⧪⧫⧬⧭⧮⧯⧰⧱⧲⧳⧴⧵⧶⧷⧸⧹⧺⧻⧼⧽⧾⧿⨀⨁⨂⨃⨄⨅⨆⨇⨈⨉⨊⨋⨌⨍⨎⨏⨐⨑⨒⨓⨔⨕⨖⨗⨘⨙⨚⨛⨜⨝⨞⨟⨠⨡⨢⨣⨤⨥⨦⨧⨨⨩⨪⨫⨬⨭⨮⨯⨰⨱⨲⨳⨴⨵⨶⨷⨸⨹⨺⨻⨼⨽⨾⨿⩀⩁⩂⩃⩄⩅⩆⩇⩈⩉⩊⩋⩌⩍⩎⩏⩐⩑⩒⩓⩔⩕⩖⩗⩘⩙⩚⩛⩜⩝⩞⩟⩠⩡⩢⩣⩤⩥⩦⩧⩨⩩⩪⩫⩬⩭⩮⩯⩰⩱⩲⩳⩴⩵⩶⩷⩸⩹⩺⩻⩼⩽⩾⩿⪀⪁⪂⪃⪄⪅⪆⪇⪈⪉⪊⪋⪌⪍⪎⪏⪐⪑⪒⪓⪔⪕⪖⪗⪘⪙⪚⪛⪜⪝⪞⪟⪠⪡⪢⪣⪤⪥⪦⪧⪨⪩⪪⪫⪬⪭⪮⪯⪰⪱⪲⪳⪴⪵⪶⪷⪸⪹⪺⪻⪼⪽⪾⪿⫀⫁⫂⫃⫄⫅⫆⫇⫈⫉⫊⫋⫌⫍⫎⫏⫐⫑⫒⫓⫔⫕⫖⫗⫘⫙⫚⫛⫝̸⫝⫞⫟⫠⫡⫢⫣⫤⫥⫦⫧⫨⫩⫪⫫⫬⫭⫮⫯⫰⫱⫲⫳⫴⫵⫶⫷⫸⫹⫺⫻⫼⫽⫾⫿⬀⬁⬂⬃⬄⬅⬆⬇⬈⬉⬊⬋⬌⬍⬎⬏⬐⬑⬒⬓⬔⬕⬖⬗⬘⬙⬚⬛⬜⬝⬞⬟⬠⬡⬢⬣⬤⬥⬦⬧⬨⬩⬪⬫⬬⬭⬮⬯⬰⬱⬲⬳⬴⬵⬶⬷⬸⬹⬺⬻⬼⬽⬾⬿⭀⭁⭂⭃⭄⭅⭆⭇⭈⭉⭊⭋⭌⭐⭑⭒⭓⭔⭕⭖⭗⭘⭙ⰀⰁⰂⰃⰄⰅⰆⰇⰈⰉⰊⰋⰌⰍⰎⰏⰐⰑⰒⰓⰔⰕⰖⰗⰘⰙⰚⰛⰜⰝⰞⰟⰠⰡⰢⰣⰤⰥⰦⰧⰨⰩⰪⰫⰬⰭⰮⰰⰱⰲⰳⰴⰵⰶⰷⰸⰹⰺⰻⰼⰽⰾⰿⱀⱁⱂⱃⱄⱅⱆⱇⱈⱉⱊⱋⱌⱍⱎⱏⱐⱑⱒⱓⱔⱕⱖⱗⱘⱙⱚⱛⱜⱝⱞⱠⱡⱢⱣⱤⱥⱦⱧⱨⱩⱪⱫⱬⱭⱮⱯⱰⱱⱲⱳⱴⱵⱶⱷⱸⱹⱺⱻⱼⱽⱾⱿⲀⲁⲂⲃⲄⲅⲆⲇⲈⲉⲊⲋⲌⲍⲎⲏⲐⲑⲒⲓⲔⲕⲖⲗⲘⲙⲚⲛⲜⲝⲞⲟⲠⲡⲢⲣⲤⲥⲦⲧⲨⲩⲪⲫⲬⲭⲮⲯⲰⲱⲲⲳⲴⲵⲶⲷⲸⲹⲺⲻⲼⲽⲾⲿⳀⳁⳂⳃⳄⳅⳆⳇⳈⳉⳊⳋⳌⳍⳎⳏⳐⳑⳒⳓⳔⳕⳖⳗⳘⳙⳚⳛⳜⳝⳞⳟⳠⳡⳢⳣⳤ⳥⳦⳧⳨⳩⳪ⳫⳬⳭⳮ⳯⳰⳱Ⳳⳳ⳹⳺⳻⳼⳽⳾⳿ⴀⴁⴂⴃⴄⴅⴆⴇⴈⴉⴊⴋⴌⴍⴎⴏⴐⴑⴒⴓⴔⴕⴖⴗⴘⴙⴚⴛⴜⴝⴞⴟⴠⴡⴢⴣⴤⴥⴧⴭⴰⴱⴲⴳⴴⴵⴶⴷⴸⴹⴺⴻⴼⴽⴾⴿⵀⵁⵂⵃⵄⵅⵆⵇⵈⵉⵊⵋⵌⵍⵎⵏⵐⵑⵒⵓⵔⵕⵖⵗⵘⵙⵚⵛⵜⵝⵞⵟⵠⵡⵢⵣⵤⵥⵦⵧⵯ⵰⵿ⶀⶁⶂⶃⶄⶅⶆⶇⶈⶉⶊⶋⶌⶍⶎⶏⶐⶑⶒⶓⶔⶕⶖⶠⶡⶢⶣⶤⶥⶦⶨⶩⶪⶫⶬⶭⶮⶰⶱⶲⶳⶴⶵⶶⶸⶹⶺⶻⶼⶽⶾⷀⷁⷂⷃⷄⷅⷆⷈⷉⷊⷋⷌⷍⷎⷐⷑⷒⷓⷔⷕⷖⷘⷙⷚⷛⷜⷝⷞⷠⷡⷢⷣⷤⷥⷦⷧⷨⷩⷪⷫⷬⷭⷮⷯⷰⷱⷲⷳⷴⷵⷶⷷⷸⷹⷺⷻⷼⷽⷾⷿ⸀⸁⸂⸃⸄⸅⸆⸇⸈⸉⸊⸋⸌⸍⸎⸏⸐⸑⸒⸓⸔⸕⸖⸗⸘⸙⸚⸛⸜⸝⸞⸟⸠⸡⸢⸣⸤⸥⸦⸧⸨⸩⸪⸫⸬⸭⸮ⸯ⸰⸱⸲⸳⸴⸵⸶⸷⸸⸹⸺⸻⺀⺁⺂⺃⺄⺅⺆⺇⺈⺉⺊⺋⺌⺍⺎⺏⺐⺑⺒⺓⺔⺕⺖⺗⺘⺙⺛⺜⺝⺞⺟⺠⺡⺢⺣⺤⺥⺦⺧⺨⺩⺪⺫⺬⺭⺮⺯⺰⺱⺲⺳⺴⺵⺶⺷⺸⺹⺺⺻⺼⺽⺾⺿⻀⻁⻂⻃⻄⻅⻆⻇⻈⻉⻊⻋⻌⻍⻎⻏⻐⻑⻒⻓⻔⻕⻖⻗⻘⻙⻚⻛⻜⻝⻞⻟⻠⻡⻢⻣⻤⻥⻦⻧⻨⻩⻪⻫⻬⻭⻮⻯⻰⻱⻲⻳⼀⼁⼂⼃⼄⼅⼆⼇⼈⼉⼊⼋⼌⼍⼎⼏⼐⼑⼒⼓⼔⼕⼖⼗⼘⼙⼚⼛⼜⼝⼞⼟⼠⼡⼢⼣⼤⼥⼦⼧⼨⼩⼪⼫⼬⼭⼮⼯⼰⼱⼲⼳⼴⼵⼶⼷⼸⼹⼺⼻⼼⼽⼾⼿⽀⽁⽂⽃⽄⽅⽆⽇⽈⽉⽊⽋⽌⽍⽎⽏⽐⽑⽒⽓⽔⽕⽖⽗⽘⽙⽚⽛⽜⽝⽞⽟⽠⽡⽢⽣⽤⽥⽦⽧⽨⽩⽪⽫⽬⽭⽮⽯⽰⽱⽲⽳⽴⽵⽶⽷⽸⽹⽺⽻⽼⽽⽾⽿⾀⾁⾂⾃⾄⾅⾆⾇⾈⾉⾊⾋⾌⾍⾎⾏⾐⾑⾒⾓⾔⾕⾖⾗⾘⾙⾚⾛⾜⾝⾞⾟⾠⾡⾢⾣⾤⾥⾦⾧⾨⾩⾪⾫⾬⾭⾮⾯⾰⾱⾲⾳⾴⾵⾶⾷⾸⾹⾺⾻⾼⾽⾾⾿⿀⿁⿂⿃⿄⿅⿆⿇⿈⿉⿊⿋⿌⿍⿎⿏⿐⿑⿒⿓⿔⿕⿰⿱⿲⿳⿴⿵⿶⿷⿸⿹⿺⿻ 、。〃〄々〆〇〈〉《》「」『』【】〒〓〔〕〖〗〘〙〚〛〜〝〞〟〠〡〢〣〤〥〦〧〨〩〪〭〮〯〫〬〰〱〲〳〴〵〶〷〸〹〺〻〼〽〾〿ぁあぃいぅうぇえぉおかがきぎくぐけげこごさざしじすずせぜそぞただちぢっつづてでとどなにぬねのはばぱひびぴふぶぷへべぺほぼぽまみむめもゃやゅゆょよらりるれろゎわゐゑをんゔゕゖ゙゚゛゜ゝゞゟ゠ァアィイゥウェエォオカガキギクグケゲコゴサザシジスズセゼソゾタダチヂッツヅテデトドナニヌネノハバパヒビピフブプヘベペホボポマミムメモャヤュユョヨラリルレロヮワヰヱヲンヴヵヶヷヸヹヺ・ーヽヾヿㄅㄆㄇㄈㄉㄊㄋㄌㄍㄎㄏㄐㄑㄒㄓㄔㄕㄖㄗㄘㄙㄚㄛㄜㄝㄞㄟㄠㄡㄢㄣㄤㄥㄦㄧㄨㄩㄪㄫㄬㄭㄱㄲㄳㄴㄵㄶㄷㄸㄹㄺㄻㄼㄽㄾㄿㅀㅁㅂㅃㅄㅅㅆㅇㅈㅉㅊㅋㅌㅍㅎㅏㅐㅑㅒㅓㅔㅕㅖㅗㅘㅙㅚㅛㅜㅝㅞㅟㅠㅡㅢㅣㅤㅥㅦㅧㅨㅩㅪㅫㅬㅭㅮㅯㅰㅱㅲㅳㅴㅵㅶㅷㅸㅹㅺㅻㅼㅽㅾㅿㆀㆁㆂㆃㆄㆅㆆㆇㆈㆉㆊㆋㆌㆍㆎ㆐㆑㆒㆓㆔㆕㆖㆗㆘㆙㆚㆛㆜㆝㆞㆟ㆠㆡㆢㆣㆤㆥㆦㆧㆨㆩㆪㆫㆬㆭㆮㆯㆰㆱㆲㆳㆴㆵㆶㆷㆸㆹㆺ㇀㇁㇂㇃㇄㇅㇆㇇㇈㇉㇊㇋㇌㇍㇎㇏㇐㇑㇒㇓㇔㇕㇖㇗㇘㇙㇚㇛㇜㇝㇞㇟㇠㇡㇢㇣ㇰㇱㇲㇳㇴㇵㇶㇷㇸㇹㇺㇻㇼㇽㇾㇿ㈀㈁㈂㈃㈄㈅㈆㈇㈈㈉㈊㈋㈌㈍㈎㈏㈐㈑㈒㈓㈔㈕㈖㈗㈘㈙㈚㈛㈜㈝㈞㈠㈡㈢㈣㈤㈥㈦㈧㈨㈩㈪㈫㈬㈭㈮㈯㈰㈱㈲㈳㈴㈵㈶㈷㈸㈹㈺㈻㈼㈽㈾㈿㉀㉁㉂㉃㉄㉅㉆㉇㉈㉉㉊㉋㉌㉍㉎㉏㉐㉑㉒㉓㉔㉕㉖㉗㉘㉙㉚㉛㉜㉝㉞㉟㉠㉡㉢㉣㉤㉥㉦㉧㉨㉩㉪㉫㉬㉭㉮㉯㉰㉱㉲㉳㉴㉵㉶㉷㉸㉹㉺㉻㉼㉽㉾㉿㊀㊁㊂㊃㊄㊅㊆㊇㊈㊉㊊㊋㊌㊍㊎㊏㊐㊑㊒㊓㊔㊕㊖㊗㊘㊙㊚㊛㊜㊝㊞㊟㊠㊡㊢㊣㊤㊥㊦㊧㊨㊩㊪㊫㊬㊭㊮㊯㊰㊱㊲㊳㊴㊵㊶㊷㊸㊹㊺㊻㊼㊽㊾㊿㋀㋁㋂㋃㋄㋅㋆㋇㋈㋉㋊㋋㋌㋍㋎㋏㋐㋑㋒㋓㋔㋕㋖㋗㋘㋙㋚㋛㋜㋝㋞㋟㋠㋡㋢㋣㋤㋥㋦㋧㋨㋩㋪㋫㋬㋭㋮㋯㋰㋱㋲㋳㋴㋵㋶㋷㋸㋹㋺㋻㋼㋽㋾㋿㌀㌁㌂㌃㌄㌅㌆㌇㌈㌉㌊㌋㌌㌍㌎㌏㌐㌑㌒㌓㌔㌕㌖㌗㌘㌙㌚㌛㌜㌝㌞㌟㌠㌡㌢㌣㌤㌥㌦㌧㌨㌩㌪㌫㌬㌭㌮㌯㌰㌱㌲㌳㌴㌵㌶㌷㌸㌹㌺㌻㌼㌽㌾㌿㍀㍁㍂㍃㍄㍅㍆㍇㍈㍉㍊㍋㍌㍍㍎㍏㍐㍑㍒㍓㍔㍕㍖㍗㍘㍙㍚㍛㍜㍝㍞㍟㍠㍡㍢㍣㍤㍥㍦㍧㍨㍩㍪㍫㍬㍭㍮㍯㍰㍱㍲㍳㍴㍵㍶㍷㍸㍹㍺㍻㍼㍽㍾㍿㎀㎁㎂㎃㎄㎅㎆㎇㎈㎉㎊㎋㎌㎍㎎㎏㎐㎑㎒㎓㎔㎕㎖㎗㎘㎙㎚㎛㎜㎝㎞㎟㎠㎡㎢㎣㎤㎥㎦㎧㎨㎩㎪㎫㎬㎭㎮㎯㎰㎱㎲㎳㎴㎵㎶㎷㎸㎹㎺㎻㎼㎽㎾㎿㏀㏁㏂㏃㏄㏅㏆㏇㏈㏉㏊㏋㏌㏍㏎㏏㏐㏑㏒㏓㏔㏕㏖㏗㏘㏙㏚㏛㏜㏝㏞㏟㏠㏡㏢㏣㏤㏥㏦㏧㏨㏩㏪㏫㏬㏭㏮㏯㏰㏱㏲㏳㏴㏵㏶㏷㏸㏹㏺㏻㏼㏽㏾㏿㐀㐁㐂㐃㐄㐅㐆㐇㐈㐉㐊㐋㐌㐍㐎㐏㐐㐑㐒㐓㐔㐕㐖㐗㐘㐙㐚㐛㐜㐝㐞㐟㐠㐡㐢㐣㐤㐥㐦㐧㐨㐩㐪㐫㐬㐭㐮㐯㐰㐱㐲㐳㐴㐵㐶㐷㐸㐹㐺㐻㐼㐽㐾㐿㑀㑁㑂㑃㑄㑅㑆㑇㑈㑉㑊㑋㑌㑍㑎㑏㑐㑑㑒㑓㑔㑕㑖㑗㑘㑙㑚㑛㑜㑝㑞㑟㑠㑡㑢㑣㑤㑥㑦㑧㑨㑩㑪㑫㑬㑭㑮㑯㑰㑱㑲㑳㑴㑵㑶㑷㑸㑹㑺㑻㑼㑽㑾㑿㒀㒁㒂㒃㒄㒅㒆㒇㒈㒉㒊㒋㒌㒍㒎㒏㒐㒑㒒㒓㒔㒕㒖㒗㒘㒙㒚㒛㒜㒝㒞㒟㒠㒡㒢㒣㒤㒥㒦㒧㒨㒩㒪㒫㒬㒭㒮㒯㒰㒱㒲㒳㒴㒵㒶㒷㒸㒹㒺㒻㒼㒽㒾㒿㓀㓁㓂㓃㓄㓅㓆㓇㓈㓉㓊㓋㓌㓍㓎㓏㓐㓑㓒㓓㓔㓕㓖㓗㓘㓙㓚㓛㓜㓝㓞㓟㓠㓡㓢㓣㓤㓥㓦㓧㓨㓩㓪㓫㓬㓭㓮㓯㓰㓱㓲㓳㓴㓵㓶㓷㓸㓹㓺㓻㓼㓽㓾㓿㔀㔁㔂㔃㔄㔅㔆㔇㔈㔉㔊㔋㔌㔍㔎㔏㔐㔑㔒㔓㔔㔕㔖㔗㔘㔙㔚㔛㔜㔝㔞㔟㔠㔡㔢㔣㔤㔥㔦㔧㔨㔩㔪㔫㔬㔭㔮㔯㔰㔱㔲㔳㔴㔵㔶㔷㔸㔹㔺㔻㔼㔽㔾㔿㕀㕁㕂㕃㕄㕅㕆㕇㕈㕉㕊㕋㕌㕍㕎㕏㕐㕑㕒㕓㕔㕕㕖㕗㕘㕙㕚㕛㕜㕝㕞㕟㕠㕡㕢㕣㕤㕥㕦㕧㕨㕩㕪㕫㕬㕭㕮㕯㕰㕱㕲㕳㕴㕵㕶㕷㕸㕹㕺㕻㕼㕽㕾㕿㖀㖁㖂㖃㖄㖅㖆㖇㖈㖉㖊㖋㖌㖍㖎㖏㖐㖑㖒㖓㖔㖕㖖㖗㖘㖙㖚㖛㖜㖝㖞㖟㖠㖡㖢㖣㖤㖥㖦㖧㖨㖩㖪㖫㖬㖭㖮㖯㖰㖱㖲㖳㖴㖵㖶㖷㖸㖹㖺㖻㖼㖽㖾㖿㗀㗁㗂㗃㗄㗅㗆㗇㗈㗉㗊㗋㗌㗍㗎㗏㗐㗑㗒㗓㗔㗕㗖㗗㗘㗙㗚㗛㗜㗝㗞㗟㗠㗡㗢㗣㗤㗥㗦㗧㗨㗩㗪㗫㗬㗭㗮㗯㗰㗱㗲㗳㗴㗵㗶㗷㗸㗹㗺㗻㗼㗽㗾㗿㘀㘁㘂㘃㘄㘅㘆㘇㘈㘉㘊㘋㘌㘍㘎㘏㘐㘑㘒㘓㘔㘕㘖㘗㘘㘙㘚㘛㘜㘝㘞㘟㘠㘡㘢㘣㘤㘥㘦㘧㘨㘩㘪㘫㘬㘭㘮㘯㘰㘱㘲㘳㘴㘵㘶㘷㘸㘹㘺㘻㘼㘽㘾㘿㙀㙁㙂㙃㙄㙅㙆㙇㙈㙉㙊㙋㙌㙍㙎㙏㙐㙑㙒㙓㙔㙕㙖㙗㙘㙙㙚㙛㙜㙝㙞㙟㙠㙡㙢㙣㙤㙥㙦㙧㙨㙩㙪㙫㙬㙭㙮㙯㙰㙱㙲㙳㙴㙵㙶㙷㙸㙹㙺㙻㙼㙽㙾㙿㚀㚁㚂㚃㚄㚅㚆㚇㚈㚉㚊㚋㚌㚍㚎㚏㚐㚑㚒㚓㚔㚕㚖㚗㚘㚙㚚㚛㚜㚝㚞㚟㚠㚡㚢㚣㚤㚥㚦㚧㚨㚩㚪㚫㚬㚭㚮㚯㚰㚱㚲㚳㚴㚵㚶㚷㚸㚹㚺㚻㚼㚽㚾㚿㛀㛁㛂㛃㛄㛅㛆㛇㛈㛉㛊㛋㛌㛍㛎㛏㛐㛑㛒㛓㛔㛕㛖㛗㛘㛙㛚㛛㛜㛝㛞㛟㛠㛡㛢㛣㛤㛥㛦㛧㛨㛩㛪㛫㛬㛭㛮㛯㛰㛱㛲㛳㛴㛵㛶㛷㛸㛹㛺㛻㛼㛽㛾㛿㜀㜁㜂㜃㜄㜅㜆㜇㜈㜉㜊㜋㜌㜍㜎㜏㜐㜑㜒㜓㜔㜕㜖㜗㜘㜙㜚㜛㜜㜝㜞㜟㜠㜡㜢㜣㜤㜥㜦㜧㜨㜩㜪㜫㜬㜭㜮㜯㜰㜱㜲㜳㜴㜵㜶㜷㜸㜹㜺㜻㜼㜽㜾㜿㝀㝁㝂㝃㝄㝅㝆㝇㝈㝉㝊㝋㝌㝍㝎㝏㝐㝑㝒㝓㝔㝕㝖㝗㝘㝙㝚㝛㝜㝝㝞㝟㝠㝡㝢㝣㝤㝥㝦㝧㝨㝩㝪㝫㝬㝭㝮㝯㝰㝱㝲㝳㝴㝵㝶㝷㝸㝹㝺㝻㝼㝽㝾㝿㞀㞁㞂㞃㞄㞅㞆㞇㞈㞉㞊㞋㞌㞍㞎㞏㞐㞑㞒㞓㞔㞕㞖㞗㞘㞙㞚㞛㞜㞝㞞㞟㞠㞡㞢㞣㞤㞥㞦㞧㞨㞩㞪㞫㞬㞭㞮㞯㞰㞱㞲㞳㞴㞵㞶㞷㞸㞹㞺㞻㞼㞽㞾㞿㟀㟁㟂㟃㟄㟅㟆㟇㟈㟉㟊㟋㟌㟍㟎㟏㟐㟑㟒㟓㟔㟕㟖㟗㟘㟙㟚㟛㟜㟝㟞㟟㟠㟡㟢㟣㟤㟥㟦㟧㟨㟩㟪㟫㟬㟭㟮㟯㟰㟱㟲㟳㟴㟵㟶㟷㟸㟹㟺㟻㟼㟽㟾㟿㠀㠁㠂㠃㠄㠅㠆㠇㠈㠉㠊㠋㠌㠍㠎㠏㠐㠑㠒㠓㠔㠕㠖㠗㠘㠙㠚㠛㠜㠝㠞㠟㠠㠡㠢㠣㠤㠥㠦㠧㠨㠩㠪㠫㠬㠭㠮㠯㠰㠱㠲㠳㠴㠵㠶㠷㠸㠹㠺㠻㠼㠽㠾㠿㡀㡁㡂㡃㡄㡅㡆㡇㡈㡉㡊㡋㡌㡍㡎㡏㡐㡑㡒㡓㡔㡕㡖㡗㡘㡙㡚㡛㡜㡝㡞㡟㡠㡡㡢㡣㡤㡥㡦㡧㡨㡩㡪㡫㡬㡭㡮㡯㡰㡱㡲㡳㡴㡵㡶㡷㡸㡹㡺㡻㡼㡽㡾㡿㢀㢁㢂㢃㢄㢅㢆㢇㢈㢉㢊㢋㢌㢍㢎㢏㢐㢑㢒㢓㢔㢕㢖㢗㢘㢙㢚㢛㢜㢝㢞㢟㢠㢡㢢㢣㢤㢥㢦㢧㢨㢩㢪㢫㢬㢭㢮㢯㢰㢱㢲㢳㢴㢵㢶㢷㢸㢹㢺㢻㢼㢽㢾㢿㣀㣁㣂㣃㣄㣅㣆㣇㣈㣉㣊㣋㣌㣍㣎㣏㣐㣑㣒㣓㣔㣕㣖㣗㣘㣙㣚㣛㣜㣝㣞㣟㣠㣡㣢㣣㣤㣥㣦㣧㣨㣩㣪㣫㣬㣭㣮㣯㣰㣱㣲㣳㣴㣵㣶㣷㣸㣹㣺㣻㣼㣽㣾㣿㤀㤁㤂㤃㤄㤅㤆㤇㤈㤉㤊㤋㤌㤍㤎㤏㤐㤑㤒㤓㤔㤕㤖㤗㤘㤙㤚㤛㤜㤝㤞㤟㤠㤡㤢㤣㤤㤥㤦㤧㤨㤩㤪㤫㤬㤭㤮㤯㤰㤱㤲㤳㤴㤵㤶㤷㤸㤹㤺㤻㤼㤽㤾㤿㥀㥁㥂㥃㥄㥅㥆㥇㥈㥉㥊㥋㥌㥍㥎㥏㥐㥑㥒㥓㥔㥕㥖㥗㥘㥙㥚㥛㥜㥝㥞㥟㥠㥡㥢㥣㥤㥥㥦㥧㥨㥩㥪㥫㥬㥭㥮㥯㥰㥱㥲㥳㥴㥵㥶㥷㥸㥹㥺㥻㥼㥽㥾㥿㦀㦁㦂㦃㦄㦅㦆㦇㦈㦉㦊㦋㦌㦍㦎㦏㦐㦑㦒㦓㦔㦕㦖㦗㦘㦙㦚㦛㦜㦝㦞㦟㦠㦡㦢㦣㦤㦥㦦㦧㦨㦩㦪㦫㦬㦭㦮㦯㦰㦱㦲㦳㦴㦵㦶㦷㦸㦹㦺㦻㦼㦽㦾㦿㧀㧁㧂㧃㧄㧅㧆㧇㧈㧉㧊㧋㧌㧍㧎㧏㧐㧑㧒㧓㧔㧕㧖㧗㧘㧙㧚㧛㧜㧝㧞㧟㧠㧡㧢㧣㧤㧥㧦㧧㧨㧩㧪㧫㧬㧭㧮㧯㧰㧱㧲㧳㧴㧵㧶㧷㧸㧹㧺㧻㧼㧽㧾㧿㨀㨁㨂㨃㨄㨅㨆㨇㨈㨉㨊㨋㨌㨍㨎㨏㨐㨑㨒㨓㨔㨕㨖㨗㨘㨙㨚㨛㨜㨝㨞㨟㨠㨡㨢㨣㨤㨥㨦㨧㨨㨩㨪㨫㨬㨭㨮㨯㨰㨱㨲㨳㨴㨵㨶㨷㨸㨹㨺㨻㨼㨽㨾㨿㩀㩁㩂㩃㩄㩅㩆㩇㩈㩉㩊㩋㩌㩍㩎㩏㩐㩑㩒㩓㩔㩕㩖㩗㩘㩙㩚㩛㩜㩝㩞㩟㩠㩡㩢㩣㩤㩥㩦㩧㩨㩩㩪㩫㩬㩭㩮㩯㩰㩱㩲㩳㩴㩵㩶㩷㩸㩹㩺㩻㩼㩽㩾㩿㪀㪁㪂㪃㪄㪅㪆㪇㪈㪉㪊㪋㪌㪍㪎㪏㪐㪑㪒㪓㪔㪕㪖㪗㪘㪙㪚㪛㪜㪝㪞㪟㪠㪡㪢㪣㪤㪥㪦㪧㪨㪩㪪㪫㪬㪭㪮㪯㪰㪱㪲㪳㪴㪵㪶㪷㪸㪹㪺㪻㪼㪽㪾㪿㫀㫁㫂㫃㫄㫅㫆㫇㫈㫉㫊㫋㫌㫍㫎㫏㫐㫑㫒㫓㫔㫕㫖㫗㫘㫙㫚㫛㫜㫝㫞㫟㫠㫡㫢㫣㫤㫥㫦㫧㫨㫩㫪㫫㫬㫭㫮㫯㫰㫱㫲㫳㫴㫵㫶㫷㫸㫹㫺㫻㫼㫽㫾㫿㬀㬁㬂㬃㬄㬅㬆㬇㬈㬉㬊㬋㬌㬍㬎㬏㬐㬑㬒㬓㬔㬕㬖㬗㬘㬙㬚㬛㬜㬝㬞㬟㬠㬡㬢㬣㬤㬥㬦㬧㬨㬩㬪㬫㬬㬭㬮㬯㬰㬱㬲㬳㬴㬵㬶㬷㬸㬹㬺㬻㬼㬽㬾㬿㭀㭁㭂㭃㭄㭅㭆㭇㭈㭉㭊㭋㭌㭍㭎㭏㭐㭑㭒㭓㭔㭕㭖㭗㭘㭙㭚㭛㭜㭝㭞㭟㭠㭡㭢㭣㭤㭥㭦㭧㭨㭩㭪㭫㭬㭭㭮㭯㭰㭱㭲㭳㭴㭵㭶㭷㭸㭹㭺㭻㭼㭽㭾㭿㮀㮁㮂㮃㮄㮅㮆㮇㮈㮉㮊㮋㮌㮍㮎㮏㮐㮑㮒㮓㮔㮕㮖㮗㮘㮙㮚㮛㮜㮝㮞㮟㮠㮡㮢㮣㮤㮥㮦㮧㮨㮩㮪㮫㮬㮭㮮㮯㮰㮱㮲㮳㮴㮵㮶㮷㮸㮹㮺㮻㮼㮽㮾㮿㯀㯁㯂㯃㯄㯅㯆㯇㯈㯉㯊㯋㯌㯍㯎㯏㯐㯑㯒㯓㯔㯕㯖㯗㯘㯙㯚㯛㯜㯝㯞㯟㯠㯡㯢㯣㯤㯥㯦㯧㯨㯩㯪㯫㯬㯭㯮㯯㯰㯱㯲㯳㯴㯵㯶㯷㯸㯹㯺㯻㯼㯽㯾㯿㰀㰁㰂㰃㰄㰅㰆㰇㰈㰉㰊㰋㰌㰍㰎㰏㰐㰑㰒㰓㰔㰕㰖㰗㰘㰙㰚㰛㰜㰝㰞㰟㰠㰡㰢㰣㰤㰥㰦㰧㰨㰩㰪㰫㰬㰭㰮㰯㰰㰱㰲㰳㰴㰵㰶㰷㰸㰹㰺㰻㰼㰽㰾㰿㱀㱁㱂㱃㱄㱅㱆㱇㱈㱉㱊㱋㱌㱍㱎㱏㱐㱑㱒㱓㱔㱕㱖㱗㱘㱙㱚㱛㱜㱝㱞㱟㱠㱡㱢㱣㱤㱥㱦㱧㱨㱩㱪㱫㱬㱭㱮㱯㱰㱱㱲㱳㱴㱵㱶㱷㱸㱹㱺㱻㱼㱽㱾㱿㲀㲁㲂㲃㲄㲅㲆㲇㲈㲉㲊㲋㲌㲍㲎㲏㲐㲑㲒㲓㲔㲕㲖㲗㲘㲙㲚㲛㲜㲝㲞㲟㲠㲡㲢㲣㲤㲥㲦㲧㲨㲩㲪㲫㲬㲭㲮㲯㲰㲱㲲㲳㲴㲵㲶㲷㲸㲹㲺㲻㲼㲽㲾㲿㳀㳁㳂㳃㳄㳅㳆㳇㳈㳉㳊㳋㳌㳍㳎㳏㳐㳑㳒㳓㳔㳕㳖㳗㳘㳙㳚㳛㳜㳝㳞㳟㳠㳡㳢㳣㳤㳥㳦㳧㳨㳩㳪㳫㳬㳭㳮㳯㳰㳱㳲㳳㳴㳵㳶㳷㳸㳹㳺㳻㳼㳽㳾㳿㴀㴁㴂㴃㴄㴅㴆㴇㴈㴉㴊㴋㴌㴍㴎㴏㴐㴑㴒㴓㴔㴕㴖㴗㴘㴙㴚㴛㴜㴝㴞㴟㴠㴡㴢㴣㴤㴥㴦㴧㴨㴩㴪㴫㴬㴭㴮㴯㴰㴱㴲㴳㴴㴵㴶㴷㴸㴹㴺㴻㴼㴽㴾㴿㵀㵁㵂㵃㵄㵅㵆㵇㵈㵉㵊㵋㵌㵍㵎㵏㵐㵑㵒㵓㵔㵕㵖㵗㵘㵙㵚㵛㵜㵝㵞㵟㵠㵡㵢㵣㵤㵥㵦㵧㵨㵩㵪㵫㵬㵭㵮㵯㵰㵱㵲㵳㵴㵵㵶㵷㵸㵹㵺㵻㵼㵽㵾㵿㶀㶁㶂㶃㶄㶅㶆㶇㶈㶉㶊㶋㶌㶍㶎㶏㶐㶑㶒㶓㶔㶕㶖㶗㶘㶙㶚㶛㶜㶝㶞㶟㶠㶡㶢㶣㶤㶥㶦㶧㶨㶩㶪㶫㶬㶭㶮㶯㶰㶱㶲㶳㶴㶵㶶㶷㶸㶹㶺㶻㶼㶽㶾㶿㷀㷁㷂㷃㷄㷅㷆㷇㷈㷉㷊㷋㷌㷍㷎㷏㷐㷑㷒㷓㷔㷕㷖㷗㷘㷙㷚㷛㷜㷝㷞㷟㷠㷡㷢㷣㷤㷥㷦㷧㷨㷩㷪㷫㷬㷭㷮㷯㷰㷱㷲㷳㷴㷵㷶㷷㷸㷹㷺㷻㷼㷽㷾㷿㸀㸁㸂㸃㸄㸅㸆㸇㸈㸉㸊㸋㸌㸍㸎㸏㸐㸑㸒㸓㸔㸕㸖㸗㸘㸙㸚㸛㸜㸝㸞㸟㸠㸡㸢㸣㸤㸥㸦㸧㸨㸩㸪㸫㸬㸭㸮㸯㸰㸱㸲㸳㸴㸵㸶㸷㸸㸹㸺㸻㸼㸽㸾㸿㹀㹁㹂㹃㹄㹅㹆㹇㹈㹉㹊㹋㹌㹍㹎㹏㹐㹑㹒㹓㹔㹕㹖㹗㹘㹙㹚㹛㹜㹝㹞㹟㹠㹡㹢㹣㹤㹥㹦㹧㹨㹩㹪㹫㹬㹭㹮㹯㹰㹱㹲㹳㹴㹵㹶㹷㹸㹹㹺㹻㹼㹽㹾㹿㺀㺁㺂㺃㺄㺅㺆㺇㺈㺉㺊㺋㺌㺍㺎㺏㺐㺑㺒㺓㺔㺕㺖㺗㺘㺙㺚㺛㺜㺝㺞㺟㺠㺡㺢㺣㺤㺥㺦㺧㺨㺩㺪㺫㺬㺭㺮㺯㺰㺱㺲㺳㺴㺵㺶㺷㺸㺹㺺㺻㺼㺽㺾㺿㻀㻁㻂㻃㻄㻅㻆㻇㻈㻉㻊㻋㻌㻍㻎㻏㻐㻑㻒㻓㻔㻕㻖㻗㻘㻙㻚㻛㻜㻝㻞㻟㻠㻡㻢㻣㻤㻥㻦㻧㻨㻩㻪㻫㻬㻭㻮㻯㻰㻱㻲㻳㻴㻵㻶㻷㻸㻹㻺㻻㻼㻽㻾㻿㼀㼁㼂㼃㼄㼅㼆㼇㼈㼉㼊㼋㼌㼍㼎㼏㼐㼑㼒㼓㼔㼕㼖㼗㼘㼙㼚㼛㼜㼝㼞㼟㼠㼡㼢㼣㼤㼥㼦㼧㼨㼩㼪㼫㼬㼭㼮㼯㼰㼱㼲㼳㼴㼵㼶㼷㼸㼹㼺㼻㼼㼽㼾㼿㽀㽁㽂㽃㽄㽅㽆㽇㽈㽉㽊㽋㽌㽍㽎㽏㽐㽑㽒㽓㽔㽕㽖㽗㽘㽙㽚㽛㽜㽝㽞㽟㽠㽡㽢㽣㽤㽥㽦㽧㽨㽩㽪㽫㽬㽭㽮㽯㽰㽱㽲㽳㽴㽵㽶㽷㽸㽹㽺㽻㽼㽽㽾㽿㾀㾁㾂㾃㾄㾅㾆㾇㾈㾉㾊㾋㾌㾍㾎㾏㾐㾑㾒㾓㾔㾕㾖㾗㾘㾙㾚㾛㾜㾝㾞㾟㾠㾡㾢㾣㾤㾥㾦㾧㾨㾩㾪㾫㾬㾭㾮㾯㾰㾱㾲㾳㾴㾵㾶㾷㾸㾹㾺㾻㾼㾽㾾㾿㿀㿁㿂㿃㿄㿅㿆㿇㿈㿉㿊㿋㿌㿍㿎㿏㿐㿑㿒㿓㿔㿕㿖㿗㿘㿙㿚㿛㿜㿝㿞㿟㿠㿡㿢㿣㿤㿥㿦㿧㿨㿩㿪㿫㿬㿭㿮㿯㿰㿱㿲㿳㿴㿵㿶㿷㿸㿹㿺㿻㿼㿽㿾㿿䀀䀁䀂䀃䀄䀅䀆䀇䀈䀉䀊䀋䀌䀍䀎䀏䀐䀑䀒䀓䀔䀕䀖䀗䀘䀙䀚䀛䀜䀝䀞䀟䀠䀡䀢䀣䀤䀥䀦䀧䀨䀩䀪䀫䀬䀭䀮䀯䀰䀱䀲䀳䀴䀵䀶䀷䀸䀹䀺䀻䀼䀽䀾䀿䁀䁁䁂䁃䁄䁅䁆䁇䁈䁉䁊䁋䁌䁍䁎䁏䁐䁑䁒䁓䁔䁕䁖䁗䁘䁙䁚䁛䁜䁝䁞䁟䁠䁡䁢䁣䁤䁥䁦䁧䁨䁩䁪䁫䁬䁭䁮䁯䁰䁱䁲䁳䁴䁵䁶䁷䁸䁹䁺䁻䁼䁽䁾䁿䂀䂁䂂䂃䂄䂅䂆䂇䂈䂉䂊䂋䂌䂍䂎䂏䂐䂑䂒䂓䂔䂕䂖䂗䂘䂙䂚䂛䂜䂝䂞䂟䂠䂡䂢䂣䂤䂥䂦䂧䂨䂩䂪䂫䂬䂭䂮䂯䂰䂱䂲䂳䂴䂵䂶䂷䂸䂹䂺䂻䂼䂽䂾䂿䃀䃁䃂䃃䃄䃅䃆䃇䃈䃉䃊䃋䃌䃍䃎䃏䃐䃑䃒䃓䃔䃕䃖䃗䃘䃙䃚䃛䃜䃝䃞䃟䃠䃡䃢䃣䃤䃥䃦䃧䃨䃩䃪䃫䃬䃭䃮䃯䃰䃱䃲䃳䃴䃵䃶䃷䃸䃹䃺䃻䃼䃽䃾䃿䄀䄁䄂䄃䄄䄅䄆䄇䄈䄉䄊䄋䄌䄍䄎䄏䄐䄑䄒䄓䄔䄕䄖䄗䄘䄙䄚䄛䄜䄝䄞䄟䄠䄡䄢䄣䄤䄥䄦䄧䄨䄩䄪䄫䄬䄭䄮䄯䄰䄱䄲䄳䄴䄵䄶䄷䄸䄹䄺䄻䄼䄽䄾䄿䅀䅁䅂䅃䅄䅅䅆䅇䅈䅉䅊䅋䅌䅍䅎䅏䅐䅑䅒䅓䅔䅕䅖䅗䅘䅙䅚䅛䅜䅝䅞䅟䅠䅡䅢䅣䅤䅥䅦䅧䅨䅩䅪䅫䅬䅭䅮䅯䅰䅱䅲䅳䅴䅵䅶䅷䅸䅹䅺䅻䅼䅽䅾䅿䆀䆁䆂䆃䆄䆅䆆䆇䆈䆉䆊䆋䆌䆍䆎䆏䆐䆑䆒䆓䆔䆕䆖䆗䆘䆙䆚䆛䆜䆝䆞䆟䆠䆡䆢䆣䆤䆥䆦䆧䆨䆩䆪䆫䆬䆭䆮䆯䆰䆱䆲䆳䆴䆵䆶䆷䆸䆹䆺䆻䆼䆽䆾䆿䇀䇁䇂䇃䇄䇅䇆䇇䇈䇉䇊䇋䇌䇍䇎䇏䇐䇑䇒䇓䇔䇕䇖䇗䇘䇙䇚䇛䇜䇝䇞䇟䇠䇡䇢䇣䇤䇥䇦䇧䇨䇩䇪䇫䇬䇭䇮䇯䇰䇱䇲䇳䇴䇵䇶䇷䇸䇹䇺䇻䇼䇽䇾䇿䈀䈁䈂䈃䈄䈅䈆䈇䈈䈉䈊䈋䈌䈍䈎䈏䈐䈑䈒䈓䈔䈕䈖䈗䈘䈙䈚䈛䈜䈝䈞䈟䈠䈡䈢䈣䈤䈥䈦䈧䈨䈩䈪䈫䈬䈭䈮䈯䈰䈱䈲䈳䈴䈵䈶䈷䈸䈹䈺䈻䈼䈽䈾䈿䉀䉁䉂䉃䉄䉅䉆䉇䉈䉉䉊䉋䉌䉍䉎䉏䉐䉑䉒䉓䉔䉕䉖䉗䉘䉙䉚䉛䉜䉝䉞䉟䉠䉡䉢䉣䉤䉥䉦䉧䉨䉩䉪䉫䉬䉭䉮䉯䉰䉱䉲䉳䉴䉵䉶䉷䉸䉹䉺䉻䉼䉽䉾䉿䊀䊁䊂䊃䊄䊅䊆䊇䊈䊉䊊䊋䊌䊍䊎䊏䊐䊑䊒䊓䊔䊕䊖䊗䊘䊙䊚䊛䊜䊝䊞䊟䊠䊡䊢䊣䊤䊥䊦䊧䊨䊩䊪䊫䊬䊭䊮䊯䊰䊱䊲䊳䊴䊵䊶䊷䊸䊹䊺䊻䊼䊽䊾䊿䋀䋁䋂䋃䋄䋅䋆䋇䋈䋉䋊䋋䋌䋍䋎䋏䋐䋑䋒䋓䋔䋕䋖䋗䋘䋙䋚䋛䋜䋝䋞䋟䋠䋡䋢䋣䋤䋥䋦䋧䋨䋩䋪䋫䋬䋭䋮䋯䋰䋱䋲䋳䋴䋵䋶䋷䋸䋹䋺䋻䋼䋽䋾䋿䌀䌁䌂䌃䌄䌅䌆䌇䌈䌉䌊䌋䌌䌍䌎䌏䌐䌑䌒䌓䌔䌕䌖䌗䌘䌙䌚䌛䌜䌝䌞䌟䌠䌡䌢䌣䌤䌥䌦䌧䌨䌩䌪䌫䌬䌭䌮䌯䌰䌱䌲䌳䌴䌵䌶䌷䌸䌹䌺䌻䌼䌽䌾䌿䍀䍁䍂䍃䍄䍅䍆䍇䍈䍉䍊䍋䍌䍍䍎䍏䍐䍑䍒䍓䍔䍕䍖䍗䍘䍙䍚䍛䍜䍝䍞䍟䍠䍡䍢䍣䍤䍥䍦䍧䍨䍩䍪䍫䍬䍭䍮䍯䍰䍱䍲䍳䍴䍵䍶䍷䍸䍹䍺䍻䍼䍽䍾䍿䎀䎁䎂䎃䎄䎅䎆䎇䎈䎉䎊䎋䎌䎍䎎䎏䎐䎑䎒䎓䎔䎕䎖䎗䎘䎙䎚䎛䎜䎝䎞䎟䎠䎡䎢䎣䎤䎥䎦䎧䎨䎩䎪䎫䎬䎭䎮䎯䎰䎱䎲䎳䎴䎵䎶䎷䎸䎹䎺䎻䎼䎽䎾䎿䏀䏁䏂䏃䏄䏅䏆䏇䏈䏉䏊䏋䏌䏍䏎䏏䏐䏑䏒䏓䏔䏕䏖䏗䏘䏙䏚䏛䏜䏝䏞䏟䏠䏡䏢䏣䏤䏥䏦䏧䏨䏩䏪䏫䏬䏭䏮䏯䏰䏱䏲䏳䏴䏵䏶䏷䏸䏹䏺䏻䏼䏽䏾䏿䐀䐁䐂䐃䐄䐅䐆䐇䐈䐉䐊䐋䐌䐍䐎䐏䐐䐑䐒䐓䐔䐕䐖䐗䐘䐙䐚䐛䐜䐝䐞䐟䐠䐡䐢䐣䐤䐥䐦䐧䐨䐩䐪䐫䐬䐭䐮䐯䐰䐱䐲䐳䐴䐵䐶䐷䐸䐹䐺䐻䐼䐽䐾䐿䑀䑁䑂䑃䑄䑅䑆䑇䑈䑉䑊䑋䑌䑍䑎䑏䑐䑑䑒䑓䑔䑕䑖䑗䑘䑙䑚䑛䑜䑝䑞䑟䑠䑡䑢䑣䑤䑥䑦䑧䑨䑩䑪䑫䑬䑭䑮䑯䑰䑱䑲䑳䑴䑵䑶䑷䑸䑹䑺䑻䑼䑽䑾䑿䒀䒁䒂䒃䒄䒅䒆䒇䒈䒉䒊䒋䒌䒍䒎䒏䒐䒑䒒䒓䒔䒕䒖䒗䒘䒙䒚䒛䒜䒝䒞䒟䒠䒡䒢䒣䒤䒥䒦䒧䒨䒩䒪䒫䒬䒭䒮䒯䒰䒱䒲䒳䒴䒵䒶䒷䒸䒹䒺䒻䒼䒽䒾䒿䓀䓁䓂䓃䓄䓅䓆䓇䓈䓉䓊䓋䓌䓍䓎䓏䓐䓑䓒䓓䓔䓕䓖䓗䓘䓙䓚䓛䓜䓝䓞䓟䓠䓡䓢䓣䓤䓥䓦䓧䓨䓩䓪䓫䓬䓭䓮䓯䓰䓱䓲䓳䓴䓵䓶䓷䓸䓹䓺䓻䓼䓽䓾䓿䔀䔁䔂䔃䔄䔅䔆䔇䔈䔉䔊䔋䔌䔍䔎䔏䔐䔑䔒䔓䔔䔕䔖䔗䔘䔙䔚䔛䔜䔝䔞䔟䔠䔡䔢䔣䔤䔥䔦䔧䔨䔩䔪䔫䔬䔭䔮䔯䔰䔱䔲䔳䔴䔵䔶䔷䔸䔹䔺䔻䔼䔽䔾䔿䕀䕁䕂䕃䕄䕅䕆䕇䕈䕉䕊䕋䕌䕍䕎䕏䕐䕑䕒䕓䕔䕕䕖䕗䕘䕙䕚䕛䕜䕝䕞䕟䕠䕡䕢䕣䕤䕥䕦䕧䕨䕩䕪䕫䕬䕭䕮䕯䕰䕱䕲䕳䕴䕵䕶䕷䕸䕹䕺䕻䕼䕽䕾䕿䖀䖁䖂䖃䖄䖅䖆䖇䖈䖉䖊䖋䖌䖍䖎䖏䖐䖑䖒䖓䖔䖕䖖䖗䖘䖙䖚䖛䖜䖝䖞䖟䖠䖡䖢䖣䖤䖥䖦䖧䖨䖩䖪䖫䖬䖭䖮䖯䖰䖱䖲䖳䖴䖵䖶䖷䖸䖹䖺䖻䖼䖽䖾䖿䗀䗁䗂䗃䗄䗅䗆䗇䗈䗉䗊䗋䗌䗍䗎䗏䗐䗑䗒䗓䗔䗕䗖䗗䗘䗙䗚䗛䗜䗝䗞䗟䗠䗡䗢䗣䗤䗥䗦䗧䗨䗩䗪䗫䗬䗭䗮䗯䗰䗱䗲䗳䗴䗵䗶䗷䗸䗹䗺䗻䗼䗽䗾䗿䘀䘁䘂䘃䘄䘅䘆䘇䘈䘉䘊䘋䘌䘍䘎䘏䘐䘑䘒䘓䘔䘕䘖䘗䘘䘙䘚䘛䘜䘝䘞䘟䘠䘡䘢䘣䘤䘥䘦䘧䘨䘩䘪䘫䘬䘭䘮䘯䘰䘱䘲䘳䘴䘵䘶䘷䘸䘹䘺䘻䘼䘽䘾䘿䙀䙁䙂䙃䙄䙅䙆䙇䙈䙉䙊䙋䙌䙍䙎䙏䙐䙑䙒䙓䙔䙕䙖䙗䙘䙙䙚䙛䙜䙝䙞䙟䙠䙡䙢䙣䙤䙥䙦䙧䙨䙩䙪䙫䙬䙭䙮䙯䙰䙱䙲䙳䙴䙵䙶䙷䙸䙹䙺䙻䙼䙽䙾䙿䚀䚁䚂䚃䚄䚅䚆䚇䚈䚉䚊䚋䚌䚍䚎䚏䚐䚑䚒䚓䚔䚕䚖䚗䚘䚙䚚䚛䚜䚝䚞䚟䚠䚡䚢䚣䚤䚥䚦䚧䚨䚩䚪䚫䚬䚭䚮䚯䚰䚱䚲䚳䚴䚵䚶䚷䚸䚹䚺䚻䚼䚽䚾䚿䛀䛁䛂䛃䛄䛅䛆䛇䛈䛉䛊䛋䛌䛍䛎䛏䛐䛑䛒䛓䛔䛕䛖䛗䛘䛙䛚䛛䛜䛝䛞䛟䛠䛡䛢䛣䛤䛥䛦䛧䛨䛩䛪䛫䛬䛭䛮䛯䛰䛱䛲䛳䛴䛵䛶䛷䛸䛹䛺䛻䛼䛽䛾䛿䜀䜁䜂䜃䜄䜅䜆䜇䜈䜉䜊䜋䜌䜍䜎䜏䜐䜑䜒䜓䜔䜕䜖䜗䜘䜙䜚䜛䜜䜝䜞䜟䜠䜡䜢䜣䜤䜥䜦䜧䜨䜩䜪䜫䜬䜭䜮䜯䜰䜱䜲䜳䜴䜵䜶䜷䜸䜹䜺䜻䜼䜽䜾䜿䝀䝁䝂䝃䝄䝅䝆䝇䝈䝉䝊䝋䝌䝍䝎䝏䝐䝑䝒䝓䝔䝕䝖䝗䝘䝙䝚䝛䝜䝝䝞䝟䝠䝡䝢䝣䝤䝥䝦䝧䝨䝩䝪䝫䝬䝭䝮䝯䝰䝱䝲䝳䝴䝵䝶䝷䝸䝹䝺䝻䝼䝽䝾䝿䞀䞁䞂䞃䞄䞅䞆䞇䞈䞉䞊䞋䞌䞍䞎䞏䞐䞑䞒䞓䞔䞕䞖䞗䞘䞙䞚䞛䞜䞝䞞䞟䞠䞡䞢䞣䞤䞥䞦䞧䞨䞩䞪䞫䞬䞭䞮䞯䞰䞱䞲䞳䞴䞵䞶䞷䞸䞹䞺䞻䞼䞽䞾䞿䟀䟁䟂䟃䟄䟅䟆䟇䟈䟉䟊䟋䟌䟍䟎䟏䟐䟑䟒䟓䟔䟕䟖䟗䟘䟙䟚䟛䟜䟝䟞䟟䟠䟡䟢䟣䟤䟥䟦䟧䟨䟩䟪䟫䟬䟭䟮䟯䟰䟱䟲䟳䟴䟵䟶䟷䟸䟹䟺䟻䟼䟽䟾䟿䠀䠁䠂䠃䠄䠅䠆䠇䠈䠉䠊䠋䠌䠍䠎䠏䠐䠑䠒䠓䠔䠕䠖䠗䠘䠙䠚䠛䠜䠝䠞䠟䠠䠡䠢䠣䠤䠥䠦䠧䠨䠩䠪䠫䠬䠭䠮䠯䠰䠱䠲䠳䠴䠵䠶䠷䠸䠹䠺䠻䠼䠽䠾䠿䡀䡁䡂䡃䡄䡅䡆䡇䡈䡉䡊䡋䡌䡍䡎䡏䡐䡑䡒䡓䡔䡕䡖䡗䡘䡙䡚䡛䡜䡝䡞䡟䡠䡡䡢䡣䡤䡥䡦䡧䡨䡩䡪䡫䡬䡭䡮䡯䡰䡱䡲䡳䡴䡵䡶䡷䡸䡹䡺䡻䡼䡽䡾䡿䢀䢁䢂䢃䢄䢅䢆䢇䢈䢉䢊䢋䢌䢍䢎䢏䢐䢑䢒䢓䢔䢕䢖䢗䢘䢙䢚䢛䢜䢝䢞䢟䢠䢡䢢䢣䢤䢥䢦䢧䢨䢩䢪䢫䢬䢭䢮䢯䢰䢱䢲䢳䢴䢵䢶䢷䢸䢹䢺䢻䢼䢽䢾䢿䣀䣁䣂䣃䣄䣅䣆䣇䣈䣉䣊䣋䣌䣍䣎䣏䣐䣑䣒䣓䣔䣕䣖䣗䣘䣙䣚䣛䣜䣝䣞䣟䣠䣡䣢䣣䣤䣥䣦䣧䣨䣩䣪䣫䣬䣭䣮䣯䣰䣱䣲䣳䣴䣵䣶䣷䣸䣹䣺䣻䣼䣽䣾䣿䤀䤁䤂䤃䤄䤅䤆䤇䤈䤉䤊䤋䤌䤍䤎䤏䤐䤑䤒䤓䤔䤕䤖䤗䤘䤙䤚䤛䤜䤝䤞䤟䤠䤡䤢䤣䤤䤥䤦䤧䤨䤩䤪䤫䤬䤭䤮䤯䤰䤱䤲䤳䤴䤵䤶䤷䤸䤹䤺䤻䤼䤽䤾䤿䥀䥁䥂䥃䥄䥅䥆䥇䥈䥉䥊䥋䥌䥍䥎䥏䥐䥑䥒䥓䥔䥕䥖䥗䥘䥙䥚䥛䥜䥝䥞䥟䥠䥡䥢䥣䥤䥥䥦䥧䥨䥩䥪䥫䥬䥭䥮䥯䥰䥱䥲䥳䥴䥵䥶䥷䥸䥹䥺䥻䥼䥽䥾䥿䦀䦁䦂䦃䦄䦅䦆䦇䦈䦉䦊䦋䦌䦍䦎䦏䦐䦑䦒䦓䦔䦕䦖䦗䦘䦙䦚䦛䦜䦝䦞䦟䦠䦡䦢䦣䦤䦥䦦䦧䦨䦩䦪䦫䦬䦭䦮䦯䦰䦱䦲䦳䦴䦵䦶䦷䦸䦹䦺䦻䦼䦽䦾䦿䧀䧁䧂䧃䧄䧅䧆䧇䧈䧉䧊䧋䧌䧍䧎䧏䧐䧑䧒䧓䧔䧕䧖䧗䧘䧙䧚䧛䧜䧝䧞䧟䧠䧡䧢䧣䧤䧥䧦䧧䧨䧩䧪䧫䧬䧭䧮䧯䧰䧱䧲䧳䧴䧵䧶䧷䧸䧹䧺䧻䧼䧽䧾䧿䨀䨁䨂䨃䨄䨅䨆䨇䨈䨉䨊䨋䨌䨍䨎䨏䨐䨑䨒䨓䨔䨕䨖䨗䨘䨙䨚䨛䨜䨝䨞䨟䨠䨡䨢䨣䨤䨥䨦䨧䨨䨩䨪䨫䨬䨭䨮䨯䨰䨱䨲䨳䨴䨵䨶䨷䨸䨹䨺䨻䨼䨽䨾䨿䩀䩁䩂䩃䩄䩅䩆䩇䩈䩉䩊䩋䩌䩍䩎䩏䩐䩑䩒䩓䩔䩕䩖䩗䩘䩙䩚䩛䩜䩝䩞䩟䩠䩡䩢䩣䩤䩥䩦䩧䩨䩩䩪䩫䩬䩭䩮䩯䩰䩱䩲䩳䩴䩵䩶䩷䩸䩹䩺䩻䩼䩽䩾䩿䪀䪁䪂䪃䪄䪅䪆䪇䪈䪉䪊䪋䪌䪍䪎䪏䪐䪑䪒䪓䪔䪕䪖䪗䪘䪙䪚䪛䪜䪝䪞䪟䪠䪡䪢䪣䪤䪥䪦䪧䪨䪩䪪䪫䪬䪭䪮䪯䪰䪱䪲䪳䪴䪵䪶䪷䪸䪹䪺䪻䪼䪽䪾䪿䫀䫁䫂䫃䫄䫅䫆䫇䫈䫉䫊䫋䫌䫍䫎䫏䫐䫑䫒䫓䫔䫕䫖䫗䫘䫙䫚䫛䫜䫝䫞䫟䫠䫡䫢䫣䫤䫥䫦䫧䫨䫩䫪䫫䫬䫭䫮䫯䫰䫱䫲䫳䫴䫵䫶䫷䫸䫹䫺䫻䫼䫽䫾䫿䬀䬁䬂䬃䬄䬅䬆䬇䬈䬉䬊䬋䬌䬍䬎䬏䬐䬑䬒䬓䬔䬕䬖䬗䬘䬙䬚䬛䬜䬝䬞䬟䬠䬡䬢䬣䬤䬥䬦䬧䬨䬩䬪䬫䬬䬭䬮䬯䬰䬱䬲䬳䬴䬵䬶䬷䬸䬹䬺䬻䬼䬽䬾䬿䭀䭁䭂䭃䭄䭅䭆䭇䭈䭉䭊䭋䭌䭍䭎䭏䭐䭑䭒䭓䭔䭕䭖䭗䭘䭙䭚䭛䭜䭝䭞䭟䭠䭡䭢䭣䭤䭥䭦䭧䭨䭩䭪䭫䭬䭭䭮䭯䭰䭱䭲䭳䭴䭵䭶䭷䭸䭹䭺䭻䭼䭽䭾䭿䮀䮁䮂䮃䮄䮅䮆䮇䮈䮉䮊䮋䮌䮍䮎䮏䮐䮑䮒䮓䮔䮕䮖䮗䮘䮙䮚䮛䮜䮝䮞䮟䮠䮡䮢䮣䮤䮥䮦䮧䮨䮩䮪䮫䮬䮭䮮䮯䮰䮱䮲䮳䮴䮵䮶䮷䮸䮹䮺䮻䮼䮽䮾䮿䯀䯁䯂䯃䯄䯅䯆䯇䯈䯉䯊䯋䯌䯍䯎䯏䯐䯑䯒䯓䯔䯕䯖䯗䯘䯙䯚䯛䯜䯝䯞䯟䯠䯡䯢䯣䯤䯥䯦䯧䯨䯩䯪䯫䯬䯭䯮䯯䯰䯱䯲䯳䯴䯵䯶䯷䯸䯹䯺䯻䯼䯽䯾䯿䰀䰁䰂䰃䰄䰅䰆䰇䰈䰉䰊䰋䰌䰍䰎䰏䰐䰑䰒䰓䰔䰕䰖䰗䰘䰙䰚䰛䰜䰝䰞䰟䰠䰡䰢䰣䰤䰥䰦䰧䰨䰩䰪䰫䰬䰭䰮䰯䰰䰱䰲䰳䰴䰵䰶䰷䰸䰹䰺䰻䰼䰽䰾䰿䱀䱁䱂䱃䱄䱅䱆䱇䱈䱉䱊䱋䱌䱍䱎䱏䱐䱑䱒䱓䱔䱕䱖䱗䱘䱙䱚䱛䱜䱝䱞䱟䱠䱡䱢䱣䱤䱥䱦䱧䱨䱩䱪䱫䱬䱭䱮䱯䱰䱱䱲䱳䱴䱵䱶䱷䱸䱹䱺䱻䱼䱽䱾䱿䲀䲁䲂䲃䲄䲅䲆䲇䲈䲉䲊䲋䲌䲍䲎䲏䲐䲑䲒䲓䲔䲕䲖䲗䲘䲙䲚䲛䲜䲝䲞䲟䲠䲡䲢䲣䲤䲥䲦䲧䲨䲩䲪䲫䲬䲭䲮䲯䲰䲱䲲䲳䲴䲵䲶䲷䲸䲹䲺䲻䲼䲽䲾䲿䳀䳁䳂䳃䳄䳅䳆䳇䳈䳉䳊䳋䳌䳍䳎䳏䳐䳑䳒䳓䳔䳕䳖䳗䳘䳙䳚䳛䳜䳝䳞䳟䳠䳡䳢䳣䳤䳥䳦䳧䳨䳩䳪䳫䳬䳭䳮䳯䳰䳱䳲䳳䳴䳵䳶䳷䳸䳹䳺䳻䳼䳽䳾䳿䴀䴁䴂䴃䴄䴅䴆䴇䴈䴉䴊䴋䴌䴍䴎䴏䴐䴑䴒䴓䴔䴕䴖䴗䴘䴙䴚䴛䴜䴝䴞䴟䴠䴡䴢䴣䴤䴥䴦䴧䴨䴩䴪䴫䴬䴭䴮䴯䴰䴱䴲䴳䴴䴵䴶䴷䴸䴹䴺䴻䴼䴽䴾䴿䵀䵁䵂䵃䵄䵅䵆䵇䵈䵉䵊䵋䵌䵍䵎䵏䵐䵑䵒䵓䵔䵕䵖䵗䵘䵙䵚䵛䵜䵝䵞䵟䵠䵡䵢䵣䵤䵥䵦䵧䵨䵩䵪䵫䵬䵭䵮䵯䵰䵱䵲䵳䵴䵵䵶䵷䵸䵹䵺䵻䵼䵽䵾䵿䶀䶁䶂䶃䶄䶅䶆䶇䶈䶉䶊䶋䶌䶍䶎䶏䶐䶑䶒䶓䶔䶕䶖䶗䶘䶙䶚䶛䶜䶝䶞䶟䶠䶡䶢䶣䶤䶥䶦䶧䶨䶩䶪䶫䶬䶭䶮䶯䶰䶱䶲䶳䶴䶵䷀䷁䷂䷃䷄䷅䷆䷇䷈䷉䷊䷋䷌䷍䷎䷏䷐䷑䷒䷓䷔䷕䷖䷗䷘䷙䷚䷛䷜䷝䷞䷟䷠䷡䷢䷣䷤䷥䷦䷧䷨䷩䷪䷫䷬䷭䷮䷯䷰䷱䷲䷳䷴䷵䷶䷷䷸䷹䷺䷻䷼䷽䷾䷿一丁丂七丄丅丆万丈三上下丌不与丏丐丑丒专且丕世丗丘丙业丛东丝丞丟丠両丢丣两严並丧丨丩个丫丬中丮丯丰丱串丳临丵丶丷丸丹为主丼丽举丿乀乁乂乃乄久乆乇么义乊之乌乍乎乏乐乑乒乓乔乕乖乗乘乙乚乛乜九乞也习乡乢乣乤乥书乧乨乩乪乫乬乭乮乯买乱乲乳乴乵乶乷乸乹乺乻乼乽乾乿亀亁亂亃亄亅了亇予争亊事二亍于亏亐云互亓五井亖亗亘亙亚些亜亝亞亟亠亡亢亣交亥亦产亨亩亪享京亭亮亯亰亱亲亳亴亵亶亷亸亹人亻亼亽亾亿什仁仂仃仄仅仆仇仈仉今介仌仍从仏仐仑仒仓仔仕他仗付仙仚仛仜仝仞仟仠仡仢代令以仦仧仨仩仪仫们仭仮仯仰仱仲仳仴仵件价仸仹仺任仼份仾仿伀企伂伃伄伅伆伇伈伉伊伋伌伍伎伏伐休伒伓伔伕伖众优伙会伛伜伝伞伟传伡伢伣伤伥伦伧伨伩伪伫伬伭伮伯估伱伲伳伴伵伶伷伸伹伺伻似伽伾伿佀佁佂佃佄佅但佇佈佉佊佋佌位低住佐佑佒体佔何佖佗佘余佚佛作佝佞佟你佡佢佣佤佥佦佧佨佩佪佫佬佭佮佯佰佱佲佳佴併佶佷佸佹佺佻佼佽佾使侀侁侂侃侄侅來侇侈侉侊例侌侍侎侏侐侑侒侓侔侕侖侗侘侙侚供侜依侞侟侠価侢侣侤侥侦侧侨侩侪侫侬侭侮侯侰侱侲侳侴侵侶侷侸侹侺侻侼侽侾便俀俁係促俄俅俆俇俈俉俊俋俌俍俎俏俐俑俒俓俔俕俖俗俘俙俚俛俜保俞俟俠信俢俣俤俥俦俧俨俩俪俫俬俭修俯俰俱俲俳俴俵俶俷俸俹俺俻俼俽俾俿倀倁倂倃倄倅倆倇倈倉倊個倌倍倎倏倐們倒倓倔倕倖倗倘候倚倛倜倝倞借倠倡倢倣値倥倦倧倨倩倪倫倬倭倮倯倰倱倲倳倴倵倶倷倸倹债倻值倽倾倿偀偁偂偃偄偅偆假偈偉偊偋偌偍偎偏偐偑偒偓偔偕偖偗偘偙做偛停偝偞偟偠偡偢偣偤健偦偧偨偩偪偫偬偭偮偯偰偱偲偳側偵偶偷偸偹偺偻偼偽偾偿傀傁傂傃傄傅傆傇傈傉傊傋傌傍傎傏傐傑傒傓傔傕傖傗傘備傚傛傜傝傞傟傠傡傢傣傤傥傦傧储傩傪傫催傭傮傯傰傱傲傳傴債傶傷傸傹傺傻傼傽傾傿僀僁僂僃僄僅僆僇僈僉僊僋僌働僎像僐僑僒僓僔僕僖僗僘僙僚僛僜僝僞僟僠僡僢僣僤僥僦僧僨僩僪僫僬僭僮僯僰僱僲僳僴僵僶僷僸價僺僻僼僽僾僿儀儁儂儃億儅儆儇儈儉儊儋儌儍儎儏儐儑儒儓儔儕儖儗儘儙儚儛儜儝儞償儠儡儢儣儤儥儦儧儨儩優儫儬儭儮儯儰儱儲儳儴儵儶儷儸儹儺儻儼儽儾儿兀允兂元兄充兆兇先光兊克兌免兎兏児兑兒兓兔兕兖兗兘兙党兛兜兝兞兟兠兡兢兣兤入兦內全兩兪八公六兮兯兰共兲关兴兵其具典兹兺养兼兽兾兿冀冁冂冃冄内円冇冈冉冊冋册再冎冏冐冑冒冓冔冕冖冗冘写冚军农冝冞冟冠冡冢冣冤冥冦冧冨冩冪冫冬冭冮冯冰冱冲决冴况冶冷冸冹冺冻冼冽冾冿净凁凂凃凄凅准凇凈凉凊凋凌凍凎减凐凑凒凓凔凕凖凗凘凙凚凛凜凝凞凟几凡凢凣凤凥処凧凨凩凪凫凬凭凮凯凰凱凲凳凴凵凶凷凸凹出击凼函凾凿刀刁刂刃刄刅分切刈刉刊刋刌刍刎刏刐刑划刓刔刕刖列刘则刚创刜初刞刟删刡刢刣判別刦刧刨利刪别刬刭刮刯到刱刲刳刴刵制刷券刹刺刻刼刽刾刿剀剁剂剃剄剅剆則剈剉削剋剌前剎剏剐剑剒剓剔剕剖剗剘剙剚剛剜剝剞剟剠剡剢剣剤剥剦剧剨剩剪剫剬剭剮副剰剱割剳剴創剶剷剸剹剺剻剼剽剾剿劀劁劂劃劄劅劆劇劈劉劊劋劌劍劎劏劐劑劒劓劔劕劖劗劘劙劚力劜劝办功加务劢劣劤劥劦劧动助努劫劬劭劮劯劰励劲劳労劵劶劷劸効劺劻劼劽劾势勀勁勂勃勄勅勆勇勈勉勊勋勌勍勎勏勐勑勒勓勔動勖勗勘務勚勛勜勝勞募勠勡勢勣勤勥勦勧勨勩勪勫勬勭勮勯勰勱勲勳勴勵勶勷勸勹勺勻勼勽勾勿匀匁匂匃匄包匆匇匈匉匊匋匌匍匎匏匐匑匒匓匔匕化北匘匙匚匛匜匝匞匟匠匡匢匣匤匥匦匧匨匩匪匫匬匭匮匯匰匱匲匳匴匵匶匷匸匹区医匼匽匾匿區十卂千卄卅卆升午卉半卋卌卍华协卐卑卒卓協单卖南単卙博卛卜卝卞卟占卡卢卣卤卥卦卧卨卩卪卫卬卭卮卯印危卲即却卵卶卷卸卹卺卻卼卽卾卿厀厁厂厃厄厅历厇厈厉厊压厌厍厎厏厐厑厒厓厔厕厖厗厘厙厚厛厜厝厞原厠厡厢厣厤厥厦厧厨厩厪厫厬厭厮厯厰厱厲厳厴厵厶厷厸厹厺去厼厽厾县叀叁参參叄叅叆叇又叉及友双反収叏叐发叒叓叔叕取受变叙叚叛叜叝叞叟叠叡叢口古句另叧叨叩只叫召叭叮可台叱史右叴叵叶号司叹叺叻叼叽叾叿吀吁吂吃各吅吆吇合吉吊吋同名后吏吐向吒吓吔吕吖吗吘吙吚君吜吝吞吟吠吡吢吣吤吥否吧吨吩吪含听吭吮启吰吱吲吳吴吵吶吷吸吹吺吻吼吽吾吿呀呁呂呃呄呅呆呇呈呉告呋呌呍呎呏呐呑呒呓呔呕呖呗员呙呚呛呜呝呞呟呠呡呢呣呤呥呦呧周呩呪呫呬呭呮呯呰呱呲味呴呵呶呷呸呹呺呻呼命呾呿咀咁咂咃咄咅咆咇咈咉咊咋和咍咎咏咐咑咒咓咔咕咖咗咘咙咚咛咜咝咞咟咠咡咢咣咤咥咦咧咨咩咪咫咬咭咮咯咰咱咲咳咴咵咶咷咸咹咺咻咼咽咾咿哀品哂哃哄哅哆哇哈哉哊哋哌响哎哏哐哑哒哓哔哕哖哗哘哙哚哛哜哝哞哟哠員哢哣哤哥哦哧哨哩哪哫哬哭哮哯哰哱哲哳哴哵哶哷哸哹哺哻哼哽哾哿唀唁唂唃唄唅唆唇唈唉唊唋唌唍唎唏唐唑唒唓唔唕唖唗唘唙唚唛唜唝唞唟唠唡唢唣唤唥唦唧唨唩唪唫唬唭售唯唰唱唲唳唴唵唶唷唸唹唺唻唼唽唾唿啀啁啂啃啄啅商啇啈啉啊啋啌啍啎問啐啑啒啓啔啕啖啗啘啙啚啛啜啝啞啟啠啡啢啣啤啥啦啧啨啩啪啫啬啭啮啯啰啱啲啳啴啵啶啷啸啹啺啻啼啽啾啿喀喁喂喃善喅喆喇喈喉喊喋喌喍喎喏喐喑喒喓喔喕喖喗喘喙喚喛喜喝喞喟喠喡喢喣喤喥喦喧喨喩喪喫喬喭單喯喰喱喲喳喴喵営喷喸喹喺喻喼喽喾喿嗀嗁嗂嗃嗄嗅嗆嗇嗈嗉嗊嗋嗌嗍嗎嗏嗐嗑嗒嗓嗔嗕嗖嗗嗘嗙嗚嗛嗜嗝嗞嗟嗠嗡嗢嗣嗤嗥嗦嗧嗨嗩嗪嗫嗬嗭嗮嗯嗰嗱嗲嗳嗴嗵嗶嗷嗸嗹嗺嗻嗼嗽嗾嗿嘀嘁嘂嘃嘄嘅嘆嘇嘈嘉嘊嘋嘌嘍嘎嘏嘐嘑嘒嘓嘔嘕嘖嘗嘘嘙嘚嘛嘜嘝嘞嘟嘠嘡嘢嘣嘤嘥嘦嘧嘨嘩嘪嘫嘬嘭嘮嘯嘰嘱嘲嘳嘴嘵嘶嘷嘸嘹嘺嘻嘼嘽嘾嘿噀噁噂噃噄噅噆噇噈噉噊噋噌噍噎噏噐噑噒噓噔噕噖噗噘噙噚噛噜噝噞噟噠噡噢噣噤噥噦噧器噩噪噫噬噭噮噯噰噱噲噳噴噵噶噷噸噹噺噻噼噽噾噿嚀嚁嚂嚃嚄嚅嚆嚇嚈嚉嚊嚋嚌嚍嚎嚏嚐嚑嚒嚓嚔嚕嚖嚗嚘嚙嚚嚛嚜嚝嚞嚟嚠嚡嚢嚣嚤嚥嚦嚧嚨嚩嚪嚫嚬嚭嚮嚯嚰嚱嚲嚳嚴嚵嚶嚷嚸嚹嚺嚻嚼嚽嚾嚿囀囁囂囃囄囅囆囇囈囉囊囋囌囍囎囏囐囑囒囓囔囕囖囗囘囙囚四囜囝回囟因囡团団囤囥囦囧囨囩囪囫囬园囮囯困囱囲図围囵囶囷囸囹固囻囼国图囿圀圁圂圃圄圅圆圇圈圉圊國圌圍圎圏圐圑園圓圔圕圖圗團圙圚圛圜圝圞土圠圡圢圣圤圥圦圧在圩圪圫圬圭圮圯地圱圲圳圴圵圶圷圸圹场圻圼圽圾圿址坁坂坃坄坅坆均坈坉坊坋坌坍坎坏坐坑坒坓坔坕坖块坘坙坚坛坜坝坞坟坠坡坢坣坤坥坦坧坨坩坪坫坬坭坮坯坰坱坲坳坴坵坶坷坸坹坺坻坼坽坾坿垀垁垂垃垄垅垆垇垈垉垊型垌垍垎垏垐垑垒垓垔垕垖垗垘垙垚垛垜垝垞垟垠垡垢垣垤垥垦垧垨垩垪垫垬垭垮垯垰垱垲垳垴垵垶垷垸垹垺垻垼垽垾垿埀埁埂埃埄埅埆埇埈埉埊埋埌埍城埏埐埑埒埓埔埕埖埗埘埙埚埛埜埝埞域埠埡埢埣埤埥埦埧埨埩埪埫埬埭埮埯埰埱埲埳埴埵埶執埸培基埻埼埽埾埿堀堁堂堃堄堅堆堇堈堉堊堋堌堍堎堏堐堑堒堓堔堕堖堗堘堙堚堛堜堝堞堟堠堡堢堣堤堥堦堧堨堩堪堫堬堭堮堯堰報堲堳場堵堶堷堸堹堺堻堼堽堾堿塀塁塂塃塄塅塆塇塈塉塊塋塌塍塎塏塐塑塒塓塔塕塖塗塘塙塚塛塜塝塞塟塠塡塢塣塤塥塦塧塨塩塪填塬塭塮塯塰塱塲塳塴塵塶塷塸塹塺塻塼塽塾塿墀墁墂境墄墅墆墇墈墉墊墋墌墍墎墏墐墑墒墓墔墕墖増墘墙墚墛墜墝增墟墠墡墢墣墤墥墦墧墨墩墪墫墬墭墮墯墰墱墲墳墴墵墶墷墸墹墺墻墼墽墾墿壀壁壂壃壄壅壆壇壈壉壊壋壌壍壎壏壐壑壒壓壔壕壖壗壘壙壚壛壜壝壞壟壠壡壢壣壤壥壦壧壨壩壪士壬壭壮壯声壱売壳壴壵壶壷壸壹壺壻壼壽壾壿夀夁夂夃处夅夆备夈変夊夋夌复夎夏夐夑夒夓夔夕外夗夘夙多夛夜夝夞够夠夡夢夣夤夥夦大夨天太夫夬夭央夯夰失夲夳头夵夶夷夸夹夺夻夼夽夾夿奀奁奂奃奄奅奆奇奈奉奊奋奌奍奎奏奐契奒奓奔奕奖套奘奙奚奛奜奝奞奟奠奡奢奣奤奥奦奧奨奩奪奫奬奭奮奯奰奱奲女奴奵奶奷奸她奺奻奼好奾奿妀妁如妃妄妅妆妇妈妉妊妋妌妍妎妏妐妑妒妓妔妕妖妗妘妙妚妛妜妝妞妟妠妡妢妣妤妥妦妧妨妩妪妫妬妭妮妯妰妱妲妳妴妵妶妷妸妹妺妻妼妽妾妿姀姁姂姃姄姅姆姇姈姉姊始姌姍姎姏姐姑姒姓委姕姖姗姘姙姚姛姜姝姞姟姠姡姢姣姤姥姦姧姨姩姪姫姬姭姮姯姰姱姲姳姴姵姶姷姸姹姺姻姼姽姾姿娀威娂娃娄娅娆娇娈娉娊娋娌娍娎娏娐娑娒娓娔娕娖娗娘娙娚娛娜娝娞娟娠娡娢娣娤娥娦娧娨娩娪娫娬娭娮娯娰娱娲娳娴娵娶娷娸娹娺娻娼娽娾娿婀婁婂婃婄婅婆婇婈婉婊婋婌婍婎婏婐婑婒婓婔婕婖婗婘婙婚婛婜婝婞婟婠婡婢婣婤婥婦婧婨婩婪婫婬婭婮婯婰婱婲婳婴婵婶婷婸婹婺婻婼婽婾婿媀媁媂媃媄媅媆媇媈媉媊媋媌媍媎媏媐媑媒媓媔媕媖媗媘媙媚媛媜媝媞媟媠媡媢媣媤媥媦媧媨媩媪媫媬媭媮媯媰媱媲媳媴媵媶媷媸媹媺媻媼媽媾媿嫀嫁嫂嫃嫄嫅嫆嫇嫈嫉嫊嫋嫌嫍嫎嫏嫐嫑嫒嫓嫔嫕嫖嫗嫘嫙嫚嫛嫜嫝嫞嫟嫠嫡嫢嫣嫤嫥嫦嫧嫨嫩嫪嫫嫬嫭嫮嫯嫰嫱嫲嫳嫴嫵嫶嫷嫸嫹嫺嫻嫼嫽嫾嫿嬀嬁嬂嬃嬄嬅嬆嬇嬈嬉嬊嬋嬌嬍嬎嬏嬐嬑嬒嬓嬔嬕嬖嬗嬘嬙嬚嬛嬜嬝嬞嬟嬠嬡嬢嬣嬤嬥嬦嬧嬨嬩嬪嬫嬬嬭嬮嬯嬰嬱嬲嬳嬴嬵嬶嬷嬸嬹嬺嬻嬼嬽嬾嬿孀孁孂孃孄孅孆孇孈孉孊孋孌孍孎孏子孑孒孓孔孕孖字存孙孚孛孜孝孞孟孠孡孢季孤孥学孧孨孩孪孫孬孭孮孯孰孱孲孳孴孵孶孷學孹孺孻孼孽孾孿宀宁宂它宄宅宆宇守安宊宋完宍宎宏宐宑宒宓宔宕宖宗官宙定宛宜宝实実宠审客宣室宥宦宧宨宩宪宫宬宭宮宯宰宱宲害宴宵家宷宸容宺宻宼宽宾宿寀寁寂寃寄寅密寇寈寉寊寋富寍寎寏寐寑寒寓寔寕寖寗寘寙寚寛寜寝寞察寠寡寢寣寤寥實寧寨審寪寫寬寭寮寯寰寱寲寳寴寵寶寷寸对寺寻导寽対寿尀封専尃射尅将將專尉尊尋尌對導小尐少尒尓尔尕尖尗尘尙尚尛尜尝尞尟尠尡尢尣尤尥尦尧尨尩尪尫尬尭尮尯尰就尲尳尴尵尶尷尸尹尺尻尼尽尾尿局屁层屃屄居屆屇屈屉届屋屌屍屎屏屐屑屒屓屔展屖屗屘屙屚屛屜屝属屟屠屡屢屣層履屦屧屨屩屪屫屬屭屮屯屰山屲屳屴屵屶屷屸屹屺屻屼屽屾屿岀岁岂岃岄岅岆岇岈岉岊岋岌岍岎岏岐岑岒岓岔岕岖岗岘岙岚岛岜岝岞岟岠岡岢岣岤岥岦岧岨岩岪岫岬岭岮岯岰岱岲岳岴岵岶岷岸岹岺岻岼岽岾岿峀峁峂峃峄峅峆峇峈峉峊峋峌峍峎峏峐峑峒峓峔峕峖峗峘峙峚峛峜峝峞峟峠峡峢峣峤峥峦峧峨峩峪峫峬峭峮峯峰峱峲峳峴峵島峷峸峹峺峻峼峽峾峿崀崁崂崃崄崅崆崇崈崉崊崋崌崍崎崏崐崑崒崓崔崕崖崗崘崙崚崛崜崝崞崟崠崡崢崣崤崥崦崧崨崩崪崫崬崭崮崯崰崱崲崳崴崵崶崷崸崹崺崻崼崽崾崿嵀嵁嵂嵃嵄嵅嵆嵇嵈嵉嵊嵋嵌嵍嵎嵏嵐嵑嵒嵓嵔嵕嵖嵗嵘嵙嵚嵛嵜嵝嵞嵟嵠嵡嵢嵣嵤嵥嵦嵧嵨嵩嵪嵫嵬嵭嵮嵯嵰嵱嵲嵳嵴嵵嵶嵷嵸嵹嵺嵻嵼嵽嵾嵿嶀嶁嶂嶃嶄嶅嶆嶇嶈嶉嶊嶋嶌嶍嶎嶏嶐嶑嶒嶓嶔嶕嶖嶗嶘嶙嶚嶛嶜嶝嶞嶟嶠嶡嶢嶣嶤嶥嶦嶧嶨嶩嶪嶫嶬嶭嶮嶯嶰嶱嶲嶳嶴嶵嶶嶷嶸嶹嶺嶻嶼嶽嶾嶿巀巁巂巃巄巅巆巇巈巉巊巋巌巍巎巏巐巑巒巓巔巕巖巗巘巙巚巛巜川州巟巠巡巢巣巤工左巧巨巩巪巫巬巭差巯巰己已巳巴巵巶巷巸巹巺巻巼巽巾巿帀币市布帄帅帆帇师帉帊帋希帍帎帏帐帑帒帓帔帕帖帗帘帙帚帛帜帝帞帟帠帡帢帣帤帥带帧帨帩帪師帬席帮帯帰帱帲帳帴帵帶帷常帹帺帻帼帽帾帿幀幁幂幃幄幅幆幇幈幉幊幋幌幍幎幏幐幑幒幓幔幕幖幗幘幙幚幛幜幝幞幟幠幡幢幣幤幥幦幧幨幩幪幫幬幭幮幯幰幱干平年幵并幷幸幹幺幻幼幽幾广庀庁庂広庄庅庆庇庈庉床庋庌庍庎序庐庑庒库应底庖店庘庙庚庛府庝庞废庠庡庢庣庤庥度座庨庩庪庫庬庭庮庯庰庱庲庳庴庵庶康庸庹庺庻庼庽庾庿廀廁廂廃廄廅廆廇廈廉廊廋廌廍廎廏廐廑廒廓廔廕廖廗廘廙廚廛廜廝廞廟廠廡廢廣廤廥廦廧廨廩廪廫廬廭廮廯廰廱廲廳廴廵延廷廸廹建廻廼廽廾廿开弁异弃弄弅弆弇弈弉弊弋弌弍弎式弐弑弒弓弔引弖弗弘弙弚弛弜弝弞弟张弡弢弣弤弥弦弧弨弩弪弫弬弭弮弯弰弱弲弳弴張弶強弸弹强弻弼弽弾弿彀彁彂彃彄彅彆彇彈彉彊彋彌彍彎彏彐彑归当彔录彖彗彘彙彚彛彜彝彞彟彠彡形彣彤彥彦彧彨彩彪彫彬彭彮彯彰影彲彳彴彵彶彷彸役彺彻彼彽彾彿往征徂徃径待徆徇很徉徊律後徍徎徏徐徑徒従徔徕徖得徘徙徚徛徜徝從徟徠御徢徣徤徥徦徧徨復循徫徬徭微徯徰徱徲徳徴徵徶德徸徹徺徻徼徽徾徿忀忁忂心忄必忆忇忈忉忊忋忌忍忎忏忐忑忒忓忔忕忖志忘忙忚忛応忝忞忟忠忡忢忣忤忥忦忧忨忩忪快忬忭忮忯忰忱忲忳忴念忶忷忸忹忺忻忼忽忾忿怀态怂怃怄怅怆怇怈怉怊怋怌怍怎怏怐怑怒怓怔怕怖怗怘怙怚怛怜思怞怟怠怡怢怣怤急怦性怨怩怪怫怬怭怮怯怰怱怲怳怴怵怶怷怸怹怺总怼怽怾怿恀恁恂恃恄恅恆恇恈恉恊恋恌恍恎恏恐恑恒恓恔恕恖恗恘恙恚恛恜恝恞恟恠恡恢恣恤恥恦恧恨恩恪恫恬恭恮息恰恱恲恳恴恵恶恷恸恹恺恻恼恽恾恿悀悁悂悃悄悅悆悇悈悉悊悋悌悍悎悏悐悑悒悓悔悕悖悗悘悙悚悛悜悝悞悟悠悡悢患悤悥悦悧您悩悪悫悬悭悮悯悰悱悲悳悴悵悶悷悸悹悺悻悼悽悾悿惀惁惂惃惄情惆惇惈惉惊惋惌惍惎惏惐惑惒惓惔惕惖惗惘惙惚惛惜惝惞惟惠惡惢惣惤惥惦惧惨惩惪惫惬惭惮惯惰惱惲想惴惵惶惷惸惹惺惻惼惽惾惿愀愁愂愃愄愅愆愇愈愉愊愋愌愍愎意愐愑愒愓愔愕愖愗愘愙愚愛愜愝愞感愠愡愢愣愤愥愦愧愨愩愪愫愬愭愮愯愰愱愲愳愴愵愶愷愸愹愺愻愼愽愾愿慀慁慂慃慄慅慆慇慈慉慊態慌慍慎慏慐慑慒慓慔慕慖慗慘慙慚慛慜慝慞慟慠慡慢慣慤慥慦慧慨慩慪慫慬慭慮慯慰慱慲慳慴慵慶慷慸慹慺慻慼慽慾慿憀憁憂憃憄憅憆憇憈憉憊憋憌憍憎憏憐憑憒憓憔憕憖憗憘憙憚憛憜憝憞憟憠憡憢憣憤憥憦憧憨憩憪憫憬憭憮憯憰憱憲憳憴憵憶憷憸憹憺憻憼憽憾憿懀懁懂懃懄懅懆懇懈應懊懋懌懍懎懏懐懑懒懓懔懕懖懗懘懙懚懛懜懝懞懟懠懡懢懣懤懥懦懧懨懩懪懫懬懭懮懯懰懱懲懳懴懵懶懷懸懹懺懻懼懽懾懿戀戁戂戃戄戅戆戇戈戉戊戋戌戍戎戏成我戒戓戔戕或戗战戙戚戛戜戝戞戟戠戡戢戣戤戥戦戧戨戩截戫戬戭戮戯戰戱戲戳戴戵戶户戸戹戺戻戼戽戾房所扁扂扃扄扅扆扇扈扉扊手扌才扎扏扐扑扒打扔払扖扗托扙扚扛扜扝扞扟扠扡扢扣扤扥扦执扨扩扪扫扬扭扮扯扰扱扲扳扴扵扶扷扸批扺扻扼扽找承技抁抂抃抄抅抆抇抈抉把抋抌抍抎抏抐抑抒抓抔投抖抗折抙抚抛抜抝択抟抠抡抢抣护报抦抧抨抩抪披抬抭抮抯抰抱抲抳抴抵抶抷抸抹抺抻押抽抾抿拀拁拂拃拄担拆拇拈拉拊拋拌拍拎拏拐拑拒拓拔拕拖拗拘拙拚招拜拝拞拟拠拡拢拣拤拥拦拧拨择拪拫括拭拮拯拰拱拲拳拴拵拶拷拸拹拺拻拼拽拾拿挀持挂挃挄挅挆指挈按挊挋挌挍挎挏挐挑挒挓挔挕挖挗挘挙挚挛挜挝挞挟挠挡挢挣挤挥挦挧挨挩挪挫挬挭挮振挰挱挲挳挴挵挶挷挸挹挺挻挼挽挾挿捀捁捂捃捄捅捆捇捈捉捊捋捌捍捎捏捐捑捒捓捔捕捖捗捘捙捚捛捜捝捞损捠捡换捣捤捥捦捧捨捩捪捫捬捭据捯捰捱捲捳捴捵捶捷捸捹捺捻捼捽捾捿掀掁掂掃掄掅掆掇授掉掊掋掌掍掎掏掐掑排掓掔掕掖掗掘掙掚掛掜掝掞掟掠採探掣掤接掦控推掩措掫掬掭掮掯掰掱掲掳掴掵掶掷掸掹掺掻掼掽掾掿揀揁揂揃揄揅揆揇揈揉揊揋揌揍揎描提揑插揓揔揕揖揗揘揙揚換揜揝揞揟揠握揢揣揤揥揦揧揨揩揪揫揬揭揮揯揰揱揲揳援揵揶揷揸揹揺揻揼揽揾揿搀搁搂搃搄搅搆搇搈搉搊搋搌損搎搏搐搑搒搓搔搕搖搗搘搙搚搛搜搝搞搟搠搡搢搣搤搥搦搧搨搩搪搫搬搭搮搯搰搱搲搳搴搵搶搷搸搹携搻搼搽搾搿摀摁摂摃摄摅摆摇摈摉摊摋摌摍摎摏摐摑摒摓摔摕摖摗摘摙摚摛摜摝摞摟摠摡摢摣摤摥摦摧摨摩摪摫摬摭摮摯摰摱摲摳摴摵摶摷摸摹摺摻摼摽摾摿撀撁撂撃撄撅撆撇撈撉撊撋撌撍撎撏撐撑撒撓撔撕撖撗撘撙撚撛撜撝撞撟撠撡撢撣撤撥撦撧撨撩撪撫撬播撮撯撰撱撲撳撴撵撶撷撸撹撺撻撼撽撾撿擀擁擂擃擄擅擆擇擈擉擊擋擌操擎擏擐擑擒擓擔擕擖擗擘擙據擛擜擝擞擟擠擡擢擣擤擥擦擧擨擩擪擫擬擭擮擯擰擱擲擳擴擵擶擷擸擹擺擻擼擽擾擿攀攁攂攃攄攅攆攇攈攉攊攋攌攍攎攏攐攑攒攓攔攕攖攗攘攙攚攛攜攝攞攟攠攡攢攣攤攥攦攧攨攩攪攫攬攭攮支攰攱攲攳攴攵收攷攸改攺攻攼攽放政敀敁敂敃敄故敆敇效敉敊敋敌敍敎敏敐救敒敓敔敕敖敗敘教敚敛敜敝敞敟敠敡敢散敤敥敦敧敨敩敪敫敬敭敮敯数敱敲敳整敵敶敷數敹敺敻敼敽敾敿斀斁斂斃斄斅斆文斈斉斊斋斌斍斎斏斐斑斒斓斔斕斖斗斘料斚斛斜斝斞斟斠斡斢斣斤斥斦斧斨斩斪斫斬断斮斯新斱斲斳斴斵斶斷斸方斺斻於施斾斿旀旁旂旃旄旅旆旇旈旉旊旋旌旍旎族旐旑旒旓旔旕旖旗旘旙旚旛旜旝旞旟无旡既旣旤日旦旧旨早旪旫旬旭旮旯旰旱旲旳旴旵时旷旸旹旺旻旼旽旾旿昀昁昂昃昄昅昆昇昈昉昊昋昌昍明昏昐昑昒易昔昕昖昗昘昙昚昛昜昝昞星映昡昢昣昤春昦昧昨昩昪昫昬昭昮是昰昱昲昳昴昵昶昷昸昹昺昻昼昽显昿晀晁時晃晄晅晆晇晈晉晊晋晌晍晎晏晐晑晒晓晔晕晖晗晘晙晚晛晜晝晞晟晠晡晢晣晤晥晦晧晨晩晪晫晬晭普景晰晱晲晳晴晵晶晷晸晹智晻晼晽晾晿暀暁暂暃暄暅暆暇暈暉暊暋暌暍暎暏暐暑暒暓暔暕暖暗暘暙暚暛暜暝暞暟暠暡暢暣暤暥暦暧暨暩暪暫暬暭暮暯暰暱暲暳暴暵暶暷暸暹暺暻暼暽暾暿曀曁曂曃曄曅曆曇曈曉曊曋曌曍曎曏曐曑曒曓曔曕曖曗曘曙曚曛曜曝曞曟曠曡曢曣曤曥曦曧曨曩曪曫曬曭曮曯曰曱曲曳更曵曶曷書曹曺曻曼曽曾替最朁朂會朄朅朆朇月有朊朋朌服朎朏朐朑朒朓朔朕朖朗朘朙朚望朜朝朞期朠朡朢朣朤朥朦朧木朩未末本札朮术朰朱朲朳朴朵朶朷朸朹机朻朼朽朾朿杀杁杂权杄杅杆杇杈杉杊杋杌杍李杏材村杒杓杔杕杖杗杘杙杚杛杜杝杞束杠条杢杣杤来杦杧杨杩杪杫杬杭杮杯杰東杲杳杴杵杶杷杸杹杺杻杼杽松板枀极枂枃构枅枆枇枈枉枊枋枌枍枎枏析枑枒枓枔枕枖林枘枙枚枛果枝枞枟枠枡枢枣枤枥枦枧枨枩枪枫枬枭枮枯枰枱枲枳枴枵架枷枸枹枺枻枼枽枾枿柀柁柂柃柄柅柆柇柈柉柊柋柌柍柎柏某柑柒染柔柕柖柗柘柙柚柛柜柝柞柟柠柡柢柣柤查柦柧柨柩柪柫柬柭柮柯柰柱柲柳柴柵柶柷柸柹柺査柼柽柾柿栀栁栂栃栄栅栆标栈栉栊栋栌栍栎栏栐树栒栓栔栕栖栗栘栙栚栛栜栝栞栟栠校栢栣栤栥栦栧栨栩株栫栬栭栮栯栰栱栲栳栴栵栶样核根栺栻格栽栾栿桀桁桂桃桄桅框桇案桉桊桋桌桍桎桏桐桑桒桓桔桕桖桗桘桙桚桛桜桝桞桟桠桡桢档桤桥桦桧桨桩桪桫桬桭桮桯桰桱桲桳桴桵桶桷桸桹桺桻桼桽桾桿梀梁梂梃梄梅梆梇梈梉梊梋梌梍梎梏梐梑梒梓梔梕梖梗梘梙梚梛梜條梞梟梠梡梢梣梤梥梦梧梨梩梪梫梬梭梮梯械梱梲梳梴梵梶梷梸梹梺梻梼梽梾梿检棁棂棃棄棅棆棇棈棉棊棋棌棍棎棏棐棑棒棓棔棕棖棗棘棙棚棛棜棝棞棟棠棡棢棣棤棥棦棧棨棩棪棫棬棭森棯棰棱棲棳棴棵棶棷棸棹棺棻棼棽棾棿椀椁椂椃椄椅椆椇椈椉椊椋椌植椎椏椐椑椒椓椔椕椖椗椘椙椚椛検椝椞椟椠椡椢椣椤椥椦椧椨椩椪椫椬椭椮椯椰椱椲椳椴椵椶椷椸椹椺椻椼椽椾椿楀楁楂楃楄楅楆楇楈楉楊楋楌楍楎楏楐楑楒楓楔楕楖楗楘楙楚楛楜楝楞楟楠楡楢楣楤楥楦楧楨楩楪楫楬業楮楯楰楱楲楳楴極楶楷楸楹楺楻楼楽楾楿榀榁概榃榄榅榆榇榈榉榊榋榌榍榎榏榐榑榒榓榔榕榖榗榘榙榚榛榜榝榞榟榠榡榢榣榤榥榦榧榨榩榪榫榬榭榮榯榰榱榲榳榴榵榶榷榸榹榺榻榼榽榾榿槀槁槂槃槄槅槆槇槈槉槊構槌槍槎槏槐槑槒槓槔槕槖槗様槙槚槛槜槝槞槟槠槡槢槣槤槥槦槧槨槩槪槫槬槭槮槯槰槱槲槳槴槵槶槷槸槹槺槻槼槽槾槿樀樁樂樃樄樅樆樇樈樉樊樋樌樍樎樏樐樑樒樓樔樕樖樗樘標樚樛樜樝樞樟樠模樢樣樤樥樦樧樨権横樫樬樭樮樯樰樱樲樳樴樵樶樷樸樹樺樻樼樽樾樿橀橁橂橃橄橅橆橇橈橉橊橋橌橍橎橏橐橑橒橓橔橕橖橗橘橙橚橛橜橝橞機橠橡橢橣橤橥橦橧橨橩橪橫橬橭橮橯橰橱橲橳橴橵橶橷橸橹橺橻橼橽橾橿檀檁檂檃檄檅檆檇檈檉檊檋檌檍檎檏檐檑檒檓檔檕檖檗檘檙檚檛檜檝檞檟檠檡檢檣檤檥檦檧檨檩檪檫檬檭檮檯檰檱檲檳檴檵檶檷檸檹檺檻檼檽檾檿櫀櫁櫂櫃櫄櫅櫆櫇櫈櫉櫊櫋櫌櫍櫎櫏櫐櫑櫒櫓櫔櫕櫖櫗櫘櫙櫚櫛櫜櫝櫞櫟櫠櫡櫢櫣櫤櫥櫦櫧櫨櫩櫪櫫櫬櫭櫮櫯櫰櫱櫲櫳櫴櫵櫶櫷櫸櫹櫺櫻櫼櫽櫾櫿欀欁欂欃欄欅欆欇欈欉權欋欌欍欎欏欐欑欒欓欔欕欖欗欘欙欚欛欜欝欞欟欠次欢欣欤欥欦欧欨欩欪欫欬欭欮欯欰欱欲欳欴欵欶欷欸欹欺欻欼欽款欿歀歁歂歃歄歅歆歇歈歉歊歋歌歍歎歏歐歑歒歓歔歕歖歗歘歙歚歛歜歝歞歟歠歡止正此步武歧歨歩歪歫歬歭歮歯歰歱歲歳歴歵歶歷歸歹歺死歼歽歾歿殀殁殂殃殄殅殆殇殈殉殊残殌殍殎殏殐殑殒殓殔殕殖殗殘殙殚殛殜殝殞殟殠殡殢殣殤殥殦殧殨殩殪殫殬殭殮殯殰殱殲殳殴段殶殷殸殹殺殻殼殽殾殿毀毁毂毃毄毅毆毇毈毉毊毋毌母毎每毐毑毒毓比毕毖毗毘毙毚毛毜毝毞毟毠毡毢毣毤毥毦毧毨毩毪毫毬毭毮毯毰毱毲毳毴毵毶毷毸毹毺毻毼毽毾毿氀氁氂氃氄氅氆氇氈氉氊氋氌氍氎氏氐民氒氓气氕氖気氘氙氚氛氜氝氞氟氠氡氢氣氤氥氦氧氨氩氪氫氬氭氮氯氰氱氲氳水氵氶氷永氹氺氻氼氽氾氿汀汁求汃汄汅汆汇汈汉汊汋汌汍汎汏汐汑汒汓汔汕汖汗汘汙汚汛汜汝汞江池污汢汣汤汥汦汧汨汩汪汫汬汭汮汯汰汱汲汳汴汵汶汷汸汹決汻汼汽汾汿沀沁沂沃沄沅沆沇沈沉沊沋沌沍沎沏沐沑沒沓沔沕沖沗沘沙沚沛沜沝沞沟沠没沢沣沤沥沦沧沨沩沪沫沬沭沮沯沰沱沲河沴沵沶沷沸油沺治沼沽沾沿泀況泂泃泄泅泆泇泈泉泊泋泌泍泎泏泐泑泒泓泔法泖泗泘泙泚泛泜泝泞泟泠泡波泣泤泥泦泧注泩泪泫泬泭泮泯泰泱泲泳泴泵泶泷泸泹泺泻泼泽泾泿洀洁洂洃洄洅洆洇洈洉洊洋洌洍洎洏洐洑洒洓洔洕洖洗洘洙洚洛洜洝洞洟洠洡洢洣洤津洦洧洨洩洪洫洬洭洮洯洰洱洲洳洴洵洶洷洸洹洺活洼洽派洿浀流浂浃浄浅浆浇浈浉浊测浌浍济浏浐浑浒浓浔浕浖浗浘浙浚浛浜浝浞浟浠浡浢浣浤浥浦浧浨浩浪浫浬浭浮浯浰浱浲浳浴浵浶海浸浹浺浻浼浽浾浿涀涁涂涃涄涅涆涇消涉涊涋涌涍涎涏涐涑涒涓涔涕涖涗涘涙涚涛涜涝涞涟涠涡涢涣涤涥润涧涨涩涪涫涬涭涮涯涰涱液涳涴涵涶涷涸涹涺涻涼涽涾涿淀淁淂淃淄淅淆淇淈淉淊淋淌淍淎淏淐淑淒淓淔淕淖淗淘淙淚淛淜淝淞淟淠淡淢淣淤淥淦淧淨淩淪淫淬淭淮淯淰深淲淳淴淵淶混淸淹淺添淼淽淾淿渀渁渂渃渄清渆渇済渉渊渋渌渍渎渏渐渑渒渓渔渕渖渗渘渙渚減渜渝渞渟渠渡渢渣渤渥渦渧渨温渪渫測渭渮港渰渱渲渳渴渵渶渷游渹渺渻渼渽渾渿湀湁湂湃湄湅湆湇湈湉湊湋湌湍湎湏湐湑湒湓湔湕湖湗湘湙湚湛湜湝湞湟湠湡湢湣湤湥湦湧湨湩湪湫湬湭湮湯湰湱湲湳湴湵湶湷湸湹湺湻湼湽湾湿満溁溂溃溄溅溆溇溈溉溊溋溌溍溎溏源溑溒溓溔溕準溗溘溙溚溛溜溝溞溟溠溡溢溣溤溥溦溧溨溩溪溫溬溭溮溯溰溱溲溳溴溵溶溷溸溹溺溻溼溽溾溿滀滁滂滃滄滅滆滇滈滉滊滋滌滍滎滏滐滑滒滓滔滕滖滗滘滙滚滛滜滝滞滟滠满滢滣滤滥滦滧滨滩滪滫滬滭滮滯滰滱滲滳滴滵滶滷滸滹滺滻滼滽滾滿漀漁漂漃漄漅漆漇漈漉漊漋漌漍漎漏漐漑漒漓演漕漖漗漘漙漚漛漜漝漞漟漠漡漢漣漤漥漦漧漨漩漪漫漬漭漮漯漰漱漲漳漴漵漶漷漸漹漺漻漼漽漾漿潀潁潂潃潄潅潆潇潈潉潊潋潌潍潎潏潐潑潒潓潔潕潖潗潘潙潚潛潜潝潞潟潠潡潢潣潤潥潦潧潨潩潪潫潬潭潮潯潰潱潲潳潴潵潶潷潸潹潺潻潼潽潾潿澀澁澂澃澄澅澆澇澈澉澊澋澌澍澎澏澐澑澒澓澔澕澖澗澘澙澚澛澜澝澞澟澠澡澢澣澤澥澦澧澨澩澪澫澬澭澮澯澰澱澲澳澴澵澶澷澸澹澺澻澼澽澾澿激濁濂濃濄濅濆濇濈濉濊濋濌濍濎濏濐濑濒濓濔濕濖濗濘濙濚濛濜濝濞濟濠濡濢濣濤濥濦濧濨濩濪濫濬濭濮濯濰濱濲濳濴濵濶濷濸濹濺濻濼濽濾濿瀀瀁瀂瀃瀄瀅瀆瀇瀈瀉瀊瀋瀌瀍瀎瀏瀐瀑瀒瀓瀔瀕瀖瀗瀘瀙瀚瀛瀜瀝瀞瀟瀠瀡瀢瀣瀤瀥瀦瀧瀨瀩瀪瀫瀬瀭瀮瀯瀰瀱瀲瀳瀴瀵瀶瀷瀸瀹瀺瀻瀼瀽瀾瀿灀灁灂灃灄灅灆灇灈灉灊灋灌灍灎灏灐灑灒灓灔灕灖灗灘灙灚灛灜灝灞灟灠灡灢灣灤灥灦灧灨灩灪火灬灭灮灯灰灱灲灳灴灵灶灷灸灹灺灻灼災灾灿炀炁炂炃炄炅炆炇炈炉炊炋炌炍炎炏炐炑炒炓炔炕炖炗炘炙炚炛炜炝炞炟炠炡炢炣炤炥炦炧炨炩炪炫炬炭炮炯炰炱炲炳炴炵炶炷炸点為炻炼炽炾炿烀烁烂烃烄烅烆烇烈烉烊烋烌烍烎烏烐烑烒烓烔烕烖烗烘烙烚烛烜烝烞烟烠烡烢烣烤烥烦烧烨烩烪烫烬热烮烯烰烱烲烳烴烵烶烷烸烹烺烻烼烽烾烿焀焁焂焃焄焅焆焇焈焉焊焋焌焍焎焏焐焑焒焓焔焕焖焗焘焙焚焛焜焝焞焟焠無焢焣焤焥焦焧焨焩焪焫焬焭焮焯焰焱焲焳焴焵然焷焸焹焺焻焼焽焾焿煀煁煂煃煄煅煆煇煈煉煊煋煌煍煎煏煐煑煒煓煔煕煖煗煘煙煚煛煜煝煞煟煠煡煢煣煤煥煦照煨煩煪煫煬煭煮煯煰煱煲煳煴煵煶煷煸煹煺煻煼煽煾煿熀熁熂熃熄熅熆熇熈熉熊熋熌熍熎熏熐熑熒熓熔熕熖熗熘熙熚熛熜熝熞熟熠熡熢熣熤熥熦熧熨熩熪熫熬熭熮熯熰熱熲熳熴熵熶熷熸熹熺熻熼熽熾熿燀燁燂燃燄燅燆燇燈燉燊燋燌燍燎燏燐燑燒燓燔燕燖燗燘燙燚燛燜燝燞營燠燡燢燣燤燥燦燧燨燩燪燫燬燭燮燯燰燱燲燳燴燵燶燷燸燹燺燻燼燽燾燿爀爁爂爃爄爅爆爇爈爉爊爋爌爍爎爏爐爑爒爓爔爕爖爗爘爙爚爛爜爝爞爟爠爡爢爣爤爥爦爧爨爩爪爫爬爭爮爯爰爱爲爳爴爵父爷爸爹爺爻爼爽爾爿牀牁牂牃牄牅牆片版牉牊牋牌牍牎牏牐牑牒牓牔牕牖牗牘牙牚牛牜牝牞牟牠牡牢牣牤牥牦牧牨物牪牫牬牭牮牯牰牱牲牳牴牵牶牷牸特牺牻牼牽牾牿犀犁犂犃犄犅犆犇犈犉犊犋犌犍犎犏犐犑犒犓犔犕犖犗犘犙犚犛犜犝犞犟犠犡犢犣犤犥犦犧犨犩犪犫犬犭犮犯犰犱犲犳犴犵状犷犸犹犺犻犼犽犾犿狀狁狂狃狄狅狆狇狈狉狊狋狌狍狎狏狐狑狒狓狔狕狖狗狘狙狚狛狜狝狞狟狠狡狢狣狤狥狦狧狨狩狪狫独狭狮狯狰狱狲狳狴狵狶狷狸狹狺狻狼狽狾狿猀猁猂猃猄猅猆猇猈猉猊猋猌猍猎猏猐猑猒猓猔猕猖猗猘猙猚猛猜猝猞猟猠猡猢猣猤猥猦猧猨猩猪猫猬猭献猯猰猱猲猳猴猵猶猷猸猹猺猻猼猽猾猿獀獁獂獃獄獅獆獇獈獉獊獋獌獍獎獏獐獑獒獓獔獕獖獗獘獙獚獛獜獝獞獟獠獡獢獣獤獥獦獧獨獩獪獫獬獭獮獯獰獱獲獳獴獵獶獷獸獹獺獻獼獽獾獿玀玁玂玃玄玅玆率玈玉玊王玌玍玎玏玐玑玒玓玔玕玖玗玘玙玚玛玜玝玞玟玠玡玢玣玤玥玦玧玨玩玪玫玬玭玮环现玱玲玳玴玵玶玷玸玹玺玻玼玽玾玿珀珁珂珃珄珅珆珇珈珉珊珋珌珍珎珏珐珑珒珓珔珕珖珗珘珙珚珛珜珝珞珟珠珡珢珣珤珥珦珧珨珩珪珫珬班珮珯珰珱珲珳珴珵珶珷珸珹珺珻珼珽現珿琀琁琂球琄琅理琇琈琉琊琋琌琍琎琏琐琑琒琓琔琕琖琗琘琙琚琛琜琝琞琟琠琡琢琣琤琥琦琧琨琩琪琫琬琭琮琯琰琱琲琳琴琵琶琷琸琹琺琻琼琽琾琿瑀瑁瑂瑃瑄瑅瑆瑇瑈瑉瑊瑋瑌瑍瑎瑏瑐瑑瑒瑓瑔瑕瑖瑗瑘瑙瑚瑛瑜瑝瑞瑟瑠瑡瑢瑣瑤瑥瑦瑧瑨瑩瑪瑫瑬瑭瑮瑯瑰瑱瑲瑳瑴瑵瑶瑷瑸瑹瑺瑻瑼瑽瑾瑿璀璁璂璃璄璅璆璇璈璉璊璋璌璍璎璏璐璑璒璓璔璕璖璗璘璙璚璛璜璝璞璟璠璡璢璣璤璥璦璧璨璩璪璫璬璭璮璯環璱璲璳璴璵璶璷璸璹璺璻璼璽璾璿瓀瓁瓂瓃瓄瓅瓆瓇瓈瓉瓊瓋瓌瓍瓎瓏瓐瓑瓒瓓瓔瓕瓖瓗瓘瓙瓚瓛瓜瓝瓞瓟瓠瓡瓢瓣瓤瓥瓦瓧瓨瓩瓪瓫瓬瓭瓮瓯瓰瓱瓲瓳瓴瓵瓶瓷瓸瓹瓺瓻瓼瓽瓾瓿甀甁甂甃甄甅甆甇甈甉甊甋甌甍甎甏甐甑甒甓甔甕甖甗甘甙甚甛甜甝甞生甠甡產産甤甥甦甧用甩甪甫甬甭甮甯田由甲申甴电甶男甸甹町画甼甽甾甿畀畁畂畃畄畅畆畇畈畉畊畋界畍畎畏畐畑畒畓畔畕畖畗畘留畚畛畜畝畞畟畠畡畢畣畤略畦畧畨畩番畫畬畭畮畯異畱畲畳畴畵當畷畸畹畺畻畼畽畾畿疀疁疂疃疄疅疆疇疈疉疊疋疌疍疎疏疐疑疒疓疔疕疖疗疘疙疚疛疜疝疞疟疠疡疢疣疤疥疦疧疨疩疪疫疬疭疮疯疰疱疲疳疴疵疶疷疸疹疺疻疼疽疾疿痀痁痂痃痄病痆症痈痉痊痋痌痍痎痏痐痑痒痓痔痕痖痗痘痙痚痛痜痝痞痟痠痡痢痣痤痥痦痧痨痩痪痫痬痭痮痯痰痱痲痳痴痵痶痷痸痹痺痻痼痽痾痿瘀瘁瘂瘃瘄瘅瘆瘇瘈瘉瘊瘋瘌瘍瘎瘏瘐瘑瘒瘓瘔瘕瘖瘗瘘瘙瘚瘛瘜瘝瘞瘟瘠瘡瘢瘣瘤瘥瘦瘧瘨瘩瘪瘫瘬瘭瘮瘯瘰瘱瘲瘳瘴瘵瘶瘷瘸瘹瘺瘻瘼瘽瘾瘿癀癁療癃癄癅癆癇癈癉癊癋癌癍癎癏癐癑癒癓癔癕癖癗癘癙癚癛癜癝癞癟癠癡癢癣癤癥癦癧癨癩癪癫癬癭癮癯癰癱癲癳癴癵癶癷癸癹発登發白百癿皀皁皂皃的皅皆皇皈皉皊皋皌皍皎皏皐皑皒皓皔皕皖皗皘皙皚皛皜皝皞皟皠皡皢皣皤皥皦皧皨皩皪皫皬皭皮皯皰皱皲皳皴皵皶皷皸皹皺皻皼皽皾皿盀盁盂盃盄盅盆盇盈盉益盋盌盍盎盏盐监盒盓盔盕盖盗盘盙盚盛盜盝盞盟盠盡盢監盤盥盦盧盨盩盪盫盬盭目盯盰盱盲盳直盵盶盷相盹盺盻盼盽盾盿眀省眂眃眄眅眆眇眈眉眊看県眍眎眏眐眑眒眓眔眕眖眗眘眙眚眛眜眝眞真眠眡眢眣眤眥眦眧眨眩眪眫眬眭眮眯眰眱眲眳眴眵眶眷眸眹眺眻眼眽眾眿着睁睂睃睄睅睆睇睈睉睊睋睌睍睎睏睐睑睒睓睔睕睖睗睘睙睚睛睜睝睞睟睠睡睢督睤睥睦睧睨睩睪睫睬睭睮睯睰睱睲睳睴睵睶睷睸睹睺睻睼睽睾睿瞀瞁瞂瞃瞄瞅瞆瞇瞈瞉瞊瞋瞌瞍瞎瞏瞐瞑瞒瞓瞔瞕瞖瞗瞘瞙瞚瞛瞜瞝瞞瞟瞠瞡瞢瞣瞤瞥瞦瞧瞨瞩瞪瞫瞬瞭瞮瞯瞰瞱瞲瞳瞴瞵瞶瞷瞸瞹瞺瞻瞼瞽瞾瞿矀矁矂矃矄矅矆矇矈矉矊矋矌矍矎矏矐矑矒矓矔矕矖矗矘矙矚矛矜矝矞矟矠矡矢矣矤知矦矧矨矩矪矫矬短矮矯矰矱矲石矴矵矶矷矸矹矺矻矼矽矾矿砀码砂砃砄砅砆砇砈砉砊砋砌砍砎砏砐砑砒砓研砕砖砗砘砙砚砛砜砝砞砟砠砡砢砣砤砥砦砧砨砩砪砫砬砭砮砯砰砱砲砳破砵砶砷砸砹砺砻砼砽砾砿础硁硂硃硄硅硆硇硈硉硊硋硌硍硎硏硐硑硒硓硔硕硖硗硘硙硚硛硜硝硞硟硠硡硢硣硤硥硦硧硨硩硪硫硬硭确硯硰硱硲硳硴硵硶硷硸硹硺硻硼硽硾硿碀碁碂碃碄碅碆碇碈碉碊碋碌碍碎碏碐碑碒碓碔碕碖碗碘碙碚碛碜碝碞碟碠碡碢碣碤碥碦碧碨碩碪碫碬碭碮碯碰碱碲碳碴碵碶碷碸碹確碻碼碽碾碿磀磁磂磃磄磅磆磇磈磉磊磋磌磍磎磏磐磑磒磓磔磕磖磗磘磙磚磛磜磝磞磟磠磡磢磣磤磥磦磧磨磩磪磫磬磭磮磯磰磱磲磳磴磵磶磷磸磹磺磻磼磽磾磿礀礁礂礃礄礅礆礇礈礉礊礋礌礍礎礏礐礑礒礓礔礕礖礗礘礙礚礛礜礝礞礟礠礡礢礣礤礥礦礧礨礩礪礫礬礭礮礯礰礱礲礳礴礵礶礷礸礹示礻礼礽社礿祀祁祂祃祄祅祆祇祈祉祊祋祌祍祎祏祐祑祒祓祔祕祖祗祘祙祚祛祜祝神祟祠祡祢祣祤祥祦祧票祩祪祫祬祭祮祯祰祱祲祳祴祵祶祷祸祹祺祻祼祽祾祿禀禁禂禃禄禅禆禇禈禉禊禋禌禍禎福禐禑禒禓禔禕禖禗禘禙禚禛禜禝禞禟禠禡禢禣禤禥禦禧禨禩禪禫禬禭禮禯禰禱禲禳禴禵禶禷禸禹禺离禼禽禾禿秀私秂秃秄秅秆秇秈秉秊秋秌种秎秏秐科秒秓秔秕秖秗秘秙秚秛秜秝秞租秠秡秢秣秤秥秦秧秨秩秪秫秬秭秮积称秱秲秳秴秵秶秷秸秹秺移秼秽秾秿稀稁稂稃稄稅稆稇稈稉稊程稌稍税稏稐稑稒稓稔稕稖稗稘稙稚稛稜稝稞稟稠稡稢稣稤稥稦稧稨稩稪稫稬稭種稯稰稱稲稳稴稵稶稷稸稹稺稻稼稽稾稿穀穁穂穃穄穅穆穇穈穉穊穋穌積穎穏穐穑穒穓穔穕穖穗穘穙穚穛穜穝穞穟穠穡穢穣穤穥穦穧穨穩穪穫穬穭穮穯穰穱穲穳穴穵究穷穸穹空穻穼穽穾穿窀突窂窃窄窅窆窇窈窉窊窋窌窍窎窏窐窑窒窓窔窕窖窗窘窙窚窛窜窝窞窟窠窡窢窣窤窥窦窧窨窩窪窫窬窭窮窯窰窱窲窳窴窵窶窷窸窹窺窻窼窽窾窿竀竁竂竃竄竅竆竇竈竉竊立竌竍竎竏竐竑竒竓竔竕竖竗竘站竚竛竜竝竞竟章竡竢竣竤童竦竧竨竩竪竫竬竭竮端竰竱竲竳竴竵競竷竸竹竺竻竼竽竾竿笀笁笂笃笄笅笆笇笈笉笊笋笌笍笎笏笐笑笒笓笔笕笖笗笘笙笚笛笜笝笞笟笠笡笢笣笤笥符笧笨笩笪笫第笭笮笯笰笱笲笳笴笵笶笷笸笹笺笻笼笽笾笿筀筁筂筃筄筅筆筇筈等筊筋筌筍筎筏筐筑筒筓答筕策筗筘筙筚筛筜筝筞筟筠筡筢筣筤筥筦筧筨筩筪筫筬筭筮筯筰筱筲筳筴筵筶筷筸筹筺筻筼筽签筿简箁箂箃箄箅箆箇箈箉箊箋箌箍箎箏箐箑箒箓箔箕箖算箘箙箚箛箜箝箞箟箠管箢箣箤箥箦箧箨箩箪箫箬箭箮箯箰箱箲箳箴箵箶箷箸箹箺箻箼箽箾箿節篁篂篃範篅篆篇篈築篊篋篌篍篎篏篐篑篒篓篔篕篖篗篘篙篚篛篜篝篞篟篠篡篢篣篤篥篦篧篨篩篪篫篬篭篮篯篰篱篲篳篴篵篶篷篸篹篺篻篼篽篾篿簀簁簂簃簄簅簆簇簈簉簊簋簌簍簎簏簐簑簒簓簔簕簖簗簘簙簚簛簜簝簞簟簠簡簢簣簤簥簦簧簨簩簪簫簬簭簮簯簰簱簲簳簴簵簶簷簸簹簺簻簼簽簾簿籀籁籂籃籄籅籆籇籈籉籊籋籌籍籎籏籐籑籒籓籔籕籖籗籘籙籚籛籜籝籞籟籠籡籢籣籤籥籦籧籨籩籪籫籬籭籮籯籰籱籲米籴籵籶籷籸籹籺类籼籽籾籿粀粁粂粃粄粅粆粇粈粉粊粋粌粍粎粏粐粑粒粓粔粕粖粗粘粙粚粛粜粝粞粟粠粡粢粣粤粥粦粧粨粩粪粫粬粭粮粯粰粱粲粳粴粵粶粷粸粹粺粻粼粽精粿糀糁糂糃糄糅糆糇糈糉糊糋糌糍糎糏糐糑糒糓糔糕糖糗糘糙糚糛糜糝糞糟糠糡糢糣糤糥糦糧糨糩糪糫糬糭糮糯糰糱糲糳糴糵糶糷糸糹糺系糼糽糾糿紀紁紂紃約紅紆紇紈紉紊紋紌納紎紏紐紑紒紓純紕紖紗紘紙級紛紜紝紞紟素紡索紣紤紥紦紧紨紩紪紫紬紭紮累細紱紲紳紴紵紶紷紸紹紺紻紼紽紾紿絀絁終絃組絅絆絇絈絉絊絋経絍絎絏結絑絒絓絔絕絖絗絘絙絚絛絜絝絞絟絠絡絢絣絤絥給絧絨絩絪絫絬絭絮絯絰統絲絳絴絵絶絷絸絹絺絻絼絽絾絿綀綁綂綃綄綅綆綇綈綉綊綋綌綍綎綏綐綑綒經綔綕綖綗綘継続綛綜綝綞綟綠綡綢綣綤綥綦綧綨綩綪綫綬維綮綯綰綱網綳綴綵綶綷綸綹綺綻綼綽綾綿緀緁緂緃緄緅緆緇緈緉緊緋緌緍緎総緐緑緒緓緔緕緖緗緘緙線緛緜緝緞緟締緡緢緣緤緥緦緧編緩緪緫緬緭緮緯緰緱緲緳練緵緶緷緸緹緺緻緼緽緾緿縀縁縂縃縄縅縆縇縈縉縊縋縌縍縎縏縐縑縒縓縔縕縖縗縘縙縚縛縜縝縞縟縠縡縢縣縤縥縦縧縨縩縪縫縬縭縮縯縰縱縲縳縴縵縶縷縸縹縺縻縼總績縿繀繁繂繃繄繅繆繇繈繉繊繋繌繍繎繏繐繑繒繓織繕繖繗繘繙繚繛繜繝繞繟繠繡繢繣繤繥繦繧繨繩繪繫繬繭繮繯繰繱繲繳繴繵繶繷繸繹繺繻繼繽繾繿纀纁纂纃纄纅纆纇纈纉纊纋續纍纎纏纐纑纒纓纔纕纖纗纘纙纚纛纜纝纞纟纠纡红纣纤纥约级纨纩纪纫纬纭纮纯纰纱纲纳纴纵纶纷纸纹纺纻纼纽纾线绀绁绂练组绅细织终绉绊绋绌绍绎经绐绑绒结绔绕绖绗绘给绚绛络绝绞统绠绡绢绣绤绥绦继绨绩绪绫绬续绮绯绰绱绲绳维绵绶绷绸绹绺绻综绽绾绿缀缁缂缃缄缅缆缇缈缉缊缋缌缍缎缏缐缑缒缓缔缕编缗缘缙缚缛缜缝缞缟缠缡缢缣缤缥缦缧缨缩缪缫缬缭缮缯缰缱缲缳缴缵缶缷缸缹缺缻缼缽缾缿罀罁罂罃罄罅罆罇罈罉罊罋罌罍罎罏罐网罒罓罔罕罖罗罘罙罚罛罜罝罞罟罠罡罢罣罤罥罦罧罨罩罪罫罬罭置罯罰罱署罳罴罵罶罷罸罹罺罻罼罽罾罿羀羁羂羃羄羅羆羇羈羉羊羋羌羍美羏羐羑羒羓羔羕羖羗羘羙羚羛羜羝羞羟羠羡羢羣群羥羦羧羨義羪羫羬羭羮羯羰羱羲羳羴羵羶羷羸羹羺羻羼羽羾羿翀翁翂翃翄翅翆翇翈翉翊翋翌翍翎翏翐翑習翓翔翕翖翗翘翙翚翛翜翝翞翟翠翡翢翣翤翥翦翧翨翩翪翫翬翭翮翯翰翱翲翳翴翵翶翷翸翹翺翻翼翽翾翿耀老耂考耄者耆耇耈耉耊耋而耍耎耏耐耑耒耓耔耕耖耗耘耙耚耛耜耝耞耟耠耡耢耣耤耥耦耧耨耩耪耫耬耭耮耯耰耱耲耳耴耵耶耷耸耹耺耻耼耽耾耿聀聁聂聃聄聅聆聇聈聉聊聋职聍聎聏聐聑聒聓联聕聖聗聘聙聚聛聜聝聞聟聠聡聢聣聤聥聦聧聨聩聪聫聬聭聮聯聰聱聲聳聴聵聶職聸聹聺聻聼聽聾聿肀肁肂肃肄肅肆肇肈肉肊肋肌肍肎肏肐肑肒肓肔肕肖肗肘肙肚肛肜肝肞肟肠股肢肣肤肥肦肧肨肩肪肫肬肭肮肯肰肱育肳肴肵肶肷肸肹肺肻肼肽肾肿胀胁胂胃胄胅胆胇胈胉胊胋背胍胎胏胐胑胒胓胔胕胖胗胘胙胚胛胜胝胞胟胠胡胢胣胤胥胦胧胨胩胪胫胬胭胮胯胰胱胲胳胴胵胶胷胸胹胺胻胼能胾胿脀脁脂脃脄脅脆脇脈脉脊脋脌脍脎脏脐脑脒脓脔脕脖脗脘脙脚脛脜脝脞脟脠脡脢脣脤脥脦脧脨脩脪脫脬脭脮脯脰脱脲脳脴脵脶脷脸脹脺脻脼脽脾脿腀腁腂腃腄腅腆腇腈腉腊腋腌腍腎腏腐腑腒腓腔腕腖腗腘腙腚腛腜腝腞腟腠腡腢腣腤腥腦腧腨腩腪腫腬腭腮腯腰腱腲腳腴腵腶腷腸腹腺腻腼腽腾腿膀膁膂膃膄膅膆膇膈膉膊膋膌膍膎膏膐膑膒膓膔膕膖膗膘膙膚膛膜膝膞膟膠膡膢膣膤膥膦膧膨膩膪膫膬膭膮膯膰膱膲膳膴膵膶膷膸膹膺膻膼膽膾膿臀臁臂臃臄臅臆臇臈臉臊臋臌臍臎臏臐臑臒臓臔臕臖臗臘臙臚臛臜臝臞臟臠臡臢臣臤臥臦臧臨臩自臫臬臭臮臯臰臱臲至致臵臶臷臸臹臺臻臼臽臾臿舀舁舂舃舄舅舆與興舉舊舋舌舍舎舏舐舑舒舓舔舕舖舗舘舙舚舛舜舝舞舟舠舡舢舣舤舥舦舧舨舩航舫般舭舮舯舰舱舲舳舴舵舶舷舸船舺舻舼舽舾舿艀艁艂艃艄艅艆艇艈艉艊艋艌艍艎艏艐艑艒艓艔艕艖艗艘艙艚艛艜艝艞艟艠艡艢艣艤艥艦艧艨艩艪艫艬艭艮良艰艱色艳艴艵艶艷艸艹艺艻艼艽艾艿芀芁节芃芄芅芆芇芈芉芊芋芌芍芎芏芐芑芒芓芔芕芖芗芘芙芚芛芜芝芞芟芠芡芢芣芤芥芦芧芨芩芪芫芬芭芮芯芰花芲芳芴芵芶芷芸芹芺芻芼芽芾芿苀苁苂苃苄苅苆苇苈苉苊苋苌苍苎苏苐苑苒苓苔苕苖苗苘苙苚苛苜苝苞苟苠苡苢苣苤若苦苧苨苩苪苫苬苭苮苯苰英苲苳苴苵苶苷苸苹苺苻苼苽苾苿茀茁茂范茄茅茆茇茈茉茊茋茌茍茎茏茐茑茒茓茔茕茖茗茘茙茚茛茜茝茞茟茠茡茢茣茤茥茦茧茨茩茪茫茬茭茮茯茰茱茲茳茴茵茶茷茸茹茺茻茼茽茾茿荀荁荂荃荄荅荆荇荈草荊荋荌荍荎荏荐荑荒荓荔荕荖荗荘荙荚荛荜荝荞荟荠荡荢荣荤荥荦荧荨荩荪荫荬荭荮药荰荱荲荳荴荵荶荷荸荹荺荻荼荽荾荿莀莁莂莃莄莅莆莇莈莉莊莋莌莍莎莏莐莑莒莓莔莕莖莗莘莙莚莛莜莝莞莟莠莡莢莣莤莥莦莧莨莩莪莫莬莭莮莯莰莱莲莳莴莵莶获莸莹莺莻莼莽莾莿菀菁菂菃菄菅菆菇菈菉菊菋菌菍菎菏菐菑菒菓菔菕菖菗菘菙菚菛菜菝菞菟菠菡菢菣菤菥菦菧菨菩菪菫菬菭菮華菰菱菲菳菴菵菶菷菸菹菺菻菼菽菾菿萀萁萂萃萄萅萆萇萈萉萊萋萌萍萎萏萐萑萒萓萔萕萖萗萘萙萚萛萜萝萞萟萠萡萢萣萤营萦萧萨萩萪萫萬萭萮萯萰萱萲萳萴萵萶萷萸萹萺萻萼落萾萿葀葁葂葃葄葅葆葇葈葉葊葋葌葍葎葏葐葑葒葓葔葕葖著葘葙葚葛葜葝葞葟葠葡葢董葤葥葦葧葨葩葪葫葬葭葮葯葰葱葲葳葴葵葶葷葸葹葺葻葼葽葾葿蒀蒁蒂蒃蒄蒅蒆蒇蒈蒉蒊蒋蒌蒍蒎蒏蒐蒑蒒蒓蒔蒕蒖蒗蒘蒙蒚蒛蒜蒝蒞蒟蒠蒡蒢蒣蒤蒥蒦蒧蒨蒩蒪蒫蒬蒭蒮蒯蒰蒱蒲蒳蒴蒵蒶蒷蒸蒹蒺蒻蒼蒽蒾蒿蓀蓁蓂蓃蓄蓅蓆蓇蓈蓉蓊蓋蓌蓍蓎蓏蓐蓑蓒蓓蓔蓕蓖蓗蓘蓙蓚蓛蓜蓝蓞蓟蓠蓡蓢蓣蓤蓥蓦蓧蓨蓩蓪蓫蓬蓭蓮蓯蓰蓱蓲蓳蓴蓵蓶蓷蓸蓹蓺蓻蓼蓽蓾蓿蔀蔁蔂蔃蔄蔅蔆蔇蔈蔉蔊蔋蔌蔍蔎蔏蔐蔑蔒蔓蔔蔕蔖蔗蔘蔙蔚蔛蔜蔝蔞蔟蔠蔡蔢蔣蔤蔥蔦蔧蔨蔩蔪蔫蔬蔭蔮蔯蔰蔱蔲蔳蔴蔵蔶蔷蔸蔹蔺蔻蔼蔽蔾蔿蕀蕁蕂蕃蕄蕅蕆蕇蕈蕉蕊蕋蕌蕍蕎蕏蕐蕑蕒蕓蕔蕕蕖蕗蕘蕙蕚蕛蕜蕝蕞蕟蕠蕡蕢蕣蕤蕥蕦蕧蕨蕩蕪蕫蕬蕭蕮蕯蕰蕱蕲蕳蕴蕵蕶蕷蕸蕹蕺蕻蕼蕽蕾蕿薀薁薂薃薄薅薆薇薈薉薊薋薌薍薎薏薐薑薒薓薔薕薖薗薘薙薚薛薜薝薞薟薠薡薢薣薤薥薦薧薨薩薪薫薬薭薮薯薰薱薲薳薴薵薶薷薸薹薺薻薼薽薾薿藀藁藂藃藄藅藆藇藈藉藊藋藌藍藎藏藐藑藒藓藔藕藖藗藘藙藚藛藜藝藞藟藠藡藢藣藤藥藦藧藨藩藪藫藬藭藮藯藰藱藲藳藴藵藶藷藸藹藺藻藼藽藾藿蘀蘁蘂蘃蘄蘅蘆蘇蘈蘉蘊蘋蘌蘍蘎蘏蘐蘑蘒蘓蘔蘕蘖蘗蘘蘙蘚蘛蘜蘝蘞蘟蘠蘡蘢蘣蘤蘥蘦蘧蘨蘩蘪蘫蘬蘭蘮蘯蘰蘱蘲蘳蘴蘵蘶蘷蘸蘹蘺蘻蘼蘽蘾蘿虀虁虂虃虄虅虆虇虈虉虊虋虌虍虎虏虐虑虒虓虔處虖虗虘虙虚虛虜虝虞號虠虡虢虣虤虥虦虧虨虩虪虫虬虭虮虯虰虱虲虳虴虵虶虷虸虹虺虻虼虽虾虿蚀蚁蚂蚃蚄蚅蚆蚇蚈蚉蚊蚋蚌蚍蚎蚏蚐蚑蚒蚓蚔蚕蚖蚗蚘蚙蚚蚛蚜蚝蚞蚟蚠蚡蚢蚣蚤蚥蚦蚧蚨蚩蚪蚫蚬蚭蚮蚯蚰蚱蚲蚳蚴蚵蚶蚷蚸蚹蚺蚻蚼蚽蚾蚿蛀蛁蛂蛃蛄蛅蛆蛇蛈蛉蛊蛋蛌蛍蛎蛏蛐蛑蛒蛓蛔蛕蛖蛗蛘蛙蛚蛛蛜蛝蛞蛟蛠蛡蛢蛣蛤蛥蛦蛧蛨蛩蛪蛫蛬蛭蛮蛯蛰蛱蛲蛳蛴蛵蛶蛷蛸蛹蛺蛻蛼蛽蛾蛿蜀蜁蜂蜃蜄蜅蜆蜇蜈蜉蜊蜋蜌蜍蜎蜏蜐蜑蜒蜓蜔蜕蜖蜗蜘蜙蜚蜛蜜蜝蜞蜟蜠蜡蜢蜣蜤蜥蜦蜧蜨蜩蜪蜫蜬蜭蜮蜯蜰蜱蜲蜳蜴蜵蜶蜷蜸蜹蜺蜻蜼蜽蜾蜿蝀蝁蝂蝃蝄蝅蝆蝇蝈蝉蝊蝋蝌蝍蝎蝏蝐蝑蝒蝓蝔蝕蝖蝗蝘蝙蝚蝛蝜蝝蝞蝟蝠蝡蝢蝣蝤蝥蝦蝧蝨蝩蝪蝫蝬蝭蝮蝯蝰蝱蝲蝳蝴蝵蝶蝷蝸蝹蝺蝻蝼蝽蝾蝿螀螁螂螃螄螅螆螇螈螉螊螋螌融螎螏螐螑螒螓螔螕螖螗螘螙螚螛螜螝螞螟螠螡螢螣螤螥螦螧螨螩螪螫螬螭螮螯螰螱螲螳螴螵螶螷螸螹螺螻螼螽螾螿蟀蟁蟂蟃蟄蟅蟆蟇蟈蟉蟊蟋蟌蟍蟎蟏蟐蟑蟒蟓蟔蟕蟖蟗蟘蟙蟚蟛蟜蟝蟞蟟蟠蟡蟢蟣蟤蟥蟦蟧蟨蟩蟪蟫蟬蟭蟮蟯蟰蟱蟲蟳蟴蟵蟶蟷蟸蟹蟺蟻蟼蟽蟾蟿蠀蠁蠂蠃蠄蠅蠆蠇蠈蠉蠊蠋蠌蠍蠎蠏蠐蠑蠒蠓蠔蠕蠖蠗蠘蠙蠚蠛蠜蠝蠞蠟蠠蠡蠢蠣蠤蠥蠦蠧蠨蠩蠪蠫蠬蠭蠮蠯蠰蠱蠲蠳蠴蠵蠶蠷蠸蠹蠺蠻蠼蠽蠾蠿血衁衂衃衄衅衆衇衈衉衊衋行衍衎衏衐衑衒術衔衕衖街衘衙衚衛衜衝衞衟衠衡衢衣衤补衦衧表衩衪衫衬衭衮衯衰衱衲衳衴衵衶衷衸衹衺衻衼衽衾衿袀袁袂袃袄袅袆袇袈袉袊袋袌袍袎袏袐袑袒袓袔袕袖袗袘袙袚袛袜袝袞袟袠袡袢袣袤袥袦袧袨袩袪被袬袭袮袯袰袱袲袳袴袵袶袷袸袹袺袻袼袽袾袿裀裁裂裃裄装裆裇裈裉裊裋裌裍裎裏裐裑裒裓裔裕裖裗裘裙裚裛補裝裞裟裠裡裢裣裤裥裦裧裨裩裪裫裬裭裮裯裰裱裲裳裴裵裶裷裸裹裺裻裼製裾裿褀褁褂褃褄褅褆複褈褉褊褋褌褍褎褏褐褑褒褓褔褕褖褗褘褙褚褛褜褝褞褟褠褡褢褣褤褥褦褧褨褩褪褫褬褭褮褯褰褱褲褳褴褵褶褷褸褹褺褻褼褽褾褿襀襁襂襃襄襅襆襇襈襉襊襋襌襍襎襏襐襑襒襓襔襕襖襗襘襙襚襛襜襝襞襟襠襡襢襣襤襥襦襧襨襩襪襫襬襭襮襯襰襱襲襳襴襵襶襷襸襹襺襻襼襽襾西覀要覂覃覄覅覆覇覈覉覊見覌覍覎規覐覑覒覓覔覕視覗覘覙覚覛覜覝覞覟覠覡覢覣覤覥覦覧覨覩親覫覬覭覮覯覰覱覲観覴覵覶覷覸覹覺覻覼覽覾覿觀见观觃规觅视觇览觉觊觋觌觍觎觏觐觑角觓觔觕觖觗觘觙觚觛觜觝觞觟觠觡觢解觤觥触觧觨觩觪觫觬觭觮觯觰觱觲觳觴觵觶觷觸觹觺觻觼觽觾觿言訁訂訃訄訅訆訇計訉訊訋訌訍討訏訐訑訒訓訔訕訖託記訙訚訛訜訝訞訟訠訡訢訣訤訥訦訧訨訩訪訫訬設訮訯訰許訲訳訴訵訶訷訸訹診註証訽訾訿詀詁詂詃詄詅詆詇詈詉詊詋詌詍詎詏詐詑詒詓詔評詖詗詘詙詚詛詜詝詞詟詠詡詢詣詤詥試詧詨詩詪詫詬詭詮詯詰話該詳詴詵詶詷詸詹詺詻詼詽詾詿誀誁誂誃誄誅誆誇誈誉誊誋誌認誎誏誐誑誒誓誔誕誖誗誘誙誚誛誜誝語誟誠誡誢誣誤誥誦誧誨誩說誫説読誮誯誰誱課誳誴誵誶誷誸誹誺誻誼誽誾調諀諁諂諃諄諅諆談諈諉諊請諌諍諎諏諐諑諒諓諔諕論諗諘諙諚諛諜諝諞諟諠諡諢諣諤諥諦諧諨諩諪諫諬諭諮諯諰諱諲諳諴諵諶諷諸諹諺諻諼諽諾諿謀謁謂謃謄謅謆謇謈謉謊謋謌謍謎謏謐謑謒謓謔謕謖謗謘謙謚講謜謝謞謟謠謡謢謣謤謥謦謧謨謩謪謫謬謭謮謯謰謱謲謳謴謵謶謷謸謹謺謻謼謽謾謿譀譁譂譃譄譅譆譇譈證譊譋譌譍譎譏譐譑譒譓譔譕譖譗識譙譚譛譜譝譞譟譠譡譢譣譤譥警譧譨譩譪譫譬譭譮譯議譱譲譳譴譵譶護譸譹譺譻譼譽譾譿讀讁讂讃讄讅讆讇讈讉變讋讌讍讎讏讐讑讒讓讔讕讖讗讘讙讚讛讜讝讞讟讠计订讣认讥讦讧讨让讪讫讬训议讯记讱讲讳讴讵讶讷许讹论讻讼讽设访诀证诂诃评诅识诇诈诉诊诋诌词诎诏诐译诒诓诔试诖诗诘诙诚诛诜话诞诟诠诡询诣诤该详诧诨诩诪诫诬语诮误诰诱诲诳说诵诶请诸诹诺读诼诽课诿谀谁谂调谄谅谆谇谈谉谊谋谌谍谎谏谐谑谒谓谔谕谖谗谘谙谚谛谜谝谞谟谠谡谢谣谤谥谦谧谨谩谪谫谬谭谮谯谰谱谲谳谴谵谶谷谸谹谺谻谼谽谾谿豀豁豂豃豄豅豆豇豈豉豊豋豌豍豎豏豐豑豒豓豔豕豖豗豘豙豚豛豜豝豞豟豠象豢豣豤豥豦豧豨豩豪豫豬豭豮豯豰豱豲豳豴豵豶豷豸豹豺豻豼豽豾豿貀貁貂貃貄貅貆貇貈貉貊貋貌貍貎貏貐貑貒貓貔貕貖貗貘貙貚貛貜貝貞貟負財貢貣貤貥貦貧貨販貪貫責貭貮貯貰貱貲貳貴貵貶買貸貹貺費貼貽貾貿賀賁賂賃賄賅賆資賈賉賊賋賌賍賎賏賐賑賒賓賔賕賖賗賘賙賚賛賜賝賞賟賠賡賢賣賤賥賦賧賨賩質賫賬賭賮賯賰賱賲賳賴賵賶賷賸賹賺賻購賽賾賿贀贁贂贃贄贅贆贇贈贉贊贋贌贍贎贏贐贑贒贓贔贕贖贗贘贙贚贛贜贝贞负贠贡财责贤败账货质贩贪贫贬购贮贯贰贱贲贳贴贵贶贷贸费贺贻贼贽贾贿赀赁赂赃资赅赆赇赈赉赊赋赌赍赎赏赐赑赒赓赔赕赖赗赘赙赚赛赜赝赞赟赠赡赢赣赤赥赦赧赨赩赪赫赬赭赮赯走赱赲赳赴赵赶起赸赹赺赻赼赽赾赿趀趁趂趃趄超趆趇趈趉越趋趌趍趎趏趐趑趒趓趔趕趖趗趘趙趚趛趜趝趞趟趠趡趢趣趤趥趦趧趨趩趪趫趬趭趮趯趰趱趲足趴趵趶趷趸趹趺趻趼趽趾趿跀跁跂跃跄跅跆跇跈跉跊跋跌跍跎跏跐跑跒跓跔跕跖跗跘跙跚跛跜距跞跟跠跡跢跣跤跥跦跧跨跩跪跫跬跭跮路跰跱跲跳跴践跶跷跸跹跺跻跼跽跾跿踀踁踂踃踄踅踆踇踈踉踊踋踌踍踎踏踐踑踒踓踔踕踖踗踘踙踚踛踜踝踞踟踠踡踢踣踤踥踦踧踨踩踪踫踬踭踮踯踰踱踲踳踴踵踶踷踸踹踺踻踼踽踾踿蹀蹁蹂蹃蹄蹅蹆蹇蹈蹉蹊蹋蹌蹍蹎蹏蹐蹑蹒蹓蹔蹕蹖蹗蹘蹙蹚蹛蹜蹝蹞蹟蹠蹡蹢蹣蹤蹥蹦蹧蹨蹩蹪蹫蹬蹭蹮蹯蹰蹱蹲蹳蹴蹵蹶蹷蹸蹹蹺蹻蹼蹽蹾蹿躀躁躂躃躄躅躆躇躈躉躊躋躌躍躎躏躐躑躒躓躔躕躖躗躘躙躚躛躜躝躞躟躠躡躢躣躤躥躦躧躨躩躪身躬躭躮躯躰躱躲躳躴躵躶躷躸躹躺躻躼躽躾躿軀軁軂軃軄軅軆軇軈軉車軋軌軍軎軏軐軑軒軓軔軕軖軗軘軙軚軛軜軝軞軟軠軡転軣軤軥軦軧軨軩軪軫軬軭軮軯軰軱軲軳軴軵軶軷軸軹軺軻軼軽軾軿輀輁輂較輄輅輆輇輈載輊輋輌輍輎輏輐輑輒輓輔輕輖輗輘輙輚輛輜輝輞輟輠輡輢輣輤輥輦輧輨輩輪輫輬輭輮輯輰輱輲輳輴輵輶輷輸輹輺輻輼輽輾輿轀轁轂轃轄轅轆轇轈轉轊轋轌轍轎轏轐轑轒轓轔轕轖轗轘轙轚轛轜轝轞轟轠轡轢轣轤轥车轧轨轩轪轫转轭轮软轰轱轲轳轴轵轶轷轸轹轺轻轼载轾轿辀辁辂较辄辅辆辇辈辉辊辋辌辍辎辏辐辑辒输辔辕辖辗辘辙辚辛辜辝辞辟辠辡辢辣辤辥辦辧辨辩辪辫辬辭辮辯辰辱農辳辴辵辶辷辸边辺辻込辽达辿迀迁迂迃迄迅迆过迈迉迊迋迌迍迎迏运近迒迓返迕迖迗还这迚进远违连迟迠迡迢迣迤迥迦迧迨迩迪迫迬迭迮迯述迱迲迳迴迵迶迷迸迹迺迻迼追迾迿退送适逃逄逅逆逇逈选逊逋逌逍逎透逐逑递逓途逕逖逗逘這通逛逜逝逞速造逡逢連逤逥逦逧逨逩逪逫逬逭逮逯逰週進逳逴逵逶逷逸逹逺逻逼逽逾逿遀遁遂遃遄遅遆遇遈遉遊運遌遍過遏遐遑遒道達違遖遗遘遙遚遛遜遝遞遟遠遡遢遣遤遥遦遧遨適遪遫遬遭遮遯遰遱遲遳遴遵遶遷選遹遺遻遼遽遾避邀邁邂邃還邅邆邇邈邉邊邋邌邍邎邏邐邑邒邓邔邕邖邗邘邙邚邛邜邝邞邟邠邡邢那邤邥邦邧邨邩邪邫邬邭邮邯邰邱邲邳邴邵邶邷邸邹邺邻邼邽邾邿郀郁郂郃郄郅郆郇郈郉郊郋郌郍郎郏郐郑郒郓郔郕郖郗郘郙郚郛郜郝郞郟郠郡郢郣郤郥郦郧部郩郪郫郬郭郮郯郰郱郲郳郴郵郶郷郸郹郺郻郼都郾郿鄀鄁鄂鄃鄄鄅鄆鄇鄈鄉鄊鄋鄌鄍鄎鄏鄐鄑鄒鄓鄔鄕鄖鄗鄘鄙鄚鄛鄜鄝鄞鄟鄠鄡鄢鄣鄤鄥鄦鄧鄨鄩鄪鄫鄬鄭鄮鄯鄰鄱鄲鄳鄴鄵鄶鄷鄸鄹鄺鄻鄼鄽鄾鄿酀酁酂酃酄酅酆酇酈酉酊酋酌配酎酏酐酑酒酓酔酕酖酗酘酙酚酛酜酝酞酟酠酡酢酣酤酥酦酧酨酩酪酫酬酭酮酯酰酱酲酳酴酵酶酷酸酹酺酻酼酽酾酿醀醁醂醃醄醅醆醇醈醉醊醋醌醍醎醏醐醑醒醓醔醕醖醗醘醙醚醛醜醝醞醟醠醡醢醣醤醥醦醧醨醩醪醫醬醭醮醯醰醱醲醳醴醵醶醷醸醹醺醻醼醽醾醿釀釁釂釃釄釅釆采釈釉释釋里重野量釐金釒釓釔釕釖釗釘釙釚釛釜針釞釟釠釡釢釣釤釥釦釧釨釩釪釫釬釭釮釯釰釱釲釳釴釵釶釷釸釹釺釻釼釽釾釿鈀鈁鈂鈃鈄鈅鈆鈇鈈鈉鈊鈋鈌鈍鈎鈏鈐鈑鈒鈓鈔鈕鈖鈗鈘鈙鈚鈛鈜鈝鈞鈟鈠鈡鈢鈣鈤鈥鈦鈧鈨鈩鈪鈫鈬鈭鈮鈯鈰鈱鈲鈳鈴鈵鈶鈷鈸鈹鈺鈻鈼鈽鈾鈿鉀鉁鉂鉃鉄鉅鉆鉇鉈鉉鉊鉋鉌鉍鉎鉏鉐鉑鉒鉓鉔鉕鉖鉗鉘鉙鉚鉛鉜鉝鉞鉟鉠鉡鉢鉣鉤鉥鉦鉧鉨鉩鉪鉫鉬鉭鉮鉯鉰鉱鉲鉳鉴鉵鉶鉷鉸鉹鉺鉻鉼鉽鉾鉿銀銁銂銃銄銅銆銇銈銉銊銋銌銍銎銏銐銑銒銓銔銕銖銗銘銙銚銛銜銝銞銟銠銡銢銣銤銥銦銧銨銩銪銫銬銭銮銯銰銱銲銳銴銵銶銷銸銹銺銻銼銽銾銿鋀鋁鋂鋃鋄鋅鋆鋇鋈鋉鋊鋋鋌鋍鋎鋏鋐鋑鋒鋓鋔鋕鋖鋗鋘鋙鋚鋛鋜鋝鋞鋟鋠鋡鋢鋣鋤鋥鋦鋧鋨鋩鋪鋫鋬鋭鋮鋯鋰鋱鋲鋳鋴鋵鋶鋷鋸鋹鋺鋻鋼鋽鋾鋿錀錁錂錃錄錅錆錇錈錉錊錋錌錍錎錏錐錑錒錓錔錕錖錗錘錙錚錛錜錝錞錟錠錡錢錣錤錥錦錧錨錩錪錫錬錭錮錯錰錱録錳錴錵錶錷錸錹錺錻錼錽錾錿鍀鍁鍂鍃鍄鍅鍆鍇鍈鍉鍊鍋鍌鍍鍎鍏鍐鍑鍒鍓鍔鍕鍖鍗鍘鍙鍚鍛鍜鍝鍞鍟鍠鍡鍢鍣鍤鍥鍦鍧鍨鍩鍪鍫鍬鍭鍮鍯鍰鍱鍲鍳鍴鍵鍶鍷鍸鍹鍺鍻鍼鍽鍾鍿鎀鎁鎂鎃鎄鎅鎆鎇鎈鎉鎊鎋鎌鎍鎎鎏鎐鎑鎒鎓鎔鎕鎖鎗鎘鎙鎚鎛鎜鎝鎞鎟鎠鎡鎢鎣鎤鎥鎦鎧鎨鎩鎪鎫鎬鎭鎮鎯鎰鎱鎲鎳鎴鎵鎶鎷鎸鎹鎺鎻鎼鎽鎾鎿鏀鏁鏂鏃鏄鏅鏆鏇鏈鏉鏊鏋鏌鏍鏎鏏鏐鏑鏒鏓鏔鏕鏖鏗鏘鏙鏚鏛鏜鏝鏞鏟鏠鏡鏢鏣鏤鏥鏦鏧鏨鏩鏪鏫鏬鏭鏮鏯鏰鏱鏲鏳鏴鏵鏶鏷鏸鏹鏺鏻鏼鏽鏾鏿鐀鐁鐂鐃鐄鐅鐆鐇鐈鐉鐊鐋鐌鐍鐎鐏鐐鐑鐒鐓鐔鐕鐖鐗鐘鐙鐚鐛鐜鐝鐞鐟鐠鐡鐢鐣鐤鐥鐦鐧鐨鐩鐪鐫鐬鐭鐮鐯鐰鐱鐲鐳鐴鐵鐶鐷鐸鐹鐺鐻鐼鐽鐾鐿鑀鑁鑂鑃鑄鑅鑆鑇鑈鑉鑊鑋鑌鑍鑎鑏鑐鑑鑒鑓鑔鑕鑖鑗鑘鑙鑚鑛鑜鑝鑞鑟鑠鑡鑢鑣鑤鑥鑦鑧鑨鑩鑪鑫鑬鑭鑮鑯鑰鑱鑲鑳鑴鑵鑶鑷鑸鑹鑺鑻鑼鑽鑾鑿钀钁钂钃钄钅钆钇针钉钊钋钌钍钎钏钐钑钒钓钔钕钖钗钘钙钚钛钜钝钞钟钠钡钢钣钤钥钦钧钨钩钪钫钬钭钮钯钰钱钲钳钴钵钶钷钸钹钺钻钼钽钾钿铀铁铂铃铄铅铆铇铈铉铊铋铌铍铎铏铐铑铒铓铔铕铖铗铘铙铚铛铜铝铞铟铠铡铢铣铤铥铦铧铨铩铪铫铬铭铮铯铰铱铲铳铴铵银铷铸铹铺铻铼铽链铿销锁锂锃锄锅锆锇锈锉锊锋锌锍锎锏锐锑锒锓锔锕锖锗锘错锚锛锜锝锞锟锠锡锢锣锤锥锦锧锨锩锪锫锬锭键锯锰锱锲锳锴锵锶锷锸锹锺锻锼锽锾锿镀镁镂镃镄镅镆镇镈镉镊镋镌镍镎镏镐镑镒镓镔镕镖镗镘镙镚镛镜镝镞镟镠镡镢镣镤镥镦镧镨镩镪镫镬镭镮镯镰镱镲镳镴镵镶長镸镹镺镻镼镽镾长門閁閂閃閄閅閆閇閈閉閊開閌閍閎閏閐閑閒間閔閕閖閗閘閙閚閛閜閝閞閟閠閡関閣閤閥閦閧閨閩閪閫閬閭閮閯閰閱閲閳閴閵閶閷閸閹閺閻閼閽閾閿闀闁闂闃闄闅闆闇闈闉闊闋闌闍闎闏闐闑闒闓闔闕闖闗闘闙闚闛關闝闞闟闠闡闢闣闤闥闦闧门闩闪闫闬闭问闯闰闱闲闳间闵闶闷闸闹闺闻闼闽闾闿阀阁阂阃阄阅阆阇阈阉阊阋阌阍阎阏阐阑阒阓阔阕阖阗阘阙阚阛阜阝阞队阠阡阢阣阤阥阦阧阨阩阪阫阬阭阮阯阰阱防阳阴阵阶阷阸阹阺阻阼阽阾阿陀陁陂陃附际陆陇陈陉陊陋陌降陎陏限陑陒陓陔陕陖陗陘陙陚陛陜陝陞陟陠陡院陣除陥陦陧陨险陪陫陬陭陮陯陰陱陲陳陴陵陶陷陸陹険陻陼陽陾陿隀隁隂隃隄隅隆隇隈隉隊隋隌隍階随隐隑隒隓隔隕隖隗隘隙隚際障隝隞隟隠隡隢隣隤隥隦隧隨隩險隫隬隭隮隯隰隱隲隳隴隵隶隷隸隹隺隻隼隽难隿雀雁雂雃雄雅集雇雈雉雊雋雌雍雎雏雐雑雒雓雔雕雖雗雘雙雚雛雜雝雞雟雠雡離難雤雥雦雧雨雩雪雫雬雭雮雯雰雱雲雳雴雵零雷雸雹雺電雼雽雾雿需霁霂霃霄霅霆震霈霉霊霋霌霍霎霏霐霑霒霓霔霕霖霗霘霙霚霛霜霝霞霟霠霡霢霣霤霥霦霧霨霩霪霫霬霭霮霯霰霱露霳霴霵霶霷霸霹霺霻霼霽霾霿靀靁靂靃靄靅靆靇靈靉靊靋靌靍靎靏靐靑青靓靔靕靖靗靘静靚靛靜靝非靟靠靡面靣靤靥靦靧靨革靪靫靬靭靮靯靰靱靲靳靴靵靶靷靸靹靺靻靼靽靾靿鞀鞁鞂鞃鞄鞅鞆鞇鞈鞉鞊鞋鞌鞍鞎鞏鞐鞑鞒鞓鞔鞕鞖鞗鞘鞙鞚鞛鞜鞝鞞鞟鞠鞡鞢鞣鞤鞥鞦鞧鞨鞩鞪鞫鞬鞭鞮鞯鞰鞱鞲鞳鞴鞵鞶鞷鞸鞹鞺鞻鞼鞽鞾鞿韀韁韂韃韄韅韆韇韈韉韊韋韌韍韎韏韐韑韒韓韔韕韖韗韘韙韚韛韜韝韞韟韠韡韢韣韤韥韦韧韨韩韪韫韬韭韮韯韰韱韲音韴韵韶韷韸韹韺韻韼韽韾響頀頁頂頃頄項順頇須頉頊頋頌頍頎頏預頑頒頓頔頕頖頗領頙頚頛頜頝頞頟頠頡頢頣頤頥頦頧頨頩頪頫頬頭頮頯頰頱頲頳頴頵頶頷頸頹頺頻頼頽頾頿顀顁顂顃顄顅顆顇顈顉顊顋題額顎顏顐顑顒顓顔顕顖顗願顙顚顛顜顝類顟顠顡顢顣顤顥顦顧顨顩顪顫顬顭顮顯顰顱顲顳顴页顶顷顸项顺须顼顽顾顿颀颁颂颃预颅领颇颈颉颊颋颌颍颎颏颐频颒颓颔颕颖颗题颙颚颛颜额颞颟颠颡颢颣颤颥颦颧風颩颪颫颬颭颮颯颰颱颲颳颴颵颶颷颸颹颺颻颼颽颾颿飀飁飂飃飄飅飆飇飈飉飊飋飌飍风飏飐飑飒飓飔飕飖飗飘飙飚飛飜飝飞食飠飡飢飣飤飥飦飧飨飩飪飫飬飭飮飯飰飱飲飳飴飵飶飷飸飹飺飻飼飽飾飿餀餁餂餃餄餅餆餇餈餉養餋餌餍餎餏餐餑餒餓餔餕餖餗餘餙餚餛餜餝餞餟餠餡餢餣餤餥餦餧館餩餪餫餬餭餮餯餰餱餲餳餴餵餶餷餸餹餺餻餼餽餾餿饀饁饂饃饄饅饆饇饈饉饊饋饌饍饎饏饐饑饒饓饔饕饖饗饘饙饚饛饜饝饞饟饠饡饢饣饤饥饦饧饨饩饪饫饬饭饮饯饰饱饲饳饴饵饶饷饸饹饺饻饼饽饾饿馀馁馂馃馄馅馆馇馈馉馊馋馌馍馎馏馐馑馒馓馔馕首馗馘香馚馛馜馝馞馟馠馡馢馣馤馥馦馧馨馩馪馫馬馭馮馯馰馱馲馳馴馵馶馷馸馹馺馻馼馽馾馿駀駁駂駃駄駅駆駇駈駉駊駋駌駍駎駏駐駑駒駓駔駕駖駗駘駙駚駛駜駝駞駟駠駡駢駣駤駥駦駧駨駩駪駫駬駭駮駯駰駱駲駳駴駵駶駷駸駹駺駻駼駽駾駿騀騁騂騃騄騅騆騇騈騉騊騋騌騍騎騏騐騑騒験騔騕騖騗騘騙騚騛騜騝騞騟騠騡騢騣騤騥騦騧騨騩騪騫騬騭騮騯騰騱騲騳騴騵騶騷騸騹騺騻騼騽騾騿驀驁驂驃驄驅驆驇驈驉驊驋驌驍驎驏驐驑驒驓驔驕驖驗驘驙驚驛驜驝驞驟驠驡驢驣驤驥驦驧驨驩驪驫马驭驮驯驰驱驲驳驴驵驶驷驸驹驺驻驼驽驾驿骀骁骂骃骄骅骆骇骈骉骊骋验骍骎骏骐骑骒骓骔骕骖骗骘骙骚骛骜骝骞骟骠骡骢骣骤骥骦骧骨骩骪骫骬骭骮骯骰骱骲骳骴骵骶骷骸骹骺骻骼骽骾骿髀髁髂髃髄髅髆髇髈髉髊髋髌髍髎髏髐髑髒髓體髕髖髗高髙髚髛髜髝髞髟髠髡髢髣髤髥髦髧髨髩髪髫髬髭髮髯髰髱髲髳髴髵髶髷髸髹髺髻髼髽髾髿鬀鬁鬂鬃鬄鬅鬆鬇鬈鬉鬊鬋鬌鬍鬎鬏鬐鬑鬒鬓鬔鬕鬖鬗鬘鬙鬚鬛鬜鬝鬞鬟鬠鬡鬢鬣鬤鬥鬦鬧鬨鬩鬪鬫鬬鬭鬮鬯鬰鬱鬲鬳鬴鬵鬶鬷鬸鬹鬺鬻鬼鬽鬾鬿魀魁魂魃魄魅魆魇魈魉魊魋魌魍魎魏魐魑魒魓魔魕魖魗魘魙魚魛魜魝魞魟魠魡魢魣魤魥魦魧魨魩魪魫魬魭魮魯魰魱魲魳魴魵魶魷魸魹魺魻魼魽魾魿鮀鮁鮂鮃鮄鮅鮆鮇鮈鮉鮊鮋鮌鮍鮎鮏鮐鮑鮒鮓鮔鮕鮖鮗鮘鮙鮚鮛鮜鮝鮞鮟鮠鮡鮢鮣鮤鮥鮦鮧鮨鮩鮪鮫鮬鮭鮮鮯鮰鮱鮲鮳鮴鮵鮶鮷鮸鮹鮺鮻鮼鮽鮾鮿鯀鯁鯂鯃鯄鯅鯆鯇鯈鯉鯊鯋鯌鯍鯎鯏鯐鯑鯒鯓鯔鯕鯖鯗鯘鯙鯚鯛鯜鯝鯞鯟鯠鯡鯢鯣鯤鯥鯦鯧鯨鯩鯪鯫鯬鯭鯮鯯鯰鯱鯲鯳鯴鯵鯶鯷鯸鯹鯺鯻鯼鯽鯾鯿鰀鰁鰂鰃鰄鰅鰆鰇鰈鰉鰊鰋鰌鰍鰎鰏鰐鰑鰒鰓鰔鰕鰖鰗鰘鰙鰚鰛鰜鰝鰞鰟鰠鰡鰢鰣鰤鰥鰦鰧鰨鰩鰪鰫鰬鰭鰮鰯鰰鰱鰲鰳鰴鰵鰶鰷鰸鰹鰺鰻鰼鰽鰾鰿鱀鱁鱂鱃鱄鱅鱆鱇鱈鱉鱊鱋鱌鱍鱎鱏鱐鱑鱒鱓鱔鱕鱖鱗鱘鱙鱚鱛鱜鱝鱞鱟鱠鱡鱢鱣鱤鱥鱦鱧鱨鱩鱪鱫鱬鱭鱮鱯鱰鱱鱲鱳鱴鱵鱶鱷鱸鱹鱺鱻鱼鱽鱾鱿鲀鲁鲂鲃鲄鲅鲆鲇鲈鲉鲊鲋鲌鲍鲎鲏鲐鲑鲒鲓鲔鲕鲖鲗鲘鲙鲚鲛鲜鲝鲞鲟鲠鲡鲢鲣鲤鲥鲦鲧鲨鲩鲪鲫鲬鲭鲮鲯鲰鲱鲲鲳鲴鲵鲶鲷鲸鲹鲺鲻鲼鲽鲾鲿鳀鳁鳂鳃鳄鳅鳆鳇鳈鳉鳊鳋鳌鳍鳎鳏鳐鳑鳒鳓鳔鳕鳖鳗鳘鳙鳚鳛鳜鳝鳞鳟鳠鳡鳢鳣鳤鳥鳦鳧鳨鳩鳪鳫鳬鳭鳮鳯鳰鳱鳲鳳鳴鳵鳶鳷鳸鳹鳺鳻鳼鳽鳾鳿鴀鴁鴂鴃鴄鴅鴆鴇鴈鴉鴊鴋鴌鴍鴎鴏鴐鴑鴒鴓鴔鴕鴖鴗鴘鴙鴚鴛鴜鴝鴞鴟鴠鴡鴢鴣鴤鴥鴦鴧鴨鴩鴪鴫鴬鴭鴮鴯鴰鴱鴲鴳鴴鴵鴶鴷鴸鴹鴺鴻鴼鴽鴾鴿鵀鵁鵂鵃鵄鵅鵆鵇鵈鵉鵊鵋鵌鵍鵎鵏鵐鵑鵒鵓鵔鵕鵖鵗鵘鵙鵚鵛鵜鵝鵞鵟鵠鵡鵢鵣鵤鵥鵦鵧鵨鵩鵪鵫鵬鵭鵮鵯鵰鵱鵲鵳鵴鵵鵶鵷鵸鵹鵺鵻鵼鵽鵾鵿鶀鶁鶂鶃鶄鶅鶆鶇鶈鶉鶊鶋鶌鶍鶎鶏鶐鶑鶒鶓鶔鶕鶖鶗鶘鶙鶚鶛鶜鶝鶞鶟鶠鶡鶢鶣鶤鶥鶦鶧鶨鶩鶪鶫鶬鶭鶮鶯鶰鶱鶲鶳鶴鶵鶶鶷鶸鶹鶺鶻鶼鶽鶾鶿鷀鷁鷂鷃鷄鷅鷆鷇鷈鷉鷊鷋鷌鷍鷎鷏鷐鷑鷒鷓鷔鷕鷖鷗鷘鷙鷚鷛鷜鷝鷞鷟鷠鷡鷢鷣鷤鷥鷦鷧鷨鷩鷪鷫鷬鷭鷮鷯鷰鷱鷲鷳鷴鷵鷶鷷鷸鷹鷺鷻鷼鷽鷾鷿鸀鸁鸂鸃鸄鸅鸆鸇鸈鸉鸊鸋鸌鸍鸎鸏鸐鸑鸒鸓鸔鸕鸖鸗鸘鸙鸚鸛鸜鸝鸞鸟鸠鸡鸢鸣鸤鸥鸦鸧鸨鸩鸪鸫鸬鸭鸮鸯鸰鸱鸲鸳鸴鸵鸶鸷鸸鸹鸺鸻鸼鸽鸾鸿鹀鹁鹂鹃鹄鹅鹆鹇鹈鹉鹊鹋鹌鹍鹎鹏鹐鹑鹒鹓鹔鹕鹖鹗鹘鹙鹚鹛鹜鹝鹞鹟鹠鹡鹢鹣鹤鹥鹦鹧鹨鹩鹪鹫鹬鹭鹮鹯鹰鹱鹲鹳鹴鹵鹶鹷鹸鹹鹺鹻鹼鹽鹾鹿麀麁麂麃麄麅麆麇麈麉麊麋麌麍麎麏麐麑麒麓麔麕麖麗麘麙麚麛麜麝麞麟麠麡麢麣麤麥麦麧麨麩麪麫麬麭麮麯麰麱麲麳麴麵麶麷麸麹麺麻麼麽麾麿黀黁黂黃黄黅黆黇黈黉黊黋黌黍黎黏黐黑黒黓黔黕黖黗默黙黚黛黜黝點黟黠黡黢黣黤黥黦黧黨黩黪黫黬黭黮黯黰黱黲黳黴黵黶黷黸黹黺黻黼黽黾黿鼀鼁鼂鼃鼄鼅鼆鼇鼈鼉鼊鼋鼌鼍鼎鼏鼐鼑鼒鼓鼔鼕鼖鼗鼘鼙鼚鼛鼜鼝鼞鼟鼠鼡鼢鼣鼤鼥鼦鼧鼨鼩鼪鼫鼬鼭鼮鼯鼰鼱鼲鼳鼴鼵鼶鼷鼸鼹鼺鼻鼼鼽鼾鼿齀齁齂齃齄齅齆齇齈齉齊齋齌齍齎齏齐齑齒齓齔齕齖齗齘齙齚齛齜齝齞齟齠齡齢齣齤齥齦齧齨齩齪齫齬齭齮齯齰齱齲齳齴齵齶齷齸齹齺齻齼齽齾齿龀龁龂龃龄龅龆龇龈龉龊龋龌龍龎龏龐龑龒龓龔龕龖龗龘龙龚龛龜龝龞龟龠龡龢龣龤龥龦龧龨龩龪龫龬龭龮龯龰龱龲龳龴龵龶龷龸龹龺龻龼龽龾龿鿀鿁鿂鿃鿄鿅鿆鿇鿈鿉鿊鿋鿌ꀀꀁꀂꀃꀄꀅꀆꀇꀈꀉꀊꀋꀌꀍꀎꀏꀐꀑꀒꀓꀔꀕꀖꀗꀘꀙꀚꀛꀜꀝꀞꀟꀠꀡꀢꀣꀤꀥꀦꀧꀨꀩꀪꀫꀬꀭꀮꀯꀰꀱꀲꀳꀴꀵꀶꀷꀸꀹꀺꀻꀼꀽꀾꀿꁀꁁꁂꁃꁄꁅꁆꁇꁈꁉꁊꁋꁌꁍꁎꁏꁐꁑꁒꁓꁔꁕꁖꁗꁘꁙꁚꁛꁜꁝꁞꁟꁠꁡꁢꁣꁤꁥꁦꁧꁨꁩꁪꁫꁬꁭꁮꁯꁰꁱꁲꁳꁴꁵꁶꁷꁸꁹꁺꁻꁼꁽꁾꁿꂀꂁꂂꂃꂄꂅꂆꂇꂈꂉꂊꂋꂌꂍꂎꂏꂐꂑꂒꂓꂔꂕꂖꂗꂘꂙꂚꂛꂜꂝꂞꂟꂠꂡꂢꂣꂤꂥꂦꂧꂨꂩꂪꂫꂬꂭꂮꂯꂰꂱꂲꂳꂴꂵꂶꂷꂸꂹꂺꂻꂼꂽꂾꂿꃀꃁꃂꃃꃄꃅꃆꃇꃈꃉꃊꃋꃌꃍꃎꃏꃐꃑꃒꃓꃔꃕꃖꃗꃘꃙꃚꃛꃜꃝꃞꃟꃠꃡꃢꃣꃤꃥꃦꃧꃨꃩꃪꃫꃬꃭꃮꃯꃰꃱꃲꃳꃴꃵꃶꃷꃸꃹꃺꃻꃼꃽꃾꃿꄀꄁꄂꄃꄄꄅꄆꄇꄈꄉꄊꄋꄌꄍꄎꄏꄐꄑꄒꄓꄔꄕꄖꄗꄘꄙꄚꄛꄜꄝꄞꄟꄠꄡꄢꄣꄤꄥꄦꄧꄨꄩꄪꄫꄬꄭꄮꄯꄰꄱꄲꄳꄴꄵꄶꄷꄸꄹꄺꄻꄼꄽꄾꄿꅀꅁꅂꅃꅄꅅꅆꅇꅈꅉꅊꅋꅌꅍꅎꅏꅐꅑꅒꅓꅔꅕꅖꅗꅘꅙꅚꅛꅜꅝꅞꅟꅠꅡꅢꅣꅤꅥꅦꅧꅨꅩꅪꅫꅬꅭꅮꅯꅰꅱꅲꅳꅴꅵꅶꅷꅸꅹꅺꅻꅼꅽꅾꅿꆀꆁꆂꆃꆄꆅꆆꆇꆈꆉꆊꆋꆌꆍꆎꆏꆐꆑꆒꆓꆔꆕꆖꆗꆘꆙꆚꆛꆜꆝꆞꆟꆠꆡꆢꆣꆤꆥꆦꆧꆨꆩꆪꆫꆬꆭꆮꆯꆰꆱꆲꆳꆴꆵꆶꆷꆸꆹꆺꆻꆼꆽꆾꆿꇀꇁꇂꇃꇄꇅꇆꇇꇈꇉꇊꇋꇌꇍꇎꇏꇐꇑꇒꇓꇔꇕꇖꇗꇘꇙꇚꇛꇜꇝꇞꇟꇠꇡꇢꇣꇤꇥꇦꇧꇨꇩꇪꇫꇬꇭꇮꇯꇰꇱꇲꇳꇴꇵꇶꇷꇸꇹꇺꇻꇼꇽꇾꇿꈀꈁꈂꈃꈄꈅꈆꈇꈈꈉꈊꈋꈌꈍꈎꈏꈐꈑꈒꈓꈔꈕꈖꈗꈘꈙꈚꈛꈜꈝꈞꈟꈠꈡꈢꈣꈤꈥꈦꈧꈨꈩꈪꈫꈬꈭꈮꈯꈰꈱꈲꈳꈴꈵꈶꈷꈸꈹꈺꈻꈼꈽꈾꈿꉀꉁꉂꉃꉄꉅꉆꉇꉈꉉꉊꉋꉌꉍꉎꉏꉐꉑꉒꉓꉔꉕꉖꉗꉘꉙꉚꉛꉜꉝꉞꉟꉠꉡꉢꉣꉤꉥꉦꉧꉨꉩꉪꉫꉬꉭꉮꉯꉰꉱꉲꉳꉴꉵꉶꉷꉸꉹꉺꉻꉼꉽꉾꉿꊀꊁꊂꊃꊄꊅꊆꊇꊈꊉꊊꊋꊌꊍꊎꊏꊐꊑꊒꊓꊔꊕꊖꊗꊘꊙꊚꊛꊜꊝꊞꊟꊠꊡꊢꊣꊤꊥꊦꊧꊨꊩꊪꊫꊬꊭꊮꊯꊰꊱꊲꊳꊴꊵꊶꊷꊸꊹꊺꊻꊼꊽꊾꊿꋀꋁꋂꋃꋄꋅꋆꋇꋈꋉꋊꋋꋌꋍꋎꋏꋐꋑꋒꋓꋔꋕꋖꋗꋘꋙꋚꋛꋜꋝꋞꋟꋠꋡꋢꋣꋤꋥꋦꋧꋨꋩꋪꋫꋬꋭꋮꋯꋰꋱꋲꋳꋴꋵꋶꋷꋸꋹꋺꋻꋼꋽꋾꋿꌀꌁꌂꌃꌄꌅꌆꌇꌈꌉꌊꌋꌌꌍꌎꌏꌐꌑꌒꌓꌔꌕꌖꌗꌘꌙꌚꌛꌜꌝꌞꌟꌠꌡꌢꌣꌤꌥꌦꌧꌨꌩꌪꌫꌬꌭꌮꌯꌰꌱꌲꌳꌴꌵꌶꌷꌸꌹꌺꌻꌼꌽꌾꌿꍀꍁꍂꍃꍄꍅꍆꍇꍈꍉꍊꍋꍌꍍꍎꍏꍐꍑꍒꍓꍔꍕꍖꍗꍘꍙꍚꍛꍜꍝꍞꍟꍠꍡꍢꍣꍤꍥꍦꍧꍨꍩꍪꍫꍬꍭꍮꍯꍰꍱꍲꍳꍴꍵꍶꍷꍸꍹꍺꍻꍼꍽꍾꍿꎀꎁꎂꎃꎄꎅꎆꎇꎈꎉꎊꎋꎌꎍꎎꎏꎐꎑꎒꎓꎔꎕꎖꎗꎘꎙꎚꎛꎜꎝꎞꎟꎠꎡꎢꎣꎤꎥꎦꎧꎨꎩꎪꎫꎬꎭꎮꎯꎰꎱꎲꎳꎴꎵꎶꎷꎸꎹꎺꎻꎼꎽꎾꎿꏀꏁꏂꏃꏄꏅꏆꏇꏈꏉꏊꏋꏌꏍꏎꏏꏐꏑꏒꏓꏔꏕꏖꏗꏘꏙꏚꏛꏜꏝꏞꏟꏠꏡꏢꏣꏤꏥꏦꏧꏨꏩꏪꏫꏬꏭꏮꏯꏰꏱꏲꏳꏴꏵꏶꏷꏸꏹꏺꏻꏼꏽꏾꏿꐀꐁꐂꐃꐄꐅꐆꐇꐈꐉꐊꐋꐌꐍꐎꐏꐐꐑꐒꐓꐔꐕꐖꐗꐘꐙꐚꐛꐜꐝꐞꐟꐠꐡꐢꐣꐤꐥꐦꐧꐨꐩꐪꐫꐬꐭꐮꐯꐰꐱꐲꐳꐴꐵꐶꐷꐸꐹꐺꐻꐼꐽꐾꐿꑀꑁꑂꑃꑄꑅꑆꑇꑈꑉꑊꑋꑌꑍꑎꑏꑐꑑꑒꑓꑔꑕꑖꑗꑘꑙꑚꑛꑜꑝꑞꑟꑠꑡꑢꑣꑤꑥꑦꑧꑨꑩꑪꑫꑬꑭꑮꑯꑰꑱꑲꑳꑴꑵꑶꑷꑸꑹꑺꑻꑼꑽꑾꑿꒀꒁꒂꒃꒄꒅꒆꒇꒈꒉꒊꒋꒌ꒐꒑꒒꒓꒔꒕꒖꒗꒘꒙꒚꒛꒜꒝꒞꒟꒠꒡꒢꒣꒤꒥꒦꒧꒨꒩꒪꒫꒬꒭꒮꒯꒰꒱꒲꒳꒴꒵꒶꒷꒸꒹꒺꒻꒼꒽꒾꒿꓀꓁꓂꓃꓄꓅꓆ꓐꓑꓒꓓꓔꓕꓖꓗꓘꓙꓚꓛꓜꓝꓞꓟꓠꓡꓢꓣꓤꓥꓦꓧꓨꓩꓪꓫꓬꓭꓮꓯꓰꓱꓲꓳꓴꓵꓶꓷꓸꓹꓺꓻꓼꓽ꓾꓿ꔀꔁꔂꔃꔄꔅꔆꔇꔈꔉꔊꔋꔌꔍꔎꔏꔐꔑꔒꔓꔔꔕꔖꔗꔘꔙꔚꔛꔜꔝꔞꔟꔠꔡꔢꔣꔤꔥꔦꔧꔨꔩꔪꔫꔬꔭꔮꔯꔰꔱꔲꔳꔴꔵꔶꔷꔸꔹꔺꔻꔼꔽꔾꔿꕀꕁꕂꕃꕄꕅꕆꕇꕈꕉꕊꕋꕌꕍꕎꕏꕐꕑꕒꕓꕔꕕꕖꕗꕘꕙꕚꕛꕜꕝꕞꕟꕠꕡꕢꕣꕤꕥꕦꕧꕨꕩꕪꕫꕬꕭꕮꕯꕰꕱꕲꕳꕴꕵꕶꕷꕸꕹꕺꕻꕼꕽꕾꕿꖀꖁꖂꖃꖄꖅꖆꖇꖈꖉꖊꖋꖌꖍꖎꖏꖐꖑꖒꖓꖔꖕꖖꖗꖘꖙꖚꖛꖜꖝꖞꖟꖠꖡꖢꖣꖤꖥꖦꖧꖨꖩꖪꖫꖬꖭꖮꖯꖰꖱꖲꖳꖴꖵꖶꖷꖸꖹꖺꖻꖼꖽꖾꖿꗀꗁꗂꗃꗄꗅꗆꗇꗈꗉꗊꗋꗌꗍꗎꗏꗐꗑꗒꗓꗔꗕꗖꗗꗘꗙꗚꗛꗜꗝꗞꗟꗠꗡꗢꗣꗤꗥꗦꗧꗨꗩꗪꗫꗬꗭꗮꗯꗰꗱꗲꗳꗴꗵꗶꗷꗸꗹꗺꗻꗼꗽꗾꗿꘀꘁꘂꘃꘄꘅꘆꘇꘈꘉꘊꘋꘌ꘍꘎꘏ꘐꘑꘒꘓꘔꘕꘖꘗꘘꘙꘚꘛꘜꘝꘞꘟ꘠꘡꘢꘣꘤꘥꘦꘧꘨꘩ꘪꘫꙀꙁꙂꙃꙄꙅꙆꙇꙈꙉꙊꙋꙌꙍꙎꙏꙐꙑꙒꙓꙔꙕꙖꙗꙘꙙꙚꙛꙜꙝꙞꙟꙠꙡꙢꙣꙤꙥꙦꙧꙨꙩꙪꙫꙬꙭꙮ꙯꙰꙱꙲꙳ꙴꙵꙶꙷꙸꙹꙺꙻ꙼꙽꙾ꙿꚀꚁꚂꚃꚄꚅꚆꚇꚈꚉꚊꚋꚌꚍꚎꚏꚐꚑꚒꚓꚔꚕꚖꚗꚟꚠꚡꚢꚣꚤꚥꚦꚧꚨꚩꚪꚫꚬꚭꚮꚯꚰꚱꚲꚳꚴꚵꚶꚷꚸꚹꚺꚻꚼꚽꚾꚿꛀꛁꛂꛃꛄꛅꛆꛇꛈꛉꛊꛋꛌꛍꛎꛏꛐꛑꛒꛓꛔꛕꛖꛗꛘꛙꛚꛛꛜꛝꛞꛟꛠꛡꛢꛣꛤꛥꛦꛧꛨꛩꛪꛫꛬꛭꛮꛯ꛰꛱꛲꛳꛴꛵꛶꛷꜀꜁꜂꜃꜄꜅꜆꜇꜈꜉꜊꜋꜌꜍꜎꜏꜐꜑꜒꜓꜔꜕꜖ꜗꜘꜙꜚꜛꜜꜝꜞꜟ꜠꜡ꜢꜣꜤꜥꜦꜧꜨꜩꜪꜫꜬꜭꜮꜯꜰꜱꜲꜳꜴꜵꜶꜷꜸꜹꜺꜻꜼꜽꜾꜿꝀꝁꝂꝃꝄꝅꝆꝇꝈꝉꝊꝋꝌꝍꝎꝏꝐꝑꝒꝓꝔꝕꝖꝗꝘꝙꝚꝛꝜꝝꝞꝟꝠꝡꝢꝣꝤꝥꝦꝧꝨꝩꝪꝫꝬꝭꝮꝯꝰꝱꝲꝳꝴꝵꝶꝷꝸꝹꝺꝻꝼꝽꝾꝿꞀꞁꞂꞃꞄꞅꞆꞇꞈ꞉꞊ꞋꞌꞍꞎꞐꞑꞒꞓꞠꞡꞢꞣꞤꞥꞦꞧꞨꞩꞪꟸꟹꟺꟻꟼꟽꟾꟿꠀꠁꠂꠃꠄꠅ꠆ꠇꠈꠉꠊꠋꠌꠍꠎꠏꠐꠑꠒꠓꠔꠕꠖꠗꠘꠙꠚꠛꠜꠝꠞꠟꠠꠡꠢꠣꠤꠥꠦꠧ꠨꠩꠪꠫꠰꠱꠲꠳꠴꠵꠶꠷꠸꠹ꡀꡁꡂꡃꡄꡅꡆꡇꡈꡉꡊꡋꡌꡍꡎꡏꡐꡑꡒꡓꡔꡕꡖꡗꡘꡙꡚꡛꡜꡝꡞꡟꡠꡡꡢꡣꡤꡥꡦꡧꡨꡩꡪꡫꡬꡭꡮꡯꡰꡱꡲꡳ꡴꡵꡶꡷ꢀꢁꢂꢃꢄꢅꢆꢇꢈꢉꢊꢋꢌꢍꢎꢏꢐꢑꢒꢓꢔꢕꢖꢗꢘꢙꢚꢛꢜꢝꢞꢟꢠꢡꢢꢣꢤꢥꢦꢧꢨꢩꢪꢫꢬꢭꢮꢯꢰꢱꢲꢳꢴꢵꢶꢷꢸꢹꢺꢻꢼꢽꢾꢿꣀꣁꣂꣃ꣄꣎꣏꣐꣑꣒꣓꣔꣕꣖꣗꣘꣙꣠꣡꣢꣣꣤꣥꣦꣧꣨꣩꣪꣫꣬꣭꣮꣯꣰꣱ꣲꣳꣴꣵꣶꣷ꣸꣹꣺ꣻ꤀꤁꤂꤃꤄꤅꤆꤇꤈꤉ꤊꤋꤌꤍꤎꤏꤐꤑꤒꤓꤔꤕꤖꤗꤘꤙꤚꤛꤜꤝꤞꤟꤠꤡꤢꤣꤤꤥꤦꤧꤨꤩꤪ꤫꤬꤭꤮꤯ꤰꤱꤲꤳꤴꤵꤶꤷꤸꤹꤺꤻꤼꤽꤾꤿꥀꥁꥂꥃꥄꥅꥆꥇꥈꥉꥊꥋꥌꥍꥎꥏꥐꥑꥒ꥓꥟ꥠꥡꥢꥣꥤꥥꥦꥧꥨꥩꥪꥫꥬꥭꥮꥯꥰꥱꥲꥳꥴꥵꥶꥷꥸꥹꥺꥻꥼꦀꦁꦂꦃꦄꦅꦆꦇꦈꦉꦊꦋꦌꦍꦎꦏꦐꦑꦒꦓꦔꦕꦖꦗꦘꦙꦚꦛꦜꦝꦞꦟꦠꦡꦢꦣꦤꦥꦦꦧꦨꦩꦪꦫꦬꦭꦮꦯꦰꦱꦲ꦳ꦴꦵꦶꦷꦸꦹꦺꦻꦼꦽꦾꦿ꧀꧁꧂꧃꧄꧅꧆꧇꧈꧉꧊꧋꧌꧍ꧏ꧐꧑꧒꧓꧔꧕꧖꧗꧘꧙꧞꧟ꨀꨁꨂꨃꨄꨅꨆꨇꨈꨉꨊꨋꨌꨍꨎꨏꨐꨑꨒꨓꨔꨕꨖꨗꨘꨙꨚꨛꨜꨝꨞꨟꨠꨡꨢꨣꨤꨥꨦꨧꨨꨩꨪꨫꨬꨭꨮꨯꨰꨱꨲꨳꨴꨵꨶꩀꩁꩂꩃꩄꩅꩆꩇꩈꩉꩊꩋꩌꩍ꩐꩑꩒꩓꩔꩕꩖꩗꩘꩙꩜꩝꩞꩟ꩠꩡꩢꩣꩤꩥꩦꩧꩨꩩꩪꩫꩬꩭꩮꩯꩰꩱꩲꩳꩴꩵꩶ꩷꩸꩹ꩺꩻꪀꪁꪂꪃꪄꪅꪆꪇꪈꪉꪊꪋꪌꪍꪎꪏꪐꪑꪒꪓꪔꪕꪖꪗꪘꪙꪚꪛꪜꪝꪞꪟꪠꪡꪢꪣꪤꪥꪦꪧꪨꪩꪪꪫꪬꪭꪮꪯꪰꪱꪴꪲꪳꪵꪶꪷꪸꪹꪺꪻꪼꪽꪾ꪿ꫀ꫁ꫂꫛꫜꫝ꫞꫟ꫠꫡꫢꫣꫤꫥꫦꫧꫨꫩꫪꫫꫬꫭꫮꫯ꫰꫱ꫲꫳꫴꫵ꫶ꬁꬂꬃꬄꬅꬆꬉꬊꬋꬌꬍꬎꬑꬒꬓꬔꬕꬖꬠꬡꬢꬣꬤꬥꬦꬨꬩꬪꬫꬬꬭꬮꯀꯁꯂꯃꯄꯅꯆꯇꯈꯉꯊꯋꯌꯍꯎꯏꯐꯑꯒꯓꯔꯕꯖꯗꯘꯙꯚꯛꯜꯝꯞꯟꯠꯡꯢꯣꯤꯥꯦꯧꯨꯩꯪ꯫꯬꯭꯰꯱꯲꯳꯴꯵꯶꯷꯸꯹가각갂갃간갅갆갇갈갉갊갋갌갍갎갏감갑값갓갔강갖갗갘같갚갛개객갞갟갠갡갢갣갤갥갦갧갨갩갪갫갬갭갮갯갰갱갲갳갴갵갶갷갸갹갺갻갼갽갾갿걀걁걂걃걄걅걆걇걈걉걊걋걌걍걎걏걐걑걒걓걔걕걖걗걘걙걚걛걜걝걞걟걠걡걢걣걤걥걦걧걨걩걪걫걬걭걮걯거걱걲걳건걵걶걷걸걹걺걻걼걽걾걿검겁겂것겄겅겆겇겈겉겊겋게겍겎겏겐겑겒겓겔겕겖겗겘겙겚겛겜겝겞겟겠겡겢겣겤겥겦겧겨격겪겫견겭겮겯결겱겲겳겴겵겶겷겸겹겺겻겼경겾겿곀곁곂곃계곅곆곇곈곉곊곋곌곍곎곏곐곑곒곓곔곕곖곗곘곙곚곛곜곝곞곟고곡곢곣곤곥곦곧골곩곪곫곬곭곮곯곰곱곲곳곴공곶곷곸곹곺곻과곽곾곿관괁괂괃괄괅괆괇괈괉괊괋괌괍괎괏괐광괒괓괔괕괖괗괘괙괚괛괜괝괞괟괠괡괢괣괤괥괦괧괨괩괪괫괬괭괮괯괰괱괲괳괴괵괶괷괸괹괺괻괼괽괾괿굀굁굂굃굄굅굆굇굈굉굊굋굌굍굎굏교굑굒굓굔굕굖굗굘굙굚굛굜굝굞굟굠굡굢굣굤굥굦굧굨굩굪굫구국굮굯군굱굲굳굴굵굶굷굸굹굺굻굼굽굾굿궀궁궂궃궄궅궆궇궈궉궊궋권궍궎궏궐궑궒궓궔궕궖궗궘궙궚궛궜궝궞궟궠궡궢궣궤궥궦궧궨궩궪궫궬궭궮궯궰궱궲궳궴궵궶궷궸궹궺궻궼궽궾궿귀귁귂귃귄귅귆귇귈귉귊귋귌귍귎귏귐귑귒귓귔귕귖귗귘귙귚귛규귝귞귟균귡귢귣귤귥귦귧귨귩귪귫귬귭귮귯귰귱귲귳귴귵귶귷그극귺귻근귽귾귿글긁긂긃긄긅긆긇금급긊긋긌긍긎긏긐긑긒긓긔긕긖긗긘긙긚긛긜긝긞긟긠긡긢긣긤긥긦긧긨긩긪긫긬긭긮긯기긱긲긳긴긵긶긷길긹긺긻긼긽긾긿김깁깂깃깄깅깆깇깈깉깊깋까깍깎깏깐깑깒깓깔깕깖깗깘깙깚깛깜깝깞깟깠깡깢깣깤깥깦깧깨깩깪깫깬깭깮깯깰깱깲깳깴깵깶깷깸깹깺깻깼깽깾깿꺀꺁꺂꺃꺄꺅꺆꺇꺈꺉꺊꺋꺌꺍꺎꺏꺐꺑꺒꺓꺔꺕꺖꺗꺘꺙꺚꺛꺜꺝꺞꺟꺠꺡꺢꺣꺤꺥꺦꺧꺨꺩꺪꺫꺬꺭꺮꺯꺰꺱꺲꺳꺴꺵꺶꺷꺸꺹꺺꺻꺼꺽꺾꺿껀껁껂껃껄껅껆껇껈껉껊껋껌껍껎껏껐껑껒껓껔껕껖껗께껙껚껛껜껝껞껟껠껡껢껣껤껥껦껧껨껩껪껫껬껭껮껯껰껱껲껳껴껵껶껷껸껹껺껻껼껽껾껿꼀꼁꼂꼃꼄꼅꼆꼇꼈꼉꼊꼋꼌꼍꼎꼏꼐꼑꼒꼓꼔꼕꼖꼗꼘꼙꼚꼛꼜꼝꼞꼟꼠꼡꼢꼣꼤꼥꼦꼧꼨꼩꼪꼫꼬꼭꼮꼯꼰꼱꼲꼳꼴꼵꼶꼷꼸꼹꼺꼻꼼꼽꼾꼿꽀꽁꽂꽃꽄꽅꽆꽇꽈꽉꽊꽋꽌꽍꽎꽏꽐꽑꽒꽓꽔꽕꽖꽗꽘꽙꽚꽛꽜꽝꽞꽟꽠꽡꽢꽣꽤꽥꽦꽧꽨꽩꽪꽫꽬꽭꽮꽯꽰꽱꽲꽳꽴꽵꽶꽷꽸꽹꽺꽻꽼꽽꽾꽿꾀꾁꾂꾃꾄꾅꾆꾇꾈꾉꾊꾋꾌꾍꾎꾏꾐꾑꾒꾓꾔꾕꾖꾗꾘꾙꾚꾛꾜꾝꾞꾟꾠꾡꾢꾣꾤꾥꾦꾧꾨꾩꾪꾫꾬꾭꾮꾯꾰꾱꾲꾳꾴꾵꾶꾷꾸꾹꾺꾻꾼꾽꾾꾿꿀꿁꿂꿃꿄꿅꿆꿇꿈꿉꿊꿋꿌꿍꿎꿏꿐꿑꿒꿓꿔꿕꿖꿗꿘꿙꿚꿛꿜꿝꿞꿟꿠꿡꿢꿣꿤꿥꿦꿧꿨꿩꿪꿫꿬꿭꿮꿯꿰꿱꿲꿳꿴꿵꿶꿷꿸꿹꿺꿻꿼꿽꿾꿿뀀뀁뀂뀃뀄뀅뀆뀇뀈뀉뀊뀋뀌뀍뀎뀏뀐뀑뀒뀓뀔뀕뀖뀗뀘뀙뀚뀛뀜뀝뀞뀟뀠뀡뀢뀣뀤뀥뀦뀧뀨뀩뀪뀫뀬뀭뀮뀯뀰뀱뀲뀳뀴뀵뀶뀷뀸뀹뀺뀻뀼뀽뀾뀿끀끁끂끃끄끅끆끇끈끉끊끋끌끍끎끏끐끑끒끓끔끕끖끗끘끙끚끛끜끝끞끟끠끡끢끣끤끥끦끧끨끩끪끫끬끭끮끯끰끱끲끳끴끵끶끷끸끹끺끻끼끽끾끿낀낁낂낃낄낅낆낇낈낉낊낋낌낍낎낏낐낑낒낓낔낕낖낗나낙낚낛난낝낞낟날낡낢낣낤낥낦낧남납낪낫났낭낮낯낰낱낲낳내낵낶낷낸낹낺낻낼낽낾낿냀냁냂냃냄냅냆냇냈냉냊냋냌냍냎냏냐냑냒냓냔냕냖냗냘냙냚냛냜냝냞냟냠냡냢냣냤냥냦냧냨냩냪냫냬냭냮냯냰냱냲냳냴냵냶냷냸냹냺냻냼냽냾냿넀넁넂넃넄넅넆넇너넉넊넋넌넍넎넏널넑넒넓넔넕넖넗넘넙넚넛넜넝넞넟넠넡넢넣네넥넦넧넨넩넪넫넬넭넮넯넰넱넲넳넴넵넶넷넸넹넺넻넼넽넾넿녀녁녂녃년녅녆녇녈녉녊녋녌녍녎녏념녑녒녓녔녕녖녗녘녙녚녛녜녝녞녟녠녡녢녣녤녥녦녧녨녩녪녫녬녭녮녯녰녱녲녳녴녵녶녷노녹녺녻논녽녾녿놀놁놂놃놄놅놆놇놈놉놊놋놌농놎놏놐놑높놓놔놕놖놗놘놙놚놛놜놝놞놟놠놡놢놣놤놥놦놧놨놩놪놫놬놭놮놯놰놱놲놳놴놵놶놷놸놹놺놻놼놽놾놿뇀뇁뇂뇃뇄뇅뇆뇇뇈뇉뇊뇋뇌뇍뇎뇏뇐뇑뇒뇓뇔뇕뇖뇗뇘뇙뇚뇛뇜뇝뇞뇟뇠뇡뇢뇣뇤뇥뇦뇧뇨뇩뇪뇫뇬뇭뇮뇯뇰뇱뇲뇳뇴뇵뇶뇷뇸뇹뇺뇻뇼뇽뇾뇿눀눁눂눃누눅눆눇눈눉눊눋눌눍눎눏눐눑눒눓눔눕눖눗눘눙눚눛눜눝눞눟눠눡눢눣눤눥눦눧눨눩눪눫눬눭눮눯눰눱눲눳눴눵눶눷눸눹눺눻눼눽눾눿뉀뉁뉂뉃뉄뉅뉆뉇뉈뉉뉊뉋뉌뉍뉎뉏뉐뉑뉒뉓뉔뉕뉖뉗뉘뉙뉚뉛뉜뉝뉞뉟뉠뉡뉢뉣뉤뉥뉦뉧뉨뉩뉪뉫뉬뉭뉮뉯뉰뉱뉲뉳뉴뉵뉶뉷뉸뉹뉺뉻뉼뉽뉾뉿늀늁늂늃늄늅늆늇늈늉늊늋늌늍늎늏느늑늒늓는늕늖늗늘늙늚늛늜늝늞늟늠늡늢늣늤능늦늧늨늩늪늫늬늭늮늯늰늱늲늳늴늵늶늷늸늹늺늻늼늽늾늿닀닁닂닃닄닅닆닇니닉닊닋닌닍닎닏닐닑닒닓닔닕닖닗님닙닚닛닜닝닞닟닠닡닢닣다닥닦닧단닩닪닫달닭닮닯닰닱닲닳담답닶닷닸당닺닻닼닽닾닿대댁댂댃댄댅댆댇댈댉댊댋댌댍댎댏댐댑댒댓댔댕댖댗댘댙댚댛댜댝댞댟댠댡댢댣댤댥댦댧댨댩댪댫댬댭댮댯댰댱댲댳댴댵댶댷댸댹댺댻댼댽댾댿덀덁덂덃덄덅덆덇덈덉덊덋덌덍덎덏덐덑덒덓더덕덖덗던덙덚덛덜덝덞덟덠덡덢덣덤덥덦덧덨덩덪덫덬덭덮덯데덱덲덳덴덵덶덷델덹덺덻덼덽덾덿뎀뎁뎂뎃뎄뎅뎆뎇뎈뎉뎊뎋뎌뎍뎎뎏뎐뎑뎒뎓뎔뎕뎖뎗뎘뎙뎚뎛뎜뎝뎞뎟뎠뎡뎢뎣뎤뎥뎦뎧뎨뎩뎪뎫뎬뎭뎮뎯뎰뎱뎲뎳뎴뎵뎶뎷뎸뎹뎺뎻뎼뎽뎾뎿돀돁돂돃도독돆돇돈돉돊돋돌돍돎돏돐돑돒돓돔돕돖돗돘동돚돛돜돝돞돟돠돡돢돣돤돥돦돧돨돩돪돫돬돭돮돯돰돱돲돳돴돵돶돷돸돹돺돻돼돽돾돿됀됁됂됃됄됅됆됇됈됉됊됋됌됍됎됏됐됑됒됓됔됕됖됗되됙됚됛된됝됞됟될됡됢됣됤됥됦됧됨됩됪됫됬됭됮됯됰됱됲됳됴됵됶됷됸됹됺됻됼됽됾됿둀둁둂둃둄둅둆둇둈둉둊둋둌둍둎둏두둑둒둓둔둕둖둗둘둙둚둛둜둝둞둟둠둡둢둣둤둥둦둧둨둩둪둫둬둭둮둯둰둱둲둳둴둵둶둷둸둹둺둻둼둽둾둿뒀뒁뒂뒃뒄뒅뒆뒇뒈뒉뒊뒋뒌뒍뒎뒏뒐뒑뒒뒓뒔뒕뒖뒗뒘뒙뒚뒛뒜뒝뒞뒟뒠뒡뒢뒣뒤뒥뒦뒧뒨뒩뒪뒫뒬뒭뒮뒯뒰뒱뒲뒳뒴뒵뒶뒷뒸뒹뒺뒻뒼뒽뒾뒿듀듁듂듃듄듅듆듇듈듉듊듋듌듍듎듏듐듑듒듓듔듕듖듗듘듙듚듛드득듞듟든듡듢듣들듥듦듧듨듩듪듫듬듭듮듯듰등듲듳듴듵듶듷듸듹듺듻듼듽듾듿딀딁딂딃딄딅딆딇딈딉딊딋딌딍딎딏딐딑딒딓디딕딖딗딘딙딚딛딜딝딞딟딠딡딢딣딤딥딦딧딨딩딪딫딬딭딮딯따딱딲딳딴딵딶딷딸딹딺딻딼딽딾딿땀땁땂땃땄땅땆땇땈땉땊땋때땍땎땏땐땑땒땓땔땕땖땗땘땙땚땛땜땝땞땟땠땡땢땣땤땥땦땧땨땩땪땫땬땭땮땯땰땱땲땳땴땵땶땷땸땹땺땻땼땽땾땿떀떁떂떃떄떅떆떇떈떉떊떋떌떍떎떏떐떑떒떓떔떕떖떗떘떙떚떛떜떝떞떟떠떡떢떣떤떥떦떧떨떩떪떫떬떭떮떯떰떱떲떳떴떵떶떷떸떹떺떻떼떽떾떿뗀뗁뗂뗃뗄뗅뗆뗇뗈뗉뗊뗋뗌뗍뗎뗏뗐뗑뗒뗓뗔뗕뗖뗗뗘뗙뗚뗛뗜뗝뗞뗟뗠뗡뗢뗣뗤뗥뗦뗧뗨뗩뗪뗫뗬뗭뗮뗯뗰뗱뗲뗳뗴뗵뗶뗷뗸뗹뗺뗻뗼뗽뗾뗿똀똁똂똃똄똅똆똇똈똉똊똋똌똍똎똏또똑똒똓똔똕똖똗똘똙똚똛똜똝똞똟똠똡똢똣똤똥똦똧똨똩똪똫똬똭똮똯똰똱똲똳똴똵똶똷똸똹똺똻똼똽똾똿뙀뙁뙂뙃뙄뙅뙆뙇뙈뙉뙊뙋뙌뙍뙎뙏뙐뙑뙒뙓뙔뙕뙖뙗뙘뙙뙚뙛뙜뙝뙞뙟뙠뙡뙢뙣뙤뙥뙦뙧뙨뙩뙪뙫뙬뙭뙮뙯뙰뙱뙲뙳뙴뙵뙶뙷뙸뙹뙺뙻뙼뙽뙾뙿뚀뚁뚂뚃뚄뚅뚆뚇뚈뚉뚊뚋뚌뚍뚎뚏뚐뚑뚒뚓뚔뚕뚖뚗뚘뚙뚚뚛뚜뚝뚞뚟뚠뚡뚢뚣뚤뚥뚦뚧뚨뚩뚪뚫뚬뚭뚮뚯뚰뚱뚲뚳뚴뚵뚶뚷뚸뚹뚺뚻뚼뚽뚾뚿뛀뛁뛂뛃뛄뛅뛆뛇뛈뛉뛊뛋뛌뛍뛎뛏뛐뛑뛒뛓뛔뛕뛖뛗뛘뛙뛚뛛뛜뛝뛞뛟뛠뛡뛢뛣뛤뛥뛦뛧뛨뛩뛪뛫뛬뛭뛮뛯뛰뛱뛲뛳뛴뛵뛶뛷뛸뛹뛺뛻뛼뛽뛾뛿뜀뜁뜂뜃뜄뜅뜆뜇뜈뜉뜊뜋뜌뜍뜎뜏뜐뜑뜒뜓뜔뜕뜖뜗뜘뜙뜚뜛뜜뜝뜞뜟뜠뜡뜢뜣뜤뜥뜦뜧뜨뜩뜪뜫뜬뜭뜮뜯뜰뜱뜲뜳뜴뜵뜶뜷뜸뜹뜺뜻뜼뜽뜾뜿띀띁띂띃띄띅띆띇띈띉띊띋띌띍띎띏띐띑띒띓띔띕띖띗띘띙띚띛띜띝띞띟띠띡띢띣띤띥띦띧띨띩띪띫띬띭띮띯띰띱띲띳띴띵띶띷띸띹띺띻라락띾띿란랁랂랃랄랅랆랇랈랉랊랋람랍랎랏랐랑랒랓랔랕랖랗래랙랚랛랜랝랞랟랠랡랢랣랤랥랦랧램랩랪랫랬랭랮랯랰랱랲랳랴략랶랷랸랹랺랻랼랽랾랿럀럁럂럃럄럅럆럇럈량럊럋럌럍럎럏럐럑럒럓럔럕럖럗럘럙럚럛럜럝럞럟럠럡럢럣럤럥럦럧럨럩럪럫러럭럮럯런럱럲럳럴럵럶럷럸럹럺럻럼럽럾럿렀렁렂렃렄렅렆렇레렉렊렋렌렍렎렏렐렑렒렓렔렕렖렗렘렙렚렛렜렝렞렟렠렡렢렣려력렦렧련렩렪렫렬렭렮렯렰렱렲렳렴렵렶렷렸령렺렻렼렽렾렿례롁롂롃롄롅롆롇롈롉롊롋롌롍롎롏롐롑롒롓롔롕롖롗롘롙롚롛로록롞롟론롡롢롣롤롥롦롧롨롩롪롫롬롭롮롯롰롱롲롳롴롵롶롷롸롹롺롻롼롽롾롿뢀뢁뢂뢃뢄뢅뢆뢇뢈뢉뢊뢋뢌뢍뢎뢏뢐뢑뢒뢓뢔뢕뢖뢗뢘뢙뢚뢛뢜뢝뢞뢟뢠뢡뢢뢣뢤뢥뢦뢧뢨뢩뢪뢫뢬뢭뢮뢯뢰뢱뢲뢳뢴뢵뢶뢷뢸뢹뢺뢻뢼뢽뢾뢿룀룁룂룃룄룅룆룇룈룉룊룋료룍룎룏룐룑룒룓룔룕룖룗룘룙룚룛룜룝룞룟룠룡룢룣룤룥룦룧루룩룪룫룬룭룮룯룰룱룲룳룴룵룶룷룸룹룺룻룼룽룾룿뤀뤁뤂뤃뤄뤅뤆뤇뤈뤉뤊뤋뤌뤍뤎뤏뤐뤑뤒뤓뤔뤕뤖뤗뤘뤙뤚뤛뤜뤝뤞뤟뤠뤡뤢뤣뤤뤥뤦뤧뤨뤩뤪뤫뤬뤭뤮뤯뤰뤱뤲뤳뤴뤵뤶뤷뤸뤹뤺뤻뤼뤽뤾뤿륀륁륂륃륄륅륆륇륈륉륊륋륌륍륎륏륐륑륒륓륔륕륖륗류륙륚륛륜륝륞륟률륡륢륣륤륥륦륧륨륩륪륫륬륭륮륯륰륱륲륳르륵륶륷른륹륺륻를륽륾륿릀릁릂릃름릅릆릇릈릉릊릋릌릍릎릏릐릑릒릓릔릕릖릗릘릙릚릛릜릝릞릟릠릡릢릣릤릥릦릧릨릩릪릫리릭릮릯린릱릲릳릴릵릶릷릸릹릺릻림립릾릿맀링맂맃맄맅맆맇마막맊맋만맍많맏말맑맒맓맔맕맖맗맘맙맚맛맜망맞맟맠맡맢맣매맥맦맧맨맩맪맫맬맭맮맯맰맱맲맳맴맵맶맷맸맹맺맻맼맽맾맿먀먁먂먃먄먅먆먇먈먉먊먋먌먍먎먏먐먑먒먓먔먕먖먗먘먙먚먛먜먝먞먟먠먡먢먣먤먥먦먧먨먩먪먫먬먭먮먯먰먱먲먳먴먵먶먷머먹먺먻먼먽먾먿멀멁멂멃멄멅멆멇멈멉멊멋멌멍멎멏멐멑멒멓메멕멖멗멘멙멚멛멜멝멞멟멠멡멢멣멤멥멦멧멨멩멪멫멬멭멮멯며멱멲멳면멵멶멷멸멹멺멻멼멽멾멿몀몁몂몃몄명몆몇몈몉몊몋몌몍몎몏몐몑몒몓몔몕몖몗몘몙몚몛몜몝몞몟몠몡몢몣몤몥몦몧모목몪몫몬몭몮몯몰몱몲몳몴몵몶몷몸몹몺못몼몽몾몿뫀뫁뫂뫃뫄뫅뫆뫇뫈뫉뫊뫋뫌뫍뫎뫏뫐뫑뫒뫓뫔뫕뫖뫗뫘뫙뫚뫛뫜뫝뫞뫟뫠뫡뫢뫣뫤뫥뫦뫧뫨뫩뫪뫫뫬뫭뫮뫯뫰뫱뫲뫳뫴뫵뫶뫷뫸뫹뫺뫻뫼뫽뫾뫿묀묁묂묃묄묅묆묇묈묉묊묋묌묍묎묏묐묑묒묓묔묕묖묗묘묙묚묛묜묝묞묟묠묡묢묣묤묥묦묧묨묩묪묫묬묭묮묯묰묱묲묳무묵묶묷문묹묺묻물묽묾묿뭀뭁뭂뭃뭄뭅뭆뭇뭈뭉뭊뭋뭌뭍뭎뭏뭐뭑뭒뭓뭔뭕뭖뭗뭘뭙뭚뭛뭜뭝뭞뭟뭠뭡뭢뭣뭤뭥뭦뭧뭨뭩뭪뭫뭬뭭뭮뭯뭰뭱뭲뭳뭴뭵뭶뭷뭸뭹뭺뭻뭼뭽뭾뭿뮀뮁뮂뮃뮄뮅뮆뮇뮈뮉뮊뮋뮌뮍뮎뮏뮐뮑뮒뮓뮔뮕뮖뮗뮘뮙뮚뮛뮜뮝뮞뮟뮠뮡뮢뮣뮤뮥뮦뮧뮨뮩뮪뮫뮬뮭뮮뮯뮰뮱뮲뮳뮴뮵뮶뮷뮸뮹뮺뮻뮼뮽뮾뮿므믁믂믃믄믅믆믇믈믉믊믋믌믍믎믏믐믑믒믓믔믕믖믗믘믙믚믛믜믝믞믟믠믡믢믣믤믥믦믧믨믩믪믫믬믭믮믯믰믱믲믳믴믵믶믷미믹믺믻민믽믾믿밀밁밂밃밄밅밆밇밈밉밊밋밌밍밎및밐밑밒밓바박밖밗반밙밚받발밝밞밟밠밡밢밣밤밥밦밧밨방밪밫밬밭밮밯배백밲밳밴밵밶밷밸밹밺밻밼밽밾밿뱀뱁뱂뱃뱄뱅뱆뱇뱈뱉뱊뱋뱌뱍뱎뱏뱐뱑뱒뱓뱔뱕뱖뱗뱘뱙뱚뱛뱜뱝뱞뱟뱠뱡뱢뱣뱤뱥뱦뱧뱨뱩뱪뱫뱬뱭뱮뱯뱰뱱뱲뱳뱴뱵뱶뱷뱸뱹뱺뱻뱼뱽뱾뱿벀벁벂벃버벅벆벇번벉벊벋벌벍벎벏벐벑벒벓범법벖벗벘벙벚벛벜벝벞벟베벡벢벣벤벥벦벧벨벩벪벫벬벭벮벯벰벱벲벳벴벵벶벷벸벹벺벻벼벽벾벿변볁볂볃별볅볆볇볈볉볊볋볌볍볎볏볐병볒볓볔볕볖볗볘볙볚볛볜볝볞볟볠볡볢볣볤볥볦볧볨볩볪볫볬볭볮볯볰볱볲볳보복볶볷본볹볺볻볼볽볾볿봀봁봂봃봄봅봆봇봈봉봊봋봌봍봎봏봐봑봒봓봔봕봖봗봘봙봚봛봜봝봞봟봠봡봢봣봤봥봦봧봨봩봪봫봬봭봮봯봰봱봲봳봴봵봶봷봸봹봺봻봼봽봾봿뵀뵁뵂뵃뵄뵅뵆뵇뵈뵉뵊뵋뵌뵍뵎뵏뵐뵑뵒뵓뵔뵕뵖뵗뵘뵙뵚뵛뵜뵝뵞뵟뵠뵡뵢뵣뵤뵥뵦뵧뵨뵩뵪뵫뵬뵭뵮뵯뵰뵱뵲뵳뵴뵵뵶뵷뵸뵹뵺뵻뵼뵽뵾뵿부북붂붃분붅붆붇불붉붊붋붌붍붎붏붐붑붒붓붔붕붖붗붘붙붚붛붜붝붞붟붠붡붢붣붤붥붦붧붨붩붪붫붬붭붮붯붰붱붲붳붴붵붶붷붸붹붺붻붼붽붾붿뷀뷁뷂뷃뷄뷅뷆뷇뷈뷉뷊뷋뷌뷍뷎뷏뷐뷑뷒뷓뷔뷕뷖뷗뷘뷙뷚뷛뷜뷝뷞뷟뷠뷡뷢뷣뷤뷥뷦뷧뷨뷩뷪뷫뷬뷭뷮뷯뷰뷱뷲뷳뷴뷵뷶뷷뷸뷹뷺뷻뷼뷽뷾뷿븀븁븂븃븄븅븆븇븈븉븊븋브븍븎븏븐븑븒븓블븕븖븗븘븙븚븛븜븝븞븟븠븡븢븣븤븥븦븧븨븩븪븫븬븭븮븯븰븱븲븳븴븵븶븷븸븹븺븻븼븽븾븿빀빁빂빃비빅빆빇빈빉빊빋빌빍빎빏빐빑빒빓빔빕빖빗빘빙빚빛빜빝빞빟빠빡빢빣빤빥빦빧빨빩빪빫빬빭빮빯빰빱빲빳빴빵빶빷빸빹빺빻빼빽빾빿뺀뺁뺂뺃뺄뺅뺆뺇뺈뺉뺊뺋뺌뺍뺎뺏뺐뺑뺒뺓뺔뺕뺖뺗뺘뺙뺚뺛뺜뺝뺞뺟뺠뺡뺢뺣뺤뺥뺦뺧뺨뺩뺪뺫뺬뺭뺮뺯뺰뺱뺲뺳뺴뺵뺶뺷뺸뺹뺺뺻뺼뺽뺾뺿뻀뻁뻂뻃뻄뻅뻆뻇뻈뻉뻊뻋뻌뻍뻎뻏뻐뻑뻒뻓뻔뻕뻖뻗뻘뻙뻚뻛뻜뻝뻞뻟뻠뻡뻢뻣뻤뻥뻦뻧뻨뻩뻪뻫뻬뻭뻮뻯뻰뻱뻲뻳뻴뻵뻶뻷뻸뻹뻺뻻뻼뻽뻾뻿뼀뼁뼂뼃뼄뼅뼆뼇뼈뼉뼊뼋뼌뼍뼎뼏뼐뼑뼒뼓뼔뼕뼖뼗뼘뼙뼚뼛뼜뼝뼞뼟뼠뼡뼢뼣뼤뼥뼦뼧뼨뼩뼪뼫뼬뼭뼮뼯뼰뼱뼲뼳뼴뼵뼶뼷뼸뼹뼺뼻뼼뼽뼾뼿뽀뽁뽂뽃뽄뽅뽆뽇뽈뽉뽊뽋뽌뽍뽎뽏뽐뽑뽒뽓뽔뽕뽖뽗뽘뽙뽚뽛뽜뽝뽞뽟뽠뽡뽢뽣뽤뽥뽦뽧뽨뽩뽪뽫뽬뽭뽮뽯뽰뽱뽲뽳뽴뽵뽶뽷뽸뽹뽺뽻뽼뽽뽾뽿뾀뾁뾂뾃뾄뾅뾆뾇뾈뾉뾊뾋뾌뾍뾎뾏뾐뾑뾒뾓뾔뾕뾖뾗뾘뾙뾚뾛뾜뾝뾞뾟뾠뾡뾢뾣뾤뾥뾦뾧뾨뾩뾪뾫뾬뾭뾮뾯뾰뾱뾲뾳뾴뾵뾶뾷뾸뾹뾺뾻뾼뾽뾾뾿뿀뿁뿂뿃뿄뿅뿆뿇뿈뿉뿊뿋뿌뿍뿎뿏뿐뿑뿒뿓뿔뿕뿖뿗뿘뿙뿚뿛뿜뿝뿞뿟뿠뿡뿢뿣뿤뿥뿦뿧뿨뿩뿪뿫뿬뿭뿮뿯뿰뿱뿲뿳뿴뿵뿶뿷뿸뿹뿺뿻뿼뿽뿾뿿쀀쀁쀂쀃쀄쀅쀆쀇쀈쀉쀊쀋쀌쀍쀎쀏쀐쀑쀒쀓쀔쀕쀖쀗쀘쀙쀚쀛쀜쀝쀞쀟쀠쀡쀢쀣쀤쀥쀦쀧쀨쀩쀪쀫쀬쀭쀮쀯쀰쀱쀲쀳쀴쀵쀶쀷쀸쀹쀺쀻쀼쀽쀾쀿쁀쁁쁂쁃쁄쁅쁆쁇쁈쁉쁊쁋쁌쁍쁎쁏쁐쁑쁒쁓쁔쁕쁖쁗쁘쁙쁚쁛쁜쁝쁞쁟쁠쁡쁢쁣쁤쁥쁦쁧쁨쁩쁪쁫쁬쁭쁮쁯쁰쁱쁲쁳쁴쁵쁶쁷쁸쁹쁺쁻쁼쁽쁾쁿삀삁삂삃삄삅삆삇삈삉삊삋삌삍삎삏삐삑삒삓삔삕삖삗삘삙삚삛삜삝삞삟삠삡삢삣삤삥삦삧삨삩삪삫사삭삮삯산삱삲삳살삵삶삷삸삹삺삻삼삽삾삿샀상샂샃샄샅샆샇새색샊샋샌샍샎샏샐샑샒샓샔샕샖샗샘샙샚샛샜생샞샟샠샡샢샣샤샥샦샧샨샩샪샫샬샭샮샯샰샱샲샳샴샵샶샷샸샹샺샻샼샽샾샿섀섁섂섃섄섅섆섇섈섉섊섋섌섍섎섏섐섑섒섓섔섕섖섗섘섙섚섛서석섞섟선섡섢섣설섥섦섧섨섩섪섫섬섭섮섯섰성섲섳섴섵섶섷세섹섺섻센섽섾섿셀셁셂셃셄셅셆셇셈셉셊셋셌셍셎셏셐셑셒셓셔셕셖셗션셙셚셛셜셝셞셟셠셡셢셣셤셥셦셧셨셩셪셫셬셭셮셯셰셱셲셳셴셵셶셷셸셹셺셻셼셽셾셿솀솁솂솃솄솅솆솇솈솉솊솋소속솎솏손솑솒솓솔솕솖솗솘솙솚솛솜솝솞솟솠송솢솣솤솥솦솧솨솩솪솫솬솭솮솯솰솱솲솳솴솵솶솷솸솹솺솻솼솽솾솿쇀쇁쇂쇃쇄쇅쇆쇇쇈쇉쇊쇋쇌쇍쇎쇏쇐쇑쇒쇓쇔쇕쇖쇗쇘쇙쇚쇛쇜쇝쇞쇟쇠쇡쇢쇣쇤쇥쇦쇧쇨쇩쇪쇫쇬쇭쇮쇯쇰쇱쇲쇳쇴쇵쇶쇷쇸쇹쇺쇻쇼쇽쇾쇿숀숁숂숃숄숅숆숇숈숉숊숋숌숍숎숏숐숑숒숓숔숕숖숗수숙숚숛순숝숞숟술숡숢숣숤숥숦숧숨숩숪숫숬숭숮숯숰숱숲숳숴숵숶숷숸숹숺숻숼숽숾숿쉀쉁쉂쉃쉄쉅쉆쉇쉈쉉쉊쉋쉌쉍쉎쉏쉐쉑쉒쉓쉔쉕쉖쉗쉘쉙쉚쉛쉜쉝쉞쉟쉠쉡쉢쉣쉤쉥쉦쉧쉨쉩쉪쉫쉬쉭쉮쉯쉰쉱쉲쉳쉴쉵쉶쉷쉸쉹쉺쉻쉼쉽쉾쉿슀슁슂슃슄슅슆슇슈슉슊슋슌슍슎슏슐슑슒슓슔슕슖슗슘슙슚슛슜슝슞슟슠슡슢슣스슥슦슧슨슩슪슫슬슭슮슯슰슱슲슳슴습슶슷슸승슺슻슼슽슾슿싀싁싂싃싄싅싆싇싈싉싊싋싌싍싎싏싐싑싒싓싔싕싖싗싘싙싚싛시식싞싟신싡싢싣실싥싦싧싨싩싪싫심십싮싯싰싱싲싳싴싵싶싷싸싹싺싻싼싽싾싿쌀쌁쌂쌃쌄쌅쌆쌇쌈쌉쌊쌋쌌쌍쌎쌏쌐쌑쌒쌓쌔쌕쌖쌗쌘쌙쌚쌛쌜쌝쌞쌟쌠쌡쌢쌣쌤쌥쌦쌧쌨쌩쌪쌫쌬쌭쌮쌯쌰쌱쌲쌳쌴쌵쌶쌷쌸쌹쌺쌻쌼쌽쌾쌿썀썁썂썃썄썅썆썇썈썉썊썋썌썍썎썏썐썑썒썓썔썕썖썗썘썙썚썛썜썝썞썟썠썡썢썣썤썥썦썧써썩썪썫썬썭썮썯썰썱썲썳썴썵썶썷썸썹썺썻썼썽썾썿쎀쎁쎂쎃쎄쎅쎆쎇쎈쎉쎊쎋쎌쎍쎎쎏쎐쎑쎒쎓쎔쎕쎖쎗쎘쎙쎚쎛쎜쎝쎞쎟쎠쎡쎢쎣쎤쎥쎦쎧쎨쎩쎪쎫쎬쎭쎮쎯쎰쎱쎲쎳쎴쎵쎶쎷쎸쎹쎺쎻쎼쎽쎾쎿쏀쏁쏂쏃쏄쏅쏆쏇쏈쏉쏊쏋쏌쏍쏎쏏쏐쏑쏒쏓쏔쏕쏖쏗쏘쏙쏚쏛쏜쏝쏞쏟쏠쏡쏢쏣쏤쏥쏦쏧쏨쏩쏪쏫쏬쏭쏮쏯쏰쏱쏲쏳쏴쏵쏶쏷쏸쏹쏺쏻쏼쏽쏾쏿쐀쐁쐂쐃쐄쐅쐆쐇쐈쐉쐊쐋쐌쐍쐎쐏쐐쐑쐒쐓쐔쐕쐖쐗쐘쐙쐚쐛쐜쐝쐞쐟쐠쐡쐢쐣쐤쐥쐦쐧쐨쐩쐪쐫쐬쐭쐮쐯쐰쐱쐲쐳쐴쐵쐶쐷쐸쐹쐺쐻쐼쐽쐾쐿쑀쑁쑂쑃쑄쑅쑆쑇쑈쑉쑊쑋쑌쑍쑎쑏쑐쑑쑒쑓쑔쑕쑖쑗쑘쑙쑚쑛쑜쑝쑞쑟쑠쑡쑢쑣쑤쑥쑦쑧쑨쑩쑪쑫쑬쑭쑮쑯쑰쑱쑲쑳쑴쑵쑶쑷쑸쑹쑺쑻쑼쑽쑾쑿쒀쒁쒂쒃쒄쒅쒆쒇쒈쒉쒊쒋쒌쒍쒎쒏쒐쒑쒒쒓쒔쒕쒖쒗쒘쒙쒚쒛쒜쒝쒞쒟쒠쒡쒢쒣쒤쒥쒦쒧쒨쒩쒪쒫쒬쒭쒮쒯쒰쒱쒲쒳쒴쒵쒶쒷쒸쒹쒺쒻쒼쒽쒾쒿쓀쓁쓂쓃쓄쓅쓆쓇쓈쓉쓊쓋쓌쓍쓎쓏쓐쓑쓒쓓쓔쓕쓖쓗쓘쓙쓚쓛쓜쓝쓞쓟쓠쓡쓢쓣쓤쓥쓦쓧쓨쓩쓪쓫쓬쓭쓮쓯쓰쓱쓲쓳쓴쓵쓶쓷쓸쓹쓺쓻쓼쓽쓾쓿씀씁씂씃씄씅씆씇씈씉씊씋씌씍씎씏씐씑씒씓씔씕씖씗씘씙씚씛씜씝씞씟씠씡씢씣씤씥씦씧씨씩씪씫씬씭씮씯씰씱씲씳씴씵씶씷씸씹씺씻씼씽씾씿앀앁앂앃아악앆앇안앉않앋알앍앎앏앐앑앒앓암압앖앗았앙앚앛앜앝앞앟애액앢앣앤앥앦앧앨앩앪앫앬앭앮앯앰앱앲앳앴앵앶앷앸앹앺앻야약앾앿얀얁얂얃얄얅얆얇얈얉얊얋얌얍얎얏얐양얒얓얔얕얖얗얘얙얚얛얜얝얞얟얠얡얢얣얤얥얦얧얨얩얪얫얬얭얮얯얰얱얲얳어억얶얷언얹얺얻얼얽얾얿엀엁엂엃엄업없엇었엉엊엋엌엍엎엏에엑엒엓엔엕엖엗엘엙엚엛엜엝엞엟엠엡엢엣엤엥엦엧엨엩엪엫여역엮엯연엱엲엳열엵엶엷엸엹엺엻염엽엾엿였영옂옃옄옅옆옇예옉옊옋옌옍옎옏옐옑옒옓옔옕옖옗옘옙옚옛옜옝옞옟옠옡옢옣오옥옦옧온옩옪옫올옭옮옯옰옱옲옳옴옵옶옷옸옹옺옻옼옽옾옿와왁왂왃완왅왆왇왈왉왊왋왌왍왎왏왐왑왒왓왔왕왖왗왘왙왚왛왜왝왞왟왠왡왢왣왤왥왦왧왨왩왪왫왬왭왮왯왰왱왲왳왴왵왶왷외왹왺왻왼왽왾왿욀욁욂욃욄욅욆욇욈욉욊욋욌욍욎욏욐욑욒욓요욕욖욗욘욙욚욛욜욝욞욟욠욡욢욣욤욥욦욧욨용욪욫욬욭욮욯우욱욲욳운욵욶욷울욹욺욻욼욽욾욿움웁웂웃웄웅웆웇웈웉웊웋워웍웎웏원웑웒웓월웕웖웗웘웙웚웛웜웝웞웟웠웡웢웣웤웥웦웧웨웩웪웫웬웭웮웯웰웱웲웳웴웵웶웷웸웹웺웻웼웽웾웿윀윁윂윃위윅윆윇윈윉윊윋윌윍윎윏윐윑윒윓윔윕윖윗윘윙윚윛윜윝윞윟유육윢윣윤윥윦윧율윩윪윫윬윭윮윯윰윱윲윳윴융윶윷윸윹윺윻으윽윾윿은읁읂읃을읅읆읇읈읉읊읋음읍읎읏읐응읒읓읔읕읖읗의읙읚읛읜읝읞읟읠읡읢읣읤읥읦읧읨읩읪읫읬읭읮읯읰읱읲읳이익읶읷인읹읺읻일읽읾읿잀잁잂잃임입잆잇있잉잊잋잌잍잎잏자작잒잓잔잕잖잗잘잙잚잛잜잝잞잟잠잡잢잣잤장잦잧잨잩잪잫재잭잮잯잰잱잲잳잴잵잶잷잸잹잺잻잼잽잾잿쟀쟁쟂쟃쟄쟅쟆쟇쟈쟉쟊쟋쟌쟍쟎쟏쟐쟑쟒쟓쟔쟕쟖쟗쟘쟙쟚쟛쟜쟝쟞쟟쟠쟡쟢쟣쟤쟥쟦쟧쟨쟩쟪쟫쟬쟭쟮쟯쟰쟱쟲쟳쟴쟵쟶쟷쟸쟹쟺쟻쟼쟽쟾쟿저적젂젃전젅젆젇절젉젊젋젌젍젎젏점접젒젓젔정젖젗젘젙젚젛제젝젞젟젠젡젢젣젤젥젦젧젨젩젪젫젬젭젮젯젰젱젲젳젴젵젶젷져젹젺젻젼젽젾젿졀졁졂졃졄졅졆졇졈졉졊졋졌졍졎졏졐졑졒졓졔졕졖졗졘졙졚졛졜졝졞졟졠졡졢졣졤졥졦졧졨졩졪졫졬졭졮졯조족졲졳존졵졶졷졸졹졺졻졼졽졾졿좀좁좂좃좄종좆좇좈좉좊좋좌좍좎좏좐좑좒좓좔좕좖좗좘좙좚좛좜좝좞좟좠좡좢좣좤좥좦좧좨좩좪좫좬좭좮좯좰좱좲좳좴좵좶좷좸좹좺좻좼좽좾좿죀죁죂죃죄죅죆죇죈죉죊죋죌죍죎죏죐죑죒죓죔죕죖죗죘죙죚죛죜죝죞죟죠죡죢죣죤죥죦죧죨죩죪죫죬죭죮죯죰죱죲죳죴죵죶죷죸죹죺죻주죽죾죿준줁줂줃줄줅줆줇줈줉줊줋줌줍줎줏줐중줒줓줔줕줖줗줘줙줚줛줜줝줞줟줠줡줢줣줤줥줦줧줨줩줪줫줬줭줮줯줰줱줲줳줴줵줶줷줸줹줺줻줼줽줾줿쥀쥁쥂쥃쥄쥅쥆쥇쥈쥉쥊쥋쥌쥍쥎쥏쥐쥑쥒쥓쥔쥕쥖쥗쥘쥙쥚쥛쥜쥝쥞쥟쥠쥡쥢쥣쥤쥥쥦쥧쥨쥩쥪쥫쥬쥭쥮쥯쥰쥱쥲쥳쥴쥵쥶쥷쥸쥹쥺쥻쥼쥽쥾쥿즀즁즂즃즄즅즆즇즈즉즊즋즌즍즎즏즐즑즒즓즔즕즖즗즘즙즚즛즜증즞즟즠즡즢즣즤즥즦즧즨즩즪즫즬즭즮즯즰즱즲즳즴즵즶즷즸즹즺즻즼즽즾즿지직짂짃진짅짆짇질짉짊짋짌짍짎짏짐집짒짓짔징짖짗짘짙짚짛짜짝짞짟짠짡짢짣짤짥짦짧짨짩짪짫짬짭짮짯짰짱짲짳짴짵짶짷째짹짺짻짼짽짾짿쨀쨁쨂쨃쨄쨅쨆쨇쨈쨉쨊쨋쨌쨍쨎쨏쨐쨑쨒쨓쨔쨕쨖쨗쨘쨙쨚쨛쨜쨝쨞쨟쨠쨡쨢쨣쨤쨥쨦쨧쨨쨩쨪쨫쨬쨭쨮쨯쨰쨱쨲쨳쨴쨵쨶쨷쨸쨹쨺쨻쨼쨽쨾쨿쩀쩁쩂쩃쩄쩅쩆쩇쩈쩉쩊쩋쩌쩍쩎쩏쩐쩑쩒쩓쩔쩕쩖쩗쩘쩙쩚쩛쩜쩝쩞쩟쩠쩡쩢쩣쩤쩥쩦쩧쩨쩩쩪쩫쩬쩭쩮쩯쩰쩱쩲쩳쩴쩵쩶쩷쩸쩹쩺쩻쩼쩽쩾쩿쪀쪁쪂쪃쪄쪅쪆쪇쪈쪉쪊쪋쪌쪍쪎쪏쪐쪑쪒쪓쪔쪕쪖쪗쪘쪙쪚쪛쪜쪝쪞쪟쪠쪡쪢쪣쪤쪥쪦쪧쪨쪩쪪쪫쪬쪭쪮쪯쪰쪱쪲쪳쪴쪵쪶쪷쪸쪹쪺쪻쪼쪽쪾쪿쫀쫁쫂쫃쫄쫅쫆쫇쫈쫉쫊쫋쫌쫍쫎쫏쫐쫑쫒쫓쫔쫕쫖쫗쫘쫙쫚쫛쫜쫝쫞쫟쫠쫡쫢쫣쫤쫥쫦쫧쫨쫩쫪쫫쫬쫭쫮쫯쫰쫱쫲쫳쫴쫵쫶쫷쫸쫹쫺쫻쫼쫽쫾쫿쬀쬁쬂쬃쬄쬅쬆쬇쬈쬉쬊쬋쬌쬍쬎쬏쬐쬑쬒쬓쬔쬕쬖쬗쬘쬙쬚쬛쬜쬝쬞쬟쬠쬡쬢쬣쬤쬥쬦쬧쬨쬩쬪쬫쬬쬭쬮쬯쬰쬱쬲쬳쬴쬵쬶쬷쬸쬹쬺쬻쬼쬽쬾쬿쭀쭁쭂쭃쭄쭅쭆쭇쭈쭉쭊쭋쭌쭍쭎쭏쭐쭑쭒쭓쭔쭕쭖쭗쭘쭙쭚쭛쭜쭝쭞쭟쭠쭡쭢쭣쭤쭥쭦쭧쭨쭩쭪쭫쭬쭭쭮쭯쭰쭱쭲쭳쭴쭵쭶쭷쭸쭹쭺쭻쭼쭽쭾쭿쮀쮁쮂쮃쮄쮅쮆쮇쮈쮉쮊쮋쮌쮍쮎쮏쮐쮑쮒쮓쮔쮕쮖쮗쮘쮙쮚쮛쮜쮝쮞쮟쮠쮡쮢쮣쮤쮥쮦쮧쮨쮩쮪쮫쮬쮭쮮쮯쮰쮱쮲쮳쮴쮵쮶쮷쮸쮹쮺쮻쮼쮽쮾쮿쯀쯁쯂쯃쯄쯅쯆쯇쯈쯉쯊쯋쯌쯍쯎쯏쯐쯑쯒쯓쯔쯕쯖쯗쯘쯙쯚쯛쯜쯝쯞쯟쯠쯡쯢쯣쯤쯥쯦쯧쯨쯩쯪쯫쯬쯭쯮쯯쯰쯱쯲쯳쯴쯵쯶쯷쯸쯹쯺쯻쯼쯽쯾쯿찀찁찂찃찄찅찆찇찈찉찊찋찌찍찎찏찐찑찒찓찔찕찖찗찘찙찚찛찜찝찞찟찠찡찢찣찤찥찦찧차착찪찫찬찭찮찯찰찱찲찳찴찵찶찷참찹찺찻찼창찾찿챀챁챂챃채책챆챇챈챉챊챋챌챍챎챏챐챑챒챓챔챕챖챗챘챙챚챛챜챝챞챟챠챡챢챣챤챥챦챧챨챩챪챫챬챭챮챯챰챱챲챳챴챵챶챷챸챹챺챻챼챽챾챿첀첁첂첃첄첅첆첇첈첉첊첋첌첍첎첏첐첑첒첓첔첕첖첗처척첚첛천첝첞첟철첡첢첣첤첥첦첧첨첩첪첫첬청첮첯첰첱첲첳체첵첶첷첸첹첺첻첼첽첾첿쳀쳁쳂쳃쳄쳅쳆쳇쳈쳉쳊쳋쳌쳍쳎쳏쳐쳑쳒쳓쳔쳕쳖쳗쳘쳙쳚쳛쳜쳝쳞쳟쳠쳡쳢쳣쳤쳥쳦쳧쳨쳩쳪쳫쳬쳭쳮쳯쳰쳱쳲쳳쳴쳵쳶쳷쳸쳹쳺쳻쳼쳽쳾쳿촀촁촂촃촄촅촆촇초촉촊촋촌촍촎촏촐촑촒촓촔촕촖촗촘촙촚촛촜총촞촟촠촡촢촣촤촥촦촧촨촩촪촫촬촭촮촯촰촱촲촳촴촵촶촷촸촹촺촻촼촽촾촿쵀쵁쵂쵃쵄쵅쵆쵇쵈쵉쵊쵋쵌쵍쵎쵏쵐쵑쵒쵓쵔쵕쵖쵗쵘쵙쵚쵛최쵝쵞쵟쵠쵡쵢쵣쵤쵥쵦쵧쵨쵩쵪쵫쵬쵭쵮쵯쵰쵱쵲쵳쵴쵵쵶쵷쵸쵹쵺쵻쵼쵽쵾쵿춀춁춂춃춄춅춆춇춈춉춊춋춌춍춎춏춐춑춒춓추축춖춗춘춙춚춛출춝춞춟춠춡춢춣춤춥춦춧춨충춪춫춬춭춮춯춰춱춲춳춴춵춶춷춸춹춺춻춼춽춾춿췀췁췂췃췄췅췆췇췈췉췊췋췌췍췎췏췐췑췒췓췔췕췖췗췘췙췚췛췜췝췞췟췠췡췢췣췤췥췦췧취췩췪췫췬췭췮췯췰췱췲췳췴췵췶췷췸췹췺췻췼췽췾췿츀츁츂츃츄츅츆츇츈츉츊츋츌츍츎츏츐츑츒츓츔츕츖츗츘츙츚츛츜츝츞츟츠측츢츣츤츥츦츧츨츩츪츫츬츭츮츯츰츱츲츳츴층츶츷츸츹츺츻츼츽츾츿칀칁칂칃칄칅칆칇칈칉칊칋칌칍칎칏칐칑칒칓칔칕칖칗치칙칚칛친칝칞칟칠칡칢칣칤칥칦칧침칩칪칫칬칭칮칯칰칱칲칳카칵칶칷칸칹칺칻칼칽칾칿캀캁캂캃캄캅캆캇캈캉캊캋캌캍캎캏캐캑캒캓캔캕캖캗캘캙캚캛캜캝캞캟캠캡캢캣캤캥캦캧캨캩캪캫캬캭캮캯캰캱캲캳캴캵캶캷캸캹캺캻캼캽캾캿컀컁컂컃컄컅컆컇컈컉컊컋컌컍컎컏컐컑컒컓컔컕컖컗컘컙컚컛컜컝컞컟컠컡컢컣커컥컦컧컨컩컪컫컬컭컮컯컰컱컲컳컴컵컶컷컸컹컺컻컼컽컾컿케켁켂켃켄켅켆켇켈켉켊켋켌켍켎켏켐켑켒켓켔켕켖켗켘켙켚켛켜켝켞켟켠켡켢켣켤켥켦켧켨켩켪켫켬켭켮켯켰켱켲켳켴켵켶켷켸켹켺켻켼켽켾켿콀콁콂콃콄콅콆콇콈콉콊콋콌콍콎콏콐콑콒콓코콕콖콗콘콙콚콛콜콝콞콟콠콡콢콣콤콥콦콧콨콩콪콫콬콭콮콯콰콱콲콳콴콵콶콷콸콹콺콻콼콽콾콿쾀쾁쾂쾃쾄쾅쾆쾇쾈쾉쾊쾋쾌쾍쾎쾏쾐쾑쾒쾓쾔쾕쾖쾗쾘쾙쾚쾛쾜쾝쾞쾟쾠쾡쾢쾣쾤쾥쾦쾧쾨쾩쾪쾫쾬쾭쾮쾯쾰쾱쾲쾳쾴쾵쾶쾷쾸쾹쾺쾻쾼쾽쾾쾿쿀쿁쿂쿃쿄쿅쿆쿇쿈쿉쿊쿋쿌쿍쿎쿏쿐쿑쿒쿓쿔쿕쿖쿗쿘쿙쿚쿛쿜쿝쿞쿟쿠쿡쿢쿣쿤쿥쿦쿧쿨쿩쿪쿫쿬쿭쿮쿯쿰쿱쿲쿳쿴쿵쿶쿷쿸쿹쿺쿻쿼쿽쿾쿿퀀퀁퀂퀃퀄퀅퀆퀇퀈퀉퀊퀋퀌퀍퀎퀏퀐퀑퀒퀓퀔퀕퀖퀗퀘퀙퀚퀛퀜퀝퀞퀟퀠퀡퀢퀣퀤퀥퀦퀧퀨퀩퀪퀫퀬퀭퀮퀯퀰퀱퀲퀳퀴퀵퀶퀷퀸퀹퀺퀻퀼퀽퀾퀿큀큁큂큃큄큅큆큇큈큉큊큋큌큍큎큏큐큑큒큓큔큕큖큗큘큙큚큛큜큝큞큟큠큡큢큣큤큥큦큧큨큩큪큫크큭큮큯큰큱큲큳클큵큶큷큸큹큺큻큼큽큾큿킀킁킂킃킄킅킆킇킈킉킊킋킌킍킎킏킐킑킒킓킔킕킖킗킘킙킚킛킜킝킞킟킠킡킢킣키킥킦킧킨킩킪킫킬킭킮킯킰킱킲킳킴킵킶킷킸킹킺킻킼킽킾킿타탁탂탃탄탅탆탇탈탉탊탋탌탍탎탏탐탑탒탓탔탕탖탗탘탙탚탛태택탞탟탠탡탢탣탤탥탦탧탨탩탪탫탬탭탮탯탰탱탲탳탴탵탶탷탸탹탺탻탼탽탾탿턀턁턂턃턄턅턆턇턈턉턊턋턌턍턎턏턐턑턒턓턔턕턖턗턘턙턚턛턜턝턞턟턠턡턢턣턤턥턦턧턨턩턪턫턬턭턮턯터턱턲턳턴턵턶턷털턹턺턻턼턽턾턿텀텁텂텃텄텅텆텇텈텉텊텋테텍텎텏텐텑텒텓텔텕텖텗텘텙텚텛템텝텞텟텠텡텢텣텤텥텦텧텨텩텪텫텬텭텮텯텰텱텲텳텴텵텶텷텸텹텺텻텼텽텾텿톀톁톂톃톄톅톆톇톈톉톊톋톌톍톎톏톐톑톒톓톔톕톖톗톘톙톚톛톜톝톞톟토톡톢톣톤톥톦톧톨톩톪톫톬톭톮톯톰톱톲톳톴통톶톷톸톹톺톻톼톽톾톿퇀퇁퇂퇃퇄퇅퇆퇇퇈퇉퇊퇋퇌퇍퇎퇏퇐퇑퇒퇓퇔퇕퇖퇗퇘퇙퇚퇛퇜퇝퇞퇟퇠퇡퇢퇣퇤퇥퇦퇧퇨퇩퇪퇫퇬퇭퇮퇯퇰퇱퇲퇳퇴퇵퇶퇷퇸퇹퇺퇻퇼퇽퇾퇿툀툁툂툃툄툅툆툇툈툉툊툋툌툍툎툏툐툑툒툓툔툕툖툗툘툙툚툛툜툝툞툟툠툡툢툣툤툥툦툧툨툩툪툫투툭툮툯툰툱툲툳툴툵툶툷툸툹툺툻툼툽툾툿퉀퉁퉂퉃퉄퉅퉆퉇퉈퉉퉊퉋퉌퉍퉎퉏퉐퉑퉒퉓퉔퉕퉖퉗퉘퉙퉚퉛퉜퉝퉞퉟퉠퉡퉢퉣퉤퉥퉦퉧퉨퉩퉪퉫퉬퉭퉮퉯퉰퉱퉲퉳퉴퉵퉶퉷퉸퉹퉺퉻퉼퉽퉾퉿튀튁튂튃튄튅튆튇튈튉튊튋튌튍튎튏튐튑튒튓튔튕튖튗튘튙튚튛튜튝튞튟튠튡튢튣튤튥튦튧튨튩튪튫튬튭튮튯튰튱튲튳튴튵튶튷트특튺튻튼튽튾튿틀틁틂틃틄틅틆틇틈틉틊틋틌틍틎틏틐틑틒틓틔틕틖틗틘틙틚틛틜틝틞틟틠틡틢틣틤틥틦틧틨틩틪틫틬틭틮틯티틱틲틳틴틵틶틷틸틹틺틻틼틽틾틿팀팁팂팃팄팅팆팇팈팉팊팋파팍팎팏판팑팒팓팔팕팖팗팘팙팚팛팜팝팞팟팠팡팢팣팤팥팦팧패팩팪팫팬팭팮팯팰팱팲팳팴팵팶팷팸팹팺팻팼팽팾팿퍀퍁퍂퍃퍄퍅퍆퍇퍈퍉퍊퍋퍌퍍퍎퍏퍐퍑퍒퍓퍔퍕퍖퍗퍘퍙퍚퍛퍜퍝퍞퍟퍠퍡퍢퍣퍤퍥퍦퍧퍨퍩퍪퍫퍬퍭퍮퍯퍰퍱퍲퍳퍴퍵퍶퍷퍸퍹퍺퍻퍼퍽퍾퍿펀펁펂펃펄펅펆펇펈펉펊펋펌펍펎펏펐펑펒펓펔펕펖펗페펙펚펛펜펝펞펟펠펡펢펣펤펥펦펧펨펩펪펫펬펭펮펯펰펱펲펳펴펵펶펷편펹펺펻펼펽펾펿폀폁폂폃폄폅폆폇폈평폊폋폌폍폎폏폐폑폒폓폔폕폖폗폘폙폚폛폜폝폞폟폠폡폢폣폤폥폦폧폨폩폪폫포폭폮폯폰폱폲폳폴폵폶폷폸폹폺폻폼폽폾폿퐀퐁퐂퐃퐄퐅퐆퐇퐈퐉퐊퐋퐌퐍퐎퐏퐐퐑퐒퐓퐔퐕퐖퐗퐘퐙퐚퐛퐜퐝퐞퐟퐠퐡퐢퐣퐤퐥퐦퐧퐨퐩퐪퐫퐬퐭퐮퐯퐰퐱퐲퐳퐴퐵퐶퐷퐸퐹퐺퐻퐼퐽퐾퐿푀푁푂푃푄푅푆푇푈푉푊푋푌푍푎푏푐푑푒푓푔푕푖푗푘푙푚푛표푝푞푟푠푡푢푣푤푥푦푧푨푩푪푫푬푭푮푯푰푱푲푳푴푵푶푷푸푹푺푻푼푽푾푿풀풁풂풃풄풅풆풇품풉풊풋풌풍풎풏풐풑풒풓풔풕풖풗풘풙풚풛풜풝풞풟풠풡풢풣풤풥풦풧풨풩풪풫풬풭풮풯풰풱풲풳풴풵풶풷풸풹풺풻풼풽풾풿퓀퓁퓂퓃퓄퓅퓆퓇퓈퓉퓊퓋퓌퓍퓎퓏퓐퓑퓒퓓퓔퓕퓖퓗퓘퓙퓚퓛퓜퓝퓞퓟퓠퓡퓢퓣퓤퓥퓦퓧퓨퓩퓪퓫퓬퓭퓮퓯퓰퓱퓲퓳퓴퓵퓶퓷퓸퓹퓺퓻퓼퓽퓾퓿픀픁픂픃프픅픆픇픈픉픊픋플픍픎픏픐픑픒픓픔픕픖픗픘픙픚픛픜픝픞픟픠픡픢픣픤픥픦픧픨픩픪픫픬픭픮픯픰픱픲픳픴픵픶픷픸픹픺픻피픽픾픿핀핁핂핃필핅핆핇핈핉핊핋핌핍핎핏핐핑핒핓핔핕핖핗하학핚핛한핝핞핟할핡핢핣핤핥핦핧함합핪핫핬항핮핯핰핱핲핳해핵핶핷핸핹핺핻핼핽핾핿햀햁햂햃햄햅햆햇했행햊햋햌햍햎햏햐햑햒햓햔햕햖햗햘햙햚햛햜햝햞햟햠햡햢햣햤향햦햧햨햩햪햫햬햭햮햯햰햱햲햳햴햵햶햷햸햹햺햻햼햽햾햿헀헁헂헃헄헅헆헇허헉헊헋헌헍헎헏헐헑헒헓헔헕헖헗험헙헚헛헜헝헞헟헠헡헢헣헤헥헦헧헨헩헪헫헬헭헮헯헰헱헲헳헴헵헶헷헸헹헺헻헼헽헾헿혀혁혂혃현혅혆혇혈혉혊혋혌혍혎혏혐협혒혓혔형혖혗혘혙혚혛혜혝혞혟혠혡혢혣혤혥혦혧혨혩혪혫혬혭혮혯혰혱혲혳혴혵혶혷호혹혺혻혼혽혾혿홀홁홂홃홄홅홆홇홈홉홊홋홌홍홎홏홐홑홒홓화확홖홗환홙홚홛활홝홞홟홠홡홢홣홤홥홦홧홨황홪홫홬홭홮홯홰홱홲홳홴홵홶홷홸홹홺홻홼홽홾홿횀횁횂횃횄횅횆횇횈횉횊횋회획횎횏횐횑횒횓횔횕횖횗횘횙횚횛횜횝횞횟횠횡횢횣횤횥횦횧효횩횪횫횬횭횮횯횰횱횲횳횴횵횶횷횸횹횺횻횼횽횾횿훀훁훂훃후훅훆훇훈훉훊훋훌훍훎훏훐훑훒훓훔훕훖훗훘훙훚훛훜훝훞훟훠훡훢훣훤훥훦훧훨훩훪훫훬훭훮훯훰훱훲훳훴훵훶훷훸훹훺훻훼훽훾훿휀휁휂휃휄휅휆휇휈휉휊휋휌휍휎휏휐휑휒휓휔휕휖휗휘휙휚휛휜휝휞휟휠휡휢휣휤휥휦휧휨휩휪휫휬휭휮휯휰휱휲휳휴휵휶휷휸휹휺휻휼휽휾휿흀흁흂흃흄흅흆흇흈흉흊흋흌흍흎흏흐흑흒흓흔흕흖흗흘흙흚흛흜흝흞흟흠흡흢흣흤흥흦흧흨흩흪흫희흭흮흯흰흱흲흳흴흵흶흷흸흹흺흻흼흽흾흿힀힁힂힃힄힅힆힇히힉힊힋힌힍힎힏힐힑힒힓힔힕힖힗힘힙힚힛힜힝힞힟힠힡힢힣ힰힱힲힳힴힵힶힷힸힹힺힻힼힽힾힿퟀퟁퟂퟃퟄퟅퟆퟋퟌퟍퟎퟏퟐퟑퟒퟓퟔퟕퟖퟗퟘퟙퟚퟛퟜퟝퟞퟟퟠퟡퟢퟣퟤퟥퟦퟧퟨퟩퟪퟫퟬퟭퟮퟯퟰퟱퟲퟳퟴퟵퟶퟷퟸퟹퟺퟻ???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????􏰀???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????豈更車賈滑串句龜龜契金喇奈懶癩羅蘿螺裸邏樂洛烙珞落酪駱亂卵欄爛蘭鸞嵐濫藍襤拉臘蠟廊朗浪狼郎來冷勞擄櫓爐盧老蘆虜路露魯鷺碌祿綠菉錄鹿論壟弄籠聾牢磊賂雷壘屢樓淚漏累縷陋勒肋凜凌稜綾菱陵讀拏樂諾丹寧怒率異北磻便復不泌數索參塞省葉說殺辰沈拾若掠略亮兩凉梁糧良諒量勵呂女廬旅濾礪閭驪麗黎力曆歷轢年憐戀撚漣煉璉秊練聯輦蓮連鍊列劣咽烈裂說廉念捻殮簾獵令囹寧嶺怜玲瑩羚聆鈴零靈領例禮醴隸惡了僚寮尿料樂燎療蓼遼龍暈阮劉杻柳流溜琉留硫紐類六戮陸倫崙淪輪律慄栗率隆利吏履易李梨泥理痢罹裏裡里離匿溺吝燐璘藺隣鱗麟林淋臨立笠粒狀炙識什茶刺切度拓糖宅洞暴輻行降見廓兀嗀﨎﨏塚﨑晴﨓﨔凞猪益礼神祥福靖精羽﨟蘒﨡諸﨣﨤逸都﨧﨨﨩飯飼館鶴郞隷侮僧免勉勤卑喝嘆器塀墨層屮悔慨憎懲敏既暑梅海渚漢煮爫琢碑社祉祈祐祖祝禍禎穀突節練縉繁署者臭艹艹著褐視謁謹賓贈辶逸難響頻恵𤋮舘並况全侀充冀勇勺喝啕喙嗢塚墳奄奔婢嬨廒廙彩徭惘慎愈憎慠懲戴揄搜摒敖晴朗望杖歹殺流滛滋漢瀞煮瞧爵犯猪瑱甆画瘝瘟益盛直睊着磌窱節类絛練缾者荒華蝹襁覆視調諸請謁諾諭謹變贈輸遲醙鉶陼難靖韛響頋頻鬒龜𢡊𢡄𣏕㮝䀘䀹𥉉𥳐𧻓齃龎fffiflffifflſtstﬓﬔﬕﬖﬗיִﬞײַﬠﬡﬢﬣﬤﬥﬦﬧﬨ﬩שׁשׂשּׁשּׂאַאָאּבּגּדּהּוּזּטּיּךּכּלּמּנּסּףּפּצּקּרּשּתּוֹבֿכֿפֿﭏﭐﭑﭒﭓﭔﭕﭖﭗﭘﭙﭚﭛﭜﭝﭞﭟﭠﭡﭢﭣﭤﭥﭦﭧﭨﭩﭪﭫﭬﭭﭮﭯﭰﭱﭲﭳﭴﭵﭶﭷﭸﭹﭺﭻﭼﭽﭾﭿﮀﮁﮂﮃﮄﮅﮆﮇﮈﮉﮊﮋﮌﮍﮎﮏﮐﮑﮒﮓﮔﮕﮖﮗﮘﮙﮚﮛﮜﮝﮞﮟﮠﮡﮢﮣﮤﮥﮦﮧﮨﮩﮪﮫﮬﮭﮮﮯﮰﮱ﮲﮳﮴﮵﮶﮷﮸﮹﮺﮻﮼﮽﮾﮿﯀﯁ﯓﯔﯕﯖﯗﯘﯙﯚﯛﯜﯝﯞﯟﯠﯡﯢﯣﯤﯥﯦﯧﯨﯩﯪﯫﯬﯭﯮﯯﯰﯱﯲﯳﯴﯵﯶﯷﯸﯹﯺﯻﯼﯽﯾﯿﰀﰁﰂﰃﰄﰅﰆﰇﰈﰉﰊﰋﰌﰍﰎﰏﰐﰑﰒﰓﰔﰕﰖﰗﰘﰙﰚﰛﰜﰝﰞﰟﰠﰡﰢﰣﰤﰥﰦﰧﰨﰩﰪﰫﰬﰭﰮﰯﰰﰱﰲﰳﰴﰵﰶﰷﰸﰹﰺﰻﰼﰽﰾﰿﱀﱁﱂﱃﱄﱅﱆﱇﱈﱉﱊﱋﱌﱍﱎﱏﱐﱑﱒﱓﱔﱕﱖﱗﱘﱙﱚﱛﱜﱝﱞﱟﱠﱡﱢﱣﱤﱥﱦﱧﱨﱩﱪﱫﱬﱭﱮﱯﱰﱱﱲﱳﱴﱵﱶﱷﱸﱹﱺﱻﱼﱽﱾﱿﲀﲁﲂﲃﲄﲅﲆﲇﲈﲉﲊﲋﲌﲍﲎﲏﲐﲑﲒﲓﲔﲕﲖﲗﲘﲙﲚﲛﲜﲝﲞﲟﲠﲡﲢﲣﲤﲥﲦﲧﲨﲩﲪﲫﲬﲭﲮﲯﲰﲱﲲﲳﲴﲵﲶﲷﲸﲹﲺﲻﲼﲽﲾﲿﳀﳁﳂﳃﳄﳅﳆﳇﳈﳉﳊﳋﳌﳍﳎﳏﳐﳑﳒﳓﳔﳕﳖﳗﳘﳙﳚﳛﳜﳝﳞﳟﳠﳡﳢﳣﳤﳥﳦﳧﳨﳩﳪﳫﳬﳭﳮﳯﳰﳱﳲﳳﳴﳵﳶﳷﳸﳹﳺﳻﳼﳽﳾﳿﴀﴁﴂﴃﴄﴅﴆﴇﴈﴉﴊﴋﴌﴍﴎﴏﴐﴑﴒﴓﴔﴕﴖﴗﴘﴙﴚﴛﴜﴝﴞﴟﴠﴡﴢﴣﴤﴥﴦﴧﴨﴩﴪﴫﴬﴭﴮﴯﴰﴱﴲﴳﴴﴵﴶﴷﴸﴹﴺﴻﴼﴽ﴾﴿ﵐﵑﵒﵓﵔﵕﵖﵗﵘﵙﵚﵛﵜﵝﵞﵟﵠﵡﵢﵣﵤﵥﵦﵧﵨﵩﵪﵫﵬﵭﵮﵯﵰﵱﵲﵳﵴﵵﵶﵷﵸﵹﵺﵻﵼﵽﵾﵿﶀﶁﶂﶃﶄﶅﶆﶇﶈﶉﶊﶋﶌﶍﶎﶏﶒﶓﶔﶕﶖﶗﶘﶙﶚﶛﶜﶝﶞﶟﶠﶡﶢﶣﶤﶥﶦﶧﶨﶩﶪﶫﶬﶭﶮﶯﶰﶱﶲﶳﶴﶵﶶﶷﶸﶹﶺﶻﶼﶽﶾﶿﷀﷁﷂﷃﷄﷅﷆﷇﷰﷱﷲﷳﷴﷵﷶﷷﷸﷹﷺﷻ﷼﷽︀︁︂︃︄︅︆︇︈︉︊︋︌︍︎️︐︑︒︓︔︕︖︗︘︙︠︡︢︣︤︥︦︰︱︲︳︴︵︶︷︸︹︺︻︼︽︾︿﹀﹁﹂﹃﹄﹅﹆﹇﹈﹉﹊﹋﹌﹍﹎﹏﹐﹑﹒﹔﹕﹖﹗﹘﹙﹚﹛﹜﹝﹞﹟﹠﹡﹢﹣﹤﹥﹦﹨﹩﹪﹫ﹰﹱﹲﹳﹴﹶﹷﹸﹹﹺﹻﹼﹽﹾﹿﺀﺁﺂﺃﺄﺅﺆﺇﺈﺉﺊﺋﺌﺍﺎﺏﺐﺑﺒﺓﺔﺕﺖﺗﺘﺙﺚﺛﺜﺝﺞﺟﺠﺡﺢﺣﺤﺥﺦﺧﺨﺩﺪﺫﺬﺭﺮﺯﺰﺱﺲﺳﺴﺵﺶﺷﺸﺹﺺﺻﺼﺽﺾﺿﻀﻁﻂﻃﻄﻅﻆﻇﻈﻉﻊﻋﻌﻍﻎﻏﻐﻑﻒﻓﻔﻕﻖﻗﻘﻙﻚﻛﻜﻝﻞﻟﻠﻡﻢﻣﻤﻥﻦﻧﻨﻩﻪﻫﻬﻭﻮﻯﻰﻱﻲﻳﻴﻵﻶﻷﻸﻹﻺﻻﻼ!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~⦅⦆。「」、・ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙゚ᅠᄀᄁᆪᄂᆬᆭᄃᄄᄅᆰᆱᆲᆳᆴᆵᄚᄆᄇᄈᄡᄉᄊᄋᄌᄍᄎᄏᄐᄑ하ᅢᅣᅤᅥᅦᅧᅨᅩᅪᅫᅬᅭᅮᅯᅰᅱᅲᅳᅴᅵ¢£¬ ̄¦¥₩│←↑→↓■○�‬‬‬ +#!#😀😃😁😎😒😞😍🙂😆😊😉 +#!#ऀँंःऄअआइईउऊऋऌऍऎएऐऑऒओऔकखगघङचछजझञटठडढणतथदधनऩपफबभमयरऱलळऴवशषसहऺऻ़ऽािीुूृॄॅॆेैॉॊोौ्ॎॏॐ॒॑॓॔ॕॖॗक़ख़ग़ज़ड़ढ़फ़य़ॠॡॢॣ।॥०१२३४५६७८९॰ॱॲॳॴॵॶॷॹॺॻॼॽॾॿ +~~END~~ + +DROP TABLE TEXT_dt; diff --git a/contrib/test/JDBC/expected/TestThrow.out b/contrib/test/JDBC/expected/TestThrow.out new file mode 100644 index 00000000000..a5f88ff029f --- /dev/null +++ b/contrib/test/JDBC/expected/TestThrow.out @@ -0,0 +1,659 @@ +CREATE TABLE throwTable (a INT); +go + +CREATE PROC throwProc1 AS +BEGIN + INSERT INTO throwTable VALUES (1); + THROW 51000, 'Throw error', 1; + INSERT INTO throwTable VALUES (2); +END +go + +CREATE PROC throwProc2 AS +BEGIN + INSERT INTO throwTable VALUES (111); + EXEC throwProc1; + INSERT INTO throwTable VALUES (222); +END +go + +CREATE PROC reThrowProc1 AS +BEGIN + BEGIN TRY + INSERT INTO throwTable VALUES (1); + THROW 51000, 'Throw error', 1; + INSERT INTO throwTable VALUES (2); + END TRY + BEGIN CATCH + THROW; + SELECT 'THROW SHOULD NOT CONTINUE' + END CATCH +END +go + +CREATE PROC reThrowProc2 AS +BEGIN + INSERT INTO throwTable VALUES (111); + EXEC reThrowProc1; + INSERT INTO throwTable VALUES (222); +END +go + +/* Error -- THORW; can only be called in CATCH block */ +THROW; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: THROW without parameters should be executed inside a CATCH block)~~ + + +/* Error -- THROW; can only be called in CATCH block */ +BEGIN TRY + THROW; +END TRY +BEGIN CATCH + THROW; +END CATCH +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: THROW without parameters should be executed inside a CATCH block)~~ + + +/* Re-throw current caught error */ +BEGIN TRY + THROW 50000, 'Throw error', 1; +END TRY +BEGIN CATCH + THROW; + SELECT 'THROW SHOULD NOT CONTINUE' +END CATCH +go +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: Throw error)~~ + + +/* Nested TRY...CATCH, test 1 */ +BEGIN TRY + BEGIN TRY + PRINT 100/0; + END TRY + BEGIN CATCH + THROW 50000, 'Throw error', 1; + END CATCH +END TRY +BEGIN CATCH + THROW; + SELECT 'THROW SHOULD NOT CONTINUE' +END CATCH +go +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: Throw error)~~ + + +/* Nested TRY...CATCH, test 2 */ +BEGIN TRY + PRINT 100/0; +END TRY +BEGIN CATCH + BEGIN TRY + THROW; + END TRY + BEGIN CATCH + THROW; + SELECT 'THROW SHOULD NOT CONTINUE' + END CATCH +END CATCH +go +~~ERROR (Code: 8134)~~ + +~~ERROR (Message: division by zero)~~ + + + + +/* XACT_ABORT OFF */ +/* 1. Not in TRY...CATCH block, throw exception */ +/* Not in TRY...CATCH block */ +DECLARE @err_no INT; +DECLARE @msg VARCHAR(50); +DECLARE @state INT; +SET @err_no = 51000; +SET @msg = N'Throw error'; +SET @state = 1; +THROW @err_no, @msg, @state; +go +~~ERROR (Code: 51000)~~ + +~~ERROR (Message: Throw error)~~ + + +BEGIN TRAN + INSERT INTO throwTable VALUES (3); + THROW 50000, 'Throw error', 1; + INSERT INTO throwTable VALUES (4); +go +~~ROW COUNT: 1~~ + +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: Throw error)~~ + +SELECT xact_state(); +SELECT @@trancount; +SELECT * FROM throwTable; +IF @@trancount > 0 ROLLBACK TRAN; +go +~~START~~ +smallint +1 +~~END~~ + +~~START~~ +int +1 +~~END~~ + +~~START~~ +int +3 +~~END~~ + +TRUNCATE TABLE throwTable +go + +/* Nested procedure call */ +BEGIN TRAN + EXEC throwProc2; +go +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 51000)~~ + +~~ERROR (Message: Throw error)~~ + +SELECT xact_state(); +SELECT @@trancount; +SELECT * FROM throwTable; +IF @@trancount > 0 ROLLBACK TRANSACTION; +go +~~START~~ +smallint +1 +~~END~~ + +~~START~~ +int +1 +~~END~~ + +~~START~~ +int +111 +1 +~~END~~ + +TRUNCATE TABLE throwTable +go + +BEGIN TRAN + EXEC reThrowProc2; +go +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 51000)~~ + +~~ERROR (Message: Throw error)~~ + +SELECT xact_state(); +SELECT @@trancount; +SELECT * FROM throwTable; +IF @@trancount > 0 ROLLBACK TRANSACTION; +go +~~START~~ +smallint +1 +~~END~~ + +~~START~~ +int +1 +~~END~~ + +~~START~~ +int +111 +1 +~~END~~ + +TRUNCATE TABLE throwTable +go + +/* 2. In TRY...CATCH block, catchable, abort batch without rollback */ +/* THROW in TRY...CATCH */ +BEGIN TRY + BEGIN TRAN + INSERT INTO throwTable VALUES (3); + THROW 50000, 'Throw error', 1; + INSERT INTO throwTable VALUES (4); + COMMIT TRAN +END TRY +BEGIN CATCH + SELECT xact_state(); + SELECT @@trancount; + SELECT * FROM throwTable; + IF @@trancount > 0 ROLLBACK TRAN; +END CATCH +go +~~ROW COUNT: 1~~ + +~~START~~ +smallint +1 +~~END~~ + +~~START~~ +int +1 +~~END~~ + +~~START~~ +int +3 +~~END~~ + +TRUNCATE TABLE throwTable +go + +/* Procedure call in TRY...CATCH */ +BEGIN TRY + BEGIN TRAN + SELECT xact_state(); + EXEC throwProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); + SELECT @@trancount; + SELECT * FROM throwTable; + IF @@trancount > 0 ROLLBACK TRAN; +END CATCH +go +~~START~~ +smallint +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +smallint +1 +~~END~~ + +~~START~~ +int +1 +~~END~~ + +~~START~~ +int +1 +~~END~~ + +TRUNCATE TABLE throwTable +go + +/* Nested TRY...CATCH, test 1 */ +BEGIN TRY + BEGIN TRY + INSERT INTO throwTable VALUES (3); + THROW 50000, 'Throw error', 1; + INSERT INTO throwTable VALUES (4); + END TRY + BEGIN CATCH + INSERT INTO throwTable VALUES (5); + END CATCH +END TRY +BEGIN CATCH + INSERT INTO throwTable VALUES (6); +END CATCH +go +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +SELECT * FROM throwTable +go +~~START~~ +int +3 +5 +~~END~~ + +TRUNCATE TABLE throwTable +go + +/* Nested TRY...CATCH, test 2 */ +BEGIN TRY + BEGIN TRY + SELECT 100/0; + END TRY + BEGIN CATCH + INSERT INTO throwTable VALUES (3); + THROW 50000, 'Throw error', 1; + INSERT INTO throwTable VALUES (4); + END CATCH +END TRY +BEGIN CATCH + INSERT INTO throwTable VALUES (6); +END CATCH +go +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +SELECT * FROM throwTable +go +~~START~~ +int +3 +6 +~~END~~ + +TRUNCATE TABLE throwTable +go + +/* Nested TRY...CATCH, test 3 */ +BEGIN TRY + SELECT 100/0; +END TRY +BEGIN CATCH + BEGIN TRY + INSERT INTO throwTable VALUES (3); + THROW 50000, 'Throw error', 1; + INSERT INTO throwTable VALUES (4); + END TRY + BEGIN CATCH + INSERT INTO throwTable VALUES (5); + END CATCH +END CATCH +go +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +SELECT * FROM throwTable +go +~~START~~ +int +3 +5 +~~END~~ + +TRUNCATE TABLE throwTable +go + +/* XACT_ABORT ON */ +SET XACT_ABORT ON; +go + +/* 1. Not in TRY...CATCH block, rollback transaction */ +/* Not in TRY...CATCH block */ +BEGIN TRAN + INSERT INTO throwTable VALUES (3); + THROW 50000, 'Throw error', 1; + INSERT INTO throwTable VALUES (4); +go +~~ROW COUNT: 1~~ + +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: Throw error)~~ + +SELECT xact_state(); +SELECT @@trancount; +SELECT * FROM throwTable; +IF @@trancount > 0 ROLLBACK TRAN; +go +~~START~~ +smallint +0 +~~END~~ + +~~START~~ +int +0 +~~END~~ + +~~START~~ +int +~~END~~ + +TRUNCATE TABLE throwTable +go + +/* Nested procedure call */ +BEGIN TRAN + EXEC throwProc2; +go +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 51000)~~ + +~~ERROR (Message: Throw error)~~ + +SELECT xact_state(); +SELECT @@trancount; +SELECT * FROM throwTable; +IF @@trancount > 0 ROLLBACK TRANSACTION; +go +~~START~~ +smallint +0 +~~END~~ + +~~START~~ +int +0 +~~END~~ + +~~START~~ +int +~~END~~ + +TRUNCATE TABLE throwTable +go + +/* 2. In TRY...CATCH block, catchable, abort batch without rollback */ +/* THROW in TRY...CATCH */ +BEGIN TRY + BEGIN TRAN + INSERT INTO throwTable VALUES (3); + THROW 50000, 'Throw error', 1; + INSERT INTO throwTable VALUES (4); + COMMIT TRAN +END TRY +BEGIN CATCH + SELECT xact_state(); + SELECT @@trancount; + SELECT * FROM throwTable; + IF @@trancount > 0 ROLLBACK TRAN; +END CATCH +go +~~ROW COUNT: 1~~ + +~~START~~ +smallint +-1 +~~END~~ + +~~START~~ +int +1 +~~END~~ + +~~START~~ +int +3 +~~END~~ + +TRUNCATE TABLE throwTable +go + +/* Procedure call in TRY...CATCH */ +BEGIN TRY + BEGIN TRAN + SELECT xact_state(); + EXEC throwProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); + SELECT @@trancount; + SELECT * FROM throwTable; + IF @@trancount > 0 ROLLBACK TRAN; +END CATCH +go +~~START~~ +smallint +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +smallint +-1 +~~END~~ + +~~START~~ +int +1 +~~END~~ + +~~START~~ +int +1 +~~END~~ + +TRUNCATE TABLE throwTable +go + +/* Nested TRY...CATCH, test 1 */ +BEGIN TRY + BEGIN TRY + INSERT INTO throwTable VALUES (3); + THROW 50000, 'Throw error', 1; + INSERT INTO throwTable VALUES (4); + END TRY + BEGIN CATCH + INSERT INTO throwTable VALUES (5); + END CATCH +END TRY +BEGIN CATCH + INSERT INTO throwTable VALUES (6); +END CATCH +go +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +SELECT * FROM throwTable +go +~~START~~ +int +3 +5 +~~END~~ + +TRUNCATE TABLE throwTable +go + +/* Nested TRY...CATCH, test 2 */ +BEGIN TRY + BEGIN TRY + SELECT 100/0; + END TRY + BEGIN CATCH + INSERT INTO throwTable VALUES (3); + THROW 50000, 'Throw error', 1; + INSERT INTO throwTable VALUES (4); + END CATCH +END TRY +BEGIN CATCH + INSERT INTO throwTable VALUES (6); +END CATCH +go +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +SELECT * FROM throwTable +go +~~START~~ +int +3 +6 +~~END~~ + +TRUNCATE TABLE throwTable +go + +/* Nested TRY...CATCH, test 3 */ +BEGIN TRY + SELECT 100/0; +END TRY +BEGIN CATCH + BEGIN TRY + INSERT INTO throwTable VALUES (3); + THROW 50000, 'Throw error', 1; + INSERT INTO throwTable VALUES (4); + END TRY + BEGIN CATCH + INSERT INTO throwTable VALUES (5); + END CATCH +END CATCH +go +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +SELECT * FROM throwTable +go +~~START~~ +int +3 +5 +~~END~~ + +TRUNCATE TABLE throwTable +go + +-- BABEL-2479 +THROW 50000, 'Throw error', 1; +go +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: Throw error)~~ + + +/* Clean up */ +SET XACT_ABORT OFF; +go +DROP PROC throwProc1; +go +DROP PROC throwProc2; +go +DROP PROC reThrowProc1; +go +DROP PROC reThrowProc2; +go +DROP TABLE throwTable; +go diff --git a/contrib/test/JDBC/expected/TestTime.out b/contrib/test/JDBC/expected/TestTime.out new file mode 100644 index 00000000000..b822af5e123 --- /dev/null +++ b/contrib/test/JDBC/expected/TestTime.out @@ -0,0 +1,300 @@ +Create table TestTime(a time(6)) + +prepst#!# Insert into TestTime Values(?) #!#Time|-|a|-|12:45:37.123|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.123|-|3 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.12|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.1|-|1 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.1234|-|4 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|6 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|5 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-| +~~ROW COUNT: 1~~ + + +select * from TestTime +~~START~~ +time +12:45:37.000000 +12:45:37.000000 +12:45:37.000000 +12:45:37.000000 +12:45:37.000000 +12:45:37.000000 +12:45:37.000000 + +~~END~~ + + +Drop table TestTime + +Create table TestTime(a time(5)) + +prepst#!# Insert into TestTime Values(?) #!#Time|-|a|-|12:45:37.123|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.123|-|3 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.12|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.1|-|1 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.1234|-|4 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|6 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|5 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-| +~~ROW COUNT: 1~~ + + +select * from TestTime +~~START~~ +time +12:45:37.00000 +12:45:37.00000 +12:45:37.00000 +12:45:37.00000 +12:45:37.00000 +12:45:37.00000 +12:45:37.00000 + +~~END~~ + + +Drop table TestTime + +Create table TestTime(a time(4)) + +prepst#!# Insert into TestTime Values(?) #!#Time|-|a|-|12:45:37.123|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.123|-|3 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.12|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.1|-|1 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.1234|-|4 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|6 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|5 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-| +~~ROW COUNT: 1~~ + + +select * from TestTime +~~START~~ +time +12:45:37.0000 +12:45:37.0000 +12:45:37.0000 +12:45:37.0000 +12:45:37.0000 +12:45:37.0000 +12:45:37.0000 + +~~END~~ + + +Drop table TestTime + +Create table TestTime(a time(3)) + +prepst#!# Insert into TestTime Values(?) #!#Time|-|a|-|12:45:37.123|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.123|-|3 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.12|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.1|-|1 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.1234|-|4 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|6 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|5 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-| +~~ROW COUNT: 1~~ + + +select * from TestTime +~~START~~ +time +12:45:37.000 +12:45:37.000 +12:45:37.000 +12:45:37.000 +12:45:37.000 +12:45:37.000 +12:45:37.000 + +~~END~~ + + +Drop table TestTime + +Create table TestTime(a time(2)) + +prepst#!# Insert into TestTime Values(?) #!#Time|-|a|-|12:45:37.123|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.123|-|3 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.12|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.1|-|1 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.1234|-|4 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|6 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|5 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-| +~~ROW COUNT: 1~~ + + +select * from TestTime +~~START~~ +time +12:45:37.00 +12:45:37.00 +12:45:37.00 +12:45:37.00 +12:45:37.00 +12:45:37.00 +12:45:37.00 + +~~END~~ + + +Drop table TestTime + +Create table TestTime(a time(1)) + +prepst#!# Insert into TestTime Values(?) #!#Time|-|a|-|12:45:37.123|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.123|-|3 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.12|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.1|-|1 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.1234|-|4 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|6 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|5 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-| +~~ROW COUNT: 1~~ + + +select * from TestTime +~~START~~ +time +12:45:37.0 +12:45:37.0 +12:45:37.0 +12:45:37.0 +12:45:37.0 +12:45:37.0 +12:45:37.0 + +~~END~~ + + +Drop table TestTime + +Create table TestTime(a time(0)) + +prepst#!# Insert into TestTime Values(?) #!#Time|-|a|-|12:45:37.123|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.123|-|3 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.12|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.1|-|1 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.1234|-|4 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|6 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|5 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-| +~~ROW COUNT: 1~~ + + +select * from TestTime +~~START~~ +time +12:45:37 +12:45:37 +12:45:37 +12:45:37 +12:45:37 +12:45:37 +12:45:37 + +~~END~~ + + +Drop table TestTime diff --git a/contrib/test/JDBC/expected/TestTinyInt.out b/contrib/test/JDBC/expected/TestTinyInt.out new file mode 100644 index 00000000000..73471b08493 --- /dev/null +++ b/contrib/test/JDBC/expected/TestTinyInt.out @@ -0,0 +1,103 @@ +CREATE TABLE TINYINT_dt (a TINYINT) +prepst#!# INSERT INTO TINYINT_dt(a) values(?) #!#TINYINT|-|a|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#TINYINT|-|a|-|-10 +~~ERROR (Code: 220)~~ + +~~ERROR (Message: value for domain tinyint violates check constraint "tinyint_check")~~ + +prepst#!#exec#!#TINYINT|-|a|-|100 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#TINYINT|-|a|-|002 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#TINYINT|-|a|-|029 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#TINYINT|-|a|-|004 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#TINYINT|-|a|-|87 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#TINYINT|-|a|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#TINYINT|-|a|-|255 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#TINYINT|-|a|-| +~~ROW COUNT: 1~~ + +SELECT * FROM TINYINT_dt; +~~START~~ +tinyint +0 +100 +2 +29 +4 +87 +0 +255 + +~~END~~ + +INSERT INTO TINYINT_dt(a) values(0) +~~ROW COUNT: 1~~ + +INSERT INTO TINYINT_dt(a) values(120) +~~ROW COUNT: 1~~ + +INSERT INTO TINYINT_dt(a) values(100) +~~ROW COUNT: 1~~ + +INSERT INTO TINYINT_dt(a) values(004) +~~ROW COUNT: 1~~ + +INSERT INTO TINYINT_dt(a) values(0) +~~ROW COUNT: 1~~ + +INSERT INTO TINYINT_dt(a) values(002) +~~ROW COUNT: 1~~ + +INSERT INTO TINYINT_dt(a) values(86) +~~ROW COUNT: 1~~ + +INSERT INTO TINYINT_dt(a) values(1000) +~~ERROR (Code: 220)~~ + +~~ERROR (Message: value for domain tinyint violates check constraint "tinyint_check")~~ + +INSERT INTO TINYINT_dt(a) values(255) +~~ROW COUNT: 1~~ + +INSERT INTO TINYINT_dt(a) values(NULL) +~~ROW COUNT: 1~~ + +SELECT * FROM TINYINT_dt; +~~START~~ +tinyint +0 +100 +2 +29 +4 +87 +0 +255 + +0 +120 +100 +4 +0 +2 +86 +255 + +~~END~~ + +DROP TABLE TINYINT_dt; diff --git a/contrib/test/JDBC/expected/TestTransactionName.out b/contrib/test/JDBC/expected/TestTransactionName.out new file mode 100644 index 00000000000..bfead419187 --- /dev/null +++ b/contrib/test/JDBC/expected/TestTransactionName.out @@ -0,0 +1,135 @@ + +-- Tests for transaction name in babel +CREATE TABLE TestTxnName(C1 INT); +GO + +-- Transaction name longer than 32 chars no allowed +BEGIN TRANSACTION longname11111111111111111111111111111111111111; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Transaction name length 46 above limit 32)~~ + + +-- Transaction name longer than 32 truncated +DECLARE @txnName varchar(100) = 'a1111111111111111111111111111111truncatethis'; +BEGIN TRAN @txnName; +ROLLBACK TRAN a1111111111111111111111111111111 +GO + +SELECT @@trancount; +GO +~~START~~ +int +0 +~~END~~ + + + +-- Transaction/savepoint names are case sensitive +DECLARE @txnName varchar(100) = 'Abc'; +DECLARE @spName varchar(100) = 'aBc'; +BEGIN TRAN abc; +INSERT INTO TestTxnName VALUES(1); +SAVE TRAN @spName; +INSERT INTO TestTxnName VALUES(2); +SAVE TRAN abC; +INSERT INTO TestTxnName VALUES(3); +SAVE TRAN ABc; +INSERT INTO TestTxnName VALUES(4); +SAVE TRAN AbC; +INSERT INTO TestTxnName VALUES(5); +SAVE TRAN [aBC]; +INSERT INTO TestTxnName VALUES(6); +BEGIN TRAN @txnName; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +SELECT C1 FROM TestTxnName ORDER BY C1; +GO +~~START~~ +int +1 +2 +3 +4 +5 +6 +~~END~~ + + +ROLLBACK TRAN [AbC]; +SELECT C1 FROM TestTxnName ORDER BY C1; +GO +~~START~~ +int +1 +2 +3 +4 +~~END~~ + + +ROLLBACK TRAN ABc; +SELECT C1 FROM TestTxnName ORDER BY C1; +GO +~~START~~ +int +1 +2 +3 +~~END~~ + + +ROLLBACK TRAN aBc; +SELECT C1 FROM TestTxnName ORDER BY C1; +GO +~~START~~ +int +1 +~~END~~ + + +DECLARE @txnName varchar(100) = 'abc'; +ROLLBACK TRAN @txnName; +SELECT C1 FROM TestTxnName ORDER BY C1; +GO +~~START~~ +int +~~END~~ + + +SELECT @@trancount; +GO +~~START~~ +int +0 +~~END~~ + + +DECLARE @txnName varchar(100) = 'abc'; +BEGIN TRAN @txnName; +COMMIT TRAN @txnName; +GO + +SELECT @@trancount; +GO +~~START~~ +int +0 +~~END~~ + + +DROP TABLE TestTxnName; +GO diff --git a/contrib/test/JDBC/expected/TestTransactionSupportForProcedure.out b/contrib/test/JDBC/expected/TestTransactionSupportForProcedure.out new file mode 100644 index 00000000000..9cd7e8958ba --- /dev/null +++ b/contrib/test/JDBC/expected/TestTransactionSupportForProcedure.out @@ -0,0 +1,976 @@ +#setup +create table txnproctable (c1 int not null, c2 varchar(100)) + +# PROC +# BEGIN TRAN +# SAVEPOINT +# ROLLBACK SAVEPOINT +# COMMIT +create procedure txnproc1 as begin tran; insert into txnproctable values (1, 'abc'); save tran sp1; update txnproctable set c1 = c1 + 1; rollback tran sp1; commit tran; +select @@trancount; +~~START~~ +int +0 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#varchar +~~END~~ + +exec txnproc1; +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +select @@trancount; +~~START~~ +int +0 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#varchar +1#!#abc +~~END~~ + + + +# PROC +# BEGIN TRAN +# SAVEPOINT +# ROLLBACK SAVEPOINT +# ROLLBACK +drop procedure txnproc1; +create procedure txnproc1 as begin tran; insert into txnproctable values(2, 'xyz'); save tran sp1; delete from txnproctable; rollback tran sp1; rollback tran; +select @@trancount; +~~START~~ +int +0 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#varchar +1#!#abc +~~END~~ + +exec txnproc1; +~~ROW COUNT: 1~~ + +~~ROW COUNT: 2~~ + +select @@trancount; +~~START~~ +int +0 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#varchar +1#!#abc +~~END~~ + + + +# PROC +# BEGIN TRAN +# SAVEPOINT +# ROLLBACK SAVEPOINT +# COMMIT +drop procedure txnproc1 +create procedure txnproc1 as begin tran; insert into txnproctable values(3, 'dbd'); save tran sp1; update txnproctable set c1 = c1 + 1; rollback tran sp1; +select @@trancount +~~START~~ +int +0 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#varchar +1#!#abc +~~END~~ + +exec txnproc1; +~~ROW COUNT: 1~~ + +~~ROW COUNT: 2~~ + +~~ERROR (Code: 266)~~ + +~~ERROR (Message: Transaction count after execution indicates a mismatch number of BEGIN and COMMIT statements. Previous count 0 current count 1)~~ + +select @@trancount +~~START~~ +int +1 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#varchar +1#!#abc +3#!#dbd +~~END~~ + +commit tran; +select @@trancount +~~START~~ +int +0 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#varchar +1#!#abc +3#!#dbd +~~END~~ + + + +# PROC +# BEGIN TRAN +# SAVEPOINT +# ROLLBACK SAVEPOINT +# COMMIT +drop procedure txnproc1 +create procedure txnproc1 as begin tran; insert into txnproctable values(4, 'sbd'); save tran sp1; update txnproctable set c1 = c1 + 1; +select @@trancount +~~START~~ +int +0 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#varchar +1#!#abc +3#!#dbd +~~END~~ + +exec txnproc1; +~~ROW COUNT: 1~~ + +~~ROW COUNT: 3~~ + +~~ERROR (Code: 266)~~ + +~~ERROR (Message: Transaction count after execution indicates a mismatch number of BEGIN and COMMIT statements. Previous count 0 current count 1)~~ + +select @@trancount +~~START~~ +int +1 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#varchar +2#!#abc +4#!#dbd +5#!#sbd +~~END~~ + +rollback tran sp1; +select @@trancount +~~START~~ +int +1 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#varchar +1#!#abc +3#!#dbd +4#!#sbd +~~END~~ + +commit tran; +select @@trancount +~~START~~ +int +0 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#varchar +1#!#abc +3#!#dbd +4#!#sbd +~~END~~ + + + +# BEGIN TRAN +# PROC +# SAVEPOINT +# ROLLBACK SAVEPOINT +# COMMIT +begin tran; +select @@trancount +~~START~~ +int +1 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#varchar +1#!#abc +3#!#dbd +4#!#sbd +~~END~~ + +drop procedure txnproc1 +create procedure txnproc1 as insert into txnproctable values(5, 'abc'); save tran sp1; update txnproctable set c1 = c1 + 1; rollback tran sp1; +select @@trancount +~~START~~ +int +1 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#varchar +1#!#abc +3#!#dbd +4#!#sbd +~~END~~ + +exec txnproc1; +~~ROW COUNT: 1~~ + +~~ROW COUNT: 4~~ + +select @@trancount +~~START~~ +int +1 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#varchar +1#!#abc +3#!#dbd +4#!#sbd +5#!#abc +~~END~~ + +commit tran; +select @@trancount +~~START~~ +int +0 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#varchar +1#!#abc +3#!#dbd +4#!#sbd +5#!#abc +~~END~~ + + + +# BEGIN TRAN +# PROC +# SAVEPOINT +# ROLLBACK SAVEPOINT +# ROLLBACK +begin tran; +select @@trancount +~~START~~ +int +1 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#varchar +1#!#abc +3#!#dbd +4#!#sbd +5#!#abc +~~END~~ + +drop procedure txnproc1 +create procedure txnproc1 as insert into txnproctable values(6, 'abc'); save tran sp1; update txnproctable set c1 = c1 + 1; rollback tran sp1; +select @@trancount +~~START~~ +int +1 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#varchar +1#!#abc +3#!#dbd +4#!#sbd +5#!#abc +~~END~~ + +exec txnproc1; +~~ROW COUNT: 1~~ + +~~ROW COUNT: 5~~ + +select @@trancount +~~START~~ +int +1 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#varchar +1#!#abc +3#!#dbd +4#!#sbd +5#!#abc +6#!#abc +~~END~~ + +commit tran; +select @@trancount +~~START~~ +int +0 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#varchar +1#!#abc +3#!#dbd +4#!#sbd +5#!#abc +6#!#abc +~~END~~ + + +# BEGIN TRAN +# PROC +# SAVEPOINT +# ROLLBACK SAVEPOINT +# COMMIT +begin tran; +select @@trancount +~~START~~ +int +1 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#varchar +1#!#abc +3#!#dbd +4#!#sbd +5#!#abc +6#!#abc +~~END~~ + +drop procedure txnproc1 +create procedure txnproc1 as insert into txnproctable values(7, 'abc'); save tran sp1; update txnproctable set c1 = c1 + 1; rollback tran sp1; update txnproctable set c1 = c1 + 1; commit tran; +select @@trancount +~~START~~ +int +1 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#varchar +1#!#abc +3#!#dbd +4#!#sbd +5#!#abc +6#!#abc +~~END~~ + +exec txnproc1; +~~ROW COUNT: 1~~ + +~~ROW COUNT: 6~~ + +~~ROW COUNT: 6~~ + +~~ERROR (Code: 266)~~ + +~~ERROR (Message: Transaction count after execution indicates a mismatch number of BEGIN and COMMIT statements. Previous count 1 current count 0)~~ + +select @@trancount +~~START~~ +int +0 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#varchar +2#!#abc +4#!#dbd +5#!#sbd +6#!#abc +7#!#abc +8#!#abc +~~END~~ + + +# BEGIN TRAN +# PROC +# SAVEPOINT +# ROLLBACK SAVEPOINT +# ROLLBACK +begin tran; +select @@trancount +~~START~~ +int +1 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#varchar +2#!#abc +4#!#dbd +5#!#sbd +6#!#abc +7#!#abc +8#!#abc +~~END~~ + +drop procedure txnproc1 +create procedure txnproc1 as insert into txnproctable values(8, 'abc'); save tran sp1; update txnproctable set c1 = c1 + 1; rollback tran sp1; update txnproctable set c1 = c1 + 1; rollback tran; +select @@trancount +~~START~~ +int +1 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#varchar +2#!#abc +4#!#dbd +5#!#sbd +6#!#abc +7#!#abc +8#!#abc +~~END~~ + +exec txnproc1; +~~ROW COUNT: 1~~ + +~~ROW COUNT: 7~~ + +~~ROW COUNT: 7~~ + +~~ERROR (Code: 266)~~ + +~~ERROR (Message: Transaction count after execution indicates a mismatch number of BEGIN and COMMIT statements. Previous count 1 current count 0)~~ + +select @@trancount +~~START~~ +int +0 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#varchar +2#!#abc +4#!#dbd +5#!#sbd +6#!#abc +7#!#abc +8#!#abc +~~END~~ + + +# BEGIN TRAN +# START SAVEPOINT +# PROC +# ROLLBACK SAVEPOINT +# ROLLBACK +begin tran; +select @@trancount +~~START~~ +int +1 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#varchar +2#!#abc +4#!#dbd +5#!#sbd +6#!#abc +7#!#abc +8#!#abc +~~END~~ + +save tran sp1; +select @@trancount +~~START~~ +int +1 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#varchar +2#!#abc +4#!#dbd +5#!#sbd +6#!#abc +7#!#abc +8#!#abc +~~END~~ + +drop procedure txnproc1 +create procedure txnproc1 as insert into txnproctable values(9, 'abc'); update txnproctable set c1 = c1 + 1; +select @@trancount +~~START~~ +int +1 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#varchar +2#!#abc +4#!#dbd +5#!#sbd +6#!#abc +7#!#abc +8#!#abc +~~END~~ + +exec txnproc1; +~~ROW COUNT: 1~~ + +~~ROW COUNT: 7~~ + +rollback tran sp1; +select @@trancount +~~START~~ +int +1 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#varchar +2#!#abc +4#!#dbd +5#!#sbd +6#!#abc +7#!#abc +8#!#abc +~~END~~ + +rollback tran; +select @@trancount +~~START~~ +int +0 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#varchar +2#!#abc +4#!#dbd +5#!#sbd +6#!#abc +7#!#abc +8#!#abc +~~END~~ + + +# BEGIN TRAN +# START SAVEPOINT +# PROC +# ROLLBACK SAVEPOINT +# ROLLBACK +begin tran; +select @@trancount +~~START~~ +int +1 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#varchar +2#!#abc +4#!#dbd +5#!#sbd +6#!#abc +7#!#abc +8#!#abc +~~END~~ + +save tran sp1; +select @@trancount +~~START~~ +int +1 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#varchar +2#!#abc +4#!#dbd +5#!#sbd +6#!#abc +7#!#abc +8#!#abc +~~END~~ + +drop procedure txnproc1 +create procedure txnproc1 as insert into txnproctable values(10, 'abc'); update txnproctable set c1 = c1 + 1; +select @@trancount +~~START~~ +int +1 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#varchar +2#!#abc +4#!#dbd +5#!#sbd +6#!#abc +7#!#abc +8#!#abc +~~END~~ + +exec txnproc1; +~~ROW COUNT: 1~~ + +~~ROW COUNT: 7~~ + +rollback tran sp1; +select @@trancount +~~START~~ +int +1 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#varchar +2#!#abc +4#!#dbd +5#!#sbd +6#!#abc +7#!#abc +8#!#abc +~~END~~ + +commit tran; +select @@trancount +~~START~~ +int +0 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#varchar +2#!#abc +4#!#dbd +5#!#sbd +6#!#abc +7#!#abc +8#!#abc +~~END~~ + + +# BEGIN TRAN +# START SAVEPOINT +# PROC +# ROLLBACK SAVEPOINT +# ROLLBACK +begin tran; +select @@trancount +~~START~~ +int +1 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#varchar +2#!#abc +4#!#dbd +5#!#sbd +6#!#abc +7#!#abc +8#!#abc +~~END~~ + +save tran sp1; +select @@trancount +~~START~~ +int +1 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#varchar +2#!#abc +4#!#dbd +5#!#sbd +6#!#abc +7#!#abc +8#!#abc +~~END~~ + +drop procedure txnproc1 +create procedure txnproc1 as insert into txnproctable values(11, 'abc'); rollback tran sp1; update txnproctable set c1 = c1 + 1; +select @@trancount +~~START~~ +int +1 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#varchar +2#!#abc +4#!#dbd +5#!#sbd +6#!#abc +7#!#abc +8#!#abc +~~END~~ + +exec txnproc1; +~~ROW COUNT: 1~~ + +~~ROW COUNT: 6~~ + +commit tran; +select @@trancount +~~START~~ +int +0 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#varchar +3#!#abc +5#!#dbd +6#!#sbd +7#!#abc +8#!#abc +9#!#abc +~~END~~ + + +# PROC1 +# BEGIN TRAN +# PROC2 +# PROC3 +# BEGIN TRAN +# START SAVEPOINT +# ROLLBACK SAVEPOINT +# COMMIT +# COMMIT +create procedure txnProc3 as begin tran; insert into txnproctable values (16, 'abc'); save tran sp1; update txnproctable set c1 = c1 + 1; rollback tran sp1; +select @@trancount +~~START~~ +int +0 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#varchar +3#!#abc +5#!#dbd +6#!#sbd +7#!#abc +8#!#abc +9#!#abc +~~END~~ + +create procedure txnProc2 as update txnproctable set c1 = c1 + 1; exec txnProc3; commit tran; +select @@trancount +~~START~~ +int +0 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#varchar +3#!#abc +5#!#dbd +6#!#sbd +7#!#abc +8#!#abc +9#!#abc +~~END~~ + +drop procedure txnproc1 +create procedure txnproc1 as delete from txnproctable; begin tran; exec txnProc2; +select @@trancount +~~START~~ +int +0 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#varchar +3#!#abc +5#!#dbd +6#!#sbd +7#!#abc +8#!#abc +9#!#abc +~~END~~ + +exec txnproc1; +~~ROW COUNT: 6~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 266)~~ + +~~ERROR (Message: Transaction count after execution indicates a mismatch number of BEGIN and COMMIT statements. Previous count 1 current count 2)~~ + +~~ERROR (Code: 266)~~ + +~~ERROR (Message: Transaction count after execution indicates a mismatch number of BEGIN and COMMIT statements. Previous count 0 current count 1)~~ + +select @@trancount +~~START~~ +int +1 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#varchar +16#!#abc +~~END~~ + +commit tran; +select @@trancount +~~START~~ +int +0 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#varchar +16#!#abc +~~END~~ + + +# PROC1 +# BEGIN TRAN +# PROC2 +# PROC3 +# BEGIN TRAN +# START SAVEPOINT +# ROLLBACK SAVEPOINT +# ROLLBACK TRAN +# COMMIT +drop procedure txnproc3 +create procedure txnProc3 as begin tran; insert into txnproctable values (20, 'abc'); save tran sp1; update txnproctable set c1 = c1 + 1; rollback tran sp1; +select @@trancount +~~START~~ +int +0 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#varchar +16#!#abc +~~END~~ + +drop procedure txnproc2 +create procedure txnProc2 as update txnproctable set c1 = c1 + 1; exec txnProc3; rollback tran; +select @@trancount +~~START~~ +int +0 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#varchar +16#!#abc +~~END~~ + +drop procedure txnproc1 +create procedure txnproc1 as delete from txnproctable; begin tran; exec txnProc2; +select @@trancount +~~START~~ +int +0 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#varchar +16#!#abc +~~END~~ + +exec txnproc1; +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 266)~~ + +~~ERROR (Message: Transaction count after execution indicates a mismatch number of BEGIN and COMMIT statements. Previous count 1 current count 2)~~ + +~~ERROR (Code: 266)~~ + +~~ERROR (Message: Transaction count after execution indicates a mismatch number of BEGIN and COMMIT statements. Previous count 1 current count 0)~~ + +select @@trancount +~~START~~ +int +0 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#varchar +~~END~~ + + +#cleanup +drop procedure txnproc3 +drop procedure txnproc2 +drop procedure txnproc1 +drop table txnproctable diff --git a/contrib/test/JDBC/expected/TestTransactionsSQLBatch.out b/contrib/test/JDBC/expected/TestTransactionsSQLBatch.out new file mode 100644 index 00000000000..c60f47da53a --- /dev/null +++ b/contrib/test/JDBC/expected/TestTransactionsSQLBatch.out @@ -0,0 +1,494 @@ +create table TxnTable(c1 int); + +# Begin transaction -> commit transaction +begin transaction; +select @@trancount; +~~START~~ +int +1 +~~END~~ + +begin transaction; +select @@trancount; +~~START~~ +int +2 +~~END~~ + +set transaction isolation level read committed; +#show transaction_isolation; +#show default_transaction_isolation; +insert into TxnTable values(1); +~~ROW COUNT: 1~~ + +commit transaction; +select @@trancount; +~~START~~ +int +1 +~~END~~ + +commit transaction; +select @@trancount; +~~START~~ +int +0 +~~END~~ + +select c1 from TxnTable; +~~START~~ +int +1 +~~END~~ + + +# Begin transaction -> rollback transaction +begin transaction; +insert into TxnTable values(2); +~~ROW COUNT: 1~~ + +rollback transaction; +select c1 from TxnTable; +~~START~~ +int +1 +~~END~~ + + +#Begin tran -> commit tran +begin tran; +insert into TxnTable values(2); +~~ROW COUNT: 1~~ + +commit tran; +select c1 from TxnTable; +~~START~~ +int +1 +2 +~~END~~ + + +# Begin tran -> rollback tran +begin tran; +select @@trancount; +~~START~~ +int +1 +~~END~~ + +begin tran; +set transaction isolation level read uncommitted; +#show transaction_isolation; +#show default_transaction_isolation; +insert into TxnTable values(3); +~~ROW COUNT: 1~~ + +select @@trancount; +~~START~~ +int +2 +~~END~~ + +rollback tran; +select @@trancount; +~~START~~ +int +0 +~~END~~ + +select c1 from TxnTable; +~~START~~ +int +1 +2 +~~END~~ + + +set transaction isolation level repeatable read; +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: REPEATABLE READ isolation level is not supported)~~ + +#show transaction_isolation; +#show default_transaction_isolation; + +# Begin transaction -> commit +begin transaction; +insert into TxnTable values(4); +~~ROW COUNT: 1~~ + +commit; +select c1 from TxnTable; +~~START~~ +int +1 +2 +4 +~~END~~ + + +# Begin transaction -> commit work +begin transaction; +insert into TxnTable values(5); +~~ROW COUNT: 1~~ + +commit work; +select c1 from TxnTable; +~~START~~ +int +1 +2 +4 +5 +~~END~~ + + +# Begin transaction -> rollback +begin transaction; +insert into TxnTable values(6); +~~ROW COUNT: 1~~ + +rollback; +select c1 from TxnTable; +~~START~~ +int +1 +2 +4 +5 +~~END~~ + + +# Begin transaction -> rollback work +begin transaction; +insert into TxnTable values(7); +~~ROW COUNT: 1~~ + +rollback work; +select c1 from TxnTable; +~~START~~ +int +1 +2 +4 +5 +~~END~~ + + +# Begin transaction name -> commit transaction name +begin transaction txn1; +insert into TxnTable values(8); +~~ROW COUNT: 1~~ + +commit transaction txn1; +select c1 from TxnTable; +~~START~~ +int +1 +2 +4 +5 +8 +~~END~~ + + +# Begin transaction name -> rollback transaction name +begin transaction txn1; +insert into TxnTable values(9); +~~ROW COUNT: 1~~ + +rollback transaction txn1; +select c1 from TxnTable; +~~START~~ +int +1 +2 +4 +5 +8 +~~END~~ + + +# Begin tran name -> commit tran name +begin tran txn1; +insert into TxnTable values(10); +~~ROW COUNT: 1~~ + +commit tran txn1; +select c1 from TxnTable; +~~START~~ +int +1 +2 +4 +5 +8 +10 +~~END~~ + + +# Begin tran name -> rollback tran name +begin tran txn1; +insert into TxnTable values(10); +~~ROW COUNT: 1~~ + +rollback tran txn1; +select c1 from TxnTable; +~~START~~ +int +1 +2 +4 +5 +8 +10 +~~END~~ + + +truncate table TxnTable; + +# save tran name -> rollback tran name +set transaction isolation level snapshot; +#show transaction_isolation; +#show default_transaction_isolation; +begin transaction txn1; +insert into TxnTable values(1); +~~ROW COUNT: 1~~ + +save transaction sp1; +select @@trancount; +~~START~~ +int +1 +~~END~~ + +insert into TxnTable values(2); +~~ROW COUNT: 1~~ + +save tran sp2; +insert into TxnTable values(3); +~~ROW COUNT: 1~~ + +save tran sp2; +select @@trancount; +~~START~~ +int +1 +~~END~~ + +insert into TxnTable values(4); +~~ROW COUNT: 1~~ + +select c1 from TxnTable; +~~START~~ +int +1 +2 +3 +4 +~~END~~ + +rollback tran sp2; +select @@trancount; +~~START~~ +int +1 +~~END~~ + +select c1 from TxnTable; +~~START~~ +int +1 +2 +3 +~~END~~ + +rollback tran sp2; +select @@trancount; +~~START~~ +int +1 +~~END~~ + +select c1 from TxnTable; +~~START~~ +int +1 +2 +~~END~~ + +rollback tran sp1; +select @@trancount; +~~START~~ +int +1 +~~END~~ + +select c1 from TxnTable; +~~START~~ +int +1 +~~END~~ + +rollback tran txn1; +select @@trancount; +~~START~~ +int +0 +~~END~~ + +select c1 from TxnTable; +~~START~~ +int +~~END~~ + + +# begin transaction name -> save transaction name -> rollback to first savepoint +begin transaction txn1; +insert into TxnTable values(1); +~~ROW COUNT: 1~~ + +save transaction sp1; +insert into TxnTable values(2); +~~ROW COUNT: 1~~ + +save transaction sp2; +insert into TxnTable values(3); +~~ROW COUNT: 1~~ + +save transaction sp3; +insert into TxnTable values(4); +~~ROW COUNT: 1~~ + +rollback tran sp1; +#rollback tran sp1; -- this will give an error +rollback tran; +select c1 from TxnTable; +~~START~~ +int +~~END~~ + + +# begin transaction name -> save transaction name -> rollback tran name, Rollback whole transaction +set transaction isolation level serializable; +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: SERIALIZABLE isolation level is not supported)~~ + +#show transaction_isolation; +#show default_transaction_isolation; +begin transaction txn1; +insert into TxnTable values(1); +~~ROW COUNT: 1~~ + +save transaction sp1; +begin transaction txn1; +insert into TxnTable values(2); +~~ROW COUNT: 1~~ + +save transaction sp1; +insert into TxnTable values(3); +~~ROW COUNT: 1~~ + +select @@trancount; +~~START~~ +int +2 +~~END~~ + +rollback tran txn1; +select @@trancount; +~~START~~ +int +0 +~~END~~ + +select c1 from TxnTable; +~~START~~ +int +~~END~~ + + +# begin transaction -> save transaction name -> rollback to savepoint, commit transaction +begin transaction txn1; +insert into TxnTable values(1); +~~ROW COUNT: 1~~ + +save transaction sp1; +insert into TxnTable values(2); +~~ROW COUNT: 1~~ + +select c1 from TxnTable; +~~START~~ +int +1 +2 +~~END~~ + +rollback tran sp1; +commit transaction; +select c1 from TxnTable; +~~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); +~~ROW COUNT: 1~~ + +save transaction sp1; +insert into TxnTable values(4); +~~ROW COUNT: 1~~ + +select c1 from TxnTable; +~~START~~ +int +1 +3 +4 +~~END~~ + +rollback tran sp1; +save transaction sp2; +insert into TxnTable values(5); +~~ROW COUNT: 1~~ + +commit transaction; +select c1 from TxnTable; +~~START~~ +int +1 +3 +5 +~~END~~ + + +# begin transaction -> save transaction name -> error -> rollback to savepoint +# commit transaction +begin transaction txn1; +insert into TxnTable values(6); +~~ROW COUNT: 1~~ + +save transaction sp1; +insert into TxnTable values(7); +~~ROW COUNT: 1~~ + +#select c1 frm TxnTable; -- error +rollback tran sp1; +commit transaction; +select c1 from TxnTable; +~~START~~ +int +1 +3 +5 +6 +~~END~~ + + +Drop table TxnTable; diff --git a/contrib/test/JDBC/expected/TestUDD.out b/contrib/test/JDBC/expected/TestUDD.out new file mode 100644 index 00000000000..4095d876908 --- /dev/null +++ b/contrib/test/JDBC/expected/TestUDD.out @@ -0,0 +1,139 @@ +CREATE TYPE udd_varchar from varchar(15); +CREATE TYPE udd_nvarchar from nvarchar(15); +CREATE TYPE udd_int from int; +CREATE TYPE udd_char from char(25); +CREATE TYPE udd_nchar from nchar(20) NOT NULL; +CREATE TYPE udd_datetime from datetime; +CREATE TYPE udd_numeric from numeric(4,1); + +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_unique_constraint', 'ignore'; +CREATE TABLE udd_dt (a udd_varchar UNIQUE, b udd_nvarchar, c udd_int PRIMARY KEY, d udd_char DEFAULT 'Whoops!', e udd_nchar, f udd_datetime, g udd_numeric CHECK (g >= 103.5)) + +INSERT INTO udd_dt VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +~~ROW COUNT: 1~~ + + +#passing a non unique value in column a +#throws error: duplicate key value violates unique constraint +INSERT INTO udd_dt VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "udd_dt_a_key")~~ + + +#passing a non unique value in column c +#throws error: duplicate key value violates unique constraint +INSERT INTO udd_dt VALUES ('Banana', N'green', 1, 'Bangalore', N'Crying😭', '2007-01-14 23:34:23.749', 908.7); +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "udd_dt_pkey")~~ + + +#passing a NULL value in column c +#throws error: null value in column "c" violates not-null constraint +INSERT INTO udd_dt VALUES ('Guava', N'yellow', NULL, 'Mumbai', N'Smirk😏', '1907-05-09 11:14:13.749', 245.6); +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "c" of relation "udd_dt" violates not-null constraint)~~ + + +#passing no value for column d +INSERT INTO udd_dt(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +~~ROW COUNT: 1~~ + + +#passing a NULL value in column e +#throws error: domain udd_nchar does not allow null values +INSERT INTO udd_dt VALUES ('Kiwi', N'purple', 4, 'Kolkata', NULL, '1907-05-09 11:14:13.749', 874.0); +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: domain udd_nchar does not allow null values)~~ + + +#passing a value less than 103.5 in column g +#throws error: new row for relation "udd_dt" violates check constraint "udd_dt_g_check" +INSERT INTO udd_dt VALUES ('Grape', N'white', 5, 'Pune', N'Angry😠', '2000-02-28 23:59:59.989', 100.1); +~~ERROR (Code: 547)~~ + +~~ERROR (Message: new row for relation "udd_dt" violates check constraint "udd_dt_g_check")~~ + + +SELECT * FROM udd_dt; +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + + +DROP TABLE udd_dt; + +CREATE TABLE udd_dt (a udd_varchar UNIQUE, b udd_nvarchar, c udd_int PRIMARY KEY, d udd_char DEFAULT 'Whoops!', e udd_nchar, f udd_datetime, g udd_numeric CHECK (g >= 103.5)) + +prepst#!#INSERT INTO udd_dt VALUES (?, ?, ?, ?, ?, ?, ?)#!#varchar|-|a|-|Apple#!#nvarchar|-|b|-|red#!#int|-|c|-|1#!#char|-|d|-|Delhi#!#nchar|-|e|-|Sad😞#!#datetime|-|f|-|2000-12-13 12:58:23.123#!#numeric|-|g|-|123.1|-|4|-|1 +~~ROW COUNT: 1~~ + + +#passing a non unique value in column a +#throws error: duplicate key value violates unique constraint +prepst#!#exec#!#varchar|-|a|-|Apple#!#nvarchar|-|b|-|blue#!#int|-|c|-|2#!#char|-|d|-|Chennai#!#nchar|-|e|-|Neutral😐#!#datetime|-|f|-|2006-11-11 22:47:23.128#!#numeric|-|g|-|512.4|-|4|-|1 +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "udd_dt_a_key")~~ + + +#passing a non unique value in column c +#throws error: duplicate key value violates unique constraint +prepst#!#exec#!#varchar|-|a|-|Banana#!#nvarchar|-|b|-|green#!#int|-|c|-|1#!#char|-|d|-|Bangalore#!#nchar|-|e|-|Crying😭#!#datetime|-|f|-|2007-01-14 23:34:23.749#!#numeric|-|g|-|908.7|-|4|-|1 +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "udd_dt_pkey")~~ + + +#passing a NULL value in column c +#throws error: null value in column "c" violates not-null constraint +prepst#!#exec#!#varchar|-|a|-|Guava#!#nvarchar|-|b|-|yellow#!#int|-|c|-|#!#char|-|d|-|Mumbai#!#nchar|-|e|-|Smirk😏'#!#datetime|-|f|-|1907-05-09 11:14:13.749#!#numeric|-|g|-|245.6|-|4|-|1 +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "c" of relation "udd_dt" violates not-null constraint)~~ + + +#passing a NULL value in column e +#throws error: domain udd_nchar does not allow null values +prepst#!#exec#!#varchar|-|a|-|Kiwi#!#nvarchar|-|b|-|purple#!#int|-|c|-|4#!#char|-|d|-|Kolkata#!#nchar|-|e|-|#!#datetime|-|f|-|1907-05-09 11:14:13.749#!#numeric|-|g|-|874.0|-|4|-|1 +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: domain udd_nchar does not allow null values)~~ + + +#passing a value less than 103.5 in column g +#throws error: new row for relation "udd_dt" violates check constraint "udd_dt_g_check" +prepst#!#exec#!#varchar|-|a|-|Grape#!#nvarchar|-|b|-|white#!#int|-|c|-|5#!#char|-|d|-|Pune#!#nchar|-|e|-|Angry😠#!#datetime|-|f|-|2000-02-28 23:59:59.989#!#numeric|-|g|-|100.1|-|4|-|1 +~~ERROR (Code: 547)~~ + +~~ERROR (Message: new row for relation "udd_dt" violates check constraint "udd_dt_g_check")~~ + + +#passing no value for column d +prepst#!#INSERT INTO udd_dt(a, b, c, e, f, g) VALUES (?, ?, ?, ?, ?, ?)#!#varchar|-|a1|-|Orange#!#nvarchar|-|b1|-|#!#int|-|c1|-|5#!#nchar|-|e1|-|Happy😀#!#datetime|-|f1|-|1900-02-28 23:59:59.989#!#numeric|-|g1|-|342.5|-|4|-|1 +~~ROW COUNT: 1~~ + + +SELECT * FROM udd_dt; +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#5#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + + +DROP TABLE udd_dt; + +DROP TYPE udd_varchar +DROP TYPE udd_nvarchar +DROP TYPE udd_int +DROP TYPE udd_char +DROP TYPE udd_nchar +DROP TYPE udd_datetime +DROP TYPE udd_numeric +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_unique_constraint', 'strict'; diff --git a/contrib/test/JDBC/expected/TestUniqueIdentifier.out b/contrib/test/JDBC/expected/TestUniqueIdentifier.out new file mode 100644 index 00000000000..0652b81f558 --- /dev/null +++ b/contrib/test/JDBC/expected/TestUniqueIdentifier.out @@ -0,0 +1,151 @@ +CREATE TABLE uniqueidentifier_dt (a uniqueidentifier); + +INSERT INTO uniqueidentifier_dt VALUES ('51f178a6-53c7-472c-9be1-1c08942342d7') +~~ROW COUNT: 1~~ + +INSERT INTO uniqueidentifier_dt VALUES ('dd8cb046-461d-411e-be40-d219252ce849') +~~ROW COUNT: 1~~ + +INSERT INTO uniqueidentifier_dt VALUES ('b84ebcc9-c927-4cfe-b08e-dc7f25b5087c') +~~ROW COUNT: 1~~ + +INSERT INTO uniqueidentifier_dt VALUES ('bab96bc8-60b9-40dd-b0de-c90a80f5739e') +~~ROW COUNT: 1~~ + +INSERT INTO uniqueidentifier_dt VALUES ('d424fdef-1404-4bac-8289-c725b540f93d') +~~ROW COUNT: 1~~ + +INSERT INTO uniqueidentifier_dt VALUES ('60aeaa5c-e272-4b17-bad0-c25710fd7a60') +~~ROW COUNT: 1~~ + +INSERT INTO uniqueidentifier_dt VALUES ('253fb146-7e45-45ef-9d92-bbe14a8ad1b2') +~~ROW COUNT: 1~~ + +INSERT INTO uniqueidentifier_dt VALUES ('dba2726c-2131-409f-aefa-5c8079571623') +~~ROW COUNT: 1~~ + +INSERT INTO uniqueidentifier_dt VALUES ('b3400fa7-3a60-40ec-b40e-fc85a3eb262d') +~~ROW COUNT: 1~~ + +INSERT INTO uniqueidentifier_dt VALUES ('851763b5-b068-42ae-88ec-764bfb0e5605') +~~ROW COUNT: 1~~ + +INSERT INTO uniqueidentifier_dt VALUES (NULL) +~~ROW COUNT: 1~~ + +SELECT * FROM uniqueidentifier_dt +~~START~~ +uniqueidentifier +51F178A6-53C7-472C-9BE1-1C08942342D7 +DD8CB046-461D-411E-BE40-D219252CE849 +B84EBCC9-C927-4CFE-B08E-DC7F25B5087C +BAB96BC8-60B9-40DD-B0DE-C90A80F5739E +D424FDEF-1404-4BAC-8289-C725B540F93D +60AEAA5C-E272-4B17-BAD0-C25710FD7A60 +253FB146-7E45-45EF-9D92-BBE14A8AD1B2 +DBA2726C-2131-409F-AEFA-5C8079571623 +B3400FA7-3A60-40EC-B40E-FC85A3EB262D +851763B5-B068-42AE-88EC-764BFB0E5605 + +~~END~~ + + +prepst#!#INSERT INTO uniqueidentifier_dt VALUES (?)#!#uniqueidentifier|-|a|-|51f178a6-53c7-472c-9be1-1c08942342d7 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#uniqueidentifier|-|a|-|767392df-87d0-450d-9b24-85a86c02811d +~~ROW COUNT: 1~~ + +prepst#!#exec#!#uniqueidentifier|-|a|-|9bcb5632-53c3-4695-b617-d9a7055813ce +~~ROW COUNT: 1~~ + +prepst#!#exec#!#uniqueidentifier|-|a|-|ac81a140-f686-4259-9b90-dd46f10b355f +~~ROW COUNT: 1~~ + +prepst#!#exec#!#uniqueidentifier|-|a|-|3d08372d-770c-48b9-9740-a667d036680e +~~ROW COUNT: 1~~ + +prepst#!#exec#!#uniqueidentifier|-|a|-|518d52c7-4d79-4143-ab33-b3765689fdf4 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#uniqueidentifier|-|a|-|bc3fa456-7391-4060-b5d8-430048075cf4 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#uniqueidentifier|-|a|-|3b75b2dd-01b7-4958-9de7-f92410693547 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#uniqueidentifier|-|a|-|ce8af10a-2709-43b0-9e4e-a02753929d17 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#uniqueidentifier|-|a|-|5b7c2e8d-6d90-411d-8e19-9a81067e6f6c +~~ROW COUNT: 1~~ + +prepst#!#exec#!#uniqueidentifier|-|a|-| +~~ROW COUNT: 1~~ + +SELECT * FROM uniqueidentifier_dt; +~~START~~ +uniqueidentifier +51F178A6-53C7-472C-9BE1-1C08942342D7 +DD8CB046-461D-411E-BE40-D219252CE849 +B84EBCC9-C927-4CFE-B08E-DC7F25B5087C +BAB96BC8-60B9-40DD-B0DE-C90A80F5739E +D424FDEF-1404-4BAC-8289-C725B540F93D +60AEAA5C-E272-4B17-BAD0-C25710FD7A60 +253FB146-7E45-45EF-9D92-BBE14A8AD1B2 +DBA2726C-2131-409F-AEFA-5C8079571623 +B3400FA7-3A60-40EC-B40E-FC85A3EB262D +851763B5-B068-42AE-88EC-764BFB0E5605 + +51F178A6-53C7-472C-9BE1-1C08942342D7 +767392DF-87D0-450D-9B24-85A86C02811D +9BCB5632-53C3-4695-B617-D9A7055813CE +AC81A140-F686-4259-9B90-DD46F10B355F +3D08372D-770C-48B9-9740-A667D036680E +518D52C7-4D79-4143-AB33-B3765689FDF4 +BC3FA456-7391-4060-B5D8-430048075CF4 +3B75B2DD-01B7-4958-9DE7-F92410693547 +CE8AF10A-2709-43B0-9E4E-A02753929D17 +5B7C2E8D-6D90-411D-8E19-9A81067E6F6C + +~~END~~ + + +# to demonstrate the truncation of data when the value is too long +INSERT INTO uniqueidentifier_dt VALUES ('51f178a6-53c7-472c-9be1-1c08942342d7thisIsTooLong') +~~ROW COUNT: 1~~ + +prepst#!#exec#!#uniqueidentifier|-|a|-|767392df-87d0-450d-9b24-85a86c02811dthisIsTooLong +~~ROW COUNT: 1~~ + +SELECT * FROM uniqueidentifier_dt; +~~START~~ +uniqueidentifier +51F178A6-53C7-472C-9BE1-1C08942342D7 +DD8CB046-461D-411E-BE40-D219252CE849 +B84EBCC9-C927-4CFE-B08E-DC7F25B5087C +BAB96BC8-60B9-40DD-B0DE-C90A80F5739E +D424FDEF-1404-4BAC-8289-C725B540F93D +60AEAA5C-E272-4B17-BAD0-C25710FD7A60 +253FB146-7E45-45EF-9D92-BBE14A8AD1B2 +DBA2726C-2131-409F-AEFA-5C8079571623 +B3400FA7-3A60-40EC-B40E-FC85A3EB262D +851763B5-B068-42AE-88EC-764BFB0E5605 + +51F178A6-53C7-472C-9BE1-1C08942342D7 +767392DF-87D0-450D-9B24-85A86C02811D +9BCB5632-53C3-4695-B617-D9A7055813CE +AC81A140-F686-4259-9B90-DD46F10B355F +3D08372D-770C-48B9-9740-A667D036680E +518D52C7-4D79-4143-AB33-B3765689FDF4 +BC3FA456-7391-4060-B5D8-430048075CF4 +3B75B2DD-01B7-4958-9DE7-F92410693547 +CE8AF10A-2709-43B0-9E4E-A02753929D17 +5B7C2E8D-6D90-411D-8E19-9A81067E6F6C + +51F178A6-53C7-472C-9BE1-1C08942342D7 +767392DF-87D0-450D-9B24-85A86C02811D +~~END~~ + + +DROP TABLE uniqueidentifier_dt; diff --git a/contrib/test/JDBC/expected/TestVarChar.out b/contrib/test/JDBC/expected/TestVarChar.out new file mode 100644 index 00000000000..1e9cbb78fd5 --- /dev/null +++ b/contrib/test/JDBC/expected/TestVarChar.out @@ -0,0 +1,159 @@ +CREATE TABLE VARCHAR_dt (a VARCHAR(20), b NVARCHAR(24)) +prepst#!# INSERT INTO VARCHAR_dt(a, b) values(?, ?) #!#VARCHAR|-|a|-|Dipesh#!#NVARCHAR|-|b|-|Dhameliya +~~ROW COUNT: 1~~ + +prepst#!#exec#!#VARCHAR|-|a|-| Dipesh #!#NVARCHAR|-|b|-| Dhameliya +~~ROW COUNT: 1~~ + +prepst#!#exec#!#VARCHAR|-|a|-| D#!#NVARCHAR|-|b|-| 🤣😃 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#VARCHAR|-|a|-| #!#NVARCHAR|-|b|-| +~~ROW COUNT: 1~~ + +prepst#!#exec#!#VARCHAR|-|a|-|#!#NVARCHAR|-|b|-| +~~ROW COUNT: 1~~ + +prepst#!#exec#!#VARCHAR|-|a|-|d#!#NVARCHAR|-|b|-|D +~~ROW COUNT: 1~~ + +prepst#!#exec#!#VARCHAR|-|a|-|abcdefghijklmnopqrst#!#NVARCHAR|-|b|-|abcdefghijklmnopqrstuvwx +~~ROW COUNT: 1~~ + +prepst#!#exec#!#VARCHAR|-|a|-|abcdefghijklmnopqrstu#!#NVARCHAR|-|b|-|abcdefghijklmnopqrstuvwxy +~~ERROR (Code: 8152)~~ + +~~ERROR (Message: value too long for type character varying(20))~~ + +prepst#!#exec#!#VARCHAR|-|a|-| #!#NVARCHAR|-|b|-|😊😋😎😍😅😆 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#VARCHAR|-|a|-|#!#NVARCHAR|-|b|-| +~~ROW COUNT: 1~~ + +SELECT * FROM VARCHAR_dt; +~~START~~ +varchar#!#nvarchar +Dipesh#!#Dhameliya + Dipesh #!# Dhameliya + D#!# 🤣😃 + #!# +#!# +d#!#D +abcdefghijklmnopqrst#!#abcdefghijklmnopqrstuvwx + #!#😊😋😎😍😅😆 +#!# +~~END~~ + +INSERT INTO VARCHAR_dt(a,b) values('Dipesh','Dhameliya') +~~ROW COUNT: 1~~ + +INSERT INTO VARCHAR_dt(a,b) values(' Dipesh',' Dhameliya') +~~ROW COUNT: 1~~ + +INSERT INTO VARCHAR_dt(a,b) values(' D',N' 🤣😃') +~~ROW COUNT: 1~~ + +INSERT INTO VARCHAR_dt(a,b) values(' ',' ') +~~ROW COUNT: 1~~ + +INSERT INTO VARCHAR_dt(a,b) values(' ',N'😊😋😎😍😅😆') +~~ROW COUNT: 1~~ + +INSERT INTO VARCHAR_dt(a,b) values('','') +~~ROW COUNT: 1~~ + +INSERT INTO VARCHAR_dt(a,b) values('d','D') +~~ROW COUNT: 1~~ + +INSERT INTO VARCHAR_dt(a,b) values('abcdefghijklmnopqrst','abcdefghijklmnopqrstuvwx') +~~ROW COUNT: 1~~ + +#INSERT INTO VARCHAR_dt(a,b) values('abcdefghijklmnopqrstu','abcdefghijklmnopqrstuvwxy') -- for this case, BABEL and SQL both will throw an error +INSERT INTO VARCHAR_dt(a,b) values(NULL,NULL) +~~ROW COUNT: 1~~ + +SELECT * FROM VARCHAR_dt; +~~START~~ +varchar#!#nvarchar +Dipesh#!#Dhameliya + Dipesh #!# Dhameliya + D#!# 🤣😃 + #!# +#!# +d#!#D +abcdefghijklmnopqrst#!#abcdefghijklmnopqrstuvwx + #!#😊😋😎😍😅😆 +#!# +Dipesh#!#Dhameliya + Dipesh#!# Dhameliya + D#!# 🤣😃 + #!# + #!#😊😋😎😍😅😆 +#!# +d#!#D +abcdefghijklmnopqrst#!#abcdefghijklmnopqrstuvwx +#!# +~~END~~ + +DROP TABLE VARCHAR_dt; + +CREATE TABLE VARCHAR_dt (a varchar(max), b nvarchar(max)); +INSERT INTO VARCHAR_dt values ('hello', N'hello😃'); +~~ROW COUNT: 1~~ + + +#checking with string of length > 65535 +INSERT INTO VARCHAR_dt values ('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', N'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😃'); +~~ROW COUNT: 1~~ + +INSERT INTO VARCHAR_dt values (NULL, NULL); +~~ROW COUNT: 1~~ + +prepst#!#INSERT INTO VARCHAR_dt values(?, ?)#!#varchar|-|a|-|hello#!#nvarchar|-|b|-|hello😃 +~~ROW COUNT: 1~~ + + +#checking with string of length > 65535 via prep-exec +prepst#!#exec#!#varchar|-|a|-|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#!#nvarchar|-|b|-|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😃 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#varchar|-|a|-|#!#nvarchar|-|b|-| +~~ROW COUNT: 1~~ + +select * from VARCHAR_dt +~~START~~ +varchar#!#nvarchar +hello#!#hello😃 +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#!#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😃 +#!# +hello#!#hello😃 +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#!#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😃 +#!# +~~END~~ + +drop table VARCHAR_dt; + +create table VARCHAR_dt (a varchar(max), b int, c int, d int, e int ,f int, g int, h int, i int); +insert into VARCHAR_dt (a,b,c,d,e,f,g,h,i) values (NULL,1,2,3,4,5,6,7,8); +~~ROW COUNT: 1~~ + +select * from VARCHAR_dt; +~~START~~ +varchar#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int +#!#1#!#2#!#3#!#4#!#5#!#6#!#7#!#8 +~~END~~ + +drop table VARCHAR_dt; + +create table VARCHAR_dt (a varchar(10), b int, c int, d int, e int ,f int, g int, h int, i int); +insert into VARCHAR_dt (a,b,c,d,e,f,g,h,i) values (NULL,1,2,3,4,5,6,7,8); +~~ROW COUNT: 1~~ + +select * from VARCHAR_dt; +~~START~~ +varchar#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int +#!#1#!#2#!#3#!#4#!#5#!#6#!#7#!#8 +~~END~~ + +drop table VARCHAR_dt; diff --git a/contrib/test/JDBC/expected/TestXML.out b/contrib/test/JDBC/expected/TestXML.out new file mode 100644 index 00000000000..dc7168f2452 --- /dev/null +++ b/contrib/test/JDBC/expected/TestXML.out @@ -0,0 +1,29 @@ +CREATE TABLE XML_dt (a XML) +#prepst#!# INSERT INTO XML_dt values(@a) #!#XML|-|a|-| +#prepst#!# INSERT INTO XML_dt values(@a) #!#XML|-|a|-|Contact Name 2YYY-YYY-YYYY +#prepst#!#exec#!#XML|-|a|-| +SELECT * FROM XML_dt; +~~START~~ +xml +~~END~~ + +INSERT INTO XML_dt values('Contact Name 2YYY-YYY-YYYY') +~~ROW COUNT: 1~~ + +INSERT INTO XML_dt values(NULL) +~~ROW COUNT: 1~~ + +#INSERT INTO XML_dt values('') +INSERT INTO XML_dt values(Contact Name 2YYY-YYY-YYYY) +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error near '<' at line 1 and character position 26)~~ + +SELECT * FROM XML_dt; +~~START~~ +xml +Contact Name 2YYY-YYY-YYYY + +~~END~~ + +DROP TABLE XML_dt; diff --git a/contrib/test/JDBC/expected/babel_613.out b/contrib/test/JDBC/expected/babel_613.out new file mode 100644 index 00000000000..76c4a668b86 --- /dev/null +++ b/contrib/test/JDBC/expected/babel_613.out @@ -0,0 +1,199 @@ +use master +go + +create table t1 (a numeric(6,4), b numeric(6,3)); +insert into t1 values (4, 16); +insert into t1 values (10.1234, 10.123); +insert into t1 values (1.2, 6); +insert into t1 values (NULL, 101.123); +go +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +-- test selection of numeric Var +select * from t1; +go +~~START~~ +numeric#!#numeric +4.0000#!#16.000 +10.1234#!#10.123 +1.2000#!#6.000 +#!#101.123 +~~END~~ + + +-- test operations on numeric var +select a+b, a-b, a*b, a/b, +a, -a from t1; +go +~~START~~ +numeric#!#numeric#!#numeric#!#numeric#!#numeric#!#numeric +20.0000#!#-12.0000#!#64.0000000#!#0.25000000000#!#4.0000#!#-4.0000 +20.2464#!#0.0004#!#102.4791782#!#1.00003951397#!#10.1234#!#-10.1234 +7.2000#!#-4.8000#!#7.2000000#!#0.20000000000#!#1.2000#!#-1.2000 +#!##!##!##!##!# +~~END~~ + + +-- test functions that returns numeric value +select round(a, 2) from t1; +go +~~START~~ +numeric +4.00000000 +10.12000000 +1.20000000 + +~~END~~ + + +select power(a, b) from t1; +go +~~START~~ +numeric +4294967296.00000000 +15028620538.57697600 +2.98598400 + +~~END~~ + + +select sqrt(a) from t1; +go +~~START~~ +numeric +2.00000000 +3.18172908 +1.09544511 + +~~END~~ + + +select abs(a) from t1; +go +~~START~~ +numeric +4.00000000 +10.12340000 +1.20000000 + +~~END~~ + + +-- test overflow error, max precision is 38 for TSQL client. +-- BABEL-2656 +select power(10.0, 100); +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Arithmetic overflow error for data type numeric.)~~ + + +-- test Nullif expression +select nullif(a, b) from t1; +go +~~START~~ +numeric +4.0000 +10.1234 +1.2000 + +~~END~~ + + +-- test Param expr +select (select 1.234); +go +~~START~~ +numeric +1.23400000 +~~END~~ + + +-- test case expr +select a, b, +case when a>5 then a + when a<=5 then b +end + from t1; +go +~~START~~ +numeric#!#numeric#!#numeric +4.0000#!#16.000#!#16.0000 +10.1234#!#10.123#!#10.1234 +1.2000#!#6.000#!#6.0000 +#!#101.123#!# +~~END~~ + + +-- test Aggref expr +select min(a), max(a), min(b), max(b) from t1; +go +~~START~~ +numeric#!#numeric#!#numeric#!#numeric +1.2000#!#10.1234#!#6.000#!#101.123 +~~END~~ + + +-- test Coalesece expr +-- BABEL-2656 +select coalesce(a, b) from t1; +go +~~START~~ +numeric +4.0000 +10.1234 +1.2000 +101.1230 +~~END~~ + + +-- test Union All +select a from t1 Union All +select b from t1; +go +~~START~~ +numeric +4.00000000 +10.12340000 +1.20000000 + +16.00000000 +10.12300000 +6.00000000 +101.12300000 +~~END~~ + + +-- test overflow from multiplication of columns +create table t2 (a numeric(38, 1), b numeric(38, 1)) +insert into t1 values (1234567890123456789012345678901234567.1), (1234567890123456789012345678901234567.2) +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Number of given values does not match target table definition)~~ + + +select * from t2 +go +~~START~~ +numeric#!#numeric +~~END~~ + + +select a * b from t2; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Arithmetic overflow error for data type numeric.)~~ + + +-- clean up +drop table t1; +drop table t2; +go diff --git a/contrib/test/JDBC/expected/babel_bit_comp.out b/contrib/test/JDBC/expected/babel_bit_comp.out new file mode 100644 index 00000000000..5fd3c50c0ea --- /dev/null +++ b/contrib/test/JDBC/expected/babel_bit_comp.out @@ -0,0 +1,264 @@ +CREATE TABLE t1 (a bit, b int); +GO +INSERT INTO t1 VALUES (1, 1); +GO +~~ROW COUNT: 1~~ + +INSERT INTO t1 VALUES (0, 0); +GO +~~ROW COUNT: 1~~ + + +SELECT a FROM t1 WHERE a = 0; +GO +~~START~~ +bit +0 +~~END~~ + +SELECT a FROM t1 WHERE a = 1; +GO +~~START~~ +bit +1 +~~END~~ + +SELECT a FROM t1 WHERE a = -1; +GO +~~START~~ +bit +1 +~~END~~ + + +SELECT a FROM t1 WHERE a <> 0; +GO +~~START~~ +bit +1 +~~END~~ + +SELECT a FROM t1 WHERE a <> 1; +GO +~~START~~ +bit +0 +~~END~~ + +SELECT a FROM t1 WHERE a <> -1; +GO +~~START~~ +bit +0 +~~END~~ + + +SELECT a FROM t1 WHERE a > 0; +GO +~~START~~ +bit +1 +~~END~~ + +SELECT a FROM t1 WHERE a > 1; +GO +~~START~~ +bit +~~END~~ + +SELECT a FROM t1 WHERE a > -1; +GO +~~START~~ +bit +~~END~~ + + +SELECT a FROM t1 WHERE a >= 0 ORDER BY b; +GO +~~START~~ +bit +0 +1 +~~END~~ + +SELECT a FROM t1 WHERE a >= 1; +GO +~~START~~ +bit +1 +~~END~~ + +SELECT a FROM t1 WHERE a >= -1; +GO +~~START~~ +bit +1 +~~END~~ + + +SELECT a FROM t1 WHERE a < 0; +GO +~~START~~ +bit +~~END~~ + +SELECT a FROM t1 WHERE a < 1; +GO +~~START~~ +bit +0 +~~END~~ + +SELECT a FROM t1 WHERE a < -1; +GO +~~START~~ +bit +0 +~~END~~ + + +SELECT a FROM t1 WHERE a <= 0; +GO +~~START~~ +bit +0 +~~END~~ + +SELECT a FROM t1 WHERE a <= 1 ORDER BY b; +GO +~~START~~ +bit +0 +1 +~~END~~ + +SELECT a FROM t1 WHERE a <= -1 ORDER BY b; +GO +~~START~~ +bit +0 +1 +~~END~~ + + +CREATE TABLE t2 ( a INT); +GO +INSERT INTO t2 VALUES (1); +GO +~~ROW COUNT: 1~~ + +INSERT INTO t2 VALUES (0); +GO +~~ROW COUNT: 1~~ + +INSERT INTO t2 VALUES (-1); +GO +~~ROW COUNT: 1~~ + + +SELECT a FROM t2 WHERE a = CAST(0 AS bit); +GO +~~START~~ +int +0 +~~END~~ + +SELECT a FROM t2 WHERE a = CAST(1 AS bit) ORDER BY a; +GO +~~START~~ +int +-1 +1 +~~END~~ + + +SELECT a FROM t2 WHERE a <> CAST(0 AS bit) ORDER BY a; +GO +~~START~~ +int +-1 +1 +~~END~~ + +SELECT a FROM t2 WHERE a <> CAST(1 AS bit); +GO +~~START~~ +int +0 +~~END~~ + + +SELECT a FROM t2 WHERE a > CAST(0 AS bit) ORDER BY a; +GO +~~START~~ +int +-1 +1 +~~END~~ + +SELECT a FROM t2 WHERE a > CAST(1 AS bit); +GO +~~START~~ +int +~~END~~ + + +SELECT a FROM t2 WHERE a >= CAST(0 AS bit) ORDER BY a; +GO +~~START~~ +int +-1 +0 +1 +~~END~~ + +SELECT a FROM t2 WHERE a >= CAST(1 AS bit) ORDER BY a; +GO +~~START~~ +int +-1 +1 +~~END~~ + + +SELECT a FROM t2 WHERE a < CAST(0 AS bit); +GO +~~START~~ +int +~~END~~ + +SELECT a FROM t2 WHERE a < CAST(1 AS bit); +GO +~~START~~ +int +0 +~~END~~ + + +SELECT a FROM t2 WHERE a <= CAST(0 AS bit); +GO +~~START~~ +int +0 +~~END~~ + +SELECT a FROM t2 WHERE a <= CAST(1 AS bit) ORDER BY a; +GO +~~START~~ +int +-1 +0 +1 +~~END~~ + + +reset babelfishpg_tsql.sql_dialect; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error near '.' at line 1 and character position 22)~~ + +DROP TABLE t1; +GO +DROP TABLE t2; +GO diff --git a/contrib/test/JDBC/expected/babel_ceiling_floor.out b/contrib/test/JDBC/expected/babel_ceiling_floor.out new file mode 100644 index 00000000000..17e891af0f8 --- /dev/null +++ b/contrib/test/JDBC/expected/babel_ceiling_floor.out @@ -0,0 +1,116 @@ + +-- +-- Tests for ISNUMERIC function +-- +DROP TABLE IF EXISTS test_table +GO + +CREATE TABLE test_table ( + bigint_type bigint, + int_type int, + smallint_type smallint, + tinyint_type tinyint, + bit_type bit, + decimal_type decimal(5,2), + numeric_type numeric(10,5), + float_type float) +GO + +INSERT INTO test_table ( + bigint_type, + int_type, + smallint_type, + tinyint_type, + bit_type, + decimal_type, + numeric_type, + float_type) +VALUES ( + 9223372036854775806, + 45000, + -32767, + 100, + 1, + 123.456, + 12345.12, + 1.79E+30 +) +GO +~~ROW COUNT: 1~~ + + +-- Check correctness of values for floor function +SELECT + floor(bigint_type), + floor(int_type), + floor(smallint_type), + floor(tinyint_type), + floor(bit_type), + floor(decimal_type), + floor(numeric_type), + floor(float_type) +FROM test_table +GO +~~START~~ +bigint#!#int#!#smallint#!#tinyint#!#float#!#numeric#!#numeric#!#float +9223372036854775806#!#45000#!#-32767#!#100#!#1.0#!#123.00000000#!#12345.00000000#!#1.79E30 +~~END~~ + + +-- Check correctness of return types for floor function +SELECT + cast(pg_typeof(floor(bigint_type)) as varchar(10)), + cast(pg_typeof(floor(int_type)) as varchar(10)), + cast(pg_typeof(floor(smallint_type)) as varchar(10)), + cast(pg_typeof(floor(tinyint_type)) as varchar(10)), + cast(pg_typeof(floor(bit_type)) as varchar(10)), + cast(pg_typeof(floor(decimal_type)) as varchar(10)), + cast(pg_typeof(floor(numeric_type)) as varchar(10)), + cast(pg_typeof(floor(float_type)) as varchar(10)) +FROM test_table +GO +~~START~~ +varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar +bigint#!#integer#!#smallint#!#tinyint#!#double pre#!#numeric#!#numeric#!#double pre +~~END~~ + + +-- Check correctness of values for ceiling function +SELECT + ceiling(bigint_type), + ceiling(int_type), + ceiling(smallint_type), + ceiling(tinyint_type), + ceiling(bit_type), + ceiling(decimal_type), + ceiling(numeric_type), + ceiling(float_type) +FROM test_table +GO +~~START~~ +bigint#!#int#!#smallint#!#tinyint#!#float#!#numeric#!#numeric#!#float +9223372036854775806#!#45000#!#-32767#!#100#!#1.0#!#124.00000000#!#12346.00000000#!#1.79E30 +~~END~~ + + +-- Check correctness of return types for ceiling function +SELECT + cast(pg_typeof(ceiling(bigint_type)) as varchar(10)), + cast(pg_typeof(ceiling(int_type)) as varchar(10)), + cast(pg_typeof(ceiling(smallint_type)) as varchar(10)), + cast(pg_typeof(ceiling(tinyint_type)) as varchar(10)), + cast(pg_typeof(ceiling(bit_type)) as varchar(10)), + cast(pg_typeof(ceiling(decimal_type)) as varchar(10)), + cast(pg_typeof(ceiling(numeric_type)) as varchar(10)), + cast(pg_typeof(ceiling(float_type)) as varchar(10)) +FROM test_table +GO +~~START~~ +varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar +bigint#!#integer#!#smallint#!#tinyint#!#double pre#!#numeric#!#numeric#!#double pre +~~END~~ + + +--Cleanup +DROP TABLE test_table +GO diff --git a/contrib/test/JDBC/expected/babel_char.out b/contrib/test/JDBC/expected/babel_char.out new file mode 100644 index 00000000000..a6cae2fd7fd --- /dev/null +++ b/contrib/test/JDBC/expected/babel_char.out @@ -0,0 +1,73 @@ +select nchar(65); +select nchar(0x1); +select nchar(1) + nchar(2); +select nchar(66) + nchar(0x43); +select nchar(0x55) + nchar(0x103); +GO +~~START~~ +nvarchar +A +~~END~~ + +~~START~~ +nvarchar + +~~END~~ + +~~START~~ +text + +~~END~~ + +~~START~~ +text +BC +~~END~~ + +~~START~~ +text +U? +~~END~~ + + +-- 0x10FFFF is max value for nchar if the database supports the SC flag +-- See SQL Server documentation for more details +select nchar(1114111); +select nchar(0x10FFFF); +GO +~~START~~ +nvarchar +􏿿 +~~END~~ + +~~START~~ +nvarchar +􏿿 +~~END~~ + + +select nchar(1114112); +select nchar(0x110000); +select nchar(0); +select nchar(-1); +GO +~~START~~ +nvarchar + +~~END~~ + +~~START~~ +nvarchar + +~~END~~ + +~~START~~ +nvarchar + +~~END~~ + +~~START~~ +nvarchar + +~~END~~ + diff --git a/contrib/test/JDBC/expected/babel_collation.out b/contrib/test/JDBC/expected/babel_collation.out new file mode 100644 index 00000000000..2a023c395e6 --- /dev/null +++ b/contrib/test/JDBC/expected/babel_collation.out @@ -0,0 +1,201 @@ +create table testing_collation (col varchar(20)); +go +insert into testing_collation values ('JONES'); +insert into testing_collation values ('jones'); +insert into testing_collation values ('Jones'); +insert into testing_collation values ('JoNes'); +insert into testing_collation values ('JoNés'); +go +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +select * from testing_collation where col collate SQL_Latin1_General_CP1_CS_AS = 'JoNes'; +go +~~START~~ +varchar +JoNes +~~END~~ + + +select * from testing_collation where col collate SQL_Latin1_General_CP1_CI_AS = 'JoNes'; +go +~~START~~ +varchar +JONES +jones +Jones +JoNes +~~END~~ + + +select * from testing_collation where col collate SQL_Latin1_General_CP1_CI_AI = 'JoNes'; +go +~~START~~ +varchar +JONES +jones +Jones +JoNes +JoNés +~~END~~ + + +-- all the currently supported TSQL collations +SELECT * from fn_helpcollations(); +go +~~START~~ +varchar#!#varchar +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 +~~END~~ + + +-- BABEL-1697 Collation and Codepage information for DMS +SELECT CAST( COLLATIONPROPERTY(Name, 'CodePage') AS INT) FROM fn_helpcollations() where Name = DATABASEPROPERTYEX('template1', 'Collation'); +go +~~START~~ +int +1252 +~~END~~ + + +SELECT CAST( COLLATIONPROPERTY(Name, 'lcid') AS INT) FROM fn_helpcollations() where Name = DATABASEPROPERTYEX('template1', 'Collation'); +go +~~START~~ +int +1033 +~~END~~ + + +-- clean up +drop table testing_collation; +go diff --git a/contrib/test/JDBC/expected/babel_iif.out b/contrib/test/JDBC/expected/babel_iif.out new file mode 100644 index 00000000000..c7127a976e2 --- /dev/null +++ b/contrib/test/JDBC/expected/babel_iif.out @@ -0,0 +1,109 @@ +select iif (2 < 1, cast('2020-10-20 09:00:00' as datetime), cast('2020-10-21' as date)); +go +~~START~~ +datetime +2020-10-21 00:00:00.0 +~~END~~ + +select iif (2 > 1, cast('abc' as varchar(3)), cast('cba' as char(3))); +go +~~START~~ +varchar +abc +~~END~~ + +select iif (2 > 1, cast(3.14 as float), cast(31.4 as numeric(3, 1))); +go +~~START~~ +float +3.14 +~~END~~ + +select iif (2 > 1, cast(3.14 as float), cast(1 as int)); +go +~~START~~ +float +3.14 +~~END~~ + +select iif (2 > 1, cast('$123.123' as money), cast(1 as int)); +go +~~START~~ +money +123.1230 +~~END~~ + +select iif (2 > 1, cast('$123.123' as money), cast(3.14 as float)); +go +~~START~~ +float +123.123 +~~END~~ + +select iif (2 > 1, cast('2020-10-20 09:00:00' as datetime), cast('09:00:00' as time)); +go +~~START~~ +datetime +2020-10-20 09:00:00.0 +~~END~~ + +select iif (2 > 1, cast('$123.123' as money), cast(321 as bigint)); +go +~~START~~ +money +123.1230 +~~END~~ + +select iif (2 > 1, cast(3.14 as float), cast('$123.123' as money)); +go +~~START~~ +float +3.14 +~~END~~ + + +-- Error, unknown literal cannot fit target type typinput func +select iif (2 > 1, 1, 'abc'); +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: invalid input syntax for type integer: "abc")~~ + +-- Error, different categories +select iif (2 > 1, cast(1 as int), cast('abc' as varchar(3))); +go +~~START~~ +int +1 +~~END~~ + +select iif (2 > 1, cast(0 as bit), cast(1 as int)); +go +~~START~~ +int +0 +~~END~~ + + +-- Null handling +select iif (2 > 1, null, 0); +go +~~START~~ +int + +~~END~~ + +select iif (null, 1, 0); +go +~~START~~ +int +0 +~~END~~ + +select iif (null, null, null); +go +~~START~~ +int + +~~END~~ + diff --git a/contrib/test/JDBC/expected/babel_isnull.out b/contrib/test/JDBC/expected/babel_isnull.out new file mode 100644 index 00000000000..23e5ba41dfc --- /dev/null +++ b/contrib/test/JDBC/expected/babel_isnull.out @@ -0,0 +1,215 @@ +-- tsql +CREATE TABLE test_numeric ( + num1 int, + num2 numeric +); +INSERT INTO test_numeric(num1, num2) +VALUES + (10, NULL), + (20, 2000), + (30, 3000), + (NULL, 4000), + (50, NULL); +GO +~~ROW COUNT: 5~~ + + +-- psql currentSchema=master_dbo,public +SELECT * FROM test_numeric; +GO +~~START~~ +int4#!#numeric +10#!# +20#!#2000 +30#!#3000 +#!#4000 +50#!# +~~END~~ + + +SELECT ISNULL(SUM(num1 - ISNULL(num2, 0)), 0) +FROM test_numeric +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: function isnull(numeric, integer) does not exist + Hint: No function matches the given name and argument types. You might need to add explicit type casts. + Position: 26 + Server SQLState: 42883)~~ + + +-- tsql +-- Prove that a user may replace null values with a specified value using ISNULL +SELECT ISNULL(SUM(num1 - ISNULL(num2, 0)), 0) +FROM test_numeric +GO +~~START~~ +numeric +-4890 +~~END~~ + + +DROP TABLE test_numeric +GO + +-- Test cases with timestamps and sub-queries inside ISNULL +CREATE TABLE test_timestamp ( + serial_no numeric, + ts datetime2, +) +GO + +INSERT INTO test_timestamp(serial_no, ts) +VALUES + (1, NULL), + (2, '2020-06-22 00:10:00'), + (3, '2020-07-23 00:10:00'), + (4, '2020-08-24 00:10:00'), + (5, NULL), + (6, '2020-09-25 00:10:00') +GO +~~ROW COUNT: 6~~ + + +SELECT * FROM test_timestamp +GO +~~START~~ +numeric#!#datetime2 +1#!# +2#!#2020-06-22 00:10:00.000000 +3#!#2020-07-23 00:10:00.000000 +4#!#2020-08-24 00:10:00.000000 +5#!# +6#!#2020-09-25 00:10:00.000000 +~~END~~ + + +SELECT ISNULL(ts, '2021-01-01 00:00:00') +FROM test_timestamp +GO +~~START~~ +datetime2 +2021-01-01 00:00:00.000000 +2020-06-22 00:10:00.000000 +2020-07-23 00:10:00.000000 +2020-08-24 00:10:00.000000 +2021-01-01 00:00:00.000000 +2020-09-25 00:10:00.000000 +~~END~~ + + +CREATE TABLE default_time ( + ts datetime2 +) +GO + +INSERT INTO default_time(ts) VALUES('1970-01-01 00:00:00') +GO +~~ROW COUNT: 1~~ + + +SELECT ISNULL(ts, (SELECT ts FROM default_time)) +FROM test_timestamp +GO +~~START~~ +datetime2 +1970-01-01 00:00:00.000000 +2020-06-22 00:10:00.000000 +2020-07-23 00:10:00.000000 +2020-08-24 00:10:00.000000 +1970-01-01 00:00:00.000000 +2020-09-25 00:10:00.000000 +~~END~~ + + +DROP TABLE test_timestamp +GO +DROP TABLE default_time +GO + +-- Test cases with characters and casts +CREATE TABLE test_char ( + name varchar(20), + employee_type numeric, + age numeric +) +GO + +INSERT INTO test_char(name, employee_type, age) +VALUES + ('John', 1, 45), + (NULL, 0, 21), + ('Jake', 3, 33), + ('Jack', 1, 64), + ('Jane', NULL, 51) +GO +~~ROW COUNT: 5~~ + + +SELECT * FROM test_char +GO +~~START~~ +varchar#!#numeric#!#numeric +John#!#1#!#45 +#!#0#!#21 +Jake#!#3#!#33 +Jack#!#1#!#64 +Jane#!##!#51 +~~END~~ + + +SELECT ISNULL(name, 'Unknown'), ISNULL(employee_type, 'N/A'), age +FROM test_char +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: invalid input syntax for type numeric: "N/A")~~ + + +DROP TABLE test_char +GO + +-- Test cases for incorrect number of arguments +CREATE TABLE test_args ( + word char(10) +) +GO +INSERT INTO test_args(word) +VALUES + ('hello'), + (NULL), + ('goodbye') +GO +~~ROW COUNT: 3~~ + + +SELECT ISNULL() from test_args +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error at or near ")")~~ + +SELECT ISNULL(word) FROM test_args +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error at or near ")")~~ + +SELECT ISNULL(word, 'no', 'yes') FROM test_args +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error at or near ",")~~ + + +-- Test case for varbinary +SELECT ISNULL(null, CAST(0xfe AS VARBINARY)) +GO +~~START~~ +varbinary +FE +~~END~~ + + +DROP TABLE test_args +GO diff --git a/contrib/test/JDBC/expected/babel_money.out b/contrib/test/JDBC/expected/babel_money.out new file mode 100644 index 00000000000..c2f0362996b --- /dev/null +++ b/contrib/test/JDBC/expected/babel_money.out @@ -0,0 +1,544 @@ +SELECT set_config('extra_float_digits', '0', 'false') +go +~~START~~ +text +0 +~~END~~ + + +-- test money operators return type money +create table t1(a money, b smallmoney); +insert into t1 values (1.1234, 2.1234); +insert into t1 values (2.5678, 3.5678); +insert into t1 values (4.9012, 5.9012); +go +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +select * from t1 order by a; +go +~~START~~ +money#!#smallmoney +1.1234#!#2.1234 +2.5678#!#3.5678 +4.9012#!#5.9012 +~~END~~ + + +-- test implicit casting for money +create table t2(a money, b smallmoney); +insert into t2 values (CAST( '1.1234' AS CHAR(10)), CAST( '2.1234' AS CHAR(10))); +insert into t2 values (CAST( '$2.56789' AS VARCHAR), CAST( '$3.56789' AS VARCHAR)); +insert into t2 values (CAST( '¥4.91' AS TEXT), CAST( '¥5.91' AS TEXT)); +insert into t2 values (CAST( '0006.' AS TEXT), CAST( '0000' AS TEXT)); +go +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +select * from t2 order by a; +go +~~START~~ +money#!#smallmoney +1.1234#!#2.1234 +2.5678#!#3.5678 +4.9100#!#5.9100 +6.0000#!#0.0000 +~~END~~ + + +select sum(a), sum(b) from t1; +go +~~START~~ +money#!#money +8.5924#!#11.5924 +~~END~~ + + +select cast(pg_typeof(sum(a)) AS VARCHAR(10)), cast(pg_typeof(sum(b)) AS VARCHAR(10)) from t1; +go +~~START~~ +varchar#!#varchar +money#!#money +~~END~~ + + +select avg(a), avg(b) from t1; +go +~~START~~ +money#!#money +2.8641#!#3.8641 +~~END~~ + + +select cast(pg_typeof(avg(a)) AS VARCHAR(10)), cast(pg_typeof(avg(b)) AS VARCHAR(10)) from t1; +go +~~START~~ +varchar#!#varchar +money#!#money +~~END~~ + + +select a+b from t1 order by a; +go +~~START~~ +money +3.2468 +6.1356 +10.8024 +~~END~~ + + +select cast(pg_typeof(a+b) AS VARCHAR(10)) from t1 order by a; +go +~~START~~ +varchar +money +money +money +~~END~~ + + +select b-a from t1 order by a; +go +~~START~~ +money +1.0000 +1.0000 +1.0000 +~~END~~ + + +select cast(pg_typeof(b-a) AS VARCHAR(10)) from t1 order by a; +go +~~START~~ +varchar +money +money +money +~~END~~ + + +select a*b from t1 order by a; +go +~~START~~ +money +2.3854 +9.1613 +28.9229 +~~END~~ + + +select cast(pg_typeof(a*b) AS VARCHAR(10)) from t1 order by a; +go +~~START~~ +varchar +money +money +money +~~END~~ + + +select a/b from t1 order by a; +go +~~START~~ +money +0.5290 +0.7197 +0.8305 +~~END~~ + + +select cast(pg_typeof(a/b) AS VARCHAR(10)) from t1 order by a; +go +~~START~~ +varchar +money +money +money +~~END~~ + + + +drop table t1, t2; +-- BABEL-598 Money type as procedure parameter should work without explicit cast +create table employees(pers_id int, fname nvarchar(20), lname nvarchar(30), sal money); +go + +create procedure p_employee_select +as +begin + select * from employees +end; +go + +create procedure p_employee_insert +@pers_id int, @fname nvarchar(20), @lname nvarchar(30), @sal money +as +begin + insert into employees values (@pers_id, @fname, @lname, @sal) +end; +go + +-- test const 123.1234 and 200 are valid MONEY inputs for the procedure without explicit cast +execute p_employee_insert @pers_id=1, @fname='John', @lname='Johnson', @sal=123.1234; +execute p_employee_insert @pers_id=1, @fname='Adam', @lname='Smith', @sal=200; +go +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +execute p_employee_select; +go +~~START~~ +int#!#nvarchar#!#nvarchar#!#money +1#!#John#!#Johnson#!#123.1234 +1#!#Adam#!#Smith#!#200.0000 +~~END~~ + + +drop procedure p_employee_select; +drop procedure p_employee_insert; +drop table employees; +go + +-- BABEL-920 +-- Test operations(e.g. +,-,*,/) between fixeddecimal(money/smallmoney) and int8(bigint) +select CAST(2.56 as bigint) + CAST(3.60 as money); +go +~~START~~ +money +5.6000 +~~END~~ + +select CAST(3.60 as money) + CAST(2.56 as bigint); +go +~~START~~ +money +5.6000 +~~END~~ + +select CAST(2.56 as bigint) - CAST(3.60 as money); +go +~~START~~ +money +-1.6000 +~~END~~ + +select CAST(3.60 as money) - CAST(2.56 as bigint); +go +~~START~~ +money +1.6000 +~~END~~ + +select CAST(2.56 as bigint) * CAST(3.60 as money); +go +~~START~~ +money +7.2000 +~~END~~ + +select CAST(3.60 as money) * CAST(2.56 as bigint); +go +~~START~~ +money +7.2000 +~~END~~ + +select CAST(2.56 as bigint) / CAST(3.60 as money); +go +~~START~~ +float +0.5555555555555556 +~~END~~ + +select CAST(3.60 as money) / CAST(2.56 as bigint); +go +~~START~~ +money +1.8000 +~~END~~ + + +select CAST(2.56 as bigint) + CAST(3.60 as smallmoney); +go +~~START~~ +money +5.6000 +~~END~~ + +select CAST(3.60 as smallmoney) + CAST(2.56 as bigint); +go +~~START~~ +money +5.6000 +~~END~~ + +select CAST(2.56 as bigint) - CAST(3.60 as smallmoney); +go +~~START~~ +money +-1.6000 +~~END~~ + +select CAST(3.60 as smallmoney) - CAST(2.56 as bigint); +go +~~START~~ +money +1.6000 +~~END~~ + +select CAST(2.56 as bigint) * CAST(3.60 as smallmoney); +go +~~START~~ +money +7.2000 +~~END~~ + +select CAST(3.60 as smallmoney) * CAST(2.56 as bigint); +go +~~START~~ +money +7.2000 +~~END~~ + +-- select CAST(2.56 as bigint) / CAST(3.60 as smallmoney); -> see BABEL-977 +-- go +select CAST(3.60 as smallmoney) / CAST(2.56 as bigint); +go +~~START~~ +money +1.8000 +~~END~~ + + +-- Test operations(e.g. +,-,*,/) between fixeddecimal(money/smallmoney) and int4(int) +select CAST(2.56 as int) + CAST(3.60 as money); +go +~~START~~ +money +5.6000 +~~END~~ + +select CAST(3.60 as money) + CAST(2.56 as int); +go +~~START~~ +money +5.6000 +~~END~~ + +select CAST(2.56 as int) - CAST(3.60 as money); +go +~~START~~ +money +-1.6000 +~~END~~ + +select CAST(3.60 as money) - CAST(2.56 as int); +go +~~START~~ +money +1.6000 +~~END~~ + +select CAST(2.56 as int) * CAST(3.60 as money); +go +~~START~~ +money +7.2000 +~~END~~ + +select CAST(3.60 as money) * CAST(2.56 as int); +go +~~START~~ +money +7.2000 +~~END~~ + +select CAST(2.56 as int) / CAST(3.60 as money); +go +~~START~~ +float +0.5555555555555556 +~~END~~ + +select CAST(3.60 as money) / CAST(2.56 as int); +go +~~START~~ +money +1.8000 +~~END~~ + + +select CAST(2.56 as int) + CAST(3.60 as smallmoney); +go +~~START~~ +money +5.6000 +~~END~~ + +select CAST(3.60 as smallmoney) + CAST(2.56 as int); +go +~~START~~ +money +5.6000 +~~END~~ + +select CAST(2.56 as int) - CAST(3.60 as smallmoney); +go +~~START~~ +money +-1.6000 +~~END~~ + +select CAST(3.60 as smallmoney) - CAST(2.56 as int); +go +~~START~~ +money +1.6000 +~~END~~ + +select CAST(2.56 as int) * CAST(3.60 as smallmoney); +go +~~START~~ +money +7.2000 +~~END~~ + +select CAST(3.60 as smallmoney) * CAST(2.56 as int); +go +~~START~~ +money +7.2000 +~~END~~ + +-- select CAST(2.56 as int) / CAST(3.60 as smallmoney); -> see BABEL-977 +-- go +select CAST(3.60 as smallmoney) / CAST(2.56 as int); +go +~~START~~ +money +1.8000 +~~END~~ + + +-- Test operations(e.g. +,-,*,/) between fixeddecimal(money/smallmoney) and int2(smallint) +select CAST(2.56 as smallint) + CAST(3.60 as money); +go +~~START~~ +money +5.6000 +~~END~~ + +select CAST(3.60 as money) + CAST(2.56 as smallint); +go +~~START~~ +money +5.6000 +~~END~~ + +select CAST(2.56 as smallint) - CAST(3.60 as money); +go +~~START~~ +money +-1.6000 +~~END~~ + +select CAST(3.60 as money) - CAST(2.56 as smallint); +go +~~START~~ +money +1.6000 +~~END~~ + +select CAST(2.56 as smallint) * CAST(3.60 as money); +go +~~START~~ +money +7.2000 +~~END~~ + +select CAST(3.60 as money) * CAST(2.56 as smallint); +go +~~START~~ +money +7.2000 +~~END~~ + +select CAST(2.56 as smallint) / CAST(3.60 as money); +go +~~START~~ +float +0.5555555555555556 +~~END~~ + +select CAST(3.60 as money) / CAST(2.56 as smallint); +go +~~START~~ +money +1.8000 +~~END~~ + + +select CAST(2.56 as smallint) + CAST(3.60 as smallmoney); +go +~~START~~ +money +5.6000 +~~END~~ + +select CAST(3.60 as smallmoney) + CAST(2.56 as smallint); +go +~~START~~ +money +5.6000 +~~END~~ + +select CAST(2.56 as smallint) - CAST(3.60 as smallmoney); +go +~~START~~ +money +-1.6000 +~~END~~ + +select CAST(3.60 as smallmoney) - CAST(2.56 as smallint); +go +~~START~~ +money +1.6000 +~~END~~ + +select CAST(2.56 as smallint) * CAST(3.60 as smallmoney); +go +~~START~~ +money +7.2000 +~~END~~ + +select CAST(3.60 as smallmoney) * CAST(2.56 as smallint); +go +~~START~~ +money +7.2000 +~~END~~ + +-- select CAST(2.56 as smallint) / CAST(3.60 as smallmoney); -> see BABEL-977 +-- go +select CAST(3.60 as smallmoney) / CAST(2.56 as smallint); +go +~~START~~ +money +1.8000 +~~END~~ + diff --git a/contrib/test/JDBC/expected/babel_numeric.out b/contrib/test/JDBC/expected/babel_numeric.out new file mode 100644 index 00000000000..40988a68576 --- /dev/null +++ b/contrib/test/JDBC/expected/babel_numeric.out @@ -0,0 +1,123 @@ +-- Test numeric in cast function +select cast(1.123 as numeric(38, 10)); +go +~~START~~ +numeric +1.1230000000 +~~END~~ + +select cast(1.123 as numeric(39, 10)); +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The size (39) given to the type 'numeric' exceeds the maximum allowed (38))~~ + + +-- Test decimal in cast function +select cast(1.123 as decimal(38, 10)); +go +~~START~~ +numeric +1.1230000000 +~~END~~ + +select cast(1.123 as decimal(39, 10)); +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The size (39) given to the type 'decimal' exceeds the maximum allowed (38))~~ + + +-- Test dec in cast function +select cast(1.123 as dec(38, 10)); +go +~~START~~ +numeric +1.1230000000 +~~END~~ + +select cast(1.123 as dec(39, 10)); +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The size (39) given to the type 'decimal' exceeds the maximum allowed (38))~~ + + +-- Test numeric in create table +create table t1 (col numeric(38,37)); +drop table t1; +go + +create table t1 (col numeric(39, 37)); +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The size (39) given to the type 'numeric' exceeds the maximum allowed (38))~~ + + +-- Test decimal in create table +create table t1 (col decimal(38,37)); +drop table t1; +go + +create table t1 (col decimal(39, 37)); +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The size (39) given to the type 'decimal' exceeds the maximum allowed (38))~~ + + +-- Test dec in create table +create table t1 (col decimal(38,37)); +drop table t1; +go + +create table t1 (col decimal(39, 37)); +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The size (39) given to the type 'decimal' exceeds the maximum allowed (38))~~ + + +-- Test default precision and scale is set to 18, 0 +create table t1 (col numeric); +insert into t1 values (1.2); +insert into t1 values (123456789012345678); +select * from t1; +go +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +numeric +1 +123456789012345678 +~~END~~ + +insert into t1 values (1234567890123456789); +select * from t1; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: numeric field overflow)~~ + + +drop table t1; +go + +-- Test default scale is set to 0 if only precision is specified +create table t1 (col numeric(4)); +insert into t1 values (1.2); +select * from t1; +go +~~ROW COUNT: 1~~ + +~~START~~ +numeric +1 +~~END~~ + + +drop table t1; +go diff --git a/contrib/test/JDBC/expected/babel_operators.out b/contrib/test/JDBC/expected/babel_operators.out new file mode 100644 index 00000000000..188153324d7 --- /dev/null +++ b/contrib/test/JDBC/expected/babel_operators.out @@ -0,0 +1,208 @@ +-- test adding with varbinary +SELECT (123 + 0x42); +SELECT (0x42 + 123); +GO +~~START~~ +bigint +189 +~~END~~ + +~~START~~ +bigint +189 +~~END~~ + + +-- test subtracting with varbinary +SELECT (123 - 0x42); +SELECT (0x42 - 123); +GO +~~START~~ +bigint +57 +~~END~~ + +~~START~~ +bigint +-57 +~~END~~ + + +-- test multiplication with varbinary +SELECT (123 * CAST(123 AS varbinary(4))); +SELECT (CAST(123 AS varbinary(4)) * 123); +GO +~~START~~ +bigint +15129 +~~END~~ + +~~START~~ +bigint +15129 +~~END~~ + + +-- test division with varbinary +SELECT (12345 / CAST(12 AS varbinary(4))); +SELECT (CAST(12345 AS varbinary(4)) / 12); +GO +~~START~~ +bigint +1028 +~~END~~ + +~~START~~ +bigint +1028 +~~END~~ + + +-- test & operator with varbinary +SELECT (CAST(123 AS varbinary(1)) & 21); +SELECT (CAST(123 AS varbinary(2)) & 321); +SELECT (CAST(12345 AS varbinary(4)) & 54321); +GO +~~START~~ +int +17 +~~END~~ + +~~START~~ +int +65 +~~END~~ + +~~START~~ +int +4145 +~~END~~ + + +SELECT (CAST(9876543210 AS BIGINT) & CAST(1234567890 AS varbinary(8))); +SELECT (543210 & CAST(12345 AS varbinary(4))); +SELECT (CAST(321 AS smallint) & CAST(123 AS varbinary(2))); +SELECT (CAST(12 AS tinyint) & CAST(21 AS varbinary(1))); +GO +~~START~~ +bigint +1217397442 +~~END~~ + +~~START~~ +int +40 +~~END~~ + +~~START~~ +smallint +65 +~~END~~ + +~~START~~ +smallint +4 +~~END~~ + + +-- test | operator with varbinary +SELECT (CAST(123 AS varbinary(1)) | 21); +SELECT (CAST(123 AS varbinary(2)) | 321); +SELECT (CAST(12345 AS varbinary(4)) | 54321); +GO +~~START~~ +int +127 +~~END~~ + +~~START~~ +int +379 +~~END~~ + +~~START~~ +int +62521 +~~END~~ + + +SELECT (CAST(9876543210 AS BIGINT) | CAST(1234567890 AS varbinary(8))); +SELECT (543210 | CAST(12345 AS varbinary(4))); +SELECT (CAST(321 AS smallint) | CAST(123 AS varbinary(2))); +SELECT (CAST(12 AS tinyint) | CAST(21 AS varbinary(1))); +GO +~~START~~ +bigint +9893713658 +~~END~~ + +~~START~~ +int +555515 +~~END~~ + +~~START~~ +smallint +379 +~~END~~ + +~~START~~ +smallint +29 +~~END~~ + + +-- test ^ operator with varbinary +SELECT (17 ^ 5); +GO +~~START~~ +int +20 +~~END~~ + + +SELECT (CAST(123 AS varbinary(1)) ^ 21); +SELECT (CAST(123 AS varbinary(2)) ^ 321); +SELECT (CAST(12345 AS varbinary(4)) ^ 54321); +GO +~~START~~ +int +110 +~~END~~ + +~~START~~ +int +314 +~~END~~ + +~~START~~ +int +58376 +~~END~~ + + +SELECT (CAST(9876543210 AS BIGINT) ^ CAST(1234567890 AS varbinary(8))); +SELECT (543210 ^ CAST(12345 AS varbinary(4))); +SELECT (CAST(321 AS smallint) ^ CAST(123 AS varbinary(2))); +SELECT (CAST(12 AS tinyint) ^ CAST(21 AS varbinary(1))); +GO +~~START~~ +bigint +8676316216 +~~END~~ + +~~START~~ +int +555475 +~~END~~ + +~~START~~ +smallint +314 +~~END~~ + +~~START~~ +smallint +25 +~~END~~ + diff --git a/contrib/test/JDBC/expected/babel_print.out b/contrib/test/JDBC/expected/babel_print.out new file mode 100644 index 00000000000..dce20955c06 --- /dev/null +++ b/contrib/test/JDBC/expected/babel_print.out @@ -0,0 +1,39 @@ +-- Test PRINT with T-sql procedures -- +-- Printing a pre-defined text +CREATE PROCEDURE tsql_print_text AS + PRINT 'Pre-defined text for tsql_print_text' +GO +EXEC tsql_print_text +GO + +-- Printing a user input text +CREATE PROCEDURE tsql_print_message(@message varchar(50)) AS +BEGIN + PRINT @message +END; +GO +EXEC tsql_print_message 'Testing message for tsql_print_message' +GO + +-- Printing a pre-defined and a user input text +CREATE PROCEDURE tsql_print_message_and_text(@message varchar(50)) AS +BEGIN + PRINT 'Pre-defined text for tsql_print_message_and_text. User input: '+ @message +END +GO +EXEC tsql_print_message_and_text 'Testing message for tsql_print_message_and_text' +GO + +-- Making a call to another function that prints +CREATE PROCEDURE tsql_print_function AS + EXECUTE tsql_print_text +GO +EXEC tsql_print_function +GO + +-- Cleanup -- +DROP PROCEDURE tsql_print_text; +DROP PROCEDURE tsql_print_message; +DROP PROCEDURE tsql_print_message_and_text; +DROP PROCEDURE tsql_print_function; +GO diff --git a/contrib/test/JDBC/expected/babel_smalldatetime.out b/contrib/test/JDBC/expected/babel_smalldatetime.out new file mode 100644 index 00000000000..4e3d97aad26 --- /dev/null +++ b/contrib/test/JDBC/expected/babel_smalldatetime.out @@ -0,0 +1,388 @@ +-- 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 15:59:00.0 +~~END~~ + +~~START~~ +smalldatetime +2010-07-08 15:59:00.0 +~~END~~ + +~~START~~ +smalldatetime +1980-07-09 07:59:00.0 +~~END~~ + +~~START~~ +smalldatetime +2010-07-09 07: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.000000 +~~END~~ + +~~START~~ +time +23:59:00.000000 +~~END~~ + +~~START~~ +time +00:00:00.000000 +~~END~~ + +~~START~~ +time +23:59:00.000000 +~~END~~ + +~~START~~ +time +00:00:00.000000 +~~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.000000 +00:00 +~~END~~ + +~~START~~ +datetimeoffset +1990-07-08 23:59:00.000000 +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~~ + +~~START~~ +smalldatetime +2079-06-06 23: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 +1900-01-01 00:00:00.0 +~~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/test/JDBC/expected/babel_top.out b/contrib/test/JDBC/expected/babel_top.out new file mode 100644 index 00000000000..df5d7b3efb2 --- /dev/null +++ b/contrib/test/JDBC/expected/babel_top.out @@ -0,0 +1,91 @@ + +-- +-- Tests for TOP clause +-- +create table students (fname varchar(10), lname varchar(10), score double precision) +go + +insert into students (fname, lname, score) +values + ('John', 'Doe', 72.5), + ('Jane', 'Smith', 88), + ('Jill', 'Johnson', 98), + ('Jack', 'Green', 67), + ('Jennifer', 'Ross', 75.7), + ('Jacob', 'Brown', 95.2) +go +~~ROW COUNT: 6~~ + + +select top 3 * from students +go +~~START~~ +varchar#!#varchar#!#float +John#!#Doe#!#72.5 +Jane#!#Smith#!#88.0 +Jill#!#Johnson#!#98.0 +~~END~~ + + +select top 4 score from students +go +~~START~~ +float +72.5 +88.0 +98.0 +67.0 +~~END~~ + + +select top 3 from students +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error near 'from' at line 1 and character position 13)~~ + + +-- test top bigint +select top 2147483648 * from students +go +~~START~~ +varchar#!#varchar#!#float +John#!#Doe#!#72.5 +Jane#!#Smith#!#88.0 +Jill#!#Johnson#!#98.0 +Jack#!#Green#!#67.0 +Jennifer#!#Ross#!#75.7 +Jacob#!#Brown#!#95.2 +~~END~~ + + +-- test top 100 percent +select top 100 percent * from students +go +~~START~~ +varchar#!#varchar#!#float +John#!#Doe#!#72.5 +Jane#!#Smith#!#88.0 +Jill#!#Johnson#!#98.0 +Jack#!#Green#!#67.0 +Jennifer#!#Ross#!#75.7 +Jacob#!#Brown#!#95.2 +~~END~~ + + +select top 100.00 percent lname from students +go +~~START~~ +varchar +Doe +Smith +Johnson +Green +Ross +Brown +~~END~~ + + +-- cleanup +drop table students +go diff --git a/contrib/test/JDBC/expected/babel_trigger.out b/contrib/test/JDBC/expected/babel_trigger.out new file mode 100644 index 00000000000..51617b0ac5d --- /dev/null +++ b/contrib/test/JDBC/expected/babel_trigger.out @@ -0,0 +1,407 @@ +-- a simple test +create table testing1(col nvarchar(60)) +GO + +create trigger notify on testing1 after insert +as +begin + SELECT 'trigger invoked' +end +GO + +insert into testing1 (col) select N'Muffler' +GO +~~START~~ +varchar +trigger invoked +~~END~~ + +~~ROW COUNT: 1~~ + + +drop trigger notify +GO + +-- test drop trigger if exists +create trigger notify on testing1 after insert +as +begin + SELECT 'trigger invoked' +end +GO + +drop trigger if exists notify +GO + +drop trigger if exists notify +GO + +-- test comma separator +create trigger notify on testing1 after insert, delete +as +begin + SELECT 'trigger invoked' +end +GO + +insert into testing1 (col) select N'Apple' +GO +~~START~~ +varchar +trigger invoked +~~END~~ + +~~ROW COUNT: 1~~ + + +delete from testing1 where col = N'Apple' +GO +~~START~~ +varchar +trigger invoked +~~END~~ + +~~ROW COUNT: 1~~ + + +drop trigger notify +GO + +-- test inserted and deleted transition tables +CREATE TABLE products( + product_id INT NOT NULL, + product_name VARCHAR(255) NOT NULL, + brand_id INT NOT NULL, + category_id INT NOT NULL, + model_year SMALLINT NOT NULL, + list_price DEC(10,2) NOT NULL +) +GO + +CREATE TABLE product_audits( + product_id INT NOT NULL, + product_name VARCHAR(255) NOT NULL, + brand_id INT NOT NULL, + category_id INT NOT NULL, + model_year SMALLINT NOT NULL, + list_price DEC(10,2) NOT NULL, + operation CHAR(3) NOT NULL, + CHECK(operation = 'INS' or operation='DEL') +) +GO + +CREATE TRIGGER trg_product_audit +ON products +AFTER INSERT +AS +BEGIN + INSERT INTO product_audits( + product_id, + product_name, + brand_id, + category_id, + model_year, + list_price, + operation + ) + SELECT + i.product_id, + product_name, + brand_id, + category_id, + model_year, + i.list_price, + 'INS' + FROM + inserted i +END +GO + +INSERT INTO products( + product_id, + product_name, + brand_id, + category_id, + model_year, + list_price +) +VALUES ( + 1, + 'Test product', + 1, + 1, + 2018, + 599 +) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +SELECT * FROM PRODUCT_AUDITS +GO +~~START~~ +int#!#varchar#!#int#!#int#!#smallint#!#numeric#!#char +1#!#Test product#!#1#!#1#!#2018#!#599.00#!#INS +~~END~~ + + +drop trigger trg_product_audit +GO + +-- clean up +drop table testing1 +GO +drop table product_audits +GO +drop table products +GO + + +-- CARRY OUT THE SAME TESTS WITH THE FOR KEYWORD -- +-- a simple test +create table testing1(col nvarchar(60)) +GO + +create trigger notify on testing1 for insert +as +begin + SELECT 'trigger invoked' +end +GO + +insert into testing1 (col) select N'Muffler' +GO +~~START~~ +varchar +trigger invoked +~~END~~ + +~~ROW COUNT: 1~~ + + +drop trigger notify +GO + +-- test drop trigger if exists +create trigger notify on testing1 for insert +as +begin + SELECT 'trigger invoked' +end +GO + +drop trigger if exists notify +GO + +drop trigger if exists notify +GO + +-- test comma separator +create trigger notify on testing1 for insert, delete +as +begin + SELECT 'trigger invoked' +end +GO + +insert into testing1 (col) select N'Apple' +GO +~~START~~ +varchar +trigger invoked +~~END~~ + +~~ROW COUNT: 1~~ + + +delete from testing1 where col = N'Apple' +GO +~~START~~ +varchar +trigger invoked +~~END~~ + +~~ROW COUNT: 1~~ + + +drop trigger notify +GO + +-- test inserted and deleted transition tables +CREATE TABLE products( + product_id INT NOT NULL, + product_name VARCHAR(255) NOT NULL, + brand_id INT NOT NULL, + category_id INT NOT NULL, + model_year SMALLINT NOT NULL, + list_price DEC(10,2) NOT NULL +) +GO + +CREATE TABLE product_audits( + product_id INT NOT NULL, + product_name VARCHAR(255) NOT NULL, + brand_id INT NOT NULL, + category_id INT NOT NULL, + model_year SMALLINT NOT NULL, + list_price DEC(10,2) NOT NULL, + operation CHAR(3) NOT NULL, + CHECK(operation = 'INS' or operation='DEL') +) +GO + +CREATE TRIGGER trg_product_audit +ON products +FOR INSERT +AS +BEGIN + INSERT INTO product_audits( + product_id, + product_name, + brand_id, + category_id, + model_year, + list_price, + operation + ) + SELECT + i.product_id, + product_name, + brand_id, + category_id, + model_year, + i.list_price, + 'INS' + FROM + inserted i +END +GO + +INSERT INTO products( + product_id, + product_name, + brand_id, + category_id, + model_year, + list_price +) +VALUES ( + 1, + 'Test product', + 1, + 1, + 2018, + 599 +) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +SELECT * FROM PRODUCT_AUDITS +GO +~~START~~ +int#!#varchar#!#int#!#int#!#smallint#!#numeric#!#char +1#!#Test product#!#1#!#1#!#2018#!#599.00#!#INS +~~END~~ + + +drop trigger trg_product_audit +GO + +-- Test drop trigger without table name -- +-- First, test that triggers must have unique names +create trigger notify on testing1 after insert +as +begin + SELECT 'trigger invoked' +end +GO + +create table testing2(col nvarchar(60)) +GO + +create trigger notify on testing2 after insert +as +begin + SELECT 'trigger invoked' +end +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: trigger "notify" already exists in the database)~~ + + +drop table testing2 +GO + +-- Now, test that drop trigger works without tablename +drop trigger notify +GO + +-- Test that drop trigger statement on non-existent trigger throws error +drop trigger notify +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: trigger "notify" does not exist)~~ + +drop trigger if exists notify +GO + +-- Test that dropping a table with triggers defined on it succeeds +create table testTbl(colA int not null primary key, colB varchar(20)) +GO + +create trigger trig1 on testTbl after insert +as +begin + SELECT 'trigger invoked' +end +GO + +create trigger trig2 on testTbl after insert +as +begin + SELECT 'trigger2 invoked' +end +GO + +drop table testTbl +GO + +-- Test 'NOT FOR REPLICATION' syntax +create trigger notify on testing1 after insert +NOT FOR REPLICATION +as +begin + SELECT 'trigger invoked' +end +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'NOT FOR REPLICATION' is not currently supported in Babelfish. please use babelfishpg_tsql.escape_hatch_for_replication to ignore)~~ + + +insert into testing1 (col) select N'Muffler' +GO +~~ROW COUNT: 1~~ + + +drop trigger notify +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: trigger "notify" does not exist)~~ + + +-- clean up +drop table testing1 +GO +drop table product_audits +GO +drop table products +GO diff --git a/contrib/test/JDBC/expected/babel_varbinary.out b/contrib/test/JDBC/expected/babel_varbinary.out new file mode 100644 index 00000000000..568ec8c8ee6 --- /dev/null +++ b/contrib/test/JDBC/expected/babel_varbinary.out @@ -0,0 +1,206 @@ +-- [BABEL-448] Test support of unquoted hexadecimal string input +select 0x1a2b3c4f; +go +~~START~~ +varbinary +1A2B3C4F +~~END~~ + +select 0X1A2B3C4F; +go +~~START~~ +varbinary +1A2B3C4F +~~END~~ + +select pg_typeof(0X1A2B3C4F); +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: data type regtype is not supported yet)~~ + + +-- BABEL-631 Test odd number of hex digigts is allowed +select 0xF; +go +~~START~~ +varbinary +0F +~~END~~ + +select 0x1; +go +~~START~~ +varbinary +01 +~~END~~ + +select 0x0; +go +~~START~~ +varbinary +00 +~~END~~ + +select 0x1F1; +go +~~START~~ +varbinary +01F1 +~~END~~ + + +-- invalid hex input +select 0x1G2A; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: invalid hexadecimal digit: "S")~~ + + +-- test insert of hex string +create table t1(a varbinary(8), b binary(8)); +insert into t1 values(0x1a2b3c4f, cast('1a2b3c4f' as binary(8))); +insert into t1 values(cast('1a2b3c4f' as varbinary(8)), cast('1a2b3c4f' as binary(8))); +go +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +-- 0x1a2b3c4f and '1a2b3c4f' are different as varbinary +select * from t1; +go +~~START~~ +varbinary#!#binary +1A2B3C4F#!#3161326233633466 +3161326233633466#!#3161326233633466 +~~END~~ + + +-- test bitwise operators on hex string and int +select 0x1F & 10; +go +~~START~~ +int +10 +~~END~~ + +select 10 & 0x1F; +go +~~START~~ +int +10 +~~END~~ + +select 0x1F | 10; +go +~~START~~ +int +31 +~~END~~ + +select 10 | 0x1F; +go +~~START~~ +int +31 +~~END~~ + +select 0x1F ^ 10; +go +~~START~~ +int +21 +~~END~~ + +select 10 ^ 0x1F; +go +~~START~~ +int +21 +~~END~~ + +select 0x1F * 10; +go +~~START~~ +bigint +310 +~~END~~ + +select 10 * 0x1F; +go +~~START~~ +bigint +310 +~~END~~ + +select 0x1F / 10; +go +~~START~~ +bigint +3 +~~END~~ + +select 100 / 0x1F; +go +~~START~~ +bigint +3 +~~END~~ + + +-- division by 0 +select 0x1F / 0; +go +~~ERROR (Code: 8134)~~ + +~~ERROR (Message: division by zero)~~ + +select 10 / 0x00; +go +~~ERROR (Code: 8134)~~ + +~~ERROR (Message: division by zero)~~ + + +-- test hex string in procedure +create procedure test_hex_bitop as +begin + select 0x1A2B3C4F ^ 101; +end; +go + +execute test_hex_bitop; +go +~~START~~ +int +439041066 +~~END~~ + + +create procedure test_hex_insert as +begin + insert into t1 values(0x1f, cast('1f' as binary(2))); +end; +go + +execute test_hex_insert; +go +~~ROW COUNT: 1~~ + +select * from t1; +go +~~START~~ +varbinary#!#binary +1A2B3C4F#!#3161326233633466 +3161326233633466#!#3161326233633466 +1F#!#3166000000000000 +~~END~~ + + +-- clean up +drop table t1; +drop procedure test_hex_bitop; +drop procedure test_hex_insert; +go diff --git a/contrib/test/JDBC/expected/insertbulk.out b/contrib/test/JDBC/expected/insertbulk.out new file mode 100644 index 00000000000..db2e3cc0828 --- /dev/null +++ b/contrib/test/JDBC/expected/insertbulk.out @@ -0,0 +1,721 @@ +# int +Create table sourceTable(a int, b int not null) +Create table destinationTable(a int, b int not null) +Insert into sourceTable values (1, 1); +~~ROW COUNT: 1~~ + +Insert into sourceTable values (NULL, 2); +~~ROW COUNT: 1~~ + +insertbulk#!#sourceTable#!#destinationTable +~~ROW COUNT: 2~~ + +Select * from sourceTable +~~START~~ +int#!#int +1#!#1 +#!#2 +~~END~~ + +Select * from destinationTable +~~START~~ +int#!#int +1#!#1 +#!#2 +~~END~~ + +drop table sourceTable +drop table destinationTable + +# smallint +Create table sourceTable(a smallint, b smallint not null) +Create table destinationTable(a smallint, b smallint not null) +Insert into sourceTable values (1, 1); +~~ROW COUNT: 1~~ + +Insert into sourceTable values (NULL, 2); +~~ROW COUNT: 1~~ + +insertbulk#!#sourceTable#!#destinationTable +~~ROW COUNT: 2~~ + +Select * from sourceTable +~~START~~ +smallint#!#smallint +1#!#1 +#!#2 +~~END~~ + +Select * from destinationTable +~~START~~ +smallint#!#smallint +1#!#1 +#!#2 +~~END~~ + +drop table sourceTable +drop table destinationTable + +# bigint +Create table sourceTable(a bigint, b bigint not null) +Create table destinationTable(a bigint, b bigint not null) +Insert into sourceTable values (1, 1); +~~ROW COUNT: 1~~ + +Insert into sourceTable values (NULL, 2); +~~ROW COUNT: 1~~ + +insertbulk#!#sourceTable#!#destinationTable +~~ROW COUNT: 2~~ + +Select * from sourceTable +~~START~~ +bigint#!#bigint +1#!#1 +#!#2 +~~END~~ + +Select * from destinationTable +~~START~~ +bigint#!#bigint +1#!#1 +#!#2 +~~END~~ + +drop table sourceTable +drop table destinationTable + +# bit +Create table sourceTable(a bit, b bit not null) +Create table destinationTable(a bit, b bit not null) +Insert into sourceTable values (1, 1); +~~ROW COUNT: 1~~ + +Insert into sourceTable values (NULL, 0); +~~ROW COUNT: 1~~ + +insertbulk#!#sourceTable#!#destinationTable +~~ROW COUNT: 2~~ + +Select * from sourceTable +~~START~~ +bit#!#bit +1#!#1 +#!#0 +~~END~~ + +Select * from destinationTable +~~START~~ +bit#!#bit +1#!#1 +#!#0 +~~END~~ + +drop table sourceTable +drop table destinationTable + +# float +Create table sourceTable(a float, b float not null) +Create table destinationTable(a float, b float not null) +Insert into sourceTable values (1.1101, 0.00010); +~~ROW COUNT: 1~~ + +Insert into sourceTable values (NULL, 0.101010); +~~ROW COUNT: 1~~ + +insertbulk#!#sourceTable#!#destinationTable +~~ROW COUNT: 2~~ + +Select * from sourceTable +~~START~~ +float#!#float +1.1101#!#1.0E-4 +#!#0.10101 +~~END~~ + +Select * from destinationTable +~~START~~ +float#!#float +1.1101#!#1.0E-4 +#!#0.10101 +~~END~~ + +drop table sourceTable +drop table destinationTable + +# real +Create table sourceTable(a real, b real not null) +Create table destinationTable(a real, b real not null) +Insert into sourceTable values (1.1101, 0.00010); +~~ROW COUNT: 1~~ + +Insert into sourceTable values (NULL, 0.101010); +~~ROW COUNT: 1~~ + +insertbulk#!#sourceTable#!#destinationTable +~~ROW COUNT: 2~~ + +Select * from sourceTable +~~START~~ +real#!#real +1.1101#!#1.0E-4 +#!#0.10101 +~~END~~ + +Select * from destinationTable +~~START~~ +real#!#real +1.1101#!#1.0E-4 +#!#0.10101 +~~END~~ + +drop table sourceTable +drop table destinationTable + +# char +Create table sourceTable(a char(10), b char(10) not null) +Create table destinationTable(a char(10), b char(10) not null) +Insert into sourceTable values ('hello', 'jello'); +~~ROW COUNT: 1~~ + +Insert into sourceTable values (NULL, 'mellow'); +~~ROW COUNT: 1~~ + +insertbulk#!#sourceTable#!#destinationTable +~~ROW COUNT: 2~~ + +Select * from sourceTable +~~START~~ +char#!#char +hello #!#jello +#!#mellow +~~END~~ + +Select * from destinationTable +~~START~~ +char#!#char +hello #!#jello +#!#mellow +~~END~~ + +drop table sourceTable +drop table destinationTable + +# nchar +Create table sourceTable(a nchar(10), b nchar(10) not null) +Create table destinationTable(a nchar(10), b nchar(10) not null) +Insert into sourceTable values ('hello', 'jello'); +~~ROW COUNT: 1~~ + +Insert into sourceTable values (NULL, 'mellow'); +~~ROW COUNT: 1~~ + +insertbulk#!#sourceTable#!#destinationTable +~~ROW COUNT: 2~~ + +Select * from sourceTable +~~START~~ +nchar#!#nchar +hello #!#jello +#!#mellow +~~END~~ + +Select * from destinationTable +~~START~~ +nchar#!#nchar +hello #!#jello +#!#mellow +~~END~~ + +drop table sourceTable +drop table destinationTable + +# varchar +Create table sourceTable(a varchar(10), b varchar(10) not null) +Create table destinationTable(a varchar(10), b varchar(10) not null) +Insert into sourceTable values ('hello', 'jello'); +~~ROW COUNT: 1~~ + +Insert into sourceTable values (NULL, 'mellow'); +~~ROW COUNT: 1~~ + +insertbulk#!#sourceTable#!#destinationTable +~~ROW COUNT: 2~~ + +Select * from sourceTable +~~START~~ +varchar#!#varchar +hello#!#jello +#!#mellow +~~END~~ + +Select * from destinationTable +~~START~~ +varchar#!#varchar +hello#!#jello +#!#mellow +~~END~~ + +drop table sourceTable +drop table destinationTable + +# nvarchar +Create table sourceTable(a nvarchar(10), b nvarchar(10) not null) +Create table destinationTable(a nvarchar(10), b nvarchar(10) not null) +Insert into sourceTable values ('hello', 'jello'); +~~ROW COUNT: 1~~ + +Insert into sourceTable values (NULL, 'mellow'); +~~ROW COUNT: 1~~ + +insertbulk#!#sourceTable#!#destinationTable +~~ROW COUNT: 2~~ + +Select * from sourceTable +~~START~~ +nvarchar#!#nvarchar +hello#!#jello +#!#mellow +~~END~~ + +Select * from destinationTable +~~START~~ +nvarchar#!#nvarchar +hello#!#jello +#!#mellow +~~END~~ + +drop table sourceTable +drop table destinationTable + +# text +Create table sourceTable(a text, b text not null) +Create table destinationTable(a text, b text not null) +Insert into sourceTable values ('hello', 'jello'); +~~ROW COUNT: 1~~ + +Insert into sourceTable values (NULL, 'mellow'); +~~ROW COUNT: 1~~ + +insertbulk#!#sourceTable#!#destinationTable +~~ROW COUNT: 2~~ + +Select * from sourceTable +~~START~~ +text#!#text +hello#!#jello +#!#mellow +~~END~~ + +Select * from destinationTable +~~START~~ +text#!#text +hello#!#jello +#!#mellow +~~END~~ + +drop table sourceTable +drop table destinationTable + +# ntext +Create table sourceTable(a ntext, b ntext not null) +Create table destinationTable(a ntext, b ntext not null) +Insert into sourceTable values ('hello', 'jello'); +~~ROW COUNT: 1~~ + +Insert into sourceTable values (NULL, 'mellow'); +~~ROW COUNT: 1~~ + +insertbulk#!#sourceTable#!#destinationTable +~~ROW COUNT: 2~~ + +Select * from sourceTable +~~START~~ +ntext#!#ntext +hello#!#jello +#!#mellow +~~END~~ + +Select * from destinationTable +~~START~~ +ntext#!#ntext +hello#!#jello +#!#mellow +~~END~~ + +drop table sourceTable +drop table destinationTable + +# binary +Create table sourceTable(a binary(10), b binary(10) not null) +Create table destinationTable(a binary(10), b binary(10) not null) +Insert into sourceTable values (0x31323334, 0x9241); +~~ROW COUNT: 1~~ + +Insert into sourceTable values (NULL, 0x4202); +~~ROW COUNT: 1~~ + +insertbulk#!#sourceTable#!#destinationTable +~~ROW COUNT: 2~~ + +Select * from sourceTable +~~START~~ +binary#!#binary +31323334000000000000#!#92410000000000000000 +#!#42020000000000000000 +~~END~~ + +Select * from destinationTable +~~START~~ +binary#!#binary +31323334000000000000#!#92410000000000000000 +#!#42020000000000000000 +~~END~~ + +drop table sourceTable +drop table destinationTable + +# varbinary +Create table sourceTable(a varbinary(10), b varbinary(10) not null) +Create table destinationTable(a varbinary(10), b varbinary(10) not null) +Insert into sourceTable values (0x31323334, 0x9241); +~~ROW COUNT: 1~~ + +Insert into sourceTable values (NULL, 0x4202); +~~ROW COUNT: 1~~ + +insertbulk#!#sourceTable#!#destinationTable +~~ROW COUNT: 2~~ + +Select * from sourceTable +~~START~~ +varbinary#!#varbinary +31323334#!#9241 +#!#4202 +~~END~~ + +Select * from destinationTable +~~START~~ +varbinary#!#varbinary +31323334#!#9241 +#!#4202 +~~END~~ + +drop table sourceTable +drop table destinationTable + +# numeric +Create table sourceTable(a numeric(38, 22), b numeric(38, 22) not null) +Create table destinationTable(a numeric(38, 22), b numeric(38, 22) not null) +Insert into sourceTable values (1.1101, 0.00010); +~~ROW COUNT: 1~~ + +Insert into sourceTable values (NULL, 0.101010); +~~ROW COUNT: 1~~ + +insertbulk#!#sourceTable#!#destinationTable +~~ROW COUNT: 2~~ + +Select * from sourceTable +~~START~~ +numeric#!#numeric +1.1101000000000000000000#!#0.0001000000000000000000 +#!#0.1010100000000000000000 +~~END~~ + +Select * from destinationTable +~~START~~ +numeric#!#numeric +1.1101000000000000000000#!#0.0001000000000000000000 +#!#0.1010100000000000000000 +~~END~~ + +drop table sourceTable +drop table destinationTable + +# decimal +Create table sourceTable(a decimal(38, 22), b decimal(38, 22) not null) +Create table destinationTable(a decimal(38, 22), b decimal(38, 22) not null) +Insert into sourceTable values (1.1101, 0.00010); +~~ROW COUNT: 1~~ + +Insert into sourceTable values (NULL, 0.101010); +~~ROW COUNT: 1~~ + +insertbulk#!#sourceTable#!#destinationTable +~~ROW COUNT: 2~~ + +Select * from sourceTable +~~START~~ +numeric#!#numeric +1.1101000000000000000000#!#0.0001000000000000000000 +#!#0.1010100000000000000000 +~~END~~ + +Select * from destinationTable +~~START~~ +numeric#!#numeric +1.1101000000000000000000#!#0.0001000000000000000000 +#!#0.1010100000000000000000 +~~END~~ + +drop table sourceTable +drop table destinationTable + +# money +Create table sourceTable(a money, b money not null) +Create table destinationTable(a money, b money not null) +Insert into sourceTable values (100.11, 0.10); +~~ROW COUNT: 1~~ + +Insert into sourceTable values (NULL, 91.12); +~~ROW COUNT: 1~~ + +insertbulk#!#sourceTable#!#destinationTable +~~ROW COUNT: 2~~ + +Select * from sourceTable +~~START~~ +money#!#money +100.1100#!#0.1000 +#!#91.1200 +~~END~~ + +Select * from destinationTable +~~START~~ +money#!#money +100.1100#!#0.1000 +#!#91.1200 +~~END~~ + +drop table sourceTable +drop table destinationTable + +# smallmoney +Create table sourceTable(a smallmoney, b smallmoney not null) +Create table destinationTable(a smallmoney, b smallmoney not null) +Insert into sourceTable values (100.11, 0.10); +~~ROW COUNT: 1~~ + +Insert into sourceTable values (NULL, 91.12); +~~ROW COUNT: 1~~ + +insertbulk#!#sourceTable#!#destinationTable +~~ROW COUNT: 2~~ + +Select * from sourceTable +~~START~~ +smallmoney#!#smallmoney +100.1100#!#0.1000 +#!#91.1200 +~~END~~ + +Select * from destinationTable +~~START~~ +smallmoney#!#smallmoney +100.1100#!#0.1000 +#!#91.1200 +~~END~~ + +drop table sourceTable +drop table destinationTable + +# uniqueidentifier +Create table sourceTable(a uniqueidentifier, b uniqueidentifier not null) +Create table destinationTable(a uniqueidentifier, b uniqueidentifier not null) +Insert into sourceTable values ('51f178a6-53c7-472c-9be1-1c08942342d7', 'dd8cb046-461d-411e-be40-d219252ce849'); +~~ROW COUNT: 1~~ + +Insert into sourceTable values (NULL, 'b84ebcc9-c927-4cfe-b08e-dc7f25b5087c'); +~~ROW COUNT: 1~~ + +insertbulk#!#sourceTable#!#destinationTable +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column "a" is of type uniqueidentifier but expression is of type bpchar)~~ + +Select * from sourceTable +~~START~~ +uniqueidentifier#!#uniqueidentifier +51F178A6-53C7-472C-9BE1-1C08942342D7#!#DD8CB046-461D-411E-BE40-D219252CE849 +#!#B84EBCC9-C927-4CFE-B08E-DC7F25B5087C +~~END~~ + +Select * from destinationTable +~~START~~ +uniqueidentifier#!#uniqueidentifier +~~END~~ + +drop table sourceTable +drop table destinationTable + +# date +Create table sourceTable(a date, b date not null) +Create table destinationTable(a date, b date not null) +Insert into sourceTable values ('2000-02-28', '0001-01-01'); +~~ROW COUNT: 1~~ + +Insert into sourceTable values (NULL, '1001-11-11'); +~~ROW COUNT: 1~~ + +insertbulk#!#sourceTable#!#destinationTable +~~ROW COUNT: 2~~ + +Select * from sourceTable +~~START~~ +date#!#date +2000-02-28#!#0001-01-01 +#!#1001-11-11 +~~END~~ + +Select * from destinationTable +~~START~~ +date#!#date +2000-02-28#!#0001-01-01 +#!#1001-11-11 +~~END~~ + +drop table sourceTable +drop table destinationTable + +# time +Create table sourceTable(a time(6), b time(6) not null) +Create table destinationTable(a time(6), b time(6) not null) +Insert into sourceTable values ('12:45:37.123', '12:45:37.12'); +~~ROW COUNT: 1~~ + +Insert into sourceTable values (NULL, '12:45:37.123456'); +~~ROW COUNT: 1~~ + +insertbulk#!#sourceTable#!#destinationTable +~~ROW COUNT: 2~~ + +Select * from sourceTable +~~START~~ +time#!#time +12:45:37.123000#!#12:45:37.120000 +#!#12:45:37.123456 +~~END~~ + +Select * from destinationTable +~~START~~ +time#!#time +12:45:37.123000#!#12:45:37.120000 +#!#12:45:37.123456 +~~END~~ + +drop table sourceTable +drop table destinationTable + +# datetime +Create table sourceTable(a datetime, b datetime not null) +Create table destinationTable(a datetime, b datetime not null) +Insert into sourceTable values ('2000-12-13 12:58:23.123', '1900-02-28 23:59:59.989'); +~~ROW COUNT: 1~~ + +Insert into sourceTable values (NULL, '9999-12-31 23:59:59.997'); +~~ROW COUNT: 1~~ + +insertbulk#!#sourceTable#!#destinationTable +~~ROW COUNT: 2~~ + +Select * from sourceTable +~~START~~ +datetime#!#datetime +2000-12-13 12:58:23.123#!#1900-02-28 23:59:59.99 +#!#9999-12-31 23:59:59.997 +~~END~~ + +Select * from destinationTable +~~START~~ +datetime#!#datetime +2000-12-13 12:58:23.123#!#1900-02-28 23:59:59.99 +#!#9999-12-31 23:59:59.997 +~~END~~ + +drop table sourceTable +drop table destinationTable + +# smalldatetime +Create table sourceTable(a smalldatetime, b smalldatetime not null) +Create table destinationTable(a smalldatetime, b smalldatetime not null) +Insert into sourceTable values ('2007-05-08 12:35:29', '2000-12-13 12:58:23'); +~~ROW COUNT: 1~~ + +Insert into sourceTable values (NULL, '2000-02-28 23:45:30'); +~~ROW COUNT: 1~~ + +insertbulk#!#sourceTable#!#destinationTable +~~ROW COUNT: 2~~ + +Select * from sourceTable +~~START~~ +smalldatetime#!#smalldatetime +2007-05-08 12:35:00.0#!#2000-12-13 12:58:00.0 +#!#2000-02-28 23:46:00.0 +~~END~~ + +Select * from destinationTable +~~START~~ +smalldatetime#!#smalldatetime +2007-05-08 12:35:00.0#!#2000-12-13 12:58:00.0 +#!#2000-02-28 23:46:00.0 +~~END~~ + +drop table sourceTable +drop table destinationTable + +# datetime2 +Create table sourceTable(a Datetime2(6), b Datetime2(6) not null) +Create table destinationTable(a Datetime2(6), b Datetime2(6) not null) +Insert into sourceTable values ('2016-10-23 12:45:37.123', '2016-10-23 12:45:37.123'); +~~ROW COUNT: 1~~ + +Insert into sourceTable values (NULL, '2016-10-23 12:45:37.123456'); +~~ROW COUNT: 1~~ + +insertbulk#!#sourceTable#!#destinationTable +~~ROW COUNT: 2~~ + +Select * from sourceTable +~~START~~ +datetime2#!#datetime2 +2016-10-23 12:45:37.123000#!#2016-10-23 12:45:37.123000 +#!#2016-10-23 12:45:37.123456 +~~END~~ + +Select * from destinationTable +~~START~~ +datetime2#!#datetime2 +2016-10-23 12:45:37.123000#!#2016-10-23 12:45:37.123000 +#!#2016-10-23 12:45:37.123456 +~~END~~ + +drop table sourceTable +drop table destinationTable + +# sql_variant +Create table sourceTable(a sql_variant, b sql_variant not null) +Create table destinationTable(a sql_variant, b sql_variant not null) +# Bug BABEL-2728 +#Insert into sourceTable values (cast (1 as int),cast ('abc' as varchar(10))); +Insert into sourceTable values (NULL, cast ('14:37:45.123456' as time(5))); +~~ROW COUNT: 1~~ + +insertbulk#!#sourceTable#!#destinationTable +~~ROW COUNT: 2~~ + +Select * from sourceTable +~~START~~ +sql_variant#!#sql_variant +#!#14:37:45.123460 +~~END~~ + +Select * from destinationTable +~~START~~ +sql_variant#!#sql_variant +#!#14:37:45.123328 +~~END~~ + +drop table sourceTable +drop table destinationTable diff --git a/contrib/test/JDBC/expected/pg_stat_activity.out b/contrib/test/JDBC/expected/pg_stat_activity.out new file mode 100644 index 00000000000..f5ca8ce8e2e --- /dev/null +++ b/contrib/test/JDBC/expected/pg_stat_activity.out @@ -0,0 +1,62 @@ +SELECT sys.babelfish_set_role(session_user); +~~START~~ +int +1 +~~END~~ + + +# Babel-1294 Support application_name in pg_stat_activity +select application_name from pg_stat_activity where pid = pg_backend_pid(); +~~START~~ +text +Microsoft JDBC Driver for SQL Server +~~END~~ + + +# BABEL-1326: Support query in pg_stat_activity +select query from pg_stat_activity where pid = pg_backend_pid(); +~~START~~ +text +select query from pg_stat_activity where pid = pg_backend_pid(); +~~END~~ + + +# BABEL-1326: Checking if the right query is returned for Prepexec with batch too +prepst#!#select query from pg_stat_activity where pid = pg_backend_pid();select ? as a#!#int|-|a|-|1 +~~START~~ +text +select query from pg_stat_activity where pid = pg_backend_pid();select @P0 as a +~~END~~ + +~~START~~ +int +1 +~~END~~ + +prepst#!#exec#!#int|-|a|-|1 +~~START~~ +text +select query from pg_stat_activity where pid = pg_backend_pid();select @P0 as a +~~END~~ + +~~START~~ +int +1 +~~END~~ + + +# BABEL-1326: Checking if the right query is returned from a procedure and a nested procedure as well +Create procedure proc_pg_stat_activity as begin select query from pg_stat_activity where pid = pg_backend_pid(); end; +exec proc_pg_stat_activity; +~~START~~ +text +exec proc_pg_stat_activity; +~~END~~ + +Create procedure proc1_pg_stat_activity as begin exec proc_pg_stat_activity end; +exec proc1_pg_stat_activity; +~~START~~ +text +exec proc1_pg_stat_activity; +~~END~~ + diff --git a/contrib/test/JDBC/expected/sys-column-property.out b/contrib/test/JDBC/expected/sys-column-property.out new file mode 100644 index 00000000000..837e35a1f27 --- /dev/null +++ b/contrib/test/JDBC/expected/sys-column-property.out @@ -0,0 +1,110 @@ +DROP TABLE IF EXISTS t_column_property +GO + +CREATE TABLE t_column_property( + cp1 CHAR(1) NOT NULL, + cp2 CHAR(129), + cp3 CHAR(4000) NOT NULL, + cp4 VARCHAR(1), + cp5 VARCHAR(129) NOT NULL, + cp6 VARCHAR(4000), + cp7 INT, + cp8 INT NOT NULL); +GO + + +DECLARE @table_id INT +SET @table_id = (select OBJECT_ID('t_column_property')); +SELECT * FROM sys.columnproperty(@table_id, 'cp1', 'charmaxlen'); +SELECT * FROM sys.columnproperty(@table_id, 'cp2', 'charmaxlen'); +SELECT * FROM sys.columnproperty(@table_id, 'cp3', 'charmaxlen'); +SELECT * FROM sys.columnproperty(@table_id, 'cp4', 'charmaxlen'); +SELECT * FROM sys.columnproperty(@table_id, 'cp5', 'charmaxlen'); +SELECT * FROM sys.columnproperty(@table_id, 'cp6', 'charmaxlen'); +GO +~~START~~ +int +1 +~~END~~ + +~~START~~ +int +129 +~~END~~ + +~~START~~ +int +4000 +~~END~~ + +~~START~~ +int +1 +~~END~~ + +~~START~~ +int +129 +~~END~~ + +~~START~~ +int +4000 +~~END~~ + + + +DECLARE @table_id INT +SET @table_id = (select OBJECT_ID('t_column_property')); +SELECT * FROM sys.columnproperty(@table_id, 'cp1', 'allowsnull'); +SELECT * FROM sys.columnproperty(@table_id, 'cp2', 'allowsnull'); +SELECT * FROM sys.columnproperty(@table_id, 'cp3', 'allowsnull'); +SELECT * FROM sys.columnproperty(@table_id, 'cp4', 'allowsnull'); +SELECT * FROM sys.columnproperty(@table_id, 'cp5', 'allowsnull'); +SELECT * FROM sys.columnproperty(@table_id, 'cp6', 'allowsnull'); +SELECT * FROM sys.columnproperty(@table_id, 'cp7', 'allowsnull'); +SELECT * FROM sys.columnproperty(@table_id, 'cp8', 'allowsnull'); +GO +~~START~~ +int +0 +~~END~~ + +~~START~~ +int +1 +~~END~~ + +~~START~~ +int +0 +~~END~~ + +~~START~~ +int +1 +~~END~~ + +~~START~~ +int +0 +~~END~~ + +~~START~~ +int +1 +~~END~~ + +~~START~~ +int +1 +~~END~~ + +~~START~~ +int +0 +~~END~~ + + +DROP TABLE IF EXISTS t_column_property +GO diff --git a/contrib/test/JDBC/expected/sys-datefirst.out b/contrib/test/JDBC/expected/sys-datefirst.out new file mode 100644 index 00000000000..d53067bc2a2 --- /dev/null +++ b/contrib/test/JDBC/expected/sys-datefirst.out @@ -0,0 +1,26 @@ +SELECT * FROM sys.datefirst() +GO +~~START~~ +int +7 +~~END~~ + + +SET datefirst 3 +GO + +SELECT @@datefirst +GO +~~START~~ +int +3 +~~END~~ + + +SELECT sys.datefirst() +GO +~~START~~ +int +3 +~~END~~ + diff --git a/contrib/test/JDBC/expected/sys-lock_timeout.out b/contrib/test/JDBC/expected/sys-lock_timeout.out new file mode 100644 index 00000000000..17abd5c3a8e --- /dev/null +++ b/contrib/test/JDBC/expected/sys-lock_timeout.out @@ -0,0 +1,28 @@ +SELECT * FROM sys.lock_timeout() +GO +~~START~~ +int +0 +~~END~~ + + +-- Setting of SET LOCK_TIMEOUT is set at execute or run time and not at parse time +-- Means will continue to display default value of 0 at next transaction +SET LOCK_TIMEOUT 100 +GO + +SELECT @@LOCK_TIMEOUT +GO +~~START~~ +int +0 +~~END~~ + + +SELECT sys.lock_timeout() +GO +~~START~~ +int +0 +~~END~~ + diff --git a/contrib/test/JDBC/expected/sys-max_connections.out b/contrib/test/JDBC/expected/sys-max_connections.out new file mode 100644 index 00000000000..e9aafb56894 --- /dev/null +++ b/contrib/test/JDBC/expected/sys-max_connections.out @@ -0,0 +1,30 @@ +SELECT * FROM sys.max_connections() +GO +~~START~~ +int +100 +~~END~~ + + +SET MAX_CONNECTIONS 3 --Should error out. Not possible for user to change. +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: unrecognized configuration parameter: MAX_CONNECTIONS)~~ + + +SELECT @@MAX_CONNECTIONS +GO +~~START~~ +int +100 +~~END~~ + + +SELECT sys.max_connections() +GO +~~START~~ +int +100 +~~END~~ + diff --git a/contrib/test/JDBC/expected/sys-original_login.out b/contrib/test/JDBC/expected/sys-original_login.out new file mode 100644 index 00000000000..8f729204a16 --- /dev/null +++ b/contrib/test/JDBC/expected/sys-original_login.out @@ -0,0 +1,7 @@ +SELECT ORIGINAL_LOGIN() +GO +~~START~~ +varchar +jdbc_user +~~END~~ + diff --git a/contrib/test/JDBC/expected/sys-schema-name.out b/contrib/test/JDBC/expected/sys-schema-name.out new file mode 100644 index 00000000000..61540c31b7f --- /dev/null +++ b/contrib/test/JDBC/expected/sys-schema-name.out @@ -0,0 +1,15 @@ +SELECT * FROM sys.schema_name() +GO +~~START~~ +varchar +dbo +~~END~~ + + +SELECT sys.schema_name() +GO +~~START~~ +varchar +dbo +~~END~~ + diff --git a/contrib/test/JDBC/expected/sys-syscolumns.out b/contrib/test/JDBC/expected/sys-syscolumns.out new file mode 100644 index 00000000000..b0189292f8d --- /dev/null +++ b/contrib/test/JDBC/expected/sys-syscolumns.out @@ -0,0 +1,114 @@ +-- create helper function to get datatype name given oid +CREATE FUNCTION OidToDataType(@Oid integer) +RETURNS VARCHAR(50) +AS +BEGIN + DECLARE @datatype VARCHAR(50); + SET @datatype = (SELECT typname from pg_type where oid = @Oid); + RETURN @datatype; +END; +GO + + + + +-- create helper function to get procedure/table name given oid +CREATE FUNCTION OidToObject(@Oid integer) +RETURNS VARCHAR(50) +AS +BEGIN + DECLARE @object_name VARCHAR(50); + SET @object_name = (SELECT relname from pg_class where oid = @Oid); + IF (@object_name is null) + BEGIN + SET @object_name = (SELECT proname from pg_proc where oid = @Oid); + END + RETURN @object_name +END; +GO + +-- create helper function to get collation name given oid +CREATE FUNCTION OidToCollation(@Oid integer) +RETURNS VARCHAR(50) +AS +BEGIN + DECLARE @collation VARCHAR(50); + SET @collation = (SELECT collname from pg_collation where oid = @Oid); + RETURN @collation; +END; +GO + +-- Setup some procedures and tables +create procedure syscolumns_demo_proc1 @firstparam NVARCHAR(50) as select 1 +GO + +create procedure syscolumns_demo_proc2 @firstparam NVARCHAR(50), @secondparam VARCHAR(50) OUT as select 2 +GO + +create table syscolumns_demo_table (col_a int, col_b bigint, col_c char(10), col_d numeric(5,4)) +GO + +select name, OidToObject(id), OidToDataType(xtype), typestat, length from sys.syscolumns where name = '@firstparam' or name = '@secondparam' or name = 'col_a' or name = 'col_b' or name = 'col_c' or name = 'col_d' order by OidToObject(id) asc, name +GO +~~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#!#-1 +col_d#!#syscolumns_demo_table#!#numeric#!#0#!#-1 +~~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~~ +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~~ +varchar#!#tinyint#!#varchar#!#smallint#!#int +#!#0#!#nvarchar#!##!# +#!#0#!#nvarchar#!##!# +#!#64#!#varchar#!##!# +#!#8#!#int4#!#32#!#0 +#!#8#!#int8#!#64#!#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~~ +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~~ + + +-- Cleanup +DROP FUNCTION OidToDataType +DROP FUNCTION OidToObject +DROP FUNCTION OidToCollation +DROP PROCEDURE syscolumns_demo_proc1 +DROP PROCEDURE syscolumns_demo_proc2 +DROP TABLE syscolumns_demo_table +GO diff --git a/contrib/test/JDBC/expected/sys-trigger_nestlevel.out b/contrib/test/JDBC/expected/sys-trigger_nestlevel.out new file mode 100644 index 00000000000..46f396f8986 --- /dev/null +++ b/contrib/test/JDBC/expected/sys-trigger_nestlevel.out @@ -0,0 +1,58 @@ +SELECT * FROM trigger_nestlevel() +GO +~~START~~ +int +0 +~~END~~ + + +SET trigger_nestlevel 3 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: unrecognized configuration parameter: trigger_nestlevel)~~ + + +DROP TABLE IF EXISTS t1 +GO + +CREATE TABLE t1(c1 int) +GO + +CREATE TRIGGER trigger1 ON t1 +AFTER INSERT +AS +BEGIN + IF (trigger_nestlevel()) = 1 + BEGIN + INSERT INTO t1(c1) VALUES (1); -- trigger_nestlevel should be 1 on first trigger call, so this should execute once & only once + END +END +GO + +INSERT INTO t1(c1) VALUES (0); +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +SELECT * FROM t1 +GO +~~START~~ +int +0 +1 +~~END~~ + + +DROP TABLE t1 +GO + +SELECT trigger_nestlevel() +GO +~~START~~ +int +0 +~~END~~ + diff --git a/contrib/test/JDBC/expected/tds_faultinjection.out b/contrib/test/JDBC/expected/tds_faultinjection.out new file mode 100644 index 00000000000..a8f012e79df --- /dev/null +++ b/contrib/test/JDBC/expected/tds_faultinjection.out @@ -0,0 +1,79 @@ +---- Inject an error in tds comm layer while reading the request +---- Test both SQL Batch and prepare exec +--SELECT inject_fault('tds_comm_throw_error', 2); +--SELECT 1; +--prepst#!# SELECT @a #!#BIGINT|-|a|-|0 + +---- test normal execution +--SELECT 1; + +-- Inject a pre-parsing error +-- Test both SQL Batch and prepare exec +SELECT inject_fault('pre_parsing_throw_error', 2); +~~START~~ +text +enabled, pending occurrences: 2 +~~END~~ + +SELECT 1; +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: error triggered from fault injection)~~ + +prepst#!# SELECT ? #!#BIGINT|-|a|-|0 +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: error triggered from fault injection)~~ + + +-- test normal execution +SELECT 1; +~~START~~ +int +1 +~~END~~ + + +-- Inject a post-parsing error +-- Test both SQL Batch and prepare exec +SELECT inject_fault('post_parsing_throw_error', 2); +~~START~~ +text +enabled, pending occurrences: 2 +~~END~~ + +SELECT 1; +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: error triggered from fault injection)~~ + +prepst#!# SELECT ? #!#BIGINT|-|a|-|0 +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: error triggered from fault injection)~~ + + +-- test normal execution +SELECT 1; +~~START~~ +int +1 +~~END~~ + + +-- Inject fault to tamper TDS request +-- Test both SQL Batch and prepare exec (but prepare exec is failing now) +SELECT inject_fault('pre_parsing_tamper_request', 1); +~~START~~ +text +enabled, pending occurrences: 1 +~~END~~ + +SELECT 1; +~~START~~ +int +1 +~~END~~ + +--prepst#!# SELECT @a #!#BIGINT|-|a|-|0 + diff --git a/contrib/test/JDBC/init.sh b/contrib/test/JDBC/init.sh new file mode 100755 index 00000000000..0eb5a19864e --- /dev/null +++ b/contrib/test/JDBC/init.sh @@ -0,0 +1,21 @@ + +#create test user and database from psql terminal +echo "============================== CREATING USER AND DATABASE ==============================" +psql -U "$USER" -d postgres -a << EOF +CREATE USER jdbc_user WITH SUPERUSER CREATEDB CREATEROLE PASSWORD '12345678' INHERIT; +DROP DATABASE IF EXISTS jdbc_testdb; +CREATE DATABASE jdbc_testdb OWNER jdbc_user; +\c jdbc_testdb +CREATE EXTENSION IF NOT EXISTS "babelfishpg_tds" CASCADE; +GRANT ALL ON SCHEMA sys to jdbc_user; +ALTER USER jdbc_user CREATEDB; +\c jdbc_testdb +ALTER SYSTEM SET babelfishpg_tsql.database_name = 'jdbc_testdb'; +ALTER SYSTEM SET babelfishpg_tds.set_db_session_property = true; +SELECT pg_reload_conf(); +\c jdbc_testdb +show babelfishpg_tsql.database_name; +show babelfishpg_tds.set_db_session_property; +CALL sys.initialize_babelfish('jdbc_user'); +EOF +echo "============================= BUILDING JDBC TEST FRAMEWORK =============================" diff --git a/contrib/test/JDBC/input/BABEL-1000.sql b/contrib/test/JDBC/input/BABEL-1000.sql new file mode 100644 index 00000000000..82ab131b068 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1000.sql @@ -0,0 +1,177 @@ +-- note: the default typmod for varchar should be 1 +CREATE FUNCTION babel_1000_test1 (@arg1 varchar) +RETURNS TABLE AS RETURN +(SELECT @arg1 as a) +GO +SELECT * FROM babel_1000_test1('babel_1000_varchar') +GO + +CREATE FUNCTION babel_1000_test2 (@arg1 varchar(10), @arg2 varchar(20)) +RETURNS TABLE AS RETURN +(SELECT @arg1 as a, @arg2 as b) +GO + +SELECT * FROM babel_1000_test2('babel_1000_varchar', 'babel_1000_varchar2') +GO +SELECT * FROM babel_1000_test2('babel_1000', 'abcdefghijklmnopqrstuvwxyz') +GO + +CREATE FUNCTION babel_1000_test3 (@arg1 nvarchar(10), @arg2 nvarchar(20)) +RETURNS TABLE AS RETURN +(SELECT @arg1 as a, @arg2 as b) +GO + +SELECT * FROM babel_1000_test3('babel_1000_varchar', 'babel_1000_varchar3') +GO +SELECT * FROM babel_1000_test3('12345678910', 'babel_1000_varchar3') +GO + +-- numeric default typmod is (18,0) +CREATE FUNCTION babel_1000_test4 (@arg1 nvarchar(10), @arg2 numeric) +RETURNS TABLE AS RETURN +(SELECT @arg1 as a, @arg2 as b) +GO + +SELECT * FROM babel_1000_test4('babel_1000_test4', 123.456) +GO +SELECT * FROM babel_1000_test4('babel_1000_test4', 123.567) +GO +SELECT * FROM babel_1000_test4('test4', 123456789012345678) +GO +-- precision 19, expect error +SELECT * FROM babel_1000_test4('test4-2', 1234567890123456789) +GO + +CREATE FUNCTION babel_1000_test5 (@arg1 nvarchar(30), @arg2 numeric(6,3)) +RETURNS TABLE AS RETURN +(SELECT @arg1 as a, @arg2 as b) +GO + +SELECT * FROM babel_1000_test5('babel_1000_test5', 123.4567) +GO +SELECT * FROM babel_1000_test5('babel_1000_test5', 567.89) +GO +-- expect overflow error +SELECT * FROM babel_1000_test5('babel_1000_test5', 5567.89) +GO + +CREATE FUNCTION babel_1000_test6 (@arg1 datetimeoffset(2), @arg2 datetime2(4)) +RETURNS TABLE AS RETURN +(SELECT @arg1 as a, @arg2 as b) +GO + +SELECT * FROM babel_1000_test6(CAST('2030-05-06 13:59:29.123456 -8:00' AS datetimeoffset), + CAST('1234-12-31 23:59:59.999999' AS datetime2)) +GO +SELECT * FROM babel_1000_test6(CAST('2030-05-06 13:59:29.124456 +8:00' AS datetimeoffset(4)), + CAST('9999-12-31 23:59:59.999999' AS datetime2(5))) +GO + +CREATE PROCEDURE babel_1000_test7 (@val datetimeoffset(2)) AS +BEGIN + DECLARE @DF datetimeoffset = @val + SELECT @DF +END +GO + +EXEC babel_1000_test7 '2030-05-06 13:59:29.123456 -8:00' +GO + +-- test return types +CREATE FUNCTION babel_1000_test8(@arg1 numeric) +RETURNS numeric(6,2) AS +BEGIN + RETURN @arg1 + 1.055 +END +GO + +SELECT * FROM babel_1000_test8(1) +GO +SELECT * FROM babel_1000_test8(12.345678) +GO +-- overflow, expect error +SELECT * FROM babel_1000_test8(123456.345678) +GO + +CREATE FUNCTION babel_1000_test9(@arg1 varchar) +RETURNS varchar(5) AS +BEGIN + RETURN @arg1 +END +GO + +SELECT * FROM babel_1000_test9('babel_1000_test9') +GO +SELECT * FROM babel_1000_test9('abcdefghijkl') +GO + +CREATE PROCEDURE babel_1000_test10 (@val varchar(2)) AS +BEGIN + DECLARE @DF varchar = @val + SELECT @DF +END +GO + +EXEC babel_1000_test10 '2030-05-06 13:59:29.123456 -8:00' +GO + +CREATE PROCEDURE babel_1000_test10_2 (@val varchar(2)) AS +BEGIN + DECLARE @DF varchar(100) = @val + SELECT @DF +END +GO + +EXEC babel_1000_test10_2 '2030-05-06 13:59:29.123456 -8:00' +GO + + +CREATE FUNCTION babel_1000_test11 (@var varchar(10)) +RETURNS varchar(4) +AS +BEGIN + return @var +END +GO + +SELECT babel_1000_test11('abcdefghijkl') +GO + +CREATE FUNCTION babel_1000_test12 (@var varbinary(10)) +RETURNS varbinary(2) +AS +BEGIN + return @var +END +GO + +SELECT babel_1000_test12(0x0123456789) +GO + + +DROP FUNCTION babel_1000_test1 +GO +DROP FUNCTION babel_1000_test2 +GO +DROP FUNCTION babel_1000_test3 +GO +DROP FUNCTION babel_1000_test4 +GO +DROP FUNCTION babel_1000_test5 +GO +DROP FUNCTION babel_1000_test6 +GO +DROP PROCEDURE babel_1000_test7 +GO +DROP FUNCTION babel_1000_test8 +GO +DROP FUNCTION babel_1000_test9 +GO +DROP PROCEDURE babel_1000_test10 +GO +DROP PROCEDURE babel_1000_test10_2 +GO +DROP FUNCTION babel_1000_test11 +GO +DROP FUNCTION babel_1000_test12 +GO diff --git a/contrib/test/JDBC/input/BABEL-101.sql b/contrib/test/JDBC/input/BABEL-101.sql new file mode 100644 index 00000000000..aca85ab6e43 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-101.sql @@ -0,0 +1,82 @@ +CREATE PROCEDURE p1 +AS +BEGIN TRY; +PRINT 'Hello 1' +END TRY +BEGIN CATCH; +PRINT 'Hello 2' +END CATCH; +GO + +CREATE PROCEDURE p2 +AS +BEGIN TRY; +PRINT 'Hello 1' +END TRY +BEGIN CATCH +PRINT 'Hello 2' +END CATCH +GO + +CREATE PROCEDURE p3 +AS +BEGIN TRY +PRINT 'Hello 1' +END TRY; +BEGIN CATCH +PRINT 'Hello 2' +END CATCH +GO + +CREATE PROCEDURE p4 +AS +BEGIN TRY +PRINT 'Hello 1' +END TRY +BEGIN CATCH; +PRINT 'Hello 2' +END CATCH +GO + +CREATE PROCEDURE p5 +AS +BEGIN TRY +PRINT 'Hello 1' +END TRY +BEGIN CATCH +PRINT 'Hello 2' +END CATCH; +GO + +CREATE PROCEDURE p6 +AS +BEGIN TRY +PRINT 'Hello 1' +END TRY +BEGIN CATCH; +PRINT 'Hello 2' +END CATCH; +GO + +CREATE PROCEDURE p7 +AS +BEGIN TRY; +PRINT 'Hello 1' +END TRY +BEGIN CATCH; +PRINT 'Hello 2' +END CATCH +GO + +DROP PROCEDURE p1 +GO +DROP PROCEDURE p2 +GO +DROP PROCEDURE p4 +GO +DROP PROCEDURE p5 +GO +DROP PROCEDURE p6 +GO +DROP PROCEDURE p7 +GO diff --git a/contrib/test/JDBC/input/BABEL-1044.sql b/contrib/test/JDBC/input/BABEL-1044.sql new file mode 100644 index 00000000000..374a06c1512 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1044.sql @@ -0,0 +1,199 @@ +-- schema +create schema schema_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij; + +-- table +create table schema_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij.table_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij( + col_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij integer +); +GO + +insert into schema_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij.table_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij values (42); +GO + +-- accessed via original name +select * from schema_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij.table_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij; +GO + +-- accessed via truncated name +select * from schema_longer_than_63_0abcdefgi2f5cbde477221faa47c8d08e1d6bbb27.table_longer_than_63_0abcdefgijc2ed7b983a352405e4e26c711bd071bf; +GO + +-- monitoring with original name +select count(*) from pg_catalog.pg_class where relname = 'table_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij'; +GO + +-- monitoring with truncated name +select count(*) from pg_catalog.pg_class where relname = 'table_longer_than_63_0abcdefgijc2ed7b983a352405e4e26c711bd071bf'; +GO + +-- object_id() for both original namd shortend name +select (case when object_id('table_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij') is not null then 'exists' else 'error' end) result; +GO + +select (case when object_id('table_longer_than_63_0abcdefgijc2ed7b983a352405e4e26c711bd071bf') is not null then 'exists' else 'error' end) result; +GO + +select (case when object_id('table_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij') = object_id('table_longer_than_63_0abcdefgijc2ed7b983a352405e4e26c711bd071bf') then 'correct' else 'error' end) result; +GO + +-- object_id(.) for both original namd shortend name +select (case when object_id('schema_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij.table_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij') is not null then 'exists' else 'error' end) result; +GO + +select (case when object_id('schema_longer_than_63_0abcdefgi2f5cbde477221faa47c8d08e1d6bbb27.table_longer_than_63_0abcdefgijc2ed7b983a352405e4e26c711bd071bf') is not null then 'exists' else 'error' end) result; +GO + +select (case when object_id('schema_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij.table_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij') = object_id('schema_longer_than_63_0abcdefgi2f5cbde477221faa47c8d08e1d6bbb27.table_longer_than_63_0abcdefgijc2ed7b983a352405e4e26c711bd071bf') then 'correct' else 'error' end) result; +GO + +drop table schema_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij.table_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij; + +drop schema schema_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij; +GO + +create table table_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij( + col_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij integer +); +GO + +insert into table_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij values (42); +GO + +-- char/varchar/text -> name casting +create table table_name_t(c1 char(128) COLLATE C, c2 varchar(128) COLLATE C, c3 text COLLATE C); +GO +insert into table_name_t values ( + 'table_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij', + 'table_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij', + 'table_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij' +); +GO +-- note: use explicit cast here. since implicit cast is not added. there is the same issue in default PG truncation behavior +select count(*) from pg_catalog.pg_class where relname in (SELECT cast (c1 as name) from table_name_t); +GO +select count(*) from pg_catalog.pg_class where relname in (SELECT cast (c2 as name) from table_name_t); +GO +select count(*) from pg_catalog.pg_class where relname in (SELECT cast (c3 as name) from table_name_t); +GO +drop table table_name_t; +GO + +-- function +create function func_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij( + @argname_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij int) +RETURNS integer +AS +BEGIN + return (select @argname_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij + 1); +END; +GO + +-- view +create view view_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij as +select func_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij( + col_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij) +from table_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij; +GO + +select * from view_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij; +GO + +-- create table with the same name +create table table_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij( + col_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij integer +); +GO + +-- create table with a different name but have same prefix +create table table_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghik( + col_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij integer +); +GO + +-- disable multi-bytes test for now since it should depend on collation setting +-- table name with multi-byte characters +--create table tλλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ(a int); +--GO +--insert into tλλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ values (42); +--GO +--select * from tλλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ; +--GO + +--create table ttλλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ(a int); +--GO +--insert into ttλλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ values (42); +--GO +--select * from ttλλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ; +--GO + +--create table tttλλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ(a int); +--GO +--insert into tttλλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ values (42); +--GO +--select * from tttλλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ; +--GO + +--create table ttttλλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ(a int); +--GO +--insert into ttttλλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ values (42); +--GO +--select * from ttttλλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ; +--GO + +drop view view_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij; +GO + +drop function func_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij; +GO + +drop table table_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij; +GO + +drop table table_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghik; +GO + +--drop table tλλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ; +--GO +--drop table ttλλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ; +--GO +--drop table tttλλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ; +--GO +--drop table ttttλλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ_λλλλλ; +--GO + +create table babel_1200_t(id int, [BALA_#] varchar(40)); +GO +insert into babel_1200_t values (42, 'aaa'), (666, 'bbb'); +GO + +create procedure babel_1200_proc +@balano as varchar(40) +as +begin + select r.ID from babel_1200_t r where r.BALA_#=@balano +end +go + +-- currently, syntax error +--exec babel_1200_proc 'aaa' +--GO + +create procedure babel_1200_proc_quoted +@balano as varchar(40) +as +begin + select r.ID from babel_1200_t r where r.[BALA_#]=@balano +end +go + +exec babel_1200_proc_quoted 'aaa' +GO + +drop procedure babel_1200_proc_quoted; +GO + +drop procedure babel_1200_proc; +GO + +drop table babel_1200_t; +GO diff --git a/contrib/test/JDBC/input/BABEL-1056.sql b/contrib/test/JDBC/input/BABEL-1056.sql new file mode 100644 index 00000000000..3f64e102ca3 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1056.sql @@ -0,0 +1,48 @@ +CREATE SCHEMA [Babelfish_1056]; +GO + +CREATE TABLE [Babelfish_1056].[employees] +(person_id int IDENTITY PRIMARY KEY, firstname nvarchar(20), lastname nvarchar(30), salary money) +GO + +CREATE PROCEDURE p_employee_insert @fname nvarchar(20), @lname nvarchar(30), @sal money +AS BEGIN +DECLARE @next_pers_id INT; +SELECT @next_pers_id = MAX(person_id) FROM [Babelfish_1056].[employees]; +IF (@next_pers_id IS NULL) + SET @next_pers_id = 0 + INSERT INTO [Babelfish_1056].[employees] + (person_id, firstname, lastname, salary) + VALUES + (@next_pers_id+1, @fname, @lname, @sal); +END +GO + +SET IDENTITY_INSERT [Babelfish_1056].[employees] ON +GO +EXEC p_employee_insert @fname='First', @lname='Employee', @sal=123.1231; +GO +SET IDENTITY_INSERT [Babelfish_1056].[employees] OFF +GO + +SET IDENTITY_INSERT [Babelfish_1056].[employees] ON +GO +EXEC p_employee_insert @fname='Second', @lname='Employee', @sal=123.1232; +GO +SET IDENTITY_INSERT [Babelfish_1056].[employees] OFF +GO + +SET IDENTITY_INSERT [Babelfish_1056].[employees] ON +GO +EXEC p_employee_insert @fname='Third', @lname='Employee', @sal=123.1233; +GO +SET IDENTITY_INSERT [Babelfish_1056].[employees] OFF +GO + +SELECT * FROM [Babelfish_1056].[employees] +GO + +DROP PROCEDURE p_employee_insert +DROP TABLE [Babelfish_1056].[employees] +DROP SCHEMA [Babelfish_1056]; +GO diff --git a/contrib/test/JDBC/input/BABEL-1066.sql b/contrib/test/JDBC/input/BABEL-1066.sql new file mode 100644 index 00000000000..3926df845d3 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1066.sql @@ -0,0 +1,17 @@ +select datename(month, cast('2002-05-23 23:41:29.998' as smalldatetime)); +go + +select datename(dw, null); +go + +select dateadd(year, 2, cast('20060830' AS datetime)); +go + +select dateadd(yy, 1, null); +go + +select datepart(weekday, cast( '2021-12-31' as date)); +go + +select datepart(dw, null); +go diff --git a/contrib/test/JDBC/input/BABEL-1073.sql b/contrib/test/JDBC/input/BABEL-1073.sql new file mode 100644 index 00000000000..999c916d042 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1073.sql @@ -0,0 +1,27 @@ +SELECT set_config('babelfishpg_tsql.escape_hatch_for_replication', 'ignore', 'false') +GO + +-- Test 'NOT FOR REPLICATION' syntax +create table testing1(col nvarchar(60)); +GO +create trigger notify on testing1 after insert +NOT FOR REPLICATION +as +begin + PRINT 'trigger invoked' +end +; +GO + +insert into testing1 (col) select N'Muffler'; +GO + +drop trigger notify; +GO + +-- clean up +drop table testing1; +GO + +SELECT set_config('babelfishpg_tsql.escape_hatch_for_replication', 'strict', 'false') +GO diff --git a/contrib/test/JDBC/input/BABEL-1091.sql b/contrib/test/JDBC/input/BABEL-1091.sql new file mode 100644 index 00000000000..59d680f8ca7 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1091.sql @@ -0,0 +1,173 @@ +CREATE TABLE t (k INT, c INT) +CREATE TABLE t2 (k INT, c1 INT, c2 INT) +GO + +-- test case 1: @v = column +DECLARE @a INT +SET @a = 0 +DECLARE @b INT +SET @b = 0 +INSERT INTO t VALUES (1, 10) +INSERT INTO t VALUES (2, 20) +UPDATE t SET @a = c, k = 3 WHERE k = 1 +UPDATE t SET k = 4, @b = c WHERE k = 2 +SELECT * FROM t ORDER BY k +SELECT @a, @b + +DELETE FROM t +GO + +-- test case 2: @v = expression +DECLARE @a INT +SET @a = 0 +DECLARE @b INT +SET @b = 0 +DECLARE @d INT +SET @d = 100 +INSERT INTO t VALUES (1, 10) +INSERT INTO t VALUES (2, 20) +UPDATE t SET @a = c + 100, k = 3 WHERE k = 1 +UPDATE t SET @b = @d + 100, k = 4 WHERE k = 2 +SELECT * FROM t ORDER BY k +SELECT @a, @b + +DELETE FROM t +GO + +-- test case 3: @v = column = value +DECLARE @a INT +SET @a = 0 +INSERT INTO t VALUES (1, 10) +INSERT INTO t VALUES (2, 20) +UPDATE t SET @a = c = 40 WHERE k = 1 +SELECT * FROM t ORDER BY k +SELECT @a + +DELETE FROM t +GO + +-- test case 4: @v = CASE clause / parens +DECLARE @a INT +DECLARE @b INT +SET @a = 0 +SET @b = 0 +INSERT INTO t2 VALUES (1, 10, 30) +INSERT INTO t2 VALUES (2, 20, 40) +UPDATE t2 SET @a = CASE WHEN c1 = 10 THEN 30 ELSE 40 END, c2 = 50 WHERE k = 1 +UPDATE t2 SET @b = (SELECT c1 FROM t2 WHERE k = 2), c2 = 60 WHERE k = 2 +SELECT * FROM t2 ORDER BY k +SELECT @a, @b + +DELETE FROM t2 +GO + +-- test case 5: @v = column with no WHERE clause +-- @v will be mapped to the last row of available value +DECLARE @a INT +SET @a = 0 +INSERT INTO t VALUES (1, 10) +INSERT INTO t VALUES (2, 20) +UPDATE t SET @a = c, k = 3 +SELECT * FROM t ORDER BY k +SELECT @a + +DELETE FROM t +GO + +-- test case 6: @v1 = column, @v2 = column +DECLARE @a INT +SET @a = 0 +DECLARE @b INT +SET @b = 0 +INSERT INTO t VALUES (1, 10) +INSERT INTO t VALUES (2, 20) +UPDATE t SET @a = c, @b = c, k = 3 WHERE k = 1 +SELECT * FROM t ORDER BY k +SELECT @a, @b + +DELETE FROM t +GO + +-- test case 7: @v1 = column which is updated at the same time +-- INCORRECT RESULT: since OUTPUT clause is unsupported, we will make use of RETURNING clause +-- which will return the updated value. What we really interested is the pre-update values +-- We will need to update this case after BABEL-588 is fixed. +DECLARE @a INT +SET @a = 0 +DECLARE @b INT +SET @b = 0 +INSERT INTO t VALUES (1, 10) +INSERT INTO t VALUES (2, 20) +UPDATE t SET @a = c, c = 70 WHERE k = 1 +UPDATE t SET c = 80, @b = c WHERE k = 2 +SELECT * FROM t ORDER BY k +SELECT @a, @b + +DELETE FROM t +GO + +-- test case 8: @v1 = column with no table updates +-- UNSUPPORTED +DECLARE @a INT +SET @a = 0 +INSERT INTO t VALUES (1, 10) +INSERT INTO t VALUES (2, 20) +UPDATE t SET @a = c WHERE k = 1 +SELECT * FROM t ORDER BY k +SELECT @a + +DELETE FROM t +GO + +-- test case 9: @v1 = column and column = @v2 at the same time +DECLARE @a INT +SET @a = 0 +DECLARE @b INT +SET @b = 3 +INSERT INTO t VALUES (1, 10) +INSERT INTO t VALUES (2, 20) +UPDATE t SET @a = c, k = @b WHERE k = 1 +SELECT * FROM t ORDER BY k +SELECT @a, @b + +DELETE FROM t +GO + +-- test case 10: @v1 = column with OUTPUT clause +-- this test is disabled as OUTPUT clause is not yet supported: BABEL-588 +-- UNSUPPORTED +-- DECLARE @a INT +-- SET @a = 0 +-- INSERT INTO t VALUES (1, 10) +-- INSERT INTO t VALUES (2, 20) +-- UPDATE t SET @a = c, k = 3 OUTPUT deleted.* WHERE k = 1 +-- SELECT * FROM t ORDER BY k +-- SELECT @a +-- DELETE FROM t +-- GO + +-- SELECT SET with CASE statement with correct parser behavior on second '=' +DECLARE @a INT +SET @a = 0 +INSERT INTO t VALUES (1, 10) +SELECT @a = CASE WHEN c = 10 THEN 1 ELSE 2 END FROM t +SELECT @a + +DELETE FROM t +GO + + +-- SELECT SET with parameters with correct parser behavior on second '=' +DECLARE @a INT +SET @a = 0 +INSERT INTO t VALUES (1, 10) +SELECT @a = ( SELECT c FROM t WHERE k = 1 ) +SELECT @a + +DELETE FROM t +GO + +-- clean up +DROP TABLE t +DROP TABLE t2 +GO \ No newline at end of file diff --git a/contrib/test/JDBC/input/BABEL-1094.sql b/contrib/test/JDBC/input/BABEL-1094.sql new file mode 100644 index 00000000000..b163fd2a0aa --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1094.sql @@ -0,0 +1,28 @@ +CREATE PROCEDURE babel_1094_proc(@p0 VARCHAR(32)) +AS +BEGIN + UPDATE T set id = @id + 1 + BEGIN TRANSACTION + UPDATE T SET col1 = s.col2 FROM @tab_var s WHERE T.col3 = s.col4 + COMMIT + SELECT * FROM T WHERE col1 = @id +END +GO + +CREATE PROCEDURE babel_1094_proc_2(@p0 VARCHAR(32)) +AS +BEGIN + UPDATE T set id = @id + 1 + BEGIN TRANSACTION + UPDATE T SET col1 = s.col2 FROM @tab_var s WHERE T.col3 = s.col4 + ROLLBACK + SELECT * FROM T WHERE col1 = @id +END +GO + +DROP PROCEDURE babel_1094_proc +GO + +DROP PROCEDURE babel_1094_proc_2 +GO + diff --git a/contrib/test/JDBC/input/BABEL-1096.sql b/contrib/test/JDBC/input/BABEL-1096.sql new file mode 100644 index 00000000000..dd4c47c977f --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1096.sql @@ -0,0 +1,60 @@ +CREATE TABLE babel_1096_t1 (a int) +GO + +INSERT INTO babel_1096_t1 values (1); +GO + +CREATE TABLE babel_1096_t2 (a int); +GO + +CREATE PROCEDURE babel_1096_proc +AS + INSERT INTO babel_1096_t2 + SELECT * FROM babel_1096_t1 + + SELECT COUNT(*) FROM babel_1096_t2 +GO + +EXEC babel_1096_proc +GO + +CREATE TABLE babel_956_t (a int, n int identity) +GO + +CREATE PROCEDURE babel_956_proc +AS + INSERT babel_956_t(a) SELECT 123 + SELECT @@identity +GO + +CREATE FUNCTION babel_1095_proc ( @stringToSplit VARCHAR(MAX) ) +RETURNS + @returnList TABLE ([Name] [nvarchar] (500)) +AS +BEGIN + INSERT INTO @returnList + SELECT '' + + SELECT @stringToSplit = '' + RETURN; +END +GO + +DROP PROCEDURE babel_1096_proc +GO + +DROP TABLE babel_1096_t1 +GO + +DROP TABLE babel_1096_t2 +GO + +DROP PROCEDURE babel_956_proc +GO + +DROP TABLE babel_956_t +GO + +DROP FUNCTION babel_1095_proc +GO + diff --git a/contrib/test/JDBC/input/BABEL-1098.sql b/contrib/test/JDBC/input/BABEL-1098.sql new file mode 100644 index 00000000000..200d2b4d334 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1098.sql @@ -0,0 +1,403 @@ +USE master; +GO + +-- Testing delete statement +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'), + (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 + +CREATE TABLE delete_test_tbl2 ( + year int, + lname char(10), +) +GO + +INSERT INTO delete_test_tbl2(year, lname) +VALUES (51, 'lname1'), + (34, 'lname3'), + (25, 'lname8'), + (95, 'lname9'), + (36, 'lname10') +GO + +CREATE TABLE delete_test_tbl3 ( + lname char(10), + city char(10), +) +GO + +INSERT INTO delete_test_tbl3(lname, city) +VALUES ('lname8','london'), + ('lname9','tokyo'), + ('lname10','mumbai') +GO + +CREATE TABLE delete_test_tbl4 ( + age int, + fname char(10), + lname char(10), + city nchar(20) +) +GO + +INSERT INTO delete_test_tbl4(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'), + (35, 'fname6', 'lname6', 'mumbai') +GO + +CREATE TABLE dbo.delete_test_tbl5 ( + age int, + fname char(10), + lname char(10), + city nchar(20) +) +GO + +INSERT INTO dbo.delete_test_tbl5(age, fname, lname, city) +VALUES (51, 'fname1', 'lname1', 'london'), + (34, 'fname2', 'lname2', 'paris'), + (102, 'fname3', 'lname10', 'brussels') +GO + +-- test using schema name +DELETE dbo.delete_test_tbl5 +FROM dbo.delete_test_tbl5 t5 +INNER JOIN delete_test_tbl3 t3 +ON t3.lname = t5.lname +GO + +SELECT * FROM dbo.delete_test_tbl5 ORDER BY lname +GO + +DELETE delete_test_tbl +FROM delete_test_tbl t1 +INNER JOIN delete_test_tbl2 t2 +ON t1.lname = t2.lname +WHERE year > 50 +GO + +SELECT * FROM delete_test_tbl ORDER BY lname +GO + +DELETE delete_test_tbl +FROM delete_test_tbl2 t2 +LEFT JOIN delete_test_tbl t1 +ON t1.lname = t2.lname +WHERE t2.year < 30 AND t1.age > 40 +GO + +SELECT * FROM delete_test_tbl ORDER BY lname +GO + +-- delete with outer join on multiple tables +DELETE delete_test_tbl +FROM delete_test_tbl3 t3 +LEFT JOIN delete_test_tbl t1 +ON t3.city = t1.city +LEFT JOIN delete_test_tbl2 t2 +ON t1.lname = t2.lname +WHERE t3.city = 'mumbai' +GO + +SELECT * FROM delete_test_tbl ORDER BY lname +GO + +-- delete when target table not shown in JoinExpr +DELETE delete_test_tbl +FROM delete_test_tbl3 t3 +LEFT JOIN delete_test_tbl2 t2 +ON t3.lname = t2.lname +GO + +SELECT * FROM delete_test_tbl ORDER BY lname +GO + +-- delete with self join +DELETE delete_test_tbl3 +FROM delete_test_tbl3 t1 +INNER JOIN delete_test_tbl3 t2 +on t1.lname = t2.lname +GO + +SELECT * FROM delete_test_tbl3 ORDER BY lname +GO + +DELETE delete_test_tbl4 +FROM delete_test_tbl4 c +JOIN +(SELECT lname, fname, age from delete_test_tbl4) b +on b.lname = c.lname +JOIN +(SELECT lname, city, age from delete_test_tbl4) a +on a.city = c.city +GO + +SELECT * FROM delete_test_tbl4 ORDER BY lname +GO + +DELETE delete_test_tbl2 +FROM +(SELECT lname, year from delete_test_tbl2) b +JOIN +(SELECT lname from delete_test_tbl2) a +on a.lname = b.lname +GO + +SELECT * FROM delete_test_tbl2 ORDER BY lname +GO + +DROP TABLE delete_test_tbl +GO + +DROP TABLE delete_test_tbl2 +GO + +DROP TABLE delete_test_tbl3 +GO + +DROP TABLE delete_test_tbl4 +GO + +DROP TABLE dbo.delete_test_tbl5 +GO + + +-- Tests for UPDATE clause +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') +GO + +CREATE TABLE update_test_tbl2 ( + year int, + lname char(10), +) +GO + +INSERT INTO update_test_tbl2(year, lname) +VALUES (51, 'lname1'), + (34, 'lname3'), + (25, 'lname8'), + (95, 'lname9'), + (36, 'lname10') +GO + +CREATE TABLE update_test_tbl3 ( + age int, + fname char(10), + lname char(10), + city nchar(20) +) +GO +INSERT INTO update_test_tbl3(lname, city) +VALUES ('lname8','london'), + ('lname9','tokyo'), + ('lname10','mumbai') +GO + +CREATE TABLE dbo.update_test_tbl4 ( + age int, + fname char(10), + lname char(10), + city nchar(20) +) +GO + +INSERT INTO dbo.update_test_tbl4(age, fname, lname, city) +VALUES (50, 'fname1', 'lname1', 'london'), + (34, 'fname2', 'lname2', 'paris'), + (35, 'fname3', 'lname3', 'brussels'), + (90, 'fname4', 'lname10', 'new york') +GO + +SELECT * FROM update_test_tbl ORDER BY lname +GO +SELECT * FROM update_test_tbl2 ORDER BY lname +GO +SELECT * FROM update_test_tbl3 ORDER BY lname +GO +SELECT * FROM dbo.update_test_tbl4 ORDER BY lname +GO +-- Simple update +UPDATE update_test_tbl SET fname = 'fname11' +GO + +SELECT * FROM update_test_tbl ORDER BY lname +GO + +-- Update with where clause +UPDATE update_test_tbl SET fname = 'fname12' +WHERE age > 50 AND city IN ('london','mumbai', 'new york' ) +GO + +SELECT * FROM update_test_tbl ORDER BY lname +GO + +-- Update with inner join +UPDATE 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 + +SELECT * FROM update_test_tbl ORDER BY lname +GO + +UPDATE update_test_tbl SET fname = 'fname14' +FROM update_test_tbl2 t2 +INNER JOIN update_test_tbl t1 +ON t1.lname = t2.lname +WHERE year < 50 AND city in ('tokyo', 'hong kong') +GO + +SELECT * FROM update_test_tbl ORDER BY lname +GO + +-- Update with outer join +UPDATE 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 + +SELECT * FROM update_test_tbl ORDER BY lname +GO + +UPDATE 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 > 60 +GO + +SELECT * FROM update_test_tbl ORDER BY lname +GO + +-- update with outer join on multiple tables +UPDATE 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 = 'mumbai' +GO + +SELECT * FROM update_test_tbl ORDER BY lname +GO + +-- update when target table not shown in JoinExpr but associated by where +UPDATE update_test_tbl +SET fname = 'fname18' +from update_test_tbl2 t2 +FULL JOIN update_test_tbl3 t3 +ON t2.lname = t3.lname +WHERE update_test_tbl.city = t3.city AND t3.lname='lname10' +GO + +SELECT * FROM update_test_tbl ORDER BY lname +GO + +-- update when target table not shown in JoinExpr +UPDATE update_test_tbl +SET fname = 'fname19' +from update_test_tbl2 t2 +FULL JOIN update_test_tbl3 t3 +ON t2.lname = t3.lname +GO + +SELECT * FROM update_test_tbl ORDER BY lname +GO + +-- update with self join +UPDATE update_test_tbl3 +SET lname = 'lname12' +FROM update_test_tbl3 t1 +INNER JOIN update_test_tbl3 t2 +on t1.lname = t2.lname +GO + +SELECT * FROM update_test_tbl3 ORDER BY lname +GO + +UPDATE 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 + +SELECT * FROM update_test_tbl ORDER BY lname +GO + +-- update when target table only appears in subselect +UPDATE 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; + +SELECT * FROM update_test_tbl ORDER BY lname +GO + +-- update with schema +UPDATE dbo.update_test_tbl4 SET fname = 'fname11' +FROM dbo.update_test_tbl4 t4 +INNER JOIN update_test_tbl3 t3 +ON t3.city = t4.city +GO + +SELECT * FROM dbo.update_test_tbl4 ORDER BY lname +GO + +DROP TABLE update_test_tbl +GO +DROP TABLE update_test_tbl2 +GO +DROP TABLE update_test_tbl3 +GO +DROP TABLE dbo.update_test_tbl4 +GO diff --git a/contrib/test/JDBC/input/BABEL-1113.sql b/contrib/test/JDBC/input/BABEL-1113.sql new file mode 100644 index 00000000000..66a91effcfa --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1113.sql @@ -0,0 +1,34 @@ +create table cctab (a int, b as a*10, c int) +go +insert cctab values (1,2) +go +select * from cctab +go + +-- Expect Error +insert into cctab values (1,2,3) +go + +create table cctab2 (a int identity, b as a+10, c int) +go +insert cctab2 values (1) +go +select * from cctab2 +go + +create table cctab3 (a int, c int, b as a*10) +go +insert cctab3 values (1,2) +go +select * from cctab3 +go + +create table cctab4 (a int, c int, b as a*10, d as c*20) +go +insert cctab4 values (1,2) +go +select * from cctab4 +go + +DROP TABLE cctab, cctab2, cctab3, cctab4 +go diff --git a/contrib/test/JDBC/input/BABEL-1114.sql b/contrib/test/JDBC/input/BABEL-1114.sql new file mode 100644 index 00000000000..ab5aa50d495 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1114.sql @@ -0,0 +1,50 @@ +create table ccol(a varchar(20), b as substring(a,1,3)) +go +insert into ccol values('hello'); +go +select * from ccol; +go + +select substring('hello',1,3) +go +select substring(cast('hello' as sys.varchar(5)),1,3) +go +select substring(cast('hello' as sys.char(5)),1,3) +go +select substring(cast('hello' as sys.nvarchar(5)),1,3) +go +select substring(cast('hello' as sys.nchar(5)),1,3) +go +select substring('hello',0, 3) +go +select substring('hello',1, 0) +go +select substring('hello',100, 3) +go +select substring('hello',-1, 3) +go +select substring('hello',-10, 3) +go +select substring('hello',-4, 7) +go +select substring('hello', 1, 100) +go +select substring('ÀÈǸẀ', 1, 3); +go +select substring('Ææ', 1, 4); +go +select substring('hello', null, 3) +go +select substring('hello', 2, null) +go + +-- should error +select substring('hello',1, -3) +go +select substring(null, 1, 3) +go + + +-- cleanup +drop table ccol; +go \ No newline at end of file diff --git a/contrib/test/JDBC/input/BABEL-1149.sql b/contrib/test/JDBC/input/BABEL-1149.sql new file mode 100644 index 00000000000..066f18e1df8 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1149.sql @@ -0,0 +1,62 @@ +-- test inline TVF which uses RETURN_QUERY statement - shouldn't send Done +-- tokens +create function itvf_1149 (@number int) returns table as return (select 1 as a, 2 as b); +GO + +select * from itvf_1149(5); +GO + +-- test multi-statement TVF which uses DECL_TABLE, INSERT/UPDATE/DELETE and +-- RETURN_TABLE statements - shouldn't send Done tokens +create function mstvf_1149(@i int) returns @tableVar table (a nvarchar(10), b int, c int) +as +begin +insert into @tableVar values('hello1', 1, 100); +insert into @tableVar values('hello2', 2, 200); +insert into @tableVar values('hello3', 3, 300); +update @tableVar set b = 2 where b = 3; +delete @tableVar where b = 2; +return; +end; +GO + +select * from mstvf_1149(10); +GO + +-- test user-defined function with DMLs on table variables - shouldn't send Done +-- tokens +create function func_1149(@i int) returns int as begin +declare @a as table (a int, b int) +insert into @a values (100, 200) +return 1; +end; +GO + +select func_1149(1); +GO + +-- test inline code blocks with DMLs on table variables - should send Done +-- tokens +declare @a table (a int, b int); +insert into @a values(1, 100); +GO + +-- test procedure with DMLs on table variables - should send Done tokens +create procedure proc_1149 as +declare @a table (a int, b int); +insert into @a values(1, 100); +update @a set b = 200; +GO + +exec proc_1149 +GO + +-- cleanup +drop function itvf_1149; +GO +drop function mstvf_1149; +GO +drop function func_1149; +GO +drop procedure proc_1149; +GO diff --git a/contrib/test/JDBC/input/BABEL-1161.sql b/contrib/test/JDBC/input/BABEL-1161.sql new file mode 100644 index 00000000000..654e9ad2c2d --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1161.sql @@ -0,0 +1,134 @@ +-- issue 1: RETURN SELECT without parenthesis +CREATE PROCEDURE babel_1161_proc_1 +AS +BEGIN + declare @a int + declare @b int + set @a = 1 + return + select @b=@a+1 +END +GO + +CREATE PROCEDURE babel_1161_proc_1_wrapper +AS +BEGIN + DECLARE @ret int; + EXEC @ret = babel_1161_proc_1 + -- note: should show 0 since procedure succeeded. + PRINT '@ret: ' + cast(@ret as varchar(10)); +END +GO + +EXEC babel_1161_proc_1_wrapper +GO + +CREATE PROCEDURE babel_1161_proc_1_2 +AS +BEGIN + RETURN SELECT 1 +END +GO + +CREATE PROCEDURE babel_1161_proc_1_2_wrapper +AS +BEGIN + DECLARE @ret int; + EXEC @ret = babel_1161_proc_1_2 + PRINT '@ret: ' + cast(@ret as varchar(10)); +END +GO + +EXEC babel_1161_proc_1_2_wrapper +GO + +CREATE PROCEDURE babel_1161_proc_1_3 +AS +BEGIN + RETURN (SELECT 1) +END +GO + +CREATE PROCEDURE babel_1161_proc_1_3_wrapper +AS +BEGIN + DECLARE @ret int; + EXEC @ret = babel_1161_proc_1_3 + PRINT '@ret: ' + cast(@ret as varchar(10)); +END +GO + +EXEC babel_1161_proc_1_3_wrapper +GO + +-- issue 2: INSERT INTO ... (SELECT ...) SELECT +CREATE TABLE babel_1161_t21(a int); +INSERT INTO babel_1161_t21 values(1); +CREATE TABLE babel_1161_t22(a int); +GO + +CREATE PROCEDURE babel_1161_proc_2 +AS + DECLARE @inserted INT + + INSERT INTO babel_1161_t22 + (SELECT * FROM babel_1161_t21) + SELECT @inserted = @@ROWCOUNT +GO + +EXEC babel_1161_proc_2; +GO + +SELECT * FROM babel_1161_t22; +GO + +-- issue 3: support SELECT TOP () ... + +create table babel_1161_t31(a int, a2 char); +insert into babel_1161_t31 values (1, 'a'), (2, 'b'); +create table babel_1161_t32(b int); +insert into babel_1161_t32 values (1), (2), (3), (4); +GO + +select top (select a from babel_1161_t31 where a2 = 'a') * from babel_1161_t32 order by b; +GO + +select top (select a from babel_1161_t31 where a2 = 'b') * from babel_1161_t32 order by b; +GO + +-- empty scalar subquery +-- note: we have a bug here: BABEL-1181 +-- please update the comment and expected output once the bug is fixed. +select top (select a from babel_1161_t31 where a2 = 'c') * from babel_1161_t32 order by b; +GO + +-- not a single row +select top (select a from babel_1161_t31) * from babel_1161_t32 order by b; +GO + +-- not a single column +select top (select a, a2 from babel_1161_t31 where a2 = 'a') * from babel_1161_t32 order by b; +GO + +DROP PROCEDURE babel_1161_proc_1_wrapper; +GO +DROP PROCEDURE babel_1161_proc_1; +GO +DROP PROCEDURE babel_1161_proc_1_2_wrapper; +GO +DROP PROCEDURE babel_1161_proc_1_2; +GO +DROP PROCEDURE babel_1161_proc_1_3_wrapper; +GO +DROP PROCEDURE babel_1161_proc_1_3; +GO +DROP PROCEDURE babel_1161_proc_2; +GO +DROP TABLE babel_1161_t21; +GO +DROP TABLE babel_1161_t22; +GO +DROP TABLE babel_1161_t31; +GO +DROP TABLE babel_1161_t32; +GO diff --git a/contrib/test/JDBC/input/BABEL-1164.sql b/contrib/test/JDBC/input/BABEL-1164.sql new file mode 100644 index 00000000000..578834853b9 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1164.sql @@ -0,0 +1,52 @@ +-- Test inserting less values than columns +CREATE TABLE t1(c1 int, c2 numeric, c3 varchar(32)); +GO + +INSERT INTO t1 VALUES (1, 2.0, 'hello'); +GO + +-- Expect error +INSERT INTO t1 VALUES (1, 2.0); +GO + +SELECT * FROM t1; +GO + +CREATE TABLE t2(id int IDENTITY, c1 int, c2 numeric, c3 AS c1 * c2); +GO + +INSERT INTO t2 VALUES (1, 2.0); +GO + +-- Expect error +INSERT INTO t2 VALUES (5); +GO + +SELECT * FROM t2; +GO + +INSERT INTO t1 SELECT c1, c2, c3 FROM t2; +GO + +SELECT * FROM t1; +GO + +-- Expect error +INSERT INTO t1 SELECT id, c2 FROM t2; +GO + +SELECT * FROM t1; +GO + +CREATE TABLE t3(c1 int, c2 numeric); +GO + +INSERT INTO t3 VALUES (2, 4); +GO + +-- Expect error +INSERT INTO t1 SELECT * FROM t3; +GO + +DROP TABLE t1, t2, t3; +GO diff --git a/contrib/test/JDBC/input/BABEL-1167.sql b/contrib/test/JDBC/input/BABEL-1167.sql new file mode 100644 index 00000000000..79b4098727c --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1167.sql @@ -0,0 +1,24 @@ +CREATE TABLE babel_1167_table (a INT); +go + +INSERT INTO babel_1167_table VALUES (111), (222) +go + +CREATE PROCEDURE babel_1167_proc AS +IF 1=1 + UPDATE babel_1167_table SET a = 0 +ELSE + UPDATE babel_1167_table SET a = 1 +go + +EXEC babel_1167_proc +go + +SELECT * FROM babel_1167_table +go + +DROP PROC babel_1167_proc +go + +DROP TABLE babel_1167_table +go diff --git a/contrib/test/JDBC/input/BABEL-1173.sql b/contrib/test/JDBC/input/BABEL-1173.sql new file mode 100644 index 00000000000..8c84057e820 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1173.sql @@ -0,0 +1,13 @@ +CREATE PROCEDURE proc_babel_1173 +( + @p INT NULL +) +AS PRINT 'helloworld' +GO + +EXEC proc_babel_1173 1 +GO + +DROP PROCEDURE proc_babel_1173 +GO + diff --git a/contrib/test/JDBC/input/BABEL-1179.sql b/contrib/test/JDBC/input/BABEL-1179.sql new file mode 100644 index 00000000000..14bba845592 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1179.sql @@ -0,0 +1,61 @@ +-- Test implicit cast: bit -> int2/int4/int8 +CREATE FUNCTION implicit_2int2(@i INT2) +RETURNS INT +AS +BEGIN + RETURN (@i) +END; +GO +SELECT implicit_2int2(CAST(1 AS bit)); +GO + +CREATE FUNCTION implicit_2int4(@i INT4) +RETURNS INT +AS +BEGIN + RETURN (@i) +END; +GO +SELECT implicit_2int4(CAST(1 AS bit)); +GO + +CREATE FUNCTION implicit_2int8(@i INT8) +RETURNS INT +AS +BEGIN + RETURN (@i) +END; +GO +SELECT implicit_2int8(CAST(1 AS bit)); +GO + +-- Test implicit cast: int2/int4/int8 -> bit +CREATE FUNCTION implicit_2bit(@i bit) +RETURNS bit +AS +BEGIN + RETURN (@i) +END; +GO +SELECT implicit_2bit(CAST(1 AS INT2)); +GO +SELECT implicit_2bit(CAST(1 AS INT4)); +GO +SELECT implicit_2bit(CAST(1 AS INT8)); +GO + + + +-- Test ISNULL() with bit and int arguments +SELECT ISNULL(CAST(1 AS bit), CAST(1 AS INT2)) +GO +SELECT ISNULL(CAST(1 AS bit), CAST(1 AS INT4)) +GO +SELECT ISNULL(CAST(1 AS bit), CAST(1 AS INT8)) +GO +SELECT ISNULL(CAST(1 AS INT2), CAST(1 AS bit)) +GO +SELECT ISNULL(CAST(1 AS INT4), CAST(1 AS bit)) +GO +SELECT ISNULL(CAST(1 AS INT8), CAST(1 AS bit)) +GO diff --git a/contrib/test/JDBC/input/BABEL-1184.sql b/contrib/test/JDBC/input/BABEL-1184.sql new file mode 100644 index 00000000000..9b1257f3fe1 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1184.sql @@ -0,0 +1,66 @@ +CREATE TABLE TMP_1 (a INT) +GO +INSERT INTO TMP_1 VALUES (1) +GO +CREATE TABLE TMP_2 (a INT, b INT) +GO + +-- test INSERT SELECT with UNION or UNION ALL in procedure +CREATE PROCEDURE TEST_INSERT_SELECT +AS +INSERT INTO TMP_2 (a) +SELECT a FROM TMP_1 +UNION +SELECT a FROM TMP_1 +UNION +SELECT a FROM TMP_1 + +INSERT INTO TMP_2 (a) +SELECT a FROM TMP_1 +UNION ALL +SELECT a FROM TMP_1 +UNION ALL +SELECT a FROM TMP_1 +GO + +SELECT * FROM TMP_2 +GO +EXECUTE TEST_INSERT_SELECT +GO +SELECT * FROM TMP_2 +GO + +-- test SELECT with UNION in procedure +CREATE PROCEDURE TEST_SELECT_1 +AS +SELECT a FROM TMP_1 +UNION +SELECT a FROM TMP_1 +UNION +SELECT a FROM TMP_1 +GO +EXECUTE TEST_SELECT_1 +GO + +-- test SELECT with UNION ALL in procedure +CREATE PROCEDURE TEST_SELECT_2 +AS +SELECT a FROM TMP_1 +UNION ALL +SELECT a FROM TMP_1 +UNION ALL +SELECT a FROM TMP_1 +GO +EXECUTE TEST_SELECT_2 +GO + +DROP TABLE TMP_1 +GO +DROP TABLE TMP_2 +GO +DROP PROCEDURE TEST_INSERT_SELECT +GO +DROP PROCEDURE TEST_SELECT_1 +GO +DROP PROCEDURE TEST_SELECT_2 +GO diff --git a/contrib/test/JDBC/input/BABEL-1185.sql b/contrib/test/JDBC/input/BABEL-1185.sql new file mode 100644 index 00000000000..2960b12cb8a --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1185.sql @@ -0,0 +1,14 @@ +CREATE TABLE t_1185(a int); +go + +CREATE TRIGGER tr_1185 ON t_1185 AFTER UPDATE AS +BEGIN + IF NOT update(a) BEGIN RETURN END +END +go + +DROP TRIGGER tr_1185; +go + +DROP TABLE t_1185; +go diff --git a/contrib/test/JDBC/input/BABEL-1189.sql b/contrib/test/JDBC/input/BABEL-1189.sql new file mode 100644 index 00000000000..d685a87baaa --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1189.sql @@ -0,0 +1,27 @@ +create table babel_1189_t1(a int); +go + +create table babel_1189_t2(a int); +go + +create trigger babel_1189_trig on babel_1189_t2 +for insert as +update babel_1189_t1 set a = 2 +go + +insert babel_1189_t1 values(1); +go + +insert babel_1189_t2 values(1); +go + +select * from babel_1189_t1; +select * from babel_1189_t2; +go + +drop trigger babel_1189_trig; +drop table babel_1189_t1; +drop table babel_1189_t2; +go + + diff --git a/contrib/test/JDBC/input/BABEL-1193.sql b/contrib/test/JDBC/input/BABEL-1193.sql new file mode 100644 index 00000000000..baa0b49bc27 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1193.sql @@ -0,0 +1,158 @@ +-- String to numeric types +-- String -> numeric(p,s) +CREATE TABLE t1 (a text, b varchar(20), c char(10)); +GO + +INSERT INTO t1 values ('94.564', '-12.1246', '32.22'); +GO +INSERT INTO t1 values ('-94.564', '12.1246', '-32.22'); +GO +INSERT INTO t1 values ('0', '0', '0'); +GO +CREATE TABLE t2 (n1 numeric(3,1), n2 numeric(3,1), n3 numeric(3,1)); +GO +INSERT INTO t2 SELECT * from t1; +GO +SELECT * FROM t2; +GO + +-- String -> int2/int4/int8 +CREATE TABLE t3 (a text, b varchar(20), c char(10)); +GO + +INSERT INTO t3 values ('12', '1234', '5431'); +GO +INSERT INTO t3 values ('0', '0', '0'); +GO +INSERT INTO t3 values ('-12', '-1234', '-5431'); +GO +-- int2 +CREATE TABLE t4 (si1 smallint, si2 smallint, si3 smallint); +GO +INSERT INTO t4 SELECT * from t3; +GO +select * from t4; +GO +-- int4 +CREATE TABLE t5 (i1 int, i2 int, i3 int); +GO +INSERT INTO t5 SELECT * from t3; +GO +select * from t5; +GO +-- int8 +CREATE TABLE t6 (bi1 bigint, bi2 bigint, bi3 bigint); +GO +INSERT INTO t6 SELECT * from t3; +GO +select * from t6; +GO + +-- String -> float,fixeddecimal +CREATE TABLE t7 (a text, b varchar(20), c char(10)); +GO + +INSERT INTO t7 values ('11.23456', '12.34234', '60.54314'); +GO +INSERT INTO t7 values ('0', '0', '0'); +GO +INSERT INTO t7 values ('-12.01233', '-19.2346', '-43.88641'); +GO +-- real (=float4) +CREATE TABLE t8 (f1 real, f2 real, f3 real); +GO +INSERT INTO t8 SELECT * from t7; +GO +select * from t8; +GO +-- float (=float(53) =double precision) +CREATE TABLE t9 (f1 float, f2 float, f3 float); +GO +INSERT INTO t9 SELECT * from t7; +GO +select * from t9; +GO +-- smallmoney +CREATE TABLE t10 (sm1 smallmoney, sm2 smallmoney, sm3 smallmoney); +GO +INSERT INTO t10 SELECT * from t7; +GO +select * from t10; +GO +-- money +CREATE TABLE t11 (m1 money, m2 money, m3 money); +GO +INSERT INTO t11 SELECT * from t7; +GO +select * from t11; +GO + + +-- Numeric types to string types +-- numeric types -> text +CREATE TABLE t12 (si smallint, i int, bi bigint, f real, f8 float, n numeric(4,2), sm smallmoney, m money); +GO + +INSERT INTO t12 values (12, 4553, 123456, 12.345, 2344.456, 12.34, 456.3334, 1123.6777); +GO +INSERT INTO t12 values (-12, -1234, -123456, -12.345, -2344.456, 12.34, -456.3334, -1123.6777); +GO +INSERT INTO t12 values (0, 0, 0, 0, 0, 0, 0, 0); +GO +CREATE TABLE t13 (txt1 text,txt2 text,txt3 text,txt4 text,txt5 text,txt6 text,txt7 text,txt8 text); +GO +INSERT INTO t13 SELECT * from t12; +GO +SELECT * FROM t13; +GO +-- numeric types -> varchar(20) +CREATE TABLE t14 (v1 varchar(20),v2 varchar(20),v3 varchar(20),v4 varchar(20),v5 varchar(20),v6 varchar(20),v7 varchar(20),v8 varchar(20)); +GO +INSERT INTO t14 SELECT * from t12; +GO +SELECT * FROM t14; +GO +-- numeric types -> char(10) +CREATE TABLE t15 (c1 char(20),c2 char(20),c3 char(20),c4 char(20),c5 char(20),c6 char(20),c7 char(20),c8 char(20)); +GO +INSERT INTO t15 SELECT * from t12; +GO +SELECT * FROM t15; +GO + +-- functions +select upper(cast (1 as smallint)), upper(cast (1 as int)), upper(cast (1 as bigint)), upper(cast (1 as real)), upper(cast (1 as float)), upper(cast (2.1 as numeric(2,1))), upper(cast (1 as smallmoney)), upper(cast (1 as money)); +GO +select round(cast ('123' as text), 1), round(cast ('123' as char(3)), 1), round(cast ('123' as varchar(3)), 1); +GO + +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 t10; +GO +DROP TABLE t11; +GO +DROP TABLE t12; +GO +DROP TABLE t13; +GO +DROP TABLE t14; +GO +DROP TABLE t15; +GO diff --git a/contrib/test/JDBC/input/BABEL-1206.sql b/contrib/test/JDBC/input/BABEL-1206.sql new file mode 100644 index 00000000000..c456d346397 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1206.sql @@ -0,0 +1,73 @@ +-- BABEL-1265 +create table babel_1265_t1 (a varbinary(8), b varbinary(8)); +go +insert into babel_1265_t1 values (0xaaa, 0xbbb); +go +select (case when ab then 1 else 0 end) r from babel_1265_t1; +go +select (case when a>=b then 1 else 0 end) r from babel_1265_t1; +go + +-- BABEL-1206 actual scenarios +CREATE TABLE babel_1206_t1( + [Login] varchar(50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, + [PasswordSHA1] varbinary(20) NOT NULL DEFAULT ((0)), + [UserLicenseKey] int NOT NULL +) +ON [PRIMARY]; +go +CREATE NONCLUSTERED INDEX babel_1206_t1_i1 + ON babel_1206_t1 ([Login] ASC, [UserLicenseKey] ASC, [PasswordSHA1] ASC) + WITH (FILLFACTOR = 90); +go +insert into babel_1206_t1 values (0xaaa, 0xbbb, 1); +go + +CREATE TABLE babel_1206_t2( + [profile_id] int NOT NULL, + [result_hash] binary(32) NULL +) +ON [PRIMARY]; +go +CREATE NONCLUSTERED INDEX babel_1206_t2_i1 + ON babel_1206_t2 ([profile_id] ASC, [result_hash] ASC); +go +insert into babel_1206_t2 values (1, 0xaaa); +go + +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_unique_constraint', 'ignore'; +go + +CREATE TABLE babel_1206_t3( + [DistinctApplicationID] [bigint] IDENTITY(1,1) NOT NULL, + [Description] [nvarchar](1024) NOT NULL, + [DescriptionHash] AS (hashbytes('MD5',[Description])) PERSISTED NOT NULL, + CONSTRAINT babel_1206_t3_i3 UNIQUE NONCLUSTERED + ( + [DescriptionHash] ASC + ) + ) ON [PRIMARY] +go + +insert into babel_1206_t3 values (0xaaa); +go +--should throw an error because of duplicate index key +insert into babel_1206_t3 values (0xaaa); +go + +drop table babel_1265_t1; +go +drop table babel_1206_t1; +go +drop table babel_1206_t2; +go +drop table babel_1206_t3; +go +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_unique_constraint', 'strict'; +go diff --git a/contrib/test/JDBC/input/BABEL-1208.sql b/contrib/test/JDBC/input/BABEL-1208.sql new file mode 100644 index 00000000000..ffaaf08dbef --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1208.sql @@ -0,0 +1,59 @@ +create table babel_1208_t1 (a uniqueidentifier); +GO +insert into babel_1208_t1 values (convert(uniqueidentifier, 0x00)); +insert into babel_1208_t1 values (convert(uniqueidentifier, 0x1)); +insert into babel_1208_t1 values (convert(uniqueidentifier, 0x01)); +insert into babel_1208_t1 values (convert(uniqueidentifier, 0x123)); +insert into babel_1208_t1 values (convert(uniqueidentifier, 0x00010203040506070809)); +insert into babel_1208_t1 values (convert(uniqueidentifier, 0x000102030405060708090a0b0c0d0e0f)); +insert into babel_1208_t1 values (convert(uniqueidentifier, 0x000102030405060708090a0b0c0d0e0f1011121314)); +GO +select * from babel_1208_t1 order by a; +GO + +-- customer scenario +CREATE TABLE babel_1208_t2([SourceActivityTypeId] [uniqueidentifier] NOT NULL) +go +ALTER TABLE babel_1208_t2 ADD DEFAULT (CONVERT([uniqueidentifier],0x00)) FOR [SourceActivityTypeId] +GO +INSERT INTO babel_1208_t2 values (default), (default); +GO +SELECT * FROM babel_1208_t2 order by 1; +GO + +-- implicit castings +CREATE FUNCTION babel_1208_f_binary(@v binary(16)) RETURNS binary(16) AS BEGIN RETURN @v; END +GO +--SELECT babel_1208_f_binary(a) FROM babel_1208_t1; +GO + +CREATE FUNCTION babel_1208_f_varbinary(@v varbinary(16)) RETURNS varbinary(16) AS BEGIN RETURN @v; END +GO +SELECT babel_1208_f_varbinary(a) FROM babel_1208_t1; +GO + + +create table babel_1208_t3 (c1 binary(16), c2 varbinary(16)); +GO +insert into babel_1208_t3 values (0x000102030405060708090a0b0c0d0e0f, 0x000102030405060708090a0b0c0d0e0f); +GO + +CREATE FUNCTION babel_1208_f_uuid(@u uniqueidentifier) RETURNS uniqueidentifier AS BEGIN RETURN @u; END +GO + +SELECT babel_1208_f_uuid(c1) binary_in, babel_1208_f_uuid(c2) varbinary_in from babel_1208_t3 +GO + +-- cleanup +drop table babel_1208_t1; +GO +drop table babel_1208_t2; +GO +drop table babel_1208_t3; +GO +drop function babel_1208_f_binary; +GO +drop function babel_1208_f_varbinary; +GO +drop function babel_1208_f_uuid; +GO diff --git a/contrib/test/JDBC/input/BABEL-1210.sql b/contrib/test/JDBC/input/BABEL-1210.sql new file mode 100644 index 00000000000..822daba3db1 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1210.sql @@ -0,0 +1,98 @@ +CREATE FUNCTION test_implicit_2int2(@i INT2) +RETURNS INT2 +AS +BEGIN + RETURN (@i) +END; +GO + +CREATE FUNCTION test_implicit_2int4(@i INT4) +RETURNS INT4 +AS +BEGIN + RETURN (@i) +END; +GO + +CREATE FUNCTION test_implicit_2int8(@i INT8) +RETURNS INT8 +AS +BEGIN + RETURN (@i) +END; +GO + +CREATE FUNCTION test_implicit_2float4(@i float4) +RETURNS float4 +AS +BEGIN + RETURN (@i) +END; +GO + +CREATE FUNCTION test_implicit_2float8(@i float8) +RETURNS float8 +AS +BEGIN + RETURN (@i) +END; +GO + + +CREATE TABLE t1 (a text, b varchar(20), c char(4)); +GO + +INSERT INTO t1 values ('1234.56', '-12.12', '3.14'); +GO +INSERT INTO t1 values ('0', '-10000', '1'); +GO +INSERT INTO t1 values ('-23.33', '12345', '0'); +GO +INSERT INTO t1 values ('-33', '22', '-145'); +GO + +-- Test implicit casting to float4 + +SELECT test_implicit_2float4(a), test_implicit_2float4(b), test_implicit_2float4(c) from t1; +GO + +-- Test implicit casting to float8 +SELECT test_implicit_2float8(a), test_implicit_2float8(b), test_implicit_2float8(c) from t1; +GO + +CREATE TABLE t2 (a text, b varchar(20), c char(4)); +GO + +INSERT INTO t2 values ('1234', '-12', '0'); +GO +INSERT INTO t2 values ('0', '10000', '-123'); +GO +INSERT INTO t2 values ('-1234', '0', '52'); +GO + +-- Test implicit casting to int2 +SELECT test_implicit_2int2(a), test_implicit_2int2(b), test_implicit_2int2(c) from t2; +GO + +-- Test implicit casting to int4 +SELECT test_implicit_2int4(a), test_implicit_2int4(b), test_implicit_2int4(c) from t2; +GO + +-- Test implicit casting to int8 +SELECT test_implicit_2int8(a), test_implicit_2int8(b), test_implicit_2int8(c) from t2; +GO + +DROP TABLE t1; +GO +DROP TABLE t2; +GO +DROP FUNCTION test_implicit_2int2; +GO +DROP FUNCTION test_implicit_2int4; +GO +DROP FUNCTION test_implicit_2int8; +GO +DROP FUNCTION test_implicit_2float4; +GO +DROP FUNCTION test_implicit_2float8; +GO diff --git a/contrib/test/JDBC/input/BABEL-1212.sql b/contrib/test/JDBC/input/BABEL-1212.sql new file mode 100644 index 00000000000..34c1d35eb42 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1212.sql @@ -0,0 +1,10 @@ +create table #tt(a int); +go +select (case when OBJECT_ID('#tt') IS NOT NULL then 'true' else 'false' end) result; +go +select (case when OBJECT_ID('tempdb..#tt') IS NOT NULL then 'true' else 'false' end) result; +go +select (case when OBJECT_ID('tempdb..#tt2') IS NULL then 'true' else 'false' end) result; +go +drop table #tt; +go diff --git a/contrib/test/JDBC/input/BABEL-1231.sql b/contrib/test/JDBC/input/BABEL-1231.sql new file mode 100644 index 00000000000..6e1b0c5e20d --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1231.sql @@ -0,0 +1,29 @@ +CREATE FUNCTION custom_diff( + @one int, + @two int +) +RETURNS int +AS +BEGIN + RETURN (@one - @two); +END; +GO + +DECLARE @one int = 100; +DECLARE @two int = 200; +DECLARE @returnstatus int; +-- execute UDF +EXECUTE @returnstatus = custom_diff @one, @two; +SELECT @returnstatus; +-- execute UDF with named arguments +EXECUTE @returnstatus = custom_diff @one = @one, @two = @two; +SELECT @returnstatus; +EXECUTE @returnstatus = custom_diff @two = @one, @one = @two; +SELECT @returnstatus; +-- execute UDF with mixed arguments +EXECUTE @returnstatus = custom_diff @one, @two = @two; +SELECT @returnstatus; +GO + +DROP FUNCTION custom_diff +GO diff --git a/contrib/test/JDBC/input/BABEL-1234.sql b/contrib/test/JDBC/input/BABEL-1234.sql new file mode 100644 index 00000000000..58979e9bb67 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1234.sql @@ -0,0 +1,2 @@ +SELECT CAST(0 AS BIT) AS N'AdminConnection'; +GO diff --git a/contrib/test/JDBC/input/BABEL-1239.sql b/contrib/test/JDBC/input/BABEL-1239.sql new file mode 100644 index 00000000000..deffe7862dd --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1239.sql @@ -0,0 +1,15 @@ +create table babel1239 (a int); +go +SELECT * from babel1239 +OPTION (MAXRECURSION 256); +go +WITH +z +AS ( + SELECT a FROM babel1239 + ) +SELECT * from z +OPTION (MAXRECURSION 256); +go +drop table babel1239; +go diff --git a/contrib/test/JDBC/input/BABEL-1241.sql b/contrib/test/JDBC/input/BABEL-1241.sql new file mode 100644 index 00000000000..429699655eb --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1241.sql @@ -0,0 +1,73 @@ +create table t_babel_1241 (a int, b int); +insert into t_babel_1241 values (10, 1); +go + +declare @v int=1; +select @v+=a from t_babel_1241; +select @v +go + +declare @v int=11; +select @v-=a from t_babel_1241; +select @v; +go + +declare @v int=2; +select @v*=a from t_babel_1241; +select @v; +go + +declare @v int=20; +select @v/=a from t_babel_1241; +select @v; +go + +declare @v int=24; +select @v%=a from t_babel_1241; +select @v; +go + +declare @v int=63; +select @v&=a from t_babel_1241; +select @v; +go + +declare @v int=7; +select @v|=a from t_babel_1241; +select @v; +go + +declare @v int=7; +select @v^=a from t_babel_1241; +select @v; +go + +-- many compound operator +declare @v int=1; +declare @v2 int=2; +declare @v3 int=3; +select @v+=a, @v2-=a, @v3*=a from t_babel_1241; +select @v, @v2, @v3; +go + +-- compound operator on same target (we don't support this) +declare @v int=1; +select @v+=a, @v-=b from t_babel_1241; +select @v +go + +-- compound operator and equal operator +declare @v int=1; +declare @v2 int=2; +select @v+=a, @v2=b from t_babel_1241; +select @v, @v2; +go + +-- compound operator and non-assignment. error should be thrown +declare @v int=1; +declare @v2 int=2; +select @v+=a, b from t_babel_1241; +go + +drop table t_babel_1241; +go diff --git a/contrib/test/JDBC/input/BABEL-1243.sql b/contrib/test/JDBC/input/BABEL-1243.sql new file mode 100644 index 00000000000..a875cb166f5 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1243.sql @@ -0,0 +1,19 @@ +CREATE TABLE employeeData( + ID INT IDENTITY (1,1) PRIMARY KEY,Emp_First_name VARCHAR (50),Emp_Last_name VARCHAR (50),Emp_Salary INT) +GO + +CREATE TRIGGER updEmployeeDatas ON employeeData AFTER UPDATE,INSERT AS + select * from inserted; +GO + +insert into employeeData values ('a','b',234); +GO + +update employeeData set Emp_Last_name = 'ccc' where id = 1; +GO + +drop trigger updEmployeeDatas +GO + +drop table employeeData +GO diff --git a/contrib/test/JDBC/input/BABEL-1249.sql b/contrib/test/JDBC/input/BABEL-1249.sql new file mode 100644 index 00000000000..fed743a269d --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1249.sql @@ -0,0 +1,43 @@ +-- time +if CAST('01:01:01' AS TIME) < CAST(CAST('02:02:02' AS TIME) AS SQL_VARIANT) SELECT 1 ELSE SELECT 2; +GO + +-- date +if CAST('2010-02-02' AS DATE) < CAST(CAST('2020-02-02' AS DATE) AS SQL_VARIANT) SELECT 1 ELSE SELECT 2; +GO + +-- smalldatetime +if CAST('2010-02-02' AS SMALLDATETIME) < CAST(CAST('2020-02-02' AS SMALLDATETIME) AS SQL_VARIANT) SELECT 1 ELSE SELECT 2; +GO + +-- datetimeoffset +if CAST('2020-10-05 09:00:00.123456-9:00' AS DATETIMEOFFSET) < CAST(CAST('2020-10-05 09:00:00.123456-8:00' AS DATETIMEOFFSET) AS SQL_VARIANT) SELECT 1 ELSE SELECT 2; +GO + +-- int +if CAST(1 AS INT) < CAST(CAST(2 AS INT) AS SQL_VARIANT) SELECT 1 ELSE SELECT 2; +GO + +-- bigint +if CAST(1 AS BIGINT) < CAST(CAST(2 AS BIGINT) AS SQL_VARIANT) SELECT 1 ELSE SELECT 2; +GO + +-- bit +if CAST(0 AS BIT) < CAST(CAST(1 AS BIT) AS SQL_VARIANT) SELECT 1 ELSE SELECT 2; +GO + +-- real +if CAST(0.1 AS REAL) < CAST(CAST(1.1 AS REAL) AS SQL_VARIANT) SELECT 1 ELSE SELECT 2; +GO + +-- float +if CAST(0.1 AS FLOAT) < CAST(CAST(1.1 AS FLOAT) AS SQL_VARIANT) SELECT 1 ELSE SELECT 2; +GO + +-- numeric +if CAST(0.1 AS NUMERIC(2,1)) < CAST(CAST(1.1 AS NUMERIC(2,1)) AS SQL_VARIANT) SELECT 1 ELSE SELECT 2; +GO + +-- uniqueidentifier +if CAST('1E984725-C51C-4BF4-9960-E1C80E27ABA0' AS UNIQUEIDENTIFIER) < CAST(CAST('2E984725-C51C-4BF4-9960-E1C80E27ABA0' AS UNIQUEIDENTIFIER) AS SQL_VARIANT) SELECT 1 ELSE SELECT 2; +GO \ No newline at end of file diff --git a/contrib/test/JDBC/input/BABEL-1251.sql b/contrib/test/JDBC/input/BABEL-1251.sql new file mode 100644 index 00000000000..ffc9276c578 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1251.sql @@ -0,0 +1,76 @@ +CREATE SCHEMA babel_1251; +GO + +-- Test id as second column +CREATE TABLE babel_1251.t1(col1 INT, id INT IDENTITY(1, 1) NOT NULL); +go +SET IDENTITY_INSERT babel_1251.t1 ON; +go +INSERT INTO babel_1251.t1(col1, id) VALUES (1, 10); +go +SELECT @@IDENTITY; +go +SET IDENTITY_INSERT babel_1251.t1 OFF; +go +INSERT INTO babel_1251.t1(col1) VALUES (1); +go +SELECT * FROM babel_1251.t1; +go +SELECT @@IDENTITY; +go + +-- Test id as middle column +CREATE TABLE babel_1251.t2(col1 VARCHAR(32), id INT IDENTITY(1, -1), col2 INT); +go +SET IDENTITY_INSERT babel_1251.t2 ON; +go +INSERT INTO babel_1251.t2(col1, id, col2) VALUES ('hello', -10, 1); +go +SELECT @@IDENTITY; +go +SET IDENTITY_INSERT babel_1251.t2 OFF; +go +INSERT INTO babel_1251.t2(col1, col2) VALUES ('world', 1); +go +SELECT @@IDENTITY; +go +SELECT * FROM babel_1251.t2; +go + +-- Test id as last column +CREATE TABLE babel_1251.t3(col1 VARCHAR(32), col2 INT, id INT IDENTITY); +go +INSERT INTO babel_1251.t3(col1, col2) VALUES ('hello', 1); +go +SELECT @@IDENTITY; +go +SET IDENTITY_INSERT babel_1251.t3 ON; +go +INSERT INTO babel_1251.t3(col1, col2, id) VALUES ('hello', 1, 20); +go +SET IDENTITY_INSERT babel_1251.t3 OFF; +go +SELECT @@IDENTITY; +go +INSERT INTO babel_1251.t3(col1, col2) VALUES ('hello', 1); +go +SELECT @@IDENTITY; +go +SET IDENTITY_INSERT babel_1251.t3 ON; +go +INSERT INTO babel_1251.t3(col1, col2, id) VALUES ('hello', 1, 30); +go +SELECT @@IDENTITY; +go +SET IDENTITY_INSERT babel_1251.t3 OFF; +go +SELECT * FROM babel_1251.t3; +go +SELECT @@IDENTITY; +go + +DROP TABLE babel_1251.t1, babel_1251.t2, babel_1251.t3; +go + +DROP SCHEMA babel_1251; +GO diff --git a/contrib/test/JDBC/input/BABEL-1252.sql b/contrib/test/JDBC/input/BABEL-1252.sql new file mode 100644 index 00000000000..c84ee1a121d --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1252.sql @@ -0,0 +1,65 @@ +use master; +go + +create table dttest (d datetime) +go +insert dttest values(cast('10/10/2000 12:34:56.789' as datetime) - 100) +insert dttest values(cast('10/10/2000 12:34:56.789' as datetime) - (-100)) +insert dttest values(100 - cast('10/10/2000 12:34:56.789' as datetime)) +insert dttest values((-100) - cast('10/10/2000 12:34:56.789' as datetime)) +insert dttest values(cast('10/10/2000 12:34:56.789' as datetime) + 100) +insert dttest values(cast('10/10/2000 12:34:56.789' as datetime) + (-100)) +insert dttest values(100 + cast('10/10/2000 12:34:56.789' as datetime)) +insert dttest values((-100) + cast('10/10/2000 12:34:56.789' as datetime)) +go + +insert dttest values(cast('10/10/2000 12:34:56.789' as datetime) - 1.5) +insert dttest values(cast('10/10/2000 12:34:56.789' as datetime) - (-1.5)) +insert dttest values(2.3 - cast('10/10/2000 12:34:56.789' as datetime)) +insert dttest values((-2.3) - cast('10/10/2000 12:34:56.789' as datetime)) +insert dttest values(cast('10/10/2000 12:34:56.789' as datetime) + .11) +insert dttest values(cast('10/10/2000 12:34:56.789' as datetime) + (-.11)) +insert dttest values(8.55 + cast('10/10/2000 12:34:56.789' as datetime)) +insert dttest values((-9.76) + cast('10/10/2000 12:34:56.789' as datetime)) +go + +-- should error, out of range +insert dttest values(10000000 + cast('10/10/2000 12:34:56.789' as datetime)) +go +insert dttest values(cast('10/10/2000 12:34:56.789' as datetime) - 10000000) +go + +select * from dttest +go + + +create table dttest2 (d smalldatetime) +go +insert dttest2 values(1000 - cast('1/10/1900 12:34:56.789' as smalldatetime)) +insert dttest2 values(cast('10/10/2000 12:34:56.789' as smalldatetime) + 100) +insert dttest2 values(cast('10/10/2000 12:34:56.789' as smalldatetime) - 10) +insert dttest2 values(100 + cast('10/10/2000 12:34:56.789' as smalldatetime)) +go + +insert dttest2 values(cast('10/10/2000 12:34:56.789' as smalldatetime) + 1.5) +insert dttest2 values(cast('10/10/2000 12:34:56.789' as smalldatetime) - (1.5)) +insert dttest2 values(20.3 - cast('1/2/1900 12:34:56.789' as smalldatetime)) +insert dttest2 values(cast('10/10/2000 12:34:56.789' as smalldatetime) + .11) +insert dttest2 values(8.55 + cast('10/10/2000 12:34:56.789' as smalldatetime)) +go + +-- should error, out of range +insert dttest2 values(100000 + cast('10/10/2000 12:34:56.789' as smalldatetime)) +go +insert dttest2 values((-100000)+ cast('10/10/2000 12:34:56.789' as smalldatetime)) +go +insert dttest2 values(cast('10/10/2000 12:34:56.789' as smalldatetime) - 10000000) +go + +select * from dttest2 +go + + +drop table dttest +drop table dttest2 +go \ No newline at end of file diff --git a/contrib/test/JDBC/input/BABEL-1261.sql b/contrib/test/JDBC/input/BABEL-1261.sql new file mode 100644 index 00000000000..c7265aaf343 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1261.sql @@ -0,0 +1,73 @@ +CREATE PROCEDURE sp_babel_1261_1 (@a SMALLINT OUTPUT) AS +BEGIN + SET @a=100; + select @a as a; +END; +GO + +exec sp_babel_1261_1 2; +GO + +CREATE PROCEDURE sp_babel_1261_2 (@a SMALLINT OUTPUT, @b SMALLINT OUTPUT) AS +BEGIN + SET @a=100; + SET @b=200; + select @a+@b as r; +END; +GO + +EXEC sp_babel_1261_2 2, 3; +GO + +DECLARE @a INT; +EXEC sp_babel_1261_2 @a OUT, 3; +SELECT @a; +GO + +DECLARE @b INT; +EXEC sp_babel_1261_2 2, @b OUT; +SELECT @b; +GO + +DECLARE @a INT; +DECLARE @b INT; +EXEC sp_babel_1261_2 @a OUT, @b OUT; +SELECT @a+@b; +GO + +CREATE PROCEDURE sp_babel_1307_1 (@a numeric(10,4) OUTPUT) AS +BEGIN + SET @a=100.41; + select @a as a; +END; +GO + +exec sp_babel_1307_1 2.000; +GO + +CREATE PROCEDURE sp_babel_1307_2 (@a numeric(10,4) OUTPUT, @b numeric(10,4) OUTPUT) AS +BEGIN + SET @a=100.41; + SET @b=200.82; + select @a+@b as r; +END; +GO + +EXEC sp_babel_1307_2 2.000, 3.000; +GO + +DECLARE @a INT; +EXEC sp_babel_1307_2 @a OUT, 3.000; +SELECT @a; +GO + +DECLARE @b INT; +EXEC sp_babel_1307_2 2.000, @b OUT; +SELECT @b; +GO + +DECLARE @a INT; +DECLARE @b INT; +EXEC sp_babel_1307_2 @a OUT, @b OUT; +SELECT @a+@b; +GO diff --git a/contrib/test/JDBC/input/BABEL-1270.txt b/contrib/test/JDBC/input/BABEL-1270.txt new file mode 100644 index 00000000000..876ede7aaab --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1270.txt @@ -0,0 +1,15 @@ +CREATE TABLE test_cursors_fetch_next(a INT, b SMALLINT, c BIGINT, d TINYINT, e BIT); +INSERT INTO test_cursors_fetch_next values(0, 0, 0, 0, 0) +INSERT INTO test_cursors_fetch_next values(NULL, NULL, NULL, NULL, NULL) +INSERT INTO test_cursors_fetch_next values(1, 2, 3, 4, 1) +INSERT INTO test_cursors_fetch_next values(211234, 9780, 891372401, 56, 1) +# SET escape_hatch_session_settings to ignore CURSOR_CLOSE_ON_COMMIT +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_session_settings', 'ignore'; +cursor#!#open#!#SELECT * FROM test_cursors_fetch_next#!#TYPE_SCROLL_INSENSITIVE#!#CONCUR_READ_ONLY#!#CLOSE_CURSORS_AT_COMMIT +cursor#!#fetch#!#afterlast +cursor#!#fetch#!#prev +cursor#!#fetch#!#beforefirst +cursor#!#fetch#!#next +cursor#!#close +DROP TABLE test_cursors_fetch_next +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_session_settings', 'strict'; diff --git a/contrib/test/JDBC/input/BABEL-1287.sql b/contrib/test/JDBC/input/BABEL-1287.sql new file mode 100644 index 00000000000..0013e330913 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1287.sql @@ -0,0 +1,98 @@ +-- implicit casting: uniqueidentifier -> string + +create table babel_1287_t1 (a uniqueidentifier); +GO +insert into babel_1287_t1 values (convert(uniqueidentifier, 0x00)); +insert into babel_1287_t1 values (convert(uniqueidentifier, 0x1)); +insert into babel_1287_t1 values (convert(uniqueidentifier, 0x01)); +insert into babel_1287_t1 values (convert(uniqueidentifier, 0x123)); +insert into babel_1287_t1 values (convert(uniqueidentifier, 0x00010203040506070809)); +insert into babel_1287_t1 values (convert(uniqueidentifier, 0x000102030405060708090a0b0c0d0e0f)); +insert into babel_1287_t1 values (convert(uniqueidentifier, 0x000102030405060708090a0b0c0d0e0f1011121314)); +GO + +CREATE FUNCTION babel_1287_f_char(@v char(40)) +RETURNS varchar(40) AS +BEGIN + RETURN @v; +END +GO + +CREATE FUNCTION babel_1287_f_varchar(@v varchar(40)) +RETURNS varchar(40) AS +BEGIN + RETURN @v; +END +GO + +CREATE FUNCTION babel_1287_f_text(@v text) +RETURNS text AS +BEGIN + RETURN @v; +END +GO + +SELECT babel_1287_f_char(a) char_result, babel_1287_f_varchar(a) varchar_result, babel_1287_f_text(a) text_result FROM babel_1287_t1; +GO + +-- implicit casting: string -> uniqueidentifier +create table babel_1287_tmp(a varchar(50)); +insert into babel_1287_tmp values ('6F9619FF-8B86-D011-B42D-00C04FC964FF'); +insert into babel_1287_tmp values ('6F9619FF-8B86-D011-B42D-00C04FC964FFwrong'); +insert into babel_1287_tmp values ('{6F9619FF-8B86-D011-B42D-00C04FC964FF}'); +GO +create table babel_1287_t2 (a char(50), b varchar(50), c text); +insert into babel_1287_t2 select a, a, a from babel_1287_tmp; +truncate table babel_1287_tmp; +GO + +insert into babel_1287_tmp values ('wrong6F9619FF-8B86-D011-B42D-00C04FC964FF'); +create table babel_1287_t2_invalid1 (a char(50), b varchar(50), c text); +insert into babel_1287_t2_invalid1 select a, a, a from babel_1287_tmp; +truncate table babel_1287_tmp; +GO + +insert into babel_1287_tmp values ('6F9619FF-8B86-D011-B42D-WRONGFC964FF'); +create table babel_1287_t2_invalid2 (a char(50), b varchar(50), c text); +insert into babel_1287_t2_invalid2 select a, a, a from babel_1287_tmp; +truncate table babel_1287_tmp; +GO + +CREATE FUNCTION babel_1287_f_ui(@v uniqueidentifier) +RETURNS uniqueidentifier AS +BEGIN + RETURN @v; +END +GO + +SELECT babel_1287_f_ui(a) char_in, babel_1287_f_ui(b) varchar_in, babel_1287_f_ui(c) text_in from babel_1287_t2; +GO + +-- wrong input +SELECT babel_1287_f_ui(a) char_in from babel_1287_t2_invalid1; +GO +SELECT babel_1287_f_ui(b) varchar_in from babel_1287_t2_invalid1; +GO +SELECT babel_1287_f_ui(c) text_in from babel_1287_t2_invalid1; +GO + +-- wrong input +SELECT babel_1287_f_ui(a) char_in from babel_1287_t2_invalid2; +GO +SELECT babel_1287_f_ui(b) varchar_in from babel_1287_t2_invalid2; +GO +SELECT babel_1287_f_ui(c) text_in from babel_1287_t2_invalid2; +GO + +DROP FUNCTION babel_1287_f_char; +DROP FUNCTION babel_1287_f_varchar; +DROP FUNCTION babel_1287_f_text; +DROP FUNCTION babel_1287_f_ui; +GO + +DROP TABLE babel_1287_t1; +DROP TABLE babel_1287_t2; +DROP TABLE babel_1287_t2_invalid1; +DROP TABLE babel_1287_t2_invalid2; +DROP TABLE babel_1287_tmp; +GO diff --git a/contrib/test/JDBC/input/BABEL-1291.sql b/contrib/test/JDBC/input/BABEL-1291.sql new file mode 100644 index 00000000000..965b626ff33 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1291.sql @@ -0,0 +1,16 @@ +CREATE TABLE sql_variant_test(a sql_variant, b sql_variant); +GO + +INSERT INTO sql_variant_test VALUES (NULL,NULL); +GO + +SELECT * FROM sql_variant_test; +GO + +DROP TABLE sql_variant_test; +GO + +select cast(cast(NULL as bit) as sql_variant); +select cast(cast(NULL as VARCHAR(2)) as sql_variant); +select cast(null as sql_variant); +GO \ No newline at end of file diff --git a/contrib/test/JDBC/input/BABEL-1299.sql b/contrib/test/JDBC/input/BABEL-1299.sql new file mode 100644 index 00000000000..584d071fd8e --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1299.sql @@ -0,0 +1,29 @@ +CREATE PROC babel_1299_proc (@a INT OUT, @b VARCHAR(10) OUTPUT) AS +BEGIN + SET @a = @a + 1; + SET @b = 'hi'; +END +go + +DECLARE @x INT = 10; +DECLARE @y VARCHAR(10) = 'hello'; +EXEC babel_1299_proc @x OUT, @y OUT +SELECT @x AS x, @y AS y; +go + +-- If an INOUT param is called without OUTPUT, +-- it's treated like a regular input param +DECLARE @x INT = 10; +DECLARE @y VARCHAR(10) = 'hello'; +EXEC babel_1299_proc @x OUT, @y +SELECT @x AS x, @y AS y; +go + +DECLARE @x INT = 10; +DECLARE @y VARCHAR(10) = 'hello'; +EXEC babel_1299_proc @x, @y OUT +SELECT @x AS x, @y AS y; +go + +DROP PROC babel_1299_proc +go diff --git a/contrib/test/JDBC/input/BABEL-1309.mix b/contrib/test/JDBC/input/BABEL-1309.mix new file mode 100644 index 00000000000..26a4356fafa --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1309.mix @@ -0,0 +1,32 @@ +-- tsql +exec sp_updatestats; +go + +exec sp_updatestats 'no'; +go + +exec sp_updatestats 'resample'; +go + +exec sp_updatestats @resample='resample'; +go + +exec sp_updatestats resample; +go + +exec sp_updatestats @resample; +go + +exec sp_updatestats @resample='sdlfkjsdf'; +go + +exec sp_updatestats 'resdflskjf'; +go + +exec sp_updatestats @random_option='resample'; +go + +-- psql +-- Case when user other than database owner executes, it should throw error +call sys.sp_updatestats(); +go diff --git a/contrib/test/JDBC/input/BABEL-1311.sql b/contrib/test/JDBC/input/BABEL-1311.sql new file mode 100644 index 00000000000..73c699c030c --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1311.sql @@ -0,0 +1,118 @@ +create table babel_1311_t(c_w_id int, c_first int); +insert into babel_1311_t values (1, 1), (2, 2); +GO + +DECLARE c_byname CURSOR STATIC FOR +SELECT customer.c_first +FROM babel_1311_t AS customer WITH (INDEX = [customer_i2], repeatableread) +INNER JOIN babel_1311_t AS C_BAL WITH (INDEX = [customer_i1], repeatableread) +ON C_BAL.c_w_id = customer.c_w_id; + +DECLARE @var_c_w_id int; + +OPEN c_byname; +FETCH c_byname into @var_c_w_id; +PRINT '@var_c_w_id: ' + cast(@var_c_w_id as varchar(10)); +FETCH c_byname into @var_c_w_id; +PRINT '@var_c_w_id: ' + cast(@var_c_w_id as varchar(10)); +CLOSE c_byname; +DEALLOCATE c_byname; +go + +DECLARE cur1 cursor for ((((select c_w_id from babel_1311_t)))); +DECLARE @var_c_w_id int; + +OPEN cur1; +FETCH cur1 into @var_c_w_id; +PRINT '@var_c_w_id: ' + cast(@var_c_w_id as varchar(10)); +FETCH cur1 into @var_c_w_id; +PRINT '@var_c_w_id: ' + cast(@var_c_w_id as varchar(10)); +CLOSE cur1; +DEALLOCATE cur1; +go + +DECLARE cur1 cursor for with cte_a as (select c_w_id from babel_1311_t where c_w_id = 2) select * from cte_a; +DECLARE @var_c_w_id int; + +OPEN cur1; +FETCH cur1 into @var_c_w_id; +PRINT '@var_c_w_id: ' + cast(@var_c_w_id as varchar(10)); +CLOSE cur1; +DEALLOCATE cur1; +go + +create procedure babel_1311_proc as +begin + DECLARE c_byname CURSOR STATIC FOR + SELECT customer.c_first + FROM babel_1311_t AS customer WITH (INDEX = [customer_i2], repeatableread) + INNER JOIN babel_1311_t AS C_BAL WITH (INDEX = [customer_i1], repeatableread) + ON C_BAL.c_w_id = customer.c_w_id; + + DECLARE @var_c_w_id int; + + OPEN c_byname; + FETCH c_byname into @var_c_w_id; + PRINT '@var_c_w_id: ' + cast(@var_c_w_id as varchar(10)); + FETCH c_byname into @var_c_w_id; + PRINT '@var_c_w_id: ' + cast(@var_c_w_id as varchar(10)); + CLOSE c_byname; +end; +go + +exec babel_1311_proc; +go + +create procedure babel_1311_proc_multiple_parethesis as +begin + DECLARE cur1 cursor for ((((select c_w_id from babel_1311_t)))); + DECLARE @var_c_w_id int; + + OPEN cur1; + FETCH cur1 into @var_c_w_id; + PRINT '@var_c_w_id: ' + cast(@var_c_w_id as varchar(10)); + FETCH cur1 into @var_c_w_id; + PRINT '@var_c_w_id: ' + cast(@var_c_w_id as varchar(10)); + CLOSE cur1; +end; +go + +exec babel_1311_proc_multiple_parethesis; +go + +create procedure babel_1311_proc_multiple_parethesis_mismatch1 as +begin + DECLARE cur1 cursor for select c_w_id from babel_1311_t); +end; +go + +create procedure babel_1311_proc_multiple_parethesis_mismatch2 as +begin + DECLARE cur1 cursor for select (c_w_id from babel_1311_t)); +end; +go + +create procedure babel_1311_proc_with_clause as +begin + DECLARE cur1 cursor for with cte_a as (select c_w_id from babel_1311_t where c_w_id = 2) select * from cte_a; + DECLARE @var_c_w_id int; + + OPEN cur1; + FETCH cur1 into @var_c_w_id; + PRINT '@var_c_w_id: ' + cast(@var_c_w_id as varchar(10)); + CLOSE cur1; +end; +go + +exec babel_1311_proc_with_clause; +go + +drop procedure babel_1311_proc; +go +drop procedure babel_1311_proc_multiple_parethesis; +go +drop procedure babel_1311_proc_with_clause; +go + +drop table babel_1311_t; +go diff --git a/contrib/test/JDBC/input/BABEL-1319.sql b/contrib/test/JDBC/input/BABEL-1319.sql new file mode 100644 index 00000000000..ada3668e249 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1319.sql @@ -0,0 +1,30 @@ +CREATE TABLE [Item] ( + [_id] int NOT NULL IDENTITY, + [Name] nvarchar(max) NULL, + CONSTRAINT [PK_Item] PRIMARY KEY ([_id]) +) +GO + +CREATE TABLE [Tag] ( [_id] int NOT NULL IDENTITY, + [Label] nvarchar(max) NULL, + [Count] int NOT NULL, + [Item_id] int NOT NULL, + CONSTRAINT [PK_Tag] PRIMARY KEY ([_id]), + CONSTRAINT [FK_Tag_Item_Item_id] FOREIGN KEY ([Item_id]) REFERENCES [Item] ([_id]) ON DELETE CASCADE +) +GO + +CREATE INDEX [IX_Tag_Item_id] ON [Tag] ([Item_id]) +GO + +INSERT INTO [Item] ([Name]) +VALUES ('ItemOne') +GO + +DELETE FROM [Item] WHERE [Name] = 'ItemOne' +GO + +DROP TABLE [Tag] +GO +DROP TABLE [Item] +GO \ No newline at end of file diff --git a/contrib/test/JDBC/input/BABEL-1320.sql b/contrib/test/JDBC/input/BABEL-1320.sql new file mode 100644 index 00000000000..94c833b32e7 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1320.sql @@ -0,0 +1,46 @@ +USE master +GO + +CREATE SCHEMA tds72; +GO + +CREATE FUNCTION tds72.test_tds_72_date_datatypes(@a date) RETURNS date AS BEGIN RETURN @a; END; +GO + +DECLARE @a date = '2020-05-14'; +SELECT tds72.test_tds_72_date_datatypes(@a); +GO + +DROP FUNCTION tds72.test_tds_72_date_datatypes; +GO + +CREATE FUNCTION tds72.test_tds_72_date_datatypes(@a DATETIME2) RETURNS DATETIME2 AS BEGIN RETURN @a; END; +GO + +DECLARE @a DATETIME2 = '2016-10-23 12:45:37.333'; +SELECT tds72.test_tds_72_date_datatypes(@a); +GO + +DROP FUNCTION tds72.test_tds_72_date_datatypes; +GO + +CREATE FUNCTION tds72.test_tds_72_date_datatypes(@a DATETIMEOFFSET) RETURNS DATETIMEOFFSET AS BEGIN RETURN @a; END; +GO + +DECLARE @a DATETIMEOFFSET = '12-10-25 12:32:10 +01:00'; +SELECT tds72.test_tds_72_date_datatypes(@a); +GO + +DROP FUNCTION tds72.test_tds_72_date_datatypes; +GO + +CREATE FUNCTION tds72.test_tds_72_date_datatypes(@a TIME) RETURNS TIME AS BEGIN RETURN @a; END; +GO + +DECLARE @a TIME = '12:15:04.1237'; +SELECT tds72.test_tds_72_date_datatypes(@a); +GO + +DROP FUNCTION tds72.test_tds_72_date_datatypes; +DROP SCHEMA tds72; +GO diff --git a/contrib/test/JDBC/input/BABEL-1329.sql b/contrib/test/JDBC/input/BABEL-1329.sql new file mode 100644 index 00000000000..97786945ab3 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1329.sql @@ -0,0 +1,26 @@ +SELECT HASHBYTES('sha2_256', 'abc') +GO + +SELECT HASHBYTES('sha256', 'abc') +GO + +SELECT HASHBYTES('sha512', 'abc') +GO + +SELECT HASHBYTES('', '') +GO + +SELECT HASHBYTES('md5', 'abc') +GO + +SELECT HASHBYTES('sha2_512', 'abc') +GO + +SELECT HASHBYTES('md2', 'abc') +GO + +SELECT HASHBYTES('md4', 'abc') +GO + +SELECT HASHBYTES('asdf', 'asdf') +GO diff --git a/contrib/test/JDBC/input/BABEL-1331.sql b/contrib/test/JDBC/input/BABEL-1331.sql new file mode 100644 index 00000000000..140257b52b7 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1331.sql @@ -0,0 +1,16 @@ +create table t_babel_1331 (a int, b int); +insert into t_babel_1331 values (1, 1), (2, 2), (3, 3), (4, 4), (5, 5); +go + +declare cur cursor for select * from t_babel_1331 +open cur +fetch cur +fetch next from cur +fetch prior from cur +fetch last from cur +fetch first from cur +fetch absolute 2 from cur +fetch relative 2 from cur +close cur +deallocate cur +go diff --git a/contrib/test/JDBC/input/BABEL-1363.mix b/contrib/test/JDBC/input/BABEL-1363.mix new file mode 100644 index 00000000000..d1224cee39a --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1363.mix @@ -0,0 +1,32 @@ +-- NOTE: this test should not run in parallel due to DB config change. +GO + +-- tsql +-- VariableSetStmt doens't work in JDBC. use workaround +DECLARE @orig_force_parallel_mode varchar(10); +SET @orig_force_parallel_mode = (SELECT current_setting('force_parallel_mode')); + +SELECT 'enable force_parallel_mode' FROM (SELECT + set_config('force_parallel_mode', 'on', false)) sq; +GO + +-- tsql +create table babel_1363_t1 (a int); +insert into babel_1363_t1 values (1), (2), (3), (4), (5), (6); +GO + +-- psql currentSchema=master_dbo,public +explain (costs off) select * from babel_1363_t1; +GO + +-- tsql +select * from babel_1363_t1; +GO + +-- tsql +DECLARE @orig_force_parallel_mode varchar(10); +SET @orig_force_parallel_mode = (SELECT current_setting('force_parallel_mode')); +SELECT 'reset force_parallel_mode' FROM (SELECT + set_config('force_parallel_mode', @orig_force_parallel_mode, false)) sq; +GO + diff --git a/contrib/test/JDBC/input/BABEL-1381.sql b/contrib/test/JDBC/input/BABEL-1381.sql new file mode 100644 index 00000000000..a9151b5d219 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1381.sql @@ -0,0 +1,99 @@ +CREATE PROCEDURE p_babel_1381_tinyint (@a tinyint OUTPUT) AS +BEGIN + SET @a=42; + select @a as a; +END; +GO + +EXEC p_babel_1381_tinyint 1; +GO + +CREATE PROCEDURE p_babel_1381_nchar (@a nchar OUTPUT) AS +BEGIN + SET @a='helloworld'; + select @a as a; +END; +GO + +EXEC p_babel_1381_nchar 'a'; +GO + +CREATE PROCEDURE p_babel_1381_nchar_10 (@a nchar(10) OUTPUT) AS +BEGIN + SET @a='helloworld'; + select @a as a; +END; +GO + +EXEC p_babel_1381_nchar_10 'a'; +GO + +CREATE PROCEDURE p_babel_1381_varchar (@a varchar OUTPUT) AS +BEGIN + SET @a='helloworld'; + select @a as a; +END; +GO + +EXEC p_babel_1381_varchar 'a'; +GO + +CREATE PROCEDURE p_babel_1381_varchar_10 (@a varchar(10) OUTPUT) AS +BEGIN + SET @a='helloworld'; + select @a as a; +END; +GO + +EXEC p_babel_1381_varchar_10 'a'; +GO + +CREATE PROCEDURE p_babel_1381_nvarchar (@a nvarchar OUTPUT) AS +BEGIN + SET @a='helloworld'; + select @a as a; +END; +GO + +EXEC p_babel_1381_varchar 'a'; +GO + +CREATE PROCEDURE p_babel_1381_nvarchar_10 (@a nvarchar(10) OUTPUT) AS +BEGIN + SET @a='helloworld'; + select @a as a; +END; +GO + +EXEC p_babel_1381_nvarchar_10 'a'; +GO + +CREATE PROCEDURE p_babel_1381_binary (@a binary OUTPUT) AS +BEGIN + SET @a=0xabcdef; + select @a as a; +END; +GO + +EXEC p_babel_1381_binary 0x1; +GO + +CREATE PROCEDURE p_babel_1381_varbinary (@a varbinary OUTPUT) AS +BEGIN + SET @a=0xabcdef; + select @a as a; +END; +GO + +EXEC p_babel_1381_varbinary 0x1; +GO + +CREATE PROCEDURE p_babel_1381_varbinary_10 (@a varbinary(10) OUTPUT) AS +BEGIN + SET @a=0xabcdef; + select @a as a; +END; +GO + +EXEC p_babel_1381_varbinary_10 0x1; +GO diff --git a/contrib/test/JDBC/input/BABEL-1389.sql b/contrib/test/JDBC/input/BABEL-1389.sql new file mode 100644 index 00000000000..e7ef26232af --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1389.sql @@ -0,0 +1,36 @@ +-- Test @@OPTIONS value changes when unsetting/setting CONCAT_NULL_YIELDS_NULL +SELECT @@OPTIONS AS OriginalOptionsValue; +SET CONCAT_NULL_YIELDS_NULL OFF; +SELECT 'abc' + NULL AS ResultWhen_OFF, @@OPTIONS AS OptionsValueWhen_OFF; +GO + +SET CONCAT_NULL_YIELDS_NULL ON; +SELECT 'abc' + NULL AS ResultWhen_ON, @@OPTIONS AS OptionsValueWhen_ON; +GO + +-- Test @@OPTIONS value changes with the setting of other options +SET IMPLICIT_TRANSACTIONS ON; +SELECT @@OPTIONS; +SET IMPLICIT_TRANSACTIONS OFF; +GO + +SET ANSI_NULLS OFF; +SELECT @@OPTIONS; +SET ANSI_NULLS ON; +GO + +SET QUOTED_IDENTIFIER ON; +SELECT @@OPTIONS; +SET QUOTED_IDENTIFIER OFF; +GO + +SET NOCOUNT ON; +SELECT @@OPTIONS; +SET NOCOUNT OFF; +GO + +SET XACT_ABORT ON; +SELECT @@OPTIONS; +SET XACT_ABORT OFF; +GO + diff --git a/contrib/test/JDBC/input/BABEL-1400.sql b/contrib/test/JDBC/input/BABEL-1400.sql new file mode 100644 index 00000000000..91554706fb3 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1400.sql @@ -0,0 +1,53 @@ +-- BABEL-1400 +-- Test NCHAR/NCARCHAR/VARBINARY/CHAR/VARCHAR/BINARY parameter default length as a procedure parameter +CREATE PROCEDURE sp_test1 (@a nchar OUTPUT, @b nvarchar OUTPUT, @c varbinary OUTPUT, @d char OUTPUT, @e varchar OUTPUT, @f binary OUTPUT) AS BEGIN Select @a, @b, @c, @d, @e, @f; END; +GO +Declare @a nchar; Set @a = 'hello'; +Declare @b nvarchar; Set @b = 'world'; +Declare @c varbinary; Set @c = 0xABCD; +Declare @d char; Set @d = 'HELLO'; +Declare @e varchar; Set @e = 'WORLD'; +Declare @f binary; Set @f = 0x1234; +exec sp_test1 @a, @b, @c, @d, @e, @f; +GO + +CREATE PROCEDURE sp_test2 (@a nchar OUTPUT, @b nvarchar OUTPUT, @c varbinary OUTPUT, @d char OUTPUT, @e varchar OUTPUT, @f binary OUTPUT) AS BEGIN Select @a, @b, @c, @d, @e, @f; END; +GO +Declare @a nchar(2); Set @a = 'hello'; +Declare @b nvarchar(2); Set @b = 'world'; +Declare @c varbinary(2); Set @c = 0xABCD; +Declare @d char(2); Set @d = 'HELLO'; +Declare @e varchar(2); Set @e = 'WORLD'; +Declare @f binary(2); Set @f = 0x1234; +exec sp_test2 @a, @b, @c, @d, @e, @f; +GO + +CREATE PROCEDURE sp_test3 (@a nchar(2) OUTPUT, @b nvarchar(2) OUTPUT, @c varbinary(2) OUTPUT, @d char(2) OUTPUT, @e varchar(2) OUTPUT, @f binary(2) OUTPUT) AS BEGIN Select @a, @b, @c, @d, @e, @f; END; +GO +Declare @a nchar(2); Set @a = 'hello'; +Declare @b nvarchar(2); Set @b = 'world'; +Declare @c varbinary(2); Set @c = 0xABCD; +Declare @d char(2); Set @d = 'HELLO'; +Declare @e varchar(2); Set @e = 'WORLD'; +Declare @f binary(2); Set @f = 0x1234; +exec sp_test3 @a, @b, @c, @d, @e, @f; +GO + +-- Test changing parameter value inside procedure +CREATE PROCEDURE sp_test4 (@a nchar OUTPUT, @b nvarchar OUTPUT, @c varbinary OUTPUT, @d char OUTPUT, @e varchar OUTPUT, @f binary OUTPUT) AS BEGIN SET @a = 'world'; SET @b = 'hello'; SET @c = 0x1234; SET @d = 'WORLD'; SET @e = 'HELLO'; SET @f = 0xABCD; Select @a, @b, @c, @d, @e, @f; END; +GO +Declare @a nchar; Set @a = 'hello'; +Declare @b nvarchar; Set @b = 'world'; +Declare @c varbinary; Set @c = 0xABCD; +Declare @d char; Set @d = 'HELLO'; +Declare @e varchar; Set @e = 'WORLD'; +Declare @f binary; Set @f = 0x1234; +exec sp_test4 @a, @b, @c, @d, @e, @f; +GO + +-- Clean up +DROP PROCEDURE sp_test1; +DROP PROCEDURE sp_test2; +DROP PROCEDURE sp_test3; +DROP PROCEDURE sp_test4; +GO diff --git a/contrib/test/JDBC/input/BABEL-1435.sql b/contrib/test/JDBC/input/BABEL-1435.sql new file mode 100644 index 00000000000..722e7f22d00 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1435.sql @@ -0,0 +1,112 @@ +-- Test inital databases +SELECT name FROM sys.sysdatabases ORDER BY name; +GO + +SELECT COUNT(*) FROM pg_roles where rolname = 'sysadmin'; +GO + +SELECT COUNT(*) FROM pg_roles where rolname = 'master_dbo'; +SELECT COUNT(*) FROM pg_roles where rolname = 'master_db_owner'; +SELECT COUNT(*) FROM pg_namespace where nspname = 'master_dbo'; +GO + +SELECT COUNT(*) FROM pg_roles where rolname = 'tempdb_dbo'; +SELECT COUNT(*) FROM pg_roles where rolname = 'tempdb_db_owner'; +SELECT COUNT(*) FROM pg_namespace where nspname = 'tempdb_dbo'; +GO + +-- Test Create User Database +CREATE DATABASE db1; +GO + +SELECT name FROM sys.sysdatabases ORDER BY name; +GO + +-- test error +CREATE DATABASE db1; +GO + +SELECT COUNT(*) FROM pg_roles where rolname = 'dbo'; +SELECT COUNT(*) FROM pg_roles where rolname = 'db_owner'; +SELECT COUNT(*) FROM pg_namespace where nspname = 'dbo'; +GO + +CREATE DATABASE db2; +GO + +USE db1; +GO + +SELECT (case when db_id() = db_id('db1') then 'true' else 'false' end) result; +GO + +USE master; +GO + +SELECT (case when db_id() = db_id('master') then 'true' else 'false' end) result; +GO + +-- test error +USE db2; +GO + +DROP DATABASE db1; +GO + +-- Set current_user for testing db mode +IF (SELECT 1 FROM pg_roles WHERE rolname='jdbc_user') = 1 +BEGIN + WITH SET_CTE + AS + (SELECT set_config('role', 'jdbc_user', false)) + SELECT NULL + FROM SET_CTE +END +ELSE +BEGIN + WITH SET_CTE + AS + (SELECT set_config('role', 'babeltestuser', false)) + SELECT NULL + FROM SET_CTE +END +GO + +-- test multi-db mode +SELECT set_config('babelfishpg_tsql.migration_mode', 'multi-db', false); +GO + +SELECT name FROM sys.sysdatabases ORDER BY name; +GO + +CREATE DATABASE db1; +GO + +-- test error +CREATE DATABASE db1; +GO + +CREATE DATABASE db2; +GO + +SELECT COUNT(*) FROM pg_roles where rolname = 'db1_dbo'; +SELECT COUNT(*) FROM pg_roles where rolname = 'db1_db_owner'; +SELECT COUNT(*) FROM pg_namespace where nspname = 'db1_dbo'; +GO + +SELECT COUNT(*) FROM pg_roles where rolname = 'db2_dbo'; +SELECT COUNT(*) FROM pg_roles where rolname = 'db2_db_owner'; +SELECT COUNT(*) FROM pg_namespace where nspname = 'db2_dbo'; +GO + +DROP DATABASE db1; +GO + +DROP DATABASE db2; +GO + +SELECT name FROM sys.sysdatabases ORDER BY name; +GO + +SELECT set_config('babelfishpg_tsql.migration_mode', 'single-db', false); +GO diff --git a/contrib/test/JDBC/input/BABEL-1437.sql b/contrib/test/JDBC/input/BABEL-1437.sql new file mode 100644 index 00000000000..cdf75e5c288 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1437.sql @@ -0,0 +1,46 @@ +-- Test unexist db, expecting null +SELECT db_id('hello'); +SELECT db_name(1234); +GO + +-- Test master and tempdb +SELECT db_id('master'); +SELECT db_name(1); +GO + +USE master; +GO + +SELECT db_id(); +SELECT db_name(); +GO + +SELECT db_id('tempdb') +SELECT db_name(2); +GO + +USE tempdb; +GO +SELECT db_id(); +SELECT db_name(); +GO + +-- Test custom database +CREATE DATABASE babel_1437_db; +GO +USE babel_1437_db; +GO + +SELECT (case when db_name() = 'babel_1437_db' then 'true' else 'false' end) result; +SELECT (case when db_name(db_id()) = 'babel_1437_db' then 'true' else 'false' end) result; +SELECT (case when db_id('babel_1437_db') = db_id() then 'true' else 'false' end) result; +GO + +-- test dropped database, expecting db_id to return null +USE MASTER; +GO + +DROP DATABASE babel_1437_db; +GO +SELECT db_id('babel_1437_db'); +GO diff --git a/contrib/test/JDBC/input/BABEL-1438.sql b/contrib/test/JDBC/input/BABEL-1438.sql new file mode 100644 index 00000000000..18ccec49fc2 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1438.sql @@ -0,0 +1,3 @@ +-- Test with unexist db as param +EXEC sp_helpdb 'hello' +GO diff --git a/contrib/test/JDBC/input/BABEL-1442.sql b/contrib/test/JDBC/input/BABEL-1442.sql new file mode 100644 index 00000000000..c8e89bc582d --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1442.sql @@ -0,0 +1,253 @@ +-- Test syntax without escape hatches +CREATE LOGIN r1 WITH PASSWORD = 'abc' MUST_CHANGE, CHECK_EXPIRATION = ON; +GO + +CREATE LOGIN r2 WITH PASSWORD = '123', CREDENTIAL = cred1; +GO + +CREATE LOGIN r3 FROM CERTIFICATE cert1; +GO + +CREATE LOGIN r4 FROM WINDOWS; +GO + +CREATE LOGIN r5 WITH PASSWORD = 'xyz', SID = 0x123ABC; +GO + +CREATE LOGIN r6 +WITH PASSWORD = '1000101', +DEFAULT_DATABASE = master, +CHECK_POLICY = OFF, +CHECK_EXPIRATION = OFF; +GO + +CREATE LOGIN r7 +WITH PASSWORD = 0x789DEF HASHED MUST_CHANGE, +DEFAULT_LANGUAGE = english, +CREDENTIAL = cred2; +GO + +CREATE LOGIN r8 +FROM WINDOWS +WITH DEFAULT_DATABASE = db2, +DEFAULT_LANGUAGE = English; +GO + +CREATE LOGIN r9 FROM ASYMMETRIC KEY asymkey1; +GO + +CREATE LOGIN r10 WITH PASSWORD = N'abc', CHECK_EXPIRATION = ON; +GO + +CREATE LOGIN r10 WITH PASSWORD = N'abc', CREDENTIAL = cred; +GO + +-- Test ALTER LOGIN syntax without escape hatches +ALTER LOGIN r1 WITH PASSWORD = '123' OLD_PASSWORD = 'abc'; +GO + +ALTER LOGIN r1 WITH PASSWORD = 0xABC123 HASHED MUST_CHANGE UNLOCK; +GO + +ALTER LOGIN r1 WITH PASSWORD = '123' MUST_CHANGE; +GO + +ALTER LOGIN r1 WITH PASSWORD = '123' UNLOCK; +GO + +ALTER LOGIN r1 WITH DEFAULT_LANGUAGE = english, +NAME = r5, +CHECK_POLICY = ON, +CHECK_EXPIRATION = ON, +NO CREDENTIAL; +GO + +ALTER LOGIN r1 WITH DEFAULT_LANGUAGE = english, +CHECK_POLICY = ON, +CHECK_EXPIRATION = ON, +NO CREDENTIAL; +GO + +ALTER LOGIN r1 WITH DEFAULT_LANGUAGE = english, +CHECK_EXPIRATION = ON, +NO CREDENTIAL; +GO + +ALTER LOGIN r1 WITH DEFAULT_LANGUAGE = english, +NO CREDENTIAL; +GO + +ALTER LOGIN r2 WITH PASSWORD = 'abc', +CREDENTIAL = cred1; +GO + +ALTER LOGIN r3 ADD CREDENTIAL cred2; +GO + +ALTER LOGIN r3 DROP CREDENTIAL cred2; +GO + +-- Test syntax with escape hatches +SELECT set_config('babelfishpg_tsql.escape_hatch_login_hashed_password', 'ignore', 'false') +GO +SELECT set_config('babelfishpg_tsql.escape_hatch_login_old_password', 'ignore', 'false') +GO +SELECT set_config('babelfishpg_tsql.escape_hatch_login_password_must_change', 'ignore', 'false') +GO +SELECT set_config('babelfishpg_tsql.escape_hatch_login_password_unlock', 'ignore', 'false') +GO +SELECT set_config('babelfishpg_tsql.escape_hatch_login_misc_options', 'ignore', 'false') +GO + +CREATE LOGIN r1 WITH PASSWORD = 'abc' MUST_CHANGE, CHECK_EXPIRATION = ON; +GO + +SELECT default_database_name FROM sys.server_principals WHERE name = 'r1'; +GO + +SELECT sys.babelfish_get_login_default_db('r1'); +GO + +CREATE LOGIN r2 WITH PASSWORD = '123', CREDENTIAL = cred1; +GO + +CREATE LOGIN r3 FROM CERTIFICATE cert1; +GO + +CREATE LOGIN r4 FROM WINDOWS; +GO + +CREATE LOGIN r5 WITH PASSWORD = 'xyz', SID = 0x123ABC; +GO + +CREATE LOGIN r6 +WITH PASSWORD = '1000101', +DEFAULT_DATABASE = master, +CHECK_POLICY = OFF, +CHECK_EXPIRATION = OFF; +GO + +SELECT default_database_name FROM sys.server_principals WHERE name = 'r6'; +GO + +SELECT sys.babelfish_get_login_default_db('r6'); +GO + +CREATE LOGIN r7 +WITH PASSWORD = 0x789DEF HASHED MUST_CHANGE, +DEFAULT_LANGUAGE = english, +CREDENTIAL = cred2; +GO + +CREATE LOGIN r8 +FROM WINDOWS +WITH DEFAULT_DATABASE = db2, +DEFAULT_LANGUAGE = English; +GO + +CREATE LOGIN r9 FROM ASYMMETRIC KEY asymkey1; +GO + +CREATE LOGIN r10 WITH PASSWORD = N'abc'; +GO + +CREATE LOGIN r11 WITH PASSWORD = N'abc' MUST_CHANGE, CHECK_EXPIRATION = ON; +GO + +-- Test ALTER syntax +ALTER LOGIN r1 ENABLE; +GO + +ALTER LOGIN r1 DISABLE; +GO + +ALTER LOGIN r1 WITH PASSWORD = '123'; +GO + +ALTER LOGIN r1 WITH PASSWORD = '123' OLD_PASSWORD = 'abc'; +GO + +ALTER LOGIN r1 WITH PASSWORD = 0xABC123 HASHED MUST_CHANGE UNLOCK; +GO + +ALTER LOGIN r1 WITH DEFAULT_DATABASE = tempdb; +GO + +SELECT default_database_name FROM sys.server_principals WHERE name = 'r1'; +GO + +SELECT sys.babelfish_get_login_default_db('r1'); +GO + +ALTER LOGIN r1 WITH DEFAULT_LANGUAGE = english, +NAME = r10, +CHECK_POLICY = ON, +CHECK_EXPIRATION = ON, +NO CREDENTIAL; +GO + +ALTER LOGIN r2 WITH PASSWORD = 'abc' UNLOCK, +DEFAULT_LANGUAGE = english, +NAME = r10, +CHECK_POLICY = ON, +CHECK_EXPIRATION = ON, +CREDENTIAL = cred1; +GO + +ALTER LOGIN r3 ADD CREDENTIAL cred2; +GO + +ALTER LOGIN r3 DROP CREDENTIAL cred2; +GO + +ALTER LOGIN r10 WITH PASSWORD = N'123'; +GO + +ALTER LOGIN r11 WITH PASSWORD = N'123' OLD_PASSWORD = N'abc'; +GO + +SELECT set_config('babelfishpg_tsql.escape_hatch_login_hashed_password', 'strict', 'false') +GO +SELECT set_config('babelfishpg_tsql.escape_hatch_login_old_password', 'strict', 'false') +GO +SELECT set_config('babelfishpg_tsql.escape_hatch_login_password_must_change', 'strict', 'false') +GO +SELECT set_config('babelfishpg_tsql.escape_hatch_login_password_unlock', 'strict', 'false') +GO +SELECT set_config('babelfishpg_tsql.escape_hatch_login_misc_options', 'strict', 'false') +GO + +-- Expect errors. Try creating login with non-existent db +CREATE LOGIN r12 WITH PASSWORD = '123', +DEFAULT_DATABASE = zzz; +GO + +ALTER LOGIN r1 WITH DEFAULT_DATABASE = zzz; +GO + +-- Clean up +DROP LOGIN r1; +GO +DROP LOGIN r2; +GO +DROP LOGIN r3; +GO +DROP LOGIN r4; +GO +DROP LOGIN r5; +GO +DROP LOGIN r6; +GO +DROP LOGIN r7; +GO +DROP LOGIN r8; +GO +DROP LOGIN r9; +GO +DROP LOGIN r10; +GO +DROP LOGIN r11; +GO + +SELECT sys.babelfish_get_login_default_db('r1'); +GO diff --git a/contrib/test/JDBC/input/BABEL-1444.sql b/contrib/test/JDBC/input/BABEL-1444.sql new file mode 100644 index 00000000000..5ab60ceaa63 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1444.sql @@ -0,0 +1,110 @@ +USE MASTER; +GO + +DECLARE @usr CHAR(30) +DECLARE @cur_usr CHAR(30) +SET @usr = user +SET @cur_usr = current_user +SELECT 'user: '+ @usr +SELECT 'current_user: '+ @cur_usr +GO + +CREATE TABLE dbo.t1 +(id INT IDENTITY(100, 1) NOT NULL, + description VARCHAR(30) NOT NULL, + usr VARCHAR(30) NOT NULL DEFAULT USER, + cur_usr VARCHAR(30) NOT NULL DEFAULT CURRENT_USER); +GO + +INSERT INTO dbo.t1 (description) VALUES ('Orange'); +INSERT INTO dbo.t1 (description) VALUES ('Blue'); +INSERT INTO dbo.t1 (description, usr) VALUES ('Green', 'Bob'); +INSERT INTO dbo.t1 (description, cur_usr) VALUES ('Purple', 'Alice'); +INSERT INTO dbo.t1 (description, usr, cur_usr) VALUES ('Red', 'Mike', 'Dave'); +GO + +SELECT * FROM dbo.t1 ORDER BY id; +GO + +DROP TABLE dbo.t1; +GO + +-- Test properties after USE +CREATE DATABASE db1; +GO + +SELECT current_setting('role'); +GO +SELECT current_setting('search_path'); +GO +SELECT session_user, current_user, user; +GO +SELECT user_name(); +GO + +USE db1; +GO + +SELECT current_setting('role'); +GO +SELECT current_setting('search_path'); +GO +SELECT session_user, current_user, user; +GO +SELECT user_name(); +GO + +-- Error: Test DROP +DROP DATABASE db1; +GO + +SELECT current_setting('role'); +GO +SELECT current_setting('search_path'); +GO +SELECT session_user, current_user, user; +GO +SELECT user_name(); +GO + +-- Test DROP when using another database +USE MASTER; +GO + +SELECT current_setting('role'); +GO +SELECT current_setting('search_path'); +GO +SELECT session_user, current_user, user; +GO +SELECT user_name(); +GO + +DROP DATABASE db1; +GO + +SELECT current_setting('role'); +GO +SELECT current_setting('search_path'); +GO +SELECT session_user, current_user, user; +GO +SELECT user_name(); +GO + +-- Test CREATE +CREATE DATABASE db1; +GO + +SELECT current_setting('role'); +GO +SELECT current_setting('search_path'); +GO +SELECT session_user, current_user, user; +GO +SELECT user_name(); +GO + +-- Clean up +DROP DATABASE db1; +GO diff --git a/contrib/test/JDBC/input/BABEL-1446.sql b/contrib/test/JDBC/input/BABEL-1446.sql new file mode 100644 index 00000000000..9603dd2cccf --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1446.sql @@ -0,0 +1,93 @@ +SELECT COUNT(*) FROM pg_auth_members +WHERE roleid = (SELECT oid FROM pg_roles WHERE rolname = 'guest') +AND "member" = (SELECT oid FROM pg_roles WHERE rolname = 'db_owner'); +GO + +CREATE DATABASE db1; +GO + +SELECT COUNT(*) FROM pg_auth_members +WHERE roleid = (SELECT oid FROM pg_roles WHERE rolname = 'guest') +AND "member" = (SELECT oid FROM pg_roles WHERE rolname = 'db_owner'); +GO + +CREATE LOGIN login1 WITH PASSWORD = '123'; +GO + +SELECT COUNT(*) FROM pg_auth_members +WHERE roleid = (SELECT oid FROM pg_roles WHERE rolname = 'guest') +AND "member" = (SELECT oid FROM pg_roles WHERE rolname = 'login1'); +GO + +CREATE LOGIN login2 WITH PASSWORD = 'abc'; +GO + +SELECT COUNT(*) FROM pg_auth_members +WHERE roleid = (SELECT oid FROM pg_roles WHERE rolname = 'guest') +AND "member" = (SELECT oid FROM pg_roles WHERE rolname = 'login2'); +GO + +DROP LOGIN login1; +GO + +SELECT COUNT(*) FROM pg_auth_members +WHERE roleid = (SELECT oid FROM pg_roles WHERE rolname = 'guest') +AND "member" = (SELECT oid FROM pg_roles WHERE rolname = 'login1'); +GO + +DROP LOGIN login2; +GO + +SELECT COUNT(*) FROM pg_auth_members +WHERE roleid = (SELECT oid FROM pg_roles WHERE rolname = 'guest') +AND "member" = (SELECT oid FROM pg_roles WHERE rolname = 'login2'); +GO + +DROP DATABASE db1; +GO + +SELECT COUNT(*) FROM pg_auth_members +WHERE roleid = (SELECT oid FROM pg_roles WHERE rolname = 'guest') +AND "member" = (SELECT oid FROM pg_roles WHERE rolname = 'db_owner'); +GO + +-- test multi-db mode +SELECT set_config('role', 'jdbc_user', false); +GO +SELECT set_config('babelfishpg_tsql.migration_mode', 'multi-db', false); +GO + +CREATE DATABASE db1; +GO + +SELECT COUNT(*) FROM pg_auth_members +WHERE roleid = (SELECT oid FROM pg_roles WHERE rolname = 'db1_guest') +AND "member" = (SELECT oid FROM pg_roles WHERE rolname = 'db1_db_owner'); +GO + +CREATE DATABASE db2; +GO + +SELECT COUNT(*) FROM pg_auth_members +WHERE roleid = (SELECT oid FROM pg_roles WHERE rolname = 'db2_guest') +AND "member" = (SELECT oid FROM pg_roles WHERE rolname = 'db2_db_owner'); +GO + +DROP DATABASE db1; +GO + +SELECT COUNT(*) FROM pg_auth_members +WHERE roleid = (SELECT oid FROM pg_roles WHERE rolname = 'db1_guest') +AND "member" = (SELECT oid FROM pg_roles WHERE rolname = 'db1_db_owner'); +GO + +DROP DATABASE db2; +GO + +SELECT COUNT(*) FROM pg_auth_members +WHERE roleid = (SELECT oid FROM pg_roles WHERE rolname = 'db2_guest') +AND "member" = (SELECT oid FROM pg_roles WHERE rolname = 'db2_db_owner'); +GO + +SELECT set_config('babelfishpg_tsql.migration_mode', 'single-db', false); +GO diff --git a/contrib/test/JDBC/input/BABEL-1454.mix b/contrib/test/JDBC/input/BABEL-1454.mix new file mode 100644 index 00000000000..d127173c5e4 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1454.mix @@ -0,0 +1,273 @@ +-- psql +ALTER SYSTEM SET babelfishpg_tsql.migration_mode = 'multi-db'; +ALTER SYSTEM SET babelfishpg_tsql.allow_antlr_to_unsupported_grammar_for_testing = true; +SELECT pg_reload_conf(); +GO + +-- tsql +CREATE DATABASE db1; +GO + +USE db1; +GO + +-- Create Basic Table +CREATE SCHEMA babel1454; +GO + +SELECT nspname FROM pg_namespace WHERE nspname = 'db1_babel1454'; +GO + +CREATE TABLE babel1454.t1 ( a int, b int ); +GO + + +-- Test Insert + +INSERT INTO db1.babel1454.t1 VALUES ( 1, 2); +GO + +INSERT INTO babel1454.t1 VALUES (2, 3); +GO + +INSERT INTO babel1454.t1 SELECT a + 10, b + 10 from db1.babel1454.t1; +GO + +SELECT * FROM db1.babel1454.t1 ORDER BY 1,2; +GO + +-- Test Delete +DELETE FROM db1.babel1454.t1 where babel1454.t1.b = 2; +GO + +DELETE FROM babel1454.t1 where db1.babel1454.t1.a = 2; +GO + +SELECT * FROM db1.babel1454.t1 ORDER BY 1,2; +GO + +-- Test Update +UPDATE babel1454.t1 SET a = babel1454.t1.a - 10, b = b - 10 WHERE db1.babel1454.t1.b = 12; +GO + +UPDATE babel1454.t1 SET a = db1.babel1454.t1.a - 10, b = db1.babel1454.t1.b - 10 WHERE babel1454.t1.b = 13; +GO + +SELECT * FROM db1.babel1454.t1 ORDER BY 1,2; +GO + +-- Test Select +SELECT db1.babel1454.t1.a , babel1454.t1.b FROM babel1454.t1 ORDER BY babel1454.t1.a, db1.babel1454.t1.b; +GO + +WITH cte as ( +SELECT db1.babel1454.t1.a , babel1454.t1.b FROM babel1454.t1 ORDER BY babel1454.t1.a, db1.babel1454.t1.b +) +SELECT * FROM cte; +GO + +SELECT distinct(db1.babel1454.t1.a) FROM babel1454.t1 ORDER BY 1; +GO + +SELECT sum(db1.babel1454.t1.a) FROM babel1454.t1 GROUP BY babel1454.t1.b ORDER BY 1; +GO + +SELECT COUNT(*) FROM db1.babel1454.t1 inner join babel1454.t1 as t2 on db1.babel1454.t1.a = t2.a; +GO + +-- Alter table stmt +ALTER TABLE db1.babel1454.t1 ADD c int; +GO + +ALTER TABLE babel1454.t1 ADD d int; +GO + +-- CRANT (error message will tell if mapping is correct ) +GRANT ALL ON db1.babel1454.t2 TO PUBLIC; +GO + +GRANT ALL ON babel1454.t2 TO PUBLIC; +GO + +GRANT ALL ON db1.babel1454.foo TO PUBLIC; +GO + +GRANT ALL ON babel1454.foo TO PUBLIC; +GO + +GRANT ALL ON db1.babel1454.foo TO PUBLIC; +GO + +GRANT ALL ON babel1454.foo TO PUBLIC; +GO + +GRANT ALL ON dummy_schema TO PUBLIC; +GO + +GRANT ALL ON db1.dummy_schema TO PUBLIC; +GO + +GRANT ALL ON babel1454.dummy_type TO PUBLIC; +GO + +GRANT ALL ON db1.babel1454.dummy_type TO PUBLIC; +GO + +--GRANT ALL ON ALL TABLES IN SCHEMA dummy_schema TO DUMMY; +--GO + +-- DROP stmt +DROP TABLE db1.dummy_schema.t2; +GO + +DROP TABLE dummy_schema.t2; +GO + +DROP SCHEMA dummy_schema; +GO + +-- Trigger +CREATE TRIGGER tri on db1.babel1454.t1 AFTER INSERT +AS BEGIN +END; +GO + +CREATE TRIGGER tri2 on babel1454.t1 AFTER INSERT +AS BEGIN +END; +GO + +DROP TRIGGER babel1454.tri; +GO + +DROP TRIGGER babel1454.tri2; +GO + +-- Truncate +TRUNCATE TABLE db1.babel1454.t1; +GO + +TRUNCATE TABLE babel1454.t1; +GO + +-- Index +CREATE INDEX babel1454_t1_i1 ON db1.babel1454.t1 ( a , b ); +GO + +CREATE INDEX babel1454_t1_i2 ON db1.babel1454.t1 ( a ); +GO + +-- Create Function + +-- CREATE FUNCTION doesn't allow to use [dbname]. +--CREATE FUNCTION db1.babel1454.foo() RETURNS INT AS BEGIN RETURN 0; END +--GO + +CREATE FUNCTION babel1454.foo2() RETURNS INT AS BEGIN RETURN 0; END +GO + +-- ALTER FUNCTION doesn't allow to use [dbname]. +--ALTER FUNCTION db1.babel1454.foo2() IMMUTABLE; +--GO + +-- We don't support T-SQL ALTER FUNCTION properly +--ALTER FUNCTION babel1454.foo() IMMUTABLE; +--GO + +-- DROP FUNCTION doesn't allow to use [dbname]. +--DROP FUNCTION db1.babel1454.foo(); +--GO + +DROP FUNCTION babel1454.foo2; +GO + +-- Rename +-- ALTER ... RENAME is not valid in T-SQL + +--ALTER FUNCTION db1.dummy.foo() RENAME TO foo2; +--GO + +--ALTER FUNCTION dummy.foo RENAME TO foo2; +--GO + +--ALTER SCHEMA dummy RENAME TO DUMMY2; +--GO + +--ALTER TABLE db1.dummy.t1 RENAME TO dummy; +--GO + +--ALTER TABLE dummy.t1 RENAME TO dummy; +--GO + +-- Create View +CREATE VIEW babel1454.v1 AS SELECT db1.babel1454.t1.b from babel1454.t1; +GO + +DROP VIEW babel1454.v1; +GO + +-- CREATE SEQUENCE doesn't allow to use [dbname]. +--CREATE SEQUENCE db1.babel1454.seq1; +--GO + +CREATE SEQUENCE babel1454.seq2; +GO + +-- ALTER SEQUENCE doesn't allow to use [dbname]. +--ALTER SEQUENCE db1.babel1454.seq2 RESTART WITH 2; +--GO + +ALTER SEQUENCE babel1454.seq2 RESTART WITH 2; +GO + +-- Alter owner +-- ALTER ... OWNER is not valid in T-SQL + +--ALTER PROCEDURE db1.dummy.foo() OWNER TO DUMMY; +--GO + +--ALTER PROCEDURE dummy.foo OWNER TO DUMMY; +--GO + +--ALTER TABLE dummy.foo OWNER TO DUMMY; +--GO + +--ALTER TABLE db1.dummy.foo OWNER TO DUMMY; +--GO + +--ALTER SCHEMA dummy2 OWNER TO jdbc_test; +--GO + +-- Create Statistics +-- CREATE STATISTICS in T-SQL and postgres is not compatible + +--CREATE STATISTICS mystat ON a,b FROM db1.dummy.t1; +--GO + +--CREATE STATISTICS mystat2 ON b,b FROM dummy.t1; +--GO + +-- CALL +EXEC dummy.foo +GO + +EXEC db1.dummy.foo +GO + +--- Cleanup +DROP TABLE babel1454.t1; +DROP SEQUENCE babel1454.seq2; +DROP SCHEMA babel1454; +GO + +USE MASTER; +GO + +DROP DATABASE db1; +GO + +-- psql +ALTER SYSTEM SET babelfishpg_tsql.migration_mode = 'single-db'; +ALTER SYSTEM SET babelfishpg_tsql.allow_antlr_to_unsupported_grammar_for_testing = false; +SELECT pg_reload_conf(); +GO diff --git a/contrib/test/JDBC/input/BABEL-1465.sql b/contrib/test/JDBC/input/BABEL-1465.sql new file mode 100644 index 00000000000..61becb2a4a3 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1465.sql @@ -0,0 +1,258 @@ +-- BABEL-1645 +-- CAST is VOLATILE if one of these conditions exists: +-- 1. Source type is sql_variant. +-- 2. Target type is sql_variant and its source type is nondeterministic. +-- 3. Source or target type is datetime/datetime2/smalldatetime, the other source or target type is a character string/sql_variant/other datetime types. + +-- VOLATILE functions can not be used to generate persisted computed columns, the following +-- tests are based on this rule. + +create table t1 (id int, a varchar(10)); +GO + +-- CAST from char to varchar is immutable/deterministic and can be used to generate computed column +alter table t1 add b as cast(cast('01-01-2012' as char(10)) as varchar(10)) persisted; +GO + +-- CAST from sql_variant to other type is VOLATILE and is not allowed to generate computed column +alter table t1 add c as cast(cast('01-01-2012' as sql_variant) as varchar(10)) persisted; +GO + +-- CAST to sql_variant from VOLATILE source type is also VOLATILE +alter table t1 add c as cast(GETDATE() as sql_variant) persisted; +GO + +-- CAST to sql_variant from datetime is VOLATILE +alter table t1 add c as cast(cast('01-01-2012' as datetime) as sql_variant) persisted; +GO + +-- CAST to sql_variant from smalldatetime is VOLATILE +alter table t1 add c as cast(cast('01-01-2012' as smalldatetime) as sql_variant) persisted; +GO + +-- CAST from datetime/datetime2/smalldatetime to character string type/other datetime typee is VOLATILE +alter table t1 add c as cast(cast('01-01-2012' as datetime) as varchar(10)) persisted; +GO + +alter table t1 add c as cast(cast('01-01-2012' as datetime) as nvarchar(10)) persisted; +GO + +alter table t1 add c as cast(cast('01-01-2012' as datetime) as char(10)) persisted; +GO + +alter table t1 add c as cast(cast('01-01-2012' as datetime) as nchar(10)) persisted; +GO + +alter table t1 add c as cast(cast('01-01-2012' as datetime) as date) persisted; +GO + +alter table t1 add c as cast(cast('01:01' as datetime) as time) persisted; +GO + +alter table t1 add c as cast(cast('01-01-2012' as datetime2) as varchar(10)) persisted; +GO + +alter table t1 add c as cast(cast('01-01-2012' as datetime2) as nvarchar(10)) persisted; +GO + +alter table t1 add c as cast(cast('01-01-2012' as datetime2) as char(10)) persisted; +GO + +alter table t1 add c as cast(cast('01-01-2012' as datetime2) as nchar(10)) persisted; +GO + +alter table t1 add c as cast(cast('01-01-2012' as datetime2) as date) persisted; +GO + +alter table t1 add c as cast(cast('01:01' as datetime2) as time) persisted; +GO + +alter table t1 add c as cast(cast('01-01-2012' as smalldatetime) as varchar(10)) persisted; +GO + +alter table t1 add c as cast(cast('01-01-2012' as smalldatetime) as nvarchar(10)) persisted; +GO + +alter table t1 add c as cast(cast('01-01-2012' as smalldatetime) as char(10)) persisted; +GO + +alter table t1 add c as cast(cast('01-01-2012' as smalldatetime) as nchar(10)) persisted; +GO + +alter table t1 add c as cast(cast('01-01-2012' as smalldatetime) as date) persisted; +GO + +alter table t1 add c as cast(cast('01:01' as smalldatetime) as time) persisted; +GO + +-- CAST to datetime/datetime2/smalldatetime from character string type/datetime type is VOLATILE +alter table t1 add c as cast(cast('01-01-2012' as varchar(10)) as datetime) persisted; +GO + +alter table t1 add c as cast(cast('01-01-2012' as nvarchar(10)) as datetime) persisted; +GO + +alter table t1 add c as cast(cast('01-01-2012' as char(10)) as datetime) persisted; +GO + +alter table t1 add c as cast(cast('01-01-2012' as nchar(10)) as datetime) persisted; +GO + +alter table t1 add c as cast(cast('01-01-2012' as date) as datetime) persisted; +GO + +alter table t1 add c as cast(cast('01:01' as time) as datetime) persisted; +GO + +alter table t1 add c as cast(cast('01-01-2012' as varchar(10)) as datetime2) persisted; +GO + +alter table t1 add c as cast(cast('01-01-2012' as nvarchar(10)) as datetime2) persisted; +GO + +alter table t1 add c as cast(cast('01-01-2012' as char(10)) as datetime2) persisted; +GO + +alter table t1 add c as cast(cast('01-01-2012' as nchar(10)) as datetime2) persisted; +GO + +alter table t1 add c as cast(cast('01-01-2012' as date) as datetime2) persisted; +GO + +alter table t1 add c as cast(cast('01:01' as time) as datetime2) persisted; +GO + +alter table t1 add c as cast(cast('01-01-2012' as varchar(10)) as smalldatetime) persisted; +GO + +alter table t1 add c as cast(cast('01-01-2012' as nvarchar(10)) as smalldatetime) persisted; +GO + +alter table t1 add c as cast(cast('01-01-2012' as char(10)) as smalldatetime) persisted; +GO + +alter table t1 add c as cast(cast('01-01-2012' as nchar(10)) as smalldatetime) persisted; +GO + +alter table t1 add c as cast(cast('01-01-2012' as date) as smalldatetime) persisted; +GO + +alter table t1 add c as cast(cast('01:01' as time) as smalldatetime) persisted; +GO + +-- Test cast between datetime/smalldatetime and varchar/nvarchar/char/nchar since we +-- added the cast functions in this patch +select cast(cast('01-01-2012' as datetime) as varchar(10)); +GO +select cast(cast('01-01-2012' as datetime) as varchar(5)); +GO + +select cast(cast('01-01-2012' as datetime) as nvarchar(10)); +GO +select cast(cast('01-01-2012' as datetime) as nvarchar(5)); +GO + +select cast(cast('01-01-2012' as datetime) as char(10)); +GO +select cast(cast('01-01-2012' as datetime) as char(5)); +GO + +select cast(cast('01-01-2012' as datetime) as nchar(10)); +GO +select cast(cast('01-01-2012' as datetime) as nchar(5)); +GO + +select cast(cast('01-01-2012' as varchar(10)) as datetime); +GO + +select cast(cast('01-01-2012' as nvarchar(10)) as datetime); +GO + +select cast(cast('01-01-2012' as char(10)) as datetime); +GO + +select cast(cast('01-01-2012' as nchar(10)) as datetime); +GO + +-- test cast between datetime2 and varchar/char... +select cast(cast('01-01-2012' as datetime2) as varchar(10)); +GO +select cast(cast('01-01-2012' as datetime2) as varchar(5)); +GO + +select cast(cast('01-01-2012' as datetime2) as nvarchar(10)); +GO +select cast(cast('01-01-2012' as datetime2) as nvarchar(5)); +GO + +select cast(cast('01-01-2012' as datetime2) as char(10)); +GO +select cast(cast('01-01-2012' as datetime2) as char(5)); +GO + +select cast(cast('01-01-2012' as datetime2) as nchar(10)); +GO +select cast(cast('01-01-2012' as datetime2) as nchar(5)); +GO + +select cast(cast('01-01-2012' as varchar(10)) as datetime2); +GO + +select cast(cast('01-01-2012' as nvarchar(10)) as datetime2); +GO + +select cast(cast('01-01-2012' as char(10)) as datetime2); +GO + +select cast(cast('01-01-2012' as nchar(10)) as datetime2); +GO + +-- test cast between smalldatetime and varchar/char... +select cast(cast('01-01-2012' as smalldatetime) as varchar(10)); +GO +select cast(cast('01-01-2012' as smalldatetime) as varchar(5)); +GO + +select cast(cast('01-01-2012' as smalldatetime) as nvarchar(10)); +GO +select cast(cast('01-01-2012' as smalldatetime) as nvarchar(5)); +GO + +select cast(cast('01-01-2012' as smalldatetime) as char(10)); +GO +select cast(cast('01-01-2012' as smalldatetime) as char(5)); +GO + +select cast(cast('01-01-2012' as smalldatetime) as nchar(10)); +GO +select cast(cast('01-01-2012' as smalldatetime) as nchar(5)); +GO + +select cast(cast('01-01-2012' as varchar(10)) as smalldatetime); +GO + +select cast(cast('01-01-2012' as nvarchar(10)) as smalldatetime); +GO + +select cast(cast('01-01-2012' as char(10)) as smalldatetime); +GO + +select cast(cast('01-01-2012' as nchar(10)) as smalldatetime); +GO + +-- TODO BABEL-1624: CAST from datetime/smalldatetime to text/ntext type should not be allowed +-- alter table t1 add c as cast(cast('01-01-2012' as datetime) as text) persisted; +-- GO + +-- alter table t1 add d as cast(cast('01-01-2012' as datetime) as ntext) persisted; +-- GO + +-- alter table t1 add c as cast(cast('01-01-2012' as smalldatetime) as text) persisted; +-- GO + +-- alter table t1 add d as cast(cast('01-01-2012' as smalldatetime) as ntext) persisted; +-- GO + +-- clean up +drop table t1; +GO diff --git a/contrib/test/JDBC/input/BABEL-1466.sql b/contrib/test/JDBC/input/BABEL-1466.sql new file mode 100644 index 00000000000..a8497161c39 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1466.sql @@ -0,0 +1,73 @@ +-- BABEL-1466 +-- CONVERT is VOLATILE if one of these conditions exists: +-- 1. Source type is sql_variant. +-- 2. Target type is sql_variant and its source type is nondeterministic. +-- 3. Source or target type is datetime/datetime2/smalldatetime, the other source or target type is a character string/sql_variant/other datetime types. + +-- VOLATILE functions can not be used to generate persisted computed columns, the following +-- tests are based on this rule. + +create table t1 (id int, a varchar(10), t datetime); +GO + +-- CONVERT from int to smallint is immutable/deterministic and can be used to generate computed column +alter table t1 add b as convert(smallint, 1) persisted; +GO + +-- TODO CONVERT from int to string type is immutable and can be used to generate computed column +-- This is not straightforward to change atm because we currently use a wrapper function babelfish_conv_helper_to_varchar +-- to implement convert to varchar (in order to support the style parameter in convert), +-- and the function is defined as either VOLAITLE or IMMUTABLE (can't be IMMUTABLE conditionally) +-- However, in SQL Server convert to varchar is IMMUTABLE conditionally. +alter table t1 add c as convert(varchar(2), 1) persisted; +GO + +-- CONVERT from sql_variant to other types are volatile and can not be used to generate computed column +alter table t1 add d as convert(smallint, convert(sql_variant, 1)) persisted; +GO + +-- CONVERT from datetime/datetime2/smalldatetime to string type is volatile and can not be used to generate computed column +alter table t1 add d as convert(varchar(15), convert(datetime, '01-01-2012')) persisted; +GO + +alter table t1 add d as convert(char(15), convert(datetime, '01-01-2012')) persisted; +GO + +alter table t1 add d as convert(varchar(15), convert(datetime2, '01-01-2012')) persisted; +GO + +alter table t1 add d as convert(char(15), convert(datetime2, '01-01-2012')) persisted; +GO + +alter table t1 add d as convert(varchar(15), convert(smalldatetime, '01-01-2012')) persisted; +GO + +alter table t1 add d as convert(char(15), convert(smalldatetime, '01-01-2012')) persisted; +GO + +-- CONVERT from datetime column to string type is volatile and can not be used to generate computed column +alter table t1 add d as convert(varchar(15), t) persisted; +GO + +-- CONVERT from string type to datetime/datetime2/smalldatetime is volatile and can not be used to generate computed column +alter table t1 add d as convert(datetime, convert(varchar(15), '01-01-2012')) persisted; +GO + +alter table t1 add d as convert(datetime, convert(char(15), '01-01-2012')) persisted; +GO + +alter table t1 add d as convert(datetime2, convert(varchar(15), '01-01-2012')) persisted; +GO + +alter table t1 add d as convert(datetime2, convert(char(15), '01-01-2012')) persisted; +GO + +alter table t1 add d as convert(smalldatetime, convert(varchar(15), '01-01-2012')) persisted; +GO + +alter table t1 add d as convert(smalldatetime, convert(char(15), '01-01-2012')) persisted; +GO + +-- Clean up +drop table t1; +GO diff --git a/contrib/test/JDBC/input/BABEL-1475.sql b/contrib/test/JDBC/input/BABEL-1475.sql new file mode 100644 index 00000000000..2e43e677dab --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1475.sql @@ -0,0 +1,109 @@ +-- Test DAY function for computed columns +CREATE TABLE dateFunctions (dt1 datetime2, dt2 datetimeoffset(6), day1 as DAY(dt1), day2 as DAY(dt2)); +INSERT INTO dateFunctions (dt1, dt2) values ('2007-01-01 13:10:10.1111111', '1912-10-25 12:24:32 +10:0'); +SELECT day1, day2 from dateFunctions; +DROP TABLE dateFunctions; +GO + +-- Test MONTH function for computed columns +CREATE TABLE dateFunctions (dt1 datetime2, dt2 datetimeoffset(6), month1 as MONTH(dt1), month2 as MONTH(dt2)); +INSERT INTO dateFunctions (dt1, dt2) values ('2007-01-01 13:10:10.1111111', '1912-10-25 12:24:32 +10:0'); +SELECT month1, month2 from dateFunctions; +DROP TABLE dateFunctions; +GO + +-- Test YEAR function for computed columns +CREATE TABLE dateFunctions (dt1 datetime2, dt2 datetimeoffset(6), year1 as YEAR(dt1), year2 as YEAR(dt2)); +INSERT INTO dateFunctions (dt1, dt2) values ('2007-01-01 13:10:10.1111111', '1912-10-25 12:24:32 +10:0'); +SELECT year1, year2 from dateFunctions; +DROP TABLE dateFunctions; +GO + +-- Test DATEADD function for computed columns +-- WRONG OUTPUT with datetimeoffset +-- CREATE TABLE dateFunctions (dt1 datetime2, dt2 datetimeoffset(6), addMonthInDate1 as DATEADD(month,1,dt1), addMonthInDate2 as DATEADD(month,1,dt2)); +-- INSERT INTO dateFunctions (dt1, dt2) values ('2007-01-01 13:10:10.1111111', '1912-10-25 12:24:32 +10:0'); +-- SELECT addMonthInDate1, addMonthInDate2 from dateFunctions; +-- DROP TABLE dateFunctions; +-- GO + +-- Test DATEDIFF function with DATE datatype for computed columns +CREATE TABLE dateFunctions (dt1 date, dt2 date, diffMonthInDates as DATEDIFF(month,dt1,dt2)); +INSERT INTO dateFunctions (dt1, dt2) values ('2007-01-01', '1912-10-25'); +SELECT diffMonthInDates from dateFunctions; +DROP TABLE dateFunctions; +GO + +-- Test DATEDIFF function with DATETIME2 datatype for computed columns +CREATE TABLE dateFunctions (dt1 datetime2, dt2 datetime2, diffMonthInDates as DATEDIFF(month,dt1,dt2)); +INSERT INTO dateFunctions (dt1, dt2) values ('2007-01-01 13:10:10', '1912-10-25 12:24:32'); +SELECT diffMonthInDates from dateFunctions; +DROP TABLE dateFunctions; +GO + +-- Test DATEDIFF function with DATETIMEOFFSET datatype for computed columns +-- CREATE TABLE dateFunctions (dt1 datetimeoffset(6), dt2 datetimeoffset(6), diffMonthInDates as DATEDIFF(month,dt1,dt2)); +-- INSERT INTO dateFunctions (dt1, dt2) values ('2007-01-01 13:10:10', '1912-10-25 12:24:32'); +-- SELECT diffMonthInDates from dateFunctions; +-- DROP TABLE dateFunctions; +-- GO + +-- Test DATEFROMPARTS function for computed columns +CREATE TABLE dateFunctions (year int, month int, day int, dateresult as DATEFROMPARTS(year, month, day)); +INSERT INTO dateFunctions (year, month, day) values (1912, 10, 25); +SELECT dateresult from dateFunctions; +DROP TABLE dateFunctions; +GO + +-- Test DATENAME function for computed columns +CREATE TABLE dateFunctions (dt date, year as DATENAME(year, dt), month as DATENAME(month, dt), weekday as DATENAME(dow, dt), dayofyear as DATENAME(dayofyear, dt), day as DATENAME(day, dt)); +INSERT INTO dateFunctions (dt) values ('1912-10-25'); +SELECT year, month, weekday, dayofyear, day from dateFunctions; +DROP TABLE dateFunctions; +GO + +-- Test DATEPART function for computed columns +CREATE TABLE dateFunctions (dt1 datetime2, dt2 datetimeoffset(6), datepart1 as DATEPART(month, dt1), datepart2 as DATEPART(month, dt2)); +INSERT INTO dateFunctions (dt1, dt2) values ('2007-01-01 13:10:10.111111', '1912-10-25 12:24:32 +10:0'); +SELECT datepart1, datepart2 from dateFunctions; +DROP TABLE dateFunctions; +GO + +-- Test DATEPART function for computed columns +CREATE TABLE dateFunctions (dt1 datetime2, dt2 datetimeoffset(6), datepart1 as DATEPART(dow, dt1), datepart2 as DATEPART(dow, dt2)); +INSERT INTO dateFunctions (dt1, dt2) values ('2007-01-01 13:10:10.1111111', '1912-10-25 12:24:32 +10:0'); +SELECT datepart1, datepart2 from dateFunctions; +DROP TABLE dateFunctions; +GO + +-- Test DATETIME2FROMPARTS function with numeric arguments for computed columns +-- WRONG OUTPUT +-- CREATE TABLE dateFunctions (year int, month int, day int, hour int, minute int, seconds int, fractions int, precision int, dateresult as DATETIME2FROMPARTS (year, month, day, hour, minute, seconds, fractions, precision)); +-- INSERT INTO dateFunctions (year, month, day, hour, minute, seconds, fractions, precision) values (2011, 8, 15, 14, 23, 44, 5, 1 ); +-- SELECT dateresult from dateFunctions; +-- DROP TABLE dateFunctions; +-- GO + +-- Test DATETIME2FROMPARTS function with textual arguments for computed columns +-- WRONG OUTPUT +-- CREATE TABLE dateFunctions (year text, month text, day text, hour text, minute text, seconds text, fractions text, precision text, dateresult as DATETIME2FROMPARTS (year, month, day, hour, minute, seconds, fractions, precision)); +-- INSERT INTO dateFunctions (year, month, day, hour, minute, seconds, fractions, precision) values ('2011', '8', '15', '14', '23', '44', '5', '1'); +-- SELECT dateresult from dateFunctions; +-- DROP TABLE dateFunctions; +-- GO + +-- Test DATETIMEFROMPARTS function with numeric arguments for computed columns +-- WRONG OUTPUT +-- CREATE TABLE dateFunctions (year int, month int, day int, hour int, minute int, seconds int, milliseconds int, dateresult as DATETIMEFROMPARTS (year, month, day, hour, minute, seconds, milliseconds)); +-- INSERT INTO dateFunctions (year, month, day, hour, minute, seconds, milliseconds) values (2010, 12, 31, 23, 59, 59, 456); +-- SELECT dateresult from dateFunctions; +-- DROP TABLE dateFunctions; +-- GO + +-- Test DATETIMEFROMPARTS function with textual arguments for computed columns +-- WRONG OUTPUT +-- CREATE TABLE dateFunctions (year text, month text, day text, hour text, minute text, seconds text, milliseconds text, dateresult as DATETIMEFROMPARTS (year, month, day, hour, minute, seconds, milliseconds)); +-- INSERT INTO dateFunctions (year, month, day, hour, minute, seconds, milliseconds) values ('2010', '12', '31', '23', '59', '59', '456'); +-- SELECT dateresult from dateFunctions; +-- DROP TABLE dateFunctions; +-- GO \ No newline at end of file diff --git a/contrib/test/JDBC/input/BABEL-1481.sql b/contrib/test/JDBC/input/BABEL-1481.sql new file mode 100644 index 00000000000..54c373a586c --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1481.sql @@ -0,0 +1,83 @@ +CREATE TABLE babel_1481_t(a VARCHAR(8000)) +GO + +INSERT INTO babel_1481_t VALUES ('Test Value 1'), ('Test Value 2'); +GO + +SELECT * FROM babel_1481_t; +GO + +DROP TABLE babel_1481_t; +GO + +CREATE TABLE babel_1481_t(a CHAR(8000)); +GO + +INSERT INTO babel_1481_t VALUES ('Test Value 1'), ('Test Value 2'); +GO + +SELECT * FROM babel_1481_t; +GO + +DROP TABLE babel_1481_t; +GO + +CREATE TABLE babel_1481_t(a VARCHAR(8001)) +GO + +CREATE TABLE babel_1481_t(a CHAR(8001)); +GO + +CREATE TABLE babel_1481_t(a NVARCHAR(4000)) +GO + +INSERT INTO babel_1481_t VALUES ('Test Value 1'), ('Test Value 2'); +GO + +SELECT * FROM babel_1481_t; +GO + +DROP TABLE babel_1481_t; +GO + +CREATE TABLE babel_1481_t(a NCHAR(4000)) +GO + +INSERT INTO babel_1481_t VALUES ('Test Value 1'), ('Test Value 2'); +GO + +SELECT * FROM babel_1481_t; +GO + +DROP TABLE babel_1481_t; +GO + +CREATE TABLE babel_1481_t(a NVARCHAR(4001)) +GO + +CREATE TABLE babel_1481_t(a NCHAR(4001)) +GO + +SELECT cast(12 as VARCHAR(8000)) +GO + +SELECT cast(12 as CHAR(8000)) +GO + +SELECT cast(12 as NVARCHAR(4000)) +GO + +SELECT cast(12 as NCHAR(4000)) +GO + +SELECT cast(12 as VARCHAR(8001)) +GO + +SELECT cast(12 as CHAR(8001)) +GO + +SELECT cast(12 as NVARCHAR(4001)) +GO + +SELECT cast(12 as NCHAR(4001)) +GO diff --git a/contrib/test/JDBC/input/BABEL-1499.sql b/contrib/test/JDBC/input/BABEL-1499.sql new file mode 100644 index 00000000000..a01a9abe8d2 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1499.sql @@ -0,0 +1,25 @@ +-- implict castings +DECLARE @a binary(10); SET @a = CAST('21' AS char(10)); SELECT @a +go + +DECLARE @a binary(10); SET @a = CAST('21' AS varchar(10)); SELECT @a +go + +DECLARE @a varbinary(10); SET @a = CAST('21' AS char(10)); SELECT @a +go + +DECLARE @a varbinary(10); SET @a = CAST('21' AS varchar(10)); SELECT @a +go + +-- explicit castings +DECLARE @a binary(10); SET @a = CONVERT(binary(10), CAST('21' AS char(10))); SELECT @a +go + +DECLARE @a binary(10); SET @a = CONVERT(binary(10), CAST('21' AS varchar(10))); SELECT @a +go + +DECLARE @a varbinary(10); SET @a = CONVERT(varbinary(10), CAST('21' AS char(10))); SELECT @a +go + +DECLARE @a varbinary(10); SET @a = CONVERT(varbinary(10), CAST('21' AS varchar(10))); SELECT @a +go diff --git a/contrib/test/JDBC/input/BABEL-1502.sql b/contrib/test/JDBC/input/BABEL-1502.sql new file mode 100644 index 00000000000..24ac16485ac --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1502.sql @@ -0,0 +1,22 @@ +CREATE TABLE BABEL_1502_t( + Id nvarchar(100) NOT NULL, + Gastly nvarchar(100) NULL, + FawfulId nvarchar(100) NOT NULL, + SwankyId nvarchar(100) NOT NULL, + WrinklyId nvarchar(100) NOT NULL, + Sandshrew int NULL, + Charmeleon int NULL, + Omastar nvarchar(100) NULL, + KamekId nvarchar(100) NOT NULL, + ThwompId nvarchar(100) NOT NULL, + Uuid uniqueidentifier NOT NULL, + UpdatedAt datetime NOT NULL, + ValidatedAt datetime NULL, + PublishedAt datetime NULL, + ImportedAt datetime NULL, + DistributedAt datetime NULL, + Mankey int NOT NULL, + FuzzyId nvarchar(100) NULL, + UpdatedBy varchar(200) NULL, +CONSTRAINT PK_Sylux PRIMARY KEY (Id) +go diff --git a/contrib/test/JDBC/input/BABEL-1510.sql b/contrib/test/JDBC/input/BABEL-1510.sql new file mode 100644 index 00000000000..04ad8d0276e --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1510.sql @@ -0,0 +1,74 @@ +USE master +GO + +create table babel_1510_t(dto datetimeoffset, dt2 datetime2, dt datetime, sdt smalldatetime, d date, t time); +go + +insert into babel_1510_t values ('2021-05-01 11:11:11.111', '2021-05-02 22:22:22.222', '2021-05-03 11:33:33.333', '2021-05-04 22:44:44.444', '2021-05-05', '11:55:55.555'); +go + +select datediff(dd, dto, dt2) from babel_1510_t; +go +select datediff(dd, dto, dt) from babel_1510_t; +go +select datediff(dd, dto, sdt) from babel_1510_t; +go +select datediff(dd, dto, d) from babel_1510_t; +go +select datediff(dd, dto, t) from babel_1510_t; +go + +select datediff(dd, dt2, dto) from babel_1510_t; +go +select datediff(dd, dt2, dt2) from babel_1510_t; +go +select datediff(dd, dt2, sdt) from babel_1510_t; +go +select datediff(dd, dt2, d) from babel_1510_t; +go +select datediff(dd, dt2, t) from babel_1510_t; +go + +select datediff(dd, dt, dto) from babel_1510_t; +go +select datediff(dd, dt, dt2) from babel_1510_t; +go +select datediff(dd, dt, sdt) from babel_1510_t; +go +select datediff(dd, dt, d) from babel_1510_t; +go +select datediff(dd, dt, t) from babel_1510_t; +go + +select datediff(dd, sdt, dto) from babel_1510_t; +go +select datediff(dd, sdt, dt2) from babel_1510_t; +go +select datediff(dd, sdt, dt) from babel_1510_t; +go +select datediff(dd, sdt, d) from babel_1510_t; +go +select datediff(dd, sdt, t) from babel_1510_t; +go + +select datediff(dd, d, dto) from babel_1510_t; +go +select datediff(dd, d, dt2) from babel_1510_t; +go +select datediff(dd, d, dt) from babel_1510_t; +go +select datediff(dd, d, sdt) from babel_1510_t; +go +select datediff(dd, d, t) from babel_1510_t; +go + +select datediff(dd, t, dto) from babel_1510_t; +go +select datediff(dd, t, dt2) from babel_1510_t; +go +select datediff(dd, t, dt) from babel_1510_t; +go +select datediff(dd, t, sdt) from babel_1510_t; +go +select datediff(dd, t, d) from babel_1510_t; +go diff --git a/contrib/test/JDBC/input/BABEL-1513.sql b/contrib/test/JDBC/input/BABEL-1513.sql new file mode 100644 index 00000000000..203e400e171 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1513.sql @@ -0,0 +1,41 @@ +DECLARE @a varchar +SELECT @a = '12345678901234567890123456789012345'; +SELECT LEN(@a), DATALENGTH(@a) +SELECT @a +GO + +DECLARE @a nvarchar +SELECT @a = '12345678901234567890123456789012345'; +SELECT LEN(@a), DATALENGTH(@a) +SELECT @a +GO + +DECLARE @a sys.varchar +SELECT @a = '12345678901234567890123456789012345'; +SELECT LEN(@a), DATALENGTH(@a) +SELECT @a +GO + +DECLARE @a pg_catalog.varchar +SELECT @a = '12345678901234567890123456789012345'; +SELECT LEN(@a), DATALENGTH(@a) +SELECT @a +GO + +DECLARE @a char +SELECT @a = '12345678901234567890123456789012345'; +SELECT LEN(@a), DATALENGTH(@a) +SELECT @a +GO + +DECLARE @a nchar +SELECT @a = '12345678901234567890123456789012345'; +SELECT LEN(@a), DATALENGTH(@a) +SELECT @a +GO + +DECLARE @a sys.char +SELECT @a = '12345678901234567890123456789012345'; +SELECT LEN(@a), DATALENGTH(@a) +SELECT @a +GO diff --git a/contrib/test/JDBC/input/BABEL-1515.sql b/contrib/test/JDBC/input/BABEL-1515.sql new file mode 100644 index 00000000000..d7074050b70 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1515.sql @@ -0,0 +1,23 @@ +DECLARE @a char(10) +SELECT @a = '12345678901234567890123456789012345'; +SELECT LEN(@a), DATALENGTH(@a) +SELECT @a +GO + +DECLARE @a nchar(10) +SELECT @a = '12345678901234567890123456789012345'; +SELECT LEN(@a), DATALENGTH(@a) +SELECT @a +GO + +DECLARE @a varchar(10) +SELECT @a = '12345678901234567890123456789012345'; +SELECT LEN(@a), DATALENGTH(@a) +SELECT @a +GO + +DECLARE @a nvarchar(10) +SELECT @a = '12345678901234567890123456789012345'; +SELECT LEN(@a), DATALENGTH(@a) +SELECT @a +GO diff --git a/contrib/test/JDBC/input/BABEL-1531.sql b/contrib/test/JDBC/input/BABEL-1531.sql new file mode 100644 index 00000000000..0d9b88c8260 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1531.sql @@ -0,0 +1,18 @@ +SELECT CONVERT(varchar(50), CAST($23.12 AS money), 0); +GO +SELECT CONVERT(varchar(50), CAST($23.12 AS money), 2); +GO +SELECT CONVERT(varchar(50), CAST($23.12 as money)); +GO +SELECT CONVERT(float, CAST($23.12 as money)); +GO +SELECT CONVERT(decimal, CAST($23.12 as money)); +GO +SELECT CONVERT(numeric, CAST($23.12 as money)); +GO +SELECT CONVERT(numeric(10,4), CAST($23.12 as money)); +GO +declare @mon money; +set @mon = $23.12; +SELECT CONVERT(varchar(50), @mon); +GO diff --git a/contrib/test/JDBC/input/BABEL-1566.sql b/contrib/test/JDBC/input/BABEL-1566.sql new file mode 100644 index 00000000000..e47c120cd3d --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1566.sql @@ -0,0 +1,24 @@ +-- Test CHECKSUM function works on string input +select CHECKSUM('abcd'); +go + +-- Test CHECKSUM function works on scalar input +select CHECKSUM(123); +go + +select CHECKSUM(10.12345); +go + +-- Test CHECKSUM works on table column +create table t1 (a int, b varchar(10)); +insert into t1 values (12345, 'abcd'); +insert into t1 values (12345, 'abcd'); +insert into t1 values (23456, 'bcd'); +go + +select CHECKSUM(a), CHECKSUM(b) from t1; +go + +-- clean up +drop table t1; +go diff --git a/contrib/test/JDBC/input/BABEL-1569.sql b/contrib/test/JDBC/input/BABEL-1569.sql new file mode 100644 index 00000000000..038ccb2301e --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1569.sql @@ -0,0 +1,57 @@ +-- Test CHARINDEX function with computed columns (general gives case-insensitive result) +--WRONG OUTPUT +-- CREATE TABLE check_charindex_general(check_for VARCHAR(10), document VARCHAR(64), ci as charindex(check_for, document)); +-- GO + +-- INSERT INTO check_charindex_general (check_for, document) VALUES ('Test','This is a Test'); +-- INSERT INTO check_charindex_general (check_for, document) VALUES ('Test','test Test test'); +-- INSERT INTO check_charindex_general (check_for, document) VALUES ('TEST','This is a test'); +-- GO + +-- Select ci from check_charindex_general; +-- GO + +-- DROP TABLE check_charindex_general; +-- GO + +-- Test CHARINDEX function with computed columns (case-insensitive) +CREATE TABLE check_charindex_case_insensitive(check_for VARCHAR(10), document VARCHAR(64), ci as charindex(check_for, document COLLATE SQL_Latin1_General_CP1_CI_AS)); +GO + +INSERT INTO check_charindex_case_insensitive (check_for, document) VALUES ('Test','This is a Test'); +INSERT INTO check_charindex_case_insensitive (check_for, document) VALUES ('Test','test Test test'); +INSERT INTO check_charindex_case_insensitive (check_for, document) VALUES ('TEST','This is a test'); +GO + +Select ci from check_charindex_case_insensitive; +GO + +DROP TABLE check_charindex_case_insensitive; +GO + +-- Test CHARINDEX function with computed columns (case-sensitive) +CREATE TABLE check_charindex_case_sensitive(check_for VARCHAR(10), document VARCHAR(64), ci as charindex(check_for, document COLLATE SQL_Latin1_General_CP1_CS_AS)); +GO + +INSERT INTO check_charindex_case_sensitive (check_for, document) VALUES ('Test','This is a Test'); +INSERT INTO check_charindex_case_sensitive (check_for, document) VALUES ('Test','test Test test'); +INSERT INTO check_charindex_case_sensitive (check_for, document) VALUES ('TEST','This is a test'); +GO + +Select ci from check_charindex_case_sensitive; +GO + +DROP TABLE check_charindex_case_sensitive; +GO + +-- Test CHECKSUM function with computed columns +CREATE TABLE country(name VARCHAR(64), cs as CHECKSUM(name)) +GO + +INSERT INTO country VALUES ('India'); +INSERT INTO country VALUES ('US'); +INSERT INTO country VALUES ('China'); +GO + +DROP TABLE country; +GO diff --git a/contrib/test/JDBC/input/BABEL-1577.sql b/contrib/test/JDBC/input/BABEL-1577.sql new file mode 100644 index 00000000000..f6d971eda91 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1577.sql @@ -0,0 +1,25 @@ +CREATE TABLE babel_1577_table (col# int, #col int, co##l int, col$$ int, co_#$#$l int, col_# int) +go + +INSERT INTO babel_1577_table VALUES (1, 2, 3, 4, 5, 6); +go + +CREATE PROC babel_1577_proc AS +SELECT + col# AS a, + #col AS b, + co##l AS c, + col$$ AS d, + co_#$#$l AS e, + col_# AS f +FROM babel_1577_table +go + +EXEC babel_1577_proc +go + +DROP PROC babel_1577_proc +go + +DROP TABLE babel_1577_table +go diff --git a/contrib/test/JDBC/input/BABEL-1603.sql b/contrib/test/JDBC/input/BABEL-1603.sql new file mode 100644 index 00000000000..d85016f4141 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1603.sql @@ -0,0 +1,35 @@ +SELECT DATEPART(weekday, CAST( '2021-12-31' as DATE)); +GO + +SELECT @@DATEFIRST; +GO + +SET DATEFIRST 1 +GO + +SELECT @@DATEFIRST; +GO + +SELECT DATEPART(weekday, CAST( '2021-12-31' as DATE)); +GO + +-- reset it to 7 +SET DATEFIRST 7 +GO + +SELECT @@DATEFIRST; +GO + +SELECT DATEPART(weekday, CAST( '2021-12-31' as DATE)); +GO + +-- invalid settings +SET DATEFIRST 0 +GO + +SET DATEFIRST 8 +GO + +SELECT @@DATEFIRST; +GO + diff --git a/contrib/test/JDBC/input/BABEL-1621.sql b/contrib/test/JDBC/input/BABEL-1621.sql new file mode 100644 index 00000000000..49223f8bf90 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1621.sql @@ -0,0 +1,5 @@ +SELECT is_member(CAST('fake_role' AS varchar)) +GO + +SELECT is_member(NULL) +GO diff --git a/contrib/test/JDBC/input/BABEL-1636.sql b/contrib/test/JDBC/input/BABEL-1636.sql new file mode 100644 index 00000000000..e1d83c11404 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1636.sql @@ -0,0 +1,50 @@ +create type tableType as table (i int, j int); +go + +-- ROLLBACK should get unsupported error message +create proc p1 as +begin + declare @tv tableType; + begin tran insert @tv values (1,2); + rollback; + select * from @tv +end +go +exec p1 +go + +-- ROLLBACK should get unsupported error message +declare @t table (a int) +begin tran +insert into @t values(1) +select @@rowcount as rows_inserted +rollback +select count(*) from @t +print 'after select' +go + +declare @tv1 tableType; +begin transaction +insert @tv1 values (1,2), (2,1); +select * from @tv1; +go + +-- ROLLBACK here is fine because @tv1 is out of scope +rollback +select * from @tv1; +go + +-- ROLLBACK should get unsupported error message +declare @tv2 tableType; +begin transaction +insert @tv2 values (3,4), (4,3); +select * from @tv2; +rollback +select * from @tv2; +go + +-- cleanup +drop type tableType; +go +drop proc p1; +go diff --git a/contrib/test/JDBC/input/BABEL-1661.sql b/contrib/test/JDBC/input/BABEL-1661.sql new file mode 100644 index 00000000000..e5c085144ac --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1661.sql @@ -0,0 +1,13 @@ +-- BABEL-1661 +-- Test CONVERT to VARCHAR applies typmod +SELECT CONVERT(VARCHAR(10), SERVERPROPERTY('productversion')); +GO + +SELECT DATALENGTH(CONVERT(VARCHAR(10), SERVERPROPERTY('productversion'))); +GO + +SELECT CONVERT(VARCHAR(2), SERVERPROPERTY('productversion')); +GO + +SELECT DATALENGTH(CONVERT(VARCHAR(2), SERVERPROPERTY('productversion'))); +GO diff --git a/contrib/test/JDBC/input/BABEL-1666.sql b/contrib/test/JDBC/input/BABEL-1666.sql new file mode 100644 index 00000000000..7c16fad70a8 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1666.sql @@ -0,0 +1,19 @@ +create procedure p_babel_1666 as + declare @p1 decimal(5,2); + set @p1 = 3.14; + select @p1; + return @p1; +go + +declare @a decimal(5,2); +exec @a = p_babel_1666; +select @a; +go + +declare @i int; +exec @i = p_babel_1666; +select @i; +go + +drop procedure p_babel_1666 +go diff --git a/contrib/test/JDBC/input/BABEL-1671.sql b/contrib/test/JDBC/input/BABEL-1671.sql new file mode 100644 index 00000000000..699c50df2ba --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1671.sql @@ -0,0 +1,18 @@ +-- Check if default binary data length is 1 when maxLen isn't specified +-- in a data definition or variable declaration statement +DROP PROCEDURE IF EXISTS sp_test12; +go +CREATE PROCEDURE sp_test12 (@a binary OUTPUT) AS BEGIN SET @a=0x121; Select @a as a; END; +go +Declare @a binary;Set @a=0x121; exec sp_test12 @a;select @a as a; +go +DROP PROCEDURE sp_test12; +go +DROP PROCEDURE IF EXISTS sp_test13; +go +CREATE PROCEDURE sp_test13 (@b binary OUTPUT) AS BEGIN SET @b=0x121111; Select @b as b; END; +go +Declare @b binary;Set @b=0x121111; exec sp_test13 @b;select @b as b; +go +DROP PROCEDURE sp_test13; +go diff --git a/contrib/test/JDBC/input/BABEL-1682.sql b/contrib/test/JDBC/input/BABEL-1682.sql new file mode 100644 index 00000000000..77bde2fde66 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1682.sql @@ -0,0 +1,26 @@ +use master +go + +create schema [Babelfish]; +go + +create type [Babelfish].[temp_type] from int; +go + +declare @tint [Babelfish].[temp_type]; +set @tint = 3; +print 'Value of variable is: ' + cast(@tint as varchar(5)); +go + +create type [Babelfish].[EmployeesType] as TABLE (first_name NVARCHAR(10), last_name NVARCHAR(10), emp_sal money); +go + +declare @emps [Babelfish].[EmployeesType]; +go + +drop type [Babelfish].[temp_type]; +go +drop type [Babelfish].[EmployeesType]; +go +drop schema [Babelfish]; +go diff --git a/contrib/test/JDBC/input/BABEL-1683.sql b/contrib/test/JDBC/input/BABEL-1683.sql new file mode 100644 index 00000000000..52acb36ab06 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1683.sql @@ -0,0 +1,106 @@ +-- CREATE TABLE stmt +-- NVARCHAR(128) +CREATE TABLE babel_1683_table_nvarchar (a INT, b NVARCHAR(128)) +go + +INSERT INTO babel_1683_table_nvarchar VALUES (1, NULL) +go + +INSERT INTO babel_1683_table_nvarchar(a) VALUES (2) +go + +SELECT * FROM babel_1683_table_nvarchar +go + +DROP TABLE babel_1683_table_nvarchar +go + +-- SYSNAME not explicitly defined as NULL +CREATE TABLE babel_1683_table_sysname (a INT, b SYSNAME) +go + +INSERT INTO babel_1683_table_sysname VALUES (1, NULL) +go + +INSERT INTO babel_1683_table_sysname(a) VALUES (2) +go + +SELECT * FROM babel_1683_table_sysname +go + +DROP TABLE babel_1683_table_sysname +go + +-- SYSNAME explicitly defined as NULL +CREATE TABLE babel_1683_table_sysname (a INT, b SYSNAME NULL) +go + +INSERT INTO babel_1683_table_sysname VALUES (1, NULL) +go + +INSERT INTO babel_1683_table_sysname(a) VALUES (2) +go + +SELECT * FROM babel_1683_table_sysname +go + +DROP TABLE babel_1683_table_sysname +go + +-- ALTER TABLE ADD stmt +-- NVARCHAR(128) +CREATE TABLE babel_1683_table_nvarchar (a INT) +go + +ALTER TABLE babel_1683_table_nvarchar ADD b NVARCHAR(128) +go + +INSERT INTO babel_1683_table_nvarchar VALUES (1, NULL) +go + +INSERT INTO babel_1683_table_nvarchar(a) VALUES (2) +go + +SELECT * FROM babel_1683_table_nvarchar +go + +DROP TABLE babel_1683_table_nvarchar +go + +-- SYSNAME not explicitly defined as NULL +CREATE TABLE babel_1683_table_sysname (a INT) +go + +ALTER TABLE babel_1683_table_sysname ADD b SYSNAME +go + +INSERT INTO babel_1683_table_sysname VALUES (1, NULL) +go + +INSERT INTO babel_1683_table_sysname(a) VALUES (2) +go + +SELECT * FROM babel_1683_table_sysname +go + +DROP TABLE babel_1683_table_sysname +go + +-- SYSNAME explicitly defined as NULL +CREATE TABLE babel_1683_table_sysname (a INT) +go + +ALTER TABLE babel_1683_table_sysname ADD b SYSNAME NULL +go + +INSERT INTO babel_1683_table_sysname VALUES (1, NULL) +go + +INSERT INTO babel_1683_table_sysname(a) VALUES (2) +go + +SELECT * FROM babel_1683_table_sysname +go + +DROP TABLE babel_1683_table_sysname +go diff --git a/contrib/test/JDBC/input/BABEL-1708.sql b/contrib/test/JDBC/input/BABEL-1708.sql new file mode 100644 index 00000000000..80523fdbe20 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1708.sql @@ -0,0 +1,76 @@ +-- Test valid maximum/minimum values for smallmoney +SELECT CAST($214748.3647 AS smallmoney); +GO + +SELECT CAST(-214748.3648 AS smallmoney); +GO + +SELECT CAST('214748.3647' AS smallmoney); +GO + +SELECT CAST('-214748.3648' AS smallmoney); +GO + +-- Test valid maximum/minimum values for money +SELECT CAST($922337203685477.5807 AS money); +GO + +SELECT CAST(-922337203685477.5808 AS money); +GO + +SELECT CAST('922337203685477.5807' AS money); +GO + +SELECT CAST('-922337203685477.5808' AS money); +GO + +-- Test out of range value for smallmoney +SELECT CAST($214748.3648 AS smallmoney); +GO + +SELECT CAST(-214748.3649 AS smallmoney); +GO + +SELECT CAST('214748.3648' AS smallmoney); +GO + +SELECT CAST('-214748.3649' AS smallmoney); +GO + +-- Test out of range values for money +SELECT CAST($922337203685477.5808 AS money); +GO + +SELECT CAST(-922337203685477.5809 AS money); +GO + +SELECT CAST('922337203685477.5808' AS money); +GO + +SELECT CAST('-922337203685477.5809' AS money); +GO + +-- Test table insert of max/min/out of range values +CREATE TABLE t1 (a smallmoney, b money) +GO + +-- Insert valid values +INSERT INTO t1 VALUES ($214748.3647, 0), (-214748.3648, 0), (0, 922337203685477.5807), (0, -922337203685477.5808) +GO + +-- Insert invalid values +INSERT INTO t1 VALUES ($214748.3648, 0) +GO + +INSERT INTO t1 VALUES (-214748.3649, 0) +GO + +INSERT INTO t1 VALUES (0, 922337203685477.5808) +GO + +INSERT INTO t1 VALUES (0, -922337203685477.5809) +GO + +-- Clean up +DROP TABLE t1; +GO diff --git a/contrib/test/JDBC/input/BABEL-1712.sql b/contrib/test/JDBC/input/BABEL-1712.sql new file mode 100644 index 00000000000..6fefeaaf2ef --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1712.sql @@ -0,0 +1,41 @@ +--Under Single-DB mode +USE master; +GO +CREATE DATABASE db1; +GO +USE db1; +GO +CREATE schema test; +GO +SELECT nspname FROM pg_namespace WHERE nspname = 'test'; +GO +CREATE table t1 ( a int, b int); -- should be created into dbo.t1 +GO +INSERT INTO t1 VALUES ( 1, 1); +GO +SELECT * FROM t1; +GO +-- cross DB reference +USE master; +GO +SELECT * FROM t1; -- doesn't exist expected, querying master.dbo.t1 +GO +SELECT * FROM db1.dbo.t1; +GO +SELECT * FROM dbo.t1; -- error expected, querying master.dbo.t1 +GO +-- search path +USE db1; +GO +CREATE TABLE test.t1 ( a int, b int, c int); +GO +INSERT INTO test.t1 VALUES (1,2,3); +GO +SELECT * FROM t1; -- selecting 2 column db1.dbo.t1 +GO +SELECT * FROM test.t1; -- selecting 3 column db1.test.t1 +GO +USE MASTER; +GO +DROP DATABASE db1; +GO diff --git a/contrib/test/JDBC/input/BABEL-1715.sql b/contrib/test/JDBC/input/BABEL-1715.sql new file mode 100644 index 00000000000..4033ad01306 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1715.sql @@ -0,0 +1,39 @@ +use master; +go + +CREATE TABLE t1715 (a int, b int CONSTRAINT uk_a PRIMARY KEY (a)); +go +INSERT INTO t1715 VALUES (1, 1); +INSERT INTO t1715 VALUES (2, 2); +go +INSERT INTO t1715 VALUES (2, 3); +go +drop table t1715; +go + + +CREATE TABLE t1715_2 (a int, b as a+1 CONSTRAINT uk_a PRIMARY KEY (a)); +go +INSERT INTO t1715_2 (a) VALUES (1); +INSERT INTO t1715_2 (a) VALUES (2); +go +INSERT INTO t1715_2 (a) VALUES (2); +go +drop table t1715_2; +go + + +CREATE TABLE t1715_invalid (a int b int); +go +CREATE TABLE t1715_invalid (a int CONSTRAINT uk_a PRIMARY KEY (a) b int); +go +CREATE TABLE t1715_invalid (a int CONSTRAINT uk_a PRIMARY KEY (a) CONSTRAINT uk_b UNIQUE (b)); +go + + +-- cx table +CREATE TABLE cx_t1715 ( name sysname NOT NULL, principal_id int NOT NULL, diagram_id int PRIMARY KEY IDENTITY, version int, definition varbinary(max) CONSTRAINT UK_principal_name UNIQUE ( principal_id, name ) ); +go + +DROP TABLE cx_t1715; +go diff --git a/contrib/test/JDBC/input/BABEL-1719.sql b/contrib/test/JDBC/input/BABEL-1719.sql new file mode 100644 index 00000000000..62e3b5be8d5 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1719.sql @@ -0,0 +1,26 @@ +CREATE DATABASE db1; +GO + +USE db1; +GO + +CREATE LOGIN login1 WITH PASSWORD = '123'; +GO + +ALTER LOGIN login1 disable; +GO + +SELECT is_disabled FROM sys.server_principals WHERE name = 'login1'; +GO + +ALTER LOGIN login1 enable; +GO + +USE MASTER; +GO + +DROP DATABASE db1; +GO + +DROP LOGIN login1; +GO diff --git a/contrib/test/JDBC/input/BABEL-1746.sql b/contrib/test/JDBC/input/BABEL-1746.sql new file mode 100644 index 00000000000..ab9a91631d3 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1746.sql @@ -0,0 +1,5 @@ +DROP DATABASE master; +GO + +DROP DATABASE tempdb; +GO diff --git a/contrib/test/JDBC/input/BABEL-1756.sql b/contrib/test/JDBC/input/BABEL-1756.sql new file mode 100644 index 00000000000..866e00b0b49 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1756.sql @@ -0,0 +1,13 @@ +CREATE TABLE foo(test_collation TEXT COLLATE "default") +GO + +SELECT colid, name, collation_100 FROM sys.spt_tablecollations_view WHERE object_id = sys.object_id('foo') ORDER BY colid +GO + +exec sp_tablecollations_100 'foo' +GO + +exec ..sp_tablecollations_100 'foo' +GO + +DROP TABLE foo; diff --git a/contrib/test/JDBC/input/BABEL-1757.sql b/contrib/test/JDBC/input/BABEL-1757.sql new file mode 100644 index 00000000000..12ba2623f0b --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1757.sql @@ -0,0 +1,9 @@ +CREATE TABLE t1(a int) +GO + +SET FMTONLY ON SELECT * FROM t1 SET FMTONLY OFF +GO + +DROP TABLE t1 +GO + diff --git a/contrib/test/JDBC/input/BABEL-1771.sql b/contrib/test/JDBC/input/BABEL-1771.sql new file mode 100644 index 00000000000..f9d8a7d7b49 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1771.sql @@ -0,0 +1,63 @@ +USE master; +GO + +CREATE SCHEMA test +GO + +CREATE TABLE t (a int) +GO + +CREATE PROCEDURE foo AS SELECT 1 +GO + +CREATE PROCEDURE test.bar AS SELECT 2 +GO + +SELECT * FROM t +GO + +SELECT * FROM ..t +GO + +SELECT * FROM master..t +GO + +SELECT * FROM .fake_schema.t +GO + +EXEC test.bar +GO + +EXEC .test.bar +GO + +EXEC master..bar +GO + +EXEC ..bar +GO + +EXEC foo +GO + +EXEC ..foo +GO + +EXEC master..foo +GO + +EXEC .schema.foo +GO + +DROP TABLE t +GO + +DROP PROCEDURE foo +GO + +DROP PROCEDURE test.bar +GO + +DROP SCHEMA test +GO + diff --git a/contrib/test/JDBC/input/BABEL-1792.sql b/contrib/test/JDBC/input/BABEL-1792.sql new file mode 100644 index 00000000000..0248dd5c4ac --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1792.sql @@ -0,0 +1,51 @@ +USE MASTER; +GO + +CREATE DATABASE db1; +GO + +USE db1; +GO + +CREATE TABLE t1 (id INT, c1 INT); +GO + +INSERT INTO t1 (id, c1) VALUES (1, 2); +GO + +USE MASTER; +GO + +-- Cannot find db1 table t1 +INSERT INTO t1 (id, c1) VALUES (2, 4); +GO + +BEGIN TRAN; +GO + +USE db1; +GO + +INSERT INTO t1 (id, c1) VALUES (3, 8); +GO + +ROLLBACK; +GO + +SELECT current_user; +GO + +SELECT current_schema(); +GO + +INSERT INTO t1 (id, c1) VALUES (4, 16); +GO + +SELECT * FROM t1; +GO + +USE MASTER; +GO + +DROP DATABASE db1; +GO diff --git a/contrib/test/JDBC/input/BABEL-1797.sql b/contrib/test/JDBC/input/BABEL-1797.sql new file mode 100644 index 00000000000..9fdb5987487 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1797.sql @@ -0,0 +1,13 @@ +USE master +GO + +create table [dbo].[t23]([id] int, [a] money, [b] datetime) +go + +exec sp_describe_undeclared_parameters +N'INSERT INTO [dbo].[t23]([id],[a],[b]) values (@P1,@P2,@P3)' +go + +-- cleanup +drop table [dbo].[t23]; +go diff --git a/contrib/test/JDBC/input/BABEL-1808.sql b/contrib/test/JDBC/input/BABEL-1808.sql new file mode 100644 index 00000000000..956dfff7d46 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1808.sql @@ -0,0 +1,40 @@ +-- Test DDL +CREATE TABLE t1 ( a [Decimal], b [DeCimal](18,0)); +GO + +-- Test Default value +CREATE TABLE t2 ( a Decimal, b [DeCimal]); +GO + +INSERT INTO t2 values (3.14, 3.14); +SELECT * FROM t2; +GO + +-- Test Identity column + +CREATE TABLE t3 ( a Decimal IDENTITY, b INT); +GO + +INSERT INTO t3 (b) VALUES (10); +SELECT * FROM t3; +GO + +CREATE TABLE t4 ( a [Decimal] IDENTITY, b INT); +GO + +INSERT INTO t4 (b) VALUES (10); +SELECT * FROM t4; +GO + +-- test error +CREATE TABLE t5 ( a Decimal(18,2) IDENTITY, b int); +GO + +DROP TABLE t1; +GO +DROP TABLE t2; +GO +DROP TABLE t3; +GO +DROP TABLE t4; +GO diff --git a/contrib/test/JDBC/input/BABEL-1813.sql b/contrib/test/JDBC/input/BABEL-1813.sql new file mode 100644 index 00000000000..dcf90cfec42 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1813.sql @@ -0,0 +1,132 @@ +use master; +go + +-- basic operations +create table t1813 (a int, b int, collation int not null); +go +insert into t1813 (a, collation) values (1, 2); +go +select a, b, collation from t1813; +go +select a, b, t1813.collation from t1813; +go +alter table t1813 add binary binary; -- column "binary" whose type is binary +go +insert into t1813(collation,binary) values (3, 0x04); +go +create unique index i1813 on t1813(collation); +go +insert into t1813(collation,binary) values (4, 0x05); +insert into t1813(collation,binary) values (4, 0x05); +go +select abs(-collation)*2 c, binary from t1813; +go +update t1813 set collation = 5 output deleted.collation where collation = 2; +go +delete from t1813 output collation where collation = 4; +go +select collation from t1813 order by collation; +go +select [collation] from t1813 order by collation; +go +select t1813.[collation] from t1813 order by collation; +go +select COLLATION from t1813 order by COLLATION; +go +select CoLlAtIoN from t1813 order by CoLlAtIoN; +go +drop table t1813; +go + +-- several types of object +create table collation(a int); +go +insert into collation values (1), (2); +update collation set a=3 where a=2; +delete from collation where a=1; +select * from collation; +go + +drop table collation; +go + +create type collation as table (a int); +go +drop type collation; +go + +create table t1813(a int); +go +create view collation as select * from t1813; +go +drop view collation; +go + +create trigger collation on t1813 after insert as begin print 'trigger invoked' end +go + +drop table t1813; +go + +create function collation(@a int) returns int as begin return @a+1; end +go +select collation(1); +go +drop function collation +go + +-- test all keywords +create table binary(binary int); +go +drop table binary; +go + +create table collation(collation int); +go +drop table collation; +go + +create table concurrently(concurrently int); +go +drop table concurrently; +go + +create table current_schema(current_schema int); +go +drop table current_schema; +go + +create table freeze(freeze int); +go +drop table freeze; +go + +create table ilike(ilike int); +go +drop table ilike; +go + +create table isnull(isnull int); +go +drop table isnull; +go + +create table natural(natural int); +go +drop table natural; +go + +create table notnull(notnull int); +go +drop table notnull; +go + +create table overlaps(overlaps int); +go +drop table overlaps; +go + +create table similar(similar int); +go +drop table similar; +go diff --git a/contrib/test/JDBC/input/BABEL-1839.sql b/contrib/test/JDBC/input/BABEL-1839.sql new file mode 100644 index 00000000000..0b50be76657 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1839.sql @@ -0,0 +1,39 @@ +SELECT + current_setting('babelfishpg_tsql.quoted_identifier', true), + current_setting('babelfishpg_tsql.nocount', true), + current_setting('babelfishpg_tsql.concat_null_yields_null', true); +GO + +SET NOCOUNT, CONCAT_NULL_YIELDS_NULL, QUOTED_IDENTIFIER ON; +GO + +SET NOCOUNT, CONCAT_NULL_YIELDS_NULL, QUOTED_IDENTIFIER OFF; +GO + +SELECT + current_setting('babelfishpg_tsql.quoted_identifier', true), + current_setting('babelfishpg_tsql.nocount', true), + current_setting('babelfishpg_tsql.concat_null_yields_null', true); +GO + +-- error expected +SET NOCOUNT, CONCAT_NULL_YIELDS_NULL, QUOTED_IDENTIFIER, NOTHING ON; +GO + +-- value shall not change +SELECT + current_setting('babelfishpg_tsql.quoted_identifier', true), + current_setting('babelfishpg_tsql.nocount', true), + current_setting('babelfishpg_tsql.concat_null_yields_null', true); +GO + +-- error expected 2 +SET NOCOUNT, CONCAT_NULL_YIELDS_NULL, QUOTED_IDENTIFIER, LANGUAGE ON; +GO + +-- value shall not change +SELECT + current_setting('babelfishpg_tsql.quoted_identifier', true), + current_setting('babelfishpg_tsql.nocount', true), + current_setting('babelfishpg_tsql.concat_null_yields_null', true); +GO diff --git a/contrib/test/JDBC/input/BABEL-1845.sql b/contrib/test/JDBC/input/BABEL-1845.sql new file mode 100644 index 00000000000..cf267975b95 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1845.sql @@ -0,0 +1,35 @@ +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_session_settings', 'strict'; +GO + +-- Test that ANSI_NULL_DFLT_ON can be set to ON and ANSI_NULL_DFLT_OFF can be set to OFF +set ANSI_NULL_DFLT_ON ON; +go + +set ANSI_NULL_DFLT_OFF OFF; +go + +-- Test a table column is nullable with the above settings (which is also the default setting) +create table t1 (c1 int); +go + +insert into t1 values (NULL); +go + +-- Expect one row of NULL value +select c1 from t1; +go + +-- Test that ANSI_NULL_DFLT_ON can not be set to OFF and ANSI_NULL_DFLT_OFF can not be set to ON +set ANSI_NULL_DFLT_ON OFF; +go + +set ANSI_NULL_DFLT_OFF ON; +go + +-- Clean up +drop table if exists t1; +go + +-- reset to default +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_session_settings', 'ignore'; +GO diff --git a/contrib/test/JDBC/input/BABEL-1858.sql b/contrib/test/JDBC/input/BABEL-1858.sql new file mode 100644 index 00000000000..b9ba9b674fb --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1858.sql @@ -0,0 +1,38 @@ +USE master; +GO + +-- test volatility of function in batch +-- should see different id values with each iteration +DECLARE @i INT = 1 +DECLARE @num_iter INT = 5 +CREATE TABLE newid_volatile (u uniqueidentifier) +WHILE @i <= @num_iter +BEGIN + INSERT INTO newid_volatile VALUES (NEWID()) + SET @i = @i + 1 +END + +-- should be equal to @num_iter +select count(distinct u) from newid_volatile +go + +-- test volatility of function in procedure +-- should see different id values with each iteration +CREATE PROC p_newid AS +DECLARE @num_iter INT = 5 +DECLARE @i INT = 1 +CREATE TABLE newid_volatile_proc (u uniqueidentifier) +WHILE @i <= @num_iter +BEGIN + INSERT INTO newid_volatile_proc VALUES (NEWID()) + SET @i = @i + 1 +END +go +EXEC p_newid +-- should be equal to @num_iter +select count(distinct u) from newid_volatile_proc +GO + + +DROP TABLE newid_volatile +GO \ No newline at end of file diff --git a/contrib/test/JDBC/input/BABEL-1944.sql b/contrib/test/JDBC/input/BABEL-1944.sql new file mode 100644 index 00000000000..f23d696a079 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1944.sql @@ -0,0 +1,140 @@ +create table t1(a int); +go +create table t2(a int); +go +create procedure sp_trancount as +select @@trancount; +GO +create procedure sp_commit_no_begin as +insert into t1 values(3); +commit; +select * from t1; +GO +create procedure sp_rollback_no_begin as +insert into t1 values(4); +rollback; +select * from t1; +GO +create procedure sp_rollback_with_begin as +begin tran; +insert into t1 values(4); +rollback; +select * from t1; +go + +select @@trancount; +go +-- trancount inside normal EXEC should be same as outside +exec sp_trancount; +go +-- trancount inside INSERT-EXEC should be 1 more than outside +insert into t1 exec sp_trancount; +go +select * from t1; +go +delete t1; +go + +-- zero level - normal EXEC should succeed with warning for no BEGIN TRAN on the +-- COMMIT +exec sp_commit_no_begin; +go +-- zero level - INSERT-EXEC should fail with error message about the COMMIT +-- inside INSERT-EXEC must have a BEGIN TRAN +delete t1; +go +insert into t2 exec sp_commit_no_begin; +go +select count(*) from t1; +select count(*) from t2; +go + +-- one level - should fail and abort that level of transaction +begin tran; +go +select @@trancount; +go +insert into t2 execute sp_commit_no_begin; +go +select @@trancount; +go +select count(*) from t1; +select count(*) from t2; +go + +-- previous level aborted, this should be the same as before +begin tran; +go +select @@trancount; +go +insert into t2 execute sp_commit_no_begin; +go +select count(*) from t1; +select count(*) from t2; +go + +-- normal EXEC with COMMIT is allowed with one level - should succeed with +-- unbalanced level warning from 1 to 0 +begin tran; +go +select @@trancount; +go +execute sp_commit_no_begin; +go +select count(*) from t1; +select count(*) from t2; +go + +-- two levels - should succeed with unbalanced level warning from 2 to 1, and +-- should not send any Row tokens +select @@trancount; +go +begin tran; +go +begin tran; +go +select @@trancount; +go +insert into t2 execute sp_commit_no_begin; +go +select count(*) from t1; +select count(*) from t2; +go +select @@trancount; +go +commit; +go + +-- INSERT-EXEC with ROLLBACK in one level of transaction - should fail and abort +-- that level of transaction +begin tran; +go +select @@trancount; +go +insert into t2 exec sp_rollback_no_begin; +go +select @@trancount; +go + +begin tran; +go +select @@trancount; +go +insert into t2 exec sp_rollback_with_begin; +go +select @@trancount; +go + +-- cleanup +drop table t1; +go +drop table t2; +go +drop procedure sp_trancount; +go +drop procedure sp_commit_no_begin; +go +drop procedure sp_rollback_no_begin; +go +drop procedure sp_rollback_with_begin; +go diff --git a/contrib/test/JDBC/input/BABEL-1963.sql b/contrib/test/JDBC/input/BABEL-1963.sql new file mode 100644 index 00000000000..2da65ad6a90 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1963.sql @@ -0,0 +1,32 @@ +-- recursive procedure +-- should fail with stack depth reached error +CREATE PROC p1 AS +BEGIN + exec p1 +END +GO + +exec p1 +go + +-- recursive trigger +-- should fail with stack depth reached error +CREATE TABLE table2_1963 (a int) +GO + +CREATE TRIGGER trig2_1963 +ON table2_1963 +AFTER INSERT +AS insert into table2_1963 values (1) +GO + +insert into table2_1963 values(5) +go + + +-- cleanup +drop table table2_1963; +go + +drop procedure p1 +go \ No newline at end of file diff --git a/contrib/test/JDBC/input/BABEL-1975.sql b/contrib/test/JDBC/input/BABEL-1975.sql new file mode 100644 index 00000000000..e1c29f861ac --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1975.sql @@ -0,0 +1,34 @@ +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_session_settings', 'strict'; +GO + +DROP TABLE if EXISTS t1; +CREATE TABLE t1 (c1 int); +INSERT INTO t1 values (1); +INSERT INTO t1 values (2); +INSERT INTO t1 values (NULL); +GO + +SELECT * FROM t1; +SELECT @@rowcount; +GO + +SET ROWCOUNT 0; +SELECT @@rowcount; +GO + +SELECT * FROM t1; +SELECT @@rowcount; +GO + +-- test invalid settings +SET ROWCOUNT 1; +SELECT @@rowcount; +GO + +-- clean up +DROP TABLE t1; +GO + +-- reset to default +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_session_settings', 'ignore'; +GO diff --git a/contrib/test/JDBC/input/BABEL-1978.sql b/contrib/test/JDBC/input/BABEL-1978.sql new file mode 100644 index 00000000000..0caeb5fe5ee --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1978.sql @@ -0,0 +1,24 @@ +SET blah ON; +GO + +SET blahblah oh_yes; +GO + +SET auto_commit_batch on; -- existing bbf GUC +GO + +-- should fail even if escape_hatch_session_settings = 'ignore' +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_session_settings', 'ignore'; +GO + +SET blah ON; +GO + +SET blahblah oh_yes; +GO + +SET auto_commit_batch on; -- existing bbf GUC +GO + +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_session_settings', 'strict'; +GO diff --git a/contrib/test/JDBC/input/BABEL-1994-CHAR.sql b/contrib/test/JDBC/input/BABEL-1994-CHAR.sql new file mode 100644 index 00000000000..02dfb09c6ed --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1994-CHAR.sql @@ -0,0 +1,146 @@ +drop table if exists pad; +go + +create table pad( + c5nn char(5) not null, + c5n character(5) null +); +go + +insert into pad values('ab ', 'ab '); +create index pad_c5nn_idx on pad(c5nn); +go + +select + concat('[', c5nn, ']') as c5nn_concat, + '[' + c5nn +']' as c5nn_to_text_concat, + concat('[', cast(c5nn as varchar), ']') as c5nn_to_varchar_concat, + concat('[', c5n, ']') as c5n_concat, + '[' + c5n + ']' as c5n_to_text_concat, + concat('[', cast(c5n as varchar), ']') as c5n_to_varchar_concat, + concat('[', cast(c5n as name), ']') as c5n_to_name_concat +from pad; +go + +drop table pad; +go + +-- default length of CHAR should be 1. Otherwise, it will crash on the below select statement. +drop table if exists t1; +go + +CREATE TABLE t1 (c1 CHAR); +INSERT INTO t1 VALUES ('A'); +GO + +SELECT c1 from t1; +go + +drop table t1; +go + +-- In case of CAST, the default length of CHAR should be 30. +select datalength(cast('123 ' as char)); +go + +-- Cast from sys.BPCHAR +select + cast(cast('2021-08-15 ' as char(11)) as sys.smalldatetime), + cast(cast('2021-08-15 ' as char(11)) as sys.datetime2), + cast(cast('2021-08-15 ' as char(11)) as sys.datetime) +; +go + +select + cast(cast('decimal ' as char(8)) as sys.sql_variant), + cast(cast('abc ' as char(5)) as pg_catalog.varchar), + cast(cast('abc ' as char(5)) as pg_catalog.bpchar(4)), + cast(cast(' ' as char(12)) as pg_catalog.xml), + cast(cast('abc ' as char(5)) as pg_catalog.text), + cast(cast('abc ' as char(5)) as pg_catalog.name), + cast(cast('abc ' as char(5)) as pg_catalog.char(1)) +; +go + +-- Convert from sys.BPCHAR +select + convert(sys.sql_variant, cast('decimal ' as char(8))), + convert(sys.smalldatetime, cast('2021-08-15 ' as char(11))), + convert(sys.datetime2, cast('2021-08-15 ' as char(11))) +; +go + +select + convert(pg_catalog.varchar, cast('abc ' as char(5))), + convert(pg_catalog.bpchar(4), cast('abc ' as char(5))), + convert(pg_catalog.xml, cast(' ' as char(12))), + convert(pg_catalog.text, cast('abc ' as char(5))), + convert(pg_catalog.name, cast('abc ' as char(5))), + convert(pg_catalog.char(1), cast('abc ' as char(5))) +; +go + +-- CAST to sys.BPCHAR +select + cast(cast('2021-08-15 ' as sys.datetime) as char(20)), + cast(cast('2021-08-15 ' as sys.datetime2) as char(20)), + cast(cast('2021-08-15 ' as sys.smalldatetime) as char(20)), + cast(cast('decimal ' as sys.sql_variant) as char(8)), + cast(FALSE as char(6)), + cast(cast('a' as pg_catalog.char(1)) as char(3)) +; +go + +select + cast(cast('abc ' as pg_catalog.name) as char(4)), + cast(cast('128' as pg_catalog.cidr) as char(13)), + cast(cast('2001:4f8:3:ba::/64' as pg_catalog.inet) as char(20)), + cast(cast('abc ' as pg_catalog.text) as char(4)), + cast(cast(' ' as pg_catalog.xml) as char(12)), + cast(cast('abc ' as pg_catalog.bpchar(5)) as char(4)), + cast(cast('abc ' as pg_catalog.varchar) as char(4)) +; +go + +-- Convert to sys.BPCHAR +select + convert(char(20), cast('2021-08-15 ' as sys.datetime)), + convert(char(20), cast('2021-08-15 ' as sys.datetime2)), + convert(char(20), cast('2021-08-15 ' as sys.smalldatetime)), + convert(char(8), cast('decimal ' as sys.sql_variant)), + convert(char(6), FALSE), + convert(char(3), cast('a' as pg_catalog.char(1))) +; +go + +select + convert(char(4), cast('abc ' as pg_catalog.name)), + convert(char(13), cast('128' as pg_catalog.cidr)), + convert(char(20), cast('2001:4f8:3:ba::/64' as pg_catalog.inet)), + convert(char(4), cast('abc ' as pg_catalog.text)), + convert(char(12), cast(' ' as pg_catalog.xml)), + convert(char(4), cast('abc ' as pg_catalog.bpchar(5))), + convert(char(4), cast('abc ' as pg_catalog.varchar)) +; +go + +-- String functions +select + unicode(cast('a ' as char(5))), + reverse(cast('a ' as char(5))), + quotename(cast('a[] b ' as char(6))), + patindex('a %', cast('a ' as char(5))), + rtrim(cast('a ' as char(5))) +; +go + +select + lower(cast('A ' as char(5))), + left(cast('a ' as char(5)), 2), + charindex(cast('a ' as char(5)), 'a '), + ascii(cast('a ' as char(5))), + datalength(cast('123 ' as char(5))), + length(cast('123 ' as char(5))), + len(cast('123 ' as char(5))) +; +go \ No newline at end of file diff --git a/contrib/test/JDBC/input/BABEL-1994-VARCHAR.sql b/contrib/test/JDBC/input/BABEL-1994-VARCHAR.sql new file mode 100644 index 00000000000..32ab99b1d2a --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1994-VARCHAR.sql @@ -0,0 +1,130 @@ +drop table if exists person; +go +create table person( + name_vcnn varchar(10) not null primary key, + name_vcn varchar(10) null +); +go + +insert into person values ('smith', 'smith'); +go +insert into person values ('jones ', 'jones '); +go +insert into person values ('jones ', 'jones '); +go + +select count(*) from person where name_vcnn = 'smith '; +go +select count(*) from person where name_vcn = 'smith '; +go +select count(*) from person where name_vcnn = 'jones '; +go +select count(*) from person where name_vcn = 'jones '; +go +select count(*) from person where name_vcn = 'jones '; +go + +drop table person; +go + +-- Cast from VARCHAR +select + cast(cast('2021-08-15 ' as varchar(11)) as smalldatetime), + cast(cast('2021-08-15 ' as varchar(11)) as datetime2), + cast(cast('2021-08-15 ' as varchar(11)) as datetime) +; +go + +select + cast(cast('decimal ' as varchar(8)) as sql_variant), + cast(cast('abc ' as varchar(5)) as pg_catalog.varchar), + cast(cast('abc ' as varchar(5)) as pg_catalog.bpchar(4)), + cast(cast(' ' as varchar(12)) as xml), + cast(cast('abc ' as varchar(5)) as text), + cast(cast('abc ' as varchar(5)) as name), + cast(cast('abc ' as varchar(5)) as char(1)) +; +go + +-- Convert from VARCHAR +select + convert(sql_variant, cast('decimal ' as varchar(8))), + convert(smalldatetime, cast('2021-08-15 ' as varchar(11))), + convert(datetime2, cast('2021-08-15 ' as varchar(11))) +; +go + +select + convert(pg_catalog.varchar, cast('abc ' as varchar(5))), + convert(pg_catalog.bpchar(4), cast('abc ' as varchar(5))), + convert(xml, cast(' ' as varchar(12))), + convert(text, cast('abc ' as varchar(5))), + convert(name, cast('abc ' as varchar(5))), + convert(char(1), cast('abc ' as varchar(5))) +; +go + +-- CAST to VARCHAR +select + cast(cast('2021-08-15 ' as datetime) as varchar(20)), + cast(cast('2021-08-15 ' as datetime2) as varchar(20)), + cast(cast('2021-08-15 ' as smalldatetime) as varchar(20)), + cast(cast('decimal ' as sql_variant) as varchar(8)), + cast(FALSE as varchar(6)), + cast(cast('a' as char(1)) as varchar(3)) +; +go + +select + cast(cast('abc ' as name) as varchar(4)), + cast(cast('128' as cidr) as varchar(13)), + cast(cast('2001:4f8:3:ba::/64' as inet) as varchar(20)), + cast(cast('abc ' as text) as varchar(4)), + cast(cast(' ' as xml) as varchar(12)), + cast(cast('abc ' as pg_catalog.bpchar(5)) as varchar(4)), + cast(cast('abc ' as pg_catalog.varchar) as varchar(4)) +; +go + +-- Convert to VARCHAR +select + convert(varchar(20), cast('2021-08-15 ' as datetime)), + convert(varchar(20), cast('2021-08-15 ' as datetime2)), + convert(varchar(20), cast('2021-08-15 ' as smalldatetime)), + convert(varchar(8), cast('decimal ' as sql_variant)), + convert(varchar(6), FALSE), + convert(varchar(3), cast('a' as pg_catalog.char(1))) +; +go + +select + convert(varchar(4), cast('abc ' as name)), + convert(varchar(13), cast('128' as cidr)), + convert(varchar(20), cast('2001:4f8:3:ba::/64' as inet)), + convert(varchar(4), cast('abc ' as text)), + convert(varchar(12), cast(' ' as xml)), + convert(varchar(4), cast('abc ' as pg_catalog.bpchar(5))), + convert(varchar(4), cast('abc ' as pg_catalog.varchar)) +; +go + +-- String functions +select + unicode(cast('a ' as varchar(5))), + reverse(cast('a ' as varchar(5))), + quotename(cast('a[] b ' as varchar(6))), + patindex('a %', cast('a ' as varchar(5))), + rtrim(cast('a ' as varchar(5))) +; +go + +select + lower(cast('A ' as varchar(5))), + left(cast('a ' as varchar(5)), 2), + charindex(cast('a ' as varchar(5)), 'a '), + ascii(cast('a ' as varchar(5))), + datalength(cast('123 ' as varchar(5))), + length(cast('123 ' as varchar(5))), + len(cast('123 ' as varchar(5))) +; +go \ No newline at end of file diff --git a/contrib/test/JDBC/input/BABEL-1997.sql b/contrib/test/JDBC/input/BABEL-1997.sql new file mode 100644 index 00000000000..20d79a1a56a --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-1997.sql @@ -0,0 +1,25 @@ +--create +CREATE TABLE t1997_1(c1 int primary key, c2 int) +GO +CREATE TABLE t1997_2(c1 int primary key, c2 int, constraint fk foreign key (c2) references t1997_1(c1)) +GO +INSERT INTO t1997_1 VALUES(1, 10) +INSERT INTO t1997_2 VALUES(100, 1) +GO +--generate error +begin tran + begin try + TRUNCATE TABLE t1997_1; + end try + begin catch + select xact_state(); + DROP TABLE t1997_2 + DROP TABLE t1997_1 + end catch +go + +--clean +DROP TABLE t1997_2 +GO +DROP TABLE t1997_1 +GO diff --git a/contrib/test/JDBC/input/BABEL-2010.sql b/contrib/test/JDBC/input/BABEL-2010.sql new file mode 100644 index 00000000000..57e6c0c7108 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2010.sql @@ -0,0 +1,31 @@ +DECLARE @a VARCHAR(50); +SELECT @a = 'SELECT ''hello world'''; +EXEC (@a); +go + +-- BABEL-1388, BABEL-2010 +DECLARE @a VARCHAR(50); +SELECT @a = 'DROP PROCEDURE myproc'; +EXEC @a; +go + +-- Error, procedure called does not exist +DECLARE @a VARCHAR(50) = 'babel_2010_proc'; +EXEC @a; +go + +CREATE PROC babel_2010_proc AS +SELECT 'hello'; +go + +-- Need support for: +-- EXEC @module_name_var +-- where @module_name_var is a variable +-- whose value is a proc/func name. +-- Should pass after BABEL-341 is fixed. +DECLARE @a VARCHAR(50) = 'babel_2010_proc'; +EXEC @a; +go + +DROP PROC babel_2010_proc +go diff --git a/contrib/test/JDBC/input/BABEL-2011.sql b/contrib/test/JDBC/input/BABEL-2011.sql new file mode 100644 index 00000000000..c919fc5b9db --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2011.sql @@ -0,0 +1,29 @@ +USE master; +GO + +-- test volatility of functions in multi-row insert +-- newsequentialid() +CREATE TABLE myTable (ColumnA uniqueidentifier DEFAULT NEWSEQUENTIALID(), a int); +go +insert myTable (a) values (1), (2) +go +-- should be equal to 2 +select count(distinct a) from myTable +go + +-- newid() +CREATE TABLE t1_2011 (a int); +CREATE TABLE myTable2 (ColumnA uniqueidentifier, a int); +go +insert t1_2011 (a) values (1), (2) +go +insert myTable2 select newid(), a from t1_2011 +go +-- should be equal to 2 +select count(distinct a) from myTable2 +go + +drop table myTable2; +drop table myTable; +drop table t1_2011; +go \ No newline at end of file diff --git a/contrib/test/JDBC/input/BABEL-2020-DELETE.sql b/contrib/test/JDBC/input/BABEL-2020-DELETE.sql new file mode 100644 index 00000000000..2d5e1084511 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2020-DELETE.sql @@ -0,0 +1,138 @@ +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 babel_2020_delete_t1 from babel_2020_delete_t1 x; +go + +exec babel_2020_delete_ct; +delete babel_2020_delete_t1 from babel_2020_delete_t1 x where x.a = 2; +go + +-- 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; +go + +exec babel_2020_delete_ct; +delete babel_2020_delete_t1 from babel_2020_delete_t1 x, babel_2020_delete_t2 y where x.a = 2; +go + +exec babel_2020_delete_ct; +delete babel_2020_delete_t1 from babel_2020_delete_t1 x, babel_2020_delete_t2 y where y.a = 2; +go + +exec babel_2020_delete_ct; +delete babel_2020_delete_t1 from babel_2020_delete_t1 x, babel_2020_delete_t2 y where x.a = y.a; +go + +-- 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; +go + +exec babel_2020_delete_ct; +delete babel_2020_delete_t1 from babel_2020_delete_t1 x join babel_2020_delete_t2 y on x.a = 2; +go + +exec babel_2020_delete_ct; +delete babel_2020_delete_t1 from babel_2020_delete_t1 x join babel_2020_delete_t2 y on y.a = 2; +go + +exec babel_2020_delete_ct; +delete babel_2020_delete_t1 from babel_2020_delete_t1 x join babel_2020_delete_t2 y on x.a = y.a; +go + +-- subqueries +exec babel_2020_delete_ct; +delete babel_2020_delete_t1 from (select * from babel_2020_delete_t1) x; +go + +exec babel_2020_delete_ct; +delete babel_2020_delete_t1 from babel_2020_delete_t1 x, (select * from babel_2020_delete_t1) y; +go + +-- self join +exec babel_2020_delete_ct; +delete babel_2020_delete_t1 from babel_2020_delete_t1 x, (select * from babel_2020_delete_t1) y where x.a + 1 = y.a; +go + +exec babel_2020_delete_ct; +delete babel_2020_delete_t1 from babel_2020_delete_t1 y, (select * from babel_2020_delete_t1) x where x.a + 1 = y.a; +go + +exec babel_2020_delete_ct; +delete babel_2020_delete_t1 from babel_2020_delete_t1 x join babel_2020_delete_t1 on babel_2020_delete_t1.a + 1 = x.a; +go + +exec babel_2020_delete_ct; +delete babel_2020_delete_t1 from babel_2020_delete_t1 join babel_2020_delete_t1 x on babel_2020_delete_t1.a + 1 = x.a; +go + +exec babel_2020_delete_ct; +delete babel_2020_delete_t1 from babel_2020_delete_t1 x, babel_2020_delete_t1 y where x.a + 1 = y.a; +go + +-- outer joins +exec babel_2020_delete_ct; +delete 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 + +exec babel_2020_delete_ct; +delete babel_2020_delete_t1 from babel_2020_delete_t2 left outer join babel_2020_delete_t1 x on babel_2020_delete_t2.a = x.a; +go + +-- null filters +exec babel_2020_delete_ct; +delete babel_2020_delete_t1 from babel_2020_delete_t1 x where x.a is null; +go + +exec babel_2020_delete_ct; +delete babel_2020_delete_t1 from babel_2020_delete_t2 left outer join babel_2020_delete_t1 x on x.a is null; +go + +-- updatable views +drop view if exists babel_2020_delete_v1; +go + +exec babel_2020_delete_ct; +go + +create view babel_2020_delete_v1 as select * from babel_2020_delete_t1 where babel_2020_delete_t1.a is not null; +go + +delete babel_2020_delete_v1 from babel_2020_delete_v1 x where x.a = 2; +go + +drop view if exists babel_2020_delete_v1; +go + +-- semi joins +exec babel_2020_delete_ct; +delete babel_2020_delete_t1 from babel_2020_delete_t1 x where x.a in (select a from babel_2020_delete_t1 where babel_2020_delete_t1.a = x.a); +go + +exec babel_2020_delete_ct; +delete 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 + +exec babel_2020_delete_ct; +delete babel_2020_delete_t1 from babel_2020_delete_t1 x where exists (select a from babel_2020_delete_t1 y where y.a + 1 = x.a); +go + +drop procedure if exists babel_2020_delete_ct; +drop table if exists babel_2020_delete_t1; +drop table if exists babel_2020_delete_t2; +go \ No newline at end of file diff --git a/contrib/test/JDBC/input/BABEL-2020-UPDATE.sql b/contrib/test/JDBC/input/BABEL-2020-UPDATE.sql new file mode 100644 index 00000000000..a3124fd52f2 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2020-UPDATE.sql @@ -0,0 +1,138 @@ +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 babel_2020_update_t1 set a = 100 from babel_2020_update_t1 x; +go + +exec babel_2020_update_ct; +update babel_2020_update_t1 set a = 100 from babel_2020_update_t1 x where x.a = 2; +go + +-- multiple tables in FROM clause +exec babel_2020_update_ct; +update babel_2020_update_t1 set a = 100 from babel_2020_update_t1 x, babel_2020_update_t2 y; +go + +exec babel_2020_update_ct; +update babel_2020_update_t1 set a = 100 from babel_2020_update_t1 x, babel_2020_update_t2 y where x.a = 2; +go + +exec babel_2020_update_ct; +update babel_2020_update_t1 set a = 100 from babel_2020_update_t1 x, babel_2020_update_t2 y where y.a = 2; +go + +exec babel_2020_update_ct; +update babel_2020_update_t1 set a = 100 from babel_2020_update_t1 x, babel_2020_update_t2 y where x.a = y.a; +go + +-- JOIN clause +exec babel_2020_update_ct; +update babel_2020_update_t1 set a = 100 from babel_2020_update_t1 x join babel_2020_update_t2 y on 1 = 1; +go + +exec babel_2020_update_ct; +update babel_2020_update_t1 set a = 100 from babel_2020_update_t1 x join babel_2020_update_t2 y on x.a = 2; +go + +exec babel_2020_update_ct; +update babel_2020_update_t1 set a = 100 from babel_2020_update_t1 x join babel_2020_update_t2 y on y.a = 2; +go + +exec babel_2020_update_ct; +update babel_2020_update_t1 set a = 100 from babel_2020_update_t1 x join babel_2020_update_t2 y on x.a = y.a; +go + +-- subqueries +exec babel_2020_update_ct; +update babel_2020_update_t1 set a = 100 from (select * from babel_2020_update_t1) x; +go + +exec babel_2020_update_ct; +update babel_2020_update_t1 set a = 100 from babel_2020_update_t1 x, (select * from babel_2020_update_t1) y; +go + +-- self join +exec babel_2020_update_ct; +update babel_2020_update_t1 set a = 100 from babel_2020_update_t1 x, (select * from babel_2020_update_t1) y where x.a + 1 = y.a; +go + +exec babel_2020_update_ct; +update babel_2020_update_t1 set a = 100 from babel_2020_update_t1 y, (select * from babel_2020_update_t1) x where x.a + 1 = y.a; +go + +exec babel_2020_update_ct; +update babel_2020_update_t1 set a = 100 from babel_2020_update_t1 x join babel_2020_update_t1 on babel_2020_update_t1.a + 1 = x.a; +go + +exec babel_2020_update_ct; +update babel_2020_update_t1 set a = 100 from babel_2020_update_t1 join babel_2020_update_t1 x on babel_2020_update_t1.a + 1 = x.a; +go + +exec babel_2020_update_ct; +update babel_2020_update_t1 set a = 100 from babel_2020_update_t1 x, babel_2020_update_t1 y where x.a + 1 = y.a; +go + +-- outer joins +exec babel_2020_update_ct; +update 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 + +exec babel_2020_update_ct; +update babel_2020_update_t1 set a = 100 from babel_2020_update_t2 left outer join babel_2020_update_t1 x on babel_2020_update_t2.a = x.a; +go + +-- null filters +exec babel_2020_update_ct; +update babel_2020_update_t1 set a = 100 from babel_2020_update_t1 x where x.a is null; +go + +exec babel_2020_update_ct; +update babel_2020_update_t1 set a = 100 from babel_2020_update_t2 left outer join babel_2020_update_t1 x on x.a is null; +go + +-- updatable views +drop view if exists babel_2020_update_v1; +go + +exec babel_2020_update_ct; +go + +create view babel_2020_update_v1 as select * from babel_2020_update_t1 where babel_2020_update_t1.a is not null; +go + +update babel_2020_update_v1 set a = 100 from babel_2020_update_v1 x where x.a = 2; +go + +drop view if exists babel_2020_update_v1; +go + +-- semi joins +exec babel_2020_update_ct; +update babel_2020_update_t1 set a = 100 from babel_2020_update_t1 x where x.a in (select a from babel_2020_update_t1 where babel_2020_update_t1.a = x.a); +go + +exec babel_2020_update_ct; +update 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 + +exec babel_2020_update_ct; +update babel_2020_update_t1 set a = 100 from babel_2020_update_t1 x where exists (select a from babel_2020_update_t1 y where y.a + 1 = x.a); +go + +drop procedure if exists babel_2020_update_ct; +drop table if exists babel_2020_update_t1; +drop table if exists babel_2020_update_t2; +go \ No newline at end of file diff --git a/contrib/test/JDBC/input/BABEL-2034.sql b/contrib/test/JDBC/input/BABEL-2034.sql new file mode 100644 index 00000000000..214ab5eb80d --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2034.sql @@ -0,0 +1,79 @@ +CREATE TABLE EasDateTime (EasDateTime pg_catalog.timestamp, LastUpdDateTime pg_catalog.timestamp, LastCompressionMaxDate pg_catalog.timestamp, CompressionRate real); +GO + +-- Test ITVF - column references such as "easdatetime" in the query collides +-- with the column names of the returned rows - should not throw error +CREATE FUNCTION CalculateEasDateTime ( @InputDate DATETIME = NULL ) RETURNS TABLE AS RETURN ( +WITH +RawValues AS (SELECT EasDateTime, LastUpdDateTime, LastCompressionMaxDate, ISNULL(CompressionRate, 1.0) AS compressionrate, ISNULL(NULL, CURRENT_TIMESTAMP) AS currdatetime FROM EasDateTime), + +RawValues2 AS (SELECT ISNULL(EasDateTime, currdatetime) AS easdatetime, ISNULL(LastUpdDateTime, currdatetime) AS lastupddatetime, LastCompressionMaxDate, currdatetime, compressionrate FROM RawValues), + +Calcs AS (SELECT easdatetime, lastupddatetime, LastCompressionMaxDate, compressionrate, currdatetime, CASE WHEN easdatetime IS NULL THEN currdatetime ELSE DATEADD(s, DATEDIFF(s, lastupddatetime, currdatetime) * compressionrate, easdatetime) END AS adjeasdatetime FROM RawValues2), + +UnionedWithDefaults AS (SELECT easdatetime, lastupddatetime, LastCompressionMaxDate, compressionrate, currdatetime, adjeasdatetime AdjDatetimeWithoutCap, 2 WeightToForceDefault FROM Calcs UNION SELECT GETDATE() easdatetime, GETDATE() lastupddatetime, GETDATE() LastCompressionMaxDate, 1.0 compressionrate, GETDATE() currdatetime, GETDATE() AdjDatetimeWithoutCap, 1 WeightToForceDefault) + +SELECT TOP 1 easdatetime, lastupddatetime, LastCompressionMaxDate, compressionrate, currdatetime, AdjDatetimeWithoutCap FROM UnionedWithDefaults ORDER BY WeightToForceDefault DESC +); +GO + +SELECT count(*) FROM CalculateEasDateTime(); +GO + +-- Test MSTVF - the return parameter @tableVar should be added to the namespace +-- so that it can prevent duplicate parameter/variable names +-- Correct case - no duplicate +create function mstvf(@i int) returns @tableVar table +( + a text not null, + b int primary key, + c int +) +as +begin + insert into @tableVar values('hello1', 1, 100); + insert into @tableVar values('hello2', 2, 200); + return; +end; +GO +select * from mstvf(1); +GO + +-- Duplicate parameter name - should throw error +create function mstvf_dup_input_arg(@tableVar int) returns @tableVar table +( + a text not null, + b int primary key, + c int +) +as +begin + insert into @tableVar values('hello1', 1, 100); + insert into @tableVar values('hello2', 2, 200); + return; +end; +GO + +-- Duplicate variable name - should throw error +create function mstvf_dup_local_arg(@i int) returns @tableVar table +( + a text not null, + b int primary key, + c int +) +as +begin + declare @tableVar int; + insert into @tableVar values('hello1', 1, 100); + insert into @tableVar values('hello2', 2, 200); + return; +end; +GO + +-- cleanup +DROP FUNCTION CalculateEasDateTime; +GO +DROP TABLE EasDateTime; +GO +drop function mstvf; +go diff --git a/contrib/test/JDBC/input/BABEL-2049.sql b/contrib/test/JDBC/input/BABEL-2049.sql new file mode 100644 index 00000000000..43d23d17935 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2049.sql @@ -0,0 +1,62 @@ +create table t_babel_2049 (a int, b int); +insert into t_babel_2049 values (10, 1); +go + +declare @v int=1; +set @v+=10 +select @v +go + +declare @v int=11; +set @v-=10; +select @v; +go + +declare @v int=2; +set @v*=10; +select @v; +go + +declare @v int=20; +set @v/=10; +select @v; +go + +declare @v int=24; +set @v%=10; +select @v; +go + +declare @v int=63; +set @v&=10; +select @v; +go + +declare @v int=7; +set @v|=10; +select @v; +go + +declare @v int=7; +set @v^=10; +select @v; +go + +declare @a int=-10; +declare @v int=1; +set @v+=abs(@a) +select @v +go + +declare @v int=1; +set @v+=-10; +select @v +go + +declare @v int=1; +set @v+=+10; +select @v +go + +drop table t_babel_2049; +go diff --git a/contrib/test/JDBC/input/BABEL-2051.sql b/contrib/test/JDBC/input/BABEL-2051.sql new file mode 100644 index 00000000000..a4ed0ab00c5 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2051.sql @@ -0,0 +1,12 @@ +USE MASTER +go + +USE master +GO + +-- test square brackets +USE [master] +GO + +USE [maSter] +GO diff --git a/contrib/test/JDBC/input/BABEL-2060.sql b/contrib/test/JDBC/input/BABEL-2060.sql new file mode 100644 index 00000000000..4b1071c0037 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2060.sql @@ -0,0 +1,104 @@ +use master; +go + +declare @a int; +select @a=1 union all select 1; +go + +declare @a int; +select @a=1 union all select @a=2; +go + +declare @a int; +select 1 union all select @a=2; +go + +declare @a int; +select @a=1 except select 1; +go + +declare @a int; +select @a=1 except select @a=2; +go + +declare @a int; +select 1 except select @a=2; +go + +declare @a int; +select @a=1 intersect select 1; +go + +declare @a int; +select @a=1 intersect select @a=2; +go + +declare @a int; +select 1 intersect select @a=2; +go + +-- derived table +declare @a int; +select @a=a from (select 1 as a) T; +select case when @a = 1 then 'ok' else 'wrong' end as result; +go + +declare @a int; +select 1 from (select @a=1) T; +go + +declare @a int; +select 1 from (select @a=1 union all select 1) T; +go + +declare @a int; +select 1 from (select 1 union all select @a=1) T; +go + +declare @a int, @b int; +select @b=1 from (select @a=1) T; +go + +declare @a int, @b int; +select @b=1 from (select @a=1 union all select 1) T; +go + +declare @a int, @b int; +select @b=1 from (select 1 union all select @a=1) T; +go + +-- subquery +declare @a int; +select @a=(select 1); +select case when @a = 1 then 'ok' else 'wrong' end as result; +go + +declare @a int; +select (select @a=1); +go + +declare @a int; +select (select @a=1 union all select 1); +go + +declare @a int; +select (select 1 union all select @a=1); +go + +-- cte +declare @a int; +with T as (select 1 as a) select @a=a from T; +select case when @a = 1 then 'ok' else 'wrong' end as result; +go + +declare @a int; +with T as (select @a=1) select * from T; +go + +declare @a int; +with T as (select @a=1 union all select 1) select * from T; +go + +declare @a int; +with T as (select 1 union all select @a=1) select * from T; +go diff --git a/contrib/test/JDBC/input/BABEL-2079.sql b/contrib/test/JDBC/input/BABEL-2079.sql new file mode 100644 index 00000000000..24a8917ee1a --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2079.sql @@ -0,0 +1,44 @@ +create schema error_mapping; +GO + +CREATE TABLE t3616(id int); +GO +CREATE TRIGGER t3616Trigger +ON t3616 +AFTER INSERT +AS +BEGIN + BEGIN TRY + BEGIN TRAN + INSERT INTO t3616 VALUES (2) + COMMIT TRAN + END TRY + BEGIN CATCH + END CATCH +END +GO + +create procedure error_mapping.ErrorHandling1 as +begin +INSERT INTO t3616 values (1) +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +end +GO + +SET NOCOUNT ON +GO + +exec error_mapping.ErrorHandling1; +GO + +select * from t3616; +GO + +drop table t3616; +GO + +drop procedure error_mapping.ErrorHandling1; +GO + +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/input/BABEL-2086.sql b/contrib/test/JDBC/input/BABEL-2086.sql new file mode 100644 index 00000000000..e437810dd16 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2086.sql @@ -0,0 +1,286 @@ +CREATE TABLE testing(col varchar(20) COLLATE latin1_general_90_bin2); +INSERT INTO testing VALUES ('COLLATION'); +SELECT * FROM testing; +GO +DROP TABLE testing; +GO + +CREATE TABLE testing(col varchar(20) COLLATE latin1_general_ci_as); +INSERT INTO testing VALUES ('COLLATION'); +SELECT * FROM testing; +GO +DROP TABLE testing; +GO + +CREATE TABLE testing(col varchar(20) COLLATE sql_latin1_general_cp1250_ci_as); +INSERT INTO testing VALUES ('COLLATION'); +SELECT * FROM testing; +GO +DROP TABLE testing; +GO + +CREATE TABLE testing(col varchar(20) COLLATE sql_latin1_general_cp1251_cs_as); +INSERT INTO testing VALUES ('COLLATION'); +SELECT * FROM testing; +GO +DROP TABLE testing; +GO + +CREATE TABLE testing(col varchar(20) COLLATE sql_latin1_general_cp1253_ci_as); +INSERT INTO testing VALUES ('COLLATION'); +SELECT * FROM testing; +GO +DROP TABLE testing; +GO + +CREATE TABLE testing(col varchar(20) COLLATE sql_latin1_general_cp1254_ci_as); +INSERT INTO testing VALUES ('COLLATION'); +SELECT * FROM testing; +GO +DROP TABLE testing; +GO + +CREATE TABLE testing(col varchar(20) COLLATE sql_latin1_general_cp1255_cs_as); +INSERT INTO testing VALUES ('COLLATION'); +SELECT * FROM testing; +GO +DROP TABLE testing; +GO + +CREATE TABLE testing(col varchar(20) COLLATE sql_latin1_general_cp1256_cs_as); +INSERT INTO testing VALUES ('COLLATION'); +SELECT * FROM testing; +GO +DROP TABLE testing; +GO + +CREATE TABLE testing(col varchar(20) COLLATE sql_latin1_general_cp1257_cs_as); +INSERT INTO testing VALUES ('COLLATION'); +SELECT * FROM testing; +GO +DROP TABLE testing; +GO + +CREATE TABLE testing(col varchar(20) COLLATE sql_latin1_general_cp1258_cs_as); +INSERT INTO testing VALUES ('COLLATION'); +SELECT * FROM testing; +GO +DROP TABLE testing; +GO + +CREATE TABLE testing(col varchar(20) COLLATE sql_latin1_general_cp1_cs_ai); +INSERT INTO testing VALUES ('COLLATION'); +SELECT * FROM testing; +GO +DROP TABLE testing; +GO + +CREATE TABLE testing(col varchar(20) COLLATE sql_latin1_general_cp874_ci_as); +INSERT INTO testing VALUES ('COLLATION'); +SELECT * FROM testing; +GO +DROP TABLE testing; +GO + +CREATE TABLE testing(col varchar(20) COLLATE arabic_ci_ai); +INSERT INTO testing VALUES ('COLLATION'); +SELECT * FROM testing; +GO +DROP TABLE testing; +GO + +CREATE TABLE testing(col varchar(20) COLLATE bbf_unicode_bin2); +INSERT INTO testing VALUES ('COLLATION'); +SELECT * FROM testing; +GO +DROP TABLE testing; +GO + +CREATE TABLE testing(col varchar(20) COLLATE bbf_unicode_cp1250_ci_as); +INSERT INTO testing VALUES ('COLLATION'); +SELECT * FROM testing; +GO +DROP TABLE testing; +GO + +CREATE TABLE testing(col varchar(20) COLLATE bbf_unicode_cp1251_ci_as); +INSERT INTO testing VALUES ('COLLATION'); +SELECT * FROM testing; +GO +DROP TABLE testing; +GO + +CREATE TABLE testing(col varchar(20) COLLATE bbf_unicode_cp1253_ci_as); +INSERT INTO testing VALUES ('COLLATION'); +SELECT * FROM testing; +GO +DROP TABLE testing; +GO + +CREATE TABLE testing(col varchar(20) COLLATE bbf_unicode_cp1254_ci_ai); +INSERT INTO testing VALUES ('COLLATION'); +SELECT * FROM testing; +GO +DROP TABLE testing; +GO + +CREATE TABLE testing(col varchar(20) COLLATE bbf_unicode_cp1255_cs_as); +INSERT INTO testing VALUES ('COLLATION'); +SELECT * FROM testing; +GO +DROP TABLE testing; +GO + +CREATE TABLE testing(col varchar(20) COLLATE bbf_unicode_pref_cp1256_cs_as); +INSERT INTO testing VALUES ('COLLATION'); +SELECT * FROM testing; +GO +DROP TABLE testing; +GO + +CREATE TABLE testing(col varchar(20) COLLATE bbf_unicode_cp1257_cs_as); +INSERT INTO testing VALUES ('COLLATION'); +SELECT * FROM testing; +GO +DROP TABLE testing; +GO + +CREATE TABLE testing(col varchar(20) COLLATE bbf_unicode_cp1258_cs_as); +INSERT INTO testing VALUES ('COLLATION'); +SELECT * FROM testing; +GO +DROP TABLE testing; +GO + +CREATE TABLE testing(col varchar(20) COLLATE bbf_unicode_cp1_cs_as); +INSERT INTO testing VALUES ('COLLATION'); +SELECT * FROM testing; +GO +DROP TABLE testing; +GO + +CREATE TABLE testing(col varchar(20) COLLATE bbf_unicode_cp874_cs_as); +INSERT INTO testing VALUES ('COLLATION'); +SELECT * FROM testing; +GO +DROP TABLE testing; +GO + +CREATE TABLE testing(col varchar(20) COLLATE bbf_unicode_general_cs_ai); +INSERT INTO testing VALUES ('COLLATION'); +SELECT * FROM testing; +GO +DROP TABLE testing; +GO + +CREATE TABLE testing(col varchar(20) COLLATE Chinese_PRC_CI_AI); +INSERT INTO testing VALUES ('COLLATION'); +SELECT * FROM testing; +GO +DROP TABLE testing; +GO + +CREATE TABLE testing(col varchar(20) COLLATE Cyrillic_General_CS_AS); +INSERT INTO testing VALUES ('COLLATION'); +SELECT * FROM testing; +GO +DROP TABLE testing; +GO + +CREATE TABLE testing(col varchar(20) COLLATE Estonian_CI_AI); +INSERT INTO testing VALUES ('COLLATION'); +SELECT * FROM testing; +GO +DROP TABLE testing; +GO + +CREATE TABLE testing(col varchar(20) COLLATE Finnish_Swedish_CI_AI); +INSERT INTO testing VALUES ('COLLATION'); +SELECT * FROM testing; +GO +DROP TABLE testing; +GO + +CREATE TABLE testing(col varchar(20) COLLATE French_CS_AS); +INSERT INTO testing VALUES ('COLLATION'); +SELECT * FROM testing; +GO +DROP TABLE testing; +GO + +CREATE TABLE testing(col varchar(20) COLLATE Greek_CS_AS); +INSERT INTO testing VALUES ('COLLATION'); +SELECT * FROM testing; +GO +DROP TABLE testing; +GO + +CREATE TABLE testing(col varchar(20) COLLATE Hebrew_CS_AS); +INSERT INTO testing VALUES ('COLLATION'); +SELECT * FROM testing; +GO +DROP TABLE testing; +GO + +CREATE TABLE testing(col varchar(20) COLLATE Korean_Wansung_CS_AS); +INSERT INTO testing VALUES ('COLLATION'); +SELECT * FROM testing; +GO +DROP TABLE testing; +GO + +CREATE TABLE testing(col varchar(20) COLLATE Modern_Spanish_CS_AS); +INSERT INTO testing VALUES ('COLLATION'); +SELECT * FROM testing; +GO +DROP TABLE testing; +GO + +CREATE TABLE testing(col varchar(20) COLLATE Mongolian_CI_AS); +INSERT INTO testing VALUES ('COLLATION'); +SELECT * FROM testing; +GO +DROP TABLE testing; +GO + +CREATE TABLE testing(col varchar(20) COLLATE Polish_CI_AS); +INSERT INTO testing VALUES ('COLLATION'); +SELECT * FROM testing; +GO +DROP TABLE testing; +GO + +CREATE TABLE testing(col varchar(20) COLLATE Thai_CS_AS); +INSERT INTO testing VALUES ('COLLATION'); +SELECT * FROM testing; +GO +DROP TABLE testing; +GO + +CREATE TABLE testing(col varchar(20) COLLATE Traditional_Spanish_CS_AS); +INSERT INTO testing VALUES ('COLLATION'); +SELECT * FROM testing; +GO +DROP TABLE testing; +GO + +CREATE TABLE testing(col varchar(20) COLLATE Turkish_CI_AS); +INSERT INTO testing VALUES ('COLLATION'); +SELECT * FROM testing; +GO +DROP TABLE testing; +GO + +CREATE TABLE testing(col varchar(20) COLLATE Ukrainian_CI_AI); +INSERT INTO testing VALUES ('COLLATION'); +SELECT * FROM testing; +GO +DROP TABLE testing; +GO + +CREATE TABLE testing(col varchar(20) COLLATE Vietnamese_CS_AS); +INSERT INTO testing VALUES ('COLLATION'); +SELECT * FROM testing; +GO +DROP TABLE testing; +GO diff --git a/contrib/test/JDBC/input/BABEL-2089.sql b/contrib/test/JDBC/input/BABEL-2089.sql new file mode 100644 index 00000000000..be75f5589f0 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2089.sql @@ -0,0 +1,384 @@ +USE master; +GO + +-- the problem is not reproducible with simple query +-- because it depends PG optimizer's decision. +-- use the almost same query with customer system. + +CREATE TABLE babel_2089_Rpd( + RpdId int NOT NULL, + Title nvarchar(max) NOT NULL, + Severity nvarchar(max) NOT NULL, + Type nvarchar(max) NOT NULL, + Priority nvarchar(max) NOT NULL, + Status nvarchar(max) NULL, + AuthorId varchar(50) NOT NULL, + AuthorType varchar(14) NOT NULL, + AuthorName nvarchar(128) NULL, + EntityType nvarchar(max) NULL, + Entity nvarchar(max) NULL, + CreatedDate datetime NOT NULL, + LastCommentDate datetime NULL, + ResolvedDate datetime NULL, + SBUpdateDate datetime NULL, + createdAt datetime2(7) NULL, + updatedAt datetime2(7) NULL, + Difficulty nvarchar(max) NULL, + LocationId int NULL, + ResolutionCode nvarchar(50) NULL, + Supplier varchar(255) NULL, + IsPaidImplementation bit NULL, +PRIMARY KEY CLUSTERED +( + RpdId 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 + +CREATE TABLE babel_2089_RpdToOpsDbInstance( + RpdId int NOT NULL, + OpsDbInstanceId int NOT NULL, +PRIMARY KEY CLUSTERED +( + RpdId ASC, + OpsDbInstanceId 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 + +CREATE TABLE babel_2089_RpdMetaDataItem( + RpdId int NOT NULL, + Item varchar(50) NOT NULL, + Value nvarchar(300) NULL, + createdAt datetime2(7) NULL, + updatedAt datetime2(7) NULL +) ON [PRIMARY] +GO +CREATE TABLE babel_2089_RpdNextSopStep( + rpdid int NOT NULL, + TeamId int NOT NULL, + TeamName nvarchar(30) NOT NULL, + SopId int NOT NULL, + StepId int NOT NULL, + StepSequence int NOT NULL, + TaskId int NOT NULL, + StepName varchar(100) NULL, + CompletedDate datetime2(7) NULL, + totalSops int NULL, + completedSops int NULL, + done int NOT NULL, + Ready int NOT NULL, + lastStepCompletedDate datetime2(7) NULL, + TimelinessTarget int NULL, +PRIMARY KEY CLUSTERED +( + rpdid ASC, + StepId 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 +CREATE TABLE babel_2089_RpdAssignee( + RpdId int NOT NULL, + EmployeeId int NOT NULL, + EmployeeName nvarchar(250) NOT NULL, + IsPrimary bit NULL, + createdAt datetime2(7) NULL, + updatedAt datetime2(7) NULL, +PRIMARY KEY CLUSTERED +( + RpdId ASC, + EmployeeId 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 +CREATE TABLE babel_2089_CompanyLocation( + LocationId int NOT NULL, + LocationName nvarchar(255) NULL, + LocationDesc nvarchar(2000) NULL, + MainLocation bit NOT NULL, + PrimaryContactId int NULL, + CompanyId int NULL, + AddressId int NULL, + Address1 nvarchar(255) NULL, + Address2 nvarchar(255) NULL, + Address3 nvarchar(255) NULL, + City nvarchar(255) NULL, + RegionCode nvarchar(50) NULL, + Country nvarchar(5) NULL, + PostCode nvarchar(40) NULL, + RegionName varchar(100) NULL, + CountryCodeDesc varchar(100) NULL, + MainPhone varchar(50) NULL, + Formatted_MainPhone varchar(50) NULL, + StatusId int NULL, + StatusTypeDesc varchar(50) NULL, + SubStatusId int NULL, + StatusSubTypeDesc varchar(50) NULL, + NumberRequiredVisits int NULL, + ProspectRating tinyint NULL, + CompanySizeId int NULL, + CompanySize varchar(50) NULL, + BusinessTypeId int NULL, + BusinessTypeDesc varchar(100) NULL, + BusinessDescId int NULL, + BusinessDescription varchar(100) NULL, + LocalSalesRep int NULL, + LocalConsultant int NULL, + InsertBy smallint NULL, + InsertDate datetime NULL, + UpdateBy smallint NULL, + UpdateDate datetime NULL, + Active int NULL, + SBUpdateDate datetime NULL, + UltimateParentName nvarchar(255) NULL, + ProspectRank int NULL, + CompanyName nvarchar(255) NULL, + UltimateParentId int NULL, + SecondaryConsultant int NULL, + KeyAccountConsultant int NULL, + KACSecondary int NULL, + CompanyClassificationId int NULL, + CompanyClassificationDesc varchar(100) NULL, + FirmTypeId int NULL, + FirmTypeName varchar(50) NULL, + FirmDescriptionId int NULL, + FirmDescriptionName varchar(50) NULL, + EnterpriseId int NULL, + EnterpriseName nvarchar(255) NULL, + SalesforceAccountName nvarchar(255) NULL, + SalesTeamDepartmentId int NULL, + ConsultingTeamDepartmentId int NULL, + SalesTeamDepartmentName nvarchar(75) NULL, + ConsultingTeamDepartmentName nvarchar(75) NULL, + MainLocationId int NULL, + Reseller bit NULL, + FactSetEMSBasketServer varchar(255) NULL, + CONSTRAINT PK_CompanyLocation PRIMARY KEY CLUSTERED +( + LocationId 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 +CREATE TABLE babel_2089_Individual( + IndividualId int NOT NULL, + LocationId int NULL, + Salutation nvarchar(50) NULL, + FirstName nvarchar(255) NULL, + MiddleName nvarchar(255) NULL, + LastName nvarchar(255) NULL, + Nickname nvarchar(255) NULL, + Suffix nvarchar(50) NULL, + EmailAddress varchar(255) NULL, + SecondaryEmailAddress varchar(255) NULL, + JobTitleId int NULL, + JobTitleDesc varchar(100) NULL, + BusinessCardTitle nvarchar(255) NULL, + DepartmentId int NULL, + DepartmentDesc varchar(100) NULL, + Division nvarchar(255) NULL, + MethodologyId int NULL, + MethodologyDesc varchar(100) NULL, + AssetTypeId int NULL, + AssetTypeDesc varchar(100) NULL, + StyleRegionId int NULL, + StyleRegionDesc varchar(100) NULL, + StyleSizeId int NULL, + StyleSizeDesc varchar(100) NULL, + BlockMarketingMail bit NULL, + BlockMarketingEmail bit NULL, + SpeaksEnglish bit NULL, + PrefferedLanguageId int NULL, + LanguageDesc varchar(100) NULL, + MainPhoneNumber varchar(50) NULL, + DirectPhoneNumber varchar(50) NULL, + MobilePhoneNumber varchar(50) NULL, + HomePhoneNumber varchar(50) NULL, + FaxNumber varchar(50) NULL, + Formatted_MainPhone varchar(50) NULL, + Formatted_DirectPhone varchar(50) NULL, + Formatted_MobilePhone varchar(50) NULL, + Formatted_HomePhone varchar(50) NULL, + Formatted_Fax varchar(50) NULL, + upgradePolicy bit NULL, + InsertBy int NULL, + InsertDate datetime NULL, + UpdateBy int NULL, + UpdateDate datetime NULL, + Active int NULL, + SBUpdateDate datetime NULL, + FactSetEntityId varchar(255) NULL, + factset_id nvarchar(255) NULL, + UserClassId int NULL, + UserClassName varchar(50) NULL, + PositionId int NULL, + PositionName varchar(50) NULL, + CONSTRAINT [PK_babel_2089_Individual] PRIMARY KEY CLUSTERED +( + IndividualId 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 +CREATE TABLE babel_2089_RpdClientsAffected( + RpdId int NOT NULL, + EntityId int NOT NULL, + EntityType nvarchar(250) NOT NULL, + ClientId int NULL, + ClientName nvarchar(250) NULL, + createdAt datetime2(7) NULL, + updatedAt datetime2(7) NULL +) ON [PRIMARY] +GO +CREATE TABLE babel_2089_Employee( + EmployeeId int NOT NULL, + FirstName nvarchar(75) NULL, + ShortFirstName nvarchar(75) NULL, + LastName nvarchar(75) NULL, + FullName_LNF nvarchar(128) NULL, + FullName_FNF nvarchar(128) NULL, + EmailAddress varchar(50) NULL, + WindowsUsername varchar(25) NULL, + Active bit NULL, + DepartmentID int NULL, + EmploymentType nvarchar(25) NULL, + JobTitleID int NULL, + ManagerId int NULL, + OfficeId int NULL, + SubsidiaryId int NULL, + OfficePhone varchar(50) NULL, + FDSCellPhone varchar(50) NULL, + updatedate datetime NULL, + MiddleName nvarchar(75) NULL, + UnixAccount nvarchar(75) NULL, + VMSAccount nvarchar(75) NULL, + JobTitle nvarchar(175) NULL, + HireDate date NULL, + OfficeExtension varchar(50) NULL, + FirstName_NDC nvarchar(150) NULL, + MiddleName_NDC nvarchar(100) NULL, + LastName_NDC nvarchar(150) NULL, + PreferredLastName nvarchar(75) NULL, + CONSTRAINT PK__Employee__7AD04F11125EB334 PRIMARY KEY CLUSTERED +( + EmployeeId 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 + +CREATE TABLE babel_2089_Department( + DepartmentId int NOT NULL, + DepartmentName nvarchar(75) NOT NULL, + ParentDepartment int NULL, + UltimateParent int NOT NULL, + SalesGroupId int NULL, + SalesGroupName nvarchar(100) NULL, + Active bit NOT NULL, + ModifiedDate datetime NOT NULL, + DepartmentManager int NULL, + DepartmentMailGroup varchar(100) NULL, + DepartmentType tinyint NULL, + DepartmentTypeName varchar(100) NULL, + ObjectSid char(84) NULL, + VerticalId int NULL, + VerticalName nvarchar(75) NULL, + SalesRegionId int NULL, + SalesRegionName nvarchar(75) NULL, + BusinessTypeId int NULL, + BusinessTypeName nvarchar(75) NULL, + updatedate datetime NULL, + CONSTRAINT PK__Department__5C37ACAD PRIMARY KEY CLUSTERED +( + DepartmentId 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 + + +CREATE view babel_2089_TeamMember as +with config as ( + select 2 as teamId, 17896 as managerId_hierarchy, cast(null as int) as departmentId -- JPOLO and indirect reports - BDI Content + union select 2 as teamId, 2670 as managerId_hierarchy, cast(null as int) as departmentId -- DBeilin and indirect reports - BDI Content + union select 2 as teamId, 18519 as managerId_hierarchy, cast(null as int) as departmentId -- LPapa and indirect reports - BDI Content + union select 1 as teamId, 363, cast(null as int) -- MSasser and indirects - BDI Licensing + union select 5 as teamId, 363, cast(null as int) -- MSasser and indirects - BDI Entitlements + union select 3 as teamId, 2165, cast(null as int) -- APetre and indirects - BDI Engineering +), mgmt as ( + -- Content Dev + select c.teamId, employeeId, managerId from babel_2089_Employee e + inner join config c on c.managerId_hierarchy = e.employeeID + union all + select m.teamId, e.employeeId, e.managerId + from mgmt m + inner join babel_2089_Employee e on e.managerId = m.employeeId + where e.active = 1 +), allUsers as ( + select teamId, employeeId from mgmt + union + select 8, employeeId + from babel_2089_Employee e + inner join babel_2089_Department d on d.DepartmentId = e.departmentId + where (e.departmentId = 1019 and e.active = 1) or employeeId = 12002 +) +select m.teamId, m.employeeId +from allUsers m +GO + + +CREATE view babel_2089_OpsDbView as + select distinct r.RpdId, r.Title, r.Severity, r.Priority, r.Status, r.CreatedDate, r.LastCommentDate + , r.AuthorName, r.EntityType, r.Entity, coalesce(cl.locationId, cl_i.locationId) as ClientLocationId, ca.ClientsAffected + , m_vendor.Value as Vendor -- case when len(meta.Vendor) > 50 then left(meta.Vendor, 30)+'...' else meta.Vendor end as Vendor + , opsDb.OpsDbInstanceId, sop.TeamId, sop.TeamName, sop.SopId, sop.StepId, sop.StepSequence, sop.TaskId, sop.StepName, sop.CompletedDate + , sop.totalSops, sop.completedSops, sop.done + , sop.Ready + , sop.timelinessTarget, sop.lastStepCompletedDate + --, m.TimelinessTarget - DATEDIFF(minute, ready.lastStepCompletedDate, GETUTCDATE()) as TatOverUnderMinutes + --, dateadd(minute, m.TimelinessTarget - DATEDIFF(minute, ready.lastStepCompletedDate, GETUTCDATE()), getutcdate()) as DueDate + + , datediff(minute, getdate(), try_parse(m_estComplDate.Value as date)) as TatOverUnderMinutes + , convert(varchar, try_parse(m_estComplDate.Value as date)) as DueDate + , convert(varchar, try_parse(m_wkstnECD.Value as date)) as WorkstationECD + , tm.AssigneeId, isnull(tm.Assignee, 'Unassigned') as Assignee + , coalesce(pa.EmployeeId, tm.AssigneeId) as PrimaryAssigneeId, coalesce(pa.EmployeeName, tm.Assignee, 'Unassigned') as PrimaryAssignee + from babel_2089_Rpd r + inner join babel_2089_RpdToOpsDbInstance opsDb on opsDb.RpdId = r.RpdId + left join babel_2089_RpdMetaDataItem m_vendor on m_vendor.RpdId = r.RpdId and m_vendor.Item = 'Vendor' + left join babel_2089_RpdMetaDataItem m_estComplDate on m_estComplDate.RpdId = r.RpdId and m_estComplDate.Item = 'EstCompletionDate' + left join babel_2089_RpdMetaDataItem m_wkstnECD on m_wkstnECD.RpdId = r.RpdId and m_wkstnECD.Item = 'WorkstationECD' + inner join babel_2089_RpdNextSopStep sop on sop.rpdId = r.RpdId + left join ( + select a.RpdId, tm.TeamId, a.EmployeeId as AssigneeId, a.EmployeeName as Assignee + from babel_2089_TeamMember tm + inner join babel_2089_RpdAssignee a on tm.EmployeeId = a.employeeID + ) tm on tm.teamId = sop.TeamId and tm.RpdId = r.RpdId + left join babel_2089_RpdAssignee pa on pa.RpdId = r.RpdId and pa.IsPrimary = 1 + left join babel_2089_CompanyLocation cl on r.EntityType = 'Location' and isnumeric(r.entity) = 1 and cl.LocationId = r.Entity + left join babel_2089_Individual i on r.EntityType = 'Individual' and isnumeric(r.entity) = 1 and i.IndividualId = r.Entity + left join babel_2089_CompanyLocation cl_i on cl_i.LocationId = i.LocationId + left join ( + select rpdId, count(distinct clientId) as ClientsAffected + from babel_2089_RpdClientsAffected + group by RpdID + having count(distinct clientId) > 0 + ) ca on ca.RpdId = r.RpdId + where r.Status <> 'Resolved' + and isnumeric(r.entity) = 1 + +go + +-- should not throw an error +select * from babel_2089_OpsDbView +go + +drop view babel_2089_opsdbview +drop view babel_2089_teammember +drop table babel_2089_rpd +drop table babel_2089_rpdtoopsdbinstance +drop table babel_2089_rpdmetadataitem +drop table babel_2089_rpdnextsopstep +drop table babel_2089_rpdassignee +drop table babel_2089_companylocation +drop table babel_2089_individual +drop table babel_2089_rpdclientsaffected +drop table babel_2089_employee +drop table babel_2089_department +go diff --git a/contrib/test/JDBC/input/BABEL-213.mix b/contrib/test/JDBC/input/BABEL-213.mix new file mode 100644 index 00000000000..d8ebc644ad2 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-213.mix @@ -0,0 +1,352 @@ +-- scalar udf returning int +CREATE FUNCTION babel_213_int_func( + @param1 INT, + @param2 INT +) +RETURNS INT +AS +BEGIN + RETURN @param1 * @param2; +END; +GO + +DECLARE @retval int; +EXEC @retval = babel_213_int_func 100, 200; +SELECT @retval; +GO + +-- using execute +DECLARE @retval int; +EXECUTE @retval = babel_213_int_func 100, 200; +SELECT @retval; +GO + +-- no retval +EXEC babel_213_int_func 100, 200; +GO + +-- scalar udf returning char +CREATE FUNCTION babel_213_char_func( + @param1 CHAR(100), + @param2 CHAR(100) +) +RETURNS CHAR(200) +AS +BEGIN + RETURN CONCAT(@param1, @param2); +END; +GO + +DECLARE @retval char(200); +EXEC @retval = babel_213_char_func 'foo', 'bar'; +SELECT @retval; +GO + +-- scalar udf returning varchar +CREATE FUNCTION babel_213_varchar_func( + @param1 VARCHAR(100), + @param2 VARCHAR(100), + @param3 VARCHAR(100) +) +RETURNS VARCHAR(300) +AS +BEGIN + RETURN CONCAT(@param1, @param2, @param3); +END; +GO + +DECLARE @retval varchar(300); +EXEC @retval = babel_213_varchar_func 'foo', 'bar', 'abc'; +SELECT @retval; +GO + +-- scalar udf returning null +CREATE FUNCTION babel_213_null_func( + @param1 INT, + @param2 INT +) +RETURNS INT +AS +BEGIN + RETURN NULL; +END; +GO + +DECLARE @retval int; +EXEC @retval = babel_213_null_func 100, 200; +SELECT ISNULL(@retval, -1); +GO + +-- sql_variant +CREATE FUNCTION babel_213_sql_variant_func(@v int) +RETURNS sql_variant +AS +BEGIN + declare @babel_213_var sql_variant; + select @babel_213_var = cast(@v as varchar(10)); + return @babel_213_var +END; +GO + +DECLARE @retval sql_variant; +EXEC @retval = babel_213_sql_variant_func 42; +SELECT sql_variant_property(@retval, 'basetype'); +GO + + +--uniqueidentifier +CREATE FUNCTION babel_213_uniqueidentifier_func(@n int) +RETURNS uniqueidentifier +AS +BEGIN + declare @id uniqueidentifier; + IF @n = 1 + select @id = CAST('1E984725-C51C-4BF4-9960-E1C80E27ABA0' AS uniqueidentifier); + ELSE + select @id = CAST('2E984725-C51C-4BF4-9960-E1C80E27ABA0' AS uniqueidentifier); + return @id +END; +GO + +DECLARE @retval uniqueidentifier; +EXEC @retval = babel_213_uniqueidentifier_func 1; +SELECT @retval; +GO + + +-- scalar udf which can cause an error +CREATE FUNCTION babel_213_div_func( + @param1 INT, + @param2 INT +) +RETURNS INT +AS +BEGIN + RETURN @param1 / @param2; +END; +GO + +DECLARE @retval int; +EXEC @retval = babel_213_div_func 100, 0; +SELECT @retval; +GO + +-- assignment to different type +-- char(200)->int (error should be thrwon) +DECLARE @retval int; +EXEC @retval = babel_213_char_func 'foo', 'bar'; +SELECT @retval; +GO + +DECLARE @retval char(200); +EXEC @retval = babel_213_int_func 100, 200; +SELECT @retval; +GO + + +--nested scalar udf +CREATE FUNCTION babel_213_n1_func( + @param1 INT +) +RETURNS INT +AS +BEGIN + RETURN @param1 + 1; +END; +GO + +CREATE FUNCTION babel_213_n2_func( + @param1 INT +) +RETURNS INT +AS +BEGIN + RETURN babel_213_n1_func(@param1) + 40; +END; +GO + +DECLARE @retval int; +EXEC @retval = babel_213_n2_func 1; +SELECT @retval; +GO + + +--nested scalar udf returning string +CREATE FUNCTION babel_213_str_n1_func( + @param1 VARCHAR(10), + @param2 VARCHAR(10) +) +RETURNS VARCHAR(20) +AS +BEGIN + RETURN CONCAT(@param1, @param2); +END; +GO + +CREATE FUNCTION babel_213_str_n2_func( + @param1 VARCHAR(10), + @param2 VARCHAR(10) +) +RETURNS VARCHAR(40) +AS +BEGIN + RETURN CONCAT(babel_213_str_n1_func(@param1, 'def'), babel_213_str_n1_func(@param2, 'lmn')); +END; +GO + +DECLARE @retval VARCHAR(40); +EXEC @retval = babel_213_str_n2_func 'abc', 'ghi'; +SELECT @retval; +GO + + +-- pl/pgsql +-- psql currentSchema=master_dbo,public +CREATE FUNCTION babel_213_int_plpgsql_func( + param1 INT, + param2 INT +) +RETURNS INT +AS $$ +BEGIN + RETURN param1 * param2; +END; +$$ LANGUAGE plpgsql; +GO + +-- tsql +use master; +go +DECLARE @retval int; +EXEC @retval = babel_213_int_plpgsql_func 100, 200; +SELECT @retval; +GO + + +-- function name having whitespace +CREATE FUNCTION [babel_213 space func]( + @param1 INT, + @param2 INT +) +RETURNS INT +AS +BEGIN + RETURN @param1 * @param2; +END; +GO + +DECLARE @retval int; +EXEC @retval = [babel_213 space func] 100, 200; +SELECT @retval; +GO + + +CREATE FUNCTION [babel_213 space func no arg]() +RETURNS INT +AS +BEGIN + RETURN 42; +END; +GO + +DECLARE @retval int; +EXEC @retval = [babel_213 space func no arg]; +SELECT @retval; +GO + + +-- with schema +CREATE SCHEMA babel_213_schema +GO + +CREATE FUNCTION babel_213_schema.babel_213_int_func( + @param1 INT, + @param2 INT +) +RETURNS INT +AS +BEGIN + RETURN @param1 * @param2; +END; +GO + +DECLARE @retval int; +EXEC @retval = babel_213_schema.babel_213_int_func 100, 200; +SELECT @retval; +GO + + +-- space between schema and funcname +DECLARE @retval int; +EXEC @retval = babel_213_schema . babel_213_int_func 100, 200; +SELECT @retval; +GO + + +-- schema and function name with space +create SCHEMA [babel_213_schema with space] +GO + +CREATE FUNCTION [babel_213_schema with space].[babel_213_int_func with space]( + @param1 INT, + @param2 INT +) +RETURNS INT +AS +BEGIN + RETURN @param1 * @param2; +END; +GO + +DECLARE @retval int; +EXEC @retval = [babel_213_schema with space] . [babel_213_int_func with space] 100, 200; +SELECT @retval; +GO + + +-- babel 647: real-world scenario +CREATE TABLE babel_647_employees (salary MONEY); +insert into babel_647_employees VALUES (1.0); +insert into babel_647_employees VALUES (10.0); +insert into babel_647_employees VALUES (100.0); +GO + +CREATE FUNCTION babel_647_employee_totalsalary(@how_many INT) +RETURNS MONEY +AS +BEGIN + DECLARE @total_sal money; + + SELECT @total_sal = SUM(salary) FROM (select TOP (@how_many) salary FROM babel_647_employees) AS top_employees + + IF (@total_sal IS NULL) + SET @total_sal = 0 + RETURN @total_sal; +END; +GO + +DECLARE @retval money; +EXEC @retval = babel_647_employee_totalsalary 2; +SELECT @retval; +GO + +DROP FUNCTION babel_213_int_func; +DROP FUNCTION babel_213_char_func; +DROP FUNCTION babel_213_varchar_func; +DROP FUNCTION babel_213_null_func; +DROP FUNCTION babel_213_sql_variant_func; +DROP FUNCTION babel_213_uniqueidentifier_func; +DROP FUNCTION babel_213_div_func; +DROP FUNCTION babel_213_n2_func; +DROP FUNCTION babel_213_n1_func; +DROP FUNCTION babel_213_str_n2_func; +DROP FUNCTION babel_213_str_n1_func; +DROP FUNCTION [babel_213 space func]; +DROP FUNCTION [babel_213 space func no arg]; +DROP FUNCTION babel_647_employee_totalsalary; +DROP FUNCTION babel_213_schema.babel_213_int_func; +DROP SCHEMA babel_213_schema; +DROP FUNCTION [babel_213_schema with space].[babel_213_int_func with space]; +DROP SCHEMA [babel_213_schema with space]; +DROP TABLE babel_647_employees; +GO diff --git a/contrib/test/JDBC/input/BABEL-2145.sql b/contrib/test/JDBC/input/BABEL-2145.sql new file mode 100644 index 00000000000..eb7ad2d422b --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2145.sql @@ -0,0 +1,32 @@ +use master; +go + +create table t2145(c1 int); +go + +-- PG backend error +SELECT PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY c1) OVER (PARTITION BY c1) as pc FROM t2145; +go + +-- antlr error +SELECT PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY c1) OVER (ORDER BY c1) as pc FROM t2145; +go + +-- antlr error +SELECT PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY c1) OVER (ORDER BY c1 ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) as pc FROM t2145; +go + +-- PG backend error +SELECT PERCENTILE_DISC(0.5) WITHIN GROUP (ORDER BY c1) OVER (PARTITION BY c1) as pc FROM t2145; +go + +-- antlr error +SELECT PERCENTILE_DISC(0.5) WITHIN GROUP (ORDER BY c1) OVER (ORDER BY c1) as pc FROM t2145; +go + +-- antlr error +SELECT PERCENTILE_DISC(0.5) WITHIN GROUP (ORDER BY c1) OVER (ORDER BY c1 ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) as pc FROM t2145; +go + +drop table t2145; +go diff --git a/contrib/test/JDBC/input/BABEL-2203.sql b/contrib/test/JDBC/input/BABEL-2203.sql new file mode 100644 index 00000000000..8cb665cf9cc --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2203.sql @@ -0,0 +1,122 @@ +-- procedure in function +CREATE PROCEDURE p2203_inner AS + SELECT 1 +GO + +CREATE FUNCTION f2203() RETURNS INT AS +BEGIN + DECLARE @return INT + SET @return = 42 + EXEC p2203_inner -- should throw runtime error + RETURN @return +END +GO + +EXEC f2203 +GO + +-- EXEC function in function -> should be allowed +CREATE FUNCTION f2203_inner() RETURNS INT AS +BEGIN + RETURN 42; +END +GO + +CREATE FUNCTION f2203_2() RETURNS INT AS +BEGIN + DECLARE @return INT + EXEC @return = f2203_inner + RETURN @return +END +GO + +DECLARE @ret INT +EXEC @ret = f2203_2 +SELECT @ret +GO + +CREATE TABLE t2203(a int); +INSERT INTO t2203 VALUES (1); +GO + +CREATE FUNCTION f2203_ie() RETURNS INT AS +BEGIN + INSERT INTO t2203 EXEC p2203_inner; + RETURN 0; +END +GO + +CREATE FUNCTION f2203_i() RETURNS INT AS +BEGIN + INSERT INTO t2203 VALUES (2); + RETURN 0; +END +GO + +CREATE FUNCTION f2203_u() RETURNS INT AS +BEGIN + UPDATE t2203 SET a = 2; + RETURN 0; +END +GO + +CREATE FUNCTION f2203_d() RETURNS INT AS +BEGIN + DELETE FROM t2203; + RETURN 0; +END +GO + +CREATE FUNCTION f2203_cv() RETURNS INT AS +BEGIN + CREATE INDEX i2203 on t2203(a); + RETURN 0; +END +GO + +CREATE FUNCTION f2203_dt() RETURNS INT AS +BEGIN + DROP TABLE t2203; + RETURN 0; +END +GO + +-- exec in trigger should be allowed +CREATE TABLE t2203_inserted_by_proc(a int); +GO + +CREATE PROCEDURE p2203_2_inner AS + INSERT INTO t2203_inserted_by_proc VALUES (42); +GO + +CREATE TABLE t2203_2(a int); +INSERT INTO t2203_2 VALUES (1); +GO + +CREATE TRIGGER tr2203_2 on t2203_2 FOR INSERT AS +BEGIN + exec p2203_2_inner; +END +GO + +INSERT INTO t2203_2 VALUES (2); +GO + +SELECT * FROM t2203_2; +GO + +-- value should be inserted by proc triggered by trigger. +SELECT * FROM t2203_inserted_by_proc; +GO + +DROP PROCEDURE p2203_inner, p2203_2_inner; +GO + +DROP FUNCTION f2203, f2203_inner, f2203_2; +GO + +DROP TRIGGER tr2203_2; +GO + +DROP TABLE t2203, t2203_2, t2203_inserted_by_proc; +GO diff --git a/contrib/test/JDBC/input/BABEL-2208.sql b/contrib/test/JDBC/input/BABEL-2208.sql new file mode 100644 index 00000000000..013325c89d0 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2208.sql @@ -0,0 +1,46 @@ +CREATE TABLE t1(c1 int, c2 varchar(10) ) +GO +-- Doesn't matter if it's DECLARE or a SELECT @@rowcount +CREATE TRIGGER tr1 ON t1 +AFTER DELETE AS + DECLARE @rowcnt int + SET @rowcnt = @@ROWCOUNT + SELECT @rowcnt AS "#rows" +go +INSERT INTO t1 VALUES + (1, 'string1' ),(2, 'string2' ),(3, 'string3' ),(4, 'string4' ) +go +--Rowcount in trigger should return 1 +DELETE FROM t1 WHERE c1 = 1 +go +--Rowcount in trigger should return 2 +DELETE FROM t1 WHERE c1 IN(2,3) +go + +CREATE TABLE t2(c1 int, c2 varchar(10) ) +go + +CREATE TRIGGER tr2 ON t2 +AFTER insert AS + DECLARE @rowcnt int + SET @rowcnt = @@ROWCOUNT + SELECT @rowcnt AS "#rows" +go +--Rowcount in trigger should return 4 +INSERT INTO t2 VALUES (1, 'string1' ),(2, 'string2' ),(3, 'string3' ),(4, 'string4' ) +go + +INSERT INTO t2 VALUES (1, 'string1' ),(2, 'string2' ),(3, 'string3' ) +GO + +drop trigger tr2; +GO + +drop trigger tr1; +GO + +drop table t2; +GO + +drop table t1; +GO \ No newline at end of file diff --git a/contrib/test/JDBC/input/BABEL-2218.sql b/contrib/test/JDBC/input/BABEL-2218.sql new file mode 100644 index 00000000000..1a794bddbae --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2218.sql @@ -0,0 +1,40 @@ +use master; +go + +CREATE TABLE t2218(c1 INT) +INSERT INTO t2218 VALUES (2218); +GO + +-- should throw an error +CREATE FUNCTION f2218() +RETURNS INT AS +BEGIN + DECLARE @return INT + SET @return = 0 + SELECT * from t2218 + RETURN @return +END +GO + +-- if select statement has a destination, no error +CREATE FUNCTION f2218() +RETURNS INT AS +BEGIN + DECLARE @return INT + SET @return = 0 + SELECT @return=c1 from t2218 + RETURN @return +END +GO + +-- we have an issue. see BABEL-2655 +--SELECT f2218(); +--GO + +DECLARE @ret INT; +SET @ret = f2218(); +SELECT @ret; + +DROP FUNCTION f2218; +DROP TABLE t2218; +GO diff --git a/contrib/test/JDBC/input/BABEL-2225.sql b/contrib/test/JDBC/input/BABEL-2225.sql new file mode 100644 index 00000000000..bdc67068529 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2225.sql @@ -0,0 +1,24 @@ +CREATE SEQUENCE seq_2225 INCREMENT BY 6 MINVALUE 5 MAXVALUE 10; +GO + +CREATE SEQUENCE seq_2225 INCREMENT BY 6 MINVALUE 5 MAXVALUE 11; +GO + +ALTER SEQUENCE seq_2225 MAXVALUE 10; +GO + +ALTER SEQUENCE seq_2225 INCREMENT BY 7; +GO + +DROP SEQUENCE seq_2225; +GO + +-- Test with extreme values +CREATE SEQUENCE seq_2225 INCREMENT BY -9223372036854775808 MINVALUE 0 MAXVALUE 9223372036854775807; +GO + +CREATE SEQUENCE seq_2225 INCREMENT BY -9223372036854775808 MINVALUE -9223372036854775808 MAXVALUE 9223372036854775807; +GO + +DROP SEQUENCE seq_2225; +GO diff --git a/contrib/test/JDBC/input/BABEL-2234.sql b/contrib/test/JDBC/input/BABEL-2234.sql new file mode 100644 index 00000000000..597c036e5b9 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2234.sql @@ -0,0 +1,21 @@ +use master; +go + +-- sql batch +SELECT NULLIF(NULL, 2); +GO + +-- create procedure -> should throw compile-time error +CREATE PROCEDURE p_2234 AS + SELECT NULLIF(NULL, 2); +GO + +-- NULL variable should be allowed +declare @a int; +set @a = NULL; +select nullif(@a, 2); +go + +-- mixed case nullif +SELECT NuLlIf(nULL, 2); +GO diff --git a/contrib/test/JDBC/input/BABEL-2257.sql b/contrib/test/JDBC/input/BABEL-2257.sql new file mode 100644 index 00000000000..9d30e278e55 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2257.sql @@ -0,0 +1,75 @@ +create schema error_mapping; +GO + +CREATE TABLE t3616(id int); +GO + +CREATE TABLE t3617(id int); +GO + +CREATE TRIGGER t3616Trigger +ON t3616 +AFTER INSERT +AS +BEGIN + BEGIN TRY + BEGIN TRAN + INSERT INTO t3616 VALUES (2) + COMMIT TRAN + END TRY + BEGIN CATCH + SELECT ERROR_MESSAGE(); + END CATCH +END +GO + + +CREATE TRIGGER t3617Trigger +ON t3617 +AFTER INSERT +AS +BEGIN + BEGIN TRY + BEGIN TRAN + INSERT INTO t3616 VALUES (1) + COMMIT TRAN + END TRY + BEGIN CATCH + SELECT ERROR_MESSAGE(); + END CATCH +END +GO + +create procedure error_mapping.ErrorHandling1 as +begin +INSERT INTO t3617 values (1) +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +end +GO + +exec error_mapping.ErrorHandling1; +GO + +select * from t3616 +GO + +select * from t3617 +GO + +drop trigger t3617Trigger; +GO + +drop trigger t3616Trigger; +GO + +drop table t3616; +GO + +drop table t3617; +GO + +drop procedure error_mapping.ErrorHandling1; +GO + +drop schema error_mapping; +GO \ No newline at end of file diff --git a/contrib/test/JDBC/input/BABEL-2258.sql b/contrib/test/JDBC/input/BABEL-2258.sql new file mode 100644 index 00000000000..42b4275ff66 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2258.sql @@ -0,0 +1,11 @@ +select 'foo' where 'bar ' = 'bar'; +go + +select 'foo' where 0xAE = 0xAE00; +go + +select 'foo' where 101.5E5 = 1015E4; +go + +select 'foo' where (select 'bar ') = (select 'bar'); +go \ No newline at end of file diff --git a/contrib/test/JDBC/input/BABEL-2262.sql b/contrib/test/JDBC/input/BABEL-2262.sql new file mode 100644 index 00000000000..c8043b00a98 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2262.sql @@ -0,0 +1,41 @@ +CREATE TABLE t_2262(c1 int); +INSERT INTO t_2262 VALUES (42); +GO + +CREATE TABLE t_2262_2(c2 int); +GO + +CREATE PROCEDURE p_2262 + @pCursor CURSOR VARYING OUTPUT +AS +BEGIN + DECLARE @c1 INT; + FETCH NEXT FROM @pCursor INTO @c1 + INSERT INTO t_2262_2 VALUES (@c1); +END +GO + +DECLARE @cur CURSOR FOR SELECT c1 FROM t_2262; +OPEN @cur; +EXEC p_2262 @cur OUTPUT; +CLOSE @cur; +DEALLOCATE @cur; +GO + +SELECT c2 from t_2262_2; +GO + +CREATE FUNCTION f_2262 (@pCursor CURSOR VARYING OUTPUT) +RETURNS INT +AS +BEGIN + DECLARE @c1 INT; + FETCH NEXT FROM @pCursor INTO @c1 + RETURN @c1 + 1; +END; +GO + +DROP PROC p_2262; +DROP TABLE t_2262; +DROP TABLE t_2262_2; +GO diff --git a/contrib/test/JDBC/input/BABEL-2266.sql b/contrib/test/JDBC/input/BABEL-2266.sql new file mode 100644 index 00000000000..aacec7c089b --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2266.sql @@ -0,0 +1,61 @@ +CREATE TABLE t2266(c1 varchar(50)) +go + +CREATE PROCEDURE pr2266_text @p1 text AS +DECLARE tcursor CURSOR FOR SELECT c1 FROM t2266 +OPEN tcursor +FETCH NEXT FROM tcursor INTO @p1 +CLOSE tcursor +DEALLOCATE tcursor; +go + +CREATE PROCEDURE pr2266_ntext @p1 ntext AS +DECLARE tcursor CURSOR FOR SELECT c1 FROM t2266 +OPEN tcursor +FETCH NEXT FROM tcursor INTO @p1 +CLOSE tcursor +DEALLOCATE tcursor; +go + +CREATE PROCEDURE pr2266_image @p1 image AS +DECLARE tcursor CURSOR FOR SELECT c1 FROM t2266 +OPEN tcursor +FETCH NEXT FROM tcursor INTO @p1 +CLOSE tcursor +DEALLOCATE tcursor; +go + +CREATE PROCEDURE pr2266_int @p1 int AS +DECLARE tcursor CURSOR FOR SELECT c1 FROM t2266 +OPEN tcursor +FETCH NEXT FROM tcursor INTO @p1 +CLOSE tcursor +DEALLOCATE tcursor; +go + +CREATE PROCEDURE pr2266_varchar @p1 varchar AS +DECLARE tcursor CURSOR FOR SELECT c1 FROM t2266 +OPEN tcursor +FETCH NEXT FROM tcursor INTO @p1 +CLOSE tcursor +DEALLOCATE tcursor; +go + +-- Cleanup +DROP PROC pr2266_text +go + +DROP PROC pr2266_ntext +go + +DROP PROC pr2266_image +go + +DROP PROC pr2266_int +go + +DROP PROC pr2266_varchar +go + +DROP TABLE t2266 +go diff --git a/contrib/test/JDBC/input/BABEL-2276.sql b/contrib/test/JDBC/input/BABEL-2276.sql new file mode 100644 index 00000000000..5ec85940790 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2276.sql @@ -0,0 +1,6 @@ +declare @v_2276 text; +go +declare @v_2276 ntext; +go +declare @v_2276 image; +go diff --git a/contrib/test/JDBC/input/BABEL-2288.sql b/contrib/test/JDBC/input/BABEL-2288.sql new file mode 100644 index 00000000000..dc76d39f57a --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2288.sql @@ -0,0 +1,26 @@ +use master; +go +-- 1 +-- 2 +BEGIN TRY -- 3 + -- Generate a divide-by-zero error. -- 4 + SELECT 1/0; -- 5: error +END TRY +BEGIN CATCH + SELECT ERROR_LINE() AS ErrorLine; +END CATCH; +GO +-- 1 +-- 2 +CREATE PROCEDURE sp_2288 -- 3 +AS -- 4 + SELECT 'dummy' -- 5 + SELECT 1/0; -- 6: error +GO +BEGIN TRY + EXEC sp_2288 +END TRY +BEGIN CATCH + SELECT ERROR_LINE() AS ErrorLine; +END CATCH; +GO diff --git a/contrib/test/JDBC/input/BABEL-2303.sql b/contrib/test/JDBC/input/BABEL-2303.sql new file mode 100644 index 00000000000..454ee99ddde --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2303.sql @@ -0,0 +1,67 @@ +-- Test multiplication between int types and money types +DECLARE @tinyint tinyint = 5 +DECLARE @smallint smallint = 5 +DECLARE @int bigint = 5 +DECLARE @smallmoney smallmoney = 2 +DECLARE @money money = 2 +SELECT + @tinyint * @smallmoney AS should_be_10 +,@tinyint * @money AS should_be_10 +,@smallint * @smallmoney AS should_be_10 +,@smallint * @money AS should_be_10 +,@int * @smallmoney AS should_be_10 +,@int * @money AS should_be_10 +,@smallmoney * @tinyint AS should_be_10 +,@money * @tinyint AS should_be_10 +,@smallmoney * @smallint AS should_be_10 +,@money * @smallint AS should_be_10 +,@smallmoney * @int AS should_be_10 +,@money * @int AS should_be_10 +GO + +CREATE TABLE t1 +( + id int PRIMARY KEY IDENTITY +,c_tinyint tinyint +,c_smallint smallint +,c_smallmoney smallmoney +,c_money money +,c_tinyint_m_smallmoney AS c_tinyint * c_smallmoney +,c_tinyint_m_money AS c_tinyint * c_money +,c_smallint_m_smallmoney AS c_smallint * c_smallmoney +,c_smallint_m_money AS c_smallint * c_money +,c_smallmoney_m_tinyint AS c_smallmoney * c_tinyint +,c_money_m_tinyint AS c_money * c_tinyint +,c_smallmoney_m_smallint AS c_smallmoney * c_smallint +,c_money_m_smallint AS c_money * c_smallint +) +GO +INSERT INTO t1(c_tinyint, c_smallint, c_smallmoney, c_money) VALUES(5,5,2,2) +GO +SELECT c_tinyint_m_smallmoney, c_tinyint_m_money, c_smallint_m_smallmoney, c_smallint_m_money, c_smallmoney_m_tinyint, c_money_m_tinyint, c_smallmoney_m_smallint, c_money_m_smallint FROM t1 +GO + +-- Test division between int types and money types +DECLARE @tinyint tinyint = 5 +DECLARE @smallint smallint = 5 +DECLARE @int bigint = 5 +DECLARE @smallmoney smallmoney = 2 +DECLARE @money money = 2 +SELECT + @tinyint / @smallmoney AS ts +,@tinyint / @money AS tm +,@smallint / @smallmoney AS ss +,@smallint / @money AS sm +,@int / @smallmoney AS ids +,@int / @money AS im +,@smallmoney / @tinyint AS st +,@money / @tinyint AS mt +,@smallmoney / @smallint AS ss +,@money / @smallint AS ms +,@smallmoney / @int AS si +,@money / @int AS mi +GO + +-- clean up +DROP TABLe t1; +GO diff --git a/contrib/test/JDBC/input/BABEL-2317.sql b/contrib/test/JDBC/input/BABEL-2317.sql new file mode 100644 index 00000000000..60b9df10f07 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2317.sql @@ -0,0 +1,22 @@ +CREATE TABLE t_2317 (c1 int IDENTITY PRIMARY KEY, c2 int default 42); +INSERT INTO t_2317 DEFAULT VALUES; +INSERT t_2317 DEFAULT VALUES; +INSERT INTO t_2317 with (dummy_hint) DEFAULT VALUES; +GO + +SELECT * FROM t_2317; +GO + +-- not yet supported since conflict at backend parser +INSERT INTO t_2317 output inserted.* DEFAULT VALUES; +GO +CREATE TABLE t_2317_2 (d1 int, d2 int); +GO +INSERT INTO t_2317 output inserted.c1, inserted.c2 INTO t_2317_2 DEFAULT VALUES; +GO +INSERT INTO t_2317 output inserted.c1, inserted.c2 INTO t_2317_2(d1, d2) DEFAULT VALUES; +GO + +DROP TABLE t_2317; +DROP TABLE t_2317_2; +GO diff --git a/contrib/test/JDBC/input/BABEL-2325.sql b/contrib/test/JDBC/input/BABEL-2325.sql new file mode 100644 index 00000000000..44799249d09 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2325.sql @@ -0,0 +1,39 @@ +SET QUOTED_IDENTIFIER OFF +GO + +-- should return literal +SELECT 'literal' +GO + +-- should report that column "ident" does not exist +SELECT [ident] +GO + +-- should return string +SELECT "string" +GO + +-- should report error (double-quoted string literals cannot contain single-quotes while QUOTED_IDENTIFIER=OFF) +SELECT "f'oo" +GO + +-------------------------------------------------------------------------------- + +SET QUOTED_IDENTIFIER ON +GO + +-- should return literal +SELECT 'literal' +GO + +-- should report that column "ident" does not exist +SELECT [ident] +GO + +-- should report that column "ident" does not exist +SELECT "ident" +GO + +-- should report that column "f'oo" does not exist +SELECT "f'oo" +GO diff --git a/contrib/test/JDBC/input/BABEL-2328.sql b/contrib/test/JDBC/input/BABEL-2328.sql new file mode 100644 index 00000000000..1fa135e6045 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2328.sql @@ -0,0 +1,58 @@ +CREATE PROCEDURE babel_2328_proc_varchar( + @nvcwl nvarchar(32), + @nvcwol nvarchar, + @vcwl varchar(32), + @vcwol varchar + ) as + select @nvcwl, @nvcwol, @vcwl, @vcwol; +; +go + +exec babel_2328_proc_varchar + N'nvarchar with length', + N'nvarchar without length', + N'varchar with length', + N'varchar without length' +; +go + +exec babel_2328_proc_varchar + 'nvarchar with length', + 'nvarchar without length', + 'varchar with length', + 'varchar without length' +; +go + +drop procedure babel_2328_proc_varchar; +go + + +CREATE PROCEDURE babel_2328_proc_char( + @ncwl nchar(32), + @ncwol nchar, + @cwl char(32), + @cwol char +) as +select @ncwl, @ncwol, @cwl, @cwol; + ; +go + +exec babel_2328_proc_char + N'nchar with length', + N'nchar without length', + N'char with length', + N'char without length' +; +go + +exec babel_2328_proc_char + 'nchar with length', + 'nchar without length', + 'char with length', + 'char without length' +; +go + +drop procedure babel_2328_proc_char; +go \ No newline at end of file diff --git a/contrib/test/JDBC/input/BABEL-2337.sql b/contrib/test/JDBC/input/BABEL-2337.sql new file mode 100644 index 00000000000..87f8b39ce6f --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2337.sql @@ -0,0 +1,5 @@ +USE master; +GO + +SELECT nspname FROM sys.babelfish_namespace_ext where dbid in (1,2) and nspname like '%dbo' order by 1; +GO diff --git a/contrib/test/JDBC/input/BABEL-2347.sql b/contrib/test/JDBC/input/BABEL-2347.sql new file mode 100644 index 00000000000..ddde2fb50fc --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2347.sql @@ -0,0 +1,162 @@ +declare @date1 DATE; +declare @date2 DATE; +set @date1 = '2012-12-31' +set @date2 = '2013-01-01' +SELECT DATEDIFF(month, @date1, @date2) as momth_diff +go + +declare @date1 DATE; +declare @date2 DATE; +set @date1 = '2012-12-31' +set @date2 = '2013-01-01' +SELECT DATEDIFF(mm, @date1, @date2) as mm_diff +go + +declare @date1 DATE; +declare @date2 DATE; +set @date1 = '2012-12-31' +set @date2 = '2013-01-01' +SELECT DATEDIFF(day, @date1, @date2) as day_diff +go + +declare @date1 DATE; +declare @date2 DATE; +set @date1 = '2012-12-31' +set @date2 = '2013-01-01' +SELECT DATEDIFF(dd, @date1, @date2) as dd_diff +go + +declare @date1 DATE; +declare @date2 DATE; +set @date1 = '2012-12-31' +set @date2 = '2013-01-01' +SELECT DATEDIFF(year, @date1, @date2) as year_diff +go + +declare @date1 DATE; +declare @date2 DATE; +set @date1 = '2012-12-31' +set @date2 = '2013-01-01' +SELECT DATEDIFF(yyyy, @date1, @date2) as yyyy_diff +go + +declare @date1 DATE; +declare @date2 DATE; +set @date1 = '2012-12-31' +set @date2 = '2013-01-01' +SELECT DATEDIFF(yy, @date1, @date2) as yy_diff +go + +declare @date1 DATE; +declare @date2 DATE; +set @date1 = '2012-12-31' +set @date2 = '2013-01-01' +SELECT DATEDIFF(dayofyear, @date1, @date2) as yy_diff +go + +declare @date1 DATE; +declare @date2 DATE; +set @date1 = '2012-12-31' +set @date2 = '2013-01-01' +SELECT DATEDIFF(dy, @date1, @date2) as yy_diff +go + +declare @date1 DATE; +declare @date2 DATE; +set @date1 = '2012-12-31' +set @date2 = '2013-01-01' +SELECT DATEDIFF(y, @date1, @date2) as yy_diff -- BABEL-1063 +SELECT DATEADD(y, 1, @date1) as yy_add -- BABEL-1063 +go + +declare @date1 DATE; +declare @date2 DATE; +set @date1 = '2012-12-31' +set @date2 = '2013-01-01' +SELECT DATEDIFF(quarter, @date1, @date2) as quarter_diff +go + +declare @date1 DATE; +declare @date2 DATE; +set @date1 = '2012-12-31' +set @date2 = '2013-01-01' +SELECT DATEDIFF(qq, @date1, @date2) as qq_diff +go + +-- BABEL-1626 +declare @date1 datetimeoffset(6) +declare @date2 datetimeoffset(6) +set @date1 = '1912-12-31 12:24:32 +10:0' +set @date2 = '1913-01-01 12:25:32 +10:0' +SELECT DATEDIFF(day, @date1, @date2) as day_diff +go + +declare @date1 datetimeoffset(6) +declare @date2 datetimeoffset(6) +set @date1 = '1912-12-31 12:24:32 +10:0' +set @date2 = '1913-01-01 12:25:32 +10:0' +SELECT DATEDIFF(dd, @date1, @date2) as dd_diff +go + +declare @date1 datetimeoffset(6) +declare @date2 datetimeoffset(6) +set @date1 = '1912-12-31 12:24:32 +10:0' +set @date2 = '1913-01-01 12:25:32 +10:0' +SELECT DATEDIFF(month, @date1, @date2) as momth_diff +go + +declare @date1 datetimeoffset(6) +declare @date2 datetimeoffset(6) +set @date1 = '1912-12-31 12:24:32 +10:0' +set @date2 = '1913-01-01 12:25:32 +10:0' +SELECT DATEDIFF(mm, @date1, @date2) as mm_diff +go + +declare @date1 datetimeoffset(6) +declare @date2 datetimeoffset(6) +set @date1 = '1912-12-31 12:24:32 +10:0' +set @date2 = '1913-01-01 12:25:32 +10:0' +SELECT DATEDIFF(year, @date1, @date2) as year_diff +go + +declare @date1 datetimeoffset(6) +declare @date2 datetimeoffset(6) +set @date1 = '1912-12-31 12:24:32 +10:0' +set @date2 = '1913-01-01 12:25:32 +10:0' +SELECT DATEDIFF(yyyy, @date1, @date2) as yyyy_diff +go + +declare @date1 datetimeoffset(6) +declare @date2 datetimeoffset(6) +set @date1 = '1912-12-31 12:24:32 +10:0' +set @date2 = '1913-01-01 12:25:32 +10:0' +SELECT DATEDIFF(yy, @date1, @date2) as yy_diff +go + +declare @date1 datetimeoffset(6) +declare @date2 datetimeoffset(6) +set @date1 = '1912-12-31 12:24:32 +10:0' +set @date2 = '1913-01-01 12:25:32 +10:0' +SELECT DATEDIFF(quarter, @date1, @date2) as quarter_diff +go + +declare @date1 datetimeoffset(6) +declare @date2 datetimeoffset(6) +set @date1 = '1912-12-31 12:24:32 +10:0' +set @date2 = '1913-01-01 12:25:32 +10:0' +SELECT DATEDIFF(qq, @date1, @date2) as qq_diff +go + +declare @date1 datetimeoffset(6) +declare @date2 datetimeoffset(6) +set @date1 = '1912-12-31 12:24:32.001 +10:0' +set @date2 = '1912-12-31 12:24:32.002 +10:0' +SELECT DATEDIFF(nanosecond, @date1, @date2) as nanosecond_diff +go + +declare @date1 datetimeoffset(6) +declare @date2 datetimeoffset(6) +set @date1 = '1912-12-31 12:24:32.001 +10:0' +set @date2 = '1912-12-31 12:24:32.002 +10:0' +SELECT DATEDIFF(ns, @date1, @date2) as ns_diff +go diff --git a/contrib/test/JDBC/input/BABEL-2349.sql b/contrib/test/JDBC/input/BABEL-2349.sql new file mode 100644 index 00000000000..754ea906990 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2349.sql @@ -0,0 +1,15 @@ +create table t1(a int, b float, c bigint, d numeric); +go + +create index i1_t1 on t1 (a, b); +go + +select indid, name from sys.sysindexes where id=OBJECT_ID('t1'); +go + +-- clean up +drop index i1_t1 on t1 +go + +drop table t1 +go diff --git a/contrib/test/JDBC/input/BABEL-235.sql b/contrib/test/JDBC/input/BABEL-235.sql new file mode 100644 index 00000000000..73458178fdc --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-235.sql @@ -0,0 +1,59 @@ +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_session_settings', 'strict'; +GO + +SET ANSI_DEFAULTS ON; +GO + +-- Test invalid setting +SET ANSI_DEFAULTS OFF; +GO + +-- Test ANSI_DEFAULTS can be set to OFF when ESCAPE_HATCH_SESSION_SETTINGS = 'ignore' +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_session_settings', 'ignore'; +GO +SET ANSI_DEFAULTS OFF; +GO + +-- expect OFF +SELECT CURRENT_SETTING('babelfishpg_tsql.ansi_nulls', true); +GO +-- expect ON +SELECT CURRENT_SETTING('babelfishpg_tsql.ansi_warnings', true); +GO +-- expect ON +SELECT CURRENT_SETTING('babelfishpg_tsql.ansi_null_dflt_on', true); +GO +-- expect ON +SELECT CURRENT_SETTING('babelfishpg_tsql.ansi_padding', true); +GO +-- expect OFF +SELECT CURRENT_SETTING('babelfishpg_tsql.implicit_transactions', true); +GO +-- expect OFF +SELECT CURRENT_SETTING('babelfishpg_tsql.quoted_identifier', true); +GO + +SET ANSI_DEFAULTS ON; +GO + +-- expect ON +SELECT CURRENT_SETTING('babelfishpg_tsql.ansi_nulls', true); +GO +-- expect ON +SELECT CURRENT_SETTING('babelfishpg_tsql.ansi_warnings', true); +GO +-- expect ON +SELECT CURRENT_SETTING('babelfishpg_tsql.ansi_null_dflt_on', true); +GO +-- expect ON +SELECT CURRENT_SETTING('babelfishpg_tsql.ansi_padding', true); +GO +-- expect ON +SELECT CURRENT_SETTING('babelfishpg_tsql.implicit_transactions', true); +GO +-- expect ON +SELECT CURRENT_SETTING('babelfishpg_tsql.quoted_identifier', true); +GO + +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_session_settings', 'ignore'; +GO diff --git a/contrib/test/JDBC/input/BABEL-2350.sql b/contrib/test/JDBC/input/BABEL-2350.sql new file mode 100644 index 00000000000..9b5b660eb0e --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2350.sql @@ -0,0 +1,44 @@ +CREATE TABLE t1 (c1 int) +GO +INSERT INTO t1(c1) VALUES(1), (3), (4), (257) +GO + +CREATE TABLE t2 (c1 int) +GO + +CREATE PROC p1 +@limit int +AS + SELECT * FROM t1 WHERE c1 <= @limit +GO + +INSERT INTO t2(c1) +EXEC('EXEC p1 1000000') +GO + +SELECT * FROM t2; +GO + +-- Test more than one level of nested EXEC +CREATE PROC p2 +@limit int +AS + EXEC p1 @limit +GO + +INSERT INTO t2(c1) +EXEC('EXEC p2 1000000') +GO + +SELECT * from t2; +GO + +-- Cleanup +DROP TABLE t1 +GO +DROP TABLE t2 +GO +DROP PROC p1 +GO +DROP PROC p2 +GO diff --git a/contrib/test/JDBC/input/BABEL-2354.sql b/contrib/test/JDBC/input/BABEL-2354.sql new file mode 100644 index 00000000000..cb2a081203a --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2354.sql @@ -0,0 +1,15 @@ +CREATE TABLE employeeData( ID INT IDENTITY (1,1) PRIMARY KEY,Emp_First_name VARCHAR (50),Emp_Last_name VARCHAR (50),Emp_Salary INT) +GO + +CREATE TRIGGER updEmployeeData ON employeeData AFTER UPDATE AS + IF (COLUMNS_UPDATED() & 14) > 0 + BEGIN + PRINT 'Columns 3, 5 and 9 updated'; + END; +GO + +drop trigger updEmployeeData +GO + +drop table employeeData +GO diff --git a/contrib/test/JDBC/input/BABEL-2355.sql b/contrib/test/JDBC/input/BABEL-2355.sql new file mode 100644 index 00000000000..7dc19e7f9ac --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2355.sql @@ -0,0 +1,15 @@ +-- All following procedures should report error. +-- Before the fix for BABEL-2355, all these +-- procedures lead to crash. + +CREATE PROC babel_2355_proc1 AS +DECLARE @a DECIMAL(38, 39) +go + +CREATE PROC babel_2355_proc2 AS +DECLARE @a INTA +go + +DROP PROC babel_2355_proc1 +DROP PROC babel_2355_proc2 +go diff --git a/contrib/test/JDBC/input/BABEL-2357.sql b/contrib/test/JDBC/input/BABEL-2357.sql new file mode 100644 index 00000000000..48e83409ffd --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2357.sql @@ -0,0 +1,9 @@ +-- Tests that ANSI_PADDING can be set to ON +SET ANSI_PADDING ON; +GO + +DECLARE @v VARCHAR(20); +SET ANSI_PADDING ON; +SET @v = 'SHOULD BE SHOWN'; +SELECT @v; +GO \ No newline at end of file diff --git a/contrib/test/JDBC/input/BABEL-2371.sql b/contrib/test/JDBC/input/BABEL-2371.sql new file mode 100644 index 00000000000..3644da5d0d4 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2371.sql @@ -0,0 +1,65 @@ +-- simple case +create table t_2371(AbCd int, EfGh varchar(10)); +GO +select attname, attoptions from pg_class C, pg_attribute A where C.oid = A.attrelid and C.relname like 't_2371' and A.attnum > 0 and attisdropped = 'f' order by attname; +GO +select * from t_2371 +go + +-- alter table add column +alter table t_2371 add IjKl int; +select attname, attoptions from pg_class C, pg_attribute A where C.oid = A.attrelid and C.relname like 't_2371' and A.attnum > 0 and attisdropped = 'f' order by attname; +GO +select * from t_2371 +go +alter table t_2371 drop column EfGh; +GO +select * from t_2371 +go +select attname, attoptions from pg_class C, pg_attribute A where C.oid = A.attrelid and C.relname like 't_2371' and A.attnum > 0 and attisdropped = 'f' order by attname; +GO +drop table t_2371 +GO + +-- identifier longer than 64 characters +create table t_2371_2(A123456789B123456789C123456789D123456789E123456789F123456789G123456789H123456789I123456789J123456789K123456789 int); +GO +select attname, attoptions from pg_class C, pg_attribute A where C.oid = A.attrelid and C.relname like 't_2371_2' and A.attname like 'a123456789%'; +GO +select * from t_2371_2 +go +drop table t_2371_2 +GO + +-- non-reserved keyword (level is non-reserved keyword in PG) +create table t_2371_3 (LeVeL int); +GO +select attname, attoptions from pg_class C, pg_attribute A where C.oid = A.attrelid and C.relname like 't_2371_3' and A.attname like 'level'; +GO +select * from t_2371_3 +go +drop table t_2371_3 +GO + +-- delimited identifier +SET QUOTED_IDENTIFIER ON; +GO +create table t_2371_4 ([Abcd] int, "Efgh" int, Ijhl int, [K)@m($[^&] int, "x'AbC""e" int, """""""" int) +GO +select attname, attoptions from pg_class C, pg_attribute A where C.oid = A.attrelid and C.relname like 't_2371_4' and A.attnum > 0 and attisdropped = 'f' order by attname; +GO +select * from t_2371_4 +go +drop table t_2371_4 +GO + +-- CREATE TYPE +CREATE TYPE ty_2371_5 as table ("a""B""c" int); +GO +select attname, attoptions from pg_class C, pg_attribute A where C.oid = A.attrelid and C.relname like 'ty_2371_5' and A.attnum > 0 and attisdropped = 'f' order by attname; +GO +drop type ty_2371_5 +GO + +SET QUOTED_IDENTIFIER OFF; -- default +GO diff --git a/contrib/test/JDBC/input/BABEL-2372.sql b/contrib/test/JDBC/input/BABEL-2372.sql new file mode 100644 index 00000000000..ab47344e541 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2372.sql @@ -0,0 +1,18 @@ +-- Setting language to anything other than "us_english" will throw an error in strict mode +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_session_settings', 'strict'; +GO + +SET LANGUAGE Italian +GO + +SET LANGUAGE us_english +GO + +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_session_settings', 'ignore'; +GO + +SET LANGUAGE Italian +GO + +SET LANGUAGE us_english +GO diff --git a/contrib/test/JDBC/input/BABEL-2381.sql b/contrib/test/JDBC/input/BABEL-2381.sql new file mode 100644 index 00000000000..53f04fcd33b --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2381.sql @@ -0,0 +1,306 @@ +USE master +go + +declare @v int = 0; +if @v = '' print 'a' else print 'b'; +go + +-- From String literals +select cast('' as tinyint); +go +select cast(' ' as tinyint); +go +select cast('1' as tinyint); +go +select cast(' 123 ' as tinyint); +go +select cast(null as tinyint); +go + +select cast('' as smallint); +go +select cast(' ' as smallint); +go +select cast('1' as smallint); +go +select cast(' 123 ' as smallint); +go +select cast(null as smallint); +go + +select cast('' as int); +go +select cast(' ' as int); +go +select cast('1' as int); +go +select cast(' 123 ' as int); +go +select cast(null as int); +go + +select cast('' as bigint); +go +select cast(' ' as bigint); +go +select cast('1' as bigint); +go +select cast(' 123 ' as bigint); +go +select cast(null as bigint); +go + +select cast('' as decimal); +go +select cast(' ' as decimal); +go +select cast('1' as decimal); +go +select cast(' 123 ' as decimal); +go +select cast(null as decimal); +go + +select cast('' as float(20)); +go +select cast(' ' as float(20)); +go +select cast('1' as float(20)); +go +select cast(' 123 ' as float(20)); +go +select cast(null as float(20)); +go + +select cast('' as float(50)); +go +select cast(' ' as float(50)); +go +select cast('1' as float(50)); +go +select cast(' 123 ' as float(50)); +go +select cast(null as float(50)); +go + +select cast('' as real); +go +select cast(' ' as real); +go +select cast('1' as real); +go +select cast(' 123 ' as real); +go +select cast(null as real); +go + +select cast('' as numeric); +go +select cast(' ' as numeric); +go +select cast('1' as numeric); +go +select cast(' 123 ' as numeric); +go +select cast(null as numeric); +go + +-- From VARCHAR +select cast(cast ('' as varchar) as tinyint); +go +select cast(cast (' ' as varchar) as tinyint); +go +select cast(cast ('1' as varchar) as tinyint); +go +select cast(cast (' 123 ' as varchar) as tinyint); +go +select cast(cast (null as varchar) as tinyint); +go + +select cast(cast ('' as varchar) as smallint); +go +select cast(cast (' ' as varchar) as smallint); +go +select cast(cast ('1' as varchar) as smallint); +go +select cast(cast (' 123 ' as varchar) as smallint); +go +select cast(cast (null as varchar) as smallint); +go + +select cast(cast ('' as varchar) as int); +go +select cast(cast (' ' as varchar) as int); +go +select cast(cast ('1' as varchar) as int); +go +select cast(cast (' 123 ' as varchar) as int); +go +select cast(cast (null as varchar) as int); +go + +select cast(cast ('' as varchar) as bigint); +go +select cast(cast (' ' as varchar) as bigint); +go +select cast(cast ('1' as varchar) as bigint); +go +select cast(cast (' 123 ' as varchar) as bigint); +go +select cast(cast (null as varchar) as bigint); +go + +select cast(cast ('' as varchar) as float(20)); +go +select cast(cast (' ' as varchar) as float(20)); +go +select cast(cast ('1' as varchar) as float(20)); +go +select cast(cast (' 123.1 ' as varchar) as float(20)); +go +select cast(cast (null as varchar) as float(20)); +go + +select cast(cast ('' as varchar) as float(50)); +go +select cast(cast (' ' as varchar) as float(50)); +go +select cast(cast ('1' as varchar) as float(50)); +go +select cast(cast (' 123.1 ' as varchar) as float(50)); +go +select cast(cast (null as varchar) as float(50)); +go + +select cast(cast ('' as varchar) as decimal); +go +select cast(cast (' ' as varchar) as decimal); +go +select cast(cast ('1' as varchar) as decimal); +go +select cast(cast (' 123.1 ' as varchar) as decimal); +go +select cast(cast (null as varchar) as decimal); +go + +select cast(cast ('' as varchar) as real); +go +select cast(cast (' ' as varchar) as real); +go +select cast(cast ('1' as varchar) as real); +go +select cast(cast (' 123.1 ' as varchar) as real); +go +select cast(cast (null as varchar) as real); +go + +select cast(cast ('' as varchar) as numeric); +go +select cast(cast (' ' as varchar) as numeric); +go +select cast(cast ('1' as varchar) as numeric); +go +select cast(cast (' 123.1 ' as varchar) as numeric); +go +select cast(cast (null as varchar) as numeric); +go + +-- From CHAR +select cast(cast ('' as char) as tinyint); +go +select cast(cast (' ' as char) as tinyint); +go +select cast(cast ('1' as char) as tinyint); +go +select cast(cast (' 123 ' as char) as tinyint); +go +select cast(cast (null as char) as tinyint); +go + +select cast(cast ('' as char) as smallint); +go +select cast(cast (' ' as char) as smallint); +go +select cast(cast ('1' as char) as smallint); +go +select cast(cast (' 123 ' as char) as smallint); +go +select cast(cast (null as char) as smallint); +go + +select cast(cast ('' as char) as int); +go +select cast(cast (' ' as char) as int); +go +select cast(cast ('1' as char) as int); +go +select cast(cast (' 123 ' as char) as int); +go +select cast(cast (null as char) as int); +go + +select cast(cast ('' as char) as bigint); +go +select cast(cast (' ' as char) as bigint); +go +select cast(cast ('1' as char) as bigint); +go +select cast(cast (' 123 ' as char) as bigint); +go +select cast(cast (null as char) as bigint); +go + +select cast(cast ('' as char) as float(20)); +go +select cast(cast (' ' as char) as float(20)); +go +select cast(cast ('1' as char) as float(20)); +go +select cast(cast (' 123.1 ' as char) as float(20)); +go +select cast(cast (null as char) as float(20)); +go + +select cast(cast ('' as char) as float(50)); +go +select cast(cast (' ' as char) as float(50)); +go +select cast(cast ('1' as char) as float(50)); +go +select cast(cast (' 123.1 ' as char) as float(50)); +go +select cast(cast (null as char) as float(50)); +go + +select cast(cast ('' as char) as decimal); +go +select cast(cast (' ' as char) as decimal); +go +select cast(cast ('1' as char) as decimal); +go +select cast(cast (' 123.1 ' as char) as decimal); +go +select cast(cast (null as char) as decimal); +go + +select cast(cast ('' as char) as real); +go +select cast(cast (' ' as char) as real); +go +select cast(cast ('1' as char) as real); +go +select cast(cast (' 123.1 ' as char) as real); +go +select cast(cast (null as char) as real); +go + +select cast(cast ('' as char) as numeric); +go +select cast(cast (' ' as char) as numeric); +go +select cast(cast ('1' as char) as numeric); +go +select cast(cast (' 123.1 ' as char) as numeric); +go +select cast(cast (null as char) as numeric); +go \ No newline at end of file diff --git a/contrib/test/JDBC/input/BABEL-2390.sql b/contrib/test/JDBC/input/BABEL-2390.sql new file mode 100644 index 00000000000..635a208c697 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2390.sql @@ -0,0 +1,24 @@ +create table t_2390(a int); +insert into t_2390 values (1), (2); +GO + +-- query hint option should be ignored +DECLARE @a int +DECLARE c_byname CURSOR STATIC LOCAL FOR select a from t_2390 order by a option (maxdop 1) +open c_byname +fetch c_byname into @a +select @a +close c_byname +GO + +-- table hint shoudl be ignored +DECLARE @a int +DECLARE c_byname CURSOR STATIC LOCAL FOR select a from t_2390 with (dummy_hint) order by a +open c_byname +fetch c_byname into @a +select @a +close c_byname +GO + +drop table t_2390; +GO diff --git a/contrib/test/JDBC/input/BABEL-2392.sql b/contrib/test/JDBC/input/BABEL-2392.sql new file mode 100644 index 00000000000..bfe1234ba93 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2392.sql @@ -0,0 +1,49 @@ +USE master; +go + +create procedure sp1 (@a int = 0, @b varchar(10)) as begin select @a, @b; end; +go + +-- Test out of order arguments +exec sp1 @b = "abcd", @a = 3; +go + +-- Test normal order arguments +exec sp1 @a = 3, @b = "abcd"; +go + +-- Test missing argument +exec sp1 @b = "abcd"; +go + +-- Test truncation on varchar/varchar(1) with out of order arguments +create procedure sp2 (@a int, @b varchar) as begin select @a, @b; end; +go + +-- Test out of order arguments +exec sp2 @b = "abcd", @a = 3; +go + +-- Test normal order arguments +exec sp2 @a = 3, @b = "abcd"; +go + +-- Test OUTPUT param and missing param +create proc sp3 (@a int, @b varchar(10) = NULL, @c varchar(8) OUTPUT) as begin select @a, @b, @c; end +go + +-- Test missing param @b +exec sp3 @c = 'abcdefghijklmn', @a = 1; +go + +-- Test out of order arguments +exec sp3 @b = 'abcdefghijklmn', @c = 'abcdefghijklmn', @a = 1; +go + +-- Test normal order arguments +exec sp3 @a = 1, @b = 'abcdefghijklmn', @c = 'abcdefghijklmn'; +go + +-- Clean up +drop procedure sp1, sp2, sp3; +go diff --git a/contrib/test/JDBC/input/BABEL-2403.mix b/contrib/test/JDBC/input/BABEL-2403.mix new file mode 100644 index 00000000000..202e621280a --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2403.mix @@ -0,0 +1,3 @@ +--psql +SELECT * FROM sys.babelfish_inconsistent_metadata(); +GO diff --git a/contrib/test/JDBC/input/BABEL-2409.mix b/contrib/test/JDBC/input/BABEL-2409.mix new file mode 100644 index 00000000000..d7e6cddaa79 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2409.mix @@ -0,0 +1,31 @@ +-- tsql +USE master +go + +-- tsql +CREATE SCHEMA abc; +GO + +-- psql +DROP SCHEMA master_abc; +GO + +-- psql +ALTER SCHEMA master_abc RENAME TO abc; +GO + +-- psql +CREATE SCHEMA master_xyz; +GO + +-- tsql +DROP SCHEMA xyz; +GO + +-- psql +DROP SCHEMA master_xyz; +GO + +-- tsql +DROP SCHEMA abc; +GO diff --git a/contrib/test/JDBC/input/BABEL-2410.sql b/contrib/test/JDBC/input/BABEL-2410.sql new file mode 100644 index 00000000000..fbc41a5668b --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2410.sql @@ -0,0 +1,27 @@ +USE master +go + +-- Should be blocked +CREATE USER babel_2410_user +go + +-- Should be blocked +CREATE ROLE babel_2410_role +go + +CREATE PROC babel_2410_proc AS +SELECT 123 +go + +-- Should be blocked +GRANT ALL ON babel_2410_proc TO jdbc_user +go + +DROP PROC babel_2410_proc +go + +DROP USER babel_2410_user +go + +DROP ROLE babel_2410_role +go diff --git a/contrib/test/JDBC/input/BABEL-2412.sql b/contrib/test/JDBC/input/BABEL-2412.sql new file mode 100644 index 00000000000..4c7ef9d0809 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2412.sql @@ -0,0 +1,5 @@ +create procedure empty_proc as ; +go + +drop procedure empty_proc; +go \ No newline at end of file diff --git a/contrib/test/JDBC/input/BABEL-2416.sql b/contrib/test/JDBC/input/BABEL-2416.sql new file mode 100644 index 00000000000..65ad98f4a49 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2416.sql @@ -0,0 +1,15 @@ +-- schema id is not a stable value, test nullability instead +USE master +GO + +SELECT CASE WHEN schema_id('dbo') IS NULL then 'is null' ELSE 'not null' END; +GO + +USE tempdb +GO + +SELECT CASE WHEN schema_id('dbo') IS NULL then 'is null' ELSE 'not null' END; +GO + +USE master +GO diff --git a/contrib/test/JDBC/input/BABEL-2417.sql b/contrib/test/JDBC/input/BABEL-2417.sql new file mode 100644 index 00000000000..161460ef85a --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2417.sql @@ -0,0 +1,5 @@ +-- Only need to scan the entire table and ensure no error is raised +DECLARE @a INT +SELECT @a = COUNT(*) FROM sys.objects +SELECT (CASE WHEN @a > 1 THEN 'true' ELSE 'false' END) AS result +go diff --git a/contrib/test/JDBC/input/BABEL-2418.sql b/contrib/test/JDBC/input/BABEL-2418.sql new file mode 100644 index 00000000000..5b548144a7c --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2418.sql @@ -0,0 +1,26 @@ +USE master +go + +CREATE DATABASE babel_2418_db +go + +USE babel_2418_db +go + +CREATE SCHEMA babel_2418_schema1 +go + +CREATE SCHEMA babel_2418_schema2 +go + +SELECT nspname FROM sys.babelfish_namespace_ext; +go + +USE master +go + +DROP DATABASE babel_2418_db +go + +SELECT nspname FROM sys.babelfish_namespace_ext; +go diff --git a/contrib/test/JDBC/input/BABEL-2419.sql b/contrib/test/JDBC/input/BABEL-2419.sql new file mode 100644 index 00000000000..04622bd3449 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2419.sql @@ -0,0 +1,20 @@ +create table t_2419 (a varchar(10)); +insert into t_2419 values ('correct'); + +select a 'alias_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij' +from t_2419 +order by alias_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij +go + +select a 'alias_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij' +from t_2419 +order by [alias_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij] +go + +select a 'alias_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij' +from t_2419 +order by [ALIAS_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij] +go + +drop table t_2419; +go diff --git a/contrib/test/JDBC/input/BABEL-2432.sql b/contrib/test/JDBC/input/BABEL-2432.sql new file mode 100644 index 00000000000..f8c6b6b2657 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2432.sql @@ -0,0 +1,27 @@ +-- mixed-case column name. select via lowercase name +create table t2432 ([COL_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij] int); +insert into t2432 values (1); +GO + +select [col_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij] from t2432; +GO + +select col_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij from t2432; +GO + +drop table t2432; +GO + +-- lowercase column name. select via mixed-case name +create table t2432_2 ([col_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij] int); +insert into t2432_2 values (1); +GO + +select [COL_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij] from t2432_2; +GO + +select COL_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij from t2432_2; +GO + +drop table t2432_2; +GO diff --git a/contrib/test/JDBC/input/BABEL-2433.sql b/contrib/test/JDBC/input/BABEL-2433.sql new file mode 100644 index 00000000000..f91835c386d --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2433.sql @@ -0,0 +1,34 @@ +USE master; +GO + +create table obytt (a int); +insert into obytt values (1); +go + +select a as B from obytt order by b; +go + +select a as B from obytt order by B; +go + +-- ORDER BY b+3 is not allowed in either the tsql or the postgres dialect +-- error is: column "b" does not exist +select a as B from obytt order by b+3; +go + +-- However, order by a+3 is allowed because a is a column name +select a+3 as B from obytt order by a+3; +go + +-- and it is done case-insensitively if the db collation is CI +select a+3 as B from obytt order by a+3; +go + +select a+3 as B from obytt order by a; +go + +select a+3 as b from obytt order by B; +go + +drop table obytt; +go diff --git a/contrib/test/JDBC/input/BABEL-2437.sql b/contrib/test/JDBC/input/BABEL-2437.sql new file mode 100644 index 00000000000..372340d7124 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2437.sql @@ -0,0 +1,16 @@ +use master; +go + +create schema babel_2437_schema; +go + +create table babel_2437_schema.t1 (a int primary key); +go + +create table babel_2437_schema.t2 (b int, FOREIGN KEY (b) REFERENCES babel_2437_schema.t1 (a) ON DELETE CASCADE ON UPDATE CASCADE); +go + +drop table if exists babel_2437_schema.t2; +drop table if exists babel_2437_schema.t1; +drop schema babel_2437_schema; +go \ No newline at end of file diff --git a/contrib/test/JDBC/input/BABEL-244.sql b/contrib/test/JDBC/input/BABEL-244.sql new file mode 100644 index 00000000000..dc47e2c515c --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-244.sql @@ -0,0 +1,43 @@ +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (a INT); +GO + +INSERT INTO t1 +VALUES (1), (2); +GO + +-- Test by default cursor can be used after commit tran +-- i.e. default setting of cursor_close_on_commit is off + +BEGIN TRAN; +DECLARE testcursor CURSOR FOR + SELECT a FROM t1; +OPEN testcursor; +COMMIT TRAN; +FETCH NEXT FROM testcursor; +CLOSE testcursor; +DEALLOCATE testcursor; +GO + +-- test cursor can not be used after close +FETCH NEXT FROM testcursor; +GO + +-- Test invalid setting. +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_session_settings', 'strict'; +SET CURSOR_CLOSE_ON_COMMIT ON; +GO + +-- Test CURSOR_CLOSE_ON_COMMIT can be set when escape_hatch_session_settings is ignore +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_session_settings', 'ignore'; +SET CURSOR_CLOSE_ON_COMMIT ON; +GO + +SET CURSOR_CLOSE_ON_COMMIT OFF; +GO + +-- Clean up +DROP TABLE t1; +GO +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_session_settings', 'ignore'; +GO diff --git a/contrib/test/JDBC/input/BABEL-2440.mix b/contrib/test/JDBC/input/BABEL-2440.mix new file mode 100644 index 00000000000..a60f2fc3dc6 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2440.mix @@ -0,0 +1,38 @@ +-- tsql +SELECT session_user, current_user, db_name(); +GO + +CREATE LOGIN r1 WITH PASSWORD = '123'; +GO + +-- tsql user=r1 password=123 +SELECT session_user, current_user, db_name(); +GO + +ALTER LOGIN r1 WITH PASSWORD = 'abc'; +GO + +SELECT session_user, current_user, db_name(); +GO + +ALTER LOGIN r1 WITH PASSWORD = '123abc' OLD_PASSWORD = 'abc'; +GO + +SELECT set_config('babelfishpg_tsql.escape_hatch_login_old_password', 'ignore', 'false') +GO + +ALTER LOGIN r1 WITH PASSWORD = '123abc' OLD_PASSWORD = 'abc'; +GO + +SELECT set_config('babelfishpg_tsql.escape_hatch_login_old_password', 'strict', 'false') +GO + +SELECT session_user, current_user, db_name(); +GO + +-- tsql +ALTER LOGIN r1 WITH PASSWORD = 'abc'; +GO + +DROP LOGIN r1; +GO diff --git a/contrib/test/JDBC/input/BABEL-2445.sql b/contrib/test/JDBC/input/BABEL-2445.sql new file mode 100644 index 00000000000..cdd42b65cdb --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2445.sql @@ -0,0 +1,11 @@ +USE master; +go + +select N'long text more than 30 characters'; +go +select 'foo' where N'bar ' = 'bar'; +go +select 'foo' where N'bar ' = N'bar'; +go +select 'foo' as N'@var'; +go \ No newline at end of file diff --git a/contrib/test/JDBC/input/BABEL-2451.sql b/contrib/test/JDBC/input/BABEL-2451.sql new file mode 100644 index 00000000000..af0d24f49aa --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2451.sql @@ -0,0 +1,11 @@ +USE master; +go + +drop table if exists [babel_'2451]; +go +create table [babel_'2451] (a int, b varchar(max), c nvarchar(max)); +go +insert into [babel_'2451] values (1, 'DDD','dede'); +go +drop table if exists [babel_'2451]; +go \ No newline at end of file diff --git a/contrib/test/JDBC/input/BABEL-2458.mix b/contrib/test/JDBC/input/BABEL-2458.mix new file mode 100644 index 00000000000..7e1131a1840 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2458.mix @@ -0,0 +1,82 @@ +-- psql +SHOW "babelfishpg_tsql.migration_mode"; -- make sure it is single-db mode +GO + +-- tsql +USE master -- 1. test master DB +GO + +CREATE SCHEMA test2458; +GO +CREATE SCHEMA master; +GO +CREATE SCHEMA xyz_sfab; +GO +-- test very long schema name +CREATE SCHEMA wqreqwreqwerqwereqwrqreqwrqwrqwerqewreqwreqwrewqreerweqrqwreqwreqreqewrqwereqrrereqwerqwereqwrw; +GO + +-- test sys.schemas return logical schema name +-- test schema_id and schema_name to handle logical name +SELECT name, schema_name(schema_id(name)) FROM sys.schemas where name = 'test2458'; +SELECT name, schema_name(schema_id(name)) FROM sys.schemas where name = 'master'; +SELECT name, schema_name(schema_id(name)) FROM sys.schemas where name = 'xyz_sfab'; +SELECT name, schema_name(schema_id(name)) FROM sys.schemas where name = 'dbo'; +GO + +SELECT COUNT(*) FROM sys.schemas where schema_name(schema_id(name)) = 'wqreqwreqwerqwereqwrqreqwrqwrqwerqewreqwreqwrewqreerweqrqwreqwreqreqewrqwereqrrereqwerqwereqwrw'; +GO + +-- cleanup +DROP SCHEMA test2458; +GO +DROP SCHEMA master; +GO +DROP SCHEMA xyz_sfab; +GO +DROP SCHEMA wqreqwreqwerqwereqwrqreqwrqwrqwerqewreqwreqwrewqreerweqrqwreqwreqreqewrqwereqrrereqwerqwereqwrw; +GO + + +CREATE DATABASE db_a; -- 2. test single-db mode user DB +GO + +USE db_a; +GO + +CREATE SCHEMA test2458; +GO +CREATE SCHEMA master; +GO +CREATE SCHEMA xyz_sfab; +GO +-- test very long schema name +CREATE SCHEMA wqreqwreqwerqwereqwrqreqwrqwrqwerqewreqwreqwrewqreerweqrqwreqwreqreqewrqwereqrrereqwerqwereqwrw; +GO + +-- test sys.schemas return logical schema name +-- test schema_id and schema_name to handle logical name +SELECT name, schema_name(schema_id(name)) FROM sys.schemas where name = 'test2458'; +SELECT name, schema_name(schema_id(name)) FROM sys.schemas where name = 'master'; +SELECT name, schema_name(schema_id(name)) FROM sys.schemas where name = 'xyz_sfab'; +SELECT name, schema_name(schema_id(name)) FROM sys.schemas where name = 'dbo'; +GO + +SELECT COUNT(*) FROM sys.schemas where schema_name(schema_id(name)) = 'wqreqwreqwerqwereqwrqreqwrqwrqwerqewreqwreqwrewqreerweqrqwreqwreqreqewrqwereqrrereqwerqwereqwrw'; +GO + +-- cleanup +DROP SCHEMA test2458; +GO +DROP SCHEMA master; +GO +DROP SCHEMA xyz_sfab; +GO +DROP SCHEMA wqreqwreqwerqwereqwrqreqwrqwrqwerqewreqwreqwrewqreerweqrqwreqwreqreqewrqwereqrrereqwerqwereqwrw; +GO + +USE master; +GO + +DROP DATABASE db_a; +GO diff --git a/contrib/test/JDBC/input/BABEL-2470.sql b/contrib/test/JDBC/input/BABEL-2470.sql new file mode 100644 index 00000000000..dc198d7bc57 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2470.sql @@ -0,0 +1,22 @@ +-- verify sys.databases.owner_sid and sys.sysdatabases.sid are the same +-- inner select should return all 1's (e.g. columns are the same) +select owner_sid from +sys.sysdatabases as sdb +inner join sys.databases as d on sdb.name = d.name where owner_sid != [sid] +go + +-- verify value of owner_sid/sid from sys.databases/sys.sysdatabases +-- exists in principal_id from server_principals +select [sid] from sys.sysdatabases + where cast(cast([sid] as int) as oid) not in + ( + select principal_id from sys.server_principals + ) +go + +select owner_sid from sys.databases + where cast(cast(owner_sid as int) as oid) not in + ( + select principal_id from sys.server_principals + ) +go diff --git a/contrib/test/JDBC/input/BABEL-2482.sql b/contrib/test/JDBC/input/BABEL-2482.sql new file mode 100644 index 00000000000..e2cb0e1f05f --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2482.sql @@ -0,0 +1,28 @@ +USE master +go + +-- create user defined type +create type dbo.inttype from int; +GO + +-- create stored procedure with arg & default referencing UDT +create proc p4 @v dbo.inttype = cast (1 as dbo.inttype) as SELECT @v; +GO + +-- execute default value +EXEC p4 +GO + +-- execute non-default value +EXEC p4 10 +GO + +-- test select case +select cast (1 as dbo.inttype); +GO + +DROP PROCEDURE p4 +GO + +DROP TYPE dbo.inttype; +GO diff --git a/contrib/test/JDBC/input/BABEL-2485.sql b/contrib/test/JDBC/input/BABEL-2485.sql new file mode 100644 index 00000000000..bed9b29250f --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2485.sql @@ -0,0 +1,74 @@ +use master; +go + +create table t2485_certificate(certificate varchar(10)); +insert into t2485_certificate values ('ok'); +select certificate from t2485_certificate; +drop table t2485_certificate; +go + +create table t2485_check_expiration(check_expiration varchar(10)); +insert into t2485_check_expiration values ('ok'); +select check_expiration from t2485_check_expiration; +drop table t2485_check_expiration; +go + +create table t2485_check_policy(check_policy varchar(10)); +insert into t2485_check_policy values ('ok'); +select check_policy from t2485_check_policy; +drop table t2485_check_policy; +go + +create table t2485_credential(credential varchar(10)); +insert into t2485_credential values ('ok'); +select credential from t2485_credential; +drop table t2485_credential; +go + +create table t2485_default_database(default_database varchar(10)); +insert into t2485_default_database values ('ok'); +select default_database from t2485_default_database; +drop table t2485_default_database; +go + +create table t2485_default_language(default_language varchar(10)); +insert into t2485_default_language values ('ok'); +select default_language from t2485_default_language; +drop table t2485_default_language; +go + +create table t2485_hashed(hashed varchar(10)); +insert into t2485_hashed values ('ok'); +select hashed from t2485_hashed; +drop table t2485_hashed; +go + +create table t2485_must_change(must_change varchar(10)); +insert into t2485_must_change values ('ok'); +select must_change from t2485_must_change; +drop table t2485_must_change; +go + +create table t2485_old_password(old_password varchar(10)); +insert into t2485_old_password values ('ok'); +select old_password from t2485_old_password; +drop table t2485_old_password; +go + +create table t2485_sid(sid varchar(10)); +insert into t2485_sid values ('ok'); +select sid from t2485_sid; +drop table t2485_sid; +go + +create table t2485_unlock(unlock varchar(10)); +insert into t2485_unlock values ('ok'); +select unlock from t2485_unlock; +drop table t2485_unlock; +go + +create table t2485_windows(windows varchar(10)); +insert into t2485_windows values ('ok'); +select windows from t2485_windows; +drop table t2485_windows; +go diff --git a/contrib/test/JDBC/input/BABEL-2513.sql b/contrib/test/JDBC/input/BABEL-2513.sql new file mode 100644 index 00000000000..68d14eeeb0d --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2513.sql @@ -0,0 +1,354 @@ +use master; +go + +CREATE TABLE t2513( + dto datetimeoffset, + dt2 datetime2, + dt datetime, + sdt smalldatetime, + d date, + t time); + +INSERT INTO t2513 values ('1900-01-01 00:00:00', '1900-01-01 00:00:00', '1900-01-01 00:00:00', '1900-01-01 00:00:00', '1900-01-01', '00:00:00'); -- all same +INSERT INTO t2513 values ('1900-01-01 00:00:00', '1900-01-02 00:00:02', '1900-01-03 00:00:03', '1900-01-04 00:00:04', '1900-01-05', '00:00:06'); -- ascending +INSERT INTO t2513 values ('1900-01-06 00:00:00', '1900-01-05 00:00:05', '1900-01-04 00:00:04', '1900-01-03 00:00:03', '1900-01-02', '00:00:01'); -- descending +GO + +-- start of dto + +-- dto vs dto +select * from t2513 where dto = dto; +select * from t2513 where dto != dto; +select * from t2513 where dto < dto; +select * from t2513 where dto <= dto; +select * from t2513 where dto > dto; +select * from t2513 where dto >= dto; +GO + +-- dto vs dt2 +select * from t2513 where dto = dt2; +select * from t2513 where dto != dt2; +select * from t2513 where dto < dt2; +select * from t2513 where dto <= dt2; +select * from t2513 where dto > dt2; +select * from t2513 where dto >= dt2; +GO + +-- dto vs dt +select * from t2513 where dto = dt; +select * from t2513 where dto != dt; +select * from t2513 where dto < dt; +select * from t2513 where dto <= dt; +select * from t2513 where dto > dt; +select * from t2513 where dto >= dt; +GO + +-- dto vs sdt +select * from t2513 where dto = sdt; +select * from t2513 where dto != sdt; +select * from t2513 where dto < sdt; +select * from t2513 where dto <= sdt; +select * from t2513 where dto > sdt; +select * from t2513 where dto >= sdt; +GO + +-- dto vs d +select * from t2513 where dto = d; +select * from t2513 where dto != d; +select * from t2513 where dto < d; +select * from t2513 where dto <= d; +select * from t2513 where dto > d; +select * from t2513 where dto >= d; +GO + +-- dto vs t +select * from t2513 where dto = t; +select * from t2513 where dto != t; +select * from t2513 where dto < t; +select * from t2513 where dto <= t; +select * from t2513 where dto > t; +select * from t2513 where dto >= t; +GO + +-- start of dt2 + +-- dt2 vs dto +select * from t2513 where dt2 = dto; +select * from t2513 where dt2 != dto; +select * from t2513 where dt2 < dto; +select * from t2513 where dt2 <= dto; +select * from t2513 where dt2 > dto; +select * from t2513 where dt2 >= dto; +GO + +-- dt2 vs dt2 +select * from t2513 where dt2 = dt2; +select * from t2513 where dt2 != dt2; +select * from t2513 where dt2 < dt2; +select * from t2513 where dt2 <= dt2; +select * from t2513 where dt2 > dt2; +select * from t2513 where dt2 >= dt2; +GO + +-- dt2 vs dt +select * from t2513 where dt2 = dt; +select * from t2513 where dt2 != dt; +select * from t2513 where dt2 < dt; +select * from t2513 where dt2 <= dt; +select * from t2513 where dt2 > dt; +select * from t2513 where dt2 >= dt; +GO + +-- dt2 vs sdt +select * from t2513 where dt2 = sdt; +select * from t2513 where dt2 != sdt; +select * from t2513 where dt2 < sdt; +select * from t2513 where dt2 <= sdt; +select * from t2513 where dt2 > sdt; +select * from t2513 where dt2 >= sdt; +GO + +-- dt2 vs d +select * from t2513 where dt2 = d; +select * from t2513 where dt2 != d; +select * from t2513 where dt2 < d; +select * from t2513 where dt2 <= d; +select * from t2513 where dt2 > d; +select * from t2513 where dt2 >= d; +GO + +-- dt2 vs t +select * from t2513 where dt2 = t; +select * from t2513 where dt2 != t; +select * from t2513 where dt2 < t; +select * from t2513 where dt2 <= t; +select * from t2513 where dt2 > t; +select * from t2513 where dt2 >= t; +GO + +-- start of dt + +-- dt vs dto +select * from t2513 where dt = dto; +select * from t2513 where dt != dto; +select * from t2513 where dt < dto; +select * from t2513 where dt <= dto; +select * from t2513 where dt > dto; +select * from t2513 where dt >= dto; +GO + +-- dt vs dt2 +select * from t2513 where dt = dt2; +select * from t2513 where dt != dt2; +select * from t2513 where dt < dt2; +select * from t2513 where dt <= dt2; +select * from t2513 where dt > dt2; +select * from t2513 where dt >= dt2; +GO + +-- dt vs dt +select * from t2513 where dt = dt; +select * from t2513 where dt != dt; +select * from t2513 where dt < dt; +select * from t2513 where dt <= dt; +select * from t2513 where dt > dt; +select * from t2513 where dt >= dt; +GO + +-- dt vs sdt +select * from t2513 where dt = sdt; +select * from t2513 where dt != sdt; +select * from t2513 where dt < sdt; +select * from t2513 where dt <= sdt; +select * from t2513 where dt > sdt; +select * from t2513 where dt >= sdt; +GO + +-- dt vs d +select * from t2513 where dt = d; +select * from t2513 where dt != d; +select * from t2513 where dt < d; +select * from t2513 where dt <= d; +select * from t2513 where dt > d; +select * from t2513 where dt >= d; +GO + +-- dt vs t +select * from t2513 where dt = t; +select * from t2513 where dt != t; +select * from t2513 where dt < t; +select * from t2513 where dt <= t; +select * from t2513 where dt > t; +select * from t2513 where dt >= t; +GO + +-- start of sdt + +-- sdt vs dto +select * from t2513 where sdt = dto; +select * from t2513 where sdt != dto; +select * from t2513 where sdt < dto; +select * from t2513 where sdt <= dto; +select * from t2513 where sdt > dto; +select * from t2513 where sdt >= dto; +GO + +-- sdt vs dt2 +select * from t2513 where sdt = dt2; +select * from t2513 where sdt != dt2; +select * from t2513 where sdt < dt2; +select * from t2513 where sdt <= dt2; +select * from t2513 where sdt > dt2; +select * from t2513 where sdt >= dt2; +GO + +-- sdt vs dt +select * from t2513 where sdt = dt; +select * from t2513 where sdt != dt; +select * from t2513 where sdt < dt; +select * from t2513 where sdt <= dt; +select * from t2513 where sdt > dt; +select * from t2513 where sdt >= dt; +GO + +-- sdt vs sdt +select * from t2513 where sdt = sdt; +select * from t2513 where sdt != sdt; +select * from t2513 where sdt < sdt; +select * from t2513 where sdt <= sdt; +select * from t2513 where sdt > sdt; +select * from t2513 where sdt >= sdt; +GO + +-- sdt vs d +select * from t2513 where sdt = d; +select * from t2513 where sdt != d; +select * from t2513 where sdt < d; +select * from t2513 where sdt <= d; +select * from t2513 where sdt > d; +select * from t2513 where sdt >= d; +GO + +-- sdt vs t +select * from t2513 where sdt = t; +select * from t2513 where sdt != t; +select * from t2513 where sdt < t; +select * from t2513 where sdt <= t; +select * from t2513 where sdt > t; +select * from t2513 where sdt >= t; +GO + +-- start of d + +-- d vs dto +select * from t2513 where d = dto; +select * from t2513 where d != dto; +select * from t2513 where d < dto; +select * from t2513 where d <= dto; +select * from t2513 where d > dto; +select * from t2513 where d >= dto; +GO + +-- d vs dt2 +select * from t2513 where d = dt2; +select * from t2513 where d != dt2; +select * from t2513 where d < dt2; +select * from t2513 where d <= dt2; +select * from t2513 where d > dt2; +select * from t2513 where d >= dt2; +GO + +-- d vs dt +select * from t2513 where d = dt; +select * from t2513 where d != dt; +select * from t2513 where d < dt; +select * from t2513 where d <= dt; +select * from t2513 where d > dt; +select * from t2513 where d >= dt; +GO + +-- d vs sdt +select * from t2513 where d = sdt; +select * from t2513 where d != sdt; +select * from t2513 where d < sdt; +select * from t2513 where d <= sdt; +select * from t2513 where d > sdt; +select * from t2513 where d >= sdt; +GO + +-- d vs d +select * from t2513 where d = d; +select * from t2513 where d != d; +select * from t2513 where d < d; +select * from t2513 where d <= d; +select * from t2513 where d > d; +select * from t2513 where d >= d; +GO + +-- d vs t +select * from t2513 where d = t; +select * from t2513 where d != t; +select * from t2513 where d < t; +select * from t2513 where d <= t; +select * from t2513 where d > t; +select * from t2513 where d >= t; +GO + +-- start of t + +-- t vs dto +select * from t2513 where t = dto; +select * from t2513 where t != dto; +select * from t2513 where t < dto; +select * from t2513 where t <= dto; +select * from t2513 where t > dto; +select * from t2513 where t >= dto; +GO + +-- t vs dt2 +select * from t2513 where t = dt2; +select * from t2513 where t != dt2; +select * from t2513 where t < dt2; +select * from t2513 where t <= dt2; +select * from t2513 where t > dt2; +select * from t2513 where t >= dt2; +GO + +-- t vs dt +select * from t2513 where t = dt; +select * from t2513 where t != dt; +select * from t2513 where t < dt; +select * from t2513 where t <= dt; +select * from t2513 where t > dt; +select * from t2513 where t >= dt; +GO + +-- t vs sdt +select * from t2513 where t = sdt; +select * from t2513 where t != sdt; +select * from t2513 where t < sdt; +select * from t2513 where t <= sdt; +select * from t2513 where t > sdt; +select * from t2513 where t >= sdt; +GO + +-- t vs d +select * from t2513 where t = d; +select * from t2513 where t != d; +select * from t2513 where t < d; +select * from t2513 where t <= d; +select * from t2513 where t > d; +select * from t2513 where t >= d; +GO + +-- t vs t +select * from t2513 where t = t; +select * from t2513 where t != t; +select * from t2513 where t < t; +select * from t2513 where t <= t; +select * from t2513 where t > t; +select * from t2513 where t >= t; +GO + +drop table t2513 +GO diff --git a/contrib/test/JDBC/input/BABEL-2514.sql b/contrib/test/JDBC/input/BABEL-2514.sql new file mode 100644 index 00000000000..be70b586f4a --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2514.sql @@ -0,0 +1,128 @@ +USE master; +go + +select 'value' = '1'; +go + +drop view if exists babel_2514_view; +go +create view babel_2514_view as ( + select (select 'value' = '1') +); +go +select * from babel_2514_view; +go +drop view if exists babel_2514_view; +go + +drop function if exists babel_2514_func; +go +create function babel_2514_func() + returns table as return + ( + select * from (select 'value' = '1') col1 + ) +go +select babel_2514_func(); +go +drop function if exists babel_2514_func; +go + +DECLARE babel_2514_cursor CURSOR FOR select * from (select 'value' = '1') col1; +OPEN babel_2514_cursor +FETCH NEXT FROM babel_2514_cursor; +close babel_2514_cursor; +deallocate babel_2514_cursor; +go + +declare @babel_2514_cursor cursor +set @babel_2514_cursor = CURSOR FOR select * from (select 'value' = '1') col1; +open @babel_2514_cursor; +fetch next from @babel_2514_cursor; +go + +select (select 'value' = '1'); +go + +select * from (select 'value' = '1') a; +go + +WITH babel_2514_cte (a) AS +( + select 'value' = '1' +) +SELECT * from babel_2514_cte; +go + +WITH XMLNAMESPACES ('uri' as ns1) +SELECT 'value' = '1' +go + +declare @string1 nvarchar(5); +SELECT 'v' = @String1; +go + +drop function if exists babel_2514_func_local_id_1; +go +create function babel_2514_func_local_id_1(@String NVARCHAR(4000)) +returns table as return +( + SELECT @string +); +go +select babel_2514_func_local_id_1('abc'); +go +drop function if exists babel_2514_func_local_id_1; +go + +drop function if exists babel_2514_func_local_id_2; +go +create function babel_2514_func_local_id_2(@String NVARCHAR(4000)) +returns table as return +( + SELECT 'value' = @String +); +go +select babel_2514_func_local_id_2('abc def'); +go +drop function if exists babel_2514_func_local_id_2; +go + +drop function if exists babel_2514_complex_func; +go +CREATE FUNCTION babel_2514_complex_func +( + @String NVARCHAR(4000), + @Delimiter NCHAR(1) +) +RETURNS TABLE +AS +RETURN +( + WITH Split(stpos, endpos) AS + ( + SELECT 0 AS stpos, CHARINDEX(@Delimiter,@String) AS endpos + UNION ALL + SELECT endpos+1, CHARINDEX(@Delimiter,@String,endpos+1) + FROM Split + WHERE endpos > 0 + ) + SELECT 'Value' = SUBSTRING(@String, stpos, COALESCE(NULLIF(endpos, 0), LEN(@String) + 1) - stpos) + FROM Split +); +go +select babel_2514_complex_func('abc def', ' '); +go +drop function if exists babel_2514_complex_func; +go + +drop view if exists babel_2514_complex_view; +go +create view babel_2514_complex_view as ( + select (select a = 1) col1, * from (select b = 2 union all select b = 3) t +); +go +select * from babel_2514_complex_view; +go +drop view if exists babel_2514_complex_view; +go \ No newline at end of file diff --git a/contrib/test/JDBC/input/BABEL-2515.sql b/contrib/test/JDBC/input/BABEL-2515.sql new file mode 100644 index 00000000000..512a0710d32 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2515.sql @@ -0,0 +1,32 @@ +use master; +GO + +CREATE TABLE [BABEL-2515] +( + [PartitionId] [smallint] NOT NULL, + CONSTRAINT [PK_DataRecord2056] PRIMARY KEY CLUSTERED ( [PartitionId] ASC ) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) + ON [XFPS_DataRecord2056]([PartitionId]) +) +ON [XFPS_DataRecord2056]([PartitionId]); +GO + +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_storage_on_partition', 'ignore'; +GO + +CREATE TABLE [BABEL-2515] +( + [PartitionId] [smallint] NOT NULL, + CONSTRAINT [PK_DataRecord2056] PRIMARY KEY CLUSTERED ( [PartitionId] ASC ) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) + ON [XFPS_DataRecord2056]([PartitionId]) +) +ON [XFPS_DataRecord2056]([PartitionId]); +GO + +DROP TABLE [BABEL-2515] +GO + +-- reset to default +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_storage_on_partition', 'strict'; +GO diff --git a/contrib/test/JDBC/input/BABEL-2535.sql b/contrib/test/JDBC/input/BABEL-2535.sql new file mode 100644 index 00000000000..d4d784dfd65 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2535.sql @@ -0,0 +1,177 @@ +CREATE TABLE t8134 (a INT) +GO +CREATE TABLE tmp (a INT) +GO + +CREATE TRIGGER tr1 ON t8134 +AFTER INSERT AS + BEGIN TRY + INSERT INTO tmp VALUES (1); + SELECT 1/0; + INSERT INTO tmp VALUES (2); + END TRY + BEGIN CATCH + SELECT XACT_STATE() AS "XACT_STATE" + END CATCH +GO + +INSERT INTO t8134 VALUES (1); +GO + +SELECT * FROM tmp; +GO + +CREATE TABLE t8134_1 (a INT) +GO +CREATE TABLE tmp_1 (a INT) +GO + +CREATE TRIGGER tr2 ON t8134_1 +AFTER INSERT AS + INSERT INTO tmp_1 VALUES (555); +GO + +INSERT INTO t8134_1 VALUES (1); +INSERT INTO t8134 VALUES (1); +GO + +SELECT * FROM tmp_1; +GO + +SELECT * FROM tmp; +GO + +SELECT * FROM t8134_1; +GO + +TRUNCATE TABLE tmp_1; +GO + +BEGIN TRAN; +GO + +INSERT INTO t8134_1 VALUES (1); +INSERT INTO t8134 VALUES (1); +GO + +SELECT * FROM tmp_1; +GO + +SELECT * FROM tmp; +GO + +SELECT @@trancount; +GO + +SELECT * FROM t8134_1; +GO + +TRUNCATE TABLE tmp; +GO + +DROP TRIGGER tr1; +GO + +CREATE TRIGGER tr1 ON t8134 +AFTER INSERT AS + SELECT 1/0; +GO + +INSERT INTO tmp VALUES (666); +INSERT INTO t8134 VALUES (1); +INSERT INTO tmp VALUES (777); +GO + +SELECT * FROM tmp; +GO + +DROP TRIGGER tr1; +GO + +DROP TRIGGER tr2; +GO + +CREATE TABLE t1 (a INT); +GO + +CREATE TABLE t2 (a INT); +GO + +create trigger tr2 on t2 +after insert as +begin try + insert into t1 values(1); +end try +begin catch + print 'tr2'; + select @@trancount; +end catch; +GO + +create trigger tr1 on t1 +after insert as +begin try + select 1/0; +end try +begin catch + print 'tr1'; + select @@trancount; + rollback tran; +end catch +GO + +INSERT INTO t2 VALUES (1); +GO + +DROP TRIGGER tr1; +GO + +CREATE TRIGGER tr1 ON t1 +AFTER INSERT AS + BEGIN TRY + SELECT 1/0 + END TRY + BEGIN CATCH + SELECT XACT_STATE() AS "XACT_STATE" --Should be -1 + COMMIT + END CATCH +go +INSERT INTO t1 VALUES(1) +go +SELECT @@TRANCOUNT AS "TRANCOUNT" --Should be 0 +go + +DROP TRIGGER tr1; +GO + +CREATE TRIGGER tr1 ON t1 +AFTER INSERT AS + BEGIN TRY + SELECT 1/0 + END TRY + BEGIN CATCH + SELECT XACT_STATE() AS "XACT_STATE" --Should be -1 + ROLLBACK + END CATCH +go +INSERT INTO t1 VALUES(1) +go +SELECT @@TRANCOUNT AS "TRANCOUNT" --Should be 0 +go + +DROP TRIGGER tr1; +GO +DROP TRIGGER tr2; +GO +DROP TABLE t2; +GO +DROP TABLE t1; +GO +DROP TABLE t8134; +GO +DROP TABLE t8134_1; +GO +DROP TABLE tmp; +GO +DROP TABLE tmp_1; +GO diff --git a/contrib/test/JDBC/input/BABEL-2569.sql b/contrib/test/JDBC/input/BABEL-2569.sql new file mode 100644 index 00000000000..b8b3bbf85cb --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2569.sql @@ -0,0 +1,17 @@ +ALTER SERVER ROLE sysadmin DROP MEMBER jdbc_user; +GO + +CREATE LOGIN test2569 with PASSWORD = '123'; +GO + +ALTER SERVER ROLE sysadmin ADD MEMBER test2569; +GO + +ALTER SERVER ROLE sysadmin DROP MEMBER test2569; +GO + +DROP LOGIN test2569; +GO + +ALTER SERVER ROLE sysadmin DROP MEMBER jdbc_user; +GO diff --git a/contrib/test/JDBC/input/BABEL-2576.sql b/contrib/test/JDBC/input/BABEL-2576.sql new file mode 100644 index 00000000000..fd9cdb16dde --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2576.sql @@ -0,0 +1,67 @@ +CREATE TABLE BABEL_2576(a char(1)); +GO + +INSERT INTO BABEL_2576 VALUES ('a'); +GO +INSERT INTO BABEL_2576 VALUES (CHAR(161)); +GO +INSERT INTO BABEL_2576 VALUES ('b'); +GO + +SELECT * FROM BABEL_2576; +GO + +DROP TABLE BABEL_2576; +GO + +CREATE TABLE BABEL_2576(a char(5)); +GO + +INSERT INTO BABEL_2576 VALUES ('abcdef'); +GO +INSERT INTO BABEL_2576 VALUES ('a'); +GO +INSERT INTO BABEL_2576 VALUES (CHAR(161)); +GO +INSERT INTO BABEL_2576 VALUES ('ab'); +GO + +SELECT * FROM BABEL_2576; +GO + +DROP TABLE BABEL_2576; +GO + +CREATE TABLE BABEL_2576 (a varchar(1)); +GO + +INSERT INTO BABEL_2576 VALUES ('a'); +GO +INSERT INTO BABEL_2576 VALUES (CHAR(161)); +GO +INSERT INTO BABEL_2576 VALUES ('b'); +GO + +SELECT * FROM BABEL_2576; +GO + +DROP TABLE BABEL_2576; +GO + +CREATE TABLE BABEL_2576 (a varchar(5)); +GO + +INSERT INTO BABEL_2576 VALUES ('abcdef'); +GO +INSERT INTO BABEL_2576 VALUES ('a'); +GO +INSERT INTO BABEL_2576 VALUES (CHAR(161)); +GO +INSERT INTO BABEL_2576 VALUES ('ab'); +GO + +SELECT * FROM BABEL_2576; +GO + +DROP TABLE BABEL_2576; +GO diff --git a/contrib/test/JDBC/input/BABEL-2585.sql b/contrib/test/JDBC/input/BABEL-2585.sql new file mode 100644 index 00000000000..b2db6516860 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2585.sql @@ -0,0 +1,178 @@ +USE master; +go + +CREATE DATABASE [babelfish-1234]; +go + +DROP DATABASE [babelfish-1234]; +go + +CREATE DATABASE babel_recursive_cte; +go + +DROP DATABASE babel_recursive_cte; +go + +CREATE SCHEMA [babelfish-1234]; +go + +DROP SCHEMA [babelfish-1234]; +go + +CREATE SCHEMA babel_recursive_cte; +go + +DROP SCHEMA babel_recursive_cte; +go + +-- Test for BABEL-2589 +-- Check the stability of CREATE/DROP LOGIN with different names +CREATE LOGIN babel_2589_login_1 WITH PASSWORD = '123' +go +DROP LOGIN babel_2589_login_1 +go + +CREATE LOGIN babel_2589_login_2 WITH PASSWORD = '123' +go +DROP LOGIN babel_2589_login_2 +go + +CREATE LOGIN babel_2589_login_3 WITH PASSWORD = '123' +go +DROP LOGIN babel_2589_login_3 +go + +CREATE LOGIN babel_2589_login_4 WITH PASSWORD = '123' +go +DROP LOGIN babel_2589_login_4 +go + +CREATE LOGIN babel_2589_login_5 WITH PASSWORD = '123' +go +DROP LOGIN babel_2589_login_5 +go + +CREATE LOGIN babel_2589_login_6 WITH PASSWORD = '123' +go +DROP LOGIN babel_2589_login_6 +go + +CREATE LOGIN babel_2589_login_7 WITH PASSWORD = '123' +go +DROP LOGIN babel_2589_login_7 +go + +CREATE LOGIN babel_2589_login_8 WITH PASSWORD = '123' +go +DROP LOGIN babel_2589_login_8 +go + +CREATE LOGIN babel_2589_login_9 WITH PASSWORD = '123' +go +DROP LOGIN babel_2589_login_9 +go + +CREATE LOGIN babel_2589_login_10 WITH PASSWORD = '123' +go +DROP LOGIN babel_2589_login_10 +go + +-- Test for BABEL-2600 +-- Check stability of CREATE/DROP DATABASE with different names +CREATE DATABASE babel_2600_db_1 +go +USE babel_2600_db_1 +go +USE master +go +DROP DATABASE babel_2600_db_1 +go + +CREATE DATABASE babel_2600_db_2 +go +USE babel_2600_db_2 +go +USE master +go +DROP DATABASE babel_2600_db_2 +go + +CREATE DATABASE babel_2600_db_3 +go +USE babel_2600_db_3 +go +USE master +go +DROP DATABASE babel_2600_db_3 +go + +CREATE DATABASE babel_2600_db_4 +go +USE babel_2600_db_4 +go +USE master +go +DROP DATABASE babel_2600_db_4 +go + +CREATE DATABASE babel_2600_db_5 +go +USE babel_2600_db_5 +go +USE master +go +DROP DATABASE babel_2600_db_5 +go + +-- Check stability of CREATE/DROP DATABASE with the same name +CREATE DATABASE babel_2600_db +go +USE babel_2600_db +go +USE master +go +DROP DATABASE babel_2600_db +go + +CREATE DATABASE babel_2600_db +go +USE babel_2600_db +go +USE master +go +DROP DATABASE babel_2600_db +go + +CREATE DATABASE babel_2600_db +go +USE babel_2600_db +go +USE master +go +DROP DATABASE babel_2600_db +go + +CREATE DATABASE babel_2600_db +go +USE babel_2600_db +go +USE master +go +DROP DATABASE babel_2600_db +go + +CREATE DATABASE babel_2600_db +go +USE babel_2600_db +go +USE master +go +DROP DATABASE babel_2600_db +go + +-- Test for BABEL-2586 +-- Check if we can get the correct default db after multiple operations +DECLARE @default_db VARCHAR(10) +SET @default_db = sys.babelfish_get_login_default_db('jdbc_user'); +SELECT CASE WHEN @default_db = 'master' THEN 'correct' ELSE 'error' END; +go diff --git a/contrib/test/JDBC/input/BABEL-2593.sql b/contrib/test/JDBC/input/BABEL-2593.sql new file mode 100644 index 00000000000..5412cc2e047 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2593.sql @@ -0,0 +1,48 @@ +use master +go + +create schema testschema +go + +create procedure testschema.proc1 as select 1 +go + +create table testschema.table1 (a int primary key); +go + +create view testschema.view1 as select a from testschema.table1; +go + +create procedure dbo.proc2 as select 1 +go + +create table dbo.table2 (a int primary key); +go + +create view dbo.view2 as select a from dbo.table2; +go + +-- test procedure, table, constraint and view are visible for testschema +select name from sys.objects where name ='proc1' or name = 'table1' or name = 'view1' or name = 'table1_pkey'; +go + +-- test procedure, table, constraint and view are visible for dbo schema +select name from sys.objects where name ='proc2' or name = 'table2' or name = 'view2' or name = 'table2_pkey'; +go + +-- test proc1 and proc2 are visible in sys.procedures +select name from sys.procedures where name ='proc1' +go + +select name from sys.procedures where name ='proc2' +go + +--Clean up +drop procedure testschema.proc1; +drop view testschema.view1; +drop table testschema.table1; +drop schema testschema; +drop procedure dbo.proc2; +drop view dbo.view2; +drop table dbo.table2; +go diff --git a/contrib/test/JDBC/input/BABEL-2596.sql b/contrib/test/JDBC/input/BABEL-2596.sql new file mode 100644 index 00000000000..160cebc821f --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2596.sql @@ -0,0 +1,41 @@ + -- Only need to scan the entire table and ensure no error is raised +DECLARE @a INT +SELECT @a = COUNT(*) FROM sys.system_objects +SELECT (CASE WHEN @a > 1 THEN 'true' ELSE 'false' END) AS result +go + +DECLARE @a INT +SELECT @a = COUNT(*) FROM sys.all_columns +SELECT (CASE WHEN @a > 1 THEN 'true' ELSE 'false' END) AS result +go + +DECLARE @a INT +SELECT @a = COUNT(*) FROM sys.all_objects +SELECT (CASE WHEN @a > 1 THEN 'true' ELSE 'false' END) AS result +go + +DECLARE @a INT +SELECT @a = COUNT(*) FROM sys.all_views +SELECT (CASE WHEN @a > 1 THEN 'true' ELSE 'false' END) AS result +go + +DECLARE @a INT +SELECT @a = COUNT(*) FROM sys.columns +SELECT (CASE WHEN @a > 1 THEN 'true' ELSE 'false' END) AS result +go + +-- TODO: BABEL-2624 Add support for sys.identity_columns +DECLARE @a INT +SELECT @a = COUNT(*) FROM sys.identity_columns +SELECT (CASE WHEN @a > 1 THEN 'true' ELSE 'false' END) AS result +go + +DECLARE @a INT +SELECT @a = COUNT(*) FROM sys.views +SELECT (CASE WHEN @a > 1 THEN 'true' ELSE 'false' END) AS result +go + +DECLARE @a INT +SELECT @a = COUNT(*) FROM sys.tables +SELECT (CASE WHEN @a > 1 THEN 'true' ELSE 'false' END) AS result +go diff --git a/contrib/test/JDBC/input/BABEL-2602.mix b/contrib/test/JDBC/input/BABEL-2602.mix new file mode 100644 index 00000000000..34b57e139be --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2602.mix @@ -0,0 +1,20 @@ +USE master +go + +CREATE LOGIN babel_2602_user WITH PASSWORD = '123' +go + +CREATE DATABASE babel_2602_db +go + +-- tsql user=babel_2602_user password=123 +-- The query should fail rather than crash +DROP DATABASE babel_2602_db +go + +-- tsql +DROP LOGIN babel_2602_user +go + +DROP DATABASE babel_2602_db +go diff --git a/contrib/test/JDBC/input/BABEL-2604.sql b/contrib/test/JDBC/input/BABEL-2604.sql new file mode 100644 index 00000000000..c7bd4355e8e --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2604.sql @@ -0,0 +1,86 @@ +create table t1(c1 int) +GO + +insert into t1 values(1) +GO + +alter table t1 add c2 char +GO + +select * from t1; +GO + +insert into t1 values(1, 'a') +GO + +select * from t1; +GO + +drop table t1; +GO + +create table t1(c1 int) +GO + +insert into t1 values(1) +GO + +alter table t1 add c2 varchar +GO + +select * from t1; +GO + +insert into t1 values(1, 'a') +GO + +select * from t1; +GO + +drop table t1; +GO + +create table t2 (a varchar(1)) +GO + +insert into t2 values ('D') +GO + +alter table t2 alter column a char +GO + +select * from t2; +GO + +drop table t2; +GO + +create table t2 (a varchar(2)) +GO + +insert into t2 values ('De') +GO + +insert into t2 values ('D') +GO + +alter table t2 alter column a char +GO + +select * from t2; +GO + +alter table t2 alter column a char(2) +GO + +select * from t2; +GO + +insert into t2 values ('A') +GO + +select * from t2; +GO + +drop table t2; +GO \ No newline at end of file diff --git a/contrib/test/JDBC/input/BABEL-2607.sql b/contrib/test/JDBC/input/BABEL-2607.sql new file mode 100644 index 00000000000..cf79dae38fd --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2607.sql @@ -0,0 +1,35 @@ +USE master +go + +CREATE DATABASE babel_2607_db +go + +-- This is to test if sp_helpdb can be executed successfully +-- Output are not fixed values, and sp_helpdb is a procedure which we cannot +-- control the output, so we run the underlying function instead +SELECT + CASE WHEN name IS NOT NULL + AND owner IS NOT NULL + AND dbid > 0 + AND created IS NOT NULL + THEN 'correct' ELSE 'error' END +FROM babelfish_helpdb(); +go + +SELECT name, dbid +FROM babelfish_helpdb('master') +WHERE name = 'master' +go + +SELECT name, dbid +FROM babelfish_helpdb('tempdb') +WHERE name = 'tempdb' +go + +SELECT name +FROM babelfish_helpdb('babel_2607_db') +WHERE name = 'babel_2607_db'; +go + +DROP DATABASE babel_2607_db +go diff --git a/contrib/test/JDBC/input/BABEL-2622.mix b/contrib/test/JDBC/input/BABEL-2622.mix new file mode 100644 index 00000000000..117d3d18b70 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2622.mix @@ -0,0 +1,27 @@ +-- psql +DROP DATABASE babel_2622; +GO + +DROP DATABASE IF EXISTS babel_2622; +GO + +CREATE DATABASE babel_2622; +GO + +ALTER DATABASE babel_2622 RENAME to babel2622; +GO + +ALTER DATABASE babel_2622 RENAME to babel2622; +GO + +DROP DATABASE IF EXISTS babel2622; +GO + +DROP DATABASE IF EXISTS babel2622; +GO + +DROP DATABASE babel2622; +GO + +ALTER DATABASE babel2622 RENAME to babel_2622; +GO diff --git a/contrib/test/JDBC/input/BABEL-2647.sql b/contrib/test/JDBC/input/BABEL-2647.sql new file mode 100644 index 00000000000..14fe76b5ddc --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2647.sql @@ -0,0 +1,13 @@ +CREATE FUNCTION dbo.mstvf_2647() RETURNS @tv TABLE (a int NULL) +AS +BEGIN + INSERT @tv VALUES(0); + RETURN; +END; +go + +SELECT * from dbo.mstvf_2647(); +go + +DROP FUNCTION dbo.mstvf_2647; +go diff --git a/contrib/test/JDBC/input/BABEL-265.sql b/contrib/test/JDBC/input/BABEL-265.sql new file mode 100644 index 00000000000..b24b5f3dad6 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-265.sql @@ -0,0 +1,56 @@ +-- When ANSI_NULLS is ON, the conditions exp = NULL, exp <> NULL and exp != NULL are never true: +CREATE TABLE t_nulls1 (c1 CHAR(1), c2 INT); +INSERT INTO t_nulls1 VALUES ('A', 1); +INSERT INTO t_nulls1 VALUES ('B', NULL); +GO + +-- Expect 0 rows +SELECT c1 FROM t_nulls1 WHERE c2 = NULL; +GO + +-- Expect 0 rows +SELECT c1 FROM t_nulls1 WHERE c2 <> NULL; +GO + +SELECT c1 FROM t_nulls1 WHERE c2 != NULL; +GO + +-- Only IS NULL and IS NOT NULL can be used. Result: A +SELECT c1 FROM t_nulls1 WHERE c2 IS NOT NULL; +GO + +SET ANSI_NULLS OFF +GO + +-- Expect A +SELECT c1 FROM t_nulls1 WHERE c2 <> NULL; +GO + +SELECT c1 FROM t_nulls1 WHERE c2 != NULL; +GO + +-- Expect B +SELECT c1 FROM t_nulls1 WHERE c2 = NULL; +GO + +-- IS NULL and IS NOT NULL still can be used when ANSI_NULLS is OFF +SELECT c1 FROM t_nulls1 WHERE c2 IS NOT NULL; +GO + +-- RESET ANSI_NULLS AND test behavior is back to normal +SET ANSI_NULLS ON + +-- Expect 0 rows +SELECT c1 FROM t_nulls1 WHERE c2 = NULL; +GO + +-- Expect 0 rows +SELECT c1 FROM t_nulls1 WHERE c2 <> NULL; +GO + +SELECT c1 FROM t_nulls1 WHERE c2 != NULL; +GO + +-- Clean up +DROP TABLE t_nulls1; +GO diff --git a/contrib/test/JDBC/input/BABEL-2659.sql b/contrib/test/JDBC/input/BABEL-2659.sql new file mode 100644 index 00000000000..6dda4205826 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2659.sql @@ -0,0 +1,50 @@ +use master; +go + + +create table t2659(ansi_defaults varchar(10)); +insert into t2659 values ('ok'); +go +select ansi_defaults from t2659; +go + +create table t2659_2(a varchar(10)); +go +-- error: non-existing column +select ansi_defaults from t2659_2; +go + +-- error: non-existing table +select ansi_defaults from t2659_3; +go + + +-- check all keywords touched by fix +CREATE TABLE t2659_all ( + ANSI_DEFAULTS varchar(30), + ANSI_NULL_DFLT_OFF varchar(30), + ANSI_NULL_DFLT_ON varchar(30), + AUTOCOMMIT varchar(30), + FIPS_FLAGGER varchar(30), + FMTONLY varchar(30), + NOEXEC varchar(30), + PARSEONLY varchar(30), + REMOTE_PROC_TRANSACTIONS varchar(30), + SHOWPLAN_ALL varchar(30), + SHOWPLAN_TEXT varchar(30), + SHOWPLAN_XML varchar(30), + XACT_ABORT varchar(30) +); +go + +insert into t2659_all values ( + 'ANSI_DEFAULTS', 'ANSI_NULL_DFLT_OFF', 'ANSI_NULL_DFLT_ON', 'AUTOCOMMIT', 'FIPS_FLAGGER', 'FMTONLY', 'NOEXEC', 'PARSEONLY', 'REMOTE_PROC_TRANSACTIONS', 'SHOWPLAN_ALL', 'SHOWPLAN_TEXT', 'SHOWPLAN_XML', 'XACT_ABORT'); +go + +select ansi_defaults, ansi_null_dflt_off, ansi_null_dflt_on, autocommit, fips_flagger, fmtonly, noexec, parseonly, remote_proc_transactions, showplan_all, showplan_text, showplan_xml, xact_abort from t2659_all; +go + +drop table t2659; +drop table t2659_2; +drop table t2659_all; +go diff --git a/contrib/test/JDBC/input/BABEL-2674.sql b/contrib/test/JDBC/input/BABEL-2674.sql new file mode 100644 index 00000000000..8356d34fc8e --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2674.sql @@ -0,0 +1,55 @@ +USE master +go + +drop table if exists babel_2674_t1; +go +create table babel_2674_t1 (A int); +go +insert into babel_2674_t1 values (1); +go +insert into babel_2674_t1 (a) values (2); +go +insert into babel_2674_t1 (A) values (3); +go +select * from babel_2674_t1; +go + +drop view if exists babel_2674_v1; +go +create view babel_2674_v1 as select A FROM babel_2674_t1; +go +insert into babel_2674_v1 values (4); +go +insert into babel_2674_v1 (a) values (5); +go +insert into babel_2674_v1 (A) values (6); +go +select * from babel_2674_v1; +go +select * from babel_2674_v1 where a = 1; +go +select * from babel_2674_v1 where A = 2; +go + +drop view if exists babel_2674_v1; +go +select * from babel_2674_t1; +go + +SELECT A into babel_2674_t2 FROM babel_2674_t1; +go +select * from babel_2674_t2; +go +INSERT INTO babel_2674_t2 SELECT 7; +go +INSERT INTO babel_2674_t2 (a) SELECT 8; +go +INSERT INTO babel_2674_t2 (A) SELECT 9; +go +select * from babel_2674_t2; +go + +drop table if exists babel_2674_t1; +go +drop table if exists babel_2674_t2; +go \ No newline at end of file diff --git a/contrib/test/JDBC/input/BABEL-2676.sql b/contrib/test/JDBC/input/BABEL-2676.sql new file mode 100644 index 00000000000..1c018a0b486 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2676.sql @@ -0,0 +1,23 @@ +create function mstvf_conditional(@i int) returns @tableVar table +( +a text not null +) +begin + insert into @tableVar values('hello1') + if @i > 0 + return + insert into @tableVar values('hello2') + return +end +go + +-- should return both rows +select * from mstvf_conditional(0) +go + +-- should only return the first row +select * from mstvf_conditional(1) +go + +drop function mstvf_conditional +go diff --git a/contrib/test/JDBC/input/BABEL-2681.sql b/contrib/test/JDBC/input/BABEL-2681.sql new file mode 100644 index 00000000000..9cff8baed72 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2681.sql @@ -0,0 +1,9 @@ +USE master +go + +select cast(SERVERPROPERTY('ProductVersion') as varchar) as ProductVersion; +select cast(SERVERPROPERTY('ProductMajorVersion') as varchar) as ProductMajorVersion; +-- only print till the server version i.e. first newline character +select substring(@@version, 1, CHARINDEX(CHAR(10), @@version) - 1); +select @@microsoftversion; +go \ No newline at end of file diff --git a/contrib/test/JDBC/input/BABEL-2706.sql b/contrib/test/JDBC/input/BABEL-2706.sql new file mode 100644 index 00000000000..28a043dd67a --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2706.sql @@ -0,0 +1,20 @@ +USE master +GO + +CREATE DATABASE db_2706 +GO + +USE db_2706 +GO + +CREATE SCHEMA [Babelfish] +GO + +CREATE TYPE [Babelfish].[table_type] AS TABLE (a int) +GO + +USE master +GO + +DROP DATABASE db_2706 +GO diff --git a/contrib/test/JDBC/input/BABEL-2724.sql b/contrib/test/JDBC/input/BABEL-2724.sql new file mode 100644 index 00000000000..4d52d2ef588 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2724.sql @@ -0,0 +1,41 @@ +use master; +go + +create table t2724(a int); +insert into t2724 values (1); +go + +select a from t2724; +go + +select t2724.a from t2724; +go + +select .t2724.a from t2724; +go + +-- valid error +select .a from t2724; +go + +-- valid error +select ..a from t2724; +go + +-- valid error +select dbo..a from t2724; +go + +-- special case on insert-column. DOT and qualifier is totally ignored +insert into t2724(a) values (2); +insert into t2724(.a) values (3); +insert into t2724(........a) values (4); +insert into t2724(invalid.a) values (5); +insert into t2724(x.y...z....w...a) values (6); +go + +select * from t2724; +go + +drop table t2724; +go diff --git a/contrib/test/JDBC/input/BABEL-2725.sql b/contrib/test/JDBC/input/BABEL-2725.sql new file mode 100644 index 00000000000..d798ae2a2fd --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-2725.sql @@ -0,0 +1,42 @@ +use master; +go + +-- basic operations +create table t2725 (a int, b int, offset int not null); +go +insert into t2725 (a, offset) values (1, 2); +go +select a, b, offset from t2725; +go +select a, b, t2725.offset from t2725; +go +alter table t2725 add binary binary; -- column "binary" whose type is binary +go +insert into t2725(offset,binary) values (3, 0x04); +go +create unique index i1813 on t2725(offset); +go +insert into t2725(offset,binary) values (4, 0x05); +insert into t2725(offset,binary) values (4, 0x05); +go +select abs(-offset)*2 c, binary from t2725; +go +update t2725 set offset = 5 output deleted.offset where offset = 2; +go +delete from t2725 output offset where offset = 4; +go +select offset from t2725 order by offset; +go +select [offset] from t2725 order by offset; +go +select t2725.[offset] from t2725 order by offset; +go +select oFfSet from t2725 order by ofFSET; +go +drop table t2725; +go + +create table offset(offset int); +go +drop table offset; +go diff --git a/contrib/test/JDBC/input/BABEL-338.sql b/contrib/test/JDBC/input/BABEL-338.sql new file mode 100644 index 00000000000..c0747f3d395 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-338.sql @@ -0,0 +1,126 @@ +create table t (a int, b int) +go + +insert t values(1,1) +insert t values(2,2) +insert t values(3,3) +insert t values(4,4) +insert t values(5,5) +go + +select * from t +go + +update t set b = b*-1 where b > 0 +go + +select * from t +go + +update top(2) t set b = b*-1 where b < 0 +go + +select count(*) from t where b > 0 +go + +delete top(2) from t where b < 0 +go + +select count(*) from t +go + +declare @a int +set @a = 1 +delete top (@a) from t +go + +select count(*) from t +go + +-- test TOP clause in UPDATE together with JOIN +create table t1 (a int, b int) +go + +insert t1 values(1,1) +insert t1 values(2,2) +insert t1 values(3,3) +insert t1 values(4,4) +insert t1 values(5,5) +go + +create table t2 (a int, b int) +go + +insert t2 values(1,-1) +insert t2 values(2,2) +insert t2 values(3,3) +insert t2 values(400,4) +insert t2 values(500,5) +go + +update top(2) t1 set a = a*-1 from t1 alias1 inner join t2 alias2 on alias1.a = alias2.a +go + +select count(*) from t1 where a < 0 +go + +-- test TOP clause in DELETE together with JOIN +create table t3 (a int, b int) +go + +insert t3 values(1,1) +insert t3 values(2,2) +insert t3 values(-3,-3) +go + +create table t4 (a int, b int) +go + +insert t4 values(1,-1) +insert t4 values(2,2) +insert t4 values(3,3) +insert t4 values(400,4) +insert t4 values(500,5) +go + +delete top(1) t3 from t3 alias3 inner join t4 alias4 on alias3.b = alias4.b +go + +select count(*) from t3 +go + +-- test error message on TOP n PERCENT +-- TOP 100 PERCENT should be supported +update top (100) percent t3 set b = 100 +go + +select count(*) from t3 where b = 100 +go + +delete top (100) percent from t3 +go + +select count(*) from t3 +go + +-- other percentage should report unsupported error +update top (10) percent t4 set b = 100 +go + +delete top (10) percent from t4 +go + +drop table t +go + +drop table t1 +go + +drop table t2 +go + +drop table t3 +go + +drop table t4 +go diff --git a/contrib/test/JDBC/input/BABEL-388.sql b/contrib/test/JDBC/input/BABEL-388.sql new file mode 100644 index 00000000000..9b55559c921 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-388.sql @@ -0,0 +1,65 @@ +-- note: this test only can run on babel since it relies on pg_typeof + +create view babel_388_v1 as select null a; +GO +select cast(pg_typeof(a) as varchar(10)) as typname from babel_388_v1; +GO + +create view babel_388_v2 as select null a union select null; +GO +select cast(pg_typeof(a) as varchar(10)) as typname from babel_388_v2; +GO + +create view babel_388_v3 as select null a union select null union select 1; +GO +select cast(pg_typeof(a) as varchar(10)) as typname from babel_388_v3; +GO + +create view babel_388_v4 as select 1 a; +GO +select cast(pg_typeof(a) as varchar(10)) as typname from babel_388_v4; +GO + +create view babel_388_v5 as select 'string' a; +GO +select cast(pg_typeof(a) as varchar(10)) as typname from babel_388_v5; +GO + +create view babel_388_v6 as select 1 a UNION select NULL; +GO +select cast(pg_typeof(a) as varchar(10)) as typname from babel_388_v6; +GO + +create view babel_388_v7 as select NULL a UNION select 1; +GO +select cast(pg_typeof(a) as varchar(10)) as typname from babel_388_v7; +GO + +create view babel_388_v8 as select 'string' a UNION select NULL; +GO +select cast(pg_typeof(a) as varchar(10)) as typname from babel_388_v8; +GO + +create view babel_388_v9 as select NULL a UNION select 'string'; +GO +select cast(pg_typeof(a) as varchar(10)) as typname from babel_388_v9; +GO + +DROP view babel_388_v1; +GO +DROP view babel_388_v2; +GO +DROP view babel_388_v3; +GO +DROP view babel_388_v4; +GO +DROP view babel_388_v5; +GO +DROP view babel_388_v6; +GO +DROP view babel_388_v7; +GO +DROP view babel_388_v8; +GO +DROP view babel_388_v9; +GO diff --git a/contrib/test/JDBC/input/BABEL-405.sql b/contrib/test/JDBC/input/BABEL-405.sql new file mode 100644 index 00000000000..3435f190568 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-405.sql @@ -0,0 +1,200 @@ +create table t_405_insert1(x int); +create table t_405_insert2(x int); +insert into t_405_insert1 values(1); +insert into t_405_insert1 select * from t_405_insert1; +insert into t_405_insert1 select * from t_405_insert1; +go + +create trigger tr1 on t_405_insert2 instead of insert +as +begin +select * from t_405_insert1; +end +go + +create trigger tr2 on t_405_insert2 instead of insert +as +begin +select * from t_405_insert1; +end +go + +insert into t_405_insert2 values(2); +go + +select * from t_405_insert2; +go + +drop trigger tr1; +go + +create trigger tr1 on t_405_insert2 instead of insert +as +begin +end +go + +insert into t_405_insert2 values(2); +select * from t_405_insert2; +go + +drop trigger tr1; +go + +insert into t_405_insert2 values(2); +select * from t_405_insert2; +go + +drop table t_405_insert1; +drop table t_405_insert2; +go + +create table t_405_delete1(x int); +create table t_405_delete2(x int); +insert into t_405_delete1 values(1); +insert into t_405_delete1 select * from t_405_delete1; +insert into t_405_delete1 select * from t_405_delete1; +insert into t_405_delete2 values(2); +go + +create trigger tr1 on t_405_delete2 instead of delete +as +begin +select * from t_405_delete1; +end +go + +create trigger tr2 on t_405_delete2 instead of insert +as +begin +select '1'; +end +go + +delete from t_405_delete2 where 1=1; +go + +select * from t_405_delete2; +go + +drop trigger tr1; +go + +create trigger tr1 on t_405_delete2 instead of delete +as +begin +end +go + +delete from t_405_delete2; +select * from t_405_delete2; +go + +drop trigger tr1; +go + +insert into t_405_delete2 values(2); +select * from t_405_delete2; +go + +drop table t_405_delete1; +drop table t_405_delete2; +go + +create table t_405_update1(x int); +create table t_405_update2(x int); +insert into t_405_update1 values(1); +insert into t_405_update1 select * from t_405_update1; +insert into t_405_update1 select * from t_405_update1; +insert into t_405_update2 values(1); +go + +create trigger tr1 on t_405_update2 instead of update +as +begin +select * from t_405_update1; +end +go + +create trigger tr2 on t_405_update2 instead of update +as +begin +select 'hello'; +end +go + +update t_405_update2 set x = 2 where x=1; +go + +select * from t_405_update2; +go + +drop trigger tr1; +go + +create trigger tr1 on t_405_update2 instead of update +as +begin +end +go + +update t_405_update2 set x = 3 where 1 = 1; +select * from t_405_update2; +go + +drop trigger tr1; +go + +update t_405_update2 set x=2 where x=1; +select * from t_405_update2; +go + +drop table t_405_update1; +drop table t_405_update2; +go + +create table t_405_insert1(x int); +create table t_405_insert2(x int); +insert into t_405_insert1 values(1); +insert into t_405_insert1 select * from t_405_insert1; +insert into t_405_insert1 select * from t_405_insert1; +go + +create trigger tr1 on t_405_insert2 instead of insert +as +begin +select * from t_405_insert1 +end; +go + +create trigger after_trig on t_405_insert2 after insert +as +begin +select 'hello' +end; +go + +insert into t_405_insert2 values(3); +go + +drop trigger tr1; +go + +insert into t_405_insert2 values(3); +go + +select * from t_405_insert2; +go + +drop trigger after_trig; + +insert into t_405_insert2 values(3); +go + +select * from t_405_insert2; +go + +drop table t_405_insert1; +drop table t_405_insert2; +go + diff --git a/contrib/test/JDBC/input/BABEL-407.sql b/contrib/test/JDBC/input/BABEL-407.sql new file mode 100644 index 00000000000..6c3a0f3b3d8 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-407.sql @@ -0,0 +1,20 @@ +USE master +go + +CREATE FUNCTION babel_407_func (@a INT) +RETURNS TABLE AS +RETURN (SELECT @a + 1 AS col); +go + +CREATE VIEW babel_407_view AS +SELECT * FROM babel_407_func(123) +go + +SELECT * FROM babel_407_view +go + +DROP VIEW babel_407_view +go + +DROP FUNCTION babel_407_func +go diff --git a/contrib/test/JDBC/input/BABEL-453.sql b/contrib/test/JDBC/input/BABEL-453.sql new file mode 100644 index 00000000000..9e7eb416ae3 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-453.sql @@ -0,0 +1,117 @@ +use master; +go + +CREATE TABLE t453_real(a real); +CREATE TABLE t453_dp(a double precision); + +-- binary -> real +declare @a binary(4) = 0xabcdabcd; +select (cast (@a as real)); +go +declare @a binary(4) = 0xabcdabcd; +insert into t453_real values (@a); +go + +-- binary -> double precision +declare @a binary(4) = 0xabcdabcd; +select (cast (@a as double precision)); +go +declare @a binary(4) = 0xabcdabcd; +insert into t453_dp values (@a); +go + +-- varbinary -> real +declare @a varbinary(4) = 0xabcdabcd; +select (cast (@a as real)); +go +declare @a varbinary(4) = 0xabcdabcd; +insert into t453_real values (@a); +go + +-- varbinary -> double precision +declare @a varbinary(4) = 0xabcdabcd; +select (cast (@a as double precision)); +go +declare @a varbinary(4) = 0xabcdabcd; +insert into t453_dp values (@a); +go + +-- reported case +CREATE PROCEDURE p453(@val real) AS +BEGIN + DECLARE @BinaryVariable sys.varbinary(4) = @val + PRINT @BinaryVariable + PRINT cast(@BinaryVariable as real) +END +GO +EXEC p453 1.1; +GO + +DROP PROCEDURE p453; +DROP TABLE t453_real; +DROP TABLE t453_dp; +GO + + +-- test for string-literal to (var)binary +CREATE TABLE t453_bin(a binary(4)); +CREATE TABLE t453_varbin(a varbinary(4)); +GO + +INSERT INTO t453_bin VALUES ('ab'); +GO +INSERT INTO t453_varbin VALUES ('ab'); +GO + +INSERT INTO t453_bin VALUES (''); +GO +INSERT INTO t453_varbin VALUES (''); +GO + +DECLARE @var CHAR(10) = 'ab'; +INSERT INTO t453_bin VALUES (@var); +GO +DECLARE @var CHAR(10) = 'ab'; +INSERT INTO t453_varbin VALUES (@var); +GO + +DECLARE @var VARCHAR(10) = 'ab'; +INSERT INTO t453_bin VALUES (@var); +GO +DECLARE @var VARCHAR(10) = 'ab'; +INSERT INTO t453_varbin VALUES (@var); +GO + + +-- valid +INSERT INTO t453_bin VALUES (NULL); +INSERT INTO t453_varbin VALUES (NULL); +GO + +INSERT INTO t453_bin VALUES (0xab); +INSERT INTO t453_varbin VALUES (0xab); +GO + +INSERT INTO t453_bin VALUES (0xabcd1234); +INSERT INTO t453_varbin VALUES (0xabcd1234); +GO + +INSERT INTO t453_bin VALUES (1); +INSERT INTO t453_varbin VALUES (1); +GO + +DECLARE @var VARCHAR(10) = 'ab'; +INSERT INTO t453_bin VALUES (convert(binary(4), @var)); +GO +DECLARE @var VARCHAR(10) = 'ab'; +INSERT INTO t453_varbin VALUES (convert(binary(4), @var)); +GO + +SELECT count(*) FROM t453_bin; +GO +SELECT count(*) FROM t453_varbin; +GO + +DROP TABLE t453_bin; +DROP TABLE t453_varbin; +GO diff --git a/contrib/test/JDBC/input/BABEL-480.sql b/contrib/test/JDBC/input/BABEL-480.sql new file mode 100644 index 00000000000..c167dbef8d1 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-480.sql @@ -0,0 +1,17 @@ +create procedure p_rcv3 as begin select 123 end +go + +create procedure p_rcv12a +as +begin -- begin + end lines are optional +select 'hello' +select 'world' +select '!!!' +end -- begin + end lines are optional +go + +drop procedure p_rcv3 +GO + +drop procedure p_rcv12a +GO \ No newline at end of file diff --git a/contrib/test/JDBC/input/BABEL-493.sql b/contrib/test/JDBC/input/BABEL-493.sql new file mode 100644 index 00000000000..f25b0856b25 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-493.sql @@ -0,0 +1,70 @@ +-- please note that this test conatins PG-specific feature to check the plan (to confirm index is hit) + +create table babel_493_t1(i int, b bit); +GO +create index babel_493_t1_full_idx_a on babel_493_t1(i); +GO + +-- FULL index +create index babel_493_t1_full_idx_b on babel_493_t1(b); +GO + +insert into babel_493_t1 values (1, 0), (2, 0), (3, 0), (4, 0); +insert into babel_493_t1 select i+4, b from babel_493_t1; +insert into babel_493_t1 select i+8, b from babel_493_t1; +insert into babel_493_t1 select i+16, b from babel_493_t1; +insert into babel_493_t1 select i+32, b from babel_493_t1; +insert into babel_493_t1 select i+64, b from babel_493_t1; +insert into babel_493_t1 select i+128, b from babel_493_t1; +insert into babel_493_t1 select i+256, b from babel_493_t1; +insert into babel_493_t1 select i+512, b from babel_493_t1; +insert into babel_493_t1 select i+1024, b from babel_493_t1; +insert into babel_493_t1 select i+2048, b from babel_493_t1; +-- make a few rows have bit value 1 +update babel_493_t1 set b = 1 where i = 3; +update babel_493_t1 set b = 1 where i = 1111; +update babel_493_t1 set b = 1 where i = 4093; +-- make a few rows have bit value NULL +update babel_493_t1 set b = NULL where i = 7; +update babel_493_t1 set b = NULL where i = 2222; +GO + +SELECT count(*) from babel_493_t1 where b = 0; +GO + +SELECT count(*) from babel_493_t1 where b = 1; +GO + +drop index babel_493_t1_full_idx_b on babel_493_t1; +GO + +-- PARTIAL index +create index babel_493_t1_partial_idx_b on babel_493_t1(b) where b = 1; +GO + +-- Bitmap Index Scan +SELECT count(*) from babel_493_t1 where b = 1; +GO + +-- Bitmap Index Scan + BitMap And +SELECT count(*) from babel_493_t1 where b = 1 and i = 4093; +GO + +drop index babel_493_t1_partial_idx_b on babel_493_t1; +GO + +-- composite index and check matching of boolean index columns to WHERE conditions and sort keys +create index babel_493_composite_idx_a_b on babel_493_t1(b,i); +GO + +select top(10) * from babel_493_t1 order by b, i; +GO + +select top(10) * from babel_493_t1 where b = 1 order by i; +GO + +select top(10) * from babel_493_t1 where not (b = 1) order by i; +GO + +DROP table babel_493_t1; +GO diff --git a/contrib/test/JDBC/input/BABEL-559.sql b/contrib/test/JDBC/input/BABEL-559.sql new file mode 100644 index 00000000000..7c60f7811ef --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-559.sql @@ -0,0 +1,35 @@ +create table babel_559_t1 (a int); +go + +alter table babel_559_t1 add primary key (a asc); +go + +create table babel_559_t2 (a int, b int, c int, d int); +go + +alter table babel_559_t2 add primary key (a asc, b desc , c); +go + +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_unique_constraint', 'ignore'; +go + +alter table babel_559_t2 add unique (a asc); +go + +alter table babel_559_t2 add unique (a asc, c desc); +go + +create table babel_559_t3 (a int, primary key(a asc)); +go + +create table babel_559_t4 (a int, b int, primary key(a asc, b desc)); +go + +create table babel_559_t5 (a int, b int, c varchar(20), unique(a asc, b, c desc)); +go + +create table babel_559_t6 (a int); +go + +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_unique_constraint', 'strict'; +go diff --git a/contrib/test/JDBC/input/BABEL-565.sql b/contrib/test/JDBC/input/BABEL-565.sql new file mode 100644 index 00000000000..998c525d482 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-565.sql @@ -0,0 +1,37 @@ +CREATE TABLE AccountsReceivable ( + Id int IDENTITY(1,1) NOT NULL, + ApplicationId int NOT NULL +) ON [PRIMARY] +GO + +drop table AccountsReceivable +GO + +-- test TEXTIMAGE_ON +CREATE TABLE AccountsReceivable ( + Id int IDENTITY(1,1) NOT NULL, + ApplicationId int NOT NULL +) TEXTIMAGE_ON [PRIMARY] +GO + +drop table AccountsReceivable +GO + +-- test on primary with TEXTIMAGE_ON +CREATE TABLE AccountsReceivable ( + Id int IDENTITY(1,1) NOT NULL, + ApplicationId int NOT NULL +) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] +GO + +drop table AccountsReceivable +GO + +CREATE TABLE AccountsReceivable ( + Id int IDENTITY(1,1) NOT NULL, + ApplicationId int NOT NULL +) TEXTIMAGE_ON [PRIMARY] ON [PRIMARY] +GO + +drop table AccountsReceivable +GO diff --git a/contrib/test/JDBC/input/BABEL-586.sql b/contrib/test/JDBC/input/BABEL-586.sql new file mode 100644 index 00000000000..dbc4fae0a85 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-586.sql @@ -0,0 +1,99 @@ +CREATE PROCEDURE test_proc1 (@p0 int, @p1 int OUTPUT, @p2 smallint, @p3 smallint OUTPUT) +AS BEGIN +SELECT @p1=@p0, @p3=@p2; +RETURN; +END +GO + +CREATE PROCEDURE test_proc2 (@p0 int, @p1 int OUTPUT, @p2 smallint, @p3 smallint OUTPUT) +AS BEGIN +SELECT @p1=@p0, @p3= @p2; +RETURN; +END +GO + +CREATE PROCEDURE test_proc3 (@p0 int, @p1 int OUTPUT, @p2 smallint, @p3 smallint OUTPUT) +AS BEGIN +SELECT @p1= @p0, @p3=@p2; +RETURN; +END +GO + +CREATE PROCEDURE test_proc4 (@p0 int, @p1 int OUTPUT, @p2 smallint, @p3 smallint OUTPUT) +AS BEGIN +SELECT @p1=@p0+@p0, @p3= @p2+@p2; +RETURN; +END +GO + +CREATE PROCEDURE test_proc5 (@p0 int, @p1 int OUTPUT, @p2 smallint, @p3 smallint OUTPUT) +AS BEGIN +SELECT @p1=CAST(@p0 as INT), @p3= @p2+@p2; +RETURN; +END +GO + +CREATE PROCEDURE test_proc6 (@p0 int, @p1 int OUTPUT, @p2 smallint, @p3 smallint OUTPUT) +AS BEGIN +SELECT @p1=1234, @p3= 5678; +RETURN; +END +GO + + +CREATE PROCEDURE test_proc0 +AS BEGIN +DECLARE @a int; +DECLARE @b smallint; + +EXEC test_proc1 1, @a OUT, 2, @b OUT; +PRINT @a +PRINT @b + +EXEC test_proc2 3, @a OUT, 4, @b OUT; +PRINT @a +PRINT @b + +EXEC test_proc3 5, @a OUT, 6, @b OUT; +PRINT @a +PRINT @b + +EXEC test_proc4 7, @a OUT, 9, @b OUT; +PRINT @a +PRINT @b + +EXEC test_proc5 11, @a OUT, 13, @b OUT; +PRINT @a +PRINT @b + +EXEC test_proc6 17, @a OUT, 19, @b OUT; +PRINT @a +PRINT @b + +END +GO + +EXEC test_proc0 +GO + +DROP PROCEDURE test_proc1 +GO + +DROP PROCEDURE test_proc2 +GO + +DROP PROCEDURE test_proc3 +GO + +DROP PROCEDURE test_proc4 +GO + +DROP PROCEDURE test_proc5 +GO + +DROP PROCEDURE test_proc6 +GO + +DROP PROCEDURE test_proc0 +GO + diff --git a/contrib/test/JDBC/input/BABEL-588.sql b/contrib/test/JDBC/input/BABEL-588.sql new file mode 100644 index 00000000000..a0c364e1a4d --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-588.sql @@ -0,0 +1,1072 @@ +-- Tests for OUTPUT with INSERT statement -- +create table t1(num integer, word varchar(10)); +go + +insert into t1 output inserted.num values(1, 'one'); +go + +insert into t1 output inserted.num, inserted.word values(2, 'two'); +go + +insert into t1 output inserted.* values(3, 'three'); +go + +select * from t1; +go + +-- Test conflict case with table name +create table inserted(num integer); +go + +insert into inserted output inserted.* values(10); +go + +-- Tests for OUTPUT with DELETE statement -- +delete t1 output deleted.num where num=1; +go + +delete t1 output deleted.num, deleted.word where word='two'; +go + +delete t1 output deleted.* where num=3; +go + +select * from t1; +go + +-- Test conflict cases with table name +create table deleted(num integer, nextnum integer); +go + +insert into deleted values(10, 11), (12, 13), (14,15); +go + +insert into t1 values(10, 'ten'), (12, 'twelve'), (14, 'fourteen'); +go + +delete deleted +output deleted.num +from deleted +inner join t1 + on deleted.num=t1.num +where t1.num=10; +go + +delete deleted +output deleted.nextnum +from deleted +inner join t1 + on deleted.num=t1.num +where t1.num=12; +go + +delete t1 +output t1.word +from t1 +inner join deleted + on t1.num=deleted.num +where t1.num=14; +go + +select * from deleted; +go + +select * from t1; +go + +-- Cleanup +drop table t1; +go + +drop table inserted; +go + +drop table deleted; +go + +-- Tests for OUTPUT INTO with INSERT statement -- +create table t1(num integer, word varchar(10)); +go + +create table t2(num integer, word varchar(10)); +go + +insert into t1(num, word) + output inserted.num, inserted.word into t2 +values(1, 'one'); +go + +select * from t1; +go + +select * from t2; +go + +create table t3(num integer, word varchar(10)); +go + +with cte(num, word) as( + select num, word from t1 +) +insert into t2(num, word) + output inserted.num, inserted.word into t3 +select num, word from cte; +go + +select * from t3; +go + +-- Test recursive CTE case +create table t4(num integer); +go + +create table t5(num integer); +go + +with Numbers as +( + select 1 as n + union all + select n + 1 from Numbers where n + 1 <= 10 +) +insert into t4(num) +output num into t5 +select n from Numbers; +go + +select * from t4; +go + +-- Cleanup +drop table t1; +go + +drop table t2; +go + +drop table t3; +go + +drop table t4; +go + +drop table t5; +go + +-- Tests for OUTPUT INTO with DELETE statement -- +create table t1(num integer, word varchar(10)); +go + +insert into t1 values(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four'); +go + +create table t1_insert(num integer, word varchar(10)); +go + +delete t1 +output deleted.* into t1_insert +where num < 4; +go + +create table t2(num integer, word varchar(10)); +go + +insert into t1 values(1, 'one'), (2, 'two'), (3, 'three'); +go + +select * from t1; +go + +select * from t1_insert; +go + +delete from t1_insert +output deleted.num, deleted.word into t2 +where num in ( + select num from t1); +go + +select * from t1_insert; +go + +select * from t2; +go + +create table inserted(num integer); +go + +insert into inserted output inserted.* values(10); +go + +create table deleted(num integer, nextnum integer); +go + +insert into deleted values(10, 11); +go + +insert into t1 values(10, 'ten'); +go + +delete deleted +output deleted.num into inserted +from deleted +inner join t1 + on deleted.num=t1.num +where t1.num=10; +go + +select * from deleted; +go + +select * from t1; +go + +-- Cleanup +drop table t1; +go + +drop table t1_insert; +go + +drop table t2; +go + +drop table inserted; +go + +drop table deleted; +go + +-- Tests for OUTPUT with UPDATE statement -- +create table t1(a integer); +go + +insert into t1(a) values (1),(2); +go + +update t1 set a=20 +output deleted.a, inserted.a +where a>1; +go + +update t1 set a=30 +output deleted.a, inserted.a; +go + +-- Test that order of execution of AND and OR in where clause is preserved +create table t2(a integer, b integer, c integer, d integer); +go + +insert into t2 values(1,2,3,4), (5,6,7,8), (4,2,6,1), (8,9,0,3); +go + +update t2 set a=25 output deleted.* +where a>2 and b<20 or c>5 and d>0; +go + +create table table1 (age integer, fname varchar(100), year integer); + insert into table1 (age, fname, year) values (10, 'albert', 30); + insert into table1 (age, fname, year) values (100, 'isaac', 40); + insert into table1 (age, fname, year) values (30, 'marie', 70); + select * from table1; +go + +create table table2 (age integer, fname varchar(100), lastname varchar(100)); + insert into table2 (age, fname, lastname) values (10, 'albert', 'einstein'); + insert into table2 (age, fname, lastname) values (100, 'isaac', 'newton'); + insert into table2 (age, fname, lastname) values (30, 'mary', 'kom'); + select * from table2; +go + +update table1 set age=1 output deleted.age +from table1 t1 +left join table2 t2 +on t1.fname=t2.fname where year>50 and lastname!='smith'; +go + +update table1 set age=1 output deleted.age +from table1 t1 +left join table2 t2 +on t1.fname=t2.fname where year>50; +go + +update table1 set year=1990 output deleted.*, inserted.* +from table1 t1 +left join table2 t2 +on t1.fname=t2.fname where t1.fname='isaac'; + +update table1 set year=2020 output deleted.* +from table2 t2 +where table1.fname=t2.fname and lastname='einstein'; +go + +-- Cleanup +drop table t1; +go + +drop table t2; +go + +drop table table1; +go + +drop table table2; +go + +-- Tests for OUTPUT INTO with UPDATE statement -- +create table t1(a integer); +go + +create table t1_insert(a integer); +go + +insert into t1(a) values (1),(2); +go + +update t1 set a=20 +output deleted.a into t1_insert +where a>1; +go + +select * from t1_insert; +go + +update t1 set a=30 +output inserted.a into t1_insert; +go + +select * from t1_insert; +go + +-- Test that order of execution of AND and OR in where clause is preserved +create table t2(a integer, b integer, c integer, d integer); +go + +create table t2_insert(a integer, b integer, c integer, d integer); +go + +insert into t2 values(1,2,3,4), (5,6,7,8), (4,2,6,1), (8,9,0,3); +go + +update t2 set a=25 output deleted.* into t2_insert +where a>2 and b<20 or c>5 and d>0; +go + +select * from t2_insert; +go + +create table table1 (age integer, fname varchar(100), year integer); + insert into table1 (age, fname, year) values (10, 'albert', 30); + insert into table1 (age, fname, year) values (100, 'isaac', 40); + insert into table1 (age, fname, year) values (30, 'marie', 70); + select * from table1; +go + +create table table2 (age integer, fname varchar(100), lastname varchar(100)); + insert into table2 (age, fname, lastname) values (10, 'albert', 'einstein'); + insert into table2 (age, fname, lastname) values (100, 'isaac', 'newton'); + insert into table2 (age, fname, lastname) values (30, 'mary', 'kom'); + select * from table2; +go + +create table table_insert (age integer, fname varchar(100), year integer); +go + +update table1 set age=1 +output deleted.age, inserted.fname, inserted.year into table_insert +from table1 t1 +left join table2 t2 +on t1.fname=t2.fname where year>50 and lastname!='smith'; +go + +select * from table_insert; +go + +update table1 set age=1 +output deleted.age, inserted.fname, inserted.year into table_insert +from table1 t1 +left join table2 t2 +on t1.fname=t2.fname where year>50; +go + +select * from table_insert; +go + +update table1 set year=1990 output deleted.*, inserted.* +from table1 t1 +left join table2 t2 +on t1.fname=t2.fname where t1.fname='isaac'; + +select * from table_insert; +go + +update table1 set year=2020 output deleted.* +from table2 t2 +where table1.fname=t2.fname and lastname='einstein'; +go + +select * from table_insert; + +-- Cleanup +drop table t1; +go + +drop table t1_insert; +go + +drop table t2; +go + +drop table t2_insert; +go + +drop table table1; +go + +drop table table2; +go + +drop table table_insert; +go + +-- Tests for order of execution of OUTPUT clause -- +create table t1 (age integer, fname varchar(20), year integer); +go + +create trigger t1_insert_trig on t1 for insert as +begin + update t1 set age = 99; +end; +go + +insert into t1 output inserted.* values (21, 'Amanda', 2000); +go + +select * from t1; +go + +drop trigger t1_insert_trig; +go + +create trigger t1_update_trig on t1 for update as +begin + delete t1; +end; +go + +update t1 set fname = 'Lucy' +output deleted.fname, inserted.fname +where fname = 'Amanda'; +go + +select * from t1; +go + +insert into t1 values (21, 'Amanda', 2000); +go + +drop trigger t1_update_trig; +go + +create trigger t1_delete_trig on t1 for delete as +begin + insert into t1 values (22, 'Tracy', 1998) +end; +go + +delete t1 output deleted.year; +go + +select * from t1; +go + +drop trigger t1_delete_trig +go + +-- Cleanup +drop table t1; +go + +-- Tests for NULL in output target list (BABEL-1768) -- +create table t1(age integer, fname varchar(100)); +create table t2(age integer, fname varchar(100), lname varchar(100)); +go + +insert into t1 + output inserted.age, inserted.fname, null into t2 +values(10, 'albert'); +go + +select * from t1; +go + +select * from t2; +go + +update t2 set age=20 + output deleted.age, null into t1 +where age=10; +go + +select * from t2; +go + +select * from t1; +go + +delete t1 +output deleted.age, deleted.fname, null; +go + +select * from t1; +go + +-- Cleanup +drop table t1; +go + +drop table t2; +go + +-- Tests for column names for target table in OUTPUT INTO (BABEL-1769) -- +create table t1(num integer, word varchar(10)); +go + +create table t2(num integer, word varchar(10), next_num integer); +go + +create table t3(prev_word varchar(10), random_number integer); +go + +insert into t1 +output inserted.num, inserted.word into t2(num, word) +values(1, 'one'); +go + +select * from t1; +go + +select * from t2; +go + +update t1 set word='one unit' +output deleted.word into t3(prev_word) +where num=1; +go + +select * from t1; +go + +select * from t3; +go + +delete t2 +output deleted.num into t1(num); +go + +select * from t2; +go + +select * from t1; +go + +-- Cleanup +drop table t1; +go + +drop table t2; +go + +drop table t3; +go + + +-- Test OUTPUT with temp tables -- +create table non_temp_tbl(fname varchar(10), lname varchar(10), age integer, score decimal); +create table #temp_tbl(fname varchar(10), lname varchar(10), age integer, score decimal); +go + +insert into non_temp_tbl +output inserted.* into #temp_tbl +values ('kelly', 'slater', 40, 100), ('john', 'cena', 50, 78); +go + +select * from non_temp_tbl; +go + +select * from #temp_tbl; +go + +update #temp_tbl set score=0 +output inserted.* into non_temp_tbl +where age=40; +go + +select * from #temp_tbl; +go + +select * from non_temp_tbl; +go + +-- Test OUTPUT with triggers -- +delete non_temp_tbl; +go + +delete #temp_tbl; +go + +create trigger insert_output_trig on non_temp_tbl for insert +as +begin +update non_temp_tbl set age=-1 +output inserted.*, deleted.* +end; +go + +insert into non_temp_tbl values ('joey', 'tribbiani', 45, 99); +go + +drop trigger insert_output_trig; +go + +create trigger update_output_trig on non_temp_tbl for update +as +begin +insert into non_temp_tbl +output inserted.* into #temp_tbl +values ('joni', 'mitchell', 80, 0) +end; +go + +update non_temp_tbl set lname='morgan' +where age=-1; +go + +select * from non_temp_tbl; +go + +select * from #temp_tbl; +go + +-- Cleanup +drop table #temp_tbl; +go + +drop table non_temp_tbl; +go + +-- Test OUTPUT with procedures -- +create table t1(num integer, word varchar(10)); +create table t2(num integer, word varchar(10)); +go + +create procedure output_insert_proc as +begin +insert into t1 output inserted.* into t2 values(1, 'one'); +end; +go + +exec output_insert_proc; +go + +select * from t1; +go + +select * from t2; +go + +create procedure output_update_proc as +begin +update t1 set num=100 output inserted.*, deleted.* where num=1; +end; +go + +exec output_update_proc; +go + +select * from t1; +go + +create procedure output_delete_proc as +begin +delete t1 output deleted.*; +end; +go + +exec output_delete_proc; +go + +select * from t1; +go + +-- Cleanup +drop procedure output_insert_proc; +go + +drop procedure output_update_proc; +go + +drop procedure output_delete_proc; +go + +drop table t1; +go + +drop table t2; +go + +-- [BABEL-1921] Test OUTPUT with functions and expressions -- +create table t1(num integer, word varchar(10)); +go + +create table t2(num integer, word varchar(10)); +go + +create table t3(str varchar(20)); +go + +insert into t1 output inserted.num+2 values(1, 'one'); +go + +select * from t1; +go + +insert into t1 output round(inserted.num)+1, 'sum' into t2 values(2, 'two'); +go + +select * from t1; +go + +select * from t2; +go + +insert into t1 values (3, 'three'), (4, 'four'), (5, 'five'); +go + +select * from t1; +go + +update t1 set word = 'one unit' output concat(inserted.word, '_old') where num = 1; +go + +select * from t1; +go + +update t1 set word = 'two units' + output concat(inserted.word, '_old') into t3 +where num = 2 and word = 'two'; +go + +select * from t1; +go + +select * from t3; +go + +delete t1 output round(deleted.num)+5 where num = 3; +go + +select * from t1; +go + +delete t1 output concat(deleted.word, '_old') into t3 where num = 4; +go + +select * from t1; +go + +select * from t3; +go + +-- Test nested functions +insert into t1 output round(floor(inserted.num)) values (6, 'six'), (7, 'seven'), (8, 'eight'), (9, 'nine'); +go + +select * from t1; +go + +-- Cleanup +drop table t1; +go + +drop table t2; +go + +drop table t3; +go + +-- Test that order by is working -- +create table t1(num integer, word varchar(10)); +go + +create table t2(num integer, word varchar(10)); +go + +insert into t1 values(2, 'two'), (1, 'one'), (3, 'three'); +go + +insert into t2 select * from t1 order by num; +go + +select * from t2; +go + +select * from t1; +go + +-- Cleanup +drop table t1; +go + +drop table t2; +go + +-- [BABEL-1901] Test specific cases that trigger ambiguous column errors +create table t1(num integer, word varchar(10)); +go + +create table t2(prev_word varchar(10), new_word varchar(10)); +go + +insert into t1 values(1, 'one'); +go + +-- output deleted, inserted of same column into table +update t1 set word='one unit' +output deleted.word, inserted.word into t2(prev_word, new_word) +where num=1; +go + +select * from t1; +go + +select * from t2; +go + +delete t1; +go + +drop table t2; +go + +create table t2(num integer, word varchar(10)); +go + +insert into t1 values(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four'), (5, 'five'); +go + +-- delete with top +delete top 2 t1 +output deleted.* into t2 +where num<5; +go + +select * from t1; +go + +select * from t2; +go + +-- 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 +where t1.num = x.num and t1.num<5; +go + +select * from t1; +go + +select * from t2; +go + +drop table t1; +go + +drop table t2; +go + +CREATE TABLE t1( + c1PK INT PRIMARY KEY + , c2INT INT NOT NULL + , c3STR VARCHAR(50) NOT NULL + , c4COMMENT VARCHAR(100) NOT NULL +) +go +CREATE TABLE HISTORY( + c4BEFORE VARCHAR(100) NOT NULL + , c4AFTER VARCHAR(100) NOT NULL +) +go +INSERT INTO t1 VALUES( 1, 10, 'filler1', 'vanilla insert' ) +go + +UPDATE t1 +SET c4COMMENT = 'updated: output to table' +OUTPUT DELETED.c4COMMENT, INSERTED.c4COMMENT INTO HISTORY +WHERE c1PK = 1 +go + +SELECT * FROM t1; +go + +SELECT * FROM HISTORY; +go + +DROP TABLE t1 +go +DROP TABLE HISTORY +go + +CREATE TABLE t1( + c1PK INT PRIMARY KEY + , c2INT INT NOT NULL + , c3STR VARCHAR(50) NOT NULL + , c4COMMENT VARCHAR(100) NOT NULL +); +go +CREATE TABLE t2( + c1PK INT PRIMARY KEY + , c2INT INT NOT NULL + , c3STR VARCHAR(50) NOT NULL + , c4COMMENT VARCHAR(100) NOT NULL +); +go +CREATE TABLE HISTORY( + c1PK INT PRIMARY KEY + , c2INT INT NOT NULL + , c3BEFORE VARCHAR(100) NOT NULL + , c4AFTER VARCHAR(100) NOT NULL +); +go +INSERT INTO t1 VALUES( 1, 10, 'filler1', 'vanilla insert' ); +go +INSERT INTO t1 VALUES( 2, 20, 'filler2', 'vanilla insert' ); +go +INSERT INTO t2 VALUES( 1, 10, 'filler1', 'vanilla insert' ); +go +INSERT INTO t2 VALUES( 2, 20, 'filler2', 'vanilla insert' ); +go + +DELETE FROM t1 +OUTPUT DELETED.c1PK, DELETED.c2INT, DELETED.c3STR, DELETED.c4COMMENT INTO HISTORY +FROM t2 table2 +WHERE t1.c1PK = 2 +AND t1.c2INT = table2.c2INT; +go + +SELECT * FROM t1 +go + +SELECT * FROM HISTORY +go + +DROP TABLE t1; +go +DROP TABLE t2; +go +DROP TABLE HISTORY; +go + +CREATE TABLE t1( + c1PK INT PRIMARY KEY + , c2INT INT NOT NULL + , c3STR VARCHAR(50) NOT NULL + , c4COMMENT VARCHAR(100) NOT NULL +) +go +CREATE TABLE t2( + c1PK INT PRIMARY KEY + , c2INT INT NOT NULL + , c3STR VARCHAR(50) NOT NULL + , c4COMMENT VARCHAR(100) NOT NULL +) +go +CREATE TABLE trigger_history( + c1OPS CHAR(3) NOT NULL + , c2PK INT NOT NULL + , c3INT INT NOT NULL + , c4COMMENT VARCHAR(100) NOT NULL + , c5ROWS INT NOT NULL + , c6SRCTABLE VARCHAR(20) NOT NULL +) +go + +CREATE TRIGGER t1_ins +ON t1 +AFTER INSERT +AS +DECLARE @rows INT = @@rowcount +PRINT '>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> INSERT TRIGGER ON t1 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<' +INSERT INTO t2 +OUTPUT 'INS', INSERTED.c1PK, INSERTED.c2INT, INSERTED.c4COMMENT, @rows, 't1' INTO trigger_history( c1OPS, c2PK, c3INT, c4COMMENT, c5ROWS, c6SRCTABLE ) +SELECT INSERTED.c1PK, INSERTED.c2INT, INSERTED.c3STR, INSERTED.c4COMMENT FROM INSERTED +PRINT '>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> TRIGGER DONE <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<' +RETURN +go + +INSERT INTO t1 VALUES( 1, 10, 'filler1', 'vanilla insert' ) +go + +SELECT * from t2 +go + +-- The value of c5ROWS needs to be changed when BABEL-2208 is fixed +SELECT * from trigger_history +go + +-- Cleanup +DROP TRIGGER t1_ins +go +DROP TABLE trigger_history +go +DROP TABLE t1 +go +DROP TABLE t2 +go + + +-- [BABEL-2522] Test specific cases that trigger ambiguous column errors +CREATE TABLE dml_table( + c1PK INT PRIMARY KEY + , c2FLOAT FLOAT NOT NULL +) +go + +CREATE TABLE output_FLOAT( + c1INT INT PRIMARY KEY + , c2FLOAT FLOAT NULL +) +go + +INSERT INTO dml_table +OUTPUT INSERTED.c1PK, INSERTED.c1PK / 21 INTO output_FLOAT( c1INT, c2FLOAT ) +VALUES ( 4, 4567.890 ) +go + +SELECT * FROM dml_table +go + +SELECT * from output_FLOAT +go + +DELETE output_FLOAT +go + +UPDATE dml_table SET c1PK = 5 +OUTPUT DELETED.c1PK, INSERTED.c1PK + DELETED.c1PK INTO output_FLOAT( c1INT, c2FLOAT ) +WHERE c1PK = 4 +go + +SELECT * FROM dml_table +go + +SELECT * FROM output_FLOAT +go + +-- Cleanup +DROP TABLE dml_table +go + +DROP TABLE output_FLOAT +go \ No newline at end of file diff --git a/contrib/test/JDBC/input/BABEL-597.sql b/contrib/test/JDBC/input/BABEL-597.sql new file mode 100644 index 00000000000..86bd5e03734 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-597.sql @@ -0,0 +1,6 @@ +-- create procedure with incomplete definition +create procedure [p_employee_insert] +@person_id int, @fname varchar(20), @lname varchar(30), @sal money +as +begin +go diff --git a/contrib/test/JDBC/input/BABEL-604.sql b/contrib/test/JDBC/input/BABEL-604.sql new file mode 100644 index 00000000000..e301373a45c --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-604.sql @@ -0,0 +1,20 @@ +create table employees(@pers_id int, @fname nvarchar(20), @lname nvarchar(30), sal money) +GO + +create procedure p_employee_select as begin select * from employees end +GO + +call p_employee_select +GO + +call p_employee_select +GO + +create procedure p as select 2; select 1; +go +execute p; +go + +drop procedure p_employee_select, p; +drop table employees; +go diff --git a/contrib/test/JDBC/input/BABEL-625.sql b/contrib/test/JDBC/input/BABEL-625.sql new file mode 100644 index 00000000000..e1a12818e6a --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-625.sql @@ -0,0 +1,9 @@ +-- create procedure with incomplete definition +create procedure hf_proc AS +GO + +exec hf_proc +GO + +DROP PROCEDURE hf_proc +GO diff --git a/contrib/test/JDBC/input/BABEL-627.sql b/contrib/test/JDBC/input/BABEL-627.sql new file mode 100644 index 00000000000..45c3eda3ff4 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-627.sql @@ -0,0 +1,10 @@ +USE master; +GO + +-- run built-in functions with master dbo +select dateadd(year, 2, CAST('20060830' AS datetime)); +GO +select datediff(year, CAST('2037-03-01 23:30:05.523' AS datetime), CAST('2036-02-28 23:30:05.523' AS datetime)); +GO +select datepart(week, CAST('2007-04-21' AS date)), datepart(weekday, CAST('2007-04-21' AS date)); +GO diff --git a/contrib/test/JDBC/input/BABEL-637.sql b/contrib/test/JDBC/input/BABEL-637.sql new file mode 100644 index 00000000000..bad94ccd4dc --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-637.sql @@ -0,0 +1,734 @@ +use master; +go + +CREATE FUNCTION babel_637_int_multiply (@a int, @b int) +RETURNS int AS +BEGIN + RETURN @a * @b; +END; +GO + +-- reported case: numeric->int4 +SELECT babel_637_int_multiply(21.1, 2.2); +GO + +-- reported case: varbinary->int4 +SELECT babel_637_int_multiply(0xe, 0xe); +GO + +-- case expession. should pick float since it has higher precedence +SELECT cast(pg_typeof(case when 2 > 1 then cast(3.14 as double precision) else cast(42 as int) end) as varchar(20)) as return_type; +GO + +SELECT cast(pg_typeof(case when 2 > 1 then cast(42 as int) else cast(3.14 as double precision) end) as varchar(20)) as reutrn_type; +GO + +--union-all +SELECT cast(pg_typeof(T.c1) as varchar(20)) as return_type from (SELECT cast(3.14 as double precision) c1 UNION ALL SELECT cast(42 as int) c1) T +GO + +SELECT cast(pg_typeof(T.c1) as varchar(20)) as return_type from (SELECT cast(42 as int) c1 UNION ALL SELECT cast(3.14 as double precision) c1) T +GO + + +-- all number type to double precision +CREATE FUNCTION babel_637_double_precision (@a double precision) +RETURNS double precision AS +BEGIN + RETURN @a; +END; +GO + +SELECT babel_637_double_precision(cast(41.9 as double precision)); +GO + +SELECT babel_637_double_precision(cast(123456789012.1 as double precision)); +GO + +SELECT babel_637_double_precision(cast(41.9 as float)); +GO + +SELECT babel_637_double_precision(cast(123456789012.1 as float)); +GO + +SELECT babel_637_double_precision(cast(41.9 as fixeddecimal)); +GO + +SELECT babel_637_double_precision(cast(123456789012.1 as fixeddecimal)); +GO + +SELECT babel_637_double_precision(cast(41.9 as numeric(18,4))); +GO + +SELECT babel_637_double_precision(cast(123456789012.1 as numeric(18,4))); +GO + +SELECT babel_637_double_precision(cast(41.9 as money)); +GO + +SELECT babel_637_double_precision(cast(922337203685475.5807 as money)); +GO + +SELECT babel_637_double_precision(cast(41.9 as smallmoney)); +GO + +SELECT babel_637_double_precision(cast(214746.3647 as smallmoney)); +GO + +SELECT babel_637_double_precision(cast(41 as bigint)); +GO + +SELECT babel_637_double_precision(cast(9223372036854775806 as bigint)); +GO + +SELECT babel_637_double_precision(cast(41 as int)); +GO + +SELECT babel_637_double_precision(cast(2147483646 as int)); +GO + +SELECT babel_637_double_precision(cast(41 as smallint)); +GO + +SELECT babel_637_double_precision(cast(32766 as smallint)); +GO + +SELECT babel_637_double_precision(cast(41 as tinyint)); +GO + +SELECT babel_637_double_precision(cast(254 as tinyint)); +GO + + +-- all number type to float +CREATE FUNCTION babel_637_float (@a float) +RETURNS float AS +BEGIN + RETURN @a; +END; +GO + +SELECT babel_637_float(cast(41.9 as double precision)); +GO + +SELECT babel_637_float(cast(123456789012.1 as double precision)); +GO + +SELECT babel_637_float(cast(41.9 as float)); +GO + +SELECT babel_637_float(cast(123456789012.1 as float)); +GO + +SELECT babel_637_float(cast(41.9 as fixeddecimal)); +GO + +SELECT babel_637_float(cast(123456789012.1 as fixeddecimal)); +GO + +SELECT babel_637_float(cast(41.9 as numeric(8,4))); +GO + +SELECT babel_637_float(cast(123456789012.1 as numeric(18,4))); +GO + +SELECT babel_637_float(cast(41.9 as money)); +GO + +SELECT babel_637_float(cast(922337203685475.5807 as money)); +GO + +SELECT babel_637_float(cast(41.9 as smallmoney)); +GO + +SELECT babel_637_float(cast(214746.3647 as smallmoney)); +GO + +SELECT babel_637_float(cast(41 as bigint)); +GO + +SELECT babel_637_float(cast(9223372036854775806 as bigint)); +GO + +SELECT babel_637_float(cast(41 as int)); +GO + +SELECT babel_637_float(cast(2147483646 as int)); +GO + +SELECT babel_637_float(cast(41 as smallint)); +GO + +SELECT babel_637_float(cast(32766 as smallint)); +GO + +SELECT babel_637_float(cast(41 as tinyint)); +GO + +SELECT babel_637_float(cast(254 as tinyint)); +GO + + +-- all number type to fixeddecimal +CREATE FUNCTION babel_637_add_one_fixeddecimal (@a fixeddecimal) +RETURNS fixeddecimal AS +BEGIN + RETURN @a + 1; +END; +GO + +SELECT babel_637_add_one_fixeddecimal(cast(41.9 as double precision)); +GO + +SELECT babel_637_add_one_fixeddecimal(cast(123456789012.1 as double precision)); +GO + +SELECT babel_637_add_one_fixeddecimal(cast(41.9 as float)); +GO + +SELECT babel_637_add_one_fixeddecimal(cast(123456789012.1 as float)); +GO + +SELECT babel_637_add_one_fixeddecimal(cast(41.9 as fixeddecimal)); +GO + +SELECT babel_637_add_one_fixeddecimal(cast(123456789012.1 as fixeddecimal)); +GO + +SELECT babel_637_add_one_fixeddecimal(cast(41.9 as numeric(8,4))); +GO + +SELECT babel_637_add_one_fixeddecimal(cast(123456789012.1 as numeric(18,4))); +GO + +SELECT babel_637_add_one_fixeddecimal(cast(41.9 as money)); +GO + +SELECT babel_637_add_one_fixeddecimal(cast(922337203685475.5807 as money)); +GO + +SELECT babel_637_add_one_fixeddecimal(cast(41.9 as smallmoney)); +GO + +SELECT babel_637_add_one_fixeddecimal(cast(214746.3647 as smallmoney)); +GO + +SELECT babel_637_add_one_fixeddecimal(cast(41 as bigint)); +GO + +SELECT babel_637_add_one_fixeddecimal(cast(9223372036854775806 as bigint)); +GO + +SELECT babel_637_add_one_fixeddecimal(cast(41 as int)); +GO + +SELECT babel_637_add_one_fixeddecimal(cast(2147483646 as int)); +GO + +SELECT babel_637_add_one_fixeddecimal(cast(41 as smallint)); +GO + +SELECT babel_637_add_one_fixeddecimal(cast(32766 as smallint)); +GO + +SELECT babel_637_add_one_fixeddecimal(cast(41 as tinyint)); +GO + +SELECT babel_637_add_one_fixeddecimal(cast(254 as tinyint)); +GO + + +-- all number type to numeric +CREATE FUNCTION babel_637_add_one_numeric (@a numeric) +RETURNS numeric AS +BEGIN + RETURN @a + 1; +END; +GO + +SELECT babel_637_add_one_numeric(cast(41.9 as double precision)); +GO + +SELECT babel_637_add_one_numeric(cast(123456789012.1 as double precision)); +GO + +SELECT babel_637_add_one_numeric(cast(41.9 as float)); +GO + +SELECT babel_637_add_one_numeric(cast(123456789012.1 as float)); +GO + +SELECT babel_637_add_one_numeric(cast(41.9 as fixeddecimal)); +GO + +SELECT babel_637_add_one_numeric(cast(123456789012.1 as fixeddecimal)); +GO + +SELECT babel_637_add_one_numeric(cast(41.9 as numeric(8,4))); +GO + +SELECT babel_637_add_one_numeric(cast(123456789012.1 as numeric(18,4))); +GO + +SELECT babel_637_add_one_numeric(cast(41.9 as money)); +GO + +SELECT babel_637_add_one_numeric(cast(922337203685475.5807 as money)); +GO + +SELECT babel_637_add_one_numeric(cast(41.9 as smallmoney)); +GO + +SELECT babel_637_add_one_numeric(cast(214746.3647 as smallmoney)); +GO + +SELECT babel_637_add_one_numeric(cast(41 as bigint)); +GO + +SELECT babel_637_add_one_numeric(cast(9223372036854775806 as bigint)); +GO + +SELECT babel_637_add_one_numeric(cast(41 as int)); +GO + +SELECT babel_637_add_one_numeric(cast(2147483646 as int)); +GO + +SELECT babel_637_add_one_numeric(cast(41 as smallint)); +GO + +SELECT babel_637_add_one_numeric(cast(32766 as smallint)); +GO + +SELECT babel_637_add_one_numeric(cast(41 as tinyint)); +GO + +SELECT babel_637_add_one_numeric(cast(254 as tinyint)); +GO + + +-- all number type to money +CREATE FUNCTION babel_637_add_one_money (@a money) +RETURNS money AS +BEGIN + RETURN @a + 1; +END; +GO + +SELECT babel_637_add_one_money(cast(41.9 as double precision)); +GO + +SELECT babel_637_add_one_money(cast(123456789012.1 as double precision)); +GO + +SELECT babel_637_add_one_money(cast(41.9 as float)); +GO + +SELECT babel_637_add_one_money(cast(123456789012.1 as float)); +GO + +SELECT babel_637_add_one_money(cast(41.9 as fixeddecimal)); +GO + +SELECT babel_637_add_one_money(cast(123456789012.1 as fixeddecimal)); +GO + +SELECT babel_637_add_one_money(cast(41.9 as numeric(8,4))); +GO + +SELECT babel_637_add_one_money(cast(123456789012.1 as numeric(18,4))); +GO + +SELECT babel_637_add_one_money(cast(41.9 as money)); +GO + +SELECT babel_637_add_one_money(cast(922337203685475.5807 as money)); +GO + +SELECT babel_637_add_one_money(cast(41.9 as smallmoney)); +GO + +SELECT babel_637_add_one_money(cast(214746.3647 as smallmoney)); +GO + +SELECT babel_637_add_one_money(cast(41 as bigint)); +GO + +SELECT babel_637_add_one_money(cast(9223372036854775806 as bigint)); +GO + +SELECT babel_637_add_one_money(cast(41 as int)); +GO + +SELECT babel_637_add_one_money(cast(2147483646 as int)); +GO + +SELECT babel_637_add_one_money(cast(41 as smallint)); +GO + +SELECT babel_637_add_one_money(cast(32766 as smallint)); +GO + +SELECT babel_637_add_one_money(cast(41 as tinyint)); +GO + +SELECT babel_637_add_one_money(cast(254 as tinyint)); +GO + + +-- all number type to smallmoney +CREATE FUNCTION babel_637_add_one_smallmoney (@a smallmoney) +RETURNS smallmoney AS +BEGIN + RETURN @a + 1; +END; +GO + +SELECT babel_637_add_one_smallmoney(cast(41.9 as double precision)); +GO + +SELECT babel_637_add_one_smallmoney(cast(123456789012.1 as double precision)); +GO + +SELECT babel_637_add_one_smallmoney(cast(41.9 as float)); +GO + +SELECT babel_637_add_one_smallmoney(cast(123456789012.1 as float)); +GO + +SELECT babel_637_add_one_smallmoney(cast(41.9 as fixeddecimal)); +GO + +SELECT babel_637_add_one_smallmoney(cast(123456789012.1 as fixeddecimal)); +GO + +SELECT babel_637_add_one_smallmoney(cast(41.9 as numeric(8,4))); +GO + +SELECT babel_637_add_one_smallmoney(cast(123456789012.1 as numeric(18,4))); +GO + +SELECT babel_637_add_one_smallmoney(cast(41.9 as money)); +GO + +SELECT babel_637_add_one_smallmoney(cast(922337203685475.5807 as money)); +GO + +SELECT babel_637_add_one_smallmoney(cast(41.9 as smallmoney)); +GO + +SELECT babel_637_add_one_smallmoney(cast(214746.3647 as smallmoney)); +GO + +SELECT babel_637_add_one_smallmoney(cast(41 as bigint)); +GO + +SELECT babel_637_add_one_smallmoney(cast(9223372036854775806 as bigint)); +GO + +SELECT babel_637_add_one_smallmoney(cast(41 as int)); +GO + +SELECT babel_637_add_one_smallmoney(cast(2147483646 as int)); +GO + +SELECT babel_637_add_one_smallmoney(cast(41 as smallint)); +GO + +SELECT babel_637_add_one_smallmoney(cast(32766 as smallint)); +GO + +SELECT babel_637_add_one_smallmoney(cast(41 as tinyint)); +GO + +SELECT babel_637_add_one_smallmoney(cast(254 as tinyint)); +GO + + +-- all number type to bigint +CREATE FUNCTION babel_637_add_one_bigint (@a bigint) +RETURNS bigint AS +BEGIN + RETURN @a + 1; +END; +GO + +SELECT babel_637_add_one_bigint(cast(41.9 as double precision)); +GO + +SELECT babel_637_add_one_bigint(cast(123456789012.1 as double precision)); +GO + +SELECT babel_637_add_one_bigint(cast(41.9 as float)); +GO + +SELECT babel_637_add_one_bigint(cast(123456789012.1 as float)); +GO + +SELECT babel_637_add_one_bigint(cast(41.9 as fixeddecimal)); +GO + +SELECT babel_637_add_one_bigint(cast(123456789012.1 as fixeddecimal)); +GO + +SELECT babel_637_add_one_bigint(cast(41.9 as numeric(8,4))); +GO + +SELECT babel_637_add_one_bigint(cast(123456789012.1 as numeric(18,4))); +GO + +SELECT babel_637_add_one_bigint(cast(41.9 as money)); +GO + +SELECT babel_637_add_one_bigint(cast(922337203685475.5807 as money)); +GO + +SELECT babel_637_add_one_bigint(cast(41.9 as smallmoney)); +GO + +SELECT babel_637_add_one_bigint(cast(214746.3647 as smallmoney)); +GO + +SELECT babel_637_add_one_bigint(cast(41 as bigint)); +GO + +SELECT babel_637_add_one_bigint(cast(9223372036854775806 as bigint)); +GO + +SELECT babel_637_add_one_bigint(cast(41 as int)); +GO + +SELECT babel_637_add_one_bigint(cast(2147483646 as int)); +GO + +SELECT babel_637_add_one_bigint(cast(41 as smallint)); +GO + +SELECT babel_637_add_one_bigint(cast(32766 as smallint)); +GO + +SELECT babel_637_add_one_bigint(cast(41 as tinyint)); +GO + +SELECT babel_637_add_one_bigint(cast(254 as tinyint)); +GO + + +-- all number type to int4 +CREATE FUNCTION babel_637_add_one_int4 (@a int) +RETURNS int AS +BEGIN + RETURN @a + 1; +END; +GO + +SELECT babel_637_add_one_int4(cast(41.9 as double precision)); +GO + +SELECT babel_637_add_one_int4(cast(123456789012.1 as double precision)); +GO + +SELECT babel_637_add_one_int4(cast(41.9 as float)); +GO + +SELECT babel_637_add_one_int4(cast(123456789012.1 as float)); +GO + +SELECT babel_637_add_one_int4(cast(41.9 as fixeddecimal)); +GO + +SELECT babel_637_add_one_int4(cast(123456789012.1 as fixeddecimal)); +GO + +SELECT babel_637_add_one_int4(cast(41.9 as numeric(8,4))); +GO + +SELECT babel_637_add_one_int4(cast(123456789012.1 as numeric(18,4))); +GO + +SELECT babel_637_add_one_int4(cast(41.9 as money)); +GO + +SELECT babel_637_add_one_int4(cast(922337203685475.5807 as money)); +GO + +SELECT babel_637_add_one_int4(cast(41.9 as smallmoney)); +GO + +SELECT babel_637_add_one_int4(cast(214746.3647 as smallmoney)); +GO + +SELECT babel_637_add_one_int4(cast(41 as bigint)); +GO + +SELECT babel_637_add_one_int4(cast(9223372036854775806 as bigint)); +GO + +SELECT babel_637_add_one_int4(cast(41 as int)); +GO + +SELECT babel_637_add_one_int4(cast(2147483646 as int)); +GO + +SELECT babel_637_add_one_int4(cast(41 as smallint)); +GO + +SELECT babel_637_add_one_int4(cast(32766 as smallint)); +GO + +SELECT babel_637_add_one_int4(cast(41 as tinyint)); +GO + +SELECT babel_637_add_one_int4(cast(254 as tinyint)); +GO + + +-- all number type to smallint +CREATE FUNCTION babel_637_add_one_smallint (@a smallint) +RETURNS smallint AS +BEGIN + RETURN @a + 1; +END; +GO + +SELECT babel_637_add_one_smallint(cast(41.9 as double precision)); +GO + +SELECT babel_637_add_one_smallint(cast(123456789012.1 as double precision)); +GO + +SELECT babel_637_add_one_smallint(cast(41.9 as float)); +GO + +SELECT babel_637_add_one_smallint(cast(123456789012.1 as float)); +GO + +SELECT babel_637_add_one_smallint(cast(41.9 as fixeddecimal)); +GO + +SELECT babel_637_add_one_smallint(cast(123456789012.1 as fixeddecimal)); +GO + +SELECT babel_637_add_one_smallint(cast(41.9 as numeric(8,4))); +GO + +SELECT babel_637_add_one_smallint(cast(123456789012.1 as numeric(18,4))); +GO + +SELECT babel_637_add_one_smallint(cast(41.9 as money)); +GO + +SELECT babel_637_add_one_smallint(cast(922337203685475.5807 as money)); +GO + +SELECT babel_637_add_one_smallint(cast(41.9 as smallmoney)); +GO + +SELECT babel_637_add_one_smallint(cast(214746.3647 as smallmoney)); +GO + +SELECT babel_637_add_one_smallint(cast(41 as bigint)); +GO + +SELECT babel_637_add_one_smallint(cast(9223372036854775806 as bigint)); +GO + +SELECT babel_637_add_one_smallint(cast(41 as int)); +GO + +SELECT babel_637_add_one_smallint(cast(2147483646 as int)); +GO + +SELECT babel_637_add_one_smallint(cast(41 as smallint)); +GO + +SELECT babel_637_add_one_smallint(cast(32766 as smallint)); +GO + +SELECT babel_637_add_one_smallint(cast(41 as tinyint)); +GO + +SELECT babel_637_add_one_smallint(cast(254 as tinyint)); +GO + + +-- all number type to tinyint +CREATE FUNCTION babel_637_add_one_tinyint (@a tinyint) +RETURNS tinyint AS +BEGIN + RETURN @a + 1; +END; +GO + +SELECT babel_637_add_one_tinyint(cast(41.9 as double precision)); +GO + +SELECT babel_637_add_one_tinyint(cast(123456789012.1 as double precision)); +GO + +SELECT babel_637_add_one_tinyint(cast(41.9 as float)); +GO + +SELECT babel_637_add_one_tinyint(cast(123456789012.1 as float)); +GO + +SELECT babel_637_add_one_tinyint(cast(41.9 as fixeddecimal)); +GO + +SELECT babel_637_add_one_tinyint(cast(123456789012.1 as fixeddecimal)); +GO + +SELECT babel_637_add_one_tinyint(cast(41.9 as numeric(8,4))); +GO + +SELECT babel_637_add_one_tinyint(cast(123456789012.1 as numeric(18,4))); +GO + +SELECT babel_637_add_one_tinyint(cast(41.9 as money)); +GO + +SELECT babel_637_add_one_tinyint(cast(922337203685475.5807 as money)); +GO + +SELECT babel_637_add_one_tinyint(cast(41.9 as smallmoney)); +GO + +SELECT babel_637_add_one_tinyint(cast(214746.3647 as smallmoney)); +GO + +SELECT babel_637_add_one_tinyint(cast(41 as bigint)); +GO + +SELECT babel_637_add_one_tinyint(cast(9223372036854775806 as bigint)); +GO + +SELECT babel_637_add_one_tinyint(cast(41 as int)); +GO + +SELECT babel_637_add_one_tinyint(cast(2147483646 as int)); +GO + +SELECT babel_637_add_one_tinyint(cast(41 as smallint)); +GO + +SELECT babel_637_add_one_tinyint(cast(32766 as smallint)); +GO + +SELECT babel_637_add_one_tinyint(cast(41 as tinyint)); +GO + +SELECT babel_637_add_one_tinyint(cast(254 as tinyint)); +GO + +DROP FUNCTION babel_637_int_multiply; +DROP FUNCTION babel_637_double_precision; +DROP FUNCTION babel_637_float; +DROP FUNCTION babel_637_add_one_fixeddecimal; +DROP FUNCTION babel_637_add_one_numeric; +DROP FUNCTION babel_637_add_one_money; +DROP FUNCTION babel_637_add_one_smallmoney; +DROP FUNCTION babel_637_add_one_bigint; +DROP FUNCTION babel_637_add_one_int4; +DROP FUNCTION babel_637_add_one_smallint; +DROP FUNCTION babel_637_add_one_tinyint; +GO diff --git a/contrib/test/JDBC/input/BABEL-646.sql b/contrib/test/JDBC/input/BABEL-646.sql new file mode 100644 index 00000000000..83fecaf2c46 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-646.sql @@ -0,0 +1,77 @@ +create table t1 ( a int ) +GO + +create procedure my_proc as +PRINT 'OK' +GO + +create procedure test_proc1 as +execute my_proc +execute [my_proc] +GO + +create procedure test_proc2 as +execute my_proc +execute [my_proc] +GO + +create procedure test_proc3 as +execute my_proc +execute [my_proc] +select 123 +GO + +create procedure test_proc4 as +execute my_proc +execute [my_proc] +insert into t1 values (1) +GO + +create procedure test_proc5 as +execute my_proc +execute [my_proc] +update t1 set a = 2 +GO + +EXEC test_proc1; +GO + +EXEC test_proc2; +GO + +EXEC test_proc3; +GO + +EXEC test_proc4; +GO + +select * from t1; +GO + +EXEC test_proc5; +GO + +select * from t1; +GO + +drop procedure test_proc1 +GO + +drop procedure test_proc2 +GO + +drop procedure test_proc3 +GO + +drop procedure test_proc4 +GO + +drop procedure test_proc5 +GO + +drop procedure my_proc +GO + +drop table t1 +GO + diff --git a/contrib/test/JDBC/input/BABEL-662.sql b/contrib/test/JDBC/input/BABEL-662.sql new file mode 100644 index 00000000000..995a73859f5 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-662.sql @@ -0,0 +1,71 @@ +-- BABEL-662 +CREATE TABLE babel_662_table (x INT, y FLOAT, z VARCHAR(10)); +go + +CREATE PROC babel_662_proc_1 AS SELECT 'hi' +go + +CREATE PROC babel_662_proc_2 @p VARCHAR(50) AS SELECT @p +go + +CREATE PROC babel_662_proc_3 +( + @a INT, + @b FLOAT, + @c VARCHAR(10) +) +AS INSERT INTO babel_662_table VALUES (@a, @b, @c); +go + +babel_662_proc_1 +go + +babel_662_proc_2 'hello' +go + +babel_662_proc_2 'hello again' +go + +babel_662_proc_3 1, 1.1, 'one'; +go + +babel_662_proc_3 @a = 2, @b = 2.2, @c = 'two'; +go + +babel_662_proc_3 3, @b = 3.3, @c = 'three'; +go + +babel_662_proc_3 4, @b = 4.4, 'four'; -- invalid +go + +SELECT * FROM babel_662_table; +go + +-- Invalid syntax +begin babel_662_proc_2 end +go + +babel_662_proc_2 +go + +-- BABEL-1995 +ABC +go + +-- BABEL-2052 +us emaster +go + +-- BABEL-2067 +seelect 1; +go + +-- Test stored procedure +sp_executesql N'SELECT ''hello world''' +go + +DROP TABLE babel_662_table +DROP PROC babel_662_proc_1 +DROP PROC babel_662_proc_2 +DROP PROC babel_662_proc_3 +go diff --git a/contrib/test/JDBC/input/BABEL-672.sql b/contrib/test/JDBC/input/BABEL-672.sql new file mode 100644 index 00000000000..c345ca90a61 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-672.sql @@ -0,0 +1,5 @@ +CREATE TABLE babel_672_table ( a int, constraint ab primary key nonclustered (a) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]) ON [PRIMARY] +go + +DROP TABLE babel_672_table +go diff --git a/contrib/test/JDBC/input/BABEL-694.sql b/contrib/test/JDBC/input/BABEL-694.sql new file mode 100644 index 00000000000..f672f8bdefc --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-694.sql @@ -0,0 +1,24 @@ +CREATE PROCEDURE my_test @a int, @b int +AS +PRINT @a + @b +GO + +CREATE PROCEDURE caller @a int, @b int +AS +EXEC my_test(@a,@b) +GO + +EXEC my_test(1,2) +GO + +EXEC my_test 1, (1,2) +GO + +EXECUTE my_test(1,2) +GO + +EXECUTE my_test 1, (1,2) +GO + +drop procedure my_test +GO diff --git a/contrib/test/JDBC/input/BABEL-701.sql b/contrib/test/JDBC/input/BABEL-701.sql new file mode 100644 index 00000000000..f7f9d342e03 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-701.sql @@ -0,0 +1,12 @@ +CREATE PROCEDURE babel_701_sp (@a varbinary OUTPUT) AS +BEGIN + SET @a=0x121; + Select @a as a; +END; +GO + +EXEC babel_701_sp 0x122 +GO + +DROP PROCEDURE babel_701_sp +GO diff --git a/contrib/test/JDBC/input/BABEL-708.sql b/contrib/test/JDBC/input/BABEL-708.sql new file mode 100644 index 00000000000..b369c9c2896 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-708.sql @@ -0,0 +1,190 @@ +CREATE PROCEDURE babel_708_proc_1 AS +DECLARE @one varchar(2) +BEGIN + SET @one = 'abcdef'; + SELECT @one; +END; +GO + +EXEC babel_708_proc_1; +GO + +CREATE PROCEDURE babel_708_proc_2(@one AS VARCHAR(2)) AS +BEGIN + SET @one = 'abcdef'; + SELECT @one; +END; +GO + +EXEC babel_708_proc_2 ''; +GO + +EXEC babel_708_proc_2 'zyxwvut'; +GO + +CREATE PROCEDURE babel_708_proc_3 AS +DECLARE @one numeric(10,4) +BEGIN + SET @one = 12.3456789; + SELECT @one; +END; +GO + +EXEC babel_708_proc_3; +GO + +CREATE PROCEDURE babel_708_proc_4(@one AS numeric(10,4)) AS +BEGIN + SET @one = 12.3456789; + SELECT @one; +END; +GO + +EXEC babel_708_proc_4 0; +GO + +EXEC babel_708_proc_4 99.9999999; +GO + +CREATE PROCEDURE babel_708_proc_5 AS +DECLARE @one varbinary(2) +BEGIN + SET @one = 0x0123456789; + SELECT @one; +END; +GO + +EXEC babel_708_proc_5; +GO + +CREATE PROCEDURE babel_708_proc_6(@one AS VARBINARY(2)) AS +BEGIN + SET @one = 0x0123456789; + SELECT @one; +END; +GO + +EXEC babel_708_proc_6 ''; +GO + +EXEC babel_708_proc_6 0xabcdefabcedf; +GO + +CREATE PROCEDURE babel_708_proc_7 AS +DECLARE @one char(2) +BEGIN + SET @one = 'abcede'; + SELECT @one; +END; +GO + +EXEC babel_708_proc_7; +GO + +CREATE PROCEDURE babel_708_proc_8(@one AS char(2)) AS +BEGIN + SET @one = 'abcede'; + SELECT @one; +END; +GO + +EXEC babel_708_proc_8 ''; +GO + +EXEC babel_708_proc_8 'abcedef'; +GO + +CREATE PROCEDURE babel_708_proc_9 AS +DECLARE @one binary(2) +BEGIN + SET @one = 0x0123456789; + SELECT @one; +END; +GO + +EXEC babel_708_proc_9; +GO + +CREATE PROCEDURE babel_708_proc_10(@one AS binary(2)) AS +BEGIN + SET @one = 0x0123456789; + SELECT @one; +END; +GO + +EXEC babel_708_proc_10 ''; +GO + +EXEC babel_708_proc_10 0xabcdefabcdef; +GO + +CREATE PROCEDURE babel_708_proc_11 AS +DECLARE @one datetimeoffset(2) +BEGIN + SET @one = '2030-05-06 13:59:29.123456 -8:00'; + SELECT @one; +END; +GO + +EXEC babel_708_proc_11; +GO + +CREATE PROCEDURE babel_708_proc_12(@one AS datetimeoffset(2)) AS +BEGIN + SET @one = '2030-05-06 13:59:29.123456 -8:00'; + SELECT @one; +END; +GO + +EXEC babel_708_proc_12 '2040-05-06 13:59:29.567891 -8:00'; +GO + +CREATE PROCEDURE babel_708_proc_13 AS +DECLARE @one datetime2(2) +BEGIN + SET @one = '2030-05-06 13:59:29.123456'; + SELECT @one; +END; +GO + +EXEC babel_708_proc_13; +GO + +CREATE PROCEDURE babel_708_proc_14(@one AS datetime2(2)) AS +BEGIN + SET @one = '2030-05-06 13:59:29.123456'; + SELECT @one; +END; +GO + +EXEC babel_708_proc_14 '2040-05-06 13:59:29.567891'; +GO + +DROP procedure babel_708_proc_1; +GO +DROP procedure babel_708_proc_2; +GO +DROP procedure babel_708_proc_3; +GO +DROP procedure babel_708_proc_4; +GO +DROP procedure babel_708_proc_5; +GO +DROP procedure babel_708_proc_6; +GO +DROP procedure babel_708_proc_7; +GO +DROP procedure babel_708_proc_8; +GO +DROP procedure babel_708_proc_9; +GO +DROP procedure babel_708_proc_10; +GO +DROP procedure babel_708_proc_11; +GO +DROP procedure babel_708_proc_12; +GO +DROP procedure babel_708_proc_13; +GO +DROP procedure babel_708_proc_14; +GO diff --git a/contrib/test/JDBC/input/BABEL-719.sql b/contrib/test/JDBC/input/BABEL-719.sql new file mode 100644 index 00000000000..f1306347269 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-719.sql @@ -0,0 +1,54 @@ +use master; +go + +select $12.4524 +go + +select +$12.4524 +go + +select -$12.4524 +go + +select $+12.4524 +go + +select $-12.4524 +go + +select abs($12.4524) +go + +select abs(+$12.4524) +go + +select abs(-$12.4524) +go + +select abs($+12.4524) +go + +select abs($-12.4524) +go + +-- udf accepting float +create function f719(@a float) returns int as begin return floor(@a) end +go + +select f719($12.4524) +go + +select f719(+$12.4524) +go + +select f719(-$12.4524) +go + +select f719($+12.4524) +go + +select f719($-12.4524) +go + +drop function f719 +go diff --git a/contrib/test/JDBC/input/BABEL-728.sql b/contrib/test/JDBC/input/BABEL-728.sql new file mode 100644 index 00000000000..4fe3e0cc6e9 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-728.sql @@ -0,0 +1,248 @@ +select sign() +go + +select sign(NULL) +go + +select sign(123.23) +go + +select sign(123) +go + +select sign(0.0) +go + +select sign(0) +go + +select sign(-123) +go + +select sign(-123.23) +go + +select sign('sdflkjs') +go + +select sign('123123.913'); +go + +select sign(cast(-123.123 as int)) +go + +select sign(cast(0 as int)) +go + +select sign(cast(123.123 as int)) +go + +select sign(cast(456 as int)) +go + +select sign(cast(0.0006 as int)) +go + +select sign(cast(-123.123 as smallint)) +go + +select sign(cast(0 as smallint)) +go + +select sign(cast(123.123 as smallint)) +go + +select sign(cast(456 as smallint)) +go + +select sign(cast(0.0006 as smallint)) +go + +select sign(cast(0 as tinyint)) +go + +select sign(cast(13.13 as tinyint)) +go + +select sign(cast(0.0006 as tinyint)) +go + +select sign(cast(-123.123 as bigint)) +go + +select sign(cast(0 as bigint)) +go + +select sign(cast(123.123 as bigint)) +go + +select sign(cast(456 as bigint)) +go + +select sign(cast(0.0006 as bigint)) +go + +select sign(cast(-123.123 as money)) +go + +select sign(cast(0 as money)) +go + +select sign(cast(123.123 as money)) +go + +select sign(cast(456 as money)) +go + +select sign(cast(0.0006 as money)) +go + +select sign(cast(-123.123 as smallmoney)) +go + +select sign(cast(0 as smallmoney)) +go + +select sign(cast(123.123 as smallmoney)) +go + +select sign(cast(456 as smallmoney)) +go + +select sign(cast(0.0006 as smallmoney)) +go + +select sign(cast(-123.123 as numeric)) +go + +select sign(cast(0 as numeric)) +go + +select sign(cast(123.123 as numeric)) +go + +select sign(cast(456 as numeric)) +go + +select sign(cast(0.0006 as numeric)) +go + +select sign(cast(-123.123 as decimal)) +go + +select sign(cast(0 as decimal)) +go + +select sign(cast(123.123 as decimal)) +go + +select sign(cast(456 as decimal)) +go + +select sign(cast(0.0006 as decimal)) +go + +select sign(cast(-123.123 as float)) +go + +select sign(cast(0 as float)) +go + +select sign(cast(123.123 as float)) +go + +select sign(cast(456 as float)) +go + +select sign(cast(0.0006 as float)) +go + +select sign(cast(-123.123 as real)) +go + +select sign(cast(0 as real)) +go + +select sign(cast(123.123 as real)) +go + +select sign(cast(456 as real)) +go + +select sign(cast(0.0006 as real)) +go + +select sign(cast(0 as binary)) +go + +select sign(cast(456 as binary)) +go + +select sign(cast(0 as varbinary)) +go + +select sign(cast(456 as varbinary)) +go + +select sign(cast('-123.123' as varchar)) +go + +select sign(cast('0' as varchar)) +go + +select sign(cast('123.123' as varchar)) +go + +select sign(cast('-123.123' as nvarchar)) +go + +select sign(cast('0' as nvarchar)) +go + +select sign(cast('123.123' as nvarchar)) +go + +select sign(cast('-123.123' as text)) +go + +select sign(cast('0' as text)) +go + +select sign(cast('123.123' as text)) +go + +select sign(cast('-123.123' as real)) +go + +select sign(cast('0' as real)) +go + +select sign(cast('123.123' as real)) +go + +select sign(cast('-123.123' as binary)) +go + +select sign(cast('0' as binary)) +go + +select sign(cast('123.123' as binary)) +go + +select sign(cast('-123.123' as varbinary)) +go + +select sign(cast('0' as varbinary)) +go + +select sign(cast('123.123' as varbinary)) +go + +select sign(cast('-123.123' as ntext)) +go + +select sign(cast('0' as ntext)) +go + +select sign(cast('123.123' as ntext)) +go \ No newline at end of file diff --git a/contrib/test/JDBC/input/BABEL-735.sql b/contrib/test/JDBC/input/BABEL-735.sql new file mode 100644 index 00000000000..fb43317dfc9 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-735.sql @@ -0,0 +1,185 @@ +select exp() +go + +select exp(null) +go + +select exp(-4321) +go + +select exp(0) +go + +select exp(4321) +go + +select exp(3214.123) +go + +select exp(-12.23) +go + +select exp(123143234534523434545645456456) +go + +select exp(-1233435465465567645645645645) +go + +select exp('23122312.2342342342') +go + +select exp('-132973942.239874234') +go + +select exp('213.123') +go + +select exp('1233.1231') +go + +select exp('-1293797.21973813') +go + +select exp(cast(12 as int)) +go + +select exp(cast(-1234.1234 as int)) +go + +select exp(cast(-12.15 as int)) +go + +select exp(cast(12.15 as int)) +go + +select exp(cast(-1234.1234 as smallint)) +go + +select exp(cast(-12.15 as smallint)) +go + +select exp(cast(12.15 as smallint)) +go + +select exp(cast(12 as tinyint)) +go + +select exp(cast(12 as bigint)) +go + +select exp(cast(-1234.1234 as bigint)) +go + +select exp(cast(-12.15 as bigint)) +go + +select exp(cast(12.15 as bigint)) +go + +select exp(cast(-1234.1234 as money)) +go + +select exp(cast(-12.15 as money)) +go + +select exp(cast(12.15 as money)) +go + +select exp(cast(-1234.1234 as smallmoney)) +go + +select exp(cast(-12.15 as smallmoney)) +go + +select exp(cast(12.15 as smallmoney)) +go + +select exp(cast(-1234.1234 as numeric)) +go + +select exp(cast(-12.15 as numeric)) +go + +select exp(cast(12.15 as numeric)) +go + +select exp(cast(-1234.1234 as decimal)) +go + +select exp(cast(-12.15 as decimal)) +go + +select exp(cast(12.15 as decimal)) +go + +select exp(cast(-1234.1234 as float)) +go + +select exp(cast(-12.15 as float)) +go + +select exp(cast(12.15 as float)) +go + +select exp(cast(12 as real)) +go + +select exp(cast(-1234.1234 as real)) +go + +select exp(cast(-12.15 as real)) +go + +select exp(cast(12.15 as real)) +go + +select exp(cast(12 as binary)) +go + +select exp(cast(-1234 as binary)) +go + +select exp(cast(-12 as binary)) +go + +select exp(cast(12 as varbinary)) +go + +select exp(cast(-12 as varbinary)) +go + +select exp(cast('-12.12' as varchar)) +go + +select exp(cast('1235.1234' as varchar)) +go + +select exp(cast('12.16' as varchar)) +go + +select exp(cast('-12.12' as nvarchar)) +go + +select exp(cast('1235.1234' as nvarchar)) +go + +select exp(cast('12.16' as nvarchar)) +go + +select exp(cast('-12.12' as text)) +go + +select exp(cast('1235.1234' as text)) +go + +select exp(cast('12.16' as text)) +go + +select exp(cast('-12.12' as ntext)) +go + +select exp(cast('1235.1234' as ntext)) +go + +select exp(cast('12.16' as ntext)) +go diff --git a/contrib/test/JDBC/input/BABEL-741.sql b/contrib/test/JDBC/input/BABEL-741.sql new file mode 100644 index 00000000000..e88d9ceb47e --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-741.sql @@ -0,0 +1,39 @@ +SELECT schema_id('public') +GO + +SELECT schema_id('pg_toast') +GO + +SELECT schema_id(NULL) +GO + +SELECT schema_id(1) +GO + +SELECT schema_id('fake_schemaname') +GO + +SELECT schema_name(99) +GO + +SELECT schema_name(2200) +GO + +SELECT schema_name(-1) +GO + +SELECT schema_name(0) +GO + +SELECT schema_name(1) +GO + +SELECT schema_name(123412341234) +GO + +SELECT schema_name(NULL) +GO + +SELECT schema_name('asdf') +GO + diff --git a/contrib/test/JDBC/input/BABEL-758.sql b/contrib/test/JDBC/input/BABEL-758.sql new file mode 100644 index 00000000000..2447790b3c3 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-758.sql @@ -0,0 +1,101 @@ +CREATE PROCEDURE babel_758_set_stmt +@how_many INT OUT +AS +BEGIN + SET @how_many = POWER(2, 23) - POWER(2, 3); +END +GO + +-- original issue: bigint +DECLARE @ret bigint; +EXECUTE babel_758_set_stmt @ret OUTPUT; +SELECT @ret; +GO + +-- double precision +DECLARE @ret double precision; +EXECUTE babel_758_set_stmt @ret OUTPUT; +SELECT @ret; +GO + +-- real +DECLARE @ret real; +EXECUTE babel_758_set_stmt @ret OUTPUT; +SELECT @ret; +GO + +-- decimal +DECLARE @ret decimal; +EXECUTE babel_758_set_stmt @ret OUTPUT; +SELECT @ret; +GO + +-- smallint +DECLARE @ret smallint; +EXECUTE babel_758_set_stmt @ret OUTPUT; +SELECT @ret; +GO + +-- tinyint +DECLARE @ret tinyint; +EXECUTE babel_758_set_stmt @ret OUTPUT; +SELECT @ret; +GO + + +CREATE TABLE [babel_758_employees] (a int); +INSERT INTO [babel_758_employees] values (1), (2), (3), (4), (5), (6), (7), (8), (9); +INSERT INTO [babel_758_employees] SELECT * FROM [babel_758_employees]; +INSERT INTO [babel_758_employees] SELECT * FROM [babel_758_employees]; +INSERT INTO [babel_758_employees] SELECT * FROM [babel_758_employees]; +INSERT INTO [babel_758_employees] SELECT * FROM [babel_758_employees]; +INSERT INTO [babel_758_employees] SELECT * FROM [babel_758_employees]; +GO + +CREATE PROCEDURE babel_758_p_employee_count +@how_many INT OUT +AS +BEGIN + SELECT @how_many = COUNT(*) from [babel_758_employees]; +END +GO + +-- original issue: bigint +DECLARE @ret bigint; +EXECUTE babel_758_p_employee_count @ret OUTPUT; +SELECT @ret; +GO + +-- double precision +DECLARE @ret double precision; +EXECUTE babel_758_p_employee_count @ret OUTPUT; +SELECT @ret; +GO + +-- real +DECLARE @ret real; +EXECUTE babel_758_p_employee_count @ret OUTPUT; +SELECT @ret; +GO + +-- decimal +DECLARE @ret decimal; +EXECUTE babel_758_p_employee_count @ret OUTPUT; +SELECT @ret; +GO + +-- smallint +DECLARE @ret smallint; +EXECUTE babel_758_p_employee_count @ret OUTPUT; +SELECT @ret; +GO + +-- tinyint +DECLARE @ret tinyint; +EXECUTE babel_758_p_employee_count @ret OUTPUT; +SELECT @ret; +GO + +DROP PROCEDURE babel_758_set_stmt; +DROP PROCEDURE babel_758_p_employee_count; +DROP TABLE babel_758_employees; diff --git a/contrib/test/JDBC/input/BABEL-768.sql b/contrib/test/JDBC/input/BABEL-768.sql new file mode 100644 index 00000000000..6a8c9ec062f --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-768.sql @@ -0,0 +1,88 @@ +-- simple case +CREATE TABLE t1 ( a INT PRIMARY KEY) +GO + +CREATE TABLE t2 ( a INT REFERENCES t1(a)) +GO + + +INSERT INTO t1 VALUES(1) +GO + +INSERT INTO t2 VALUES(1) +GO + + +-- test TSQL specific types + +CREATE TABLE t3 ( a UNIQUEIDENTIFIER PRIMARY KEY) +GO + +CREATE TABLE t4 ( a UNIQUEIDENTIFIER REFERENCES t3(a)) +GO + +INSERT INTO t3 VALUES('123e4567-e89b-12d3-a456-426614174000') +GO + +INSERT INTO t4 VALUES('123e4567-e89b-12d3-a456-426614174000') +GO + + + +CREATE TABLE t5 (a SQL_VARIANT PRIMARY KEY) +GO + +CREATE TABLE t6 (a SQL_VARIANT REFERENCES t5(a)) +GO + +INSERT INTO t5 VALUES('123') +GO + +INSERT INTO t6 VALUES('123') +GO + + +-- other scenarios may trigger modified codes + +CREATE TABLE t7 ( a INT PRIMARY KEY) +GO + +CREATE TABLE t8 ( a INT REFERENCES t7(a) ON DELETE RESTRICT) +GO + + +INSERT INTO t7 VALUES(1) +GO + +INSERT INTO t8 VALUES(1) +GO + +DELETE FROM t7 WHERE a = 1 +GO + + +-- drop tables (dependent table first) +DROP TABLE t2 +GO + +DROP TABLE t1 +GO + +DROP TABLE t4 +GO + +DROP TABLE t3 +GO + +DROP TABLE t6 +GO + +DROP TABLE t5 +GO + +DROP TABLE t8 +GO + +DROP TABLE t7 +GO + diff --git a/contrib/test/JDBC/input/BABEL-775.sql b/contrib/test/JDBC/input/BABEL-775.sql new file mode 100644 index 00000000000..1dc596b7c28 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-775.sql @@ -0,0 +1,42 @@ +USE master +go + +create schema babel_775_logging +go + +create schema babel_775_efm +go + +CREATE TABLE [babel_775_logging].[EFMIntegrationMessage]( +[EFMIntegrationLogId] int IDENTITY(1, 1) NOT NULL +) +ON [PRIMARY]; +GO + +ALTER TABLE [babel_775_logging].[EFMIntegrationMessage] +ADD CONSTRAINT [PK_logging.EFMIntegrationMessage] PRIMARY KEY ([EFMIntegrationLogId]); +GO + +CREATE TABLE [babel_775_efm].[FilingCompletion]( +[FilingCompletionId] int IDENTITY(1, 1) NOT NULL, +[EfmIntegrationLogId] int NULL +) +ON [PRIMARY]; +GO + +ALTER TABLE [babel_775_efm].[FilingCompletion] +ADD CONSTRAINT [FK_efm.FilingCompletion_logging.EFMIntegrationMessage_EfmIntegrationLogId] FOREIGN KEY ([EfmIntegrationLogId]) +REFERENCES [babel_775_logging].[EFMIntegrationMessage] ([EFMIntegrationLogId]); +GO + +DROP TABLE [babel_775_efm].[FilingCompletion] +GO + +DROP SCHEMA babel_775_efm +go + +DROP TABLE [babel_775_logging].[EFMIntegrationMessage] +GO + +DROP SCHEMA babel_775_logging +go diff --git a/contrib/test/JDBC/input/BABEL-776.sql b/contrib/test/JDBC/input/BABEL-776.sql new file mode 100644 index 00000000000..4b5863006ee --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-776.sql @@ -0,0 +1,74 @@ +USE master; +GO + +SELECT FORMATMESSAGE('%s', 'Hi') +GO + +SELECT FORMATMESSAGE('Hello %s', CAST('World' as VARCHAR(10))) +GO + +SELECT FORMATMESSAGE('Testing %s, %s, %s', CAST('one' AS VARCHAR(10)), CAST('two' AS VARCHAR(10)), CAST('three' AS VARCHAR(10))) +GO + +SELECT formatmessage('Testing adjacent %d%s%d%s', 1, CAST('two' as VARCHAR(10)), 3, CAST('four' AS VARCHAR(10))) +GO + +SELECT formatmessage('d: %d %d %d', 1, 2, 3) +GO + +SELECT formatmessage('i: %i, %i, %i', 1, 2, 3) +GO + +SELECT formatmessage('Extra params with no format', CAST('asdf' AS VARCHAR(10)), CAST('asdf' AS VARCHAR(10)), CAST('asdf' AS VARCHAR(10))) +GO + +select formatmessage('Not enough parameters: %s, %s, %s, %s', CAST('1' AS VARCHAR(10)), CAST('2' AS VARCHAR(10))) +GO + +SELECT formatmessage('More parameters than %s', CAST('placeholders' AS VARCHAR(12)), CAST('to' AS VARCHAR(10)), CAST('handle' AS VARCHAR(10))) +GO + +SELECT formatmessage('Testing no inputs with placeholder %s') +GO + +SELECT FORMATMESSAGE('Unsigned hexadecimal %x, %X, %X, %X, %x', 11, 11, -11, 50, -50) +GO + +SELECT FORMATMESSAGE('Unsigned int %u, %u', 50, -50) +GO + +SELECT FORMATMESSAGE('Unsigned octal %o, %o', 50, -50) +GO + +SELECT FORMATMESSAGE('Nonlatin: 亚马%s', CAST('逊' AS VARCHAR(10))) +GO + +SELECT FORMATMESSAGE('Long string tests: \n\n Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla consequat metus sit amet lectus vulputate lacinia. Nam vel auctor enim, quis finibus lorem. Quisque maximus egestas est, et vehicula lectus. Curabitur sodales efficitur nibh, quis varius metus semper vel. Aenean quis rhoncus tortor. Nullam eleifend blandit imperdiet. Donec a gravida ex. Cras ac nulla orci. Fusce ut est ac odio consequat rutrum. Morbi diam erat, blandit ut nunc efficitur, venenatis placerat nunc. Sed laoreet aliquam leo. Quisque vestibulum hendrerit mi, at cursus eros aliquet vitae. Mauris a sem blandit, interdum ligula et, feugiat nulla. Sed quis ipsum at dolor congue vulputate at elementum ex. Integer iaculis, libero nec pulvinar molestie, neque mi vestibulum nisl, in volutpat metus arcu in purus. Praesent ullamcorper mi sit amet consectetur mattis. Sed quis ex placerat, finibus purus dignissim, porttitor nibh. Maecenas dignissim tristique tempus. Proin venenatis sem a orci sagittis, vel consequat sem vestibulum. Donec consectetur cursus tortor, eget volutpat lacus posuere a. Pellentesque eu orci hendrerit sapien dictum fringilla. Morbi rutrum mollis ipsum sit amet hendrerit. Nullam nec felis tortor. Mauris augue turpis, volutpat ac odio in, faucibus venenatis purus. Curabitur scelerisque pharetra nunc non mattis. Nunc sagittis euismod mi sit amet gravida. Integer malesuada pretium nibh. Maecenas sagittis facilisis enim, et hendrerit nulla fringilla in. Nam pulvinar, nibh non mattis hendrerit, arcu velit molestie sem, sed rutrum arcu odio a risus. Pellentesque lorem sem, dictum nec sem nec, congue ornare purus. Mauris id efficitur mi. Phasellus nec tortor lacus. Integer vitae tempus lorem. Suspendisse augue orci, volutpat vitae magna id, venenatis viverra nunc. Sed lobortis faucibus ante, ac porttitor risus. Proin viverra vestibulum enim, sed dignissim erat lobortis scelerisque. Aliquam et diam ut lacus dictum tristique. Sed a sapien quis nulla semper elementum. Ut fringilla laoreet luctus. Vivamus mi ipsum. %s', CAST('Ellipsis' AS VARCHAR(3000))) +GO + +SELECT FORMATMESSAGE('Long string test parameter: %s', CAST('Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla consequat metus sit amet lectus vulputate lacinia. Nam vel auctor enim, quis finibus lorem. Quisque maximus egestas est, et vehicula lectus. Curabitur sodales efficitur nibh, quis varius metus semper vel. Aenean quis rhoncus tortor. Nullam eleifend blandit imperdiet. Donec a gravida ex. Cras ac nulla orci. Fusce ut est ac odio consequat rutrum. Morbi diam erat, blandit ut nunc efficitur, venenatis placerat nunc. Sed laoreet aliquam leo. Quisque vestibulum hendrerit mi, at cursus eros aliquet vitae. Mauris a sem blandit, interdum ligula et, feugiat nulla. Sed quis ipsum at dolor congue vulputate at elementum ex. Integer iaculis, libero nec pulvinar molestie, neque mi vestibulum nisl, in volutpat metus arcu in purus. Praesent ullamcorper mi sit amet consectetur mattis. Sed quis ex placerat, finibus purus dignissim, porttitor nibh. Maecenas dignissim tristique tempus. Proin venenatis sem a orci sagittis, vel consequat sem vestibulum. Donec consectetur cursus tortor, eget volutpat lacus posuere a. Pellentesque eu orci hendrerit sapien dictum fringilla. Morbi rutrum mollis ipsum sit amet hendrerit. Nullam nec felis tortor. Mauris augue turpis, volutpat ac odio in, faucibus venenatis purus. Curabitur scelerisque pharetra nunc non mattis. Nunc sagittis euismod mi sit amet gravida. Integer malesuada pretium nibh. Maecenas sagittis facilisis enim, et hendrerit nulla fringilla in. Nam pulvinar, nibh non mattis hendrerit, arcu velit molestie sem, sed rutrum arcu odio a risus. Pellentesque lorem sem, dictum nec sem nec, congue ornare purus. Mauris id efficitur mi. Phasellus nec tortor lacus. Integer vitae tempus lorem. Suspendisse augue orci, volutpat vitae magna id, venenatis viverra nunc. Sed lobortis faucibus ante, ac porttitor risus. Proin viverra vestibulum enim, sed dignissim erat lobortis scelerisque. Aliquam et diam ut lacus dictum tristique. Sed a sapien quis nulla semper elementum. Ut fringilla laoreet luctus. Vivamus mi ipsum.i' AS VARCHAR(3000))) +GO + +SELECT FORMATMESSAGE('21 args: %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s', CAST('one' AS VARCHAR(10)), CAST('two' AS VARCHAR(10)),CAST('three' AS VARCHAR(10)),CAST('four' AS VARCHAR(10)),CAST('five' AS VARCHAR(10)),CAST('six' AS VARCHAR(10)),CAST('seven' AS VARCHAR(10)),CAST('eight' AS VARCHAR(10)),CAST('nine' AS VARCHAR(10)),CAST('ten' AS VARCHAR(10)),CAST('eleven' AS VARCHAR(10)),CAST('twelve' AS VARCHAR(10)),CAST('thirteen' AS VARCHAR(10)),CAST('fourteen' AS VARCHAR(10)),CAST('fifteen' AS VARCHAR(10)),CAST('sixteen' AS VARCHAR(10)),CAST('seventeen' AS VARCHAR(10)),CAST('eighteen' AS VARCHAR(10)),CAST('nineteen' AS VARCHAR(10)),CAST('twenty' AS VARCHAR(10)),CAST('twenty-one' AS VARCHAR(10))) +GO + +SELECT FORMATMESSAGE('Invalid parameter example: %s', TRUE) +GO + +SELECT FORMATMESSAGE('Invalid placeholder example: %m', 0) +GO + +SELECT FORMATMESSAGE(NULL, 0) +GO + +SELECT FORMATMESSAGE('Placeholder null: %s', NULL) +GO + +SELECT FORMATMESSAGE('Mismatch datatype: %d', 'string') +GO + +SELECT FORMATMESSAGE('Mismatch datatype: %o', CAST('string' AS VARCHAR(10))) +GO + +SELECT FORMATMESSAGE('Mismatch datatype: %s', 123); +GO diff --git a/contrib/test/JDBC/input/BABEL-785.sql b/contrib/test/JDBC/input/BABEL-785.sql new file mode 100644 index 00000000000..5303c5c5ddb --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-785.sql @@ -0,0 +1,115 @@ +-- Verify correct value of ANSI_NULLS +select sessionproperty('ANSI_NULLS'); +go + +create table testTbl(fname varchar(10)); +insert into testTbl values (null), ('Jenny'); +select * from testTbl +go + +select * from testTbl where fname=null; +go + +select * from testTbl where fname<>null; +go + +drop table testTbl; +go + +-- Verify correct value of ANSI_PADDING +select sessionproperty('ANSI_PADDING'); +go + +create table testTbl ( + is_char_null char(10) null, + is_char_notnull char(10) not null, + is_varchar_null varchar(10) null, + is_varchar_notnull varchar(10) not null +); +go + +insert into testTbl values + ('aaa','aaa','aaa','aaa'), + ('aaa ','aaa ','aaa ','aaa '); +go + +select datalength(is_char_null) as is_char_null_len, + datalength(is_char_notnull) as is_char_notnull_len, + datalength(is_varchar_null) as is_varchar_null_len, + datalength(is_varchar_notnull) as is_varchar_notnull_len +from testTbl; +go + +SELECT + is_char_null+'|' as is_char_null, + is_char_notnull+'|' as is_char_notnull, + is_varchar_null+'|' as is_varchar_null, + is_varchar_notnull+'|' as is_varchar_notnull +from testTbl; +go + +drop table testTbl; +go + +-- Verify correct value of ANSI_WARNINGS +select sessionproperty('ANSI_WARNINGS'); +go + +create table testTbl(fname varchar(10)); +go + +insert into testTbl values (null), ('Jenny Matthews'); +go + +drop table testTbl; +go + +-- Verify correct value of ARITHABORT +select sessionproperty('ARITHABORT'); +go + +select 25/0; +go + +-- Verify correct value of CONCAT_NULL_YIELDS_NULL +select sessionproperty('CONCAT_NULL_YIELDS_NULL'); +go + +select 'test'+null; +go + +select concat('test', null); +go + +select concat(null, 'test'); +go + +-- Verify correct value of NUMERIC_ROUNDABORT +select sessionproperty('NUMERIC_ROUNDABORT'); +go + +create table testTbl(size int) +go + +insert into testTbl values (707072), (1024000); +go + +select (100 / SUM((((size) * 8.00) / 1024))) from testTbl as T; +go + +drop table testTbl; +go + +-- Verify correct value of QUOTED_IDENTIFIER +select sessionproperty('QUOTED_IDENTIFIER'); +go + +select 'Hello, world!'; +go + +select "Hello, world!"; +go + +-- Test invalid property +select sessionproperty('nonexistent_property'); +go \ No newline at end of file diff --git a/contrib/test/JDBC/input/BABEL-788.sql b/contrib/test/JDBC/input/BABEL-788.sql new file mode 100644 index 00000000000..416e3449808 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-788.sql @@ -0,0 +1,91 @@ + +drop table if exists babel_788_int; +GO + +create table babel_788_int(a int null, b int not null); +GO + +insert babel_788_int values (1, 10); +insert babel_788_int values (3, 7); +insert babel_788_int values (null, 8); +GO + +select * from babel_788_int order by a; +GO +select * from babel_788_int order by a asc; +GO +select * from babel_788_int order by a desc; +GO + +select * from babel_788_int order by b; +GO +select * from babel_788_int order by b asc; +GO +select * from babel_788_int order by b desc; +GO + +select * from babel_788_int order by a + b; +GO +select * from babel_788_int order by a + b asc; +GO +select * from babel_788_int order by a + b desc; +GO + +select * from (select top(2) a from babel_788_int order by 1) s; +GO + +drop table if exists babel_788_select_into; +GO +select top(2) a into babel_788_select_into from babel_788_int order by 1; +GO +select * from babel_788_select_into; +GO + +drop table if exists babel_788_subquery_select_into; +GO +select * into babel_788_subquery_select_into from (select top(2) a from babel_788_int order by 1) s; +GO +select * from babel_788_subquery_select_into; +GO + +drop table if exists babel_788_int; +GO +drop table if exists babel_788_select_into; +GO +drop table if exists babel_788_subquery_select_into; +GO + +drop table if exists babel_788_varchar; +GO + +create table babel_788_varchar(a varchar(2) null, b varchar(2) not null); +GO + +insert babel_788_varchar values ('1', '10'); +insert babel_788_varchar values ('3', '7'); +insert babel_788_varchar values ('', ' '); +insert babel_788_varchar values (null, '8'); +GO + +select * from babel_788_varchar order by a; +GO +select * from babel_788_varchar order by a asc; +GO +select * from babel_788_varchar order by a desc; +GO + +select * from babel_788_varchar order by b; +GO +select * from babel_788_varchar order by b asc; +GO +select * from babel_788_varchar order by b desc; +GO + +select * from babel_788_varchar order by a + b; +GO +select * from babel_788_varchar order by a + b asc; +GO +select * from babel_788_varchar order by a + b desc; +GO +drop table if exists babel_788_varchar; +GO diff --git a/contrib/test/JDBC/input/BABEL-798.sql b/contrib/test/JDBC/input/BABEL-798.sql new file mode 100644 index 00000000000..c2c1bf74739 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-798.sql @@ -0,0 +1,9 @@ +-- Without any transaction +SELECT XACT_STATE() +GO + +-- Inside a transaction +BEGIN TRANSACTION + SELECT XACT_STATE() +COMMIT TRANSACTION +GO \ No newline at end of file diff --git a/contrib/test/JDBC/input/BABEL-807.sql b/contrib/test/JDBC/input/BABEL-807.sql new file mode 100644 index 00000000000..cf3ca5d9870 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-807.sql @@ -0,0 +1,9 @@ +-- supported collation +SELECT COLLATIONPROPERTY('Traditional_Spanish_CS_AS', 'CodePage'), COLLATIONPROPERTY('Traditional_Spanish_CS_AS', 'ComparisonStyle'), COLLATIONPROPERTY('Traditional_Spanish_CS_AS', 'Version'), COLLATIONPROPERTY('Traditional_Spanish_CS_AS', 'LCID'); +go + +SELECT COLLATIONPROPERTY('Traditional_Spanish_CS_AS', 'INVALID'); +go + +SELECT COLLATIONPROPERTY('INVALID', 'LCID'); +go diff --git a/contrib/test/JDBC/input/BABEL-820.sql b/contrib/test/JDBC/input/BABEL-820.sql new file mode 100644 index 00000000000..c38b8c65dd1 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-820.sql @@ -0,0 +1,21 @@ +SELECT 42 = CAST(42 AS numeric(38,0)) +GO + +SELECT CAST(42 AS numeric(38,0)) = 42 +GO + + +CREATE TABLE babel_820_test_table1(test_id INT IDENTITY, test_col1 INT) +GO + +INSERT INTO babel_820_test_table1 (test_col1) VALUES (10), (20), (30) +GO + + +SELECT test_col1 FROM babel_820_test_table1 WHERE test_id = @@IDENTITY +GO + + +DROP TABLE babel_820_test_table1 +GO + diff --git a/contrib/test/JDBC/input/BABEL-872.sql b/contrib/test/JDBC/input/BABEL-872.sql new file mode 100644 index 00000000000..c38b8c65dd1 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-872.sql @@ -0,0 +1,21 @@ +SELECT 42 = CAST(42 AS numeric(38,0)) +GO + +SELECT CAST(42 AS numeric(38,0)) = 42 +GO + + +CREATE TABLE babel_820_test_table1(test_id INT IDENTITY, test_col1 INT) +GO + +INSERT INTO babel_820_test_table1 (test_col1) VALUES (10), (20), (30) +GO + + +SELECT test_col1 FROM babel_820_test_table1 WHERE test_id = @@IDENTITY +GO + + +DROP TABLE babel_820_test_table1 +GO + diff --git a/contrib/test/JDBC/input/BABEL-909.sql b/contrib/test/JDBC/input/BABEL-909.sql new file mode 100644 index 00000000000..61a82019cc0 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-909.sql @@ -0,0 +1,30 @@ +-- Test NEWSEQUENTIALID() as column default constraint +CREATE TABLE new_sequential_id_table_1 (ColumnA uniqueidentifier DEFAULT NEWSEQUENTIALID()); +go +-- Test NEWSEQUENTIALID() in alter table +ALTER TABLE new_sequential_id_table_1 ADD ColumnB uniqueidentifier DEFAULT NEWSEQUENTIALID(); +go +-- Test NEWSEQUENTIALID() as column default constraint with wrong type (shoudl fail) +CREATE TABLE new_sequential_id_table_2 (ColumnA varchar(60) DEFAULT NEWSEQUENTIALID()); +go +-- Test NEWSEQUENTIALID() in SELECT statement (shoudl fail) +SELECT pg_typeof(newsequentialid()); +go +-- Test NEWSEQUENTIALID() as scalar function (should fail) +CREATE FUNCTION foo(@i uniqueidentifier) +RETURNS uniqueidentifier +AS +BEGIN + RETURN @i +END; +go +CREATE TABLE new_sequential_id_table_3 (ColumnA uniqueidentifier DEFAULT foo(NEWSEQUENTIALID())); +go +DROP TABLE new_sequential_id_table_1; +go +DROP TABLE new_sequential_id_table_2; +go +DROP TABLE new_sequential_id_table_3; +go +DROP FUNCTION foo; +go diff --git a/contrib/test/JDBC/input/BABEL-911.sql b/contrib/test/JDBC/input/BABEL-911.sql new file mode 100644 index 00000000000..63ba8cb1bdd --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-911.sql @@ -0,0 +1,11 @@ +-- BABEL-911: make sure table column constraints don't get confused as variable +-- constraints. +declare @tableVar1 table (a int not null, b int default 0, c nvarchar(60) collate Arabic_CS_AS); +select * from @tableVar1; +GO + +-- NOT NULL after ')' should be parsed as variable constraint and should report +-- error. +declare @tableVar1 table (a int) not null; +end; +GO diff --git a/contrib/test/JDBC/input/BABEL-931.sql b/contrib/test/JDBC/input/BABEL-931.sql new file mode 100644 index 00000000000..f9d0eec5345 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-931.sql @@ -0,0 +1,51 @@ +CREATE PROCEDURE babel_931_proc (@a INT OUTPUT, @b INT OUTPUT) AS +BEGIN + SET @a=100; PRINT '@a (inner): ' + cast(@a as varchar(10)); + SET @b=200; PRINT '@b (inner): ' + cast(@b as varchar(10)); + select @a+@b as ret; END; +GO + +CREATE PROCEDURE babel_931_caller AS +BEGIN + EXEC babel_931_proc 2, 3; +END +GO + +EXEC babel_931_caller +GO + +CREATE PROCEDURE babel_931_caller_2 AS +BEGIN + DECLARE @b INT; + EXEC babel_931_proc 2, @b OUT; + PRINT '@b (outer): ' + cast(@b as varchar(10)); +END +GO + +EXEC babel_931_caller_2 +GO + +CREATE PROCEDURE babel_931_caller_3 AS +BEGIN + DECLARE @a INT; + DECLARE @b INT; + EXEC babel_931_proc @a OUT, @b OUT; + PRINT '@a (outer): ' + cast(@a as varchar(10)); + PRINT '@b (outer): ' + cast(@b as varchar(10)); +END +GO + +EXEC babel_931_caller_3 +GO + +DROP PROCEDURE babel_931_proc +GO + +DROP PROCEDURE babel_931_caller +GO + +DROP PROCEDURE babel_931_caller_2 +GO + +DROP PROCEDURE babel_931_caller_3 +GO diff --git a/contrib/test/JDBC/input/BABEL-941.sql b/contrib/test/JDBC/input/BABEL-941.sql new file mode 100644 index 00000000000..7293c3e2594 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-941.sql @@ -0,0 +1,43 @@ +CREATE PROCEDURE p1 as +BEGIN +DECLARE @a int; +SELECT @a = 123; +PRINT @a; +END +GO + +CREATE TABLE t1 ( b int) ; +GO + +INSERT INTO t1 VALUES (1) +GO + +INSERT INTO t1 VALUES (2) +GO + +INSERT INTO t1 VALUES (3) +GO + +CREATE PROCEDURE p2 as +BEGIN +DECLARE @a int; +SELECT @a = b from t1 where (b = 1); +PRINT @a; +END +GO + +EXEC p1; +GO + +EXEC p2; +GO + +DROP TABLE t1 +GO + +DROP PROCEDURE p1 +GO + +DROP PROCEDURE p2 +GO + diff --git a/contrib/test/JDBC/input/BABEL-955.sql b/contrib/test/JDBC/input/BABEL-955.sql new file mode 100644 index 00000000000..8dd732c95bb --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-955.sql @@ -0,0 +1,50 @@ +create schema test1; +GO + +CREATE TABLE test1.t1(c1 int, c2 varchar(10) ) +GO +-- Doesn't matter if it's DECLARE or a SELECT @@rowcount +CREATE TRIGGER test1.tr1 ON test1.t1 AFTER DELETE AS + DECLARE @rowcnt int + SET @rowcnt = @@ROWCOUNT + SELECT @rowcnt AS "#rows" +go + +CREATE TRIGGER tr1 ON test1.t1 AFTER DELETE AS + DECLARE @rowcnt int + SET @rowcnt = @@ROWCOUNT + SELECT @rowcnt AS "#rows" +go + +create schema test2; +go + +CREATE TRIGGER test2.tr2 ON test1.t1 AFTER DELETE AS + DECLARE @rowcnt int + SET @rowcnt = @@ROWCOUNT + SELECT @rowcnt AS "#rows" +go + +CREATE TRIGGER test2.tr2 ON t1 AFTER DELETE AS + DECLARE @rowcnt int + SET @rowcnt = @@ROWCOUNT + SELECT @rowcnt AS "#rows" +go + +drop schema test2; +go + +drop trigger tr1 +go + +drop trigger test2.tr1 +go + +drop trigger test1.tr1 +go + +drop table test1.t1 +go + +drop schema test1 +go diff --git a/contrib/test/JDBC/input/BABEL-APPLOCK.sql b/contrib/test/JDBC/input/BABEL-APPLOCK.sql new file mode 100644 index 00000000000..9b11fc85653 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-APPLOCK.sql @@ -0,0 +1,136 @@ +-- Part #1: single-session tests + +-- default params +BEGIN TRAN; +exec sp_getapplock @Resource = 'lock1', @LockMode = 'SHARED'; +COMMIT; +GO + +-- given params +exec sp_getapplock @Resource = 'lock1', @LockMode = 'EXCLUSIVE', @LockOwner = 'SESSION', @LockTimeout = 10, @DbPrincipal = 'dbo'; +GO + +exec sp_releaseapplock @Resource = 'lock1', @LockOwner = 'SESSION'; +GO + +-- null params not allowed +exec sp_getapplock @Resource = null, @LockMode = 'shared'; +GO + +exec sp_getapplock @Resource = 'lock1', @LockMode = null; +GO + +-- parameters are case-insensitive except for the lock name + +exec sp_getapplock @Resource = 'lock1', @LockMode = 'Shared', @LockOwner = 'session'; +GO + +exec sp_getapplock @Resource = 'LOCK1', @LockMode = 'Exclusive', @LockOwner = 'SESSION'; +GO + +exec sp_releaseapplock @Resource = 'lock1', @LockOwner = 'SESSION'; +GO + +exec sp_releaseapplock @Resource = 'LOCK1', @LockOwner = 'session'; +GO + +-- implicit unlocking, lock will be gone after commit +BEGIN TRAN; +exec sp_getapplock @Resource = 'lock1', @LockMode = 'SHARED', @LockOwner = 'TRANSACTION'; +GO +COMMIT; +GO + +-- explicit unlocking (trx & session) +BEGIN TRAN; +exec sp_getapplock @Resource = 'lock1', @LockMode = 'SHARED', @LockOwner = 'TRANSACTION'; +GO +exec sp_releaseapplock @Resource = 'lock1'; +GO +COMMIT; +GO + +exec sp_getapplock @Resource = 'lock1', @LockMode = 'SHARED', @LockOwner = 'SESSION'; +GO + +exec sp_releaseapplock @Resource = 'lock1', @LockOwner = 'SESSION'; +GO + +-- aquire lock multiple times, and need to unlock same number of times too + +exec sp_getapplock @Resource = 'lock1', @LockMode = 'SHARED', @LockOwner = 'SESSION'; +GO + +exec sp_getapplock @Resource = 'lock1', @LockMode = 'SHARED', @LockOwner = 'SESSION'; +GO + +exec sp_releaseapplock @Resource = 'lock1', @LockOwner = 'SESSION'; +GO + +exec sp_releaseapplock @Resource = 'lock1', @LockOwner = 'SESSION'; +GO + +-- APPLOCK_MODE tests +exec sp_getapplock @Resource = 'test1', @LockMode = 'shared', @LockOwner = 'session'; +GO + +select APPLOCK_MODE ('dbo', 'test1', 'session'); -- should show 'Shared' +go + +exec sp_getapplock @Resource = 'test1', @LockMode = 'update', @LockOwner = 'session'; +GO + +select APPLOCK_MODE ('dbo', 'test1', 'session'); -- should show 'Update' +go + +exec sp_releaseapplock @Resource = 'test1', @LockOwner = 'session'; +GO + +exec sp_releaseapplock @Resource = 'test1', @LockOwner = 'session'; +GO + +exec sp_getapplock @Resource = 'test1', @LockMode = 'update', @LockOwner = 'session'; +GO + +exec sp_getapplock @Resource = 'test1', @LockMode = 'IntentExclusive', @LockOwner = 'session'; +GO + +select APPLOCK_MODE ('dbo', 'test1', 'session'); -- should show 'UpdateIntentExclusive' +go + +exec sp_releaseapplock @Resource = 'test1', @LockOwner = 'session'; +GO + +exec sp_releaseapplock @Resource = 'test1', @LockOwner = 'session'; +GO + +exec sp_getapplock @Resource = 'test1', @LockMode = 'exclusive', @LockOwner = 'session'; +GO + +select APPLOCK_MODE ('dbo', 'test1', 'session'); -- should show "Exclusive" +go + +exec sp_releaseapplock @Resource = 'test1', @LockOwner = 'session'; +GO + +select APPLOCK_MODE ('dbo', 'test1', 'session'); -- should show "NoLock" +go + +-- APPLOCK_TEST tests +SELECT APPLOCK_TEST('dbo', 'lock1', 'Exclusive', 'Session'); +GO + +SELECT APPLOCK_TEST('public', 'MyAppLock', 'Shared', 'Transaction') -- should throw error +GO + +BEGIN TRAN +SELECT APPLOCK_TEST('dbo', 'lock1', 'Shared', 'Transaction'); +COMMIT +GO + +BEGIN TRAN +exec sp_getapplock @Resource = 'lock1', @LockMode = 'exclusive', @LockOwner = 'Transaction' +SELECT APPLOCK_TEST('dbo', 'lock1', 'Shared', 'Transaction'); +COMMIT +GO + diff --git a/contrib/test/JDBC/input/BABEL-COLUMN-ALIAS.sql b/contrib/test/JDBC/input/BABEL-COLUMN-ALIAS.sql new file mode 100644 index 00000000000..a75cc5a6515 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-COLUMN-ALIAS.sql @@ -0,0 +1,114 @@ +SELECT 1 a +go + +SELECT 1 'a' +go + +SELECT 1 "a" +go + +SELECT a=1 +go + +SELECT 'a'=1 +go + +SELECT "a"=1 +go + +-- column alias using PG reserved keyword but non-reserved keyword in T-SQL +SELECT 1 year +go + +SELECT 1 'year' +go + +SELECT 1 "year" +go + +SELECT year=1 +go + +SELECT 'year'=1 +go + +SELECT "year"=1 +go + +CREATE TABLE t_567 (a int); +INSERT INTO t_567 VALUES (42); +GO +SELECT a year from t_567; +GO +SELECT a 'year' from t_567; +GO +SELECT a "year" from t_567; +GO +SELECT year=a from t_567; +GO +SELECT 'year'=a from t_567; +GO +SELECT "year"=a from t_567; +GO +DROP TABLE t_567; +GO + +-- double quoted alias having escapted charcter +SELECT 1 """col""" +go + +SELECT """col"""=1 +go + +-- column alias with squred bracket +SELECT 1 ["col"] +go + +SELECT ["col"]=1 +go + +-- BABEL-2116: regression in a complex query. Plase note column alias LastRefreshed is specificed and expression refers to a local tsql variable +CREATE PROC [GetLandingPageDetails] AS +BEGIN + SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; + DECLARE @MaxDateHeapUsage DATE; + DECLARE @MaxDateAuditorSummary DATE + DECLARE @MaxDateBadCname DATE + DECLARE @MaxDateCPUSummary DATE + DECLARE @MaxDDLAudit DATE + DECLARE @MaxDateLinkServerSecurity DATE; + SELECT @MaxDateLinkServerSecurity = CAST(MAX(LinkServerCodeLastCheck) AS DATE) FROM MCPBI.dbo.LinkServerRemediation (NOLOCK); + SELECT @MaxDateHeapUsage = MAX(ForDate) FROM dbo.HeapUsageSummary (NOLOCK); + SELECT @MaxDateAuditorSummary = MAX(ExecutionDate) FROM dbo.AuditorSummary (NOLOCK); + SELECT @MaxDateBadCname = d.Date FROM MCPData.Dimension.Date AS d (NOLOCK) WHERE d.DateID = (SELECT MAX(b.DateID) FROM dbo.BadCNameUsage AS b (NOLOCK)); + SELECT @MaxDateCPUSummary = MAX(EndDate) FROM CPUSummary_TeamNames_Monthly (NOLOCK); + SELECT @MaxDDLAudit = CAST(MAX(LastCheckUTC) AS DATE) FROM MCPInventory.Metric.DBA_tblAuditDDL (NOLOCK); + WITH rptUsage AS (SELECT rud.Path, rud.Name, COUNT(*) AS RunCount FROM ReportServer.dbo.vwReportUsageDetails AS rud JOIN MCPInventory.Pub.vw_vw_WD_HRIS_Model AS hrd ON ('AQR\' + hrd.DomainId) COLLATE Latin1_General_100_CI_AS_KS_WS = rud.UserName WHERE hrd.GroupName != 'DBA' AND rud.Name IS NOT NULL AND rud.Path <> '/HeapUsageSummary' GROUP BY rud.Path, rud.Name) + SELECT bil.Name, bil.Description, bil.rptLink, bil.DataRefreshCycle, LastRefreshed = CASE WHEN bil.DependsOnTable = 'AuditorSummary' THEN @MaxDateAuditorSummary WHEN bil.DependsOnTable = 'HeapUsageSummary' THEN @MaxDateHeapUsage WHEN bil.DependsOnTable = 'BadCNameUsage' THEN @MaxDateBadCname WHEN bil.DependsOnTable = 'CPUSummary_TeamNames_Monthly' THEN @MaxDateCPUSummary WHEN bil.DependsOnTable = 'Metric.DBA_tblAuditDDL' THEN @MaxDDLAudit WHEN bil.DependsOnTable = 'MCPBI.dbo.LinkServerRemediation' THEN @MaxDateLinkServerSecurity END, ISNULL(ru.RunCount, 0) AS UsageInLast60Days, bil.isProd FROM SSRS.BIReportsList AS bil LEFT JOIN rptUsage AS ru ON bil.rptName COLLATE Latin1_General_100_CI_AS_KS_WS = ru.Name WHERE bil.isProd = 1; +END; +GO + +CREATE PROC [GetLandingPageDetails_2] AS +BEGIN + SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; + DECLARE @MaxDateHeapUsage DATE; + DECLARE @MaxDateAuditorSummary DATE + DECLARE @MaxDateBadCname DATE + DECLARE @MaxDateCPUSummary DATE + DECLARE @MaxDDLAudit DATE + DECLARE @MaxDateLinkServerSecurity DATE; + SELECT @MaxDateLinkServerSecurity = CAST(MAX(LinkServerCodeLastCheck) AS DATE) FROM MCPBI.dbo.LinkServerRemediation (NOLOCK); + SELECT @MaxDateHeapUsage = MAX(ForDate) FROM dbo.HeapUsageSummary (NOLOCK); + SELECT @MaxDateAuditorSummary = MAX(ExecutionDate) FROM dbo.AuditorSummary (NOLOCK); + SELECT @MaxDateBadCname = d.Date FROM MCPData.Dimension.Date AS d (NOLOCK) WHERE d.DateID = (SELECT MAX(b.DateID) FROM dbo.BadCNameUsage AS b (NOLOCK)); + SELECT @MaxDateCPUSummary = MAX(EndDate) FROM CPUSummary_TeamNames_Monthly (NOLOCK); + SELECT @MaxDDLAudit = CAST(MAX(LastCheckUTC) AS DATE) FROM MCPInventory.Metric.DBA_tblAuditDDL (NOLOCK); + WITH rptUsage AS (SELECT rud.Path, rud.Name, COUNT(*) AS RunCount FROM ReportServer.dbo.vwReportUsageDetails AS rud JOIN MCPInventory.Pub.vw_vw_WD_HRIS_Model AS hrd ON ('AQR\' + hrd.DomainId) COLLATE Latin1_General_100_CI_AS_KS_WS = rud.UserName WHERE hrd.GroupName != 'DBA' AND rud.Name IS NOT NULL AND rud.Path <> '/HeapUsageSummary' GROUP BY rud.Path, rud.Name) + SELECT bil.Name, bil.Description, bil.rptLink, bil.DataRefreshCycle, CASE WHEN bil.DependsOnTable = 'AuditorSummary' THEN @MaxDateAuditorSummary WHEN bil.DependsOnTable = 'HeapUsageSummary' THEN @MaxDateHeapUsage WHEN bil.DependsOnTable = 'BadCNameUsage' THEN @MaxDateBadCname WHEN bil.DependsOnTable = 'CPUSummary_TeamNames_Monthly' THEN @MaxDateCPUSummary WHEN bil.DependsOnTable = 'Metric.DBA_tblAuditDDL' THEN @MaxDDLAudit WHEN bil.DependsOnTable = 'MCPBI.dbo.LinkServerRemediation' THEN @MaxDateLinkServerSecurity END LastRefereshed, ISNULL(ru.RunCount, 0) AS UsageInLast60Days, bil.isProd FROM SSRS.BIReportsList AS bil LEFT JOIN rptUsage AS ru ON bil.rptName COLLATE Latin1_General_100_CI_AS_KS_WS = ru.Name WHERE bil.isProd = 1; +END; +GO + +DROP PROC [GetLandingPageDetails] +GO +DROP PROC [GetLandingPageDetails_2] +GO diff --git a/contrib/test/JDBC/input/BABEL-COLUMN-CONSTRAINT.sql b/contrib/test/JDBC/input/BABEL-COLUMN-CONSTRAINT.sql new file mode 100644 index 00000000000..e913b5e909f --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-COLUMN-CONSTRAINT.sql @@ -0,0 +1,57 @@ +CREATE SCHEMA [Babelfish_COLCONST]; +GO + +create table [Babelfish_COLCONST].[a] ( + id int identity primary key, + texto varchar(50) NOT NULL +); + +create table [Babelfish_COLCONST].[b] ( + id int identity primary key, + foreign_id int not null references [Babelfish_COLCONST].[a], + texto varchar(50) NOT NULL +); +GO + +create table [Babelfish_COLCONST].[c] ( + id int identity primary key, + foreign_id int not null, + foreign key(foreign_id) references [Babelfish_COLCONST].[a](id), + texto varchar(50) NOT NULL +); +GO + +SET IDENTITY_INSERT [Babelfish_COLCONST].[a] ON; +GO + +insert into [Babelfish_COLCONST].[a](id,texto) values(1, 'some text'); +GO + +insert into [Babelfish_COLCONST].[b](foreign_id, texto) values(1,'insert text'); +GO + +insert into [Babelfish_COLCONST].[c](foreign_id, texto) values(1,'insert text'); +GO + +select * from [Babelfish_COLCONST].[a]; +GO + +select * from [Babelfish_COLCONST].[b]; +GO + +select * from [Babelfish_COLCONST].[c]; +GO + +-- test invalid data insert +insert into [Babelfish_COLCONST].[b](foreign_id, texto) values(2,'insert text'); +GO + +-- test invalid data insert +insert into [Babelfish_COLCONST].[c](foreign_id, texto) values(2,'insert text'); +GO + +DROP TABLE [Babelfish_COLCONST].[c]; +DROP TABLE [Babelfish_COLCONST].[b]; +DROP TABLE [Babelfish_COLCONST].[a]; +DROP SCHEMA [Babelfish_COLCONST]; +GO diff --git a/contrib/test/JDBC/input/BABEL-DATABASEPROPERTYEX.sql b/contrib/test/JDBC/input/BABEL-DATABASEPROPERTYEX.sql new file mode 100644 index 00000000000..efe0f414271 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-DATABASEPROPERTYEX.sql @@ -0,0 +1,21 @@ +-- test databasepropertyex() function +select databasepropertyex(N'template1',N'Collation') +GO +select databasepropertyex(N'template1',N'IsInStandBy') +GO +select databasepropertyex(N'template1',N'IsAutoClose') +GO +select databasepropertyex(N'template1',N'IsAutoCreateStatistics') +GO +select 'true' where databasepropertyex(N'template1',N'IsTornPageDetectionEnabled') >= 0 +GO +select databasepropertyex(N'template1',N'Updateability') +GO +select databasepropertyex(N'template1',N'Status') +GO +SELECT (case when charindex(cast(databasepropertyex(N'template1',N'Version') as nvarchar), version()) > 0 then 'true' else 'false' end) result +GO +select databasepropertyex(N'template1',N'IsArithmeticAbortEnabled') +GO +select databasepropertyex(N'template1',N'IsAutoShrink') +GO diff --git a/contrib/test/JDBC/input/BABEL-EXTENDEDPROPERTY.sql b/contrib/test/JDBC/input/BABEL-EXTENDEDPROPERTY.sql new file mode 100644 index 00000000000..3230ae17ac2 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-EXTENDEDPROPERTY.sql @@ -0,0 +1,17 @@ +create table t1 (a int) +go + +-- For now, will always return empty result set because sys.extended_properties +-- is always empty before the support of sp_[add/drop/update]extendedproperty (BABEL-280) +select * FROM fn_listextendedproperty('COLUMN', 'schema', N'dbo', 'table', N't1', 'column', N'a'); +go + +select * FROM fn_listextendedproperty(NULL, 'schema', N'dbo', 'table', N't1', NULL, NULL); +go + +-- Failed query in BABEL-1784 +exec [sys].sp_columns_100 N't23',N'dbo',NULL,NULL,@ODBCVer=3,@fUsePattern=1; +go + +drop table t1 +go diff --git a/contrib/test/JDBC/input/BABEL-GUC-PLAN.sql b/contrib/test/JDBC/input/BABEL-GUC-PLAN.sql new file mode 100644 index 00000000000..bf46c12ed51 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-GUC-PLAN.sql @@ -0,0 +1,213 @@ +CREATE TABLE test_table1(test_id INT IDENTITY, test_col1 INT); +go + +CREATE TABLE test_table2(test_id INT IDENTITY, test_col1 INT); +go + +CREATE PROCEDURE insert_test_table1_stmt1 +AS BEGIN +INSERT INTO test_table1 (test_id, test_col1) VALUES (5, 1); +END; +go + +CREATE PROCEDURE insert_test_table1_stmt1_outer +AS BEGIN +EXEC insert_test_table1_stmt1; +END; +go + +CREATE PROCEDURE insert_test_table1_stmt2 +AS BEGIN +INSERT INTO test_table1 (test_id, test_col1) VALUES (8, 2); +END; +go + +CREATE PROCEDURE insert_test_table1_stmt2_outer +AS BEGIN +EXEC insert_test_table1_stmt2; +END; +go + +CREATE PROCEDURE insert_test_table1_stmt3 +AS BEGIN +INSERT INTO test_table1 (test_id, test_col1) VALUES (10, 3); +END; +go + +CREATE PROCEDURE insert_test_table1_stmt4 +AS BEGIN +INSERT INTO test_table1 (test_id, test_col1) VALUES (64, 4); +END; +go + +CREATE PROCEDURE insert_test_table1_stmt5 +AS BEGIN +INSERT INTO test_table1 (test_id, test_col1) VALUES (128, 5); +END; +go + +CREATE PROCEDURE insert_test_table1_stmt6 +AS BEGIN +INSERT INTO test_table1 (test_id, test_col1) VALUES (-2, 6); +END; +go + +CREATE PROCEDURE insert_test_table1_test_multi_stmts +AS BEGIN +EXEC insert_test_table1_stmt1 +EXEC insert_test_table1_stmt2 +EXEC insert_test_table1_stmt3 +EXEC insert_test_table1_stmt4 +EXEC insert_test_table1_stmt5 +EXEC insert_test_table1_stmt6 + +EXEC insert_test_table1_stmt3 +EXEC insert_test_table1_stmt5 +EXEC insert_test_table1_stmt4 +EXEC insert_test_table1_stmt6 +EXEC insert_test_table1_stmt1 +EXEC insert_test_table1_stmt2 +END; +go + +CREATE PROCEDURE insert_test_table1_val +@val INT +AS BEGIN +INSERT INTO test_table1 VALUES (@val); +END; +go + +-- Test re-planning based on GUC state +SET IDENTITY_INSERT test_table1 ON; +go + +EXEC insert_test_table1_stmt1_outer; +go + +EXEC insert_test_table1_stmt2_outer; +go + +SET IDENTITY_INSERT test_table1 OFF; +go + +EXEC insert_test_table1_stmt1_outer; +go + +EXEC insert_test_table1_stmt2_outer; +go + +SET IDENTITY_INSERT test_table1 ON; + +EXEC insert_test_table1_test_multi_stmts; +go + +SET IDENTITY_INSERT test_table1 OFF; +go + +-- Test a follow-up regular INSERT +EXEC insert_test_table1_val 7; +go + +SELECT * FROM test_table1; +go + +-- Test procedure drops +SET IDENTITY_INSERT test_table1 ON; +go + +EXEC insert_test_table1_stmt1_outer; +go + +EXEC insert_test_table1_stmt2_outer; +go + +DROP PROC insert_test_table1_stmt1_outer; +go + +EXEC insert_test_table1_stmt2_outer; +go + +SET IDENTITY_INSERT test_table1 OFF; +go + +EXEC insert_test_table1_stmt2_outer; +go + +SELECT * FROM test_table1; +go + +-- Test after arbitrarily changing state +SET IDENTITY_INSERT test_table2 ON; +go + +EXEC insert_test_table1_stmt1; +go + +EXEC insert_test_table1_stmt2; +go + +SET IDENTITY_INSERT test_table2 ON; +go + +SET IDENTITY_INSERT test_table2 OFF; +go + +SET IDENTITY_INSERT test_table2 OFF; +go + +EXEC insert_test_table1_stmt1; +go + +EXEC insert_test_table1_stmt2; +go + +SET IDENTITY_INSERT test_table1 ON; +go + +SET IDENTITY_INSERT test_table1 OFF; +go + +EXEC insert_test_table1_stmt1; +go + +EXEC insert_test_table1_stmt2; +go + +SET IDENTITY_INSERT test_table1 ON; +go + +EXEC insert_test_table1_stmt1; +go + +SET IDENTITY_INSERT test_table1 ON; +go + +EXEC insert_test_table1_stmt2; +go + +SET IDENTITY_INSERT test_table1 OFF; +go + +EXEC insert_test_table1_stmt1; +go + +EXEC insert_test_table1_stmt2; +go + +SELECT * FROM test_table1; +go + +-- Clean up +DROP PROC insert_test_table1_stmt1, +insert_test_table1_stmt2, +insert_test_table1_stmt2_outer, +insert_test_table1_stmt3, +insert_test_table1_stmt4, +insert_test_table1_stmt5, +insert_test_table1_stmt6, +insert_test_table1_test_multi_stmts, +insert_test_table1_val; +go +DROP TABLE test_table1, +test_table2; +go diff --git a/contrib/test/JDBC/input/BABEL-IDENTITY-BIFS.sql b/contrib/test/JDBC/input/BABEL-IDENTITY-BIFS.sql new file mode 100644 index 00000000000..2b94ac949b5 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-IDENTITY-BIFS.sql @@ -0,0 +1,346 @@ +CREATE SCHEMA ident_bifs; +GO + +-- Test standard INSERTs +SELECT IDENT_SEED('ident_bifs.t1'); +go +SELECT IDENT_INCR('ident_bifs.t1'); +go +SELECT IDENT_CURRENT('ident_bifs.t1'); +go +CREATE TABLE ident_bifs.t1(id INT IDENTITY, c1 INT); +go +SELECT @@IDENTITY; +go +SELECT IDENT_SEED('ident_bifs.t1'); +go +SELECT IDENT_INCR('ident_bifs.t1'); +go +SELECT IDENT_CURRENT('ident_bifs.t1'); +go +INSERT INTO ident_bifs.t1 (c1) VALUES (42); +go +INSERT INTO ident_bifs.t1 (c1) VALUES (42); +go +INSERT INTO ident_bifs.t1 (c1) VALUES (42); +go +INSERT INTO ident_bifs.t1 (c1) VALUES (42); +go +INSERT INTO ident_bifs.t1 (c1) VALUES (42); +go +SELECT @@IDENTITY; +go +SELECT IDENT_CURRENT('ident_bifs.t1'); +go + +-- Test IDENTITY_INSERT +SET IDENTITY_INSERT ident_bifs.t1 ON; +go +INSERT INTO ident_bifs.t1 (id, c1) VALUES (10, 42); +go +SELECT @@IDENTITY; +go +SELECT IDENT_CURRENT('ident_bifs.t1'); +go +INSERT INTO ident_bifs.t1 (id, c1) VALUES (-5, 42); +go +SELECT @@IDENTITY; +go +SELECT IDENT_CURRENT('ident_bifs.t1'); +go +SET IDENTITY_INSERT ident_bifs.t1 OFF; +go + +-- Test follow-up INSERTs +INSERT INTO ident_bifs.t1 (c1) VALUES (42); +go +SELECT @@IDENTITY; +go +SELECT IDENT_CURRENT('ident_bifs.t1'); +go +INSERT INTO ident_bifs.t1 (c1) VALUES (42); +go +SELECT @@IDENTITY; +go +SELECT IDENT_CURRENT('ident_bifs.t1'); +go + +-- Test new table with IDENTITY_INSERT +CREATE TABLE ident_bifs.t2(id INT IDENTITY, c1 INT); +go +SET IDENTITY_INSERT ident_bifs.t2 ON; +go +INSERT INTO ident_bifs.t2 (id, c1) VALUES (10, 42); +go +SELECT @@IDENTITY; +go +SELECT IDENT_CURRENT('ident_bifs.t2'); +go +SET IDENTITY_INSERT ident_bifs.t2 OFF; +go + +-- Test follow-up INSERTs +INSERT INTO ident_bifs.t2 (c1) VALUES (42); +go +SELECT @@IDENTITY; +go +SELECT IDENT_CURRENT('ident_bifs.t2'); +go +INSERT INTO ident_bifs.t2 (c1) VALUES (42); +go +SELECT @@IDENTITY; +go +SELECT IDENT_CURRENT('ident_bifs.t2'); +go + +-- Test follow-up INSERTs to the previous table +INSERT INTO ident_bifs.t1 (c1) VALUES (42); +go +SELECT @@IDENTITY; +go +SELECT IDENT_CURRENT('ident_bifs.t1'); +go +INSERT INTO ident_bifs.t1 (c1) VALUES (42); +go +SELECT @@IDENTITY; +go +SELECT IDENT_CURRENT('ident_bifs.t1'); +go + +-- Test standard INSERTs with decrementing values +CREATE TABLE ident_bifs.t3(id INT IDENTITY(5, -25), c1 INT); +go +SELECT @@IDENTITY; +go +SELECT IDENT_SEED('ident_bifs.t3'); +go +SELECT IDENT_INCR('ident_bifs.t3'); +go +SELECT IDENT_CURRENT('ident_bifs.t3'); +go +INSERT INTO ident_bifs.t3 (c1) VALUES (42); +go +INSERT INTO ident_bifs.t3 (c1) VALUES (42); +go +INSERT INTO ident_bifs.t3 (c1) VALUES (42); +go +INSERT INTO ident_bifs.t3 (c1) VALUES (42); +go +INSERT INTO ident_bifs.t3 (c1) VALUES (42); +go +SELECT @@IDENTITY; +go +SELECT IDENT_CURRENT('ident_bifs.t3'); +go + +-- Test IDENTITY_INSERT +SET IDENTITY_INSERT ident_bifs.t3 ON; +go +INSERT INTO ident_bifs.t3 (id, c1) VALUES (-500, 42); +go +SELECT @@IDENTITY; +go +SELECT IDENT_CURRENT('ident_bifs.t3'); +go +INSERT INTO ident_bifs.t3 (id, c1) VALUES (10, 42); +go +SELECT @@IDENTITY; +go +SELECT IDENT_CURRENT('ident_bifs.t3'); +go +SET IDENTITY_INSERT ident_bifs.t3 OFF; +go + +-- Test follow-up INSERTs +INSERT INTO ident_bifs.t3 (c1) VALUES (42); +go +SELECT @@IDENTITY; +go +SELECT IDENT_CURRENT('ident_bifs.t3'); +go +INSERT INTO ident_bifs.t3 (c1) VALUES (42); +go +SELECT @@IDENTITY; +go +SELECT IDENT_CURRENT('ident_bifs.t3'); +go + +-- Test new table with IDENTITY_INSERT +CREATE TABLE ident_bifs.t4(id INT IDENTITY(-10, -1), c1 INT); +go +SELECT IDENT_SEED('ident_bifs.t4'); +go +SELECT IDENT_INCR('ident_bifs.t4'); +go +SELECT IDENT_CURRENT('ident_bifs.t4'); +go +SET IDENTITY_INSERT ident_bifs.t4 ON; +go +INSERT INTO ident_bifs.t4 (id, c1) VALUES (-50, 42); +go +SELECT @@IDENTITY; +go +SELECT IDENT_CURRENT('ident_bifs.t4'); +go +SET IDENTITY_INSERT ident_bifs.t4 OFF; +go + +-- Test follow-up INSERTs +INSERT INTO ident_bifs.t4 (c1) VALUES (42); +go +SELECT @@IDENTITY; +go +SELECT IDENT_CURRENT('ident_bifs.t4'); +go +INSERT INTO ident_bifs.t4 (c1) VALUES (42); +go +SELECT @@IDENTITY; +go +SELECT IDENT_CURRENT('ident_bifs.t4'); +go + +-- Test follow-up INSERTs to the previous table +INSERT INTO ident_bifs.t3 (c1) VALUES (42); +go +SELECT @@IDENTITY; +go +SELECT IDENT_CURRENT('ident_bifs.t3'); +go +INSERT INTO ident_bifs.t3 (c1) VALUES (42); +go +SELECT @@IDENTITY; +go +SELECT IDENT_CURRENT('ident_bifs.t3'); +go + +-- Test multi-inserts +SET IDENTITY_INSERT ident_bifs.t1 ON; +go +INSERT INTO ident_bifs.t1 (id, c1) VALUES (10, 42), (9999,42), (0, 42), (-100, 42); +go +SELECT @@IDENTITY; +go +SELECT IDENT_CURRENT('ident_bifs.t1'); +go +SET IDENTITY_INSERT ident_bifs.t1 OFF; +go + +CREATE PROCEDURE ident_bifs.insertLoopT1 +AS BEGIN +DECLARE @N INT +SET @N = 1 +SET IDENTITY_INSERT ident_bifs.t1 ON +WHILE (@N < 10) +BEGIN + INSERT INTO ident_bifs.t1 (id, c1) VALUES (@N*42, 42) + SET @N = @N + 1 +END +SET IDENTITY_INSERT ident_bifs.t1 OFF +END; +go + +EXEC ident_bifs.insertLoopT1; +go +SELECT @@IDENTITY; +go +SELECT IDENT_CURRENT('ident_bifs.t1'); +go + +-- Update the last identity value as a reference +INSERT INTO ident_bifs.t2 (c1) VALUES (42); +go +SELECT @@IDENTITY; +go +SELECT IDENT_CURRENT('ident_bifs.t2'); +go + +-- Insert select and check that the last value changed to what is expected +SET IDENTITY_INSERT ident_bifs.t2 ON; +go +INSERT INTO ident_bifs.t2 (id, c1) SELECT * FROM ident_bifs.t1; +go +SELECT @@IDENTITY; +go +SELECT IDENT_CURRENT('ident_bifs.t2'); +go +SET IDENTITY_INSERT ident_bifs.t2 OFF; +go + +-- Check value of each table in the session so far +SELECT IDENT_CURRENT('ident_bifs.t1'); +go +SELECT IDENT_CURRENT('ident_bifs.t2'); +go +SELECT IDENT_CURRENT('ident_bifs.t3'); +go +SELECT IDENT_CURRENT('ident_bifs.t4'); +go + +-- Test with table in default schema +CREATE TABLE id_bifs_t1(id INT IDENTITY(64, 32), c1 INT); +go +SELECT IDENT_SEED('id_bifs_t1'); +go +SELECT IDENT_INCR('id_bifs_t1'); +go +SELECT IDENT_CURRENT('id_bifs_t1'); +go +INSERT INTO id_bifs_t1 (c1) VALUES (8); +go +SELECT IDENT_CURRENT('id_bifs_t1'); +go +SELECT @@IDENTITY; +go + +-- Test camel case +CREATE TABLE [ident_bifs].[ID_BIFs_T2](id INT IDENTITY(0, -128), c1 INT); +go +SELECT IDENT_SEED('[ident_bifs].[ID_BIFs_T2]'); +go +SELECT IDENT_INCR('[ident_bifs].[ID_BIFs_T2]'); +go +SELECT IDENT_CURRENT('[ident_bifs].[ID_BIFs_T2]'); +go +INSERT INTO [ident_bifs].[ID_BIFs_T2] (c1) VALUES (8); +go +SELECT IDENT_CURRENT('[ident_bifs].[ID_BIFs_T2]'); +go +INSERT INTO [ident_bifs].[ID_BIFs_T2] (c1) VALUES (8); +go +SELECT IDENT_CURRENT('[ident_bifs].[ID_BIFs_T2]'); +go +SELECT @@IDENTITY; +go + +-- Test faulty input +SELECT IDENT_SEED('[ident_bifs].ID_BIFs_T2'); +go +SELECT IDENT_INCR('[ident_bifs].[ID_BIFs_T2'); +go +SELECT IDENT_CURRENT('[ident_bifs].ID_BIFs_T2]'); +go +SELECT IDENT_SEED('[ident_bifs].[[ID_BIFs_T2]]'); +go +SELECT IDENT_INCR('[ident_bifs].[[ID_BIFs_T2]'); +go +SELECT IDENT_CURRENT('[ident_bifs].ID_[BIFs]_T2'); +go +SELECT IDENT_SEED(''); +go +SELECT IDENT_INCR(''); +go +SELECT IDENT_CURRENT(''); +go +SELECT IDENT_SEED(NULL); +go +SELECT IDENT_INCR(NULL); +go +SELECT IDENT_CURRENT(NULL); +go + +DROP PROC ident_bifs.insertLoopT1; +go +DROP TABLE ident_bifs.t1, ident_bifs.t2, ident_bifs.t3, ident_bifs.t4, id_bifs_t1, ident_bifs.ID_BIFs_T2; +go +DROP SCHEMA ident_bifs; +GO diff --git a/contrib/test/JDBC/input/BABEL-IDENTITY-COLUMN.sql b/contrib/test/JDBC/input/BABEL-IDENTITY-COLUMN.sql new file mode 100644 index 00000000000..55c06ff9e87 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-IDENTITY-COLUMN.sql @@ -0,0 +1,123 @@ +USE MASTER; +GO + +-- Expect an error. Test nullable identity column creation. +CREATE TABLE dbo.t1(id INT IDENTITY NULL, col1 INT); +go + +CREATE TABLE dbo.t1(id INT IDENTITY NOT NULL, col1 INT); +go + +CREATE TABLE dbo.t2(col1 INT); +go + +-- Expect an error. +ALTER TABLE dbo.t2 ADD id INT IDENTITY NULL; +go + +ALTER TABLE dbo.t2 ADD id INT IDENTITY NOT NULL; +go + +CREATE TABLE dbo.test_table1(test_id INT IDENTITY(10, -1), test_col1 INT); +go + +INSERT INTO test_table1 VALUES (2), (4), (8), (16); +go + +SELECT * FROM test_table1; +go + +CREATE TABLE dbo.test_table2(test_id INT IDENTITY(100, -20), test_col1 INT); +go + +INSERT INTO test_table2 VALUES (2), (4), (8), (16); +go + +SELECT * FROM test_table2; +go + +CREATE TABLE dbo.test_table3(test_id INT IDENTITY(-10, 5), test_col1 INT); +go + +INSERT INTO test_table3 VALUES (2), (4), (8), (16); +go + +SELECT * FROM test_table3; +go + +-- Test if TRUNCATE resets identity +INSERT INTO dbo.t1 VALUES (2), (4), (8), (16); +go + +SELECT * FROM dbo.t1; +go + +TRUNCATE TABLE dbo.t1; +GO + +INSERT INTO dbo.t1 VALUES (2), (4), (8), (16); +go + +SELECT * FROM dbo.t1; +go + +TRUNCATE TABLE test_table1; +go + +SELECT * FROM test_table1; +go + +INSERT INTO test_table1 VALUES (2), (4), (8), (16); +go + +SELECT * FROM test_table1; +go + +-- Test preventing multiple identity columns +-- Expect error +CREATE TABLE dbo.t3(id1 INT IDENTITY, id2 INT IDENTITY); +GO + +-- Expect error +CREATE TABLE dbo.t3(id1 NUMERIC IDENTITY, id2 INT IDENTITY, id3 DECIMAL IDENTITY); +GO + +CREATE TABLE dbo.t3(id1 INT IDENTITY, c1 INT); +GO + +-- Expect error +ALTER TABLE dbo.t3 ADD id2 INT IDENTITY; +GO + +ALTER TABLE dbo.t3 DROP COLUMN id1; +GO + +ALTER TABLE dbo.t3 ADD id1 INT IDENTITY; +GO + +-- Expect error +ALTER TABLE dbo.t3 ADD id2 INT IDENTITY; +GO + +CREATE TABLE dbo.t4(c1 INT); +GO + +ALTER TABLE dbo.t4 ADD id2 SMALLINT IDENTITY; +GO + +-- Expect error +ALTER TABLE dbo.t4 ADD id3 BIGINT IDENTITY; +GO + +ALTER TABLE dbo.t4 DROP COLUMN id2; +GO + +ALTER TABLE dbo.t4 ADD id2 SMALLINT IDENTITY; +GO + +-- Expect error +ALTER TABLE dbo.t4 ADD id3 BIGINT IDENTITY; +GO + +DROP TABLE dbo.t1, dbo.t2, dbo.t3, dbo.t4, dbo.test_table1, dbo.test_table2, dbo.test_table3; +GO diff --git a/contrib/test/JDBC/input/BABEL-IDENTITY.sql b/contrib/test/JDBC/input/BABEL-IDENTITY.sql new file mode 100644 index 00000000000..bb05f5bc965 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-IDENTITY.sql @@ -0,0 +1,270 @@ +USE MASTER; +GO + +CREATE TABLE dbo.test_table1 (test_id INT IDENTITY, test_col1 INT); +go + +CREATE PROCEDURE insert_test_table1 + @id INT, + @val INT +AS + INSERT INTO dbo.test_table1 (test_id, test_col1) VALUES (@id, @val); +go + +SELECT @@IDENTITY; +go +SELECT SCOPE_IDENTITY(); +go +INSERT INTO dbo.test_table1 (test_col1) VALUES (10); +go +SELECT @@IDENTITY; +go +SELECT SCOPE_IDENTITY(); +go +SELECT @@SERVERNAME; +go +-- Expect an error +INSERT INTO dbo.test_table1 (test_id, test_col1) VALUES (2, 10); +go + +SET IDENTITY_INSERT dbo.test_table1 ON; +go + +-- Test custom insert +EXECUTE insert_test_table1 2, 10; +go + +-- Insert a non-sequential max identity value +EXECUTE insert_test_table1 10, 10; +go + +-- Insert a lesser identity value +EXECUTE insert_test_table1 5, 10; +go + +-- Set to off. Notice we're not specifying the schema this time +SET IDENTITY_INSERT test_table1 OFF; +go + +-- Verify the identity sequence value is updated to the max value +INSERT INTO dbo.test_table1 (test_col1) VALUES (11); +go +INSERT INTO dbo.test_table1 (test_col1) VALUES (12); +go + +SELECT * FROM dbo.test_table1; +go + +-- Expect an error. Verify IDENTITY_INSERT set off +INSERT INTO dbo.test_table1 (test_id, test_col1) VALUES (2, 10); +go + +-- Set to table then drop it. Should implicitly turn IDENTITY_INSERT off +SET IDENTITY_INSERT dbo.test_table1 ON; +go +DROP TABLE test_table1; +go + +-- Create a table with the same name +CREATE TABLE dbo.test_table1 (test_id INT IDENTITY, test_col1 INT); +go + +-- Try to insert. Expect an error. Same name but different OID +INSERT INTO dbo.test_table1 (test_id, test_col1) VALUES (2, 10); +go + +-- Expect errors +SET IDENTITY_INSERT test_table2 ON; +go +SET IDENTITY_INSERT fake_schema.test_table1 ON; +go +SET IDENTITY_INSERT fake_db.dbo.test_table1 ON; +go + +CREATE TABLE dbo.test_table2 (test_id INT IDENTITY(7,2), test_col1 INT); +go + +-- Expect error. Set IDENTITY_INSERT to a table then try setting it to another +SET IDENTITY_INSERT dbo.test_table1 ON; +go +SET IDENTITY_INSERT dbo.test_table2 ON; +go +SET IDENTITY_INSERT dbo.test_table1 OFF; +go +INSERT INTO dbo.test_table2 (test_col1) VALUES (13); +go +INSERT INTO dbo.test_table2 (test_col1) VALUES (108); +go +SELECT @@IDENTITY; +go +SELECT SCOPE_IDENTITY(); +go + +SELECT * FROM dbo.test_table2; +go + +-- Expect error. Cannot set IDENTITY_INSERT to table without identity property +CREATE TABLE dbo.test_table3 (test_id INT, test_col1 INT); +go + +SET IDENTITY_INSERT dbo.test_table3 ON; +go + +-- Test INSERT with default target list that omits identity columns +CREATE TABLE dbo.employees +(person_id int IDENTITY PRIMARY KEY, firstname nvarchar(20), lastname nvarchar(30), salary money); +go + +INSERT INTO employees VALUES (N'Neil', N'Armstrong', 11236.9898); +go + +SELECT * FROM dbo.employees; +go + +-- Test identity insert with multiple columns +SET IDENTITY_INSERT dbo.employees ON; +go + +CREATE PROCEDURE insert_employees + @id INT, + @first TEXT, + @last TEXT, + @salary NUMERIC(18,4) +AS + INSERT INTO dbo.employees (person_id, firstname, lastname, salary) VALUES (@id, @first, @last, @salary); +go + +EXEC insert_employees 5, N'Buzz', N'Aldrin', 11236.9898; +go + +SELECT @@IDENTITY; +go + +-- Expect Errors. Cannot insert without explicit identity column value +INSERT INTO employees VALUES (N'Michael', N'Collins', 11236.9898); +go + +INSERT INTO employees (firstname, lastname, salary) VALUES (N'Michael', N'Collins', 11236.9898); +go + +SET IDENTITY_INSERT dbo.employees OFF; +go + +INSERT INTO employees VALUES (N'Michael', N'Collins', 11236.9898); +go + +SELECT * FROM dbo.employees; +go + +-- Test Camel Case +CREATE TABLE [dbo].[Test_Table1]([Test_Id] INT IDENTITY, test_col1 INT); +go + +SET IDENTITY_INSERT [Test_Table1] ON; +go + +CREATE PROCEDURE insert_test_table_c + @id INT, + @val INT +AS + INSERT INTO [dbo].[Test_Table1] ([Test_Id], test_col1) VALUES (@id, @val); +go + +CREATE PROCEDURE insert_test_table_c_default + @val INT +AS + INSERT INTO [dbo].[Test_Table1] (test_col1) VALUES (@val); +go + +EXEC insert_test_table_c 1, 10; +go + +EXEC insert_test_table_c 5, 20; +go + +-- Expect error. Insert restriction +EXEC insert_test_table_c_default 30; +go +-- Expect errors. Not matching case +SET IDENTITY_INSERT Test_Table1 ON; +go +SET IDENTITY_INSERT [tEst_tAble1] ON; +go +SET IDENTITY_INSERT [dbo].[Test_Table1] ON; +go +INSERT INTO [dbo].[Test_Table1] (test_id, test_col1) VALUES (10, 30); +go + +-- Set to off and verify table +SET IDENTITY_INSERT [dbo].[Test_Table1] OFF; +go + +EXEC insert_test_table_c_default 30; +go + +SELECT * FROM [Test_Table1]; +go + +-- Test updating negative increment +CREATE TABLE dbo.t_neg_inc_1(id INT IDENTITY(1, -1), col1 INT); +go + +CREATE PROCEDURE insert_default_neg_inc_1 + @val INT +AS BEGIN + INSERT INTO dbo.t_neg_inc_1(col1) VALUES (@val); +END; +go + +CREATE PROCEDURE insert_id_neg_inc_1 + @id INT, + @val INT +AS BEGIN + SET IDENTITY_INSERT t_neg_inc_1 ON; + INSERT INTO dbo.t_neg_inc_1(id, col1) VALUES (@id, @val); + SET IDENTITY_INSERT t_neg_inc_1 OFF; +END; +go + +EXEC insert_default_neg_inc_1 10; +go + +EXEC insert_default_neg_inc_1 20; +go + +EXEC insert_id_neg_inc_1 -5, 30; +go + +EXEC insert_default_neg_inc_1 40; +go + +EXEC insert_id_neg_inc_1 5, 50; +go + +EXEC insert_default_neg_inc_1 60; +go + +SELECT * FROM t_neg_inc_1; +go + +-- Test get id max/min helper functions +SELECT sys.get_min_id_from_table(';drop table master_dbo.test_table1;', 'master_dbo', 'test_table1'); +GO + +SELECT sys.get_max_id_from_table('test_id', ';drop table master_dbo', 'test_table1;'); +GO + +-- Clean up +DROP PROCEDURE insert_test_table1, +insert_employees, +insert_test_table_c, +insert_test_table_c_default, +insert_default_neg_inc_1, +insert_id_neg_inc_1; +go +DROP TABLE dbo.test_table1, +dbo.test_table2, +dbo.test_table3, +dbo.employees, +dbo.t_neg_inc_1; +go diff --git a/contrib/test/JDBC/input/BABEL-IMPLICIT_TRAN-PREPEXEC.txt b/contrib/test/JDBC/input/BABEL-IMPLICIT_TRAN-PREPEXEC.txt new file mode 100644 index 00000000000..d01c429277e --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-IMPLICIT_TRAN-PREPEXEC.txt @@ -0,0 +1,40 @@ +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_unique_constraint', 'ignore'; +CREATE TABLE impl_txn_prepexec_table (a varchar(15) UNIQUE, b nvarchar(25), c int PRIMARY KEY, d char(15) DEFAULT 'Whoops!', e nchar(25), f datetime, g numeric(4,1) CHECK (g >= 103.5)) + +prepst#!#INSERT INTO impl_txn_prepexec_table VALUES (@a, @b, @c, @d, @e, @f, @g)#!#varchar|-|a|-|Apple#!#nvarchar|-|b|-|red#!#int|-|c|-|1#!#char|-|d|-|Delhi#!#nchar|-|e|-|Sad😞#!#datetime|-|f|-|2000-12-13 12:58:23.123#!#numeric|-|g|-|123.1|-|4|-|1 + +SET IMPLICIT_TRANSACTIONS ON + +SELECT @@TRANCOUNT +prepst#!#SELECT * FROM impl_txn_prepexec_table WHERE a = @p1 AND b = @p2 AND c = @p3#!#varchar|-|p1|-|Apple#!#nvarchar|-|p2|-|red#!#int|-|p3|-|1 +SELECT @@TRANCOUNT +IF @@TRANCOUNT > 0 COMMIT + +SELECT @@TRANCOUNT +prepst#!#exec#!#varchar|-|p1|-|Apple#!#nvarchar|-|p2|-|red#!#int|-|p3|-|2 +SELECT @@TRANCOUNT +IF @@TRANCOUNT > 0 COMMIT + +SELECT @@TRANCOUNT +prepst#!#exec#!#varchar|-|p1|-|Apple#!#nvarchar|-|p2|-|green#!#int|-|p3|-|1 +SELECT @@TRANCOUNT +IF @@TRANCOUNT > 0 COMMIT + +SELECT @@TRANCOUNT +prepst#!#SELECT 12, 34, 56 FROM (SELECT * FROM impl_txn_prepexec_table WHERE a = @p1 AND b = @p2 AND c = @p3) AS dummy_table#!#varchar|-|p1|-|Apple#!#nvarchar|-|p2|-|red#!#int|-|p3|-|1 +SELECT @@TRANCOUNT +IF @@TRANCOUNT > 0 COMMIT + +SELECT @@TRANCOUNT +prepst#!#exec#!#varchar|-|p1|-|Apple#!#nvarchar|-|p2|-|red#!#int|-|p3|-|2 +SELECT @@TRANCOUNT +IF @@TRANCOUNT > 0 COMMIT + +SELECT @@TRANCOUNT +prepst#!#exec#!#varchar|-|p1|-|Apple#!#nvarchar|-|p2|-|green#!#int|-|p3|-|1 +SELECT @@TRANCOUNT +IF @@TRANCOUNT > 0 COMMIT + +SET IMPLICIT_TRANSACTIONS OFF +DROP TABLE impl_txn_prepexec_table +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_unique_constraint', 'strict'; diff --git a/contrib/test/JDBC/input/BABEL-IMPLICIT_TRAN.sql b/contrib/test/JDBC/input/BABEL-IMPLICIT_TRAN.sql new file mode 100644 index 00000000000..3f56ac6daeb --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-IMPLICIT_TRAN.sql @@ -0,0 +1,232 @@ +-- Setup +CREATE TABLE implicit_tran_table (a int) +GO + +INSERT INTO implicit_tran_table VALUES (10) +GO + +SET IMPLICIT_TRANSACTIONS ON +GO + +-- Select from table should start implicit transaction +SELECT @@TRANCOUNT +SELECT * FROM implicit_tran_table +SELECT @@TRANCOUNT +IF @@TRANCOUNT > 0 COMMIT +GO + +SELECT @@TRANCOUNT +DECLARE @implicit_tran_table_var int +SELECT @implicit_tran_table_var = a FROM implicit_tran_table +SELECT @@TRANCOUNT +IF @@TRANCOUNT > 0 COMMIT +GO + +-- Select from table variable should start implicit transaction +SELECT @@TRANCOUNT +DECLARE @implicit_tran_table_var TABLE (col1 VARCHAR(10)); +SELECT * FROM @implicit_tran_table_var +SELECT @@TRANCOUNT +IF @@TRANCOUNT > 0 COMMIT +GO + +-- Select not from a table should not start implicit transaction +SELECT @@TRANCOUNT +SELECT 123 +SELECT @@TRANCOUNT +IF @@TRANCOUNT > 0 COMMIT +GO + +SELECT @@TRANCOUNT +DECLARE @implicit_tran_table_var int +SELECT @implicit_tran_table_var = 1234 +SELECT @@TRANCOUNT +IF @@TRANCOUNT > 0 COMMIT +GO + +-- BABEL-1869 +-- 2-Column select should not start implicit transaction +SELECT @@TRANCOUNT +SELECT 1, 2 +SELECT @@TRANCOUNT +IF @@TRANCOUNT > 0 COMMIT +GO + +SELECT @@TRANCOUNT +SELECT 1, 2, 3 +SELECT @@TRANCOUNT +IF @@TRANCOUNT > 0 COMMIT +GO + +-- Select from table in subquery should start implicit transaction +SELECT @@TRANCOUNT +SELECT (select count(*) from implicit_tran_table) +SELECT @@TRANCOUNT +IF @@TRANCOUNT > 0 COMMIT +GO + +SELECT @@TRANCOUNT +SELECT 1, 2 FROM (SELECT * FROM implicit_tran_table) as dummy_table +SELECT @@TRANCOUNT +IF @@TRANCOUNT > 0 COMMIT +GO + +-- Select to call a function should not start implicit transaction +SELECT @@TRANCOUNT +SELECT @@ERROR +SELECT @@TRANCOUNT +IF @@TRANCOUNT > 0 COMMIT +GO + +/* + * DMLs should start implicit transaction + * Note: Did not add test for MERGE since + * we do not support it (BABEL-877) + */ +SELECT @@TRANCOUNT +INSERT INTO implicit_tran_table VALUES (11) +SELECT @@TRANCOUNT +IF @@TRANCOUNT > 0 COMMIT +GO + +SELECT @@TRANCOUNT +UPDATE implicit_tran_table SET a = 100 WHERE a = 10 +SELECT @@TRANCOUNT +IF @@TRANCOUNT > 0 COMMIT +GO + +SELECT @@TRANCOUNT +DELETE FROM implicit_tran_table WHERE a = 100 +SELECT @@TRANCOUNT +IF @@TRANCOUNT > 0 COMMIT +GO + +-- Create table should start implicit transaction +SELECT @@TRANCOUNT +CREATE TABLE implicit_tran_table2 (c smallint) +SELECT @@TRANCOUNT +IF @@TRANCOUNT > 0 COMMIT +GO + +-- BABEL-1870 +-- SELECT ... INTO should start implicit transaction +-- Note: We internally convert this to CREATE TABLE AS +SELECT @@TRANCOUNT +SELECT * INTO dummy_table FROM implicit_tran_table2 +SELECT @@TRANCOUNT +DROP TABLE dummy_table +IF @@TRANCOUNT > 0 COMMIT +GO + +-- Alter table should start implicit transaction +SELECT @@TRANCOUNT; +ALTER TABLE implicit_tran_table2 ADD CONSTRAINT default_c DEFAULT 99 FOR c +SELECT @@TRANCOUNT; +IF @@TRANCOUNT > 0 COMMIT +GO + +-- truncate table should start implicit transaction +SELECT @@TRANCOUNT +TRUNCATE TABLE implicit_tran_table2 +SELECT @@TRANCOUNT +IF @@TRANCOUNT > 0 COMMIT +GO + +-- Drop table should start implicit transaction +SELECT @@TRANCOUNT +DROP TABLE implicit_tran_table2 +SELECT @@TRANCOUNT +IF @@TRANCOUNT > 0 COMMIT +GO + +-- Create procedure should start implicit transaction +SELECT @@TRANCOUNT +GO +CREATE PROCEDURE implicit_tran_proc + AS + BEGIN + SELECT 'Select inside a procedure' + END +GO +SELECT @@TRANCOUNT +IF @@TRANCOUNT > 0 COMMIT +GO + +/* + * Alter procedure should start implicit transaction + * Note: Did not add test for ALTER PROCEDURE since + * we do not support it (BABEL-442) + */ + + +-- Drop procedure should start implicit transaction +SELECT @@TRANCOUNT +DROP PROCEDURE implicit_tran_proc +SELECT @@TRANCOUNT +IF @@TRANCOUNT > 0 COMMIT +GO + +-- Begin transaction should start implicit transaction +SELECT @@TRANCOUNT +BEGIN TRANSACTION +SELECT @@TRANCOUNT +IF @@TRANCOUNT > 0 COMMIT +IF @@TRANCOUNT > 0 COMMIT +GO + +-- Create database should not start implicit transaction +SELECT @@TRANCOUNT +CREATE DATABASE implicit_tran_db +SELECT @@TRANCOUNT +IF @@TRANCOUNT > 0 COMMIT +GO + +-- Drop database should not start implicit transaction +SELECT @@TRANCOUNT +DROP DATABASE implicit_tran_db +SELECT @@TRANCOUNT +IF @@TRANCOUNT > 0 COMMIT +GO + +/* + * Declare cursor should start an implicit transaction + */ +SELECT @@TRANCOUNT; +DECLARE implicit_tran_cursor CURSOR FOR SELECT * FROM implicit_tran_table; +SELECT @@TRANCOUNT; +DEALLOCATE implicit_tran_cursor; +IF @@TRANCOUNT > 0 COMMIT; +GO + +SELECT @@TRANCOUNT; +DECLARE implicit_tran_cursor CURSOR FOR SELECT 9876; +SELECT @@TRANCOUNT; +DEALLOCATE implicit_tran_cursor; +GO + +-- Open and fetch should start implicit transaction +-- Close and deallocate should not start implicit transaction +DECLARE implicit_tran_cursor CURSOR FOR SELECT * FROM implicit_tran_table; +DECLARE @val INT; +IF @@TRANCOUNT > 0 COMMIT; +SELECT @@TRANCOUNT; +OPEN implicit_tran_cursor; +SELECT @@TRANCOUNT; +IF @@TRANCOUNT > 0 COMMIT; +SELECT @@TRANCOUNT; +FETCH FROM implicit_tran_cursor INTO @val; +SELECT @@TRANCOUNT; +IF @@TRANCOUNT > 0 COMMIT; +SELECT @@TRANCOUNT; +CLOSE implicit_tran_cursor; +SELECT @@TRANCOUNT; +DEALLOCATE implicit_tran_cursor; +SELECT @@TRANCOUNT; +GO + +-- Cleanup +SET IMPLICIT_TRANSACTIONS OFF +GO + +DROP TABLE implicit_tran_table +GO diff --git a/contrib/test/JDBC/input/BABEL-INSERT-EXECUTE.sql b/contrib/test/JDBC/input/BABEL-INSERT-EXECUTE.sql new file mode 100644 index 00000000000..dce94d8d521 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-INSERT-EXECUTE.sql @@ -0,0 +1,272 @@ +create table t1 (a int); +GO +insert into t1 values (1); +GO +create table t2 (a int); +GO + +-- procedure with SELECT +create procedure sp_multi_selects as +select * from t1; +select a from t1; +go +-- normal execute +execute sp_multi_selects; +go +-- insert execute +select * from t2; +go +insert into t2 execute sp_multi_selects; +go +select * from t2; +go +-- insert execute a second time +insert into t2 execute sp_multi_selects; +go +select * from t2; +go + +-- column mismatch +create table t3(a int, b int, c int); +GO +insert into t3 execute sp_multi_selects; +GO +select * from t3; +GO +-- INSERT with matching column list +insert into t3 (a) execute sp_multi_selects; +GO +select * from t3; +GO + +-- DML statements in procedure +create procedure sp_dml_select as +insert into t1 values(2); +update t1 set a = 3 where a = 2; +delete t1 where a = 3; +select * from t1; +GO +select * from t1; +GO +-- normal EXECUTE - each DML should send result to client +execute sp_dml_select; +GO +-- INSERT EXECUTE - only final INSERT should send result to client +insert into t2 execute sp_dml_select; +GO + +-- DDL statements in procedure +create procedure sp_ddl_select as +create table sp_ddl_select_table(c int); +select * from sp_ddl_select_table; +drop table sp_ddl_select_table; +GO +-- normal EXECUTE +execute sp_ddl_select; +GO +-- INSERT EXECUTE +insert into t2 execute sp_ddl_select; +GO + +-- test using OUTPUT clause in INSERT EXECUTE +insert into t2 output inserted.* into t3.a exec sp_multi_selects; +GO + +-- COMMIT with no BEGIN TRAN +create procedure sp_commit_no_begin as +insert into t1 values(3); +commit; +select * from t1; +GO +-- normal EXECUTE - should insert into t1 +select * from t1; +GO +execute sp_commit_no_begin; +GO +select * from t1; +GO +-- INSERT EXECUTE - should not insert into t1 or t2 +select * from t2; +GO +insert into t2 execute sp_commit_no_begin; +GO +select * from t1; +GO +select * from t2; +GO +-- more COMMIT than BEGIN TRAN +create procedure sp_commits_begin as +begin tran +insert into t1 values(3); +commit; +commit; +select * from t1; +go +-- normal EXECUTE - should insert into t1 +execute sp_commits_begin; +GO +select * from t1; +GO +-- INSERT EXECUTE - should not insert into t1 or t2 +insert into t2 execute sp_commits_begin; +GO +select * from t1; +GO +select * from t2; +GO + +-- ROLLBACK stmt is not allowed in INSERT EXEC, whether there is BEGIN TRAN or +-- not. +-- ROLLBACK with no BEGIN TRAN +create procedure sp_rollback_no_begin as +insert into t1 values(4); +rollback; +select * from t1; +GO +-- normal EXECUTE - should insert into t1 +execute sp_rollback_no_begin +GO +select * from t1; +GO +-- INSERT EXECUTE - should not insert into t1 or t2 +select * from t2; +GO +insert into t2 execute sp_rollback_no_begin; +GO +select * from t1; +GO +select * from t2; +GO +-- ROLLBACK with BEGIN TRAN +create procedure sp_rollback_with_begin as +begin tran; +insert into t1 values(4); +rollback; +select * from t1; +go +-- normal EXECUTE - should insert into t1 and rollback +execute sp_rollback_with_begin +GO +select * from t1; +GO +-- INSERT EXECUTE - should not insert into t1 or t2 +select * from t2; +GO +insert into t2 execute sp_rollback_with_begin; +GO +select * from t1; +GO +select * from t2; +GO + +-- column mismatch with previous DML - should not insert into t1 or t2 +create procedure sp_select_mismatch_with_dml as +insert into t1 values(5); +select a, a from t1; +GO +select * from t1; +GO +select * from t2; +GO +insert into t2 execute sp_select_mismatch_with_dml +go +select * from t1; +GO +select * from t2; +GO + +-- column mismatch with previous DML in subtransaction - should not insert into +-- t1 or t2 +create procedure sp_select_mismatch_after_subtran as +begin tran; +insert into t1 values(6); +commit; +select a, a from t1; +GO +select * from t1; +GO +select * from t2; +GO +insert into t2 execute sp_select_mismatch_after_subtran; +GO +select * from t1; +GO +select * from t2; +GO + +-- procedure with parameter +create procedure sp_select_param (@a int) as +select * from t1 where a = @a; +GO +insert into t1 values (2); +GO +select * from t1; +GO +-- normal EXECUTE +execute sp_select_param 1; +go +select * from t2; +GO +-- INSERT EXECUTE +insert into t2 execute sp_select_param 1; +GO +select * from t2; +GO + +-- test if PL parser correctly recognizes whether EXECUTE starts a new statement +-- or not +-- INSERT has VALUES - EXEC should start a new statement +insert into t1 values(7) +exec sp_multi_selects +go +-- INSERT has SELECT - EXEC should start a new statement +insert into t2 values(8) +insert into t1 select * from t2 where a = 8 +exec sp_multi_selects +go +-- INSERT has EXEC - SELECT should start a new statement +insert into t2 exec sp_multi_selects +select * from t1 +go + +-- test INSERT EXEC with inline code blocks +delete t1; +go +insert into t1 exec('select 1; select 2'); +go +select * from t1; +go +-- test INSERT EXEC with inline code blocks on table variable +declare @a table (a int); +insert into @a execute('select * from t1; select 3'); +select * from @a; +go + +-- clean up +drop table t1 +go +drop table t2 +go +drop table t3 +go +drop procedure sp_multi_selects +go +drop procedure sp_dml_select +go +drop procedure sp_ddl_select +go +drop procedure sp_commit_no_begin +go +drop procedure sp_commits_begin +go +drop procedure sp_rollback_no_begin +go +drop procedure sp_rollback_with_begin +go +drop procedure sp_select_mismatch_with_dml +go +-- drop savepoint +drop procedure sp_select_mismatch_after_subtran +go +drop procedure sp_select_param +go diff --git a/contrib/test/JDBC/input/BABEL-LIKE2ILIKE.sql b/contrib/test/JDBC/input/BABEL-LIKE2ILIKE.sql new file mode 100644 index 00000000000..697a6ada2d2 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-LIKE2ILIKE.sql @@ -0,0 +1,96 @@ +-- test LIKE to ILIKE transformation +create table like_tesing1 (c1 varchar(20), c2 char(20), c3 nvarchar(20)) +GO +insert into like_tesing1 values ('JONES','JONES','JONES') +GO +insert into like_tesing1 values ('JoneS','JoneS','JoneS') +GO +insert into like_tesing1 values ('jOnes','jOnes','jOnes') +GO +insert into like_tesing1 values ('abcD','AbcD','ABCd') +GO +insert into like_tesing1 values ('äbĆD','äḃcD','äƀCd') +GO +-- test that like is case-insenstive +select c1 from like_tesing1 where c1 LIKE 'jones' +GO +select c1 from like_tesing1 where c1 LIKE 'Jon%' +GO +select c1 from like_tesing1 where c1 LIKE 'jone_' +GO +select c1 from like_tesing1 where c1 LIKE '_one_' +GO +-- test that like is accent-senstive for CI_AS collation +select c1 from like_tesing1 where c1 LIKE 'ab%' +GO +select c1 from like_tesing1 where c1 LIKE 'äb%' +GO +select c1 from like_tesing1 where c1 LIKE 'äḃĆ_' +GO +-- test not like +select c1 from like_tesing1 where c1 NOT LIKE 'jones' +GO +select c1 from like_tesing1 where c1 NOT LIKE 'jone%' +GO +-- wild card literals are transformed to equal +select c1 from like_tesing1 where c1 LIKE '\%ones' +GO +select c1 from like_tesing1 where c1 LIKE '\_ones' +GO +-- test combining with other string functions +select c1 from like_tesing1 where c1 LIKE lower('_ones') +GO +select c1 from like_tesing1 where c1 LIKE upper('_ones') +GO +select c1 from like_tesing1 where c1 LIKE concat('_on','_s') +GO +select c1 from like_tesing1 where c1 LIKE concat('a','%d') +GO +select c1 from like_tesing1 where c1 NOT LIKE lower('%s') +GO +-- test sub-queries +Select count(*) from like_tesing1 where c1 LIKE (select c1 from like_tesing1 where c1 LIKE 'AbcD') +GO +Select count(*) from like_tesing1 where c2 NOT LIKE (select c2 from like_tesing1 where c2 NOT LIKE 'jo%' AND c2 NOT LIKE 'ä%') +GO +Select count(*) from like_tesing1 where c3 LIKE (select c3 from like_tesing1 where c3 NOT LIKE'jo%' AND c3 NOT LIKE 'ä%') +GO +with p1 as (select c1 from like_tesing1 where c1 LIKE '__Ć_'), +p2 as (select c3 from like_tesing1 where c3 LIKE 'äƀ__') +select * from p1 union all select * from p2 +GO +-- test case expression +select c1,(case when c1 LIKE 'j%' then 1 when c1 NOT LIKE 'j%' then 2 end) from like_tesing1 +GO +-- test that LIKE transformation is only applied for SQL_LATIN1_GENERAL_CI_AS column +create table like_tesing2(c1 varchar(20) COLLATE SQL_Latin1_General_CP1_CS_AS) +GO +insert into like_tesing2 values ('JONES') +GO +insert into like_tesing2 values ('JoneS') +GO +insert into like_tesing2 values ('abcD') +GO +insert into like_tesing2 values ('äbĆD') +GO +select * from like_tesing2 where c1 LIKE 'jo%' +GO +select * from like_tesing2 where c1 NOT LIKE 'j%' +GO +select * from like_tesing2 where c1 LIKE 'AB%' +GO +-- test eplicitly specify collation as CI_AS, like transformation is also applied. +SELECT CASE WHEN 'JONES' like 'jo%' THEN 1 ELSE 0 END +GO +SELECT CASE WHEN 'JONES' COLLATE SQL_Latin1_General_CP1_CI_AS like 'jo%' THEN 1 ELSE 0 END +GO +-- test when pattern is NULL +SELECT CASE WHEN 'JONES' like '' THEN 1 ELSE 0 END +GO +SELECT * from like_tesing1 where c1 like '' +GO + +drop table like_tesing1 +GO +drop table like_tesing2 +GO diff --git a/contrib/test/JDBC/input/BABEL-LOGIN-USER-EXT.mix b/contrib/test/JDBC/input/BABEL-LOGIN-USER-EXT.mix new file mode 100644 index 00000000000..812034f3ab4 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-LOGIN-USER-EXT.mix @@ -0,0 +1,289 @@ +-- psql +ALTER SYSTEM SET babelfishpg_tsql.allow_antlr_to_unsupported_grammar_for_testing = true; +SELECT pg_reload_conf(); +CREATE USER foo WITH LOGIN PASSWORD 'abc'; +CREATE USER su_user WITH SUPERUSER LOGIN PASSWORD 'abc'; +GO + +-- tsql user=foo password=abc +-- Login with non babelfish user should fail +go + +-- Login with a superuser should succeed +-- tsql user=su_user password=abc +SELECT 1; +go + +-- psql +DROP USER IF EXISTS foo; +DROP USER IF EXISTS su_user; +go + +-- Create Login through tsql +-- tsql +CREATE LOGIN r1 WITH PASSWORD = 'abc'; +go + +-- Login with a Babelfish user should succeed +-- tsql user=r1 password=abc +SELECT 1; +go + +-- tsql +DROP LOGIN r1; +go +-- Test initialization +SELECT COUNT(*) FROM sys.babelfish_authid_login_ext; +go + +CREATE LOGIN r1 WITH PASSWORD = 'abc'; +go + +SELECT COUNT(*) FROM sys.babelfish_authid_login_ext; +go + +-- Test initialization with password +CREATE LOGIN r2 WITH PASSWORD = '123' +go + +SELECT COUNT(*) FROM sys.babelfish_authid_login_ext; +go + +-- Test altering the login ability +SELECT rolcanlogin FROM pg_catalog.pg_roles WHERE rolname = 'r1'; +go +SELECT name, is_disabled FROM sys.server_principals WHERE name = 'r1'; +go + +ALTER LOGIN r1 disable; +go + +SELECT rolcanlogin FROM pg_catalog.pg_roles WHERE rolname = 'r1'; +go +SELECT name, is_disabled FROM sys.server_principals WHERE name = 'r1'; +go + +ALTER LOGIN r1 enable; +go + +SELECT rolcanlogin FROM pg_catalog.pg_roles WHERE rolname = 'r1'; +go +SELECT name, is_disabled FROM sys.server_principals WHERE name = 'r1'; +go + +-- Test altering the password +ALTER LOGIN r2 WITH PASSWORD = '456' +go + +-- Test dropping +DROP LOGIN r1; +go + +SELECT COUNT(*) FROM sys.babelfish_authid_login_ext; +go + +DROP LOGIN r2; +go + +SELECT COUNT(*) FROM sys.babelfish_authid_login_ext; +go + +-- Test membership +CREATE LOGIN r3 WITH PASSWORD = '789'; +GO + +SELECT COUNT(*) FROM pg_auth_members +WHERE roleid = (SELECT oid FROM pg_roles WHERE rolname = 'sysadmin') +AND "member" = (SELECT oid FROM pg_roles WHERE rolname = 'r3'); +GO + +ALTER SERVER ROLE sysadmin ADD MEMBER r3; +GO + +SELECT COUNT(*) FROM pg_auth_members +WHERE roleid = (SELECT oid FROM pg_roles WHERE rolname = 'sysadmin') +AND "member" = (SELECT oid FROM pg_roles WHERE rolname = 'r3'); +GO + +ALTER SERVER ROLE sysadmin DROP MEMBER r3; +GO + +SELECT COUNT(*) FROM pg_auth_members +WHERE roleid = (SELECT oid FROM pg_roles WHERE rolname = 'sysadmin') +AND "member" = (SELECT oid FROM pg_roles WHERE rolname = 'r3'); +GO + +DROP LOGIN r3; +GO + +-- Test error cases +ALTER SERVER ROLE db_owner ADD MEMBER dummy; +GO + +ALTER SERVER ROLE db_owner DROP MEMBER dummy; +GO + +-- Test CREATE User +CREATE USER user1; +GO + +-- Test User functions +USE MASTER; +GO + +SELECT user_name(); +GO + +SELECT user_name(user_id()); +GO + +SELECT user_name(user_id('guest')); +GO + +SELECT rolname FROM pg_roles WHERE oid = user_id('dbo'); +GO + +SELECT rolname FROM pg_roles WHERE oid = user_id('guest'); +GO + +USE TEMPDB; +GO + +SELECT user_name(); +GO + +SELECT user_name(user_id()); +GO + +SELECT user_name(user_id('guest')); +GO + +SELECT rolname FROM pg_roles WHERE oid = user_id('dbo'); +GO + +SELECT rolname FROM pg_roles WHERE oid = user_id('guest'); +GO + +CREATE DATABASE db1; +GO + +USE db1; +GO + +SELECT user_name(); +GO + +SELECT user_name(user_id()); +GO + +SELECT user_name(user_id('guest')); +GO + +SELECT rolname FROM pg_roles WHERE oid = user_id('dbo'); +GO + +SELECT rolname FROM pg_roles WHERE oid = user_id('guest'); +GO + +-- Expect NULL +SELECT user_name(-1); +GO + +SELECT user_id('master_dbo'); +GO + +-- Test Login functions +CREATE LOGIN login1 WITH PASSWORD = '456'; +GO + +SELECT name FROM sys.server_principals WHERE principal_id = suser_id('login1'); +GO + +SELECT name FROM sys.server_principals WHERE name = suser_name(suser_id('login1')); +GO + +-- Expect NULL +SELECT suser_name(-1); +GO + +USE MASTER; +GO + +DROP DATABASE db1; +GO + +DROP LOGIN login1; +GO + +-- psql +ALTER SYSTEM SET babelfishpg_tsql.migration_mode = 'multi-db'; +SELECT pg_reload_conf(); +GO + +-- tsql +-- Test multi-db mode +USE master; +GO + +CREATE DATABASE db1; +GO + +CREATE DATABASE db2; +GO + +USE db1; +GO + +SELECT user_name(user_id('dbo')); +GO + +SELECT user_name(user_id('guest')); +GO + +SELECT rolname FROM pg_roles WHERE oid = user_id('dbo'); +GO + +SELECT rolname FROM pg_roles WHERE oid = user_id('guest'); +GO + +USE db2; +GO + +SELECT user_name(user_id('dbo')); +GO + +SELECT user_name(user_id('guest')); +GO + +SELECT rolname FROM pg_roles WHERE oid = user_id('dbo'); +GO + +SELECT rolname FROM pg_roles WHERE oid = user_id('guest'); +GO + +USE MASTER; +GO + +SELECT user_name(user_id('dbo')); +GO + +SELECT user_name(user_id('guest')); +GO + +SELECT rolname FROM pg_roles WHERE oid = user_id('dbo'); +GO + +SELECT rolname FROM pg_roles WHERE oid = user_id('guest'); +GO + +DROP DATABASE db1; +GO + +DROP DATABASE db2; +GO + +-- psql +ALTER SYSTEM SET babelfishpg_tsql.migration_mode = 'single-db'; +ALTER SYSTEM SET babelfishpg_tsql.allow_antlr_to_unsupported_grammar_for_testing = false; +SELECT pg_reload_conf(); +GO diff --git a/contrib/test/JDBC/input/BABEL-OBJECT-FUNCTIONS.sql b/contrib/test/JDBC/input/BABEL-OBJECT-FUNCTIONS.sql new file mode 100644 index 00000000000..4818499e54b --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-OBJECT-FUNCTIONS.sql @@ -0,0 +1,25 @@ +CREATE SCHEMA obj_funcs; +GO + +CREATE TABLE obj_funcs.t1(id INT, c1 NVARCHAR); +GO + +SELECT (CASE WHEN OBJECT_NAME(OBJECT_ID(N't1 ', N'U')) = 't1' THEN 'true' ELSE 'false' END) result; +GO + +SELECT (CASE WHEN OBJECT_NAME(OBJECT_ID(N' t1', N'U')) = 't1' THEN 'true' ELSE 'false' END) result; +GO + +SELECT (CASE WHEN OBJECT_NAME(OBJECT_ID(N' t1 ')) = 't1' THEN 'true' ELSE 'false' END) result; +GO + +SELECT (CASE WHEN OBJECT_NAME(OBJECT_ID(N' [t1] ', N'U')) = 't1' THEN 'true' ELSE 'false' END) result; +GO + +SELECT (CASE WHEN OBJECT_NAME(OBJECT_ID(N' [obj_funcs].[t1] ', N'U')) = 't1' THEN 'true' ELSE 'false' END) result; +GO + +DROP TABLE obj_funcs.t1; +GO +DROP SCHEMA obj_funcs; +GO diff --git a/contrib/test/JDBC/input/BABEL-PROCID.sql b/contrib/test/JDBC/input/BABEL-PROCID.sql new file mode 100644 index 00000000000..93a80d92b61 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-PROCID.sql @@ -0,0 +1,198 @@ +-- Test outside of a procedure +SELECT @@PROCID; +GO + +-- Test procedure +CREATE PROCEDURE demo_proc1 +AS +DECLARE @proc_name sysname; +DECLARE @msg varchar(100); +SET @proc_name = OBJECT_NAME(@@PROCID); +SET @msg = 'Running stored procedure ' + @proc_name + '!'; +SELECT @msg; +GO + +EXEC demo_proc1; +GO + +-- Test nested procedure +CREATE PROCEDURE demo_proc2 +AS +DECLARE @proc_name sysname; +DECLARE @msg varchar(100); +EXEC demo_proc1; +SET @proc_name = OBJECT_NAME(@@PROCID); +SET @msg = 'Running stored procedure ' + @proc_name + '!'; +SELECT @msg; +EXEC demo_proc1; +GO + +EXEC demo_proc2; +GO + +DROP PROCEDURE demo_proc2; +GO + +-- Test UDF function +CREATE FUNCTION demo_func1() +RETURNS varchar(100) +AS +BEGIN + DECLARE @name varchar(100); + SET @name = 'Running function ' + OBJECT_NAME(@@PROCID) + '!'; + RETURN @name; +END; +GO + +SELECT demo_func1(); +GO + +-- Test nested function inside a procedure +CREATE PROCEDURE demo_proc2 +AS +DECLARE @proc_name sysname; +DECLARE @msg varchar(100); +-- Execute another procedure +EXEC demo_proc1; +-- Call a function +SELECT demo_func1(); +-- Execute this procedure +SET @proc_name = OBJECT_NAME(@@PROCID); +SET @msg = 'Running stored procedure ' + @proc_name + '!'; +SELECT @msg; +-- Again execute another procedure +EXEC demo_proc1; +GO + +EXEC demo_proc2; +GO + +DROP PROCEDURE demo_proc2; +GO + +-- Test nested function inside a function +CREATE FUNCTION demo_func2() +RETURNS varchar(100) +AS +BEGIN + DECLARE @name varchar(100); + SET @name = OBJECT_NAME(@@PROCID); + RETURN @name; +END +GO + +CREATE FUNCTION demo_func3() +RETURNS TABLE AS +RETURN +( + SELECT demo_func2() as nested_function, OBJECT_NAME(@@PROCID) as current_function +) +GO + +SELECT * FROM demo_func3(); +GO + +DROP FUNCTION demo_func2; +DROP FUNCTION demo_func3; +GO + +-- Test triggers +CREATE TABLE data (a int NOT NULL); +GO + +CREATE TABLE data_log (procedure_name sysname NULL); +GO + +CREATE TRIGGER trg_data_log ON data AFTER INSERT +AS +INSERT INTO data_log(procedure_name) VALUES(OBJECT_NAME(@@PROCID)); +GO + +INSERT INTO data(a) VALUES(1); +GO + +-- Should print name of the trigger +SELECT * FROM data_log; +GO + +DROP TRIGGER trg_data_log; +DROP TABLE data_log; +GO + +--Test nested function and procedure inside a trigger +CREATE TRIGGER trg_call_modules ON data AFTER INSERT +AS +-- Execute procedure +EXEC demo_proc1; +-- Call function +SELECT demo_func1(); +-- Print name of this trigger +DECLARE @msg varchar(100); +SET @msg = 'Inside trigger ' + OBJECT_NAME(@@PROCID) + '!'; +SELECT @msg; +GO + +INSERT INTO data(a) VALUES(1); +GO + +DROP PROCEDURE demo_proc1; +DROP FUNCTION demo_func1; +DROP TRIGGER trg_call_modules; +GO + +-- Test when nested module throws error +CREATE PROCEDURE demo_proc1 +AS +RAISERROR('Procedure demo_proc1 failed', 16, 1); +GO + +CREATE PROCEDURE demo_proc2 +AS +BEGIN TRY + EXEC demo_proc1; +END TRY +BEGIN CATCH + DECLARE @msg varchar(100); + SET @msg = 'Running procedure ' + OBJECT_NAME(@@PROCID); + SELECT @msg; +END CATCH; +GO + +EXEC demo_proc2; +GO + +CREATE TRIGGER trg_err_check ON data AFTER INSERT +AS +BEGIN TRY + EXEC demo_proc1; +END TRY +BEGIN CATCH + DECLARE @msg varchar(100); + SET @msg = 'Running trigger ' + OBJECT_NAME(@@PROCID); + SELECT @msg; +END CATCH; +GO + +INSERT INTO data(a) VALUES(3); +GO + +-- Test insert through a procedure +CREATE PROCEDURE table_insert +@val INT +AS +-- Insert will invoke the trigger +INSERT INTO data(a) VALUES(@val); +DECLARE @msg varchar(100); +SET @msg = 'Running procedure ' + OBJECT_NAME(@@PROCID); +SELECT @msg; +GO + +EXEC table_insert 4; +GO + +DROP TRIGGER trg_err_check; +DROP TABLE data; +DROP PROCEDURE table_insert; +DROP PROCEDURE demo_proc2; +DROP PROCEDURE demo_proc1; +GO diff --git a/contrib/test/JDBC/input/BABEL-RAND.sql b/contrib/test/JDBC/input/BABEL-RAND.sql new file mode 100644 index 00000000000..d3ce35e13b0 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-RAND.sql @@ -0,0 +1,29 @@ +USE master; +GO + +SELECT rand(2147483647) +GO +SELECT rand() +GO +SELECT rand() +GO +SELECT rand() +GO + +SELECT rand(0) +GO +SELECT rand() +GO +SELECT rand() +GO +SELECT rand() +GO + +SELECT rand(-2147483648) +GO +SELECT rand() +GO +SELECT rand() +GO +SELECT rand() +GO \ No newline at end of file diff --git a/contrib/test/JDBC/input/BABEL-RECURSIVE-CTE.sql b/contrib/test/JDBC/input/BABEL-RECURSIVE-CTE.sql new file mode 100644 index 00000000000..3441e307e45 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-RECURSIVE-CTE.sql @@ -0,0 +1,85 @@ +USE master; +GO + +CREATE SCHEMA babel_recursive_cte; +GO + +CREATE TABLE babel_recursive_cte.numbers (c1 int); +GO + +INSERT INTO babel_recursive_cte.numbers VALUES (3) +GO + +-- basic positive case +WITH numbers(c1) +AS ( + SELECT 1 + UNION ALL + SELECT c1 + 1 FROM numbers WHERE c1 <= 5 +) +SELECT c1 FROM numbers ORDER BY c1 +GO + +-- basic negative case (not recursive) +WITH numbers(c1) +AS ( + SELECT 1 + UNION ALL + SELECT c1 + 1 FROM babel_recursive_cte.numbers WHERE c1 <= 5 -- referring physical table +) +SELECT c1 FROM numbers ORDER BY c1 +GO + +-- invalid recursive cte 1 +WITH numbers(c1) +AS ( + SELECT 1 FROM numbers + UNION ALL + SELECT c1 + 1 FROM numbers WHERE c1 <= 5 +) +SELECT c1 FROM numbers ORDER BY c1 +GO + +-- invalid recursive cte 2 +WITH numbers(c1) +AS ( + SELECT c1 + 1 FROM numbers WHERE c1 <= 5 +) +SELECT c1 FROM numbers ORDER BY c1 +GO + +-- recursive + join +WITH numbers(c1) +AS ( + SELECT 1 + UNION ALL + SELECT Y.c1 + 1 FROM babel_recursive_cte.numbers X INNER JOIN numbers Y on 1 = 1 WHERE Y.c1 <= 5 +) +SELECT c1 FROM numbers ORDER BY c1 +GO + +-- recursive + subquery +WITH numbers(c1) +AS ( + SELECT 1 + UNION ALL + SELECT c1 + 1 FROM (SELECT * FROM numbers) X WHERE c1 <= 5 +) +SELECT c1 FROM numbers ORDER BY c1 +GO + +-- recursive + expr-subquery (unsupported) +WITH numbers(c1) +AS ( + SELECT 1 + UNION ALL + SELECT (SELECT c1 FROM numbers) + 1 FROM babel_recursive_cte.numbers X WHERE c1 <= 5 +) +SELECT c1 FROM numbers ORDER BY c1 +GO + +DROP TABLE babel_recursive_cte.numbers; +GO + +DROP SCHEMA babel_recursive_cte; +GO \ No newline at end of file diff --git a/contrib/test/JDBC/input/BABEL-ROWCOUNT.sql b/contrib/test/JDBC/input/BABEL-ROWCOUNT.sql new file mode 100644 index 00000000000..d3b9f547eba --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-ROWCOUNT.sql @@ -0,0 +1,112 @@ +USE master; +GO + +CREATE TABLE babel_rowcount(test_id INT IDENTITY, test_col1 INT); +GO + +CREATE PROCEDURE babel_rowcount_insert +AS BEGIN + INSERT INTO babel_rowcount (test_col1) VALUES (10), (10), (10) + + IF @@ROWCOUNT <> 3 PRINT @@ROWCOUNT + + INSERT INTO babel_rowcount (test_col1) VALUES (20) + INSERT INTO babel_rowcount (test_col1) VALUES (20) + + IF @@ROWCOUNT <> 1 PRINT @@ROWCOUNT +END; +GO + +CREATE PROCEDURE babel_rowcount_select +AS BEGIN + SELECT * FROM babel_rowcount + IF @@ROWCOUNT <> 5 PRINT @@ROWCOUNT +END; +GO + +CREATE PROCEDURE babel_rowcount_update +AS BEGIN + UPDATE babel_rowcount SET test_col1 = 1 WHERE test_col1 = 10 + + IF @@ROWCOUNT <> 3 PRINT @@ROWCOUNT + + UPDATE babel_rowcount SET test_col1 = 2 WHERE test_col1 = 20 + + IF @@ROWCOUNT <> 2 PRINT @@ROWCOUNT +END; +GO + +CREATE PROCEDURE babel_rowcount_select_set +AS BEGIN + DECLARE @v int + SELECT @v = test_col1 FROM babel_rowcount + IF @@ROWCOUNT <> 5 PRINT @@ROWCOUNT +END; +GO + +CREATE PROCEDURE babel_rowcount_delete +AS BEGIN + DELETE FROM babel_rowcount WHERE test_col1 = 1 + + IF @@ROWCOUNT <> 3 PRINT @@ROWCOUNT + + DELETE FROM babel_rowcount WHERE test_col1 = 2 + + IF @@ROWCOUNT <> 2 PRINT @@ROWCOUNT +END; +GO + +CREATE PROCEDURE babel_rowcount_basic_statements +AS BEGIN + DECLARE @v int + SET @v = 42 + IF @@ROWCOUNT <> 1 raiserror('ROWCOUNT should be 1', 11, 1) + print @v + IF @@ROWCOUNT <> 0 raiserror('ROWCOUNT should be 0', 11, 1) +END; +GO + +CREATE PROCEDURE babel_rowcount_return +AS BEGIN + RETURN 1 +END; +GO + +EXEC babel_rowcount_insert; +GO +EXEC babel_rowcount_select; +GO +EXEC babel_rowcount_update; +GO +-- Expect 2. Implicit return does not affect value +SELECT @@ROWCOUNT; +GO +EXEC babel_rowcount_select_set; +GO +EXEC babel_rowcount_return; +GO +-- Expect 1. Explicit return resets to 1 +SELECT @@ROWCOUNT; +GO +EXEC babel_rowcount_delete; +GO +EXEC babel_rowcount_basic_statements; +GO + +-- Clean up +DROP TABLE babel_rowcount; +GO +DROP PROCEDURE babel_rowcount_insert; +GO +DROP PROCEDURE babel_rowcount_select; +GO +DROP PROCEDURE babel_rowcount_update; +GO +DROP PROCEDURE babel_rowcount_select_set; +GO +DROP PROCEDURE babel_rowcount_return; +GO +DROP PROCEDURE babel_rowcount_delete; +GO +DROP PROCEDURE babel_rowcount_basic_statements; +GO \ No newline at end of file diff --git a/contrib/test/JDBC/input/BABEL-SCHEMABINDING.sql b/contrib/test/JDBC/input/BABEL-SCHEMABINDING.sql new file mode 100644 index 00000000000..a13b9dc6bfc --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-SCHEMABINDING.sql @@ -0,0 +1,64 @@ +CREATE TABLE t_babel_1201 (a int); +INSERT INTO t_babel_1201 values (1); +GO + +-- create view with schemabinding +CREATE VIEW v_babel_1201 WITH SCHEMABINDING AS SELECT * FROM t_babel_1201; +GO +SELECT * FROM v_babel_1201; +GO + +-- create trigger with schemabinding +CREATE TABLE t_babel_1201_2 (c varchar(20)); +GO +CREATE TRIGGER tr_babel_1201 on t_babel_1201 AFTER INSERT AS INSERT INTO t_babel_1201_2 values ('triggered'); +GO +INSERT INTO t_babel_1201 values (2); +GO +SELECT * FROM t_babel_1201_2; +GO + +-- create procedure with schemabinding +CREATE PROCEDURE p_babel_1201 (@v int) WITH SCHEMABINDING AS BEGIN PRINT CAST(@v AS VARCHAR(10)) END; +GO +EXEC p_babel_1201 1 +GO + +-- create function with schemabinding +CREATE FUNCTION f_babel_1201_1 (@v int) RETURNS INT WITH SCHEMABINDING AS BEGIN RETURN @v+1 END; +GO +SELECT f_babel_1201_1(1) +GO + +CREATE FUNCTION f_babel_1201_2 (@v int) RETURNS TABLE WITH SCHEMABINDING AS RETURN select @v+1 as a; +GO +SELECT f_babel_1201_2(2) +GO + +-- create function with other function options +CREATE FUNCTION f_babel_1201_3 (@v int) RETURNS INT WITH SCHEMABINDING, RETURNS NULL ON NULL INPUT AS BEGIN RETURN @v+1 END; +GO +SELECT f_babel_1201_3(3) +GO + +CREATE FUNCTION f_babel_1201_4 (@v int) RETURNS INT WITH RETURNS NULL ON NULL INPUT, SCHEMABINDING AS BEGIN RETURN @v+1 END; +GO +SELECT f_babel_1201_4(4) +GO + +-- create function with duplicate schemabinding +CREATE FUNCTION f_babel_1201_5 (@v int) RETURNS INT WITH SCHEMABINDING, SCHEMABINDING AS BEGIN RETURN @v+1 END; +GO +SELECT f_babel_1201_5(5) +GO + +DROP FUNCTION f_babel_1201_1; +DROP FUNCTION f_babel_1201_2; +DROP FUNCTION f_babel_1201_3; +DROP FUNCTION f_babel_1201_4; +DROP FUNCTION f_babel_1201_5; +DROP PROCEDURE p_babel_1201; +DROP VIEW v_babel_1201; +DROP TRIGGER tr_babel_1201; +DROP TABLE t_babel_1201; +GO diff --git a/contrib/test/JDBC/input/BABEL-SEQUENCE.sql b/contrib/test/JDBC/input/BABEL-SEQUENCE.sql new file mode 100644 index 00000000000..2422144dfd7 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-SEQUENCE.sql @@ -0,0 +1,300 @@ +USE master; +GO + +CREATE TABLE babel_sequence_tinyint (id [tinyint] IDENTITY, col1 [tinyint]); +go +CREATE PROCEDURE insert_babel_sequence_tinyint_id +@id tinyint, @val tinyint +AS BEGIN + SET IDENTITY_INSERT babel_sequence_tinyint ON; + INSERT INTO babel_sequence_tinyint (id, col1) VALUES (@id, @val); + SET IDENTITY_INSERT babel_sequence_tinyint OFF; +END; +go +EXEC insert_babel_sequence_tinyint_id 2, 1; +go +EXEC insert_babel_sequence_tinyint_id 8, 2; +go +INSERT INTO babel_sequence_tinyint (col1) VALUES (10), (20), (30); +go +EXEC insert_babel_sequence_tinyint_id 16, 3; +go +EXEC insert_babel_sequence_tinyint_id 255, 4; +go +INSERT INTO babel_sequence_tinyint (col1) VALUES (40); +go +SELECT * FROM babel_sequence_tinyint; +go + +CREATE TABLE babel_sequence_tinyint_dec (id [tinyint] IDENTITY(1,-1), col1 [tinyint]); +go +INSERT INTO babel_sequence_tinyint_dec (col1) VALUES (10); +go +INSERT INTO babel_sequence_tinyint_dec (col1) VALUES (20); +go +INSERT INTO babel_sequence_tinyint_dec (col1) VALUES (30); +go +SELECT * FROM babel_sequence_tinyint_dec; +go + +CREATE TABLE babel_sequence_smallint (id [smallint] IDENTITY, col1 [int]); +go +INSERT INTO babel_sequence_smallint (col1) VALUES (10), (20), (30); +go +SELECT * FROM babel_sequence_smallint; +go + +CREATE TABLE babel_sequence_int (id [int] IDENTITY, col1 [int]); +go +CREATE PROCEDURE insert_babel_sequence_int_id +@id INT, @val INT +AS BEGIN + SET IDENTITY_INSERT babel_sequence_int ON; + INSERT INTO babel_sequence_int (id, col1) VALUES (@id, @val); + SET IDENTITY_INSERT babel_sequence_int OFF; +END; +go +EXEC insert_babel_sequence_int_id 2, 1; +go +EXEC insert_babel_sequence_int_id 8, 2; +go +INSERT INTO babel_sequence_int (col1) VALUES (10), (20), (30); +go +EXEC insert_babel_sequence_int_id 16, 3; +go +EXEC insert_babel_sequence_int_id 32, 4; +go +SELECT * FROM babel_sequence_int; +go + +CREATE TABLE babel_sequence_bigint (id [bigint] IDENTITY, col1 [int]); +go +INSERT INTO babel_sequence_bigint (col1) VALUES (10), (20), (30); +go +SELECT * FROM babel_sequence_bigint; +go + +CREATE TABLE babel_sequence_numeric (id numeric(18,0) IDENTITY, col1 int); +go +CREATE PROCEDURE insert_babel_sequence_numeric_id +@id NUMERIC, @val NUMERIC +AS BEGIN + SET IDENTITY_INSERT babel_sequence_numeric ON; + INSERT INTO babel_sequence_numeric (id, col1) VALUES (@id, @val); + SET IDENTITY_INSERT babel_sequence_numeric OFF; +END; +go +EXEC insert_babel_sequence_numeric_id 2, 1; +go +EXEC insert_babel_sequence_numeric_id 8, 2; +go +INSERT INTO babel_sequence_numeric (col1) VALUES (10), (20), (30); +go +EXEC insert_babel_sequence_numeric_id 16, 3; +go +EXEC insert_babel_sequence_numeric_id 32, 4; +go +SELECT * FROM babel_sequence_numeric; +go + +CREATE TABLE babel_sequence_decimal (id decimal(18,0) IDENTITY, col1 int); +go +CREATE PROCEDURE insert_babel_sequence_decimal_id +@id DECIMAL, @val DECIMAL +AS BEGIN + SET IDENTITY_INSERT babel_sequence_decimal ON; + INSERT INTO babel_sequence_decimal (id, col1) VALUES (@id, @val); + SET IDENTITY_INSERT babel_sequence_decimal OFF; +END; +go +EXEC insert_babel_sequence_decimal_id 2, 1; +go +EXEC insert_babel_sequence_decimal_id 8, 2; +go +INSERT INTO babel_sequence_decimal (col1) VALUES (10), (20), (30); +go +EXEC insert_babel_sequence_decimal_id 16, 3; +go +EXEC insert_babel_sequence_decimal_id 32, 4; +go +SELECT * FROM babel_sequence_decimal; +go + +-- Test faulty table creation +CREATE TABLE babel_sequence_numeric_faulty_scale (id numeric(18,6) IDENTITY, col1 int); +go +CREATE TABLE babel_sequence_numeric_faulty_precision (id numeric(20,0) IDENTITY, col1 int); +go + +-- Test ALTER on identity property +CREATE TABLE babel_sequence_alter (col1 [int]); +go +INSERT INTO babel_sequence_alter VALUES (-5), (10), (42); +go + +ALTER TABLE babel_sequence_alter ADD id_tinyint [tinyint] IDENTITY(1,1); +go +SELECT * FROM babel_sequence_alter; +go +ALTER TABLE babel_sequence_alter DROP COLUMN id_tinyint; +go + +ALTER TABLE babel_sequence_alter ADD id_smallint [smallint] IDENTITY(1,1); +go +SELECT * FROM babel_sequence_alter; +go +ALTER TABLE babel_sequence_alter DROP COLUMN id_smallint; +go + +ALTER TABLE babel_sequence_alter ADD id_int [int] IDENTITY; +go +SELECT * FROM babel_sequence_alter; +go +ALTER TABLE babel_sequence_alter DROP COLUMN id_int; +go + +ALTER TABLE babel_sequence_alter ADD id_bigint [bigint] IDENTITY(32,8); +go +INSERT INTO babel_sequence_alter VALUES (-5), (10), (42); +go +SELECT * FROM babel_sequence_alter; +go +ALTER TABLE babel_sequence_alter DROP COLUMN id_bigint; +go + +ALTER TABLE babel_sequence_alter ADD id_numeric numeric(18,0) IDENTITY(32,8); +go +INSERT INTO babel_sequence_alter VALUES (-5), (10), (42); +go +SELECT * FROM babel_sequence_alter; +go +ALTER TABLE babel_sequence_alter DROP COLUMN id_numeric; +go + +ALTER TABLE babel_sequence_alter ADD id_decimal decimal(18,0) IDENTITY(32,8); +go +INSERT INTO babel_sequence_alter VALUES (-5), (10), (42); +go +SELECT * FROM babel_sequence_alter; +go +ALTER TABLE babel_sequence_alter DROP COLUMN id_decimal; +go + +-- Test sequences +CREATE SEQUENCE seq_tinyint +AS [tinyint] +START WITH 1 +INCREMENT BY 1 +CACHE 50 +go +SELECT nextval('seq_tinyint'); +go +SELECT setval('seq_tinyint', 255); +go +SELECT nextval('seq_tinyint'); +go + +CREATE SEQUENCE seq_smallint +AS [smallint] +START WITH 1 +INCREMENT BY 1 +CACHE 50 +go +SELECT nextval('seq_smallint'); +go +SELECT setval('seq_smallint', 32767); +go +SELECT nextval('seq_smallint'); +go + +CREATE SEQUENCE seq_int +AS [int] +START WITH 1 +INCREMENT BY 1 +CACHE 50 +go +SELECT nextval('seq_int'); +go +SELECT setval('seq_int', 2147483647); +go +SELECT nextval('seq_int'); +go + +CREATE SEQUENCE seq_bigint +AS [bigint] +START WITH 1 +INCREMENT BY 1 +CACHE 50 +go +SELECT nextval('seq_bigint'); +go +SELECT setval('seq_bigint', 9223372036854775807); +go +SELECT nextval('seq_bigint'); +go + +CREATE SEQUENCE seq_numeric +AS numeric(18,0) +START WITH 1 +INCREMENT BY 1 +CACHE 50 +go +SELECT nextval('seq_numeric'); +go +SELECT setval('seq_numeric', 9223372036854775807); +go +SELECT nextval('seq_numeric'); +go + +CREATE SEQUENCE seq_decimal +AS decimal(18,0) +START WITH 1 +INCREMENT BY 1 +CACHE 50 +go +SELECT nextval('seq_decimal'); +go +SELECT setval('seq_decimal', 9223372036854775807); +go +SELECT nextval('seq_decimal'); +go + +-- Test faulty sequence creation +CREATE SEQUENCE seq_tinyint_faulty_min +AS [tinyint] +START WITH 1 +INCREMENT BY 1 +MINVALUE -1 +MAXVALUE 255 +CACHE 50 +go + +CREATE SEQUENCE seq_tinyint_faulty_max +AS [tinyint] +START WITH 1 +INCREMENT BY 1 +MINVALUE 0 +MAXVALUE 256 +CACHE 50 +go + +CREATE SEQUENCE seq_numeric_faulty_scale +AS numeric(10,1) +START WITH 1 +INCREMENT BY 1 +CACHE 50 +go + +CREATE SEQUENCE seq_numeric_faulty_precision +AS numeric(21,0) +START WITH 1 +INCREMENT BY 1 +CACHE 50 +go + +DROP PROC insert_babel_sequence_tinyint_id, insert_babel_sequence_int_id, insert_babel_sequence_numeric_id, insert_babel_sequence_decimal_id; +go +DROP TABLE babel_sequence_tinyint, babel_sequence_tinyint_dec, babel_sequence_smallint, babel_sequence_int, babel_sequence_bigint, babel_sequence_numeric, babel_sequence_decimal, babel_sequence_alter; +go +DROP SEQUENCE seq_tinyint, seq_smallint, seq_int, seq_bigint, seq_numeric, seq_decimal; +go \ No newline at end of file diff --git a/contrib/test/JDBC/input/BABEL-SERVERPROPERTY.sql b/contrib/test/JDBC/input/BABEL-SERVERPROPERTY.sql new file mode 100644 index 00000000000..e3c7a6d50d2 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-SERVERPROPERTY.sql @@ -0,0 +1,17 @@ +-- test serverproperty() function +-- invalid property name, should reutnr NULL +select serverproperty('invalid property'); +go +-- valid supported properties +select serverproperty('collation'); +go +select 'true' where serverproperty('collationId') >= 0; +go +select serverproperty('IsSingleUser'); +go +select serverproperty('ServerName'); +go + +-- BABEL-1286 +SELECT SERVERPROPERTY('babelfish'); +go diff --git a/contrib/test/JDBC/input/BABEL-SET-COMMAND.sql b/contrib/test/JDBC/input/BABEL-SET-COMMAND.sql new file mode 100644 index 00000000000..a360cac4f0c --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-SET-COMMAND.sql @@ -0,0 +1,52 @@ +-- Simple SET +SET XACT_ABORT ON; +SELECT name, setting FROM pg_settings WHERE name = 'babelfishpg_tsql.xact_abort'; +GO +SELECT name, setting FROM pg_settings WHERE name = 'babelfishpg_tsql.xact_abort'; +SET XACT_ABORT OFF; +GO + +-- Inside transaction with commit +BEGIN TRANSACTION + SET XACT_ABORT ON; +COMMIT TRANSACTION +GO +SELECT name, setting FROM pg_settings WHERE name = 'babelfishpg_tsql.xact_abort'; +SET XACT_ABORT OFF; +GO + +-- Inside transaction with rollback +BEGIN TRANSACTION + SET XACT_ABORT ON; +ROLLBACK TRANSACTION +GO +SELECT name, setting FROM pg_settings WHERE name = 'babelfishpg_tsql.xact_abort'; +SET XACT_ABORT OFF; +GO + +-- Inside transaction with rollback to savepoint +BEGIN TRANSACTION; + SET XACT_ABORT OFF; + SAVE TRAN SP1; + SET XACT_ABORT ON; + SELECT name, setting FROM pg_settings WHERE name = 'babelfishpg_tsql.xact_abort'; + ROLLBACK TRAN SP1; + SELECT name, setting FROM pg_settings WHERE name = 'babelfishpg_tsql.xact_abort'; +ROLLBACK TRANSACTION +GO +SELECT name, setting FROM pg_settings WHERE name = 'babelfishpg_tsql.xact_abort'; +SET XACT_ABORT OFF; +GO + +-- Inside procedure +CREATE PROCEDURE xact_proc +AS +BEGIN + SET XACT_ABORT ON; + SELECT name, setting FROM pg_settings WHERE name = 'babelfishpg_tsql.xact_abort'; +END +GO +EXEC xact_proc; +SELECT name, setting FROM pg_settings WHERE name = 'babelfishpg_tsql.xact_abort'; +SET XACT_ABORT OFF; +GO \ No newline at end of file diff --git a/contrib/test/JDBC/input/BABEL-SPCOLUMNS.sql b/contrib/test/JDBC/input/BABEL-SPCOLUMNS.sql new file mode 100644 index 00000000000..dd585d38e1c --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-SPCOLUMNS.sql @@ -0,0 +1,56 @@ +USE master +GO +CREATE DATABASE mydb1 +GO +USE mydb1 +GO + +-- Error: have to provide table name +EXEC sp_columns +GO + +-- Testing a few different types +CREATE table t_time (a time) +GO +EXEC sp_columns @table_name = 't_time' +GO + +CREATE table t_text(a text) +GO +exec sp_columns @table_name = 't_text' +GO + +CREATE table t_int (a int) +GO +exec sp_columns @table_name = 't_int' +GO + +CREATE table t_money(a money) +GO +exec sp_columns @table_name = 't_money' +GO + +-- Testing all parameters +EXEC sp_columns @table_name = 't_int', @table_owner = 'dbo', @table_qualifier = 'mydb1', @column_name = 'a' +GO +EXEC sp_columns 't_int', 'dbo', 'mydb1', 'a' +GO + +-- sp_columns_100, wild card matching enabled +EXEC sp_columns_100 '%_money', 'dbo', NULL, NULL, 0, 2, 1 +GO + +-- no wild card matching +EXEC sp_columns_100 '%_money', 'dbo', NULL, NULL, 0, 2, 0 +GO + +drop table t_int +drop table t_text +drop table t_time +drop table t_money +GO + +USE master +GO +DROP DATABASE mydb1 +GO diff --git a/contrib/test/JDBC/input/BABEL-SPCURSOR.sql b/contrib/test/JDBC/input/BABEL-SPCURSOR.sql new file mode 100644 index 00000000000..dc805abfa12 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-SPCURSOR.sql @@ -0,0 +1,226 @@ +CREATE TABLE babel_cursor_t1 (i INT, d double precision, c varchar(10), u uniqueidentifier, v sql_variant); +INSERT INTO babel_cursor_t1 VALUES (1, 1.1, 'a', '1E984725-C51C-4BF4-9960-E1C80E27ABA0', 1); +INSERT INTO babel_cursor_t1 VALUES (2, 22.22, 'bb', '2E984725-C51C-4BF4-9960-E1C80E27ABA0', 22.22); +INSERT INTO babel_cursor_t1 VALUES (3, 333.333, 'cccc', '3E984725-C51C-4BF4-9960-E1C80E27ABA0', 'cccc'); +INSERT INTO babel_cursor_t1 VALUES (4, 4444.4444, 'dddddd', '4E984725-C51C-4BF4-9960-E1C80E27ABA0', cast('4E984725-C51C-4BF4-9960-E1C80E27ABA0' as uniqueidentifier)); +INSERT INTO babel_cursor_t1 VALUES (NULL, NULL, NULL, NULL, NULL); +GO + +-- simple happy case +DECLARE @cursor_handle int; +EXEC sp_cursoropen @cursor_handle OUTPUT, 'select i, d, c, u from babel_cursor_t1', 2, 8193; +-- NEXT 1 +EXEC sp_cursorfetch @cursor_handle, 2, 0, 1; +-- NEXT 1 +EXEC sp_cursorfetch @cursor_handle, 2, 0, 1; +-- NEXT 1 +EXEC sp_cursorfetch @cursor_handle, 2, 0, 1; +-- PREV 1 +EXEC sp_cursorfetch @cursor_handle, 4, 0, 1; +-- FIRST 2 +EXEC sp_cursorfetch @cursor_handle, 1, 0, 2; +-- LAST 3 +EXEC sp_cursorfetch @cursor_handle, 8, 0, 3; +-- ABSOLUTE 2 2 +EXEC sp_cursorfetch @cursor_handle, 16, 2, 2; +EXEC sp_cursorclose @cursor_handle; +GO + +-- sp_cursor auto-close +DECLARE @cursor_handle int; +EXEC sp_cursoropen @cursor_handle OUTPUT, 'select i, d, c, u from babel_cursor_t1', 16400, 8193; +EXEC sp_cursorfetch @cursor_handle, 2, 0, 100; +DECLARE @num_opened_cursor int; +SELECT @num_opened_cursor = count(*) FROM pg_catalog.pg_cursors where statement not like '%num_opened_cursor%'; +PRINT 'num_opened_cursor: ' + cast(@num_opened_cursor as varchar(10)); +GO + +-- sp_cursor auto-close (no fast-forward) +DECLARE @cursor_handle int; +EXEC sp_cursoropen @cursor_handle OUTPUT, 'select i, d, c, u from babel_cursor_t1', 16384, 8193; +EXEC sp_cursorfetch @cursor_handle, 2, 0, 100; +DECLARE @num_opened_cursor int; +SELECT @num_opened_cursor = count(*) FROM pg_catalog.pg_cursors where statement not like '%num_opened_cursor%'; +PRINT 'num_opened_cursor: ' + cast(@num_opened_cursor as varchar(10)); +GO + +-- sp_cursor auto-close (BABEL-1812) +DECLARE @cursor_handle int; +EXEC sp_cursoropen @cursor_handle OUTPUT, 'select i, d, c, u from babel_cursor_t1', 16388, 8193; +EXEC sp_cursorfetch @cursor_handle, 2, 0, 100; +DECLARE @num_opened_cursor int; +SELECT @num_opened_cursor = count(*) FROM pg_catalog.pg_cursors where statement not like '%num_opened_cursor%'; +PRINT 'num_opened_cursor: ' + cast(@num_opened_cursor as varchar(10)); +GO + + +-- sp_cursoroption and sp_cursor (not meaningful without TDS implemenation) +DECLARE @cursor_handle int; +EXEC sp_cursoropen @cursor_handle OUTPUT, 'select i, d, c, u from babel_cursor_t1', 2, 1; +EXEC sp_cursorfetch @cursor_handle, 2, 0, 2; +-- TEXTPTR_ONLY 2 +EXEC sp_cursoroption @cursor_handle, 1, 2; +EXEC sp_cursor @cursor_handle, 40, 1, ''; +-- TEXTPTR_ONLY 4 +EXEC sp_cursoroption @cursor_handle, 1, 4; +EXEC sp_cursor @cursor_handle, 40, 1, ''; +-- TEXTPTR_ONLY 0 +EXEC sp_cursoroption @cursor_handle, 1, 0; +EXEC sp_cursor @cursor_handle, 40, 1, ''; +-- TEXTDATA 3 +EXEC sp_cursoroption @cursor_handle, 3, 3; +EXEC sp_cursor @cursor_handle, 40, 1, ''; +-- TEXTDATA 0 +EXEC sp_cursoroption @cursor_handle, 3, 0; +EXEC sp_cursor @cursor_handle, 40, 1, ''; +EXEC sp_cursorclose @cursor_handle; +GO + +-- cursor prep/exec test +DECLARE @stmt_handle int; +DECLARE @cursor_handle int; +DECLARE @cursor_handle2 int; +EXEC sp_cursorprepare @stmt_handle OUTPUT, N'', 'select i, d, c, u from babel_cursor_t1', 0, 2, 1; +EXEC sp_cursorexecute @stmt_handle, @cursor_handle OUTPUT, 2, 1; +EXEC sp_cursorfetch @cursor_handle, 2, 0, 1; +EXEC sp_cursorclose @cursor_handle; +EXEC sp_cursorexecute @stmt_handle, @cursor_handle2 OUTPUT, 2, 1; +EXEC sp_cursorfetch @cursor_handle2, 2, 0, 4; +EXEC sp_cursorclose @cursor_handle2; +EXEC sp_cursorunprepare @stmt_handle; +GO + +-- cursor prepexec test +DECLARE @stmt_handle int; +DECLARE @cursor_handle int; +DECLARE @cursor_handle2 int; +EXEC sp_cursorprepexec @stmt_handle OUTPUT, @cursor_handle OUTPUT, N'', 'select i+100 from babel_cursor_t1', 16400, 1; +EXEC sp_cursorfetch @cursor_handle, 2, 0, 1; +EXEC sp_cursorclose @cursor_handle; +EXEC sp_cursorexecute @stmt_handle, @cursor_handle2 OUTPUT, 2, 1; +EXEC sp_cursorfetch @cursor_handle2, 2, 0, 4; +EXEC sp_cursorclose @cursor_handle2; +EXEC sp_cursorunprepare @stmt_handle; +GO + +-- parameterized query +-- sp_cursoropen +DECLARE @cursor_handle int; +EXEC sp_cursoropen @cursor_handle OUTPUT, N'select i, d, c, u from babel_cursor_t1 where i > @ii and c not like @cc', 2, 8193, 20, N'@ii int, @cc varchar(10)', 1, 'd%'; +EXEC sp_cursorfetch @cursor_handle, 2, 0, 1; +EXEC sp_cursorfetch @cursor_handle, 2, 0, 1; +EXEC sp_cursorfetch @cursor_handle, 2, 0, 1; +EXEC sp_cursorclose @cursor_handle; +GO + +-- sp_cursorprepare + sp_cursorexecute +DECLARE @stmt_handle int; +DECLARE @cursor_handle int; +DECLARE @cursor_handle2 int; +EXEC sp_cursorprepare @stmt_handle OUTPUT, N'@ii int,@cc varchar(10)', N'select i, d, c, u from babel_cursor_t1 where i > @ii and c not like @cc', 0, 2, 8193; +EXEC sp_cursorexecute @stmt_handle, @cursor_handle OUTPUT, 2, 8193, 20, 1, 'd%'; +EXEC sp_cursorfetch @cursor_handle, 2, 0, 1; +EXEC sp_cursorfetch @cursor_handle, 2, 0, 1; +EXEC sp_cursorfetch @cursor_handle, 2, 0, 1; +EXEC sp_cursorclose @cursor_handle; +EXEC sp_cursorexecute @stmt_handle, @cursor_handle2 OUTPUT, 2, 8193, 20, 2, 'c%'; +EXEC sp_cursorfetch @cursor_handle2, 2, 0, 1; +EXEC sp_cursorfetch @cursor_handle2, 2, 0, 1; +EXEC sp_cursorclose @cursor_handle2; +EXEC sp_cursorunprepare @stmt_handle; +GO + +-- sp_cursorprepexec +DECLARE @stmt_handle int; +DECLARE @cursor_handle int; +DECLARE @cursor_handle2 int; +EXEC sp_cursorprepexec @stmt_handle OUTPUT, @cursor_handle OUTPUT, N'@ii int,@cc varchar(10)', N'select i, d, c, u from babel_cursor_t1 where i > @ii and c not like @cc', 2, 8193, 20, 1, 'd%'; +EXEC sp_cursorfetch @cursor_handle, 2, 0, 1; +EXEC sp_cursorclose @cursor_handle; +EXEC sp_cursorexecute @stmt_handle, @cursor_handle2 OUTPUT, 2, 8193, 20, 2, 'c%'; +EXEC sp_cursorfetch @cursor_handle2, 2, 0, 4; +EXEC sp_cursorclose @cursor_handle2; +EXEC sp_cursorunprepare @stmt_handle; +GO + + +-- passing parameter using variables +DECLARE @ii int = 1; +DECLARE @cc varchar(10) = 'd%'; +DECLARE @cursor_handle int; +EXEC sp_cursoropen @cursor_handle OUTPUT, N'select i, d, c, u from babel_cursor_t1 where i > @ii and c not like @cc', 2, 8193, 20, N'@ii int, @cc varchar(10)', @ii, @cc; +EXEC sp_cursorfetch @cursor_handle, 2, 0, 1; +EXEC sp_cursorfetch @cursor_handle, 2, 0, 1; +EXEC sp_cursorfetch @cursor_handle, 2, 0, 1; +EXEC sp_cursorclose @cursor_handle; +GO + + +-- NULL parameter +DECLARE @cursor_handle int; + EXEC sp_cursoropen @cursor_handle OUTPUT, N'select i, d, c, u from babel_cursor_t1 where i > (case when @ii is null then 1 else 1000 end)', 2, 8193, 20, N'@ii int', NULL; +EXEC sp_cursorfetch @cursor_handle, 2, 0, 1; +EXEC sp_cursorfetch @cursor_handle, 2, 0, 1; +EXEC sp_cursorfetch @cursor_handle, 2, 0, 1; +EXEC sp_cursorclose @cursor_handle; +GO + + +-- valid error: the # of parameter mismatches +DECLARE @cursor_handle int; +EXEC sp_cursoropen @cursor_handle OUTPUT, N'select i, d, c, u from babel_cursor_t1 where i > @ii and c not like @cc', 2, 8193, 20, N'@ii int, @cc varchar(10)', 1; +GO + +DECLARE @stmt_handle int; +DECLARE @cursor_handle int; +EXEC sp_cursorprepare @stmt_handle OUTPUT, N'@ii int,@cc varchar(10)', N'select i, d, c, u from babel_cursor_t1 where i > @ii and c not like @cc', 0, 2, 8193; +EXEC sp_cursorexecute @stmt_handle, @cursor_handle OUTPUT, 2, 8193, 20, 1; +EXEC sp_cursorunprepare @stmt_handle +GO + + +-- unsupported feature: named parameter +DECLARE @cursor_handle int; +EXEC sp_cursoropen @cursor_handle OUTPUT, N'select i, d, c, u from babel_cursor_t1 where i > @ii and c not like @cc', 2, 8193, 20, N'@ii int, @cc varchar(10)', @ii=1, @cc='c%'; +GO + +DECLARE @stmt_handle int; +DECLARE @cursor_handle int; +EXEC sp_cursorprepare @stmt_handle OUTPUT, N'@ii int,@cc varchar(10)', N'select i, d, c, u from babel_cursor_t1 where i > @ii and c not like @cc', 0, 2, 8193; +EXEC sp_cursorexecute @stmt_handle, @cursor_handle OUTPUT, 2, 8193, 20, @ii=1, @cc='c%'; +EXEC sp_cursorunprepare @stmt_handle +GO + +-- unsupported feature: output parameter +DECLARE @ii int; +DECLARE @cursor_handle int; +EXEC sp_cursoropen @cursor_handle OUTPUT, N'select i, d, c, u from babel_cursor_t1 where i > @ii and c not like @cc', 2, 8193, 20, N'@ii int OUTPUT, @cc varchar(10)', @ii, 'c%'; +GO + +DECLARE @ii int; +DECLARE @stmt_handle int; +DECLARE @cursor_handle int; +EXEC sp_cursorprepare @stmt_handle OUTPUT, N'@ii int OUTPUT, @cc varchar(10)', N'select i, d, c, u from babel_cursor_t1 where i > @ii and c not like @cc', 0, 2, 8193; +EXEC sp_cursorexecute @stmt_handle, @cursor_handle OUTPUT, 2, 8193, 20, @ii, 'c%'; +EXEC sp_cursorunprepare @stmt_handle +GO + + +-- BABEL-1812 +CREATE TABLE t1812(id int primary key, a int, b int); +GO +declare @p1 int +set @p1=1 +declare @p2 int +set @p2=0 +declare @p5 int +set @p5=16388 +declare @p6 int +set @p6=8193 +declare @p7 int +set @p7=0 +exec sp_cursorprepexec @p1 output,@p2 output,NULL,N'SELECT [id],[a],[b] FROM [dbo].[t1812]',@p5 output,@p6 output,@p7 output +select @p1, @p2, @p5, @p6, @p7; +exec sp_cursorclose @p2; +exec sp_cursorunprepare @p1; +go diff --git a/contrib/test/JDBC/input/BABEL-SP_DATABASES.sql b/contrib/test/JDBC/input/BABEL-SP_DATABASES.sql new file mode 100644 index 00000000000..9a35d281f12 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-SP_DATABASES.sql @@ -0,0 +1,24 @@ +create database db1; +go +use db1; +go +create table t_spdatabases(a int); +go +insert into t_spdatabases(a) values(10); +go +insert into t_spdatabases(a) values(10); +go +insert into t_spdatabases(a) values(10); +go +insert into t_spdatabases(a) values(10); +go + +select * from sys.sp_databases_view where database_name='db1'; +go + +drop table t_spdatabases; +go +use master; +go +drop database db1; +go diff --git a/contrib/test/JDBC/input/BABEL-SP_DATATYPE_INFO.sql b/contrib/test/JDBC/input/BABEL-SP_DATATYPE_INFO.sql new file mode 100644 index 00000000000..dadd8763b90 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-SP_DATATYPE_INFO.sql @@ -0,0 +1,9 @@ +exec sp_datatype_info_100 @data_type = 1 +go + +exec sp_datatype_info @data_type = 2 +go + +-- Failed query in BABEL-2448 +EXEC sys.sp_datatype_info_100 1, @odbcver = 2 +go diff --git a/contrib/test/JDBC/input/BABEL-SP_DESCRIBE_FRIST_RESULT_SET.sql b/contrib/test/JDBC/input/BABEL-SP_DESCRIBE_FRIST_RESULT_SET.sql new file mode 100644 index 00000000000..83fbbd04617 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-SP_DESCRIBE_FRIST_RESULT_SET.sql @@ -0,0 +1,17 @@ +create table t1(a int) +go + +-- no result +exec sys.sp_describe_first_result_set 'insert into t1 values(1)', NULL, 0 +go + +-- shows column info of 'a' +exec sp_describe_first_result_set 'select * from t1' +go + +-- should be empty because the queries above are not executed +select * from t1 +go + +drop table t1 +go diff --git a/contrib/test/JDBC/input/BABEL-SP_PKEYS.sql b/contrib/test/JDBC/input/BABEL-SP_PKEYS.sql new file mode 100644 index 00000000000..b1728ed4c12 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-SP_PKEYS.sql @@ -0,0 +1,46 @@ +create database db1 +go +use db1 +go +create table t1(a int, primary key(a)) +go +create table t2(a int, b int, c int, primary key(b, c)) +go +create table t3(a int, b int, c int, primary key(c, b)) +go +create table t4(a int) +go + +-- syntax error: @table_name is required +exec sp_pkeys +go + +exec sp_pkeys @table_name = 't1' +go + +exec sp_pkeys @table_name = 't2', @table_qualifier = 'db1' +go + +exec sp_pkeys @table_name = 't3', @table_owner = 'dbo' +go + +-- unnamed invocation +exec sp_pkeys 't1', 'dbo', 'db1' +go + +-- case-insensative invocation +EXEC SP_PKEYS @TABLE_NAME = 't2', @TABLE_OWNER = 'dbo', @TABLE_QUALIFIER = 'db1' +GO + +drop table t1 +go +drop table t2 +go +drop table t3 +go +drop table t4 +go +use master +go +drop database db1 +go diff --git a/contrib/test/JDBC/input/BABEL-SP_STATISTICS.sql b/contrib/test/JDBC/input/BABEL-SP_STATISTICS.sql new file mode 100644 index 00000000000..fa3780c23c1 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-SP_STATISTICS.sql @@ -0,0 +1,71 @@ +create database db1 +go +use db1 +go +create table t1(a int) +go +create index i1 on t1(a) +go +create table t2(a int, b int) +go +create index i2 on t2(a,b) +go +create table t3(a int, b int, c int) +go +create index i3 on t3(c,a) +go +CREATE TABLE t4( + c1 INT PRIMARY KEY + , c2 CHAR(10) NOT NULL UNIQUE + , c3 VARCHAR(20) NULL +) +create index i4 on t4(c2) +go + +-- syntax error: @table_name is required +exec sp_statistics +go + +exec sp_statistics @table_name = 't1' +go + +exec sp_statistics @table_name = 't2', @table_qualifier = 'db1' +go + +exec sp_statistics @table_name = 't3', @table_owner = 'dbo' +go + +exec sp_statistics @table_name = 't4' +go + +exec sp_statistics @table_name = 't4', @is_unique = 'Y' +go + +-- unnamed invocation +exec sp_statistics 't1', 'dbo', 'db1' +go + +-- case-insensative invocation +EXEC sp_statistics @TABLE_NAME = 't2', @TABLE_OWNER = 'dbo', @TABLE_QUALIFIER = 'db1' +GO + +-- sp_statistics_100 is implemented as same as sp_statistics +exec sp_statistics_100 @table_name = 't3' +go + +drop index i1 on t1 +go +drop index i2 on t2 +go +drop index i3 on t3 +go +drop table t1 +go +drop table t2 +go +drop table t3 +go +use master +go +drop database db1 +go diff --git a/contrib/test/JDBC/input/BABEL-SP_TABLES.sql b/contrib/test/JDBC/input/BABEL-SP_TABLES.sql new file mode 100644 index 00000000000..c4700d25303 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-SP_TABLES.sql @@ -0,0 +1,55 @@ +create database db1 +go +use db1 +go +create table t_sptables(a int) +go + +-- syntax error: @table_name is required +exec sys.sp_tables +go + +exec sp_tables @table_name = 't_sptables' +go + +exec sp_tables @table_name = 't_sptables', @table_owner = 'dbo' +go + +exec sp_tables @table_name = 't_sptables', @table_qualifier = 'db1' +go + +exec sp_tables @table_name = 't_sptables', @table_type = "'TABLE'" +go + +exec sp_tables @table_name = 't_sptables', @table_type = "'TABLE','VIEW'" +go + +-- pattern matching is default to be ON +exec sp_tables @table_name = 't_spt%' +go + +-- pattern matching set to OFF +exec sp_tables @table_name = 't_spt%', @fUsePattern = '0' +go + +exec sp_tables @table_name = 't_sptables_nonexist' +go + +-- unnamed invocation +exec sp_tables 't_sptables', 'dbo', 'db1' +go + +-- case-insensative invocation +EXEC SP_TABLES @TABLE_NAME = 't_sptables', @TABLE_OWNER = 'dbo', @TABLE_QUALIFIER = 'db1' +GO + +-- failed query in BABEL-1782 +exec [sys].sp_tables N't23',N'dbo',NULL,N'''TABLE''',@fUsePattern=1; +go + +drop table t_sptables +go +use master +go +drop database db1 +go diff --git a/contrib/test/JDBC/input/BABEL-SQL-CONFIG-FUNCTIONS.sql b/contrib/test/JDBC/input/BABEL-SQL-CONFIG-FUNCTIONS.sql new file mode 100644 index 00000000000..7e75e1e5a5e --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-SQL-CONFIG-FUNCTIONS.sql @@ -0,0 +1,2 @@ +SELECT count(*) FROM (SELECT @@VERSION) a where version like 'Babelfish for PostgreSQL with SQL Server Compatibility%' +GO diff --git a/contrib/test/JDBC/input/BABEL-SQUARE.sql b/contrib/test/JDBC/input/BABEL-SQUARE.sql new file mode 100644 index 00000000000..86dd155b7af --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-SQUARE.sql @@ -0,0 +1,40 @@ +-- Test all numeric datatypes +SELECT square(CAST(12 AS int)); +GO +SELECT square(CAST(12.4 AS float)); +GO +SELECT square(CAST(12.4 AS real)); +GO +SELECT square(CAST(12.4 AS bigint)); +GO +SELECT square(CAST(12.4 AS smallint)); +GO +SELECT square(CAST(12.4 AS tinyint)); +GO +SELECT square(CAST('$12.4' AS money)); +GO +SELECT square(CAST('$12.4' AS smallmoney)); +GO +SELECT square(CAST(12.4 AS decimal)); +GO +SELECT square(CAST(12.4 AS numeric)); +GO + +-- Test select from table +CREATE TABLE cubes(id int, side_length float(24)); +GO +INSERT INTO cubes VALUES (1, 24.22); +INSERT INTO cubes VALUES (1, 145.76); +GO +SELECT id, square(side_length)*side_length AS volume FROM cubes; +GO +DROP TABLE cubes; +GO + +-- Float overflow: expect error +SELECT square(CAST('-1.79E+308' AS float)); +GO +SELECT square(CAST('-1.79E+153' AS float)); +GO +SELECT square(NULL); +GO diff --git a/contrib/test/JDBC/input/BABEL-SYS-DATABASES.mix b/contrib/test/JDBC/input/BABEL-SYS-DATABASES.mix new file mode 100644 index 00000000000..f9f5b18d5ba --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-SYS-DATABASES.mix @@ -0,0 +1,26 @@ +-- psql +ALTER SYSTEM SET babelfishpg_tsql.migration_mode = 'multi-db'; +SELECT pg_reload_conf(); +GO + +-- tsql +CREATE DATABASE db1; +GO + +CREATE DATABASE db2; +GO + +SELECT name, compatibility_level, collation_name FROM sys.databases ORDER BY name; +GO + +SELECT name, snapshot_isolation_state, catalog_collation_type_desc FROM sys.databases ORDER BY name; +GO + +DROP DATABASE db1; +DROP DATABASE db2; +GO + +-- psql +ALTER SYSTEM SET babelfishpg_tsql.migration_mode = 'single-db'; +SELECT pg_reload_conf(); +GO diff --git a/contrib/test/JDBC/input/BABEL-SYSCHARSETS.sql b/contrib/test/JDBC/input/BABEL-SYSCHARSETS.sql new file mode 100644 index 00000000000..bcacaf425d9 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-SYSCHARSETS.sql @@ -0,0 +1,5 @@ +USE master +go + +select * from sys.syscharsets; +go \ No newline at end of file diff --git a/contrib/test/JDBC/input/BABEL-SYS_COLUMNS.sql b/contrib/test/JDBC/input/BABEL-SYS_COLUMNS.sql new file mode 100644 index 00000000000..724f2cbc7cc --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-SYS_COLUMNS.sql @@ -0,0 +1,37 @@ +-- Tests for sys.columns catalog view +-- Test precision and scale for all numeric datatypes +create table t1(a int, b float, c bigint, d numeric, e smallint, f tinyint, g decimal, h money, i smallmoney); +go +select name, column_id, precision, scale from sys.columns where object_id=OBJECT_ID('t1') order by name; +go + +-- Test identity and computed columns +create table t2(a int, b int IDENTITY(1,1), c as a * b); +go +select name, column_id, is_identity, is_computed from sys.columns where object_id=OBJECT_ID('t2') order by name; +go + +-- Test ansi padded columns +create table t3(a char(10), b nchar(10), c binary(10)); +go +select name, column_id, is_ansi_padded from sys.columns where object_id=OBJECT_ID('t3') order by name; +go + +-- Test collation name +create table t4( + c1 char(10) COLLATE SQL_LATIN1_GENERAL_CP1_CI_AI, + c2 char(10) COLLATE SQL_LATIN1_GENERAL_CP1_CI_AS, + c3 char(10) COLLATE SQL_LATIN1_GENERAL_CP1_CS_AI, + c4 char(10) COLLATE SQL_LATIN1_GENERAL_CP1_CS_AS, + c5 char(10) COLLATE SQL_LATIN1_GENERAL_CP1250_CI_AS +); +go +select name, column_id, collation_name from sys.columns where object_id=OBJECT_ID('t4') order by name; +go + +-- Cleanup +drop table t1; +drop table t2; +drop table t3; +drop table t4; +go diff --git a/contrib/test/JDBC/input/BABEL-TABLEHINT.sql b/contrib/test/JDBC/input/BABEL-TABLEHINT.sql new file mode 100644 index 00000000000..1bbcd0732df --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-TABLEHINT.sql @@ -0,0 +1,84 @@ +create sequence t1_sec start with 1; +go +create table t1 (id int default nextval('t1_sec'), a int); +go + +-- Only checking the syntax. +-- INSERT +insert into t1 with() (a) values (1); -- syntax error +go +insert into t1 with((nowait)) (a) values (2); -- syntax error +go +insert into t1 with('nowait') (a) values (3); -- syntax error +go +insert into t1 with(123nowait) (a) values (4); -- syntax error +go +insert into t1 with($nowait) (a) values (5); -- syntax error +go +insert into t1 with(nowait.serializable) (a) values (6); -- syntax error +go +insert into t1 with(nowait) (a) values (7); +go +insert into t1 with(nowait serializable) (a) values (8); +go +insert into t1 with(nowait, serializable) (a) values (9); +go +select * from t1 order by id; +go + +-- DELETE +delete from t1 with (nowait) where a = 7; +go +delete from t1 with (nowait serializable) where a = 8; +go +delete from t1 with (nowait, serializable) where a = 9; +go +select * from t1 order by id; +go + +-- UPDATE +insert into t1 (a) values (1), (2), (3); +go +select * from t1 order by id; +go +update t1 with (nowait) +set a = 11 where a = 1; +go +update t1 with (nowait serializable) +set a = 22 where a = 2; +go +update t1 with (nowait, serializable) +set a = 33 where a = 3; +go +select * from t1 order by id; +go + +-- SELECT +select * from t1 with (nowait) order by id; +go +select * from t1 with (nowait serializable) order by id; +go +select * from t1 with (nowait, serializable) order by id; +go + +select * from t1 with (index=i1) order by id; +go +select * from t1 with (index(i1)) order by id; +go +select * from t1 with (index(i1, i2)) order by id; +go +select count(*) from t1 s1 with (index(i1,i2)) join t1 s2 with (index=i3) on s1.a=s2.a; +go + +-- BABEL-1148: Use table hints w/o WITH keyword +select * from t1 (tablock) order by id; -- success +go +select * from t1 (tablock, index(i1)) order by id; -- syntax error +go +-- BABEL-1263: syntax "FROM [table] ([table_hint]) [alias]" should be supported +Select * FROM t1 n1 (Nolock) WHERE (Select Count(*) FROM t1 (Nolock) n2) <= 0; +go + +-- Clean up +drop table t1; +go diff --git a/contrib/test/JDBC/input/BABEL-TARGETLIST.sql b/contrib/test/JDBC/input/BABEL-TARGETLIST.sql new file mode 100644 index 00000000000..2708d7cece5 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-TARGETLIST.sql @@ -0,0 +1,16 @@ +CREATE SCHEMA ts; +CREATE TABLE ts.t1 (ABC text, b varchar(20), c char(4), Xyz int, [Delimited] int, [Square Brackets] bigint); +GO + +SELECT * from ts.t1; +SELECT xyz, XYZ, xYz, xyz ColName, xYz AS ColName, [Square Brackets], [Delimited], [DeLIMITed] from ts.t1; +GO + +SELECT xyz AS [WOW! This is a very very long identifier that will get truncated with a uniquifying suffix by Babelfish] from ts.t1; +GO +SELECT xyz AS [WOW! This is a very very long identifier that will get truncated with a uniquifying suffix by Babelfish - with extra stuff at the end] from ts.t1; +GO + +DROP TABLE ts.t1; +DROP SCHEMA ts; +GO diff --git a/contrib/test/JDBC/input/BABEL-UNSUPPORTED.sql b/contrib/test/JDBC/input/BABEL-UNSUPPORTED.sql new file mode 100644 index 00000000000..629361d3b25 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL-UNSUPPORTED.sql @@ -0,0 +1,1512 @@ +-- default value was changed from 'strict' to 'ignore'. +-- to minimize touching test, test 'strict' first. +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_session_settings', 'strict'; +GO + +-- simple unsupported query but accepted in backend parser. should throw an error. +SET ANSI_PADDING OFF; +GO + +SET ANSI_WARNINGS OFF; +GO + +SET ARITHABORT OFF; +GO + +SET ARITHIGNORE ON; +GO + +SET NUMERIC_ROUNDABORT ON; +GO + +SET NOEXEC ON; +GO + +SET SHOWPLAN_ALL ON; +GO + +SET SHOWPLAN_TEXT ON; +GO + +SET SHOWPLAN_XML ON; +GO + +SET STATISTICS IO ON; +GO + +SET OFFSETS SELECT ON; +GO + +SET DATEFORMAT dmy; +GO + +SET DEADLOCK_PRIORITY 0; +GO + +SET LOCK_TIMEOUT 10; +GO + +SET CONTEXT_INFO 0; +GO + +SET LANGUAGE 'english' +GO + +-- one supported + one unsupported +SET ANSI_NULLS, ANSI_PADDING OFF; +GO +select current_setting('babelfishpg_tsql.ansi_nulls'); +GO +SET ANSI_NULLS ON; +GO + +SET ANSI_NULLS, STATISTICS IO OFF; +GO +select current_setting('babelfishpg_tsql.ansi_nulls'); -- should not be chagned +GO + +-- two unsupported +SET ANSI_PADDING, FORCEPLAN ON; +GO + +SET STATISTICS IO, OFFSETS SELECT ON; +GO + +-- escape_hatch_session_settings +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_session_settings', 'ignore'; +GO + +SET ANSI_PADDING OFF; +GO +select current_setting('babelfishpg_tsql.ansi_padding'); +GO + +SET ANSI_WARNINGS OFF; +GO +select current_setting('babelfishpg_tsql.ansi_warnings'); +GO + +SET ARITHABORT OFF; +GO +select current_setting('babelfishpg_tsql.arithabort'); +GO + +SET ARITHIGNORE ON; +GO +select current_setting('babelfishpg_tsql.arithignore'); +GO + +SET NUMERIC_ROUNDABORT ON; +GO +select current_setting('babelfishpg_tsql.numeric_roundabort'); +GO + +SET NOEXEC ON; +GO +select current_setting('babelfishpg_tsql.noexec'); +GO + +SET SHOWPLAN_ALL ON; +GO +select current_setting('babelfishpg_tsql.showplan_all'); +GO + +SET SHOWPLAN_TEXT ON; +GO +select current_setting('babelfishpg_tsql.showplan_text'); +GO + +SET SHOWPLAN_XML ON; +GO +select current_setting('babelfishpg_tsql.showplan_xml'); +GO + +-- these statement will be ignored silently +SET STATISTICS IO ON; +GO +SET OFFSETS SELECT ON; +GO +SET DATEFORMAT dmy; +GO +SET DEADLOCK_PRIORITY 0; +GO +SET LOCK_TIMEOUT 10; +GO +SET CONTEXT_INFO 0; +GO +SET LANGUAGE 'english'; +GO + +-- one supported + one unsupported +SET ANSI_NULLS, ANSI_PADDING OFF; +GO +select current_setting('babelfishpg_tsql.ansi_nulls'); -- should be changed +GO +SET ANSI_NULLS ON; +GO + +SET ANSI_NULLS, STATISTICS IO OFF; +GO +select current_setting('babelfishpg_tsql.ansi_nulls'); -- should not be chagned +GO +SET ANSI_NULLS ON; +GO + +-- two unsupported +SET ANSI_PADDING, FORCEPLAN ON; +GO + +SET STATISTICS IO, OFFSETS SELECT ON; +GO + + +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_session_settings', 'strict'; +GO + +-- simple unsupported query which backend parser can't understand. should throw an error with nice error message +ALTER DATABASE blah SET ANSI_PADDING OFF; +GO + +-- unsupported query in a batch. execution should be aborted. +DECLARE @v varchar(20); +SET ANSI_PADDING OFF; -- error +SET @v = 'SHOULD NOT BE SHOWN'; +SELECT @v; +GO + +DECLARE @v varchar(20); +ALTER DATABASE blah SET ANSI_PADDING OFF; -- error +SET @v = 'SHOULD NOT BE SHOWN'; +SELECT @v; +GO + +-- escape hatch: storage_options +-- 'ignore' is default + +CREATE TABLE t_unsupported_fg1(a int) ON [primary]; +GO +DROP TABLE t_unsupported_fg1 +GO + +CREATE TABLE t_unsupported_fg2(a int) TEXTIMAGE_ON [primary]; +GO +DROP TABLE t_unsupported_fg2 +GO + +CREATE TABLE t_unsupported_fg3(a int) FILESTREAM_ON [primary]; +GO +DROP TABLE t_unsupported_fg3 +GO + +CREATE TABLE t_unsupported_fg4(a int) ON [primary] TEXTIMAGE_ON [primary]; +GO +DROP TABLE t_unsupported_fg4 +GO + +CREATE TABLE t_unsupported_fg5(a int); +GO +CREATE INDEX t_unsupported_fg5_i1 ON t_unsupported_fg5(a) ON [primary]; +GO +DROP TABLE t_unsupported_fg5; +GO + +CREATE TABLE t_unsupported_fg6(a int); +GO +ALTER TABLE t_unsupported_fg6 SET (FILESTREAM_ON = [primary]); +GO +DROP TABLE t_unsupported_fg6; +GO + +CREATE TABLE t_unsupported_fg7(a int) ON "default"; +GO +DROP TABLE t_unsupported_fg7; +GO + +CREATE TABLE t_unsupported_fg8(a int) FILESTREAM_ON [primary]; +GO +DROP TABLE t_unsupported_fg8 +GO + +SELECT set_config('babelfishpg_tsql.escape_hatch_storage_options', 'strict', 'false') +GO + +CREATE TABLE t_unsupported_fg1(a int) ON [primary]; +GO + +CREATE TABLE t_unsupported_fg2(a int) TEXTIMAGE_ON [primary]; +GO + +CREATE TABLE t_unsupported_fg3(a int) FILESTREAM_ON [primary]; +GO + +CREATE TABLE t_unsupported_fg4(a int) ON [primary] TEXTIMAGE_ON [primary]; +GO + +CREATE TABLE t_unsupported_fg5(a int); +GO +CREATE INDEX t_unsupported_fg5_i1 ON t_unsupported_fg5(a) ON [primary]; +GO +DROP TABLE t_unsupported_fg5; +GO + +CREATE TABLE t_unsupported_fg6(a int); +GO +ALTER TABLE t_unsupported_fg6 SET (FILESTREAM_ON = [primary]); +GO +DROP TABLE t_unsupported_fg6; +GO + +CREATE TABLE t_unsupported_fg7(a int) ON "default"; +GO + +CREATE TABLE t_unsupported_fg8(a int) FILESTREAM_ON [primary]; +GO + +SELECT set_config('babelfishpg_tsql.escape_hatch_storage_options', 'ignore', 'false') +GO + +-- escape hatch: storage_on_partition. +-- 'strict' is default + +CREATE TABLE t_unsupported_sop1(a int) ON partition(a); +GO + +CREATE TABLE t_unsupported_sop2(a int) FILESTREAM_ON partition(a); +GO + +SELECT set_config('babelfishpg_tsql.escape_hatch_storage_on_partition', 'ignore', 'false') +GO + +CREATE TABLE t_unsupported_sop1(a int) ON partition(a); +GO +DROP TABLE t_unsupported_sop1; +GO + +CREATE TABLE t_unsupported_sop2(a int) FILESTREAM_ON partition(a); +GO +DROP TABLE t_unsupported_sop2 +GO + +SELECT set_config('babelfishpg_tsql.escape_hatch_storage_on_partition', 'strict', 'false') +GO + + +-- escape hatch: database_misc_options +-- 'ignore is default + +CREATE DATABASE db_unsupported1 CONTAINMENT = NONE; +GO +DROP DATABASE db_unsupported1; +GO + +CREATE DATABASE db_unsupported2 CONTAINMENT = PARTIAL; +GO +DROP DATABASE db_unsupported2; +GO + +CREATE DATABASE db_unsupported3 WITH DB_CHAINING ON; +GO +DROP DATABASE db_unsupported3; +GO + +CREATE DATABASE db_unsupported4 WITH TRUSTWORTHY OFF; +GO +DROP DATABASE db_unsupported4; +GO + +CREATE DATABASE db_unsupported5 CONTAINMENT = NONE WITH DB_CHAINING ON, DEFAULT_LANGUAGE = us_english, TRUSTWORTHY OFF; +GO +DROP DATABASE db_unsupported5; +GO + +CREATE DATABASE db_unsupported6 WITH PERSISTENT_LOG_BUFFER = ON (DIRECTORY_NAME = '/tmp'); +GO +DROP DATABASE db_unsupported6; +GO + +SELECT set_config('babelfishpg_tsql.escape_hatch_database_misc_options', 'strict', 'false') +GO + +CREATE DATABASE db_unsupported1 CONTAINMENT = NONE; +GO + +CREATE DATABASE db_unsupported2 CONTAINMENT = PARTIAL; +GO + +CREATE DATABASE db_unsupported3 WITH DB_CHAINING ON; +GO + +CREATE DATABASE db_unsupported4 WITH TRUSTWORTHY OFF; +GO + +CREATE DATABASE db_unsupported5 CONTAINMENT = NONE WITH DB_CHAINING ON, DEFAULT_LANGUAGE = us_english, TRUSTWORTHY OFF; +GO + +CREATE DATABASE db_unsupported6 WITH PERSISTENT_LOG_BUFFER = ON (DIRECTORY_NAME = '/tmp'); +GO +DROP DATABASE db_unsupported6; +GO + +SELECT set_config('babelfishpg_tsql.escape_hatch_database_misc_options', 'ignore', 'false') +GO + + +-- escape hatch: language_non_english +-- default is 'strict' + +CREATE DATABASE db_unsupported_l1 WITH DEFAULT_LANGUAGE = us_english; +GO +DROP DATABASE db_unsupported_l1; +GO + +CREATE DATABASE db_unsupported_l2 WITH DEFAULT_LANGUAGE = English; +GO +DROP DATABASE db_unsupported_l2; +GO + +CREATE DATABASE db_unsupported_l3 WITH DEFAULT_LANGUAGE = Deutsch; +GO + +CREATE LOGIN u_unsupported with password='12345678', default_language=english; +GO + +ALTER LOGIN u_unsupported with default_language=english; +GO + +ALTER LOGIN u_unsupported with default_language=spanish; +GO + +DROP LOGIN u_unsupported; +GO + +CREATE LOGIN u_unsupported_2 with password='12345678', default_language=spanish; +GO + +SELECT set_config('babelfishpg_tsql.escape_hatch_language_non_english', 'ignore', 'false') +GO + +CREATE DATABASE db_unsupported_l1 WITH DEFAULT_LANGUAGE = us_english; +GO +DROP DATABASE db_unsupported_l1; +GO + +CREATE DATABASE db_unsupported_l2 WITH DEFAULT_LANGUAGE = English; +GO +DROP DATABASE db_unsupported_l2; +GO + +CREATE DATABASE db_unsupported_l3 WITH DEFAULT_LANGUAGE = Deutsch; +GO +DROP DATABASE db_unsupported_l3; +GO + +CREATE LOGIN u_unsupported with password='12345678', default_language=english; +GO + +ALTER LOGIN u_unsupported with default_language=english; +GO + +ALTER LOGIN u_unsupported with default_language=spanish; +GO + +DROP LOGIN u_unsupported; +GO + +CREATE LOGIN u_unsupported_2 with password='12345678', default_language=spanish; +GO + +DROP LOGIN u_unsupported_2; +GO + +SELECT set_config('babelfishpg_tsql.escape_hatch_language_non_english', 'strict', 'false') +GO + + +-- escape hatch: fulltext +-- 'strict' is default + +CREATE TABLE t_unsupported_ft (a text); +GO + +CREATE FULLTEXT INDEX ON t_unsupported_ft(a) KEY INDEX ix_unsupported_ft; +GO + +DROP TABLE t_unsupported_ft; +GO + +CREATE DATABASE db_unsupported_ft WITH DEFAULT_FULLTEXT_LANGUAGE = English; +GO + +SELECT set_config('babelfishpg_tsql.escape_hatch_fulltext', 'ignore', 'false') +GO + +CREATE TABLE t_unsupported_ft (a text); +GO + +CREATE FULLTEXT INDEX ON t_unsupported_ft(a) KEY INDEX ix_unsupported_ft; +GO + +DROP TABLE t_unsupported_ft; +GO + +CREATE DATABASE db_unsupported_ft WITH DEFAULT_FULLTEXT_LANGUAGE = English; +GO +DROP DATABASE db_unsupported_ft; +GO + +SELECT set_config('babelfishpg_tsql.escape_hatch_fulltext', 'strict', 'false') +GO + + +-- escape hatch: schemabinding. +-- 'ignore' is by default. test if an error is thrown in strict mode if it is not explicitly given +SELECT set_config('babelfishpg_tsql.escape_hatch_schemabinding_function', 'strict', 'false') +GO +CREATE FUNCTION f_unsupported_1 (@v int) RETURNS INT AS BEGIN RETURN @v+1 END; +GO +CREATE FUNCTION f_unsupported_2 (@v int) RETURNS TABLE AS RETURN select @v+1 as a; +GO +CREATE FUNCTION f_unsupported_3 (@v int) RETURNS INT WITH RETURNS NULL ON NULL INPUT AS BEGIN RETURN @v+1 END; +GO +SELECT set_config('babelfishpg_tsql.escape_hatch_schemabinding_function', 'ignore', 'false') +GO + +SELECT set_config('babelfishpg_tsql.escape_hatch_schemabinding_procedure', 'strict', 'false') +GO +CREATE PROCEDURE p_unsupported_1 (@v int) AS BEGIN PRINT CAST(@v AS VARCHAR(10)) END; +GO +SELECT set_config('babelfishpg_tsql.escape_hatch_schemabinding_procedure', 'ignore', 'false') +GO + +CREATE TABLE t_unsupported (a int); +INSERT INTO t_unsupported values (1); +GO + +SELECT set_config('babelfishpg_tsql.escape_hatch_schemabinding_view', 'strict', 'false') +GO +CREATE VIEW v_unsupported AS SELECT * FROM t_unsupported; +GO +SELECT set_config('babelfishpg_tsql.escape_hatch_schemabinding_view', 'ignore', 'false') +GO + +SELECT set_config('babelfishpg_tsql.escape_hatch_schemabinding_trigger', 'strict', 'false') +GO +CREATE TRIGGER tr_unsupported on t_unsupported AFTER INSERT AS print 'triggered'; +GO +SELECT set_config('babelfishpg_tsql.escape_hatch_schemabinding_trigger', 'ignore', 'false') +GO + +DROP table t_unsupported; +GO + + +-- escape hatch escape_hatch_index_clustering +-- 'ignore' is default + +CREATE TABLE t_unsupported_ic1(a int, b int); +GO +CREATE CLUSTERED INDEX i_unsupported_ic11 on t_unsupported_ic1(a); +GO +CREATE NONCLUSTERED INDEX i_unsupported_ic12 on t_unsupported_ic1(b); +GO +DROP TABLE t_unsupported_ic1 +GO + +SELECT set_config('babelfishpg_tsql.escape_hatch_index_clustering', 'strict', 'false') +GO + +CREATE TABLE t_unsupported_ic1(a int, b int); +GO +CREATE CLUSTERED INDEX i_unsupported_ic11 on t_unsupported_ic1(a); +GO +CREATE NONCLUSTERED INDEX i_unsupported_ic12 on t_unsupported_ic1(b); +GO +DROP TABLE t_unsupported_ic1 +GO + +SELECT set_config('babelfishpg_tsql.escape_hatch_index_clustering', 'ignore', 'false') +GO + +-- BABEL-1484 +-- escape hatch escape_hatch_unique_constraint +-- 'strict' is default +-- Test UNIQUE CONSTRAINT is not allowed on nullable column +-- this includes: create unique index, alter table add constraint unique +-- and create table with column constraint +CREATE TABLE t_unsupported_uc1(a int, b int NOT NULL, c int NOT NULL); +GO +CREATE UNIQUE INDEX i_unsupported_uc1 on t_unsupported_uc1(a); +GO +ALTER TABLE t_unsupported_uc1 ADD CONSTRAINT UQ_a UNIQUE (a); +GO +CREATE TABLE t_unsupported_uc2(a int UNIQUE, b int); +GO + +-- Test UNIQUE CONSTRAINT is allowed on NOT NULL column +CREATE UNIQUE INDEX i_unsupported_uc1 on t_unsupported_uc1(b); +GO +ALTER TABLE t_unsupported_uc1 ADD CONSTRAINT UQ_c UNIQUE (c); +GO +CREATE TABLE t_unsupported_uc2(a int UNIQUE NOT NULL, b int NOT NULL UNIQUE); +GO + +DROP TABLE t_unsupported_uc1; +DROP TABLE t_unsupported_uc2; +GO + +-- test UNIQUE INDEX/CONSTRAINT is allowed on nullable column +-- if escap_hatch_unique_constraint is set to ignore +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_unique_constraint', 'ignore'; +GO + +CREATE TABLE t_unsupported_uc1(a int, b varchar(10)); +GO + +CREATE UNIQUE INDEX i_unsupported_uc1 on t_unsupported_uc1(b); +GO + +ALTER TABLE t_unsupported_uc1 ADD CONSTRAINT UQ_a UNIQUE (a); +GO + +CREATE TABLE t_unsupported_uc2(a int UNIQUE, b varchar(10) UNIQUE); +GO + +DROP TABLE t_unsupported_uc1 +DROP TABLE t_unsupported_uc2 +GO + +-- escape hatch escape_hatch_index_columnstore +-- 'strict' is default + +CREATE TABLE t_unsupported_cs1(a int, b int); +GO +CREATE COLUMNSTORE INDEX i_unsupported_cs1 on t_unsupported_cs1(a); +GO +DROP TABLE t_unsupported_cs1 +GO + +SELECT set_config('babelfishpg_tsql.escape_hatch_index_columnstore', 'ignore', 'false') +GO + +CREATE TABLE t_unsupported_cs1(a int, b int); +GO +CREATE COLUMNSTORE INDEX i_unsupported_cs1 on t_unsupported_cs1(a); +GO +DROP TABLE t_unsupported_cs1 +GO + +SELECT set_config('babelfishpg_tsql.escape_hatch_index_columnstore', 'strict', 'false') +GO + + +-- escape hatch escape_hatch_for_replication +-- 'strict' is default + +CREATE TABLE t_unsupported_fr1(a int FOR REPLICATION); +GO + +CREATE TABLE t_unsupported_fr2(a int); +GO +ALTER TABLE t_unsupported_fr2 ADD b int NOT FOR REPLICATION; +GO +DROP TABLE t_unsupported_fr2; +GO + +CREATE PROCEDURE p_unsupported_fr1 (@v int) FOR REPLICATION AS BEGIN PRINT CAST(@v AS VARCHAR(10)) END; +GO + +CREATE TABLE t_unsupported_fr3(a int); +GO +CREATE TRIGGER tr_unsupported_fr3 on t_unsupported_fr3 AFTER INSERT NOT FOR REPLICATION AS print 'triggered'; +GO +DROP TABLE t_unsupported_fr3; +GO + +SELECT set_config('babelfishpg_tsql.escape_hatch_for_replication', 'ignore', 'false') +GO + +CREATE TABLE t_unsupported_fr1(a int FOR REPLICATION); +GO +DROP TABLE t_unsupported_fr1; +GO + +CREATE TABLE t_unsupported_fr2(a int); +GO +ALTER TABLE t_unsupported_fr2 ADD b int NOT FOR REPLICATION; +GO +DROP TABLE t_unsupported_fr2; +GO + +CREATE PROCEDURE p_unsupported_fr1 (@v int) FOR REPLICATION AS BEGIN PRINT CAST(@v AS VARCHAR(10)) END; +GO +DROP PROCEDURE p_unsupported_fr1; +GO + +CREATE TABLE t_unsupported_fr3(a int); +GO +CREATE TRIGGER tr_unsupported_fr3 on t_unsupported_fr3 AFTER INSERT NOT FOR REPLICATION AS print 'triggered'; +GO +DROP TABLE t_unsupported_fr3; +GO + +SELECT set_config('babelfishpg_tsql.escape_hatch_for_replication', 'strict', 'false') +GO + + +-- escape hatch escape_hatch_rowguidcol_column +-- 'ignore' is default + +CREATE TABLE t_unsupported_gc1(a int ROWGUIDCOL); +GO +DROP TABLE t_unsupported_gc1; +GO + +CREATE TABLE t_unsupported_gc2(a int); +GO +ALTER TABLE t_unsupported_gc2 ADD b int ROWGUIDCOL; +GO +DROP TABLE t_unsupported_gc2; +GO + +SELECT set_config('babelfishpg_tsql.escape_hatch_rowguidcol_column', 'strict', 'false') +GO + +CREATE TABLE t_unsupported_gc1(a int ROWGUIDCOL); +GO + +CREATE TABLE t_unsupported_gc2(a int); +GO +ALTER TABLE t_unsupported_gc2 ADD b int ROWGUIDCOL; +GO +DROP TABLE t_unsupported_gc2; +GO + +SELECT set_config('babelfishpg_tsql.escape_hatch_rowguidcol_column', 'ignore', 'false') +GO + + +-- escape hatch escape_hatch_sparse_column (incorporated with storage_options) +-- 'ignore' is default + +CREATE TABLE t_unsupported_sc1(a int SPARSE, b int); +GO +DROP TABLE t_unsupported_sc1 +GO + +CREATE TABLE t_unsupported_sc2(a int); +GO +ALTER TABLE t_unsupported_sc2 ADD b int SPARSE; +GO +DROP TABLE t_unsupported_sc2; +GO + +SELECT set_config('babelfishpg_tsql.escape_hatch_storage_options', 'strict', 'false') +GO + +CREATE TABLE t_unsupported_sc1(a int SPARSE, b int); +GO + +CREATE TABLE t_unsupported_sc2(a int); +GO +ALTER TABLE t_unsupported_sc2 ADD b int SPARSE; +GO +DROP TABLE t_unsupported_sc2; +GO + +SELECT set_config('babelfishpg_tsql.escape_hatch_storage_options', 'ignore', 'false') +GO + + +-- escape hatch: filestream. (incorporated into storage_options) +-- 'ignore' is default + +CREATE TABLE t_unsupported_fs1(a int FILESTREAM, b int); +GO +DROP TABLE t_unsupported_fs1 +GO + +CREATE TABLE t_unsupported_fs2(a int); +GO +ALTER TABLE t_unsupported_fs2 ADD b int FILESTREAM; +GO +DROP TABLE t_unsupported_fs2; +GO + +SELECT set_config('babelfishpg_tsql.escape_hatch_storage_options', 'strict', 'false') +GO + +CREATE TABLE t_unsupported_fs1(a int FILESTREAM, b int); +GO + +CREATE TABLE t_unsupported_fs2(a int); +GO +ALTER TABLE t_unsupported_fs2 ADD b int FILESTREAM; +GO +DROP TABLE t_unsupported_fs2; +GO + +SELECT set_config('babelfishpg_tsql.escape_hatch_storage_options', 'ignore', 'false') +GO + + +-- escape hatch: escape_hatch_fillfactor. (incorporated with storage_options) +-- 'ignore' is default + +CREATE TABLE t_unsupported_ff1(a int, primary key(a) with fillfactor=50); +GO +DROP TABLE t_unsupported_ff1 +GO + +CREATE TABLE t_unsupported_ff2(a int primary key with fillfactor=50); +GO +DROP TABLE t_unsupported_ff2 +GO + +CREATE TABLE t_unsupported_ff3(a int); +GO +ALTER TABLE t_unsupported_ff3 ADD PRIMARY KEY(a) with fillfactor=50; +GO +DROP TABLE t_unsupported_ff3; +GO + +SELECT set_config('babelfishpg_tsql.escape_hatch_storage_options', 'strict', 'false') +GO + +CREATE TABLE t_unsupported_ff1(a int, primary key(a) with fillfactor=50); +GO + +CREATE TABLE t_unsupported_ff2(a int primary key with fillfactor=50); +GO + +CREATE TABLE t_unsupported_ff3(a int); +GO +ALTER TABLE t_unsupported_ff3 ADD PRIMARY KEY(a) with fillfactor=50; +GO +DROP TABLE t_unsupported_ff3; +GO + +SELECT set_config('babelfishpg_tsql.escape_hatch_storage_options', 'ignore', 'false') +GO + + +-- escape hatch: escape_hatch_storage_options (especially index option). +-- 'ignore' is default + +CREATE TABLE t_unsupported_so1(a int, primary key(a) with data_compression=none); +GO +DROP TABLE t_unsupported_so1 +GO + +CREATE TABLE t_unsupported_so2(a int, primary key(a) with pad_index=on); +GO +DROP TABLE t_unsupported_so2 +GO + +CREATE TABLE t_unsupported_so3(a int, primary key(a) with ignore_dup_key=on); +GO +DROP TABLE t_unsupported_so3 +GO + +CREATE TABLE t_unsupported_so4(a int, primary key(a) with STATISTICS_NORECOMPUTE=on); +GO +DROP TABLE t_unsupported_so4 +GO + +CREATE TABLE t_unsupported_so5(a int, primary key(a) with STATISTICS_INCREMENTAL=on); +GO +DROP TABLE t_unsupported_so5 +GO + +CREATE TABLE t_unsupported_so6(a int, primary key(a) with DROP_EXISTING=on); +GO + +CREATE TABLE t_unsupported_so7(a int, primary key(a) with ONLINE=on); +GO + +CREATE TABLE t_unsupported_so8(a int, primary key(a) with RESUMABLE=on, ONLINE=on); +GO + +CREATE TABLE t_unsupported_so9(a int, primary key(a) with (MAX_DURATION=60, ONLINE=on)); +GO + +CREATE TABLE t_unsupported_so10(a int, primary key(a) with (ALLOW_ROW_LOCKS=on)); +GO +DROP TABLE t_unsupported_so10; +GO + +CREATE TABLE t_unsupported_so11(a int, primary key(a) with (ALLOW_PAGE_LOCKS=on)); +GO +DROP TABLE t_unsupported_so11; +GO + +CREATE TABLE t_unsupported_so12(a int, primary key(a) with (OPTIMIZE_FOR_SEQUENTIAL_KEY=on)); +GO +DROP TABLE t_unsupported_so12; +GO + +CREATE TABLE t_unsupported_so13(a int, primary key(a) with (MAXDOP=40)); +GO +DROP TABLE t_unsupported_so13; +GO + +-- multiple options +CREATE TABLE t_unsupported_so14(a int, primary key(a) with data_compression=none, fillfactor=50); +GO +DROP TABLE t_unsupported_so14 +GO + +-- create index +CREATE TABLE t_unsupported_so15(a int); +GO +CREATE INDEX i_unsupported_so15 on t_unsupported_so15(a) with data_compression=none; +GO +DROP TABLE t_unsupported_so15 +GO + +-- create database with filestream +CREATE DATABASE db_unsupported1 WITH FILESTREAM (DIRECTORY_NAME = '/tmp') +GO +DROP DATABASE db_unsupported1; +GO + +SELECT set_config('babelfishpg_tsql.escape_hatch_storage_options', 'strict', 'false') +GO + +CREATE TABLE t_unsupported_so1(a int, primary key(a) with data_compression=none); +GO + +CREATE TABLE t_unsupported_so2(a int, primary key(a) with pad_index=on); +GO + +CREATE TABLE t_unsupported_so3(a int, primary key(a) with ignore_dup_key=on); +GO + +CREATE TABLE t_unsupported_so4(a int, primary key(a) with STATISTICS_NORECOMPUTE=on); +GO + +CREATE TABLE t_unsupported_so5(a int, primary key(a) with STATISTICS_INCREMENTAL=on); +GO + +CREATE TABLE t_unsupported_so6(a int, primary key(a) with DROP_EXISTING=on); +GO + +CREATE TABLE t_unsupported_so7(a int, primary key(a) with ONLINE=on); +GO + +CREATE TABLE t_unsupported_so8(a int, primary key(a) with RESUMABLE=on, ONLINE=on); +GO + +CREATE TABLE t_unsupported_so9(a int, primary key(a) with (MAX_DURATION=60, ONLINE=on)); +GO + +CREATE TABLE t_unsupported_so10(a int, primary key(a) with (ALLOW_ROW_LOCKS=on)); +GO + +CREATE TABLE t_unsupported_so11(a int, primary key(a) with (ALLOW_PAGE_LOCKS=on)); +GO + +CREATE TABLE t_unsupported_so12(a int, primary key(a) with (OPTIMIZE_FOR_SEQUENTIAL_KEY=on)); +GO + +CREATE TABLE t_unsupported_so13(a int, primary key(a) with (MAXDOP=40)); +GO + +-- multiple options +CREATE TABLE t_unsupported_so14(a int, primary key(a) with data_compression=none, fillfactor=50); +GO + +-- create index +CREATE TABLE t_unsupported_so15(a int); +GO +CREATE INDEX i_unsupported_so15 on t_unsupported_so15(a) with data_compression=none; +GO +DROP TABLE t_unsupported_so15 +GO + +-- create database with filestream +CREATE DATABASE db_unsupported1 WITH FILESTREAM (DIRECTORY_NAME = '/tmp') +GO + +SELECT set_config('babelfishpg_tsql.escape_hatch_storage_options', 'ignore', 'false') +GO + + +-- escape hatch: escape_hatch_nocheck_add_constraint. +-- 'strict' is default + +CREATE TABLE t_unsupported_cac1(a int, b int); +GO +ALTER TABLE t_unsupported_cac1 WITH CHECK ADD constraint chk1 check (a > 0) +GO +ALTER TABLE t_unsupported_cac1 WITH NOCHECK ADD constraint chk2 check (b < 0) +GO +DROP TABLE t_unsupported_cac1 +GO + +SELECT set_config('babelfishpg_tsql.escape_hatch_nocheck_add_constraint', 'ignore', 'false') +GO + +CREATE TABLE t_unsupported_cac1(a int, b int); + + + + +SELECT set_config('babelfishpg_tsql.escape_hatch_storage_options', 'strict', 'false') +GO + +CREATE TABLE t_unsupported_so1(a int, primary key(a) with data_compression=none); +GO + +SELECT set_config('babelfishpg_tsql.escape_hatch_storage_options', 'ignore', 'false') +GO + + +-- escape hatch: escape_hatch_nocheck_add_constraint. +-- 'strict' is default + +CREATE TABLE t_unsupported_cac1(a int, b int); +GO +ALTER TABLE t_unsupported_cac1 WITH CHECK ADD constraint chk1 check (a > 0) +GO +ALTER TABLE t_unsupported_cac1 WITH NOCHECK ADD constraint chk2 check (b < 0) +GO +DROP TABLE t_unsupported_cac1 +GO + +SELECT set_config('babelfishpg_tsql.escape_hatch_nocheck_add_constraint', 'ignore', 'false') +GO + +CREATE TABLE t_unsupported_cac1(a int, b int); +GO +ALTER TABLE t_unsupported_cac1 WITH CHECK ADD constraint chk1 check (a > 0) +GO +ALTER TABLE t_unsupported_cac1 WITH NOCHECK ADD constraint chk2 check (b < 0) +GO +INSERT INTO t_unsupported_cac1 VALUES (0, 0); +GO +DROP TABLE t_unsupported_cac1 +GO + +SELECT set_config('babelfishpg_tsql.escape_hatch_nocheck_add_constraint', 'strict', 'false') +GO + + +-- escape hatch: escape_hatch_nocheck_existing_constraint. +-- 'strict' is default + +CREATE TABLE t_unsupported_cec1(a int, b int); +GO +INSERT INTO t_unsupported_cec1 values (0, 0); +GO +ALTER TABLE t_unsupported_cec1 ADD constraint chk1 check (a > 0) +GO +ALTER TABLE t_unsupported_cec1 CHECK constraint chk1 +GO +DROP TABLE t_unsupported_cec1 +GO + +SELECT set_config('babelfishpg_tsql.escape_hatch_nocheck_existing_constraint', 'ignore', 'false') +GO + +CREATE TABLE t_unsupported_cec1(a int, b int); +GO +INSERT INTO t_unsupported_cec1 values (0, 0); +GO +ALTER TABLE t_unsupported_cec1 ADD constraint chk1 check (a > 0) +GO +ALTER TABLE t_unsupported_cec1 CHECK constraint chk1 +GO +DROP TABLE t_unsupported_cec1 +GO + +SELECT set_config('babelfishpg_tsql.escape_hatch_nocheck_existing_constraint', 'strict', 'false') +GO + +-- escape hatch: escape_hatch_constraint_name_for_default. +-- 'ignore' is deafult + +CREATE TABLE t_unsupported_cd1(a int, b int); +GO +ALTER TABLE t_unsupported_cd1 ADD CONSTRAINT d1 DEFAULT 99 FOR a; +GO +INSERT INTO t_unsupported_cd1(b) VALUES (1); +GO +SELECT * FROM t_unsupported_cd1; +GO +DROP TABLE t_unsupported_cd1; +GO + +SELECT set_config('babelfishpg_tsql.escape_hatch_constraint_name_for_default', 'strict', 'false') +GO + +CREATE TABLE t_unsupported_cd1(a int, b int); +GO +ALTER TABLE t_unsupported_cd1 ADD CONSTRAINT d1 DEFAULT 99 FOR a; +GO +INSERT INTO t_unsupported_cd1(b) VALUES (1); +GO +SELECT * FROM t_unsupported_cd1; +GO +DROP TABLE t_unsupported_cd1; +GO + +SELECT set_config('babelfishpg_tsql.escape_hatch_constraint_name_for_default', 'ignore', 'false') +GO + +-- escape hatch: table_hints +-- 'ignore' is default. +-- we have separate test already so briefly check simple cases here. + +CREATE TABLE t_unsupported_th1(a int); +GO +INSERT INTO t_unsupported_th1 WITH (INDEX=i1) VALUES (1), (2); +GO +UPDATE t_unsupported_th1 WITH (INDEX=i1) SET a = 3 WHERE a=2; +GO +DELETE FROM t_unsupported_th1 WITH (INDEX=i1) WHERE a = 1; +GO +SELECT * FROM t_unsupported_th1 WITH (INDEX=i1); +GO +DROP TABLE t_unsupported_th1; +GO + +SELECT set_config('babelfishpg_tsql.escape_hatch_table_hints', 'strict', 'false') +GO + +CREATE TABLE t_unsupported_th1(a int); +GO +INSERT INTO t_unsupported_th1 WITH (INDEX=i1) VALUES (1), (2); +GO +UPDATE t_unsupported_th1 WITH (INDEX=i1) SET a = 3 WHERE a=2; +GO +DELETE FROM t_unsupported_th1 WITH (INDEX=i1) WHERE a = 1; +GO +SELECT * FROM t_unsupported_th1 WITH (INDEX=i1); +GO +DROP TABLE t_unsupported_th1; +GO + +SELECT set_config('babelfishpg_tsql.escape_hatch_table_hints', 'ignore', 'false') +GO + + +-- escape hatch: query_hints +-- 'ignore' is default. + +CREATE TABLE t_unsupported_qh1(a int); +GO +INSERT INTO t_unsupported_qh1 VALUES (1), (2) OPTION (MERGE JOIN) +GO +UPDATE t_unsupported_qh1 SET a = 3 WHERE a=2 OPTION (HASH GROUP); +GO +DELETE FROM t_unsupported_qh1 WHERE a = 1 OPTION (CONCAT UNION); +GO +SELECT * FROM t_unsupported_qh1 OPTION (FORCE ORDER); +GO +DROP TABLE t_unsupported_qh1; +GO + + +SELECT set_config('babelfishpg_tsql.escape_hatch_query_hints', 'strict', 'false') +GO + +CREATE TABLE t_unsupported_qh1(a int); +GO +INSERT INTO t_unsupported_qh1 VALUES (1), (2) OPTION (MERGE JOIN) +GO +UPDATE t_unsupported_qh1 SET a = 3 WHERE a=2 OPTION (HASH GROUP); +GO +DELETE FROM t_unsupported_qh1 WHERE a = 1 OPTION (CONCAT UNION); +GO +SELECT * FROM t_unsupported_qh1 OPTION (FORCE ORDER); +GO +DROP TABLE t_unsupported_qh1; +GO + +SELECT set_config('babelfishpg_tsql.escape_hatch_query_hints', 'ignore', 'false') +GO + + +-- escape hatch: join_hints +-- 'ignore' is default. + +CREATE TABLE t_unsupported_jh1(a int); +CREATE TABLE t_unsupported_jh2(a int); +GO +INSERT INTO t_unsupported_jh1 values (1), (2); +INSERT INTO t_unsupported_jh2 values (1), (3); +GO +SELECT * FROM t_unsupported_jh1 t1 INNER HASH JOIN t_unsupported_jh2 t2 ON t1.a=t2.a; +GO +DROP TABLE t_unsupported_jh1; +DROP TABLE t_unsupported_jh2; +GO + +SELECT set_config('babelfishpg_tsql.escape_hatch_join_hints', 'strict', 'false') +GO + +CREATE TABLE t_unsupported_jh1(a int); +CREATE TABLE t_unsupported_jh2(a int); +GO +INSERT INTO t_unsupported_jh1 values (1), (2); +INSERT INTO t_unsupported_jh2 values (1), (3); +GO +SELECT * FROM t_unsupported_jh1 t1 INNER HASH JOIN t_unsupported_jh2 t2 ON t1.a=t2.a; +GO +DROP TABLE t_unsupported_jh1; +DROP TABLE t_unsupported_jh2; +GO + +SELECT set_config('babelfishpg_tsql.escape_hatch_join_hints', 'ignore', 'false') +GO + + +-- test of sp_babelfish_configure + +EXEC sp_babelfish_configure; +GO + +-- short name +EXEC sp_babelfish_configure 'escape_hatch_schemabinding_function'; +GO + +-- full name +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_schemabinding_function'; +GO + +-- with wildcard +EXEC sp_babelfish_configure '%'; +GO + +EXEC sp_babelfish_configure 'babelfishpg_tsql.%'; +GO + +EXEC sp_babelfish_configure 'escape_hatch_schemabinding_%'; +GO + +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_schemabinding_%'; +GO + +-- set +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_schemabinding_function', 'strict'; +GO + +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_schemabinding_function'; +GO + +-- now should throw an error +CREATE FUNCTION f_unsupported_1 (@v int) RETURNS INT AS BEGIN RETURN @v+1 END; +GO + +-- set with wildcard +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_schemabinding_%', 'strict'; +GO + +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_schemabinding_%'; +GO + +-- should throw an error +CREATE PROCEDURE p_unsupported_1 (@v int) AS BEGIN PRINT CAST(@v AS VARCHAR(10)) END; +GO + +-- reset +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_schemabinding_%', 'ignore'; +GO + +-- same tests with no prefix +EXEC sp_babelfish_configure 'escape_hatch_schemabinding_function', 'strict'; +GO + +EXEC sp_babelfish_configure 'escape_hatch_schemabinding_function'; +GO + +-- now should throw an error +CREATE FUNCTION f_unsupported_1 (@v int) RETURNS INT AS BEGIN RETURN @v+1 END; +GO + +-- set with wildcard +EXEC sp_babelfish_configure 'escape_hatch_schemabinding_%', 'strict'; +GO + +EXEC sp_babelfish_configure 'escape_hatch_schemabinding_%'; +GO + +-- should throw an error +CREATE PROCEDURE p_unsupported_1 (@v int) AS BEGIN PRINT CAST(@v AS VARCHAR(10)) END; +GO + +-- reset +EXEC sp_babelfish_configure 'escape_hatch_schemabinding_%', 'ignore'; +GO + +-- server option +EXEC sp_babelfish_configure 'escape_hatch_schemabinding_%', 'strict', 'server'; +GO + +EXEC sp_babelfish_configure 'escape_hatch_schemabinding_%'; +GO +select config_value from (select unnest(setconfig) config_value from pg_db_role_setting) t where config_value like '%escape_hatch_schemabinding_%' order by config_value; +GO + +EXEC sp_babelfish_configure 'escape_hatch_schemabinding_function', 'ignore', 'server'; +GO + +EXEC sp_babelfish_configure 'escape_hatch_schemabinding_%'; +GO +select config_value from (select unnest(setconfig) config_value from pg_db_role_setting) t where config_value like '%escape_hatch_schemabinding_%' order by config_value; +GO + +-- reset +EXEC sp_babelfish_configure 'escape_hatch_schemabinding_%', 'ignore', 'server'; +GO + +EXEC sp_babelfish_configure 'escape_hatch_schemabinding_%'; +GO +select config_value from (select unnest(setconfig) config_value from pg_db_role_setting) t where config_value like '%escape_hatch_schemabinding_%' order by config_value; +GO + +-- non-existing guc +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_XX', 'ignore'; +GO + +-- invalid server option +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_schemabinding_%', 'ignore', 'invalid'; +GO + +-- test automatically generated message for unsupported DDL +CREATE PARTITION FUNCTION f_unsupported_1(datetime) AS RANGE RIGHT FOR VALUES (N'2017-07-11T00:00:00.000', N'2017-07-12T00:00:00.000', N'2017-07-13T00:00:00.000'); +GO + +ALTER AUTHORIZATION ON a1 TO SCHEMA OWNER; +GO + +-- kill (BABEL-2159) +KILL 1; +GO + +-- apply +SELECT * FROM t1 CROSS APPLY (SELECT * FROM Employee E WHERE E.DepartmentID = D.DepartmentID) A +GO + +-- alter view (BABEL-2017) +CREATE TABLE t_babel_2017(a int, b int); +GO +CREATE VIEW v_babel_2017 AS SELECT * FROM t_babel_2017; +GO +ALTER VIEW v_babel_2017 AS SELECT a FROM t_babel_2017; +GO +CREATE OR ALTER VIEW v_babel_2017 AS SELECT b FROM t_babel_2017; +GO +DROP VIEW v_babel_2017; +GO +DROP TABLE t_babel_2017; +GO + + +-- alter trigger (2110) +CREATE TABLE t2110a(c int); +CREATE TABLE t2110b(c int); +GO +CREATE TRIGGER trigger2110 ON t2110a FOR INSERT AS SELECT * FROM t2110a; +GO +ALTER TRIGGER trigger2110 ON t2110b FOR INSERT AS SELECT * FROM t2110a; +GO +DROP TABLE t2110a, t2110b; +GO + + +-- alter schema transfer (33144) +CREATE SCHEMA s33144; +GO +CREATE TABLE t33144(a int); +GO +ALTER SCHEMA s33144 TRANSFER t33144; +GO +DROP TABLE t33144; +GO +DROP SCHEMA s33144; +GO + + +-- alter table add PERSISTED (4919) +CREATE TABLE t4919(c1 int, c2 varchar(1)); +GO +ALTER TABLE t4919 ALTER COLUMN c2 varchar(1) ADD PERSISTED; +GO +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 +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 +DROP TABLE t488; +GO + + +-- CREATE DATBASE COLLATE (448) +CREATE DATABASE t448 COLLATE NOT_VALID_COLLATION; +GO + + +-- unsupported index option in CREATE INDEX (1070) +CREATE TABLE t1070(c1 int, c2 int); +GO +CREATE INDEX i1070 on t1070 (c1,c2) with allow_dup_row; +GO +DROP TABLE t1070 +GO + +-- XML (8113) +CREATE TABLE t8113_x(a XML); +GO +CREATE TABLE t8113_a(a int); +GO +UPDATE t8113_a SET a.query('.'); +GO +DROP TABLE t8113_x; +GO +DROP TABLE t8113_a; +GO + +-- NEXT VALUE FORa (11738) +CREATE SEQUENCE s11738 AS INT START WITH 5 INCREMENT BY 1; +GO +PRINT RIGHT('000000' + CAST(NEXT VALUE FOR s11738 AS NVARCHAR), 6); +GO +DROP SEQUENCE s11738; +GO + +-- APPLY (4101) +CREATE TABLE t4101(c1 VARCHAR(60), c2 INT) +GO +CREATE FUNCTION f4101(@n1 INT, @n2 INT) RETURNS TABLE AS RETURN (SELECT 1 AS ret); +GO +SELECT t.c1, tmp.t2 FROM t4101 t CROSS APPLY (SELECT SUM(c2) AS t2)tmp +GO +DROP FUNCTION f4101; +GO +DROP TABLE t4101; +GO + +-- XMLNAMESPACES (6869, 6870, 6871) +WITH XMLNAMESPACES ('test.com' AS ns1, 'test2.com' AS ns1) SELECT 'test' AS 'TestAttr' FOR XML RAW +GO +WITH XMLNAMESPACES ('test.com' AS n@s1) SELECT 'test' AS 'TestAttr' FOR XML RAW +GO +WITH XMLNAMESPACES ('test.com' AS xmlns) SELECT 'test' AS 'TestAttr' FOR XML RAW +GO + +-- BEGIN ATOMIC (10782) +create proc p10782 AS begin atomic with (transaction isolation level = snapshot, language = N'us_english') SELECT 1; end +GO + +-- DBCC (12608) +CREATE DATABASE d12608; +GO +DBCC CLONEDATABASE (d12608, d12608_clone); +GO +DROP DATABASE d12608; +GO + +-- ALTER WORKLOAD GROUP (10915) +ALTER WORKLOAD GROUP internal WITH (REQUEST_MAX_MEMORY_GRANT_PERCENT = 45); +GO + +-- $IDENTITY and $ROWGUID +SELECT $IDENTITY; +GO + +SELECT $ROWGUID; +GO + +-- TIMESTAMP and ROWVERSION +CREATE TABLE t_ts(a timestamp); +GO +CREATE TABLE t_ts2(a pg_catalog.timestamp); -- it's fine +GO +DROP TABLE t_ts2; +GO +CREATE TABLE t_rv(a ROWVERSION); +GO +CREATE PROCEDURE p_t2 (@v timestamp) AS BEGIN PRINT CAST(@v AS VARCHAR(10)) END; +GO + +-- CREATE TYPE WITH (10788) +CREATE TYPE type10788 AS TABLE (c1 INT) WITH (DATA_COMPRESSION = NONE) +GO + +-- ALTER TABLE ALTER COLUMN +CREATE TABLE t5074(a SMALLINT NOT NULL IDENTITY) +GO +ALTER TABLE t5074 ADD CONSTRAINT PK_t5074 PRIMARY KEY (a) +GO +ALTER TABLE t5074 ALTER COLUMN a INT NOT NULL +GO +DROP TABLE t5074 +GO + +-- XMLDATA +SELECT 'abc' AS 'TestAttr' FOR XML RAW, XMLDATA, ROOT; +GO + +-- EXECUTE AS (487) +CREATE TABLE t487(c1 int) +GO +CREATE FUNCTION f487() RETURNS TABLE WITH EXECUTE AS 'user' AS +RETURN (SELECT * FROM t487) +GO +DROP TABLE t487 +GO + +-- DEFAULT arguemnt +select func1(DEFAULT); +GO + +EXEC proc1 DEFAULT; +GO + +-- NATIONAL/VARYING (BABEL-2360/2361) +declare @v char varying(10); +GO +declare @v char varying; +GO +declare @v character varying(10); +GO +declare @v character varying; +GO +declare @v nchar varying(10); +GO +declare @v nchar varying; +GO +declare @v national char varying(10); +GO +declare @v national char varying; +GO +declare @v national char(10); +GO +declare @v national char; +GO + +-- unsupported system procedures +sp_help 'a' +GO + +EXEC sp_help 'a' +GO + +CREATE TABLE t_unsupported_sp (a int); +GO +INSERT INTO t_unsupported_sp EXEC sp_help 'a' +GO +DROP TABLE t_unsupported_sp; +GO diff --git a/contrib/test/JDBC/input/BABEL_2429.sql b/contrib/test/JDBC/input/BABEL_2429.sql new file mode 100644 index 00000000000..30c32d26921 --- /dev/null +++ b/contrib/test/JDBC/input/BABEL_2429.sql @@ -0,0 +1,30 @@ +create login newlogin with password = '12345678' , default_database=master; +go + +select db_name(), user_name() +go + +create database zzz +go + +drop database zzz +go + +create login newlogin2 with password = '12345678' , default_database=master; +go + +create login newlogin3 with password = '12345678' , default_database=master; +go + +create database zzz +go + +drop database zzz +go + +drop login newlogin +go +drop login newlogin2 +go +drop login newlogin3 +go diff --git a/contrib/test/JDBC/input/Babel-2655.sql b/contrib/test/JDBC/input/Babel-2655.sql new file mode 100644 index 00000000000..8c84c311eb6 --- /dev/null +++ b/contrib/test/JDBC/input/Babel-2655.sql @@ -0,0 +1,26 @@ +CREATE TABLE t2218(c1 INT) +INSERT INTO t2218 VALUES (2218) +go + +CREATE FUNCTION f2218() RETURNS INT AS BEGIN DECLARE @return INT SET @return = 0 SELECT @return=c1 from t2218 RETURN @return END +go + +select f2218() +go + +drop function f2218 +go + +CREATE PROCEDURE p2655 +AS +BEGIN + DECLARE @return INT SET @return = 0 SELECT @return=c1 from t2218 +END +GO + +exec p2655 +go + +drop procedure p2655 +drop table t2218 +go \ No newline at end of file diff --git a/contrib/test/JDBC/input/ErrorMapping/102_1.sql b/contrib/test/JDBC/input/ErrorMapping/102_1.sql new file mode 100644 index 00000000000..370c6a84795 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/102_1.sql @@ -0,0 +1,316 @@ +USE master; +GO + +-- simple batch start + +CREATE TABLE t102__2(c1 int); +GO +SELuCT * FROM t +GO +DROP TABLE t102__2; +GO + +DROP TABLE @t102; +GO + +begin transaction +GO +CREATE TABLE t102__2(c1 int); +GO +SELuCT * FROM t +GO + +if (@@trancount > 0) select cast('Txn is not rolledback' as text) else select cast('Txn is rolledback' as text) +GO + +if (@@trancount > 0) rollback tran +GO + +DROP TABLE t102__2; +GO + +DROP TABLE @t102; +GO + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + +CREATE TABLE t102__2(c1 int); +GO +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +SELuCT * FROM t +end +GO + +DROP TABLE t102__2; +GO + +DROP TABLE @t102; +GO + +create table error_mapping.temp2 (a int) +GO + +CREATE TABLE t102__2(c1 int); +GO +insert into error_mapping.temp2 values(1) +SELuCT * FROM t +GO + +DROP TABLE t102__2; +GO + +DROP TABLE @t102; +GO + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + +CREATE TABLE t102__2(c1 int); +GO +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO + +DROP TABLE t102__2; +GO + +DROP TABLE @t102; +GO + +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 + +-- Parse analysis phase end +GO + +-- compile time error portion + +-- Executing test error_mapping.ErrorHandling1 +CREATE TABLE t102__2(c1 int); +GO + +create procedure error_mapping.ErrorHandling1 as +begin +SELuCT * FROM t +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 +DROP TABLE t102__2; +GO + +DROP TABLE @t102; +GO + + +CREATE TABLE t102__2(c1 int); +GO +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +SELuCT * FROM t +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 + +GO +DROP TABLE t102__2; +GO + +DROP TABLE @t102; +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE t102__2(c1 int); +GO +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +SELuCT * FROM t +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 + +GO +DROP TABLE t102__2; +GO + +DROP TABLE @t102; +GO +set xact_abort OFF; +GO + +-- comiple time error portion end -- +-- Next portion is for runtime error -- + +-- Executing test error_mapping.ErrorHandling10000000 +CREATE TABLE t102__2(c1 int); +GO + +create procedure error_mapping.ErrorHandling1 as +begin +SELuCT * FROM t +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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 +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 +DROP TABLE t102__2; +GO + +DROP TABLE @t102; +GO + + +set xact_abort ON; +GO +-- Executing test error_mapping.ErrorHandling10000000 +CREATE TABLE t102__2(c1 int); +GO + +create procedure error_mapping.ErrorHandling1 as +begin +SELuCT * FROM t +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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 +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 +DROP TABLE t102__2; +GO + +DROP TABLE @t102; +GO + + + +set xact_abort OFF; +GO + +-- Error classification is done -- + +-- Executing test error_mapping.ErrorHandling10000000 +CREATE TABLE t102__2(c1 int); +GO + +begin try +select 1 +SELuCT * FROM t +end try +begin catch + select xact_state(); +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 +DROP TABLE t102__2; +GO + +DROP TABLE @t102; +GO + + + +GO +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/input/ErrorMapping/102_2.sql b/contrib/test/JDBC/input/ErrorMapping/102_2.sql new file mode 100644 index 00000000000..654228e0368 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/102_2.sql @@ -0,0 +1,326 @@ +USE master; +GO + +-- simple batch start + +CREATE TABLE t102__2(c1 int); +GO +--Windowing framing cannot have negative PRECEEDING +SELECT *, SUM(c1) OVER (ORDER BY c1 ROWS BETWEEN -1 PRECEDING AND 3 FOLLOWING) FROM t102__2; +GO +DROP TABLE t102__2; +GO + +DROP TABLE @t102; +GO + +begin transaction +GO +CREATE TABLE t102__2(c1 int); +GO +--Windowing framing cannot have negative PRECEEDING +SELECT *, SUM(c1) OVER (ORDER BY c1 ROWS BETWEEN -1 PRECEDING AND 3 FOLLOWING) FROM t102__2; +GO + +if (@@trancount > 0) select cast('Txn is not rolledback' as text) else select cast('Txn is rolledback' as text) +GO + +if (@@trancount > 0) rollback tran +GO + +DROP TABLE t102__2; +GO + +DROP TABLE @t102; +GO + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + +CREATE TABLE t102__2(c1 int); +GO +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +--Windowing framing cannot have negative PRECEEDING +SELECT *, SUM(c1) OVER (ORDER BY c1 ROWS BETWEEN -1 PRECEDING AND 3 FOLLOWING) FROM t102__2; +end +GO + +DROP TABLE t102__2; +GO + +DROP TABLE @t102; +GO + +create table error_mapping.temp2 (a int) +GO + +CREATE TABLE t102__2(c1 int); +GO +insert into error_mapping.temp2 values(1) +--Windowing framing cannot have negative PRECEEDING +SELECT *, SUM(c1) OVER (ORDER BY c1 ROWS BETWEEN -1 PRECEDING AND 3 FOLLOWING) FROM t102__2; +GO + +DROP TABLE t102__2; +GO + +DROP TABLE @t102; +GO + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + +CREATE TABLE t102__2(c1 int); +GO +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO + +DROP TABLE t102__2; +GO + +DROP TABLE @t102; +GO + +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 + +-- Parse analysis phase end +GO + +-- compile time error portion + +-- Executing test error_mapping.ErrorHandling1 +CREATE TABLE t102__2(c1 int); +GO + +create procedure error_mapping.ErrorHandling1 as +begin +--Windowing framing cannot have negative PRECEEDING +SELECT *, SUM(c1) OVER (ORDER BY c1 ROWS BETWEEN -1 PRECEDING AND 3 FOLLOWING) FROM t102__2; +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 +DROP TABLE t102__2; +GO + +DROP TABLE @t102; +GO + + +CREATE TABLE t102__2(c1 int); +GO +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +--Windowing framing cannot have negative PRECEEDING +SELECT *, SUM(c1) OVER (ORDER BY c1 ROWS BETWEEN -1 PRECEDING AND 3 FOLLOWING) FROM t102__2; +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 + +GO +DROP TABLE t102__2; +GO + +DROP TABLE @t102; +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE t102__2(c1 int); +GO +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +--Windowing framing cannot have negative PRECEEDING +SELECT *, SUM(c1) OVER (ORDER BY c1 ROWS BETWEEN -1 PRECEDING AND 3 FOLLOWING) FROM t102__2; +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 + +GO +DROP TABLE t102__2; +GO + +DROP TABLE @t102; +GO +set xact_abort OFF; +GO + +-- comiple time error portion end -- +-- Next portion is for runtime error -- + +-- Executing test error_mapping.ErrorHandling10000000 +CREATE TABLE t102__2(c1 int); +GO + +create procedure error_mapping.ErrorHandling1 as +begin +--Windowing framing cannot have negative PRECEEDING +SELECT *, SUM(c1) OVER (ORDER BY c1 ROWS BETWEEN -1 PRECEDING AND 3 FOLLOWING) FROM t102__2; +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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 +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 +DROP TABLE t102__2; +GO + +DROP TABLE @t102; +GO + + +set xact_abort ON; +GO +-- Executing test error_mapping.ErrorHandling10000000 +CREATE TABLE t102__2(c1 int); +GO + +create procedure error_mapping.ErrorHandling1 as +begin +--Windowing framing cannot have negative PRECEEDING +SELECT *, SUM(c1) OVER (ORDER BY c1 ROWS BETWEEN -1 PRECEDING AND 3 FOLLOWING) FROM t102__2; +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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 +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 +DROP TABLE t102__2; +GO + +DROP TABLE @t102; +GO + + + +set xact_abort OFF; +GO + +-- Error classification is done -- + +-- Executing test error_mapping.ErrorHandling10000000 +CREATE TABLE t102__2(c1 int); +GO + +begin try +select 1 +--Windowing framing cannot have negative PRECEEDING +SELECT *, SUM(c1) OVER (ORDER BY c1 ROWS BETWEEN -1 PRECEDING AND 3 FOLLOWING) FROM t102__2; +end try +begin catch + select xact_state(); +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 +DROP TABLE t102__2; +GO + +DROP TABLE @t102; +GO + + + +GO +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/input/ErrorMapping/102_3.sql b/contrib/test/JDBC/input/ErrorMapping/102_3.sql new file mode 100644 index 00000000000..1bb2b5bc960 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/102_3.sql @@ -0,0 +1,326 @@ +USE master; +GO + +-- simple batch start + +CREATE TABLE t102__2(c1 int); +GO +--Windowing framing cannot have negative FOLLOWING +SELECT *, SUM(c1) OVER (ORDER BY c1 ROWS BETWEEN 1 PRECEDING AND -3 FOLLOWING) FROM t102__2; +GO +DROP TABLE t102__2; +GO + +DROP TABLE @t102; +GO + +begin transaction +GO +CREATE TABLE t102__2(c1 int); +GO +--Windowing framing cannot have negative FOLLOWING +SELECT *, SUM(c1) OVER (ORDER BY c1 ROWS BETWEEN 1 PRECEDING AND -3 FOLLOWING) FROM t102__2; +GO + +if (@@trancount > 0) select cast('Txn is not rolledback' as text) else select cast('Txn is rolledback' as text) +GO + +if (@@trancount > 0) rollback tran +GO + +DROP TABLE t102__2; +GO + +DROP TABLE @t102; +GO + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + +CREATE TABLE t102__2(c1 int); +GO +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +--Windowing framing cannot have negative FOLLOWING +SELECT *, SUM(c1) OVER (ORDER BY c1 ROWS BETWEEN 1 PRECEDING AND -3 FOLLOWING) FROM t102__2; +end +GO + +DROP TABLE t102__2; +GO + +DROP TABLE @t102; +GO + +create table error_mapping.temp2 (a int) +GO + +CREATE TABLE t102__2(c1 int); +GO +insert into error_mapping.temp2 values(1) +--Windowing framing cannot have negative FOLLOWING +SELECT *, SUM(c1) OVER (ORDER BY c1 ROWS BETWEEN 1 PRECEDING AND -3 FOLLOWING) FROM t102__2; +GO + +DROP TABLE t102__2; +GO + +DROP TABLE @t102; +GO + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + +CREATE TABLE t102__2(c1 int); +GO +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO + +DROP TABLE t102__2; +GO + +DROP TABLE @t102; +GO + +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 + +-- Parse analysis phase end +GO + +-- compile time error portion + +-- Executing test error_mapping.ErrorHandling1 +CREATE TABLE t102__2(c1 int); +GO + +create procedure error_mapping.ErrorHandling1 as +begin +--Windowing framing cannot have negative FOLLOWING +SELECT *, SUM(c1) OVER (ORDER BY c1 ROWS BETWEEN 1 PRECEDING AND -3 FOLLOWING) FROM t102__2; +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 +DROP TABLE t102__2; +GO + +DROP TABLE @t102; +GO + + +CREATE TABLE t102__2(c1 int); +GO +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +--Windowing framing cannot have negative FOLLOWING +SELECT *, SUM(c1) OVER (ORDER BY c1 ROWS BETWEEN 1 PRECEDING AND -3 FOLLOWING) FROM t102__2; +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 + +GO +DROP TABLE t102__2; +GO + +DROP TABLE @t102; +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE t102__2(c1 int); +GO +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +--Windowing framing cannot have negative FOLLOWING +SELECT *, SUM(c1) OVER (ORDER BY c1 ROWS BETWEEN 1 PRECEDING AND -3 FOLLOWING) FROM t102__2; +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 + +GO +DROP TABLE t102__2; +GO + +DROP TABLE @t102; +GO +set xact_abort OFF; +GO + +-- comiple time error portion end -- +-- Next portion is for runtime error -- + +-- Executing test error_mapping.ErrorHandling10000000 +CREATE TABLE t102__2(c1 int); +GO + +create procedure error_mapping.ErrorHandling1 as +begin +--Windowing framing cannot have negative FOLLOWING +SELECT *, SUM(c1) OVER (ORDER BY c1 ROWS BETWEEN 1 PRECEDING AND -3 FOLLOWING) FROM t102__2; +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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 +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 +DROP TABLE t102__2; +GO + +DROP TABLE @t102; +GO + + +set xact_abort ON; +GO +-- Executing test error_mapping.ErrorHandling10000000 +CREATE TABLE t102__2(c1 int); +GO + +create procedure error_mapping.ErrorHandling1 as +begin +--Windowing framing cannot have negative FOLLOWING +SELECT *, SUM(c1) OVER (ORDER BY c1 ROWS BETWEEN 1 PRECEDING AND -3 FOLLOWING) FROM t102__2; +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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 +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 +DROP TABLE t102__2; +GO + +DROP TABLE @t102; +GO + + + +set xact_abort OFF; +GO + +-- Error classification is done -- + +-- Executing test error_mapping.ErrorHandling10000000 +CREATE TABLE t102__2(c1 int); +GO + +begin try +select 1 +--Windowing framing cannot have negative FOLLOWING +SELECT *, SUM(c1) OVER (ORDER BY c1 ROWS BETWEEN 1 PRECEDING AND -3 FOLLOWING) FROM t102__2; +end try +begin catch + select xact_state(); +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 +DROP TABLE t102__2; +GO + +DROP TABLE @t102; +GO + + + +GO +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/input/ErrorMapping/102_6.sql b/contrib/test/JDBC/input/ErrorMapping/102_6.sql new file mode 100644 index 00000000000..6193c5586b1 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/102_6.sql @@ -0,0 +1,316 @@ +USE master; +GO + +-- simple batch start + +CREATE TABLE t102__2(c1 int); +GO +CREATE TABLE @t102(c1 int) +GO +DROP TABLE t102__2; +GO + +DROP TABLE @t102; +GO + +begin transaction +GO +CREATE TABLE t102__2(c1 int); +GO +CREATE TABLE @t102(c1 int) +GO + +if (@@trancount > 0) select cast('Txn is not rolledback' as text) else select cast('Txn is rolledback' as text) +GO + +if (@@trancount > 0) rollback tran +GO + +DROP TABLE t102__2; +GO + +DROP TABLE @t102; +GO + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + +CREATE TABLE t102__2(c1 int); +GO +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +CREATE TABLE @t102(c1 int) +end +GO + +DROP TABLE t102__2; +GO + +DROP TABLE @t102; +GO + +create table error_mapping.temp2 (a int) +GO + +CREATE TABLE t102__2(c1 int); +GO +insert into error_mapping.temp2 values(1) +CREATE TABLE @t102(c1 int) +GO + +DROP TABLE t102__2; +GO + +DROP TABLE @t102; +GO + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + +CREATE TABLE t102__2(c1 int); +GO +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO + +DROP TABLE t102__2; +GO + +DROP TABLE @t102; +GO + +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 + +-- Parse analysis phase end +GO + +-- compile time error portion + +-- Executing test error_mapping.ErrorHandling1 +CREATE TABLE t102__2(c1 int); +GO + +create procedure error_mapping.ErrorHandling1 as +begin +CREATE TABLE @t102(c1 int) +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 +DROP TABLE t102__2; +GO + +DROP TABLE @t102; +GO + + +CREATE TABLE t102__2(c1 int); +GO +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +CREATE TABLE @t102(c1 int) +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 + +GO +DROP TABLE t102__2; +GO + +DROP TABLE @t102; +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE t102__2(c1 int); +GO +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +CREATE TABLE @t102(c1 int) +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 + +GO +DROP TABLE t102__2; +GO + +DROP TABLE @t102; +GO +set xact_abort OFF; +GO + +-- comiple time error portion end -- +-- Next portion is for runtime error -- + +-- Executing test error_mapping.ErrorHandling10000000 +CREATE TABLE t102__2(c1 int); +GO + +create procedure error_mapping.ErrorHandling1 as +begin +CREATE TABLE @t102(c1 int) +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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 +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 +DROP TABLE t102__2; +GO + +DROP TABLE @t102; +GO + + +set xact_abort ON; +GO +-- Executing test error_mapping.ErrorHandling10000000 +CREATE TABLE t102__2(c1 int); +GO + +create procedure error_mapping.ErrorHandling1 as +begin +CREATE TABLE @t102(c1 int) +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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 +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 +DROP TABLE t102__2; +GO + +DROP TABLE @t102; +GO + + + +set xact_abort OFF; +GO + +-- Error classification is done -- + +-- Executing test error_mapping.ErrorHandling10000000 +CREATE TABLE t102__2(c1 int); +GO + +begin try +select 1 +CREATE TABLE @t102(c1 int) +end try +begin catch + select xact_state(); +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 +DROP TABLE t102__2; +GO + +DROP TABLE @t102; +GO + + + +GO +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/input/ErrorMapping/1034_1.sql b/contrib/test/JDBC/input/ErrorMapping/1034_1.sql new file mode 100644 index 00000000000..8aeb0ae25a5 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/1034_1.sql @@ -0,0 +1,54 @@ +-- simple batch start + +CREATE TABLE t1034 +( + c1 int +,c2 int +) +GO + +GO +CREATE TRIGGER tr1034 +ON t1034 +FOR UPDATE, UPDATE +AS +SELECT 1 + +GO +DROP TABLE t1034 +GO + +SET XACT_ABORT ON; +GO + +begin transaction +GO +CREATE TABLE t1034 +( + c1 int +,c2 int +) +GO + +GO +CREATE TRIGGER tr1034 +ON t1034 +FOR UPDATE, UPDATE +AS +SELECT 1 + +GO + + +if (@@trancount > 0) select cast('Does not respect xact_abort flag' as text) else select cast('Respects xact_abort flag' as text) +GO + +if (@@trancount > 0) rollback tran +GO + +DROP TABLE t1034 +GO + +SET XACT_ABORT OFF; +GO + diff --git a/contrib/test/JDBC/input/ErrorMapping/1049_1.sql b/contrib/test/JDBC/input/ErrorMapping/1049_1.sql new file mode 100644 index 00000000000..0fb43878855 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/1049_1.sql @@ -0,0 +1,323 @@ +-- simple batch start + +CREATE TABLE t1049 (c1 INT) +GO + +DECLARE cur1049 SCROLL CURSOR FAST_FORWARD READ_ONLY +FOR SELECT c1 FROM t1049 + +GO +DROP TABLE t1049 +GO + + +begin transaction +GO +CREATE TABLE t1049 (c1 INT) +GO + +DECLARE cur1049 SCROLL CURSOR FAST_FORWARD READ_ONLY +FOR SELECT c1 FROM t1049 + +GO + +-- Below output is only applicable if query is special case. for example, CREATE/ALTER TRIGGER, CREATE/ALTER FUNCTION, CREATE/ALTER PROC, CREATE/ALTER VIEW etc + +if (@@trancount > 0) select cast('compile time error' as text) else select cast('runtime error' as text) +GO + +if (@@trancount > 0) rollback tran +GO + +DROP TABLE t1049 +GO + + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + +CREATE TABLE t1049 (c1 INT) +GO + +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +DECLARE cur1049 SCROLL CURSOR FAST_FORWARD READ_ONLY +FOR SELECT c1 FROM t1049 + +end +GO + +DROP TABLE t1049 +GO + + +create table error_mapping.temp2 (a int) +GO + +CREATE TABLE t1049 (c1 INT) +GO + +insert into error_mapping.temp2 values(1) +DECLARE cur1049 SCROLL CURSOR FAST_FORWARD READ_ONLY +FOR SELECT c1 FROM t1049 + +GO + +DROP TABLE t1049 +GO + + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + +CREATE TABLE t1049 (c1 INT) +GO + +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO + +DROP TABLE t1049 +GO + + +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 + +-- Parse analysis phase end +GO + +-- compile time error portion + +-- Executing test error_mapping.ErrorHandling1 +CREATE TABLE t1049 (c1 INT) +GO + + +create procedure error_mapping.ErrorHandling1 as +begin +DECLARE cur1049 SCROLL CURSOR FAST_FORWARD READ_ONLY +FOR SELECT c1 FROM t1049 + +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 +DROP TABLE t1049 +GO + + + +CREATE TABLE t1049 (c1 INT) +GO + +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +DECLARE cur1049 SCROLL CURSOR FAST_FORWARD READ_ONLY +FOR SELECT c1 FROM t1049 + +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 + +GO +DROP TABLE t1049 +GO + + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE t1049 (c1 INT) +GO + +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +DECLARE cur1049 SCROLL CURSOR FAST_FORWARD READ_ONLY +FOR SELECT c1 FROM t1049 + +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 + +GO +DROP TABLE t1049 +GO + +set xact_abort OFF; +GO + +-- comiple time error portion end -- +---- Next portion is for runtime error -- +-- +---- Executing test error_mapping.ErrorHandling10000000 +--CREATE TABLE t1049 (c1 INT) +--GO +-- +-- +--create procedure error_mapping.ErrorHandling1 as +--begin +--DECLARE cur1049 SCROLL CURSOR FAST_FORWARD READ_ONLY +--FOR SELECT c1 FROM t1049 +-- +--if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +--select @@trancount; +--end +-- +--GO +-- +--if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +--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 +--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 +--DROP TABLE t1049 +--GO +-- +-- +-- +--set xact_abort ON; +--GO +---- Executing test error_mapping.ErrorHandling10000000 +--CREATE TABLE t1049 (c1 INT) +--GO +-- +-- +--create procedure error_mapping.ErrorHandling1 as +--begin +--DECLARE cur1049 SCROLL CURSOR FAST_FORWARD READ_ONLY +--FOR SELECT c1 FROM t1049 +-- +--if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +--select @@trancount; +--end +-- +--GO +-- +--if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +--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 +--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 +--DROP TABLE t1049 +--GO +-- +-- +-- +-- +--set xact_abort OFF; +--GO + +-- Error classification is done -- + +CREATE TABLE t1049 (c1 INT) +GO + + +begin try +select 1 +DECLARE cur1049 SCROLL CURSOR FAST_FORWARD READ_ONLY +FOR SELECT c1 FROM t1049 + +end try +begin catch + select xact_state(); +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 +DROP TABLE t1049 +GO + + + + +GO +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/input/ErrorMapping/1051_1.sql b/contrib/test/JDBC/input/ErrorMapping/1051_1.sql new file mode 100644 index 00000000000..aad51efe5e2 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/1051_1.sql @@ -0,0 +1,58 @@ +-- simple batch start + +CREATE TABLE t1051 +( + c1 int +,c2 int NULL +) +GO + + +CREATE PROC p1051_1 + @a CURSOR OUTPUT VARYING + AS +DECLARE c CURSOR + READ_ONLY +FOR +SELECT * FROM t1051 + +GO +DROP TABLE t1051 +GO + + +SET XACT_ABORT ON; +GO + +begin transaction +GO +CREATE TABLE t1051 +( + c1 int +,c2 int NULL +) +GO + + +CREATE PROC p1051_1 + @a CURSOR OUTPUT VARYING + AS +DECLARE c CURSOR + READ_ONLY +FOR +SELECT * FROM t1051 + +GO + +if (@@trancount > 0) select cast('Does not respect xact_abort flag' as text) else select cast('Respects xact_abort flag' as text) +GO + +if (@@trancount > 0) rollback tran +GO + +DROP TABLE t1051 +GO + +SET XACT_ABORT OFF; +GO + diff --git a/contrib/test/JDBC/input/ErrorMapping/10610_1.sql b/contrib/test/JDBC/input/ErrorMapping/10610_1.sql new file mode 100644 index 00000000000..b0f24c913b6 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/10610_1.sql @@ -0,0 +1,267 @@ +# Executing test ErrorHandling1 +CREATE TABLE t10610( + c1 int, + c2 int +) +GO + +CREATE VIEW v10610 AS +SELECT c1, c2 +FROM t10610 +GO + +create procedure ErrorHandling1 as +begin +CREATE INDEX i10610 +ON v10610 (c1) +WHERE c2 = 1 +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP VIEW v10610 +GO + +DROP TABLE t10610 +GO + + + +CREATE TABLE t10610( + c1 int, + c2 int +) +GO + +CREATE VIEW v10610 AS +SELECT c1, c2 +FROM t10610 +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +CREATE INDEX i10610 +ON v10610 (c1) +WHERE c2 = 1 +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +DROP VIEW v10610 +GO + +DROP TABLE t10610 +GO + + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE t10610( + c1 int, + c2 int +) +GO + +CREATE VIEW v10610 AS +SELECT c1, c2 +FROM t10610 +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +CREATE INDEX i10610 +ON v10610 (c1) +WHERE c2 = 1 +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +DROP VIEW v10610 +GO + +DROP TABLE t10610 +GO + +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +# Executing test ErrorHandling10000000 +CREATE TABLE t10610( + c1 int, + c2 int +) +GO + +CREATE VIEW v10610 AS +SELECT c1, c2 +FROM t10610 +GO + +create procedure ErrorHandling1 as +begin +CREATE INDEX i10610 +ON v10610 (c1) +WHERE c2 = 1 +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP VIEW v10610 +GO + +DROP TABLE t10610 +GO + + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +CREATE TABLE t10610( + c1 int, + c2 int +) +GO + +CREATE VIEW v10610 AS +SELECT c1, c2 +FROM t10610 +GO + +create procedure ErrorHandling1 as +begin +CREATE INDEX i10610 +ON v10610 (c1) +WHERE c2 = 1 +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP VIEW v10610 +GO + +DROP TABLE t10610 +GO + + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +# Executing test ErrorHandling10000000 +CREATE TABLE t10610( + c1 int, + c2 int +) +GO + +CREATE VIEW v10610 AS +SELECT c1, c2 +FROM t10610 +GO + +begin try +select 1 +CREATE INDEX i10610 +ON v10610 (c1) +WHERE c2 = 1 +end try +begin catch + select xact_state(); +end catch + +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP VIEW v10610 +GO + +DROP TABLE t10610 +GO + + + diff --git a/contrib/test/JDBC/input/ErrorMapping/113_1.sql b/contrib/test/JDBC/input/ErrorMapping/113_1.sql new file mode 100644 index 00000000000..221b8c8502a --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/113_1.sql @@ -0,0 +1,207 @@ +# Executing test ErrorHandling1 +--113 Unclosed end comment +--Note that there's no post-section since that would be included in the comment + +--Pre +GO + +create procedure ErrorHandling1 as +begin +--Generate the error +SELECT 1; /* comment SELECT 1GO +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +GO + + +--113 Unclosed end comment +--Note that there's no post-section since that would be included in the comment + +--Pre +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +--Generate the error +SELECT 1; /* comment SELECT 1GO +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +--Post +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +--113 Unclosed end comment +--Note that there's no post-section since that would be included in the comment + +--Pre +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +--Generate the error +SELECT 1; /* comment SELECT 1GO +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +--Post +GO +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +# Executing test ErrorHandling10000000 +--113 Unclosed end comment +--Note that there's no post-section since that would be included in the comment + +--Pre +GO + +create procedure ErrorHandling1 as +begin +--Generate the error +SELECT 1; /* comment SELECT 1GO +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +--113 Unclosed end comment +--Note that there's no post-section since that would be included in the comment + +--Pre +GO + +create procedure ErrorHandling1 as +begin +--Generate the error +SELECT 1; /* comment SELECT 1GO +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +GO + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +# Executing test ErrorHandling10000000 +--113 Unclosed end comment +--Note that there's no post-section since that would be included in the comment + +--Pre +GO + +begin try +select 1 +--Generate the error +SELECT 1; /* comment SELECT 1GO +end try +begin catch + select xact_state(); +end catch + +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +GO + + diff --git a/contrib/test/JDBC/input/ErrorMapping/11700_1.sql b/contrib/test/JDBC/input/ErrorMapping/11700_1.sql new file mode 100644 index 00000000000..f3f308bb220 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/11700_1.sql @@ -0,0 +1,189 @@ +# Executing test ErrorHandling1 +GO + +create procedure ErrorHandling1 as +begin +CREATE SEQUENCE s11700 + START WITH 1 + INCREMENT BY 0 + +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +GO + + +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +CREATE SEQUENCE s11700 + START WITH 1 + INCREMENT BY 0 + +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +CREATE SEQUENCE s11700 + START WITH 1 + INCREMENT BY 0 + +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +GO +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +# Executing test ErrorHandling10000000 +GO + +create procedure ErrorHandling1 as +begin +CREATE SEQUENCE s11700 + START WITH 1 + INCREMENT BY 0 + +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +GO + +create procedure ErrorHandling1 as +begin +CREATE SEQUENCE s11700 + START WITH 1 + INCREMENT BY 0 + +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +GO + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +# Executing test ErrorHandling10000000 +GO + +begin try +select 1 +CREATE SEQUENCE s11700 + START WITH 1 + INCREMENT BY 0 + +end try +begin catch + select xact_state(); +end catch + +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +GO + + diff --git a/contrib/test/JDBC/input/ErrorMapping/11701_1.sql b/contrib/test/JDBC/input/ErrorMapping/11701_1.sql new file mode 100644 index 00000000000..37c75917dba --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/11701_1.sql @@ -0,0 +1,201 @@ +create schema error_mapping; +GO +-- Executing test error_mapping.ErrorHandling1 +GO + +create procedure error_mapping.ErrorHandling1 as +begin +CREATE SEQUENCE s11701 INCREMENT BY 6 + MINVALUE 5 + MAXVALUE 10 + + +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 +GO + + +GO +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +CREATE SEQUENCE s11701 INCREMENT BY 6 + MINVALUE 5 + MAXVALUE 10 + + +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 + +GO +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +GO +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +CREATE SEQUENCE s11701 INCREMENT BY 6 + MINVALUE 5 + MAXVALUE 10 + + +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 + +GO +GO +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +-- Executing test error_mapping.ErrorHandling10000000 +GO + +create procedure error_mapping.ErrorHandling1 as +begin +CREATE SEQUENCE s11701 INCREMENT BY 6 + MINVALUE 5 + MAXVALUE 10 + + +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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 +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 +GO + + +set xact_abort ON; +GO +-- Executing test error_mapping.ErrorHandling10000000 +GO + +create procedure error_mapping.ErrorHandling1 as +begin +CREATE SEQUENCE s11701 INCREMENT BY 6 + MINVALUE 5 + MAXVALUE 10 + + +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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 +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 +GO + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +-- Executing test error_mapping.ErrorHandling10000000 +GO + +begin try +select 1 +CREATE SEQUENCE s11701 INCREMENT BY 6 + MINVALUE 5 + MAXVALUE 10 + + +end try +begin catch + select xact_state(); +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 +GO + + + +GO +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/input/ErrorMapping/11702_1.sql b/contrib/test/JDBC/input/ErrorMapping/11702_1.sql new file mode 100644 index 00000000000..f53faf5f66f --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/11702_1.sql @@ -0,0 +1,260 @@ +-- simple batch start + +GO +CREATE SEQUENCE seq11702 AS bit +GO +GO + +begin transaction +GO +GO +CREATE SEQUENCE seq11702 AS bit +GO + +-- Below output is only applicable if query is special case. for example, CREATE/ALTER TRIGGER, CREATE/ALTER FUNCTION, CREATE/ALTER PROC, CREATE/ALTER VIEW etc + +if (@@trancount > 0) select cast('compile time error' as text) else select cast('runtime error' as text) +GO + +if (@@trancount > 0) rollback tran +GO + +GO + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + +GO +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +CREATE SEQUENCE seq11702 AS bit +end +GO + +GO + +create table error_mapping.temp2 (a int) +GO + +GO +insert into error_mapping.temp2 values(1) +CREATE SEQUENCE seq11702 AS bit +GO + +GO + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + +GO +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO + +GO + +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 + +-- Parse analysis phase end +GO + +-- compile time error portion + +-- Executing test error_mapping.ErrorHandling1 +GO + +create procedure error_mapping.ErrorHandling1 as +begin +CREATE SEQUENCE seq11702 AS bit +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 +GO + + +GO +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +CREATE SEQUENCE seq11702 AS bit +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 + +GO +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +GO +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +CREATE SEQUENCE seq11702 AS bit +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 + +GO +GO +set xact_abort OFF; +GO + +-- comiple time error portion end -- +-- Next portion is for runtime error -- + +-- Executing test error_mapping.ErrorHandling10000000 +GO + +create procedure error_mapping.ErrorHandling1 as +begin +CREATE SEQUENCE seq11702 AS bit +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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 +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 +GO + + +set xact_abort ON; +GO +-- Executing test error_mapping.ErrorHandling10000000 +GO + +create procedure error_mapping.ErrorHandling1 as +begin +CREATE SEQUENCE seq11702 AS bit +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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 +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 +GO + + + +set xact_abort OFF; +GO + +-- Error classification is done -- + +-- Executing test error_mapping.ErrorHandling10000000 +GO + +begin try +select 1 +CREATE SEQUENCE seq11702 AS bit +end try +begin catch + select xact_state(); +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 +GO + + + +GO +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/input/ErrorMapping/11703_1.sql b/contrib/test/JDBC/input/ErrorMapping/11703_1.sql new file mode 100644 index 00000000000..cfe82ad1527 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/11703_1.sql @@ -0,0 +1,300 @@ +-- simple batch start + +GO +CREATE SEQUENCE s11703 + START WITH 11 + MINVALUE 5 + MAXVALUE 10 + +GO +GO + +begin transaction +GO +GO +CREATE SEQUENCE s11703 + START WITH 11 + MINVALUE 5 + MAXVALUE 10 + +GO + +-- Below output is only applicable if query is special case. for example, CREATE/ALTER TRIGGER, CREATE/ALTER FUNCTION, CREATE/ALTER PROC, CREATE/ALTER VIEW etc + +if (@@trancount > 0) select cast('compile time error' as text) else select cast('runtime error' as text) +GO + +if (@@trancount > 0) rollback tran +GO + +GO + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + +GO +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +CREATE SEQUENCE s11703 + START WITH 11 + MINVALUE 5 + MAXVALUE 10 + +end +GO + +GO + +create table error_mapping.temp2 (a int) +GO + +GO +insert into error_mapping.temp2 values(1) +CREATE SEQUENCE s11703 + START WITH 11 + MINVALUE 5 + MAXVALUE 10 + +GO + +GO + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + +GO +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO + +GO + +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 + +-- Parse analysis phase end +GO + +-- compile time error portion + +-- Executing test error_mapping.ErrorHandling1 +GO + +create procedure error_mapping.ErrorHandling1 as +begin +CREATE SEQUENCE s11703 + START WITH 11 + MINVALUE 5 + MAXVALUE 10 + +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 +GO + + +GO +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +CREATE SEQUENCE s11703 + START WITH 11 + MINVALUE 5 + MAXVALUE 10 + +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 + +GO +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +GO +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +CREATE SEQUENCE s11703 + START WITH 11 + MINVALUE 5 + MAXVALUE 10 + +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 + +GO +GO +set xact_abort OFF; +GO + +-- comiple time error portion end -- +-- Next portion is for runtime error -- + +-- Executing test error_mapping.ErrorHandling10000000 +GO + +create procedure error_mapping.ErrorHandling1 as +begin +CREATE SEQUENCE s11703 + START WITH 11 + MINVALUE 5 + MAXVALUE 10 + +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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 +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 +GO + + +set xact_abort ON; +GO +-- Executing test error_mapping.ErrorHandling10000000 +GO + +create procedure error_mapping.ErrorHandling1 as +begin +CREATE SEQUENCE s11703 + START WITH 11 + MINVALUE 5 + MAXVALUE 10 + +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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 +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 +GO + + + +set xact_abort OFF; +GO + +-- Error classification is done -- + +-- Executing test error_mapping.ErrorHandling10000000 +GO + +begin try +select 1 +CREATE SEQUENCE s11703 + START WITH 11 + MINVALUE 5 + MAXVALUE 10 + +end try +begin catch + select xact_state(); +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 +GO + + + +GO +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/input/ErrorMapping/11703_2.sql b/contrib/test/JDBC/input/ErrorMapping/11703_2.sql new file mode 100644 index 00000000000..b5d256eedb9 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/11703_2.sql @@ -0,0 +1,300 @@ +-- simple batch start + +GO +CREATE SEQUENCE s11703 + START WITH 1 + MINVALUE 5 + MAXVALUE 10 + +GO +GO + +begin transaction +GO +GO +CREATE SEQUENCE s11703 + START WITH 1 + MINVALUE 5 + MAXVALUE 10 + +GO + +-- Below output is only applicable if query is special case. for example, CREATE/ALTER TRIGGER, CREATE/ALTER FUNCTION, CREATE/ALTER PROC, CREATE/ALTER VIEW etc + +if (@@trancount > 0) select cast('compile time error' as text) else select cast('runtime error' as text) +GO + +if (@@trancount > 0) rollback tran +GO + +GO + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + +GO +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +CREATE SEQUENCE s11703 + START WITH 1 + MINVALUE 5 + MAXVALUE 10 + +end +GO + +GO + +create table error_mapping.temp2 (a int) +GO + +GO +insert into error_mapping.temp2 values(1) +CREATE SEQUENCE s11703 + START WITH 1 + MINVALUE 5 + MAXVALUE 10 + +GO + +GO + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + +GO +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO + +GO + +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 + +-- Parse analysis phase end +GO + +-- compile time error portion + +-- Executing test error_mapping.ErrorHandling1 +GO + +create procedure error_mapping.ErrorHandling1 as +begin +CREATE SEQUENCE s11703 + START WITH 1 + MINVALUE 5 + MAXVALUE 10 + +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 +GO + + +GO +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +CREATE SEQUENCE s11703 + START WITH 1 + MINVALUE 5 + MAXVALUE 10 + +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 + +GO +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +GO +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +CREATE SEQUENCE s11703 + START WITH 1 + MINVALUE 5 + MAXVALUE 10 + +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 + +GO +GO +set xact_abort OFF; +GO + +-- comiple time error portion end -- +-- Next portion is for runtime error -- + +-- Executing test error_mapping.ErrorHandling10000000 +GO + +create procedure error_mapping.ErrorHandling1 as +begin +CREATE SEQUENCE s11703 + START WITH 1 + MINVALUE 5 + MAXVALUE 10 + +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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 +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 +GO + + +set xact_abort ON; +GO +-- Executing test error_mapping.ErrorHandling10000000 +GO + +create procedure error_mapping.ErrorHandling1 as +begin +CREATE SEQUENCE s11703 + START WITH 1 + MINVALUE 5 + MAXVALUE 10 + +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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 +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 +GO + + + +set xact_abort OFF; +GO + +-- Error classification is done -- + +-- Executing test error_mapping.ErrorHandling10000000 +GO + +begin try +select 1 +CREATE SEQUENCE s11703 + START WITH 1 + MINVALUE 5 + MAXVALUE 10 + +end try +begin catch + select xact_state(); +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 +GO + + + +GO +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/input/ErrorMapping/11704_1.sql b/contrib/test/JDBC/input/ErrorMapping/11704_1.sql new file mode 100644 index 00000000000..8a11ffaeb4e --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/11704_1.sql @@ -0,0 +1,201 @@ +# Executing test ErrorHandling1 +CREATE SEQUENCE s11704 +start with 5 +increment by 1 +GO + +create procedure ErrorHandling1 as +begin +ALTER SEQUENCE s11704 + MINVALUE 6; +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP SEQUENCE s11704 +GO + + +CREATE SEQUENCE s11704 +start with 5 +increment by 1 +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +ALTER SEQUENCE s11704 + MINVALUE 6; +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +DROP SEQUENCE s11704 +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE SEQUENCE s11704 +start with 5 +increment by 1 +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +ALTER SEQUENCE s11704 + MINVALUE 6; +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +DROP SEQUENCE s11704 +GO +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +# Executing test ErrorHandling10000000 +CREATE SEQUENCE s11704 +start with 5 +increment by 1 +GO + +create procedure ErrorHandling1 as +begin +ALTER SEQUENCE s11704 + MINVALUE 6; +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP SEQUENCE s11704 +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +CREATE SEQUENCE s11704 +start with 5 +increment by 1 +GO + +create procedure ErrorHandling1 as +begin +ALTER SEQUENCE s11704 + MINVALUE 6; +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP SEQUENCE s11704 +GO + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +# Executing test ErrorHandling10000000 +CREATE SEQUENCE s11704 +start with 5 +increment by 1 +GO + +begin try +select 1 +ALTER SEQUENCE s11704 + MINVALUE 6; +end try +begin catch + select xact_state(); +end catch + +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP SEQUENCE s11704 +GO + + diff --git a/contrib/test/JDBC/input/ErrorMapping/11704_2.sql b/contrib/test/JDBC/input/ErrorMapping/11704_2.sql new file mode 100644 index 00000000000..cecc08d935e --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/11704_2.sql @@ -0,0 +1,219 @@ +# Executing test ErrorHandling1 +CREATE SEQUENCE s11704 +start with 5 +increment by 1 +GO + +create procedure ErrorHandling1 as +begin +ALTER SEQUENCE s11704 + MINVALUE 3; + +ALTER SEQUENCE s11704 + MAXVALUE 4; +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP SEQUENCE s11704 +GO + + +CREATE SEQUENCE s11704 +start with 5 +increment by 1 +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +ALTER SEQUENCE s11704 + MINVALUE 3; + +ALTER SEQUENCE s11704 + MAXVALUE 4; +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +DROP SEQUENCE s11704 +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE SEQUENCE s11704 +start with 5 +increment by 1 +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +ALTER SEQUENCE s11704 + MINVALUE 3; + +ALTER SEQUENCE s11704 + MAXVALUE 4; +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +DROP SEQUENCE s11704 +GO +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +# Executing test ErrorHandling10000000 +CREATE SEQUENCE s11704 +start with 5 +increment by 1 +GO + +create procedure ErrorHandling1 as +begin +ALTER SEQUENCE s11704 + MINVALUE 3; + +ALTER SEQUENCE s11704 + MAXVALUE 4; +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP SEQUENCE s11704 +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +CREATE SEQUENCE s11704 +start with 5 +increment by 1 +GO + +create procedure ErrorHandling1 as +begin +ALTER SEQUENCE s11704 + MINVALUE 3; + +ALTER SEQUENCE s11704 + MAXVALUE 4; +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP SEQUENCE s11704 +GO + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +# Executing test ErrorHandling10000000 +CREATE SEQUENCE s11704 +start with 5 +increment by 1 +GO + +begin try +select 1 +ALTER SEQUENCE s11704 + MINVALUE 3; + +ALTER SEQUENCE s11704 + MAXVALUE 4; +end try +begin catch + select xact_state(); +end catch + +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP SEQUENCE s11704 +GO + + diff --git a/contrib/test/JDBC/input/ErrorMapping/11705_1.sql b/contrib/test/JDBC/input/ErrorMapping/11705_1.sql new file mode 100644 index 00000000000..9f813b8b5f3 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/11705_1.sql @@ -0,0 +1,195 @@ +# Executing test ErrorHandling1 +GO + +create procedure ErrorHandling1 as +begin +CREATE SEQUENCE s11705 + increment by 1 + MINVALUE 10 + MAXVALUE 5 + +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +GO + + +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +CREATE SEQUENCE s11705 + increment by 1 + MINVALUE 10 + MAXVALUE 5 + +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +CREATE SEQUENCE s11705 + increment by 1 + MINVALUE 10 + MAXVALUE 5 + +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +GO +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +# Executing test ErrorHandling10000000 +GO + +create procedure ErrorHandling1 as +begin +CREATE SEQUENCE s11705 + increment by 1 + MINVALUE 10 + MAXVALUE 5 + +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +GO + +create procedure ErrorHandling1 as +begin +CREATE SEQUENCE s11705 + increment by 1 + MINVALUE 10 + MAXVALUE 5 + +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +GO + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +# Executing test ErrorHandling10000000 +GO + +begin try +select 1 +CREATE SEQUENCE s11705 + increment by 1 + MINVALUE 10 + MAXVALUE 5 + +end try +begin catch + select xact_state(); +end catch + +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +GO + + diff --git a/contrib/test/JDBC/input/ErrorMapping/11706_1.sql b/contrib/test/JDBC/input/ErrorMapping/11706_1.sql new file mode 100644 index 00000000000..e13a8d23303 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/11706_1.sql @@ -0,0 +1,213 @@ +# Executing test ErrorHandling1 +GO + + +create procedure ErrorHandling1 as +begin +CREATE SEQUENCE s11706 + AS INT + START WITH 5 + INCREMENT BY 1 + CACHE 0 + + +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +GO + + +GO + +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +CREATE SEQUENCE s11706 + AS INT + START WITH 5 + INCREMENT BY 1 + CACHE 0 + + +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +GO + +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +CREATE SEQUENCE s11706 + AS INT + START WITH 5 + INCREMENT BY 1 + CACHE 0 + + +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +GO +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +# Executing test ErrorHandling10000000 +GO + + +create procedure ErrorHandling1 as +begin +CREATE SEQUENCE s11706 + AS INT + START WITH 5 + INCREMENT BY 1 + CACHE 0 + + +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +GO + + +create procedure ErrorHandling1 as +begin +CREATE SEQUENCE s11706 + AS INT + START WITH 5 + INCREMENT BY 1 + CACHE 0 + + +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +GO + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +# Executing test ErrorHandling10000000 +GO + + +begin try +select 1 +CREATE SEQUENCE s11706 + AS INT + START WITH 5 + INCREMENT BY 1 + CACHE 0 + + +end try +begin catch + select xact_state(); +end catch + +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +GO + + diff --git a/contrib/test/JDBC/input/ErrorMapping/11708_1.sql b/contrib/test/JDBC/input/ErrorMapping/11708_1.sql new file mode 100644 index 00000000000..a4e8e466b30 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/11708_1.sql @@ -0,0 +1,201 @@ +# Executing test ErrorHandling1 +GO + +create procedure ErrorHandling1 as +begin +CREATE SEQUENCE seq_11708 +AS [tinyint] +START WITH 1 +INCREMENT BY 1 +MINVALUE 1 +MAXVALUE 256 +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +GO + + +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +CREATE SEQUENCE seq_11708 +AS [tinyint] +START WITH 1 +INCREMENT BY 1 +MINVALUE 1 +MAXVALUE 256 +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +CREATE SEQUENCE seq_11708 +AS [tinyint] +START WITH 1 +INCREMENT BY 1 +MINVALUE 1 +MAXVALUE 256 +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +GO +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +# Executing test ErrorHandling10000000 +GO + +create procedure ErrorHandling1 as +begin +CREATE SEQUENCE seq_11708 +AS [tinyint] +START WITH 1 +INCREMENT BY 1 +MINVALUE 1 +MAXVALUE 256 +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +GO + +create procedure ErrorHandling1 as +begin +CREATE SEQUENCE seq_11708 +AS [tinyint] +START WITH 1 +INCREMENT BY 1 +MINVALUE 1 +MAXVALUE 256 +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +GO + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +# Executing test ErrorHandling10000000 +GO + +begin try +select 1 +CREATE SEQUENCE seq_11708 +AS [tinyint] +START WITH 1 +INCREMENT BY 1 +MINVALUE 1 +MAXVALUE 256 +end try +begin catch + select xact_state(); +end catch + +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +GO + + diff --git a/contrib/test/JDBC/input/ErrorMapping/129_1.sql b/contrib/test/JDBC/input/ErrorMapping/129_1.sql new file mode 100644 index 00000000000..f24f09001ef --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/129_1.sql @@ -0,0 +1,305 @@ +USE master; +GO + +-- simple batch start + +CREATE TABLE t129(id int) +GO +CREATE INDEX i129 ON t129 (id) +WITH (FILLFACTOR = 1000) +GO +GO +DROP TABLE t129 +GO + +begin transaction +GO +CREATE TABLE t129(id int) +GO +CREATE INDEX i129 ON t129 (id) +WITH (FILLFACTOR = 1000) +GO +GO + +-- Below output is only applicable if query is special case. for example, CREATE/ALTER TRIGGER, CREATE/ALTER FUNCTION, CREATE/ALTER PROC, CREATE/ALTER VIEW etc + +if (@@trancount > 0) select cast('compile time error' as text) else select cast('runtime error' as text) +GO + +if (@@trancount > 0) rollback tran +GO + +DROP TABLE t129 +GO + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + +CREATE TABLE t129(id int) +GO +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +CREATE INDEX i129 ON t129 (id) +WITH (FILLFACTOR = 1000) +GO +end +GO + +DROP TABLE t129 +GO + +create table error_mapping.temp2 (a int) +GO + +CREATE TABLE t129(id int) +GO +insert into error_mapping.temp2 values(1) +CREATE INDEX i129 ON t129 (id) +WITH (FILLFACTOR = 1000) +GO +GO + +DROP TABLE t129 +GO + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + +CREATE TABLE t129(id int) +GO +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO + +DROP TABLE t129 +GO + +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 + +-- Parse analysis phase end +GO + +-- compile time error portion + +-- Executing test error_mapping.ErrorHandling1 +CREATE TABLE t129(id int) +GO + +create procedure error_mapping.ErrorHandling1 as +begin +CREATE INDEX i129 ON t129 (id) +WITH (FILLFACTOR = 1000) +GO +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 +DROP TABLE t129 +GO + + +CREATE TABLE t129(id int) +GO +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +CREATE INDEX i129 ON t129 (id) +WITH (FILLFACTOR = 1000) +GO +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 + +GO +DROP TABLE t129 +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE t129(id int) +GO +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +CREATE INDEX i129 ON t129 (id) +WITH (FILLFACTOR = 1000) +GO +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 + +GO +DROP TABLE t129 +GO +set xact_abort OFF; +GO + +-- comiple time error portion end -- +-- Next portion is for runtime error -- + +-- Executing test error_mapping.ErrorHandling10000000 +CREATE TABLE t129(id int) +GO + +create procedure error_mapping.ErrorHandling1 as +begin +CREATE INDEX i129 ON t129 (id) +WITH (FILLFACTOR = 1000) +GO +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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 +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 +DROP TABLE t129 +GO + + +set xact_abort ON; +GO +-- Executing test error_mapping.ErrorHandling10000000 +CREATE TABLE t129(id int) +GO + +create procedure error_mapping.ErrorHandling1 as +begin +CREATE INDEX i129 ON t129 (id) +WITH (FILLFACTOR = 1000) +GO +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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 +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 +DROP TABLE t129 +GO + + + +set xact_abort OFF; +GO + +-- Error classification is done -- + +-- Executing test error_mapping.ErrorHandling10000000 +CREATE TABLE t129(id int) +GO + +begin try +select 1 +CREATE INDEX i129 ON t129 (id) +WITH (FILLFACTOR = 1000) +GO +end try +begin catch + select xact_state(); +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 +DROP TABLE t129 +GO + + + +GO +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/input/ErrorMapping/132_1.sql b/contrib/test/JDBC/input/ErrorMapping/132_1.sql new file mode 100644 index 00000000000..70d48050d41 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/132_1.sql @@ -0,0 +1,376 @@ +-- simple batch start + +--132 Label already declared + +--Could not find this PG error in excel file + +--------------------------------------------------------------------------- +--Pre +GO +--------------------------------------------------------------------------- +--Generate the error +lbl: +lbl: +GO +--------------------------------------------------------------------------- +--Post +GO + +begin transaction +GO +--132 Label already declared + +--Could not find this PG error in excel file + +--------------------------------------------------------------------------- +--Pre +GO +--------------------------------------------------------------------------- +--Generate the error +lbl: +lbl: +GO + +-- Below output is only applicable if query is special case. for example, CREATE/ALTER TRIGGER, CREATE/ALTER FUNCTION, CREATE/ALTER PROC, CREATE/ALTER VIEW etc + +if (@@trancount > 0) select cast('compile time error' as text) else select cast('runtime error' as text) +GO + +if (@@trancount > 0) rollback tran +GO + +--------------------------------------------------------------------------- +--Post +GO + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + +--132 Label already declared + +--Could not find this PG error in excel file + +--------------------------------------------------------------------------- +--Pre +GO +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +--------------------------------------------------------------------------- +--Generate the error +lbl: +lbl: +end +GO + +--------------------------------------------------------------------------- +--Post +GO + +create table error_mapping.temp2 (a int) +GO + +--132 Label already declared + +--Could not find this PG error in excel file + +--------------------------------------------------------------------------- +--Pre +GO +insert into error_mapping.temp2 values(1) +--------------------------------------------------------------------------- +--Generate the error +lbl: +lbl: +GO + +--------------------------------------------------------------------------- +--Post +GO + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + +--132 Label already declared + +--Could not find this PG error in excel file + +--------------------------------------------------------------------------- +--Pre +GO +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO + +--------------------------------------------------------------------------- +--Post +GO + +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 + +-- Parse analysis phase end +GO + +-- compile time error portion + +-- Executing test error_mapping.ErrorHandling1 +--132 Label already declared + +--Could not find this PG error in excel file + +--------------------------------------------------------------------------- +--Pre +GO + +create procedure error_mapping.ErrorHandling1 as +begin +--------------------------------------------------------------------------- +--Generate the error +lbl: +lbl: +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 +GO + + +--132 Label already declared + +--Could not find this PG error in excel file + +--------------------------------------------------------------------------- +--Pre +GO +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +--------------------------------------------------------------------------- +--Generate the error +lbl: +lbl: +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 + +GO +--------------------------------------------------------------------------- +--Post +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +--132 Label already declared + +--Could not find this PG error in excel file + +--------------------------------------------------------------------------- +--Pre +GO +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +--------------------------------------------------------------------------- +--Generate the error +lbl: +lbl: +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 + +GO +--------------------------------------------------------------------------- +--Post +GO +set xact_abort OFF; +GO + +-- comiple time error portion end -- +---- Next portion is for runtime error -- +-- +---- Executing test error_mapping.ErrorHandling10000000 +----132 Label already declared +-- +----Could not find this PG error in excel file +-- +----------------------------------------------------------------------------- +----Pre +--GO +-- +--create procedure error_mapping.ErrorHandling1 as +--begin +----------------------------------------------------------------------------- +----Generate the error +--lbl: +--lbl: +--if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +--select @@trancount; +--end +-- +--GO +-- +--if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +--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 +--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 +----------------------------------------------------------------------------- +----Post +--GO +-- +-- +--set xact_abort ON; +--GO +---- Executing test error_mapping.ErrorHandling10000000 +----132 Label already declared +-- +----Could not find this PG error in excel file +-- +----------------------------------------------------------------------------- +----Pre +--GO +-- +--create procedure error_mapping.ErrorHandling1 as +--begin +----------------------------------------------------------------------------- +----Generate the error +--lbl: +--lbl: +--if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +--select @@trancount; +--end +-- +--GO +-- +--if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +--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 +--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 +----------------------------------------------------------------------------- +----Post +--GO +-- +-- +-- +--set xact_abort OFF; +--GO +-- +-- Error classification is done -- + +-- Executing test error_mapping.ErrorHandling10000000 +--132 Label already declared + +--------------------------------------------------------------------------- +--Pre +GO + +begin try +select 1 +--------------------------------------------------------------------------- +--Generate the error +lbl: +lbl: +end try +begin catch + select xact_state(); +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 +----------------------------------------------------------------------------- +----Post +--GO +-- +-- +-- +GO +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/input/ErrorMapping/133_1.sql b/contrib/test/JDBC/input/ErrorMapping/133_1.sql new file mode 100644 index 00000000000..79292e52ce9 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/133_1.sql @@ -0,0 +1,378 @@ +-- simple batch start + +--133 Reference non-existing label in GOTO + +--Could not find this PG error in excel file + +--------------------------------------------------------------------------- +--Pre +GO +--------------------------------------------------------------------------- +--Generate the error +GOTO lbl2 +blb3: +GO +--------------------------------------------------------------------------- +--Post +GO + +begin transaction +GO +--133 Reference non-existing label in GOTO + +--Could not find this PG error in excel file + +--------------------------------------------------------------------------- +--Pre +GO +--------------------------------------------------------------------------- +--Generate the error +GOTO lbl2 +blb3: +GO + +-- Below output is only applicable if query is special case. for example, CREATE/ALTER TRIGGER, CREATE/ALTER FUNCTION, CREATE/ALTER PROC, CREATE/ALTER VIEW etc + +if (@@trancount > 0) select cast('compile time error' as text) else select cast('runtime error' as text) +GO + +if (@@trancount > 0) rollback tran +GO + +--------------------------------------------------------------------------- +--Post +GO + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + +--133 Reference non-existing label in GOTO + +--Could not find this PG error in excel file + +--------------------------------------------------------------------------- +--Pre +GO +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +--------------------------------------------------------------------------- +--Generate the error +GOTO lbl2 +blb3: +end +GO + +--------------------------------------------------------------------------- +--Post +GO + +create table error_mapping.temp2 (a int) +GO + +--133 Reference non-existing label in GOTO + +--Could not find this PG error in excel file + +--------------------------------------------------------------------------- +--Pre +GO +insert into error_mapping.temp2 values(1) +--------------------------------------------------------------------------- +--Generate the error +GOTO lbl2 +blb3: +GO + +--------------------------------------------------------------------------- +--Post +GO + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + +--133 Reference non-existing label in GOTO + +--Could not find this PG error in excel file + +--------------------------------------------------------------------------- +--Pre +GO +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO + +--------------------------------------------------------------------------- +--Post +GO + +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 + +-- Parse analysis phase end +GO + +-- compile time error portion + +-- Executing test error_mapping.ErrorHandling1 +--133 Reference non-existing label in GOTO + +--Could not find this PG error in excel file + +--------------------------------------------------------------------------- +--Pre +GO + +create procedure error_mapping.ErrorHandling1 as +begin +--------------------------------------------------------------------------- +--Generate the error +GOTO lbl2 +blb3: +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 +GO + + +--133 Reference non-existing label in GOTO + +--Could not find this PG error in excel file + +--------------------------------------------------------------------------- +--Pre +GO +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +--------------------------------------------------------------------------- +--Generate the error +GOTO lbl2 +blb3: +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 + +GO +--------------------------------------------------------------------------- +--Post +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +--133 Reference non-existing label in GOTO + +--Could not find this PG error in excel file + +--------------------------------------------------------------------------- +--Pre +GO +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +--------------------------------------------------------------------------- +--Generate the error +GOTO lbl2 +blb3: +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 + +GO +--------------------------------------------------------------------------- +--Post +GO +set xact_abort OFF; +GO + +-- comiple time error portion end -- +-- Next portion is for runtime error -- + +-- Executing test error_mapping.ErrorHandling10000000 +--133 Reference non-existing label in GOTO + +--Could not find this PG error in excel file + +--------------------------------------------------------------------------- +--Pre +--GO +-- +--create procedure error_mapping.ErrorHandling1 as +--begin +----------------------------------------------------------------------------- +----Generate the error +--GOTO lbl2 +--blb3: +--if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +--select @@trancount; +--end +-- +--GO +-- +--if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +--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 +--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 +----------------------------------------------------------------------------- +----Post +--GO +-- +-- +--set xact_abort ON; +--GO +---- Executing test error_mapping.ErrorHandling10000000 +----133 Reference non-existing label in GOTO +-- +----Could not find this PG error in excel file +-- +----------------------------------------------------------------------------- +----Pre +--GO +-- +--create procedure error_mapping.ErrorHandling1 as +--begin +----------------------------------------------------------------------------- +----Generate the error +--GOTO lbl2 +--blb3: +--if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +--select @@trancount; +--end +-- +--GO +-- +--if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +--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 +--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 +----------------------------------------------------------------------------- +----Post +--GO +-- +-- +-- +--set xact_abort OFF; +--GO +-- +-- Error classification is done -- + +-- Executing test error_mapping.ErrorHandling10000000 +--133 Reference non-existing label in GOTO + +--Could not find this PG error in excel file + +--------------------------------------------------------------------------- +--Pre +GO + +begin try +select 1 +--------------------------------------------------------------------------- +--Generate the error +GOTO lbl2 +blb3: +end try +begin catch + select xact_state(); +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 +----------------------------------------------------------------------------- +----Post +--GO +-- +-- +-- +GO +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/input/ErrorMapping/134_1.sql b/contrib/test/JDBC/input/ErrorMapping/134_1.sql new file mode 100644 index 00000000000..da1bcb27682 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/134_1.sql @@ -0,0 +1,365 @@ +-- simple batch start + +--134 Declare same variable name twice + +--------------------------------------------------------------------------- +--Pre +GO +--------------------------------------------------------------------------- +--Generate the error + +--CHECK constraint conflict, when adding constraint +DECLARE @a int; +DECLARE @a int; +GO +--Post +GO + +begin transaction +GO +--134 Declare same variable name twice + +--------------------------------------------------------------------------- +--Pre +GO +--------------------------------------------------------------------------- +--Generate the error + +--CHECK constraint conflict, when adding constraint +DECLARE @a int; +DECLARE @a int; +GO + +-- Below output is only applicable if query is special case. for example, CREATE/ALTER TRIGGER, CREATE/ALTER FUNCTION, CREATE/ALTER PROC, CREATE/ALTER VIEW etc + +if (@@trancount > 0) select cast('compile time error' as text) else select cast('runtime error' as text) +GO + +if (@@trancount > 0) rollback tran +GO + +--Post +GO + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + +--134 Declare same variable name twice + +--------------------------------------------------------------------------- +--Pre +GO +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +--------------------------------------------------------------------------- +--Generate the error + +--CHECK constraint conflict, when adding constraint +DECLARE @a int; +DECLARE @a int; +end +GO + +--Post +GO + +create table error_mapping.temp2 (a int) +GO + +--134 Declare same variable name twice + +--------------------------------------------------------------------------- +--Pre +GO +insert into error_mapping.temp2 values(1) +--------------------------------------------------------------------------- +--Generate the error + +--CHECK constraint conflict, when adding constraint +DECLARE @a int; +DECLARE @a int; +GO + +--Post +GO + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + +--134 Declare same variable name twice + +--------------------------------------------------------------------------- +--Pre +GO +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO + +--Post +GO + +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 + +-- Parse analysis phase end +GO + +-- compile time error portion + +-- Executing test error_mapping.ErrorHandling1 +--134 Declare same variable name twice + +--------------------------------------------------------------------------- +--Pre +GO + +create procedure error_mapping.ErrorHandling1 as +begin +--------------------------------------------------------------------------- +--Generate the error + +--CHECK constraint conflict, when adding constraint +DECLARE @a int; +DECLARE @a int; +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 +GO + + +--134 Declare same variable name twice + +--------------------------------------------------------------------------- +--Pre +GO +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +--------------------------------------------------------------------------- +--Generate the error + +--CHECK constraint conflict, when adding constraint +DECLARE @a int; +DECLARE @a int; +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 + +GO +--Post +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +--134 Declare same variable name twice + +--------------------------------------------------------------------------- +--Pre +GO +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +--------------------------------------------------------------------------- +--Generate the error + +--CHECK constraint conflict, when adding constraint +DECLARE @a int; +DECLARE @a int; +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 + +GO +--Post +GO +set xact_abort OFF; +GO + +-- comiple time error portion end -- +-- Next portion is for runtime error -- + +-- Executing test error_mapping.ErrorHandling10000000 +--134 Declare same variable name twice + +--------------------------------------------------------------------------- +--Pre +--GO +-- +--create procedure error_mapping.ErrorHandling1 as +--begin +----------------------------------------------------------------------------- +----Generate the error +-- +----CHECK constraint conflict, when adding constraint +--DECLARE @a int; +--DECLARE @a int; +--if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +--select @@trancount; +--end +-- +--GO +-- +--if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +--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 +--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 +----Post +--GO +-- +-- +--set xact_abort ON; +--GO +---- Executing test error_mapping.ErrorHandling10000000 +----134 Declare same variable name twice +-- +----------------------------------------------------------------------------- +----Pre +--GO +-- +--create procedure error_mapping.ErrorHandling1 as +--begin +----------------------------------------------------------------------------- +----Generate the error +-- +----CHECK constraint conflict, when adding constraint +--DECLARE @a int; +--DECLARE @a int; +--if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +--select @@trancount; +--end +-- +--GO +-- +--if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +--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 +--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 +----Post +--GO +-- +-- +-- +--set xact_abort OFF; +--GO +-- +-- Error classification is done -- + +-- Executing test error_mapping.ErrorHandling10000000 +--134 Declare same variable name twice + +--------------------------------------------------------------------------- +--Pre +GO + +begin try +select 1 +--------------------------------------------------------------------------- +--Generate the error + +--CHECK constraint conflict, when adding constraint +DECLARE @a int; +DECLARE @a int; +end try +begin catch + select xact_state(); +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 +----Post +--GO +-- +-- +-- +GO +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/input/ErrorMapping/135_1.sql b/contrib/test/JDBC/input/ErrorMapping/135_1.sql new file mode 100644 index 00000000000..7660eda460a --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/135_1.sql @@ -0,0 +1,336 @@ +-- simple batch start + +--135 BREAK when not in WHILE loop + +--Could not find this error in excel file + +--Pre +GO +--Generate the error +BREAK +GO +--Post +GO + +begin transaction +GO +--135 BREAK when not in WHILE loop + +--Could not find this error in excel file + +--Pre +GO +--Generate the error +BREAK +GO + +-- Below output is only applicable if query is special case. for example, CREATE/ALTER TRIGGER, CREATE/ALTER FUNCTION, CREATE/ALTER PROC, CREATE/ALTER VIEW etc + +if (@@trancount > 0) select cast('compile time error' as text) else select cast('runtime error' as text) +GO + +if (@@trancount > 0) rollback tran +GO + +--Post +GO + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + +--135 BREAK when not in WHILE loop + +--Could not find this error in excel file + +--Pre +GO +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +--Generate the error +BREAK +end +GO + +--Post +GO + +create table error_mapping.temp2 (a int) +GO + +--135 BREAK when not in WHILE loop + +--Could not find this error in excel file + +--Pre +GO +insert into error_mapping.temp2 values(1) +--Generate the error +BREAK +GO + +--Post +GO + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + +--135 BREAK when not in WHILE loop + +--Could not find this error in excel file + +--Pre +GO +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO + +--Post +GO + +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 + +-- Parse analysis phase end +GO + +-- compile time error portion + +-- Executing test error_mapping.ErrorHandling1 +--135 BREAK when not in WHILE loop + +--Could not find this error in excel file + +--Pre +GO + +create procedure error_mapping.ErrorHandling1 as +begin +--Generate the error +BREAK +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 +GO + + +--135 BREAK when not in WHILE loop + +--Could not find this error in excel file + +--Pre +GO +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +--Generate the error +BREAK +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 + +GO +--Post +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +--135 BREAK when not in WHILE loop + +--Could not find this error in excel file + +--Pre +GO +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +--Generate the error +BREAK +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 + +GO +--Post +GO +set xact_abort OFF; +GO + +-- comiple time error portion end -- +-- Next portion is for runtime error -- + +-- Executing test error_mapping.ErrorHandling10000000 +--135 BREAK when not in WHILE loop + +--Could not find this error in excel file + +--Pre +--GO +-- +--create procedure error_mapping.ErrorHandling1 as +--begin +----Generate the error +--BREAK +--if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +--select @@trancount; +--end +-- +--GO +-- +--if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +--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 +--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 +----Post +--GO +-- +-- +--set xact_abort ON; +--GO +---- Executing test error_mapping.ErrorHandling10000000 +----135 BREAK when not in WHILE loop +-- +----Could not find this error in excel file +-- +----Pre +--GO +-- +--create procedure error_mapping.ErrorHandling1 as +--begin +----Generate the error +--BREAK +--if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +--select @@trancount; +--end +-- +--GO +-- +--if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +--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 +--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 +----Post +--GO +-- +-- +-- +--set xact_abort OFF; +--GO +-- +-- Error classification is done -- + +-- Executing test error_mapping.ErrorHandling10000000 +--135 BREAK when not in WHILE loop + +--Could not find this error in excel file + +--Pre +GO + +begin try +select 1 +--Generate the error +BREAK +end try +begin catch + select xact_state(); +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 +----Post +--GO +-- +-- +-- +GO +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/input/ErrorMapping/136_1.sql b/contrib/test/JDBC/input/ErrorMapping/136_1.sql new file mode 100644 index 00000000000..b679b1285b9 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/136_1.sql @@ -0,0 +1,336 @@ +-- simple batch start + +--136 CONTINUE when not in WHILE loop + +--Could not find this error in excel file + +--Pre +GO +--Generate the error +CONTINUE +GO +--Post +GO + +begin transaction +GO +--136 CONTINUE when not in WHILE loop + +--Could not find this error in excel file + +--Pre +GO +--Generate the error +CONTINUE +GO + +-- Below output is only applicable if query is special case. for example, CREATE/ALTER TRIGGER, CREATE/ALTER FUNCTION, CREATE/ALTER PROC, CREATE/ALTER VIEW etc + +if (@@trancount > 0) select cast('compile time error' as text) else select cast('runtime error' as text) +GO + +if (@@trancount > 0) rollback tran +GO + +--Post +GO + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + +--136 CONTINUE when not in WHILE loop + +--Could not find this error in excel file + +--Pre +GO +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +--Generate the error +CONTINUE +end +GO + +--Post +GO + +create table error_mapping.temp2 (a int) +GO + +--136 CONTINUE when not in WHILE loop + +--Could not find this error in excel file + +--Pre +GO +insert into error_mapping.temp2 values(1) +--Generate the error +CONTINUE +GO + +--Post +GO + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + +--136 CONTINUE when not in WHILE loop + +--Could not find this error in excel file + +--Pre +GO +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO + +--Post +GO + +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 + +-- Parse analysis phase end +GO + +-- compile time error portion + +-- Executing test error_mapping.ErrorHandling1 +--136 CONTINUE when not in WHILE loop + +--Could not find this error in excel file + +--Pre +GO + +create procedure error_mapping.ErrorHandling1 as +begin +--Generate the error +CONTINUE +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 +GO + + +--136 CONTINUE when not in WHILE loop + +--Could not find this error in excel file + +--Pre +GO +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +--Generate the error +CONTINUE +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 + +GO +--Post +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +--136 CONTINUE when not in WHILE loop + +--Could not find this error in excel file + +--Pre +GO +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +--Generate the error +CONTINUE +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 + +GO +--Post +GO +set xact_abort OFF; +GO + +-- comiple time error portion end -- +-- Next portion is for runtime error -- + +-- Executing test error_mapping.ErrorHandling10000000 +--136 CONTINUE when not in WHILE loop + +--Could not find this error in excel file + +--Pre +--GO +-- +--create procedure error_mapping.ErrorHandling1 as +--begin +----Generate the error +--CONTINUE +--if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +--select @@trancount; +--end +-- +--GO +-- +--if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +--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 +--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 +----Post +--GO +-- +-- +--set xact_abort ON; +--GO +---- Executing test error_mapping.ErrorHandling10000000 +----136 CONTINUE when not in WHILE loop +-- +----Could not find this error in excel file +-- +----Pre +--GO +-- +--create procedure error_mapping.ErrorHandling1 as +--begin +----Generate the error +--CONTINUE +--if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +--select @@trancount; +--end +-- +--GO +-- +--if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +--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 +--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 +----Post +--GO +-- +-- +-- +--set xact_abort OFF; +--GO + +-- Error classification is done -- + +-- Executing test error_mapping.ErrorHandling10000000 +--136 CONTINUE when not in WHILE loop + +--Could not find this error in excel file + +--Pre +GO + +begin try +select 1 +--Generate the error +CONTINUE +end try +begin catch + select xact_state(); +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 +----Post +--GO +-- +-- +-- +GO +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/input/ErrorMapping/141_1.sql b/contrib/test/JDBC/input/ErrorMapping/141_1.sql new file mode 100644 index 00000000000..4cca64f0fce --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/141_1.sql @@ -0,0 +1,343 @@ +-- simple batch start + +--141 Inline variable assignment for only some columns + +--Pre +CREATE TABLE t141(c1 int, c2 int); +GO +--Generate the error +DECLARE @a int; +SELECT @a = c1, c2 FROM t141 +GO +--Post +DROP TABLE t141; +GO + +begin transaction +GO +--141 Inline variable assignment for only some columns + +--Pre +CREATE TABLE t141(c1 int, c2 int); +GO +--Generate the error +DECLARE @a int; +SELECT @a = c1, c2 FROM t141 +GO + +-- Below output is only applicable if query is special case. for example, CREATE/ALTER TRIGGER, CREATE/ALTER FUNCTION, CREATE/ALTER PROC, CREATE/ALTER VIEW etc + +if (@@trancount > 0) select cast('compile time error' as text) else select cast('runtime error' as text) +GO + +if (@@trancount > 0) rollback tran +GO + +--Post +DROP TABLE t141; +GO + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + +--141 Inline variable assignment for only some columns + +--Pre +CREATE TABLE t141(c1 int, c2 int); +GO +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +--Generate the error +DECLARE @a int; +SELECT @a = c1, c2 FROM t141 +end +GO + +--Post +DROP TABLE t141; +GO + +create table error_mapping.temp2 (a int) +GO + +--141 Inline variable assignment for only some columns + +--Pre +CREATE TABLE t141(c1 int, c2 int); +GO +insert into error_mapping.temp2 values(1) +--Generate the error +DECLARE @a int; +SELECT @a = c1, c2 FROM t141 +GO + +--Post +DROP TABLE t141; +GO + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + +--141 Inline variable assignment for only some columns + +--Pre +CREATE TABLE t141(c1 int, c2 int); +GO +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO + +--Post +DROP TABLE t141; +GO + +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 + +-- Parse analysis phase end +GO + +-- compile time error portion + +-- Executing test error_mapping.ErrorHandling1 +--141 Inline variable assignment for only some columns + +--Pre +CREATE TABLE t141(c1 int, c2 int); +GO + +create procedure error_mapping.ErrorHandling1 as +begin +--Generate the error +DECLARE @a int; +SELECT @a = c1, c2 FROM t141 +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 +DROP TABLE t141; +GO + + +--141 Inline variable assignment for only some columns + +--Pre +CREATE TABLE t141(c1 int, c2 int); +GO +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +--Generate the error +DECLARE @a int; +SELECT @a = c1, c2 FROM t141 +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 + +GO +--Post +DROP TABLE t141; +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +--141 Inline variable assignment for only some columns + +--Pre +CREATE TABLE t141(c1 int, c2 int); +GO +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +--Generate the error +DECLARE @a int; +SELECT @a = c1, c2 FROM t141 +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 + +GO +--Post +DROP TABLE t141; +GO +set xact_abort OFF; +GO + +-- comiple time error portion end -- +---- Next portion is for runtime error -- +-- +---- Executing test error_mapping.ErrorHandling10000000 +----141 Inline variable assignment for only some columns +-- +----Pre +--CREATE TABLE t141(c1 int, c2 int); +--GO +-- +--create procedure error_mapping.ErrorHandling1 as +--begin +----Generate the error +--DECLARE @a int; +--SELECT @a = c1, c2 FROM t141 +--if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +--select @@trancount; +--end +-- +--GO +-- +--if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +--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 +--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 +----Post +--DROP TABLE t141; +--GO +-- +-- +--set xact_abort ON; +--GO +---- Executing test error_mapping.ErrorHandling10000000 +----141 Inline variable assignment for only some columns +-- +----Pre +--CREATE TABLE t141(c1 int, c2 int); +--GO +-- +--create procedure error_mapping.ErrorHandling1 as +--begin +----Generate the error +--DECLARE @a int; +--SELECT @a = c1, c2 FROM t141 +--if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +--select @@trancount; +--end +-- +--GO +-- +--if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +--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 +--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 +----Post +--DROP TABLE t141; +--GO +-- +-- +-- +--set xact_abort OFF; +--GO +-- +-- Error classification is done -- + +-- Executing test error_mapping.ErrorHandling10000000 +--141 Inline variable assignment for only some columns + +--Pre +CREATE TABLE t141(c1 int, c2 int); +GO + +begin try +select 1 +--Generate the error +DECLARE @a int; +SELECT @a = c1, c2 FROM t141 +end try +begin catch + select xact_state(); +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 +----Post +DROP TABLE t141; +GO + +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/input/ErrorMapping/142_1.sql b/contrib/test/JDBC/input/ErrorMapping/142_1.sql new file mode 100644 index 00000000000..9b44c9f8a9b --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/142_1.sql @@ -0,0 +1,282 @@ +-- simple batch start + +CREATE TABLE someTable(c1 int PRIMARY KEY) +GO +CREATE TABLE t142(id_c int, REFERENCES someTable(c1)) +GO +DROP TABLE someTable +GO + +begin transaction +GO +CREATE TABLE someTable(c1 int PRIMARY KEY) +GO +CREATE TABLE t142(id_c int, REFERENCES someTable(c1)) +GO + +-- Below output is only applicable if query is special case. for example, CREATE/ALTER TRIGGER, CREATE/ALTER FUNCTION, CREATE/ALTER PROC, CREATE/ALTER VIEW etc + +if (@@trancount > 0) select cast('compile time error' as text) else select cast('runtime error' as text) +GO + +if (@@trancount > 0) rollback tran +GO + +DROP TABLE someTable +GO + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + +CREATE TABLE someTable(c1 int PRIMARY KEY) +GO +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +CREATE TABLE t142(id_c int, REFERENCES someTable(c1)) +end +GO + +DROP TABLE someTable +GO + +create table error_mapping.temp2 (a int) +GO + +CREATE TABLE someTable(c1 int PRIMARY KEY) +GO +insert into error_mapping.temp2 values(1) +CREATE TABLE t142(id_c int, REFERENCES someTable(c1)) +GO + +DROP TABLE someTable +GO + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + +CREATE TABLE someTable(c1 int PRIMARY KEY) +GO +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO + +DROP TABLE someTable +GO + +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 + +-- Parse analysis phase end +GO + +-- compile time error portion + +-- Executing test error_mapping.ErrorHandling1 +CREATE TABLE someTable(c1 int PRIMARY KEY) +GO + +create procedure error_mapping.ErrorHandling1 as +begin +CREATE TABLE t142(id_c int, REFERENCES someTable(c1)) +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 +DROP TABLE someTable +GO + + +CREATE TABLE someTable(c1 int PRIMARY KEY) +GO +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +CREATE TABLE t142(id_c int, REFERENCES someTable(c1)) +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 + +GO +DROP TABLE someTable +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE someTable(c1 int PRIMARY KEY) +GO +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +CREATE TABLE t142(id_c int, REFERENCES someTable(c1)) +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 + +GO +DROP TABLE someTable +GO +set xact_abort OFF; +GO + +---- comiple time error portion end -- +---- Next portion is for runtime error -- +-- +---- Executing test error_mapping.ErrorHandling10000000 +--CREATE TABLE someTable(c1 int PRIMARY KEY) +--GO +-- +--create procedure error_mapping.ErrorHandling1 as +--begin +--CREATE TABLE t142(id_c int, REFERENCES someTable(c1)) +--if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +--select @@trancount; +--end +-- +--GO +-- +--if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +--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 +--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 +--DROP TABLE someTable +--GO +-- +-- +--set xact_abort ON; +--GO +---- Executing test error_mapping.ErrorHandling10000000 +--CREATE TABLE someTable(c1 int PRIMARY KEY) +--GO +-- +--create procedure error_mapping.ErrorHandling1 as +--begin +--CREATE TABLE t142(id_c int, REFERENCES someTable(c1)) +--if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +--select @@trancount; +--end +-- +--GO +-- +--if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +--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 +--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 +--DROP TABLE someTable +--GO +-- +-- +-- +--set xact_abort OFF; +--GO +-- +---- Error classification is done -- + +-- Executing test error_mapping.ErrorHandling10000000 +CREATE TABLE someTable(c1 int PRIMARY KEY) +GO + +begin try +select 1 +CREATE TABLE t142(id_c int, REFERENCES someTable(c1)) +end try +begin catch + select xact_state(); +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 +--DROP TABLE someTable +--GO +-- +-- +-- +GO +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/input/ErrorMapping/1505_1.sql b/contrib/test/JDBC/input/ErrorMapping/1505_1.sql new file mode 100644 index 00000000000..9ee0fa08ae4 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/1505_1.sql @@ -0,0 +1,211 @@ +# Executing test ErrorHandling1 +--Pre +CREATE TABLE t1505(c1 int); +INSERT INTO t1505 VALUES(1), (1); +GO + +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_unique_constraint', 'ignore'; +GO + +create procedure ErrorHandling1 as +begin +--Generate the error +CREATE UNIQUE INDEX x ON t1505(c1); +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +DROP TABLE t1505; +GO + + +--Pre +CREATE TABLE t1505(c1 int); +INSERT INTO t1505 VALUES(1), (1); +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +--Generate the error +CREATE UNIQUE INDEX x ON t1505(c1); +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +--Post +DROP TABLE t1505; +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +--Pre +CREATE TABLE t1505(c1 int); +INSERT INTO t1505 VALUES(1), (1); +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +--Generate the error +CREATE UNIQUE INDEX x ON t1505(c1); +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +--Post +DROP TABLE t1505; +GO +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +# Executing test ErrorHandling10000000 +--Pre +CREATE TABLE t1505(c1 int); +INSERT INTO t1505 VALUES(1), (1); +GO + +create procedure ErrorHandling1 as +begin +--Generate the error +CREATE UNIQUE INDEX x ON t1505(c1); +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +DROP TABLE t1505; +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +--Pre +CREATE TABLE t1505(c1 int); +INSERT INTO t1505 VALUES(1), (1); +GO + +create procedure ErrorHandling1 as +begin +--Generate the error +CREATE UNIQUE INDEX x ON t1505(c1); +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +DROP TABLE t1505; +GO + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +# Executing test ErrorHandling10000000 +--Pre +CREATE TABLE t1505(c1 int); +INSERT INTO t1505 VALUES(1), (1); +GO + +begin try +select 1 +--Generate the error +CREATE UNIQUE INDEX x ON t1505(c1); +end try +begin catch + select xact_state(); +end catch + +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +DROP TABLE t1505; +GO + +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_unique_constraint', 'strict'; +GO diff --git a/contrib/test/JDBC/input/ErrorMapping/16948_1.sql b/contrib/test/JDBC/input/ErrorMapping/16948_1.sql new file mode 100644 index 00000000000..e3e3c07411e --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/16948_1.sql @@ -0,0 +1,500 @@ +-- simple batch start + +CREATE TABLE t16948(c1 int) +GO +INSERT INTO t16948 (c1) +VALUES +(10), +(3), +(8) +GO + + +DECLARE @notCursor INT + +DECLARE @c1 INT +DECLARE tcursor CURSOR FOR +SELECT c1 +FROM t16948 + +OPEN tcursor +FETCH NEXT FROM @notCursor INTO @c1 + +CLOSE tcursor +DEALLOCATE tcursor + +GO +DROP TABLE t16948 +GO + + +begin transaction +GO +CREATE TABLE t16948(c1 int) +GO +INSERT INTO t16948 (c1) +VALUES +(10), +(3), +(8) +GO + + +DECLARE @notCursor INT + +DECLARE @c1 INT +DECLARE tcursor CURSOR FOR +SELECT c1 +FROM t16948 + +OPEN tcursor +FETCH NEXT FROM @notCursor INTO @c1 + +CLOSE tcursor +DEALLOCATE tcursor + +GO + +-- Below output is only applicable if query is special case. for example, CREATE/ALTER TRIGGER, CREATE/ALTER FUNCTION, CREATE/ALTER PROC, CREATE/ALTER VIEW etc + +if (@@trancount > 0) select cast('compile time error' as text) else select cast('runtime error' as text) +GO + +if (@@trancount > 0) rollback tran +GO + +DROP TABLE t16948 +GO + + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + +CREATE TABLE t16948(c1 int) +GO +INSERT INTO t16948 (c1) +VALUES +(10), +(3), +(8) +GO + + +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +DECLARE @notCursor INT + +DECLARE @c1 INT +DECLARE tcursor CURSOR FOR +SELECT c1 +FROM t16948 + +OPEN tcursor +FETCH NEXT FROM @notCursor INTO @c1 + +CLOSE tcursor +DEALLOCATE tcursor + +end +GO + +DROP TABLE t16948 +GO + + +create table error_mapping.temp2 (a int) +GO + +CREATE TABLE t16948(c1 int) +GO +INSERT INTO t16948 (c1) +VALUES +(10), +(3), +(8) +GO + + +insert into error_mapping.temp2 values(1) +DECLARE @notCursor INT + +DECLARE @c1 INT +DECLARE tcursor CURSOR FOR +SELECT c1 +FROM t16948 + +OPEN tcursor +FETCH NEXT FROM @notCursor INTO @c1 + +CLOSE tcursor +DEALLOCATE tcursor + +GO + +DROP TABLE t16948 +GO + + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + +CREATE TABLE t16948(c1 int) +GO +INSERT INTO t16948 (c1) +VALUES +(10), +(3), +(8) +GO + + +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO + +DROP TABLE t16948 +GO + + +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 + +-- Parse analysis phase end +GO + +-- compile time error portion + +-- Executing test error_mapping.ErrorHandling1 +CREATE TABLE t16948(c1 int) +GO +INSERT INTO t16948 (c1) +VALUES +(10), +(3), +(8) +GO + + + +create procedure error_mapping.ErrorHandling1 as +begin +DECLARE @notCursor INT + +DECLARE @c1 INT +DECLARE tcursor CURSOR FOR +SELECT c1 +FROM t16948 + +OPEN tcursor +FETCH NEXT FROM @notCursor INTO @c1 + +CLOSE tcursor +DEALLOCATE tcursor + +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 +DROP TABLE t16948 +GO + + + +CREATE TABLE t16948(c1 int) +GO +INSERT INTO t16948 (c1) +VALUES +(10), +(3), +(8) +GO + + +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +DECLARE @notCursor INT + +DECLARE @c1 INT +DECLARE tcursor CURSOR FOR +SELECT c1 +FROM t16948 + +OPEN tcursor +FETCH NEXT FROM @notCursor INTO @c1 + +CLOSE tcursor +DEALLOCATE tcursor + +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 + +GO +DROP TABLE t16948 +GO + + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE t16948(c1 int) +GO +INSERT INTO t16948 (c1) +VALUES +(10), +(3), +(8) +GO + + +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +DECLARE @notCursor INT + +DECLARE @c1 INT +DECLARE tcursor CURSOR FOR +SELECT c1 +FROM t16948 + +OPEN tcursor +FETCH NEXT FROM @notCursor INTO @c1 + +CLOSE tcursor +DEALLOCATE tcursor + +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 + +GO +DROP TABLE t16948 +GO + +set xact_abort OFF; +GO + +-- comiple time error portion end -- +-- Next portion is for runtime error -- + +-- Executing test error_mapping.ErrorHandling10000000 +--CREATE TABLE t16948(c1 int) +--GO +--INSERT INTO t16948 (c1) +--VALUES +--(10), +--(3), +--(8) +--GO +-- +-- +-- +--create procedure error_mapping.ErrorHandling1 as +--begin +--DECLARE @notCursor INT +-- +--DECLARE @c1 INT +--DECLARE tcursor CURSOR FOR +--SELECT c1 +--FROM t16948 +-- +--OPEN tcursor +--FETCH NEXT FROM @notCursor INTO @c1 +-- +--CLOSE tcursor +--DEALLOCATE tcursor +-- +--if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +--select @@trancount; +--end +-- +--GO +-- +--if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +--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 +--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 +--DROP TABLE t16948 +--GO +-- +-- +-- +--set xact_abort ON; +--GO +---- Executing test error_mapping.ErrorHandling10000000 +--CREATE TABLE t16948(c1 int) +--GO +--INSERT INTO t16948 (c1) +--VALUES +--(10), +--(3), +--(8) +--GO +-- +-- +-- +--create procedure error_mapping.ErrorHandling1 as +--begin +--DECLARE @notCursor INT +-- +--DECLARE @c1 INT +--DECLARE tcursor CURSOR FOR +--SELECT c1 +--FROM t16948 +-- +--OPEN tcursor +--FETCH NEXT FROM @notCursor INTO @c1 +-- +--CLOSE tcursor +--DEALLOCATE tcursor +-- +--if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +--select @@trancount; +--end +-- +--GO +-- +--if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +--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 +--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 +--DROP TABLE t16948 +--GO +-- +-- +-- +-- +--set xact_abort OFF; +--GO +-- +-- Error classification is done -- + +CREATE TABLE t16948(c1 int) +GO +INSERT INTO t16948 (c1) +VALUES +(10), +(3), +(8) +GO + + + +begin try +select 1 +DECLARE @notCursor INT + +DECLARE @c1 INT +DECLARE tcursor CURSOR FOR +SELECT c1 +FROM t16948 + +OPEN tcursor +FETCH NEXT FROM @notCursor INTO @c1 + +CLOSE tcursor +DEALLOCATE tcursor + +end try +begin catch + select xact_state(); +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 +--DROP TABLE t16948 +--GO +-- +-- +-- +-- +GO +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/input/ErrorMapping/16950_1.sql b/contrib/test/JDBC/input/ErrorMapping/16950_1.sql new file mode 100644 index 00000000000..f8f70b05594 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/16950_1.sql @@ -0,0 +1,322 @@ +-- simple batch start + +GO + +DECLARE @c1 INT +DECLARE @cursor1 CURSOR + +FETCH NEXT FROM @cursor1 INTO @c1 + +GO +GO + + +begin transaction +GO +GO + +DECLARE @c1 INT +DECLARE @cursor1 CURSOR + +FETCH NEXT FROM @cursor1 INTO @c1 + +GO + +-- Below output is only applicable if query is special case. for example, CREATE/ALTER TRIGGER, CREATE/ALTER FUNCTION, CREATE/ALTER PROC, CREATE/ALTER VIEW etc + +if (@@trancount > 0) select cast('compile time error' as text) else select cast('runtime error' as text) +GO + +if (@@trancount > 0) rollback tran +GO + +GO + + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + +GO + +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +DECLARE @c1 INT +DECLARE @cursor1 CURSOR + +FETCH NEXT FROM @cursor1 INTO @c1 + +end +GO + +GO + + +create table error_mapping.temp2 (a int) +GO + +GO + +insert into error_mapping.temp2 values(1) +DECLARE @c1 INT +DECLARE @cursor1 CURSOR + +FETCH NEXT FROM @cursor1 INTO @c1 + +GO + +GO + + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + +GO + +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO + +GO + + +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 + +-- Parse analysis phase end +GO + +-- compile time error portion + +-- Executing test error_mapping.ErrorHandling1 +GO + + +create procedure error_mapping.ErrorHandling1 as +begin +DECLARE @c1 INT +DECLARE @cursor1 CURSOR + +FETCH NEXT FROM @cursor1 INTO @c1 + +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 +GO + + + +GO + +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +DECLARE @c1 INT +DECLARE @cursor1 CURSOR + +FETCH NEXT FROM @cursor1 INTO @c1 + +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 + +GO +GO + + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +GO + +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +DECLARE @c1 INT +DECLARE @cursor1 CURSOR + +FETCH NEXT FROM @cursor1 INTO @c1 + +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 + +GO +GO + +set xact_abort OFF; +GO + +-- comiple time error portion end -- +-- Next portion is for runtime error -- + +-- Executing test error_mapping.ErrorHandling10000000 +GO + + +create procedure error_mapping.ErrorHandling1 as +begin +DECLARE @c1 INT +DECLARE @cursor1 CURSOR + +FETCH NEXT FROM @cursor1 INTO @c1 + +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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 +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 +GO + + + +set xact_abort ON; +GO +-- Executing test error_mapping.ErrorHandling10000000 +GO + + +create procedure error_mapping.ErrorHandling1 as +begin +DECLARE @c1 INT +DECLARE @cursor1 CURSOR + +FETCH NEXT FROM @cursor1 INTO @c1 + +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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 +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 +GO + + + + +set xact_abort OFF; +GO + +-- Error classification is done -- + +-- Executing test error_mapping.ErrorHandling10000000 +GO + + +begin try +select 1 +DECLARE @c1 INT +DECLARE @cursor1 CURSOR + +FETCH NEXT FROM @cursor1 INTO @c1 + +end try +begin catch + select xact_state(); +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 +GO + + + + +GO +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/input/ErrorMapping/1752_1750_2.sql b/contrib/test/JDBC/input/ErrorMapping/1752_1750_2.sql new file mode 100644 index 00000000000..316e18288e3 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/1752_1750_2.sql @@ -0,0 +1,201 @@ +# Executing test ErrorHandling1 +CREATE TABLE t1752(c1 INT, c2 INT, c3 as c1*c2) +GO + + +create procedure ErrorHandling1 as +begin +ALTER TABLE t1752 +ADD CONSTRAINT constraint1752 DEFAULT 1 FOR c3 + +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t1752 +GO + + +CREATE TABLE t1752(c1 INT, c2 INT, c3 as c1*c2) +GO + +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +ALTER TABLE t1752 +ADD CONSTRAINT constraint1752 DEFAULT 1 FOR c3 + +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +DROP TABLE t1752 +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE t1752(c1 INT, c2 INT, c3 as c1*c2) +GO + +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +ALTER TABLE t1752 +ADD CONSTRAINT constraint1752 DEFAULT 1 FOR c3 + +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +DROP TABLE t1752 +GO +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +# Executing test ErrorHandling10000000 +CREATE TABLE t1752(c1 INT, c2 INT, c3 as c1*c2) +GO + + +create procedure ErrorHandling1 as +begin +ALTER TABLE t1752 +ADD CONSTRAINT constraint1752 DEFAULT 1 FOR c3 + +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t1752 +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +CREATE TABLE t1752(c1 INT, c2 INT, c3 as c1*c2) +GO + + +create procedure ErrorHandling1 as +begin +ALTER TABLE t1752 +ADD CONSTRAINT constraint1752 DEFAULT 1 FOR c3 + +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t1752 +GO + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +# Executing test ErrorHandling10000000 +CREATE TABLE t1752(c1 INT, c2 INT, c3 as c1*c2) +GO + + +begin try +select 1 +ALTER TABLE t1752 +ADD CONSTRAINT constraint1752 DEFAULT 1 FOR c3 + +end try +begin catch + select xact_state(); +end catch + +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t1752 +GO + + diff --git a/contrib/test/JDBC/input/ErrorMapping/1765_1750_1.sql b/contrib/test/JDBC/input/ErrorMapping/1765_1750_1.sql new file mode 100644 index 00000000000..458fa4ad778 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/1765_1750_1.sql @@ -0,0 +1,303 @@ +# Executing test ErrorHandling1 +CREATE TABLE t1765_1 +( + c1 int PRIMARY KEY +,c2 int +) +GO + + + + + +create procedure ErrorHandling1 as +begin +--SET QUOTED_IDENTIFIER ON +--GO + +CREATE TABLE t1765_2 +( + c1 int PRIMARY KEY +,c2 AS c1 + 1 PERSISTED +, FOREIGN KEY (c2) + REFERENCES t1765_1(c1) ON DELETE SET NULL) + +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t1765_1 +GO + +DROP TABLE t1765_2 +GO + + +CREATE TABLE t1765_1 +( + c1 int PRIMARY KEY +,c2 int +) +GO + + + + +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +--SET QUOTED_IDENTIFIER ON +--GO + +CREATE TABLE t1765_2 +( + c1 int PRIMARY KEY +,c2 AS c1 + 1 PERSISTED +, FOREIGN KEY (c2) + REFERENCES t1765_1(c1) ON DELETE SET NULL) + +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +DROP TABLE t1765_1 +GO + +DROP TABLE t1765_2 +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE t1765_1 +( + c1 int PRIMARY KEY +,c2 int +) +GO + + + + +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +--SET QUOTED_IDENTIFIER ON +--GO + +CREATE TABLE t1765_2 +( + c1 int PRIMARY KEY +,c2 AS c1 + 1 PERSISTED +, FOREIGN KEY (c2) + REFERENCES t1765_1(c1) ON DELETE SET NULL) + +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +DROP TABLE t1765_1 +GO + +DROP TABLE t1765_2 +GO +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +# Executing test ErrorHandling10000000 +CREATE TABLE t1765_1 +( + c1 int PRIMARY KEY +,c2 int +) +GO + + + + + +create procedure ErrorHandling1 as +begin +--SET QUOTED_IDENTIFIER ON +--GO + +CREATE TABLE t1765_2 +( + c1 int PRIMARY KEY +,c2 AS c1 + 1 PERSISTED +, FOREIGN KEY (c2) + REFERENCES t1765_1(c1) ON DELETE SET NULL) + +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t1765_1 +GO + +DROP TABLE t1765_2 +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +CREATE TABLE t1765_1 +( + c1 int PRIMARY KEY +,c2 int +) +GO + + + + + +create procedure ErrorHandling1 as +begin +--SET QUOTED_IDENTIFIER ON +--GO + +CREATE TABLE t1765_2 +( + c1 int PRIMARY KEY +,c2 AS c1 + 1 PERSISTED +, FOREIGN KEY (c2) + REFERENCES t1765_1(c1) ON DELETE SET NULL) + +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t1765_1 +GO + +DROP TABLE t1765_2 +GO + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +# Executing test ErrorHandling10000000 +CREATE TABLE t1765_1 +( + c1 int PRIMARY KEY +,c2 int +) +GO + + + + + +begin try +select 1 +--SET QUOTED_IDENTIFIER ON +--GO + +CREATE TABLE t1765_2 +( + c1 int PRIMARY KEY +,c2 AS c1 + 1 PERSISTED +, FOREIGN KEY (c2) + REFERENCES t1765_1(c1) ON DELETE SET NULL) + +end try +begin catch + select xact_state(); +end catch + +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t1765_1 +GO + +DROP TABLE t1765_2 +GO + + diff --git a/contrib/test/JDBC/input/ErrorMapping/1768_1750_1.sql b/contrib/test/JDBC/input/ErrorMapping/1768_1750_1.sql new file mode 100644 index 00000000000..8adf209b2db --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/1768_1750_1.sql @@ -0,0 +1,291 @@ +# Executing test ErrorHandling1 +CREATE TABLE t1768_1( + c1 int NOT NULL +,c2 int NOT NULL +,PRIMARY KEY (c1)) +GO + +CREATE VIEW v1768 +AS +SELECT c1, c2 +FROM t1768_1 +GO + +create procedure ErrorHandling1 as +begin +CREATE TABLE t1768_2 ( + c1 int +,c2 int +,CONSTRAINT fk1768_2 FOREIGN KEY (c1) REFERENCES v1768 +) +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP VIEW v1768 +GO + +DROP TABLE t1768_1 +GO + + + + +CREATE TABLE t1768_1( + c1 int NOT NULL +,c2 int NOT NULL +,PRIMARY KEY (c1)) +GO + +CREATE VIEW v1768 +AS +SELECT c1, c2 +FROM t1768_1 +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +CREATE TABLE t1768_2 ( + c1 int +,c2 int +,CONSTRAINT fk1768_2 FOREIGN KEY (c1) REFERENCES v1768 +) +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +DROP VIEW v1768 +GO + +DROP TABLE t1768_1 +GO + + + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE t1768_1( + c1 int NOT NULL +,c2 int NOT NULL +,PRIMARY KEY (c1)) +GO + +CREATE VIEW v1768 +AS +SELECT c1, c2 +FROM t1768_1 +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +CREATE TABLE t1768_2 ( + c1 int +,c2 int +,CONSTRAINT fk1768_2 FOREIGN KEY (c1) REFERENCES v1768 +) +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +DROP VIEW v1768 +GO + +DROP TABLE t1768_1 +GO + + +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +# Executing test ErrorHandling10000000 +CREATE TABLE t1768_1( + c1 int NOT NULL +,c2 int NOT NULL +,PRIMARY KEY (c1)) +GO + +CREATE VIEW v1768 +AS +SELECT c1, c2 +FROM t1768_1 +GO + +create procedure ErrorHandling1 as +begin +CREATE TABLE t1768_2 ( + c1 int +,c2 int +,CONSTRAINT fk1768_2 FOREIGN KEY (c1) REFERENCES v1768 +) +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP VIEW v1768 +GO + +DROP TABLE t1768_1 +GO + + + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +CREATE TABLE t1768_1( + c1 int NOT NULL +,c2 int NOT NULL +,PRIMARY KEY (c1)) +GO + +CREATE VIEW v1768 +AS +SELECT c1, c2 +FROM t1768_1 +GO + +create procedure ErrorHandling1 as +begin +CREATE TABLE t1768_2 ( + c1 int +,c2 int +,CONSTRAINT fk1768_2 FOREIGN KEY (c1) REFERENCES v1768 +) +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP VIEW v1768 +GO + +DROP TABLE t1768_1 +GO + + + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +# Executing test ErrorHandling10000000 +CREATE TABLE t1768_1( + c1 int NOT NULL +,c2 int NOT NULL +,PRIMARY KEY (c1)) +GO + +CREATE VIEW v1768 +AS +SELECT c1, c2 +FROM t1768_1 +GO + +begin try +select 1 +CREATE TABLE t1768_2 ( + c1 int +,c2 int +,CONSTRAINT fk1768_2 FOREIGN KEY (c1) REFERENCES v1768 +) +end try +begin catch + select xact_state(); +end catch + +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP VIEW v1768 +GO + +DROP TABLE t1768_1 +GO + + + + diff --git a/contrib/test/JDBC/input/ErrorMapping/1770_1750_1.sql b/contrib/test/JDBC/input/ErrorMapping/1770_1750_1.sql new file mode 100644 index 00000000000..a473dcee8d7 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/1770_1750_1.sql @@ -0,0 +1,201 @@ +# Executing test ErrorHandling1 +CREATE TABLE t1770_1750_1(c1 int); +GO + +create procedure ErrorHandling1 as +begin +CREATE TABLE t1770_1750_2( + c1 int PRIMARY KEY +,c2 int, CONSTRAINT fkt1770_1750_1 FOREIGN KEY (c2) REFERENCES t1770_1750_1(c3)) +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t1770_1750_1 +GO + + + +CREATE TABLE t1770_1750_1(c1 int); +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +CREATE TABLE t1770_1750_2( + c1 int PRIMARY KEY +,c2 int, CONSTRAINT fkt1770_1750_1 FOREIGN KEY (c2) REFERENCES t1770_1750_1(c3)) +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +DROP TABLE t1770_1750_1 +GO + + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE t1770_1750_1(c1 int); +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +CREATE TABLE t1770_1750_2( + c1 int PRIMARY KEY +,c2 int, CONSTRAINT fkt1770_1750_1 FOREIGN KEY (c2) REFERENCES t1770_1750_1(c3)) +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +DROP TABLE t1770_1750_1 +GO + +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +# Executing test ErrorHandling10000000 +CREATE TABLE t1770_1750_1(c1 int); +GO + +create procedure ErrorHandling1 as +begin +CREATE TABLE t1770_1750_2( + c1 int PRIMARY KEY +,c2 int, CONSTRAINT fkt1770_1750_1 FOREIGN KEY (c2) REFERENCES t1770_1750_1(c3)) +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t1770_1750_1 +GO + + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +CREATE TABLE t1770_1750_1(c1 int); +GO + +create procedure ErrorHandling1 as +begin +CREATE TABLE t1770_1750_2( + c1 int PRIMARY KEY +,c2 int, CONSTRAINT fkt1770_1750_1 FOREIGN KEY (c2) REFERENCES t1770_1750_1(c3)) +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t1770_1750_1 +GO + + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +# Executing test ErrorHandling10000000 +CREATE TABLE t1770_1750_1(c1 int); +GO + +begin try +select 1 +CREATE TABLE t1770_1750_2( + c1 int PRIMARY KEY +,c2 int, CONSTRAINT fkt1770_1750_1 FOREIGN KEY (c2) REFERENCES t1770_1750_1(c3)) +end try +begin catch + select xact_state(); +end catch + +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t1770_1750_1 +GO + + + diff --git a/contrib/test/JDBC/input/ErrorMapping/1774_1750_1.sql b/contrib/test/JDBC/input/ErrorMapping/1774_1750_1.sql new file mode 100644 index 00000000000..a8392dfff51 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/1774_1750_1.sql @@ -0,0 +1,249 @@ +# Executing test ErrorHandling1 +CREATE TABLE t1774a( + c1 int, + c2 int, + primary key(c1,c2) + ) + +GO + + +create procedure ErrorHandling1 as +begin +CREATE TABLE t1774b +( +c1 int, +foreign key(c1) references t1774a +) +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t1774a +GO + + + +CREATE TABLE t1774a( + c1 int, + c2 int, + primary key(c1,c2) + ) + +GO + +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +CREATE TABLE t1774b +( +c1 int, +foreign key(c1) references t1774a +) +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +DROP TABLE t1774a +GO + + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE t1774a( + c1 int, + c2 int, + primary key(c1,c2) + ) + +GO + +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +CREATE TABLE t1774b +( +c1 int, +foreign key(c1) references t1774a +) +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +DROP TABLE t1774a +GO + +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +# Executing test ErrorHandling10000000 +CREATE TABLE t1774a( + c1 int, + c2 int, + primary key(c1,c2) + ) + +GO + + +create procedure ErrorHandling1 as +begin +CREATE TABLE t1774b +( +c1 int, +foreign key(c1) references t1774a +) +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t1774a +GO + + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +CREATE TABLE t1774a( + c1 int, + c2 int, + primary key(c1,c2) + ) + +GO + + +create procedure ErrorHandling1 as +begin +CREATE TABLE t1774b +( +c1 int, +foreign key(c1) references t1774a +) +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t1774a +GO + + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +# Executing test ErrorHandling10000000 +CREATE TABLE t1774a( + c1 int, + c2 int, + primary key(c1,c2) + ) + +GO + + +begin try +select 1 +CREATE TABLE t1774b +( +c1 int, +foreign key(c1) references t1774a +) +end try +begin catch + select xact_state(); +end catch + +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t1774a +GO + + + diff --git a/contrib/test/JDBC/input/ErrorMapping/180_1.sql b/contrib/test/JDBC/input/ErrorMapping/180_1.sql new file mode 100644 index 00000000000..dc7412dc953 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/180_1.sql @@ -0,0 +1,4246 @@ +-- simple batch start + + +GO +CREATE FUNCTION fn180( + @p1 int +,@p2 int +,@p3 int +,@p4 int +,@p5 int +,@p6 int +,@p7 int +,@p8 int +,@p9 int +,@p10 int +,@p11 int +,@p12 int +,@p13 int +,@p14 int +,@p15 int +,@p16 int +,@p17 int +,@p18 int +,@p19 int +,@p20 int +,@p21 int +,@p22 int +,@p23 int +,@p24 int +,@p25 int +,@p26 int +,@p27 int +,@p28 int +,@p29 int +,@p30 int +,@p31 int +,@p32 int +,@p33 int +,@p34 int +,@p35 int +,@p36 int +,@p37 int +,@p38 int +,@p39 int +,@p40 int +,@p41 int +,@p42 int +,@p43 int +,@p44 int +,@p45 int +,@p46 int +,@p47 int +,@p48 int +,@p49 int +,@p50 int +,@p51 int +,@p52 int +,@p53 int +,@p54 int +,@p55 int +,@p56 int +,@p57 int +,@p58 int +,@p59 int +,@p60 int +,@p61 int +,@p62 int +,@p63 int +,@p64 int +,@p65 int +,@p66 int +,@p67 int +,@p68 int +,@p69 int +,@p70 int +,@p71 int +,@p72 int +,@p73 int +,@p74 int +,@p75 int +,@p76 int +,@p77 int +,@p78 int +,@p79 int +,@p80 int +,@p81 int +,@p82 int +,@p83 int +,@p84 int +,@p85 int +,@p86 int +,@p87 int +,@p88 int +,@p89 int +,@p90 int +,@p91 int +,@p92 int +,@p93 int +,@p94 int +,@p95 int +,@p96 int +,@p97 int +,@p98 int +,@p99 int +,@p100 int +,@p101 int +,@p102 int +,@p103 int +,@p104 int +,@p105 int +,@p106 int +,@p107 int +,@p108 int +,@p109 int +,@p110 int +,@p111 int +,@p112 int +,@p113 int +,@p114 int +,@p115 int +,@p116 int +,@p117 int +,@p118 int +,@p119 int +,@p120 int +,@p121 int +,@p122 int +,@p123 int +,@p124 int +,@p125 int +,@p126 int +,@p127 int +,@p128 int +,@p129 int +,@p130 int +,@p131 int +,@p132 int +,@p133 int +,@p134 int +,@p135 int +,@p136 int +,@p137 int +,@p138 int +,@p139 int +,@p140 int +,@p141 int +,@p142 int +,@p143 int +,@p144 int +,@p145 int +,@p146 int +,@p147 int +,@p148 int +,@p149 int +,@p150 int +,@p151 int +,@p152 int +,@p153 int +,@p154 int +,@p155 int +,@p156 int +,@p157 int +,@p158 int +,@p159 int +,@p160 int +,@p161 int +,@p162 int +,@p163 int +,@p164 int +,@p165 int +,@p166 int +,@p167 int +,@p168 int +,@p169 int +,@p170 int +,@p171 int +,@p172 int +,@p173 int +,@p174 int +,@p175 int +,@p176 int +,@p177 int +,@p178 int +,@p179 int +,@p180 int +,@p181 int +,@p182 int +,@p183 int +,@p184 int +,@p185 int +,@p186 int +,@p187 int +,@p188 int +,@p189 int +,@p190 int +,@p191 int +,@p192 int +,@p193 int +,@p194 int +,@p195 int +,@p196 int +,@p197 int +,@p198 int +,@p199 int +,@p200 int +,@p201 int +,@p202 int +,@p203 int +,@p204 int +,@p205 int +,@p206 int +,@p207 int +,@p208 int +,@p209 int +,@p210 int +,@p211 int +,@p212 int +,@p213 int +,@p214 int +,@p215 int +,@p216 int +,@p217 int +,@p218 int +,@p219 int +,@p220 int +,@p221 int +,@p222 int +,@p223 int +,@p224 int +,@p225 int +,@p226 int +,@p227 int +,@p228 int +,@p229 int +,@p230 int +,@p231 int +,@p232 int +,@p233 int +,@p234 int +,@p235 int +,@p236 int +,@p237 int +,@p238 int +,@p239 int +,@p240 int +,@p241 int +,@p242 int +,@p243 int +,@p244 int +,@p245 int +,@p246 int +,@p247 int +,@p248 int +,@p249 int +,@p250 int +,@p251 int +,@p252 int +,@p253 int +,@p254 int +,@p255 int +,@p256 int +,@p257 int +,@p258 int +,@p259 int +,@p260 int +,@p261 int +,@p262 int +,@p263 int +,@p264 int +,@p265 int +,@p266 int +,@p267 int +,@p268 int +,@p269 int +,@p270 int +,@p271 int +,@p272 int +,@p273 int +,@p274 int +,@p275 int +,@p276 int +,@p277 int +,@p278 int +,@p279 int +,@p280 int +,@p281 int +,@p282 int +,@p283 int +,@p284 int +,@p285 int +,@p286 int +,@p287 int +,@p288 int +,@p289 int +,@p290 int +,@p291 int +,@p292 int +,@p293 int +,@p294 int +,@p295 int +,@p296 int +,@p297 int +,@p298 int +,@p299 int +,@p300 int +,@p301 int +,@p302 int +,@p303 int +,@p304 int +,@p305 int +,@p306 int +,@p307 int +,@p308 int +,@p309 int +,@p310 int +,@p311 int +,@p312 int +,@p313 int +,@p314 int +,@p315 int +,@p316 int +,@p317 int +,@p318 int +,@p319 int +,@p320 int +,@p321 int +,@p322 int +,@p323 int +,@p324 int +,@p325 int +,@p326 int +,@p327 int +,@p328 int +,@p329 int +,@p330 int +,@p331 int +,@p332 int +,@p333 int +,@p334 int +,@p335 int +,@p336 int +,@p337 int +,@p338 int +,@p339 int +,@p340 int +,@p341 int +,@p342 int +,@p343 int +,@p344 int +,@p345 int +,@p346 int +,@p347 int +,@p348 int +,@p349 int +,@p350 int +,@p351 int +,@p352 int +,@p353 int +,@p354 int +,@p355 int +,@p356 int +,@p357 int +,@p358 int +,@p359 int +,@p360 int +,@p361 int +,@p362 int +,@p363 int +,@p364 int +,@p365 int +,@p366 int +,@p367 int +,@p368 int +,@p369 int +,@p370 int +,@p371 int +,@p372 int +,@p373 int +,@p374 int +,@p375 int +,@p376 int +,@p377 int +,@p378 int +,@p379 int +,@p380 int +,@p381 int +,@p382 int +,@p383 int +,@p384 int +,@p385 int +,@p386 int +,@p387 int +,@p388 int +,@p389 int +,@p390 int +,@p391 int +,@p392 int +,@p393 int +,@p394 int +,@p395 int +,@p396 int +,@p397 int +,@p398 int +,@p399 int +,@p400 int +,@p401 int +,@p402 int +,@p403 int +,@p404 int +,@p405 int +,@p406 int +,@p407 int +,@p408 int +,@p409 int +,@p410 int +,@p411 int +,@p412 int +,@p413 int +,@p414 int +,@p415 int +,@p416 int +,@p417 int +,@p418 int +,@p419 int +,@p420 int +,@p421 int +,@p422 int +,@p423 int +,@p424 int +,@p425 int +,@p426 int +,@p427 int +,@p428 int +,@p429 int +,@p430 int +,@p431 int +,@p432 int +,@p433 int +,@p434 int +,@p435 int +,@p436 int +,@p437 int +,@p438 int +,@p439 int +,@p440 int +,@p441 int +,@p442 int +,@p443 int +,@p444 int +,@p445 int +,@p446 int +,@p447 int +,@p448 int +,@p449 int +,@p450 int +,@p451 int +,@p452 int +,@p453 int +,@p454 int +,@p455 int +,@p456 int +,@p457 int +,@p458 int +,@p459 int +,@p460 int +,@p461 int +,@p462 int +,@p463 int +,@p464 int +,@p465 int +,@p466 int +,@p467 int +,@p468 int +,@p469 int +,@p470 int +,@p471 int +,@p472 int +,@p473 int +,@p474 int +,@p475 int +,@p476 int +,@p477 int +,@p478 int +,@p479 int +,@p480 int +,@p481 int +,@p482 int +,@p483 int +,@p484 int +,@p485 int +,@p486 int +,@p487 int +,@p488 int +,@p489 int +,@p490 int +,@p491 int +,@p492 int +,@p493 int +,@p494 int +,@p495 int +,@p496 int +,@p497 int +,@p498 int +,@p499 int +,@p500 int +,@p501 int +,@p502 int +,@p503 int +,@p504 int +,@p505 int +,@p506 int +,@p507 int +,@p508 int +,@p509 int +,@p510 int +,@p511 int +,@p512 int +,@p513 int +,@p514 int +,@p515 int +,@p516 int +,@p517 int +,@p518 int +,@p519 int +,@p520 int +,@p521 int +,@p522 int +,@p523 int +,@p524 int +,@p525 int +,@p526 int +,@p527 int +,@p528 int +,@p529 int +,@p530 int +,@p531 int +,@p532 int +,@p533 int +,@p534 int +,@p535 int +,@p536 int +,@p537 int +,@p538 int +,@p539 int +,@p540 int +,@p541 int +,@p542 int +,@p543 int +,@p544 int +,@p545 int +,@p546 int +,@p547 int +,@p548 int +,@p549 int +,@p550 int +,@p551 int +,@p552 int +,@p553 int +,@p554 int +,@p555 int +,@p556 int +,@p557 int +,@p558 int +,@p559 int +,@p560 int +,@p561 int +,@p562 int +,@p563 int +,@p564 int +,@p565 int +,@p566 int +,@p567 int +,@p568 int +,@p569 int +,@p570 int +,@p571 int +,@p572 int +,@p573 int +,@p574 int +,@p575 int +,@p576 int +,@p577 int +,@p578 int +,@p579 int +,@p580 int +,@p581 int +,@p582 int +,@p583 int +,@p584 int +,@p585 int +,@p586 int +,@p587 int +,@p588 int +,@p589 int +,@p590 int +,@p591 int +,@p592 int +,@p593 int +,@p594 int +,@p595 int +,@p596 int +,@p597 int +,@p598 int +,@p599 int +,@p600 int +,@p601 int +,@p602 int +,@p603 int +,@p604 int +,@p605 int +,@p606 int +,@p607 int +,@p608 int +,@p609 int +,@p610 int +,@p611 int +,@p612 int +,@p613 int +,@p614 int +,@p615 int +,@p616 int +,@p617 int +,@p618 int +,@p619 int +,@p620 int +,@p621 int +,@p622 int +,@p623 int +,@p624 int +,@p625 int +,@p626 int +,@p627 int +,@p628 int +,@p629 int +,@p630 int +,@p631 int +,@p632 int +,@p633 int +,@p634 int +,@p635 int +,@p636 int +,@p637 int +,@p638 int +,@p639 int +,@p640 int +,@p641 int +,@p642 int +,@p643 int +,@p644 int +,@p645 int +,@p646 int +,@p647 int +,@p648 int +,@p649 int +,@p650 int +,@p651 int +,@p652 int +,@p653 int +,@p654 int +,@p655 int +,@p656 int +,@p657 int +,@p658 int +,@p659 int +,@p660 int +,@p661 int +,@p662 int +,@p663 int +,@p664 int +,@p665 int +,@p666 int +,@p667 int +,@p668 int +,@p669 int +,@p670 int +,@p671 int +,@p672 int +,@p673 int +,@p674 int +,@p675 int +,@p676 int +,@p677 int +,@p678 int +,@p679 int +,@p680 int +,@p681 int +,@p682 int +,@p683 int +,@p684 int +,@p685 int +,@p686 int +,@p687 int +,@p688 int +,@p689 int +,@p690 int +,@p691 int +,@p692 int +,@p693 int +,@p694 int +,@p695 int +,@p696 int +,@p697 int +,@p698 int +,@p699 int +,@p700 int +,@p701 int +,@p702 int +,@p703 int +,@p704 int +,@p705 int +,@p706 int +,@p707 int +,@p708 int +,@p709 int +,@p710 int +,@p711 int +,@p712 int +,@p713 int +,@p714 int +,@p715 int +,@p716 int +,@p717 int +,@p718 int +,@p719 int +,@p720 int +,@p721 int +,@p722 int +,@p723 int +,@p724 int +,@p725 int +,@p726 int +,@p727 int +,@p728 int +,@p729 int +,@p730 int +,@p731 int +,@p732 int +,@p733 int +,@p734 int +,@p735 int +,@p736 int +,@p737 int +,@p738 int +,@p739 int +,@p740 int +,@p741 int +,@p742 int +,@p743 int +,@p744 int +,@p745 int +,@p746 int +,@p747 int +,@p748 int +,@p749 int +,@p750 int +,@p751 int +,@p752 int +,@p753 int +,@p754 int +,@p755 int +,@p756 int +,@p757 int +,@p758 int +,@p759 int +,@p760 int +,@p761 int +,@p762 int +,@p763 int +,@p764 int +,@p765 int +,@p766 int +,@p767 int +,@p768 int +,@p769 int +,@p770 int +,@p771 int +,@p772 int +,@p773 int +,@p774 int +,@p775 int +,@p776 int +,@p777 int +,@p778 int +,@p779 int +,@p780 int +,@p781 int +,@p782 int +,@p783 int +,@p784 int +,@p785 int +,@p786 int +,@p787 int +,@p788 int +,@p789 int +,@p790 int +,@p791 int +,@p792 int +,@p793 int +,@p794 int +,@p795 int +,@p796 int +,@p797 int +,@p798 int +,@p799 int +,@p800 int +,@p801 int +,@p802 int +,@p803 int +,@p804 int +,@p805 int +,@p806 int +,@p807 int +,@p808 int +,@p809 int +,@p810 int +,@p811 int +,@p812 int +,@p813 int +,@p814 int +,@p815 int +,@p816 int +,@p817 int +,@p818 int +,@p819 int +,@p820 int +,@p821 int +,@p822 int +,@p823 int +,@p824 int +,@p825 int +,@p826 int +,@p827 int +,@p828 int +,@p829 int +,@p830 int +,@p831 int +,@p832 int +,@p833 int +,@p834 int +,@p835 int +,@p836 int +,@p837 int +,@p838 int +,@p839 int +,@p840 int +,@p841 int +,@p842 int +,@p843 int +,@p844 int +,@p845 int +,@p846 int +,@p847 int +,@p848 int +,@p849 int +,@p850 int +,@p851 int +,@p852 int +,@p853 int +,@p854 int +,@p855 int +,@p856 int +,@p857 int +,@p858 int +,@p859 int +,@p860 int +,@p861 int +,@p862 int +,@p863 int +,@p864 int +,@p865 int +,@p866 int +,@p867 int +,@p868 int +,@p869 int +,@p870 int +,@p871 int +,@p872 int +,@p873 int +,@p874 int +,@p875 int +,@p876 int +,@p877 int +,@p878 int +,@p879 int +,@p880 int +,@p881 int +,@p882 int +,@p883 int +,@p884 int +,@p885 int +,@p886 int +,@p887 int +,@p888 int +,@p889 int +,@p890 int +,@p891 int +,@p892 int +,@p893 int +,@p894 int +,@p895 int +,@p896 int +,@p897 int +,@p898 int +,@p899 int +,@p900 int +,@p901 int +,@p902 int +,@p903 int +,@p904 int +,@p905 int +,@p906 int +,@p907 int +,@p908 int +,@p909 int +,@p910 int +,@p911 int +,@p912 int +,@p913 int +,@p914 int +,@p915 int +,@p916 int +,@p917 int +,@p918 int +,@p919 int +,@p920 int +,@p921 int +,@p922 int +,@p923 int +,@p924 int +,@p925 int +,@p926 int +,@p927 int +,@p928 int +,@p929 int +,@p930 int +,@p931 int +,@p932 int +,@p933 int +,@p934 int +,@p935 int +,@p936 int +,@p937 int +,@p938 int +,@p939 int +,@p940 int +,@p941 int +,@p942 int +,@p943 int +,@p944 int +,@p945 int +,@p946 int +,@p947 int +,@p948 int +,@p949 int +,@p950 int +,@p951 int +,@p952 int +,@p953 int +,@p954 int +,@p955 int +,@p956 int +,@p957 int +,@p958 int +,@p959 int +,@p960 int +,@p961 int +,@p962 int +,@p963 int +,@p964 int +,@p965 int +,@p966 int +,@p967 int +,@p968 int +,@p969 int +,@p970 int +,@p971 int +,@p972 int +,@p973 int +,@p974 int +,@p975 int +,@p976 int +,@p977 int +,@p978 int +,@p979 int +,@p980 int +,@p981 int +,@p982 int +,@p983 int +,@p984 int +,@p985 int +,@p986 int +,@p987 int +,@p988 int +,@p989 int +,@p990 int +,@p991 int +,@p992 int +,@p993 int +,@p994 int +,@p995 int +,@p996 int +,@p997 int +,@p998 int +,@p999 int +,@p1000 int +,@p1001 int +,@p1002 int +,@p1003 int +,@p1004 int +,@p1005 int +,@p1006 int +,@p1007 int +,@p1008 int +,@p1009 int +,@p1010 int +,@p1011 int +,@p1012 int +,@p1013 int +,@p1014 int +,@p1015 int +,@p1016 int +,@p1017 int +,@p1018 int +,@p1019 int +,@p1020 int +,@p1021 int +,@p1022 int +,@p1023 int +,@p1024 int +,@p1025 int +,@p1026 int +,@p1027 int +,@p1028 int +,@p1029 int +,@p1030 int +,@p1031 int +,@p1032 int +,@p1033 int +,@p1034 int +,@p1035 int +,@p1036 int +,@p1037 int +,@p1038 int +,@p1039 int +,@p1040 int +,@p1041 int +,@p1042 int +,@p1043 int +,@p1044 int +,@p1045 int +,@p1046 int +,@p1047 int +,@p1048 int +,@p1049 int +,@p1050 int +,@p1051 int +,@p1052 int +,@p1053 int +,@p1054 int +,@p1055 int +,@p1056 int +,@p1057 int +,@p1058 int +,@p1059 int +,@p1060 int +,@p1061 int +,@p1062 int +,@p1063 int +,@p1064 int +,@p1065 int +,@p1066 int +,@p1067 int +,@p1068 int +,@p1069 int +,@p1070 int +,@p1071 int +,@p1072 int +,@p1073 int +,@p1074 int +,@p1075 int +,@p1076 int +,@p1077 int +,@p1078 int +,@p1079 int +,@p1080 int +,@p1081 int +,@p1082 int +,@p1083 int +,@p1084 int +,@p1085 int +,@p1086 int +,@p1087 int +,@p1088 int +,@p1089 int +,@p1090 int +,@p1091 int +,@p1092 int +,@p1093 int +,@p1094 int +,@p1095 int +,@p1096 int +,@p1097 int +,@p1098 int +,@p1099 int +,@p1100 int +,@p1101 int +,@p1102 int +,@p1103 int +,@p1104 int +,@p1105 int +,@p1106 int +,@p1107 int +,@p1108 int +,@p1109 int +,@p1110 int +,@p1111 int +,@p1112 int +,@p1113 int +,@p1114 int +,@p1115 int +,@p1116 int +,@p1117 int +,@p1118 int +,@p1119 int +,@p1120 int +,@p1121 int +,@p1122 int +,@p1123 int +,@p1124 int +,@p1125 int +,@p1126 int +,@p1127 int +,@p1128 int +,@p1129 int +,@p1130 int +,@p1131 int +,@p1132 int +,@p1133 int +,@p1134 int +,@p1135 int +,@p1136 int +,@p1137 int +,@p1138 int +,@p1139 int +,@p1140 int +,@p1141 int +,@p1142 int +,@p1143 int +,@p1144 int +,@p1145 int +,@p1146 int +,@p1147 int +,@p1148 int +,@p1149 int +,@p1150 int +,@p1151 int +,@p1152 int +,@p1153 int +,@p1154 int +,@p1155 int +,@p1156 int +,@p1157 int +,@p1158 int +,@p1159 int +,@p1160 int +,@p1161 int +,@p1162 int +,@p1163 int +,@p1164 int +,@p1165 int +,@p1166 int +,@p1167 int +,@p1168 int +,@p1169 int +,@p1170 int +,@p1171 int +,@p1172 int +,@p1173 int +,@p1174 int +,@p1175 int +,@p1176 int +,@p1177 int +,@p1178 int +,@p1179 int +,@p1180 int +,@p1181 int +,@p1182 int +,@p1183 int +,@p1184 int +,@p1185 int +,@p1186 int +,@p1187 int +,@p1188 int +,@p1189 int +,@p1190 int +,@p1191 int +,@p1192 int +,@p1193 int +,@p1194 int +,@p1195 int +,@p1196 int +,@p1197 int +,@p1198 int +,@p1199 int +,@p1200 int +,@p1201 int +,@p1202 int +,@p1203 int +,@p1204 int +,@p1205 int +,@p1206 int +,@p1207 int +,@p1208 int +,@p1209 int +,@p1210 int +,@p1211 int +,@p1212 int +,@p1213 int +,@p1214 int +,@p1215 int +,@p1216 int +,@p1217 int +,@p1218 int +,@p1219 int +,@p1220 int +,@p1221 int +,@p1222 int +,@p1223 int +,@p1224 int +,@p1225 int +,@p1226 int +,@p1227 int +,@p1228 int +,@p1229 int +,@p1230 int +,@p1231 int +,@p1232 int +,@p1233 int +,@p1234 int +,@p1235 int +,@p1236 int +,@p1237 int +,@p1238 int +,@p1239 int +,@p1240 int +,@p1241 int +,@p1242 int +,@p1243 int +,@p1244 int +,@p1245 int +,@p1246 int +,@p1247 int +,@p1248 int +,@p1249 int +,@p1250 int +,@p1251 int +,@p1252 int +,@p1253 int +,@p1254 int +,@p1255 int +,@p1256 int +,@p1257 int +,@p1258 int +,@p1259 int +,@p1260 int +,@p1261 int +,@p1262 int +,@p1263 int +,@p1264 int +,@p1265 int +,@p1266 int +,@p1267 int +,@p1268 int +,@p1269 int +,@p1270 int +,@p1271 int +,@p1272 int +,@p1273 int +,@p1274 int +,@p1275 int +,@p1276 int +,@p1277 int +,@p1278 int +,@p1279 int +,@p1280 int +,@p1281 int +,@p1282 int +,@p1283 int +,@p1284 int +,@p1285 int +,@p1286 int +,@p1287 int +,@p1288 int +,@p1289 int +,@p1290 int +,@p1291 int +,@p1292 int +,@p1293 int +,@p1294 int +,@p1295 int +,@p1296 int +,@p1297 int +,@p1298 int +,@p1299 int +,@p1300 int +,@p1301 int +,@p1302 int +,@p1303 int +,@p1304 int +,@p1305 int +,@p1306 int +,@p1307 int +,@p1308 int +,@p1309 int +,@p1310 int +,@p1311 int +,@p1312 int +,@p1313 int +,@p1314 int +,@p1315 int +,@p1316 int +,@p1317 int +,@p1318 int +,@p1319 int +,@p1320 int +,@p1321 int +,@p1322 int +,@p1323 int +,@p1324 int +,@p1325 int +,@p1326 int +,@p1327 int +,@p1328 int +,@p1329 int +,@p1330 int +,@p1331 int +,@p1332 int +,@p1333 int +,@p1334 int +,@p1335 int +,@p1336 int +,@p1337 int +,@p1338 int +,@p1339 int +,@p1340 int +,@p1341 int +,@p1342 int +,@p1343 int +,@p1344 int +,@p1345 int +,@p1346 int +,@p1347 int +,@p1348 int +,@p1349 int +,@p1350 int +,@p1351 int +,@p1352 int +,@p1353 int +,@p1354 int +,@p1355 int +,@p1356 int +,@p1357 int +,@p1358 int +,@p1359 int +,@p1360 int +,@p1361 int +,@p1362 int +,@p1363 int +,@p1364 int +,@p1365 int +,@p1366 int +,@p1367 int +,@p1368 int +,@p1369 int +,@p1370 int +,@p1371 int +,@p1372 int +,@p1373 int +,@p1374 int +,@p1375 int +,@p1376 int +,@p1377 int +,@p1378 int +,@p1379 int +,@p1380 int +,@p1381 int +,@p1382 int +,@p1383 int +,@p1384 int +,@p1385 int +,@p1386 int +,@p1387 int +,@p1388 int +,@p1389 int +,@p1390 int +,@p1391 int +,@p1392 int +,@p1393 int +,@p1394 int +,@p1395 int +,@p1396 int +,@p1397 int +,@p1398 int +,@p1399 int +,@p1400 int +,@p1401 int +,@p1402 int +,@p1403 int +,@p1404 int +,@p1405 int +,@p1406 int +,@p1407 int +,@p1408 int +,@p1409 int +,@p1410 int +,@p1411 int +,@p1412 int +,@p1413 int +,@p1414 int +,@p1415 int +,@p1416 int +,@p1417 int +,@p1418 int +,@p1419 int +,@p1420 int +,@p1421 int +,@p1422 int +,@p1423 int +,@p1424 int +,@p1425 int +,@p1426 int +,@p1427 int +,@p1428 int +,@p1429 int +,@p1430 int +,@p1431 int +,@p1432 int +,@p1433 int +,@p1434 int +,@p1435 int +,@p1436 int +,@p1437 int +,@p1438 int +,@p1439 int +,@p1440 int +,@p1441 int +,@p1442 int +,@p1443 int +,@p1444 int +,@p1445 int +,@p1446 int +,@p1447 int +,@p1448 int +,@p1449 int +,@p1450 int +,@p1451 int +,@p1452 int +,@p1453 int +,@p1454 int +,@p1455 int +,@p1456 int +,@p1457 int +,@p1458 int +,@p1459 int +,@p1460 int +,@p1461 int +,@p1462 int +,@p1463 int +,@p1464 int +,@p1465 int +,@p1466 int +,@p1467 int +,@p1468 int +,@p1469 int +,@p1470 int +,@p1471 int +,@p1472 int +,@p1473 int +,@p1474 int +,@p1475 int +,@p1476 int +,@p1477 int +,@p1478 int +,@p1479 int +,@p1480 int +,@p1481 int +,@p1482 int +,@p1483 int +,@p1484 int +,@p1485 int +,@p1486 int +,@p1487 int +,@p1488 int +,@p1489 int +,@p1490 int +,@p1491 int +,@p1492 int +,@p1493 int +,@p1494 int +,@p1495 int +,@p1496 int +,@p1497 int +,@p1498 int +,@p1499 int +,@p1500 int +,@p1501 int +,@p1502 int +,@p1503 int +,@p1504 int +,@p1505 int +,@p1506 int +,@p1507 int +,@p1508 int +,@p1509 int +,@p1510 int +,@p1511 int +,@p1512 int +,@p1513 int +,@p1514 int +,@p1515 int +,@p1516 int +,@p1517 int +,@p1518 int +,@p1519 int +,@p1520 int +,@p1521 int +,@p1522 int +,@p1523 int +,@p1524 int +,@p1525 int +,@p1526 int +,@p1527 int +,@p1528 int +,@p1529 int +,@p1530 int +,@p1531 int +,@p1532 int +,@p1533 int +,@p1534 int +,@p1535 int +,@p1536 int +,@p1537 int +,@p1538 int +,@p1539 int +,@p1540 int +,@p1541 int +,@p1542 int +,@p1543 int +,@p1544 int +,@p1545 int +,@p1546 int +,@p1547 int +,@p1548 int +,@p1549 int +,@p1550 int +,@p1551 int +,@p1552 int +,@p1553 int +,@p1554 int +,@p1555 int +,@p1556 int +,@p1557 int +,@p1558 int +,@p1559 int +,@p1560 int +,@p1561 int +,@p1562 int +,@p1563 int +,@p1564 int +,@p1565 int +,@p1566 int +,@p1567 int +,@p1568 int +,@p1569 int +,@p1570 int +,@p1571 int +,@p1572 int +,@p1573 int +,@p1574 int +,@p1575 int +,@p1576 int +,@p1577 int +,@p1578 int +,@p1579 int +,@p1580 int +,@p1581 int +,@p1582 int +,@p1583 int +,@p1584 int +,@p1585 int +,@p1586 int +,@p1587 int +,@p1588 int +,@p1589 int +,@p1590 int +,@p1591 int +,@p1592 int +,@p1593 int +,@p1594 int +,@p1595 int +,@p1596 int +,@p1597 int +,@p1598 int +,@p1599 int +,@p1600 int +,@p1601 int +,@p1602 int +,@p1603 int +,@p1604 int +,@p1605 int +,@p1606 int +,@p1607 int +,@p1608 int +,@p1609 int +,@p1610 int +,@p1611 int +,@p1612 int +,@p1613 int +,@p1614 int +,@p1615 int +,@p1616 int +,@p1617 int +,@p1618 int +,@p1619 int +,@p1620 int +,@p1621 int +,@p1622 int +,@p1623 int +,@p1624 int +,@p1625 int +,@p1626 int +,@p1627 int +,@p1628 int +,@p1629 int +,@p1630 int +,@p1631 int +,@p1632 int +,@p1633 int +,@p1634 int +,@p1635 int +,@p1636 int +,@p1637 int +,@p1638 int +,@p1639 int +,@p1640 int +,@p1641 int +,@p1642 int +,@p1643 int +,@p1644 int +,@p1645 int +,@p1646 int +,@p1647 int +,@p1648 int +,@p1649 int +,@p1650 int +,@p1651 int +,@p1652 int +,@p1653 int +,@p1654 int +,@p1655 int +,@p1656 int +,@p1657 int +,@p1658 int +,@p1659 int +,@p1660 int +,@p1661 int +,@p1662 int +,@p1663 int +,@p1664 int +,@p1665 int +,@p1666 int +,@p1667 int +,@p1668 int +,@p1669 int +,@p1670 int +,@p1671 int +,@p1672 int +,@p1673 int +,@p1674 int +,@p1675 int +,@p1676 int +,@p1677 int +,@p1678 int +,@p1679 int +,@p1680 int +,@p1681 int +,@p1682 int +,@p1683 int +,@p1684 int +,@p1685 int +,@p1686 int +,@p1687 int +,@p1688 int +,@p1689 int +,@p1690 int +,@p1691 int +,@p1692 int +,@p1693 int +,@p1694 int +,@p1695 int +,@p1696 int +,@p1697 int +,@p1698 int +,@p1699 int +,@p1700 int +,@p1701 int +,@p1702 int +,@p1703 int +,@p1704 int +,@p1705 int +,@p1706 int +,@p1707 int +,@p1708 int +,@p1709 int +,@p1710 int +,@p1711 int +,@p1712 int +,@p1713 int +,@p1714 int +,@p1715 int +,@p1716 int +,@p1717 int +,@p1718 int +,@p1719 int +,@p1720 int +,@p1721 int +,@p1722 int +,@p1723 int +,@p1724 int +,@p1725 int +,@p1726 int +,@p1727 int +,@p1728 int +,@p1729 int +,@p1730 int +,@p1731 int +,@p1732 int +,@p1733 int +,@p1734 int +,@p1735 int +,@p1736 int +,@p1737 int +,@p1738 int +,@p1739 int +,@p1740 int +,@p1741 int +,@p1742 int +,@p1743 int +,@p1744 int +,@p1745 int +,@p1746 int +,@p1747 int +,@p1748 int +,@p1749 int +,@p1750 int +,@p1751 int +,@p1752 int +,@p1753 int +,@p1754 int +,@p1755 int +,@p1756 int +,@p1757 int +,@p1758 int +,@p1759 int +,@p1760 int +,@p1761 int +,@p1762 int +,@p1763 int +,@p1764 int +,@p1765 int +,@p1766 int +,@p1767 int +,@p1768 int +,@p1769 int +,@p1770 int +,@p1771 int +,@p1772 int +,@p1773 int +,@p1774 int +,@p1775 int +,@p1776 int +,@p1777 int +,@p1778 int +,@p1779 int +,@p1780 int +,@p1781 int +,@p1782 int +,@p1783 int +,@p1784 int +,@p1785 int +,@p1786 int +,@p1787 int +,@p1788 int +,@p1789 int +,@p1790 int +,@p1791 int +,@p1792 int +,@p1793 int +,@p1794 int +,@p1795 int +,@p1796 int +,@p1797 int +,@p1798 int +,@p1799 int +,@p1800 int +,@p1801 int +,@p1802 int +,@p1803 int +,@p1804 int +,@p1805 int +,@p1806 int +,@p1807 int +,@p1808 int +,@p1809 int +,@p1810 int +,@p1811 int +,@p1812 int +,@p1813 int +,@p1814 int +,@p1815 int +,@p1816 int +,@p1817 int +,@p1818 int +,@p1819 int +,@p1820 int +,@p1821 int +,@p1822 int +,@p1823 int +,@p1824 int +,@p1825 int +,@p1826 int +,@p1827 int +,@p1828 int +,@p1829 int +,@p1830 int +,@p1831 int +,@p1832 int +,@p1833 int +,@p1834 int +,@p1835 int +,@p1836 int +,@p1837 int +,@p1838 int +,@p1839 int +,@p1840 int +,@p1841 int +,@p1842 int +,@p1843 int +,@p1844 int +,@p1845 int +,@p1846 int +,@p1847 int +,@p1848 int +,@p1849 int +,@p1850 int +,@p1851 int +,@p1852 int +,@p1853 int +,@p1854 int +,@p1855 int +,@p1856 int +,@p1857 int +,@p1858 int +,@p1859 int +,@p1860 int +,@p1861 int +,@p1862 int +,@p1863 int +,@p1864 int +,@p1865 int +,@p1866 int +,@p1867 int +,@p1868 int +,@p1869 int +,@p1870 int +,@p1871 int +,@p1872 int +,@p1873 int +,@p1874 int +,@p1875 int +,@p1876 int +,@p1877 int +,@p1878 int +,@p1879 int +,@p1880 int +,@p1881 int +,@p1882 int +,@p1883 int +,@p1884 int +,@p1885 int +,@p1886 int +,@p1887 int +,@p1888 int +,@p1889 int +,@p1890 int +,@p1891 int +,@p1892 int +,@p1893 int +,@p1894 int +,@p1895 int +,@p1896 int +,@p1897 int +,@p1898 int +,@p1899 int +,@p1900 int +,@p1901 int +,@p1902 int +,@p1903 int +,@p1904 int +,@p1905 int +,@p1906 int +,@p1907 int +,@p1908 int +,@p1909 int +,@p1910 int +,@p1911 int +,@p1912 int +,@p1913 int +,@p1914 int +,@p1915 int +,@p1916 int +,@p1917 int +,@p1918 int +,@p1919 int +,@p1920 int +,@p1921 int +,@p1922 int +,@p1923 int +,@p1924 int +,@p1925 int +,@p1926 int +,@p1927 int +,@p1928 int +,@p1929 int +,@p1930 int +,@p1931 int +,@p1932 int +,@p1933 int +,@p1934 int +,@p1935 int +,@p1936 int +,@p1937 int +,@p1938 int +,@p1939 int +,@p1940 int +,@p1941 int +,@p1942 int +,@p1943 int +,@p1944 int +,@p1945 int +,@p1946 int +,@p1947 int +,@p1948 int +,@p1949 int +,@p1950 int +,@p1951 int +,@p1952 int +,@p1953 int +,@p1954 int +,@p1955 int +,@p1956 int +,@p1957 int +,@p1958 int +,@p1959 int +,@p1960 int +,@p1961 int +,@p1962 int +,@p1963 int +,@p1964 int +,@p1965 int +,@p1966 int +,@p1967 int +,@p1968 int +,@p1969 int +,@p1970 int +,@p1971 int +,@p1972 int +,@p1973 int +,@p1974 int +,@p1975 int +,@p1976 int +,@p1977 int +,@p1978 int +,@p1979 int +,@p1980 int +,@p1981 int +,@p1982 int +,@p1983 int +,@p1984 int +,@p1985 int +,@p1986 int +,@p1987 int +,@p1988 int +,@p1989 int +,@p1990 int +,@p1991 int +,@p1992 int +,@p1993 int +,@p1994 int +,@p1995 int +,@p1996 int +,@p1997 int +,@p1998 int +,@p1999 int +,@p2000 int +,@p2001 int +,@p2002 int +,@p2003 int +,@p2004 int +,@p2005 int +,@p2006 int +,@p2007 int +,@p2008 int +,@p2009 int +,@p2010 int +,@p2011 int +,@p2012 int +,@p2013 int +,@p2014 int +,@p2015 int +,@p2016 int +,@p2017 int +,@p2018 int +,@p2019 int +,@p2020 int +,@p2021 int +,@p2022 int +,@p2023 int +,@p2024 int +,@p2025 int +,@p2026 int +,@p2027 int +,@p2028 int +,@p2029 int +,@p2030 int +,@p2031 int +,@p2032 int +,@p2033 int +,@p2034 int +,@p2035 int +,@p2036 int +,@p2037 int +,@p2038 int +,@p2039 int +,@p2040 int +,@p2041 int +,@p2042 int +,@p2043 int +,@p2044 int +,@p2045 int +,@p2046 int +,@p2047 int +,@p2048 int +,@p2049 int +,@p2050 int +,@p2051 int +,@p2052 int +,@p2053 int +,@p2054 int +,@p2055 int +,@p2056 int +,@p2057 int +,@p2058 int +,@p2059 int +,@p2060 int +,@p2061 int +,@p2062 int +,@p2063 int +,@p2064 int +,@p2065 int +,@p2066 int +,@p2067 int +,@p2068 int +,@p2069 int +,@p2070 int +,@p2071 int +,@p2072 int +,@p2073 int +,@p2074 int +,@p2075 int +,@p2076 int +,@p2077 int +,@p2078 int +,@p2079 int +,@p2080 int +,@p2081 int +,@p2082 int +,@p2083 int +,@p2084 int +,@p2085 int +,@p2086 int +,@p2087 int +,@p2088 int +,@p2089 int +,@p2090 int +,@p2091 int +,@p2092 int +,@p2093 int +,@p2094 int +,@p2095 int +,@p2096 int +,@p2097 int +,@p2098 int +,@p2099 int +,@p2100 int +,@p2101 int +) +RETURNS INT +AS +BEGIN + RETURN 100 +END + +GO + +GO + +SET XACT_ABORT ON; +GO + +begin transaction +GO + +GO +CREATE FUNCTION fn180( + @p1 int +,@p2 int +,@p3 int +,@p4 int +,@p5 int +,@p6 int +,@p7 int +,@p8 int +,@p9 int +,@p10 int +,@p11 int +,@p12 int +,@p13 int +,@p14 int +,@p15 int +,@p16 int +,@p17 int +,@p18 int +,@p19 int +,@p20 int +,@p21 int +,@p22 int +,@p23 int +,@p24 int +,@p25 int +,@p26 int +,@p27 int +,@p28 int +,@p29 int +,@p30 int +,@p31 int +,@p32 int +,@p33 int +,@p34 int +,@p35 int +,@p36 int +,@p37 int +,@p38 int +,@p39 int +,@p40 int +,@p41 int +,@p42 int +,@p43 int +,@p44 int +,@p45 int +,@p46 int +,@p47 int +,@p48 int +,@p49 int +,@p50 int +,@p51 int +,@p52 int +,@p53 int +,@p54 int +,@p55 int +,@p56 int +,@p57 int +,@p58 int +,@p59 int +,@p60 int +,@p61 int +,@p62 int +,@p63 int +,@p64 int +,@p65 int +,@p66 int +,@p67 int +,@p68 int +,@p69 int +,@p70 int +,@p71 int +,@p72 int +,@p73 int +,@p74 int +,@p75 int +,@p76 int +,@p77 int +,@p78 int +,@p79 int +,@p80 int +,@p81 int +,@p82 int +,@p83 int +,@p84 int +,@p85 int +,@p86 int +,@p87 int +,@p88 int +,@p89 int +,@p90 int +,@p91 int +,@p92 int +,@p93 int +,@p94 int +,@p95 int +,@p96 int +,@p97 int +,@p98 int +,@p99 int +,@p100 int +,@p101 int +,@p102 int +,@p103 int +,@p104 int +,@p105 int +,@p106 int +,@p107 int +,@p108 int +,@p109 int +,@p110 int +,@p111 int +,@p112 int +,@p113 int +,@p114 int +,@p115 int +,@p116 int +,@p117 int +,@p118 int +,@p119 int +,@p120 int +,@p121 int +,@p122 int +,@p123 int +,@p124 int +,@p125 int +,@p126 int +,@p127 int +,@p128 int +,@p129 int +,@p130 int +,@p131 int +,@p132 int +,@p133 int +,@p134 int +,@p135 int +,@p136 int +,@p137 int +,@p138 int +,@p139 int +,@p140 int +,@p141 int +,@p142 int +,@p143 int +,@p144 int +,@p145 int +,@p146 int +,@p147 int +,@p148 int +,@p149 int +,@p150 int +,@p151 int +,@p152 int +,@p153 int +,@p154 int +,@p155 int +,@p156 int +,@p157 int +,@p158 int +,@p159 int +,@p160 int +,@p161 int +,@p162 int +,@p163 int +,@p164 int +,@p165 int +,@p166 int +,@p167 int +,@p168 int +,@p169 int +,@p170 int +,@p171 int +,@p172 int +,@p173 int +,@p174 int +,@p175 int +,@p176 int +,@p177 int +,@p178 int +,@p179 int +,@p180 int +,@p181 int +,@p182 int +,@p183 int +,@p184 int +,@p185 int +,@p186 int +,@p187 int +,@p188 int +,@p189 int +,@p190 int +,@p191 int +,@p192 int +,@p193 int +,@p194 int +,@p195 int +,@p196 int +,@p197 int +,@p198 int +,@p199 int +,@p200 int +,@p201 int +,@p202 int +,@p203 int +,@p204 int +,@p205 int +,@p206 int +,@p207 int +,@p208 int +,@p209 int +,@p210 int +,@p211 int +,@p212 int +,@p213 int +,@p214 int +,@p215 int +,@p216 int +,@p217 int +,@p218 int +,@p219 int +,@p220 int +,@p221 int +,@p222 int +,@p223 int +,@p224 int +,@p225 int +,@p226 int +,@p227 int +,@p228 int +,@p229 int +,@p230 int +,@p231 int +,@p232 int +,@p233 int +,@p234 int +,@p235 int +,@p236 int +,@p237 int +,@p238 int +,@p239 int +,@p240 int +,@p241 int +,@p242 int +,@p243 int +,@p244 int +,@p245 int +,@p246 int +,@p247 int +,@p248 int +,@p249 int +,@p250 int +,@p251 int +,@p252 int +,@p253 int +,@p254 int +,@p255 int +,@p256 int +,@p257 int +,@p258 int +,@p259 int +,@p260 int +,@p261 int +,@p262 int +,@p263 int +,@p264 int +,@p265 int +,@p266 int +,@p267 int +,@p268 int +,@p269 int +,@p270 int +,@p271 int +,@p272 int +,@p273 int +,@p274 int +,@p275 int +,@p276 int +,@p277 int +,@p278 int +,@p279 int +,@p280 int +,@p281 int +,@p282 int +,@p283 int +,@p284 int +,@p285 int +,@p286 int +,@p287 int +,@p288 int +,@p289 int +,@p290 int +,@p291 int +,@p292 int +,@p293 int +,@p294 int +,@p295 int +,@p296 int +,@p297 int +,@p298 int +,@p299 int +,@p300 int +,@p301 int +,@p302 int +,@p303 int +,@p304 int +,@p305 int +,@p306 int +,@p307 int +,@p308 int +,@p309 int +,@p310 int +,@p311 int +,@p312 int +,@p313 int +,@p314 int +,@p315 int +,@p316 int +,@p317 int +,@p318 int +,@p319 int +,@p320 int +,@p321 int +,@p322 int +,@p323 int +,@p324 int +,@p325 int +,@p326 int +,@p327 int +,@p328 int +,@p329 int +,@p330 int +,@p331 int +,@p332 int +,@p333 int +,@p334 int +,@p335 int +,@p336 int +,@p337 int +,@p338 int +,@p339 int +,@p340 int +,@p341 int +,@p342 int +,@p343 int +,@p344 int +,@p345 int +,@p346 int +,@p347 int +,@p348 int +,@p349 int +,@p350 int +,@p351 int +,@p352 int +,@p353 int +,@p354 int +,@p355 int +,@p356 int +,@p357 int +,@p358 int +,@p359 int +,@p360 int +,@p361 int +,@p362 int +,@p363 int +,@p364 int +,@p365 int +,@p366 int +,@p367 int +,@p368 int +,@p369 int +,@p370 int +,@p371 int +,@p372 int +,@p373 int +,@p374 int +,@p375 int +,@p376 int +,@p377 int +,@p378 int +,@p379 int +,@p380 int +,@p381 int +,@p382 int +,@p383 int +,@p384 int +,@p385 int +,@p386 int +,@p387 int +,@p388 int +,@p389 int +,@p390 int +,@p391 int +,@p392 int +,@p393 int +,@p394 int +,@p395 int +,@p396 int +,@p397 int +,@p398 int +,@p399 int +,@p400 int +,@p401 int +,@p402 int +,@p403 int +,@p404 int +,@p405 int +,@p406 int +,@p407 int +,@p408 int +,@p409 int +,@p410 int +,@p411 int +,@p412 int +,@p413 int +,@p414 int +,@p415 int +,@p416 int +,@p417 int +,@p418 int +,@p419 int +,@p420 int +,@p421 int +,@p422 int +,@p423 int +,@p424 int +,@p425 int +,@p426 int +,@p427 int +,@p428 int +,@p429 int +,@p430 int +,@p431 int +,@p432 int +,@p433 int +,@p434 int +,@p435 int +,@p436 int +,@p437 int +,@p438 int +,@p439 int +,@p440 int +,@p441 int +,@p442 int +,@p443 int +,@p444 int +,@p445 int +,@p446 int +,@p447 int +,@p448 int +,@p449 int +,@p450 int +,@p451 int +,@p452 int +,@p453 int +,@p454 int +,@p455 int +,@p456 int +,@p457 int +,@p458 int +,@p459 int +,@p460 int +,@p461 int +,@p462 int +,@p463 int +,@p464 int +,@p465 int +,@p466 int +,@p467 int +,@p468 int +,@p469 int +,@p470 int +,@p471 int +,@p472 int +,@p473 int +,@p474 int +,@p475 int +,@p476 int +,@p477 int +,@p478 int +,@p479 int +,@p480 int +,@p481 int +,@p482 int +,@p483 int +,@p484 int +,@p485 int +,@p486 int +,@p487 int +,@p488 int +,@p489 int +,@p490 int +,@p491 int +,@p492 int +,@p493 int +,@p494 int +,@p495 int +,@p496 int +,@p497 int +,@p498 int +,@p499 int +,@p500 int +,@p501 int +,@p502 int +,@p503 int +,@p504 int +,@p505 int +,@p506 int +,@p507 int +,@p508 int +,@p509 int +,@p510 int +,@p511 int +,@p512 int +,@p513 int +,@p514 int +,@p515 int +,@p516 int +,@p517 int +,@p518 int +,@p519 int +,@p520 int +,@p521 int +,@p522 int +,@p523 int +,@p524 int +,@p525 int +,@p526 int +,@p527 int +,@p528 int +,@p529 int +,@p530 int +,@p531 int +,@p532 int +,@p533 int +,@p534 int +,@p535 int +,@p536 int +,@p537 int +,@p538 int +,@p539 int +,@p540 int +,@p541 int +,@p542 int +,@p543 int +,@p544 int +,@p545 int +,@p546 int +,@p547 int +,@p548 int +,@p549 int +,@p550 int +,@p551 int +,@p552 int +,@p553 int +,@p554 int +,@p555 int +,@p556 int +,@p557 int +,@p558 int +,@p559 int +,@p560 int +,@p561 int +,@p562 int +,@p563 int +,@p564 int +,@p565 int +,@p566 int +,@p567 int +,@p568 int +,@p569 int +,@p570 int +,@p571 int +,@p572 int +,@p573 int +,@p574 int +,@p575 int +,@p576 int +,@p577 int +,@p578 int +,@p579 int +,@p580 int +,@p581 int +,@p582 int +,@p583 int +,@p584 int +,@p585 int +,@p586 int +,@p587 int +,@p588 int +,@p589 int +,@p590 int +,@p591 int +,@p592 int +,@p593 int +,@p594 int +,@p595 int +,@p596 int +,@p597 int +,@p598 int +,@p599 int +,@p600 int +,@p601 int +,@p602 int +,@p603 int +,@p604 int +,@p605 int +,@p606 int +,@p607 int +,@p608 int +,@p609 int +,@p610 int +,@p611 int +,@p612 int +,@p613 int +,@p614 int +,@p615 int +,@p616 int +,@p617 int +,@p618 int +,@p619 int +,@p620 int +,@p621 int +,@p622 int +,@p623 int +,@p624 int +,@p625 int +,@p626 int +,@p627 int +,@p628 int +,@p629 int +,@p630 int +,@p631 int +,@p632 int +,@p633 int +,@p634 int +,@p635 int +,@p636 int +,@p637 int +,@p638 int +,@p639 int +,@p640 int +,@p641 int +,@p642 int +,@p643 int +,@p644 int +,@p645 int +,@p646 int +,@p647 int +,@p648 int +,@p649 int +,@p650 int +,@p651 int +,@p652 int +,@p653 int +,@p654 int +,@p655 int +,@p656 int +,@p657 int +,@p658 int +,@p659 int +,@p660 int +,@p661 int +,@p662 int +,@p663 int +,@p664 int +,@p665 int +,@p666 int +,@p667 int +,@p668 int +,@p669 int +,@p670 int +,@p671 int +,@p672 int +,@p673 int +,@p674 int +,@p675 int +,@p676 int +,@p677 int +,@p678 int +,@p679 int +,@p680 int +,@p681 int +,@p682 int +,@p683 int +,@p684 int +,@p685 int +,@p686 int +,@p687 int +,@p688 int +,@p689 int +,@p690 int +,@p691 int +,@p692 int +,@p693 int +,@p694 int +,@p695 int +,@p696 int +,@p697 int +,@p698 int +,@p699 int +,@p700 int +,@p701 int +,@p702 int +,@p703 int +,@p704 int +,@p705 int +,@p706 int +,@p707 int +,@p708 int +,@p709 int +,@p710 int +,@p711 int +,@p712 int +,@p713 int +,@p714 int +,@p715 int +,@p716 int +,@p717 int +,@p718 int +,@p719 int +,@p720 int +,@p721 int +,@p722 int +,@p723 int +,@p724 int +,@p725 int +,@p726 int +,@p727 int +,@p728 int +,@p729 int +,@p730 int +,@p731 int +,@p732 int +,@p733 int +,@p734 int +,@p735 int +,@p736 int +,@p737 int +,@p738 int +,@p739 int +,@p740 int +,@p741 int +,@p742 int +,@p743 int +,@p744 int +,@p745 int +,@p746 int +,@p747 int +,@p748 int +,@p749 int +,@p750 int +,@p751 int +,@p752 int +,@p753 int +,@p754 int +,@p755 int +,@p756 int +,@p757 int +,@p758 int +,@p759 int +,@p760 int +,@p761 int +,@p762 int +,@p763 int +,@p764 int +,@p765 int +,@p766 int +,@p767 int +,@p768 int +,@p769 int +,@p770 int +,@p771 int +,@p772 int +,@p773 int +,@p774 int +,@p775 int +,@p776 int +,@p777 int +,@p778 int +,@p779 int +,@p780 int +,@p781 int +,@p782 int +,@p783 int +,@p784 int +,@p785 int +,@p786 int +,@p787 int +,@p788 int +,@p789 int +,@p790 int +,@p791 int +,@p792 int +,@p793 int +,@p794 int +,@p795 int +,@p796 int +,@p797 int +,@p798 int +,@p799 int +,@p800 int +,@p801 int +,@p802 int +,@p803 int +,@p804 int +,@p805 int +,@p806 int +,@p807 int +,@p808 int +,@p809 int +,@p810 int +,@p811 int +,@p812 int +,@p813 int +,@p814 int +,@p815 int +,@p816 int +,@p817 int +,@p818 int +,@p819 int +,@p820 int +,@p821 int +,@p822 int +,@p823 int +,@p824 int +,@p825 int +,@p826 int +,@p827 int +,@p828 int +,@p829 int +,@p830 int +,@p831 int +,@p832 int +,@p833 int +,@p834 int +,@p835 int +,@p836 int +,@p837 int +,@p838 int +,@p839 int +,@p840 int +,@p841 int +,@p842 int +,@p843 int +,@p844 int +,@p845 int +,@p846 int +,@p847 int +,@p848 int +,@p849 int +,@p850 int +,@p851 int +,@p852 int +,@p853 int +,@p854 int +,@p855 int +,@p856 int +,@p857 int +,@p858 int +,@p859 int +,@p860 int +,@p861 int +,@p862 int +,@p863 int +,@p864 int +,@p865 int +,@p866 int +,@p867 int +,@p868 int +,@p869 int +,@p870 int +,@p871 int +,@p872 int +,@p873 int +,@p874 int +,@p875 int +,@p876 int +,@p877 int +,@p878 int +,@p879 int +,@p880 int +,@p881 int +,@p882 int +,@p883 int +,@p884 int +,@p885 int +,@p886 int +,@p887 int +,@p888 int +,@p889 int +,@p890 int +,@p891 int +,@p892 int +,@p893 int +,@p894 int +,@p895 int +,@p896 int +,@p897 int +,@p898 int +,@p899 int +,@p900 int +,@p901 int +,@p902 int +,@p903 int +,@p904 int +,@p905 int +,@p906 int +,@p907 int +,@p908 int +,@p909 int +,@p910 int +,@p911 int +,@p912 int +,@p913 int +,@p914 int +,@p915 int +,@p916 int +,@p917 int +,@p918 int +,@p919 int +,@p920 int +,@p921 int +,@p922 int +,@p923 int +,@p924 int +,@p925 int +,@p926 int +,@p927 int +,@p928 int +,@p929 int +,@p930 int +,@p931 int +,@p932 int +,@p933 int +,@p934 int +,@p935 int +,@p936 int +,@p937 int +,@p938 int +,@p939 int +,@p940 int +,@p941 int +,@p942 int +,@p943 int +,@p944 int +,@p945 int +,@p946 int +,@p947 int +,@p948 int +,@p949 int +,@p950 int +,@p951 int +,@p952 int +,@p953 int +,@p954 int +,@p955 int +,@p956 int +,@p957 int +,@p958 int +,@p959 int +,@p960 int +,@p961 int +,@p962 int +,@p963 int +,@p964 int +,@p965 int +,@p966 int +,@p967 int +,@p968 int +,@p969 int +,@p970 int +,@p971 int +,@p972 int +,@p973 int +,@p974 int +,@p975 int +,@p976 int +,@p977 int +,@p978 int +,@p979 int +,@p980 int +,@p981 int +,@p982 int +,@p983 int +,@p984 int +,@p985 int +,@p986 int +,@p987 int +,@p988 int +,@p989 int +,@p990 int +,@p991 int +,@p992 int +,@p993 int +,@p994 int +,@p995 int +,@p996 int +,@p997 int +,@p998 int +,@p999 int +,@p1000 int +,@p1001 int +,@p1002 int +,@p1003 int +,@p1004 int +,@p1005 int +,@p1006 int +,@p1007 int +,@p1008 int +,@p1009 int +,@p1010 int +,@p1011 int +,@p1012 int +,@p1013 int +,@p1014 int +,@p1015 int +,@p1016 int +,@p1017 int +,@p1018 int +,@p1019 int +,@p1020 int +,@p1021 int +,@p1022 int +,@p1023 int +,@p1024 int +,@p1025 int +,@p1026 int +,@p1027 int +,@p1028 int +,@p1029 int +,@p1030 int +,@p1031 int +,@p1032 int +,@p1033 int +,@p1034 int +,@p1035 int +,@p1036 int +,@p1037 int +,@p1038 int +,@p1039 int +,@p1040 int +,@p1041 int +,@p1042 int +,@p1043 int +,@p1044 int +,@p1045 int +,@p1046 int +,@p1047 int +,@p1048 int +,@p1049 int +,@p1050 int +,@p1051 int +,@p1052 int +,@p1053 int +,@p1054 int +,@p1055 int +,@p1056 int +,@p1057 int +,@p1058 int +,@p1059 int +,@p1060 int +,@p1061 int +,@p1062 int +,@p1063 int +,@p1064 int +,@p1065 int +,@p1066 int +,@p1067 int +,@p1068 int +,@p1069 int +,@p1070 int +,@p1071 int +,@p1072 int +,@p1073 int +,@p1074 int +,@p1075 int +,@p1076 int +,@p1077 int +,@p1078 int +,@p1079 int +,@p1080 int +,@p1081 int +,@p1082 int +,@p1083 int +,@p1084 int +,@p1085 int +,@p1086 int +,@p1087 int +,@p1088 int +,@p1089 int +,@p1090 int +,@p1091 int +,@p1092 int +,@p1093 int +,@p1094 int +,@p1095 int +,@p1096 int +,@p1097 int +,@p1098 int +,@p1099 int +,@p1100 int +,@p1101 int +,@p1102 int +,@p1103 int +,@p1104 int +,@p1105 int +,@p1106 int +,@p1107 int +,@p1108 int +,@p1109 int +,@p1110 int +,@p1111 int +,@p1112 int +,@p1113 int +,@p1114 int +,@p1115 int +,@p1116 int +,@p1117 int +,@p1118 int +,@p1119 int +,@p1120 int +,@p1121 int +,@p1122 int +,@p1123 int +,@p1124 int +,@p1125 int +,@p1126 int +,@p1127 int +,@p1128 int +,@p1129 int +,@p1130 int +,@p1131 int +,@p1132 int +,@p1133 int +,@p1134 int +,@p1135 int +,@p1136 int +,@p1137 int +,@p1138 int +,@p1139 int +,@p1140 int +,@p1141 int +,@p1142 int +,@p1143 int +,@p1144 int +,@p1145 int +,@p1146 int +,@p1147 int +,@p1148 int +,@p1149 int +,@p1150 int +,@p1151 int +,@p1152 int +,@p1153 int +,@p1154 int +,@p1155 int +,@p1156 int +,@p1157 int +,@p1158 int +,@p1159 int +,@p1160 int +,@p1161 int +,@p1162 int +,@p1163 int +,@p1164 int +,@p1165 int +,@p1166 int +,@p1167 int +,@p1168 int +,@p1169 int +,@p1170 int +,@p1171 int +,@p1172 int +,@p1173 int +,@p1174 int +,@p1175 int +,@p1176 int +,@p1177 int +,@p1178 int +,@p1179 int +,@p1180 int +,@p1181 int +,@p1182 int +,@p1183 int +,@p1184 int +,@p1185 int +,@p1186 int +,@p1187 int +,@p1188 int +,@p1189 int +,@p1190 int +,@p1191 int +,@p1192 int +,@p1193 int +,@p1194 int +,@p1195 int +,@p1196 int +,@p1197 int +,@p1198 int +,@p1199 int +,@p1200 int +,@p1201 int +,@p1202 int +,@p1203 int +,@p1204 int +,@p1205 int +,@p1206 int +,@p1207 int +,@p1208 int +,@p1209 int +,@p1210 int +,@p1211 int +,@p1212 int +,@p1213 int +,@p1214 int +,@p1215 int +,@p1216 int +,@p1217 int +,@p1218 int +,@p1219 int +,@p1220 int +,@p1221 int +,@p1222 int +,@p1223 int +,@p1224 int +,@p1225 int +,@p1226 int +,@p1227 int +,@p1228 int +,@p1229 int +,@p1230 int +,@p1231 int +,@p1232 int +,@p1233 int +,@p1234 int +,@p1235 int +,@p1236 int +,@p1237 int +,@p1238 int +,@p1239 int +,@p1240 int +,@p1241 int +,@p1242 int +,@p1243 int +,@p1244 int +,@p1245 int +,@p1246 int +,@p1247 int +,@p1248 int +,@p1249 int +,@p1250 int +,@p1251 int +,@p1252 int +,@p1253 int +,@p1254 int +,@p1255 int +,@p1256 int +,@p1257 int +,@p1258 int +,@p1259 int +,@p1260 int +,@p1261 int +,@p1262 int +,@p1263 int +,@p1264 int +,@p1265 int +,@p1266 int +,@p1267 int +,@p1268 int +,@p1269 int +,@p1270 int +,@p1271 int +,@p1272 int +,@p1273 int +,@p1274 int +,@p1275 int +,@p1276 int +,@p1277 int +,@p1278 int +,@p1279 int +,@p1280 int +,@p1281 int +,@p1282 int +,@p1283 int +,@p1284 int +,@p1285 int +,@p1286 int +,@p1287 int +,@p1288 int +,@p1289 int +,@p1290 int +,@p1291 int +,@p1292 int +,@p1293 int +,@p1294 int +,@p1295 int +,@p1296 int +,@p1297 int +,@p1298 int +,@p1299 int +,@p1300 int +,@p1301 int +,@p1302 int +,@p1303 int +,@p1304 int +,@p1305 int +,@p1306 int +,@p1307 int +,@p1308 int +,@p1309 int +,@p1310 int +,@p1311 int +,@p1312 int +,@p1313 int +,@p1314 int +,@p1315 int +,@p1316 int +,@p1317 int +,@p1318 int +,@p1319 int +,@p1320 int +,@p1321 int +,@p1322 int +,@p1323 int +,@p1324 int +,@p1325 int +,@p1326 int +,@p1327 int +,@p1328 int +,@p1329 int +,@p1330 int +,@p1331 int +,@p1332 int +,@p1333 int +,@p1334 int +,@p1335 int +,@p1336 int +,@p1337 int +,@p1338 int +,@p1339 int +,@p1340 int +,@p1341 int +,@p1342 int +,@p1343 int +,@p1344 int +,@p1345 int +,@p1346 int +,@p1347 int +,@p1348 int +,@p1349 int +,@p1350 int +,@p1351 int +,@p1352 int +,@p1353 int +,@p1354 int +,@p1355 int +,@p1356 int +,@p1357 int +,@p1358 int +,@p1359 int +,@p1360 int +,@p1361 int +,@p1362 int +,@p1363 int +,@p1364 int +,@p1365 int +,@p1366 int +,@p1367 int +,@p1368 int +,@p1369 int +,@p1370 int +,@p1371 int +,@p1372 int +,@p1373 int +,@p1374 int +,@p1375 int +,@p1376 int +,@p1377 int +,@p1378 int +,@p1379 int +,@p1380 int +,@p1381 int +,@p1382 int +,@p1383 int +,@p1384 int +,@p1385 int +,@p1386 int +,@p1387 int +,@p1388 int +,@p1389 int +,@p1390 int +,@p1391 int +,@p1392 int +,@p1393 int +,@p1394 int +,@p1395 int +,@p1396 int +,@p1397 int +,@p1398 int +,@p1399 int +,@p1400 int +,@p1401 int +,@p1402 int +,@p1403 int +,@p1404 int +,@p1405 int +,@p1406 int +,@p1407 int +,@p1408 int +,@p1409 int +,@p1410 int +,@p1411 int +,@p1412 int +,@p1413 int +,@p1414 int +,@p1415 int +,@p1416 int +,@p1417 int +,@p1418 int +,@p1419 int +,@p1420 int +,@p1421 int +,@p1422 int +,@p1423 int +,@p1424 int +,@p1425 int +,@p1426 int +,@p1427 int +,@p1428 int +,@p1429 int +,@p1430 int +,@p1431 int +,@p1432 int +,@p1433 int +,@p1434 int +,@p1435 int +,@p1436 int +,@p1437 int +,@p1438 int +,@p1439 int +,@p1440 int +,@p1441 int +,@p1442 int +,@p1443 int +,@p1444 int +,@p1445 int +,@p1446 int +,@p1447 int +,@p1448 int +,@p1449 int +,@p1450 int +,@p1451 int +,@p1452 int +,@p1453 int +,@p1454 int +,@p1455 int +,@p1456 int +,@p1457 int +,@p1458 int +,@p1459 int +,@p1460 int +,@p1461 int +,@p1462 int +,@p1463 int +,@p1464 int +,@p1465 int +,@p1466 int +,@p1467 int +,@p1468 int +,@p1469 int +,@p1470 int +,@p1471 int +,@p1472 int +,@p1473 int +,@p1474 int +,@p1475 int +,@p1476 int +,@p1477 int +,@p1478 int +,@p1479 int +,@p1480 int +,@p1481 int +,@p1482 int +,@p1483 int +,@p1484 int +,@p1485 int +,@p1486 int +,@p1487 int +,@p1488 int +,@p1489 int +,@p1490 int +,@p1491 int +,@p1492 int +,@p1493 int +,@p1494 int +,@p1495 int +,@p1496 int +,@p1497 int +,@p1498 int +,@p1499 int +,@p1500 int +,@p1501 int +,@p1502 int +,@p1503 int +,@p1504 int +,@p1505 int +,@p1506 int +,@p1507 int +,@p1508 int +,@p1509 int +,@p1510 int +,@p1511 int +,@p1512 int +,@p1513 int +,@p1514 int +,@p1515 int +,@p1516 int +,@p1517 int +,@p1518 int +,@p1519 int +,@p1520 int +,@p1521 int +,@p1522 int +,@p1523 int +,@p1524 int +,@p1525 int +,@p1526 int +,@p1527 int +,@p1528 int +,@p1529 int +,@p1530 int +,@p1531 int +,@p1532 int +,@p1533 int +,@p1534 int +,@p1535 int +,@p1536 int +,@p1537 int +,@p1538 int +,@p1539 int +,@p1540 int +,@p1541 int +,@p1542 int +,@p1543 int +,@p1544 int +,@p1545 int +,@p1546 int +,@p1547 int +,@p1548 int +,@p1549 int +,@p1550 int +,@p1551 int +,@p1552 int +,@p1553 int +,@p1554 int +,@p1555 int +,@p1556 int +,@p1557 int +,@p1558 int +,@p1559 int +,@p1560 int +,@p1561 int +,@p1562 int +,@p1563 int +,@p1564 int +,@p1565 int +,@p1566 int +,@p1567 int +,@p1568 int +,@p1569 int +,@p1570 int +,@p1571 int +,@p1572 int +,@p1573 int +,@p1574 int +,@p1575 int +,@p1576 int +,@p1577 int +,@p1578 int +,@p1579 int +,@p1580 int +,@p1581 int +,@p1582 int +,@p1583 int +,@p1584 int +,@p1585 int +,@p1586 int +,@p1587 int +,@p1588 int +,@p1589 int +,@p1590 int +,@p1591 int +,@p1592 int +,@p1593 int +,@p1594 int +,@p1595 int +,@p1596 int +,@p1597 int +,@p1598 int +,@p1599 int +,@p1600 int +,@p1601 int +,@p1602 int +,@p1603 int +,@p1604 int +,@p1605 int +,@p1606 int +,@p1607 int +,@p1608 int +,@p1609 int +,@p1610 int +,@p1611 int +,@p1612 int +,@p1613 int +,@p1614 int +,@p1615 int +,@p1616 int +,@p1617 int +,@p1618 int +,@p1619 int +,@p1620 int +,@p1621 int +,@p1622 int +,@p1623 int +,@p1624 int +,@p1625 int +,@p1626 int +,@p1627 int +,@p1628 int +,@p1629 int +,@p1630 int +,@p1631 int +,@p1632 int +,@p1633 int +,@p1634 int +,@p1635 int +,@p1636 int +,@p1637 int +,@p1638 int +,@p1639 int +,@p1640 int +,@p1641 int +,@p1642 int +,@p1643 int +,@p1644 int +,@p1645 int +,@p1646 int +,@p1647 int +,@p1648 int +,@p1649 int +,@p1650 int +,@p1651 int +,@p1652 int +,@p1653 int +,@p1654 int +,@p1655 int +,@p1656 int +,@p1657 int +,@p1658 int +,@p1659 int +,@p1660 int +,@p1661 int +,@p1662 int +,@p1663 int +,@p1664 int +,@p1665 int +,@p1666 int +,@p1667 int +,@p1668 int +,@p1669 int +,@p1670 int +,@p1671 int +,@p1672 int +,@p1673 int +,@p1674 int +,@p1675 int +,@p1676 int +,@p1677 int +,@p1678 int +,@p1679 int +,@p1680 int +,@p1681 int +,@p1682 int +,@p1683 int +,@p1684 int +,@p1685 int +,@p1686 int +,@p1687 int +,@p1688 int +,@p1689 int +,@p1690 int +,@p1691 int +,@p1692 int +,@p1693 int +,@p1694 int +,@p1695 int +,@p1696 int +,@p1697 int +,@p1698 int +,@p1699 int +,@p1700 int +,@p1701 int +,@p1702 int +,@p1703 int +,@p1704 int +,@p1705 int +,@p1706 int +,@p1707 int +,@p1708 int +,@p1709 int +,@p1710 int +,@p1711 int +,@p1712 int +,@p1713 int +,@p1714 int +,@p1715 int +,@p1716 int +,@p1717 int +,@p1718 int +,@p1719 int +,@p1720 int +,@p1721 int +,@p1722 int +,@p1723 int +,@p1724 int +,@p1725 int +,@p1726 int +,@p1727 int +,@p1728 int +,@p1729 int +,@p1730 int +,@p1731 int +,@p1732 int +,@p1733 int +,@p1734 int +,@p1735 int +,@p1736 int +,@p1737 int +,@p1738 int +,@p1739 int +,@p1740 int +,@p1741 int +,@p1742 int +,@p1743 int +,@p1744 int +,@p1745 int +,@p1746 int +,@p1747 int +,@p1748 int +,@p1749 int +,@p1750 int +,@p1751 int +,@p1752 int +,@p1753 int +,@p1754 int +,@p1755 int +,@p1756 int +,@p1757 int +,@p1758 int +,@p1759 int +,@p1760 int +,@p1761 int +,@p1762 int +,@p1763 int +,@p1764 int +,@p1765 int +,@p1766 int +,@p1767 int +,@p1768 int +,@p1769 int +,@p1770 int +,@p1771 int +,@p1772 int +,@p1773 int +,@p1774 int +,@p1775 int +,@p1776 int +,@p1777 int +,@p1778 int +,@p1779 int +,@p1780 int +,@p1781 int +,@p1782 int +,@p1783 int +,@p1784 int +,@p1785 int +,@p1786 int +,@p1787 int +,@p1788 int +,@p1789 int +,@p1790 int +,@p1791 int +,@p1792 int +,@p1793 int +,@p1794 int +,@p1795 int +,@p1796 int +,@p1797 int +,@p1798 int +,@p1799 int +,@p1800 int +,@p1801 int +,@p1802 int +,@p1803 int +,@p1804 int +,@p1805 int +,@p1806 int +,@p1807 int +,@p1808 int +,@p1809 int +,@p1810 int +,@p1811 int +,@p1812 int +,@p1813 int +,@p1814 int +,@p1815 int +,@p1816 int +,@p1817 int +,@p1818 int +,@p1819 int +,@p1820 int +,@p1821 int +,@p1822 int +,@p1823 int +,@p1824 int +,@p1825 int +,@p1826 int +,@p1827 int +,@p1828 int +,@p1829 int +,@p1830 int +,@p1831 int +,@p1832 int +,@p1833 int +,@p1834 int +,@p1835 int +,@p1836 int +,@p1837 int +,@p1838 int +,@p1839 int +,@p1840 int +,@p1841 int +,@p1842 int +,@p1843 int +,@p1844 int +,@p1845 int +,@p1846 int +,@p1847 int +,@p1848 int +,@p1849 int +,@p1850 int +,@p1851 int +,@p1852 int +,@p1853 int +,@p1854 int +,@p1855 int +,@p1856 int +,@p1857 int +,@p1858 int +,@p1859 int +,@p1860 int +,@p1861 int +,@p1862 int +,@p1863 int +,@p1864 int +,@p1865 int +,@p1866 int +,@p1867 int +,@p1868 int +,@p1869 int +,@p1870 int +,@p1871 int +,@p1872 int +,@p1873 int +,@p1874 int +,@p1875 int +,@p1876 int +,@p1877 int +,@p1878 int +,@p1879 int +,@p1880 int +,@p1881 int +,@p1882 int +,@p1883 int +,@p1884 int +,@p1885 int +,@p1886 int +,@p1887 int +,@p1888 int +,@p1889 int +,@p1890 int +,@p1891 int +,@p1892 int +,@p1893 int +,@p1894 int +,@p1895 int +,@p1896 int +,@p1897 int +,@p1898 int +,@p1899 int +,@p1900 int +,@p1901 int +,@p1902 int +,@p1903 int +,@p1904 int +,@p1905 int +,@p1906 int +,@p1907 int +,@p1908 int +,@p1909 int +,@p1910 int +,@p1911 int +,@p1912 int +,@p1913 int +,@p1914 int +,@p1915 int +,@p1916 int +,@p1917 int +,@p1918 int +,@p1919 int +,@p1920 int +,@p1921 int +,@p1922 int +,@p1923 int +,@p1924 int +,@p1925 int +,@p1926 int +,@p1927 int +,@p1928 int +,@p1929 int +,@p1930 int +,@p1931 int +,@p1932 int +,@p1933 int +,@p1934 int +,@p1935 int +,@p1936 int +,@p1937 int +,@p1938 int +,@p1939 int +,@p1940 int +,@p1941 int +,@p1942 int +,@p1943 int +,@p1944 int +,@p1945 int +,@p1946 int +,@p1947 int +,@p1948 int +,@p1949 int +,@p1950 int +,@p1951 int +,@p1952 int +,@p1953 int +,@p1954 int +,@p1955 int +,@p1956 int +,@p1957 int +,@p1958 int +,@p1959 int +,@p1960 int +,@p1961 int +,@p1962 int +,@p1963 int +,@p1964 int +,@p1965 int +,@p1966 int +,@p1967 int +,@p1968 int +,@p1969 int +,@p1970 int +,@p1971 int +,@p1972 int +,@p1973 int +,@p1974 int +,@p1975 int +,@p1976 int +,@p1977 int +,@p1978 int +,@p1979 int +,@p1980 int +,@p1981 int +,@p1982 int +,@p1983 int +,@p1984 int +,@p1985 int +,@p1986 int +,@p1987 int +,@p1988 int +,@p1989 int +,@p1990 int +,@p1991 int +,@p1992 int +,@p1993 int +,@p1994 int +,@p1995 int +,@p1996 int +,@p1997 int +,@p1998 int +,@p1999 int +,@p2000 int +,@p2001 int +,@p2002 int +,@p2003 int +,@p2004 int +,@p2005 int +,@p2006 int +,@p2007 int +,@p2008 int +,@p2009 int +,@p2010 int +,@p2011 int +,@p2012 int +,@p2013 int +,@p2014 int +,@p2015 int +,@p2016 int +,@p2017 int +,@p2018 int +,@p2019 int +,@p2020 int +,@p2021 int +,@p2022 int +,@p2023 int +,@p2024 int +,@p2025 int +,@p2026 int +,@p2027 int +,@p2028 int +,@p2029 int +,@p2030 int +,@p2031 int +,@p2032 int +,@p2033 int +,@p2034 int +,@p2035 int +,@p2036 int +,@p2037 int +,@p2038 int +,@p2039 int +,@p2040 int +,@p2041 int +,@p2042 int +,@p2043 int +,@p2044 int +,@p2045 int +,@p2046 int +,@p2047 int +,@p2048 int +,@p2049 int +,@p2050 int +,@p2051 int +,@p2052 int +,@p2053 int +,@p2054 int +,@p2055 int +,@p2056 int +,@p2057 int +,@p2058 int +,@p2059 int +,@p2060 int +,@p2061 int +,@p2062 int +,@p2063 int +,@p2064 int +,@p2065 int +,@p2066 int +,@p2067 int +,@p2068 int +,@p2069 int +,@p2070 int +,@p2071 int +,@p2072 int +,@p2073 int +,@p2074 int +,@p2075 int +,@p2076 int +,@p2077 int +,@p2078 int +,@p2079 int +,@p2080 int +,@p2081 int +,@p2082 int +,@p2083 int +,@p2084 int +,@p2085 int +,@p2086 int +,@p2087 int +,@p2088 int +,@p2089 int +,@p2090 int +,@p2091 int +,@p2092 int +,@p2093 int +,@p2094 int +,@p2095 int +,@p2096 int +,@p2097 int +,@p2098 int +,@p2099 int +,@p2100 int +,@p2101 int +) +RETURNS INT +AS +BEGIN + RETURN 100 +END + +GO + +if (@@trancount > 0) select cast('Does not respect xact_abort flag' as text) else select cast('Respects xact_abort flag' as text) +GO + +if (@@trancount > 0) rollback tran +GO + +GO + +SET XACT_ABORT OFF; +GO + diff --git a/contrib/test/JDBC/input/ErrorMapping/180_2.sql b/contrib/test/JDBC/input/ErrorMapping/180_2.sql new file mode 100644 index 00000000000..2ec467a6bd5 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/180_2.sql @@ -0,0 +1,4242 @@ +-- simple batch start + + +GO +CREATE PROC p180( + @p1 int +,@p2 int +,@p3 int +,@p4 int +,@p5 int +,@p6 int +,@p7 int +,@p8 int +,@p9 int +,@p10 int +,@p11 int +,@p12 int +,@p13 int +,@p14 int +,@p15 int +,@p16 int +,@p17 int +,@p18 int +,@p19 int +,@p20 int +,@p21 int +,@p22 int +,@p23 int +,@p24 int +,@p25 int +,@p26 int +,@p27 int +,@p28 int +,@p29 int +,@p30 int +,@p31 int +,@p32 int +,@p33 int +,@p34 int +,@p35 int +,@p36 int +,@p37 int +,@p38 int +,@p39 int +,@p40 int +,@p41 int +,@p42 int +,@p43 int +,@p44 int +,@p45 int +,@p46 int +,@p47 int +,@p48 int +,@p49 int +,@p50 int +,@p51 int +,@p52 int +,@p53 int +,@p54 int +,@p55 int +,@p56 int +,@p57 int +,@p58 int +,@p59 int +,@p60 int +,@p61 int +,@p62 int +,@p63 int +,@p64 int +,@p65 int +,@p66 int +,@p67 int +,@p68 int +,@p69 int +,@p70 int +,@p71 int +,@p72 int +,@p73 int +,@p74 int +,@p75 int +,@p76 int +,@p77 int +,@p78 int +,@p79 int +,@p80 int +,@p81 int +,@p82 int +,@p83 int +,@p84 int +,@p85 int +,@p86 int +,@p87 int +,@p88 int +,@p89 int +,@p90 int +,@p91 int +,@p92 int +,@p93 int +,@p94 int +,@p95 int +,@p96 int +,@p97 int +,@p98 int +,@p99 int +,@p100 int +,@p101 int +,@p102 int +,@p103 int +,@p104 int +,@p105 int +,@p106 int +,@p107 int +,@p108 int +,@p109 int +,@p110 int +,@p111 int +,@p112 int +,@p113 int +,@p114 int +,@p115 int +,@p116 int +,@p117 int +,@p118 int +,@p119 int +,@p120 int +,@p121 int +,@p122 int +,@p123 int +,@p124 int +,@p125 int +,@p126 int +,@p127 int +,@p128 int +,@p129 int +,@p130 int +,@p131 int +,@p132 int +,@p133 int +,@p134 int +,@p135 int +,@p136 int +,@p137 int +,@p138 int +,@p139 int +,@p140 int +,@p141 int +,@p142 int +,@p143 int +,@p144 int +,@p145 int +,@p146 int +,@p147 int +,@p148 int +,@p149 int +,@p150 int +,@p151 int +,@p152 int +,@p153 int +,@p154 int +,@p155 int +,@p156 int +,@p157 int +,@p158 int +,@p159 int +,@p160 int +,@p161 int +,@p162 int +,@p163 int +,@p164 int +,@p165 int +,@p166 int +,@p167 int +,@p168 int +,@p169 int +,@p170 int +,@p171 int +,@p172 int +,@p173 int +,@p174 int +,@p175 int +,@p176 int +,@p177 int +,@p178 int +,@p179 int +,@p180 int +,@p181 int +,@p182 int +,@p183 int +,@p184 int +,@p185 int +,@p186 int +,@p187 int +,@p188 int +,@p189 int +,@p190 int +,@p191 int +,@p192 int +,@p193 int +,@p194 int +,@p195 int +,@p196 int +,@p197 int +,@p198 int +,@p199 int +,@p200 int +,@p201 int +,@p202 int +,@p203 int +,@p204 int +,@p205 int +,@p206 int +,@p207 int +,@p208 int +,@p209 int +,@p210 int +,@p211 int +,@p212 int +,@p213 int +,@p214 int +,@p215 int +,@p216 int +,@p217 int +,@p218 int +,@p219 int +,@p220 int +,@p221 int +,@p222 int +,@p223 int +,@p224 int +,@p225 int +,@p226 int +,@p227 int +,@p228 int +,@p229 int +,@p230 int +,@p231 int +,@p232 int +,@p233 int +,@p234 int +,@p235 int +,@p236 int +,@p237 int +,@p238 int +,@p239 int +,@p240 int +,@p241 int +,@p242 int +,@p243 int +,@p244 int +,@p245 int +,@p246 int +,@p247 int +,@p248 int +,@p249 int +,@p250 int +,@p251 int +,@p252 int +,@p253 int +,@p254 int +,@p255 int +,@p256 int +,@p257 int +,@p258 int +,@p259 int +,@p260 int +,@p261 int +,@p262 int +,@p263 int +,@p264 int +,@p265 int +,@p266 int +,@p267 int +,@p268 int +,@p269 int +,@p270 int +,@p271 int +,@p272 int +,@p273 int +,@p274 int +,@p275 int +,@p276 int +,@p277 int +,@p278 int +,@p279 int +,@p280 int +,@p281 int +,@p282 int +,@p283 int +,@p284 int +,@p285 int +,@p286 int +,@p287 int +,@p288 int +,@p289 int +,@p290 int +,@p291 int +,@p292 int +,@p293 int +,@p294 int +,@p295 int +,@p296 int +,@p297 int +,@p298 int +,@p299 int +,@p300 int +,@p301 int +,@p302 int +,@p303 int +,@p304 int +,@p305 int +,@p306 int +,@p307 int +,@p308 int +,@p309 int +,@p310 int +,@p311 int +,@p312 int +,@p313 int +,@p314 int +,@p315 int +,@p316 int +,@p317 int +,@p318 int +,@p319 int +,@p320 int +,@p321 int +,@p322 int +,@p323 int +,@p324 int +,@p325 int +,@p326 int +,@p327 int +,@p328 int +,@p329 int +,@p330 int +,@p331 int +,@p332 int +,@p333 int +,@p334 int +,@p335 int +,@p336 int +,@p337 int +,@p338 int +,@p339 int +,@p340 int +,@p341 int +,@p342 int +,@p343 int +,@p344 int +,@p345 int +,@p346 int +,@p347 int +,@p348 int +,@p349 int +,@p350 int +,@p351 int +,@p352 int +,@p353 int +,@p354 int +,@p355 int +,@p356 int +,@p357 int +,@p358 int +,@p359 int +,@p360 int +,@p361 int +,@p362 int +,@p363 int +,@p364 int +,@p365 int +,@p366 int +,@p367 int +,@p368 int +,@p369 int +,@p370 int +,@p371 int +,@p372 int +,@p373 int +,@p374 int +,@p375 int +,@p376 int +,@p377 int +,@p378 int +,@p379 int +,@p380 int +,@p381 int +,@p382 int +,@p383 int +,@p384 int +,@p385 int +,@p386 int +,@p387 int +,@p388 int +,@p389 int +,@p390 int +,@p391 int +,@p392 int +,@p393 int +,@p394 int +,@p395 int +,@p396 int +,@p397 int +,@p398 int +,@p399 int +,@p400 int +,@p401 int +,@p402 int +,@p403 int +,@p404 int +,@p405 int +,@p406 int +,@p407 int +,@p408 int +,@p409 int +,@p410 int +,@p411 int +,@p412 int +,@p413 int +,@p414 int +,@p415 int +,@p416 int +,@p417 int +,@p418 int +,@p419 int +,@p420 int +,@p421 int +,@p422 int +,@p423 int +,@p424 int +,@p425 int +,@p426 int +,@p427 int +,@p428 int +,@p429 int +,@p430 int +,@p431 int +,@p432 int +,@p433 int +,@p434 int +,@p435 int +,@p436 int +,@p437 int +,@p438 int +,@p439 int +,@p440 int +,@p441 int +,@p442 int +,@p443 int +,@p444 int +,@p445 int +,@p446 int +,@p447 int +,@p448 int +,@p449 int +,@p450 int +,@p451 int +,@p452 int +,@p453 int +,@p454 int +,@p455 int +,@p456 int +,@p457 int +,@p458 int +,@p459 int +,@p460 int +,@p461 int +,@p462 int +,@p463 int +,@p464 int +,@p465 int +,@p466 int +,@p467 int +,@p468 int +,@p469 int +,@p470 int +,@p471 int +,@p472 int +,@p473 int +,@p474 int +,@p475 int +,@p476 int +,@p477 int +,@p478 int +,@p479 int +,@p480 int +,@p481 int +,@p482 int +,@p483 int +,@p484 int +,@p485 int +,@p486 int +,@p487 int +,@p488 int +,@p489 int +,@p490 int +,@p491 int +,@p492 int +,@p493 int +,@p494 int +,@p495 int +,@p496 int +,@p497 int +,@p498 int +,@p499 int +,@p500 int +,@p501 int +,@p502 int +,@p503 int +,@p504 int +,@p505 int +,@p506 int +,@p507 int +,@p508 int +,@p509 int +,@p510 int +,@p511 int +,@p512 int +,@p513 int +,@p514 int +,@p515 int +,@p516 int +,@p517 int +,@p518 int +,@p519 int +,@p520 int +,@p521 int +,@p522 int +,@p523 int +,@p524 int +,@p525 int +,@p526 int +,@p527 int +,@p528 int +,@p529 int +,@p530 int +,@p531 int +,@p532 int +,@p533 int +,@p534 int +,@p535 int +,@p536 int +,@p537 int +,@p538 int +,@p539 int +,@p540 int +,@p541 int +,@p542 int +,@p543 int +,@p544 int +,@p545 int +,@p546 int +,@p547 int +,@p548 int +,@p549 int +,@p550 int +,@p551 int +,@p552 int +,@p553 int +,@p554 int +,@p555 int +,@p556 int +,@p557 int +,@p558 int +,@p559 int +,@p560 int +,@p561 int +,@p562 int +,@p563 int +,@p564 int +,@p565 int +,@p566 int +,@p567 int +,@p568 int +,@p569 int +,@p570 int +,@p571 int +,@p572 int +,@p573 int +,@p574 int +,@p575 int +,@p576 int +,@p577 int +,@p578 int +,@p579 int +,@p580 int +,@p581 int +,@p582 int +,@p583 int +,@p584 int +,@p585 int +,@p586 int +,@p587 int +,@p588 int +,@p589 int +,@p590 int +,@p591 int +,@p592 int +,@p593 int +,@p594 int +,@p595 int +,@p596 int +,@p597 int +,@p598 int +,@p599 int +,@p600 int +,@p601 int +,@p602 int +,@p603 int +,@p604 int +,@p605 int +,@p606 int +,@p607 int +,@p608 int +,@p609 int +,@p610 int +,@p611 int +,@p612 int +,@p613 int +,@p614 int +,@p615 int +,@p616 int +,@p617 int +,@p618 int +,@p619 int +,@p620 int +,@p621 int +,@p622 int +,@p623 int +,@p624 int +,@p625 int +,@p626 int +,@p627 int +,@p628 int +,@p629 int +,@p630 int +,@p631 int +,@p632 int +,@p633 int +,@p634 int +,@p635 int +,@p636 int +,@p637 int +,@p638 int +,@p639 int +,@p640 int +,@p641 int +,@p642 int +,@p643 int +,@p644 int +,@p645 int +,@p646 int +,@p647 int +,@p648 int +,@p649 int +,@p650 int +,@p651 int +,@p652 int +,@p653 int +,@p654 int +,@p655 int +,@p656 int +,@p657 int +,@p658 int +,@p659 int +,@p660 int +,@p661 int +,@p662 int +,@p663 int +,@p664 int +,@p665 int +,@p666 int +,@p667 int +,@p668 int +,@p669 int +,@p670 int +,@p671 int +,@p672 int +,@p673 int +,@p674 int +,@p675 int +,@p676 int +,@p677 int +,@p678 int +,@p679 int +,@p680 int +,@p681 int +,@p682 int +,@p683 int +,@p684 int +,@p685 int +,@p686 int +,@p687 int +,@p688 int +,@p689 int +,@p690 int +,@p691 int +,@p692 int +,@p693 int +,@p694 int +,@p695 int +,@p696 int +,@p697 int +,@p698 int +,@p699 int +,@p700 int +,@p701 int +,@p702 int +,@p703 int +,@p704 int +,@p705 int +,@p706 int +,@p707 int +,@p708 int +,@p709 int +,@p710 int +,@p711 int +,@p712 int +,@p713 int +,@p714 int +,@p715 int +,@p716 int +,@p717 int +,@p718 int +,@p719 int +,@p720 int +,@p721 int +,@p722 int +,@p723 int +,@p724 int +,@p725 int +,@p726 int +,@p727 int +,@p728 int +,@p729 int +,@p730 int +,@p731 int +,@p732 int +,@p733 int +,@p734 int +,@p735 int +,@p736 int +,@p737 int +,@p738 int +,@p739 int +,@p740 int +,@p741 int +,@p742 int +,@p743 int +,@p744 int +,@p745 int +,@p746 int +,@p747 int +,@p748 int +,@p749 int +,@p750 int +,@p751 int +,@p752 int +,@p753 int +,@p754 int +,@p755 int +,@p756 int +,@p757 int +,@p758 int +,@p759 int +,@p760 int +,@p761 int +,@p762 int +,@p763 int +,@p764 int +,@p765 int +,@p766 int +,@p767 int +,@p768 int +,@p769 int +,@p770 int +,@p771 int +,@p772 int +,@p773 int +,@p774 int +,@p775 int +,@p776 int +,@p777 int +,@p778 int +,@p779 int +,@p780 int +,@p781 int +,@p782 int +,@p783 int +,@p784 int +,@p785 int +,@p786 int +,@p787 int +,@p788 int +,@p789 int +,@p790 int +,@p791 int +,@p792 int +,@p793 int +,@p794 int +,@p795 int +,@p796 int +,@p797 int +,@p798 int +,@p799 int +,@p800 int +,@p801 int +,@p802 int +,@p803 int +,@p804 int +,@p805 int +,@p806 int +,@p807 int +,@p808 int +,@p809 int +,@p810 int +,@p811 int +,@p812 int +,@p813 int +,@p814 int +,@p815 int +,@p816 int +,@p817 int +,@p818 int +,@p819 int +,@p820 int +,@p821 int +,@p822 int +,@p823 int +,@p824 int +,@p825 int +,@p826 int +,@p827 int +,@p828 int +,@p829 int +,@p830 int +,@p831 int +,@p832 int +,@p833 int +,@p834 int +,@p835 int +,@p836 int +,@p837 int +,@p838 int +,@p839 int +,@p840 int +,@p841 int +,@p842 int +,@p843 int +,@p844 int +,@p845 int +,@p846 int +,@p847 int +,@p848 int +,@p849 int +,@p850 int +,@p851 int +,@p852 int +,@p853 int +,@p854 int +,@p855 int +,@p856 int +,@p857 int +,@p858 int +,@p859 int +,@p860 int +,@p861 int +,@p862 int +,@p863 int +,@p864 int +,@p865 int +,@p866 int +,@p867 int +,@p868 int +,@p869 int +,@p870 int +,@p871 int +,@p872 int +,@p873 int +,@p874 int +,@p875 int +,@p876 int +,@p877 int +,@p878 int +,@p879 int +,@p880 int +,@p881 int +,@p882 int +,@p883 int +,@p884 int +,@p885 int +,@p886 int +,@p887 int +,@p888 int +,@p889 int +,@p890 int +,@p891 int +,@p892 int +,@p893 int +,@p894 int +,@p895 int +,@p896 int +,@p897 int +,@p898 int +,@p899 int +,@p900 int +,@p901 int +,@p902 int +,@p903 int +,@p904 int +,@p905 int +,@p906 int +,@p907 int +,@p908 int +,@p909 int +,@p910 int +,@p911 int +,@p912 int +,@p913 int +,@p914 int +,@p915 int +,@p916 int +,@p917 int +,@p918 int +,@p919 int +,@p920 int +,@p921 int +,@p922 int +,@p923 int +,@p924 int +,@p925 int +,@p926 int +,@p927 int +,@p928 int +,@p929 int +,@p930 int +,@p931 int +,@p932 int +,@p933 int +,@p934 int +,@p935 int +,@p936 int +,@p937 int +,@p938 int +,@p939 int +,@p940 int +,@p941 int +,@p942 int +,@p943 int +,@p944 int +,@p945 int +,@p946 int +,@p947 int +,@p948 int +,@p949 int +,@p950 int +,@p951 int +,@p952 int +,@p953 int +,@p954 int +,@p955 int +,@p956 int +,@p957 int +,@p958 int +,@p959 int +,@p960 int +,@p961 int +,@p962 int +,@p963 int +,@p964 int +,@p965 int +,@p966 int +,@p967 int +,@p968 int +,@p969 int +,@p970 int +,@p971 int +,@p972 int +,@p973 int +,@p974 int +,@p975 int +,@p976 int +,@p977 int +,@p978 int +,@p979 int +,@p980 int +,@p981 int +,@p982 int +,@p983 int +,@p984 int +,@p985 int +,@p986 int +,@p987 int +,@p988 int +,@p989 int +,@p990 int +,@p991 int +,@p992 int +,@p993 int +,@p994 int +,@p995 int +,@p996 int +,@p997 int +,@p998 int +,@p999 int +,@p1000 int +,@p1001 int +,@p1002 int +,@p1003 int +,@p1004 int +,@p1005 int +,@p1006 int +,@p1007 int +,@p1008 int +,@p1009 int +,@p1010 int +,@p1011 int +,@p1012 int +,@p1013 int +,@p1014 int +,@p1015 int +,@p1016 int +,@p1017 int +,@p1018 int +,@p1019 int +,@p1020 int +,@p1021 int +,@p1022 int +,@p1023 int +,@p1024 int +,@p1025 int +,@p1026 int +,@p1027 int +,@p1028 int +,@p1029 int +,@p1030 int +,@p1031 int +,@p1032 int +,@p1033 int +,@p1034 int +,@p1035 int +,@p1036 int +,@p1037 int +,@p1038 int +,@p1039 int +,@p1040 int +,@p1041 int +,@p1042 int +,@p1043 int +,@p1044 int +,@p1045 int +,@p1046 int +,@p1047 int +,@p1048 int +,@p1049 int +,@p1050 int +,@p1051 int +,@p1052 int +,@p1053 int +,@p1054 int +,@p1055 int +,@p1056 int +,@p1057 int +,@p1058 int +,@p1059 int +,@p1060 int +,@p1061 int +,@p1062 int +,@p1063 int +,@p1064 int +,@p1065 int +,@p1066 int +,@p1067 int +,@p1068 int +,@p1069 int +,@p1070 int +,@p1071 int +,@p1072 int +,@p1073 int +,@p1074 int +,@p1075 int +,@p1076 int +,@p1077 int +,@p1078 int +,@p1079 int +,@p1080 int +,@p1081 int +,@p1082 int +,@p1083 int +,@p1084 int +,@p1085 int +,@p1086 int +,@p1087 int +,@p1088 int +,@p1089 int +,@p1090 int +,@p1091 int +,@p1092 int +,@p1093 int +,@p1094 int +,@p1095 int +,@p1096 int +,@p1097 int +,@p1098 int +,@p1099 int +,@p1100 int +,@p1101 int +,@p1102 int +,@p1103 int +,@p1104 int +,@p1105 int +,@p1106 int +,@p1107 int +,@p1108 int +,@p1109 int +,@p1110 int +,@p1111 int +,@p1112 int +,@p1113 int +,@p1114 int +,@p1115 int +,@p1116 int +,@p1117 int +,@p1118 int +,@p1119 int +,@p1120 int +,@p1121 int +,@p1122 int +,@p1123 int +,@p1124 int +,@p1125 int +,@p1126 int +,@p1127 int +,@p1128 int +,@p1129 int +,@p1130 int +,@p1131 int +,@p1132 int +,@p1133 int +,@p1134 int +,@p1135 int +,@p1136 int +,@p1137 int +,@p1138 int +,@p1139 int +,@p1140 int +,@p1141 int +,@p1142 int +,@p1143 int +,@p1144 int +,@p1145 int +,@p1146 int +,@p1147 int +,@p1148 int +,@p1149 int +,@p1150 int +,@p1151 int +,@p1152 int +,@p1153 int +,@p1154 int +,@p1155 int +,@p1156 int +,@p1157 int +,@p1158 int +,@p1159 int +,@p1160 int +,@p1161 int +,@p1162 int +,@p1163 int +,@p1164 int +,@p1165 int +,@p1166 int +,@p1167 int +,@p1168 int +,@p1169 int +,@p1170 int +,@p1171 int +,@p1172 int +,@p1173 int +,@p1174 int +,@p1175 int +,@p1176 int +,@p1177 int +,@p1178 int +,@p1179 int +,@p1180 int +,@p1181 int +,@p1182 int +,@p1183 int +,@p1184 int +,@p1185 int +,@p1186 int +,@p1187 int +,@p1188 int +,@p1189 int +,@p1190 int +,@p1191 int +,@p1192 int +,@p1193 int +,@p1194 int +,@p1195 int +,@p1196 int +,@p1197 int +,@p1198 int +,@p1199 int +,@p1200 int +,@p1201 int +,@p1202 int +,@p1203 int +,@p1204 int +,@p1205 int +,@p1206 int +,@p1207 int +,@p1208 int +,@p1209 int +,@p1210 int +,@p1211 int +,@p1212 int +,@p1213 int +,@p1214 int +,@p1215 int +,@p1216 int +,@p1217 int +,@p1218 int +,@p1219 int +,@p1220 int +,@p1221 int +,@p1222 int +,@p1223 int +,@p1224 int +,@p1225 int +,@p1226 int +,@p1227 int +,@p1228 int +,@p1229 int +,@p1230 int +,@p1231 int +,@p1232 int +,@p1233 int +,@p1234 int +,@p1235 int +,@p1236 int +,@p1237 int +,@p1238 int +,@p1239 int +,@p1240 int +,@p1241 int +,@p1242 int +,@p1243 int +,@p1244 int +,@p1245 int +,@p1246 int +,@p1247 int +,@p1248 int +,@p1249 int +,@p1250 int +,@p1251 int +,@p1252 int +,@p1253 int +,@p1254 int +,@p1255 int +,@p1256 int +,@p1257 int +,@p1258 int +,@p1259 int +,@p1260 int +,@p1261 int +,@p1262 int +,@p1263 int +,@p1264 int +,@p1265 int +,@p1266 int +,@p1267 int +,@p1268 int +,@p1269 int +,@p1270 int +,@p1271 int +,@p1272 int +,@p1273 int +,@p1274 int +,@p1275 int +,@p1276 int +,@p1277 int +,@p1278 int +,@p1279 int +,@p1280 int +,@p1281 int +,@p1282 int +,@p1283 int +,@p1284 int +,@p1285 int +,@p1286 int +,@p1287 int +,@p1288 int +,@p1289 int +,@p1290 int +,@p1291 int +,@p1292 int +,@p1293 int +,@p1294 int +,@p1295 int +,@p1296 int +,@p1297 int +,@p1298 int +,@p1299 int +,@p1300 int +,@p1301 int +,@p1302 int +,@p1303 int +,@p1304 int +,@p1305 int +,@p1306 int +,@p1307 int +,@p1308 int +,@p1309 int +,@p1310 int +,@p1311 int +,@p1312 int +,@p1313 int +,@p1314 int +,@p1315 int +,@p1316 int +,@p1317 int +,@p1318 int +,@p1319 int +,@p1320 int +,@p1321 int +,@p1322 int +,@p1323 int +,@p1324 int +,@p1325 int +,@p1326 int +,@p1327 int +,@p1328 int +,@p1329 int +,@p1330 int +,@p1331 int +,@p1332 int +,@p1333 int +,@p1334 int +,@p1335 int +,@p1336 int +,@p1337 int +,@p1338 int +,@p1339 int +,@p1340 int +,@p1341 int +,@p1342 int +,@p1343 int +,@p1344 int +,@p1345 int +,@p1346 int +,@p1347 int +,@p1348 int +,@p1349 int +,@p1350 int +,@p1351 int +,@p1352 int +,@p1353 int +,@p1354 int +,@p1355 int +,@p1356 int +,@p1357 int +,@p1358 int +,@p1359 int +,@p1360 int +,@p1361 int +,@p1362 int +,@p1363 int +,@p1364 int +,@p1365 int +,@p1366 int +,@p1367 int +,@p1368 int +,@p1369 int +,@p1370 int +,@p1371 int +,@p1372 int +,@p1373 int +,@p1374 int +,@p1375 int +,@p1376 int +,@p1377 int +,@p1378 int +,@p1379 int +,@p1380 int +,@p1381 int +,@p1382 int +,@p1383 int +,@p1384 int +,@p1385 int +,@p1386 int +,@p1387 int +,@p1388 int +,@p1389 int +,@p1390 int +,@p1391 int +,@p1392 int +,@p1393 int +,@p1394 int +,@p1395 int +,@p1396 int +,@p1397 int +,@p1398 int +,@p1399 int +,@p1400 int +,@p1401 int +,@p1402 int +,@p1403 int +,@p1404 int +,@p1405 int +,@p1406 int +,@p1407 int +,@p1408 int +,@p1409 int +,@p1410 int +,@p1411 int +,@p1412 int +,@p1413 int +,@p1414 int +,@p1415 int +,@p1416 int +,@p1417 int +,@p1418 int +,@p1419 int +,@p1420 int +,@p1421 int +,@p1422 int +,@p1423 int +,@p1424 int +,@p1425 int +,@p1426 int +,@p1427 int +,@p1428 int +,@p1429 int +,@p1430 int +,@p1431 int +,@p1432 int +,@p1433 int +,@p1434 int +,@p1435 int +,@p1436 int +,@p1437 int +,@p1438 int +,@p1439 int +,@p1440 int +,@p1441 int +,@p1442 int +,@p1443 int +,@p1444 int +,@p1445 int +,@p1446 int +,@p1447 int +,@p1448 int +,@p1449 int +,@p1450 int +,@p1451 int +,@p1452 int +,@p1453 int +,@p1454 int +,@p1455 int +,@p1456 int +,@p1457 int +,@p1458 int +,@p1459 int +,@p1460 int +,@p1461 int +,@p1462 int +,@p1463 int +,@p1464 int +,@p1465 int +,@p1466 int +,@p1467 int +,@p1468 int +,@p1469 int +,@p1470 int +,@p1471 int +,@p1472 int +,@p1473 int +,@p1474 int +,@p1475 int +,@p1476 int +,@p1477 int +,@p1478 int +,@p1479 int +,@p1480 int +,@p1481 int +,@p1482 int +,@p1483 int +,@p1484 int +,@p1485 int +,@p1486 int +,@p1487 int +,@p1488 int +,@p1489 int +,@p1490 int +,@p1491 int +,@p1492 int +,@p1493 int +,@p1494 int +,@p1495 int +,@p1496 int +,@p1497 int +,@p1498 int +,@p1499 int +,@p1500 int +,@p1501 int +,@p1502 int +,@p1503 int +,@p1504 int +,@p1505 int +,@p1506 int +,@p1507 int +,@p1508 int +,@p1509 int +,@p1510 int +,@p1511 int +,@p1512 int +,@p1513 int +,@p1514 int +,@p1515 int +,@p1516 int +,@p1517 int +,@p1518 int +,@p1519 int +,@p1520 int +,@p1521 int +,@p1522 int +,@p1523 int +,@p1524 int +,@p1525 int +,@p1526 int +,@p1527 int +,@p1528 int +,@p1529 int +,@p1530 int +,@p1531 int +,@p1532 int +,@p1533 int +,@p1534 int +,@p1535 int +,@p1536 int +,@p1537 int +,@p1538 int +,@p1539 int +,@p1540 int +,@p1541 int +,@p1542 int +,@p1543 int +,@p1544 int +,@p1545 int +,@p1546 int +,@p1547 int +,@p1548 int +,@p1549 int +,@p1550 int +,@p1551 int +,@p1552 int +,@p1553 int +,@p1554 int +,@p1555 int +,@p1556 int +,@p1557 int +,@p1558 int +,@p1559 int +,@p1560 int +,@p1561 int +,@p1562 int +,@p1563 int +,@p1564 int +,@p1565 int +,@p1566 int +,@p1567 int +,@p1568 int +,@p1569 int +,@p1570 int +,@p1571 int +,@p1572 int +,@p1573 int +,@p1574 int +,@p1575 int +,@p1576 int +,@p1577 int +,@p1578 int +,@p1579 int +,@p1580 int +,@p1581 int +,@p1582 int +,@p1583 int +,@p1584 int +,@p1585 int +,@p1586 int +,@p1587 int +,@p1588 int +,@p1589 int +,@p1590 int +,@p1591 int +,@p1592 int +,@p1593 int +,@p1594 int +,@p1595 int +,@p1596 int +,@p1597 int +,@p1598 int +,@p1599 int +,@p1600 int +,@p1601 int +,@p1602 int +,@p1603 int +,@p1604 int +,@p1605 int +,@p1606 int +,@p1607 int +,@p1608 int +,@p1609 int +,@p1610 int +,@p1611 int +,@p1612 int +,@p1613 int +,@p1614 int +,@p1615 int +,@p1616 int +,@p1617 int +,@p1618 int +,@p1619 int +,@p1620 int +,@p1621 int +,@p1622 int +,@p1623 int +,@p1624 int +,@p1625 int +,@p1626 int +,@p1627 int +,@p1628 int +,@p1629 int +,@p1630 int +,@p1631 int +,@p1632 int +,@p1633 int +,@p1634 int +,@p1635 int +,@p1636 int +,@p1637 int +,@p1638 int +,@p1639 int +,@p1640 int +,@p1641 int +,@p1642 int +,@p1643 int +,@p1644 int +,@p1645 int +,@p1646 int +,@p1647 int +,@p1648 int +,@p1649 int +,@p1650 int +,@p1651 int +,@p1652 int +,@p1653 int +,@p1654 int +,@p1655 int +,@p1656 int +,@p1657 int +,@p1658 int +,@p1659 int +,@p1660 int +,@p1661 int +,@p1662 int +,@p1663 int +,@p1664 int +,@p1665 int +,@p1666 int +,@p1667 int +,@p1668 int +,@p1669 int +,@p1670 int +,@p1671 int +,@p1672 int +,@p1673 int +,@p1674 int +,@p1675 int +,@p1676 int +,@p1677 int +,@p1678 int +,@p1679 int +,@p1680 int +,@p1681 int +,@p1682 int +,@p1683 int +,@p1684 int +,@p1685 int +,@p1686 int +,@p1687 int +,@p1688 int +,@p1689 int +,@p1690 int +,@p1691 int +,@p1692 int +,@p1693 int +,@p1694 int +,@p1695 int +,@p1696 int +,@p1697 int +,@p1698 int +,@p1699 int +,@p1700 int +,@p1701 int +,@p1702 int +,@p1703 int +,@p1704 int +,@p1705 int +,@p1706 int +,@p1707 int +,@p1708 int +,@p1709 int +,@p1710 int +,@p1711 int +,@p1712 int +,@p1713 int +,@p1714 int +,@p1715 int +,@p1716 int +,@p1717 int +,@p1718 int +,@p1719 int +,@p1720 int +,@p1721 int +,@p1722 int +,@p1723 int +,@p1724 int +,@p1725 int +,@p1726 int +,@p1727 int +,@p1728 int +,@p1729 int +,@p1730 int +,@p1731 int +,@p1732 int +,@p1733 int +,@p1734 int +,@p1735 int +,@p1736 int +,@p1737 int +,@p1738 int +,@p1739 int +,@p1740 int +,@p1741 int +,@p1742 int +,@p1743 int +,@p1744 int +,@p1745 int +,@p1746 int +,@p1747 int +,@p1748 int +,@p1749 int +,@p1750 int +,@p1751 int +,@p1752 int +,@p1753 int +,@p1754 int +,@p1755 int +,@p1756 int +,@p1757 int +,@p1758 int +,@p1759 int +,@p1760 int +,@p1761 int +,@p1762 int +,@p1763 int +,@p1764 int +,@p1765 int +,@p1766 int +,@p1767 int +,@p1768 int +,@p1769 int +,@p1770 int +,@p1771 int +,@p1772 int +,@p1773 int +,@p1774 int +,@p1775 int +,@p1776 int +,@p1777 int +,@p1778 int +,@p1779 int +,@p1780 int +,@p1781 int +,@p1782 int +,@p1783 int +,@p1784 int +,@p1785 int +,@p1786 int +,@p1787 int +,@p1788 int +,@p1789 int +,@p1790 int +,@p1791 int +,@p1792 int +,@p1793 int +,@p1794 int +,@p1795 int +,@p1796 int +,@p1797 int +,@p1798 int +,@p1799 int +,@p1800 int +,@p1801 int +,@p1802 int +,@p1803 int +,@p1804 int +,@p1805 int +,@p1806 int +,@p1807 int +,@p1808 int +,@p1809 int +,@p1810 int +,@p1811 int +,@p1812 int +,@p1813 int +,@p1814 int +,@p1815 int +,@p1816 int +,@p1817 int +,@p1818 int +,@p1819 int +,@p1820 int +,@p1821 int +,@p1822 int +,@p1823 int +,@p1824 int +,@p1825 int +,@p1826 int +,@p1827 int +,@p1828 int +,@p1829 int +,@p1830 int +,@p1831 int +,@p1832 int +,@p1833 int +,@p1834 int +,@p1835 int +,@p1836 int +,@p1837 int +,@p1838 int +,@p1839 int +,@p1840 int +,@p1841 int +,@p1842 int +,@p1843 int +,@p1844 int +,@p1845 int +,@p1846 int +,@p1847 int +,@p1848 int +,@p1849 int +,@p1850 int +,@p1851 int +,@p1852 int +,@p1853 int +,@p1854 int +,@p1855 int +,@p1856 int +,@p1857 int +,@p1858 int +,@p1859 int +,@p1860 int +,@p1861 int +,@p1862 int +,@p1863 int +,@p1864 int +,@p1865 int +,@p1866 int +,@p1867 int +,@p1868 int +,@p1869 int +,@p1870 int +,@p1871 int +,@p1872 int +,@p1873 int +,@p1874 int +,@p1875 int +,@p1876 int +,@p1877 int +,@p1878 int +,@p1879 int +,@p1880 int +,@p1881 int +,@p1882 int +,@p1883 int +,@p1884 int +,@p1885 int +,@p1886 int +,@p1887 int +,@p1888 int +,@p1889 int +,@p1890 int +,@p1891 int +,@p1892 int +,@p1893 int +,@p1894 int +,@p1895 int +,@p1896 int +,@p1897 int +,@p1898 int +,@p1899 int +,@p1900 int +,@p1901 int +,@p1902 int +,@p1903 int +,@p1904 int +,@p1905 int +,@p1906 int +,@p1907 int +,@p1908 int +,@p1909 int +,@p1910 int +,@p1911 int +,@p1912 int +,@p1913 int +,@p1914 int +,@p1915 int +,@p1916 int +,@p1917 int +,@p1918 int +,@p1919 int +,@p1920 int +,@p1921 int +,@p1922 int +,@p1923 int +,@p1924 int +,@p1925 int +,@p1926 int +,@p1927 int +,@p1928 int +,@p1929 int +,@p1930 int +,@p1931 int +,@p1932 int +,@p1933 int +,@p1934 int +,@p1935 int +,@p1936 int +,@p1937 int +,@p1938 int +,@p1939 int +,@p1940 int +,@p1941 int +,@p1942 int +,@p1943 int +,@p1944 int +,@p1945 int +,@p1946 int +,@p1947 int +,@p1948 int +,@p1949 int +,@p1950 int +,@p1951 int +,@p1952 int +,@p1953 int +,@p1954 int +,@p1955 int +,@p1956 int +,@p1957 int +,@p1958 int +,@p1959 int +,@p1960 int +,@p1961 int +,@p1962 int +,@p1963 int +,@p1964 int +,@p1965 int +,@p1966 int +,@p1967 int +,@p1968 int +,@p1969 int +,@p1970 int +,@p1971 int +,@p1972 int +,@p1973 int +,@p1974 int +,@p1975 int +,@p1976 int +,@p1977 int +,@p1978 int +,@p1979 int +,@p1980 int +,@p1981 int +,@p1982 int +,@p1983 int +,@p1984 int +,@p1985 int +,@p1986 int +,@p1987 int +,@p1988 int +,@p1989 int +,@p1990 int +,@p1991 int +,@p1992 int +,@p1993 int +,@p1994 int +,@p1995 int +,@p1996 int +,@p1997 int +,@p1998 int +,@p1999 int +,@p2000 int +,@p2001 int +,@p2002 int +,@p2003 int +,@p2004 int +,@p2005 int +,@p2006 int +,@p2007 int +,@p2008 int +,@p2009 int +,@p2010 int +,@p2011 int +,@p2012 int +,@p2013 int +,@p2014 int +,@p2015 int +,@p2016 int +,@p2017 int +,@p2018 int +,@p2019 int +,@p2020 int +,@p2021 int +,@p2022 int +,@p2023 int +,@p2024 int +,@p2025 int +,@p2026 int +,@p2027 int +,@p2028 int +,@p2029 int +,@p2030 int +,@p2031 int +,@p2032 int +,@p2033 int +,@p2034 int +,@p2035 int +,@p2036 int +,@p2037 int +,@p2038 int +,@p2039 int +,@p2040 int +,@p2041 int +,@p2042 int +,@p2043 int +,@p2044 int +,@p2045 int +,@p2046 int +,@p2047 int +,@p2048 int +,@p2049 int +,@p2050 int +,@p2051 int +,@p2052 int +,@p2053 int +,@p2054 int +,@p2055 int +,@p2056 int +,@p2057 int +,@p2058 int +,@p2059 int +,@p2060 int +,@p2061 int +,@p2062 int +,@p2063 int +,@p2064 int +,@p2065 int +,@p2066 int +,@p2067 int +,@p2068 int +,@p2069 int +,@p2070 int +,@p2071 int +,@p2072 int +,@p2073 int +,@p2074 int +,@p2075 int +,@p2076 int +,@p2077 int +,@p2078 int +,@p2079 int +,@p2080 int +,@p2081 int +,@p2082 int +,@p2083 int +,@p2084 int +,@p2085 int +,@p2086 int +,@p2087 int +,@p2088 int +,@p2089 int +,@p2090 int +,@p2091 int +,@p2092 int +,@p2093 int +,@p2094 int +,@p2095 int +,@p2096 int +,@p2097 int +,@p2098 int +,@p2099 int +,@p2100 int +,@p2101 int +) +AS +BEGIN + RETURN 100 +END + +GO + +GO + +SET XACT_ABORT ON; +GO + +begin transaction +GO + +GO +CREATE PROC p180( + @p1 int +,@p2 int +,@p3 int +,@p4 int +,@p5 int +,@p6 int +,@p7 int +,@p8 int +,@p9 int +,@p10 int +,@p11 int +,@p12 int +,@p13 int +,@p14 int +,@p15 int +,@p16 int +,@p17 int +,@p18 int +,@p19 int +,@p20 int +,@p21 int +,@p22 int +,@p23 int +,@p24 int +,@p25 int +,@p26 int +,@p27 int +,@p28 int +,@p29 int +,@p30 int +,@p31 int +,@p32 int +,@p33 int +,@p34 int +,@p35 int +,@p36 int +,@p37 int +,@p38 int +,@p39 int +,@p40 int +,@p41 int +,@p42 int +,@p43 int +,@p44 int +,@p45 int +,@p46 int +,@p47 int +,@p48 int +,@p49 int +,@p50 int +,@p51 int +,@p52 int +,@p53 int +,@p54 int +,@p55 int +,@p56 int +,@p57 int +,@p58 int +,@p59 int +,@p60 int +,@p61 int +,@p62 int +,@p63 int +,@p64 int +,@p65 int +,@p66 int +,@p67 int +,@p68 int +,@p69 int +,@p70 int +,@p71 int +,@p72 int +,@p73 int +,@p74 int +,@p75 int +,@p76 int +,@p77 int +,@p78 int +,@p79 int +,@p80 int +,@p81 int +,@p82 int +,@p83 int +,@p84 int +,@p85 int +,@p86 int +,@p87 int +,@p88 int +,@p89 int +,@p90 int +,@p91 int +,@p92 int +,@p93 int +,@p94 int +,@p95 int +,@p96 int +,@p97 int +,@p98 int +,@p99 int +,@p100 int +,@p101 int +,@p102 int +,@p103 int +,@p104 int +,@p105 int +,@p106 int +,@p107 int +,@p108 int +,@p109 int +,@p110 int +,@p111 int +,@p112 int +,@p113 int +,@p114 int +,@p115 int +,@p116 int +,@p117 int +,@p118 int +,@p119 int +,@p120 int +,@p121 int +,@p122 int +,@p123 int +,@p124 int +,@p125 int +,@p126 int +,@p127 int +,@p128 int +,@p129 int +,@p130 int +,@p131 int +,@p132 int +,@p133 int +,@p134 int +,@p135 int +,@p136 int +,@p137 int +,@p138 int +,@p139 int +,@p140 int +,@p141 int +,@p142 int +,@p143 int +,@p144 int +,@p145 int +,@p146 int +,@p147 int +,@p148 int +,@p149 int +,@p150 int +,@p151 int +,@p152 int +,@p153 int +,@p154 int +,@p155 int +,@p156 int +,@p157 int +,@p158 int +,@p159 int +,@p160 int +,@p161 int +,@p162 int +,@p163 int +,@p164 int +,@p165 int +,@p166 int +,@p167 int +,@p168 int +,@p169 int +,@p170 int +,@p171 int +,@p172 int +,@p173 int +,@p174 int +,@p175 int +,@p176 int +,@p177 int +,@p178 int +,@p179 int +,@p180 int +,@p181 int +,@p182 int +,@p183 int +,@p184 int +,@p185 int +,@p186 int +,@p187 int +,@p188 int +,@p189 int +,@p190 int +,@p191 int +,@p192 int +,@p193 int +,@p194 int +,@p195 int +,@p196 int +,@p197 int +,@p198 int +,@p199 int +,@p200 int +,@p201 int +,@p202 int +,@p203 int +,@p204 int +,@p205 int +,@p206 int +,@p207 int +,@p208 int +,@p209 int +,@p210 int +,@p211 int +,@p212 int +,@p213 int +,@p214 int +,@p215 int +,@p216 int +,@p217 int +,@p218 int +,@p219 int +,@p220 int +,@p221 int +,@p222 int +,@p223 int +,@p224 int +,@p225 int +,@p226 int +,@p227 int +,@p228 int +,@p229 int +,@p230 int +,@p231 int +,@p232 int +,@p233 int +,@p234 int +,@p235 int +,@p236 int +,@p237 int +,@p238 int +,@p239 int +,@p240 int +,@p241 int +,@p242 int +,@p243 int +,@p244 int +,@p245 int +,@p246 int +,@p247 int +,@p248 int +,@p249 int +,@p250 int +,@p251 int +,@p252 int +,@p253 int +,@p254 int +,@p255 int +,@p256 int +,@p257 int +,@p258 int +,@p259 int +,@p260 int +,@p261 int +,@p262 int +,@p263 int +,@p264 int +,@p265 int +,@p266 int +,@p267 int +,@p268 int +,@p269 int +,@p270 int +,@p271 int +,@p272 int +,@p273 int +,@p274 int +,@p275 int +,@p276 int +,@p277 int +,@p278 int +,@p279 int +,@p280 int +,@p281 int +,@p282 int +,@p283 int +,@p284 int +,@p285 int +,@p286 int +,@p287 int +,@p288 int +,@p289 int +,@p290 int +,@p291 int +,@p292 int +,@p293 int +,@p294 int +,@p295 int +,@p296 int +,@p297 int +,@p298 int +,@p299 int +,@p300 int +,@p301 int +,@p302 int +,@p303 int +,@p304 int +,@p305 int +,@p306 int +,@p307 int +,@p308 int +,@p309 int +,@p310 int +,@p311 int +,@p312 int +,@p313 int +,@p314 int +,@p315 int +,@p316 int +,@p317 int +,@p318 int +,@p319 int +,@p320 int +,@p321 int +,@p322 int +,@p323 int +,@p324 int +,@p325 int +,@p326 int +,@p327 int +,@p328 int +,@p329 int +,@p330 int +,@p331 int +,@p332 int +,@p333 int +,@p334 int +,@p335 int +,@p336 int +,@p337 int +,@p338 int +,@p339 int +,@p340 int +,@p341 int +,@p342 int +,@p343 int +,@p344 int +,@p345 int +,@p346 int +,@p347 int +,@p348 int +,@p349 int +,@p350 int +,@p351 int +,@p352 int +,@p353 int +,@p354 int +,@p355 int +,@p356 int +,@p357 int +,@p358 int +,@p359 int +,@p360 int +,@p361 int +,@p362 int +,@p363 int +,@p364 int +,@p365 int +,@p366 int +,@p367 int +,@p368 int +,@p369 int +,@p370 int +,@p371 int +,@p372 int +,@p373 int +,@p374 int +,@p375 int +,@p376 int +,@p377 int +,@p378 int +,@p379 int +,@p380 int +,@p381 int +,@p382 int +,@p383 int +,@p384 int +,@p385 int +,@p386 int +,@p387 int +,@p388 int +,@p389 int +,@p390 int +,@p391 int +,@p392 int +,@p393 int +,@p394 int +,@p395 int +,@p396 int +,@p397 int +,@p398 int +,@p399 int +,@p400 int +,@p401 int +,@p402 int +,@p403 int +,@p404 int +,@p405 int +,@p406 int +,@p407 int +,@p408 int +,@p409 int +,@p410 int +,@p411 int +,@p412 int +,@p413 int +,@p414 int +,@p415 int +,@p416 int +,@p417 int +,@p418 int +,@p419 int +,@p420 int +,@p421 int +,@p422 int +,@p423 int +,@p424 int +,@p425 int +,@p426 int +,@p427 int +,@p428 int +,@p429 int +,@p430 int +,@p431 int +,@p432 int +,@p433 int +,@p434 int +,@p435 int +,@p436 int +,@p437 int +,@p438 int +,@p439 int +,@p440 int +,@p441 int +,@p442 int +,@p443 int +,@p444 int +,@p445 int +,@p446 int +,@p447 int +,@p448 int +,@p449 int +,@p450 int +,@p451 int +,@p452 int +,@p453 int +,@p454 int +,@p455 int +,@p456 int +,@p457 int +,@p458 int +,@p459 int +,@p460 int +,@p461 int +,@p462 int +,@p463 int +,@p464 int +,@p465 int +,@p466 int +,@p467 int +,@p468 int +,@p469 int +,@p470 int +,@p471 int +,@p472 int +,@p473 int +,@p474 int +,@p475 int +,@p476 int +,@p477 int +,@p478 int +,@p479 int +,@p480 int +,@p481 int +,@p482 int +,@p483 int +,@p484 int +,@p485 int +,@p486 int +,@p487 int +,@p488 int +,@p489 int +,@p490 int +,@p491 int +,@p492 int +,@p493 int +,@p494 int +,@p495 int +,@p496 int +,@p497 int +,@p498 int +,@p499 int +,@p500 int +,@p501 int +,@p502 int +,@p503 int +,@p504 int +,@p505 int +,@p506 int +,@p507 int +,@p508 int +,@p509 int +,@p510 int +,@p511 int +,@p512 int +,@p513 int +,@p514 int +,@p515 int +,@p516 int +,@p517 int +,@p518 int +,@p519 int +,@p520 int +,@p521 int +,@p522 int +,@p523 int +,@p524 int +,@p525 int +,@p526 int +,@p527 int +,@p528 int +,@p529 int +,@p530 int +,@p531 int +,@p532 int +,@p533 int +,@p534 int +,@p535 int +,@p536 int +,@p537 int +,@p538 int +,@p539 int +,@p540 int +,@p541 int +,@p542 int +,@p543 int +,@p544 int +,@p545 int +,@p546 int +,@p547 int +,@p548 int +,@p549 int +,@p550 int +,@p551 int +,@p552 int +,@p553 int +,@p554 int +,@p555 int +,@p556 int +,@p557 int +,@p558 int +,@p559 int +,@p560 int +,@p561 int +,@p562 int +,@p563 int +,@p564 int +,@p565 int +,@p566 int +,@p567 int +,@p568 int +,@p569 int +,@p570 int +,@p571 int +,@p572 int +,@p573 int +,@p574 int +,@p575 int +,@p576 int +,@p577 int +,@p578 int +,@p579 int +,@p580 int +,@p581 int +,@p582 int +,@p583 int +,@p584 int +,@p585 int +,@p586 int +,@p587 int +,@p588 int +,@p589 int +,@p590 int +,@p591 int +,@p592 int +,@p593 int +,@p594 int +,@p595 int +,@p596 int +,@p597 int +,@p598 int +,@p599 int +,@p600 int +,@p601 int +,@p602 int +,@p603 int +,@p604 int +,@p605 int +,@p606 int +,@p607 int +,@p608 int +,@p609 int +,@p610 int +,@p611 int +,@p612 int +,@p613 int +,@p614 int +,@p615 int +,@p616 int +,@p617 int +,@p618 int +,@p619 int +,@p620 int +,@p621 int +,@p622 int +,@p623 int +,@p624 int +,@p625 int +,@p626 int +,@p627 int +,@p628 int +,@p629 int +,@p630 int +,@p631 int +,@p632 int +,@p633 int +,@p634 int +,@p635 int +,@p636 int +,@p637 int +,@p638 int +,@p639 int +,@p640 int +,@p641 int +,@p642 int +,@p643 int +,@p644 int +,@p645 int +,@p646 int +,@p647 int +,@p648 int +,@p649 int +,@p650 int +,@p651 int +,@p652 int +,@p653 int +,@p654 int +,@p655 int +,@p656 int +,@p657 int +,@p658 int +,@p659 int +,@p660 int +,@p661 int +,@p662 int +,@p663 int +,@p664 int +,@p665 int +,@p666 int +,@p667 int +,@p668 int +,@p669 int +,@p670 int +,@p671 int +,@p672 int +,@p673 int +,@p674 int +,@p675 int +,@p676 int +,@p677 int +,@p678 int +,@p679 int +,@p680 int +,@p681 int +,@p682 int +,@p683 int +,@p684 int +,@p685 int +,@p686 int +,@p687 int +,@p688 int +,@p689 int +,@p690 int +,@p691 int +,@p692 int +,@p693 int +,@p694 int +,@p695 int +,@p696 int +,@p697 int +,@p698 int +,@p699 int +,@p700 int +,@p701 int +,@p702 int +,@p703 int +,@p704 int +,@p705 int +,@p706 int +,@p707 int +,@p708 int +,@p709 int +,@p710 int +,@p711 int +,@p712 int +,@p713 int +,@p714 int +,@p715 int +,@p716 int +,@p717 int +,@p718 int +,@p719 int +,@p720 int +,@p721 int +,@p722 int +,@p723 int +,@p724 int +,@p725 int +,@p726 int +,@p727 int +,@p728 int +,@p729 int +,@p730 int +,@p731 int +,@p732 int +,@p733 int +,@p734 int +,@p735 int +,@p736 int +,@p737 int +,@p738 int +,@p739 int +,@p740 int +,@p741 int +,@p742 int +,@p743 int +,@p744 int +,@p745 int +,@p746 int +,@p747 int +,@p748 int +,@p749 int +,@p750 int +,@p751 int +,@p752 int +,@p753 int +,@p754 int +,@p755 int +,@p756 int +,@p757 int +,@p758 int +,@p759 int +,@p760 int +,@p761 int +,@p762 int +,@p763 int +,@p764 int +,@p765 int +,@p766 int +,@p767 int +,@p768 int +,@p769 int +,@p770 int +,@p771 int +,@p772 int +,@p773 int +,@p774 int +,@p775 int +,@p776 int +,@p777 int +,@p778 int +,@p779 int +,@p780 int +,@p781 int +,@p782 int +,@p783 int +,@p784 int +,@p785 int +,@p786 int +,@p787 int +,@p788 int +,@p789 int +,@p790 int +,@p791 int +,@p792 int +,@p793 int +,@p794 int +,@p795 int +,@p796 int +,@p797 int +,@p798 int +,@p799 int +,@p800 int +,@p801 int +,@p802 int +,@p803 int +,@p804 int +,@p805 int +,@p806 int +,@p807 int +,@p808 int +,@p809 int +,@p810 int +,@p811 int +,@p812 int +,@p813 int +,@p814 int +,@p815 int +,@p816 int +,@p817 int +,@p818 int +,@p819 int +,@p820 int +,@p821 int +,@p822 int +,@p823 int +,@p824 int +,@p825 int +,@p826 int +,@p827 int +,@p828 int +,@p829 int +,@p830 int +,@p831 int +,@p832 int +,@p833 int +,@p834 int +,@p835 int +,@p836 int +,@p837 int +,@p838 int +,@p839 int +,@p840 int +,@p841 int +,@p842 int +,@p843 int +,@p844 int +,@p845 int +,@p846 int +,@p847 int +,@p848 int +,@p849 int +,@p850 int +,@p851 int +,@p852 int +,@p853 int +,@p854 int +,@p855 int +,@p856 int +,@p857 int +,@p858 int +,@p859 int +,@p860 int +,@p861 int +,@p862 int +,@p863 int +,@p864 int +,@p865 int +,@p866 int +,@p867 int +,@p868 int +,@p869 int +,@p870 int +,@p871 int +,@p872 int +,@p873 int +,@p874 int +,@p875 int +,@p876 int +,@p877 int +,@p878 int +,@p879 int +,@p880 int +,@p881 int +,@p882 int +,@p883 int +,@p884 int +,@p885 int +,@p886 int +,@p887 int +,@p888 int +,@p889 int +,@p890 int +,@p891 int +,@p892 int +,@p893 int +,@p894 int +,@p895 int +,@p896 int +,@p897 int +,@p898 int +,@p899 int +,@p900 int +,@p901 int +,@p902 int +,@p903 int +,@p904 int +,@p905 int +,@p906 int +,@p907 int +,@p908 int +,@p909 int +,@p910 int +,@p911 int +,@p912 int +,@p913 int +,@p914 int +,@p915 int +,@p916 int +,@p917 int +,@p918 int +,@p919 int +,@p920 int +,@p921 int +,@p922 int +,@p923 int +,@p924 int +,@p925 int +,@p926 int +,@p927 int +,@p928 int +,@p929 int +,@p930 int +,@p931 int +,@p932 int +,@p933 int +,@p934 int +,@p935 int +,@p936 int +,@p937 int +,@p938 int +,@p939 int +,@p940 int +,@p941 int +,@p942 int +,@p943 int +,@p944 int +,@p945 int +,@p946 int +,@p947 int +,@p948 int +,@p949 int +,@p950 int +,@p951 int +,@p952 int +,@p953 int +,@p954 int +,@p955 int +,@p956 int +,@p957 int +,@p958 int +,@p959 int +,@p960 int +,@p961 int +,@p962 int +,@p963 int +,@p964 int +,@p965 int +,@p966 int +,@p967 int +,@p968 int +,@p969 int +,@p970 int +,@p971 int +,@p972 int +,@p973 int +,@p974 int +,@p975 int +,@p976 int +,@p977 int +,@p978 int +,@p979 int +,@p980 int +,@p981 int +,@p982 int +,@p983 int +,@p984 int +,@p985 int +,@p986 int +,@p987 int +,@p988 int +,@p989 int +,@p990 int +,@p991 int +,@p992 int +,@p993 int +,@p994 int +,@p995 int +,@p996 int +,@p997 int +,@p998 int +,@p999 int +,@p1000 int +,@p1001 int +,@p1002 int +,@p1003 int +,@p1004 int +,@p1005 int +,@p1006 int +,@p1007 int +,@p1008 int +,@p1009 int +,@p1010 int +,@p1011 int +,@p1012 int +,@p1013 int +,@p1014 int +,@p1015 int +,@p1016 int +,@p1017 int +,@p1018 int +,@p1019 int +,@p1020 int +,@p1021 int +,@p1022 int +,@p1023 int +,@p1024 int +,@p1025 int +,@p1026 int +,@p1027 int +,@p1028 int +,@p1029 int +,@p1030 int +,@p1031 int +,@p1032 int +,@p1033 int +,@p1034 int +,@p1035 int +,@p1036 int +,@p1037 int +,@p1038 int +,@p1039 int +,@p1040 int +,@p1041 int +,@p1042 int +,@p1043 int +,@p1044 int +,@p1045 int +,@p1046 int +,@p1047 int +,@p1048 int +,@p1049 int +,@p1050 int +,@p1051 int +,@p1052 int +,@p1053 int +,@p1054 int +,@p1055 int +,@p1056 int +,@p1057 int +,@p1058 int +,@p1059 int +,@p1060 int +,@p1061 int +,@p1062 int +,@p1063 int +,@p1064 int +,@p1065 int +,@p1066 int +,@p1067 int +,@p1068 int +,@p1069 int +,@p1070 int +,@p1071 int +,@p1072 int +,@p1073 int +,@p1074 int +,@p1075 int +,@p1076 int +,@p1077 int +,@p1078 int +,@p1079 int +,@p1080 int +,@p1081 int +,@p1082 int +,@p1083 int +,@p1084 int +,@p1085 int +,@p1086 int +,@p1087 int +,@p1088 int +,@p1089 int +,@p1090 int +,@p1091 int +,@p1092 int +,@p1093 int +,@p1094 int +,@p1095 int +,@p1096 int +,@p1097 int +,@p1098 int +,@p1099 int +,@p1100 int +,@p1101 int +,@p1102 int +,@p1103 int +,@p1104 int +,@p1105 int +,@p1106 int +,@p1107 int +,@p1108 int +,@p1109 int +,@p1110 int +,@p1111 int +,@p1112 int +,@p1113 int +,@p1114 int +,@p1115 int +,@p1116 int +,@p1117 int +,@p1118 int +,@p1119 int +,@p1120 int +,@p1121 int +,@p1122 int +,@p1123 int +,@p1124 int +,@p1125 int +,@p1126 int +,@p1127 int +,@p1128 int +,@p1129 int +,@p1130 int +,@p1131 int +,@p1132 int +,@p1133 int +,@p1134 int +,@p1135 int +,@p1136 int +,@p1137 int +,@p1138 int +,@p1139 int +,@p1140 int +,@p1141 int +,@p1142 int +,@p1143 int +,@p1144 int +,@p1145 int +,@p1146 int +,@p1147 int +,@p1148 int +,@p1149 int +,@p1150 int +,@p1151 int +,@p1152 int +,@p1153 int +,@p1154 int +,@p1155 int +,@p1156 int +,@p1157 int +,@p1158 int +,@p1159 int +,@p1160 int +,@p1161 int +,@p1162 int +,@p1163 int +,@p1164 int +,@p1165 int +,@p1166 int +,@p1167 int +,@p1168 int +,@p1169 int +,@p1170 int +,@p1171 int +,@p1172 int +,@p1173 int +,@p1174 int +,@p1175 int +,@p1176 int +,@p1177 int +,@p1178 int +,@p1179 int +,@p1180 int +,@p1181 int +,@p1182 int +,@p1183 int +,@p1184 int +,@p1185 int +,@p1186 int +,@p1187 int +,@p1188 int +,@p1189 int +,@p1190 int +,@p1191 int +,@p1192 int +,@p1193 int +,@p1194 int +,@p1195 int +,@p1196 int +,@p1197 int +,@p1198 int +,@p1199 int +,@p1200 int +,@p1201 int +,@p1202 int +,@p1203 int +,@p1204 int +,@p1205 int +,@p1206 int +,@p1207 int +,@p1208 int +,@p1209 int +,@p1210 int +,@p1211 int +,@p1212 int +,@p1213 int +,@p1214 int +,@p1215 int +,@p1216 int +,@p1217 int +,@p1218 int +,@p1219 int +,@p1220 int +,@p1221 int +,@p1222 int +,@p1223 int +,@p1224 int +,@p1225 int +,@p1226 int +,@p1227 int +,@p1228 int +,@p1229 int +,@p1230 int +,@p1231 int +,@p1232 int +,@p1233 int +,@p1234 int +,@p1235 int +,@p1236 int +,@p1237 int +,@p1238 int +,@p1239 int +,@p1240 int +,@p1241 int +,@p1242 int +,@p1243 int +,@p1244 int +,@p1245 int +,@p1246 int +,@p1247 int +,@p1248 int +,@p1249 int +,@p1250 int +,@p1251 int +,@p1252 int +,@p1253 int +,@p1254 int +,@p1255 int +,@p1256 int +,@p1257 int +,@p1258 int +,@p1259 int +,@p1260 int +,@p1261 int +,@p1262 int +,@p1263 int +,@p1264 int +,@p1265 int +,@p1266 int +,@p1267 int +,@p1268 int +,@p1269 int +,@p1270 int +,@p1271 int +,@p1272 int +,@p1273 int +,@p1274 int +,@p1275 int +,@p1276 int +,@p1277 int +,@p1278 int +,@p1279 int +,@p1280 int +,@p1281 int +,@p1282 int +,@p1283 int +,@p1284 int +,@p1285 int +,@p1286 int +,@p1287 int +,@p1288 int +,@p1289 int +,@p1290 int +,@p1291 int +,@p1292 int +,@p1293 int +,@p1294 int +,@p1295 int +,@p1296 int +,@p1297 int +,@p1298 int +,@p1299 int +,@p1300 int +,@p1301 int +,@p1302 int +,@p1303 int +,@p1304 int +,@p1305 int +,@p1306 int +,@p1307 int +,@p1308 int +,@p1309 int +,@p1310 int +,@p1311 int +,@p1312 int +,@p1313 int +,@p1314 int +,@p1315 int +,@p1316 int +,@p1317 int +,@p1318 int +,@p1319 int +,@p1320 int +,@p1321 int +,@p1322 int +,@p1323 int +,@p1324 int +,@p1325 int +,@p1326 int +,@p1327 int +,@p1328 int +,@p1329 int +,@p1330 int +,@p1331 int +,@p1332 int +,@p1333 int +,@p1334 int +,@p1335 int +,@p1336 int +,@p1337 int +,@p1338 int +,@p1339 int +,@p1340 int +,@p1341 int +,@p1342 int +,@p1343 int +,@p1344 int +,@p1345 int +,@p1346 int +,@p1347 int +,@p1348 int +,@p1349 int +,@p1350 int +,@p1351 int +,@p1352 int +,@p1353 int +,@p1354 int +,@p1355 int +,@p1356 int +,@p1357 int +,@p1358 int +,@p1359 int +,@p1360 int +,@p1361 int +,@p1362 int +,@p1363 int +,@p1364 int +,@p1365 int +,@p1366 int +,@p1367 int +,@p1368 int +,@p1369 int +,@p1370 int +,@p1371 int +,@p1372 int +,@p1373 int +,@p1374 int +,@p1375 int +,@p1376 int +,@p1377 int +,@p1378 int +,@p1379 int +,@p1380 int +,@p1381 int +,@p1382 int +,@p1383 int +,@p1384 int +,@p1385 int +,@p1386 int +,@p1387 int +,@p1388 int +,@p1389 int +,@p1390 int +,@p1391 int +,@p1392 int +,@p1393 int +,@p1394 int +,@p1395 int +,@p1396 int +,@p1397 int +,@p1398 int +,@p1399 int +,@p1400 int +,@p1401 int +,@p1402 int +,@p1403 int +,@p1404 int +,@p1405 int +,@p1406 int +,@p1407 int +,@p1408 int +,@p1409 int +,@p1410 int +,@p1411 int +,@p1412 int +,@p1413 int +,@p1414 int +,@p1415 int +,@p1416 int +,@p1417 int +,@p1418 int +,@p1419 int +,@p1420 int +,@p1421 int +,@p1422 int +,@p1423 int +,@p1424 int +,@p1425 int +,@p1426 int +,@p1427 int +,@p1428 int +,@p1429 int +,@p1430 int +,@p1431 int +,@p1432 int +,@p1433 int +,@p1434 int +,@p1435 int +,@p1436 int +,@p1437 int +,@p1438 int +,@p1439 int +,@p1440 int +,@p1441 int +,@p1442 int +,@p1443 int +,@p1444 int +,@p1445 int +,@p1446 int +,@p1447 int +,@p1448 int +,@p1449 int +,@p1450 int +,@p1451 int +,@p1452 int +,@p1453 int +,@p1454 int +,@p1455 int +,@p1456 int +,@p1457 int +,@p1458 int +,@p1459 int +,@p1460 int +,@p1461 int +,@p1462 int +,@p1463 int +,@p1464 int +,@p1465 int +,@p1466 int +,@p1467 int +,@p1468 int +,@p1469 int +,@p1470 int +,@p1471 int +,@p1472 int +,@p1473 int +,@p1474 int +,@p1475 int +,@p1476 int +,@p1477 int +,@p1478 int +,@p1479 int +,@p1480 int +,@p1481 int +,@p1482 int +,@p1483 int +,@p1484 int +,@p1485 int +,@p1486 int +,@p1487 int +,@p1488 int +,@p1489 int +,@p1490 int +,@p1491 int +,@p1492 int +,@p1493 int +,@p1494 int +,@p1495 int +,@p1496 int +,@p1497 int +,@p1498 int +,@p1499 int +,@p1500 int +,@p1501 int +,@p1502 int +,@p1503 int +,@p1504 int +,@p1505 int +,@p1506 int +,@p1507 int +,@p1508 int +,@p1509 int +,@p1510 int +,@p1511 int +,@p1512 int +,@p1513 int +,@p1514 int +,@p1515 int +,@p1516 int +,@p1517 int +,@p1518 int +,@p1519 int +,@p1520 int +,@p1521 int +,@p1522 int +,@p1523 int +,@p1524 int +,@p1525 int +,@p1526 int +,@p1527 int +,@p1528 int +,@p1529 int +,@p1530 int +,@p1531 int +,@p1532 int +,@p1533 int +,@p1534 int +,@p1535 int +,@p1536 int +,@p1537 int +,@p1538 int +,@p1539 int +,@p1540 int +,@p1541 int +,@p1542 int +,@p1543 int +,@p1544 int +,@p1545 int +,@p1546 int +,@p1547 int +,@p1548 int +,@p1549 int +,@p1550 int +,@p1551 int +,@p1552 int +,@p1553 int +,@p1554 int +,@p1555 int +,@p1556 int +,@p1557 int +,@p1558 int +,@p1559 int +,@p1560 int +,@p1561 int +,@p1562 int +,@p1563 int +,@p1564 int +,@p1565 int +,@p1566 int +,@p1567 int +,@p1568 int +,@p1569 int +,@p1570 int +,@p1571 int +,@p1572 int +,@p1573 int +,@p1574 int +,@p1575 int +,@p1576 int +,@p1577 int +,@p1578 int +,@p1579 int +,@p1580 int +,@p1581 int +,@p1582 int +,@p1583 int +,@p1584 int +,@p1585 int +,@p1586 int +,@p1587 int +,@p1588 int +,@p1589 int +,@p1590 int +,@p1591 int +,@p1592 int +,@p1593 int +,@p1594 int +,@p1595 int +,@p1596 int +,@p1597 int +,@p1598 int +,@p1599 int +,@p1600 int +,@p1601 int +,@p1602 int +,@p1603 int +,@p1604 int +,@p1605 int +,@p1606 int +,@p1607 int +,@p1608 int +,@p1609 int +,@p1610 int +,@p1611 int +,@p1612 int +,@p1613 int +,@p1614 int +,@p1615 int +,@p1616 int +,@p1617 int +,@p1618 int +,@p1619 int +,@p1620 int +,@p1621 int +,@p1622 int +,@p1623 int +,@p1624 int +,@p1625 int +,@p1626 int +,@p1627 int +,@p1628 int +,@p1629 int +,@p1630 int +,@p1631 int +,@p1632 int +,@p1633 int +,@p1634 int +,@p1635 int +,@p1636 int +,@p1637 int +,@p1638 int +,@p1639 int +,@p1640 int +,@p1641 int +,@p1642 int +,@p1643 int +,@p1644 int +,@p1645 int +,@p1646 int +,@p1647 int +,@p1648 int +,@p1649 int +,@p1650 int +,@p1651 int +,@p1652 int +,@p1653 int +,@p1654 int +,@p1655 int +,@p1656 int +,@p1657 int +,@p1658 int +,@p1659 int +,@p1660 int +,@p1661 int +,@p1662 int +,@p1663 int +,@p1664 int +,@p1665 int +,@p1666 int +,@p1667 int +,@p1668 int +,@p1669 int +,@p1670 int +,@p1671 int +,@p1672 int +,@p1673 int +,@p1674 int +,@p1675 int +,@p1676 int +,@p1677 int +,@p1678 int +,@p1679 int +,@p1680 int +,@p1681 int +,@p1682 int +,@p1683 int +,@p1684 int +,@p1685 int +,@p1686 int +,@p1687 int +,@p1688 int +,@p1689 int +,@p1690 int +,@p1691 int +,@p1692 int +,@p1693 int +,@p1694 int +,@p1695 int +,@p1696 int +,@p1697 int +,@p1698 int +,@p1699 int +,@p1700 int +,@p1701 int +,@p1702 int +,@p1703 int +,@p1704 int +,@p1705 int +,@p1706 int +,@p1707 int +,@p1708 int +,@p1709 int +,@p1710 int +,@p1711 int +,@p1712 int +,@p1713 int +,@p1714 int +,@p1715 int +,@p1716 int +,@p1717 int +,@p1718 int +,@p1719 int +,@p1720 int +,@p1721 int +,@p1722 int +,@p1723 int +,@p1724 int +,@p1725 int +,@p1726 int +,@p1727 int +,@p1728 int +,@p1729 int +,@p1730 int +,@p1731 int +,@p1732 int +,@p1733 int +,@p1734 int +,@p1735 int +,@p1736 int +,@p1737 int +,@p1738 int +,@p1739 int +,@p1740 int +,@p1741 int +,@p1742 int +,@p1743 int +,@p1744 int +,@p1745 int +,@p1746 int +,@p1747 int +,@p1748 int +,@p1749 int +,@p1750 int +,@p1751 int +,@p1752 int +,@p1753 int +,@p1754 int +,@p1755 int +,@p1756 int +,@p1757 int +,@p1758 int +,@p1759 int +,@p1760 int +,@p1761 int +,@p1762 int +,@p1763 int +,@p1764 int +,@p1765 int +,@p1766 int +,@p1767 int +,@p1768 int +,@p1769 int +,@p1770 int +,@p1771 int +,@p1772 int +,@p1773 int +,@p1774 int +,@p1775 int +,@p1776 int +,@p1777 int +,@p1778 int +,@p1779 int +,@p1780 int +,@p1781 int +,@p1782 int +,@p1783 int +,@p1784 int +,@p1785 int +,@p1786 int +,@p1787 int +,@p1788 int +,@p1789 int +,@p1790 int +,@p1791 int +,@p1792 int +,@p1793 int +,@p1794 int +,@p1795 int +,@p1796 int +,@p1797 int +,@p1798 int +,@p1799 int +,@p1800 int +,@p1801 int +,@p1802 int +,@p1803 int +,@p1804 int +,@p1805 int +,@p1806 int +,@p1807 int +,@p1808 int +,@p1809 int +,@p1810 int +,@p1811 int +,@p1812 int +,@p1813 int +,@p1814 int +,@p1815 int +,@p1816 int +,@p1817 int +,@p1818 int +,@p1819 int +,@p1820 int +,@p1821 int +,@p1822 int +,@p1823 int +,@p1824 int +,@p1825 int +,@p1826 int +,@p1827 int +,@p1828 int +,@p1829 int +,@p1830 int +,@p1831 int +,@p1832 int +,@p1833 int +,@p1834 int +,@p1835 int +,@p1836 int +,@p1837 int +,@p1838 int +,@p1839 int +,@p1840 int +,@p1841 int +,@p1842 int +,@p1843 int +,@p1844 int +,@p1845 int +,@p1846 int +,@p1847 int +,@p1848 int +,@p1849 int +,@p1850 int +,@p1851 int +,@p1852 int +,@p1853 int +,@p1854 int +,@p1855 int +,@p1856 int +,@p1857 int +,@p1858 int +,@p1859 int +,@p1860 int +,@p1861 int +,@p1862 int +,@p1863 int +,@p1864 int +,@p1865 int +,@p1866 int +,@p1867 int +,@p1868 int +,@p1869 int +,@p1870 int +,@p1871 int +,@p1872 int +,@p1873 int +,@p1874 int +,@p1875 int +,@p1876 int +,@p1877 int +,@p1878 int +,@p1879 int +,@p1880 int +,@p1881 int +,@p1882 int +,@p1883 int +,@p1884 int +,@p1885 int +,@p1886 int +,@p1887 int +,@p1888 int +,@p1889 int +,@p1890 int +,@p1891 int +,@p1892 int +,@p1893 int +,@p1894 int +,@p1895 int +,@p1896 int +,@p1897 int +,@p1898 int +,@p1899 int +,@p1900 int +,@p1901 int +,@p1902 int +,@p1903 int +,@p1904 int +,@p1905 int +,@p1906 int +,@p1907 int +,@p1908 int +,@p1909 int +,@p1910 int +,@p1911 int +,@p1912 int +,@p1913 int +,@p1914 int +,@p1915 int +,@p1916 int +,@p1917 int +,@p1918 int +,@p1919 int +,@p1920 int +,@p1921 int +,@p1922 int +,@p1923 int +,@p1924 int +,@p1925 int +,@p1926 int +,@p1927 int +,@p1928 int +,@p1929 int +,@p1930 int +,@p1931 int +,@p1932 int +,@p1933 int +,@p1934 int +,@p1935 int +,@p1936 int +,@p1937 int +,@p1938 int +,@p1939 int +,@p1940 int +,@p1941 int +,@p1942 int +,@p1943 int +,@p1944 int +,@p1945 int +,@p1946 int +,@p1947 int +,@p1948 int +,@p1949 int +,@p1950 int +,@p1951 int +,@p1952 int +,@p1953 int +,@p1954 int +,@p1955 int +,@p1956 int +,@p1957 int +,@p1958 int +,@p1959 int +,@p1960 int +,@p1961 int +,@p1962 int +,@p1963 int +,@p1964 int +,@p1965 int +,@p1966 int +,@p1967 int +,@p1968 int +,@p1969 int +,@p1970 int +,@p1971 int +,@p1972 int +,@p1973 int +,@p1974 int +,@p1975 int +,@p1976 int +,@p1977 int +,@p1978 int +,@p1979 int +,@p1980 int +,@p1981 int +,@p1982 int +,@p1983 int +,@p1984 int +,@p1985 int +,@p1986 int +,@p1987 int +,@p1988 int +,@p1989 int +,@p1990 int +,@p1991 int +,@p1992 int +,@p1993 int +,@p1994 int +,@p1995 int +,@p1996 int +,@p1997 int +,@p1998 int +,@p1999 int +,@p2000 int +,@p2001 int +,@p2002 int +,@p2003 int +,@p2004 int +,@p2005 int +,@p2006 int +,@p2007 int +,@p2008 int +,@p2009 int +,@p2010 int +,@p2011 int +,@p2012 int +,@p2013 int +,@p2014 int +,@p2015 int +,@p2016 int +,@p2017 int +,@p2018 int +,@p2019 int +,@p2020 int +,@p2021 int +,@p2022 int +,@p2023 int +,@p2024 int +,@p2025 int +,@p2026 int +,@p2027 int +,@p2028 int +,@p2029 int +,@p2030 int +,@p2031 int +,@p2032 int +,@p2033 int +,@p2034 int +,@p2035 int +,@p2036 int +,@p2037 int +,@p2038 int +,@p2039 int +,@p2040 int +,@p2041 int +,@p2042 int +,@p2043 int +,@p2044 int +,@p2045 int +,@p2046 int +,@p2047 int +,@p2048 int +,@p2049 int +,@p2050 int +,@p2051 int +,@p2052 int +,@p2053 int +,@p2054 int +,@p2055 int +,@p2056 int +,@p2057 int +,@p2058 int +,@p2059 int +,@p2060 int +,@p2061 int +,@p2062 int +,@p2063 int +,@p2064 int +,@p2065 int +,@p2066 int +,@p2067 int +,@p2068 int +,@p2069 int +,@p2070 int +,@p2071 int +,@p2072 int +,@p2073 int +,@p2074 int +,@p2075 int +,@p2076 int +,@p2077 int +,@p2078 int +,@p2079 int +,@p2080 int +,@p2081 int +,@p2082 int +,@p2083 int +,@p2084 int +,@p2085 int +,@p2086 int +,@p2087 int +,@p2088 int +,@p2089 int +,@p2090 int +,@p2091 int +,@p2092 int +,@p2093 int +,@p2094 int +,@p2095 int +,@p2096 int +,@p2097 int +,@p2098 int +,@p2099 int +,@p2100 int +,@p2101 int +) +AS +BEGIN + RETURN 100 +END + +GO + +if @@trancount > 0 select cast('Does not respoect xact_abort flag' as TEXT) else select cast('Respects xact_abort flag' as text); +GO + +if @@trancount > 0 rollback tran +GO + +SET XACT_ABORT OFF; +GO + diff --git a/contrib/test/JDBC/input/ErrorMapping/1946_1.sql b/contrib/test/JDBC/input/ErrorMapping/1946_1.sql new file mode 100644 index 00000000000..96a1454aae9 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/1946_1.sql @@ -0,0 +1,523 @@ +-- simple batch start + +CREATE TABLE t1946 +(c1 int IDENTITY +,c2 varchar(500) +,c3 varchar(500) +,c4 varchar(500) +,c5 varchar(500) +,c6 varchar(500) +,c7 varchar(500) +) +GO + +CREATE INDEX ix1946 ON t1946(c1, c2, c3, c4, c5, c6, c7) +GO +INSERT INTO t1946(c2, c3, c4, c5, c6, c7) +VALUES( + REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +) + + + + +GO +DROP TABLE t1946 +GO + +begin transaction +GO +CREATE TABLE t1946 +(c1 int IDENTITY +,c2 varchar(500) +,c3 varchar(500) +,c4 varchar(500) +,c5 varchar(500) +,c6 varchar(500) +,c7 varchar(500) +) +GO + +CREATE INDEX ix1946 ON t1946(c1, c2, c3, c4, c5, c6, c7) +GO +INSERT INTO t1946(c2, c3, c4, c5, c6, c7) +VALUES( + REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +) + + + + +GO + +-- Below output is only applicable if query is special case. for example, CREATE/ALTER TRIGGER, CREATE/ALTER FUNCTION, CREATE/ALTER PROC, CREATE/ALTER VIEW etc + +if (@@trancount > 0) select cast('compile time error' as text) else select cast('runtime error' as text) +GO + +if (@@trancount > 0) rollback tran +GO + +DROP TABLE t1946 +GO + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + +CREATE TABLE t1946 +(c1 int IDENTITY +,c2 varchar(500) +,c3 varchar(500) +,c4 varchar(500) +,c5 varchar(500) +,c6 varchar(500) +,c7 varchar(500) +) +GO + +CREATE INDEX ix1946 ON t1946(c1, c2, c3, c4, c5, c6, c7) +GO +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +INSERT INTO t1946(c2, c3, c4, c5, c6, c7) +VALUES( + REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +) + + + + +end +GO + +DROP TABLE t1946 +GO + +create table error_mapping.temp2 (a int) +GO + +CREATE TABLE t1946 +(c1 int IDENTITY +,c2 varchar(500) +,c3 varchar(500) +,c4 varchar(500) +,c5 varchar(500) +,c6 varchar(500) +,c7 varchar(500) +) +GO + +CREATE INDEX ix1946 ON t1946(c1, c2, c3, c4, c5, c6, c7) +GO +insert into error_mapping.temp2 values(1) +INSERT INTO t1946(c2, c3, c4, c5, c6, c7) +VALUES( + REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +) + + + + +GO + +DROP TABLE t1946 +GO + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + +CREATE TABLE t1946 +(c1 int IDENTITY +,c2 varchar(500) +,c3 varchar(500) +,c4 varchar(500) +,c5 varchar(500) +,c6 varchar(500) +,c7 varchar(500) +) +GO + +CREATE INDEX ix1946 ON t1946(c1, c2, c3, c4, c5, c6, c7) +GO +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO + +DROP TABLE t1946 +GO + +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 + +-- Parse analysis phase end +GO + +-- compile time error portion + +-- Executing test error_mapping.ErrorHandling1 +CREATE TABLE t1946 +(c1 int IDENTITY +,c2 varchar(500) +,c3 varchar(500) +,c4 varchar(500) +,c5 varchar(500) +,c6 varchar(500) +,c7 varchar(500) +) +GO + +CREATE INDEX ix1946 ON t1946(c1, c2, c3, c4, c5, c6, c7) +GO + +create procedure error_mapping.ErrorHandling1 as +begin +INSERT INTO t1946(c2, c3, c4, c5, c6, c7) +VALUES( + REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +) + + + + +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 +DROP TABLE t1946 +GO + + +CREATE TABLE t1946 +(c1 int IDENTITY +,c2 varchar(500) +,c3 varchar(500) +,c4 varchar(500) +,c5 varchar(500) +,c6 varchar(500) +,c7 varchar(500) +) +GO + +CREATE INDEX ix1946 ON t1946(c1, c2, c3, c4, c5, c6, c7) +GO +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +INSERT INTO t1946(c2, c3, c4, c5, c6, c7) +VALUES( + REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +) + + + + +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 + +GO +DROP TABLE t1946 +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE t1946 +(c1 int IDENTITY +,c2 varchar(500) +,c3 varchar(500) +,c4 varchar(500) +,c5 varchar(500) +,c6 varchar(500) +,c7 varchar(500) +) +GO + +CREATE INDEX ix1946 ON t1946(c1, c2, c3, c4, c5, c6, c7) +GO +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +INSERT INTO t1946(c2, c3, c4, c5, c6, c7) +VALUES( + REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +) + + + + +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 + +GO +DROP TABLE t1946 +GO +set xact_abort OFF; +GO + +-- comiple time error portion end -- +-- Next portion is for runtime error -- + +-- Executing test error_mapping.ErrorHandling10000000 +CREATE TABLE t1946 +(c1 int IDENTITY +,c2 varchar(500) +,c3 varchar(500) +,c4 varchar(500) +,c5 varchar(500) +,c6 varchar(500) +,c7 varchar(500) +) +GO + +CREATE INDEX ix1946 ON t1946(c1, c2, c3, c4, c5, c6, c7) +GO + +create procedure error_mapping.ErrorHandling1 as +begin +INSERT INTO t1946(c2, c3, c4, c5, c6, c7) +VALUES( + REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +) + + + + +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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 +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 +DROP TABLE t1946 +GO + + +set xact_abort ON; +GO +-- Executing test error_mapping.ErrorHandling10000000 +CREATE TABLE t1946 +(c1 int IDENTITY +,c2 varchar(500) +,c3 varchar(500) +,c4 varchar(500) +,c5 varchar(500) +,c6 varchar(500) +,c7 varchar(500) +) +GO + +CREATE INDEX ix1946 ON t1946(c1, c2, c3, c4, c5, c6, c7) +GO + +create procedure error_mapping.ErrorHandling1 as +begin +INSERT INTO t1946(c2, c3, c4, c5, c6, c7) +VALUES( + REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +) + + + + +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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 +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 +DROP TABLE t1946 +GO + + + +set xact_abort OFF; +GO + +-- Error classification is done -- + +-- Executing test error_mapping.ErrorHandling10000000 +CREATE TABLE t1946 +(c1 int IDENTITY +,c2 varchar(500) +,c3 varchar(500) +,c4 varchar(500) +,c5 varchar(500) +,c6 varchar(500) +,c7 varchar(500) +) +GO + +CREATE INDEX ix1946 ON t1946(c1, c2, c3, c4, c5, c6, c7) +GO + +begin try +select 1 +INSERT INTO t1946(c2, c3, c4, c5, c6, c7) +VALUES( + REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +) + + + + +end try +begin catch + select xact_state(); +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 +DROP TABLE t1946 +GO + + + +GO +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/input/ErrorMapping/208_1.sql b/contrib/test/JDBC/input/ErrorMapping/208_1.sql new file mode 100644 index 00000000000..6b706dbefbf --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/208_1.sql @@ -0,0 +1,189 @@ +# Executing test ErrorHandling1 +--Pre +GO + +create procedure ErrorHandling1 as +begin +--Table doesn't exist +SELECT * FROM t208; +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +GO + + +--Pre +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +--Table doesn't exist +SELECT * FROM t208; +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +--Post +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +--Pre +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +--Table doesn't exist +SELECT * FROM t208; +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +--Post +GO +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +# Executing test ErrorHandling10000000 +--Pre +GO + +create procedure ErrorHandling1 as +begin +--Table doesn't exist +SELECT * FROM t208; +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +--Pre +GO + +create procedure ErrorHandling1 as +begin +--Table doesn't exist +SELECT * FROM t208; +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +GO + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +# Executing test ErrorHandling10000000 +--Pre +GO + +begin try +select 1 +--Table doesn't exist +SELECT * FROM t208; +end try +begin catch + select xact_state(); +end catch + +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +GO + + diff --git a/contrib/test/JDBC/input/ErrorMapping/217_1.sql b/contrib/test/JDBC/input/ErrorMapping/217_1.sql new file mode 100644 index 00000000000..03e723ad2d9 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/217_1.sql @@ -0,0 +1,285 @@ +# Executing test ErrorHandling1 +--217 NESTLEVEL exceeded + +--Bbf has the incorrect max nestlevel. Should be 32, but it is 1040. +--Known, as BABEL-610 + +--------------------------------------------------------------------------- +--Pre +CREATE PROC p217 AS +PRINT @@NESTLEVEL +--IF @@NESTLEVEL = 33 +--BEGIN +-- RETURN +--END +EXEC p217; +GO + +create procedure ErrorHandling1 as +begin +--------------------------------------------------------------------------- +--Generate the error +EXEC p217; +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--------------------------------------------------------------------------- +--Post +DROP PROC p217 +GO + + +--217 NESTLEVEL exceeded + +--Bbf has the incorrect max nestlevel. Should be 32, but it is 1040. +--Known, as BABEL-610 + +--------------------------------------------------------------------------- +--Pre +CREATE PROC p217 AS +PRINT @@NESTLEVEL +--IF @@NESTLEVEL = 33 +--BEGIN +-- RETURN +--END +EXEC p217; +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +--------------------------------------------------------------------------- +--Generate the error +EXEC p217; +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +--------------------------------------------------------------------------- +--Post +DROP PROC p217 +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +--217 NESTLEVEL exceeded + +--Bbf has the incorrect max nestlevel. Should be 32, but it is 1040. +--Known, as BABEL-610 + +--------------------------------------------------------------------------- +--Pre +CREATE PROC p217 AS +PRINT @@NESTLEVEL +--IF @@NESTLEVEL = 33 +--BEGIN +-- RETURN +--END +EXEC p217; +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +--------------------------------------------------------------------------- +--Generate the error +EXEC p217; +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +--------------------------------------------------------------------------- +--Post +DROP PROC p217 +GO +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +# Executing test ErrorHandling10000000 +--217 NESTLEVEL exceeded + +--Bbf has the incorrect max nestlevel. Should be 32, but it is 1040. +--Known, as BABEL-610 + +--------------------------------------------------------------------------- +--Pre +CREATE PROC p217 AS +PRINT @@NESTLEVEL +--IF @@NESTLEVEL = 33 +--BEGIN +-- RETURN +--END +EXEC p217; +GO + +create procedure ErrorHandling1 as +begin +--------------------------------------------------------------------------- +--Generate the error +EXEC p217; +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--------------------------------------------------------------------------- +--Post +DROP PROC p217 +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +--217 NESTLEVEL exceeded + +--Bbf has the incorrect max nestlevel. Should be 32, but it is 1040. +--Known, as BABEL-610 + +--------------------------------------------------------------------------- +--Pre +CREATE PROC p217 AS +PRINT @@NESTLEVEL +--IF @@NESTLEVEL = 33 +--BEGIN +-- RETURN +--END +EXEC p217; +GO + +create procedure ErrorHandling1 as +begin +--------------------------------------------------------------------------- +--Generate the error +EXEC p217; +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--------------------------------------------------------------------------- +--Post +DROP PROC p217 +GO + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +# Executing test ErrorHandling10000000 +--217 NESTLEVEL exceeded + +--Bbf has the incorrect max nestlevel. Should be 32, but it is 1040. +--Known, as BABEL-610 + +--------------------------------------------------------------------------- +--Pre +CREATE PROC p217 AS +PRINT @@NESTLEVEL +--IF @@NESTLEVEL = 33 +--BEGIN +-- RETURN +--END +EXEC p217; +GO + +begin try +select 1 +--------------------------------------------------------------------------- +--Generate the error +EXEC p217; +end try +begin catch + select xact_state(); +end catch + +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--------------------------------------------------------------------------- +--Post +DROP PROC p217 +GO + + diff --git a/contrib/test/JDBC/input/ErrorMapping/218_1.sql b/contrib/test/JDBC/input/ErrorMapping/218_1.sql new file mode 100644 index 00000000000..a11e3cd534f --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/218_1.sql @@ -0,0 +1,263 @@ +USE master; +GO + +-- simple batch start + +GO +DROP TYPE type_218 +GO +GO + +begin transaction +GO +GO +DROP TYPE type_218 +GO + +-- Below output is only applicable if query is special case. for example, CREATE/ALTER TRIGGER, CREATE/ALTER FUNCTION, CREATE/ALTER PROC, CREATE/ALTER VIEW etc + +if (@@trancount > 0) select cast('compile time error' as text) else select cast('runtime error' as text) +GO + +if (@@trancount > 0) rollback tran +GO + +GO + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + +GO +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +DROP TYPE type_218 +end +GO + +GO + +create table error_mapping.temp2 (a int) +GO + +GO +insert into error_mapping.temp2 values(1) +DROP TYPE type_218 +GO + +GO + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + +GO +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO + +GO + +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 + +-- Parse analysis phase end +GO + +-- compile time error portion + +-- Executing test error_mapping.ErrorHandling1 +GO + +create procedure error_mapping.ErrorHandling1 as +begin +DROP TYPE type_218 +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 +GO + + +GO +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +DROP TYPE type_218 +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 + +GO +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +GO +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +DROP TYPE type_218 +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 + +GO +GO +set xact_abort OFF; +GO + +-- comiple time error portion end -- +-- Next portion is for runtime error -- + +-- Executing test error_mapping.ErrorHandling10000000 +GO + +create procedure error_mapping.ErrorHandling1 as +begin +DROP TYPE type_218 +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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 +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 +GO + + +set xact_abort ON; +GO +-- Executing test error_mapping.ErrorHandling10000000 +GO + +create procedure error_mapping.ErrorHandling1 as +begin +DROP TYPE type_218 +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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 +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 +GO + + + +set xact_abort OFF; +GO + +-- Error classification is done -- + +-- Executing test error_mapping.ErrorHandling10000000 +GO + +begin try +select 1 +DROP TYPE type_218 +end try +begin catch + select xact_state(); +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 +GO + + + +GO +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/input/ErrorMapping/219_1.sql b/contrib/test/JDBC/input/ErrorMapping/219_1.sql new file mode 100644 index 00000000000..d7893bf7564 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/219_1.sql @@ -0,0 +1,183 @@ +# Executing test ErrorHandling1 +CREATE TYPE type_218 from INT +GO + +create procedure ErrorHandling1 as +begin +CREATE TYPE type_218 from INT +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TYPE type_218 +GO + + +CREATE TYPE type_218 from INT +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +CREATE TYPE type_218 from INT +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +DROP TYPE type_218 +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TYPE type_218 from INT +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +CREATE TYPE type_218 from INT +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +DROP TYPE type_218 +GO +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +# Executing test ErrorHandling10000000 +CREATE TYPE type_218 from INT +GO + +create procedure ErrorHandling1 as +begin +CREATE TYPE type_218 from INT +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TYPE type_218 +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +CREATE TYPE type_218 from INT +GO + +create procedure ErrorHandling1 as +begin +CREATE TYPE type_218 from INT +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TYPE type_218 +GO + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +# Executing test ErrorHandling10000000 +CREATE TYPE type_218 from INT +GO + +begin try +select 1 +CREATE TYPE type_218 from INT +end try +begin catch + select xact_state(); +end catch + +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TYPE type_218 +GO + + diff --git a/contrib/test/JDBC/input/ErrorMapping/220_1.sql b/contrib/test/JDBC/input/ErrorMapping/220_1.sql new file mode 100644 index 00000000000..65b0e244eb5 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/220_1.sql @@ -0,0 +1,219 @@ +# Executing test ErrorHandling1 +--Pre +CREATE TABLE t220_1(c1 tinyint); +CREATE TABLE t220_2(c1 smallint); +GO + +create procedure ErrorHandling1 as +begin +--Generate the error +DECLARE @a tinyint = 1000; +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +DROP TABLE t220_1 +GO +DROP TABLE t220_2 +GO + + +--Pre +CREATE TABLE t220_1(c1 tinyint); +CREATE TABLE t220_2(c1 smallint); +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +--Generate the error +DECLARE @a tinyint = 1000; +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +--Post +DROP TABLE t220_1 +GO +DROP TABLE t220_2 +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +--Pre +CREATE TABLE t220_1(c1 tinyint); +CREATE TABLE t220_2(c1 smallint); +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +--Generate the error +DECLARE @a tinyint = 1000; +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +--Post +DROP TABLE t220_1 +GO +DROP TABLE t220_2 +GO +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +# Executing test ErrorHandling10000000 +--Pre +CREATE TABLE t220_1(c1 tinyint); +CREATE TABLE t220_2(c1 smallint); +GO + +create procedure ErrorHandling1 as +begin +--Generate the error +DECLARE @a tinyint = 1000; +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +DROP TABLE t220_1 +GO +DROP TABLE t220_2 +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +--Pre +CREATE TABLE t220_1(c1 tinyint); +CREATE TABLE t220_2(c1 smallint); +GO + +create procedure ErrorHandling1 as +begin +--Generate the error +DECLARE @a tinyint = 1000; +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +DROP TABLE t220_1 +GO +DROP TABLE t220_2 +GO + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +# Executing test ErrorHandling10000000 +--Pre +CREATE TABLE t220_1(c1 tinyint); +CREATE TABLE t220_2(c1 smallint); +GO + +begin try +select 1 +--Generate the error +DECLARE @a tinyint = 1000; +end try +begin catch + select xact_state(); +end catch + +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +DROP TABLE t220_1 +GO +DROP TABLE t220_2 +GO + + diff --git a/contrib/test/JDBC/input/ErrorMapping/220_2.sql b/contrib/test/JDBC/input/ErrorMapping/220_2.sql new file mode 100644 index 00000000000..984ec81627b --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/220_2.sql @@ -0,0 +1,213 @@ +# Executing test ErrorHandling1 +--Pre +CREATE TABLE t220_1(c1 tinyint); +CREATE TABLE t220_2(c1 smallint); +GO + +create procedure ErrorHandling1 as +begin +DECLARE @a smallint = 45000; +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +DROP TABLE t220_1 +GO +DROP TABLE t220_2 +GO + + +--Pre +CREATE TABLE t220_1(c1 tinyint); +CREATE TABLE t220_2(c1 smallint); +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +DECLARE @a smallint = 45000; +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +--Post +DROP TABLE t220_1 +GO +DROP TABLE t220_2 +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +--Pre +CREATE TABLE t220_1(c1 tinyint); +CREATE TABLE t220_2(c1 smallint); +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +DECLARE @a smallint = 45000; +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +--Post +DROP TABLE t220_1 +GO +DROP TABLE t220_2 +GO +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +# Executing test ErrorHandling10000000 +--Pre +CREATE TABLE t220_1(c1 tinyint); +CREATE TABLE t220_2(c1 smallint); +GO + +create procedure ErrorHandling1 as +begin +DECLARE @a smallint = 45000; +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +DROP TABLE t220_1 +GO +DROP TABLE t220_2 +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +--Pre +CREATE TABLE t220_1(c1 tinyint); +CREATE TABLE t220_2(c1 smallint); +GO + +create procedure ErrorHandling1 as +begin +DECLARE @a smallint = 45000; +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +DROP TABLE t220_1 +GO +DROP TABLE t220_2 +GO + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +# Executing test ErrorHandling10000000 +--Pre +CREATE TABLE t220_1(c1 tinyint); +CREATE TABLE t220_2(c1 smallint); +GO + +begin try +select 1 +DECLARE @a smallint = 45000; +end try +begin catch + select xact_state(); +end catch + +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +DROP TABLE t220_1 +GO +DROP TABLE t220_2 +GO + + diff --git a/contrib/test/JDBC/input/ErrorMapping/220_3.sql b/contrib/test/JDBC/input/ErrorMapping/220_3.sql new file mode 100644 index 00000000000..382a5f2491f --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/220_3.sql @@ -0,0 +1,213 @@ +# Executing test ErrorHandling1 +--Pre +CREATE TABLE t220_1(c1 tinyint); +CREATE TABLE t220_2(c1 smallint); +GO + +create procedure ErrorHandling1 as +begin +INSERT INTO t220_1(c1) VALUES(1000); +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +DROP TABLE t220_1 +GO +DROP TABLE t220_2 +GO + + +--Pre +CREATE TABLE t220_1(c1 tinyint); +CREATE TABLE t220_2(c1 smallint); +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +INSERT INTO t220_1(c1) VALUES(1000); +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +--Post +DROP TABLE t220_1 +GO +DROP TABLE t220_2 +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +--Pre +CREATE TABLE t220_1(c1 tinyint); +CREATE TABLE t220_2(c1 smallint); +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +INSERT INTO t220_1(c1) VALUES(1000); +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +--Post +DROP TABLE t220_1 +GO +DROP TABLE t220_2 +GO +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +# Executing test ErrorHandling10000000 +--Pre +CREATE TABLE t220_1(c1 tinyint); +CREATE TABLE t220_2(c1 smallint); +GO + +create procedure ErrorHandling1 as +begin +INSERT INTO t220_1(c1) VALUES(1000); +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +DROP TABLE t220_1 +GO +DROP TABLE t220_2 +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +--Pre +CREATE TABLE t220_1(c1 tinyint); +CREATE TABLE t220_2(c1 smallint); +GO + +create procedure ErrorHandling1 as +begin +INSERT INTO t220_1(c1) VALUES(1000); +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +DROP TABLE t220_1 +GO +DROP TABLE t220_2 +GO + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +# Executing test ErrorHandling10000000 +--Pre +CREATE TABLE t220_1(c1 tinyint); +CREATE TABLE t220_2(c1 smallint); +GO + +begin try +select 1 +INSERT INTO t220_1(c1) VALUES(1000); +end try +begin catch + select xact_state(); +end catch + +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +DROP TABLE t220_1 +GO +DROP TABLE t220_2 +GO + + diff --git a/contrib/test/JDBC/input/ErrorMapping/220_4.sql b/contrib/test/JDBC/input/ErrorMapping/220_4.sql new file mode 100644 index 00000000000..da731983a52 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/220_4.sql @@ -0,0 +1,213 @@ +# Executing test ErrorHandling1 +--Pre +CREATE TABLE t220_1(c1 tinyint); +CREATE TABLE t220_2(c1 smallint); +GO + +create procedure ErrorHandling1 as +begin +INSERT INTO t220_2(c1) VALUES(45000); +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +DROP TABLE t220_1 +GO +DROP TABLE t220_2 +GO + + +--Pre +CREATE TABLE t220_1(c1 tinyint); +CREATE TABLE t220_2(c1 smallint); +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +INSERT INTO t220_2(c1) VALUES(45000); +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +--Post +DROP TABLE t220_1 +GO +DROP TABLE t220_2 +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +--Pre +CREATE TABLE t220_1(c1 tinyint); +CREATE TABLE t220_2(c1 smallint); +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +INSERT INTO t220_2(c1) VALUES(45000); +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +--Post +DROP TABLE t220_1 +GO +DROP TABLE t220_2 +GO +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +# Executing test ErrorHandling10000000 +--Pre +CREATE TABLE t220_1(c1 tinyint); +CREATE TABLE t220_2(c1 smallint); +GO + +create procedure ErrorHandling1 as +begin +INSERT INTO t220_2(c1) VALUES(45000); +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +DROP TABLE t220_1 +GO +DROP TABLE t220_2 +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +--Pre +CREATE TABLE t220_1(c1 tinyint); +CREATE TABLE t220_2(c1 smallint); +GO + +create procedure ErrorHandling1 as +begin +INSERT INTO t220_2(c1) VALUES(45000); +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +DROP TABLE t220_1 +GO +DROP TABLE t220_2 +GO + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +# Executing test ErrorHandling10000000 +--Pre +CREATE TABLE t220_1(c1 tinyint); +CREATE TABLE t220_2(c1 smallint); +GO + +begin try +select 1 +INSERT INTO t220_2(c1) VALUES(45000); +end try +begin catch + select xact_state(); +end catch + +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +DROP TABLE t220_1 +GO +DROP TABLE t220_2 +GO + + diff --git a/contrib/test/JDBC/input/ErrorMapping/222_1.sql b/contrib/test/JDBC/input/ErrorMapping/222_1.sql new file mode 100644 index 00000000000..2feab3d4f5a --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/222_1.sql @@ -0,0 +1,195 @@ +# Executing test ErrorHandling1 +--Pre +GO + +create procedure ErrorHandling1 as +begin +--Generate the error +CREATE TYPE t222_1 FROM t222_2 +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +GO + + + +--Pre +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +--Generate the error +CREATE TYPE t222_1 FROM t222_2 +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +--Post +GO + + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +--Pre +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +--Generate the error +CREATE TYPE t222_1 FROM t222_2 +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +--Post +GO + +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +# Executing test ErrorHandling10000000 +--Pre +GO + +create procedure ErrorHandling1 as +begin +--Generate the error +CREATE TYPE t222_1 FROM t222_2 +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +GO + + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +--Pre +GO + +create procedure ErrorHandling1 as +begin +--Generate the error +CREATE TYPE t222_1 FROM t222_2 +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +GO + + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +# Executing test ErrorHandling10000000 +--Pre +GO + +begin try +select 1 +--Generate the error +CREATE TYPE t222_1 FROM t222_2 +end try +begin catch + select xact_state(); +end catch + +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +GO + + + diff --git a/contrib/test/JDBC/input/ErrorMapping/257_2.sql b/contrib/test/JDBC/input/ErrorMapping/257_2.sql new file mode 100644 index 00000000000..2a4f3422e7f --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/257_2.sql @@ -0,0 +1,195 @@ +# Executing test ErrorHandling1 +--Pre +CREATE TABLE t257(c1 binary(10)); +GO + +create procedure ErrorHandling1 as +begin +DECLARE @a real; SET @a = CAST(GETDATE() AS smalldatetime); +GO +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t257; +GO + + +--Pre +CREATE TABLE t257(c1 binary(10)); +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +DECLARE @a real; SET @a = CAST(GETDATE() AS smalldatetime); +GO +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +DROP TABLE t257; +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +--Pre +CREATE TABLE t257(c1 binary(10)); +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +DECLARE @a real; SET @a = CAST(GETDATE() AS smalldatetime); +GO +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +DROP TABLE t257; +GO +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +# Executing test ErrorHandling10000000 +--Pre +CREATE TABLE t257(c1 binary(10)); +GO + +create procedure ErrorHandling1 as +begin +DECLARE @a real; SET @a = CAST(GETDATE() AS smalldatetime); +GO +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t257; +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +--Pre +CREATE TABLE t257(c1 binary(10)); +GO + +create procedure ErrorHandling1 as +begin +DECLARE @a real; SET @a = CAST(GETDATE() AS smalldatetime); +GO +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t257; +GO + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +# Executing test ErrorHandling10000000 +--Pre +CREATE TABLE t257(c1 binary(10)); +GO + +begin try +select 1 +DECLARE @a real; SET @a = CAST(GETDATE() AS smalldatetime); +GO +end try +begin catch + select xact_state(); +end catch + +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t257; +GO + + diff --git a/contrib/test/JDBC/input/ErrorMapping/2732_1.sql b/contrib/test/JDBC/input/ErrorMapping/2732_1.sql new file mode 100644 index 00000000000..0b7af080bff --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/2732_1.sql @@ -0,0 +1,282 @@ +-- simple batch start + +GO + +RAISERROR(5005, 10, 1, N'ErrorMessage') +GO +GO + + +begin transaction +GO +GO + +RAISERROR(5005, 10, 1, N'ErrorMessage') +GO + +-- Below output is only applicable if query is special case. for example, CREATE/ALTER TRIGGER, CREATE/ALTER FUNCTION, CREATE/ALTER PROC, CREATE/ALTER VIEW etc + +if (@@trancount > 0) select cast('compile time error' as text) else select cast('runtime error' as text) +GO + +if (@@trancount > 0) rollback tran +GO + +GO + + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + +GO + +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +RAISERROR(5005, 10, 1, N'ErrorMessage') +end +GO + +GO + + +create table error_mapping.temp2 (a int) +GO + +GO + +insert into error_mapping.temp2 values(1) +RAISERROR(5005, 10, 1, N'ErrorMessage') +GO + +GO + + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + +GO + +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO + +GO + + +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 + +-- Parse analysis phase end +GO + +-- compile time error portion + +-- Executing test error_mapping.ErrorHandling1 +GO + + +create procedure error_mapping.ErrorHandling1 as +begin +RAISERROR(5005, 10, 1, N'ErrorMessage') +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 +GO + + + +GO + +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +RAISERROR(5005, 10, 1, N'ErrorMessage') +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 + +GO +GO + + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +GO + +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +RAISERROR(5005, 10, 1, N'ErrorMessage') +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 + +GO +GO + +set xact_abort OFF; +GO + +-- comiple time error portion end -- +-- Next portion is for runtime error -- + +-- Executing test error_mapping.ErrorHandling10000000 +GO + + +create procedure error_mapping.ErrorHandling1 as +begin +RAISERROR(5005, 10, 1, N'ErrorMessage') +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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 +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 +GO + + + +set xact_abort ON; +GO +-- Executing test error_mapping.ErrorHandling10000000 +GO + + +create procedure error_mapping.ErrorHandling1 as +begin +RAISERROR(5005, 10, 1, N'ErrorMessage') +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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 +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 +GO + + + + +set xact_abort OFF; +GO + +-- Error classification is done -- + +-- Executing test error_mapping.ErrorHandling10000000 +GO + + +begin try +select 1 +RAISERROR(5005, 10, 1, N'ErrorMessage') +end try +begin catch + select xact_state(); +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 +GO + + + + +GO +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/input/ErrorMapping/2747_1.sql b/contrib/test/JDBC/input/ErrorMapping/2747_1.sql new file mode 100644 index 00000000000..4ed164f206b --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/2747_1.sql @@ -0,0 +1,300 @@ +-- simple batch start + +GO +RAISERROR('%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d' +,1, +1, +3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3) + +GO +GO + +begin transaction +GO +GO +RAISERROR('%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d' +,1, +1, +3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3) + +GO + +-- Below output is only applicable if query is special case. for example, CREATE/ALTER TRIGGER, CREATE/ALTER FUNCTION, CREATE/ALTER PROC, CREATE/ALTER VIEW etc + +if (@@trancount > 0) select cast('compile time error' as text) else select cast('runtime error' as text) +GO + +if (@@trancount > 0) rollback tran +GO + +GO + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + +GO +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +RAISERROR('%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d' +,1, +1, +3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3) + +end +GO + +GO + +create table error_mapping.temp2 (a int) +GO + +GO +insert into error_mapping.temp2 values(1) +RAISERROR('%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d' +,1, +1, +3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3) + +GO + +GO + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + +GO +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO + +GO + +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 + +-- Parse analysis phase end +GO + +-- compile time error portion + +-- Executing test error_mapping.ErrorHandling1 +GO + +create procedure error_mapping.ErrorHandling1 as +begin +RAISERROR('%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d' +,1, +1, +3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3) + +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 +GO + + +GO +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +RAISERROR('%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d' +,1, +1, +3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3) + +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 + +GO +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +GO +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +RAISERROR('%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d' +,1, +1, +3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3) + +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 + +GO +GO +set xact_abort OFF; +GO + +-- comiple time error portion end -- +-- Next portion is for runtime error -- + +-- Executing test error_mapping.ErrorHandling10000000 +--GO +-- +--create procedure error_mapping.ErrorHandling1 as +--begin +--RAISERROR('%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d' +--,1, +--1, +--3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3) +-- +--if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +--select @@trancount; +--end +-- +--GO +-- +--if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +--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 +--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 +--GO +-- +-- +--set xact_abort ON; +--GO +---- Executing test error_mapping.ErrorHandling10000000 +--GO +-- +--create procedure error_mapping.ErrorHandling1 as +--begin +--RAISERROR('%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d' +--,1, +--1, +--3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3) +-- +--if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +--select @@trancount; +--end +-- +--GO +-- +--if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +--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 +--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 +--GO +-- +-- +-- +--set xact_abort OFF; +--GO +-- +-- Error classification is done -- + +-- Executing test error_mapping.ErrorHandling10000000 +GO + +begin try +select 1 +RAISERROR('%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d' +,1, +1, +3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3) + +end try +begin catch + select xact_state(); +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 +--GO +-- +-- +-- +GO +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/input/ErrorMapping/2760_1.sql b/contrib/test/JDBC/input/ErrorMapping/2760_1.sql new file mode 100644 index 00000000000..ff379afade7 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/2760_1.sql @@ -0,0 +1,186 @@ +USE master; +GO + +# Executing test ErrorHandling1 +GO + +create procedure ErrorHandling1 as +begin +CREATE TABLE N0nExistantSchema.t2760 (c1 INT) + +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +GO + + + +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +CREATE TABLE N0nExistantSchema.t2760 (c1 INT) + +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +GO + + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +CREATE TABLE N0nExistantSchema.t2760 (c1 INT) + +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +GO + +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +# Executing test ErrorHandling10000000 +GO + +create procedure ErrorHandling1 as +begin +CREATE TABLE N0nExistantSchema.t2760 (c1 INT) + +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +GO + + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +GO + +create procedure ErrorHandling1 as +begin +CREATE TABLE N0nExistantSchema.t2760 (c1 INT) + +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +GO + + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +# Executing test ErrorHandling10000000 +GO + +begin try +select 1 +CREATE TABLE N0nExistantSchema.t2760 (c1 INT) + +end try +begin catch + select xact_state(); +end catch + +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +GO + + + diff --git a/contrib/test/JDBC/input/ErrorMapping/2787_1.sql b/contrib/test/JDBC/input/ErrorMapping/2787_1.sql new file mode 100644 index 00000000000..a8c5fef8d96 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/2787_1.sql @@ -0,0 +1,282 @@ +-- simple batch start + + +GO +RAISERROR('Hello %q', 16, 1, 'as') +GO + +GO + +begin transaction +GO + +GO +RAISERROR('Hello %q', 16, 1, 'as') +GO + +-- Below output is only applicable if query is special case. for example, CREATE/ALTER TRIGGER, CREATE/ALTER FUNCTION, CREATE/ALTER PROC, CREATE/ALTER VIEW etc + +if (@@trancount > 0) select cast('compile time error' as text) else select cast('runtime error' as text) +GO + +if (@@trancount > 0) rollback tran +GO + + +GO + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + + +GO +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +RAISERROR('Hello %q', 16, 1, 'as') +end +GO + + +GO + +create table error_mapping.temp2 (a int) +GO + + +GO +insert into error_mapping.temp2 values(1) +RAISERROR('Hello %q', 16, 1, 'as') +GO + + +GO + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + + +GO +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO + + +GO + +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 + +-- Parse analysis phase end +GO + +-- compile time error portion + +-- Executing test error_mapping.ErrorHandling1 + +GO + +create procedure error_mapping.ErrorHandling1 as +begin +RAISERROR('Hello %q', 16, 1, 'as') +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 + +GO + + + +GO +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +RAISERROR('Hello %q', 16, 1, 'as') +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 + +GO + +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO + +GO +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +RAISERROR('Hello %q', 16, 1, 'as') +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 + +GO + +GO +set xact_abort OFF; +GO + +-- comiple time error portion end -- +-- Next portion is for runtime error -- + +-- Executing test error_mapping.ErrorHandling10000000 + +GO + +create procedure error_mapping.ErrorHandling1 as +begin +RAISERROR('Hello %q', 16, 1, 'as') +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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 +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 + +GO + + +set xact_abort ON; +GO +-- Executing test error_mapping.ErrorHandling10000000 + +GO + +create procedure error_mapping.ErrorHandling1 as +begin +RAISERROR('Hello %q', 16, 1, 'as') +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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 +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 + +GO + + + +set xact_abort OFF; +GO + +-- Error classification is done -- + +-- Executing test error_mapping.ErrorHandling10000000 + +GO + +begin try +select 1 +RAISERROR('Hello %q', 16, 1, 'as') +end try +begin catch + select xact_state(); +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 + +GO + + + +GO +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/input/ErrorMapping/2812_1.sql b/contrib/test/JDBC/input/ErrorMapping/2812_1.sql new file mode 100644 index 00000000000..2d8bc27bad7 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/2812_1.sql @@ -0,0 +1,177 @@ +# Executing test ErrorHandling1 +--Pre +GO + +create procedure ErrorHandling1 as +begin +glarg buh +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +GO + + +--Pre +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +glarg buh +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +--Pre +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +glarg buh +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +GO +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +# Executing test ErrorHandling10000000 +--Pre +GO + +create procedure ErrorHandling1 as +begin +glarg buh +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +--Pre +GO + +create procedure ErrorHandling1 as +begin +glarg buh +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +GO + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +# Executing test ErrorHandling10000000 +--Pre +GO + +begin try +select 1 +glarg buh +end try +begin catch + select xact_state(); +end catch + +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +GO + + diff --git a/contrib/test/JDBC/input/ErrorMapping/2812_2.sql b/contrib/test/JDBC/input/ErrorMapping/2812_2.sql new file mode 100644 index 00000000000..58457e3dda6 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/2812_2.sql @@ -0,0 +1,177 @@ +# Executing test ErrorHandling1 +--Pre +GO + +create procedure ErrorHandling1 as +begin +EXEC gurka +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +GO + + +--Pre +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +EXEC gurka +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +--Pre +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +EXEC gurka +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +GO +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +# Executing test ErrorHandling10000000 +--Pre +GO + +create procedure ErrorHandling1 as +begin +EXEC gurka +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +--Pre +GO + +create procedure ErrorHandling1 as +begin +EXEC gurka +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +GO + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +# Executing test ErrorHandling10000000 +--Pre +GO + +begin try +select 1 +EXEC gurka +end try +begin catch + select xact_state(); +end catch + +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +GO + + diff --git a/contrib/test/JDBC/input/ErrorMapping/2812_3.sql b/contrib/test/JDBC/input/ErrorMapping/2812_3.sql new file mode 100644 index 00000000000..a1d50102a32 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/2812_3.sql @@ -0,0 +1,177 @@ +# Executing test ErrorHandling1 +--Pre +GO + +create procedure ErrorHandling1 as +begin +glärg buh +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +GO + + +--Pre +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +glärg buh +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +--Pre +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +glärg buh +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +GO +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +# Executing test ErrorHandling10000000 +--Pre +GO + +create procedure ErrorHandling1 as +begin +glärg buh +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +--Pre +GO + +create procedure ErrorHandling1 as +begin +glärg buh +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +GO + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +# Executing test ErrorHandling10000000 +--Pre +GO + +begin try +select 1 +glärg buh +end try +begin catch + select xact_state(); +end catch + +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +GO + + diff --git a/contrib/test/JDBC/input/ErrorMapping/293_1.sql b/contrib/test/JDBC/input/ErrorMapping/293_1.sql new file mode 100644 index 00000000000..482eb5a7208 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/293_1.sql @@ -0,0 +1,378 @@ +-- simple batch start + +CREATE TABLE t293(c1 varchar(255)) +GO + +INSERT INTO t293(c1) +VALUES ('string'); +GO + +SELECT CAST( + (SELECT * FROM t293) + AS SMALLMONEY) + +GO +DROP TABLE t293 +GO + + +begin transaction +GO +CREATE TABLE t293(c1 varchar(255)) +GO + +INSERT INTO t293(c1) +VALUES ('string'); +GO + +SELECT CAST( + (SELECT * FROM t293) + AS SMALLMONEY) + +GO + +-- Below output is only applicable if query is special case. for example, CREATE/ALTER TRIGGER, CREATE/ALTER FUNCTION, CREATE/ALTER PROC, CREATE/ALTER VIEW etc + +if (@@trancount > 0) select cast('compile time error' as text) else select cast('runtime error' as text) +GO + +if (@@trancount > 0) rollback tran +GO + +DROP TABLE t293 +GO + + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + +CREATE TABLE t293(c1 varchar(255)) +GO + +INSERT INTO t293(c1) +VALUES ('string'); +GO + +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +SELECT CAST( + (SELECT * FROM t293) + AS SMALLMONEY) + +end +GO + +DROP TABLE t293 +GO + + +create table error_mapping.temp2 (a int) +GO + +CREATE TABLE t293(c1 varchar(255)) +GO + +INSERT INTO t293(c1) +VALUES ('string'); +GO + +insert into error_mapping.temp2 values(1) +SELECT CAST( + (SELECT * FROM t293) + AS SMALLMONEY) + +GO + +DROP TABLE t293 +GO + + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + +CREATE TABLE t293(c1 varchar(255)) +GO + +INSERT INTO t293(c1) +VALUES ('string'); +GO + +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO + +DROP TABLE t293 +GO + + +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 + +-- Parse analysis phase end +GO + +-- compile time error portion + +-- Executing test error_mapping.ErrorHandling1 +CREATE TABLE t293(c1 varchar(255)) +GO + +INSERT INTO t293(c1) +VALUES ('string'); +GO + + +create procedure error_mapping.ErrorHandling1 as +begin +SELECT CAST( + (SELECT * FROM t293) + AS SMALLMONEY) + +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 +DROP TABLE t293 +GO + + + +CREATE TABLE t293(c1 varchar(255)) +GO + +INSERT INTO t293(c1) +VALUES ('string'); +GO + +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +SELECT CAST( + (SELECT * FROM t293) + AS SMALLMONEY) + +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 + +GO +DROP TABLE t293 +GO + + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE t293(c1 varchar(255)) +GO + +INSERT INTO t293(c1) +VALUES ('string'); +GO + +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +SELECT CAST( + (SELECT * FROM t293) + AS SMALLMONEY) + +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 + +GO +DROP TABLE t293 +GO + +set xact_abort OFF; +GO + +-- comiple time error portion end -- +-- Next portion is for runtime error -- + +-- Executing test error_mapping.ErrorHandling10000000 +CREATE TABLE t293(c1 varchar(255)) +GO + +INSERT INTO t293(c1) +VALUES ('string'); +GO + + +create procedure error_mapping.ErrorHandling1 as +begin +SELECT CAST( + (SELECT * FROM t293) + AS SMALLMONEY) + +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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 +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 +DROP TABLE t293 +GO + + + +set xact_abort ON; +GO +-- Executing test error_mapping.ErrorHandling10000000 +CREATE TABLE t293(c1 varchar(255)) +GO + +INSERT INTO t293(c1) +VALUES ('string'); +GO + + +create procedure error_mapping.ErrorHandling1 as +begin +SELECT CAST( + (SELECT * FROM t293) + AS SMALLMONEY) + +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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 +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 +DROP TABLE t293 +GO + + + + +set xact_abort OFF; +GO + +-- Error classification is done -- + +-- Executing test error_mapping.ErrorHandling10000000 +CREATE TABLE t293(c1 varchar(255)) +GO + +INSERT INTO t293(c1) +VALUES ('string'); +GO + + +begin try +select 1 +SELECT CAST( + (SELECT * FROM t293) + AS SMALLMONEY) + +end try +begin catch + select xact_state(); +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 +DROP TABLE t293 +GO + + + + +GO +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/input/ErrorMapping/3609_1.sql b/contrib/test/JDBC/input/ErrorMapping/3609_1.sql new file mode 100644 index 00000000000..ff8eb30595a --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/3609_1.sql @@ -0,0 +1,403 @@ +-- simple batch start + +CREATE TABLE t3609(id int); +GO + +CREATE TRIGGER t3609Trigger +ON t3609 +AFTER INSERT +AS +BEGIN + COMMIT TRANSACTION + +END +GO + +INSERT INTO t3609 values (1) +GO +DROP TABLE t3609 +Go + +begin transaction +GO +CREATE TABLE t3609(id int); +GO + +CREATE TRIGGER t3609Trigger +ON t3609 +AFTER INSERT +AS +BEGIN + COMMIT TRANSACTION + +END +GO + +INSERT INTO t3609 values (1) +GO + +-- Below output is only applicable if query is special case. for example, CREATE/ALTER TRIGGER, CREATE/ALTER FUNCTION, CREATE/ALTER PROC, CREATE/ALTER VIEW etc + +if (@@trancount > 0) select cast('compile time error' as text) else select cast('runtime error' as text) +GO + +if (@@trancount > 0) rollback tran +GO + +DROP TABLE t3609 +Go + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + +CREATE TABLE t3609(id int); +GO + +CREATE TRIGGER t3609Trigger +ON t3609 +AFTER INSERT +AS +BEGIN + COMMIT TRANSACTION + +END +GO + +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +INSERT INTO t3609 values (1) +end +GO + +DROP TABLE t3609 +Go + +create table error_mapping.temp2 (a int) +GO + +CREATE TABLE t3609(id int); +GO + +CREATE TRIGGER t3609Trigger +ON t3609 +AFTER INSERT +AS +BEGIN + COMMIT TRANSACTION + +END +GO + +insert into error_mapping.temp2 values(1) +INSERT INTO t3609 values (1) +GO + +DROP TABLE t3609 +Go + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + +CREATE TABLE t3609(id int); +GO + +CREATE TRIGGER t3609Trigger +ON t3609 +AFTER INSERT +AS +BEGIN + COMMIT TRANSACTION + +END +GO + +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO + +DROP TABLE t3609 +Go + +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 + +-- Parse analysis phase end +GO + +-- compile time error portion + +-- Executing test error_mapping.ErrorHandling1 +CREATE TABLE t3609(id int); +GO + +CREATE TRIGGER t3609Trigger +ON t3609 +AFTER INSERT +AS +BEGIN + COMMIT TRANSACTION + +END +GO + + +create procedure error_mapping.ErrorHandling1 as +begin +INSERT INTO t3609 values (1) +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 +DROP TABLE t3609 +Go + + +CREATE TABLE t3609(id int); +GO + +CREATE TRIGGER t3609Trigger +ON t3609 +AFTER INSERT +AS +BEGIN + COMMIT TRANSACTION + +END +GO + +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +INSERT INTO t3609 values (1) +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 + +GO +DROP TABLE t3609 +Go + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE t3609(id int); +GO + +CREATE TRIGGER t3609Trigger +ON t3609 +AFTER INSERT +AS +BEGIN + COMMIT TRANSACTION + +END +GO + +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +INSERT INTO t3609 values (1) +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 + +GO +DROP TABLE t3609 +Go +set xact_abort OFF; +GO + +-- comiple time error portion end -- +-- Next portion is for runtime error -- + +-- Executing test error_mapping.ErrorHandling10000000 +CREATE TABLE t3609(id int); +GO + +CREATE TRIGGER t3609Trigger +ON t3609 +AFTER INSERT +AS +BEGIN + COMMIT TRANSACTION + +END +GO + + +create procedure error_mapping.ErrorHandling1 as +begin +INSERT INTO t3609 values (1) +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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 +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 +DROP TABLE t3609 +Go + + +set xact_abort ON; +GO +-- Executing test error_mapping.ErrorHandling10000000 +CREATE TABLE t3609(id int); +GO + +CREATE TRIGGER t3609Trigger +ON t3609 +AFTER INSERT +AS +BEGIN + COMMIT TRANSACTION + +END +GO + + +create procedure error_mapping.ErrorHandling1 as +begin +INSERT INTO t3609 values (1) +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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 +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 +DROP TABLE t3609 +Go + + + +set xact_abort OFF; +GO + +-- Error classification is done -- + +-- Executing test error_mapping.ErrorHandling10000000 +CREATE TABLE t3609(id int); +GO + +CREATE TRIGGER t3609Trigger +ON t3609 +AFTER INSERT +AS +BEGIN + COMMIT TRANSACTION + +END +GO + + +begin try +select 1 +INSERT INTO t3609 values (1) +end try +begin catch + select xact_state(); +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 +DROP TABLE t3609 +Go + + + +GO +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/input/ErrorMapping/3701_3.sql b/contrib/test/JDBC/input/ErrorMapping/3701_3.sql new file mode 100644 index 00000000000..3356773f32c --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/3701_3.sql @@ -0,0 +1,189 @@ +# Executing test ErrorHandling1 +--Pre +GO + +create procedure ErrorHandling1 as +begin +--Procedure doesn't exist +DROP PROC p3701; +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +GO + + +--Pre +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +--Procedure doesn't exist +DROP PROC p3701; +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +--Post +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +--Pre +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +--Procedure doesn't exist +DROP PROC p3701; +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +--Post +GO +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +# Executing test ErrorHandling10000000 +--Pre +GO + +create procedure ErrorHandling1 as +begin +--Procedure doesn't exist +DROP PROC p3701; +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +--Pre +GO + +create procedure ErrorHandling1 as +begin +--Procedure doesn't exist +DROP PROC p3701; +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +GO + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +# Executing test ErrorHandling10000000 +--Pre +GO + +begin try +select 1 +--Procedure doesn't exist +DROP PROC p3701; +end try +begin catch + select xact_state(); +end catch + +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +GO + + diff --git a/contrib/test/JDBC/input/ErrorMapping/3701_4.sql b/contrib/test/JDBC/input/ErrorMapping/3701_4.sql new file mode 100644 index 00000000000..ac808023e8e --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/3701_4.sql @@ -0,0 +1,189 @@ +# Executing test ErrorHandling1 +--Pre +GO + +create procedure ErrorHandling1 as +begin +--Trigger doesn't exist +DROP TRIGGER tr3701 +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +GO + + +--Pre +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +--Trigger doesn't exist +DROP TRIGGER tr3701 +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +--Post +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +--Pre +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +--Trigger doesn't exist +DROP TRIGGER tr3701 +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +--Post +GO +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +# Executing test ErrorHandling10000000 +--Pre +GO + +create procedure ErrorHandling1 as +begin +--Trigger doesn't exist +DROP TRIGGER tr3701 +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +--Pre +GO + +create procedure ErrorHandling1 as +begin +--Trigger doesn't exist +DROP TRIGGER tr3701 +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +GO + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +# Executing test ErrorHandling10000000 +--Pre +GO + +begin try +select 1 +--Trigger doesn't exist +DROP TRIGGER tr3701 +end try +begin catch + select xact_state(); +end catch + +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +GO + + diff --git a/contrib/test/JDBC/input/ErrorMapping/3701_5.sql b/contrib/test/JDBC/input/ErrorMapping/3701_5.sql new file mode 100644 index 00000000000..980908ca7a7 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/3701_5.sql @@ -0,0 +1,189 @@ +# Executing test ErrorHandling1 +--Pre +GO + +create procedure ErrorHandling1 as +begin +--Function doesn't exist +DROP FUNCTION fn3701; +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +GO + + +--Pre +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +--Function doesn't exist +DROP FUNCTION fn3701; +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +--Post +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +--Pre +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +--Function doesn't exist +DROP FUNCTION fn3701; +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +--Post +GO +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +# Executing test ErrorHandling10000000 +--Pre +GO + +create procedure ErrorHandling1 as +begin +--Function doesn't exist +DROP FUNCTION fn3701; +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +--Pre +GO + +create procedure ErrorHandling1 as +begin +--Function doesn't exist +DROP FUNCTION fn3701; +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +GO + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +# Executing test ErrorHandling10000000 +--Pre +GO + +begin try +select 1 +--Function doesn't exist +DROP FUNCTION fn3701; +end try +begin catch + select xact_state(); +end catch + +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +GO + + diff --git a/contrib/test/JDBC/input/ErrorMapping/3728_3727_1.sql b/contrib/test/JDBC/input/ErrorMapping/3728_3727_1.sql new file mode 100644 index 00000000000..b463f352780 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/3728_3727_1.sql @@ -0,0 +1,225 @@ +# Executing test ErrorHandling1 +CREATE TABLE t3728(c1 int, c2 int) +GO +INSERT INTO t3728 VALUES(1, 11) +INSERT INTO t3728 VALUES(1, 111) +INSERT INTO t3728 VALUES(2, 22) +GO + + +create procedure ErrorHandling1 as +begin +ALTER TABLE t3728 + DROP CONSTRAINT NonExistingConstraint +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t3728 +GO + + + +CREATE TABLE t3728(c1 int, c2 int) +GO +INSERT INTO t3728 VALUES(1, 11) +INSERT INTO t3728 VALUES(1, 111) +INSERT INTO t3728 VALUES(2, 22) +GO + +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +ALTER TABLE t3728 + DROP CONSTRAINT NonExistingConstraint +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +DROP TABLE t3728 +GO + + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE t3728(c1 int, c2 int) +GO +INSERT INTO t3728 VALUES(1, 11) +INSERT INTO t3728 VALUES(1, 111) +INSERT INTO t3728 VALUES(2, 22) +GO + +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +ALTER TABLE t3728 + DROP CONSTRAINT NonExistingConstraint +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +DROP TABLE t3728 +GO + +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +# Executing test ErrorHandling10000000 +CREATE TABLE t3728(c1 int, c2 int) +GO +INSERT INTO t3728 VALUES(1, 11) +INSERT INTO t3728 VALUES(1, 111) +INSERT INTO t3728 VALUES(2, 22) +GO + + +create procedure ErrorHandling1 as +begin +ALTER TABLE t3728 + DROP CONSTRAINT NonExistingConstraint +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t3728 +GO + + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +CREATE TABLE t3728(c1 int, c2 int) +GO +INSERT INTO t3728 VALUES(1, 11) +INSERT INTO t3728 VALUES(1, 111) +INSERT INTO t3728 VALUES(2, 22) +GO + + +create procedure ErrorHandling1 as +begin +ALTER TABLE t3728 + DROP CONSTRAINT NonExistingConstraint +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t3728 +GO + + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +# Executing test ErrorHandling10000000 +CREATE TABLE t3728(c1 int, c2 int) +GO +INSERT INTO t3728 VALUES(1, 11) +INSERT INTO t3728 VALUES(1, 111) +INSERT INTO t3728 VALUES(2, 22) +GO + + +begin try +select 1 +ALTER TABLE t3728 + DROP CONSTRAINT NonExistingConstraint +end try +begin catch + select xact_state(); +end catch + +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t3728 +GO + + + diff --git a/contrib/test/JDBC/input/ErrorMapping/3729_1.sql b/contrib/test/JDBC/input/ErrorMapping/3729_1.sql new file mode 100644 index 00000000000..31ba3ca2e6b --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/3729_1.sql @@ -0,0 +1,282 @@ +USE master +GO + +# Executing test ErrorHandling1 +CREATE SCHEMA s3729 +GO + +CREATE FUNCTION s3729.f3729 () +RETURNS INT +AS +BEGIN + RETURN 123 ; +END; +GO + +CREATE TABLE t3729(c1 int default s3729.f3729()) +GO + + +create procedure ErrorHandling1 as +begin +DROP FUNCTION s3729.f3729 +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t3729 +GO +DROP FUNCTION s3729.f3729 +GO +DROP SCHEMA s3729 +GO + + +CREATE SCHEMA s3729 +GO + +CREATE FUNCTION s3729.f3729 () +RETURNS INT +AS +BEGIN + RETURN 123 ; +END; +GO + +CREATE TABLE t3729(c1 int default s3729.f3729()) +GO + +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +DROP FUNCTION s3729.f3729 +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +DROP TABLE t3729 +GO +DROP FUNCTION s3729.f3729 +GO +DROP SCHEMA s3729 +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE SCHEMA s3729 +GO + +CREATE FUNCTION s3729.f3729 () +RETURNS INT +AS +BEGIN + RETURN 123 ; +END; +GO + +CREATE TABLE t3729(c1 int default s3729.f3729()) +GO + +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +DROP FUNCTION s3729.f3729 +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +DROP TABLE t3729 +GO +DROP FUNCTION s3729.f3729 +GO +DROP SCHEMA s3729 +GO +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +# Executing test ErrorHandling10000000 +CREATE SCHEMA s3729 +GO + +CREATE FUNCTION s3729.f3729 () +RETURNS INT +AS +BEGIN + RETURN 123 ; +END; +GO + +CREATE TABLE t3729(c1 int default s3729.f3729()) +GO + + +create procedure ErrorHandling1 as +begin +DROP FUNCTION s3729.f3729 +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t3729 +GO +DROP FUNCTION s3729.f3729 +GO +DROP SCHEMA s3729 +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +CREATE SCHEMA s3729 +GO + +CREATE FUNCTION s3729.f3729 () +RETURNS INT +AS +BEGIN + RETURN 123 ; +END; +GO + +CREATE TABLE t3729(c1 int default s3729.f3729()) +GO + + +create procedure ErrorHandling1 as +begin +DROP FUNCTION s3729.f3729 +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t3729 +GO +DROP FUNCTION s3729.f3729 +GO +DROP SCHEMA s3729 +GO + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +# Executing test ErrorHandling10000000 +CREATE SCHEMA s3729 +GO + +CREATE FUNCTION s3729.f3729 () +RETURNS INT +AS +BEGIN + RETURN 123 ; +END; +GO + +CREATE TABLE t3729(c1 int default s3729.f3729()) +GO + + +begin try +select 1 +DROP FUNCTION s3729.f3729 +end try +begin catch + select xact_state(); +end catch + +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t3729 +GO +DROP FUNCTION s3729.f3729 +GO +DROP SCHEMA s3729 +GO + + diff --git a/contrib/test/JDBC/input/ErrorMapping/3902_1.sql b/contrib/test/JDBC/input/ErrorMapping/3902_1.sql new file mode 100644 index 00000000000..24180c29af7 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/3902_1.sql @@ -0,0 +1,189 @@ +# Executing test ErrorHandling1 +--Pre +GO + +create procedure ErrorHandling1 as +begin +--Generate the error +COMMIT; +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +GO + + +--Pre +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +--Generate the error +COMMIT; +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +--Post +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +--Pre +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +--Generate the error +COMMIT; +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +--Post +GO +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +# Executing test ErrorHandling10000000 +--Pre +GO + +create procedure ErrorHandling1 as +begin +--Generate the error +COMMIT; +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +--Pre +GO + +create procedure ErrorHandling1 as +begin +--Generate the error +COMMIT; +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +GO + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +# Executing test ErrorHandling10000000 +--Pre +GO + +begin try +select 1 +--Generate the error +COMMIT; +end try +begin catch + select xact_state(); +end catch + +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +GO + + diff --git a/contrib/test/JDBC/input/ErrorMapping/3903_1.sql b/contrib/test/JDBC/input/ErrorMapping/3903_1.sql new file mode 100644 index 00000000000..055eeee72a2 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/3903_1.sql @@ -0,0 +1,195 @@ +# Executing test ErrorHandling1 +--Pre +GO + + +create procedure ErrorHandling1 as +begin +--Generate the error +ROLLBACK +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +GO + + +--Pre +GO + +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +--Generate the error +ROLLBACK +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +--Post +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +--Pre +GO + +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +--Generate the error +ROLLBACK +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +--Post +GO +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +# Executing test ErrorHandling10000000 +--Pre +GO + + +create procedure ErrorHandling1 as +begin +--Generate the error +ROLLBACK +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +--Pre +GO + + +create procedure ErrorHandling1 as +begin +--Generate the error +ROLLBACK +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +GO + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +# Executing test ErrorHandling10000000 +--Pre +GO + + +begin try +select 1 +--Generate the error +ROLLBACK +end try +begin catch + select xact_state(); +end catch + +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +GO + + diff --git a/contrib/test/JDBC/input/ErrorMapping/3930_1.sql b/contrib/test/JDBC/input/ErrorMapping/3930_1.sql new file mode 100644 index 00000000000..cfa82a2f7d9 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/3930_1.sql @@ -0,0 +1,271 @@ +# Executing test ErrorHandling1 +CREATE TABLE t3930_1(c1 int primary key, c2 int) +GO +CREATE TABLE t3930_2(c1 int primary key, c2 int, constraint fk foreign key (c2) references t3930_1(c1)) +GO +CREATE TABLE t3930 (a int) +GO + +create procedure ErrorHandling1 as +begin +begin tran + begin try + TRUNCATE TABLE t3930_1; + end try + begin catch + select xact_state(); + drop table t3930; + end catch +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t3930_2 +GO +DROP TABLE t3930_1 +GO +DROP TABLE t3930 +GO + + +CREATE TABLE t3930_1(c1 int primary key, c2 int) +GO +CREATE TABLE t3930_2(c1 int primary key, c2 int, constraint fk foreign key (c2) references t3930_1(c1)) +GO +CREATE TABLE t3930 (a int) +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +begin tran + begin try + TRUNCATE TABLE t3930_1; + end try + begin catch + select xact_state(); + drop table t3930; + end catch +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +DROP TABLE t3930_2 +GO +DROP TABLE t3930_1 +GO +DROP TABLE t3930 +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE t3930_1(c1 int primary key, c2 int) +GO +CREATE TABLE t3930_2(c1 int primary key, c2 int, constraint fk foreign key (c2) references t3930_1(c1)) +GO +CREATE TABLE t3930 (a int) +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +begin tran + begin try + TRUNCATE TABLE t3930_1; + end try + begin catch + select xact_state(); + drop table t3930; + end catch +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +DROP TABLE t3930_2 +GO +DROP TABLE t3930_1 +GO +DROP TABLE t3930 +GO +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +# Executing test ErrorHandling10000000 +CREATE TABLE t3930_1(c1 int primary key, c2 int) +GO +CREATE TABLE t3930_2(c1 int primary key, c2 int, constraint fk foreign key (c2) references t3930_1(c1)) +GO +CREATE TABLE t3930 (a int) +GO + +create procedure ErrorHandling1 as +begin +begin tran + begin try + TRUNCATE TABLE t3930_1; + end try + begin catch + select xact_state(); + drop table t3930; + end catch +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t3930_2 +GO +DROP TABLE t3930_1 +GO +DROP TABLE t3930 +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +CREATE TABLE t3930_1(c1 int primary key, c2 int) +GO +CREATE TABLE t3930_2(c1 int primary key, c2 int, constraint fk foreign key (c2) references t3930_1(c1)) +GO +CREATE TABLE t3930 (a int) +GO + +create procedure ErrorHandling1 as +begin +begin tran + begin try + TRUNCATE TABLE t3930_1; + end try + begin catch + select xact_state(); + drop table t3930; + end catch +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t3930_2 +GO +DROP TABLE t3930_1 +GO +DROP TABLE t3930 +GO + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +# Executing test ErrorHandling10000000 +CREATE TABLE t3930_1(c1 int primary key, c2 int) +GO +CREATE TABLE t3930_2(c1 int primary key, c2 int, constraint fk foreign key (c2) references t3930_1(c1)) +GO +CREATE TABLE t3930 (a int) +GO + +begin try +select 1 +begin tran + begin try + TRUNCATE TABLE t3930_1; + end try + begin catch + select xact_state(); + drop table t3930; + end catch +end try +begin catch + select xact_state(); +end catch + +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t3930_2 +GO +DROP TABLE t3930_1 +GO +DROP TABLE t3930 +GO diff --git a/contrib/test/JDBC/input/ErrorMapping/4708_1.sql b/contrib/test/JDBC/input/ErrorMapping/4708_1.sql new file mode 100644 index 00000000000..eb905be40dc --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/4708_1.sql @@ -0,0 +1,249 @@ +# Executing test ErrorHandling1 +CREATE TABLE t4708(c1 int) +GO +CREATE VIEW v4708 +AS +SELECT c1 FROM t4708 +GO + + + +create procedure ErrorHandling1 as +begin +TRUNCATE TABLE v4708 + +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP VIEW v4708 +GO +DROP TABLE t4708 +GO + + + + +CREATE TABLE t4708(c1 int) +GO +CREATE VIEW v4708 +AS +SELECT c1 FROM t4708 +GO + + +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +TRUNCATE TABLE v4708 + +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +DROP VIEW v4708 +GO +DROP TABLE t4708 +GO + + + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE t4708(c1 int) +GO +CREATE VIEW v4708 +AS +SELECT c1 FROM t4708 +GO + + +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +TRUNCATE TABLE v4708 + +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +DROP VIEW v4708 +GO +DROP TABLE t4708 +GO + + +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +# Executing test ErrorHandling10000000 +CREATE TABLE t4708(c1 int) +GO +CREATE VIEW v4708 +AS +SELECT c1 FROM t4708 +GO + + + +create procedure ErrorHandling1 as +begin +TRUNCATE TABLE v4708 + +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP VIEW v4708 +GO +DROP TABLE t4708 +GO + + + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +CREATE TABLE t4708(c1 int) +GO +CREATE VIEW v4708 +AS +SELECT c1 FROM t4708 +GO + + + +create procedure ErrorHandling1 as +begin +TRUNCATE TABLE v4708 + +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP VIEW v4708 +GO +DROP TABLE t4708 +GO + + + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +# Executing test ErrorHandling10000000 +CREATE TABLE t4708(c1 int) +GO +CREATE VIEW v4708 +AS +SELECT c1 FROM t4708 +GO + + + +begin try +select 1 +TRUNCATE TABLE v4708 + +end try +begin catch + select xact_state(); +end catch + +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP VIEW v4708 +GO +DROP TABLE t4708 +GO + + + + diff --git a/contrib/test/JDBC/input/ErrorMapping/4712_1.sql b/contrib/test/JDBC/input/ErrorMapping/4712_1.sql new file mode 100644 index 00000000000..087f43520ca --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/4712_1.sql @@ -0,0 +1,243 @@ +# Executing test ErrorHandling1 +--Pre +CREATE TABLE t4712_1(c1 int primary key, c2 int) +GO +CREATE TABLE t4712_2(c1 int primary key, c2 int, constraint fk foreign key (c2) references t4712_1(c1)) +GO +INSERT INTO t4712_1 VALUES(1, 10) +INSERT INTO t4712_2 VALUES(100, 1) +GO + +create procedure ErrorHandling1 as +begin +--CHECK constraint conflict, when adding constraint +TRUNCATE TABLE t4712_1 +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +DROP TABLE t4712_2 +GO +DROP TABLE t4712_1 +GO + + +--Pre +CREATE TABLE t4712_1(c1 int primary key, c2 int) +GO +CREATE TABLE t4712_2(c1 int primary key, c2 int, constraint fk foreign key (c2) references t4712_1(c1)) +GO +INSERT INTO t4712_1 VALUES(1, 10) +INSERT INTO t4712_2 VALUES(100, 1) +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +--CHECK constraint conflict, when adding constraint +TRUNCATE TABLE t4712_1 +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +--Post +DROP TABLE t4712_2 +GO +DROP TABLE t4712_1 +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +--Pre +CREATE TABLE t4712_1(c1 int primary key, c2 int) +GO +CREATE TABLE t4712_2(c1 int primary key, c2 int, constraint fk foreign key (c2) references t4712_1(c1)) +GO +INSERT INTO t4712_1 VALUES(1, 10) +INSERT INTO t4712_2 VALUES(100, 1) +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +--CHECK constraint conflict, when adding constraint +TRUNCATE TABLE t4712_1 +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +--Post +DROP TABLE t4712_2 +GO +DROP TABLE t4712_1 +GO +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +# Executing test ErrorHandling10000000 +--Pre +CREATE TABLE t4712_1(c1 int primary key, c2 int) +GO +CREATE TABLE t4712_2(c1 int primary key, c2 int, constraint fk foreign key (c2) references t4712_1(c1)) +GO +INSERT INTO t4712_1 VALUES(1, 10) +INSERT INTO t4712_2 VALUES(100, 1) +GO + +create procedure ErrorHandling1 as +begin +--CHECK constraint conflict, when adding constraint +TRUNCATE TABLE t4712_1 +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +DROP TABLE t4712_2 +GO +DROP TABLE t4712_1 +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +--Pre +CREATE TABLE t4712_1(c1 int primary key, c2 int) +GO +CREATE TABLE t4712_2(c1 int primary key, c2 int, constraint fk foreign key (c2) references t4712_1(c1)) +GO +INSERT INTO t4712_1 VALUES(1, 10) +INSERT INTO t4712_2 VALUES(100, 1) +GO + +create procedure ErrorHandling1 as +begin +--CHECK constraint conflict, when adding constraint +TRUNCATE TABLE t4712_1 +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +DROP TABLE t4712_2 +GO +DROP TABLE t4712_1 +GO + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +# Executing test ErrorHandling10000000 +--Pre +CREATE TABLE t4712_1(c1 int primary key, c2 int) +GO +CREATE TABLE t4712_2(c1 int primary key, c2 int, constraint fk foreign key (c2) references t4712_1(c1)) +GO +INSERT INTO t4712_1 VALUES(1, 10) +INSERT INTO t4712_2 VALUES(100, 1) +GO + +begin try +select 1 +--CHECK constraint conflict, when adding constraint +TRUNCATE TABLE t4712_1 +end try +begin catch + select xact_state(); +end catch + +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +DROP TABLE t4712_2 +GO +DROP TABLE t4712_1 +GO + + diff --git a/contrib/test/JDBC/input/ErrorMapping/4901_1.sql b/contrib/test/JDBC/input/ErrorMapping/4901_1.sql new file mode 100644 index 00000000000..974c8c12681 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/4901_1.sql @@ -0,0 +1,326 @@ +-- simple batch start + +CREATE TABLE t4901(c1 varchar(23)) +GO +INSERT INTO t4901 VALUES('a') +GO + +ALTER TABLE t4901 ADD c2 int NOT NULL +GO +DROP TABLE t4901 +GO + + +begin transaction +GO +CREATE TABLE t4901(c1 varchar(23)) +GO +INSERT INTO t4901 VALUES('a') +GO + +ALTER TABLE t4901 ADD c2 int NOT NULL +GO + +-- Below output is only applicable if query is special case. for example, CREATE/ALTER TRIGGER, CREATE/ALTER FUNCTION, CREATE/ALTER PROC, CREATE/ALTER VIEW etc + +if (@@trancount > 0) select cast('compile time error' as text) else select cast('runtime error' as text) +GO + +if (@@trancount > 0) rollback tran +GO + +DROP TABLE t4901 +GO + + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + +CREATE TABLE t4901(c1 varchar(23)) +GO +INSERT INTO t4901 VALUES('a') +GO + +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +ALTER TABLE t4901 ADD c2 int NOT NULL +end +GO + +DROP TABLE t4901 +GO + + +create table error_mapping.temp2 (a int) +GO + +CREATE TABLE t4901(c1 varchar(23)) +GO +INSERT INTO t4901 VALUES('a') +GO + +insert into error_mapping.temp2 values(1) +ALTER TABLE t4901 ADD c2 int NOT NULL +GO + +DROP TABLE t4901 +GO + + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + +CREATE TABLE t4901(c1 varchar(23)) +GO +INSERT INTO t4901 VALUES('a') +GO + +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO + +DROP TABLE t4901 +GO + + +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 + +-- Parse analysis phase end +GO + +-- compile time error portion + +-- Executing test error_mapping.ErrorHandling1 +CREATE TABLE t4901(c1 varchar(23)) +GO +INSERT INTO t4901 VALUES('a') +GO + + +create procedure error_mapping.ErrorHandling1 as +begin +ALTER TABLE t4901 ADD c2 int NOT NULL +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 +DROP TABLE t4901 +GO + + + +CREATE TABLE t4901(c1 varchar(23)) +GO +INSERT INTO t4901 VALUES('a') +GO + +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +ALTER TABLE t4901 ADD c2 int NOT NULL +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 + +GO +DROP TABLE t4901 +GO + + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE t4901(c1 varchar(23)) +GO +INSERT INTO t4901 VALUES('a') +GO + +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +ALTER TABLE t4901 ADD c2 int NOT NULL +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 + +GO +DROP TABLE t4901 +GO + +set xact_abort OFF; +GO + +-- comiple time error portion end -- +-- Next portion is for runtime error -- + +-- Executing test error_mapping.ErrorHandling10000000 +CREATE TABLE t4901(c1 varchar(23)) +GO +INSERT INTO t4901 VALUES('a') +GO + + +create procedure error_mapping.ErrorHandling1 as +begin +ALTER TABLE t4901 ADD c2 int NOT NULL +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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 +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 +DROP TABLE t4901 +GO + + + +set xact_abort ON; +GO +-- Executing test error_mapping.ErrorHandling10000000 +CREATE TABLE t4901(c1 varchar(23)) +GO +INSERT INTO t4901 VALUES('a') +GO + + +create procedure error_mapping.ErrorHandling1 as +begin +ALTER TABLE t4901 ADD c2 int NOT NULL +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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 +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 +DROP TABLE t4901 +GO + + + + +set xact_abort OFF; +GO + +-- Error classification is done -- + +-- Executing test error_mapping.ErrorHandling10000000 +CREATE TABLE t4901(c1 varchar(23)) +GO +INSERT INTO t4901 VALUES('a') +GO + + +begin try +select 1 +ALTER TABLE t4901 ADD c2 int NOT NULL +end try +begin catch + select xact_state(); +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 +DROP TABLE t4901 +GO + + + + +GO +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/input/ErrorMapping/4920_1.sql b/contrib/test/JDBC/input/ErrorMapping/4920_1.sql new file mode 100644 index 00000000000..fb4f2933df1 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/4920_1.sql @@ -0,0 +1,243 @@ +# Executing test ErrorHandling1 +CREATE TABLE t4920(c1 int) +GO + +CREATE TRIGGER tr_4920 ON t4920 +AFTER INSERT +AS +SELECT 1 +GO + + +create procedure ErrorHandling1 as +begin +ALTER TABLE t4920 + DISABLE TRIGGER NonExisting +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t4920 +GO + + + + +CREATE TABLE t4920(c1 int) +GO + +CREATE TRIGGER tr_4920 ON t4920 +AFTER INSERT +AS +SELECT 1 +GO + +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +ALTER TABLE t4920 + DISABLE TRIGGER NonExisting +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +DROP TABLE t4920 +GO + + + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE t4920(c1 int) +GO + +CREATE TRIGGER tr_4920 ON t4920 +AFTER INSERT +AS +SELECT 1 +GO + +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +ALTER TABLE t4920 + DISABLE TRIGGER NonExisting +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +DROP TABLE t4920 +GO + + +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +# Executing test ErrorHandling10000000 +CREATE TABLE t4920(c1 int) +GO + +CREATE TRIGGER tr_4920 ON t4920 +AFTER INSERT +AS +SELECT 1 +GO + + +create procedure ErrorHandling1 as +begin +ALTER TABLE t4920 + DISABLE TRIGGER NonExisting +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t4920 +GO + + + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +CREATE TABLE t4920(c1 int) +GO + +CREATE TRIGGER tr_4920 ON t4920 +AFTER INSERT +AS +SELECT 1 +GO + + +create procedure ErrorHandling1 as +begin +ALTER TABLE t4920 + DISABLE TRIGGER NonExisting +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t4920 +GO + + + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +# Executing test ErrorHandling10000000 +CREATE TABLE t4920(c1 int) +GO + +CREATE TRIGGER tr_4920 ON t4920 +AFTER INSERT +AS +SELECT 1 +GO + + +begin try +select 1 +ALTER TABLE t4920 + DISABLE TRIGGER NonExisting +end try +begin catch + select xact_state(); +end catch + +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t4920 +GO + + + + diff --git a/contrib/test/JDBC/input/ErrorMapping/4924_1.sql b/contrib/test/JDBC/input/ErrorMapping/4924_1.sql new file mode 100644 index 00000000000..2fc0b449c56 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/4924_1.sql @@ -0,0 +1,225 @@ +# Executing test ErrorHandling1 +CREATE TABLE t4924(c1 int, c2 int) +GO + + +create procedure ErrorHandling1 as +begin +ALTER TABLE t4924 DROP COLUMN NonExisting + + + + +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t4924 +GO + + + + +CREATE TABLE t4924(c1 int, c2 int) +GO + +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +ALTER TABLE t4924 DROP COLUMN NonExisting + + + + +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +DROP TABLE t4924 +GO + + + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE t4924(c1 int, c2 int) +GO + +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +ALTER TABLE t4924 DROP COLUMN NonExisting + + + + +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +DROP TABLE t4924 +GO + + +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +# Executing test ErrorHandling10000000 +CREATE TABLE t4924(c1 int, c2 int) +GO + + +create procedure ErrorHandling1 as +begin +ALTER TABLE t4924 DROP COLUMN NonExisting + + + + +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t4924 +GO + + + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +CREATE TABLE t4924(c1 int, c2 int) +GO + + +create procedure ErrorHandling1 as +begin +ALTER TABLE t4924 DROP COLUMN NonExisting + + + + +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t4924 +GO + + + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +# Executing test ErrorHandling10000000 +CREATE TABLE t4924(c1 int, c2 int) +GO + + +begin try +select 1 +ALTER TABLE t4924 DROP COLUMN NonExisting + + + + +end try +begin catch + select xact_state(); +end catch + +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t4924 +GO + + + + diff --git a/contrib/test/JDBC/input/ErrorMapping/4924_2.sql b/contrib/test/JDBC/input/ErrorMapping/4924_2.sql new file mode 100644 index 00000000000..2a3eab1f6dd --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/4924_2.sql @@ -0,0 +1,225 @@ +# Executing test ErrorHandling1 +CREATE TABLE t4924(c1 int, c2 int) +GO + + +create procedure ErrorHandling1 as +begin +ALTER TABLE t4924 ALTER COLUMN c3 bigint + + + + +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t4924 +GO + + + + +CREATE TABLE t4924(c1 int, c2 int) +GO + +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +ALTER TABLE t4924 ALTER COLUMN c3 bigint + + + + +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +DROP TABLE t4924 +GO + + + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE t4924(c1 int, c2 int) +GO + +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +ALTER TABLE t4924 ALTER COLUMN c3 bigint + + + + +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +DROP TABLE t4924 +GO + + +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +# Executing test ErrorHandling10000000 +CREATE TABLE t4924(c1 int, c2 int) +GO + + +create procedure ErrorHandling1 as +begin +ALTER TABLE t4924 ALTER COLUMN c3 bigint + + + + +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t4924 +GO + + + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +CREATE TABLE t4924(c1 int, c2 int) +GO + + +create procedure ErrorHandling1 as +begin +ALTER TABLE t4924 ALTER COLUMN c3 bigint + + + + +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t4924 +GO + + + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +# Executing test ErrorHandling10000000 +CREATE TABLE t4924(c1 int, c2 int) +GO + + +begin try +select 1 +ALTER TABLE t4924 ALTER COLUMN c3 bigint + + + + +end try +begin catch + select xact_state(); +end catch + +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t4924 +GO + + + + diff --git a/contrib/test/JDBC/input/ErrorMapping/4936_1.sql b/contrib/test/JDBC/input/ErrorMapping/4936_1.sql new file mode 100644 index 00000000000..4e9b06e04a0 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/4936_1.sql @@ -0,0 +1,195 @@ +# Executing test ErrorHandling1 +CREATE TABLE t4936 (c1 DATETIME, c2 INT) +GO + + +create procedure ErrorHandling1 as +begin +ALTER TABLE t4936 ADD c3 AS CONVERT(DATETIME2,ISNULL(c1, DATEADD(SECOND, c2, CONVERT(DATE,'19700101'))),112) PERSISTED + +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t4936 +GO + + +CREATE TABLE t4936 (c1 DATETIME, c2 INT) +GO + +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +ALTER TABLE t4936 ADD c3 AS CONVERT(DATETIME2,ISNULL(c1, DATEADD(SECOND, c2, CONVERT(DATE,'19700101'))),112) PERSISTED + +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +DROP TABLE t4936 +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE t4936 (c1 DATETIME, c2 INT) +GO + +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +ALTER TABLE t4936 ADD c3 AS CONVERT(DATETIME2,ISNULL(c1, DATEADD(SECOND, c2, CONVERT(DATE,'19700101'))),112) PERSISTED + +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +DROP TABLE t4936 +GO +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +# Executing test ErrorHandling10000000 +CREATE TABLE t4936 (c1 DATETIME, c2 INT) +GO + + +create procedure ErrorHandling1 as +begin +ALTER TABLE t4936 ADD c3 AS CONVERT(DATETIME2,ISNULL(c1, DATEADD(SECOND, c2, CONVERT(DATE,'19700101'))),112) PERSISTED + +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t4936 +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +CREATE TABLE t4936 (c1 DATETIME, c2 INT) +GO + + +create procedure ErrorHandling1 as +begin +ALTER TABLE t4936 ADD c3 AS CONVERT(DATETIME2,ISNULL(c1, DATEADD(SECOND, c2, CONVERT(DATE,'19700101'))),112) PERSISTED + +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t4936 +GO + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +# Executing test ErrorHandling10000000 +CREATE TABLE t4936 (c1 DATETIME, c2 INT) +GO + + +begin try +select 1 +ALTER TABLE t4936 ADD c3 AS CONVERT(DATETIME2,ISNULL(c1, DATEADD(SECOND, c2, CONVERT(DATE,'19700101'))),112) PERSISTED + +end try +begin catch + select xact_state(); +end catch + +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t4936 +GO + + diff --git a/contrib/test/JDBC/input/ErrorMapping/4936_2.sql b/contrib/test/JDBC/input/ErrorMapping/4936_2.sql new file mode 100644 index 00000000000..cccc03a4dd8 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/4936_2.sql @@ -0,0 +1,213 @@ +# Executing test ErrorHandling1 +CREATE TABLE t4936 (c1 DATETIME, c2 INT) +GO + + +create procedure ErrorHandling1 as +begin +CREATE TABLE t4936b +( + c1 INT, + c2 AS GETDATE() persisted +) +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t4936 +GO + + +CREATE TABLE t4936 (c1 DATETIME, c2 INT) +GO + +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +CREATE TABLE t4936b +( + c1 INT, + c2 AS GETDATE() persisted +) +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +DROP TABLE t4936 +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE t4936 (c1 DATETIME, c2 INT) +GO + +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +CREATE TABLE t4936b +( + c1 INT, + c2 AS GETDATE() persisted +) +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +DROP TABLE t4936 +GO +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +# Executing test ErrorHandling10000000 +CREATE TABLE t4936 (c1 DATETIME, c2 INT) +GO + + +create procedure ErrorHandling1 as +begin +CREATE TABLE t4936b +( + c1 INT, + c2 AS GETDATE() persisted +) +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t4936 +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +CREATE TABLE t4936 (c1 DATETIME, c2 INT) +GO + + +create procedure ErrorHandling1 as +begin +CREATE TABLE t4936b +( + c1 INT, + c2 AS GETDATE() persisted +) +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t4936 +GO + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +# Executing test ErrorHandling10000000 +CREATE TABLE t4936 (c1 DATETIME, c2 INT) +GO + + +begin try +select 1 +CREATE TABLE t4936b +( + c1 INT, + c2 AS GETDATE() persisted +) +end try +begin catch + select xact_state(); +end catch + +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t4936 +GO + + diff --git a/contrib/test/JDBC/input/ErrorMapping/512_1.sql b/contrib/test/JDBC/input/ErrorMapping/512_1.sql new file mode 100644 index 00000000000..824c21a363d --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/512_1.sql @@ -0,0 +1,207 @@ +# Executing test ErrorHandling1 +--Pre +CREATE TABLE t512(c1 int); +INSERT INTO t512 VALUES(1), (5); +GO + +create procedure ErrorHandling1 as +begin +--Generate the error +SELECT * FROM t512 WHERE c1 = (SELECT c1 FROM t512); +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +DROP TABLE t512; +GO + + +--Pre +CREATE TABLE t512(c1 int); +INSERT INTO t512 VALUES(1), (5); +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +--Generate the error +SELECT * FROM t512 WHERE c1 = (SELECT c1 FROM t512); +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +--Post +DROP TABLE t512; +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +--Pre +CREATE TABLE t512(c1 int); +INSERT INTO t512 VALUES(1), (5); +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +--Generate the error +SELECT * FROM t512 WHERE c1 = (SELECT c1 FROM t512); +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +--Post +DROP TABLE t512; +GO +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +# Executing test ErrorHandling10000000 +--Pre +CREATE TABLE t512(c1 int); +INSERT INTO t512 VALUES(1), (5); +GO + +create procedure ErrorHandling1 as +begin +--Generate the error +SELECT * FROM t512 WHERE c1 = (SELECT c1 FROM t512); +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +DROP TABLE t512; +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +--Pre +CREATE TABLE t512(c1 int); +INSERT INTO t512 VALUES(1), (5); +GO + +create procedure ErrorHandling1 as +begin +--Generate the error +SELECT * FROM t512 WHERE c1 = (SELECT c1 FROM t512); +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +DROP TABLE t512; +GO + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +# Executing test ErrorHandling10000000 +--Pre +CREATE TABLE t512(c1 int); +INSERT INTO t512 VALUES(1), (5); +GO + +begin try +select 1 +--Generate the error +SELECT * FROM t512 WHERE c1 = (SELECT c1 FROM t512); +end try +begin catch + select xact_state(); +end catch + +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +DROP TABLE t512; +GO + + diff --git a/contrib/test/JDBC/input/ErrorMapping/515_1.sql b/contrib/test/JDBC/input/ErrorMapping/515_1.sql new file mode 100644 index 00000000000..79c8af57f18 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/515_1.sql @@ -0,0 +1,201 @@ +# Executing test ErrorHandling1 +--Pre +CREATE TABLE t515(c1 int not null); +GO + +create procedure ErrorHandling1 as +begin +--Generate the error +INSERT INTO t515 VALUES(null); +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +DROP TABLE t515 +GO + + +--Pre +CREATE TABLE t515(c1 int not null); +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +--Generate the error +INSERT INTO t515 VALUES(null); +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +--Post +DROP TABLE t515 +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +--Pre +CREATE TABLE t515(c1 int not null); +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +--Generate the error +INSERT INTO t515 VALUES(null); +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +--Post +DROP TABLE t515 +GO +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +# Executing test ErrorHandling10000000 +--Pre +CREATE TABLE t515(c1 int not null); +GO + +create procedure ErrorHandling1 as +begin +--Generate the error +INSERT INTO t515 VALUES(null); +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +DROP TABLE t515 +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +--Pre +CREATE TABLE t515(c1 int not null); +GO + +create procedure ErrorHandling1 as +begin +--Generate the error +INSERT INTO t515 VALUES(null); +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +DROP TABLE t515 +GO + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +# Executing test ErrorHandling10000000 +--Pre +CREATE TABLE t515(c1 int not null); +GO + +begin try +select 1 +--Generate the error +INSERT INTO t515 VALUES(null); +end try +begin catch + select xact_state(); +end catch + +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +DROP TABLE t515 +GO + + diff --git a/contrib/test/JDBC/input/ErrorMapping/517_1.sql b/contrib/test/JDBC/input/ErrorMapping/517_1.sql new file mode 100644 index 00000000000..6c19f4c2801 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/517_1.sql @@ -0,0 +1,282 @@ +-- simple batch start + +GO + +SELECT DATEADD(YY,-300,getdate()) +GO +GO + + +begin transaction +GO +GO + +SELECT DATEADD(YY,-300,getdate()) +GO + +-- Below output is only applicable if query is special case. for example, CREATE/ALTER TRIGGER, CREATE/ALTER FUNCTION, CREATE/ALTER PROC, CREATE/ALTER VIEW etc + +if (@@trancount > 0) select cast('compile time error' as text) else select cast('runtime error' as text) +GO + +if (@@trancount > 0) rollback tran +GO + +GO + + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + +GO + +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +SELECT DATEADD(YY,-300,getdate()) +end +GO + +GO + + +create table error_mapping.temp2 (a int) +GO + +GO + +insert into error_mapping.temp2 values(1) +SELECT DATEADD(YY,-300,getdate()) +GO + +GO + + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + +GO + +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO + +GO + + +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 + +-- Parse analysis phase end +GO + +-- compile time error portion + +-- Executing test error_mapping.ErrorHandling1 +GO + + +create procedure error_mapping.ErrorHandling1 as +begin +SELECT DATEADD(YY,-300,getdate()) +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 +GO + + + +GO + +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +SELECT DATEADD(YY,-300,getdate()) +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 + +GO +GO + + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +GO + +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +SELECT DATEADD(YY,-300,getdate()) +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 + +GO +GO + +set xact_abort OFF; +GO + +-- comiple time error portion end -- +-- Next portion is for runtime error -- + +-- Executing test error_mapping.ErrorHandling10000000 +GO + + +create procedure error_mapping.ErrorHandling1 as +begin +SELECT DATEADD(YY,-300,getdate()) +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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 +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 +GO + + + +set xact_abort ON; +GO +-- Executing test error_mapping.ErrorHandling10000000 +GO + + +create procedure error_mapping.ErrorHandling1 as +begin +SELECT DATEADD(YY,-300,getdate()) +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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 +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 +GO + + + + +set xact_abort OFF; +GO + +-- Error classification is done -- + +-- Executing test error_mapping.ErrorHandling10000000 +GO + + +begin try +select 1 +SELECT DATEADD(YY,-300,getdate()) +end try +begin catch + select xact_state(); +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 +GO + + + + +GO +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/input/ErrorMapping/545_1.sql b/contrib/test/JDBC/input/ErrorMapping/545_1.sql new file mode 100644 index 00000000000..f9f961e6dcc --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/545_1.sql @@ -0,0 +1,261 @@ +# Executing test ErrorHandling1 +CREATE TABLE t545 +( + c1 int IDENTITY +,c2 int +) + +GO + + + +create procedure ErrorHandling1 as +begin +SET IDENTITY_INSERT t545 ON + +INSERT INTO t545 (c2) VALUES(2) + +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t545 + +GO + + + + +CREATE TABLE t545 +( + c1 int IDENTITY +,c2 int +) + +GO + + +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +SET IDENTITY_INSERT t545 ON + +INSERT INTO t545 (c2) VALUES(2) + +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +DROP TABLE t545 + +GO + + + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE t545 +( + c1 int IDENTITY +,c2 int +) + +GO + + +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +SET IDENTITY_INSERT t545 ON + +INSERT INTO t545 (c2) VALUES(2) + +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +DROP TABLE t545 + +GO + + +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +# Executing test ErrorHandling10000000 +CREATE TABLE t545 +( + c1 int IDENTITY +,c2 int +) + +GO + + + +create procedure ErrorHandling1 as +begin +SET IDENTITY_INSERT t545 ON + +INSERT INTO t545 (c2) VALUES(2) + +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t545 + +GO + + + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +CREATE TABLE t545 +( + c1 int IDENTITY +,c2 int +) + +GO + + + +create procedure ErrorHandling1 as +begin +SET IDENTITY_INSERT t545 ON + +INSERT INTO t545 (c2) VALUES(2) + +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t545 + +GO + + + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +# Executing test ErrorHandling10000000 +CREATE TABLE t545 +( + c1 int IDENTITY +,c2 int +) + +GO + + + +begin try +select 1 +SET IDENTITY_INSERT t545 ON + +INSERT INTO t545 (c2) VALUES(2) + +end try +begin catch + select xact_state(); +end catch + +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t545 + +GO + + + + diff --git a/contrib/test/JDBC/input/ErrorMapping/550_1.sql b/contrib/test/JDBC/input/ErrorMapping/550_1.sql new file mode 100644 index 00000000000..a3245c3ef72 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/550_1.sql @@ -0,0 +1,279 @@ +# Executing test ErrorHandling1 +CREATE TABLE t550 +( + c1 int IDENTITY +,c2 int +) +GO + +CREATE VIEW v550 +AS +SELECT c1, c2 FROM t550 WHERE c2 < 10 +WITH CHECK OPTION +GO + + +create procedure ErrorHandling1 as +begin +INSERT INTO v550 (c2) VALUES(20) +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP VIEW v550 +GO + +DROP TABLE t550 +GO + + + + +CREATE TABLE t550 +( + c1 int IDENTITY +,c2 int +) +GO + +CREATE VIEW v550 +AS +SELECT c1, c2 FROM t550 WHERE c2 < 10 +WITH CHECK OPTION +GO + +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +INSERT INTO v550 (c2) VALUES(20) +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +DROP VIEW v550 +GO + +DROP TABLE t550 +GO + + + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE t550 +( + c1 int IDENTITY +,c2 int +) +GO + +CREATE VIEW v550 +AS +SELECT c1, c2 FROM t550 WHERE c2 < 10 +WITH CHECK OPTION +GO + +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +INSERT INTO v550 (c2) VALUES(20) +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +DROP VIEW v550 +GO + +DROP TABLE t550 +GO + + +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +# Executing test ErrorHandling10000000 +CREATE TABLE t550 +( + c1 int IDENTITY +,c2 int +) +GO + +CREATE VIEW v550 +AS +SELECT c1, c2 FROM t550 WHERE c2 < 10 +WITH CHECK OPTION +GO + + +create procedure ErrorHandling1 as +begin +INSERT INTO v550 (c2) VALUES(20) +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP VIEW v550 +GO + +DROP TABLE t550 +GO + + + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +CREATE TABLE t550 +( + c1 int IDENTITY +,c2 int +) +GO + +CREATE VIEW v550 +AS +SELECT c1, c2 FROM t550 WHERE c2 < 10 +WITH CHECK OPTION +GO + + +create procedure ErrorHandling1 as +begin +INSERT INTO v550 (c2) VALUES(20) +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP VIEW v550 +GO + +DROP TABLE t550 +GO + + + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +# Executing test ErrorHandling10000000 +CREATE TABLE t550 +( + c1 int IDENTITY +,c2 int +) +GO + +CREATE VIEW v550 +AS +SELECT c1, c2 FROM t550 WHERE c2 < 10 +WITH CHECK OPTION +GO + + +begin try +select 1 +INSERT INTO v550 (c2) VALUES(20) +end try +begin catch + select xact_state(); +end catch + +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP VIEW v550 +GO + +DROP TABLE t550 +GO + + + + diff --git a/contrib/test/JDBC/input/ErrorMapping/556_1.sql b/contrib/test/JDBC/input/ErrorMapping/556_1.sql new file mode 100644 index 00000000000..ffd3aa1aeec --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/556_1.sql @@ -0,0 +1,468 @@ +-- simple batch start + +CREATE TABLE t556 ( + id int NOT NULL + , results varchar(50) NOT NULL +); +GO + +CREATE PROCEDURE proc_556 +AS +BEGIN + ALTER TABLE t556 ADD test_type INT; +END; +GO +INSERT INTO t556(id, results) +EXECUTE proc_556; +GO + +INSERT INTO t556(id, results) +EXECUTE proc_556; +GO +DROP PROC proc_556 +GO +DROP TABLE t556 +GO + +begin transaction +GO +CREATE TABLE t556 ( + id int NOT NULL + , results varchar(50) NOT NULL +); +GO + +CREATE PROCEDURE proc_556 +AS +BEGIN + ALTER TABLE t556 ADD test_type INT; +END; +GO +INSERT INTO t556(id, results) +EXECUTE proc_556; +GO + +INSERT INTO t556(id, results) +EXECUTE proc_556; +GO + +-- Below output is only applicable if query is special case. for example, CREATE/ALTER TRIGGER, CREATE/ALTER FUNCTION, CREATE/ALTER PROC, CREATE/ALTER VIEW etc + +if (@@trancount > 0) select cast('compile time error' as text) else select cast('runtime error' as text) +GO + +if (@@trancount > 0) rollback tran +GO + +DROP PROC proc_556 +GO +DROP TABLE t556 +GO + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + +CREATE TABLE t556 ( + id int NOT NULL + , results varchar(50) NOT NULL +); +GO + +CREATE PROCEDURE proc_556 +AS +BEGIN + ALTER TABLE t556 ADD test_type INT; +END; +GO +INSERT INTO t556(id, results) +EXECUTE proc_556; +GO + +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +INSERT INTO t556(id, results) +EXECUTE proc_556; +end +GO + +DROP PROC proc_556 +GO +DROP TABLE t556 +GO + +create table error_mapping.temp2 (a int) +GO + +CREATE TABLE t556 ( + id int NOT NULL + , results varchar(50) NOT NULL +); +GO + +CREATE PROCEDURE proc_556 +AS +BEGIN + ALTER TABLE t556 ADD test_type INT; +END; +GO +INSERT INTO t556(id, results) +EXECUTE proc_556; +GO + +insert into error_mapping.temp2 values(1) +INSERT INTO t556(id, results) +EXECUTE proc_556; +GO + +DROP PROC proc_556 +GO +DROP TABLE t556 +GO + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + +CREATE TABLE t556 ( + id int NOT NULL + , results varchar(50) NOT NULL +); +GO + +CREATE PROCEDURE proc_556 +AS +BEGIN + ALTER TABLE t556 ADD test_type INT; +END; +GO +INSERT INTO t556(id, results) +EXECUTE proc_556; +GO + +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO + +DROP PROC proc_556 +GO +DROP TABLE t556 +GO + +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 + +-- Parse analysis phase end +GO + +-- compile time error portion + +-- Executing test error_mapping.ErrorHandling1 +CREATE TABLE t556 ( + id int NOT NULL + , results varchar(50) NOT NULL +); +GO + +CREATE PROCEDURE proc_556 +AS +BEGIN + ALTER TABLE t556 ADD test_type INT; +END; +GO +INSERT INTO t556(id, results) +EXECUTE proc_556; +GO + + +create procedure error_mapping.ErrorHandling1 as +begin +INSERT INTO t556(id, results) +EXECUTE proc_556; +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 +DROP PROC proc_556 +GO +DROP TABLE t556 +GO + + +CREATE TABLE t556 ( + id int NOT NULL + , results varchar(50) NOT NULL +); +GO + +CREATE PROCEDURE proc_556 +AS +BEGIN + ALTER TABLE t556 ADD test_type INT; +END; +GO +INSERT INTO t556(id, results) +EXECUTE proc_556; +GO + +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +INSERT INTO t556(id, results) +EXECUTE proc_556; +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 + +GO +DROP PROC proc_556 +GO +DROP TABLE t556 +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE t556 ( + id int NOT NULL + , results varchar(50) NOT NULL +); +GO + +CREATE PROCEDURE proc_556 +AS +BEGIN + ALTER TABLE t556 ADD test_type INT; +END; +GO +INSERT INTO t556(id, results) +EXECUTE proc_556; +GO + +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +INSERT INTO t556(id, results) +EXECUTE proc_556; +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 + +GO +DROP PROC proc_556 +GO +DROP TABLE t556 +GO +set xact_abort OFF; +GO + +-- comiple time error portion end -- +-- Next portion is for runtime error -- + +-- Executing test error_mapping.ErrorHandling10000000 +CREATE TABLE t556 ( + id int NOT NULL + , results varchar(50) NOT NULL +); +GO + +CREATE PROCEDURE proc_556 +AS +BEGIN + ALTER TABLE t556 ADD test_type INT; +END; +GO +INSERT INTO t556(id, results) +EXECUTE proc_556; +GO + + +create procedure error_mapping.ErrorHandling1 as +begin +INSERT INTO t556(id, results) +EXECUTE proc_556; +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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 +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 +DROP PROC proc_556 +GO +DROP TABLE t556 +GO + + +set xact_abort ON; +GO +-- Executing test error_mapping.ErrorHandling10000000 +CREATE TABLE t556 ( + id int NOT NULL + , results varchar(50) NOT NULL +); +GO + +CREATE PROCEDURE proc_556 +AS +BEGIN + ALTER TABLE t556 ADD test_type INT; +END; +GO +INSERT INTO t556(id, results) +EXECUTE proc_556; +GO + + +create procedure error_mapping.ErrorHandling1 as +begin +INSERT INTO t556(id, results) +EXECUTE proc_556; +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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 +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 +DROP PROC proc_556 +GO +DROP TABLE t556 +GO + + + +set xact_abort OFF; +GO + +-- Error classification is done -- + +-- Executing test error_mapping.ErrorHandling10000000 +CREATE TABLE t556 ( + id int NOT NULL + , results varchar(50) NOT NULL +); +GO + +CREATE PROCEDURE proc_556 +AS +BEGIN + ALTER TABLE t556 ADD test_type INT; +END; +GO +INSERT INTO t556(id, results) +EXECUTE proc_556; +GO + + +begin try +select 1 +INSERT INTO t556(id, results) +EXECUTE proc_556; +end try +begin catch + select xact_state(); +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 +DROP PROC proc_556 +GO +DROP TABLE t556 +GO + + + +GO +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/input/ErrorMapping/6401_1.sql b/contrib/test/JDBC/input/ErrorMapping/6401_1.sql new file mode 100644 index 00000000000..0cf0f52c1e7 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/6401_1.sql @@ -0,0 +1,213 @@ +# Executing test ErrorHandling1 +--Pre +GO + +create procedure ErrorHandling1 as +begin +--Generate the error +BEGIN TRAN; +SAVE TRAN mytran; +ROLLBACK TRAN myMispelledTran; +ROLLBACK; +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +GO + + + +--Pre +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +--Generate the error +BEGIN TRAN; +SAVE TRAN mytran; +ROLLBACK TRAN myMispelledTran; +ROLLBACK; +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +--Post +GO + + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +--Pre +GO +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +--Generate the error +BEGIN TRAN; +SAVE TRAN mytran; +ROLLBACK TRAN myMispelledTran; +ROLLBACK; +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +--Post +GO + +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +# Executing test ErrorHandling10000000 +--Pre +GO + +create procedure ErrorHandling1 as +begin +--Generate the error +BEGIN TRAN; +SAVE TRAN mytran; +ROLLBACK TRAN myMispelledTran; +ROLLBACK; +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +GO + + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +--Pre +GO + +create procedure ErrorHandling1 as +begin +--Generate the error +BEGIN TRAN; +SAVE TRAN mytran; +ROLLBACK TRAN myMispelledTran; +ROLLBACK; +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +GO + + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +# Executing test ErrorHandling10000000 +--Pre +GO + +begin try +select 1 +--Generate the error +BEGIN TRAN; +SAVE TRAN mytran; +ROLLBACK TRAN myMispelledTran; +ROLLBACK; +end try +begin catch + select xact_state(); +end catch + +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +GO + + + diff --git a/contrib/test/JDBC/input/ErrorMapping/8106_1.sql b/contrib/test/JDBC/input/ErrorMapping/8106_1.sql new file mode 100644 index 00000000000..c7719b63f17 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/8106_1.sql @@ -0,0 +1,314 @@ +-- simple batch start + +CREATE TABLE t8106(a int) +GO + +SET IDENTITY_INSERT t8106 ON + +GO +DROP TABLE t8106 +GO + + +begin transaction +GO +CREATE TABLE t8106(a int) +GO + +SET IDENTITY_INSERT t8106 ON + +GO + +-- Below output is only applicable if query is special case. for example, CREATE/ALTER TRIGGER, CREATE/ALTER FUNCTION, CREATE/ALTER PROC, CREATE/ALTER VIEW etc + +if (@@trancount > 0) select cast('compile time error' as text) else select cast('runtime error' as text) +GO + +if (@@trancount > 0) rollback tran +GO + +DROP TABLE t8106 +GO + + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + +CREATE TABLE t8106(a int) +GO + +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +SET IDENTITY_INSERT t8106 ON + +end +GO + +DROP TABLE t8106 +GO + + +create table error_mapping.temp2 (a int) +GO + +CREATE TABLE t8106(a int) +GO + +insert into error_mapping.temp2 values(1) +SET IDENTITY_INSERT t8106 ON + +GO + +DROP TABLE t8106 +GO + + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + +CREATE TABLE t8106(a int) +GO + +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO + +DROP TABLE t8106 +GO + + +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 + +-- Parse analysis phase end +GO + +-- compile time error portion + +-- Executing test error_mapping.ErrorHandling1 +CREATE TABLE t8106(a int) +GO + + +create procedure error_mapping.ErrorHandling1 as +begin +SET IDENTITY_INSERT t8106 ON + +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 +DROP TABLE t8106 +GO + + + +CREATE TABLE t8106(a int) +GO + +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +SET IDENTITY_INSERT t8106 ON + +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 + +GO +DROP TABLE t8106 +GO + + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE t8106(a int) +GO + +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +SET IDENTITY_INSERT t8106 ON + +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 + +GO +DROP TABLE t8106 +GO + +set xact_abort OFF; +GO + +-- comiple time error portion end -- +-- Next portion is for runtime error -- + +-- Executing test error_mapping.ErrorHandling10000000 +CREATE TABLE t8106(a int) +GO + + +create procedure error_mapping.ErrorHandling1 as +begin +SET IDENTITY_INSERT t8106 ON + +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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 +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 +DROP TABLE t8106 +GO + + + +set xact_abort ON; +GO +-- Executing test error_mapping.ErrorHandling10000000 +CREATE TABLE t8106(a int) +GO + + +create procedure error_mapping.ErrorHandling1 as +begin +SET IDENTITY_INSERT t8106 ON + +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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 +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 +DROP TABLE t8106 +GO + + + + +set xact_abort OFF; +GO + +-- Error classification is done -- + +-- Executing test error_mapping.ErrorHandling10000000 +CREATE TABLE t8106(a int) +GO + + +begin try +select 1 +SET IDENTITY_INSERT t8106 ON + +end try +begin catch + select xact_state(); +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 +DROP TABLE t8106 +GO + + + + +GO +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/input/ErrorMapping/8107_1.sql b/contrib/test/JDBC/input/ErrorMapping/8107_1.sql new file mode 100644 index 00000000000..ce13194e796 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/8107_1.sql @@ -0,0 +1,291 @@ +# Executing test ErrorHandling1 +CREATE TABLE t8107_1(a int identity) +GO + +CREATE TABLE t8107_2(a int identity) +GO + +SET IDENTITY_INSERT t8107_1 ON +GO + +INSERT INTO t8107_1(a) VALUES(1) +GO + + +create procedure ErrorHandling1 as +begin +SET IDENTITY_INSERT t8107_2 ON + +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +SET IDENTITY_INSERT t8107_1 OFF +GO + +DROP TABLE t8107_1 +GO + +DROP TABLE t8107_2 +GO + + + +CREATE TABLE t8107_1(a int identity) +GO + +CREATE TABLE t8107_2(a int identity) +GO + +SET IDENTITY_INSERT t8107_1 ON +GO + +INSERT INTO t8107_1(a) VALUES(1) +GO + +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +SET IDENTITY_INSERT t8107_2 ON + +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +SET IDENTITY_INSERT t8107_1 OFF +GO + +DROP TABLE t8107_1 +GO + +DROP TABLE t8107_2 +GO + + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE t8107_1(a int identity) +GO + +CREATE TABLE t8107_2(a int identity) +GO + +SET IDENTITY_INSERT t8107_1 ON +GO + +INSERT INTO t8107_1(a) VALUES(1) +GO + +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +SET IDENTITY_INSERT t8107_2 ON + +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +SET IDENTITY_INSERT t8107_1 OFF +GO + +DROP TABLE t8107_1 +GO + +DROP TABLE t8107_2 +GO + +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +# Executing test ErrorHandling10000000 +CREATE TABLE t8107_1(a int identity) +GO + +CREATE TABLE t8107_2(a int identity) +GO + +SET IDENTITY_INSERT t8107_1 ON +GO + +INSERT INTO t8107_1(a) VALUES(1) +GO + + +create procedure ErrorHandling1 as +begin +SET IDENTITY_INSERT t8107_2 ON + +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +SET IDENTITY_INSERT t8107_1 OFF +GO + +DROP TABLE t8107_1 +GO + +DROP TABLE t8107_2 +GO + + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +CREATE TABLE t8107_1(a int identity) +GO + +CREATE TABLE t8107_2(a int identity) +GO + +SET IDENTITY_INSERT t8107_1 ON +GO + +INSERT INTO t8107_1(a) VALUES(1) +GO + + +create procedure ErrorHandling1 as +begin +SET IDENTITY_INSERT t8107_2 ON + +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +SET IDENTITY_INSERT t8107_1 OFF +GO + +DROP TABLE t8107_1 +GO + +DROP TABLE t8107_2 +GO + + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +# Executing test ErrorHandling10000000 +CREATE TABLE t8107_1(a int identity) +GO + +CREATE TABLE t8107_2(a int identity) +GO + +SET IDENTITY_INSERT t8107_1 ON +GO + +INSERT INTO t8107_1(a) VALUES(1) +GO + + +begin try +select 1 +SET IDENTITY_INSERT t8107_2 ON + +end try +begin catch + select xact_state(); +end catch + +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +SET IDENTITY_INSERT t8107_1 OFF +GO + +DROP TABLE t8107_1 +GO + +DROP TABLE t8107_2 +GO + + + diff --git a/contrib/test/JDBC/input/ErrorMapping/8143_1.sql b/contrib/test/JDBC/input/ErrorMapping/8143_1.sql new file mode 100644 index 00000000000..8cc8923259a --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/8143_1.sql @@ -0,0 +1,201 @@ +# Executing test ErrorHandling1 + +GO + + + +create procedure ErrorHandling1 as +begin +EXEC sp_releaseapplock @Resource = 'SomeResource', @Resource = 'SomeResource' + +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO + + + +GO + + +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +EXEC sp_releaseapplock @Resource = 'SomeResource', @Resource = 'SomeResource' + +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO + +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO + +GO + + +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +EXEC sp_releaseapplock @Resource = 'SomeResource', @Resource = 'SomeResource' + +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO + +GO +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +# Executing test ErrorHandling10000000 + +GO + + + +create procedure ErrorHandling1 as +begin +EXEC sp_releaseapplock @Resource = 'SomeResource', @Resource = 'SomeResource' + +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 + +GO + + + +create procedure ErrorHandling1 as +begin +EXEC sp_releaseapplock @Resource = 'SomeResource', @Resource = 'SomeResource' + +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +# Executing test ErrorHandling10000000 + +GO + + + +begin try +select 1 +EXEC sp_releaseapplock @Resource = 'SomeResource', @Resource = 'SomeResource' + +end try +begin catch + select xact_state(); +end catch + +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO + + diff --git a/contrib/test/JDBC/input/ErrorMapping/8143_2.sql b/contrib/test/JDBC/input/ErrorMapping/8143_2.sql new file mode 100644 index 00000000000..1ae4604bd29 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/8143_2.sql @@ -0,0 +1,201 @@ +# Executing test ErrorHandling1 + +GO + + + +create procedure ErrorHandling1 as +begin +EXEC sp_getapplock @Resource = 'SomeResource', @Resource = 'SomeResource', @LockMode = 'Shared' + +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO + + + +GO + + +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +EXEC sp_getapplock @Resource = 'SomeResource', @Resource = 'SomeResource', @LockMode = 'Shared' + +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO + +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO + +GO + + +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +EXEC sp_getapplock @Resource = 'SomeResource', @Resource = 'SomeResource', @LockMode = 'Shared' + +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO + +GO +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +# Executing test ErrorHandling10000000 + +GO + + + +create procedure ErrorHandling1 as +begin +EXEC sp_getapplock @Resource = 'SomeResource', @Resource = 'SomeResource', @LockMode = 'Shared' + +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 + +GO + + + +create procedure ErrorHandling1 as +begin +EXEC sp_getapplock @Resource = 'SomeResource', @Resource = 'SomeResource', @LockMode = 'Shared' + +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +# Executing test ErrorHandling10000000 + +GO + + + +begin try +select 1 +EXEC sp_getapplock @Resource = 'SomeResource', @Resource = 'SomeResource', @LockMode = 'Shared' + +end try +begin catch + select xact_state(); +end catch + +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO + + diff --git a/contrib/test/JDBC/input/ErrorMapping/8152_1.sql b/contrib/test/JDBC/input/ErrorMapping/8152_1.sql new file mode 100644 index 00000000000..9d85e93ca99 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/8152_1.sql @@ -0,0 +1,207 @@ +# Executing test ErrorHandling1 +CREATE TABLE t8152(a CHAR(5)) +GO + + +create procedure ErrorHandling1 as +begin +INSERT INTO t8152(a) VALUES('123456') + +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t8152 +GO + + + + +CREATE TABLE t8152(a CHAR(5)) +GO + +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +INSERT INTO t8152(a) VALUES('123456') + +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +DROP TABLE t8152 +GO + + + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE t8152(a CHAR(5)) +GO + +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +INSERT INTO t8152(a) VALUES('123456') + +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +DROP TABLE t8152 +GO + + +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +# Executing test ErrorHandling10000000 +CREATE TABLE t8152(a CHAR(5)) +GO + + +create procedure ErrorHandling1 as +begin +INSERT INTO t8152(a) VALUES('123456') + +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t8152 +GO + + + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +CREATE TABLE t8152(a CHAR(5)) +GO + + +create procedure ErrorHandling1 as +begin +INSERT INTO t8152(a) VALUES('123456') + +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t8152 +GO + + + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +# Executing test ErrorHandling10000000 +CREATE TABLE t8152(a CHAR(5)) +GO + + +begin try +select 1 +INSERT INTO t8152(a) VALUES('123456') + +end try +begin catch + select xact_state(); +end catch + +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t8152 +GO + + + + diff --git a/contrib/test/JDBC/input/ErrorMapping/8152_2.sql b/contrib/test/JDBC/input/ErrorMapping/8152_2.sql new file mode 100644 index 00000000000..6f27402c8c1 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/8152_2.sql @@ -0,0 +1,195 @@ +# Executing test ErrorHandling1 +CREATE TABLE t2628(c1 int IDENTITY, c2 varchar(3)) +GO + + +create procedure ErrorHandling1 as +begin +INSERT INTO t2628 VALUES('1234') + +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t2628 +GO + + +CREATE TABLE t2628(c1 int IDENTITY, c2 varchar(3)) +GO + +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +INSERT INTO t2628 VALUES('1234') + +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +DROP TABLE t2628 +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE t2628(c1 int IDENTITY, c2 varchar(3)) +GO + +begin transaction +GO +# Executing test ErrorHandling1 +create procedure ErrorHandling1 as +begin +INSERT INTO t2628 VALUES('1234') + +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO +DROP TABLE t2628 +GO +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +# Executing test ErrorHandling10000000 +CREATE TABLE t2628(c1 int IDENTITY, c2 varchar(3)) +GO + + +create procedure ErrorHandling1 as +begin +INSERT INTO t2628 VALUES('1234') + +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t2628 +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +CREATE TABLE t2628(c1 int IDENTITY, c2 varchar(3)) +GO + + +create procedure ErrorHandling1 as +begin +INSERT INTO t2628 VALUES('1234') + +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end + +GO + +begin transaction; +GO +exec ErrorHandling2; +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t2628 +GO + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +# Executing test ErrorHandling10000000 +CREATE TABLE t2628(c1 int IDENTITY, c2 varchar(3)) +GO + + +begin try +select 1 +INSERT INTO t2628 VALUES('1234') + +end try +begin catch + select xact_state(); +end catch + +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t2628 +GO + + diff --git a/contrib/test/JDBC/input/ErrorMapping/8159_1.sql b/contrib/test/JDBC/input/ErrorMapping/8159_1.sql new file mode 100644 index 00000000000..11a54f38e06 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/8159_1.sql @@ -0,0 +1,40 @@ +-- simple batch start + +GO + + +CREATE VIEW v8159(c1, c2) +AS +SELECT + 'a' AS c1 +GO +DROP VIEW v8159 +GO + +SET XACT_ABORT ON; +GO + +begin transaction +GO +GO + + +CREATE VIEW v8159(c1, c2) +AS +SELECT + 'a' AS c1 +GO + +if (@@trancount > 0) select cast('Does not respect xact_abort flag' as text) else select cast('Respects xact_abort flag' as text) +GO + +if (@@trancount > 0) rollback tran +GO + +DROP VIEW v8159 +GO + +SET XACT_ABORT OFF; +GO + + diff --git a/contrib/test/JDBC/input/ErrorMapping/8179_1.sql b/contrib/test/JDBC/input/ErrorMapping/8179_1.sql new file mode 100644 index 00000000000..7920e29ea43 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/8179_1.sql @@ -0,0 +1,302 @@ +-- simple batch start + +GO + +DECLARE @P1 INT = 12345 +EXEC sp_execute @P1, 1 + +GO +GO + + +begin transaction +GO +GO + +DECLARE @P1 INT = 12345 +EXEC sp_execute @P1, 1 + +GO + +-- Below output is only applicable if query is special case. for example, CREATE/ALTER TRIGGER, CREATE/ALTER FUNCTION, CREATE/ALTER PROC, CREATE/ALTER VIEW etc + +if (@@trancount > 0) select cast('compile time error' as text) else select cast('runtime error' as text) +GO + +if (@@trancount > 0) rollback tran +GO + +GO + + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + +GO + +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +DECLARE @P1 INT = 12345 +EXEC sp_execute @P1, 1 + +end +GO + +GO + + +create table error_mapping.temp2 (a int) +GO + +GO + +insert into error_mapping.temp2 values(1) +DECLARE @P1 INT = 12345 +EXEC sp_execute @P1, 1 + +GO + +GO + + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + +GO + +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO + +GO + + +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 + +-- Parse analysis phase end +GO + +-- compile time error portion + +-- Executing test error_mapping.ErrorHandling1 +GO + + +create procedure error_mapping.ErrorHandling1 as +begin +DECLARE @P1 INT = 12345 +EXEC sp_execute @P1, 1 + +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 +GO + + + +GO + +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +DECLARE @P1 INT = 12345 +EXEC sp_execute @P1, 1 + +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 + +GO +GO + + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +GO + +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +DECLARE @P1 INT = 12345 +EXEC sp_execute @P1, 1 + +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 + +GO +GO + +set xact_abort OFF; +GO + +-- comiple time error portion end -- +-- Next portion is for runtime error -- + +-- Executing test error_mapping.ErrorHandling10000000 +GO + + +create procedure error_mapping.ErrorHandling1 as +begin +DECLARE @P1 INT = 12345 +EXEC sp_execute @P1, 1 + +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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 +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 +GO + + + +set xact_abort ON; +GO +-- Executing test error_mapping.ErrorHandling10000000 +GO + + +create procedure error_mapping.ErrorHandling1 as +begin +DECLARE @P1 INT = 12345 +EXEC sp_execute @P1, 1 + +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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 +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 +GO + + + + +set xact_abort OFF; +GO + +-- Error classification is done -- + +-- Executing test error_mapping.ErrorHandling10000000 +GO + + +begin try +select 1 +DECLARE @P1 INT = 12345 +EXEC sp_execute @P1, 1 + +end try +begin catch + select xact_state(); +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 +GO + + + + +GO +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/input/ErrorMapping/9809_1.sql b/contrib/test/JDBC/input/ErrorMapping/9809_1.sql new file mode 100644 index 00000000000..474b30fbcdb --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/9809_1.sql @@ -0,0 +1,292 @@ +-- simple batch start + +GO + +SELECT CONVERT(DATE, '10-10-10', 140) + +GO +GO + + +begin transaction +GO +GO + +SELECT CONVERT(DATE, '10-10-10', 140) + +GO + +-- Below output is only applicable if query is special case. for example, CREATE/ALTER TRIGGER, CREATE/ALTER FUNCTION, CREATE/ALTER PROC, CREATE/ALTER VIEW etc + +if (@@trancount > 0) select cast('compile time error' as text) else select cast('runtime error' as text) +GO + +if (@@trancount > 0) rollback tran +GO + +GO + + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + +GO + +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +SELECT CONVERT(DATE, '10-10-10', 140) + +end +GO + +GO + + +create table error_mapping.temp2 (a int) +GO + +GO + +insert into error_mapping.temp2 values(1) +SELECT CONVERT(DATE, '10-10-10', 140) + +GO + +GO + + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + +GO + +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO + +GO + + +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 + +-- Parse analysis phase end +GO + +-- compile time error portion + +-- Executing test error_mapping.ErrorHandling1 +GO + + +create procedure error_mapping.ErrorHandling1 as +begin +SELECT CONVERT(DATE, '10-10-10', 140) + +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 +GO + + + +GO + +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +SELECT CONVERT(DATE, '10-10-10', 140) + +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 + +GO +GO + + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +GO + +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +SELECT CONVERT(DATE, '10-10-10', 140) + +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 + +GO +GO + +set xact_abort OFF; +GO + +-- comiple time error portion end -- +-- Next portion is for runtime error -- + +-- Executing test error_mapping.ErrorHandling10000000 +GO + + +create procedure error_mapping.ErrorHandling1 as +begin +SELECT CONVERT(DATE, '10-10-10', 140) + +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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 +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 +GO + + + +set xact_abort ON; +GO +-- Executing test error_mapping.ErrorHandling10000000 +GO + + +create procedure error_mapping.ErrorHandling1 as +begin +SELECT CONVERT(DATE, '10-10-10', 140) + +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end + +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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 +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 +GO + + + + +set xact_abort OFF; +GO + +-- Error classification is done -- + +-- Executing test error_mapping.ErrorHandling10000000 +GO + + +begin try +select 1 +SELECT CONVERT(DATE, '10-10-10', 140) + +end try +begin catch + select xact_state(); +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 +GO + + + + +GO +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/input/ErrorMapping/TestCompileTimeErrorWithDefaultBehave.sql b/contrib/test/JDBC/input/ErrorMapping/TestCompileTimeErrorWithDefaultBehave.sql new file mode 100644 index 00000000000..85fba4bf404 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/TestCompileTimeErrorWithDefaultBehave.sql @@ -0,0 +1,190 @@ +USE master; +GO + +-- This file contains test cases to test un-mapped compile time error against Babelfish server. +GO + +CREATE SCHEMA error_mapping; +GO + +-- Example 1 +GO + +DECLARE @xml XML +SET @xml = CONVERT(XML, '') +SELECT @xml.value('()[1]', 'VARCHAR') + +GO +GO + + +begin transaction +GO +GO + +DECLARE @xml XML +SET @xml = CONVERT(XML, '') +SELECT @xml.value('()[1]', 'VARCHAR') + +GO + +-- Below output is only applicable if query is special case. for example, CREATE/ALTER TRIGGER, CREATE/ALTER FUNCTION, CREATE/ALTER PROC, CREATE/ALTER VIEW etc + +if (@@trancount > 0) select cast('txn is not rolledback' as text) else select cast('txn is rolledback' as text) +GO + +if (@@trancount > 0) rollback tran +GO + +GO + +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +DECLARE @xml XML +SET @xml = CONVERT(XML, '') +SELECT @xml.value('()[1]', 'VARCHAR') + +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 + +GO +GO + + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +GO + +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +DECLARE @xml XML +SET @xml = CONVERT(XML, '') +SELECT @xml.value('()[1]', 'VARCHAR') + +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 + +GO +GO + +set xact_abort OFF; +GO + +-- Example 2 +GO + +DECLARE @xml XML +SET @xml = CONVERT(XML, '') +SELECT @xml.value('(*:)[1]', 'VARCHAR') + +GO +GO + + +begin transaction +GO +GO + +DECLARE @xml XML +SET @xml = CONVERT(XML, '') +SELECT @xml.value('(*:)[1]', 'VARCHAR') + +GO + + +if (@@trancount > 0) select cast('txn is not rolledback' as text) else select cast('txn is rolledback' as text) +GO + +if (@@trancount > 0) rollback tran +GO + +GO + +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +DECLARE @xml XML +SET @xml = CONVERT(XML, '') +SELECT @xml.value('(*:)[1]', 'VARCHAR') + +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 + +GO +GO + + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +GO + +begin transaction +GO +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +DECLARE @xml XML +SET @xml = CONVERT(XML, '') +SELECT @xml.value('(*:)[1]', 'VARCHAR') + +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 + +GO +GO + +set xact_abort OFF; +GO + + +DROP SCHEMA error_mapping; +GO + diff --git a/contrib/test/JDBC/input/ErrorMapping/TestErrorHelperFunctions.sql b/contrib/test/JDBC/input/ErrorMapping/TestErrorHelperFunctions.sql new file mode 100644 index 00000000000..61ebdf1d9d3 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/TestErrorHelperFunctions.sql @@ -0,0 +1,23 @@ +create table testErrorHF(c1 int not null); +insert into testErrorHF values(1); +GO + +begin try + insert into testErrorHF values('abc'); +end try +begin catch + select @@error, @@pgerror; +end catch +GO + +select @@error, @@pgerror; +GO + +insert into testErrorHF values(null); +GO + +select @@error, @@pgerror; +GO + +select * from fn_mapped_system_error_list(); +GO diff --git a/contrib/test/JDBC/input/ErrorMapping/TestRunTimeErrorWithDefaultBehave.sql b/contrib/test/JDBC/input/ErrorMapping/TestRunTimeErrorWithDefaultBehave.sql new file mode 100644 index 00000000000..1462d54cec8 --- /dev/null +++ b/contrib/test/JDBC/input/ErrorMapping/TestRunTimeErrorWithDefaultBehave.sql @@ -0,0 +1,207 @@ +-- This file contains test cases to test un-mapped runtime error against Babelfish server. +GO + +CREATE SCHEMA error_mapping; +GO + +-- Example 1 +GO + +CREATE TABLE t257(c1 binary(10)); +GO +DECLARE @a binary(10); +SET @a = CAST('21' AS char(10)); +SELECT @a +GO +DROP TABLE t257; +GO + +begin transaction +GO +--Pre +CREATE TABLE t257(c1 binary(10)); +GO + +DECLARE @a binary(10); +SET @a = CAST('21' AS char(10)); +SELECT @a +GO + +if (@@trancount > 0) select cast('txn is not rolledback' as text) else select cast('txn is rolledback' as text) +GO + +if (@@trancount > 0) rollback tran +GO + +DROP TABLE t257; +GO + +SET XACT_ABORT ON; +GO + +begin transaction +GO +--Pre +CREATE TABLE t257(c1 binary(10)); +GO + +DECLARE @a binary(10); +SET @a = CAST('21' AS char(10)); +SELECT @a +GO + +if (@@trancount > 0) select cast('txn is not rolledback' as text) else select cast('txn is rolledback' as text) +GO + +if (@@trancount > 0) rollback tran +GO + +DROP TABLE t257; +GO + +SET XACT_ABORT OFF; +GO + + +CREATE TABLE t257(c1 binary(10)); +GO + +create procedure error_mapping.ErrorHandling1 as +begin + begin try + select 1 + DECLARE @a binary(10); + SET @a = CAST('21' AS char(10)); + SELECT @a + end try + begin catch + select xact_state(); + end catch + select @@trancount; +end +GO + +if @@error > 0 select cast('Compile time error' as text); +GO + +begin transaction; +GO + +exec error_mapping.ErrorHandling1; +GO + +if @@trancount > 0 select cast('Txn is not rolledback') +GO + +if @@trancount > 0 rollback transaction; +GO + + +set xact_abort ON; +GO + +exec error_mapping.ErrorHandling1; +GO + +if @@trancount > 0 select cast('Txn is not rolledback') +GO + +if @@trancount > 0 rollback transaction; +GO + +set xact_abort OFF; +GO + +drop procedure error_mapping.ErrorHandling1; +GO + +DROP TABLE t257; +GO + +-- Example 2 +GO + +SELECT DATEPART(xyz, CAST('2012-12-12' AS date)); +GO + +begin transaction +GO + +SELECT DATEPART(xyz, CAST('2012-12-12' AS date)); +GO + +if (@@trancount > 0) select cast('txn is not rolledback' as text) else select cast('txn is rolledback' as text) +GO + +if (@@trancount > 0) rollback tran +GO + +SET XACT_ABORT ON; +GO + +begin transaction +GO + +SELECT DATEPART(xyz, CAST('2012-12-12' AS date)); +GO + +if (@@trancount > 0) select cast('txn is not rolledback' as text) else select cast('txn is rolledback' as text) +GO + +if (@@trancount > 0) rollback tran +GO + +SET XACT_ABORT OFF; +GO + +create procedure error_mapping.ErrorHandling1 as +begin + begin try + select 1 + SELECT DATEPART(xyz, CAST('2012-12-12' AS date)); + end try + begin catch + select xact_state(); + end catch + select @@trancount; +end +GO + +if @@error > 0 select cast('Compile time error' as text) +GO + +begin transaction; +GO + +exec error_mapping.ErrorHandling1; +GO + +if @@trancount > 0 select cast('txn is not rolledback' as text) +GO + +if @@trancount > 0 rollback tran; +GO + +set xact_abort ON; +GO + +begin transaction; +GO + +exec error_mapping.ErrorHandling1; +GO + +if @@trancount > 0 select cast('txn is not rolledback' as text) +GO + +if @@trancount > 0 rollback tran; +GO + +set xact_abort OFF; +GO + +drop procedure error_mapping.ErrorHandling1; +GO + +DROP SCHEMA error_mapping; +GO \ No newline at end of file diff --git a/contrib/test/JDBC/input/TestNotNull.txt b/contrib/test/JDBC/input/TestNotNull.txt new file mode 100644 index 00000000000..e86986b6dea --- /dev/null +++ b/contrib/test/JDBC/input/TestNotNull.txt @@ -0,0 +1,260 @@ +# int +Create table sourceTable(a int, b int not null) +prepst#!# INSERT INTO sourceTable(a, b) values(@a, @b) #!#int|-|a|-|2#!#int|-|b|-|2 +prepst#!#exec#!#int|-|a|-|#!#int|-|b|-|3 +Select * from sourceTable +Insert into sourceTable values (1, 1); +Insert into sourceTable values (NULL, 1); +Select * from sourceTable +drop table sourceTable + +# smallint +Create table sourceTable(a smallint, b smallint not null) +prepst#!# INSERT INTO sourceTable(a, b) values(@a, @b) #!#smallint|-|a|-|2#!#smallint|-|b|-|2 +prepst#!#exec#!#smallint|-|a|-|#!#smallint|-|b|-|3 +Select * from sourceTable +Insert into sourceTable values (1, 1); +Insert into sourceTable values (NULL, 1); +Select * from sourceTable +drop table sourceTable + +# bigint +Create table sourceTable(a bigint, b bigint not null) +prepst#!# INSERT INTO sourceTable(a, b) values(@a, @b) #!#bigint|-|a|-|2#!#bigint|-|b|-|2 +prepst#!#exec#!#bigint|-|a|-|#!#bigint|-|b|-|3 +Select * from sourceTable +Insert into sourceTable values (1, 1); +Insert into sourceTable values (NULL, 1); +Select * from sourceTable +drop table sourceTable + +# bit +Create table sourceTable(a bit, b bit not null) +prepst#!# INSERT INTO sourceTable(a, b) values(@a, @b) #!#bit|-|a|-|true#!#bit|-|b|-|false +prepst#!#exec#!#bit|-|a|-|#!#bit|-|b|-|true +Select * from sourceTable +Insert into sourceTable values (1, 1); +Insert into sourceTable values (NULL, 1); +Select * from sourceTable +drop table sourceTable + +# float +Create table sourceTable(a float, b float not null) +prepst#!# INSERT INTO sourceTable(a, b) values(@a, @b) #!#float|-|a|-|2.00#!#float|-|b|-|2.01 +prepst#!#exec#!#float|-|a|-|#!#float|-|b|-|2.20 +Select * from sourceTable +Insert into sourceTable values (1.1101, 0.00010); +Insert into sourceTable values (NULL, 1); +Select * from sourceTable +drop table sourceTable + +# real +Create table sourceTable(a real, b real not null) +prepst#!# INSERT INTO sourceTable(a, b) values(@a, @b) #!#real|-|a|-|2.00#!#real|-|b|-|2.01 +prepst#!#exec#!#real|-|a|-|#!#real|-|b|-|2.20 +Select * from sourceTable +Insert into sourceTable values (1.1101, 0.00010); +Insert into sourceTable values (NULL, 1); +Select * from sourceTable +drop table sourceTable + +# char +Create table sourceTable(a char(10), b char(10) not null) +prepst#!# INSERT INTO sourceTable(a, b) values(@a, @b) #!#char|-|a|-|hello#!#char|-|b|-|jello +prepst#!#exec#!#char|-|a|-|#!#char|-|b|-|mellow +Select * from sourceTable +Insert into sourceTable values ('hello', 'jello'); +Insert into sourceTable values (NULL, 'jello'); +Select * from sourceTable +drop table sourceTable + +# nchar +Create table sourceTable(a nchar(10), b nchar(10) not null) +prepst#!# INSERT INTO sourceTable(a, b) values(@a, @b) #!#nchar|-|a|-|hello#!#nchar|-|b|-|jello +prepst#!#exec#!#nchar|-|a|-|#!#nchar|-|b|-|mellow +Select * from sourceTable +Insert into sourceTable values ('hello', 'jello'); +Insert into sourceTable values (NULL, 'jello'); +Select * from sourceTable +drop table sourceTable + +# varchar +Create table sourceTable(a varchar(10), b varchar(10) not null) +prepst#!# INSERT INTO sourceTable(a, b) values(@a, @b) #!#varchar|-|a|-|hello#!#varchar|-|b|-|jello +prepst#!#exec#!#varchar|-|a|-|#!#varchar|-|b|-|mellow +Select * from sourceTable +Insert into sourceTable values ('hello', 'jello'); +Insert into sourceTable values (NULL, 'jello'); +Select * from sourceTable +drop table sourceTable + +# nvarchar +Create table sourceTable(a nvarchar(10), b nvarchar(10) not null) +prepst#!# INSERT INTO sourceTable(a, b) values(@a, @b) #!#nvarchar|-|a|-|hello#!#nvarchar|-|b|-|jello +prepst#!#exec#!#nvarchar|-|a|-|#!#nvarchar|-|b|-|mellow +Select * from sourceTable +Insert into sourceTable values ('hello', 'jello'); +Insert into sourceTable values (NULL, 'jello'); +Select * from sourceTable +drop table sourceTable + +# text +Create table sourceTable(a text, b text not null) +prepst#!# INSERT INTO sourceTable(a, b) values(@a, @b) #!#text|-|a|-|utils/sample.txt#!#text|-|b|-|utils/sample.txt +prepst#!#exec#!#text|-|a|-|#!#text|-|b|-|utils/sample.txt +Select * from sourceTable +Insert into sourceTable values ('hello', 'jello'); +Insert into sourceTable values (NULL, 'jello'); +Select * from sourceTable +drop table sourceTable + +# ntext +Create table sourceTable(a ntext, b ntext not null) +prepst#!# INSERT INTO sourceTable(a, b) values(@a, @b) #!#ntext|-|a|-|utils/sample.txt#!#ntext|-|b|-|utils/sample.txt +prepst#!#exec#!#ntext|-|a|-|#!#ntext|-|b|-|utils/sample.txt +Select * from sourceTable +Insert into sourceTable values ('hello', 'jello'); +Insert into sourceTable values (NULL, 'jello'); +Select * from sourceTable +drop table sourceTable + +# binary +Create table sourceTable(a binary(10), b binary(10) not null) +prepst#!# INSERT INTO sourceTable(a, b) values(@a, @b) #!#binary|-|a|-|0x31323334#!#binary|-|b|-|0x9241 +prepst#!#exec#!#binary|-|a|-|#!#binary|-|b|-|0x9241 +Select * from sourceTable +Insert into sourceTable values (0x31323334, 0x9241); +Insert into sourceTable values (NULL, 0x9241); +Select * from sourceTable +drop table sourceTable + +# varbinary +Create table sourceTable(a varbinary(10), b varbinary(10) not null) +prepst#!# INSERT INTO sourceTable(a, b) values(@a, @b) #!#varbinary|-|a|-|0x31323334#!#varbinary|-|b|-|0x9241 +prepst#!#exec#!#varbinary|-|a|-|#!#varbinary|-|b|-|0x9241 +Select * from sourceTable +Insert into sourceTable values (0x31323334, 0x9241); +Insert into sourceTable values (NULL, 0x9241); +Select * from sourceTable +drop table sourceTable + +# numeric +Create table sourceTable(a numeric(38, 22), b numeric(38, 22) not null) +prepst#!# INSERT INTO sourceTable(a, b) values(@a, @b) #!#numeric|-|a|-|1.1101#!#numeric|-|b|-|1.1101 +prepst#!#exec#!#numeric|-|a|-|#!#numeric|-|b|-|0.00 +Select * from sourceTable +Insert into sourceTable values (1.1101, 0.00010); +Insert into sourceTable values (NULL, 0.00010); +Select * from sourceTable +drop table sourceTable + +# decimal +Create table sourceTable(a decimal(38, 22), b decimal(38, 22) not null) +prepst#!# INSERT INTO sourceTable(a, b) values(@a, @b) #!#decimal|-|a|-|1.1101#!#decimal|-|b|-|1.1101 +prepst#!#exec#!#decimal|-|a|-|#!#decimal|-|b|-|1.1101 +Select * from sourceTable +Insert into sourceTable values (1.1101, 0.00010); +Insert into sourceTable values (NULL, 0.00010); +Select * from sourceTable +drop table sourceTable + +# money +Create table sourceTable(a money, b money not null) +prepst#!# INSERT INTO sourceTable(a, b) values(@a, @b) #!#money|-|a|-|100.11#!#money|-|b|-|100.11 +prepst#!#exec#!#money|-|a|-|#!#money|-|b|-|100.11 +Select * from sourceTable +Insert into sourceTable values (100.11, 0.10); +Insert into sourceTable values (NULL, 0.10); +Select * from sourceTable +drop table sourceTable + +# smallmoney +Create table sourceTable(a smallmoney, b smallmoney not null) +prepst#!# INSERT INTO sourceTable(a, b) values(@a, @b) #!#smallmoney|-|a|-|0.10#!#smallmoney|-|b|-|0.10 +prepst#!#exec#!#smallmoney|-|a|-|#!#smallmoney|-|b|-|0.10 +Select * from sourceTable +Insert into sourceTable values (100.11, 0.10); +Insert into sourceTable values (NULL, 0.10); +Select * from sourceTable +drop table sourceTable + +# uniqueidentifier +Create table sourceTable(a uniqueidentifier, b uniqueidentifier not null) +prepst#!# INSERT INTO sourceTable(a, b) values(@a, @b) #!#uniqueidentifier|-|a|-|51f178a6-53c7-472c-9be1-1c08942342d7#!#uniqueidentifier|-|b|-|51f178a6-53c7-472c-9be1-1c08942342d7 +prepst#!#exec#!#uniqueidentifier|-|a|-|#!#uniqueidentifier|-|b|-|51f178a6-53c7-472c-9be1-1c08942342d7 +Select * from sourceTable +Insert into sourceTable values ('51f178a6-53c7-472c-9be1-1c08942342d7', 'dd8cb046-461d-411e-be40-d219252ce849'); +Insert into sourceTable values (NULL, 'dd8cb046-461d-411e-be40-d219252ce849'); +Select * from sourceTable +drop table sourceTable + +# date +Create table sourceTable(a date, b date not null) +prepst#!# INSERT INTO sourceTable(a, b) values(@a, @b) #!#date|-|a|-|2000-02-28#!#date|-|b|-|2000-02-28 +prepst#!#exec#!#date|-|a|-|#!#date|-|b|-|2000-02-28 +Select * from sourceTable +Insert into sourceTable values ('2000-02-28', '0001-01-01'); +Insert into sourceTable values (NULL, '0001-01-01'); +Select * from sourceTable +drop table sourceTable + +# time +Create table sourceTable(a time(6), b time(6) not null) +prepst#!# INSERT INTO sourceTable(a, b) values(@a, @b) #!#time|-|a|-|12:45:37.123#!#time|-|b|-|12:45:37.123 +prepst#!#exec#!#time|-|a|-|#!#time|-|b|-|12:45:37.123 +Select * from sourceTable +Insert into sourceTable values ('12:45:37.123', '12:45:37.12'); +Insert into sourceTable values (NULL, '12:45:37.12'); +Select * from sourceTable +drop table sourceTable + +# datetime +Create table sourceTable(a datetime, b datetime not null) +prepst#!# INSERT INTO sourceTable(a, b) values(@a, @b) #!#datetime|-|a|-|2000-12-13 12:58:23.123#!#datetime|-|b|-|2000-12-13 12:58:23.123 +prepst#!#exec#!#datetime|-|a|-|#!#datetime|-|b|-|2000-12-13 12:58:23.123 +Select * from sourceTable +Insert into sourceTable values ('2000-12-13 12:58:23.123', '1900-02-28 23:59:59.989'); +Insert into sourceTable values (NULL, '1900-02-28 23:59:59.989'); +Select * from sourceTable +drop table sourceTable + +# smalldatetime +Create table sourceTable(a smalldatetime, b smalldatetime not null) +prepst#!# INSERT INTO sourceTable(a, b) values(@a, @b) #!#smalldatetime|-|a|-|2007-05-08 12:35:29#!#smalldatetime|-|b|-|2007-05-08 12:35:29 +prepst#!#exec#!#smalldatetime|-|a|-|#!#smalldatetime|-|b|-|2007-05-08 12:35:29 +Select * from sourceTable +Insert into sourceTable values ('2007-05-08 12:35:29', '2000-12-13 12:58:23'); +Insert into sourceTable values (NULL, '2000-12-13 12:58:23'); +Select * from sourceTable +drop table sourceTable + +# datetime2 +Create table sourceTable(a Datetime2(6), b Datetime2(6) not null) +prepst#!# INSERT INTO sourceTable(a, b) values(@a, @b) #!#Datetime2|-|a|-|2016-10-23 12:45:37.123|-|6#!#Datetime2|-|b|-|2016-10-23 12:45:37.123|-|6 +prepst#!#exec#!#Datetime2|-|a|-|#!#Datetime2|-|b|-|2016-10-23 12:45:37.123|-|6 +Select * from sourceTable +Insert into sourceTable values ('2016-10-23 12:45:37.123', '2016-10-23 12:45:37.123'); +Insert into sourceTable values (NULL, '2016-10-23 12:45:37.123'); +Select * from sourceTable +drop table sourceTable + +# datetimeoffset +Create table sourceTable(a datetimeoffset(6), b datetimeoffset(6) not null) +prepst#!# INSERT INTO sourceTable(a, b) values(@a, @b) #!#datetimeoffset|-|a|-|2016-10-23 12:24:32|-|6#!#datetimeoffset|-|b|-|2016-10-23 12:24:32|-|6 +prepst#!#exec#!#datetimeoffset|-|a|-|#!#datetimeoffset|-|b|-|2016-10-23 12:24:32|-|6 +Select * from sourceTable +Insert into sourceTable values ('2016-10-23 12:24:32 +10:0', '2016-10-23 12:24:32 +10:0'); +Insert into sourceTable values (NULL, '2016-10-23 12:24:32 +10:0'); +Select * from sourceTable +drop table sourceTable + +# sql_variant +Create table sourceTable(a sql_variant, b sql_variant not null) +prepst#!# INSERT INTO sourceTable(a, b) values(@a, @b) #!#bit|-|a|-|#!#int|-|b|-|2 +prepst#!#exec#!#bit|-|a|-|0#!#bit|-|b|-|1 +Select * from sourceTable +Insert into sourceTable values (cast (1 as int), cast ('abc' as varchar(10))); +Insert into sourceTable values (NULL, cast ('abc' as varchar(10))); +Select * from sourceTable +drop table sourceTable + diff --git a/contrib/test/JDBC/input/authentication/TestAuth.txt b/contrib/test/JDBC/input/authentication/TestAuth.txt new file mode 100644 index 00000000000..3e65de42fdd --- /dev/null +++ b/contrib/test/JDBC/input/authentication/TestAuth.txt @@ -0,0 +1,18 @@ +#database name, username and password should not exceed 128 characters +java_auth#!#database|-|11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +java_auth#!#database|-|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112 +java_auth#!#user|-|11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +java_auth#!#user|-|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112 +#database and user name arguments are case-insensitive +java_auth#!#database|-|MASTER +java_auth#!#database|-|MaStEr +java_auth#!#user|-|JDBC_USER +java_auth#!#user|-|JdBc_UsEr +#not sure why any password is accepted during authentication through cloud desktop +#This test should throw error but from cloud desktop a connection is successfully established +#java_auth#!#password|-|11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +java_auth#!#password|-|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112 +java_auth#!#others|-|packetSize=0 +java_auth#!#others|-|packetSize=-1 +java_auth#!#others|-|packetSize=4096 +java_auth#!#database|-|test1 SELECT 1 diff --git a/contrib/test/JDBC/input/babel_613.sql b/contrib/test/JDBC/input/babel_613.sql new file mode 100644 index 00000000000..4c09aa5e779 --- /dev/null +++ b/contrib/test/JDBC/input/babel_613.sql @@ -0,0 +1,81 @@ +use master +go + +create table t1 (a numeric(6,4), b numeric(6,3)); +insert into t1 values (4, 16); +insert into t1 values (10.1234, 10.123); +insert into t1 values (1.2, 6); +insert into t1 values (NULL, 101.123); +go + +-- test selection of numeric Var +select * from t1; +go + +-- test operations on numeric var +select a+b, a-b, a*b, a/b, +a, -a from t1; +go + +-- test functions that returns numeric value +select round(a, 2) from t1; +go + +select power(a, b) from t1; +go + +select sqrt(a) from t1; +go + +select abs(a) from t1; +go + +-- test overflow error, max precision is 38 for TSQL client. +-- BABEL-2656 +select power(10.0, 100); +go + +-- test Nullif expression +select nullif(a, b) from t1; +go + +-- test Param expr +select (select 1.234); +go + +-- test case expr +select a, b, +case when a>5 then a + when a<=5 then b +end + from t1; +go + +-- test Aggref expr +select min(a), max(a), min(b), max(b) from t1; +go + +-- test Coalesece expr +-- BABEL-2656 +select coalesce(a, b) from t1; +go + +-- test Union All +select a from t1 Union All +select b from t1; +go + +-- test overflow from multiplication of columns +create table t2 (a numeric(38, 1), b numeric(38, 1)) +insert into t1 values (1234567890123456789012345678901234567.1), (1234567890123456789012345678901234567.2) +go + +select * from t2 +go + +select a * b from t2; +go + +-- clean up +drop table t1; +drop table t2; +go diff --git a/contrib/test/JDBC/input/babel_bit_comp.sql b/contrib/test/JDBC/input/babel_bit_comp.sql new file mode 100644 index 00000000000..3ec7c56abe1 --- /dev/null +++ b/contrib/test/JDBC/input/babel_bit_comp.sql @@ -0,0 +1,94 @@ +CREATE TABLE t1 (a bit, b int); +GO +INSERT INTO t1 VALUES (1, 1); +GO +INSERT INTO t1 VALUES (0, 0); +GO + +SELECT a FROM t1 WHERE a = 0; +GO +SELECT a FROM t1 WHERE a = 1; +GO +SELECT a FROM t1 WHERE a = -1; +GO + +SELECT a FROM t1 WHERE a <> 0; +GO +SELECT a FROM t1 WHERE a <> 1; +GO +SELECT a FROM t1 WHERE a <> -1; +GO + +SELECT a FROM t1 WHERE a > 0; +GO +SELECT a FROM t1 WHERE a > 1; +GO +SELECT a FROM t1 WHERE a > -1; +GO + +SELECT a FROM t1 WHERE a >= 0 ORDER BY b; +GO +SELECT a FROM t1 WHERE a >= 1; +GO +SELECT a FROM t1 WHERE a >= -1; +GO + +SELECT a FROM t1 WHERE a < 0; +GO +SELECT a FROM t1 WHERE a < 1; +GO +SELECT a FROM t1 WHERE a < -1; +GO + +SELECT a FROM t1 WHERE a <= 0; +GO +SELECT a FROM t1 WHERE a <= 1 ORDER BY b; +GO +SELECT a FROM t1 WHERE a <= -1 ORDER BY b; +GO + +CREATE TABLE t2 ( a INT); +GO +INSERT INTO t2 VALUES (1); +GO +INSERT INTO t2 VALUES (0); +GO +INSERT INTO t2 VALUES (-1); +GO + +SELECT a FROM t2 WHERE a = CAST(0 AS bit); +GO +SELECT a FROM t2 WHERE a = CAST(1 AS bit) ORDER BY a; +GO + +SELECT a FROM t2 WHERE a <> CAST(0 AS bit) ORDER BY a; +GO +SELECT a FROM t2 WHERE a <> CAST(1 AS bit); +GO + +SELECT a FROM t2 WHERE a > CAST(0 AS bit) ORDER BY a; +GO +SELECT a FROM t2 WHERE a > CAST(1 AS bit); +GO + +SELECT a FROM t2 WHERE a >= CAST(0 AS bit) ORDER BY a; +GO +SELECT a FROM t2 WHERE a >= CAST(1 AS bit) ORDER BY a; +GO + +SELECT a FROM t2 WHERE a < CAST(0 AS bit); +GO +SELECT a FROM t2 WHERE a < CAST(1 AS bit); +GO + +SELECT a FROM t2 WHERE a <= CAST(0 AS bit); +GO +SELECT a FROM t2 WHERE a <= CAST(1 AS bit) ORDER BY a; +GO + +reset babelfishpg_tsql.sql_dialect; +GO +DROP TABLE t1; +GO +DROP TABLE t2; +GO diff --git a/contrib/test/JDBC/input/babel_ceiling_floor.sql b/contrib/test/JDBC/input/babel_ceiling_floor.sql new file mode 100644 index 00000000000..3860bdace18 --- /dev/null +++ b/contrib/test/JDBC/input/babel_ceiling_floor.sql @@ -0,0 +1,94 @@ +-- +-- Tests for ISNUMERIC function +-- + +DROP TABLE IF EXISTS test_table +GO + +CREATE TABLE test_table ( + bigint_type bigint, + int_type int, + smallint_type smallint, + tinyint_type tinyint, + bit_type bit, + decimal_type decimal(5,2), + numeric_type numeric(10,5), + float_type float) +GO + +INSERT INTO test_table ( + bigint_type, + int_type, + smallint_type, + tinyint_type, + bit_type, + decimal_type, + numeric_type, + float_type) +VALUES ( + 9223372036854775806, + 45000, + -32767, + 100, + 1, + 123.456, + 12345.12, + 1.79E+30 +) +GO + +-- Check correctness of values for floor function +SELECT + floor(bigint_type), + floor(int_type), + floor(smallint_type), + floor(tinyint_type), + floor(bit_type), + floor(decimal_type), + floor(numeric_type), + floor(float_type) +FROM test_table +GO + +-- Check correctness of return types for floor function +SELECT + cast(pg_typeof(floor(bigint_type)) as varchar(10)), + cast(pg_typeof(floor(int_type)) as varchar(10)), + cast(pg_typeof(floor(smallint_type)) as varchar(10)), + cast(pg_typeof(floor(tinyint_type)) as varchar(10)), + cast(pg_typeof(floor(bit_type)) as varchar(10)), + cast(pg_typeof(floor(decimal_type)) as varchar(10)), + cast(pg_typeof(floor(numeric_type)) as varchar(10)), + cast(pg_typeof(floor(float_type)) as varchar(10)) +FROM test_table +GO + +-- Check correctness of values for ceiling function +SELECT + ceiling(bigint_type), + ceiling(int_type), + ceiling(smallint_type), + ceiling(tinyint_type), + ceiling(bit_type), + ceiling(decimal_type), + ceiling(numeric_type), + ceiling(float_type) +FROM test_table +GO + +-- Check correctness of return types for ceiling function +SELECT + cast(pg_typeof(ceiling(bigint_type)) as varchar(10)), + cast(pg_typeof(ceiling(int_type)) as varchar(10)), + cast(pg_typeof(ceiling(smallint_type)) as varchar(10)), + cast(pg_typeof(ceiling(tinyint_type)) as varchar(10)), + cast(pg_typeof(ceiling(bit_type)) as varchar(10)), + cast(pg_typeof(ceiling(decimal_type)) as varchar(10)), + cast(pg_typeof(ceiling(numeric_type)) as varchar(10)), + cast(pg_typeof(ceiling(float_type)) as varchar(10)) +FROM test_table +GO + +--Cleanup +DROP TABLE test_table +GO \ No newline at end of file diff --git a/contrib/test/JDBC/input/babel_char.sql b/contrib/test/JDBC/input/babel_char.sql new file mode 100644 index 00000000000..589e631d200 --- /dev/null +++ b/contrib/test/JDBC/input/babel_char.sql @@ -0,0 +1,18 @@ +select nchar(65); +select nchar(0x1); +select nchar(1) + nchar(2); +select nchar(66) + nchar(0x43); +select nchar(0x55) + nchar(0x103); +GO + +-- 0x10FFFF is max value for nchar if the database supports the SC flag +-- See SQL Server documentation for more details +select nchar(1114111); +select nchar(0x10FFFF); +GO + +select nchar(1114112); +select nchar(0x110000); +select nchar(0); +select nchar(-1); +GO \ No newline at end of file diff --git a/contrib/test/JDBC/input/babel_collation.sql b/contrib/test/JDBC/input/babel_collation.sql new file mode 100644 index 00000000000..1e45b68dc6a --- /dev/null +++ b/contrib/test/JDBC/input/babel_collation.sql @@ -0,0 +1,31 @@ +create table testing_collation (col varchar(20)); +go +insert into testing_collation values ('JONES'); +insert into testing_collation values ('jones'); +insert into testing_collation values ('Jones'); +insert into testing_collation values ('JoNes'); +insert into testing_collation values ('JoNés'); +go +select * from testing_collation where col collate SQL_Latin1_General_CP1_CS_AS = 'JoNes'; +go + +select * from testing_collation where col collate SQL_Latin1_General_CP1_CI_AS = 'JoNes'; +go + +select * from testing_collation where col collate SQL_Latin1_General_CP1_CI_AI = 'JoNes'; +go + +-- all the currently supported TSQL collations +SELECT * from fn_helpcollations(); +go + +-- BABEL-1697 Collation and Codepage information for DMS +SELECT CAST( COLLATIONPROPERTY(Name, 'CodePage') AS INT) FROM fn_helpcollations() where Name = DATABASEPROPERTYEX('template1', 'Collation'); +go + +SELECT CAST( COLLATIONPROPERTY(Name, 'lcid') AS INT) FROM fn_helpcollations() where Name = DATABASEPROPERTYEX('template1', 'Collation'); +go + +-- clean up +drop table testing_collation; +go diff --git a/contrib/test/JDBC/input/babel_iif.sql b/contrib/test/JDBC/input/babel_iif.sql new file mode 100644 index 00000000000..41dbe6ef838 --- /dev/null +++ b/contrib/test/JDBC/input/babel_iif.sql @@ -0,0 +1,35 @@ +select iif (2 < 1, cast('2020-10-20 09:00:00' as datetime), cast('2020-10-21' as date)); +go +select iif (2 > 1, cast('abc' as varchar(3)), cast('cba' as char(3))); +go +select iif (2 > 1, cast(3.14 as float), cast(31.4 as numeric(3, 1))); +go +select iif (2 > 1, cast(3.14 as float), cast(1 as int)); +go +select iif (2 > 1, cast('$123.123' as money), cast(1 as int)); +go +select iif (2 > 1, cast('$123.123' as money), cast(3.14 as float)); +go +select iif (2 > 1, cast('2020-10-20 09:00:00' as datetime), cast('09:00:00' as time)); +go +select iif (2 > 1, cast('$123.123' as money), cast(321 as bigint)); +go +select iif (2 > 1, cast(3.14 as float), cast('$123.123' as money)); +go + +-- Error, unknown literal cannot fit target type typinput func +select iif (2 > 1, 1, 'abc'); +go +-- Error, different categories +select iif (2 > 1, cast(1 as int), cast('abc' as varchar(3))); +go +select iif (2 > 1, cast(0 as bit), cast(1 as int)); +go + +-- Null handling +select iif (2 > 1, null, 0); +go +select iif (null, 1, 0); +go +select iif (null, null, null); +go diff --git a/contrib/test/JDBC/input/babel_isnull.mix b/contrib/test/JDBC/input/babel_isnull.mix new file mode 100644 index 00000000000..de22de53032 --- /dev/null +++ b/contrib/test/JDBC/input/babel_isnull.mix @@ -0,0 +1,124 @@ +-- tsql +CREATE TABLE test_numeric ( + num1 int, + num2 numeric +); +INSERT INTO test_numeric(num1, num2) +VALUES + (10, NULL), + (20, 2000), + (30, 3000), + (NULL, 4000), + (50, NULL); +GO + +-- psql currentSchema=master_dbo,public +SELECT * FROM test_numeric; +GO + +SELECT ISNULL(SUM(num1 - ISNULL(num2, 0)), 0) +FROM test_numeric +GO + +-- tsql +-- Prove that a user may replace null values with a specified value using ISNULL +SELECT ISNULL(SUM(num1 - ISNULL(num2, 0)), 0) +FROM test_numeric +GO + +DROP TABLE test_numeric +GO + +-- Test cases with timestamps and sub-queries inside ISNULL +CREATE TABLE test_timestamp ( + serial_no numeric, + ts datetime2, +) +GO + +INSERT INTO test_timestamp(serial_no, ts) +VALUES + (1, NULL), + (2, '2020-06-22 00:10:00'), + (3, '2020-07-23 00:10:00'), + (4, '2020-08-24 00:10:00'), + (5, NULL), + (6, '2020-09-25 00:10:00') +GO + +SELECT * FROM test_timestamp +GO + +SELECT ISNULL(ts, '2021-01-01 00:00:00') +FROM test_timestamp +GO + +CREATE TABLE default_time ( + ts datetime2 +) +GO + +INSERT INTO default_time(ts) VALUES('1970-01-01 00:00:00') +GO + +SELECT ISNULL(ts, (SELECT ts FROM default_time)) +FROM test_timestamp +GO + +DROP TABLE test_timestamp +GO +DROP TABLE default_time +GO + +-- Test cases with characters and casts +CREATE TABLE test_char ( + name varchar(20), + employee_type numeric, + age numeric +) +GO + +INSERT INTO test_char(name, employee_type, age) +VALUES + ('John', 1, 45), + (NULL, 0, 21), + ('Jake', 3, 33), + ('Jack', 1, 64), + ('Jane', NULL, 51) +GO + +SELECT * FROM test_char +GO + +SELECT ISNULL(name, 'Unknown'), ISNULL(employee_type, 'N/A'), age +FROM test_char +GO + +DROP TABLE test_char +GO + +-- Test cases for incorrect number of arguments +CREATE TABLE test_args ( + word char(10) +) +GO +INSERT INTO test_args(word) +VALUES + ('hello'), + (NULL), + ('goodbye') +GO + +SELECT ISNULL() from test_args +GO +SELECT ISNULL(word) FROM test_args +GO +SELECT ISNULL(word, 'no', 'yes') FROM test_args +GO + +-- Test case for varbinary +SELECT ISNULL(null, CAST(0xfe AS VARBINARY)) +GO + +DROP TABLE test_args +GO diff --git a/contrib/test/JDBC/input/babel_money.sql b/contrib/test/JDBC/input/babel_money.sql new file mode 100644 index 00000000000..661c16587c4 --- /dev/null +++ b/contrib/test/JDBC/input/babel_money.sql @@ -0,0 +1,199 @@ +SELECT set_config('extra_float_digits', '0', 'false') +go + +-- test money operators return type money +create table t1(a money, b smallmoney); +insert into t1 values (1.1234, 2.1234); +insert into t1 values (2.5678, 3.5678); +insert into t1 values (4.9012, 5.9012); +go + +select * from t1 order by a; +go + +-- test implicit casting for money +create table t2(a money, b smallmoney); +insert into t2 values (CAST( '1.1234' AS CHAR(10)), CAST( '2.1234' AS CHAR(10))); +insert into t2 values (CAST( '$2.56789' AS VARCHAR), CAST( '$3.56789' AS VARCHAR)); +insert into t2 values (CAST( '¥4.91' AS TEXT), CAST( '¥5.91' AS TEXT)); +insert into t2 values (CAST( '0006.' AS TEXT), CAST( '0000' AS TEXT)); +go + +select * from t2 order by a; +go + +select sum(a), sum(b) from t1; +go + +select cast(pg_typeof(sum(a)) AS VARCHAR(10)), cast(pg_typeof(sum(b)) AS VARCHAR(10)) from t1; +go + +select avg(a), avg(b) from t1; +go + +select cast(pg_typeof(avg(a)) AS VARCHAR(10)), cast(pg_typeof(avg(b)) AS VARCHAR(10)) from t1; +go + +select a+b from t1 order by a; +go + +select cast(pg_typeof(a+b) AS VARCHAR(10)) from t1 order by a; +go + +select b-a from t1 order by a; +go + +select cast(pg_typeof(b-a) AS VARCHAR(10)) from t1 order by a; +go + +select a*b from t1 order by a; +go + +select cast(pg_typeof(a*b) AS VARCHAR(10)) from t1 order by a; +go + +select a/b from t1 order by a; +go + +select cast(pg_typeof(a/b) AS VARCHAR(10)) from t1 order by a; +go + +drop table t1, t2; + +-- BABEL-598 Money type as procedure parameter should work without explicit cast +create table employees(pers_id int, fname nvarchar(20), lname nvarchar(30), sal money); +go + +create procedure p_employee_select +as +begin + select * from employees +end; +go + +create procedure p_employee_insert +@pers_id int, @fname nvarchar(20), @lname nvarchar(30), @sal money +as +begin + insert into employees values (@pers_id, @fname, @lname, @sal) +end; +go + +-- test const 123.1234 and 200 are valid MONEY inputs for the procedure without explicit cast +execute p_employee_insert @pers_id=1, @fname='John', @lname='Johnson', @sal=123.1234; +execute p_employee_insert @pers_id=1, @fname='Adam', @lname='Smith', @sal=200; +go + +execute p_employee_select; +go + +drop procedure p_employee_select; +drop procedure p_employee_insert; +drop table employees; +go + +-- BABEL-920 +-- Test operations(e.g. +,-,*,/) between fixeddecimal(money/smallmoney) and int8(bigint) +select CAST(2.56 as bigint) + CAST(3.60 as money); +go +select CAST(3.60 as money) + CAST(2.56 as bigint); +go +select CAST(2.56 as bigint) - CAST(3.60 as money); +go +select CAST(3.60 as money) - CAST(2.56 as bigint); +go +select CAST(2.56 as bigint) * CAST(3.60 as money); +go +select CAST(3.60 as money) * CAST(2.56 as bigint); +go +select CAST(2.56 as bigint) / CAST(3.60 as money); +go +select CAST(3.60 as money) / CAST(2.56 as bigint); +go + +select CAST(2.56 as bigint) + CAST(3.60 as smallmoney); +go +select CAST(3.60 as smallmoney) + CAST(2.56 as bigint); +go +select CAST(2.56 as bigint) - CAST(3.60 as smallmoney); +go +select CAST(3.60 as smallmoney) - CAST(2.56 as bigint); +go +select CAST(2.56 as bigint) * CAST(3.60 as smallmoney); +go +select CAST(3.60 as smallmoney) * CAST(2.56 as bigint); +go +-- select CAST(2.56 as bigint) / CAST(3.60 as smallmoney); -> see BABEL-977 +-- go +select CAST(3.60 as smallmoney) / CAST(2.56 as bigint); +go + +-- Test operations(e.g. +,-,*,/) between fixeddecimal(money/smallmoney) and int4(int) +select CAST(2.56 as int) + CAST(3.60 as money); +go +select CAST(3.60 as money) + CAST(2.56 as int); +go +select CAST(2.56 as int) - CAST(3.60 as money); +go +select CAST(3.60 as money) - CAST(2.56 as int); +go +select CAST(2.56 as int) * CAST(3.60 as money); +go +select CAST(3.60 as money) * CAST(2.56 as int); +go +select CAST(2.56 as int) / CAST(3.60 as money); +go +select CAST(3.60 as money) / CAST(2.56 as int); +go + +select CAST(2.56 as int) + CAST(3.60 as smallmoney); +go +select CAST(3.60 as smallmoney) + CAST(2.56 as int); +go +select CAST(2.56 as int) - CAST(3.60 as smallmoney); +go +select CAST(3.60 as smallmoney) - CAST(2.56 as int); +go +select CAST(2.56 as int) * CAST(3.60 as smallmoney); +go +select CAST(3.60 as smallmoney) * CAST(2.56 as int); +go +-- select CAST(2.56 as int) / CAST(3.60 as smallmoney); -> see BABEL-977 +-- go +select CAST(3.60 as smallmoney) / CAST(2.56 as int); +go + +-- Test operations(e.g. +,-,*,/) between fixeddecimal(money/smallmoney) and int2(smallint) +select CAST(2.56 as smallint) + CAST(3.60 as money); +go +select CAST(3.60 as money) + CAST(2.56 as smallint); +go +select CAST(2.56 as smallint) - CAST(3.60 as money); +go +select CAST(3.60 as money) - CAST(2.56 as smallint); +go +select CAST(2.56 as smallint) * CAST(3.60 as money); +go +select CAST(3.60 as money) * CAST(2.56 as smallint); +go +select CAST(2.56 as smallint) / CAST(3.60 as money); +go +select CAST(3.60 as money) / CAST(2.56 as smallint); +go + +select CAST(2.56 as smallint) + CAST(3.60 as smallmoney); +go +select CAST(3.60 as smallmoney) + CAST(2.56 as smallint); +go +select CAST(2.56 as smallint) - CAST(3.60 as smallmoney); +go +select CAST(3.60 as smallmoney) - CAST(2.56 as smallint); +go +select CAST(2.56 as smallint) * CAST(3.60 as smallmoney); +go +select CAST(3.60 as smallmoney) * CAST(2.56 as smallint); +go +-- select CAST(2.56 as smallint) / CAST(3.60 as smallmoney); -> see BABEL-977 +-- go +select CAST(3.60 as smallmoney) / CAST(2.56 as smallint); +go diff --git a/contrib/test/JDBC/input/babel_numeric.sql b/contrib/test/JDBC/input/babel_numeric.sql new file mode 100644 index 00000000000..2dab904ac1c --- /dev/null +++ b/contrib/test/JDBC/input/babel_numeric.sql @@ -0,0 +1,63 @@ +-- Test numeric in cast function +select cast(1.123 as numeric(38, 10)); +go +select cast(1.123 as numeric(39, 10)); +go + +-- Test decimal in cast function +select cast(1.123 as decimal(38, 10)); +go +select cast(1.123 as decimal(39, 10)); +go + +-- Test dec in cast function +select cast(1.123 as dec(38, 10)); +go +select cast(1.123 as dec(39, 10)); +go + +-- Test numeric in create table +create table t1 (col numeric(38,37)); +drop table t1; +go + +create table t1 (col numeric(39, 37)); +go + +-- Test decimal in create table +create table t1 (col decimal(38,37)); +drop table t1; +go + +create table t1 (col decimal(39, 37)); +go + +-- Test dec in create table +create table t1 (col decimal(38,37)); +drop table t1; +go + +create table t1 (col decimal(39, 37)); +go + +-- Test default precision and scale is set to 18, 0 +create table t1 (col numeric); +insert into t1 values (1.2); +insert into t1 values (123456789012345678); +select * from t1; +go +insert into t1 values (1234567890123456789); +select * from t1; +go + +drop table t1; +go + +-- Test default scale is set to 0 if only precision is specified +create table t1 (col numeric(4)); +insert into t1 values (1.2); +select * from t1; +go + +drop table t1; +go \ No newline at end of file diff --git a/contrib/test/JDBC/input/babel_operators.sql b/contrib/test/JDBC/input/babel_operators.sql new file mode 100644 index 00000000000..62dda38355c --- /dev/null +++ b/contrib/test/JDBC/input/babel_operators.sql @@ -0,0 +1,58 @@ +-- test adding with varbinary +SELECT (123 + 0x42); +SELECT (0x42 + 123); +GO + +-- test subtracting with varbinary +SELECT (123 - 0x42); +SELECT (0x42 - 123); +GO + +-- test multiplication with varbinary +SELECT (123 * CAST(123 AS varbinary(4))); +SELECT (CAST(123 AS varbinary(4)) * 123); +GO + +-- test division with varbinary +SELECT (12345 / CAST(12 AS varbinary(4))); +SELECT (CAST(12345 AS varbinary(4)) / 12); +GO + +-- test & operator with varbinary +SELECT (CAST(123 AS varbinary(1)) & 21); +SELECT (CAST(123 AS varbinary(2)) & 321); +SELECT (CAST(12345 AS varbinary(4)) & 54321); +GO + +SELECT (CAST(9876543210 AS BIGINT) & CAST(1234567890 AS varbinary(8))); +SELECT (543210 & CAST(12345 AS varbinary(4))); +SELECT (CAST(321 AS smallint) & CAST(123 AS varbinary(2))); +SELECT (CAST(12 AS tinyint) & CAST(21 AS varbinary(1))); +GO + +-- test | operator with varbinary +SELECT (CAST(123 AS varbinary(1)) | 21); +SELECT (CAST(123 AS varbinary(2)) | 321); +SELECT (CAST(12345 AS varbinary(4)) | 54321); +GO + +SELECT (CAST(9876543210 AS BIGINT) | CAST(1234567890 AS varbinary(8))); +SELECT (543210 | CAST(12345 AS varbinary(4))); +SELECT (CAST(321 AS smallint) | CAST(123 AS varbinary(2))); +SELECT (CAST(12 AS tinyint) | CAST(21 AS varbinary(1))); +GO + +-- test ^ operator with varbinary +SELECT (17 ^ 5); +GO + +SELECT (CAST(123 AS varbinary(1)) ^ 21); +SELECT (CAST(123 AS varbinary(2)) ^ 321); +SELECT (CAST(12345 AS varbinary(4)) ^ 54321); +GO + +SELECT (CAST(9876543210 AS BIGINT) ^ CAST(1234567890 AS varbinary(8))); +SELECT (543210 ^ CAST(12345 AS varbinary(4))); +SELECT (CAST(321 AS smallint) ^ CAST(123 AS varbinary(2))); +SELECT (CAST(12 AS tinyint) ^ CAST(21 AS varbinary(1))); +GO diff --git a/contrib/test/JDBC/input/babel_print.sql b/contrib/test/JDBC/input/babel_print.sql new file mode 100644 index 00000000000..dce20955c06 --- /dev/null +++ b/contrib/test/JDBC/input/babel_print.sql @@ -0,0 +1,39 @@ +-- Test PRINT with T-sql procedures -- +-- Printing a pre-defined text +CREATE PROCEDURE tsql_print_text AS + PRINT 'Pre-defined text for tsql_print_text' +GO +EXEC tsql_print_text +GO + +-- Printing a user input text +CREATE PROCEDURE tsql_print_message(@message varchar(50)) AS +BEGIN + PRINT @message +END; +GO +EXEC tsql_print_message 'Testing message for tsql_print_message' +GO + +-- Printing a pre-defined and a user input text +CREATE PROCEDURE tsql_print_message_and_text(@message varchar(50)) AS +BEGIN + PRINT 'Pre-defined text for tsql_print_message_and_text. User input: '+ @message +END +GO +EXEC tsql_print_message_and_text 'Testing message for tsql_print_message_and_text' +GO + +-- Making a call to another function that prints +CREATE PROCEDURE tsql_print_function AS + EXECUTE tsql_print_text +GO +EXEC tsql_print_function +GO + +-- Cleanup -- +DROP PROCEDURE tsql_print_text; +DROP PROCEDURE tsql_print_message; +DROP PROCEDURE tsql_print_message_and_text; +DROP PROCEDURE tsql_print_function; +GO diff --git a/contrib/test/JDBC/input/babel_smalldatetime.sql b/contrib/test/JDBC/input/babel_smalldatetime.sql new file mode 100644 index 00000000000..390b4587710 --- /dev/null +++ b/contrib/test/JDBC/input/babel_smalldatetime.sql @@ -0,0 +1,102 @@ +-- 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 + +-- 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 + +-- 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 + +-- 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 +-- 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 + +-- 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 + +-- 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 + +-- 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 + +-- Clean up +drop table smalldatetime_testing; +drop table t1; +go diff --git a/contrib/test/JDBC/input/babel_top.sql b/contrib/test/JDBC/input/babel_top.sql new file mode 100644 index 00000000000..9382c9d8c6b --- /dev/null +++ b/contrib/test/JDBC/input/babel_top.sql @@ -0,0 +1,40 @@ +-- +-- Tests for TOP clause +-- + +create table students (fname varchar(10), lname varchar(10), score double precision) +go + +insert into students (fname, lname, score) +values + ('John', 'Doe', 72.5), + ('Jane', 'Smith', 88), + ('Jill', 'Johnson', 98), + ('Jack', 'Green', 67), + ('Jennifer', 'Ross', 75.7), + ('Jacob', 'Brown', 95.2) +go + +select top 3 * from students +go + +select top 4 score from students +go + +select top 3 from students +go + +-- test top bigint +select top 2147483648 * from students +go + +-- test top 100 percent +select top 100 percent * from students +go + +select top 100.00 percent lname from students +go + +-- cleanup +drop table students +go \ No newline at end of file diff --git a/contrib/test/JDBC/input/babel_trigger.sql b/contrib/test/JDBC/input/babel_trigger.sql new file mode 100644 index 00000000000..fcfc72c2d9d --- /dev/null +++ b/contrib/test/JDBC/input/babel_trigger.sql @@ -0,0 +1,329 @@ +-- a simple test +create table testing1(col nvarchar(60)) +GO + +create trigger notify on testing1 after insert +as +begin + SELECT 'trigger invoked' +end +GO + +insert into testing1 (col) select N'Muffler' +GO + +drop trigger notify +GO + +-- test drop trigger if exists +create trigger notify on testing1 after insert +as +begin + SELECT 'trigger invoked' +end +GO + +drop trigger if exists notify +GO + +drop trigger if exists notify +GO + +-- test comma separator +create trigger notify on testing1 after insert, delete +as +begin + SELECT 'trigger invoked' +end +GO + +insert into testing1 (col) select N'Apple' +GO + +delete from testing1 where col = N'Apple' +GO + +drop trigger notify +GO + +-- test inserted and deleted transition tables +CREATE TABLE products( + product_id INT NOT NULL, + product_name VARCHAR(255) NOT NULL, + brand_id INT NOT NULL, + category_id INT NOT NULL, + model_year SMALLINT NOT NULL, + list_price DEC(10,2) NOT NULL +) +GO + +CREATE TABLE product_audits( + product_id INT NOT NULL, + product_name VARCHAR(255) NOT NULL, + brand_id INT NOT NULL, + category_id INT NOT NULL, + model_year SMALLINT NOT NULL, + list_price DEC(10,2) NOT NULL, + operation CHAR(3) NOT NULL, + CHECK(operation = 'INS' or operation='DEL') +) +GO + +CREATE TRIGGER trg_product_audit +ON products +AFTER INSERT +AS +BEGIN + INSERT INTO product_audits( + product_id, + product_name, + brand_id, + category_id, + model_year, + list_price, + operation + ) + SELECT + i.product_id, + product_name, + brand_id, + category_id, + model_year, + i.list_price, + 'INS' + FROM + inserted i +END +GO + +INSERT INTO products( + product_id, + product_name, + brand_id, + category_id, + model_year, + list_price +) +VALUES ( + 1, + 'Test product', + 1, + 1, + 2018, + 599 +) +GO + +SELECT * FROM PRODUCT_AUDITS +GO + +drop trigger trg_product_audit +GO + +-- clean up +drop table testing1 +GO +drop table product_audits +GO +drop table products +GO + +-- CARRY OUT THE SAME TESTS WITH THE FOR KEYWORD -- + +-- a simple test +create table testing1(col nvarchar(60)) +GO + +create trigger notify on testing1 for insert +as +begin + SELECT 'trigger invoked' +end +GO + +insert into testing1 (col) select N'Muffler' +GO + +drop trigger notify +GO + +-- test drop trigger if exists +create trigger notify on testing1 for insert +as +begin + SELECT 'trigger invoked' +end +GO + +drop trigger if exists notify +GO + +drop trigger if exists notify +GO + +-- test comma separator +create trigger notify on testing1 for insert, delete +as +begin + SELECT 'trigger invoked' +end +GO + +insert into testing1 (col) select N'Apple' +GO + +delete from testing1 where col = N'Apple' +GO + +drop trigger notify +GO + +-- test inserted and deleted transition tables +CREATE TABLE products( + product_id INT NOT NULL, + product_name VARCHAR(255) NOT NULL, + brand_id INT NOT NULL, + category_id INT NOT NULL, + model_year SMALLINT NOT NULL, + list_price DEC(10,2) NOT NULL +) +GO + +CREATE TABLE product_audits( + product_id INT NOT NULL, + product_name VARCHAR(255) NOT NULL, + brand_id INT NOT NULL, + category_id INT NOT NULL, + model_year SMALLINT NOT NULL, + list_price DEC(10,2) NOT NULL, + operation CHAR(3) NOT NULL, + CHECK(operation = 'INS' or operation='DEL') +) +GO + +CREATE TRIGGER trg_product_audit +ON products +FOR INSERT +AS +BEGIN + INSERT INTO product_audits( + product_id, + product_name, + brand_id, + category_id, + model_year, + list_price, + operation + ) + SELECT + i.product_id, + product_name, + brand_id, + category_id, + model_year, + i.list_price, + 'INS' + FROM + inserted i +END +GO + +INSERT INTO products( + product_id, + product_name, + brand_id, + category_id, + model_year, + list_price +) +VALUES ( + 1, + 'Test product', + 1, + 1, + 2018, + 599 +) +GO + +SELECT * FROM PRODUCT_AUDITS +GO + +drop trigger trg_product_audit +GO + +-- Test drop trigger without table name -- +-- First, test that triggers must have unique names +create trigger notify on testing1 after insert +as +begin + SELECT 'trigger invoked' +end +GO + +create table testing2(col nvarchar(60)) +GO + +create trigger notify on testing2 after insert +as +begin + SELECT 'trigger invoked' +end +GO + +drop table testing2 +GO + +-- Now, test that drop trigger works without tablename +drop trigger notify +GO + +-- Test that drop trigger statement on non-existent trigger throws error +drop trigger notify +GO +drop trigger if exists notify +GO + +-- Test that dropping a table with triggers defined on it succeeds +create table testTbl(colA int not null primary key, colB varchar(20)) +GO + +create trigger trig1 on testTbl after insert +as +begin + SELECT 'trigger invoked' +end +GO + +create trigger trig2 on testTbl after insert +as +begin + SELECT 'trigger2 invoked' +end +GO + +drop table testTbl +GO + +-- Test 'NOT FOR REPLICATION' syntax +create trigger notify on testing1 after insert +NOT FOR REPLICATION +as +begin + SELECT 'trigger invoked' +end +GO + +insert into testing1 (col) select N'Muffler' +GO + +drop trigger notify +GO + +-- clean up +drop table testing1 +GO +drop table product_audits +GO +drop table products +GO \ No newline at end of file diff --git a/contrib/test/JDBC/input/babel_varbinary.sql b/contrib/test/JDBC/input/babel_varbinary.sql new file mode 100644 index 00000000000..fc4c541b021 --- /dev/null +++ b/contrib/test/JDBC/input/babel_varbinary.sql @@ -0,0 +1,86 @@ +-- [BABEL-448] Test support of unquoted hexadecimal string input +select 0x1a2b3c4f; +go +select 0X1A2B3C4F; +go +select pg_typeof(0X1A2B3C4F); +go + +-- BABEL-631 Test odd number of hex digigts is allowed +select 0xF; +go +select 0x1; +go +select 0x0; +go +select 0x1F1; +go + +-- invalid hex input +select 0x1G2A; +go + +-- test insert of hex string +create table t1(a varbinary(8), b binary(8)); +insert into t1 values(0x1a2b3c4f, cast('1a2b3c4f' as binary(8))); +insert into t1 values(cast('1a2b3c4f' as varbinary(8)), cast('1a2b3c4f' as binary(8))); +go + +-- 0x1a2b3c4f and '1a2b3c4f' are different as varbinary +select * from t1; +go + +-- test bitwise operators on hex string and int +select 0x1F & 10; +go +select 10 & 0x1F; +go +select 0x1F | 10; +go +select 10 | 0x1F; +go +select 0x1F ^ 10; +go +select 10 ^ 0x1F; +go +select 0x1F * 10; +go +select 10 * 0x1F; +go +select 0x1F / 10; +go +select 100 / 0x1F; +go + +-- division by 0 +select 0x1F / 0; +go +select 10 / 0x00; +go + +-- test hex string in procedure +create procedure test_hex_bitop as +begin + select 0x1A2B3C4F ^ 101; +end; +go + +execute test_hex_bitop; +go + +create procedure test_hex_insert as +begin + insert into t1 values(0x1f, cast('1f' as binary(2))); +end; +go + +execute test_hex_insert; +go +select * from t1; +go + +-- clean up +drop table t1; +drop procedure test_hex_bitop; +drop procedure test_hex_insert; +go \ No newline at end of file diff --git a/contrib/test/JDBC/input/cursors/BABEL-1390.txt b/contrib/test/JDBC/input/cursors/BABEL-1390.txt new file mode 100644 index 00000000000..b99d1986b2c --- /dev/null +++ b/contrib/test/JDBC/input/cursors/BABEL-1390.txt @@ -0,0 +1,19 @@ +# Setup a table with some data +CREATE TABLE updatable_cursor_table(a INT, b SMALLINT, c BIGINT, d TINYINT, e BIT); +INSERT INTO updatable_cursor_table values(0, 0, 0, 0, 0) +INSERT INTO updatable_cursor_table values(NULL, NULL, NULL, NULL, NULL) +INSERT INTO updatable_cursor_table values(1, 2, 3, 4, 1) +INSERT INTO updatable_cursor_table values(211234, 9780, 891372401, 56, 1) + +# Try opening an updatable cursor using JDBC API +# SET escape_hatch_session_settings to ignore CURSOR_CLOSE_ON_COMMIT +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_session_settings', 'ignore'; +cursor#!#open#!#SELECT * FROM updatable_cursor_table#!#CONCUR_UPDATABLE#!#CLOSE_CURSORS_AT_COMMIT + +# Try opening an updatable (i.e. dynamic) cursor using SQL Batch +DECLARE updatable_cursor CURSOR DYNAMIC FOR SELECT a FROM updatable_cursor_table; OPEN updatable_cursor; CLOSE updatable_cursor; DEALLOCATE updatable_cursor; + +# Drop table +DROP TABLE updatable_cursor_table +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_session_settings', 'strict'; + diff --git a/contrib/test/JDBC/input/cursors/TestCursorFetchNext.txt b/contrib/test/JDBC/input/cursors/TestCursorFetchNext.txt new file mode 100644 index 00000000000..22ffd004d35 --- /dev/null +++ b/contrib/test/JDBC/input/cursors/TestCursorFetchNext.txt @@ -0,0 +1,89 @@ +CREATE TABLE test_cursors_fetch_next(a INT, b SMALLINT, c BIGINT, d TINYINT, e BIT); +INSERT INTO test_cursors_fetch_next values(0, 0, 0, 0, 0) +INSERT INTO test_cursors_fetch_next values(NULL, NULL, NULL, NULL, NULL) +INSERT INTO test_cursors_fetch_next values(1, 2, 3, 4, 1) +INSERT INTO test_cursors_fetch_next values(211234, 9780, 891372401, 56, 1) +# SET escape_hatch_session_settings to ignore CURSOR_CLOSE_ON_COMMIT +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_session_settings', 'ignore'; +cursor#!#open#!#SELECT * FROM test_cursors_fetch_next#!#TYPE_SCROLL_INSENSITIVE#!#CONCUR_READ_ONLY#!#CLOSE_CURSORS_AT_COMMIT +cursor#!#fetch#!#next +cursor#!#fetch#!#abs#!#2 +cursor#!#fetch#!#next +cursor#!#fetch#!#first +cursor#!#fetch#!#next +cursor#!#fetch#!#last +cursor#!#fetch#!#next +#cursor#!#fetch#!#prev +#cursor#!#fetch#!#next +#cursor#!#fetch#!#beforefirst +#cursor#!#fetch#!#next +#cursor#!#fetch#!#afterlast +#cursor#!#fetch#!#next +cursor#!#close +DROP TABLE test_cursors_fetch_next + +CREATE TABLE test_cursors_fetch_next(a CHAR(30), b VARCHAR(30), c NCHAR(30), d NVARCHAR(30)); +INSERT INTO test_cursors_fetch_next values(' ', ' ', ' ', ' ') +INSERT INTO test_cursors_fetch_next values(NULL, NULL, NULL, NULL) +INSERT INTO test_cursors_fetch_next values('hello', 'from the', N'server', N'side 😆') +INSERT INTO test_cursors_fetch_next values('Its', 'always', N'day', N'1') +cursor#!#open#!#SELECT * FROM test_cursors_fetch_next#!#TYPE_SCROLL_INSENSITIVE#!#CONCUR_READ_ONLY#!#CLOSE_CURSORS_AT_COMMIT +cursor#!#fetch#!#abs#!#3 +cursor#!#fetch#!#next +cursor#!#fetch#!#first +cursor#!#fetch#!#next +cursor#!#fetch#!#last +cursor#!#fetch#!#next +#cursor#!#fetch#!#prev +#cursor#!#fetch#!#next +#cursor#!#fetch#!#beforefirst +#cursor#!#fetch#!#next +#cursor#!#fetch#!#afterlast +#cursor#!#fetch#!#next +cursor#!#close +DROP TABLE test_cursors_fetch_next + +CREATE TABLE test_cursors_fetch_next(a DATE, b DATETIME, c SMALLDATETIME); +INSERT INTO test_cursors_fetch_next values('2000-12-13', '1900-02-28 23:59:59.989', '2000-12-13 12:58:23') +INSERT INTO test_cursors_fetch_next values(NULL, NULL, NULL) +INSERT INTO test_cursors_fetch_next values('1997-05-07', '1900-02-28 11:23:17.895', '2000-12-13 10:23:44') +INSERT INTO test_cursors_fetch_next values('1876-08-07', '1980-02-05 16:11:45.215', '1987-10-01 07:55:24') +cursor#!#open#!#SELECT * FROM test_cursors_fetch_next#!#TYPE_SCROLL_INSENSITIVE#!#CONCUR_READ_ONLY#!#CLOSE_CURSORS_AT_COMMIT +cursor#!#fetch#!#first +cursor#!#fetch#!#abs#!#4 +cursor#!#fetch#!#next +cursor#!#fetch#!#first +cursor#!#fetch#!#next +cursor#!#fetch#!#last +cursor#!#fetch#!#next +#cursor#!#fetch#!#prev +#cursor#!#fetch#!#next +#cursor#!#fetch#!#beforefirst +#cursor#!#fetch#!#next +#cursor#!#fetch#!#afterlast +#cursor#!#fetch#!#next +cursor#!#close +DROP TABLE test_cursors_fetch_next + +CREATE TABLE test_cursors_fetch_next(a FLOAT, b REAL, c MONEY, d SMALLMONEY); +INSERT INTO test_cursors_fetch_next values(0, 0, '$0', '$0') +INSERT INTO test_cursors_fetch_next values(NULL, NULL, NULL, NULL) +INSERT INTO test_cursors_fetch_next values(241.7832, 1214.691236, '62,514.00', '690.817') +INSERT INTO test_cursors_fetch_next values('32546', '980.709', '1,988,232.08', '$86,798') +cursor#!#open#!#SELECT * FROM test_cursors_fetch_next#!#TYPE_SCROLL_INSENSITIVE#!#CONCUR_READ_ONLY#!#CLOSE_CURSORS_AT_COMMIT +cursor#!#fetch#!#next +cursor#!#fetch#!#abs#!#2 +cursor#!#fetch#!#next +cursor#!#fetch#!#first +cursor#!#fetch#!#next +cursor#!#fetch#!#last +cursor#!#fetch#!#next +#cursor#!#fetch#!#prev +#cursor#!#fetch#!#next +#cursor#!#fetch#!#beforefirst +#cursor#!#fetch#!#next +#cursor#!#fetch#!#afterlast +#cursor#!#fetch#!#next +cursor#!#close +DROP TABLE test_cursors_fetch_next +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_session_settings', 'strict'; diff --git a/contrib/test/JDBC/input/cursors/TestCursorPrepExecFetchNext.txt b/contrib/test/JDBC/input/cursors/TestCursorPrepExecFetchNext.txt new file mode 100644 index 00000000000..e2627d990c2 --- /dev/null +++ b/contrib/test/JDBC/input/cursors/TestCursorPrepExecFetchNext.txt @@ -0,0 +1,97 @@ +CREATE TABLE test_cursor_prep_exec_fetch_next(a INT, b SMALLINT, c BIGINT, d TINYINT, e BIT); +INSERT INTO test_cursor_prep_exec_fetch_next values(0, 0, 0, 0, 0) +INSERT INTO test_cursor_prep_exec_fetch_next values(NULL, NULL, NULL, NULL, NULL) +INSERT INTO test_cursor_prep_exec_fetch_next values(1, 2, 3, 4, 1) +INSERT INTO test_cursor_prep_exec_fetch_next values(211234, 9780, 891372401, 56, 1) + +# SET escape_hatch_session_settings to ignore CURSOR_CLOSE_ON_COMMIT +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_session_settings', 'ignore'; +cursor#!#open#!#prepst#!#SELECT * FROM test_cursor_prep_exec_fetch_next WHERE a > @a #!#INT|-|a|-|-2#!#TYPE_SCROLL_INSENSITIVE#!#CONCUR_READ_ONLY#!#CLOSE_CURSORS_AT_COMMIT +cursor#!#fetch#!#next +cursor#!#fetch#!#abs#!#2 +cursor#!#fetch#!#next +cursor#!#fetch#!#first +cursor#!#fetch#!#next +cursor#!#close +cursor#!#open#!#prepst#!#exec#!#INT|-|a|-|0#!#TYPE_SCROLL_INSENSITIVE#!#CONCUR_READ_ONLY#!#HOLD_CURSORS_OVER_COMMIT +cursor#!#fetch#!#last +cursor#!#fetch#!#next +#cursor#!#fetch#!#prev +#cursor#!#fetch#!#next +#cursor#!#fetch#!#beforefirst +#cursor#!#fetch#!#next +#cursor#!#fetch#!#afterlast +#cursor#!#fetch#!#next +cursor#!#close +DROP TABLE test_cursor_prep_exec_fetch_next + +CREATE TABLE test_cursor_prep_exec_fetch_next(a CHAR(30), b VARCHAR(30), c NCHAR(30), d NVARCHAR(30)); +INSERT INTO test_cursor_prep_exec_fetch_next values(' ', ' ', ' ', ' ') +INSERT INTO test_cursor_prep_exec_fetch_next values(NULL, NULL, NULL, NULL) +INSERT INTO test_cursor_prep_exec_fetch_next values('hello', 'from the', N'server', N'side 😆') +INSERT INTO test_cursor_prep_exec_fetch_next values('Its', 'always', N'day', N'1') +cursor#!#open#!#prepst#!#SELECT * FROM test_cursor_prep_exec_fetch_next WHERE a <> @a #!#CHAR|-|a|-|hello#!#TYPE_SCROLL_INSENSITIVE#!#CONCUR_READ_ONLY#!#CLOSE_CURSORS_AT_COMMIT +cursor#!#fetch#!#abs#!#3 +cursor#!#fetch#!#next +cursor#!#fetch#!#first +cursor#!#fetch#!#next +cursor#!#close +cursor#!#open#!#prepst#!#exec#!#CHAR|-|a|-|Its#!#TYPE_SCROLL_INSENSITIVE#!#CONCUR_READ_ONLY#!#CLOSE_CURSORS_AT_COMMIT +cursor#!#fetch#!#last +cursor#!#fetch#!#next +#cursor#!#fetch#!#prev +#cursor#!#fetch#!#next +#cursor#!#fetch#!#beforefirst +#cursor#!#fetch#!#next +#cursor#!#fetch#!#afterlast +#cursor#!#fetch#!#next +cursor#!#close +DROP TABLE test_cursor_prep_exec_fetch_next + +CREATE TABLE test_cursor_prep_exec_fetch_next(a DATE, b DATETIME, c SMALLDATETIME); +INSERT INTO test_cursor_prep_exec_fetch_next values('2000-12-13', '1900-02-28 23:59:59.989', '2000-12-13 12:58:23') +INSERT INTO test_cursor_prep_exec_fetch_next values(NULL, NULL, NULL) +INSERT INTO test_cursor_prep_exec_fetch_next values('1997-05-07', '1900-02-28 11:23:17.895', '2000-12-13 10:23:44') +INSERT INTO test_cursor_prep_exec_fetch_next values('1876-08-07', '1980-02-05 16:11:45.215', '1987-10-01 07:55:24') +cursor#!#open#!#prepst#!#SELECT * FROM test_cursor_prep_exec_fetch_next WHERE b > @b #!#DATETIME|-|b|-|1753-01-01 00:00:00.000#!#TYPE_SCROLL_INSENSITIVE#!#CONCUR_READ_ONLY#!#CLOSE_CURSORS_AT_COMMIT +cursor#!#fetch#!#first +cursor#!#fetch#!#abs#!#2 +cursor#!#fetch#!#next +cursor#!#fetch#!#first +cursor#!#fetch#!#next +cursor#!#close +cursor#!#open#!#prepst#!#exec#!#DATETIME|-|b|-|1947-01-01 11:23:17.374#!#TYPE_SCROLL_INSENSITIVE#!#CONCUR_READ_ONLY#!#CLOSE_CURSORS_AT_COMMIT +cursor#!#fetch#!#last +cursor#!#fetch#!#next +#cursor#!#fetch#!#prev +#cursor#!#fetch#!#next +#cursor#!#fetch#!#beforefirst +#cursor#!#fetch#!#next +#cursor#!#fetch#!#afterlast +#cursor#!#fetch#!#next +cursor#!#close +DROP TABLE test_cursor_prep_exec_fetch_next + +CREATE TABLE test_cursor_prep_exec_fetch_next(a FLOAT, b REAL, c MONEY, d SMALLMONEY); +INSERT INTO test_cursor_prep_exec_fetch_next values(0, 0, '$0', '$0') +INSERT INTO test_cursor_prep_exec_fetch_next values(NULL, NULL, NULL, NULL) +INSERT INTO test_cursor_prep_exec_fetch_next values(241.7832, 1214.691236, '62,514.00', '690.817') +INSERT INTO test_cursor_prep_exec_fetch_next values('32546', '980.709', '1,988,232.08', '$86,798') +cursor#!#open#!#prepst#!#SELECT * FROM test_cursor_prep_exec_fetch_next WHERE b > @b #!#REAL|-|b|-|12.0834#!#TYPE_SCROLL_INSENSITIVE#!#CONCUR_READ_ONLY#!#CLOSE_CURSORS_AT_COMMIT +cursor#!#fetch#!#next +cursor#!#fetch#!#abs#!#3 +cursor#!#fetch#!#next +cursor#!#fetch#!#first +cursor#!#fetch#!#next +cursor#!#close +cursor#!#open#!#prepst#!#exec#!#REAL|-|b|-|1000.241#!#TYPE_SCROLL_INSENSITIVE#!#CONCUR_READ_ONLY#!#CLOSE_CURSORS_AT_COMMIT +cursor#!#fetch#!#last +cursor#!#fetch#!#next +#cursor#!#fetch#!#prev +#cursor#!#fetch#!#next +#cursor#!#fetch#!#beforefirst +#cursor#!#fetch#!#next +#cursor#!#fetch#!#afterlast +#cursor#!#fetch#!#next +cursor#!#close +DROP TABLE test_cursor_prep_exec_fetch_next diff --git a/contrib/test/JDBC/input/datatypes/TestBIT.txt b/contrib/test/JDBC/input/datatypes/TestBIT.txt new file mode 100644 index 00000000000..8424eadd597 --- /dev/null +++ b/contrib/test/JDBC/input/datatypes/TestBIT.txt @@ -0,0 +1,16 @@ +CREATE TABLE BIT_dt (a BIT) +prepst#!# INSERT INTO BIT_dt(a) values(@a) #!#BIT|-|a|-|false +prepst#!#exec#!#BIT|-|a|-|true +#next two lines are not allowed +#prepst#!#exec#!#BIT|-|a|-|0 +#prepst#!#exec#!#BIT|-|a|-|1 +prepst#!#exec#!#BIT|-|a|-| +SELECT * FROM BIT_dt; +INSERT INTO BIT_dt(a) values(1) +INSERT INTO BIT_dt(a) values(0) +#next two lines are not allowed +#INSERT INTO BIT_dt(a) values(false) +#INSERT INTO BIT_dt(a) values(true) +INSERT INTO BIT_dt(a) values(NULL) +SELECT * FROM BIT_dt; +DROP TABLE BIT_dt; \ No newline at end of file diff --git a/contrib/test/JDBC/input/datatypes/TestBigInt.txt b/contrib/test/JDBC/input/datatypes/TestBigInt.txt new file mode 100644 index 00000000000..ef1451f78e8 --- /dev/null +++ b/contrib/test/JDBC/input/datatypes/TestBigInt.txt @@ -0,0 +1,24 @@ +CREATE TABLE BIGINT_dt (a BIGINT) +prepst#!# INSERT INTO BIGINT_dt(a) values(@a) #!#BIGINT|-|a|-|0 +prepst#!#exec#!#BIGINT|-|a|-|-10 +prepst#!#exec#!#BIGINT|-|a|-|122100 +prepst#!#exec#!#BIGINT|-|a|-|0001202 +prepst#!#exec#!#BIGINT|-|a|-|-024112329 +prepst#!#exec#!#BIGINT|-|a|-|-0000000000000000002 +prepst#!#exec#!#BIGINT|-|a|-|0000000000000000086 +prepst#!#exec#!#BIGINT|-|a|-|-9223372036854775808 +prepst#!#exec#!#BIGINT|-|a|-|9223372036854775807 +prepst#!#exec#!#BIGINT|-|a|-| +SELECT * FROM BIGINT_dt; +INSERT INTO BIGINT_dt(a) values(0) +INSERT INTO BIGINT_dt(a) values(-120) +INSERT INTO BIGINT_dt(a) values(00100) +INSERT INTO BIGINT_dt(a) values(-004) +INSERT INTO BIGINT_dt(a) values(-012245532534) +INSERT INTO BIGINT_dt(a) values(-0000000000000000002) +INSERT INTO BIGINT_dt(a) values(0000000000000000086) +INSERT INTO BIGINT_dt(a) values(-9223372036854775808) +INSERT INTO BIGINT_dt(a) values(9223372036854775807) +INSERT INTO BIGINT_dt(a) values(NULL) +SELECT * FROM BIGINT_dt; +DROP TABLE BIGINT_dt; \ No newline at end of file diff --git a/contrib/test/JDBC/input/datatypes/TestBinary.txt b/contrib/test/JDBC/input/datatypes/TestBinary.txt new file mode 100644 index 00000000000..0d2ffb12071 --- /dev/null +++ b/contrib/test/JDBC/input/datatypes/TestBinary.txt @@ -0,0 +1,29 @@ +CREATE TABLE BINARY_dt(a BINARY(8), b VARBINARY(10)); +#inserting random values +INSERT INTO BINARY_dt(a, b) values (1234, 12345); +INSERT INTO BINARY_dt(a, b) values (NULL, NULL); +#INSERT INTO BINARY_dt(a, b) values (0x31323334, 0x3132333435); +SELECT * FROM BINARY_dt +#prepst#!# INSERT INTO BINARY_dt(a, b) values(@a, @b) #!#binary|-|a|-|1234#!#varbinary|-|b|-|12345 +DROP TABLE BINARY_dt + + +CREATE TABLE BINARY_dt(a VARBINARY(max)); +INSERT INTO BINARY_dt(a) values (NULL); +SELECT * FROM BINARY_dt; +DROP TABLE BINARY_dt; + +create table BINARY_dt (a VARBINARY(max), b int, c int, d int, e int ,f int, g int, h int, i int); +insert into BINARY_dt (a,b,c,d,e,f,g,h,i) values (NULL,1,2,3,4,5,6,7,8); +select * from BINARY_dt; +drop table BINARY_dt; + +CREATE TABLE BINARY_dt(a BINARY(8), b VARBINARY(10)); +INSERT INTO BINARY_dt(a, b) values (1234, 12345); +prepst#!# INSERT INTO BINARY_dt(a, b) values(@a, @b) #!#binary|-|a|-|1234#!#varbinary|-|b|-|12345 +prepst#!#exec#!#binary|-|a|-|123456789#!#varbinary|-|b|-|12345 +prepst#!#exec#!#binary|-|a|-|1234#!#varbinary|-|b|-|123456789 +SELECT * FROM BINARY_dt; +DROP TABLE BINARY_dt; + + diff --git a/contrib/test/JDBC/input/datatypes/TestChar.txt b/contrib/test/JDBC/input/datatypes/TestChar.txt new file mode 100644 index 00000000000..c982a1e7265 --- /dev/null +++ b/contrib/test/JDBC/input/datatypes/TestChar.txt @@ -0,0 +1,16 @@ +CREATE TABLE CHAR_dt (a CHAR(24), b NCHAR(24)) +prepst#!# INSERT INTO CHAR_dt(a, b) values(@a, @b) #!#CHAR|-|a|-|Dipesh#!#NCHAR|-|b|-|Dhameliya +prepst#!#exec#!#CHAR|-|a|-| Dipesh #!#NCHAR|-|b|-| Dhameliya +prepst#!#exec#!#CHAR|-|a|-| D#!#NCHAR|-|b|-| 🤣😃 +prepst#!#exec#!#CHAR|-|a|-| #!#NCHAR|-|b|-| +prepst#!#exec#!#CHAR|-|a|-| #!#NCHAR|-|b|-|😊😋😎😍😅😆 +prepst#!#exec#!#CHAR|-|a|-|#!#NCHAR|-|b|-| +SELECT * FROM CHAR_dt; +INSERT INTO CHAR_dt(a,b) values('Dipesh','Dhameliya') +INSERT INTO CHAR_dt(a,b) values(' Dipesh',' Dhameliya') +#INSERT INTO CHAR_dt(a,b) values(' D',N' 🤣😃') +INSERT INTO CHAR_dt(a,b) values(' ',' ') +#INSERT INTO CHAR_dt(a,b) values(' ',N'😊😋😎😍😅😆') +INSERT INTO CHAR_dt(a,b) values(NULL,NULL) +SELECT * FROM CHAR_dt; +DROP TABLE CHAR_dt; \ No newline at end of file diff --git a/contrib/test/JDBC/input/datatypes/TestDate.txt b/contrib/test/JDBC/input/datatypes/TestDate.txt new file mode 100644 index 00000000000..5af2f499b2f --- /dev/null +++ b/contrib/test/JDBC/input/datatypes/TestDate.txt @@ -0,0 +1,14 @@ +CREATE TABLE DATE_dt (a DATE) +prepst#!# INSERT INTO DATE_dt(a) values(@a) #!#DATE|-|a|-|2000-12-13 +prepst#!#exec#!#DATE|-|a|-|2000-02-28 +prepst#!#exec#!#DATE|-|a|-|0001-01-01 +prepst#!#exec#!#DATE|-|a|-|9999-12-31 +prepst#!#exec#!#DATE|-|a|-| +SELECT * FROM DATE_dt; +INSERT INTO DATE_dt(a) values('2000-12-13') +INSERT INTO DATE_dt(a) values('1900-02-28') +INSERT INTO DATE_dt(a) values('0001-01-01') +INSERT INTO DATE_dt(a) values('9999-12-31') +INSERT INTO DATE_dt(a) values(NULL) +SELECT * FROM DATE_dt; +DROP TABLE DATE_dt; \ No newline at end of file diff --git a/contrib/test/JDBC/input/datatypes/TestDatetime.txt b/contrib/test/JDBC/input/datatypes/TestDatetime.txt new file mode 100644 index 00000000000..a5df9ff4d9e --- /dev/null +++ b/contrib/test/JDBC/input/datatypes/TestDatetime.txt @@ -0,0 +1,36 @@ +CREATE TABLE DATETIME_dt (a DATETIME) +prepst#!# INSERT INTO DATETIME_dt(a) values(@a) #!#DATETIME|-|a|-|2000-12-13 12:58:23.123 +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.989 +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.990 +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.991 +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.992 +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.993 +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.994 +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.995 +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.996 +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.997 +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.998 +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.999 +prepst#!#exec#!#DATETIME|-|a|-|1900-02-28 23:59:59.989 +prepst#!#exec#!#DATETIME|-|a|-|1753-01-01 00:00:00.000 +prepst#!#exec#!#DATETIME|-|a|-|9999-12-31 23:59:59.997 +prepst#!#exec#!#DATETIME|-|a|-| +SELECT * FROM DATETIME_dt; +INSERT INTO DATETIME_dt(a) values('2000-12-13 12:58:23.123') +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.989') +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.990') +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.991') +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.992') +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.993') +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.994') +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.995') +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.996') +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.997') +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.998') +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.999') +INSERT INTO DATETIME_dt(a) values('2000-02-28 23:59:59.989') +INSERT INTO DATETIME_dt(a) values('1753-01-01 00:00:00.000') +INSERT INTO DATETIME_dt(a) values('9999-12-31 23:59:59.997') +INSERT INTO DATETIME_dt(a) values(NULL) +SELECT * FROM DATETIME_dt; +DROP TABLE DATETIME_dt; \ No newline at end of file diff --git a/contrib/test/JDBC/input/datatypes/TestDatetime2.txt b/contrib/test/JDBC/input/datatypes/TestDatetime2.txt new file mode 100644 index 00000000000..2a6062abb25 --- /dev/null +++ b/contrib/test/JDBC/input/datatypes/TestDatetime2.txt @@ -0,0 +1,15 @@ +Create table TestDatetime2(a Datetime2(6)) + +prepst#!# Insert into TestDatetime2 Values(@a) #!#Datetime2|-|a|-|2016-10-23 12:45:37.123|-|0 +prepst#!#exec#!#Datetime2|-|a|-|2016-10-23 12:45:37.123|-|3 +prepst#!#exec#!#Datetime2|-|a|-|2016-10-23 12:45:37.12|-|2 +prepst#!#exec#!#Datetime2|-|a|-|2016-10-23 12:45:37.1|-|1 +prepst#!#exec#!#Datetime2|-|a|-|2016-10-23 12:45:37.1234|-|4 +prepst#!#exec#!#Datetime2|-|a|-|2016-10-23 12:45:37.123456|-|6 +prepst#!#exec#!#Datetime2|-|a|-|2016-10-23 12:45:37.123456|-|5 +#prepst#!#exec#!#Datetime2|-|a|-|12:45:37.123456|-|5 +prepst#!#exec#!#Datetime2|-|a|-| + +select * from TestDatetime2 + +Drop table TestDatetime2 \ No newline at end of file diff --git a/contrib/test/JDBC/input/datatypes/TestDecimal.txt b/contrib/test/JDBC/input/datatypes/TestDecimal.txt new file mode 100644 index 00000000000..531fb023efe --- /dev/null +++ b/contrib/test/JDBC/input/datatypes/TestDecimal.txt @@ -0,0 +1,180 @@ +CREATE TABLE decimal_table(num decimal(5, 2)); + +prepst#!#INSERT INTO decimal_table(num) VALUES(@a) #!#decimal|-|a|-|3|-|5|-|2 +prepst#!#exec#!#decimal|-|a|-|123.456|-|5|-|2 +prepst#!#exec#!#decimal|-|a|-|123.4|-|5|-|2 +prepst#!#exec#!#decimal|-|a|-|123|-|5|-|2 +prepst#!#exec#!#decimal|-|a|-|123.45|-|5|-|2 +prepst#!#exec#!#decimal|-|a|-||-|5|-|2 +prepst#!#exec#!#decimal|-|a|-|-123.456|-|5|-|2 +prepst#!#exec#!#decimal|-|a|-|-123.4|-|5|-|2 +prepst#!#exec#!#decimal|-|a|-|-123|-|5|-|2 +#prepst#!#exec#!#decimal|-|a|-|0|-|5|-|2 +prepst#!#exec#!#decimal|-|a|-|-1|-|3|-|2 +prepst#!#exec#!#decimal|-|a|-|-123|-|9|-|2 + +SELECT * FROM decimal_table; + +DROP TABLE decimal_table; + +CREATE TABLE decimal_table(num decimal(38, 3)); + +prepst#!#INSERT INTO decimal_table(num) VALUES(@a1) #!#decimal|-|a1|-|3|-|5|-|2 +prepst#!#exec#!#decimal|-|a1|-|123.456|-|5|-|2 +prepst#!#exec#!#decimal|-|a1|-|123.4|-|5|-|2 +prepst#!#exec#!#decimal|-|a1|-|123|-|5|-|2 +prepst#!#exec#!#decimal|-|a1|-|123.45|-|5|-|2 +prepst#!#exec#!#decimal|-|a1|-||-|5|-|2 +prepst#!#exec#!#decimal|-|a1|-|-123.456|-|5|-|2 +prepst#!#exec#!#decimal|-|a1|-|-123.4|-|5|-|2 +prepst#!#exec#!#decimal|-|a1|-|-123|-|5|-|2 +#prepst#!#exec#!#decimal|-|a1|-|0|-|5|-|2 +prepst#!#exec#!#decimal|-|a1|-|-1|-|3|-|2 +prepst#!#exec#!#decimal|-|a1|-|-123|-|9|-|2 + +prepst#!#exec#!#decimal|-|a1|-|2147483647|-|10|-|0 +prepst#!#exec#!#decimal|-|a1|-|-2147483647|-|10|-|0 +prepst#!#exec#!#decimal|-|a1|-|2147483646|-|10|-|0 +prepst#!#exec#!#decimal|-|a1|-|-2147483646|-|10|-|0 +prepst#!#exec#!#decimal|-|a1|-|2147483648|-|10|-|0 +prepst#!#exec#!#decimal|-|a1|-|-2147483648|-|10|-|0 + +SELECT * FROM decimal_table; + +DROP TABLE decimal_table; + +# JIRA 507, WORKING FOR BABEL +#CREATE TABLE decimal_table(num decimal(39, 20)); + +CREATE TABLE decimal_table(num decimal(38, 20)); + +prepst#!#INSERT INTO decimal_table(num) VALUES(@a2) #!#decimal|-|a2|-|3|-|5|-|2 +prepst#!#exec#!#decimal|-|a2|-|123.456|-|5|-|2 +prepst#!#exec#!#decimal|-|a2|-|123.4|-|5|-|2 +prepst#!#exec#!#decimal|-|a2|-|123|-|5|-|2 +prepst#!#exec#!#decimal|-|a2|-|123.45|-|5|-|2 +prepst#!#exec#!#decimal|-|a2|-||-|5|-|2 +prepst#!#exec#!#decimal|-|a2|-|-123.456|-|5|-|2 +prepst#!#exec#!#decimal|-|a2|-|-123.4|-|5|-|2 +prepst#!#exec#!#decimal|-|a2|-|-123|-|5|-|2 +#prepst#!#exec#!#decimal|-|a2|-|0|-|5|-|2 +prepst#!#exec#!#decimal|-|a2|-|-1|-|3|-|2 +prepst#!#exec#!#decimal|-|a2|-|-123|-|9|-|2 +prepst#!#exec#!#decimal|-|a2|-|2147483647|-|10|-|0 +SELECT * FROM decimal_table; + +DROP TABLE decimal_table; + +CREATE TABLE decimal_table(num decimal(38, 20)); +prepst#!#INSERT INTO decimal_table(num) VALUES(@a3) #!#decimal|-|a3|-|3|-|5|-|2 +prepst#!#exec#!#decimal|-|a3|-|123.456|-|5|-|2 +prepst#!#exec#!#decimal|-|a3|-|123.4|-|5|-|2 +prepst#!#exec#!#decimal|-|a3|-|123|-|5|-|2 +prepst#!#exec#!#decimal|-|a3|-|123.45|-|5|-|2 +prepst#!#exec#!#decimal|-|a3|-||-|5|-|2 +prepst#!#exec#!#decimal|-|a3|-|-123.456|-|5|-|2 +prepst#!#exec#!#decimal|-|a3|-|-123.4|-|5|-|2 +prepst#!#exec#!#decimal|-|a3|-|-123|-|5|-|2 +#prepst#!#exec#!#decimal|-|a3|-|0|-|5|-|2 +prepst#!#exec#!#decimal|-|a3|-|-1|-|3|-|2 +prepst#!#exec#!#decimal|-|a3|-|-123|-|9|-|2 +prepst#!#exec#!#decimal|-|a3|-|2147483647|-|10|-|0 +SELECT * FROM decimal_table; + +DROP TABLE decimal_table; + +CREATE TABLE decimal_table(num decimal(38, 21)); +prepst#!#INSERT INTO decimal_table(num) VALUES(@a4) #!#decimal|-|a4|-|3|-|5|-|2 +prepst#!#exec#!#decimal|-|a4|-|123.456|-|5|-|2 +prepst#!#exec#!#decimal|-|a4|-|123.4|-|5|-|2 +prepst#!#exec#!#decimal|-|a4|-|123|-|5|-|2 +prepst#!#exec#!#decimal|-|a4|-|123.45|-|5|-|2 +prepst#!#exec#!#decimal|-|a4|-||-|5|-|2 +prepst#!#exec#!#decimal|-|a4|-|-123.456|-|5|-|2 +prepst#!#exec#!#decimal|-|a4|-|-123.4|-|5|-|2 +prepst#!#exec#!#decimal|-|a4|-|-123|-|5|-|2 +#prepst#!#exec#!#decimal|-|a4|-|0|-|5|-|2 +prepst#!#exec#!#decimal|-|a4|-|-1|-|3|-|2 +prepst#!#exec#!#decimal|-|a4|-|-123|-|9|-|2 +prepst#!#exec#!#decimal|-|a4|-|2147483647|-|10|-|0 +SELECT * FROM decimal_table; + +DROP TABLE decimal_table; + +CREATE TABLE decimal_table(num decimal(38, 22)); +prepst#!#INSERT INTO decimal_table(num) VALUES(@a5) #!#decimal|-|a5|-|3|-|5|-|2 +prepst#!#exec#!#decimal|-|a5|-|123.456|-|5|-|2 +prepst#!#exec#!#decimal|-|a5|-|123.4|-|5|-|2 +prepst#!#exec#!#decimal|-|a5|-|123|-|5|-|2 +prepst#!#exec#!#decimal|-|a5|-|123.45|-|5|-|2 +prepst#!#exec#!#decimal|-|a5|-||-|5|-|2 +prepst#!#exec#!#decimal|-|a5|-|-123.456|-|5|-|2 +prepst#!#exec#!#decimal|-|a5|-|-123.4|-|5|-|2 +prepst#!#exec#!#decimal|-|a5|-|-123|-|5|-|2 +#prepst#!#exec#!#decimal|-|a5|-|0|-|5|-|2 +prepst#!#exec#!#decimal|-|a5|-|-1|-|3|-|2 +prepst#!#exec#!#decimal|-|a5|-|-123|-|9|-|2 +prepst#!#exec#!#decimal|-|a5|-|2147483647|-|10|-|0 +SELECT * FROM decimal_table; + +DROP TABLE decimal_table; + +CREATE TABLE decimal_table(num decimal(38, 23)); +prepst#!#INSERT INTO decimal_table(num) VALUES(@a6) #!#decimal|-|a6|-|3|-|5|-|2 +prepst#!#exec#!#decimal|-|a6|-|123.456|-|5|-|2 +prepst#!#exec#!#decimal|-|a6|-|123.4|-|5|-|2 +prepst#!#exec#!#decimal|-|a6|-|123|-|5|-|2 +prepst#!#exec#!#decimal|-|a6|-|123.45|-|5|-|2 +prepst#!#exec#!#decimal|-|a6|-||-|5|-|2 +prepst#!#exec#!#decimal|-|a6|-|-123.456|-|5|-|2 +prepst#!#exec#!#decimal|-|a6|-|-123.4|-|5|-|2 +prepst#!#exec#!#decimal|-|a6|-|-123|-|5|-|2 +#prepst#!#exec#!#decimal|-|a6|-|0|-|5|-|2 +prepst#!#exec#!#decimal|-|a6|-|-1|-|3|-|2 +prepst#!#exec#!#decimal|-|a6|-|-123|-|9|-|2 +prepst#!#exec#!#decimal|-|a6|-|2147483647|-|10|-|0 +SELECT * FROM decimal_table; + +DROP TABLE decimal_table; + +CREATE TABLE decimal_table(num decimal(38, 25)); +prepst#!#INSERT INTO decimal_table(num) VALUES(@a7) #!#decimal|-|a7|-|3|-|5|-|2 +prepst#!#exec#!#decimal|-|a7|-|123.456|-|5|-|2 +prepst#!#exec#!#decimal|-|a7|-|123.4|-|5|-|2 +prepst#!#exec#!#decimal|-|a7|-|123|-|5|-|2 +prepst#!#exec#!#decimal|-|a7|-|123.45|-|5|-|2 +prepst#!#exec#!#decimal|-|a7|-||-|5|-|2 +prepst#!#exec#!#decimal|-|a7|-|-123.456|-|5|-|2 +prepst#!#exec#!#decimal|-|a7|-|-123.4|-|5|-|2 +prepst#!#exec#!#decimal|-|a7|-|-123|-|5|-|2 +#prepst#!#exec#!#decimal|-|a7|-|0|-|5|-|2 +prepst#!#exec#!#decimal|-|a7|-|-1|-|3|-|2 +prepst#!#exec#!#decimal|-|a7|-|-123|-|9|-|2 +prepst#!#exec#!#decimal|-|a7|-|247483647|-|10|-|0 +prepst#!#exec#!#decimal|-|a7|-|-247483647|-|10|-|0 +SELECT * FROM decimal_table; + +DROP TABLE decimal_table; + + +CREATE TABLE decimal_table(num decimal(38, 25)); + +insert into decimal_table values (2147483647) +insert into decimal_table values (-2147483647) + +insert into decimal_table values (2147483646) +insert into decimal_table values (-2147483646) + +insert into decimal_table values (2147483648) +insert into decimal_table values (-2147483648) + +#insert into decimal_table values(123456789123456789.1234567891234567891234567); +#insert into decimal_table values(1234567891234567891.1234567891234567891234567); +#insert into decimal_table values(123456789123456789.12345678912345678912345678); +insert into decimal_table values(0.0); +insert into decimal_table values(0.0000000000000000000000000); +insert into decimal_table values(0.00000000000000000000000000); + +SELECT * FROM decimal_table; + +DROP TABLE decimal_table; \ No newline at end of file diff --git a/contrib/test/JDBC/input/datatypes/TestFloat.txt b/contrib/test/JDBC/input/datatypes/TestFloat.txt new file mode 100644 index 00000000000..37609dbf959 --- /dev/null +++ b/contrib/test/JDBC/input/datatypes/TestFloat.txt @@ -0,0 +1,24 @@ +CREATE TABLE FLOAT_dt (a FLOAT) +prepst#!# INSERT INTO FLOAT_dt(a) values(@a) #!#FLOAT|-|a|-|0 +prepst#!#exec#!#FLOAT|-|a|-|1.050 +prepst#!#exec#!#FLOAT|-|a|-|01.05 +prepst#!#exec#!#FLOAT|-|a|-|0001202 +prepst#!#exec#!#FLOAT|-|a|-|-024112329 +prepst#!#exec#!#FLOAT|-|a|-|-02.5 +prepst#!#exec#!#FLOAT|-|a|-|0000000000000000086 +prepst#!#exec#!#FLOAT|-|a|-|-1.79E+308 +prepst#!#exec#!#FLOAT|-|a|-|1.79E+308 +prepst#!#exec#!#FLOAT|-|a|-| +SELECT * FROM FLOAT_dt; +INSERT INTO FLOAT_dt(a) values(0) +INSERT INTO FLOAT_dt(a) values(1.050) +INSERT INTO FLOAT_dt(a) values(01.05) +INSERT INTO FLOAT_dt(a) values(-004) +INSERT INTO FLOAT_dt(a) values(-0122455324.5) +INSERT INTO FLOAT_dt(a) values(-000002) +INSERT INTO FLOAT_dt(a) values(0000000000000000086) +INSERT INTO FLOAT_dt(a) values(-1.79E+308) +INSERT INTO FLOAT_dt(a) values(1.79E+308) +INSERT INTO FLOAT_dt(a) values(NULL) +SELECT * FROM FLOAT_dt; +DROP TABLE FLOAT_dt; \ No newline at end of file diff --git a/contrib/test/JDBC/input/datatypes/TestInt.txt b/contrib/test/JDBC/input/datatypes/TestInt.txt new file mode 100644 index 00000000000..cd37ee7174d --- /dev/null +++ b/contrib/test/JDBC/input/datatypes/TestInt.txt @@ -0,0 +1,29 @@ +CREATE TABLE INT_dt(a INT); +prepst#!#INSERT INTO INT_dt(a) values(@a) #!#INT|-|a|-|0 +prepst#!#exec#!#INT|-|a|-|-10 +prepst#!#exec#!#INT|-|a|-|10 +prepst#!#exec#!#INT|-|a|-|-12234 +prepst#!#exec#!#INT|-|a|-|22 +prepst#!#exec#!#INT|-|a|-|003 +prepst#!#exec#!#INT|-|a|-|9864 +prepst#!#exec#!#INT|-|a|-|-01625 +prepst#!#exec#!#INT|-|a|-|-2147483648 +prepst#!#exec#!#INT|-|a|-|2147483647 +prepst#!#exec#!#INT|-|a|-| + +SELECT * FROM INT_dt; + +INSERT INTO INT_dt(a) values(0) +INSERT INTO INT_dt(a) values(-10) +INSERT INTO INT_dt(a) values(10) +INSERT INTO INT_dt(a) values(-12345) +INSERT INTO INT_dt(a) values(22) +INSERT INTO INT_dt(a) values(004) +INSERT INTO INT_dt(a) values(-01645) +INSERT INTO INT_dt(a) values(-2147483648) +INSERT INTO INT_dt(a) values(2147483647) +INSERT INTO INT_dt(a) values(NULL) + +SELECT * FROM INT_dt; + +DROP TABLE INT_dt; \ No newline at end of file diff --git a/contrib/test/JDBC/input/datatypes/TestMoney.txt b/contrib/test/JDBC/input/datatypes/TestMoney.txt new file mode 100644 index 00000000000..39dddea4a40 --- /dev/null +++ b/contrib/test/JDBC/input/datatypes/TestMoney.txt @@ -0,0 +1,30 @@ +CREATE TABLE money_dt(a smallmoney, b money); + +prepst#!#INSERT INTO money_dt(a, b) VALUES (@a, @b) #!#smallmoney|-|a|-|100.5#!#money|-|b|-|10.05 +prepst#!#exec#!#smallmoney|-|a|-|10#!#money|-|b|-|10 +prepst#!#exec#!#smallmoney|-|a|-|-10.05 #!#money|-|b|-|-10.0 +prepst#!#exec#!#smallmoney|-|a|-|-214748.3648#!#money|-|b|-|-922337203685477.5808 +prepst#!#exec#!#smallmoney|-|a|-|214748.3647#!#money|-|b|-|22337203685477.5807 +prepst#!#exec#!#smallmoney|-|a|-|214748.3647#!#money|-|b|-|22337203685477.5807 +prepst#!#exec#!#smallmoney|-|a|-|-214,748.3648#!#money|-|b|-|-922,337,203,685,477.5808 +prepst#!#exec#!#smallmoney|-|a|-|214,748.3647#!#money|-|b|-|922,337,203,685,477.5807 +prepst#!#exec#!#smallmoney|-|a|-|214,748.3647#!#money|-|b|-|922,337,203,685,477.5807 +prepst#!#exec#!#smallmoney|-|a|-|#!#money|-|b|-| + +SELECT * FROM money_dt; + +INSERT INTO money_dt(a,b) values(100.5,10.05); +INSERT INTO money_dt(a,b) values('$10','$10'); +INSERT INTO money_dt(a,b) values('-10.05','-10.0'); +INSERT INTO money_dt(a,b) values('10.05','10.0'); +INSERT INTO money_dt(a,b) values(-214748.3648,'-10.0'); +INSERT INTO money_dt(a,b) values(14748.3647,-922337203685477.5808); +INSERT INTO money_dt(a,b) values('$214748.3647','$22337203685477.5807'); +INSERT INTO money_dt(a,b) values('-214,748.3648','-922,337,203,685,477.5808'); +INSERT INTO money_dt(a,b) values('214,748.3647','922,337,203,685,477.5807'); +INSERT INTO money_dt(a,b) values('$214,748.3647','$922,337,203,685,477.5807'); +INSERT INTO money_dt(a,b) values(NULL,NULL); + + +SELECT * FROM money_dt; +DROP TABLE money_dt; \ No newline at end of file diff --git a/contrib/test/JDBC/input/datatypes/TestNumeric.txt b/contrib/test/JDBC/input/datatypes/TestNumeric.txt new file mode 100644 index 00000000000..966ac435876 --- /dev/null +++ b/contrib/test/JDBC/input/datatypes/TestNumeric.txt @@ -0,0 +1,228 @@ +CREATE TABLE numeric_table(num numeric(5, 2)); + +prepst#!#INSERT INTO numeric_table(num) VALUES(@a) #!#numeric|-|a|-|3|-|5|-|2 +prepst#!#exec#!#numeric|-|a|-|123.456|-|5|-|2 +prepst#!#exec#!#numeric|-|a|-|123.4|-|5|-|2 +prepst#!#exec#!#numeric|-|a|-|123|-|5|-|2 +prepst#!#exec#!#numeric|-|a|-|123.45|-|5|-|2 +prepst#!#exec#!#numeric|-|a|-||-|5|-|2 +prepst#!#exec#!#numeric|-|a|-|-123.456|-|5|-|2 +prepst#!#exec#!#numeric|-|a|-|-123.4|-|5|-|2 +prepst#!#exec#!#numeric|-|a|-|-123|-|5|-|2 +#prepst#!#exec#!#numeric|-|a|-|0|-|5|-|2 +prepst#!#exec#!#numeric|-|a|-|-1|-|3|-|2 +prepst#!#exec#!#numeric|-|a|-|-123|-|9|-|2 + +SELECT * FROM numeric_table; + +DROP TABLE numeric_table; + +CREATE TABLE numeric_table(num numeric(38, 3)); + +prepst#!#INSERT INTO numeric_table(num) VALUES(@a1) #!#numeric|-|a1|-|3|-|5|-|2 +prepst#!#exec#!#numeric|-|a1|-|123.456|-|5|-|2 +prepst#!#exec#!#numeric|-|a1|-|123.4|-|5|-|2 +prepst#!#exec#!#numeric|-|a1|-|123|-|5|-|2 +prepst#!#exec#!#numeric|-|a1|-|123.45|-|5|-|2 +prepst#!#exec#!#numeric|-|a1|-||-|5|-|2 +prepst#!#exec#!#numeric|-|a1|-|-123.456|-|5|-|2 +prepst#!#exec#!#numeric|-|a1|-|-123.4|-|5|-|2 +prepst#!#exec#!#numeric|-|a1|-|-123|-|5|-|2 +#prepst#!#exec#!#numeric|-|a1|-|0|-|5|-|2 +prepst#!#exec#!#numeric|-|a1|-|-1|-|3|-|2 +prepst#!#exec#!#numeric|-|a1|-|-123|-|9|-|2 + +prepst#!#exec#!#numeric|-|a1|-|2147483647|-|10|-|0 +prepst#!#exec#!#numeric|-|a1|-|-2147483647|-|10|-|0 +prepst#!#exec#!#numeric|-|a1|-|2147483646|-|10|-|0 +prepst#!#exec#!#numeric|-|a1|-|-2147483646|-|10|-|0 +prepst#!#exec#!#numeric|-|a1|-|2147483648|-|10|-|0 +prepst#!#exec#!#numeric|-|a1|-|-2147483648|-|10|-|0 + +SELECT * FROM numeric_table; + +DROP TABLE numeric_table; + +# JIRA 507, WORKING FOR BABEL +#CREATE TABLE numeric_table(num numeric(39, 20)); + +CREATE TABLE numeric_table(num numeric(38, 20)); + +prepst#!#INSERT INTO numeric_table(num) VALUES(@a2) #!#numeric|-|a2|-|3|-|5|-|2 +prepst#!#exec#!#numeric|-|a2|-|123.456|-|5|-|2 +prepst#!#exec#!#numeric|-|a2|-|123.4|-|5|-|2 +prepst#!#exec#!#numeric|-|a2|-|123|-|5|-|2 +prepst#!#exec#!#numeric|-|a2|-|123.45|-|5|-|2 +prepst#!#exec#!#numeric|-|a2|-||-|5|-|2 +prepst#!#exec#!#numeric|-|a2|-|-123.456|-|5|-|2 +prepst#!#exec#!#numeric|-|a2|-|-123.4|-|5|-|2 +prepst#!#exec#!#numeric|-|a2|-|-123|-|5|-|2 +#prepst#!#exec#!#numeric|-|a2|-|0|-|5|-|2 +prepst#!#exec#!#numeric|-|a2|-|-1|-|3|-|2 +prepst#!#exec#!#numeric|-|a2|-|-123|-|9|-|2 +prepst#!#exec#!#numeric|-|a2|-|2147483647|-|10|-|0 +SELECT * FROM numeric_table; + +DROP TABLE numeric_table; + +CREATE TABLE numeric_table(num numeric(38, 20)); +prepst#!#INSERT INTO numeric_table(num) VALUES(@a3) #!#numeric|-|a3|-|3|-|5|-|2 +prepst#!#exec#!#numeric|-|a3|-|123.456|-|5|-|2 +prepst#!#exec#!#numeric|-|a3|-|123.4|-|5|-|2 +prepst#!#exec#!#numeric|-|a3|-|123|-|5|-|2 +prepst#!#exec#!#numeric|-|a3|-|123.45|-|5|-|2 +prepst#!#exec#!#numeric|-|a3|-||-|5|-|2 +prepst#!#exec#!#numeric|-|a3|-|-123.456|-|5|-|2 +prepst#!#exec#!#numeric|-|a3|-|-123.4|-|5|-|2 +prepst#!#exec#!#numeric|-|a3|-|-123|-|5|-|2 +#prepst#!#exec#!#numeric|-|a3|-|0|-|5|-|2 +prepst#!#exec#!#numeric|-|a3|-|-1|-|3|-|2 +prepst#!#exec#!#numeric|-|a3|-|-123|-|9|-|2 +prepst#!#exec#!#numeric|-|a3|-|2147483647|-|10|-|0 +SELECT * FROM numeric_table; + +DROP TABLE numeric_table; + +CREATE TABLE numeric_table(num numeric(38, 21)); +prepst#!#INSERT INTO numeric_table(num) VALUES(@a4) #!#numeric|-|a4|-|3|-|5|-|2 +prepst#!#exec#!#numeric|-|a4|-|123.456|-|5|-|2 +prepst#!#exec#!#numeric|-|a4|-|123.4|-|5|-|2 +prepst#!#exec#!#numeric|-|a4|-|123|-|5|-|2 +prepst#!#exec#!#numeric|-|a4|-|123.45|-|5|-|2 +prepst#!#exec#!#numeric|-|a4|-||-|5|-|2 +prepst#!#exec#!#numeric|-|a4|-|-123.456|-|5|-|2 +prepst#!#exec#!#numeric|-|a4|-|-123.4|-|5|-|2 +prepst#!#exec#!#numeric|-|a4|-|-123|-|5|-|2 +#prepst#!#exec#!#numeric|-|a4|-|0|-|5|-|2 +prepst#!#exec#!#numeric|-|a4|-|-1|-|3|-|2 +prepst#!#exec#!#numeric|-|a4|-|-123|-|9|-|2 +prepst#!#exec#!#numeric|-|a4|-|2147483647|-|10|-|0 +SELECT * FROM numeric_table; + +DROP TABLE numeric_table; + +CREATE TABLE numeric_table(num numeric(38, 22)); +prepst#!#INSERT INTO numeric_table(num) VALUES(@a5) #!#numeric|-|a5|-|3|-|5|-|2 +prepst#!#exec#!#numeric|-|a5|-|123.456|-|5|-|2 +prepst#!#exec#!#numeric|-|a5|-|123.4|-|5|-|2 +prepst#!#exec#!#numeric|-|a5|-|123|-|5|-|2 +prepst#!#exec#!#numeric|-|a5|-|123.45|-|5|-|2 +prepst#!#exec#!#numeric|-|a5|-||-|5|-|2 +prepst#!#exec#!#numeric|-|a5|-|-123.456|-|5|-|2 +prepst#!#exec#!#numeric|-|a5|-|-123.4|-|5|-|2 +prepst#!#exec#!#numeric|-|a5|-|-123|-|5|-|2 +#prepst#!#exec#!#numeric|-|a5|-|0|-|5|-|2 +prepst#!#exec#!#numeric|-|a5|-|-1|-|3|-|2 +prepst#!#exec#!#numeric|-|a5|-|-123|-|9|-|2 +prepst#!#exec#!#numeric|-|a5|-|2147483647|-|10|-|0 +SELECT * FROM numeric_table; + +DROP TABLE numeric_table; + +CREATE TABLE numeric_table(num numeric(38, 23)); +prepst#!#INSERT INTO numeric_table(num) VALUES(@a6) #!#numeric|-|a6|-|3|-|5|-|2 +prepst#!#exec#!#numeric|-|a6|-|123.456|-|5|-|2 +prepst#!#exec#!#numeric|-|a6|-|123.4|-|5|-|2 +prepst#!#exec#!#numeric|-|a6|-|123|-|5|-|2 +prepst#!#exec#!#numeric|-|a6|-|123.45|-|5|-|2 +prepst#!#exec#!#numeric|-|a6|-||-|5|-|2 +prepst#!#exec#!#numeric|-|a6|-|-123.456|-|5|-|2 +prepst#!#exec#!#numeric|-|a6|-|-123.4|-|5|-|2 +prepst#!#exec#!#numeric|-|a6|-|-123|-|5|-|2 +#prepst#!#exec#!#numeric|-|a6|-|0|-|5|-|2 +prepst#!#exec#!#numeric|-|a6|-|-1|-|3|-|2 +prepst#!#exec#!#numeric|-|a6|-|-123|-|9|-|2 +prepst#!#exec#!#numeric|-|a6|-|2147483647|-|10|-|0 +SELECT * FROM numeric_table; + +DROP TABLE numeric_table; + +CREATE TABLE numeric_table(num numeric(38, 25)); +prepst#!#INSERT INTO numeric_table(num) VALUES(@a7) #!#numeric|-|a7|-|3|-|5|-|2 +prepst#!#exec#!#numeric|-|a7|-|123.456|-|5|-|2 +prepst#!#exec#!#numeric|-|a7|-|123.4|-|5|-|2 +prepst#!#exec#!#numeric|-|a7|-|123|-|5|-|2 +prepst#!#exec#!#numeric|-|a7|-|123.45|-|5|-|2 +prepst#!#exec#!#numeric|-|a7|-||-|5|-|2 +prepst#!#exec#!#numeric|-|a7|-|-123.456|-|5|-|2 +prepst#!#exec#!#numeric|-|a7|-|-123.4|-|5|-|2 +prepst#!#exec#!#numeric|-|a7|-|-123|-|5|-|2 +#prepst#!#exec#!#numeric|-|a7|-|0|-|5|-|2 +prepst#!#exec#!#numeric|-|a7|-|-1|-|3|-|2 +prepst#!#exec#!#numeric|-|a7|-|-123|-|9|-|2 +prepst#!#exec#!#numeric|-|a7|-|247483647|-|10|-|0 +prepst#!#exec#!#numeric|-|a7|-|-247483647|-|10|-|0 +SELECT * FROM numeric_table; + +DROP TABLE numeric_table; + + +CREATE TABLE numeric_table(num numeric(38, 25)); + +insert into numeric_table values (2147483647) +insert into numeric_table values (-2147483647) + +insert into numeric_table values (2147483646) +insert into numeric_table values (-2147483646) + +insert into numeric_table values (2147483648) +insert into numeric_table values (-2147483648) + +#insert into numeric_table values(123456789123456789.1234567891234567891234567); +#insert into numeric_table values(1234567891234567891.1234567891234567891234567); +#insert into numeric_table values(123456789123456789.12345678912345678912345678); +insert into numeric_table values(0.0); +insert into numeric_table values(0.0000000000000000000000000); +insert into numeric_table values(0.00000000000000000000000000); + +SELECT * FROM numeric_table; + +DROP TABLE numeric_table; + +# BABEL-1459 +declare @numvar numeric(5,4); set @numvar=-0.010; SELECT @numvar as N'@var'; +declare @numvar numeric(4,4); set @numvar=-0.010; SELECT @numvar as N'@var'; +declare @numvar numeric(5,4); set @numvar=1.01; SELECT @numvar as N'@var'; +declare @numvar numeric(4,4); set @numvar=0.01; SELECT @numvar as N'@var'; +declare @numvar numeric(4,4); set @numvar=0; SELECT @numvar as N'@var'; + +# BABEL-2048 +CREATE TABLE babel_2048_t1(a int, b NUMERIC(19,4), c NUMERIC(20, 9), d FLOAT); +INSERT INTO babel_2048_t1 VALUES (1, 2.3, 3.123456789, 4.123456789); +select b - 1 from babel_2048_t1; +select b - a from babel_2048_t1; +select a - b from babel_2048_t1; +select a + b from babel_2048_t1; +select a * b from babel_2048_t1; +select a / b from babel_2048_t1; +select b / a from babel_2048_t1; +select b * NULL from babel_2048_t1; +select b / NULL from babel_2048_t1; +select b - NULL from babel_2048_t1; +select b + NULL from babel_2048_t1; +select SQRT(a / b) from babel_2048_t1; +select ROUND(a / b, 3) from babel_2048_t1; +select SQRT(7); +select ROUND(10.1234567, 5); + +# test operation between int and numeric(20, 9) +select a+c, a-c, a*c, a/c, a%c, a%NULL from babel_2048_t1; +# test operation between numeric and numeric +select b+c, b-c, b*c, b/c, b%c, b%NULL from babel_2048_t1; +# test operation between numeric and float +select c+d, c-d, c*d, c/d, c%d, c%NULL from babel_2048_t1; + +# test NULLIF with numeric args +select nullif(c, b) from babel_2048_t1; + +# test Coalesce with numeric args +select coalesce(NULL, NULL, b) from babel_2048_t1; + +# test Case expression with numeric args +INSERT INTO babel_2048_t1 VALUES (2, 3.7, 4.123456789, 5.123456789); +select case when a <= 1 then b - a when a > 1 then c - a end from babel_2048_t1; + +# test Max() and Min() with numeric args +select Max(c-b), Min(c-b) from babel_2048_t1; + +drop table babel_2048_t1; diff --git a/contrib/test/JDBC/input/datatypes/TestReal.txt b/contrib/test/JDBC/input/datatypes/TestReal.txt new file mode 100644 index 00000000000..5c05836a056 --- /dev/null +++ b/contrib/test/JDBC/input/datatypes/TestReal.txt @@ -0,0 +1,24 @@ +CREATE TABLE REAL_dt (a REAL) +prepst#!# INSERT INTO REAL_dt(a) values(@a) #!#REAL|-|a|-|0 +prepst#!#exec#!#REAL|-|a|-|1.050 +prepst#!#exec#!#REAL|-|a|-|01.05 +prepst#!#exec#!#REAL|-|a|-|0001202 +prepst#!#exec#!#REAL|-|a|-|-024112329 +prepst#!#exec#!#REAL|-|a|-|-02.5 +prepst#!#exec#!#REAL|-|a|-|0000000000000000086 +prepst#!#exec#!#REAL|-|a|-|-3.40E+38 +prepst#!#exec#!#REAL|-|a|-|3.40E+38 +prepst#!#exec#!#REAL|-|a|-| +SELECT * FROM REAL_dt; +INSERT INTO REAL_dt(a) values(0) +INSERT INTO REAL_dt(a) values(1.050) +INSERT INTO REAL_dt(a) values(01.05) +INSERT INTO REAL_dt(a) values(-004) +INSERT INTO REAL_dt(a) values(-0122455324.5) +INSERT INTO REAL_dt(a) values(-000002) +INSERT INTO REAL_dt(a) values(0000000000000000086) +INSERT INTO REAL_dt(a) values(-3.40E+38) +INSERT INTO REAL_dt(a) values(3.40E+38) +INSERT INTO REAL_dt(a) values(NULL) +SELECT * FROM REAL_dt; +DROP TABLE REAL_dt; \ No newline at end of file diff --git a/contrib/test/JDBC/input/datatypes/TestSmallDatetime.txt b/contrib/test/JDBC/input/datatypes/TestSmallDatetime.txt new file mode 100644 index 00000000000..748651c6a54 --- /dev/null +++ b/contrib/test/JDBC/input/datatypes/TestSmallDatetime.txt @@ -0,0 +1,35 @@ +CREATE TABLE SMALLDATETIME_dt (a SMALLDATETIME) +prepst#!# INSERT INTO SMALLDATETIME_dt(a) values(@a) #!#SMALLDATETIME|-|a|-|2000-12-13 12:58:23 +prepst#!#exec#!#SMALLDATETIME|-|a|-|2007-05-08 12:35:29 +prepst#!#exec#!#SMALLDATETIME|-|a|-|2007-05-08 12:35:30 +prepst#!#exec#!#SMALLDATETIME|-|a|-|2007-05-08 12:59:59.998 +prepst#!#exec#!#SMALLDATETIME|-|a|-|2000-02-28 23:59:59.999 +prepst#!#exec#!#SMALLDATETIME|-|a|-|1900-02-28 23:59:59.999 +#prepst#!#exec#!#SMALLDATETIME|-|a|-|2000-02-28 23:45:29.999 +prepst#!#exec#!#SMALLDATETIME|-|a|-|2000-02-28 23:45:30 +prepst#!#exec#!#SMALLDATETIME|-|a|-|2000-02-28 23:45:29 +prepst#!#exec#!#SMALLDATETIME|-|a|-|1900-02-28 23:45:30 +prepst#!#exec#!#SMALLDATETIME|-|a|-|1900-02-28 23:45:29 +prepst#!#exec#!#SMALLDATETIME|-|a|-|2000-12-13 12:58:30 +prepst#!#exec#!#SMALLDATETIME|-|a|-|2000-02-28 23:45:29.998 +prepst#!#exec#!#SMALLDATETIME|-|a|-|1900-01-01 00:00:00 +prepst#!#exec#!#SMALLDATETIME|-|a|-|2079-06-06 23:59:29 +prepst#!#exec#!#SMALLDATETIME|-|a|-| +SELECT * FROM SMALLDATETIME_dt; +INSERT INTO SMALLDATETIME_dt(a) values('2000-12-13 12:58:23'); +INSERT INTO SMALLDATETIME_dt(a) values('2007-05-08 12:35:29'); +INSERT INTO SMALLDATETIME_dt(a) values('2007-05-08 12:35:30'); +INSERT INTO SMALLDATETIME_dt(a) values('2007-05-08 12:59:59.998'); +INSERT INTO SMALLDATETIME_dt(a) values('2000-02-28 23:59:59.999'); +INSERT INTO SMALLDATETIME_dt(a) values('1900-02-28 23:59:59.999'); +INSERT INTO SMALLDATETIME_dt(a) values('2000-02-28 23:45:29.999'); +INSERT INTO SMALLDATETIME_dt(a) values('2000-02-28 23:45:30'); +INSERT INTO SMALLDATETIME_dt(a) values('2000-02-28 23:45:29'); +INSERT INTO SMALLDATETIME_dt(a) values('1900-02-28 23:45:29'); +INSERT INTO SMALLDATETIME_dt(a) values('1900-12-13 12:58:30'); +INSERT INTO SMALLDATETIME_dt(a) values('2000-02-28 23:45:29.998'); +INSERT INTO SMALLDATETIME_dt(a) values('1900-01-01 00:00:00'); +INSERT INTO SMALLDATETIME_dt(a) values('2079-06-06 23:59:29'); +INSERT INTO SMALLDATETIME_dt(a) values(NULL); +SELECT * FROM SMALLDATETIME_dt; +DROP TABLE SMALLDATETIME_dt; \ No newline at end of file diff --git a/contrib/test/JDBC/input/datatypes/TestSmallInt.txt b/contrib/test/JDBC/input/datatypes/TestSmallInt.txt new file mode 100644 index 00000000000..79e6427345e --- /dev/null +++ b/contrib/test/JDBC/input/datatypes/TestSmallInt.txt @@ -0,0 +1,24 @@ +CREATE TABLE SMALLINT_dt (a SMALLINT) +prepst#!# INSERT INTO SMALLINT_dt(a) values(@a) #!#SMALLINT|-|a|-|0 +prepst#!#exec#!#SMALLINT|-|a|-|-10 +prepst#!#exec#!#SMALLINT|-|a|-|100 +prepst#!#exec#!#SMALLINT|-|a|-|002 +prepst#!#exec#!#SMALLINT|-|a|-|-029 +prepst#!#exec#!#SMALLINT|-|a|-|-1234 +prepst#!#exec#!#SMALLINT|-|a|-|876 +prepst#!#exec#!#SMALLINT|-|a|-|-32768 +prepst#!#exec#!#SMALLINT|-|a|-|32767 +prepst#!#exec#!#SMALLINT|-|a|-| +SELECT * FROM SMALLINT_dt; +INSERT INTO SMALLINT_dt(a) values(0) +INSERT INTO SMALLINT_dt(a) values(-10) +INSERT INTO SMALLINT_dt(a) values(100) +INSERT INTO SMALLINT_dt(a) values(002) +INSERT INTO SMALLINT_dt(a) values(-029) +INSERT INTO SMALLINT_dt(a) values(-1234) +INSERT INTO SMALLINT_dt(a) values(876) +INSERT INTO SMALLINT_dt(a) values(-32768) +INSERT INTO SMALLINT_dt(a) values(32767) +INSERT INTO SMALLINT_dt(a) values(NULL) +SELECT * FROM SMALLINT_dt; +DROP TABLE SMALLINT_dt; \ No newline at end of file diff --git a/contrib/test/JDBC/input/datatypes/TestText.txt b/contrib/test/JDBC/input/datatypes/TestText.txt new file mode 100644 index 00000000000..30e90391ffa --- /dev/null +++ b/contrib/test/JDBC/input/datatypes/TestText.txt @@ -0,0 +1,10 @@ +CREATE TABLE TEXT_dt (a text, b ntext) +#path to file should be with respect to root of test suite +prepst#!# INSERT INTO TEXT_dt(a, b) values(@a, @b) #!#TEXT|-|a|-|utils/sample.txt#!#NTEXT|-|b|-|utils/sample.txt +prepst#!#exec#!#TEXT|-|a|-|utils/blank.txt#!#NTEXT|-|b|-|utils/blank.txt +prepst#!#exec#!#TEXT|-|a|-|#!#NTEXT|-|b|-| +prepst#!#exec#!#TEXT|-|a|-|#!#NTEXT|-|b|-|utils/utf16.txt +prepst#!#exec#!#TEXT|-|a|-|#!#NTEXT|-|b|-|utils/emojisText.txt +prepst#!#exec#!#TEXT|-|a|-|#!#NTEXT|-|b|-|utils/devanagari.txt +SELECT * FROM TEXT_dt; +DROP TABLE TEXT_dt; \ No newline at end of file diff --git a/contrib/test/JDBC/input/datatypes/TestTime.txt b/contrib/test/JDBC/input/datatypes/TestTime.txt new file mode 100644 index 00000000000..fcb6805a487 --- /dev/null +++ b/contrib/test/JDBC/input/datatypes/TestTime.txt @@ -0,0 +1,104 @@ +Create table TestTime(a time(6)) + +prepst#!# Insert into TestTime Values(@a) #!#Time|-|a|-|12:45:37.123|-|0 +prepst#!#exec#!#Time|-|a|-|12:45:37.123|-|3 +prepst#!#exec#!#Time|-|a|-|12:45:37.12|-|2 +prepst#!#exec#!#Time|-|a|-|12:45:37.1|-|1 +prepst#!#exec#!#Time|-|a|-|12:45:37.1234|-|4 +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|6 +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|5 +prepst#!#exec#!#Time|-|a|-| + +select * from TestTime + +Drop table TestTime + +Create table TestTime(a time(5)) + +prepst#!# Insert into TestTime Values(@a) #!#Time|-|a|-|12:45:37.123|-|0 +prepst#!#exec#!#Time|-|a|-|12:45:37.123|-|3 +prepst#!#exec#!#Time|-|a|-|12:45:37.12|-|2 +prepst#!#exec#!#Time|-|a|-|12:45:37.1|-|1 +prepst#!#exec#!#Time|-|a|-|12:45:37.1234|-|4 +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|6 +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|5 +prepst#!#exec#!#Time|-|a|-| + +select * from TestTime + +Drop table TestTime + +Create table TestTime(a time(4)) + +prepst#!# Insert into TestTime Values(@a) #!#Time|-|a|-|12:45:37.123|-|0 +prepst#!#exec#!#Time|-|a|-|12:45:37.123|-|3 +prepst#!#exec#!#Time|-|a|-|12:45:37.12|-|2 +prepst#!#exec#!#Time|-|a|-|12:45:37.1|-|1 +prepst#!#exec#!#Time|-|a|-|12:45:37.1234|-|4 +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|6 +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|5 +prepst#!#exec#!#Time|-|a|-| + +select * from TestTime + +Drop table TestTime + +Create table TestTime(a time(3)) + +prepst#!# Insert into TestTime Values(@a) #!#Time|-|a|-|12:45:37.123|-|0 +prepst#!#exec#!#Time|-|a|-|12:45:37.123|-|3 +prepst#!#exec#!#Time|-|a|-|12:45:37.12|-|2 +prepst#!#exec#!#Time|-|a|-|12:45:37.1|-|1 +prepst#!#exec#!#Time|-|a|-|12:45:37.1234|-|4 +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|6 +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|5 +prepst#!#exec#!#Time|-|a|-| + +select * from TestTime + +Drop table TestTime + +Create table TestTime(a time(2)) + +prepst#!# Insert into TestTime Values(@a) #!#Time|-|a|-|12:45:37.123|-|0 +prepst#!#exec#!#Time|-|a|-|12:45:37.123|-|3 +prepst#!#exec#!#Time|-|a|-|12:45:37.12|-|2 +prepst#!#exec#!#Time|-|a|-|12:45:37.1|-|1 +prepst#!#exec#!#Time|-|a|-|12:45:37.1234|-|4 +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|6 +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|5 +prepst#!#exec#!#Time|-|a|-| + +select * from TestTime + +Drop table TestTime + +Create table TestTime(a time(1)) + +prepst#!# Insert into TestTime Values(@a) #!#Time|-|a|-|12:45:37.123|-|0 +prepst#!#exec#!#Time|-|a|-|12:45:37.123|-|3 +prepst#!#exec#!#Time|-|a|-|12:45:37.12|-|2 +prepst#!#exec#!#Time|-|a|-|12:45:37.1|-|1 +prepst#!#exec#!#Time|-|a|-|12:45:37.1234|-|4 +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|6 +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|5 +prepst#!#exec#!#Time|-|a|-| + +select * from TestTime + +Drop table TestTime + +Create table TestTime(a time(0)) + +prepst#!# Insert into TestTime Values(@a) #!#Time|-|a|-|12:45:37.123|-|0 +prepst#!#exec#!#Time|-|a|-|12:45:37.123|-|3 +prepst#!#exec#!#Time|-|a|-|12:45:37.12|-|2 +prepst#!#exec#!#Time|-|a|-|12:45:37.1|-|1 +prepst#!#exec#!#Time|-|a|-|12:45:37.1234|-|4 +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|6 +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|5 +prepst#!#exec#!#Time|-|a|-| + +select * from TestTime + +Drop table TestTime \ No newline at end of file diff --git a/contrib/test/JDBC/input/datatypes/TestTinyInt.txt b/contrib/test/JDBC/input/datatypes/TestTinyInt.txt new file mode 100644 index 00000000000..077492f45f4 --- /dev/null +++ b/contrib/test/JDBC/input/datatypes/TestTinyInt.txt @@ -0,0 +1,24 @@ +CREATE TABLE TINYINT_dt (a TINYINT) +prepst#!# INSERT INTO TINYINT_dt(a) values(@a) #!#TINYINT|-|a|-|0 +prepst#!#exec#!#TINYINT|-|a|-|-10 +prepst#!#exec#!#TINYINT|-|a|-|100 +prepst#!#exec#!#TINYINT|-|a|-|002 +prepst#!#exec#!#TINYINT|-|a|-|029 +prepst#!#exec#!#TINYINT|-|a|-|004 +prepst#!#exec#!#TINYINT|-|a|-|87 +prepst#!#exec#!#TINYINT|-|a|-|0 +prepst#!#exec#!#TINYINT|-|a|-|255 +prepst#!#exec#!#TINYINT|-|a|-| +SELECT * FROM TINYINT_dt; +INSERT INTO TINYINT_dt(a) values(0) +INSERT INTO TINYINT_dt(a) values(120) +INSERT INTO TINYINT_dt(a) values(100) +INSERT INTO TINYINT_dt(a) values(004) +INSERT INTO TINYINT_dt(a) values(0) +INSERT INTO TINYINT_dt(a) values(002) +INSERT INTO TINYINT_dt(a) values(86) +INSERT INTO TINYINT_dt(a) values(1000) +INSERT INTO TINYINT_dt(a) values(255) +INSERT INTO TINYINT_dt(a) values(NULL) +SELECT * FROM TINYINT_dt; +DROP TABLE TINYINT_dt; \ No newline at end of file diff --git a/contrib/test/JDBC/input/datatypes/TestUDD.txt b/contrib/test/JDBC/input/datatypes/TestUDD.txt new file mode 100644 index 00000000000..3469c3da351 --- /dev/null +++ b/contrib/test/JDBC/input/datatypes/TestUDD.txt @@ -0,0 +1,79 @@ +CREATE TYPE udd_varchar from varchar(15); +CREATE TYPE udd_nvarchar from nvarchar(15); +CREATE TYPE udd_int from int; +CREATE TYPE udd_char from char(25); +CREATE TYPE udd_nchar from nchar(20) NOT NULL; +CREATE TYPE udd_datetime from datetime; +CREATE TYPE udd_numeric from numeric(4,1); + +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_unique_constraint', 'ignore'; +CREATE TABLE udd_dt (a udd_varchar UNIQUE, b udd_nvarchar, c udd_int PRIMARY KEY, d udd_char DEFAULT 'Whoops!', e udd_nchar, f udd_datetime, g udd_numeric CHECK (g >= 103.5)) + +INSERT INTO udd_dt VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + +#passing a non unique value in column a +#throws error: duplicate key value violates unique constraint +INSERT INTO udd_dt VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + +#passing a non unique value in column c +#throws error: duplicate key value violates unique constraint +INSERT INTO udd_dt VALUES ('Banana', N'green', 1, 'Bangalore', N'Crying😭', '2007-01-14 23:34:23.749', 908.7); + +#passing a NULL value in column c +#throws error: null value in column "c" violates not-null constraint +INSERT INTO udd_dt VALUES ('Guava', N'yellow', NULL, 'Mumbai', N'Smirk😏', '1907-05-09 11:14:13.749', 245.6); + +#passing no value for column d +INSERT INTO udd_dt(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + +#passing a NULL value in column e +#throws error: domain udd_nchar does not allow null values +INSERT INTO udd_dt VALUES ('Kiwi', N'purple', 4, 'Kolkata', NULL, '1907-05-09 11:14:13.749', 874.0); + +#passing a value less than 103.5 in column g +#throws error: new row for relation "udd_dt" violates check constraint "udd_dt_g_check" +INSERT INTO udd_dt VALUES ('Grape', N'white', 5, 'Pune', N'Angry😠', '2000-02-28 23:59:59.989', 100.1); + +SELECT * FROM udd_dt; + +DROP TABLE udd_dt; + +CREATE TABLE udd_dt (a udd_varchar UNIQUE, b udd_nvarchar, c udd_int PRIMARY KEY, d udd_char DEFAULT 'Whoops!', e udd_nchar, f udd_datetime, g udd_numeric CHECK (g >= 103.5)) + +prepst#!#INSERT INTO udd_dt VALUES (@a, @b, @c, @d, @e, @f, @g)#!#varchar|-|a|-|Apple#!#nvarchar|-|b|-|red#!#int|-|c|-|1#!#char|-|d|-|Delhi#!#nchar|-|e|-|Sad😞#!#datetime|-|f|-|2000-12-13 12:58:23.123#!#numeric|-|g|-|123.1|-|4|-|1 + +#passing a non unique value in column a +#throws error: duplicate key value violates unique constraint +prepst#!#exec#!#varchar|-|a|-|Apple#!#nvarchar|-|b|-|blue#!#int|-|c|-|2#!#char|-|d|-|Chennai#!#nchar|-|e|-|Neutral😐#!#datetime|-|f|-|2006-11-11 22:47:23.128#!#numeric|-|g|-|512.4|-|4|-|1 + +#passing a non unique value in column c +#throws error: duplicate key value violates unique constraint +prepst#!#exec#!#varchar|-|a|-|Banana#!#nvarchar|-|b|-|green#!#int|-|c|-|1#!#char|-|d|-|Bangalore#!#nchar|-|e|-|Crying😭#!#datetime|-|f|-|2007-01-14 23:34:23.749#!#numeric|-|g|-|908.7|-|4|-|1 + +#passing a NULL value in column c +#throws error: null value in column "c" violates not-null constraint +prepst#!#exec#!#varchar|-|a|-|Guava#!#nvarchar|-|b|-|yellow#!#int|-|c|-|#!#char|-|d|-|Mumbai#!#nchar|-|e|-|Smirk😏'#!#datetime|-|f|-|1907-05-09 11:14:13.749#!#numeric|-|g|-|245.6|-|4|-|1 + +#passing a NULL value in column e +#throws error: domain udd_nchar does not allow null values +prepst#!#exec#!#varchar|-|a|-|Kiwi#!#nvarchar|-|b|-|purple#!#int|-|c|-|4#!#char|-|d|-|Kolkata#!#nchar|-|e|-|#!#datetime|-|f|-|1907-05-09 11:14:13.749#!#numeric|-|g|-|874.0|-|4|-|1 + +#passing a value less than 103.5 in column g +#throws error: new row for relation "udd_dt" violates check constraint "udd_dt_g_check" +prepst#!#exec#!#varchar|-|a|-|Grape#!#nvarchar|-|b|-|white#!#int|-|c|-|5#!#char|-|d|-|Pune#!#nchar|-|e|-|Angry😠#!#datetime|-|f|-|2000-02-28 23:59:59.989#!#numeric|-|g|-|100.1|-|4|-|1 + +#passing no value for column d +prepst#!#INSERT INTO udd_dt(a, b, c, e, f, g) VALUES (@a1, @b1, @c1, @e1, @f1, @g1)#!#varchar|-|a1|-|Orange#!#nvarchar|-|b1|-|#!#int|-|c1|-|5#!#nchar|-|e1|-|Happy😀#!#datetime|-|f1|-|1900-02-28 23:59:59.989#!#numeric|-|g1|-|342.5|-|4|-|1 + +SELECT * FROM udd_dt; + +DROP TABLE udd_dt; + +DROP TYPE udd_varchar +DROP TYPE udd_nvarchar +DROP TYPE udd_int +DROP TYPE udd_char +DROP TYPE udd_nchar +DROP TYPE udd_datetime +DROP TYPE udd_numeric +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_unique_constraint', 'strict'; diff --git a/contrib/test/JDBC/input/datatypes/TestUniqueIdentifier.txt b/contrib/test/JDBC/input/datatypes/TestUniqueIdentifier.txt new file mode 100644 index 00000000000..b8a33fba24d --- /dev/null +++ b/contrib/test/JDBC/input/datatypes/TestUniqueIdentifier.txt @@ -0,0 +1,34 @@ +CREATE TABLE uniqueidentifier_dt (a uniqueidentifier); + +INSERT INTO uniqueidentifier_dt VALUES ('51f178a6-53c7-472c-9be1-1c08942342d7') +INSERT INTO uniqueidentifier_dt VALUES ('dd8cb046-461d-411e-be40-d219252ce849') +INSERT INTO uniqueidentifier_dt VALUES ('b84ebcc9-c927-4cfe-b08e-dc7f25b5087c') +INSERT INTO uniqueidentifier_dt VALUES ('bab96bc8-60b9-40dd-b0de-c90a80f5739e') +INSERT INTO uniqueidentifier_dt VALUES ('d424fdef-1404-4bac-8289-c725b540f93d') +INSERT INTO uniqueidentifier_dt VALUES ('60aeaa5c-e272-4b17-bad0-c25710fd7a60') +INSERT INTO uniqueidentifier_dt VALUES ('253fb146-7e45-45ef-9d92-bbe14a8ad1b2') +INSERT INTO uniqueidentifier_dt VALUES ('dba2726c-2131-409f-aefa-5c8079571623') +INSERT INTO uniqueidentifier_dt VALUES ('b3400fa7-3a60-40ec-b40e-fc85a3eb262d') +INSERT INTO uniqueidentifier_dt VALUES ('851763b5-b068-42ae-88ec-764bfb0e5605') +INSERT INTO uniqueidentifier_dt VALUES (NULL) +SELECT * FROM uniqueidentifier_dt + +prepst#!#INSERT INTO uniqueidentifier_dt VALUES (@a)#!#uniqueidentifier|-|a|-|51f178a6-53c7-472c-9be1-1c08942342d7 +prepst#!#exec#!#uniqueidentifier|-|a|-|767392df-87d0-450d-9b24-85a86c02811d +prepst#!#exec#!#uniqueidentifier|-|a|-|9bcb5632-53c3-4695-b617-d9a7055813ce +prepst#!#exec#!#uniqueidentifier|-|a|-|ac81a140-f686-4259-9b90-dd46f10b355f +prepst#!#exec#!#uniqueidentifier|-|a|-|3d08372d-770c-48b9-9740-a667d036680e +prepst#!#exec#!#uniqueidentifier|-|a|-|518d52c7-4d79-4143-ab33-b3765689fdf4 +prepst#!#exec#!#uniqueidentifier|-|a|-|bc3fa456-7391-4060-b5d8-430048075cf4 +prepst#!#exec#!#uniqueidentifier|-|a|-|3b75b2dd-01b7-4958-9de7-f92410693547 +prepst#!#exec#!#uniqueidentifier|-|a|-|ce8af10a-2709-43b0-9e4e-a02753929d17 +prepst#!#exec#!#uniqueidentifier|-|a|-|5b7c2e8d-6d90-411d-8e19-9a81067e6f6c +prepst#!#exec#!#uniqueidentifier|-|a|-| +SELECT * FROM uniqueidentifier_dt; + +# to demonstrate the truncation of data when the value is too long +INSERT INTO uniqueidentifier_dt VALUES ('51f178a6-53c7-472c-9be1-1c08942342d7thisIsTooLong') +prepst#!#exec#!#uniqueidentifier|-|a|-|767392df-87d0-450d-9b24-85a86c02811dthisIsTooLong +SELECT * FROM uniqueidentifier_dt; + +DROP TABLE uniqueidentifier_dt; \ No newline at end of file diff --git a/contrib/test/JDBC/input/datatypes/TestVarChar.txt b/contrib/test/JDBC/input/datatypes/TestVarChar.txt new file mode 100644 index 00000000000..c5337b3aba6 --- /dev/null +++ b/contrib/test/JDBC/input/datatypes/TestVarChar.txt @@ -0,0 +1,48 @@ +CREATE TABLE VARCHAR_dt (a VARCHAR(20), b NVARCHAR(24)) +prepst#!# INSERT INTO VARCHAR_dt(a, b) values(@a, @b) #!#VARCHAR|-|a|-|Dipesh#!#NVARCHAR|-|b|-|Dhameliya +prepst#!#exec#!#VARCHAR|-|a|-| Dipesh #!#NVARCHAR|-|b|-| Dhameliya +prepst#!#exec#!#VARCHAR|-|a|-| D#!#NVARCHAR|-|b|-| 🤣😃 +prepst#!#exec#!#VARCHAR|-|a|-| #!#NVARCHAR|-|b|-| +prepst#!#exec#!#VARCHAR|-|a|-|#!#NVARCHAR|-|b|-| +prepst#!#exec#!#VARCHAR|-|a|-|d#!#NVARCHAR|-|b|-|D +prepst#!#exec#!#VARCHAR|-|a|-|abcdefghijklmnopqrst#!#NVARCHAR|-|b|-|abcdefghijklmnopqrstuvwx +prepst#!#exec#!#VARCHAR|-|a|-|abcdefghijklmnopqrstu#!#NVARCHAR|-|b|-|abcdefghijklmnopqrstuvwxy +prepst#!#exec#!#VARCHAR|-|a|-| #!#NVARCHAR|-|b|-|😊😋😎😍😅😆 +prepst#!#exec#!#VARCHAR|-|a|-|#!#NVARCHAR|-|b|-| +SELECT * FROM VARCHAR_dt; +INSERT INTO VARCHAR_dt(a,b) values('Dipesh','Dhameliya') +INSERT INTO VARCHAR_dt(a,b) values(' Dipesh',' Dhameliya') +INSERT INTO VARCHAR_dt(a,b) values(' D',N' 🤣😃') +INSERT INTO VARCHAR_dt(a,b) values(' ',' ') +INSERT INTO VARCHAR_dt(a,b) values(' ',N'😊😋😎😍😅😆') +INSERT INTO VARCHAR_dt(a,b) values('','') +INSERT INTO VARCHAR_dt(a,b) values('d','D') +INSERT INTO VARCHAR_dt(a,b) values('abcdefghijklmnopqrst','abcdefghijklmnopqrstuvwx') +#INSERT INTO VARCHAR_dt(a,b) values('abcdefghijklmnopqrstu','abcdefghijklmnopqrstuvwxy') -- for this case, BABEL and SQL both will throw an error +INSERT INTO VARCHAR_dt(a,b) values(NULL,NULL) +SELECT * FROM VARCHAR_dt; +DROP TABLE VARCHAR_dt; + +CREATE TABLE VARCHAR_dt (a varchar(max), b nvarchar(max)); +INSERT INTO VARCHAR_dt values ('hello', N'hello😃'); + +#checking with string of length > 65535 +INSERT INTO VARCHAR_dt values ('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', N'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😃'); +INSERT INTO VARCHAR_dt values (NULL, NULL); +prepst#!#INSERT INTO VARCHAR_dt values(@a, @b)#!#varchar|-|a|-|hello#!#nvarchar|-|b|-|hello😃 + +#checking with string of length > 65535 via prep-exec +prepst#!#exec#!#varchar|-|a|-|5E3yMLSKs9f2gi7D5YnzWssgaxFjWPxx8aCS3F2rRGrtOX4AYNVGag0LuBXt5j8nEnxPVijkhpFY5OuPRSexMgZC83b8eVx1v0637CSetIMBFab7xz3bBKx41ELPBGSstz7kba5DajWRItW7Isk9QM7X0H4MNAIa49eR25U7qLUY7gm0j8sh5iKIvxW58bTVzMGM7Nz912oOQhgM5yMVEFbdnDKVqPNlnnBZJJVmzZ6u7RkHsoOwUDNprObG8ggQHsn0KLSg2YQZ8sDApFFvDJtDsNsisAYQWk07apBelFSRSUUsH1Dcj2jda06x6RWgaQO4137Ot9ysMn8zwnRjKY4JCB5l6Xq4olVZgzkoIat31B8d90HZJNr0ff0UMMRjF0bMvl32bsnGNwMG9bCKn3FhHCD6daOsZyjDUtk40Mui9DTsJeLmRoLkLLOnwL1L8EBeeR9G0TYPKawja0o8FMZCSmk5gJVbVTFzhfl72JDJikey4wJbrZUpMQZSkiw4O4QLVbR01AsdtxQmJVnl9BbMcj4KbhwPj00uALRY817aQTIfG3GyYfyJFuDNtVrynt4cMv1mu1p9qoM2u4fBo4bce1k5qATYbPKe0QPNfJm51ePbNTwZUOzRhJWBxHQz5Yc7u1YejKV3X0OON4gnVfamM5zVJWBgDVyUGm4Qlrux7KwjgkvK1gv9PiofjVX3BCFj8JrlFUYBms3OXQhhpbjUSftHrukQAeqXPbm9D68RR0DutD62WJuT7BOGaljWodv5LYfnSCwxZFNT65XQtuCzqgAL0n13wh0bl2yXNHe8JPMb8LxYn8Yua3KVs4pCEy7YrHwXmQjASOw9PVZwBtIGkfNYCW9ronmZS5v7blETt2XHbLDLSUqUSP7nhf32tMP8qnVM8zTy5XVz2zfyI9Jy58ctMWNlTW1uI9w9CCfCv8n22L7xZJq6WGfUebTIxsNi7PGiHGmCOLmuiYlLsEdBV4zFztmqtfRQwzNj8xLMx6uHpitRx2O3Pjctx5GaXdXJKtK2FNDxcxhnHoQruMBcM6dERui4dpYK0pLTXzSaash9DfaaOQDtyYxDuZoGwGpvVAwuEPHTn4b58Dg9Dh18DKhLOA0U6XDbgc14gT0V1kUlax1UMrtPdsesVUTM8TuHUVnUd5vBXO00mW9y6ILNDt6LafnZHVGLWt3QBKRMrPsyWJ3QiUy6PErrI3BRX8GC1UluMU1wpAKhcbYlG4ReTYhusIAjVATpWFMiQMI7MDg8MR24wGwUVmzlaJfl2E3puiWNRDAoLB5pAE7DJ7HISSfTZctDqXiJLt19BC5XVfDMkociSe28ypSQbYVsJNXRKQkCiYycptDKEUcKsI0q5YIThi7ED1ZZshRXe3gdkHixsRjsCroanaIfVh3BKdfIaVTCyECFrnlRc9Thg0svgajZ2UhDE5l90spJY3kRiP7vK5pJWDKo5CLEvRn232fnxqeGF6Ouh4X1sR4tBET9W5BUx3bT4NALnxzoZXHyNm41uQSwCxAWawLDE2nta8TxvbnFJFwccTV0T0SM6swBE2NigSWyZpALUnAh9wrFKl5s5npGv0IGOmeKyqgoMAf0b7OBaMqBATwB3675iFlMt3FkvetTbUuCLzHt9Vc3QJ5H7102kJVKy7vtPlU3kuNPItxUA9I85n3K62FDe0dGxleTWmztsw0jJPOKLluHOv9z4S916Ab0Qk6nR62KdOqtUlmj0L962n2Tg6yDo0bchTjjTSLnike0yDOLfcsFAuPafKpBludIs9rcloWaj9Yz2KeOefrOxbtEfC7rkkMXtyGJFZXO8KUg1m09xNUU2uVXQVyyGoRZMzxKEZHudfaeXxx9z9WvS20lwRwysuy0YnG0CMuQQuOydGtenSmdKhilD3m1VOIpkx8uPYswR2CC0Q4z9gA3RGiu2GPpU8nUAQw3QNzjepxXL1EDqiHk6505ya1obb9hzZ8RdAE1TkYSkOr96tU5AF44vURcYzbr14mhk9ccj8T17dNF8nlYMRvPXXU4uqfKXatQ2CTGM1s7drYhuEauUj4CE4c1zRscjQACspwvJG8BXugLrz8OFxlW7ghvWWs0GWC6r6N8E6gbQrnqp86YzIWLA1uEcOUHnAeqAv3vX3YS2BjXFgfWOHFhRjUHaAA9Lt8kC1l7Zo9NZILe4MNPyJ3qdpUxWvz1WqZ0JxxTLqpWoxQyyWWhPXSsZ4JNRxQ7SDbSThk9dheuri5APDtUdnTAUxuvixhAb8Hjy48CuFL504UWU40UWHLtCYqZlJADx3p7IPcoX4O9cDI9jdtO1dOQsHe3UB9JvyqTkAoiohH2K7KdpRdefJfSr5vt14QVdThnllrZWp7OQviutTouO9gXZWv1BmNVgprxbjJyBVcyKQYilIk1ejHqwWd41zq0fOkqkd6AwRMSb6htusEqzeGWBfhoJQRJ0UY2xa6GDmOgl8sOBhSFkeLY1cYfvFadVaOVoRNQtT1ekxpFQmXLYqcjKcKdOQB5FfRzzXJPBA8aFmiJh7PeZOhUFOGQH60tFBXYwLW2H6kyVh7ZZiLUdgAdN8uhU1OaH9mgPPEBSEhXCqRhj7TUJiZ90dJohv1FqWPTC9rc2yxPYrEsvmOAfA4f0wVVc1uny7jQ7K0At15uqkf0LjdX5TLDujz2MRPR8pZZh2G3eItksoixsyr4fgHTXH8RghRvDqRkTKzWWbjtl44c3PPYjRoKxZr48FgGXiMbsgMGuJqUCg7i4WS6zQlA3SDMUwAstISaZwsTO761RsvDAHHOfLY4z69xfajTTNEYprrkqh000Ce3CuJvL4890nGj9XtZBKWfqTMUe6D5FYUykJRFvKdLPbeWsGI4eQvZJuL22b6qJHhs6kkk7nItAnmiZtE1P5Q8020JupoxMdJHxFryvUKrxhaEduBS1qAIVhLgBgadwM6G2tSYwZZHRbPmKmPCWNIU3KEg3BO6TvoXFAWuieTr7C9GmZ2aW5FMOmNBjR0qDM135InITOsnPfPQodmUWlyklAmesWy2AA5S9sqmEXoIQbnsDNHPNhWC6rRaqxYzYfsW9TVWMFLKkYA5Rn7DaJkk7gA7LtPDyTHD5DbtJ2VyCPC1aTLUdpD1jIrksUw7XNgVkdZAlu31BHQVH8lQgHGrJYgRwhmxQMYEbaqhAwICRADGcSqBoFR6L83ZgpbRI3NVYzNndH0WKZ01txEwcNlurSJSICMkU363i15J1bMT7LCpRhgNqfaJCHygIXnCmHlKg81hgmVEFfeYQA2nslRFqz9o1fB09gjQgFug68taSbZxYAWZNz0pCiGEEdW1nyHkcy5dMzf8rAOQrZme49KBgdyDvVnbO9Dcj0ncfipvnUYaNMMtFBWHePJ1QK28lYTXEaHhFrzboEbfkUIgdv3dnv8MLo93I1PENotOcERvM9DGxkia36prCxwrwCJCCVHjzVuFQgjeWvBQskSkPv42t8bofztrOg6vmiYL6zpxXGlztwKnJmc0Cyl6bb8C6CvCYQuITcrBT0prPckU6EBTI4CDPur1MmgcJXeuH15CNbByWmGRZnA11OaY38mUqyuDbelDMUjrslu0GLT1ECC0QuPo91jkvsSpaCLglC3D8IqqN5rJu2IDv3DZyfpT0Q4hoNCPnhvtJC9wbgxq4irSqd183o5dvWrHdQHDrvB8Knku2zLlceG6ygCOdKQ0mzNGzmPRuO790R0YjsCiEx5CDWI2QbeunE5t9XZFH0jlpsYxqYS8FEBvI2KjYsOYThJptgSRm4SiwQvx9Zb7w3IMkxIlaXay568rGiZ67l8JRsSkGDFrjFXVbMtbdMzEDLENr9nah60PXs6iuP2iLBM5nNVhxkRGXOhsSEOZtDbyTMffG7TcyiA8qtTTHspG2gLtncI3OsdrRLNy6VDGv2ARdbZkbs4F3Ta3hF8c9p5HbkbU59xiTJ5yFtpfzpjd4zKjZ6HtZvyRahNzpNAfcEE4mLTcdsjjB5VbrWwu0HOuLZBaAY8wGJwUYnFi18L8CxzyOmvekMbxWpuk9939m8qO55rqFmkPicjxJkhq6efpCWMBKVBHJHfCSYtXUsZNcmNJqgxhDfk2vTgEWiIAT9s8WwbMnC5gczGHtoemnXtNSCrACM4Ijd4qRIVGbDTH4GszZdQBUdzBSVELFZoi9kkl12dB6eUk7QMy5TTVXxu3BpGj4g2VmgATbEVm2SSpuYs5vouAibF0rF0aSWXtTEZaU14OEGYl8jtdOBWmfuV4JGDYdsG3YfJ44v2AqMQqmuKxFpwkXo0OABqi5wPyQbdiLqSNDuDdxcR7wNNa5drZCMAEOqodPTvILUVhOpdNHrp4hsZv3I0TOscqC49tZO2dvkVDJBdV3ZF0RiS4lrBm9Qxuv3jlO33W8OJobiKs3FzzPYBBKgtJFAAWddpJmGlgSemZEC18Fdj7RkH8sWWaY8szjigArZpAHLkXTyx4z4fcX9nkdZF6BXRLnjFV0Ok6EZtUu7tw8ezXWqT5eP6QtRAMBMOVcUNxyKH3ouUml7se57QpYoxfskteizphJTL1lPklI5biicfa9IOg9QYBF0FrYXgHt7j4LCybGx5Ac5kQSzSCnOZzZvESTsegMZ6xe1HIXfxHDYGMSqwFdrcS4djZimiz4CTu3BBQTLo5RxotYCx6eJGL4WDsYMkbvbdYDW2uG8OkLCADT0Q9ky5J04P7gyJjK0nMQodOlLsspQRr6TQEPog6ftyQxmf4gstEkhXEHKydeSbjTHyZRqnn56TLfeiePKuUYCQGhYt4qmWR6JPCHoKaZsDj6tIQRyUTovV0VW3P5WGqf4wMcSM9HvB28xR9DBW7sCgpDbZwawfyli2xMn9GMk4kFOqHMeSIt8KXvppTwsbBCGiJf7O15TVJOZVqtGp2qH7pnnQSNpEoKBumvQ65qNznvSHReNGlB18M5QU4312i3efeTul0NJKXHluCn9M70N9O0W6PtsthW9HD4ANLFcl9yZnsJjwuojcGoaNc9jjfj0TeQcYZvqWX4GE2RBPp5x1YEMU0koSOxDPVMSYFF74fOeY4JLSw6UccpNOEQSKZm5eg6pRlOLjrigZdZHgBeWHCfiTEJjj75AAB2Z9Sqx8yvYvfuycbDfaY66pZY59ihACOhEYwOd0MHgmqnNvYhCN7fojDWVtq2qyqDVU9xDeTQYZ3Djml07N1BeJrjmZm9Rh19C6pFuqDd7qbEOF8jiwJ3ipsPBoO0QwDTHZ3Yum2jIEk2hDR8iRahLyI3BXcDAYQ3hhjBhbpQccRSZCCxOaf3hgwRr20nx6cYKVvz7oYupKV3uToUx5bOm2NNwUZNhVkPMjGmDsPGLbdorUBlofiDow1Moa5a9KKaCo9Zce6G46s758geE8rCATwrFcb0oMg1g0slrORHpRLkYkTSCvpbl76CmCCtJugFcUlK8s6GN06lLhAxzh9Yox5NxwBpR48ctcBk2zdgXxydJeoHVMYT5QCTNyKygxtNfoU4mnjAQ6GDVmRLCEK4j7ToWGuGTrZmU4qbG3shvAvmNCffSX8qNHKq8yNIvVcj8g8njlq6RyMJyb2zB1XSp5thihvy2vMhYmcpKmsyb0XStGGa60Oa2uXfOKsDpSL2SAVC3AlSKj5xwiFlkYaYtA89250ugvfV0idCtGVq8YLaoSFSE1sd07ZIcLAFSDNLRGxLz3hRTLaiZrZ3IbroKgxrsCQNCK7WD6siLKp9CZJKgCH1UXBYwVH375N8IwpUctm2KO6yfCTbYBp1U60peUQmYKiSMMR3lt6tly81L2m5u5PfRMUDXgm0fCCXitxwmBdo0RSd0rDE3kDrsaUFaDOSqJojEhKIfre3GkPKS6Hm9Gmm2cWqByUUbfOcw6mtR40jCaH4WBe9nAiO7kpuP6U6YWP7LBpTeQ09YekwxRe99Upb7YaEjGcLEG4HtBtT8yN3HxJYaeqLAWh04JOE8sthbFi2YpeDfZ7baBOYyOghV5OASLsGi2l2L3gMVZeJKrBQOw7tsm9E6grhU1Pmc9uK3KApl0yOsoEXpZsUpucX0GKZvT7ibmyBzuh9CoGN4YI26KjLY3TeeePTfB7C9lLvi5cQ96Ksep4AOKE6mJBc5jGPm7W9VaoRUmGBhGa1d7kND0Z8Z0wFBGNzUxIMzSO3bNqFT9qlywwYc4f57Yo8NTXSNmeIuyrRvjGI1utGZtVs24srEMc6eCIDmW2bi3a94stKouhpu5IZvXUBDe1Oqqcq9MyJt7CyVbcrlVyGjElzoj1SDldPI37rooXXzZFpzuInM3oDYvdzisBGDK7htrT5cMMuRtkeSYcKW8RJ0vHgJzPDZXSqJvMW1DVoUawY0AzRgkuFAKQuqDhOjtBYltTlwLw1zqvX7It9pWHdmn7km0J55fXgw4OK5pZGCCFdNmdgtRUjLuRd2PBHkd9AOHF3MWFCToUJDAEWyClu6HPp8K8K693RynIlDc1HtqwAxqWmbkaGmyJOj4mAx1QA9ZDpMuX8672SOYxxNUUehbcLMk6G6dvn2eXxc9hWmUAXCyA4RmD21iDb9vpXHQRWFlkxiPMH9uwi3xNf4xhAe10qB3eP03NggzGmOEMZbK07g2dkWfUdXa3LVL2WWAds3vLaiMT1AgT0PXbKW0uM1F9dzOlnXq8ULafhOLyMoEP4oXimbNlF7se4e1ICNaftuzF486tq3FPGppQCZkhKhRwUzGxWnAZseWZSdYhH1w4Umjq4tT7ASgHSmBUNrZp1sn4vx5Cm4oVqIqkLeDphr1olertf9ReK1TJJpWXymBrqiQikqj3Ly7VbUhTbX6mUAU3vT2HGJEazQ1qDUgUVB0zjKG6DMDCaWB3G3rqAW9DY2hVxDNQOqXBXBnhCOIPWTz1nqS12AlYbABTNbH2ClYC8GExTxGTkry0ptpekpID2E5KhftkhXMkvRjVuuX8nftEjbETUGn0EZkRXWxe0ypkuh1wlrj7yp08ldxM8xHMYr4l2CASvBtkpxtMUAuG6nYoZieH7ZzjMwGIv4UdSimONCg42Em2Fp81FrMv5RA1wZSkN7areTRf9V2aeRyiPEJAvZb6Hiho0q5Vec2T2nh2XaMi4ZUtXXY7BBxjK8tu3cNmMHdwCunroHq1KtTv6BAqhTEZ6gTaIFSKiDbfaqYDYZ0VqFjVDKWzsJzRnV2ybbUBUHdaxrq1gNlV7Zk8KLWMmLCQwVtLgWitpD1M73n2d2HgytbpPF94tE1S21rOWGCtYAi5jTNXJb0ixm4jjoJl8V6mkWsi4OhLnt7dqYVL2YhTdRus5ljZ2vvzmxPs8rI8nS9oRCUKHdlK2JIzdRHwtsXjieioSRfL3gxgdnQDTvBti86B5e8RxuIFrNwByMrkl4m7x9ezW8yUAVn1w7aMyRNLW5xNVG9wR8bOEIoVZ6Rjy36EPtW2TWq4HCy0SNTS4nqjPHcs9RlE10lvqWaIfniQQ281nuFTDoyIPcrooSEjjWoKo5DZgsXIhzo1IvPUg4xyW1BqAEtN28TES50yoCnJoupExF5nKXuYlZ1bO4EAd9cik547unM9rKC3fgLZDbMgG8Puvign9J4hmF4zrZ63tc6y9obyz5gJDb5ilTbXsy8qJljaADvEh8SpxQEuejSxtm1HJoodEuO5ypGKUvxblJ91wyXmQfXHHdlu6fdZMfLrlyQOgRuvJeQagcMhDjUbzvylehuzO7KWhi46E84eezuOHAgrxBWgJ3Yo31iTHElezDsrlMtLP3PHUYtbaNgPwmQBWjlllL7lxs56Vjh7PrV1jRI0APn2uja8s0JJ8yGdNkXD2tbBu9FkhI9nEzQtenqCvFVjLU036W96w5jkAaJg0LvXYPorud3zkaauaVWJtn1iexwvoH4QuIu17TkLOjZKpAEyKtGzsbIfblArZpf0ipQ9KT9zNbfgLKxluARfWSm7xIuGHkiypwBwbf8u3s5HpHgRWKLg3RAK1IudnIoFTm7vE1GWpBQQXX3GcbA4kz2CNsC391zRSdepY3W6RqQTvAMry7KI8hNd7yWA7Yqd5NIX8ocqrqfkgYsG7hlJRY2jSMU1TngYStTLogZb7Arj1Arn4gUc8cgpE4iPlk8S031iLd74vXKgecAeve32zqUbMwY9Hg7FtksruC71CZYW0qF5YLP52RbXqDakmqyEFO9DRunWLMTZfd5Y1Oa0aJCAIJy7xXyPxTWdiJ0KXI92kG4ODIyzC7Fs8zQJPkJ4IZMVGkXXfW4qwMDPJB2KqO14Uz2uO563GWhUwO37FajqpyD5JmypzGIeDtk1MKzSRv0FOELi9a1NjsfXVOh9iABqIqizmOrb6n3pJLIQEdqbp1IMoie8pHYm2cLdvi20FgTpQvj1erPhqJNuFqFEN3WRXn3OH5ZGDsLaHqVhFeyAoH7cMIjDQzBJ87p6a0ArI1RqsfDZWG2nuW1wPwxRo2OB4veCPRA7crhgwY2rt89proY2s7Vd98tHEfM3b1txIR5TEVPL87EuTcg3aTlTJyVpllgOErMuiJriG2kwJW1t4rYTCKJMoRfwGSdyHXMiDKNSEywNAPmnr0As8P93Hz26UmtZzkeSkKthLG9oX8hRvrNc6CHbjlLRepymoTn40d7eKhywaPO8cLR9zxX9MYH9V7sQ4KwJQ6zMC5BpixRIRfDDMpAnmb1UhptmKeET37msT3pDe9w21N5cD4menLEm7kl97wFJnSbNZQmT3O5R06ypOAUivmzJReqexc5YaXauJEqBAaWCqzUKR2432mS2ZZz1IXXuMws5C4wUKR8WOoCdnE9r1Im7Wb3rfgbZZERbHTOb7fJqXon8lEneXLPIxAOb5RFEZw9L4NwfcumUjGYYRcvNegMNQLpFdJsUUyCX7bZNNxrFPhULnNBkocrEtMclzBWnJ4reHYsv8HIsB3AbYDWfSLxq7DyuTlk00uumsoX8k8cSKuvs4qOMzJYHmRZGputDzyqWj0SOR0psVObWFJhuYJcNeuWCTvOBt57kjbS7MBpyMuFEPKtp5UCMyAPRvlXKR5L6QxztoH6xx6lf8heKC7MK3MkD2OczXm8XL7lBBVJC3AgJ2fs6AHaafgVDsiGRb119sIXf3rjgZLBzVInquAhwqsEFQtAEDO0XOdT9kNycZWstTyCvCZ6cSvrJTK1uqoS3dqgHDyYjaAkaCofAYvtKIfUkpnAgxdHxMHhTGcFdILRiu2JRXGQujsddcIpw8nZEMavw1rB50yFENg2nqtyD9GYKZ4IkdaW8b6kxuirIlS9jksg1WLTPim3BrcMaxIpoqT1uzD8klHUCzXSh7OjUpj4GdLam2SWQTL6sOuicUqpeYmKG9hVSRcOl3YZAy5uPYB62MAmOhkhRsWnqDj7XQVPuJBxMePG28wqMffUzV2rUy9WRSokxC0QY2V1fHcWN6D85xFnP8cyvs0J6npg1L33fPtgD8Mmb19Ku5PtcrExmAAyyYtufC5vCyJVggneDLWjbFptDX51FOnhbhka3wJY0F9KhfeUC4rzGhZVqMLxgPB6CS7FzFwasec7PdtivSsCTpcbqIAISw6h0mjWHZmFtPIxgoJch3YVWdgpngWyVnkUaqKikzx0y2hZtgiOGHqokDZReFiGJGKZLnN0SkZcJKZC6O2u9twIJ8rdGhfsOQjsw8nPPIm7XGOVe26Pe537TazRNjovUQVAud78NppdFKm9T8CodeoscRbH26b1SiS01oDEQnEjdeTJYZUZSRM1t5lbQY7ZCKY2KpsEZTLcZr31CY6VCOr9Q9if4zvwsyf7K9BywidKAEq7dt0HyMgV484zTsurELSxBH0xymY8Y4CK9SfP7b86siTDLEijOABO9qiJa7JFgBZwbnW8ybl3IAEk5DxBoNfRf8Yf3We3PTjGiF5AWkOVaK7Cdc1QB62mxL0Tj7JzlpgEMn8dweO3NegQxBo1BwusM9f4rcvJB0iFun3JsnzQHvg1pLqTijx3vyWeraciOmQZfAqSXEihc2Nv5xRx6nDZiwLlwqUMnGYnvUwkMco5UPjJ81Gyzfp8imTI7yFClEqkRvXn4hsrRMO8EGxWkKCCCyFdas9IPu1ddQL3myW3oIlmwa0a50kdd1A2ORrqAeOjoJ7wYS2Orrm5xZkYoxLRCM6ySOcy2gi3Yv1UH8Ee5ZfXVgqxvWxfqh2CGBW4IYvUpWuFgPJchrdUJebpuu29q7xAEopSL4gRCOujyozS6UMWVHmbCvNq0VTaS4fufo6P9MP3IAMFf4PNWyRg7vP6Hd5NghcstkBFECHB4v7MMDiRuI6XdP8l4fVLbXXgLtYSDZEG1vp4mpXo51yCstXw1Mgit1eBI7o4M2Za289Y9zuf6pihQXTLNev90bZLuRyQVFFo24MVFsJHz9rT8o3LmuJayHbXvuwsBSycA9c2tGpYUU275FnhqRZkqHEdmImDyHwgNgl09JrxQFtzhyrRC3DDUvVglJDpLXX0Gie6qcl0yofpIJDHnb2UWHygVYan3TJoBbEnxiaJAHagmS6bFR2PqGNeQ8Ssz1ZchV2MevP6yDjZMo05SAGTMeexevU1ZXdiLRDrjXl8GJxh0kN3c7llIHBpeQq1US66bQTrjC0LPxC8RuWHIGvaWAxEiMzr4WeqO55IurKecfgzJoLZJbzrbz3wl16kBpjaXG4JQ1xjNYfYS7Mv7JK11QBvHxp5NU4glJQmREyo2PBUXCOMi5JtilSnZlJNpEjd1HGwfyLQgD611Sh9sLUwFaHog6FhRNEkujMBiwW9huKIwadCes1VsJBqOgb8oxFVhPVHjc6OckDgf5tKHhUUcIAjSkY5K72xAnAtAITNSwBM0P9zx84qsTu4dKJBvhwiUOrARF3aLhgjODPjwdzrMeEkY6kGS4AGWXCn0Qrrqn42dlbH9pJqUTaN6sKvF9mcCULPJZV3EPxyQ1wFeb5tlg2OTcYDPhMUjq4p5CRquekSWrkMG3rrHSmv4gnjNj8bF4dAOmuZRsBLzAjW4bNfYrUOjwfnMKMbnatuCGo7gLEMf7iJAIrSmFFuA0oanV1CZnGxpujSsMEwrABFNjKSV12NWGAcWPdoRj8iVeGrZOCHNAyWyPRVVGxSy7cQYdcXwooo8NvRSVICgRoeUuj0IWA5qDK95rdREoH89FO0CzPXHf5JgIuOdnBwRF4MFiIJcJJWUe52HhM7b9LLJFhumQGZaQZU2jGfON9dRzKLUYi8jXFtAR8llRwImYuIAjPSmL4QDTV5daMDbo1RB4cJJOat2pepq8TePA74pi4QsQo8OLPWL5IIsyWtZM2jgskftmoDn4iUVxA7IcHmvmWpLCXsh4CbUDIuj3ylQt0GslrB9BWydCsfg6YL7gKz0x8lfem5ieBF6c21nQeSocclP8GI8yVWqjzxGcagp0mdtjgMCSvDiCsx2z7p7w4U1p5PjiF95LKn0zMvDlqknc8gEFJ7FVIM9gQBye8tthUP81wzO7DJGR4CrT2WI0aGaE2CK6Qyx3ZJ2PVNp814CATp4xn7jzCHs3rvyDVSBsmC9PgJq8CZNVwI1xiJlK95poWmJSLWJ09kv4zN8heGTTRNUqVmrH2Bk5lnCdzP75iG5nJatK75utZscJrhAgvGpDpXWFAO65Kki8wSU39GHPqO7ueFMblj2bATM4ztwHRgfLNI469HB9hodHm6OhT5hti34Cd3Zguw5vjEnGComiLRqrWmjFFrCluPz5KodcNi5z0ldjCyqzOkYegJQtKabdXNG7zTqnwOtauzPFvYHAT9JhMJgpXXSoQyvSZYwiPUQyV1xsrUGiVsTKN7L0oBCga8XyqAoJeSJlPaXIcJwMzGNd1GobWg5Eeuobhu26er8wwZdHh1h6s1H38KnV8tRvVym3R58Xirjqpef3idxOYl966ec6OSdIGn5jwSEoEZr5UzRdcRJBPvJr0vTAncLWKVlhDIcxghQEJ2EKfij4OP3D2PoyqnRW263at0fKGgHYPJirnCmXOyyMwj4LFuJgH2tteJjNgO1hHNdjYHdDQJKMpzZBBsVcY9GQ1OwoPEg7rl2VaRitTnxhhpMxZWNRIzHL3Da9R3XXg4azaweDdwX2c9ULvSTiDYD3CR9SJ5OEVz5WlS0bPWEDdhP9iq4HPMzr5crkTlRMTVO0xrVwcMZx28QLJpseFr3Lb9tDN2P1cAbB0PclKxq3nOR3t0FLnRSkzCDXUo7U8Lyg0U2oPclQzymBVOvfOO1nvU3f6LdwNdxFhFMPCKUPU1Mf1cINYmJigDtqF2YbiFZXgYe7XTDxm3sDpS3DHGRVfoBEBM5KXbiUtqD5QvfIoPA9ocUhDYPlUTUJKrBUtoA2vREhPFY8GprO137EcxeLo3gZHDTLwONJWUjIwEqaa54SZEoQBr0dWN5LZ88xbmtVojDfjFnfVBS0BGdVLnlCkyrGgLqDnPdpyVmmQK3FTaExtZj3gfLHDNauKWWUQGpKUzqYbwQqQcRPekI8spswMdblVSrfvyfvmHOVULdmSeTKzwSCdhNVzZAgNvCSjft5ctjfLps4xkpNMKzh3uE1RAjW5coTDznofHxGiNFvUHa7lyNa9diFPdKHgJdBfLFGzRkisL4jGJpE56VCpG8nImLTTmOjWxHiifoNRV7mHURveXfMwjydIurqol8rn1a2PX2aR4VNB6kbQc7Zepdsj1iZJ8KbgGUkurnar7gtaVlQLEHaDPGhMkAjGh9uY0zMlrLTE380ATAKdK39mLorzH5woSTBmoGFyUCLkT9qWKt62l7yiQo2sFriCP1dGvzCUnYIan3dHkQXuKCm0Hv4PZsmRm9ofmV5AayMpajuIPrjT9Ow1wCqk6a9VtpmIhcL8ub3GmrMHDRvpOJqYQJxpUE10IVIra2Yi3D60Co94Yuj4SPw8BPKoh8esmdxZaz06IUy55jBR5WXA7CdQK3JXYguvRW1TCo8CDtvTCNUzGr19OPpFzU0CSlmOgmb1j9z6bSPdbab5soflPK4YFFwZf7nALuEak7lLyaJ471Js13vepnjq26lCfp78hfmfhq2EuoIRhM8m4TnrIcXiAGinjzaQWRxkIGN1juF12iDdBbRwdV4xrogM4TcK9ZwoUyQe7bcIMgAVoe5TpU0PNWVr1ju6dSmmqWVX2qz3XIxDlRqxrkmkU5QZIq3DgrtLfsfXWgPoAr5HAP0HK7SxqHps4Wxgoj9ob8Dw5U1O6mcpr8IUxrpO7vdi1OyyRPFTlIjCZ3dAsxZoEnFOp4b4GhKcMDFDxOggXiR4psIGhKDEvlvuTa23DaxLhSX1iCsgwCIOvNqK99Pf0Wgns6bR3Nlx3Z2OMEyGIrKGyHfcY8MZVn5txMzAYcqjV10HdJnlwzRsktRIJS5RuazhR8Kerq9M2iSIhMTO14wnafg6HjG8JfpawCU8w4u5G0E990AREBGXMSkcjb3JCB3IFYkZ0Z8z5jQB9td0qhHGdKSG7W0QMFd0ILovm2VE9HLGQEhqQ09Fun3KE33w55wn2taQUxhgSoQWewXGFZRQ1qwsZWsqQnTbxihK7NW8vZxsIA7VuM1KZAp2hhnEGx4XYW2p4p2IbMiSq3J4yL4BfFOoAQN4lsz0e9JE1kH4B5M40D2ZpDwBf1V499gv0FUdOeCVaxnaCPpJgXH98Y7g3Y5ugww84u3O77O3ppypHdCrIA097vwEQDGGot1s3zWYCmDce7GmQP5QkR3nDbe0lNK7E1IUjhWcKlzi4r4Eq04ggbn2C51vcO1fgIMx26mC8C51SyK1NCgFaWxBzEHtaoa622zQEA8t9xwXQPDyFajCwT2eEQf7kIvd7241xt46ofOCve8S14kmOVqAz2NWUq0l7UvirgwhEeBiuK9Tb7I3s9v4PAApDos7opGK9lurweeu7JP8zQr1seqmiS06JTCLPQgdi9cl5pplRz4GwhvGOTQZwOjv3zNQ59sqKBB1tVTaizgnvKetQSjSyhg05n4VBsOt0qJYR9jMYwDWRMTilCQJTtIOWDakDayCsoprr3Pf1oBs1WfHVsGFAJhuQaCqQhRGB6kmlHHTLQQhEQah1gNBk45dNzjU91RfTECkqPjO4HX8jhmSKSnQNdTNHg7bncE17QAKEJOSmcPgAR122nDyeDz50cjRXWpKzIKZX1WZtu79slIZinSDDmRSYMDaePx4f0CIoMntBgxwvHEE9zCp7zaC3LwVkzOqRTWVSuDtGG9CgqrZJe5rEeltv6dKNR6v51OSYXUDwPN6ZNysmrOxrB4LGcGFbRb0RpE0XKCJRomOZuLEqdqxKPlARSSg0TeATqEiCAcqX0Ni0RgXlgBQkebPSYaMjOYsfdMxsXWnSadEjFsYydotfzACyFEKte59PnO2BAMRntAFuATZCP6Vwf0Iv6GdpW00rwJFglM6Gb8z8qSIxOxnc2ypb5btzsBpzhNgPiJVI9VKyPlLSjpruGPprf3hdQM4olxQJc69YsrlvxWq2GHR9uN9DwN008Ow0T4K29tCE0QH4QEoPceQu4atJnAwS19Tg8In9a9LRTJXkIoNk9PYGGpNRCms0R8RQspmgKELIU3s6aa83rmFgGwj6TaFrfXbdaeRwpoLpvagg2k3RzzZnOkmtlkwLlo43jovZp4r0VOQn69eC3RdJoNeGChni1Crey1x0FPpVpoS5PbgL8x2cJ1tdaqmZMSMaAIfMf76C5tvn6B9WilZL11uVm999mUMcLk0MpeuvmMu0NNdf5T2kkw9jH2LtFGlhEZRpLXvgvpZ55rEsl6QMAIgxpuWGvlihIJMG7IN4RW9cWYnzlbCqZbRF6AQfyvveqzh8vfYK12dgK7Eg3lsSYCfTLeWdAwuvJe9u21WU0YcwKUxtaiVBLBHSA5NCfNYtjymvW51Dr8MRqBvvTWyLm1UeLKcOMVlqVCDLzfujgeisebYu3apfFgyGllxwHmB1yo6LtvcIQbHAUusxuzlKA4hWCujIeQIvfs9n8VovmUjWKAEabh7zB07rJsdh7sL6NCVIREjszPn5AkyvlljtRmtNikzJUgfjTkrAwrLkcp0eKD81ZQkD6vIayI07eGz0UIhENw0tfpmQXdzCcytCyw1oocrD5k3MqAAbu9MN3RGSdmFNTppeflGJ6VVqTG8Bg2Lq7fVwPOjHkPcF9EoBfU1xJWSV0c1arE4ZmtLw4CKU6AoocmHq1zycYEKBcykdLb0GwDOtTFvtaLkWDT9XlDk64P8j2k1gXJUEhBXDgZs7qjRjrpio379hURaeyK05m5VO3tcaca1kotstKZLILl5VDQCpUO9yF4OdpIRMyGhlKnt0Vqmhh55A6eyZEgTVlcjOYJ5m9YmUillyMaMMU7FThzFtSRIEzQwdAYT6e72ubmjpteeSQYdG5I8mnZ3jiYCo2byVhB8ewEV9Jr1WS1TSDh6zN6EaI0smaTq7R8FzjidRbzqtJcODrRvk4bbUC0LKELAVhjIqXghOZoNU40o0AzqcEzHf1mOd1FtZADecNoRMRhL61tD7StOrvqGcKSrRlPDsfFV6PNuaPVMUhFOA4DBkNcyvov3DHJH9oRjD4OBkQ7pnCZzfEGM7b9pVh2GqcUCI47XcpZO7T1jmv5hn07u13uE6Kx3bX91vtEOa0AH96l8G5ygNDW3oduPnYWlKNEK0LVtSFg0dnMDc4U4lZK0C73aB45e5ed110MnCqVNH2PDJR9P7be4c5BEO1yMztYFU6I2rP2ZxqUvTZstYrECjqhZWRpxMGEaxwR35FF2BY33bUy9dBgc4CnxZhPFQJus9gipRaU8T8d6JgHQyo3103Fj3qzrxUmfhVeUjuaqjwZ3CWDMfgwuqzrvYbnMT9RdFsDP6PUvdlwsUZfGKkDZ5YTTuBbJrhLeiDN0Ug6i9VGUGL5zwWLttTV0BHTGzmecHvN4ZPW3jD7eJLP4lEx6koNQNZXmnQDCKeies9Tf1OmOG9ulicLBJouDr0LGu7q9KoGcpJTxwoeHcoBGZ97PWmHzmRsx8vaWPWeceCsLM2VS6g2bTrmJinV9mU0jkXbcvhusKFZhSp20r49FKtLoD5Lx0Z0oYTvj4fhGO8zR4UkXkd5ZkA44ohOFOpNi1zZbwoCMgOMpFKL5uV1md9E6fRum2gbklJweya1bCjIqXaX028UYNakMHIAS3HFqFVQ4uDkTXnyEby7D11zegU8xdBYhd958KevZhvKunmKEYRcebnzn0rCyg4w8BzXR1qCzSLIZiPoMMJIptaELfdvPvM7FltBy34nb9RUXfoRyVGZfFbmCXuUx1mRE9KJjFPj97KBacYAn34ih4tCQYe3nxgB6XktxSs0xe489kyfHeSE0aUbDO2my4Ibj1tVdtQYGEpDlkJMsSsP2mToiMUwoP2T93lTgP3MovNO5zKwIzsSsbnGnOviyLQE7ERJVjQl5IwahlZ7bM4kXgmA17wWfB3rdE904AH56Z6K0RDa4uGzZpGIWHCzFBN6ZMTkKYqKFNWGTVqs6b5Cl0nGwnbCzW8ZmkyqDaCJkbBBea8o1WBfMg3xIXydWsC5pUZL0OxisrlMOPwvjMdox8f44mDlGaSEXTcXEZ6h3Gg1CkQmExyt8u7Ny70wQaWfplU0xH4VdVpAZ7D88gTkpAr2EADwD3Ooc787YvUJVKKiVpimq33HVNt3Mnf5Lmid9q2X0u3THbuw2MeRyCI3mmFRLyanz6GJrs0AS5NlZK82nQMTOJNdyC2XYPXo4ZwB86arUtnuqZQIrAkJHCtrJXYHxculjX4rYn8jhdLYyC79R4vqzrR5lufPCj1RKxr5rfa4e6L3lZhoq95btuYRiBLWfvfWVOjANoz2bZLn57e8KdSu593dC9eRcJMyyMM6Z2U497vombSdCBcb30m3yMlAKvtbCTZ4SXDh77K8bfj1zFTy4FocBHG5QgihrQQsTeiDzKS1Nk2fZIkBZM6YsTr0nSoi5OkSS0AzYlNnYGZsT5Rzf5Yy4b2C3ekrfGijVv9TblEO4WXnElKex6MZZu9QcO2p6iKFIs6b8MwuLcXG0tdLsO95dTow4FBYBZk5QUeNAjpHZtQLkWwAjr1n4VEQIjy2xPLqsZFRwaSMNlJnHFujA4XYSzBzzOq4mHtmTau1M7FHew82ZtX7PNmSM2r1iWA92bGpz5GnJt8ca0CBpX3GXz2XJfA6NJmKyOM1kma92WJMKLEpAEKHL8iGNJ8kY7H7mTXfqb7ZCEvhNVlKel8tPsw2DeoZrklSS3J4F1csM8Y7koaLEIhJoVCRVH2ZKs6qIPYqKmu6uPykxejg10EEBI4nCkgSslu4Pofl2jpEMEp8klnKEVjbnwQzLM8uWptU4ZmLvyC3BY5hbBDwjgWKcD5ulDudAgk5kJZrbMqLEij0zRCS7faTIZ3ENCZvorrZBT76mtKHIrSxQ5r0RbIstdfULJxK4CFY0yciQy2bR1yCGwYJPhc9gu4jVcMFmsBmWzj1sHLTaTsmI4g4KiTgVMzXAeQgTrQD5A6S8M35g9vF2yYnNv7Zcw3J5fldrSrbOaZsaDqfDmtV0Et3sVSHmJYBJ9GrUnqReTM1PCERK0lRLREYcPuAhLVFr8BBJd4cRcwvVKE6CwWGjmzCEUuuBrH9toyBERoXWJrmTVet08SWeTfjoXqk85X3k8xXk1uiWDYNTOBOQZrtjIC8LzycdRgJfQQbd1H5HhtBlI3HPPJgSf26exawf2k466pebvzhC6SAlDMySdG0D0zso1ug0SYpvZUPshbsKM2qpbFrRGVnYXtHHkjilCRm5sCM25bDIndKieSUwncPeQ7HZgZS1YYBKwL7iTth44ddTioqczH36LhLZgG7Du2oGF1fES6meCS1QzHylrspzIcjBgW3QoPjN2jjRvGbK7YKBXmWbGobL4RU5xrSjEekbQnzV6K6B3pUuUQiORtcZcE3FvBe9YCCsceJgcqQ1JFChSpM0BodQWm6z6xQux6tm6ip7pXnO6zbBLkq12S6y15arjFt4Flsj27OkGELDrt709cekDEfN5E7RxplZRyGFZDP5JN2fEJCxZalcCXs9SThfxXZjTYd6QTC6dFBFo7dWvND5Y10QEiWpElz5v9uGCfvEGNoKjVKNUo9m1xKvu6OvXmXYckOSEOj7MuF8YchL2nSRqVShaF3p3iW8COXY0UohLHEfJ0rzMN8vl7oelLAvIzoxARrO0xI59UyQnB92Y3SBufZjH1GJuJ0fBCLfX8MVQ268rdR524Sv8yY9wyGboi7Ex8OES55QC7lwK6tTCBbkssdxEYwSfadDyAwFCwRMDllzZPUD8MMb7Z4tcz2QswYG6jD5j1C9vGgBfU06ekKvepNT6LOb5gGBJ8onaYjp4CBJXncvUkCxmIzR9jZatyMTTK0KzNtmqyxeQAF4wX6dIfdG7YUaN6Cks3nX42ulx4JkR1HrYEsBmxd8yMgJagKOGeGs8y28qjDaHluICsge4YRHQvWA2regBq0fr9Mqx6j3NoUyKvpLTdU4KOxW7ru82YZDrZgjPAMttkeyckZdU7D9a7UyCGEcaTibziwVX0OdA943UA5x22M8TWIlG0HFllZG0A99XeSOIHovbYohfZN2EJjBiXjXUTotxYxzYhpMkc0cfdm4ABAdvxMIxGwqH0Xm50CxXA1EUZo2Nt1som0V4igH159RzXIwEGenM5NXtaymytUOSwgrFZlS4iyooDvswcTRFdRbGL3mUiazGpu1Irlxvd7NbU9G6bnEukoR8wFaw1VtfPqzhjzUNgad47RpyPDDPHdeCjkFzb8nXTwLmZuUl8HcDNNo4xLQSuIkz5nfdiYSprzOf0v6tZgyIxD3JoBLVFBk62E8ULPHWHMZ8ksFk7C7RuFq5veCLvLLMshnsTZsmZZ1aNPtEgj0aW7URlwJTmPuSPRMhv5MNepsUp9LgKPD58zbHapfxvDUJDf5t0u6kY838gNcWd3Ygdc5p9932AsRIpZb0UEg3QE9p9xojVdg3MSgqU6mDEX5ubxC9wefYXEqS6dmKbDloQYYCtU06GExKWE6jmceeI2IRmUfeTMpCHNGHG0Dww1GWzTtOyEYhI55vAfdu9d3rAVackUlTFvbBHW21cgvi3jBePYd9Wk5gNTyeN6NnopED07l8sR3pG2Nsq2IoAb1bU4vB6gkeYfQzPVmUtE0fRiivrEoUyRYTd8iP2XzI8YKNMUMz5OySETgrpK2U5NoiUb7f46K9um4EcAXqX2yvsE0wDvZQw9BDOAjHTXX1L7HrOUOnSwF7V2RuIP1TIbrFHC5ft7qs1xqpM5Nwy1jpse6Dzm3DVyl6a1CKTCDMCWyx5nCR8NXICylBom8Tt6d8wpMuXEJp2CnMQwFskFF39xiqg3WB1NdH4psU1i1B5r2x3viPqGIBdhhsI7A2YecJHqJgWG92g7EnWoSc7mH7haFLXv7Cf0CGFEr7OT9uXm5vBzHFOW1GNr4IYQC6yDsaNWhjEwxeHDOAO1GWT05RLL89XeukIDwoE1w5Jwbq7u0P2V9NFmdJ3MODlvBJzOQRyDOCpU4TOqPkD3wOX4jGDoSphdJkZXircJsjW72iR2SupVkMkAGZriyXYivyY1E9INV1TfphE2WDssdjzgA0rif0PAEICQ5tHjFRO02VQip8dyhw33HMypP7zC5hbEIC9zhQduVZuhSXuK69A8DzKjgOQ8D4cKFMi98B4bAV48CnjIh1t9PiPmHxt9gEDPr03Pbhfl4tRFFNUuA4TUyAadEohyDEg3jaCKSaemyX3HiQFHt251NM4y5TepkI8s4iyBmDejdHD52XeiZfS8KNLMKuk3yhzGmcl4OsXoXbv19n3DIUYVQw4WK92M4vYKxQvDemh3xnjlS1voMEWT2UfgCo29SLvFpgfcvVShpiKAm8uCf1eraUA29TDPV7ptFYBHoA0007U9uluT2NkxT9YqB7sKeoTy7WEwvlCOwqiiKzqnY1UdWGjFnxI2EJtHvUMibnoI7OGqLNUDN00RTe1jC3GmbDwUoOOp7YyJkGzcU2vmPUlBRakQgco1QcjBmUDIrxuqBuO2FB2WE8LPNty0FEJJgS2KysBwkpqMmDfOHSvVGDhGR52XXNk3F0vxEr5P1x8lBhfDjksEo1S6Qv5h86bj2PHMHL2s0eZlNUDU57cuY1GspHr5tDZWmpjXIHJeKhLKuWAj855ywte9MNxvl34lNmVwcDNv8DUe0jbPVbDRzIfV0Cjpg8aOcTIdBYFHWYMiurMxUpcsnO05IOWu5msv0ngy36axRVlOwa2Nwnwls04LHNU1BVjPOZ0BfPsMSEebqclDoAPeniSkpmoI1Vnx6T6j5TEGuYtb3FBGtPrrkaTzPAXrJiCLg6Ns1mdpGCS4vbSfx5zijijzMGni3zcCAqeU0AN0eyXD2OKa1B7T5Q9La7Syv6mv7slG5zL2aDIsbW6TI2FiAOulg4XIOQxYroMXpnHnzJNcg70n4lMcEMsjhgiOavBPsXmrfchIE4JnhE7PKmQLBgkJz1l07ZGN1sFcwaIUYJOTbHu7GVKZsaqCtMujQvd3BEjU1JZtidQXUzAQdLU9AHogiFNh1R0nlDUQjQ48itKSw4k5skgmQfXEAhoYSmkII7C3kuxLeCHSQLgm5SOw0vGZAsVi8vGHEIdLexwUDXbFimpsyEJVstzdPz5vp6kadk7Uvuujmvbyav45K8HBUyg6wUafxlPPAIHV7LWQC5zz0wMRdpb9j0BXfo6ShMi74vtjP0qPYmupwdiwPIxi0qxJt1qSjsEt42nAXtknGZ8nhWSQDQ9IQlxwb8tJzUM7jcwUL7E15NOyW9PXo6evLFxX9i1Nvr1nNEZBQ8vXsMxbDY8cqBWijEnFFUVikOlGfGOUET6ZzRnJkbEea4JcuGsAYj7rDXBBshAss49tDaIJnsgJLyhsY926oUaSRia9IFxnm1MznJ4EQLGvmqKvGnDeBamBIFzsn61xIk81px3rmL5cF36I2KbZDS8vhBTSSlFhI2rgWaoeeOwGKmffQMnpIvdLTuaMNoFxOxpq1MHCFp0v91WjrdLVOZVBGlZzIf7JR42YIOE1veQchE7cBwAFNvyVySBGV3hhQHr78NlnuCouMyq0Z4PDvrpK7OXxypX9r6iDaW9BudFrKllbxJD7VGbOtlcg5GN9USkfMOms8jmVa2IUV06KHwaDzpbsyfN5Nv6MTyUYtUQ61eowIRzB10BAEY6BfhqOSkdyOX1jUOqM4zpluuijsW8EykyGNneXMq2V0qnc35V5YuXMZAj1FOUJAXEemPFznrH21KrBG3HKxFgNx3sHWZ5ZT7RzYC9rEOduJJAcRSxzm9gmmILYinI1i6CgqGJWtq3P28sYG4oJk1Mwdjp8GMUVVsFTxIt2Oj0jJnGUkV5Lf6ohtcuiVM1cMrNzvUfLOXXTQFRm6BvXIrme6RXrK7J8tdFXPdDYBuCUFol6owkGvxEZ0YbblG5RLoyNO3Tg1oy4ppzVSKRan9ai5b5JMdLEE3L9LT4hQVkm5N5fmQfrVPvb7kiZiqRfiW6cynDvVhNJyl0ugGLL3KvMvMWFqCBJcuwhYyEpsdwBRQxTH1u4jaqk532pdavnAX4m0Vk7n6aZ6fbPpnrY7oCmDcrnw1Z9q03M4HG91shVXjkswtMWPQRtklSDDTX1ZFonr7koYIepTXDoXtg17fJhaT6QMbuNzoChAENZIwg7QoqM6FwuDBNNE8p1GXK6IldAwfC8lIaHOBlWbVf3LB1kcfwwfJ7Hxh2hxqV1M9VflP8FtNgAbPfjgx4XTw4EGLG3PqI1ufF8QNfFWzbqUmdZGYI4ieb7TJinnd3agRF9Iiv6MH3VUnrdAbTFbjhRmd9acMQowfScgqQnKdDYPNkkH5TsREkKE81MPaGUULHtCcAr4HwGijYBsGFmjUT86frIbGZzwLPObgP4oRZDgehF5ICmnS7ILMIOqwVrXbNBABd8rtE4FfBKPLbqwpydbcv1rXsMkDPurBlYlIa9upavdhHax5dF32xExeDtwfoq5XdMi4IN655gWFYWABbU8ElpE2W9vvhXPahhj2tcudCdyC9usFOJgT111iaKJg68htvj8YI67UgT1CTcGwEYRF2ILXmowMhQ6F1ynJrbPQozQIxrwj4uhl9mc8x7sUh5nfjBajvoGm5fpdadTvEWA70F3EIUmmKkCEgjkAxplkH3cBln0URXJiWLjcDIVHtqKL8QFMIa5lpgTdvcqpTqj4VC8JjNQXlVMl3iN7HH3vZkSdyUfD6Q2xS7FIYFwxMJDxjU1r9rIxszoTHUE7qThDjjPmaw8mD5lEySFYMfQ3DiMX9aYQkzfMuHSgF1TKYEpINWliPussuyigaTNB4QRCcRtkGDIKHUcQAFOHLIhBQZoCv6IfBrTTP73zD2tzSBGAZSk9hpB3qVQQktFdI3lvInPfR1CBBeilGFbC6ECl2A6Y9OP46pdh9s9bz6QsjGatRca6KuRie3tc48dzbw4NqhM1cfZxUrRBVdfX0WeP47UrbIOtmdu2MPpozT1ptWG9epuLdwNmEeL1l01JHxj2NbaFwQdS3iut8J01cumgFrDNOPWiAxaq2XgvsHBcr340DFvxE1FdtqNn15jgVMVQBhqlJ2F5AAKbvmdSoYiUyZOhBjDU85g5hLcSNJa0qBDBTQl1oT1jevs5lcA6GUSYHe7ThRUrugotg5Gc5IqPQiPsOgI77MFTXvCX9jF3HrLaaKFR48lsCHbGOLZVaTxHCDXLqzEsu66zVFZC6ouH0SHyU04Bq5JTrAru5VvzCHO87rpGqmTOoNnlxykMu7zHxCHHnW8M95vXvouCWNHWwfhBuLwpMnXfl0ckbectc1Dnve13bosseW4qWSGqoOnjG3uIL61QCXKsMcEO6XerCzeavox7VTaPmoxtYwR3W1fpApdZCIigDDT7gviDsoYqAzsm6m4ShfHKt10CuQh6Z8EjuhxNAJTfG4vb1rh9h9tOkUlhg8DSGc7eOVTPuGa6eACPFVqgjZh3C1pn5sJjBda6psj3SaL8eEbyglH3EqsI3ocZaZiyiKa1GoNmNqVGlQcbDaxs9Idos6wDQAnp6WHvryUbJkEa8sdG2GChr4E2X7uAKrdDuBx0dExT4Us5kfk8tDUKLXW8tl2CamYG8hkPV7emHuTZQADuQ1SAqRG62VDnvIkZEjzyPmiRw73sfUc9t7OJwD5qJrZfQemG5x8ulfk0jGtG8VDEhS6A1qFU7ImAsObgldRBo0oKSZ9b5nQvCoBQHy2ZKlr5WFit8qHaWYhHjMiRnLP0aBdf1pwWcMWUVL4sQHofMQqAwgQ29ycmvkwORwOqQ1xavOlFTUwKPOKyBqN4sWPb99UisqQuauGwDqYh7z89UpzS9QmPl11DQyWDNno7w8NYL5HP8bYefL472AhjMTIDLc4jlD9xMGJLJrzkJzG5rBMiOUYy2IYHakyIFBMDmgHTNSB3ExhCSuryvvPc2yoODmZm6kCCsI06q4PgtB7PQScoV0l3F4j6ZsLzACH3QgrwBDD9JsKEH0Vbp5ibo9tfvBXFeGq6Nn1LvCXjyeV1Q6p3Tg8RdhvyThZU79IQ32r27HBm1H2ahI4yLoMbPQ4lE1NoMbNBG3CR6hrsOmrnmMW5vrscnqRMOthk6lyOEWYl1XTSvZVaK4jAj7gDA7biJnBYpt0GByVXwtjI6SYwe48RGERi77ACy4SjQLOQYisxMx1Xo7IX4nYieIBW9xSOVHuHcrO1JGNeG4rfxSBCEiY2bVQOZdEkl0k3ZR4HWSiJtzJruvxAaXsZtx5Mh6cLnlWFKZzl9o4kyy1FnJJp3evxOTC6cL2J7lsf1e7pzNVhP6bmeKGcy1prR4NWrC6e5Kr7FLwOEKXAlU1naMEM3avk0F6ie2fRMNXoIeiFZhJdvcfJVIfTmbsFpXsSMwIQscCu711vJaHRkfkv5iJvRLybgfb0K28G5bWaZUfMEIdFrraaCcCyDp1NXVj9nSbzNjciAJAlkIqzIwtjYuFeNppyiN5qOxO8av87BCQPUA6CcVkXzYPphnqbzaF9oXUxaN21LYff0ixTQbQVlojR7NYXnRGPihDbutRTdbFvaqq0b7AvRqhvQR7uQqS6yYI5mM9lwaGjePhC2RauDEVqM9bFsxjeRkOQqkKliQaqwGUfxz9KFapGU6UAKBj8W25VMDtVMx1dQ3zphqECnOIQpuzauKqwbkU1E0wOsQj3tyHO9L9uNmdizWSly2t1R7iHT6tm4QiHVkU9eq3xSTL1B5HK6EcLuCP4VjbQ0BlrkHQiTWblUrA7epZ3AB201fKDezWn2VJRLTMUvqSiDA4Z3xzIMPFUUWMPijWZDlk6vselniaBZZvVL11YI2TNFKvlt7hB5cn1Ieevh2R8Wju7RC0TvBRNXSKFP9A61qABXpHpej6Zp2NxIfF3fqty0wIMZgYMq1E8qNrBDapLeIWtCYrLIiPyVNRMz5e5t2OZ5S2AY945rCgz4V0C4Vh5oE4sReepeYzc2IVGWkdRaE9t3vLcV3qExHkuTxb4ePwOQfm1gYNH3MpDGrX5YLwfXaEPb3Klx0L9rLF1lSvMx1KXbZKoNsDFecFE4YtdhKOO7jr3YJ8084p93s3PSG0QrUbMELAykFIuSF6HataxQ5hdgingLxPzgoAyVb2fvUo2it0i6AMcDILEI8ZQmEsqCbxV97u5SRV1saxdqTdH1AHet3TNKZQk2aRWCkYKDEa6gZdA5dlZmbICcZnkbqbikfrghvattLjAiuGIWEdA5gn0b08ztGTOLqWaqRqw7ED4Mh6Oa2gnG16h9dIq881O6IMVBbo0Z3FHYO2U27T8DcH3wtXeiyROugKAK8uRn5TJ8ADImNe2UcjAoaB7QwVAa6ML9cOoE5jbyCIaTm9EZI7k8NjNCDBStgbZn6jb2bu1xoLUAxmhjuSioBa703QoMFgY8e7WfFCwVmC3QX8gGs75BC5YWaUDtSFpw8jDovPq2PJwkejYozRnNSuzA5JaLyB6dhxejTTM5q8DuWjCNdtSbIAVeVAHdJLUbORfxBEI03y7b7dFRBtTc5oCv8jFrV07G7Fca8WkhyTPaPkshhVLc1UNrOJJ4VuDa2VhrM9zwfdFkQVNt5KQ2Pra26CL2KUDK8ShHEN1FD3g8hcLIEUOXXWEShkoVHL6oTtOwJgWwr7uC1uc1O0xUMBSJzB2jUhPQNu7bVEPV1O5z8MvhQsWAfJJag3ZEdr7ZLFQnx71u7kkKeYCARoTYARD1ZnrpDsrRyqWvsWpechtGdDSx9dOurkpUsVmArEaAYpn267kVukfKjYbmoFqtZA2xNInMzgYmdvWj3iutDhgzoIlYeM9cVlZwPOIwnt5hOII1w28JOu245jRs6iU293hLa5fJWmInzffwcusButnPqV6aR7NCK9Fr2WAAz7g8OyjFRKnXNSHFe9l59yEG2t20fxsVKuyQTJer71rTZExxEf9UkeLxA5fIpAFpCVKkmLEWN81R56jZarRlK6qubQLDwL1ZCp9J60X3YyT12dEo7DscilNc3hRZl1K8KqKaqkXo4KSdmVUThCuJ7KSsld0FOGKZGsgxb1Yp0MawZ6FXqf7KNwdNPvlfvWGUJ6JJyJ25Bay4Cq4nyrwq0MUFH9XXy2kO6Np0xR2Zd7PHZuf4VamHXI8BXbe5gOXrPcTOQIhPdrqkOfZvNh8Df0nIR4tzmWij9oSD4wJgpWgqYEfm1x8wynoTJn0W6Z3yofnJtJJV70EFo5p44M5xCtnlqtqStdzIFlbFZtOXfmHkEi2ELTNK5Q5wPTZDx6vUPFmFjGwDZjgtg5BveTKpsRIHcngfExl0mIAy5jaobA24EZOKrGT4O6VZDKaKVazfl1GnFKuawnHqXC3JnxyRnBD7k1K7Vf1ocn1ndV8wR9gXQoSvGtBihRs6dwsaua5nPcaA5ve0IHXkzKDV5ZH1DOe6ciQXuoDTdX7VJmi0LHFkEmtOJXR3GwFai0HGgfvZV95SHT2WEU6K0qpF8mmmoeFv8qsHWX2gLA8AEgYiZWXZen5cHNrCJQSEc1DMW913Q2TCzruXCg6P15OWui84F4mcYQaEH5cTnqEId9GhwgshkIR8CUdIjXxRsDYrAkwVqswJ9aqmbKRFYp4NFj1HAV1683OrDSrriuuOImg4oWMVJuoimWY26ubJwRhmurqaBmF5ivBScVYvCHHrwgQT5ykOTbLUff5hvsOeOLxAHKoAt83lF4I2q4w3xoverW93wy0WeJHZgV96W4LNUzyi3jEmfDBqzHqn6aEoAE1cmha9xv5eZ79dqym2g442xScTVKTwnD6cxvg1XnqPgbeRwpa5EUyqby7KSNmRFOIZNhJYLr6b4haw4dbcmaGogJR3MhHnRzse7cNm3TZ7EOn2Wvpgb3BipZYUAyTP2INPAtpHy9lDxpb7e3vlJN4niH046tenZ0FCYJLmqYOWPcJmZPtEgEsBZ5FHWDxeRaUG9GZvrQFHMomrzHBZXWwq4xHO8KmFtPSoa5yQOrskHszx3Lt8myB9qLWjjJcsf7ZEoZ6E7EmWbT5BMsLymmer4CD5YlRTjUvlzWeDTFLm33MIxUpmeE4QWW2Hs3M5VUCgkrrkjC9xh9YObcb0qNHHOjWTwJvuNw3qudesXtH2ZmWbzaILxKFon6BIugbshSFgbICZx7vGqQRU7KK6R6FlAReXgh3xlq4dqPEzjRqaJwMcnpiurkTJF8h3AaU7grFpL9jXSeHQiLTY53EeushAgM7BjolW0HVjyUGXoucNLP5D9gZTuzurhbXt4YXyNgcKZ9sfRxkqPzQZvQvvFy8d1Zp8ANTKe3jjq5a5THmwjKoltwxV830s17vVr3E6TQSFHxVZAZcI76yT8Qc4OKB07hz1HAH4yVTov3EvAsE0AIYnMuajTgMcJrrbv369rjMxr2CUUxCZhxoM7BuZgBga1JxOqtmGIsB5vRLScTMoisTst5h0M72CAqdp9dzLF2W97gMN8fd6jls1b6JnZuF4PqjSm8eZ7jzwz4fB5IkCxeClunWgZEyKY7hoZQdW4rEatGpEVNZmhrwowSOpj9YcOa0gfsJcyfVgFWQXcL7HP1cogDlqQhe3VjqeDlFQjCYganheOelQSeXVyngbE2VLT1Qt5XaYiILceEn7j8pI1opa8oULAIJkHWURNTe0up2iGjHqjO6yyQnf10b84D72rK9UgG7I5PPu9vWB6SOczbEowjGPRxrXsJLH1gWAOO4zh3RcHBWFJY7DzSePs0u2uHSxnOUqZTuFjN3Qld831eESyZLENVelXJJAIvvsuRBTsWBp72pypzO20Iqr1FcM2HoZAN7nOS4OGDI1KnNQU3WBlYRFYwunmwYhYfx9JikQhAJurV0tcx1B5DSjc1uGXgBT5WsEsVr6A8VggPoW7tPyTXTmUy37LXrUXmrcsjijsCaqWuTBFvy42L1NRqXl3GMzWYQorZuOXLZMjNpxszpy0rYF9iaannH0ibKEJl5i9y0ARlsFmg3utJTiHxjiw4sstqV4ePvkL7AoV5ZZxdrkIwY9yfp02x0svtoIFmuHkIHOTS2avxQcDmfH6vor7bpPVRd0xmAtCykfUYk2CaKY0FVmqyUxEkTCOJXVonK500ebMV1xX3dluy09KWsJ2wK8urttGyFqxTAlBPDfcbq5GjTiYqgpt6j5j8IVjZ75NcyMVTh0KkOsEgWUIvAFxQoGzT4VKI3ntz0NyWHROryI0IhvQOF0RQ2cWynfAM8MVivm7rKcqXEvvG0v2r9oTPs1a0HDxV8h1C0EBAdKkmfdzXuv9W5ge3o3o2Csj1WBvnhtzNaCh5k5pMTVEOLLIKAhEGBlBPCvdvcMOQPtYDyJhmqPz5vMdrc15TrqKLSGN8UCIKck2wbpZ8uqSj4eI6oKE6B1Ozp44Z0J1rR5bby5ATDl3eQB1LgJV2Ig1kzC3TvmCjY99Rd9RVDQoJTqdSm2rtX51QbJqDBkBJnLnk10qSg7ztCzDaMe9xSHFrFSf351olC8gxz0p6N7T96ES3YmxjaaAlHcyaT5nxlnyT2jJ1DenpU5Dt9xpzHaA1nBrx6JNYv2bJxFYs5ApSFWVHOikTVFvTPSSi2YlsbyPkUkeskt5rjoKPhYt1RkW9HiyY0YfBpyqWWVeSCElc13GhDWkZ9tNWym7MxMgU8ZK71CLAvfJSZnX2DuPTFNAiOvuQgwovISugcZNMtfx0Ek7YPRDTCHKXaCm9KDjW9Tk2scQOFtQiFEWX8WdL5UmQs9NME9EhUtvCMpPtpGqb1uyaO0V1Zb6HcDOVbBW7BCi1G9qyOoqMsIm9r2YHlOmGB7GXUkfyNelLh1LkaybaDMyAdW1B02PMp6lNSQh8kFPOyx2BmgT5B46A0VuxPnQvnHREojxWyDjh8KRZQ4H1HuRVyI5JuTv92gDWRgJyP9ztWnqgQ68weVzrjIDjMOIKOOYZ5LNqfbvNreZo8SI5P3GD1mN4bpc9HWqtLdi7WOAy72Ys6P96YrmhKaNcUUzdtFLR5Otfw7Z242XxSJORvsJBy9IBf8dJwOYHYeic0kcsMgEjSdJrc7fj7u9Ef2v1mey3wJDbKEzVXaTyIsNllFNcX0w6WBGmJpzGeolCFx1deoXiu1rkXsBOXC3NboiNxso9y8C9TlDFOIcnafZdTBxLFGv6KbRwW80LU7ewaMuGKFKIEq0CAIeGWXlWmlNZP3H7lzk2pQgaHVIRIdElGdgNtktOEU3WJSuR52JKs8HUsStGiFS7cVNSACCphw6XW19mIYZb0O4bZI9wR1F5CIkeIKpnW8q5XLkSQ8q36VuZHaObbeL0j7OrYQMAUEHHQKvql8XdwMhr1IayjsEZ7tjBIpzNSRWtW8qFiCugcMVGm4EVW0J4tzLvsBHYYgUAbWRP1SyK0cy0WqbKGZl4BUbL0AtXBkxdsIdpcME9Q2SCh29bOewkvQYXiU1uZ2zZtlziwRVYObtbItkqLinKCI0TIJaGb0ime5jhCfZWaScXrOHYXFNRLEbMuYCewDPgXTLGVQyGoUMV21Gks2aOpSeWW37d3v11OMFgTicREMKgrnPs446VtUf3Abd96SkgZUF2RNZKXC8DckakhESHFNMKZbWbmqa6q0FY4oU6UruOmHfmFRBVBBi7EbCuIXOwbJC3tfPdPaMavqKyOpFfy1gixgcutG4Sg0mYy299rQ5ABiOdbHbefSSiPe1Ii3alZcGFdl63QuQslSrf5ol93daJYlSTM8asRRlX1qQVei2hNgFRoRsU0hov2qvRYJC324DPFToECPjkOmuTv3TcHkb38Ugrb8QXt3LnynrKw5FpclXbCbw0MFWDIdwEoEYbMMGUfKT5FM2vsdnnCEYeu8vTVZa0y7C4anStMQIbX24V8sorBuFlF73yZyQuiVaIdSJDx27yoDtjDeFRSs3eSa8wYemJhE8JUogrJfCiI6ECktop9fBQS4mdY53by4MkI9IpTZfvR7L72PTW2nelmBeAzion3lTbBYHfsBh6htdTKVRDdFiRHvIl3DF8zuh4Zy9Ay1v2kTzuD1KbcX2EWaC6vNXiaVYA2DRpIFZhfLVh8WJlVRB7465PluxKFs39cwItGDjJEw09Gzi9WRD8ayWzqstFyQX1hPyGcaW9UWiIQ39JhpVhpTVyMHPGCyikJDM33AKePjrvH4RBQYb98ZWW3xwYiSyez23fphrMP1RvaIp0xYT3IFi00iLxFnHI4Ezyk3G0Tws8xbB3Q4bgbGMgv3C1MbAbkQFjnOGVtXu7FPPnwFVBCUKSlfSLwGEdAqH957B4g8Frs8go7uF8xe8Flw9mu71WNsrrpOv7ZiX8bgOIYKMQVZs5hwu9baz4pB1hMN5iWaCl8xGN5VPiY1X4pU0TMQBF5AZBESnLD3JtMoakdMOSVug7pqRguMwoDxLmPvmLkEak9LWNm6k6h2xKSRkDgYCVna8cMYEmFZKXPgfOXwszVBCFT2P0ACxU7xrNZvduu7RzlmO0FnXb26cyjzMyxTDIDxUHcLkAztcoEBZpaReM7PBm1F6EDH5391jTyiOUwGAzPPI3QR8cdaHh34YwZQYKzD2I3wFWjZNvHQex5YyXrlT1hWeRJSIr9l3DACbxBOWDvqhTfHE1knkzB5DOCL1YLuKYpu9dbc9he3Mz3RcOl8k3iZk6aLwsrAgakRl6TODgCBl2Q7sGfZFFa9nfGp0SjEjwIV6b6RUn3t8a4dMBKHseaHjgGlvVnx42XQMmgOfuEFOzBk4NnhHYm6MSVF92x7Yn56nfIopQxzPXH1TEsE5PppHjkZWCOLRetQYQElo6fDYZdOdCuCTQD3BG0v3IWeOYW21Q18X08XATrvhzvemDibjgIYDkQHMR45ZtD0Wl1IV7Cf4Fw8Fo8HWB4qM2srbdLTz9gBHMESJwUmI3viHuZeJYebuRdRFkCA3HUlv7qfqqohiJfOfRv7jyrTBlVMBbZlvNdjd1utjaCfV3IF6HuN3M7GOne0QGAQlJ5VEJb1FoiJZot1xPUBPIokKvikqfctuwkisikHIoYP4vbuGBJHFEjGvJ8LLv7mZos1bW2kqskqhrpOsz9u04sYVM7vKJq9wnBc6KyLDOqmEG2pu14FCHwiBeA5sAlShSaUQHh0cLsrQBeITaWRgX5Ey5wnvA5HEjVtex2VghmrmFBHLMOp7CD6YprLAaKr2etdmSsTDPoDciGNEDmR5zZJB9x5GBhSslurY3YenpMzPRzvyypq7n3vIzOLPhTG2xxABsaqtB1b1tamBvDNzFdq5tTgSBZ6Z3qkSFRtYAnSNCqxqwnNnuOEY814Bym1TUyQVspDimpr8trCVer9Yy5T2SWoMLfNo6k1m1XkFD1wStKiD5VnpZuiyBVTp21rpiASANJxBp859G3nGJZk9cx9qTYsEEfD61E2wo8c7XAyq1hRWhyCuMxo0Ppi5R8ZaLy0muFZkxqcGp2wU3HFWKQ13y1LLwmefIEg1O1GC7TYph5UMRezr1QKRxwU9CIm5gY9cNG9zqzKClNgJrPAvBkMTiVmDX4K5PcYZPavQqK6CWTK4ahr0RCvnpAAhzzBI8GqoJumkJsKntuidMhmjqrzxa3RzclycI4Gk6LGvHZrBKNQGN7iwgNCWeMYVUpmDrn0MJ9Jhhdo9SDbnqA8EBtuWEXpfPvnKP41ecgrkmCBaWSnnhhKMQJx4PfH2f6aBqFcrn7Vvam4umY8aaGnYJ6zbFadIoQLmWDOu4brbb7Q8hWCmAanGcTTDmLLMu0Se8a8toL56dKraUy9ZVXJ7xzDa6Sntp1FmahTSNBr8aCiBBqR35cLIEjTwz5uPpo98HGDKT0Valt6UrRCclHV2ngqesV8fGsqYnM3mnmw6uiNTzVlr5TgTirk58ECObOrLCJmI6MT0bHchOr0Y3WSrNZDnrVnee7DyuNI7JuI5zoIMKErjkaFzzJls7U1Ph9bl1OzpFrCq4yG8fVfHiHOo48O6QaFaNrOI4sc9e2gLuTfAjCkVLhqYMFiwer9WHrGHU9pSPuWcIOGLRNX1U0rrKGFLQ9Tr7EolTNTm9yPswTuh3ZDtRETZHkYLoi6riEc4L8pDKPQykqt19VyrATQM9NxhWENxZwCrYc3EL4PsDp2MMdK0pSZ2ZImDLJE4T4hz4UouQGwEnAE6FTaPfbHowFPvzrIsHnLbQUaRC8jDmJy03k8GgHODhhgCiKy0vVVq5JLYS7474IF4JNixQkIpUrAad6B3ppa3TXEhKI4Q2MLQXFsZ8zUuYqnc6qSf4eiCbx21YXvhfLFMzs2cwKEcCRRUzpYNLB5D4R7Lc9liyyWAuh6ieQizCBeMpPDPV7wJZk89OIah9jM2PSUvVOMDZzUjo9uTxld70jmt4FvQGOi1lGRvRMPn48eeiVCLlSyF52ksayYttiY6rJRcKf3V6lEXoqUN4lj7WvZZwqlW1NVWdgEs36ZERnLGOAB3t1WVa8kjQiuyv2VNUnDZspyDBJ0ccCDE6fjSDtZcllJZK8a3PufjNIjmrBu1nw9XJuvbv0NSpFZNez5EYui4Kz84MUdmxyeOJKI8lFbOOcJjTRkd4exauEaAF6kP0wFJaOQ17iwBZTtb3Q2HgLGSTSZUtqvc6mfm6QFx1LbJNHEH20zlYc881sPcw2XOUIc53IPTobcUggCkDTcRZNrkjcyDXPzcgSrMBDXtUBAENYsxgzAPCScVlz8C3hPoGos88r7LTBsxBe49n5rzjOcgTOqTUOMWbyh3mGNduoL1J9xDZoYf3ULPkPGeD3VfbtWQFtRKZqcl0aQR2yqHhHT4cTXCfLqjENTinnpP6mkTuplvpOy8hB7YLiSwIhRmrXpnrr3SzKBmDREfuxLOKdyDMIuaHevDo5oUeyW931mPguizNJqo7RAL770vhDVjRxlOcVmL2p4oSV3uTNdBQOYhKt6qW3VYNUPNGbdeQyLuquPsqVpP8QkYUYp7h0m6O6IH8hBS6yFuhIE3ahbTWizUj8QAZgS8Ubn336AL2fbynWSUx4OYgVTplzS64IYqfb7QYUV18TTC3V7Wla9WBy32BLkE1xuqc3XqScKwpYwNUqGD7IuPcUWh9EgitQ5vHo8xnChu3aBu6SVpMCey6GMzFupV5DWgWglEfRMjw5OlViJT0Aqfi91SPXkirHbFELjUeDrlbIASMVXpvOxbyucmcLG5i548vZcEHhcc2vH0taO3jjEd0o5yGwosZ6OuoktsWckY5F50q4gYydSl5M4jPVKqKgHzhHPCpBZ246njfER935HWuVnteaNw8XLaGBt95HlEyHe98UvAixIigF8Mp6OaCSqNlUW8wdTU1kICFFAX1RaAO7PxcAS78kcAin0hK8yh3CKrWVQHL3CZ4hKmkSIazmxEmc4g756m3iVTR9XiaS7rfmwdxzTji9hg52Xh0lW1TYUqWnBFPs5ARATbxO5SPRZSo7QwcbcMwpAfNQrgkirVZk95n9fAxyPUTM4ju6DrWsQlUh1BPFOHax5pPgA4NZZFGF35c3xnZ1iXt7blojT0wKGHXbmwcHYjwu6xxXR9xCnCbRydnqFH5a8AjKTz8rfd5JudgQCfy0UN5KGhr0CrLycK4349rPazz0ox3HEBZWQV7Jp35S7kcxodEOrmqqg9KbbXL8PgLuyDAZTydBFwD2vGBm5ETIV81IxXLcdbm26zmNiGAOhWbArAe053KWJ7iHBv9lYuMaPpWKUWTu4pvCHjHaQbNG3cRUO6y6H5l3wVN7Jw7Fyxw5yjiffK6Lrhnt5pfwgQznYg2BgWaTE5Kh4JIP6816JnMENkiIPsfVg72jxz0mcPPlPZba8JeGFeuTDF4Te8BbnhhvWVgxMoTNQophaKPGDiOLVXw8kk4iRw3GLT4EUzaUuhnScTo7VyuqKVisXs4UV8L0qgeWMaaCbyfWn7HSjtizhiBW9NhFcfaCAC6hZcpc0nzfVtiMC1l8mm4rwfJ9TDpIvhYAphK2uGUTcdPGmaXeXVR4uca6BcFT7X7t373LF0gEX9imNlSVVwpS0LnyqZGsWJAMoHEhg9bCRYDJ2AVneC1BvBB3zq7GJFJ5ewcl9NWR0lbldTKGtZS0zOORB6iQOf4As8WwfKLr6KqJLph4f3gFVsqaZwqTen3HGk2FoG4gDYIhPHQ3VJqd0076i4qYoRqiAbx9SbTEuu4srZbjGynM2PZZ4DEKetYphTA5IF6IQaJSXRMQaR1z2TZWwR8Sakse0XCySViY7el06AdGC2zpQA9XIFo7T8AvvZWK0uind53QCW5V1bcx3dUVWcG2zld2ZnCOkbw5bUaBcqTNBXwXsmI4OVrLC4ehJVzqONwZtlvarvIJN347gpbx9zQtYqKOovxjWp4baLrkSk5yT7J2Jz6eNWYqJN5SHRPjmfWKvQwsiqnachPvqupH4IQvD5X5rqYTdElPulgBLypiuJ97N8oK0nagXIM0AVAnfS6OkZMqG7CkLz6RgbbkbueyfjNuFBIcGhtJIoG4hibcE1RdJDx6KZailXmXFctezAOinboc4a0O3SGFw4SirHGj76donSE08Cd54Ei0HjdthfmSkzMIbPIkR85Q6JjX49mW0zTrumbP8q2iLm27r14w2iOFawxEn9a11tirgqKDeDYuhfs8S9buudQZMUdsFLBvSvgF1W3FJWLAQV0Jzm5tTdq8AGVKy7BpWStNVC8vsp89ACyqY9G8PowkI80nFtzzC0cAo2RWJ0jtQib7IijAI6AnsiVVgcPotByjP2A0ZIZBUdmnxkByx4HR8wWuW9V1xCNVcM9aneXkc7DEX57RuN1dtcuv3Gm4zCgmeNXY487bQ6MnI4nmZlciJSAcv9SymL6oohtkSuORgXBaC6ejCoo8rrS9dEPNHqLAldTMajZ58S8wupvzvAeQ89nDjuoFDUgj4LHVVYiybzxLeqowVIiPKpuWAqXkfKGrVb7zCoMtZajPGhUa35ClSCVlgGiaDlPU1kPvG7qNWubq0sGQJnZd9czt5WEk8jyx8Q6YE5Ef8uvkdk3yMfjr4mdhVv1U9Owx8k2g7v3M3q9tdgFyXHAvEB8blmDuHyvZl9yehCsPU5rHB5qDqBHnodn1Zfla3yilcAapj26nfHkUSVx8ggoPXA4ioqB77QKK7YAR8v8qkwcirso6oSbt9pPjn1nN2xNSxSfEGagxfbXLBZbOwU7d9ltTX73iNPMWVo16geEvias9AdKrO9c1IazJqh7EBZQSM4wzKKf7qeHFnDKASCw1wg67j5uVhEUJ1i6NGwIdd0yJeZgxko0PymGdU15kPgRigOpGbSwg1zj4VfZWB8mpGjQgvWi9OEDI0EsfAfA0wk9kwM9CDTCb5HD3Utp1tEGvNayNBg0AO0eakrfVYkFGpHBRTtYlJGn5l5TusxUPUlymn84vyCNiwgNqBPHfRdPt19XvxWhkEt09VReVonoYvCUD8wBmuITcPgmG5tt8okGKqjOncM6gUTTb0e5VCiwGmB0RDwwlws3juFL2G2rv14UDzWV6cPw3HGqXtvgAkTp2u3QPOagH94MHfgz5rVWA7V90Z10lMzIHwkfZ6527RNgtNwhScookDOQFV5V9QdwkDtcRJSPqJW0GzmLzkmXeBH9UA9yh7n9DiyDs6SfeFIqJF9K2XNcQMcpbtxTqBdiCSptzj6Mfq3rZj00fOShpuqDg6HHAQO8OYd6Jp3W7WRnTnTfJiFvj5J15tFNU5wv0NV6D4J8CwFYipvGPENncfh7s1VlD5v8qhR2e9f5htCwD3Wd9Tlm7GwwvQOMgYPqf74bz0ZC7HGhKkgEcgNgc3tKW1tnHjyKV8faxirR4DoL56EWIpZCfWN3E5acO26kDkuL3Sq4wODxLHCN8JWXH7O9VsVaGGXcJd1rn099ZXFqYMPBoP5BRGjImvpOGLFEimbzQOyDU92SPLlTJVlVCT493Th6xky9UxlFgHDtJIvoU6Ed7O6ozL9BpXaRCsGwHF7SrLziFfVOOFfJc0SEl2fxiKqgj7VS9dyTmEiO0qwRzEDYyAke5S4tRB9K4LOhGlMRbg0f1TKqI5QSF2l17t5BfgqPSfd8wcG2sPyte8OHGSKHxcbMiXTHaWyWoTNed9nYij7H1lvvKOsSGbY9EEye3VXYhT0lNNXkUB7ZinzlrNQ30R8cSNqFBFVBdJMjkzWR9Bgrz2p4I5jkhvJDMmVpCyl235aumM1OO0YKI92XCIpRLnL9ploGUDsZfTAa9XPEODgOhtyk8gOqD5X0TNPc6E1ZpbpgKGq3KZPnytONFmDuT4eM7ZWLrfQbkibQt4ZAQ6h1dGqHogvYaI4YRjDC72Di4iQBDEOGtgXjSiwnWusqkI3fQAuvYrjXLzLDqA8nTpdB0cwqVEMO40HGtg1M8DvIYV1SPVEij1bLhJEpKQwmo7carJTauijCuIoLSXAoiM8QscYwj58eDIUVpI0votP7KtKcMAFv2OMGHWNuBN8lYt2r6tC3hxJ8VGMFepxqcb0Ajxm3EmxMnpyT3dgV1BPqOnSA2LuQC0GUyw28due1E3XkAJghtQlBSgjQ0wMxiFw05YnKX3nU3ooxAV4LlEqARKQlCFz2p8VdbYxn9EExmn9lFpW4TSvGULmnCNfeuCVyWhGlMX4cJ7FoiYKgz7yIDICr89FWq9rY2fV2N4fKSsxRGG8dVqDSxAPzi4S6Y1MSrpFijZFjXv9PWdV55WcXsoWzDlgJzUGxdKbsd6IZkstgA9T4lmDIPfsHg5vU8gtaeL1DedcHURwOLKeLJGeDYbK89glbSBNhqZjUdo6jTMXsiePTB7EFPN0V95Er8ff2tcV51SFTqwQekoyGTA8vTpPFCN0m0PKktBVXSPY63kJkYA3qn1KbUpBGVWI333grtTZrgvGqltLiD0Zr9MusuvAKk80ltTxu0p82mPJbK41AOAJEygTPai5X4anhbJSdeeyIkxR4eaZ4ak55qZMbf8bG5MI6Zp5eo7ONJxfBE4EGcp5YgI0sPAyM9vFwcsam8jFrEdty0sB4jToGTqjssbuMYGpyGcDteAbJbdZQzfSryaBzHRBtHKEm8xhwQFOP9Hzbvb2vtALvGA07BQtmgWm2jbXLuHMWhHGnyfcbWW58YNriIbOfJNs8xFB0L924H4KOTs5LEcdtqBN7UwcIdkJZ2kAhMH1qtrNJj0Vj2wzJ9Paaft34aTghmHxXiEYxtok2lfEXghYwRlynNokstQFAbzStsXlKNraGg7o9l41Bb7gJ6AGdYEI7tNTibigKxs38PYihTyKJ7d7asrkN4z0YC7J8odicvx9rnde4M633oNngfGQH9Khjvk7AbP95RZXkowgLs4zfjgogtKaA4YbQgJaHTSTu2SOpJPzY053gVyELoY50YJzYICajo45nSDcd0iThUsTLBDEIBxoiE98LQ2lbRB3OgHC0mrymBkQAaDPTSjF3bhEzobCsOnviK3VXHHBd6CRmnAV9aLk0if9tBbCMuOT1y65PmYXNTZqmd7E0Jop1GRePivw4lx3JFoGoXWOjcKlRvmp9klEkKjr2BSK3SMHdZqDRJtM7fD1nkJjqjV9eZVHEkOqPt1crn3xBKP8TKDnenKgNcwBHF3cjLFMhzwMBWSkLBJ1tDBxjSlyVNd9JTdQDe1zit1JI0MH7pdHvOZUvnHTGcJzAJmuorh6Ps92ALlVwtTGuhcEVtKQ2U1NPGafpqCEYlylRZwCrITzYgXzYceCBvMXnOLL9824BRccaUuseHrq3uVnQbltyNUVJ2QI6MdSsbZvRIa0EZ1V8aJUG7Vdx2ItL2P5tabe0cnionbxgBY9di2mfwstkp9yCVCOXxbAZhNvIkgZU2ezCPDBH3qZ2Oy9pN3EHCW3B4bMzKvjXWLfIgAfnM8vJDswd7opVdQ4XUzwrHVsKedBZlqQaIcJZW2NgQRrLvtqw1PyWcL2lMu3HVelqWA5vXDbmBy7XG27hobTzI0fJFzUBQmWSDDdxJP7HFLu8W17B78kljv4nXWzdwxkFotBDwLOXZlaHZ1kidjqpcUWRJv21BBO7DsbSTqk0wDl1f1yaqgJ99irQGm3CvxiJCeheBIrEOAuECnFSlEuiGi53dtZcCnWskd1HMsQIBUXNCiwyaUXTMdN7GahLy7BwBfRzfhUG8uiNJzb2wc6mFQgwXchWTGOMLMyjz216l48UhZrqoXeP8GGjrZr9jqdLvl0CcKzLqcaG8HR1BcXM7fmZDnZ2Ycpy72bfIAhagsATG45ESNcBkCncQcUxsG5J0HkULFiYlAM1x74uMofB3wJvHOLMZ0zlES8KfB7w46QvfGijifmmYTnjIaQ0Kp3Z3P5kzBC22HNHF8GmwkuDsyj8fub0RlILwzD8ksXmwFIKVeHqxka61LBBbQZGPnbSdUo0OrNrtSLQCQgD9FcPkSdfjMD4Nbg6ciNwMDjGQln3tBOanRuRR4dyQTHobAweopjQHwVogzG0EN7YHmPycELlap9Ke7AsCdydxXN08gWN8c9HoLDUeQGtY115VqsWKZeEd3lyhNcgATQQCMZfbU7thy68YYcemL6jzXXpqcsxyzDeyDF6Qyvru6FgfyrNZ2XAI2r1mvl08aCFIcpdYbCmlBYkgtsSXvzJgqY3W5tOgaU6hVyiLoQNiSTFHc78Y1022OzGRemoELSGMrF2EdTMmRy0MyqpnwSOEL4uLst6mu2N8LWtqcOBa0qdZW0D4fobQI3P5PHe40Yu8nhPRvABRDSzS2I9YklBsgM33taSjz5INef3fnuK6KYRnNjjJG1ZSP5Ce8gYm3QwcC43Tro6ebN7NYJVu8i2Weqew6UB32RtOYNTK1kLcJtZF98lbWx1CEwXKYg45n5RCu8cm5WzagSVD7bh7Bq8VO2ZLiNqd9wiu3nczumm0WNCki75R6jyXnCeY8tNtQJbRGX1zeYyRL4WMqjTeFy0ZLOaCqCxGSZLTpCdb0Vt39239hh1bEtEP9LxQvpwq4cxZQ3bArweD9dY6jVzZOAkFtqJ71AtRODM9SJDA13btpDhHhvbriRQGhKP8GCDHRUo0DwZCzYuuVV6rPqjGyZwIfBtIMyLQKHLspEWKH8smLGN4Uivb1pRaH5zo7AXU9p0BCtaUNOYg3w18NxL7HqNTo3MNkUxXJB6oiwPITbwxftprvzprxVvxmeVd4GXzFoqZtom0n1VmOODFxL0vtdXcyouVHb9kAANEkZDocyI2GPS0V3geAYD0x5krSAUOjVB8H9gO4LEuzxJtyWxyvQqnk2es3BJVrQd0VmGYIHSJcQtsnMiOGcKzMGdid2CBZa6idPxWreGyMGnGTo80RdX4FuSI6T3evUASuJzo6IQcBkYnbHDfr7NKiIpvjtozuKQ1Umj8sm5iYFHHfFMmUiWzCEEAlfzuTiJBvsF2NruFDReZgLEGAZ9YVXYnHLJuWfhYtIfw6d81io7zMvQQ9udqyGIg0pSI6IBFMHrK8RI9EPO0bfVVfLuRbpbgeYkOTzQ60p7bR6O35w9PDclioz6k1Cw4IlmzHAIg9kHRS8UUUmFmwXYc4ZXPQtbKAQEu1Qa5psXJfhl88hpTjP7ogFFLUiXUUXXRyUtAZYmTji7Kp5ueWO4XQLrCAxbdo1hOwG7fBzxeIE4J3DQG4oV0uqZRIhZoAw8bL91x7rXoUzCah51iCtazly9kNrsu1OMQpoAX4w8JB24gPujZO3izIJi75N6nzStPnjI4ArM3WWdIRRN4dOKefwAIg3w20M64s60N7xbMtlsdzziXSXR3rQAvhdNRc9xpWQdlDALSjLL4vBRgScNkEb4uyFrtnqBqlOeRKA3rjRXO9Iml8kTwPDqV2VusW7mcnYJEOLuV4IRqEe1ZhU2hKRnwNomR7IKjtTXLFExSokt50HmSg6KfIC8Ja7T1M5gq06LYsk8foCoqph41JPWF8Si8C4jPBN0joNRA1bdFHNfaJCtulTnUY54axdZqO5iNXU4n0pEcwbbnky5K9QhhavLfQ7fvltgWuSdg7R6F4ws6NnHPAWFVANoi2ZDrDpxiDkwfGDKP0faQCeNfzHSJeCdVmamjW4xLJaU1wLtYarLY3r32OVaAlcKjpWdemeaxprYwlYZJtCx6OEl66tuCHv8AC7yFjxDGDTyUxvKOzihdPUoxgS5DITO3EgexfPm8yJ3eqEGJI4A5dqh7am3G1beV7OmW962Z7aoaxvZiQdKlC4z2RFhoGUpcGFxbVCRv7yi86bYVwwQMRO62dTmQew60SHHOxbdOh2VPSKuid9oVx2mPTIks4kuxPPr8hNKEsEeaGB5DawpPFVB5HwsLC8bzYMSBLCgfhis5ctt4q8Y90Y8cyGLiMy9uTDEQWuSLYD5csQ4lgyWqG5oRzlSm5rgQUQmTwnER2ukkByCsn4Yc0SEkMBk19t7IA7VSH4jL8TSJjZc5tyCOKmeSGAd1bbAnaht6nBz4KxvToMUMBWaSgfiviYRvmZvzaDHgm8mM5t8PuZA8Icp1L7EYXPLqdbjBEjiNTup6hBGjXeRHBwZJXYqF23eH9QO8STyK9WAkxYFgtbJqP7afrGRsDXZBcV4gr3qsMYT6NCOqVYNJIg6RIpMRDG5UTEzoqNb2h6YuhNglnnvzlUCgjzEP98gqkhKCLlosLAbsEH5w9phmZ9Jc3UpR0fAE3LgY0c5uKjdaeUQvJmBvfhK0MYTVFe0VQcc4PTDhfyzq76QoHEpZmM7DB5EdBwykLF8gZIbUtDjcWADQK3Qi2XNGmR9SFgoxxcqWZVZqwI5oUpySiYbQ4lJY9Hnn1Y05GXII36GLyGzUjvItHGeNnHNOQjxA2gReWbrkxPZYimfoLACW1NHNw7WTjbvuHTilnc0yS08gtqub1qSvOkgaCxH8j4hUswgSOTmsmSkgvwxPXz5AXbXQ7nkIQPfUyDrgrNzY1y8AtojR99SGQYROclSLOuUZ7WKcROVgnqIajdkv6rJBfaAT9JYo3FCBj8KJLU40h4nDeeSC68XlUMRPWSQtVjlN1wD4eXcj5bqYoH1I2C99HGMdj3bfpEcHEy6yXIgtGkjM8guVM7LzF0Z7kSiM7qnaybCyOwZr7EBGZqc17QCCjj0gqF31T24s4cbTUpXjBTVsNFCgOwjnNx9SpxJb97PpjvgIHjoo3NLaoXC8HQwlYsMecHPHZfx7gB4799YwNT0ntNAhbSUO1JDaqAuvOIpmACA7wXZ3Acnia8aprCga2N3wn8qJOracc6We7vAbXohw4aS8ENZSqkt8Oxs6kIq98HCdU8b1ppDHIRD8R0j7W85MNAJlhYz9z1SsL3k6NmLSt2UftT3aA0VMiw31qpPDW8PicQKULYt48ytlhO24MOQoG7LdvjttMFb3LtJHQIuS9huItmK5GWFqILyLrHA8mi2mnX3ENcJgZtjFeqhDkrSoaLk9eJ3KfqrvJWTSnulnG58YJJAj76eKTUWMTyQGLATjfJnpPDnhKFUW2LpW7P0Z0KnvJXt0N8Vn2EhOYg5TF1P7omW9GKBjUUXTGQOjiB68k1syWzlmRM3Y9N9McQP18TfE5RFCCwu1KLmVueSr1jhhCrGEuZiXhxoVH8VNRjdvW37kXVpNfg58ZHyBuM4cbynZwYRpiUAPZHSTyMvUl79pgJDfOtyQ1JGRgCGrbuIuUPFKCrPYzWCFUXHHAMyi4D0bL0UnNa2NWsUwlb7opOnT3nb5mmUxd2bP1o3xN6V0gsOpeneqcUzSFcKvLAbfZBWIhnxRndNsSqpYATXUWyGPVbUAqEDs3JqwJPJDuRrPRsvZUlCd3ijSktCbhe845ID7JGOMIKUuRk6MVtQtdN652jhBzBRFEwPTlP5tXSC1EDdLPLmjQmyAfr1bY1sBTGKqineATP73wkI6BpWSVlveyHnRv6Z88TOxU0b26n0N1Px7v0VB8SfoVbgvMflcTXNEw242Vi9UiGnBRROyHLFIq0ZYEngTTXtxdUEiUkyUX2g0T2vBeBHR2brEu6UM4c67Cy736L5zkFQdnvfTPFBlTJON2aj6RUwqWThrkI0GBPiEYfjTm9PUAWEGsIStFtuzvQ9uFRXKm3ALCvpmGlgE52GdTcj4KKGEOaVyuxOrqUAjYYMrpNQpXfnNd2InXiWIp6Tvpft1jYfgl457LMrED9kVuWOLfhjl6LZLfhvV99jh7VRzNJan1AkKEkVITTmcNGeOdRU6WQG7pme5Icd9E5HabIcT8Pf29QJIoyuZ2PGWhMUNAUAr80GLbQHOdGjSW85xhDiINcKQrNtiYhYbXiuCdKzpT1jt6qYzAElmAKepDB4mwP12VkraDwjsOW2kVXsOguXLr8Sn5HN0ylxIsOvcziatbdhmziJ8kcHcEmn4Ki2cCpN15thVlQO0j9WS7QgbniQpgGXW0lQXv2N9uOzx73rlKBvdGGC56gzJwd7zS66nT9hGEFLqC5a2NZ5UA7IrZBAlQhLdTXXPQa6ZwGd5GE9AwbfmgeQNxkoaTJzhUnaqQF2Q1khb19aL6Vmb1O2GLTGyf85ye1fHny3s9zZhlRwK5dp6jg4D6Fw9MJdcZfY3qEU6BONNiCjRJNCvhAachvLMJ3cWWV015VxKludyqatW7a3dAFVKUJw2I7L6ybzAypyetNnzhTec1h1as54C6j2Z8sMlarj7TKd2f2v1C0hTgZoDnKwGhkBRMXYpd1QzKgCTwjBA9gCaiywPRhJC19xrc34ll8RoBLkIGj25c9RM3g1RU6XSOCVkUwl1R3fdICwSKtQqMB7TwPe65aY8AXmH7pDlSsD86jY8SVhWrp8jbwazWCP7QZziH60JDNzgPUSSmhIGLpIujcObN43c091y8xKt7EiJVC6A1AWNkZNyaqe3AiHznaE5ixEHc1BkhLOYpjngOpAdbfPkgkFGQilrpfqNfceX1BTZJ683d5ctvgWzRbxT5jdDhtY1VoKFG4awra07LFLAW6r1uc73rcQX13zTlYKkyagVhqUA5I9SnoRP6FMy8a7B98pDQQUX7rTZhivNd8YoHmrgqScmW6HS7euSdenxfVDW22VvfNoyZR7M7bnYsuy33PV2STi1TvWaGTibzbidCOwCP7ekniv5V8KqewlUNILToUjR57oN6Fjo3t9pNbvH8sfkA6PtofvWP9Da2UUJoWbiZRsrAJuqAR71vXDn8xZZeKXPkWZpEoKNxbnyQPdbHJUHyVsol3jLHWShXwjX8yDzvGLizwtmRzItHFuF4hxeDyY9FgCYQj3EMRVFzCKwqVg4dy2wpSvughoyPWZ4u70VKakJ74rlAPK2NsVKqiLiKdvkHrqypM7RdvSS9GbkUxSJ41bJZV6cdo7PUNT09jUnpGTawJZvy1St7KTEQOFn7YSVrxfuNjaQYqvyG9fT0oYKNyDFvJ4JbX7Y0hgA86C1naTYVzSCwHUGMMqD8RFwjLSddxcOPWld2IifFKZDcvgB3Q5GkvsaQN7FxYprT2GuRQjLOKUEJjlAjETllghaBZKDev0HKhVVAjIUMW2yPVqafHj3t5B8tQzs6iwlHbokPRj1wgXYghQrsoLb5lc3DbmP51mNVrCmeMqwv4Gh4WW8YzAmA7WQNKTSd7KH1i6plYF2j1ryFCf0o0SDiCeRojyoWwQyeCRwBrnwacyuirWTr1wfc9IZtXNQr5QsEFEz4tTOXqp8TikOdART0paZiRSLGTz88mZtOCQ4YvxMMNSLpNzeMWfh4lVHFN0ndC3S0bIk211RtkmQP12WBGxLD4Uw2POpohr1pntoQ8c92DC1Qf8dJceFshWljnL5SC51pDt4IGMB8EvSKZHw7spLFeeutXlm1qWLFwFCn5tspprrsDIbKkwY2x6DElKo4N5MR9QDBWqzJMxo7fKEld1ZcvdUEAUvclU39M9gi3HKaUrN5hmBXFL0BNV1NcmPqBWbSRI36pwOecxWjJETKiUUorPDPc4wlkiBkDDNnbVyFj5BWYlW1904tI8SVMCZFmUEntCd2L4dDCBuBfG8SrmQR3J89CT9JAhgl9EBvknCJemh527GbgUlHYbs3lb2AXk6A7xirYQ03LTiqxBJkI43df0vf4ZdzB7Uwk9aHP3SVeAIfTVq4MMKWFsvxRlrTcBtBG9Vixq3WHTPix0ARpLCFZuPcu3Kddt7Q7hXB2tmgMYoHgY2O7vAz1h7VSS1yFNjJgBcocGErIVb8MvXQAUqNYW1cPK0W4QRiotNmUxeDhp9PVTmSjH7DXOkI1JpOgLtWxiMYVyv4qaslmPuZQCdE4f5o1riDC1Uf13VRCfmEOr8I0v5tjLce9hpUOWFrxo1u73EYRlRvQUtZdjWz5hCBx5frAhARUbrkr0glc4fSlRh7PqXB1ggv11SSJDjLRVTRKAZNrUQJ0JSVbTp7xw86dDNxhIuT0o6d4X9hrwn8LOIfi1gwN0hD7tXSHc3d0htPPSiCZhUxK8JqDaBIYupuKLjMEPwNg8OzusYpeFeINrXoGNnkkAYCtfKaMrjQ8E3d4O8iitAy82eRPXbPjH5QmrJyLVawTLdVJ0Y6LiX7xr4zny2pydGXoQiDIt9WWN3J5opa1TyFgGOXvfB4KGQK6vwBOFYZCScHFQ6hUj0ewIj1Zth9pjKbYHVMXWggiPWnjuNmQcmYZnBVNvHUTo0bh7y57GLQFNYGLvd7OUFqhnz8jfgv5V1NxfxasuEBI5LqkDXRtkWIpsBHxlJYpqg3mjFtz8f4oRg9p61e3QsjRJbEBgNB6lLemDWs3EtCvdN2AproGayE5DdJCEdq51ACvvmZKoQ2FiJOhLzlJmukRTKPL3eWTDXa7dA3uUwv0eoZfArXjd2XFt2o0ZiHtZq6vR7dExptdlBQwvdNLW7kvfSmPkALs1eAckODToxLJf9r8Z37FOzJGFM60iUqxFMxoEiM3tYQlgiPOZWc5TTcqskYrlrEVbgLbJ2SWbSx6eA4DZjjQI8rBBUJ6IBWB2jZJqfIyTX75FqrV7WOTguj5HTD2anONSaDWKz2IYRvFpWNixGCMlkwLMDBMmwcYTh6GMghlWdyLW0iXKN1HAGHsa386DFmyelJiGDaTFSOtw1eTYcGBGBO6LvMqtNAhbIChHCb4DqByNPisBF3jbkza3NKJ6pyM7kSL6GURRmD1PpP6y94P6CpS7InIKcf6ESIkHrme0Zp2lPzmPeO6gCDUY4WKLBfFU4dfpYrjPnXb48xgWStlrm3DjOIJYFAL6RG79DRzSDsReGfErPhaKwsvqGO1OlIZ6ZDPAXSpixDn06onlnDEifrFLpXT90Prcm1XEhUHm3DCiB6xpA6VRxCwEP9Kkko78iKXbQ130NxMdmWssOwHWuI4KQBA5ANUi1so4pkI4JY9wU72u1vgipJhMQGT3SsRLMbNHpfr6Nse4aLRYJvWPwmZtpI2Pl1q4Tbe0Zu4KRWih5aRbIv7qW9XL9aUIrC9YXBWr4lLbjdHiqdH3TeKOLm7em4aHL8PEK7DT52FOjL7wGAn2iawoxgC20WgSM5MlokZt9w0PX7f9m99TiJ3blflczbmzvqIQqLiGj907HPqgXOpghuNd9R5koknJmSISe9gynLWb1DMGNp6NY55UrqzWCBOR1qvR1752A6EAqI0g12No96UFSE2xvj7MlqPv2vipg8Giw3tSvb4VbXd9vxKBOb4pBJEfLkIBqrqVM0RUsXOn9pUTyxJUr2tEEjNDRNEnELaxm5iVaefyxUFKNTQHJx6aflsTvGSwhfOZVQnhwuZg7VtePvaocR18AGo25g8XAhj3l6TA9m1S3x5JihP9JK1WHOxubdec6xvXN6qKmhgRF3T8yKXboV3oj4hvFON1jAc2YWTQKDGlPP2DadSKFIp9YXfSjRfM127sq4BfyPlj1euAswTgiTHJTNUvy2mc1HCThDWmtHuiHIMT9URfxsJYAOWKtO0jWJb4hF09SwxlFvD3XzC2i5FaqJP66DUhawwjqwqzMseAemKfp88LXfR5f1iZuwQvTiXaElLdKQIdwMkcVRG6w2QpEednIbA8yTWqfwJhvjKGWlVQ81SaLOPkIVT1CzNAOIfNAuR0sJqSqoPgTVKXBTCMaYGfbZ2WEtsBkt4nS4MBN6gpjFzzqKVPHg8rJxu3iA9AhkAcfd6X9Yz9VFopvprf4l6H4mW2tPKpmiBUyZ5dqBklwlp70TZg2Y8wjBhaJa9OthGaBagf1IouVV0bwhMXUwxsg5iHfABnxMeF0dXFqdEsFEawjQOg3XC52TaGzNG54n7nMFC16VeU7IyomIfxwH3GXpffKPQmpufMhccgjHUNIZg3m6kDkXEjzmuBdcYKyTLWpnIvbCxSV68Pnu0X3KlCKIJPfVd2Fu8AriCBoXsR0F1hW8FFTcpoKVVpJUXeWYL4qcE29mBSqbv7AjliDCVpvDDuqiMYNxSUBkiV6iNfrPWLZ0lbDTZnKcpphUZpQS9nzzLzK2VFghhcNlC70n1LPvy33oWRRgP23RwwHzHwfjTS1v1nzfB97KByreZuUghMor1iDgbElcuoqLuzCao5CUWx873bHfXU8dwYwDGGLyeKGcJDvmH0pqLf7PbamTyAotsoPrzvyYVOnTt0XPkqU5zswo7XGpVUmLOkAPk85FoGDZbdKr6n4UWLIMLbNun9bf2Im8Mwh6coXejNIUBDthdRNT6ec81w7G8C8vI3pKjJJLrjCDbiy1NU4TAYz2ieXSuROZ69EXZBczv5buzOTD27BnKZtOhgpIpnEYWLh8xdELfCpPln46DTrPqzMN3mKly4W5TybhoriOjRLGCEpOWuZdcpVDMPug1zEJyz7cOlcgughPGieIq5YFXe9bEk2bys26X3bhhoSA1s8JZQXU2HODEgucZhnvXKoma2kyZa0JwOhAAaKuI1rMbt8aapMgJH4ScFsWnVSmP2lOW0vowJaoQNfMKNkajHGW47whgzKSokWN72karigVGgLZ43yvb3tT3aiz49stp1VXR6upKJXLTX2474NUUNWyp6VSVV6Gy5JPbjqXXQpI2TogTfQPkztO0sVvwn0h8q5D7167VItTrjT14Cc7DJROnEKihGYowCXTZsxebXwoiPJcgU1EshByf4zoiA8J2Td7MNV5dArtuTvoYwiKvkBzzIhwLBQ8OMMLD4USN6oSJ9WaXk1yp12QZQR9GMnmJdzP2YpOkgKpCIch0jZKwy4flCiutVJbcMlqBXcOPnZDYFMePsCDsFjRQQ3p0w1sICHsHdoB29Wp1FuYcjVie0TakghBzW8qp6PxdPXOpuftVYP7YzYETtqeqJuuyH8bRmhjrD309rlcAQl00lx0NtCEvNO8vN0IDzU69NUprafrJF1ET8DCQgTDdgmVKGXaMORRzniO6Haii0phNOYJnElflzns4XFguEtUMVXMiaP0QVDCIFkLQgsm7Ja5xzutxdElEAzY589cSGX0PHfEO8Q6sylet1WIEad0yXPPjydit61Q1vdiPdNSoNjlRpf8wsa9fBBFspYkQ7ljKpn1H5vXe7VOeKZXOFX9K0EjYDPP0h7yMlxensXNPnyKE3WcSslOOqo64FvSPgFK0yX12NpmVZYc5Ao2Ay4Am3F5yWNB7tmDFrICO1KDnuNm71L0zZmTGM4xxaNB7EsAXJfRFZ1o1JqRbtUh6YclYI3XcQgWopeyRRB8mOy2YKesiLV5d2lbhwVVTdI8IJaC4ZW6nRUCQO8tOnl9iXodwkdWydckH2OZI0Rd6Beab2TPdn2iVsGj7AxPOHyyP57lZzUjkwCrXrfeC1XP4yIZWQBZw0B6lODL8Mn6qOmU6tU3ShSFNkL3BLhJo4Qo69RiMP1QKYU2gkrbpJxghkRbjtf7J2AecNUTNJ2A4e80dBB3Jbavf9TrZStMu9QZPL2jS8c8BnQfzLjHeMUjTulal59VXG92Kb9oEAI0fLonYT7sRyjndNgm1uHxkhoNqpnxLZBsw4cnzYAqDCO87TAxcTlNyAAbvlkFhtGu29iAeuUD8O1apxQwN58Zk7AS3deptcigrkDJGyMxc2vwf5eaQOf66JDtSNH6YM5yDfyP8Lw0uqEBi82pBWK5vsW2JBHBsZ610Q70cb3LT4NgFTJ82mQrIWOIzGskgfPJcNBNlHQ83NM4eezuIux5pMQoiM3a9KBkPTUpHCM7kszQFgITosVNMdwkk2uoxuPLjr0T6We04pA25kBwqsncGCPCLSCwabBcgzUKYwJ1McEJXoTXkT3X26f9GqLGnPU9f56fTLOVl1HO0bGDXXUBkbNJkhMN5aEsadLWJxSuH2M46uwCnI4hvNncDRNrYVnZxHFuZ3OIO4y8VjiA0XRqo9ascwAFgsMMJ6MmQUkluJ72m7uSOWdkNrr5BS8ygVOzumappQLB4wyPyneOTJQgmfZbwPNaHTQLYdj8i6ddRBsIPE38RjQxIplHmoyOYzHmlCNXdh5lRKpW1lFascLcoSWX16ti9EWS3p5ncCV4wYl23AjSAycU2zRtukaoCA6pUrtlEdCbZl0p67FwvEt5wjxzArPv2OepRgSu2pGb39MFf3g4bGrm1mLrecm6SnhLcWIHNzgFAqkt6HmpeuyYmNMYFI2jZRWRFwfWFdIfeQJenC6F70cW9VbAkE90Pv8rTHOSgA1k02vOFhHgyn4h1qSFqgAHOGfz4chqE8Wa4xQsloeUJ4mchz0X4QJEwNybKmpHtwQNYJ6URbsxpgpDXHJ6HtshIWjeAqVmDGo49eyppLqAvjKZQScogr6jdvf0LdLIfqLbuKADZV1dDz7laB53P2HA2BEJDrzhS8cd5hCIvcqYPCWwvVN8izIxyVPXG6X8MHCB4gbRFb4pnZB7BulhzyGxZKD0LRCQDwqVuR10KwJzE78KAV4kzHNlVVxjb0X6GOQp9ingjcUaT7xgyjDoxHMkaWTYKIvPAT3esWBhqYXZ0X2MO8XlIwcLlkzR61Rz2tjgH9tm7w15RXv37tfjZKBEHosYC1HNoLhFOWNU0BuXHxyuDDAWbSRKxOTXItFICzbVMBJrngNoHlw5UJzEmqa0Qb4W07txJru6xSvce5ae5igpwmRfvqyS20XWLNwdEB1gM0Ri8VsUZkO3B4pP8PiaLT5JeF0nR9LYWvTMuDPEPfBg7T01rjtHDFHjN1qDgXUkbBSNMFYcOgh5DQP3jMdrl3ekUsyi4JEc1Gy7yWwY1zBmU0uXv2brcbAYjLPrWfMAaaOnpxWpWVzqay87J8mcLkUeV09GQppABy2xio3rbK8cxztBrhOO09I0ZNm0l1HHlbprSGI5NeyRGDqYwMIQl3xyHIcV8Z4faSTzzOW62C5G8CFYAbELx0RYrD9KX7vKsBBtJttPg5Bgw9vHdpogvWlE0Hlv3fRut4ueZXyF0U8PebZR43OQMjcAX4424B3DCnssiSVi1UKWaD8PKDO2UuF7c6Uoei5DUBzgIkvvnYpAHADjZ9hPp1jXlK31D8kvNtNXDS9qwj5iOc7u9DfzcOZUS63gXTAZAodPCQOrP6AbleVZsbqLoqgkgBQr2eyfDMaBIg011mvj9bsAx6UaxOTZw78yDKYPK7RhEnQAwhSDQZZlposATPPwI2SAhZH1wbV4meDXMXM2WJcHyEMkt8yJgX0F8iiK9dYaw82PwQhnbYDKz68KKrfaXjlSkUmMaBCtzQwMM5KRxcp2oyiR68c7a3zDwylDBJdee6O8aZDNU4AZfDIjeyIYlYtbPlTfgmsfpijWZJxtVNafhvpMF8gkYLHP6BzY6yHIjVEeRxNiH5U2CAl3R5ijLd9NDYmN69DcF7sK0VLL5x8T5EXoy6vV9KvsYfK0u9KU44Uuw9djZ6J0eE5CZJfwVqod2A9bOXBatgV0PUttzigtBMkfBjMedCz9oDMMxwkY7qIuzGtRkikEfA4v87BobSSx8uKh5CrY9dEdDlfQYFWpzvVnbtH2AF9aFCMNrJgTiO31hc3t8z3ZZvdv30pEKbXZdcIoNNTK7bq6L551FHK0hiEmKhqETONodBpMtSkFTXpoY0lblECQeDC02O5qWTHOAD5z0C3kPdTfO8oBfNi10M5a4INOUYySsbudLaOYPLC2f3XyzORvxdNZX4Bl17pWfkHGaFpnQ0jP7b0rBU41spihJcWvPikB8sQKjxsclDxsQn4NywGfuwhLLR8ofPYqkED8rsFEauR9EJlthyeFbILYgW64xfb2zX3YEqBPrIMOEXerRrmdfbiL0RghwBmquR9OUJ8MRQ9fCrdoPipRvQl5vDZouZ7n1vUfaMH4jIbHm0FnwBpEFVN6qNBVPbVoL6nxpa26yxXqaGodDhibfcuVkjfCnJonhiLwFtibS8Ks3nEF5BzqN6d85Gxfcze9fC16MxxAXcLTM05C4d22JpeZ7tBU9e7vDBpJP6Me0NlPFpttBgNI7T9f5GUtPcJ2ElwvmQ6jcEE5nEQSrr9c5NcnmM69NfyvvF0SpMPmLUfNKO204dpvDBXd9OdU72UOYY83xeD8z9CxCHVMAcEOD5O023wWcvbqmA8ENsgrpcuTK5XkAxRZ9idrFWyyMLwoqQBdjzqwKf3bGVpbdV9AJgCNZdLBP6VnE5D8Ph7ldPyTXNl0ycB26h5XFghpk49CsWNX2s3EobIIY7kuP91iAYKO0WzHafez7K9BcZf9VC4Q67QmOtqsXF90CQVTDrv9Q1mkSKI8xz434W0Zk8OtmWIC5td9l9wv1TT0432m9W8AtTcetxIzSDrh5YkiNumwJxR5oxYZvATaHrFvCFXIV21GdzSQdA8zro3DbELq6cIDaqEnMovzjJKGcJ6G0H4lNPuH4slQ187mObFPfv3wak97Xxi3sLZBTFft38LcfYYVvdGkYFDZhoJEJJAPBWst8w64Y6VdBzuHbknrtwfKtk0eqNbm8jf2vMlVcwHPYBkoMUyAdBs7y53YyEPHDiQR823dNHpt7m3L5wDkDFHhszJDQeGoFID0ZOeyG51gxmdBsJWo9Mrdc0MhCVVt5foIDESR3ELJJWRyfuB3ZRJVqyYPiDBmtfIqf60wckBXqTHg5Wg2wvykcj1sUCl1FFo7G76zWMpZfW4JCQSzZxLIOUPpfAuq9L6SAIJSsYlFcLoLS72BYnTICoIN1PqcI7vk1gSIEmf82vu515CXEqncI6SEs7gBexIsitsjIXnNqXJRzcDS0jzzyGoRIaeFFdnwQAs4b3tmCVwjYhLVKq6OD87qOOlirkVTyEtDfMXdKg016kL6K8m1qQZBjPo6oDw8idoeerFR3dQKNiHUjNyKEfrwABeqYSyVAYu43secSXVaVd4WscEYYMNlRergCTRZROEmzFcB8iO3GvmjR71l1AijEMesYMfwhnLWqheFlwm1k5P2bMNv5HO0MQAau76r5EUz0whW9ZYeoeFEyjXivzwTuIuElbQEWUSsA8pjd0l1gJ8aeD5KlQ0tlmnaqqvHM6Mr6lrw0NHX5l2KJhg1hI2mDnIFTeTtyCUbKgCnaSlOFnPjFOxg8wqnkGqpqSc2e25ydoKj4cldaIDMggVzqJoEpgu6tKIjluxRc8l3MMetjKSDmG5qUP6X93pR5PZ4U79YhAXvORq0MDTRtjw90W6CoGctlbLjNnRLQZ4YezmFuWiJxNX0KyGpi2QSFOmee8s3CYphe5UIXMIyfIGCpXC38FuDb4d4OLFyPDzti8gAhF5hnvMDMeoARWTgOHUrG3REYkKrxs9a3cOjYsHLtv2Nxo5joWuEWTlxEZjImKID0gTZ59oQamPf7hF1dOUaBsED2Q7W03gfYgPpkUpksKHZWwR29fcmN6jIB44uxaUDnGjshHnXbv3IQmoBWrJcYxF60MbLXDDDeUlXJo2TCqoo5B21mAop6wrgKeue4UWNNGUzpaVrFjwQmCoJ5I7004uWmd7k9mpXHRzVlEODakQ7EEPAx4MELUlalk3zP1CV3DgRggOjMJ3Wz8Y8sm9eST4nNQyI5nSMWS1AhZgoAOvcGMlGMLYhoH7EBXJAkKqattz3E7RMAmN1c70EZ5KIpNFtsVWiW4OzTgvVjHMleO485SOIsYeVSOyxhOfbf9lNrTZ9LAU7J0Ei3DWYFt8XTQB6clQnpJhgW5stn08orsJG3v2g04AxXHNllcjVDq0R3kJEB23idco7azOHepmHDsYaA7Yfao3CgWCPeDiBREMAOJ1d6MniVdNAfJkpXX5TQsynfu727J3EiGss4zRQQEyYnUjRA9jkTyyBSA3bo789dVAucP8pGr0IynOV7YPjREqHRtU0kNiTpgTNvbzVXEI6DOrsAIz0fwd6p5L7UT14E8EeVlKEtLn9GoCe11RgKZTXxZAe5Vgx3eLrGvqBc468X4QSkpTZgPsr5g2eVvPOn4Re7J3gAPLPHV3TOtSBHEkJk3zVqjfyWn2NfP5EGRQZEt6hJY9WyftwflE58XA8CQRk8sqcpI8uB8qzQ6bW5wF34clOeprdSAXySKkXmatrjvbkWIFIcXiEpF3XtYuG5SLRqZVQdMp0BSdHHqo40fgylvB8DhDs8AOu84Xfcrhc6nu1OvYqQ2zijImsqoyJfA1wlhoz5bXq9FwrRMMwgarUH2XomFdmQRHEndjB37WaufbKmY3yA2uHXuZWytyCigp9CkgOBSUsni5SJwYvjgbc6OF8XTdtGAcjJ8430ttvQla86IXpn8K4xQ9NzpWKjIMLWpF0Lmuj1tCh1sZw468wKKu5gW75hSjlGxP6CCPUuns8Bts0R9BnuauCJBDwYQcf83Pfl64KLU5SR2fDrOaUUOOqPTcOmBtiOkBziG0rbstxWi5UAOFVWoM3Cufm66I6KWaEwHsBiVXGWWZGe7qHdIJpGwMOGqvUIzLQQqOsGfhMhE05Ca3XJSVBT3GqMQTdhFiETzIxe0smtZCnaobke2rDsCBWqwmIEcJO9RnEgXmJ7S3uTjxbocnryBcTTZOmTXS34zNNUwkxgbQzz5bYz9YXfO2wRIknMubuZ52eoPwfpmFWIPnM1DBnjQhnZpZ4WYi1rGFDoZ42TuUsJqIkNKVa37PQtzSD1pFln5opkKMvotWjDIH5gtPc8XuKBu8C53N1pZigWdMzk1BF4FU0u9yVkBIXn5U9RJlq1I1CHq0CNEE9MtDT9kVfTLfdWbXzOXLDi7c1YNIDKscSK6eFZJtETb9Hg848exAJHPnCS0OfuTyomUQ1GprtXO4hTkG1jVfz2mxJWFQTMp8q9VzKYnxCiuSeJK1rW3SNndFphKOukEguDUMRgE0Liro6N427n4CGJ5uZvNBtA4V1Ol3MJcc8rhxeOexKHfD7JaxCdHNkMIi15rl89J2TIjTbTn3QxiB3c1F3BlDYiVEtxQcjcQsDZRvXKSwY9BObgRDczhdSoniSWmQRYuN5m5v3B7nSNGI7JWsqcDw47LLI0hjupobVOKlPVxwG5tSIqF9jis4oTh2n2rZeNJCDiw2ZB5diiRy3GdvliGCdVYDWY1u8bVjdeoqbYb3z4wwgzeLyVGzhwh6r8GGSZ3sSeyijyk45bCmQprdLjGJry8mkD6lVauLaTtc41rcMPaf90hMKMIO0EGXnC5xiNE9UPm4CYR822cFSgPyFSzWX0myaVluLg39uD6uGC5ffYX05v96EYVHX8tdJqIWJcofsYFqhbRpcB1obSE4nEIH60qFMzZqgFZF96NYqJvgcggpJAZlpuoIL6dOWBjSQ7Oq29D70Vo91OA4dfqElI67Z4cl7pKH9o5uRxNFJuhcS83reLGWP0AdEzyFdh5DvUEtTdLLG0V36ZoHxIl2aMakpATFIkzt1lhsMV4RuM35DcyLtyy95zNJgKfg8Arx36KHRDKVixlsQRh71xkgaJdDqFodE5jqYgxtAVT0ytApGzVqpu6Gqa8KdjNR6kXTPAy6cFFcN8eyPaOd2zvghJeVP0jZO1N6VQnDAZhWPZkTB06QhP5Bc0SYzdrcsZAL7MI600HPKptVmKiV9JRi0BPHBdTUVI2UvttkKu9JDodSkaa4l70zqgEU4D2UxM7RIXTWVhWFxx6WAzLbYo2jChLvaoZc5ssSNlJ3CSAQivUKA6JAJiXe9e2QRYuryTtRfadg9bBST87N4ROZ0iMPZkzlV5kX0BMn3kEu3KjzdwsAo6dRaLveIjFsp1lhDymzZiaI2e1dxUQK7pm1eZiku7dhjRghmNXhWk63HAWscxINt9X7GchhPVQGaCtm5ClgFzDSG80XIxCOPhMc1BEt4lSpx9AWYul4RZwz2MBLsDtXYzZCHnrlPpnm5ULo7PvY1sijGf5sdsQJ59Vc8m2QAaXfufhNiLP4ZkrGAsqPKu0j3z7AJ9BFhTCRXYvi3lptGUjJITTbqZ7AaOrhJqiVy0TCrBx4dT8tKYzyDmuuc2H6XdjpCc9fE7Bd5eQA6YIuBSYm9o5TZS2iQSboVcCoLD0cAunXYdDw1SRH6j9GnXlLhbrMJmJCZNEk3JKNaWS72hDhMl0X5HSSuLSTlAiBED3vBEUlzJ71ziiZRvoGqdVuohon0t3oWRPxSMU11qqmcy8zDAeHscPYf9XK9svkaet4XP1szsSsO9IXdAM5mRH49TuYgRMaaYJTn0Dqtg7PutSyVrci5epIelzpKjgapNZ9QBngBo37kFMZzG1nsrWYMirLqh43Awy19KWqFmdu1EW69FNzO5PiIJ6FTDb0OcmyKFe7UsFBNZyb5a4k2lT9TMaJQb78i9NAPymFEfTYSCOjIsizDUFOvZZq0KBdWJcpttrTTqjaGDKwSwuYfGvimhzIX3Kz5Mrdl5NY1VkbTL1AXepHph4VMv7a8w1XPVyZ9LhHqACi4rMSNic4STgQEeMcGE9MIzCCfSmhlu5tlNM2SnFOFlYJ65KV58GXRGvgtu0pCEYHZhdBAHwrrDdDzZTml8y5aoP4c10qDGHhTaknPbRGsfxg9gZ99EWvwkN8FXBvwYLl4rGnWPtfFJ5X6xginnKoUpLkiXun59S3J6ihWvLvdoutgQTPMakGmPBplmNcePCNKwOi4MaIxo3LpjW297g5M4AduVBS30978kud2NKUMOcngIKL24ZWhaIpSdjWNfzraueFPsHj2mCJZc3ogQCV10BV8KDmqAtpNs9dfRLLQF4Io63d9SmbQJ9XC0GBase4uD70AVMMZ2gHngHERDxGoRvbwlZUas0tLmEPU0JcUhped99s2H4lPOTLTGkf0UnIh1BiPOQj4JKzUJjxuqK2lvZW9kQpU6Ps31931yltiynb3U3WWt9gZaICF0ieyg6Ncv9zLtTGMcJBZLbFktakzvUwA8Qban9mz9RIJVkCveFIpscb9dqTTH1q283PqsQHSlYe5qRMO1jasSlkeRp4Vf2souYPyBeXUmFie14CVMMmqV4OYTkAXEzuVGbIg6lwlfAAxtzjWHdcspFIWk2g2xg3OojL1qX6xgeJCnXZyoeVuhwIOlxBggCb017RR3iL2SwKkAW3x6I1Ssr7lCcMTRRX2n5YCBiXwLZM5dktC6uDPyPJGDyRDS9OQDKexwyouBP7RuVlYZZovjK0wVtd2vEe38rSi2XWUecRbvrTh9M1zAuMyHAGqlJvXeXWhBNRv4J59u15kclXOFGAgvyH8A07uUTyqpEv2tEounybNPspIBu4zY50wsJaES5tHOsAzVFb5aMTn3YoBuhtq98kOebU8Sn58crq9sMxUjDxAyipMavjKkKPI7qlIqSbZt0YyOyiBnF56YDvpcism5qukvHhgAdc3Z5iuYmQV6iRGqJRubqeOTZlrKUkCcHBuBRFPqVuaY7lE99uzpTM3zj9rw35WJbBwjaj7bRpsMI3SFOM6YcaOnmloA4fVYvFYpwTjutWZDVxctWmlzMxKyFU0fnWBA9izwShHTQFn9h8iaM0QArMiUjBvD1ttR0lZROuKiu5iquCvSLtG9FLQXvDs6Gg4HoffwydHeQmZovk1HqxnV26j3oF7jBQDqNnX9CgRu7yKmodVedrRrWZndkYoRMpdtr8R4dHjwaKd91VSEhwBtoIocxhJ8dm8rJP60zeh1NM4X0l3TvJ8JkD4fimKWhlp9whQgKJKQGklQrWf4pt4ERKbHzqWV2yR6voE2P0JZBZhr1mhw3JEgt9y0qHnKYj30EndMwBhFJ2iTLTD3uMYTmGTZ5w9M7gM1mg85B9RueGYBzf4nyhUvrOTY9NK7y53rg8Os0t5uc6nOmEj3bxNQBoJIbvejF0Eds53JeXaqWOZ7ZowqDv5V5A7qGn3XylMGdgoskIpnfK78dbpomOSlubQYy4FRU2WDm6jjEFdyVxDMO0pAAwqZVLgtokdzDIYiXYmRKUXnVvfRE2OPQSXEfZ535R3bpzuH3DfvOIjesKFxRL3jxUOMnv4oXKpLtsRsxOt1ET0G3zxIA8P0xR8HIscajyWZfNb3za0JkdiADaqJqhoPJXruf8NZGtWpjoj62m6mH2zKOInBQtbrzhaj9jXlOHrqQiAwLjZOQ4brdK6A0Exws1XufJQZMj1HK9U5pE5tL9UMgv7tLbdc5Sdq0mHEDWyPZ3MQiYuGedXvwRWGoCIUes0j4QB7MLKTtYioI1EMj4CasYafFdRnq67XpPcmNWVGtDIvrMwVhAeCObBR8Cz6k7Rw4ZqdsU2usVwe8ZcxgJA63XoAjjkVLIiwhi5qR39HrwqRNNeJw1Y8GNT7cIPeISEzF2iShi8YCgZsI6dG6ShCscG62T5OhjGAeLmaIhHARXJpeN7iICvPBAupmis0o1WtCEtZEBKDcbpUMBNRWGeiEpIym1j5utCMzpPY0RkvwRMhrbeGkk5EMyW1DmIHcJafR1g13gPq6UVnOxUdPFllDIL7e1AUvFAp5tJA8417RS5blrNkL0MJ4knJCn5fUG0PkZZxul4D0Yi23MU4YFPjKqTiroZcBYyluWIBNQSwtwb6w7vO9jD4bptiJTR4k63AP5EjjOits9vNhiuG0PbWuQGUGungyShkHcCY31qAJJXZzxT4q5wlISvLdaoSPbon2n8SAdmPuf8zAP6QtN3zrtgQCnI9RJF65StPRxQPJrwubfv17lGEswlEzjdzmXxwSduE1kGeYNcpP4t8ifcaaHJcJggNfQ0ns8ZIk7jgYlfb1EQVelke0jnRMPFv5V9drVRkNG8SJNUeZkwUwPDbEr7egvBQ1DeDZEIopU5FCNUwes52J4kj3s4OqOCHTferHRueYhelrLxnHTryZBTw0ty1KQTqiuNvixfDsh7eUdyq0l1eJmF0LqoWWOf4DM6MFb7gYBNVLpMcGDzGKQ551MmpnHs9mTSTdBvjM5gxs3IOukZU9IYNKBzCpd9bM2TsnYDgiVZI4RzU2dHfmSFRF8is0lh94Vjr4C8WSmmMCZO2thhY73N2947g2EbA7gRaZ5ZCcP7tCoc42XFFofISZCqoYcgrdqc0vAdVQxzy4qRwnmqwg89TaUca4QPwK50YFtptAzIEy4eanRSuY2drMFjbwS2JM0ISONzsMe9rauSRnHv5lXc2525VV74x9e8qJmKXvb4ZxTVfeL7x9T42AYYONPUzm07V9InNLYxMTlGvXOQHPEiAxrqpuhniyMxWu7lK0qWvjIuEOeziAE4qcvPLdDYCHaLL6D1Mb3IV7UYoVM2aWxNZFv4oCJbZw3242C13daXib5xeNcPV1facdEjy5P9uHYsj0pUXyrM54ZU4l3MuDsFB9Fi3fvLo1rn34SJuVtrimquEqphri4tDwj9YKdafzGiTjOjZnOQRlK5YoTrLxduUUq2yq5TbAsZ1KDdL1LABlrcsOvk1wquae2SveXVvFaApGpjEpqTsYlOsnh9dKns7lUFpknQYmFLc1PGC8QbPnc4znoxZBxVbLDvP2iHYX1eTeJZdV8UEtXVcxANBtFZor0GcZUt8ZJPwYujH2VYBqn5m4lJOFhHn8zm8FkbRSrWBT1ZgcUhZkCzN7x8wD2kJol3dIMslO8WMmathMSPpXlOXo0gv5TVnIP1QGtMgF6HS6zC6qw1LJuZaxRKtLW1txAtzp16laC34uKO4bUxVhHxRbeVYm5HdlcKg2bjngy7euX9CoGBc6y4DkNNaOYXs9r1UIM2qOSpeCSDYjzmOlGRVuXfMf9yaEyW79cY1ALOGxfSJX9ZcyxTo7pquQAJSNheiNXXfjOa5JKdG5uwUi25e6ea83jt5EIxEABqO4qiIcn4DiNegm3Spao7BWDHphPxPOOEi5eJfgAEsSEvXCicHqcURfHLxkUGD4KgUPYzDlje0goWx0S0FSnKcDZ4X82Y63xzXvkFiFFNhbkx9hrhsNWH4zuhqlNTbgrNlbp2o62PADxp8dEEJ0deh5Nf27BCvpQZzuyqqHDnel4HIKHK0bs7zBitwHjBSq7j8bU5YdQdhyGhfaMfdxslAdceb2sWmf3jowh6Hjmbkam7xZJcOzyczrR45VdCML8fZO4j5STtnuREfwrfV21jxRrGJzOKePjLksn7UQPAjJ6JwQC0WqSL5eYdnI0A4SO6CKTExze2X5804qVvU5HikVOFV2YvF6JqRrOm75gh35akFcfK9t2IpIHKqsTfCbF0ZEpji4f2xelrjOYc6xIQGnVVNLympBc3tur2AyVowc6sJMrRU9Wo8m4gxkQXE5zl4PVB6hmLLAl58nZI5BhdJG2Ceo7QMzY57O0zI8gPq9B9o6W42mHfFzJmkzFKeT7lmwd3bhdMi0kj420YXX5ilrB2syoaocEbvLZYTwzn6PJFUbNlMZROnLIB3a42cqfKLSVeCqK9iDS3oFXTZu1qyxWvmxsYrnqFDO0Gxk54oF08PKiDcP63NnI4FAR7VT2eMlfUNDUYRVKYJ5sg5Zi7DxShaw6veNHS8MJGIfym04ZZJ0QkV01uFC1j41Ty1nwInAkuUdtEzUqzlblUtXO2cCTEGYVK0bHLs5Teu0ek7oQmJVzEU56hDZPDWA4DLWWilk294eBSjDmaQwNHyDUKFyJnEvbpaCquTEe1XSuJV2fTrq5v9Xptr5RJ90iRj0x9XqzNpPpfJqymiuf4zSXsO1lUyWKzq6gazeIIG0PVWPm1pcuv168J20HjXlvV8q2gk94DT5PUVu4yN2GcEUry945EZepmZxDwmpigcgHtWEgr0ZWePxS2cjtWvelXD2EbwfpNAO36dHmc9hSRdbznFjVgRxiU7RUdGaa5qpOKLNtImQWZa2tbEdZpDynYhqn1J0QbpRFd1pBdViQFwYqACg7cWGVbpHbhg3IcqWY92PDTxtqNJ3t8lUrlFctFbKMdfB1p6govoBKohsukYhUYXuoZgdGQV7MtF2oQjJOWZ3EN7E86UGv8ZhofCfqvF0azoGgWDR2awjEo7BoG46BEMScW8mfgNoxWaHRbE1r4EfcaoZrn05cOFPSPOTgz7jxgofcdOERFYrxEmgL9WtEuLEN1SR7SD0BMJIDjr7nimFCjRxFB2I4um3HI9lp73tM12PLDFfByKXwq6O96cyjJeBOTaQ67ZqgztUOBlwmyNdSd0JstUABRL9Qr5AbNkgErofPjZaICUvkF3Z4vJw2KJWXqBbA1a5g4mB2DRZL5HjQQTs8VZChyB6d4aqKxfxOh4lEXSFnWcbneLyhCdLk3nYcKEAYxcIaJr97d2cAq2BZxzhNEsk7g3lsoTQ5kkwx3XAASNwK6Cce410VikrnXsRpLxJY6ZUHAsNiUbWrQ2S5fedojU5y2Dcna0LCYpVd2btojsof7pDMYH84fCDzFiIe9kxw85iPGd5RJqspSweQJUE11MoSAjlwL98p03V69IBpIExzWHMxkTdiXezYI3atAdyehJMsrmvGBuIAUm93SZBctEI9NoliuzAgegXmTaAR0aYs2OwXoSX5mUpAT2ntktHi1V6oTPNQZb3QV2ATePx9LFX2Acwn9KjE30fk1r7rY3gyUKwJT7tK64n2ynGCTphZgXiawdZdlocjw1bOKfYDPQ6rC5u3pyynTXkwFcrU9HveCF1xJ6CKwr5GqgGKOtUD0qj7WONbGxmBhdIOh5doEvaemJEDXdcRafhjvaCYyNWzjyBFT18Dw8yiEYSsNzdKGKTXceIktCWXb6ATvbrAEnuPQmY9rcXWOFJUKmrxJig922r2JaUB0jufUMTeJ89nM1HyAmLETFslyKCGfsUQqxQLgLkNmNgshZybSGjIRH5dbwAIfCRPPA1BhunQlIWCmLAhu6W2P2Bjc72EgqBu4IhyLsOfTaK8TlxilhvPVDkIxoLXysuTDpgUO4pehRb9dSWKPrqc78Mtl1H5rl9Wi9wojlYr9NULc4jBqNimdd12V3fP78SlyhVWayKZewpyFi6ZcGcZnntcc7kdQFRMV2T1I3sMKghZ8mgkga8VQP4NNNIc3M7JZ1Yxxh1Nr3HhYgL0e0zRc1JIu8KnOoacmUcZbUbA78tJGzzXxzALbl9hqEf5xJWlTRdMO0W0EtUBBDy6adRJqzuFozdlCTOn8QcTHCQxDrXW07nHaKB8vWe4iBrGbzgmwN4XeVEfWT6gVmffvjzwafiM1MChlk2xcG5HU5leVpGMx6XgchQIT05HHganqgLLzSWKTu6A642S435JrmQbOiTLCc2FghTco3P0Z3FqUHQtGLkIMQymtzM0xHvQZ8Cn1OLMheozhmriHtDR3gZBUfSyZu1jbTsJZ2Z2n3XCaL4E1dmKgrj6C5LNuhnAfK0cF3iJrj02SPCm9GvBkSJEtFctmkwO3tf8eyGQXdCzyFDvbJ6yb1vkh4ngLVUVWw0tnldNlnEHBTiifrbpkoIVC48K0RckHYRjse7XfX88LFAKXrdkAaZk4pENMp7HJqnigtVkhKMs5k9kzKMN6cNn8S3BVCCbXfRKIQHo6okRJNKdacPKb7NUwHLFrT6NDuBzTbbkUV8cPZYSEd8Pj7zeoh9bz8zmWp5JuL8dlmBvZwBpvcTSVavwQbZ4vz1zA0LXcxIo6iB9gy0rDcP5OXuvsPBNim7b3Ulf98VsWpoTwaK2c947dGwp9vwAFWKvKRQAkKr2Jt19pbLpmtkez0B3B1KuSgnI7v34GlnFohuvxV44aqz5aSxSKqvaoH5DnDEUMfCmhhU7y4Gq414nvgVlUtsM0LehzProJ5XG2qj4P05KMhJY1x4KLg1A7m277J2OpmGYw8LlyfexCaohv5VBaL4woOUTfgDYttK1RJmHQzMjc0C7yTCRFb96E7cAi53KQtEHIQ8fm59uBIRyunexa0TZjt06eX6VtsklOSAvTAOHTR52OQIUlAVmMLqUxFeNpKNbCxItaVwd2LH5LJ4nSYAjC91cxqIqOFeHbPZX5AcISm9f4q3ZZ7acYOmbwpJyhqreZpdCL5wwBwTwe4w9pVgflTsBAd4IAOngjFyxEyEYJQw6flj1UKZRt2dCAVLQhgvpdAnGmQ0V7BKeuztD0XjaRR2F0WT8ymXYPyAeXmt6TX7HCZBSREoqWF4Fi4LAXKK4jFDJHRZxHInhowhCLaSQvH1jwSNGd8x24I6RHjGpU9t3TvOG74f2FgkSWIPxS84HwHGqJQRQFsND2mJelnyhPUQXJePdlw8ggpdTzS6lknBgyXuvL0alHNtr317Ntd8w7xbetXvE2RuYRJ8PbAvW6kUKOZUwI3es0dZQuBECb5Si0jmFPqKgLyam0PIcNVt32tlJYB0krX5I6oPOVvM3v7aSraEKukODhzsrKlMVZrSe5cd9kMiflpknXPIVdaKFwa2ZF49gxWn44VxvufAAJUCSbZotkkfXL1FtGTJWuGQOQ42DtzCiyeuHPfVm78oGKKdCo8xUjE68iaI8XBGAFzxFZlFifmOemLmAPIUDFJfcpZA7iM5mXCl1pZ0fYa1apm13OxI4BM1k8HirBIP3vIE21xSmJGi1oCw7RJZQpcsSqbZhgToBjNHw2VZWt22QaCaNOOeiUO1Cn8jMhz5myRRP0x4fjBokzExF9aPyeSLc26IqguS1DY1WVNq2YeokbbPMRLYL3sRlos4kVld0nMES1I9qCOq3jX9pcuJvvqxLeBKytIbsFvWqIWrLclpoXkX0kwcpSSN9jzLPsOuqGaZJ13M2FpKghll0gGTFv2d3J54Z0FKuaV8YYaiboU2mnKD0lmZsyoQwP5TjvhgwS5yyb5EroVghVazmN4bV7Vx2QXF8X5iyN1yXQyWo3Z2cbfYGlXPl7JNZTB6zZnk22RHFVPohwB1WQV9UO1w5Ba6NDF99dS2GYIL35GjqwQMJWZSI9zAmlAOHQFLltJ1QFFV1AzVtag5IXcBZh8WPi0zARWkaza0tGc4E4DRcxPNHJKe8hodNwpzepIkHhF4o2n0mrW37TNhLGzVLQiRXz5jxJUPLt6RzcjJczaFiBT30r8DH2AR8Zb0ykHX5AkibRxmOuf65UiGzg5tPC5gzvl9YR7sCoBsvehZ75W39Ft3rJYu9XBTbvRmBWbAG9C319LE4sSXIJMWdiIiqRB7pHMtqOsBxvaxqhG76c7ZHVPQWjSPUSsKPT9u0igpMImQwTlucg2SK1AUvyAb1BWayRyI74L6fBRGJnODjzFNFGTw9i09H26EqGhk8Mwl5asCfOkq2BUMJBm3THPyTyWPgon5TjShJTnRKY23kOUzQlqI6R6pfO60W4kh1NhCvIE722cjCe1FHFHFRGRAC0p4dD0qavTHetkPdw6m8jahBjM51umzUvuVG6gKXOn2EsqSnAVgo3SNOy85q6xgvc6Agufzc1cUMae3EnskPYtiur5KjOJteqJAK5bu7a7MHNa6IFt3tpr7rFGhYs9ZryzdJ82wOgqXGdetzBNt5Q8lJ3V6oCxft5tls5gFD7Phsvb2FNBfwvTwU4cf1gbJg4OBI0sLyjnt4AWGi7Li2cags0HTGiXd23RbiCrgbGV05aRxsmZ9yrspDywJzNypZjqzPUR2GJ6CBsYTSk24epESlNneSTzz8ZNj62bQbYgK9I2HMYLWTERp9ORncQcWrJFZXXHk39nJhetbtQkemISUigVO4r1e5atX7d7ymPCOiL9JKB48aXsyWbEvh1TzVGtFwnWDBF7b0T445GCLA9frQqyhqkPIPvhdtdazYTJiMnyep5WsdvNDHcZcARRj6ueDuKMh2cZg2glnZvI1EvXKxtfkwQDuNWhxWhwDfFFfHIBuRlNPwbazdcnN0ab481UXYWqb8U4DTLlXXeEbgZ83dle04xKEBLKwv7Vx4XkALEmcXPPxm9DVvLz0909PEw62sRiPJYSverLPHRrIvIZtvSdkbcQjfZUB0dLMvdYD9qpN1x01fITztzKottDn1LsM2TsjkkN9v3bhxXw1D4i1tZObpdthzghM9mQO2OK3jynSC0jkpvCK1CVoKU3czIGb2lbnVo3IIFPujLFLSAPJVtCXs6FeiFN6q4PiRsnB5lcEgME318wl3JODIcfbfI7sSgV7GgogHaL9mGPMzxZehFm3TMnu8gTWlnK7At84GisJ9cPXSoQKB00NCkE90nNNWeQIAdKm3zzYsxF1m1ov4mAW5QDOr9FhrqnvJ9XmY1zgZ2pACM6buwefUpKdBxCUV0aMD0aPcrKFJ2DbjUGbOGIyTfx1bBTPmqPnZGDqz122IaSNWZK6awMu2uzMPOyD9XGsVwgWiFiIaWPSSedM3qLqCsGg8veLeZDlXTJj0DZfBVMljpCF5Efn8b8SCcz2iiOwCcGtITl0pCJ51gT9ptbLdSvEjEgS4elbkAV6Y4o6mk7K9hKEcpUpM2N7hG2gplYpEQtJ0YZeIULN7tgJw9YkA36BiVlO2M3Bi1Si9Uyc9w1dUWDkvYCErs07VuPRwHCDklpvELO03HA5UtR7HDG2SyRk6EJOkotNC1rFaEvQgertCKJ3gyKK4lvbS04ZlzKgKkAruaFd1WcgWF2UuAozGWAStIWM4Mi3wBMiMtBV6UnHHDEQ9dy0EtSzvvIzHqvEyIozEO088CfE8MTs2P66H5yVB6oGYHBMJ07ktnoTzvRaOc7a2ezantsKDh7Bg77GpdFDsujgyllltRfah14IHYeooJiWbaSHZfLTeK4fH8QEvBCjkYwrKyHi9QZdh6OjVi8dJB3pLQKiX2W9MtvHbCG6ASy0tDVE6D8Qia0sD7sAgc3SZ7fJHAv08IgtFk7SY8OFGSwWR2TpMIq5IdagqaOCEHq8GRfS0smoM06iN5TZXuKCdv3mi8jyKr9d9kAw9HKsoVsct5BzK8htGLlEYqppqkpyNResxxqy8dogD5T8WnZpXgl9SpjQuSuMHqz5xbK6LJ16TtPY2AwEkqiye5HFKuJ06KUzMl694BdPRsGH2XbMb9cN5kLe1n7krHrYeKRiu7eIf9nwFvtL60pDnKYXGNoztB0PVo9PAprw53u1DkcGH5rvrJLMR0U51YFyv8TPrN5VmlOGOfcr4Z17uAmwXsHtWWKxOFmr8mYeUS6d3iKYrW0ABHRWxobqdZjhdN8PjQci6fWOW86karZDCK8TZxgDzqwyLj8GEZWrmmJ11oKdDPiIttqZetnoPhqgSOjpEvinPELKTWgRo0HaN4Sk6CskncSpHDTen6rKNS9kZCox5HyCLlSAjjy4CWLeF7gsg1gemkCWCr6PPXfbulcCkOgACQOjqLzILQTWxl59XqQ7QPSv5OnbJQslTSgWVzjUdJK1W5RkNnMq1kcsq4XOBEDGCHPiEmwzcO7JYHPjxZaK1zPCbdi3gsgSHpqxzr1EjR3rRrSAL82Z6p6Kd93aS1THCORpqz2YLnMurLFl2fovUeO6PhrhjKULM5ARmZjJfe01KWyRE0xLvvLmIzSmRoELQsetRH6Xcb18vAzGOeJ9IPcDAFoGb4SDDUjDSQj2hnhreybOMQoDmY5QwPscll6NCAo4Xvo5JZ0mum62f05OJXCwUfBkcC0DuZhuW1gMBUhQdGVfjWNOhOBtHqJymZvEmA0zsf6TgywDPYt55VyMHv8uTgCSXvGDqZE0BSDpVSlnTdenDdi6yvLOddVMwPGvAxM3GS9DfkOVddfGkm7mqdxvyRADr9h0lEGqFYKU0LyVolsPJEgmMrD47YV1FwJFRqIsqRL3jjMT2499ZpaCjY2wdHhqawJJ6ntlLWSSWZMUWDVqrPrdHToevWwrFb2Y6Hh3D80qeBnAKiHE48TAxf1KiQjyEYaReNrUUp8QtWV3YIAqPHTHR9tcDa9vrKPxmNjJ7wUq4haUSmuDykmNh6bRfJ3xkdBnCFDmfENYmxnFSznULzohMSuvkC4yl9ATLaahEsf7W8ZC0M5kDr7U4qHSDj1EEgUzmzFNmFJVvfWLYGsfohfakC3wKdkS7NSjkYYALRTGe047sKKCIPBjGOgMiiTgUjlqs0t21XeqIVOpuO0OCs8fWoWb1mZQ5w2kr9ZFc6pXkyUU3Taxi8kF2uvGg0uTvE750N88AzylpQS6I4lcp1lRKE4ntBa95xc2w4ZA7NeuMf7ilvkckewDILSvWd14lKFqcni5NgleG2qFN3ZJiJkEXUwBw71Z4SVqaMZ9qxPdQoPFyo4oQ7WazDoaVtQOWF1i4r5U8I3XDAMC5c4ilxZJ16imFEFD3ZKtzMcqcPcwJNJmgraxueWqFAozNCSOe3Mq7fl4UY5CZrlne1hiABhNZRydMIjOpfD1TlDAVTo6SHpoF1VSqeL6u88gRnUhRShZAOiARNNtvXbkPDOpz6iKOGNfx3ONG98Jw92LPaWb21574MT4CfqVyXvXm6OnE8AwOZBRjhv7iREu2vd06RXDnozurXCHH8UY4PaArZmXxwHkDxSZG2gndxiXucD3pCallCWjlwis6E8y7pm0KX2LOuuu2bzmkZreK0RWDbjXyNFOujJavW73QiewPE6SEkEhEEd7pYUpQ1M6m8ZvjtpvBGuICbZB2SHUakc9pRUWLEyYZbIo9MtxX8uLFGa6Ws7xNQDWZzl5mVK5tFpsNXGdGHmsHPyzBaS1eH3inrF9SpWNhn9MmPIxYgQTePuMzxYbFSi9fZzupQqg3pg35xngRuEiXcCGAAPeLzc0dUgBqvDdQU4JTZo3IYlq7Ku9hrjwQvEcp9Avv3G8H8d2f8TxIl2UZ5qlU5GiXWBaXfWDJw1l4lJp0VYPzPKlgzpH2ymLM5ho4PbTYVIzeJCDHwmWaZ9IndHvy0RNo8uVeiVfZj9KyehznkKhhUplXrWHmmvxpgScwshAmSR6INiY3meNXvRR5307m9re08wFVOT1qAtseYYQeemBqtz3oZxT6J1HxctKZ1VjHx90k2MjxCnHtyOhmKFcm2ikDMFC7cjLwHzeEqsul2pTKxPHVqz98YDB5fYhKW1DGp7WI4LHxCFCdpKgeCb62OAewEhzuVdwOVkrqpo4ztHOWJqgtZ91c1xzHhFwDs0BxrlUomZ5OP5WXmTVZiKyilTzZlSM5ZYOwLqCqkAnHCowegTHx4yxroF3fTeMIQyY4i0jhkKHboauX8nmxVfj0tP143ZCA13oK6DOaFSQaHAiUKuWKuPAng0QZsumL8TCrWJcDqK4rOVIXudjohESXTo00yqlwm1BHr5Dz10QkBPRKOkvEcYGcdsiGslVsFWG5SnRqV3DOQY0SEjUrhzusSLnXpxLRIUJbyUg6dINoRsv314IilYlCb7SWIddKgNLGr2C8EFNviIIOZlzwiMPI8je5rplPhWbqOrOydhyUwp3TxgwIXsyJAzP3TLGVyeEW5YqfEhs755yPSgphvTNzqzGwGAogSFQrcuLl0RWyHq68EtAl3eoa4yJNKX7LOOlIHzNIeDrgMSVvOeGUYhtCjBBABO5EvHVtljk8mcSv22U3RU83YZE3OltwXtkrEelQmLXdd3NHQZ7863qWSeZtoyLqJnr8SNjkiLInteOfcrO2eqtnEcViS0uNBKJJLIfaFSXlvG33TBK3kryNo6fRL4lWFjiyUD6LtAWXHy7qC51tRIealSGiadp0RNEhCvrkfpGKYekGcZbyn5mTBNVqHKsqnOXM9dxHlud6Ly4zsksG16OzrhB7NJHuc4nRkAhGyWLfsha6omKYklWBgu1rJOffadvoxuR2FvHqW6th7qON13ZUCoOpBCEbRqvR09biRbxPwpEqpE9RTrctT7ihcaF311VrgSG1hLj3DBPqaodJ6qAfM03qmozpaiYCOHJTzZU5k7RGbfEsReiRZUinS0qmU90Jgfh5etU3pFjz0UcG5V62SEtQEPpgKuqEmFbAy0fHBjlCwt74bKNnjmAnasd8WV2uM5lNZdqDDQYJKMUM83cVY1MGBFYooRuzXEAWuolj2NZb8Kky2hDtnitt91Hlm0Q9sgf7sJkHNs1OIt4QMR9casnkIXXA4IiUnQYbzLHtBGIRDSQKLNay2sBTftNqdKpJ2akuEWD7BVLm3HyAgiRqPH3srBnYdQKvCre65ukj3l3EIecuy2pm5cznUWPfUERwhwARCTUVcQ69GIHehTixL40zoDf4OP3mdHJrm#!#nvarchar|-|b|-|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😃 +prepst#!#exec#!#varchar|-|a|-|#!#nvarchar|-|b|-| +select * from VARCHAR_dt +drop table VARCHAR_dt; + +create table VARCHAR_dt (a varchar(max), b int, c int, d int, e int ,f int, g int, h int, i int); +insert into VARCHAR_dt (a,b,c,d,e,f,g,h,i) values (NULL,1,2,3,4,5,6,7,8); +select * from VARCHAR_dt; +drop table VARCHAR_dt; + +create table VARCHAR_dt (a varchar(10), b int, c int, d int, e int ,f int, g int, h int, i int); +insert into VARCHAR_dt (a,b,c,d,e,f,g,h,i) values (NULL,1,2,3,4,5,6,7,8); +select * from VARCHAR_dt; +drop table VARCHAR_dt; diff --git a/contrib/test/JDBC/input/datatypes/TestXML.txt b/contrib/test/JDBC/input/datatypes/TestXML.txt new file mode 100644 index 00000000000..11b9ac8e138 --- /dev/null +++ b/contrib/test/JDBC/input/datatypes/TestXML.txt @@ -0,0 +1,11 @@ +CREATE TABLE XML_dt (a XML) +#prepst#!# INSERT INTO XML_dt values(@a) #!#XML|-|a|-| +#prepst#!# INSERT INTO XML_dt values(@a) #!#XML|-|a|-|Contact Name 2YYY-YYY-YYYY +#prepst#!#exec#!#XML|-|a|-| +SELECT * FROM XML_dt; +INSERT INTO XML_dt values('Contact Name 2YYY-YYY-YYYY') +INSERT INTO XML_dt values(NULL) +#INSERT INTO XML_dt values('') +INSERT INTO XML_dt values(Contact Name 2YYY-YYY-YYYY) +SELECT * FROM XML_dt; +DROP TABLE XML_dt; \ No newline at end of file diff --git a/contrib/test/JDBC/input/ddl/temp-tables.sql b/contrib/test/JDBC/input/ddl/temp-tables.sql new file mode 100644 index 00000000000..61c5b7d22ed --- /dev/null +++ b/contrib/test/JDBC/input/ddl/temp-tables.sql @@ -0,0 +1,303 @@ +USE master +GO + +-- +-- Tests for T-SQL style temp tables +-- + +-- Basic temp table create/insert/select using tsql dialect + +CREATE TABLE #local_tempt(col int); +GO + +INSERT INTO #local_tempt VALUES (1); +GO + +SELECT * FROM #local_tempt; +GO + +CREATE TABLE ##global_tempt(col int); +GO + +CREATE SCHEMA temp_tables_test; +GO + +CREATE TABLE temp_tables_test.#local_tempt_withschema(col int); +GO + +INSERT INTO temp_tables_test.#local_tempt_withschema VALUES (1); +GO + +SELECT * FROM temp_tables_test.#local_tempt_withschema; +GO + +DROP SCHEMA temp_tables_test; +GO + +-- various catalog/schema cases +CREATE TABLE non_exist_db..#tt(a int) +GO +DROP TABLE #tt +GO + +CREATE TABLE non_exist_schema.#tt(a int) +GO +DROP TABLE #tt +GO + +CREATE TABLE .#tt(a int) +GO +DROP TABLE #tt +GO + +CREATE TABLE ..#tt(a int) +GO +DROP TABLE #tt +GO + +-- Implicitly creating temp tables + +CREATE TABLE tt_test_t1 (col int); +GO + +INSERT INTO tt_test_t1 values (1); +GO + +INSERT INTO tt_test_t1 values (NULL); +GO + +SELECT * INTO #local_tempt2 FROM tt_test_t1; +GO + +SELECT * FROM #local_tempt2; +GO + +-- Implicitly creating temp tables in procedure + +CREATE PROCEDURE temp_table_sp AS +BEGIN + SELECT * INTO #tt_sp_local FROM tt_test_t1; + INSERT INTO #tt_sp_local VALUES(2); +END; +GO + +EXEC temp_table_sp; +GO + +-- BABEL-903: create temp table named #[digit][string] +create procedure babel903 AS +BEGIN + create table #903 (a int); + select col into #903tt from tt_test_t1; + insert into #903 values(1); + insert into #903tt values(1); +END +GO + +exec babel903; +GO + +-- BABEL-904: drop temp table +CREATE PROCEDURE babel904 AS +BEGIN + create table #t (a int); + create table #tt (a int); + drop table #t; + drop table #tt; +END +go + +exec babel904; +GO + +-- Visibility tests + +create table #tt (a int); +go +insert into #tt values(0); +go + +CREATE procedure temp_table_nested_sp_1st AS +BEGIN + CREATE TABLE #tt_1st (a int); + insert into #tt values(1); + insert into #tt_1st values(1); + insert into #tt_2nd values(1); + insert into #tt_3rd values(1); +END; +GO + +CREATE procedure temp_table_nested_sp_2nd AS +BEGIN + CREATE TABLE #tt_2nd (a int); + EXEC temp_table_nested_sp_1st; + insert into #tt values(2); + insert into #tt_2nd values(2); + insert into #tt_3rd values(2); +END; +GO + +CREATE procedure temp_table_nested_sp_3rd AS +BEGIN + CREATE TABLE #tt_3rd (a int); + EXEC temp_table_nested_sp_2nd; + insert into #tt values(3); + insert into #tt_3rd values(3); +END; +GO + +EXEC temp_table_nested_sp_3rd; +GO + +-- should fail to find these tables +select * from #tt_1st; +go +select * from #tt_2nd; +go +select * from #tt_3rd; +go +-- This should print 0, 1, 2 and 3 +select * from #tt; +go + +DROP PROCEDURE temp_table_nested_sp_1st; +go +DROP PROCEDURE temp_table_nested_sp_2nd; +go +DROP PROCEDURE temp_table_nested_sp_3rd; +go +DROP TABLE #tt; +go + +-- creating temp tables with duplicated names. +create table #tt (a int); +go +insert into #tt values(1); +go + +CREATE procedure temp_table_nested_sp_inner AS +BEGIN + CREATE TABLE #tt (a int); -- same name as the top-level, allowed + CREATE TABLE #tt_sp_outer (a int); -- same name as the outer procedure, allowed + insert into #tt values(3); +END; +GO + +CREATE procedure temp_table_nested_sp_outer AS +BEGIN + CREATE TABLE #tt (a int); -- same name as the top-level, allowed + CREATE TABLE #tt_sp_outer (a int); + insert into #tt values(2); + EXEC temp_table_nested_sp_inner; +END; +GO + +EXEC temp_table_nested_sp_outer; +go +select * from #tt; -- should only print value '1' +go +drop table #tt; +go + +-- procedure with exception +CREATE procedure temp_table_sp_exception AS +BEGIN + CREATE TABLE #tt (a int); + CREATE TABLE #tt (a int); -- throws error +END; +GO +EXEC temp_table_sp_exception; +GO +select * from #tt; -- can't find the table +go + +-- drop/alter tables +CREATE procedure temp_table_sp_alter AS +BEGIN + CREATE TABLE #tt (a int); + CREATE TABLE #tt2 (a int); + DROP TABLE #tt2; + ALTER TABLE #tt ADD b char; + insert into #tt values(1, 'x'); +END; +GO + +EXEC temp_table_sp_alter; +GO + +-- constraints + +create table #tt_con(a int CHECK (a > 10)); +go +insert into #tt_con values(1); -- errorneous +go +CREATE PROCEDURE temp_table_sp_constraint AS +BEGIN + create table #tt (a int CHECK (a > 10)); + insert into #tt values(11); + insert into #tt_con(a) select a from #tt; +END +go +exec temp_table_sp_constraint; +go +select * from #tt_con; -- should print 11 +go + +-- statistic + +create table #tt_stat(a int, b int); +go +insert into #tt_stat values(1, 2); +go +-- valid T-SQL create-statitstics is not supported yet +--CREATE STATISTICS s1 on #tt_stat(a, b); +--go +drop table #tt_stat; +go + +-- BABEL-322: '#' in column name is allowed in tsql + +CREATE TABLE #babel322(#col int, ##col int); +GO +DROP TABLE #babel322; +GO + +-- BABEL-1637: rollback within procedure makes top-level temp table gone +create proc sp_babel1637 as + create table #tt_1637 (a int) + begin tran + insert into #tt_1637 values (123) + rollback + select * from #tt_1637 +go +create table #tt_1637 (a int) +insert into #tt_1637 values (456) +select * from #tt_1637 +go +exec sp_babel1637 +go +select * from #tt_1637 +go +drop table #tt_1637 +go + +-- cleanup + +DROP PROCEDURE temp_table_sp; +GO +DROP PROCEDURE babel903; +GO +DROP PROCEDURE babel904; +GO +DROP PROCEDURE temp_table_nested_sp_inner; +GO +DROP PROCEDURE temp_table_nested_sp_outer; +GO +DROP PROCEDURE temp_table_sp_exception; +GO +DROP PROCEDURE temp_table_sp_alter; +GO +DROP PROCEDURE temp_table_sp_constraint; +GO +DROP TABLE tt_test_t1; +GO diff --git a/contrib/test/JDBC/input/errorHandling/TestErrorFunctions.sql b/contrib/test/JDBC/input/errorHandling/TestErrorFunctions.sql new file mode 100644 index 00000000000..30612073958 --- /dev/null +++ b/contrib/test/JDBC/input/errorHandling/TestErrorFunctions.sql @@ -0,0 +1,190 @@ +CREATE PROC errorFuncProc1 AS +BEGIN TRY + RAISERROR ('raiserror 16', 16, 1); +END TRY +BEGIN CATCH + SELECT 'CATCH in Procedure 1'; + SELECT + ERROR_LINE() AS line, + ERROR_MESSAGE() AS msg, + ERROR_NUMBER() AS num, + ERROR_PROCEDURE() AS proc_, + ERROR_SEVERITY() AS sev, + ERROR_STATE() AS state; + + THROW; +END CATCH +go + +CREATE PROC errorFuncProc2 AS +BEGIN TRY + EXEC errorFuncProc1; +END TRY +BEGIN CATCH + DECLARE @msg NVARCHAR(4000); + DECLARE @sev INT; + DECLARE @state INT; + + SELECT 'CATCH in Procedure 2'; + SELECT + ERROR_LINE() AS line, + ERROR_MESSAGE() AS msg, + ERROR_NUMBER() AS num, + ERROR_PROCEDURE() AS proc_, + ERROR_SEVERITY() AS sev, + ERROR_STATE() AS state; + + SELECT + @msg = ERROR_MESSAGE(), + @sev = ERROR_SEVERITY(), + @state = ERROR_STATE(); + + SET @state = @state+1; + + RAISERROR (@msg, @sev, @state); +END CATCH +go + +/* Outside of CATCH -- test 1 */ +SELECT + ERROR_LINE() AS line, + ERROR_MESSAGE() AS msg, + ERROR_NUMBER() AS num, + ERROR_PROCEDURE() AS proc_, + ERROR_SEVERITY() AS sev, + ERROR_STATE() AS state; +go + +/* Outside of CATCH -- test 2 */ +BEGIN TRY + SELECT + ERROR_LINE() AS line, + ERROR_MESSAGE() AS msg, + ERROR_NUMBER() AS num, + ERROR_PROCEDURE() AS proc_, + ERROR_SEVERITY() AS sev, + ERROR_STATE() AS state; +END TRY +BEGIN CATCH + SELECT 'Not arriving here'; +END CATCH +go + +/* Multiple errors in single batch -- test 1 */ +BEGIN TRY + SELECT 100/0; +END TRY +BEGIN CATCH + SELECT 'First CATCH'; + SELECT + ERROR_LINE() AS line, + ERROR_MESSAGE() AS msg, + ERROR_NUMBER() AS num, + ERROR_PROCEDURE() AS proc_, + ERROR_SEVERITY() AS sev, + ERROR_STATE() AS state; +END CATCH +BEGIN TRY + THROW 51000, 'throw error', 1; +END TRY +BEGIN CATCH + SELECT 'Second CATCH'; + SELECT + ERROR_LINE() AS line, + ERROR_MESSAGE() AS msg, + ERROR_NUMBER() AS num, + ERROR_PROCEDURE() AS proc_, + ERROR_SEVERITY() AS sev, + ERROR_STATE() AS state; +END CATCH +go + +/* Multiple errors in single batch -- test 2 */ +/* Nested TRY...CATCH */ +BEGIN TRY + SELECT 100/0; +END TRY +BEGIN CATCH + BEGIN TRY + THROW 51000, 'throw error', 1; + END TRY + BEGIN CATCH + SELECT 'Inner CATCH'; + SELECT + ERROR_LINE() AS line, + ERROR_MESSAGE() AS msg, + ERROR_NUMBER() AS num, + ERROR_PROCEDURE() AS proc_, + ERROR_SEVERITY() AS sev, + ERROR_STATE() AS state; + END CATCH + SELECT 'Outer CATCH'; + SELECT + ERROR_LINE() AS line, + ERROR_MESSAGE() AS msg, + ERROR_NUMBER() AS num, + ERROR_PROCEDURE() AS proc_, + ERROR_SEVERITY() AS sev, + ERROR_STATE() AS state; +END CATCH + +/* Multiple errors in nested batch */ +EXEC errorFuncProc2; +go + +/* + * BABEL-1602 + * Output of ERROR functions should be the same as error message + */ +CREATE TABLE errorFuncTable +( + a INT, + b INT, + c VARCHAR(10) NOT NULL, + CONSTRAINT CK_a_gt_b CHECK (b > a) +) +go + +INSERT INTO errorFuncTable VALUES (5, 2, 'one') +go + +BEGIN TRY + INSERT INTO errorFuncTable VALUES (5, 2, 'one') +END TRY +BEGIN CATCH + SELECT + ERROR_LINE() AS line, + ERROR_MESSAGE() AS msg, + ERROR_NUMBER() AS num, + ERROR_PROCEDURE() AS proc_, + ERROR_SEVERITY() AS sev, + ERROR_STATE() AS state; +END CATCH +go + +INSERT INTO errorFuncTable VALUES (1, 2, NULL) +go + +BEGIN TRY + INSERT INTO errorFuncTable VALUES (1, 2, NULL) +END TRY +BEGIN CATCH + SELECT + ERROR_LINE() AS line, + ERROR_MESSAGE() AS msg, + ERROR_NUMBER() AS num, + ERROR_PROCEDURE() AS proc_, + ERROR_SEVERITY() AS sev, + ERROR_STATE() AS state; +END CATCH +go + +/* Clean up */ +DROP PROC errorFuncProc1 +go + +DROP PROC errorFuncProc2 +go + +DROP TABLE errorFuncTable +go diff --git a/contrib/test/JDBC/input/errorHandling/TestErrorsWithTryCatch.sql b/contrib/test/JDBC/input/errorHandling/TestErrorsWithTryCatch.sql new file mode 100644 index 00000000000..3580bdefc4c --- /dev/null +++ b/contrib/test/JDBC/input/errorHandling/TestErrorsWithTryCatch.sql @@ -0,0 +1,979 @@ +CREATE TABLE ErrorWithTryCatchTable (a varchar(15) UNIQUE NOT NULL, b nvarchar(25), c int PRIMARY KEY, d char(15) DEFAULT 'Whoops!', e nchar(25), f datetime, g numeric(4,1) CHECK (g >= 103.5)) +GO + +-- setup for "invalid characters found: cannot cast value "%s" to money" error +CREATE TABLE t293_1(a money, b int); +GO + +INSERT INTO t293_1(a, b) values ($100, 1), ($101, 2); +GO + +-- setup for error "column \"%s\" of relation \"%s\" is a generated column" error +CREATE TABLE t1752_2(c1 INT, c2 INT, c3 as c1*c2) +GO + +-- setup for "A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations" error +CREATE TABLE t141_2(c1 int, c2 int); +GO + +-- Error: duplicate key value violates unique constraint +-- Simple batch with try catch +BEGIN TRY + SELECT xact_state(); + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +truncate table ErrorWithTryCatchTable +GO + +-- Error: duplicate key value violates unique constraint +-- Simple batch with transaction inside try-catch +BEGIN TRY + BEGIN TRAN + SELECT xact_state(); + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +IF @@trancount > 0 ROLLBACK TRAN; +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +truncate table ErrorWithTryCatchTable +GO + +-- Error: duplicate key value violates unique constraint +-- Simple procedure inside try-catch +CREATE PROCEDURE errorWithTryCatchProc1 +AS +INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); +GO +BEGIN TRY + SELECT xact_state(); + EXEC errorWithTryCatchProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +DROP PROCEDURE errorWithTryCatchProc1 +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +truncate table ErrorWithTryCatchTable +GO + +-- Error: duplicate key value violates unique constraint +-- Transaction inside try-catch but not inside procedure +CREATE PROCEDURE errorWithTryCatchProc1 +AS +INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); +GO +BEGIN TRY + BEGIN TRAN + SELECT xact_state(); + EXEC errorWithTryCatchProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +IF @@trancount > 0 ROLLBACK TRAN; +GO +DROP PROCEDURE errorWithTryCatchProc1 +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +truncate table ErrorWithTryCatchTable +GO + +-- Error: duplicate key value violates unique constraint +-- Transaction inside procedure but not inside try-catch +CREATE PROCEDURE errorWithTryCatchProc1 +AS +BEGIN + BEGIN TRAN + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + COMMIT TRAN +END +GO +BEGIN TRY + SELECT xact_state(); + EXEC errorWithTryCatchProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +IF @@trancount > 0 ROLLBACK TRAN; +GO +DROP PROCEDURE errorWithTryCatchProc1 +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +truncate table ErrorWithTryCatchTable +GO + +-- Error: duplicate key value violates unique constraint +-- Transaction inside try-catch and inside procedure +CREATE PROCEDURE errorWithTryCatchProc1 +AS +BEGIN + BEGIN TRAN + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + COMMIT TRAN +END +GO +BEGIN TRY + BEGIN TRAN + SELECT xact_state(); + EXEC errorWithTryCatchProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +IF @@trancount > 0 ROLLBACK TRAN; +GO +DROP PROCEDURE errorWithTryCatchProc1 +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +truncate table ErrorWithTryCatchTable +GO + + + + +-- Error: check constraint violation +-- Simple batch with try catch +BEGIN TRY + SELECT xact_state(); + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE ErrorWithTryCatchTable SET g = 101.4 WHERE a = 1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +truncate table ErrorWithTryCatchTable +GO + +-- Error: check constraint violation +-- Simple batch with transaction inside try-catch +BEGIN TRY + BEGIN TRAN + SELECT xact_state(); + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE ErrorWithTryCatchTable SET g = 101.4 WHERE a = 1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +IF @@trancount > 0 ROLLBACK TRAN; +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +truncate table ErrorWithTryCatchTable +GO + +-- Error: check constraint violation +-- Simple procedure inside try-catch +CREATE PROCEDURE errorWithTryCatchProc1 +AS +INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +UPDATE ErrorWithTryCatchTable SET g = 101.4 WHERE a = 1; +GO +BEGIN TRY + SELECT xact_state(); + EXEC errorWithTryCatchProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +DROP PROCEDURE errorWithTryCatchProc1 +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +truncate table ErrorWithTryCatchTable +GO + +-- Error: check constraint violation +-- Transaction inside try-catch but not inside procedure +CREATE PROCEDURE errorWithTryCatchProc1 +AS +INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +UPDATE ErrorWithTryCatchTable SET g = 101.4 WHERE a = 1; +GO +BEGIN TRY + BEGIN TRAN + SELECT xact_state(); + EXEC errorWithTryCatchProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +IF @@trancount > 0 ROLLBACK TRAN; +GO +DROP PROCEDURE errorWithTryCatchProc1 +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +truncate table ErrorWithTryCatchTable +GO + +-- Error: check constraint violation +-- Transaction inside procedure but not inside try-catch +CREATE PROCEDURE errorWithTryCatchProc1 +AS +BEGIN + BEGIN TRAN + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE ErrorWithTryCatchTable SET g = 101.4 WHERE a = 1; + COMMIT TRAN +END +GO +BEGIN TRY + SELECT xact_state(); + EXEC errorWithTryCatchProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +IF @@trancount > 0 ROLLBACK TRAN; +GO +DROP PROCEDURE errorWithTryCatchProc1 +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +truncate table ErrorWithTryCatchTable +GO + +-- Error: check constraint violation +-- Transaction inside try-catch and inside procedure +CREATE PROCEDURE errorWithTryCatchProc1 +AS +BEGIN + BEGIN TRAN + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE ErrorWithTryCatchTable SET g = 101.4 WHERE a = 1; + COMMIT TRAN +END +GO +BEGIN TRY + BEGIN TRAN + SELECT xact_state(); + EXEC errorWithTryCatchProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +IF @@trancount > 0 ROLLBACK TRAN; +GO +DROP PROCEDURE errorWithTryCatchProc1 +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +truncate table ErrorWithTryCatchTable +GO + + + + + + + +-- Error: not null constraint violation +-- Simple batch with try catch +BEGIN TRY + SELECT xact_state(); + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE ErrorWithTryCatchTable SET c = NULL WHERE a = 1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +truncate table ErrorWithTryCatchTable +GO + +-- Error: not null constraint violation +-- Simple batch with transaction inside try-catch +BEGIN TRY + BEGIN TRAN + SELECT xact_state(); + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE ErrorWithTryCatchTable SET c = NULL WHERE a = 1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +IF @@trancount > 0 ROLLBACK TRAN; +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +truncate table ErrorWithTryCatchTable +GO + +-- Error: not null constraint violation +-- Simple procedure inside try-catch +CREATE PROCEDURE errorWithTryCatchProc1 +AS +INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +UPDATE ErrorWithTryCatchTable SET c = NULL WHERE a = 1; +GO +BEGIN TRY + SELECT xact_state(); + EXEC errorWithTryCatchProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +DROP PROCEDURE errorWithTryCatchProc1 +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +truncate table ErrorWithTryCatchTable +GO + +-- Error: not null constraint violation +-- Transaction inside try-catch but not inside procedure +CREATE PROCEDURE errorWithTryCatchProc1 +AS +INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +UPDATE ErrorWithTryCatchTable SET c = NULL WHERE a = 1; +GO +BEGIN TRY + BEGIN TRAN + SELECT xact_state(); + EXEC errorWithTryCatchProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +IF @@trancount > 0 ROLLBACK TRAN; +GO +DROP PROCEDURE errorWithTryCatchProc1 +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +truncate table ErrorWithTryCatchTable +GO + +-- Error: not null constraint violation +-- Transaction inside procedure but not inside try-catch +CREATE PROCEDURE errorWithTryCatchProc1 +AS +BEGIN + BEGIN TRAN + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE ErrorWithTryCatchTable SET c = NULL WHERE a = 1; + COMMIT TRAN +END +GO +BEGIN TRY + SELECT xact_state(); + EXEC errorWithTryCatchProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +IF @@trancount > 0 ROLLBACK TRAN; +GO +DROP PROCEDURE errorWithTryCatchProc1 +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +truncate table ErrorWithTryCatchTable +GO + +-- Error: not null constraint violation +-- Transaction inside try-catch and inside procedure +CREATE PROCEDURE errorWithTryCatchProc1 +AS +BEGIN + BEGIN TRAN + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE ErrorWithTryCatchTable SET c = NULL WHERE a = 1; + COMMIT TRAN +END +GO +BEGIN TRY + BEGIN TRAN + SELECT xact_state(); + EXEC errorWithTryCatchProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +IF @@trancount > 0 ROLLBACK TRAN; +GO +DROP PROCEDURE errorWithTryCatchProc1 +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +truncate table ErrorWithTryCatchTable +GO + + + + + + + +-- Error: creating an existing table +-- Simple batch with try catch +BEGIN TRY + SELECT xact_state(); + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE ErrorWithTryCatchTable (a int); +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +truncate table ErrorWithTryCatchTable +GO + +-- Error: creating an existing table +-- Simple batch with transaction inside try-catch +BEGIN TRY + BEGIN TRAN + SELECT xact_state(); + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE ErrorWithTryCatchTable (a int); +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +IF @@trancount > 0 ROLLBACK TRAN; +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +truncate table ErrorWithTryCatchTable +GO + +-- Error: creating an existing table +-- Simple procedure inside try-catch +CREATE PROCEDURE errorWithTryCatchProc1 +AS +INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE ErrorWithTryCatchTable (a int); +GO +BEGIN TRY + SELECT xact_state(); + EXEC errorWithTryCatchProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +DROP PROCEDURE errorWithTryCatchProc1 +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +truncate table ErrorWithTryCatchTable +GO + +-- Error: creating an existing table +-- Transaction inside try-catch but not inside procedure +CREATE PROCEDURE errorWithTryCatchProc1 +AS +INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE ErrorWithTryCatchTable (a int); +GO +BEGIN TRY + BEGIN TRAN + SELECT xact_state(); + EXEC errorWithTryCatchProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +IF @@trancount > 0 ROLLBACK TRAN; +GO +DROP PROCEDURE errorWithTryCatchProc1 +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +truncate table ErrorWithTryCatchTable +GO + +-- Error: creating an existing table +-- Transaction inside procedure but not inside try-catch +CREATE PROCEDURE errorWithTryCatchProc1 +AS +BEGIN + BEGIN TRAN + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE ErrorWithTryCatchTable (a int); + COMMIT TRAN +END +GO +BEGIN TRY + SELECT xact_state(); + EXEC errorWithTryCatchProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +IF @@trancount > 0 ROLLBACK TRAN; +GO +DROP PROCEDURE errorWithTryCatchProc1 +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +truncate table ErrorWithTryCatchTable +GO + +-- Error: creating an existing table +-- Transaction inside try-catch and inside procedure +CREATE PROCEDURE errorWithTryCatchProc1 +AS +BEGIN + BEGIN TRAN + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE ErrorWithTryCatchTable (a int); + COMMIT TRAN +END +GO +BEGIN TRY + BEGIN TRAN + SELECT xact_state(); + EXEC errorWithTryCatchProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +IF @@trancount > 0 ROLLBACK TRAN; +GO +DROP PROCEDURE errorWithTryCatchProc1 +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +truncate table ErrorWithTryCatchTable +GO + + + + + + + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- Simple batch with try catch +BEGIN TRY + SELECT xact_state(); + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + ALTER TABLE t1752_2 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +truncate table ErrorWithTryCatchTable +GO + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- Simple batch with transaction inside try-catch +BEGIN TRY + BEGIN TRAN + SELECT xact_state(); + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + ALTER TABLE t1752_2 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +IF @@trancount > 0 ROLLBACK TRAN; +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +truncate table ErrorWithTryCatchTable +GO + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- Simple procedure inside try-catch +CREATE PROCEDURE errorWithTryCatchProc1 +AS +INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +ALTER TABLE t1752_2 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; +GO +BEGIN TRY + SELECT xact_state(); + EXEC errorWithTryCatchProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +DROP PROCEDURE errorWithTryCatchProc1 +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +truncate table ErrorWithTryCatchTable +GO + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- Transaction inside try-catch but not inside procedure +CREATE PROCEDURE errorWithTryCatchProc1 +AS +INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +ALTER TABLE t1752_2 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; +GO +BEGIN TRY + BEGIN TRAN + SELECT xact_state(); + EXEC errorWithTryCatchProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +IF @@trancount > 0 ROLLBACK TRAN; +GO +DROP PROCEDURE errorWithTryCatchProc1 +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +truncate table ErrorWithTryCatchTable +GO + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- Transaction inside procedure but not inside try-catch +CREATE PROCEDURE errorWithTryCatchProc1 +AS +BEGIN + BEGIN TRAN + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + ALTER TABLE t1752_2 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; + COMMIT TRAN +END +GO +BEGIN TRY + SELECT xact_state(); + EXEC errorWithTryCatchProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +IF @@trancount > 0 ROLLBACK TRAN; +GO +DROP PROCEDURE errorWithTryCatchProc1 +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +truncate table ErrorWithTryCatchTable +GO + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- Transaction inside try-catch and inside procedure +CREATE PROCEDURE errorWithTryCatchProc1 +AS +BEGIN + BEGIN TRAN + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + ALTER TABLE t1752_2 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; + COMMIT TRAN +END +GO +BEGIN TRY + BEGIN TRAN + SELECT xact_state(); + EXEC errorWithTryCatchProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +IF @@trancount > 0 ROLLBACK TRAN; +GO +DROP PROCEDURE errorWithTryCatchProc1 +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +truncate table ErrorWithTryCatchTable +GO + + +-- Error: "A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations" +-- Simple batch with try catch +BEGIN TRY + SELECT xact_state(); + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + DECLARE @a int; SELECT @a = c1, c2 FROM t141_2; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +truncate table ErrorWithTryCatchTable +GO + +-- Error: "A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations" +-- Simple batch with transaction inside try-catch +BEGIN TRY + BEGIN TRAN + SELECT xact_state(); + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + DECLARE @a int; SELECT @a = c1, c2 FROM t141_2; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +IF @@trancount > 0 ROLLBACK TRAN; +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +truncate table ErrorWithTryCatchTable +GO + +-- Error: "value for domain tinyint violates check constraint "tinyint_check"" +-- Simple error inside try-catch +BEGIN TRY + SELECT xact_state(); + DECLARE @a tinyint = 1000; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +truncate table ErrorWithTryCatchTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- Simple batch with try catch +BEGIN TRY + SELECT xact_state(); + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE t293_1 SET a = convert(money, ''string'') WHERE b > 1;'; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +truncate table ErrorWithTryCatchTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- Simple batch with transaction inside try-catch +BEGIN TRY + BEGIN TRAN + SELECT xact_state(); + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE t293_1 SET a = convert(money, ''string'') WHERE b > 1;'; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +IF @@trancount > 0 ROLLBACK TRAN; +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +truncate table ErrorWithTryCatchTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- Simple procedure inside try-catch +CREATE PROCEDURE errorWithTryCatchProc1 +AS +INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE t293_1 SET a = convert(money, ''string'') WHERE b > 1;';; +GO +BEGIN TRY + SELECT xact_state(); + EXEC errorWithTryCatchProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +DROP PROCEDURE errorWithTryCatchProc1 +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +truncate table ErrorWithTryCatchTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- Transaction inside try-catch but not inside procedure +CREATE PROCEDURE errorWithTryCatchProc1 +AS +INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE t293_1 SET a = convert(money, ''string'') WHERE b > 1;'; +GO +BEGIN TRY + BEGIN TRAN + SELECT xact_state(); + EXEC errorWithTryCatchProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +IF @@trancount > 0 ROLLBACK TRAN; +GO +DROP PROCEDURE errorWithTryCatchProc1 +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +truncate table ErrorWithTryCatchTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- Transaction inside procedure but not inside try-catch +CREATE PROCEDURE errorWithTryCatchProc1 +AS +BEGIN + BEGIN TRAN + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE t293_1 SET a = convert(money, ''string'') WHERE b > 1;'; + COMMIT TRAN +END +GO +BEGIN TRY + SELECT xact_state(); + EXEC errorWithTryCatchProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +IF @@trancount > 0 ROLLBACK TRAN; +GO +DROP PROCEDURE errorWithTryCatchProc1 +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +truncate table ErrorWithTryCatchTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- Transaction inside try-catch and inside procedure +CREATE PROCEDURE errorWithTryCatchProc1 +AS +BEGIN + BEGIN TRAN + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE t293_1 SET a = convert(money, ''string'') WHERE b > 1;'; + COMMIT TRAN +END +GO +BEGIN TRY + BEGIN TRAN + SELECT xact_state(); + EXEC errorWithTryCatchProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +IF @@trancount > 0 ROLLBACK TRAN; +GO +DROP PROCEDURE errorWithTryCatchProc1 +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +truncate table ErrorWithTryCatchTable +GO + +-- valid INSERT inside catch after an error +-- Simple batch with try catch +BEGIN TRY + BEGIN TRAN + SELECT xact_state(); + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); +END TRY +BEGIN CATCH + SELECT xact_state(); + INSERT INTO ErrorWithTryCatchTable VALUES ('Orange', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); +END CATCH; +GO +select a from ErrorWithTryCatchTable ORDER BY c +GO +truncate table ErrorWithTryCatchTable +GO + +-- invalid INSERT inside catch after an error +-- Simple batch with try catch +BEGIN TRY + BEGIN TRAN + SELECT xact_state(); + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); +END TRY +BEGIN CATCH + SELECT xact_state(); + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); +END CATCH; +GO +select a from ErrorWithTryCatchTable ORDER BY c +GO +truncate table ErrorWithTryCatchTable +GO + + +DROP TABLE ErrorWithTryCatchTable +GO + +-- cleanup for "invalid characters found: cannot cast value "%s" to money" error +DROP TABLE t293_1; +GO + +-- cleanup for error "column \"%s\" of relation \"%s\" is a generated column" error +DROP TABLE t1752_2 +GO + +-- cleanup for "A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations" error +DROP TABLE t141_2; +GO + +while (@@trancount > 0) commit tran; +GO + diff --git a/contrib/test/JDBC/input/errorHandling/TestRaiserror.sql b/contrib/test/JDBC/input/errorHandling/TestRaiserror.sql new file mode 100644 index 00000000000..4b10bdc575e --- /dev/null +++ b/contrib/test/JDBC/input/errorHandling/TestRaiserror.sql @@ -0,0 +1,410 @@ +CREATE TABLE raiserrorTable (a INT); +go + +CREATE PROC raiserrorProc1 AS +BEGIN + INSERT INTO raiserrorTable VALUES (1); + RAISERROR ('raiserror 16', 16, 1); + INSERT INTO raiserrorTable VALUES (2); +END +go + +CREATE PROC raiserrorProc2 AS +BEGIN + INSERT INTO raiserrorTable VALUES (111); + EXEC raiserrorProc1; + INSERT INTO raiserrorTable VALUES (222); +END +go + +CREATE PROC raiserrorProc3 AS +BEGIN + BEGIN TRY + RAISERROR ('raiserror 16', 16, 1); + END TRY + BEGIN CATCH + INSERT INTO raiserrorTable VALUES (11); + RAISERROR ('raiserror 16', 16, 1); + INSERT INTO raiserrorTable VALUES (12); + END CATCH +END +go + +/* XACT_ABORT OFF */ + +/* 1. Not in TRY...CATCH block, terminates nothing */ +/* Not in TRY...CATCH block */ +RAISERROR('raiserror 0', 0, 1); + +DECLARE @m1 NVARCHAR(10); +DECLARE @m2 VARCHAR(10); +DECLARE @m3 NCHAR(10); +DECLARE @m4 CHAR(10); + +SET @m1 = 'raiserror 0'; +SET @m2 = 'raiserror 0'; +SET @m3 = 'raiserror 0'; +SET @m4 = 'raiserror 0'; + +RAISERROR(@m1, 0, 1); +RAISERROR(@m2, 0, 2); +RAISERROR(@m3, 0, 3); +RAISERROR(@m4, 0, 4); +go + +DECLARE @msg_id INT; +DECLARE @severity INT; +DECLARE @state INT; +SET @msg_id = 51000; +SET @severity = 0; +SET @state = 1; +RAISERROR(@msg_id, @severity, @state) WITH LOG, NOWAIT, SETERROR; +go + +BEGIN TRANSACTION + INSERT INTO raiserrorTable VALUES (3); + RAISERROR('raiserror 16', 16, 1); + INSERT INTO raiserrorTable VALUES (4); +go +SELECT xact_state(); +SELECT @@trancount; +SELECT * FROM raiserrorTable; +IF @@trancount > 0 ROLLBACK TRANSACTION; +go +TRUNCATE TABLE raiserrorTable +go + +/* Nested procedure call */ +BEGIN TRANSACTION + EXEC raiserrorProc2; +go +SELECT xact_state(); +SELECT @@trancount; +SELECT * FROM raiserrorTable; +IF @@trancount > 0 ROLLBACK TRANSACTION; +go +TRUNCATE TABLE raiserrorTable +go + +/* 2. In TRY...CATCH block, catchable */ +/* RAISERROR in TRY...CATCH */ +BEGIN TRY + BEGIN TRANSACTION + RAISERROR('raiserror 10', 10, 1); + INSERT INTO raiserrorTable VALUES (3); + RAISERROR('raiserror 16', 16, 1); + INSERT INTO raiserrorTable VALUES (4); + COMMIT TRANSACTION +END TRY +BEGIN CATCH + SELECT xact_state(); + SELECT @@trancount; + SELECT * FROM raiserrorTable; + IF @@trancount > 0 ROLLBACK TRANSACTION; +END CATCH +go +TRUNCATE TABLE raiserrorTable +go + +/* Procedure call in TRY...CATCH */ +BEGIN TRY + BEGIN TRANSACTION + SELECT xact_state(); + EXEC raiserrorProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); + SELECT @@trancount; + SELECT * FROM raiserrorTable; + IF @@trancount > 0 ROLLBACK TRANSACTION; +END CATCH +go +TRUNCATE TABLE raiserrorTable +go + +/* Error in both TRY...CATCH */ +BEGIN TRY + BEGIN TRANSACTION + INSERT INTO raiserrorTable VALUES(1); + RAISERROR('raiserror 16', 16, 1); + INSERT INTO raiserrorTable VALUES(3); +END TRY +BEGIN CATCH + INSERT INTO raiserrorTable VALUES (5); + RAISERROR('raiserror 16', 16, 1); + INSERT INTO raiserrorTable VALUES (7); + SELECT * FROM raiserrorTable + IF @@trancount > 0 ROLLBACK TRANSACTION; +END CATCH +go +TRUNCATE TABLE raiserrorTable +go + +/* Error in nested CATCH */ +BEGIN TRY + BEGIN TRANSACTION + INSERT INTO raiserrorTable VALUES(1); + EXEC raiserrorProc3; + INSERT INTO raiserrorTable VALUES(3); +END TRY +BEGIN CATCH + INSERT INTO raiserrorTable VALUES (5); + RAISERROR('raiserror 16', 16, 1); + INSERT INTO raiserrorTable VALUES (7); + SELECT * FROM raiserrorTable + IF @@trancount > 0 ROLLBACK TRANSACTION; +END CATCH +go +TRUNCATE TABLE raiserrorTable +go + +/* Error in CATCH chain */ +BEGIN TRY + BEGIN TRANSACTION + INSERT INTO raiserrorTable VALUES(1); + RAISERROR('raiserror 16', 16, 1); + INSERT INTO raiserrorTable VALUES(3); +END TRY +BEGIN CATCH + INSERT INTO raiserrorTable VALUES (5); + EXEC raiserrorProc3; + INSERT INTO raiserrorTable VALUES (7); + SELECT * FROM raiserrorTable + IF @@trancount > 0 ROLLBACK TRANSACTION; +END CATCH +go +TRUNCATE TABLE raiserrorTable +go + + +/* Nested TRY..CATCH, test 1 */ +BEGIN TRY + BEGIN TRY + INSERT INTO raiserrorTable VALUES (3); + RAISERROR('raiserror 16', 16, 1); + INSERT INTO raiserrorTable VALUES (4); + END TRY + BEGIN CATCH + INSERT INTO raiserrorTable VALUES (5); + END CATCH +END TRY +BEGIN CATCH + INSERT INTO raiserrorTable VALUES (6); +END CATCH +go +SELECT * FROM raiserrorTable +go +TRUNCATE TABLE raiserrorTable +go + +/* Nested TRY...CATCH, test 2 */ +BEGIN TRY + BEGIN TRY + SELECT 100/0; + END TRY + BEGIN CATCH + INSERT INTO raiserrorTable VALUES (3); + RAISERROR('raiserror 16', 16, 1); + INSERT INTO raiserrorTable VALUES (4); + END CATCH +END TRY +BEGIN CATCH + INSERT INTO raiserrorTable VALUES (5); +END CATCH +go +SELECT * FROM raiserrorTable +go +TRUNCATE TABLE raiserrorTable +go + +/* Nested TRY...CATCH, test 3 */ +BEGIN TRY + SELECT 100/0; +END TRY +BEGIN CATCH + BEGIN TRY + INSERT INTO raiserrorTable VALUES (3); + RAISERROR('raiserror 16', 16, 1); + INSERT INTO raiserrorTable VALUES (4); + END TRY + BEGIN CATCH + INSERT INTO raiserrorTable VALUES (5); + END CATCH +END CATCH +go +SELECT * FROM raiserrorTable +go +TRUNCATE TABLE raiserrorTable +go + +/* XACT_ABORT ON, RAISERROR does not honor XACT_ABORT */ +SET XACT_ABORT ON; +go + +/* 1. Not in TRY...CATCH block, terminates nothing */ +/* Not in TRY...CATCH block */ +BEGIN TRANSACTION + INSERT INTO raiserrorTable VALUES (3); + RAISERROR('raiserror 16', 16, 1); + INSERT INTO raiserrorTable VALUES (4); +go +SELECT xact_state(); +SELECT @@trancount; +SELECT * FROM raiserrorTable; +IF @@trancount > 0 ROLLBACK TRANSACTION; +go +TRUNCATE TABLE raiserrorTable +go + +/* Nested procedure call */ +BEGIN TRANSACTION + EXEC raiserrorProc2; +go +SELECT xact_state(); +SELECT @@trancount; +SELECT * FROM raiserrorTable; +IF @@trancount > 0 ROLLBACK TRANSACTION; +go +TRUNCATE TABLE raiserrorTable +go + +/* 2. In TRY...CATCH block, catchable */ +/* RAISERROR in TRY...CATCH */ +BEGIN TRY + BEGIN TRANSACTION + RAISERROR('raiserror 10', 10, 1); + INSERT INTO raiserrorTable VALUES (3); + RAISERROR('raiserror 16', 16, 1); + INSERT INTO raiserrorTable VALUES (4); + COMMIT TRANSACTION +END TRY +BEGIN CATCH + SELECT xact_state(); + SELECT @@trancount; + SELECT * FROM raiserrorTable; + IF @@trancount > 0 ROLLBACK TRANSACTION; +END CATCH +go +TRUNCATE TABLE raiserrorTable +go + +/* Procedure call in TRY...CATCH */ +BEGIN TRY + BEGIN TRANSACTION + SELECT xact_state(); + EXEC raiserrorProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); + SELECT @@trancount; + SELECT * FROM raiserrorTable; + IF @@trancount > 0 ROLLBACK TRANSACTION; +END CATCH +go +TRUNCATE TABLE raiserrorTable +go + +/* Nested TRY..CATCH, test 1 */ +BEGIN TRY + BEGIN TRY + INSERT INTO raiserrorTable VALUES (3); + RAISERROR('raiserror 16', 16, 1); + INSERT INTO raiserrorTable VALUES (4); + END TRY + BEGIN CATCH + INSERT INTO raiserrorTable VALUES (5); + END CATCH +END TRY +BEGIN CATCH + INSERT INTO raiserrorTable VALUES (6); +END CATCH +go +SELECT * FROM raiserrorTable +go +TRUNCATE TABLE raiserrorTable +go + +/* Nested TRY...CATCH, test 2 */ +BEGIN TRY + BEGIN TRY + SELECT 100/0; + END TRY + BEGIN CATCH + INSERT INTO raiserrorTable VALUES (3); + RAISERROR('raiserror 16', 16, 1); + INSERT INTO raiserrorTable VALUES (4); + END CATCH +END TRY +BEGIN CATCH + INSERT INTO raiserrorTable VALUES (5); +END CATCH +go +SELECT * FROM raiserrorTable +TRUNCATE TABLE raiserrorTable +go + +/* Nested TRY...CATCH, test 3 */ +BEGIN TRY + SELECT 100/0; +END TRY +BEGIN CATCH + BEGIN TRY + INSERT INTO raiserrorTable VALUES (3); + RAISERROR('raiserror 16', 16, 1); + INSERT INTO raiserrorTable VALUES (4); + END TRY + BEGIN CATCH + INSERT INTO raiserrorTable VALUES (5); + END CATCH +END CATCH +go +SELECT * FROM raiserrorTable +go +TRUNCATE TABLE raiserrorTable +go + +/* + * SETERROR option + * 1. Outside TRY...CATCH, SETERROR would set @@ERROR to specified msg_id + * or 50000, regardless of the severity level + * 2. Inside TRY...CATCH, @@ERROR is always set to the captured error number + * with or without SETERROR + * TODO: After full support, @@ERROR should return user defined error number + */ +DECLARE @err INT; +RAISERROR(51000, 10, 1); +SET @err = @@ERROR; IF @err = 0 SELECT 0 ELSE SELECT 1; +RAISERROR(51000, 10, 2) WITH SETERROR; +SET @err = @@ERROR; IF @err = 0 SELECT 0 ELSE SELECT 1; +RAISERROR('raiserror 16', 16, 1); +SET @err = @@ERROR; IF @err = 0 SELECT 0 ELSE SELECT 1; +RAISERROR('raiserror 16', 16, 2) WITH SETERROR; +SET @err = @@ERROR; IF @err = 0 SELECT 0 ELSE SELECT 1; +go + +DECLARE @err INT; +BEGIN TRY + BEGIN TRY + RAISERROR(51000, 16, 1); + END TRY + BEGIN CATCH + SET @err = @@ERROR; IF @err = 0 SELECT 0 ELSE SELECT 1; + RAISERROR(51000, 16, 2) WITH SETERROR; + END CATCH +END TRY +BEGIN CATCH + SET @err = @@ERROR; IF @err = 0 SELECT 0 ELSE SELECT 1; +END CATCH +go + +/* Clean up */ +SET XACT_ABORT OFF; +go +DROP PROC raiserrorProc1; +go +DROP PROC raiserrorProc2; +go +DROP PROC raiserrorProc3; +go +DROP TABLE raiserrorTable; +go diff --git a/contrib/test/JDBC/input/errorHandling/TestRaiserrorFormat.sql b/contrib/test/JDBC/input/errorHandling/TestRaiserrorFormat.sql new file mode 100644 index 00000000000..d7df924b3b2 --- /dev/null +++ b/contrib/test/JDBC/input/errorHandling/TestRaiserrorFormat.sql @@ -0,0 +1,53 @@ +RAISERROR('%s', 16, 1, 'Hi'); +go + +RAISERROR('Hello %s', 16, 1, 'World'); +go + +DECLARE @str VARCHAR(20) = 'Multiple variable inputs'; +DECLARE @p1 TINYINT = 1; +DECLARE @p2 SMALLINT = 2; +DECLARE @p3 INT = 3; +DECLARE @p4 CHAR(5) = 'four'; +DECLARE @p5 VARCHAR(5) = 'five'; +DECLARE @p6 NCHAR(5) = 'six'; +DECLARE @p7 NVARCHAR(5) = 'seven'; +RAISERROR('%s: %d%d%d%s%s%s%s', 16, 1, @str, @p1, @p2, @p3, @p4, @p5, @p6, @p7); +go + +RAISERROR('More than 20 args', 16, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21); +go + +RAISERROR('Signed integer i: %i, %i', 16, 1, 5, -5); +go + +RAISERROR('Unsigned integer u: %u, %u', 16, 1, 5, -5); +go + +RAISERROR('Unsigned octal o: %o, %o', 16, 1, 5, -5); +go + +RAISERROR('Unsigned hexadecimal x: %x, %X, %X, %X, %x', 16, 1, 11, 11, -11, 50, -50); +go + +RAISERROR('Not enough args: %d, %d', 16, 1, 1, 2, 3, 4); +go + +RAISERROR('No arg for placeholder: %s', 16, 1); +go + +RAISERROR('Invalid placeholder: %m', 16, 1, 0); +go + +RAISERROR('Null arg for placeholder: %s', 16, 1, NULL); +go + +-- Datatype mismatch +RAISERROR('Mismatch datatype: %d', 16, 1, 'string'); +go + +RAISERROR('Mismatch datatype: %o', 16, 1, N'string'); +go + +RAISERROR('Mismatch datatype: %s', 16, 1, 123); +go diff --git a/contrib/test/JDBC/input/errorHandling/TestSimpleErrors.sql b/contrib/test/JDBC/input/errorHandling/TestSimpleErrors.sql new file mode 100644 index 00000000000..95832cfe32f --- /dev/null +++ b/contrib/test/JDBC/input/errorHandling/TestSimpleErrors.sql @@ -0,0 +1,2532 @@ +CREATE TABLE simpleErrorTable (a varchar(15) UNIQUE NOT NULL, b nvarchar(25), c int PRIMARY KEY, d char(15) DEFAULT 'Whoops!', e nchar(25), f datetime, g numeric(4,1) CHECK (g >= 103.5)) +GO + +-- setup for "data out of range for datetime" error +CREATE TABLE t517_1(a datetime); +GO + +-- setup for "A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations" error +CREATE TABLE t141_1(c1 int, c2 int); +GO + +-- setup for "column \"%s\" of relation \"%s\" is a generated column" +CREATE TABLE t1752_1(c1 INT, c2 INT, c3 as c1*c2) +GO + +if @@trancount > 0 commit tran; +GO + +-- Error: duplicate key value violates unique constraint +-- simple batch +INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); +declare @err int = @@error; if @err = 0 select 0 else select 1; +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +GO +select * from simpleErrorTable ORDER BY c +GO +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- simple batch with commit transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + declare @err int = @@error; if @err = 0 select 0 else select 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +commit tran; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- simple batch with rollback transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + declare @err int = @@error; if @err = 0 select 0 else select 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +rollback tran; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- simple batch with rollback transaction and rollback to savepoint +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + save tran sp1; + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + declare @err int = @@error; if @err = 0 select 0 else select 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran sp1 +rollback tran; +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- simple procedure +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- simple batch with nested transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +commit tran; +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- simple procedure with transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +exec simpleErrorProc1 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- simple procedure with transaction started inside procedure but ended outside procedure +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +commit tran +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- simple procedure with transaction started outside procedure but ended inside procedure through commit +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- simple procedure with transaction started outside procedure but ended inside procedure through rollback +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- nested procedure (level 2) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +exec simpleErrorProc2 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- nested procedure (level 3) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +create procedure simpleErrorProc3 +as +begin + SELECT 1; + exec simpleErrorProc2; + SELECT 2; +end +GO +exec simpleErrorProc3 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +drop procedure simpleErrorProc3 +GO +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- nested procedure with commit transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + commit tran; +end +GO +exec simpleErrorProc2 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- nested procedure with rollback transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + rollback tran; +end +GO +exec simpleErrorProc2 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: data out of range for datetime +-- simple batch +INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +INSERT INTO t517_1 VALUES (DATEADD(YY,-300,getdate())); +declare @err int = @@error; if @err = 0 select 0 else select 1; +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +GO +select * from simpleErrorTable ORDER BY c +GO +truncate table simpleErrorTable +GO + +-- Error: data out of range for datetime +-- simple batch with commit transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO t517_1 VALUES (DATEADD(YY,-300,getdate())); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +commit tran; +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: data out of range for datetime +-- simple batch with rollback transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO t517_1 VALUES (DATEADD(YY,-300,getdate())); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +rollback tran; +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: data out of range for datetime +-- simple batch with rollback transaction and rollback to savepoint +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + save tran sp1; + INSERT INTO t517_1 VALUES (DATEADD(YY,-300,getdate())); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran sp1; +rollback tran; +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: data out of range for datetime +-- simple procedure +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO t517_1 VALUES (DATEADD(YY,-300,getdate())); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: data out of range for datetime +-- simple batch with nested transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + INSERT INTO t517_1 VALUES (DATEADD(YY,-300,getdate())); + declare @err int = @@error; if @err = 0 select 0 else select 1; + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +commit tran; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: data out of range for datetime +-- simple procedure with transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + INSERT INTO t517_1 VALUES (DATEADD(YY,-300,getdate())); + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +exec simpleErrorProc1 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: data out of range for datetime +-- simple procedure with transaction started inside procedure but ended outside procedure +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO t517_1 VALUES (DATEADD(YY,-300,getdate())); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +commit tran +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: data out of range for datetime +-- simple procedure with transaction started outside procedure but ended inside procedure through commit +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO t517_1 VALUES (DATEADD(YY,-300,getdate())); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: data out of range for datetime +-- simple procedure with transaction started outside procedure but ended inside procedure through rollback +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO t517_1 VALUES (DATEADD(YY,-300,getdate())); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: data out of range for datetime +-- nested procedure (level 2) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO t517_1 VALUES (DATEADD(YY,-300,getdate())); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +exec simpleErrorProc2 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: data out of range for datetime +-- nested procedure (level 3) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO t517_1 VALUES (DATEADD(YY,-300,getdate())); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +create procedure simpleErrorProc3 +as +begin + SELECT 1; + exec simpleErrorProc2; + SELECT 2; +end +GO +exec simpleErrorProc3 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +drop procedure simpleErrorProc3 +GO +truncate table simpleErrorTable +GO + +-- Error: data out of range for datetime +-- nested procedure with commit transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO t517_1 VALUES (DATEADD(YY,-300,getdate())); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + commit tran; +end +GO +exec simpleErrorProc2 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: data out of range for datetime +-- nested procedure with rollback transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO t517_1 VALUES (DATEADD(YY,-300,getdate())); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + rollback tran; +end +GO +exec simpleErrorProc2 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- simple batch +INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +UPDATE simpleErrorTable SET c = NULL WHERE c = 1; +declare @err int = @@error; if @err = 0 select 0 else select 1; +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +GO +select * from simpleErrorTable ORDER BY c +GO +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- simple batch with commit transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + declare @err int = @@error; if @err = 0 select 0 else select 1; +commit tran; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- simple batch with rollback transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + declare @err int = @@error; if @err = 0 select 0 else select 1; +rollback tran; +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- simple batch with rollback transaction and rollback to savepoint +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + save tran sp1; + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + declare @err int = @@error; if @err = 0 select 0 else select 1; + rollback tran sp1; +rollback tran; +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- simple procedure +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- simple batch with nested transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + declare @err int = @@error; if @err = 0 select 0 else select 1; +commit tran; +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- simple procedure with transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +exec simpleErrorProc1 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- simple procedure with transaction started inside procedure but ended outside procedure +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +commit tran +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- simple procedure with transaction started outside procedure but ended inside procedure through commit +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- simple procedure with transaction started outside procedure but ended inside procedure through rollback +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- nested procedure (level 2) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +exec simpleErrorProc2 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- nested procedure (level 3) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +create procedure simpleErrorProc3 +as +begin + SELECT 1; + exec simpleErrorProc2; + SELECT 2; +end +GO +exec simpleErrorProc3 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +drop procedure simpleErrorProc3 +GO +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- nested procedure with commit transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + commit tran; +end +GO +exec simpleErrorProc2 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- nested procedure with rollback transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + rollback tran; +end +GO +exec simpleErrorProc2 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + + +-- Error: creating an existing table +-- simple batch +INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +CREATE TABLE simpleErrorTable (a int); +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- simple batch with commit transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +GO +commit tran; +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- simple batch with rollback transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +GO +rollback tran; +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- simple batch with rollback transaction and rollback to savepoint +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + save tran sp1; + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +GO +rollback tran sp1; +GO +rollback tran; +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- simple procedure +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- simple batch with nested transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + CREATE TABLE simpleErrorTable (a int); +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +commit tran; +GO +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +GO +commit tran; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- simple procedure with transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + CREATE TABLE simpleErrorTable (a int); + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +exec simpleErrorProc1 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- simple procedure with transaction started inside procedure but ended outside procedure +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +commit tran +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- simple procedure with transaction started outside procedure but ended inside procedure through commit +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- simple procedure with transaction started outside procedure but ended inside procedure through rollback +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- nested procedure (level 2) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +exec simpleErrorProc2 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- nested procedure (level 3) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +create procedure simpleErrorProc3 +as +begin + SELECT 1; + exec simpleErrorProc2; + SELECT 2; +end +GO +exec simpleErrorProc3 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +drop procedure simpleErrorProc3 +GO +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- nested procedure with commit transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + commit tran; +end +GO +exec simpleErrorProc2 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- nested procedure with rollback transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + rollback tran; +end +GO +exec simpleErrorProc2 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- simple batch +INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +ALTER TABLE t1752_1 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; +declare @err int = @@error; if @err = 0 select 0 else select 1; +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +GO +GO +select * from simpleErrorTable ORDER BY c +GO +truncate table simpleErrorTable +GO + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- simple batch with commit transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + ALTER TABLE t1752_1 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +commit tran; +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +commit tran +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- simple batch with rollback transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + ALTER TABLE t1752_1 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +rollback tran; +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +commit tran +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- simple batch with rollback transaction and rollback to savepoint +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + save tran sp1; + ALTER TABLE t1752_1 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran sp1; +rollback tran; +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +commit tran +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- simple procedure +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + ALTER TABLE t1752_1 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- simple batch with nested transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + ALTER TABLE t1752_1 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +commit tran; +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +commit tran +GO +select @@trancount +GO +commit tran +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- simple procedure with transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + ALTER TABLE t1752_1 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +exec simpleErrorProc1 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +commit tran +GO +select @@trancount +GO +commit tran +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- simple procedure with transaction started inside procedure but ended outside procedure +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + ALTER TABLE t1752_1 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +commit tran +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- simple procedure with transaction started outside procedure but ended inside procedure through commit +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + ALTER TABLE t1752_1 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +commit tran +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- simple procedure with transaction started outside procedure but ended inside procedure through rollback +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + ALTER TABLE t1752_1 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +commit tran +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- nested procedure (level 2) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + ALTER TABLE t1752_1 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +exec simpleErrorProc2 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- nested procedure (level 3) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + ALTER TABLE t1752_1 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +create procedure simpleErrorProc3 +as +begin + SELECT 1; + exec simpleErrorProc2; + SELECT 2; +end +GO +exec simpleErrorProc3 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +drop procedure simpleErrorProc3 +GO +truncate table simpleErrorTable +GO + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- nested procedure with commit transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + ALTER TABLE t1752_1 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + commit tran; +end +GO +exec simpleErrorProc2 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +commit tran +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- nested procedure with rollback transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + ALTER TABLE t1752_1 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + rollback tran; +end +GO +exec simpleErrorProc2 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +commit tran +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: "A SELECT statement that assigns a value to a variable must not be +-- combined with data-retrieval operations" +-- simple batch +INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +DECLARE @a int; SELECT @a = c1, c2 FROM t141_1; +declare @err int = @@error; if @err = 0 select 0 else select 1; +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +GO +select * from simpleErrorTable ORDER BY c +GO +truncate table simpleErrorTable +GO + +-- Error: "A SELECT statement that assigns a value to a variable must not be +-- combined with data-retrieval operations" +-- simple batch with commit transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + DECLARE @a int; SELECT @a = c1, c2 FROM t141_1; +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +commit tran; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: "A SELECT statement that assigns a value to a variable must not be +-- combined with data-retrieval operations" +-- simple batch with rollback transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + DECLARE @a int; SELECT @a = c1, c2 FROM t141_1; +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +rollback tran; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: "A SELECT statement that assigns a value to a variable must not be +-- combined with data-retrieval operations" +-- simple batch with rollback transaction and rollback to savepoint +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + save tran sp1; + DECLARE @a int; SELECT @a = c1, c2 FROM t141_1; +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +rollback tran sp1; +GO +rollback tran; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + + +-- Error: "A SELECT statement that assigns a value to a variable must not be +-- combined with data-retrieval operations" +-- simple procedure with transaction started outside procedure but ended inside procedure through commit +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + DECLARE @a int; SELECT @a = c1, c2 FROM t141_1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +begin tran +GO +DECLARE @a tinyint = 1000; +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +commit tran +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: "A SELECT statement that assigns a value to a variable must not be +-- combined with data-retrieval operations" +-- simple procedure with transaction started outside procedure but ended inside procedure through rollback +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + DECLARE @a int; SELECT @a = c1, c2 FROM t141_1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +begin tran +GO +DECLARE @a tinyint = 1000; +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +commit tran +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: "A SELECT statement that assigns a value to a variable must not be +-- combined with data-retrieval operations" +-- nested procedure (level 2) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + DECLARE @a int; SELECT @a = c1, c2 FROM t141_1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + DECLARE @a tinyint = 1000; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +exec simpleErrorProc2 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: "A SELECT statement that assigns a value to a variable must not be +-- combined with data-retrieval operations" +-- nested procedure (level 3) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + DECLARE @a int; SELECT @a = c1, c2 FROM t141_1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + DECLARE @a tinyint = 1000; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +create procedure simpleErrorProc3 +as +begin + SELECT 1; + exec simpleErrorProc2; + SELECT 2; +end +GO +exec simpleErrorProc3 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +drop procedure simpleErrorProc2 +GO +drop procedure simpleErrorProc3 +GO +truncate table simpleErrorTable +GO + +-- Error: "A SELECT statement that assigns a value to a variable must not be +-- combined with data-retrieval operations" +-- nested procedure with commit transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + DECLARE @a int; SELECT @a = c1, c2 FROM t141_1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + DECLARE @a tinyint = 1000; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + commit tran; +end +GO +exec simpleErrorProc2 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: "A SELECT statement that assigns a value to a variable must not be +-- combined with data-retrieval operations" +-- nested procedure with rollback transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + DECLARE @a int; SELECT @a = c1, c2 FROM t141_1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + DECLARE @a tinyint = 1000; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + rollback tran; +end +GO +exec simpleErrorProc2 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +select @@trancount; +GO + +if @@trancount > 0 commit tran; +GO + +-- Error: value for domain tinyint violates check constraint "tinyint_check" +INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +DECLARE @a tinyint = 1000; +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- simple batch +INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- simple batch with commit transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; +GO +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +commit tran; +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- simple batch with rollback transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; +GO +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +rollback tran; +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- simple batch with rollback transaction and rollback to savepoint +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + save tran sp1; + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; +GO +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +rollback tran sp1; +GO +rollback tran; +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- simple procedure +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- simple batch with nested transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; +GO +commit tran; +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +GO +commit tran; +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- simple procedure with transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +exec simpleErrorProc1 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- simple procedure with transaction started inside procedure but ended outside procedure +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +commit tran +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- simple procedure with transaction started outside procedure but ended inside procedure through commit +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- simple procedure with transaction started outside procedure but ended inside procedure through rollback +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- nested procedure (level 2) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +exec simpleErrorProc2 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- nested procedure (level 3) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +create procedure simpleErrorProc3 +as +begin + SELECT 1; + exec simpleErrorProc2; + SELECT 2; +end +GO +exec simpleErrorProc2 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +drop procedure simpleErrorProc3 +GO +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- nested procedure with commit transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + commit tran; +end +GO +exec simpleErrorProc2 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- nested procedure with rollback transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + rollback tran; +end +GO +exec simpleErrorProc2 +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- cleanup for "data out of range for datetime" error +DROP TABLE t517_1; +GO + +-- clean up for "A SELECT statement that assigns a value to a variable must not +-- be combined with data-retrieval operations" error +DROP TABLE t141_1; +GO + +-- setup for "column \"%s\" of relation \"%s\" is a generated column" +DROP TABLE t1752_1; +GO + +drop table simpleErrorTable +GO + +while (@@trancount > 0) commit tran; +GO + diff --git a/contrib/test/JDBC/input/errorHandling/TestSimpleErrorsWithImplicitTran.txt b/contrib/test/JDBC/input/errorHandling/TestSimpleErrorsWithImplicitTran.txt new file mode 100644 index 00000000000..81899318253 --- /dev/null +++ b/contrib/test/JDBC/input/errorHandling/TestSimpleErrorsWithImplicitTran.txt @@ -0,0 +1,9 @@ +#Setup +SET IMPLICIT_TRANSACTIONS ON + +#Run error handling tests +include#!#input/errorHandling/TestSimpleErrors.sql + +#Cleanup +IF @@trancount > 0 ROLLBACK +SET IMPLICIT_TRANSACTIONS OFF diff --git a/contrib/test/JDBC/input/errorHandling/TestSimpleErrorsWithXactAbort.sql b/contrib/test/JDBC/input/errorHandling/TestSimpleErrorsWithXactAbort.sql new file mode 100644 index 00000000000..0137b7cc36a --- /dev/null +++ b/contrib/test/JDBC/input/errorHandling/TestSimpleErrorsWithXactAbort.sql @@ -0,0 +1,2379 @@ +SET XACT_ABORT ON +GO + +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_unique_constraint', 'ignore'; +GO + +CREATE TABLE simpleErrorTable (a varchar(15) UNIQUE, b nvarchar(25), c int PRIMARY KEY, d char(15) DEFAULT 'Whoops!', e nchar(25), f datetime, g numeric(4,1) CHECK (g >= 103.5)) +GO + +-- Error: duplicate key value violates unique constraint +-- simple batch +INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +GO +select * from simpleErrorTable ORDER BY c +GO +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- simple batch with commit transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +commit tran; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- simple batch with rollback transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +rollback tran; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- simple batch with rollback transaction and rollback to savepoint +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + save tran sp1; + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran sp1 +rollback tran; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- simple procedure +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +select * from simpleErrorTable ORDER BY c +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- simple batch with nested transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +commit tran; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- simple procedure with transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +exec simpleErrorProc1 +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- simple procedure with transaction started inside procedure but ended outside procedure +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +commit tran +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- simple procedure with transaction started outside procedure but ended inside procedure through commit +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- simple procedure with transaction started outside procedure but ended inside procedure through rollback +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- nested procedure (level 2) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +exec simpleErrorProc2 +GO +select * from simpleErrorTable ORDER BY c +GO +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- nested procedure (level 3) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +create procedure simpleErrorProc3 +as +begin + SELECT 1; + exec simpleErrorProc2; + SELECT 2; +end +GO +exec simpleErrorProc3 +GO +select * from simpleErrorTable ORDER BY c +GO +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +drop procedure simpleErrorProc3 +GO +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- nested procedure with commit transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + commit tran; +end +GO +exec simpleErrorProc2 +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- nested procedure with rollback transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + rollback tran; +end +GO +exec simpleErrorProc2 +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + + +-- Error: check constraint violation +-- simple batch +INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +UPDATE simpleErrorTable SET g = 101.4 WHERE c = 1; +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +GO +select * from simpleErrorTable ORDER BY c +GO +truncate table simpleErrorTable +GO + +-- Error: check constraint violation +-- simple batch with commit transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET g = 101.4 WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +commit tran; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: check constraint violation +-- simple batch with rollback transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET g = 101.4 WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +rollback tran; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: check constraint violation +-- simple batch with rollback transaction and rollback to savepoint +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + save tran sp1; + UPDATE simpleErrorTable SET g = 101.4 WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran sp1; +rollback tran; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: check constraint violation +-- simple procedure +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET g = 101.4 WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +select * from simpleErrorTable ORDER BY c +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: check constraint violation +-- simple batch with nested transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + UPDATE simpleErrorTable SET g = 101.4 WHERE c = 1; + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +commit tran; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: check constraint violation +-- simple procedure with transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + UPDATE simpleErrorTable SET g = 101.4 WHERE c = 1; + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +exec simpleErrorProc1 +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: check constraint violation +-- simple procedure with transaction started inside procedure but ended outside procedure +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET g = 101.4 WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +commit tran +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: check constraint violation +-- simple procedure with transaction started outside procedure but ended inside procedure through commit +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET g = 101.4 WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: check constraint violation +-- simple procedure with transaction started outside procedure but ended inside procedure through rollback +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET g = 101.4 WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: check constraint violation +-- nested procedure (level 2) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET g = 101.4 WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +exec simpleErrorProc2 +GO +select * from simpleErrorTable ORDER BY c +GO +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: check constraint violation +-- nested procedure (level 3) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET g = 101.4 WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +create procedure simpleErrorProc3 +as +begin + SELECT 1; + exec simpleErrorProc2; + SELECT 2; +end +GO +exec simpleErrorProc3 +GO +select * from simpleErrorTable ORDER BY c +GO +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +drop procedure simpleErrorProc3 +GO +truncate table simpleErrorTable +GO + +-- Error: check constraint violation +-- nested procedure with commit transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET g = 101.4 WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + commit tran; +end +GO +exec simpleErrorProc2 +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: check constraint violation +-- nested procedure with rollback transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET g = 101.4 WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + rollback tran; +end +GO +exec simpleErrorProc2 +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + + +-- Error: not null constraint violation +-- simple batch +INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +UPDATE simpleErrorTable SET c = NULL WHERE c = 1; +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +GO +select * from simpleErrorTable ORDER BY c +GO +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- simple batch with commit transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +commit tran; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- simple batch with rollback transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +rollback tran; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- simple batch with rollback transaction and rollback to savepoint +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + save tran sp1; + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran sp1; +rollback tran; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- simple procedure +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +select * from simpleErrorTable ORDER BY c +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- simple batch with nested transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +commit tran; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- simple procedure with transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +exec simpleErrorProc1 +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- simple procedure with transaction started inside procedure but ended outside procedure +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +commit tran +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- simple procedure with transaction started outside procedure but ended inside procedure through commit +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- simple procedure with transaction started outside procedure but ended inside procedure through rollback +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- nested procedure (level 2) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +exec simpleErrorProc2 +GO +select * from simpleErrorTable ORDER BY c +GO +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- nested procedure (level 3) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +create procedure simpleErrorProc3 +as +begin + SELECT 1; + exec simpleErrorProc2; + SELECT 2; +end +GO +exec simpleErrorProc3 +GO +select * from simpleErrorTable ORDER BY c +GO +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +drop procedure simpleErrorProc3 +GO +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- nested procedure with commit transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + commit tran; +end +GO +exec simpleErrorProc2 +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- nested procedure with rollback transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + rollback tran; +end +GO +exec simpleErrorProc2 +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + + +-- Error: creating an existing table +-- simple batch +INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +CREATE TABLE simpleErrorTable (a int); +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +GO +select * from simpleErrorTable ORDER BY c +GO +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- simple batch with commit transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +commit tran; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- simple batch with rollback transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +rollback tran; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- simple batch with rollback transaction and rollback to savepoint +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + save tran sp1; + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran sp1; +rollback tran; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- simple procedure +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +select * from simpleErrorTable ORDER BY c +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- simple batch with nested transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + CREATE TABLE simpleErrorTable (a int); + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +commit tran; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- simple procedure with transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + CREATE TABLE simpleErrorTable (a int); + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +exec simpleErrorProc1 +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- simple procedure with transaction started inside procedure but ended outside procedure +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +commit tran +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- simple procedure with transaction started outside procedure but ended inside procedure through commit +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- simple procedure with transaction started outside procedure but ended inside procedure through rollback +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- nested procedure (level 2) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +exec simpleErrorProc2 +GO +select * from simpleErrorTable ORDER BY c +GO +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- nested procedure (level 3) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +create procedure simpleErrorProc3 +as +begin + SELECT 1; + exec simpleErrorProc2; + SELECT 2; +end +GO +exec simpleErrorProc3 +GO +select * from simpleErrorTable ORDER BY c +GO +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +drop procedure simpleErrorProc3 +GO +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- nested procedure with commit transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + commit tran; +end +GO +exec simpleErrorProc2 +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- nested procedure with rollback transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + rollback tran; +end +GO +exec simpleErrorProc2 +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + + +-- Error: deleting values from a table that does not exist +-- simple batch +INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +DELETE FROM simpleErrorTable1 WHERE c = 1; +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +GO +select * from simpleErrorTable ORDER BY c +GO +truncate table simpleErrorTable +GO + +-- Error: deleting values from a table that does not exist +-- simple batch with commit transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + DELETE FROM simpleErrorTable1 WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +commit tran; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +commit tran +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: deleting values from a table that does not exist +-- simple batch with rollback transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + DELETE FROM simpleErrorTable1 WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +rollback tran; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +commit tran +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: deleting values from a table that does not exist +-- simple batch with rollback transaction and rollback to savepoint +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + save tran sp1; + DELETE FROM simpleErrorTable1 WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran sp1; +rollback tran; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +commit tran +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: deleting values from a table that does not exist +-- simple procedure +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + DELETE FROM simpleErrorTable1 WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +select * from simpleErrorTable ORDER BY c +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: deleting values from a table that does not exist +-- simple batch with nested transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + DELETE FROM simpleErrorTable1 WHERE c = 1; + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +commit tran; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +commit tran +GO +select @@trancount +GO +commit tran +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: deleting values from a table that does not exist +-- simple procedure with transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + DELETE FROM simpleErrorTable1 WHERE c = 1; + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +exec simpleErrorProc1 +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +commit tran +GO +select @@trancount +GO +commit tran +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: deleting values from a table that does not exist +-- simple procedure with transaction started inside procedure but ended outside procedure +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + DELETE FROM simpleErrorTable1 WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +commit tran +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: deleting values from a table that does not exist +-- simple procedure with transaction started outside procedure but ended inside procedure through commit +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + DELETE FROM simpleErrorTable1 WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +commit tran +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: deleting values from a table that does not exist +-- simple procedure with transaction started outside procedure but ended inside procedure through rollback +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + DELETE FROM simpleErrorTable1 WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +commit tran +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: deleting values from a table that does not exist +-- nested procedure (level 2) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + DELETE FROM simpleErrorTable1 WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +exec simpleErrorProc2 +GO +select * from simpleErrorTable ORDER BY c +GO +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: deleting values from a table that does not exist +-- nested procedure (level 3) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + DELETE FROM simpleErrorTable1 WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +create procedure simpleErrorProc3 +as +begin + SELECT 1; + exec simpleErrorProc2; + SELECT 2; +end +GO +exec simpleErrorProc3 +GO +select * from simpleErrorTable ORDER BY c +GO +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +drop procedure simpleErrorProc3 +GO +truncate table simpleErrorTable +GO + +-- Error: deleting values from a table that does not exist +-- nested procedure with commit transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + DELETE FROM simpleErrorTable1 WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + commit tran; +end +GO +exec simpleErrorProc2 +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +commit tran +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: deleting values from a table that does not exist +-- nested procedure with rollback transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + DELETE FROM simpleErrorTable1 WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + rollback tran; +end +GO +exec simpleErrorProc2 +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +commit tran +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + + +-- Error: syntax error +-- simple batch +INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +UPDATE1 simpleErrorTable SET c = NULL WHERE c = 1; +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +GO +select * from simpleErrorTable ORDER BY c +GO +truncate table simpleErrorTable +GO + +-- Error: syntax error +-- simple batch with commit transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE1 simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +commit tran; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: syntax error +-- simple batch with rollback transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE1 simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +rollback tran; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: syntax error +-- simple batch with rollback transaction and rollback to savepoint +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + save tran sp1; + UPDATE1 simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran sp1; +rollback tran; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: syntax error +-- simple procedure +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE1 simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +select * from simpleErrorTable ORDER BY c +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: syntax error +-- simple batch with nested transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + UPDATE1 simpleErrorTable SET c = NULL WHERE c = 1; + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +commit tran; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: syntax error +-- simple procedure with transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + UPDATE1 simpleErrorTable SET c = NULL WHERE c = 1; + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +exec simpleErrorProc1 +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: syntax error +-- simple procedure with transaction started inside procedure but ended outside procedure +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE1 simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +commit tran +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: syntax error +-- simple procedure with transaction started outside procedure but ended inside procedure through commit +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE1 simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +commit tran +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: syntax error +-- simple procedure with transaction started outside procedure but ended inside procedure through rollback +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE1 simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +commit tran +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: syntax error +-- nested procedure (level 2) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE1 simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +exec simpleErrorProc2 +GO +select * from simpleErrorTable ORDER BY c +GO +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: syntax error +-- nested procedure (level 3) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE1 simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +create procedure simpleErrorProc3 +as +begin + SELECT 1; + exec simpleErrorProc2; + SELECT 2; +end +GO +exec simpleErrorProc3 +GO +select * from simpleErrorTable ORDER BY c +GO +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +drop procedure simpleErrorProc3 +GO +truncate table simpleErrorTable +GO + +-- Error: syntax error +-- nested procedure with commit transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE1 simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + commit tran; +end +GO +exec simpleErrorProc2 +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: syntax error +-- nested procedure with rollback transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE1 simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + rollback tran; +end +GO +exec simpleErrorProc2 +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + + +-- Error: conversion error and executing stored procedure using sp_executesql +-- simple batch +INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +GO +select * from simpleErrorTable ORDER BY c +GO +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- simple batch with commit transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +commit tran; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- simple batch with rollback transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +rollback tran; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- simple batch with rollback transaction and rollback to savepoint +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + save tran sp1; + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran sp1; +rollback tran; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- simple procedure +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +select * from simpleErrorTable ORDER BY c +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- simple batch with nested transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +commit tran; +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- simple procedure with transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +exec simpleErrorProc1 +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- simple procedure with transaction started inside procedure but ended outside procedure +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +commit tran +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- simple procedure with transaction started outside procedure but ended inside procedure through commit +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- simple procedure with transaction started outside procedure but ended inside procedure through rollback +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- nested procedure (level 2) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +exec simpleErrorProc2 +GO +select * from simpleErrorTable ORDER BY c +GO +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- nested procedure (level 3) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +create procedure simpleErrorProc3 +as +begin + SELECT 1; + exec simpleErrorProc2; + SELECT 2; +end +GO +exec simpleErrorProc2 +GO +select * from simpleErrorTable ORDER BY c +GO +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +drop procedure simpleErrorProc3 +GO +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- nested procedure with commit transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + commit tran; +end +GO +exec simpleErrorProc2 +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- nested procedure with rollback transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + rollback tran; +end +GO +exec simpleErrorProc2 +GO +select * from simpleErrorTable ORDER BY c +GO +select @@trancount +GO +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- cleanup +SET XACT_ABORT OFF; +GO + +drop table simpleErrorTable +GO + +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_unique_constraint', 'strict'; +GO diff --git a/contrib/test/JDBC/input/errorHandling/TestThrow.sql b/contrib/test/JDBC/input/errorHandling/TestThrow.sql new file mode 100644 index 00000000000..51a97ec1c23 --- /dev/null +++ b/contrib/test/JDBC/input/errorHandling/TestThrow.sql @@ -0,0 +1,382 @@ +CREATE TABLE throwTable (a INT); +go + +CREATE PROC throwProc1 AS +BEGIN + INSERT INTO throwTable VALUES (1); + THROW 51000, 'Throw error', 1; + INSERT INTO throwTable VALUES (2); +END +go + +CREATE PROC throwProc2 AS +BEGIN + INSERT INTO throwTable VALUES (111); + EXEC throwProc1; + INSERT INTO throwTable VALUES (222); +END +go + +CREATE PROC reThrowProc1 AS +BEGIN + BEGIN TRY + INSERT INTO throwTable VALUES (1); + THROW 51000, 'Throw error', 1; + INSERT INTO throwTable VALUES (2); + END TRY + BEGIN CATCH + THROW; + SELECT 'THROW SHOULD NOT CONTINUE' + END CATCH +END +go + +CREATE PROC reThrowProc2 AS +BEGIN + INSERT INTO throwTable VALUES (111); + EXEC reThrowProc1; + INSERT INTO throwTable VALUES (222); +END +go + +/* Error -- THORW; can only be called in CATCH block */ +THROW; +go + +/* Error -- THROW; can only be called in CATCH block */ +BEGIN TRY + THROW; +END TRY +BEGIN CATCH + THROW; +END CATCH +go + +/* Re-throw current caught error */ +BEGIN TRY + THROW 50000, 'Throw error', 1; +END TRY +BEGIN CATCH + THROW; + SELECT 'THROW SHOULD NOT CONTINUE' +END CATCH +go + +/* Nested TRY...CATCH, test 1 */ +BEGIN TRY + BEGIN TRY + PRINT 100/0; + END TRY + BEGIN CATCH + THROW 50000, 'Throw error', 1; + END CATCH +END TRY +BEGIN CATCH + THROW; + SELECT 'THROW SHOULD NOT CONTINUE' +END CATCH +go + +/* Nested TRY...CATCH, test 2 */ +BEGIN TRY + PRINT 100/0; +END TRY +BEGIN CATCH + BEGIN TRY + THROW; + END TRY + BEGIN CATCH + THROW; + SELECT 'THROW SHOULD NOT CONTINUE' + END CATCH +END CATCH +go + + +/* XACT_ABORT OFF */ + +/* 1. Not in TRY...CATCH block, throw exception */ +/* Not in TRY...CATCH block */ +DECLARE @err_no INT; +DECLARE @msg VARCHAR(50); +DECLARE @state INT; +SET @err_no = 51000; +SET @msg = N'Throw error'; +SET @state = 1; +THROW @err_no, @msg, @state; +go + +BEGIN TRAN + INSERT INTO throwTable VALUES (3); + THROW 50000, 'Throw error', 1; + INSERT INTO throwTable VALUES (4); +go +SELECT xact_state(); +SELECT @@trancount; +SELECT * FROM throwTable; +IF @@trancount > 0 ROLLBACK TRAN; +go +TRUNCATE TABLE throwTable +go + +/* Nested procedure call */ +BEGIN TRAN + EXEC throwProc2; +go +SELECT xact_state(); +SELECT @@trancount; +SELECT * FROM throwTable; +IF @@trancount > 0 ROLLBACK TRANSACTION; +go +TRUNCATE TABLE throwTable +go + +BEGIN TRAN + EXEC reThrowProc2; +go +SELECT xact_state(); +SELECT @@trancount; +SELECT * FROM throwTable; +IF @@trancount > 0 ROLLBACK TRANSACTION; +go +TRUNCATE TABLE throwTable +go + +/* 2. In TRY...CATCH block, catchable, abort batch without rollback */ +/* THROW in TRY...CATCH */ +BEGIN TRY + BEGIN TRAN + INSERT INTO throwTable VALUES (3); + THROW 50000, 'Throw error', 1; + INSERT INTO throwTable VALUES (4); + COMMIT TRAN +END TRY +BEGIN CATCH + SELECT xact_state(); + SELECT @@trancount; + SELECT * FROM throwTable; + IF @@trancount > 0 ROLLBACK TRAN; +END CATCH +go +TRUNCATE TABLE throwTable +go + +/* Procedure call in TRY...CATCH */ +BEGIN TRY + BEGIN TRAN + SELECT xact_state(); + EXEC throwProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); + SELECT @@trancount; + SELECT * FROM throwTable; + IF @@trancount > 0 ROLLBACK TRAN; +END CATCH +go +TRUNCATE TABLE throwTable +go + +/* Nested TRY...CATCH, test 1 */ +BEGIN TRY + BEGIN TRY + INSERT INTO throwTable VALUES (3); + THROW 50000, 'Throw error', 1; + INSERT INTO throwTable VALUES (4); + END TRY + BEGIN CATCH + INSERT INTO throwTable VALUES (5); + END CATCH +END TRY +BEGIN CATCH + INSERT INTO throwTable VALUES (6); +END CATCH +go +SELECT * FROM throwTable +go +TRUNCATE TABLE throwTable +go + +/* Nested TRY...CATCH, test 2 */ +BEGIN TRY + BEGIN TRY + SELECT 100/0; + END TRY + BEGIN CATCH + INSERT INTO throwTable VALUES (3); + THROW 50000, 'Throw error', 1; + INSERT INTO throwTable VALUES (4); + END CATCH +END TRY +BEGIN CATCH + INSERT INTO throwTable VALUES (6); +END CATCH +go +SELECT * FROM throwTable +go +TRUNCATE TABLE throwTable +go + +/* Nested TRY...CATCH, test 3 */ +BEGIN TRY + SELECT 100/0; +END TRY +BEGIN CATCH + BEGIN TRY + INSERT INTO throwTable VALUES (3); + THROW 50000, 'Throw error', 1; + INSERT INTO throwTable VALUES (4); + END TRY + BEGIN CATCH + INSERT INTO throwTable VALUES (5); + END CATCH +END CATCH +go +SELECT * FROM throwTable +go +TRUNCATE TABLE throwTable +go + +/* XACT_ABORT ON */ +SET XACT_ABORT ON; +go + +/* 1. Not in TRY...CATCH block, rollback transaction */ +/* Not in TRY...CATCH block */ +BEGIN TRAN + INSERT INTO throwTable VALUES (3); + THROW 50000, 'Throw error', 1; + INSERT INTO throwTable VALUES (4); +go +SELECT xact_state(); +SELECT @@trancount; +SELECT * FROM throwTable; +IF @@trancount > 0 ROLLBACK TRAN; +go +TRUNCATE TABLE throwTable +go + +/* Nested procedure call */ +BEGIN TRAN + EXEC throwProc2; +go +SELECT xact_state(); +SELECT @@trancount; +SELECT * FROM throwTable; +IF @@trancount > 0 ROLLBACK TRANSACTION; +go +TRUNCATE TABLE throwTable +go + +/* 2. In TRY...CATCH block, catchable, abort batch without rollback */ +/* THROW in TRY...CATCH */ +BEGIN TRY + BEGIN TRAN + INSERT INTO throwTable VALUES (3); + THROW 50000, 'Throw error', 1; + INSERT INTO throwTable VALUES (4); + COMMIT TRAN +END TRY +BEGIN CATCH + SELECT xact_state(); + SELECT @@trancount; + SELECT * FROM throwTable; + IF @@trancount > 0 ROLLBACK TRAN; +END CATCH +go +TRUNCATE TABLE throwTable +go + +/* Procedure call in TRY...CATCH */ +BEGIN TRY + BEGIN TRAN + SELECT xact_state(); + EXEC throwProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); + SELECT @@trancount; + SELECT * FROM throwTable; + IF @@trancount > 0 ROLLBACK TRAN; +END CATCH +go +TRUNCATE TABLE throwTable +go + +/* Nested TRY...CATCH, test 1 */ +BEGIN TRY + BEGIN TRY + INSERT INTO throwTable VALUES (3); + THROW 50000, 'Throw error', 1; + INSERT INTO throwTable VALUES (4); + END TRY + BEGIN CATCH + INSERT INTO throwTable VALUES (5); + END CATCH +END TRY +BEGIN CATCH + INSERT INTO throwTable VALUES (6); +END CATCH +go +SELECT * FROM throwTable +go +TRUNCATE TABLE throwTable +go + +/* Nested TRY...CATCH, test 2 */ +BEGIN TRY + BEGIN TRY + SELECT 100/0; + END TRY + BEGIN CATCH + INSERT INTO throwTable VALUES (3); + THROW 50000, 'Throw error', 1; + INSERT INTO throwTable VALUES (4); + END CATCH +END TRY +BEGIN CATCH + INSERT INTO throwTable VALUES (6); +END CATCH +go +SELECT * FROM throwTable +go +TRUNCATE TABLE throwTable +go + +/* Nested TRY...CATCH, test 3 */ +BEGIN TRY + SELECT 100/0; +END TRY +BEGIN CATCH + BEGIN TRY + INSERT INTO throwTable VALUES (3); + THROW 50000, 'Throw error', 1; + INSERT INTO throwTable VALUES (4); + END TRY + BEGIN CATCH + INSERT INTO throwTable VALUES (5); + END CATCH +END CATCH +go +SELECT * FROM throwTable +go +TRUNCATE TABLE throwTable +go + +-- BABEL-2479 +THROW 50000, 'Throw error', 1; +go + +/* Clean up */ +SET XACT_ABORT OFF; +go +DROP PROC throwProc1; +go +DROP PROC throwProc2; +go +DROP PROC reThrowProc1; +go +DROP PROC reThrowProc2; +go +DROP TABLE throwTable; +go diff --git a/contrib/test/JDBC/input/forxml/TestForXML.sql b/contrib/test/JDBC/input/forxml/TestForXML.sql new file mode 100644 index 00000000000..f4ca2da9dfa --- /dev/null +++ b/contrib/test/JDBC/input/forxml/TestForXML.sql @@ -0,0 +1,250 @@ +create table t1 (id int, a varchar(10)); +create table t2 (id int, a varchar(10)); +insert into t1 values (1, 't1_a1'); +insert into t1 values (2, 't1_a2'); +insert into t1 values (3, NULL); +insert into t2 values (1, 't2_a1'); +insert into t2 values (2, 't2_a2'); +insert into t2 values (3, NULL); +go + +-- Test Select For XML syntax +select * from t1 for xml auto; +go + +select * from t1 for xml raw; +go + +select * from t1 for xml raw('myrow'); +go + +select * from t1 for xml path; +go + +select * from t1 for xml path('myrow'); +go + +select * from t1 for xml explicit; +go + +select * from t1, t2 where t1.id = t2.id for xml path('myrow'); +go + +select * from t1, t2 where t1.id = t2.id for xml path('myrow'), type; +go + +select * from t1, t2 where t1.id = t2.id for xml path('myrow'), type, root('myroot'); +go + +select * from t1, t2 where t1.id = t2.id for xml path('myrow'), type, root('myroot'), BINARY BASE64; +go + +-- Test result format when all values are NULL +select a from t1 where a is NULL for xml raw; +go + +select a from t1 where a is NULL for xml path; +go + +-- Test result format when one value is NULL +select id, a from t1 where a is NULL for xml raw; +go + +select id, a from t1 where a is NULL for xml path; +go + +-- Test for xml with order by clause +select * from t1 order by id for xml raw ('t1'); +go + +-- Test for xml with group by +select count(*) as cnt, a from t1 group by a,id order by id; +go +select count(*) as cnt, a from t1 group by a,id order by id for xml path; +go + +-- Test BASE64 encoding on binary data +CREATE TABLE MyTable (Col1 int PRIMARY KEY, Col2 binary); +INSERT INTO MyTable VALUES (1, 0x7); +GO +SELECT Col1, CAST(Col2 as image) as Col2 FROM MyTable FOR XML PATH; +GO +SELECT Col1, CAST(Col2 as image) as Col2 FROM MyTable FOR XML PATH, BINARY BASE64; +GO + +-- Test for xml in subquery, The subquery is supposed to return only one XML value +select id, (select a from t2 for xml path) as col from t1; +go + +-- Test 2 levels of for xml nesting, with TYPE option +select id, (select a from t2 for xml path, type) as col from t1 for xml path, type; +go + +-- Test 2 levels of for xml nesting, without TYPE option, expect special character escaping +select id, (select a from t2 for xml path) as col from t1 for xml path; +go + +-- Test 3 levels of for xml nesting with TYPE option +select id, (select id, (select a from t2 for xml path, type) as col1 from t1 for xml path, type) as col2 from t1 for xml path, type; +go + +-- Test simple for xml path in procedure +create table employees( +pers_id int, +fname nvarchar(20), +lname nvarchar(20), +sal money); +insert into employees values (1, 'John', 'Johnson', 123.1234); +insert into employees values (2, 'Max', 'Welch', 200.1234); +go + +create procedure p_employee_select as +begin + select * from employees for xml path; +end; +go + +execute p_employee_select; +go +drop procedure p_employee_select; +go + +-- Test for xml in procedure with parameters +create procedure p_employee_select @minsal MONEY, @maxsal MONEY as +begin + select * from employees where sal > @minsal and sal < @maxsal + for xml path('Employee'); +end; +go + +execute p_employee_select 150, 300; +go + +-- Test for xml in create view +create view v1 (col1) as select * from t1 for xml raw, type; +go + +select * from v1; +go + +-- Test for xml on view with xml column +select * from v1 for xml path; +go + +-- Test for xml on pure relational view +create view v2 (col1, col2) as select * from t1; +go + +select * from v2 for xml path; +go + +drop view v1, v2; +go + +-- Test for xml and union all +select a from t1 UNION ALL select a from t2 for xml raw ('myrow'); +go + +-- Test invalid syntax when FOR XML is on both sides of UNION ALL, this is SQL Server behavior +select a from t1 for xml raw ('t1') UNION ALL select a from t2 for xml raw ('t2'); +go + +-- For xml can access CTE from same query block +with cte as (select a from t1) +select * from cte for xml raw; +go + +-- BABEL-1202: For xml subquery can't access CTE from outer query block +with cte as (select a from t1) +select * from t2, (select * from cte for xml raw) as t3(colxml); +go + +with cte as (select a from t1) +select (select * from cte for xml raw) as colxml, * from t2; +go + +with +cte1 as (select * from t1), +cte2 as (select a from cte1 for xml raw) +select * from cte2; +go + +-- Test for xml and recursive CTE +CREATE TABLE employees2 ( + id serial, + name varchar(255), + manager_id int +); + +INSERT INTO employees2 VALUES (1, 'Mark', null); +INSERT INTO employees2 VALUES (2, 'John', 1); +INSERT INTO employees2 VALUES (3, 'Dan', 2); +INSERT INTO employees2 VALUES (4, 'Clark', 1); +INSERT INTO employees2 VALUES (5, 'Linda', 2); +INSERT INTO employees2 VALUES (6, 'Willy', 2); +INSERT INTO employees2 VALUES (7, 'Barack', 2); +INSERT INTO employees2 VALUES (8, 'Elen', 2); +INSERT INTO employees2 VALUES (9, 'Kate', 3); +INSERT INTO employees2 VALUES (10, 'Terry', 4); +GO + +WITH managertree AS ( + SELECT id, name, manager_id + FROM employees2 + WHERE id = 2 + UNION ALL + SELECT e.id, e.name, e.manager_id + FROM employees2 e + INNER JOIN managertree mtree ON mtree.id = e.manager_id +) +SELECT * +FROM managertree mt; +GO + +WITH managertree AS ( + SELECT id, name, manager_id + FROM employees2 + WHERE id = 2 + UNION ALL + SELECT e.id, e.name, e.manager_id + FROM employees2 e + INNER JOIN managertree mtree ON mtree.id = e.manager_id +) +SELECT * +FROM managertree mt WHERE mt.name = 'Linda' FOR XML RAW ('managertree'); +GO + +-- BABEL-1178, data type of variable is lost during variable binding in FORMAT +-- function +create procedure test_forxml @pid int as +declare @a int, @b smallint; +set @a = 1; +set @b = 1; +select a, datalength(@a), datalength(@b) from t1 where id = @pid for xml raw; +go + +-- datalength(@b) should be 2. But the data type of @b is lost during the +-- query transformation for FOR XML, so we end up getting a wrong length. +exec test_forxml 1; +go + +-- test string variable can be binded with for xml query +create procedure test_forxml_strvar @pid int, @str varchar(10) as +select * from t1 where id = @pid and a = @str for xml raw; +go +exec test_forxml_strvar 1, 't1_a1'; +go +-- test NULL parameter +exec test_forxml_strvar 1, NULL; +go + +-- clean up +drop table t1; +drop table t2; +drop table MyTable; +drop table employees; +drop procedure p_employee_select; +drop table employees2; +drop procedure test_forxml; +drop procedure test_forxml_strvar; +go diff --git a/contrib/test/JDBC/input/functions/sys-column-property.sql b/contrib/test/JDBC/input/functions/sys-column-property.sql new file mode 100644 index 00000000000..272e6c0b232 --- /dev/null +++ b/contrib/test/JDBC/input/functions/sys-column-property.sql @@ -0,0 +1,40 @@ +DROP TABLE IF EXISTS t_column_property +GO + +CREATE TABLE t_column_property( + cp1 CHAR(1) NOT NULL, + cp2 CHAR(129), + cp3 CHAR(4000) NOT NULL, + cp4 VARCHAR(1), + cp5 VARCHAR(129) NOT NULL, + cp6 VARCHAR(4000), + cp7 INT, + cp8 INT NOT NULL); +GO + +DECLARE @table_id INT +SET @table_id = (select OBJECT_ID('t_column_property')); + +SELECT * FROM sys.columnproperty(@table_id, 'cp1', 'charmaxlen'); +SELECT * FROM sys.columnproperty(@table_id, 'cp2', 'charmaxlen'); +SELECT * FROM sys.columnproperty(@table_id, 'cp3', 'charmaxlen'); +SELECT * FROM sys.columnproperty(@table_id, 'cp4', 'charmaxlen'); +SELECT * FROM sys.columnproperty(@table_id, 'cp5', 'charmaxlen'); +SELECT * FROM sys.columnproperty(@table_id, 'cp6', 'charmaxlen'); +GO + +DECLARE @table_id INT +SET @table_id = (select OBJECT_ID('t_column_property')); + +SELECT * FROM sys.columnproperty(@table_id, 'cp1', 'allowsnull'); +SELECT * FROM sys.columnproperty(@table_id, 'cp2', 'allowsnull'); +SELECT * FROM sys.columnproperty(@table_id, 'cp3', 'allowsnull'); +SELECT * FROM sys.columnproperty(@table_id, 'cp4', 'allowsnull'); +SELECT * FROM sys.columnproperty(@table_id, 'cp5', 'allowsnull'); +SELECT * FROM sys.columnproperty(@table_id, 'cp6', 'allowsnull'); +SELECT * FROM sys.columnproperty(@table_id, 'cp7', 'allowsnull'); +SELECT * FROM sys.columnproperty(@table_id, 'cp8', 'allowsnull'); +GO + +DROP TABLE IF EXISTS t_column_property +GO diff --git a/contrib/test/JDBC/input/functions/sys-datefirst.sql b/contrib/test/JDBC/input/functions/sys-datefirst.sql new file mode 100644 index 00000000000..b6d7b7b2f05 --- /dev/null +++ b/contrib/test/JDBC/input/functions/sys-datefirst.sql @@ -0,0 +1,11 @@ +SELECT * FROM sys.datefirst() +GO + +SET datefirst 3 +GO + +SELECT @@datefirst +GO + +SELECT sys.datefirst() +GO diff --git a/contrib/test/JDBC/input/functions/sys-lock_timeout.sql b/contrib/test/JDBC/input/functions/sys-lock_timeout.sql new file mode 100644 index 00000000000..c285e9425f4 --- /dev/null +++ b/contrib/test/JDBC/input/functions/sys-lock_timeout.sql @@ -0,0 +1,13 @@ +SELECT * FROM sys.lock_timeout() +GO + +-- Setting of SET LOCK_TIMEOUT is set at execute or run time and not at parse time +-- Means will continue to display default value of 0 at next transaction +SET LOCK_TIMEOUT 100 +GO + +SELECT @@LOCK_TIMEOUT +GO + +SELECT sys.lock_timeout() +GO \ No newline at end of file diff --git a/contrib/test/JDBC/input/functions/sys-max_connections.sql b/contrib/test/JDBC/input/functions/sys-max_connections.sql new file mode 100644 index 00000000000..108703a6985 --- /dev/null +++ b/contrib/test/JDBC/input/functions/sys-max_connections.sql @@ -0,0 +1,11 @@ +SELECT * FROM sys.max_connections() +GO + +SET MAX_CONNECTIONS 3 --Should error out. Not possible for user to change. +GO + +SELECT @@MAX_CONNECTIONS +GO + +SELECT sys.max_connections() +GO \ No newline at end of file diff --git a/contrib/test/JDBC/input/functions/sys-original_login.sql b/contrib/test/JDBC/input/functions/sys-original_login.sql new file mode 100644 index 00000000000..831c8087cc2 --- /dev/null +++ b/contrib/test/JDBC/input/functions/sys-original_login.sql @@ -0,0 +1,2 @@ +SELECT ORIGINAL_LOGIN() +GO diff --git a/contrib/test/JDBC/input/functions/sys-schema-name.sql b/contrib/test/JDBC/input/functions/sys-schema-name.sql new file mode 100644 index 00000000000..4f8da357def --- /dev/null +++ b/contrib/test/JDBC/input/functions/sys-schema-name.sql @@ -0,0 +1,5 @@ +SELECT * FROM sys.schema_name() +GO + +SELECT sys.schema_name() +GO diff --git a/contrib/test/JDBC/input/functions/sys-trigger_nestlevel.sql b/contrib/test/JDBC/input/functions/sys-trigger_nestlevel.sql new file mode 100644 index 00000000000..c3099ee58fe --- /dev/null +++ b/contrib/test/JDBC/input/functions/sys-trigger_nestlevel.sql @@ -0,0 +1,34 @@ +SELECT * FROM trigger_nestlevel() +GO + +SET trigger_nestlevel 3 +GO + +DROP TABLE IF EXISTS t1 +GO + +CREATE TABLE t1(c1 int) +GO + +CREATE TRIGGER trigger1 ON t1 +AFTER INSERT +AS +BEGIN + IF (trigger_nestlevel()) = 1 + BEGIN + INSERT INTO t1(c1) VALUES (1); -- trigger_nestlevel should be 1 on first trigger call, so this should execute once & only once + END +END +GO + +INSERT INTO t1(c1) VALUES (0); +GO + +SELECT * FROM t1 +GO + +DROP TABLE t1 +GO + +SELECT trigger_nestlevel() +GO diff --git a/contrib/test/JDBC/input/insertbulk.txt b/contrib/test/JDBC/input/insertbulk.txt new file mode 100644 index 00000000000..d9cabdfb19d --- /dev/null +++ b/contrib/test/JDBC/input/insertbulk.txt @@ -0,0 +1,275 @@ +# int +Create table sourceTable(a int, b int not null) +Create table destinationTable(a int, b int not null) +Insert into sourceTable values (1, 1); +Insert into sourceTable values (NULL, 2); +insertbulk#!#sourceTable#!#destinationTable +Select * from sourceTable +Select * from destinationTable +drop table sourceTable +drop table destinationTable + +# smallint +Create table sourceTable(a smallint, b smallint not null) +Create table destinationTable(a smallint, b smallint not null) +Insert into sourceTable values (1, 1); +Insert into sourceTable values (NULL, 2); +insertbulk#!#sourceTable#!#destinationTable +Select * from sourceTable +Select * from destinationTable +drop table sourceTable +drop table destinationTable + +# bigint +Create table sourceTable(a bigint, b bigint not null) +Create table destinationTable(a bigint, b bigint not null) +Insert into sourceTable values (1, 1); +Insert into sourceTable values (NULL, 2); +insertbulk#!#sourceTable#!#destinationTable +Select * from sourceTable +Select * from destinationTable +drop table sourceTable +drop table destinationTable + +# bit +Create table sourceTable(a bit, b bit not null) +Create table destinationTable(a bit, b bit not null) +Insert into sourceTable values (1, 1); +Insert into sourceTable values (NULL, 0); +insertbulk#!#sourceTable#!#destinationTable +Select * from sourceTable +Select * from destinationTable +drop table sourceTable +drop table destinationTable + +# float +Create table sourceTable(a float, b float not null) +Create table destinationTable(a float, b float not null) +Insert into sourceTable values (1.1101, 0.00010); +Insert into sourceTable values (NULL, 0.101010); +insertbulk#!#sourceTable#!#destinationTable +Select * from sourceTable +Select * from destinationTable +drop table sourceTable +drop table destinationTable + +# real +Create table sourceTable(a real, b real not null) +Create table destinationTable(a real, b real not null) +Insert into sourceTable values (1.1101, 0.00010); +Insert into sourceTable values (NULL, 0.101010); +insertbulk#!#sourceTable#!#destinationTable +Select * from sourceTable +Select * from destinationTable +drop table sourceTable +drop table destinationTable + +# char +Create table sourceTable(a char(10), b char(10) not null) +Create table destinationTable(a char(10), b char(10) not null) +Insert into sourceTable values ('hello', 'jello'); +Insert into sourceTable values (NULL, 'mellow'); +insertbulk#!#sourceTable#!#destinationTable +Select * from sourceTable +Select * from destinationTable +drop table sourceTable +drop table destinationTable + +# nchar +Create table sourceTable(a nchar(10), b nchar(10) not null) +Create table destinationTable(a nchar(10), b nchar(10) not null) +Insert into sourceTable values ('hello', 'jello'); +Insert into sourceTable values (NULL, 'mellow'); +insertbulk#!#sourceTable#!#destinationTable +Select * from sourceTable +Select * from destinationTable +drop table sourceTable +drop table destinationTable + +# varchar +Create table sourceTable(a varchar(10), b varchar(10) not null) +Create table destinationTable(a varchar(10), b varchar(10) not null) +Insert into sourceTable values ('hello', 'jello'); +Insert into sourceTable values (NULL, 'mellow'); +insertbulk#!#sourceTable#!#destinationTable +Select * from sourceTable +Select * from destinationTable +drop table sourceTable +drop table destinationTable + +# nvarchar +Create table sourceTable(a nvarchar(10), b nvarchar(10) not null) +Create table destinationTable(a nvarchar(10), b nvarchar(10) not null) +Insert into sourceTable values ('hello', 'jello'); +Insert into sourceTable values (NULL, 'mellow'); +insertbulk#!#sourceTable#!#destinationTable +Select * from sourceTable +Select * from destinationTable +drop table sourceTable +drop table destinationTable + +# text +Create table sourceTable(a text, b text not null) +Create table destinationTable(a text, b text not null) +Insert into sourceTable values ('hello', 'jello'); +Insert into sourceTable values (NULL, 'mellow'); +insertbulk#!#sourceTable#!#destinationTable +Select * from sourceTable +Select * from destinationTable +drop table sourceTable +drop table destinationTable + +# ntext +Create table sourceTable(a ntext, b ntext not null) +Create table destinationTable(a ntext, b ntext not null) +Insert into sourceTable values ('hello', 'jello'); +Insert into sourceTable values (NULL, 'mellow'); +insertbulk#!#sourceTable#!#destinationTable +Select * from sourceTable +Select * from destinationTable +drop table sourceTable +drop table destinationTable + +# binary +Create table sourceTable(a binary(10), b binary(10) not null) +Create table destinationTable(a binary(10), b binary(10) not null) +Insert into sourceTable values (0x31323334, 0x9241); +Insert into sourceTable values (NULL, 0x4202); +insertbulk#!#sourceTable#!#destinationTable +Select * from sourceTable +Select * from destinationTable +drop table sourceTable +drop table destinationTable + +# varbinary +Create table sourceTable(a varbinary(10), b varbinary(10) not null) +Create table destinationTable(a varbinary(10), b varbinary(10) not null) +Insert into sourceTable values (0x31323334, 0x9241); +Insert into sourceTable values (NULL, 0x4202); +insertbulk#!#sourceTable#!#destinationTable +Select * from sourceTable +Select * from destinationTable +drop table sourceTable +drop table destinationTable + +# numeric +Create table sourceTable(a numeric(38, 22), b numeric(38, 22) not null) +Create table destinationTable(a numeric(38, 22), b numeric(38, 22) not null) +Insert into sourceTable values (1.1101, 0.00010); +Insert into sourceTable values (NULL, 0.101010); +insertbulk#!#sourceTable#!#destinationTable +Select * from sourceTable +Select * from destinationTable +drop table sourceTable +drop table destinationTable + +# decimal +Create table sourceTable(a decimal(38, 22), b decimal(38, 22) not null) +Create table destinationTable(a decimal(38, 22), b decimal(38, 22) not null) +Insert into sourceTable values (1.1101, 0.00010); +Insert into sourceTable values (NULL, 0.101010); +insertbulk#!#sourceTable#!#destinationTable +Select * from sourceTable +Select * from destinationTable +drop table sourceTable +drop table destinationTable + +# money +Create table sourceTable(a money, b money not null) +Create table destinationTable(a money, b money not null) +Insert into sourceTable values (100.11, 0.10); +Insert into sourceTable values (NULL, 91.12); +insertbulk#!#sourceTable#!#destinationTable +Select * from sourceTable +Select * from destinationTable +drop table sourceTable +drop table destinationTable + +# smallmoney +Create table sourceTable(a smallmoney, b smallmoney not null) +Create table destinationTable(a smallmoney, b smallmoney not null) +Insert into sourceTable values (100.11, 0.10); +Insert into sourceTable values (NULL, 91.12); +insertbulk#!#sourceTable#!#destinationTable +Select * from sourceTable +Select * from destinationTable +drop table sourceTable +drop table destinationTable + +# uniqueidentifier +Create table sourceTable(a uniqueidentifier, b uniqueidentifier not null) +Create table destinationTable(a uniqueidentifier, b uniqueidentifier not null) +Insert into sourceTable values ('51f178a6-53c7-472c-9be1-1c08942342d7', 'dd8cb046-461d-411e-be40-d219252ce849'); +Insert into sourceTable values (NULL, 'b84ebcc9-c927-4cfe-b08e-dc7f25b5087c'); +insertbulk#!#sourceTable#!#destinationTable +Select * from sourceTable +Select * from destinationTable +drop table sourceTable +drop table destinationTable + +# date +Create table sourceTable(a date, b date not null) +Create table destinationTable(a date, b date not null) +Insert into sourceTable values ('2000-02-28', '0001-01-01'); +Insert into sourceTable values (NULL, '1001-11-11'); +insertbulk#!#sourceTable#!#destinationTable +Select * from sourceTable +Select * from destinationTable +drop table sourceTable +drop table destinationTable + +# time +Create table sourceTable(a time(6), b time(6) not null) +Create table destinationTable(a time(6), b time(6) not null) +Insert into sourceTable values ('12:45:37.123', '12:45:37.12'); +Insert into sourceTable values (NULL, '12:45:37.123456'); +insertbulk#!#sourceTable#!#destinationTable +Select * from sourceTable +Select * from destinationTable +drop table sourceTable +drop table destinationTable + +# datetime +Create table sourceTable(a datetime, b datetime not null) +Create table destinationTable(a datetime, b datetime not null) +Insert into sourceTable values ('2000-12-13 12:58:23.123', '1900-02-28 23:59:59.989'); +Insert into sourceTable values (NULL, '9999-12-31 23:59:59.997'); +insertbulk#!#sourceTable#!#destinationTable +Select * from sourceTable +Select * from destinationTable +drop table sourceTable +drop table destinationTable + +# smalldatetime +Create table sourceTable(a smalldatetime, b smalldatetime not null) +Create table destinationTable(a smalldatetime, b smalldatetime not null) +Insert into sourceTable values ('2007-05-08 12:35:29', '2000-12-13 12:58:23'); +Insert into sourceTable values (NULL, '2000-02-28 23:45:30'); +insertbulk#!#sourceTable#!#destinationTable +Select * from sourceTable +Select * from destinationTable +drop table sourceTable +drop table destinationTable + +# datetime2 +Create table sourceTable(a Datetime2(6), b Datetime2(6) not null) +Create table destinationTable(a Datetime2(6), b Datetime2(6) not null) +Insert into sourceTable values ('2016-10-23 12:45:37.123', '2016-10-23 12:45:37.123'); +Insert into sourceTable values (NULL, '2016-10-23 12:45:37.123456'); +insertbulk#!#sourceTable#!#destinationTable +Select * from sourceTable +Select * from destinationTable +drop table sourceTable +drop table destinationTable + +# sql_variant +Create table sourceTable(a sql_variant, b sql_variant not null) +Create table destinationTable(a sql_variant, b sql_variant not null) +# Bug BABEL-2728 +#Insert into sourceTable values (cast (1 as int),cast ('abc' as varchar(10))); +Insert into sourceTable values (NULL, cast ('14:37:45.123456' as time(5))); +insertbulk#!#sourceTable#!#destinationTable +Select * from sourceTable +Select * from destinationTable +drop table sourceTable +drop table destinationTable \ No newline at end of file diff --git a/contrib/test/JDBC/input/interoperability/TestBasicInterop.mix b/contrib/test/JDBC/input/interoperability/TestBasicInterop.mix new file mode 100644 index 00000000000..589497d7cd4 --- /dev/null +++ b/contrib/test/JDBC/input/interoperability/TestBasicInterop.mix @@ -0,0 +1,129 @@ +-- tsql +CREATE PROCEDURE tsql_interop_proc1 +AS +SELECT CAST('$1.0909' AS money); +EXEC [public].pg_interop_proc2; +BEGIN TRANSACTION; +COMMIT; +GO +-- psql +CREATE PROCEDURE pg_interop_proc1() +AS +$$ +BEGIN + CALL master_dbo.tsql_interop_proc1(); +END +$$ LANGUAGE PLPGSQL; +GO +CREATE PROCEDURE pg_interop_proc2() +AS +$$ +BEGIN + COMMIT; +END +$$ LANGUAGE PLPGSQL; +GO + +-- tsql +EXEC [public].pg_interop_proc1 +GO +-- psql +CALL pg_interop_proc1() +GO +DROP PROCEDURE pg_interop_proc1 +GO +DROP PROCEDURE pg_interop_proc2 +GO + +-- tsql +DROP PROCEDURE tsql_interop_proc1 +GO + +-- tsql +CREATE PROCEDURE tsql_interop_proc1 +AS +EXEC [public].pg_interop_proc1; +GO +-- psql +CREATE PROCEDURE pg_interop_proc1() +AS +$$ +BEGIN + CALL master_dbo.tsql_interop_proc2(); +END +$$ LANGUAGE PLPGSQL; +GO +-- tsql +CREATE PROCEDURE tsql_interop_proc2 +AS +SELECT 1/0; +GO + +-- tsql +EXEC tsql_interop_proc1 +GO +-- psql +CALL master_dbo.tsql_interop_proc1() +GO + +-- tsql +CREATE PROCEDURE tsql_interop_proc_sp_exec +AS +DECLARE @SQLString NVARCHAR(100); +SET @SQLString = N'commit;'; +EXEC sp_executesql @SQLString; +GO + +-- psql +CREATE PROCEDURE pg_interop_proc_sp_exec() +AS +$$ +BEGIN + CALL master_dbo.tsql_interop_proc_sp_exec(); +END +$$ LANGUAGE PLPGSQL; +GO + +-- tsql +BEGIN TRAN; +EXEC [public].pg_interop_proc_sp_exec +GO + +-- tsql +SELECT CONVERT(datetime, '2021-12-30') +GO + +-- tsql +SELECT DATETIME2('9999-99-99'); +DROP PROCEDURE wrongProcedure; +GO + +--tsql +SELECT CONVERT(varchar(50), GETDATE(), 200); +GO + +--tsql +select set_config('babelfishpg_tsql.auto_commit_batch', 'off', false); +CREATE TABLE batch_table(c1 int); +GO + +--psql +SELECT * FROM batch_table; +DROP TABLE batch_table; +GO + +-- psql +DROP PROCEDURE pg_interop_proc1 +GO + +-- tsql +DROP PROCEDURE tsql_interop_proc1 +GO +DROP PROCEDURE tsql_interop_proc2 +GO +DROP PROCEDURE tsql_interop_proc_sp_exec +GO + +-- psql +DROP PROCEDURE pg_interop_proc_sp_exec +GO diff --git a/contrib/test/JDBC/input/interoperability/TestInteropProcedures.mix b/contrib/test/JDBC/input/interoperability/TestInteropProcedures.mix new file mode 100644 index 00000000000..bc71fa6edee --- /dev/null +++ b/contrib/test/JDBC/input/interoperability/TestInteropProcedures.mix @@ -0,0 +1,161 @@ +-- tsql +CREATE PROCEDURE tsql_interop_proc1 +AS +UPDATE procTab1 SET c1=10 where c2='b'; +INSERT INTO procTab1 values(1,'a'); +INSERT INTO procTab1 values(2,'b'); +EXEC psql_interop_proc2; +GO + +-- psql currentSchema=master_dbo,public +CREATE PROCEDURE psql_interop_proc1() +AS +$$ +BEGIN + CREATE TABLE procTab1(c1 int); + INSERT INTO procTab1 values (5); + ALTER TABLE procTab1 ADD c2 char; + CALL tsql_interop_proc1(); +END +$$ LANGUAGE PLPGSQL; +GO + +CREATE PROCEDURE psql_interop_proc2() +AS +$$ +BEGIN + INSERT INTO procTab1(c1,c2) values (3,'c'); + UPDATE procTab1 SET c1=10 where c2='b'; + INSERT INTO procTab1(c1,c2) values (4,'d'); + DELETE FROM procTab1 where c2='a'; +END +$$ LANGUAGE PLPGSQL; +GO + +-- tsql +EXEC psql_interop_proc1 +GO +SELECT * FROM procTab1 order by c1 +GO + +-- psql currentSchema=master_dbo,public +CALL tsql_interop_proc1() +GO +SELECT DISTINCT c1 FROM procTab1 +GO + +-- tsql +DROP TABLE procTab1 +GO +DROP PROCEDURE tsql_interop_proc1 +GO + +-- tsql +CREATE PROCEDURE tsql_interop_proc1 +AS +DECLARE @SQLString NVARCHAR(100); +SET @SQLString = N'ALTER TABLE procTab1 ALTER COLUMN c2 varchar(10);'; +EXEC sp_executesql @SQLString; +INSERT INTO procTab1(c1,c2) values(11,'abc'); +UPDATE procTab1 SET c1=c1+1 WHERE c2 IS NULL OR c2='a'; +EXEC psql_interop_proc3; +GO + +-- psql currentSchema=master_dbo,public +CREATE PROCEDURE psql_interop_proc3() +AS +$$ +DECLARE myvar varchar(10) = 'def'; +BEGIN +UPDATE procTab1 SET c2=myvar WHERE c1 BETWEEN 2 AND 10; +INSERT INTO procTab1(c1,c2) values(12,'xyz'); +END +$$ LANGUAGE PLPGSQL; +GO + +-- tsql +EXEC psql_interop_proc1 +GO +SELECT * FROM procTab1 WHERE c2 LIKE 'a%' +GO +DROP TABLE procTab1 +GO + +-- tsql +CREATE PROCEDURE tsql_interop_proc +AS +DECLARE @handle int; +EXEC SP_PREPARE @handle OUT, NULL, 'SELECT ''OK''' +EXEC SP_EXECUTE @handle +EXEC SP_UNPREPARE @handle +GO + +-- psql currentSchema=master_dbo,public +CREATE PROCEDURE psql_interop_proc() +AS +$$ +BEGIN +CALL tsql_interop_proc(); +END +$$ LANGUAGE PLPGSQL; +GO + +-- tsql +EXEC psql_interop_proc; +GO +DROP PROCEDURE tsql_interop_proc +GO + +-- tsql +CREATE PROCEDURE tsql_interop_proc +AS +CREATE TABLE cursorTab(a INT, b SMALLINT, c BIGINT, d TINYINT, e BIT); +INSERT INTO cursorTab values(0, 0, 0, 0, 0); +INSERT INTO cursorTab values(1, 2, 3, 4, 1); +DECLARE @cursor_handle int; +EXEC sp_cursoropen @cursor_handle OUTPUT, 'select a,b,c,d from cursorTab', 2, 1; +EXEC sp_cursorfetch @cursor_handle, 2, 0, 2; +EXEC sp_cursoroption @cursor_handle, 1, 2; +EXEC sp_cursor @cursor_handle, 40, 1, ''; +EXEC sp_cursorclose @cursor_handle; +GO + +EXEC psql_interop_proc; +GO +DROP TABLE cursorTab +GO +DROP PROCEDURE tsql_interop_proc +GO + +-- tsql +CREATE PROCEDURE tsql_interop_proc +AS +BEGIN TRY + SELECT 1/0; +END TRY +BEGIN CATCH + SELECT 1; +END CATCH +GO + +-- tsql +EXEC psql_interop_proc +GO +DROP PROCEDURE tsql_interop_proc +GO + +-- psql currentSchema=master_dbo,public +DROP PROCEDURE psql_interop_proc1 +GO +DROP PROCEDURE psql_interop_proc2 +GO +DROP PROCEDURE psql_interop_proc3 +GO + +-- tsql +DROP PROCEDURE tsql_interop_proc1 +GO + +-- psql currentSchema=master_dbo,public +DROP PROCEDURE psql_interop_proc +GO diff --git a/contrib/test/JDBC/input/interoperability/TestProcedureWithErrorHandling.mix b/contrib/test/JDBC/input/interoperability/TestProcedureWithErrorHandling.mix new file mode 100644 index 00000000000..5fae9b3a298 --- /dev/null +++ b/contrib/test/JDBC/input/interoperability/TestProcedureWithErrorHandling.mix @@ -0,0 +1,292 @@ +-- tsql +CREATE PROCEDURE tsql_interop_proc +AS +CREATE TABLE procTab1(c1 money, c2 char); +BEGIN TRY + SELECT xact_state(); + INSERT INTO procTab1 values($1,'a'); + INSERT INTO procTab1 values('i','a'); +END TRY +BEGIN CATCH + SELECT xact_state(); + SELECT @@trancount; +END CATCH +GO + +-- psql +CREATE PROCEDURE psql_interop_proc() +AS +$$ +BEGIN + CALL master_dbo.tsql_interop_proc(); +END +$$ LANGUAGE PLPGSQL; +GO + +-- tsql +EXEC [public].psql_interop_proc +GO +SELECT * FROM procTab1 +GO +EXEC tsql_interop_proc +GO +SELECT * FROM procTab1 +GO +DROP TABLE procTab1 +GO +BEGIN TRANSACTION +GO +EXEC [public].psql_interop_proc +GO +SELECT * FROM procTab1 +GO +COMMIT +GO +DROP TABLE procTab1 +GO + +/* TODO: BABEL-2377 */ +/* -- psql */ +/* CALL psql_interop_proc(); */ +/* GO */ +/* SELECT * FROM procTab1; */ +/* GO */ + +-- tsql +SET IMPLICIT_TRANSACTIONS ON +GO +EXEC [public].psql_interop_proc +GO +SELECT * FROM procTab1 +GO +IF @@TRANCOUNT > 0 ROLLBACK; +GO +SET IMPLICIT_TRANSACTIONS OFF +GO +DROP PROCEDURE tsql_interop_proc +GO + +-- tsql +CREATE PROCEDURE tsql_interop_proc +AS +CREATE TABLE procTab1(c1 money, c2 char); +BEGIN TRY + SELECT xact_state(); + INSERT INTO procTab1 values($1,'a'); + EXEC psql_interop_proc1; +END TRY +BEGIN CATCH + SELECT xact_state(); + SELECT @@TRANCOUNT; +END CATCH +GO + +-- psql +CREATE PROCEDURE psql_interop_proc1() +AS +$$ +BEGIN + INSERT INTO procTab1(c1,c2) values('i','a'); +END +$$ LANGUAGE PLPGSQL; +GO + +/* -- psql */ +/* CALL psql_interop_proc(); */ +/* GO */ +/* SELECT * FROM procTab1; */ +/* GO */ + +-- tsql +EXEC [public].psql_interop_proc; +GO +SELECT * FROM procTab1 +GO +DROP PROCEDURE tsql_interop_proc +GO + +-- psql +DROP PROCEDURE psql_interop_proc1 +GO + +-- tsql +CREATE PROCEDURE tsql_interop_proc +AS +BEGIN TRY + RAISERROR ('raiserror 16', 16, 1); +END TRY +BEGIN CATCH + SELECT 'CATCH in Procedure 1'; + SELECT + ERROR_LINE() AS line, + ERROR_MESSAGE() AS msg, + ERROR_NUMBER() AS num, + ERROR_PROCEDURE() AS proc_, + ERROR_SEVERITY() AS sev, + ERROR_STATE() AS state; + THROW; +END CATCH +GO +EXEC [public].psql_interop_proc; +GO + +/* -- psql */ +/* CALL psql_interop_proc(); */ +/* GO */ + +DROP PROCEDURE tsql_interop_proc +GO + +-- tsql +CREATE PROCEDURE tsql_interop_proc2 +AS +BEGIN TRY + RAISERROR ('raiserror 16', 16, 1); +END TRY +BEGIN CATCH + SELECT 'CATCH in Procedure 1'; + SELECT + ERROR_LINE() AS line, + ERROR_MESSAGE() AS msg, + ERROR_NUMBER() AS num, + ERROR_PROCEDURE() AS proc_, + ERROR_SEVERITY() AS sev, + ERROR_STATE() AS state; + + THROW; +END CATCH +GO + +CREATE PROCEDURE tsql_interop_proc +AS +BEGIN TRY + EXEC tsql_interop_proc2; +END TRY +BEGIN CATCH + SELECT 'CATCH in Procedure 2'; + SELECT + ERROR_NUMBER() AS num, + ERROR_PROCEDURE() AS proc_, + ERROR_SEVERITY() AS sev, + ERROR_STATE() AS state; + THROW; +END CATCH +GO + +EXEC [public].psql_interop_proc; +GO + +/* -- psql */ +/* CALL psql_interop_proc(); */ +/* GO */ + +DROP PROCEDURE tsql_interop_proc2 +GO + +-- tsql +CREATE PROCEDURE tsql_interop_proc2 +AS + EXEC [public].psql_interop_proc2; +GO + +-- psql +CREATE PROCEDURE psql_interop_proc2() +AS +$$ +BEGIN + SELECT 100/0; +END +$$ LANGUAGE PLPGSQL; +GO + +-- tsql +EXEC [public].psql_interop_proc; +GO + +/* -- psql */ +/* CALL psql_interop_proc(); */ +/* GO */ + +-- psql +DROP PROCEDURE psql_interop_proc2 +GO + +-- tsql +DROP PROCEDURE tsql_interop_proc +GO +DROP PROCEDURE tsql_interop_proc2 +GO + +-- tsql +CREATE PROCEDURE tsql_interop_proc +AS +BEGIN TRY + SELECT 100/0; + RAISERROR('Hello %s', 16, 1, 'World'); +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH +GO + +-- tsql +EXEC [public].psql_interop_proc; +GO + +/* -- psql */ +/* CALL psql_interop_proc(); */ +/* GO */ + +-- tsql +SET XACT_ABORT OFF; +GO +EXEC [public].psql_interop_proc +GO +SET XACT_ABORT ON; +GO +DROP PROCEDURE tsql_interop_proc +GO + +-- tsql +CREATE PROCEDURE tsql_interop_proc +AS + RAISERROR('Hello %s', 16, 1, 'World'); + SELECT xact_state(); + SELECT @@trancount; +GO + +-- tsql +EXEC [public].psql_interop_proc +GO + +-- psql +CALL psql_interop_proc(); +GO + +-- tsql +SET XACT_ABORT OFF; +GO +SET IMPLICIT_TRANSACTIONS ON +GO +EXEC [public].psql_interop_proc +GO +EXEC tsql_interop_proc +GO + +-- psql +CALL psql_interop_proc(); +GO + +-- tsql +SET IMPLICIT_TRANSACTIONS OFF +GO +SET XACT_ABORT ON; +GO + +-- psql +DROP PROCEDURE psql_interop_proc +GO + +-- tsql +DROP PROCEDURE tsql_interop_proc +GO diff --git a/contrib/test/JDBC/input/interoperability/TestProcedureWithTransactions.mix b/contrib/test/JDBC/input/interoperability/TestProcedureWithTransactions.mix new file mode 100644 index 00000000000..5dcaed860e7 --- /dev/null +++ b/contrib/test/JDBC/input/interoperability/TestProcedureWithTransactions.mix @@ -0,0 +1,457 @@ +-- tsql +CREATE PROCEDURE tsql_interop_proc1 +AS +UPDATE procTab1 SET c1=10 where c2='b'; +INSERT INTO procTab1 values(1,'a'); +INSERT INTO procTab1 values(2,'b'); +EXEC psql_interop_proc2; +GO + +-- psql currentSchema=master_dbo,public +CREATE PROCEDURE psql_interop_proc1() +AS +$$ +BEGIN + CREATE TABLE procTab1(c1 int); + ALTER TABLE procTab1 OWNER TO master_dbo; + INSERT INTO procTab1 values (5); + ALTER TABLE procTab1 ADD c2 char; + CALL tsql_interop_proc1(); +END +$$ LANGUAGE PLPGSQL; +GO + +CREATE PROCEDURE psql_interop_proc2() +AS +$$ +BEGIN + INSERT INTO procTab1(c1,c2) values (3,'c'); + UPDATE procTab1 SET c1=10 where c2='b'; + INSERT INTO procTab1(c1,c2) values (4,'d'); + DELETE FROM procTab1 where c2='a'; +END +$$ LANGUAGE PLPGSQL; +GO + +-- tsql +BEGIN TRANSACTION +GO +EXEC psql_interop_proc1 +GO +COMMIT +GO +SELECT * FROM procTab1 order by c1 +GO + +-- psql currentSchema=master_dbo,public +BEGIN TRANSACTION +GO +CALL tsql_interop_proc1() +GO +COMMIT +GO +SELECT * FROM procTab1 +GO + +-- psql currentSchema=master_dbo,public +BEGIN TRANSACTION +GO +CALL tsql_interop_proc1() +GO +ROLLBACK +GO +SELECT * FROM procTab1 +GO + +-- tsql +BEGIN TRANSACTION +GO +SAVE TRANSACTION sp1 +GO +EXEC tsql_interop_proc1 +GO +INSERT INTO procTab1(c1,c2) values(11,'e') +GO +ROLLBACK TRANSACTION sp1 +GO +SELECT * FROM procTab1 +GO +ROLLBACK +GO +SELECT * FROM procTab1 +GO + +-- tsql +DROP TABLE procTab1 +GO + +-- psql currentSchema=master_dbo,public +DROP PROCEDURE psql_interop_proc2 +GO + +-- psql currentSchema=master_dbo,public +CREATE PROCEDURE psql_interop_proc2() +AS +$$ +DECLARE myvar varchar(1) = 'f'; +BEGIN + UPDATE procTab1 SET c2=myvar WHERE c1 BETWEEN 2 AND 10; + INSERT INTO procTab1(c1,c2) values(12,'x'); + COMMIT; +END +$$ LANGUAGE PLPGSQL; +GO + +-- tsql +BEGIN TRANSACTION +GO +EXEC psql_interop_proc1 +GO +SELECT * FROM procTab1 +GO +DROP PROCEDURE psql_interop_proc2 +GO + +-- psql currentSchema=master_dbo,public +CREATE PROCEDURE psql_interop_proc2() +AS +$$ +BEGIN + UPDATE procTab1 SET c1=c1+2 WHERE c1 BETWEEN 2 AND 10; + SAVEPOINT sp1; + INSERT INTO procTab1(c1,c2) values(13,'w'); + EXECUTE "ROLLBACK TO $1" USING sp1; + ROLLBACK; +END +$$ LANGUAGE PLPGSQL; +GO + +-- tsql +BEGIN TRANSACTION +GO +EXEC psql_interop_proc1 +GO +SELECT * FROM procTab1 +GO + +-- psql currentSchema=master_dbo,public +DROP PROCEDURE psql_interop_proc2 +GO + +-- psql currentSchema=master_dbo,public +CREATE PROCEDURE psql_interop_proc2() +AS +$$ +BEGIN + UPDATE procTab1 SET c1=c1+2 WHERE c1 BETWEEN 2 AND 10; + INSERT INTO procTab1(c1,c2) values(13,'w'); + ROLLBACK; +END +$$ LANGUAGE PLPGSQL; +GO + +-- tsql +BEGIN TRANSACTION +GO +EXEC psql_interop_proc1 +GO +SELECT * FROM procTab1 +GO + +-- tsql +BEGIN TRANSACTION +GO +SAVE TRANSACTION sp1; +GO +EXEC psql_interop_proc1 +GO +SELECT * FROM procTab1 +GO + +-- tsql +BEGIN TRANSACTION +GO +EXEC psql_interop_proc1 +GO +SELECT * FROM procTab1 +GO + +-- psql currentSchema=master_dbo,public +DROP PROCEDURE psql_interop_proc2 +GO + +-- tsql +DROP PROCEDURE tsql_interop_proc1 +GO + +-- tsql +CREATE PROCEDURE tsql_interop_proc1 +AS +BEGIN TRANSACTION; +UPDATE procTab1 SET c1=10 where c2='b'; +INSERT INTO procTab1 values(1,'a'); +INSERT INTO procTab1 values(2,'b'); +EXEC psql_interop_proc2; +GO + +-- psql currentSchema=master_dbo,public +CREATE PROCEDURE psql_interop_proc2() +AS +$$ +BEGIN + UPDATE procTab1 SET c1=c1+2 WHERE c1 BETWEEN 2 AND 10; + SAVEPOINT sp1; + INSERT INTO procTab1(c1,c2) values(13,'w'); + EXECUTE "ROLLBACK TO $1" USING sp1; + COMMIT; +END +$$ LANGUAGE PLPGSQL; +GO + +-- tsql +EXEC psql_interop_proc1 +GO +SELECT * FROM procTab1 +GO + +-- psql currentSchema=master_dbo,public +DROP PROCEDURE psql_interop_proc2 +GO + +-- tsql +DROP PROCEDURE tsql_interop_proc1 +GO + +-- tsql +CREATE PROCEDURE tsql_interop_proc1 +AS +BEGIN TRANSACTION; +UPDATE procTab1 SET c1=10 where c2='b'; +SAVE TRANSACTION sp1; +INSERT INTO procTab1 values(1,'a'); +ROLLBACK TRANSACTION sp1; +INSERT INTO procTab1 values(2,'b'); +EXEC psql_interop_proc2; +GO + +-- psql currentSchema=master_dbo,public +CREATE PROCEDURE psql_interop_proc2() +AS +$$ +BEGIN + UPDATE procTab1 SET c1=c1+2 WHERE c1 BETWEEN 2 AND 10; + SAVEPOINT sp2; + INSERT INTO procTab1(c1,c2) values(13,'w'); + EXECUTE "ROLLBACK TO $1" USING sp2; + COMMIT; +END +$$ LANGUAGE PLPGSQL; +GO + +-- tsql +EXEC psql_interop_proc1 +GO +SELECT * FROM procTab1 +GO + +-- psql currentSchema=master_dbo,public +DROP PROCEDURE psql_interop_proc2 +GO + +-- psql currentSchema=master_dbo,public +CREATE PROCEDURE psql_interop_proc2() +AS +$$ +BEGIN + UPDATE procTab1 SET c1=c1+2 WHERE c1 BETWEEN 2 AND 10; + INSERT INTO procTab1(c1,c2) values(13,'w'); + COMMIT; +END +$$ LANGUAGE PLPGSQL; +GO + +-- tsql +EXEC psql_interop_proc1 +GO +SELECT * FROM procTab1 +GO +DROP PROCEDURE tsql_interop_proc1 +GO + +-- tsql +CREATE PROCEDURE tsql_interop_proc1 +AS +DECLARE @dt DATETIME = '2019-12-31 14:43:35.863'; +CREATE TABLE procTab1(c1 int, c2 char); +SELECT CONVERT(varchar(30), @dt, 1); +INSERT INTO procTab1 values(1,'a'); +ROLLBACK TRANSACTION sp1; +INSERT INTO procTab1 values(2,'b'); +SELECT CONVERT(varchar(30), CAST('2017-08-25' AS date), 102); +GO + +-- psql currentSchema=master_dbo,public +BEGIN TRANSACTION +GO +SAVEPOINT sp1 +GO +CALL tsql_interop_proc1() +GO +COMMIT +GO +SELECT * FROM procTab1 +GO + +-- tsql +BEGIN TRANSACTION +GO +SAVE TRANSACTION sp1 +GO +EXEC tsql_interop_proc1 +GO +ROLLBACK +GO +SELECT * FROM procTab1 +GO + +-- tsql +CREATE PROCEDURE tsql_interop_proc +AS +DECLARE @handle int; +EXEC SP_PREPEXEC @handle OUT, NULL, 'SELECT ''OK''' +EXEC SP_EXECUTE @handle +EXEC SP_EXECUTE @handle +EXEC SP_UNPREPARE @handle +EXEC ('select datetimefromparts(2016, 12, 26, 23, 30, 5, 32);') +GO + +-- psql currentSchema=master_dbo,public +CREATE PROCEDURE psql_interop_proc() +AS +$$ +BEGIN +CALL tsql_interop_proc(); +END +$$ LANGUAGE PLPGSQL; +GO + +-- tsql +BEGIN TRANSACTION +GO +EXEC psql_interop_proc; +GO +COMMIT +GO +DROP PROCEDURE tsql_interop_proc +GO + +-- tsql +CREATE PROCEDURE tsql_interop_proc +AS +DECLARE @handle INT; +DECLARE @batch VARCHAR(500); +SET @batch = 'begin transaction; insert into t1 values(1); commit;' +EXEC sp_prepare @handle OUT, NULL, @batch +EXEC sp_execute @handle +BEGIN TRANSACTION; +EXEC sp_execute @handle +ROLLBACK; +EXEC SP_UNPREPARE @handle; +GO + +-- tsql +CREATE TABLE t1 (a INT); +GO +EXEC psql_interop_proc; +GO +SELECT count(*) FROM t1; +GO +DROP PROCEDURE tsql_interop_proc +GO +DROP TABLE t1 +GO + +-- tsql +CREATE PROCEDURE tsql_interop_proc +AS +DECLARE @handle int; +DECLARE @inner_handle int; +DECLARE @batch VARCHAR(500); +SET @batch = 'EXEC SP_PREPARE @inner_handle OUT, NULL, ''SELECT 1'' ' +EXEC SP_PREPARE @handle out, '@inner_handle int OUT', @batch +EXEC SP_EXECUTE @handle, @inner_handle OUT +BEGIN TRANSACTION; +EXEC SP_EXECUTE @inner_handle +ROLLBACK; +EXEC SP_UNPREPARE @inner_handle -- unprepare inner first +EXEC SP_UNPREPARE @handle +GO + +-- tsql +EXEC psql_interop_proc; +GO +DROP PROCEDURE tsql_interop_proc +GO + +-- tsql +CREATE PROCEDURE tsql_interop_proc +AS +CREATE TABLE cursorTab(a INT, b SMALLINT, c BIGINT, d TINYINT, e BIT); +INSERT INTO cursorTab values(0, 0, 0, 0, 0); +INSERT INTO cursorTab values(1, 2, 3, 4, 1); +INSERT INTO cursorTab values(4, 5, 6, 7, 4); +DECLARE @cursor_handle int; +EXEC sp_cursoropen @cursor_handle OUTPUT, 'select a,b,c,d from cursorTab', 2, 1; +EXEC sp_cursorfetch @cursor_handle, 2, 0, 2; +EXEC sp_cursoroption @cursor_handle, 1, 2; +BEGIN TRANSACTION; +EXEC sp_cursor @cursor_handle, 40, 1, ''; +COMMIT; +EXEC sp_cursorclose @cursor_handle; +GO + +EXEC psql_interop_proc; +GO +DROP PROCEDURE tsql_interop_proc +GO + +-- tsql +CREATE PROCEDURE tsql_interop_proc +AS +SELECT DATEPART(weekday, CAST( '2021-12-31' as DATE)); +SELECT DATENAME(year, cast('2002-05-23 23:41:29.998' as smalldatetime)); +SELECT @@DATEFIRST; +SELECT dateadd(year, 2, CAST('20060830' AS datetime)); +SELECT + lower(cast('A ' as char(5))), + left(cast('a ' as char(5)), 2), + charindex(cast('a ' as char(5)), 'a '), + ascii(cast('a ' as char(5))), + datalength(cast('123 ' as char(5))), + length(cast('123 ' as char(5))), + len(cast('123 ' as char(5))); +BEGIN TRANSACTION; +SELECT cast(cast('2021-08-15 ' as char(11)) as sys.smalldatetime); +COMMIT; +GO + +EXEC tsql_interop_proc; +GO +EXEC psql_interop_proc; +GO +DROP PROCEDURE tsql_interop_proc +GO + +-- psql currentSchema=master_dbo,public +DROP PROCEDURE psql_interop_proc1 +GO +DROP PROCEDURE psql_interop_proc2 +GO + +-- tsql +DROP PROCEDURE tsql_interop_proc1 +GO + +-- psql currentSchema=master_dbo,public +DROP PROCEDURE psql_interop_proc +GO diff --git a/contrib/test/JDBC/input/interoperability/TestProcedureWithTriggers.mix b/contrib/test/JDBC/input/interoperability/TestProcedureWithTriggers.mix new file mode 100644 index 00000000000..1c4641357bb --- /dev/null +++ b/contrib/test/JDBC/input/interoperability/TestProcedureWithTriggers.mix @@ -0,0 +1,597 @@ +-- psql currentSchema=master_dbo,public +CREATE PROCEDURE psql_interop_proc1() +AS +$$ +BEGIN + CREATE TABLE triggerTab1(c1 int, c2 varchar(30)); + CREATE TABLE triggerTab2(c1 int); + INSERT INTO triggerTab1 VALUES(1, 'first'); + INSERT INTO triggerTab2 VALUES(1); +END +$$ LANGUAGE PLPGSQL; +GO + +-- tsql +EXEC psql_interop_proc1 +GO + +CREATE TRIGGER txnTrig1 ON triggerTab1 AFTER INSERT AS +INSERT INTO triggerTab2 VALUES(4); +UPDATE triggerTab2 set c1 = c1+2; +GO + +CREATE TRIGGER txnTrig2 ON triggerTab2 FOR UPDATE AS +INSERT INTO triggerTab2 VALUES(2); +UPDATE triggerTab1 set c1 = c1+2; +DELETE FROM triggerTab2; +INSERT INTO triggerTab2 values(2); +GO + +-- psql currentSchema=master_dbo,public +CREATE PROCEDURE psql_interop_proc2() +AS +$$ +BEGIN + INSERT INTO triggerTab1 VALUES(2, 'second'); + INSERT INTO triggerTab1 VALUES(3, 'third'); +END +$$ LANGUAGE PLPGSQL; +GO + +-- tsql +CREATE PROCEDURE tsql_interop_proc +AS +INSERT INTO triggerTab1 VALUES(2, 'second'); +INSERT INTO triggerTab1 VALUES(3, 'third'); +GO + +-- tsql +EXEC tsql_interop_proc +GO +SELECT * from triggerTab1 ORDER BY c1; +GO + +EXEC psql_interop_proc2 +GO +SELECT * from triggerTab2 ORDER BY c1; +GO + +-- psql currentSchema=master_dbo,public +CALL tsql_interop_proc(); +GO +SELECT * from triggerTab1 ORDER BY c1; +GO + +CALL psql_interop_proc2(); +GO +SELECT * from triggerTab2 ORDER BY c1; +GO + +-- tsql +BEGIN TRANSACTION +GO +EXEC tsql_interop_proc +GO +SELECT * from triggerTab1 ORDER BY c1; +GO +COMMIT +GO + +-- psql currentSchema=master_dbo,public +BEGIN TRANSACTION +GO +CALL tsql_interop_proc(); +GO +SELECT * from triggerTab1 ORDER BY c1; +GO +ROLLBACK +GO + +-- tsql +BEGIN TRANSACTION +GO +EXEC psql_interop_proc2 +GO +SELECT * from triggerTab2 ORDER BY c1; +GO +ROLLBACK +GO + +-- psql currentSchema=master_dbo,public +BEGIN TRANSACTION +GO +CALL psql_interop_proc2(); +GO +SELECT * from triggerTab2 ORDER BY c1; +GO +COMMIT +GO + +-- tsql +BEGIN TRANSACTION +GO +SAVE TRANSACTION sp1; +GO +EXEC psql_interop_proc2 +GO +ROLLBACK TRANSACTION sp1; +GO +SELECT * from triggerTab1 ORDER BY c1; +GO +COMMIT +GO + +-- tsql +BEGIN TRANSACTION +GO +SAVE TRANSACTION sp1; +GO +EXEC tsql_interop_proc +GO +ROLLBACK TRANSACTION sp1; +GO +SELECT * from triggerTab2 ORDER BY c1; +GO +COMMIT +GO + +-- psql currentSchema=master_dbo,public +BEGIN TRANSACTION +GO +SAVEPOINT sp1; +GO +CALL tsql_interop_proc(); +GO +ROLLBACK TO sp1; +GO +SELECT * from triggerTab2 ORDER BY c1; +GO +COMMIT +GO + +-- tsql +DROP PROCEDURE tsql_interop_proc; +GO + +CREATE PROCEDURE tsql_interop_proc +AS +BEGIN TRANSACTION; +INSERT INTO triggerTab1 VALUES(2, 'second'); +COMMIT; +GO + +-- tsql +EXEC tsql_interop_proc +GO +SELECT * from triggerTab1 ORDER BY c1; +GO + +-- psql currentSchema=master_dbo,public +CALL tsql_interop_proc(); +GO +SELECT * from triggerTab2 ORDER BY c1; +GO + +-- tsql +DROP PROCEDURE tsql_interop_proc; +GO + +CREATE PROCEDURE tsql_interop_proc +AS +BEGIN TRANSACTION; +INSERT INTO triggerTab1 VALUES(2, 'second'); +ROLLBACK; +INSERT INTO triggerTab1 VALUES(3, 'third'); +GO + +-- tsql +EXEC tsql_interop_proc +GO +SELECT * from triggerTab1 ORDER BY c1; +GO + +-- psql currentSchema=master_dbo,public +CALL tsql_interop_proc(); +GO +SELECT * from triggerTab2 ORDER BY c1; +GO + +-- tsql +DROP PROCEDURE tsql_interop_proc; +GO + +CREATE PROCEDURE tsql_interop_proc +AS +BEGIN TRANSACTION; +INSERT INTO triggerTab1 VALUES(2, 'second'); +SAVE TRANSACTION sp1; +INSERT INTO triggerTab1 VALUES(3, 'third'); +ROLLBACK TRANSACTION sp1; +COMMIT; +GO + +-- tsql +EXEC tsql_interop_proc +GO +SELECT * FROM triggerTab1 ORDER BY c1; +GO + +-- psql currentSchema=master_dbo,public +CALL tsql_interop_proc(); +GO +SELECT * FROM triggerTab2 ORDER BY c1; +GO + +-- tsql +DROP TRIGGER txnTrig1; +GO +DROP TRIGGER txnTrig2; +GO +DROP TABLE triggerTab1; +GO +DROP TABLE triggerTab2; +GO +CREATE PROCEDURE tsql_create_table +AS + CREATE TABLE triggerTab1(c1 int, c2 varchar(30)); + CREATE TABLE triggerTab2(c1 int); + INSERT INTO triggerTab1 VALUES(1, 'first'); + INSERT INTO triggerTab2 VALUES(1); +GO +EXEC tsql_create_table; +GO + +-- psql currentSchema=master_dbo,public +CREATE FUNCTION trigger_txnTrig3() + RETURNS TRIGGER + LANGUAGE PLPGSQL +AS $$ +BEGIN + UPDATE triggerTab1 set c1 = c1/2; + DELETE FROM triggerTab2; + RETURN NEW; +END; +$$ +GO + +CREATE TRIGGER txnTrig3 +AFTER DELETE ON triggerTab1 +FOR EACH ROW +EXECUTE PROCEDURE trigger_txnTrig3(); +GO + +-- tsql +CREATE TRIGGER txnTrig1 ON triggerTab1 AFTER INSERT AS +INSERT INTO triggerTab2 VALUES(4); +UPDATE triggerTab2 set c1 = c1+2; +GO + +CREATE TRIGGER txnTrig2 ON triggerTab2 FOR UPDATE AS +INSERT INTO triggerTab2 VALUES(2); +UPDATE triggerTab1 set c1 = c1+2; +DELETE FROM triggerTab2; +INSERT INTO triggerTab2 values(2); +GO + +-- psql currentSchema=master_dbo,public +CALL psql_interop_proc2(); +GO +SELECT * FROM triggerTab1 ORDER BY c1; +GO + +-- tsql +BEGIN TRANSACTION +GO +EXEC psql_interop_proc2; +GO +SELECT * FROM triggerTab2 ORDER BY c1; +GO +COMMIT +GO + +-- tsql +DROP TRIGGER txnTrig1; +GO +DROP TRIGGER txnTrig2; +GO +DROP TRIGGER txnTrig3; +GO +DROP FUNCTION trigger_txnTrig3; +GO + +-- tsql +CREATE TRIGGER txnTrig1 ON triggerTab1 AFTER INSERT AS +SELECT * FROM inserted; +UPDATE triggerTab2 set c1 = c1+2; +COMMIT; +GO + +CREATE TRIGGER txnTrig2 ON triggerTab2 FOR UPDATE AS +INSERT INTO triggerTab2 VALUES(2); +SELECT * FROM deleted; +DELETE FROM triggerTab1; +GO + +DROP PROCEDURE tsql_interop_proc +GO +CREATE PROCEDURE tsql_interop_proc +AS +BEGIN TRANSACTION; +INSERT INTO triggerTab1 VALUES(3, 'third'); +GO + +-- tsql +EXEC tsql_interop_proc +GO +SELECT * from triggerTab1 ORDER BY c1; +GO + +-- psql currentSchema=master_dbo,public +CALL tsql_interop_proc(); +GO +SELECT * from triggerTab1 ORDER BY c1; +GO + +-- tsql +DROP TRIGGER txnTrig1; +GO +CREATE TRIGGER txnTrig1 ON triggerTab1 AFTER INSERT AS +BEGIN TRANSACTION; +UPDATE triggerTab2 set c1 = c1+2; +COMMIT; +GO + +DROP PROCEDURE tsql_interop_proc; +GO +CREATE PROCEDURE tsql_interop_proc +AS +INSERT INTO triggerTab1 VALUES(2, 'second'); +GO + +-- tsql +EXEC tsql_interop_proc +GO +SELECT * from triggerTab2 ORDER BY c1; +GO + +-- psql currentSchema=master_dbo,public +CALL tsql_interop_proc(); +GO +SELECT * from triggerTab2 ORDER BY c1; +GO + +-- tsql +DROP TRIGGER txnTrig1; +GO + +CREATE TRIGGER txnTrig1 ON triggerTab1 AFTER INSERT AS +BEGIN TRANSACTION; +SELECT * FROM inserted; +UPDATE triggerTab2 set c1 = c1+2; +GO + +DROP PROCEDURE tsql_interop_proc; +GO +CREATE PROCEDURE tsql_interop_proc +AS +INSERT INTO triggerTab1 VALUES(3, 'third'); +SAVE TRANSACTION sp1; +INSERT INTO triggerTab2 VALUES(3); +ROLLBACK TRANSACTION sp1; +COMMIT; +GO + +-- tsql +EXEC tsql_interop_proc +GO +SELECT * from triggerTab2 ORDER BY c1; +GO + +-- psql currentSchema=master_dbo,public +CALL tsql_interop_proc(); +GO +SELECT * from triggerTab1 ORDER BY c1; +GO + +-- tsql +DROP TRIGGER txnTrig1; +GO + +CREATE TRIGGER txnTrig1 ON triggerTab1 AFTER INSERT AS +SAVE TRANSACTION sp1; +SELECT * FROM inserted; +UPDATE triggerTab2 set c1 = c1+2; +GO + +DROP PROCEDURE tsql_interop_proc; +GO +CREATE PROCEDURE tsql_interop_proc +AS +BEGIN TRANSACTION; +INSERT INTO triggerTab1 VALUES(3, 'third'); +INSERT INTO triggerTab2 VALUES(3); +ROLLBACK TRANSACTION sp1; +COMMIT; +GO + +-- tsql +EXEC tsql_interop_proc +GO +SELECT * from triggerTab2 ORDER BY c1; +GO + +-- psql currentSchema=master_dbo,public +CALL tsql_interop_proc(); +GO +SELECT * from triggerTab1 ORDER BY c1; +GO + +-- tsql +DROP TRIGGER txnTrig1; +GO + +CREATE TRIGGER txnTrig1 ON triggerTab1 AFTER INSERT AS +ROLLBACK TRANSACTION sp1; +UPDATE triggerTab2 set c1 = c1+2; +GO + +DROP PROCEDURE tsql_interop_proc; +GO +CREATE PROCEDURE tsql_interop_proc +AS +BEGIN TRANSACTION; +SAVE TRANSACTION sp1; +INSERT INTO triggerTab1 VALUES(3, 'third'); +INSERT INTO triggerTab2 VALUES(3); +COMMIT; +GO + +-- tsql +EXEC tsql_interop_proc +GO +SELECT * from triggerTab2 ORDER BY c1; +GO + +-- psql currentSchema=master_dbo,public +CALL tsql_interop_proc(); +GO +SELECT * from triggerTab1 ORDER BY c1; +GO + +-- tsql +DROP TRIGGER txnTrig1; +GO + +CREATE TRIGGER txnTrig1 ON triggerTab1 AFTER INSERT AS +SELECT * FROM inserted; +SAVE TRANSACTION sp1; +UPDATE triggerTab2 set c1 = c1+2; +ROLLBACK TRANSACTION sp1; +GO + +DROP PROCEDURE tsql_interop_proc; +GO +CREATE PROCEDURE tsql_interop_proc +AS +BEGIN TRANSACTION; +INSERT INTO triggerTab1 VALUES(3, 'third'); +INSERT INTO triggerTab2 VALUES(3); +COMMIT; +GO + +-- tsql +EXEC tsql_interop_proc +GO +SELECT * from triggerTab2 ORDER BY c1; +GO + +-- psql currentSchema=master_dbo,public +CALL tsql_interop_proc(); +GO +SELECT * from triggerTab1 ORDER BY c1; +GO + +-- tsql +DROP TRIGGER txnTrig1; +GO + +CREATE TRIGGER txnTrig1 ON triggerTab1 AFTER INSERT AS +SELECT * FROM inserted; +SAVE TRANSACTION sp1; +UPDATE triggerTab2 set c1 = c1+2; +COMMIT; +GO + +DROP PROCEDURE tsql_interop_proc; +GO +CREATE PROCEDURE tsql_interop_proc +AS +BEGIN TRANSACTION; +INSERT INTO triggerTab1 VALUES(3, 'third'); +INSERT INTO triggerTab2 VALUES(3); +GO + +-- tsql +EXEC tsql_interop_proc +GO +SELECT * from triggerTab2 ORDER BY c1; +GO + +-- psql currentSchema=master_dbo,public +CALL tsql_interop_proc(); +GO +SELECT * from triggerTab1 ORDER BY c1; +GO + +-- tsql +DROP TRIGGER txnTrig1; +GO +DROP TRIGGER txnTrig2; +GO + +CREATE TRIGGER txnTrig1 ON triggerTab1 AFTER INSERT AS +SELECT * FROM inserted; +SAVE TRANSACTION sp1; +SELECT dateadd(year, 2, CAST('20060830' AS datetime)); +UPDATE triggerTab2 set c1 = c1+2; +GO + +CREATE TRIGGER txnTrig2 ON triggerTab2 FOR UPDATE AS +SELECT * FROM inserted; +INSERT INTO triggerTab2 VALUES(2); +SELECT * FROM deleted; +EXEC tsql_interop_proc1; +SELECT * FROM table_interop('tsql_interop','psql_interop'); +ROLLBACK TRANSACTION sp1; +DELETE FROM triggerTab1; +GO + +CREATE PROCEDURE tsql_interop_proc1 +AS +SELECT datepart(week, CAST('2007-04-21' AS date)), datepart(weekday, CAST('2007-04-21' AS date)); +GO + +DROP PROCEDURE tsql_interop_proc; +GO +CREATE PROCEDURE tsql_interop_proc +AS +BEGIN TRANSACTION; +INSERT INTO triggerTab1 VALUES(3, 'third'); +INSERT INTO triggerTab2 VALUES(3); +COMMIT; +GO + +CREATE FUNCTION table_interop (@arg1 varchar(5), @arg2 varchar(10)) +RETURNS TABLE AS RETURN +(SELECT @arg1 as a, @arg2 as b) +GO + +-- tsql +EXEC tsql_interop_proc +GO +SELECT * from triggerTab2 ORDER BY c1; +GO +DROP TRIGGER txnTrig1; +GO +DROP TRIGGER txnTrig2; +GO + +-- psql currentSchema=master_dbo,public +DROP PROCEDURE psql_interop_proc1; +GO +DROP PROCEDURE psql_interop_proc2; +GO + +-- tsql +DROP FUNCTION table_interop; +GO +DROP PROCEDURE tsql_create_table; +GO +DROP PROCEDURE tsql_interop_proc; +GO +DROP PROCEDURE tsql_interop_proc1; +GO +DROP TABLE triggerTab1; +GO +DROP TABLE triggerTab2; +GO diff --git a/contrib/test/JDBC/input/pg_stat_activity.txt b/contrib/test/JDBC/input/pg_stat_activity.txt new file mode 100644 index 00000000000..2a3fc913247 --- /dev/null +++ b/contrib/test/JDBC/input/pg_stat_activity.txt @@ -0,0 +1,17 @@ +SELECT sys.babelfish_set_role(session_user); + +# Babel-1294 Support application_name in pg_stat_activity +select application_name from pg_stat_activity where pid = pg_backend_pid(); + +# BABEL-1326: Support query in pg_stat_activity +select query from pg_stat_activity where pid = pg_backend_pid(); + +# BABEL-1326: Checking if the right query is returned for Prepexec with batch too +prepst#!#select query from pg_stat_activity where pid = pg_backend_pid();select @a as a#!#int|-|a|-|1 +prepst#!#exec#!#int|-|a|-|1 + +# BABEL-1326: Checking if the right query is returned from a procedure and a nested procedure as well +Create procedure proc_pg_stat_activity as begin select query from pg_stat_activity where pid = pg_backend_pid(); end; +exec proc_pg_stat_activity; +Create procedure proc1_pg_stat_activity as begin exec proc_pg_stat_activity end; +exec proc1_pg_stat_activity; diff --git a/contrib/test/JDBC/input/sqlBatch/TestSQLQueries.txt b/contrib/test/JDBC/input/sqlBatch/TestSQLQueries.txt new file mode 100644 index 00000000000..8b7e65c1fc8 --- /dev/null +++ b/contrib/test/JDBC/input/sqlBatch/TestSQLQueries.txt @@ -0,0 +1,234 @@ +#1 CREATE TABLE with primary and unique keyword +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_unique_constraint', 'ignore'; +CREATE TABLE tmp(a int PRIMARY KEY, b int UNIQUE); +INSERT INTO tmp(a,b) values(1,1); +INSERT INTO tmp(a,b) values(2,2); +SELECT * FROM tmp; +DROP TABLE tmp; + +#2 2 table with foreign key relation +#CREATE TABLE tmp1(b int PRIMARY KEY); +#CREATE TABLE tmp2(a int PRIMARY KEY, b int FOREIGN KEY REFERENCES tmp1(b)); +#INSERT INTO tmp1(b) VALUES (1); +#INSERT INTO tmp2(a,b) values(1,1); +#SELECT * FROM tmp1; +#SELECT * FROM tmp2; +#DROP TABLE tmp2; +#DROP TABLE tmp1; + +#3 Repeated #2 with CONSTRAINT keyword +#CREATE TABLE tmp1(b int PRIMARY KEY); +#CREATE TABLE tmp2(a int, b int, PRIMARY KEY(a), CONSTRAINT FK_tmp FOREIGN KEY (b) REFERENCES tmp1(b)); +#INSERT INTO tmp1(b) VALUES (1); +#INSERT INTO tmp2(a,b) values(1,1); +#SELECT * FROM tmp1; +#SELECT * FROM tmp2; +#DROP TABLE tmp2; +#DROP TABLE tmp1; + +#4 CREATE TABLE with NOT NULL column +CREATE TABLE tmp(a int PRIMARY KEY,b int NOT NULL); +INSERT INTO tmp(a,b) values(1,1); +INSERT INTO tmp(a,b) values(2,1); +#INSERT INTO tmp(a,b) values(2,NULL); +SELECT * FROM tmp; +DROP TABLE tmp; + +#5 INSERTION and DELETION +CREATE TABLE tmp(a int PRIMARY KEY); +INSERT INTO tmp(a) VALUES(1); +INSERT INTO tmp(a) VALUES(2); +INSERT INTO tmp(a) VALUES(3); +INSERT INTO tmp(a) VALUES(4); +INSERT INTO tmp(a) VALUES(5); +SELECT * FROM tmp; +DELETE FROM tmp WHERE a>2; +SELECT * FROM tmp; +DROP TABLE tmp; + +#6 IS NOT NULL condition in WHERE clause +CREATE TABLE tmp(a int PRIMARY KEY,b int); +INSERT INTO tmp(a,b) values(1,1); +INSERT INTO tmp(a,b) values(2,1); +INSERT INTO tmp(a,b) values(3,NULL); +INSERT INTO tmp(a,b) values(4,NULL); +SELECT * FROM tmp WHERE b IS NOT NULL; +DROP TABLE tmp; + +#7 Add new column using ALTER TABLE +CREATE TABLE tmp(a int PRIMARY KEY); +INSERT INTO tmp(a) VALUES(1); +INSERT INTO tmp(a) VALUES(2); +SELECT * FROM tmp; +ALTER TABLE tmp ADD b VARCHAR(20) NULL; +SELECT * FROM tmp; +INSERT INTO tmp(a,b) VALUES(4,'Dipesh'); +INSERT INTO tmp(a,b) VALUES(5,' Dipesh'); +SELECT * FROM tmp; +DROP TABLE tmp; + +#8 Repeated #8 with default value for newly added col +CREATE TABLE tmp(a int PRIMARY KEY); +INSERT INTO tmp(a) VALUES(1); +INSERT INTO tmp(a) VALUES(2); +SELECT * FROM tmp; +ALTER TABLE tmp ADD b VARCHAR(20) DEFAULT 'Dipesj'; +SELECT * FROM tmp; +INSERT INTO tmp(a,b) VALUES(4,'Dipesh'); +INSERT INTO tmp(a,b) VALUES(5,' Dipesh'); +SELECT * FROM tmp; +DROP TABLE tmp; + +#9 Change datatype of existing column using ALTER TABLE +CREATE TABLE tmp(a int PRIMARY KEY,b int); +INSERT INTO tmp(a,b) VALUES(1,1); +INSERT INTO tmp(a,b) VALUES(2,2); +SELECT * FROM tmp; +ALTER TABLE tmp ALTER COLUMN b VARCHAR(10); +SELECT * FROM tmp; +INSERT INTO tmp(a,b) VALUES(4,'Dipesh'); +INSERT INTO tmp(a,b) VALUES(5,' Dipesh'); +SELECT * FROM tmp; +DROP TABLE tmp; + +#10 UPDATE TABLE with fancy condition +CREATE TABLE tmp(a int PRIMARY KEY,b int); +INSERT INTO tmp(a,b) VALUES(1,1); +INSERT INTO tmp(a,b) VALUES(2,2); +INSERT INTO tmp(a,b) VALUES(3,3); +INSERT INTO tmp(a,b) VALUES(4,4); +INSERT INTO tmp(a,b) VALUES(5,5); +SELECT * FROM tmp; +UPDATE tmp SET b=b+1 WHERE b>2; +SELECT * FROM tmp; +DROP TABLE tmp; + +#11 DROP some column using ALTER TABLE +CREATE TABLE tmp(a int PRIMARY KEY,b int); +INSERT INTO tmp(a,b) VALUES(1,1); +INSERT INTO tmp(a,b) VALUES(2,2); +INSERT INTO tmp(a,b) VALUES(3,3); +INSERT INTO tmp(a,b) VALUES(4,4); +INSERT INTO tmp(a,b) VALUES(5,5); +SELECT * FROM tmp; +#ALTER TABLE tmp DROP COLUMN b; +#INSERT INTO tmp(a) values (6); +#SELECT * FROM tmp; +DROP TABLE tmp; + +#12 CREATE TABLE with fancy constraint +CREATE TABLE tmp(a int PRIMARY KEY CHECK (a>10),b int); +INSERT INTO tmp(a,b) VALUES(11,1); +INSERT INTO tmp(a,b) VALUES(12,2); +INSERT INTO tmp(a,b) VALUES(13,3); +INSERT INTO tmp(a,b) VALUES(14,4); +INSERT INTO tmp(a,b) VALUES(15,5); +SELECT * FROM tmp; +DROP TABLE tmp; + +#CREATE PROCEDURE tmp AS +#BEGIN +# CREATE TABLE dip(a int PRIMARY KEY CHECK (a>10),b int); +# INSERT INTO dip(a,b) VALUES(11,1); +# INSERT INTO dip(a,b) VALUES(12,2); +# INSERT INTO dip(a,b) VALUES(13,3); +# INSERT INTO dip(a,b) VALUES(14,4); +# INSERT INTO dip(a,b) VALUES(15,5); +# SELECT * FROM dip; +# DROP TABLE dip; +#END; + +#13 invoke simple stored procedure using EXECUTE +EXECUTE tmp; + +#14 invoke simple stored procedure using EXEC +EXEC tmp; + +#DROP PROCEDURE tmp; + +#15 UPDATE rows in existing table +CREATE TABLE tmp(a int PRIMARY KEY,b int); +INSERT INTO tmp(a,b) VALUES(1,1),(2,2),(3,3),(4,4),(5,5); +SELECT * FROM tmp; +UPDATE tmp SET b=b*2+1 WHERE (a>2); +SELECT * FROM tmp; +DROP TABLE tmp; + +#16 TRUNCATE table +CREATE TABLE tmp(a int PRIMARY KEY,b int); +INSERT INTO tmp(a,b) VALUES(1,1),(2,2),(3,3),(4,4),(5,5); +SELECT * FROM tmp; +TRUNCATE TABLE tmp; +SELECT * FROM tmp; +DROP TABLE tmp; + +CREATE TABLE temp1 (i INT,j INT,t TEXT); + +CREATE TABLE temp2 ( i INT,k INT); + +INSERT INTO temp1 VALUES (1, 4, 'one'); +INSERT INTO temp1 VALUES (2, 3, 'two'); +INSERT INTO temp1 VALUES (3, 2, 'three'); +INSERT INTO temp1 VALUES (4, 1, 'four'); +INSERT INTO temp1 VALUES (5, 0, 'five'); +INSERT INTO temp1 VALUES (6, 6, 'six'); +INSERT INTO temp1 VALUES (7, 7, 'seven'); +INSERT INTO temp1 VALUES (8, 8, 'eight'); +INSERT INTO temp1 VALUES (0, NULL, 'zero'); +INSERT INTO temp1 VALUES (NULL, NULL, NULL); +INSERT INTO temp1 VALUES (NULL, 0, 'zero'); + +INSERT INTO temp2 VALUES (1, -1); +INSERT INTO temp2 VALUES (2, 2); +INSERT INTO temp2 VALUES (3, -3); +INSERT INTO temp2 VALUES (2, 4); +INSERT INTO temp2 VALUES (5, -5); +INSERT INTO temp2 VALUES (5, -5); +INSERT INTO temp2 VALUES (0, NULL); +INSERT INTO temp2 VALUES (NULL, NULL); +INSERT INTO temp2 VALUES (NULL, 0); + +#17 CROSS JOIN +SELECT * FROM temp1 CROSS JOIN temp2; + +#18 INNER JOIN +SELECT temp1.i, temp1.j, temp1.t, temp2.k FROM temp1 INNER JOIN temp2 ON temp1.i=temp2.i; +SELECT temp1.i, temp1.j, temp1.t, temp2.k FROM temp1 JOIN temp2 ON temp1.i=temp2.i; + +#19 LEFT JOIN +SELECT * FROM temp1 LEFT OUTER JOIN temp2 ON temp1.i=temp2.k; + +#20 RIGHT JOIN +SELECT * FROM temp1 RIGHT OUTER JOIN temp2 ON temp1.i=temp2.i; + +#21 FULL OUTER JOIN +SELECT * FROM temp1,temp2; + +DROP TABLE temp1; +DROP TABLE temp2; + +#22 dropping all columns +CREATE TABLE tmp(a int PRIMARY KEY,b int); +INSERT INTO tmp(a,b) VALUES(1,1); +INSERT INTO tmp(a,b) VALUES(2,2); +INSERT INTO tmp(a,b) VALUES(3,3); +INSERT INTO tmp(a,b) VALUES(4,4); +INSERT INTO tmp(a,b) VALUES(5,5); +SELECT * FROM tmp; +#ALTER TABLE tmp DROP COLUMN b; +#ALTER TABLE tmp DROP COLUMN a; +#SELECT * FROM tmp; +DROP TABLE tmp; + +#23 +CREATE TABLE DATE_dt (a DATE); +INSERT INTO DATE_dt(a) values('2000-12-13'); +INSERT INTO DATE_dt(a) values('1900-02-28'); +INSERT INTO DATE_dt(a) values('0001-01-01'); +INSERT INTO DATE_dt(a) values('9999-12-31'); +INSERT INTO DATE_dt(a) values(NULL); +SELECT * FROM DATE_dt; +ALTER TABLE DATE_dt ALTER COLUMN a DATETIME; +SELECT * FROM DATE_dt; +DROP TABLE DATE_dt; +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_unique_constraint', 'strict'; diff --git a/contrib/test/JDBC/input/storedProcedures/BABEL-1365.sql b/contrib/test/JDBC/input/storedProcedures/BABEL-1365.sql new file mode 100644 index 00000000000..832608d3f4a --- /dev/null +++ b/contrib/test/JDBC/input/storedProcedures/BABEL-1365.sql @@ -0,0 +1,23 @@ +-- Test normal case: @v = SP_EXECUTESQL 'SQL' +DECLARE @SQLString NVARCHAR(100); +DECLARE @P0 int; +set @SQLString = N'SELECT 123;' +EXEC @P0 = sp_executesql @SQLString; +SELECT @P0; +go + +-- Test case: @v = SP_EXECUTESQL 'SQL' where @v is implicitly casted to varchar +DECLARE @SQLString NVARCHAR(100); +DECLARE @P0 varchar(3); +set @SQLString = N'SELECT 321;' +EXEC @P0 = sp_executesql @SQLString; +SELECT @P0; +go + +-- Test case: @v = SP_EXECUTESQL 'SQL' where 'SQL' statement does not return result set +DECLARE @SQLString NVARCHAR(100); +DECLARE @P0 int; +set @SQLString = N'CREATE TABLE t(a INT); DROP TABLE t;'; +EXEC @P0 = sp_executesql @SQLString; +SELECT @P0; +go \ No newline at end of file diff --git a/contrib/test/JDBC/input/storedProcedures/TestPrepareExec.txt b/contrib/test/JDBC/input/storedProcedures/TestPrepareExec.txt new file mode 100644 index 00000000000..ba229a4434a --- /dev/null +++ b/contrib/test/JDBC/input/storedProcedures/TestPrepareExec.txt @@ -0,0 +1,15 @@ +#single parameter bind in target list +prepst#!#SELECT @a#!#INT|-|a|-|1 +prepst#!#exec#!#INT|-|a|-|1 +prepst#!#exec#!#INT|-|a|-|1 +prepst#!#exec#!#INT|-|a|-|1 +#no parameter bind +prepst#!#SELECT 1#!# +prepst#!#exec#!# +prepst#!#exec#!# +prepst#!#exec#!# +#empty query +prepst#!# #!# +prepst#!#exec#!# +prepst#!#exec#!# +prepst#!#exec#!# diff --git a/contrib/test/JDBC/input/storedProcedures/TestSPExecutesql.sql b/contrib/test/JDBC/input/storedProcedures/TestSPExecutesql.sql new file mode 100644 index 00000000000..fb71ce869a4 --- /dev/null +++ b/contrib/test/JDBC/input/storedProcedures/TestSPExecutesql.sql @@ -0,0 +1,194 @@ +CREATE TABLE spExecutesqlTable1 (a INT, b VARCHAR(10)); +CREATE TABLE spExecutesqlTable2 (a INT, b INT, c INT, d INT); +go + +/* 1. Execute a string of statement */ +DECLARE @SQLString NVARCHAR(100); +SET @SQLString = N'SELECT N''hello world'';'; +EXEC sp_executesql @SQLString; +go + +/* 2. Execute a statement string with parameters */ +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'INSERT INTO spExecutesqlTable1 VALUES (@a, @b);'; +SET @ParamDef = N'@a INT, @b VARCHAR(10)'; + +DECLARE @p INT = 1; +EXEC sp_executesql @SQLString, @ParamDef, @p, @b = N'hello'; +SELECT * FROM spExecutesqlTable1; +go + +TRUNCATE TABLE spExecutesqlTable1; +go + +/* 3. Execute a statement string with both unnamed params and named params */ +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'INSERT INTO spExecutesqlTable2 VALUES (@a, @b, @c, @d);'; +SET @ParamDef = N'@a INT, @b INT, @c INT, @d INT'; + +EXEC sp_executesql @SQLString, @ParamDef, 1, 2, @d = 4, @c = 3; +SELECT * FROM spExecutesqlTable2; +go + +TRUNCATE TABLE spExecutesqlTable2; +go + +/* 4. Nested sp_executesql */ +DECLARE @SQLString1 NVARCHAR(100); +DECLARE @SQLString2 NVARCHAR(max); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString1 = N'INSERT INTO spExecutesqlTable1 VALUES (@a, @b);' +SET @SQLString2 = @SQLString1 + N'EXEC sp_executesql N''INSERT INTO spExecutesqlTable1 VALUES (@c + @c, @d + @d);'', N''@c INT, @d VARCHAR(10)'', @a, @b;' +SET @ParamDef = N'@a INT, @b VARCHAR(10)'; +EXEC sp_executesql @SQLString2, @ParamDef, @a = 10, @b = N'str'; +SELECT * FROM spExecutesqlTable1; +go + +TRUNCATE TABLE spExecutesqlTable1; +go + +-- Nested with param name collision +DECLARE @SQLString1 NVARCHAR(100); +DECLARE @SQLString2 NVARCHAR(max); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString1 = N'INSERT INTO spExecutesqlTable1 VALUES (@a, @b);' +SET @SQLString2 = @SQLString1 + N'EXEC sp_executesql N''INSERT INTO spExecutesqlTable1 VALUES (@a + @a, @b + @b);'', N''@a INT, @b VARCHAR(10)'', @a, @b;' +SET @ParamDef = N'@a INT, @b VARCHAR(10)'; +EXEC sp_executesql @SQLString2, @ParamDef, @a = 11, @b = N'rts'; +SELECT * FROM spExecutesqlTable1; +go + +TRUNCATE TABLE spExecutesqlTable1; +go + +/* 5. Execute a statement string with OUT/INOUT param */ +DECLARE @SQLString1 NVARCHAR(100); +DECLARE @SQLString2 NVARCHAR(max); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString1 = N'SET @a = @b + @b'; +SET @SQLString2 = N'EXEC sp_executesql N''SET @a = @b + @b'', N''@a INT OUT, @b INT'', @a OUT, @b;'; +SET @ParamDef = N'@a INT OUTPUT, @b INT'; + +DECLARE @p INT; +DECLARE @a INT; +-- OUT param +EXEC sp_executesql @SQLString1, @ParamDef, @a = @p OUT, @b = 10; +-- Nested with OUT param name collision +EXEC sp_executesql @SQLString2, @ParamDef, @a = @a OUT, @b = 11; +SELECT @p, @a; +go + +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'SET @a = @a + 1;'; +SET @ParamDef = N'@a INT OUT'; + +DECLARE @p1 INT = 1; +DECLARE @p2 INT = 1; +-- Declared as INOUT and called as OUT +EXEC sp_executesql @SQLString, @ParamDef, @a = @p1 OUT; +-- Declared as INOUT and called as IN +EXEC sp_executesql @SQLString, @ParamDef, @a = @p2; +SELECT @p1, @p2; +go + +/* 6. Implicit cast for IN param */ +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'SET @b = @a;'; +SET @ParamDef = N'@a FLOAT, @b FLOAT OUT'; + +DECLARE @p FLOAT; +DECLARE @a MONEY = 3.14; +EXEC sp_executesql @SQLString, @ParamDef, @a = @a, @b = @p OUTPUT; +SELECT @p; +go + +/* 7. Implicit cast for OUT param */ +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'SET @a = CAST(''2020-01-01'' AS DATE); SET @b = @a;'; +SET @ParamDef = N'@a DATE OUT, @b DATETIME OUT'; + +DECLARE @p1 DATETIME; +DECLARE @p2 DATETIME; +EXEC sp_executesql @SQLString, @ParamDef, @a = @p1 OUT, @b = @p2 OUT; +SELECT @p1, @p2; +go + +/* Exceptions */ +/* 1. Wrong order of named/unnamed params */ +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'INSERT INTO spExecutesqlTable2 VALUES (@a, @b, @c, @d);'; +SET @ParamDef = N'@a INT, @b INT, @c INT, @d INT'; +EXEC sp_executesql @SQLString, @ParamDef, @b = 2, @c = 3, 1, @d = 4; +go + +/* 2. Number mismatch of param defs and given params */ +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'INSERT INTO spExecutesqlTable2 VALUES (@a, @b, @c, @d);'; +SET @ParamDef = N'@a INT, @b INT, @c INT, @d INT'; +EXEC sp_executesql @SQLString, @ParamDef, 1, 2, 3; +go + +/* 3. Invalid param name */ +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'INSERT INTO spExecutesqlTable2 VALUES (@a, @b, @c, @d);'; +SET @ParamDef = N'@a INT, @b INT, @c INT, @d INT'; +EXEC sp_executesql @SQLString, @ParamDef, @a = 1, @b = 2, @c = 3, @e = 4; +go + +/* 4. Invalid param def */ +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'INSERT INTO spExecutesqlTable2 VALUES (@a, @b, @c, @d);'; +SET @ParamDef = N'@a INT, @b INT, @c, @d INT'; +EXEC sp_executesql @SQLString, @ParamDef, 1, 2, 3, 4; +go + +/* 5. Unsupported implicit cast */ +-- IN param +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'INSERT INTO spExecutesqlTable2 VALUES (@a, @b, @c, @d);'; +SET @ParamDef = N'@a INT, @b INT, @c INT, @d INT'; +EXEC sp_executesql @SQLString, @ParamDef, 1, 3.14, 'hello', 4; +go + +-- OUT param +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'SET @a = CAST(''abc'' AS VARCHAR(3));'; +SET @ParamDef = N'@a FLOAT OUT'; + +DECLARE @p FLOAT; +EXEC sp_executesql @SQLString, @ParamDef, @a = @p OUT; +go + +/* 6. Invalid OUT param */ +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'SET @a = 20'; +SET @ParamDef = N'@a INT OUT'; +EXEC sp_executesql @SQLString, @ParamDef, @a = 10 OUT; +go + +/* 7. Param declared as IN but called as OUT */ +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'SET @a = 20'; +SET @ParamDef = N'@a INT'; + +DECLARE @p INT; +EXEC sp_executesql @SQLString, @ParamDef, @a = @p OUT; +go + +/* Clean up */ +DROP TABLE spExecutesqlTable1; +DROP TABLE spExecutesqlTable2; +go diff --git a/contrib/test/JDBC/input/storedProcedures/TestSPPrepare.sql b/contrib/test/JDBC/input/storedProcedures/TestSPPrepare.sql new file mode 100644 index 00000000000..a0f20968e5f --- /dev/null +++ b/contrib/test/JDBC/input/storedProcedures/TestSPPrepare.sql @@ -0,0 +1,357 @@ +--- Simple SP_PREPARE +DECLARE @handle int; +EXEC SP_PREPARE @handle OUT, NULL, 'SELECT ''OK''' +EXEC SP_EXECUTE @handle +EXEC SP_EXECUTE @handle +EXEC SP_EXECUTE @handle +EXEC SP_UNPREPARE @handle +GO + +--- Simple SP_PREPEXEC +DECLARE @handle int; +EXEC SP_PREPEXEC @handle OUT, NULL, 'SELECT ''OK''' +EXEC SP_EXECUTE @handle +EXEC SP_EXECUTE @handle +EXEC SP_EXECUTE @handle +EXEC SP_UNPREPARE @handle +GO + +--- Basic SP_PREPARE with args +DECLARE @handle int; +EXEC SP_PREPARE @handle out, N'@a int, @b int', N'select @a, @b', 10; +EXEC SP_EXECUTE @handle, 1, 2 +EXEC SP_EXECUTE @handle, 1, 2 +EXEC SP_EXECUTE @handle, 1, 2 +EXEC SP_UNPREPARE @handle; +GO + +--- Basic SP_PREPARE with args +DECLARE @handle int; +EXEC SP_PREPEXEC @handle out, N'@a int, @b int', N'select @a, @b', 1, 2; +EXEC SP_EXECUTE @handle, 1, 2 +EXEC SP_EXECUTE @handle, 1, 2 +EXEC SP_EXECUTE @handle, 1, 2 +EXEC SP_UNPREPARE @handle; +GO + +--- SP_PREPARE Batch Support +DECLARE @handle int; +DECLARE @batch nvarchar(500); +DECLARE @paramdef nvarchar(500); +DECLARE @var int; +SET @batch = 'IF (@cond > 0) SELECT @o = @a ELSE SELECT @o = @b' +SET @paramdef = '@cond int, @a int, @b int, @o int OUTPUT' +EXEC SP_PREPARE @handle OUT, @paramdef, @batch +EXEC SP_EXECUTE @handle, -1, 10, 20, @var OUTPUT +SELECT @var +EXEC SP_EXECUTE @handle, 1, 10, 20, @var OUTPUT +SELECT @var +EXEC SP_UNPREPARE @handle; +GO + +--- SP_PREPEXEC Batch Support +DECLARE @handle int; +DECLARE @batch nvarchar(500); +DECLARE @paramdef nvarchar(500); +DECLARE @var int; +SET @batch = 'IF (@cond > 0) SELECT @o = @a ELSE SELECT @o = @b' +SET @paramdef = '@cond int, @a int, @b int, @o int OUTPUT' +EXEC SP_PREPEXEC @handle out, @paramdef, @batch, 1, 30, 40, @var OUTPUT +SELECT @var +EXEC SP_EXECUTE @handle, -1, 10, 20, @var OUTPUT +SELECT @var +EXEC SP_EXECUTE @handle, 1, 10, 20, @var OUTPUT +SELECT @var +EXEC SP_UNPREPARE @handle; +GO + +--- Parsing specific +DECLARE @handle int; +EXEC SP_PREPEXEC @handle + 1 OUTPUT, NULL, 'SELECT 1' +GO + +DECLARE @handle VARCHAR(20) +EXEC SP_PREPEXEC @handle OUTPUT, NULL, 'SELECT 1' +GO + +DECLARE @handle int; +EXEC SP_PREPEXEC @handle, NULL, 'SELECT 1' +GO + +--- Corner case 1: empty batch +DECLARE @handle int; +EXEC SP_PREPARE @handle out, NULL, NULL +EXEC SP_EXECUTE @handle +EXEC SP_UNPREPARE @handle +GO + +DECLARE @handle int; +EXEC SP_PREPEXEC @handle out, NULL, NULL +EXEC SP_EXECUTE @handle +EXEC SP_UNPREPARE @handle +GO + +--- Corner case 2: nested prepare +DECLARE @handle int; +DECLARE @inner_handle int; +DECLARE @batch VARCHAR(500); +SET @batch = 'EXEC SP_PREPARE @inner_handle OUT, NULL, ''SELECT 1'' ' +EXEC SP_PREPARE @handle out, '@inner_handle int OUT', @batch +EXEC SP_EXECUTE @handle, @inner_handle OUT +EXEC SP_EXECUTE @inner_handle +EXEC SP_UNPREPARE @inner_handle -- unprepare inner first +EXEC SP_UNPREPARE @handle +GO + +DECLARE @handle int; +DECLARE @inner_handle int; +DECLARE @batch VARCHAR(500); +SET @batch = 'EXEC SP_PREPARE @inner_handle OUT, NULL, ''SELECT 1'' ' +EXEC SP_PREPARE @handle out, '@inner_handle int OUT', @batch +EXEC SP_EXECUTE @handle, @inner_handle OUT +EXEC SP_EXECUTE @inner_handle +EXEC SP_UNPREPARE @handle --unprepare outer first +EXEC SP_EXECUTE @inner_handle +EXEC SP_UNPREPARE @inner_handle +GO + +--- Corner case 3: mismatch paramdef and params +DECLARE @handle int; +DECLARE @var int; +DECLARE @batch VARCHAR(500); +DECLARE @paramdef VARCHAR(500); +SET @batch = 'SELECT @a'; +SET @paramdef = '@a int'; +EXEC SP_PREPARE @handle OUT, @paramdef, @batch +EXEC SP_EXECUTE @handle, 100 +EXEC SP_EXECUTE @handle, @var OUT +EXEC SP_UNPREPARE @handle +GO + +--- Prepare DML statement +CREATE TABLE t1 (a int, b int); +GO + +DECLARE @handle int; +DECLARE @batch VARCHAR(500); +DECLARE @paramdef VARCHAR(500); +SET @batch = ' +INSERT INTO t1 VALUES (@v1, @v2) +INSERT INTO t1 VALUES (@v3, @v4) +' +SET @paramdef = '@v1 int, @v2 int, @v3 int, @v4 int' +EXEC SP_PREPARE @handle OUT, @paramdef, @batch +EXEC SP_EXECUTE @handle, 1, 2, 2, 3 +EXEC SP_EXECUTE @handle, 3, 4, 4, 5 +SELECT * FROM t1 ORDER BY 1, 2; +GO + +DECLARE @handle int; +DECLARE @batch VARCHAR(500); +DECLARE @paramdef VARCHAR(500); +SET @batch = ' +UPDATE t1 SET a = a * 10, b = b *10 where a = @var1; +UPDATE t1 SET a = a * 10, b = b *10 where a = @var2; +' +SET @paramdef = '@var1 int, @var2 int' +EXEC SP_PREPARE @handle OUT, @paramdef, @batch +EXEC SP_EXECUTE @handle, 1, 2 +EXEC SP_EXECUTE @handle, 3, 4 +SELECT * FROM t1 ORDER BY 1, 2; + +EXEC SP_UNPREPARE @handle +DROP TABLE t1; +GO + +--- Transaction with SP_EXECUTE +CREATE TABLE t1 (a int, b int); +GO + +DECLARE @handle int; +DECLARE @batch VARCHAR(500); +DECLARE @paramdef VARCHAR(500); +SET @batch = ' +INSERT INTO t1 VALUES (@v1, @v2); +INSERT INTO t1 VALUES (@v3, @v4); +' +SET @paramdef = '@v1 int, @v2 int, @v3 int, @v4 int' + +EXEC SP_PREPARE @handle OUT, @paramdef, @batch + +BEGIN TRANSACTION; +EXEC SP_EXECUTE @handle, 1, 2, 2, 3 +SELECT * FROM t1 ORDER BY 1, 2; +COMMIT; +SELECT * FROM t1 ORDER BY 1, 2; + +BEGIN TRANSACTION; +EXEC SP_EXECUTE @handle, 3, 4, 4, 5 +SELECT * FROM t1 ORDER BY 1, 2; +ROLLBACK; +SELECT * FROM t1 ORDER BY 1, 2; + +EXEC SP_UNPREPARE @handle +GO + +DROP TABLE t1; +GO + +--- PREPARE Batch with Transaction +CREATE TABLE t1 (a int, b int); +GO + +DECLARE @handle int; +DECLARE @batch VARCHAR(500); +DECLARE @paramdef VARCHAR(500); +SET @batch = ' +BEGIN TRANSACTION +INSERT INTO t1 VALUES (@v1, @v2); +INSERT INTO t1 VALUES (@v3, @v4); +SELECT * FROM t1 ORDER BY 1, 2; +IF (@v1 = 10) + COMMIT; +ELSE + ROLLBACK; +' +SET @paramdef = '@v1 int, @v2 int, @v3 int, @v4 int' +EXEC SP_PREPARE @handle OUT, @paramdef, @batch +EXEC SP_EXECUTE @handle, 10, 20, 30, 40 +SELECT * FROM t1 ORDER BY 1, 2; +EXEC SP_EXECUTE @handle, 50, 60, 70, 80 +SELECT * FROM t1 ORDER BY 1, 2; + +EXEC SP_UNPREPARE @handle +GO + +DROP TABLE t1; +GO + +-- Test Save Point +CREATE TABLE t1 ( a int, b int); +GO + +DECLARE @handle int; +DECLARE @batch VARCHAR(500); +SET @batch = ' +DECLARE @handle int; +BEGIN TRANSACTION; +INSERT INTO t1 VALUES (1, 2); +SAVE TRANSACTION my_savept; +EXEC SP_PREPEXEC @handle OUT, NULL, +''INSERT INTO t1 VALUES (3, 4); + SELECT * FROM t1 ORDER BY 1, 2; + ROLLBACK TRANSACTION my_savept; + SELECT * FROM t1 ORDER BY 1, 2; +''; +SELECT * FROM t1 ORDER BY 1, 2; +ROLLBACK; +SELECT * FROM t1 ORDER BY 1, 2; +EXEC SP_UNPREPARE @handle; +' +EXEC SP_PREPARE @handle OUT, NULL, @batch; +PRINT @handle +EXEC SP_EXECUTE @handle; +EXEC SP_UNPREPARE @handle; +GO + +DROP TABLE t1; +GO + +--- Test string type +CREATE TABLE t1 ( a VARCHAR(10), b VARCHAR(10)); +GO + +DECLARE @handle int; +EXEC SP_PREPEXEC @handle OUT, '@v1 VARCHAR(10), @v2 VARCHAR(10)', 'INSERT INTO t1 VALUES (@v1,@v2)', 'abc', 'efg' +EXEC SP_EXECUTE @handle, 'lmn', 'opq' +EXEC SP_UNPREPARE @handle +SELECT * FROM t1 ORDER BY 1, 2; +GO + +DROP TABLE t1; +GO + +-- Test transaction begins outside the batch and commited/rollbacked inside the batch +CREATE TABLE t1 (a INT); +GO + +BEGIN TRAN; +GO +DECLARE @handle INT; +DECLARE @batch VARCHAR(500); +SET @batch = 'insert into t1 values(1); commit; begin tran;' +EXEC sp_prepare @handle OUT, NULL, @batch +EXEC sp_execute @handle +EXEC sp_execute @handle +EXEC SP_UNPREPARE @handle; +COMMIT; +SELECT COUNT(*) FROM t1; +GO + +BEGIN TRAN; +GO +DECLARE @handle INT; +DECLARE @batch VARCHAR(500); +SET @batch = 'insert into t1 values(1); rollback tran; begin tran;' +EXEC sp_prepare @handle OUT, NULL, @batch +EXEC sp_execute @handle +EXEC sp_execute @handle +EXEC SP_UNPREPARE @handle; +COMMIT; +SELECT COUNT(*) FROM t1; +GO + +DROP TABLE t1; +GO + +-- prepare time error 1 +DECLARE @handle int; +EXEC SP_PREPARE @handle OUT, NULL, 'SELECT * FROM t1' +SELECT (case when @handle IS NOT NULL then 'true' else 'false' end) as 'Prepared' +GO + +-- prepare time error 1-2 +DECLARE @handle int; +EXEC SP_PREPARE @handle OUT, NULL, 'DECLARE @var int; SELECT * FROM t1 WHERE c = @var' +SELECT (case when @handle IS NOT NULL then 'true' else 'false' end) as 'Prepared' +GO + +-- prepare time error 2 +DECLARE @handle int; +EXEC SP_PREPARE @handle OUT, NULL, 'EXEC my_proc' +SELECT (case when @handle IS NOT NULL then 'true' else 'false' end) as 'Prepared' +GO + +-- prepare time error 2-2 +DECLARE @handle int; +EXEC SP_PREPARE @handle OUT, NULL, 'DECLARE @var int; EXEC my_proc @var' +SELECT (case when @handle IS NOT NULL then 'true' else 'false' end) as 'Prepared' +GO + +-- runtime error 1 +DECLARE @handle int; +EXEC SP_PREPARE @handle OUT, NULL, 'SELECT * FROM t1; SELECT * FROM t1;' +SELECT (case when @handle IS NOT NULL then 'true' else 'false' end) as 'Prepared' +EXEC SP_EXECUTE @handle +GO + +-- runtime error 2 +DECLARE @handle int; +EXEC SP_PREPARE @handle OUT, NULL, 'EXEC my_proc; EXEC my_proc;' +SELECT (case when @handle IS NOT NULL then 'true' else 'false' end) as 'Prepared' +EXEC SP_EXECUTE @handle +GO + +-- runtime error 3 +DECLARE @handle int; +EXEC SP_PREPARE @handle OUT, NULL, 'IF (1=1) SELECT * FROM t1;' +SELECT (case when @handle IS NOT NULL then 'true' else 'false' end) as 'Prepared' +EXEC SP_EXECUTE @handle +GO + +-- runtime error 4 +DECLARE @handle int; +EXEC SP_PREPARE @handle OUT, NULL, 'DECLARE @var int; SET @var = 1; select * from t1 where c = @var' +SELECT (case when @handle IS NOT NULL then 'true' else 'false' end) as 'Prepared' +EXEC SP_EXECUTE @handle +GO diff --git a/contrib/test/JDBC/input/storedProcedures/TestStoredProcedures.txt b/contrib/test/JDBC/input/storedProcedures/TestStoredProcedures.txt new file mode 100644 index 00000000000..e0eeac847af --- /dev/null +++ b/contrib/test/JDBC/input/storedProcedures/TestStoredProcedures.txt @@ -0,0 +1,140 @@ +# PROCEDURE WITH NO BODY +#create procedure sp_test AS BEGIN END; +# PROCEDURE WITH NO PARAMS +create table temp_sp2(a int); +CREATE PROCEDURE sp_test AS BEGIN insert into temp_sp2 values(1); END; +storedproc#!#prep#!#sp_test#!# +SELECT * FROM temp_sp2; +drop table temp_sp2; +drop Procedure sp_test; +# PROCEDURE WITH INPUT PARAMETER +#drop table temp_sp; +create table temp_sp(a int); +Create Procedure stored_proc1 (@a int) As Begin insert into temp_sp values(@a) End; +# NOT WORKING FOR BABEL,RAISED JIRA 444 +storedproc#!#prep#!#stored_proc1#!#int|-|a|-|-100|-|input +# MISMATCH IN RETURN VALUES +exec stored_proc1 -200 +exec stored_proc1 0 +exec stored_proc1 -1 +exec stored_proc1 2 +# filed Jira on this, doesnt work for babel +#exec stored_proc1 2.2 +SELECT * FROM temp_sp; +DROP table temp_sp; +DROP Procedure stored_proc1 +# input parameter +CREATE PROCEDURE sp_test1 (@a INT) AS BEGIN SET @a=100; Select @a as a; END; +exec sp_test1 2 +Declare @a int;Set @a=1; exec sp_test1 @a;select @a as a; +storedproc#!#prep#!#sp_test1#!#int|-|a|-|1|-|input +storedproc#!#prep#!#sp_test1#!#int|-|a|-|10|-|input +DROP PROCEDURE sp_test1 +# TESTING OUT PARAMETERS FOR ALL THE DATATYPES +# int +CREATE PROCEDURE sp_test1 (@a INT OUTPUT) AS BEGIN SET @a=100; Select @a as a; END; +#Declare @a int;Set @a=1; exec sp_test1 @a;select @a as a; +storedproc#!#prep#!#sp_test1#!#int|-|a|-|1|-|output +storedproc#!#prep#!#sp_test1#!#int|-|a|-|1|-|inputoutput +DROP PROCEDURE sp_test1 +# smallint +CREATE PROCEDURE sp_test2 (@a SMALLINT OUTPUT) AS BEGIN SET @a=100; Select @a as a; END; +#Declare @a smallint;Set @a=1; exec sp_test2 @a;select @a as a; +storedproc#!#prep#!#sp_test2#!#smallint|-|a|-|10|-|output +storedproc#!#prep#!#sp_test2#!#smallint|-|a|-|10|-|inputoutput +DROP PROCEDURE sp_test2 +# bigint +CREATE PROCEDURE sp_test3 (@a BIGINT OUTPUT) AS BEGIN SET @a=100; Select @a as a; END; +storedproc#!#prep#!#sp_test3#!#bigint|-|a|-|10|-|output +storedproc#!#prep#!#sp_test3#!#bigint|-|a|-|10|-|inputoutput +DROP PROCEDURE sp_test3 +# tinyint +#CREATE PROCEDURE sp_test4 (@a tinyint OUTPUT) AS BEGIN SET @a=100; Select @a as a; END; +#storedproc#!#prep#!#sp_test4#!#tinyint|-|a|-|10|-|output +#storedproc#!#prep#!#sp_test4#!#tinyint|-|a|-|10|-|inputoutput +#DROP PROCEDURE sp_test4 +# float +CREATE PROCEDURE sp_test5 (@a float OUTPUT) AS BEGIN SET @a=100.12; Select @a as a; END; +#Declare @a float;Set @a=1.1; exec sp_test5 @a;select @a as a; +storedproc#!#prep#!#sp_test5#!#float|-|a|-|10.1|-|output +storedproc#!#prep#!#sp_test5#!#float|-|a|-|10.1|-|inputoutput +DROP PROCEDURE sp_test5 +# varchar +#CREATE PROCEDURE sp_test6 (@a varchar OUTPUT) AS BEGIN SET @a='helloworld'; Select @a as a; END; +#storedproc#!#prep#!#sp_test6#!#varchar|-|a|-|hello|-|output +#storedproc#!#prep#!#sp_test6#!#varchar|-|a|-|hello|-|inputoutput +#DROP PROCEDURE sp_test6 +# char BABEL-705 +#CREATE PROCEDURE sp_test7 (@a char OUTPUT) AS BEGIN SET @a='b'; Select @a as a; END; +#Declare @a varchar;Set @a='h'; exec sp_test7 @a;select @a as a; +#storedproc#!#prep#!#sp_test7#!#char|-|a|-|t|-|output +#storedproc#!#prep#!#sp_test7#!#char|-|a|-|t|-|inputoutput +#DROP PROCEDURE sp_test7 +# nvarchar +#CREATE PROCEDURE sp_test9 (@a nvarchar OUTPUT) AS BEGIN SET @a='helloworld'; Select @a as a; END; +#Declare @a nvarchar;Set @a='hello'; exec sp_test9 @a;select @a as a; +#storedproc#!#prep#!#sp_test9#!#varchar|-|a|-|hello|-|output +#storedproc#!#prep#!#sp_test9#!#varchar|-|a|-|hello|-|inputoutput +#DROP PROCEDURE sp_test9 +# numeric +CREATE PROCEDURE sp_test10 (@a numeric(10,4) OUTPUT) AS BEGIN SET @a=100.41; Select @a as a; END; +#Declare @a numeric(10,4);Set @a=10.04; exec sp_test10 @a;select @a as a; +#storedproc#!#prep#!#sp_test10#!#numeric|-|a|-|123|-|10|-|3|-|output +#storedproc#!#prep#!#sp_test10#!#numeric|-|a|-|123|-|10|-|2|-|inputoutput +DROP PROCEDURE sp_test10 +# decimal +CREATE PROCEDURE sp_test11 (@a decimal(10,4) OUTPUT) AS BEGIN SET @a=100.41; Select @a as a; END; +#Declare @a decimal(10,4);Set @a=10.04; exec sp_test11 @a;select @a as a; +#storedproc#!#prep#!#sp_test11#!#decimal|-|a|-|123|-|10|-|3|-|output +#storedproc#!#prep#!#sp_test11#!#decimal|-|a|-|123|-|10|-|2|-|inputoutput +DROP PROCEDURE sp_test11 +# binary +#CREATE PROCEDURE sp_test12 (@a binary OUTPUT) AS BEGIN SET @a=0x121; Select @a as a; END; +#exec sp_test12 0x122 +#Declare @a binary;Set @a=0x121; exec sp_test12 @a;select @a as a; +#storedproc#!#prep#!#sp_test12#!#binary|-|a|-|0x122|-|output +#storedproc#!#prep#!#sp_test12#!#binary|-|a|-|0x122|-|inputoutput +#DROP PROCEDURE sp_test12 +# varbinary BABEL-701 +#CREATE PROCEDURE sp_test13 (@a varbinary OUTPUT) AS BEGIN SET @a=0x121; Select @a as a; END; +#exec sp_test13 0x122 +#Declare @a varbinary;Set @a=0x122; exec sp_test13 @a;select @a as a; +#storedproc#!#prep#!#sp_test13#!#varbinary|-|a|-|0x122|-|output +#storedproc#!#prep#!#sp_test13#!#varbinary|-|a|-|0x122|-|inputoutput +#DROP PROCEDURE sp_test13 +# date +CREATE PROCEDURE sp_test14 (@a date output) AS BEGIN SET @a='1999-1-3'; Select @a as a; END; +#Declare @a DATE;Set @a='9999-12-31'; exec sp_test14 @a;select @a as a; +storedproc#!#prep#!#sp_test14#!#DATE|-|a|-|9999-12-31|-|output +storedproc#!#prep#!#sp_test14#!#DATE|-|a|-|9999-12-31|-|inputoutput +DROP PROCEDURE sp_test14 +# time +#CREATE PROCEDURE sp_test15 (@a time(4) OUTPUT) AS BEGIN SET @a='11:25:07.123'; Select @a as a; END; +#Declare @a Time;Set @a='12:45:37.123'; exec sp_test15 @a;select @a as a; +#storedproc#!#prep#!#sp_test15#!#Time|-|a|-|12:45:37.123|-|3|-|output +#storedproc#!#prep#!#sp_test15#!#Time|-|a|-|12:45:37.123|-|3|-|inputoutput +#DROP PROCEDURE sp_test15 +# dateime BABEL-694 +#CREATE PROCEDURE sp_test16 (@a datetime output) AS BEGIN SET @a='2004-05-18 13:59:59.995'; Select @a as a; END; +#Declare @a DATETIME;Set @a='2000-02-28 23:59:59.995'; exec sp_test16 @a;select @a as a; +#storedproc#!#prep#!#sp_test16#!#DATETIME|-|a|-|2000-02-28 23:59:59.995|-|output +#storedproc#!#prep#!#sp_test16#!#DATETIME|-|a|-|2000-02-28 23:59:59.995|-|inputoutput +#DROP PROCEDURE sp_test16 +# datetime2 +#CREATE PROCEDURE sp_test17 (@a datetime2(5) OUTPUT) AS BEGIN SET @a='2014-10-2 1:45:37.123456'; Select @a as a; END; +#Declare @a Datetime2;Set @a='2016-10-23 12:45:37.123456'; exec sp_test17 @a;select @a as a; +#storedproc#!#prep#!#sp_test17#!#Datetime2|-|a|-|2016-10-23 12:45:37.123456|-|5|-|output +#storedproc#!#prep#!#sp_test17#!#Datetime2|-|a|-|2016-10-23 12:45:37.123456|-|5|-|inputoutput +#DROP PROCEDURE sp_test17 +# smalldatetime BABEL-694 +#CREATE PROCEDURE sp_test18 (@a smalldatetime output) AS BEGIN SET @a='2010-02-03 12:58:23'; Select @a as a; END; +#Declare @a SMALLDATETIME;Set @a='2000-12-13 12:58:23'; exec sp_test18 @a;select @a as a; +#storedproc#!#prep#!#sp_test18#!#SMALLDATETIME|-|a|-|2000-12-13 12:58:23|-|output +#storedproc#!#prep#!#sp_test18#!#SMALLDATETIME|-|a|-|2000-12-13 12:58:23|-|inputoutput +#DROP PROCEDURE sp_test18 +# UID +#CREATE PROCEDURE sp_test19 (@a uniqueidentifier OUTPUT) AS BEGIN SET @a='ce8af10a-2709-43b0-9e4e-a02753929d17'; Select @a as a; END; +#Declare @a uniqueidentifier;Set @a='5b7c2e8d-6d90-411d-8e19-9a81067e6f6c'; exec sp_test19 @a;select @a as a; +#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 diff --git a/contrib/test/JDBC/input/tds_faultinjection.txt b/contrib/test/JDBC/input/tds_faultinjection.txt new file mode 100644 index 00000000000..882989216be --- /dev/null +++ b/contrib/test/JDBC/input/tds_faultinjection.txt @@ -0,0 +1,33 @@ +---- Inject an error in tds comm layer while reading the request +---- Test both SQL Batch and prepare exec +--SELECT inject_fault('tds_comm_throw_error', 2); +--SELECT 1; +--prepst#!# SELECT @a #!#BIGINT|-|a|-|0 + +---- test normal execution +--SELECT 1; + +-- Inject a pre-parsing error +-- Test both SQL Batch and prepare exec +SELECT inject_fault('pre_parsing_throw_error', 2); +SELECT 1; +prepst#!# SELECT @a #!#BIGINT|-|a|-|0 + +-- test normal execution +SELECT 1; + +-- Inject a post-parsing error +-- Test both SQL Batch and prepare exec +SELECT inject_fault('post_parsing_throw_error', 2); +SELECT 1; +prepst#!# SELECT @a #!#BIGINT|-|a|-|0 + +-- test normal execution +SELECT 1; + +-- Inject fault to tamper TDS request +-- Test both SQL Batch and prepare exec (but prepare exec is failing now) +SELECT inject_fault('pre_parsing_tamper_request', 1); +SELECT 1; +--prepst#!# SELECT @a #!#BIGINT|-|a|-|0 + diff --git a/contrib/test/JDBC/input/transactions/TestIsolationLevels.sql b/contrib/test/JDBC/input/transactions/TestIsolationLevels.sql new file mode 100644 index 00000000000..6c3ab561dda --- /dev/null +++ b/contrib/test/JDBC/input/transactions/TestIsolationLevels.sql @@ -0,0 +1,36 @@ +set transaction isolation level read uncommitted; +go + +set transaction isolation level read committed; +go + +set transaction isolation level repeatable read; +go + +set transaction isolation level snapshot; +go + +set transaction isolation level serializable; +go + +select set_config('default_transaction_isolation', 'read uncommitted', false); +go +select set_config('default_transaction_isolation', 'read committed', false); +go +select set_config('default_transaction_isolation', 'repeatable read', false); +go +select set_config('default_transaction_isolation', 'snapshot', false); +go +select set_config('default_transaction_isolation', 'serializable', false); +go + +select set_config('transaction_isolation', 'read uncommitted', false); +go +select set_config('transaction_isolation', 'read committed', false); +go +select set_config('transaction_isolation', 'repeatable read', false); +go +select set_config('transaction_isolation', 'snapshot', false); +go +select set_config('transaction_isolation', 'serializable', false); +go diff --git a/contrib/test/JDBC/input/transactions/TestTransactionName.sql b/contrib/test/JDBC/input/transactions/TestTransactionName.sql new file mode 100644 index 00000000000..22de0f0932e --- /dev/null +++ b/contrib/test/JDBC/input/transactions/TestTransactionName.sql @@ -0,0 +1,70 @@ +-- Tests for transaction name in babel + +CREATE TABLE TestTxnName(C1 INT); +GO + +-- Transaction name longer than 32 chars no allowed +BEGIN TRANSACTION longname11111111111111111111111111111111111111; +GO + +-- Transaction name longer than 32 truncated +DECLARE @txnName varchar(100) = 'a1111111111111111111111111111111truncatethis'; +BEGIN TRAN @txnName; +ROLLBACK TRAN a1111111111111111111111111111111 +GO + +SELECT @@trancount; +GO + +-- Transaction/savepoint names are case sensitive +DECLARE @txnName varchar(100) = 'Abc'; +DECLARE @spName varchar(100) = 'aBc'; + +BEGIN TRAN abc; +INSERT INTO TestTxnName VALUES(1); +SAVE TRAN @spName; +INSERT INTO TestTxnName VALUES(2); +SAVE TRAN abC; +INSERT INTO TestTxnName VALUES(3); +SAVE TRAN ABc; +INSERT INTO TestTxnName VALUES(4); +SAVE TRAN AbC; +INSERT INTO TestTxnName VALUES(5); +SAVE TRAN [aBC]; +INSERT INTO TestTxnName VALUES(6); +BEGIN TRAN @txnName; +GO + +SELECT C1 FROM TestTxnName ORDER BY C1; +GO + +ROLLBACK TRAN [AbC]; +SELECT C1 FROM TestTxnName ORDER BY C1; +GO + +ROLLBACK TRAN ABc; +SELECT C1 FROM TestTxnName ORDER BY C1; +GO + +ROLLBACK TRAN aBc; +SELECT C1 FROM TestTxnName ORDER BY C1; +GO + +DECLARE @txnName varchar(100) = 'abc'; +ROLLBACK TRAN @txnName; +SELECT C1 FROM TestTxnName ORDER BY C1; +GO + +SELECT @@trancount; +GO + +DECLARE @txnName varchar(100) = 'abc'; +BEGIN TRAN @txnName; +COMMIT TRAN @txnName; +GO + +SELECT @@trancount; +GO + +DROP TABLE TestTxnName; +GO diff --git a/contrib/test/JDBC/input/transactions/TestTransactionSupportForProcedure.txt b/contrib/test/JDBC/input/transactions/TestTransactionSupportForProcedure.txt new file mode 100644 index 00000000000..a9a997b1c75 --- /dev/null +++ b/contrib/test/JDBC/input/transactions/TestTransactionSupportForProcedure.txt @@ -0,0 +1,260 @@ +#setup +create table txnproctable (c1 int not null, c2 varchar(100)) + +# PROC +# BEGIN TRAN +# SAVEPOINT +# ROLLBACK SAVEPOINT +# COMMIT +create procedure txnproc1 as begin tran; insert into txnproctable values (1, 'abc'); save tran sp1; update txnproctable set c1 = c1 + 1; rollback tran sp1; commit tran; +select @@trancount; +select * from txnproctable order by c1; +exec txnproc1; +select @@trancount; +select * from txnproctable order by c1; + + +# PROC +# BEGIN TRAN +# SAVEPOINT +# ROLLBACK SAVEPOINT +# ROLLBACK +drop procedure txnproc1; +create procedure txnproc1 as begin tran; insert into txnproctable values(2, 'xyz'); save tran sp1; delete from txnproctable; rollback tran sp1; rollback tran; +select @@trancount; +select * from txnproctable order by c1; +exec txnproc1; +select @@trancount; +select * from txnproctable order by c1; + + +# PROC +# BEGIN TRAN +# SAVEPOINT +# ROLLBACK SAVEPOINT +# COMMIT +drop procedure txnproc1 +create procedure txnproc1 as begin tran; insert into txnproctable values(3, 'dbd'); save tran sp1; update txnproctable set c1 = c1 + 1; rollback tran sp1; +select @@trancount +select * from txnproctable order by c1; +exec txnproc1; +select @@trancount +select * from txnproctable order by c1; +commit tran; +select @@trancount +select * from txnproctable order by c1; + + +# PROC +# BEGIN TRAN +# SAVEPOINT +# ROLLBACK SAVEPOINT +# COMMIT +drop procedure txnproc1 +create procedure txnproc1 as begin tran; insert into txnproctable values(4, 'sbd'); save tran sp1; update txnproctable set c1 = c1 + 1; +select @@trancount +select * from txnproctable order by c1; +exec txnproc1; +select @@trancount +select * from txnproctable order by c1; +rollback tran sp1; +select @@trancount +select * from txnproctable order by c1; +commit tran; +select @@trancount +select * from txnproctable order by c1; + + +# BEGIN TRAN +# PROC +# SAVEPOINT +# ROLLBACK SAVEPOINT +# COMMIT +begin tran; +select @@trancount +select * from txnproctable order by c1; +drop procedure txnproc1 +create procedure txnproc1 as insert into txnproctable values(5, 'abc'); save tran sp1; update txnproctable set c1 = c1 + 1; rollback tran sp1; +select @@trancount +select * from txnproctable order by c1; +exec txnproc1; +select @@trancount +select * from txnproctable order by c1; +commit tran; +select @@trancount +select * from txnproctable order by c1; + + +# BEGIN TRAN +# PROC +# SAVEPOINT +# ROLLBACK SAVEPOINT +# ROLLBACK +begin tran; +select @@trancount +select * from txnproctable order by c1; +drop procedure txnproc1 +create procedure txnproc1 as insert into txnproctable values(6, 'abc'); save tran sp1; update txnproctable set c1 = c1 + 1; rollback tran sp1; +select @@trancount +select * from txnproctable order by c1; +exec txnproc1; +select @@trancount +select * from txnproctable order by c1; +commit tran; +select @@trancount +select * from txnproctable order by c1; + +# BEGIN TRAN +# PROC +# SAVEPOINT +# ROLLBACK SAVEPOINT +# COMMIT +begin tran; +select @@trancount +select * from txnproctable order by c1; +drop procedure txnproc1 +create procedure txnproc1 as insert into txnproctable values(7, 'abc'); save tran sp1; update txnproctable set c1 = c1 + 1; rollback tran sp1; update txnproctable set c1 = c1 + 1; commit tran; +select @@trancount +select * from txnproctable order by c1; +exec txnproc1; +select @@trancount +select * from txnproctable order by c1; + +# BEGIN TRAN +# PROC +# SAVEPOINT +# ROLLBACK SAVEPOINT +# ROLLBACK +begin tran; +select @@trancount +select * from txnproctable order by c1; +drop procedure txnproc1 +create procedure txnproc1 as insert into txnproctable values(8, 'abc'); save tran sp1; update txnproctable set c1 = c1 + 1; rollback tran sp1; update txnproctable set c1 = c1 + 1; rollback tran; +select @@trancount +select * from txnproctable order by c1; +exec txnproc1; +select @@trancount +select * from txnproctable order by c1; + +# BEGIN TRAN +# START SAVEPOINT +# PROC +# ROLLBACK SAVEPOINT +# ROLLBACK +begin tran; +select @@trancount +select * from txnproctable order by c1; +save tran sp1; +select @@trancount +select * from txnproctable order by c1; +drop procedure txnproc1 +create procedure txnproc1 as insert into txnproctable values(9, 'abc'); update txnproctable set c1 = c1 + 1; +select @@trancount +select * from txnproctable order by c1; +exec txnproc1; +rollback tran sp1; +select @@trancount +select * from txnproctable order by c1; +rollback tran; +select @@trancount +select * from txnproctable order by c1; + +# BEGIN TRAN +# START SAVEPOINT +# PROC +# ROLLBACK SAVEPOINT +# ROLLBACK +begin tran; +select @@trancount +select * from txnproctable order by c1; +save tran sp1; +select @@trancount +select * from txnproctable order by c1; +drop procedure txnproc1 +create procedure txnproc1 as insert into txnproctable values(10, 'abc'); update txnproctable set c1 = c1 + 1; +select @@trancount +select * from txnproctable order by c1; +exec txnproc1; +rollback tran sp1; +select @@trancount +select * from txnproctable order by c1; +commit tran; +select @@trancount +select * from txnproctable order by c1; + +# BEGIN TRAN +# START SAVEPOINT +# PROC +# ROLLBACK SAVEPOINT +# ROLLBACK +begin tran; +select @@trancount +select * from txnproctable order by c1; +save tran sp1; +select @@trancount +select * from txnproctable order by c1; +drop procedure txnproc1 +create procedure txnproc1 as insert into txnproctable values(11, 'abc'); rollback tran sp1; update txnproctable set c1 = c1 + 1; +select @@trancount +select * from txnproctable order by c1; +exec txnproc1; +commit tran; +select @@trancount +select * from txnproctable order by c1; + +# PROC1 +# BEGIN TRAN +# PROC2 +# PROC3 +# BEGIN TRAN +# START SAVEPOINT +# ROLLBACK SAVEPOINT +# COMMIT +# COMMIT +create procedure txnProc3 as begin tran; insert into txnproctable values (16, 'abc'); save tran sp1; update txnproctable set c1 = c1 + 1; rollback tran sp1; +select @@trancount +select * from txnproctable order by c1; +create procedure txnProc2 as update txnproctable set c1 = c1 + 1; exec txnProc3; commit tran; +select @@trancount +select * from txnproctable order by c1; +drop procedure txnproc1 +create procedure txnproc1 as delete from txnproctable; begin tran; exec txnProc2; +select @@trancount +select * from txnproctable order by c1; +exec txnproc1; +select @@trancount +select * from txnproctable order by c1; +commit tran; +select @@trancount +select * from txnproctable order by c1; + +# PROC1 +# BEGIN TRAN +# PROC2 +# PROC3 +# BEGIN TRAN +# START SAVEPOINT +# ROLLBACK SAVEPOINT +# ROLLBACK TRAN +# COMMIT +drop procedure txnproc3 +create procedure txnProc3 as begin tran; insert into txnproctable values (20, 'abc'); save tran sp1; update txnproctable set c1 = c1 + 1; rollback tran sp1; +select @@trancount +select * from txnproctable order by c1; +drop procedure txnproc2 +create procedure txnProc2 as update txnproctable set c1 = c1 + 1; exec txnProc3; rollback tran; +select @@trancount +select * from txnproctable order by c1; +drop procedure txnproc1 +create procedure txnproc1 as delete from txnproctable; begin tran; exec txnProc2; +select @@trancount +select * from txnproctable order by c1; +exec txnproc1; +select @@trancount +select * from txnproctable order by c1; + +#cleanup +drop procedure txnproc3 +drop procedure txnproc2 +drop procedure txnproc1 +drop table txnproctable \ No newline at end of file diff --git a/contrib/test/JDBC/input/transactions/TestTransactionsSQLBatch.txt b/contrib/test/JDBC/input/transactions/TestTransactionsSQLBatch.txt new file mode 100644 index 00000000000..c767fbbaead --- /dev/null +++ b/contrib/test/JDBC/input/transactions/TestTransactionsSQLBatch.txt @@ -0,0 +1,189 @@ +create table TxnTable(c1 int); + +# Begin transaction -> commit transaction +begin transaction; +select @@trancount; +begin transaction; +select @@trancount; +set transaction isolation level read committed; +#show transaction_isolation; +#show default_transaction_isolation; +insert into TxnTable values(1); +commit transaction; +select @@trancount; +commit transaction; +select @@trancount; +select c1 from TxnTable; + +# Begin transaction -> rollback transaction +begin transaction; +insert into TxnTable values(2); +rollback transaction; +select c1 from TxnTable; + +#Begin tran -> commit tran +begin tran; +insert into TxnTable values(2); +commit tran; +select c1 from TxnTable; + +# Begin tran -> rollback tran +begin tran; +select @@trancount; +begin tran; +set transaction isolation level read uncommitted; +#show transaction_isolation; +#show default_transaction_isolation; +insert into TxnTable values(3); +select @@trancount; +rollback tran; +select @@trancount; +select c1 from TxnTable; + +set transaction isolation level repeatable read; +#show transaction_isolation; +#show default_transaction_isolation; + +# Begin transaction -> commit +begin transaction; +insert into TxnTable values(4); +commit; +select c1 from TxnTable; + +# Begin transaction -> commit work +begin transaction; +insert into TxnTable values(5); +commit work; +select c1 from TxnTable; + +# Begin transaction -> rollback +begin transaction; +insert into TxnTable values(6); +rollback; +select c1 from TxnTable; + +# Begin transaction -> rollback work +begin transaction; +insert into TxnTable values(7); +rollback work; +select c1 from TxnTable; + +# Begin transaction name -> commit transaction name +begin transaction txn1; +insert into TxnTable values(8); +commit transaction txn1; +select c1 from TxnTable; + +# Begin transaction name -> rollback transaction name +begin transaction txn1; +insert into TxnTable values(9); +rollback transaction txn1; +select c1 from TxnTable; + +# Begin tran name -> commit tran name +begin tran txn1; +insert into TxnTable values(10); +commit tran txn1; +select c1 from TxnTable; + +# Begin tran name -> rollback tran name +begin tran txn1; +insert into TxnTable values(10); +rollback tran txn1; +select c1 from TxnTable; + +truncate table TxnTable; + +# save tran name -> rollback tran name +set transaction isolation level snapshot; +#show transaction_isolation; +#show default_transaction_isolation; +begin transaction txn1; +insert into TxnTable values(1); +save transaction sp1; +select @@trancount; +insert into TxnTable values(2); +save tran sp2; +insert into TxnTable values(3); +save tran sp2; +select @@trancount; +insert into TxnTable values(4); +select c1 from TxnTable; +rollback tran sp2; +select @@trancount; +select c1 from TxnTable; +rollback tran sp2; +select @@trancount; +select c1 from TxnTable; +rollback tran sp1; +select @@trancount; +select c1 from TxnTable; +rollback tran txn1; +select @@trancount; +select c1 from TxnTable; + +# begin transaction name -> save transaction name -> rollback to first savepoint +begin transaction txn1; +insert into TxnTable values(1); +save transaction sp1; +insert into TxnTable values(2); +save transaction sp2; +insert into TxnTable values(3); +save transaction sp3; +insert into TxnTable values(4); +rollback tran sp1; +#rollback tran sp1; -- this will give an error +rollback tran; +select c1 from TxnTable; + +# begin transaction name -> save transaction name -> rollback tran name, Rollback whole transaction +set transaction isolation level serializable; +#show transaction_isolation; +#show default_transaction_isolation; +begin transaction txn1; +insert into TxnTable values(1); +save transaction sp1; +begin transaction txn1; +insert into TxnTable values(2); +save transaction sp1; +insert into TxnTable values(3); +select @@trancount; +rollback tran txn1; +select @@trancount; +select c1 from TxnTable; + +# 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; +rollback tran sp1; +commit transaction; +select c1 from TxnTable; + +# 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; +rollback tran sp1; +save transaction sp2; +insert into TxnTable values(5); +commit transaction; +select c1 from TxnTable; + +# 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 +rollback tran sp1; +commit transaction; +select c1 from TxnTable; + +Drop table TxnTable; \ No newline at end of file diff --git a/contrib/test/JDBC/input/transactions/TestTriggers.sql b/contrib/test/JDBC/input/transactions/TestTriggers.sql new file mode 100644 index 00000000000..04a9ad44a72 --- /dev/null +++ b/contrib/test/JDBC/input/transactions/TestTriggers.sql @@ -0,0 +1,197 @@ +create table triggerTab1(c1 int, c2 varchar(30)) +go + +create table triggerTab2(c1 int) +go + +create table triggerTab3(c1 int) +go + +insert into triggerTab1 values(1, 'first') +go + +insert into triggerTab2 values(1) +go + +insert into triggerTab3 values(1) +go + +create trigger txnTrig1 on triggerTab1 for insert as +begin tran; +update triggerTab2 set c1 = 2; +commit; +select * from triggerTab2 order by c1; +select * from inserted; +go + +create trigger txnTrig2 on triggerTab2 for update as +save tran sp1; +save tran sp2; +delete from triggerTab3; +rollback tran sp1; +go + +create trigger txnTrig3 on triggerTab3 for delete as +select * from triggerTab3 order by c1; +insert into triggerTab3 values(1); +select * from deleted; +rollback tran sp2; +go + +insert into triggerTab1 values(2, 'second'); +go + +begin tran; +go +insert into triggerTab1 values(3, 'third'); +go +commit; +go + +drop trigger txnTrig1; +go + +create trigger txnTrig1 on triggerTab1 for insert as +commit; +update triggerTab2 set c1 = 2; +select * from triggerTab2 order by c1; +go + +insert into triggerTab1 values(2, 'second'); +go + +begin tran; +go + +insert into triggerTab1 values(2, 'second'); +go + +drop trigger txnTrig1; +go + +create trigger txnTrig1 on triggerTab1 for insert as +rollback; +update triggerTab2 set c1 = 3; +select * from triggerTab2 order by c1; +go + +insert into triggerTab1 values(2, 'second'); +go + +begin tran; +go + +insert into triggerTab1 values(2, 'second'); +go + +create procedure triggerProc1 as +save tran sp1; +insert into triggerTab1 values(3, 'third'); +rollback tran sp1; +go + +create procedure triggerProc2 as +begin tran; +exec triggerProc1; +insert into triggerTab1 values(3, 'third'); +commit; +go + +exec triggerProc2; +go + +create table triggerErrorTab(c1 int not null); +go + +create trigger triggerErr on triggerErrorTab for insert as +insert into triggerErrorTab values(NULL); +insert into invalidTab values(1); +go + +insert into triggerErrorTab values(1); +go + + +drop procedure triggerProc1; +go +drop procedure triggerProc2; +go +drop trigger txnTrig1 +go + + +create procedure triggerProc1 as +commit; +go + +create procedure triggerProc2 as +exec triggerProc1; +go + +create trigger txnTrig1 on triggerTab1 for insert as +exec triggerProc2; +go + +insert into triggerTab1 values(1, 'value1'); +go + +drop procedure triggerProc1; +go +drop procedure triggerProc2; +go +drop trigger txnTrig1 +go + + +create procedure triggerProc1 as +rollback; +go + +create procedure triggerProc2 as +exec triggerProc1; +go + +create trigger txnTrig1 on triggerTab1 after insert as +exec triggerProc2; +go + +insert into triggerTab1 values(1, 'value2'); +go + +drop procedure triggerProc1; +go +drop procedure triggerProc2; +go +drop trigger txnTrig1 +go + + +create procedure triggerProc1 as +rollback tran sp1; +go + +create procedure triggerProc2 as +exec triggerProc1; +go + +create trigger txnTrig1 on triggerTab1 for insert as +save tran sp1; +exec triggerProc2; +go + +insert into triggerTab1 values(1, 'value3'); +go + + +drop procedure triggerProc1; +go +drop procedure triggerProc2; +go +drop table triggerTab1; +go +drop table triggerTab2; +go +drop table triggerTab3; +go +drop table triggerErrorTab +go diff --git a/contrib/test/JDBC/input/views/sys-all_columns.sql b/contrib/test/JDBC/input/views/sys-all_columns.sql new file mode 100644 index 00000000000..ac6bcb3c903 --- /dev/null +++ b/contrib/test/JDBC/input/views/sys-all_columns.sql @@ -0,0 +1,21 @@ +DROP TABLE IF EXISTS sys_all_columns_table +GO + +CREATE TABLE sys_all_columns_table ( + sac_int_col INT PRIMARY KEY, + sac_text_col_not_null VARCHAR(50) NOT NULL, + sac_date_col DATETIME +) +GO + +SELECT name, is_nullable, column_id +FROM sys.all_columns +WHERE name in ('sac_int_col', 'sac_text_col_not_null', 'sac_date_col') +ORDER BY name +GO + +SELECT COUNT(*) FROM sys.all_columns WHERE object_id = object_id('sys.all_columns'); +GO + +DROP TABLE IF EXISTS sys_all_columns_table +GO diff --git a/contrib/test/JDBC/input/views/sys-check_constraints.sql b/contrib/test/JDBC/input/views/sys-check_constraints.sql new file mode 100644 index 00000000000..39abb3a6e84 --- /dev/null +++ b/contrib/test/JDBC/input/views/sys-check_constraints.sql @@ -0,0 +1,16 @@ +DROP TABLE IF EXISTS sys_check_constraints +GO + +CREATE TABLE sys_check_constraints ( + sck_date_col DATETIME CHECK (sck_date_col IS NOT NULL) +) +GO + +SELECT name FROM sys.check_constraints WHERE NAME IN ('sys_check_constraints_sck_date_col_check') +GO + +SELECT COUNT(*) FROM sys.all_columns WHERE object_id = object_id('sys.check_constraints'); +GO + +DROP TABLE IF EXISTS sys_check_constraints +GO diff --git a/contrib/test/JDBC/input/views/sys-computed_columns.sql b/contrib/test/JDBC/input/views/sys-computed_columns.sql new file mode 100644 index 00000000000..364f24bdf65 --- /dev/null +++ b/contrib/test/JDBC/input/views/sys-computed_columns.sql @@ -0,0 +1,18 @@ +DROP TABLE IF EXISTS sys_computed_columns +GO + +CREATE TABLE sys_computed_columns ( + scc_first_number smallint, + scc_second_number money, + scc_multiplied AS scc_first_number * scc_second_number +) +GO + +SELECT name FROM sys.computed_columns where name in ('scc_multiplied') +GO + +SELECT COUNT(*) FROM sys.all_columns WHERE object_id = object_id('sys.computed_columns'); +GO + +DROP TABLE IF EXISTS sys_computed_columns +GO diff --git a/contrib/test/JDBC/input/views/sys-databases.sql b/contrib/test/JDBC/input/views/sys-databases.sql new file mode 100644 index 00000000000..9c79d517e6d --- /dev/null +++ b/contrib/test/JDBC/input/views/sys-databases.sql @@ -0,0 +1,14 @@ +DROP DATABASE IF EXISTS my_test_database; +GO + +CREATE DATABASE my_test_database; +GO + +SELECT COUNT(*) FROM sys.all_columns WHERE object_id = object_id('sys.databases'); +GO + +SELECT name FROM sys.databases where name = 'my_test_database'; +GO + +DROP DATABASE IF EXISTS my_test_database; +GO diff --git a/contrib/test/JDBC/input/views/sys-default_constraints.sql b/contrib/test/JDBC/input/views/sys-default_constraints.sql new file mode 100644 index 00000000000..9e4bc44de9b --- /dev/null +++ b/contrib/test/JDBC/input/views/sys-default_constraints.sql @@ -0,0 +1,17 @@ +DROP TABLE IF EXISTS sys_default_definitions +GO + +CREATE TABLE sys_default_definitions (column_a INT, column_b INT) +GO + +ALTER TABLE sys_default_definitions ADD CONSTRAINT DF_sdd_column_b DEFAULT 50 FOR column_b +GO + +SELECT definition FROM sys.default_constraints where name LIKE '%sys_default_definitions%' +GO + +SELECT COUNT(*) FROM sys.all_columns WHERE object_id = object_id('sys.default_constraints'); +GO + +DROP TABLE IF EXISTS sys_default_definitions +GO diff --git a/contrib/test/JDBC/input/views/sys-extended_properties.sql b/contrib/test/JDBC/input/views/sys-extended_properties.sql new file mode 100644 index 00000000000..cdac6f66aee --- /dev/null +++ b/contrib/test/JDBC/input/views/sys-extended_properties.sql @@ -0,0 +1,2 @@ +SELECT COUNT(*) FROM sys.all_columns WHERE object_id = object_id('sys.extended_properties'); +GO diff --git a/contrib/test/JDBC/input/views/sys-index_columns.sql b/contrib/test/JDBC/input/views/sys-index_columns.sql new file mode 100644 index 00000000000..a019d7aa54f --- /dev/null +++ b/contrib/test/JDBC/input/views/sys-index_columns.sql @@ -0,0 +1,21 @@ +DROP TABLE IF EXISTS sys_index_columns +GO + +CREATE TABLE sys_index_columns ( + sic_name VARCHAR (50), + sic_surname VARCHAR (50) +) +GO + +CREATE INDEX sic_test_index +ON sys_index_columns (sic_name) +GO + +SELECT COUNT(*) FROM sys.index_columns WHERE object_id = OBJECT_ID('sys_index_columns') +GO + +SELECT COUNT(*) FROM sys.all_columns WHERE object_id = object_id('sys.index_columns') +GO + +DROP TABLE IF EXISTS sys_index_columns +GO diff --git a/contrib/test/JDBC/input/views/sys-indexes.sql b/contrib/test/JDBC/input/views/sys-indexes.sql new file mode 100644 index 00000000000..1f3d82a5455 --- /dev/null +++ b/contrib/test/JDBC/input/views/sys-indexes.sql @@ -0,0 +1,41 @@ +SELECT COUNT(*) FROM sys.all_columns WHERE object_id = object_id('sys.indexes'); +GO + +DROP TABLE IF EXISTS t_sys_index_test1 +GO + +CREATE TABLE t_sys_index_test1 ( + c1 INT, + c2 VARCHAR(128) +); +GO + +INSERT INTO t_sys_index_test1 (c1, c2) VALUES +(100, 'abc'), +(200, 'bcd'), +(300, 'cde'), +(1400, 'def') +GO + +CREATE INDEX i_sys_index_test1 ON t_sys_index_test1 (c1); +CREATE INDEX i_sys_index_test1a ON t_sys_index_test1 (c2); +GO + +SELECT COUNT(*) FROM sys.indexes WHERE object_id = OBJECT_ID('t_sys_index_test1') +GO + +SELECT COUNT(*) FROM sys.indexes WHERE name LIKE 'i_sys_index_test1%'; +GO + +SELECT type, type_desc FROM sys.indexes WHERE name LIKE 'i_sys_index_test1%'; +GO + +DROP INDEX i_sys_index_test1 ON t_sys_index_test1; +DROP INDEX i_sys_index_test1a ON t_sys_index_test1; +GO + +SELECT COUNT(*) FROM sys.indexes WHERE name LIKE 'i_sys_index_test%'; +GO + +DROP TABLE IF EXISTS t_sys_index_test1 +GO diff --git a/contrib/test/JDBC/input/views/sys-schemas.sql b/contrib/test/JDBC/input/views/sys-schemas.sql new file mode 100644 index 00000000000..9973f2c2ded --- /dev/null +++ b/contrib/test/JDBC/input/views/sys-schemas.sql @@ -0,0 +1,22 @@ +SELECT COUNT(*) FROM sys.all_columns WHERE object_id = object_id('sys.schemas'); +GO + +SELECT name FROM sys.schemas +WHERE name = 'dbo'; +GO + +CREATE SCHEMA sys_schema_test1; +CREATE SCHEMA sys_schema_test2; +GO + +SELECT name FROM sys.schemas +WHERE name in ('dbo', 'sys_schema_test1', 'sys_schema_test2'); +GO + +DROP SCHEMA sys_schema_test1; +DROP SCHEMA sys_schema_test2; +GO + +SELECT name FROM sys.schemas +WHERE name in ('dbo', 'sys_schema_test1', 'sys_schema_test2'); +GO diff --git a/contrib/test/JDBC/input/views/sys-server_principals.sql b/contrib/test/JDBC/input/views/sys-server_principals.sql new file mode 100644 index 00000000000..25af17f708c --- /dev/null +++ b/contrib/test/JDBC/input/views/sys-server_principals.sql @@ -0,0 +1,23 @@ +SELECT COUNT(*) FROM sys.all_columns WHERE object_id = object_id('sys.server_principals'); +GO + +SELECT name, type, type_desc, default_database_name, default_language_name +FROM sys.server_principals +WHERE name = 'jdbc_user'; +GO + +CREATE LOGIN serv_principal_test WITH PASSWORD = 'test'; +GO + +SELECT name, type, type_desc, default_database_name, default_language_name +FROM sys.server_principals +WHERE name in ('jdbc_user', 'serv_principal_test'); +GO + +DROP LOGIN serv_principal_test; +GO + +SELECT name, type, type_desc, default_database_name, default_language_name +FROM sys.server_principals +WHERE name in ('jdbc_user', 'serv_principal_test'); +GO diff --git a/contrib/test/JDBC/input/views/sys-syscolumns.sql b/contrib/test/JDBC/input/views/sys-syscolumns.sql new file mode 100644 index 00000000000..f0c9ffe2698 --- /dev/null +++ b/contrib/test/JDBC/input/views/sys-syscolumns.sql @@ -0,0 +1,70 @@ +-- create helper function to get datatype name given oid +CREATE FUNCTION OidToDataType(@Oid integer) +RETURNS VARCHAR(50) +AS +BEGIN + DECLARE @datatype VARCHAR(50); + SET @datatype = (SELECT typname from pg_type where oid = @Oid); + RETURN @datatype; +END; +GO + +-- create helper function to get procedure/table name given oid +CREATE FUNCTION OidToObject(@Oid integer) +RETURNS VARCHAR(50) +AS +BEGIN + DECLARE @object_name VARCHAR(50); + + SET @object_name = (SELECT relname from pg_class where oid = @Oid); + + IF (@object_name is null) + BEGIN + SET @object_name = (SELECT proname from pg_proc where oid = @Oid); + END + + RETURN @object_name +END; +GO + +-- create helper function to get collation name given oid +CREATE FUNCTION OidToCollation(@Oid integer) +RETURNS VARCHAR(50) +AS +BEGIN + DECLARE @collation VARCHAR(50); + SET @collation = (SELECT collname from pg_collation where oid = @Oid); + RETURN @collation; +END; +GO + +-- Setup some procedures and tables +create procedure syscolumns_demo_proc1 @firstparam NVARCHAR(50) as select 1 +GO + +create procedure syscolumns_demo_proc2 @firstparam NVARCHAR(50), @secondparam VARCHAR(50) OUT as select 2 +GO + +create table syscolumns_demo_table (col_a int, col_b bigint, col_c char(10), col_d numeric(5,4)) +GO + +select name, OidToObject(id), OidToDataType(xtype), typestat, length from sys.syscolumns where name = '@firstparam' or name = '@secondparam' or name = 'col_a' or name = 'col_b' or name = 'col_c' or name = 'col_d' order by OidToObject(id) asc, name +GO + +select colid, cdefault, domain, number from sys.syscolumns where name = '@firstparam' or name = '@secondparam' or name = 'col_a' or name = 'col_b' or name = 'col_c' or name = 'col_d' order by OidToObject(id) asc, name +GO + +select OidToCollation(collationid), status, OidToDataType(type), prec, scale from sys.syscolumns where name = '@firstparam' or name = '@secondparam' or name = 'col_a' or name = 'col_b' or name = 'col_c' or name = 'col_d' order by OidToObject(id) asc, name +GO + +select 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 + +-- Cleanup +DROP FUNCTION OidToDataType +DROP FUNCTION OidToObject +DROP FUNCTION OidToCollation +DROP PROCEDURE syscolumns_demo_proc1 +DROP PROCEDURE syscolumns_demo_proc2 +DROP TABLE syscolumns_demo_table +GO \ No newline at end of file diff --git a/contrib/test/JDBC/jdbc_schedule b/contrib/test/JDBC/jdbc_schedule new file mode 100644 index 00000000000..eabc1bbad9f --- /dev/null +++ b/contrib/test/JDBC/jdbc_schedule @@ -0,0 +1,12 @@ +# Schedule File for JDBC Test Framework for local run +# 1. Lines starting with '#' will be treated as comments +# 2. To run a postgres command: cmd#!#postgresql#!# +# 3. To run a T-SQL command: cmd#!#sqlserver#!# +# 4. Keyword "all" is equivalent to running all test files in +# input folder +# 5. To add a test, add test name (without extension Eg. BABEL-TEST) on a +# new line +# 6. If you want the framework to not run certain files, use: ignore#!# + +all + diff --git a/contrib/test/JDBC/pom.xml b/contrib/test/JDBC/pom.xml new file mode 100644 index 00000000000..cbe83b011e9 --- /dev/null +++ b/contrib/test/JDBC/pom.xml @@ -0,0 +1,87 @@ + + 4.0.0 + com.sqlsamples + JDBC-testsuite + jar + 1.0.0 + JDBC-testsuite + http://maven.apache.org + + + org.junit.jupiter + junit-jupiter + 5.7.0 + + + org.junit.jupiter + junit-jupiter-params + 5.5.2 + test + + + commons-io + commons-io + 2.6 + + + org.apache.commons + commons-math3 + 3.6.1 + + + org.apache.commons + commons-csv + 1.4 + + + org.apache.logging.log4j + log4j-api + 2.16.0 + + + org.apache.logging.log4j + log4j-core + 2.16.0 + + + + com.microsoft.sqlserver + mssql-jdbc + 8.2.2.jre8 + + + org.postgresql + postgresql + 42.2.18 + + + + + + + maven-surefire-plugin + 3.0.0-M5 + + + false + 3.0 + true + true + true + true + + + + + maven-failsafe-plugin + 2.22.2 + + + + + + 1.8 + 1.8 + + \ No newline at end of file diff --git a/contrib/test/JDBC/sql_expected/1034_1.out b/contrib/test/JDBC/sql_expected/1034_1.out new file mode 100644 index 00000000000..87bb7a12708 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/1034_1.out @@ -0,0 +1,71 @@ + +-- simple batch start +CREATE TABLE t1034 +( + c1 int +,c2 int +) +GO + +GO + +CREATE TRIGGER tr1034 +ON t1034 +FOR UPDATE, UPDATE +AS +SELECT 1 +GO +~~ERROR (Code: 1034)~~ + +~~ERROR (Message: Syntax error: Duplicate specification of the action "UPDATE" in the trigger declaration.)~~ + +DROP TABLE t1034 +GO + +SET XACT_ABORT ON; +GO + +begin transaction +GO +CREATE TABLE t1034 +( + c1 int +,c2 int +) +GO + +GO + +CREATE TRIGGER tr1034 +ON t1034 +FOR UPDATE, UPDATE +AS +SELECT 1 +GO +~~ERROR (Code: 1034)~~ + +~~ERROR (Message: Syntax error: Duplicate specification of the action "UPDATE" in the trigger declaration.)~~ + + + +if (@@trancount > 0) select cast('Does not respect xact_abort flag' as text) else select cast('Respects xact_abort flag' as text) +GO +~~START~~ +text +Does not respect xact_abort flag +~~END~~ + + +if (@@trancount > 0) rollback tran +GO + +DROP TABLE t1034 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the table 't1034', because it does not exist or you do not have permission.)~~ + + +SET XACT_ABORT OFF; +GO + diff --git a/contrib/test/JDBC/sql_expected/1049_1.out b/contrib/test/JDBC/sql_expected/1049_1.out new file mode 100644 index 00000000000..86d81f28928 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/1049_1.out @@ -0,0 +1,406 @@ + +-- simple batch start +CREATE TABLE t1049 (c1 INT) +GO + + +DECLARE cur1049 SCROLL CURSOR FAST_FORWARD READ_ONLY +FOR SELECT c1 FROM t1049 +GO +~~ERROR (Code: 1049)~~ + +~~ERROR (Message: Mixing old and new syntax to specify cursor options is not allowed.)~~ + +DROP TABLE t1049 +GO + + +begin transaction +GO +CREATE TABLE t1049 (c1 INT) +GO + + +DECLARE cur1049 SCROLL CURSOR FAST_FORWARD READ_ONLY +FOR SELECT c1 FROM t1049 +GO +~~ERROR (Code: 1049)~~ + +~~ERROR (Message: Mixing old and new syntax to specify cursor options is not allowed.)~~ + + + +-- Below output is only applicable if query is special case. for example, CREATE/ALTER TRIGGER, CREATE/ALTER FUNCTION, CREATE/ALTER PROC, CREATE/ALTER VIEW etc +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 + +DROP TABLE t1049 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the table 't1049', because it does not exist or you do not have permission.)~~ + + + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + +CREATE TABLE t1049 (c1 INT) +GO + + +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +DECLARE cur1049 SCROLL CURSOR FAST_FORWARD READ_ONLY +FOR SELECT c1 FROM t1049 +end +GO +~~ERROR (Code: 1049)~~ + +~~ERROR (Message: Mixing old and new syntax to specify cursor options is not allowed.)~~ + + +DROP TABLE t1049 +GO + + +create table error_mapping.temp2 (a int) +GO + +CREATE TABLE t1049 (c1 INT) +GO + + +insert into error_mapping.temp2 values(1) +DECLARE cur1049 SCROLL CURSOR FAST_FORWARD READ_ONLY +FOR SELECT c1 FROM t1049 +GO +~~ERROR (Code: 1049)~~ + +~~ERROR (Message: Mixing old and new syntax to specify cursor options is not allowed.)~~ + + +DROP TABLE t1049 +GO + + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + +CREATE TABLE t1049 (c1 INT) +GO + +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2812)~~ + +~~ERROR (Message: Could not find stored procedure 'error_mapping.ErrorHandling1'.)~~ + + +DROP TABLE t1049 +GO + + +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 +~~START~~ +text +parse analysis phase error +~~END~~ + + +drop procedure error_mapping.ErrorHandling1; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + +drop table error_mapping.temp1; +drop table error_mapping.temp2; +drop table error_mapping.temp3; +GO + +-- Parse analysis phase end +GO + + +-- compile time error portion +-- Executing test error_mapping.ErrorHandling1 +CREATE TABLE t1049 (c1 INT) +GO + + + + +create procedure error_mapping.ErrorHandling1 as +begin +DECLARE cur1049 SCROLL CURSOR FAST_FORWARD READ_ONLY +FOR SELECT c1 FROM t1049 +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO +~~ERROR (Code: 1049)~~ + +~~ERROR (Message: Mixing old and new syntax to specify cursor options is not allowed.)~~ + + +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 +~~START~~ +text +Compile time error +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + +DROP TABLE t1049 +GO + + + +CREATE TABLE t1049 (c1 INT) +GO + +begin transaction +GO + + +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +DECLARE cur1049 SCROLL CURSOR FAST_FORWARD READ_ONLY +FOR SELECT c1 FROM t1049 +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +end +GO +~~ERROR (Code: 1049)~~ + +~~ERROR (Message: Mixing old and new syntax to specify cursor options is not allowed.)~~ + + +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 +~~START~~ +text +BATCH ONLY TERMINATING +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +DROP TABLE t1049 +GO + + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE t1049 (c1 INT) +GO + +begin transaction +GO + + +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +DECLARE cur1049 SCROLL CURSOR FAST_FORWARD READ_ONLY +FOR SELECT c1 FROM t1049 +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +end +GO +~~ERROR (Code: 1049)~~ + +~~ERROR (Message: Mixing old and new syntax to specify cursor options is not allowed.)~~ + + +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 +~~START~~ +text +BATCH ONLY TERMINATING +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +DROP TABLE t1049 +GO + +set xact_abort OFF; +GO + + + +-- comiple time error portion end -- +---- Next portion is for runtime error -- +-- +---- Executing test error_mapping.ErrorHandling10000000 +--CREATE TABLE t1049 (c1 INT) +--GO +-- +-- +--create procedure error_mapping.ErrorHandling1 as +--begin +--DECLARE cur1049 SCROLL CURSOR FAST_FORWARD READ_ONLY +--FOR SELECT c1 FROM t1049 +-- +--if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +--select @@trancount; +--end +-- +--GO +-- +--if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +--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 +--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 +--DROP TABLE t1049 +--GO +-- +-- +-- +--set xact_abort ON; +--GO +---- Executing test error_mapping.ErrorHandling10000000 +--CREATE TABLE t1049 (c1 INT) +--GO +-- +-- +--create procedure error_mapping.ErrorHandling1 as +--begin +--DECLARE cur1049 SCROLL CURSOR FAST_FORWARD READ_ONLY +--FOR SELECT c1 FROM t1049 +-- +--if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +--select @@trancount; +--end +-- +--GO +-- +--if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +--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 +--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 +--DROP TABLE t1049 +--GO +-- +-- +-- +-- +--set xact_abort OFF; +--GO +-- Error classification is done -- +CREATE TABLE t1049 (c1 INT) +GO + + + + +begin try +select 1 +DECLARE cur1049 SCROLL CURSOR FAST_FORWARD READ_ONLY +FOR SELECT c1 FROM t1049 +end try +begin catch + select xact_state(); +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 +~~ERROR (Code: 1049)~~ + +~~ERROR (Message: Mixing old and new syntax to specify cursor options is not allowed.)~~ + +DROP TABLE t1049 +GO + + + + +GO +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/sql_expected/1051_1.out b/contrib/test/JDBC/sql_expected/1051_1.out new file mode 100644 index 00000000000..7237bb46e2d --- /dev/null +++ b/contrib/test/JDBC/sql_expected/1051_1.out @@ -0,0 +1,75 @@ + +-- simple batch start +CREATE TABLE t1051 +( + c1 int +,c2 int NULL +) +GO + + + +CREATE PROC p1051_1 + @a CURSOR OUTPUT VARYING + AS +DECLARE c CURSOR + READ_ONLY +FOR +SELECT * FROM t1051 +GO +~~ERROR (Code: 1051)~~ + +~~ERROR (Message: Cursor parameters in a stored procedure must be declared with OUTPUT and VARYING options, and they must be specified in the order CURSOR VARYING OUTPUT.)~~ + +DROP TABLE t1051 +GO + + +SET XACT_ABORT ON; +GO + +begin transaction +GO +CREATE TABLE t1051 +( + c1 int +,c2 int NULL +) +GO + + + +CREATE PROC p1051_1 + @a CURSOR OUTPUT VARYING + AS +DECLARE c CURSOR + READ_ONLY +FOR +SELECT * FROM t1051 +GO +~~ERROR (Code: 1051)~~ + +~~ERROR (Message: Cursor parameters in a stored procedure must be declared with OUTPUT and VARYING options, and they must be specified in the order CURSOR VARYING OUTPUT.)~~ + + +if (@@trancount > 0) select cast('Does not respect xact_abort flag' as text) else select cast('Respects xact_abort flag' as text) +GO +~~START~~ +text +Does not respect xact_abort flag +~~END~~ + + +if (@@trancount > 0) rollback tran +GO + +DROP TABLE t1051 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the table 't1051', because it does not exist or you do not have permission.)~~ + + +SET XACT_ABORT OFF; +GO + diff --git a/contrib/test/JDBC/sql_expected/10610_1.out b/contrib/test/JDBC/sql_expected/10610_1.out new file mode 100644 index 00000000000..476ba898456 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/10610_1.out @@ -0,0 +1,311 @@ +# Executing test ErrorHandling1 +CREATE TABLE t10610( + c1 int, + c2 int +) +GO + +CREATE VIEW v10610 AS +SELECT c1, c2 +FROM t10610 +GO + + +create procedure ErrorHandling1 as +begin +CREATE INDEX i10610 +ON v10610 (c1) +WHERE c2 = 1 +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP VIEW v10610 +GO + +DROP TABLE t10610 +GO + + + +CREATE TABLE t10610( + c1 int, + c2 int +) +GO + +CREATE VIEW v10610 AS +SELECT c1, c2 +FROM t10610 +GO +begin transaction +GO +# Executing test ErrorHandling1 + +create procedure ErrorHandling1 as +begin +CREATE INDEX i10610 +ON v10610 (c1) +WHERE c2 = 1 +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +DROP VIEW v10610 +GO + +DROP TABLE t10610 +GO + + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE t10610( + c1 int, + c2 int +) +GO + +CREATE VIEW v10610 AS +SELECT c1, c2 +FROM t10610 +GO +begin transaction +GO +# Executing test ErrorHandling1 + +create procedure ErrorHandling1 as +begin +CREATE INDEX i10610 +ON v10610 (c1) +WHERE c2 = 1 +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +DROP VIEW v10610 +GO + +DROP TABLE t10610 +GO + +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Next portion is for runtime error -- +CREATE TABLE t10610( + c1 int, + c2 int +) +GO + +CREATE VIEW v10610 AS +SELECT c1, c2 +FROM t10610 +GO + + +create procedure ErrorHandling1 as +begin +CREATE INDEX i10610 +ON v10610 (c1) +WHERE c2 = 1 +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 10610)~~ + +~~ERROR (Message: Filtered index 'i10610' cannot be created on object 'v10610' because it is not a user table. Filtered indexes are only supported on tables. If you are trying to create a filtered index on a view, consider creating an indexed view with the filter expression incorporated in the view definition.)~~ + +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +DROP VIEW v10610 +GO + +DROP TABLE t10610 +GO + + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +CREATE TABLE t10610( + c1 int, + c2 int +) +GO + +CREATE VIEW v10610 AS +SELECT c1, c2 +FROM t10610 +GO + + +create procedure ErrorHandling1 as +begin +CREATE INDEX i10610 +ON v10610 (c1) +WHERE c2 = 1 +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 10610)~~ + +~~ERROR (Message: Filtered index 'i10610' cannot be created on object 'v10610' because it is not a user table. Filtered indexes are only supported on tables. If you are trying to create a filtered index on a view, consider creating an indexed view with the filter expression incorporated in the view definition.)~~ + +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +DROP VIEW v10610 +GO + +DROP TABLE t10610 +GO + + + + +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Error classification is done -- +CREATE TABLE t10610( + c1 int, + c2 int +) +GO + +CREATE VIEW v10610 AS +SELECT c1, c2 +FROM t10610 +GO + + +begin try +select 1 +CREATE INDEX i10610 +ON v10610 (c1) +WHERE c2 = 1 +end try +begin catch + select xact_state(); +end catch +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +int +1 +~~END~~ + +~~START~~ +smallint +0 +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling2', because it does not exist or you do not have permission.)~~ + +DROP VIEW v10610 +GO + +DROP TABLE t10610 +GO + + + diff --git a/contrib/test/JDBC/sql_expected/11700_1.out b/contrib/test/JDBC/sql_expected/11700_1.out new file mode 100644 index 00000000000..c5c8a6262c5 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/11700_1.out @@ -0,0 +1,232 @@ +# Executing test ErrorHandling1 +GO + + + +create procedure ErrorHandling1 as +begin +CREATE SEQUENCE s11700 + START WITH 1 + INCREMENT BY 0 +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +GO + + +GO +begin transaction +GO +# Executing test ErrorHandling1 + + +create procedure ErrorHandling1 as +begin +CREATE SEQUENCE s11700 + START WITH 1 + INCREMENT BY 0 +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "errorhandling1")~~ + + +GO +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +GO +begin transaction +GO +# Executing test ErrorHandling1 + + +create procedure ErrorHandling1 as +begin +CREATE SEQUENCE s11700 + START WITH 1 + INCREMENT BY 0 +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "errorhandling1")~~ + + +GO +GO +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Next portion is for runtime error -- +GO + + + +create procedure ErrorHandling1 as +begin +CREATE SEQUENCE s11700 + START WITH 1 + INCREMENT BY 0 +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 11700)~~ + +~~ERROR (Message: INCREMENT must not be zero)~~ + +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +GO + + + +create procedure ErrorHandling1 as +begin +CREATE SEQUENCE s11700 + START WITH 1 + INCREMENT BY 0 +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 11700)~~ + +~~ERROR (Message: INCREMENT must not be zero)~~ + +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +GO + + + +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Error classification is done -- +GO + + + +begin try +select 1 +CREATE SEQUENCE s11700 + START WITH 1 + INCREMENT BY 0 +end try +begin catch + select xact_state(); +end catch +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +int +1 +~~END~~ + +~~START~~ +smallint +0 +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "errorhandling1")~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "errorhandling2")~~ + + + diff --git a/contrib/test/JDBC/sql_expected/11701_1.out b/contrib/test/JDBC/sql_expected/11701_1.out new file mode 100644 index 00000000000..596b42822e1 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/11701_1.out @@ -0,0 +1,245 @@ +create schema error_mapping; +GO +-- Executing test error_mapping.ErrorHandling1 +GO + + + +create procedure error_mapping.ErrorHandling1 as +begin +CREATE SEQUENCE s11701 INCREMENT BY 6 + MINVALUE 5 + MAXVALUE 10 + +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 +GO + + +GO +begin transaction +GO + + +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +CREATE SEQUENCE s11701 INCREMENT BY 6 + MINVALUE 5 + MAXVALUE 10 + +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: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +GO +begin transaction +GO + + +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +CREATE SEQUENCE s11701 INCREMENT BY 6 + MINVALUE 5 + MAXVALUE 10 + +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: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +GO +set xact_abort OFF; +GO + +-- Next portion is for runtime error -- +-- Executing test error_mapping.ErrorHandling10000000 +GO + + + +create procedure error_mapping.ErrorHandling1 as +begin +CREATE SEQUENCE s11701 INCREMENT BY 6 + MINVALUE 5 + MAXVALUE 10 + +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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: 11701)~~ + +~~ERROR (Message: The absolute value of the increment for sequence object 's11701' must be less than or equal to the difference between the minimum and maximum value of the sequence object.)~~ + +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 +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +GO + + +set xact_abort ON; +GO +-- Executing test error_mapping.ErrorHandling10000000 +GO + + + +create procedure error_mapping.ErrorHandling1 as +begin +CREATE SEQUENCE s11701 INCREMENT BY 6 + MINVALUE 5 + MAXVALUE 10 + +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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: 11701)~~ + +~~ERROR (Message: The absolute value of the increment for sequence object 's11701' must be less than or equal to the difference between the minimum and maximum value of the sequence object.)~~ + +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 +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +GO + + + +set xact_abort OFF; +GO + +-- Error classification is done -- +-- Executing test error_mapping.ErrorHandling10000000 +GO + + + +begin try +select 1 +CREATE SEQUENCE s11701 INCREMENT BY 6 + MINVALUE 5 + MAXVALUE 10 + +end try +begin catch + select xact_state(); +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 +~~START~~ +int +1 +~~END~~ + +~~START~~ +smallint +0 +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling2', because it does not exist or you do not have permission.)~~ + +GO + + + +GO +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/sql_expected/11702_1.out b/contrib/test/JDBC/sql_expected/11702_1.out new file mode 100644 index 00000000000..8cafd718be0 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/11702_1.out @@ -0,0 +1,331 @@ + +-- simple batch start +GO +CREATE SEQUENCE seq11702 AS bit +GO +~~ERROR (Code: 11702)~~ + +~~ERROR (Message: The sequence object 'seq11702' must be of data type int, bigint, smallint, tinyint, or decimal or numeric with a scale of 0, or any user-defined data type that is based on one of the above integer data types.)~~ + +GO + +begin transaction +GO +GO +CREATE SEQUENCE seq11702 AS bit +GO +~~ERROR (Code: 11702)~~ + +~~ERROR (Message: The sequence object 'seq11702' must be of data type int, bigint, smallint, tinyint, or decimal or numeric with a scale of 0, or any user-defined data type that is based on one of the above integer data types.)~~ + + + +-- Below output is only applicable if query is special case. for example, CREATE/ALTER TRIGGER, CREATE/ALTER FUNCTION, CREATE/ALTER PROC, CREATE/ALTER VIEW etc +if (@@trancount > 0) select cast('compile time error' as text) else select cast('runtime error' as text) +GO +~~START~~ +text +runtime error +~~END~~ + + +if (@@trancount > 0) rollback tran +GO + +GO + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + +GO +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +CREATE SEQUENCE seq11702 AS bit +end +GO + +GO + +create table error_mapping.temp2 (a int) +GO + +GO +insert into error_mapping.temp2 values(1) +CREATE SEQUENCE seq11702 AS bit +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 11702)~~ + +~~ERROR (Message: The sequence object 'seq11702' must be of data type int, bigint, smallint, tinyint, or decimal or numeric with a scale of 0, or any user-defined data type that is based on one of the above integer data types.)~~ + + +GO + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + +GO +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 11702)~~ + +~~ERROR (Message: The sequence object 'seq11702' must be of data type int, bigint, smallint, tinyint, or decimal or numeric with a scale of 0, or any user-defined data type that is based on one of the above integer data types.)~~ + + +GO + +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 + +-- Parse analysis phase end +GO + + +-- compile time error portion +-- Executing test error_mapping.ErrorHandling1 +GO + + +create procedure error_mapping.ErrorHandling1 as +begin +CREATE SEQUENCE seq11702 AS bit +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 +GO + + +GO +begin transaction +GO + +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +CREATE SEQUENCE seq11702 AS bit +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: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +GO +begin transaction +GO + +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +CREATE SEQUENCE seq11702 AS bit +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: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +GO +set xact_abort OFF; +GO + + +-- comiple time error portion end -- +-- Next portion is for runtime error -- +-- Executing test error_mapping.ErrorHandling10000000 +GO + + +create procedure error_mapping.ErrorHandling1 as +begin +CREATE SEQUENCE seq11702 AS bit +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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: 11702)~~ + +~~ERROR (Message: The sequence object 'seq11702' must be of data type int, bigint, smallint, tinyint, or decimal or numeric with a scale of 0, or any user-defined data type that is based on one of the above integer data types.)~~ + +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 +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +GO + + +set xact_abort ON; +GO +-- Executing test error_mapping.ErrorHandling10000000 +GO + + +create procedure error_mapping.ErrorHandling1 as +begin +CREATE SEQUENCE seq11702 AS bit +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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: 11702)~~ + +~~ERROR (Message: The sequence object 'seq11702' must be of data type int, bigint, smallint, tinyint, or decimal or numeric with a scale of 0, or any user-defined data type that is based on one of the above integer data types.)~~ + +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 +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +GO + + + +set xact_abort OFF; +GO + + +-- Error classification is done -- +-- Executing test error_mapping.ErrorHandling10000000 +GO + + +begin try +select 1 +CREATE SEQUENCE seq11702 AS bit +end try +begin catch + select xact_state(); +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 +~~START~~ +int +1 +~~END~~ + +~~START~~ +smallint +0 +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling2', because it does not exist or you do not have permission.)~~ + +GO + + + +GO +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/sql_expected/11703_1.out b/contrib/test/JDBC/sql_expected/11703_1.out new file mode 100644 index 00000000000..2c218a1d101 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/11703_1.out @@ -0,0 +1,371 @@ + +-- simple batch start +GO + +CREATE SEQUENCE s11703 + START WITH 11 + MINVALUE 5 + MAXVALUE 10 +GO +~~ERROR (Code: 11703)~~ + +~~ERROR (Message: The start value for sequence object 's11703' must be between the minimum and maximum value of the sequence object.)~~ + +GO + +begin transaction +GO +GO + +CREATE SEQUENCE s11703 + START WITH 11 + MINVALUE 5 + MAXVALUE 10 +GO +~~ERROR (Code: 11703)~~ + +~~ERROR (Message: The start value for sequence object 's11703' must be between the minimum and maximum value of the sequence object.)~~ + + + +-- Below output is only applicable if query is special case. for example, CREATE/ALTER TRIGGER, CREATE/ALTER FUNCTION, CREATE/ALTER PROC, CREATE/ALTER VIEW etc +if (@@trancount > 0) select cast('compile time error' as text) else select cast('runtime error' as text) +GO +~~START~~ +text +runtime error +~~END~~ + + +if (@@trancount > 0) rollback tran +GO + +GO + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + +GO + +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +CREATE SEQUENCE s11703 + START WITH 11 + MINVALUE 5 + MAXVALUE 10 +end +GO + +GO + +create table error_mapping.temp2 (a int) +GO + +GO + +insert into error_mapping.temp2 values(1) +CREATE SEQUENCE s11703 + START WITH 11 + MINVALUE 5 + MAXVALUE 10 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 11703)~~ + +~~ERROR (Message: The start value for sequence object 's11703' must be between the minimum and maximum value of the sequence object.)~~ + + +GO + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + +GO +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 11703)~~ + +~~ERROR (Message: The start value for sequence object 's11703' must be between the minimum and maximum value of the sequence object.)~~ + + +GO + +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 + +-- Parse analysis phase end +GO + + +-- compile time error portion +-- Executing test error_mapping.ErrorHandling1 +GO + + + +create procedure error_mapping.ErrorHandling1 as +begin +CREATE SEQUENCE s11703 + START WITH 11 + MINVALUE 5 + MAXVALUE 10 +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 +GO + + +GO +begin transaction +GO + + +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +CREATE SEQUENCE s11703 + START WITH 11 + MINVALUE 5 + MAXVALUE 10 +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: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +GO +begin transaction +GO + + +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +CREATE SEQUENCE s11703 + START WITH 11 + MINVALUE 5 + MAXVALUE 10 +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: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +GO +set xact_abort OFF; +GO + + +-- comiple time error portion end -- +-- Next portion is for runtime error -- +-- Executing test error_mapping.ErrorHandling10000000 +GO + + + +create procedure error_mapping.ErrorHandling1 as +begin +CREATE SEQUENCE s11703 + START WITH 11 + MINVALUE 5 + MAXVALUE 10 +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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: 11703)~~ + +~~ERROR (Message: The start value for sequence object 's11703' must be between the minimum and maximum value of the sequence object.)~~ + +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 +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +GO + + +set xact_abort ON; +GO +-- Executing test error_mapping.ErrorHandling10000000 +GO + + + +create procedure error_mapping.ErrorHandling1 as +begin +CREATE SEQUENCE s11703 + START WITH 11 + MINVALUE 5 + MAXVALUE 10 +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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: 11703)~~ + +~~ERROR (Message: The start value for sequence object 's11703' must be between the minimum and maximum value of the sequence object.)~~ + +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 +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +GO + + + +set xact_abort OFF; +GO + + +-- Error classification is done -- +-- Executing test error_mapping.ErrorHandling10000000 +GO + + + +begin try +select 1 +CREATE SEQUENCE s11703 + START WITH 11 + MINVALUE 5 + MAXVALUE 10 +end try +begin catch + select xact_state(); +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 +~~START~~ +int +1 +~~END~~ + +~~START~~ +smallint +0 +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling2', because it does not exist or you do not have permission.)~~ + +GO + + + +GO +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/sql_expected/11703_2.out b/contrib/test/JDBC/sql_expected/11703_2.out new file mode 100644 index 00000000000..6d33548304c --- /dev/null +++ b/contrib/test/JDBC/sql_expected/11703_2.out @@ -0,0 +1,371 @@ + +-- simple batch start +GO + +CREATE SEQUENCE s11703 + START WITH 1 + MINVALUE 5 + MAXVALUE 10 +GO +~~ERROR (Code: 11703)~~ + +~~ERROR (Message: The start value for sequence object 's11703' must be between the minimum and maximum value of the sequence object.)~~ + +GO + +begin transaction +GO +GO + +CREATE SEQUENCE s11703 + START WITH 1 + MINVALUE 5 + MAXVALUE 10 +GO +~~ERROR (Code: 11703)~~ + +~~ERROR (Message: The start value for sequence object 's11703' must be between the minimum and maximum value of the sequence object.)~~ + + + +-- Below output is only applicable if query is special case. for example, CREATE/ALTER TRIGGER, CREATE/ALTER FUNCTION, CREATE/ALTER PROC, CREATE/ALTER VIEW etc +if (@@trancount > 0) select cast('compile time error' as text) else select cast('runtime error' as text) +GO +~~START~~ +text +runtime error +~~END~~ + + +if (@@trancount > 0) rollback tran +GO + +GO + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + +GO + +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +CREATE SEQUENCE s11703 + START WITH 1 + MINVALUE 5 + MAXVALUE 10 +end +GO + +GO + +create table error_mapping.temp2 (a int) +GO + +GO + +insert into error_mapping.temp2 values(1) +CREATE SEQUENCE s11703 + START WITH 1 + MINVALUE 5 + MAXVALUE 10 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 11703)~~ + +~~ERROR (Message: The start value for sequence object 's11703' must be between the minimum and maximum value of the sequence object.)~~ + + +GO + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + +GO +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 11703)~~ + +~~ERROR (Message: The start value for sequence object 's11703' must be between the minimum and maximum value of the sequence object.)~~ + + +GO + +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 + +-- Parse analysis phase end +GO + + +-- compile time error portion +-- Executing test error_mapping.ErrorHandling1 +GO + + + +create procedure error_mapping.ErrorHandling1 as +begin +CREATE SEQUENCE s11703 + START WITH 1 + MINVALUE 5 + MAXVALUE 10 +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 +GO + + +GO +begin transaction +GO + + +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +CREATE SEQUENCE s11703 + START WITH 1 + MINVALUE 5 + MAXVALUE 10 +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: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +GO +begin transaction +GO + + +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +CREATE SEQUENCE s11703 + START WITH 1 + MINVALUE 5 + MAXVALUE 10 +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: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +GO +set xact_abort OFF; +GO + + +-- comiple time error portion end -- +-- Next portion is for runtime error -- +-- Executing test error_mapping.ErrorHandling10000000 +GO + + + +create procedure error_mapping.ErrorHandling1 as +begin +CREATE SEQUENCE s11703 + START WITH 1 + MINVALUE 5 + MAXVALUE 10 +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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: 11703)~~ + +~~ERROR (Message: The start value for sequence object 's11703' must be between the minimum and maximum value of the sequence object.)~~ + +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 +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +GO + + +set xact_abort ON; +GO +-- Executing test error_mapping.ErrorHandling10000000 +GO + + + +create procedure error_mapping.ErrorHandling1 as +begin +CREATE SEQUENCE s11703 + START WITH 1 + MINVALUE 5 + MAXVALUE 10 +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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: 11703)~~ + +~~ERROR (Message: The start value for sequence object 's11703' must be between the minimum and maximum value of the sequence object.)~~ + +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 +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +GO + + + +set xact_abort OFF; +GO + + +-- Error classification is done -- +-- Executing test error_mapping.ErrorHandling10000000 +GO + + + +begin try +select 1 +CREATE SEQUENCE s11703 + START WITH 1 + MINVALUE 5 + MAXVALUE 10 +end try +begin catch + select xact_state(); +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 +~~START~~ +int +1 +~~END~~ + +~~START~~ +smallint +0 +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling2', because it does not exist or you do not have permission.)~~ + +GO + + + +GO +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/sql_expected/11705_1.out b/contrib/test/JDBC/sql_expected/11705_1.out new file mode 100644 index 00000000000..52d279bd657 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/11705_1.out @@ -0,0 +1,239 @@ +# Executing test ErrorHandling1 +GO + + + +create procedure ErrorHandling1 as +begin +CREATE SEQUENCE s11705 + increment by 1 + MINVALUE 10 + MAXVALUE 5 +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +GO + + +GO +begin transaction +GO +# Executing test ErrorHandling1 + + +create procedure ErrorHandling1 as +begin +CREATE SEQUENCE s11705 + increment by 1 + MINVALUE 10 + MAXVALUE 5 +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +GO +begin transaction +GO +# Executing test ErrorHandling1 + + +create procedure ErrorHandling1 as +begin +CREATE SEQUENCE s11705 + increment by 1 + MINVALUE 10 + MAXVALUE 5 +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +GO +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Next portion is for runtime error -- +GO + + + +create procedure ErrorHandling1 as +begin +CREATE SEQUENCE s11705 + increment by 1 + MINVALUE 10 + MAXVALUE 5 +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 11705)~~ + +~~ERROR (Message: The minimum value for sequence object 's11705' must be less than its maximum value.)~~ + +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +GO + + + +create procedure ErrorHandling1 as +begin +CREATE SEQUENCE s11705 + increment by 1 + MINVALUE 10 + MAXVALUE 5 +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 11705)~~ + +~~ERROR (Message: The minimum value for sequence object 's11705' must be less than its maximum value.)~~ + +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +GO + + + +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Error classification is done -- +GO + + + +begin try +select 1 +CREATE SEQUENCE s11705 + increment by 1 + MINVALUE 10 + MAXVALUE 5 +end try +begin catch + select xact_state(); +end catch +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +int +1 +~~END~~ + +~~START~~ +smallint +0 +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling2', because it does not exist or you do not have permission.)~~ + +GO + + diff --git a/contrib/test/JDBC/sql_expected/11706_1.out b/contrib/test/JDBC/sql_expected/11706_1.out new file mode 100644 index 00000000000..4cb9ab10038 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/11706_1.out @@ -0,0 +1,257 @@ +# Executing test ErrorHandling1 +GO + + + + + +create procedure ErrorHandling1 as +begin +CREATE SEQUENCE s11706 + AS INT + START WITH 5 + INCREMENT BY 1 + CACHE 0 +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +GO + + +GO + +begin transaction +GO +# Executing test ErrorHandling1 + + + +create procedure ErrorHandling1 as +begin +CREATE SEQUENCE s11706 + AS INT + START WITH 5 + INCREMENT BY 1 + CACHE 0 +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +GO + +begin transaction +GO +# Executing test ErrorHandling1 + + + +create procedure ErrorHandling1 as +begin +CREATE SEQUENCE s11706 + AS INT + START WITH 5 + INCREMENT BY 1 + CACHE 0 +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +GO +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Next portion is for runtime error -- +GO + + + + + +create procedure ErrorHandling1 as +begin +CREATE SEQUENCE s11706 + AS INT + START WITH 5 + INCREMENT BY 1 + CACHE 0 +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 11706)~~ + +~~ERROR (Message: The cache size for sequence object 's11706' must be greater than 0.)~~ + +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +GO + + + + + +create procedure ErrorHandling1 as +begin +CREATE SEQUENCE s11706 + AS INT + START WITH 5 + INCREMENT BY 1 + CACHE 0 +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 11706)~~ + +~~ERROR (Message: The cache size for sequence object 's11706' must be greater than 0.)~~ + +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +GO + + + +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Error classification is done -- +GO + + + + + +begin try +select 1 +CREATE SEQUENCE s11706 + AS INT + START WITH 5 + INCREMENT BY 1 + CACHE 0 +end try +begin catch + select xact_state(); +end catch +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +int +1 +~~END~~ + +~~START~~ +smallint +0 +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling2', because it does not exist or you do not have permission.)~~ + +GO + + diff --git a/contrib/test/JDBC/sql_expected/11708_1.out b/contrib/test/JDBC/sql_expected/11708_1.out new file mode 100644 index 00000000000..91aaa7d317e --- /dev/null +++ b/contrib/test/JDBC/sql_expected/11708_1.out @@ -0,0 +1,245 @@ +# Executing test ErrorHandling1 +GO + + +create procedure ErrorHandling1 as +begin +CREATE SEQUENCE seq_11708 +AS [tinyint] +START WITH 1 +INCREMENT BY 1 +MINVALUE 1 +MAXVALUE 256 +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +GO + + +GO +begin transaction +GO +# Executing test ErrorHandling1 + +create procedure ErrorHandling1 as +begin +CREATE SEQUENCE seq_11708 +AS [tinyint] +START WITH 1 +INCREMENT BY 1 +MINVALUE 1 +MAXVALUE 256 +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +GO +begin transaction +GO +# Executing test ErrorHandling1 + +create procedure ErrorHandling1 as +begin +CREATE SEQUENCE seq_11708 +AS [tinyint] +START WITH 1 +INCREMENT BY 1 +MINVALUE 1 +MAXVALUE 256 +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +GO +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Next portion is for runtime error -- +GO + + +create procedure ErrorHandling1 as +begin +CREATE SEQUENCE seq_11708 +AS [tinyint] +START WITH 1 +INCREMENT BY 1 +MINVALUE 1 +MAXVALUE 256 +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 11708)~~ + +~~ERROR (Message: An invalid value was specified for argument 'MAXVALUE' for the given data type.)~~ + +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +GO + + +create procedure ErrorHandling1 as +begin +CREATE SEQUENCE seq_11708 +AS [tinyint] +START WITH 1 +INCREMENT BY 1 +MINVALUE 1 +MAXVALUE 256 +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 11708)~~ + +~~ERROR (Message: An invalid value was specified for argument 'MAXVALUE' for the given data type.)~~ + +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +GO + + + +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Error classification is done -- +GO + + +begin try +select 1 +CREATE SEQUENCE seq_11708 +AS [tinyint] +START WITH 1 +INCREMENT BY 1 +MINVALUE 1 +MAXVALUE 256 +end try +begin catch + select xact_state(); +end catch +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +int +1 +~~END~~ + +~~START~~ +smallint +0 +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling2', because it does not exist or you do not have permission.)~~ + +GO + + diff --git a/contrib/test/JDBC/sql_expected/132_1.out b/contrib/test/JDBC/sql_expected/132_1.out new file mode 100644 index 00000000000..215f7176d92 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/132_1.out @@ -0,0 +1,455 @@ + + + +-- simple batch start +--132 Label already declared +--Could not find this PG error in excel file +--------------------------------------------------------------------------- +--Pre +GO +--------------------------------------------------------------------------- +--Generate the error +lbl: +lbl: +GO +~~ERROR (Code: 132)~~ + +~~ERROR (Message: The label 'lbl' has already been declared. Label names must be unique within a query batch or stored procedure.)~~ + +--------------------------------------------------------------------------- +--Post +GO + +begin transaction +GO + + +--132 Label already declared +--Could not find this PG error in excel file +--------------------------------------------------------------------------- +--Pre +GO +--------------------------------------------------------------------------- +--Generate the error +lbl: +lbl: +GO +~~ERROR (Code: 132)~~ + +~~ERROR (Message: The label 'lbl' has already been declared. Label names must be unique within a query batch or stored procedure.)~~ + + + +-- Below output is only applicable if query is special case. for example, CREATE/ALTER TRIGGER, CREATE/ALTER FUNCTION, CREATE/ALTER PROC, CREATE/ALTER VIEW etc +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 + +--------------------------------------------------------------------------- +--Post +GO + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + + + +--132 Label already declared +--Could not find this PG error in excel file +--------------------------------------------------------------------------- +--Pre +GO +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +--------------------------------------------------------------------------- +--Generate the error +lbl: +lbl: +end +GO +~~ERROR (Code: 132)~~ + +~~ERROR (Message: The label 'lbl' has already been declared. Label names must be unique within a query batch or stored procedure.)~~ + + +--------------------------------------------------------------------------- +--Post +GO + +create table error_mapping.temp2 (a int) +GO + + + +--132 Label already declared +--Could not find this PG error in excel file +--------------------------------------------------------------------------- +--Pre +GO +insert into error_mapping.temp2 values(1) +--------------------------------------------------------------------------- +--Generate the error +lbl: +lbl: +GO +~~ERROR (Code: 132)~~ + +~~ERROR (Message: The label 'lbl' has already been declared. Label names must be unique within a query batch or stored procedure.)~~ + + +--------------------------------------------------------------------------- +--Post +GO + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + + + +--132 Label already declared +--Could not find this PG error in excel file +--------------------------------------------------------------------------- +--Pre +GO +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2812)~~ + +~~ERROR (Message: Could not find stored procedure 'error_mapping.ErrorHandling1'.)~~ + + +--------------------------------------------------------------------------- +--Post +GO + +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 +~~START~~ +text +parse analysis phase error +~~END~~ + + +drop procedure error_mapping.ErrorHandling1; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + +drop table error_mapping.temp1; +drop table error_mapping.temp2; +drop table error_mapping.temp3; +GO + +-- Parse analysis phase end +GO + + + + +-- compile time error portion +-- Executing test error_mapping.ErrorHandling1 +--132 Label already declared +--Could not find this PG error in excel file +--------------------------------------------------------------------------- +--Pre +GO + + +create procedure error_mapping.ErrorHandling1 as +begin +--------------------------------------------------------------------------- +--Generate the error +lbl: +lbl: +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO +~~ERROR (Code: 132)~~ + +~~ERROR (Message: The label 'lbl' has already been declared. Label names must be unique within a query batch or stored procedure.)~~ + + +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 +~~START~~ +text +Compile time error +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + +--------------------------------------------------------------------------- +--Post +GO + + + + +--132 Label already declared +--Could not find this PG error in excel file +--------------------------------------------------------------------------- +--Pre +GO +begin transaction +GO + +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +--------------------------------------------------------------------------- +--Generate the error +lbl: +lbl: +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +end +GO +~~ERROR (Code: 132)~~ + +~~ERROR (Message: The label 'lbl' has already been declared. Label names must be unique within a query batch or stored procedure.)~~ + + +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 +~~START~~ +text +BATCH ONLY TERMINATING +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +--------------------------------------------------------------------------- +--Post +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO + + +--132 Label already declared +--Could not find this PG error in excel file +--------------------------------------------------------------------------- +--Pre +GO +begin transaction +GO + +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +--------------------------------------------------------------------------- +--Generate the error +lbl: +lbl: +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +end +GO +~~ERROR (Code: 132)~~ + +~~ERROR (Message: The label 'lbl' has already been declared. Label names must be unique within a query batch or stored procedure.)~~ + + +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 +~~START~~ +text +BATCH ONLY TERMINATING +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +--------------------------------------------------------------------------- +--Post +GO +set xact_abort OFF; +GO + + + +-- comiple time error portion end -- +---- Next portion is for runtime error -- +-- +---- Executing test error_mapping.ErrorHandling10000000 +----132 Label already declared +-- +----Could not find this PG error in excel file +-- +----------------------------------------------------------------------------- +----Pre +--GO +-- +--create procedure error_mapping.ErrorHandling1 as +--begin +----------------------------------------------------------------------------- +----Generate the error +--lbl: +--lbl: +--if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +--select @@trancount; +--end +-- +--GO +-- +--if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +--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 +--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 +----------------------------------------------------------------------------- +----Post +--GO +-- +-- +--set xact_abort ON; +--GO +---- Executing test error_mapping.ErrorHandling10000000 +----132 Label already declared +-- +----Could not find this PG error in excel file +-- +----------------------------------------------------------------------------- +----Pre +--GO +-- +--create procedure error_mapping.ErrorHandling1 as +--begin +----------------------------------------------------------------------------- +----Generate the error +--lbl: +--lbl: +--if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +--select @@trancount; +--end +-- +--GO +-- +--if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +--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 +--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 +----------------------------------------------------------------------------- +----Post +--GO +-- +-- +-- +--set xact_abort OFF; +--GO +-- +-- Error classification is done -- +-- Executing test error_mapping.ErrorHandling10000000 +--132 Label already declared +--------------------------------------------------------------------------- +--Pre +GO + + +begin try +select 1 +--------------------------------------------------------------------------- +--Generate the error +lbl: +lbl: +end try +begin catch + select xact_state(); +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 +----------------------------------------------------------------------------- +----Post +--GO +-- +-- +-- +GO +~~ERROR (Code: 132)~~ + +~~ERROR (Message: The label 'lbl' has already been declared. Label names must be unique within a query batch or stored procedure.)~~ + +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/sql_expected/133_1.out b/contrib/test/JDBC/sql_expected/133_1.out new file mode 100644 index 00000000000..c3303084ac7 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/133_1.out @@ -0,0 +1,457 @@ + + + +-- simple batch start +--133 Reference non-existing label in GOTO +--Could not find this PG error in excel file +--------------------------------------------------------------------------- +--Pre +GO +--------------------------------------------------------------------------- +--Generate the error +GOTO lbl2 +blb3: +GO +~~ERROR (Code: 133)~~ + +~~ERROR (Message: A GOTO statement references the label 'lbl2' but the label has not been declared.)~~ + +--------------------------------------------------------------------------- +--Post +GO + +begin transaction +GO + + +--133 Reference non-existing label in GOTO +--Could not find this PG error in excel file +--------------------------------------------------------------------------- +--Pre +GO +--------------------------------------------------------------------------- +--Generate the error +GOTO lbl2 +blb3: +GO +~~ERROR (Code: 133)~~ + +~~ERROR (Message: A GOTO statement references the label 'lbl2' but the label has not been declared.)~~ + + + +-- Below output is only applicable if query is special case. for example, CREATE/ALTER TRIGGER, CREATE/ALTER FUNCTION, CREATE/ALTER PROC, CREATE/ALTER VIEW etc +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 + +--------------------------------------------------------------------------- +--Post +GO + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + + + +--133 Reference non-existing label in GOTO +--Could not find this PG error in excel file +--------------------------------------------------------------------------- +--Pre +GO +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +--------------------------------------------------------------------------- +--Generate the error +GOTO lbl2 +blb3: +end +GO +~~ERROR (Code: 133)~~ + +~~ERROR (Message: A GOTO statement references the label 'lbl2' but the label has not been declared.)~~ + + +--------------------------------------------------------------------------- +--Post +GO + +create table error_mapping.temp2 (a int) +GO + + + +--133 Reference non-existing label in GOTO +--Could not find this PG error in excel file +--------------------------------------------------------------------------- +--Pre +GO +insert into error_mapping.temp2 values(1) +--------------------------------------------------------------------------- +--Generate the error +GOTO lbl2 +blb3: +GO +~~ERROR (Code: 133)~~ + +~~ERROR (Message: A GOTO statement references the label 'lbl2' but the label has not been declared.)~~ + + +--------------------------------------------------------------------------- +--Post +GO + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + + + +--133 Reference non-existing label in GOTO +--Could not find this PG error in excel file +--------------------------------------------------------------------------- +--Pre +GO +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2812)~~ + +~~ERROR (Message: Could not find stored procedure 'error_mapping.ErrorHandling1'.)~~ + + +--------------------------------------------------------------------------- +--Post +GO + +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 +~~START~~ +text +parse analysis phase error +~~END~~ + + +drop procedure error_mapping.ErrorHandling1; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + +drop table error_mapping.temp1; +drop table error_mapping.temp2; +drop table error_mapping.temp3; +GO + +-- Parse analysis phase end +GO + + + + +-- compile time error portion +-- Executing test error_mapping.ErrorHandling1 +--133 Reference non-existing label in GOTO +--Could not find this PG error in excel file +--------------------------------------------------------------------------- +--Pre +GO + + +create procedure error_mapping.ErrorHandling1 as +begin +--------------------------------------------------------------------------- +--Generate the error +GOTO lbl2 +blb3: +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO +~~ERROR (Code: 133)~~ + +~~ERROR (Message: A GOTO statement references the label 'lbl2' but the label has not been declared.)~~ + + +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 +~~START~~ +text +Compile time error +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + +--------------------------------------------------------------------------- +--Post +GO + + + + +--133 Reference non-existing label in GOTO +--Could not find this PG error in excel file +--------------------------------------------------------------------------- +--Pre +GO +begin transaction +GO + +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +--------------------------------------------------------------------------- +--Generate the error +GOTO lbl2 +blb3: +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +end +GO +~~ERROR (Code: 133)~~ + +~~ERROR (Message: A GOTO statement references the label 'lbl2' but the label has not been declared.)~~ + + +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 +~~START~~ +text +BATCH ONLY TERMINATING +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +--------------------------------------------------------------------------- +--Post +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO + + +--133 Reference non-existing label in GOTO +--Could not find this PG error in excel file +--------------------------------------------------------------------------- +--Pre +GO +begin transaction +GO + +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +--------------------------------------------------------------------------- +--Generate the error +GOTO lbl2 +blb3: +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +end +GO +~~ERROR (Code: 133)~~ + +~~ERROR (Message: A GOTO statement references the label 'lbl2' but the label has not been declared.)~~ + + +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 +~~START~~ +text +BATCH ONLY TERMINATING +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +--------------------------------------------------------------------------- +--Post +GO +set xact_abort OFF; +GO + + + + + + + +-- comiple time error portion end -- +-- Next portion is for runtime error -- +-- Executing test error_mapping.ErrorHandling10000000 +--133 Reference non-existing label in GOTO +--Could not find this PG error in excel file +--------------------------------------------------------------------------- +--Pre +--GO +-- +--create procedure error_mapping.ErrorHandling1 as +--begin +----------------------------------------------------------------------------- +----Generate the error +--GOTO lbl2 +--blb3: +--if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +--select @@trancount; +--end +-- +--GO +-- +--if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +--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 +--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 +----------------------------------------------------------------------------- +----Post +--GO +-- +-- +--set xact_abort ON; +--GO +---- Executing test error_mapping.ErrorHandling10000000 +----133 Reference non-existing label in GOTO +-- +----Could not find this PG error in excel file +-- +----------------------------------------------------------------------------- +----Pre +--GO +-- +--create procedure error_mapping.ErrorHandling1 as +--begin +----------------------------------------------------------------------------- +----Generate the error +--GOTO lbl2 +--blb3: +--if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +--select @@trancount; +--end +-- +--GO +-- +--if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +--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 +--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 +----------------------------------------------------------------------------- +----Post +--GO +-- +-- +-- +--set xact_abort OFF; +--GO +-- +-- Error classification is done -- +-- Executing test error_mapping.ErrorHandling10000000 +--133 Reference non-existing label in GOTO +--Could not find this PG error in excel file +--------------------------------------------------------------------------- +--Pre +GO + + +begin try +select 1 +--------------------------------------------------------------------------- +--Generate the error +GOTO lbl2 +blb3: +end try +begin catch + select xact_state(); +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 +----------------------------------------------------------------------------- +----Post +--GO +-- +-- +-- +GO +~~ERROR (Code: 133)~~ + +~~ERROR (Message: A GOTO statement references the label 'lbl2' but the label has not been declared.)~~ + +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/sql_expected/134_1.out b/contrib/test/JDBC/sql_expected/134_1.out new file mode 100644 index 00000000000..ec5d3c03708 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/134_1.out @@ -0,0 +1,444 @@ + + +-- simple batch start +--134 Declare same variable name twice +--------------------------------------------------------------------------- +--Pre +GO + +--------------------------------------------------------------------------- +--Generate the error +--CHECK constraint conflict, when adding constraint +DECLARE @a int; +DECLARE @a int; +GO +~~ERROR (Code: 134)~~ + +~~ERROR (Message: The variable name '@a' has already been declared. Variable names must be unique within a query batch or stored procedure.)~~ + +--Post +GO + +begin transaction +GO + +--134 Declare same variable name twice +--------------------------------------------------------------------------- +--Pre +GO + +--------------------------------------------------------------------------- +--Generate the error +--CHECK constraint conflict, when adding constraint +DECLARE @a int; +DECLARE @a int; +GO +~~ERROR (Code: 134)~~ + +~~ERROR (Message: The variable name '@a' has already been declared. Variable names must be unique within a query batch or stored procedure.)~~ + + + +-- Below output is only applicable if query is special case. for example, CREATE/ALTER TRIGGER, CREATE/ALTER FUNCTION, CREATE/ALTER PROC, CREATE/ALTER VIEW etc +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 + +--Post +GO + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + + +--134 Declare same variable name twice +--------------------------------------------------------------------------- +--Pre +GO + +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +--------------------------------------------------------------------------- +--Generate the error +--CHECK constraint conflict, when adding constraint +DECLARE @a int; +DECLARE @a int; +end +GO +~~ERROR (Code: 134)~~ + +~~ERROR (Message: The variable name '@a' has already been declared. Variable names must be unique within a query batch or stored procedure.)~~ + + +--Post +GO + +create table error_mapping.temp2 (a int) +GO + + +--134 Declare same variable name twice +--------------------------------------------------------------------------- +--Pre +GO + +insert into error_mapping.temp2 values(1) +--------------------------------------------------------------------------- +--Generate the error +--CHECK constraint conflict, when adding constraint +DECLARE @a int; +DECLARE @a int; +GO +~~ERROR (Code: 134)~~ + +~~ERROR (Message: The variable name '@a' has already been declared. Variable names must be unique within a query batch or stored procedure.)~~ + + +--Post +GO + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + + +--134 Declare same variable name twice +--------------------------------------------------------------------------- +--Pre +GO +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2812)~~ + +~~ERROR (Message: Could not find stored procedure 'error_mapping.ErrorHandling1'.)~~ + + +--Post +GO + +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 +~~START~~ +text +parse analysis phase error +~~END~~ + + +drop procedure error_mapping.ErrorHandling1; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + +drop table error_mapping.temp1; +drop table error_mapping.temp2; +drop table error_mapping.temp3; +GO + +-- Parse analysis phase end +GO + + + +-- compile time error portion +-- Executing test error_mapping.ErrorHandling1 +--134 Declare same variable name twice +--------------------------------------------------------------------------- +--Pre +GO + + + +create procedure error_mapping.ErrorHandling1 as +begin +--------------------------------------------------------------------------- +--Generate the error +--CHECK constraint conflict, when adding constraint +DECLARE @a int; +DECLARE @a int; +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO +~~ERROR (Code: 134)~~ + +~~ERROR (Message: The variable name '@a' has already been declared. Variable names must be unique within a query batch or stored procedure.)~~ + + +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 +~~START~~ +text +Compile time error +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + +--Post +GO + + + +--134 Declare same variable name twice +--------------------------------------------------------------------------- +--Pre +GO +begin transaction +GO + + +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +--------------------------------------------------------------------------- +--Generate the error +--CHECK constraint conflict, when adding constraint +DECLARE @a int; +DECLARE @a int; +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +end +GO +~~ERROR (Code: 134)~~ + +~~ERROR (Message: The variable name '@a' has already been declared. Variable names must be unique within a query batch or stored procedure.)~~ + + +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 +~~START~~ +text +BATCH ONLY TERMINATING +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +--Post +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO + +--134 Declare same variable name twice +--------------------------------------------------------------------------- +--Pre +GO +begin transaction +GO + + +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +--------------------------------------------------------------------------- +--Generate the error +--CHECK constraint conflict, when adding constraint +DECLARE @a int; +DECLARE @a int; +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +end +GO +~~ERROR (Code: 134)~~ + +~~ERROR (Message: The variable name '@a' has already been declared. Variable names must be unique within a query batch or stored procedure.)~~ + + +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 +~~START~~ +text +BATCH ONLY TERMINATING +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +--Post +GO +set xact_abort OFF; +GO + + + + + +-- comiple time error portion end -- +-- Next portion is for runtime error -- +-- Executing test error_mapping.ErrorHandling10000000 +--134 Declare same variable name twice +--------------------------------------------------------------------------- +--Pre +--GO +-- +--create procedure error_mapping.ErrorHandling1 as +--begin +----------------------------------------------------------------------------- +----Generate the error +-- +----CHECK constraint conflict, when adding constraint +--DECLARE @a int; +--DECLARE @a int; +--if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +--select @@trancount; +--end +-- +--GO +-- +--if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +--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 +--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 +----Post +--GO +-- +-- +--set xact_abort ON; +--GO +---- Executing test error_mapping.ErrorHandling10000000 +----134 Declare same variable name twice +-- +----------------------------------------------------------------------------- +----Pre +--GO +-- +--create procedure error_mapping.ErrorHandling1 as +--begin +----------------------------------------------------------------------------- +----Generate the error +-- +----CHECK constraint conflict, when adding constraint +--DECLARE @a int; +--DECLARE @a int; +--if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +--select @@trancount; +--end +-- +--GO +-- +--if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +--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 +--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 +----Post +--GO +-- +-- +-- +--set xact_abort OFF; +--GO +-- +-- Error classification is done -- +-- Executing test error_mapping.ErrorHandling10000000 +--134 Declare same variable name twice +--------------------------------------------------------------------------- +--Pre +GO + + + +begin try +select 1 +--------------------------------------------------------------------------- +--Generate the error +--CHECK constraint conflict, when adding constraint +DECLARE @a int; +DECLARE @a int; +end try +begin catch + select xact_state(); +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 +----Post +--GO +-- +-- +-- +GO +~~ERROR (Code: 134)~~ + +~~ERROR (Message: The variable name '@a' has already been declared. Variable names must be unique within a query batch or stored procedure.)~~ + +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/sql_expected/135_1.out b/contrib/test/JDBC/sql_expected/135_1.out new file mode 100644 index 00000000000..c3bb9a936a5 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/135_1.out @@ -0,0 +1,415 @@ + + + +-- simple batch start +--135 BREAK when not in WHILE loop +--Could not find this error in excel file +--Pre +GO +--Generate the error +BREAK +GO +~~ERROR (Code: 135)~~ + +~~ERROR (Message: Cannot use a BREAK statement outside the scope of a WHILE statement.)~~ + +--Post +GO + +begin transaction +GO + + +--135 BREAK when not in WHILE loop +--Could not find this error in excel file +--Pre +GO +--Generate the error +BREAK +GO +~~ERROR (Code: 135)~~ + +~~ERROR (Message: Cannot use a BREAK statement outside the scope of a WHILE statement.)~~ + + + +-- Below output is only applicable if query is special case. for example, CREATE/ALTER TRIGGER, CREATE/ALTER FUNCTION, CREATE/ALTER PROC, CREATE/ALTER VIEW etc +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 + +--Post +GO + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + + + +--135 BREAK when not in WHILE loop +--Could not find this error in excel file +--Pre +GO +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +--Generate the error +BREAK +end +GO +~~ERROR (Code: 135)~~ + +~~ERROR (Message: Cannot use a BREAK statement outside the scope of a WHILE statement.)~~ + + +--Post +GO + +create table error_mapping.temp2 (a int) +GO + + + +--135 BREAK when not in WHILE loop +--Could not find this error in excel file +--Pre +GO +insert into error_mapping.temp2 values(1) +--Generate the error +BREAK +GO +~~ERROR (Code: 135)~~ + +~~ERROR (Message: Cannot use a BREAK statement outside the scope of a WHILE statement.)~~ + + +--Post +GO + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + + + +--135 BREAK when not in WHILE loop +--Could not find this error in excel file +--Pre +GO +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2812)~~ + +~~ERROR (Message: Could not find stored procedure 'error_mapping.ErrorHandling1'.)~~ + + +--Post +GO + +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 +~~START~~ +text +parse analysis phase error +~~END~~ + + +drop procedure error_mapping.ErrorHandling1; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + +drop table error_mapping.temp1; +drop table error_mapping.temp2; +drop table error_mapping.temp3; +GO + +-- Parse analysis phase end +GO + + + + +-- compile time error portion +-- Executing test error_mapping.ErrorHandling1 +--135 BREAK when not in WHILE loop +--Could not find this error in excel file +--Pre +GO + + +create procedure error_mapping.ErrorHandling1 as +begin +--Generate the error +BREAK +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO +~~ERROR (Code: 135)~~ + +~~ERROR (Message: Cannot use a BREAK statement outside the scope of a WHILE statement.)~~ + + +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 +~~START~~ +text +Compile time error +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + +--Post +GO + + + + +--135 BREAK when not in WHILE loop +--Could not find this error in excel file +--Pre +GO +begin transaction +GO + +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +--Generate the error +BREAK +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +end +GO +~~ERROR (Code: 135)~~ + +~~ERROR (Message: Cannot use a BREAK statement outside the scope of a WHILE statement.)~~ + + +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 +~~START~~ +text +BATCH ONLY TERMINATING +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +--Post +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO + + +--135 BREAK when not in WHILE loop +--Could not find this error in excel file +--Pre +GO +begin transaction +GO + +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +--Generate the error +BREAK +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +end +GO +~~ERROR (Code: 135)~~ + +~~ERROR (Message: Cannot use a BREAK statement outside the scope of a WHILE statement.)~~ + + +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 +~~START~~ +text +BATCH ONLY TERMINATING +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +--Post +GO +set xact_abort OFF; +GO + + + + + + + +-- comiple time error portion end -- +-- Next portion is for runtime error -- +-- Executing test error_mapping.ErrorHandling10000000 +--135 BREAK when not in WHILE loop +--Could not find this error in excel file +--Pre +--GO +-- +--create procedure error_mapping.ErrorHandling1 as +--begin +----Generate the error +--BREAK +--if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +--select @@trancount; +--end +-- +--GO +-- +--if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +--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 +--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 +----Post +--GO +-- +-- +--set xact_abort ON; +--GO +---- Executing test error_mapping.ErrorHandling10000000 +----135 BREAK when not in WHILE loop +-- +----Could not find this error in excel file +-- +----Pre +--GO +-- +--create procedure error_mapping.ErrorHandling1 as +--begin +----Generate the error +--BREAK +--if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +--select @@trancount; +--end +-- +--GO +-- +--if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +--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 +--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 +----Post +--GO +-- +-- +-- +--set xact_abort OFF; +--GO +-- +-- Error classification is done -- +-- Executing test error_mapping.ErrorHandling10000000 +--135 BREAK when not in WHILE loop +--Could not find this error in excel file +--Pre +GO + + +begin try +select 1 +--Generate the error +BREAK +end try +begin catch + select xact_state(); +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 +----Post +--GO +-- +-- +-- +GO +~~ERROR (Code: 135)~~ + +~~ERROR (Message: Cannot use a BREAK statement outside the scope of a WHILE statement.)~~ + +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/sql_expected/136_1.out b/contrib/test/JDBC/sql_expected/136_1.out new file mode 100644 index 00000000000..145ac1a28b2 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/136_1.out @@ -0,0 +1,415 @@ + + + +-- simple batch start +--136 CONTINUE when not in WHILE loop +--Could not find this error in excel file +--Pre +GO +--Generate the error +CONTINUE +GO +~~ERROR (Code: 136)~~ + +~~ERROR (Message: Cannot use a CONTINUE statement outside the scope of a WHILE statement.)~~ + +--Post +GO + +begin transaction +GO + + +--136 CONTINUE when not in WHILE loop +--Could not find this error in excel file +--Pre +GO +--Generate the error +CONTINUE +GO +~~ERROR (Code: 136)~~ + +~~ERROR (Message: Cannot use a CONTINUE statement outside the scope of a WHILE statement.)~~ + + + +-- Below output is only applicable if query is special case. for example, CREATE/ALTER TRIGGER, CREATE/ALTER FUNCTION, CREATE/ALTER PROC, CREATE/ALTER VIEW etc +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 + +--Post +GO + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + + + +--136 CONTINUE when not in WHILE loop +--Could not find this error in excel file +--Pre +GO +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +--Generate the error +CONTINUE +end +GO +~~ERROR (Code: 136)~~ + +~~ERROR (Message: Cannot use a CONTINUE statement outside the scope of a WHILE statement.)~~ + + +--Post +GO + +create table error_mapping.temp2 (a int) +GO + + + +--136 CONTINUE when not in WHILE loop +--Could not find this error in excel file +--Pre +GO +insert into error_mapping.temp2 values(1) +--Generate the error +CONTINUE +GO +~~ERROR (Code: 136)~~ + +~~ERROR (Message: Cannot use a CONTINUE statement outside the scope of a WHILE statement.)~~ + + +--Post +GO + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + + + +--136 CONTINUE when not in WHILE loop +--Could not find this error in excel file +--Pre +GO +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2812)~~ + +~~ERROR (Message: Could not find stored procedure 'error_mapping.ErrorHandling1'.)~~ + + +--Post +GO + +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 +~~START~~ +text +parse analysis phase error +~~END~~ + + +drop procedure error_mapping.ErrorHandling1; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + +drop table error_mapping.temp1; +drop table error_mapping.temp2; +drop table error_mapping.temp3; +GO + +-- Parse analysis phase end +GO + + + + +-- compile time error portion +-- Executing test error_mapping.ErrorHandling1 +--136 CONTINUE when not in WHILE loop +--Could not find this error in excel file +--Pre +GO + + +create procedure error_mapping.ErrorHandling1 as +begin +--Generate the error +CONTINUE +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO +~~ERROR (Code: 136)~~ + +~~ERROR (Message: Cannot use a CONTINUE statement outside the scope of a WHILE statement.)~~ + + +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 +~~START~~ +text +Compile time error +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + +--Post +GO + + + + +--136 CONTINUE when not in WHILE loop +--Could not find this error in excel file +--Pre +GO +begin transaction +GO + +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +--Generate the error +CONTINUE +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +end +GO +~~ERROR (Code: 136)~~ + +~~ERROR (Message: Cannot use a CONTINUE statement outside the scope of a WHILE statement.)~~ + + +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 +~~START~~ +text +BATCH ONLY TERMINATING +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +--Post +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO + + +--136 CONTINUE when not in WHILE loop +--Could not find this error in excel file +--Pre +GO +begin transaction +GO + +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +--Generate the error +CONTINUE +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +end +GO +~~ERROR (Code: 136)~~ + +~~ERROR (Message: Cannot use a CONTINUE statement outside the scope of a WHILE statement.)~~ + + +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 +~~START~~ +text +BATCH ONLY TERMINATING +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +--Post +GO +set xact_abort OFF; +GO + + + + + + + + +-- comiple time error portion end -- +-- Next portion is for runtime error -- +-- Executing test error_mapping.ErrorHandling10000000 +--136 CONTINUE when not in WHILE loop +--Could not find this error in excel file +--Pre +--GO +-- +--create procedure error_mapping.ErrorHandling1 as +--begin +----Generate the error +--CONTINUE +--if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +--select @@trancount; +--end +-- +--GO +-- +--if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +--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 +--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 +----Post +--GO +-- +-- +--set xact_abort ON; +--GO +---- Executing test error_mapping.ErrorHandling10000000 +----136 CONTINUE when not in WHILE loop +-- +----Could not find this error in excel file +-- +----Pre +--GO +-- +--create procedure error_mapping.ErrorHandling1 as +--begin +----Generate the error +--CONTINUE +--if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +--select @@trancount; +--end +-- +--GO +-- +--if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +--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 +--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 +----Post +--GO +-- +-- +-- +--set xact_abort OFF; +--GO +-- Error classification is done -- +-- Executing test error_mapping.ErrorHandling10000000 +--136 CONTINUE when not in WHILE loop +--Could not find this error in excel file +--Pre +GO + + +begin try +select 1 +--Generate the error +CONTINUE +end try +begin catch + select xact_state(); +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 +----Post +--GO +-- +-- +-- +GO +~~ERROR (Code: 136)~~ + +~~ERROR (Message: Cannot use a CONTINUE statement outside the scope of a WHILE statement.)~~ + +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/sql_expected/141_1.out b/contrib/test/JDBC/sql_expected/141_1.out new file mode 100644 index 00000000000..91767248ec7 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/141_1.out @@ -0,0 +1,426 @@ + + +-- simple batch start +--141 Inline variable assignment for only some columns +--Pre +CREATE TABLE t141(c1 int, c2 int); +GO +--Generate the error +DECLARE @a int; +SELECT @a = c1, c2 FROM t141 +GO +~~ERROR (Code: 141)~~ + +~~ERROR (Message: A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations.)~~ + +--Post +DROP TABLE t141; +GO + +begin transaction +GO + +--141 Inline variable assignment for only some columns +--Pre +CREATE TABLE t141(c1 int, c2 int); +GO +--Generate the error +DECLARE @a int; +SELECT @a = c1, c2 FROM t141 +GO +~~ERROR (Code: 141)~~ + +~~ERROR (Message: A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations.)~~ + + + +-- Below output is only applicable if query is special case. for example, CREATE/ALTER TRIGGER, CREATE/ALTER FUNCTION, CREATE/ALTER PROC, CREATE/ALTER VIEW etc +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 + +--Post +DROP TABLE t141; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the table 't141', because it does not exist or you do not have permission.)~~ + + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + + +--141 Inline variable assignment for only some columns +--Pre +CREATE TABLE t141(c1 int, c2 int); +GO +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +--Generate the error +DECLARE @a int; +SELECT @a = c1, c2 FROM t141 +end +GO +~~ERROR (Code: 141)~~ + +~~ERROR (Message: A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations.)~~ + + +--Post +DROP TABLE t141; +GO + +create table error_mapping.temp2 (a int) +GO + + +--141 Inline variable assignment for only some columns +--Pre +CREATE TABLE t141(c1 int, c2 int); +GO +insert into error_mapping.temp2 values(1) +--Generate the error +DECLARE @a int; +SELECT @a = c1, c2 FROM t141 +GO +~~ERROR (Code: 141)~~ + +~~ERROR (Message: A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations.)~~ + + +--Post +DROP TABLE t141; +GO + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + + +--141 Inline variable assignment for only some columns +--Pre +CREATE TABLE t141(c1 int, c2 int); +GO +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2812)~~ + +~~ERROR (Message: Could not find stored procedure 'error_mapping.ErrorHandling1'.)~~ + + +--Post +DROP TABLE t141; +GO + +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 +~~START~~ +text +parse analysis phase error +~~END~~ + + +drop procedure error_mapping.ErrorHandling1; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + +drop table error_mapping.temp1; +drop table error_mapping.temp2; +drop table error_mapping.temp3; +GO + +-- Parse analysis phase end +GO + + + +-- compile time error portion +-- Executing test error_mapping.ErrorHandling1 +--141 Inline variable assignment for only some columns +--Pre +CREATE TABLE t141(c1 int, c2 int); +GO + + +create procedure error_mapping.ErrorHandling1 as +begin +--Generate the error +DECLARE @a int; +SELECT @a = c1, c2 FROM t141 +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO +~~ERROR (Code: 141)~~ + +~~ERROR (Message: A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations.)~~ + + +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 +~~START~~ +text +Compile time error +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + +--Post +DROP TABLE t141; +GO + + + +--141 Inline variable assignment for only some columns +--Pre +CREATE TABLE t141(c1 int, c2 int); +GO +begin transaction +GO + +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +--Generate the error +DECLARE @a int; +SELECT @a = c1, c2 FROM t141 +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +end +GO +~~ERROR (Code: 141)~~ + +~~ERROR (Message: A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations.)~~ + + +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 +~~START~~ +text +BATCH ONLY TERMINATING +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +--Post +DROP TABLE t141; +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO + +--141 Inline variable assignment for only some columns +--Pre +CREATE TABLE t141(c1 int, c2 int); +GO +begin transaction +GO + +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +--Generate the error +DECLARE @a int; +SELECT @a = c1, c2 FROM t141 +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +end +GO +~~ERROR (Code: 141)~~ + +~~ERROR (Message: A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations.)~~ + + +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 +~~START~~ +text +BATCH ONLY TERMINATING +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +--Post +DROP TABLE t141; +GO +set xact_abort OFF; +GO + + + +-- comiple time error portion end -- +---- Next portion is for runtime error -- +-- +---- Executing test error_mapping.ErrorHandling10000000 +----141 Inline variable assignment for only some columns +-- +----Pre +--CREATE TABLE t141(c1 int, c2 int); +--GO +-- +--create procedure error_mapping.ErrorHandling1 as +--begin +----Generate the error +--DECLARE @a int; +--SELECT @a = c1, c2 FROM t141 +--if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +--select @@trancount; +--end +-- +--GO +-- +--if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +--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 +--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 +----Post +--DROP TABLE t141; +--GO +-- +-- +--set xact_abort ON; +--GO +---- Executing test error_mapping.ErrorHandling10000000 +----141 Inline variable assignment for only some columns +-- +----Pre +--CREATE TABLE t141(c1 int, c2 int); +--GO +-- +--create procedure error_mapping.ErrorHandling1 as +--begin +----Generate the error +--DECLARE @a int; +--SELECT @a = c1, c2 FROM t141 +--if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +--select @@trancount; +--end +-- +--GO +-- +--if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +--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 +--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 +----Post +--DROP TABLE t141; +--GO +-- +-- +-- +--set xact_abort OFF; +--GO +-- +-- Error classification is done -- +-- Executing test error_mapping.ErrorHandling10000000 +--141 Inline variable assignment for only some columns +--Pre +CREATE TABLE t141(c1 int, c2 int); +GO + + +begin try +select 1 +--Generate the error +DECLARE @a int; +SELECT @a = c1, c2 FROM t141 +end try +begin catch + select xact_state(); +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 +----Post +DROP TABLE t141; +GO +~~ERROR (Code: 141)~~ + +~~ERROR (Message: A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations.)~~ + + +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/sql_expected/142_1.out b/contrib/test/JDBC/sql_expected/142_1.out new file mode 100644 index 00000000000..c331f1df083 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/142_1.out @@ -0,0 +1,365 @@ + +-- simple batch start +CREATE TABLE someTable(c1 int PRIMARY KEY) +GO +CREATE TABLE t142(id_c int, REFERENCES someTable(c1)) +GO +~~ERROR (Code: 142)~~ + +~~ERROR (Message: Incorrect syntax for definition of the 'TABLE' constraint.)~~ + +DROP TABLE someTable +GO + +begin transaction +GO +CREATE TABLE someTable(c1 int PRIMARY KEY) +GO +CREATE TABLE t142(id_c int, REFERENCES someTable(c1)) +GO +~~ERROR (Code: 142)~~ + +~~ERROR (Message: Incorrect syntax for definition of the 'TABLE' constraint.)~~ + + + +-- Below output is only applicable if query is special case. for example, CREATE/ALTER TRIGGER, CREATE/ALTER FUNCTION, CREATE/ALTER PROC, CREATE/ALTER VIEW etc +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 + +DROP TABLE someTable +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the table 'someTable', because it does not exist or you do not have permission.)~~ + + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + +CREATE TABLE someTable(c1 int PRIMARY KEY) +GO +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +CREATE TABLE t142(id_c int, REFERENCES someTable(c1)) +end +GO +~~ERROR (Code: 142)~~ + +~~ERROR (Message: Incorrect syntax for definition of the 'TABLE' constraint.)~~ + + +DROP TABLE someTable +GO + +create table error_mapping.temp2 (a int) +GO + +CREATE TABLE someTable(c1 int PRIMARY KEY) +GO +insert into error_mapping.temp2 values(1) +CREATE TABLE t142(id_c int, REFERENCES someTable(c1)) +GO +~~ERROR (Code: 142)~~ + +~~ERROR (Message: Incorrect syntax for definition of the 'TABLE' constraint.)~~ + + +DROP TABLE someTable +GO + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + +CREATE TABLE someTable(c1 int PRIMARY KEY) +GO +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2812)~~ + +~~ERROR (Message: Could not find stored procedure 'error_mapping.ErrorHandling1'.)~~ + + +DROP TABLE someTable +GO + +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 +~~START~~ +text +parse analysis phase error +~~END~~ + + +drop procedure error_mapping.ErrorHandling1; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + +drop table error_mapping.temp1; +drop table error_mapping.temp2; +drop table error_mapping.temp3; +GO + +-- Parse analysis phase end +GO + + +-- compile time error portion +-- Executing test error_mapping.ErrorHandling1 +CREATE TABLE someTable(c1 int PRIMARY KEY) +GO + + +create procedure error_mapping.ErrorHandling1 as +begin +CREATE TABLE t142(id_c int, REFERENCES someTable(c1)) +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO +~~ERROR (Code: 142)~~ + +~~ERROR (Message: Incorrect syntax for definition of the 'TABLE' constraint.)~~ + + +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 +~~START~~ +text +Compile time error +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + +DROP TABLE someTable +GO + + +CREATE TABLE someTable(c1 int PRIMARY KEY) +GO +begin transaction +GO + +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +CREATE TABLE t142(id_c int, REFERENCES someTable(c1)) +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +end +GO +~~ERROR (Code: 142)~~ + +~~ERROR (Message: Incorrect syntax for definition of the 'TABLE' constraint.)~~ + + +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 +~~START~~ +text +BATCH ONLY TERMINATING +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +DROP TABLE someTable +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE someTable(c1 int PRIMARY KEY) +GO +begin transaction +GO + +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +CREATE TABLE t142(id_c int, REFERENCES someTable(c1)) +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +end +GO +~~ERROR (Code: 142)~~ + +~~ERROR (Message: Incorrect syntax for definition of the 'TABLE' constraint.)~~ + + +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 +~~START~~ +text +BATCH ONLY TERMINATING +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +DROP TABLE someTable +GO +set xact_abort OFF; +GO + + +---- comiple time error portion end -- +---- Next portion is for runtime error -- +-- +---- Executing test error_mapping.ErrorHandling10000000 +--CREATE TABLE someTable(c1 int PRIMARY KEY) +--GO +-- +--create procedure error_mapping.ErrorHandling1 as +--begin +--CREATE TABLE t142(id_c int, REFERENCES someTable(c1)) +--if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +--select @@trancount; +--end +-- +--GO +-- +--if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +--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 +--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 +--DROP TABLE someTable +--GO +-- +-- +--set xact_abort ON; +--GO +---- Executing test error_mapping.ErrorHandling10000000 +--CREATE TABLE someTable(c1 int PRIMARY KEY) +--GO +-- +--create procedure error_mapping.ErrorHandling1 as +--begin +--CREATE TABLE t142(id_c int, REFERENCES someTable(c1)) +--if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +--select @@trancount; +--end +-- +--GO +-- +--if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +--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 +--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 +--DROP TABLE someTable +--GO +-- +-- +-- +--set xact_abort OFF; +--GO +-- +---- Error classification is done -- +-- Executing test error_mapping.ErrorHandling10000000 +CREATE TABLE someTable(c1 int PRIMARY KEY) +GO + + +begin try +select 1 +CREATE TABLE t142(id_c int, REFERENCES someTable(c1)) +end try +begin catch + select xact_state(); +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 +--DROP TABLE someTable +--GO +-- +-- +-- +GO +~~ERROR (Code: 142)~~ + +~~ERROR (Message: Incorrect syntax for definition of the 'TABLE' constraint.)~~ + +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/sql_expected/1505_1.out b/contrib/test/JDBC/sql_expected/1505_1.out new file mode 100644 index 00000000000..3891445df4a --- /dev/null +++ b/contrib/test/JDBC/sql_expected/1505_1.out @@ -0,0 +1,267 @@ +# Executing test ErrorHandling1 +--Pre +CREATE TABLE t1505(c1 int); +INSERT INTO t1505 VALUES(1), (1); +GO +~~ROW COUNT: 2~~ + + +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_unique_constraint', 'ignore'; +GO + + +create procedure ErrorHandling1 as +begin +--Generate the error +CREATE UNIQUE INDEX x ON t1505(c1); +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +DROP TABLE t1505; +GO + + +--Pre +CREATE TABLE t1505(c1 int); +INSERT INTO t1505 VALUES(1), (1); +GO +~~ROW COUNT: 2~~ + +begin transaction +GO +# Executing test ErrorHandling1 + +create procedure ErrorHandling1 as +begin +--Generate the error +CREATE UNIQUE INDEX x ON t1505(c1); +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "errorhandling1")~~ + + +GO +--Post +DROP TABLE t1505; +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +--Pre +CREATE TABLE t1505(c1 int); +INSERT INTO t1505 VALUES(1), (1); +GO +~~ROW COUNT: 2~~ + +begin transaction +GO +# Executing test ErrorHandling1 + +create procedure ErrorHandling1 as +begin +--Generate the error +CREATE UNIQUE INDEX x ON t1505(c1); +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "errorhandling1")~~ + + +GO +--Post +DROP TABLE t1505; +GO +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Next portion is for runtime error -- +--Pre +CREATE TABLE t1505(c1 int); +INSERT INTO t1505 VALUES(1), (1); +GO +~~ROW COUNT: 2~~ + + + +create procedure ErrorHandling1 as +begin +--Generate the error +CREATE UNIQUE INDEX x ON t1505(c1); +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 1505)~~ + +~~ERROR (Message: could not create unique index "xt15059dd4e461268c8034f5c8564e155c67a6")~~ + +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +--Post +DROP TABLE t1505; +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +--Pre +CREATE TABLE t1505(c1 int); +INSERT INTO t1505 VALUES(1), (1); +GO +~~ROW COUNT: 2~~ + + + +create procedure ErrorHandling1 as +begin +--Generate the error +CREATE UNIQUE INDEX x ON t1505(c1); +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 1505)~~ + +~~ERROR (Message: could not create unique index "xt15059dd4e461268c8034f5c8564e155c67a6")~~ + +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +--Post +DROP TABLE t1505; +GO + + + +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Error classification is done -- +--Pre +CREATE TABLE t1505(c1 int); +INSERT INTO t1505 VALUES(1), (1); +GO +~~ROW COUNT: 2~~ + + + +begin try +select 1 +--Generate the error +CREATE UNIQUE INDEX x ON t1505(c1); +end try +begin catch + select xact_state(); +end catch +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +int +1 +~~END~~ + +~~START~~ +smallint +0 +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "errorhandling1")~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "errorhandling2")~~ + +--Post +DROP TABLE t1505; +GO + +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_unique_constraint', 'strict'; +GO diff --git a/contrib/test/JDBC/sql_expected/16948_1.out b/contrib/test/JDBC/sql_expected/16948_1.out new file mode 100644 index 00000000000..fdbe53590d5 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/16948_1.out @@ -0,0 +1,601 @@ + +-- simple batch start +CREATE TABLE t16948(c1 int) +GO +INSERT INTO t16948 (c1) +VALUES +(10), +(3), +(8) +GO +~~ROW COUNT: 3~~ + + + + + + + +DECLARE @notCursor INT +DECLARE @c1 INT +DECLARE tcursor CURSOR FOR +SELECT c1 +FROM t16948 +OPEN tcursor +FETCH NEXT FROM @notCursor INTO @c1 +CLOSE tcursor +DEALLOCATE tcursor +GO +~~ERROR (Code: 16948)~~ + +~~ERROR (Message: The variable '@notCursor' is not a cursor variable, but it is used in a place where a cursor variable is expected.)~~ + +DROP TABLE t16948 +GO + + +begin transaction +GO +CREATE TABLE t16948(c1 int) +GO +INSERT INTO t16948 (c1) +VALUES +(10), +(3), +(8) +GO +~~ROW COUNT: 3~~ + + + + + + + +DECLARE @notCursor INT +DECLARE @c1 INT +DECLARE tcursor CURSOR FOR +SELECT c1 +FROM t16948 +OPEN tcursor +FETCH NEXT FROM @notCursor INTO @c1 +CLOSE tcursor +DEALLOCATE tcursor +GO +~~ERROR (Code: 16948)~~ + +~~ERROR (Message: The variable '@notCursor' is not a cursor variable, but it is used in a place where a cursor variable is expected.)~~ + + + +-- Below output is only applicable if query is special case. for example, CREATE/ALTER TRIGGER, CREATE/ALTER FUNCTION, CREATE/ALTER PROC, CREATE/ALTER VIEW etc +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 + +DROP TABLE t16948 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the table 't16948', because it does not exist or you do not have permission.)~~ + + + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + +CREATE TABLE t16948(c1 int) +GO +INSERT INTO t16948 (c1) +VALUES +(10), +(3), +(8) +GO +~~ROW COUNT: 3~~ + + + + + + + +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +DECLARE @notCursor INT +DECLARE @c1 INT +DECLARE tcursor CURSOR FOR +SELECT c1 +FROM t16948 +OPEN tcursor +FETCH NEXT FROM @notCursor INTO @c1 +CLOSE tcursor +DEALLOCATE tcursor +end +GO +~~ERROR (Code: 16948)~~ + +~~ERROR (Message: The variable '@notCursor' is not a cursor variable, but it is used in a place where a cursor variable is expected.)~~ + + +DROP TABLE t16948 +GO + + +create table error_mapping.temp2 (a int) +GO + +CREATE TABLE t16948(c1 int) +GO +INSERT INTO t16948 (c1) +VALUES +(10), +(3), +(8) +GO +~~ROW COUNT: 3~~ + + + + + + + +insert into error_mapping.temp2 values(1) +DECLARE @notCursor INT +DECLARE @c1 INT +DECLARE tcursor CURSOR FOR +SELECT c1 +FROM t16948 +OPEN tcursor +FETCH NEXT FROM @notCursor INTO @c1 +CLOSE tcursor +DEALLOCATE tcursor +GO +~~ERROR (Code: 16948)~~ + +~~ERROR (Message: The variable '@notCursor' is not a cursor variable, but it is used in a place where a cursor variable is expected.)~~ + + +DROP TABLE t16948 +GO + + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + +CREATE TABLE t16948(c1 int) +GO +INSERT INTO t16948 (c1) +VALUES +(10), +(3), +(8) +GO +~~ROW COUNT: 3~~ + + + +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2812)~~ + +~~ERROR (Message: Could not find stored procedure 'error_mapping.ErrorHandling1'.)~~ + + +DROP TABLE t16948 +GO + + +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 +~~START~~ +text +parse analysis phase error +~~END~~ + + +drop procedure error_mapping.ErrorHandling1; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + +drop table error_mapping.temp1; +drop table error_mapping.temp2; +drop table error_mapping.temp3; +GO + +-- Parse analysis phase end +GO + + +-- compile time error portion +-- Executing test error_mapping.ErrorHandling1 +CREATE TABLE t16948(c1 int) +GO +INSERT INTO t16948 (c1) +VALUES +(10), +(3), +(8) +GO +~~ROW COUNT: 3~~ + + + + + + + + + +create procedure error_mapping.ErrorHandling1 as +begin +DECLARE @notCursor INT +DECLARE @c1 INT +DECLARE tcursor CURSOR FOR +SELECT c1 +FROM t16948 +OPEN tcursor +FETCH NEXT FROM @notCursor INTO @c1 +CLOSE tcursor +DEALLOCATE tcursor +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO +~~ERROR (Code: 16948)~~ + +~~ERROR (Message: The variable '@notCursor' is not a cursor variable, but it is used in a place where a cursor variable is expected.)~~ + + +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 +~~START~~ +text +Compile time error +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + +DROP TABLE t16948 +GO + + + +CREATE TABLE t16948(c1 int) +GO +INSERT INTO t16948 (c1) +VALUES +(10), +(3), +(8) +GO +~~ROW COUNT: 3~~ + + + +begin transaction +GO + + + + + +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +DECLARE @notCursor INT +DECLARE @c1 INT +DECLARE tcursor CURSOR FOR +SELECT c1 +FROM t16948 +OPEN tcursor +FETCH NEXT FROM @notCursor INTO @c1 +CLOSE tcursor +DEALLOCATE tcursor +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +end +GO +~~ERROR (Code: 16948)~~ + +~~ERROR (Message: The variable '@notCursor' is not a cursor variable, but it is used in a place where a cursor variable is expected.)~~ + + +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 +~~START~~ +text +BATCH ONLY TERMINATING +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +DROP TABLE t16948 +GO + + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE t16948(c1 int) +GO +INSERT INTO t16948 (c1) +VALUES +(10), +(3), +(8) +GO +~~ROW COUNT: 3~~ + + + +begin transaction +GO + + + + + +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +DECLARE @notCursor INT +DECLARE @c1 INT +DECLARE tcursor CURSOR FOR +SELECT c1 +FROM t16948 +OPEN tcursor +FETCH NEXT FROM @notCursor INTO @c1 +CLOSE tcursor +DEALLOCATE tcursor +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +end +GO +~~ERROR (Code: 16948)~~ + +~~ERROR (Message: The variable '@notCursor' is not a cursor variable, but it is used in a place where a cursor variable is expected.)~~ + + +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 +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +DROP TABLE t16948 +GO + +set xact_abort OFF; +GO + + + +-- comiple time error portion end -- +-- Next portion is for runtime error -- +-- Executing test error_mapping.ErrorHandling10000000 +--CREATE TABLE t16948(c1 int) +--GO +--INSERT INTO t16948 (c1) +--VALUES +--(10), +--(3), +--(8) +--GO +-- +-- +-- +--create procedure error_mapping.ErrorHandling1 as +--begin +--DECLARE @notCursor INT +-- +--DECLARE @c1 INT +--DECLARE tcursor CURSOR FOR +--SELECT c1 +--FROM t16948 +-- +--OPEN tcursor +--FETCH NEXT FROM @notCursor INTO @c1 +-- +--CLOSE tcursor +--DEALLOCATE tcursor +-- +--if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +--select @@trancount; +--end +-- +--GO +-- +--if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +--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 +--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 +--DROP TABLE t16948 +--GO +-- +-- +-- +--set xact_abort ON; +--GO +---- Executing test error_mapping.ErrorHandling10000000 +--CREATE TABLE t16948(c1 int) +--GO +--INSERT INTO t16948 (c1) +--VALUES +--(10), +--(3), +--(8) +--GO +-- +-- +-- +--create procedure error_mapping.ErrorHandling1 as +--begin +--DECLARE @notCursor INT +-- +--DECLARE @c1 INT +--DECLARE tcursor CURSOR FOR +--SELECT c1 +--FROM t16948 +-- +--OPEN tcursor +--FETCH NEXT FROM @notCursor INTO @c1 +-- +--CLOSE tcursor +--DEALLOCATE tcursor +-- +--if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +--select @@trancount; +--end +-- +--GO +-- +--if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +--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 +--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 +--DROP TABLE t16948 +--GO +-- +-- +-- +-- +--set xact_abort OFF; +--GO +-- +-- Error classification is done -- +CREATE TABLE t16948(c1 int) +GO +INSERT INTO t16948 (c1) +VALUES +(10), +(3), +(8) +GO +~~ROW COUNT: 3~~ + + + + + + + + + +begin try +select 1 +DECLARE @notCursor INT +DECLARE @c1 INT +DECLARE tcursor CURSOR FOR +SELECT c1 +FROM t16948 +OPEN tcursor +FETCH NEXT FROM @notCursor INTO @c1 +CLOSE tcursor +DEALLOCATE tcursor +end try +begin catch + select xact_state(); +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 +--DROP TABLE t16948 +--GO +-- +-- +-- +-- +GO +~~ERROR (Code: 16948)~~ + +~~ERROR (Message: The variable '@notCursor' is not a cursor variable, but it is used in a place where a cursor variable is expected.)~~ + +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/sql_expected/16950_1.out b/contrib/test/JDBC/sql_expected/16950_1.out new file mode 100644 index 00000000000..b66185abb50 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/16950_1.out @@ -0,0 +1,398 @@ + +-- simple batch start +GO + + + +DECLARE @c1 INT +DECLARE @cursor1 CURSOR +FETCH NEXT FROM @cursor1 INTO @c1 +GO +~~ERROR (Code: 16950)~~ + +~~ERROR (Message: The variable '@cursor1' does not currently have a cursor allocated to it.)~~ + +GO + + +begin transaction +GO +GO + + + +DECLARE @c1 INT +DECLARE @cursor1 CURSOR +FETCH NEXT FROM @cursor1 INTO @c1 +GO +~~ERROR (Code: 16950)~~ + +~~ERROR (Message: The variable '@cursor1' does not currently have a cursor allocated to it.)~~ + + + +-- Below output is only applicable if query is special case. for example, CREATE/ALTER TRIGGER, CREATE/ALTER FUNCTION, CREATE/ALTER PROC, CREATE/ALTER VIEW etc +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 + +GO + + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + +GO + + + +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +DECLARE @c1 INT +DECLARE @cursor1 CURSOR +FETCH NEXT FROM @cursor1 INTO @c1 +end +GO + +GO + + +create table error_mapping.temp2 (a int) +GO + +GO + + + +insert into error_mapping.temp2 values(1) +DECLARE @c1 INT +DECLARE @cursor1 CURSOR +FETCH NEXT FROM @cursor1 INTO @c1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 16950)~~ + +~~ERROR (Message: The variable '@cursor1' does not currently have a cursor allocated to it.)~~ + + +GO + + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + +GO + +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 16950)~~ + +~~ERROR (Message: The variable '@cursor1' does not currently have a cursor allocated to it.)~~ + + +GO + + +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 + +-- Parse analysis phase end +GO + + +-- compile time error portion +-- Executing test error_mapping.ErrorHandling1 +GO + + + + + +create procedure error_mapping.ErrorHandling1 as +begin +DECLARE @c1 INT +DECLARE @cursor1 CURSOR +FETCH NEXT FROM @cursor1 INTO @c1 +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 +GO + + + +GO + +begin transaction +GO + + + +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +DECLARE @c1 INT +DECLARE @cursor1 CURSOR +FETCH NEXT FROM @cursor1 INTO @c1 +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: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +GO + + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +GO + +begin transaction +GO + + + +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +DECLARE @c1 INT +DECLARE @cursor1 CURSOR +FETCH NEXT FROM @cursor1 INTO @c1 +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: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +GO + +set xact_abort OFF; +GO + + +-- comiple time error portion end -- +-- Next portion is for runtime error -- +-- Executing test error_mapping.ErrorHandling10000000 +GO + + + + + +create procedure error_mapping.ErrorHandling1 as +begin +DECLARE @c1 INT +DECLARE @cursor1 CURSOR +FETCH NEXT FROM @cursor1 INTO @c1 +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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: 16950)~~ + +~~ERROR (Message: The variable '@cursor1' does not currently have a cursor allocated to it.)~~ + +~~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 +GO + + + +set xact_abort ON; +GO +-- Executing test error_mapping.ErrorHandling10000000 +GO + + + + + +create procedure error_mapping.ErrorHandling1 as +begin +DECLARE @c1 INT +DECLARE @cursor1 CURSOR +FETCH NEXT FROM @cursor1 INTO @c1 +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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: 16950)~~ + +~~ERROR (Message: The variable '@cursor1' does not currently have a cursor allocated to it.)~~ + +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 +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +GO + + + + +set xact_abort OFF; +GO + + +-- Error classification is done -- +-- Executing test error_mapping.ErrorHandling10000000 +GO + + + + + +begin try +select 1 +DECLARE @c1 INT +DECLARE @cursor1 CURSOR +FETCH NEXT FROM @cursor1 INTO @c1 +end try +begin catch + select xact_state(); +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 +~~START~~ +int +1 +~~END~~ + +~~START~~ +smallint +0 +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling2', because it does not exist or you do not have permission.)~~ + +GO + + + + +GO +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/sql_expected/1752_1750_2.out b/contrib/test/JDBC/sql_expected/1752_1750_2.out new file mode 100644 index 00000000000..cbad2bf2883 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/1752_1750_2.out @@ -0,0 +1,236 @@ +# Executing test ErrorHandling1 +CREATE TABLE t1752(c1 INT, c2 INT, c3 as c1*c2) +GO + + + + +create procedure ErrorHandling1 as +begin +ALTER TABLE t1752 +ADD CONSTRAINT constraint1752 DEFAULT 1 FOR c3 +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t1752 +GO + + +CREATE TABLE t1752(c1 INT, c2 INT, c3 as c1*c2) +GO + +begin transaction +GO +# Executing test ErrorHandling1 + + +create procedure ErrorHandling1 as +begin +ALTER TABLE t1752 +ADD CONSTRAINT constraint1752 DEFAULT 1 FOR c3 +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +DROP TABLE t1752 +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE t1752(c1 INT, c2 INT, c3 as c1*c2) +GO + +begin transaction +GO +# Executing test ErrorHandling1 + + +create procedure ErrorHandling1 as +begin +ALTER TABLE t1752 +ADD CONSTRAINT constraint1752 DEFAULT 1 FOR c3 +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +DROP TABLE t1752 +GO +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Next portion is for runtime error -- +CREATE TABLE t1752(c1 INT, c2 INT, c3 as c1*c2) +GO + + + + +create procedure ErrorHandling1 as +begin +ALTER TABLE t1752 +ADD CONSTRAINT constraint1752 DEFAULT 1 FOR c3 +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 1752)~~ + +~~ERROR (Message: Column 'c3' in table 't1752' is invalid for creating a default constraint.)~~ + +~~START~~ +text +CURRENT BATCH TERMINATING ERROR +~~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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t1752 +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +CREATE TABLE t1752(c1 INT, c2 INT, c3 as c1*c2) +GO + + + + +create procedure ErrorHandling1 as +begin +ALTER TABLE t1752 +ADD CONSTRAINT constraint1752 DEFAULT 1 FOR c3 +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 1752)~~ + +~~ERROR (Message: Column 'c3' in table 't1752' is invalid for creating a default constraint.)~~ + +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +DROP TABLE t1752 +GO + + + +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Error classification is done -- +CREATE TABLE t1752(c1 INT, c2 INT, c3 as c1*c2) +GO + + + + +begin try +select 1 +ALTER TABLE t1752 +ADD CONSTRAINT constraint1752 DEFAULT 1 FOR c3 +end try +begin catch + select xact_state(); +end catch +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +int +1 +~~END~~ + +~~ERROR (Code: 1752)~~ + +~~ERROR (Message: Column 'c3' in table 't1752' is invalid for creating a default constraint.)~~ + +DROP TABLE t1752 +GO + + diff --git a/contrib/test/JDBC/sql_expected/1765_1750_1.out b/contrib/test/JDBC/sql_expected/1765_1750_1.out new file mode 100644 index 00000000000..f2b1db6d277 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/1765_1750_1.out @@ -0,0 +1,371 @@ +# Executing test ErrorHandling1 +CREATE TABLE t1765_1 +( + c1 int PRIMARY KEY +,c2 int +) +GO + + + + + + + + +create procedure ErrorHandling1 as +begin +--SET QUOTED_IDENTIFIER ON +--GO +CREATE TABLE t1765_2 +( + c1 int PRIMARY KEY +,c2 AS c1 + 1 PERSISTED +, FOREIGN KEY (c2) + REFERENCES t1765_1(c1) ON DELETE SET NULL) +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t1765_1 +GO + +DROP TABLE t1765_2 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the table 't1765_2', because it does not exist or you do not have permission.)~~ + + + +CREATE TABLE t1765_1 +( + c1 int PRIMARY KEY +,c2 int +) +GO + + + + +begin transaction +GO +# Executing test ErrorHandling1 + + + +create procedure ErrorHandling1 as +begin +--SET QUOTED_IDENTIFIER ON +--GO +CREATE TABLE t1765_2 +( + c1 int PRIMARY KEY +,c2 AS c1 + 1 PERSISTED +, FOREIGN KEY (c2) + REFERENCES t1765_1(c1) ON DELETE SET NULL) +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +DROP TABLE t1765_1 +GO + +DROP TABLE t1765_2 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the table 't1765_2', because it does not exist or you do not have permission.)~~ + + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE t1765_1 +( + c1 int PRIMARY KEY +,c2 int +) +GO + + + + +begin transaction +GO +# Executing test ErrorHandling1 + + + +create procedure ErrorHandling1 as +begin +--SET QUOTED_IDENTIFIER ON +--GO +CREATE TABLE t1765_2 +( + c1 int PRIMARY KEY +,c2 AS c1 + 1 PERSISTED +, FOREIGN KEY (c2) + REFERENCES t1765_1(c1) ON DELETE SET NULL) +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +DROP TABLE t1765_1 +GO + +DROP TABLE t1765_2 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the table 't1765_2', because it does not exist or you do not have permission.)~~ + +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Next portion is for runtime error -- +CREATE TABLE t1765_1 +( + c1 int PRIMARY KEY +,c2 int +) +GO + + + + + + + + +create procedure ErrorHandling1 as +begin +--SET QUOTED_IDENTIFIER ON +--GO +CREATE TABLE t1765_2 +( + c1 int PRIMARY KEY +,c2 AS c1 + 1 PERSISTED +, FOREIGN KEY (c2) + REFERENCES t1765_1(c1) ON DELETE SET NULL) +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 1765)~~ + +~~ERROR (Message: Foreign key 'FK__t1765_2__c2__2D00F5CE' creation failed. Only NO ACTION and CASCADE referential delete actions are allowed for referencing computed column 'c2'.)~~ + +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +DROP TABLE t1765_1 +GO + +DROP TABLE t1765_2 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the table 't1765_2', because it does not exist or you do not have permission.)~~ + + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +CREATE TABLE t1765_1 +( + c1 int PRIMARY KEY +,c2 int +) +GO + + + + + + + + +create procedure ErrorHandling1 as +begin +--SET QUOTED_IDENTIFIER ON +--GO +CREATE TABLE t1765_2 +( + c1 int PRIMARY KEY +,c2 AS c1 + 1 PERSISTED +, FOREIGN KEY (c2) + REFERENCES t1765_1(c1) ON DELETE SET NULL) +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 1765)~~ + +~~ERROR (Message: Foreign key 'FK__t1765_2__c2__33ADF35D' creation failed. Only NO ACTION and CASCADE referential delete actions are allowed for referencing computed column 'c2'.)~~ + +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +DROP TABLE t1765_1 +GO + +DROP TABLE t1765_2 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the table 't1765_2', because it does not exist or you do not have permission.)~~ + + + + +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Error classification is done -- +CREATE TABLE t1765_1 +( + c1 int PRIMARY KEY +,c2 int +) +GO + + + + + + + + +begin try +select 1 +--SET QUOTED_IDENTIFIER ON +--GO +CREATE TABLE t1765_2 +( + c1 int PRIMARY KEY +,c2 AS c1 + 1 PERSISTED +, FOREIGN KEY (c2) + REFERENCES t1765_1(c1) ON DELETE SET NULL) +end try +begin catch + select xact_state(); +end catch +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +int +1 +~~END~~ + +~~START~~ +smallint +0 +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling2', because it does not exist or you do not have permission.)~~ + +DROP TABLE t1765_1 +GO + +DROP TABLE t1765_2 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the table 't1765_2', because it does not exist or you do not have permission.)~~ + + + diff --git a/contrib/test/JDBC/sql_expected/1768_1750_1.out b/contrib/test/JDBC/sql_expected/1768_1750_1.out new file mode 100644 index 00000000000..81a4fcc8194 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/1768_1750_1.out @@ -0,0 +1,335 @@ +# Executing test ErrorHandling1 +CREATE TABLE t1768_1( + c1 int NOT NULL +,c2 int NOT NULL +,PRIMARY KEY (c1)) +GO + +CREATE VIEW v1768 +AS +SELECT c1, c2 +FROM t1768_1 +GO + + +create procedure ErrorHandling1 as +begin +CREATE TABLE t1768_2 ( + c1 int +,c2 int +,CONSTRAINT fk1768_2 FOREIGN KEY (c1) REFERENCES v1768 +) +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP VIEW v1768 +GO + +DROP TABLE t1768_1 +GO + + + + +CREATE TABLE t1768_1( + c1 int NOT NULL +,c2 int NOT NULL +,PRIMARY KEY (c1)) +GO + +CREATE VIEW v1768 +AS +SELECT c1, c2 +FROM t1768_1 +GO +begin transaction +GO +# Executing test ErrorHandling1 + +create procedure ErrorHandling1 as +begin +CREATE TABLE t1768_2 ( + c1 int +,c2 int +,CONSTRAINT fk1768_2 FOREIGN KEY (c1) REFERENCES v1768 +) +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +DROP VIEW v1768 +GO + +DROP TABLE t1768_1 +GO + + + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE t1768_1( + c1 int NOT NULL +,c2 int NOT NULL +,PRIMARY KEY (c1)) +GO + +CREATE VIEW v1768 +AS +SELECT c1, c2 +FROM t1768_1 +GO +begin transaction +GO +# Executing test ErrorHandling1 + +create procedure ErrorHandling1 as +begin +CREATE TABLE t1768_2 ( + c1 int +,c2 int +,CONSTRAINT fk1768_2 FOREIGN KEY (c1) REFERENCES v1768 +) +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +DROP VIEW v1768 +GO + +DROP TABLE t1768_1 +GO + + +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Next portion is for runtime error -- +CREATE TABLE t1768_1( + c1 int NOT NULL +,c2 int NOT NULL +,PRIMARY KEY (c1)) +GO + +CREATE VIEW v1768 +AS +SELECT c1, c2 +FROM t1768_1 +GO + + +create procedure ErrorHandling1 as +begin +CREATE TABLE t1768_2 ( + c1 int +,c2 int +,CONSTRAINT fk1768_2 FOREIGN KEY (c1) REFERENCES v1768 +) +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 1768)~~ + +~~ERROR (Message: Foreign key 'fk1768_2' references object 'v1768' which is not a user table.)~~ + +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +DROP VIEW v1768 +GO + +DROP TABLE t1768_1 +GO + + + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +CREATE TABLE t1768_1( + c1 int NOT NULL +,c2 int NOT NULL +,PRIMARY KEY (c1)) +GO + +CREATE VIEW v1768 +AS +SELECT c1, c2 +FROM t1768_1 +GO + + +create procedure ErrorHandling1 as +begin +CREATE TABLE t1768_2 ( + c1 int +,c2 int +,CONSTRAINT fk1768_2 FOREIGN KEY (c1) REFERENCES v1768 +) +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 1768)~~ + +~~ERROR (Message: Foreign key 'fk1768_2' references object 'v1768' which is not a user table.)~~ + +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +DROP VIEW v1768 +GO + +DROP TABLE t1768_1 +GO + + + + + +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Error classification is done -- +CREATE TABLE t1768_1( + c1 int NOT NULL +,c2 int NOT NULL +,PRIMARY KEY (c1)) +GO + +CREATE VIEW v1768 +AS +SELECT c1, c2 +FROM t1768_1 +GO + + +begin try +select 1 +CREATE TABLE t1768_2 ( + c1 int +,c2 int +,CONSTRAINT fk1768_2 FOREIGN KEY (c1) REFERENCES v1768 +) +end try +begin catch + select xact_state(); +end catch +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +int +1 +~~END~~ + +~~START~~ +smallint +0 +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling2', because it does not exist or you do not have permission.)~~ + +DROP VIEW v1768 +GO + +DROP TABLE t1768_1 +GO + + + + diff --git a/contrib/test/JDBC/sql_expected/180_1.out b/contrib/test/JDBC/sql_expected/180_1.out new file mode 100644 index 00000000000..01509ef97a8 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/180_1.out @@ -0,0 +1,4259 @@ + + +-- simple batch start +GO + +CREATE FUNCTION fn180( + @p1 int +,@p2 int +,@p3 int +,@p4 int +,@p5 int +,@p6 int +,@p7 int +,@p8 int +,@p9 int +,@p10 int +,@p11 int +,@p12 int +,@p13 int +,@p14 int +,@p15 int +,@p16 int +,@p17 int +,@p18 int +,@p19 int +,@p20 int +,@p21 int +,@p22 int +,@p23 int +,@p24 int +,@p25 int +,@p26 int +,@p27 int +,@p28 int +,@p29 int +,@p30 int +,@p31 int +,@p32 int +,@p33 int +,@p34 int +,@p35 int +,@p36 int +,@p37 int +,@p38 int +,@p39 int +,@p40 int +,@p41 int +,@p42 int +,@p43 int +,@p44 int +,@p45 int +,@p46 int +,@p47 int +,@p48 int +,@p49 int +,@p50 int +,@p51 int +,@p52 int +,@p53 int +,@p54 int +,@p55 int +,@p56 int +,@p57 int +,@p58 int +,@p59 int +,@p60 int +,@p61 int +,@p62 int +,@p63 int +,@p64 int +,@p65 int +,@p66 int +,@p67 int +,@p68 int +,@p69 int +,@p70 int +,@p71 int +,@p72 int +,@p73 int +,@p74 int +,@p75 int +,@p76 int +,@p77 int +,@p78 int +,@p79 int +,@p80 int +,@p81 int +,@p82 int +,@p83 int +,@p84 int +,@p85 int +,@p86 int +,@p87 int +,@p88 int +,@p89 int +,@p90 int +,@p91 int +,@p92 int +,@p93 int +,@p94 int +,@p95 int +,@p96 int +,@p97 int +,@p98 int +,@p99 int +,@p100 int +,@p101 int +,@p102 int +,@p103 int +,@p104 int +,@p105 int +,@p106 int +,@p107 int +,@p108 int +,@p109 int +,@p110 int +,@p111 int +,@p112 int +,@p113 int +,@p114 int +,@p115 int +,@p116 int +,@p117 int +,@p118 int +,@p119 int +,@p120 int +,@p121 int +,@p122 int +,@p123 int +,@p124 int +,@p125 int +,@p126 int +,@p127 int +,@p128 int +,@p129 int +,@p130 int +,@p131 int +,@p132 int +,@p133 int +,@p134 int +,@p135 int +,@p136 int +,@p137 int +,@p138 int +,@p139 int +,@p140 int +,@p141 int +,@p142 int +,@p143 int +,@p144 int +,@p145 int +,@p146 int +,@p147 int +,@p148 int +,@p149 int +,@p150 int +,@p151 int +,@p152 int +,@p153 int +,@p154 int +,@p155 int +,@p156 int +,@p157 int +,@p158 int +,@p159 int +,@p160 int +,@p161 int +,@p162 int +,@p163 int +,@p164 int +,@p165 int +,@p166 int +,@p167 int +,@p168 int +,@p169 int +,@p170 int +,@p171 int +,@p172 int +,@p173 int +,@p174 int +,@p175 int +,@p176 int +,@p177 int +,@p178 int +,@p179 int +,@p180 int +,@p181 int +,@p182 int +,@p183 int +,@p184 int +,@p185 int +,@p186 int +,@p187 int +,@p188 int +,@p189 int +,@p190 int +,@p191 int +,@p192 int +,@p193 int +,@p194 int +,@p195 int +,@p196 int +,@p197 int +,@p198 int +,@p199 int +,@p200 int +,@p201 int +,@p202 int +,@p203 int +,@p204 int +,@p205 int +,@p206 int +,@p207 int +,@p208 int +,@p209 int +,@p210 int +,@p211 int +,@p212 int +,@p213 int +,@p214 int +,@p215 int +,@p216 int +,@p217 int +,@p218 int +,@p219 int +,@p220 int +,@p221 int +,@p222 int +,@p223 int +,@p224 int +,@p225 int +,@p226 int +,@p227 int +,@p228 int +,@p229 int +,@p230 int +,@p231 int +,@p232 int +,@p233 int +,@p234 int +,@p235 int +,@p236 int +,@p237 int +,@p238 int +,@p239 int +,@p240 int +,@p241 int +,@p242 int +,@p243 int +,@p244 int +,@p245 int +,@p246 int +,@p247 int +,@p248 int +,@p249 int +,@p250 int +,@p251 int +,@p252 int +,@p253 int +,@p254 int +,@p255 int +,@p256 int +,@p257 int +,@p258 int +,@p259 int +,@p260 int +,@p261 int +,@p262 int +,@p263 int +,@p264 int +,@p265 int +,@p266 int +,@p267 int +,@p268 int +,@p269 int +,@p270 int +,@p271 int +,@p272 int +,@p273 int +,@p274 int +,@p275 int +,@p276 int +,@p277 int +,@p278 int +,@p279 int +,@p280 int +,@p281 int +,@p282 int +,@p283 int +,@p284 int +,@p285 int +,@p286 int +,@p287 int +,@p288 int +,@p289 int +,@p290 int +,@p291 int +,@p292 int +,@p293 int +,@p294 int +,@p295 int +,@p296 int +,@p297 int +,@p298 int +,@p299 int +,@p300 int +,@p301 int +,@p302 int +,@p303 int +,@p304 int +,@p305 int +,@p306 int +,@p307 int +,@p308 int +,@p309 int +,@p310 int +,@p311 int +,@p312 int +,@p313 int +,@p314 int +,@p315 int +,@p316 int +,@p317 int +,@p318 int +,@p319 int +,@p320 int +,@p321 int +,@p322 int +,@p323 int +,@p324 int +,@p325 int +,@p326 int +,@p327 int +,@p328 int +,@p329 int +,@p330 int +,@p331 int +,@p332 int +,@p333 int +,@p334 int +,@p335 int +,@p336 int +,@p337 int +,@p338 int +,@p339 int +,@p340 int +,@p341 int +,@p342 int +,@p343 int +,@p344 int +,@p345 int +,@p346 int +,@p347 int +,@p348 int +,@p349 int +,@p350 int +,@p351 int +,@p352 int +,@p353 int +,@p354 int +,@p355 int +,@p356 int +,@p357 int +,@p358 int +,@p359 int +,@p360 int +,@p361 int +,@p362 int +,@p363 int +,@p364 int +,@p365 int +,@p366 int +,@p367 int +,@p368 int +,@p369 int +,@p370 int +,@p371 int +,@p372 int +,@p373 int +,@p374 int +,@p375 int +,@p376 int +,@p377 int +,@p378 int +,@p379 int +,@p380 int +,@p381 int +,@p382 int +,@p383 int +,@p384 int +,@p385 int +,@p386 int +,@p387 int +,@p388 int +,@p389 int +,@p390 int +,@p391 int +,@p392 int +,@p393 int +,@p394 int +,@p395 int +,@p396 int +,@p397 int +,@p398 int +,@p399 int +,@p400 int +,@p401 int +,@p402 int +,@p403 int +,@p404 int +,@p405 int +,@p406 int +,@p407 int +,@p408 int +,@p409 int +,@p410 int +,@p411 int +,@p412 int +,@p413 int +,@p414 int +,@p415 int +,@p416 int +,@p417 int +,@p418 int +,@p419 int +,@p420 int +,@p421 int +,@p422 int +,@p423 int +,@p424 int +,@p425 int +,@p426 int +,@p427 int +,@p428 int +,@p429 int +,@p430 int +,@p431 int +,@p432 int +,@p433 int +,@p434 int +,@p435 int +,@p436 int +,@p437 int +,@p438 int +,@p439 int +,@p440 int +,@p441 int +,@p442 int +,@p443 int +,@p444 int +,@p445 int +,@p446 int +,@p447 int +,@p448 int +,@p449 int +,@p450 int +,@p451 int +,@p452 int +,@p453 int +,@p454 int +,@p455 int +,@p456 int +,@p457 int +,@p458 int +,@p459 int +,@p460 int +,@p461 int +,@p462 int +,@p463 int +,@p464 int +,@p465 int +,@p466 int +,@p467 int +,@p468 int +,@p469 int +,@p470 int +,@p471 int +,@p472 int +,@p473 int +,@p474 int +,@p475 int +,@p476 int +,@p477 int +,@p478 int +,@p479 int +,@p480 int +,@p481 int +,@p482 int +,@p483 int +,@p484 int +,@p485 int +,@p486 int +,@p487 int +,@p488 int +,@p489 int +,@p490 int +,@p491 int +,@p492 int +,@p493 int +,@p494 int +,@p495 int +,@p496 int +,@p497 int +,@p498 int +,@p499 int +,@p500 int +,@p501 int +,@p502 int +,@p503 int +,@p504 int +,@p505 int +,@p506 int +,@p507 int +,@p508 int +,@p509 int +,@p510 int +,@p511 int +,@p512 int +,@p513 int +,@p514 int +,@p515 int +,@p516 int +,@p517 int +,@p518 int +,@p519 int +,@p520 int +,@p521 int +,@p522 int +,@p523 int +,@p524 int +,@p525 int +,@p526 int +,@p527 int +,@p528 int +,@p529 int +,@p530 int +,@p531 int +,@p532 int +,@p533 int +,@p534 int +,@p535 int +,@p536 int +,@p537 int +,@p538 int +,@p539 int +,@p540 int +,@p541 int +,@p542 int +,@p543 int +,@p544 int +,@p545 int +,@p546 int +,@p547 int +,@p548 int +,@p549 int +,@p550 int +,@p551 int +,@p552 int +,@p553 int +,@p554 int +,@p555 int +,@p556 int +,@p557 int +,@p558 int +,@p559 int +,@p560 int +,@p561 int +,@p562 int +,@p563 int +,@p564 int +,@p565 int +,@p566 int +,@p567 int +,@p568 int +,@p569 int +,@p570 int +,@p571 int +,@p572 int +,@p573 int +,@p574 int +,@p575 int +,@p576 int +,@p577 int +,@p578 int +,@p579 int +,@p580 int +,@p581 int +,@p582 int +,@p583 int +,@p584 int +,@p585 int +,@p586 int +,@p587 int +,@p588 int +,@p589 int +,@p590 int +,@p591 int +,@p592 int +,@p593 int +,@p594 int +,@p595 int +,@p596 int +,@p597 int +,@p598 int +,@p599 int +,@p600 int +,@p601 int +,@p602 int +,@p603 int +,@p604 int +,@p605 int +,@p606 int +,@p607 int +,@p608 int +,@p609 int +,@p610 int +,@p611 int +,@p612 int +,@p613 int +,@p614 int +,@p615 int +,@p616 int +,@p617 int +,@p618 int +,@p619 int +,@p620 int +,@p621 int +,@p622 int +,@p623 int +,@p624 int +,@p625 int +,@p626 int +,@p627 int +,@p628 int +,@p629 int +,@p630 int +,@p631 int +,@p632 int +,@p633 int +,@p634 int +,@p635 int +,@p636 int +,@p637 int +,@p638 int +,@p639 int +,@p640 int +,@p641 int +,@p642 int +,@p643 int +,@p644 int +,@p645 int +,@p646 int +,@p647 int +,@p648 int +,@p649 int +,@p650 int +,@p651 int +,@p652 int +,@p653 int +,@p654 int +,@p655 int +,@p656 int +,@p657 int +,@p658 int +,@p659 int +,@p660 int +,@p661 int +,@p662 int +,@p663 int +,@p664 int +,@p665 int +,@p666 int +,@p667 int +,@p668 int +,@p669 int +,@p670 int +,@p671 int +,@p672 int +,@p673 int +,@p674 int +,@p675 int +,@p676 int +,@p677 int +,@p678 int +,@p679 int +,@p680 int +,@p681 int +,@p682 int +,@p683 int +,@p684 int +,@p685 int +,@p686 int +,@p687 int +,@p688 int +,@p689 int +,@p690 int +,@p691 int +,@p692 int +,@p693 int +,@p694 int +,@p695 int +,@p696 int +,@p697 int +,@p698 int +,@p699 int +,@p700 int +,@p701 int +,@p702 int +,@p703 int +,@p704 int +,@p705 int +,@p706 int +,@p707 int +,@p708 int +,@p709 int +,@p710 int +,@p711 int +,@p712 int +,@p713 int +,@p714 int +,@p715 int +,@p716 int +,@p717 int +,@p718 int +,@p719 int +,@p720 int +,@p721 int +,@p722 int +,@p723 int +,@p724 int +,@p725 int +,@p726 int +,@p727 int +,@p728 int +,@p729 int +,@p730 int +,@p731 int +,@p732 int +,@p733 int +,@p734 int +,@p735 int +,@p736 int +,@p737 int +,@p738 int +,@p739 int +,@p740 int +,@p741 int +,@p742 int +,@p743 int +,@p744 int +,@p745 int +,@p746 int +,@p747 int +,@p748 int +,@p749 int +,@p750 int +,@p751 int +,@p752 int +,@p753 int +,@p754 int +,@p755 int +,@p756 int +,@p757 int +,@p758 int +,@p759 int +,@p760 int +,@p761 int +,@p762 int +,@p763 int +,@p764 int +,@p765 int +,@p766 int +,@p767 int +,@p768 int +,@p769 int +,@p770 int +,@p771 int +,@p772 int +,@p773 int +,@p774 int +,@p775 int +,@p776 int +,@p777 int +,@p778 int +,@p779 int +,@p780 int +,@p781 int +,@p782 int +,@p783 int +,@p784 int +,@p785 int +,@p786 int +,@p787 int +,@p788 int +,@p789 int +,@p790 int +,@p791 int +,@p792 int +,@p793 int +,@p794 int +,@p795 int +,@p796 int +,@p797 int +,@p798 int +,@p799 int +,@p800 int +,@p801 int +,@p802 int +,@p803 int +,@p804 int +,@p805 int +,@p806 int +,@p807 int +,@p808 int +,@p809 int +,@p810 int +,@p811 int +,@p812 int +,@p813 int +,@p814 int +,@p815 int +,@p816 int +,@p817 int +,@p818 int +,@p819 int +,@p820 int +,@p821 int +,@p822 int +,@p823 int +,@p824 int +,@p825 int +,@p826 int +,@p827 int +,@p828 int +,@p829 int +,@p830 int +,@p831 int +,@p832 int +,@p833 int +,@p834 int +,@p835 int +,@p836 int +,@p837 int +,@p838 int +,@p839 int +,@p840 int +,@p841 int +,@p842 int +,@p843 int +,@p844 int +,@p845 int +,@p846 int +,@p847 int +,@p848 int +,@p849 int +,@p850 int +,@p851 int +,@p852 int +,@p853 int +,@p854 int +,@p855 int +,@p856 int +,@p857 int +,@p858 int +,@p859 int +,@p860 int +,@p861 int +,@p862 int +,@p863 int +,@p864 int +,@p865 int +,@p866 int +,@p867 int +,@p868 int +,@p869 int +,@p870 int +,@p871 int +,@p872 int +,@p873 int +,@p874 int +,@p875 int +,@p876 int +,@p877 int +,@p878 int +,@p879 int +,@p880 int +,@p881 int +,@p882 int +,@p883 int +,@p884 int +,@p885 int +,@p886 int +,@p887 int +,@p888 int +,@p889 int +,@p890 int +,@p891 int +,@p892 int +,@p893 int +,@p894 int +,@p895 int +,@p896 int +,@p897 int +,@p898 int +,@p899 int +,@p900 int +,@p901 int +,@p902 int +,@p903 int +,@p904 int +,@p905 int +,@p906 int +,@p907 int +,@p908 int +,@p909 int +,@p910 int +,@p911 int +,@p912 int +,@p913 int +,@p914 int +,@p915 int +,@p916 int +,@p917 int +,@p918 int +,@p919 int +,@p920 int +,@p921 int +,@p922 int +,@p923 int +,@p924 int +,@p925 int +,@p926 int +,@p927 int +,@p928 int +,@p929 int +,@p930 int +,@p931 int +,@p932 int +,@p933 int +,@p934 int +,@p935 int +,@p936 int +,@p937 int +,@p938 int +,@p939 int +,@p940 int +,@p941 int +,@p942 int +,@p943 int +,@p944 int +,@p945 int +,@p946 int +,@p947 int +,@p948 int +,@p949 int +,@p950 int +,@p951 int +,@p952 int +,@p953 int +,@p954 int +,@p955 int +,@p956 int +,@p957 int +,@p958 int +,@p959 int +,@p960 int +,@p961 int +,@p962 int +,@p963 int +,@p964 int +,@p965 int +,@p966 int +,@p967 int +,@p968 int +,@p969 int +,@p970 int +,@p971 int +,@p972 int +,@p973 int +,@p974 int +,@p975 int +,@p976 int +,@p977 int +,@p978 int +,@p979 int +,@p980 int +,@p981 int +,@p982 int +,@p983 int +,@p984 int +,@p985 int +,@p986 int +,@p987 int +,@p988 int +,@p989 int +,@p990 int +,@p991 int +,@p992 int +,@p993 int +,@p994 int +,@p995 int +,@p996 int +,@p997 int +,@p998 int +,@p999 int +,@p1000 int +,@p1001 int +,@p1002 int +,@p1003 int +,@p1004 int +,@p1005 int +,@p1006 int +,@p1007 int +,@p1008 int +,@p1009 int +,@p1010 int +,@p1011 int +,@p1012 int +,@p1013 int +,@p1014 int +,@p1015 int +,@p1016 int +,@p1017 int +,@p1018 int +,@p1019 int +,@p1020 int +,@p1021 int +,@p1022 int +,@p1023 int +,@p1024 int +,@p1025 int +,@p1026 int +,@p1027 int +,@p1028 int +,@p1029 int +,@p1030 int +,@p1031 int +,@p1032 int +,@p1033 int +,@p1034 int +,@p1035 int +,@p1036 int +,@p1037 int +,@p1038 int +,@p1039 int +,@p1040 int +,@p1041 int +,@p1042 int +,@p1043 int +,@p1044 int +,@p1045 int +,@p1046 int +,@p1047 int +,@p1048 int +,@p1049 int +,@p1050 int +,@p1051 int +,@p1052 int +,@p1053 int +,@p1054 int +,@p1055 int +,@p1056 int +,@p1057 int +,@p1058 int +,@p1059 int +,@p1060 int +,@p1061 int +,@p1062 int +,@p1063 int +,@p1064 int +,@p1065 int +,@p1066 int +,@p1067 int +,@p1068 int +,@p1069 int +,@p1070 int +,@p1071 int +,@p1072 int +,@p1073 int +,@p1074 int +,@p1075 int +,@p1076 int +,@p1077 int +,@p1078 int +,@p1079 int +,@p1080 int +,@p1081 int +,@p1082 int +,@p1083 int +,@p1084 int +,@p1085 int +,@p1086 int +,@p1087 int +,@p1088 int +,@p1089 int +,@p1090 int +,@p1091 int +,@p1092 int +,@p1093 int +,@p1094 int +,@p1095 int +,@p1096 int +,@p1097 int +,@p1098 int +,@p1099 int +,@p1100 int +,@p1101 int +,@p1102 int +,@p1103 int +,@p1104 int +,@p1105 int +,@p1106 int +,@p1107 int +,@p1108 int +,@p1109 int +,@p1110 int +,@p1111 int +,@p1112 int +,@p1113 int +,@p1114 int +,@p1115 int +,@p1116 int +,@p1117 int +,@p1118 int +,@p1119 int +,@p1120 int +,@p1121 int +,@p1122 int +,@p1123 int +,@p1124 int +,@p1125 int +,@p1126 int +,@p1127 int +,@p1128 int +,@p1129 int +,@p1130 int +,@p1131 int +,@p1132 int +,@p1133 int +,@p1134 int +,@p1135 int +,@p1136 int +,@p1137 int +,@p1138 int +,@p1139 int +,@p1140 int +,@p1141 int +,@p1142 int +,@p1143 int +,@p1144 int +,@p1145 int +,@p1146 int +,@p1147 int +,@p1148 int +,@p1149 int +,@p1150 int +,@p1151 int +,@p1152 int +,@p1153 int +,@p1154 int +,@p1155 int +,@p1156 int +,@p1157 int +,@p1158 int +,@p1159 int +,@p1160 int +,@p1161 int +,@p1162 int +,@p1163 int +,@p1164 int +,@p1165 int +,@p1166 int +,@p1167 int +,@p1168 int +,@p1169 int +,@p1170 int +,@p1171 int +,@p1172 int +,@p1173 int +,@p1174 int +,@p1175 int +,@p1176 int +,@p1177 int +,@p1178 int +,@p1179 int +,@p1180 int +,@p1181 int +,@p1182 int +,@p1183 int +,@p1184 int +,@p1185 int +,@p1186 int +,@p1187 int +,@p1188 int +,@p1189 int +,@p1190 int +,@p1191 int +,@p1192 int +,@p1193 int +,@p1194 int +,@p1195 int +,@p1196 int +,@p1197 int +,@p1198 int +,@p1199 int +,@p1200 int +,@p1201 int +,@p1202 int +,@p1203 int +,@p1204 int +,@p1205 int +,@p1206 int +,@p1207 int +,@p1208 int +,@p1209 int +,@p1210 int +,@p1211 int +,@p1212 int +,@p1213 int +,@p1214 int +,@p1215 int +,@p1216 int +,@p1217 int +,@p1218 int +,@p1219 int +,@p1220 int +,@p1221 int +,@p1222 int +,@p1223 int +,@p1224 int +,@p1225 int +,@p1226 int +,@p1227 int +,@p1228 int +,@p1229 int +,@p1230 int +,@p1231 int +,@p1232 int +,@p1233 int +,@p1234 int +,@p1235 int +,@p1236 int +,@p1237 int +,@p1238 int +,@p1239 int +,@p1240 int +,@p1241 int +,@p1242 int +,@p1243 int +,@p1244 int +,@p1245 int +,@p1246 int +,@p1247 int +,@p1248 int +,@p1249 int +,@p1250 int +,@p1251 int +,@p1252 int +,@p1253 int +,@p1254 int +,@p1255 int +,@p1256 int +,@p1257 int +,@p1258 int +,@p1259 int +,@p1260 int +,@p1261 int +,@p1262 int +,@p1263 int +,@p1264 int +,@p1265 int +,@p1266 int +,@p1267 int +,@p1268 int +,@p1269 int +,@p1270 int +,@p1271 int +,@p1272 int +,@p1273 int +,@p1274 int +,@p1275 int +,@p1276 int +,@p1277 int +,@p1278 int +,@p1279 int +,@p1280 int +,@p1281 int +,@p1282 int +,@p1283 int +,@p1284 int +,@p1285 int +,@p1286 int +,@p1287 int +,@p1288 int +,@p1289 int +,@p1290 int +,@p1291 int +,@p1292 int +,@p1293 int +,@p1294 int +,@p1295 int +,@p1296 int +,@p1297 int +,@p1298 int +,@p1299 int +,@p1300 int +,@p1301 int +,@p1302 int +,@p1303 int +,@p1304 int +,@p1305 int +,@p1306 int +,@p1307 int +,@p1308 int +,@p1309 int +,@p1310 int +,@p1311 int +,@p1312 int +,@p1313 int +,@p1314 int +,@p1315 int +,@p1316 int +,@p1317 int +,@p1318 int +,@p1319 int +,@p1320 int +,@p1321 int +,@p1322 int +,@p1323 int +,@p1324 int +,@p1325 int +,@p1326 int +,@p1327 int +,@p1328 int +,@p1329 int +,@p1330 int +,@p1331 int +,@p1332 int +,@p1333 int +,@p1334 int +,@p1335 int +,@p1336 int +,@p1337 int +,@p1338 int +,@p1339 int +,@p1340 int +,@p1341 int +,@p1342 int +,@p1343 int +,@p1344 int +,@p1345 int +,@p1346 int +,@p1347 int +,@p1348 int +,@p1349 int +,@p1350 int +,@p1351 int +,@p1352 int +,@p1353 int +,@p1354 int +,@p1355 int +,@p1356 int +,@p1357 int +,@p1358 int +,@p1359 int +,@p1360 int +,@p1361 int +,@p1362 int +,@p1363 int +,@p1364 int +,@p1365 int +,@p1366 int +,@p1367 int +,@p1368 int +,@p1369 int +,@p1370 int +,@p1371 int +,@p1372 int +,@p1373 int +,@p1374 int +,@p1375 int +,@p1376 int +,@p1377 int +,@p1378 int +,@p1379 int +,@p1380 int +,@p1381 int +,@p1382 int +,@p1383 int +,@p1384 int +,@p1385 int +,@p1386 int +,@p1387 int +,@p1388 int +,@p1389 int +,@p1390 int +,@p1391 int +,@p1392 int +,@p1393 int +,@p1394 int +,@p1395 int +,@p1396 int +,@p1397 int +,@p1398 int +,@p1399 int +,@p1400 int +,@p1401 int +,@p1402 int +,@p1403 int +,@p1404 int +,@p1405 int +,@p1406 int +,@p1407 int +,@p1408 int +,@p1409 int +,@p1410 int +,@p1411 int +,@p1412 int +,@p1413 int +,@p1414 int +,@p1415 int +,@p1416 int +,@p1417 int +,@p1418 int +,@p1419 int +,@p1420 int +,@p1421 int +,@p1422 int +,@p1423 int +,@p1424 int +,@p1425 int +,@p1426 int +,@p1427 int +,@p1428 int +,@p1429 int +,@p1430 int +,@p1431 int +,@p1432 int +,@p1433 int +,@p1434 int +,@p1435 int +,@p1436 int +,@p1437 int +,@p1438 int +,@p1439 int +,@p1440 int +,@p1441 int +,@p1442 int +,@p1443 int +,@p1444 int +,@p1445 int +,@p1446 int +,@p1447 int +,@p1448 int +,@p1449 int +,@p1450 int +,@p1451 int +,@p1452 int +,@p1453 int +,@p1454 int +,@p1455 int +,@p1456 int +,@p1457 int +,@p1458 int +,@p1459 int +,@p1460 int +,@p1461 int +,@p1462 int +,@p1463 int +,@p1464 int +,@p1465 int +,@p1466 int +,@p1467 int +,@p1468 int +,@p1469 int +,@p1470 int +,@p1471 int +,@p1472 int +,@p1473 int +,@p1474 int +,@p1475 int +,@p1476 int +,@p1477 int +,@p1478 int +,@p1479 int +,@p1480 int +,@p1481 int +,@p1482 int +,@p1483 int +,@p1484 int +,@p1485 int +,@p1486 int +,@p1487 int +,@p1488 int +,@p1489 int +,@p1490 int +,@p1491 int +,@p1492 int +,@p1493 int +,@p1494 int +,@p1495 int +,@p1496 int +,@p1497 int +,@p1498 int +,@p1499 int +,@p1500 int +,@p1501 int +,@p1502 int +,@p1503 int +,@p1504 int +,@p1505 int +,@p1506 int +,@p1507 int +,@p1508 int +,@p1509 int +,@p1510 int +,@p1511 int +,@p1512 int +,@p1513 int +,@p1514 int +,@p1515 int +,@p1516 int +,@p1517 int +,@p1518 int +,@p1519 int +,@p1520 int +,@p1521 int +,@p1522 int +,@p1523 int +,@p1524 int +,@p1525 int +,@p1526 int +,@p1527 int +,@p1528 int +,@p1529 int +,@p1530 int +,@p1531 int +,@p1532 int +,@p1533 int +,@p1534 int +,@p1535 int +,@p1536 int +,@p1537 int +,@p1538 int +,@p1539 int +,@p1540 int +,@p1541 int +,@p1542 int +,@p1543 int +,@p1544 int +,@p1545 int +,@p1546 int +,@p1547 int +,@p1548 int +,@p1549 int +,@p1550 int +,@p1551 int +,@p1552 int +,@p1553 int +,@p1554 int +,@p1555 int +,@p1556 int +,@p1557 int +,@p1558 int +,@p1559 int +,@p1560 int +,@p1561 int +,@p1562 int +,@p1563 int +,@p1564 int +,@p1565 int +,@p1566 int +,@p1567 int +,@p1568 int +,@p1569 int +,@p1570 int +,@p1571 int +,@p1572 int +,@p1573 int +,@p1574 int +,@p1575 int +,@p1576 int +,@p1577 int +,@p1578 int +,@p1579 int +,@p1580 int +,@p1581 int +,@p1582 int +,@p1583 int +,@p1584 int +,@p1585 int +,@p1586 int +,@p1587 int +,@p1588 int +,@p1589 int +,@p1590 int +,@p1591 int +,@p1592 int +,@p1593 int +,@p1594 int +,@p1595 int +,@p1596 int +,@p1597 int +,@p1598 int +,@p1599 int +,@p1600 int +,@p1601 int +,@p1602 int +,@p1603 int +,@p1604 int +,@p1605 int +,@p1606 int +,@p1607 int +,@p1608 int +,@p1609 int +,@p1610 int +,@p1611 int +,@p1612 int +,@p1613 int +,@p1614 int +,@p1615 int +,@p1616 int +,@p1617 int +,@p1618 int +,@p1619 int +,@p1620 int +,@p1621 int +,@p1622 int +,@p1623 int +,@p1624 int +,@p1625 int +,@p1626 int +,@p1627 int +,@p1628 int +,@p1629 int +,@p1630 int +,@p1631 int +,@p1632 int +,@p1633 int +,@p1634 int +,@p1635 int +,@p1636 int +,@p1637 int +,@p1638 int +,@p1639 int +,@p1640 int +,@p1641 int +,@p1642 int +,@p1643 int +,@p1644 int +,@p1645 int +,@p1646 int +,@p1647 int +,@p1648 int +,@p1649 int +,@p1650 int +,@p1651 int +,@p1652 int +,@p1653 int +,@p1654 int +,@p1655 int +,@p1656 int +,@p1657 int +,@p1658 int +,@p1659 int +,@p1660 int +,@p1661 int +,@p1662 int +,@p1663 int +,@p1664 int +,@p1665 int +,@p1666 int +,@p1667 int +,@p1668 int +,@p1669 int +,@p1670 int +,@p1671 int +,@p1672 int +,@p1673 int +,@p1674 int +,@p1675 int +,@p1676 int +,@p1677 int +,@p1678 int +,@p1679 int +,@p1680 int +,@p1681 int +,@p1682 int +,@p1683 int +,@p1684 int +,@p1685 int +,@p1686 int +,@p1687 int +,@p1688 int +,@p1689 int +,@p1690 int +,@p1691 int +,@p1692 int +,@p1693 int +,@p1694 int +,@p1695 int +,@p1696 int +,@p1697 int +,@p1698 int +,@p1699 int +,@p1700 int +,@p1701 int +,@p1702 int +,@p1703 int +,@p1704 int +,@p1705 int +,@p1706 int +,@p1707 int +,@p1708 int +,@p1709 int +,@p1710 int +,@p1711 int +,@p1712 int +,@p1713 int +,@p1714 int +,@p1715 int +,@p1716 int +,@p1717 int +,@p1718 int +,@p1719 int +,@p1720 int +,@p1721 int +,@p1722 int +,@p1723 int +,@p1724 int +,@p1725 int +,@p1726 int +,@p1727 int +,@p1728 int +,@p1729 int +,@p1730 int +,@p1731 int +,@p1732 int +,@p1733 int +,@p1734 int +,@p1735 int +,@p1736 int +,@p1737 int +,@p1738 int +,@p1739 int +,@p1740 int +,@p1741 int +,@p1742 int +,@p1743 int +,@p1744 int +,@p1745 int +,@p1746 int +,@p1747 int +,@p1748 int +,@p1749 int +,@p1750 int +,@p1751 int +,@p1752 int +,@p1753 int +,@p1754 int +,@p1755 int +,@p1756 int +,@p1757 int +,@p1758 int +,@p1759 int +,@p1760 int +,@p1761 int +,@p1762 int +,@p1763 int +,@p1764 int +,@p1765 int +,@p1766 int +,@p1767 int +,@p1768 int +,@p1769 int +,@p1770 int +,@p1771 int +,@p1772 int +,@p1773 int +,@p1774 int +,@p1775 int +,@p1776 int +,@p1777 int +,@p1778 int +,@p1779 int +,@p1780 int +,@p1781 int +,@p1782 int +,@p1783 int +,@p1784 int +,@p1785 int +,@p1786 int +,@p1787 int +,@p1788 int +,@p1789 int +,@p1790 int +,@p1791 int +,@p1792 int +,@p1793 int +,@p1794 int +,@p1795 int +,@p1796 int +,@p1797 int +,@p1798 int +,@p1799 int +,@p1800 int +,@p1801 int +,@p1802 int +,@p1803 int +,@p1804 int +,@p1805 int +,@p1806 int +,@p1807 int +,@p1808 int +,@p1809 int +,@p1810 int +,@p1811 int +,@p1812 int +,@p1813 int +,@p1814 int +,@p1815 int +,@p1816 int +,@p1817 int +,@p1818 int +,@p1819 int +,@p1820 int +,@p1821 int +,@p1822 int +,@p1823 int +,@p1824 int +,@p1825 int +,@p1826 int +,@p1827 int +,@p1828 int +,@p1829 int +,@p1830 int +,@p1831 int +,@p1832 int +,@p1833 int +,@p1834 int +,@p1835 int +,@p1836 int +,@p1837 int +,@p1838 int +,@p1839 int +,@p1840 int +,@p1841 int +,@p1842 int +,@p1843 int +,@p1844 int +,@p1845 int +,@p1846 int +,@p1847 int +,@p1848 int +,@p1849 int +,@p1850 int +,@p1851 int +,@p1852 int +,@p1853 int +,@p1854 int +,@p1855 int +,@p1856 int +,@p1857 int +,@p1858 int +,@p1859 int +,@p1860 int +,@p1861 int +,@p1862 int +,@p1863 int +,@p1864 int +,@p1865 int +,@p1866 int +,@p1867 int +,@p1868 int +,@p1869 int +,@p1870 int +,@p1871 int +,@p1872 int +,@p1873 int +,@p1874 int +,@p1875 int +,@p1876 int +,@p1877 int +,@p1878 int +,@p1879 int +,@p1880 int +,@p1881 int +,@p1882 int +,@p1883 int +,@p1884 int +,@p1885 int +,@p1886 int +,@p1887 int +,@p1888 int +,@p1889 int +,@p1890 int +,@p1891 int +,@p1892 int +,@p1893 int +,@p1894 int +,@p1895 int +,@p1896 int +,@p1897 int +,@p1898 int +,@p1899 int +,@p1900 int +,@p1901 int +,@p1902 int +,@p1903 int +,@p1904 int +,@p1905 int +,@p1906 int +,@p1907 int +,@p1908 int +,@p1909 int +,@p1910 int +,@p1911 int +,@p1912 int +,@p1913 int +,@p1914 int +,@p1915 int +,@p1916 int +,@p1917 int +,@p1918 int +,@p1919 int +,@p1920 int +,@p1921 int +,@p1922 int +,@p1923 int +,@p1924 int +,@p1925 int +,@p1926 int +,@p1927 int +,@p1928 int +,@p1929 int +,@p1930 int +,@p1931 int +,@p1932 int +,@p1933 int +,@p1934 int +,@p1935 int +,@p1936 int +,@p1937 int +,@p1938 int +,@p1939 int +,@p1940 int +,@p1941 int +,@p1942 int +,@p1943 int +,@p1944 int +,@p1945 int +,@p1946 int +,@p1947 int +,@p1948 int +,@p1949 int +,@p1950 int +,@p1951 int +,@p1952 int +,@p1953 int +,@p1954 int +,@p1955 int +,@p1956 int +,@p1957 int +,@p1958 int +,@p1959 int +,@p1960 int +,@p1961 int +,@p1962 int +,@p1963 int +,@p1964 int +,@p1965 int +,@p1966 int +,@p1967 int +,@p1968 int +,@p1969 int +,@p1970 int +,@p1971 int +,@p1972 int +,@p1973 int +,@p1974 int +,@p1975 int +,@p1976 int +,@p1977 int +,@p1978 int +,@p1979 int +,@p1980 int +,@p1981 int +,@p1982 int +,@p1983 int +,@p1984 int +,@p1985 int +,@p1986 int +,@p1987 int +,@p1988 int +,@p1989 int +,@p1990 int +,@p1991 int +,@p1992 int +,@p1993 int +,@p1994 int +,@p1995 int +,@p1996 int +,@p1997 int +,@p1998 int +,@p1999 int +,@p2000 int +,@p2001 int +,@p2002 int +,@p2003 int +,@p2004 int +,@p2005 int +,@p2006 int +,@p2007 int +,@p2008 int +,@p2009 int +,@p2010 int +,@p2011 int +,@p2012 int +,@p2013 int +,@p2014 int +,@p2015 int +,@p2016 int +,@p2017 int +,@p2018 int +,@p2019 int +,@p2020 int +,@p2021 int +,@p2022 int +,@p2023 int +,@p2024 int +,@p2025 int +,@p2026 int +,@p2027 int +,@p2028 int +,@p2029 int +,@p2030 int +,@p2031 int +,@p2032 int +,@p2033 int +,@p2034 int +,@p2035 int +,@p2036 int +,@p2037 int +,@p2038 int +,@p2039 int +,@p2040 int +,@p2041 int +,@p2042 int +,@p2043 int +,@p2044 int +,@p2045 int +,@p2046 int +,@p2047 int +,@p2048 int +,@p2049 int +,@p2050 int +,@p2051 int +,@p2052 int +,@p2053 int +,@p2054 int +,@p2055 int +,@p2056 int +,@p2057 int +,@p2058 int +,@p2059 int +,@p2060 int +,@p2061 int +,@p2062 int +,@p2063 int +,@p2064 int +,@p2065 int +,@p2066 int +,@p2067 int +,@p2068 int +,@p2069 int +,@p2070 int +,@p2071 int +,@p2072 int +,@p2073 int +,@p2074 int +,@p2075 int +,@p2076 int +,@p2077 int +,@p2078 int +,@p2079 int +,@p2080 int +,@p2081 int +,@p2082 int +,@p2083 int +,@p2084 int +,@p2085 int +,@p2086 int +,@p2087 int +,@p2088 int +,@p2089 int +,@p2090 int +,@p2091 int +,@p2092 int +,@p2093 int +,@p2094 int +,@p2095 int +,@p2096 int +,@p2097 int +,@p2098 int +,@p2099 int +,@p2100 int +,@p2101 int +) +RETURNS INT +AS +BEGIN + RETURN 100 +END +GO +~~ERROR (Code: 180)~~ + +~~ERROR (Message: There are too many parameters in this CREATE FUNCTION statement. The maximum number is 2100.)~~ + + +GO + +SET XACT_ABORT ON; +GO + +begin transaction +GO + +GO + +CREATE FUNCTION fn180( + @p1 int +,@p2 int +,@p3 int +,@p4 int +,@p5 int +,@p6 int +,@p7 int +,@p8 int +,@p9 int +,@p10 int +,@p11 int +,@p12 int +,@p13 int +,@p14 int +,@p15 int +,@p16 int +,@p17 int +,@p18 int +,@p19 int +,@p20 int +,@p21 int +,@p22 int +,@p23 int +,@p24 int +,@p25 int +,@p26 int +,@p27 int +,@p28 int +,@p29 int +,@p30 int +,@p31 int +,@p32 int +,@p33 int +,@p34 int +,@p35 int +,@p36 int +,@p37 int +,@p38 int +,@p39 int +,@p40 int +,@p41 int +,@p42 int +,@p43 int +,@p44 int +,@p45 int +,@p46 int +,@p47 int +,@p48 int +,@p49 int +,@p50 int +,@p51 int +,@p52 int +,@p53 int +,@p54 int +,@p55 int +,@p56 int +,@p57 int +,@p58 int +,@p59 int +,@p60 int +,@p61 int +,@p62 int +,@p63 int +,@p64 int +,@p65 int +,@p66 int +,@p67 int +,@p68 int +,@p69 int +,@p70 int +,@p71 int +,@p72 int +,@p73 int +,@p74 int +,@p75 int +,@p76 int +,@p77 int +,@p78 int +,@p79 int +,@p80 int +,@p81 int +,@p82 int +,@p83 int +,@p84 int +,@p85 int +,@p86 int +,@p87 int +,@p88 int +,@p89 int +,@p90 int +,@p91 int +,@p92 int +,@p93 int +,@p94 int +,@p95 int +,@p96 int +,@p97 int +,@p98 int +,@p99 int +,@p100 int +,@p101 int +,@p102 int +,@p103 int +,@p104 int +,@p105 int +,@p106 int +,@p107 int +,@p108 int +,@p109 int +,@p110 int +,@p111 int +,@p112 int +,@p113 int +,@p114 int +,@p115 int +,@p116 int +,@p117 int +,@p118 int +,@p119 int +,@p120 int +,@p121 int +,@p122 int +,@p123 int +,@p124 int +,@p125 int +,@p126 int +,@p127 int +,@p128 int +,@p129 int +,@p130 int +,@p131 int +,@p132 int +,@p133 int +,@p134 int +,@p135 int +,@p136 int +,@p137 int +,@p138 int +,@p139 int +,@p140 int +,@p141 int +,@p142 int +,@p143 int +,@p144 int +,@p145 int +,@p146 int +,@p147 int +,@p148 int +,@p149 int +,@p150 int +,@p151 int +,@p152 int +,@p153 int +,@p154 int +,@p155 int +,@p156 int +,@p157 int +,@p158 int +,@p159 int +,@p160 int +,@p161 int +,@p162 int +,@p163 int +,@p164 int +,@p165 int +,@p166 int +,@p167 int +,@p168 int +,@p169 int +,@p170 int +,@p171 int +,@p172 int +,@p173 int +,@p174 int +,@p175 int +,@p176 int +,@p177 int +,@p178 int +,@p179 int +,@p180 int +,@p181 int +,@p182 int +,@p183 int +,@p184 int +,@p185 int +,@p186 int +,@p187 int +,@p188 int +,@p189 int +,@p190 int +,@p191 int +,@p192 int +,@p193 int +,@p194 int +,@p195 int +,@p196 int +,@p197 int +,@p198 int +,@p199 int +,@p200 int +,@p201 int +,@p202 int +,@p203 int +,@p204 int +,@p205 int +,@p206 int +,@p207 int +,@p208 int +,@p209 int +,@p210 int +,@p211 int +,@p212 int +,@p213 int +,@p214 int +,@p215 int +,@p216 int +,@p217 int +,@p218 int +,@p219 int +,@p220 int +,@p221 int +,@p222 int +,@p223 int +,@p224 int +,@p225 int +,@p226 int +,@p227 int +,@p228 int +,@p229 int +,@p230 int +,@p231 int +,@p232 int +,@p233 int +,@p234 int +,@p235 int +,@p236 int +,@p237 int +,@p238 int +,@p239 int +,@p240 int +,@p241 int +,@p242 int +,@p243 int +,@p244 int +,@p245 int +,@p246 int +,@p247 int +,@p248 int +,@p249 int +,@p250 int +,@p251 int +,@p252 int +,@p253 int +,@p254 int +,@p255 int +,@p256 int +,@p257 int +,@p258 int +,@p259 int +,@p260 int +,@p261 int +,@p262 int +,@p263 int +,@p264 int +,@p265 int +,@p266 int +,@p267 int +,@p268 int +,@p269 int +,@p270 int +,@p271 int +,@p272 int +,@p273 int +,@p274 int +,@p275 int +,@p276 int +,@p277 int +,@p278 int +,@p279 int +,@p280 int +,@p281 int +,@p282 int +,@p283 int +,@p284 int +,@p285 int +,@p286 int +,@p287 int +,@p288 int +,@p289 int +,@p290 int +,@p291 int +,@p292 int +,@p293 int +,@p294 int +,@p295 int +,@p296 int +,@p297 int +,@p298 int +,@p299 int +,@p300 int +,@p301 int +,@p302 int +,@p303 int +,@p304 int +,@p305 int +,@p306 int +,@p307 int +,@p308 int +,@p309 int +,@p310 int +,@p311 int +,@p312 int +,@p313 int +,@p314 int +,@p315 int +,@p316 int +,@p317 int +,@p318 int +,@p319 int +,@p320 int +,@p321 int +,@p322 int +,@p323 int +,@p324 int +,@p325 int +,@p326 int +,@p327 int +,@p328 int +,@p329 int +,@p330 int +,@p331 int +,@p332 int +,@p333 int +,@p334 int +,@p335 int +,@p336 int +,@p337 int +,@p338 int +,@p339 int +,@p340 int +,@p341 int +,@p342 int +,@p343 int +,@p344 int +,@p345 int +,@p346 int +,@p347 int +,@p348 int +,@p349 int +,@p350 int +,@p351 int +,@p352 int +,@p353 int +,@p354 int +,@p355 int +,@p356 int +,@p357 int +,@p358 int +,@p359 int +,@p360 int +,@p361 int +,@p362 int +,@p363 int +,@p364 int +,@p365 int +,@p366 int +,@p367 int +,@p368 int +,@p369 int +,@p370 int +,@p371 int +,@p372 int +,@p373 int +,@p374 int +,@p375 int +,@p376 int +,@p377 int +,@p378 int +,@p379 int +,@p380 int +,@p381 int +,@p382 int +,@p383 int +,@p384 int +,@p385 int +,@p386 int +,@p387 int +,@p388 int +,@p389 int +,@p390 int +,@p391 int +,@p392 int +,@p393 int +,@p394 int +,@p395 int +,@p396 int +,@p397 int +,@p398 int +,@p399 int +,@p400 int +,@p401 int +,@p402 int +,@p403 int +,@p404 int +,@p405 int +,@p406 int +,@p407 int +,@p408 int +,@p409 int +,@p410 int +,@p411 int +,@p412 int +,@p413 int +,@p414 int +,@p415 int +,@p416 int +,@p417 int +,@p418 int +,@p419 int +,@p420 int +,@p421 int +,@p422 int +,@p423 int +,@p424 int +,@p425 int +,@p426 int +,@p427 int +,@p428 int +,@p429 int +,@p430 int +,@p431 int +,@p432 int +,@p433 int +,@p434 int +,@p435 int +,@p436 int +,@p437 int +,@p438 int +,@p439 int +,@p440 int +,@p441 int +,@p442 int +,@p443 int +,@p444 int +,@p445 int +,@p446 int +,@p447 int +,@p448 int +,@p449 int +,@p450 int +,@p451 int +,@p452 int +,@p453 int +,@p454 int +,@p455 int +,@p456 int +,@p457 int +,@p458 int +,@p459 int +,@p460 int +,@p461 int +,@p462 int +,@p463 int +,@p464 int +,@p465 int +,@p466 int +,@p467 int +,@p468 int +,@p469 int +,@p470 int +,@p471 int +,@p472 int +,@p473 int +,@p474 int +,@p475 int +,@p476 int +,@p477 int +,@p478 int +,@p479 int +,@p480 int +,@p481 int +,@p482 int +,@p483 int +,@p484 int +,@p485 int +,@p486 int +,@p487 int +,@p488 int +,@p489 int +,@p490 int +,@p491 int +,@p492 int +,@p493 int +,@p494 int +,@p495 int +,@p496 int +,@p497 int +,@p498 int +,@p499 int +,@p500 int +,@p501 int +,@p502 int +,@p503 int +,@p504 int +,@p505 int +,@p506 int +,@p507 int +,@p508 int +,@p509 int +,@p510 int +,@p511 int +,@p512 int +,@p513 int +,@p514 int +,@p515 int +,@p516 int +,@p517 int +,@p518 int +,@p519 int +,@p520 int +,@p521 int +,@p522 int +,@p523 int +,@p524 int +,@p525 int +,@p526 int +,@p527 int +,@p528 int +,@p529 int +,@p530 int +,@p531 int +,@p532 int +,@p533 int +,@p534 int +,@p535 int +,@p536 int +,@p537 int +,@p538 int +,@p539 int +,@p540 int +,@p541 int +,@p542 int +,@p543 int +,@p544 int +,@p545 int +,@p546 int +,@p547 int +,@p548 int +,@p549 int +,@p550 int +,@p551 int +,@p552 int +,@p553 int +,@p554 int +,@p555 int +,@p556 int +,@p557 int +,@p558 int +,@p559 int +,@p560 int +,@p561 int +,@p562 int +,@p563 int +,@p564 int +,@p565 int +,@p566 int +,@p567 int +,@p568 int +,@p569 int +,@p570 int +,@p571 int +,@p572 int +,@p573 int +,@p574 int +,@p575 int +,@p576 int +,@p577 int +,@p578 int +,@p579 int +,@p580 int +,@p581 int +,@p582 int +,@p583 int +,@p584 int +,@p585 int +,@p586 int +,@p587 int +,@p588 int +,@p589 int +,@p590 int +,@p591 int +,@p592 int +,@p593 int +,@p594 int +,@p595 int +,@p596 int +,@p597 int +,@p598 int +,@p599 int +,@p600 int +,@p601 int +,@p602 int +,@p603 int +,@p604 int +,@p605 int +,@p606 int +,@p607 int +,@p608 int +,@p609 int +,@p610 int +,@p611 int +,@p612 int +,@p613 int +,@p614 int +,@p615 int +,@p616 int +,@p617 int +,@p618 int +,@p619 int +,@p620 int +,@p621 int +,@p622 int +,@p623 int +,@p624 int +,@p625 int +,@p626 int +,@p627 int +,@p628 int +,@p629 int +,@p630 int +,@p631 int +,@p632 int +,@p633 int +,@p634 int +,@p635 int +,@p636 int +,@p637 int +,@p638 int +,@p639 int +,@p640 int +,@p641 int +,@p642 int +,@p643 int +,@p644 int +,@p645 int +,@p646 int +,@p647 int +,@p648 int +,@p649 int +,@p650 int +,@p651 int +,@p652 int +,@p653 int +,@p654 int +,@p655 int +,@p656 int +,@p657 int +,@p658 int +,@p659 int +,@p660 int +,@p661 int +,@p662 int +,@p663 int +,@p664 int +,@p665 int +,@p666 int +,@p667 int +,@p668 int +,@p669 int +,@p670 int +,@p671 int +,@p672 int +,@p673 int +,@p674 int +,@p675 int +,@p676 int +,@p677 int +,@p678 int +,@p679 int +,@p680 int +,@p681 int +,@p682 int +,@p683 int +,@p684 int +,@p685 int +,@p686 int +,@p687 int +,@p688 int +,@p689 int +,@p690 int +,@p691 int +,@p692 int +,@p693 int +,@p694 int +,@p695 int +,@p696 int +,@p697 int +,@p698 int +,@p699 int +,@p700 int +,@p701 int +,@p702 int +,@p703 int +,@p704 int +,@p705 int +,@p706 int +,@p707 int +,@p708 int +,@p709 int +,@p710 int +,@p711 int +,@p712 int +,@p713 int +,@p714 int +,@p715 int +,@p716 int +,@p717 int +,@p718 int +,@p719 int +,@p720 int +,@p721 int +,@p722 int +,@p723 int +,@p724 int +,@p725 int +,@p726 int +,@p727 int +,@p728 int +,@p729 int +,@p730 int +,@p731 int +,@p732 int +,@p733 int +,@p734 int +,@p735 int +,@p736 int +,@p737 int +,@p738 int +,@p739 int +,@p740 int +,@p741 int +,@p742 int +,@p743 int +,@p744 int +,@p745 int +,@p746 int +,@p747 int +,@p748 int +,@p749 int +,@p750 int +,@p751 int +,@p752 int +,@p753 int +,@p754 int +,@p755 int +,@p756 int +,@p757 int +,@p758 int +,@p759 int +,@p760 int +,@p761 int +,@p762 int +,@p763 int +,@p764 int +,@p765 int +,@p766 int +,@p767 int +,@p768 int +,@p769 int +,@p770 int +,@p771 int +,@p772 int +,@p773 int +,@p774 int +,@p775 int +,@p776 int +,@p777 int +,@p778 int +,@p779 int +,@p780 int +,@p781 int +,@p782 int +,@p783 int +,@p784 int +,@p785 int +,@p786 int +,@p787 int +,@p788 int +,@p789 int +,@p790 int +,@p791 int +,@p792 int +,@p793 int +,@p794 int +,@p795 int +,@p796 int +,@p797 int +,@p798 int +,@p799 int +,@p800 int +,@p801 int +,@p802 int +,@p803 int +,@p804 int +,@p805 int +,@p806 int +,@p807 int +,@p808 int +,@p809 int +,@p810 int +,@p811 int +,@p812 int +,@p813 int +,@p814 int +,@p815 int +,@p816 int +,@p817 int +,@p818 int +,@p819 int +,@p820 int +,@p821 int +,@p822 int +,@p823 int +,@p824 int +,@p825 int +,@p826 int +,@p827 int +,@p828 int +,@p829 int +,@p830 int +,@p831 int +,@p832 int +,@p833 int +,@p834 int +,@p835 int +,@p836 int +,@p837 int +,@p838 int +,@p839 int +,@p840 int +,@p841 int +,@p842 int +,@p843 int +,@p844 int +,@p845 int +,@p846 int +,@p847 int +,@p848 int +,@p849 int +,@p850 int +,@p851 int +,@p852 int +,@p853 int +,@p854 int +,@p855 int +,@p856 int +,@p857 int +,@p858 int +,@p859 int +,@p860 int +,@p861 int +,@p862 int +,@p863 int +,@p864 int +,@p865 int +,@p866 int +,@p867 int +,@p868 int +,@p869 int +,@p870 int +,@p871 int +,@p872 int +,@p873 int +,@p874 int +,@p875 int +,@p876 int +,@p877 int +,@p878 int +,@p879 int +,@p880 int +,@p881 int +,@p882 int +,@p883 int +,@p884 int +,@p885 int +,@p886 int +,@p887 int +,@p888 int +,@p889 int +,@p890 int +,@p891 int +,@p892 int +,@p893 int +,@p894 int +,@p895 int +,@p896 int +,@p897 int +,@p898 int +,@p899 int +,@p900 int +,@p901 int +,@p902 int +,@p903 int +,@p904 int +,@p905 int +,@p906 int +,@p907 int +,@p908 int +,@p909 int +,@p910 int +,@p911 int +,@p912 int +,@p913 int +,@p914 int +,@p915 int +,@p916 int +,@p917 int +,@p918 int +,@p919 int +,@p920 int +,@p921 int +,@p922 int +,@p923 int +,@p924 int +,@p925 int +,@p926 int +,@p927 int +,@p928 int +,@p929 int +,@p930 int +,@p931 int +,@p932 int +,@p933 int +,@p934 int +,@p935 int +,@p936 int +,@p937 int +,@p938 int +,@p939 int +,@p940 int +,@p941 int +,@p942 int +,@p943 int +,@p944 int +,@p945 int +,@p946 int +,@p947 int +,@p948 int +,@p949 int +,@p950 int +,@p951 int +,@p952 int +,@p953 int +,@p954 int +,@p955 int +,@p956 int +,@p957 int +,@p958 int +,@p959 int +,@p960 int +,@p961 int +,@p962 int +,@p963 int +,@p964 int +,@p965 int +,@p966 int +,@p967 int +,@p968 int +,@p969 int +,@p970 int +,@p971 int +,@p972 int +,@p973 int +,@p974 int +,@p975 int +,@p976 int +,@p977 int +,@p978 int +,@p979 int +,@p980 int +,@p981 int +,@p982 int +,@p983 int +,@p984 int +,@p985 int +,@p986 int +,@p987 int +,@p988 int +,@p989 int +,@p990 int +,@p991 int +,@p992 int +,@p993 int +,@p994 int +,@p995 int +,@p996 int +,@p997 int +,@p998 int +,@p999 int +,@p1000 int +,@p1001 int +,@p1002 int +,@p1003 int +,@p1004 int +,@p1005 int +,@p1006 int +,@p1007 int +,@p1008 int +,@p1009 int +,@p1010 int +,@p1011 int +,@p1012 int +,@p1013 int +,@p1014 int +,@p1015 int +,@p1016 int +,@p1017 int +,@p1018 int +,@p1019 int +,@p1020 int +,@p1021 int +,@p1022 int +,@p1023 int +,@p1024 int +,@p1025 int +,@p1026 int +,@p1027 int +,@p1028 int +,@p1029 int +,@p1030 int +,@p1031 int +,@p1032 int +,@p1033 int +,@p1034 int +,@p1035 int +,@p1036 int +,@p1037 int +,@p1038 int +,@p1039 int +,@p1040 int +,@p1041 int +,@p1042 int +,@p1043 int +,@p1044 int +,@p1045 int +,@p1046 int +,@p1047 int +,@p1048 int +,@p1049 int +,@p1050 int +,@p1051 int +,@p1052 int +,@p1053 int +,@p1054 int +,@p1055 int +,@p1056 int +,@p1057 int +,@p1058 int +,@p1059 int +,@p1060 int +,@p1061 int +,@p1062 int +,@p1063 int +,@p1064 int +,@p1065 int +,@p1066 int +,@p1067 int +,@p1068 int +,@p1069 int +,@p1070 int +,@p1071 int +,@p1072 int +,@p1073 int +,@p1074 int +,@p1075 int +,@p1076 int +,@p1077 int +,@p1078 int +,@p1079 int +,@p1080 int +,@p1081 int +,@p1082 int +,@p1083 int +,@p1084 int +,@p1085 int +,@p1086 int +,@p1087 int +,@p1088 int +,@p1089 int +,@p1090 int +,@p1091 int +,@p1092 int +,@p1093 int +,@p1094 int +,@p1095 int +,@p1096 int +,@p1097 int +,@p1098 int +,@p1099 int +,@p1100 int +,@p1101 int +,@p1102 int +,@p1103 int +,@p1104 int +,@p1105 int +,@p1106 int +,@p1107 int +,@p1108 int +,@p1109 int +,@p1110 int +,@p1111 int +,@p1112 int +,@p1113 int +,@p1114 int +,@p1115 int +,@p1116 int +,@p1117 int +,@p1118 int +,@p1119 int +,@p1120 int +,@p1121 int +,@p1122 int +,@p1123 int +,@p1124 int +,@p1125 int +,@p1126 int +,@p1127 int +,@p1128 int +,@p1129 int +,@p1130 int +,@p1131 int +,@p1132 int +,@p1133 int +,@p1134 int +,@p1135 int +,@p1136 int +,@p1137 int +,@p1138 int +,@p1139 int +,@p1140 int +,@p1141 int +,@p1142 int +,@p1143 int +,@p1144 int +,@p1145 int +,@p1146 int +,@p1147 int +,@p1148 int +,@p1149 int +,@p1150 int +,@p1151 int +,@p1152 int +,@p1153 int +,@p1154 int +,@p1155 int +,@p1156 int +,@p1157 int +,@p1158 int +,@p1159 int +,@p1160 int +,@p1161 int +,@p1162 int +,@p1163 int +,@p1164 int +,@p1165 int +,@p1166 int +,@p1167 int +,@p1168 int +,@p1169 int +,@p1170 int +,@p1171 int +,@p1172 int +,@p1173 int +,@p1174 int +,@p1175 int +,@p1176 int +,@p1177 int +,@p1178 int +,@p1179 int +,@p1180 int +,@p1181 int +,@p1182 int +,@p1183 int +,@p1184 int +,@p1185 int +,@p1186 int +,@p1187 int +,@p1188 int +,@p1189 int +,@p1190 int +,@p1191 int +,@p1192 int +,@p1193 int +,@p1194 int +,@p1195 int +,@p1196 int +,@p1197 int +,@p1198 int +,@p1199 int +,@p1200 int +,@p1201 int +,@p1202 int +,@p1203 int +,@p1204 int +,@p1205 int +,@p1206 int +,@p1207 int +,@p1208 int +,@p1209 int +,@p1210 int +,@p1211 int +,@p1212 int +,@p1213 int +,@p1214 int +,@p1215 int +,@p1216 int +,@p1217 int +,@p1218 int +,@p1219 int +,@p1220 int +,@p1221 int +,@p1222 int +,@p1223 int +,@p1224 int +,@p1225 int +,@p1226 int +,@p1227 int +,@p1228 int +,@p1229 int +,@p1230 int +,@p1231 int +,@p1232 int +,@p1233 int +,@p1234 int +,@p1235 int +,@p1236 int +,@p1237 int +,@p1238 int +,@p1239 int +,@p1240 int +,@p1241 int +,@p1242 int +,@p1243 int +,@p1244 int +,@p1245 int +,@p1246 int +,@p1247 int +,@p1248 int +,@p1249 int +,@p1250 int +,@p1251 int +,@p1252 int +,@p1253 int +,@p1254 int +,@p1255 int +,@p1256 int +,@p1257 int +,@p1258 int +,@p1259 int +,@p1260 int +,@p1261 int +,@p1262 int +,@p1263 int +,@p1264 int +,@p1265 int +,@p1266 int +,@p1267 int +,@p1268 int +,@p1269 int +,@p1270 int +,@p1271 int +,@p1272 int +,@p1273 int +,@p1274 int +,@p1275 int +,@p1276 int +,@p1277 int +,@p1278 int +,@p1279 int +,@p1280 int +,@p1281 int +,@p1282 int +,@p1283 int +,@p1284 int +,@p1285 int +,@p1286 int +,@p1287 int +,@p1288 int +,@p1289 int +,@p1290 int +,@p1291 int +,@p1292 int +,@p1293 int +,@p1294 int +,@p1295 int +,@p1296 int +,@p1297 int +,@p1298 int +,@p1299 int +,@p1300 int +,@p1301 int +,@p1302 int +,@p1303 int +,@p1304 int +,@p1305 int +,@p1306 int +,@p1307 int +,@p1308 int +,@p1309 int +,@p1310 int +,@p1311 int +,@p1312 int +,@p1313 int +,@p1314 int +,@p1315 int +,@p1316 int +,@p1317 int +,@p1318 int +,@p1319 int +,@p1320 int +,@p1321 int +,@p1322 int +,@p1323 int +,@p1324 int +,@p1325 int +,@p1326 int +,@p1327 int +,@p1328 int +,@p1329 int +,@p1330 int +,@p1331 int +,@p1332 int +,@p1333 int +,@p1334 int +,@p1335 int +,@p1336 int +,@p1337 int +,@p1338 int +,@p1339 int +,@p1340 int +,@p1341 int +,@p1342 int +,@p1343 int +,@p1344 int +,@p1345 int +,@p1346 int +,@p1347 int +,@p1348 int +,@p1349 int +,@p1350 int +,@p1351 int +,@p1352 int +,@p1353 int +,@p1354 int +,@p1355 int +,@p1356 int +,@p1357 int +,@p1358 int +,@p1359 int +,@p1360 int +,@p1361 int +,@p1362 int +,@p1363 int +,@p1364 int +,@p1365 int +,@p1366 int +,@p1367 int +,@p1368 int +,@p1369 int +,@p1370 int +,@p1371 int +,@p1372 int +,@p1373 int +,@p1374 int +,@p1375 int +,@p1376 int +,@p1377 int +,@p1378 int +,@p1379 int +,@p1380 int +,@p1381 int +,@p1382 int +,@p1383 int +,@p1384 int +,@p1385 int +,@p1386 int +,@p1387 int +,@p1388 int +,@p1389 int +,@p1390 int +,@p1391 int +,@p1392 int +,@p1393 int +,@p1394 int +,@p1395 int +,@p1396 int +,@p1397 int +,@p1398 int +,@p1399 int +,@p1400 int +,@p1401 int +,@p1402 int +,@p1403 int +,@p1404 int +,@p1405 int +,@p1406 int +,@p1407 int +,@p1408 int +,@p1409 int +,@p1410 int +,@p1411 int +,@p1412 int +,@p1413 int +,@p1414 int +,@p1415 int +,@p1416 int +,@p1417 int +,@p1418 int +,@p1419 int +,@p1420 int +,@p1421 int +,@p1422 int +,@p1423 int +,@p1424 int +,@p1425 int +,@p1426 int +,@p1427 int +,@p1428 int +,@p1429 int +,@p1430 int +,@p1431 int +,@p1432 int +,@p1433 int +,@p1434 int +,@p1435 int +,@p1436 int +,@p1437 int +,@p1438 int +,@p1439 int +,@p1440 int +,@p1441 int +,@p1442 int +,@p1443 int +,@p1444 int +,@p1445 int +,@p1446 int +,@p1447 int +,@p1448 int +,@p1449 int +,@p1450 int +,@p1451 int +,@p1452 int +,@p1453 int +,@p1454 int +,@p1455 int +,@p1456 int +,@p1457 int +,@p1458 int +,@p1459 int +,@p1460 int +,@p1461 int +,@p1462 int +,@p1463 int +,@p1464 int +,@p1465 int +,@p1466 int +,@p1467 int +,@p1468 int +,@p1469 int +,@p1470 int +,@p1471 int +,@p1472 int +,@p1473 int +,@p1474 int +,@p1475 int +,@p1476 int +,@p1477 int +,@p1478 int +,@p1479 int +,@p1480 int +,@p1481 int +,@p1482 int +,@p1483 int +,@p1484 int +,@p1485 int +,@p1486 int +,@p1487 int +,@p1488 int +,@p1489 int +,@p1490 int +,@p1491 int +,@p1492 int +,@p1493 int +,@p1494 int +,@p1495 int +,@p1496 int +,@p1497 int +,@p1498 int +,@p1499 int +,@p1500 int +,@p1501 int +,@p1502 int +,@p1503 int +,@p1504 int +,@p1505 int +,@p1506 int +,@p1507 int +,@p1508 int +,@p1509 int +,@p1510 int +,@p1511 int +,@p1512 int +,@p1513 int +,@p1514 int +,@p1515 int +,@p1516 int +,@p1517 int +,@p1518 int +,@p1519 int +,@p1520 int +,@p1521 int +,@p1522 int +,@p1523 int +,@p1524 int +,@p1525 int +,@p1526 int +,@p1527 int +,@p1528 int +,@p1529 int +,@p1530 int +,@p1531 int +,@p1532 int +,@p1533 int +,@p1534 int +,@p1535 int +,@p1536 int +,@p1537 int +,@p1538 int +,@p1539 int +,@p1540 int +,@p1541 int +,@p1542 int +,@p1543 int +,@p1544 int +,@p1545 int +,@p1546 int +,@p1547 int +,@p1548 int +,@p1549 int +,@p1550 int +,@p1551 int +,@p1552 int +,@p1553 int +,@p1554 int +,@p1555 int +,@p1556 int +,@p1557 int +,@p1558 int +,@p1559 int +,@p1560 int +,@p1561 int +,@p1562 int +,@p1563 int +,@p1564 int +,@p1565 int +,@p1566 int +,@p1567 int +,@p1568 int +,@p1569 int +,@p1570 int +,@p1571 int +,@p1572 int +,@p1573 int +,@p1574 int +,@p1575 int +,@p1576 int +,@p1577 int +,@p1578 int +,@p1579 int +,@p1580 int +,@p1581 int +,@p1582 int +,@p1583 int +,@p1584 int +,@p1585 int +,@p1586 int +,@p1587 int +,@p1588 int +,@p1589 int +,@p1590 int +,@p1591 int +,@p1592 int +,@p1593 int +,@p1594 int +,@p1595 int +,@p1596 int +,@p1597 int +,@p1598 int +,@p1599 int +,@p1600 int +,@p1601 int +,@p1602 int +,@p1603 int +,@p1604 int +,@p1605 int +,@p1606 int +,@p1607 int +,@p1608 int +,@p1609 int +,@p1610 int +,@p1611 int +,@p1612 int +,@p1613 int +,@p1614 int +,@p1615 int +,@p1616 int +,@p1617 int +,@p1618 int +,@p1619 int +,@p1620 int +,@p1621 int +,@p1622 int +,@p1623 int +,@p1624 int +,@p1625 int +,@p1626 int +,@p1627 int +,@p1628 int +,@p1629 int +,@p1630 int +,@p1631 int +,@p1632 int +,@p1633 int +,@p1634 int +,@p1635 int +,@p1636 int +,@p1637 int +,@p1638 int +,@p1639 int +,@p1640 int +,@p1641 int +,@p1642 int +,@p1643 int +,@p1644 int +,@p1645 int +,@p1646 int +,@p1647 int +,@p1648 int +,@p1649 int +,@p1650 int +,@p1651 int +,@p1652 int +,@p1653 int +,@p1654 int +,@p1655 int +,@p1656 int +,@p1657 int +,@p1658 int +,@p1659 int +,@p1660 int +,@p1661 int +,@p1662 int +,@p1663 int +,@p1664 int +,@p1665 int +,@p1666 int +,@p1667 int +,@p1668 int +,@p1669 int +,@p1670 int +,@p1671 int +,@p1672 int +,@p1673 int +,@p1674 int +,@p1675 int +,@p1676 int +,@p1677 int +,@p1678 int +,@p1679 int +,@p1680 int +,@p1681 int +,@p1682 int +,@p1683 int +,@p1684 int +,@p1685 int +,@p1686 int +,@p1687 int +,@p1688 int +,@p1689 int +,@p1690 int +,@p1691 int +,@p1692 int +,@p1693 int +,@p1694 int +,@p1695 int +,@p1696 int +,@p1697 int +,@p1698 int +,@p1699 int +,@p1700 int +,@p1701 int +,@p1702 int +,@p1703 int +,@p1704 int +,@p1705 int +,@p1706 int +,@p1707 int +,@p1708 int +,@p1709 int +,@p1710 int +,@p1711 int +,@p1712 int +,@p1713 int +,@p1714 int +,@p1715 int +,@p1716 int +,@p1717 int +,@p1718 int +,@p1719 int +,@p1720 int +,@p1721 int +,@p1722 int +,@p1723 int +,@p1724 int +,@p1725 int +,@p1726 int +,@p1727 int +,@p1728 int +,@p1729 int +,@p1730 int +,@p1731 int +,@p1732 int +,@p1733 int +,@p1734 int +,@p1735 int +,@p1736 int +,@p1737 int +,@p1738 int +,@p1739 int +,@p1740 int +,@p1741 int +,@p1742 int +,@p1743 int +,@p1744 int +,@p1745 int +,@p1746 int +,@p1747 int +,@p1748 int +,@p1749 int +,@p1750 int +,@p1751 int +,@p1752 int +,@p1753 int +,@p1754 int +,@p1755 int +,@p1756 int +,@p1757 int +,@p1758 int +,@p1759 int +,@p1760 int +,@p1761 int +,@p1762 int +,@p1763 int +,@p1764 int +,@p1765 int +,@p1766 int +,@p1767 int +,@p1768 int +,@p1769 int +,@p1770 int +,@p1771 int +,@p1772 int +,@p1773 int +,@p1774 int +,@p1775 int +,@p1776 int +,@p1777 int +,@p1778 int +,@p1779 int +,@p1780 int +,@p1781 int +,@p1782 int +,@p1783 int +,@p1784 int +,@p1785 int +,@p1786 int +,@p1787 int +,@p1788 int +,@p1789 int +,@p1790 int +,@p1791 int +,@p1792 int +,@p1793 int +,@p1794 int +,@p1795 int +,@p1796 int +,@p1797 int +,@p1798 int +,@p1799 int +,@p1800 int +,@p1801 int +,@p1802 int +,@p1803 int +,@p1804 int +,@p1805 int +,@p1806 int +,@p1807 int +,@p1808 int +,@p1809 int +,@p1810 int +,@p1811 int +,@p1812 int +,@p1813 int +,@p1814 int +,@p1815 int +,@p1816 int +,@p1817 int +,@p1818 int +,@p1819 int +,@p1820 int +,@p1821 int +,@p1822 int +,@p1823 int +,@p1824 int +,@p1825 int +,@p1826 int +,@p1827 int +,@p1828 int +,@p1829 int +,@p1830 int +,@p1831 int +,@p1832 int +,@p1833 int +,@p1834 int +,@p1835 int +,@p1836 int +,@p1837 int +,@p1838 int +,@p1839 int +,@p1840 int +,@p1841 int +,@p1842 int +,@p1843 int +,@p1844 int +,@p1845 int +,@p1846 int +,@p1847 int +,@p1848 int +,@p1849 int +,@p1850 int +,@p1851 int +,@p1852 int +,@p1853 int +,@p1854 int +,@p1855 int +,@p1856 int +,@p1857 int +,@p1858 int +,@p1859 int +,@p1860 int +,@p1861 int +,@p1862 int +,@p1863 int +,@p1864 int +,@p1865 int +,@p1866 int +,@p1867 int +,@p1868 int +,@p1869 int +,@p1870 int +,@p1871 int +,@p1872 int +,@p1873 int +,@p1874 int +,@p1875 int +,@p1876 int +,@p1877 int +,@p1878 int +,@p1879 int +,@p1880 int +,@p1881 int +,@p1882 int +,@p1883 int +,@p1884 int +,@p1885 int +,@p1886 int +,@p1887 int +,@p1888 int +,@p1889 int +,@p1890 int +,@p1891 int +,@p1892 int +,@p1893 int +,@p1894 int +,@p1895 int +,@p1896 int +,@p1897 int +,@p1898 int +,@p1899 int +,@p1900 int +,@p1901 int +,@p1902 int +,@p1903 int +,@p1904 int +,@p1905 int +,@p1906 int +,@p1907 int +,@p1908 int +,@p1909 int +,@p1910 int +,@p1911 int +,@p1912 int +,@p1913 int +,@p1914 int +,@p1915 int +,@p1916 int +,@p1917 int +,@p1918 int +,@p1919 int +,@p1920 int +,@p1921 int +,@p1922 int +,@p1923 int +,@p1924 int +,@p1925 int +,@p1926 int +,@p1927 int +,@p1928 int +,@p1929 int +,@p1930 int +,@p1931 int +,@p1932 int +,@p1933 int +,@p1934 int +,@p1935 int +,@p1936 int +,@p1937 int +,@p1938 int +,@p1939 int +,@p1940 int +,@p1941 int +,@p1942 int +,@p1943 int +,@p1944 int +,@p1945 int +,@p1946 int +,@p1947 int +,@p1948 int +,@p1949 int +,@p1950 int +,@p1951 int +,@p1952 int +,@p1953 int +,@p1954 int +,@p1955 int +,@p1956 int +,@p1957 int +,@p1958 int +,@p1959 int +,@p1960 int +,@p1961 int +,@p1962 int +,@p1963 int +,@p1964 int +,@p1965 int +,@p1966 int +,@p1967 int +,@p1968 int +,@p1969 int +,@p1970 int +,@p1971 int +,@p1972 int +,@p1973 int +,@p1974 int +,@p1975 int +,@p1976 int +,@p1977 int +,@p1978 int +,@p1979 int +,@p1980 int +,@p1981 int +,@p1982 int +,@p1983 int +,@p1984 int +,@p1985 int +,@p1986 int +,@p1987 int +,@p1988 int +,@p1989 int +,@p1990 int +,@p1991 int +,@p1992 int +,@p1993 int +,@p1994 int +,@p1995 int +,@p1996 int +,@p1997 int +,@p1998 int +,@p1999 int +,@p2000 int +,@p2001 int +,@p2002 int +,@p2003 int +,@p2004 int +,@p2005 int +,@p2006 int +,@p2007 int +,@p2008 int +,@p2009 int +,@p2010 int +,@p2011 int +,@p2012 int +,@p2013 int +,@p2014 int +,@p2015 int +,@p2016 int +,@p2017 int +,@p2018 int +,@p2019 int +,@p2020 int +,@p2021 int +,@p2022 int +,@p2023 int +,@p2024 int +,@p2025 int +,@p2026 int +,@p2027 int +,@p2028 int +,@p2029 int +,@p2030 int +,@p2031 int +,@p2032 int +,@p2033 int +,@p2034 int +,@p2035 int +,@p2036 int +,@p2037 int +,@p2038 int +,@p2039 int +,@p2040 int +,@p2041 int +,@p2042 int +,@p2043 int +,@p2044 int +,@p2045 int +,@p2046 int +,@p2047 int +,@p2048 int +,@p2049 int +,@p2050 int +,@p2051 int +,@p2052 int +,@p2053 int +,@p2054 int +,@p2055 int +,@p2056 int +,@p2057 int +,@p2058 int +,@p2059 int +,@p2060 int +,@p2061 int +,@p2062 int +,@p2063 int +,@p2064 int +,@p2065 int +,@p2066 int +,@p2067 int +,@p2068 int +,@p2069 int +,@p2070 int +,@p2071 int +,@p2072 int +,@p2073 int +,@p2074 int +,@p2075 int +,@p2076 int +,@p2077 int +,@p2078 int +,@p2079 int +,@p2080 int +,@p2081 int +,@p2082 int +,@p2083 int +,@p2084 int +,@p2085 int +,@p2086 int +,@p2087 int +,@p2088 int +,@p2089 int +,@p2090 int +,@p2091 int +,@p2092 int +,@p2093 int +,@p2094 int +,@p2095 int +,@p2096 int +,@p2097 int +,@p2098 int +,@p2099 int +,@p2100 int +,@p2101 int +) +RETURNS INT +AS +BEGIN + RETURN 100 +END +GO +~~ERROR (Code: 180)~~ + +~~ERROR (Message: There are too many parameters in this CREATE FUNCTION statement. The maximum number is 2100.)~~ + + +if (@@trancount > 0) select cast('Does not respect xact_abort flag' as text) else select cast('Respects xact_abort flag' as text) +GO +~~START~~ +text +Does not respect xact_abort flag +~~END~~ + + +if (@@trancount > 0) rollback tran +GO + +GO + +SET XACT_ABORT OFF; +GO + diff --git a/contrib/test/JDBC/sql_expected/180_2.out b/contrib/test/JDBC/sql_expected/180_2.out new file mode 100644 index 00000000000..a6fb35843c4 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/180_2.out @@ -0,0 +1,4255 @@ + + +-- simple batch start +GO + +CREATE PROC p180( + @p1 int +,@p2 int +,@p3 int +,@p4 int +,@p5 int +,@p6 int +,@p7 int +,@p8 int +,@p9 int +,@p10 int +,@p11 int +,@p12 int +,@p13 int +,@p14 int +,@p15 int +,@p16 int +,@p17 int +,@p18 int +,@p19 int +,@p20 int +,@p21 int +,@p22 int +,@p23 int +,@p24 int +,@p25 int +,@p26 int +,@p27 int +,@p28 int +,@p29 int +,@p30 int +,@p31 int +,@p32 int +,@p33 int +,@p34 int +,@p35 int +,@p36 int +,@p37 int +,@p38 int +,@p39 int +,@p40 int +,@p41 int +,@p42 int +,@p43 int +,@p44 int +,@p45 int +,@p46 int +,@p47 int +,@p48 int +,@p49 int +,@p50 int +,@p51 int +,@p52 int +,@p53 int +,@p54 int +,@p55 int +,@p56 int +,@p57 int +,@p58 int +,@p59 int +,@p60 int +,@p61 int +,@p62 int +,@p63 int +,@p64 int +,@p65 int +,@p66 int +,@p67 int +,@p68 int +,@p69 int +,@p70 int +,@p71 int +,@p72 int +,@p73 int +,@p74 int +,@p75 int +,@p76 int +,@p77 int +,@p78 int +,@p79 int +,@p80 int +,@p81 int +,@p82 int +,@p83 int +,@p84 int +,@p85 int +,@p86 int +,@p87 int +,@p88 int +,@p89 int +,@p90 int +,@p91 int +,@p92 int +,@p93 int +,@p94 int +,@p95 int +,@p96 int +,@p97 int +,@p98 int +,@p99 int +,@p100 int +,@p101 int +,@p102 int +,@p103 int +,@p104 int +,@p105 int +,@p106 int +,@p107 int +,@p108 int +,@p109 int +,@p110 int +,@p111 int +,@p112 int +,@p113 int +,@p114 int +,@p115 int +,@p116 int +,@p117 int +,@p118 int +,@p119 int +,@p120 int +,@p121 int +,@p122 int +,@p123 int +,@p124 int +,@p125 int +,@p126 int +,@p127 int +,@p128 int +,@p129 int +,@p130 int +,@p131 int +,@p132 int +,@p133 int +,@p134 int +,@p135 int +,@p136 int +,@p137 int +,@p138 int +,@p139 int +,@p140 int +,@p141 int +,@p142 int +,@p143 int +,@p144 int +,@p145 int +,@p146 int +,@p147 int +,@p148 int +,@p149 int +,@p150 int +,@p151 int +,@p152 int +,@p153 int +,@p154 int +,@p155 int +,@p156 int +,@p157 int +,@p158 int +,@p159 int +,@p160 int +,@p161 int +,@p162 int +,@p163 int +,@p164 int +,@p165 int +,@p166 int +,@p167 int +,@p168 int +,@p169 int +,@p170 int +,@p171 int +,@p172 int +,@p173 int +,@p174 int +,@p175 int +,@p176 int +,@p177 int +,@p178 int +,@p179 int +,@p180 int +,@p181 int +,@p182 int +,@p183 int +,@p184 int +,@p185 int +,@p186 int +,@p187 int +,@p188 int +,@p189 int +,@p190 int +,@p191 int +,@p192 int +,@p193 int +,@p194 int +,@p195 int +,@p196 int +,@p197 int +,@p198 int +,@p199 int +,@p200 int +,@p201 int +,@p202 int +,@p203 int +,@p204 int +,@p205 int +,@p206 int +,@p207 int +,@p208 int +,@p209 int +,@p210 int +,@p211 int +,@p212 int +,@p213 int +,@p214 int +,@p215 int +,@p216 int +,@p217 int +,@p218 int +,@p219 int +,@p220 int +,@p221 int +,@p222 int +,@p223 int +,@p224 int +,@p225 int +,@p226 int +,@p227 int +,@p228 int +,@p229 int +,@p230 int +,@p231 int +,@p232 int +,@p233 int +,@p234 int +,@p235 int +,@p236 int +,@p237 int +,@p238 int +,@p239 int +,@p240 int +,@p241 int +,@p242 int +,@p243 int +,@p244 int +,@p245 int +,@p246 int +,@p247 int +,@p248 int +,@p249 int +,@p250 int +,@p251 int +,@p252 int +,@p253 int +,@p254 int +,@p255 int +,@p256 int +,@p257 int +,@p258 int +,@p259 int +,@p260 int +,@p261 int +,@p262 int +,@p263 int +,@p264 int +,@p265 int +,@p266 int +,@p267 int +,@p268 int +,@p269 int +,@p270 int +,@p271 int +,@p272 int +,@p273 int +,@p274 int +,@p275 int +,@p276 int +,@p277 int +,@p278 int +,@p279 int +,@p280 int +,@p281 int +,@p282 int +,@p283 int +,@p284 int +,@p285 int +,@p286 int +,@p287 int +,@p288 int +,@p289 int +,@p290 int +,@p291 int +,@p292 int +,@p293 int +,@p294 int +,@p295 int +,@p296 int +,@p297 int +,@p298 int +,@p299 int +,@p300 int +,@p301 int +,@p302 int +,@p303 int +,@p304 int +,@p305 int +,@p306 int +,@p307 int +,@p308 int +,@p309 int +,@p310 int +,@p311 int +,@p312 int +,@p313 int +,@p314 int +,@p315 int +,@p316 int +,@p317 int +,@p318 int +,@p319 int +,@p320 int +,@p321 int +,@p322 int +,@p323 int +,@p324 int +,@p325 int +,@p326 int +,@p327 int +,@p328 int +,@p329 int +,@p330 int +,@p331 int +,@p332 int +,@p333 int +,@p334 int +,@p335 int +,@p336 int +,@p337 int +,@p338 int +,@p339 int +,@p340 int +,@p341 int +,@p342 int +,@p343 int +,@p344 int +,@p345 int +,@p346 int +,@p347 int +,@p348 int +,@p349 int +,@p350 int +,@p351 int +,@p352 int +,@p353 int +,@p354 int +,@p355 int +,@p356 int +,@p357 int +,@p358 int +,@p359 int +,@p360 int +,@p361 int +,@p362 int +,@p363 int +,@p364 int +,@p365 int +,@p366 int +,@p367 int +,@p368 int +,@p369 int +,@p370 int +,@p371 int +,@p372 int +,@p373 int +,@p374 int +,@p375 int +,@p376 int +,@p377 int +,@p378 int +,@p379 int +,@p380 int +,@p381 int +,@p382 int +,@p383 int +,@p384 int +,@p385 int +,@p386 int +,@p387 int +,@p388 int +,@p389 int +,@p390 int +,@p391 int +,@p392 int +,@p393 int +,@p394 int +,@p395 int +,@p396 int +,@p397 int +,@p398 int +,@p399 int +,@p400 int +,@p401 int +,@p402 int +,@p403 int +,@p404 int +,@p405 int +,@p406 int +,@p407 int +,@p408 int +,@p409 int +,@p410 int +,@p411 int +,@p412 int +,@p413 int +,@p414 int +,@p415 int +,@p416 int +,@p417 int +,@p418 int +,@p419 int +,@p420 int +,@p421 int +,@p422 int +,@p423 int +,@p424 int +,@p425 int +,@p426 int +,@p427 int +,@p428 int +,@p429 int +,@p430 int +,@p431 int +,@p432 int +,@p433 int +,@p434 int +,@p435 int +,@p436 int +,@p437 int +,@p438 int +,@p439 int +,@p440 int +,@p441 int +,@p442 int +,@p443 int +,@p444 int +,@p445 int +,@p446 int +,@p447 int +,@p448 int +,@p449 int +,@p450 int +,@p451 int +,@p452 int +,@p453 int +,@p454 int +,@p455 int +,@p456 int +,@p457 int +,@p458 int +,@p459 int +,@p460 int +,@p461 int +,@p462 int +,@p463 int +,@p464 int +,@p465 int +,@p466 int +,@p467 int +,@p468 int +,@p469 int +,@p470 int +,@p471 int +,@p472 int +,@p473 int +,@p474 int +,@p475 int +,@p476 int +,@p477 int +,@p478 int +,@p479 int +,@p480 int +,@p481 int +,@p482 int +,@p483 int +,@p484 int +,@p485 int +,@p486 int +,@p487 int +,@p488 int +,@p489 int +,@p490 int +,@p491 int +,@p492 int +,@p493 int +,@p494 int +,@p495 int +,@p496 int +,@p497 int +,@p498 int +,@p499 int +,@p500 int +,@p501 int +,@p502 int +,@p503 int +,@p504 int +,@p505 int +,@p506 int +,@p507 int +,@p508 int +,@p509 int +,@p510 int +,@p511 int +,@p512 int +,@p513 int +,@p514 int +,@p515 int +,@p516 int +,@p517 int +,@p518 int +,@p519 int +,@p520 int +,@p521 int +,@p522 int +,@p523 int +,@p524 int +,@p525 int +,@p526 int +,@p527 int +,@p528 int +,@p529 int +,@p530 int +,@p531 int +,@p532 int +,@p533 int +,@p534 int +,@p535 int +,@p536 int +,@p537 int +,@p538 int +,@p539 int +,@p540 int +,@p541 int +,@p542 int +,@p543 int +,@p544 int +,@p545 int +,@p546 int +,@p547 int +,@p548 int +,@p549 int +,@p550 int +,@p551 int +,@p552 int +,@p553 int +,@p554 int +,@p555 int +,@p556 int +,@p557 int +,@p558 int +,@p559 int +,@p560 int +,@p561 int +,@p562 int +,@p563 int +,@p564 int +,@p565 int +,@p566 int +,@p567 int +,@p568 int +,@p569 int +,@p570 int +,@p571 int +,@p572 int +,@p573 int +,@p574 int +,@p575 int +,@p576 int +,@p577 int +,@p578 int +,@p579 int +,@p580 int +,@p581 int +,@p582 int +,@p583 int +,@p584 int +,@p585 int +,@p586 int +,@p587 int +,@p588 int +,@p589 int +,@p590 int +,@p591 int +,@p592 int +,@p593 int +,@p594 int +,@p595 int +,@p596 int +,@p597 int +,@p598 int +,@p599 int +,@p600 int +,@p601 int +,@p602 int +,@p603 int +,@p604 int +,@p605 int +,@p606 int +,@p607 int +,@p608 int +,@p609 int +,@p610 int +,@p611 int +,@p612 int +,@p613 int +,@p614 int +,@p615 int +,@p616 int +,@p617 int +,@p618 int +,@p619 int +,@p620 int +,@p621 int +,@p622 int +,@p623 int +,@p624 int +,@p625 int +,@p626 int +,@p627 int +,@p628 int +,@p629 int +,@p630 int +,@p631 int +,@p632 int +,@p633 int +,@p634 int +,@p635 int +,@p636 int +,@p637 int +,@p638 int +,@p639 int +,@p640 int +,@p641 int +,@p642 int +,@p643 int +,@p644 int +,@p645 int +,@p646 int +,@p647 int +,@p648 int +,@p649 int +,@p650 int +,@p651 int +,@p652 int +,@p653 int +,@p654 int +,@p655 int +,@p656 int +,@p657 int +,@p658 int +,@p659 int +,@p660 int +,@p661 int +,@p662 int +,@p663 int +,@p664 int +,@p665 int +,@p666 int +,@p667 int +,@p668 int +,@p669 int +,@p670 int +,@p671 int +,@p672 int +,@p673 int +,@p674 int +,@p675 int +,@p676 int +,@p677 int +,@p678 int +,@p679 int +,@p680 int +,@p681 int +,@p682 int +,@p683 int +,@p684 int +,@p685 int +,@p686 int +,@p687 int +,@p688 int +,@p689 int +,@p690 int +,@p691 int +,@p692 int +,@p693 int +,@p694 int +,@p695 int +,@p696 int +,@p697 int +,@p698 int +,@p699 int +,@p700 int +,@p701 int +,@p702 int +,@p703 int +,@p704 int +,@p705 int +,@p706 int +,@p707 int +,@p708 int +,@p709 int +,@p710 int +,@p711 int +,@p712 int +,@p713 int +,@p714 int +,@p715 int +,@p716 int +,@p717 int +,@p718 int +,@p719 int +,@p720 int +,@p721 int +,@p722 int +,@p723 int +,@p724 int +,@p725 int +,@p726 int +,@p727 int +,@p728 int +,@p729 int +,@p730 int +,@p731 int +,@p732 int +,@p733 int +,@p734 int +,@p735 int +,@p736 int +,@p737 int +,@p738 int +,@p739 int +,@p740 int +,@p741 int +,@p742 int +,@p743 int +,@p744 int +,@p745 int +,@p746 int +,@p747 int +,@p748 int +,@p749 int +,@p750 int +,@p751 int +,@p752 int +,@p753 int +,@p754 int +,@p755 int +,@p756 int +,@p757 int +,@p758 int +,@p759 int +,@p760 int +,@p761 int +,@p762 int +,@p763 int +,@p764 int +,@p765 int +,@p766 int +,@p767 int +,@p768 int +,@p769 int +,@p770 int +,@p771 int +,@p772 int +,@p773 int +,@p774 int +,@p775 int +,@p776 int +,@p777 int +,@p778 int +,@p779 int +,@p780 int +,@p781 int +,@p782 int +,@p783 int +,@p784 int +,@p785 int +,@p786 int +,@p787 int +,@p788 int +,@p789 int +,@p790 int +,@p791 int +,@p792 int +,@p793 int +,@p794 int +,@p795 int +,@p796 int +,@p797 int +,@p798 int +,@p799 int +,@p800 int +,@p801 int +,@p802 int +,@p803 int +,@p804 int +,@p805 int +,@p806 int +,@p807 int +,@p808 int +,@p809 int +,@p810 int +,@p811 int +,@p812 int +,@p813 int +,@p814 int +,@p815 int +,@p816 int +,@p817 int +,@p818 int +,@p819 int +,@p820 int +,@p821 int +,@p822 int +,@p823 int +,@p824 int +,@p825 int +,@p826 int +,@p827 int +,@p828 int +,@p829 int +,@p830 int +,@p831 int +,@p832 int +,@p833 int +,@p834 int +,@p835 int +,@p836 int +,@p837 int +,@p838 int +,@p839 int +,@p840 int +,@p841 int +,@p842 int +,@p843 int +,@p844 int +,@p845 int +,@p846 int +,@p847 int +,@p848 int +,@p849 int +,@p850 int +,@p851 int +,@p852 int +,@p853 int +,@p854 int +,@p855 int +,@p856 int +,@p857 int +,@p858 int +,@p859 int +,@p860 int +,@p861 int +,@p862 int +,@p863 int +,@p864 int +,@p865 int +,@p866 int +,@p867 int +,@p868 int +,@p869 int +,@p870 int +,@p871 int +,@p872 int +,@p873 int +,@p874 int +,@p875 int +,@p876 int +,@p877 int +,@p878 int +,@p879 int +,@p880 int +,@p881 int +,@p882 int +,@p883 int +,@p884 int +,@p885 int +,@p886 int +,@p887 int +,@p888 int +,@p889 int +,@p890 int +,@p891 int +,@p892 int +,@p893 int +,@p894 int +,@p895 int +,@p896 int +,@p897 int +,@p898 int +,@p899 int +,@p900 int +,@p901 int +,@p902 int +,@p903 int +,@p904 int +,@p905 int +,@p906 int +,@p907 int +,@p908 int +,@p909 int +,@p910 int +,@p911 int +,@p912 int +,@p913 int +,@p914 int +,@p915 int +,@p916 int +,@p917 int +,@p918 int +,@p919 int +,@p920 int +,@p921 int +,@p922 int +,@p923 int +,@p924 int +,@p925 int +,@p926 int +,@p927 int +,@p928 int +,@p929 int +,@p930 int +,@p931 int +,@p932 int +,@p933 int +,@p934 int +,@p935 int +,@p936 int +,@p937 int +,@p938 int +,@p939 int +,@p940 int +,@p941 int +,@p942 int +,@p943 int +,@p944 int +,@p945 int +,@p946 int +,@p947 int +,@p948 int +,@p949 int +,@p950 int +,@p951 int +,@p952 int +,@p953 int +,@p954 int +,@p955 int +,@p956 int +,@p957 int +,@p958 int +,@p959 int +,@p960 int +,@p961 int +,@p962 int +,@p963 int +,@p964 int +,@p965 int +,@p966 int +,@p967 int +,@p968 int +,@p969 int +,@p970 int +,@p971 int +,@p972 int +,@p973 int +,@p974 int +,@p975 int +,@p976 int +,@p977 int +,@p978 int +,@p979 int +,@p980 int +,@p981 int +,@p982 int +,@p983 int +,@p984 int +,@p985 int +,@p986 int +,@p987 int +,@p988 int +,@p989 int +,@p990 int +,@p991 int +,@p992 int +,@p993 int +,@p994 int +,@p995 int +,@p996 int +,@p997 int +,@p998 int +,@p999 int +,@p1000 int +,@p1001 int +,@p1002 int +,@p1003 int +,@p1004 int +,@p1005 int +,@p1006 int +,@p1007 int +,@p1008 int +,@p1009 int +,@p1010 int +,@p1011 int +,@p1012 int +,@p1013 int +,@p1014 int +,@p1015 int +,@p1016 int +,@p1017 int +,@p1018 int +,@p1019 int +,@p1020 int +,@p1021 int +,@p1022 int +,@p1023 int +,@p1024 int +,@p1025 int +,@p1026 int +,@p1027 int +,@p1028 int +,@p1029 int +,@p1030 int +,@p1031 int +,@p1032 int +,@p1033 int +,@p1034 int +,@p1035 int +,@p1036 int +,@p1037 int +,@p1038 int +,@p1039 int +,@p1040 int +,@p1041 int +,@p1042 int +,@p1043 int +,@p1044 int +,@p1045 int +,@p1046 int +,@p1047 int +,@p1048 int +,@p1049 int +,@p1050 int +,@p1051 int +,@p1052 int +,@p1053 int +,@p1054 int +,@p1055 int +,@p1056 int +,@p1057 int +,@p1058 int +,@p1059 int +,@p1060 int +,@p1061 int +,@p1062 int +,@p1063 int +,@p1064 int +,@p1065 int +,@p1066 int +,@p1067 int +,@p1068 int +,@p1069 int +,@p1070 int +,@p1071 int +,@p1072 int +,@p1073 int +,@p1074 int +,@p1075 int +,@p1076 int +,@p1077 int +,@p1078 int +,@p1079 int +,@p1080 int +,@p1081 int +,@p1082 int +,@p1083 int +,@p1084 int +,@p1085 int +,@p1086 int +,@p1087 int +,@p1088 int +,@p1089 int +,@p1090 int +,@p1091 int +,@p1092 int +,@p1093 int +,@p1094 int +,@p1095 int +,@p1096 int +,@p1097 int +,@p1098 int +,@p1099 int +,@p1100 int +,@p1101 int +,@p1102 int +,@p1103 int +,@p1104 int +,@p1105 int +,@p1106 int +,@p1107 int +,@p1108 int +,@p1109 int +,@p1110 int +,@p1111 int +,@p1112 int +,@p1113 int +,@p1114 int +,@p1115 int +,@p1116 int +,@p1117 int +,@p1118 int +,@p1119 int +,@p1120 int +,@p1121 int +,@p1122 int +,@p1123 int +,@p1124 int +,@p1125 int +,@p1126 int +,@p1127 int +,@p1128 int +,@p1129 int +,@p1130 int +,@p1131 int +,@p1132 int +,@p1133 int +,@p1134 int +,@p1135 int +,@p1136 int +,@p1137 int +,@p1138 int +,@p1139 int +,@p1140 int +,@p1141 int +,@p1142 int +,@p1143 int +,@p1144 int +,@p1145 int +,@p1146 int +,@p1147 int +,@p1148 int +,@p1149 int +,@p1150 int +,@p1151 int +,@p1152 int +,@p1153 int +,@p1154 int +,@p1155 int +,@p1156 int +,@p1157 int +,@p1158 int +,@p1159 int +,@p1160 int +,@p1161 int +,@p1162 int +,@p1163 int +,@p1164 int +,@p1165 int +,@p1166 int +,@p1167 int +,@p1168 int +,@p1169 int +,@p1170 int +,@p1171 int +,@p1172 int +,@p1173 int +,@p1174 int +,@p1175 int +,@p1176 int +,@p1177 int +,@p1178 int +,@p1179 int +,@p1180 int +,@p1181 int +,@p1182 int +,@p1183 int +,@p1184 int +,@p1185 int +,@p1186 int +,@p1187 int +,@p1188 int +,@p1189 int +,@p1190 int +,@p1191 int +,@p1192 int +,@p1193 int +,@p1194 int +,@p1195 int +,@p1196 int +,@p1197 int +,@p1198 int +,@p1199 int +,@p1200 int +,@p1201 int +,@p1202 int +,@p1203 int +,@p1204 int +,@p1205 int +,@p1206 int +,@p1207 int +,@p1208 int +,@p1209 int +,@p1210 int +,@p1211 int +,@p1212 int +,@p1213 int +,@p1214 int +,@p1215 int +,@p1216 int +,@p1217 int +,@p1218 int +,@p1219 int +,@p1220 int +,@p1221 int +,@p1222 int +,@p1223 int +,@p1224 int +,@p1225 int +,@p1226 int +,@p1227 int +,@p1228 int +,@p1229 int +,@p1230 int +,@p1231 int +,@p1232 int +,@p1233 int +,@p1234 int +,@p1235 int +,@p1236 int +,@p1237 int +,@p1238 int +,@p1239 int +,@p1240 int +,@p1241 int +,@p1242 int +,@p1243 int +,@p1244 int +,@p1245 int +,@p1246 int +,@p1247 int +,@p1248 int +,@p1249 int +,@p1250 int +,@p1251 int +,@p1252 int +,@p1253 int +,@p1254 int +,@p1255 int +,@p1256 int +,@p1257 int +,@p1258 int +,@p1259 int +,@p1260 int +,@p1261 int +,@p1262 int +,@p1263 int +,@p1264 int +,@p1265 int +,@p1266 int +,@p1267 int +,@p1268 int +,@p1269 int +,@p1270 int +,@p1271 int +,@p1272 int +,@p1273 int +,@p1274 int +,@p1275 int +,@p1276 int +,@p1277 int +,@p1278 int +,@p1279 int +,@p1280 int +,@p1281 int +,@p1282 int +,@p1283 int +,@p1284 int +,@p1285 int +,@p1286 int +,@p1287 int +,@p1288 int +,@p1289 int +,@p1290 int +,@p1291 int +,@p1292 int +,@p1293 int +,@p1294 int +,@p1295 int +,@p1296 int +,@p1297 int +,@p1298 int +,@p1299 int +,@p1300 int +,@p1301 int +,@p1302 int +,@p1303 int +,@p1304 int +,@p1305 int +,@p1306 int +,@p1307 int +,@p1308 int +,@p1309 int +,@p1310 int +,@p1311 int +,@p1312 int +,@p1313 int +,@p1314 int +,@p1315 int +,@p1316 int +,@p1317 int +,@p1318 int +,@p1319 int +,@p1320 int +,@p1321 int +,@p1322 int +,@p1323 int +,@p1324 int +,@p1325 int +,@p1326 int +,@p1327 int +,@p1328 int +,@p1329 int +,@p1330 int +,@p1331 int +,@p1332 int +,@p1333 int +,@p1334 int +,@p1335 int +,@p1336 int +,@p1337 int +,@p1338 int +,@p1339 int +,@p1340 int +,@p1341 int +,@p1342 int +,@p1343 int +,@p1344 int +,@p1345 int +,@p1346 int +,@p1347 int +,@p1348 int +,@p1349 int +,@p1350 int +,@p1351 int +,@p1352 int +,@p1353 int +,@p1354 int +,@p1355 int +,@p1356 int +,@p1357 int +,@p1358 int +,@p1359 int +,@p1360 int +,@p1361 int +,@p1362 int +,@p1363 int +,@p1364 int +,@p1365 int +,@p1366 int +,@p1367 int +,@p1368 int +,@p1369 int +,@p1370 int +,@p1371 int +,@p1372 int +,@p1373 int +,@p1374 int +,@p1375 int +,@p1376 int +,@p1377 int +,@p1378 int +,@p1379 int +,@p1380 int +,@p1381 int +,@p1382 int +,@p1383 int +,@p1384 int +,@p1385 int +,@p1386 int +,@p1387 int +,@p1388 int +,@p1389 int +,@p1390 int +,@p1391 int +,@p1392 int +,@p1393 int +,@p1394 int +,@p1395 int +,@p1396 int +,@p1397 int +,@p1398 int +,@p1399 int +,@p1400 int +,@p1401 int +,@p1402 int +,@p1403 int +,@p1404 int +,@p1405 int +,@p1406 int +,@p1407 int +,@p1408 int +,@p1409 int +,@p1410 int +,@p1411 int +,@p1412 int +,@p1413 int +,@p1414 int +,@p1415 int +,@p1416 int +,@p1417 int +,@p1418 int +,@p1419 int +,@p1420 int +,@p1421 int +,@p1422 int +,@p1423 int +,@p1424 int +,@p1425 int +,@p1426 int +,@p1427 int +,@p1428 int +,@p1429 int +,@p1430 int +,@p1431 int +,@p1432 int +,@p1433 int +,@p1434 int +,@p1435 int +,@p1436 int +,@p1437 int +,@p1438 int +,@p1439 int +,@p1440 int +,@p1441 int +,@p1442 int +,@p1443 int +,@p1444 int +,@p1445 int +,@p1446 int +,@p1447 int +,@p1448 int +,@p1449 int +,@p1450 int +,@p1451 int +,@p1452 int +,@p1453 int +,@p1454 int +,@p1455 int +,@p1456 int +,@p1457 int +,@p1458 int +,@p1459 int +,@p1460 int +,@p1461 int +,@p1462 int +,@p1463 int +,@p1464 int +,@p1465 int +,@p1466 int +,@p1467 int +,@p1468 int +,@p1469 int +,@p1470 int +,@p1471 int +,@p1472 int +,@p1473 int +,@p1474 int +,@p1475 int +,@p1476 int +,@p1477 int +,@p1478 int +,@p1479 int +,@p1480 int +,@p1481 int +,@p1482 int +,@p1483 int +,@p1484 int +,@p1485 int +,@p1486 int +,@p1487 int +,@p1488 int +,@p1489 int +,@p1490 int +,@p1491 int +,@p1492 int +,@p1493 int +,@p1494 int +,@p1495 int +,@p1496 int +,@p1497 int +,@p1498 int +,@p1499 int +,@p1500 int +,@p1501 int +,@p1502 int +,@p1503 int +,@p1504 int +,@p1505 int +,@p1506 int +,@p1507 int +,@p1508 int +,@p1509 int +,@p1510 int +,@p1511 int +,@p1512 int +,@p1513 int +,@p1514 int +,@p1515 int +,@p1516 int +,@p1517 int +,@p1518 int +,@p1519 int +,@p1520 int +,@p1521 int +,@p1522 int +,@p1523 int +,@p1524 int +,@p1525 int +,@p1526 int +,@p1527 int +,@p1528 int +,@p1529 int +,@p1530 int +,@p1531 int +,@p1532 int +,@p1533 int +,@p1534 int +,@p1535 int +,@p1536 int +,@p1537 int +,@p1538 int +,@p1539 int +,@p1540 int +,@p1541 int +,@p1542 int +,@p1543 int +,@p1544 int +,@p1545 int +,@p1546 int +,@p1547 int +,@p1548 int +,@p1549 int +,@p1550 int +,@p1551 int +,@p1552 int +,@p1553 int +,@p1554 int +,@p1555 int +,@p1556 int +,@p1557 int +,@p1558 int +,@p1559 int +,@p1560 int +,@p1561 int +,@p1562 int +,@p1563 int +,@p1564 int +,@p1565 int +,@p1566 int +,@p1567 int +,@p1568 int +,@p1569 int +,@p1570 int +,@p1571 int +,@p1572 int +,@p1573 int +,@p1574 int +,@p1575 int +,@p1576 int +,@p1577 int +,@p1578 int +,@p1579 int +,@p1580 int +,@p1581 int +,@p1582 int +,@p1583 int +,@p1584 int +,@p1585 int +,@p1586 int +,@p1587 int +,@p1588 int +,@p1589 int +,@p1590 int +,@p1591 int +,@p1592 int +,@p1593 int +,@p1594 int +,@p1595 int +,@p1596 int +,@p1597 int +,@p1598 int +,@p1599 int +,@p1600 int +,@p1601 int +,@p1602 int +,@p1603 int +,@p1604 int +,@p1605 int +,@p1606 int +,@p1607 int +,@p1608 int +,@p1609 int +,@p1610 int +,@p1611 int +,@p1612 int +,@p1613 int +,@p1614 int +,@p1615 int +,@p1616 int +,@p1617 int +,@p1618 int +,@p1619 int +,@p1620 int +,@p1621 int +,@p1622 int +,@p1623 int +,@p1624 int +,@p1625 int +,@p1626 int +,@p1627 int +,@p1628 int +,@p1629 int +,@p1630 int +,@p1631 int +,@p1632 int +,@p1633 int +,@p1634 int +,@p1635 int +,@p1636 int +,@p1637 int +,@p1638 int +,@p1639 int +,@p1640 int +,@p1641 int +,@p1642 int +,@p1643 int +,@p1644 int +,@p1645 int +,@p1646 int +,@p1647 int +,@p1648 int +,@p1649 int +,@p1650 int +,@p1651 int +,@p1652 int +,@p1653 int +,@p1654 int +,@p1655 int +,@p1656 int +,@p1657 int +,@p1658 int +,@p1659 int +,@p1660 int +,@p1661 int +,@p1662 int +,@p1663 int +,@p1664 int +,@p1665 int +,@p1666 int +,@p1667 int +,@p1668 int +,@p1669 int +,@p1670 int +,@p1671 int +,@p1672 int +,@p1673 int +,@p1674 int +,@p1675 int +,@p1676 int +,@p1677 int +,@p1678 int +,@p1679 int +,@p1680 int +,@p1681 int +,@p1682 int +,@p1683 int +,@p1684 int +,@p1685 int +,@p1686 int +,@p1687 int +,@p1688 int +,@p1689 int +,@p1690 int +,@p1691 int +,@p1692 int +,@p1693 int +,@p1694 int +,@p1695 int +,@p1696 int +,@p1697 int +,@p1698 int +,@p1699 int +,@p1700 int +,@p1701 int +,@p1702 int +,@p1703 int +,@p1704 int +,@p1705 int +,@p1706 int +,@p1707 int +,@p1708 int +,@p1709 int +,@p1710 int +,@p1711 int +,@p1712 int +,@p1713 int +,@p1714 int +,@p1715 int +,@p1716 int +,@p1717 int +,@p1718 int +,@p1719 int +,@p1720 int +,@p1721 int +,@p1722 int +,@p1723 int +,@p1724 int +,@p1725 int +,@p1726 int +,@p1727 int +,@p1728 int +,@p1729 int +,@p1730 int +,@p1731 int +,@p1732 int +,@p1733 int +,@p1734 int +,@p1735 int +,@p1736 int +,@p1737 int +,@p1738 int +,@p1739 int +,@p1740 int +,@p1741 int +,@p1742 int +,@p1743 int +,@p1744 int +,@p1745 int +,@p1746 int +,@p1747 int +,@p1748 int +,@p1749 int +,@p1750 int +,@p1751 int +,@p1752 int +,@p1753 int +,@p1754 int +,@p1755 int +,@p1756 int +,@p1757 int +,@p1758 int +,@p1759 int +,@p1760 int +,@p1761 int +,@p1762 int +,@p1763 int +,@p1764 int +,@p1765 int +,@p1766 int +,@p1767 int +,@p1768 int +,@p1769 int +,@p1770 int +,@p1771 int +,@p1772 int +,@p1773 int +,@p1774 int +,@p1775 int +,@p1776 int +,@p1777 int +,@p1778 int +,@p1779 int +,@p1780 int +,@p1781 int +,@p1782 int +,@p1783 int +,@p1784 int +,@p1785 int +,@p1786 int +,@p1787 int +,@p1788 int +,@p1789 int +,@p1790 int +,@p1791 int +,@p1792 int +,@p1793 int +,@p1794 int +,@p1795 int +,@p1796 int +,@p1797 int +,@p1798 int +,@p1799 int +,@p1800 int +,@p1801 int +,@p1802 int +,@p1803 int +,@p1804 int +,@p1805 int +,@p1806 int +,@p1807 int +,@p1808 int +,@p1809 int +,@p1810 int +,@p1811 int +,@p1812 int +,@p1813 int +,@p1814 int +,@p1815 int +,@p1816 int +,@p1817 int +,@p1818 int +,@p1819 int +,@p1820 int +,@p1821 int +,@p1822 int +,@p1823 int +,@p1824 int +,@p1825 int +,@p1826 int +,@p1827 int +,@p1828 int +,@p1829 int +,@p1830 int +,@p1831 int +,@p1832 int +,@p1833 int +,@p1834 int +,@p1835 int +,@p1836 int +,@p1837 int +,@p1838 int +,@p1839 int +,@p1840 int +,@p1841 int +,@p1842 int +,@p1843 int +,@p1844 int +,@p1845 int +,@p1846 int +,@p1847 int +,@p1848 int +,@p1849 int +,@p1850 int +,@p1851 int +,@p1852 int +,@p1853 int +,@p1854 int +,@p1855 int +,@p1856 int +,@p1857 int +,@p1858 int +,@p1859 int +,@p1860 int +,@p1861 int +,@p1862 int +,@p1863 int +,@p1864 int +,@p1865 int +,@p1866 int +,@p1867 int +,@p1868 int +,@p1869 int +,@p1870 int +,@p1871 int +,@p1872 int +,@p1873 int +,@p1874 int +,@p1875 int +,@p1876 int +,@p1877 int +,@p1878 int +,@p1879 int +,@p1880 int +,@p1881 int +,@p1882 int +,@p1883 int +,@p1884 int +,@p1885 int +,@p1886 int +,@p1887 int +,@p1888 int +,@p1889 int +,@p1890 int +,@p1891 int +,@p1892 int +,@p1893 int +,@p1894 int +,@p1895 int +,@p1896 int +,@p1897 int +,@p1898 int +,@p1899 int +,@p1900 int +,@p1901 int +,@p1902 int +,@p1903 int +,@p1904 int +,@p1905 int +,@p1906 int +,@p1907 int +,@p1908 int +,@p1909 int +,@p1910 int +,@p1911 int +,@p1912 int +,@p1913 int +,@p1914 int +,@p1915 int +,@p1916 int +,@p1917 int +,@p1918 int +,@p1919 int +,@p1920 int +,@p1921 int +,@p1922 int +,@p1923 int +,@p1924 int +,@p1925 int +,@p1926 int +,@p1927 int +,@p1928 int +,@p1929 int +,@p1930 int +,@p1931 int +,@p1932 int +,@p1933 int +,@p1934 int +,@p1935 int +,@p1936 int +,@p1937 int +,@p1938 int +,@p1939 int +,@p1940 int +,@p1941 int +,@p1942 int +,@p1943 int +,@p1944 int +,@p1945 int +,@p1946 int +,@p1947 int +,@p1948 int +,@p1949 int +,@p1950 int +,@p1951 int +,@p1952 int +,@p1953 int +,@p1954 int +,@p1955 int +,@p1956 int +,@p1957 int +,@p1958 int +,@p1959 int +,@p1960 int +,@p1961 int +,@p1962 int +,@p1963 int +,@p1964 int +,@p1965 int +,@p1966 int +,@p1967 int +,@p1968 int +,@p1969 int +,@p1970 int +,@p1971 int +,@p1972 int +,@p1973 int +,@p1974 int +,@p1975 int +,@p1976 int +,@p1977 int +,@p1978 int +,@p1979 int +,@p1980 int +,@p1981 int +,@p1982 int +,@p1983 int +,@p1984 int +,@p1985 int +,@p1986 int +,@p1987 int +,@p1988 int +,@p1989 int +,@p1990 int +,@p1991 int +,@p1992 int +,@p1993 int +,@p1994 int +,@p1995 int +,@p1996 int +,@p1997 int +,@p1998 int +,@p1999 int +,@p2000 int +,@p2001 int +,@p2002 int +,@p2003 int +,@p2004 int +,@p2005 int +,@p2006 int +,@p2007 int +,@p2008 int +,@p2009 int +,@p2010 int +,@p2011 int +,@p2012 int +,@p2013 int +,@p2014 int +,@p2015 int +,@p2016 int +,@p2017 int +,@p2018 int +,@p2019 int +,@p2020 int +,@p2021 int +,@p2022 int +,@p2023 int +,@p2024 int +,@p2025 int +,@p2026 int +,@p2027 int +,@p2028 int +,@p2029 int +,@p2030 int +,@p2031 int +,@p2032 int +,@p2033 int +,@p2034 int +,@p2035 int +,@p2036 int +,@p2037 int +,@p2038 int +,@p2039 int +,@p2040 int +,@p2041 int +,@p2042 int +,@p2043 int +,@p2044 int +,@p2045 int +,@p2046 int +,@p2047 int +,@p2048 int +,@p2049 int +,@p2050 int +,@p2051 int +,@p2052 int +,@p2053 int +,@p2054 int +,@p2055 int +,@p2056 int +,@p2057 int +,@p2058 int +,@p2059 int +,@p2060 int +,@p2061 int +,@p2062 int +,@p2063 int +,@p2064 int +,@p2065 int +,@p2066 int +,@p2067 int +,@p2068 int +,@p2069 int +,@p2070 int +,@p2071 int +,@p2072 int +,@p2073 int +,@p2074 int +,@p2075 int +,@p2076 int +,@p2077 int +,@p2078 int +,@p2079 int +,@p2080 int +,@p2081 int +,@p2082 int +,@p2083 int +,@p2084 int +,@p2085 int +,@p2086 int +,@p2087 int +,@p2088 int +,@p2089 int +,@p2090 int +,@p2091 int +,@p2092 int +,@p2093 int +,@p2094 int +,@p2095 int +,@p2096 int +,@p2097 int +,@p2098 int +,@p2099 int +,@p2100 int +,@p2101 int +) +AS +BEGIN + RETURN 100 +END +GO +~~ERROR (Code: 180)~~ + +~~ERROR (Message: There are too many parameters in this CREATE PROCEDURE statement. The maximum number is 2100.)~~ + + +GO + +SET XACT_ABORT ON; +GO + +begin transaction +GO + +GO + +CREATE PROC p180( + @p1 int +,@p2 int +,@p3 int +,@p4 int +,@p5 int +,@p6 int +,@p7 int +,@p8 int +,@p9 int +,@p10 int +,@p11 int +,@p12 int +,@p13 int +,@p14 int +,@p15 int +,@p16 int +,@p17 int +,@p18 int +,@p19 int +,@p20 int +,@p21 int +,@p22 int +,@p23 int +,@p24 int +,@p25 int +,@p26 int +,@p27 int +,@p28 int +,@p29 int +,@p30 int +,@p31 int +,@p32 int +,@p33 int +,@p34 int +,@p35 int +,@p36 int +,@p37 int +,@p38 int +,@p39 int +,@p40 int +,@p41 int +,@p42 int +,@p43 int +,@p44 int +,@p45 int +,@p46 int +,@p47 int +,@p48 int +,@p49 int +,@p50 int +,@p51 int +,@p52 int +,@p53 int +,@p54 int +,@p55 int +,@p56 int +,@p57 int +,@p58 int +,@p59 int +,@p60 int +,@p61 int +,@p62 int +,@p63 int +,@p64 int +,@p65 int +,@p66 int +,@p67 int +,@p68 int +,@p69 int +,@p70 int +,@p71 int +,@p72 int +,@p73 int +,@p74 int +,@p75 int +,@p76 int +,@p77 int +,@p78 int +,@p79 int +,@p80 int +,@p81 int +,@p82 int +,@p83 int +,@p84 int +,@p85 int +,@p86 int +,@p87 int +,@p88 int +,@p89 int +,@p90 int +,@p91 int +,@p92 int +,@p93 int +,@p94 int +,@p95 int +,@p96 int +,@p97 int +,@p98 int +,@p99 int +,@p100 int +,@p101 int +,@p102 int +,@p103 int +,@p104 int +,@p105 int +,@p106 int +,@p107 int +,@p108 int +,@p109 int +,@p110 int +,@p111 int +,@p112 int +,@p113 int +,@p114 int +,@p115 int +,@p116 int +,@p117 int +,@p118 int +,@p119 int +,@p120 int +,@p121 int +,@p122 int +,@p123 int +,@p124 int +,@p125 int +,@p126 int +,@p127 int +,@p128 int +,@p129 int +,@p130 int +,@p131 int +,@p132 int +,@p133 int +,@p134 int +,@p135 int +,@p136 int +,@p137 int +,@p138 int +,@p139 int +,@p140 int +,@p141 int +,@p142 int +,@p143 int +,@p144 int +,@p145 int +,@p146 int +,@p147 int +,@p148 int +,@p149 int +,@p150 int +,@p151 int +,@p152 int +,@p153 int +,@p154 int +,@p155 int +,@p156 int +,@p157 int +,@p158 int +,@p159 int +,@p160 int +,@p161 int +,@p162 int +,@p163 int +,@p164 int +,@p165 int +,@p166 int +,@p167 int +,@p168 int +,@p169 int +,@p170 int +,@p171 int +,@p172 int +,@p173 int +,@p174 int +,@p175 int +,@p176 int +,@p177 int +,@p178 int +,@p179 int +,@p180 int +,@p181 int +,@p182 int +,@p183 int +,@p184 int +,@p185 int +,@p186 int +,@p187 int +,@p188 int +,@p189 int +,@p190 int +,@p191 int +,@p192 int +,@p193 int +,@p194 int +,@p195 int +,@p196 int +,@p197 int +,@p198 int +,@p199 int +,@p200 int +,@p201 int +,@p202 int +,@p203 int +,@p204 int +,@p205 int +,@p206 int +,@p207 int +,@p208 int +,@p209 int +,@p210 int +,@p211 int +,@p212 int +,@p213 int +,@p214 int +,@p215 int +,@p216 int +,@p217 int +,@p218 int +,@p219 int +,@p220 int +,@p221 int +,@p222 int +,@p223 int +,@p224 int +,@p225 int +,@p226 int +,@p227 int +,@p228 int +,@p229 int +,@p230 int +,@p231 int +,@p232 int +,@p233 int +,@p234 int +,@p235 int +,@p236 int +,@p237 int +,@p238 int +,@p239 int +,@p240 int +,@p241 int +,@p242 int +,@p243 int +,@p244 int +,@p245 int +,@p246 int +,@p247 int +,@p248 int +,@p249 int +,@p250 int +,@p251 int +,@p252 int +,@p253 int +,@p254 int +,@p255 int +,@p256 int +,@p257 int +,@p258 int +,@p259 int +,@p260 int +,@p261 int +,@p262 int +,@p263 int +,@p264 int +,@p265 int +,@p266 int +,@p267 int +,@p268 int +,@p269 int +,@p270 int +,@p271 int +,@p272 int +,@p273 int +,@p274 int +,@p275 int +,@p276 int +,@p277 int +,@p278 int +,@p279 int +,@p280 int +,@p281 int +,@p282 int +,@p283 int +,@p284 int +,@p285 int +,@p286 int +,@p287 int +,@p288 int +,@p289 int +,@p290 int +,@p291 int +,@p292 int +,@p293 int +,@p294 int +,@p295 int +,@p296 int +,@p297 int +,@p298 int +,@p299 int +,@p300 int +,@p301 int +,@p302 int +,@p303 int +,@p304 int +,@p305 int +,@p306 int +,@p307 int +,@p308 int +,@p309 int +,@p310 int +,@p311 int +,@p312 int +,@p313 int +,@p314 int +,@p315 int +,@p316 int +,@p317 int +,@p318 int +,@p319 int +,@p320 int +,@p321 int +,@p322 int +,@p323 int +,@p324 int +,@p325 int +,@p326 int +,@p327 int +,@p328 int +,@p329 int +,@p330 int +,@p331 int +,@p332 int +,@p333 int +,@p334 int +,@p335 int +,@p336 int +,@p337 int +,@p338 int +,@p339 int +,@p340 int +,@p341 int +,@p342 int +,@p343 int +,@p344 int +,@p345 int +,@p346 int +,@p347 int +,@p348 int +,@p349 int +,@p350 int +,@p351 int +,@p352 int +,@p353 int +,@p354 int +,@p355 int +,@p356 int +,@p357 int +,@p358 int +,@p359 int +,@p360 int +,@p361 int +,@p362 int +,@p363 int +,@p364 int +,@p365 int +,@p366 int +,@p367 int +,@p368 int +,@p369 int +,@p370 int +,@p371 int +,@p372 int +,@p373 int +,@p374 int +,@p375 int +,@p376 int +,@p377 int +,@p378 int +,@p379 int +,@p380 int +,@p381 int +,@p382 int +,@p383 int +,@p384 int +,@p385 int +,@p386 int +,@p387 int +,@p388 int +,@p389 int +,@p390 int +,@p391 int +,@p392 int +,@p393 int +,@p394 int +,@p395 int +,@p396 int +,@p397 int +,@p398 int +,@p399 int +,@p400 int +,@p401 int +,@p402 int +,@p403 int +,@p404 int +,@p405 int +,@p406 int +,@p407 int +,@p408 int +,@p409 int +,@p410 int +,@p411 int +,@p412 int +,@p413 int +,@p414 int +,@p415 int +,@p416 int +,@p417 int +,@p418 int +,@p419 int +,@p420 int +,@p421 int +,@p422 int +,@p423 int +,@p424 int +,@p425 int +,@p426 int +,@p427 int +,@p428 int +,@p429 int +,@p430 int +,@p431 int +,@p432 int +,@p433 int +,@p434 int +,@p435 int +,@p436 int +,@p437 int +,@p438 int +,@p439 int +,@p440 int +,@p441 int +,@p442 int +,@p443 int +,@p444 int +,@p445 int +,@p446 int +,@p447 int +,@p448 int +,@p449 int +,@p450 int +,@p451 int +,@p452 int +,@p453 int +,@p454 int +,@p455 int +,@p456 int +,@p457 int +,@p458 int +,@p459 int +,@p460 int +,@p461 int +,@p462 int +,@p463 int +,@p464 int +,@p465 int +,@p466 int +,@p467 int +,@p468 int +,@p469 int +,@p470 int +,@p471 int +,@p472 int +,@p473 int +,@p474 int +,@p475 int +,@p476 int +,@p477 int +,@p478 int +,@p479 int +,@p480 int +,@p481 int +,@p482 int +,@p483 int +,@p484 int +,@p485 int +,@p486 int +,@p487 int +,@p488 int +,@p489 int +,@p490 int +,@p491 int +,@p492 int +,@p493 int +,@p494 int +,@p495 int +,@p496 int +,@p497 int +,@p498 int +,@p499 int +,@p500 int +,@p501 int +,@p502 int +,@p503 int +,@p504 int +,@p505 int +,@p506 int +,@p507 int +,@p508 int +,@p509 int +,@p510 int +,@p511 int +,@p512 int +,@p513 int +,@p514 int +,@p515 int +,@p516 int +,@p517 int +,@p518 int +,@p519 int +,@p520 int +,@p521 int +,@p522 int +,@p523 int +,@p524 int +,@p525 int +,@p526 int +,@p527 int +,@p528 int +,@p529 int +,@p530 int +,@p531 int +,@p532 int +,@p533 int +,@p534 int +,@p535 int +,@p536 int +,@p537 int +,@p538 int +,@p539 int +,@p540 int +,@p541 int +,@p542 int +,@p543 int +,@p544 int +,@p545 int +,@p546 int +,@p547 int +,@p548 int +,@p549 int +,@p550 int +,@p551 int +,@p552 int +,@p553 int +,@p554 int +,@p555 int +,@p556 int +,@p557 int +,@p558 int +,@p559 int +,@p560 int +,@p561 int +,@p562 int +,@p563 int +,@p564 int +,@p565 int +,@p566 int +,@p567 int +,@p568 int +,@p569 int +,@p570 int +,@p571 int +,@p572 int +,@p573 int +,@p574 int +,@p575 int +,@p576 int +,@p577 int +,@p578 int +,@p579 int +,@p580 int +,@p581 int +,@p582 int +,@p583 int +,@p584 int +,@p585 int +,@p586 int +,@p587 int +,@p588 int +,@p589 int +,@p590 int +,@p591 int +,@p592 int +,@p593 int +,@p594 int +,@p595 int +,@p596 int +,@p597 int +,@p598 int +,@p599 int +,@p600 int +,@p601 int +,@p602 int +,@p603 int +,@p604 int +,@p605 int +,@p606 int +,@p607 int +,@p608 int +,@p609 int +,@p610 int +,@p611 int +,@p612 int +,@p613 int +,@p614 int +,@p615 int +,@p616 int +,@p617 int +,@p618 int +,@p619 int +,@p620 int +,@p621 int +,@p622 int +,@p623 int +,@p624 int +,@p625 int +,@p626 int +,@p627 int +,@p628 int +,@p629 int +,@p630 int +,@p631 int +,@p632 int +,@p633 int +,@p634 int +,@p635 int +,@p636 int +,@p637 int +,@p638 int +,@p639 int +,@p640 int +,@p641 int +,@p642 int +,@p643 int +,@p644 int +,@p645 int +,@p646 int +,@p647 int +,@p648 int +,@p649 int +,@p650 int +,@p651 int +,@p652 int +,@p653 int +,@p654 int +,@p655 int +,@p656 int +,@p657 int +,@p658 int +,@p659 int +,@p660 int +,@p661 int +,@p662 int +,@p663 int +,@p664 int +,@p665 int +,@p666 int +,@p667 int +,@p668 int +,@p669 int +,@p670 int +,@p671 int +,@p672 int +,@p673 int +,@p674 int +,@p675 int +,@p676 int +,@p677 int +,@p678 int +,@p679 int +,@p680 int +,@p681 int +,@p682 int +,@p683 int +,@p684 int +,@p685 int +,@p686 int +,@p687 int +,@p688 int +,@p689 int +,@p690 int +,@p691 int +,@p692 int +,@p693 int +,@p694 int +,@p695 int +,@p696 int +,@p697 int +,@p698 int +,@p699 int +,@p700 int +,@p701 int +,@p702 int +,@p703 int +,@p704 int +,@p705 int +,@p706 int +,@p707 int +,@p708 int +,@p709 int +,@p710 int +,@p711 int +,@p712 int +,@p713 int +,@p714 int +,@p715 int +,@p716 int +,@p717 int +,@p718 int +,@p719 int +,@p720 int +,@p721 int +,@p722 int +,@p723 int +,@p724 int +,@p725 int +,@p726 int +,@p727 int +,@p728 int +,@p729 int +,@p730 int +,@p731 int +,@p732 int +,@p733 int +,@p734 int +,@p735 int +,@p736 int +,@p737 int +,@p738 int +,@p739 int +,@p740 int +,@p741 int +,@p742 int +,@p743 int +,@p744 int +,@p745 int +,@p746 int +,@p747 int +,@p748 int +,@p749 int +,@p750 int +,@p751 int +,@p752 int +,@p753 int +,@p754 int +,@p755 int +,@p756 int +,@p757 int +,@p758 int +,@p759 int +,@p760 int +,@p761 int +,@p762 int +,@p763 int +,@p764 int +,@p765 int +,@p766 int +,@p767 int +,@p768 int +,@p769 int +,@p770 int +,@p771 int +,@p772 int +,@p773 int +,@p774 int +,@p775 int +,@p776 int +,@p777 int +,@p778 int +,@p779 int +,@p780 int +,@p781 int +,@p782 int +,@p783 int +,@p784 int +,@p785 int +,@p786 int +,@p787 int +,@p788 int +,@p789 int +,@p790 int +,@p791 int +,@p792 int +,@p793 int +,@p794 int +,@p795 int +,@p796 int +,@p797 int +,@p798 int +,@p799 int +,@p800 int +,@p801 int +,@p802 int +,@p803 int +,@p804 int +,@p805 int +,@p806 int +,@p807 int +,@p808 int +,@p809 int +,@p810 int +,@p811 int +,@p812 int +,@p813 int +,@p814 int +,@p815 int +,@p816 int +,@p817 int +,@p818 int +,@p819 int +,@p820 int +,@p821 int +,@p822 int +,@p823 int +,@p824 int +,@p825 int +,@p826 int +,@p827 int +,@p828 int +,@p829 int +,@p830 int +,@p831 int +,@p832 int +,@p833 int +,@p834 int +,@p835 int +,@p836 int +,@p837 int +,@p838 int +,@p839 int +,@p840 int +,@p841 int +,@p842 int +,@p843 int +,@p844 int +,@p845 int +,@p846 int +,@p847 int +,@p848 int +,@p849 int +,@p850 int +,@p851 int +,@p852 int +,@p853 int +,@p854 int +,@p855 int +,@p856 int +,@p857 int +,@p858 int +,@p859 int +,@p860 int +,@p861 int +,@p862 int +,@p863 int +,@p864 int +,@p865 int +,@p866 int +,@p867 int +,@p868 int +,@p869 int +,@p870 int +,@p871 int +,@p872 int +,@p873 int +,@p874 int +,@p875 int +,@p876 int +,@p877 int +,@p878 int +,@p879 int +,@p880 int +,@p881 int +,@p882 int +,@p883 int +,@p884 int +,@p885 int +,@p886 int +,@p887 int +,@p888 int +,@p889 int +,@p890 int +,@p891 int +,@p892 int +,@p893 int +,@p894 int +,@p895 int +,@p896 int +,@p897 int +,@p898 int +,@p899 int +,@p900 int +,@p901 int +,@p902 int +,@p903 int +,@p904 int +,@p905 int +,@p906 int +,@p907 int +,@p908 int +,@p909 int +,@p910 int +,@p911 int +,@p912 int +,@p913 int +,@p914 int +,@p915 int +,@p916 int +,@p917 int +,@p918 int +,@p919 int +,@p920 int +,@p921 int +,@p922 int +,@p923 int +,@p924 int +,@p925 int +,@p926 int +,@p927 int +,@p928 int +,@p929 int +,@p930 int +,@p931 int +,@p932 int +,@p933 int +,@p934 int +,@p935 int +,@p936 int +,@p937 int +,@p938 int +,@p939 int +,@p940 int +,@p941 int +,@p942 int +,@p943 int +,@p944 int +,@p945 int +,@p946 int +,@p947 int +,@p948 int +,@p949 int +,@p950 int +,@p951 int +,@p952 int +,@p953 int +,@p954 int +,@p955 int +,@p956 int +,@p957 int +,@p958 int +,@p959 int +,@p960 int +,@p961 int +,@p962 int +,@p963 int +,@p964 int +,@p965 int +,@p966 int +,@p967 int +,@p968 int +,@p969 int +,@p970 int +,@p971 int +,@p972 int +,@p973 int +,@p974 int +,@p975 int +,@p976 int +,@p977 int +,@p978 int +,@p979 int +,@p980 int +,@p981 int +,@p982 int +,@p983 int +,@p984 int +,@p985 int +,@p986 int +,@p987 int +,@p988 int +,@p989 int +,@p990 int +,@p991 int +,@p992 int +,@p993 int +,@p994 int +,@p995 int +,@p996 int +,@p997 int +,@p998 int +,@p999 int +,@p1000 int +,@p1001 int +,@p1002 int +,@p1003 int +,@p1004 int +,@p1005 int +,@p1006 int +,@p1007 int +,@p1008 int +,@p1009 int +,@p1010 int +,@p1011 int +,@p1012 int +,@p1013 int +,@p1014 int +,@p1015 int +,@p1016 int +,@p1017 int +,@p1018 int +,@p1019 int +,@p1020 int +,@p1021 int +,@p1022 int +,@p1023 int +,@p1024 int +,@p1025 int +,@p1026 int +,@p1027 int +,@p1028 int +,@p1029 int +,@p1030 int +,@p1031 int +,@p1032 int +,@p1033 int +,@p1034 int +,@p1035 int +,@p1036 int +,@p1037 int +,@p1038 int +,@p1039 int +,@p1040 int +,@p1041 int +,@p1042 int +,@p1043 int +,@p1044 int +,@p1045 int +,@p1046 int +,@p1047 int +,@p1048 int +,@p1049 int +,@p1050 int +,@p1051 int +,@p1052 int +,@p1053 int +,@p1054 int +,@p1055 int +,@p1056 int +,@p1057 int +,@p1058 int +,@p1059 int +,@p1060 int +,@p1061 int +,@p1062 int +,@p1063 int +,@p1064 int +,@p1065 int +,@p1066 int +,@p1067 int +,@p1068 int +,@p1069 int +,@p1070 int +,@p1071 int +,@p1072 int +,@p1073 int +,@p1074 int +,@p1075 int +,@p1076 int +,@p1077 int +,@p1078 int +,@p1079 int +,@p1080 int +,@p1081 int +,@p1082 int +,@p1083 int +,@p1084 int +,@p1085 int +,@p1086 int +,@p1087 int +,@p1088 int +,@p1089 int +,@p1090 int +,@p1091 int +,@p1092 int +,@p1093 int +,@p1094 int +,@p1095 int +,@p1096 int +,@p1097 int +,@p1098 int +,@p1099 int +,@p1100 int +,@p1101 int +,@p1102 int +,@p1103 int +,@p1104 int +,@p1105 int +,@p1106 int +,@p1107 int +,@p1108 int +,@p1109 int +,@p1110 int +,@p1111 int +,@p1112 int +,@p1113 int +,@p1114 int +,@p1115 int +,@p1116 int +,@p1117 int +,@p1118 int +,@p1119 int +,@p1120 int +,@p1121 int +,@p1122 int +,@p1123 int +,@p1124 int +,@p1125 int +,@p1126 int +,@p1127 int +,@p1128 int +,@p1129 int +,@p1130 int +,@p1131 int +,@p1132 int +,@p1133 int +,@p1134 int +,@p1135 int +,@p1136 int +,@p1137 int +,@p1138 int +,@p1139 int +,@p1140 int +,@p1141 int +,@p1142 int +,@p1143 int +,@p1144 int +,@p1145 int +,@p1146 int +,@p1147 int +,@p1148 int +,@p1149 int +,@p1150 int +,@p1151 int +,@p1152 int +,@p1153 int +,@p1154 int +,@p1155 int +,@p1156 int +,@p1157 int +,@p1158 int +,@p1159 int +,@p1160 int +,@p1161 int +,@p1162 int +,@p1163 int +,@p1164 int +,@p1165 int +,@p1166 int +,@p1167 int +,@p1168 int +,@p1169 int +,@p1170 int +,@p1171 int +,@p1172 int +,@p1173 int +,@p1174 int +,@p1175 int +,@p1176 int +,@p1177 int +,@p1178 int +,@p1179 int +,@p1180 int +,@p1181 int +,@p1182 int +,@p1183 int +,@p1184 int +,@p1185 int +,@p1186 int +,@p1187 int +,@p1188 int +,@p1189 int +,@p1190 int +,@p1191 int +,@p1192 int +,@p1193 int +,@p1194 int +,@p1195 int +,@p1196 int +,@p1197 int +,@p1198 int +,@p1199 int +,@p1200 int +,@p1201 int +,@p1202 int +,@p1203 int +,@p1204 int +,@p1205 int +,@p1206 int +,@p1207 int +,@p1208 int +,@p1209 int +,@p1210 int +,@p1211 int +,@p1212 int +,@p1213 int +,@p1214 int +,@p1215 int +,@p1216 int +,@p1217 int +,@p1218 int +,@p1219 int +,@p1220 int +,@p1221 int +,@p1222 int +,@p1223 int +,@p1224 int +,@p1225 int +,@p1226 int +,@p1227 int +,@p1228 int +,@p1229 int +,@p1230 int +,@p1231 int +,@p1232 int +,@p1233 int +,@p1234 int +,@p1235 int +,@p1236 int +,@p1237 int +,@p1238 int +,@p1239 int +,@p1240 int +,@p1241 int +,@p1242 int +,@p1243 int +,@p1244 int +,@p1245 int +,@p1246 int +,@p1247 int +,@p1248 int +,@p1249 int +,@p1250 int +,@p1251 int +,@p1252 int +,@p1253 int +,@p1254 int +,@p1255 int +,@p1256 int +,@p1257 int +,@p1258 int +,@p1259 int +,@p1260 int +,@p1261 int +,@p1262 int +,@p1263 int +,@p1264 int +,@p1265 int +,@p1266 int +,@p1267 int +,@p1268 int +,@p1269 int +,@p1270 int +,@p1271 int +,@p1272 int +,@p1273 int +,@p1274 int +,@p1275 int +,@p1276 int +,@p1277 int +,@p1278 int +,@p1279 int +,@p1280 int +,@p1281 int +,@p1282 int +,@p1283 int +,@p1284 int +,@p1285 int +,@p1286 int +,@p1287 int +,@p1288 int +,@p1289 int +,@p1290 int +,@p1291 int +,@p1292 int +,@p1293 int +,@p1294 int +,@p1295 int +,@p1296 int +,@p1297 int +,@p1298 int +,@p1299 int +,@p1300 int +,@p1301 int +,@p1302 int +,@p1303 int +,@p1304 int +,@p1305 int +,@p1306 int +,@p1307 int +,@p1308 int +,@p1309 int +,@p1310 int +,@p1311 int +,@p1312 int +,@p1313 int +,@p1314 int +,@p1315 int +,@p1316 int +,@p1317 int +,@p1318 int +,@p1319 int +,@p1320 int +,@p1321 int +,@p1322 int +,@p1323 int +,@p1324 int +,@p1325 int +,@p1326 int +,@p1327 int +,@p1328 int +,@p1329 int +,@p1330 int +,@p1331 int +,@p1332 int +,@p1333 int +,@p1334 int +,@p1335 int +,@p1336 int +,@p1337 int +,@p1338 int +,@p1339 int +,@p1340 int +,@p1341 int +,@p1342 int +,@p1343 int +,@p1344 int +,@p1345 int +,@p1346 int +,@p1347 int +,@p1348 int +,@p1349 int +,@p1350 int +,@p1351 int +,@p1352 int +,@p1353 int +,@p1354 int +,@p1355 int +,@p1356 int +,@p1357 int +,@p1358 int +,@p1359 int +,@p1360 int +,@p1361 int +,@p1362 int +,@p1363 int +,@p1364 int +,@p1365 int +,@p1366 int +,@p1367 int +,@p1368 int +,@p1369 int +,@p1370 int +,@p1371 int +,@p1372 int +,@p1373 int +,@p1374 int +,@p1375 int +,@p1376 int +,@p1377 int +,@p1378 int +,@p1379 int +,@p1380 int +,@p1381 int +,@p1382 int +,@p1383 int +,@p1384 int +,@p1385 int +,@p1386 int +,@p1387 int +,@p1388 int +,@p1389 int +,@p1390 int +,@p1391 int +,@p1392 int +,@p1393 int +,@p1394 int +,@p1395 int +,@p1396 int +,@p1397 int +,@p1398 int +,@p1399 int +,@p1400 int +,@p1401 int +,@p1402 int +,@p1403 int +,@p1404 int +,@p1405 int +,@p1406 int +,@p1407 int +,@p1408 int +,@p1409 int +,@p1410 int +,@p1411 int +,@p1412 int +,@p1413 int +,@p1414 int +,@p1415 int +,@p1416 int +,@p1417 int +,@p1418 int +,@p1419 int +,@p1420 int +,@p1421 int +,@p1422 int +,@p1423 int +,@p1424 int +,@p1425 int +,@p1426 int +,@p1427 int +,@p1428 int +,@p1429 int +,@p1430 int +,@p1431 int +,@p1432 int +,@p1433 int +,@p1434 int +,@p1435 int +,@p1436 int +,@p1437 int +,@p1438 int +,@p1439 int +,@p1440 int +,@p1441 int +,@p1442 int +,@p1443 int +,@p1444 int +,@p1445 int +,@p1446 int +,@p1447 int +,@p1448 int +,@p1449 int +,@p1450 int +,@p1451 int +,@p1452 int +,@p1453 int +,@p1454 int +,@p1455 int +,@p1456 int +,@p1457 int +,@p1458 int +,@p1459 int +,@p1460 int +,@p1461 int +,@p1462 int +,@p1463 int +,@p1464 int +,@p1465 int +,@p1466 int +,@p1467 int +,@p1468 int +,@p1469 int +,@p1470 int +,@p1471 int +,@p1472 int +,@p1473 int +,@p1474 int +,@p1475 int +,@p1476 int +,@p1477 int +,@p1478 int +,@p1479 int +,@p1480 int +,@p1481 int +,@p1482 int +,@p1483 int +,@p1484 int +,@p1485 int +,@p1486 int +,@p1487 int +,@p1488 int +,@p1489 int +,@p1490 int +,@p1491 int +,@p1492 int +,@p1493 int +,@p1494 int +,@p1495 int +,@p1496 int +,@p1497 int +,@p1498 int +,@p1499 int +,@p1500 int +,@p1501 int +,@p1502 int +,@p1503 int +,@p1504 int +,@p1505 int +,@p1506 int +,@p1507 int +,@p1508 int +,@p1509 int +,@p1510 int +,@p1511 int +,@p1512 int +,@p1513 int +,@p1514 int +,@p1515 int +,@p1516 int +,@p1517 int +,@p1518 int +,@p1519 int +,@p1520 int +,@p1521 int +,@p1522 int +,@p1523 int +,@p1524 int +,@p1525 int +,@p1526 int +,@p1527 int +,@p1528 int +,@p1529 int +,@p1530 int +,@p1531 int +,@p1532 int +,@p1533 int +,@p1534 int +,@p1535 int +,@p1536 int +,@p1537 int +,@p1538 int +,@p1539 int +,@p1540 int +,@p1541 int +,@p1542 int +,@p1543 int +,@p1544 int +,@p1545 int +,@p1546 int +,@p1547 int +,@p1548 int +,@p1549 int +,@p1550 int +,@p1551 int +,@p1552 int +,@p1553 int +,@p1554 int +,@p1555 int +,@p1556 int +,@p1557 int +,@p1558 int +,@p1559 int +,@p1560 int +,@p1561 int +,@p1562 int +,@p1563 int +,@p1564 int +,@p1565 int +,@p1566 int +,@p1567 int +,@p1568 int +,@p1569 int +,@p1570 int +,@p1571 int +,@p1572 int +,@p1573 int +,@p1574 int +,@p1575 int +,@p1576 int +,@p1577 int +,@p1578 int +,@p1579 int +,@p1580 int +,@p1581 int +,@p1582 int +,@p1583 int +,@p1584 int +,@p1585 int +,@p1586 int +,@p1587 int +,@p1588 int +,@p1589 int +,@p1590 int +,@p1591 int +,@p1592 int +,@p1593 int +,@p1594 int +,@p1595 int +,@p1596 int +,@p1597 int +,@p1598 int +,@p1599 int +,@p1600 int +,@p1601 int +,@p1602 int +,@p1603 int +,@p1604 int +,@p1605 int +,@p1606 int +,@p1607 int +,@p1608 int +,@p1609 int +,@p1610 int +,@p1611 int +,@p1612 int +,@p1613 int +,@p1614 int +,@p1615 int +,@p1616 int +,@p1617 int +,@p1618 int +,@p1619 int +,@p1620 int +,@p1621 int +,@p1622 int +,@p1623 int +,@p1624 int +,@p1625 int +,@p1626 int +,@p1627 int +,@p1628 int +,@p1629 int +,@p1630 int +,@p1631 int +,@p1632 int +,@p1633 int +,@p1634 int +,@p1635 int +,@p1636 int +,@p1637 int +,@p1638 int +,@p1639 int +,@p1640 int +,@p1641 int +,@p1642 int +,@p1643 int +,@p1644 int +,@p1645 int +,@p1646 int +,@p1647 int +,@p1648 int +,@p1649 int +,@p1650 int +,@p1651 int +,@p1652 int +,@p1653 int +,@p1654 int +,@p1655 int +,@p1656 int +,@p1657 int +,@p1658 int +,@p1659 int +,@p1660 int +,@p1661 int +,@p1662 int +,@p1663 int +,@p1664 int +,@p1665 int +,@p1666 int +,@p1667 int +,@p1668 int +,@p1669 int +,@p1670 int +,@p1671 int +,@p1672 int +,@p1673 int +,@p1674 int +,@p1675 int +,@p1676 int +,@p1677 int +,@p1678 int +,@p1679 int +,@p1680 int +,@p1681 int +,@p1682 int +,@p1683 int +,@p1684 int +,@p1685 int +,@p1686 int +,@p1687 int +,@p1688 int +,@p1689 int +,@p1690 int +,@p1691 int +,@p1692 int +,@p1693 int +,@p1694 int +,@p1695 int +,@p1696 int +,@p1697 int +,@p1698 int +,@p1699 int +,@p1700 int +,@p1701 int +,@p1702 int +,@p1703 int +,@p1704 int +,@p1705 int +,@p1706 int +,@p1707 int +,@p1708 int +,@p1709 int +,@p1710 int +,@p1711 int +,@p1712 int +,@p1713 int +,@p1714 int +,@p1715 int +,@p1716 int +,@p1717 int +,@p1718 int +,@p1719 int +,@p1720 int +,@p1721 int +,@p1722 int +,@p1723 int +,@p1724 int +,@p1725 int +,@p1726 int +,@p1727 int +,@p1728 int +,@p1729 int +,@p1730 int +,@p1731 int +,@p1732 int +,@p1733 int +,@p1734 int +,@p1735 int +,@p1736 int +,@p1737 int +,@p1738 int +,@p1739 int +,@p1740 int +,@p1741 int +,@p1742 int +,@p1743 int +,@p1744 int +,@p1745 int +,@p1746 int +,@p1747 int +,@p1748 int +,@p1749 int +,@p1750 int +,@p1751 int +,@p1752 int +,@p1753 int +,@p1754 int +,@p1755 int +,@p1756 int +,@p1757 int +,@p1758 int +,@p1759 int +,@p1760 int +,@p1761 int +,@p1762 int +,@p1763 int +,@p1764 int +,@p1765 int +,@p1766 int +,@p1767 int +,@p1768 int +,@p1769 int +,@p1770 int +,@p1771 int +,@p1772 int +,@p1773 int +,@p1774 int +,@p1775 int +,@p1776 int +,@p1777 int +,@p1778 int +,@p1779 int +,@p1780 int +,@p1781 int +,@p1782 int +,@p1783 int +,@p1784 int +,@p1785 int +,@p1786 int +,@p1787 int +,@p1788 int +,@p1789 int +,@p1790 int +,@p1791 int +,@p1792 int +,@p1793 int +,@p1794 int +,@p1795 int +,@p1796 int +,@p1797 int +,@p1798 int +,@p1799 int +,@p1800 int +,@p1801 int +,@p1802 int +,@p1803 int +,@p1804 int +,@p1805 int +,@p1806 int +,@p1807 int +,@p1808 int +,@p1809 int +,@p1810 int +,@p1811 int +,@p1812 int +,@p1813 int +,@p1814 int +,@p1815 int +,@p1816 int +,@p1817 int +,@p1818 int +,@p1819 int +,@p1820 int +,@p1821 int +,@p1822 int +,@p1823 int +,@p1824 int +,@p1825 int +,@p1826 int +,@p1827 int +,@p1828 int +,@p1829 int +,@p1830 int +,@p1831 int +,@p1832 int +,@p1833 int +,@p1834 int +,@p1835 int +,@p1836 int +,@p1837 int +,@p1838 int +,@p1839 int +,@p1840 int +,@p1841 int +,@p1842 int +,@p1843 int +,@p1844 int +,@p1845 int +,@p1846 int +,@p1847 int +,@p1848 int +,@p1849 int +,@p1850 int +,@p1851 int +,@p1852 int +,@p1853 int +,@p1854 int +,@p1855 int +,@p1856 int +,@p1857 int +,@p1858 int +,@p1859 int +,@p1860 int +,@p1861 int +,@p1862 int +,@p1863 int +,@p1864 int +,@p1865 int +,@p1866 int +,@p1867 int +,@p1868 int +,@p1869 int +,@p1870 int +,@p1871 int +,@p1872 int +,@p1873 int +,@p1874 int +,@p1875 int +,@p1876 int +,@p1877 int +,@p1878 int +,@p1879 int +,@p1880 int +,@p1881 int +,@p1882 int +,@p1883 int +,@p1884 int +,@p1885 int +,@p1886 int +,@p1887 int +,@p1888 int +,@p1889 int +,@p1890 int +,@p1891 int +,@p1892 int +,@p1893 int +,@p1894 int +,@p1895 int +,@p1896 int +,@p1897 int +,@p1898 int +,@p1899 int +,@p1900 int +,@p1901 int +,@p1902 int +,@p1903 int +,@p1904 int +,@p1905 int +,@p1906 int +,@p1907 int +,@p1908 int +,@p1909 int +,@p1910 int +,@p1911 int +,@p1912 int +,@p1913 int +,@p1914 int +,@p1915 int +,@p1916 int +,@p1917 int +,@p1918 int +,@p1919 int +,@p1920 int +,@p1921 int +,@p1922 int +,@p1923 int +,@p1924 int +,@p1925 int +,@p1926 int +,@p1927 int +,@p1928 int +,@p1929 int +,@p1930 int +,@p1931 int +,@p1932 int +,@p1933 int +,@p1934 int +,@p1935 int +,@p1936 int +,@p1937 int +,@p1938 int +,@p1939 int +,@p1940 int +,@p1941 int +,@p1942 int +,@p1943 int +,@p1944 int +,@p1945 int +,@p1946 int +,@p1947 int +,@p1948 int +,@p1949 int +,@p1950 int +,@p1951 int +,@p1952 int +,@p1953 int +,@p1954 int +,@p1955 int +,@p1956 int +,@p1957 int +,@p1958 int +,@p1959 int +,@p1960 int +,@p1961 int +,@p1962 int +,@p1963 int +,@p1964 int +,@p1965 int +,@p1966 int +,@p1967 int +,@p1968 int +,@p1969 int +,@p1970 int +,@p1971 int +,@p1972 int +,@p1973 int +,@p1974 int +,@p1975 int +,@p1976 int +,@p1977 int +,@p1978 int +,@p1979 int +,@p1980 int +,@p1981 int +,@p1982 int +,@p1983 int +,@p1984 int +,@p1985 int +,@p1986 int +,@p1987 int +,@p1988 int +,@p1989 int +,@p1990 int +,@p1991 int +,@p1992 int +,@p1993 int +,@p1994 int +,@p1995 int +,@p1996 int +,@p1997 int +,@p1998 int +,@p1999 int +,@p2000 int +,@p2001 int +,@p2002 int +,@p2003 int +,@p2004 int +,@p2005 int +,@p2006 int +,@p2007 int +,@p2008 int +,@p2009 int +,@p2010 int +,@p2011 int +,@p2012 int +,@p2013 int +,@p2014 int +,@p2015 int +,@p2016 int +,@p2017 int +,@p2018 int +,@p2019 int +,@p2020 int +,@p2021 int +,@p2022 int +,@p2023 int +,@p2024 int +,@p2025 int +,@p2026 int +,@p2027 int +,@p2028 int +,@p2029 int +,@p2030 int +,@p2031 int +,@p2032 int +,@p2033 int +,@p2034 int +,@p2035 int +,@p2036 int +,@p2037 int +,@p2038 int +,@p2039 int +,@p2040 int +,@p2041 int +,@p2042 int +,@p2043 int +,@p2044 int +,@p2045 int +,@p2046 int +,@p2047 int +,@p2048 int +,@p2049 int +,@p2050 int +,@p2051 int +,@p2052 int +,@p2053 int +,@p2054 int +,@p2055 int +,@p2056 int +,@p2057 int +,@p2058 int +,@p2059 int +,@p2060 int +,@p2061 int +,@p2062 int +,@p2063 int +,@p2064 int +,@p2065 int +,@p2066 int +,@p2067 int +,@p2068 int +,@p2069 int +,@p2070 int +,@p2071 int +,@p2072 int +,@p2073 int +,@p2074 int +,@p2075 int +,@p2076 int +,@p2077 int +,@p2078 int +,@p2079 int +,@p2080 int +,@p2081 int +,@p2082 int +,@p2083 int +,@p2084 int +,@p2085 int +,@p2086 int +,@p2087 int +,@p2088 int +,@p2089 int +,@p2090 int +,@p2091 int +,@p2092 int +,@p2093 int +,@p2094 int +,@p2095 int +,@p2096 int +,@p2097 int +,@p2098 int +,@p2099 int +,@p2100 int +,@p2101 int +) +AS +BEGIN + RETURN 100 +END +GO +~~ERROR (Code: 180)~~ + +~~ERROR (Message: There are too many parameters in this CREATE PROCEDURE statement. The maximum number is 2100.)~~ + + +if @@trancount > 0 select cast('Does not respoect xact_abort flag' as TEXT) else select cast('Respects xact_abort flag' as text); +GO +~~START~~ +text +Does not respoect xact_abort flag +~~END~~ + + +if @@trancount > 0 rollback tran +GO + +SET XACT_ABORT OFF; +GO + diff --git a/contrib/test/JDBC/sql_expected/1946_1.out b/contrib/test/JDBC/sql_expected/1946_1.out new file mode 100644 index 00000000000..fe3da4f7ad2 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/1946_1.out @@ -0,0 +1,598 @@ + +-- simple batch start +CREATE TABLE t1946 +(c1 int IDENTITY +,c2 varchar(500) +,c3 varchar(500) +,c4 varchar(500) +,c5 varchar(500) +,c6 varchar(500) +,c7 varchar(500) +) +GO + +CREATE INDEX ix1946 ON t1946(c1, c2, c3, c4, c5, c6, c7) +GO + + + + +INSERT INTO t1946(c2, c3, c4, c5, c6, c7) +VALUES( + REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +) +GO +~~ERROR (Code: 1946)~~ + +~~ERROR (Message: Operation failed. The index entry of length 3004 bytes for the index 'ix1946' exceeds the maximum length of 900 bytes.)~~ + +DROP TABLE t1946 +GO + +begin transaction +GO +CREATE TABLE t1946 +(c1 int IDENTITY +,c2 varchar(500) +,c3 varchar(500) +,c4 varchar(500) +,c5 varchar(500) +,c6 varchar(500) +,c7 varchar(500) +) +GO + +CREATE INDEX ix1946 ON t1946(c1, c2, c3, c4, c5, c6, c7) +GO + + + + +INSERT INTO t1946(c2, c3, c4, c5, c6, c7) +VALUES( + REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +) +GO +~~ERROR (Code: 1946)~~ + +~~ERROR (Message: Operation failed. The index entry of length 3004 bytes for the index 'ix1946' exceeds the maximum length of 900 bytes.)~~ + + + +-- Below output is only applicable if query is special case. for example, CREATE/ALTER TRIGGER, CREATE/ALTER FUNCTION, CREATE/ALTER PROC, CREATE/ALTER VIEW etc +if (@@trancount > 0) select cast('compile time error' as text) else select cast('runtime error' as text) +GO +~~START~~ +text +runtime error +~~END~~ + + +if (@@trancount > 0) rollback tran +GO + +DROP TABLE t1946 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the table 't1946', because it does not exist or you do not have permission.)~~ + + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + +CREATE TABLE t1946 +(c1 int IDENTITY +,c2 varchar(500) +,c3 varchar(500) +,c4 varchar(500) +,c5 varchar(500) +,c6 varchar(500) +,c7 varchar(500) +) +GO + +CREATE INDEX ix1946 ON t1946(c1, c2, c3, c4, c5, c6, c7) +GO + + + + +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +INSERT INTO t1946(c2, c3, c4, c5, c6, c7) +VALUES( + REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +) +end +GO + +DROP TABLE t1946 +GO + +create table error_mapping.temp2 (a int) +GO + +CREATE TABLE t1946 +(c1 int IDENTITY +,c2 varchar(500) +,c3 varchar(500) +,c4 varchar(500) +,c5 varchar(500) +,c6 varchar(500) +,c7 varchar(500) +) +GO + +CREATE INDEX ix1946 ON t1946(c1, c2, c3, c4, c5, c6, c7) +GO + + + + +insert into error_mapping.temp2 values(1) +INSERT INTO t1946(c2, c3, c4, c5, c6, c7) +VALUES( + REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +) +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 1946)~~ + +~~ERROR (Message: Operation failed. The index entry of length 3004 bytes for the index 'ix1946' exceeds the maximum length of 900 bytes.)~~ + + +DROP TABLE t1946 +GO + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + +CREATE TABLE t1946 +(c1 int IDENTITY +,c2 varchar(500) +,c3 varchar(500) +,c4 varchar(500) +,c5 varchar(500) +,c6 varchar(500) +,c7 varchar(500) +) +GO + +CREATE INDEX ix1946 ON t1946(c1, c2, c3, c4, c5, c6, c7) +GO +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 1946)~~ + +~~ERROR (Message: Operation failed. The index entry of length 3004 bytes for the index 'ix1946' exceeds the maximum length of 900 bytes.)~~ + + +DROP TABLE t1946 +GO + +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 + +-- Parse analysis phase end +GO + + +-- compile time error portion +-- Executing test error_mapping.ErrorHandling1 +CREATE TABLE t1946 +(c1 int IDENTITY +,c2 varchar(500) +,c3 varchar(500) +,c4 varchar(500) +,c5 varchar(500) +,c6 varchar(500) +,c7 varchar(500) +) +GO + +CREATE INDEX ix1946 ON t1946(c1, c2, c3, c4, c5, c6, c7) +GO + + + + + + +create procedure error_mapping.ErrorHandling1 as +begin +INSERT INTO t1946(c2, c3, c4, c5, c6, c7) +VALUES( + REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +) +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 +DROP TABLE t1946 +GO + + +CREATE TABLE t1946 +(c1 int IDENTITY +,c2 varchar(500) +,c3 varchar(500) +,c4 varchar(500) +,c5 varchar(500) +,c6 varchar(500) +,c7 varchar(500) +) +GO + +CREATE INDEX ix1946 ON t1946(c1, c2, c3, c4, c5, c6, c7) +GO +begin transaction +GO + + + + + +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +INSERT INTO t1946(c2, c3, c4, c5, c6, c7) +VALUES( + REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +) +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: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +DROP TABLE t1946 +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE t1946 +(c1 int IDENTITY +,c2 varchar(500) +,c3 varchar(500) +,c4 varchar(500) +,c5 varchar(500) +,c6 varchar(500) +,c7 varchar(500) +) +GO + +CREATE INDEX ix1946 ON t1946(c1, c2, c3, c4, c5, c6, c7) +GO +begin transaction +GO + + + + + +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +INSERT INTO t1946(c2, c3, c4, c5, c6, c7) +VALUES( + REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +) +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: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +DROP TABLE t1946 +GO +set xact_abort OFF; +GO + + +-- comiple time error portion end -- +-- Next portion is for runtime error -- +-- Executing test error_mapping.ErrorHandling10000000 +CREATE TABLE t1946 +(c1 int IDENTITY +,c2 varchar(500) +,c3 varchar(500) +,c4 varchar(500) +,c5 varchar(500) +,c6 varchar(500) +,c7 varchar(500) +) +GO + +CREATE INDEX ix1946 ON t1946(c1, c2, c3, c4, c5, c6, c7) +GO + + + + + + +create procedure error_mapping.ErrorHandling1 as +begin +INSERT INTO t1946(c2, c3, c4, c5, c6, c7) +VALUES( + REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +) +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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: 1946)~~ + +~~ERROR (Message: Operation failed. The index entry of length 3004 bytes for the index 'ix1946' exceeds the maximum length of 900 bytes.)~~ + +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 +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +DROP TABLE t1946 +GO + + +set xact_abort ON; +GO +-- Executing test error_mapping.ErrorHandling10000000 +CREATE TABLE t1946 +(c1 int IDENTITY +,c2 varchar(500) +,c3 varchar(500) +,c4 varchar(500) +,c5 varchar(500) +,c6 varchar(500) +,c7 varchar(500) +) +GO + +CREATE INDEX ix1946 ON t1946(c1, c2, c3, c4, c5, c6, c7) +GO + + + + + + +create procedure error_mapping.ErrorHandling1 as +begin +INSERT INTO t1946(c2, c3, c4, c5, c6, c7) +VALUES( + REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +) +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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: 1946)~~ + +~~ERROR (Message: Operation failed. The index entry of length 3004 bytes for the index 'ix1946' exceeds the maximum length of 900 bytes.)~~ + +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 +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +DROP TABLE t1946 +GO + + + +set xact_abort OFF; +GO + + +-- Error classification is done -- +-- Executing test error_mapping.ErrorHandling10000000 +CREATE TABLE t1946 +(c1 int IDENTITY +,c2 varchar(500) +,c3 varchar(500) +,c4 varchar(500) +,c5 varchar(500) +,c6 varchar(500) +,c7 varchar(500) +) +GO + +CREATE INDEX ix1946 ON t1946(c1, c2, c3, c4, c5, c6, c7) +GO + + + + + + +begin try +select 1 +INSERT INTO t1946(c2, c3, c4, c5, c6, c7) +VALUES( + REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +,REPLICATE('a', 500) +) +end try +begin catch + select xact_state(); +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 +~~START~~ +int +1 +~~END~~ + +~~START~~ +smallint +0 +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling2', because it does not exist or you do not have permission.)~~ + +DROP TABLE t1946 +GO + + + +GO +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/sql_expected/217_1.out b/contrib/test/JDBC/sql_expected/217_1.out new file mode 100644 index 00000000000..632fee0c246 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/217_1.out @@ -0,0 +1,329 @@ +# Executing test ErrorHandling1 + + +--217 NESTLEVEL exceeded +--Bbf has the incorrect max nestlevel. Should be 32, but it is 1040. +--Known, as BABEL-610 +--------------------------------------------------------------------------- +--Pre +CREATE PROC p217 AS +PRINT @@NESTLEVEL +--IF @@NESTLEVEL = 33 +--BEGIN +-- RETURN +--END +EXEC p217; +GO + + +create procedure ErrorHandling1 as +begin +--------------------------------------------------------------------------- +--Generate the error +EXEC p217; +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--------------------------------------------------------------------------- +--Post +DROP PROC p217 +GO + + + + +--217 NESTLEVEL exceeded +--Bbf has the incorrect max nestlevel. Should be 32, but it is 1040. +--Known, as BABEL-610 +--------------------------------------------------------------------------- +--Pre +CREATE PROC p217 AS +PRINT @@NESTLEVEL +--IF @@NESTLEVEL = 33 +--BEGIN +-- RETURN +--END +EXEC p217; +GO +begin transaction +GO +# Executing test ErrorHandling1 + +create procedure ErrorHandling1 as +begin +--------------------------------------------------------------------------- +--Generate the error +EXEC p217; +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +--------------------------------------------------------------------------- +--Post +DROP PROC p217 +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO + + +--217 NESTLEVEL exceeded +--Bbf has the incorrect max nestlevel. Should be 32, but it is 1040. +--Known, as BABEL-610 +--------------------------------------------------------------------------- +--Pre +CREATE PROC p217 AS +PRINT @@NESTLEVEL +--IF @@NESTLEVEL = 33 +--BEGIN +-- RETURN +--END +EXEC p217; +GO +begin transaction +GO +# Executing test ErrorHandling1 + +create procedure ErrorHandling1 as +begin +--------------------------------------------------------------------------- +--Generate the error +EXEC p217; +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +--------------------------------------------------------------------------- +--Post +DROP PROC p217 +GO +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 + + +-- Next portion is for runtime error -- +--217 NESTLEVEL exceeded +--Bbf has the incorrect max nestlevel. Should be 32, but it is 1040. +--Known, as BABEL-610 +--------------------------------------------------------------------------- +--Pre +CREATE PROC p217 AS +PRINT @@NESTLEVEL +--IF @@NESTLEVEL = 33 +--BEGIN +-- RETURN +--END +EXEC p217; +GO + + +create procedure ErrorHandling1 as +begin +--------------------------------------------------------------------------- +--Generate the error +EXEC p217; +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 217)~~ + +~~ERROR (Message: Maximum stored procedure, function, trigger, or view nesting level exceeded (limit 32).)~~ + +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +--------------------------------------------------------------------------- +--Post +DROP PROC p217 +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 + + +--217 NESTLEVEL exceeded +--Bbf has the incorrect max nestlevel. Should be 32, but it is 1040. +--Known, as BABEL-610 +--------------------------------------------------------------------------- +--Pre +CREATE PROC p217 AS +PRINT @@NESTLEVEL +--IF @@NESTLEVEL = 33 +--BEGIN +-- RETURN +--END +EXEC p217; +GO + + +create procedure ErrorHandling1 as +begin +--------------------------------------------------------------------------- +--Generate the error +EXEC p217; +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 217)~~ + +~~ERROR (Message: Maximum stored procedure, function, trigger, or view nesting level exceeded (limit 32).)~~ + +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +--------------------------------------------------------------------------- +--Post +DROP PROC p217 +GO + + + +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 + + +-- Error classification is done -- +--217 NESTLEVEL exceeded +--Bbf has the incorrect max nestlevel. Should be 32, but it is 1040. +--Known, as BABEL-610 +--------------------------------------------------------------------------- +--Pre +CREATE PROC p217 AS +PRINT @@NESTLEVEL +--IF @@NESTLEVEL = 33 +--BEGIN +-- RETURN +--END +EXEC p217; +GO + + +begin try +select 1 +--------------------------------------------------------------------------- +--Generate the error +EXEC p217; +end try +begin catch + select xact_state(); +end catch +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +int +1 +~~END~~ + +~~START~~ +smallint +0 +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling2', because it does not exist or you do not have permission.)~~ + +--------------------------------------------------------------------------- +--Post +DROP PROC p217 +GO + + diff --git a/contrib/test/JDBC/sql_expected/219_1.out b/contrib/test/JDBC/sql_expected/219_1.out new file mode 100644 index 00000000000..16ffcb4a894 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/219_1.out @@ -0,0 +1,227 @@ +# Executing test ErrorHandling1 +CREATE TYPE type_218 from INT +GO + + +create procedure ErrorHandling1 as +begin +CREATE TYPE type_218 from INT +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TYPE type_218 +GO + + +CREATE TYPE type_218 from INT +GO +begin transaction +GO +# Executing test ErrorHandling1 + +create procedure ErrorHandling1 as +begin +CREATE TYPE type_218 from INT +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +DROP TYPE type_218 +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TYPE type_218 from INT +GO +begin transaction +GO +# Executing test ErrorHandling1 + +create procedure ErrorHandling1 as +begin +CREATE TYPE type_218 from INT +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +DROP TYPE type_218 +GO +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Next portion is for runtime error -- +CREATE TYPE type_218 from INT +GO + + +create procedure ErrorHandling1 as +begin +CREATE TYPE type_218 from INT +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 219)~~ + +~~ERROR (Message: The type 'type_218' already exists, or you do not have permission to create it.)~~ + +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +DROP TYPE type_218 +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +CREATE TYPE type_218 from INT +GO + + +create procedure ErrorHandling1 as +begin +CREATE TYPE type_218 from INT +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 219)~~ + +~~ERROR (Message: The type 'type_218' already exists, or you do not have permission to create it.)~~ + +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +DROP TYPE type_218 +GO + + + +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Error classification is done -- +CREATE TYPE type_218 from INT +GO + + +begin try +select 1 +CREATE TYPE type_218 from INT +end try +begin catch + select xact_state(); +end catch +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +int +1 +~~END~~ + +~~START~~ +smallint +0 +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling2', because it does not exist or you do not have permission.)~~ + +DROP TYPE type_218 +GO + + diff --git a/contrib/test/JDBC/sql_expected/220_1.out b/contrib/test/JDBC/sql_expected/220_1.out new file mode 100644 index 00000000000..eaaa90133b1 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/220_1.out @@ -0,0 +1,268 @@ +# Executing test ErrorHandling1 +--Pre +CREATE TABLE t220_1(c1 tinyint); +CREATE TABLE t220_2(c1 smallint); +GO + + +create procedure ErrorHandling1 as +begin +--Generate the error +DECLARE @a tinyint = 1000; +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +DROP TABLE t220_1 +GO +DROP TABLE t220_2 +GO + + +--Pre +CREATE TABLE t220_1(c1 tinyint); +CREATE TABLE t220_2(c1 smallint); +GO +begin transaction +GO +# Executing test ErrorHandling1 + +create procedure ErrorHandling1 as +begin +--Generate the error +DECLARE @a tinyint = 1000; +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +--Post +DROP TABLE t220_1 +GO +DROP TABLE t220_2 +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +--Pre +CREATE TABLE t220_1(c1 tinyint); +CREATE TABLE t220_2(c1 smallint); +GO +begin transaction +GO +# Executing test ErrorHandling1 + +create procedure ErrorHandling1 as +begin +--Generate the error +DECLARE @a tinyint = 1000; +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +--Post +DROP TABLE t220_1 +GO +DROP TABLE t220_2 +GO +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Next portion is for runtime error -- +--Pre +CREATE TABLE t220_1(c1 tinyint); +CREATE TABLE t220_2(c1 smallint); +GO + + +create procedure ErrorHandling1 as +begin +--Generate the error +DECLARE @a tinyint = 1000; +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 220)~~ + +~~ERROR (Message: Arithmetic overflow error for data type tinyint, value = 1000.)~~ + +~~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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +DROP TABLE t220_1 +GO +DROP TABLE t220_2 +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +--Pre +CREATE TABLE t220_1(c1 tinyint); +CREATE TABLE t220_2(c1 smallint); +GO + + +create procedure ErrorHandling1 as +begin +--Generate the error +DECLARE @a tinyint = 1000; +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 220)~~ + +~~ERROR (Message: Arithmetic overflow error for data type tinyint, value = 1000.)~~ + +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +--Post +DROP TABLE t220_1 +GO +DROP TABLE t220_2 +GO + + + +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Error classification is done -- +--Pre +CREATE TABLE t220_1(c1 tinyint); +CREATE TABLE t220_2(c1 smallint); +GO + + +begin try +select 1 +--Generate the error +DECLARE @a tinyint = 1000; +end try +begin catch + select xact_state(); +end catch +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +int +1 +~~END~~ + +~~START~~ +smallint +0 +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling2', because it does not exist or you do not have permission.)~~ + +--Post +DROP TABLE t220_1 +GO +DROP TABLE t220_2 +GO + + diff --git a/contrib/test/JDBC/sql_expected/220_2.out b/contrib/test/JDBC/sql_expected/220_2.out new file mode 100644 index 00000000000..4009a6ce944 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/220_2.out @@ -0,0 +1,262 @@ +# Executing test ErrorHandling1 +--Pre +CREATE TABLE t220_1(c1 tinyint); +CREATE TABLE t220_2(c1 smallint); +GO + + +create procedure ErrorHandling1 as +begin +DECLARE @a smallint = 45000; +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +DROP TABLE t220_1 +GO +DROP TABLE t220_2 +GO + + +--Pre +CREATE TABLE t220_1(c1 tinyint); +CREATE TABLE t220_2(c1 smallint); +GO +begin transaction +GO +# Executing test ErrorHandling1 + +create procedure ErrorHandling1 as +begin +DECLARE @a smallint = 45000; +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +--Post +DROP TABLE t220_1 +GO +DROP TABLE t220_2 +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +--Pre +CREATE TABLE t220_1(c1 tinyint); +CREATE TABLE t220_2(c1 smallint); +GO +begin transaction +GO +# Executing test ErrorHandling1 + +create procedure ErrorHandling1 as +begin +DECLARE @a smallint = 45000; +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +--Post +DROP TABLE t220_1 +GO +DROP TABLE t220_2 +GO +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Next portion is for runtime error -- +--Pre +CREATE TABLE t220_1(c1 tinyint); +CREATE TABLE t220_2(c1 smallint); +GO + + +create procedure ErrorHandling1 as +begin +DECLARE @a smallint = 45000; +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 220)~~ + +~~ERROR (Message: Arithmetic overflow error for data type smallint, value = 45000.)~~ + +~~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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +DROP TABLE t220_1 +GO +DROP TABLE t220_2 +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +--Pre +CREATE TABLE t220_1(c1 tinyint); +CREATE TABLE t220_2(c1 smallint); +GO + + +create procedure ErrorHandling1 as +begin +DECLARE @a smallint = 45000; +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 220)~~ + +~~ERROR (Message: Arithmetic overflow error for data type smallint, value = 45000.)~~ + +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +--Post +DROP TABLE t220_1 +GO +DROP TABLE t220_2 +GO + + + +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Error classification is done -- +--Pre +CREATE TABLE t220_1(c1 tinyint); +CREATE TABLE t220_2(c1 smallint); +GO + + +begin try +select 1 +DECLARE @a smallint = 45000; +end try +begin catch + select xact_state(); +end catch +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +int +1 +~~END~~ + +~~START~~ +smallint +0 +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling2', because it does not exist or you do not have permission.)~~ + +--Post +DROP TABLE t220_1 +GO +DROP TABLE t220_2 +GO + + diff --git a/contrib/test/JDBC/sql_expected/220_3.out b/contrib/test/JDBC/sql_expected/220_3.out new file mode 100644 index 00000000000..6619721852d --- /dev/null +++ b/contrib/test/JDBC/sql_expected/220_3.out @@ -0,0 +1,262 @@ +# Executing test ErrorHandling1 +--Pre +CREATE TABLE t220_1(c1 tinyint); +CREATE TABLE t220_2(c1 smallint); +GO + + +create procedure ErrorHandling1 as +begin +INSERT INTO t220_1(c1) VALUES(1000); +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +DROP TABLE t220_1 +GO +DROP TABLE t220_2 +GO + + +--Pre +CREATE TABLE t220_1(c1 tinyint); +CREATE TABLE t220_2(c1 smallint); +GO +begin transaction +GO +# Executing test ErrorHandling1 + +create procedure ErrorHandling1 as +begin +INSERT INTO t220_1(c1) VALUES(1000); +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +--Post +DROP TABLE t220_1 +GO +DROP TABLE t220_2 +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +--Pre +CREATE TABLE t220_1(c1 tinyint); +CREATE TABLE t220_2(c1 smallint); +GO +begin transaction +GO +# Executing test ErrorHandling1 + +create procedure ErrorHandling1 as +begin +INSERT INTO t220_1(c1) VALUES(1000); +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +--Post +DROP TABLE t220_1 +GO +DROP TABLE t220_2 +GO +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Next portion is for runtime error -- +--Pre +CREATE TABLE t220_1(c1 tinyint); +CREATE TABLE t220_2(c1 smallint); +GO + + +create procedure ErrorHandling1 as +begin +INSERT INTO t220_1(c1) VALUES(1000); +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 220)~~ + +~~ERROR (Message: Arithmetic overflow error for data type tinyint, value = 1000.)~~ + +~~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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +DROP TABLE t220_1 +GO +DROP TABLE t220_2 +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +--Pre +CREATE TABLE t220_1(c1 tinyint); +CREATE TABLE t220_2(c1 smallint); +GO + + +create procedure ErrorHandling1 as +begin +INSERT INTO t220_1(c1) VALUES(1000); +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 220)~~ + +~~ERROR (Message: Arithmetic overflow error for data type tinyint, value = 1000.)~~ + +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +--Post +DROP TABLE t220_1 +GO +DROP TABLE t220_2 +GO + + + +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Error classification is done -- +--Pre +CREATE TABLE t220_1(c1 tinyint); +CREATE TABLE t220_2(c1 smallint); +GO + + +begin try +select 1 +INSERT INTO t220_1(c1) VALUES(1000); +end try +begin catch + select xact_state(); +end catch +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +int +1 +~~END~~ + +~~START~~ +smallint +0 +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling2', because it does not exist or you do not have permission.)~~ + +--Post +DROP TABLE t220_1 +GO +DROP TABLE t220_2 +GO + + diff --git a/contrib/test/JDBC/sql_expected/220_4.out b/contrib/test/JDBC/sql_expected/220_4.out new file mode 100644 index 00000000000..8182368d663 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/220_4.out @@ -0,0 +1,262 @@ +# Executing test ErrorHandling1 +--Pre +CREATE TABLE t220_1(c1 tinyint); +CREATE TABLE t220_2(c1 smallint); +GO + + +create procedure ErrorHandling1 as +begin +INSERT INTO t220_2(c1) VALUES(45000); +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +DROP TABLE t220_1 +GO +DROP TABLE t220_2 +GO + + +--Pre +CREATE TABLE t220_1(c1 tinyint); +CREATE TABLE t220_2(c1 smallint); +GO +begin transaction +GO +# Executing test ErrorHandling1 + +create procedure ErrorHandling1 as +begin +INSERT INTO t220_2(c1) VALUES(45000); +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +--Post +DROP TABLE t220_1 +GO +DROP TABLE t220_2 +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +--Pre +CREATE TABLE t220_1(c1 tinyint); +CREATE TABLE t220_2(c1 smallint); +GO +begin transaction +GO +# Executing test ErrorHandling1 + +create procedure ErrorHandling1 as +begin +INSERT INTO t220_2(c1) VALUES(45000); +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +--Post +DROP TABLE t220_1 +GO +DROP TABLE t220_2 +GO +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Next portion is for runtime error -- +--Pre +CREATE TABLE t220_1(c1 tinyint); +CREATE TABLE t220_2(c1 smallint); +GO + + +create procedure ErrorHandling1 as +begin +INSERT INTO t220_2(c1) VALUES(45000); +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 220)~~ + +~~ERROR (Message: Arithmetic overflow error for data type smallint, value = 45000.)~~ + +~~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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +DROP TABLE t220_1 +GO +DROP TABLE t220_2 +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +--Pre +CREATE TABLE t220_1(c1 tinyint); +CREATE TABLE t220_2(c1 smallint); +GO + + +create procedure ErrorHandling1 as +begin +INSERT INTO t220_2(c1) VALUES(45000); +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 220)~~ + +~~ERROR (Message: Arithmetic overflow error for data type smallint, value = 45000.)~~ + +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +--Post +DROP TABLE t220_1 +GO +DROP TABLE t220_2 +GO + + + +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Error classification is done -- +--Pre +CREATE TABLE t220_1(c1 tinyint); +CREATE TABLE t220_2(c1 smallint); +GO + + +begin try +select 1 +INSERT INTO t220_2(c1) VALUES(45000); +end try +begin catch + select xact_state(); +end catch +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +int +1 +~~END~~ + +~~START~~ +smallint +0 +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling2', because it does not exist or you do not have permission.)~~ + +--Post +DROP TABLE t220_1 +GO +DROP TABLE t220_2 +GO + + diff --git a/contrib/test/JDBC/sql_expected/2732_1.out b/contrib/test/JDBC/sql_expected/2732_1.out new file mode 100644 index 00000000000..2a58222a5dd --- /dev/null +++ b/contrib/test/JDBC/sql_expected/2732_1.out @@ -0,0 +1,358 @@ + +-- simple batch start +GO + +RAISERROR(5005, 10, 1, N'ErrorMessage') +GO +~~ERROR (Code: 2732)~~ + +~~ERROR (Message: Error number 5005 is invalid. The number must be from 13000 through 2147483647 and it cannot be 50000.)~~ + +GO + + +begin transaction +GO +GO + +RAISERROR(5005, 10, 1, N'ErrorMessage') +GO +~~ERROR (Code: 2732)~~ + +~~ERROR (Message: Error number 5005 is invalid. The number must be from 13000 through 2147483647 and it cannot be 50000.)~~ + + + +-- Below output is only applicable if query is special case. for example, CREATE/ALTER TRIGGER, CREATE/ALTER FUNCTION, CREATE/ALTER PROC, CREATE/ALTER VIEW etc +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 + +GO + + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + +GO + +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +RAISERROR(5005, 10, 1, N'ErrorMessage') +end +GO + +GO + + +create table error_mapping.temp2 (a int) +GO + +GO + +insert into error_mapping.temp2 values(1) +RAISERROR(5005, 10, 1, N'ErrorMessage') +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2732)~~ + +~~ERROR (Message: Error number 5005 is invalid. The number must be from 13000 through 2147483647 and it cannot be 50000.)~~ + + +GO + + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + +GO + +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2732)~~ + +~~ERROR (Message: Error number 5005 is invalid. The number must be from 13000 through 2147483647 and it cannot be 50000.)~~ + + +GO + + +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 + +-- Parse analysis phase end +GO + + +-- compile time error portion +-- Executing test error_mapping.ErrorHandling1 +GO + + + +create procedure error_mapping.ErrorHandling1 as +begin +RAISERROR(5005, 10, 1, N'ErrorMessage') +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 +GO + + + +GO + +begin transaction +GO + +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +RAISERROR(5005, 10, 1, N'ErrorMessage') +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: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +GO + + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +GO + +begin transaction +GO + +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +RAISERROR(5005, 10, 1, N'ErrorMessage') +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: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +GO + +set xact_abort OFF; +GO + + +-- comiple time error portion end -- +-- Next portion is for runtime error -- +-- Executing test error_mapping.ErrorHandling10000000 +GO + + + +create procedure error_mapping.ErrorHandling1 as +begin +RAISERROR(5005, 10, 1, N'ErrorMessage') +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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: 2732)~~ + +~~ERROR (Message: Error number 5005 is invalid. The number must be from 13000 through 2147483647 and it cannot be 50000.)~~ + +~~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 +GO + + + +set xact_abort ON; +GO +-- Executing test error_mapping.ErrorHandling10000000 +GO + + + +create procedure error_mapping.ErrorHandling1 as +begin +RAISERROR(5005, 10, 1, N'ErrorMessage') +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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: 2732)~~ + +~~ERROR (Message: Error number 5005 is invalid. The number must be from 13000 through 2147483647 and it cannot be 50000.)~~ + +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 +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +GO + + + + +set xact_abort OFF; +GO + + +-- Error classification is done -- +-- Executing test error_mapping.ErrorHandling10000000 +GO + + + +begin try +select 1 +RAISERROR(5005, 10, 1, N'ErrorMessage') +end try +begin catch + select xact_state(); +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 +~~START~~ +int +1 +~~END~~ + +~~START~~ +smallint +0 +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling2', because it does not exist or you do not have permission.)~~ + +GO + + + + +GO +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/sql_expected/2747_1.out b/contrib/test/JDBC/sql_expected/2747_1.out new file mode 100644 index 00000000000..a1bbc698d86 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/2747_1.out @@ -0,0 +1,379 @@ + +-- simple batch start +GO + +RAISERROR('%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d' +,1, +1, +3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3) +GO +~~ERROR (Code: 2747)~~ + +~~ERROR (Message: Too many substitution parameters for RAISERROR. Cannot exceed 20 substitution parameters.)~~ + +GO + +begin transaction +GO +GO + +RAISERROR('%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d' +,1, +1, +3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3) +GO +~~ERROR (Code: 2747)~~ + +~~ERROR (Message: Too many substitution parameters for RAISERROR. Cannot exceed 20 substitution parameters.)~~ + + + +-- Below output is only applicable if query is special case. for example, CREATE/ALTER TRIGGER, CREATE/ALTER FUNCTION, CREATE/ALTER PROC, CREATE/ALTER VIEW etc +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 + +GO + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + +GO + +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +RAISERROR('%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d' +,1, +1, +3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3) +end +GO +~~ERROR (Code: 2747)~~ + +~~ERROR (Message: Too many substitution parameters for RAISERROR. Cannot exceed 20 substitution parameters.)~~ + + +GO + +create table error_mapping.temp2 (a int) +GO + +GO + +insert into error_mapping.temp2 values(1) +RAISERROR('%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d' +,1, +1, +3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3) +GO +~~ERROR (Code: 2747)~~ + +~~ERROR (Message: Too many substitution parameters for RAISERROR. Cannot exceed 20 substitution parameters.)~~ + + +GO + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + +GO +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2812)~~ + +~~ERROR (Message: Could not find stored procedure 'error_mapping.ErrorHandling1'.)~~ + + +GO + +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 +~~START~~ +text +parse analysis phase error +~~END~~ + + +drop procedure error_mapping.ErrorHandling1; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + +drop table error_mapping.temp1; +drop table error_mapping.temp2; +drop table error_mapping.temp3; +GO + +-- Parse analysis phase end +GO + + +-- compile time error portion +-- Executing test error_mapping.ErrorHandling1 +GO + + + +create procedure error_mapping.ErrorHandling1 as +begin +RAISERROR('%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d' +,1, +1, +3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3) +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO +~~ERROR (Code: 2747)~~ + +~~ERROR (Message: Too many substitution parameters for RAISERROR. Cannot exceed 20 substitution parameters.)~~ + + +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 +~~START~~ +text +Compile time error +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + +GO + + +GO +begin transaction +GO + + +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +RAISERROR('%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d' +,1, +1, +3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3) +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +end +GO +~~ERROR (Code: 2747)~~ + +~~ERROR (Message: Too many substitution parameters for RAISERROR. Cannot exceed 20 substitution parameters.)~~ + + +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 +~~START~~ +text +BATCH ONLY TERMINATING +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +GO +begin transaction +GO + + +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +RAISERROR('%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d' +,1, +1, +3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3) +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +end +GO +~~ERROR (Code: 2747)~~ + +~~ERROR (Message: Too many substitution parameters for RAISERROR. Cannot exceed 20 substitution parameters.)~~ + + +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 +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +GO +set xact_abort OFF; +GO + + + +-- comiple time error portion end -- +-- Next portion is for runtime error -- +-- Executing test error_mapping.ErrorHandling10000000 +--GO +-- +--create procedure error_mapping.ErrorHandling1 as +--begin +--RAISERROR('%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d' +--,1, +--1, +--3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3) +-- +--if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +--select @@trancount; +--end +-- +--GO +-- +--if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +--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 +--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 +--GO +-- +-- +--set xact_abort ON; +--GO +---- Executing test error_mapping.ErrorHandling10000000 +--GO +-- +--create procedure error_mapping.ErrorHandling1 as +--begin +--RAISERROR('%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d' +--,1, +--1, +--3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3) +-- +--if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +--select @@trancount; +--end +-- +--GO +-- +--if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +--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 +--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 +--GO +-- +-- +-- +--set xact_abort OFF; +--GO +-- +-- Error classification is done -- +-- Executing test error_mapping.ErrorHandling10000000 +GO + + + +begin try +select 1 +RAISERROR('%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d' +,1, +1, +3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3) +end try +begin catch + select xact_state(); +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 +--GO +-- +-- +-- +GO +~~ERROR (Code: 2747)~~ + +~~ERROR (Message: Too many substitution parameters for RAISERROR. Cannot exceed 20 substitution parameters.)~~ + +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/sql_expected/2787_1.out b/contrib/test/JDBC/sql_expected/2787_1.out new file mode 100644 index 00000000000..453a6a1691f --- /dev/null +++ b/contrib/test/JDBC/sql_expected/2787_1.out @@ -0,0 +1,363 @@ + + +-- simple batch start +GO +RAISERROR('Hello %q', 16, 1, 'as') +GO +~~ERROR (Code: 2787)~~ + +~~ERROR (Message: Invalid format specification: '%q'.)~~ + + +GO + +begin transaction +GO + +GO +RAISERROR('Hello %q', 16, 1, 'as') +GO +~~ERROR (Code: 2787)~~ + +~~ERROR (Message: Invalid format specification: '%q'.)~~ + + + +-- Below output is only applicable if query is special case. for example, CREATE/ALTER TRIGGER, CREATE/ALTER FUNCTION, CREATE/ALTER PROC, CREATE/ALTER VIEW etc +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 + + +GO + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + + +GO +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +RAISERROR('Hello %q', 16, 1, 'as') +end +GO + + +GO + +create table error_mapping.temp2 (a int) +GO + + +GO +insert into error_mapping.temp2 values(1) +RAISERROR('Hello %q', 16, 1, 'as') +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2787)~~ + +~~ERROR (Message: Invalid format specification: '%q'.)~~ + + + +GO + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + + +GO +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2787)~~ + +~~ERROR (Message: Invalid format specification: '%q'.)~~ + + + +GO + +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 + +-- Parse analysis phase end +GO + + + +-- compile time error portion +-- Executing test error_mapping.ErrorHandling1 +GO + + +create procedure error_mapping.ErrorHandling1 as +begin +RAISERROR('Hello %q', 16, 1, 'as') +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 + +GO + + + +GO +begin transaction +GO + +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +RAISERROR('Hello %q', 16, 1, 'as') +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: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO + +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO + +GO +begin transaction +GO + +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +RAISERROR('Hello %q', 16, 1, 'as') +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: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO + +GO +set xact_abort OFF; +GO + + + +-- comiple time error portion end -- +-- Next portion is for runtime error -- +-- Executing test error_mapping.ErrorHandling10000000 +GO + + +create procedure error_mapping.ErrorHandling1 as +begin +RAISERROR('Hello %q', 16, 1, 'as') +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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: 2787)~~ + +~~ERROR (Message: Invalid format specification: '%q'.)~~ + +~~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 + +GO + + +set xact_abort ON; +GO + +-- Executing test error_mapping.ErrorHandling10000000 +GO + + +create procedure error_mapping.ErrorHandling1 as +begin +RAISERROR('Hello %q', 16, 1, 'as') +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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: 2787)~~ + +~~ERROR (Message: Invalid format specification: '%q'.)~~ + +~~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 + +GO + + + +set xact_abort OFF; +GO + + + +-- Error classification is done -- +-- Executing test error_mapping.ErrorHandling10000000 +GO + + +begin try +select 1 +RAISERROR('Hello %q', 16, 1, 'as') +end try +begin catch + select xact_state(); +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 +~~START~~ +int +1 +~~END~~ + +~~START~~ +smallint +0 +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling2', because it does not exist or you do not have permission.)~~ + + +GO + + + +GO +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/sql_expected/293_1.out b/contrib/test/JDBC/sql_expected/293_1.out new file mode 100644 index 00000000000..17132a1686a --- /dev/null +++ b/contrib/test/JDBC/sql_expected/293_1.out @@ -0,0 +1,491 @@ + +-- simple batch start +CREATE TABLE t293(c1 varchar(255)) +GO + +INSERT INTO t293(c1) +VALUES ('string'); +GO +~~ROW COUNT: 1~~ + + + +SELECT CAST( + (SELECT * FROM t293) + AS SMALLMONEY) +GO +~~START~~ +smallmoney +~~ERROR (Code: 293)~~ + +~~ERROR (Message: Cannot convert char value to smallmoney. The char value has incorrect syntax.)~~ + +DROP TABLE t293 +GO + + +begin transaction +GO +CREATE TABLE t293(c1 varchar(255)) +GO + +INSERT INTO t293(c1) +VALUES ('string'); +GO +~~ROW COUNT: 1~~ + + + +SELECT CAST( + (SELECT * FROM t293) + AS SMALLMONEY) +GO +~~START~~ +smallmoney +~~ERROR (Code: 293)~~ + +~~ERROR (Message: Cannot convert char value to smallmoney. The char value has incorrect syntax.)~~ + + + +-- Below output is only applicable if query is special case. for example, CREATE/ALTER TRIGGER, CREATE/ALTER FUNCTION, CREATE/ALTER PROC, CREATE/ALTER VIEW etc +if (@@trancount > 0) select cast('compile time error' as text) else select cast('runtime error' as text) +GO +~~START~~ +text +runtime error +~~END~~ + + +if (@@trancount > 0) rollback tran +GO + +DROP TABLE t293 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the table 't293', because it does not exist or you do not have permission.)~~ + + + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + +CREATE TABLE t293(c1 varchar(255)) +GO + +INSERT INTO t293(c1) +VALUES ('string'); +GO +~~ROW COUNT: 1~~ + + + +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +SELECT CAST( + (SELECT * FROM t293) + AS SMALLMONEY) +end +GO + +DROP TABLE t293 +GO + + +create table error_mapping.temp2 (a int) +GO + +CREATE TABLE t293(c1 varchar(255)) +GO + +INSERT INTO t293(c1) +VALUES ('string'); +GO +~~ROW COUNT: 1~~ + + + +insert into error_mapping.temp2 values(1) +SELECT CAST( + (SELECT * FROM t293) + AS SMALLMONEY) +GO +~~ROW COUNT: 1~~ + +~~START~~ +smallmoney +~~ERROR (Code: 293)~~ + +~~ERROR (Message: Cannot convert char value to smallmoney. The char value has incorrect syntax.)~~ + + +DROP TABLE t293 +GO + + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + +CREATE TABLE t293(c1 varchar(255)) +GO + +INSERT INTO t293(c1) +VALUES ('string'); +GO +~~ROW COUNT: 1~~ + + +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +smallmoney +~~ERROR (Code: 293)~~ + +~~ERROR (Message: Cannot convert char value to smallmoney. The char value has incorrect syntax.)~~ + + +DROP TABLE t293 +GO + + +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 + +-- Parse analysis phase end +GO + + +-- compile time error portion +-- Executing test error_mapping.ErrorHandling1 +CREATE TABLE t293(c1 varchar(255)) +GO + +INSERT INTO t293(c1) +VALUES ('string'); +GO +~~ROW COUNT: 1~~ + + + + + +create procedure error_mapping.ErrorHandling1 as +begin +SELECT CAST( + (SELECT * FROM t293) + AS SMALLMONEY) +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 +DROP TABLE t293 +GO + + + +CREATE TABLE t293(c1 varchar(255)) +GO + +INSERT INTO t293(c1) +VALUES ('string'); +GO +~~ROW COUNT: 1~~ + + +begin transaction +GO + + +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +SELECT CAST( + (SELECT * FROM t293) + AS SMALLMONEY) +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: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +DROP TABLE t293 +GO + + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE t293(c1 varchar(255)) +GO + +INSERT INTO t293(c1) +VALUES ('string'); +GO +~~ROW COUNT: 1~~ + + +begin transaction +GO + + +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +SELECT CAST( + (SELECT * FROM t293) + AS SMALLMONEY) +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: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +DROP TABLE t293 +GO + +set xact_abort OFF; +GO + + +-- comiple time error portion end -- +-- Next portion is for runtime error -- +-- Executing test error_mapping.ErrorHandling10000000 +CREATE TABLE t293(c1 varchar(255)) +GO + +INSERT INTO t293(c1) +VALUES ('string'); +GO +~~ROW COUNT: 1~~ + + + + + +create procedure error_mapping.ErrorHandling1 as +begin +SELECT CAST( + (SELECT * FROM t293) + AS SMALLMONEY) +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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 +~~START~~ +smallmoney +~~ERROR (Code: 293)~~ + +~~ERROR (Message: Cannot convert char value to smallmoney. The char value has incorrect syntax.)~~ + +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 +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +DROP TABLE t293 +GO + + + +set xact_abort ON; +GO +-- Executing test error_mapping.ErrorHandling10000000 +CREATE TABLE t293(c1 varchar(255)) +GO + +INSERT INTO t293(c1) +VALUES ('string'); +GO +~~ROW COUNT: 1~~ + + + + + +create procedure error_mapping.ErrorHandling1 as +begin +SELECT CAST( + (SELECT * FROM t293) + AS SMALLMONEY) +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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 +~~START~~ +smallmoney +~~ERROR (Code: 293)~~ + +~~ERROR (Message: Cannot convert char value to smallmoney. The char value has incorrect syntax.)~~ + +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 +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +DROP TABLE t293 +GO + + + + +set xact_abort OFF; +GO + + +-- Error classification is done -- +-- Executing test error_mapping.ErrorHandling10000000 +CREATE TABLE t293(c1 varchar(255)) +GO + +INSERT INTO t293(c1) +VALUES ('string'); +GO +~~ROW COUNT: 1~~ + + + + + +begin try +select 1 +SELECT CAST( + (SELECT * FROM t293) + AS SMALLMONEY) +end try +begin catch + select xact_state(); +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 +~~START~~ +int +1 +~~END~~ + +~~START~~ +smallmoney +~~END~~ + +~~START~~ +smallint +0 +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling2', because it does not exist or you do not have permission.)~~ + +DROP TABLE t293 +GO + + + + +GO +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/sql_expected/3609_1.out b/contrib/test/JDBC/sql_expected/3609_1.out new file mode 100644 index 00000000000..0fe42b2bd6f --- /dev/null +++ b/contrib/test/JDBC/sql_expected/3609_1.out @@ -0,0 +1,474 @@ + +-- simple batch start +CREATE TABLE t3609(id int); +GO + + +CREATE TRIGGER t3609Trigger +ON t3609 +AFTER INSERT +AS +BEGIN + COMMIT TRANSACTION +END +GO + +INSERT INTO t3609 values (1) +GO +~~ERROR (Code: 3609)~~ + +~~ERROR (Message: The transaction ended in the trigger. The batch has been aborted.)~~ + +DROP TABLE t3609 +Go + +begin transaction +GO +CREATE TABLE t3609(id int); +GO + + +CREATE TRIGGER t3609Trigger +ON t3609 +AFTER INSERT +AS +BEGIN + COMMIT TRANSACTION +END +GO + +INSERT INTO t3609 values (1) +GO +~~ERROR (Code: 3609)~~ + +~~ERROR (Message: The transaction ended in the trigger. The batch has been aborted.)~~ + + + +-- Below output is only applicable if query is special case. for example, CREATE/ALTER TRIGGER, CREATE/ALTER FUNCTION, CREATE/ALTER PROC, CREATE/ALTER VIEW etc +if (@@trancount > 0) select cast('compile time error' as text) else select cast('runtime error' as text) +GO +~~START~~ +text +runtime error +~~END~~ + + +if (@@trancount > 0) rollback tran +GO + +DROP TABLE t3609 +Go + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + +CREATE TABLE t3609(id int); +GO + + +CREATE TRIGGER t3609Trigger +ON t3609 +AFTER INSERT +AS +BEGIN + COMMIT TRANSACTION +END +GO + +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +INSERT INTO t3609 values (1) +end +GO + +DROP TABLE t3609 +Go + +create table error_mapping.temp2 (a int) +GO + +CREATE TABLE t3609(id int); +GO + + +CREATE TRIGGER t3609Trigger +ON t3609 +AFTER INSERT +AS +BEGIN + COMMIT TRANSACTION +END +GO + +insert into error_mapping.temp2 values(1) +INSERT INTO t3609 values (1) +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 3609)~~ + +~~ERROR (Message: The transaction ended in the trigger. The batch has been aborted.)~~ + + +DROP TABLE t3609 +Go + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + +CREATE TABLE t3609(id int); +GO + + +CREATE TRIGGER t3609Trigger +ON t3609 +AFTER INSERT +AS +BEGIN + COMMIT TRANSACTION +END +GO + +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 3609)~~ + +~~ERROR (Message: The transaction ended in the trigger. The batch has been aborted.)~~ + + +DROP TABLE t3609 +Go + +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 + +-- Parse analysis phase end +GO + + +-- compile time error portion +-- Executing test error_mapping.ErrorHandling1 +CREATE TABLE t3609(id int); +GO + + +CREATE TRIGGER t3609Trigger +ON t3609 +AFTER INSERT +AS +BEGIN + COMMIT TRANSACTION +END +GO + + + +create procedure error_mapping.ErrorHandling1 as +begin +INSERT INTO t3609 values (1) +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 +DROP TABLE t3609 +Go + + +CREATE TABLE t3609(id int); +GO + + +CREATE TRIGGER t3609Trigger +ON t3609 +AFTER INSERT +AS +BEGIN + COMMIT TRANSACTION +END +GO + +begin transaction +GO + +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +INSERT INTO t3609 values (1) +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: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +DROP TABLE t3609 +Go + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE t3609(id int); +GO + + +CREATE TRIGGER t3609Trigger +ON t3609 +AFTER INSERT +AS +BEGIN + COMMIT TRANSACTION +END +GO + +begin transaction +GO + +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +INSERT INTO t3609 values (1) +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: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +DROP TABLE t3609 +Go +set xact_abort OFF; +GO + + +-- comiple time error portion end -- +-- Next portion is for runtime error -- +-- Executing test error_mapping.ErrorHandling10000000 +CREATE TABLE t3609(id int); +GO + + +CREATE TRIGGER t3609Trigger +ON t3609 +AFTER INSERT +AS +BEGIN + COMMIT TRANSACTION +END +GO + + + +create procedure error_mapping.ErrorHandling1 as +begin +INSERT INTO t3609 values (1) +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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: 3609)~~ + +~~ERROR (Message: The transaction ended in the trigger. The batch has been aborted.)~~ + +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 +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +DROP TABLE t3609 +Go + + +set xact_abort ON; +GO +-- Executing test error_mapping.ErrorHandling10000000 +CREATE TABLE t3609(id int); +GO + + +CREATE TRIGGER t3609Trigger +ON t3609 +AFTER INSERT +AS +BEGIN + COMMIT TRANSACTION +END +GO + + + +create procedure error_mapping.ErrorHandling1 as +begin +INSERT INTO t3609 values (1) +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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: 3609)~~ + +~~ERROR (Message: The transaction ended in the trigger. The batch has been aborted.)~~ + +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 +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +DROP TABLE t3609 +Go + + + +set xact_abort OFF; +GO + + +-- Error classification is done -- +-- Executing test error_mapping.ErrorHandling10000000 +CREATE TABLE t3609(id int); +GO + + +CREATE TRIGGER t3609Trigger +ON t3609 +AFTER INSERT +AS +BEGIN + COMMIT TRANSACTION +END +GO + + + +begin try +select 1 +INSERT INTO t3609 values (1) +end try +begin catch + select xact_state(); +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 +~~START~~ +int +1 +~~END~~ + +~~START~~ +smallint +0 +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling2', because it does not exist or you do not have permission.)~~ + +DROP TABLE t3609 +Go + + + +GO +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/sql_expected/3701_3.out b/contrib/test/JDBC/sql_expected/3701_3.out new file mode 100644 index 00000000000..921d2020aa2 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/3701_3.out @@ -0,0 +1,243 @@ +# Executing test ErrorHandling1 +--Pre +GO + + +create procedure ErrorHandling1 as +begin +--Procedure doesn't exist +DROP PROC p3701; +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +GO + + +--Pre +GO +begin transaction +GO +# Executing test ErrorHandling1 + +create procedure ErrorHandling1 as +begin +--Procedure doesn't exist +DROP PROC p3701; +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +--Post +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +--Pre +GO +begin transaction +GO +# Executing test ErrorHandling1 + +create procedure ErrorHandling1 as +begin +--Procedure doesn't exist +DROP PROC p3701; +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +--Post +GO +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Next portion is for runtime error -- +--Pre +GO + + +create procedure ErrorHandling1 as +begin +--Procedure doesn't exist +DROP PROC p3701; +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'p3701', because it does not exist or you do not have permission.)~~ + +~~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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +--Pre +GO + + +create procedure ErrorHandling1 as +begin +--Procedure doesn't exist +DROP PROC p3701; +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'p3701', because it does not exist or you do not have permission.)~~ + +~~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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +GO + + + +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Error classification is done -- +--Pre +GO + + +begin try +select 1 +--Procedure doesn't exist +DROP PROC p3701; +end try +begin catch + select xact_state(); +end catch +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +int +1 +~~END~~ + +~~START~~ +smallint +0 +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling2', because it does not exist or you do not have permission.)~~ + +--Post +GO + + diff --git a/contrib/test/JDBC/sql_expected/3701_4.out b/contrib/test/JDBC/sql_expected/3701_4.out new file mode 100644 index 00000000000..b91c0556847 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/3701_4.out @@ -0,0 +1,243 @@ +# Executing test ErrorHandling1 +--Pre +GO + + +create procedure ErrorHandling1 as +begin +--Trigger doesn't exist +DROP TRIGGER tr3701 +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +GO + + +--Pre +GO +begin transaction +GO +# Executing test ErrorHandling1 + +create procedure ErrorHandling1 as +begin +--Trigger doesn't exist +DROP TRIGGER tr3701 +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +--Post +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +--Pre +GO +begin transaction +GO +# Executing test ErrorHandling1 + +create procedure ErrorHandling1 as +begin +--Trigger doesn't exist +DROP TRIGGER tr3701 +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +--Post +GO +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Next portion is for runtime error -- +--Pre +GO + + +create procedure ErrorHandling1 as +begin +--Trigger doesn't exist +DROP TRIGGER tr3701 +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the trigger 'tr3701', because it does not exist or you do not have permission.)~~ + +~~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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +--Pre +GO + + +create procedure ErrorHandling1 as +begin +--Trigger doesn't exist +DROP TRIGGER tr3701 +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the trigger 'tr3701', because it does not exist or you do not have permission.)~~ + +~~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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +GO + + + +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Error classification is done -- +--Pre +GO + + +begin try +select 1 +--Trigger doesn't exist +DROP TRIGGER tr3701 +end try +begin catch + select xact_state(); +end catch +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +int +1 +~~END~~ + +~~START~~ +smallint +0 +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling2', because it does not exist or you do not have permission.)~~ + +--Post +GO + + diff --git a/contrib/test/JDBC/sql_expected/3701_5.out b/contrib/test/JDBC/sql_expected/3701_5.out new file mode 100644 index 00000000000..1ab3e8be8e7 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/3701_5.out @@ -0,0 +1,243 @@ +# Executing test ErrorHandling1 +--Pre +GO + + +create procedure ErrorHandling1 as +begin +--Function doesn't exist +DROP FUNCTION fn3701; +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +GO + + +--Pre +GO +begin transaction +GO +# Executing test ErrorHandling1 + +create procedure ErrorHandling1 as +begin +--Function doesn't exist +DROP FUNCTION fn3701; +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +--Post +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +--Pre +GO +begin transaction +GO +# Executing test ErrorHandling1 + +create procedure ErrorHandling1 as +begin +--Function doesn't exist +DROP FUNCTION fn3701; +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +--Post +GO +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Next portion is for runtime error -- +--Pre +GO + + +create procedure ErrorHandling1 as +begin +--Function doesn't exist +DROP FUNCTION fn3701; +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the function 'fn3701', because it does not exist or you do not have permission.)~~ + +~~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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +--Pre +GO + + +create procedure ErrorHandling1 as +begin +--Function doesn't exist +DROP FUNCTION fn3701; +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the function 'fn3701', because it does not exist or you do not have permission.)~~ + +~~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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +GO + + + +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Error classification is done -- +--Pre +GO + + +begin try +select 1 +--Function doesn't exist +DROP FUNCTION fn3701; +end try +begin catch + select xact_state(); +end catch +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +int +1 +~~END~~ + +~~START~~ +smallint +0 +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling2', because it does not exist or you do not have permission.)~~ + +--Post +GO + + diff --git a/contrib/test/JDBC/sql_expected/3728_3727_1.out b/contrib/test/JDBC/sql_expected/3728_3727_1.out new file mode 100644 index 00000000000..847a67d02b1 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/3728_3727_1.out @@ -0,0 +1,305 @@ +# Executing test ErrorHandling1 +CREATE TABLE t3728(c1 int, c2 int) +GO +INSERT INTO t3728 VALUES(1, 11) +INSERT INTO t3728 VALUES(1, 111) +INSERT INTO t3728 VALUES(2, 22) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + + + +create procedure ErrorHandling1 as +begin +ALTER TABLE t3728 + DROP CONSTRAINT NonExistingConstraint +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t3728 +GO + + + +CREATE TABLE t3728(c1 int, c2 int) +GO +INSERT INTO t3728 VALUES(1, 11) +INSERT INTO t3728 VALUES(1, 111) +INSERT INTO t3728 VALUES(2, 22) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +begin transaction +GO +# Executing test ErrorHandling1 + +create procedure ErrorHandling1 as +begin +ALTER TABLE t3728 + DROP CONSTRAINT NonExistingConstraint +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +DROP TABLE t3728 +GO + + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE t3728(c1 int, c2 int) +GO +INSERT INTO t3728 VALUES(1, 11) +INSERT INTO t3728 VALUES(1, 111) +INSERT INTO t3728 VALUES(2, 22) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +begin transaction +GO +# Executing test ErrorHandling1 + +create procedure ErrorHandling1 as +begin +ALTER TABLE t3728 + DROP CONSTRAINT NonExistingConstraint +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +DROP TABLE t3728 +GO + +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Next portion is for runtime error -- +CREATE TABLE t3728(c1 int, c2 int) +GO +INSERT INTO t3728 VALUES(1, 11) +INSERT INTO t3728 VALUES(1, 111) +INSERT INTO t3728 VALUES(2, 22) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + + + +create procedure ErrorHandling1 as +begin +ALTER TABLE t3728 + DROP CONSTRAINT NonExistingConstraint +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 3728)~~ + +~~ERROR (Message: 'NonExistingConstraint' is not a constraint.)~~ + +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +DROP TABLE t3728 +GO + + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +CREATE TABLE t3728(c1 int, c2 int) +GO +INSERT INTO t3728 VALUES(1, 11) +INSERT INTO t3728 VALUES(1, 111) +INSERT INTO t3728 VALUES(2, 22) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + + + +create procedure ErrorHandling1 as +begin +ALTER TABLE t3728 + DROP CONSTRAINT NonExistingConstraint +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 3728)~~ + +~~ERROR (Message: 'NonExistingConstraint' is not a constraint.)~~ + +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +DROP TABLE t3728 +GO + + + + +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Error classification is done -- +CREATE TABLE t3728(c1 int, c2 int) +GO +INSERT INTO t3728 VALUES(1, 11) +INSERT INTO t3728 VALUES(1, 111) +INSERT INTO t3728 VALUES(2, 22) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + + + +begin try +select 1 +ALTER TABLE t3728 + DROP CONSTRAINT NonExistingConstraint +end try +begin catch + select xact_state(); +end catch +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +int +1 +~~END~~ + +~~START~~ +smallint +0 +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling2', because it does not exist or you do not have permission.)~~ + +DROP TABLE t3728 +GO + + + diff --git a/contrib/test/JDBC/sql_expected/3729_1.out b/contrib/test/JDBC/sql_expected/3729_1.out new file mode 100644 index 00000000000..09ce7e63ed5 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/3729_1.out @@ -0,0 +1,326 @@ +USE master +GO + +# Executing test ErrorHandling1 +CREATE SCHEMA s3729 +GO + +CREATE FUNCTION s3729.f3729 () +RETURNS INT +AS +BEGIN + RETURN 123 ; +END; +GO + +CREATE TABLE t3729(c1 int default s3729.f3729()) +GO + + + +create procedure ErrorHandling1 as +begin +DROP FUNCTION s3729.f3729 +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t3729 +GO +DROP FUNCTION s3729.f3729 +GO +DROP SCHEMA s3729 +GO + + +CREATE SCHEMA s3729 +GO + +CREATE FUNCTION s3729.f3729 () +RETURNS INT +AS +BEGIN + RETURN 123 ; +END; +GO + +CREATE TABLE t3729(c1 int default s3729.f3729()) +GO + +begin transaction +GO +# Executing test ErrorHandling1 + +create procedure ErrorHandling1 as +begin +DROP FUNCTION s3729.f3729 +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "errorhandling1")~~ + + +GO +DROP TABLE t3729 +GO +DROP FUNCTION s3729.f3729 +GO +DROP SCHEMA s3729 +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE SCHEMA s3729 +GO + +CREATE FUNCTION s3729.f3729 () +RETURNS INT +AS +BEGIN + RETURN 123 ; +END; +GO + +CREATE TABLE t3729(c1 int default s3729.f3729()) +GO + +begin transaction +GO +# Executing test ErrorHandling1 + +create procedure ErrorHandling1 as +begin +DROP FUNCTION s3729.f3729 +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "errorhandling1")~~ + + +GO +DROP TABLE t3729 +GO +DROP FUNCTION s3729.f3729 +GO +DROP SCHEMA s3729 +GO +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Next portion is for runtime error -- +CREATE SCHEMA s3729 +GO + +CREATE FUNCTION s3729.f3729 () +RETURNS INT +AS +BEGIN + RETURN 123 ; +END; +GO + +CREATE TABLE t3729(c1 int default s3729.f3729()) +GO + + + +create procedure ErrorHandling1 as +begin +DROP FUNCTION s3729.f3729 +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 3729)~~ + +~~ERROR (Message: cannot drop function master_s3729.f3729() because other objects depend on it)~~ + +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +DROP TABLE t3729 +GO +DROP FUNCTION s3729.f3729 +GO +DROP SCHEMA s3729 +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +CREATE SCHEMA s3729 +GO + +CREATE FUNCTION s3729.f3729 () +RETURNS INT +AS +BEGIN + RETURN 123 ; +END; +GO + +CREATE TABLE t3729(c1 int default s3729.f3729()) +GO + + + +create procedure ErrorHandling1 as +begin +DROP FUNCTION s3729.f3729 +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 3729)~~ + +~~ERROR (Message: cannot drop function master_s3729.f3729() because other objects depend on it)~~ + +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +DROP TABLE t3729 +GO +DROP FUNCTION s3729.f3729 +GO +DROP SCHEMA s3729 +GO + + + +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Error classification is done -- +CREATE SCHEMA s3729 +GO + +CREATE FUNCTION s3729.f3729 () +RETURNS INT +AS +BEGIN + RETURN 123 ; +END; +GO + +CREATE TABLE t3729(c1 int default s3729.f3729()) +GO + + + +begin try +select 1 +DROP FUNCTION s3729.f3729 +end try +begin catch + select xact_state(); +end catch +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +int +1 +~~END~~ + +~~START~~ +smallint +0 +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "errorhandling1")~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "errorhandling2")~~ + +DROP TABLE t3729 +GO +DROP FUNCTION s3729.f3729 +GO +DROP SCHEMA s3729 +GO + + diff --git a/contrib/test/JDBC/sql_expected/3902_1.out b/contrib/test/JDBC/sql_expected/3902_1.out new file mode 100644 index 00000000000..c9a81164794 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/3902_1.out @@ -0,0 +1,261 @@ +# Executing test ErrorHandling1 +--Pre +GO + + +create procedure ErrorHandling1 as +begin +--Generate the error +COMMIT; +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +GO + + +--Pre +GO +begin transaction +GO +# Executing test ErrorHandling1 + +create procedure ErrorHandling1 as +begin +--Generate the error +COMMIT; +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +--Post +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +--Pre +GO +begin transaction +GO +# Executing test ErrorHandling1 + +create procedure ErrorHandling1 as +begin +--Generate the error +COMMIT; +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +--Post +GO +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Next portion is for runtime error -- +--Pre +GO + + +create procedure ErrorHandling1 as +begin +--Generate the error +COMMIT; +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~START~~ +int +0 +~~END~~ + +~~ERROR (Code: 266)~~ + +~~ERROR (Message: Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMIT statements. Previous count = 1, current count = 0.)~~ + +~~START~~ +text +CURRENT BATCH TERMINATING ERROR +~~END~~ + +~~ERROR (Code: 266)~~ + +~~ERROR (Message: Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMIT statements. Previous count = 1, current count = 0.)~~ + +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +--Post +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +--Pre +GO + + +create procedure ErrorHandling1 as +begin +--Generate the error +COMMIT; +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~START~~ +int +0 +~~END~~ + +~~ERROR (Code: 266)~~ + +~~ERROR (Message: Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMIT statements. Previous count = 1, current count = 0.)~~ + +~~START~~ +text +CURRENT BATCH TERMINATING ERROR +~~END~~ + +~~ERROR (Code: 266)~~ + +~~ERROR (Message: Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMIT statements. Previous count = 1, current count = 0.)~~ + +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +--Post +GO + + + +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Error classification is done -- +--Pre +GO + + +begin try +select 1 +--Generate the error +COMMIT; +end try +begin catch + select xact_state(); +end catch +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +int +1 +~~END~~ + +~~START~~ +smallint +0 +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling2', because it does not exist or you do not have permission.)~~ + +--Post +GO + + diff --git a/contrib/test/JDBC/sql_expected/3903_1.out b/contrib/test/JDBC/sql_expected/3903_1.out new file mode 100644 index 00000000000..4d6cf02d505 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/3903_1.out @@ -0,0 +1,267 @@ +# Executing test ErrorHandling1 +--Pre +GO + + + +create procedure ErrorHandling1 as +begin +--Generate the error +ROLLBACK +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +GO + + +--Pre +GO + +begin transaction +GO +# Executing test ErrorHandling1 + +create procedure ErrorHandling1 as +begin +--Generate the error +ROLLBACK +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +--Post +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +--Pre +GO + +begin transaction +GO +# Executing test ErrorHandling1 + +create procedure ErrorHandling1 as +begin +--Generate the error +ROLLBACK +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +--Post +GO +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Next portion is for runtime error -- +--Pre +GO + + + +create procedure ErrorHandling1 as +begin +--Generate the error +ROLLBACK +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~START~~ +int +0 +~~END~~ + +~~ERROR (Code: 266)~~ + +~~ERROR (Message: Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMIT statements. Previous count = 1, current count = 0.)~~ + +~~START~~ +text +CURRENT BATCH TERMINATING ERROR +~~END~~ + +~~ERROR (Code: 266)~~ + +~~ERROR (Message: Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMIT statements. Previous count = 1, current count = 0.)~~ + +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +--Post +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +--Pre +GO + + + +create procedure ErrorHandling1 as +begin +--Generate the error +ROLLBACK +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~START~~ +int +0 +~~END~~ + +~~ERROR (Code: 266)~~ + +~~ERROR (Message: Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMIT statements. Previous count = 1, current count = 0.)~~ + +~~START~~ +text +CURRENT BATCH TERMINATING ERROR +~~END~~ + +~~ERROR (Code: 266)~~ + +~~ERROR (Message: Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMIT statements. Previous count = 1, current count = 0.)~~ + +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +--Post +GO + + + +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Error classification is done -- +--Pre +GO + + + +begin try +select 1 +--Generate the error +ROLLBACK +end try +begin catch + select xact_state(); +end catch +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +int +1 +~~END~~ + +~~START~~ +smallint +0 +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling2', because it does not exist or you do not have permission.)~~ + +--Post +GO + + diff --git a/contrib/test/JDBC/sql_expected/3930_1.out b/contrib/test/JDBC/sql_expected/3930_1.out new file mode 100644 index 00000000000..c3da5148b65 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/3930_1.out @@ -0,0 +1,330 @@ +# Executing test ErrorHandling1 +CREATE TABLE t3930_1(c1 int primary key, c2 int) +GO +CREATE TABLE t3930_2(c1 int primary key, c2 int, constraint fk foreign key (c2) references t3930_1(c1)) +GO +CREATE TABLE t3930 (a int) +GO + + +create procedure ErrorHandling1 as +begin +begin tran + begin try + TRUNCATE TABLE t3930_1; + end try + begin catch + select xact_state(); + drop table t3930; + end catch +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t3930_2 +GO +DROP TABLE t3930_1 +GO +DROP TABLE t3930 +GO + + +CREATE TABLE t3930_1(c1 int primary key, c2 int) +GO +CREATE TABLE t3930_2(c1 int primary key, c2 int, constraint fk foreign key (c2) references t3930_1(c1)) +GO +CREATE TABLE t3930 (a int) +GO +begin transaction +GO +# Executing test ErrorHandling1 + +create procedure ErrorHandling1 as +begin +begin tran + begin try + TRUNCATE TABLE t3930_1; + end try + begin catch + select xact_state(); + drop table t3930; + end catch +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "errorhandling1")~~ + + +GO +DROP TABLE t3930_2 +GO +DROP TABLE t3930_1 +GO +DROP TABLE t3930 +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE t3930_1(c1 int primary key, c2 int) +GO +CREATE TABLE t3930_2(c1 int primary key, c2 int, constraint fk foreign key (c2) references t3930_1(c1)) +GO +CREATE TABLE t3930 (a int) +GO +begin transaction +GO +# Executing test ErrorHandling1 + +create procedure ErrorHandling1 as +begin +begin tran + begin try + TRUNCATE TABLE t3930_1; + end try + begin catch + select xact_state(); + drop table t3930; + end catch +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "errorhandling1")~~ + + +GO +DROP TABLE t3930_2 +GO +DROP TABLE t3930_1 +GO +DROP TABLE t3930 +GO +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Next portion is for runtime error -- +CREATE TABLE t3930_1(c1 int primary key, c2 int) +GO +CREATE TABLE t3930_2(c1 int primary key, c2 int, constraint fk foreign key (c2) references t3930_1(c1)) +GO +CREATE TABLE t3930 (a int) +GO + + +create procedure ErrorHandling1 as +begin +begin tran + begin try + TRUNCATE TABLE t3930_1; + end try + begin catch + select xact_state(); + drop table t3930; + end catch +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~START~~ +smallint +-1 +~~END~~ + +~~ERROR (Code: 3930)~~ + +~~ERROR (Message: The current transaction cannot be committed and cannot support operations that write to the log file. Roll back the transaction.)~~ + +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +DROP TABLE t3930_2 +GO +DROP TABLE t3930_1 +GO +DROP TABLE t3930 +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +CREATE TABLE t3930_1(c1 int primary key, c2 int) +GO +CREATE TABLE t3930_2(c1 int primary key, c2 int, constraint fk foreign key (c2) references t3930_1(c1)) +GO +CREATE TABLE t3930 (a int) +GO + + +create procedure ErrorHandling1 as +begin +begin tran + begin try + TRUNCATE TABLE t3930_1; + end try + begin catch + select xact_state(); + drop table t3930; + end catch +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~START~~ +smallint +-1 +~~END~~ + +~~ERROR (Code: 3930)~~ + +~~ERROR (Message: The current transaction cannot be committed and cannot support operations that write to the log file. Roll back the transaction.)~~ + +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +DROP TABLE t3930_2 +GO +DROP TABLE t3930_1 +GO +DROP TABLE t3930 +GO + + + +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Error classification is done -- +CREATE TABLE t3930_1(c1 int primary key, c2 int) +GO +CREATE TABLE t3930_2(c1 int primary key, c2 int, constraint fk foreign key (c2) references t3930_1(c1)) +GO +CREATE TABLE t3930 (a int) +GO + + +begin try +select 1 +begin tran + begin try + TRUNCATE TABLE t3930_1; + end try + begin catch + select xact_state(); + drop table t3930; + end catch +end try +begin catch + select xact_state(); +end catch +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +int +1 +~~END~~ + +~~START~~ +smallint +-1 +~~END~~ + +~~START~~ +smallint +-1 +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "errorhandling1")~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "errorhandling2")~~ + +DROP TABLE t3930_2 +GO +DROP TABLE t3930_1 +GO +DROP TABLE t3930 +GO diff --git a/contrib/test/JDBC/sql_expected/4708_1.out b/contrib/test/JDBC/sql_expected/4708_1.out new file mode 100644 index 00000000000..913051df70a --- /dev/null +++ b/contrib/test/JDBC/sql_expected/4708_1.out @@ -0,0 +1,293 @@ +# Executing test ErrorHandling1 +CREATE TABLE t4708(c1 int) +GO +CREATE VIEW v4708 +AS +SELECT c1 FROM t4708 +GO + + + + + +create procedure ErrorHandling1 as +begin +TRUNCATE TABLE v4708 +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP VIEW v4708 +GO +DROP TABLE t4708 +GO + + + + +CREATE TABLE t4708(c1 int) +GO +CREATE VIEW v4708 +AS +SELECT c1 FROM t4708 +GO + + +begin transaction +GO +# Executing test ErrorHandling1 + + +create procedure ErrorHandling1 as +begin +TRUNCATE TABLE v4708 +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +DROP VIEW v4708 +GO +DROP TABLE t4708 +GO + + + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE t4708(c1 int) +GO +CREATE VIEW v4708 +AS +SELECT c1 FROM t4708 +GO + + +begin transaction +GO +# Executing test ErrorHandling1 + + +create procedure ErrorHandling1 as +begin +TRUNCATE TABLE v4708 +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +DROP VIEW v4708 +GO +DROP TABLE t4708 +GO + + +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Next portion is for runtime error -- +CREATE TABLE t4708(c1 int) +GO +CREATE VIEW v4708 +AS +SELECT c1 FROM t4708 +GO + + + + + +create procedure ErrorHandling1 as +begin +TRUNCATE TABLE v4708 +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 4708)~~ + +~~ERROR (Message: Could not truncate object 'v4708' because it is not a table.)~~ + +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +DROP VIEW v4708 +GO +DROP TABLE t4708 +GO + + + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +CREATE TABLE t4708(c1 int) +GO +CREATE VIEW v4708 +AS +SELECT c1 FROM t4708 +GO + + + + + +create procedure ErrorHandling1 as +begin +TRUNCATE TABLE v4708 +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 4708)~~ + +~~ERROR (Message: Could not truncate object 'v4708' because it is not a table.)~~ + +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +DROP VIEW v4708 +GO +DROP TABLE t4708 +GO + + + + + +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Error classification is done -- +CREATE TABLE t4708(c1 int) +GO +CREATE VIEW v4708 +AS +SELECT c1 FROM t4708 +GO + + + + + +begin try +select 1 +TRUNCATE TABLE v4708 +end try +begin catch + select xact_state(); +end catch +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +int +1 +~~END~~ + +~~START~~ +smallint +0 +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling2', because it does not exist or you do not have permission.)~~ + +DROP VIEW v4708 +GO +DROP TABLE t4708 +GO + + + + diff --git a/contrib/test/JDBC/sql_expected/4712_1.out b/contrib/test/JDBC/sql_expected/4712_1.out new file mode 100644 index 00000000000..deab64dc201 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/4712_1.out @@ -0,0 +1,311 @@ +# Executing test ErrorHandling1 +--Pre +CREATE TABLE t4712_1(c1 int primary key, c2 int) +GO +CREATE TABLE t4712_2(c1 int primary key, c2 int, constraint fk foreign key (c2) references t4712_1(c1)) +GO +INSERT INTO t4712_1 VALUES(1, 10) +INSERT INTO t4712_2 VALUES(100, 1) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + + +create procedure ErrorHandling1 as +begin +--CHECK constraint conflict, when adding constraint +TRUNCATE TABLE t4712_1 +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +DROP TABLE t4712_2 +GO +DROP TABLE t4712_1 +GO + + +--Pre +CREATE TABLE t4712_1(c1 int primary key, c2 int) +GO +CREATE TABLE t4712_2(c1 int primary key, c2 int, constraint fk foreign key (c2) references t4712_1(c1)) +GO +INSERT INTO t4712_1 VALUES(1, 10) +INSERT INTO t4712_2 VALUES(100, 1) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +begin transaction +GO +# Executing test ErrorHandling1 + +create procedure ErrorHandling1 as +begin +--CHECK constraint conflict, when adding constraint +TRUNCATE TABLE t4712_1 +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +--Post +DROP TABLE t4712_2 +GO +DROP TABLE t4712_1 +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +--Pre +CREATE TABLE t4712_1(c1 int primary key, c2 int) +GO +CREATE TABLE t4712_2(c1 int primary key, c2 int, constraint fk foreign key (c2) references t4712_1(c1)) +GO +INSERT INTO t4712_1 VALUES(1, 10) +INSERT INTO t4712_2 VALUES(100, 1) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +begin transaction +GO +# Executing test ErrorHandling1 + +create procedure ErrorHandling1 as +begin +--CHECK constraint conflict, when adding constraint +TRUNCATE TABLE t4712_1 +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +--Post +DROP TABLE t4712_2 +GO +DROP TABLE t4712_1 +GO +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Next portion is for runtime error -- +--Pre +CREATE TABLE t4712_1(c1 int primary key, c2 int) +GO +CREATE TABLE t4712_2(c1 int primary key, c2 int, constraint fk foreign key (c2) references t4712_1(c1)) +GO +INSERT INTO t4712_1 VALUES(1, 10) +INSERT INTO t4712_2 VALUES(100, 1) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + + +create procedure ErrorHandling1 as +begin +--CHECK constraint conflict, when adding constraint +TRUNCATE TABLE t4712_1 +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 4712)~~ + +~~ERROR (Message: Cannot truncate table 't4712_1' because it is being referenced by a FOREIGN KEY constraint.)~~ + +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +--Post +DROP TABLE t4712_2 +GO +DROP TABLE t4712_1 +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +--Pre +CREATE TABLE t4712_1(c1 int primary key, c2 int) +GO +CREATE TABLE t4712_2(c1 int primary key, c2 int, constraint fk foreign key (c2) references t4712_1(c1)) +GO +INSERT INTO t4712_1 VALUES(1, 10) +INSERT INTO t4712_2 VALUES(100, 1) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + + +create procedure ErrorHandling1 as +begin +--CHECK constraint conflict, when adding constraint +TRUNCATE TABLE t4712_1 +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 4712)~~ + +~~ERROR (Message: Cannot truncate table 't4712_1' because it is being referenced by a FOREIGN KEY constraint.)~~ + +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +--Post +DROP TABLE t4712_2 +GO +DROP TABLE t4712_1 +GO + + + +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Error classification is done -- +--Pre +CREATE TABLE t4712_1(c1 int primary key, c2 int) +GO +CREATE TABLE t4712_2(c1 int primary key, c2 int, constraint fk foreign key (c2) references t4712_1(c1)) +GO +INSERT INTO t4712_1 VALUES(1, 10) +INSERT INTO t4712_2 VALUES(100, 1) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + + +begin try +select 1 +--CHECK constraint conflict, when adding constraint +TRUNCATE TABLE t4712_1 +end try +begin catch + select xact_state(); +end catch +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +int +1 +~~END~~ + +~~START~~ +smallint +0 +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling2', because it does not exist or you do not have permission.)~~ + +--Post +DROP TABLE t4712_2 +GO +DROP TABLE t4712_1 +GO + + diff --git a/contrib/test/JDBC/sql_expected/4901_1.out b/contrib/test/JDBC/sql_expected/4901_1.out new file mode 100644 index 00000000000..58b9d621384 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/4901_1.out @@ -0,0 +1,423 @@ + +-- simple batch start +CREATE TABLE t4901(c1 varchar(23)) +GO +INSERT INTO t4901 VALUES('a') +GO +~~ROW COUNT: 1~~ + + +ALTER TABLE t4901 ADD c2 int NOT NULL +GO +~~ERROR (Code: 4901)~~ + +~~ERROR (Message: ALTER TABLE only allows columns to be added that can contain nulls, or have a DEFAULT definition specified, or the column being added is an identity or timestamp column, or alternatively if none of the previous conditions are satisfied the table must be empty to allow addition of this column. Column 'c2' cannot be added to non-empty table 't4901' because it does not satisfy these conditions.)~~ + +DROP TABLE t4901 +GO + + +begin transaction +GO +CREATE TABLE t4901(c1 varchar(23)) +GO +INSERT INTO t4901 VALUES('a') +GO +~~ROW COUNT: 1~~ + + +ALTER TABLE t4901 ADD c2 int NOT NULL +GO +~~ERROR (Code: 4901)~~ + +~~ERROR (Message: ALTER TABLE only allows columns to be added that can contain nulls, or have a DEFAULT definition specified, or the column being added is an identity or timestamp column, or alternatively if none of the previous conditions are satisfied the table must be empty to allow addition of this column. Column 'c2' cannot be added to non-empty table 't4901' because it does not satisfy these conditions.)~~ + + + +-- Below output is only applicable if query is special case. for example, CREATE/ALTER TRIGGER, CREATE/ALTER FUNCTION, CREATE/ALTER PROC, CREATE/ALTER VIEW etc +if (@@trancount > 0) select cast('compile time error' as text) else select cast('runtime error' as text) +GO +~~START~~ +text +runtime error +~~END~~ + + +if (@@trancount > 0) rollback tran +GO + +DROP TABLE t4901 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the table 't4901', because it does not exist or you do not have permission.)~~ + + + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + +CREATE TABLE t4901(c1 varchar(23)) +GO +INSERT INTO t4901 VALUES('a') +GO +~~ROW COUNT: 1~~ + + +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +ALTER TABLE t4901 ADD c2 int NOT NULL +end +GO + +DROP TABLE t4901 +GO + + +create table error_mapping.temp2 (a int) +GO + +CREATE TABLE t4901(c1 varchar(23)) +GO +INSERT INTO t4901 VALUES('a') +GO +~~ROW COUNT: 1~~ + + +insert into error_mapping.temp2 values(1) +ALTER TABLE t4901 ADD c2 int NOT NULL +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 4901)~~ + +~~ERROR (Message: ALTER TABLE only allows columns to be added that can contain nulls, or have a DEFAULT definition specified, or the column being added is an identity or timestamp column, or alternatively if none of the previous conditions are satisfied the table must be empty to allow addition of this column. Column 'c2' cannot be added to non-empty table 't4901' because it does not satisfy these conditions.)~~ + + +DROP TABLE t4901 +GO + + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + +CREATE TABLE t4901(c1 varchar(23)) +GO +INSERT INTO t4901 VALUES('a') +GO +~~ROW COUNT: 1~~ + + +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 4901)~~ + +~~ERROR (Message: ALTER TABLE only allows columns to be added that can contain nulls, or have a DEFAULT definition specified, or the column being added is an identity or timestamp column, or alternatively if none of the previous conditions are satisfied the table must be empty to allow addition of this column. Column 'c2' cannot be added to non-empty table 't4901' because it does not satisfy these conditions.)~~ + + +DROP TABLE t4901 +GO + + +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 + +-- Parse analysis phase end +GO + + +-- compile time error portion +-- Executing test error_mapping.ErrorHandling1 +CREATE TABLE t4901(c1 varchar(23)) +GO +INSERT INTO t4901 VALUES('a') +GO +~~ROW COUNT: 1~~ + + + + +create procedure error_mapping.ErrorHandling1 as +begin +ALTER TABLE t4901 ADD c2 int NOT NULL +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 +DROP TABLE t4901 +GO + + + +CREATE TABLE t4901(c1 varchar(23)) +GO +INSERT INTO t4901 VALUES('a') +GO +~~ROW COUNT: 1~~ + + +begin transaction +GO + +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +ALTER TABLE t4901 ADD c2 int NOT NULL +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: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +DROP TABLE t4901 +GO + + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE t4901(c1 varchar(23)) +GO +INSERT INTO t4901 VALUES('a') +GO +~~ROW COUNT: 1~~ + + +begin transaction +GO + +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +ALTER TABLE t4901 ADD c2 int NOT NULL +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: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +DROP TABLE t4901 +GO + +set xact_abort OFF; +GO + + +-- comiple time error portion end -- +-- Next portion is for runtime error -- +-- Executing test error_mapping.ErrorHandling10000000 +CREATE TABLE t4901(c1 varchar(23)) +GO +INSERT INTO t4901 VALUES('a') +GO +~~ROW COUNT: 1~~ + + + + +create procedure error_mapping.ErrorHandling1 as +begin +ALTER TABLE t4901 ADD c2 int NOT NULL +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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: 4901)~~ + +~~ERROR (Message: ALTER TABLE only allows columns to be added that can contain nulls, or have a DEFAULT definition specified, or the column being added is an identity or timestamp column, or alternatively if none of the previous conditions are satisfied the table must be empty to allow addition of this column. Column 'c2' cannot be added to non-empty table 't4901' because it does not satisfy these conditions.)~~ + +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 +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +DROP TABLE t4901 +GO + + + +set xact_abort ON; +GO +-- Executing test error_mapping.ErrorHandling10000000 +CREATE TABLE t4901(c1 varchar(23)) +GO +INSERT INTO t4901 VALUES('a') +GO +~~ROW COUNT: 1~~ + + + + +create procedure error_mapping.ErrorHandling1 as +begin +ALTER TABLE t4901 ADD c2 int NOT NULL +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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: 4901)~~ + +~~ERROR (Message: ALTER TABLE only allows columns to be added that can contain nulls, or have a DEFAULT definition specified, or the column being added is an identity or timestamp column, or alternatively if none of the previous conditions are satisfied the table must be empty to allow addition of this column. Column 'c2' cannot be added to non-empty table 't4901' because it does not satisfy these conditions.)~~ + +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 +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +DROP TABLE t4901 +GO + + + + +set xact_abort OFF; +GO + + +-- Error classification is done -- +-- Executing test error_mapping.ErrorHandling10000000 +CREATE TABLE t4901(c1 varchar(23)) +GO +INSERT INTO t4901 VALUES('a') +GO +~~ROW COUNT: 1~~ + + + + +begin try +select 1 +ALTER TABLE t4901 ADD c2 int NOT NULL +end try +begin catch + select xact_state(); +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 +~~START~~ +int +1 +~~END~~ + +~~START~~ +smallint +0 +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling2', because it does not exist or you do not have permission.)~~ + +DROP TABLE t4901 +GO + + + + +GO +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/sql_expected/4920_1.out b/contrib/test/JDBC/sql_expected/4920_1.out new file mode 100644 index 00000000000..ffa68792989 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/4920_1.out @@ -0,0 +1,287 @@ +# Executing test ErrorHandling1 +CREATE TABLE t4920(c1 int) +GO + +CREATE TRIGGER tr_4920 ON t4920 +AFTER INSERT +AS +SELECT 1 +GO + + + +create procedure ErrorHandling1 as +begin +ALTER TABLE t4920 + DISABLE TRIGGER NonExisting +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t4920 +GO + + + + +CREATE TABLE t4920(c1 int) +GO + +CREATE TRIGGER tr_4920 ON t4920 +AFTER INSERT +AS +SELECT 1 +GO + +begin transaction +GO +# Executing test ErrorHandling1 + +create procedure ErrorHandling1 as +begin +ALTER TABLE t4920 + DISABLE TRIGGER NonExisting +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +DROP TABLE t4920 +GO + + + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE t4920(c1 int) +GO + +CREATE TRIGGER tr_4920 ON t4920 +AFTER INSERT +AS +SELECT 1 +GO + +begin transaction +GO +# Executing test ErrorHandling1 + +create procedure ErrorHandling1 as +begin +ALTER TABLE t4920 + DISABLE TRIGGER NonExisting +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +DROP TABLE t4920 +GO + + +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Next portion is for runtime error -- +CREATE TABLE t4920(c1 int) +GO + +CREATE TRIGGER tr_4920 ON t4920 +AFTER INSERT +AS +SELECT 1 +GO + + + +create procedure ErrorHandling1 as +begin +ALTER TABLE t4920 + DISABLE TRIGGER NonExisting +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 4920)~~ + +~~ERROR (Message: ALTER TABLE failed because trigger 'NonExisting' on table 't4920' does not exist.)~~ + +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +DROP TABLE t4920 +GO + + + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +CREATE TABLE t4920(c1 int) +GO + +CREATE TRIGGER tr_4920 ON t4920 +AFTER INSERT +AS +SELECT 1 +GO + + + +create procedure ErrorHandling1 as +begin +ALTER TABLE t4920 + DISABLE TRIGGER NonExisting +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 4920)~~ + +~~ERROR (Message: ALTER TABLE failed because trigger 'NonExisting' on table 't4920' does not exist.)~~ + +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +DROP TABLE t4920 +GO + + + + + +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Error classification is done -- +CREATE TABLE t4920(c1 int) +GO + +CREATE TRIGGER tr_4920 ON t4920 +AFTER INSERT +AS +SELECT 1 +GO + + + +begin try +select 1 +ALTER TABLE t4920 + DISABLE TRIGGER NonExisting +end try +begin catch + select xact_state(); +end catch +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +int +1 +~~END~~ + +~~START~~ +smallint +0 +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling2', because it does not exist or you do not have permission.)~~ + +DROP TABLE t4920 +GO + + + + diff --git a/contrib/test/JDBC/sql_expected/512_1.out b/contrib/test/JDBC/sql_expected/512_1.out new file mode 100644 index 00000000000..47439f4815c --- /dev/null +++ b/contrib/test/JDBC/sql_expected/512_1.out @@ -0,0 +1,276 @@ +# Executing test ErrorHandling1 +--Pre +CREATE TABLE t512(c1 int); +INSERT INTO t512 VALUES(1), (5); +GO +~~ROW COUNT: 2~~ + + + +create procedure ErrorHandling1 as +begin +--Generate the error +SELECT * FROM t512 WHERE c1 = (SELECT c1 FROM t512); +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +DROP TABLE t512; +GO + + +--Pre +CREATE TABLE t512(c1 int); +INSERT INTO t512 VALUES(1), (5); +GO +~~ROW COUNT: 2~~ + +begin transaction +GO +# Executing test ErrorHandling1 + +create procedure ErrorHandling1 as +begin +--Generate the error +SELECT * FROM t512 WHERE c1 = (SELECT c1 FROM t512); +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +--Post +DROP TABLE t512; +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +--Pre +CREATE TABLE t512(c1 int); +INSERT INTO t512 VALUES(1), (5); +GO +~~ROW COUNT: 2~~ + +begin transaction +GO +# Executing test ErrorHandling1 + +create procedure ErrorHandling1 as +begin +--Generate the error +SELECT * FROM t512 WHERE c1 = (SELECT c1 FROM t512); +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +--Post +DROP TABLE t512; +GO +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Next portion is for runtime error -- +--Pre +CREATE TABLE t512(c1 int); +INSERT INTO t512 VALUES(1), (5); +GO +~~ROW COUNT: 2~~ + + + +create procedure ErrorHandling1 as +begin +--Generate the error +SELECT * FROM t512 WHERE c1 = (SELECT c1 FROM t512); +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~START~~ +int +~~ERROR (Code: 512)~~ + +~~ERROR (Message: Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.)~~ + +~~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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +DROP TABLE t512; +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +--Pre +CREATE TABLE t512(c1 int); +INSERT INTO t512 VALUES(1), (5); +GO +~~ROW COUNT: 2~~ + + + +create procedure ErrorHandling1 as +begin +--Generate the error +SELECT * FROM t512 WHERE c1 = (SELECT c1 FROM t512); +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~START~~ +int +~~ERROR (Code: 512)~~ + +~~ERROR (Message: Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.)~~ + +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +--Post +DROP TABLE t512; +GO + + + +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Error classification is done -- +--Pre +CREATE TABLE t512(c1 int); +INSERT INTO t512 VALUES(1), (5); +GO +~~ROW COUNT: 2~~ + + + +begin try +select 1 +--Generate the error +SELECT * FROM t512 WHERE c1 = (SELECT c1 FROM t512); +end try +begin catch + select xact_state(); +end catch +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +int +1 +~~END~~ + +~~START~~ +int +~~END~~ + +~~START~~ +smallint +0 +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling2', because it does not exist or you do not have permission.)~~ + +--Post +DROP TABLE t512; +GO + + diff --git a/contrib/test/JDBC/sql_expected/515_1.out b/contrib/test/JDBC/sql_expected/515_1.out new file mode 100644 index 00000000000..c855423f725 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/515_1.out @@ -0,0 +1,250 @@ +# Executing test ErrorHandling1 +--Pre +CREATE TABLE t515(c1 int not null); +GO + + +create procedure ErrorHandling1 as +begin +--Generate the error +INSERT INTO t515 VALUES(null); +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +DROP TABLE t515 +GO + + +--Pre +CREATE TABLE t515(c1 int not null); +GO +begin transaction +GO +# Executing test ErrorHandling1 + +create procedure ErrorHandling1 as +begin +--Generate the error +INSERT INTO t515 VALUES(null); +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +--Post +DROP TABLE t515 +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +--Pre +CREATE TABLE t515(c1 int not null); +GO +begin transaction +GO +# Executing test ErrorHandling1 + +create procedure ErrorHandling1 as +begin +--Generate the error +INSERT INTO t515 VALUES(null); +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +--Post +DROP TABLE t515 +GO +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Next portion is for runtime error -- +--Pre +CREATE TABLE t515(c1 int not null); +GO + + +create procedure ErrorHandling1 as +begin +--Generate the error +INSERT INTO t515 VALUES(null); +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 515)~~ + +~~ERROR (Message: Cannot insert the value NULL into column 'c1', table 'AdventureWorks2014.dbo.t515'; column does not allow nulls. INSERT fails.)~~ + +~~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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +DROP TABLE t515 +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +--Pre +CREATE TABLE t515(c1 int not null); +GO + + +create procedure ErrorHandling1 as +begin +--Generate the error +INSERT INTO t515 VALUES(null); +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 515)~~ + +~~ERROR (Message: Cannot insert the value NULL into column 'c1', table 'AdventureWorks2014.dbo.t515'; column does not allow nulls. INSERT fails.)~~ + +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +--Post +DROP TABLE t515 +GO + + + +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Error classification is done -- +--Pre +CREATE TABLE t515(c1 int not null); +GO + + +begin try +select 1 +--Generate the error +INSERT INTO t515 VALUES(null); +end try +begin catch + select xact_state(); +end catch +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +int +1 +~~END~~ + +~~START~~ +smallint +0 +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling2', because it does not exist or you do not have permission.)~~ + +--Post +DROP TABLE t515 +GO + + diff --git a/contrib/test/JDBC/sql_expected/517_1.out b/contrib/test/JDBC/sql_expected/517_1.out new file mode 100644 index 00000000000..63bd8885383 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/517_1.out @@ -0,0 +1,374 @@ + +-- simple batch start +GO + +SELECT DATEADD(YY,-300,getdate()) +GO +~~START~~ +datetime +~~ERROR (Code: 517)~~ + +~~ERROR (Message: Adding a value to a 'datetime' column caused an overflow.)~~ + +GO + + +begin transaction +GO +GO + +SELECT DATEADD(YY,-300,getdate()) +GO +~~START~~ +datetime +~~ERROR (Code: 517)~~ + +~~ERROR (Message: Adding a value to a 'datetime' column caused an overflow.)~~ + + + +-- Below output is only applicable if query is special case. for example, CREATE/ALTER TRIGGER, CREATE/ALTER FUNCTION, CREATE/ALTER PROC, CREATE/ALTER VIEW etc +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 + +GO + + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + +GO + +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +SELECT DATEADD(YY,-300,getdate()) +end +GO + +GO + + +create table error_mapping.temp2 (a int) +GO + +GO + +insert into error_mapping.temp2 values(1) +SELECT DATEADD(YY,-300,getdate()) +GO +~~ROW COUNT: 1~~ + +~~START~~ +datetime +~~ERROR (Code: 517)~~ + +~~ERROR (Message: Adding a value to a 'datetime' column caused an overflow.)~~ + + +GO + + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + +GO + +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +datetime +~~ERROR (Code: 517)~~ + +~~ERROR (Message: Adding a value to a 'datetime' column caused an overflow.)~~ + + +GO + + +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 + +-- Parse analysis phase end +GO + + +-- compile time error portion +-- Executing test error_mapping.ErrorHandling1 +GO + + + +create procedure error_mapping.ErrorHandling1 as +begin +SELECT DATEADD(YY,-300,getdate()) +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 +GO + + + +GO + +begin transaction +GO + +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +SELECT DATEADD(YY,-300,getdate()) +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: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +GO + + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +GO + +begin transaction +GO + +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +SELECT DATEADD(YY,-300,getdate()) +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: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +GO + +set xact_abort OFF; +GO + + +-- comiple time error portion end -- +-- Next portion is for runtime error -- +-- Executing test error_mapping.ErrorHandling10000000 +GO + + + +create procedure error_mapping.ErrorHandling1 as +begin +SELECT DATEADD(YY,-300,getdate()) +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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 +~~START~~ +datetime +~~ERROR (Code: 517)~~ + +~~ERROR (Message: Adding a value to a 'datetime' column caused an overflow.)~~ + +~~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 +GO + + + +set xact_abort ON; +GO +-- Executing test error_mapping.ErrorHandling10000000 +GO + + + +create procedure error_mapping.ErrorHandling1 as +begin +SELECT DATEADD(YY,-300,getdate()) +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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 +~~START~~ +datetime +~~ERROR (Code: 517)~~ + +~~ERROR (Message: Adding a value to a 'datetime' column caused an overflow.)~~ + +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 +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +GO + + + + +set xact_abort OFF; +GO + + +-- Error classification is done -- +-- Executing test error_mapping.ErrorHandling10000000 +GO + + + +begin try +select 1 +SELECT DATEADD(YY,-300,getdate()) +end try +begin catch + select xact_state(); +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 +~~START~~ +int +1 +~~END~~ + +~~START~~ +datetime +~~END~~ + +~~START~~ +smallint +0 +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling2', because it does not exist or you do not have permission.)~~ + +GO + + + + +GO +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/sql_expected/545_1.out b/contrib/test/JDBC/sql_expected/545_1.out new file mode 100644 index 00000000000..a58e8bbdc1b --- /dev/null +++ b/contrib/test/JDBC/sql_expected/545_1.out @@ -0,0 +1,310 @@ +# Executing test ErrorHandling1 + +CREATE TABLE t545 +( + c1 int IDENTITY +,c2 int +) +GO + + + + + + +create procedure ErrorHandling1 as +begin +SET IDENTITY_INSERT t545 ON +INSERT INTO t545 (c2) VALUES(2) +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +DROP TABLE t545 +GO + + + + + +CREATE TABLE t545 +( + c1 int IDENTITY +,c2 int +) +GO + + +begin transaction +GO +# Executing test ErrorHandling1 + + + +create procedure ErrorHandling1 as +begin +SET IDENTITY_INSERT t545 ON +INSERT INTO t545 (c2) VALUES(2) +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO + +DROP TABLE t545 +GO + + + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO + +CREATE TABLE t545 +( + c1 int IDENTITY +,c2 int +) +GO + + +begin transaction +GO +# Executing test ErrorHandling1 + + + +create procedure ErrorHandling1 as +begin +SET IDENTITY_INSERT t545 ON +INSERT INTO t545 (c2) VALUES(2) +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO + +DROP TABLE t545 +GO + + +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 + +-- Next portion is for runtime error -- +CREATE TABLE t545 +( + c1 int IDENTITY +,c2 int +) +GO + + + + + + +create procedure ErrorHandling1 as +begin +SET IDENTITY_INSERT t545 ON +INSERT INTO t545 (c2) VALUES(2) +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 545)~~ + +~~ERROR (Message: Explicit value must be specified for identity column in table 't545' either when IDENTITY_INSERT is set to ON or when a replication user is inserting into a NOT FOR REPLICATION identity column.)~~ + +~~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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +DROP TABLE t545 +GO + + + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 + +CREATE TABLE t545 +( + c1 int IDENTITY +,c2 int +) +GO + + + + + + +create procedure ErrorHandling1 as +begin +SET IDENTITY_INSERT t545 ON +INSERT INTO t545 (c2) VALUES(2) +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 545)~~ + +~~ERROR (Message: Explicit value must be specified for identity column in table 't545' either when IDENTITY_INSERT is set to ON or when a replication user is inserting into a NOT FOR REPLICATION identity column.)~~ + +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + + +DROP TABLE t545 +GO + + + + + +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 + +-- Error classification is done -- +CREATE TABLE t545 +( + c1 int IDENTITY +,c2 int +) +GO + + + + + + +begin try +select 1 +SET IDENTITY_INSERT t545 ON +INSERT INTO t545 (c2) VALUES(2) +end try +begin catch + select xact_state(); +end catch +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +int +1 +~~END~~ + +~~START~~ +smallint +0 +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling2', because it does not exist or you do not have permission.)~~ + + +DROP TABLE t545 +GO + + + + diff --git a/contrib/test/JDBC/sql_expected/550_1.out b/contrib/test/JDBC/sql_expected/550_1.out new file mode 100644 index 00000000000..754039a6a77 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/550_1.out @@ -0,0 +1,328 @@ +# Executing test ErrorHandling1 +CREATE TABLE t550 +( + c1 int IDENTITY +,c2 int +) +GO + +CREATE VIEW v550 +AS +SELECT c1, c2 FROM t550 WHERE c2 < 10 +WITH CHECK OPTION +GO + + + +create procedure ErrorHandling1 as +begin +INSERT INTO v550 (c2) VALUES(20) +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP VIEW v550 +GO + +DROP TABLE t550 +GO + + + + +CREATE TABLE t550 +( + c1 int IDENTITY +,c2 int +) +GO + +CREATE VIEW v550 +AS +SELECT c1, c2 FROM t550 WHERE c2 < 10 +WITH CHECK OPTION +GO + +begin transaction +GO +# Executing test ErrorHandling1 + +create procedure ErrorHandling1 as +begin +INSERT INTO v550 (c2) VALUES(20) +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +DROP VIEW v550 +GO + +DROP TABLE t550 +GO + + + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE t550 +( + c1 int IDENTITY +,c2 int +) +GO + +CREATE VIEW v550 +AS +SELECT c1, c2 FROM t550 WHERE c2 < 10 +WITH CHECK OPTION +GO + +begin transaction +GO +# Executing test ErrorHandling1 + +create procedure ErrorHandling1 as +begin +INSERT INTO v550 (c2) VALUES(20) +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +DROP VIEW v550 +GO + +DROP TABLE t550 +GO + + +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Next portion is for runtime error -- +CREATE TABLE t550 +( + c1 int IDENTITY +,c2 int +) +GO + +CREATE VIEW v550 +AS +SELECT c1, c2 FROM t550 WHERE c2 < 10 +WITH CHECK OPTION +GO + + + +create procedure ErrorHandling1 as +begin +INSERT INTO v550 (c2) VALUES(20) +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 550)~~ + +~~ERROR (Message: The attempted insert or update failed because the target view either specifies WITH CHECK OPTION or spans a view that specifies WITH CHECK OPTION and one or more rows resulting from the operation did not qualify under the CHECK OPTION constraint.)~~ + +~~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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP VIEW v550 +GO + +DROP TABLE t550 +GO + + + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +CREATE TABLE t550 +( + c1 int IDENTITY +,c2 int +) +GO + +CREATE VIEW v550 +AS +SELECT c1, c2 FROM t550 WHERE c2 < 10 +WITH CHECK OPTION +GO + + + +create procedure ErrorHandling1 as +begin +INSERT INTO v550 (c2) VALUES(20) +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 550)~~ + +~~ERROR (Message: The attempted insert or update failed because the target view either specifies WITH CHECK OPTION or spans a view that specifies WITH CHECK OPTION and one or more rows resulting from the operation did not qualify under the CHECK OPTION constraint.)~~ + +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +DROP VIEW v550 +GO + +DROP TABLE t550 +GO + + + + + +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Error classification is done -- +CREATE TABLE t550 +( + c1 int IDENTITY +,c2 int +) +GO + +CREATE VIEW v550 +AS +SELECT c1, c2 FROM t550 WHERE c2 < 10 +WITH CHECK OPTION +GO + + + +begin try +select 1 +INSERT INTO v550 (c2) VALUES(20) +end try +begin catch + select xact_state(); +end catch +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +int +1 +~~END~~ + +~~START~~ +smallint +0 +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling2', because it does not exist or you do not have permission.)~~ + +DROP VIEW v550 +GO + +DROP TABLE t550 +GO + + + + diff --git a/contrib/test/JDBC/sql_expected/556_1.out b/contrib/test/JDBC/sql_expected/556_1.out new file mode 100644 index 00000000000..bdbaabc4c11 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/556_1.out @@ -0,0 +1,591 @@ + +-- simple batch start +CREATE TABLE t556 ( + id int NOT NULL + , results varchar(50) NOT NULL +); +GO + +CREATE PROCEDURE proc_556 +AS +BEGIN + ALTER TABLE t556 ADD test_type INT; +END; +GO +INSERT INTO t556(id, results) +EXECUTE proc_556; +GO +~~ERROR (Code: 556)~~ + +~~ERROR (Message: INSERT EXEC failed because the stored procedure altered the schema of the target table.)~~ + + +INSERT INTO t556(id, results) +EXECUTE proc_556; +GO +~~ERROR (Code: 556)~~ + +~~ERROR (Message: INSERT EXEC failed because the stored procedure altered the schema of the target table.)~~ + +DROP PROC proc_556 +GO +DROP TABLE t556 +GO + +begin transaction +GO +CREATE TABLE t556 ( + id int NOT NULL + , results varchar(50) NOT NULL +); +GO + +CREATE PROCEDURE proc_556 +AS +BEGIN + ALTER TABLE t556 ADD test_type INT; +END; +GO +INSERT INTO t556(id, results) +EXECUTE proc_556; +GO +~~ERROR (Code: 556)~~ + +~~ERROR (Message: INSERT EXEC failed because the stored procedure altered the schema of the target table.)~~ + + +INSERT INTO t556(id, results) +EXECUTE proc_556; +GO +~~ERROR (Code: 208)~~ + +~~ERROR (Message: Invalid object name 't556'.)~~ + + + +-- Below output is only applicable if query is special case. for example, CREATE/ALTER TRIGGER, CREATE/ALTER FUNCTION, CREATE/ALTER PROC, CREATE/ALTER VIEW etc +if (@@trancount > 0) select cast('compile time error' as text) else select cast('runtime error' as text) +GO +~~START~~ +text +runtime error +~~END~~ + + +if (@@trancount > 0) rollback tran +GO + +DROP PROC proc_556 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'proc_556', because it does not exist or you do not have permission.)~~ + +DROP TABLE t556 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the table 't556', because it does not exist or you do not have permission.)~~ + + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + +CREATE TABLE t556 ( + id int NOT NULL + , results varchar(50) NOT NULL +); +GO + +CREATE PROCEDURE proc_556 +AS +BEGIN + ALTER TABLE t556 ADD test_type INT; +END; +GO +INSERT INTO t556(id, results) +EXECUTE proc_556; +GO +~~ERROR (Code: 556)~~ + +~~ERROR (Message: INSERT EXEC failed because the stored procedure altered the schema of the target table.)~~ + + +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +INSERT INTO t556(id, results) +EXECUTE proc_556; +end +GO + +DROP PROC proc_556 +GO +DROP TABLE t556 +GO + +create table error_mapping.temp2 (a int) +GO + +CREATE TABLE t556 ( + id int NOT NULL + , results varchar(50) NOT NULL +); +GO + +CREATE PROCEDURE proc_556 +AS +BEGIN + ALTER TABLE t556 ADD test_type INT; +END; +GO +INSERT INTO t556(id, results) +EXECUTE proc_556; +GO +~~ERROR (Code: 556)~~ + +~~ERROR (Message: INSERT EXEC failed because the stored procedure altered the schema of the target table.)~~ + + +insert into error_mapping.temp2 values(1) +INSERT INTO t556(id, results) +EXECUTE proc_556; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 556)~~ + +~~ERROR (Message: INSERT EXEC failed because the stored procedure altered the schema of the target table.)~~ + + +DROP PROC proc_556 +GO +DROP TABLE t556 +GO + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + +CREATE TABLE t556 ( + id int NOT NULL + , results varchar(50) NOT NULL +); +GO + +CREATE PROCEDURE proc_556 +AS +BEGIN + ALTER TABLE t556 ADD test_type INT; +END; +GO +INSERT INTO t556(id, results) +EXECUTE proc_556; +GO +~~ERROR (Code: 556)~~ + +~~ERROR (Message: INSERT EXEC failed because the stored procedure altered the schema of the target table.)~~ + + +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 556)~~ + +~~ERROR (Message: INSERT EXEC failed because the stored procedure altered the schema of the target table.)~~ + + +DROP PROC proc_556 +GO +DROP TABLE t556 +GO + +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 + +-- Parse analysis phase end +GO + + +-- compile time error portion +-- Executing test error_mapping.ErrorHandling1 +CREATE TABLE t556 ( + id int NOT NULL + , results varchar(50) NOT NULL +); +GO + +CREATE PROCEDURE proc_556 +AS +BEGIN + ALTER TABLE t556 ADD test_type INT; +END; +GO +INSERT INTO t556(id, results) +EXECUTE proc_556; +GO +~~ERROR (Code: 556)~~ + +~~ERROR (Message: INSERT EXEC failed because the stored procedure altered the schema of the target table.)~~ + + + + +create procedure error_mapping.ErrorHandling1 as +begin +INSERT INTO t556(id, results) +EXECUTE proc_556; +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 +DROP PROC proc_556 +GO +DROP TABLE t556 +GO + + +CREATE TABLE t556 ( + id int NOT NULL + , results varchar(50) NOT NULL +); +GO + +CREATE PROCEDURE proc_556 +AS +BEGIN + ALTER TABLE t556 ADD test_type INT; +END; +GO +INSERT INTO t556(id, results) +EXECUTE proc_556; +GO +~~ERROR (Code: 556)~~ + +~~ERROR (Message: INSERT EXEC failed because the stored procedure altered the schema of the target table.)~~ + + +begin transaction +GO + +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +INSERT INTO t556(id, results) +EXECUTE proc_556; +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: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +DROP PROC proc_556 +GO +DROP TABLE t556 +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE t556 ( + id int NOT NULL + , results varchar(50) NOT NULL +); +GO + +CREATE PROCEDURE proc_556 +AS +BEGIN + ALTER TABLE t556 ADD test_type INT; +END; +GO +INSERT INTO t556(id, results) +EXECUTE proc_556; +GO +~~ERROR (Code: 556)~~ + +~~ERROR (Message: INSERT EXEC failed because the stored procedure altered the schema of the target table.)~~ + + +begin transaction +GO + +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +INSERT INTO t556(id, results) +EXECUTE proc_556; +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: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +DROP PROC proc_556 +GO +DROP TABLE t556 +GO +set xact_abort OFF; +GO + + +-- comiple time error portion end -- +-- Next portion is for runtime error -- +-- Executing test error_mapping.ErrorHandling10000000 +CREATE TABLE t556 ( + id int NOT NULL + , results varchar(50) NOT NULL +); +GO + +CREATE PROCEDURE proc_556 +AS +BEGIN + ALTER TABLE t556 ADD test_type INT; +END; +GO +INSERT INTO t556(id, results) +EXECUTE proc_556; +GO +~~ERROR (Code: 556)~~ + +~~ERROR (Message: INSERT EXEC failed because the stored procedure altered the schema of the target table.)~~ + + + + +create procedure error_mapping.ErrorHandling1 as +begin +INSERT INTO t556(id, results) +EXECUTE proc_556; +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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: 556)~~ + +~~ERROR (Message: INSERT EXEC failed because the stored procedure altered the schema of the target table.)~~ + +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 +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +DROP PROC proc_556 +GO +DROP TABLE t556 +GO + + +set xact_abort ON; +GO +-- Executing test error_mapping.ErrorHandling10000000 +CREATE TABLE t556 ( + id int NOT NULL + , results varchar(50) NOT NULL +); +GO + +CREATE PROCEDURE proc_556 +AS +BEGIN + ALTER TABLE t556 ADD test_type INT; +END; +GO +INSERT INTO t556(id, results) +EXECUTE proc_556; +GO +~~ERROR (Code: 556)~~ + +~~ERROR (Message: INSERT EXEC failed because the stored procedure altered the schema of the target table.)~~ + + + + +create procedure error_mapping.ErrorHandling1 as +begin +INSERT INTO t556(id, results) +EXECUTE proc_556; +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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: 556)~~ + +~~ERROR (Message: INSERT EXEC failed because the stored procedure altered the schema of the target table.)~~ + +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 +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +DROP PROC proc_556 +GO +DROP TABLE t556 +GO + + + +set xact_abort OFF; +GO + + +-- Error classification is done -- +-- Executing test error_mapping.ErrorHandling10000000 +CREATE TABLE t556 ( + id int NOT NULL + , results varchar(50) NOT NULL +); +GO + +CREATE PROCEDURE proc_556 +AS +BEGIN + ALTER TABLE t556 ADD test_type INT; +END; +GO +INSERT INTO t556(id, results) +EXECUTE proc_556; +GO +~~ERROR (Code: 556)~~ + +~~ERROR (Message: INSERT EXEC failed because the stored procedure altered the schema of the target table.)~~ + + + + +begin try +select 1 +INSERT INTO t556(id, results) +EXECUTE proc_556; +end try +begin catch + select xact_state(); +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 +~~START~~ +int +1 +~~END~~ + +~~START~~ +smallint +0 +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling2', because it does not exist or you do not have permission.)~~ + +DROP PROC proc_556 +GO +DROP TABLE t556 +GO + + + +GO +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/sql_expected/6401_1.out b/contrib/test/JDBC/sql_expected/6401_1.out new file mode 100644 index 00000000000..3487ba0697b --- /dev/null +++ b/contrib/test/JDBC/sql_expected/6401_1.out @@ -0,0 +1,275 @@ +# Executing test ErrorHandling1 +--Pre +GO + + +create procedure ErrorHandling1 as +begin +--Generate the error +BEGIN TRAN; +SAVE TRAN mytran; +ROLLBACK TRAN myMispelledTran; +ROLLBACK; +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +--Post +GO + + + +--Pre +GO +begin transaction +GO +# Executing test ErrorHandling1 + +create procedure ErrorHandling1 as +begin +--Generate the error +BEGIN TRAN; +SAVE TRAN mytran; +ROLLBACK TRAN myMispelledTran; +ROLLBACK; +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +--Post +GO + + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +--Pre +GO +begin transaction +GO +# Executing test ErrorHandling1 + +create procedure ErrorHandling1 as +begin +--Generate the error +BEGIN TRAN; +SAVE TRAN mytran; +ROLLBACK TRAN myMispelledTran; +ROLLBACK; +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +--Post +GO + +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Next portion is for runtime error -- +--Pre +GO + + +create procedure ErrorHandling1 as +begin +--Generate the error +BEGIN TRAN; +SAVE TRAN mytran; +ROLLBACK TRAN myMispelledTran; +ROLLBACK; +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 6401)~~ + +~~ERROR (Message: Cannot roll back myMispelledTran. No transaction or savepoint of that name was found.)~~ + +~~START~~ +int +0 +~~END~~ + +~~ERROR (Code: 266)~~ + +~~ERROR (Message: Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMIT statements. Previous count = 1, current count = 0.)~~ + +~~START~~ +text +CURRENT BATCH TERMINATING ERROR +~~END~~ + +~~ERROR (Code: 266)~~ + +~~ERROR (Message: Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMIT statements. Previous count = 1, current count = 0.)~~ + +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +--Post +GO + + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +--Pre +GO + + +create procedure ErrorHandling1 as +begin +--Generate the error +BEGIN TRAN; +SAVE TRAN mytran; +ROLLBACK TRAN myMispelledTran; +ROLLBACK; +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 6401)~~ + +~~ERROR (Message: Cannot roll back myMispelledTran. No transaction or savepoint of that name was found.)~~ + +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +--Post +GO + + + + +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Error classification is done -- +--Pre +GO + + +begin try +select 1 +--Generate the error +BEGIN TRAN; +SAVE TRAN mytran; +ROLLBACK TRAN myMispelledTran; +ROLLBACK; +end try +begin catch + select xact_state(); +end catch +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +int +1 +~~END~~ + +~~START~~ +smallint +1 +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling2', because it does not exist or you do not have permission.)~~ + +--Post +GO + + + diff --git a/contrib/test/JDBC/sql_expected/8106_1.out b/contrib/test/JDBC/sql_expected/8106_1.out new file mode 100644 index 00000000000..f7368f629b1 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/8106_1.out @@ -0,0 +1,389 @@ + +-- simple batch start +CREATE TABLE t8106(a int) +GO + + +SET IDENTITY_INSERT t8106 ON +GO +~~ERROR (Code: 8106)~~ + +~~ERROR (Message: Table 't8106' does not have the identity property. Cannot perform SET operation.)~~ + +DROP TABLE t8106 +GO + + +begin transaction +GO +CREATE TABLE t8106(a int) +GO + + +SET IDENTITY_INSERT t8106 ON +GO +~~ERROR (Code: 8106)~~ + +~~ERROR (Message: Table 't8106' does not have the identity property. Cannot perform SET operation.)~~ + + + +-- Below output is only applicable if query is special case. for example, CREATE/ALTER TRIGGER, CREATE/ALTER FUNCTION, CREATE/ALTER PROC, CREATE/ALTER VIEW etc +if (@@trancount > 0) select cast('compile time error' as text) else select cast('runtime error' as text) +GO +~~START~~ +text +runtime error +~~END~~ + + +if (@@trancount > 0) rollback tran +GO + +DROP TABLE t8106 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the table 't8106', because it does not exist or you do not have permission.)~~ + + + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + +CREATE TABLE t8106(a int) +GO + + +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +SET IDENTITY_INSERT t8106 ON +end +GO + +DROP TABLE t8106 +GO + + +create table error_mapping.temp2 (a int) +GO + +CREATE TABLE t8106(a int) +GO + + +insert into error_mapping.temp2 values(1) +SET IDENTITY_INSERT t8106 ON +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 8106)~~ + +~~ERROR (Message: Table 't8106' does not have the identity property. Cannot perform SET operation.)~~ + + +DROP TABLE t8106 +GO + + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + +CREATE TABLE t8106(a int) +GO + +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 8106)~~ + +~~ERROR (Message: Table 't8106' does not have the identity property. Cannot perform SET operation.)~~ + + +DROP TABLE t8106 +GO + + +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 + +-- Parse analysis phase end +GO + + +-- compile time error portion +-- Executing test error_mapping.ErrorHandling1 +CREATE TABLE t8106(a int) +GO + + + + +create procedure error_mapping.ErrorHandling1 as +begin +SET IDENTITY_INSERT t8106 ON +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 +DROP TABLE t8106 +GO + + + +CREATE TABLE t8106(a int) +GO + +begin transaction +GO + + +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +SET IDENTITY_INSERT t8106 ON +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: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +DROP TABLE t8106 +GO + + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE t8106(a int) +GO + +begin transaction +GO + + +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +SET IDENTITY_INSERT t8106 ON +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: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +DROP TABLE t8106 +GO + +set xact_abort OFF; +GO + + +-- comiple time error portion end -- +-- Next portion is for runtime error -- +-- Executing test error_mapping.ErrorHandling10000000 +CREATE TABLE t8106(a int) +GO + + + + +create procedure error_mapping.ErrorHandling1 as +begin +SET IDENTITY_INSERT t8106 ON +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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: 8106)~~ + +~~ERROR (Message: Table 't8106' does not have the identity property. Cannot perform SET operation.)~~ + +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 +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +DROP TABLE t8106 +GO + + + +set xact_abort ON; +GO +-- Executing test error_mapping.ErrorHandling10000000 +CREATE TABLE t8106(a int) +GO + + + + +create procedure error_mapping.ErrorHandling1 as +begin +SET IDENTITY_INSERT t8106 ON +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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: 8106)~~ + +~~ERROR (Message: Table 't8106' does not have the identity property. Cannot perform SET operation.)~~ + +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 +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +DROP TABLE t8106 +GO + + + + +set xact_abort OFF; +GO + + +-- Error classification is done -- +-- Executing test error_mapping.ErrorHandling10000000 +CREATE TABLE t8106(a int) +GO + + + + +begin try +select 1 +SET IDENTITY_INSERT t8106 ON +end try +begin catch + select xact_state(); +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 +~~START~~ +int +1 +~~END~~ + +~~START~~ +smallint +0 +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling2', because it does not exist or you do not have permission.)~~ + +DROP TABLE t8106 +GO + + + + +GO +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/sql_expected/8107_1.out b/contrib/test/JDBC/sql_expected/8107_1.out new file mode 100644 index 00000000000..f2592c2fba5 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/8107_1.out @@ -0,0 +1,347 @@ +# Executing test ErrorHandling1 +CREATE TABLE t8107_1(a int identity) +GO + +CREATE TABLE t8107_2(a int identity) +GO + +SET IDENTITY_INSERT t8107_1 ON +GO + +INSERT INTO t8107_1(a) VALUES(1) +GO +~~ROW COUNT: 1~~ + + + + + +create procedure ErrorHandling1 as +begin +SET IDENTITY_INSERT t8107_2 ON +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +SET IDENTITY_INSERT t8107_1 OFF +GO + +DROP TABLE t8107_1 +GO + +DROP TABLE t8107_2 +GO + + + +CREATE TABLE t8107_1(a int identity) +GO + +CREATE TABLE t8107_2(a int identity) +GO + +SET IDENTITY_INSERT t8107_1 ON +GO + +INSERT INTO t8107_1(a) VALUES(1) +GO +~~ROW COUNT: 1~~ + + +begin transaction +GO +# Executing test ErrorHandling1 + + +create procedure ErrorHandling1 as +begin +SET IDENTITY_INSERT t8107_2 ON +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +SET IDENTITY_INSERT t8107_1 OFF +GO + +DROP TABLE t8107_1 +GO + +DROP TABLE t8107_2 +GO + + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE t8107_1(a int identity) +GO + +CREATE TABLE t8107_2(a int identity) +GO + +SET IDENTITY_INSERT t8107_1 ON +GO + +INSERT INTO t8107_1(a) VALUES(1) +GO +~~ROW COUNT: 1~~ + + +begin transaction +GO +# Executing test ErrorHandling1 + + +create procedure ErrorHandling1 as +begin +SET IDENTITY_INSERT t8107_2 ON +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +SET IDENTITY_INSERT t8107_1 OFF +GO + +DROP TABLE t8107_1 +GO + +DROP TABLE t8107_2 +GO + +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Next portion is for runtime error -- +CREATE TABLE t8107_1(a int identity) +GO + +CREATE TABLE t8107_2(a int identity) +GO + +SET IDENTITY_INSERT t8107_1 ON +GO + +INSERT INTO t8107_1(a) VALUES(1) +GO +~~ROW COUNT: 1~~ + + + + + +create procedure ErrorHandling1 as +begin +SET IDENTITY_INSERT t8107_2 ON +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 8107)~~ + +~~ERROR (Message: IDENTITY_INSERT is already ON for table 'AdventureWorks2014.dbo.t8107_1'. Cannot perform SET operation for table 't8107_2'.)~~ + +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +SET IDENTITY_INSERT t8107_1 OFF +GO + +DROP TABLE t8107_1 +GO + +DROP TABLE t8107_2 +GO + + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +CREATE TABLE t8107_1(a int identity) +GO + +CREATE TABLE t8107_2(a int identity) +GO + +SET IDENTITY_INSERT t8107_1 ON +GO + +INSERT INTO t8107_1(a) VALUES(1) +GO +~~ROW COUNT: 1~~ + + + + + +create procedure ErrorHandling1 as +begin +SET IDENTITY_INSERT t8107_2 ON +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 8107)~~ + +~~ERROR (Message: IDENTITY_INSERT is already ON for table 'AdventureWorks2014.dbo.t8107_1'. Cannot perform SET operation for table 't8107_2'.)~~ + +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +SET IDENTITY_INSERT t8107_1 OFF +GO + +DROP TABLE t8107_1 +GO + +DROP TABLE t8107_2 +GO + + + + +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Error classification is done -- +CREATE TABLE t8107_1(a int identity) +GO + +CREATE TABLE t8107_2(a int identity) +GO + +SET IDENTITY_INSERT t8107_1 ON +GO + +INSERT INTO t8107_1(a) VALUES(1) +GO +~~ROW COUNT: 1~~ + + + + + +begin try +select 1 +SET IDENTITY_INSERT t8107_2 ON +end try +begin catch + select xact_state(); +end catch +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +int +1 +~~END~~ + +~~START~~ +smallint +0 +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling2', because it does not exist or you do not have permission.)~~ + +SET IDENTITY_INSERT t8107_1 OFF +GO + +DROP TABLE t8107_1 +GO + +DROP TABLE t8107_2 +GO + + + diff --git a/contrib/test/JDBC/sql_expected/8143_1.out b/contrib/test/JDBC/sql_expected/8143_1.out new file mode 100644 index 00000000000..922ce699ee8 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/8143_1.out @@ -0,0 +1,250 @@ +# Executing test ErrorHandling1 + +GO + + + + + +create procedure ErrorHandling1 as +begin +EXEC sp_releaseapplock @Resource = 'SomeResource', @Resource = 'SomeResource' +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO + + + +GO + + +begin transaction +GO +# Executing test ErrorHandling1 + + +create procedure ErrorHandling1 as +begin +EXEC sp_releaseapplock @Resource = 'SomeResource', @Resource = 'SomeResource' +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO + +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO + +GO + + +begin transaction +GO +# Executing test ErrorHandling1 + + +create procedure ErrorHandling1 as +begin +EXEC sp_releaseapplock @Resource = 'SomeResource', @Resource = 'SomeResource' +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO + +GO +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 + +-- Next portion is for runtime error -- +GO + + + + + +create procedure ErrorHandling1 as +begin +EXEC sp_releaseapplock @Resource = 'SomeResource', @Resource = 'SomeResource' +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 8143)~~ + +~~ERROR (Message: Parameter '@Resource' was supplied multiple times.)~~ + +~~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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 + +GO + + + + + +create procedure ErrorHandling1 as +begin +EXEC sp_releaseapplock @Resource = 'SomeResource', @Resource = 'SomeResource' +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 8143)~~ + +~~ERROR (Message: Parameter '@Resource' was supplied multiple times.)~~ + +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + + +GO + + + +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 + +-- Error classification is done -- +GO + + + + + +begin try +select 1 +EXEC sp_releaseapplock @Resource = 'SomeResource', @Resource = 'SomeResource' +end try +begin catch + select xact_state(); +end catch +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +int +1 +~~END~~ + +~~START~~ +smallint +0 +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling2', because it does not exist or you do not have permission.)~~ + + +GO + + diff --git a/contrib/test/JDBC/sql_expected/8143_2.out b/contrib/test/JDBC/sql_expected/8143_2.out new file mode 100644 index 00000000000..c476e50d99a --- /dev/null +++ b/contrib/test/JDBC/sql_expected/8143_2.out @@ -0,0 +1,250 @@ +# Executing test ErrorHandling1 + +GO + + + + + +create procedure ErrorHandling1 as +begin +EXEC sp_getapplock @Resource = 'SomeResource', @Resource = 'SomeResource', @LockMode = 'Shared' +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO + + + +GO + + +begin transaction +GO +# Executing test ErrorHandling1 + + +create procedure ErrorHandling1 as +begin +EXEC sp_getapplock @Resource = 'SomeResource', @Resource = 'SomeResource', @LockMode = 'Shared' +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO + +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO + +GO + + +begin transaction +GO +# Executing test ErrorHandling1 + + +create procedure ErrorHandling1 as +begin +EXEC sp_getapplock @Resource = 'SomeResource', @Resource = 'SomeResource', @LockMode = 'Shared' +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO + +GO +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 + +-- Next portion is for runtime error -- +GO + + + + + +create procedure ErrorHandling1 as +begin +EXEC sp_getapplock @Resource = 'SomeResource', @Resource = 'SomeResource', @LockMode = 'Shared' +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 8143)~~ + +~~ERROR (Message: Parameter '@Resource' was supplied multiple times.)~~ + +~~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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO + +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 + +GO + + + + + +create procedure ErrorHandling1 as +begin +EXEC sp_getapplock @Resource = 'SomeResource', @Resource = 'SomeResource', @LockMode = 'Shared' +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 8143)~~ + +~~ERROR (Message: Parameter '@Resource' was supplied multiple times.)~~ + +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + + +GO + + + +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 + +-- Error classification is done -- +GO + + + + + +begin try +select 1 +EXEC sp_getapplock @Resource = 'SomeResource', @Resource = 'SomeResource', @LockMode = 'Shared' +end try +begin catch + select xact_state(); +end catch +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +int +1 +~~END~~ + +~~START~~ +smallint +0 +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling2', because it does not exist or you do not have permission.)~~ + + +GO + + diff --git a/contrib/test/JDBC/sql_expected/8152_1.out b/contrib/test/JDBC/sql_expected/8152_1.out new file mode 100644 index 00000000000..307bddc9a40 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/8152_1.out @@ -0,0 +1,256 @@ +# Executing test ErrorHandling1 +CREATE TABLE t8152(a CHAR(5)) +GO + + + + +create procedure ErrorHandling1 as +begin +INSERT INTO t8152(a) VALUES('123456') +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t8152 +GO + + + + +CREATE TABLE t8152(a CHAR(5)) +GO + +begin transaction +GO +# Executing test ErrorHandling1 + + +create procedure ErrorHandling1 as +begin +INSERT INTO t8152(a) VALUES('123456') +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +DROP TABLE t8152 +GO + + + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE t8152(a CHAR(5)) +GO + +begin transaction +GO +# Executing test ErrorHandling1 + + +create procedure ErrorHandling1 as +begin +INSERT INTO t8152(a) VALUES('123456') +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +DROP TABLE t8152 +GO + + +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Next portion is for runtime error -- +CREATE TABLE t8152(a CHAR(5)) +GO + + + + +create procedure ErrorHandling1 as +begin +INSERT INTO t8152(a) VALUES('123456') +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 8152)~~ + +~~ERROR (Message: String or binary data would be truncated.)~~ + +~~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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t8152 +GO + + + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +CREATE TABLE t8152(a CHAR(5)) +GO + + + + +create procedure ErrorHandling1 as +begin +INSERT INTO t8152(a) VALUES('123456') +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 8152)~~ + +~~ERROR (Message: String or binary data would be truncated.)~~ + +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +DROP TABLE t8152 +GO + + + + + +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Error classification is done -- +CREATE TABLE t8152(a CHAR(5)) +GO + + + + +begin try +select 1 +INSERT INTO t8152(a) VALUES('123456') +end try +begin catch + select xact_state(); +end catch +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +int +1 +~~END~~ + +~~START~~ +smallint +0 +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + +DROP TABLE t8152 +GO + + + + diff --git a/contrib/test/JDBC/sql_expected/8152_2.out b/contrib/test/JDBC/sql_expected/8152_2.out new file mode 100644 index 00000000000..c046e483a89 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/8152_2.out @@ -0,0 +1,244 @@ +# Executing test ErrorHandling1 +CREATE TABLE t2628(c1 int IDENTITY, c2 varchar(3)) +GO + + + + +create procedure ErrorHandling1 as +begin +INSERT INTO t2628 VALUES('1234') +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t2628 +GO + + +CREATE TABLE t2628(c1 int IDENTITY, c2 varchar(3)) +GO + +begin transaction +GO +# Executing test ErrorHandling1 + + +create procedure ErrorHandling1 as +begin +INSERT INTO t2628 VALUES('1234') +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +DROP TABLE t2628 +GO + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +CREATE TABLE t2628(c1 int IDENTITY, c2 varchar(3)) +GO + +begin transaction +GO +# Executing test ErrorHandling1 + + +create procedure ErrorHandling1 as +begin +INSERT INTO t2628 VALUES('1234') +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 ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +DROP TABLE t2628 +GO +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Next portion is for runtime error -- +CREATE TABLE t2628(c1 int IDENTITY, c2 varchar(3)) +GO + + + + +create procedure ErrorHandling1 as +begin +INSERT INTO t2628 VALUES('1234') +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 8152)~~ + +~~ERROR (Message: String or binary data would be truncated.)~~ + +~~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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +DROP TABLE t2628 +GO + + +set xact_abort ON; +GO +# Executing test ErrorHandling10000000 +CREATE TABLE t2628(c1 int IDENTITY, c2 varchar(3)) +GO + + + + +create procedure ErrorHandling1 as +begin +INSERT INTO t2628 VALUES('1234') +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +GO + +create procedure ErrorHandling2 as +begin +exec ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec ErrorHandling2; +GO +~~ERROR (Code: 8152)~~ + +~~ERROR (Message: String or binary data would be truncated.)~~ + +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 ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +DROP TABLE t2628 +GO + + + +set xact_abort OFF; +GO + +# Executing test ErrorHandling10000000 +-- Error classification is done -- +CREATE TABLE t2628(c1 int IDENTITY, c2 varchar(3)) +GO + + + + +begin try +select 1 +INSERT INTO t2628 VALUES('1234') +end try +begin catch + select xact_state(); +end catch +if @@trancount > 0 rollback transaction; +drop procedure ErrorHandling1; +drop procedure ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~START~~ +int +1 +~~END~~ + +~~START~~ +smallint +0 +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling1', because it does not exist or you do not have permission.)~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'ErrorHandling2', because it does not exist or you do not have permission.)~~ + +DROP TABLE t2628 +GO + + diff --git a/contrib/test/JDBC/sql_expected/8159_1.out b/contrib/test/JDBC/sql_expected/8159_1.out new file mode 100644 index 00000000000..03c66025687 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/8159_1.out @@ -0,0 +1,61 @@ + +-- simple batch start +GO + + +CREATE VIEW v8159(c1, c2) +AS +SELECT + 'a' AS c1 +GO +~~ERROR (Code: 8159)~~ + +~~ERROR (Message: 'v8159' has fewer columns than were specified in the column list.)~~ + +DROP VIEW v8159 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the view 'v8159', because it does not exist or you do not have permission.)~~ + + +SET XACT_ABORT ON; +GO + +begin transaction +GO +GO + + +CREATE VIEW v8159(c1, c2) +AS +SELECT + 'a' AS c1 +GO +~~ERROR (Code: 8159)~~ + +~~ERROR (Message: 'v8159' has fewer columns than were specified in the column list.)~~ + + +if (@@trancount > 0) select cast('Does not respect xact_abort flag' as text) else select cast('Respects xact_abort flag' as text) +GO +~~START~~ +text +Respects xact_abort flag +~~END~~ + + +if (@@trancount > 0) rollback tran +GO + +DROP VIEW v8159 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the view 'v8159', because it does not exist or you do not have permission.)~~ + + +SET XACT_ABORT OFF; +GO + + diff --git a/contrib/test/JDBC/sql_expected/8179_1.out b/contrib/test/JDBC/sql_expected/8179_1.out new file mode 100644 index 00000000000..f46cf0cdaf7 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/8179_1.out @@ -0,0 +1,378 @@ + +-- simple batch start +GO + + +DECLARE @P1 INT = 12345 +EXEC sp_execute @P1, 1 +GO +~~ERROR (Code: 8179)~~ + +~~ERROR (Message: Could not find prepared statement with handle 12345.)~~ + +GO + + +begin transaction +GO +GO + + +DECLARE @P1 INT = 12345 +EXEC sp_execute @P1, 1 +GO +~~ERROR (Code: 8179)~~ + +~~ERROR (Message: Could not find prepared statement with handle 12345.)~~ + + + +-- Below output is only applicable if query is special case. for example, CREATE/ALTER TRIGGER, CREATE/ALTER FUNCTION, CREATE/ALTER PROC, CREATE/ALTER VIEW etc +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 + +GO + + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + +GO + + +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +DECLARE @P1 INT = 12345 +EXEC sp_execute @P1, 1 +end +GO + +GO + + +create table error_mapping.temp2 (a int) +GO + +GO + + +insert into error_mapping.temp2 values(1) +DECLARE @P1 INT = 12345 +EXEC sp_execute @P1, 1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 8179)~~ + +~~ERROR (Message: Could not find prepared statement with handle 12345.)~~ + + +GO + + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + +GO + +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 8179)~~ + +~~ERROR (Message: Could not find prepared statement with handle 12345.)~~ + + +GO + + +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 + +-- Parse analysis phase end +GO + + +-- compile time error portion +-- Executing test error_mapping.ErrorHandling1 +GO + + + + +create procedure error_mapping.ErrorHandling1 as +begin +DECLARE @P1 INT = 12345 +EXEC sp_execute @P1, 1 +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 +GO + + + +GO + +begin transaction +GO + + +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +DECLARE @P1 INT = 12345 +EXEC sp_execute @P1, 1 +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: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +GO + + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +GO + +begin transaction +GO + + +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +DECLARE @P1 INT = 12345 +EXEC sp_execute @P1, 1 +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: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +GO + +set xact_abort OFF; +GO + + +-- comiple time error portion end -- +-- Next portion is for runtime error -- +-- Executing test error_mapping.ErrorHandling10000000 +GO + + + + +create procedure error_mapping.ErrorHandling1 as +begin +DECLARE @P1 INT = 12345 +EXEC sp_execute @P1, 1 +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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: 8179)~~ + +~~ERROR (Message: Could not find prepared statement with handle 12345.)~~ + +~~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 +GO + + + +set xact_abort ON; +GO +-- Executing test error_mapping.ErrorHandling10000000 +GO + + + + +create procedure error_mapping.ErrorHandling1 as +begin +DECLARE @P1 INT = 12345 +EXEC sp_execute @P1, 1 +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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: 8179)~~ + +~~ERROR (Message: Could not find prepared statement with handle 12345.)~~ + +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 +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +GO + + + + +set xact_abort OFF; +GO + + +-- Error classification is done -- +-- Executing test error_mapping.ErrorHandling10000000 +GO + + + + +begin try +select 1 +DECLARE @P1 INT = 12345 +EXEC sp_execute @P1, 1 +end try +begin catch + select xact_state(); +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 +~~START~~ +int +1 +~~END~~ + +~~START~~ +smallint +0 +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling2', because it does not exist or you do not have permission.)~~ + +GO + + + + +GO +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/sql_expected/9809_1.out b/contrib/test/JDBC/sql_expected/9809_1.out new file mode 100644 index 00000000000..2e6f6871e99 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/9809_1.out @@ -0,0 +1,384 @@ + +-- simple batch start +GO + + +SELECT CONVERT(DATE, '10-10-10', 140) +GO +~~START~~ +date +~~ERROR (Code: 9809)~~ + +~~ERROR (Message: The style 140 is not supported for conversions from varchar to date.)~~ + +GO + + +begin transaction +GO +GO + + +SELECT CONVERT(DATE, '10-10-10', 140) +GO +~~START~~ +date +~~ERROR (Code: 9809)~~ + +~~ERROR (Message: The style 140 is not supported for conversions from varchar to date.)~~ + + + +-- Below output is only applicable if query is special case. for example, CREATE/ALTER TRIGGER, CREATE/ALTER FUNCTION, CREATE/ALTER PROC, CREATE/ALTER VIEW etc +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 + +GO + + +-- simple batch end +GO + +create schema error_mapping; +GO +-- Next portion is to check if error is being raised during parse analysis phase +GO + +create table error_mapping.temp1 (a int) +GO + +GO + + +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +SELECT CONVERT(DATE, '10-10-10', 140) +end +GO + +GO + + +create table error_mapping.temp2 (a int) +GO + +GO + + +insert into error_mapping.temp2 values(1) +SELECT CONVERT(DATE, '10-10-10', 140) +GO +~~ROW COUNT: 1~~ + +~~START~~ +date +~~ERROR (Code: 9809)~~ + +~~ERROR (Message: The style 140 is not supported for conversions from varchar to date.)~~ + + +GO + + +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +GO + +create table error_mapping.temp3 (a int) +GO + +GO + +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +date +~~ERROR (Code: 9809)~~ + +~~ERROR (Message: The style 140 is not supported for conversions from varchar to date.)~~ + + +GO + + +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 + +-- Parse analysis phase end +GO + + +-- compile time error portion +-- Executing test error_mapping.ErrorHandling1 +GO + + + + +create procedure error_mapping.ErrorHandling1 as +begin +SELECT CONVERT(DATE, '10-10-10', 140) +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 +GO + + + +GO + +begin transaction +GO + + +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +SELECT CONVERT(DATE, '10-10-10', 140) +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: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +GO + + + +-- Checking xact_abort_flag for compile time error -- +set xact_abort ON; +GO +GO + +begin transaction +GO + + +-- Executing test error_mapping.ErrorHandling1 +create procedure error_mapping.ErrorHandling1 as +begin +SELECT CONVERT(DATE, '10-10-10', 140) +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: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + + +GO +GO + +set xact_abort OFF; +GO + + +-- comiple time error portion end -- +-- Next portion is for runtime error -- +-- Executing test error_mapping.ErrorHandling10000000 +GO + + + + +create procedure error_mapping.ErrorHandling1 as +begin +SELECT CONVERT(DATE, '10-10-10', 140) +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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 +~~START~~ +date +~~ERROR (Code: 9809)~~ + +~~ERROR (Message: The style 140 is not supported for conversions from varchar to date.)~~ + +~~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 +GO + + + +set xact_abort ON; +GO +-- Executing test error_mapping.ErrorHandling10000000 +GO + + + + +create procedure error_mapping.ErrorHandling1 as +begin +SELECT CONVERT(DATE, '10-10-10', 140) +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +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 +~~START~~ +date +~~ERROR (Code: 9809)~~ + +~~ERROR (Message: The style 140 is not supported for conversions from varchar to date.)~~ + +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 +~~START~~ +text +BATCH TERMINATING\ txn rolledback +~~END~~ + +GO + + + + +set xact_abort OFF; +GO + + +-- Error classification is done -- +-- Executing test error_mapping.ErrorHandling10000000 +GO + + + + +begin try +select 1 +SELECT CONVERT(DATE, '10-10-10', 140) +end try +begin catch + select xact_state(); +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 +~~START~~ +int +1 +~~END~~ + +~~START~~ +date +~~END~~ + +~~START~~ +smallint +0 +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling1', because it does not exist or you do not have permission.)~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: Cannot drop the procedure 'error_mapping.ErrorHandling2', because it does not exist or you do not have permission.)~~ + +GO + + + + +GO +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/sql_expected/BABEL-1243.out b/contrib/test/JDBC/sql_expected/BABEL-1243.out new file mode 100644 index 00000000000..1bf33500d9d --- /dev/null +++ b/contrib/test/JDBC/sql_expected/BABEL-1243.out @@ -0,0 +1,33 @@ +CREATE TABLE employeeData( + ID INT IDENTITY (1,1) PRIMARY KEY,Emp_First_name VARCHAR (50),Emp_Last_name VARCHAR (50),Emp_Salary INT) +GO + +CREATE TRIGGER updEmployeeDatas ON employeeData AFTER UPDATE,INSERT AS + select * from inserted; +GO + +insert into employeeData values ('a','b',234); +GO +~~START~~ +int#!#varchar#!#varchar#!#int +1#!#a#!#b#!#234 +~~END~~ + +~~ROW COUNT: 1~~ + + +update employeeData set Emp_Last_name = 'ccc' where id = 1; +GO +~~START~~ +int#!#varchar#!#varchar#!#int +1#!#a#!#ccc#!#234 +~~END~~ + +~~ROW COUNT: 1~~ + + +drop trigger updEmployeeDatas +GO + +drop table employeeData +GO diff --git a/contrib/test/JDBC/sql_expected/BABEL-1944.out b/contrib/test/JDBC/sql_expected/BABEL-1944.out new file mode 100644 index 00000000000..dfd9363ecf1 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/BABEL-1944.out @@ -0,0 +1,312 @@ +create table t1(a int); +go +create table t2(a int); +go +create procedure sp_trancount as +select @@trancount; +GO +create procedure sp_commit_no_begin as +insert into t1 values(3); +commit; +select * from t1; +GO +create procedure sp_rollback_no_begin as +insert into t1 values(4); +rollback; +select * from t1; +GO +create procedure sp_rollback_with_begin as +begin tran; +insert into t1 values(4); +rollback; +select * from t1; +go + +select @@trancount; +go +~~START~~ +int +0 +~~END~~ + +-- trancount inside normal EXEC should be same as outside +exec sp_trancount; +go +~~START~~ +int +0 +~~END~~ + +-- trancount inside INSERT-EXEC should be 1 more than outside +insert into t1 exec sp_trancount; +go +~~ROW COUNT: 1~~ + +select * from t1; +go +~~START~~ +int +1 +~~END~~ + +delete t1; +go +~~ROW COUNT: 1~~ + + +-- zero level - normal EXEC should succeed with warning for no BEGIN TRAN on the +-- COMMIT +exec sp_commit_no_begin; +go +~~ROW COUNT: 1~~ + +~~ERROR (Code: 3902)~~ + +~~ERROR (Message: COMMIT can only be used in transaction blocks)~~ + +~~START~~ +int +3 +~~END~~ + +-- zero level - INSERT-EXEC should fail with error message about the COMMIT +-- inside INSERT-EXEC must have a BEGIN TRAN +delete t1; +go +~~ROW COUNT: 1~~ + +insert into t2 exec sp_commit_no_begin; +go +~~ERROR (Code: 4)~~ + +~~ERROR (Message: Cannot use the COMMIT statement within an INSERT-EXEC statement unless BEGIN TRANSACTION is used first.)~~ + +select count(*) from t1; +select count(*) from t2; +go +~~START~~ +int +0 +~~END~~ + +~~START~~ +int +0 +~~END~~ + + +-- one level - should fail and abort that level of transaction +begin tran; +go +select @@trancount; +go +~~START~~ +int +1 +~~END~~ + +insert into t2 execute sp_commit_no_begin; +go +~~ERROR (Code: 4)~~ + +~~ERROR (Message: Cannot use the COMMIT statement within an INSERT-EXEC statement unless BEGIN TRANSACTION is used first.)~~ + +select @@trancount; +go +~~START~~ +int +0 +~~END~~ + +select count(*) from t1; +select count(*) from t2; +go +~~START~~ +int +0 +~~END~~ + +~~START~~ +int +0 +~~END~~ + + +-- previous level aborted, this should be the same as before +begin tran; +go +select @@trancount; +go +~~START~~ +int +1 +~~END~~ + +insert into t2 execute sp_commit_no_begin; +go +~~ERROR (Code: 4)~~ + +~~ERROR (Message: Cannot use the COMMIT statement within an INSERT-EXEC statement unless BEGIN TRANSACTION is used first.)~~ + +select count(*) from t1; +select count(*) from t2; +go +~~START~~ +int +0 +~~END~~ + +~~START~~ +int +0 +~~END~~ + + +-- normal EXEC with COMMIT is allowed with one level - should succeed with +-- unbalanced level warning from 1 to 0 +begin tran; +go +select @@trancount; +go +~~START~~ +int +1 +~~END~~ + +execute sp_commit_no_begin; +go +~~ROW COUNT: 1~~ + +~~START~~ +int +3 +~~END~~ + +~~ERROR (Code: 33554436)~~ + +~~ERROR (Message: Transaction count after execution indicates a mismatch number of BEGIN and COMMIT statements. Previous count 1 current count 0)~~ + +select count(*) from t1; +select count(*) from t2; +go +~~START~~ +int +1 +~~END~~ + +~~START~~ +int +0 +~~END~~ + + +-- two levels - should succeed with unbalanced level warning from 2 to 1, and +-- should not send any Row tokens +select @@trancount; +go +~~START~~ +int +0 +~~END~~ + +begin tran; +go +begin tran; +go +select @@trancount; +go +~~START~~ +int +2 +~~END~~ + +insert into t2 execute sp_commit_no_begin; +go +~~ERROR (Code: 33554436)~~ + +~~ERROR (Message: Transaction count after execution indicates a mismatch number of BEGIN and COMMIT statements. Previous count 2 current count 1)~~ + +select count(*) from t1; +select count(*) from t2; +go +~~START~~ +int +2 +~~END~~ + +~~START~~ +int +2 +~~END~~ + +select @@trancount; +go +~~START~~ +int +1 +~~END~~ + +commit; +go + +-- INSERT-EXEC with ROLLBACK in one level of transaction - should fail and abort +-- that level of transaction +begin tran; +go +select @@trancount; +go +~~START~~ +int +1 +~~END~~ + +insert into t2 exec sp_rollback_no_begin; +go +~~ERROR (Code: 4)~~ + +~~ERROR (Message: Cannot use the ROLLBACK statement within an INSERT-EXEC statement.)~~ + +select @@trancount; +go +~~START~~ +int +0 +~~END~~ + + +begin tran; +go +select @@trancount; +go +~~START~~ +int +1 +~~END~~ + +insert into t2 exec sp_rollback_with_begin; +go +~~ERROR (Code: 4)~~ + +~~ERROR (Message: Cannot use the ROLLBACK statement within an INSERT-EXEC statement.)~~ + +select @@trancount; +go +~~START~~ +int +0 +~~END~~ + + +-- cleanup +drop table t1; +go +drop table t2; +go +drop procedure sp_trancount; +go +drop procedure sp_commit_no_begin; +go +drop procedure sp_rollback_no_begin; +go +drop procedure sp_rollback_with_begin; +go diff --git a/contrib/test/JDBC/sql_expected/BABEL-2079.out b/contrib/test/JDBC/sql_expected/BABEL-2079.out new file mode 100644 index 00000000000..7d731c3145f --- /dev/null +++ b/contrib/test/JDBC/sql_expected/BABEL-2079.out @@ -0,0 +1,50 @@ +create schema error_mapping; +GO + +CREATE TABLE t3616(id int); +GO +CREATE TRIGGER t3616Trigger +ON t3616 +AFTER INSERT +AS +BEGIN + BEGIN TRY + BEGIN TRAN + INSERT INTO t3616 VALUES (2) + COMMIT TRAN + END TRY + BEGIN CATCH + END CATCH +END +GO + +create procedure error_mapping.ErrorHandling1 as +begin +INSERT INTO t3616 values (1) +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +end +GO + +SET NOCOUNT ON +GO + +exec error_mapping.ErrorHandling1; +GO + +select * from t3616; +GO +~~START~~ +int +1 +2 +~~END~~ + + +drop table t3616; +GO + +drop procedure error_mapping.ErrorHandling1; +GO + +drop schema error_mapping; +GO diff --git a/contrib/test/JDBC/sql_expected/BABEL-2354.out b/contrib/test/JDBC/sql_expected/BABEL-2354.out new file mode 100644 index 00000000000..0935a7889bd --- /dev/null +++ b/contrib/test/JDBC/sql_expected/BABEL-2354.out @@ -0,0 +1,23 @@ +CREATE TABLE employeeData( ID INT IDENTITY (1,1) PRIMARY KEY,Emp_First_name VARCHAR (50),Emp_Last_name VARCHAR (50),Emp_Salary INT) +GO + +CREATE TRIGGER updEmployeeData ON employeeData AFTER UPDATE AS + IF (COLUMNS_UPDATED() & 14) > 0 + BEGIN + PRINT 'Columns 3, 5 and 9 updated'; + END; +GO +~~ERROR (Code: 1088)~~ + +~~ERROR (Message: 'COLUMNS_UPDATED FUNC IN TRIGGER' is not currently supported in Babelfish)~~ + + +drop trigger updEmployeeData +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: trigger "updemployeedata" does not exist)~~ + + +drop table employeeData +GO diff --git a/contrib/test/JDBC/sql_expected/BABEL-2419.out b/contrib/test/JDBC/sql_expected/BABEL-2419.out new file mode 100644 index 00000000000..07d2e8b94fa --- /dev/null +++ b/contrib/test/JDBC/sql_expected/BABEL-2419.out @@ -0,0 +1,37 @@ + +create table t_2419 (a varchar(10)); +insert into t_2419 values ('correct'); +select a 'alias_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij' +from t_2419 +order by alias_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij +go +~~ROW COUNT: 1~~ + +~~START~~ +varchar +correct +~~END~~ + + +select a 'alias_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij' +from t_2419 +order by [alias_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij] +go +~~START~~ +varchar +correct +~~END~~ + + +select a 'alias_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij' +from t_2419 +order by [ALIAS_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij] +go +~~START~~ +varchar +correct +~~END~~ + + +drop table t_2419; +go diff --git a/contrib/test/JDBC/sql_expected/BABEL-2432.out b/contrib/test/JDBC/sql_expected/BABEL-2432.out new file mode 100644 index 00000000000..49197a0abbd --- /dev/null +++ b/contrib/test/JDBC/sql_expected/BABEL-2432.out @@ -0,0 +1,51 @@ +-- mixed-case column name. select via lowercase name +create table t2432 ([COL_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij] int); +insert into t2432 values (1); +GO +~~ROW COUNT: 1~~ + + +select [col_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij] from t2432; +GO +~~START~~ +int +1 +~~END~~ + + +select col_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij from t2432; +GO +~~START~~ +int +1 +~~END~~ + + +drop table t2432; +GO + +-- lowercase column name. select via mixed-case name +create table t2432_2 ([col_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij] int); +insert into t2432_2 values (1); +GO +~~ROW COUNT: 1~~ + + +select [COL_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij] from t2432_2; +GO +~~START~~ +int +1 +~~END~~ + + +select COL_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij from t2432_2; +GO +~~START~~ +int +1 +~~END~~ + + +drop table t2432_2; +GO diff --git a/contrib/test/JDBC/sql_expected/BABEL-2437.out b/contrib/test/JDBC/sql_expected/BABEL-2437.out new file mode 100644 index 00000000000..454980175f4 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/BABEL-2437.out @@ -0,0 +1,16 @@ +use master; +go + +create schema babel_2437_schema; +go + +create table babel_2437_schema.t1 (a int primary key); +go + +create table babel_2437_schema.t2 (b int, FOREIGN KEY (b) REFERENCES babel_2437_schema.t1 (a) ON DELETE CASCADE ON UPDATE CASCADE); +go + +drop table if exists babel_2437_schema.t2; +drop table if exists babel_2437_schema.t1; +drop schema babel_2437_schema; +go diff --git a/contrib/test/JDBC/sql_expected/BABEL-2681.out b/contrib/test/JDBC/sql_expected/BABEL-2681.out new file mode 100644 index 00000000000..02d1fbb58a1 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/BABEL-2681.out @@ -0,0 +1,29 @@ +USE master +go + +select cast(SERVERPROPERTY('ProductVersion') as varchar) as ProductVersion; +select cast(SERVERPROPERTY('ProductMajorVersion') as varchar) as ProductMajorVersion; +-- only print till the server version i.e. first newline character +select substring(@@version, 1, CHARINDEX(CHAR(10), @@version) - 1); +select @@microsoftversion; +go +~~START~~ +varchar +12.0.2000.8 +~~END~~ + +~~START~~ +varchar +12 +~~END~~ + +~~START~~ +nvarchar +Babelfish for PostgreSQL with SQL Server Compatibility - 12.0.2000.8 +~~END~~ + +~~START~~ +int +201332885 +~~END~~ + diff --git a/contrib/test/JDBC/sql_expected/BABEL-EXTENDEDPROPERTY.out b/contrib/test/JDBC/sql_expected/BABEL-EXTENDEDPROPERTY.out new file mode 100644 index 00000000000..c68de5857ac --- /dev/null +++ b/contrib/test/JDBC/sql_expected/BABEL-EXTENDEDPROPERTY.out @@ -0,0 +1,29 @@ +create table t1 (a int) +go + +-- For now, will always return empty result set because sys.extended_properties +-- is always empty before the support of sp_[add/drop/update]extendedproperty (BABEL-280) +select * FROM fn_listextendedproperty('COLUMN', 'schema', N'dbo', 'table', N't1', 'column', N'a'); +go +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +~~END~~ + + +select * FROM fn_listextendedproperty(NULL, 'schema', N'dbo', 'table', N't1', NULL, NULL); +go +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +~~END~~ + + +-- Failed query in BABEL-1784 +exec [sys].sp_columns_100 N't23',N'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#!#tinyint +~~END~~ + + +drop table t1 +go diff --git a/contrib/test/JDBC/sql_expected/BABEL-IDENTITY.out b/contrib/test/JDBC/sql_expected/BABEL-IDENTITY.out new file mode 100644 index 00000000000..cea0a23895d --- /dev/null +++ b/contrib/test/JDBC/sql_expected/BABEL-IDENTITY.out @@ -0,0 +1,458 @@ +USE MASTER; +GO + +CREATE TABLE dbo.test_table1 (test_id INT IDENTITY, test_col1 INT); +go + +CREATE PROCEDURE insert_test_table1 + @id INT, + @val INT +AS + INSERT INTO dbo.test_table1 (test_id, test_col1) VALUES (@id, @val); +go + +SELECT @@IDENTITY; +go +~~START~~ +numeric + +~~END~~ + +SELECT SCOPE_IDENTITY(); +go +~~START~~ +numeric + +~~END~~ + +INSERT INTO dbo.test_table1 (test_col1) VALUES (10); +go +~~ROW COUNT: 1~~ + +SELECT @@IDENTITY; +go +~~START~~ +numeric +1 +~~END~~ + +SELECT SCOPE_IDENTITY(); +go +~~START~~ +numeric +1 +~~END~~ + +SELECT @@SERVERNAME; +go +~~START~~ +nvarchar +BABELFISH +~~END~~ + +-- Expect an error +INSERT INTO dbo.test_table1 (test_id, test_col1) VALUES (2, 10); +go +~~ERROR (Code: 156008580)~~ + +~~ERROR (Message: cannot insert into column "test_id")~~ + + +SET IDENTITY_INSERT dbo.test_table1 ON; +go + +-- Test custom insert +EXECUTE insert_test_table1 2, 10; +go +~~ROW COUNT: 1~~ + + +-- Insert a non-sequential max identity value +EXECUTE insert_test_table1 10, 10; +go +~~ROW COUNT: 1~~ + + +-- Insert a lesser identity value +EXECUTE insert_test_table1 5, 10; +go +~~ROW COUNT: 1~~ + + +-- Set to off. Notice we're not specifying the schema this time +SET IDENTITY_INSERT test_table1 OFF; +go + +-- Verify the identity sequence value is updated to the max value +INSERT INTO dbo.test_table1 (test_col1) VALUES (11); +go +~~ROW COUNT: 1~~ + +INSERT INTO dbo.test_table1 (test_col1) VALUES (12); +go +~~ROW COUNT: 1~~ + + +SELECT * FROM dbo.test_table1; +go +~~START~~ +int#!#int +1#!#10 +2#!#10 +10#!#10 +5#!#10 +11#!#11 +12#!#12 +~~END~~ + + +-- Expect an error. Verify IDENTITY_INSERT set off +INSERT INTO dbo.test_table1 (test_id, test_col1) VALUES (2, 10); +go +~~ERROR (Code: 156008580)~~ + +~~ERROR (Message: cannot insert into column "test_id")~~ + + +-- Set to table then drop it. Should implicitly turn IDENTITY_INSERT off +SET IDENTITY_INSERT dbo.test_table1 ON; +go +DROP TABLE test_table1; +go + +-- Create a table with the same name +CREATE TABLE dbo.test_table1 (test_id INT IDENTITY, test_col1 INT); +go + +-- Try to insert. Expect an error. Same name but different OID +INSERT INTO dbo.test_table1 (test_id, test_col1) VALUES (2, 10); +go +~~ERROR (Code: 156008580)~~ + +~~ERROR (Message: cannot insert into column "test_id")~~ + + +-- Expect errors +SET IDENTITY_INSERT test_table2 ON; +go +~~ERROR (Code: 208)~~ + +~~ERROR (Message: relation "test_table2" does not exist)~~ + +SET IDENTITY_INSERT fake_schema.test_table1 ON; +go +~~ERROR (Code: 1411)~~ + +~~ERROR (Message: schema "fake_schema" does not exist)~~ + +SET IDENTITY_INSERT fake_db.dbo.test_table1 ON; +go +~~ERROR (Code: 1088)~~ + +~~ERROR (Message: cross-database references are not implemented: "fake_db.dbo.test_table1")~~ + + +CREATE TABLE dbo.test_table2 (test_id INT IDENTITY(7,2), test_col1 INT); +go + +-- Expect error. Set IDENTITY_INSERT to a table then try setting it to another +SET IDENTITY_INSERT dbo.test_table1 ON; +go +SET IDENTITY_INSERT dbo.test_table2 ON; +go +~~ERROR (Code: 16777410)~~ + +~~ERROR (Message: IDENTITY_INSERT is already ON for table 'jdbc_testdb.dbo.test_table1')~~ + +SET IDENTITY_INSERT dbo.test_table1 OFF; +go +INSERT INTO dbo.test_table2 (test_col1) VALUES (13); +go +~~ROW COUNT: 1~~ + +INSERT INTO dbo.test_table2 (test_col1) VALUES (108); +go +~~ROW COUNT: 1~~ + +SELECT @@IDENTITY; +go +~~START~~ +numeric +9 +~~END~~ + +SELECT SCOPE_IDENTITY(); +go +~~START~~ +numeric +9 +~~END~~ + + +SELECT * FROM dbo.test_table2; +go +~~START~~ +int#!#int +7#!#13 +9#!#108 +~~END~~ + + +-- Expect error. Cannot set IDENTITY_INSERT to table without identity property +CREATE TABLE dbo.test_table3 (test_id INT, test_col1 INT); +go + +SET IDENTITY_INSERT dbo.test_table3 ON; +go +~~ERROR (Code: 50360452)~~ + +~~ERROR (Message: Table 'dbo.test_table3' does not have the identity property. Cannot perform SET operation.)~~ + + +-- Test INSERT with default target list that omits identity columns +CREATE TABLE dbo.employees +(person_id int IDENTITY PRIMARY KEY, firstname nvarchar(20), lastname nvarchar(30), salary money); +go + +INSERT INTO employees VALUES (N'Neil', N'Armstrong', 11236.9898); +go +~~ROW COUNT: 1~~ + + +SELECT * FROM dbo.employees; +go +~~START~~ +int#!#nvarchar#!#nvarchar#!#money +1#!#Neil#!#Armstrong#!#11236.9898 +~~END~~ + + +-- Test identity insert with multiple columns +SET IDENTITY_INSERT dbo.employees ON; +go + +CREATE PROCEDURE insert_employees + @id INT, + @first TEXT, + @last TEXT, + @salary NUMERIC(18,4) +AS + INSERT INTO dbo.employees (person_id, firstname, lastname, salary) VALUES (@id, @first, @last, @salary); +go + +EXEC insert_employees 5, N'Buzz', N'Aldrin', 11236.9898; +go +~~ROW COUNT: 1~~ + + +SELECT @@IDENTITY; +go +~~START~~ +numeric +5 +~~END~~ + + +-- Expect Errors. Cannot insert without explicit identity column value +INSERT INTO employees VALUES (N'Michael', N'Collins', 11236.9898); +go +~~ERROR (Code: 50360452)~~ + +~~ERROR (Message: Explicit value must be specified for identity column in table 'employees' when IDENTITY_INSERT is set to ON)~~ + + +INSERT INTO employees (firstname, lastname, salary) VALUES (N'Michael', N'Collins', 11236.9898); +go +~~ERROR (Code: 50360452)~~ + +~~ERROR (Message: Explicit value must be specified for identity column in table 'employees' when IDENTITY_INSERT is set to ON)~~ + + +SET IDENTITY_INSERT dbo.employees OFF; +go + +INSERT INTO employees VALUES (N'Michael', N'Collins', 11236.9898); +go +~~ROW COUNT: 1~~ + + +SELECT * FROM dbo.employees; +go +~~START~~ +int#!#nvarchar#!#nvarchar#!#money +1#!#Neil#!#Armstrong#!#11236.9898 +5#!#Buzz#!#Aldrin#!#11236.9898 +6#!#Michael#!#Collins#!#11236.9898 +~~END~~ + + +-- Test Camel Case +CREATE TABLE [dbo].[Test_Table1]([Test_Id] INT IDENTITY, test_col1 INT); +go +~~ERROR (Code: 2714)~~ + +~~ERROR (Message: relation "test_table1" already exists)~~ + + +SET IDENTITY_INSERT [Test_Table1] ON; +go + +CREATE PROCEDURE insert_test_table_c + @id INT, + @val INT +AS + INSERT INTO [dbo].[Test_Table1] ([Test_Id], test_col1) VALUES (@id, @val); +go + +CREATE PROCEDURE insert_test_table_c_default + @val INT +AS + INSERT INTO [dbo].[Test_Table1] (test_col1) VALUES (@val); +go + +EXEC insert_test_table_c 1, 10; +go +~~ROW COUNT: 1~~ + + +EXEC insert_test_table_c 5, 20; +go +~~ROW COUNT: 1~~ + + +-- Expect error. Insert restriction +EXEC insert_test_table_c_default 30; +go +~~ERROR (Code: 50360452)~~ + +~~ERROR (Message: Explicit value must be specified for identity column in table 'test_table1' when IDENTITY_INSERT is set to ON)~~ + +-- Expect errors. Not matching case +SET IDENTITY_INSERT Test_Table1 ON; +go +SET IDENTITY_INSERT [tEst_tAble1] ON; +go +SET IDENTITY_INSERT [dbo].[Test_Table1] ON; +go +INSERT INTO [dbo].[Test_Table1] (test_id, test_col1) VALUES (10, 30); +go +~~ROW COUNT: 1~~ + + +-- Set to off and verify table +SET IDENTITY_INSERT [dbo].[Test_Table1] OFF; +go + +EXEC insert_test_table_c_default 30; +go +~~ROW COUNT: 1~~ + + +SELECT * FROM [Test_Table1]; +go +~~START~~ +int#!#int +1#!#10 +5#!#20 +10#!#30 +11#!#30 +~~END~~ + + +-- Test updating negative increment +CREATE TABLE dbo.t_neg_inc_1(id INT IDENTITY(1, -1), col1 INT); +go + +CREATE PROCEDURE insert_default_neg_inc_1 + @val INT +AS BEGIN + INSERT INTO dbo.t_neg_inc_1(col1) VALUES (@val); +END; +go + +CREATE PROCEDURE insert_id_neg_inc_1 + @id INT, + @val INT +AS BEGIN + SET IDENTITY_INSERT t_neg_inc_1 ON; + INSERT INTO dbo.t_neg_inc_1(id, col1) VALUES (@id, @val); + SET IDENTITY_INSERT t_neg_inc_1 OFF; +END; +go + +EXEC insert_default_neg_inc_1 10; +go +~~ROW COUNT: 1~~ + + +EXEC insert_default_neg_inc_1 20; +go +~~ROW COUNT: 1~~ + + +EXEC insert_id_neg_inc_1 -5, 30; +go +~~ROW COUNT: 1~~ + + +EXEC insert_default_neg_inc_1 40; +go +~~ROW COUNT: 1~~ + + +EXEC insert_id_neg_inc_1 5, 50; +go +~~ROW COUNT: 1~~ + + +EXEC insert_default_neg_inc_1 60; +go +~~ROW COUNT: 1~~ + + +SELECT * FROM t_neg_inc_1; +go +~~START~~ +int#!#int +1#!#10 +0#!#20 +-5#!#30 +-6#!#40 +5#!#50 +-7#!#60 +~~END~~ + + +-- Test get id max/min helper functions +SELECT sys.get_min_id_from_table(';drop table master_dbo.test_table1;', 'master_dbo', 'test_table1'); +GO +~~START~~ +bigint +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column ";drop table master_dbo.test_table1;" does not exist)~~ + + +SELECT sys.get_max_id_from_table('test_id', ';drop table master_dbo', 'test_table1;'); +GO +~~START~~ +bigint +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation ";drop table master_dbo.test_table1;" does not exist)~~ + + +-- Clean up +DROP PROCEDURE insert_test_table1, +insert_employees, +insert_test_table_c, +insert_test_table_c_default, +insert_default_neg_inc_1, +insert_id_neg_inc_1; +go +DROP TABLE dbo.test_table1, +dbo.test_table2, +dbo.test_table3, +dbo.employees, +dbo.t_neg_inc_1; +go diff --git a/contrib/test/JDBC/sql_expected/BABEL-IMPLICIT_TRAN-PREPEXEC.out b/contrib/test/JDBC/sql_expected/BABEL-IMPLICIT_TRAN-PREPEXEC.out new file mode 100644 index 00000000000..b9d3b095199 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/BABEL-IMPLICIT_TRAN-PREPEXEC.out @@ -0,0 +1,128 @@ +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_unique_constraint', 'ignore'; +CREATE TABLE impl_txn_prepexec_table (a varchar(15) UNIQUE, b nvarchar(25), c int PRIMARY KEY, d char(15) DEFAULT 'Whoops!', e nchar(25), f datetime, g numeric(4,1) CHECK (g >= 103.5)) + +prepst#!#INSERT INTO impl_txn_prepexec_table VALUES (?, ?, ?, ?, ?, ?, ?)#!#varchar|-|a|-|Apple#!#nvarchar|-|b|-|red#!#int|-|c|-|1#!#char|-|d|-|Delhi#!#nchar|-|e|-|Sad😞#!#datetime|-|f|-|2000-12-13 12:58:23.123#!#numeric|-|g|-|123.1|-|4|-|1 +~~ROW COUNT: 1~~ + + +SET IMPLICIT_TRANSACTIONS ON + +SELECT @@TRANCOUNT +~~START~~ +int +0 +~~END~~ + +prepst#!#SELECT * FROM impl_txn_prepexec_table WHERE a = ? AND b = ? AND c = ?#!#varchar|-|p1|-|Apple#!#nvarchar|-|p2|-|red#!#int|-|p3|-|1 +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +SELECT @@TRANCOUNT +~~START~~ +int +1 +~~END~~ + +IF @@TRANCOUNT > 0 COMMIT + +SELECT @@TRANCOUNT +~~START~~ +int +0 +~~END~~ + +prepst#!#exec#!#varchar|-|p1|-|Apple#!#nvarchar|-|p2|-|red#!#int|-|p3|-|2 +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +SELECT @@TRANCOUNT +~~START~~ +int +1 +~~END~~ + +IF @@TRANCOUNT > 0 COMMIT + +SELECT @@TRANCOUNT +~~START~~ +int +0 +~~END~~ + +prepst#!#exec#!#varchar|-|p1|-|Apple#!#nvarchar|-|p2|-|green#!#int|-|p3|-|1 +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +SELECT @@TRANCOUNT +~~START~~ +int +1 +~~END~~ + +IF @@TRANCOUNT > 0 COMMIT + +SELECT @@TRANCOUNT +~~START~~ +int +0 +~~END~~ + +prepst#!#SELECT 12, 34, 56 FROM (SELECT * FROM impl_txn_prepexec_table WHERE a = ? AND b = ? AND c = ?) AS dummy_table#!#varchar|-|p1|-|Apple#!#nvarchar|-|p2|-|red#!#int|-|p3|-|1 +~~START~~ +int#!#int#!#int +12#!#34#!#56 +~~END~~ + +SELECT @@TRANCOUNT +~~START~~ +int +1 +~~END~~ + +IF @@TRANCOUNT > 0 COMMIT + +SELECT @@TRANCOUNT +~~START~~ +int +0 +~~END~~ + +prepst#!#exec#!#varchar|-|p1|-|Apple#!#nvarchar|-|p2|-|red#!#int|-|p3|-|2 +~~START~~ +int#!#int#!#int +~~END~~ + +SELECT @@TRANCOUNT +~~START~~ +int +1 +~~END~~ + +IF @@TRANCOUNT > 0 COMMIT + +SELECT @@TRANCOUNT +~~START~~ +int +0 +~~END~~ + +prepst#!#exec#!#varchar|-|p1|-|Apple#!#nvarchar|-|p2|-|green#!#int|-|p3|-|1 +~~START~~ +int#!#int#!#int +~~END~~ + +SELECT @@TRANCOUNT +~~START~~ +int +1 +~~END~~ + +IF @@TRANCOUNT > 0 COMMIT + +SET IMPLICIT_TRANSACTIONS OFF +DROP TABLE impl_txn_prepexec_table +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_unique_constraint', 'strict'; diff --git a/contrib/test/JDBC/sql_expected/BABEL-IMPLICIT_TRAN.out b/contrib/test/JDBC/sql_expected/BABEL-IMPLICIT_TRAN.out new file mode 100644 index 00000000000..6e2551bfab0 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/BABEL-IMPLICIT_TRAN.out @@ -0,0 +1,564 @@ +-- Setup +CREATE TABLE implicit_tran_table (a int) +GO + +INSERT INTO implicit_tran_table VALUES (10) +GO +~~ROW COUNT: 1~~ + + +SET IMPLICIT_TRANSACTIONS ON +GO + +-- Select from table should start implicit transaction +SELECT @@TRANCOUNT +SELECT * FROM implicit_tran_table +SELECT @@TRANCOUNT +IF @@TRANCOUNT > 0 COMMIT +GO +~~START~~ +int +0 +~~END~~ + +~~START~~ +int +10 +~~END~~ + +~~START~~ +int +1 +~~END~~ + + +SELECT @@TRANCOUNT +DECLARE @implicit_tran_table_var int +SELECT @implicit_tran_table_var = a FROM implicit_tran_table +SELECT @@TRANCOUNT +IF @@TRANCOUNT > 0 COMMIT +GO +~~START~~ +int +0 +~~END~~ + +~~START~~ +int +1 +~~END~~ + + +-- Select from table variable should start implicit transaction +SELECT @@TRANCOUNT +DECLARE @implicit_tran_table_var TABLE (col1 VARCHAR(10)); +SELECT * FROM @implicit_tran_table_var +SELECT @@TRANCOUNT +IF @@TRANCOUNT > 0 COMMIT +GO +~~START~~ +int +0 +~~END~~ + +~~START~~ +varchar +~~END~~ + +~~START~~ +int +1 +~~END~~ + + +-- Select not from a table should not start implicit transaction +SELECT @@TRANCOUNT +SELECT 123 +SELECT @@TRANCOUNT +IF @@TRANCOUNT > 0 COMMIT +GO +~~START~~ +int +0 +~~END~~ + +~~START~~ +int +123 +~~END~~ + +~~START~~ +int +0 +~~END~~ + + +SELECT @@TRANCOUNT +DECLARE @implicit_tran_table_var int +SELECT @implicit_tran_table_var = 1234 +SELECT @@TRANCOUNT +IF @@TRANCOUNT > 0 COMMIT +GO +~~START~~ +int +0 +~~END~~ + +~~START~~ +int +0 +~~END~~ + + +-- BABEL-1869 +-- 2-Column select should not start implicit transaction +SELECT @@TRANCOUNT +SELECT 1, 2 +SELECT @@TRANCOUNT +IF @@TRANCOUNT > 0 COMMIT +GO +~~START~~ +int +0 +~~END~~ + +~~START~~ +int#!#int +1#!#2 +~~END~~ + +~~START~~ +int +0 +~~END~~ + + +SELECT @@TRANCOUNT +SELECT 1, 2, 3 +SELECT @@TRANCOUNT +IF @@TRANCOUNT > 0 COMMIT +GO +~~START~~ +int +0 +~~END~~ + +~~START~~ +int#!#int#!#int +1#!#2#!#3 +~~END~~ + +~~START~~ +int +0 +~~END~~ + + +-- Select from table in subquery should start implicit transaction +SELECT @@TRANCOUNT +SELECT (select count(*) from implicit_tran_table) +SELECT @@TRANCOUNT +IF @@TRANCOUNT > 0 COMMIT +GO +~~START~~ +int +0 +~~END~~ + +~~START~~ +int +1 +~~END~~ + +~~START~~ +int +1 +~~END~~ + + +SELECT @@TRANCOUNT +SELECT 1, 2 FROM (SELECT * FROM implicit_tran_table) as dummy_table +SELECT @@TRANCOUNT +IF @@TRANCOUNT > 0 COMMIT +GO +~~START~~ +int +0 +~~END~~ + +~~START~~ +int#!#int +1#!#2 +~~END~~ + +~~START~~ +int +1 +~~END~~ + + +-- Select to call a function should not start implicit transaction +SELECT @@TRANCOUNT +SELECT @@ERROR +SELECT @@TRANCOUNT +IF @@TRANCOUNT > 0 COMMIT +GO +~~START~~ +int +0 +~~END~~ + +~~START~~ +int +0 +~~END~~ + +~~START~~ +int +0 +~~END~~ + + +/* + * DMLs should start implicit transaction + * Note: Did not add test for MERGE since + * we do not support it (BABEL-877) + */ +SELECT @@TRANCOUNT +INSERT INTO implicit_tran_table VALUES (11) +SELECT @@TRANCOUNT +IF @@TRANCOUNT > 0 COMMIT +GO +~~START~~ +int +0 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +1 +~~END~~ + + +SELECT @@TRANCOUNT +UPDATE implicit_tran_table SET a = 100 WHERE a = 10 +SELECT @@TRANCOUNT +IF @@TRANCOUNT > 0 COMMIT +GO +~~START~~ +int +0 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +1 +~~END~~ + + +SELECT @@TRANCOUNT +DELETE FROM implicit_tran_table WHERE a = 100 +SELECT @@TRANCOUNT +IF @@TRANCOUNT > 0 COMMIT +GO +~~START~~ +int +0 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +1 +~~END~~ + + +-- Create table should start implicit transaction +SELECT @@TRANCOUNT +CREATE TABLE implicit_tran_table2 (c smallint) +SELECT @@TRANCOUNT +IF @@TRANCOUNT > 0 COMMIT +GO +~~START~~ +int +0 +~~END~~ + +~~START~~ +int +1 +~~END~~ + + +-- BABEL-1870 +-- SELECT ... INTO should start implicit transaction +-- Note: We internally convert this to CREATE TABLE AS +SELECT @@TRANCOUNT +SELECT * INTO dummy_table FROM implicit_tran_table2 +SELECT @@TRANCOUNT +DROP TABLE dummy_table +IF @@TRANCOUNT > 0 COMMIT +GO +~~START~~ +int +0 +~~END~~ + +~~START~~ +int +1 +~~END~~ + + +-- Alter table should start implicit transaction +SELECT @@TRANCOUNT; +ALTER TABLE implicit_tran_table2 ADD CONSTRAINT default_c DEFAULT 99 FOR c +SELECT @@TRANCOUNT; +IF @@TRANCOUNT > 0 COMMIT +GO +~~START~~ +int +0 +~~END~~ + +~~START~~ +int +1 +~~END~~ + + +-- truncate table should start implicit transaction +SELECT @@TRANCOUNT +TRUNCATE TABLE implicit_tran_table2 +SELECT @@TRANCOUNT +IF @@TRANCOUNT > 0 COMMIT +GO +~~START~~ +int +0 +~~END~~ + +~~START~~ +int +1 +~~END~~ + + +-- Drop table should start implicit transaction +SELECT @@TRANCOUNT +DROP TABLE implicit_tran_table2 +SELECT @@TRANCOUNT +IF @@TRANCOUNT > 0 COMMIT +GO +~~START~~ +int +0 +~~END~~ + +~~START~~ +int +1 +~~END~~ + + +-- Create procedure should start implicit transaction +SELECT @@TRANCOUNT +GO +~~START~~ +int +0 +~~END~~ + +CREATE PROCEDURE implicit_tran_proc + AS + BEGIN + SELECT 'Select inside a procedure' + END +GO +SELECT @@TRANCOUNT +IF @@TRANCOUNT > 0 COMMIT +GO +~~START~~ +int +1 +~~END~~ + + + + +/* + * Alter procedure should start implicit transaction + * Note: Did not add test for ALTER PROCEDURE since + * we do not support it (BABEL-442) + */ +-- Drop procedure should start implicit transaction +SELECT @@TRANCOUNT +DROP PROCEDURE implicit_tran_proc +SELECT @@TRANCOUNT +IF @@TRANCOUNT > 0 COMMIT +GO +~~START~~ +int +0 +~~END~~ + +~~START~~ +int +1 +~~END~~ + + +-- Begin transaction should start implicit transaction +SELECT @@TRANCOUNT +BEGIN TRANSACTION +SELECT @@TRANCOUNT +IF @@TRANCOUNT > 0 COMMIT +IF @@TRANCOUNT > 0 COMMIT +GO +~~START~~ +int +0 +~~END~~ + +~~START~~ +int +2 +~~END~~ + + +-- Create database should not start implicit transaction +SELECT @@TRANCOUNT +CREATE DATABASE implicit_tran_db +SELECT @@TRANCOUNT +IF @@TRANCOUNT > 0 COMMIT +GO +~~START~~ +int +0 +~~END~~ + +~~START~~ +int +0 +~~END~~ + + +-- Drop database should not start implicit transaction +SELECT @@TRANCOUNT +DROP DATABASE implicit_tran_db +SELECT @@TRANCOUNT +IF @@TRANCOUNT > 0 COMMIT +GO +~~START~~ +int +0 +~~END~~ + +~~START~~ +int +0 +~~END~~ + + +/* + * Declare cursor should start an implicit transaction + */ +SELECT @@TRANCOUNT; +DECLARE implicit_tran_cursor CURSOR FOR SELECT * FROM implicit_tran_table; +SELECT @@TRANCOUNT; +DEALLOCATE implicit_tran_cursor; +IF @@TRANCOUNT > 0 COMMIT; +GO +~~START~~ +int +0 +~~END~~ + +~~START~~ +int +1 +~~END~~ + + +SELECT @@TRANCOUNT; +DECLARE implicit_tran_cursor CURSOR FOR SELECT 9876; +SELECT @@TRANCOUNT; +DEALLOCATE implicit_tran_cursor; +GO +~~START~~ +int +0 +~~END~~ + +~~START~~ +int +1 +~~END~~ + + +-- Open and fetch should start implicit transaction +-- Close and deallocate should not start implicit transaction +DECLARE implicit_tran_cursor CURSOR FOR SELECT * FROM implicit_tran_table; +DECLARE @val INT; +IF @@TRANCOUNT > 0 COMMIT; +SELECT @@TRANCOUNT; +OPEN implicit_tran_cursor; +SELECT @@TRANCOUNT; +IF @@TRANCOUNT > 0 COMMIT; +SELECT @@TRANCOUNT; +FETCH FROM implicit_tran_cursor INTO @val; +SELECT @@TRANCOUNT; +IF @@TRANCOUNT > 0 COMMIT; +SELECT @@TRANCOUNT; +CLOSE implicit_tran_cursor; +SELECT @@TRANCOUNT; +DEALLOCATE implicit_tran_cursor; +SELECT @@TRANCOUNT; +GO +~~START~~ +int +0 +~~END~~ + +~~START~~ +int +1 +~~END~~ + +~~START~~ +int +0 +~~END~~ + +~~START~~ +int +1 +~~END~~ + +~~START~~ +int +0 +~~END~~ + +~~START~~ +int +0 +~~END~~ + +~~START~~ +int +0 +~~END~~ + + +-- Cleanup +SET IMPLICIT_TRANSACTIONS OFF +GO + +DROP TABLE implicit_tran_table +GO diff --git a/contrib/test/JDBC/sql_expected/TestAuth.out b/contrib/test/JDBC/sql_expected/TestAuth.out new file mode 100644 index 00000000000..7ea90e3bbe2 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/TestAuth.out @@ -0,0 +1,49 @@ +#database name, username and password should not exceed 128 characters +java_auth#!#database|-|11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +~~ERROR (Code: 1283)~~ + +~~ERROR (Message: database "111111111111111111111111111111111111111111111111111111111111111" does not exist ClientConnectionId:26480caa-93c1-42d0-9a24-38f36eeebb5e)~~ + +java_auth#!#database|-|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112 +~~ERROR (Code: 0)~~ + +~~ERROR (Message: The databaseName property exceeds the maximum number of 128 characters.)~~ + +java_auth#!#user|-|11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +~~ERROR (Code: 514)~~ + +~~ERROR (Message: role "111111111111111111111111111111111111111111111111111111111111111" does not exist ClientConnectionId:9914082d-a9a3-4857-959b-029461beae5f)~~ + +java_auth#!#user|-|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112 +~~ERROR (Code: 0)~~ + +~~ERROR (Message: The user property exceeds the maximum number of 128 characters.)~~ + +#database and user name arguments are case-insensitive +java_auth#!#database|-|MASTER +~~SUCCESS~~ +java_auth#!#database|-|MaStEr +~~SUCCESS~~ +java_auth#!#user|-|JDBC_USER +~~SUCCESS~~ +java_auth#!#user|-|JdBc_UsEr +~~SUCCESS~~ +#not sure why any password is accepted during authentication through cloud desktop +#This test should throw error but from cloud desktop a connection is successfully established +#java_auth#!#password|-|11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +java_auth#!#password|-|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112 +~~ERROR (Code: 0)~~ + +~~ERROR (Message: The password property exceeds the maximum number of 128 characters.)~~ + +java_auth#!#others|-|packetSize=0 +~~SUCCESS~~ +java_auth#!#others|-|packetSize=-1 +~~SUCCESS~~ +java_auth#!#others|-|packetSize=4096 +~~SUCCESS~~ +java_auth#!#database|-|test1 SELECT 1 +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: database "test1 SELECT 1" does not exist ClientConnectionId:02c14f23-c21c-435f-8c00-f2b823b83437)~~ + diff --git a/contrib/test/JDBC/sql_expected/TestErrorsWithTryCatch.out b/contrib/test/JDBC/sql_expected/TestErrorsWithTryCatch.out new file mode 100644 index 00000000000..0f8b51ca03e --- /dev/null +++ b/contrib/test/JDBC/sql_expected/TestErrorsWithTryCatch.out @@ -0,0 +1,1702 @@ +CREATE TABLE ErrorWithTryCatchTable (a varchar(15) UNIQUE NOT NULL, b nvarchar(25), c int PRIMARY KEY, d char(15) DEFAULT 'Whoops!', e nchar(25), f datetime, g numeric(4,1) CHECK (g >= 103.5)) +GO + +-- setup for "invalid characters found: cannot cast value "%s" to money" error +CREATE TABLE t293_1(a money, b int); +GO + +INSERT INTO t293_1(a, b) values ($100, 1), ($101, 2); +GO +~~ROW COUNT: 2~~ + + +-- setup for error "column \"%s\" of relation \"%s\" is a generated column" error +CREATE TABLE t1752_2(c1 INT, c2 INT, c3 as c1*c2) +GO + +-- setup for "A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations" error +CREATE TABLE t141_2(c1 int, c2 int); +GO + +-- Error: duplicate key value violates unique constraint +-- Simple batch with try catch +BEGIN TRY + SELECT xact_state(); + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH +GO +~~START~~ +smallint +0 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +smallint +0 +~~END~~ + +select * from ErrorWithTryCatchTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +truncate table ErrorWithTryCatchTable +GO + +-- Error: duplicate key value violates unique constraint +-- Simple batch with transaction inside try-catch +BEGIN TRY + BEGIN TRAN + SELECT xact_state(); + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +~~START~~ +smallint +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +smallint +1 +~~END~~ + +IF @@trancount > 0 ROLLBACK TRAN; +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +truncate table ErrorWithTryCatchTable +GO + +-- Error: duplicate key value violates unique constraint +-- Simple procedure inside try-catch +CREATE PROCEDURE errorWithTryCatchProc1 +AS +INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); +GO +BEGIN TRY + SELECT xact_state(); + EXEC errorWithTryCatchProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +~~START~~ +smallint +0 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +smallint +0 +~~END~~ + +DROP PROCEDURE errorWithTryCatchProc1 +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +truncate table ErrorWithTryCatchTable +GO + +-- Error: duplicate key value violates unique constraint +-- Transaction inside try-catch but not inside procedure +CREATE PROCEDURE errorWithTryCatchProc1 +AS +INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); +GO +BEGIN TRY + BEGIN TRAN + SELECT xact_state(); + EXEC errorWithTryCatchProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +~~START~~ +smallint +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +smallint +1 +~~END~~ + +IF @@trancount > 0 ROLLBACK TRAN; +GO +DROP PROCEDURE errorWithTryCatchProc1 +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +truncate table ErrorWithTryCatchTable +GO + +-- Error: duplicate key value violates unique constraint +-- Transaction inside procedure but not inside try-catch +CREATE PROCEDURE errorWithTryCatchProc1 +AS +BEGIN + BEGIN TRAN + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + COMMIT TRAN +END +GO +BEGIN TRY + SELECT xact_state(); + EXEC errorWithTryCatchProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +~~START~~ +smallint +0 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +smallint +1 +~~END~~ + +IF @@trancount > 0 ROLLBACK TRAN; +GO +DROP PROCEDURE errorWithTryCatchProc1 +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +truncate table ErrorWithTryCatchTable +GO + +-- Error: duplicate key value violates unique constraint +-- Transaction inside try-catch and inside procedure +CREATE PROCEDURE errorWithTryCatchProc1 +AS +BEGIN + BEGIN TRAN + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + COMMIT TRAN +END +GO +BEGIN TRY + BEGIN TRAN + SELECT xact_state(); + EXEC errorWithTryCatchProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +~~START~~ +smallint +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +smallint +1 +~~END~~ + +IF @@trancount > 0 ROLLBACK TRAN; +GO +DROP PROCEDURE errorWithTryCatchProc1 +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +truncate table ErrorWithTryCatchTable +GO + + + + +-- Error: check constraint violation +-- Simple batch with try catch +BEGIN TRY + SELECT xact_state(); + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE ErrorWithTryCatchTable SET g = 101.4 WHERE a = 1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH +GO +~~START~~ +smallint +0 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +smallint +0 +~~END~~ + +select * from ErrorWithTryCatchTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +truncate table ErrorWithTryCatchTable +GO + +-- Error: check constraint violation +-- Simple batch with transaction inside try-catch +BEGIN TRY + BEGIN TRAN + SELECT xact_state(); + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE ErrorWithTryCatchTable SET g = 101.4 WHERE a = 1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +~~START~~ +smallint +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +smallint +-1 +~~END~~ + +~~ERROR (Code: 4)~~ + +~~ERROR (Message: Uncommittable transaction is detected at the end of the batch. The transaction is rolled back.)~~ + +IF @@trancount > 0 ROLLBACK TRAN; +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +truncate table ErrorWithTryCatchTable +GO + +-- Error: check constraint violation +-- Simple procedure inside try-catch +CREATE PROCEDURE errorWithTryCatchProc1 +AS +INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +UPDATE ErrorWithTryCatchTable SET g = 101.4 WHERE a = 1; +GO +BEGIN TRY + SELECT xact_state(); + EXEC errorWithTryCatchProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +~~START~~ +smallint +0 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +smallint +0 +~~END~~ + +DROP PROCEDURE errorWithTryCatchProc1 +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +truncate table ErrorWithTryCatchTable +GO + +-- Error: check constraint violation +-- Transaction inside try-catch but not inside procedure +CREATE PROCEDURE errorWithTryCatchProc1 +AS +INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +UPDATE ErrorWithTryCatchTable SET g = 101.4 WHERE a = 1; +GO +BEGIN TRY + BEGIN TRAN + SELECT xact_state(); + EXEC errorWithTryCatchProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +~~START~~ +smallint +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +smallint +-1 +~~END~~ + +~~ERROR (Code: 4)~~ + +~~ERROR (Message: Uncommittable transaction is detected at the end of the batch. The transaction is rolled back.)~~ + +IF @@trancount > 0 ROLLBACK TRAN; +GO +DROP PROCEDURE errorWithTryCatchProc1 +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +truncate table ErrorWithTryCatchTable +GO + +-- Error: check constraint violation +-- Transaction inside procedure but not inside try-catch +CREATE PROCEDURE errorWithTryCatchProc1 +AS +BEGIN + BEGIN TRAN + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE ErrorWithTryCatchTable SET g = 101.4 WHERE a = 1; + COMMIT TRAN +END +GO +BEGIN TRY + SELECT xact_state(); + EXEC errorWithTryCatchProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +~~START~~ +smallint +0 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +smallint +-1 +~~END~~ + +~~ERROR (Code: 4)~~ + +~~ERROR (Message: Uncommittable transaction is detected at the end of the batch. The transaction is rolled back.)~~ + +IF @@trancount > 0 ROLLBACK TRAN; +GO +DROP PROCEDURE errorWithTryCatchProc1 +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +truncate table ErrorWithTryCatchTable +GO + +-- Error: check constraint violation +-- Transaction inside try-catch and inside procedure +CREATE PROCEDURE errorWithTryCatchProc1 +AS +BEGIN + BEGIN TRAN + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE ErrorWithTryCatchTable SET g = 101.4 WHERE a = 1; + COMMIT TRAN +END +GO +BEGIN TRY + BEGIN TRAN + SELECT xact_state(); + EXEC errorWithTryCatchProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +~~START~~ +smallint +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +smallint +-1 +~~END~~ + +~~ERROR (Code: 4)~~ + +~~ERROR (Message: Uncommittable transaction is detected at the end of the batch. The transaction is rolled back.)~~ + +IF @@trancount > 0 ROLLBACK TRAN; +GO +DROP PROCEDURE errorWithTryCatchProc1 +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +truncate table ErrorWithTryCatchTable +GO + + + + + + + +-- Error: not null constraint violation +-- Simple batch with try catch +BEGIN TRY + SELECT xact_state(); + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE ErrorWithTryCatchTable SET c = NULL WHERE a = 1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH +GO +~~START~~ +smallint +0 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +smallint +0 +~~END~~ + +select * from ErrorWithTryCatchTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +truncate table ErrorWithTryCatchTable +GO + +-- Error: not null constraint violation +-- Simple batch with transaction inside try-catch +BEGIN TRY + BEGIN TRAN + SELECT xact_state(); + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE ErrorWithTryCatchTable SET c = NULL WHERE a = 1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +~~START~~ +smallint +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +smallint +-1 +~~END~~ + +~~ERROR (Code: 4)~~ + +~~ERROR (Message: Uncommittable transaction is detected at the end of the batch. The transaction is rolled back.)~~ + +IF @@trancount > 0 ROLLBACK TRAN; +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +truncate table ErrorWithTryCatchTable +GO + +-- Error: not null constraint violation +-- Simple procedure inside try-catch +CREATE PROCEDURE errorWithTryCatchProc1 +AS +INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +UPDATE ErrorWithTryCatchTable SET c = NULL WHERE a = 1; +GO +BEGIN TRY + SELECT xact_state(); + EXEC errorWithTryCatchProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +~~START~~ +smallint +0 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +smallint +0 +~~END~~ + +DROP PROCEDURE errorWithTryCatchProc1 +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +truncate table ErrorWithTryCatchTable +GO + +-- Error: not null constraint violation +-- Transaction inside try-catch but not inside procedure +CREATE PROCEDURE errorWithTryCatchProc1 +AS +INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +UPDATE ErrorWithTryCatchTable SET c = NULL WHERE a = 1; +GO +BEGIN TRY + BEGIN TRAN + SELECT xact_state(); + EXEC errorWithTryCatchProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +~~START~~ +smallint +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +smallint +-1 +~~END~~ + +~~ERROR (Code: 4)~~ + +~~ERROR (Message: Uncommittable transaction is detected at the end of the batch. The transaction is rolled back.)~~ + +IF @@trancount > 0 ROLLBACK TRAN; +GO +DROP PROCEDURE errorWithTryCatchProc1 +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +truncate table ErrorWithTryCatchTable +GO + +-- Error: not null constraint violation +-- Transaction inside procedure but not inside try-catch +CREATE PROCEDURE errorWithTryCatchProc1 +AS +BEGIN + BEGIN TRAN + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE ErrorWithTryCatchTable SET c = NULL WHERE a = 1; + COMMIT TRAN +END +GO +BEGIN TRY + SELECT xact_state(); + EXEC errorWithTryCatchProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +~~START~~ +smallint +0 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +smallint +-1 +~~END~~ + +~~ERROR (Code: 4)~~ + +~~ERROR (Message: Uncommittable transaction is detected at the end of the batch. The transaction is rolled back.)~~ + +IF @@trancount > 0 ROLLBACK TRAN; +GO +DROP PROCEDURE errorWithTryCatchProc1 +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +truncate table ErrorWithTryCatchTable +GO + +-- Error: not null constraint violation +-- Transaction inside try-catch and inside procedure +CREATE PROCEDURE errorWithTryCatchProc1 +AS +BEGIN + BEGIN TRAN + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE ErrorWithTryCatchTable SET c = NULL WHERE a = 1; + COMMIT TRAN +END +GO +BEGIN TRY + BEGIN TRAN + SELECT xact_state(); + EXEC errorWithTryCatchProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +~~START~~ +smallint +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +smallint +-1 +~~END~~ + +~~ERROR (Code: 4)~~ + +~~ERROR (Message: Uncommittable transaction is detected at the end of the batch. The transaction is rolled back.)~~ + +IF @@trancount > 0 ROLLBACK TRAN; +GO +DROP PROCEDURE errorWithTryCatchProc1 +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +truncate table ErrorWithTryCatchTable +GO + + + + + + + +-- Error: creating an existing table +-- Simple batch with try catch +BEGIN TRY + SELECT xact_state(); + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE ErrorWithTryCatchTable (a int); +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH +GO +~~START~~ +smallint +0 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +smallint +0 +~~END~~ + +select * from ErrorWithTryCatchTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +truncate table ErrorWithTryCatchTable +GO + +-- Error: creating an existing table +-- Simple batch with transaction inside try-catch +BEGIN TRY + BEGIN TRAN + SELECT xact_state(); + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE ErrorWithTryCatchTable (a int); +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +~~START~~ +smallint +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +smallint +-1 +~~END~~ + +~~ERROR (Code: 4)~~ + +~~ERROR (Message: Uncommittable transaction is detected at the end of the batch. The transaction is rolled back.)~~ + +IF @@trancount > 0 ROLLBACK TRAN; +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +truncate table ErrorWithTryCatchTable +GO + +-- Error: creating an existing table +-- Simple procedure inside try-catch +CREATE PROCEDURE errorWithTryCatchProc1 +AS +INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE ErrorWithTryCatchTable (a int); +GO +BEGIN TRY + SELECT xact_state(); + EXEC errorWithTryCatchProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +~~START~~ +smallint +0 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +smallint +0 +~~END~~ + +DROP PROCEDURE errorWithTryCatchProc1 +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +truncate table ErrorWithTryCatchTable +GO + +-- Error: creating an existing table +-- Transaction inside try-catch but not inside procedure +CREATE PROCEDURE errorWithTryCatchProc1 +AS +INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE ErrorWithTryCatchTable (a int); +GO +BEGIN TRY + BEGIN TRAN + SELECT xact_state(); + EXEC errorWithTryCatchProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +~~START~~ +smallint +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +smallint +-1 +~~END~~ + +~~ERROR (Code: 4)~~ + +~~ERROR (Message: Uncommittable transaction is detected at the end of the batch. The transaction is rolled back.)~~ + +IF @@trancount > 0 ROLLBACK TRAN; +GO +DROP PROCEDURE errorWithTryCatchProc1 +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +truncate table ErrorWithTryCatchTable +GO + +-- Error: creating an existing table +-- Transaction inside procedure but not inside try-catch +CREATE PROCEDURE errorWithTryCatchProc1 +AS +BEGIN + BEGIN TRAN + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE ErrorWithTryCatchTable (a int); + COMMIT TRAN +END +GO +BEGIN TRY + SELECT xact_state(); + EXEC errorWithTryCatchProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +~~START~~ +smallint +0 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +smallint +-1 +~~END~~ + +~~ERROR (Code: 4)~~ + +~~ERROR (Message: Uncommittable transaction is detected at the end of the batch. The transaction is rolled back.)~~ + +IF @@trancount > 0 ROLLBACK TRAN; +GO +DROP PROCEDURE errorWithTryCatchProc1 +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +truncate table ErrorWithTryCatchTable +GO + +-- Error: creating an existing table +-- Transaction inside try-catch and inside procedure +CREATE PROCEDURE errorWithTryCatchProc1 +AS +BEGIN + BEGIN TRAN + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE ErrorWithTryCatchTable (a int); + COMMIT TRAN +END +GO +BEGIN TRY + BEGIN TRAN + SELECT xact_state(); + EXEC errorWithTryCatchProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +~~START~~ +smallint +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +smallint +-1 +~~END~~ + +~~ERROR (Code: 4)~~ + +~~ERROR (Message: Uncommittable transaction is detected at the end of the batch. The transaction is rolled back.)~~ + +IF @@trancount > 0 ROLLBACK TRAN; +GO +DROP PROCEDURE errorWithTryCatchProc1 +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +truncate table ErrorWithTryCatchTable +GO + + + + + + + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- Simple batch with try catch +BEGIN TRY + SELECT xact_state(); + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + ALTER TABLE t1752_2 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH +GO +~~START~~ +smallint +0 +~~END~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 1752)~~ + +~~ERROR (Message: column "c3" of relation "t1752_2" is a generated column)~~ + +select * from ErrorWithTryCatchTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +truncate table ErrorWithTryCatchTable +GO + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- Simple batch with transaction inside try-catch +BEGIN TRY + BEGIN TRAN + SELECT xact_state(); + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + ALTER TABLE t1752_2 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +~~START~~ +smallint +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 1752)~~ + +~~ERROR (Message: column "c3" of relation "t1752_2" is a generated column)~~ + +IF @@trancount > 0 ROLLBACK TRAN; +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +truncate table ErrorWithTryCatchTable +GO + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- Simple procedure inside try-catch +CREATE PROCEDURE errorWithTryCatchProc1 +AS +INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +ALTER TABLE t1752_2 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; +GO +BEGIN TRY + SELECT xact_state(); + EXEC errorWithTryCatchProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +~~START~~ +smallint +0 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +smallint +0 +~~END~~ + +DROP PROCEDURE errorWithTryCatchProc1 +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +truncate table ErrorWithTryCatchTable +GO + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- Transaction inside try-catch but not inside procedure +CREATE PROCEDURE errorWithTryCatchProc1 +AS +INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +ALTER TABLE t1752_2 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; +GO +BEGIN TRY + BEGIN TRAN + SELECT xact_state(); + EXEC errorWithTryCatchProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +~~START~~ +smallint +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +smallint +1 +~~END~~ + +IF @@trancount > 0 ROLLBACK TRAN; +GO +DROP PROCEDURE errorWithTryCatchProc1 +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +truncate table ErrorWithTryCatchTable +GO + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- Transaction inside procedure but not inside try-catch +CREATE PROCEDURE errorWithTryCatchProc1 +AS +BEGIN + BEGIN TRAN + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + ALTER TABLE t1752_2 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; + COMMIT TRAN +END +GO +BEGIN TRY + SELECT xact_state(); + EXEC errorWithTryCatchProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +~~START~~ +smallint +0 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +smallint +1 +~~END~~ + +IF @@trancount > 0 ROLLBACK TRAN; +GO +DROP PROCEDURE errorWithTryCatchProc1 +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +truncate table ErrorWithTryCatchTable +GO + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- Transaction inside try-catch and inside procedure +CREATE PROCEDURE errorWithTryCatchProc1 +AS +BEGIN + BEGIN TRAN + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + ALTER TABLE t1752_2 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; + COMMIT TRAN +END +GO +BEGIN TRY + BEGIN TRAN + SELECT xact_state(); + EXEC errorWithTryCatchProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +~~START~~ +smallint +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +smallint +1 +~~END~~ + +IF @@trancount > 0 ROLLBACK TRAN; +GO +DROP PROCEDURE errorWithTryCatchProc1 +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +truncate table ErrorWithTryCatchTable +GO + + +-- Error: "A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations" +-- Simple batch with try catch +BEGIN TRY + SELECT xact_state(); + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + DECLARE @a int; SELECT @a = c1, c2 FROM t141_2; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH +GO +~~ERROR (Code: 141)~~ + +~~ERROR (Message: A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations)~~ + +select * from ErrorWithTryCatchTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +truncate table ErrorWithTryCatchTable +GO + +-- Error: "A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations" +-- Simple batch with transaction inside try-catch +BEGIN TRY + BEGIN TRAN + SELECT xact_state(); + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + DECLARE @a int; SELECT @a = c1, c2 FROM t141_2; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +~~ERROR (Code: 141)~~ + +~~ERROR (Message: A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations)~~ + +IF @@trancount > 0 ROLLBACK TRAN; +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +truncate table ErrorWithTryCatchTable +GO + +-- Error: "value for domain tinyint violates check constraint "tinyint_check"" +-- Simple error inside try-catch +BEGIN TRY + SELECT xact_state(); + DECLARE @a tinyint = 1000; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +~~START~~ +smallint +0 +~~END~~ + +~~START~~ +smallint +0 +~~END~~ + +select * from ErrorWithTryCatchTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +truncate table ErrorWithTryCatchTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- Simple batch with try catch +BEGIN TRY + SELECT xact_state(); + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE t293_1 SET a = convert(money, ''string'') WHERE b > 1;'; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH +GO +~~START~~ +smallint +0 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +smallint +0 +~~END~~ + +select * from ErrorWithTryCatchTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +truncate table ErrorWithTryCatchTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- Simple batch with transaction inside try-catch +BEGIN TRY + BEGIN TRAN + SELECT xact_state(); + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE t293_1 SET a = convert(money, ''string'') WHERE b > 1;'; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +~~START~~ +smallint +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +smallint +-1 +~~END~~ + +~~ERROR (Code: 4)~~ + +~~ERROR (Message: Uncommittable transaction is detected at the end of the batch. The transaction is rolled back.)~~ + +IF @@trancount > 0 ROLLBACK TRAN; +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +truncate table ErrorWithTryCatchTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- Simple procedure inside try-catch +CREATE PROCEDURE errorWithTryCatchProc1 +AS +INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE t293_1 SET a = convert(money, ''string'') WHERE b > 1;';; +GO +BEGIN TRY + SELECT xact_state(); + EXEC errorWithTryCatchProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +~~START~~ +smallint +0 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +smallint +0 +~~END~~ + +DROP PROCEDURE errorWithTryCatchProc1 +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +truncate table ErrorWithTryCatchTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- Transaction inside try-catch but not inside procedure +CREATE PROCEDURE errorWithTryCatchProc1 +AS +INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE t293_1 SET a = convert(money, ''string'') WHERE b > 1;'; +GO +BEGIN TRY + BEGIN TRAN + SELECT xact_state(); + EXEC errorWithTryCatchProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +~~START~~ +smallint +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +smallint +-1 +~~END~~ + +~~ERROR (Code: 4)~~ + +~~ERROR (Message: Uncommittable transaction is detected at the end of the batch. The transaction is rolled back.)~~ + +IF @@trancount > 0 ROLLBACK TRAN; +GO +DROP PROCEDURE errorWithTryCatchProc1 +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +truncate table ErrorWithTryCatchTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- Transaction inside procedure but not inside try-catch +CREATE PROCEDURE errorWithTryCatchProc1 +AS +BEGIN + BEGIN TRAN + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE t293_1 SET a = convert(money, ''string'') WHERE b > 1;'; + COMMIT TRAN +END +GO +BEGIN TRY + SELECT xact_state(); + EXEC errorWithTryCatchProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +~~START~~ +smallint +0 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +smallint +-1 +~~END~~ + +~~ERROR (Code: 4)~~ + +~~ERROR (Message: Uncommittable transaction is detected at the end of the batch. The transaction is rolled back.)~~ + +IF @@trancount > 0 ROLLBACK TRAN; +GO +DROP PROCEDURE errorWithTryCatchProc1 +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +truncate table ErrorWithTryCatchTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- Transaction inside try-catch and inside procedure +CREATE PROCEDURE errorWithTryCatchProc1 +AS +BEGIN + BEGIN TRAN + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE t293_1 SET a = convert(money, ''string'') WHERE b > 1;'; + COMMIT TRAN +END +GO +BEGIN TRY + BEGIN TRAN + SELECT xact_state(); + EXEC errorWithTryCatchProc1; +END TRY +BEGIN CATCH + SELECT xact_state(); +END CATCH; +GO +~~START~~ +smallint +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +smallint +-1 +~~END~~ + +~~ERROR (Code: 4)~~ + +~~ERROR (Message: Uncommittable transaction is detected at the end of the batch. The transaction is rolled back.)~~ + +IF @@trancount > 0 ROLLBACK TRAN; +GO +DROP PROCEDURE errorWithTryCatchProc1 +GO +select * from ErrorWithTryCatchTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +truncate table ErrorWithTryCatchTable +GO + +-- valid INSERT inside catch after an error +-- Simple batch with try catch +BEGIN TRY + BEGIN TRAN + SELECT xact_state(); + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); +END TRY +BEGIN CATCH + SELECT xact_state(); + INSERT INTO ErrorWithTryCatchTable VALUES ('Orange', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); +END CATCH; +GO +~~START~~ +smallint +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +smallint +1 +~~END~~ + +~~ROW COUNT: 1~~ + +select a from ErrorWithTryCatchTable ORDER BY c +GO +~~START~~ +varchar +Apple +Orange +~~END~~ + +truncate table ErrorWithTryCatchTable +GO + +-- invalid INSERT inside catch after an error +-- Simple batch with try catch +BEGIN TRY + BEGIN TRAN + SELECT xact_state(); + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); +END TRY +BEGIN CATCH + SELECT xact_state(); + INSERT INTO ErrorWithTryCatchTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); +END CATCH; +GO +~~START~~ +smallint +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +smallint +1 +~~END~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "errorwithtrycatchtable_a_key")~~ + +select a from ErrorWithTryCatchTable ORDER BY c +GO +~~START~~ +varchar +Apple +~~END~~ + +truncate table ErrorWithTryCatchTable +GO + + +DROP TABLE ErrorWithTryCatchTable +GO + +-- cleanup for "invalid characters found: cannot cast value "%s" to money" error +DROP TABLE t293_1; +GO + +-- cleanup for error "column \"%s\" of relation \"%s\" is a generated column" error +DROP TABLE t1752_2 +GO + +-- cleanup for "A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations" error +DROP TABLE t141_2; +GO + +while (@@trancount > 0) commit tran; +GO + diff --git a/contrib/test/JDBC/sql_expected/TestSimpleErrors.out b/contrib/test/JDBC/sql_expected/TestSimpleErrors.out new file mode 100644 index 00000000000..dfbbf262fd2 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/TestSimpleErrors.out @@ -0,0 +1,4844 @@ +CREATE TABLE simpleErrorTable (a varchar(15) UNIQUE NOT NULL, b nvarchar(25), c int PRIMARY KEY, d char(15) DEFAULT 'Whoops!', e nchar(25), f datetime, g numeric(4,1) CHECK (g >= 103.5)) +GO + +-- setup for "data out of range for datetime" error +CREATE TABLE t517_1(a datetime); +GO + +-- setup for "A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations" error +CREATE TABLE t141_1(c1 int, c2 int); +GO + +-- setup for "column \"%s\" of relation \"%s\" is a generated column" +CREATE TABLE t1752_1(c1 INT, c2 INT, c3 as c1*c2) +GO + +if @@trancount > 0 commit tran; +GO + +-- Error: duplicate key value violates unique constraint +-- simple batch +INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); +declare @err int = @@error; if @err = 0 select 0 else select 1; +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "simpleerrortable_a_key")~~ + +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- simple batch with commit transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + declare @err int = @@error; if @err = 0 select 0 else select 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +commit tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "simpleerrortable_a_key")~~ + +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- simple batch with rollback transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + declare @err int = @@error; if @err = 0 select 0 else select 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +rollback tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "simpleerrortable_a_key")~~ + +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- simple batch with rollback transaction and rollback to savepoint +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + save tran sp1; + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + declare @err int = @@error; if @err = 0 select 0 else select 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran sp1 +rollback tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "simpleerrortable_a_key")~~ + +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- simple procedure +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "simpleerrortable_a_key")~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- simple batch with nested transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +commit tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "simpleerrortable_a_key")~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- simple procedure with transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "simpleerrortable_a_key")~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- simple procedure with transaction started inside procedure but ended outside procedure +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "simpleerrortable_a_key")~~ + +~~ERROR (Code: 266)~~ + +~~ERROR (Message: Transaction count after execution indicates a mismatch number of BEGIN and COMMIT statements. Previous count 0 current count 1)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +commit tran +GO +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- simple procedure with transaction started outside procedure but ended inside procedure through commit +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "simpleerrortable_a_key")~~ + +~~ERROR (Code: 266)~~ + +~~ERROR (Message: Transaction count after execution indicates a mismatch number of BEGIN and COMMIT statements. Previous count 1 current count 0)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- simple procedure with transaction started outside procedure but ended inside procedure through rollback +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "simpleerrortable_a_key")~~ + +~~ERROR (Code: 266)~~ + +~~ERROR (Message: Transaction count after execution indicates a mismatch number of BEGIN and COMMIT statements. Previous count 1 current count 0)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- nested procedure (level 2) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "simpleerrortable_a_key")~~ + +~~ROW COUNT: 1~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +Pineapple#!#pink#!#7#!#Surat #!#Frown😠 #!#2000-12-13 12:58:23.123#!#123.1 +Cherry#!#indigo#!#8#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- nested procedure (level 3) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +create procedure simpleErrorProc3 +as +begin + SELECT 1; + exec simpleErrorProc2; + SELECT 2; +end +GO +exec simpleErrorProc3 +GO +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "simpleerrortable_a_key")~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +2 +~~END~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +Pineapple#!#pink#!#7#!#Surat #!#Frown😠 #!#2000-12-13 12:58:23.123#!#123.1 +Cherry#!#indigo#!#8#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +drop procedure simpleErrorProc3 +GO +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- nested procedure with commit transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + commit tran; +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "simpleerrortable_a_key")~~ + +~~ROW COUNT: 1~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +Pineapple#!#pink#!#7#!#Surat #!#Frown😠 #!#2000-12-13 12:58:23.123#!#123.1 +Cherry#!#indigo#!#8#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- nested procedure with rollback transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + rollback tran; +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "simpleerrortable_a_key")~~ + +~~ERROR (Code: 266)~~ + +~~ERROR (Message: Transaction count after execution indicates a mismatch number of BEGIN and COMMIT statements. Previous count 1 current count 0)~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 3903)~~ + +~~ERROR (Message: ROLLBACK can only be used in transaction blocks)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Cherry#!#indigo#!#8#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: data out of range for datetime +-- simple batch +INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +INSERT INTO t517_1 VALUES (DATEADD(YY,-300,getdate())); +declare @err int = @@error; if @err = 0 select 0 else select 1; +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 517)~~ + +~~ERROR (Message: data out of range for datetime)~~ + +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: data out of range for datetime +-- simple batch with commit transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO t517_1 VALUES (DATEADD(YY,-300,getdate())); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +commit tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 517)~~ + +~~ERROR (Message: data out of range for datetime)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: data out of range for datetime +-- simple batch with rollback transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO t517_1 VALUES (DATEADD(YY,-300,getdate())); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +rollback tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 517)~~ + +~~ERROR (Message: data out of range for datetime)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: data out of range for datetime +-- simple batch with rollback transaction and rollback to savepoint +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + save tran sp1; + INSERT INTO t517_1 VALUES (DATEADD(YY,-300,getdate())); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran sp1; +rollback tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 517)~~ + +~~ERROR (Message: data out of range for datetime)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: data out of range for datetime +-- simple procedure +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO t517_1 VALUES (DATEADD(YY,-300,getdate())); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 517)~~ + +~~ERROR (Message: data out of range for datetime)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: data out of range for datetime +-- simple batch with nested transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + INSERT INTO t517_1 VALUES (DATEADD(YY,-300,getdate())); + declare @err int = @@error; if @err = 0 select 0 else select 1; + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +commit tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 517)~~ + +~~ERROR (Message: data out of range for datetime)~~ + +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: data out of range for datetime +-- simple procedure with transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + INSERT INTO t517_1 VALUES (DATEADD(YY,-300,getdate())); + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 517)~~ + +~~ERROR (Message: data out of range for datetime)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: data out of range for datetime +-- simple procedure with transaction started inside procedure but ended outside procedure +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO t517_1 VALUES (DATEADD(YY,-300,getdate())); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 517)~~ + +~~ERROR (Message: data out of range for datetime)~~ + +~~ERROR (Code: 266)~~ + +~~ERROR (Message: Transaction count after execution indicates a mismatch number of BEGIN and COMMIT statements. Previous count 0 current count 1)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +commit tran +GO +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: data out of range for datetime +-- simple procedure with transaction started outside procedure but ended inside procedure through commit +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO t517_1 VALUES (DATEADD(YY,-300,getdate())); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 517)~~ + +~~ERROR (Message: data out of range for datetime)~~ + +~~ERROR (Code: 266)~~ + +~~ERROR (Message: Transaction count after execution indicates a mismatch number of BEGIN and COMMIT statements. Previous count 1 current count 0)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: data out of range for datetime +-- simple procedure with transaction started outside procedure but ended inside procedure through rollback +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO t517_1 VALUES (DATEADD(YY,-300,getdate())); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 517)~~ + +~~ERROR (Message: data out of range for datetime)~~ + +~~ERROR (Code: 266)~~ + +~~ERROR (Message: Transaction count after execution indicates a mismatch number of BEGIN and COMMIT statements. Previous count 1 current count 0)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: data out of range for datetime +-- nested procedure (level 2) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO t517_1 VALUES (DATEADD(YY,-300,getdate())); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 517)~~ + +~~ERROR (Message: data out of range for datetime)~~ + +~~ROW COUNT: 1~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +Pineapple#!#pink#!#7#!#Surat #!#Frown😠 #!#2000-12-13 12:58:23.123#!#123.1 +Cherry#!#indigo#!#8#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: data out of range for datetime +-- nested procedure (level 3) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO t517_1 VALUES (DATEADD(YY,-300,getdate())); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +create procedure simpleErrorProc3 +as +begin + SELECT 1; + exec simpleErrorProc2; + SELECT 2; +end +GO +exec simpleErrorProc3 +GO +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 517)~~ + +~~ERROR (Message: data out of range for datetime)~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +2 +~~END~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +Pineapple#!#pink#!#7#!#Surat #!#Frown😠 #!#2000-12-13 12:58:23.123#!#123.1 +Cherry#!#indigo#!#8#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +drop procedure simpleErrorProc3 +GO +truncate table simpleErrorTable +GO + +-- Error: data out of range for datetime +-- nested procedure with commit transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO t517_1 VALUES (DATEADD(YY,-300,getdate())); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + commit tran; +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 517)~~ + +~~ERROR (Message: data out of range for datetime)~~ + +~~ROW COUNT: 1~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +Pineapple#!#pink#!#7#!#Surat #!#Frown😠 #!#2000-12-13 12:58:23.123#!#123.1 +Cherry#!#indigo#!#8#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: data out of range for datetime +-- nested procedure with rollback transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO t517_1 VALUES (DATEADD(YY,-300,getdate())); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + rollback tran; +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 517)~~ + +~~ERROR (Message: data out of range for datetime)~~ + +~~ERROR (Code: 266)~~ + +~~ERROR (Message: Transaction count after execution indicates a mismatch number of BEGIN and COMMIT statements. Previous count 1 current count 0)~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 3903)~~ + +~~ERROR (Message: ROLLBACK can only be used in transaction blocks)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Cherry#!#indigo#!#8#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- simple batch +INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +UPDATE simpleErrorTable SET c = NULL WHERE c = 1; +declare @err int = @@error; if @err = 0 select 0 else select 1; +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "c" of relation "simpleerrortable" violates not-null constraint)~~ + +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- simple batch with commit transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + declare @err int = @@error; if @err = 0 select 0 else select 1; +commit tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "c" of relation "simpleerrortable" violates not-null constraint)~~ + +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- simple batch with rollback transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + declare @err int = @@error; if @err = 0 select 0 else select 1; +rollback tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "c" of relation "simpleerrortable" violates not-null constraint)~~ + +~~START~~ +int +0 +~~END~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- simple batch with rollback transaction and rollback to savepoint +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + save tran sp1; + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + declare @err int = @@error; if @err = 0 select 0 else select 1; + rollback tran sp1; +rollback tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "c" of relation "simpleerrortable" violates not-null constraint)~~ + +~~START~~ +int +0 +~~END~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- simple procedure +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "c" of relation "simpleerrortable" violates not-null constraint)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- simple batch with nested transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + declare @err int = @@error; if @err = 0 select 0 else select 1; +commit tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "c" of relation "simpleerrortable" violates not-null constraint)~~ + +~~START~~ +int +0 +~~END~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- simple procedure with transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "c" of relation "simpleerrortable" violates not-null constraint)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- simple procedure with transaction started inside procedure but ended outside procedure +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "c" of relation "simpleerrortable" violates not-null constraint)~~ + +~~ERROR (Code: 266)~~ + +~~ERROR (Message: Transaction count after execution indicates a mismatch number of BEGIN and COMMIT statements. Previous count 0 current count 1)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +commit tran +GO +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- simple procedure with transaction started outside procedure but ended inside procedure through commit +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "c" of relation "simpleerrortable" violates not-null constraint)~~ + +~~ERROR (Code: 266)~~ + +~~ERROR (Message: Transaction count after execution indicates a mismatch number of BEGIN and COMMIT statements. Previous count 1 current count 0)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- simple procedure with transaction started outside procedure but ended inside procedure through rollback +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "c" of relation "simpleerrortable" violates not-null constraint)~~ + +~~ERROR (Code: 266)~~ + +~~ERROR (Message: Transaction count after execution indicates a mismatch number of BEGIN and COMMIT statements. Previous count 1 current count 0)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- nested procedure (level 2) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "c" of relation "simpleerrortable" violates not-null constraint)~~ + +~~ROW COUNT: 1~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +Pineapple#!#pink#!#7#!#Surat #!#Frown😠 #!#2000-12-13 12:58:23.123#!#123.1 +Cherry#!#indigo#!#8#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- nested procedure (level 3) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +create procedure simpleErrorProc3 +as +begin + SELECT 1; + exec simpleErrorProc2; + SELECT 2; +end +GO +exec simpleErrorProc3 +GO +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "c" of relation "simpleerrortable" violates not-null constraint)~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +2 +~~END~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +Pineapple#!#pink#!#7#!#Surat #!#Frown😠 #!#2000-12-13 12:58:23.123#!#123.1 +Cherry#!#indigo#!#8#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +drop procedure simpleErrorProc3 +GO +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- nested procedure with commit transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + commit tran; +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "c" of relation "simpleerrortable" violates not-null constraint)~~ + +~~ROW COUNT: 1~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +Pineapple#!#pink#!#7#!#Surat #!#Frown😠 #!#2000-12-13 12:58:23.123#!#123.1 +Cherry#!#indigo#!#8#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- nested procedure with rollback transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + rollback tran; +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "c" of relation "simpleerrortable" violates not-null constraint)~~ + +~~ERROR (Code: 266)~~ + +~~ERROR (Message: Transaction count after execution indicates a mismatch number of BEGIN and COMMIT statements. Previous count 1 current count 0)~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 3903)~~ + +~~ERROR (Message: ROLLBACK can only be used in transaction blocks)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Cherry#!#indigo#!#8#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + + +-- Error: creating an existing table +-- simple batch +INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +CREATE TABLE simpleErrorTable (a int); +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2714)~~ + +~~ERROR (Message: relation "simpleerrortable" already exists)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- simple batch with commit transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2714)~~ + +~~ERROR (Message: relation "simpleerrortable" already exists)~~ + +commit tran; +GO +~~ERROR (Code: 3902)~~ + +~~ERROR (Message: COMMIT can only be used in transaction blocks)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- simple batch with rollback transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2714)~~ + +~~ERROR (Message: relation "simpleerrortable" already exists)~~ + +rollback tran; +GO +~~ERROR (Code: 3903)~~ + +~~ERROR (Message: ROLLBACK can only be used in transaction blocks)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- simple batch with rollback transaction and rollback to savepoint +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + save tran sp1; + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2714)~~ + +~~ERROR (Message: relation "simpleerrortable" already exists)~~ + +rollback tran sp1; +GO +~~ERROR (Code: 3903)~~ + +~~ERROR (Message: ROLLBACK TO SAVEPOINT can only be used in transaction blocks)~~ + +rollback tran; +GO +~~ERROR (Code: 3903)~~ + +~~ERROR (Message: ROLLBACK can only be used in transaction blocks)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- simple procedure +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2714)~~ + +~~ERROR (Message: relation "simpleerrortable" already exists)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- simple batch with nested transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + CREATE TABLE simpleErrorTable (a int); +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2714)~~ + +~~ERROR (Message: relation "simpleerrortable" already exists)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +commit tran; +GO +~~ERROR (Code: 3902)~~ + +~~ERROR (Message: COMMIT can only be used in transaction blocks)~~ + +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +GO +~~ROW COUNT: 1~~ + +commit tran; +GO +~~ERROR (Code: 3902)~~ + +~~ERROR (Message: COMMIT can only be used in transaction blocks)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- simple procedure with transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + CREATE TABLE simpleErrorTable (a int); + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2714)~~ + +~~ERROR (Message: relation "simpleerrortable" already exists)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- simple procedure with transaction started inside procedure but ended outside procedure +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2714)~~ + +~~ERROR (Message: relation "simpleerrortable" already exists)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +commit tran +GO +~~ERROR (Code: 3902)~~ + +~~ERROR (Message: COMMIT can only be used in transaction blocks)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- simple procedure with transaction started outside procedure but ended inside procedure through commit +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2714)~~ + +~~ERROR (Message: relation "simpleerrortable" already exists)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- simple procedure with transaction started outside procedure but ended inside procedure through rollback +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2714)~~ + +~~ERROR (Message: relation "simpleerrortable" already exists)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- nested procedure (level 2) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2714)~~ + +~~ERROR (Message: relation "simpleerrortable" already exists)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Pineapple#!#pink#!#7#!#Surat #!#Frown😠 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- nested procedure (level 3) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +create procedure simpleErrorProc3 +as +begin + SELECT 1; + exec simpleErrorProc2; + SELECT 2; +end +GO +exec simpleErrorProc3 +GO +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2714)~~ + +~~ERROR (Message: relation "simpleerrortable" already exists)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Pineapple#!#pink#!#7#!#Surat #!#Frown😠 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +drop procedure simpleErrorProc3 +GO +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- nested procedure with commit transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + commit tran; +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2714)~~ + +~~ERROR (Message: relation "simpleerrortable" already exists)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- nested procedure with rollback transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + rollback tran; +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2714)~~ + +~~ERROR (Message: relation "simpleerrortable" already exists)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- simple batch +INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +ALTER TABLE t1752_1 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; +declare @err int = @@error; if @err = 0 select 0 else select 1; +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 1752)~~ + +~~ERROR (Message: column "c3" of relation "t1752_1" is a generated column)~~ + +GO +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- simple batch with commit transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + ALTER TABLE t1752_1 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +commit tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 1752)~~ + +~~ERROR (Message: column "c3" of relation "t1752_1" is a generated column)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +commit tran +GO +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- simple batch with rollback transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + ALTER TABLE t1752_1 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +rollback tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 1752)~~ + +~~ERROR (Message: column "c3" of relation "t1752_1" is a generated column)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +commit tran +GO +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- simple batch with rollback transaction and rollback to savepoint +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + save tran sp1; + ALTER TABLE t1752_1 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran sp1; +rollback tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 1752)~~ + +~~ERROR (Message: column "c3" of relation "t1752_1" is a generated column)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +commit tran +GO +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- simple procedure +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + ALTER TABLE t1752_1 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 1752)~~ + +~~ERROR (Message: column "c3" of relation "t1752_1" is a generated column)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- simple batch with nested transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + ALTER TABLE t1752_1 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +commit tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 1752)~~ + +~~ERROR (Message: column "c3" of relation "t1752_1" is a generated column)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +select @@trancount +GO +~~START~~ +int +2 +~~END~~ + +commit tran +GO +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +commit tran +GO +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- simple procedure with transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + ALTER TABLE t1752_1 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 1752)~~ + +~~ERROR (Message: column "c3" of relation "t1752_1" is a generated column)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +select @@trancount +GO +~~START~~ +int +2 +~~END~~ + +commit tran +GO +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +commit tran +GO +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- simple procedure with transaction started inside procedure but ended outside procedure +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + ALTER TABLE t1752_1 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 1752)~~ + +~~ERROR (Message: column "c3" of relation "t1752_1" is a generated column)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +commit tran +GO +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- simple procedure with transaction started outside procedure but ended inside procedure through commit +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + ALTER TABLE t1752_1 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 1752)~~ + +~~ERROR (Message: column "c3" of relation "t1752_1" is a generated column)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +commit tran +GO +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- simple procedure with transaction started outside procedure but ended inside procedure through rollback +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + ALTER TABLE t1752_1 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 1752)~~ + +~~ERROR (Message: column "c3" of relation "t1752_1" is a generated column)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +commit tran +GO +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- nested procedure (level 2) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + ALTER TABLE t1752_1 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 1752)~~ + +~~ERROR (Message: column "c3" of relation "t1752_1" is a generated column)~~ + +~~ROW COUNT: 1~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Pineapple#!#pink#!#7#!#Surat #!#Frown😠 #!#2000-12-13 12:58:23.123#!#123.1 +Cherry#!#indigo#!#8#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- nested procedure (level 3) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + ALTER TABLE t1752_1 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +create procedure simpleErrorProc3 +as +begin + SELECT 1; + exec simpleErrorProc2; + SELECT 2; +end +GO +exec simpleErrorProc3 +GO +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 1752)~~ + +~~ERROR (Message: column "c3" of relation "t1752_1" is a generated column)~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +2 +~~END~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Pineapple#!#pink#!#7#!#Surat #!#Frown😠 #!#2000-12-13 12:58:23.123#!#123.1 +Cherry#!#indigo#!#8#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +drop procedure simpleErrorProc3 +GO +truncate table simpleErrorTable +GO + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- nested procedure with commit transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + ALTER TABLE t1752_1 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + commit tran; +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 1752)~~ + +~~ERROR (Message: column "c3" of relation "t1752_1" is a generated column)~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 266)~~ + +~~ERROR (Message: Transaction count after execution indicates a mismatch number of BEGIN and COMMIT statements. Previous count 0 current count 1)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Pineapple#!#pink#!#7#!#Surat #!#Frown😠 #!#2000-12-13 12:58:23.123#!#123.1 +Cherry#!#indigo#!#8#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +commit tran +GO +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- nested procedure with rollback transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + ALTER TABLE t1752_1 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + rollback tran; +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 1752)~~ + +~~ERROR (Message: column "c3" of relation "t1752_1" is a generated column)~~ + +~~ROW COUNT: 1~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +commit tran +GO +~~ERROR (Code: 3902)~~ + +~~ERROR (Message: COMMIT can only be used in transaction blocks)~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: "A SELECT statement that assigns a value to a variable must not be +-- combined with data-retrieval operations" +-- simple batch +INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +DECLARE @a int; SELECT @a = c1, c2 FROM t141_1; +declare @err int = @@error; if @err = 0 select 0 else select 1; +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +GO +~~ERROR (Code: 141)~~ + +~~ERROR (Message: A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: "A SELECT statement that assigns a value to a variable must not be +-- combined with data-retrieval operations" +-- simple batch with commit transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + DECLARE @a int; SELECT @a = c1, c2 FROM t141_1; +GO +~~ERROR (Code: 141)~~ + +~~ERROR (Message: A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +commit tran; +GO +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 3902)~~ + +~~ERROR (Message: COMMIT can only be used in transaction blocks)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: "A SELECT statement that assigns a value to a variable must not be +-- combined with data-retrieval operations" +-- simple batch with rollback transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + DECLARE @a int; SELECT @a = c1, c2 FROM t141_1; +GO +~~ERROR (Code: 141)~~ + +~~ERROR (Message: A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +rollback tran; +GO +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 3903)~~ + +~~ERROR (Message: ROLLBACK can only be used in transaction blocks)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: "A SELECT statement that assigns a value to a variable must not be +-- combined with data-retrieval operations" +-- simple batch with rollback transaction and rollback to savepoint +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + save tran sp1; + DECLARE @a int; SELECT @a = c1, c2 FROM t141_1; +GO +~~ERROR (Code: 141)~~ + +~~ERROR (Message: A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +rollback tran sp1; +GO +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 3903)~~ + +~~ERROR (Message: ROLLBACK TO SAVEPOINT can only be used in transaction blocks)~~ + +rollback tran; +GO +~~ERROR (Code: 3903)~~ + +~~ERROR (Message: ROLLBACK can only be used in transaction blocks)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + + +-- Error: "A SELECT statement that assigns a value to a variable must not be +-- combined with data-retrieval operations" +-- simple procedure with transaction started outside procedure but ended inside procedure through commit +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + DECLARE @a int; SELECT @a = c1, c2 FROM t141_1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +~~ERROR (Code: 141)~~ + +~~ERROR (Message: A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations)~~ + +begin tran +GO +DECLARE @a tinyint = 1000; +GO +~~ERROR (Code: 220)~~ + +~~ERROR (Message: value for domain tinyint violates check constraint "tinyint_check")~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +commit tran +GO +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc1")~~ + +truncate table simpleErrorTable +GO + +-- Error: "A SELECT statement that assigns a value to a variable must not be +-- combined with data-retrieval operations" +-- simple procedure with transaction started outside procedure but ended inside procedure through rollback +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + DECLARE @a int; SELECT @a = c1, c2 FROM t141_1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +~~ERROR (Code: 141)~~ + +~~ERROR (Message: A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations)~~ + +begin tran +GO +DECLARE @a tinyint = 1000; +GO +~~ERROR (Code: 220)~~ + +~~ERROR (Message: value for domain tinyint violates check constraint "tinyint_check")~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +commit tran +GO +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc1")~~ + +truncate table simpleErrorTable +GO + +-- Error: "A SELECT statement that assigns a value to a variable must not be +-- combined with data-retrieval operations" +-- nested procedure (level 2) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + DECLARE @a int; SELECT @a = c1, c2 FROM t141_1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +~~ERROR (Code: 141)~~ + +~~ERROR (Message: A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations)~~ + +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + DECLARE @a tinyint = 1000; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 220)~~ + +~~ERROR (Message: value for domain tinyint violates check constraint "tinyint_check")~~ + +~~ROW COUNT: 1~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Pineapple#!#pink#!#7#!#Surat #!#Frown😠 #!#2000-12-13 12:58:23.123#!#123.1 +Cherry#!#indigo#!#8#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: "A SELECT statement that assigns a value to a variable must not be +-- combined with data-retrieval operations" +-- nested procedure (level 3) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + DECLARE @a int; SELECT @a = c1, c2 FROM t141_1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +~~ERROR (Code: 141)~~ + +~~ERROR (Message: A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations)~~ + +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + DECLARE @a tinyint = 1000; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +create procedure simpleErrorProc3 +as +begin + SELECT 1; + exec simpleErrorProc2; + SELECT 2; +end +GO +exec simpleErrorProc3 +GO +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 220)~~ + +~~ERROR (Message: value for domain tinyint violates check constraint "tinyint_check")~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +2 +~~END~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Pineapple#!#pink#!#7#!#Surat #!#Frown😠 #!#2000-12-13 12:58:23.123#!#123.1 +Cherry#!#indigo#!#8#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +drop procedure simpleErrorProc2 +GO +drop procedure simpleErrorProc3 +GO +truncate table simpleErrorTable +GO + +-- Error: "A SELECT statement that assigns a value to a variable must not be +-- combined with data-retrieval operations" +-- nested procedure with commit transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + DECLARE @a int; SELECT @a = c1, c2 FROM t141_1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +~~ERROR (Code: 141)~~ + +~~ERROR (Message: A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations)~~ + +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + DECLARE @a tinyint = 1000; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + commit tran; +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 220)~~ + +~~ERROR (Message: value for domain tinyint violates check constraint "tinyint_check")~~ + +~~ROW COUNT: 1~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Pineapple#!#pink#!#7#!#Surat #!#Frown😠 #!#2000-12-13 12:58:23.123#!#123.1 +Cherry#!#indigo#!#8#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: "A SELECT statement that assigns a value to a variable must not be +-- combined with data-retrieval operations" +-- nested procedure with rollback transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + DECLARE @a int; SELECT @a = c1, c2 FROM t141_1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +~~ERROR (Code: 141)~~ + +~~ERROR (Message: A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations)~~ + +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + DECLARE @a tinyint = 1000; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + rollback tran; +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 220)~~ + +~~ERROR (Message: value for domain tinyint violates check constraint "tinyint_check")~~ + +~~ROW COUNT: 1~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +select @@trancount; +GO +~~START~~ +int +0 +~~END~~ + + +if @@trancount > 0 commit tran; +GO + +-- Error: value for domain tinyint violates check constraint "tinyint_check" +INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +DECLARE @a tinyint = 1000; +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 220)~~ + +~~ERROR (Message: value for domain tinyint violates check constraint "tinyint_check")~~ + +~~ROW COUNT: 1~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +drop procedure simpleErrorProc1 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc1")~~ + +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- simple batch +INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33685634)~~ + +~~ERROR (Message: invalid input syntax for type integer: "abc")~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- simple batch with commit transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33685634)~~ + +~~ERROR (Message: invalid input syntax for type integer: "abc")~~ + +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +commit tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 3902)~~ + +~~ERROR (Message: COMMIT can only be used in transaction blocks)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- simple batch with rollback transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33685634)~~ + +~~ERROR (Message: invalid input syntax for type integer: "abc")~~ + +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +rollback tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 3903)~~ + +~~ERROR (Message: ROLLBACK can only be used in transaction blocks)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- simple batch with rollback transaction and rollback to savepoint +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + save tran sp1; + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33685634)~~ + +~~ERROR (Message: invalid input syntax for type integer: "abc")~~ + +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +rollback tran sp1; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 3903)~~ + +~~ERROR (Message: ROLLBACK TO SAVEPOINT can only be used in transaction blocks)~~ + +rollback tran; +GO +~~ERROR (Code: 3903)~~ + +~~ERROR (Message: ROLLBACK can only be used in transaction blocks)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- simple procedure +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33685634)~~ + +~~ERROR (Message: invalid input syntax for type integer: "abc")~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- simple batch with nested transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33685634)~~ + +~~ERROR (Message: invalid input syntax for type integer: "abc")~~ + +commit tran; +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +GO +~~ERROR (Code: 3902)~~ + +~~ERROR (Message: COMMIT can only be used in transaction blocks)~~ + +~~ROW COUNT: 1~~ + +commit tran; +GO +~~ERROR (Code: 3902)~~ + +~~ERROR (Message: COMMIT can only be used in transaction blocks)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- simple procedure with transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33685634)~~ + +~~ERROR (Message: invalid input syntax for type integer: "abc")~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- simple procedure with transaction started inside procedure but ended outside procedure +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33685634)~~ + +~~ERROR (Message: invalid input syntax for type integer: "abc")~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +commit tran +GO +~~ERROR (Code: 3902)~~ + +~~ERROR (Message: COMMIT can only be used in transaction blocks)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- simple procedure with transaction started outside procedure but ended inside procedure through commit +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33685634)~~ + +~~ERROR (Message: invalid input syntax for type integer: "abc")~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- simple procedure with transaction started outside procedure but ended inside procedure through rollback +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33685634)~~ + +~~ERROR (Message: invalid input syntax for type integer: "abc")~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- nested procedure (level 2) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33685634)~~ + +~~ERROR (Message: invalid input syntax for type integer: "abc")~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Pineapple#!#pink#!#7#!#Surat #!#Frown😠 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- nested procedure (level 3) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +create procedure simpleErrorProc3 +as +begin + SELECT 1; + exec simpleErrorProc2; + SELECT 2; +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33685634)~~ + +~~ERROR (Message: invalid input syntax for type integer: "abc")~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Pineapple#!#pink#!#7#!#Surat #!#Frown😠 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +drop procedure simpleErrorProc3 +GO +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- nested procedure with commit transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + commit tran; +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33685634)~~ + +~~ERROR (Message: invalid input syntax for type integer: "abc")~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- nested procedure with rollback transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + rollback tran; +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33685634)~~ + +~~ERROR (Message: invalid input syntax for type integer: "abc")~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- cleanup for "data out of range for datetime" error +DROP TABLE t517_1; +GO + +-- clean up for "A SELECT statement that assigns a value to a variable must not +-- be combined with data-retrieval operations" error +DROP TABLE t141_1; +GO + +-- setup for "column \"%s\" of relation \"%s\" is a generated column" +DROP TABLE t1752_1; +GO + +drop table simpleErrorTable +GO + +while (@@trancount > 0) commit tran; +GO + diff --git a/contrib/test/JDBC/sql_expected/TestSimpleErrorsWithImplicitTran.out b/contrib/test/JDBC/sql_expected/TestSimpleErrorsWithImplicitTran.out new file mode 100644 index 00000000000..862a2096141 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/TestSimpleErrorsWithImplicitTran.out @@ -0,0 +1,4918 @@ +#Setup +SET IMPLICIT_TRANSACTIONS ON + +#Run error handling tests +CREATE TABLE simpleErrorTable (a varchar(15) UNIQUE NOT NULL, b nvarchar(25), c int PRIMARY KEY, d char(15) DEFAULT 'Whoops!', e nchar(25), f datetime, g numeric(4,1) CHECK (g >= 103.5)) +GO + +-- setup for "data out of range for datetime" error +CREATE TABLE t517_1(a datetime); +GO + +-- setup for "A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations" error +CREATE TABLE t141_1(c1 int, c2 int); +GO + +-- setup for "column \"%s\" of relation \"%s\" is a generated column" +CREATE TABLE t1752_1(c1 INT, c2 INT, c3 as c1*c2) +GO + +if @@trancount > 0 commit tran; +GO + +-- Error: duplicate key value violates unique constraint +-- simple batch +INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); +declare @err int = @@error; if @err = 0 select 0 else select 1; +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "simpleerrortable_a_key")~~ + +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- simple batch with commit transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + declare @err int = @@error; if @err = 0 select 0 else select 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +commit tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "simpleerrortable_a_key")~~ + +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- simple batch with rollback transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + declare @err int = @@error; if @err = 0 select 0 else select 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +rollback tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "simpleerrortable_a_key")~~ + +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- simple batch with rollback transaction and rollback to savepoint +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + save tran sp1; + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + declare @err int = @@error; if @err = 0 select 0 else select 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran sp1 +rollback tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "simpleerrortable_a_key")~~ + +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- simple procedure +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "simpleerrortable_a_key")~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- simple batch with nested transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +commit tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "simpleerrortable_a_key")~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- simple procedure with transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "simpleerrortable_a_key")~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- simple procedure with transaction started inside procedure but ended outside procedure +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "simpleerrortable_a_key")~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +commit tran +GO +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- simple procedure with transaction started outside procedure but ended inside procedure through commit +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "simpleerrortable_a_key")~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- simple procedure with transaction started outside procedure but ended inside procedure through rollback +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "simpleerrortable_a_key")~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc1")~~ + +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- nested procedure (level 2) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "simpleerrortable_a_key")~~ + +~~ROW COUNT: 1~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +Pineapple#!#pink#!#7#!#Surat #!#Frown😠 #!#2000-12-13 12:58:23.123#!#123.1 +Cherry#!#indigo#!#8#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- nested procedure (level 3) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +create procedure simpleErrorProc3 +as +begin + SELECT 1; + exec simpleErrorProc2; + SELECT 2; +end +GO +exec simpleErrorProc3 +GO +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "simpleerrortable_a_key")~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +2 +~~END~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +Pineapple#!#pink#!#7#!#Surat #!#Frown😠 #!#2000-12-13 12:58:23.123#!#123.1 +Cherry#!#indigo#!#8#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +drop procedure simpleErrorProc3 +GO +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- nested procedure with commit transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + commit tran; +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "simpleerrortable_a_key")~~ + +~~ROW COUNT: 1~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +Pineapple#!#pink#!#7#!#Surat #!#Frown😠 #!#2000-12-13 12:58:23.123#!#123.1 +Cherry#!#indigo#!#8#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- nested procedure with rollback transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + rollback tran; +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "simpleerrortable_a_key")~~ + +~~ROW COUNT: 1~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc1")~~ + +drop procedure simpleErrorProc2 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc2")~~ + +truncate table simpleErrorTable +GO + +-- Error: data out of range for datetime +-- simple batch +INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +INSERT INTO t517_1 VALUES (DATEADD(YY,-300,getdate())); +declare @err int = @@error; if @err = 0 select 0 else select 1; +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 517)~~ + +~~ERROR (Message: data out of range for datetime)~~ + +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: data out of range for datetime +-- simple batch with commit transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO t517_1 VALUES (DATEADD(YY,-300,getdate())); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +commit tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 517)~~ + +~~ERROR (Message: data out of range for datetime)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: data out of range for datetime +-- simple batch with rollback transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO t517_1 VALUES (DATEADD(YY,-300,getdate())); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +rollback tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 517)~~ + +~~ERROR (Message: data out of range for datetime)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: data out of range for datetime +-- simple batch with rollback transaction and rollback to savepoint +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + save tran sp1; + INSERT INTO t517_1 VALUES (DATEADD(YY,-300,getdate())); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran sp1; +rollback tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 517)~~ + +~~ERROR (Message: data out of range for datetime)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: data out of range for datetime +-- simple procedure +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO t517_1 VALUES (DATEADD(YY,-300,getdate())); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 517)~~ + +~~ERROR (Message: data out of range for datetime)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: data out of range for datetime +-- simple batch with nested transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + INSERT INTO t517_1 VALUES (DATEADD(YY,-300,getdate())); + declare @err int = @@error; if @err = 0 select 0 else select 1; + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +commit tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 517)~~ + +~~ERROR (Message: data out of range for datetime)~~ + +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: data out of range for datetime +-- simple procedure with transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + INSERT INTO t517_1 VALUES (DATEADD(YY,-300,getdate())); + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 517)~~ + +~~ERROR (Message: data out of range for datetime)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: data out of range for datetime +-- simple procedure with transaction started inside procedure but ended outside procedure +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO t517_1 VALUES (DATEADD(YY,-300,getdate())); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 517)~~ + +~~ERROR (Message: data out of range for datetime)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +commit tran +GO +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: data out of range for datetime +-- simple procedure with transaction started outside procedure but ended inside procedure through commit +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO t517_1 VALUES (DATEADD(YY,-300,getdate())); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 517)~~ + +~~ERROR (Message: data out of range for datetime)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: data out of range for datetime +-- simple procedure with transaction started outside procedure but ended inside procedure through rollback +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO t517_1 VALUES (DATEADD(YY,-300,getdate())); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 517)~~ + +~~ERROR (Message: data out of range for datetime)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc1")~~ + +truncate table simpleErrorTable +GO + +-- Error: data out of range for datetime +-- nested procedure (level 2) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO t517_1 VALUES (DATEADD(YY,-300,getdate())); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 517)~~ + +~~ERROR (Message: data out of range for datetime)~~ + +~~ROW COUNT: 1~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +Pineapple#!#pink#!#7#!#Surat #!#Frown😠 #!#2000-12-13 12:58:23.123#!#123.1 +Cherry#!#indigo#!#8#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: data out of range for datetime +-- nested procedure (level 3) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO t517_1 VALUES (DATEADD(YY,-300,getdate())); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +create procedure simpleErrorProc3 +as +begin + SELECT 1; + exec simpleErrorProc2; + SELECT 2; +end +GO +exec simpleErrorProc3 +GO +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 517)~~ + +~~ERROR (Message: data out of range for datetime)~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +2 +~~END~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +Pineapple#!#pink#!#7#!#Surat #!#Frown😠 #!#2000-12-13 12:58:23.123#!#123.1 +Cherry#!#indigo#!#8#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +drop procedure simpleErrorProc3 +GO +truncate table simpleErrorTable +GO + +-- Error: data out of range for datetime +-- nested procedure with commit transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO t517_1 VALUES (DATEADD(YY,-300,getdate())); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + commit tran; +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 517)~~ + +~~ERROR (Message: data out of range for datetime)~~ + +~~ROW COUNT: 1~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +Pineapple#!#pink#!#7#!#Surat #!#Frown😠 #!#2000-12-13 12:58:23.123#!#123.1 +Cherry#!#indigo#!#8#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: data out of range for datetime +-- nested procedure with rollback transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO t517_1 VALUES (DATEADD(YY,-300,getdate())); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + rollback tran; +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 517)~~ + +~~ERROR (Message: data out of range for datetime)~~ + +~~ROW COUNT: 1~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc1")~~ + +drop procedure simpleErrorProc2 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc2")~~ + +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- simple batch +INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +UPDATE simpleErrorTable SET c = NULL WHERE c = 1; +declare @err int = @@error; if @err = 0 select 0 else select 1; +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "c" of relation "simpleerrortable" violates not-null constraint)~~ + +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- simple batch with commit transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + declare @err int = @@error; if @err = 0 select 0 else select 1; +commit tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "c" of relation "simpleerrortable" violates not-null constraint)~~ + +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- simple batch with rollback transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + declare @err int = @@error; if @err = 0 select 0 else select 1; +rollback tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "c" of relation "simpleerrortable" violates not-null constraint)~~ + +~~START~~ +int +0 +~~END~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- simple batch with rollback transaction and rollback to savepoint +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + save tran sp1; + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + declare @err int = @@error; if @err = 0 select 0 else select 1; + rollback tran sp1; +rollback tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "c" of relation "simpleerrortable" violates not-null constraint)~~ + +~~START~~ +int +0 +~~END~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- simple procedure +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "c" of relation "simpleerrortable" violates not-null constraint)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- simple batch with nested transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + declare @err int = @@error; if @err = 0 select 0 else select 1; +commit tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "c" of relation "simpleerrortable" violates not-null constraint)~~ + +~~START~~ +int +0 +~~END~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- simple procedure with transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "c" of relation "simpleerrortable" violates not-null constraint)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- simple procedure with transaction started inside procedure but ended outside procedure +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "c" of relation "simpleerrortable" violates not-null constraint)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +commit tran +GO +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- simple procedure with transaction started outside procedure but ended inside procedure through commit +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "c" of relation "simpleerrortable" violates not-null constraint)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- simple procedure with transaction started outside procedure but ended inside procedure through rollback +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "c" of relation "simpleerrortable" violates not-null constraint)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc1")~~ + +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- nested procedure (level 2) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "c" of relation "simpleerrortable" violates not-null constraint)~~ + +~~ROW COUNT: 1~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +Pineapple#!#pink#!#7#!#Surat #!#Frown😠 #!#2000-12-13 12:58:23.123#!#123.1 +Cherry#!#indigo#!#8#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- nested procedure (level 3) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +create procedure simpleErrorProc3 +as +begin + SELECT 1; + exec simpleErrorProc2; + SELECT 2; +end +GO +exec simpleErrorProc3 +GO +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "c" of relation "simpleerrortable" violates not-null constraint)~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +2 +~~END~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +Pineapple#!#pink#!#7#!#Surat #!#Frown😠 #!#2000-12-13 12:58:23.123#!#123.1 +Cherry#!#indigo#!#8#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +drop procedure simpleErrorProc3 +GO +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- nested procedure with commit transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + commit tran; +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "c" of relation "simpleerrortable" violates not-null constraint)~~ + +~~ROW COUNT: 1~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +Pineapple#!#pink#!#7#!#Surat #!#Frown😠 #!#2000-12-13 12:58:23.123#!#123.1 +Cherry#!#indigo#!#8#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- nested procedure with rollback transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + rollback tran; +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "c" of relation "simpleerrortable" violates not-null constraint)~~ + +~~ROW COUNT: 1~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc1")~~ + +drop procedure simpleErrorProc2 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc2")~~ + +truncate table simpleErrorTable +GO + + +-- Error: creating an existing table +-- simple batch +INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +CREATE TABLE simpleErrorTable (a int); +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2714)~~ + +~~ERROR (Message: relation "simpleerrortable" already exists)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- simple batch with commit transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2714)~~ + +~~ERROR (Message: relation "simpleerrortable" already exists)~~ + +commit tran; +GO +~~ERROR (Code: 3902)~~ + +~~ERROR (Message: COMMIT can only be used in transaction blocks)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- simple batch with rollback transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2714)~~ + +~~ERROR (Message: relation "simpleerrortable" already exists)~~ + +rollback tran; +GO +~~ERROR (Code: 3903)~~ + +~~ERROR (Message: ROLLBACK can only be used in transaction blocks)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- simple batch with rollback transaction and rollback to savepoint +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + save tran sp1; + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2714)~~ + +~~ERROR (Message: relation "simpleerrortable" already exists)~~ + +rollback tran sp1; +GO +~~ERROR (Code: 3903)~~ + +~~ERROR (Message: ROLLBACK TO SAVEPOINT can only be used in transaction blocks)~~ + +rollback tran; +GO +~~ERROR (Code: 3903)~~ + +~~ERROR (Message: ROLLBACK can only be used in transaction blocks)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- simple procedure +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2714)~~ + +~~ERROR (Message: relation "simpleerrortable" already exists)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +drop procedure simpleErrorProc1 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc1")~~ + +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- simple batch with nested transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + CREATE TABLE simpleErrorTable (a int); +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2714)~~ + +~~ERROR (Message: relation "simpleerrortable" already exists)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +commit tran; +GO +~~ERROR (Code: 3902)~~ + +~~ERROR (Message: COMMIT can only be used in transaction blocks)~~ + +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +GO +~~ROW COUNT: 1~~ + +commit tran; +GO +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- simple procedure with transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + CREATE TABLE simpleErrorTable (a int); + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2714)~~ + +~~ERROR (Message: relation "simpleerrortable" already exists)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc1")~~ + +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- simple procedure with transaction started inside procedure but ended outside procedure +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2714)~~ + +~~ERROR (Message: relation "simpleerrortable" already exists)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +commit tran +GO +~~ERROR (Code: 3902)~~ + +~~ERROR (Message: COMMIT can only be used in transaction blocks)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc1")~~ + +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- simple procedure with transaction started outside procedure but ended inside procedure through commit +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2714)~~ + +~~ERROR (Message: relation "simpleerrortable" already exists)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc1")~~ + +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- simple procedure with transaction started outside procedure but ended inside procedure through rollback +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2714)~~ + +~~ERROR (Message: relation "simpleerrortable" already exists)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc1")~~ + +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- nested procedure (level 2) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2714)~~ + +~~ERROR (Message: relation "simpleerrortable" already exists)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +drop procedure simpleErrorProc1 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc1")~~ + +drop procedure simpleErrorProc2 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc2")~~ + +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- nested procedure (level 3) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +create procedure simpleErrorProc3 +as +begin + SELECT 1; + exec simpleErrorProc2; + SELECT 2; +end +GO +exec simpleErrorProc3 +GO +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2714)~~ + +~~ERROR (Message: relation "simpleerrortable" already exists)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +drop procedure simpleErrorProc1 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc1")~~ + +drop procedure simpleErrorProc2 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc2")~~ + +drop procedure simpleErrorProc3 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc3")~~ + +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- nested procedure with commit transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + commit tran; +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2714)~~ + +~~ERROR (Message: relation "simpleerrortable" already exists)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc1")~~ + +drop procedure simpleErrorProc2 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc2")~~ + +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- nested procedure with rollback transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + rollback tran; +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2714)~~ + +~~ERROR (Message: relation "simpleerrortable" already exists)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc1")~~ + +drop procedure simpleErrorProc2 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc2")~~ + +truncate table simpleErrorTable +GO + + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- simple batch +INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +ALTER TABLE t1752_1 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; +declare @err int = @@error; if @err = 0 select 0 else select 1; +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 1752)~~ + +~~ERROR (Message: column "c3" of relation "t1752_1" is a generated column)~~ + +GO +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- simple batch with commit transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + ALTER TABLE t1752_1 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +commit tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 1752)~~ + +~~ERROR (Message: column "c3" of relation "t1752_1" is a generated column)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +select @@trancount +GO +~~START~~ +int +2 +~~END~~ + +commit tran +GO +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- simple batch with rollback transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + ALTER TABLE t1752_1 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +rollback tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 1752)~~ + +~~ERROR (Message: column "c3" of relation "t1752_1" is a generated column)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +select @@trancount +GO +~~START~~ +int +2 +~~END~~ + +commit tran +GO +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- simple batch with rollback transaction and rollback to savepoint +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + save tran sp1; + ALTER TABLE t1752_1 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran sp1; +rollback tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 1752)~~ + +~~ERROR (Message: column "c3" of relation "t1752_1" is a generated column)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +select @@trancount +GO +~~START~~ +int +2 +~~END~~ + +commit tran +GO +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- simple procedure +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + ALTER TABLE t1752_1 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 1752)~~ + +~~ERROR (Message: column "c3" of relation "t1752_1" is a generated column)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- simple batch with nested transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + ALTER TABLE t1752_1 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +commit tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 1752)~~ + +~~ERROR (Message: column "c3" of relation "t1752_1" is a generated column)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +select @@trancount +GO +~~START~~ +int +3 +~~END~~ + +commit tran +GO +select @@trancount +GO +~~START~~ +int +2 +~~END~~ + +commit tran +GO +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- simple procedure with transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + ALTER TABLE t1752_1 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 1752)~~ + +~~ERROR (Message: column "c3" of relation "t1752_1" is a generated column)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +select @@trancount +GO +~~START~~ +int +3 +~~END~~ + +commit tran +GO +select @@trancount +GO +~~START~~ +int +2 +~~END~~ + +commit tran +GO +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- simple procedure with transaction started inside procedure but ended outside procedure +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + ALTER TABLE t1752_1 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 1752)~~ + +~~ERROR (Message: column "c3" of relation "t1752_1" is a generated column)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +commit tran +GO +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- simple procedure with transaction started outside procedure but ended inside procedure through commit +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + ALTER TABLE t1752_1 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 1752)~~ + +~~ERROR (Message: column "c3" of relation "t1752_1" is a generated column)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +select @@trancount +GO +~~START~~ +int +2 +~~END~~ + +commit tran +GO +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- simple procedure with transaction started outside procedure but ended inside procedure through rollback +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + ALTER TABLE t1752_1 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 1752)~~ + +~~ERROR (Message: column "c3" of relation "t1752_1" is a generated column)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +select @@trancount +GO +~~START~~ +int +2 +~~END~~ + +commit tran +GO +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- nested procedure (level 2) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + ALTER TABLE t1752_1 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 1752)~~ + +~~ERROR (Message: column "c3" of relation "t1752_1" is a generated column)~~ + +~~ROW COUNT: 1~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Pineapple#!#pink#!#7#!#Surat #!#Frown😠 #!#2000-12-13 12:58:23.123#!#123.1 +Cherry#!#indigo#!#8#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- nested procedure (level 3) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + ALTER TABLE t1752_1 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +create procedure simpleErrorProc3 +as +begin + SELECT 1; + exec simpleErrorProc2; + SELECT 2; +end +GO +exec simpleErrorProc3 +GO +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 1752)~~ + +~~ERROR (Message: column "c3" of relation "t1752_1" is a generated column)~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +2 +~~END~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Pineapple#!#pink#!#7#!#Surat #!#Frown😠 #!#2000-12-13 12:58:23.123#!#123.1 +Cherry#!#indigo#!#8#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +drop procedure simpleErrorProc3 +GO +truncate table simpleErrorTable +GO + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- nested procedure with commit transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + ALTER TABLE t1752_1 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + commit tran; +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 1752)~~ + +~~ERROR (Message: column "c3" of relation "t1752_1" is a generated column)~~ + +~~ROW COUNT: 1~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Pineapple#!#pink#!#7#!#Surat #!#Frown😠 #!#2000-12-13 12:58:23.123#!#123.1 +Cherry#!#indigo#!#8#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +select @@trancount +GO +~~START~~ +int +2 +~~END~~ + +commit tran +GO +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: "column \"%s\" of relation \"%s\" is a generated column" +-- nested procedure with rollback transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + ALTER TABLE t1752_1 ADD CONSTRAINT constraint1752 DEFAULT 'test' FOR c3; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + rollback tran; +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 1752)~~ + +~~ERROR (Message: column "c3" of relation "t1752_1" is a generated column)~~ + +~~ROW COUNT: 1~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +commit tran +GO +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc1")~~ + +drop procedure simpleErrorProc2 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc2")~~ + +truncate table simpleErrorTable +GO + +-- Error: "A SELECT statement that assigns a value to a variable must not be +-- combined with data-retrieval operations" +-- simple batch +INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +DECLARE @a int; SELECT @a = c1, c2 FROM t141_1; +declare @err int = @@error; if @err = 0 select 0 else select 1; +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +GO +~~ERROR (Code: 141)~~ + +~~ERROR (Message: A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: "A SELECT statement that assigns a value to a variable must not be +-- combined with data-retrieval operations" +-- simple batch with commit transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + DECLARE @a int; SELECT @a = c1, c2 FROM t141_1; +GO +~~ERROR (Code: 141)~~ + +~~ERROR (Message: A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +commit tran; +GO +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: "A SELECT statement that assigns a value to a variable must not be +-- combined with data-retrieval operations" +-- simple batch with rollback transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + DECLARE @a int; SELECT @a = c1, c2 FROM t141_1; +GO +~~ERROR (Code: 141)~~ + +~~ERROR (Message: A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +rollback tran; +GO +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: "A SELECT statement that assigns a value to a variable must not be +-- combined with data-retrieval operations" +-- simple batch with rollback transaction and rollback to savepoint +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + save tran sp1; + DECLARE @a int; SELECT @a = c1, c2 FROM t141_1; +GO +~~ERROR (Code: 141)~~ + +~~ERROR (Message: A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations)~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +rollback tran sp1; +GO +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 6401)~~ + +~~ERROR (Message: savepoint "sp1" does not exist)~~ + +rollback tran; +GO +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +truncate table simpleErrorTable +GO + + +-- Error: "A SELECT statement that assigns a value to a variable must not be +-- combined with data-retrieval operations" +-- simple procedure with transaction started outside procedure but ended inside procedure through commit +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + DECLARE @a int; SELECT @a = c1, c2 FROM t141_1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +~~ERROR (Code: 141)~~ + +~~ERROR (Message: A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations)~~ + +begin tran +GO +DECLARE @a tinyint = 1000; +GO +~~ERROR (Code: 220)~~ + +~~ERROR (Message: value for domain tinyint violates check constraint "tinyint_check")~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +2 +~~END~~ + +commit tran +GO +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc1")~~ + +truncate table simpleErrorTable +GO + +-- Error: "A SELECT statement that assigns a value to a variable must not be +-- combined with data-retrieval operations" +-- simple procedure with transaction started outside procedure but ended inside procedure through rollback +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + DECLARE @a int; SELECT @a = c1, c2 FROM t141_1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +~~ERROR (Code: 141)~~ + +~~ERROR (Message: A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations)~~ + +begin tran +GO +DECLARE @a tinyint = 1000; +GO +~~ERROR (Code: 220)~~ + +~~ERROR (Message: value for domain tinyint violates check constraint "tinyint_check")~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +2 +~~END~~ + +commit tran +GO +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc1")~~ + +truncate table simpleErrorTable +GO + +-- Error: "A SELECT statement that assigns a value to a variable must not be +-- combined with data-retrieval operations" +-- nested procedure (level 2) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + DECLARE @a int; SELECT @a = c1, c2 FROM t141_1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +~~ERROR (Code: 141)~~ + +~~ERROR (Message: A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations)~~ + +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + DECLARE @a tinyint = 1000; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 220)~~ + +~~ERROR (Message: value for domain tinyint violates check constraint "tinyint_check")~~ + +~~ROW COUNT: 1~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Pineapple#!#pink#!#7#!#Surat #!#Frown😠 #!#2000-12-13 12:58:23.123#!#123.1 +Cherry#!#indigo#!#8#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: "A SELECT statement that assigns a value to a variable must not be +-- combined with data-retrieval operations" +-- nested procedure (level 3) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + DECLARE @a int; SELECT @a = c1, c2 FROM t141_1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +~~ERROR (Code: 141)~~ + +~~ERROR (Message: A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations)~~ + +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + DECLARE @a tinyint = 1000; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +create procedure simpleErrorProc3 +as +begin + SELECT 1; + exec simpleErrorProc2; + SELECT 2; +end +GO +exec simpleErrorProc3 +GO +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 220)~~ + +~~ERROR (Message: value for domain tinyint violates check constraint "tinyint_check")~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +2 +~~END~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Pineapple#!#pink#!#7#!#Surat #!#Frown😠 #!#2000-12-13 12:58:23.123#!#123.1 +Cherry#!#indigo#!#8#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +drop procedure simpleErrorProc2 +GO +drop procedure simpleErrorProc3 +GO +truncate table simpleErrorTable +GO + +-- Error: "A SELECT statement that assigns a value to a variable must not be +-- combined with data-retrieval operations" +-- nested procedure with commit transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + DECLARE @a int; SELECT @a = c1, c2 FROM t141_1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +~~ERROR (Code: 141)~~ + +~~ERROR (Message: A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations)~~ + +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + DECLARE @a tinyint = 1000; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + commit tran; +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 220)~~ + +~~ERROR (Message: value for domain tinyint violates check constraint "tinyint_check")~~ + +~~ROW COUNT: 1~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Pineapple#!#pink#!#7#!#Surat #!#Frown😠 #!#2000-12-13 12:58:23.123#!#123.1 +Cherry#!#indigo#!#8#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: "A SELECT statement that assigns a value to a variable must not be +-- combined with data-retrieval operations" +-- nested procedure with rollback transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + DECLARE @a int; SELECT @a = c1, c2 FROM t141_1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +~~ERROR (Code: 141)~~ + +~~ERROR (Message: A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations)~~ + +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + DECLARE @a tinyint = 1000; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + rollback tran; +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 220)~~ + +~~ERROR (Message: value for domain tinyint violates check constraint "tinyint_check")~~ + +~~ROW COUNT: 1~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +drop procedure simpleErrorProc2 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc2")~~ + +truncate table simpleErrorTable +GO + +select @@trancount; +GO +~~START~~ +int +1 +~~END~~ + + +if @@trancount > 0 commit tran; +GO + +-- Error: value for domain tinyint violates check constraint "tinyint_check" +INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +DECLARE @a tinyint = 1000; +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 220)~~ + +~~ERROR (Message: value for domain tinyint violates check constraint "tinyint_check")~~ + +~~ROW COUNT: 1~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +drop procedure simpleErrorProc1 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc1")~~ + +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- simple batch +INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33685634)~~ + +~~ERROR (Message: invalid input syntax for type integer: "abc")~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- simple batch with commit transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33685634)~~ + +~~ERROR (Message: invalid input syntax for type integer: "abc")~~ + +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +commit tran; +GO +~~ROW COUNT: 1~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- simple batch with rollback transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33685634)~~ + +~~ERROR (Message: invalid input syntax for type integer: "abc")~~ + +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +rollback tran; +GO +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "simpleerrortable_pkey")~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- simple batch with rollback transaction and rollback to savepoint +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + save tran sp1; + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33685634)~~ + +~~ERROR (Message: invalid input syntax for type integer: "abc")~~ + +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +rollback tran sp1; +GO +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "simpleerrortable_pkey")~~ + +rollback tran; +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- simple procedure +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33685634)~~ + +~~ERROR (Message: invalid input syntax for type integer: "abc")~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +drop procedure simpleErrorProc1 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc1")~~ + +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- simple batch with nested transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33685634)~~ + +~~ERROR (Message: invalid input syntax for type integer: "abc")~~ + +commit tran; +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +GO +~~ERROR (Code: 3902)~~ + +~~ERROR (Message: COMMIT can only be used in transaction blocks)~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "simpleerrortable_pkey")~~ + +commit tran; +GO +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +0 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- simple procedure with transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33685634)~~ + +~~ERROR (Message: invalid input syntax for type integer: "abc")~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc1")~~ + +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- simple procedure with transaction started inside procedure but ended outside procedure +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33685634)~~ + +~~ERROR (Message: invalid input syntax for type integer: "abc")~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +commit tran +GO +~~ERROR (Code: 3902)~~ + +~~ERROR (Message: COMMIT can only be used in transaction blocks)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc1")~~ + +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- simple procedure with transaction started outside procedure but ended inside procedure through commit +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33685634)~~ + +~~ERROR (Message: invalid input syntax for type integer: "abc")~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc1")~~ + +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- simple procedure with transaction started outside procedure but ended inside procedure through rollback +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33685634)~~ + +~~ERROR (Message: invalid input syntax for type integer: "abc")~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc1")~~ + +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- nested procedure (level 2) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33685634)~~ + +~~ERROR (Message: invalid input syntax for type integer: "abc")~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +drop procedure simpleErrorProc1 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc1")~~ + +drop procedure simpleErrorProc2 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc2")~~ + +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- nested procedure (level 3) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +create procedure simpleErrorProc3 +as +begin + SELECT 1; + exec simpleErrorProc2; + SELECT 2; +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33685634)~~ + +~~ERROR (Message: invalid input syntax for type integer: "abc")~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +drop procedure simpleErrorProc1 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc1")~~ + +drop procedure simpleErrorProc2 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc2")~~ + +drop procedure simpleErrorProc3 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc3")~~ + +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- nested procedure with commit transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + commit tran; +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33685634)~~ + +~~ERROR (Message: invalid input syntax for type integer: "abc")~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc1")~~ + +drop procedure simpleErrorProc2 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc2")~~ + +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- nested procedure with rollback transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + rollback tran; +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33685634)~~ + +~~ERROR (Message: invalid input syntax for type integer: "abc")~~ + +declare @err int = @@error; if @err = 0 select 0 else select 1; +GO +~~START~~ +int +1 +~~END~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.99#!#342.5 +~~END~~ + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc1")~~ + +drop procedure simpleErrorProc2 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc2")~~ + +truncate table simpleErrorTable +GO + +-- cleanup for "data out of range for datetime" error +DROP TABLE t517_1; +GO + +-- clean up for "A SELECT statement that assigns a value to a variable must not +-- be combined with data-retrieval operations" error +DROP TABLE t141_1; +GO + +-- setup for "column \"%s\" of relation \"%s\" is a generated column" +DROP TABLE t1752_1; +GO + +drop table simpleErrorTable +GO + +while (@@trancount > 0) commit tran; +GO + + +#Cleanup +IF @@trancount > 0 ROLLBACK +SET IMPLICIT_TRANSACTIONS OFF diff --git a/contrib/test/JDBC/sql_expected/TestSimpleErrorsWithXactAbort.out b/contrib/test/JDBC/sql_expected/TestSimpleErrorsWithXactAbort.out new file mode 100644 index 00000000000..e194f7dd702 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/TestSimpleErrorsWithXactAbort.out @@ -0,0 +1,4022 @@ +SET XACT_ABORT ON +GO + +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_unique_constraint', 'ignore'; +GO + +CREATE TABLE simpleErrorTable (a varchar(15) UNIQUE, b nvarchar(25), c int PRIMARY KEY, d char(15) DEFAULT 'Whoops!', e nchar(25), f datetime, g numeric(4,1) CHECK (g >= 103.5)) +GO + +-- Error: duplicate key value violates unique constraint +-- simple batch +INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "simpleerrortable_a_key")~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- simple batch with commit transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +commit tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "simpleerrortable_a_key")~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- simple batch with rollback transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +rollback tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "simpleerrortable_a_key")~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- simple batch with rollback transaction and rollback to savepoint +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + save tran sp1; + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran sp1 +rollback tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "simpleerrortable_a_key")~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- simple procedure +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "simpleerrortable_a_key")~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- simple batch with nested transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +commit tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "simpleerrortable_a_key")~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- simple procedure with transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "simpleerrortable_a_key")~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- simple procedure with transaction started inside procedure but ended outside procedure +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "simpleerrortable_a_key")~~ + +commit tran +GO +~~ERROR (Code: 3902)~~ + +~~ERROR (Message: COMMIT can only be used in transaction blocks)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- simple procedure with transaction started outside procedure but ended inside procedure through commit +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "simpleerrortable_a_key")~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- simple procedure with transaction started outside procedure but ended inside procedure through rollback +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "simpleerrortable_a_key")~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- nested procedure (level 2) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "simpleerrortable_a_key")~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Pineapple#!#pink#!#7#!#Surat #!#Frown😠 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- nested procedure (level 3) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +create procedure simpleErrorProc3 +as +begin + SELECT 1; + exec simpleErrorProc2; + SELECT 2; +end +GO +exec simpleErrorProc3 +GO +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "simpleerrortable_a_key")~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Pineapple#!#pink#!#7#!#Surat #!#Frown😠 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +drop procedure simpleErrorProc3 +GO +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- nested procedure with commit transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + commit tran; +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "simpleerrortable_a_key")~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: duplicate key value violates unique constraint +-- nested procedure with rollback transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + INSERT INTO simpleErrorTable VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + rollback tran; +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "simpleerrortable_a_key")~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + + +-- Error: check constraint violation +-- simple batch +INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +UPDATE simpleErrorTable SET g = 101.4 WHERE c = 1; +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 67391682)~~ + +~~ERROR (Message: new row for relation "simpleerrortable" violates check constraint "simpleerrortable_g_check")~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: check constraint violation +-- simple batch with commit transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET g = 101.4 WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +commit tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 67391682)~~ + +~~ERROR (Message: new row for relation "simpleerrortable" violates check constraint "simpleerrortable_g_check")~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: check constraint violation +-- simple batch with rollback transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET g = 101.4 WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +rollback tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 67391682)~~ + +~~ERROR (Message: new row for relation "simpleerrortable" violates check constraint "simpleerrortable_g_check")~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: check constraint violation +-- simple batch with rollback transaction and rollback to savepoint +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + save tran sp1; + UPDATE simpleErrorTable SET g = 101.4 WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran sp1; +rollback tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 67391682)~~ + +~~ERROR (Message: new row for relation "simpleerrortable" violates check constraint "simpleerrortable_g_check")~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: check constraint violation +-- simple procedure +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET g = 101.4 WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 67391682)~~ + +~~ERROR (Message: new row for relation "simpleerrortable" violates check constraint "simpleerrortable_g_check")~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: check constraint violation +-- simple batch with nested transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + UPDATE simpleErrorTable SET g = 101.4 WHERE c = 1; + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +commit tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 67391682)~~ + +~~ERROR (Message: new row for relation "simpleerrortable" violates check constraint "simpleerrortable_g_check")~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: check constraint violation +-- simple procedure with transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + UPDATE simpleErrorTable SET g = 101.4 WHERE c = 1; + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 67391682)~~ + +~~ERROR (Message: new row for relation "simpleerrortable" violates check constraint "simpleerrortable_g_check")~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: check constraint violation +-- simple procedure with transaction started inside procedure but ended outside procedure +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET g = 101.4 WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 67391682)~~ + +~~ERROR (Message: new row for relation "simpleerrortable" violates check constraint "simpleerrortable_g_check")~~ + +commit tran +GO +~~ERROR (Code: 3902)~~ + +~~ERROR (Message: COMMIT can only be used in transaction blocks)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: check constraint violation +-- simple procedure with transaction started outside procedure but ended inside procedure through commit +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET g = 101.4 WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 67391682)~~ + +~~ERROR (Message: new row for relation "simpleerrortable" violates check constraint "simpleerrortable_g_check")~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: check constraint violation +-- simple procedure with transaction started outside procedure but ended inside procedure through rollback +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET g = 101.4 WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 67391682)~~ + +~~ERROR (Message: new row for relation "simpleerrortable" violates check constraint "simpleerrortable_g_check")~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: check constraint violation +-- nested procedure (level 2) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET g = 101.4 WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 67391682)~~ + +~~ERROR (Message: new row for relation "simpleerrortable" violates check constraint "simpleerrortable_g_check")~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Pineapple#!#pink#!#7#!#Surat #!#Frown😠 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: check constraint violation +-- nested procedure (level 3) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET g = 101.4 WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +create procedure simpleErrorProc3 +as +begin + SELECT 1; + exec simpleErrorProc2; + SELECT 2; +end +GO +exec simpleErrorProc3 +GO +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 67391682)~~ + +~~ERROR (Message: new row for relation "simpleerrortable" violates check constraint "simpleerrortable_g_check")~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Pineapple#!#pink#!#7#!#Surat #!#Frown😠 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +drop procedure simpleErrorProc3 +GO +truncate table simpleErrorTable +GO + +-- Error: check constraint violation +-- nested procedure with commit transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET g = 101.4 WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + commit tran; +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 67391682)~~ + +~~ERROR (Message: new row for relation "simpleerrortable" violates check constraint "simpleerrortable_g_check")~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: check constraint violation +-- nested procedure with rollback transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET g = 101.4 WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + rollback tran; +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 67391682)~~ + +~~ERROR (Message: new row for relation "simpleerrortable" violates check constraint "simpleerrortable_g_check")~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + + +-- Error: not null constraint violation +-- simple batch +INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +UPDATE simpleErrorTable SET c = NULL WHERE c = 1; +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "c" of relation "simpleerrortable" violates not-null constraint)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- simple batch with commit transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +commit tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "c" of relation "simpleerrortable" violates not-null constraint)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- simple batch with rollback transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +rollback tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "c" of relation "simpleerrortable" violates not-null constraint)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- simple batch with rollback transaction and rollback to savepoint +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + save tran sp1; + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran sp1; +rollback tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "c" of relation "simpleerrortable" violates not-null constraint)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- simple procedure +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "c" of relation "simpleerrortable" violates not-null constraint)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- simple batch with nested transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +commit tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "c" of relation "simpleerrortable" violates not-null constraint)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- simple procedure with transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "c" of relation "simpleerrortable" violates not-null constraint)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- simple procedure with transaction started inside procedure but ended outside procedure +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "c" of relation "simpleerrortable" violates not-null constraint)~~ + +commit tran +GO +~~ERROR (Code: 3902)~~ + +~~ERROR (Message: COMMIT can only be used in transaction blocks)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- simple procedure with transaction started outside procedure but ended inside procedure through commit +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "c" of relation "simpleerrortable" violates not-null constraint)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- simple procedure with transaction started outside procedure but ended inside procedure through rollback +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "c" of relation "simpleerrortable" violates not-null constraint)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- nested procedure (level 2) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "c" of relation "simpleerrortable" violates not-null constraint)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Pineapple#!#pink#!#7#!#Surat #!#Frown😠 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- nested procedure (level 3) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +create procedure simpleErrorProc3 +as +begin + SELECT 1; + exec simpleErrorProc2; + SELECT 2; +end +GO +exec simpleErrorProc3 +GO +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "c" of relation "simpleerrortable" violates not-null constraint)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Pineapple#!#pink#!#7#!#Surat #!#Frown😠 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +drop procedure simpleErrorProc3 +GO +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- nested procedure with commit transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + commit tran; +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "c" of relation "simpleerrortable" violates not-null constraint)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: not null constraint violation +-- nested procedure with rollback transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + rollback tran; +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "c" of relation "simpleerrortable" violates not-null constraint)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + + +-- Error: creating an existing table +-- simple batch +INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +CREATE TABLE simpleErrorTable (a int); +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2714)~~ + +~~ERROR (Message: relation "simpleerrortable" already exists)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- simple batch with commit transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +commit tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2714)~~ + +~~ERROR (Message: relation "simpleerrortable" already exists)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- simple batch with rollback transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +rollback tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2714)~~ + +~~ERROR (Message: relation "simpleerrortable" already exists)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- simple batch with rollback transaction and rollback to savepoint +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + save tran sp1; + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran sp1; +rollback tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2714)~~ + +~~ERROR (Message: relation "simpleerrortable" already exists)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- simple procedure +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2714)~~ + +~~ERROR (Message: relation "simpleerrortable" already exists)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- simple batch with nested transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + CREATE TABLE simpleErrorTable (a int); + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +commit tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2714)~~ + +~~ERROR (Message: relation "simpleerrortable" already exists)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- simple procedure with transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + CREATE TABLE simpleErrorTable (a int); + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2714)~~ + +~~ERROR (Message: relation "simpleerrortable" already exists)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- simple procedure with transaction started inside procedure but ended outside procedure +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2714)~~ + +~~ERROR (Message: relation "simpleerrortable" already exists)~~ + +commit tran +GO +~~ERROR (Code: 3902)~~ + +~~ERROR (Message: COMMIT can only be used in transaction blocks)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- simple procedure with transaction started outside procedure but ended inside procedure through commit +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2714)~~ + +~~ERROR (Message: relation "simpleerrortable" already exists)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- simple procedure with transaction started outside procedure but ended inside procedure through rollback +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2714)~~ + +~~ERROR (Message: relation "simpleerrortable" already exists)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- nested procedure (level 2) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2714)~~ + +~~ERROR (Message: relation "simpleerrortable" already exists)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Pineapple#!#pink#!#7#!#Surat #!#Frown😠 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- nested procedure (level 3) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +create procedure simpleErrorProc3 +as +begin + SELECT 1; + exec simpleErrorProc2; + SELECT 2; +end +GO +exec simpleErrorProc3 +GO +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2714)~~ + +~~ERROR (Message: relation "simpleerrortable" already exists)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Pineapple#!#pink#!#7#!#Surat #!#Frown😠 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +drop procedure simpleErrorProc3 +GO +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- nested procedure with commit transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + commit tran; +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2714)~~ + +~~ERROR (Message: relation "simpleerrortable" already exists)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: creating an existing table +-- nested procedure with rollback transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + CREATE TABLE simpleErrorTable (a int); + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + rollback tran; +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2714)~~ + +~~ERROR (Message: relation "simpleerrortable" already exists)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + + +-- Error: deleting values from a table that does not exist +-- simple batch +INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +DELETE FROM simpleErrorTable1 WHERE c = 1; +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 208)~~ + +~~ERROR (Message: relation "simpleerrortable1" does not exist)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: deleting values from a table that does not exist +-- simple batch with commit transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + DELETE FROM simpleErrorTable1 WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +commit tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 208)~~ + +~~ERROR (Message: relation "simpleerrortable1" does not exist)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +commit tran +GO +~~ERROR (Code: 3902)~~ + +~~ERROR (Message: COMMIT can only be used in transaction blocks)~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: deleting values from a table that does not exist +-- simple batch with rollback transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + DELETE FROM simpleErrorTable1 WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +rollback tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 208)~~ + +~~ERROR (Message: relation "simpleerrortable1" does not exist)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +commit tran +GO +~~ERROR (Code: 3902)~~ + +~~ERROR (Message: COMMIT can only be used in transaction blocks)~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: deleting values from a table that does not exist +-- simple batch with rollback transaction and rollback to savepoint +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + save tran sp1; + DELETE FROM simpleErrorTable1 WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran sp1; +rollback tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 208)~~ + +~~ERROR (Message: relation "simpleerrortable1" does not exist)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +commit tran +GO +~~ERROR (Code: 3902)~~ + +~~ERROR (Message: COMMIT can only be used in transaction blocks)~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: deleting values from a table that does not exist +-- simple procedure +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + DELETE FROM simpleErrorTable1 WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 208)~~ + +~~ERROR (Message: relation "simpleerrortable1" does not exist)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: deleting values from a table that does not exist +-- simple batch with nested transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + DELETE FROM simpleErrorTable1 WHERE c = 1; + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +commit tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 208)~~ + +~~ERROR (Message: relation "simpleerrortable1" does not exist)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +commit tran +GO +~~ERROR (Code: 3902)~~ + +~~ERROR (Message: COMMIT can only be used in transaction blocks)~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +commit tran +GO +~~ERROR (Code: 3902)~~ + +~~ERROR (Message: COMMIT can only be used in transaction blocks)~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: deleting values from a table that does not exist +-- simple procedure with transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + DELETE FROM simpleErrorTable1 WHERE c = 1; + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 208)~~ + +~~ERROR (Message: relation "simpleerrortable1" does not exist)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +commit tran +GO +~~ERROR (Code: 3902)~~ + +~~ERROR (Message: COMMIT can only be used in transaction blocks)~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +commit tran +GO +~~ERROR (Code: 3902)~~ + +~~ERROR (Message: COMMIT can only be used in transaction blocks)~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: deleting values from a table that does not exist +-- simple procedure with transaction started inside procedure but ended outside procedure +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + DELETE FROM simpleErrorTable1 WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 208)~~ + +~~ERROR (Message: relation "simpleerrortable1" does not exist)~~ + +commit tran +GO +~~ERROR (Code: 3902)~~ + +~~ERROR (Message: COMMIT can only be used in transaction blocks)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: deleting values from a table that does not exist +-- simple procedure with transaction started outside procedure but ended inside procedure through commit +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + DELETE FROM simpleErrorTable1 WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 208)~~ + +~~ERROR (Message: relation "simpleerrortable1" does not exist)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +commit tran +GO +~~ERROR (Code: 3902)~~ + +~~ERROR (Message: COMMIT can only be used in transaction blocks)~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: deleting values from a table that does not exist +-- simple procedure with transaction started outside procedure but ended inside procedure through rollback +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + DELETE FROM simpleErrorTable1 WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 208)~~ + +~~ERROR (Message: relation "simpleerrortable1" does not exist)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +commit tran +GO +~~ERROR (Code: 3902)~~ + +~~ERROR (Message: COMMIT can only be used in transaction blocks)~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: deleting values from a table that does not exist +-- nested procedure (level 2) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + DELETE FROM simpleErrorTable1 WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 208)~~ + +~~ERROR (Message: relation "simpleerrortable1" does not exist)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Pineapple#!#pink#!#7#!#Surat #!#Frown😠 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: deleting values from a table that does not exist +-- nested procedure (level 3) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + DELETE FROM simpleErrorTable1 WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +create procedure simpleErrorProc3 +as +begin + SELECT 1; + exec simpleErrorProc2; + SELECT 2; +end +GO +exec simpleErrorProc3 +GO +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 208)~~ + +~~ERROR (Message: relation "simpleerrortable1" does not exist)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Pineapple#!#pink#!#7#!#Surat #!#Frown😠 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +drop procedure simpleErrorProc3 +GO +truncate table simpleErrorTable +GO + +-- Error: deleting values from a table that does not exist +-- nested procedure with commit transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + DELETE FROM simpleErrorTable1 WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + commit tran; +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 208)~~ + +~~ERROR (Message: relation "simpleerrortable1" does not exist)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +commit tran +GO +~~ERROR (Code: 3902)~~ + +~~ERROR (Message: COMMIT can only be used in transaction blocks)~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: deleting values from a table that does not exist +-- nested procedure with rollback transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + DELETE FROM simpleErrorTable1 WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + rollback tran; +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 208)~~ + +~~ERROR (Message: relation "simpleerrortable1" does not exist)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +commit tran +GO +~~ERROR (Code: 3902)~~ + +~~ERROR (Message: COMMIT can only be used in transaction blocks)~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + + +-- Error: syntax error +-- simple batch +INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +UPDATE1 simpleErrorTable SET c = NULL WHERE c = 1; +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +GO +~~ERROR (Code: 16801924)~~ + +~~ERROR (Message: syntax error near 'simpleErrorTable' at line 4 and character position 8)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: syntax error +-- simple batch with commit transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE1 simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +commit tran; +GO +~~ERROR (Code: 16801924)~~ + +~~ERROR (Message: syntax error near 'simpleErrorTable' at line 5 and character position 12)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: syntax error +-- simple batch with rollback transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE1 simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +rollback tran; +GO +~~ERROR (Code: 16801924)~~ + +~~ERROR (Message: syntax error near 'simpleErrorTable' at line 5 and character position 12)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: syntax error +-- simple batch with rollback transaction and rollback to savepoint +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + save tran sp1; + UPDATE1 simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran sp1; +rollback tran; +GO +~~ERROR (Code: 16801924)~~ + +~~ERROR (Message: syntax error near 'simpleErrorTable' at line 6 and character position 12)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: syntax error +-- simple procedure +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE1 simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +~~ERROR (Code: 16801924)~~ + +~~ERROR (Message: syntax error near 'simpleErrorTable' at line 7 and character position 12)~~ + +exec simpleErrorProc1 +GO +~~ERROR (Code: 52461700)~~ + +~~ERROR (Message: procedure simpleerrorproc1() does not exist)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +drop procedure simpleErrorProc1 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc1")~~ + +truncate table simpleErrorTable +GO + +-- Error: syntax error +-- simple batch with nested transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + UPDATE1 simpleErrorTable SET c = NULL WHERE c = 1; + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +commit tran; +GO +~~ERROR (Code: 16801924)~~ + +~~ERROR (Message: syntax error near 'simpleErrorTable' at line 6 and character position 16)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: syntax error +-- simple procedure with transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + UPDATE1 simpleErrorTable SET c = NULL WHERE c = 1; + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +~~ERROR (Code: 16801924)~~ + +~~ERROR (Message: syntax error near 'simpleErrorTable' at line 9 and character position 24)~~ + +exec simpleErrorProc1 +GO +~~ERROR (Code: 52461700)~~ + +~~ERROR (Message: procedure simpleerrorproc1() does not exist)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc1")~~ + +truncate table simpleErrorTable +GO + +-- Error: syntax error +-- simple procedure with transaction started inside procedure but ended outside procedure +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE1 simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +~~ERROR (Code: 16801924)~~ + +~~ERROR (Message: syntax error near 'simpleErrorTable' at line 8 and character position 16)~~ + +exec simpleErrorProc1 +GO +~~ERROR (Code: 52461700)~~ + +~~ERROR (Message: procedure simpleerrorproc1() does not exist)~~ + +commit tran +GO +~~ERROR (Code: 3902)~~ + +~~ERROR (Message: COMMIT can only be used in transaction blocks)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc1")~~ + +truncate table simpleErrorTable +GO + +-- Error: syntax error +-- simple procedure with transaction started outside procedure but ended inside procedure through commit +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE1 simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +~~ERROR (Code: 16801924)~~ + +~~ERROR (Message: syntax error near 'simpleErrorTable' at line 7 and character position 12)~~ + +begin tran +GO +exec simpleErrorProc1 +GO +~~ERROR (Code: 52461700)~~ + +~~ERROR (Message: procedure simpleerrorproc1() does not exist)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +commit tran +GO +~~ERROR (Code: 3902)~~ + +~~ERROR (Message: COMMIT can only be used in transaction blocks)~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc1")~~ + +truncate table simpleErrorTable +GO + +-- Error: syntax error +-- simple procedure with transaction started outside procedure but ended inside procedure through rollback +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE1 simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +~~ERROR (Code: 16801924)~~ + +~~ERROR (Message: syntax error near 'simpleErrorTable' at line 7 and character position 12)~~ + +begin tran +GO +exec simpleErrorProc1 +GO +~~ERROR (Code: 52461700)~~ + +~~ERROR (Message: procedure simpleerrorproc1() does not exist)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +commit tran +GO +~~ERROR (Code: 3902)~~ + +~~ERROR (Message: COMMIT can only be used in transaction blocks)~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc1")~~ + +truncate table simpleErrorTable +GO + +-- Error: syntax error +-- nested procedure (level 2) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE1 simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +~~ERROR (Code: 16801924)~~ + +~~ERROR (Message: syntax error near 'simpleErrorTable' at line 7 and character position 12)~~ + +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 52461700)~~ + +~~ERROR (Message: procedure simpleerrorproc1() does not exist)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Pineapple#!#pink#!#7#!#Surat #!#Frown😠 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc1")~~ + +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: syntax error +-- nested procedure (level 3) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE1 simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +~~ERROR (Code: 16801924)~~ + +~~ERROR (Message: syntax error near 'simpleErrorTable' at line 7 and character position 12)~~ + +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +create procedure simpleErrorProc3 +as +begin + SELECT 1; + exec simpleErrorProc2; + SELECT 2; +end +GO +exec simpleErrorProc3 +GO +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 52461700)~~ + +~~ERROR (Message: procedure simpleerrorproc1() does not exist)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Pineapple#!#pink#!#7#!#Surat #!#Frown😠 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc1")~~ + +drop procedure simpleErrorProc2 +GO +drop procedure simpleErrorProc3 +GO +truncate table simpleErrorTable +GO + +-- Error: syntax error +-- nested procedure with commit transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE1 simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +~~ERROR (Code: 16801924)~~ + +~~ERROR (Message: syntax error near 'simpleErrorTable' at line 8 and character position 16)~~ + +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + commit tran; +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 52461700)~~ + +~~ERROR (Message: procedure simpleerrorproc1() does not exist)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc1")~~ + +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: syntax error +-- nested procedure with rollback transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + UPDATE1 simpleErrorTable SET c = NULL WHERE c = 1; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +~~ERROR (Code: 16801924)~~ + +~~ERROR (Message: syntax error near 'simpleErrorTable' at line 8 and character position 16)~~ + +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + rollback tran; +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 52461700)~~ + +~~ERROR (Message: procedure simpleerrorproc1() does not exist)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "simpleerrorproc1")~~ + +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + + +-- Error: conversion error and executing stored procedure using sp_executesql +-- simple batch +INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; +INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33685634)~~ + +~~ERROR (Message: invalid input syntax for type integer: "abc")~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- simple batch with commit transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +commit tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33685634)~~ + +~~ERROR (Message: invalid input syntax for type integer: "abc")~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- simple batch with rollback transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +rollback tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33685634)~~ + +~~ERROR (Message: invalid input syntax for type integer: "abc")~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- simple batch with rollback transaction and rollback to savepoint +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + save tran sp1; + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran sp1; +rollback tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33685634)~~ + +~~ERROR (Message: invalid input syntax for type integer: "abc")~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- simple procedure +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33685634)~~ + +~~ERROR (Message: invalid input syntax for type integer: "abc")~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- simple batch with nested transaction +begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +commit tran; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33685634)~~ + +~~ERROR (Message: invalid input syntax for type integer: "abc")~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- simple procedure with transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + begin tran; + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; + commit tran; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33685634)~~ + +~~ERROR (Message: invalid input syntax for type integer: "abc")~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- simple procedure with transaction started inside procedure but ended outside procedure +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33685634)~~ + +~~ERROR (Message: invalid input syntax for type integer: "abc")~~ + +commit tran +GO +~~ERROR (Code: 3902)~~ + +~~ERROR (Message: COMMIT can only be used in transaction blocks)~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- simple procedure with transaction started outside procedure but ended inside procedure through commit +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33685634)~~ + +~~ERROR (Message: invalid input syntax for type integer: "abc")~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- simple procedure with transaction started outside procedure but ended inside procedure through rollback +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +begin tran +GO +exec simpleErrorProc1 +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33685634)~~ + +~~ERROR (Message: invalid input syntax for type integer: "abc")~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- nested procedure (level 2) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33685634)~~ + +~~ERROR (Message: invalid input syntax for type integer: "abc")~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Pineapple#!#pink#!#7#!#Surat #!#Frown😠 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- nested procedure (level 3) +create procedure simpleErrorProc1 +as +begin + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +end +GO +create procedure simpleErrorProc2 +as +begin + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +end +GO +create procedure simpleErrorProc3 +as +begin + SELECT 1; + exec simpleErrorProc2; + SELECT 2; +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33685634)~~ + +~~ERROR (Message: invalid input syntax for type integer: "abc")~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123#!#123.1 +Pineapple#!#pink#!#7#!#Surat #!#Frown😠 #!#2000-12-13 12:58:23.123#!#123.1 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +drop procedure simpleErrorProc3 +GO +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- nested procedure with commit transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + commit tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + commit tran; +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33685634)~~ + +~~ERROR (Message: invalid input syntax for type integer: "abc")~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- Error: conversion error and executing stored procedure using sp_executesql +-- nested procedure with rollback transaction +create procedure simpleErrorProc1 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + EXECUTE sp_executesql N'UPDATE simpleErrorTable SET a = convert(int, ''abc'') WHERE c = 1;'; + INSERT INTO simpleErrorTable(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + rollback tran; +end +GO +create procedure simpleErrorProc2 +as +begin + begin tran; + INSERT INTO simpleErrorTable VALUES ('Pineapple', N'pink', 7, 'Surat', N'Frown😠', '2000-12-13 12:58:23.123', 123.1); + exec simpleErrorProc1; + INSERT INTO simpleErrorTable VALUES ('Cherry', N'indigo', 8, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + rollback tran; +end +GO +exec simpleErrorProc2 +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33685634)~~ + +~~ERROR (Message: invalid input syntax for type integer: "abc")~~ + +select * from simpleErrorTable ORDER BY c +GO +~~START~~ +varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric +~~END~~ + +select @@trancount +GO +~~START~~ +int +0 +~~END~~ + +drop procedure simpleErrorProc1 +GO +drop procedure simpleErrorProc2 +GO +truncate table simpleErrorTable +GO + +-- cleanup +SET XACT_ABORT OFF; +GO + +drop table simpleErrorTable +GO + +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_unique_constraint', 'strict'; +GO diff --git a/contrib/test/JDBC/sql_expected/TestTriggers.out b/contrib/test/JDBC/sql_expected/TestTriggers.out new file mode 100644 index 00000000000..88577bbdcc0 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/TestTriggers.out @@ -0,0 +1,391 @@ +create table triggerTab1(c1 int, c2 varchar(30)) +go + +create table triggerTab2(c1 int) +go + +create table triggerTab3(c1 int) +go + +insert into triggerTab1 values(1, 'first') +go +~~ROW COUNT: 1~~ + + +insert into triggerTab2 values(1) +go +~~ROW COUNT: 1~~ + + +insert into triggerTab3 values(1) +go +~~ROW COUNT: 1~~ + + +create trigger txnTrig1 on triggerTab1 for insert as +begin tran; +update triggerTab2 set c1 = 2; +commit; +select * from triggerTab2 order by c1; +select * from inserted; +go + +create trigger txnTrig2 on triggerTab2 for update as +save tran sp1; +save tran sp2; +delete from triggerTab3; +rollback tran sp1; +go + +create trigger txnTrig3 on triggerTab3 for delete as +select * from triggerTab3 order by c1; +insert into triggerTab3 values(1); +select * from deleted; +rollback tran sp2; +go + +insert into triggerTab1 values(2, 'second'); +go +~~START~~ +int +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +2 +~~END~~ + +~~START~~ +int#!#varchar +2#!#second +~~END~~ + +~~ROW COUNT: 1~~ + + +begin tran; +go +insert into triggerTab1 values(3, 'third'); +go +~~START~~ +int +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +2 +~~END~~ + +~~START~~ +int#!#varchar +3#!#third +~~END~~ + +~~ROW COUNT: 1~~ + +commit; +go + +drop trigger txnTrig1; +go + +create trigger txnTrig1 on triggerTab1 for insert as +commit; +update triggerTab2 set c1 = 2; +select * from triggerTab2 order by c1; +go + +insert into triggerTab1 values(2, 'second'); +go +~~START~~ +int +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +2 +~~END~~ + +~~ERROR (Code: 3609)~~ + +~~ERROR (Message: The transaction ended in the trigger. The batch has been aborted.)~~ + + +begin tran; +go + +insert into triggerTab1 values(2, 'second'); +go +~~START~~ +int +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +2 +~~END~~ + +~~ERROR (Code: 3609)~~ + +~~ERROR (Message: The transaction ended in the trigger. The batch has been aborted.)~~ + + +drop trigger txnTrig1; +go + +create trigger txnTrig1 on triggerTab1 for insert as +rollback; +update triggerTab2 set c1 = 3; +select * from triggerTab2 order by c1; +go + +insert into triggerTab1 values(2, 'second'); +go +~~START~~ +int +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +3 +~~END~~ + +~~ERROR (Code: 3609)~~ + +~~ERROR (Message: The transaction ended in the trigger. The batch has been aborted.)~~ + + +begin tran; +go + +insert into triggerTab1 values(2, 'second'); +go +~~START~~ +int +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +3 +~~END~~ + +~~ERROR (Code: 3609)~~ + +~~ERROR (Message: The transaction ended in the trigger. The batch has been aborted.)~~ + + +create procedure triggerProc1 as +save tran sp1; +insert into triggerTab1 values(3, 'third'); +rollback tran sp1; +go + +create procedure triggerProc2 as +begin tran; +exec triggerProc1; +insert into triggerTab1 values(3, 'third'); +commit; +go + +exec triggerProc2; +go +~~START~~ +int +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +3 +~~END~~ + +~~ERROR (Code: 3609)~~ + +~~ERROR (Message: The transaction ended in the trigger. The batch has been aborted.)~~ + + +create table triggerErrorTab(c1 int not null); +go + +create trigger triggerErr on triggerErrorTab for insert as +insert into triggerErrorTab values(NULL); +insert into invalidTab values(1); +go + +insert into triggerErrorTab values(1); +go +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "c1" of relation "triggererrortab" violates not-null constraint)~~ + + + +drop procedure triggerProc1; +go +drop procedure triggerProc2; +go +drop trigger txnTrig1 +go + + +create procedure triggerProc1 as +commit; +go + +create procedure triggerProc2 as +exec triggerProc1; +go + +create trigger txnTrig1 on triggerTab1 for insert as +exec triggerProc2; +go + +insert into triggerTab1 values(1, 'value1'); +go +~~ERROR (Code: 3609)~~ + +~~ERROR (Message: The transaction ended in the trigger. The batch has been aborted.)~~ + + +drop procedure triggerProc1; +go +drop procedure triggerProc2; +go +drop trigger txnTrig1 +go + + +create procedure triggerProc1 as +rollback; +go + +create procedure triggerProc2 as +exec triggerProc1; +go + +create trigger txnTrig1 on triggerTab1 after insert as +exec triggerProc2; +go + +insert into triggerTab1 values(1, 'value2'); +go +~~ERROR (Code: 3609)~~ + +~~ERROR (Message: The transaction ended in the trigger. The batch has been aborted.)~~ + + +drop procedure triggerProc1; +go +drop procedure triggerProc2; +go +drop trigger txnTrig1 +go + + +create procedure triggerProc1 as +rollback tran sp1; +go + +create procedure triggerProc2 as +exec triggerProc1; +go + +create trigger txnTrig1 on triggerTab1 for insert as +save tran sp1; +exec triggerProc2; +go + +insert into triggerTab1 values(1, 'value3'); +go +~~ROW COUNT: 1~~ + + + +drop procedure triggerProc1; +go +drop procedure triggerProc2; +go +drop table triggerTab1; +go +drop table triggerTab2; +go +drop table triggerTab3; +go +drop table triggerErrorTab +go diff --git a/contrib/test/JDBC/sql_expected/sys-all_columns.out b/contrib/test/JDBC/sql_expected/sys-all_columns.out new file mode 100644 index 00000000000..554bf6a3524 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/sys-all_columns.out @@ -0,0 +1,33 @@ +DROP TABLE IF EXISTS sys_all_columns_table +GO + +CREATE TABLE sys_all_columns_table ( + sac_int_col INT PRIMARY KEY, + sac_text_col_not_null VARCHAR(50) NOT NULL, + sac_date_col DATETIME +) +GO + +SELECT name, is_nullable, column_id +FROM sys.all_columns +WHERE name in ('sac_int_col', 'sac_text_col_not_null', 'sac_date_col') +ORDER BY name +GO +~~START~~ +varchar#!#int#!#smallint +sac_date_col#!#1#!#3 +sac_int_col#!#0#!#1 +sac_text_col_not_null#!#0#!#2 +~~END~~ + + +SELECT COUNT(*) FROM sys.all_columns WHERE object_id = object_id('sys.all_columns'); +GO +~~START~~ +int +34 +~~END~~ + + +DROP TABLE IF EXISTS sys_all_columns_table +GO diff --git a/contrib/test/JDBC/sql_expected/sys-check_constraints.out b/contrib/test/JDBC/sql_expected/sys-check_constraints.out new file mode 100644 index 00000000000..2f34f7fa3de --- /dev/null +++ b/contrib/test/JDBC/sql_expected/sys-check_constraints.out @@ -0,0 +1,26 @@ +DROP TABLE IF EXISTS sys_check_constraints +GO + +CREATE TABLE sys_check_constraints ( + sck_date_col DATETIME CHECK (sck_date_col IS NOT NULL) +) +GO + +SELECT name FROM sys.check_constraints WHERE NAME IN ('sys_check_constraints_sck_date_col_check') +GO +~~START~~ +varchar +sys_check_constraints_sck_date_col_check +~~END~~ + + +SELECT COUNT(*) FROM sys.all_columns WHERE object_id = object_id('sys.check_constraints'); +GO +~~START~~ +int +19 +~~END~~ + + +DROP TABLE IF EXISTS sys_check_constraints +GO diff --git a/contrib/test/JDBC/sql_expected/sys-computed_columns.out b/contrib/test/JDBC/sql_expected/sys-computed_columns.out new file mode 100644 index 00000000000..3ce24f3c3c1 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/sys-computed_columns.out @@ -0,0 +1,28 @@ +DROP TABLE IF EXISTS sys_computed_columns +GO + +CREATE TABLE sys_computed_columns ( + scc_first_number smallint, + scc_second_number money, + scc_multiplied AS scc_first_number * scc_second_number +) +GO + +SELECT name FROM sys.computed_columns where name in ('scc_multiplied') +GO +~~START~~ +varchar +scc_multiplied +~~END~~ + + +SELECT COUNT(*) FROM sys.all_columns WHERE object_id = object_id('sys.computed_columns'); +GO +~~START~~ +int +39 +~~END~~ + + +DROP TABLE IF EXISTS sys_computed_columns +GO diff --git a/contrib/test/JDBC/sql_expected/sys-databases.out b/contrib/test/JDBC/sql_expected/sys-databases.out new file mode 100644 index 00000000000..35d3c094010 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/sys-databases.out @@ -0,0 +1,24 @@ +DROP DATABASE IF EXISTS my_test_database; +GO + +CREATE DATABASE my_test_database; +GO + +SELECT COUNT(*) FROM sys.all_columns WHERE object_id = object_id('sys.databases'); +GO +~~START~~ +int +87 +~~END~~ + + +SELECT name FROM sys.databases where name = 'my_test_database'; +GO +~~START~~ +text +my_test_database +~~END~~ + + +DROP DATABASE IF EXISTS my_test_database; +GO diff --git a/contrib/test/JDBC/sql_expected/sys-default_constraints.out b/contrib/test/JDBC/sql_expected/sys-default_constraints.out new file mode 100644 index 00000000000..e8ddcd51eed --- /dev/null +++ b/contrib/test/JDBC/sql_expected/sys-default_constraints.out @@ -0,0 +1,27 @@ +DROP TABLE IF EXISTS sys_default_definitions +GO + +CREATE TABLE sys_default_definitions (column_a INT, column_b INT) +GO + +ALTER TABLE sys_default_definitions ADD CONSTRAINT DF_sdd_column_b DEFAULT 50 FOR column_b +GO + +SELECT definition FROM sys.default_constraints where name LIKE '%sys_default_definitions%' +GO +~~START~~ +text +50 +~~END~~ + + +SELECT COUNT(*) FROM sys.all_columns WHERE object_id = object_id('sys.default_constraints'); +GO +~~START~~ +int +15 +~~END~~ + + +DROP TABLE IF EXISTS sys_default_definitions +GO diff --git a/contrib/test/JDBC/sql_expected/sys-extended_properties.out b/contrib/test/JDBC/sql_expected/sys-extended_properties.out new file mode 100644 index 00000000000..ad81733cd13 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/sys-extended_properties.out @@ -0,0 +1,7 @@ +SELECT COUNT(*) FROM sys.all_columns WHERE object_id = object_id('sys.extended_properties'); +GO +~~START~~ +int +6 +~~END~~ + diff --git a/contrib/test/JDBC/sql_expected/sys-index_columns.out b/contrib/test/JDBC/sql_expected/sys-index_columns.out new file mode 100644 index 00000000000..5049514485b --- /dev/null +++ b/contrib/test/JDBC/sql_expected/sys-index_columns.out @@ -0,0 +1,31 @@ +DROP TABLE IF EXISTS sys_index_columns +GO + +CREATE TABLE sys_index_columns ( + sic_name VARCHAR (50), + sic_surname VARCHAR (50) +) +GO + +CREATE INDEX sic_test_index +ON sys_index_columns (sic_name) +GO + +SELECT COUNT(*) FROM sys.index_columns WHERE object_id = OBJECT_ID('sys_index_columns') +GO +~~START~~ +int +1 +~~END~~ + + +SELECT COUNT(*) FROM sys.all_columns WHERE object_id = object_id('sys.index_columns') +GO +~~START~~ +int +8 +~~END~~ + + +DROP TABLE IF EXISTS sys_index_columns +GO diff --git a/contrib/test/JDBC/sql_expected/sys-indexes.out b/contrib/test/JDBC/sql_expected/sys-indexes.out new file mode 100644 index 00000000000..f831d64c369 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/sys-indexes.out @@ -0,0 +1,69 @@ +SELECT COUNT(*) FROM sys.all_columns WHERE object_id = object_id('sys.indexes'); +GO +~~START~~ +int +19 +~~END~~ + + +DROP TABLE IF EXISTS t_sys_index_test1 +GO + +CREATE TABLE t_sys_index_test1 ( + c1 INT, + c2 VARCHAR(128) +); +GO + +INSERT INTO t_sys_index_test1 (c1, c2) VALUES +(100, 'abc'), +(200, 'bcd'), +(300, 'cde'), +(1400, 'def') +GO +~~ROW COUNT: 4~~ + + +CREATE INDEX i_sys_index_test1 ON t_sys_index_test1 (c1); +CREATE INDEX i_sys_index_test1a ON t_sys_index_test1 (c2); +GO + +SELECT COUNT(*) FROM sys.indexes WHERE object_id = OBJECT_ID('t_sys_index_test1') +GO +~~START~~ +int +2 +~~END~~ + + +SELECT COUNT(*) FROM sys.indexes WHERE name LIKE 'i_sys_index_test1%'; +GO +~~START~~ +int +2 +~~END~~ + + +SELECT type, type_desc FROM sys.indexes WHERE name LIKE 'i_sys_index_test1%'; +GO +~~START~~ +int#!#varchar +2#!#NONCLUSTERED +2#!#NONCLUSTERED +~~END~~ + + +DROP INDEX i_sys_index_test1 ON t_sys_index_test1; +DROP INDEX i_sys_index_test1a ON t_sys_index_test1; +GO + +SELECT COUNT(*) FROM sys.indexes WHERE name LIKE 'i_sys_index_test%'; +GO +~~START~~ +int +0 +~~END~~ + + +DROP TABLE IF EXISTS t_sys_index_test1 +GO diff --git a/contrib/test/JDBC/sql_expected/sys-schemas.out b/contrib/test/JDBC/sql_expected/sys-schemas.out new file mode 100644 index 00000000000..cacf54a3f21 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/sys-schemas.out @@ -0,0 +1,44 @@ +SELECT COUNT(*) FROM sys.all_columns WHERE object_id = object_id('sys.schemas'); +GO +~~START~~ +int +3 +~~END~~ + + +SELECT name FROM sys.schemas +WHERE name = 'dbo'; +GO +~~START~~ +varchar +dbo +~~END~~ + + +CREATE SCHEMA sys_schema_test1; +CREATE SCHEMA sys_schema_test2; +GO + +SELECT name FROM sys.schemas +WHERE name in ('dbo', 'sys_schema_test1', 'sys_schema_test2'); +GO +~~START~~ +varchar +dbo +sys_schema_test1 +sys_schema_test2 +~~END~~ + + +DROP SCHEMA sys_schema_test1; +DROP SCHEMA sys_schema_test2; +GO + +SELECT name FROM sys.schemas +WHERE name in ('dbo', 'sys_schema_test1', 'sys_schema_test2'); +GO +~~START~~ +varchar +dbo +~~END~~ + diff --git a/contrib/test/JDBC/sql_expected/sys-server_principals.out b/contrib/test/JDBC/sql_expected/sys-server_principals.out new file mode 100644 index 00000000000..1d54344cce5 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/sys-server_principals.out @@ -0,0 +1,44 @@ +SELECT COUNT(*) FROM sys.all_columns WHERE object_id = object_id('sys.server_principals'); +GO +~~START~~ +int +13 +~~END~~ + + +SELECT name, type, type_desc, default_database_name, default_language_name +FROM sys.server_principals +WHERE name = 'jdbc_user'; +GO +~~START~~ +varchar#!#char#!#nvarchar#!#nvarchar#!#nvarchar +jdbc_user#!#S#!#SQL_LOGIN#!#master#!#English +~~END~~ + + +CREATE LOGIN serv_principal_test WITH PASSWORD = 'test'; +GO + +SELECT name, type, type_desc, default_database_name, default_language_name +FROM sys.server_principals +WHERE name in ('jdbc_user', 'serv_principal_test'); +GO +~~START~~ +varchar#!#char#!#nvarchar#!#nvarchar#!#nvarchar +jdbc_user#!#S#!#SQL_LOGIN#!#master#!#English +serv_principal_test#!#S#!#SQL_LOGIN#!#master#!#English +~~END~~ + + +DROP LOGIN serv_principal_test; +GO + +SELECT name, type, type_desc, default_database_name, default_language_name +FROM sys.server_principals +WHERE name in ('jdbc_user', 'serv_principal_test'); +GO +~~START~~ +varchar#!#char#!#nvarchar#!#nvarchar#!#nvarchar +jdbc_user#!#S#!#SQL_LOGIN#!#master#!#English +~~END~~ + diff --git a/contrib/test/JDBC/sql_expected/temp-tables.out b/contrib/test/JDBC/sql_expected/temp-tables.out new file mode 100644 index 00000000000..c5ce8169a31 --- /dev/null +++ b/contrib/test/JDBC/sql_expected/temp-tables.out @@ -0,0 +1,431 @@ +USE master +GO + + + +-- +-- Tests for T-SQL style temp tables +-- +-- Basic temp table create/insert/select using tsql dialect +CREATE TABLE #local_tempt(col int); +GO + +INSERT INTO #local_tempt VALUES (1); +GO +~~ROW COUNT: 1~~ + + +SELECT * FROM #local_tempt; +GO +~~START~~ +int +1 +~~END~~ + + +CREATE TABLE ##global_tempt(col int); +GO +~~ERROR (Code: 1088)~~ + +~~ERROR (Message: 'GLOBAL TEMPORARY TABLE' is not currently supported in Babelfish)~~ + + +CREATE SCHEMA temp_tables_test; +GO + +CREATE TABLE temp_tables_test.#local_tempt_withschema(col int); +GO + +INSERT INTO temp_tables_test.#local_tempt_withschema VALUES (1); +GO +~~ROW COUNT: 1~~ + + +SELECT * FROM temp_tables_test.#local_tempt_withschema; +GO +~~START~~ +int +1 +~~END~~ + + +DROP SCHEMA temp_tables_test; +GO + +-- various catalog/schema cases +CREATE TABLE non_exist_db..#tt(a int) +GO +DROP TABLE #tt +GO + +CREATE TABLE non_exist_schema.#tt(a int) +GO +DROP TABLE #tt +GO + +CREATE TABLE .#tt(a int) +GO +DROP TABLE #tt +GO + +CREATE TABLE ..#tt(a int) +GO +DROP TABLE #tt +GO + + +-- Implicitly creating temp tables +CREATE TABLE tt_test_t1 (col int); +GO + +INSERT INTO tt_test_t1 values (1); +GO +~~ROW COUNT: 1~~ + + +INSERT INTO tt_test_t1 values (NULL); +GO +~~ROW COUNT: 1~~ + + +SELECT * INTO #local_tempt2 FROM tt_test_t1; +GO + +SELECT * FROM #local_tempt2; +GO +~~START~~ +int +1 + +~~END~~ + + + +-- Implicitly creating temp tables in procedure +CREATE PROCEDURE temp_table_sp AS +BEGIN + SELECT * INTO #tt_sp_local FROM tt_test_t1; + INSERT INTO #tt_sp_local VALUES(2); +END; +GO + +EXEC temp_table_sp; +GO +~~ROW COUNT: 1~~ + + +-- BABEL-903: create temp table named #[digit][string] +create procedure babel903 AS +BEGIN + create table #903 (a int); + select col into #903tt from tt_test_t1; + insert into #903 values(1); + insert into #903tt values(1); +END +GO + +exec babel903; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +-- BABEL-904: drop temp table +CREATE PROCEDURE babel904 AS +BEGIN + create table #t (a int); + create table #tt (a int); + drop table #t; + drop table #tt; +END +go + +exec babel904; +GO + + +-- Visibility tests +create table #tt (a int); +go +insert into #tt values(0); +go +~~ROW COUNT: 1~~ + + +CREATE procedure temp_table_nested_sp_1st AS +BEGIN + CREATE TABLE #tt_1st (a int); + insert into #tt values(1); + insert into #tt_1st values(1); + insert into #tt_2nd values(1); + insert into #tt_3rd values(1); +END; +GO + +CREATE procedure temp_table_nested_sp_2nd AS +BEGIN + CREATE TABLE #tt_2nd (a int); + EXEC temp_table_nested_sp_1st; + insert into #tt values(2); + insert into #tt_2nd values(2); + insert into #tt_3rd values(2); +END; +GO + +CREATE procedure temp_table_nested_sp_3rd AS +BEGIN + CREATE TABLE #tt_3rd (a int); + EXEC temp_table_nested_sp_2nd; + insert into #tt values(3); + insert into #tt_3rd values(3); +END; +GO + +EXEC temp_table_nested_sp_3rd; +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~~ + + +-- should fail to find these tables +select * from #tt_1st; +go +~~ERROR (Code: 16908420)~~ + +~~ERROR (Message: relation "#tt_1st" does not exist)~~ + +select * from #tt_2nd; +go +~~ERROR (Code: 16908420)~~ + +~~ERROR (Message: relation "#tt_2nd" does not exist)~~ + +select * from #tt_3rd; +go +~~ERROR (Code: 16908420)~~ + +~~ERROR (Message: relation "#tt_3rd" does not exist)~~ + +-- This should print 0, 1, 2 and 3 +select * from #tt; +go +~~START~~ +int +0 +1 +2 +3 +~~END~~ + + +DROP PROCEDURE temp_table_nested_sp_1st; +go +DROP PROCEDURE temp_table_nested_sp_2nd; +go +DROP PROCEDURE temp_table_nested_sp_3rd; +go +DROP TABLE #tt; +go + +-- creating temp tables with duplicated names. +create table #tt (a int); +go +insert into #tt values(1); +go +~~ROW COUNT: 1~~ + + +CREATE procedure temp_table_nested_sp_inner AS +BEGIN + CREATE TABLE #tt (a int); -- same name as the top-level, allowed + CREATE TABLE #tt_sp_outer (a int); -- same name as the outer procedure, allowed + insert into #tt values(3); +END; +GO + +CREATE procedure temp_table_nested_sp_outer AS +BEGIN + CREATE TABLE #tt (a int); -- same name as the top-level, allowed + CREATE TABLE #tt_sp_outer (a int); + insert into #tt values(2); + EXEC temp_table_nested_sp_inner; +END; +GO + +EXEC temp_table_nested_sp_outer; +go +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +select * from #tt; -- should only print value '1' +go +~~START~~ +int +1 +~~END~~ + +drop table #tt; +go + +-- procedure with exception +CREATE procedure temp_table_sp_exception AS +BEGIN + CREATE TABLE #tt (a int); + CREATE TABLE #tt (a int); -- throws error +END; +GO +EXEC temp_table_sp_exception; +GO +~~ERROR (Code: 2714)~~ + +~~ERROR (Message: relation "#tt" already exists)~~ + +select * from #tt; -- can't find the table +go +~~ERROR (Code: 16908420)~~ + +~~ERROR (Message: relation "#tt" does not exist)~~ + + +-- drop/alter tables +CREATE procedure temp_table_sp_alter AS +BEGIN + CREATE TABLE #tt (a int); + CREATE TABLE #tt2 (a int); + DROP TABLE #tt2; + ALTER TABLE #tt ADD b char; + insert into #tt values(1, 'x'); +END; +GO + +EXEC temp_table_sp_alter; +GO +~~ROW COUNT: 1~~ + + + +-- constraints +create table #tt_con(a int CHECK (a > 10)); +go +insert into #tt_con values(1); -- errorneous +go +~~ERROR (Code: 67391682)~~ + +~~ERROR (Message: new row for relation "#tt_con" violates check constraint "#tt_con_a_check")~~ + +CREATE PROCEDURE temp_table_sp_constraint AS +BEGIN + create table #tt (a int CHECK (a > 10)); + insert into #tt values(11); + insert into #tt_con(a) select a from #tt; +END +go +exec temp_table_sp_constraint; +go +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +select * from #tt_con; -- should print 11 +go +~~START~~ +int +11 +~~END~~ + + + +-- statistic +create table #tt_stat(a int, b int); +go +insert into #tt_stat values(1, 2); +go +~~ROW COUNT: 1~~ + +-- valid T-SQL create-statitstics is not supported yet +--CREATE STATISTICS s1 on #tt_stat(a, b); +--go +drop table #tt_stat; +go + + +-- BABEL-322: '#' in column name is allowed in tsql +CREATE TABLE #babel322(#col int, ##col int); +GO +DROP TABLE #babel322; +GO + +-- BABEL-1637: rollback within procedure makes top-level temp table gone +create proc sp_babel1637 as + create table #tt_1637 (a int) + begin tran + insert into #tt_1637 values (123) + rollback + select * from #tt_1637 +go +create table #tt_1637 (a int) +insert into #tt_1637 values (456) +select * from #tt_1637 +go +~~ROW COUNT: 1~~ + +~~START~~ +int +456 +~~END~~ + +exec sp_babel1637 +go +~~ROW COUNT: 1~~ + +~~START~~ +int +~~END~~ + +select * from #tt_1637 +go +~~START~~ +int +456 +~~END~~ + +drop table #tt_1637 +go + + +-- cleanup +DROP PROCEDURE temp_table_sp; +GO +DROP PROCEDURE babel903; +GO +DROP PROCEDURE babel904; +GO +DROP PROCEDURE temp_table_nested_sp_inner; +GO +DROP PROCEDURE temp_table_nested_sp_outer; +GO +DROP PROCEDURE temp_table_sp_exception; +GO +DROP PROCEDURE temp_table_sp_alter; +GO +DROP PROCEDURE temp_table_sp_constraint; +GO +DROP TABLE tt_test_t1; +GO diff --git a/contrib/test/JDBC/src/main/java/com/sqlsamples/CompareResults.java b/contrib/test/JDBC/src/main/java/com/sqlsamples/CompareResults.java new file mode 100644 index 00000000000..ff3d85e0e0c --- /dev/null +++ b/contrib/test/JDBC/src/main/java/com/sqlsamples/CompareResults.java @@ -0,0 +1,296 @@ +package com.sqlsamples; + +import org.junit.jupiter.api.Assertions; +import org.opentest4j.AssertionFailedError; +import microsoft.sql.DateTimeOffset; +import org.apache.logging.log4j.Logger; + +import java.io.BufferedWriter; +import java.io.IOException; +import java.sql.*; +import java.text.DecimalFormat; +import java.text.NumberFormat; +import java.text.ParseException; +import java.time.LocalTime; +import java.util.Locale; + +import static com.sqlsamples.Config.outputColumnName; +import static com.sqlsamples.HandleException.handleSQLExceptionWithFile; +import static java.sql.Types.*; +import static java.util.Objects.isNull; + +public class CompareResults { + + // function to write result set into a file + public static void writeResultSetToFile(BufferedWriter bw, ResultSet rs, Logger logger) { + try { + bw.write("~~START~~"); + bw.newLine(); + + ResultSetMetaData rsmd = rs.getMetaData(); + int cols = rsmd.getColumnCount(); + + if (outputColumnName) { + for (int i = 1; i <= cols; i++) { + bw.write(rsmd.getColumnName(i)); + if (i != cols) bw.write("#!#"); + } + bw.newLine(); + } + + for (int i = 1; i <= cols; i++) { + bw.write(rsmd.getColumnTypeName(i)); + if (i != cols) bw.write("#!#"); + } + bw.newLine(); + + while (rs.next()) { + for (int i = 1; i <= cols; i++) { + if(isNull(rs.getObject(i))){ + bw.write(""); + } else { + String str = rs.getString(i); + str = str.replaceAll("[\r\n]+", ""); + bw.write(str); + } + + if (i != cols) bw.write("#!#"); + } + bw.newLine(); + } + + bw.write("~~END~~"); + bw.newLine(); + bw.newLine(); + + rs.close(); + + } catch (SQLException e) { + handleSQLExceptionWithFile(e, bw, logger); + } catch (IOException ioe) { + logger.error("IO Exception: " + ioe.getMessage(), ioe); + } + } + + // function to write the tuple, result set cursor is pointing to, into a file + public static void writeCursorResultSetToFile(BufferedWriter bw, ResultSet cursor, Logger logger) { + try { + bw.write("~~START~~"); + bw.newLine(); + + ResultSetMetaData rsmd = cursor.getMetaData(); + int cols = rsmd.getColumnCount(); + + if (outputColumnName) { + for (int i = 1; i <= cols; i++) { + bw.write(rsmd.getColumnName(i)); + if (i != cols) bw.write("#!#"); + } + bw.newLine(); + } + + for (int i = 1; i <= cols; i++) { + bw.write(rsmd.getColumnTypeName(i)); + if (i != cols) bw.write("#!#"); + } + + bw.newLine(); + + for (int i = 1; i <= cols; i++) { + if(isNull(cursor.getObject(i))){ + bw.write(""); + } else { + bw.write(cursor.getObject(i).toString()); + } + if (i != cols) bw.write("#!#"); + } + bw.newLine(); + bw.write("~~END~~"); + bw.newLine(); + bw.newLine(); + + } catch (SQLException e) { + handleSQLExceptionWithFile(e, bw, logger); + } catch (IOException ioe) { + logger.error("IO Exception: " + ioe.getMessage(), ioe); + } + } + + // processes all the results sequentially that we get from executing a JDBC Statement + static void processResults(Statement stmt, BufferedWriter bw, int resultsProcessed, boolean resultSetExist, Logger logger) { + int updateCount = -9; // initialize to impossible value + + while (true) { + boolean exceptionOccurred = true; + do { + try { + if (resultsProcessed > 0) { + resultSetExist = stmt.getMoreResults(); + } + exceptionOccurred = false; + updateCount = stmt.getUpdateCount(); + } catch (SQLException e) { + handleSQLExceptionWithFile(e, bw, logger); + } + resultsProcessed++; + } while (exceptionOccurred); + + if ((!resultSetExist) && (updateCount == -1)) { + break; + } + + if (resultSetExist) { + try (ResultSet rs = stmt.getResultSet()) { + writeResultSetToFile(bw, rs, logger); + } catch (SQLException e) { + handleSQLExceptionWithFile(e, bw, logger); + } + } else { + if (updateCount > 0) { + try { + bw.write("~~ROW COUNT: " + updateCount + "~~"); + bw.newLine(); + bw.newLine(); + } catch (IOException e) { + logger.error("IO Exception: " + e.getMessage(), e); + } + } + } + } + } + + // function to map SQL data type to JDBC data types + static int SQLtoJDBCDataTypeMapping(String sqlDataType) { + + if(sqlDataType.equalsIgnoreCase("bigint")) { + return BIGINT; + } else if (sqlDataType.equalsIgnoreCase("binary") + || sqlDataType.equalsIgnoreCase("timestamp")) { + return BINARY; + } else if (sqlDataType.equalsIgnoreCase("bit")) { + return BIT; + } else if (sqlDataType.equalsIgnoreCase("char") + || sqlDataType.equalsIgnoreCase("uniqueidentifier")) { + return CHAR; + } else if (sqlDataType.equalsIgnoreCase("date")) { + return DATE; + } else if (sqlDataType.equalsIgnoreCase("datetime") + || sqlDataType.equalsIgnoreCase("datetime2") + || sqlDataType.equalsIgnoreCase("smalldatetime")) { + return TIMESTAMP; + } else if (sqlDataType.equalsIgnoreCase("datetimeoffset")) { + return microsoft.sql.Types.DATETIMEOFFSET; + } else if (sqlDataType.equalsIgnoreCase("decimal") + || sqlDataType.equalsIgnoreCase("money") + || sqlDataType.equalsIgnoreCase("smallmoney")) { + return DECIMAL; + } else if (sqlDataType.equalsIgnoreCase("float")) { + return DOUBLE; + } else if (sqlDataType.equalsIgnoreCase("image")) { + return LONGVARBINARY; + } else if (sqlDataType.equalsIgnoreCase("int")) { + return INTEGER; + } else if (sqlDataType.equalsIgnoreCase("nchar")) { + return NCHAR; + } else if (sqlDataType.equalsIgnoreCase("nvarchar") + || sqlDataType.equalsIgnoreCase("nvarcharmax")) { + return NVARCHAR; + } else if (sqlDataType.equalsIgnoreCase("ntext") + || sqlDataType.equalsIgnoreCase("xml")) { + return LONGNVARCHAR; + } else if (sqlDataType.equalsIgnoreCase("numeric")) { + return NUMERIC; + } else if (sqlDataType.equalsIgnoreCase("real")) { + return REAL; + } else if (sqlDataType.equalsIgnoreCase("smallint")) { + return SMALLINT; + } else if (sqlDataType.equalsIgnoreCase("text")) { + return LONGVARCHAR; + } else if (sqlDataType.equalsIgnoreCase("time")) { + return TIME; + } else if (sqlDataType.equalsIgnoreCase("tinyint")) { + return TINYINT; + } else if (sqlDataType.equalsIgnoreCase("udt") + || sqlDataType.equalsIgnoreCase("varbinary") + || sqlDataType.equalsIgnoreCase("varbinarymax") + || sqlDataType.equalsIgnoreCase("geometry") + || sqlDataType.equalsIgnoreCase("geography")) { + return VARBINARY; + } else if (sqlDataType.equalsIgnoreCase("varchar") + || sqlDataType.equalsIgnoreCase("varcharmax")) { + return VARCHAR; + } else if (sqlDataType.equalsIgnoreCase("sqlvariant")) { + return microsoft.sql.Types.SQL_VARIANT; + } else return 0; + } + + // function to parse SQL data type to Java data type + static Object parse_data(String result, String datatype, Logger logger) { + + try { + if(result.equals("")){ + return null; + } + + /* TODO: Add more data types here as we support them */ + if (datatype.equalsIgnoreCase("int")) { + return Integer.parseInt(result); + } else if (datatype.equalsIgnoreCase("string") + || datatype.equalsIgnoreCase("char") + || datatype.equalsIgnoreCase("nchar") + || datatype.equalsIgnoreCase("varchar") + || datatype.equalsIgnoreCase("nvarchar") + || datatype.equalsIgnoreCase("uniqueidentifier") + || datatype.equalsIgnoreCase("varcharmax") + || datatype.equalsIgnoreCase("nvarcharmax")) { + return result; + } else if (datatype.equalsIgnoreCase("boolean") + || datatype.equalsIgnoreCase("bit")) { + return Boolean.parseBoolean(result); + } else if (datatype.equalsIgnoreCase("long") + || datatype.equalsIgnoreCase("bigint")) { + return Long.parseLong(result); + } else if (datatype.equalsIgnoreCase("double") + || datatype.equalsIgnoreCase("float")) { + return Double.parseDouble(result); + } else if (datatype.equalsIgnoreCase("unsigned_char") + || datatype.equalsIgnoreCase("smallint") + || datatype.equalsIgnoreCase("tinyint")) { + return Short.parseShort(result); + } else if (datatype.equalsIgnoreCase("real")) { + return Float.parseFloat(result); + } else if (datatype.equalsIgnoreCase("byte")) { + return Byte.parseByte(result); + } else if (datatype.equalsIgnoreCase("binary") + || datatype.equalsIgnoreCase("varbinary") + || datatype.equalsIgnoreCase("timestamp") + || datatype.equalsIgnoreCase("udt")) { + return result; + } else if (datatype.equalsIgnoreCase("decimal") + || datatype.equalsIgnoreCase("money") + || datatype.equalsIgnoreCase("smallmoney") + || datatype.equalsIgnoreCase("numeric")) { + DecimalFormat format = (DecimalFormat) NumberFormat.getInstance(Locale.US); + format.setParseBigDecimal(true); + return format.parse(result); + } else if (datatype.equalsIgnoreCase("datetime") + || datatype.equalsIgnoreCase("datetime2") + || datatype.equalsIgnoreCase("smalldatetime")){ + return Timestamp.valueOf(result); + } else if (datatype.equalsIgnoreCase("date")){ + return Date.valueOf(result); + } else if (datatype.equalsIgnoreCase("time")){ + return Time.valueOf(LocalTime.parse(result)); + } else if (datatype.equalsIgnoreCase("text") + || datatype.equalsIgnoreCase("ntext")){ + return result.replaceAll("", System.lineSeparator()); + } else if (datatype.equalsIgnoreCase("datetimeoffset")){ + return DateTimeOffset.valueOf(Timestamp.valueOf(result), 0); + } + } catch (ParseException pe) { + logger.error("Parse Exception: " + pe.getMessage(), pe); + } + + return null; + } +} diff --git a/contrib/test/JDBC/src/main/java/com/sqlsamples/Config.java b/contrib/test/JDBC/src/main/java/com/sqlsamples/Config.java new file mode 100644 index 00000000000..3c6e22b8ec4 --- /dev/null +++ b/contrib/test/JDBC/src/main/java/com/sqlsamples/Config.java @@ -0,0 +1,145 @@ +package com.sqlsamples; + +import org.apache.logging.log4j.*; +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.appender.*; +import org.apache.logging.log4j.core.config.AppenderRef; +import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.config.Configurator; +import org.apache.logging.log4j.core.config.LoggerConfig; +import org.apache.logging.log4j.core.layout.PatternLayout; + +import java.io.*; +import java.util.Map; +import java.util.Properties; + +import static java.util.Objects.isNull; + +public class Config { + + static Properties properties = readConfig(); + static String inputFilesDirectoryPath = properties.getProperty("inputFilesPath"); + static boolean printLogsToConsole = Boolean.parseBoolean(properties.getProperty("printLogsToConsole")); + static String JDBCDriver = properties.getProperty("driver"); + static boolean performanceTest = Boolean.parseBoolean(properties.getProperty("performanceTest")); + static boolean outputColumnName = Boolean.parseBoolean(properties.getProperty("outputColumnName")); + static boolean outputErrorCode = Boolean.parseBoolean(properties.getProperty("outputErrorCode")); + static String scheduleFileName = properties.getProperty("scheduleFile"); + static String testFileRoot = properties.getProperty("testFileRoot"); + + static String connectionString = constructConnectionString(); + + // read configuration from text file "config.txt" and load it as properties + static Properties readConfig() { + Properties prop = new Properties(); + String filePath = System.getProperty("babel-config-file"); + if (filePath == null){ + filePath = "resources/config.txt"; + } + + try { + File file = new File(filePath); + FileInputStream fis; + + if (file.isFile()) { + fis = new FileInputStream(file); + } else { + // try alternate path + fis = new FileInputStream("src/main/resources/config.txt"); + } + + prop.load(fis); + + // override configuration if system environment variables are defined + String env, property; + + for(Map.Entry entry : prop.entrySet()){ + property = entry.getKey().toString(); + env = System.getenv(property); + if (isNull(env)) { + env = System.getProperty(property); + } + + if(!isNull(env)) { + prop.put(property, env); + } + } + } catch (IOException e) { + e.printStackTrace(); + } + + return prop; + } + + // configure properties of logger + public static void configureLogger(String logFileName, Logger logger) throws IOException { + LoggerContext context = LoggerContext.getContext(false); + Configuration config = context.getConfiguration(); + + PatternLayout pattern = PatternLayout.newBuilder().withPattern("%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p - %m%n").build(); + FileAppender fileAppender = FileAppender.newBuilder().setName("fileAppender").setLayout(pattern).withFileName(logFileName+ ".log").build(); + + AppenderRef ref = AppenderRef.createAppenderRef("fileAppender", null, null); + AppenderRef[] refs = new AppenderRef[] { ref }; + LoggerConfig loggerConfig = LoggerConfig.createLogger(false, Level.ERROR, logger.getName(), null, refs, null, config, null); + loggerConfig.addAppender(fileAppender, null, null); + + config.addLogger(logger.getName(), loggerConfig); /* 2 */ + context.updateLoggers(); + } + + // configure properties of summary logger + public static void configureSummaryLogger(String logFileName, Logger summaryLogger) throws IOException { + Logger rootLogger = LogManager.getRootLogger(); + Configurator.setLevel(rootLogger.getName(), Level.DEBUG); + + LoggerContext context = LoggerContext.getContext(false); + Configuration config = context.getConfiguration(); + + PatternLayout pattern = PatternLayout.newBuilder().withPattern("%m%n").build(); + FileAppender fileAppender = FileAppender.newBuilder().setName("summaryFileAppender").setLayout(pattern).withFileName(logFileName+ ".log").build(); + ConsoleAppender consoleAppender = ConsoleAppender.newBuilder().setName("summaryConsoleAppender").setLayout(pattern).build(); + + AppenderRef fileRef = AppenderRef.createAppenderRef("summaryFileAppender", null, null); + AppenderRef consoleRef = AppenderRef.createAppenderRef("summaryConsoleAppender", null, null); + + AppenderRef[] refs = new AppenderRef[] { fileRef, consoleRef }; + LoggerConfig loggerConfig = LoggerConfig.createLogger(false, summaryLogger.getLevel(), summaryLogger.getName(), null, refs, null, config, null); + loggerConfig.addAppender(fileAppender, null, null); + loggerConfig.addAppender(consoleAppender, null, null); + + config.addLogger(summaryLogger.getName(), loggerConfig); + context.updateLoggers(); + } + + static String createSQLServerConnectionString(String URL, String port, String databaseName, String user, String password) { + return "jdbc:sqlserver://" + URL + ":" + port + ";" + "databaseName=" + + databaseName + ";" + "user=" + user + ";" + "password=" + password; + } + + static String createPostgreSQLConnectionString(String URL, String port, String databaseName, String user, String password) { + return "jdbc:postgresql://" + URL + ":" + port + "/" + + databaseName + "?" + "user=" + user + "&" + "password=" + password; + } + + private static String constructConnectionString() { + + String URL = properties.getProperty("URL"); + String port = properties.getProperty("port"); + String databaseName = properties.getProperty("databaseName"); + String physicalDatabaseName = properties.getProperty("physicalDatabaseName"); + String user = properties.getProperty("user"); + String password = properties.getProperty("password"); + + // return connection strings + if (JDBCDriver.equalsIgnoreCase("sqlserver")) { + String tsql_port = properties.getProperty("tsql_port"); + return createSQLServerConnectionString(URL, tsql_port, databaseName, user, password); + } else if (JDBCDriver.equalsIgnoreCase("postgresql")) { + String psql_port = properties.getProperty("psql_port"); + return createPostgreSQLConnectionString(URL, psql_port, physicalDatabaseName, user, password); + } else System.out.println("Incorrect driver specified in config.txt . Please specify either \"sqlserver\" or \"postgresql\""); + + return null; + } +} diff --git a/contrib/test/JDBC/src/main/java/com/sqlsamples/ExportResults.java b/contrib/test/JDBC/src/main/java/com/sqlsamples/ExportResults.java new file mode 100644 index 00000000000..379fa4fcc0f --- /dev/null +++ b/contrib/test/JDBC/src/main/java/com/sqlsamples/ExportResults.java @@ -0,0 +1,33 @@ +package com.sqlsamples; + +import org.apache.commons.csv.CSVFormat; +import org.apache.commons.csv.CSVPrinter; + +import java.io.FileWriter; +import java.io.IOException; +import java.util.HashMap; + +public class ExportResults { + + public static void createCSVFile(String CSVfileName, HashMap statisticsHashMap) { + + String[] HEADERS = { "URI", "Min exec time", "Max exec time", "Mean exec time", "Median exec time", "Std. dev"}; + + try { + FileWriter out = new FileWriter(CSVfileName + ".csv"); + CSVPrinter printer = new CSVPrinter(out, CSVFormat.DEFAULT.withHeader(HEADERS)); + statisticsHashMap.forEach((URI, statistics) -> { + try { + printer.printRecord(URI, statistics.minimum(), statistics.maximum(), statistics.mean(), statistics.median(), statistics.stddev()); + } catch (IOException e) { + e.printStackTrace(); + } + }); + + printer.close(); + out.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/contrib/test/JDBC/src/main/java/com/sqlsamples/HandleException.java b/contrib/test/JDBC/src/main/java/com/sqlsamples/HandleException.java new file mode 100644 index 00000000000..affd085fdd3 --- /dev/null +++ b/contrib/test/JDBC/src/main/java/com/sqlsamples/HandleException.java @@ -0,0 +1,55 @@ +package com.sqlsamples; + +import org.apache.logging.log4j.*; + +import java.io.BufferedWriter; +import java.io.IOException; +import java.sql.SQLException; + +import org.postgresql.util.PSQLException; + +import static com.sqlsamples.Config.outputErrorCode; + +public class HandleException { + + // function to handle SQL exception + // writes error message to a file + static void handleSQLExceptionWithFile(SQLException e, BufferedWriter bw, Logger logger){ + try { + if (outputErrorCode) { + bw.write("~~ERROR (Code: " + e.getErrorCode() + ")~~"); + bw.newLine(); + bw.newLine(); + + // Ensure SQLState is printed as part of pg error message + if (e instanceof PSQLException) { + String errorMsg = e.getMessage(); + + // Do not print error location as part of error message + int index = errorMsg.indexOf("Location:"); + + if (index != -1) { + errorMsg = errorMsg.substring(0, index); + } else { + errorMsg += "\n "; + } + bw.write("~~ERROR (Message: "+ errorMsg + " Server SQLState: " + e.getSQLState() + ")~~"); + } else { + String errorMsg = e.getMessage(); + //Do not print ClientConnectionId as part of error message + int index = errorMsg.indexOf("ClientConnectionId"); + if (index != -1) { + errorMsg = errorMsg.substring(0, index); + } + bw.write("~~ERROR (Message: "+ errorMsg + ")~~"); + } + } else { + bw.write("~~ERROR~~"); + } + bw.newLine(); + bw.newLine(); + } catch (IOException ioe) { + logger.error("IO Exception: " + ioe.getMessage(), ioe); + } + } +} diff --git a/contrib/test/JDBC/src/main/java/com/sqlsamples/JDBCAuthentication.java b/contrib/test/JDBC/src/main/java/com/sqlsamples/JDBCAuthentication.java new file mode 100644 index 00000000000..a135f900f83 --- /dev/null +++ b/contrib/test/JDBC/src/main/java/com/sqlsamples/JDBCAuthentication.java @@ -0,0 +1,85 @@ +package com.sqlsamples; + +import org.apache.logging.log4j.Logger; + +import java.io.BufferedWriter; +import java.io.IOException; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.Properties; + +import static com.sqlsamples.Config.*; +import static com.sqlsamples.HandleException.handleSQLExceptionWithFile; + +public class JDBCAuthentication { + + void javaAuthentication(String strLine, BufferedWriter bw, Logger logger) { + + // Convert .NET input file format for authentication to JDBC + String[] result = strLine.split("#!#"); + + Properties connectionPropertiesBabel = new Properties(); + + // get default values from current connection + connectionPropertiesBabel.put("serverName", properties.getProperty("URL")); + + if (JDBCDriver.equalsIgnoreCase("sqlserver")) { + connectionPropertiesBabel.put("portNumber", properties.getProperty("tsql_port")); + } + if (JDBCDriver.equalsIgnoreCase("postgresql")) { + connectionPropertiesBabel.put("portNumber", properties.getProperty("psql_port")); + } + + connectionPropertiesBabel.put("database", properties.getProperty("databaseName")); + connectionPropertiesBabel.put("user", properties.getProperty("user")); + connectionPropertiesBabel.put("password", properties.getProperty("password")); + + String port = ""; + + if (JDBCDriver.equalsIgnoreCase("sqlserver")) { + port = properties.getProperty("tsql_port"); + } + if (JDBCDriver.equalsIgnoreCase("postgresql")) { + port = properties.getProperty("psql_port"); + } + + connectionPropertiesBabel.put("url", "jdbc:sqlserver://" + properties.getProperty("URL") + ":" + port); + + String other_prop = ""; + + String connectionString_babel = createConnectionString(result, connectionPropertiesBabel, other_prop); + + try { + bw.write(strLine); + bw.newLine(); + + // establish connection using connection string + DriverManager.getConnection(connectionString_babel); + + bw.write("~~SUCCESS~~"); + bw.newLine(); + + } catch (SQLException e) { + handleSQLExceptionWithFile(e, bw, logger); + } catch (IOException ioe) { + logger.error("IO Exception: " + ioe.getMessage(), ioe); + } + } + + private String createConnectionString(String[] result, Properties connectionPropertiesBabel, String other_prop) { + for (int i = 1; i < result.length; i++) { + if (result[i].startsWith("others")) { + other_prop = result[i].replaceFirst("others\\|-\\|", ""); + } else { + String[] property = result[i].split("\\|-\\|", -1); + connectionPropertiesBabel.put(property[0], property[1]); + } + } + + return connectionPropertiesBabel.get("url") + + ";" + "databaseName=" + connectionPropertiesBabel.get("database") + + ";" + "user=" + connectionPropertiesBabel.get("user") + + ";" + "password=" + connectionPropertiesBabel.get("password") + + ";" + other_prop; + } +} diff --git a/contrib/test/JDBC/src/main/java/com/sqlsamples/JDBCBulkCopy.java b/contrib/test/JDBC/src/main/java/com/sqlsamples/JDBCBulkCopy.java new file mode 100644 index 00000000000..5b12c00176a --- /dev/null +++ b/contrib/test/JDBC/src/main/java/com/sqlsamples/JDBCBulkCopy.java @@ -0,0 +1,47 @@ +package com.sqlsamples; + +import com.microsoft.sqlserver.jdbc.SQLServerBulkCopy; +import com.microsoft.sqlserver.jdbc.SQLServerException; +import org.apache.logging.log4j.Logger; + +import java.io.BufferedWriter; +import java.io.IOException; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +import static com.sqlsamples.HandleException.handleSQLExceptionWithFile; + +public class JDBCBulkCopy { + + void executeInsertBulk(Connection con_bbl, String destinationTable, String sourceTable, Logger logger, BufferedWriter bw) + { + ResultSet rsSourceData = null; + Statement stmt_sql = null; + Statement stmt_bbl = null; + try { + stmt_bbl = con_bbl.createStatement(); + rsSourceData = stmt_bbl.executeQuery("select * from " + sourceTable); + } catch (SQLException e) { + handleSQLExceptionWithFile(e, bw, logger); + return; + } + try { + SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con_bbl); + bulkCopy.setDestinationTableName(destinationTable); + bulkCopy.writeToServer(rsSourceData); + + /* To fetch the rowcount we have added this implicit query. */ + rsSourceData = stmt_bbl.executeQuery("Select @@rowcount"); + rsSourceData.next(); + bw.write("~~ROW COUNT: " + rsSourceData.getString(1) + "~~"); + bw.newLine(); + bw.newLine(); + } catch (SQLException e) { + handleSQLExceptionWithFile(e, bw, logger); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/contrib/test/JDBC/src/main/java/com/sqlsamples/JDBCCallableStatement.java b/contrib/test/JDBC/src/main/java/com/sqlsamples/JDBCCallableStatement.java new file mode 100644 index 00000000000..5baf2ebeddf --- /dev/null +++ b/contrib/test/JDBC/src/main/java/com/sqlsamples/JDBCCallableStatement.java @@ -0,0 +1,196 @@ +package com.sqlsamples; + +import com.microsoft.sqlserver.jdbc.SQLServerCallableStatement; +import com.microsoft.sqlserver.jdbc.SQLServerDataTable; +import microsoft.sql.DateTimeOffset; +import org.apache.logging.log4j.Logger; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.*; +import java.math.BigDecimal; +import java.sql.*; +import java.sql.Date; +import java.text.DecimalFormat; +import java.text.NumberFormat; +import java.text.ParseException; +import java.time.LocalTime; +import java.util.*; + +import static com.sqlsamples.HandleException.handleSQLExceptionWithFile; + +public class JDBCCallableStatement { + + CallableStatement cstmt_bbl; + + void createCallableStatements(Connection con_bbl, String SQL, BufferedWriter bw, Logger logger) { + try { + cstmt_bbl = con_bbl.prepareCall(SQL); + } catch (SQLException e) { + handleSQLExceptionWithFile(e, bw, logger); + } + } + + void closeCallableStatements(BufferedWriter bw, Logger logger) { + try { + if (cstmt_bbl != null) cstmt_bbl.close(); + } catch (SQLException e) { + handleSQLExceptionWithFile(e, bw, logger); + } + } + + // function to write output of executed callable statement to a file + void testCallableStatementWithFile(String[] result, BufferedWriter bw, String strLine, Logger logger){ + try { + bw.write(strLine); + bw.newLine(); + set_bind_values(result, cstmt_bbl, bw, logger); + + boolean resultSetExist = false; + int resultsProcessed = 0; + try { + resultSetExist = cstmt_bbl.execute(); + } catch (SQLException e) { + handleSQLExceptionWithFile(e, bw, logger); + resultsProcessed++; + } + CompareResults.processResults(cstmt_bbl, bw, resultsProcessed, resultSetExist, logger); + } catch (IOException ioe) { + logger.error("IO Exception: " + ioe.getMessage(), ioe); + } + } + + + // method to set values of bind variables in a callable statement + private void set_bind_values(String[] result, CallableStatement cstmt, BufferedWriter bw, Logger logger) { + + for (int j = 3; j < (result.length); j++) { + String[] parameter = result[j].split("\\|-\\|", -1); + parameter[0] = parameter[0].toLowerCase(); + try{ + if (parameter[parameter.length - 1].toLowerCase().contains("out")) { + cstmt.registerOutParameter(j - 2, CompareResults.SQLtoJDBCDataTypeMapping(parameter[0])); + } + if (parameter[parameter.length - 1].toLowerCase().contains("in")) { + /* TODO: Add more data types here as we support them */ + if (parameter[2].equalsIgnoreCase("")) { + cstmt.setNull(j - 2, CompareResults.SQLtoJDBCDataTypeMapping(parameter[0])); + } else if (parameter[0].equalsIgnoreCase("int")) { + // if there is decimal point, remove everything after the point + if (parameter[2].indexOf('.') != -1) parameter[2] = parameter[2].substring(0, parameter[2].indexOf('.') - 1); + cstmt.setInt(j - 2, Integer.parseInt(parameter[2])); + } else if (parameter[0].equalsIgnoreCase("string") + || parameter[0].equalsIgnoreCase("char") + || parameter[0].equalsIgnoreCase("nchar") + || parameter[0].equalsIgnoreCase("varchar") + || parameter[0].equalsIgnoreCase("nvarchar") + || parameter[0].equalsIgnoreCase("uniqueidentifier") + || parameter[0].equalsIgnoreCase("varcharmax") + || parameter[0].equalsIgnoreCase("nvarcharmax")) { + cstmt.setString(j - 2, parameter[2]); + } else if (parameter[0].equalsIgnoreCase("boolean") + || parameter[0].equalsIgnoreCase("bit")) { + cstmt.setBoolean(j - 2, Boolean.parseBoolean(parameter[2])); + } else if (parameter[0].equalsIgnoreCase("long") + || parameter[0].equalsIgnoreCase("bigint")) { + cstmt.setLong(j - 2, Long.parseLong(parameter[2])); + } else if (parameter[0].equalsIgnoreCase("double") + || parameter[0].equalsIgnoreCase("float")) { + cstmt.setDouble(j - 2, Double.parseDouble(parameter[2])); + } else if (parameter[0].equalsIgnoreCase("unsigned_char") + || parameter[0].equalsIgnoreCase("smallint") + || parameter[0].equalsIgnoreCase("tinyint")) { + cstmt.setShort(j - 2, Short.parseShort(parameter[2])); + } else if (parameter[0].equalsIgnoreCase("real")) { + cstmt.setFloat(j - 2, Float.parseFloat(parameter[2])); + } else if (parameter[0].equalsIgnoreCase("byte")) { + cstmt.setByte(j - 2, Byte.parseByte(parameter[2])); + } else if (parameter[0].equalsIgnoreCase("binary") + || parameter[0].equalsIgnoreCase("varbinary") + || parameter[0].equalsIgnoreCase("timestamp") + || parameter[0].equalsIgnoreCase("udt")) { + byte[] byteArray = parameter[2].getBytes(); + cstmt.setBytes(j - 2, byteArray); + } else if (parameter[0].equalsIgnoreCase("decimal") + || parameter[0].equalsIgnoreCase("money") + || parameter[0].equalsIgnoreCase("smallmoney") + || parameter[0].equalsIgnoreCase("numeric")) { + DecimalFormat format = (DecimalFormat) NumberFormat.getInstance(Locale.US); + format.setParseBigDecimal(true); + // remove dollar sign else parsing decimal from this will throw exception + String decimalString = parameter[2].replace("$", ""); + BigDecimal number = (BigDecimal) format.parse(decimalString); + cstmt.setBigDecimal(j - 2, number); + } else if (parameter[0].equalsIgnoreCase("datetime") + || parameter[0].equalsIgnoreCase("datetime2") + || parameter[0].equalsIgnoreCase("smalldatetime")) { + cstmt.setTimestamp(j - 2, Timestamp.valueOf(parameter[2])); + } else if (parameter[0].equalsIgnoreCase("date")) { + cstmt.setDate(j - 2, Date.valueOf(parameter[2])); + } else if (parameter[0].equalsIgnoreCase("time")) { + cstmt.setTime(j - 2, Time.valueOf(LocalTime.parse(parameter[2]))); + } else if (parameter[0].equalsIgnoreCase("datetimeoffset")) { + SQLServerCallableStatement ssCstmt = (SQLServerCallableStatement) cstmt; + ssCstmt.setDateTimeOffset(j - 1, DateTimeOffset.valueOf(Timestamp.valueOf(parameter[2]), 0)); + cstmt = ssCstmt; + } else if (parameter[0].equalsIgnoreCase("text") + || parameter[0].equalsIgnoreCase("ntext")) { + Reader r = new FileReader(parameter[2]); + cstmt.setCharacterStream(j - 2, r); + } else if (parameter[0].equalsIgnoreCase("image")) { + File file = new File(parameter[2]); + BufferedImage bImage = ImageIO.read(file); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ImageIO.write(bImage, "jpg", bos); + byte[] byteArray = bos.toByteArray(); + cstmt.setBytes(j - 2, byteArray); + } else if (parameter[0].equalsIgnoreCase("xml")) { + SQLXML sqlxml = cstmt.getConnection().createSQLXML(); + sqlxml.setString(parameter[2]); + cstmt.setSQLXML(j - 2, sqlxml); + } else if (parameter[0].equalsIgnoreCase("tvp")) { + FileInputStream fstream = new FileInputStream(parameter[2]); + DataInputStream in = new DataInputStream(fstream); + BufferedReader br = new BufferedReader(new InputStreamReader(in)); + + SQLServerDataTable sourceDataTable = new SQLServerDataTable(); + + // first line of file has table columns and their data types + String strLine = br.readLine(); + + String[] columnMetaData = strLine.split(","); + + for (String columnMetaDatum : columnMetaData) { + String[] column = columnMetaDatum.split("-"); + sourceDataTable.addColumnMetadata(column[0], CompareResults.SQLtoJDBCDataTypeMapping(column[1])); + } + + // process and add all rows to data table + while ((strLine = br.readLine()) != null) { + String[] row = strLine.split(","); + ArrayList rowTuple = new ArrayList<>(); + + for(int i = 0; i < row.length; i++) { + rowTuple.add(CompareResults.parse_data(row[i], columnMetaData[i], logger)); + } + sourceDataTable.addRow(rowTuple); + } + + // setStructured API is only applicable to SQLServerCallableStatement + SQLServerCallableStatement ssCstmt = (SQLServerCallableStatement) cstmt; + ssCstmt.setStructured(j - 1, parameter[1], sourceDataTable); + cstmt = ssCstmt; + } + } + } catch (ParseException pe) { + logger.error("Parse Exception: " + pe.getMessage(), pe); + } catch (SQLException se) { + handleSQLExceptionWithFile(se, bw, logger); + } catch (FileNotFoundException e) { + logger.error("File Not Found Exception: " + e.getMessage(), e); + } catch (IOException e) { + logger.error("IO Exception: " + e.getMessage(), e); + } + } + } +} diff --git a/contrib/test/JDBC/src/main/java/com/sqlsamples/JDBCCrossDialect.java b/contrib/test/JDBC/src/main/java/com/sqlsamples/JDBCCrossDialect.java new file mode 100644 index 00000000000..4eb1701e771 --- /dev/null +++ b/contrib/test/JDBC/src/main/java/com/sqlsamples/JDBCCrossDialect.java @@ -0,0 +1,170 @@ +package com.sqlsamples; + +import org.apache.logging.log4j.*; + +import java.util.*; +import java.io.BufferedWriter; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; + +import static com.sqlsamples.Config.*; +import static com.sqlsamples.HandleException.handleSQLExceptionWithFile; + +public class JDBCCrossDialect { + + String URL = properties.getProperty("URL"); + String tsql_port = properties.getProperty("tsql_port"); + String psql_port = properties.getProperty("psql_port"); + String databaseName = properties.getProperty("databaseName"); + String physicalDatabaseName = properties.getProperty("physicalDatabaseName"); + String user = properties.getProperty("user"); + String password = properties.getProperty("password"); + + // Key is the username, password and database name concatenated + // Value is the connection object created using the above 3 attributes + HashMap tsqlConnectionMap = new HashMap<>(); + HashMap psqlConnectionMap = new HashMap<>(); + + String newUser = null; + String newPassword = null; + String newDatabase = null; + String newPhysicalDatabase = null; + String searchPath = null; + + JDBCCrossDialect (Connection connection) { + + // Add already established connection to appropriate hash map + if (JDBCDriver.equalsIgnoreCase("sqlserver")) + tsqlConnectionMap.put(user, connection); + + if (JDBCDriver.equalsIgnoreCase("postgresql")) + psqlConnectionMap.put(user, connection); + } + + void getConnectionAttributes (String strLine) { + // Extract username, password and database from string + String[] connAttributes = strLine.split("\\s+"); + + // First two elements of array will be "--" and ("tsql" or "psql") + for (int i = 2; i < connAttributes.length; i++) { + String connAttribute = connAttributes[i]; + + if (connAttribute.contains("user=")) { + newUser = connAttribute.split("=")[1]; + } else if (connAttribute.contains("password=")) { + newPassword = connAttribute.split("=")[1]; + } else if (connAttribute.contains("database=")) { + newDatabase = connAttribute.split("=")[1]; + } else if (connAttribute.contains("currentSchema=")) { + searchPath = connAttribute.split("=")[1]; + } + } + + // If a connection attribute is not provided, we take the value from config file + if (newUser == null) + newUser = user; + + if (newPassword == null) + newPassword = password; + + if (newDatabase == null) + newDatabase = databaseName; + + if (newPhysicalDatabase == null) + newPhysicalDatabase = physicalDatabaseName; + } + + void resetConnectionAttributes () { + newUser = null; + newPassword = null; + newDatabase = null; + } + + Connection getTsqlConnection (String strLine, BufferedWriter bw, Logger logger) { + + Connection tsqlConnection = null; + + getConnectionAttributes(strLine); + + try { + // Use sqlserver JDBC driver + Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); + + // if we already have opened a tsql connection then reuse that + tsqlConnection = tsqlConnectionMap.get(newUser + newPassword + newDatabase); + + if (tsqlConnection == null) { + // Create a new connection on tsql port and use that + String connectionString = createSQLServerConnectionString(URL, tsql_port, newDatabase, newUser, newPassword); + tsqlConnection = DriverManager.getConnection(connectionString); + + tsqlConnectionMap.put(newUser + newPassword + newDatabase, tsqlConnection); + } + + } catch (ClassNotFoundException e) { + logger.error("Class Not Found Exception: " + e.getMessage(), e); + } catch (SQLException se) { + handleSQLExceptionWithFile(se, bw, logger); + } + + resetConnectionAttributes(); + + return tsqlConnection; + } + + Connection getPsqlConnection (String strLine, BufferedWriter bw, Logger logger) { + + Connection psqlConnection = null; + + getConnectionAttributes(strLine); + + try { + // Use postgresql JDBC driver + Class.forName("org.postgresql.Driver"); + + // if we already have opened a psql connection then reuse that + psqlConnection = psqlConnectionMap.get(newUser + newPassword + newPhysicalDatabase + searchPath); + + // Create a new connection on psql port and use that + if (psqlConnection == null) { + String connectionString = createPostgreSQLConnectionString(URL, psql_port, newPhysicalDatabase, newUser, newPassword); + + if (searchPath != null) { + connectionString += ("¤tSchema=" + searchPath); + } + psqlConnection = DriverManager.getConnection(connectionString); + + psqlConnectionMap.put(newUser + newPassword + newPhysicalDatabase + searchPath, psqlConnection); + } + + } catch (ClassNotFoundException e) { + logger.error("Class Not Found Exception: " + e.getMessage(), e); + } catch (SQLException se) { + handleSQLExceptionWithFile(se, bw, logger); + } + + resetConnectionAttributes(); + + return psqlConnection; + } + + void closeConnectionsUtil (HashMap connectionMap, BufferedWriter bw, Logger logger) { + connectionMap.forEach( + (connectionAttribute, connection) -> { + if (connection != null) { + try { + connection.close(); + } catch (SQLException e) { + handleSQLExceptionWithFile(e, bw, logger); + } + } + } + ); + } + + void closeConnections (BufferedWriter bw, Logger logger) { + closeConnectionsUtil(tsqlConnectionMap, bw, logger); + closeConnectionsUtil(psqlConnectionMap, bw, logger); + } +} diff --git a/contrib/test/JDBC/src/main/java/com/sqlsamples/JDBCCursor.java b/contrib/test/JDBC/src/main/java/com/sqlsamples/JDBCCursor.java new file mode 100644 index 00000000000..c54aa353b26 --- /dev/null +++ b/contrib/test/JDBC/src/main/java/com/sqlsamples/JDBCCursor.java @@ -0,0 +1,192 @@ +package com.sqlsamples; + +import org.apache.logging.log4j.Logger; + +import java.io.BufferedWriter; +import java.io.IOException; +import java.sql.*; +import java.util.ArrayList; +import java.util.List; + +import static com.sqlsamples.HandleException.handleSQLExceptionWithFile; + +public class JDBCCursor { + + ResultSet cursor_bbl; + PreparedStatement pstmt_bbl; + + int[] setCursorOptions(int i, String[] result, Logger logger) { + int type = ResultSet.TYPE_FORWARD_ONLY; + int concur = ResultSet.CONCUR_READ_ONLY; + int holdability = 0; + + for(; i < result.length; i++) { + if (result[i].equalsIgnoreCase("TYPE_FORWARD_ONLY")) { + logger.info("Setting cursor type: forward-only"); + type = ResultSet.TYPE_FORWARD_ONLY; + } else if (result[i].equalsIgnoreCase("TYPE_SCROLL_SENSITIVE")) { + logger.info("Setting cursor type: scroll sensitive"); + type = ResultSet.TYPE_SCROLL_SENSITIVE; + } else if (result[i].equalsIgnoreCase("TYPE_SCROLL_INSENSITIVE")) { + logger.info("Setting cursor type: scroll insensitive"); + type = ResultSet.TYPE_SCROLL_INSENSITIVE; + } else if (result[i].equalsIgnoreCase("CONCUR_READ_ONLY")) { + logger.info("Setting cursor concurrency: read-only"); + concur = ResultSet.CONCUR_READ_ONLY; + } else if (result[i].equalsIgnoreCase("CONCUR_UPDATABLE")) { + logger.info("Setting cursor concurrency: updatable"); + concur = ResultSet.CONCUR_UPDATABLE; + } else if (result[i].equalsIgnoreCase("HOLD_CURSORS_OVER_COMMIT")) { + logger.info("Setting cursor holdability: hold cursors over commit"); + holdability = ResultSet.HOLD_CURSORS_OVER_COMMIT; + } else if (result[i].equalsIgnoreCase("CLOSE_CURSORS_AT_COMMIT")) { + logger.info("Setting cursor holdability: close cursors at commit"); + holdability = ResultSet.CLOSE_CURSORS_AT_COMMIT; + } else { + logger.error("Invalid Cursor attribute!"); + } + } + + return new int[]{type, concur, holdability}; + } + + void openCursor(Connection con_bbl, Logger logger, String[] result, String strLine, BufferedWriter bw) { + logger.info("Opening Cursor"); + + if (result[2].toLowerCase().startsWith("prepst")) { + openCursorOnPreparedStatement(con_bbl, logger, result, bw); + } else { + openCursorOnStatement(con_bbl, bw, logger, result); + } + } + + void openCursorOnPreparedStatement(Connection con_bbl, Logger logger, String[] result, BufferedWriter bw) { + // array with prepared statement relevant contents + List contents = new ArrayList<>(); + contents.add(result[2]); + contents.add(result[3]); + + int i; + + // while the result array contains prepared statement relevant delimiter + // add those array elements to contents' list + for (i = 4; i < result.length && result[i].contains("|-|"); i++) { + contents.add(result[i]); + } + + String[] contentsArray = contents.toArray(new String[0]); + + // set cursor options + int[] cursorOptions = setCursorOptions(i, result, logger); + int type = cursorOptions[0]; + int concur = cursorOptions[1]; + int holdability = cursorOptions[2]; + + String SQL = contentsArray[1]; + + try { + con_bbl.setHoldability(holdability); + if (!result[3].toLowerCase().startsWith("exec")) { + if (pstmt_bbl != null) pstmt_bbl.close(); + pstmt_bbl = con_bbl.prepareStatement(SQL, type, concur); + } + + JDBCPreparedStatement.set_bind_values(contentsArray, pstmt_bbl, bw, logger); + cursor_bbl = pstmt_bbl.executeQuery(); + bw.write("~~SUCCESS~~"); + bw.newLine(); + } catch (SQLException e) { + handleSQLExceptionWithFile(e, bw, logger); + } catch (IOException ioe) { + logger.error("IO Exception: " + ioe.getMessage(), ioe); + } + } + + void openCursorOnStatement(Connection con_bbl, BufferedWriter bw, Logger logger, String[] result) { + // set cursor options + int[] cursorOptions = setCursorOptions(3, result, logger); + int type = cursorOptions[0]; + int concur = cursorOptions[1]; + int holdability = cursorOptions[2]; + + String SQL = result[2]; + Statement stmt_sql = null, stmt_bbl = null; + + try { + con_bbl.setHoldability(holdability); + stmt_bbl = con_bbl.createStatement(type, concur); + cursor_bbl = stmt_bbl.executeQuery(SQL); + bw.write("~~SUCCESS~~"); + bw.newLine(); + } catch (SQLException e) { + handleSQLExceptionWithFile(e, bw, logger); + } catch (IOException ioe) { + logger.error("IO Exception: " + ioe.getMessage(), ioe); + } + } + + void cursorFetch(BufferedWriter bw, Logger logger, String[] result) { + + try { + if (cursor_bbl == null) { + bw.write("~~ERROR~~"); + bw.newLine(); + } else if (result[2].toLowerCase().startsWith("beforefirst")) { + cursor_bbl.beforeFirst(); + bw.write("~~SUCCESS~~"); + bw.newLine(); + } else if (result[2].toLowerCase().startsWith("afterlast")) { + cursor_bbl.afterLast(); + bw.write("~~SUCCESS~~"); + bw.newLine(); + } else if (result[2].toLowerCase().startsWith("first")) { + cursor_bbl.first(); + CompareResults.writeCursorResultSetToFile(bw, cursor_bbl, logger); + } else if (result[2].toLowerCase().startsWith("last")) { + cursor_bbl.last(); + CompareResults.writeCursorResultSetToFile(bw, cursor_bbl, logger); + } else if (result[2].toLowerCase().startsWith("next")) { + cursor_bbl.next(); + CompareResults.writeCursorResultSetToFile(bw, cursor_bbl, logger); + } else if (result[2].toLowerCase().startsWith("prev")) { + cursor_bbl.previous(); + CompareResults.writeCursorResultSetToFile(bw, cursor_bbl, logger); + } else if (result[2].toLowerCase().startsWith("abs") || result[2].toLowerCase().startsWith("rel")) { + if (result.length < 4 || result[3].length() == 0 || result[3].matches("[ \\t]+")) { + bw.write("~~ERROR~~"); + bw.newLine(); + } else { + int pos = Integer.parseInt(result[3]); + + if (result[2].toLowerCase().startsWith("abs")) { + cursor_bbl.absolute(pos); + } else { + cursor_bbl.relative(pos); + } + CompareResults.writeCursorResultSetToFile(bw, cursor_bbl, logger); + } + } else { + bw.write("~~ERROR~~"); + bw.newLine(); + } + } catch (SQLException e) { + handleSQLExceptionWithFile(e, bw, logger); + } catch (IOException ioe) { + logger.error("IO Exception: " + ioe.getMessage(), ioe); + } + } + + void cursorClose(BufferedWriter bw, Logger logger) { + logger.info("Closing cursors"); + + try { + if (cursor_bbl != null) cursor_bbl.close(); + bw.write("~~SUCCESS~~"); + bw.newLine(); + } catch(SQLException e) { + handleSQLExceptionWithFile(e, bw, logger); + } catch (IOException ioe) { + logger.error("IO Exception: " + ioe.getMessage(), ioe); + } + } +} diff --git a/contrib/test/JDBC/src/main/java/com/sqlsamples/JDBCPreparedStatement.java b/contrib/test/JDBC/src/main/java/com/sqlsamples/JDBCPreparedStatement.java new file mode 100644 index 00000000000..ae0a01155e4 --- /dev/null +++ b/contrib/test/JDBC/src/main/java/com/sqlsamples/JDBCPreparedStatement.java @@ -0,0 +1,191 @@ +package com.sqlsamples; + +import com.microsoft.sqlserver.jdbc.SQLServerDataTable; +import com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement; +import microsoft.sql.DateTimeOffset; +import org.apache.logging.log4j.Logger; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.*; +import java.math.BigDecimal; +import java.sql.*; +import java.text.DecimalFormat; +import java.text.NumberFormat; +import java.text.ParseException; +import java.time.LocalTime; +import java.util.ArrayList; +import java.util.Locale; + +import static com.sqlsamples.HandleException.handleSQLExceptionWithFile; + +public class JDBCPreparedStatement { + + PreparedStatement pstmt_bbl; + + void createPreparedStatements(Connection con_bbl, String SQL, BufferedWriter bw, Logger logger) { + try { + pstmt_bbl = con_bbl.prepareStatement(SQL); + } catch (SQLException e) { + handleSQLExceptionWithFile(e, bw, logger); + } + } + + void closePreparedStatements(BufferedWriter bw, Logger logger) { + try { + if (pstmt_bbl != null) pstmt_bbl.close(); + } catch (SQLException e) { + handleSQLExceptionWithFile(e, bw, logger); + } + } + + // function to write output of executed prepared statement to a file + void testPreparedStatementWithFile(String[] result, BufferedWriter bw, String strLine, Logger logger){ + try { + bw.write(strLine); + bw.newLine(); + set_bind_values(result, pstmt_bbl, bw, logger); + + boolean resultSetExist = false; + int resultsProcessed = 0; + try { + resultSetExist = pstmt_bbl.execute(); + } catch (SQLException e) { + handleSQLExceptionWithFile(e, bw, logger); + resultsProcessed++; + } + CompareResults.processResults(pstmt_bbl, bw, resultsProcessed, resultSetExist, logger); + } catch (IOException ioe) { + logger.error("IO Exception: " + ioe.getMessage(), ioe); + } + } + + // method to set values of bind variables in a prepared statement + static void set_bind_values(String[] result, PreparedStatement pstmt, BufferedWriter bw, Logger logger) { + + for (int j = 2; j < (result.length); j++) { + String[] parameter = result[j].split("\\|-\\|", -1); + + try{ + /* TODO: Add more data types here as we support them */ + if(parameter[2].equalsIgnoreCase("")){ + pstmt.setNull(j - 1, CompareResults.SQLtoJDBCDataTypeMapping(parameter[0])); + } else if (parameter[0].equalsIgnoreCase("int")) { + // if there is decimal point, remove everything after the point + if (parameter[2].indexOf('.') != -1) parameter[2] = parameter[2].substring(0, parameter[2].indexOf('.') - 1); + pstmt.setInt(j - 1, Integer.parseInt(parameter[2])); + } else if (parameter[0].equalsIgnoreCase("string") + || parameter[0].equalsIgnoreCase("char") + || parameter[0].equalsIgnoreCase("nchar") + || parameter[0].equalsIgnoreCase("varchar") + || parameter[0].equalsIgnoreCase("nvarchar") + || parameter[0].equalsIgnoreCase("uniqueidentifier") + || parameter[0].equalsIgnoreCase("varcharmax") + || parameter[0].equalsIgnoreCase("nvarcharmax")) { + pstmt.setString(j - 1, parameter[2]); + } else if (parameter[0].equalsIgnoreCase("boolean") + || parameter[0].equalsIgnoreCase("bit")) { + pstmt.setBoolean(j - 1, Boolean.parseBoolean(parameter[2])); + } else if (parameter[0].equalsIgnoreCase("long") + || parameter[0].equalsIgnoreCase("bigint")) { + pstmt.setLong(j - 1, Long.parseLong(parameter[2])); + } else if (parameter[0].equalsIgnoreCase("double") + || parameter[0].equalsIgnoreCase("float")) { + pstmt.setDouble(j - 1, Double.parseDouble(parameter[2])); + } else if (parameter[0].equalsIgnoreCase("unsigned_char") + || parameter[0].equalsIgnoreCase("smallint") + || parameter[0].equalsIgnoreCase("tinyint")) { + pstmt.setShort(j - 1, Short.parseShort(parameter[2])); + } else if (parameter[0].equalsIgnoreCase("real")) { + pstmt.setFloat(j - 1, Float.parseFloat(parameter[2])); + } else if (parameter[0].equalsIgnoreCase("byte")) { + pstmt.setByte(j - 1, Byte.parseByte(parameter[2])); + } else if (parameter[0].equalsIgnoreCase("binary") + || parameter[0].equalsIgnoreCase("varbinary") + || parameter[0].equalsIgnoreCase("timestamp") + || parameter[0].equalsIgnoreCase("udt")) { + byte[] byteArray = parameter[2].getBytes(); + pstmt.setBytes(j - 1, byteArray); + } else if (parameter[0].equalsIgnoreCase("decimal") + || parameter[0].equalsIgnoreCase("money") + || parameter[0].equalsIgnoreCase("smallmoney") + || parameter[0].equalsIgnoreCase("numeric")) { + DecimalFormat format = (DecimalFormat) NumberFormat.getInstance(Locale.US); + format.setParseBigDecimal(true); + // remove dollar sign else parsing decimal from this will throw exception + String decimalString = parameter[2].replace("$", ""); + BigDecimal number = (BigDecimal) format.parse(decimalString); + pstmt.setBigDecimal(j - 1, number); + } else if (parameter[0].equalsIgnoreCase("datetime") + || parameter[0].equalsIgnoreCase("datetime2") + || parameter[0].equalsIgnoreCase("smalldatetime")) { + pstmt.setTimestamp(j - 1, Timestamp.valueOf(parameter[2])); + } else if (parameter[0].equalsIgnoreCase("date")) { + pstmt.setDate(j - 1, Date.valueOf(parameter[2])); + } else if (parameter[0].equalsIgnoreCase("time")) { + pstmt.setTime(j - 1, Time.valueOf(LocalTime.parse(parameter[2]))); + } else if (parameter[0].equalsIgnoreCase("datetimeoffset")) { + SQLServerPreparedStatement ssPstmt = (SQLServerPreparedStatement) pstmt; + ssPstmt.setDateTimeOffset(j - 1, DateTimeOffset.valueOf(Timestamp.valueOf(parameter[2]), 0)); + pstmt = ssPstmt; + } else if (parameter[0].equalsIgnoreCase("text") + || parameter[0].equalsIgnoreCase("ntext")) { + Reader r = new FileReader(parameter[2]); + pstmt.setCharacterStream(j - 1, r); + } else if (parameter[0].equalsIgnoreCase("image")) { + File file = new File(parameter[2]); + BufferedImage bImage = ImageIO.read(file); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ImageIO.write(bImage, "jpg", bos ); + byte [] byteArray = bos.toByteArray(); + pstmt.setBytes(j - 1, byteArray); + } else if (parameter[0].equalsIgnoreCase("xml")) { + SQLXML sqlxml = pstmt.getConnection().createSQLXML(); + sqlxml.setString(parameter[2]); + pstmt.setSQLXML(j - 1, sqlxml); + } else if (parameter[0].equalsIgnoreCase("tvp")) { + FileInputStream fstream = new FileInputStream(parameter[2]); + DataInputStream in = new DataInputStream(fstream); + BufferedReader br = new BufferedReader(new InputStreamReader(in)); + + SQLServerDataTable sourceDataTable = new SQLServerDataTable(); + + // first line of file has table columns and their data types + String strLine = br.readLine(); + + String[] columnMetaData = strLine.split(","); + + for (String columnMetaDatum : columnMetaData) { + String[] column = columnMetaDatum.split("-"); + sourceDataTable.addColumnMetadata(column[0], CompareResults.SQLtoJDBCDataTypeMapping(column[1])); + } + + // process and add all rows to data table + while ((strLine = br.readLine()) != null) { + String[] row = strLine.split(","); + ArrayList rowTuple = new ArrayList<>(); + + for(int i = 0; i < row.length; i++) { + String columnDataType = columnMetaData[i].split("-")[1]; + Object value = CompareResults.parse_data(row[i], columnDataType, logger); + rowTuple.add(value); + } + sourceDataTable.addRow(rowTuple.toArray()); + } + + SQLServerPreparedStatement ssPstmt = (SQLServerPreparedStatement) pstmt; + ssPstmt.setStructured(j - 1, parameter[1], sourceDataTable); + pstmt = ssPstmt; + } + } catch (SQLException se) { + handleSQLExceptionWithFile(se, bw, logger); + } catch (FileNotFoundException e) { + logger.error("File Not Found Exception: " + e.getMessage(), e); + } catch (IOException e) { + logger.error("IO Exception: " + e.getMessage(), e); + } catch (ParseException e) { + logger.error("Parse Exception: " + e.getMessage(), e); + } + } + } +} diff --git a/contrib/test/JDBC/src/main/java/com/sqlsamples/JDBCStatement.java b/contrib/test/JDBC/src/main/java/com/sqlsamples/JDBCStatement.java new file mode 100644 index 00000000000..4f012c29793 --- /dev/null +++ b/contrib/test/JDBC/src/main/java/com/sqlsamples/JDBCStatement.java @@ -0,0 +1,53 @@ +package com.sqlsamples; + +import org.apache.logging.log4j.Logger; + +import java.io.BufferedWriter; +import java.io.IOException; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +import static com.sqlsamples.HandleException.handleSQLExceptionWithFile; + +public class JDBCStatement { + + Statement stmt_bbl; + + void createStatements(Connection con_bbl, BufferedWriter bw, Logger logger) { + try { + stmt_bbl = con_bbl.createStatement(); + } catch (SQLException e) { + handleSQLExceptionWithFile(e, bw, logger); + } + } + + void closeStatements(BufferedWriter bw, Logger logger) { + try { + if (stmt_bbl != null) stmt_bbl.close(); + } catch (SQLException e) { + handleSQLExceptionWithFile(e, bw, logger); + } + } + + // function to write output of executed statement to a file + void testStatementWithFile(String SQL, BufferedWriter bw, String strLine, Logger logger){ + try { + bw.write(strLine); + bw.newLine(); + + boolean resultSetExist = false; + int resultsProcessed = 0; + try { + resultSetExist = stmt_bbl.execute(SQL); + } catch (SQLException e) { + handleSQLExceptionWithFile(e, bw, logger); + resultsProcessed++; + } + CompareResults.processResults(stmt_bbl, bw, resultsProcessed, resultSetExist, logger); + } catch (IOException ioe) { + logger.error("IO Exception: " + ioe.getMessage(), ioe); + } + } +} diff --git a/contrib/test/JDBC/src/main/java/com/sqlsamples/JDBCTransaction.java b/contrib/test/JDBC/src/main/java/com/sqlsamples/JDBCTransaction.java new file mode 100644 index 00000000000..24cf748d7bb --- /dev/null +++ b/contrib/test/JDBC/src/main/java/com/sqlsamples/JDBCTransaction.java @@ -0,0 +1,121 @@ +package com.sqlsamples; + +import org.apache.logging.log4j.Logger; + +import java.io.BufferedWriter; +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Savepoint; +import java.util.*; + +import static com.sqlsamples.HandleException.handleSQLExceptionWithFile; +import static java.sql.Connection.*; + +public class JDBCTransaction { + + private HashMap> savepointMap = new HashMap<>(); + + void beginTransaction(Connection con_bbl, BufferedWriter bw, Logger logger) { + logger.info("Beginning transaction"); + + try { + con_bbl.setAutoCommit(false); + } catch (SQLException e) { + handleSQLExceptionWithFile(e, bw, logger); + } + } + + void transactionCommit(Connection con_bbl, BufferedWriter bw, Logger logger) { + logger.info("Committing transaction"); + + try { + con_bbl.commit(); + con_bbl.setAutoCommit(true); + } catch (SQLException e) { + handleSQLExceptionWithFile(e, bw, logger); + } + } + + void transactionRollback(Connection con_bbl, BufferedWriter bw, Logger logger) { + logger.info("Rolling back transaction"); + + try { + con_bbl.rollback(); + } catch (SQLException e) { + handleSQLExceptionWithFile(e, bw, logger); + } + } + + void transactionRollbackToSavepoint(Connection con_bbl, String[] result, BufferedWriter bw, Logger logger) { + logger.info("Rolling back to savepoint " + result[2]); + if (!savepointMap.containsKey(result[2])) { + logger.error("Savepoint with the name " + result[2] + " does not exist!"); + } else { + try { + con_bbl.rollback(savepointMap.get(result[2]).getKey()); + con_bbl.setAutoCommit(true); + } catch (SQLException e) { + handleSQLExceptionWithFile(e, bw, logger); + } + } + } + + + void setTransactionSavepoint(Connection con_bbl, BufferedWriter bw, Logger logger){ + // unnamed savepoint + logger.info("Setting unnamed savepoint"); + + try { + con_bbl.setSavepoint(); + } catch (SQLException e) { + handleSQLExceptionWithFile(e, bw, logger); + } + } + + void setTransactionNamedSavepoint(Connection con_bbl, String[] result, BufferedWriter bw, Logger logger) { + // named savepoint + logger.info("Setting savepoint " + result[2]); + + try { + Savepoint bblSavepoint = con_bbl.setSavepoint(result[2]); + savepointMap.put(result[2], new AbstractMap.SimpleEntry<>(bblSavepoint, null)); + } catch (SQLException e) { + handleSQLExceptionWithFile(e, bw, logger); + } + } + + void setTransactionIsolationLevelUtil(Connection con, int isolationLevel, BufferedWriter bw, Logger logger) { + try { + con.setTransactionIsolation(isolationLevel); + } catch (SQLException e) { + handleSQLExceptionWithFile(e, bw, logger); + } + } + + void setTransactionIsolationLevel(Connection con_bbl, String[] result, BufferedWriter bw, Logger logger) { + if (result.length < 3 || result[2].length() == 0 || result[2].matches("[ \\t]+")) { + logger.error("No isolation level specified!"); + } else { + String isolationLevel = result[2]; + + if (isolationLevel.toLowerCase().startsWith("ru")) { + logger.info("Transaction isolation level set to TRANSACTION_READ_UNCOMMITTED"); + setTransactionIsolationLevelUtil(con_bbl, TRANSACTION_READ_UNCOMMITTED, bw, logger); + } else if (isolationLevel.toLowerCase().startsWith("rc")) { + logger.info("Transaction isolation level set to TRANSACTION_READ_COMMITTED"); + setTransactionIsolationLevelUtil(con_bbl, TRANSACTION_READ_COMMITTED, bw, logger); + } else if (isolationLevel.toLowerCase().startsWith("rr")) { + logger.info("Transaction isolation level set to TRANSACTION_REPEATABLE_READ"); + setTransactionIsolationLevelUtil(con_bbl, TRANSACTION_REPEATABLE_READ, bw, logger); + } else if (isolationLevel.toLowerCase().startsWith("se")) { + logger.info("Transaction isolation level set to TRANSACTION_SERIALIZABLE"); + setTransactionIsolationLevelUtil(con_bbl, TRANSACTION_SERIALIZABLE, bw, logger); + } else if (isolationLevel.toLowerCase().startsWith("sn")) { + logger.info("Transaction isolation level set to TRANSACTION_SNAPSHOT"); + setTransactionIsolationLevelUtil(con_bbl, TRANSACTION_READ_COMMITTED + 4094, bw, logger); + } else { + logger.error("Invalid Transaction isolation level! Set from ru, rc, rr or s"); + } + } + } +} diff --git a/contrib/test/JDBC/src/main/java/com/sqlsamples/Statistics.java b/contrib/test/JDBC/src/main/java/com/sqlsamples/Statistics.java new file mode 100644 index 00000000000..270938480ba --- /dev/null +++ b/contrib/test/JDBC/src/main/java/com/sqlsamples/Statistics.java @@ -0,0 +1,34 @@ +package com.sqlsamples; + +import java.util.*; + +import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics; + +public class Statistics { + DescriptiveStatistics descriptiveStatistics; + static ArrayList exec_times = new ArrayList<>(); + + public Statistics(double[] values) { + descriptiveStatistics = new DescriptiveStatistics(values); + } + + public double mean() { + return descriptiveStatistics.getMean(); + } + + public double median() { + return descriptiveStatistics.getPercentile(50); + } + + public double stddev() { + return descriptiveStatistics.getStandardDeviation(); + } + + public double minimum() { + return descriptiveStatistics.getMin(); + } + + public double maximum() { + return descriptiveStatistics.getMax(); + } +} diff --git a/contrib/test/JDBC/src/main/java/com/sqlsamples/batch_run.java b/contrib/test/JDBC/src/main/java/com/sqlsamples/batch_run.java new file mode 100644 index 00000000000..442aee6daad --- /dev/null +++ b/contrib/test/JDBC/src/main/java/com/sqlsamples/batch_run.java @@ -0,0 +1,294 @@ +package com.sqlsamples; + +import org.apache.logging.log4j.Logger; + +import java.io.*; +import java.sql.*; +import java.util.*; + +import static java.util.Objects.isNull; + +import static com.sqlsamples.Config.*; +import static com.sqlsamples.Statistics.exec_times; + +public class batch_run { + + // method that iterates through an input file and writes output to corresponding .out file. + static void batch_run_sql(Connection con_bbl, BufferedWriter bw, String testFilePath, Logger logger) { + + boolean isSQLFile = testFilePath.contains(".sql"); + boolean isCrossDialectFile = false; + boolean tsqlDialect = false; + boolean psqlDialect = false; + + if (testFilePath.contains(".mix")) { + isCrossDialectFile = true; + isSQLFile = true; // we want to treat GO as a batch separator in this case + } + + // initializing objects + JDBCAuthentication jdbcAuthentication = new JDBCAuthentication(); + JDBCCallableStatement jdbcCallableStatement = new JDBCCallableStatement(); + JDBCCursor jdbcCursor = new JDBCCursor(); + JDBCPreparedStatement jdbcPreparedStatement = new JDBCPreparedStatement(); + JDBCStatement jdbcStatement = new JDBCStatement(); + JDBCTransaction jdbcTransaction = new JDBCTransaction(); + JDBCCrossDialect jdbcCrossDialect = null; + JDBCBulkCopy jdbcBulkCopy = new JDBCBulkCopy(); + + if (isCrossDialectFile) + jdbcCrossDialect = new JDBCCrossDialect(con_bbl); + + int passed = 0; + int failed = 0; + + try { + String SQL; // holds the SQL statement + StringBuilder sqlBatch = new StringBuilder(); + String strLine; // holds the current line which is getting executed + FileInputStream fstream; // stream of input file with the SQL batch queries to be tested + DataInputStream in; + BufferedReader br; + + fstream = new FileInputStream(testFilePath); + // get the object of DataInputStream + in = new DataInputStream(fstream); + br = new BufferedReader(new InputStreamReader(in)); + + // each iteration will process one line(SQL statement) from input file and compare result sets from SQL server and Babel instance + while ((strLine = br.readLine()) != null) { + // if line has no characters, or is commented out, or is a dotnet auth statement, proceed to next line + if (strLine.length() < 1 || strLine.startsWith("#") || strLine.startsWith("dotnet_auth")) { + if (strLine.length() < 1 || strLine.startsWith("#")) { + bw.write(strLine); + bw.newLine(); + } + continue; + } + + long startTime = System.nanoTime(); + + // if line starts with keyword "prepst", it means it is either a prep exec statement or an exec statement + if (strLine.startsWith("prepst")) { + + // Convert .NET input file format for prepared statement to JDBC + strLine = strLine.replaceAll("@[a-zA-Z0-9]+", "?"); + + String[] result; + // split wrt delimiter + result = strLine.split("#!#"); + // if an exec statement, set bind variables and execute query + if ((result[1].startsWith("exec")) || (result[1].startsWith("call"))) { + + StringBuilder params = new StringBuilder(); + // populate params with bind variables' types and values (used for logging only) + for (int i = 2; i < result.length; i++) { + params.append(result[i]); + if (i < result.length - 1) params.append(", "); + } + + logger.info("Executing an already prepared statement with the following bind variables: " + params.toString()); + jdbcPreparedStatement.testPreparedStatementWithFile(result, bw, strLine, logger); + + } else if (!result[1].equals("exec")) { + + jdbcPreparedStatement.closePreparedStatements(bw, logger); + + SQL = result[1]; + logger.info("Preparing the query: " + SQL); + + StringBuilder params = new StringBuilder(); + + for (int i = 2; i < result.length; i++) { + params.append(result[i]); + if (i < result.length - 1) params.append(", "); + } + + jdbcPreparedStatement.createPreparedStatements(con_bbl, SQL, bw, logger); + + logger.info("Executing with the bind variables " + params.toString()); + + jdbcPreparedStatement.testPreparedStatementWithFile(result, bw, strLine, logger); + } + + // if line starts with keyword "storedproc", it means it is a stored procedure + } else if (strLine.startsWith("storedproc")) { + + String[] result = strLine.split("#!#"); + + if (result[1].startsWith("prep")) { + + // close existing callable statements + jdbcCallableStatement.closeCallableStatements(bw, logger); + + SQL = result[2]; + StringBuilder bindparam = new StringBuilder(); + + for ( int i = 0; i <= result.length - 4; i++) { + if (i == 0) { + bindparam.append("("); + } + + if (i != result.length - 4) { + bindparam.append("?,"); + } else { + bindparam.append("?)"); + } + } + + // Convert .NET input file format for callable statement to JDBC + SQL = "{ call " + SQL + bindparam + " }"; + + logger.info("Preparing and executing call: " + SQL); + + jdbcCallableStatement.createCallableStatements(con_bbl, SQL, bw, logger); + jdbcCallableStatement.testCallableStatementWithFile(result, bw, strLine, logger); + + } else { + + logger.info("Executing an already prepared call"); + jdbcCallableStatement.testCallableStatementWithFile(result, bw, strLine, logger); + } + + // if line starts with keyword "txn", it means it is a transaction + } else if (strLine.startsWith("txn")) { + String[] result = strLine.split("#!#"); + + bw.write(strLine); + bw.newLine(); + + if (result[1].toLowerCase().startsWith("begin")) { + jdbcTransaction.beginTransaction(con_bbl, bw, logger); + } else if (result[1].toLowerCase().startsWith("commit")) { + jdbcTransaction.transactionCommit(con_bbl, bw, logger); + } else if (result[1].toLowerCase().startsWith("rollback")) { + if (result.length < 3 || result[2].length() == 0 || result[2].matches("[ \\t]+")) { + jdbcTransaction.transactionRollback(con_bbl, bw, logger); + } else { + // rolling back to a named savepoint + jdbcTransaction.transactionRollbackToSavepoint(con_bbl, result, bw, logger); + } + } else if (result[1].toLowerCase().startsWith("savepoint")) { + if (result.length < 3 || result[2].length() == 0 || result[2].matches("[ \\t]+")) { + jdbcTransaction.setTransactionSavepoint(con_bbl, bw, logger); + } else { + jdbcTransaction.setTransactionNamedSavepoint(con_bbl, result, bw, logger); + } + } else if (result[1].toLowerCase().startsWith("isolation")) { + jdbcTransaction.setTransactionIsolationLevel(con_bbl, result, bw, logger); + } else { + logger.error("Unrecognized Transaction! Either statement syntax is " + + "invalid or the test suite does not handle this query at the time"); + } + // assuming transactions don't return a result set + bw.write("~~SUCCESS~~"); + bw.newLine(); + + // if line starts with keyword "cursor", it means it is a cursor operation + } else if (strLine.startsWith("cursor")) { + + // Convert .NET input file format for prepared statement to JDBC + // Used if cursor opened on a result set from a prepared statement + if (strLine.contains("prepst")) { + strLine = strLine.replaceAll("@[a-zA-Z0-9]+", "?"); + } + + String[] result = strLine.split("#!#"); + + bw.write(strLine); + bw.newLine(); + + if (result[1].toLowerCase().startsWith("open")) { + jdbcCursor.openCursor(con_bbl, logger, result, strLine, bw); + + } else if (result[1].toLowerCase().startsWith("fetch")) { + jdbcCursor.cursorFetch(bw, logger, result); + } else if (result[1].toLowerCase().startsWith("close")) { + jdbcCursor.cursorClose(bw, logger); + } else { + logger.error("Unrecognized Cursor action! Either statement syntax is " + + "invalid or the test suite does not handle this action at the time"); + } + + } else if (strLine.startsWith("java_auth")) { + jdbcAuthentication.javaAuthentication(strLine, bw, logger); + + } else if (strLine.startsWith("include") && !isSQLFile) { + String[] result = strLine.split("#!#"); + String filePath = new File(result[1]).getAbsolutePath(); + + // Run the iterative parse and compare loop for test file + batch_run_sql(con_bbl, bw, filePath, logger); + + } else if (strLine.startsWith("insertbulk")) { + bw.write(strLine); + bw.newLine(); + + String[] result = strLine.split("#!#"); + String sourceTable = result[1]; + String destinationTable = result[2]; + jdbcBulkCopy.executeInsertBulk(con_bbl, destinationTable, sourceTable, logger, bw); + + } else if (isCrossDialectFile && ( (tsqlDialect = strLine.toLowerCase().startsWith("-- tsql")) || + (psqlDialect = strLine.toLowerCase().startsWith("-- psql")))) { + // Cross dialect testing + + Connection connection = null; + + bw.write(strLine); + bw.newLine(); + + /* + * If tsql/psql connection with given username exists, reuse it. + * Else, create a new tsql/psql connection with that username and + * assign it to existing connection object. + */ + if (tsqlDialect) { + connection = jdbcCrossDialect.getTsqlConnection(strLine, bw, logger); + } else if (psqlDialect) { + connection = jdbcCrossDialect.getPsqlConnection(strLine, bw, logger); + } + + // Ensure con_bbl is never null + if (connection != null) con_bbl = connection; + + } else { + // execute statement as a normal SQL statement + if (isSQLFile) { + if (!strLine.equalsIgnoreCase("GO")) { + sqlBatch.append(strLine).append(System.lineSeparator()); + continue; + } else { + SQL = sqlBatch.toString(); + sqlBatch = new StringBuilder(); + bw.write(SQL); + } + } else { + SQL = strLine; + } + + logger.info("Executing: " + SQL); + + jdbcStatement.closeStatements(bw, logger); + jdbcStatement.createStatements(con_bbl, bw, logger); + jdbcStatement.testStatementWithFile(SQL, bw, strLine, logger); + } + + long endTime = System.nanoTime(); + long duration = (endTime - startTime); + exec_times.add(duration); + } + } catch (IOException ioe) { + logger.error("IO Exception: " + ioe.getMessage(), ioe); + } + + // close existing statements if any + jdbcStatement.closeStatements(bw, logger); + jdbcPreparedStatement.closePreparedStatements(bw, logger); + jdbcCallableStatement.closeCallableStatements(bw, logger); + + // close connection used for cross dialect queries + if (jdbcCrossDialect != null) + jdbcCrossDialect.closeConnections(bw, logger); + } +} diff --git a/contrib/test/JDBC/src/main/resources/config.txt b/contrib/test/JDBC/src/main/resources/config.txt new file mode 100644 index 00000000000..fcb3a283a6f --- /dev/null +++ b/contrib/test/JDBC/src/main/resources/config.txt @@ -0,0 +1,40 @@ +# SET THIS CONNECTION STRING TO GENERATE THE EXPECTED OUTPUT FILE +URL = localhost +tsql_port = 1433 +psql_port = 5432 +databaseName = master +physicalDatabaseName = jdbc_testdb +user = jdbc_user +password = 12345678 + +# PATH TO INPUT TEST FILES FOLDER +inputFilesPath = input + +# SPECIFY IF YOU WISH TO PRINT ALL THE SUMMARY LOGS/DIFF TO CONSOLE +printLogsToConsole = false + +# SPECIFY WHICH JDBC DRIVER TO USE. CHOOSE FROM "postgresql" OR "sqlserver" +driver = sqlserver + +# SPECIFY IF YOU WANT TO GENERATE A PERFORMANCE REPORT +performanceTest = false + +# TO OVERCOME CERTAIN LIMITATIONS OF BABELFISH, INTRODUCED THE FOLLOWING 2 FLAGS +# SET THESE FLAGS TO "false" WHILE GENERATING OUTPUT FILES YOU WISH TO CHECK INSIDE +# THE "expected" FOLDER. THESE FLAGS ARE ONLY THERE FOR PURPOSE OF DEBUGGING + +# BABEL-415 AND BABEL-681 +# SPECIFY IF COLUMN NAMES SHOULD BE ACCOMPANYING RESULT SETS IN OUTPUT FILE +outputColumnName = false + +# BABEL-780 AND BABEL-1012 +# SPECIFY IF ERROR CODE SHOULD BE DISPLAYED IN OUTPUT FILE +outputErrorCode = true + +############################################ WHICH TEST TO RUN ############################################ + +# PLEASE LOOK AT THE jdbc_schedule FILE +scheduleFile = ./jdbc_schedule + +# Where to find the input, output, expected, etc. +testFileRoot = ./ diff --git a/contrib/test/JDBC/src/main/resources/junit-platform.properties b/contrib/test/JDBC/src/main/resources/junit-platform.properties new file mode 100644 index 00000000000..b776c389728 --- /dev/null +++ b/contrib/test/JDBC/src/main/resources/junit-platform.properties @@ -0,0 +1,2 @@ +junit.jupiter.execution.parallel.enabled = false +junit.jupiter.execution.parallel.mode.default = concurrent diff --git a/contrib/test/JDBC/src/test/java/com/sqlsamples/TestQueryFile.java b/contrib/test/JDBC/src/test/java/com/sqlsamples/TestQueryFile.java new file mode 100644 index 00000000000..8a8dad25044 --- /dev/null +++ b/contrib/test/JDBC/src/test/java/com/sqlsamples/TestQueryFile.java @@ -0,0 +1,356 @@ +package com.sqlsamples; + +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LogManager; +import org.junit.jupiter.api.*; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import java.io.*; +import java.sql.*; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.Date; +import java.util.stream.Stream; + +import static com.sqlsamples.Config.*; + +import static com.sqlsamples.Statistics.exec_times; + +public class TestQueryFile { + + static String timestamp = new SimpleDateFormat("dd-MM-yyyy'T'HH:mm:ss.SSS").format(new Date()); + static String generatedFilesDirectoryPath = testFileRoot + "/expected/"; + static String sqlServerGeneratedFilesDirectoryPath = testFileRoot + "/sql_expected/"; + static String outputFilesDirectoryPath = testFileRoot + "/output/"; + static Logger summaryLogger = LogManager.getLogger("testSummaryLogger"); //logger to write summary of tests executed + static Logger logger = LogManager.getLogger("eventLoggger"); //logger to log any test framework events + static ArrayList> summaryMap = new ArrayList<>(); //map to store test names and status + static ArrayList>> testCountMap = new ArrayList<>(); //map to store test names and number of tests passed + static ArrayList fileList = new ArrayList<>(); + static HashMap filePaths = new HashMap<>(); //map to store fileName and their paths + static ArrayList testsToRun = new ArrayList(); + static HashSet testsToIgnore = new HashSet(); + static File diffFile; + + String inputFileName; + Connection connection_bbl; // connection object for Babel instance + + public static void createTestFilesListUtil(String directory, String testToRun) { + File dir = new File(directory); + + File[] directoryListing = dir.listFiles(); + if (directoryListing != null) { + for (File file : directoryListing) { + + if (file.getName().startsWith(".")) { + continue; + } + + if (file.isDirectory()) { + createTestFilesListUtil(file.getAbsolutePath(), testToRun); + } else { + // append filename to arraylist and omit extension + String fileName = file.getName().replaceFirst("[.][^.]+$", ""); + + if (testToRun.equals("all") || testToRun.equals(fileName)) { + fileList.add(fileName); + filePaths.put(fileName, file.getAbsolutePath()); + } + } + } + } + } + + public static void createTestFilesList(String directory) { + for(String testToRun : testsToRun) { + /* prefix indicates it is a postgres command */ + if (testToRun.startsWith("cmd#!#")) { + fileList.add(testToRun); + } + else if (testToRun.startsWith("ignore#!#")) { + testsToIgnore.add(testToRun.split("#!#", -1)[1]); + } else { + createTestFilesListUtil(directory, testToRun); + } + } + } + + public static void execCommand(String cmd) throws ClassNotFoundException { + String[] command = cmd.split("#!#"); + + String URL = properties.getProperty("URL"); + String tsql_port = properties.getProperty("tsql_port"); + String psql_port = properties.getProperty("psql_port"); + String databaseName = properties.getProperty("databaseName"); + String physicalDatabaseName = properties.getProperty("physicalDatabaseName"); + String user = properties.getProperty("user"); + String password = properties.getProperty("password"); + String connectionString; + + if (command[1].equalsIgnoreCase("sqlserver")) { + /* if are trying to execute a t-sql command but we are using postgres driver */ + if(JDBCDriver.equalsIgnoreCase("postgresql")) { + Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); //use sql server driver + } + connectionString = createSQLServerConnectionString(URL, tsql_port, databaseName, user, password); + summaryLogger.info("Execute T-SQL Command: " + command[2]); + } else if (command[1].equalsIgnoreCase("postgresql")) { + /* if are trying to execute a postgres command but we are using sqlserver driver */ + if(JDBCDriver.equalsIgnoreCase("sqlserver")) { + Class.forName("org.postgresql.Driver"); //use postgres driver + } + connectionString = createPostgreSQLConnectionString(URL, psql_port, physicalDatabaseName, user, password); + summaryLogger.info("Execute Postgres Command: " + command[2]); + } else { + summaryLogger.error("Invalid cmd type. Choose from \"sqlserver\" or \"postgresql\""); + return; + } + + try { + DriverManager.getConnection(connectionString).createStatement().executeQuery(command[2]); + } catch (SQLException e) { + summaryLogger.error(e.getMessage()); + } + + /* use the driver specified in config.txt */ + selectDriver(); + } + + static void selectDriver() throws ClassNotFoundException { + if (JDBCDriver.equalsIgnoreCase("postgresql")) { + Class.forName("org.postgresql.Driver"); + } else if (JDBCDriver.equalsIgnoreCase("sqlserver")) { + Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); + } else throw new ClassNotFoundException("Driver not found for: " + JDBCDriver +". Choose from either 'sqlserver' or 'postgresql'"); + } + + // test data is seeded from here + static Stream inputFileNames() { + File dir = new File(inputFilesDirectoryPath); + File scheduleFile = new File(scheduleFileName); + + try (BufferedReader br = new BufferedReader(new FileReader(scheduleFile))) { + String line; + while ((line = br.readLine()) != null) { + if (!line.startsWith("#") && line.trim().length() > 0) + testsToRun.add(line); + } + } catch (IOException e) { + e.printStackTrace(); + } + + createTestFilesList(dir.getAbsolutePath()); + return fileList.stream(); + } + + // configure logger for summary file and setup initial directory structure + @BeforeAll + public static void setup() throws IOException { + String testRunDir = "Info/" + timestamp + "/"; + new File(testRunDir).mkdirs(); + + new File(outputFilesDirectoryPath).mkdirs(); + diffFile = new File(testRunDir + timestamp + ".diff"); + diffFile.createNewFile(); + + String logSummaryFile = testRunDir + timestamp + "_runSummary"; + configureSummaryLogger(logSummaryFile, summaryLogger); + + String logFile = testRunDir + timestamp; + configureLogger(logFile, logger); + + summaryLogger.info("Started test suite. Now running tests..."); + } + + // close connections that are not null after every test + @AfterEach + public void closeConnections() throws SQLException { + if (connection_bbl != null) connection_bbl.close(); + } + + // write summary log after all tests have been executed + @AfterAll + public static void logSummary() { + int passed = 0; + int failed = 0; + int maxlen = 0; + String testStats = ""; + + summaryLogger.info("All tests executed successfully!"); + + summaryLogger.info("###########################################################################"); + summaryLogger.info("################################ SUMMARY ################################"); + summaryLogger.info("###########################################################################"); + + // get max length of test name (used for pretty print in logs) + for(AbstractMap.SimpleEntry set: summaryMap){ + String testMethodName = set.getKey(); + int len = testMethodName.length(); + if(len > maxlen) maxlen = len; + } + + // for every test in map, log test name and status + int i; + + for (i = 0; i < summaryMap.size(); i++) { + String testMethodName = summaryMap.get(i).getKey(); + + boolean status = summaryMap.get(i).getValue(); + int testsPassed = 0, totalTests = 0; + + if(status){ + //extra spaces for right side padding + summaryLogger.info((testMethodName + ":" + " ").substring(0, maxlen+2) + "Passed!" + testStats); + passed++; + } + else{ + //extra spaces for right side padding + summaryLogger.info((testMethodName + ":" + " ").substring(0, maxlen+2) + "Failed!" + testStats); + failed++; + } + } + + summaryLogger.info("###########################################################################"); + summaryLogger.info("TOTAL TESTS:\t" + (passed + failed)); + summaryLogger.info("TESTS PASSED:\t" + passed); + summaryLogger.info("TESTS FAILED:\t" + failed); + summaryLogger.info("###########################################################################"); + + if (performanceTest) { + performanceSummary(exec_times); + } + + // print absolute path to file containing diff + if(failed > 0) { + summaryLogger.info("Output diff can be found in '" + diffFile.getAbsolutePath() + "'"); + } + + // displays content of file holding diff to console + if(printLogsToConsole) { + System.out.println("############################# DIFF STARTS HERE #############################"); + try (BufferedReader br = new BufferedReader(new FileReader(diffFile))) { + String line; + while ((line = br.readLine()) != null) { + System.out.println(line); + } + } catch (IOException e) { + e.printStackTrace(); + } + System.out.println("############################## DIFF ENDS HERE ##############################"); + } + } + + // generates performance report which has mean, median, mode of query execution times + static void performanceSummary(ArrayList exec_times) { + + com.sqlsamples.Statistics stats = new com.sqlsamples.Statistics(exec_times.stream().filter(Objects::nonNull).mapToDouble(i -> i).toArray()); + + HashMap statisticsHashMap = new HashMap() { + { + put(connectionString, stats); + } + }; + + String testRunDir = "Info/" + timestamp + "/"; + + String CSVFileName = testRunDir + timestamp + "_performanceReport"; + com.sqlsamples.ExportResults.createCSVFile(CSVFileName, statisticsHashMap); + } + + private static boolean compareOutFiles (File outputFile, File expectedFile) { + String outputFilePath = outputFile.getAbsolutePath(); + String expectedFilePath = expectedFile.getAbsolutePath(); + ProcessBuilder diffProcessBuilder; + + // if expected file is generated from SQL Server, do not compare error code and message + if (expectedFilePath.contains("sql_expected")) { + diffProcessBuilder = new ProcessBuilder("diff", "-a", "-u", "-I", "~~ERROR", expectedFilePath, outputFilePath); + } else { + diffProcessBuilder = new ProcessBuilder("diff", "-a", "-u", expectedFilePath, outputFilePath); + } + + try { + diffProcessBuilder.redirectError(ProcessBuilder.Redirect.appendTo(diffFile)); + diffProcessBuilder.redirectOutput(ProcessBuilder.Redirect.appendTo(diffFile)); + int exitCode = diffProcessBuilder.start().waitFor(); + + switch (exitCode) { + case 0: + return true; + + case 1: + return false; + + case 2: + System.out.println("There was some trouble when the diff command was executed!"); + return false; + + default: + System.out.println("Unknown exit code encountered while running diff!"); + return false; + } + } catch (IOException | InterruptedException e) { + e.printStackTrace(); + } + + return false; + } + + // parameterized test + @ParameterizedTest(name="{0}") + @MethodSource("inputFileNames") + public void TestQueryBatch(String inputFileName) throws SQLException, ClassNotFoundException, Throwable { + + // if it is a command and not a fileName + if (inputFileName.startsWith("cmd#!#")) { + execCommand(inputFileName); + return; + } else if (testsToIgnore.contains(inputFileName)) { + // if test is to be ignored, don't run it + return; + } else { + selectDriver(); + connection_bbl = DriverManager.getConnection(connectionString); + } + + summaryLogger.info("RUNNING " + inputFileName); + + logger.info("Running " + inputFileName + "..."); + + String testFilePath = filePaths.get(inputFileName); + + boolean result; // whether test passed or failed + int failed; + + File outputFile = new File(outputFilesDirectoryPath + inputFileName + ".out"); + + // generate buffer reader associated with the file + FileWriter fw = new FileWriter(outputFile); + BufferedWriter bw = new BufferedWriter(fw); + batch_run.batch_run_sql(connection_bbl, bw, testFilePath, logger); + bw.close(); + + File expectedFile = new File(generatedFilesDirectoryPath + inputFileName + ".out"); + File sqlExpectedFile = new File(sqlServerGeneratedFilesDirectoryPath + inputFileName + ".out"); + + if (expectedFile.exists()) { + // get the diff + result = compareOutFiles(outputFile, expectedFile); + } else if (sqlExpectedFile.exists()) { + // get the diff + result = compareOutFiles(outputFile, sqlExpectedFile); + } else { + result = false; + } + + summaryMap.add(new AbstractMap.SimpleEntry<>(inputFileName, result)); //add test name and result to map + + try { + Assertions.assertTrue(result); + } catch (AssertionError e) { + Throwable throwable = new Throwable(inputFileName + " FAILED! Output diff can be found in '" + diffFile.getAbsolutePath() + "'"); + throwable.setStackTrace(new StackTraceElement[0]); + throw throwable; + } + } +} diff --git a/contrib/test/JDBC/utils/Blank.jpeg b/contrib/test/JDBC/utils/Blank.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..1cda9a53dc357ce07d3c67051b7615ebf7dc2f64 GIT binary patch literal 631 zcmex=^(PF6}rMnOeST|r4lSw=>~TvNxu(8R<ECr+Na zbot8FYu9hwy!G(W<0ns_J%91?)yGetzkL1n{m0K=Ab&A3Fhjfr_ZgbM1cClyVqsxs zVF&q(k*OSrnFU!`6%E;h90S=C3x$=88aYIqCNA7~kW<+>=!0ld(M2vX6_bamA3L7B$%azX<@d&d)*s literal 0 HcmV?d00001 diff --git a/contrib/test/JDBC/utils/TxnErrorHandingCases.py b/contrib/test/JDBC/utils/TxnErrorHandingCases.py new file mode 100644 index 00000000000..01d43cb7b1c --- /dev/null +++ b/contrib/test/JDBC/utils/TxnErrorHandingCases.py @@ -0,0 +1,597 @@ +import random +import sys + + +prefix = 'ErrorHandling' +goTerm = 'GO\n' + +blockCount = 0 +tryList = [] +procList = [] +procOpen = [] +txnCnt = 0 +spList = [] + +testNum = 1 +testDict = {} +opNum = 0 +batchDone = False + +class Operation: + def __init__(self): + global opNum + self.inc = 0 + self.active = False; + self.opNum = opNum + self.batch = False + opNum = opNum + 1 + + def getSQL(self): + pass + + def getOpNum(self): + return str(self.opNum) + + def appendTerm(self, sql): + sql += ';\n' + if not self.batch: + sql += goTerm + return sql + + def appendOnlyGo(self, sql): + if not self.batch: + sql += 'GO\n' + return sql + + def include(self): + self.inc = self.inc + 1 + + def exclude(self): + self.inc = self.inc - 1 + + def isInclude(self): + return (self.inc > 0) + + def push(self, stmts): + if stmtDict.get("ERROR_COMMAND").isActive(): + return False + if blockCount > 0: + self.batch = True + self.active = True + return True + + def pop(self): + self.active = False + self.batch = False + + def isActive(self): + return self.active + + def validStmt(self): + global stmtDict, procList + validStmt = stmtDict.get("ERROR_COMMAND").isActive() + if not validStmt: + for proc in procList: + if stmtDict.get("EXEC_PROC" + str(proc)).isActive(): + validStmt = True + break + return validStmt + + +class XactAbort(Operation): + def __init__(self): + super().__init__() + self.params = ['ON', 'OFF'] + self.idx = 0 + + def getSQL(self): + res = [] + sql = 'set xact_abort ' + self.params[self.idx] + self.idx = (self.idx + 1)%2 + res.append(self.appendTerm(sql)) + return res + +class ImplTxns(Operation): + def __init__(self): + super().__init__() + self.params = ['ON', 'OFF'] + + def getSQL(self): + res = [] + sql = 'set implicit_transactions ' + self.params[random.randint(0,1)] + res.append(self.appendTerm(sql)) + return res + +class BeginTxn(Operation): + + def getSQL(self): + res = [self.appendTerm('begin transaction')] + return res + + def push(self, stmts): + global txnCnt + if stmtDict.get("ERROR_COMMAND").isActive(): + return False + txnCnt = txnCnt + 1 + if blockCount > 0: + self.batch = True + return True + + def pop(self): + global txnCnt + txnCnt = txnCnt - 1 + self.batch = False + +class CommitTxn(Operation): + + def getSQL(self): + res = [self.appendTerm('commit transaction')] + return res + + def push(self, stmts): + global txnCnt + if txnCnt == 0: + return False; + if not self.validStmt(): + return False + if blockCount > 0: + self.batch = True + txnCnt = txnCnt - 1 + return True + + def pop(self): + global txnCnt + txnCnt = txnCnt + 1 + self.batch = False + +class RollbackTxn(Operation): + def __init__(self): + super().__init__() + self.oldTxnCnt = 0 + + + def getSQL(self): + res = [self.appendTerm('rollback transaction')] + return res + + def push(self, stmts): + global txnCnt + if txnCnt == 0: + return False; + if not self.validStmt(): + return False + if blockCount > 0: + self.batch = True + self.oldTxnCnt = txnCnt + txnCnt = 0; + return True + + def pop(self): + global txnCnt + txnCnt = self.oldTxnCnt; + self.batch = False + +class SaveTxn(Operation): + def __init__(self): + super().__init__() + self.params = [prefix + 'sp'] + + def getSQL(self): + res = [self.appendTerm('save transaction ' + self.params[0])] + return res + + def push(self, stmts): + global spList + if txnCnt == 0: + return False; + if stmtDict.get("ERROR_COMMAND").isActive(): + return False + spList.append(self.params[0]) + if blockCount > 0: + self.batch = True + return True + + def pop(self): + global spList + spList.pop() + self.batch = False + +class RollbackSave(Operation): + def __init__(self): + super().__init__() + self.params = [prefix + 'sp'] + + def getSQL(self): + res = [self.appendTerm('rollback transaction ' + self.params[0])] + return res + + def push(self, stmts): + global spList + if len(spList) == 0: + return False + if not self.validStmt(): + return False + spList.pop() + if blockCount > 0: + self.batch = True + return True + + def pop(self): + global spList + spList.append(self.params[0]) + self.batch = False + +class Try(Operation): + def __init__(self, num): + super().__init__() + self.num = num; + + def getSQL(self): + res = ['begin try\n'] + return res; + + def push(self, stmts): + global blockCount, tryList + if stmtDict.get("ERROR_COMMAND").isActive(): + return False + if self.num > len(tryList) + 1: + return False + blockCount += 1 + tryList.append(self.num) + self.batch = True + return True + + def pop(self): + global blockCount, tryList + blockCount -= 1 + tryList.remove(self.num) + self.batch = False + +class Catch(Operation): + def __init__(self, num): + super().__init__() + self.num = num; + + def getSQL(self): + sql = 'end try\nbegin catch\n\tselect xact_state();\nend catch\n' + sql = self.appendOnlyGo(sql) + res = [sql] + return res; + + def push(self, stmts): + global blockCount, tryList + if len(tryList) == 0 or self.num != tryList[-1]: + return False + if not self.validStmt(): + return False + + blockCount -= 1 + tryList.remove(self.num) + if blockCount > 0: + self.batch = True + return True + + def pop(self): + global blockCount, tryList + blockCount += 1 + tryList.append(self.num) + self.batch = False + + +class BeginProc(Operation): + def __init__(self, num): + super().__init__() + self.num = num; + + def getSQL(self): + res = ['create procedure ' + prefix + str(self.num) + ' as\nbegin\n'] + return res + + def push(self, stmts): + global blockCount, procOpen + if blockCount > 0 or len(procOpen) > 0: + return False + if self.num > len(procList) + 1: + return False + + if len(procList) == 0 and stmtDict.get("ERROR_COMMAND").isActive(): + return False + + validStmt = not stmtDict.get("ERROR_COMMAND").isActive() + for proc in procList: + if not stmtDict.get("EXEC_PROC" + str(proc)).isActive(): + validStmt = True + break + if not validStmt: + return False + + blockCount += 1 + procOpen.append(self.num) + self.batch = True + return True + + def pop(self): + global blockCount, procOpen + blockCount -= 1 + procOpen.pop() + self.batch = False + + +class EndProc(Operation): + def __init__(self, num): + super().__init__() + self.num = num; + + def getSQL(self): + res = [self.appendOnlyGo('end\n')] + return res + + def push(self, stmts): + global blockCount, procOpen + if self.num not in procOpen or len(tryList) > 0: + return False + + stmtValid = False + for stmt in reversed(stmts): + if stmt == stmtDict.get("BEGIN_PROC" + str(self.num)): + break; + if stmt == stmtDict.get("ERROR_COMMAND"): + stmtValid = True + break + for proc in procList: + if stmt == stmtDict.get("EXEC_PROC" + str(proc)): + stmtValid = True + break + if stmtValid: + break + + if not stmtValid: + return False + + procList.append(self.num) + blockCount -= 1 + procOpen.pop() + self.batch = False + return True + + def pop(self): + global blockCount, procOpen + blockCount += 1 + procOpen.append(self.num) + procList.pop() + self.batch = False + + +class ExecProc(Operation): + def __init__(self, num): + super().__init__() + self.num = num; + + def getSQL(self): + sql = self.appendTerm('exec ' + prefix + str(self.num)); + res = [sql] + return res + + def push(self, stmts): + if self.num not in procList: + return False + if blockCount > 0: + self.batch = True + self.active = True + return True + +class AtAtTranCount(Operation): + def getSQL(self): + res = [self.appendTerm('select @@trancount')] + return res + +class PrintError(Operation): + def __init__(self, comment): + super().__init__() + self.done = False + self.comment = comment + + def getSQL(self): + self.done = True + msg = '' + if self.comment: + msg += "if @@error > 0 print '" + self.comment + "'" + elif batchDone: + msg += "declare @err int = @@error; if (@err > 0 and @@trancount > 0) print 'BATCH ONLY TERMINATING' else if @err > 0 print 'BATCH TERMINATING'" + else: + msg += "if @@error > 0 print 'STATEMENT TERMINATING ERROR'" + res = [msg + ";\n"] + return res + +class BatchStart(Operation): + def getSQL(self): + global batchDone + batchDone = False + return [''] + +class BatchEnd(Operation): + def getSQL(self): + global batchDone + batchDone = True + return [''] + +class ErrorCommand(Operation): + def __init__(self): + super().__init__() + + def getSQL(self): + res = [self.appendOnlyGo(commandQuery)] + return res + + +stmtDict = { + "XACT_ABORT": XactAbort(), + "BEGIN_TXN": BeginTxn(), + "COMMIT_TXN": CommitTxn(), + "ROLLBACK_TXN": RollbackTxn(), + "SAVE_TXN": SaveTxn(), + "ROLLBACK_SAVE": RollbackSave(), + "IMPL_TXNS": ImplTxns(), + "TRY1": Try(1), + "TRY2": Try(2), + "CATCH2": Catch(2), + "CATCH1": Catch(1), + "BEGIN_PROC1": BeginProc(1), + "EXEC_PROC2": ExecProc(2), + "END_PROC1": EndProc(1), + "BEGIN_PROC2": BeginProc(2), + "END_PROC2": EndProc(2), + "EXEC_PROC1": ExecProc(1), + "ERROR_COMMAND": ErrorCommand() + } + +def writeStmts(testFile, stmt): + sqls = stmt.getSQL() + for sql in sqls: + testFile.write(sql+"\n") + +def genBatch(testFile, stmtList, errCmd): + global testNum + for i in range(0, len(stmtList) + 1): + testFile.write('# Executing test ' + prefix + str(testNum) + '\n') + testFile.write(setupQuery+"\n") + j = 0 + for stmt in stmtList: + if (i == j): + writeStmts(testFile, errCmd) + writeStmts(testFile, stmt) + j += 1 + + if (i == j): + writeStmts(testFile, errCmd) + + testFile.write('if @@trancount > 0 rollback transaction\n') + testFile.write('set xact_abort OFF\n') + testFile.write('set implicit_transactions OFF\n') + testFile.write(celanupQuery) + testFile.write('\n\n\n') + testNum += 1 + +def genBatch(testFile, stmtList): + testFile.write('# Executing test ' + prefix + str(testNum) + '\n') + testFile.write(setupQuery+"\n") + for stmt in stmtList: + writeStmts(testFile, stmt) + + testFile.write('if @@trancount > 0 rollback transaction;\n') + for proc in procList: + testFile.write('drop procedure ' + prefix + str(proc) + ';\n') + testFile.write('set xact_abort OFF;\n') + testFile.write('set implicit_transactions OFF;\n') + testFile.write(celanupQuery) + testFile.write('\n\n\n') + +def genBasicCases(testFile): + global testNum, procList + atAtTranCount = AtAtTranCount(); + errorCommand = ErrorCommand(); + try1 = Try(1); + try2 = Try(2); + catch1 = Catch(1); + catch2 = Catch(2); + beginProc1 = BeginProc(1); + beginProc2 = BeginProc(2); + endProc1 = EndProc(1); + endProc2 = EndProc(2); + execProc1 = ExecProc(1); + execProc2 = ExecProc(2); + xactAbort = XactAbort(); + beginTxn = BeginTxn(); + commitTxn = CommitTxn(); + printError = PrintError(None); + printComplError = PrintError("CURRENT BATCH TERMINATING ERROR"); + + errorCommand.batch = True + atAtTranCount.batch = True + beginTxn.batch = True + commitTxn.batch = True + execProc1.batch = True + catch1.batch = True + """ + testNum = 10000000 + genBatch(testFile, [BatchStart(), beginTxn, errorCommand, + printError, atAtTranCount, + commitTxn, BatchEnd(), printError]) + testNum = 20000000 + genBatch(testFile, [try1, beginTxn, try2, errorCommand, atAtTranCount, catch1, catch2]) + """ + testNum = 10000000 + procList = [1, 2] + genBatch(testFile, [BatchStart(), beginProc1, errorCommand, + printError, atAtTranCount, + endProc1, beginProc2, execProc1, printComplError, endProc2, + beginTxn, execProc2, BatchEnd(), printError]) + """ + testNum = 40000000 + procList = [1, 2] + genBatch(testFile, [xactAbort, beginProc1, try1, errorCommand, + atAtTranCount, catch1, endProc1, beginProc2, execProc1, + endProc2, beginTxn, execProc2]) + procList.clear() + testNum = 1 + """ + +def swap(stmtList, i, j): + val = stmtList[i] + stmtList[i] = stmtList[j] + stmtList[j] = val + +def genValidCases(testFile, stmtDict, stmtList, curStmtList, idx): + global blockCount, testDict, procList, testNum + if testNum > testEnd: + return + procDone = True + for proc in procList: + if not stmtDict.get("EXEC_PROC" + str(proc)).isActive(): + procDone = False + break + + if procDone and stmtDict.get("ERROR_COMMAND").isActive() and blockCount == 0: + seq = '' + for stmt in curStmtList: + seq = seq + stmt.getOpNum() + if not testDict.get(seq, False): + if testNum < testStart: + testNum += 1 + return + testDict[seq] = True + genBatch(testFile, curStmtList) + testNum += 1 + return + + if (len(stmtList) == idx): + return + + if not stmtList[idx].isInclude(): + genValidCases(testFile, stmtDict, stmtList, curStmtList, idx + 1) + + stmtList[idx].include() + N = len(stmtList) + for i in range(idx, N): + if not stmtList[i].push(curStmtList): + continue + curStmtList.append(stmtList[i]) + swap(stmtList, idx, i) + genValidCases(testFile, stmtDict, stmtList, curStmtList, idx + 1) + swap(stmtList, idx, i) + curStmtList.pop() + stmtList[i].pop() + stmtList[idx].exclude() + +assert len(sys.argv) == 7, "Please provide setup, command and cleanup files together with test range as well as output file" + +setupQuery = open(sys.argv[1], "r").read() +commandQuery = open(sys.argv[2], "r").read() +celanupQuery = open(sys.argv[3], "r").read() +testStart = int(sys.argv[4]) +testEnd = int(sys.argv[5]) + +testFile = open(sys.argv[6], "w", buffering=1) +genBasicCases(testFile) +genValidCases(testFile, stmtDict, list(stmtDict.values()), [], 0) +testFile.close() diff --git a/contrib/test/JDBC/utils/blank.txt b/contrib/test/JDBC/utils/blank.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/contrib/test/JDBC/utils/devanagari.txt b/contrib/test/JDBC/utils/devanagari.txt new file mode 100644 index 00000000000..45f37b695da --- /dev/null +++ b/contrib/test/JDBC/utils/devanagari.txt @@ -0,0 +1 @@ +ऀँंःऄअआइईउऊऋऌऍऎएऐऑऒओऔकखगघङचछजझञटठडढणतथदधनऩपफबभमयरऱलळऴवशषसहऺऻ़ऽािीुूृॄॅॆेैॉॊोौ्ॎॏॐ॒॑॓॔ॕॖॗक़ख़ग़ज़ड़ढ़फ़य़ॠॡॢॣ।॥०१२३४५६७८९॰ॱॲॳॴॵॶॷॹॺॻॼॽॾॿ \ No newline at end of file diff --git a/contrib/test/JDBC/utils/emojisText.txt b/contrib/test/JDBC/utils/emojisText.txt new file mode 100644 index 00000000000..117dfc03289 --- /dev/null +++ b/contrib/test/JDBC/utils/emojisText.txt @@ -0,0 +1 @@ +😀😃😁😎😒😞😍🙂😆😊😉 \ No newline at end of file diff --git a/contrib/test/JDBC/utils/flower.jpg b/contrib/test/JDBC/utils/flower.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3e41ba4e61e597534fed792d96ef49673cedb91a GIT binary patch literal 3572 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 H$<+S=_7-46 literal 0 HcmV?d00001 diff --git a/contrib/test/JDBC/utils/sample.txt b/contrib/test/JDBC/utils/sample.txt new file mode 100644 index 00000000000..352a3fb9297 --- /dev/null +++ b/contrib/test/JDBC/utils/sample.txt @@ -0,0 +1,6 @@ +AAAAAAAAAAAAAAAAAAAA +BBBBBBBBBB +CCCCC +badksjvbajsdcbvjads +sejvhsdbfjhcgvasdhgcvsj +21639812365091264 \ No newline at end of file diff --git a/contrib/test/JDBC/utils/utf16.txt b/contrib/test/JDBC/utils/utf16.txt new file mode 100644 index 00000000000..ee839d6a00c --- /dev/null +++ b/contrib/test/JDBC/utils/utf16.txt @@ -0,0 +1 @@ + !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƻƼƽƾƿǀǁǂǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴǵǶǷǸǹǺǻǼǽǾǿȀȁȂȃȄȅȆȇȈȉȊȋȌȍȎȏȐȑȒȓȔȕȖȗȘșȚțȜȝȞȟȠȡȢȣȤȥȦȧȨȩȪȫȬȭȮȯȰȱȲȳȴȵȶȷȸȹȺȻȼȽȾȿɀɁɂɃɄɅɆɇɈɉɊɋɌɍɎɏɐɑɒɓɔɕɖɗɘəɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯʰʱʲʳʴʵʶʷʸʹʺʻʼʽʾʿˀˁ˂˃˄˅ˆˇˈˉˊˋˌˍˎˏːˑ˒˓˔˕˖˗˘˙˚˛˜˝˞˟ˠˡˢˣˤ˥˦˧˨˩˪˫ˬ˭ˮ˯˰˱˲˳˴˵˶˷˸˹˺˻˼˽˾˿̴̵̶̷̸̡̢̧̨̛̖̗̘̙̜̝̞̟̠̣̤̥̦̩̪̫̬̭̮̯̰̱̲̳̹̺̻̼͇͈͉͍͎̀́̂̃̄̅̆̇̈̉̊̋̌̍̎̏̐̑̒̓̔̽̾̿̀́͂̓̈́͆͊͋͌̕̚ͅ͏͓͔͕͖͙͚͐͑͒͗͛ͣͤͥͦͧͨͩͪͫͬͭͮͯ͘͜͟͢͝͞͠͡ͰͱͲͳʹ͵Ͷͷͺͻͼͽ;΄΅Ά·ΈΉΊΌΎΏΐΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩΪΫάέήίΰαβγδεζηθικλμνξοπρςστυφχψωϊϋόύώϏϐϑϒϓϔϕϖϗϘϙϚϛϜϝϞϟϠϡϢϣϤϥϦϧϨϩϪϫϬϭϮϯϰϱϲϳϴϵ϶ϷϸϹϺϻϼϽϾϿЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяѐёђѓєѕіїјљњћќѝўџѠѡѢѣѤѥѦѧѨѩѪѫѬѭѮѯѰѱѲѳѴѵѶѷѸѹѺѻѼѽѾѿҀҁ҂҃҄҅҆҇҈҉ҊҋҌҍҎҏҐґҒғҔҕҖҗҘҙҚқҜҝҞҟҠҡҢңҤҥҦҧҨҩҪҫҬҭҮүҰұҲҳҴҵҶҷҸҹҺһҼҽҾҿӀӁӂӃӄӅӆӇӈӉӊӋӌӍӎӏӐӑӒӓӔӕӖӗӘәӚӛӜӝӞӟӠӡӢӣӤӥӦӧӨөӪӫӬӭӮӯӰӱӲӳӴӵӶӷӸӹӺӻӼӽӾӿԀԁԂԃԄԅԆԇԈԉԊԋԌԍԎԏԐԑԒԓԔԕԖԗԘԙԚԛԜԝԞԟԠԡԢԣԤԥԦԧԱԲԳԴԵԶԷԸԹԺԻԼԽԾԿՀՁՂՃՄՅՆՇՈՉՊՋՌՍՎՏՐՑՒՓՔՕՖՙ՚՛՜՝՞՟աբգդեզէըթժիլխծկհձղճմյնշոչպջռսվտրցւփքօֆև։֊֏ְֱֲֳִֵֶַָֹֺֻּֽ֑֖֛֢֣֤֥֦֧֪֚֭֮֒֓֔֕֗֘֙֜֝֞֟֠֡֨֩֫֬֯־ֿ׀ׁׂ׃ׅׄ׆ׇאבגדהוזחטיךכלםמןנסעףפץצקרשתװױײ׳״؀؁؂؃؄؆؇؈؉؊؋،؍؎؏ؘؙؚؐؑؒؓؔؕؖؗ؛؞؟ؠءآأؤإئابةتثجحخدذرزسشصضطظعغػؼؽؾؿـفقكلمنهوىيًٌٍَُِّْٕٖٜٟٓٔٗ٘ٙٚٛٝٞ٠١٢٣٤٥٦٧٨٩٪٫٬٭ٮٯٰٱٲٳٴٵٶٷٸٹٺٻټٽپٿڀځڂڃڄڅچڇڈډڊڋڌڍڎڏڐڑڒړڔڕږڗژڙښڛڜڝڞڟڠڡڢڣڤڥڦڧڨکڪګڬڭڮگڰڱڲڳڴڵڶڷڸڹںڻڼڽھڿۀہۂۃۄۅۆۇۈۉۊۋیۍێۏېۑےۓ۔ەۖۗۘۙۚۛۜ۝۞ۣ۟۠ۡۢۤۥۦۧۨ۩۪ۭ۫۬ۮۯ۰۱۲۳۴۵۶۷۸۹ۺۻۼ۽۾ۿ܀܁܂܃܄܅܆܇܈܉܊܋܌܍܏ܐܑܒܓܔܕܖܗܘܙܚܛܜܝܞܟܠܡܢܣܤܥܦܧܨܩܪܫܬܭܮܯܱܴܷܸܹܻܼܾ݂݄݆݈ܰܲܳܵܶܺܽܿ݀݁݃݅݇݉݊ݍݎݏݐݑݒݓݔݕݖݗݘݙݚݛݜݝݞݟݠݡݢݣݤݥݦݧݨݩݪݫݬݭݮݯݰݱݲݳݴݵݶݷݸݹݺݻݼݽݾݿހށނރބޅކއވމފދތލގޏސޑޒޓޔޕޖޗޘޙޚޛޜޝޞޟޠޡޢޣޤޥަާިީުޫެޭޮޯްޱ߀߁߂߃߄߅߆߇߈߉ߊߋߌߍߎߏߐߑߒߓߔߕߖߗߘߙߚߛߜߝߞߟߠߡߢߣߤߥߦߧߨߩߪ߲߫߬߭߮߯߰߱߳ߴߵ߶߷߸߹ߺࠀࠁࠂࠃࠄࠅࠆࠇࠈࠉࠊࠋࠌࠍࠎࠏࠐࠑࠒࠓࠔࠕࠖࠗ࠘࠙ࠚࠛࠜࠝࠞࠟࠠࠡࠢࠣࠤࠥࠦࠧࠨࠩࠪࠫࠬ࠭࠰࠱࠲࠳࠴࠵࠶࠷࠸࠹࠺࠻࠼࠽࠾ࡀࡁࡂࡃࡄࡅࡆࡇࡈࡉࡊࡋࡌࡍࡎࡏࡐࡑࡒࡓࡔࡕࡖࡗࡘ࡙࡚࡛࡞ࢠࢢࢣࢤࢥࢦࢧࢨࢩࢪࢫࢬࣰࣱࣲࣦࣩ࣭࣮࣯ࣶࣹࣺࣤࣥࣧࣨ࣪࣫࣬ࣳࣴࣵࣷࣸࣻࣼࣽࣾऀँंःऄअआइईउऊऋऌऍऎएऐऑऒओऔकखगघङचछजझञटठडढणतथदधनऩपफबभमयरऱलळऴवशषसहऺऻ़ऽािीुूृॄॅॆेैॉॊोौ्ॎॏॐ॒॑॓॔ॕॖॗक़ख़ग़ज़ड़ढ़फ़य़ॠॡॢॣ।॥०१२३४५६७८९॰ॱॲॳॴॵॶॷॹॺॻॼॽॾॿঁংঃঅআইঈউঊঋঌএঐওঔকখগঘঙচছজঝঞটঠডঢণতথদধনপফবভমযরলশষসহ়ঽািীুূৃৄেৈোৌ্ৎৗড়ঢ়য়ৠৡৢৣ০১২৩৪৫৬৭৮৯ৰৱ৲৳৴৵৶৷৸৹৺৻ਁਂਃਅਆਇਈਉਊਏਐਓਔਕਖਗਘਙਚਛਜਝਞਟਠਡਢਣਤਥਦਧਨਪਫਬਭਮਯਰਲਲ਼ਵਸ਼ਸਹ਼ਾਿੀੁੂੇੈੋੌ੍ੑਖ਼ਗ਼ਜ਼ੜਫ਼੦੧੨੩੪੫੬੭੮੯ੰੱੲੳੴੵઁંઃઅઆઇઈઉઊઋઌઍએઐઑઓઔકખગઘઙચછજઝઞટઠડઢણતથદધનપફબભમયરલળવશષસહ઼ઽાિીુૂૃૄૅેૈૉોૌ્ૐૠૡૢૣ૦૧૨૩૪૫૬૭૮૯૰૱ଁଂଃଅଆଇଈଉଊଋଌଏଐଓଔକଖଗଘଙଚଛଜଝଞଟଠଡଢଣତଥଦଧନପଫବଭମଯରଲଳଵଶଷସହ଼ଽାିୀୁୂୃୄେୈୋୌ୍ୖୗଡ଼ଢ଼ୟୠୡୢୣ୦୧୨୩୪୫୬୭୮୯୰ୱ୲୳୴୵୶୷ஂஃஅஆஇஈஉஊஎஏஐஒஓஔகஙசஜஞடணதநனபமயரறலளழவஶஷஸஹாிீுூெேைொோௌ்ௐௗ௦௧௨௩௪௫௬௭௮௯௰௱௲௳௴௵௶௷௸௹௺ఁంఃఅఆఇఈఉఊఋఌఎఏఐఒఓఔకఖగఘఙచఛజఝఞటఠడఢణతథదధనపఫబభమయరఱలళవశషసహఽాిీుూృౄెేైొోౌ్ౕౖౘౙౠౡౢౣ౦౧౨౩౪౫౬౭౮౯౸౹౺౻౼౽౾౿ಂಃಅಆಇಈಉಊಋಌಎಏಐಒಓಔಕಖಗಘಙಚಛಜಝಞಟಠಡಢಣತಥದಧನಪಫಬಭಮಯರಱಲಳವಶಷಸಹ಼ಽಾಿೀುೂೃೄೆೇೈೊೋೌ್ೕೖೞೠೡೢೣ೦೧೨೩೪೫೬೭೮೯ೱೲംഃഅആഇഈഉഊഋഌഎഏഐഒഓഔകഖഗഘങചഛജഝഞടഠഡഢണതഥദധനഩപഫബഭമയരറലളഴവശഷസഹഺഽാിീുൂൃൄെേൈൊോൌ്ൎൗൠൡൢൣ൦൧൨൩൪൫൬൭൮൯൰൱൲൳൴൵൹ൺൻർൽൾൿංඃඅආඇඈඉඊඋඌඍඎඏඐඑඒඓඔඕඖකඛගඝඞඟචඡජඣඤඥඦටඨඩඪණඬතථදධනඳපඵබභමඹයරලවශෂසහළෆ්ාැෑිීුූෘෙේෛොෝෞෟෲෳ෴กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำิีึืฺุู฿เแโใไๅๆ็่้๊๋์ํ๎๏๐๑๒๓๔๕๖๗๘๙๚๛ກຂຄງຈຊຍດຕຖທນບປຜຝພຟມຢຣລວສຫອຮຯະັາຳິີຶືຸູົຼຽເແໂໃໄໆ່້໊໋໌ໍ໐໑໒໓໔໕໖໗໘໙ໜໝໞໟༀ༁༂༃༄༅༆༇༈༉༊་༌།༎༏༐༑༒༓༔༕༖༗༘༙༚༛༜༝༞༟༠༡༢༣༤༥༦༧༨༩༪༫༬༭༮༯༰༱༲༳༴༵༶༷༸༹༺༻༼༽༾༿ཀཁགགྷངཅཆཇཉཊཋཌཌྷཎཏཐདདྷནཔཕབབྷམཙཚཛཛྷཝཞཟའཡརལཤཥསཧཨཀྵཪཫཬཱཱཱིིུུྲྀཷླྀཹེཻོཽཾཿ྄ཱྀྀྂྃ྅྆྇ྈྉྊྋྌྍྎྏྐྑྒྒྷྔྕྖྗྙྚྛྜྜྷྞྟྠྡྡྷྣྤྥྦྦྷྨྩྪྫྫྷྭྮྯྰྱྲླྴྵྶྷྸྐྵྺྻྼ྾྿࿀࿁࿂࿃࿄࿅࿆࿇࿈࿉࿊࿋࿌࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚ကခဂဃငစဆဇဈဉညဋဌဍဎဏတထဒဓနပဖဗဘမယရလဝသဟဠအဢဣဤဥဦဧဨဩဪါာိီုူေဲဳဴဵံ့း္်ျြွှဿ၀၁၂၃၄၅၆၇၈၉၊။၌၍၎၏ၐၑၒၓၔၕၖၗၘၙၚၛၜၝၞၟၠၡၢၣၤၥၦၧၨၩၪၫၬၭၮၯၰၱၲၳၴၵၶၷၸၹၺၻၼၽၾၿႀႁႂႃႄႅႆႇႈႉႊႋႌႍႎႏ႐႑႒႓႔႕႖႗႘႙ႚႛႜႝ႞႟ႠႡႢႣႤႥႦႧႨႩႪႫႬႭႮႯႰႱႲႳႴႵႶႷႸႹႺႻႼႽႾႿჀჁჂჃჄჅჇჍაბგდევზთიკლმნოპჟრსტუფქღყშჩცძწჭხჯჰჱჲჳჴჵჶჷჸჹჺ჻ჼჽჾჿᄀᄁᄂᄃᄄᄅᄆᄇᄈᄉᄊᄋᄌᄍᄎᄏᄐᄑᄒᄓᄔᄕᄖᄗᄘᄙᄚᄛᄜᄝᄞᄟᄠᄡᄢᄣᄤᄥᄦᄧᄨᄩᄪᄫᄬᄭᄮᄯᄰᄱᄲᄳᄴᄵᄶᄷᄸᄹᄺᄻᄼᄽᄾᄿᅀᅁᅂᅃᅄᅅᅆᅇᅈᅉᅊᅋᅌᅍᅎᅏᅐᅑᅒᅓᅔᅕᅖᅗᅘᅙᅚᅛᅜᅝᅞᅟᅠᅡᅢᅣᅤᅥᅦᅧᅨᅩᅪᅫᅬᅭᅮᅯᅰᅱᅲᅳᅴᅵᅶᅷᅸᅹᅺᅻᅼᅽᅾᅿᆀᆁᆂᆃᆄᆅᆆᆇᆈᆉᆊᆋᆌᆍᆎᆏᆐᆑᆒᆓᆔᆕᆖᆗᆘᆙᆚᆛᆜᆝᆞᆟᆠᆡᆢᆣᆤᆥᆦᆧᆨᆩᆪᆫᆬᆭᆮᆯᆰᆱᆲᆳᆴᆵᆶᆷᆸᆹᆺᆻᆼᆽᆾᆿᇀᇁᇂᇃᇄᇅᇆᇇᇈᇉᇊᇋᇌᇍᇎᇏᇐᇑᇒᇓᇔᇕᇖᇗᇘᇙᇚᇛᇜᇝᇞᇟᇠᇡᇢᇣᇤᇥᇦᇧᇨᇩᇪᇫᇬᇭᇮᇯᇰᇱᇲᇳᇴᇵᇶᇷᇸᇹᇺᇻᇼᇽᇾᇿሀሁሂሃሄህሆሇለሉሊላሌልሎሏሐሑሒሓሔሕሖሗመሙሚማሜምሞሟሠሡሢሣሤሥሦሧረሩሪራሬርሮሯሰሱሲሳሴስሶሷሸሹሺሻሼሽሾሿቀቁቂቃቄቅቆቇቈቊቋቌቍቐቑቒቓቔቕቖቘቚቛቜቝበቡቢባቤብቦቧቨቩቪቫቬቭቮቯተቱቲታቴትቶቷቸቹቺቻቼችቾቿኀኁኂኃኄኅኆኇኈኊኋኌኍነኑኒናኔንኖኗኘኙኚኛኜኝኞኟአኡኢኣኤእኦኧከኩኪካኬክኮኯኰኲኳኴኵኸኹኺኻኼኽኾዀዂዃዄዅወዉዊዋዌውዎዏዐዑዒዓዔዕዖዘዙዚዛዜዝዞዟዠዡዢዣዤዥዦዧየዩዪያዬይዮዯደዱዲዳዴድዶዷዸዹዺዻዼዽዾዿጀጁጂጃጄጅጆጇገጉጊጋጌግጎጏጐጒጓጔጕጘጙጚጛጜጝጞጟጠጡጢጣጤጥጦጧጨጩጪጫጬጭጮጯጰጱጲጳጴጵጶጷጸጹጺጻጼጽጾጿፀፁፂፃፄፅፆፇፈፉፊፋፌፍፎፏፐፑፒፓፔፕፖፗፘፙፚ፝፞፟፠፡።፣፤፥፦፧፨፩፪፫፬፭፮፯፰፱፲፳፴፵፶፷፸፹፺፻፼ᎀᎁᎂᎃᎄᎅᎆᎇᎈᎉᎊᎋᎌᎍᎎᎏ᎐᎑᎒᎓᎔᎕᎖᎗᎘᎙ᎠᎡᎢᎣᎤᎥᎦᎧᎨᎩᎪᎫᎬᎭᎮᎯᎰᎱᎲᎳᎴᎵᎶᎷᎸᎹᎺᎻᎼᎽᎾᎿᏀᏁᏂᏃᏄᏅᏆᏇᏈᏉᏊᏋᏌᏍᏎᏏᏐᏑᏒᏓᏔᏕᏖᏗᏘᏙᏚᏛᏜᏝᏞᏟᏠᏡᏢᏣᏤᏥᏦᏧᏨᏩᏪᏫᏬᏭᏮᏯᏰᏱᏲᏳᏴ᐀ᐁᐂᐃᐄᐅᐆᐇᐈᐉᐊᐋᐌᐍᐎᐏᐐᐑᐒᐓᐔᐕᐖᐗᐘᐙᐚᐛᐜᐝᐞᐟᐠᐡᐢᐣᐤᐥᐦᐧᐨᐩᐪᐫᐬᐭᐮᐯᐰᐱᐲᐳᐴᐵᐶᐷᐸᐹᐺᐻᐼᐽᐾᐿᑀᑁᑂᑃᑄᑅᑆᑇᑈᑉᑊᑋᑌᑍᑎᑏᑐᑑᑒᑓᑔᑕᑖᑗᑘᑙᑚᑛᑜᑝᑞᑟᑠᑡᑢᑣᑤᑥᑦᑧᑨᑩᑪᑫᑬᑭᑮᑯᑰᑱᑲᑳᑴᑵᑶᑷᑸᑹᑺᑻᑼᑽᑾᑿᒀᒁᒂᒃᒄᒅᒆᒇᒈᒉᒊᒋᒌᒍᒎᒏᒐᒑᒒᒓᒔᒕᒖᒗᒘᒙᒚᒛᒜᒝᒞᒟᒠᒡᒢᒣᒤᒥᒦᒧᒨᒩᒪᒫᒬᒭᒮᒯᒰᒱᒲᒳᒴᒵᒶᒷᒸᒹᒺᒻᒼᒽᒾᒿᓀᓁᓂᓃᓄᓅᓆᓇᓈᓉᓊᓋᓌᓍᓎᓏᓐᓑᓒᓓᓔᓕᓖᓗᓘᓙᓚᓛᓜᓝᓞᓟᓠᓡᓢᓣᓤᓥᓦᓧᓨᓩᓪᓫᓬᓭᓮᓯᓰᓱᓲᓳᓴᓵᓶᓷᓸᓹᓺᓻᓼᓽᓾᓿᔀᔁᔂᔃᔄᔅᔆᔇᔈᔉᔊᔋᔌᔍᔎᔏᔐᔑᔒᔓᔔᔕᔖᔗᔘᔙᔚᔛᔜᔝᔞᔟᔠᔡᔢᔣᔤᔥᔦᔧᔨᔩᔪᔫᔬᔭᔮᔯᔰᔱᔲᔳᔴᔵᔶᔷᔸᔹᔺᔻᔼᔽᔾᔿᕀᕁᕂᕃᕄᕅᕆᕇᕈᕉᕊᕋᕌᕍᕎᕏᕐᕑᕒᕓᕔᕕᕖᕗᕘᕙᕚᕛᕜᕝᕞᕟᕠᕡᕢᕣᕤᕥᕦᕧᕨᕩᕪᕫᕬᕭᕮᕯᕰᕱᕲᕳᕴᕵᕶᕷᕸᕹᕺᕻᕼᕽᕾᕿᖀᖁᖂᖃᖄᖅᖆᖇᖈᖉᖊᖋᖌᖍᖎᖏᖐᖑᖒᖓᖔᖕᖖᖗᖘᖙᖚᖛᖜᖝᖞᖟᖠᖡᖢᖣᖤᖥᖦᖧᖨᖩᖪᖫᖬᖭᖮᖯᖰᖱᖲᖳᖴᖵᖶᖷᖸᖹᖺᖻᖼᖽᖾᖿᗀᗁᗂᗃᗄᗅᗆᗇᗈᗉᗊᗋᗌᗍᗎᗏᗐᗑᗒᗓᗔᗕᗖᗗᗘᗙᗚᗛᗜᗝᗞᗟᗠᗡᗢᗣᗤᗥᗦᗧᗨᗩᗪᗫᗬᗭᗮᗯᗰᗱᗲᗳᗴᗵᗶᗷᗸᗹᗺᗻᗼᗽᗾᗿᘀᘁᘂᘃᘄᘅᘆᘇᘈᘉᘊᘋᘌᘍᘎᘏᘐᘑᘒᘓᘔᘕᘖᘗᘘᘙᘚᘛᘜᘝᘞᘟᘠᘡᘢᘣᘤᘥᘦᘧᘨᘩᘪᘫᘬᘭᘮᘯᘰᘱᘲᘳᘴᘵᘶᘷᘸᘹᘺᘻᘼᘽᘾᘿᙀᙁᙂᙃᙄᙅᙆᙇᙈᙉᙊᙋᙌᙍᙎᙏᙐᙑᙒᙓᙔᙕᙖᙗᙘᙙᙚᙛᙜᙝᙞᙟᙠᙡᙢᙣᙤᙥᙦᙧᙨᙩᙪᙫᙬ᙭᙮ᙯᙰᙱᙲᙳᙴᙵᙶᙷᙸᙹᙺᙻᙼᙽᙾᙿ ᚁᚂᚃᚄᚅᚆᚇᚈᚉᚊᚋᚌᚍᚎᚏᚐᚑᚒᚓᚔᚕᚖᚗᚘᚙᚚ᚛᚜ᚠᚡᚢᚣᚤᚥᚦᚧᚨᚩᚪᚫᚬᚭᚮᚯᚰᚱᚲᚳᚴᚵᚶᚷᚸᚹᚺᚻᚼᚽᚾᚿᛀᛁᛂᛃᛄᛅᛆᛇᛈᛉᛊᛋᛌᛍᛎᛏᛐᛑᛒᛓᛔᛕᛖᛗᛘᛙᛚᛛᛜᛝᛞᛟᛠᛡᛢᛣᛤᛥᛦᛧᛨᛩᛪ᛫᛬᛭ᛮᛯᛰᜀᜁᜂᜃᜄᜅᜆᜇᜈᜉᜊᜋᜌᜎᜏᜐᜑᜒᜓ᜔ᜠᜡᜢᜣᜤᜥᜦᜧᜨᜩᜪᜫᜬᜭᜮᜯᜰᜱᜲᜳ᜴᜵᜶ᝀᝁᝂᝃᝄᝅᝆᝇᝈᝉᝊᝋᝌᝍᝎᝏᝐᝑᝒᝓᝠᝡᝢᝣᝤᝥᝦᝧᝨᝩᝪᝫᝬᝮᝯᝰᝲᝳកខគឃងចឆជឈញដឋឌឍណតថទធនបផពភមយរលវឝឞសហឡអឣឤឥឦឧឨឩឪឫឬឭឮឯឰឱឲឳ឴឵ាិីឹឺុូួើឿៀេែៃោៅំះៈ៉៊់៌៍៎៏័៑្៓។៕៖ៗ៘៙៚៛ៜ៝០១២៣៤៥៦៧៨៩៰៱៲៳៴៵៶៷៸៹᠀᠁᠂᠃᠄᠅᠆᠇᠈᠉᠊᠋᠌᠍᠎᠐᠑᠒᠓᠔᠕᠖᠗᠘᠙ᠠᠡᠢᠣᠤᠥᠦᠧᠨᠩᠪᠫᠬᠭᠮᠯᠰᠱᠲᠳᠴᠵᠶᠷᠸᠹᠺᠻᠼᠽᠾᠿᡀᡁᡂᡃᡄᡅᡆᡇᡈᡉᡊᡋᡌᡍᡎᡏᡐᡑᡒᡓᡔᡕᡖᡗᡘᡙᡚᡛᡜᡝᡞᡟᡠᡡᡢᡣᡤᡥᡦᡧᡨᡩᡪᡫᡬᡭᡮᡯᡰᡱᡲᡳᡴᡵᡶᡷᢀᢁᢂᢃᢄᢅᢆᢇᢈᢉᢊᢋᢌᢍᢎᢏᢐᢑᢒᢓᢔᢕᢖᢗᢘᢙᢚᢛᢜᢝᢞᢟᢠᢡᢢᢣᢤᢥᢦᢧᢨᢩᢪᢰᢱᢲᢳᢴᢵᢶᢷᢸᢹᢺᢻᢼᢽᢾᢿᣀᣁᣂᣃᣄᣅᣆᣇᣈᣉᣊᣋᣌᣍᣎᣏᣐᣑᣒᣓᣔᣕᣖᣗᣘᣙᣚᣛᣜᣝᣞᣟᣠᣡᣢᣣᣤᣥᣦᣧᣨᣩᣪᣫᣬᣭᣮᣯᣰᣱᣲᣳᣴᣵᤀᤁᤂᤃᤄᤅᤆᤇᤈᤉᤊᤋᤌᤍᤎᤏᤐᤑᤒᤓᤔᤕᤖᤗᤘᤙᤚᤛᤜᤠᤡᤢᤣᤤᤥᤦᤧᤨᤩᤪᤫᤰᤱᤲᤳᤴᤵᤶᤷᤸ᤻᤹᤺᥀᥄᥅᥆᥇᥈᥉᥊᥋᥌᥍᥎᥏ᥐᥑᥒᥓᥔᥕᥖᥗᥘᥙᥚᥛᥜᥝᥞᥟᥠᥡᥢᥣᥤᥥᥦᥧᥨᥩᥪᥫᥬᥭᥰᥱᥲᥳᥴᦀᦁᦂᦃᦄᦅᦆᦇᦈᦉᦊᦋᦌᦍᦎᦏᦐᦑᦒᦓᦔᦕᦖᦗᦘᦙᦚᦛᦜᦝᦞᦟᦠᦡᦢᦣᦤᦥᦦᦧᦨᦩᦪᦫᦰᦱᦲᦳᦴᦵᦶᦷᦸᦹᦺᦻᦼᦽᦾᦿᧀᧁᧂᧃᧄᧅᧆᧇᧈᧉ᧐᧑᧒᧓᧔᧕᧖᧗᧘᧙᧚᧞᧟᧠᧡᧢᧣᧤᧥᧦᧧᧨᧩᧪᧫᧬᧭᧮᧯᧰᧱᧲᧳᧴᧵᧶᧷᧸᧹᧺᧻᧼᧽᧾᧿ᨀᨁᨂᨃᨄᨅᨆᨇᨈᨉᨊᨋᨌᨍᨎᨏᨐᨑᨒᨓᨔᨕᨖᨘᨗᨙᨚᨛ᨞᨟ᨠᨡᨢᨣᨤᨥᨦᨧᨨᨩᨪᨫᨬᨭᨮᨯᨰᨱᨲᨳᨴᨵᨶᨷᨸᨹᨺᨻᨼᨽᨾᨿᩀᩁᩂᩃᩄᩅᩆᩇᩈᩉᩊᩋᩌᩍᩎᩏᩐᩑᩒᩓᩔᩕᩖᩗᩘᩙᩚᩛᩜᩝᩞ᩠ᩡᩢᩣᩤᩥᩦᩧᩨᩩᩪᩫᩬᩭᩮᩯᩰᩱᩲᩳᩴ᩿᩵᩶᩷᩸᩹᩺᩻᩼᪀᪁᪂᪃᪄᪅᪆᪇᪈᪉᪐᪑᪒᪓᪔᪕᪖᪗᪘᪙᪠᪡᪢᪣᪤᪥᪦ᪧ᪨᪩᪪᪫᪬᪭ᬀᬁᬂᬃᬄᬅᬆᬇᬈᬉᬊᬋᬌᬍᬎᬏᬐᬑᬒᬓᬔᬕᬖᬗᬘᬙᬚᬛᬜᬝᬞᬟᬠᬡᬢᬣᬤᬥᬦᬧᬨᬩᬪᬫᬬᬭᬮᬯᬰᬱᬲᬳ᬴ᬵᬶᬷᬸᬹᬺᬻᬼᬽᬾᬿᭀᭁᭂᭃ᭄ᭅᭆᭇᭈᭉᭊᭋ᭐᭑᭒᭓᭔᭕᭖᭗᭘᭙᭚᭛᭜᭝᭞᭟᭠᭡᭢᭣᭤᭥᭦᭧᭨᭩᭪᭬᭫᭭᭮᭯᭰᭱᭲᭳᭴᭵᭶᭷᭸᭹᭺᭻᭼ᮀᮁᮂᮃᮄᮅᮆᮇᮈᮉᮊᮋᮌᮍᮎᮏᮐᮑᮒᮓᮔᮕᮖᮗᮘᮙᮚᮛᮜᮝᮞᮟᮠᮡᮢᮣᮤᮥᮦᮧᮨᮩ᮪᮫ᮬᮭᮮᮯ᮰᮱᮲᮳᮴᮵᮶᮷᮸᮹ᮺᮻᮼᮽᮾᮿᯀᯁᯂᯃᯄᯅᯆᯇᯈᯉᯊᯋᯌᯍᯎᯏᯐᯑᯒᯓᯔᯕᯖᯗᯘᯙᯚᯛᯜᯝᯞᯟᯠᯡᯢᯣᯤᯥ᯦ᯧᯨᯩᯪᯫᯬᯭᯮᯯᯰᯱ᯲᯳᯼᯽᯾᯿ᰀᰁᰂᰃᰄᰅᰆᰇᰈᰉᰊᰋᰌᰍᰎᰏᰐᰑᰒᰓᰔᰕᰖᰗᰘᰙᰚᰛᰜᰝᰞᰟᰠᰡᰢᰣᰤᰥᰦᰧᰨᰩᰪᰫᰬᰭᰮᰯᰰᰱᰲᰳᰴᰵᰶ᰷᰻᰼᰽᰾᰿᱀᱁᱂᱃᱄᱅᱆᱇᱈᱉ᱍᱎᱏ᱐᱑᱒᱓᱔᱕᱖᱗᱘᱙ᱚᱛᱜᱝᱞᱟᱠᱡᱢᱣᱤᱥᱦᱧᱨᱩᱪᱫᱬᱭᱮᱯᱰᱱᱲᱳᱴᱵᱶᱷᱸᱹᱺᱻᱼᱽ᱾᱿᳀᳁᳂᳃᳄᳅᳆᳇᳐᳑᳒᳓᳔᳕᳖᳗᳘᳙᳜᳝᳞᳟᳚᳛᳠᳡᳢᳣᳤᳥᳦᳧᳨ᳩᳪᳫᳬ᳭ᳮᳯᳰᳱᳲᳳ᳴ᳵᳶᴀᴁᴂᴃᴄᴅᴆᴇᴈᴉᴊᴋᴌᴍᴎᴏᴐᴑᴒᴓᴔᴕᴖᴗᴘᴙᴚᴛᴜᴝᴞᴟᴠᴡᴢᴣᴤᴥᴦᴧᴨᴩᴪᴫᴬᴭᴮᴯᴰᴱᴲᴳᴴᴵᴶᴷᴸᴹᴺᴻᴼᴽᴾᴿᵀᵁᵂᵃᵄᵅᵆᵇᵈᵉᵊᵋᵌᵍᵎᵏᵐᵑᵒᵓᵔᵕᵖᵗᵘᵙᵚᵛᵜᵝᵞᵟᵠᵡᵢᵣᵤᵥᵦᵧᵨᵩᵪᵫᵬᵭᵮᵯᵰᵱᵲᵳᵴᵵᵶᵷᵸᵹᵺᵻᵼᵽᵾᵿᶀᶁᶂᶃᶄᶅᶆᶇᶈᶉᶊᶋᶌᶍᶎᶏᶐᶑᶒᶓᶔᶕᶖᶗᶘᶙᶚᶛᶜᶝᶞᶟᶠᶡᶢᶣᶤᶥᶦᶧᶨᶩᶪᶫᶬᶭᶮᶯᶰᶱᶲᶳᶴᶵᶶᶷᶸᶹᶺᶻᶼᶽᶾᶿ᷐᷎᷂᷊᷏᷽᷿᷀᷁᷃᷄᷅᷆᷇᷈᷉᷋᷌᷑᷒ᷓᷔᷕᷖᷗᷘᷙᷚᷛᷜᷝᷞᷟᷠᷡᷢᷣᷤᷥᷦ᷾᷼᷍ḀḁḂḃḄḅḆḇḈḉḊḋḌḍḎḏḐḑḒḓḔḕḖḗḘḙḚḛḜḝḞḟḠḡḢḣḤḥḦḧḨḩḪḫḬḭḮḯḰḱḲḳḴḵḶḷḸḹḺḻḼḽḾḿṀṁṂṃṄṅṆṇṈṉṊṋṌṍṎṏṐṑṒṓṔṕṖṗṘṙṚṛṜṝṞṟṠṡṢṣṤṥṦṧṨṩṪṫṬṭṮṯṰṱṲṳṴṵṶṷṸṹṺṻṼṽṾṿẀẁẂẃẄẅẆẇẈẉẊẋẌẍẎẏẐẑẒẓẔẕẖẗẘẙẚẛẜẝẞẟẠạẢảẤấẦầẨẩẪẫẬậẮắẰằẲẳẴẵẶặẸẹẺẻẼẽẾếỀềỂểỄễỆệỈỉỊịỌọỎỏỐốỒồỔổỖỗỘộỚớỜờỞởỠỡỢợỤụỦủỨứỪừỬửỮữỰựỲỳỴỵỶỷỸỹỺỻỼỽỾỿἀἁἂἃἄἅἆἇἈἉἊἋἌἍἎἏἐἑἒἓἔἕἘἙἚἛἜἝἠἡἢἣἤἥἦἧἨἩἪἫἬἭἮἯἰἱἲἳἴἵἶἷἸἹἺἻἼἽἾἿὀὁὂὃὄὅὈὉὊὋὌὍὐὑὒὓὔὕὖὗὙὛὝὟὠὡὢὣὤὥὦὧὨὩὪὫὬὭὮὯὰάὲέὴήὶίὸόὺύὼώᾀᾁᾂᾃᾄᾅᾆᾇᾈᾉᾊᾋᾌᾍᾎᾏᾐᾑᾒᾓᾔᾕᾖᾗᾘᾙᾚᾛᾜᾝᾞᾟᾠᾡᾢᾣᾤᾥᾦᾧᾨᾩᾪᾫᾬᾭᾮᾯᾰᾱᾲᾳᾴᾶᾷᾸᾹᾺΆᾼ᾽ι᾿῀῁ῂῃῄῆῇῈΈῊΉῌ῍῎῏ῐῑῒΐῖῗῘῙῚΊ῝῞῟ῠῡῢΰῤῥῦῧῨῩῪΎῬ῭΅`ῲῳῴῶῷῸΌῺΏῼ´῾           ​‌‍‎‏‐‑‒–—―‖‗‘’‚‛“”„‟†‡•‣․‥…‧

‪‭‮ ‰‱′″‴‵‶‷‸‹›※‼‽‾‿⁀⁁⁂⁃⁄⁅⁆⁇⁈⁉⁊⁋⁌⁍⁎⁏⁐⁑⁒⁓⁔⁕⁖⁗⁘⁙⁚⁛⁜⁝⁞ ⁠⁡⁢⁣⁤⁰ⁱ⁴⁵⁶⁷⁸⁹⁺⁻⁼⁽⁾ⁿ₀₁₂₃₄₅₆₇₈₉₊₋₌₍₎ₐₑₒₓₔₕₖₗₘₙₚₛₜ₠₡₢₣₤₥₦₧₨₩₪₫€₭₮₯₰₱₲₳₴₵₶₷₸₹₺₻₼₽₾₿⃒⃓⃘⃙⃚⃐⃑⃔⃕⃖⃗⃛⃜⃝⃞⃟⃠⃡⃢⃣⃤⃥⃦⃪⃫⃨⃬⃭⃮⃯⃧⃩⃰℀℁ℂ℃℄℅℆ℇ℈℉ℊℋℌℍℎℏℐℑℒℓ℔ℕ№℗℘ℙℚℛℜℝ℞℟℠℡™℣ℤ℥Ω℧ℨ℩KÅℬℭ℮ℯℰℱℲℳℴℵℶℷℸℹ℺℻ℼℽℾℿ⅀⅁⅂⅃⅄ⅅⅆⅇⅈⅉ⅊⅋⅌⅍ⅎ⅏⅐⅑⅒⅓⅔⅕⅖⅗⅘⅙⅚⅛⅜⅝⅞⅟ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫⅬⅭⅮⅯⅰⅱⅲⅳⅴⅵⅶⅷⅸⅹⅺⅻⅼⅽⅾⅿↀↁↂↃↄↅↆↇↈ↉←↑→↓↔↕↖↗↘↙↚↛↜↝↞↟↠↡↢↣↤↥↦↧↨↩↪↫↬↭↮↯↰↱↲↳↴↵↶↷↸↹↺↻↼↽↾↿⇀⇁⇂⇃⇄⇅⇆⇇⇈⇉⇊⇋⇌⇍⇎⇏⇐⇑⇒⇓⇔⇕⇖⇗⇘⇙⇚⇛⇜⇝⇞⇟⇠⇡⇢⇣⇤⇥⇦⇧⇨⇩⇪⇫⇬⇭⇮⇯⇰⇱⇲⇳⇴⇵⇶⇷⇸⇹⇺⇻⇼⇽⇾⇿∀∁∂∃∄∅∆∇∈∉∊∋∌∍∎∏∐∑−∓∔∕∖∗∘∙√∛∜∝∞∟∠∡∢∣∤∥∦∧∨∩∪∫∬∭∮∯∰∱∲∳∴∵∶∷∸∹∺∻∼∽∾∿≀≁≂≃≄≅≆≇≈≉≊≋≌≍≎≏≐≑≒≓≔≕≖≗≘≙≚≛≜≝≞≟≠≡≢≣≤≥≦≧≨≩≪≫≬≭≮≯≰≱≲≳≴≵≶≷≸≹≺≻≼≽≾≿⊀⊁⊂⊃⊄⊅⊆⊇⊈⊉⊊⊋⊌⊍⊎⊏⊐⊑⊒⊓⊔⊕⊖⊗⊘⊙⊚⊛⊜⊝⊞⊟⊠⊡⊢⊣⊤⊥⊦⊧⊨⊩⊪⊫⊬⊭⊮⊯⊰⊱⊲⊳⊴⊵⊶⊷⊸⊹⊺⊻⊼⊽⊾⊿⋀⋁⋂⋃⋄⋅⋆⋇⋈⋉⋊⋋⋌⋍⋎⋏⋐⋑⋒⋓⋔⋕⋖⋗⋘⋙⋚⋛⋜⋝⋞⋟⋠⋡⋢⋣⋤⋥⋦⋧⋨⋩⋪⋫⋬⋭⋮⋯⋰⋱⋲⋳⋴⋵⋶⋷⋸⋹⋺⋻⋼⋽⋾⋿⌀⌁⌂⌃⌄⌅⌆⌇⌈⌉⌊⌋⌌⌍⌎⌏⌐⌑⌒⌓⌔⌕⌖⌗⌘⌙⌚⌛⌜⌝⌞⌟⌠⌡⌢⌣⌤⌥⌦⌧⌨〈〉⌫⌬⌭⌮⌯⌰⌱⌲⌳⌴⌵⌶⌷⌸⌹⌺⌻⌼⌽⌾⌿⍀⍁⍂⍃⍄⍅⍆⍇⍈⍉⍊⍋⍌⍍⍎⍏⍐⍑⍒⍓⍔⍕⍖⍗⍘⍙⍚⍛⍜⍝⍞⍟⍠⍡⍢⍣⍤⍥⍦⍧⍨⍩⍪⍫⍬⍭⍮⍯⍰⍱⍲⍳⍴⍵⍶⍷⍸⍹⍺⍻⍼⍽⍾⍿⎀⎁⎂⎃⎄⎅⎆⎇⎈⎉⎊⎋⎌⎍⎎⎏⎐⎑⎒⎓⎔⎕⎖⎗⎘⎙⎚⎛⎜⎝⎞⎟⎠⎡⎢⎣⎤⎥⎦⎧⎨⎩⎪⎫⎬⎭⎮⎯⎰⎱⎲⎳⎴⎵⎶⎷⎸⎹⎺⎻⎼⎽⎾⎿⏀⏁⏂⏃⏄⏅⏆⏇⏈⏉⏊⏋⏌⏍⏎⏏⏐⏑⏒⏓⏔⏕⏖⏗⏘⏙⏚⏛⏜⏝⏞⏟⏠⏡⏢⏣⏤⏥⏦⏧⏨⏩⏪⏫⏬⏭⏮⏯⏰⏱⏲⏳␀␁␂␃␄␅␆␇␈␉␊␋␌␍␎␏␐␑␒␓␔␕␖␗␘␙␚␛␜␝␞␟␠␡␢␣␤␥␦⑀⑁⑂⑃⑄⑅⑆⑇⑈⑉⑊①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳⑴⑵⑶⑷⑸⑹⑺⑻⑼⑽⑾⑿⒀⒁⒂⒃⒄⒅⒆⒇⒈⒉⒊⒋⒌⒍⒎⒏⒐⒑⒒⒓⒔⒕⒖⒗⒘⒙⒚⒛⒜⒝⒞⒟⒠⒡⒢⒣⒤⒥⒦⒧⒨⒩⒪⒫⒬⒭⒮⒯⒰⒱⒲⒳⒴⒵ⒶⒷⒸⒹⒺⒻⒼⒽⒾⒿⓀⓁⓂⓃⓄⓅⓆⓇⓈⓉⓊⓋⓌⓍⓎⓏⓐⓑⓒⓓⓔⓕⓖⓗⓘⓙⓚⓛⓜⓝⓞⓟⓠⓡⓢⓣⓤⓥⓦⓧⓨⓩ⓪⓫⓬⓭⓮⓯⓰⓱⓲⓳⓴⓵⓶⓷⓸⓹⓺⓻⓼⓽⓾⓿─━│┃┄┅┆┇┈┉┊┋┌┍┎┏┐┑┒┓└┕┖┗┘┙┚┛├┝┞┟┠┡┢┣┤┥┦┧┨┩┪┫┬┭┮┯┰┱┲┳┴┵┶┷┸┹┺┻┼┽┾┿╀╁╂╃╄╅╆╇╈╉╊╋╌╍╎╏═║╒╓╔╕╖╗╘╙╚╛╜╝╞╟╠╡╢╣╤╥╦╧╨╩╪╫╬╭╮╯╰╱╲╳╴╵╶╷╸╹╺╻╼╽╾╿▀▁▂▃▄▅▆▇█▉▊▋▌▍▎▏▐░▒▓▔▕▖▗▘▙▚▛▜▝▞▟■□▢▣▤▥▦▧▨▩▪▫▬▭▮▯▰▱▲△▴▵▶▷▸▹►▻▼▽▾▿◀◁◂◃◄◅◆◇◈◉◊○◌◍◎●◐◑◒◓◔◕◖◗◘◙◚◛◜◝◞◟◠◡◢◣◤◥◦◧◨◩◪◫◬◭◮◯◰◱◲◳◴◵◶◷◸◹◺◻◼◽◾◿☀☁☂☃☄★☆☇☈☉☊☋☌☍☎☏☐☑☒☓☔☕☖☗☘☙☚☛☜☝☞☟☠☡☢☣☤☥☦☧☨☩☪☫☬☭☮☯☰☱☲☳☴☵☶☷☸☹☺☻☼☽☾☿♀♁♂♃♄♅♆♇♈♉♊♋♌♍♎♏♐♑♒♓♔♕♖♗♘♙♚♛♜♝♞♟♠♡♢♣♤♥♦♧♨♩♪♫♬♭♮♯♰♱♲♳♴♵♶♷♸♹♺♻♼♽♾♿⚀⚁⚂⚃⚄⚅⚆⚇⚈⚉⚊⚋⚌⚍⚎⚏⚐⚑⚒⚓⚔⚕⚖⚗⚘⚙⚚⚛⚜⚝⚞⚟⚠⚡⚢⚣⚤⚥⚦⚧⚨⚩⚪⚫⚬⚭⚮⚯⚰⚱⚲⚳⚴⚵⚶⚷⚸⚹⚺⚻⚼⚽⚾⚿⛀⛁⛂⛃⛄⛅⛆⛇⛈⛉⛊⛋⛌⛍⛎⛏⛐⛑⛒⛓⛔⛕⛖⛗⛘⛙⛚⛛⛜⛝⛞⛟⛠⛡⛢⛣⛤⛥⛦⛧⛨⛩⛪⛫⛬⛭⛮⛯⛰⛱⛲⛳⛴⛵⛶⛷⛸⛹⛺⛻⛼⛽⛾⛿✁✂✃✄✅✆✇✈✉✊✋✌✍✎✏✐✑✒✓✔✕✖✗✘✙✚✛✜✝✞✟✠✡✢✣✤✥✦✧✨✩✪✫✬✭✮✯✰✱✲✳✴✵✶✷✸✹✺✻✼✽✾✿❀❁❂❃❄❅❆❇❈❉❊❋❌❍❎❏❐❑❒❓❔❕❖❗❘❙❚❛❜❝❞❟❠❡❢❣❤❥❦❧❨❩❪❫❬❭❮❯❰❱❲❳❴❵❶❷❸❹❺❻❼❽❾❿➀➁➂➃➄➅➆➇➈➉➊➋➌➍➎➏➐➑➒➓➔➕➖➗➘➙➚➛➜➝➞➟➠➡➢➣➤➥➦➧➨➩➪➫➬➭➮➯➰➱➲➳➴➵➶➷➸➹➺➻➼➽➾➿⟀⟁⟂⟃⟄⟅⟆⟇⟈⟉⟊⟋⟌⟍⟎⟏⟐⟑⟒⟓⟔⟕⟖⟗⟘⟙⟚⟛⟜⟝⟞⟟⟠⟡⟢⟣⟤⟥⟦⟧⟨⟩⟪⟫⟬⟭⟮⟯⟰⟱⟲⟳⟴⟵⟶⟷⟸⟹⟺⟻⟼⟽⟾⟿⠀⠁⠂⠃⠄⠅⠆⠇⠈⠉⠊⠋⠌⠍⠎⠏⠐⠑⠒⠓⠔⠕⠖⠗⠘⠙⠚⠛⠜⠝⠞⠟⠠⠡⠢⠣⠤⠥⠦⠧⠨⠩⠪⠫⠬⠭⠮⠯⠰⠱⠲⠳⠴⠵⠶⠷⠸⠹⠺⠻⠼⠽⠾⠿⡀⡁⡂⡃⡄⡅⡆⡇⡈⡉⡊⡋⡌⡍⡎⡏⡐⡑⡒⡓⡔⡕⡖⡗⡘⡙⡚⡛⡜⡝⡞⡟⡠⡡⡢⡣⡤⡥⡦⡧⡨⡩⡪⡫⡬⡭⡮⡯⡰⡱⡲⡳⡴⡵⡶⡷⡸⡹⡺⡻⡼⡽⡾⡿⢀⢁⢂⢃⢄⢅⢆⢇⢈⢉⢊⢋⢌⢍⢎⢏⢐⢑⢒⢓⢔⢕⢖⢗⢘⢙⢚⢛⢜⢝⢞⢟⢠⢡⢢⢣⢤⢥⢦⢧⢨⢩⢪⢫⢬⢭⢮⢯⢰⢱⢲⢳⢴⢵⢶⢷⢸⢹⢺⢻⢼⢽⢾⢿⣀⣁⣂⣃⣄⣅⣆⣇⣈⣉⣊⣋⣌⣍⣎⣏⣐⣑⣒⣓⣔⣕⣖⣗⣘⣙⣚⣛⣜⣝⣞⣟⣠⣡⣢⣣⣤⣥⣦⣧⣨⣩⣪⣫⣬⣭⣮⣯⣰⣱⣲⣳⣴⣵⣶⣷⣸⣹⣺⣻⣼⣽⣾⣿⤀⤁⤂⤃⤄⤅⤆⤇⤈⤉⤊⤋⤌⤍⤎⤏⤐⤑⤒⤓⤔⤕⤖⤗⤘⤙⤚⤛⤜⤝⤞⤟⤠⤡⤢⤣⤤⤥⤦⤧⤨⤩⤪⤫⤬⤭⤮⤯⤰⤱⤲⤳⤴⤵⤶⤷⤸⤹⤺⤻⤼⤽⤾⤿⥀⥁⥂⥃⥄⥅⥆⥇⥈⥉⥊⥋⥌⥍⥎⥏⥐⥑⥒⥓⥔⥕⥖⥗⥘⥙⥚⥛⥜⥝⥞⥟⥠⥡⥢⥣⥤⥥⥦⥧⥨⥩⥪⥫⥬⥭⥮⥯⥰⥱⥲⥳⥴⥵⥶⥷⥸⥹⥺⥻⥼⥽⥾⥿⦀⦁⦂⦃⦄⦅⦆⦇⦈⦉⦊⦋⦌⦍⦎⦏⦐⦑⦒⦓⦔⦕⦖⦗⦘⦙⦚⦛⦜⦝⦞⦟⦠⦡⦢⦣⦤⦥⦦⦧⦨⦩⦪⦫⦬⦭⦮⦯⦰⦱⦲⦳⦴⦵⦶⦷⦸⦹⦺⦻⦼⦽⦾⦿⧀⧁⧂⧃⧄⧅⧆⧇⧈⧉⧊⧋⧌⧍⧎⧏⧐⧑⧒⧓⧔⧕⧖⧗⧘⧙⧚⧛⧜⧝⧞⧟⧠⧡⧢⧣⧤⧥⧦⧧⧨⧩⧪⧫⧬⧭⧮⧯⧰⧱⧲⧳⧴⧵⧶⧷⧸⧹⧺⧻⧼⧽⧾⧿⨀⨁⨂⨃⨄⨅⨆⨇⨈⨉⨊⨋⨌⨍⨎⨏⨐⨑⨒⨓⨔⨕⨖⨗⨘⨙⨚⨛⨜⨝⨞⨟⨠⨡⨢⨣⨤⨥⨦⨧⨨⨩⨪⨫⨬⨭⨮⨯⨰⨱⨲⨳⨴⨵⨶⨷⨸⨹⨺⨻⨼⨽⨾⨿⩀⩁⩂⩃⩄⩅⩆⩇⩈⩉⩊⩋⩌⩍⩎⩏⩐⩑⩒⩓⩔⩕⩖⩗⩘⩙⩚⩛⩜⩝⩞⩟⩠⩡⩢⩣⩤⩥⩦⩧⩨⩩⩪⩫⩬⩭⩮⩯⩰⩱⩲⩳⩴⩵⩶⩷⩸⩹⩺⩻⩼⩽⩾⩿⪀⪁⪂⪃⪄⪅⪆⪇⪈⪉⪊⪋⪌⪍⪎⪏⪐⪑⪒⪓⪔⪕⪖⪗⪘⪙⪚⪛⪜⪝⪞⪟⪠⪡⪢⪣⪤⪥⪦⪧⪨⪩⪪⪫⪬⪭⪮⪯⪰⪱⪲⪳⪴⪵⪶⪷⪸⪹⪺⪻⪼⪽⪾⪿⫀⫁⫂⫃⫄⫅⫆⫇⫈⫉⫊⫋⫌⫍⫎⫏⫐⫑⫒⫓⫔⫕⫖⫗⫘⫙⫚⫛⫝̸⫝⫞⫟⫠⫡⫢⫣⫤⫥⫦⫧⫨⫩⫪⫫⫬⫭⫮⫯⫰⫱⫲⫳⫴⫵⫶⫷⫸⫹⫺⫻⫼⫽⫾⫿⬀⬁⬂⬃⬄⬅⬆⬇⬈⬉⬊⬋⬌⬍⬎⬏⬐⬑⬒⬓⬔⬕⬖⬗⬘⬙⬚⬛⬜⬝⬞⬟⬠⬡⬢⬣⬤⬥⬦⬧⬨⬩⬪⬫⬬⬭⬮⬯⬰⬱⬲⬳⬴⬵⬶⬷⬸⬹⬺⬻⬼⬽⬾⬿⭀⭁⭂⭃⭄⭅⭆⭇⭈⭉⭊⭋⭌⭐⭑⭒⭓⭔⭕⭖⭗⭘⭙ⰀⰁⰂⰃⰄⰅⰆⰇⰈⰉⰊⰋⰌⰍⰎⰏⰐⰑⰒⰓⰔⰕⰖⰗⰘⰙⰚⰛⰜⰝⰞⰟⰠⰡⰢⰣⰤⰥⰦⰧⰨⰩⰪⰫⰬⰭⰮⰰⰱⰲⰳⰴⰵⰶⰷⰸⰹⰺⰻⰼⰽⰾⰿⱀⱁⱂⱃⱄⱅⱆⱇⱈⱉⱊⱋⱌⱍⱎⱏⱐⱑⱒⱓⱔⱕⱖⱗⱘⱙⱚⱛⱜⱝⱞⱠⱡⱢⱣⱤⱥⱦⱧⱨⱩⱪⱫⱬⱭⱮⱯⱰⱱⱲⱳⱴⱵⱶⱷⱸⱹⱺⱻⱼⱽⱾⱿⲀⲁⲂⲃⲄⲅⲆⲇⲈⲉⲊⲋⲌⲍⲎⲏⲐⲑⲒⲓⲔⲕⲖⲗⲘⲙⲚⲛⲜⲝⲞⲟⲠⲡⲢⲣⲤⲥⲦⲧⲨⲩⲪⲫⲬⲭⲮⲯⲰⲱⲲⲳⲴⲵⲶⲷⲸⲹⲺⲻⲼⲽⲾⲿⳀⳁⳂⳃⳄⳅⳆⳇⳈⳉⳊⳋⳌⳍⳎⳏⳐⳑⳒⳓⳔⳕⳖⳗⳘⳙⳚⳛⳜⳝⳞⳟⳠⳡⳢⳣⳤ⳥⳦⳧⳨⳩⳪ⳫⳬⳭⳮ⳯⳰⳱Ⳳⳳ⳹⳺⳻⳼⳽⳾⳿ⴀⴁⴂⴃⴄⴅⴆⴇⴈⴉⴊⴋⴌⴍⴎⴏⴐⴑⴒⴓⴔⴕⴖⴗⴘⴙⴚⴛⴜⴝⴞⴟⴠⴡⴢⴣⴤⴥⴧⴭⴰⴱⴲⴳⴴⴵⴶⴷⴸⴹⴺⴻⴼⴽⴾⴿⵀⵁⵂⵃⵄⵅⵆⵇⵈⵉⵊⵋⵌⵍⵎⵏⵐⵑⵒⵓⵔⵕⵖⵗⵘⵙⵚⵛⵜⵝⵞⵟⵠⵡⵢⵣⵤⵥⵦⵧⵯ⵰⵿ⶀⶁⶂⶃⶄⶅⶆⶇⶈⶉⶊⶋⶌⶍⶎⶏⶐⶑⶒⶓⶔⶕⶖⶠⶡⶢⶣⶤⶥⶦⶨⶩⶪⶫⶬⶭⶮⶰⶱⶲⶳⶴⶵⶶⶸⶹⶺⶻⶼⶽⶾⷀⷁⷂⷃⷄⷅⷆⷈⷉⷊⷋⷌⷍⷎⷐⷑⷒⷓⷔⷕⷖⷘⷙⷚⷛⷜⷝⷞⷠⷡⷢⷣⷤⷥⷦⷧⷨⷩⷪⷫⷬⷭⷮⷯⷰⷱⷲⷳⷴⷵⷶⷷⷸⷹⷺⷻⷼⷽⷾⷿ⸀⸁⸂⸃⸄⸅⸆⸇⸈⸉⸊⸋⸌⸍⸎⸏⸐⸑⸒⸓⸔⸕⸖⸗⸘⸙⸚⸛⸜⸝⸞⸟⸠⸡⸢⸣⸤⸥⸦⸧⸨⸩⸪⸫⸬⸭⸮ⸯ⸰⸱⸲⸳⸴⸵⸶⸷⸸⸹⸺⸻⺀⺁⺂⺃⺄⺅⺆⺇⺈⺉⺊⺋⺌⺍⺎⺏⺐⺑⺒⺓⺔⺕⺖⺗⺘⺙⺛⺜⺝⺞⺟⺠⺡⺢⺣⺤⺥⺦⺧⺨⺩⺪⺫⺬⺭⺮⺯⺰⺱⺲⺳⺴⺵⺶⺷⺸⺹⺺⺻⺼⺽⺾⺿⻀⻁⻂⻃⻄⻅⻆⻇⻈⻉⻊⻋⻌⻍⻎⻏⻐⻑⻒⻓⻔⻕⻖⻗⻘⻙⻚⻛⻜⻝⻞⻟⻠⻡⻢⻣⻤⻥⻦⻧⻨⻩⻪⻫⻬⻭⻮⻯⻰⻱⻲⻳⼀⼁⼂⼃⼄⼅⼆⼇⼈⼉⼊⼋⼌⼍⼎⼏⼐⼑⼒⼓⼔⼕⼖⼗⼘⼙⼚⼛⼜⼝⼞⼟⼠⼡⼢⼣⼤⼥⼦⼧⼨⼩⼪⼫⼬⼭⼮⼯⼰⼱⼲⼳⼴⼵⼶⼷⼸⼹⼺⼻⼼⼽⼾⼿⽀⽁⽂⽃⽄⽅⽆⽇⽈⽉⽊⽋⽌⽍⽎⽏⽐⽑⽒⽓⽔⽕⽖⽗⽘⽙⽚⽛⽜⽝⽞⽟⽠⽡⽢⽣⽤⽥⽦⽧⽨⽩⽪⽫⽬⽭⽮⽯⽰⽱⽲⽳⽴⽵⽶⽷⽸⽹⽺⽻⽼⽽⽾⽿⾀⾁⾂⾃⾄⾅⾆⾇⾈⾉⾊⾋⾌⾍⾎⾏⾐⾑⾒⾓⾔⾕⾖⾗⾘⾙⾚⾛⾜⾝⾞⾟⾠⾡⾢⾣⾤⾥⾦⾧⾨⾩⾪⾫⾬⾭⾮⾯⾰⾱⾲⾳⾴⾵⾶⾷⾸⾹⾺⾻⾼⾽⾾⾿⿀⿁⿂⿃⿄⿅⿆⿇⿈⿉⿊⿋⿌⿍⿎⿏⿐⿑⿒⿓⿔⿕⿰⿱⿲⿳⿴⿵⿶⿷⿸⿹⿺⿻ 、。〃〄々〆〇〈〉《》「」『』【】〒〓〔〕〖〗〘〙〚〛〜〝〞〟〠〡〢〣〤〥〦〧〨〩〪〭〮〯〫〬〰〱〲〳〴〵〶〷〸〹〺〻〼〽〾〿ぁあぃいぅうぇえぉおかがきぎくぐけげこごさざしじすずせぜそぞただちぢっつづてでとどなにぬねのはばぱひびぴふぶぷへべぺほぼぽまみむめもゃやゅゆょよらりるれろゎわゐゑをんゔゕゖ゙゚゛゜ゝゞゟ゠ァアィイゥウェエォオカガキギクグケゲコゴサザシジスズセゼソゾタダチヂッツヅテデトドナニヌネノハバパヒビピフブプヘベペホボポマミムメモャヤュユョヨラリルレロヮワヰヱヲンヴヵヶヷヸヹヺ・ーヽヾヿㄅㄆㄇㄈㄉㄊㄋㄌㄍㄎㄏㄐㄑㄒㄓㄔㄕㄖㄗㄘㄙㄚㄛㄜㄝㄞㄟㄠㄡㄢㄣㄤㄥㄦㄧㄨㄩㄪㄫㄬㄭㄱㄲㄳㄴㄵㄶㄷㄸㄹㄺㄻㄼㄽㄾㄿㅀㅁㅂㅃㅄㅅㅆㅇㅈㅉㅊㅋㅌㅍㅎㅏㅐㅑㅒㅓㅔㅕㅖㅗㅘㅙㅚㅛㅜㅝㅞㅟㅠㅡㅢㅣㅤㅥㅦㅧㅨㅩㅪㅫㅬㅭㅮㅯㅰㅱㅲㅳㅴㅵㅶㅷㅸㅹㅺㅻㅼㅽㅾㅿㆀㆁㆂㆃㆄㆅㆆㆇㆈㆉㆊㆋㆌㆍㆎ㆐㆑㆒㆓㆔㆕㆖㆗㆘㆙㆚㆛㆜㆝㆞㆟ㆠㆡㆢㆣㆤㆥㆦㆧㆨㆩㆪㆫㆬㆭㆮㆯㆰㆱㆲㆳㆴㆵㆶㆷㆸㆹㆺ㇀㇁㇂㇃㇄㇅㇆㇇㇈㇉㇊㇋㇌㇍㇎㇏㇐㇑㇒㇓㇔㇕㇖㇗㇘㇙㇚㇛㇜㇝㇞㇟㇠㇡㇢㇣ㇰㇱㇲㇳㇴㇵㇶㇷㇸㇹㇺㇻㇼㇽㇾㇿ㈀㈁㈂㈃㈄㈅㈆㈇㈈㈉㈊㈋㈌㈍㈎㈏㈐㈑㈒㈓㈔㈕㈖㈗㈘㈙㈚㈛㈜㈝㈞㈠㈡㈢㈣㈤㈥㈦㈧㈨㈩㈪㈫㈬㈭㈮㈯㈰㈱㈲㈳㈴㈵㈶㈷㈸㈹㈺㈻㈼㈽㈾㈿㉀㉁㉂㉃㉄㉅㉆㉇㉈㉉㉊㉋㉌㉍㉎㉏㉐㉑㉒㉓㉔㉕㉖㉗㉘㉙㉚㉛㉜㉝㉞㉟㉠㉡㉢㉣㉤㉥㉦㉧㉨㉩㉪㉫㉬㉭㉮㉯㉰㉱㉲㉳㉴㉵㉶㉷㉸㉹㉺㉻㉼㉽㉾㉿㊀㊁㊂㊃㊄㊅㊆㊇㊈㊉㊊㊋㊌㊍㊎㊏㊐㊑㊒㊓㊔㊕㊖㊗㊘㊙㊚㊛㊜㊝㊞㊟㊠㊡㊢㊣㊤㊥㊦㊧㊨㊩㊪㊫㊬㊭㊮㊯㊰㊱㊲㊳㊴㊵㊶㊷㊸㊹㊺㊻㊼㊽㊾㊿㋀㋁㋂㋃㋄㋅㋆㋇㋈㋉㋊㋋㋌㋍㋎㋏㋐㋑㋒㋓㋔㋕㋖㋗㋘㋙㋚㋛㋜㋝㋞㋟㋠㋡㋢㋣㋤㋥㋦㋧㋨㋩㋪㋫㋬㋭㋮㋯㋰㋱㋲㋳㋴㋵㋶㋷㋸㋹㋺㋻㋼㋽㋾㋿㌀㌁㌂㌃㌄㌅㌆㌇㌈㌉㌊㌋㌌㌍㌎㌏㌐㌑㌒㌓㌔㌕㌖㌗㌘㌙㌚㌛㌜㌝㌞㌟㌠㌡㌢㌣㌤㌥㌦㌧㌨㌩㌪㌫㌬㌭㌮㌯㌰㌱㌲㌳㌴㌵㌶㌷㌸㌹㌺㌻㌼㌽㌾㌿㍀㍁㍂㍃㍄㍅㍆㍇㍈㍉㍊㍋㍌㍍㍎㍏㍐㍑㍒㍓㍔㍕㍖㍗㍘㍙㍚㍛㍜㍝㍞㍟㍠㍡㍢㍣㍤㍥㍦㍧㍨㍩㍪㍫㍬㍭㍮㍯㍰㍱㍲㍳㍴㍵㍶㍷㍸㍹㍺㍻㍼㍽㍾㍿㎀㎁㎂㎃㎄㎅㎆㎇㎈㎉㎊㎋㎌㎍㎎㎏㎐㎑㎒㎓㎔㎕㎖㎗㎘㎙㎚㎛㎜㎝㎞㎟㎠㎡㎢㎣㎤㎥㎦㎧㎨㎩㎪㎫㎬㎭㎮㎯㎰㎱㎲㎳㎴㎵㎶㎷㎸㎹㎺㎻㎼㎽㎾㎿㏀㏁㏂㏃㏄㏅㏆㏇㏈㏉㏊㏋㏌㏍㏎㏏㏐㏑㏒㏓㏔㏕㏖㏗㏘㏙㏚㏛㏜㏝㏞㏟㏠㏡㏢㏣㏤㏥㏦㏧㏨㏩㏪㏫㏬㏭㏮㏯㏰㏱㏲㏳㏴㏵㏶㏷㏸㏹㏺㏻㏼㏽㏾㏿㐀㐁㐂㐃㐄㐅㐆㐇㐈㐉㐊㐋㐌㐍㐎㐏㐐㐑㐒㐓㐔㐕㐖㐗㐘㐙㐚㐛㐜㐝㐞㐟㐠㐡㐢㐣㐤㐥㐦㐧㐨㐩㐪㐫㐬㐭㐮㐯㐰㐱㐲㐳㐴㐵㐶㐷㐸㐹㐺㐻㐼㐽㐾㐿㑀㑁㑂㑃㑄㑅㑆㑇㑈㑉㑊㑋㑌㑍㑎㑏㑐㑑㑒㑓㑔㑕㑖㑗㑘㑙㑚㑛㑜㑝㑞㑟㑠㑡㑢㑣㑤㑥㑦㑧㑨㑩㑪㑫㑬㑭㑮㑯㑰㑱㑲㑳㑴㑵㑶㑷㑸㑹㑺㑻㑼㑽㑾㑿㒀㒁㒂㒃㒄㒅㒆㒇㒈㒉㒊㒋㒌㒍㒎㒏㒐㒑㒒㒓㒔㒕㒖㒗㒘㒙㒚㒛㒜㒝㒞㒟㒠㒡㒢㒣㒤㒥㒦㒧㒨㒩㒪㒫㒬㒭㒮㒯㒰㒱㒲㒳㒴㒵㒶㒷㒸㒹㒺㒻㒼㒽㒾㒿㓀㓁㓂㓃㓄㓅㓆㓇㓈㓉㓊㓋㓌㓍㓎㓏㓐㓑㓒㓓㓔㓕㓖㓗㓘㓙㓚㓛㓜㓝㓞㓟㓠㓡㓢㓣㓤㓥㓦㓧㓨㓩㓪㓫㓬㓭㓮㓯㓰㓱㓲㓳㓴㓵㓶㓷㓸㓹㓺㓻㓼㓽㓾㓿㔀㔁㔂㔃㔄㔅㔆㔇㔈㔉㔊㔋㔌㔍㔎㔏㔐㔑㔒㔓㔔㔕㔖㔗㔘㔙㔚㔛㔜㔝㔞㔟㔠㔡㔢㔣㔤㔥㔦㔧㔨㔩㔪㔫㔬㔭㔮㔯㔰㔱㔲㔳㔴㔵㔶㔷㔸㔹㔺㔻㔼㔽㔾㔿㕀㕁㕂㕃㕄㕅㕆㕇㕈㕉㕊㕋㕌㕍㕎㕏㕐㕑㕒㕓㕔㕕㕖㕗㕘㕙㕚㕛㕜㕝㕞㕟㕠㕡㕢㕣㕤㕥㕦㕧㕨㕩㕪㕫㕬㕭㕮㕯㕰㕱㕲㕳㕴㕵㕶㕷㕸㕹㕺㕻㕼㕽㕾㕿㖀㖁㖂㖃㖄㖅㖆㖇㖈㖉㖊㖋㖌㖍㖎㖏㖐㖑㖒㖓㖔㖕㖖㖗㖘㖙㖚㖛㖜㖝㖞㖟㖠㖡㖢㖣㖤㖥㖦㖧㖨㖩㖪㖫㖬㖭㖮㖯㖰㖱㖲㖳㖴㖵㖶㖷㖸㖹㖺㖻㖼㖽㖾㖿㗀㗁㗂㗃㗄㗅㗆㗇㗈㗉㗊㗋㗌㗍㗎㗏㗐㗑㗒㗓㗔㗕㗖㗗㗘㗙㗚㗛㗜㗝㗞㗟㗠㗡㗢㗣㗤㗥㗦㗧㗨㗩㗪㗫㗬㗭㗮㗯㗰㗱㗲㗳㗴㗵㗶㗷㗸㗹㗺㗻㗼㗽㗾㗿㘀㘁㘂㘃㘄㘅㘆㘇㘈㘉㘊㘋㘌㘍㘎㘏㘐㘑㘒㘓㘔㘕㘖㘗㘘㘙㘚㘛㘜㘝㘞㘟㘠㘡㘢㘣㘤㘥㘦㘧㘨㘩㘪㘫㘬㘭㘮㘯㘰㘱㘲㘳㘴㘵㘶㘷㘸㘹㘺㘻㘼㘽㘾㘿㙀㙁㙂㙃㙄㙅㙆㙇㙈㙉㙊㙋㙌㙍㙎㙏㙐㙑㙒㙓㙔㙕㙖㙗㙘㙙㙚㙛㙜㙝㙞㙟㙠㙡㙢㙣㙤㙥㙦㙧㙨㙩㙪㙫㙬㙭㙮㙯㙰㙱㙲㙳㙴㙵㙶㙷㙸㙹㙺㙻㙼㙽㙾㙿㚀㚁㚂㚃㚄㚅㚆㚇㚈㚉㚊㚋㚌㚍㚎㚏㚐㚑㚒㚓㚔㚕㚖㚗㚘㚙㚚㚛㚜㚝㚞㚟㚠㚡㚢㚣㚤㚥㚦㚧㚨㚩㚪㚫㚬㚭㚮㚯㚰㚱㚲㚳㚴㚵㚶㚷㚸㚹㚺㚻㚼㚽㚾㚿㛀㛁㛂㛃㛄㛅㛆㛇㛈㛉㛊㛋㛌㛍㛎㛏㛐㛑㛒㛓㛔㛕㛖㛗㛘㛙㛚㛛㛜㛝㛞㛟㛠㛡㛢㛣㛤㛥㛦㛧㛨㛩㛪㛫㛬㛭㛮㛯㛰㛱㛲㛳㛴㛵㛶㛷㛸㛹㛺㛻㛼㛽㛾㛿㜀㜁㜂㜃㜄㜅㜆㜇㜈㜉㜊㜋㜌㜍㜎㜏㜐㜑㜒㜓㜔㜕㜖㜗㜘㜙㜚㜛㜜㜝㜞㜟㜠㜡㜢㜣㜤㜥㜦㜧㜨㜩㜪㜫㜬㜭㜮㜯㜰㜱㜲㜳㜴㜵㜶㜷㜸㜹㜺㜻㜼㜽㜾㜿㝀㝁㝂㝃㝄㝅㝆㝇㝈㝉㝊㝋㝌㝍㝎㝏㝐㝑㝒㝓㝔㝕㝖㝗㝘㝙㝚㝛㝜㝝㝞㝟㝠㝡㝢㝣㝤㝥㝦㝧㝨㝩㝪㝫㝬㝭㝮㝯㝰㝱㝲㝳㝴㝵㝶㝷㝸㝹㝺㝻㝼㝽㝾㝿㞀㞁㞂㞃㞄㞅㞆㞇㞈㞉㞊㞋㞌㞍㞎㞏㞐㞑㞒㞓㞔㞕㞖㞗㞘㞙㞚㞛㞜㞝㞞㞟㞠㞡㞢㞣㞤㞥㞦㞧㞨㞩㞪㞫㞬㞭㞮㞯㞰㞱㞲㞳㞴㞵㞶㞷㞸㞹㞺㞻㞼㞽㞾㞿㟀㟁㟂㟃㟄㟅㟆㟇㟈㟉㟊㟋㟌㟍㟎㟏㟐㟑㟒㟓㟔㟕㟖㟗㟘㟙㟚㟛㟜㟝㟞㟟㟠㟡㟢㟣㟤㟥㟦㟧㟨㟩㟪㟫㟬㟭㟮㟯㟰㟱㟲㟳㟴㟵㟶㟷㟸㟹㟺㟻㟼㟽㟾㟿㠀㠁㠂㠃㠄㠅㠆㠇㠈㠉㠊㠋㠌㠍㠎㠏㠐㠑㠒㠓㠔㠕㠖㠗㠘㠙㠚㠛㠜㠝㠞㠟㠠㠡㠢㠣㠤㠥㠦㠧㠨㠩㠪㠫㠬㠭㠮㠯㠰㠱㠲㠳㠴㠵㠶㠷㠸㠹㠺㠻㠼㠽㠾㠿㡀㡁㡂㡃㡄㡅㡆㡇㡈㡉㡊㡋㡌㡍㡎㡏㡐㡑㡒㡓㡔㡕㡖㡗㡘㡙㡚㡛㡜㡝㡞㡟㡠㡡㡢㡣㡤㡥㡦㡧㡨㡩㡪㡫㡬㡭㡮㡯㡰㡱㡲㡳㡴㡵㡶㡷㡸㡹㡺㡻㡼㡽㡾㡿㢀㢁㢂㢃㢄㢅㢆㢇㢈㢉㢊㢋㢌㢍㢎㢏㢐㢑㢒㢓㢔㢕㢖㢗㢘㢙㢚㢛㢜㢝㢞㢟㢠㢡㢢㢣㢤㢥㢦㢧㢨㢩㢪㢫㢬㢭㢮㢯㢰㢱㢲㢳㢴㢵㢶㢷㢸㢹㢺㢻㢼㢽㢾㢿㣀㣁㣂㣃㣄㣅㣆㣇㣈㣉㣊㣋㣌㣍㣎㣏㣐㣑㣒㣓㣔㣕㣖㣗㣘㣙㣚㣛㣜㣝㣞㣟㣠㣡㣢㣣㣤㣥㣦㣧㣨㣩㣪㣫㣬㣭㣮㣯㣰㣱㣲㣳㣴㣵㣶㣷㣸㣹㣺㣻㣼㣽㣾㣿㤀㤁㤂㤃㤄㤅㤆㤇㤈㤉㤊㤋㤌㤍㤎㤏㤐㤑㤒㤓㤔㤕㤖㤗㤘㤙㤚㤛㤜㤝㤞㤟㤠㤡㤢㤣㤤㤥㤦㤧㤨㤩㤪㤫㤬㤭㤮㤯㤰㤱㤲㤳㤴㤵㤶㤷㤸㤹㤺㤻㤼㤽㤾㤿㥀㥁㥂㥃㥄㥅㥆㥇㥈㥉㥊㥋㥌㥍㥎㥏㥐㥑㥒㥓㥔㥕㥖㥗㥘㥙㥚㥛㥜㥝㥞㥟㥠㥡㥢㥣㥤㥥㥦㥧㥨㥩㥪㥫㥬㥭㥮㥯㥰㥱㥲㥳㥴㥵㥶㥷㥸㥹㥺㥻㥼㥽㥾㥿㦀㦁㦂㦃㦄㦅㦆㦇㦈㦉㦊㦋㦌㦍㦎㦏㦐㦑㦒㦓㦔㦕㦖㦗㦘㦙㦚㦛㦜㦝㦞㦟㦠㦡㦢㦣㦤㦥㦦㦧㦨㦩㦪㦫㦬㦭㦮㦯㦰㦱㦲㦳㦴㦵㦶㦷㦸㦹㦺㦻㦼㦽㦾㦿㧀㧁㧂㧃㧄㧅㧆㧇㧈㧉㧊㧋㧌㧍㧎㧏㧐㧑㧒㧓㧔㧕㧖㧗㧘㧙㧚㧛㧜㧝㧞㧟㧠㧡㧢㧣㧤㧥㧦㧧㧨㧩㧪㧫㧬㧭㧮㧯㧰㧱㧲㧳㧴㧵㧶㧷㧸㧹㧺㧻㧼㧽㧾㧿㨀㨁㨂㨃㨄㨅㨆㨇㨈㨉㨊㨋㨌㨍㨎㨏㨐㨑㨒㨓㨔㨕㨖㨗㨘㨙㨚㨛㨜㨝㨞㨟㨠㨡㨢㨣㨤㨥㨦㨧㨨㨩㨪㨫㨬㨭㨮㨯㨰㨱㨲㨳㨴㨵㨶㨷㨸㨹㨺㨻㨼㨽㨾㨿㩀㩁㩂㩃㩄㩅㩆㩇㩈㩉㩊㩋㩌㩍㩎㩏㩐㩑㩒㩓㩔㩕㩖㩗㩘㩙㩚㩛㩜㩝㩞㩟㩠㩡㩢㩣㩤㩥㩦㩧㩨㩩㩪㩫㩬㩭㩮㩯㩰㩱㩲㩳㩴㩵㩶㩷㩸㩹㩺㩻㩼㩽㩾㩿㪀㪁㪂㪃㪄㪅㪆㪇㪈㪉㪊㪋㪌㪍㪎㪏㪐㪑㪒㪓㪔㪕㪖㪗㪘㪙㪚㪛㪜㪝㪞㪟㪠㪡㪢㪣㪤㪥㪦㪧㪨㪩㪪㪫㪬㪭㪮㪯㪰㪱㪲㪳㪴㪵㪶㪷㪸㪹㪺㪻㪼㪽㪾㪿㫀㫁㫂㫃㫄㫅㫆㫇㫈㫉㫊㫋㫌㫍㫎㫏㫐㫑㫒㫓㫔㫕㫖㫗㫘㫙㫚㫛㫜㫝㫞㫟㫠㫡㫢㫣㫤㫥㫦㫧㫨㫩㫪㫫㫬㫭㫮㫯㫰㫱㫲㫳㫴㫵㫶㫷㫸㫹㫺㫻㫼㫽㫾㫿㬀㬁㬂㬃㬄㬅㬆㬇㬈㬉㬊㬋㬌㬍㬎㬏㬐㬑㬒㬓㬔㬕㬖㬗㬘㬙㬚㬛㬜㬝㬞㬟㬠㬡㬢㬣㬤㬥㬦㬧㬨㬩㬪㬫㬬㬭㬮㬯㬰㬱㬲㬳㬴㬵㬶㬷㬸㬹㬺㬻㬼㬽㬾㬿㭀㭁㭂㭃㭄㭅㭆㭇㭈㭉㭊㭋㭌㭍㭎㭏㭐㭑㭒㭓㭔㭕㭖㭗㭘㭙㭚㭛㭜㭝㭞㭟㭠㭡㭢㭣㭤㭥㭦㭧㭨㭩㭪㭫㭬㭭㭮㭯㭰㭱㭲㭳㭴㭵㭶㭷㭸㭹㭺㭻㭼㭽㭾㭿㮀㮁㮂㮃㮄㮅㮆㮇㮈㮉㮊㮋㮌㮍㮎㮏㮐㮑㮒㮓㮔㮕㮖㮗㮘㮙㮚㮛㮜㮝㮞㮟㮠㮡㮢㮣㮤㮥㮦㮧㮨㮩㮪㮫㮬㮭㮮㮯㮰㮱㮲㮳㮴㮵㮶㮷㮸㮹㮺㮻㮼㮽㮾㮿㯀㯁㯂㯃㯄㯅㯆㯇㯈㯉㯊㯋㯌㯍㯎㯏㯐㯑㯒㯓㯔㯕㯖㯗㯘㯙㯚㯛㯜㯝㯞㯟㯠㯡㯢㯣㯤㯥㯦㯧㯨㯩㯪㯫㯬㯭㯮㯯㯰㯱㯲㯳㯴㯵㯶㯷㯸㯹㯺㯻㯼㯽㯾㯿㰀㰁㰂㰃㰄㰅㰆㰇㰈㰉㰊㰋㰌㰍㰎㰏㰐㰑㰒㰓㰔㰕㰖㰗㰘㰙㰚㰛㰜㰝㰞㰟㰠㰡㰢㰣㰤㰥㰦㰧㰨㰩㰪㰫㰬㰭㰮㰯㰰㰱㰲㰳㰴㰵㰶㰷㰸㰹㰺㰻㰼㰽㰾㰿㱀㱁㱂㱃㱄㱅㱆㱇㱈㱉㱊㱋㱌㱍㱎㱏㱐㱑㱒㱓㱔㱕㱖㱗㱘㱙㱚㱛㱜㱝㱞㱟㱠㱡㱢㱣㱤㱥㱦㱧㱨㱩㱪㱫㱬㱭㱮㱯㱰㱱㱲㱳㱴㱵㱶㱷㱸㱹㱺㱻㱼㱽㱾㱿㲀㲁㲂㲃㲄㲅㲆㲇㲈㲉㲊㲋㲌㲍㲎㲏㲐㲑㲒㲓㲔㲕㲖㲗㲘㲙㲚㲛㲜㲝㲞㲟㲠㲡㲢㲣㲤㲥㲦㲧㲨㲩㲪㲫㲬㲭㲮㲯㲰㲱㲲㲳㲴㲵㲶㲷㲸㲹㲺㲻㲼㲽㲾㲿㳀㳁㳂㳃㳄㳅㳆㳇㳈㳉㳊㳋㳌㳍㳎㳏㳐㳑㳒㳓㳔㳕㳖㳗㳘㳙㳚㳛㳜㳝㳞㳟㳠㳡㳢㳣㳤㳥㳦㳧㳨㳩㳪㳫㳬㳭㳮㳯㳰㳱㳲㳳㳴㳵㳶㳷㳸㳹㳺㳻㳼㳽㳾㳿㴀㴁㴂㴃㴄㴅㴆㴇㴈㴉㴊㴋㴌㴍㴎㴏㴐㴑㴒㴓㴔㴕㴖㴗㴘㴙㴚㴛㴜㴝㴞㴟㴠㴡㴢㴣㴤㴥㴦㴧㴨㴩㴪㴫㴬㴭㴮㴯㴰㴱㴲㴳㴴㴵㴶㴷㴸㴹㴺㴻㴼㴽㴾㴿㵀㵁㵂㵃㵄㵅㵆㵇㵈㵉㵊㵋㵌㵍㵎㵏㵐㵑㵒㵓㵔㵕㵖㵗㵘㵙㵚㵛㵜㵝㵞㵟㵠㵡㵢㵣㵤㵥㵦㵧㵨㵩㵪㵫㵬㵭㵮㵯㵰㵱㵲㵳㵴㵵㵶㵷㵸㵹㵺㵻㵼㵽㵾㵿㶀㶁㶂㶃㶄㶅㶆㶇㶈㶉㶊㶋㶌㶍㶎㶏㶐㶑㶒㶓㶔㶕㶖㶗㶘㶙㶚㶛㶜㶝㶞㶟㶠㶡㶢㶣㶤㶥㶦㶧㶨㶩㶪㶫㶬㶭㶮㶯㶰㶱㶲㶳㶴㶵㶶㶷㶸㶹㶺㶻㶼㶽㶾㶿㷀㷁㷂㷃㷄㷅㷆㷇㷈㷉㷊㷋㷌㷍㷎㷏㷐㷑㷒㷓㷔㷕㷖㷗㷘㷙㷚㷛㷜㷝㷞㷟㷠㷡㷢㷣㷤㷥㷦㷧㷨㷩㷪㷫㷬㷭㷮㷯㷰㷱㷲㷳㷴㷵㷶㷷㷸㷹㷺㷻㷼㷽㷾㷿㸀㸁㸂㸃㸄㸅㸆㸇㸈㸉㸊㸋㸌㸍㸎㸏㸐㸑㸒㸓㸔㸕㸖㸗㸘㸙㸚㸛㸜㸝㸞㸟㸠㸡㸢㸣㸤㸥㸦㸧㸨㸩㸪㸫㸬㸭㸮㸯㸰㸱㸲㸳㸴㸵㸶㸷㸸㸹㸺㸻㸼㸽㸾㸿㹀㹁㹂㹃㹄㹅㹆㹇㹈㹉㹊㹋㹌㹍㹎㹏㹐㹑㹒㹓㹔㹕㹖㹗㹘㹙㹚㹛㹜㹝㹞㹟㹠㹡㹢㹣㹤㹥㹦㹧㹨㹩㹪㹫㹬㹭㹮㹯㹰㹱㹲㹳㹴㹵㹶㹷㹸㹹㹺㹻㹼㹽㹾㹿㺀㺁㺂㺃㺄㺅㺆㺇㺈㺉㺊㺋㺌㺍㺎㺏㺐㺑㺒㺓㺔㺕㺖㺗㺘㺙㺚㺛㺜㺝㺞㺟㺠㺡㺢㺣㺤㺥㺦㺧㺨㺩㺪㺫㺬㺭㺮㺯㺰㺱㺲㺳㺴㺵㺶㺷㺸㺹㺺㺻㺼㺽㺾㺿㻀㻁㻂㻃㻄㻅㻆㻇㻈㻉㻊㻋㻌㻍㻎㻏㻐㻑㻒㻓㻔㻕㻖㻗㻘㻙㻚㻛㻜㻝㻞㻟㻠㻡㻢㻣㻤㻥㻦㻧㻨㻩㻪㻫㻬㻭㻮㻯㻰㻱㻲㻳㻴㻵㻶㻷㻸㻹㻺㻻㻼㻽㻾㻿㼀㼁㼂㼃㼄㼅㼆㼇㼈㼉㼊㼋㼌㼍㼎㼏㼐㼑㼒㼓㼔㼕㼖㼗㼘㼙㼚㼛㼜㼝㼞㼟㼠㼡㼢㼣㼤㼥㼦㼧㼨㼩㼪㼫㼬㼭㼮㼯㼰㼱㼲㼳㼴㼵㼶㼷㼸㼹㼺㼻㼼㼽㼾㼿㽀㽁㽂㽃㽄㽅㽆㽇㽈㽉㽊㽋㽌㽍㽎㽏㽐㽑㽒㽓㽔㽕㽖㽗㽘㽙㽚㽛㽜㽝㽞㽟㽠㽡㽢㽣㽤㽥㽦㽧㽨㽩㽪㽫㽬㽭㽮㽯㽰㽱㽲㽳㽴㽵㽶㽷㽸㽹㽺㽻㽼㽽㽾㽿㾀㾁㾂㾃㾄㾅㾆㾇㾈㾉㾊㾋㾌㾍㾎㾏㾐㾑㾒㾓㾔㾕㾖㾗㾘㾙㾚㾛㾜㾝㾞㾟㾠㾡㾢㾣㾤㾥㾦㾧㾨㾩㾪㾫㾬㾭㾮㾯㾰㾱㾲㾳㾴㾵㾶㾷㾸㾹㾺㾻㾼㾽㾾㾿㿀㿁㿂㿃㿄㿅㿆㿇㿈㿉㿊㿋㿌㿍㿎㿏㿐㿑㿒㿓㿔㿕㿖㿗㿘㿙㿚㿛㿜㿝㿞㿟㿠㿡㿢㿣㿤㿥㿦㿧㿨㿩㿪㿫㿬㿭㿮㿯㿰㿱㿲㿳㿴㿵㿶㿷㿸㿹㿺㿻㿼㿽㿾㿿䀀䀁䀂䀃䀄䀅䀆䀇䀈䀉䀊䀋䀌䀍䀎䀏䀐䀑䀒䀓䀔䀕䀖䀗䀘䀙䀚䀛䀜䀝䀞䀟䀠䀡䀢䀣䀤䀥䀦䀧䀨䀩䀪䀫䀬䀭䀮䀯䀰䀱䀲䀳䀴䀵䀶䀷䀸䀹䀺䀻䀼䀽䀾䀿䁀䁁䁂䁃䁄䁅䁆䁇䁈䁉䁊䁋䁌䁍䁎䁏䁐䁑䁒䁓䁔䁕䁖䁗䁘䁙䁚䁛䁜䁝䁞䁟䁠䁡䁢䁣䁤䁥䁦䁧䁨䁩䁪䁫䁬䁭䁮䁯䁰䁱䁲䁳䁴䁵䁶䁷䁸䁹䁺䁻䁼䁽䁾䁿䂀䂁䂂䂃䂄䂅䂆䂇䂈䂉䂊䂋䂌䂍䂎䂏䂐䂑䂒䂓䂔䂕䂖䂗䂘䂙䂚䂛䂜䂝䂞䂟䂠䂡䂢䂣䂤䂥䂦䂧䂨䂩䂪䂫䂬䂭䂮䂯䂰䂱䂲䂳䂴䂵䂶䂷䂸䂹䂺䂻䂼䂽䂾䂿䃀䃁䃂䃃䃄䃅䃆䃇䃈䃉䃊䃋䃌䃍䃎䃏䃐䃑䃒䃓䃔䃕䃖䃗䃘䃙䃚䃛䃜䃝䃞䃟䃠䃡䃢䃣䃤䃥䃦䃧䃨䃩䃪䃫䃬䃭䃮䃯䃰䃱䃲䃳䃴䃵䃶䃷䃸䃹䃺䃻䃼䃽䃾䃿䄀䄁䄂䄃䄄䄅䄆䄇䄈䄉䄊䄋䄌䄍䄎䄏䄐䄑䄒䄓䄔䄕䄖䄗䄘䄙䄚䄛䄜䄝䄞䄟䄠䄡䄢䄣䄤䄥䄦䄧䄨䄩䄪䄫䄬䄭䄮䄯䄰䄱䄲䄳䄴䄵䄶䄷䄸䄹䄺䄻䄼䄽䄾䄿䅀䅁䅂䅃䅄䅅䅆䅇䅈䅉䅊䅋䅌䅍䅎䅏䅐䅑䅒䅓䅔䅕䅖䅗䅘䅙䅚䅛䅜䅝䅞䅟䅠䅡䅢䅣䅤䅥䅦䅧䅨䅩䅪䅫䅬䅭䅮䅯䅰䅱䅲䅳䅴䅵䅶䅷䅸䅹䅺䅻䅼䅽䅾䅿䆀䆁䆂䆃䆄䆅䆆䆇䆈䆉䆊䆋䆌䆍䆎䆏䆐䆑䆒䆓䆔䆕䆖䆗䆘䆙䆚䆛䆜䆝䆞䆟䆠䆡䆢䆣䆤䆥䆦䆧䆨䆩䆪䆫䆬䆭䆮䆯䆰䆱䆲䆳䆴䆵䆶䆷䆸䆹䆺䆻䆼䆽䆾䆿䇀䇁䇂䇃䇄䇅䇆䇇䇈䇉䇊䇋䇌䇍䇎䇏䇐䇑䇒䇓䇔䇕䇖䇗䇘䇙䇚䇛䇜䇝䇞䇟䇠䇡䇢䇣䇤䇥䇦䇧䇨䇩䇪䇫䇬䇭䇮䇯䇰䇱䇲䇳䇴䇵䇶䇷䇸䇹䇺䇻䇼䇽䇾䇿䈀䈁䈂䈃䈄䈅䈆䈇䈈䈉䈊䈋䈌䈍䈎䈏䈐䈑䈒䈓䈔䈕䈖䈗䈘䈙䈚䈛䈜䈝䈞䈟䈠䈡䈢䈣䈤䈥䈦䈧䈨䈩䈪䈫䈬䈭䈮䈯䈰䈱䈲䈳䈴䈵䈶䈷䈸䈹䈺䈻䈼䈽䈾䈿䉀䉁䉂䉃䉄䉅䉆䉇䉈䉉䉊䉋䉌䉍䉎䉏䉐䉑䉒䉓䉔䉕䉖䉗䉘䉙䉚䉛䉜䉝䉞䉟䉠䉡䉢䉣䉤䉥䉦䉧䉨䉩䉪䉫䉬䉭䉮䉯䉰䉱䉲䉳䉴䉵䉶䉷䉸䉹䉺䉻䉼䉽䉾䉿䊀䊁䊂䊃䊄䊅䊆䊇䊈䊉䊊䊋䊌䊍䊎䊏䊐䊑䊒䊓䊔䊕䊖䊗䊘䊙䊚䊛䊜䊝䊞䊟䊠䊡䊢䊣䊤䊥䊦䊧䊨䊩䊪䊫䊬䊭䊮䊯䊰䊱䊲䊳䊴䊵䊶䊷䊸䊹䊺䊻䊼䊽䊾䊿䋀䋁䋂䋃䋄䋅䋆䋇䋈䋉䋊䋋䋌䋍䋎䋏䋐䋑䋒䋓䋔䋕䋖䋗䋘䋙䋚䋛䋜䋝䋞䋟䋠䋡䋢䋣䋤䋥䋦䋧䋨䋩䋪䋫䋬䋭䋮䋯䋰䋱䋲䋳䋴䋵䋶䋷䋸䋹䋺䋻䋼䋽䋾䋿䌀䌁䌂䌃䌄䌅䌆䌇䌈䌉䌊䌋䌌䌍䌎䌏䌐䌑䌒䌓䌔䌕䌖䌗䌘䌙䌚䌛䌜䌝䌞䌟䌠䌡䌢䌣䌤䌥䌦䌧䌨䌩䌪䌫䌬䌭䌮䌯䌰䌱䌲䌳䌴䌵䌶䌷䌸䌹䌺䌻䌼䌽䌾䌿䍀䍁䍂䍃䍄䍅䍆䍇䍈䍉䍊䍋䍌䍍䍎䍏䍐䍑䍒䍓䍔䍕䍖䍗䍘䍙䍚䍛䍜䍝䍞䍟䍠䍡䍢䍣䍤䍥䍦䍧䍨䍩䍪䍫䍬䍭䍮䍯䍰䍱䍲䍳䍴䍵䍶䍷䍸䍹䍺䍻䍼䍽䍾䍿䎀䎁䎂䎃䎄䎅䎆䎇䎈䎉䎊䎋䎌䎍䎎䎏䎐䎑䎒䎓䎔䎕䎖䎗䎘䎙䎚䎛䎜䎝䎞䎟䎠䎡䎢䎣䎤䎥䎦䎧䎨䎩䎪䎫䎬䎭䎮䎯䎰䎱䎲䎳䎴䎵䎶䎷䎸䎹䎺䎻䎼䎽䎾䎿䏀䏁䏂䏃䏄䏅䏆䏇䏈䏉䏊䏋䏌䏍䏎䏏䏐䏑䏒䏓䏔䏕䏖䏗䏘䏙䏚䏛䏜䏝䏞䏟䏠䏡䏢䏣䏤䏥䏦䏧䏨䏩䏪䏫䏬䏭䏮䏯䏰䏱䏲䏳䏴䏵䏶䏷䏸䏹䏺䏻䏼䏽䏾䏿䐀䐁䐂䐃䐄䐅䐆䐇䐈䐉䐊䐋䐌䐍䐎䐏䐐䐑䐒䐓䐔䐕䐖䐗䐘䐙䐚䐛䐜䐝䐞䐟䐠䐡䐢䐣䐤䐥䐦䐧䐨䐩䐪䐫䐬䐭䐮䐯䐰䐱䐲䐳䐴䐵䐶䐷䐸䐹䐺䐻䐼䐽䐾䐿䑀䑁䑂䑃䑄䑅䑆䑇䑈䑉䑊䑋䑌䑍䑎䑏䑐䑑䑒䑓䑔䑕䑖䑗䑘䑙䑚䑛䑜䑝䑞䑟䑠䑡䑢䑣䑤䑥䑦䑧䑨䑩䑪䑫䑬䑭䑮䑯䑰䑱䑲䑳䑴䑵䑶䑷䑸䑹䑺䑻䑼䑽䑾䑿䒀䒁䒂䒃䒄䒅䒆䒇䒈䒉䒊䒋䒌䒍䒎䒏䒐䒑䒒䒓䒔䒕䒖䒗䒘䒙䒚䒛䒜䒝䒞䒟䒠䒡䒢䒣䒤䒥䒦䒧䒨䒩䒪䒫䒬䒭䒮䒯䒰䒱䒲䒳䒴䒵䒶䒷䒸䒹䒺䒻䒼䒽䒾䒿䓀䓁䓂䓃䓄䓅䓆䓇䓈䓉䓊䓋䓌䓍䓎䓏䓐䓑䓒䓓䓔䓕䓖䓗䓘䓙䓚䓛䓜䓝䓞䓟䓠䓡䓢䓣䓤䓥䓦䓧䓨䓩䓪䓫䓬䓭䓮䓯䓰䓱䓲䓳䓴䓵䓶䓷䓸䓹䓺䓻䓼䓽䓾䓿䔀䔁䔂䔃䔄䔅䔆䔇䔈䔉䔊䔋䔌䔍䔎䔏䔐䔑䔒䔓䔔䔕䔖䔗䔘䔙䔚䔛䔜䔝䔞䔟䔠䔡䔢䔣䔤䔥䔦䔧䔨䔩䔪䔫䔬䔭䔮䔯䔰䔱䔲䔳䔴䔵䔶䔷䔸䔹䔺䔻䔼䔽䔾䔿䕀䕁䕂䕃䕄䕅䕆䕇䕈䕉䕊䕋䕌䕍䕎䕏䕐䕑䕒䕓䕔䕕䕖䕗䕘䕙䕚䕛䕜䕝䕞䕟䕠䕡䕢䕣䕤䕥䕦䕧䕨䕩䕪䕫䕬䕭䕮䕯䕰䕱䕲䕳䕴䕵䕶䕷䕸䕹䕺䕻䕼䕽䕾䕿䖀䖁䖂䖃䖄䖅䖆䖇䖈䖉䖊䖋䖌䖍䖎䖏䖐䖑䖒䖓䖔䖕䖖䖗䖘䖙䖚䖛䖜䖝䖞䖟䖠䖡䖢䖣䖤䖥䖦䖧䖨䖩䖪䖫䖬䖭䖮䖯䖰䖱䖲䖳䖴䖵䖶䖷䖸䖹䖺䖻䖼䖽䖾䖿䗀䗁䗂䗃䗄䗅䗆䗇䗈䗉䗊䗋䗌䗍䗎䗏䗐䗑䗒䗓䗔䗕䗖䗗䗘䗙䗚䗛䗜䗝䗞䗟䗠䗡䗢䗣䗤䗥䗦䗧䗨䗩䗪䗫䗬䗭䗮䗯䗰䗱䗲䗳䗴䗵䗶䗷䗸䗹䗺䗻䗼䗽䗾䗿䘀䘁䘂䘃䘄䘅䘆䘇䘈䘉䘊䘋䘌䘍䘎䘏䘐䘑䘒䘓䘔䘕䘖䘗䘘䘙䘚䘛䘜䘝䘞䘟䘠䘡䘢䘣䘤䘥䘦䘧䘨䘩䘪䘫䘬䘭䘮䘯䘰䘱䘲䘳䘴䘵䘶䘷䘸䘹䘺䘻䘼䘽䘾䘿䙀䙁䙂䙃䙄䙅䙆䙇䙈䙉䙊䙋䙌䙍䙎䙏䙐䙑䙒䙓䙔䙕䙖䙗䙘䙙䙚䙛䙜䙝䙞䙟䙠䙡䙢䙣䙤䙥䙦䙧䙨䙩䙪䙫䙬䙭䙮䙯䙰䙱䙲䙳䙴䙵䙶䙷䙸䙹䙺䙻䙼䙽䙾䙿䚀䚁䚂䚃䚄䚅䚆䚇䚈䚉䚊䚋䚌䚍䚎䚏䚐䚑䚒䚓䚔䚕䚖䚗䚘䚙䚚䚛䚜䚝䚞䚟䚠䚡䚢䚣䚤䚥䚦䚧䚨䚩䚪䚫䚬䚭䚮䚯䚰䚱䚲䚳䚴䚵䚶䚷䚸䚹䚺䚻䚼䚽䚾䚿䛀䛁䛂䛃䛄䛅䛆䛇䛈䛉䛊䛋䛌䛍䛎䛏䛐䛑䛒䛓䛔䛕䛖䛗䛘䛙䛚䛛䛜䛝䛞䛟䛠䛡䛢䛣䛤䛥䛦䛧䛨䛩䛪䛫䛬䛭䛮䛯䛰䛱䛲䛳䛴䛵䛶䛷䛸䛹䛺䛻䛼䛽䛾䛿䜀䜁䜂䜃䜄䜅䜆䜇䜈䜉䜊䜋䜌䜍䜎䜏䜐䜑䜒䜓䜔䜕䜖䜗䜘䜙䜚䜛䜜䜝䜞䜟䜠䜡䜢䜣䜤䜥䜦䜧䜨䜩䜪䜫䜬䜭䜮䜯䜰䜱䜲䜳䜴䜵䜶䜷䜸䜹䜺䜻䜼䜽䜾䜿䝀䝁䝂䝃䝄䝅䝆䝇䝈䝉䝊䝋䝌䝍䝎䝏䝐䝑䝒䝓䝔䝕䝖䝗䝘䝙䝚䝛䝜䝝䝞䝟䝠䝡䝢䝣䝤䝥䝦䝧䝨䝩䝪䝫䝬䝭䝮䝯䝰䝱䝲䝳䝴䝵䝶䝷䝸䝹䝺䝻䝼䝽䝾䝿䞀䞁䞂䞃䞄䞅䞆䞇䞈䞉䞊䞋䞌䞍䞎䞏䞐䞑䞒䞓䞔䞕䞖䞗䞘䞙䞚䞛䞜䞝䞞䞟䞠䞡䞢䞣䞤䞥䞦䞧䞨䞩䞪䞫䞬䞭䞮䞯䞰䞱䞲䞳䞴䞵䞶䞷䞸䞹䞺䞻䞼䞽䞾䞿䟀䟁䟂䟃䟄䟅䟆䟇䟈䟉䟊䟋䟌䟍䟎䟏䟐䟑䟒䟓䟔䟕䟖䟗䟘䟙䟚䟛䟜䟝䟞䟟䟠䟡䟢䟣䟤䟥䟦䟧䟨䟩䟪䟫䟬䟭䟮䟯䟰䟱䟲䟳䟴䟵䟶䟷䟸䟹䟺䟻䟼䟽䟾䟿䠀䠁䠂䠃䠄䠅䠆䠇䠈䠉䠊䠋䠌䠍䠎䠏䠐䠑䠒䠓䠔䠕䠖䠗䠘䠙䠚䠛䠜䠝䠞䠟䠠䠡䠢䠣䠤䠥䠦䠧䠨䠩䠪䠫䠬䠭䠮䠯䠰䠱䠲䠳䠴䠵䠶䠷䠸䠹䠺䠻䠼䠽䠾䠿䡀䡁䡂䡃䡄䡅䡆䡇䡈䡉䡊䡋䡌䡍䡎䡏䡐䡑䡒䡓䡔䡕䡖䡗䡘䡙䡚䡛䡜䡝䡞䡟䡠䡡䡢䡣䡤䡥䡦䡧䡨䡩䡪䡫䡬䡭䡮䡯䡰䡱䡲䡳䡴䡵䡶䡷䡸䡹䡺䡻䡼䡽䡾䡿䢀䢁䢂䢃䢄䢅䢆䢇䢈䢉䢊䢋䢌䢍䢎䢏䢐䢑䢒䢓䢔䢕䢖䢗䢘䢙䢚䢛䢜䢝䢞䢟䢠䢡䢢䢣䢤䢥䢦䢧䢨䢩䢪䢫䢬䢭䢮䢯䢰䢱䢲䢳䢴䢵䢶䢷䢸䢹䢺䢻䢼䢽䢾䢿䣀䣁䣂䣃䣄䣅䣆䣇䣈䣉䣊䣋䣌䣍䣎䣏䣐䣑䣒䣓䣔䣕䣖䣗䣘䣙䣚䣛䣜䣝䣞䣟䣠䣡䣢䣣䣤䣥䣦䣧䣨䣩䣪䣫䣬䣭䣮䣯䣰䣱䣲䣳䣴䣵䣶䣷䣸䣹䣺䣻䣼䣽䣾䣿䤀䤁䤂䤃䤄䤅䤆䤇䤈䤉䤊䤋䤌䤍䤎䤏䤐䤑䤒䤓䤔䤕䤖䤗䤘䤙䤚䤛䤜䤝䤞䤟䤠䤡䤢䤣䤤䤥䤦䤧䤨䤩䤪䤫䤬䤭䤮䤯䤰䤱䤲䤳䤴䤵䤶䤷䤸䤹䤺䤻䤼䤽䤾䤿䥀䥁䥂䥃䥄䥅䥆䥇䥈䥉䥊䥋䥌䥍䥎䥏䥐䥑䥒䥓䥔䥕䥖䥗䥘䥙䥚䥛䥜䥝䥞䥟䥠䥡䥢䥣䥤䥥䥦䥧䥨䥩䥪䥫䥬䥭䥮䥯䥰䥱䥲䥳䥴䥵䥶䥷䥸䥹䥺䥻䥼䥽䥾䥿䦀䦁䦂䦃䦄䦅䦆䦇䦈䦉䦊䦋䦌䦍䦎䦏䦐䦑䦒䦓䦔䦕䦖䦗䦘䦙䦚䦛䦜䦝䦞䦟䦠䦡䦢䦣䦤䦥䦦䦧䦨䦩䦪䦫䦬䦭䦮䦯䦰䦱䦲䦳䦴䦵䦶䦷䦸䦹䦺䦻䦼䦽䦾䦿䧀䧁䧂䧃䧄䧅䧆䧇䧈䧉䧊䧋䧌䧍䧎䧏䧐䧑䧒䧓䧔䧕䧖䧗䧘䧙䧚䧛䧜䧝䧞䧟䧠䧡䧢䧣䧤䧥䧦䧧䧨䧩䧪䧫䧬䧭䧮䧯䧰䧱䧲䧳䧴䧵䧶䧷䧸䧹䧺䧻䧼䧽䧾䧿䨀䨁䨂䨃䨄䨅䨆䨇䨈䨉䨊䨋䨌䨍䨎䨏䨐䨑䨒䨓䨔䨕䨖䨗䨘䨙䨚䨛䨜䨝䨞䨟䨠䨡䨢䨣䨤䨥䨦䨧䨨䨩䨪䨫䨬䨭䨮䨯䨰䨱䨲䨳䨴䨵䨶䨷䨸䨹䨺䨻䨼䨽䨾䨿䩀䩁䩂䩃䩄䩅䩆䩇䩈䩉䩊䩋䩌䩍䩎䩏䩐䩑䩒䩓䩔䩕䩖䩗䩘䩙䩚䩛䩜䩝䩞䩟䩠䩡䩢䩣䩤䩥䩦䩧䩨䩩䩪䩫䩬䩭䩮䩯䩰䩱䩲䩳䩴䩵䩶䩷䩸䩹䩺䩻䩼䩽䩾䩿䪀䪁䪂䪃䪄䪅䪆䪇䪈䪉䪊䪋䪌䪍䪎䪏䪐䪑䪒䪓䪔䪕䪖䪗䪘䪙䪚䪛䪜䪝䪞䪟䪠䪡䪢䪣䪤䪥䪦䪧䪨䪩䪪䪫䪬䪭䪮䪯䪰䪱䪲䪳䪴䪵䪶䪷䪸䪹䪺䪻䪼䪽䪾䪿䫀䫁䫂䫃䫄䫅䫆䫇䫈䫉䫊䫋䫌䫍䫎䫏䫐䫑䫒䫓䫔䫕䫖䫗䫘䫙䫚䫛䫜䫝䫞䫟䫠䫡䫢䫣䫤䫥䫦䫧䫨䫩䫪䫫䫬䫭䫮䫯䫰䫱䫲䫳䫴䫵䫶䫷䫸䫹䫺䫻䫼䫽䫾䫿䬀䬁䬂䬃䬄䬅䬆䬇䬈䬉䬊䬋䬌䬍䬎䬏䬐䬑䬒䬓䬔䬕䬖䬗䬘䬙䬚䬛䬜䬝䬞䬟䬠䬡䬢䬣䬤䬥䬦䬧䬨䬩䬪䬫䬬䬭䬮䬯䬰䬱䬲䬳䬴䬵䬶䬷䬸䬹䬺䬻䬼䬽䬾䬿䭀䭁䭂䭃䭄䭅䭆䭇䭈䭉䭊䭋䭌䭍䭎䭏䭐䭑䭒䭓䭔䭕䭖䭗䭘䭙䭚䭛䭜䭝䭞䭟䭠䭡䭢䭣䭤䭥䭦䭧䭨䭩䭪䭫䭬䭭䭮䭯䭰䭱䭲䭳䭴䭵䭶䭷䭸䭹䭺䭻䭼䭽䭾䭿䮀䮁䮂䮃䮄䮅䮆䮇䮈䮉䮊䮋䮌䮍䮎䮏䮐䮑䮒䮓䮔䮕䮖䮗䮘䮙䮚䮛䮜䮝䮞䮟䮠䮡䮢䮣䮤䮥䮦䮧䮨䮩䮪䮫䮬䮭䮮䮯䮰䮱䮲䮳䮴䮵䮶䮷䮸䮹䮺䮻䮼䮽䮾䮿䯀䯁䯂䯃䯄䯅䯆䯇䯈䯉䯊䯋䯌䯍䯎䯏䯐䯑䯒䯓䯔䯕䯖䯗䯘䯙䯚䯛䯜䯝䯞䯟䯠䯡䯢䯣䯤䯥䯦䯧䯨䯩䯪䯫䯬䯭䯮䯯䯰䯱䯲䯳䯴䯵䯶䯷䯸䯹䯺䯻䯼䯽䯾䯿䰀䰁䰂䰃䰄䰅䰆䰇䰈䰉䰊䰋䰌䰍䰎䰏䰐䰑䰒䰓䰔䰕䰖䰗䰘䰙䰚䰛䰜䰝䰞䰟䰠䰡䰢䰣䰤䰥䰦䰧䰨䰩䰪䰫䰬䰭䰮䰯䰰䰱䰲䰳䰴䰵䰶䰷䰸䰹䰺䰻䰼䰽䰾䰿䱀䱁䱂䱃䱄䱅䱆䱇䱈䱉䱊䱋䱌䱍䱎䱏䱐䱑䱒䱓䱔䱕䱖䱗䱘䱙䱚䱛䱜䱝䱞䱟䱠䱡䱢䱣䱤䱥䱦䱧䱨䱩䱪䱫䱬䱭䱮䱯䱰䱱䱲䱳䱴䱵䱶䱷䱸䱹䱺䱻䱼䱽䱾䱿䲀䲁䲂䲃䲄䲅䲆䲇䲈䲉䲊䲋䲌䲍䲎䲏䲐䲑䲒䲓䲔䲕䲖䲗䲘䲙䲚䲛䲜䲝䲞䲟䲠䲡䲢䲣䲤䲥䲦䲧䲨䲩䲪䲫䲬䲭䲮䲯䲰䲱䲲䲳䲴䲵䲶䲷䲸䲹䲺䲻䲼䲽䲾䲿䳀䳁䳂䳃䳄䳅䳆䳇䳈䳉䳊䳋䳌䳍䳎䳏䳐䳑䳒䳓䳔䳕䳖䳗䳘䳙䳚䳛䳜䳝䳞䳟䳠䳡䳢䳣䳤䳥䳦䳧䳨䳩䳪䳫䳬䳭䳮䳯䳰䳱䳲䳳䳴䳵䳶䳷䳸䳹䳺䳻䳼䳽䳾䳿䴀䴁䴂䴃䴄䴅䴆䴇䴈䴉䴊䴋䴌䴍䴎䴏䴐䴑䴒䴓䴔䴕䴖䴗䴘䴙䴚䴛䴜䴝䴞䴟䴠䴡䴢䴣䴤䴥䴦䴧䴨䴩䴪䴫䴬䴭䴮䴯䴰䴱䴲䴳䴴䴵䴶䴷䴸䴹䴺䴻䴼䴽䴾䴿䵀䵁䵂䵃䵄䵅䵆䵇䵈䵉䵊䵋䵌䵍䵎䵏䵐䵑䵒䵓䵔䵕䵖䵗䵘䵙䵚䵛䵜䵝䵞䵟䵠䵡䵢䵣䵤䵥䵦䵧䵨䵩䵪䵫䵬䵭䵮䵯䵰䵱䵲䵳䵴䵵䵶䵷䵸䵹䵺䵻䵼䵽䵾䵿䶀䶁䶂䶃䶄䶅䶆䶇䶈䶉䶊䶋䶌䶍䶎䶏䶐䶑䶒䶓䶔䶕䶖䶗䶘䶙䶚䶛䶜䶝䶞䶟䶠䶡䶢䶣䶤䶥䶦䶧䶨䶩䶪䶫䶬䶭䶮䶯䶰䶱䶲䶳䶴䶵䷀䷁䷂䷃䷄䷅䷆䷇䷈䷉䷊䷋䷌䷍䷎䷏䷐䷑䷒䷓䷔䷕䷖䷗䷘䷙䷚䷛䷜䷝䷞䷟䷠䷡䷢䷣䷤䷥䷦䷧䷨䷩䷪䷫䷬䷭䷮䷯䷰䷱䷲䷳䷴䷵䷶䷷䷸䷹䷺䷻䷼䷽䷾䷿一丁丂七丄丅丆万丈三上下丌不与丏丐丑丒专且丕世丗丘丙业丛东丝丞丟丠両丢丣两严並丧丨丩个丫丬中丮丯丰丱串丳临丵丶丷丸丹为主丼丽举丿乀乁乂乃乄久乆乇么义乊之乌乍乎乏乐乑乒乓乔乕乖乗乘乙乚乛乜九乞也习乡乢乣乤乥书乧乨乩乪乫乬乭乮乯买乱乲乳乴乵乶乷乸乹乺乻乼乽乾乿亀亁亂亃亄亅了亇予争亊事二亍于亏亐云互亓五井亖亗亘亙亚些亜亝亞亟亠亡亢亣交亥亦产亨亩亪享京亭亮亯亰亱亲亳亴亵亶亷亸亹人亻亼亽亾亿什仁仂仃仄仅仆仇仈仉今介仌仍从仏仐仑仒仓仔仕他仗付仙仚仛仜仝仞仟仠仡仢代令以仦仧仨仩仪仫们仭仮仯仰仱仲仳仴仵件价仸仹仺任仼份仾仿伀企伂伃伄伅伆伇伈伉伊伋伌伍伎伏伐休伒伓伔伕伖众优伙会伛伜伝伞伟传伡伢伣伤伥伦伧伨伩伪伫伬伭伮伯估伱伲伳伴伵伶伷伸伹伺伻似伽伾伿佀佁佂佃佄佅但佇佈佉佊佋佌位低住佐佑佒体佔何佖佗佘余佚佛作佝佞佟你佡佢佣佤佥佦佧佨佩佪佫佬佭佮佯佰佱佲佳佴併佶佷佸佹佺佻佼佽佾使侀侁侂侃侄侅來侇侈侉侊例侌侍侎侏侐侑侒侓侔侕侖侗侘侙侚供侜依侞侟侠価侢侣侤侥侦侧侨侩侪侫侬侭侮侯侰侱侲侳侴侵侶侷侸侹侺侻侼侽侾便俀俁係促俄俅俆俇俈俉俊俋俌俍俎俏俐俑俒俓俔俕俖俗俘俙俚俛俜保俞俟俠信俢俣俤俥俦俧俨俩俪俫俬俭修俯俰俱俲俳俴俵俶俷俸俹俺俻俼俽俾俿倀倁倂倃倄倅倆倇倈倉倊個倌倍倎倏倐們倒倓倔倕倖倗倘候倚倛倜倝倞借倠倡倢倣値倥倦倧倨倩倪倫倬倭倮倯倰倱倲倳倴倵倶倷倸倹债倻值倽倾倿偀偁偂偃偄偅偆假偈偉偊偋偌偍偎偏偐偑偒偓偔偕偖偗偘偙做偛停偝偞偟偠偡偢偣偤健偦偧偨偩偪偫偬偭偮偯偰偱偲偳側偵偶偷偸偹偺偻偼偽偾偿傀傁傂傃傄傅傆傇傈傉傊傋傌傍傎傏傐傑傒傓傔傕傖傗傘備傚傛傜傝傞傟傠傡傢傣傤傥傦傧储傩傪傫催傭傮傯傰傱傲傳傴債傶傷傸傹傺傻傼傽傾傿僀僁僂僃僄僅僆僇僈僉僊僋僌働僎像僐僑僒僓僔僕僖僗僘僙僚僛僜僝僞僟僠僡僢僣僤僥僦僧僨僩僪僫僬僭僮僯僰僱僲僳僴僵僶僷僸價僺僻僼僽僾僿儀儁儂儃億儅儆儇儈儉儊儋儌儍儎儏儐儑儒儓儔儕儖儗儘儙儚儛儜儝儞償儠儡儢儣儤儥儦儧儨儩優儫儬儭儮儯儰儱儲儳儴儵儶儷儸儹儺儻儼儽儾儿兀允兂元兄充兆兇先光兊克兌免兎兏児兑兒兓兔兕兖兗兘兙党兛兜兝兞兟兠兡兢兣兤入兦內全兩兪八公六兮兯兰共兲关兴兵其具典兹兺养兼兽兾兿冀冁冂冃冄内円冇冈冉冊冋册再冎冏冐冑冒冓冔冕冖冗冘写冚军农冝冞冟冠冡冢冣冤冥冦冧冨冩冪冫冬冭冮冯冰冱冲决冴况冶冷冸冹冺冻冼冽冾冿净凁凂凃凄凅准凇凈凉凊凋凌凍凎减凐凑凒凓凔凕凖凗凘凙凚凛凜凝凞凟几凡凢凣凤凥処凧凨凩凪凫凬凭凮凯凰凱凲凳凴凵凶凷凸凹出击凼函凾凿刀刁刂刃刄刅分切刈刉刊刋刌刍刎刏刐刑划刓刔刕刖列刘则刚创刜初刞刟删刡刢刣判別刦刧刨利刪别刬刭刮刯到刱刲刳刴刵制刷券刹刺刻刼刽刾刿剀剁剂剃剄剅剆則剈剉削剋剌前剎剏剐剑剒剓剔剕剖剗剘剙剚剛剜剝剞剟剠剡剢剣剤剥剦剧剨剩剪剫剬剭剮副剰剱割剳剴創剶剷剸剹剺剻剼剽剾剿劀劁劂劃劄劅劆劇劈劉劊劋劌劍劎劏劐劑劒劓劔劕劖劗劘劙劚力劜劝办功加务劢劣劤劥劦劧动助努劫劬劭劮劯劰励劲劳労劵劶劷劸効劺劻劼劽劾势勀勁勂勃勄勅勆勇勈勉勊勋勌勍勎勏勐勑勒勓勔動勖勗勘務勚勛勜勝勞募勠勡勢勣勤勥勦勧勨勩勪勫勬勭勮勯勰勱勲勳勴勵勶勷勸勹勺勻勼勽勾勿匀匁匂匃匄包匆匇匈匉匊匋匌匍匎匏匐匑匒匓匔匕化北匘匙匚匛匜匝匞匟匠匡匢匣匤匥匦匧匨匩匪匫匬匭匮匯匰匱匲匳匴匵匶匷匸匹区医匼匽匾匿區十卂千卄卅卆升午卉半卋卌卍华协卐卑卒卓協单卖南単卙博卛卜卝卞卟占卡卢卣卤卥卦卧卨卩卪卫卬卭卮卯印危卲即却卵卶卷卸卹卺卻卼卽卾卿厀厁厂厃厄厅历厇厈厉厊压厌厍厎厏厐厑厒厓厔厕厖厗厘厙厚厛厜厝厞原厠厡厢厣厤厥厦厧厨厩厪厫厬厭厮厯厰厱厲厳厴厵厶厷厸厹厺去厼厽厾县叀叁参參叄叅叆叇又叉及友双反収叏叐发叒叓叔叕取受变叙叚叛叜叝叞叟叠叡叢口古句另叧叨叩只叫召叭叮可台叱史右叴叵叶号司叹叺叻叼叽叾叿吀吁吂吃各吅吆吇合吉吊吋同名后吏吐向吒吓吔吕吖吗吘吙吚君吜吝吞吟吠吡吢吣吤吥否吧吨吩吪含听吭吮启吰吱吲吳吴吵吶吷吸吹吺吻吼吽吾吿呀呁呂呃呄呅呆呇呈呉告呋呌呍呎呏呐呑呒呓呔呕呖呗员呙呚呛呜呝呞呟呠呡呢呣呤呥呦呧周呩呪呫呬呭呮呯呰呱呲味呴呵呶呷呸呹呺呻呼命呾呿咀咁咂咃咄咅咆咇咈咉咊咋和咍咎咏咐咑咒咓咔咕咖咗咘咙咚咛咜咝咞咟咠咡咢咣咤咥咦咧咨咩咪咫咬咭咮咯咰咱咲咳咴咵咶咷咸咹咺咻咼咽咾咿哀品哂哃哄哅哆哇哈哉哊哋哌响哎哏哐哑哒哓哔哕哖哗哘哙哚哛哜哝哞哟哠員哢哣哤哥哦哧哨哩哪哫哬哭哮哯哰哱哲哳哴哵哶哷哸哹哺哻哼哽哾哿唀唁唂唃唄唅唆唇唈唉唊唋唌唍唎唏唐唑唒唓唔唕唖唗唘唙唚唛唜唝唞唟唠唡唢唣唤唥唦唧唨唩唪唫唬唭售唯唰唱唲唳唴唵唶唷唸唹唺唻唼唽唾唿啀啁啂啃啄啅商啇啈啉啊啋啌啍啎問啐啑啒啓啔啕啖啗啘啙啚啛啜啝啞啟啠啡啢啣啤啥啦啧啨啩啪啫啬啭啮啯啰啱啲啳啴啵啶啷啸啹啺啻啼啽啾啿喀喁喂喃善喅喆喇喈喉喊喋喌喍喎喏喐喑喒喓喔喕喖喗喘喙喚喛喜喝喞喟喠喡喢喣喤喥喦喧喨喩喪喫喬喭單喯喰喱喲喳喴喵営喷喸喹喺喻喼喽喾喿嗀嗁嗂嗃嗄嗅嗆嗇嗈嗉嗊嗋嗌嗍嗎嗏嗐嗑嗒嗓嗔嗕嗖嗗嗘嗙嗚嗛嗜嗝嗞嗟嗠嗡嗢嗣嗤嗥嗦嗧嗨嗩嗪嗫嗬嗭嗮嗯嗰嗱嗲嗳嗴嗵嗶嗷嗸嗹嗺嗻嗼嗽嗾嗿嘀嘁嘂嘃嘄嘅嘆嘇嘈嘉嘊嘋嘌嘍嘎嘏嘐嘑嘒嘓嘔嘕嘖嘗嘘嘙嘚嘛嘜嘝嘞嘟嘠嘡嘢嘣嘤嘥嘦嘧嘨嘩嘪嘫嘬嘭嘮嘯嘰嘱嘲嘳嘴嘵嘶嘷嘸嘹嘺嘻嘼嘽嘾嘿噀噁噂噃噄噅噆噇噈噉噊噋噌噍噎噏噐噑噒噓噔噕噖噗噘噙噚噛噜噝噞噟噠噡噢噣噤噥噦噧器噩噪噫噬噭噮噯噰噱噲噳噴噵噶噷噸噹噺噻噼噽噾噿嚀嚁嚂嚃嚄嚅嚆嚇嚈嚉嚊嚋嚌嚍嚎嚏嚐嚑嚒嚓嚔嚕嚖嚗嚘嚙嚚嚛嚜嚝嚞嚟嚠嚡嚢嚣嚤嚥嚦嚧嚨嚩嚪嚫嚬嚭嚮嚯嚰嚱嚲嚳嚴嚵嚶嚷嚸嚹嚺嚻嚼嚽嚾嚿囀囁囂囃囄囅囆囇囈囉囊囋囌囍囎囏囐囑囒囓囔囕囖囗囘囙囚四囜囝回囟因囡团団囤囥囦囧囨囩囪囫囬园囮囯困囱囲図围囵囶囷囸囹固囻囼国图囿圀圁圂圃圄圅圆圇圈圉圊國圌圍圎圏圐圑園圓圔圕圖圗團圙圚圛圜圝圞土圠圡圢圣圤圥圦圧在圩圪圫圬圭圮圯地圱圲圳圴圵圶圷圸圹场圻圼圽圾圿址坁坂坃坄坅坆均坈坉坊坋坌坍坎坏坐坑坒坓坔坕坖块坘坙坚坛坜坝坞坟坠坡坢坣坤坥坦坧坨坩坪坫坬坭坮坯坰坱坲坳坴坵坶坷坸坹坺坻坼坽坾坿垀垁垂垃垄垅垆垇垈垉垊型垌垍垎垏垐垑垒垓垔垕垖垗垘垙垚垛垜垝垞垟垠垡垢垣垤垥垦垧垨垩垪垫垬垭垮垯垰垱垲垳垴垵垶垷垸垹垺垻垼垽垾垿埀埁埂埃埄埅埆埇埈埉埊埋埌埍城埏埐埑埒埓埔埕埖埗埘埙埚埛埜埝埞域埠埡埢埣埤埥埦埧埨埩埪埫埬埭埮埯埰埱埲埳埴埵埶執埸培基埻埼埽埾埿堀堁堂堃堄堅堆堇堈堉堊堋堌堍堎堏堐堑堒堓堔堕堖堗堘堙堚堛堜堝堞堟堠堡堢堣堤堥堦堧堨堩堪堫堬堭堮堯堰報堲堳場堵堶堷堸堹堺堻堼堽堾堿塀塁塂塃塄塅塆塇塈塉塊塋塌塍塎塏塐塑塒塓塔塕塖塗塘塙塚塛塜塝塞塟塠塡塢塣塤塥塦塧塨塩塪填塬塭塮塯塰塱塲塳塴塵塶塷塸塹塺塻塼塽塾塿墀墁墂境墄墅墆墇墈墉墊墋墌墍墎墏墐墑墒墓墔墕墖増墘墙墚墛墜墝增墟墠墡墢墣墤墥墦墧墨墩墪墫墬墭墮墯墰墱墲墳墴墵墶墷墸墹墺墻墼墽墾墿壀壁壂壃壄壅壆壇壈壉壊壋壌壍壎壏壐壑壒壓壔壕壖壗壘壙壚壛壜壝壞壟壠壡壢壣壤壥壦壧壨壩壪士壬壭壮壯声壱売壳壴壵壶壷壸壹壺壻壼壽壾壿夀夁夂夃处夅夆备夈変夊夋夌复夎夏夐夑夒夓夔夕外夗夘夙多夛夜夝夞够夠夡夢夣夤夥夦大夨天太夫夬夭央夯夰失夲夳头夵夶夷夸夹夺夻夼夽夾夿奀奁奂奃奄奅奆奇奈奉奊奋奌奍奎奏奐契奒奓奔奕奖套奘奙奚奛奜奝奞奟奠奡奢奣奤奥奦奧奨奩奪奫奬奭奮奯奰奱奲女奴奵奶奷奸她奺奻奼好奾奿妀妁如妃妄妅妆妇妈妉妊妋妌妍妎妏妐妑妒妓妔妕妖妗妘妙妚妛妜妝妞妟妠妡妢妣妤妥妦妧妨妩妪妫妬妭妮妯妰妱妲妳妴妵妶妷妸妹妺妻妼妽妾妿姀姁姂姃姄姅姆姇姈姉姊始姌姍姎姏姐姑姒姓委姕姖姗姘姙姚姛姜姝姞姟姠姡姢姣姤姥姦姧姨姩姪姫姬姭姮姯姰姱姲姳姴姵姶姷姸姹姺姻姼姽姾姿娀威娂娃娄娅娆娇娈娉娊娋娌娍娎娏娐娑娒娓娔娕娖娗娘娙娚娛娜娝娞娟娠娡娢娣娤娥娦娧娨娩娪娫娬娭娮娯娰娱娲娳娴娵娶娷娸娹娺娻娼娽娾娿婀婁婂婃婄婅婆婇婈婉婊婋婌婍婎婏婐婑婒婓婔婕婖婗婘婙婚婛婜婝婞婟婠婡婢婣婤婥婦婧婨婩婪婫婬婭婮婯婰婱婲婳婴婵婶婷婸婹婺婻婼婽婾婿媀媁媂媃媄媅媆媇媈媉媊媋媌媍媎媏媐媑媒媓媔媕媖媗媘媙媚媛媜媝媞媟媠媡媢媣媤媥媦媧媨媩媪媫媬媭媮媯媰媱媲媳媴媵媶媷媸媹媺媻媼媽媾媿嫀嫁嫂嫃嫄嫅嫆嫇嫈嫉嫊嫋嫌嫍嫎嫏嫐嫑嫒嫓嫔嫕嫖嫗嫘嫙嫚嫛嫜嫝嫞嫟嫠嫡嫢嫣嫤嫥嫦嫧嫨嫩嫪嫫嫬嫭嫮嫯嫰嫱嫲嫳嫴嫵嫶嫷嫸嫹嫺嫻嫼嫽嫾嫿嬀嬁嬂嬃嬄嬅嬆嬇嬈嬉嬊嬋嬌嬍嬎嬏嬐嬑嬒嬓嬔嬕嬖嬗嬘嬙嬚嬛嬜嬝嬞嬟嬠嬡嬢嬣嬤嬥嬦嬧嬨嬩嬪嬫嬬嬭嬮嬯嬰嬱嬲嬳嬴嬵嬶嬷嬸嬹嬺嬻嬼嬽嬾嬿孀孁孂孃孄孅孆孇孈孉孊孋孌孍孎孏子孑孒孓孔孕孖字存孙孚孛孜孝孞孟孠孡孢季孤孥学孧孨孩孪孫孬孭孮孯孰孱孲孳孴孵孶孷學孹孺孻孼孽孾孿宀宁宂它宄宅宆宇守安宊宋完宍宎宏宐宑宒宓宔宕宖宗官宙定宛宜宝实実宠审客宣室宥宦宧宨宩宪宫宬宭宮宯宰宱宲害宴宵家宷宸容宺宻宼宽宾宿寀寁寂寃寄寅密寇寈寉寊寋富寍寎寏寐寑寒寓寔寕寖寗寘寙寚寛寜寝寞察寠寡寢寣寤寥實寧寨審寪寫寬寭寮寯寰寱寲寳寴寵寶寷寸对寺寻导寽対寿尀封専尃射尅将將專尉尊尋尌對導小尐少尒尓尔尕尖尗尘尙尚尛尜尝尞尟尠尡尢尣尤尥尦尧尨尩尪尫尬尭尮尯尰就尲尳尴尵尶尷尸尹尺尻尼尽尾尿局屁层屃屄居屆屇屈屉届屋屌屍屎屏屐屑屒屓屔展屖屗屘屙屚屛屜屝属屟屠屡屢屣層履屦屧屨屩屪屫屬屭屮屯屰山屲屳屴屵屶屷屸屹屺屻屼屽屾屿岀岁岂岃岄岅岆岇岈岉岊岋岌岍岎岏岐岑岒岓岔岕岖岗岘岙岚岛岜岝岞岟岠岡岢岣岤岥岦岧岨岩岪岫岬岭岮岯岰岱岲岳岴岵岶岷岸岹岺岻岼岽岾岿峀峁峂峃峄峅峆峇峈峉峊峋峌峍峎峏峐峑峒峓峔峕峖峗峘峙峚峛峜峝峞峟峠峡峢峣峤峥峦峧峨峩峪峫峬峭峮峯峰峱峲峳峴峵島峷峸峹峺峻峼峽峾峿崀崁崂崃崄崅崆崇崈崉崊崋崌崍崎崏崐崑崒崓崔崕崖崗崘崙崚崛崜崝崞崟崠崡崢崣崤崥崦崧崨崩崪崫崬崭崮崯崰崱崲崳崴崵崶崷崸崹崺崻崼崽崾崿嵀嵁嵂嵃嵄嵅嵆嵇嵈嵉嵊嵋嵌嵍嵎嵏嵐嵑嵒嵓嵔嵕嵖嵗嵘嵙嵚嵛嵜嵝嵞嵟嵠嵡嵢嵣嵤嵥嵦嵧嵨嵩嵪嵫嵬嵭嵮嵯嵰嵱嵲嵳嵴嵵嵶嵷嵸嵹嵺嵻嵼嵽嵾嵿嶀嶁嶂嶃嶄嶅嶆嶇嶈嶉嶊嶋嶌嶍嶎嶏嶐嶑嶒嶓嶔嶕嶖嶗嶘嶙嶚嶛嶜嶝嶞嶟嶠嶡嶢嶣嶤嶥嶦嶧嶨嶩嶪嶫嶬嶭嶮嶯嶰嶱嶲嶳嶴嶵嶶嶷嶸嶹嶺嶻嶼嶽嶾嶿巀巁巂巃巄巅巆巇巈巉巊巋巌巍巎巏巐巑巒巓巔巕巖巗巘巙巚巛巜川州巟巠巡巢巣巤工左巧巨巩巪巫巬巭差巯巰己已巳巴巵巶巷巸巹巺巻巼巽巾巿帀币市布帄帅帆帇师帉帊帋希帍帎帏帐帑帒帓帔帕帖帗帘帙帚帛帜帝帞帟帠帡帢帣帤帥带帧帨帩帪師帬席帮帯帰帱帲帳帴帵帶帷常帹帺帻帼帽帾帿幀幁幂幃幄幅幆幇幈幉幊幋幌幍幎幏幐幑幒幓幔幕幖幗幘幙幚幛幜幝幞幟幠幡幢幣幤幥幦幧幨幩幪幫幬幭幮幯幰幱干平年幵并幷幸幹幺幻幼幽幾广庀庁庂広庄庅庆庇庈庉床庋庌庍庎序庐庑庒库应底庖店庘庙庚庛府庝庞废庠庡庢庣庤庥度座庨庩庪庫庬庭庮庯庰庱庲庳庴庵庶康庸庹庺庻庼庽庾庿廀廁廂廃廄廅廆廇廈廉廊廋廌廍廎廏廐廑廒廓廔廕廖廗廘廙廚廛廜廝廞廟廠廡廢廣廤廥廦廧廨廩廪廫廬廭廮廯廰廱廲廳廴廵延廷廸廹建廻廼廽廾廿开弁异弃弄弅弆弇弈弉弊弋弌弍弎式弐弑弒弓弔引弖弗弘弙弚弛弜弝弞弟张弡弢弣弤弥弦弧弨弩弪弫弬弭弮弯弰弱弲弳弴張弶強弸弹强弻弼弽弾弿彀彁彂彃彄彅彆彇彈彉彊彋彌彍彎彏彐彑归当彔录彖彗彘彙彚彛彜彝彞彟彠彡形彣彤彥彦彧彨彩彪彫彬彭彮彯彰影彲彳彴彵彶彷彸役彺彻彼彽彾彿往征徂徃径待徆徇很徉徊律後徍徎徏徐徑徒従徔徕徖得徘徙徚徛徜徝從徟徠御徢徣徤徥徦徧徨復循徫徬徭微徯徰徱徲徳徴徵徶德徸徹徺徻徼徽徾徿忀忁忂心忄必忆忇忈忉忊忋忌忍忎忏忐忑忒忓忔忕忖志忘忙忚忛応忝忞忟忠忡忢忣忤忥忦忧忨忩忪快忬忭忮忯忰忱忲忳忴念忶忷忸忹忺忻忼忽忾忿怀态怂怃怄怅怆怇怈怉怊怋怌怍怎怏怐怑怒怓怔怕怖怗怘怙怚怛怜思怞怟怠怡怢怣怤急怦性怨怩怪怫怬怭怮怯怰怱怲怳怴怵怶怷怸怹怺总怼怽怾怿恀恁恂恃恄恅恆恇恈恉恊恋恌恍恎恏恐恑恒恓恔恕恖恗恘恙恚恛恜恝恞恟恠恡恢恣恤恥恦恧恨恩恪恫恬恭恮息恰恱恲恳恴恵恶恷恸恹恺恻恼恽恾恿悀悁悂悃悄悅悆悇悈悉悊悋悌悍悎悏悐悑悒悓悔悕悖悗悘悙悚悛悜悝悞悟悠悡悢患悤悥悦悧您悩悪悫悬悭悮悯悰悱悲悳悴悵悶悷悸悹悺悻悼悽悾悿惀惁惂惃惄情惆惇惈惉惊惋惌惍惎惏惐惑惒惓惔惕惖惗惘惙惚惛惜惝惞惟惠惡惢惣惤惥惦惧惨惩惪惫惬惭惮惯惰惱惲想惴惵惶惷惸惹惺惻惼惽惾惿愀愁愂愃愄愅愆愇愈愉愊愋愌愍愎意愐愑愒愓愔愕愖愗愘愙愚愛愜愝愞感愠愡愢愣愤愥愦愧愨愩愪愫愬愭愮愯愰愱愲愳愴愵愶愷愸愹愺愻愼愽愾愿慀慁慂慃慄慅慆慇慈慉慊態慌慍慎慏慐慑慒慓慔慕慖慗慘慙慚慛慜慝慞慟慠慡慢慣慤慥慦慧慨慩慪慫慬慭慮慯慰慱慲慳慴慵慶慷慸慹慺慻慼慽慾慿憀憁憂憃憄憅憆憇憈憉憊憋憌憍憎憏憐憑憒憓憔憕憖憗憘憙憚憛憜憝憞憟憠憡憢憣憤憥憦憧憨憩憪憫憬憭憮憯憰憱憲憳憴憵憶憷憸憹憺憻憼憽憾憿懀懁懂懃懄懅懆懇懈應懊懋懌懍懎懏懐懑懒懓懔懕懖懗懘懙懚懛懜懝懞懟懠懡懢懣懤懥懦懧懨懩懪懫懬懭懮懯懰懱懲懳懴懵懶懷懸懹懺懻懼懽懾懿戀戁戂戃戄戅戆戇戈戉戊戋戌戍戎戏成我戒戓戔戕或戗战戙戚戛戜戝戞戟戠戡戢戣戤戥戦戧戨戩截戫戬戭戮戯戰戱戲戳戴戵戶户戸戹戺戻戼戽戾房所扁扂扃扄扅扆扇扈扉扊手扌才扎扏扐扑扒打扔払扖扗托扙扚扛扜扝扞扟扠扡扢扣扤扥扦执扨扩扪扫扬扭扮扯扰扱扲扳扴扵扶扷扸批扺扻扼扽找承技抁抂抃抄抅抆抇抈抉把抋抌抍抎抏抐抑抒抓抔投抖抗折抙抚抛抜抝択抟抠抡抢抣护报抦抧抨抩抪披抬抭抮抯抰抱抲抳抴抵抶抷抸抹抺抻押抽抾抿拀拁拂拃拄担拆拇拈拉拊拋拌拍拎拏拐拑拒拓拔拕拖拗拘拙拚招拜拝拞拟拠拡拢拣拤拥拦拧拨择拪拫括拭拮拯拰拱拲拳拴拵拶拷拸拹拺拻拼拽拾拿挀持挂挃挄挅挆指挈按挊挋挌挍挎挏挐挑挒挓挔挕挖挗挘挙挚挛挜挝挞挟挠挡挢挣挤挥挦挧挨挩挪挫挬挭挮振挰挱挲挳挴挵挶挷挸挹挺挻挼挽挾挿捀捁捂捃捄捅捆捇捈捉捊捋捌捍捎捏捐捑捒捓捔捕捖捗捘捙捚捛捜捝捞损捠捡换捣捤捥捦捧捨捩捪捫捬捭据捯捰捱捲捳捴捵捶捷捸捹捺捻捼捽捾捿掀掁掂掃掄掅掆掇授掉掊掋掌掍掎掏掐掑排掓掔掕掖掗掘掙掚掛掜掝掞掟掠採探掣掤接掦控推掩措掫掬掭掮掯掰掱掲掳掴掵掶掷掸掹掺掻掼掽掾掿揀揁揂揃揄揅揆揇揈揉揊揋揌揍揎描提揑插揓揔揕揖揗揘揙揚換揜揝揞揟揠握揢揣揤揥揦揧揨揩揪揫揬揭揮揯揰揱揲揳援揵揶揷揸揹揺揻揼揽揾揿搀搁搂搃搄搅搆搇搈搉搊搋搌損搎搏搐搑搒搓搔搕搖搗搘搙搚搛搜搝搞搟搠搡搢搣搤搥搦搧搨搩搪搫搬搭搮搯搰搱搲搳搴搵搶搷搸搹携搻搼搽搾搿摀摁摂摃摄摅摆摇摈摉摊摋摌摍摎摏摐摑摒摓摔摕摖摗摘摙摚摛摜摝摞摟摠摡摢摣摤摥摦摧摨摩摪摫摬摭摮摯摰摱摲摳摴摵摶摷摸摹摺摻摼摽摾摿撀撁撂撃撄撅撆撇撈撉撊撋撌撍撎撏撐撑撒撓撔撕撖撗撘撙撚撛撜撝撞撟撠撡撢撣撤撥撦撧撨撩撪撫撬播撮撯撰撱撲撳撴撵撶撷撸撹撺撻撼撽撾撿擀擁擂擃擄擅擆擇擈擉擊擋擌操擎擏擐擑擒擓擔擕擖擗擘擙據擛擜擝擞擟擠擡擢擣擤擥擦擧擨擩擪擫擬擭擮擯擰擱擲擳擴擵擶擷擸擹擺擻擼擽擾擿攀攁攂攃攄攅攆攇攈攉攊攋攌攍攎攏攐攑攒攓攔攕攖攗攘攙攚攛攜攝攞攟攠攡攢攣攤攥攦攧攨攩攪攫攬攭攮支攰攱攲攳攴攵收攷攸改攺攻攼攽放政敀敁敂敃敄故敆敇效敉敊敋敌敍敎敏敐救敒敓敔敕敖敗敘教敚敛敜敝敞敟敠敡敢散敤敥敦敧敨敩敪敫敬敭敮敯数敱敲敳整敵敶敷數敹敺敻敼敽敾敿斀斁斂斃斄斅斆文斈斉斊斋斌斍斎斏斐斑斒斓斔斕斖斗斘料斚斛斜斝斞斟斠斡斢斣斤斥斦斧斨斩斪斫斬断斮斯新斱斲斳斴斵斶斷斸方斺斻於施斾斿旀旁旂旃旄旅旆旇旈旉旊旋旌旍旎族旐旑旒旓旔旕旖旗旘旙旚旛旜旝旞旟无旡既旣旤日旦旧旨早旪旫旬旭旮旯旰旱旲旳旴旵时旷旸旹旺旻旼旽旾旿昀昁昂昃昄昅昆昇昈昉昊昋昌昍明昏昐昑昒易昔昕昖昗昘昙昚昛昜昝昞星映昡昢昣昤春昦昧昨昩昪昫昬昭昮是昰昱昲昳昴昵昶昷昸昹昺昻昼昽显昿晀晁時晃晄晅晆晇晈晉晊晋晌晍晎晏晐晑晒晓晔晕晖晗晘晙晚晛晜晝晞晟晠晡晢晣晤晥晦晧晨晩晪晫晬晭普景晰晱晲晳晴晵晶晷晸晹智晻晼晽晾晿暀暁暂暃暄暅暆暇暈暉暊暋暌暍暎暏暐暑暒暓暔暕暖暗暘暙暚暛暜暝暞暟暠暡暢暣暤暥暦暧暨暩暪暫暬暭暮暯暰暱暲暳暴暵暶暷暸暹暺暻暼暽暾暿曀曁曂曃曄曅曆曇曈曉曊曋曌曍曎曏曐曑曒曓曔曕曖曗曘曙曚曛曜曝曞曟曠曡曢曣曤曥曦曧曨曩曪曫曬曭曮曯曰曱曲曳更曵曶曷書曹曺曻曼曽曾替最朁朂會朄朅朆朇月有朊朋朌服朎朏朐朑朒朓朔朕朖朗朘朙朚望朜朝朞期朠朡朢朣朤朥朦朧木朩未末本札朮术朰朱朲朳朴朵朶朷朸朹机朻朼朽朾朿杀杁杂权杄杅杆杇杈杉杊杋杌杍李杏材村杒杓杔杕杖杗杘杙杚杛杜杝杞束杠条杢杣杤来杦杧杨杩杪杫杬杭杮杯杰東杲杳杴杵杶杷杸杹杺杻杼杽松板枀极枂枃构枅枆枇枈枉枊枋枌枍枎枏析枑枒枓枔枕枖林枘枙枚枛果枝枞枟枠枡枢枣枤枥枦枧枨枩枪枫枬枭枮枯枰枱枲枳枴枵架枷枸枹枺枻枼枽枾枿柀柁柂柃柄柅柆柇柈柉柊柋柌柍柎柏某柑柒染柔柕柖柗柘柙柚柛柜柝柞柟柠柡柢柣柤查柦柧柨柩柪柫柬柭柮柯柰柱柲柳柴柵柶柷柸柹柺査柼柽柾柿栀栁栂栃栄栅栆标栈栉栊栋栌栍栎栏栐树栒栓栔栕栖栗栘栙栚栛栜栝栞栟栠校栢栣栤栥栦栧栨栩株栫栬栭栮栯栰栱栲栳栴栵栶样核根栺栻格栽栾栿桀桁桂桃桄桅框桇案桉桊桋桌桍桎桏桐桑桒桓桔桕桖桗桘桙桚桛桜桝桞桟桠桡桢档桤桥桦桧桨桩桪桫桬桭桮桯桰桱桲桳桴桵桶桷桸桹桺桻桼桽桾桿梀梁梂梃梄梅梆梇梈梉梊梋梌梍梎梏梐梑梒梓梔梕梖梗梘梙梚梛梜條梞梟梠梡梢梣梤梥梦梧梨梩梪梫梬梭梮梯械梱梲梳梴梵梶梷梸梹梺梻梼梽梾梿检棁棂棃棄棅棆棇棈棉棊棋棌棍棎棏棐棑棒棓棔棕棖棗棘棙棚棛棜棝棞棟棠棡棢棣棤棥棦棧棨棩棪棫棬棭森棯棰棱棲棳棴棵棶棷棸棹棺棻棼棽棾棿椀椁椂椃椄椅椆椇椈椉椊椋椌植椎椏椐椑椒椓椔椕椖椗椘椙椚椛検椝椞椟椠椡椢椣椤椥椦椧椨椩椪椫椬椭椮椯椰椱椲椳椴椵椶椷椸椹椺椻椼椽椾椿楀楁楂楃楄楅楆楇楈楉楊楋楌楍楎楏楐楑楒楓楔楕楖楗楘楙楚楛楜楝楞楟楠楡楢楣楤楥楦楧楨楩楪楫楬業楮楯楰楱楲楳楴極楶楷楸楹楺楻楼楽楾楿榀榁概榃榄榅榆榇榈榉榊榋榌榍榎榏榐榑榒榓榔榕榖榗榘榙榚榛榜榝榞榟榠榡榢榣榤榥榦榧榨榩榪榫榬榭榮榯榰榱榲榳榴榵榶榷榸榹榺榻榼榽榾榿槀槁槂槃槄槅槆槇槈槉槊構槌槍槎槏槐槑槒槓槔槕槖槗様槙槚槛槜槝槞槟槠槡槢槣槤槥槦槧槨槩槪槫槬槭槮槯槰槱槲槳槴槵槶槷槸槹槺槻槼槽槾槿樀樁樂樃樄樅樆樇樈樉樊樋樌樍樎樏樐樑樒樓樔樕樖樗樘標樚樛樜樝樞樟樠模樢樣樤樥樦樧樨権横樫樬樭樮樯樰樱樲樳樴樵樶樷樸樹樺樻樼樽樾樿橀橁橂橃橄橅橆橇橈橉橊橋橌橍橎橏橐橑橒橓橔橕橖橗橘橙橚橛橜橝橞機橠橡橢橣橤橥橦橧橨橩橪橫橬橭橮橯橰橱橲橳橴橵橶橷橸橹橺橻橼橽橾橿檀檁檂檃檄檅檆檇檈檉檊檋檌檍檎檏檐檑檒檓檔檕檖檗檘檙檚檛檜檝檞檟檠檡檢檣檤檥檦檧檨檩檪檫檬檭檮檯檰檱檲檳檴檵檶檷檸檹檺檻檼檽檾檿櫀櫁櫂櫃櫄櫅櫆櫇櫈櫉櫊櫋櫌櫍櫎櫏櫐櫑櫒櫓櫔櫕櫖櫗櫘櫙櫚櫛櫜櫝櫞櫟櫠櫡櫢櫣櫤櫥櫦櫧櫨櫩櫪櫫櫬櫭櫮櫯櫰櫱櫲櫳櫴櫵櫶櫷櫸櫹櫺櫻櫼櫽櫾櫿欀欁欂欃欄欅欆欇欈欉權欋欌欍欎欏欐欑欒欓欔欕欖欗欘欙欚欛欜欝欞欟欠次欢欣欤欥欦欧欨欩欪欫欬欭欮欯欰欱欲欳欴欵欶欷欸欹欺欻欼欽款欿歀歁歂歃歄歅歆歇歈歉歊歋歌歍歎歏歐歑歒歓歔歕歖歗歘歙歚歛歜歝歞歟歠歡止正此步武歧歨歩歪歫歬歭歮歯歰歱歲歳歴歵歶歷歸歹歺死歼歽歾歿殀殁殂殃殄殅殆殇殈殉殊残殌殍殎殏殐殑殒殓殔殕殖殗殘殙殚殛殜殝殞殟殠殡殢殣殤殥殦殧殨殩殪殫殬殭殮殯殰殱殲殳殴段殶殷殸殹殺殻殼殽殾殿毀毁毂毃毄毅毆毇毈毉毊毋毌母毎每毐毑毒毓比毕毖毗毘毙毚毛毜毝毞毟毠毡毢毣毤毥毦毧毨毩毪毫毬毭毮毯毰毱毲毳毴毵毶毷毸毹毺毻毼毽毾毿氀氁氂氃氄氅氆氇氈氉氊氋氌氍氎氏氐民氒氓气氕氖気氘氙氚氛氜氝氞氟氠氡氢氣氤氥氦氧氨氩氪氫氬氭氮氯氰氱氲氳水氵氶氷永氹氺氻氼氽氾氿汀汁求汃汄汅汆汇汈汉汊汋汌汍汎汏汐汑汒汓汔汕汖汗汘汙汚汛汜汝汞江池污汢汣汤汥汦汧汨汩汪汫汬汭汮汯汰汱汲汳汴汵汶汷汸汹決汻汼汽汾汿沀沁沂沃沄沅沆沇沈沉沊沋沌沍沎沏沐沑沒沓沔沕沖沗沘沙沚沛沜沝沞沟沠没沢沣沤沥沦沧沨沩沪沫沬沭沮沯沰沱沲河沴沵沶沷沸油沺治沼沽沾沿泀況泂泃泄泅泆泇泈泉泊泋泌泍泎泏泐泑泒泓泔法泖泗泘泙泚泛泜泝泞泟泠泡波泣泤泥泦泧注泩泪泫泬泭泮泯泰泱泲泳泴泵泶泷泸泹泺泻泼泽泾泿洀洁洂洃洄洅洆洇洈洉洊洋洌洍洎洏洐洑洒洓洔洕洖洗洘洙洚洛洜洝洞洟洠洡洢洣洤津洦洧洨洩洪洫洬洭洮洯洰洱洲洳洴洵洶洷洸洹洺活洼洽派洿浀流浂浃浄浅浆浇浈浉浊测浌浍济浏浐浑浒浓浔浕浖浗浘浙浚浛浜浝浞浟浠浡浢浣浤浥浦浧浨浩浪浫浬浭浮浯浰浱浲浳浴浵浶海浸浹浺浻浼浽浾浿涀涁涂涃涄涅涆涇消涉涊涋涌涍涎涏涐涑涒涓涔涕涖涗涘涙涚涛涜涝涞涟涠涡涢涣涤涥润涧涨涩涪涫涬涭涮涯涰涱液涳涴涵涶涷涸涹涺涻涼涽涾涿淀淁淂淃淄淅淆淇淈淉淊淋淌淍淎淏淐淑淒淓淔淕淖淗淘淙淚淛淜淝淞淟淠淡淢淣淤淥淦淧淨淩淪淫淬淭淮淯淰深淲淳淴淵淶混淸淹淺添淼淽淾淿渀渁渂渃渄清渆渇済渉渊渋渌渍渎渏渐渑渒渓渔渕渖渗渘渙渚減渜渝渞渟渠渡渢渣渤渥渦渧渨温渪渫測渭渮港渰渱渲渳渴渵渶渷游渹渺渻渼渽渾渿湀湁湂湃湄湅湆湇湈湉湊湋湌湍湎湏湐湑湒湓湔湕湖湗湘湙湚湛湜湝湞湟湠湡湢湣湤湥湦湧湨湩湪湫湬湭湮湯湰湱湲湳湴湵湶湷湸湹湺湻湼湽湾湿満溁溂溃溄溅溆溇溈溉溊溋溌溍溎溏源溑溒溓溔溕準溗溘溙溚溛溜溝溞溟溠溡溢溣溤溥溦溧溨溩溪溫溬溭溮溯溰溱溲溳溴溵溶溷溸溹溺溻溼溽溾溿滀滁滂滃滄滅滆滇滈滉滊滋滌滍滎滏滐滑滒滓滔滕滖滗滘滙滚滛滜滝滞滟滠满滢滣滤滥滦滧滨滩滪滫滬滭滮滯滰滱滲滳滴滵滶滷滸滹滺滻滼滽滾滿漀漁漂漃漄漅漆漇漈漉漊漋漌漍漎漏漐漑漒漓演漕漖漗漘漙漚漛漜漝漞漟漠漡漢漣漤漥漦漧漨漩漪漫漬漭漮漯漰漱漲漳漴漵漶漷漸漹漺漻漼漽漾漿潀潁潂潃潄潅潆潇潈潉潊潋潌潍潎潏潐潑潒潓潔潕潖潗潘潙潚潛潜潝潞潟潠潡潢潣潤潥潦潧潨潩潪潫潬潭潮潯潰潱潲潳潴潵潶潷潸潹潺潻潼潽潾潿澀澁澂澃澄澅澆澇澈澉澊澋澌澍澎澏澐澑澒澓澔澕澖澗澘澙澚澛澜澝澞澟澠澡澢澣澤澥澦澧澨澩澪澫澬澭澮澯澰澱澲澳澴澵澶澷澸澹澺澻澼澽澾澿激濁濂濃濄濅濆濇濈濉濊濋濌濍濎濏濐濑濒濓濔濕濖濗濘濙濚濛濜濝濞濟濠濡濢濣濤濥濦濧濨濩濪濫濬濭濮濯濰濱濲濳濴濵濶濷濸濹濺濻濼濽濾濿瀀瀁瀂瀃瀄瀅瀆瀇瀈瀉瀊瀋瀌瀍瀎瀏瀐瀑瀒瀓瀔瀕瀖瀗瀘瀙瀚瀛瀜瀝瀞瀟瀠瀡瀢瀣瀤瀥瀦瀧瀨瀩瀪瀫瀬瀭瀮瀯瀰瀱瀲瀳瀴瀵瀶瀷瀸瀹瀺瀻瀼瀽瀾瀿灀灁灂灃灄灅灆灇灈灉灊灋灌灍灎灏灐灑灒灓灔灕灖灗灘灙灚灛灜灝灞灟灠灡灢灣灤灥灦灧灨灩灪火灬灭灮灯灰灱灲灳灴灵灶灷灸灹灺灻灼災灾灿炀炁炂炃炄炅炆炇炈炉炊炋炌炍炎炏炐炑炒炓炔炕炖炗炘炙炚炛炜炝炞炟炠炡炢炣炤炥炦炧炨炩炪炫炬炭炮炯炰炱炲炳炴炵炶炷炸点為炻炼炽炾炿烀烁烂烃烄烅烆烇烈烉烊烋烌烍烎烏烐烑烒烓烔烕烖烗烘烙烚烛烜烝烞烟烠烡烢烣烤烥烦烧烨烩烪烫烬热烮烯烰烱烲烳烴烵烶烷烸烹烺烻烼烽烾烿焀焁焂焃焄焅焆焇焈焉焊焋焌焍焎焏焐焑焒焓焔焕焖焗焘焙焚焛焜焝焞焟焠無焢焣焤焥焦焧焨焩焪焫焬焭焮焯焰焱焲焳焴焵然焷焸焹焺焻焼焽焾焿煀煁煂煃煄煅煆煇煈煉煊煋煌煍煎煏煐煑煒煓煔煕煖煗煘煙煚煛煜煝煞煟煠煡煢煣煤煥煦照煨煩煪煫煬煭煮煯煰煱煲煳煴煵煶煷煸煹煺煻煼煽煾煿熀熁熂熃熄熅熆熇熈熉熊熋熌熍熎熏熐熑熒熓熔熕熖熗熘熙熚熛熜熝熞熟熠熡熢熣熤熥熦熧熨熩熪熫熬熭熮熯熰熱熲熳熴熵熶熷熸熹熺熻熼熽熾熿燀燁燂燃燄燅燆燇燈燉燊燋燌燍燎燏燐燑燒燓燔燕燖燗燘燙燚燛燜燝燞營燠燡燢燣燤燥燦燧燨燩燪燫燬燭燮燯燰燱燲燳燴燵燶燷燸燹燺燻燼燽燾燿爀爁爂爃爄爅爆爇爈爉爊爋爌爍爎爏爐爑爒爓爔爕爖爗爘爙爚爛爜爝爞爟爠爡爢爣爤爥爦爧爨爩爪爫爬爭爮爯爰爱爲爳爴爵父爷爸爹爺爻爼爽爾爿牀牁牂牃牄牅牆片版牉牊牋牌牍牎牏牐牑牒牓牔牕牖牗牘牙牚牛牜牝牞牟牠牡牢牣牤牥牦牧牨物牪牫牬牭牮牯牰牱牲牳牴牵牶牷牸特牺牻牼牽牾牿犀犁犂犃犄犅犆犇犈犉犊犋犌犍犎犏犐犑犒犓犔犕犖犗犘犙犚犛犜犝犞犟犠犡犢犣犤犥犦犧犨犩犪犫犬犭犮犯犰犱犲犳犴犵状犷犸犹犺犻犼犽犾犿狀狁狂狃狄狅狆狇狈狉狊狋狌狍狎狏狐狑狒狓狔狕狖狗狘狙狚狛狜狝狞狟狠狡狢狣狤狥狦狧狨狩狪狫独狭狮狯狰狱狲狳狴狵狶狷狸狹狺狻狼狽狾狿猀猁猂猃猄猅猆猇猈猉猊猋猌猍猎猏猐猑猒猓猔猕猖猗猘猙猚猛猜猝猞猟猠猡猢猣猤猥猦猧猨猩猪猫猬猭献猯猰猱猲猳猴猵猶猷猸猹猺猻猼猽猾猿獀獁獂獃獄獅獆獇獈獉獊獋獌獍獎獏獐獑獒獓獔獕獖獗獘獙獚獛獜獝獞獟獠獡獢獣獤獥獦獧獨獩獪獫獬獭獮獯獰獱獲獳獴獵獶獷獸獹獺獻獼獽獾獿玀玁玂玃玄玅玆率玈玉玊王玌玍玎玏玐玑玒玓玔玕玖玗玘玙玚玛玜玝玞玟玠玡玢玣玤玥玦玧玨玩玪玫玬玭玮环现玱玲玳玴玵玶玷玸玹玺玻玼玽玾玿珀珁珂珃珄珅珆珇珈珉珊珋珌珍珎珏珐珑珒珓珔珕珖珗珘珙珚珛珜珝珞珟珠珡珢珣珤珥珦珧珨珩珪珫珬班珮珯珰珱珲珳珴珵珶珷珸珹珺珻珼珽現珿琀琁琂球琄琅理琇琈琉琊琋琌琍琎琏琐琑琒琓琔琕琖琗琘琙琚琛琜琝琞琟琠琡琢琣琤琥琦琧琨琩琪琫琬琭琮琯琰琱琲琳琴琵琶琷琸琹琺琻琼琽琾琿瑀瑁瑂瑃瑄瑅瑆瑇瑈瑉瑊瑋瑌瑍瑎瑏瑐瑑瑒瑓瑔瑕瑖瑗瑘瑙瑚瑛瑜瑝瑞瑟瑠瑡瑢瑣瑤瑥瑦瑧瑨瑩瑪瑫瑬瑭瑮瑯瑰瑱瑲瑳瑴瑵瑶瑷瑸瑹瑺瑻瑼瑽瑾瑿璀璁璂璃璄璅璆璇璈璉璊璋璌璍璎璏璐璑璒璓璔璕璖璗璘璙璚璛璜璝璞璟璠璡璢璣璤璥璦璧璨璩璪璫璬璭璮璯環璱璲璳璴璵璶璷璸璹璺璻璼璽璾璿瓀瓁瓂瓃瓄瓅瓆瓇瓈瓉瓊瓋瓌瓍瓎瓏瓐瓑瓒瓓瓔瓕瓖瓗瓘瓙瓚瓛瓜瓝瓞瓟瓠瓡瓢瓣瓤瓥瓦瓧瓨瓩瓪瓫瓬瓭瓮瓯瓰瓱瓲瓳瓴瓵瓶瓷瓸瓹瓺瓻瓼瓽瓾瓿甀甁甂甃甄甅甆甇甈甉甊甋甌甍甎甏甐甑甒甓甔甕甖甗甘甙甚甛甜甝甞生甠甡產産甤甥甦甧用甩甪甫甬甭甮甯田由甲申甴电甶男甸甹町画甼甽甾甿畀畁畂畃畄畅畆畇畈畉畊畋界畍畎畏畐畑畒畓畔畕畖畗畘留畚畛畜畝畞畟畠畡畢畣畤略畦畧畨畩番畫畬畭畮畯異畱畲畳畴畵當畷畸畹畺畻畼畽畾畿疀疁疂疃疄疅疆疇疈疉疊疋疌疍疎疏疐疑疒疓疔疕疖疗疘疙疚疛疜疝疞疟疠疡疢疣疤疥疦疧疨疩疪疫疬疭疮疯疰疱疲疳疴疵疶疷疸疹疺疻疼疽疾疿痀痁痂痃痄病痆症痈痉痊痋痌痍痎痏痐痑痒痓痔痕痖痗痘痙痚痛痜痝痞痟痠痡痢痣痤痥痦痧痨痩痪痫痬痭痮痯痰痱痲痳痴痵痶痷痸痹痺痻痼痽痾痿瘀瘁瘂瘃瘄瘅瘆瘇瘈瘉瘊瘋瘌瘍瘎瘏瘐瘑瘒瘓瘔瘕瘖瘗瘘瘙瘚瘛瘜瘝瘞瘟瘠瘡瘢瘣瘤瘥瘦瘧瘨瘩瘪瘫瘬瘭瘮瘯瘰瘱瘲瘳瘴瘵瘶瘷瘸瘹瘺瘻瘼瘽瘾瘿癀癁療癃癄癅癆癇癈癉癊癋癌癍癎癏癐癑癒癓癔癕癖癗癘癙癚癛癜癝癞癟癠癡癢癣癤癥癦癧癨癩癪癫癬癭癮癯癰癱癲癳癴癵癶癷癸癹発登發白百癿皀皁皂皃的皅皆皇皈皉皊皋皌皍皎皏皐皑皒皓皔皕皖皗皘皙皚皛皜皝皞皟皠皡皢皣皤皥皦皧皨皩皪皫皬皭皮皯皰皱皲皳皴皵皶皷皸皹皺皻皼皽皾皿盀盁盂盃盄盅盆盇盈盉益盋盌盍盎盏盐监盒盓盔盕盖盗盘盙盚盛盜盝盞盟盠盡盢監盤盥盦盧盨盩盪盫盬盭目盯盰盱盲盳直盵盶盷相盹盺盻盼盽盾盿眀省眂眃眄眅眆眇眈眉眊看県眍眎眏眐眑眒眓眔眕眖眗眘眙眚眛眜眝眞真眠眡眢眣眤眥眦眧眨眩眪眫眬眭眮眯眰眱眲眳眴眵眶眷眸眹眺眻眼眽眾眿着睁睂睃睄睅睆睇睈睉睊睋睌睍睎睏睐睑睒睓睔睕睖睗睘睙睚睛睜睝睞睟睠睡睢督睤睥睦睧睨睩睪睫睬睭睮睯睰睱睲睳睴睵睶睷睸睹睺睻睼睽睾睿瞀瞁瞂瞃瞄瞅瞆瞇瞈瞉瞊瞋瞌瞍瞎瞏瞐瞑瞒瞓瞔瞕瞖瞗瞘瞙瞚瞛瞜瞝瞞瞟瞠瞡瞢瞣瞤瞥瞦瞧瞨瞩瞪瞫瞬瞭瞮瞯瞰瞱瞲瞳瞴瞵瞶瞷瞸瞹瞺瞻瞼瞽瞾瞿矀矁矂矃矄矅矆矇矈矉矊矋矌矍矎矏矐矑矒矓矔矕矖矗矘矙矚矛矜矝矞矟矠矡矢矣矤知矦矧矨矩矪矫矬短矮矯矰矱矲石矴矵矶矷矸矹矺矻矼矽矾矿砀码砂砃砄砅砆砇砈砉砊砋砌砍砎砏砐砑砒砓研砕砖砗砘砙砚砛砜砝砞砟砠砡砢砣砤砥砦砧砨砩砪砫砬砭砮砯砰砱砲砳破砵砶砷砸砹砺砻砼砽砾砿础硁硂硃硄硅硆硇硈硉硊硋硌硍硎硏硐硑硒硓硔硕硖硗硘硙硚硛硜硝硞硟硠硡硢硣硤硥硦硧硨硩硪硫硬硭确硯硰硱硲硳硴硵硶硷硸硹硺硻硼硽硾硿碀碁碂碃碄碅碆碇碈碉碊碋碌碍碎碏碐碑碒碓碔碕碖碗碘碙碚碛碜碝碞碟碠碡碢碣碤碥碦碧碨碩碪碫碬碭碮碯碰碱碲碳碴碵碶碷碸碹確碻碼碽碾碿磀磁磂磃磄磅磆磇磈磉磊磋磌磍磎磏磐磑磒磓磔磕磖磗磘磙磚磛磜磝磞磟磠磡磢磣磤磥磦磧磨磩磪磫磬磭磮磯磰磱磲磳磴磵磶磷磸磹磺磻磼磽磾磿礀礁礂礃礄礅礆礇礈礉礊礋礌礍礎礏礐礑礒礓礔礕礖礗礘礙礚礛礜礝礞礟礠礡礢礣礤礥礦礧礨礩礪礫礬礭礮礯礰礱礲礳礴礵礶礷礸礹示礻礼礽社礿祀祁祂祃祄祅祆祇祈祉祊祋祌祍祎祏祐祑祒祓祔祕祖祗祘祙祚祛祜祝神祟祠祡祢祣祤祥祦祧票祩祪祫祬祭祮祯祰祱祲祳祴祵祶祷祸祹祺祻祼祽祾祿禀禁禂禃禄禅禆禇禈禉禊禋禌禍禎福禐禑禒禓禔禕禖禗禘禙禚禛禜禝禞禟禠禡禢禣禤禥禦禧禨禩禪禫禬禭禮禯禰禱禲禳禴禵禶禷禸禹禺离禼禽禾禿秀私秂秃秄秅秆秇秈秉秊秋秌种秎秏秐科秒秓秔秕秖秗秘秙秚秛秜秝秞租秠秡秢秣秤秥秦秧秨秩秪秫秬秭秮积称秱秲秳秴秵秶秷秸秹秺移秼秽秾秿稀稁稂稃稄稅稆稇稈稉稊程稌稍税稏稐稑稒稓稔稕稖稗稘稙稚稛稜稝稞稟稠稡稢稣稤稥稦稧稨稩稪稫稬稭種稯稰稱稲稳稴稵稶稷稸稹稺稻稼稽稾稿穀穁穂穃穄穅穆穇穈穉穊穋穌積穎穏穐穑穒穓穔穕穖穗穘穙穚穛穜穝穞穟穠穡穢穣穤穥穦穧穨穩穪穫穬穭穮穯穰穱穲穳穴穵究穷穸穹空穻穼穽穾穿窀突窂窃窄窅窆窇窈窉窊窋窌窍窎窏窐窑窒窓窔窕窖窗窘窙窚窛窜窝窞窟窠窡窢窣窤窥窦窧窨窩窪窫窬窭窮窯窰窱窲窳窴窵窶窷窸窹窺窻窼窽窾窿竀竁竂竃竄竅竆竇竈竉竊立竌竍竎竏竐竑竒竓竔竕竖竗竘站竚竛竜竝竞竟章竡竢竣竤童竦竧竨竩竪竫竬竭竮端竰竱竲竳竴竵競竷竸竹竺竻竼竽竾竿笀笁笂笃笄笅笆笇笈笉笊笋笌笍笎笏笐笑笒笓笔笕笖笗笘笙笚笛笜笝笞笟笠笡笢笣笤笥符笧笨笩笪笫第笭笮笯笰笱笲笳笴笵笶笷笸笹笺笻笼笽笾笿筀筁筂筃筄筅筆筇筈等筊筋筌筍筎筏筐筑筒筓答筕策筗筘筙筚筛筜筝筞筟筠筡筢筣筤筥筦筧筨筩筪筫筬筭筮筯筰筱筲筳筴筵筶筷筸筹筺筻筼筽签筿简箁箂箃箄箅箆箇箈箉箊箋箌箍箎箏箐箑箒箓箔箕箖算箘箙箚箛箜箝箞箟箠管箢箣箤箥箦箧箨箩箪箫箬箭箮箯箰箱箲箳箴箵箶箷箸箹箺箻箼箽箾箿節篁篂篃範篅篆篇篈築篊篋篌篍篎篏篐篑篒篓篔篕篖篗篘篙篚篛篜篝篞篟篠篡篢篣篤篥篦篧篨篩篪篫篬篭篮篯篰篱篲篳篴篵篶篷篸篹篺篻篼篽篾篿簀簁簂簃簄簅簆簇簈簉簊簋簌簍簎簏簐簑簒簓簔簕簖簗簘簙簚簛簜簝簞簟簠簡簢簣簤簥簦簧簨簩簪簫簬簭簮簯簰簱簲簳簴簵簶簷簸簹簺簻簼簽簾簿籀籁籂籃籄籅籆籇籈籉籊籋籌籍籎籏籐籑籒籓籔籕籖籗籘籙籚籛籜籝籞籟籠籡籢籣籤籥籦籧籨籩籪籫籬籭籮籯籰籱籲米籴籵籶籷籸籹籺类籼籽籾籿粀粁粂粃粄粅粆粇粈粉粊粋粌粍粎粏粐粑粒粓粔粕粖粗粘粙粚粛粜粝粞粟粠粡粢粣粤粥粦粧粨粩粪粫粬粭粮粯粰粱粲粳粴粵粶粷粸粹粺粻粼粽精粿糀糁糂糃糄糅糆糇糈糉糊糋糌糍糎糏糐糑糒糓糔糕糖糗糘糙糚糛糜糝糞糟糠糡糢糣糤糥糦糧糨糩糪糫糬糭糮糯糰糱糲糳糴糵糶糷糸糹糺系糼糽糾糿紀紁紂紃約紅紆紇紈紉紊紋紌納紎紏紐紑紒紓純紕紖紗紘紙級紛紜紝紞紟素紡索紣紤紥紦紧紨紩紪紫紬紭紮累細紱紲紳紴紵紶紷紸紹紺紻紼紽紾紿絀絁終絃組絅絆絇絈絉絊絋経絍絎絏結絑絒絓絔絕絖絗絘絙絚絛絜絝絞絟絠絡絢絣絤絥給絧絨絩絪絫絬絭絮絯絰統絲絳絴絵絶絷絸絹絺絻絼絽絾絿綀綁綂綃綄綅綆綇綈綉綊綋綌綍綎綏綐綑綒經綔綕綖綗綘継続綛綜綝綞綟綠綡綢綣綤綥綦綧綨綩綪綫綬維綮綯綰綱網綳綴綵綶綷綸綹綺綻綼綽綾綿緀緁緂緃緄緅緆緇緈緉緊緋緌緍緎総緐緑緒緓緔緕緖緗緘緙線緛緜緝緞緟締緡緢緣緤緥緦緧編緩緪緫緬緭緮緯緰緱緲緳練緵緶緷緸緹緺緻緼緽緾緿縀縁縂縃縄縅縆縇縈縉縊縋縌縍縎縏縐縑縒縓縔縕縖縗縘縙縚縛縜縝縞縟縠縡縢縣縤縥縦縧縨縩縪縫縬縭縮縯縰縱縲縳縴縵縶縷縸縹縺縻縼總績縿繀繁繂繃繄繅繆繇繈繉繊繋繌繍繎繏繐繑繒繓織繕繖繗繘繙繚繛繜繝繞繟繠繡繢繣繤繥繦繧繨繩繪繫繬繭繮繯繰繱繲繳繴繵繶繷繸繹繺繻繼繽繾繿纀纁纂纃纄纅纆纇纈纉纊纋續纍纎纏纐纑纒纓纔纕纖纗纘纙纚纛纜纝纞纟纠纡红纣纤纥约级纨纩纪纫纬纭纮纯纰纱纲纳纴纵纶纷纸纹纺纻纼纽纾线绀绁绂练组绅细织终绉绊绋绌绍绎经绐绑绒结绔绕绖绗绘给绚绛络绝绞统绠绡绢绣绤绥绦继绨绩绪绫绬续绮绯绰绱绲绳维绵绶绷绸绹绺绻综绽绾绿缀缁缂缃缄缅缆缇缈缉缊缋缌缍缎缏缐缑缒缓缔缕编缗缘缙缚缛缜缝缞缟缠缡缢缣缤缥缦缧缨缩缪缫缬缭缮缯缰缱缲缳缴缵缶缷缸缹缺缻缼缽缾缿罀罁罂罃罄罅罆罇罈罉罊罋罌罍罎罏罐网罒罓罔罕罖罗罘罙罚罛罜罝罞罟罠罡罢罣罤罥罦罧罨罩罪罫罬罭置罯罰罱署罳罴罵罶罷罸罹罺罻罼罽罾罿羀羁羂羃羄羅羆羇羈羉羊羋羌羍美羏羐羑羒羓羔羕羖羗羘羙羚羛羜羝羞羟羠羡羢羣群羥羦羧羨義羪羫羬羭羮羯羰羱羲羳羴羵羶羷羸羹羺羻羼羽羾羿翀翁翂翃翄翅翆翇翈翉翊翋翌翍翎翏翐翑習翓翔翕翖翗翘翙翚翛翜翝翞翟翠翡翢翣翤翥翦翧翨翩翪翫翬翭翮翯翰翱翲翳翴翵翶翷翸翹翺翻翼翽翾翿耀老耂考耄者耆耇耈耉耊耋而耍耎耏耐耑耒耓耔耕耖耗耘耙耚耛耜耝耞耟耠耡耢耣耤耥耦耧耨耩耪耫耬耭耮耯耰耱耲耳耴耵耶耷耸耹耺耻耼耽耾耿聀聁聂聃聄聅聆聇聈聉聊聋职聍聎聏聐聑聒聓联聕聖聗聘聙聚聛聜聝聞聟聠聡聢聣聤聥聦聧聨聩聪聫聬聭聮聯聰聱聲聳聴聵聶職聸聹聺聻聼聽聾聿肀肁肂肃肄肅肆肇肈肉肊肋肌肍肎肏肐肑肒肓肔肕肖肗肘肙肚肛肜肝肞肟肠股肢肣肤肥肦肧肨肩肪肫肬肭肮肯肰肱育肳肴肵肶肷肸肹肺肻肼肽肾肿胀胁胂胃胄胅胆胇胈胉胊胋背胍胎胏胐胑胒胓胔胕胖胗胘胙胚胛胜胝胞胟胠胡胢胣胤胥胦胧胨胩胪胫胬胭胮胯胰胱胲胳胴胵胶胷胸胹胺胻胼能胾胿脀脁脂脃脄脅脆脇脈脉脊脋脌脍脎脏脐脑脒脓脔脕脖脗脘脙脚脛脜脝脞脟脠脡脢脣脤脥脦脧脨脩脪脫脬脭脮脯脰脱脲脳脴脵脶脷脸脹脺脻脼脽脾脿腀腁腂腃腄腅腆腇腈腉腊腋腌腍腎腏腐腑腒腓腔腕腖腗腘腙腚腛腜腝腞腟腠腡腢腣腤腥腦腧腨腩腪腫腬腭腮腯腰腱腲腳腴腵腶腷腸腹腺腻腼腽腾腿膀膁膂膃膄膅膆膇膈膉膊膋膌膍膎膏膐膑膒膓膔膕膖膗膘膙膚膛膜膝膞膟膠膡膢膣膤膥膦膧膨膩膪膫膬膭膮膯膰膱膲膳膴膵膶膷膸膹膺膻膼膽膾膿臀臁臂臃臄臅臆臇臈臉臊臋臌臍臎臏臐臑臒臓臔臕臖臗臘臙臚臛臜臝臞臟臠臡臢臣臤臥臦臧臨臩自臫臬臭臮臯臰臱臲至致臵臶臷臸臹臺臻臼臽臾臿舀舁舂舃舄舅舆與興舉舊舋舌舍舎舏舐舑舒舓舔舕舖舗舘舙舚舛舜舝舞舟舠舡舢舣舤舥舦舧舨舩航舫般舭舮舯舰舱舲舳舴舵舶舷舸船舺舻舼舽舾舿艀艁艂艃艄艅艆艇艈艉艊艋艌艍艎艏艐艑艒艓艔艕艖艗艘艙艚艛艜艝艞艟艠艡艢艣艤艥艦艧艨艩艪艫艬艭艮良艰艱色艳艴艵艶艷艸艹艺艻艼艽艾艿芀芁节芃芄芅芆芇芈芉芊芋芌芍芎芏芐芑芒芓芔芕芖芗芘芙芚芛芜芝芞芟芠芡芢芣芤芥芦芧芨芩芪芫芬芭芮芯芰花芲芳芴芵芶芷芸芹芺芻芼芽芾芿苀苁苂苃苄苅苆苇苈苉苊苋苌苍苎苏苐苑苒苓苔苕苖苗苘苙苚苛苜苝苞苟苠苡苢苣苤若苦苧苨苩苪苫苬苭苮苯苰英苲苳苴苵苶苷苸苹苺苻苼苽苾苿茀茁茂范茄茅茆茇茈茉茊茋茌茍茎茏茐茑茒茓茔茕茖茗茘茙茚茛茜茝茞茟茠茡茢茣茤茥茦茧茨茩茪茫茬茭茮茯茰茱茲茳茴茵茶茷茸茹茺茻茼茽茾茿荀荁荂荃荄荅荆荇荈草荊荋荌荍荎荏荐荑荒荓荔荕荖荗荘荙荚荛荜荝荞荟荠荡荢荣荤荥荦荧荨荩荪荫荬荭荮药荰荱荲荳荴荵荶荷荸荹荺荻荼荽荾荿莀莁莂莃莄莅莆莇莈莉莊莋莌莍莎莏莐莑莒莓莔莕莖莗莘莙莚莛莜莝莞莟莠莡莢莣莤莥莦莧莨莩莪莫莬莭莮莯莰莱莲莳莴莵莶获莸莹莺莻莼莽莾莿菀菁菂菃菄菅菆菇菈菉菊菋菌菍菎菏菐菑菒菓菔菕菖菗菘菙菚菛菜菝菞菟菠菡菢菣菤菥菦菧菨菩菪菫菬菭菮華菰菱菲菳菴菵菶菷菸菹菺菻菼菽菾菿萀萁萂萃萄萅萆萇萈萉萊萋萌萍萎萏萐萑萒萓萔萕萖萗萘萙萚萛萜萝萞萟萠萡萢萣萤营萦萧萨萩萪萫萬萭萮萯萰萱萲萳萴萵萶萷萸萹萺萻萼落萾萿葀葁葂葃葄葅葆葇葈葉葊葋葌葍葎葏葐葑葒葓葔葕葖著葘葙葚葛葜葝葞葟葠葡葢董葤葥葦葧葨葩葪葫葬葭葮葯葰葱葲葳葴葵葶葷葸葹葺葻葼葽葾葿蒀蒁蒂蒃蒄蒅蒆蒇蒈蒉蒊蒋蒌蒍蒎蒏蒐蒑蒒蒓蒔蒕蒖蒗蒘蒙蒚蒛蒜蒝蒞蒟蒠蒡蒢蒣蒤蒥蒦蒧蒨蒩蒪蒫蒬蒭蒮蒯蒰蒱蒲蒳蒴蒵蒶蒷蒸蒹蒺蒻蒼蒽蒾蒿蓀蓁蓂蓃蓄蓅蓆蓇蓈蓉蓊蓋蓌蓍蓎蓏蓐蓑蓒蓓蓔蓕蓖蓗蓘蓙蓚蓛蓜蓝蓞蓟蓠蓡蓢蓣蓤蓥蓦蓧蓨蓩蓪蓫蓬蓭蓮蓯蓰蓱蓲蓳蓴蓵蓶蓷蓸蓹蓺蓻蓼蓽蓾蓿蔀蔁蔂蔃蔄蔅蔆蔇蔈蔉蔊蔋蔌蔍蔎蔏蔐蔑蔒蔓蔔蔕蔖蔗蔘蔙蔚蔛蔜蔝蔞蔟蔠蔡蔢蔣蔤蔥蔦蔧蔨蔩蔪蔫蔬蔭蔮蔯蔰蔱蔲蔳蔴蔵蔶蔷蔸蔹蔺蔻蔼蔽蔾蔿蕀蕁蕂蕃蕄蕅蕆蕇蕈蕉蕊蕋蕌蕍蕎蕏蕐蕑蕒蕓蕔蕕蕖蕗蕘蕙蕚蕛蕜蕝蕞蕟蕠蕡蕢蕣蕤蕥蕦蕧蕨蕩蕪蕫蕬蕭蕮蕯蕰蕱蕲蕳蕴蕵蕶蕷蕸蕹蕺蕻蕼蕽蕾蕿薀薁薂薃薄薅薆薇薈薉薊薋薌薍薎薏薐薑薒薓薔薕薖薗薘薙薚薛薜薝薞薟薠薡薢薣薤薥薦薧薨薩薪薫薬薭薮薯薰薱薲薳薴薵薶薷薸薹薺薻薼薽薾薿藀藁藂藃藄藅藆藇藈藉藊藋藌藍藎藏藐藑藒藓藔藕藖藗藘藙藚藛藜藝藞藟藠藡藢藣藤藥藦藧藨藩藪藫藬藭藮藯藰藱藲藳藴藵藶藷藸藹藺藻藼藽藾藿蘀蘁蘂蘃蘄蘅蘆蘇蘈蘉蘊蘋蘌蘍蘎蘏蘐蘑蘒蘓蘔蘕蘖蘗蘘蘙蘚蘛蘜蘝蘞蘟蘠蘡蘢蘣蘤蘥蘦蘧蘨蘩蘪蘫蘬蘭蘮蘯蘰蘱蘲蘳蘴蘵蘶蘷蘸蘹蘺蘻蘼蘽蘾蘿虀虁虂虃虄虅虆虇虈虉虊虋虌虍虎虏虐虑虒虓虔處虖虗虘虙虚虛虜虝虞號虠虡虢虣虤虥虦虧虨虩虪虫虬虭虮虯虰虱虲虳虴虵虶虷虸虹虺虻虼虽虾虿蚀蚁蚂蚃蚄蚅蚆蚇蚈蚉蚊蚋蚌蚍蚎蚏蚐蚑蚒蚓蚔蚕蚖蚗蚘蚙蚚蚛蚜蚝蚞蚟蚠蚡蚢蚣蚤蚥蚦蚧蚨蚩蚪蚫蚬蚭蚮蚯蚰蚱蚲蚳蚴蚵蚶蚷蚸蚹蚺蚻蚼蚽蚾蚿蛀蛁蛂蛃蛄蛅蛆蛇蛈蛉蛊蛋蛌蛍蛎蛏蛐蛑蛒蛓蛔蛕蛖蛗蛘蛙蛚蛛蛜蛝蛞蛟蛠蛡蛢蛣蛤蛥蛦蛧蛨蛩蛪蛫蛬蛭蛮蛯蛰蛱蛲蛳蛴蛵蛶蛷蛸蛹蛺蛻蛼蛽蛾蛿蜀蜁蜂蜃蜄蜅蜆蜇蜈蜉蜊蜋蜌蜍蜎蜏蜐蜑蜒蜓蜔蜕蜖蜗蜘蜙蜚蜛蜜蜝蜞蜟蜠蜡蜢蜣蜤蜥蜦蜧蜨蜩蜪蜫蜬蜭蜮蜯蜰蜱蜲蜳蜴蜵蜶蜷蜸蜹蜺蜻蜼蜽蜾蜿蝀蝁蝂蝃蝄蝅蝆蝇蝈蝉蝊蝋蝌蝍蝎蝏蝐蝑蝒蝓蝔蝕蝖蝗蝘蝙蝚蝛蝜蝝蝞蝟蝠蝡蝢蝣蝤蝥蝦蝧蝨蝩蝪蝫蝬蝭蝮蝯蝰蝱蝲蝳蝴蝵蝶蝷蝸蝹蝺蝻蝼蝽蝾蝿螀螁螂螃螄螅螆螇螈螉螊螋螌融螎螏螐螑螒螓螔螕螖螗螘螙螚螛螜螝螞螟螠螡螢螣螤螥螦螧螨螩螪螫螬螭螮螯螰螱螲螳螴螵螶螷螸螹螺螻螼螽螾螿蟀蟁蟂蟃蟄蟅蟆蟇蟈蟉蟊蟋蟌蟍蟎蟏蟐蟑蟒蟓蟔蟕蟖蟗蟘蟙蟚蟛蟜蟝蟞蟟蟠蟡蟢蟣蟤蟥蟦蟧蟨蟩蟪蟫蟬蟭蟮蟯蟰蟱蟲蟳蟴蟵蟶蟷蟸蟹蟺蟻蟼蟽蟾蟿蠀蠁蠂蠃蠄蠅蠆蠇蠈蠉蠊蠋蠌蠍蠎蠏蠐蠑蠒蠓蠔蠕蠖蠗蠘蠙蠚蠛蠜蠝蠞蠟蠠蠡蠢蠣蠤蠥蠦蠧蠨蠩蠪蠫蠬蠭蠮蠯蠰蠱蠲蠳蠴蠵蠶蠷蠸蠹蠺蠻蠼蠽蠾蠿血衁衂衃衄衅衆衇衈衉衊衋行衍衎衏衐衑衒術衔衕衖街衘衙衚衛衜衝衞衟衠衡衢衣衤补衦衧表衩衪衫衬衭衮衯衰衱衲衳衴衵衶衷衸衹衺衻衼衽衾衿袀袁袂袃袄袅袆袇袈袉袊袋袌袍袎袏袐袑袒袓袔袕袖袗袘袙袚袛袜袝袞袟袠袡袢袣袤袥袦袧袨袩袪被袬袭袮袯袰袱袲袳袴袵袶袷袸袹袺袻袼袽袾袿裀裁裂裃裄装裆裇裈裉裊裋裌裍裎裏裐裑裒裓裔裕裖裗裘裙裚裛補裝裞裟裠裡裢裣裤裥裦裧裨裩裪裫裬裭裮裯裰裱裲裳裴裵裶裷裸裹裺裻裼製裾裿褀褁褂褃褄褅褆複褈褉褊褋褌褍褎褏褐褑褒褓褔褕褖褗褘褙褚褛褜褝褞褟褠褡褢褣褤褥褦褧褨褩褪褫褬褭褮褯褰褱褲褳褴褵褶褷褸褹褺褻褼褽褾褿襀襁襂襃襄襅襆襇襈襉襊襋襌襍襎襏襐襑襒襓襔襕襖襗襘襙襚襛襜襝襞襟襠襡襢襣襤襥襦襧襨襩襪襫襬襭襮襯襰襱襲襳襴襵襶襷襸襹襺襻襼襽襾西覀要覂覃覄覅覆覇覈覉覊見覌覍覎規覐覑覒覓覔覕視覗覘覙覚覛覜覝覞覟覠覡覢覣覤覥覦覧覨覩親覫覬覭覮覯覰覱覲観覴覵覶覷覸覹覺覻覼覽覾覿觀见观觃规觅视觇览觉觊觋觌觍觎觏觐觑角觓觔觕觖觗觘觙觚觛觜觝觞觟觠觡觢解觤觥触觧觨觩觪觫觬觭觮觯觰觱觲觳觴觵觶觷觸觹觺觻觼觽觾觿言訁訂訃訄訅訆訇計訉訊訋訌訍討訏訐訑訒訓訔訕訖託記訙訚訛訜訝訞訟訠訡訢訣訤訥訦訧訨訩訪訫訬設訮訯訰許訲訳訴訵訶訷訸訹診註証訽訾訿詀詁詂詃詄詅詆詇詈詉詊詋詌詍詎詏詐詑詒詓詔評詖詗詘詙詚詛詜詝詞詟詠詡詢詣詤詥試詧詨詩詪詫詬詭詮詯詰話該詳詴詵詶詷詸詹詺詻詼詽詾詿誀誁誂誃誄誅誆誇誈誉誊誋誌認誎誏誐誑誒誓誔誕誖誗誘誙誚誛誜誝語誟誠誡誢誣誤誥誦誧誨誩說誫説読誮誯誰誱課誳誴誵誶誷誸誹誺誻誼誽誾調諀諁諂諃諄諅諆談諈諉諊請諌諍諎諏諐諑諒諓諔諕論諗諘諙諚諛諜諝諞諟諠諡諢諣諤諥諦諧諨諩諪諫諬諭諮諯諰諱諲諳諴諵諶諷諸諹諺諻諼諽諾諿謀謁謂謃謄謅謆謇謈謉謊謋謌謍謎謏謐謑謒謓謔謕謖謗謘謙謚講謜謝謞謟謠謡謢謣謤謥謦謧謨謩謪謫謬謭謮謯謰謱謲謳謴謵謶謷謸謹謺謻謼謽謾謿譀譁譂譃譄譅譆譇譈證譊譋譌譍譎譏譐譑譒譓譔譕譖譗識譙譚譛譜譝譞譟譠譡譢譣譤譥警譧譨譩譪譫譬譭譮譯議譱譲譳譴譵譶護譸譹譺譻譼譽譾譿讀讁讂讃讄讅讆讇讈讉變讋讌讍讎讏讐讑讒讓讔讕讖讗讘讙讚讛讜讝讞讟讠计订讣认讥讦讧讨让讪讫讬训议讯记讱讲讳讴讵讶讷许讹论讻讼讽设访诀证诂诃评诅识诇诈诉诊诋诌词诎诏诐译诒诓诔试诖诗诘诙诚诛诜话诞诟诠诡询诣诤该详诧诨诩诪诫诬语诮误诰诱诲诳说诵诶请诸诹诺读诼诽课诿谀谁谂调谄谅谆谇谈谉谊谋谌谍谎谏谐谑谒谓谔谕谖谗谘谙谚谛谜谝谞谟谠谡谢谣谤谥谦谧谨谩谪谫谬谭谮谯谰谱谲谳谴谵谶谷谸谹谺谻谼谽谾谿豀豁豂豃豄豅豆豇豈豉豊豋豌豍豎豏豐豑豒豓豔豕豖豗豘豙豚豛豜豝豞豟豠象豢豣豤豥豦豧豨豩豪豫豬豭豮豯豰豱豲豳豴豵豶豷豸豹豺豻豼豽豾豿貀貁貂貃貄貅貆貇貈貉貊貋貌貍貎貏貐貑貒貓貔貕貖貗貘貙貚貛貜貝貞貟負財貢貣貤貥貦貧貨販貪貫責貭貮貯貰貱貲貳貴貵貶買貸貹貺費貼貽貾貿賀賁賂賃賄賅賆資賈賉賊賋賌賍賎賏賐賑賒賓賔賕賖賗賘賙賚賛賜賝賞賟賠賡賢賣賤賥賦賧賨賩質賫賬賭賮賯賰賱賲賳賴賵賶賷賸賹賺賻購賽賾賿贀贁贂贃贄贅贆贇贈贉贊贋贌贍贎贏贐贑贒贓贔贕贖贗贘贙贚贛贜贝贞负贠贡财责贤败账货质贩贪贫贬购贮贯贰贱贲贳贴贵贶贷贸费贺贻贼贽贾贿赀赁赂赃资赅赆赇赈赉赊赋赌赍赎赏赐赑赒赓赔赕赖赗赘赙赚赛赜赝赞赟赠赡赢赣赤赥赦赧赨赩赪赫赬赭赮赯走赱赲赳赴赵赶起赸赹赺赻赼赽赾赿趀趁趂趃趄超趆趇趈趉越趋趌趍趎趏趐趑趒趓趔趕趖趗趘趙趚趛趜趝趞趟趠趡趢趣趤趥趦趧趨趩趪趫趬趭趮趯趰趱趲足趴趵趶趷趸趹趺趻趼趽趾趿跀跁跂跃跄跅跆跇跈跉跊跋跌跍跎跏跐跑跒跓跔跕跖跗跘跙跚跛跜距跞跟跠跡跢跣跤跥跦跧跨跩跪跫跬跭跮路跰跱跲跳跴践跶跷跸跹跺跻跼跽跾跿踀踁踂踃踄踅踆踇踈踉踊踋踌踍踎踏踐踑踒踓踔踕踖踗踘踙踚踛踜踝踞踟踠踡踢踣踤踥踦踧踨踩踪踫踬踭踮踯踰踱踲踳踴踵踶踷踸踹踺踻踼踽踾踿蹀蹁蹂蹃蹄蹅蹆蹇蹈蹉蹊蹋蹌蹍蹎蹏蹐蹑蹒蹓蹔蹕蹖蹗蹘蹙蹚蹛蹜蹝蹞蹟蹠蹡蹢蹣蹤蹥蹦蹧蹨蹩蹪蹫蹬蹭蹮蹯蹰蹱蹲蹳蹴蹵蹶蹷蹸蹹蹺蹻蹼蹽蹾蹿躀躁躂躃躄躅躆躇躈躉躊躋躌躍躎躏躐躑躒躓躔躕躖躗躘躙躚躛躜躝躞躟躠躡躢躣躤躥躦躧躨躩躪身躬躭躮躯躰躱躲躳躴躵躶躷躸躹躺躻躼躽躾躿軀軁軂軃軄軅軆軇軈軉車軋軌軍軎軏軐軑軒軓軔軕軖軗軘軙軚軛軜軝軞軟軠軡転軣軤軥軦軧軨軩軪軫軬軭軮軯軰軱軲軳軴軵軶軷軸軹軺軻軼軽軾軿輀輁輂較輄輅輆輇輈載輊輋輌輍輎輏輐輑輒輓輔輕輖輗輘輙輚輛輜輝輞輟輠輡輢輣輤輥輦輧輨輩輪輫輬輭輮輯輰輱輲輳輴輵輶輷輸輹輺輻輼輽輾輿轀轁轂轃轄轅轆轇轈轉轊轋轌轍轎轏轐轑轒轓轔轕轖轗轘轙轚轛轜轝轞轟轠轡轢轣轤轥车轧轨轩轪轫转轭轮软轰轱轲轳轴轵轶轷轸轹轺轻轼载轾轿辀辁辂较辄辅辆辇辈辉辊辋辌辍辎辏辐辑辒输辔辕辖辗辘辙辚辛辜辝辞辟辠辡辢辣辤辥辦辧辨辩辪辫辬辭辮辯辰辱農辳辴辵辶辷辸边辺辻込辽达辿迀迁迂迃迄迅迆过迈迉迊迋迌迍迎迏运近迒迓返迕迖迗还这迚进远违连迟迠迡迢迣迤迥迦迧迨迩迪迫迬迭迮迯述迱迲迳迴迵迶迷迸迹迺迻迼追迾迿退送适逃逄逅逆逇逈选逊逋逌逍逎透逐逑递逓途逕逖逗逘這通逛逜逝逞速造逡逢連逤逥逦逧逨逩逪逫逬逭逮逯逰週進逳逴逵逶逷逸逹逺逻逼逽逾逿遀遁遂遃遄遅遆遇遈遉遊運遌遍過遏遐遑遒道達違遖遗遘遙遚遛遜遝遞遟遠遡遢遣遤遥遦遧遨適遪遫遬遭遮遯遰遱遲遳遴遵遶遷選遹遺遻遼遽遾避邀邁邂邃還邅邆邇邈邉邊邋邌邍邎邏邐邑邒邓邔邕邖邗邘邙邚邛邜邝邞邟邠邡邢那邤邥邦邧邨邩邪邫邬邭邮邯邰邱邲邳邴邵邶邷邸邹邺邻邼邽邾邿郀郁郂郃郄郅郆郇郈郉郊郋郌郍郎郏郐郑郒郓郔郕郖郗郘郙郚郛郜郝郞郟郠郡郢郣郤郥郦郧部郩郪郫郬郭郮郯郰郱郲郳郴郵郶郷郸郹郺郻郼都郾郿鄀鄁鄂鄃鄄鄅鄆鄇鄈鄉鄊鄋鄌鄍鄎鄏鄐鄑鄒鄓鄔鄕鄖鄗鄘鄙鄚鄛鄜鄝鄞鄟鄠鄡鄢鄣鄤鄥鄦鄧鄨鄩鄪鄫鄬鄭鄮鄯鄰鄱鄲鄳鄴鄵鄶鄷鄸鄹鄺鄻鄼鄽鄾鄿酀酁酂酃酄酅酆酇酈酉酊酋酌配酎酏酐酑酒酓酔酕酖酗酘酙酚酛酜酝酞酟酠酡酢酣酤酥酦酧酨酩酪酫酬酭酮酯酰酱酲酳酴酵酶酷酸酹酺酻酼酽酾酿醀醁醂醃醄醅醆醇醈醉醊醋醌醍醎醏醐醑醒醓醔醕醖醗醘醙醚醛醜醝醞醟醠醡醢醣醤醥醦醧醨醩醪醫醬醭醮醯醰醱醲醳醴醵醶醷醸醹醺醻醼醽醾醿釀釁釂釃釄釅釆采釈釉释釋里重野量釐金釒釓釔釕釖釗釘釙釚釛釜針釞釟釠釡釢釣釤釥釦釧釨釩釪釫釬釭釮釯釰釱釲釳釴釵釶釷釸釹釺釻釼釽釾釿鈀鈁鈂鈃鈄鈅鈆鈇鈈鈉鈊鈋鈌鈍鈎鈏鈐鈑鈒鈓鈔鈕鈖鈗鈘鈙鈚鈛鈜鈝鈞鈟鈠鈡鈢鈣鈤鈥鈦鈧鈨鈩鈪鈫鈬鈭鈮鈯鈰鈱鈲鈳鈴鈵鈶鈷鈸鈹鈺鈻鈼鈽鈾鈿鉀鉁鉂鉃鉄鉅鉆鉇鉈鉉鉊鉋鉌鉍鉎鉏鉐鉑鉒鉓鉔鉕鉖鉗鉘鉙鉚鉛鉜鉝鉞鉟鉠鉡鉢鉣鉤鉥鉦鉧鉨鉩鉪鉫鉬鉭鉮鉯鉰鉱鉲鉳鉴鉵鉶鉷鉸鉹鉺鉻鉼鉽鉾鉿銀銁銂銃銄銅銆銇銈銉銊銋銌銍銎銏銐銑銒銓銔銕銖銗銘銙銚銛銜銝銞銟銠銡銢銣銤銥銦銧銨銩銪銫銬銭銮銯銰銱銲銳銴銵銶銷銸銹銺銻銼銽銾銿鋀鋁鋂鋃鋄鋅鋆鋇鋈鋉鋊鋋鋌鋍鋎鋏鋐鋑鋒鋓鋔鋕鋖鋗鋘鋙鋚鋛鋜鋝鋞鋟鋠鋡鋢鋣鋤鋥鋦鋧鋨鋩鋪鋫鋬鋭鋮鋯鋰鋱鋲鋳鋴鋵鋶鋷鋸鋹鋺鋻鋼鋽鋾鋿錀錁錂錃錄錅錆錇錈錉錊錋錌錍錎錏錐錑錒錓錔錕錖錗錘錙錚錛錜錝錞錟錠錡錢錣錤錥錦錧錨錩錪錫錬錭錮錯錰錱録錳錴錵錶錷錸錹錺錻錼錽錾錿鍀鍁鍂鍃鍄鍅鍆鍇鍈鍉鍊鍋鍌鍍鍎鍏鍐鍑鍒鍓鍔鍕鍖鍗鍘鍙鍚鍛鍜鍝鍞鍟鍠鍡鍢鍣鍤鍥鍦鍧鍨鍩鍪鍫鍬鍭鍮鍯鍰鍱鍲鍳鍴鍵鍶鍷鍸鍹鍺鍻鍼鍽鍾鍿鎀鎁鎂鎃鎄鎅鎆鎇鎈鎉鎊鎋鎌鎍鎎鎏鎐鎑鎒鎓鎔鎕鎖鎗鎘鎙鎚鎛鎜鎝鎞鎟鎠鎡鎢鎣鎤鎥鎦鎧鎨鎩鎪鎫鎬鎭鎮鎯鎰鎱鎲鎳鎴鎵鎶鎷鎸鎹鎺鎻鎼鎽鎾鎿鏀鏁鏂鏃鏄鏅鏆鏇鏈鏉鏊鏋鏌鏍鏎鏏鏐鏑鏒鏓鏔鏕鏖鏗鏘鏙鏚鏛鏜鏝鏞鏟鏠鏡鏢鏣鏤鏥鏦鏧鏨鏩鏪鏫鏬鏭鏮鏯鏰鏱鏲鏳鏴鏵鏶鏷鏸鏹鏺鏻鏼鏽鏾鏿鐀鐁鐂鐃鐄鐅鐆鐇鐈鐉鐊鐋鐌鐍鐎鐏鐐鐑鐒鐓鐔鐕鐖鐗鐘鐙鐚鐛鐜鐝鐞鐟鐠鐡鐢鐣鐤鐥鐦鐧鐨鐩鐪鐫鐬鐭鐮鐯鐰鐱鐲鐳鐴鐵鐶鐷鐸鐹鐺鐻鐼鐽鐾鐿鑀鑁鑂鑃鑄鑅鑆鑇鑈鑉鑊鑋鑌鑍鑎鑏鑐鑑鑒鑓鑔鑕鑖鑗鑘鑙鑚鑛鑜鑝鑞鑟鑠鑡鑢鑣鑤鑥鑦鑧鑨鑩鑪鑫鑬鑭鑮鑯鑰鑱鑲鑳鑴鑵鑶鑷鑸鑹鑺鑻鑼鑽鑾鑿钀钁钂钃钄钅钆钇针钉钊钋钌钍钎钏钐钑钒钓钔钕钖钗钘钙钚钛钜钝钞钟钠钡钢钣钤钥钦钧钨钩钪钫钬钭钮钯钰钱钲钳钴钵钶钷钸钹钺钻钼钽钾钿铀铁铂铃铄铅铆铇铈铉铊铋铌铍铎铏铐铑铒铓铔铕铖铗铘铙铚铛铜铝铞铟铠铡铢铣铤铥铦铧铨铩铪铫铬铭铮铯铰铱铲铳铴铵银铷铸铹铺铻铼铽链铿销锁锂锃锄锅锆锇锈锉锊锋锌锍锎锏锐锑锒锓锔锕锖锗锘错锚锛锜锝锞锟锠锡锢锣锤锥锦锧锨锩锪锫锬锭键锯锰锱锲锳锴锵锶锷锸锹锺锻锼锽锾锿镀镁镂镃镄镅镆镇镈镉镊镋镌镍镎镏镐镑镒镓镔镕镖镗镘镙镚镛镜镝镞镟镠镡镢镣镤镥镦镧镨镩镪镫镬镭镮镯镰镱镲镳镴镵镶長镸镹镺镻镼镽镾长門閁閂閃閄閅閆閇閈閉閊開閌閍閎閏閐閑閒間閔閕閖閗閘閙閚閛閜閝閞閟閠閡関閣閤閥閦閧閨閩閪閫閬閭閮閯閰閱閲閳閴閵閶閷閸閹閺閻閼閽閾閿闀闁闂闃闄闅闆闇闈闉闊闋闌闍闎闏闐闑闒闓闔闕闖闗闘闙闚闛關闝闞闟闠闡闢闣闤闥闦闧门闩闪闫闬闭问闯闰闱闲闳间闵闶闷闸闹闺闻闼闽闾闿阀阁阂阃阄阅阆阇阈阉阊阋阌阍阎阏阐阑阒阓阔阕阖阗阘阙阚阛阜阝阞队阠阡阢阣阤阥阦阧阨阩阪阫阬阭阮阯阰阱防阳阴阵阶阷阸阹阺阻阼阽阾阿陀陁陂陃附际陆陇陈陉陊陋陌降陎陏限陑陒陓陔陕陖陗陘陙陚陛陜陝陞陟陠陡院陣除陥陦陧陨险陪陫陬陭陮陯陰陱陲陳陴陵陶陷陸陹険陻陼陽陾陿隀隁隂隃隄隅隆隇隈隉隊隋隌隍階随隐隑隒隓隔隕隖隗隘隙隚際障隝隞隟隠隡隢隣隤隥隦隧隨隩險隫隬隭隮隯隰隱隲隳隴隵隶隷隸隹隺隻隼隽难隿雀雁雂雃雄雅集雇雈雉雊雋雌雍雎雏雐雑雒雓雔雕雖雗雘雙雚雛雜雝雞雟雠雡離難雤雥雦雧雨雩雪雫雬雭雮雯雰雱雲雳雴雵零雷雸雹雺電雼雽雾雿需霁霂霃霄霅霆震霈霉霊霋霌霍霎霏霐霑霒霓霔霕霖霗霘霙霚霛霜霝霞霟霠霡霢霣霤霥霦霧霨霩霪霫霬霭霮霯霰霱露霳霴霵霶霷霸霹霺霻霼霽霾霿靀靁靂靃靄靅靆靇靈靉靊靋靌靍靎靏靐靑青靓靔靕靖靗靘静靚靛靜靝非靟靠靡面靣靤靥靦靧靨革靪靫靬靭靮靯靰靱靲靳靴靵靶靷靸靹靺靻靼靽靾靿鞀鞁鞂鞃鞄鞅鞆鞇鞈鞉鞊鞋鞌鞍鞎鞏鞐鞑鞒鞓鞔鞕鞖鞗鞘鞙鞚鞛鞜鞝鞞鞟鞠鞡鞢鞣鞤鞥鞦鞧鞨鞩鞪鞫鞬鞭鞮鞯鞰鞱鞲鞳鞴鞵鞶鞷鞸鞹鞺鞻鞼鞽鞾鞿韀韁韂韃韄韅韆韇韈韉韊韋韌韍韎韏韐韑韒韓韔韕韖韗韘韙韚韛韜韝韞韟韠韡韢韣韤韥韦韧韨韩韪韫韬韭韮韯韰韱韲音韴韵韶韷韸韹韺韻韼韽韾響頀頁頂頃頄項順頇須頉頊頋頌頍頎頏預頑頒頓頔頕頖頗領頙頚頛頜頝頞頟頠頡頢頣頤頥頦頧頨頩頪頫頬頭頮頯頰頱頲頳頴頵頶頷頸頹頺頻頼頽頾頿顀顁顂顃顄顅顆顇顈顉顊顋題額顎顏顐顑顒顓顔顕顖顗願顙顚顛顜顝類顟顠顡顢顣顤顥顦顧顨顩顪顫顬顭顮顯顰顱顲顳顴页顶顷顸项顺须顼顽顾顿颀颁颂颃预颅领颇颈颉颊颋颌颍颎颏颐频颒颓颔颕颖颗题颙颚颛颜额颞颟颠颡颢颣颤颥颦颧風颩颪颫颬颭颮颯颰颱颲颳颴颵颶颷颸颹颺颻颼颽颾颿飀飁飂飃飄飅飆飇飈飉飊飋飌飍风飏飐飑飒飓飔飕飖飗飘飙飚飛飜飝飞食飠飡飢飣飤飥飦飧飨飩飪飫飬飭飮飯飰飱飲飳飴飵飶飷飸飹飺飻飼飽飾飿餀餁餂餃餄餅餆餇餈餉養餋餌餍餎餏餐餑餒餓餔餕餖餗餘餙餚餛餜餝餞餟餠餡餢餣餤餥餦餧館餩餪餫餬餭餮餯餰餱餲餳餴餵餶餷餸餹餺餻餼餽餾餿饀饁饂饃饄饅饆饇饈饉饊饋饌饍饎饏饐饑饒饓饔饕饖饗饘饙饚饛饜饝饞饟饠饡饢饣饤饥饦饧饨饩饪饫饬饭饮饯饰饱饲饳饴饵饶饷饸饹饺饻饼饽饾饿馀馁馂馃馄馅馆馇馈馉馊馋馌馍馎馏馐馑馒馓馔馕首馗馘香馚馛馜馝馞馟馠馡馢馣馤馥馦馧馨馩馪馫馬馭馮馯馰馱馲馳馴馵馶馷馸馹馺馻馼馽馾馿駀駁駂駃駄駅駆駇駈駉駊駋駌駍駎駏駐駑駒駓駔駕駖駗駘駙駚駛駜駝駞駟駠駡駢駣駤駥駦駧駨駩駪駫駬駭駮駯駰駱駲駳駴駵駶駷駸駹駺駻駼駽駾駿騀騁騂騃騄騅騆騇騈騉騊騋騌騍騎騏騐騑騒験騔騕騖騗騘騙騚騛騜騝騞騟騠騡騢騣騤騥騦騧騨騩騪騫騬騭騮騯騰騱騲騳騴騵騶騷騸騹騺騻騼騽騾騿驀驁驂驃驄驅驆驇驈驉驊驋驌驍驎驏驐驑驒驓驔驕驖驗驘驙驚驛驜驝驞驟驠驡驢驣驤驥驦驧驨驩驪驫马驭驮驯驰驱驲驳驴驵驶驷驸驹驺驻驼驽驾驿骀骁骂骃骄骅骆骇骈骉骊骋验骍骎骏骐骑骒骓骔骕骖骗骘骙骚骛骜骝骞骟骠骡骢骣骤骥骦骧骨骩骪骫骬骭骮骯骰骱骲骳骴骵骶骷骸骹骺骻骼骽骾骿髀髁髂髃髄髅髆髇髈髉髊髋髌髍髎髏髐髑髒髓體髕髖髗高髙髚髛髜髝髞髟髠髡髢髣髤髥髦髧髨髩髪髫髬髭髮髯髰髱髲髳髴髵髶髷髸髹髺髻髼髽髾髿鬀鬁鬂鬃鬄鬅鬆鬇鬈鬉鬊鬋鬌鬍鬎鬏鬐鬑鬒鬓鬔鬕鬖鬗鬘鬙鬚鬛鬜鬝鬞鬟鬠鬡鬢鬣鬤鬥鬦鬧鬨鬩鬪鬫鬬鬭鬮鬯鬰鬱鬲鬳鬴鬵鬶鬷鬸鬹鬺鬻鬼鬽鬾鬿魀魁魂魃魄魅魆魇魈魉魊魋魌魍魎魏魐魑魒魓魔魕魖魗魘魙魚魛魜魝魞魟魠魡魢魣魤魥魦魧魨魩魪魫魬魭魮魯魰魱魲魳魴魵魶魷魸魹魺魻魼魽魾魿鮀鮁鮂鮃鮄鮅鮆鮇鮈鮉鮊鮋鮌鮍鮎鮏鮐鮑鮒鮓鮔鮕鮖鮗鮘鮙鮚鮛鮜鮝鮞鮟鮠鮡鮢鮣鮤鮥鮦鮧鮨鮩鮪鮫鮬鮭鮮鮯鮰鮱鮲鮳鮴鮵鮶鮷鮸鮹鮺鮻鮼鮽鮾鮿鯀鯁鯂鯃鯄鯅鯆鯇鯈鯉鯊鯋鯌鯍鯎鯏鯐鯑鯒鯓鯔鯕鯖鯗鯘鯙鯚鯛鯜鯝鯞鯟鯠鯡鯢鯣鯤鯥鯦鯧鯨鯩鯪鯫鯬鯭鯮鯯鯰鯱鯲鯳鯴鯵鯶鯷鯸鯹鯺鯻鯼鯽鯾鯿鰀鰁鰂鰃鰄鰅鰆鰇鰈鰉鰊鰋鰌鰍鰎鰏鰐鰑鰒鰓鰔鰕鰖鰗鰘鰙鰚鰛鰜鰝鰞鰟鰠鰡鰢鰣鰤鰥鰦鰧鰨鰩鰪鰫鰬鰭鰮鰯鰰鰱鰲鰳鰴鰵鰶鰷鰸鰹鰺鰻鰼鰽鰾鰿鱀鱁鱂鱃鱄鱅鱆鱇鱈鱉鱊鱋鱌鱍鱎鱏鱐鱑鱒鱓鱔鱕鱖鱗鱘鱙鱚鱛鱜鱝鱞鱟鱠鱡鱢鱣鱤鱥鱦鱧鱨鱩鱪鱫鱬鱭鱮鱯鱰鱱鱲鱳鱴鱵鱶鱷鱸鱹鱺鱻鱼鱽鱾鱿鲀鲁鲂鲃鲄鲅鲆鲇鲈鲉鲊鲋鲌鲍鲎鲏鲐鲑鲒鲓鲔鲕鲖鲗鲘鲙鲚鲛鲜鲝鲞鲟鲠鲡鲢鲣鲤鲥鲦鲧鲨鲩鲪鲫鲬鲭鲮鲯鲰鲱鲲鲳鲴鲵鲶鲷鲸鲹鲺鲻鲼鲽鲾鲿鳀鳁鳂鳃鳄鳅鳆鳇鳈鳉鳊鳋鳌鳍鳎鳏鳐鳑鳒鳓鳔鳕鳖鳗鳘鳙鳚鳛鳜鳝鳞鳟鳠鳡鳢鳣鳤鳥鳦鳧鳨鳩鳪鳫鳬鳭鳮鳯鳰鳱鳲鳳鳴鳵鳶鳷鳸鳹鳺鳻鳼鳽鳾鳿鴀鴁鴂鴃鴄鴅鴆鴇鴈鴉鴊鴋鴌鴍鴎鴏鴐鴑鴒鴓鴔鴕鴖鴗鴘鴙鴚鴛鴜鴝鴞鴟鴠鴡鴢鴣鴤鴥鴦鴧鴨鴩鴪鴫鴬鴭鴮鴯鴰鴱鴲鴳鴴鴵鴶鴷鴸鴹鴺鴻鴼鴽鴾鴿鵀鵁鵂鵃鵄鵅鵆鵇鵈鵉鵊鵋鵌鵍鵎鵏鵐鵑鵒鵓鵔鵕鵖鵗鵘鵙鵚鵛鵜鵝鵞鵟鵠鵡鵢鵣鵤鵥鵦鵧鵨鵩鵪鵫鵬鵭鵮鵯鵰鵱鵲鵳鵴鵵鵶鵷鵸鵹鵺鵻鵼鵽鵾鵿鶀鶁鶂鶃鶄鶅鶆鶇鶈鶉鶊鶋鶌鶍鶎鶏鶐鶑鶒鶓鶔鶕鶖鶗鶘鶙鶚鶛鶜鶝鶞鶟鶠鶡鶢鶣鶤鶥鶦鶧鶨鶩鶪鶫鶬鶭鶮鶯鶰鶱鶲鶳鶴鶵鶶鶷鶸鶹鶺鶻鶼鶽鶾鶿鷀鷁鷂鷃鷄鷅鷆鷇鷈鷉鷊鷋鷌鷍鷎鷏鷐鷑鷒鷓鷔鷕鷖鷗鷘鷙鷚鷛鷜鷝鷞鷟鷠鷡鷢鷣鷤鷥鷦鷧鷨鷩鷪鷫鷬鷭鷮鷯鷰鷱鷲鷳鷴鷵鷶鷷鷸鷹鷺鷻鷼鷽鷾鷿鸀鸁鸂鸃鸄鸅鸆鸇鸈鸉鸊鸋鸌鸍鸎鸏鸐鸑鸒鸓鸔鸕鸖鸗鸘鸙鸚鸛鸜鸝鸞鸟鸠鸡鸢鸣鸤鸥鸦鸧鸨鸩鸪鸫鸬鸭鸮鸯鸰鸱鸲鸳鸴鸵鸶鸷鸸鸹鸺鸻鸼鸽鸾鸿鹀鹁鹂鹃鹄鹅鹆鹇鹈鹉鹊鹋鹌鹍鹎鹏鹐鹑鹒鹓鹔鹕鹖鹗鹘鹙鹚鹛鹜鹝鹞鹟鹠鹡鹢鹣鹤鹥鹦鹧鹨鹩鹪鹫鹬鹭鹮鹯鹰鹱鹲鹳鹴鹵鹶鹷鹸鹹鹺鹻鹼鹽鹾鹿麀麁麂麃麄麅麆麇麈麉麊麋麌麍麎麏麐麑麒麓麔麕麖麗麘麙麚麛麜麝麞麟麠麡麢麣麤麥麦麧麨麩麪麫麬麭麮麯麰麱麲麳麴麵麶麷麸麹麺麻麼麽麾麿黀黁黂黃黄黅黆黇黈黉黊黋黌黍黎黏黐黑黒黓黔黕黖黗默黙黚黛黜黝點黟黠黡黢黣黤黥黦黧黨黩黪黫黬黭黮黯黰黱黲黳黴黵黶黷黸黹黺黻黼黽黾黿鼀鼁鼂鼃鼄鼅鼆鼇鼈鼉鼊鼋鼌鼍鼎鼏鼐鼑鼒鼓鼔鼕鼖鼗鼘鼙鼚鼛鼜鼝鼞鼟鼠鼡鼢鼣鼤鼥鼦鼧鼨鼩鼪鼫鼬鼭鼮鼯鼰鼱鼲鼳鼴鼵鼶鼷鼸鼹鼺鼻鼼鼽鼾鼿齀齁齂齃齄齅齆齇齈齉齊齋齌齍齎齏齐齑齒齓齔齕齖齗齘齙齚齛齜齝齞齟齠齡齢齣齤齥齦齧齨齩齪齫齬齭齮齯齰齱齲齳齴齵齶齷齸齹齺齻齼齽齾齿龀龁龂龃龄龅龆龇龈龉龊龋龌龍龎龏龐龑龒龓龔龕龖龗龘龙龚龛龜龝龞龟龠龡龢龣龤龥龦龧龨龩龪龫龬龭龮龯龰龱龲龳龴龵龶龷龸龹龺龻龼龽龾龿鿀鿁鿂鿃鿄鿅鿆鿇鿈鿉鿊鿋鿌ꀀꀁꀂꀃꀄꀅꀆꀇꀈꀉꀊꀋꀌꀍꀎꀏꀐꀑꀒꀓꀔꀕꀖꀗꀘꀙꀚꀛꀜꀝꀞꀟꀠꀡꀢꀣꀤꀥꀦꀧꀨꀩꀪꀫꀬꀭꀮꀯꀰꀱꀲꀳꀴꀵꀶꀷꀸꀹꀺꀻꀼꀽꀾꀿꁀꁁꁂꁃꁄꁅꁆꁇꁈꁉꁊꁋꁌꁍꁎꁏꁐꁑꁒꁓꁔꁕꁖꁗꁘꁙꁚꁛꁜꁝꁞꁟꁠꁡꁢꁣꁤꁥꁦꁧꁨꁩꁪꁫꁬꁭꁮꁯꁰꁱꁲꁳꁴꁵꁶꁷꁸꁹꁺꁻꁼꁽꁾꁿꂀꂁꂂꂃꂄꂅꂆꂇꂈꂉꂊꂋꂌꂍꂎꂏꂐꂑꂒꂓꂔꂕꂖꂗꂘꂙꂚꂛꂜꂝꂞꂟꂠꂡꂢꂣꂤꂥꂦꂧꂨꂩꂪꂫꂬꂭꂮꂯꂰꂱꂲꂳꂴꂵꂶꂷꂸꂹꂺꂻꂼꂽꂾꂿꃀꃁꃂꃃꃄꃅꃆꃇꃈꃉꃊꃋꃌꃍꃎꃏꃐꃑꃒꃓꃔꃕꃖꃗꃘꃙꃚꃛꃜꃝꃞꃟꃠꃡꃢꃣꃤꃥꃦꃧꃨꃩꃪꃫꃬꃭꃮꃯꃰꃱꃲꃳꃴꃵꃶꃷꃸꃹꃺꃻꃼꃽꃾꃿꄀꄁꄂꄃꄄꄅꄆꄇꄈꄉꄊꄋꄌꄍꄎꄏꄐꄑꄒꄓꄔꄕꄖꄗꄘꄙꄚꄛꄜꄝꄞꄟꄠꄡꄢꄣꄤꄥꄦꄧꄨꄩꄪꄫꄬꄭꄮꄯꄰꄱꄲꄳꄴꄵꄶꄷꄸꄹꄺꄻꄼꄽꄾꄿꅀꅁꅂꅃꅄꅅꅆꅇꅈꅉꅊꅋꅌꅍꅎꅏꅐꅑꅒꅓꅔꅕꅖꅗꅘꅙꅚꅛꅜꅝꅞꅟꅠꅡꅢꅣꅤꅥꅦꅧꅨꅩꅪꅫꅬꅭꅮꅯꅰꅱꅲꅳꅴꅵꅶꅷꅸꅹꅺꅻꅼꅽꅾꅿꆀꆁꆂꆃꆄꆅꆆꆇꆈꆉꆊꆋꆌꆍꆎꆏꆐꆑꆒꆓꆔꆕꆖꆗꆘꆙꆚꆛꆜꆝꆞꆟꆠꆡꆢꆣꆤꆥꆦꆧꆨꆩꆪꆫꆬꆭꆮꆯꆰꆱꆲꆳꆴꆵꆶꆷꆸꆹꆺꆻꆼꆽꆾꆿꇀꇁꇂꇃꇄꇅꇆꇇꇈꇉꇊꇋꇌꇍꇎꇏꇐꇑꇒꇓꇔꇕꇖꇗꇘꇙꇚꇛꇜꇝꇞꇟꇠꇡꇢꇣꇤꇥꇦꇧꇨꇩꇪꇫꇬꇭꇮꇯꇰꇱꇲꇳꇴꇵꇶꇷꇸꇹꇺꇻꇼꇽꇾꇿꈀꈁꈂꈃꈄꈅꈆꈇꈈꈉꈊꈋꈌꈍꈎꈏꈐꈑꈒꈓꈔꈕꈖꈗꈘꈙꈚꈛꈜꈝꈞꈟꈠꈡꈢꈣꈤꈥꈦꈧꈨꈩꈪꈫꈬꈭꈮꈯꈰꈱꈲꈳꈴꈵꈶꈷꈸꈹꈺꈻꈼꈽꈾꈿꉀꉁꉂꉃꉄꉅꉆꉇꉈꉉꉊꉋꉌꉍꉎꉏꉐꉑꉒꉓꉔꉕꉖꉗꉘꉙꉚꉛꉜꉝꉞꉟꉠꉡꉢꉣꉤꉥꉦꉧꉨꉩꉪꉫꉬꉭꉮꉯꉰꉱꉲꉳꉴꉵꉶꉷꉸꉹꉺꉻꉼꉽꉾꉿꊀꊁꊂꊃꊄꊅꊆꊇꊈꊉꊊꊋꊌꊍꊎꊏꊐꊑꊒꊓꊔꊕꊖꊗꊘꊙꊚꊛꊜꊝꊞꊟꊠꊡꊢꊣꊤꊥꊦꊧꊨꊩꊪꊫꊬꊭꊮꊯꊰꊱꊲꊳꊴꊵꊶꊷꊸꊹꊺꊻꊼꊽꊾꊿꋀꋁꋂꋃꋄꋅꋆꋇꋈꋉꋊꋋꋌꋍꋎꋏꋐꋑꋒꋓꋔꋕꋖꋗꋘꋙꋚꋛꋜꋝꋞꋟꋠꋡꋢꋣꋤꋥꋦꋧꋨꋩꋪꋫꋬꋭꋮꋯꋰꋱꋲꋳꋴꋵꋶꋷꋸꋹꋺꋻꋼꋽꋾꋿꌀꌁꌂꌃꌄꌅꌆꌇꌈꌉꌊꌋꌌꌍꌎꌏꌐꌑꌒꌓꌔꌕꌖꌗꌘꌙꌚꌛꌜꌝꌞꌟꌠꌡꌢꌣꌤꌥꌦꌧꌨꌩꌪꌫꌬꌭꌮꌯꌰꌱꌲꌳꌴꌵꌶꌷꌸꌹꌺꌻꌼꌽꌾꌿꍀꍁꍂꍃꍄꍅꍆꍇꍈꍉꍊꍋꍌꍍꍎꍏꍐꍑꍒꍓꍔꍕꍖꍗꍘꍙꍚꍛꍜꍝꍞꍟꍠꍡꍢꍣꍤꍥꍦꍧꍨꍩꍪꍫꍬꍭꍮꍯꍰꍱꍲꍳꍴꍵꍶꍷꍸꍹꍺꍻꍼꍽꍾꍿꎀꎁꎂꎃꎄꎅꎆꎇꎈꎉꎊꎋꎌꎍꎎꎏꎐꎑꎒꎓꎔꎕꎖꎗꎘꎙꎚꎛꎜꎝꎞꎟꎠꎡꎢꎣꎤꎥꎦꎧꎨꎩꎪꎫꎬꎭꎮꎯꎰꎱꎲꎳꎴꎵꎶꎷꎸꎹꎺꎻꎼꎽꎾꎿꏀꏁꏂꏃꏄꏅꏆꏇꏈꏉꏊꏋꏌꏍꏎꏏꏐꏑꏒꏓꏔꏕꏖꏗꏘꏙꏚꏛꏜꏝꏞꏟꏠꏡꏢꏣꏤꏥꏦꏧꏨꏩꏪꏫꏬꏭꏮꏯꏰꏱꏲꏳꏴꏵꏶꏷꏸꏹꏺꏻꏼꏽꏾꏿꐀꐁꐂꐃꐄꐅꐆꐇꐈꐉꐊꐋꐌꐍꐎꐏꐐꐑꐒꐓꐔꐕꐖꐗꐘꐙꐚꐛꐜꐝꐞꐟꐠꐡꐢꐣꐤꐥꐦꐧꐨꐩꐪꐫꐬꐭꐮꐯꐰꐱꐲꐳꐴꐵꐶꐷꐸꐹꐺꐻꐼꐽꐾꐿꑀꑁꑂꑃꑄꑅꑆꑇꑈꑉꑊꑋꑌꑍꑎꑏꑐꑑꑒꑓꑔꑕꑖꑗꑘꑙꑚꑛꑜꑝꑞꑟꑠꑡꑢꑣꑤꑥꑦꑧꑨꑩꑪꑫꑬꑭꑮꑯꑰꑱꑲꑳꑴꑵꑶꑷꑸꑹꑺꑻꑼꑽꑾꑿꒀꒁꒂꒃꒄꒅꒆꒇꒈꒉꒊꒋꒌ꒐꒑꒒꒓꒔꒕꒖꒗꒘꒙꒚꒛꒜꒝꒞꒟꒠꒡꒢꒣꒤꒥꒦꒧꒨꒩꒪꒫꒬꒭꒮꒯꒰꒱꒲꒳꒴꒵꒶꒷꒸꒹꒺꒻꒼꒽꒾꒿꓀꓁꓂꓃꓄꓅꓆ꓐꓑꓒꓓꓔꓕꓖꓗꓘꓙꓚꓛꓜꓝꓞꓟꓠꓡꓢꓣꓤꓥꓦꓧꓨꓩꓪꓫꓬꓭꓮꓯꓰꓱꓲꓳꓴꓵꓶꓷꓸꓹꓺꓻꓼꓽ꓾꓿ꔀꔁꔂꔃꔄꔅꔆꔇꔈꔉꔊꔋꔌꔍꔎꔏꔐꔑꔒꔓꔔꔕꔖꔗꔘꔙꔚꔛꔜꔝꔞꔟꔠꔡꔢꔣꔤꔥꔦꔧꔨꔩꔪꔫꔬꔭꔮꔯꔰꔱꔲꔳꔴꔵꔶꔷꔸꔹꔺꔻꔼꔽꔾꔿꕀꕁꕂꕃꕄꕅꕆꕇꕈꕉꕊꕋꕌꕍꕎꕏꕐꕑꕒꕓꕔꕕꕖꕗꕘꕙꕚꕛꕜꕝꕞꕟꕠꕡꕢꕣꕤꕥꕦꕧꕨꕩꕪꕫꕬꕭꕮꕯꕰꕱꕲꕳꕴꕵꕶꕷꕸꕹꕺꕻꕼꕽꕾꕿꖀꖁꖂꖃꖄꖅꖆꖇꖈꖉꖊꖋꖌꖍꖎꖏꖐꖑꖒꖓꖔꖕꖖꖗꖘꖙꖚꖛꖜꖝꖞꖟꖠꖡꖢꖣꖤꖥꖦꖧꖨꖩꖪꖫꖬꖭꖮꖯꖰꖱꖲꖳꖴꖵꖶꖷꖸꖹꖺꖻꖼꖽꖾꖿꗀꗁꗂꗃꗄꗅꗆꗇꗈꗉꗊꗋꗌꗍꗎꗏꗐꗑꗒꗓꗔꗕꗖꗗꗘꗙꗚꗛꗜꗝꗞꗟꗠꗡꗢꗣꗤꗥꗦꗧꗨꗩꗪꗫꗬꗭꗮꗯꗰꗱꗲꗳꗴꗵꗶꗷꗸꗹꗺꗻꗼꗽꗾꗿꘀꘁꘂꘃꘄꘅꘆꘇꘈꘉꘊꘋꘌ꘍꘎꘏ꘐꘑꘒꘓꘔꘕꘖꘗꘘꘙꘚꘛꘜꘝꘞꘟ꘠꘡꘢꘣꘤꘥꘦꘧꘨꘩ꘪꘫꙀꙁꙂꙃꙄꙅꙆꙇꙈꙉꙊꙋꙌꙍꙎꙏꙐꙑꙒꙓꙔꙕꙖꙗꙘꙙꙚꙛꙜꙝꙞꙟꙠꙡꙢꙣꙤꙥꙦꙧꙨꙩꙪꙫꙬꙭꙮ꙯꙰꙱꙲꙳ꙴꙵꙶꙷꙸꙹꙺꙻ꙼꙽꙾ꙿꚀꚁꚂꚃꚄꚅꚆꚇꚈꚉꚊꚋꚌꚍꚎꚏꚐꚑꚒꚓꚔꚕꚖꚗꚟꚠꚡꚢꚣꚤꚥꚦꚧꚨꚩꚪꚫꚬꚭꚮꚯꚰꚱꚲꚳꚴꚵꚶꚷꚸꚹꚺꚻꚼꚽꚾꚿꛀꛁꛂꛃꛄꛅꛆꛇꛈꛉꛊꛋꛌꛍꛎꛏꛐꛑꛒꛓꛔꛕꛖꛗꛘꛙꛚꛛꛜꛝꛞꛟꛠꛡꛢꛣꛤꛥꛦꛧꛨꛩꛪꛫꛬꛭꛮꛯ꛰꛱꛲꛳꛴꛵꛶꛷꜀꜁꜂꜃꜄꜅꜆꜇꜈꜉꜊꜋꜌꜍꜎꜏꜐꜑꜒꜓꜔꜕꜖ꜗꜘꜙꜚꜛꜜꜝꜞꜟ꜠꜡ꜢꜣꜤꜥꜦꜧꜨꜩꜪꜫꜬꜭꜮꜯꜰꜱꜲꜳꜴꜵꜶꜷꜸꜹꜺꜻꜼꜽꜾꜿꝀꝁꝂꝃꝄꝅꝆꝇꝈꝉꝊꝋꝌꝍꝎꝏꝐꝑꝒꝓꝔꝕꝖꝗꝘꝙꝚꝛꝜꝝꝞꝟꝠꝡꝢꝣꝤꝥꝦꝧꝨꝩꝪꝫꝬꝭꝮꝯꝰꝱꝲꝳꝴꝵꝶꝷꝸꝹꝺꝻꝼꝽꝾꝿꞀꞁꞂꞃꞄꞅꞆꞇꞈ꞉꞊ꞋꞌꞍꞎꞐꞑꞒꞓꞠꞡꞢꞣꞤꞥꞦꞧꞨꞩꞪꟸꟹꟺꟻꟼꟽꟾꟿꠀꠁꠂꠃꠄꠅ꠆ꠇꠈꠉꠊꠋꠌꠍꠎꠏꠐꠑꠒꠓꠔꠕꠖꠗꠘꠙꠚꠛꠜꠝꠞꠟꠠꠡꠢꠣꠤꠥꠦꠧ꠨꠩꠪꠫꠰꠱꠲꠳꠴꠵꠶꠷꠸꠹ꡀꡁꡂꡃꡄꡅꡆꡇꡈꡉꡊꡋꡌꡍꡎꡏꡐꡑꡒꡓꡔꡕꡖꡗꡘꡙꡚꡛꡜꡝꡞꡟꡠꡡꡢꡣꡤꡥꡦꡧꡨꡩꡪꡫꡬꡭꡮꡯꡰꡱꡲꡳ꡴꡵꡶꡷ꢀꢁꢂꢃꢄꢅꢆꢇꢈꢉꢊꢋꢌꢍꢎꢏꢐꢑꢒꢓꢔꢕꢖꢗꢘꢙꢚꢛꢜꢝꢞꢟꢠꢡꢢꢣꢤꢥꢦꢧꢨꢩꢪꢫꢬꢭꢮꢯꢰꢱꢲꢳꢴꢵꢶꢷꢸꢹꢺꢻꢼꢽꢾꢿꣀꣁꣂꣃ꣄꣎꣏꣐꣑꣒꣓꣔꣕꣖꣗꣘꣙꣠꣡꣢꣣꣤꣥꣦꣧꣨꣩꣪꣫꣬꣭꣮꣯꣰꣱ꣲꣳꣴꣵꣶꣷ꣸꣹꣺ꣻ꤀꤁꤂꤃꤄꤅꤆꤇꤈꤉ꤊꤋꤌꤍꤎꤏꤐꤑꤒꤓꤔꤕꤖꤗꤘꤙꤚꤛꤜꤝꤞꤟꤠꤡꤢꤣꤤꤥꤦꤧꤨꤩꤪ꤫꤬꤭꤮꤯ꤰꤱꤲꤳꤴꤵꤶꤷꤸꤹꤺꤻꤼꤽꤾꤿꥀꥁꥂꥃꥄꥅꥆꥇꥈꥉꥊꥋꥌꥍꥎꥏꥐꥑꥒ꥓꥟ꥠꥡꥢꥣꥤꥥꥦꥧꥨꥩꥪꥫꥬꥭꥮꥯꥰꥱꥲꥳꥴꥵꥶꥷꥸꥹꥺꥻꥼꦀꦁꦂꦃꦄꦅꦆꦇꦈꦉꦊꦋꦌꦍꦎꦏꦐꦑꦒꦓꦔꦕꦖꦗꦘꦙꦚꦛꦜꦝꦞꦟꦠꦡꦢꦣꦤꦥꦦꦧꦨꦩꦪꦫꦬꦭꦮꦯꦰꦱꦲ꦳ꦴꦵꦶꦷꦸꦹꦺꦻꦼꦽꦾꦿ꧀꧁꧂꧃꧄꧅꧆꧇꧈꧉꧊꧋꧌꧍ꧏ꧐꧑꧒꧓꧔꧕꧖꧗꧘꧙꧞꧟ꨀꨁꨂꨃꨄꨅꨆꨇꨈꨉꨊꨋꨌꨍꨎꨏꨐꨑꨒꨓꨔꨕꨖꨗꨘꨙꨚꨛꨜꨝꨞꨟꨠꨡꨢꨣꨤꨥꨦꨧꨨꨩꨪꨫꨬꨭꨮꨯꨰꨱꨲꨳꨴꨵꨶꩀꩁꩂꩃꩄꩅꩆꩇꩈꩉꩊꩋꩌꩍ꩐꩑꩒꩓꩔꩕꩖꩗꩘꩙꩜꩝꩞꩟ꩠꩡꩢꩣꩤꩥꩦꩧꩨꩩꩪꩫꩬꩭꩮꩯꩰꩱꩲꩳꩴꩵꩶ꩷꩸꩹ꩺꩻꪀꪁꪂꪃꪄꪅꪆꪇꪈꪉꪊꪋꪌꪍꪎꪏꪐꪑꪒꪓꪔꪕꪖꪗꪘꪙꪚꪛꪜꪝꪞꪟꪠꪡꪢꪣꪤꪥꪦꪧꪨꪩꪪꪫꪬꪭꪮꪯꪰꪱꪴꪲꪳꪵꪶꪷꪸꪹꪺꪻꪼꪽꪾ꪿ꫀ꫁ꫂꫛꫜꫝ꫞꫟ꫠꫡꫢꫣꫤꫥꫦꫧꫨꫩꫪꫫꫬꫭꫮꫯ꫰꫱ꫲꫳꫴꫵ꫶ꬁꬂꬃꬄꬅꬆꬉꬊꬋꬌꬍꬎꬑꬒꬓꬔꬕꬖꬠꬡꬢꬣꬤꬥꬦꬨꬩꬪꬫꬬꬭꬮꯀꯁꯂꯃꯄꯅꯆꯇꯈꯉꯊꯋꯌꯍꯎꯏꯐꯑꯒꯓꯔꯕꯖꯗꯘꯙꯚꯛꯜꯝꯞꯟꯠꯡꯢꯣꯤꯥꯦꯧꯨꯩꯪ꯫꯬꯭꯰꯱꯲꯳꯴꯵꯶꯷꯸꯹가각갂갃간갅갆갇갈갉갊갋갌갍갎갏감갑값갓갔강갖갗갘같갚갛개객갞갟갠갡갢갣갤갥갦갧갨갩갪갫갬갭갮갯갰갱갲갳갴갵갶갷갸갹갺갻갼갽갾갿걀걁걂걃걄걅걆걇걈걉걊걋걌걍걎걏걐걑걒걓걔걕걖걗걘걙걚걛걜걝걞걟걠걡걢걣걤걥걦걧걨걩걪걫걬걭걮걯거걱걲걳건걵걶걷걸걹걺걻걼걽걾걿검겁겂것겄겅겆겇겈겉겊겋게겍겎겏겐겑겒겓겔겕겖겗겘겙겚겛겜겝겞겟겠겡겢겣겤겥겦겧겨격겪겫견겭겮겯결겱겲겳겴겵겶겷겸겹겺겻겼경겾겿곀곁곂곃계곅곆곇곈곉곊곋곌곍곎곏곐곑곒곓곔곕곖곗곘곙곚곛곜곝곞곟고곡곢곣곤곥곦곧골곩곪곫곬곭곮곯곰곱곲곳곴공곶곷곸곹곺곻과곽곾곿관괁괂괃괄괅괆괇괈괉괊괋괌괍괎괏괐광괒괓괔괕괖괗괘괙괚괛괜괝괞괟괠괡괢괣괤괥괦괧괨괩괪괫괬괭괮괯괰괱괲괳괴괵괶괷괸괹괺괻괼괽괾괿굀굁굂굃굄굅굆굇굈굉굊굋굌굍굎굏교굑굒굓굔굕굖굗굘굙굚굛굜굝굞굟굠굡굢굣굤굥굦굧굨굩굪굫구국굮굯군굱굲굳굴굵굶굷굸굹굺굻굼굽굾굿궀궁궂궃궄궅궆궇궈궉궊궋권궍궎궏궐궑궒궓궔궕궖궗궘궙궚궛궜궝궞궟궠궡궢궣궤궥궦궧궨궩궪궫궬궭궮궯궰궱궲궳궴궵궶궷궸궹궺궻궼궽궾궿귀귁귂귃귄귅귆귇귈귉귊귋귌귍귎귏귐귑귒귓귔귕귖귗귘귙귚귛규귝귞귟균귡귢귣귤귥귦귧귨귩귪귫귬귭귮귯귰귱귲귳귴귵귶귷그극귺귻근귽귾귿글긁긂긃긄긅긆긇금급긊긋긌긍긎긏긐긑긒긓긔긕긖긗긘긙긚긛긜긝긞긟긠긡긢긣긤긥긦긧긨긩긪긫긬긭긮긯기긱긲긳긴긵긶긷길긹긺긻긼긽긾긿김깁깂깃깄깅깆깇깈깉깊깋까깍깎깏깐깑깒깓깔깕깖깗깘깙깚깛깜깝깞깟깠깡깢깣깤깥깦깧깨깩깪깫깬깭깮깯깰깱깲깳깴깵깶깷깸깹깺깻깼깽깾깿꺀꺁꺂꺃꺄꺅꺆꺇꺈꺉꺊꺋꺌꺍꺎꺏꺐꺑꺒꺓꺔꺕꺖꺗꺘꺙꺚꺛꺜꺝꺞꺟꺠꺡꺢꺣꺤꺥꺦꺧꺨꺩꺪꺫꺬꺭꺮꺯꺰꺱꺲꺳꺴꺵꺶꺷꺸꺹꺺꺻꺼꺽꺾꺿껀껁껂껃껄껅껆껇껈껉껊껋껌껍껎껏껐껑껒껓껔껕껖껗께껙껚껛껜껝껞껟껠껡껢껣껤껥껦껧껨껩껪껫껬껭껮껯껰껱껲껳껴껵껶껷껸껹껺껻껼껽껾껿꼀꼁꼂꼃꼄꼅꼆꼇꼈꼉꼊꼋꼌꼍꼎꼏꼐꼑꼒꼓꼔꼕꼖꼗꼘꼙꼚꼛꼜꼝꼞꼟꼠꼡꼢꼣꼤꼥꼦꼧꼨꼩꼪꼫꼬꼭꼮꼯꼰꼱꼲꼳꼴꼵꼶꼷꼸꼹꼺꼻꼼꼽꼾꼿꽀꽁꽂꽃꽄꽅꽆꽇꽈꽉꽊꽋꽌꽍꽎꽏꽐꽑꽒꽓꽔꽕꽖꽗꽘꽙꽚꽛꽜꽝꽞꽟꽠꽡꽢꽣꽤꽥꽦꽧꽨꽩꽪꽫꽬꽭꽮꽯꽰꽱꽲꽳꽴꽵꽶꽷꽸꽹꽺꽻꽼꽽꽾꽿꾀꾁꾂꾃꾄꾅꾆꾇꾈꾉꾊꾋꾌꾍꾎꾏꾐꾑꾒꾓꾔꾕꾖꾗꾘꾙꾚꾛꾜꾝꾞꾟꾠꾡꾢꾣꾤꾥꾦꾧꾨꾩꾪꾫꾬꾭꾮꾯꾰꾱꾲꾳꾴꾵꾶꾷꾸꾹꾺꾻꾼꾽꾾꾿꿀꿁꿂꿃꿄꿅꿆꿇꿈꿉꿊꿋꿌꿍꿎꿏꿐꿑꿒꿓꿔꿕꿖꿗꿘꿙꿚꿛꿜꿝꿞꿟꿠꿡꿢꿣꿤꿥꿦꿧꿨꿩꿪꿫꿬꿭꿮꿯꿰꿱꿲꿳꿴꿵꿶꿷꿸꿹꿺꿻꿼꿽꿾꿿뀀뀁뀂뀃뀄뀅뀆뀇뀈뀉뀊뀋뀌뀍뀎뀏뀐뀑뀒뀓뀔뀕뀖뀗뀘뀙뀚뀛뀜뀝뀞뀟뀠뀡뀢뀣뀤뀥뀦뀧뀨뀩뀪뀫뀬뀭뀮뀯뀰뀱뀲뀳뀴뀵뀶뀷뀸뀹뀺뀻뀼뀽뀾뀿끀끁끂끃끄끅끆끇끈끉끊끋끌끍끎끏끐끑끒끓끔끕끖끗끘끙끚끛끜끝끞끟끠끡끢끣끤끥끦끧끨끩끪끫끬끭끮끯끰끱끲끳끴끵끶끷끸끹끺끻끼끽끾끿낀낁낂낃낄낅낆낇낈낉낊낋낌낍낎낏낐낑낒낓낔낕낖낗나낙낚낛난낝낞낟날낡낢낣낤낥낦낧남납낪낫났낭낮낯낰낱낲낳내낵낶낷낸낹낺낻낼낽낾낿냀냁냂냃냄냅냆냇냈냉냊냋냌냍냎냏냐냑냒냓냔냕냖냗냘냙냚냛냜냝냞냟냠냡냢냣냤냥냦냧냨냩냪냫냬냭냮냯냰냱냲냳냴냵냶냷냸냹냺냻냼냽냾냿넀넁넂넃넄넅넆넇너넉넊넋넌넍넎넏널넑넒넓넔넕넖넗넘넙넚넛넜넝넞넟넠넡넢넣네넥넦넧넨넩넪넫넬넭넮넯넰넱넲넳넴넵넶넷넸넹넺넻넼넽넾넿녀녁녂녃년녅녆녇녈녉녊녋녌녍녎녏념녑녒녓녔녕녖녗녘녙녚녛녜녝녞녟녠녡녢녣녤녥녦녧녨녩녪녫녬녭녮녯녰녱녲녳녴녵녶녷노녹녺녻논녽녾녿놀놁놂놃놄놅놆놇놈놉놊놋놌농놎놏놐놑높놓놔놕놖놗놘놙놚놛놜놝놞놟놠놡놢놣놤놥놦놧놨놩놪놫놬놭놮놯놰놱놲놳놴놵놶놷놸놹놺놻놼놽놾놿뇀뇁뇂뇃뇄뇅뇆뇇뇈뇉뇊뇋뇌뇍뇎뇏뇐뇑뇒뇓뇔뇕뇖뇗뇘뇙뇚뇛뇜뇝뇞뇟뇠뇡뇢뇣뇤뇥뇦뇧뇨뇩뇪뇫뇬뇭뇮뇯뇰뇱뇲뇳뇴뇵뇶뇷뇸뇹뇺뇻뇼뇽뇾뇿눀눁눂눃누눅눆눇눈눉눊눋눌눍눎눏눐눑눒눓눔눕눖눗눘눙눚눛눜눝눞눟눠눡눢눣눤눥눦눧눨눩눪눫눬눭눮눯눰눱눲눳눴눵눶눷눸눹눺눻눼눽눾눿뉀뉁뉂뉃뉄뉅뉆뉇뉈뉉뉊뉋뉌뉍뉎뉏뉐뉑뉒뉓뉔뉕뉖뉗뉘뉙뉚뉛뉜뉝뉞뉟뉠뉡뉢뉣뉤뉥뉦뉧뉨뉩뉪뉫뉬뉭뉮뉯뉰뉱뉲뉳뉴뉵뉶뉷뉸뉹뉺뉻뉼뉽뉾뉿늀늁늂늃늄늅늆늇늈늉늊늋늌늍늎늏느늑늒늓는늕늖늗늘늙늚늛늜늝늞늟늠늡늢늣늤능늦늧늨늩늪늫늬늭늮늯늰늱늲늳늴늵늶늷늸늹늺늻늼늽늾늿닀닁닂닃닄닅닆닇니닉닊닋닌닍닎닏닐닑닒닓닔닕닖닗님닙닚닛닜닝닞닟닠닡닢닣다닥닦닧단닩닪닫달닭닮닯닰닱닲닳담답닶닷닸당닺닻닼닽닾닿대댁댂댃댄댅댆댇댈댉댊댋댌댍댎댏댐댑댒댓댔댕댖댗댘댙댚댛댜댝댞댟댠댡댢댣댤댥댦댧댨댩댪댫댬댭댮댯댰댱댲댳댴댵댶댷댸댹댺댻댼댽댾댿덀덁덂덃덄덅덆덇덈덉덊덋덌덍덎덏덐덑덒덓더덕덖덗던덙덚덛덜덝덞덟덠덡덢덣덤덥덦덧덨덩덪덫덬덭덮덯데덱덲덳덴덵덶덷델덹덺덻덼덽덾덿뎀뎁뎂뎃뎄뎅뎆뎇뎈뎉뎊뎋뎌뎍뎎뎏뎐뎑뎒뎓뎔뎕뎖뎗뎘뎙뎚뎛뎜뎝뎞뎟뎠뎡뎢뎣뎤뎥뎦뎧뎨뎩뎪뎫뎬뎭뎮뎯뎰뎱뎲뎳뎴뎵뎶뎷뎸뎹뎺뎻뎼뎽뎾뎿돀돁돂돃도독돆돇돈돉돊돋돌돍돎돏돐돑돒돓돔돕돖돗돘동돚돛돜돝돞돟돠돡돢돣돤돥돦돧돨돩돪돫돬돭돮돯돰돱돲돳돴돵돶돷돸돹돺돻돼돽돾돿됀됁됂됃됄됅됆됇됈됉됊됋됌됍됎됏됐됑됒됓됔됕됖됗되됙됚됛된됝됞됟될됡됢됣됤됥됦됧됨됩됪됫됬됭됮됯됰됱됲됳됴됵됶됷됸됹됺됻됼됽됾됿둀둁둂둃둄둅둆둇둈둉둊둋둌둍둎둏두둑둒둓둔둕둖둗둘둙둚둛둜둝둞둟둠둡둢둣둤둥둦둧둨둩둪둫둬둭둮둯둰둱둲둳둴둵둶둷둸둹둺둻둼둽둾둿뒀뒁뒂뒃뒄뒅뒆뒇뒈뒉뒊뒋뒌뒍뒎뒏뒐뒑뒒뒓뒔뒕뒖뒗뒘뒙뒚뒛뒜뒝뒞뒟뒠뒡뒢뒣뒤뒥뒦뒧뒨뒩뒪뒫뒬뒭뒮뒯뒰뒱뒲뒳뒴뒵뒶뒷뒸뒹뒺뒻뒼뒽뒾뒿듀듁듂듃듄듅듆듇듈듉듊듋듌듍듎듏듐듑듒듓듔듕듖듗듘듙듚듛드득듞듟든듡듢듣들듥듦듧듨듩듪듫듬듭듮듯듰등듲듳듴듵듶듷듸듹듺듻듼듽듾듿딀딁딂딃딄딅딆딇딈딉딊딋딌딍딎딏딐딑딒딓디딕딖딗딘딙딚딛딜딝딞딟딠딡딢딣딤딥딦딧딨딩딪딫딬딭딮딯따딱딲딳딴딵딶딷딸딹딺딻딼딽딾딿땀땁땂땃땄땅땆땇땈땉땊땋때땍땎땏땐땑땒땓땔땕땖땗땘땙땚땛땜땝땞땟땠땡땢땣땤땥땦땧땨땩땪땫땬땭땮땯땰땱땲땳땴땵땶땷땸땹땺땻땼땽땾땿떀떁떂떃떄떅떆떇떈떉떊떋떌떍떎떏떐떑떒떓떔떕떖떗떘떙떚떛떜떝떞떟떠떡떢떣떤떥떦떧떨떩떪떫떬떭떮떯떰떱떲떳떴떵떶떷떸떹떺떻떼떽떾떿뗀뗁뗂뗃뗄뗅뗆뗇뗈뗉뗊뗋뗌뗍뗎뗏뗐뗑뗒뗓뗔뗕뗖뗗뗘뗙뗚뗛뗜뗝뗞뗟뗠뗡뗢뗣뗤뗥뗦뗧뗨뗩뗪뗫뗬뗭뗮뗯뗰뗱뗲뗳뗴뗵뗶뗷뗸뗹뗺뗻뗼뗽뗾뗿똀똁똂똃똄똅똆똇똈똉똊똋똌똍똎똏또똑똒똓똔똕똖똗똘똙똚똛똜똝똞똟똠똡똢똣똤똥똦똧똨똩똪똫똬똭똮똯똰똱똲똳똴똵똶똷똸똹똺똻똼똽똾똿뙀뙁뙂뙃뙄뙅뙆뙇뙈뙉뙊뙋뙌뙍뙎뙏뙐뙑뙒뙓뙔뙕뙖뙗뙘뙙뙚뙛뙜뙝뙞뙟뙠뙡뙢뙣뙤뙥뙦뙧뙨뙩뙪뙫뙬뙭뙮뙯뙰뙱뙲뙳뙴뙵뙶뙷뙸뙹뙺뙻뙼뙽뙾뙿뚀뚁뚂뚃뚄뚅뚆뚇뚈뚉뚊뚋뚌뚍뚎뚏뚐뚑뚒뚓뚔뚕뚖뚗뚘뚙뚚뚛뚜뚝뚞뚟뚠뚡뚢뚣뚤뚥뚦뚧뚨뚩뚪뚫뚬뚭뚮뚯뚰뚱뚲뚳뚴뚵뚶뚷뚸뚹뚺뚻뚼뚽뚾뚿뛀뛁뛂뛃뛄뛅뛆뛇뛈뛉뛊뛋뛌뛍뛎뛏뛐뛑뛒뛓뛔뛕뛖뛗뛘뛙뛚뛛뛜뛝뛞뛟뛠뛡뛢뛣뛤뛥뛦뛧뛨뛩뛪뛫뛬뛭뛮뛯뛰뛱뛲뛳뛴뛵뛶뛷뛸뛹뛺뛻뛼뛽뛾뛿뜀뜁뜂뜃뜄뜅뜆뜇뜈뜉뜊뜋뜌뜍뜎뜏뜐뜑뜒뜓뜔뜕뜖뜗뜘뜙뜚뜛뜜뜝뜞뜟뜠뜡뜢뜣뜤뜥뜦뜧뜨뜩뜪뜫뜬뜭뜮뜯뜰뜱뜲뜳뜴뜵뜶뜷뜸뜹뜺뜻뜼뜽뜾뜿띀띁띂띃띄띅띆띇띈띉띊띋띌띍띎띏띐띑띒띓띔띕띖띗띘띙띚띛띜띝띞띟띠띡띢띣띤띥띦띧띨띩띪띫띬띭띮띯띰띱띲띳띴띵띶띷띸띹띺띻라락띾띿란랁랂랃랄랅랆랇랈랉랊랋람랍랎랏랐랑랒랓랔랕랖랗래랙랚랛랜랝랞랟랠랡랢랣랤랥랦랧램랩랪랫랬랭랮랯랰랱랲랳랴략랶랷랸랹랺랻랼랽랾랿럀럁럂럃럄럅럆럇럈량럊럋럌럍럎럏럐럑럒럓럔럕럖럗럘럙럚럛럜럝럞럟럠럡럢럣럤럥럦럧럨럩럪럫러럭럮럯런럱럲럳럴럵럶럷럸럹럺럻럼럽럾럿렀렁렂렃렄렅렆렇레렉렊렋렌렍렎렏렐렑렒렓렔렕렖렗렘렙렚렛렜렝렞렟렠렡렢렣려력렦렧련렩렪렫렬렭렮렯렰렱렲렳렴렵렶렷렸령렺렻렼렽렾렿례롁롂롃롄롅롆롇롈롉롊롋롌롍롎롏롐롑롒롓롔롕롖롗롘롙롚롛로록롞롟론롡롢롣롤롥롦롧롨롩롪롫롬롭롮롯롰롱롲롳롴롵롶롷롸롹롺롻롼롽롾롿뢀뢁뢂뢃뢄뢅뢆뢇뢈뢉뢊뢋뢌뢍뢎뢏뢐뢑뢒뢓뢔뢕뢖뢗뢘뢙뢚뢛뢜뢝뢞뢟뢠뢡뢢뢣뢤뢥뢦뢧뢨뢩뢪뢫뢬뢭뢮뢯뢰뢱뢲뢳뢴뢵뢶뢷뢸뢹뢺뢻뢼뢽뢾뢿룀룁룂룃룄룅룆룇룈룉룊룋료룍룎룏룐룑룒룓룔룕룖룗룘룙룚룛룜룝룞룟룠룡룢룣룤룥룦룧루룩룪룫룬룭룮룯룰룱룲룳룴룵룶룷룸룹룺룻룼룽룾룿뤀뤁뤂뤃뤄뤅뤆뤇뤈뤉뤊뤋뤌뤍뤎뤏뤐뤑뤒뤓뤔뤕뤖뤗뤘뤙뤚뤛뤜뤝뤞뤟뤠뤡뤢뤣뤤뤥뤦뤧뤨뤩뤪뤫뤬뤭뤮뤯뤰뤱뤲뤳뤴뤵뤶뤷뤸뤹뤺뤻뤼뤽뤾뤿륀륁륂륃륄륅륆륇륈륉륊륋륌륍륎륏륐륑륒륓륔륕륖륗류륙륚륛륜륝륞륟률륡륢륣륤륥륦륧륨륩륪륫륬륭륮륯륰륱륲륳르륵륶륷른륹륺륻를륽륾륿릀릁릂릃름릅릆릇릈릉릊릋릌릍릎릏릐릑릒릓릔릕릖릗릘릙릚릛릜릝릞릟릠릡릢릣릤릥릦릧릨릩릪릫리릭릮릯린릱릲릳릴릵릶릷릸릹릺릻림립릾릿맀링맂맃맄맅맆맇마막맊맋만맍많맏말맑맒맓맔맕맖맗맘맙맚맛맜망맞맟맠맡맢맣매맥맦맧맨맩맪맫맬맭맮맯맰맱맲맳맴맵맶맷맸맹맺맻맼맽맾맿먀먁먂먃먄먅먆먇먈먉먊먋먌먍먎먏먐먑먒먓먔먕먖먗먘먙먚먛먜먝먞먟먠먡먢먣먤먥먦먧먨먩먪먫먬먭먮먯먰먱먲먳먴먵먶먷머먹먺먻먼먽먾먿멀멁멂멃멄멅멆멇멈멉멊멋멌멍멎멏멐멑멒멓메멕멖멗멘멙멚멛멜멝멞멟멠멡멢멣멤멥멦멧멨멩멪멫멬멭멮멯며멱멲멳면멵멶멷멸멹멺멻멼멽멾멿몀몁몂몃몄명몆몇몈몉몊몋몌몍몎몏몐몑몒몓몔몕몖몗몘몙몚몛몜몝몞몟몠몡몢몣몤몥몦몧모목몪몫몬몭몮몯몰몱몲몳몴몵몶몷몸몹몺못몼몽몾몿뫀뫁뫂뫃뫄뫅뫆뫇뫈뫉뫊뫋뫌뫍뫎뫏뫐뫑뫒뫓뫔뫕뫖뫗뫘뫙뫚뫛뫜뫝뫞뫟뫠뫡뫢뫣뫤뫥뫦뫧뫨뫩뫪뫫뫬뫭뫮뫯뫰뫱뫲뫳뫴뫵뫶뫷뫸뫹뫺뫻뫼뫽뫾뫿묀묁묂묃묄묅묆묇묈묉묊묋묌묍묎묏묐묑묒묓묔묕묖묗묘묙묚묛묜묝묞묟묠묡묢묣묤묥묦묧묨묩묪묫묬묭묮묯묰묱묲묳무묵묶묷문묹묺묻물묽묾묿뭀뭁뭂뭃뭄뭅뭆뭇뭈뭉뭊뭋뭌뭍뭎뭏뭐뭑뭒뭓뭔뭕뭖뭗뭘뭙뭚뭛뭜뭝뭞뭟뭠뭡뭢뭣뭤뭥뭦뭧뭨뭩뭪뭫뭬뭭뭮뭯뭰뭱뭲뭳뭴뭵뭶뭷뭸뭹뭺뭻뭼뭽뭾뭿뮀뮁뮂뮃뮄뮅뮆뮇뮈뮉뮊뮋뮌뮍뮎뮏뮐뮑뮒뮓뮔뮕뮖뮗뮘뮙뮚뮛뮜뮝뮞뮟뮠뮡뮢뮣뮤뮥뮦뮧뮨뮩뮪뮫뮬뮭뮮뮯뮰뮱뮲뮳뮴뮵뮶뮷뮸뮹뮺뮻뮼뮽뮾뮿므믁믂믃믄믅믆믇믈믉믊믋믌믍믎믏믐믑믒믓믔믕믖믗믘믙믚믛믜믝믞믟믠믡믢믣믤믥믦믧믨믩믪믫믬믭믮믯믰믱믲믳믴믵믶믷미믹믺믻민믽믾믿밀밁밂밃밄밅밆밇밈밉밊밋밌밍밎및밐밑밒밓바박밖밗반밙밚받발밝밞밟밠밡밢밣밤밥밦밧밨방밪밫밬밭밮밯배백밲밳밴밵밶밷밸밹밺밻밼밽밾밿뱀뱁뱂뱃뱄뱅뱆뱇뱈뱉뱊뱋뱌뱍뱎뱏뱐뱑뱒뱓뱔뱕뱖뱗뱘뱙뱚뱛뱜뱝뱞뱟뱠뱡뱢뱣뱤뱥뱦뱧뱨뱩뱪뱫뱬뱭뱮뱯뱰뱱뱲뱳뱴뱵뱶뱷뱸뱹뱺뱻뱼뱽뱾뱿벀벁벂벃버벅벆벇번벉벊벋벌벍벎벏벐벑벒벓범법벖벗벘벙벚벛벜벝벞벟베벡벢벣벤벥벦벧벨벩벪벫벬벭벮벯벰벱벲벳벴벵벶벷벸벹벺벻벼벽벾벿변볁볂볃별볅볆볇볈볉볊볋볌볍볎볏볐병볒볓볔볕볖볗볘볙볚볛볜볝볞볟볠볡볢볣볤볥볦볧볨볩볪볫볬볭볮볯볰볱볲볳보복볶볷본볹볺볻볼볽볾볿봀봁봂봃봄봅봆봇봈봉봊봋봌봍봎봏봐봑봒봓봔봕봖봗봘봙봚봛봜봝봞봟봠봡봢봣봤봥봦봧봨봩봪봫봬봭봮봯봰봱봲봳봴봵봶봷봸봹봺봻봼봽봾봿뵀뵁뵂뵃뵄뵅뵆뵇뵈뵉뵊뵋뵌뵍뵎뵏뵐뵑뵒뵓뵔뵕뵖뵗뵘뵙뵚뵛뵜뵝뵞뵟뵠뵡뵢뵣뵤뵥뵦뵧뵨뵩뵪뵫뵬뵭뵮뵯뵰뵱뵲뵳뵴뵵뵶뵷뵸뵹뵺뵻뵼뵽뵾뵿부북붂붃분붅붆붇불붉붊붋붌붍붎붏붐붑붒붓붔붕붖붗붘붙붚붛붜붝붞붟붠붡붢붣붤붥붦붧붨붩붪붫붬붭붮붯붰붱붲붳붴붵붶붷붸붹붺붻붼붽붾붿뷀뷁뷂뷃뷄뷅뷆뷇뷈뷉뷊뷋뷌뷍뷎뷏뷐뷑뷒뷓뷔뷕뷖뷗뷘뷙뷚뷛뷜뷝뷞뷟뷠뷡뷢뷣뷤뷥뷦뷧뷨뷩뷪뷫뷬뷭뷮뷯뷰뷱뷲뷳뷴뷵뷶뷷뷸뷹뷺뷻뷼뷽뷾뷿븀븁븂븃븄븅븆븇븈븉븊븋브븍븎븏븐븑븒븓블븕븖븗븘븙븚븛븜븝븞븟븠븡븢븣븤븥븦븧븨븩븪븫븬븭븮븯븰븱븲븳븴븵븶븷븸븹븺븻븼븽븾븿빀빁빂빃비빅빆빇빈빉빊빋빌빍빎빏빐빑빒빓빔빕빖빗빘빙빚빛빜빝빞빟빠빡빢빣빤빥빦빧빨빩빪빫빬빭빮빯빰빱빲빳빴빵빶빷빸빹빺빻빼빽빾빿뺀뺁뺂뺃뺄뺅뺆뺇뺈뺉뺊뺋뺌뺍뺎뺏뺐뺑뺒뺓뺔뺕뺖뺗뺘뺙뺚뺛뺜뺝뺞뺟뺠뺡뺢뺣뺤뺥뺦뺧뺨뺩뺪뺫뺬뺭뺮뺯뺰뺱뺲뺳뺴뺵뺶뺷뺸뺹뺺뺻뺼뺽뺾뺿뻀뻁뻂뻃뻄뻅뻆뻇뻈뻉뻊뻋뻌뻍뻎뻏뻐뻑뻒뻓뻔뻕뻖뻗뻘뻙뻚뻛뻜뻝뻞뻟뻠뻡뻢뻣뻤뻥뻦뻧뻨뻩뻪뻫뻬뻭뻮뻯뻰뻱뻲뻳뻴뻵뻶뻷뻸뻹뻺뻻뻼뻽뻾뻿뼀뼁뼂뼃뼄뼅뼆뼇뼈뼉뼊뼋뼌뼍뼎뼏뼐뼑뼒뼓뼔뼕뼖뼗뼘뼙뼚뼛뼜뼝뼞뼟뼠뼡뼢뼣뼤뼥뼦뼧뼨뼩뼪뼫뼬뼭뼮뼯뼰뼱뼲뼳뼴뼵뼶뼷뼸뼹뼺뼻뼼뼽뼾뼿뽀뽁뽂뽃뽄뽅뽆뽇뽈뽉뽊뽋뽌뽍뽎뽏뽐뽑뽒뽓뽔뽕뽖뽗뽘뽙뽚뽛뽜뽝뽞뽟뽠뽡뽢뽣뽤뽥뽦뽧뽨뽩뽪뽫뽬뽭뽮뽯뽰뽱뽲뽳뽴뽵뽶뽷뽸뽹뽺뽻뽼뽽뽾뽿뾀뾁뾂뾃뾄뾅뾆뾇뾈뾉뾊뾋뾌뾍뾎뾏뾐뾑뾒뾓뾔뾕뾖뾗뾘뾙뾚뾛뾜뾝뾞뾟뾠뾡뾢뾣뾤뾥뾦뾧뾨뾩뾪뾫뾬뾭뾮뾯뾰뾱뾲뾳뾴뾵뾶뾷뾸뾹뾺뾻뾼뾽뾾뾿뿀뿁뿂뿃뿄뿅뿆뿇뿈뿉뿊뿋뿌뿍뿎뿏뿐뿑뿒뿓뿔뿕뿖뿗뿘뿙뿚뿛뿜뿝뿞뿟뿠뿡뿢뿣뿤뿥뿦뿧뿨뿩뿪뿫뿬뿭뿮뿯뿰뿱뿲뿳뿴뿵뿶뿷뿸뿹뿺뿻뿼뿽뿾뿿쀀쀁쀂쀃쀄쀅쀆쀇쀈쀉쀊쀋쀌쀍쀎쀏쀐쀑쀒쀓쀔쀕쀖쀗쀘쀙쀚쀛쀜쀝쀞쀟쀠쀡쀢쀣쀤쀥쀦쀧쀨쀩쀪쀫쀬쀭쀮쀯쀰쀱쀲쀳쀴쀵쀶쀷쀸쀹쀺쀻쀼쀽쀾쀿쁀쁁쁂쁃쁄쁅쁆쁇쁈쁉쁊쁋쁌쁍쁎쁏쁐쁑쁒쁓쁔쁕쁖쁗쁘쁙쁚쁛쁜쁝쁞쁟쁠쁡쁢쁣쁤쁥쁦쁧쁨쁩쁪쁫쁬쁭쁮쁯쁰쁱쁲쁳쁴쁵쁶쁷쁸쁹쁺쁻쁼쁽쁾쁿삀삁삂삃삄삅삆삇삈삉삊삋삌삍삎삏삐삑삒삓삔삕삖삗삘삙삚삛삜삝삞삟삠삡삢삣삤삥삦삧삨삩삪삫사삭삮삯산삱삲삳살삵삶삷삸삹삺삻삼삽삾삿샀상샂샃샄샅샆샇새색샊샋샌샍샎샏샐샑샒샓샔샕샖샗샘샙샚샛샜생샞샟샠샡샢샣샤샥샦샧샨샩샪샫샬샭샮샯샰샱샲샳샴샵샶샷샸샹샺샻샼샽샾샿섀섁섂섃섄섅섆섇섈섉섊섋섌섍섎섏섐섑섒섓섔섕섖섗섘섙섚섛서석섞섟선섡섢섣설섥섦섧섨섩섪섫섬섭섮섯섰성섲섳섴섵섶섷세섹섺섻센섽섾섿셀셁셂셃셄셅셆셇셈셉셊셋셌셍셎셏셐셑셒셓셔셕셖셗션셙셚셛셜셝셞셟셠셡셢셣셤셥셦셧셨셩셪셫셬셭셮셯셰셱셲셳셴셵셶셷셸셹셺셻셼셽셾셿솀솁솂솃솄솅솆솇솈솉솊솋소속솎솏손솑솒솓솔솕솖솗솘솙솚솛솜솝솞솟솠송솢솣솤솥솦솧솨솩솪솫솬솭솮솯솰솱솲솳솴솵솶솷솸솹솺솻솼솽솾솿쇀쇁쇂쇃쇄쇅쇆쇇쇈쇉쇊쇋쇌쇍쇎쇏쇐쇑쇒쇓쇔쇕쇖쇗쇘쇙쇚쇛쇜쇝쇞쇟쇠쇡쇢쇣쇤쇥쇦쇧쇨쇩쇪쇫쇬쇭쇮쇯쇰쇱쇲쇳쇴쇵쇶쇷쇸쇹쇺쇻쇼쇽쇾쇿숀숁숂숃숄숅숆숇숈숉숊숋숌숍숎숏숐숑숒숓숔숕숖숗수숙숚숛순숝숞숟술숡숢숣숤숥숦숧숨숩숪숫숬숭숮숯숰숱숲숳숴숵숶숷숸숹숺숻숼숽숾숿쉀쉁쉂쉃쉄쉅쉆쉇쉈쉉쉊쉋쉌쉍쉎쉏쉐쉑쉒쉓쉔쉕쉖쉗쉘쉙쉚쉛쉜쉝쉞쉟쉠쉡쉢쉣쉤쉥쉦쉧쉨쉩쉪쉫쉬쉭쉮쉯쉰쉱쉲쉳쉴쉵쉶쉷쉸쉹쉺쉻쉼쉽쉾쉿슀슁슂슃슄슅슆슇슈슉슊슋슌슍슎슏슐슑슒슓슔슕슖슗슘슙슚슛슜슝슞슟슠슡슢슣스슥슦슧슨슩슪슫슬슭슮슯슰슱슲슳슴습슶슷슸승슺슻슼슽슾슿싀싁싂싃싄싅싆싇싈싉싊싋싌싍싎싏싐싑싒싓싔싕싖싗싘싙싚싛시식싞싟신싡싢싣실싥싦싧싨싩싪싫심십싮싯싰싱싲싳싴싵싶싷싸싹싺싻싼싽싾싿쌀쌁쌂쌃쌄쌅쌆쌇쌈쌉쌊쌋쌌쌍쌎쌏쌐쌑쌒쌓쌔쌕쌖쌗쌘쌙쌚쌛쌜쌝쌞쌟쌠쌡쌢쌣쌤쌥쌦쌧쌨쌩쌪쌫쌬쌭쌮쌯쌰쌱쌲쌳쌴쌵쌶쌷쌸쌹쌺쌻쌼쌽쌾쌿썀썁썂썃썄썅썆썇썈썉썊썋썌썍썎썏썐썑썒썓썔썕썖썗썘썙썚썛썜썝썞썟썠썡썢썣썤썥썦썧써썩썪썫썬썭썮썯썰썱썲썳썴썵썶썷썸썹썺썻썼썽썾썿쎀쎁쎂쎃쎄쎅쎆쎇쎈쎉쎊쎋쎌쎍쎎쎏쎐쎑쎒쎓쎔쎕쎖쎗쎘쎙쎚쎛쎜쎝쎞쎟쎠쎡쎢쎣쎤쎥쎦쎧쎨쎩쎪쎫쎬쎭쎮쎯쎰쎱쎲쎳쎴쎵쎶쎷쎸쎹쎺쎻쎼쎽쎾쎿쏀쏁쏂쏃쏄쏅쏆쏇쏈쏉쏊쏋쏌쏍쏎쏏쏐쏑쏒쏓쏔쏕쏖쏗쏘쏙쏚쏛쏜쏝쏞쏟쏠쏡쏢쏣쏤쏥쏦쏧쏨쏩쏪쏫쏬쏭쏮쏯쏰쏱쏲쏳쏴쏵쏶쏷쏸쏹쏺쏻쏼쏽쏾쏿쐀쐁쐂쐃쐄쐅쐆쐇쐈쐉쐊쐋쐌쐍쐎쐏쐐쐑쐒쐓쐔쐕쐖쐗쐘쐙쐚쐛쐜쐝쐞쐟쐠쐡쐢쐣쐤쐥쐦쐧쐨쐩쐪쐫쐬쐭쐮쐯쐰쐱쐲쐳쐴쐵쐶쐷쐸쐹쐺쐻쐼쐽쐾쐿쑀쑁쑂쑃쑄쑅쑆쑇쑈쑉쑊쑋쑌쑍쑎쑏쑐쑑쑒쑓쑔쑕쑖쑗쑘쑙쑚쑛쑜쑝쑞쑟쑠쑡쑢쑣쑤쑥쑦쑧쑨쑩쑪쑫쑬쑭쑮쑯쑰쑱쑲쑳쑴쑵쑶쑷쑸쑹쑺쑻쑼쑽쑾쑿쒀쒁쒂쒃쒄쒅쒆쒇쒈쒉쒊쒋쒌쒍쒎쒏쒐쒑쒒쒓쒔쒕쒖쒗쒘쒙쒚쒛쒜쒝쒞쒟쒠쒡쒢쒣쒤쒥쒦쒧쒨쒩쒪쒫쒬쒭쒮쒯쒰쒱쒲쒳쒴쒵쒶쒷쒸쒹쒺쒻쒼쒽쒾쒿쓀쓁쓂쓃쓄쓅쓆쓇쓈쓉쓊쓋쓌쓍쓎쓏쓐쓑쓒쓓쓔쓕쓖쓗쓘쓙쓚쓛쓜쓝쓞쓟쓠쓡쓢쓣쓤쓥쓦쓧쓨쓩쓪쓫쓬쓭쓮쓯쓰쓱쓲쓳쓴쓵쓶쓷쓸쓹쓺쓻쓼쓽쓾쓿씀씁씂씃씄씅씆씇씈씉씊씋씌씍씎씏씐씑씒씓씔씕씖씗씘씙씚씛씜씝씞씟씠씡씢씣씤씥씦씧씨씩씪씫씬씭씮씯씰씱씲씳씴씵씶씷씸씹씺씻씼씽씾씿앀앁앂앃아악앆앇안앉않앋알앍앎앏앐앑앒앓암압앖앗았앙앚앛앜앝앞앟애액앢앣앤앥앦앧앨앩앪앫앬앭앮앯앰앱앲앳앴앵앶앷앸앹앺앻야약앾앿얀얁얂얃얄얅얆얇얈얉얊얋얌얍얎얏얐양얒얓얔얕얖얗얘얙얚얛얜얝얞얟얠얡얢얣얤얥얦얧얨얩얪얫얬얭얮얯얰얱얲얳어억얶얷언얹얺얻얼얽얾얿엀엁엂엃엄업없엇었엉엊엋엌엍엎엏에엑엒엓엔엕엖엗엘엙엚엛엜엝엞엟엠엡엢엣엤엥엦엧엨엩엪엫여역엮엯연엱엲엳열엵엶엷엸엹엺엻염엽엾엿였영옂옃옄옅옆옇예옉옊옋옌옍옎옏옐옑옒옓옔옕옖옗옘옙옚옛옜옝옞옟옠옡옢옣오옥옦옧온옩옪옫올옭옮옯옰옱옲옳옴옵옶옷옸옹옺옻옼옽옾옿와왁왂왃완왅왆왇왈왉왊왋왌왍왎왏왐왑왒왓왔왕왖왗왘왙왚왛왜왝왞왟왠왡왢왣왤왥왦왧왨왩왪왫왬왭왮왯왰왱왲왳왴왵왶왷외왹왺왻왼왽왾왿욀욁욂욃욄욅욆욇욈욉욊욋욌욍욎욏욐욑욒욓요욕욖욗욘욙욚욛욜욝욞욟욠욡욢욣욤욥욦욧욨용욪욫욬욭욮욯우욱욲욳운욵욶욷울욹욺욻욼욽욾욿움웁웂웃웄웅웆웇웈웉웊웋워웍웎웏원웑웒웓월웕웖웗웘웙웚웛웜웝웞웟웠웡웢웣웤웥웦웧웨웩웪웫웬웭웮웯웰웱웲웳웴웵웶웷웸웹웺웻웼웽웾웿윀윁윂윃위윅윆윇윈윉윊윋윌윍윎윏윐윑윒윓윔윕윖윗윘윙윚윛윜윝윞윟유육윢윣윤윥윦윧율윩윪윫윬윭윮윯윰윱윲윳윴융윶윷윸윹윺윻으윽윾윿은읁읂읃을읅읆읇읈읉읊읋음읍읎읏읐응읒읓읔읕읖읗의읙읚읛읜읝읞읟읠읡읢읣읤읥읦읧읨읩읪읫읬읭읮읯읰읱읲읳이익읶읷인읹읺읻일읽읾읿잀잁잂잃임입잆잇있잉잊잋잌잍잎잏자작잒잓잔잕잖잗잘잙잚잛잜잝잞잟잠잡잢잣잤장잦잧잨잩잪잫재잭잮잯잰잱잲잳잴잵잶잷잸잹잺잻잼잽잾잿쟀쟁쟂쟃쟄쟅쟆쟇쟈쟉쟊쟋쟌쟍쟎쟏쟐쟑쟒쟓쟔쟕쟖쟗쟘쟙쟚쟛쟜쟝쟞쟟쟠쟡쟢쟣쟤쟥쟦쟧쟨쟩쟪쟫쟬쟭쟮쟯쟰쟱쟲쟳쟴쟵쟶쟷쟸쟹쟺쟻쟼쟽쟾쟿저적젂젃전젅젆젇절젉젊젋젌젍젎젏점접젒젓젔정젖젗젘젙젚젛제젝젞젟젠젡젢젣젤젥젦젧젨젩젪젫젬젭젮젯젰젱젲젳젴젵젶젷져젹젺젻젼젽젾젿졀졁졂졃졄졅졆졇졈졉졊졋졌졍졎졏졐졑졒졓졔졕졖졗졘졙졚졛졜졝졞졟졠졡졢졣졤졥졦졧졨졩졪졫졬졭졮졯조족졲졳존졵졶졷졸졹졺졻졼졽졾졿좀좁좂좃좄종좆좇좈좉좊좋좌좍좎좏좐좑좒좓좔좕좖좗좘좙좚좛좜좝좞좟좠좡좢좣좤좥좦좧좨좩좪좫좬좭좮좯좰좱좲좳좴좵좶좷좸좹좺좻좼좽좾좿죀죁죂죃죄죅죆죇죈죉죊죋죌죍죎죏죐죑죒죓죔죕죖죗죘죙죚죛죜죝죞죟죠죡죢죣죤죥죦죧죨죩죪죫죬죭죮죯죰죱죲죳죴죵죶죷죸죹죺죻주죽죾죿준줁줂줃줄줅줆줇줈줉줊줋줌줍줎줏줐중줒줓줔줕줖줗줘줙줚줛줜줝줞줟줠줡줢줣줤줥줦줧줨줩줪줫줬줭줮줯줰줱줲줳줴줵줶줷줸줹줺줻줼줽줾줿쥀쥁쥂쥃쥄쥅쥆쥇쥈쥉쥊쥋쥌쥍쥎쥏쥐쥑쥒쥓쥔쥕쥖쥗쥘쥙쥚쥛쥜쥝쥞쥟쥠쥡쥢쥣쥤쥥쥦쥧쥨쥩쥪쥫쥬쥭쥮쥯쥰쥱쥲쥳쥴쥵쥶쥷쥸쥹쥺쥻쥼쥽쥾쥿즀즁즂즃즄즅즆즇즈즉즊즋즌즍즎즏즐즑즒즓즔즕즖즗즘즙즚즛즜증즞즟즠즡즢즣즤즥즦즧즨즩즪즫즬즭즮즯즰즱즲즳즴즵즶즷즸즹즺즻즼즽즾즿지직짂짃진짅짆짇질짉짊짋짌짍짎짏짐집짒짓짔징짖짗짘짙짚짛짜짝짞짟짠짡짢짣짤짥짦짧짨짩짪짫짬짭짮짯짰짱짲짳짴짵짶짷째짹짺짻짼짽짾짿쨀쨁쨂쨃쨄쨅쨆쨇쨈쨉쨊쨋쨌쨍쨎쨏쨐쨑쨒쨓쨔쨕쨖쨗쨘쨙쨚쨛쨜쨝쨞쨟쨠쨡쨢쨣쨤쨥쨦쨧쨨쨩쨪쨫쨬쨭쨮쨯쨰쨱쨲쨳쨴쨵쨶쨷쨸쨹쨺쨻쨼쨽쨾쨿쩀쩁쩂쩃쩄쩅쩆쩇쩈쩉쩊쩋쩌쩍쩎쩏쩐쩑쩒쩓쩔쩕쩖쩗쩘쩙쩚쩛쩜쩝쩞쩟쩠쩡쩢쩣쩤쩥쩦쩧쩨쩩쩪쩫쩬쩭쩮쩯쩰쩱쩲쩳쩴쩵쩶쩷쩸쩹쩺쩻쩼쩽쩾쩿쪀쪁쪂쪃쪄쪅쪆쪇쪈쪉쪊쪋쪌쪍쪎쪏쪐쪑쪒쪓쪔쪕쪖쪗쪘쪙쪚쪛쪜쪝쪞쪟쪠쪡쪢쪣쪤쪥쪦쪧쪨쪩쪪쪫쪬쪭쪮쪯쪰쪱쪲쪳쪴쪵쪶쪷쪸쪹쪺쪻쪼쪽쪾쪿쫀쫁쫂쫃쫄쫅쫆쫇쫈쫉쫊쫋쫌쫍쫎쫏쫐쫑쫒쫓쫔쫕쫖쫗쫘쫙쫚쫛쫜쫝쫞쫟쫠쫡쫢쫣쫤쫥쫦쫧쫨쫩쫪쫫쫬쫭쫮쫯쫰쫱쫲쫳쫴쫵쫶쫷쫸쫹쫺쫻쫼쫽쫾쫿쬀쬁쬂쬃쬄쬅쬆쬇쬈쬉쬊쬋쬌쬍쬎쬏쬐쬑쬒쬓쬔쬕쬖쬗쬘쬙쬚쬛쬜쬝쬞쬟쬠쬡쬢쬣쬤쬥쬦쬧쬨쬩쬪쬫쬬쬭쬮쬯쬰쬱쬲쬳쬴쬵쬶쬷쬸쬹쬺쬻쬼쬽쬾쬿쭀쭁쭂쭃쭄쭅쭆쭇쭈쭉쭊쭋쭌쭍쭎쭏쭐쭑쭒쭓쭔쭕쭖쭗쭘쭙쭚쭛쭜쭝쭞쭟쭠쭡쭢쭣쭤쭥쭦쭧쭨쭩쭪쭫쭬쭭쭮쭯쭰쭱쭲쭳쭴쭵쭶쭷쭸쭹쭺쭻쭼쭽쭾쭿쮀쮁쮂쮃쮄쮅쮆쮇쮈쮉쮊쮋쮌쮍쮎쮏쮐쮑쮒쮓쮔쮕쮖쮗쮘쮙쮚쮛쮜쮝쮞쮟쮠쮡쮢쮣쮤쮥쮦쮧쮨쮩쮪쮫쮬쮭쮮쮯쮰쮱쮲쮳쮴쮵쮶쮷쮸쮹쮺쮻쮼쮽쮾쮿쯀쯁쯂쯃쯄쯅쯆쯇쯈쯉쯊쯋쯌쯍쯎쯏쯐쯑쯒쯓쯔쯕쯖쯗쯘쯙쯚쯛쯜쯝쯞쯟쯠쯡쯢쯣쯤쯥쯦쯧쯨쯩쯪쯫쯬쯭쯮쯯쯰쯱쯲쯳쯴쯵쯶쯷쯸쯹쯺쯻쯼쯽쯾쯿찀찁찂찃찄찅찆찇찈찉찊찋찌찍찎찏찐찑찒찓찔찕찖찗찘찙찚찛찜찝찞찟찠찡찢찣찤찥찦찧차착찪찫찬찭찮찯찰찱찲찳찴찵찶찷참찹찺찻찼창찾찿챀챁챂챃채책챆챇챈챉챊챋챌챍챎챏챐챑챒챓챔챕챖챗챘챙챚챛챜챝챞챟챠챡챢챣챤챥챦챧챨챩챪챫챬챭챮챯챰챱챲챳챴챵챶챷챸챹챺챻챼챽챾챿첀첁첂첃첄첅첆첇첈첉첊첋첌첍첎첏첐첑첒첓첔첕첖첗처척첚첛천첝첞첟철첡첢첣첤첥첦첧첨첩첪첫첬청첮첯첰첱첲첳체첵첶첷첸첹첺첻첼첽첾첿쳀쳁쳂쳃쳄쳅쳆쳇쳈쳉쳊쳋쳌쳍쳎쳏쳐쳑쳒쳓쳔쳕쳖쳗쳘쳙쳚쳛쳜쳝쳞쳟쳠쳡쳢쳣쳤쳥쳦쳧쳨쳩쳪쳫쳬쳭쳮쳯쳰쳱쳲쳳쳴쳵쳶쳷쳸쳹쳺쳻쳼쳽쳾쳿촀촁촂촃촄촅촆촇초촉촊촋촌촍촎촏촐촑촒촓촔촕촖촗촘촙촚촛촜총촞촟촠촡촢촣촤촥촦촧촨촩촪촫촬촭촮촯촰촱촲촳촴촵촶촷촸촹촺촻촼촽촾촿쵀쵁쵂쵃쵄쵅쵆쵇쵈쵉쵊쵋쵌쵍쵎쵏쵐쵑쵒쵓쵔쵕쵖쵗쵘쵙쵚쵛최쵝쵞쵟쵠쵡쵢쵣쵤쵥쵦쵧쵨쵩쵪쵫쵬쵭쵮쵯쵰쵱쵲쵳쵴쵵쵶쵷쵸쵹쵺쵻쵼쵽쵾쵿춀춁춂춃춄춅춆춇춈춉춊춋춌춍춎춏춐춑춒춓추축춖춗춘춙춚춛출춝춞춟춠춡춢춣춤춥춦춧춨충춪춫춬춭춮춯춰춱춲춳춴춵춶춷춸춹춺춻춼춽춾춿췀췁췂췃췄췅췆췇췈췉췊췋췌췍췎췏췐췑췒췓췔췕췖췗췘췙췚췛췜췝췞췟췠췡췢췣췤췥췦췧취췩췪췫췬췭췮췯췰췱췲췳췴췵췶췷췸췹췺췻췼췽췾췿츀츁츂츃츄츅츆츇츈츉츊츋츌츍츎츏츐츑츒츓츔츕츖츗츘츙츚츛츜츝츞츟츠측츢츣츤츥츦츧츨츩츪츫츬츭츮츯츰츱츲츳츴층츶츷츸츹츺츻츼츽츾츿칀칁칂칃칄칅칆칇칈칉칊칋칌칍칎칏칐칑칒칓칔칕칖칗치칙칚칛친칝칞칟칠칡칢칣칤칥칦칧침칩칪칫칬칭칮칯칰칱칲칳카칵칶칷칸칹칺칻칼칽칾칿캀캁캂캃캄캅캆캇캈캉캊캋캌캍캎캏캐캑캒캓캔캕캖캗캘캙캚캛캜캝캞캟캠캡캢캣캤캥캦캧캨캩캪캫캬캭캮캯캰캱캲캳캴캵캶캷캸캹캺캻캼캽캾캿컀컁컂컃컄컅컆컇컈컉컊컋컌컍컎컏컐컑컒컓컔컕컖컗컘컙컚컛컜컝컞컟컠컡컢컣커컥컦컧컨컩컪컫컬컭컮컯컰컱컲컳컴컵컶컷컸컹컺컻컼컽컾컿케켁켂켃켄켅켆켇켈켉켊켋켌켍켎켏켐켑켒켓켔켕켖켗켘켙켚켛켜켝켞켟켠켡켢켣켤켥켦켧켨켩켪켫켬켭켮켯켰켱켲켳켴켵켶켷켸켹켺켻켼켽켾켿콀콁콂콃콄콅콆콇콈콉콊콋콌콍콎콏콐콑콒콓코콕콖콗콘콙콚콛콜콝콞콟콠콡콢콣콤콥콦콧콨콩콪콫콬콭콮콯콰콱콲콳콴콵콶콷콸콹콺콻콼콽콾콿쾀쾁쾂쾃쾄쾅쾆쾇쾈쾉쾊쾋쾌쾍쾎쾏쾐쾑쾒쾓쾔쾕쾖쾗쾘쾙쾚쾛쾜쾝쾞쾟쾠쾡쾢쾣쾤쾥쾦쾧쾨쾩쾪쾫쾬쾭쾮쾯쾰쾱쾲쾳쾴쾵쾶쾷쾸쾹쾺쾻쾼쾽쾾쾿쿀쿁쿂쿃쿄쿅쿆쿇쿈쿉쿊쿋쿌쿍쿎쿏쿐쿑쿒쿓쿔쿕쿖쿗쿘쿙쿚쿛쿜쿝쿞쿟쿠쿡쿢쿣쿤쿥쿦쿧쿨쿩쿪쿫쿬쿭쿮쿯쿰쿱쿲쿳쿴쿵쿶쿷쿸쿹쿺쿻쿼쿽쿾쿿퀀퀁퀂퀃퀄퀅퀆퀇퀈퀉퀊퀋퀌퀍퀎퀏퀐퀑퀒퀓퀔퀕퀖퀗퀘퀙퀚퀛퀜퀝퀞퀟퀠퀡퀢퀣퀤퀥퀦퀧퀨퀩퀪퀫퀬퀭퀮퀯퀰퀱퀲퀳퀴퀵퀶퀷퀸퀹퀺퀻퀼퀽퀾퀿큀큁큂큃큄큅큆큇큈큉큊큋큌큍큎큏큐큑큒큓큔큕큖큗큘큙큚큛큜큝큞큟큠큡큢큣큤큥큦큧큨큩큪큫크큭큮큯큰큱큲큳클큵큶큷큸큹큺큻큼큽큾큿킀킁킂킃킄킅킆킇킈킉킊킋킌킍킎킏킐킑킒킓킔킕킖킗킘킙킚킛킜킝킞킟킠킡킢킣키킥킦킧킨킩킪킫킬킭킮킯킰킱킲킳킴킵킶킷킸킹킺킻킼킽킾킿타탁탂탃탄탅탆탇탈탉탊탋탌탍탎탏탐탑탒탓탔탕탖탗탘탙탚탛태택탞탟탠탡탢탣탤탥탦탧탨탩탪탫탬탭탮탯탰탱탲탳탴탵탶탷탸탹탺탻탼탽탾탿턀턁턂턃턄턅턆턇턈턉턊턋턌턍턎턏턐턑턒턓턔턕턖턗턘턙턚턛턜턝턞턟턠턡턢턣턤턥턦턧턨턩턪턫턬턭턮턯터턱턲턳턴턵턶턷털턹턺턻턼턽턾턿텀텁텂텃텄텅텆텇텈텉텊텋테텍텎텏텐텑텒텓텔텕텖텗텘텙텚텛템텝텞텟텠텡텢텣텤텥텦텧텨텩텪텫텬텭텮텯텰텱텲텳텴텵텶텷텸텹텺텻텼텽텾텿톀톁톂톃톄톅톆톇톈톉톊톋톌톍톎톏톐톑톒톓톔톕톖톗톘톙톚톛톜톝톞톟토톡톢톣톤톥톦톧톨톩톪톫톬톭톮톯톰톱톲톳톴통톶톷톸톹톺톻톼톽톾톿퇀퇁퇂퇃퇄퇅퇆퇇퇈퇉퇊퇋퇌퇍퇎퇏퇐퇑퇒퇓퇔퇕퇖퇗퇘퇙퇚퇛퇜퇝퇞퇟퇠퇡퇢퇣퇤퇥퇦퇧퇨퇩퇪퇫퇬퇭퇮퇯퇰퇱퇲퇳퇴퇵퇶퇷퇸퇹퇺퇻퇼퇽퇾퇿툀툁툂툃툄툅툆툇툈툉툊툋툌툍툎툏툐툑툒툓툔툕툖툗툘툙툚툛툜툝툞툟툠툡툢툣툤툥툦툧툨툩툪툫투툭툮툯툰툱툲툳툴툵툶툷툸툹툺툻툼툽툾툿퉀퉁퉂퉃퉄퉅퉆퉇퉈퉉퉊퉋퉌퉍퉎퉏퉐퉑퉒퉓퉔퉕퉖퉗퉘퉙퉚퉛퉜퉝퉞퉟퉠퉡퉢퉣퉤퉥퉦퉧퉨퉩퉪퉫퉬퉭퉮퉯퉰퉱퉲퉳퉴퉵퉶퉷퉸퉹퉺퉻퉼퉽퉾퉿튀튁튂튃튄튅튆튇튈튉튊튋튌튍튎튏튐튑튒튓튔튕튖튗튘튙튚튛튜튝튞튟튠튡튢튣튤튥튦튧튨튩튪튫튬튭튮튯튰튱튲튳튴튵튶튷트특튺튻튼튽튾튿틀틁틂틃틄틅틆틇틈틉틊틋틌틍틎틏틐틑틒틓틔틕틖틗틘틙틚틛틜틝틞틟틠틡틢틣틤틥틦틧틨틩틪틫틬틭틮틯티틱틲틳틴틵틶틷틸틹틺틻틼틽틾틿팀팁팂팃팄팅팆팇팈팉팊팋파팍팎팏판팑팒팓팔팕팖팗팘팙팚팛팜팝팞팟팠팡팢팣팤팥팦팧패팩팪팫팬팭팮팯팰팱팲팳팴팵팶팷팸팹팺팻팼팽팾팿퍀퍁퍂퍃퍄퍅퍆퍇퍈퍉퍊퍋퍌퍍퍎퍏퍐퍑퍒퍓퍔퍕퍖퍗퍘퍙퍚퍛퍜퍝퍞퍟퍠퍡퍢퍣퍤퍥퍦퍧퍨퍩퍪퍫퍬퍭퍮퍯퍰퍱퍲퍳퍴퍵퍶퍷퍸퍹퍺퍻퍼퍽퍾퍿펀펁펂펃펄펅펆펇펈펉펊펋펌펍펎펏펐펑펒펓펔펕펖펗페펙펚펛펜펝펞펟펠펡펢펣펤펥펦펧펨펩펪펫펬펭펮펯펰펱펲펳펴펵펶펷편펹펺펻펼펽펾펿폀폁폂폃폄폅폆폇폈평폊폋폌폍폎폏폐폑폒폓폔폕폖폗폘폙폚폛폜폝폞폟폠폡폢폣폤폥폦폧폨폩폪폫포폭폮폯폰폱폲폳폴폵폶폷폸폹폺폻폼폽폾폿퐀퐁퐂퐃퐄퐅퐆퐇퐈퐉퐊퐋퐌퐍퐎퐏퐐퐑퐒퐓퐔퐕퐖퐗퐘퐙퐚퐛퐜퐝퐞퐟퐠퐡퐢퐣퐤퐥퐦퐧퐨퐩퐪퐫퐬퐭퐮퐯퐰퐱퐲퐳퐴퐵퐶퐷퐸퐹퐺퐻퐼퐽퐾퐿푀푁푂푃푄푅푆푇푈푉푊푋푌푍푎푏푐푑푒푓푔푕푖푗푘푙푚푛표푝푞푟푠푡푢푣푤푥푦푧푨푩푪푫푬푭푮푯푰푱푲푳푴푵푶푷푸푹푺푻푼푽푾푿풀풁풂풃풄풅풆풇품풉풊풋풌풍풎풏풐풑풒풓풔풕풖풗풘풙풚풛풜풝풞풟풠풡풢풣풤풥풦풧풨풩풪풫풬풭풮풯풰풱풲풳풴풵풶풷풸풹풺풻풼풽풾풿퓀퓁퓂퓃퓄퓅퓆퓇퓈퓉퓊퓋퓌퓍퓎퓏퓐퓑퓒퓓퓔퓕퓖퓗퓘퓙퓚퓛퓜퓝퓞퓟퓠퓡퓢퓣퓤퓥퓦퓧퓨퓩퓪퓫퓬퓭퓮퓯퓰퓱퓲퓳퓴퓵퓶퓷퓸퓹퓺퓻퓼퓽퓾퓿픀픁픂픃프픅픆픇픈픉픊픋플픍픎픏픐픑픒픓픔픕픖픗픘픙픚픛픜픝픞픟픠픡픢픣픤픥픦픧픨픩픪픫픬픭픮픯픰픱픲픳픴픵픶픷픸픹픺픻피픽픾픿핀핁핂핃필핅핆핇핈핉핊핋핌핍핎핏핐핑핒핓핔핕핖핗하학핚핛한핝핞핟할핡핢핣핤핥핦핧함합핪핫핬항핮핯핰핱핲핳해핵핶핷핸핹핺핻핼핽핾핿햀햁햂햃햄햅햆햇했행햊햋햌햍햎햏햐햑햒햓햔햕햖햗햘햙햚햛햜햝햞햟햠햡햢햣햤향햦햧햨햩햪햫햬햭햮햯햰햱햲햳햴햵햶햷햸햹햺햻햼햽햾햿헀헁헂헃헄헅헆헇허헉헊헋헌헍헎헏헐헑헒헓헔헕헖헗험헙헚헛헜헝헞헟헠헡헢헣헤헥헦헧헨헩헪헫헬헭헮헯헰헱헲헳헴헵헶헷헸헹헺헻헼헽헾헿혀혁혂혃현혅혆혇혈혉혊혋혌혍혎혏혐협혒혓혔형혖혗혘혙혚혛혜혝혞혟혠혡혢혣혤혥혦혧혨혩혪혫혬혭혮혯혰혱혲혳혴혵혶혷호혹혺혻혼혽혾혿홀홁홂홃홄홅홆홇홈홉홊홋홌홍홎홏홐홑홒홓화확홖홗환홙홚홛활홝홞홟홠홡홢홣홤홥홦홧홨황홪홫홬홭홮홯홰홱홲홳홴홵홶홷홸홹홺홻홼홽홾홿횀횁횂횃횄횅횆횇횈횉횊횋회획횎횏횐횑횒횓횔횕횖횗횘횙횚횛횜횝횞횟횠횡횢횣횤횥횦횧효횩횪횫횬횭횮횯횰횱횲횳횴횵횶횷횸횹횺횻횼횽횾횿훀훁훂훃후훅훆훇훈훉훊훋훌훍훎훏훐훑훒훓훔훕훖훗훘훙훚훛훜훝훞훟훠훡훢훣훤훥훦훧훨훩훪훫훬훭훮훯훰훱훲훳훴훵훶훷훸훹훺훻훼훽훾훿휀휁휂휃휄휅휆휇휈휉휊휋휌휍휎휏휐휑휒휓휔휕휖휗휘휙휚휛휜휝휞휟휠휡휢휣휤휥휦휧휨휩휪휫휬휭휮휯휰휱휲휳휴휵휶휷휸휹휺휻휼휽휾휿흀흁흂흃흄흅흆흇흈흉흊흋흌흍흎흏흐흑흒흓흔흕흖흗흘흙흚흛흜흝흞흟흠흡흢흣흤흥흦흧흨흩흪흫희흭흮흯흰흱흲흳흴흵흶흷흸흹흺흻흼흽흾흿힀힁힂힃힄힅힆힇히힉힊힋힌힍힎힏힐힑힒힓힔힕힖힗힘힙힚힛힜힝힞힟힠힡힢힣ힰힱힲힳힴힵힶힷힸힹힺힻힼힽힾힿퟀퟁퟂퟃퟄퟅퟆퟋퟌퟍퟎퟏퟐퟑퟒퟓퟔퟕퟖퟗퟘퟙퟚퟛퟜퟝퟞퟟퟠퟡퟢퟣퟤퟥퟦퟧퟨퟩퟪퟫퟬퟭퟮퟯퟰퟱퟲퟳퟴퟵퟶퟷퟸퟹퟺퟻ???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????􏰀???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????豈更車賈滑串句龜龜契金喇奈懶癩羅蘿螺裸邏樂洛烙珞落酪駱亂卵欄爛蘭鸞嵐濫藍襤拉臘蠟廊朗浪狼郎來冷勞擄櫓爐盧老蘆虜路露魯鷺碌祿綠菉錄鹿論壟弄籠聾牢磊賂雷壘屢樓淚漏累縷陋勒肋凜凌稜綾菱陵讀拏樂諾丹寧怒率異北磻便復不泌數索參塞省葉說殺辰沈拾若掠略亮兩凉梁糧良諒量勵呂女廬旅濾礪閭驪麗黎力曆歷轢年憐戀撚漣煉璉秊練聯輦蓮連鍊列劣咽烈裂說廉念捻殮簾獵令囹寧嶺怜玲瑩羚聆鈴零靈領例禮醴隸惡了僚寮尿料樂燎療蓼遼龍暈阮劉杻柳流溜琉留硫紐類六戮陸倫崙淪輪律慄栗率隆利吏履易李梨泥理痢罹裏裡里離匿溺吝燐璘藺隣鱗麟林淋臨立笠粒狀炙識什茶刺切度拓糖宅洞暴輻行降見廓兀嗀﨎﨏塚﨑晴﨓﨔凞猪益礼神祥福靖精羽﨟蘒﨡諸﨣﨤逸都﨧﨨﨩飯飼館鶴郞隷侮僧免勉勤卑喝嘆器塀墨層屮悔慨憎懲敏既暑梅海渚漢煮爫琢碑社祉祈祐祖祝禍禎穀突節練縉繁署者臭艹艹著褐視謁謹賓贈辶逸難響頻恵𤋮舘並况全侀充冀勇勺喝啕喙嗢塚墳奄奔婢嬨廒廙彩徭惘慎愈憎慠懲戴揄搜摒敖晴朗望杖歹殺流滛滋漢瀞煮瞧爵犯猪瑱甆画瘝瘟益盛直睊着磌窱節类絛練缾者荒華蝹襁覆視調諸請謁諾諭謹變贈輸遲醙鉶陼難靖韛響頋頻鬒龜𢡊𢡄𣏕㮝䀘䀹𥉉𥳐𧻓齃龎fffiflffifflſtstﬓﬔﬕﬖﬗיִﬞײַﬠﬡﬢﬣﬤﬥﬦﬧﬨ﬩שׁשׂשּׁשּׂאַאָאּבּגּדּהּוּזּטּיּךּכּלּמּנּסּףּפּצּקּרּשּתּוֹבֿכֿפֿﭏﭐﭑﭒﭓﭔﭕﭖﭗﭘﭙﭚﭛﭜﭝﭞﭟﭠﭡﭢﭣﭤﭥﭦﭧﭨﭩﭪﭫﭬﭭﭮﭯﭰﭱﭲﭳﭴﭵﭶﭷﭸﭹﭺﭻﭼﭽﭾﭿﮀﮁﮂﮃﮄﮅﮆﮇﮈﮉﮊﮋﮌﮍﮎﮏﮐﮑﮒﮓﮔﮕﮖﮗﮘﮙﮚﮛﮜﮝﮞﮟﮠﮡﮢﮣﮤﮥﮦﮧﮨﮩﮪﮫﮬﮭﮮﮯﮰﮱ﮲﮳﮴﮵﮶﮷﮸﮹﮺﮻﮼﮽﮾﮿﯀﯁ﯓﯔﯕﯖﯗﯘﯙﯚﯛﯜﯝﯞﯟﯠﯡﯢﯣﯤﯥﯦﯧﯨﯩﯪﯫﯬﯭﯮﯯﯰﯱﯲﯳﯴﯵﯶﯷﯸﯹﯺﯻﯼﯽﯾﯿﰀﰁﰂﰃﰄﰅﰆﰇﰈﰉﰊﰋﰌﰍﰎﰏﰐﰑﰒﰓﰔﰕﰖﰗﰘﰙﰚﰛﰜﰝﰞﰟﰠﰡﰢﰣﰤﰥﰦﰧﰨﰩﰪﰫﰬﰭﰮﰯﰰﰱﰲﰳﰴﰵﰶﰷﰸﰹﰺﰻﰼﰽﰾﰿﱀﱁﱂﱃﱄﱅﱆﱇﱈﱉﱊﱋﱌﱍﱎﱏﱐﱑﱒﱓﱔﱕﱖﱗﱘﱙﱚﱛﱜﱝﱞﱟﱠﱡﱢﱣﱤﱥﱦﱧﱨﱩﱪﱫﱬﱭﱮﱯﱰﱱﱲﱳﱴﱵﱶﱷﱸﱹﱺﱻﱼﱽﱾﱿﲀﲁﲂﲃﲄﲅﲆﲇﲈﲉﲊﲋﲌﲍﲎﲏﲐﲑﲒﲓﲔﲕﲖﲗﲘﲙﲚﲛﲜﲝﲞﲟﲠﲡﲢﲣﲤﲥﲦﲧﲨﲩﲪﲫﲬﲭﲮﲯﲰﲱﲲﲳﲴﲵﲶﲷﲸﲹﲺﲻﲼﲽﲾﲿﳀﳁﳂﳃﳄﳅﳆﳇﳈﳉﳊﳋﳌﳍﳎﳏﳐﳑﳒﳓﳔﳕﳖﳗﳘﳙﳚﳛﳜﳝﳞﳟﳠﳡﳢﳣﳤﳥﳦﳧﳨﳩﳪﳫﳬﳭﳮﳯﳰﳱﳲﳳﳴﳵﳶﳷﳸﳹﳺﳻﳼﳽﳾﳿﴀﴁﴂﴃﴄﴅﴆﴇﴈﴉﴊﴋﴌﴍﴎﴏﴐﴑﴒﴓﴔﴕﴖﴗﴘﴙﴚﴛﴜﴝﴞﴟﴠﴡﴢﴣﴤﴥﴦﴧﴨﴩﴪﴫﴬﴭﴮﴯﴰﴱﴲﴳﴴﴵﴶﴷﴸﴹﴺﴻﴼﴽ﴾﴿ﵐﵑﵒﵓﵔﵕﵖﵗﵘﵙﵚﵛﵜﵝﵞﵟﵠﵡﵢﵣﵤﵥﵦﵧﵨﵩﵪﵫﵬﵭﵮﵯﵰﵱﵲﵳﵴﵵﵶﵷﵸﵹﵺﵻﵼﵽﵾﵿﶀﶁﶂﶃﶄﶅﶆﶇﶈﶉﶊﶋﶌﶍﶎﶏﶒﶓﶔﶕﶖﶗﶘﶙﶚﶛﶜﶝﶞﶟﶠﶡﶢﶣﶤﶥﶦﶧﶨﶩﶪﶫﶬﶭﶮﶯﶰﶱﶲﶳﶴﶵﶶﶷﶸﶹﶺﶻﶼﶽﶾﶿﷀﷁﷂﷃﷄﷅﷆﷇﷰﷱﷲﷳﷴﷵﷶﷷﷸﷹﷺﷻ﷼﷽︀︁︂︃︄︅︆︇︈︉︊︋︌︍︎️︐︑︒︓︔︕︖︗︘︙︠︡︢︣︤︥︦︰︱︲︳︴︵︶︷︸︹︺︻︼︽︾︿﹀﹁﹂﹃﹄﹅﹆﹇﹈﹉﹊﹋﹌﹍﹎﹏﹐﹑﹒﹔﹕﹖﹗﹘﹙﹚﹛﹜﹝﹞﹟﹠﹡﹢﹣﹤﹥﹦﹨﹩﹪﹫ﹰﹱﹲﹳﹴﹶﹷﹸﹹﹺﹻﹼﹽﹾﹿﺀﺁﺂﺃﺄﺅﺆﺇﺈﺉﺊﺋﺌﺍﺎﺏﺐﺑﺒﺓﺔﺕﺖﺗﺘﺙﺚﺛﺜﺝﺞﺟﺠﺡﺢﺣﺤﺥﺦﺧﺨﺩﺪﺫﺬﺭﺮﺯﺰﺱﺲﺳﺴﺵﺶﺷﺸﺹﺺﺻﺼﺽﺾﺿﻀﻁﻂﻃﻄﻅﻆﻇﻈﻉﻊﻋﻌﻍﻎﻏﻐﻑﻒﻓﻔﻕﻖﻗﻘﻙﻚﻛﻜﻝﻞﻟﻠﻡﻢﻣﻤﻥﻦﻧﻨﻩﻪﻫﻬﻭﻮﻯﻰﻱﻲﻳﻴﻵﻶﻷﻸﻹﻺﻻﻼ!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~⦅⦆。「」、・ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙゚ᅠᄀᄁᆪᄂᆬᆭᄃᄄᄅᆰᆱᆲᆳᆴᆵᄚᄆᄇᄈᄡᄉᄊᄋᄌᄍᄎᄏᄐᄑ하ᅢᅣᅤᅥᅦᅧᅨᅩᅪᅫᅬᅭᅮᅯᅰᅱᅲᅳᅴᅵ¢£¬ ̄¦¥₩│←↑→↓■○�‬‬‬ diff --git a/contrib/test/dotnet/ExpectedOutput/ScalarFunctionsSQLBatch.out b/contrib/test/dotnet/ExpectedOutput/ScalarFunctionsSQLBatch.out new file mode 100644 index 00000000000..aaa0c8f8eda --- /dev/null +++ b/contrib/test/dotnet/ExpectedOutput/ScalarFunctionsSQLBatch.out @@ -0,0 +1,79 @@ +#Q#create schema tests +#Q#CREATE FUNCTION tests.multiply (@a int, @b int) RETURNS int AS BEGIN RETURN @a * @b; END; +#Q#Select tests.multiply(1, 1) +#D#int +1 +#Q#Select tests.multiply(1, 0) +#D#int +0 +#Q#Select tests.multiply(1, -1) +#D#int +-1 +#Q#Select tests.multiply(1.1, -1.1) +#D#int +-1 +#Q#Select tests.multiply(1, -1.00000001) +#D#int +-1 +#Q#Select tests.multiply(1000000000, 1000000000) +#Q#select tests.multiply(-1, tests.multiply(-10,20)) +#D#int +200 +#Q#select tests.multiply(0xe, 0xe) +#D#int +196 +#Q#select tests.multiply('100', '100') +#D#int +10000 +#Q#CREATE FUNCTION tests.multiply1() RETURNS int AS BEGIN RETURN 100 * 1; END; +#Q#select tests.multiply1() +#D#int +100 +#Q#select tests.multiply(1, tests.multiply1()); +#D#int +100 +#Q#select tests.multiply(tests.multiply(-1,1), tests.multiply1()) +#D#int +-100 +#Q#CREATE FUNCTION tests.func3() Returns int AS BEGIN RETURN tests.multiply(1,tests.multiply1()); END; +#Q#select tests.func3() +#D#int +100 +#Q#CREATE FUNCTION tests.func4() Returns int AS BEGIN return 1.1 END; +#Q#Select tests.func4() +#D#int +1 +#Q#CREATE FUNCTION tests.func5() Returns varchar As begin RETURN('abc''abc'); END; +#Q#select tests.func5() +#D#varchar +a +#Q#CREATE FUNCTION tests.func7(@a int) Returns varchar(100) As begin SET @a = 100 RETURN(@a); END; +#Q#select tests.func7(1) +#D#varchar +100 +#Q#select tests.multiply(@a,@b) +#D#int +-200 +#Q#select tests.multiply1() +#D#int +100 +#Q#select tests.func3() +#D#int +100 +#Q#select tests.func4() +#D#int +1 +#Q#select tests.func5() +#D#varchar +a +#Q#select tests.func7() +#E#function master_tests.func7() does not exist +#Q#DROP FUNCTION tests.mutliply +#E#could not find a function named "master_tests.mutliply" +#Q#DROP FUNCTION tests.multiply1 +#Q#DROP FUNCTION tests.func3 +#Q#DROP FUNCTION tests.func4 +#Q#DROP FUNCTION tests.func5 +#Q#DROP FUNCTION tests.func7 +#Q#drop schema tests +#E#cannot drop schema master_tests because other objects depend on it diff --git a/contrib/test/dotnet/ExpectedOutput/TestAuthentication.out b/contrib/test/dotnet/ExpectedOutput/TestAuthentication.out new file mode 100644 index 00000000000..005880c45f6 --- /dev/null +++ b/contrib/test/dotnet/ExpectedOutput/TestAuthentication.out @@ -0,0 +1,46 @@ +#Q#Data Source = 10.200.222.164; Initial Catalog = demo; User ID = kushaal; Password = hello;Pooling=false; +#E#database "demo" does not exist +#Q#Data Source = 10.200.222.164; Initial Catalog = demo; User ID = kushaal; Password = hello;Pooling=false; +#E#database "demo" does not exist +#Q#Data Source = 10.200.222.164; Initial Catalog = ; User ID = kushaal; Password = hello;Pooling=false; +PASSED +#Q#Data Source = 10.200.222.164; Initial Catalog = master; User ID = @; Password = hello;Pooling=false; +#E#password authentication failed for user "@" +#Q#Data Source = 10.200.222.164; Initial Catalog = master; User ID = ; Password = hello;Pooling=false; +#E#no PostgreSQL user name specified in startup packet +#Q#Data Source = 10.200.222.164; Initial Catalog = master; User ID = kushaal; Password = kushaal;Pooling=false; +#E#password authentication failed for user "kushaal" +#Q#Data Source = 10.200.222.164; Initial Catalog = master; User ID = kushaal; Password = ;Pooling=false; +#E#invalid TDS authentication request for host "10.94.231.241", user "kushaal", database "master" +#Q#Data Source = 10.200.222.164; Initial Catalog = master; User ID = kushaal; Password = hello;Pooling=false; +PASSED +#Q#Data Source = 10.200.222.164; Initial Catalog = demo; User ID = kushaal1; Password = hello;Pooling=false; +#E#password authentication failed for user "kushaal1" +#Q#Data Source = 10.200.222.164; Initial Catalog = demo; User ID = kushaal; Password = hell;Pooling=false; +#E#password authentication failed for user "kushaal" +#Q#Data Source = 10.200.222.164; Initial Catalog = demo; User ID = kushaal; Password = hell;Pooling=false;ConnectRetryCount=2 +#E#password authentication failed for user "kushaal" +#Q#Data Source = 10.200.222.164; Initial Catalog = master; User ID = kushaal; Password = hello;Pooling=false;Language=English +PASSED +#Q#Data Source = 10.200.222.164; Initial Catalog = master; User ID = kushaal; Password = hello;Pooling=false;Language=French +PASSED +#Q#Data Source = 10.200.222.164; Initial Catalog = master; User ID = kushaal; Password = hello;Pooling=false;Language= +PASSED +#Q#Data Source = 10.200.222.164; Initial Catalog = master; User ID = kushaal; Password = hello;Pooling=false;Timeout=5 +PASSED +#Q#Data Source = 10.200.222.164; Initial Catalog = master; User ID = kushaal; Password = hello;Pooling=false;Timeout=0 +PASSED +#Q#Data Source = 10.200.222.164; Initial Catalog = master; User ID = kushaal; Password = hello;Pooling=false;Encrypt=true +#E#The instance of SQL Server you attempted to connect to does not support encryption. +#Q#Data Source = 10.200.222.164; Initial Catalog = master; User ID = kushaal; Password = hello;Pooling=false;Encrypt=false +PASSED +#Q#Data Source = 10.200.222.164; Initial Catalog = master; User ID = kushaal; Password = hello;Pooling=false;Max Pool Size=1 +PASSED +#Q#Data Source = 10.200.222.164; Initial Catalog = master; User ID = kushaal; Password = hello;Pooling=false;Packet Size=512 +PASSED +#Q#Data Source = 10.200.222.164; Initial Catalog = master; User ID = kushaal; Password = hello;Pooling=false;Packet Size=32768 +#E#Invalid packet size: 32768, Packet size has to be zero or a number between 512 and 32767. +#Q#Data Source = 10.200.222.164; Initial Catalog = master; User ID = kushaal; Password = hello;Pooling=false;TrustServerCertificate=true +PASSED +#Q#Data Source = 10.200.222.164; Initial Catalog = master; User ID = kushaal; Password = hello;Pooling=false;TrustServerCertificate=false +PASSED diff --git a/contrib/test/dotnet/ExpectedOutput/TestBIT.out b/contrib/test/dotnet/ExpectedOutput/TestBIT.out new file mode 100644 index 00000000000..f3d5bdef65c --- /dev/null +++ b/contrib/test/dotnet/ExpectedOutput/TestBIT.out @@ -0,0 +1,21 @@ +#Q#CREATE TABLE BIT_dt (a BIT) +#Q# INSERT INTO BIT_dt(a) values(@a) +#Q# INSERT INTO BIT_dt(a) values(@a) +#Q# INSERT INTO BIT_dt(a) values(@a) +#Q#SELECT * FROM BIT_dt; +#D#bit +False +True + +#Q#INSERT INTO BIT_dt(a) values(1) +#Q#INSERT INTO BIT_dt(a) values(0) +#Q#INSERT INTO BIT_dt(a) values(NULL) +#Q#SELECT * FROM BIT_dt; +#D#bit +False +True + +True +False + +#Q#DROP TABLE BIT_dt; diff --git a/contrib/test/dotnet/ExpectedOutput/TestBigInt.out b/contrib/test/dotnet/ExpectedOutput/TestBigInt.out new file mode 100644 index 00000000000..c4acfaf24ac --- /dev/null +++ b/contrib/test/dotnet/ExpectedOutput/TestBigInt.out @@ -0,0 +1,56 @@ +#Q#CREATE TABLE BIGINT_dt (a BIGINT) +#Q# INSERT INTO BIGINT_dt(a) values(@a) +#Q# INSERT INTO BIGINT_dt(a) values(@a) +#Q# INSERT INTO BIGINT_dt(a) values(@a) +#Q# INSERT INTO BIGINT_dt(a) values(@a) +#Q# INSERT INTO BIGINT_dt(a) values(@a) +#Q# INSERT INTO BIGINT_dt(a) values(@a) +#Q# INSERT INTO BIGINT_dt(a) values(@a) +#Q# INSERT INTO BIGINT_dt(a) values(@a) +#Q# INSERT INTO BIGINT_dt(a) values(@a) +#Q# INSERT INTO BIGINT_dt(a) values(@a) +#Q#SELECT * FROM BIGINT_dt; +#D#bigint +0 +-10 +122100 +1202 +-24112329 +-2 +86 +-9223372036854775808 +9223372036854775807 + +#Q#INSERT INTO BIGINT_dt(a) values(0) +#Q#INSERT INTO BIGINT_dt(a) values(-120) +#Q#INSERT INTO BIGINT_dt(a) values(00100) +#Q#INSERT INTO BIGINT_dt(a) values(-004) +#Q#INSERT INTO BIGINT_dt(a) values(-012245532534) +#Q#INSERT INTO BIGINT_dt(a) values(-0000000000000000002) +#Q#INSERT INTO BIGINT_dt(a) values(0000000000000000086) +#Q#INSERT INTO BIGINT_dt(a) values(-9223372036854775808) +#Q#INSERT INTO BIGINT_dt(a) values(9223372036854775807) +#Q#INSERT INTO BIGINT_dt(a) values(NULL) +#Q#SELECT * FROM BIGINT_dt; +#D#bigint +0 +-10 +122100 +1202 +-24112329 +-2 +86 +-9223372036854775808 +9223372036854775807 + +0 +-120 +100 +-4 +-12245532534 +-2 +86 +-9223372036854775808 +9223372036854775807 + +#Q#DROP TABLE BIGINT_dt; diff --git a/contrib/test/dotnet/ExpectedOutput/TestBinary.out b/contrib/test/dotnet/ExpectedOutput/TestBinary.out new file mode 100644 index 00000000000..f9514be88bc --- /dev/null +++ b/contrib/test/dotnet/ExpectedOutput/TestBinary.out @@ -0,0 +1,9 @@ +#Q#CREATE TABLE BINARY_dt(a BINARY(8), b VARBINARY(10)); +#Q#INSERT INTO BINARY_dt(a, b) values (1234, 12345); +#Q#INSERT INTO BINARY_dt(a, b) values (NULL, NULL); +#Q#SELECT * FROM BINARY_dt +#D#binary#!#varbinary +0000004210#!#004857 + + +#Q#DROP TABLE BINARY_dt diff --git a/contrib/test/dotnet/ExpectedOutput/TestChar.out b/contrib/test/dotnet/ExpectedOutput/TestChar.out new file mode 100644 index 00000000000..730f3372511 --- /dev/null +++ b/contrib/test/dotnet/ExpectedOutput/TestChar.out @@ -0,0 +1,38 @@ +#Q#CREATE TABLE CHAR_dt (a CHAR(20), b NCHAR(20)) +#Q# INSERT INTO CHAR_dt(a, b) values(@a, @b) +#Q# INSERT INTO CHAR_dt(a, b) values(@a, @b) +#Q# INSERT INTO CHAR_dt(a, b) values(@a, @b) +#Q# INSERT INTO CHAR_dt(a, b) values(@a, @b) +#Q# INSERT INTO CHAR_dt(a, b) values(@a, @b) +#Q# INSERT INTO CHAR_dt(a, b) values(@a, @b) +#Q# INSERT INTO CHAR_dt(a, b) values(@a, @b) +#E#value too long for type character(20) +#Q#SELECT * FROM CHAR_dt; +#D#char#!#nchar +Dipesh #!#Dhameliya +Dipesh #!#Dhameliya +D #!#🤣😃 + #!# + #!#😊😋😎😍😅😆 +#!# +#Q#INSERT INTO CHAR_dt(a,b) values('Dipesh','Dhameliya') +#Q#INSERT INTO CHAR_dt(a,b) values(' Dipesh',' Dhameliya') +#Q#INSERT INTO CHAR_dt(a,b) values(' D',N' 🤣😃') +#Q#INSERT INTO CHAR_dt(a,b) values(' ',' ') +#Q#INSERT INTO CHAR_dt(a,b) values(' ',N'😊😋😎😍😅😆') +#Q#INSERT INTO CHAR_dt(a,b) values(NULL,NULL) +#Q#SELECT * FROM CHAR_dt; +#D#char#!#nchar +Dipesh #!#Dhameliya +Dipesh #!#Dhameliya +D #!#🤣😃 + #!# + #!#😊😋😎😍😅😆 +#!# +Dipesh #!#Dhameliya + Dipesh #!# Dhameliya + D #!# 🤣😃 + #!# + #!#😊😋😎😍😅😆 +#!# +#Q#DROP TABLE CHAR_dt; diff --git a/contrib/test/dotnet/ExpectedOutput/TestDate.out b/contrib/test/dotnet/ExpectedOutput/TestDate.out new file mode 100644 index 00000000000..580846d11b7 --- /dev/null +++ b/contrib/test/dotnet/ExpectedOutput/TestDate.out @@ -0,0 +1,31 @@ +#Q#CREATE TABLE DATE_dt (a DATE) +#Q# INSERT INTO DATE_dt(a) values(@a) +#Q# INSERT INTO DATE_dt(a) values(@a) +#Q# INSERT INTO DATE_dt(a) values(@a) +#Q# INSERT INTO DATE_dt(a) values(@a) +#Q# INSERT INTO DATE_dt(a) values(@a) +#Q#SELECT * FROM DATE_dt; +#D#date +12/13/2000 00:00:00 +02/28/2000 00:00:00 +01/01/0001 00:00:00 +12/31/9999 00:00:00 + +#Q#INSERT INTO DATE_dt(a) values('2000-12-13') +#Q#INSERT INTO DATE_dt(a) values('1900-02-28') +#Q#INSERT INTO DATE_dt(a) values('0001-01-01') +#Q#INSERT INTO DATE_dt(a) values('9999-12-31') +#Q#INSERT INTO DATE_dt(a) values(NULL) +#Q#SELECT * FROM DATE_dt; +#D#date +12/13/2000 00:00:00 +02/28/2000 00:00:00 +01/01/0001 00:00:00 +12/31/9999 00:00:00 + +12/13/2000 00:00:00 +02/28/1900 00:00:00 +01/01/0001 00:00:00 +12/31/9999 00:00:00 + +#Q#DROP TABLE DATE_dt; diff --git a/contrib/test/dotnet/ExpectedOutput/TestDatetime.out b/contrib/test/dotnet/ExpectedOutput/TestDatetime.out new file mode 100644 index 00000000000..9d2c5cccaa0 --- /dev/null +++ b/contrib/test/dotnet/ExpectedOutput/TestDatetime.out @@ -0,0 +1,86 @@ +#Q#CREATE TABLE DATETIME_dt (a DATETIME) +#Q# INSERT INTO DATETIME_dt(a) values(@a) +#Q# INSERT INTO DATETIME_dt(a) values(@a) +#Q# INSERT INTO DATETIME_dt(a) values(@a) +#Q# INSERT INTO DATETIME_dt(a) values(@a) +#Q# INSERT INTO DATETIME_dt(a) values(@a) +#Q# INSERT INTO DATETIME_dt(a) values(@a) +#Q# INSERT INTO DATETIME_dt(a) values(@a) +#Q# INSERT INTO DATETIME_dt(a) values(@a) +#Q# INSERT INTO DATETIME_dt(a) values(@a) +#Q# INSERT INTO DATETIME_dt(a) values(@a) +#Q# INSERT INTO DATETIME_dt(a) values(@a) +#Q# INSERT INTO DATETIME_dt(a) values(@a) +#Q# INSERT INTO DATETIME_dt(a) values(@a) +#Q# INSERT INTO DATETIME_dt(a) values(@a) +#Q# INSERT INTO DATETIME_dt(a) values(@a) +#Q# INSERT INTO DATETIME_dt(a) values(@a) +#Q#SELECT * FROM DATETIME_dt; +#D#datetime +12/13/2000 12:58:23 +02/28/2000 23:59:59 +02/28/2000 23:59:59 +02/28/2000 23:59:59 +02/28/2000 23:59:59 +02/28/2000 23:59:59 +02/28/2000 23:59:59 +02/28/2000 23:59:59 +02/28/2000 23:59:59 +02/28/2000 23:59:59 +02/28/2000 23:59:59 +02/29/2000 00:00:00 +02/28/1900 23:59:59 +01/01/1753 00:00:00 +12/31/9999 23:59:59 + +#Q#INSERT INTO DATETIME_dt(a) values('2000-12-13 12:58:23.123') +#Q#INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.989') +#Q#INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.990') +#Q#INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.991') +#Q#INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.992') +#Q#INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.993') +#Q#INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.994') +#Q#INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.995') +#Q#INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.996') +#Q#INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.997') +#Q#INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.998') +#Q#INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.999') +#Q#INSERT INTO DATETIME_dt(a) values('2000-02-28 23:59:59.989') +#Q#INSERT INTO DATETIME_dt(a) values('1753-01-01 00:00:00.000') +#Q#INSERT INTO DATETIME_dt(a) values('9999-12-31 23:59:59.997') +#Q#INSERT INTO DATETIME_dt(a) values(NULL) +#Q#SELECT * FROM DATETIME_dt; +#D#datetime +12/13/2000 12:58:23 +02/28/2000 23:59:59 +02/28/2000 23:59:59 +02/28/2000 23:59:59 +02/28/2000 23:59:59 +02/28/2000 23:59:59 +02/28/2000 23:59:59 +02/28/2000 23:59:59 +02/28/2000 23:59:59 +02/28/2000 23:59:59 +02/28/2000 23:59:59 +02/29/2000 00:00:00 +02/28/1900 23:59:59 +01/01/1753 00:00:00 +12/31/9999 23:59:59 + +12/13/2000 12:58:23 +02/28/1900 23:59:59 +02/28/1900 23:59:59 +02/28/1900 23:59:59 +02/28/1900 23:59:59 +02/28/1900 23:59:59 +02/28/1900 23:59:59 +02/28/1900 23:59:59 +02/28/1900 23:59:59 +02/28/1900 23:59:59 +02/28/1900 23:59:59 +03/01/1900 00:00:00 +02/28/2000 23:59:59 +01/01/1753 00:00:00 +12/31/9999 23:59:59 + +#Q#DROP TABLE DATETIME_dt; diff --git a/contrib/test/dotnet/ExpectedOutput/TestDatetime2.out b/contrib/test/dotnet/ExpectedOutput/TestDatetime2.out new file mode 100644 index 00000000000..4a5f71a2f2e --- /dev/null +++ b/contrib/test/dotnet/ExpectedOutput/TestDatetime2.out @@ -0,0 +1,22 @@ +#Q#Create table TestDatetime2(a Datetime2(6)) +#Q# Insert into TestDatetime2 Values(@a) +#Q# Insert into TestDatetime2 Values(@a) +#Q# Insert into TestDatetime2 Values(@a) +#Q# Insert into TestDatetime2 Values(@a) +#Q# Insert into TestDatetime2 Values(@a) +#Q# Insert into TestDatetime2 Values(@a) +#Q# Insert into TestDatetime2 Values(@a) +#Q# Insert into TestDatetime2 Values(@a) +#Q# Insert into TestDatetime2 Values(@a) +#Q#select * from TestDatetime2 +#D#datetime2 +10/23/2016 12:45:37 +10/23/2016 12:45:37 +10/23/2016 12:45:37 +10/23/2016 12:45:37 +10/23/2016 12:45:37 +10/23/2016 12:45:37 +10/23/2016 12:45:37 +10/23/2016 12:45:37 + +#Q#Drop table TestDatetime2 diff --git a/contrib/test/dotnet/ExpectedOutput/TestDecimal.out b/contrib/test/dotnet/ExpectedOutput/TestDecimal.out new file mode 100644 index 00000000000..e781d7baa78 --- /dev/null +++ b/contrib/test/dotnet/ExpectedOutput/TestDecimal.out @@ -0,0 +1,208 @@ +#Q#CREATE TABLE decimal_table(num decimal(5, 2)); +#Q#INSERT INTO decimal_table(num) VALUES(@a) +#Q#INSERT INTO decimal_table(num) VALUES(@a) +#Q#INSERT INTO decimal_table(num) VALUES(@a) +#Q#INSERT INTO decimal_table(num) VALUES(@a) +#Q#INSERT INTO decimal_table(num) VALUES(@a) +#Q#INSERT INTO decimal_table(num) VALUES(@a) +#Q#INSERT INTO decimal_table(num) VALUES(@a) +#Q#INSERT INTO decimal_table(num) VALUES(@a) +#Q#INSERT INTO decimal_table(num) VALUES(@a) +#Q#INSERT INTO decimal_table(num) VALUES(@a) +#Q#INSERT INTO decimal_table(num) VALUES(@a) +#Q#SELECT * FROM decimal_table; +#D#decimal +3.00 +123.45 +123.40 +123.00 +123.45 + +-123.45 +-123.40 +-123.00 +-1.00 +-123.00 +#Q#DROP TABLE decimal_table; +#Q#CREATE TABLE decimal_table(num decimal(38, 3)); +#Q#INSERT INTO decimal_table(num) VALUES(@a1) +#Q#INSERT INTO decimal_table(num) VALUES(@a1) +#Q#INSERT INTO decimal_table(num) VALUES(@a1) +#Q#INSERT INTO decimal_table(num) VALUES(@a1) +#Q#INSERT INTO decimal_table(num) VALUES(@a1) +#Q#INSERT INTO decimal_table(num) VALUES(@a1) +#Q#INSERT INTO decimal_table(num) VALUES(@a1) +#Q#INSERT INTO decimal_table(num) VALUES(@a1) +#Q#INSERT INTO decimal_table(num) VALUES(@a1) +#Q#INSERT INTO decimal_table(num) VALUES(@a1) +#Q#INSERT INTO decimal_table(num) VALUES(@a1) +#Q#SELECT * FROM decimal_table; +#D#decimal +3.000 +123.450 +123.400 +123.000 +123.450 + +-123.450 +-123.400 +-123.000 +-1.000 +-123.000 +#Q#DROP TABLE decimal_table; +#Q#CREATE TABLE decimal_table(num decimal(38, 20)); +#Q#INSERT INTO decimal_table(num) VALUES(@a2) +#Q#INSERT INTO decimal_table(num) VALUES(@a2) +#Q#INSERT INTO decimal_table(num) VALUES(@a2) +#Q#INSERT INTO decimal_table(num) VALUES(@a2) +#Q#INSERT INTO decimal_table(num) VALUES(@a2) +#Q#INSERT INTO decimal_table(num) VALUES(@a2) +#Q#INSERT INTO decimal_table(num) VALUES(@a2) +#Q#INSERT INTO decimal_table(num) VALUES(@a2) +#Q#INSERT INTO decimal_table(num) VALUES(@a2) +#Q#INSERT INTO decimal_table(num) VALUES(@a2) +#Q#INSERT INTO decimal_table(num) VALUES(@a2) +#Q#SELECT * FROM decimal_table; +#D#decimal +3.00000000000000000000 +123.45000000000000000000 +123.40000000000000000000 +123.00000000000000000000 +123.45000000000000000000 + +-123.45000000000000000000 +-123.40000000000000000000 +-123.00000000000000000000 +-1.00000000000000000000 +-123.00000000000000000000 +#Q#DROP TABLE decimal_table; +#Q#CREATE TABLE decimal_table(num decimal(38, 20)); +#Q#INSERT INTO decimal_table(num) VALUES(@a3) +#Q#INSERT INTO decimal_table(num) VALUES(@a3) +#Q#INSERT INTO decimal_table(num) VALUES(@a3) +#Q#INSERT INTO decimal_table(num) VALUES(@a3) +#Q#INSERT INTO decimal_table(num) VALUES(@a3) +#Q#INSERT INTO decimal_table(num) VALUES(@a3) +#Q#INSERT INTO decimal_table(num) VALUES(@a3) +#Q#INSERT INTO decimal_table(num) VALUES(@a3) +#Q#INSERT INTO decimal_table(num) VALUES(@a3) +#Q#INSERT INTO decimal_table(num) VALUES(@a3) +#Q#INSERT INTO decimal_table(num) VALUES(@a3) +#Q#SELECT * FROM decimal_table; +#D#decimal +3.00000000000000000000 +123.45000000000000000000 +123.40000000000000000000 +123.00000000000000000000 +123.45000000000000000000 + +-123.45000000000000000000 +-123.40000000000000000000 +-123.00000000000000000000 +-1.00000000000000000000 +-123.00000000000000000000 +#Q#DROP TABLE decimal_table; +#Q#CREATE TABLE decimal_table(num decimal(38, 21)); +#Q#INSERT INTO decimal_table(num) VALUES(@a4) +#Q#INSERT INTO decimal_table(num) VALUES(@a4) +#Q#INSERT INTO decimal_table(num) VALUES(@a4) +#Q#INSERT INTO decimal_table(num) VALUES(@a4) +#Q#INSERT INTO decimal_table(num) VALUES(@a4) +#Q#INSERT INTO decimal_table(num) VALUES(@a4) +#Q#INSERT INTO decimal_table(num) VALUES(@a4) +#Q#INSERT INTO decimal_table(num) VALUES(@a4) +#Q#INSERT INTO decimal_table(num) VALUES(@a4) +#Q#INSERT INTO decimal_table(num) VALUES(@a4) +#Q#INSERT INTO decimal_table(num) VALUES(@a4) +#Q#SELECT * FROM decimal_table; +#D#decimal +3.000000000000000000000 +123.450000000000000000000 +123.400000000000000000000 +123.000000000000000000000 +123.450000000000000000000 + +-123.450000000000000000000 +-123.400000000000000000000 +-123.000000000000000000000 +-1.000000000000000000000 +-123.000000000000000000000 +#Q#DROP TABLE decimal_table; +#Q#CREATE TABLE decimal_table(num decimal(38, 22)); +#Q#INSERT INTO decimal_table(num) VALUES(@a5) +#Q#INSERT INTO decimal_table(num) VALUES(@a5) +#Q#INSERT INTO decimal_table(num) VALUES(@a5) +#Q#INSERT INTO decimal_table(num) VALUES(@a5) +#Q#INSERT INTO decimal_table(num) VALUES(@a5) +#Q#INSERT INTO decimal_table(num) VALUES(@a5) +#Q#INSERT INTO decimal_table(num) VALUES(@a5) +#Q#INSERT INTO decimal_table(num) VALUES(@a5) +#Q#INSERT INTO decimal_table(num) VALUES(@a5) +#Q#INSERT INTO decimal_table(num) VALUES(@a5) +#Q#INSERT INTO decimal_table(num) VALUES(@a5) +#Q#SELECT * FROM decimal_table; +#D#decimal +3.0000000000000000000000 +123.4500000000000000000000 +123.4000000000000000000000 +123.0000000000000000000000 +123.4500000000000000000000 + +-123.4500000000000000000000 +-123.4000000000000000000000 +-123.0000000000000000000000 +-1.0000000000000000000000 +-123.0000000000000000000000 +#Q#DROP TABLE decimal_table; +#Q#CREATE TABLE decimal_table(num decimal(38, 23)); +#Q#INSERT INTO decimal_table(num) VALUES(@a6) +#Q#INSERT INTO decimal_table(num) VALUES(@a6) +#Q#INSERT INTO decimal_table(num) VALUES(@a6) +#Q#INSERT INTO decimal_table(num) VALUES(@a6) +#Q#INSERT INTO decimal_table(num) VALUES(@a6) +#Q#INSERT INTO decimal_table(num) VALUES(@a6) +#Q#INSERT INTO decimal_table(num) VALUES(@a6) +#Q#INSERT INTO decimal_table(num) VALUES(@a6) +#Q#INSERT INTO decimal_table(num) VALUES(@a6) +#Q#INSERT INTO decimal_table(num) VALUES(@a6) +#Q#INSERT INTO decimal_table(num) VALUES(@a6) +#Q#SELECT * FROM decimal_table; +#D#decimal +3.00000000000000000000000 +123.45000000000000000000000 +123.40000000000000000000000 +123.00000000000000000000000 +123.45000000000000000000000 + +-123.45000000000000000000000 +-123.40000000000000000000000 +-123.00000000000000000000000 +-1.00000000000000000000000 +-123.00000000000000000000000 +#Q#DROP TABLE decimal_table; +#Q#CREATE TABLE decimal_table(num decimal(38, 25)); +#Q#INSERT INTO decimal_table(num) VALUES(@a7) +#Q#INSERT INTO decimal_table(num) VALUES(@a7) +#Q#INSERT INTO decimal_table(num) VALUES(@a7) +#Q#INSERT INTO decimal_table(num) VALUES(@a7) +#Q#INSERT INTO decimal_table(num) VALUES(@a7) +#Q#INSERT INTO decimal_table(num) VALUES(@a7) +#Q#INSERT INTO decimal_table(num) VALUES(@a7) +#Q#INSERT INTO decimal_table(num) VALUES(@a7) +#Q#INSERT INTO decimal_table(num) VALUES(@a7) +#Q#INSERT INTO decimal_table(num) VALUES(@a7) +#Q#INSERT INTO decimal_table(num) VALUES(@a7) +#Q#SELECT * FROM decimal_table; +#D#decimal +3.0000000000000000000000000 +123.4500000000000000000000000 +123.4000000000000000000000000 +123.0000000000000000000000000 +123.4500000000000000000000000 + +-123.4500000000000000000000000 +-123.4000000000000000000000000 +-123.0000000000000000000000000 +-1.0000000000000000000000000 +-123.0000000000000000000000000 +#Q#DROP TABLE decimal_table; diff --git a/contrib/test/dotnet/ExpectedOutput/TestFloat.out b/contrib/test/dotnet/ExpectedOutput/TestFloat.out new file mode 100644 index 00000000000..ccb328e67a2 --- /dev/null +++ b/contrib/test/dotnet/ExpectedOutput/TestFloat.out @@ -0,0 +1,56 @@ +#Q#CREATE TABLE FLOAT_dt (a FLOAT) +#Q# INSERT INTO FLOAT_dt(a) values(@a) +#Q# INSERT INTO FLOAT_dt(a) values(@a) +#Q# INSERT INTO FLOAT_dt(a) values(@a) +#Q# INSERT INTO FLOAT_dt(a) values(@a) +#Q# INSERT INTO FLOAT_dt(a) values(@a) +#Q# INSERT INTO FLOAT_dt(a) values(@a) +#Q# INSERT INTO FLOAT_dt(a) values(@a) +#Q# INSERT INTO FLOAT_dt(a) values(@a) +#Q# INSERT INTO FLOAT_dt(a) values(@a) +#Q# INSERT INTO FLOAT_dt(a) values(@a) +#Q#SELECT * FROM FLOAT_dt; +#D#float +0 +1.05 +1.05 +1202 +-24112329 +-2.5 +86 +-1.79E+308 +1.79E+308 + +#Q#INSERT INTO FLOAT_dt(a) values(0) +#Q#INSERT INTO FLOAT_dt(a) values(1.050) +#Q#INSERT INTO FLOAT_dt(a) values(01.05) +#Q#INSERT INTO FLOAT_dt(a) values(-004) +#Q#INSERT INTO FLOAT_dt(a) values(-0122455324.5) +#Q#INSERT INTO FLOAT_dt(a) values(-000002) +#Q#INSERT INTO FLOAT_dt(a) values(0000000000000000086) +#Q#INSERT INTO FLOAT_dt(a) values(-1.79E+308) +#Q#INSERT INTO FLOAT_dt(a) values(1.79E+308) +#Q#INSERT INTO FLOAT_dt(a) values(NULL) +#Q#SELECT * FROM FLOAT_dt; +#D#float +0 +1.05 +1.05 +1202 +-24112329 +-2.5 +86 +-1.79E+308 +1.79E+308 + +0 +1.05 +1.05 +-4 +-122455324.5 +-2 +86 +-1.79E+308 +1.79E+308 + +#Q#DROP TABLE FLOAT_dt; diff --git a/contrib/test/dotnet/ExpectedOutput/TestInt.out b/contrib/test/dotnet/ExpectedOutput/TestInt.out new file mode 100644 index 00000000000..3674713954d --- /dev/null +++ b/contrib/test/dotnet/ExpectedOutput/TestInt.out @@ -0,0 +1,59 @@ +#Q#CREATE TABLE INT_dt(a INT); +#Q#INSERT INTO INT_dt(a) values(@a) +#Q#INSERT INTO INT_dt(a) values(@a) +#Q#INSERT INTO INT_dt(a) values(@a) +#Q#INSERT INTO INT_dt(a) values(@a) +#Q#INSERT INTO INT_dt(a) values(@a) +#Q#INSERT INTO INT_dt(a) values(@a) +#Q#INSERT INTO INT_dt(a) values(@a) +#Q#INSERT INTO INT_dt(a) values(@a) +#Q#INSERT INTO INT_dt(a) values(@a) +#Q#INSERT INTO INT_dt(a) values(@a) +#Q#INSERT INTO INT_dt(a) values(@a) +#Q#SELECT * FROM INT_dt; +#D#int +0 +-10 +10 +-12234 +-12234 +3 +9864 +-1625 +-2147483648 +2147483647 + +#Q#INSERT INTO INT_dt(a) values(0) +#Q#INSERT INTO INT_dt(a) values(-10) +#Q#INSERT INTO INT_dt(a) values(10) +#Q#INSERT INTO INT_dt(a) values(-12345) +#Q#INSERT INTO INT_dt(a) values(22) +#Q#INSERT INTO INT_dt(a) values(004) +#Q#INSERT INTO INT_dt(a) values(-01645) +#Q#INSERT INTO INT_dt(a) values(-2147483648) +#Q#INSERT INTO INT_dt(a) values(2147483647) +#Q#INSERT INTO INT_dt(a) values(NULL) +#Q#SELECT * FROM INT_dt; +#D#int +0 +-10 +10 +-12234 +-12234 +3 +9864 +-1625 +-2147483648 +2147483647 + +0 +-10 +10 +-12345 +22 +4 +-1645 +-2147483648 +2147483647 + +#Q#DROP TABLE INT_dt; diff --git a/contrib/test/dotnet/ExpectedOutput/TestMoney.out b/contrib/test/dotnet/ExpectedOutput/TestMoney.out new file mode 100644 index 00000000000..b0123712b0c --- /dev/null +++ b/contrib/test/dotnet/ExpectedOutput/TestMoney.out @@ -0,0 +1,55 @@ +#Q#CREATE TABLE money_dt(a smallmoney, b money); +#Q#INSERT INTO money_dt(a, b) VALUES (@a, @b) +#Q#INSERT INTO money_dt(a, b) VALUES (@a, @b) +#Q#INSERT INTO money_dt(a, b) VALUES (@a, @b) +#E#value for domain smallmoney violates check constraint "smallmoney_check" +#Q#INSERT INTO money_dt(a, b) VALUES (@a, @b) +#E#value for domain smallmoney violates check constraint "smallmoney_check" +#Q#INSERT INTO money_dt(a, b) VALUES (@a, @b) +#Q#INSERT INTO money_dt(a, b) VALUES (@a, @b) +#Q#INSERT INTO money_dt(a, b) VALUES (@a, @b) +#E#value for domain smallmoney violates check constraint "smallmoney_check" +#Q#INSERT INTO money_dt(a, b) VALUES (@a, @b) +#Q#INSERT INTO money_dt(a, b) VALUES (@a, @b) +#Q#INSERT INTO money_dt(a, b) VALUES (@a, @b) +#Q#SELECT * FROM money_dt; +#D#smallmoney#!#money +100.5000#!#10.0500 +100.5000#!#10.0500 +214748.3647#!#22337203685477.5807 +214748.3647#!#22337203685477.5807 +214748.3647#!#922337203685477.5807 +214748.3647#!#922337203685477.5807 +#!# +#Q#INSERT INTO money_dt(a,b) values(100.5,10.05); +#Q#INSERT INTO money_dt(a,b) values('$10','$10'); +#Q#INSERT INTO money_dt(a,b) values('-10.05','-10.0'); +#Q#INSERT INTO money_dt(a,b) values('10.05','10.0'); +#Q#INSERT INTO money_dt(a,b) values(-214748.3648,'-10.0'); +#Q#INSERT INTO money_dt(a,b) values(14748.3647,-922337203685477.5808); +#Q#INSERT INTO money_dt(a,b) values('$214748.3647','$22337203685477.5807'); +#Q#INSERT INTO money_dt(a,b) values('-214,748.3648','-922,337,203,685,477.5808'); +#Q#INSERT INTO money_dt(a,b) values('214,748.3647','922,337,203,685,477.5807'); +#Q#INSERT INTO money_dt(a,b) values('$214,748.3647','$922,337,203,685,477.5807'); +#Q#INSERT INTO money_dt(a,b) values(NULL,NULL); +#Q#SELECT * FROM money_dt; +#D#smallmoney#!#money +100.5000#!#10.0500 +100.5000#!#10.0500 +214748.3647#!#22337203685477.5807 +214748.3647#!#22337203685477.5807 +214748.3647#!#922337203685477.5807 +214748.3647#!#922337203685477.5807 +#!# +100.5000#!#10.0500 +10.0000#!#10.0000 +-10.0500#!#-10.0000 +10.0500#!#10.0000 +-214748.3648#!#-10.0000 +14748.3647#!#-922337203685477.5808 +214748.3647#!#22337203685477.5807 +-214748.3648#!#-922337203685477.5808 +214748.3647#!#922337203685477.5807 +214748.3647#!#922337203685477.5807 +#!# +#Q#DROP TABLE money_dt; diff --git a/contrib/test/dotnet/ExpectedOutput/TestNumeric.out b/contrib/test/dotnet/ExpectedOutput/TestNumeric.out new file mode 100644 index 00000000000..647fd8ee059 --- /dev/null +++ b/contrib/test/dotnet/ExpectedOutput/TestNumeric.out @@ -0,0 +1,196 @@ +#Q#CREATE TABLE numeric_table(num numeric(5, 2)); +#Q#INSERT INTO numeric_table(num) VALUES(@a) +#Q#INSERT INTO numeric_table(num) VALUES(@a) +#Q#INSERT INTO numeric_table(num) VALUES(@a) +#Q#INSERT INTO numeric_table(num) VALUES(@a) +#Q#INSERT INTO numeric_table(num) VALUES(@a) +#Q#INSERT INTO numeric_table(num) VALUES(@a) +#Q#INSERT INTO numeric_table(num) VALUES(@a) +#Q#INSERT INTO numeric_table(num) VALUES(@a) +#Q#INSERT INTO numeric_table(num) VALUES(@a) +#Q#INSERT INTO numeric_table(num) VALUES(@a) +#Q#INSERT INTO numeric_table(num) VALUES(@a) +#Q#SELECT * FROM numeric_table; +#D#decimal +3.00 +123.45 +123.40 +123.00 +123.45 + +-123.45 +-123.40 +-123.00 +-1.00 +-123.00 +#Q#DROP TABLE numeric_table; +#Q#CREATE TABLE numeric_table(num numeric(5, 0)); +#Q#SELECT * FROM numeric_table; +#Q#DROP TABLE numeric_table; +#Q#CREATE TABLE numeric_table(num numeric(38, 3)); +#Q#INSERT INTO numeric_table(num) VALUES(@a1) +#Q#INSERT INTO numeric_table(num) VALUES(@a1) +#Q#INSERT INTO numeric_table(num) VALUES(@a1) +#Q#INSERT INTO numeric_table(num) VALUES(@a1) +#Q#INSERT INTO numeric_table(num) VALUES(@a1) +#Q#INSERT INTO numeric_table(num) VALUES(@a1) +#Q#INSERT INTO numeric_table(num) VALUES(@a1) +#Q#INSERT INTO numeric_table(num) VALUES(@a1) +#Q#INSERT INTO numeric_table(num) VALUES(@a1) +#Q#INSERT INTO numeric_table(num) VALUES(@a1) +#Q#SELECT * FROM numeric_table; +#D#decimal +3.000 +123.400 +123.000 +123.450 + +-123.450 +-123.400 +-123.000 +-1.000 +-123.000 +#Q#DROP TABLE numeric_table; +#Q#CREATE TABLE numeric_table(num numeric(38, 20)); +#Q#INSERT INTO numeric_table(num) VALUES(@a2) +#Q#INSERT INTO numeric_table(num) VALUES(@a2) +#Q#INSERT INTO numeric_table(num) VALUES(@a2) +#Q#INSERT INTO numeric_table(num) VALUES(@a2) +#Q#INSERT INTO numeric_table(num) VALUES(@a2) +#Q#INSERT INTO numeric_table(num) VALUES(@a2) +#Q#INSERT INTO numeric_table(num) VALUES(@a2) +#Q#INSERT INTO numeric_table(num) VALUES(@a2) +#Q#INSERT INTO numeric_table(num) VALUES(@a2) +#Q#INSERT INTO numeric_table(num) VALUES(@a2) +#Q#INSERT INTO numeric_table(num) VALUES(@a2) +#Q#SELECT * FROM numeric_table; +#D#decimal +3.00000000000000000000 +123.45000000000000000000 +123.40000000000000000000 +123.00000000000000000000 +123.45000000000000000000 + +-123.45000000000000000000 +-123.40000000000000000000 +-123.00000000000000000000 +-1.00000000000000000000 +-123.00000000000000000000 +#Q#DROP TABLE numeric_table; +#Q#CREATE TABLE numeric_table(num numeric(38, 20)); +#Q#INSERT INTO numeric_table(num) VALUES(@a3) +#Q#INSERT INTO numeric_table(num) VALUES(@a3) +#Q#INSERT INTO numeric_table(num) VALUES(@a3) +#Q#INSERT INTO numeric_table(num) VALUES(@a3) +#Q#INSERT INTO numeric_table(num) VALUES(@a3) +#Q#INSERT INTO numeric_table(num) VALUES(@a3) +#Q#INSERT INTO numeric_table(num) VALUES(@a3) +#Q#INSERT INTO numeric_table(num) VALUES(@a3) +#Q#INSERT INTO numeric_table(num) VALUES(@a3) +#Q#INSERT INTO numeric_table(num) VALUES(@a3) +#Q#INSERT INTO numeric_table(num) VALUES(@a3) +#Q#SELECT * FROM numeric_table; +#D#decimal +3.00000000000000000000 +123.45000000000000000000 +123.40000000000000000000 +123.00000000000000000000 +123.45000000000000000000 + +-123.45000000000000000000 +-123.40000000000000000000 +-123.00000000000000000000 +-1.00000000000000000000 +-123.00000000000000000000 +#Q#DROP TABLE numeric_table; +#Q#CREATE TABLE numeric_table(num numeric(38, 21)); +#Q#INSERT INTO numeric_table(num) VALUES(@a4) +#Q#INSERT INTO numeric_table(num) VALUES(@a4) +#Q#INSERT INTO numeric_table(num) VALUES(@a4) +#Q#INSERT INTO numeric_table(num) VALUES(@a4) +#Q#INSERT INTO numeric_table(num) VALUES(@a4) +#Q#INSERT INTO numeric_table(num) VALUES(@a4) +#Q#INSERT INTO numeric_table(num) VALUES(@a4) +#Q#INSERT INTO numeric_table(num) VALUES(@a4) +#Q#INSERT INTO numeric_table(num) VALUES(@a4) +#Q#INSERT INTO numeric_table(num) VALUES(@a4) +#Q#INSERT INTO numeric_table(num) VALUES(@a4) +#Q#SELECT * FROM numeric_table; +#D#decimal +3.000000000000000000000 +123.450000000000000000000 +123.400000000000000000000 +123.000000000000000000000 +123.450000000000000000000 + +-123.450000000000000000000 +-123.400000000000000000000 +-123.000000000000000000000 +-1.000000000000000000000 +-123.000000000000000000000 +#Q#DROP TABLE numeric_table; +#Q#CREATE TABLE numeric_table(num numeric(38, 22)); +#Q#INSERT INTO numeric_table(num) VALUES(@a5) +#Q#INSERT INTO numeric_table(num) VALUES(@a5) +#Q#INSERT INTO numeric_table(num) VALUES(@a5) +#Q#INSERT INTO numeric_table(num) VALUES(@a5) +#Q#INSERT INTO numeric_table(num) VALUES(@a5) +#Q#INSERT INTO numeric_table(num) VALUES(@a5) +#Q#INSERT INTO numeric_table(num) VALUES(@a5) +#Q#INSERT INTO numeric_table(num) VALUES(@a5) +#Q#INSERT INTO numeric_table(num) VALUES(@a5) +#Q#INSERT INTO numeric_table(num) VALUES(@a5) +#Q#INSERT INTO numeric_table(num) VALUES(@a5) +#Q#SELECT * FROM numeric_table; +#D#decimal +3.0000000000000000000000 +123.4500000000000000000000 +123.4000000000000000000000 +123.0000000000000000000000 +123.4500000000000000000000 + +-123.4500000000000000000000 +-123.4000000000000000000000 +-123.0000000000000000000000 +-1.0000000000000000000000 +-123.0000000000000000000000 +#Q#DROP TABLE numeric_table; +#Q#CREATE TABLE numeric_table(num numeric(38, 23)); +#Q#INSERT INTO numeric_table(num) VALUES(@a6) +#Q#INSERT INTO numeric_table(num) VALUES(@a6) +#Q#INSERT INTO numeric_table(num) VALUES(@a6) +#Q#INSERT INTO numeric_table(num) VALUES(@a6) +#Q#INSERT INTO numeric_table(num) VALUES(@a6) +#Q#INSERT INTO numeric_table(num) VALUES(@a6) +#Q#INSERT INTO numeric_table(num) VALUES(@a6) +#Q#INSERT INTO numeric_table(num) VALUES(@a6) +#Q#INSERT INTO numeric_table(num) VALUES(@a6) +#Q#INSERT INTO numeric_table(num) VALUES(@a6) +#Q#INSERT INTO numeric_table(num) VALUES(@a6) +#Q#SELECT * FROM numeric_table; +#D#decimal +3.00000000000000000000000 +123.45000000000000000000000 +123.40000000000000000000000 +123.00000000000000000000000 +123.45000000000000000000000 + +-123.45000000000000000000000 +-123.40000000000000000000000 +-123.00000000000000000000000 +-1.00000000000000000000000 +-123.00000000000000000000000 +#Q#DROP TABLE numeric_table; +#Q#CREATE TABLE numeric_table(num numeric(38, 25)); +#Q#INSERT INTO numeric_table(num) VALUES(@a7) +#Q#INSERT INTO numeric_table(num) VALUES(@a7) +#Q#INSERT INTO numeric_table(num) VALUES(@a7) +#Q#INSERT INTO numeric_table(num) VALUES(@a7) +#Q#INSERT INTO numeric_table(num) VALUES(@a7) +#Q#INSERT INTO numeric_table(num) VALUES(@a7) +#Q#INSERT INTO numeric_table(num) VALUES(@a7) +#Q#INSERT INTO numeric_table(num) VALUES(@a7) +#Q#INSERT INTO numeric_table(num) VALUES(@a7) +#Q#INSERT INTO numeric_table(num) VALUES(@a7) +#Q#INSERT INTO numeric_table(num) VALUES(@a7) +#Q#DROP TABLE numeric_table; diff --git a/contrib/test/dotnet/ExpectedOutput/TestPrepareExec.out b/contrib/test/dotnet/ExpectedOutput/TestPrepareExec.out new file mode 100644 index 00000000000..4a9accd9f4c --- /dev/null +++ b/contrib/test/dotnet/ExpectedOutput/TestPrepareExec.out @@ -0,0 +1,32 @@ +#Q#CREATE TABLE prep_exec_t1(a int, b float, c smallint, d real, e int); +#Q#INSERT INTO prep_exec_t1 VALUES(@a, @b, @c, @d, @e) +#Q#INSERT INTO prep_exec_t1 VALUES(@a, @b, @c, @d, @e) +#Q#INSERT INTO prep_exec_t1 VALUES(@a, @b, @c, @d, @e) +#Q#INSERT INTO prep_exec_t1 VALUES(@a, @b, @c, @d, @e) +#Q#INSERT INTO prep_exec_t1 VALUES(@a, @b, @c, @d, @e) +#Q#Select * from prep_exec_t1; +#D#int#!#float#!#smallint#!#real#!#int +100#!#10.1#!#10#!#10.1#!# +200#!#20.2#!#20#!#20.2#!# +200#!#20.2#!#20#!#20.2#!# +300#!#30.3#!#30#!#30.3#!# +400#!#40.3#!#40#!#40.4#!# +#Q#Select * from prep_exec_t1 WHERE a = 100; +#D#int#!#float#!#smallint#!#real#!#int +100#!#10.1#!#10#!#10.1#!# +#Q#INSERT INTO prep_exec_t1 VALUES(@q, @z, @p, @o, @i); +#Q#INSERT INTO prep_exec_t1 VALUES(@q, @z, @p, @o, @i); +#Q#INSERT INTO prep_exec_t1 VALUES(@q, @z, @p, @o, @i); +#Q#INSERT INTO prep_exec_t1 VALUES(@q, @z, @p, @o, @i); +#Q#Select * from prep_exec_t1; +#D#int#!#float#!#smallint#!#real#!#int +100#!#10.1#!#10#!#10.1#!# +200#!#20.2#!#20#!#20.2#!# +200#!#20.2#!#20#!#20.2#!# +300#!#30.3#!#30#!#30.3#!# +400#!#40.3#!#40#!#40.4#!# +100#!##!##!##!# +200#!##!##!##!# +300#!##!##!##!# +400#!##!##!##!# +#Q#DROP TABLE prep_exec_t1; diff --git a/contrib/test/dotnet/ExpectedOutput/TestReal.out b/contrib/test/dotnet/ExpectedOutput/TestReal.out new file mode 100644 index 00000000000..7b792600b7c --- /dev/null +++ b/contrib/test/dotnet/ExpectedOutput/TestReal.out @@ -0,0 +1,56 @@ +#Q#CREATE TABLE REAL_dt (a REAL) +#Q# INSERT INTO REAL_dt(a) values(@a) +#Q# INSERT INTO REAL_dt(a) values(@a) +#Q# INSERT INTO REAL_dt(a) values(@a) +#Q# INSERT INTO REAL_dt(a) values(@a) +#Q# INSERT INTO REAL_dt(a) values(@a) +#Q# INSERT INTO REAL_dt(a) values(@a) +#Q# INSERT INTO REAL_dt(a) values(@a) +#Q# INSERT INTO REAL_dt(a) values(@a) +#Q# INSERT INTO REAL_dt(a) values(@a) +#Q# INSERT INTO REAL_dt(a) values(@a) +#Q#SELECT * FROM REAL_dt; +#D#real +0 +1.05 +1.05 +1202 +-24112328 +-2.5 +86 +-3.4E+38 +3.4E+38 + +#Q#INSERT INTO REAL_dt(a) values(0) +#Q#INSERT INTO REAL_dt(a) values(1.050) +#Q#INSERT INTO REAL_dt(a) values(01.05) +#Q#INSERT INTO REAL_dt(a) values(-004) +#Q#INSERT INTO REAL_dt(a) values(-0122455324.5) +#Q#INSERT INTO REAL_dt(a) values(-000002) +#Q#INSERT INTO REAL_dt(a) values(0000000000000000086) +#Q#INSERT INTO REAL_dt(a) values(-3.40E+38) +#Q#INSERT INTO REAL_dt(a) values(3.40E+38) +#Q#INSERT INTO REAL_dt(a) values(NULL) +#Q#SELECT * FROM REAL_dt; +#D#real +0 +1.05 +1.05 +1202 +-24112328 +-2.5 +86 +-3.4E+38 +3.4E+38 + +0 +1.05 +1.05 +-4 +-122455330 +-2 +86 +-3.4E+38 +3.4E+38 + +#Q#DROP TABLE REAL_dt; diff --git a/contrib/test/dotnet/ExpectedOutput/TestSQLQueries.out b/contrib/test/dotnet/ExpectedOutput/TestSQLQueries.out new file mode 100644 index 00000000000..6518f90cc7b --- /dev/null +++ b/contrib/test/dotnet/ExpectedOutput/TestSQLQueries.out @@ -0,0 +1,257 @@ +#Q#CREATE TABLE tmp(a int PRIMARY KEY, b int UNIQUE); +#E#Nullable UNIQUE constraint is not supported. Please use babelfishpg_tsql.escape_hatch_unique_constraint to ignore or add a NOT NULL constraint +#Q#INSERT INTO tmp(a,b) values(1,1); +#E#relation "tmp" does not exist +#Q#INSERT INTO tmp(a,b) values(2,2); +#E#relation "tmp" does not exist +#Q#SELECT * FROM tmp; +#E#relation "tmp" does not exist +#Q#DROP TABLE tmp; +#E#table "tmp" does not exist +#Q#CREATE TABLE tmp(a int PRIMARY KEY,b int NOT NULL); +#Q#INSERT INTO tmp(a,b) values(1,1); +#Q#INSERT INTO tmp(a,b) values(2,1); +#Q#SELECT * FROM tmp; +#D#int#!#int +1#!#1 +2#!#1 +#Q#DROP TABLE tmp; +#Q#CREATE TABLE tmp(a int PRIMARY KEY); +#Q#INSERT INTO tmp(a) VALUES(1); +#Q#INSERT INTO tmp(a) VALUES(2); +#Q#INSERT INTO tmp(a) VALUES(3); +#Q#INSERT INTO tmp(a) VALUES(4); +#Q#INSERT INTO tmp(a) VALUES(5); +#Q#SELECT * FROM tmp; +#D#int +1 +2 +3 +4 +5 +#Q#DELETE FROM tmp WHERE a>2; +#Q#SELECT * FROM tmp; +#D#int +1 +2 +#Q#DROP TABLE tmp; +#Q#CREATE TABLE tmp(a int PRIMARY KEY,b int); +#Q#INSERT INTO tmp(a,b) values(1,1); +#Q#INSERT INTO tmp(a,b) values(2,1); +#Q#INSERT INTO tmp(a,b) values(3,NULL); +#Q#INSERT INTO tmp(a,b) values(4,NULL); +#Q#SELECT * FROM tmp WHERE b IS NOT NULL; +#D#int#!#int +1#!#1 +2#!#1 +#Q#DROP TABLE tmp; +#Q#CREATE TABLE tmp(a int PRIMARY KEY); +#Q#INSERT INTO tmp(a) VALUES(1); +#Q#INSERT INTO tmp(a) VALUES(2); +#Q#SELECT * FROM tmp; +#D#int +1 +2 +#Q#SELECT * FROM tmp; +#D#int +1 +2 +#Q#SELECT * FROM tmp; +#D#int +1 +2 +#Q#DROP TABLE tmp; +#Q#CREATE TABLE tmp(a int PRIMARY KEY); +#Q#INSERT INTO tmp(a) VALUES(1); +#Q#INSERT INTO tmp(a) VALUES(2); +#Q#SELECT * FROM tmp; +#D#int +1 +2 +#Q#SELECT * FROM tmp; +#D#int +1 +2 +#Q#SELECT * FROM tmp; +#D#int +1 +2 +#Q#DROP TABLE tmp; +#Q#CREATE TABLE tmp(a int PRIMARY KEY,b int); +#Q#INSERT INTO tmp(a,b) VALUES(1,1); +#Q#INSERT INTO tmp(a,b) VALUES(2,2); +#Q#SELECT * FROM tmp; +#D#int#!#int +1#!#1 +2#!#2 +#Q#SELECT * FROM tmp; +#D#int#!#int +1#!#1 +2#!#2 +#Q#SELECT * FROM tmp; +#D#int#!#int +1#!#1 +2#!#2 +#Q#DROP TABLE tmp; +#Q#CREATE TABLE tmp(a int PRIMARY KEY,b int); +#Q#INSERT INTO tmp(a,b) VALUES(1,1); +#Q#INSERT INTO tmp(a,b) VALUES(2,2); +#Q#INSERT INTO tmp(a,b) VALUES(3,3); +#Q#INSERT INTO tmp(a,b) VALUES(4,4); +#Q#INSERT INTO tmp(a,b) VALUES(5,5); +#Q#SELECT * FROM tmp; +#D#int#!#int +1#!#1 +2#!#2 +3#!#3 +4#!#4 +5#!#5 +#Q#UPDATE tmp SET b=b+1 WHERE b>2; +#Q#SELECT * FROM tmp; +#D#int#!#int +1#!#1 +2#!#2 +3#!#4 +4#!#5 +5#!#6 +#Q#DROP TABLE tmp; +#Q#CREATE TABLE tmp(a int PRIMARY KEY,b int); +#Q#INSERT INTO tmp(a,b) VALUES(1,1); +#Q#INSERT INTO tmp(a,b) VALUES(2,2); +#Q#INSERT INTO tmp(a,b) VALUES(3,3); +#Q#INSERT INTO tmp(a,b) VALUES(4,4); +#Q#INSERT INTO tmp(a,b) VALUES(5,5); +#Q#SELECT * FROM tmp; +#D#int#!#int +1#!#1 +2#!#2 +3#!#3 +4#!#4 +5#!#5 +#Q#INSERT INTO tmp(a) values (6); +#Q#SELECT * FROM tmp; +#D#int#!#int +1#!#1 +2#!#2 +3#!#3 +4#!#4 +5#!#5 +6#!# +#Q#DROP TABLE tmp; +#Q#CREATE TABLE tmp(a int PRIMARY KEY CHECK (a>10),b int); +#Q#INSERT INTO tmp(a,b) VALUES(11,1); +#Q#INSERT INTO tmp(a,b) VALUES(12,2); +#Q#INSERT INTO tmp(a,b) VALUES(13,3); +#Q#INSERT INTO tmp(a,b) VALUES(14,4); +#Q#INSERT INTO tmp(a,b) VALUES(15,5); +#Q#SELECT * FROM tmp; +#D#int#!#int +11#!#1 +12#!#2 +13#!#3 +14#!#4 +15#!#5 +#Q#DROP TABLE tmp; +#Q#CREATE PROCEDURE tmp AS BEGIN CREATE TABLE dip(a int PRIMARY KEY CHECK (a>10),b int); INSERT INTO dip(a,b) VALUES(11,1); INSERT INTO dip(a,b) VALUES(12,2); INSERT INTO dip(a,b) VALUES(13,3); INSERT INTO dip(a,b) VALUES(14,4); INSERT INTO dip(a,b) VALUES(15,5); SELECT * FROM dip; DROP TABLE dip; END; +#Q#DROP PROCEDURE tmp; +#Q#CREATE TABLE tmp(a int PRIMARY KEY,b int); +#Q#INSERT INTO tmp(a,b) VALUES(1,1),(2,2),(3,3),(4,4),(5,5); +#Q#SELECT * FROM tmp; +#D#int#!#int +1#!#1 +2#!#2 +3#!#3 +4#!#4 +5#!#5 +#Q#UPDATE tmp SET b=b*2+1 WHERE (a>2); +#Q#SELECT * FROM tmp; +#D#int#!#int +1#!#1 +2#!#2 +3#!#7 +4#!#9 +5#!#11 +#Q#DROP TABLE tmp; +#Q#CREATE TABLE tmp(a int PRIMARY KEY,b int); +#Q#INSERT INTO tmp(a,b) VALUES(1,1),(2,2),(3,3),(4,4),(5,5); +#Q#SELECT * FROM tmp; +#D#int#!#int +1#!#1 +2#!#2 +3#!#3 +4#!#4 +5#!#5 +#Q#SELECT * FROM tmp; +#D#int#!#int +1#!#1 +2#!#2 +3#!#3 +4#!#4 +5#!#5 +#Q#DROP TABLE tmp; +#Q#CREATE TABLE temp1 (i INT,j INT,t TEXT); +#Q#CREATE TABLE temp2 ( i INT,k INT); +#Q#INSERT INTO temp1 VALUES (1, 4, 'one'); +#Q#INSERT INTO temp1 VALUES (2, 3, 'two'); +#Q#INSERT INTO temp1 VALUES (3, 2, 'three'); +#Q#INSERT INTO temp1 VALUES (4, 1, 'four'); +#Q#INSERT INTO temp1 VALUES (5, 0, 'five'); +#Q#INSERT INTO temp1 VALUES (6, 6, 'six'); +#Q#INSERT INTO temp1 VALUES (7, 7, 'seven'); +#Q#INSERT INTO temp1 VALUES (8, 8, 'eight'); +#Q#INSERT INTO temp1 VALUES (0, NULL, 'zero'); +#Q#INSERT INTO temp1 VALUES (NULL, NULL, NULL); +#Q#INSERT INTO temp1 VALUES (NULL, 0, 'zero'); +#Q#INSERT INTO temp2 VALUES (1, -1); +#Q#INSERT INTO temp2 VALUES (2, 2); +#Q#INSERT INTO temp2 VALUES (3, -3); +#Q#INSERT INTO temp2 VALUES (2, 4); +#Q#INSERT INTO temp2 VALUES (5, -5); +#Q#INSERT INTO temp2 VALUES (5, -5); +#Q#INSERT INTO temp2 VALUES (0, NULL); +#Q#INSERT INTO temp2 VALUES (NULL, NULL); +#Q#INSERT INTO temp2 VALUES (NULL, 0); +#Q#DROP TABLE temp1; +#Q#DROP TABLE temp2; +#Q#CREATE TABLE tmp(a int PRIMARY KEY,b int); +#Q#INSERT INTO tmp(a,b) VALUES(1,1); +#Q#INSERT INTO tmp(a,b) VALUES(2,2); +#Q#INSERT INTO tmp(a,b) VALUES(3,3); +#Q#INSERT INTO tmp(a,b) VALUES(4,4); +#Q#INSERT INTO tmp(a,b) VALUES(5,5); +#Q#SELECT * FROM tmp; +#D#int#!#int +1#!#1 +2#!#2 +3#!#3 +4#!#4 +5#!#5 +#Q#SELECT * FROM tmp; +#D#int#!#int +1#!#1 +2#!#2 +3#!#3 +4#!#4 +5#!#5 +#Q#DROP TABLE tmp; +#Q#CREATE TABLE DATE_dt (a DATE); +#Q#INSERT INTO DATE_dt(a) values('2000-12-13'); +#Q#INSERT INTO DATE_dt(a) values('1900-02-28'); +#Q#INSERT INTO DATE_dt(a) values('0001-01-01'); +#Q#INSERT INTO DATE_dt(a) values('9999-12-31'); +#Q#INSERT INTO DATE_dt(a) values(NULL); +#Q#SELECT * FROM DATE_dt; +#D#date +12/13/2000 00:00:00 +02/28/1900 00:00:00 +01/01/0001 00:00:00 +12/31/9999 00:00:00 + +#Q#SELECT * FROM DATE_dt; +#D#date +12/13/2000 00:00:00 +02/28/1900 00:00:00 +01/01/0001 00:00:00 +12/31/9999 00:00:00 + +#Q#DROP TABLE DATE_dt; diff --git a/contrib/test/dotnet/ExpectedOutput/TestSmallDatetime.out b/contrib/test/dotnet/ExpectedOutput/TestSmallDatetime.out new file mode 100644 index 00000000000..03b4414d1d9 --- /dev/null +++ b/contrib/test/dotnet/ExpectedOutput/TestSmallDatetime.out @@ -0,0 +1,84 @@ +#Q#CREATE TABLE SMALLDATETIME_dt (a SMALLDATETIME) +#Q# INSERT INTO SMALLDATETIME_dt(a) values(@a) +#Q# INSERT INTO SMALLDATETIME_dt(a) values(@a) +#Q# INSERT INTO SMALLDATETIME_dt(a) values(@a) +#Q# INSERT INTO SMALLDATETIME_dt(a) values(@a) +#Q# INSERT INTO SMALLDATETIME_dt(a) values(@a) +#Q# INSERT INTO SMALLDATETIME_dt(a) values(@a) +#Q# INSERT INTO SMALLDATETIME_dt(a) values(@a) +#Q# INSERT INTO SMALLDATETIME_dt(a) values(@a) +#Q# INSERT INTO SMALLDATETIME_dt(a) values(@a) +#Q# INSERT INTO SMALLDATETIME_dt(a) values(@a) +#Q# INSERT INTO SMALLDATETIME_dt(a) values(@a) +#Q# INSERT INTO SMALLDATETIME_dt(a) values(@a) +#Q# INSERT INTO SMALLDATETIME_dt(a) values(@a) +#Q# INSERT INTO SMALLDATETIME_dt(a) values(@a) +#Q# INSERT INTO SMALLDATETIME_dt(a) values(@a) +#Q# INSERT INTO SMALLDATETIME_dt(a) values(@a) +#Q#SELECT * FROM SMALLDATETIME_dt; +#D#smalldatetime +12/13/2000 12:58:00 +05/08/2007 12:35:00 +05/08/2007 12:36:00 +05/08/2007 13:00:00 +02/29/2000 00:00:00 +03/01/1900 00:00:00 +02/28/2000 23:46:00 +02/28/2000 23:46:00 +02/28/2000 23:45:00 +02/28/1900 23:46:00 +02/28/1900 23:45:00 +12/13/2000 12:59:00 +02/28/2000 23:45:00 +01/01/1900 00:00:00 +06/06/2079 23:59:00 + +#Q#INSERT INTO SMALLDATETIME_dt(a) values('2000-12-13 12:58:23'); +#Q#INSERT INTO SMALLDATETIME_dt(a) values('2007-05-08 12:35:29'); +#Q#INSERT INTO SMALLDATETIME_dt(a) values('2007-05-08 12:35:30'); +#Q#INSERT INTO SMALLDATETIME_dt(a) values('2007-05-08 12:59:59.998'); +#Q#INSERT INTO SMALLDATETIME_dt(a) values('2000-02-28 23:59:59.999'); +#Q#INSERT INTO SMALLDATETIME_dt(a) values('1900-02-28 23:59:59.999'); +#Q#INSERT INTO SMALLDATETIME_dt(a) values('2000-02-28 23:45:29.999'); +#Q#INSERT INTO SMALLDATETIME_dt(a) values('2000-02-28 23:45:30'); +#Q#INSERT INTO SMALLDATETIME_dt(a) values('2000-02-28 23:45:29'); +#Q#INSERT INTO SMALLDATETIME_dt(a) values('1900-02-28 23:45:29'); +#Q#INSERT INTO SMALLDATETIME_dt(a) values('1900-12-13 12:58:30'); +#Q#INSERT INTO SMALLDATETIME_dt(a) values('2000-02-28 23:45:29.998'); +#Q#INSERT INTO SMALLDATETIME_dt(a) values('1900-01-01 00:00:00'); +#Q#INSERT INTO SMALLDATETIME_dt(a) values('2079-06-06 23:59:29'); +#Q#INSERT INTO SMALLDATETIME_dt(a) values(NULL); +#Q#SELECT * FROM SMALLDATETIME_dt; +#D#smalldatetime +12/13/2000 12:58:00 +05/08/2007 12:35:00 +05/08/2007 12:36:00 +05/08/2007 13:00:00 +02/29/2000 00:00:00 +03/01/1900 00:00:00 +02/28/2000 23:46:00 +02/28/2000 23:46:00 +02/28/2000 23:45:00 +02/28/1900 23:46:00 +02/28/1900 23:45:00 +12/13/2000 12:59:00 +02/28/2000 23:45:00 +01/01/1900 00:00:00 +06/06/2079 23:59:00 + +12/13/2000 12:58:00 +05/08/2007 12:35:00 +05/08/2007 12:36:00 +05/08/2007 13:00:00 +02/29/2000 00:00:00 +03/01/1900 00:00:00 +02/28/2000 23:46:00 +02/28/2000 23:46:00 +02/28/2000 23:45:00 +02/28/1900 23:45:00 +12/13/1900 12:59:00 +02/28/2000 23:45:00 +01/01/1900 00:00:00 +06/06/2079 23:59:00 + +#Q#DROP TABLE SMALLDATETIME_dt; diff --git a/contrib/test/dotnet/ExpectedOutput/TestSmallInt.out b/contrib/test/dotnet/ExpectedOutput/TestSmallInt.out new file mode 100644 index 00000000000..b0896b3632b --- /dev/null +++ b/contrib/test/dotnet/ExpectedOutput/TestSmallInt.out @@ -0,0 +1,56 @@ +#Q#CREATE TABLE SMALLINT_dt (a SMALLINT) +#Q# INSERT INTO SMALLINT_dt(a) values(@a) +#Q# INSERT INTO SMALLINT_dt(a) values(@a) +#Q# INSERT INTO SMALLINT_dt(a) values(@a) +#Q# INSERT INTO SMALLINT_dt(a) values(@a) +#Q# INSERT INTO SMALLINT_dt(a) values(@a) +#Q# INSERT INTO SMALLINT_dt(a) values(@a) +#Q# INSERT INTO SMALLINT_dt(a) values(@a) +#Q# INSERT INTO SMALLINT_dt(a) values(@a) +#Q# INSERT INTO SMALLINT_dt(a) values(@a) +#Q# INSERT INTO SMALLINT_dt(a) values(@a) +#Q#SELECT * FROM SMALLINT_dt; +#D#smallint +0 +-10 +100 +2 +-29 +-1234 +876 +-32768 +32767 + +#Q#INSERT INTO SMALLINT_dt(a) values(0) +#Q#INSERT INTO SMALLINT_dt(a) values(-10) +#Q#INSERT INTO SMALLINT_dt(a) values(100) +#Q#INSERT INTO SMALLINT_dt(a) values(002) +#Q#INSERT INTO SMALLINT_dt(a) values(-029) +#Q#INSERT INTO SMALLINT_dt(a) values(-1234) +#Q#INSERT INTO SMALLINT_dt(a) values(876) +#Q#INSERT INTO SMALLINT_dt(a) values(-32768) +#Q#INSERT INTO SMALLINT_dt(a) values(32767) +#Q#INSERT INTO SMALLINT_dt(a) values(NULL) +#Q#SELECT * FROM SMALLINT_dt; +#D#smallint +0 +-10 +100 +2 +-29 +-1234 +876 +-32768 +32767 + +0 +-10 +100 +2 +-29 +-1234 +876 +-32768 +32767 + +#Q#DROP TABLE SMALLINT_dt; diff --git a/contrib/test/dotnet/ExpectedOutput/TestSqlVariant.out b/contrib/test/dotnet/ExpectedOutput/TestSqlVariant.out new file mode 100644 index 00000000000..5864c3a90de --- /dev/null +++ b/contrib/test/dotnet/ExpectedOutput/TestSqlVariant.out @@ -0,0 +1,77 @@ +#Q#CREATE TABLE SQL_VARIANT_dt (a sql_variant) +#Q# INSERT INTO SQL_VARIANT_dt(a) values(@a) +#Q# INSERT INTO SQL_VARIANT_dt(a) values(@a) +#Q# INSERT INTO SQL_VARIANT_dt(a) values(@a) +#Q# INSERT INTO SQL_VARIANT_dt(a) values(@a) +#Q# INSERT INTO SQL_VARIANT_dt(a) values(@a) +#Q# INSERT INTO SQL_VARIANT_dt(a) values(@a) +#Q# INSERT INTO SQL_VARIANT_dt(a) values(@a) +#Q# INSERT INTO SQL_VARIANT_dt(a) values(@a) +#Q# INSERT INTO SQL_VARIANT_dt(a) values(@a) +#Q# INSERT INTO SQL_VARIANT_dt(a) values(@a) +#Q# INSERT INTO SQL_VARIANT_dt(a) values(@a) +#Q#SELECT * FROM SQL_VARIANT_dt; +#D#sql_variant +0 +-100 +122.1000 +123.45 +60 +60 +System.Byte[] +1234.56 +78.5600 +0 + +#Q#drop table SQL_VARIANT_dt; +#Q#CREATE TABLE SQL_VARIANT_dt (a sql_variant) +#Q#INSERT INTO SQL_VARIANT_dt(a) values(cast (1 as bit)) +#Q#INSERT INTO SQL_VARIANT_dt(a) values(cast (6 as tinyint)) +#Q#INSERT INTO SQL_VARIANT_dt(a) values(cast (60 as smallint)) +#Q#INSERT INTO SQL_VARIANT_dt(a) values(cast (600 as int)) +#Q#INSERT INTO SQL_VARIANT_dt(a) values(cast (60000 as bigint)) +#Q#INSERT INTO SQL_VARIANT_dt(a) values(cast (600.00 as real)) +#Q#INSERT INTO SQL_VARIANT_dt(a) values(cast (60000.00 as float)) +#Q#INSERT INTO SQL_VARIANT_dt(a) values(cast (700.00 as smallmoney)) +#Q#INSERT INTO SQL_VARIANT_dt(a) values(cast (70000.00 as money)) +#Q#INSERT INTO SQL_VARIANT_dt(a) values(cast (123.45 as numeric(5, 2))) +#Q#INSERT INTO SQL_VARIANT_dt(a) values(cast ('abc' as char(10))) +#Q#INSERT INTO SQL_VARIANT_dt(a) values(cast ('abc' as nchar(10))) +#Q#INSERT INTO SQL_VARIANT_dt(a) values(cast ('abc' as varchar(10))) +#Q#INSERT INTO SQL_VARIANT_dt(a) values(cast ('abc' as nvarchar(10))) +#Q#INSERT INTO SQL_VARIANT_dt(a) values(cast (123 as binary(10))) +#Q#INSERT INTO SQL_VARIANT_dt(a) values(cast (123 as varbinary(10))) +#Q#INSERT INTO SQL_VARIANT_dt(a) values(cast ('1968-12-13' as date)) +#Q#INSERT INTO SQL_VARIANT_dt(a) values(cast ('1968-12-13 14:37:45.123' as smalldatetime)) +#Q#INSERT INTO SQL_VARIANT_dt(a) values(cast ('1968-12-13 14:37:45.123' as datetime)) +#Q#INSERT INTO SQL_VARIANT_dt(a) values(cast ('1968-12-13 14:37:45.123456' as datetime2(4))) +#Q#INSERT INTO SQL_VARIANT_dt(a) values(cast ('14:37:45.123456' as time(5))) +#Q#SELECT * FROM SQL_VARIANT_dt; +#D#sql_variant +True +6 +60 +600 +60000 +600 +60000 +700.0000 +70000.0000 +123.45 +abc +abc +abc +abc +System.Byte[] +System.Byte[] +12/13/1968 00:00:00 +12/13/1968 14:38:00 +12/13/1968 14:37:45 +12/13/1968 14:37:45 +14:37:45.1234600 +#Q#Drop table SQL_VARIANT_dt; +#Q# select @a +#D#sql_variant + +#Q#CREATE PROCEDURE temp_sql_variant @a sql_variant OUTPUT AS SELECT @a; END; +#E#syntax error near ';' at line 1 and character position 73 diff --git a/contrib/test/dotnet/ExpectedOutput/TestStoredProcedure.out b/contrib/test/dotnet/ExpectedOutput/TestStoredProcedure.out new file mode 100644 index 00000000000..65acc1a519c --- /dev/null +++ b/contrib/test/dotnet/ExpectedOutput/TestStoredProcedure.out @@ -0,0 +1,387 @@ +#Q#create table temp_sp2(a int); +#Q#CREATE PROCEDURE sp_test AS BEGIN insert into temp_sp2 values(1); END; +#Q#sp_test +#Q#SELECT * FROM temp_sp2; +#D#int +1 +#Q#drop table temp_sp2; +#Q#drop Procedure sp_test; +#Q#create table temp_sp(a int); +#Q#Create Procedure stored_proc1 (@a int) As Begin insert into temp_sp values(@a) End; +#Q#stored_proc1 +#Q#exec stored_proc1 -200 +#Q#exec stored_proc1 0 +#Q#exec stored_proc1 -1 +#Q#exec stored_proc1 2 +#Q#SELECT * FROM temp_sp; +#D#int +-100 +-200 +0 +-1 +2 +#Q#DROP table temp_sp; +#Q#DROP Procedure stored_proc1 +#Q#CREATE PROCEDURE sp_test1 (@a INT) AS BEGIN SET @a=100; Select @a as a; END; +#Q#exec sp_test1 2 +#D#int +100 +#Q#Declare @a int;Set @a=1; exec sp_test1 @a;select @a as a; +#D#int +100 +1 +#Q#sp_test1 +#D#int +100 +#Q#sp_test1 +#D#int +100 +#Q#DROP PROCEDURE sp_test1 +#Q#CREATE PROCEDURE sp_test1 (@a INT OUTPUT) AS BEGIN SET @a=100; Select @a as a; END; +#Q#exec sp_test1 2 +#D#int +100 +#Q#Declare @a int;Set @a=1; exec sp_test1 @a;select @a as a; +#D#int +100 +1 +#Q#sp_test1 +#D#int +100 +--OUT PARAMETERS-- +a +Int32 +100 + +#Q#sp_test1 +#D#int +100 +--OUT PARAMETERS-- +a +Int32 +100 + +#Q#DROP PROCEDURE sp_test1 +#Q#CREATE PROCEDURE sp_test2 (@a SMALLINT OUTPUT) AS BEGIN SET @a=100; Select @a as a; END; +#Q#exec sp_test2 2 +#D#smallint +100 +#Q#Declare @a smallint;Set @a=1; exec sp_test2 @a;select @a as a; +#D#smallint +100 +1 +#Q#sp_test2 +#D#smallint +100 +--OUT PARAMETERS-- +a +Int16 +100 + +#Q#sp_test2 +#D#smallint +100 +--OUT PARAMETERS-- +a +Int16 +100 + +#Q#DROP PROCEDURE sp_test2 +#Q#CREATE PROCEDURE sp_test3 (@a BIGINT OUTPUT) AS BEGIN SET @a=100; Select @a as a; END; +#Q#exec sp_test3 2 +#D#bigint +100 +#Q#Declare @a bigint;Set @a=1; exec sp_test3 @a;select @a as a; +#D#bigint +100 +1 +#Q#sp_test3 +#D#bigint +100 +--OUT PARAMETERS-- +a +Int64 +100 + +#Q#sp_test3 +#D#bigint +100 +--OUT PARAMETERS-- +a +Int64 +100 + +#Q#DROP PROCEDURE sp_test3 +#Q#CREATE PROCEDURE sp_test4 (@a tinyint OUTPUT) AS BEGIN SET @a=100; Select @a as a; END; +#Q#exec sp_test4 4 +#D#tinyint +100 +#Q#Declare @a bigint;Set @a=1; exec sp_test4 @a;select @a as a; +#D#tinyint +100 +1 +#Q#sp_test4 +#D#tinyint +100 +--OUT PARAMETERS-- +a +Byte +100 + +#Q#sp_test4 +#D#tinyint +100 +--OUT PARAMETERS-- +a +Byte +100 + +#Q#DROP PROCEDURE sp_test4 +#Q#CREATE PROCEDURE sp_test5 (@a float OUTPUT) AS BEGIN SET @a=100.12; Select @a as a; END; +#Q#exec sp_test5 2.1 +#D#float +100.12 +#Q#Declare @a float;Set @a=1.1; exec sp_test5 @a;select @a as a; +#D#float +100.12 +1.1 +#Q#sp_test5 +#D#float +100.12 +--OUT PARAMETERS-- +a +Double +100.12 + +#Q#sp_test5 +#D#float +100.12 +--OUT PARAMETERS-- +a +Double +100.12 + +#Q#DROP PROCEDURE sp_test5 +#Q#CREATE PROCEDURE sp_test6 (@a varchar OUTPUT) AS BEGIN SET @a='helloworld'; Select @a as a; END; +#Q#exec sp_test6 'hello' +#D#varchar +h +#Q#Declare @a varchar;Set @a='hello'; exec sp_test6 @a;select @a as a; +#D#varchar +h +h +#Q#sp_test6 +#D#varchar +h +--OUT PARAMETERS-- +a +AnsiString +h + +#Q#sp_test6 +#D#varchar +h +--OUT PARAMETERS-- +a +AnsiString +h + +#Q#DROP PROCEDURE sp_test6 +#Q#CREATE PROCEDURE sp_test9 (@a nvarchar OUTPUT) AS BEGIN SET @a='helloworld'; Select @a as a; END; +#Q#exec sp_test9 'hello' +#D#nvarchar +h +#Q#Declare @a nvarchar;Set @a='hello'; exec sp_test9 @a;select @a as a; +#D#nvarchar +h +h +#Q#sp_test9 +#D#nvarchar +h +--OUT PARAMETERS-- +a +AnsiString +h + +#Q#sp_test9 +#D#nvarchar +h +--OUT PARAMETERS-- +a +AnsiString +h + +#Q#DROP PROCEDURE sp_test9 +#Q#CREATE PROCEDURE sp_test11 (@a decimal(10,4) OUTPUT) AS BEGIN SET @a=100.41; Select @a as a; END; +#Q#exec sp_test11 2.00 +#D#decimal +100.4100 +#Q#Declare @a decimal(10,4);Set @a=10.04; exec sp_test11 @a;select @a as a; +#D#decimal +100.4100 +10.0400 +#Q#sp_test11 +#D#decimal +100.4100 +--OUT PARAMETERS-- +a +Decimal +100.410 + +#Q#sp_test11 +#D#decimal +100.4100 +--OUT PARAMETERS-- +a +Decimal +100.41 + +#Q#DROP PROCEDURE sp_test11 +#Q#CREATE PROCEDURE sp_test14 (@a date output) AS BEGIN SET @a='1999-1-3'; Select @a as a; END; +#Q#exec sp_test14 '9999-12-31' +#D#date +01/03/1999 00:00:00 +#Q#Declare @a DATE;Set @a='9999-12-31'; exec sp_test14 @a;select @a as a; +#D#date +01/03/1999 00:00:00 +12/31/9999 00:00:00 +#Q#sp_test14 +#D#date +01/03/1999 00:00:00 +--OUT PARAMETERS-- +a +Date +01/03/1999 00:00:00 + +#Q#sp_test14 +#D#date +01/03/1999 00:00:00 +--OUT PARAMETERS-- +a +Date +01/03/1999 00:00:00 + +#Q#DROP PROCEDURE sp_test14 +#Q#CREATE PROCEDURE sp_test15 (@a time(4) OUTPUT) AS BEGIN SET @a='11:25:07.123'; Select @a as a; END; +#Q#exec sp_test15 '12:45:37.123' +#D#time +11:25:07.1230000 +#Q#Declare @a Time;Set @a='12:45:37.123'; exec sp_test15 @a;select @a as a; +#D#time +11:25:07.1230000 +12:45:37.1230000 +#Q#sp_test15 +#D#time +11:25:07.1230000 +--OUT PARAMETERS-- +a +Time +11:25:07.1230000 + +#Q#sp_test15 +#D#time +11:25:07.1230000 +--OUT PARAMETERS-- +a +Time +11:25:07.1230000 + +#Q#DROP PROCEDURE sp_test15 +#Q#CREATE PROCEDURE sp_test16 (@a datetime output) AS BEGIN SET @a='2004-05-18 13:59:59.995'; Select @a as a; END; +#Q#exec sp_test16 '2000-02-28 23:59:59.995' +#D#datetime +05/18/2004 13:59:59 +#Q#Declare @a DATETIME;Set @a='2000-02-28 23:59:59.995'; exec sp_test16 @a;select @a as a; +#D#datetime +05/18/2004 13:59:59 +02/28/2000 23:59:59 +#Q#sp_test16 +#D#datetime +05/18/2004 13:59:59 +--OUT PARAMETERS-- +a +DateTime +05/18/2004 13:59:59 + +#Q#sp_test16 +#D#datetime +05/18/2004 13:59:59 +--OUT PARAMETERS-- +a +DateTime +05/18/2004 13:59:59 + +#Q#DROP PROCEDURE sp_test16 +#Q#CREATE PROCEDURE sp_test17 (@a datetime2(5) OUTPUT) AS BEGIN SET @a='2014-10-2 1:45:37.123456'; Select @a as a; END; +#Q#exec sp_test17 '2016-10-23 12:45:37.123456' +#D#datetime2 +10/02/2014 01:45:37 +#Q#Declare @a Datetime2;Set @a='2016-10-23 12:45:37.123456'; exec sp_test17 @a;select @a as a; +#D#datetime2 +10/02/2014 01:45:37 +10/23/2016 12:45:37 +#Q#sp_test17 +#D#datetime2 +10/02/2014 01:45:37 +--OUT PARAMETERS-- +a +DateTime2 +10/02/2014 01:45:37 + +#Q#sp_test17 +#D#datetime2 +10/02/2014 01:45:37 +--OUT PARAMETERS-- +a +DateTime2 +10/02/2014 01:45:37 + +#Q#DROP PROCEDURE sp_test17 +#Q#CREATE PROCEDURE sp_test18 (@a smalldatetime output) AS BEGIN SET @a='2010-02-03 12:58:23'; Select @a as a; END; +#Q#exec sp_test18 '2005-02-19 02:58:23' +#D#smalldatetime +02/03/2010 12:58:00 +#Q#Declare @a SMALLDATETIME;Set @a='2000-12-13 12:58:23'; exec sp_test18 @a;select @a as a; +#D#smalldatetime +02/03/2010 12:58:00 +12/13/2000 12:58:00 +#Q#sp_test18 +#D#smalldatetime +02/03/2010 12:58:00 +--OUT PARAMETERS-- +a +DateTime +02/03/2010 12:58:00 + +#Q#sp_test18 +#D#smalldatetime +02/03/2010 12:58:00 +--OUT PARAMETERS-- +a +DateTime +02/03/2010 12:58:00 + +#Q#DROP PROCEDURE sp_test18 +#Q#DROP PROCEDURE sp_test20 +#E#could not find a procedure named "sp_test20" +#Q#CREATE PROCEDURE sp_test20 ( @one int, @two int ) AS BEGIN SELECT @one, @two; END; +#Q#DECLARE @one int = 100; DECLARE @two int = 200; EXECUTE sp_test20 @one = @one, @two = @two; +#D#int#!#int +100#!#200 +#Q#DECLARE @one int = 100; DECLARE @two int = 200; EXECUTE sp_test20 @one = @two, @two = @one; +#D#int#!#int +200#!#100 +#Q#sp_test20 +#D#int#!#int +100#!#200 +#Q#DROP PROCEDURE sp_test20 +#Q#DROP PROCEDURE sp_test21 +#E#could not find a procedure named "sp_test21" +#Q#CREATE PROCEDURE sp_test21 ( @one varchar(30), @two int ) AS BEGIN SELECT @one, @two; END; +#Q#EXECUTE sp_test21 @one = "hello", @two = 1; +#D#varchar#!#int +hello#!#1 +#Q#sp_test21 +#D#varchar#!#int +hello#!#200 +#Q#DROP PROCEDURE sp_test21 diff --git a/contrib/test/dotnet/ExpectedOutput/TestText.out b/contrib/test/dotnet/ExpectedOutput/TestText.out new file mode 100644 index 00000000000..757b2740163 --- /dev/null +++ b/contrib/test/dotnet/ExpectedOutput/TestText.out @@ -0,0 +1,25 @@ +#Q#CREATE TABLE TEXT_dt (b ntext) +#Q# INSERT INTO TEXT_dt( b) values( @b) +#Q# INSERT INTO TEXT_dt( b) values( @b) +#Q# INSERT INTO TEXT_dt( b) values( @b) +#Q#INSERT INTO TEXT_dt(b) values(@b1) +#Q#SELECT * FROM TEXT_dt; +#D#ntext +AAAAAAAAAAAAAAAAAAAA +BBBBBBBBBB +CCCCC +badksjvbajsdcbvjads +sejvhsdbfjhcgvasdhgcvsj +21639812365091264 + +😀😃😁😎😒😞😍🙂😆😊😉 + +AAAAAAAAAAAAAAAAAAAA +BBBBBBBBBB +CCCCC +badksjvbajsdcbvjads +sejvhsdbfjhcgvasdhgcvsj +21639812365091264 + +ऀँंःऄअआइईउऊऋऌऍऎएऐऑऒओऔकखगघङचछजझञटठडढणतथदधनऩपफबभमयरऱलळऴवशषसहऺऻ़ऽािीुूृॄॅॆेैॉॊोौ्ॎॏॐ॒॑॓॔ॕॖॗक़ख़ग़ज़ड़ढ़फ़य़ॠॡॢॣ +#Q#DROP TABLE TEXT_dt; diff --git a/contrib/test/dotnet/ExpectedOutput/TestTime.out b/contrib/test/dotnet/ExpectedOutput/TestTime.out new file mode 100644 index 00000000000..65e25c0cd54 --- /dev/null +++ b/contrib/test/dotnet/ExpectedOutput/TestTime.out @@ -0,0 +1,140 @@ +#Q#Create table TestTime(a time(6)) +#Q# Insert into TestTime Values(@a) +#Q# Insert into TestTime Values(@a) +#Q# Insert into TestTime Values(@a) +#Q# Insert into TestTime Values(@a) +#Q# Insert into TestTime Values(@a) +#Q# Insert into TestTime Values(@a) +#Q# Insert into TestTime Values(@a) +#Q# Insert into TestTime Values(@a) +#Q#select * from TestTime +#D#time +12:45:37.1230000 +12:45:37.1230000 +12:45:37.1200000 +12:45:37.1000000 +12:45:37.1234000 +12:45:37.1234560 +12:45:37.1234500 + +#Q#Drop table TestTime +#Q#Create table TestTime(a time(5)) +#Q# Insert into TestTime Values(@a) +#Q# Insert into TestTime Values(@a) +#Q# Insert into TestTime Values(@a) +#Q# Insert into TestTime Values(@a) +#Q# Insert into TestTime Values(@a) +#Q# Insert into TestTime Values(@a) +#Q# Insert into TestTime Values(@a) +#Q# Insert into TestTime Values(@a) +#Q#select * from TestTime +#D#time +12:45:37.1230000 +12:45:37.1230000 +12:45:37.1200000 +12:45:37.1000000 +12:45:37.1234000 +12:45:37.1234600 +12:45:37.1234500 + +#Q#Drop table TestTime +#Q#Create table TestTime(a time(4)) +#Q# Insert into TestTime Values(@a) +#Q# Insert into TestTime Values(@a) +#Q# Insert into TestTime Values(@a) +#Q# Insert into TestTime Values(@a) +#Q# Insert into TestTime Values(@a) +#Q# Insert into TestTime Values(@a) +#Q# Insert into TestTime Values(@a) +#Q# Insert into TestTime Values(@a) +#Q#select * from TestTime +#D#time +12:45:37.1230000 +12:45:37.1230000 +12:45:37.1200000 +12:45:37.1000000 +12:45:37.1234000 +12:45:37.1235000 +12:45:37.1235000 + +#Q#Drop table TestTime +#Q#Create table TestTime(a time(3)) +#Q# Insert into TestTime Values(@a) +#Q# Insert into TestTime Values(@a) +#Q# Insert into TestTime Values(@a) +#Q# Insert into TestTime Values(@a) +#Q# Insert into TestTime Values(@a) +#Q# Insert into TestTime Values(@a) +#Q# Insert into TestTime Values(@a) +#Q# Insert into TestTime Values(@a) +#Q#select * from TestTime +#D#time +12:45:37.1230000 +12:45:37.1230000 +12:45:37.1200000 +12:45:37.1000000 +12:45:37.1230000 +12:45:37.1230000 +12:45:37.1230000 + +#Q#Drop table TestTime +#Q#Create table TestTime(a time(2)) +#Q# Insert into TestTime Values(@a) +#Q# Insert into TestTime Values(@a) +#Q# Insert into TestTime Values(@a) +#Q# Insert into TestTime Values(@a) +#Q# Insert into TestTime Values(@a) +#Q# Insert into TestTime Values(@a) +#Q# Insert into TestTime Values(@a) +#Q# Insert into TestTime Values(@a) +#Q#select * from TestTime +#D#time +12:45:37.1200000 +12:45:37.1200000 +12:45:37.1200000 +12:45:37.1000000 +12:45:37.1200000 +12:45:37.1200000 +12:45:37.1200000 + +#Q#Drop table TestTime +#Q#Create table TestTime(a time(1)) +#Q# Insert into TestTime Values(@a) +#Q# Insert into TestTime Values(@a) +#Q# Insert into TestTime Values(@a) +#Q# Insert into TestTime Values(@a) +#Q# Insert into TestTime Values(@a) +#Q# Insert into TestTime Values(@a) +#Q# Insert into TestTime Values(@a) +#Q# Insert into TestTime Values(@a) +#Q#select * from TestTime +#D#time +12:45:37.1000000 +12:45:37.1000000 +12:45:37.1000000 +12:45:37.1000000 +12:45:37.1000000 +12:45:37.1000000 +12:45:37.1000000 + +#Q#Drop table TestTime +#Q#Create table TestTime(a time(0)) +#Q# Insert into TestTime Values(@a) +#Q# Insert into TestTime Values(@a) +#Q# Insert into TestTime Values(@a) +#Q# Insert into TestTime Values(@a) +#Q# Insert into TestTime Values(@a) +#Q# Insert into TestTime Values(@a) +#Q# Insert into TestTime Values(@a) +#Q# Insert into TestTime Values(@a) +#Q#select * from TestTime +#D#time +12:45:37 +12:45:37 +12:45:37 +12:45:37 +12:45:37 +12:45:37 +12:45:37 + +#Q#Drop table TestTime diff --git a/contrib/test/dotnet/ExpectedOutput/TestTinyInt.out b/contrib/test/dotnet/ExpectedOutput/TestTinyInt.out new file mode 100644 index 00000000000..72ea2ed09ee --- /dev/null +++ b/contrib/test/dotnet/ExpectedOutput/TestTinyInt.out @@ -0,0 +1,56 @@ +#Q#CREATE TABLE TINYINT_dt (a TINYINT) +#Q# INSERT INTO TINYINT_dt(a) values(@a) +#Q# INSERT INTO TINYINT_dt(a) values(@a) +#Q# INSERT INTO TINYINT_dt(a) values(@a) +#Q# INSERT INTO TINYINT_dt(a) values(@a) +#Q# INSERT INTO TINYINT_dt(a) values(@a) +#Q# INSERT INTO TINYINT_dt(a) values(@a) +#Q# INSERT INTO TINYINT_dt(a) values(@a) +#Q# INSERT INTO TINYINT_dt(a) values(@a) +#Q# INSERT INTO TINYINT_dt(a) values(@a) +#Q# INSERT INTO TINYINT_dt(a) values(@a) +#Q#SELECT * FROM TINYINT_dt; +#D#tinyint +0 +0 +100 +2 +29 +4 +87 +0 +254 + +#Q#INSERT INTO TINYINT_dt(a) values(0) +#Q#INSERT INTO TINYINT_dt(a) values(120) +#Q#INSERT INTO TINYINT_dt(a) values(100) +#Q#INSERT INTO TINYINT_dt(a) values(004) +#Q#INSERT INTO TINYINT_dt(a) values(0) +#Q#INSERT INTO TINYINT_dt(a) values(002) +#Q#INSERT INTO TINYINT_dt(a) values(86) +#Q#INSERT INTO TINYINT_dt(a) values(0) +#Q#INSERT INTO TINYINT_dt(a) values(255) +#Q#INSERT INTO TINYINT_dt(a) values(NULL) +#Q#SELECT * FROM TINYINT_dt; +#D#tinyint +0 +0 +100 +2 +29 +4 +87 +0 +254 + +0 +120 +100 +4 +0 +2 +86 +0 +255 + +#Q#DROP TABLE TINYINT_dt; diff --git a/contrib/test/dotnet/ExpectedOutput/TestTransactions.out b/contrib/test/dotnet/ExpectedOutput/TestTransactions.out new file mode 100644 index 00000000000..c02a9b93dcd --- /dev/null +++ b/contrib/test/dotnet/ExpectedOutput/TestTransactions.out @@ -0,0 +1,263 @@ +#Q#create table txntable1(c1 int); +#Q#select @@trancount; +#D#int +1 +#Q#insert into txntable1 values(1); +#Q#select @@trancount; +#D#int +0 +#Q#select c1 from txntable1; +#D#int +1 +#Q#insert into txntable1 values(2); +#Q#select c1 from txntable1; +#D#int +1 +#Q#insert into txntable1 values(2); +#Q#select c1 from txntable1; +#D#int +1 +2 +#Q#select @@trancount; +#D#int +1 +#Q#insert into txntable1 values(3); +#Q#select @@trancount; +#D#int +1 +#Q#select @@trancount; +#D#int +0 +#Q#select c1 from txntable1; +#D#int +1 +2 +#Q#insert into txntable1 values(4); +#Q#select c1 from txntable1; +#D#int +1 +2 +4 +#Q#insert into txntable1 values(5); +#Q#select c1 from txntable1; +#D#int +1 +2 +4 +5 +#Q#insert into txntable1 values(6); +#Q#select c1 from txntable1; +#D#int +1 +2 +4 +5 +#Q#insert into txntable1 values(7); +#Q#select c1 from txntable1; +#D#int +1 +2 +4 +5 +#Q#insert into txntable1 values(8); +#Q#select c1 from txntable1; +#D#int +1 +2 +4 +5 +8 +#Q#insert into txntable1 values(9); +#Q#select c1 from txntable1; +#D#int +1 +2 +4 +5 +8 +#Q#insert into txntable1 values(10); +#Q#select c1 from txntable1; +#D#int +1 +2 +4 +5 +8 +10 +#Q#insert into txntable1 values(10); +#Q#select c1 from txntable1; +#D#int +1 +2 +4 +5 +8 +10 +#Q#insert into txntable1 values(1); +#Q#select @@trancount; +#D#int +1 +#Q#insert into txntable1 values(2); +#Q#insert into txntable1 values(3); +#Q#select @@trancount; +#D#int +1 +#Q#insert into txntable1 values(4); +#Q#select c1 from txntable1; +#D#int +1 +2 +4 +5 +8 +10 +1 +2 +3 +4 +#Q#select @@trancount; +#D#int +1 +#Q#select c1 from txntable1; +#D#int +1 +2 +4 +5 +8 +10 +1 +2 +3 +#Q#select @@trancount; +#D#int +1 +#Q#select c1 from txntable1; +#D#int +1 +2 +4 +5 +8 +10 +1 +2 +#Q#select @@trancount; +#D#int +1 +#Q#select c1 from txntable1; +#D#int +1 +2 +4 +5 +8 +10 +1 +#Q#select @@trancount; +#D#int +0 +#Q#select c1 from txntable1; +#D#int +1 +2 +4 +5 +8 +10 +#Q#insert into txntable1 values(1); +#Q#insert into txntable1 values(2); +#Q#insert into txntable1 values(3); +#Q#insert into txntable1 values(4); +#Q#select c1 from txntable1; +#D#int +1 +2 +4 +5 +8 +10 +#Q#insert into txntable1 values(1); +#Q#insert into txntable1 values(2); +#Q#insert into txntable1 values(3); +#Q#select @@trancount; +#D#int +1 +#Q#select @@trancount; +#D#int +0 +#Q#select c1 from txntable1; +#D#int +1 +2 +4 +5 +8 +10 +#Q#insert into txntable1 values(1); +#Q#insert into txntable1 values(2); +#Q#select c1 from txntable1; +#D#int +1 +2 +4 +5 +8 +10 +1 +2 +#Q#select c1 from txntable1; +#D#int +1 +2 +4 +5 +8 +10 +#Q#insert into txntable1 values(3); +#Q#insert into txntable1 values(4); +#Q#select c1 from txntable1; +#D#int +1 +2 +4 +5 +8 +10 +3 +4 +#Q#insert into txntable1 values(5); +#Q#select c1 from txntable1; +#D#int +1 +2 +4 +5 +8 +10 +3 +5 +#Q#insert into txntable1 values(6); +#Q#insert into txntable1 values(7); +#Q#select c1 frm txntable1; +#E#syntax error near ';' at line 1 and character position 23 +#Q#select c1 from txntable1; +#D#int +1 +2 +4 +5 +8 +10 +3 +5 +#Q#select @@trancount; +#D#int +0 +#Q#select @@trancount; +#D#int +0 +#Q#select @@trancount; +#D#int +0 +#Q#DROP TABLE txntable1; diff --git a/contrib/test/dotnet/ExpectedOutput/TestTransactionsSQLBatch.out b/contrib/test/dotnet/ExpectedOutput/TestTransactionsSQLBatch.out new file mode 100644 index 00000000000..8aa4a228ff2 --- /dev/null +++ b/contrib/test/dotnet/ExpectedOutput/TestTransactionsSQLBatch.out @@ -0,0 +1,322 @@ +#Q#create table TxnTable(c1 int); +#Q#begin transaction; +#Q#select @@trancount; +#D#int +1 +#Q#begin transaction; +#Q#select @@trancount; +#D#int +2 +#Q#insert into TxnTable values(1); +#Q#commit transaction; +#Q#select @@trancount; +#D#int +1 +#Q#commit transaction; +#Q#select @@trancount; +#D#int +0 +#Q#select c1 from TxnTable; +#D#int +1 +#Q#begin transaction; +#Q#insert into TxnTable values(2); +#Q#rollback transaction; +#Q#select c1 from TxnTable; +#D#int +1 +#Q#begin tran; +#Q#insert into TxnTable values(2); +#Q#commit tran; +#Q#select c1 from TxnTable; +#D#int +1 +2 +#Q#begin tran; +#Q#select @@trancount; +#D#int +1 +#Q#begin tran; +#Q#insert into TxnTable values(3); +#Q#select @@trancount; +#D#int +2 +#Q#rollback tran; +#Q#select @@trancount; +#D#int +0 +#Q#select c1 from TxnTable; +#D#int +1 +2 +#Q#begin transaction; +#Q#insert into TxnTable values(4); +#Q#commit; +#Q#select c1 from TxnTable; +#D#int +1 +2 +4 +#Q#begin transaction; +#Q#insert into TxnTable values(5); +#Q#commit work; +#Q#select c1 from TxnTable; +#D#int +1 +2 +4 +5 +#Q#begin transaction; +#Q#insert into TxnTable values(6); +#Q#rollback; +#Q#select c1 from TxnTable; +#D#int +1 +2 +4 +5 +#Q#begin transaction; +#Q#insert into TxnTable values(7); +#Q#rollback work; +#Q#select c1 from TxnTable; +#D#int +1 +2 +4 +5 +#Q#begin transaction txn1; +#Q#insert into TxnTable values(8); +#Q#commit transaction txn1; +#Q#select c1 from TxnTable; +#D#int +1 +2 +4 +5 +8 +#Q#begin transaction txn1; +#Q#insert into TxnTable values(9); +#Q#rollback transaction txn1; +#Q#select c1 from TxnTable; +#D#int +1 +2 +4 +5 +8 +#Q#begin tran txn1; +#Q#insert into TxnTable values(10); +#Q#commit tran txn1; +#Q#select c1 from TxnTable; +#D#int +1 +2 +4 +5 +8 +10 +#Q#begin tran txn1; +#Q#insert into TxnTable values(10); +#Q#rollback tran txn1; +#Q#select c1 from TxnTable; +#D#int +1 +2 +4 +5 +8 +10 +#Q#begin transaction txn1; +#Q#insert into TxnTable values(1); +#Q#save transaction sp1; +#Q#select @@trancount; +#D#int +1 +#Q#insert into TxnTable values(2); +#Q#save tran sp2; +#Q#insert into TxnTable values(3); +#Q#save tran sp2; +#Q#select @@trancount; +#D#int +1 +#Q#insert into TxnTable values(4); +#Q#select c1 from TxnTable; +#D#int +1 +2 +4 +5 +8 +10 +1 +2 +3 +4 +#Q#rollback tran sp2; +#Q#select @@trancount; +#D#int +1 +#Q#select c1 from TxnTable; +#D#int +1 +2 +4 +5 +8 +10 +1 +2 +3 +#Q#rollback tran sp2; +#Q#select @@trancount; +#D#int +1 +#Q#select c1 from TxnTable; +#D#int +1 +2 +4 +5 +8 +10 +1 +2 +#Q#rollback tran sp1; +#Q#select @@trancount; +#D#int +1 +#Q#select c1 from TxnTable; +#D#int +1 +2 +4 +5 +8 +10 +1 +#Q#rollback tran txn1; +#Q#select @@trancount; +#D#int +0 +#Q#select c1 from TxnTable; +#D#int +1 +2 +4 +5 +8 +10 +#Q#begin transaction txn1; +#Q#insert into TxnTable values(1); +#Q#save transaction sp1; +#Q#insert into TxnTable values(2); +#Q#save transaction sp2; +#Q#insert into TxnTable values(3); +#Q#save transaction sp3; +#Q#insert into TxnTable values(4); +#Q#rollback tran sp1; +#Q#rollback tran; +#Q#select c1 from TxnTable; +#D#int +1 +2 +4 +5 +8 +10 +#Q#begin transaction txn1; +#Q#insert into TxnTable values(1); +#Q#save transaction sp1; +#Q#begin transaction txn1; +#Q#insert into TxnTable values(2); +#Q#save transaction sp1; +#Q#insert into TxnTable values(3); +#Q#select @@trancount; +#D#int +2 +#Q#rollback tran txn1; +#Q#select @@trancount; +#D#int +0 +#Q#select c1 from TxnTable; +#D#int +1 +2 +4 +5 +8 +10 +#Q#begin transaction txn1; +#Q#insert into TxnTable values(1); +#Q#save transaction sp1; +#Q#insert into TxnTable values(2); +#Q#select c1 from TxnTable; +#D#int +1 +2 +4 +5 +8 +10 +1 +2 +#Q#rollback tran sp1; +#Q#commit transaction; +#Q#select c1 from TxnTable; +#D#int +1 +2 +4 +5 +8 +10 +1 +#Q#begin transaction txn1; +#Q#insert into TxnTable values(3); +#Q#save transaction sp1; +#Q#insert into TxnTable values(4); +#Q#select c1 from TxnTable; +#D#int +1 +2 +4 +5 +8 +10 +1 +3 +4 +#Q#rollback tran sp1; +#Q#save transaction sp2; +#Q#insert into TxnTable values(5); +#Q#commit transaction; +#Q#select c1 from TxnTable; +#D#int +1 +2 +4 +5 +8 +10 +1 +3 +5 +#Q#begin transaction txn1; +#Q#insert into TxnTable values(6); +#Q#save transaction sp1; +#Q#insert into TxnTable values(7); +#Q#rollback tran sp1; +#Q#commit transaction; +#Q#select c1 from TxnTable; +#D#int +1 +2 +4 +5 +8 +10 +1 +3 +5 +6 +#Q#Drop table TxnTable; diff --git a/contrib/test/dotnet/ExpectedOutput/TestTvp.out b/contrib/test/dotnet/ExpectedOutput/TestTvp.out new file mode 100644 index 00000000000..7bdfce38f4e --- /dev/null +++ b/contrib/test/dotnet/ExpectedOutput/TestTvp.out @@ -0,0 +1,6 @@ +#Q#create schema testtvp +#Q#create type testtvp.tableType as table (a int, b smallint, c bigint, d tinyint, e bit, f char(10), g nchar(10), h varchar(10), i nvarchar(10), j text, k ntext, l varbinary(10), m binary(10), n date, o datetime, p money, q uniqueidentifier,r float, s real, t numeric(4,3), u decimal(5,3), v time(5), w datetime2(5)) +#Q#Select * from @a +#E#schema "testtvp" does not exist +#Q#drop type testtvp.tableType; +#Q#drop schema testtvp diff --git a/contrib/test/dotnet/ExpectedOutput/TestUDD.out b/contrib/test/dotnet/ExpectedOutput/TestUDD.out new file mode 100644 index 00000000000..a60d3de446e --- /dev/null +++ b/contrib/test/dotnet/ExpectedOutput/TestUDD.out @@ -0,0 +1,51 @@ +#Q#EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_unique_constraint', 'ignore'; +#Q#CREATE TYPE udd_varchar from varchar(15); +#Q#CREATE TYPE udd_nvarchar from nvarchar(15); +#Q#CREATE TYPE udd_int from int; +#Q#CREATE TYPE udd_char from char(25); +#Q#CREATE TYPE udd_nchar from nchar(20) NOT NULL; +#Q#CREATE TYPE udd_datetime from datetime; +#Q#CREATE TYPE udd_numeric from numeric(4,1); +#Q#CREATE TABLE udd_dt (a udd_varchar UNIQUE, b udd_nvarchar, c udd_int PRIMARY KEY, d udd_char DEFAULT 'Whoops!', e udd_nchar, f udd_datetime, g udd_numeric CHECK (g >= 103.5)) +#Q#INSERT INTO udd_dt VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +#Q#INSERT INTO udd_dt VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); +#E#duplicate key value violates unique constraint "udd_dt_a_key" +#Q#INSERT INTO udd_dt VALUES ('Banana', N'green', 1, 'Bangalore', N'Crying😭', '2007-01-14 23:34:23.749', 908.7); +#E#duplicate key value violates unique constraint "udd_dt_pkey" +#Q#INSERT INTO udd_dt VALUES ('Guava', N'yellow', NULL, 'Mumbai', N'Smirk😏', '1907-05-09 11:14:13.749', 245.6); +#E#null value in column "c" of relation "udd_dt" violates not-null constraint +#Q#INSERT INTO udd_dt(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +#Q#INSERT INTO udd_dt VALUES ('Kiwi', N'purple', 4, 'Kolkata', NULL, '1907-05-09 11:14:13.749', 874.0); +#E#domain udd_nchar does not allow null values +#Q#INSERT INTO udd_dt VALUES ('Grape', N'white', 5, 'Pune', N'Angry😠', '2000-02-28 23:59:59.989', 100.1); +#E#new row for relation "udd_dt" violates check constraint "udd_dt_g_check" +#Q#SELECT * FROM udd_dt; +#D#varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#decimal +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#12/13/2000 12:58:23#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#02/28/1900 23:59:59#!#342.5 +#Q#DROP TABLE udd_dt; +#Q#CREATE TABLE udd_dt (a udd_varchar UNIQUE, b udd_nvarchar, c udd_int PRIMARY KEY, d udd_char DEFAULT 'Whoops!', e udd_nchar, f udd_datetime, g udd_numeric CHECK (g >= 103.5)) +#Q#INSERT INTO udd_dt VALUES (@a, @b, @c, @d, @e, @f, @g) +#Q#INSERT INTO udd_dt VALUES (@a, @b, @c, @d, @e, @f, @g) +#E#duplicate key value violates unique constraint "udd_dt_a_key" +#Q#INSERT INTO udd_dt VALUES (@a, @b, @c, @d, @e, @f, @g) +#E#duplicate key value violates unique constraint "udd_dt_pkey" +#Q#INSERT INTO udd_dt VALUES (@a, @b, @c, @d, @e, @f, @g) +#E#null value in column "c" of relation "udd_dt" violates not-null constraint +#Q#INSERT INTO udd_dt VALUES (@a, @b, @c, @d, @e, @f, @g) +#E#domain udd_nchar does not allow null values +#Q#INSERT INTO udd_dt VALUES (@a, @b, @c, @d, @e, @f, @g) +#E#new row for relation "udd_dt" violates check constraint "udd_dt_g_check" +#Q#INSERT INTO udd_dt(a, b, c, e, f, g) VALUES (@a1, @b1, @c1, @e1, @f1, @g1) +#Q#SELECT * FROM udd_dt; +#D#varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#decimal +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#12/13/2000 12:58:23#!#123.1 +Orange#!##!#5#!#Whoops! #!#Happy😀 #!#02/28/1900 23:59:59#!#342.5 +#Q#DROP TABLE udd_dt; +#Q#DROP TYPE udd_varchar +#Q#DROP TYPE udd_nvarchar +#Q#DROP TYPE udd_int +#Q#DROP TYPE udd_char +#Q#DROP TYPE udd_nchar +#Q#DROP TYPE udd_datetime +#Q#DROP TYPE udd_numeric diff --git a/contrib/test/dotnet/ExpectedOutput/TestUID.out b/contrib/test/dotnet/ExpectedOutput/TestUID.out new file mode 100644 index 00000000000..6ef54d0506b --- /dev/null +++ b/contrib/test/dotnet/ExpectedOutput/TestUID.out @@ -0,0 +1,89 @@ +#Q#CREATE TABLE uniqueidentifier_dt (a uniqueidentifier); +#Q#INSERT INTO uniqueidentifier_dt VALUES ('51f178a6-53c7-472c-9be1-1c08942342d7') +#Q#INSERT INTO uniqueidentifier_dt VALUES ('dd8cb046-461d-411e-be40-d219252ce849') +#Q#INSERT INTO uniqueidentifier_dt VALUES ('b84ebcc9-c927-4cfe-b08e-dc7f25b5087c') +#Q#INSERT INTO uniqueidentifier_dt VALUES ('bab96bc8-60b9-40dd-b0de-c90a80f5739e') +#Q#INSERT INTO uniqueidentifier_dt VALUES ('d424fdef-1404-4bac-8289-c725b540f93d') +#Q#INSERT INTO uniqueidentifier_dt VALUES ('60aeaa5c-e272-4b17-bad0-c25710fd7a60') +#Q#INSERT INTO uniqueidentifier_dt VALUES ('253fb146-7e45-45ef-9d92-bbe14a8ad1b2') +#Q#INSERT INTO uniqueidentifier_dt VALUES ('dba2726c-2131-409f-aefa-5c8079571623') +#Q#INSERT INTO uniqueidentifier_dt VALUES ('b3400fa7-3a60-40ec-b40e-fc85a3eb262d') +#Q#INSERT INTO uniqueidentifier_dt VALUES ('851763b5-b068-42ae-88ec-764bfb0e5605') +#Q#INSERT INTO uniqueidentifier_dt VALUES (NULL) +#Q#SELECT * FROM uniqueidentifier_dt +#D#uniqueidentifier +51f178a6-53c7-472c-9be1-1c08942342d7 +dd8cb046-461d-411e-be40-d219252ce849 +b84ebcc9-c927-4cfe-b08e-dc7f25b5087c +bab96bc8-60b9-40dd-b0de-c90a80f5739e +d424fdef-1404-4bac-8289-c725b540f93d +60aeaa5c-e272-4b17-bad0-c25710fd7a60 +253fb146-7e45-45ef-9d92-bbe14a8ad1b2 +dba2726c-2131-409f-aefa-5c8079571623 +b3400fa7-3a60-40ec-b40e-fc85a3eb262d +851763b5-b068-42ae-88ec-764bfb0e5605 + +#Q#INSERT INTO uniqueidentifier_dt VALUES (@a1) +#Q#INSERT INTO uniqueidentifier_dt VALUES (@a1) +#Q#INSERT INTO uniqueidentifier_dt VALUES (@a1) +#Q#INSERT INTO uniqueidentifier_dt VALUES (@a1) +#Q#INSERT INTO uniqueidentifier_dt VALUES (@a1) +#Q#INSERT INTO uniqueidentifier_dt VALUES (@a1) +#Q#INSERT INTO uniqueidentifier_dt VALUES (@a1) +#Q#INSERT INTO uniqueidentifier_dt VALUES (@a1) +#Q#INSERT INTO uniqueidentifier_dt VALUES (@a1) +#Q#INSERT INTO uniqueidentifier_dt VALUES (@a1) +#Q#INSERT INTO uniqueidentifier_dt VALUES (@a1) +#Q#SELECT * FROM uniqueidentifier_dt; +#D#uniqueidentifier +51f178a6-53c7-472c-9be1-1c08942342d7 +dd8cb046-461d-411e-be40-d219252ce849 +b84ebcc9-c927-4cfe-b08e-dc7f25b5087c +bab96bc8-60b9-40dd-b0de-c90a80f5739e +d424fdef-1404-4bac-8289-c725b540f93d +60aeaa5c-e272-4b17-bad0-c25710fd7a60 +253fb146-7e45-45ef-9d92-bbe14a8ad1b2 +dba2726c-2131-409f-aefa-5c8079571623 +b3400fa7-3a60-40ec-b40e-fc85a3eb262d +851763b5-b068-42ae-88ec-764bfb0e5605 + +51f178a6-53c7-472c-9be1-1c08942342d7 +767392df-87d0-450d-9b24-85a86c02811d +9bcb5632-53c3-4695-b617-d9a7055813ce +ac81a140-f686-4259-9b90-dd46f10b355f +3d08372d-770c-48b9-9740-a667d036680e +518d52c7-4d79-4143-ab33-b3765689fdf4 +bc3fa456-7391-4060-b5d8-430048075cf4 +3b75b2dd-01b7-4958-9de7-f92410693547 +ce8af10a-2709-43b0-9e4e-a02753929d17 +5b7c2e8d-6d90-411d-8e19-9a81067e6f6c + +#Q#INSERT INTO uniqueidentifier_dt VALUES ('51f178a6-53c7-472c-9be1-1c08942342d7thisIsTooLong') +#Q#INSERT INTO uniqueidentifier_dt VALUES (@a2) +#Q#SELECT * FROM uniqueidentifier_dt; +#D#uniqueidentifier +51f178a6-53c7-472c-9be1-1c08942342d7 +dd8cb046-461d-411e-be40-d219252ce849 +b84ebcc9-c927-4cfe-b08e-dc7f25b5087c +bab96bc8-60b9-40dd-b0de-c90a80f5739e +d424fdef-1404-4bac-8289-c725b540f93d +60aeaa5c-e272-4b17-bad0-c25710fd7a60 +253fb146-7e45-45ef-9d92-bbe14a8ad1b2 +dba2726c-2131-409f-aefa-5c8079571623 +b3400fa7-3a60-40ec-b40e-fc85a3eb262d +851763b5-b068-42ae-88ec-764bfb0e5605 + +51f178a6-53c7-472c-9be1-1c08942342d7 +767392df-87d0-450d-9b24-85a86c02811d +9bcb5632-53c3-4695-b617-d9a7055813ce +ac81a140-f686-4259-9b90-dd46f10b355f +3d08372d-770c-48b9-9740-a667d036680e +518d52c7-4d79-4143-ab33-b3765689fdf4 +bc3fa456-7391-4060-b5d8-430048075cf4 +3b75b2dd-01b7-4958-9de7-f92410693547 +ce8af10a-2709-43b0-9e4e-a02753929d17 +5b7c2e8d-6d90-411d-8e19-9a81067e6f6c + +51f178a6-53c7-472c-9be1-1c08942342d7 +51f178a6-53c7-472c-9be1-1c08942342d7 +#Q#DROP TABLE uniqueidentifier_dt; diff --git a/contrib/test/dotnet/ExpectedOutput/TestVarChar.out b/contrib/test/dotnet/ExpectedOutput/TestVarChar.out new file mode 100644 index 00000000000..aa9e4b7ac33 --- /dev/null +++ b/contrib/test/dotnet/ExpectedOutput/TestVarChar.out @@ -0,0 +1,10 @@ +#Q#CREATE TABLE VARCHAR_dt (a VARCHAR(20), b NVARCHAR(24)) +#Q# INSERT INTO VARCHAR_dt(a, b) values(@a, @b) +#Q# INSERT INTO VARCHAR_dt(a, b) values(@a, @b) +#Q# INSERT INTO VARCHAR_dt(a, b) values(@a, @b) +#E#value too long for type character varying(20) +#Q#select * from VARCHAR_dt +#D#varchar#!#nvarchar +Dipesh123#!#Dhameliya123 +abcdefghijklmnopqrst#!#abcdefghijklmnopqrstuvwx +#Q#drop table VARCHAR_dt; diff --git a/contrib/test/dotnet/ExpectedOutput/TestXML.out b/contrib/test/dotnet/ExpectedOutput/TestXML.out new file mode 100644 index 00000000000..082632f6131 --- /dev/null +++ b/contrib/test/dotnet/ExpectedOutput/TestXML.out @@ -0,0 +1,17 @@ +#Q#CREATE TABLE XML_dt (a XML) +#Q# INSERT INTO XML_dt values(@a) +#Q# INSERT INTO XML_dt values(@a) +#Q# INSERT INTO XML_dt values(@a) +#Q#SELECT * FROM XML_dt; +#D#xml +Contact Name 2YYY-YYY-YYYY + + +#Q#INSERT INTO XML_dt values('Contact Name 2YYY-YYY-YYYY') +#Q#SELECT * FROM XML_dt; +#D#xml +Contact Name 2YYY-YYY-YYYY + + +Contact Name 2YYY-YYY-YYYY +#Q#DROP TABLE XML_dt; diff --git a/contrib/test/dotnet/Info/.gitignore b/contrib/test/dotnet/Info/.gitignore new file mode 100644 index 00000000000..86d0cb2726c --- /dev/null +++ b/contrib/test/dotnet/Info/.gitignore @@ -0,0 +1,4 @@ +# Ignore everything in this directory +* +# Except this file +!.gitignore \ No newline at end of file diff --git a/contrib/test/dotnet/Output/.gitignore b/contrib/test/dotnet/Output/.gitignore new file mode 100644 index 00000000000..86d0cb2726c --- /dev/null +++ b/contrib/test/dotnet/Output/.gitignore @@ -0,0 +1,4 @@ +# Ignore everything in this directory +* +# Except this file +!.gitignore \ No newline at end of file diff --git a/contrib/test/dotnet/ReadMe.txt b/contrib/test/dotnet/ReadMe.txt new file mode 100644 index 00000000000..98ec565f276 --- /dev/null +++ b/contrib/test/dotnet/ReadMe.txt @@ -0,0 +1,78 @@ +// NOT UPTO DATE + +############################################################################################################### +################################### HOW TO CREATE AND RUN TESTS OF YOUR OWN ################################### +############################################################################################################### + +1. Create a .txt File and Place them in Project-Folder/Queries Folder. For format of queries check the next section. + You can even give your own query folder path in the config file. + +2. In the config file under the section of TestName you can add the name of your tests separated by a semicolon + For example TestName~SimpleSelect;DataMathFunctions;PrepareExecOneVariable + + Or you could run for all tests by setting it as shown --> TestName~all + + +############################################################################################################### +############################################ CONFIGURATIONS TO ADD ############################################ +############################################################################################################### + +In Queries/config.txt: + +1. sqlConnectionString and bblConnectionString are the respective connection Strings for SQL Server and Babel. + (IF YOU USE "CompareWithExpectedOutput" OR "fileGenerator" AS TRUE, THEN ONLY CONNECTION WITH bblConnectionString WILL BE ESTABLISHED) + +2. captureInterface is the interface at which the packets are received on your machine for example for Mac it is utun2, for Win-Ethernet and for Ubuntu- ens5 + +3. Set tcp-dump true for Packet comparison and false if you want only result-level comparison. + +4. queryFolder - Please add full path of your query folder to this key. + +5. fileGeneratorConnectionString - *SET THIS CONNECTION STRING TO GENERATE THE EXPECTED OUTPUT FILE* + +6. For Flags to be set for execution modes, check config.txt in the project folder. It has the necessary comments. + +############################################################################################################### +################################### HOW TO ADD YOUR OWN QUERIES FOR TESTING ################################### +############################################################################################################### + +1. For a Prepare/Execute query: + + prepst#!# #!# + + Parameter definitions should be separated by '|-|' as: |-| |-| + + Eg. If you wish to prepare the statement: "SELECT [Gender] FROM [HumanResources].[Employee] WHERE [BusinessEntityID] = @a" + with the bind variable 1 (int). Then you will add your query as shown below: + + prepst#!#SELECT [Gender] FROM [HumanResources].[Employee] WHERE [BusinessEntityID] = @a#!#int|-|a|-|1 + +2. For an Execute query: + + prepst#!#exec#!# + + Parameter definitions should be separated by '|-|' as: ~ ~ + +3. If it is a basic SQL query: + + + + i.e. as the query as it is. + + Eg. If you wish to add the query "SELECT * FROM [HumanResources].[Employee]". Then add your query as shown below: + + SELECT * FROM [HumanResources].[Employee] + +4. For a Transaction query: + + Option to run the queries as basic SQL queries as mentioned above, by simply using the queries you would run on sqlCmd + + Or you can use the connection properties to begin/commit/savepoint etc:- + txn#!# #!# transaction-name/savepoint-name + For Isolation Levels:- + txn#!#begin#!#isolation#!#< rc/rr/ru/s/ss > + Where rc is READ COMMITED + Where rr is REPEATABLE READ + Where ru is READ UNCOMMITED + Where s is READ SERIALIZABLE + Where ss is READ SNAPSHOT diff --git a/contrib/test/dotnet/config.txt b/contrib/test/dotnet/config.txt new file mode 100644 index 00000000000..10d65358e49 --- /dev/null +++ b/contrib/test/dotnet/config.txt @@ -0,0 +1,25 @@ +#Babel connection string attributes +babel_URL = +babel_port = +babel_databaseName = +babel_user = +babel_password = + +# GIVE PATH TO YOUR QUERY FOLDER +queryFolder=./../../../input/ + + +runInParallel = false +printToConsole = true + +driver = sql +provider = SQL NATIVE CLIENT + +################################### WHICH TEST TO RUN ################################### + +# SET AS "all" TO RUN ALL THE TESTS FOR THE QUEIRY FILES IN "queryFolder" +# OR SET AS THE NAME OF THE QUERY FILE YOU WANT TO TEST/CREATE EXPECTED OUTCOME FOR +# MULTIPPLE QUERY FILE NAMES WITH EXTENSION CAN BE GIVEN SEPARATED WITH A SEMICOLON AND NO SPACES + + +testName=all diff --git a/contrib/test/dotnet/dotnet.csproj b/contrib/test/dotnet/dotnet.csproj new file mode 100644 index 00000000000..b2f2008d4b1 --- /dev/null +++ b/contrib/test/dotnet/dotnet.csproj @@ -0,0 +1,26 @@ + + + + Exe + netcoreapp3.1 + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + diff --git a/contrib/test/dotnet/input/Authentication/TestAuthentication.txt b/contrib/test/dotnet/input/Authentication/TestAuthentication.txt new file mode 100644 index 00000000000..80b92233388 --- /dev/null +++ b/contrib/test/dotnet/input/Authentication/TestAuthentication.txt @@ -0,0 +1,60 @@ +# THIS IS FOR .NET + +dotnet_auth#!#db|-|demo#!#user|-|kushaal +dotnet_auth#!#db|-|demo +dotnet_auth#!#db|-| + +dotnet_auth#!#user|-|@ +dotnet_auth#!#user|-| + +dotnet_auth#!#pwd|-|kushaal +dotnet_auth#!#pwd|-| + +dotnet_auth#!#url|-| + +dotnet_auth#!#db|-|demo#!#user|-|kushaal1 +dotnet_auth#!#db|-|demo#!#pwd|-|hell + +dotnet_auth#!#db|-|demo#!#pwd|-|hell#!#others|-|ConnectRetryCount=2 + +dotnet_auth#!#others|-|Language=English +dotnet_auth#!#others|-|Language=French +dotnet_auth#!#others|-|Language= +dotnet_auth#!#others|-|Timeout=5 +dotnet_auth#!#others|-|Timeout=0 +dotnet_auth#!#others|-|Encrypt=true +dotnet_auth#!#others|-|Encrypt=false +dotnet_auth#!#others|-|Max Pool Size=1 +dotnet_auth#!#others|-|Packet Size=0 +dotnet_auth#!#others|-|Packet Size=512 +dotnet_auth#!#others|-|Packet Size=32768 +dotnet_auth#!#others|-|TrustServerCertificate=true +dotnet_auth#!#others|-|TrustServerCertificate=false + + +# THIS IS FOR JAVA + +java_auth#!#db|-|demo +java_auth#!#db|-| +java_auth#!#user|-|@ +java_auth#!#user|-| +java_auth#!#pwd|-|kushaal +java_auth#!#pwd|-| +java_auth#!#url|-| +java_auth#!#db|-|demo#!#user|-|kushaal1 +java_auth#!#db|-|demo#!#pwd|-|hell +java_auth#!#db|-|demo#!#pwd|-|hell#!#others|-|loginTimeout=10 +java_auth#!#others|-|responseBuffering=adaptive +java_auth#!#others|-|responseBuffering=full +java_auth#!#others|-|socketTimeout=5 +java_auth#!#others|-|socketTimeout=1 +java_auth#!#others|-|encrypt=true +java_auth#!#others|-|encrypt=false +java_auth#!#others|-|disableStatementPooling=true +java_auth#!#others|-|disableStatementPooling=false +java_auth#!#others|-|packetSizee=0 +java_auth#!#others|-|packetSize=-1 +java_auth#!#others|-|packetSize=32767 +java_auth#!#others|-|packetSize=32768 +java_auth#!#others|-|TrustServerCertificate=true +java_auth#!#others|-|TrustServerCertificate=false \ No newline at end of file diff --git a/contrib/test/dotnet/input/Datatypes/TestBIT.txt b/contrib/test/dotnet/input/Datatypes/TestBIT.txt new file mode 100644 index 00000000000..8424eadd597 --- /dev/null +++ b/contrib/test/dotnet/input/Datatypes/TestBIT.txt @@ -0,0 +1,16 @@ +CREATE TABLE BIT_dt (a BIT) +prepst#!# INSERT INTO BIT_dt(a) values(@a) #!#BIT|-|a|-|false +prepst#!#exec#!#BIT|-|a|-|true +#next two lines are not allowed +#prepst#!#exec#!#BIT|-|a|-|0 +#prepst#!#exec#!#BIT|-|a|-|1 +prepst#!#exec#!#BIT|-|a|-| +SELECT * FROM BIT_dt; +INSERT INTO BIT_dt(a) values(1) +INSERT INTO BIT_dt(a) values(0) +#next two lines are not allowed +#INSERT INTO BIT_dt(a) values(false) +#INSERT INTO BIT_dt(a) values(true) +INSERT INTO BIT_dt(a) values(NULL) +SELECT * FROM BIT_dt; +DROP TABLE BIT_dt; \ No newline at end of file diff --git a/contrib/test/dotnet/input/Datatypes/TestBigInt.txt b/contrib/test/dotnet/input/Datatypes/TestBigInt.txt new file mode 100644 index 00000000000..ef1451f78e8 --- /dev/null +++ b/contrib/test/dotnet/input/Datatypes/TestBigInt.txt @@ -0,0 +1,24 @@ +CREATE TABLE BIGINT_dt (a BIGINT) +prepst#!# INSERT INTO BIGINT_dt(a) values(@a) #!#BIGINT|-|a|-|0 +prepst#!#exec#!#BIGINT|-|a|-|-10 +prepst#!#exec#!#BIGINT|-|a|-|122100 +prepst#!#exec#!#BIGINT|-|a|-|0001202 +prepst#!#exec#!#BIGINT|-|a|-|-024112329 +prepst#!#exec#!#BIGINT|-|a|-|-0000000000000000002 +prepst#!#exec#!#BIGINT|-|a|-|0000000000000000086 +prepst#!#exec#!#BIGINT|-|a|-|-9223372036854775808 +prepst#!#exec#!#BIGINT|-|a|-|9223372036854775807 +prepst#!#exec#!#BIGINT|-|a|-| +SELECT * FROM BIGINT_dt; +INSERT INTO BIGINT_dt(a) values(0) +INSERT INTO BIGINT_dt(a) values(-120) +INSERT INTO BIGINT_dt(a) values(00100) +INSERT INTO BIGINT_dt(a) values(-004) +INSERT INTO BIGINT_dt(a) values(-012245532534) +INSERT INTO BIGINT_dt(a) values(-0000000000000000002) +INSERT INTO BIGINT_dt(a) values(0000000000000000086) +INSERT INTO BIGINT_dt(a) values(-9223372036854775808) +INSERT INTO BIGINT_dt(a) values(9223372036854775807) +INSERT INTO BIGINT_dt(a) values(NULL) +SELECT * FROM BIGINT_dt; +DROP TABLE BIGINT_dt; \ No newline at end of file diff --git a/contrib/test/dotnet/input/Datatypes/TestBinary.txt b/contrib/test/dotnet/input/Datatypes/TestBinary.txt new file mode 100644 index 00000000000..fd01cd66091 --- /dev/null +++ b/contrib/test/dotnet/input/Datatypes/TestBinary.txt @@ -0,0 +1,28 @@ +CREATE TABLE BINARY_dt(a BINARY(8), b VARBINARY(10)); +#inserting random values +INSERT INTO BINARY_dt(a, b) values (1234, 12345); +INSERT INTO BINARY_dt(a, b) values (NULL, NULL); +SELECT * FROM BINARY_dt +#prepst#!# INSERT INTO BINARY_dt(a, b) values(@a, @b) #!#binary|-|a|-|1234#!#varbinary|-|b|-|12345 +#prepst#!#exec#!#binary|-|a|-|#!#varbinary|-|b|-| + +#inserting out of bound values, all will throw error +#prepst#!#exec#!#binary|-|a|-|123456789#!#varbinary|-|b|-|12345 +#prepst#!#exec#!#binary|-|a|-|1234#!#varbinary|-|b|-|123456789:; +#INSERT INTO BINARY_dt(a, b) values (0x313233343536373839, 0x3132333435); +#INSERT INTO BINARY_dt(a, b) values (0x31323334, 0x3132333435363738393A3B); +#SELECT * FROM BINARY_dt +DROP TABLE BINARY_dt + + +#CREATE TABLE BINARY_dt(a BINARY(100), b VARBINARY(100)); +#prepst#!# INSERT INTO BINARY_dt(a, b) values(@a1, @b1) #!#binary|-|a1|-|!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~#!#varbinary|-|b1|-|!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ +#SELECT * FROM BINARY_dt +#DROP TABLE BINARY_dt +#CREATE TABLE IMAGE_dt(img IMAGE); +#prepst#!#insert into IMAGE_dt values (@img)#!#image|-|img|-|utils/flower.jpg +#prepst#!#exec#!#image|-|img|-|utils/Blank.jpeg +#prepst#!#exec#!#image|-|img|-| +#insert into IMAGE_dt VALUES (NULL); +#SELECT * FROM IMAGE_dt +#DROP TABLE IMAGE_dt \ No newline at end of file diff --git a/contrib/test/dotnet/input/Datatypes/TestChar.txt b/contrib/test/dotnet/input/Datatypes/TestChar.txt new file mode 100644 index 00000000000..1acc6c84270 --- /dev/null +++ b/contrib/test/dotnet/input/Datatypes/TestChar.txt @@ -0,0 +1,17 @@ +CREATE TABLE CHAR_dt (a CHAR(20), b NCHAR(20)) +prepst#!# INSERT INTO CHAR_dt(a, b) values(@a, @b) #!#CHAR|-|a|-|Dipesh#!#NCHAR|-|b|-|Dhameliya +prepst#!#exec#!#CHAR|-|a|-| Dipesh #!#NCHAR|-|b|-| Dhameliya +prepst#!#exec#!#CHAR|-|a|-| D#!#NCHAR|-|b|-| 🤣😃 +prepst#!#exec#!#CHAR|-|a|-| #!#NCHAR|-|b|-| +prepst#!#exec#!#CHAR|-|a|-| #!#NCHAR|-|b|-|😊😋😎😍😅😆 +prepst#!#exec#!#CHAR|-|a|-|#!#NCHAR|-|b|-| +prepst#!#exec#!#CHAR|-|a|-| Dipesh #!#NCHAR|-|b|-| Dham7898767895867576eliya +SELECT * FROM CHAR_dt; +INSERT INTO CHAR_dt(a,b) values('Dipesh','Dhameliya') +INSERT INTO CHAR_dt(a,b) values(' Dipesh',' Dhameliya') +INSERT INTO CHAR_dt(a,b) values(' D',N' 🤣😃') +INSERT INTO CHAR_dt(a,b) values(' ',' ') +INSERT INTO CHAR_dt(a,b) values(' ',N'😊😋😎😍😅😆') +INSERT INTO CHAR_dt(a,b) values(NULL,NULL) +SELECT * FROM CHAR_dt; +DROP TABLE CHAR_dt; \ No newline at end of file diff --git a/contrib/test/dotnet/input/Datatypes/TestDate.txt b/contrib/test/dotnet/input/Datatypes/TestDate.txt new file mode 100644 index 00000000000..ad269cabfb8 --- /dev/null +++ b/contrib/test/dotnet/input/Datatypes/TestDate.txt @@ -0,0 +1,18 @@ +CREATE TABLE DATE_dt (a DATE) +prepst#!# INSERT INTO DATE_dt(a) values(@a) #!#DATE|-|a|-|2000-12-13 +prepst#!#exec#!#DATE|-|a|-|2000-02-28 +prepst#!#exec#!#DATE|-|a|-|0001-01-01 +prepst#!#exec#!#DATE|-|a|-|9999-12-31 +#prepst#!#exec#!#DATE|-|a|-|10:10:10 +#prepst#!#exec#!#DATE|-|a|-|10-10-10 +prepst#!#exec#!#DATE|-|a|-| +SELECT * FROM DATE_dt; +#INSERT INTO DATE_dt(a) values('10/10/10') +#INSERT INTO DATE_dt(a) values('10:10:10') +INSERT INTO DATE_dt(a) values('2000-12-13') +INSERT INTO DATE_dt(a) values('1900-02-28') +INSERT INTO DATE_dt(a) values('0001-01-01') +INSERT INTO DATE_dt(a) values('9999-12-31') +INSERT INTO DATE_dt(a) values(NULL) +SELECT * FROM DATE_dt; +DROP TABLE DATE_dt; \ No newline at end of file diff --git a/contrib/test/dotnet/input/Datatypes/TestDatetime.txt b/contrib/test/dotnet/input/Datatypes/TestDatetime.txt new file mode 100644 index 00000000000..a5df9ff4d9e --- /dev/null +++ b/contrib/test/dotnet/input/Datatypes/TestDatetime.txt @@ -0,0 +1,36 @@ +CREATE TABLE DATETIME_dt (a DATETIME) +prepst#!# INSERT INTO DATETIME_dt(a) values(@a) #!#DATETIME|-|a|-|2000-12-13 12:58:23.123 +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.989 +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.990 +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.991 +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.992 +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.993 +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.994 +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.995 +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.996 +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.997 +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.998 +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.999 +prepst#!#exec#!#DATETIME|-|a|-|1900-02-28 23:59:59.989 +prepst#!#exec#!#DATETIME|-|a|-|1753-01-01 00:00:00.000 +prepst#!#exec#!#DATETIME|-|a|-|9999-12-31 23:59:59.997 +prepst#!#exec#!#DATETIME|-|a|-| +SELECT * FROM DATETIME_dt; +INSERT INTO DATETIME_dt(a) values('2000-12-13 12:58:23.123') +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.989') +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.990') +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.991') +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.992') +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.993') +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.994') +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.995') +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.996') +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.997') +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.998') +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.999') +INSERT INTO DATETIME_dt(a) values('2000-02-28 23:59:59.989') +INSERT INTO DATETIME_dt(a) values('1753-01-01 00:00:00.000') +INSERT INTO DATETIME_dt(a) values('9999-12-31 23:59:59.997') +INSERT INTO DATETIME_dt(a) values(NULL) +SELECT * FROM DATETIME_dt; +DROP TABLE DATETIME_dt; \ No newline at end of file diff --git a/contrib/test/dotnet/input/Datatypes/TestDatetime2.txt b/contrib/test/dotnet/input/Datatypes/TestDatetime2.txt new file mode 100644 index 00000000000..62e786a71f7 --- /dev/null +++ b/contrib/test/dotnet/input/Datatypes/TestDatetime2.txt @@ -0,0 +1,15 @@ +Create table TestDatetime2(a Datetime2(6)) + +prepst#!# Insert into TestDatetime2 Values(@a) #!#Datetime2|-|a|-|2016-10-23 12:45:37.123|-|0 +prepst#!#exec#!#Datetime2|-|a|-|2016-10-23 12:45:37.123|-|3 +prepst#!#exec#!#Datetime2|-|a|-|2016-10-23 12:45:37.12|-|2 +prepst#!#exec#!#Datetime2|-|a|-|2016-10-23 12:45:37.1|-|1 +prepst#!#exec#!#Datetime2|-|a|-|2016-10-23 12:45:37.1234|-|4 +prepst#!#exec#!#Datetime2|-|a|-|2016-10-23 12:45:37.123456|-|6 +prepst#!#exec#!#Datetime2|-|a|-|2016-10-23 12:45:37.123456|-|5 +prepst#!#exec#!#Datetime2|-|a|-|2016-10-23 12:45:37.123456|-|5 +prepst#!#exec#!#Datetime2|-|a|-| + +select * from TestDatetime2 + +Drop table TestDatetime2 \ No newline at end of file diff --git a/contrib/test/dotnet/input/Datatypes/TestDecimal.txt b/contrib/test/dotnet/input/Datatypes/TestDecimal.txt new file mode 100644 index 00000000000..f74cde784b1 --- /dev/null +++ b/contrib/test/dotnet/input/Datatypes/TestDecimal.txt @@ -0,0 +1,158 @@ +CREATE TABLE decimal_table(num decimal(5, 2)); + +prepst#!#INSERT INTO decimal_table(num) VALUES(@a) #!#decimal|-|a|-|3|-|5|-|2 +prepst#!#exec#!#decimal|-|a|-|123.456|-|5|-|2 +prepst#!#exec#!#decimal|-|a|-|123.4|-|5|-|2 +prepst#!#exec#!#decimal|-|a|-|123|-|5|-|2 +prepst#!#exec#!#decimal|-|a|-|123.45|-|5|-|2 +prepst#!#exec#!#decimal|-|a|-||-|5|-|2 +prepst#!#exec#!#decimal|-|a|-|-123.456|-|5|-|2 +prepst#!#exec#!#decimal|-|a|-|-123.4|-|5|-|2 +prepst#!#exec#!#decimal|-|a|-|-123|-|5|-|2 +#prepst#!#exec#!#decimal|-|a|-|0|-|5|-|2 +prepst#!#exec#!#decimal|-|a|-|-1|-|3|-|2 +prepst#!#exec#!#decimal|-|a|-|-123|-|9|-|2 + +SELECT * FROM decimal_table; + +DROP TABLE decimal_table; + +CREATE TABLE decimal_table(num decimal(38, 3)); + +prepst#!#INSERT INTO decimal_table(num) VALUES(@a1) #!#decimal|-|a1|-|3|-|5|-|2 +prepst#!#exec#!#decimal|-|a1|-|123.456|-|5|-|2 +prepst#!#exec#!#decimal|-|a1|-|123.4|-|5|-|2 +prepst#!#exec#!#decimal|-|a1|-|123|-|5|-|2 +prepst#!#exec#!#decimal|-|a1|-|123.45|-|5|-|2 +prepst#!#exec#!#decimal|-|a1|-||-|5|-|2 +prepst#!#exec#!#decimal|-|a1|-|-123.456|-|5|-|2 +prepst#!#exec#!#decimal|-|a1|-|-123.4|-|5|-|2 +prepst#!#exec#!#decimal|-|a1|-|-123|-|5|-|2 +#prepst#!#exec#!#decimal|-|a1|-|0|-|5|-|2 +prepst#!#exec#!#decimal|-|a1|-|-1|-|3|-|2 +prepst#!#exec#!#decimal|-|a1|-|-123|-|9|-|2 + +# Should generate "Error converting data type numeric to decimal" (BABEL-510) +#prepst#!#exec#!#decimal|-|a1|-|2147483647|-|10|-|0 +#prepst#!#exec#!#decimal|-|a1|-|-2147483647|-|10|-|0 +#prepst#!#exec#!#decimal|-|a1|-|2147483646|-|10|-|0 +#prepst#!#exec#!#decimal|-|a1|-|-2147483646|-|10|-|0 +#prepst#!#exec#!#decimal|-|a1|-|2147483648|-|10|-|0 +#prepst#!#exec#!#decimal|-|a1|-|-2147483648|-|10|-|0 + +SELECT * FROM decimal_table; + +DROP TABLE decimal_table; + +# JIRA 507, WORKING FOR BABEL +#CREATE TABLE decimal_table(num decimal(39, 20)); + +CREATE TABLE decimal_table(num decimal(38, 20)); + +prepst#!#INSERT INTO decimal_table(num) VALUES(@a2) #!#decimal|-|a2|-|3|-|5|-|2 +prepst#!#exec#!#decimal|-|a2|-|123.456|-|5|-|2 +prepst#!#exec#!#decimal|-|a2|-|123.4|-|5|-|2 +prepst#!#exec#!#decimal|-|a2|-|123|-|5|-|2 +prepst#!#exec#!#decimal|-|a2|-|123.45|-|5|-|2 +prepst#!#exec#!#decimal|-|a2|-||-|5|-|2 +prepst#!#exec#!#decimal|-|a2|-|-123.456|-|5|-|2 +prepst#!#exec#!#decimal|-|a2|-|-123.4|-|5|-|2 +prepst#!#exec#!#decimal|-|a2|-|-123|-|5|-|2 +#prepst#!#exec#!#decimal|-|a2|-|0|-|5|-|2 +prepst#!#exec#!#decimal|-|a2|-|-1|-|3|-|2 +prepst#!#exec#!#decimal|-|a2|-|-123|-|9|-|2 +#prepst#!#exec#!#decimal|-|a2|-| 2147483647|-|10|-|0 +SELECT * FROM decimal_table; + +DROP TABLE decimal_table; + +CREATE TABLE decimal_table(num decimal(38, 20)); +prepst#!#INSERT INTO decimal_table(num) VALUES(@a3) #!#decimal|-|a3|-|3|-|5|-|2 +prepst#!#exec#!#decimal|-|a3|-|123.456|-|5|-|2 +prepst#!#exec#!#decimal|-|a3|-|123.4|-|5|-|2 +prepst#!#exec#!#decimal|-|a3|-|123|-|5|-|2 +prepst#!#exec#!#decimal|-|a3|-|123.45|-|5|-|2 +prepst#!#exec#!#decimal|-|a3|-||-|5|-|2 +prepst#!#exec#!#decimal|-|a3|-|-123.456|-|5|-|2 +prepst#!#exec#!#decimal|-|a3|-|-123.4|-|5|-|2 +prepst#!#exec#!#decimal|-|a3|-|-123|-|5|-|2 +#prepst#!#exec#!#decimal|-|a3|-|0|-|5|-|2 +prepst#!#exec#!#decimal|-|a3|-|-1|-|3|-|2 +prepst#!#exec#!#decimal|-|a3|-|-123|-|9|-|2 +#prepst#!#exec#!#decimal|-|a3|-| 2147483647|-|10|-|0 +SELECT * FROM decimal_table; + +DROP TABLE decimal_table; + +CREATE TABLE decimal_table(num decimal(38, 21)); +prepst#!#INSERT INTO decimal_table(num) VALUES(@a4) #!#decimal|-|a4|-|3|-|5|-|2 +prepst#!#exec#!#decimal|-|a4|-|123.456|-|5|-|2 +prepst#!#exec#!#decimal|-|a4|-|123.4|-|5|-|2 +prepst#!#exec#!#decimal|-|a4|-|123|-|5|-|2 +prepst#!#exec#!#decimal|-|a4|-|123.45|-|5|-|2 +prepst#!#exec#!#decimal|-|a4|-||-|5|-|2 +prepst#!#exec#!#decimal|-|a4|-|-123.456|-|5|-|2 +prepst#!#exec#!#decimal|-|a4|-|-123.4|-|5|-|2 +prepst#!#exec#!#decimal|-|a4|-|-123|-|5|-|2 +#prepst#!#exec#!#decimal|-|a4|-|0|-|5|-|2 +prepst#!#exec#!#decimal|-|a4|-|-1|-|3|-|2 +prepst#!#exec#!#decimal|-|a4|-|-123|-|9|-|2 +#prepst#!#exec#!#decimal|-|a4|-| 2147483647|-|10|-|0 +SELECT * FROM decimal_table; + +DROP TABLE decimal_table; + +CREATE TABLE decimal_table(num decimal(38, 22)); +prepst#!#INSERT INTO decimal_table(num) VALUES(@a5) #!#decimal|-|a5|-|3|-|5|-|2 +prepst#!#exec#!#decimal|-|a5|-|123.456|-|5|-|2 +prepst#!#exec#!#decimal|-|a5|-|123.4|-|5|-|2 +prepst#!#exec#!#decimal|-|a5|-|123|-|5|-|2 +prepst#!#exec#!#decimal|-|a5|-|123.45|-|5|-|2 +prepst#!#exec#!#decimal|-|a5|-||-|5|-|2 +prepst#!#exec#!#decimal|-|a5|-|-123.456|-|5|-|2 +prepst#!#exec#!#decimal|-|a5|-|-123.4|-|5|-|2 +prepst#!#exec#!#decimal|-|a5|-|-123|-|5|-|2 +#prepst#!#exec#!#decimal|-|a5|-|0|-|5|-|2 +prepst#!#exec#!#decimal|-|a5|-|-1|-|3|-|2 +prepst#!#exec#!#decimal|-|a5|-|-123|-|9|-|2 +#prepst#!#exec#!#decimal|-|a5|-| 2147483647|-|10|-|0 +SELECT * FROM decimal_table; + +DROP TABLE decimal_table; + +CREATE TABLE decimal_table(num decimal(38, 23)); +prepst#!#INSERT INTO decimal_table(num) VALUES(@a6) #!#decimal|-|a6|-|3|-|5|-|2 +prepst#!#exec#!#decimal|-|a6|-|123.456|-|5|-|2 +prepst#!#exec#!#decimal|-|a6|-|123.4|-|5|-|2 +prepst#!#exec#!#decimal|-|a6|-|123|-|5|-|2 +prepst#!#exec#!#decimal|-|a6|-|123.45|-|5|-|2 +prepst#!#exec#!#decimal|-|a6|-||-|5|-|2 +prepst#!#exec#!#decimal|-|a6|-|-123.456|-|5|-|2 +prepst#!#exec#!#decimal|-|a6|-|-123.4|-|5|-|2 +prepst#!#exec#!#decimal|-|a6|-|-123|-|5|-|2 +#prepst#!#exec#!#decimal|-|a6|-|0|-|5|-|2 +prepst#!#exec#!#decimal|-|a6|-|-1|-|3|-|2 +prepst#!#exec#!#decimal|-|a6|-|-123|-|9|-|2 +#prepst#!#exec#!#decimal|-|a6|-| 2147483647|-|10|-|0 +SELECT * FROM decimal_table; + +DROP TABLE decimal_table; + +CREATE TABLE decimal_table(num decimal(38, 25)); +prepst#!#INSERT INTO decimal_table(num) VALUES(@a7) #!#decimal|-|a7|-|3|-|5|-|2 +prepst#!#exec#!#decimal|-|a7|-|123.456|-|5|-|2 +prepst#!#exec#!#decimal|-|a7|-|123.4|-|5|-|2 +prepst#!#exec#!#decimal|-|a7|-|123|-|5|-|2 +prepst#!#exec#!#decimal|-|a7|-|123.45|-|5|-|2 +prepst#!#exec#!#decimal|-|a7|-||-|5|-|2 +prepst#!#exec#!#decimal|-|a7|-|-123.456|-|5|-|2 +prepst#!#exec#!#decimal|-|a7|-|-123.4|-|5|-|2 +prepst#!#exec#!#decimal|-|a7|-|-123|-|5|-|2 +#prepst#!#exec#!#decimal|-|a7|-|0|-|5|-|2 +prepst#!#exec#!#decimal|-|a7|-|-1|-|3|-|2 +prepst#!#exec#!#decimal|-|a7|-|-123|-|9|-|2 +#prepst#!#exec#!#decimal|-|a7|-| 247483647|-|10|-|0 +#prepst#!#exec#!#decimal|-|a7|-|-247483647|-|10|-|0 +SELECT * FROM decimal_table; + +DROP TABLE decimal_table; diff --git a/contrib/test/dotnet/input/Datatypes/TestFloat.txt b/contrib/test/dotnet/input/Datatypes/TestFloat.txt new file mode 100644 index 00000000000..37609dbf959 --- /dev/null +++ b/contrib/test/dotnet/input/Datatypes/TestFloat.txt @@ -0,0 +1,24 @@ +CREATE TABLE FLOAT_dt (a FLOAT) +prepst#!# INSERT INTO FLOAT_dt(a) values(@a) #!#FLOAT|-|a|-|0 +prepst#!#exec#!#FLOAT|-|a|-|1.050 +prepst#!#exec#!#FLOAT|-|a|-|01.05 +prepst#!#exec#!#FLOAT|-|a|-|0001202 +prepst#!#exec#!#FLOAT|-|a|-|-024112329 +prepst#!#exec#!#FLOAT|-|a|-|-02.5 +prepst#!#exec#!#FLOAT|-|a|-|0000000000000000086 +prepst#!#exec#!#FLOAT|-|a|-|-1.79E+308 +prepst#!#exec#!#FLOAT|-|a|-|1.79E+308 +prepst#!#exec#!#FLOAT|-|a|-| +SELECT * FROM FLOAT_dt; +INSERT INTO FLOAT_dt(a) values(0) +INSERT INTO FLOAT_dt(a) values(1.050) +INSERT INTO FLOAT_dt(a) values(01.05) +INSERT INTO FLOAT_dt(a) values(-004) +INSERT INTO FLOAT_dt(a) values(-0122455324.5) +INSERT INTO FLOAT_dt(a) values(-000002) +INSERT INTO FLOAT_dt(a) values(0000000000000000086) +INSERT INTO FLOAT_dt(a) values(-1.79E+308) +INSERT INTO FLOAT_dt(a) values(1.79E+308) +INSERT INTO FLOAT_dt(a) values(NULL) +SELECT * FROM FLOAT_dt; +DROP TABLE FLOAT_dt; \ No newline at end of file diff --git a/contrib/test/dotnet/input/Datatypes/TestInt.txt b/contrib/test/dotnet/input/Datatypes/TestInt.txt new file mode 100644 index 00000000000..0dfaf007fad --- /dev/null +++ b/contrib/test/dotnet/input/Datatypes/TestInt.txt @@ -0,0 +1,29 @@ +CREATE TABLE INT_dt(a INT); +prepst#!#INSERT INTO INT_dt(a) values(@a) #!#INT|-|a|-|0 +prepst#!#exec#!#INT|-|a|-|-10 +prepst#!#exec#!#INT|-|a|-|10 +prepst#!#exec#!#INT|-|a|-|-12234 +prepst#!#exec#!#INT|-|a|-|22.0 +prepst#!#exec#!#INT|-|a|-|003 +prepst#!#exec#!#INT|-|a|-|9864 +prepst#!#exec#!#INT|-|a|-|-01625 +prepst#!#exec#!#INT|-|a|-|-2147483648 +prepst#!#exec#!#INT|-|a|-|2147483647 +prepst#!#exec#!#INT|-|a|-| + +SELECT * FROM INT_dt; + +INSERT INTO INT_dt(a) values(0) +INSERT INTO INT_dt(a) values(-10) +INSERT INTO INT_dt(a) values(10) +INSERT INTO INT_dt(a) values(-12345) +INSERT INTO INT_dt(a) values(22) +INSERT INTO INT_dt(a) values(004) +INSERT INTO INT_dt(a) values(-01645) +INSERT INTO INT_dt(a) values(-2147483648) +INSERT INTO INT_dt(a) values(2147483647) +INSERT INTO INT_dt(a) values(NULL) + +SELECT * FROM INT_dt; + +DROP TABLE INT_dt; diff --git a/contrib/test/dotnet/input/Datatypes/TestMoney.txt b/contrib/test/dotnet/input/Datatypes/TestMoney.txt new file mode 100644 index 00000000000..1f18d51c555 --- /dev/null +++ b/contrib/test/dotnet/input/Datatypes/TestMoney.txt @@ -0,0 +1,30 @@ +CREATE TABLE money_dt(a smallmoney, b money); + +prepst#!#INSERT INTO money_dt(a, b) VALUES (@a, @b) #!#smallmoney|-|a|-|100.5 #!#money|-|b|-|10.05 +prepst#!#exec#!#smallmoney|-|a|-|$10#!#money|-|b|-|$10 +prepst#!#exec#!#smallmoney|-|a|-|-10.05 #!#money|-|b|-|-10.0 +prepst#!#exec#!#smallmoney|-|a|-|-214748.3648 #!#money|-|b|-|-922337203685477.5808 +prepst#!#exec#!#smallmoney|-|a|-|214748.3647 #!#money|-|b|-|22337203685477.5807 +prepst#!#exec#!#smallmoney|-|a|-|$214748.3647 #!#money|-|b|-|$22337203685477.5807 +prepst#!#exec#!#smallmoney|-|a|-|-214,748.3648 #!#money|-|b|-|-922,337,203,685,477.5808 +prepst#!#exec#!#smallmoney|-|a|-|214,748.3647 #!#money|-|b|-|922,337,203,685,477.5807 +prepst#!#exec#!#smallmoney|-|a|-|$214,748.3647 #!#money|-|b|-|$922,337,203,685,477.5807 +prepst#!#exec#!#smallmoney|-|a|-|#!#money|-|b|-| + +SELECT * FROM money_dt; + +INSERT INTO money_dt(a,b) values(100.5,10.05); +INSERT INTO money_dt(a,b) values('$10','$10'); +INSERT INTO money_dt(a,b) values('-10.05','-10.0'); +INSERT INTO money_dt(a,b) values('10.05','10.0'); +INSERT INTO money_dt(a,b) values(-214748.3648,'-10.0'); +INSERT INTO money_dt(a,b) values(14748.3647,-922337203685477.5808); +INSERT INTO money_dt(a,b) values('$214748.3647','$22337203685477.5807'); +INSERT INTO money_dt(a,b) values('-214,748.3648','-922,337,203,685,477.5808'); +INSERT INTO money_dt(a,b) values('214,748.3647','922,337,203,685,477.5807'); +INSERT INTO money_dt(a,b) values('$214,748.3647','$922,337,203,685,477.5807'); +INSERT INTO money_dt(a,b) values(NULL,NULL); + + +SELECT * FROM money_dt; +DROP TABLE money_dt; \ No newline at end of file diff --git a/contrib/test/dotnet/input/Datatypes/TestNumeric.txt b/contrib/test/dotnet/input/Datatypes/TestNumeric.txt new file mode 100644 index 00000000000..04fa5fd1c17 --- /dev/null +++ b/contrib/test/dotnet/input/Datatypes/TestNumeric.txt @@ -0,0 +1,178 @@ +CREATE TABLE numeric_table(num numeric(5, 2)); + +prepst#!#INSERT INTO numeric_table(num) VALUES(@a) #!#numeric|-|a|-|3|-|5|-|2 +prepst#!#exec#!#numeric|-|a|-|123.456|-|5|-|2 +prepst#!#exec#!#numeric|-|a|-|123.4|-|5|-|2 +prepst#!#exec#!#numeric|-|a|-|123|-|5|-|2 +prepst#!#exec#!#numeric|-|a|-|123.45|-|5|-|2 +prepst#!#exec#!#numeric|-|a|-||-|5|-|2 +prepst#!#exec#!#numeric|-|a|-|-123.456|-|5|-|2 +prepst#!#exec#!#numeric|-|a|-|-123.4|-|5|-|2 +prepst#!#exec#!#numeric|-|a|-|-123|-|5|-|2 +#prepst#!#exec#!#numeric|-|a|-|0|-|5|-|2 +prepst#!#exec#!#numeric|-|a|-|-1|-|3|-|2 +prepst#!#exec#!#numeric|-|a|-|-123|-|9|-|2 + +SELECT * FROM numeric_table; + +DROP TABLE numeric_table; + +CREATE TABLE numeric_table(num numeric(5, 0)); + +# Should generate "Error converting data type numeric to decimal" (BABEL-510) +#prepst#!#INSERT INTO numeric_table(num) VALUES(@a) #!#numeric|-|a|-|3|-|5|-|2 +#prepst#!#exec#!#numeric|-|a|-|123|-|5|-|0 +#prepst#!#exec#!#numeric|-|a|-|123.4|-|5|-|0 +#prepst#!#exec#!#numeric|-|a|-|123|-|5|-|0 +#prepst#!#exec#!#numeric|-|a|-|12345|-|5|-|0 +#prepst#!#exec#!#numeric|-|a|-||-|5|-|0 +#prepst#!#exec#!#numeric|-|a|-|-123456|-|5|-|0 +#prepst#!#exec#!#numeric|-|a|-|-1234|-|5|-|0 +#prepst#!#exec#!#numeric|-|a|-|-123|-|5|-|0 +##prepst#!#exec#!#numeric|-|a|-|0|-|5|-|0 +#prepst#!#exec#!#numeric|-|a|-|-1|-|3|-|0 +#prepst#!#exec#!#numeric|-|a|-|-123|-|9|-|0 + +SELECT * FROM numeric_table; + +DROP TABLE numeric_table; + +CREATE TABLE numeric_table(num numeric(38, 3)); + +prepst#!#INSERT INTO numeric_table(num) VALUES(@a1) #!#numeric|-|a1|-|3|-|5|-|2 +#prepst#!#exec#!#numeric|-|a1|-|12345|-|5|-|0 +prepst#!#exec#!#numeric|-|a1|-|123.4|-|5|-|2 +prepst#!#exec#!#numeric|-|a1|-|123|-|5|-|2 +prepst#!#exec#!#numeric|-|a1|-|123.45|-|5|-|2 +prepst#!#exec#!#numeric|-|a1|-||-|5|-|2 +prepst#!#exec#!#numeric|-|a1|-|-123.456|-|5|-|2 +prepst#!#exec#!#numeric|-|a1|-|-123.4|-|5|-|2 +prepst#!#exec#!#numeric|-|a1|-|-123|-|5|-|2 +#prepst#!#exec#!#numeric|-|a1|-|0|-|5|-|2 +prepst#!#exec#!#numeric|-|a1|-|-1|-|3|-|2 +prepst#!#exec#!#numeric|-|a1|-|-123|-|9|-|2 + +# Should generate "Error converting data type numeric to decimal" (BABEL-510) +#prepst#!#exec#!#numeric|-|a1|-|2147483647|-|10|-|0 +#prepst#!#exec#!#numeric|-|a1|-|-2147483647|-|10|-|0 +#prepst#!#exec#!#numeric|-|a1|-|2147483646|-|10|-|0 +#prepst#!#exec#!#numeric|-|a1|-|-2147483646|-|10|-|0 +#prepst#!#exec#!#numeric|-|a1|-|2147483648|-|10|-|0 +#prepst#!#exec#!#numeric|-|a1|-|-2147483648|-|10|-|0 + +SELECT * FROM numeric_table; + +DROP TABLE numeric_table; + +# JIRA 507, WORKING FOR BABEL +#CREATE TABLE numeric_table(num numeric(39, 20)); + +CREATE TABLE numeric_table(num numeric(38, 20)); + +prepst#!#INSERT INTO numeric_table(num) VALUES(@a2) #!#numeric|-|a2|-|3|-|5|-|2 +prepst#!#exec#!#numeric|-|a2|-|123.456|-|5|-|2 +prepst#!#exec#!#numeric|-|a2|-|123.4|-|5|-|2 +prepst#!#exec#!#numeric|-|a2|-|123|-|5|-|2 +prepst#!#exec#!#numeric|-|a2|-|123.45|-|5|-|2 +prepst#!#exec#!#numeric|-|a2|-||-|5|-|2 +prepst#!#exec#!#numeric|-|a2|-|-123.456|-|5|-|2 +prepst#!#exec#!#numeric|-|a2|-|-123.4|-|5|-|2 +prepst#!#exec#!#numeric|-|a2|-|-123|-|5|-|2 +#prepst#!#exec#!#numeric|-|a2|-|0|-|5|-|2 +prepst#!#exec#!#numeric|-|a2|-|-1|-|3|-|2 +prepst#!#exec#!#numeric|-|a2|-|-123|-|9|-|2 +#prepst#!#exec#!#numeric|-|a2|-| 2147483647|-|10|-|0 +SELECT * FROM numeric_table; + +DROP TABLE numeric_table; + +CREATE TABLE numeric_table(num numeric(38, 20)); +prepst#!#INSERT INTO numeric_table(num) VALUES(@a3) #!#numeric|-|a3|-|3|-|5|-|2 +prepst#!#exec#!#numeric|-|a3|-|123.456|-|5|-|2 +prepst#!#exec#!#numeric|-|a3|-|123.4|-|5|-|2 +prepst#!#exec#!#numeric|-|a3|-|123|-|5|-|2 +prepst#!#exec#!#numeric|-|a3|-|123.45|-|5|-|2 +prepst#!#exec#!#numeric|-|a3|-||-|5|-|2 +prepst#!#exec#!#numeric|-|a3|-|-123.456|-|5|-|2 +prepst#!#exec#!#numeric|-|a3|-|-123.4|-|5|-|2 +prepst#!#exec#!#numeric|-|a3|-|-123|-|5|-|2 +#prepst#!#exec#!#numeric|-|a3|-|0|-|5|-|2 +prepst#!#exec#!#numeric|-|a3|-|-1|-|3|-|2 +prepst#!#exec#!#numeric|-|a3|-|-123|-|9|-|2 +#prepst#!#exec#!#numeric|-|a3|-| 2147483647|-|10|-|0 +SELECT * FROM numeric_table; + +DROP TABLE numeric_table; + +CREATE TABLE numeric_table(num numeric(38, 21)); +prepst#!#INSERT INTO numeric_table(num) VALUES(@a4) #!#numeric|-|a4|-|3|-|5|-|2 +prepst#!#exec#!#numeric|-|a4|-|123.456|-|5|-|2 +prepst#!#exec#!#numeric|-|a4|-|123.4|-|5|-|2 +prepst#!#exec#!#numeric|-|a4|-|123|-|5|-|2 +prepst#!#exec#!#numeric|-|a4|-|123.45|-|5|-|2 +prepst#!#exec#!#numeric|-|a4|-||-|5|-|2 +prepst#!#exec#!#numeric|-|a4|-|-123.456|-|5|-|2 +prepst#!#exec#!#numeric|-|a4|-|-123.4|-|5|-|2 +prepst#!#exec#!#numeric|-|a4|-|-123|-|5|-|2 +#prepst#!#exec#!#numeric|-|a4|-|0|-|5|-|2 +prepst#!#exec#!#numeric|-|a4|-|-1|-|3|-|2 +prepst#!#exec#!#numeric|-|a4|-|-123|-|9|-|2 +#prepst#!#exec#!#numeric|-|a4|-| 2147483647|-|10|-|0 +SELECT * FROM numeric_table; + +DROP TABLE numeric_table; + +CREATE TABLE numeric_table(num numeric(38, 22)); +prepst#!#INSERT INTO numeric_table(num) VALUES(@a5) #!#numeric|-|a5|-|3|-|5|-|2 +prepst#!#exec#!#numeric|-|a5|-|123.456|-|5|-|2 +prepst#!#exec#!#numeric|-|a5|-|123.4|-|5|-|2 +prepst#!#exec#!#numeric|-|a5|-|123|-|5|-|2 +prepst#!#exec#!#numeric|-|a5|-|123.45|-|5|-|2 +prepst#!#exec#!#numeric|-|a5|-||-|5|-|2 +prepst#!#exec#!#numeric|-|a5|-|-123.456|-|5|-|2 +prepst#!#exec#!#numeric|-|a5|-|-123.4|-|5|-|2 +prepst#!#exec#!#numeric|-|a5|-|-123|-|5|-|2 +#prepst#!#exec#!#numeric|-|a5|-|0|-|5|-|2 +prepst#!#exec#!#numeric|-|a5|-|-1|-|3|-|2 +prepst#!#exec#!#numeric|-|a5|-|-123|-|9|-|2 +#prepst#!#exec#!#numeric|-|a5|-| 2147483647|-|10|-|0 +SELECT * FROM numeric_table; + +DROP TABLE numeric_table; + +CREATE TABLE numeric_table(num numeric(38, 23)); +prepst#!#INSERT INTO numeric_table(num) VALUES(@a6) #!#numeric|-|a6|-|3|-|5|-|2 +prepst#!#exec#!#numeric|-|a6|-|123.456|-|5|-|2 +prepst#!#exec#!#numeric|-|a6|-|123.4|-|5|-|2 +prepst#!#exec#!#numeric|-|a6|-|123|-|5|-|2 +prepst#!#exec#!#numeric|-|a6|-|123.45|-|5|-|2 +prepst#!#exec#!#numeric|-|a6|-||-|5|-|2 +prepst#!#exec#!#numeric|-|a6|-|-123.456|-|5|-|2 +prepst#!#exec#!#numeric|-|a6|-|-123.4|-|5|-|2 +prepst#!#exec#!#numeric|-|a6|-|-123|-|5|-|2 +#prepst#!#exec#!#numeric|-|a6|-|0|-|5|-|2 +prepst#!#exec#!#numeric|-|a6|-|-1|-|3|-|2 +prepst#!#exec#!#numeric|-|a6|-|-123|-|9|-|2 +#prepst#!#exec#!#numeric|-|a6|-| 2147483647|-|10|-|0 +SELECT * FROM numeric_table; + +DROP TABLE numeric_table; + +CREATE TABLE numeric_table(num numeric(38, 25)); +prepst#!#INSERT INTO numeric_table(num) VALUES(@a7) #!#numeric|-|a7|-|3|-|5|-|2 +prepst#!#exec#!#numeric|-|a7|-|123.456|-|5|-|2 +prepst#!#exec#!#numeric|-|a7|-|123.4|-|5|-|2 +prepst#!#exec#!#numeric|-|a7|-|123|-|5|-|2 +prepst#!#exec#!#numeric|-|a7|-|123.45|-|5|-|2 +prepst#!#exec#!#numeric|-|a7|-||-|5|-|2 +prepst#!#exec#!#numeric|-|a7|-|-123.456|-|5|-|2 +prepst#!#exec#!#numeric|-|a7|-|-123.4|-|5|-|2 +prepst#!#exec#!#numeric|-|a7|-|-123|-|5|-|2 +#prepst#!#exec#!#numeric|-|a7|-|0|-|5|-|2 +prepst#!#exec#!#numeric|-|a7|-|-1|-|3|-|2 +prepst#!#exec#!#numeric|-|a7|-|-123|-|9|-|2 +#prepst#!#exec#!#numeric|-|a7|-| 247483647|-|10|-|0 +#prepst#!#exec#!#numeric|-|a7|-|-247483647|-|10|-|0 +#SELECT * FROM numeric_table; + +DROP TABLE numeric_table; diff --git a/contrib/test/dotnet/input/Datatypes/TestReal.txt b/contrib/test/dotnet/input/Datatypes/TestReal.txt new file mode 100644 index 00000000000..5c05836a056 --- /dev/null +++ b/contrib/test/dotnet/input/Datatypes/TestReal.txt @@ -0,0 +1,24 @@ +CREATE TABLE REAL_dt (a REAL) +prepst#!# INSERT INTO REAL_dt(a) values(@a) #!#REAL|-|a|-|0 +prepst#!#exec#!#REAL|-|a|-|1.050 +prepst#!#exec#!#REAL|-|a|-|01.05 +prepst#!#exec#!#REAL|-|a|-|0001202 +prepst#!#exec#!#REAL|-|a|-|-024112329 +prepst#!#exec#!#REAL|-|a|-|-02.5 +prepst#!#exec#!#REAL|-|a|-|0000000000000000086 +prepst#!#exec#!#REAL|-|a|-|-3.40E+38 +prepst#!#exec#!#REAL|-|a|-|3.40E+38 +prepst#!#exec#!#REAL|-|a|-| +SELECT * FROM REAL_dt; +INSERT INTO REAL_dt(a) values(0) +INSERT INTO REAL_dt(a) values(1.050) +INSERT INTO REAL_dt(a) values(01.05) +INSERT INTO REAL_dt(a) values(-004) +INSERT INTO REAL_dt(a) values(-0122455324.5) +INSERT INTO REAL_dt(a) values(-000002) +INSERT INTO REAL_dt(a) values(0000000000000000086) +INSERT INTO REAL_dt(a) values(-3.40E+38) +INSERT INTO REAL_dt(a) values(3.40E+38) +INSERT INTO REAL_dt(a) values(NULL) +SELECT * FROM REAL_dt; +DROP TABLE REAL_dt; \ No newline at end of file diff --git a/contrib/test/dotnet/input/Datatypes/TestSmallDatetime.txt b/contrib/test/dotnet/input/Datatypes/TestSmallDatetime.txt new file mode 100644 index 00000000000..ebcc4e91ccc --- /dev/null +++ b/contrib/test/dotnet/input/Datatypes/TestSmallDatetime.txt @@ -0,0 +1,35 @@ +CREATE TABLE SMALLDATETIME_dt (a SMALLDATETIME) +prepst#!# INSERT INTO SMALLDATETIME_dt(a) values(@a) #!#SMALLDATETIME|-|a|-|2000-12-13 12:58:23 +prepst#!#exec#!#SMALLDATETIME|-|a|-|2007-05-08 12:35:29 +prepst#!#exec#!#SMALLDATETIME|-|a|-|2007-05-08 12:35:30 +prepst#!#exec#!#SMALLDATETIME|-|a|-|2007-05-08 12:59:59.998 +prepst#!#exec#!#SMALLDATETIME|-|a|-|2000-02-28 23:59:59.999 +prepst#!#exec#!#SMALLDATETIME|-|a|-|1900-02-28 23:59:59.999 +prepst#!#exec#!#SMALLDATETIME|-|a|-|2000-02-28 23:45:29.999 +prepst#!#exec#!#SMALLDATETIME|-|a|-|2000-02-28 23:45:30 +prepst#!#exec#!#SMALLDATETIME|-|a|-|2000-02-28 23:45:29 +prepst#!#exec#!#SMALLDATETIME|-|a|-|1900-02-28 23:45:30 +prepst#!#exec#!#SMALLDATETIME|-|a|-|1900-02-28 23:45:29 +prepst#!#exec#!#SMALLDATETIME|-|a|-|2000-12-13 12:58:30 +prepst#!#exec#!#SMALLDATETIME|-|a|-|2000-02-28 23:45:29.998 +prepst#!#exec#!#SMALLDATETIME|-|a|-|1900-01-01 00:00:00 +prepst#!#exec#!#SMALLDATETIME|-|a|-|2079-06-06 23:59:29 +prepst#!#exec#!#SMALLDATETIME|-|a|-| +SELECT * FROM SMALLDATETIME_dt; +INSERT INTO SMALLDATETIME_dt(a) values('2000-12-13 12:58:23'); +INSERT INTO SMALLDATETIME_dt(a) values('2007-05-08 12:35:29'); +INSERT INTO SMALLDATETIME_dt(a) values('2007-05-08 12:35:30'); +INSERT INTO SMALLDATETIME_dt(a) values('2007-05-08 12:59:59.998'); +INSERT INTO SMALLDATETIME_dt(a) values('2000-02-28 23:59:59.999'); +INSERT INTO SMALLDATETIME_dt(a) values('1900-02-28 23:59:59.999'); +INSERT INTO SMALLDATETIME_dt(a) values('2000-02-28 23:45:29.999'); +INSERT INTO SMALLDATETIME_dt(a) values('2000-02-28 23:45:30'); +INSERT INTO SMALLDATETIME_dt(a) values('2000-02-28 23:45:29'); +INSERT INTO SMALLDATETIME_dt(a) values('1900-02-28 23:45:29'); +INSERT INTO SMALLDATETIME_dt(a) values('1900-12-13 12:58:30'); +INSERT INTO SMALLDATETIME_dt(a) values('2000-02-28 23:45:29.998'); +INSERT INTO SMALLDATETIME_dt(a) values('1900-01-01 00:00:00'); +INSERT INTO SMALLDATETIME_dt(a) values('2079-06-06 23:59:29'); +INSERT INTO SMALLDATETIME_dt(a) values(NULL); +SELECT * FROM SMALLDATETIME_dt; +DROP TABLE SMALLDATETIME_dt; \ No newline at end of file diff --git a/contrib/test/dotnet/input/Datatypes/TestSmallInt.txt b/contrib/test/dotnet/input/Datatypes/TestSmallInt.txt new file mode 100644 index 00000000000..79e6427345e --- /dev/null +++ b/contrib/test/dotnet/input/Datatypes/TestSmallInt.txt @@ -0,0 +1,24 @@ +CREATE TABLE SMALLINT_dt (a SMALLINT) +prepst#!# INSERT INTO SMALLINT_dt(a) values(@a) #!#SMALLINT|-|a|-|0 +prepst#!#exec#!#SMALLINT|-|a|-|-10 +prepst#!#exec#!#SMALLINT|-|a|-|100 +prepst#!#exec#!#SMALLINT|-|a|-|002 +prepst#!#exec#!#SMALLINT|-|a|-|-029 +prepst#!#exec#!#SMALLINT|-|a|-|-1234 +prepst#!#exec#!#SMALLINT|-|a|-|876 +prepst#!#exec#!#SMALLINT|-|a|-|-32768 +prepst#!#exec#!#SMALLINT|-|a|-|32767 +prepst#!#exec#!#SMALLINT|-|a|-| +SELECT * FROM SMALLINT_dt; +INSERT INTO SMALLINT_dt(a) values(0) +INSERT INTO SMALLINT_dt(a) values(-10) +INSERT INTO SMALLINT_dt(a) values(100) +INSERT INTO SMALLINT_dt(a) values(002) +INSERT INTO SMALLINT_dt(a) values(-029) +INSERT INTO SMALLINT_dt(a) values(-1234) +INSERT INTO SMALLINT_dt(a) values(876) +INSERT INTO SMALLINT_dt(a) values(-32768) +INSERT INTO SMALLINT_dt(a) values(32767) +INSERT INTO SMALLINT_dt(a) values(NULL) +SELECT * FROM SMALLINT_dt; +DROP TABLE SMALLINT_dt; \ No newline at end of file diff --git a/contrib/test/dotnet/input/Datatypes/TestSqlVariant.txt b/contrib/test/dotnet/input/Datatypes/TestSqlVariant.txt new file mode 100644 index 00000000000..3ee31d1e83b --- /dev/null +++ b/contrib/test/dotnet/input/Datatypes/TestSqlVariant.txt @@ -0,0 +1,41 @@ +CREATE TABLE SQL_VARIANT_dt (a sql_variant) +prepst#!# INSERT INTO SQL_VARIANT_dt(a) values(@a) #!#SQL_VARIANT-int|-|a|-|0 +prepst#!#exec#!#SQL_VARIANT-INT|-|a|-|-100 +prepst#!#exec#!#SQL_VARIANT-MONEY|-|a|-|122.100 +prepst#!#exec#!#SQL_VARIANT-REAL|-|a|-|123.45 +prepst#!#exec#!#SQL_VARIANT-SMALLINT|-|a|-|60 +prepst#!#exec#!#SQL_VARIANT-BIT|-|a|-|0 +prepst#!#exec#!#SQL_VARIANT-BINARY|-|a|-|6789 +prepst#!#exec#!#SQL_VARIANT-FLOAT|-|a|-|1234.56 +prepst#!#exec#!#SQL_VARIANT-SMALLMONEY|-|a|-|78.56 +prepst#!#exec#!#numeric|-|a|-|123.456|-|5|-|2 +prepst#!#exec#!#SQL_VARIANT-INT|-|a|-| +SELECT * FROM SQL_VARIANT_dt; +drop table SQL_VARIANT_dt; +CREATE TABLE SQL_VARIANT_dt (a sql_variant) +INSERT INTO SQL_VARIANT_dt(a) values(cast (1 as bit)) +INSERT INTO SQL_VARIANT_dt(a) values(cast (6 as tinyint)) +INSERT INTO SQL_VARIANT_dt(a) values(cast (60 as smallint)) +INSERT INTO SQL_VARIANT_dt(a) values(cast (600 as int)) +INSERT INTO SQL_VARIANT_dt(a) values(cast (60000 as bigint)) +INSERT INTO SQL_VARIANT_dt(a) values(cast (600.00 as real)) +INSERT INTO SQL_VARIANT_dt(a) values(cast (60000.00 as float)) +INSERT INTO SQL_VARIANT_dt(a) values(cast (700.00 as smallmoney)) +INSERT INTO SQL_VARIANT_dt(a) values(cast (70000.00 as money)) +INSERT INTO SQL_VARIANT_dt(a) values(cast (123.45 as numeric(5, 2))) +INSERT INTO SQL_VARIANT_dt(a) values(cast ('abc' as char(10))) +INSERT INTO SQL_VARIANT_dt(a) values(cast ('abc' as nchar(10))) +INSERT INTO SQL_VARIANT_dt(a) values(cast ('abc' as varchar(10))) +INSERT INTO SQL_VARIANT_dt(a) values(cast ('abc' as nvarchar(10))) +INSERT INTO SQL_VARIANT_dt(a) values(cast (123 as binary(10))) +INSERT INTO SQL_VARIANT_dt(a) values(cast (123 as varbinary(10))) +INSERT INTO SQL_VARIANT_dt(a) values(cast ('1968-12-13' as date)) +INSERT INTO SQL_VARIANT_dt(a) values(cast ('1968-12-13 14:37:45.123' as smalldatetime)) +INSERT INTO SQL_VARIANT_dt(a) values(cast ('1968-12-13 14:37:45.123' as datetime)) +INSERT INTO SQL_VARIANT_dt(a) values(cast ('1968-12-13 14:37:45.123456' as datetime2(4))) +INSERT INTO SQL_VARIANT_dt(a) values(cast ('14:37:45.123456' as time(5))) +SELECT * FROM SQL_VARIANT_dt; +Drop table SQL_VARIANT_dt; +prepst#!# select @a #!#SQL_VARIANT-int|-|a|-| +CREATE PROCEDURE temp_sql_variant @a sql_variant OUTPUT AS SELECT @a; END; +#storedproc#!#prep#!#temp_sql_variant#!#SQL_VARIANT-INT|-|a|-| \ No newline at end of file diff --git a/contrib/test/dotnet/input/Datatypes/TestText.txt b/contrib/test/dotnet/input/Datatypes/TestText.txt new file mode 100644 index 00000000000..c915d70e2c1 --- /dev/null +++ b/contrib/test/dotnet/input/Datatypes/TestText.txt @@ -0,0 +1,12 @@ +CREATE TABLE TEXT_dt (b ntext) +prepst#!# INSERT INTO TEXT_dt( b) values( @b) #!#NTEXT|-|b|-|/Users/kushaal/Downloads/sample.txt +#prepst#!#exec#!#TEXT|-|b|-|utils/blank.txt#!#NTEXT|-|b|-|/Users/kushaal/Downloads/blank.txt +#prepst#!#exec#!#TEXT|-|b|-|#!#NTEXT|-|b|-| +#prepst#!#exec#!#TEXT|-|b|-|#!#NTEXT|-|b|-|/Users/kushaal/Downloads/utf16.txt + +prepst#!#exec#!#NTEXT|-|b|-|/Users/kushaal/Downloads/emojisText.txt +prepst#!#exec#!#NTEXT|-|b|-|/Users/kushaal/Downloads/sample.txt + +prepst#!#INSERT INTO TEXT_dt(b) values(@b1) #!#ntext|-|b1|-|/Users/kushaal/Downloads/devanagari.txt +SELECT * FROM TEXT_dt; +DROP TABLE TEXT_dt; \ No newline at end of file diff --git a/contrib/test/dotnet/input/Datatypes/TestTime.txt b/contrib/test/dotnet/input/Datatypes/TestTime.txt new file mode 100644 index 00000000000..fcb6805a487 --- /dev/null +++ b/contrib/test/dotnet/input/Datatypes/TestTime.txt @@ -0,0 +1,104 @@ +Create table TestTime(a time(6)) + +prepst#!# Insert into TestTime Values(@a) #!#Time|-|a|-|12:45:37.123|-|0 +prepst#!#exec#!#Time|-|a|-|12:45:37.123|-|3 +prepst#!#exec#!#Time|-|a|-|12:45:37.12|-|2 +prepst#!#exec#!#Time|-|a|-|12:45:37.1|-|1 +prepst#!#exec#!#Time|-|a|-|12:45:37.1234|-|4 +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|6 +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|5 +prepst#!#exec#!#Time|-|a|-| + +select * from TestTime + +Drop table TestTime + +Create table TestTime(a time(5)) + +prepst#!# Insert into TestTime Values(@a) #!#Time|-|a|-|12:45:37.123|-|0 +prepst#!#exec#!#Time|-|a|-|12:45:37.123|-|3 +prepst#!#exec#!#Time|-|a|-|12:45:37.12|-|2 +prepst#!#exec#!#Time|-|a|-|12:45:37.1|-|1 +prepst#!#exec#!#Time|-|a|-|12:45:37.1234|-|4 +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|6 +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|5 +prepst#!#exec#!#Time|-|a|-| + +select * from TestTime + +Drop table TestTime + +Create table TestTime(a time(4)) + +prepst#!# Insert into TestTime Values(@a) #!#Time|-|a|-|12:45:37.123|-|0 +prepst#!#exec#!#Time|-|a|-|12:45:37.123|-|3 +prepst#!#exec#!#Time|-|a|-|12:45:37.12|-|2 +prepst#!#exec#!#Time|-|a|-|12:45:37.1|-|1 +prepst#!#exec#!#Time|-|a|-|12:45:37.1234|-|4 +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|6 +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|5 +prepst#!#exec#!#Time|-|a|-| + +select * from TestTime + +Drop table TestTime + +Create table TestTime(a time(3)) + +prepst#!# Insert into TestTime Values(@a) #!#Time|-|a|-|12:45:37.123|-|0 +prepst#!#exec#!#Time|-|a|-|12:45:37.123|-|3 +prepst#!#exec#!#Time|-|a|-|12:45:37.12|-|2 +prepst#!#exec#!#Time|-|a|-|12:45:37.1|-|1 +prepst#!#exec#!#Time|-|a|-|12:45:37.1234|-|4 +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|6 +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|5 +prepst#!#exec#!#Time|-|a|-| + +select * from TestTime + +Drop table TestTime + +Create table TestTime(a time(2)) + +prepst#!# Insert into TestTime Values(@a) #!#Time|-|a|-|12:45:37.123|-|0 +prepst#!#exec#!#Time|-|a|-|12:45:37.123|-|3 +prepst#!#exec#!#Time|-|a|-|12:45:37.12|-|2 +prepst#!#exec#!#Time|-|a|-|12:45:37.1|-|1 +prepst#!#exec#!#Time|-|a|-|12:45:37.1234|-|4 +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|6 +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|5 +prepst#!#exec#!#Time|-|a|-| + +select * from TestTime + +Drop table TestTime + +Create table TestTime(a time(1)) + +prepst#!# Insert into TestTime Values(@a) #!#Time|-|a|-|12:45:37.123|-|0 +prepst#!#exec#!#Time|-|a|-|12:45:37.123|-|3 +prepst#!#exec#!#Time|-|a|-|12:45:37.12|-|2 +prepst#!#exec#!#Time|-|a|-|12:45:37.1|-|1 +prepst#!#exec#!#Time|-|a|-|12:45:37.1234|-|4 +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|6 +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|5 +prepst#!#exec#!#Time|-|a|-| + +select * from TestTime + +Drop table TestTime + +Create table TestTime(a time(0)) + +prepst#!# Insert into TestTime Values(@a) #!#Time|-|a|-|12:45:37.123|-|0 +prepst#!#exec#!#Time|-|a|-|12:45:37.123|-|3 +prepst#!#exec#!#Time|-|a|-|12:45:37.12|-|2 +prepst#!#exec#!#Time|-|a|-|12:45:37.1|-|1 +prepst#!#exec#!#Time|-|a|-|12:45:37.1234|-|4 +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|6 +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|5 +prepst#!#exec#!#Time|-|a|-| + +select * from TestTime + +Drop table TestTime \ No newline at end of file diff --git a/contrib/test/dotnet/input/Datatypes/TestTinyInt.txt b/contrib/test/dotnet/input/Datatypes/TestTinyInt.txt new file mode 100644 index 00000000000..9a00b3eb451 --- /dev/null +++ b/contrib/test/dotnet/input/Datatypes/TestTinyInt.txt @@ -0,0 +1,24 @@ +CREATE TABLE TINYINT_dt (a TINYINT) +prepst#!# INSERT INTO TINYINT_dt(a) values(@a) #!#TINYINT|-|a|-|0 +prepst#!#exec#!#TINYINT|-|a|-|-10 +prepst#!#exec#!#TINYINT|-|a|-|100 +prepst#!#exec#!#TINYINT|-|a|-|002 +prepst#!#exec#!#TINYINT|-|a|-|029 +prepst#!#exec#!#TINYINT|-|a|-|004 +prepst#!#exec#!#TINYINT|-|a|-|87 +prepst#!#exec#!#TINYINT|-|a|-|0 +prepst#!#exec#!#TINYINT|-|a|-|254 +prepst#!#exec#!#TINYINT|-|a|-| +SELECT * FROM TINYINT_dt; +INSERT INTO TINYINT_dt(a) values(0) +INSERT INTO TINYINT_dt(a) values(120) +INSERT INTO TINYINT_dt(a) values(100) +INSERT INTO TINYINT_dt(a) values(004) +INSERT INTO TINYINT_dt(a) values(0) +INSERT INTO TINYINT_dt(a) values(002) +INSERT INTO TINYINT_dt(a) values(86) +INSERT INTO TINYINT_dt(a) values(0) +INSERT INTO TINYINT_dt(a) values(255) +INSERT INTO TINYINT_dt(a) values(NULL) +SELECT * FROM TINYINT_dt; +DROP TABLE TINYINT_dt; \ No newline at end of file diff --git a/contrib/test/dotnet/input/Datatypes/TestTvp.txt b/contrib/test/dotnet/input/Datatypes/TestTvp.txt new file mode 100644 index 00000000000..42d0908f59f --- /dev/null +++ b/contrib/test/dotnet/input/Datatypes/TestTvp.txt @@ -0,0 +1,5 @@ +create schema testtvp +create type testtvp.tableType as table (a int, b smallint, c bigint, d tinyint, e bit, f char(10), g nchar(10), h varchar(10), i nvarchar(10), j text, k ntext, l varbinary(10), m binary(10), n date, o datetime, p money, q uniqueidentifier,r float, s real, t numeric(4,3), u decimal(5,3), v time(5), w datetime2(5)) +prepst#!#Select * from @a #!#tvp|-|a|-|testtvp.tableType|-|/Users/kushaal/Downloads/tvp-dotnet.csv +drop type testtvp.tableType; +drop schema testtvp \ No newline at end of file diff --git a/contrib/test/dotnet/input/Datatypes/TestUDD.txt b/contrib/test/dotnet/input/Datatypes/TestUDD.txt new file mode 100644 index 00000000000..5772d41774d --- /dev/null +++ b/contrib/test/dotnet/input/Datatypes/TestUDD.txt @@ -0,0 +1,78 @@ +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_unique_constraint', 'ignore'; +CREATE TYPE udd_varchar from varchar(15); +CREATE TYPE udd_nvarchar from nvarchar(15); +CREATE TYPE udd_int from int; +CREATE TYPE udd_char from char(25); +CREATE TYPE udd_nchar from nchar(20) NOT NULL; +CREATE TYPE udd_datetime from datetime; +CREATE TYPE udd_numeric from numeric(4,1); + +CREATE TABLE udd_dt (a udd_varchar UNIQUE, b udd_nvarchar, c udd_int PRIMARY KEY, d udd_char DEFAULT 'Whoops!', e udd_nchar, f udd_datetime, g udd_numeric CHECK (g >= 103.5)) + +INSERT INTO udd_dt VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + +#passing a non unique value in column a +#throws error: duplicate key value violates unique constraint +INSERT INTO udd_dt VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + +#passing a non unique value in column c +#throws error: duplicate key value violates unique constraint +INSERT INTO udd_dt VALUES ('Banana', N'green', 1, 'Bangalore', N'Crying😭', '2007-01-14 23:34:23.749', 908.7); + +#passing a NULL value in column c +#throws error: null value in column "c" violates not-null constraint +INSERT INTO udd_dt VALUES ('Guava', N'yellow', NULL, 'Mumbai', N'Smirk😏', '1907-05-09 11:14:13.749', 245.6); + +#passing no value for column d +INSERT INTO udd_dt(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + +#passing a NULL value in column e +#throws error: domain udd_nchar does not allow null values +INSERT INTO udd_dt VALUES ('Kiwi', N'purple', 4, 'Kolkata', NULL, '1907-05-09 11:14:13.749', 874.0); + +#passing a value less than 103.5 in column g +#throws error: new row for relation "udd_dt" violates check constraint "udd_dt_g_check" +INSERT INTO udd_dt VALUES ('Grape', N'white', 5, 'Pune', N'Angry😠', '2000-02-28 23:59:59.989', 100.1); + +SELECT * FROM udd_dt; + +DROP TABLE udd_dt; + +CREATE TABLE udd_dt (a udd_varchar UNIQUE, b udd_nvarchar, c udd_int PRIMARY KEY, d udd_char DEFAULT 'Whoops!', e udd_nchar, f udd_datetime, g udd_numeric CHECK (g >= 103.5)) + +prepst#!#INSERT INTO udd_dt VALUES (@a, @b, @c, @d, @e, @f, @g)#!#varchar|-|a|-|Apple#!#nvarchar|-|b|-|red#!#int|-|c|-|1#!#char|-|d|-|Delhi#!#nchar|-|e|-|Sad😞#!#datetime|-|f|-|2000-12-13 12:58:23.123#!#numeric|-|g|-|123.1|-|4|-|1 + +#passing a non unique value in column a +#throws error: duplicate key value violates unique constraint +prepst#!#exec#!#varchar|-|a|-|Apple#!#nvarchar|-|b|-|blue#!#int|-|c|-|2#!#char|-|d|-|Chennai#!#nchar|-|e|-|Neutral😐#!#datetime|-|f|-|2006-11-11 22:47:23.128#!#numeric|-|g|-|512.4|-|4|-|1 + +#passing a non unique value in column c +#throws error: duplicate key value violates unique constraint +prepst#!#exec#!#varchar|-|a|-|Banana#!#nvarchar|-|b|-|green#!#int|-|c|-|1#!#char|-|d|-|Bangalore#!#nchar|-|e|-|Crying😭#!#datetime|-|f|-|2007-01-14 23:34:23.749#!#numeric|-|g|-|908.7|-|4|-|1 + +#passing a NULL value in column c +#throws error: null value in column "c" violates not-null constraint +prepst#!#exec#!#varchar|-|a|-|Guava#!#nvarchar|-|b|-|yellow#!#int|-|c|-|#!#char|-|d|-|Mumbai#!#nchar|-|e|-|Smirk😏'#!#datetime|-|f|-|1907-05-09 11:14:13.749#!#numeric|-|g|-|245.6|-|4|-|1 + +#passing a NULL value in column e +#throws error: domain udd_nchar does not allow null values +prepst#!#exec#!#varchar|-|a|-|Kiwi#!#nvarchar|-|b|-|purple#!#int|-|c|-|4#!#char|-|d|-|Kolkata#!#nchar|-|e|-|#!#datetime|-|f|-|1907-05-09 11:14:13.749#!#numeric|-|g|-|874.0|-|4|-|1 + +#passing a value less than 103.5 in column g +#throws error: new row for relation "udd_dt" violates check constraint "udd_dt_g_check" +prepst#!#exec#!#varchar|-|a|-|Grape#!#nvarchar|-|b|-|white#!#int|-|c|-|5#!#char|-|d|-|Pune#!#nchar|-|e|-|Angry😠#!#datetime|-|f|-|2000-02-28 23:59:59.989#!#numeric|-|g|-|100.1|-|4|-|1 + +#passing no value for column d +prepst#!#INSERT INTO udd_dt(a, b, c, e, f, g) VALUES (@a1, @b1, @c1, @e1, @f1, @g1)#!#varchar|-|a1|-|Orange#!#nvarchar|-|b1|-|#!#int|-|c1|-|5#!#nchar|-|e1|-|Happy😀#!#datetime|-|f1|-|1900-02-28 23:59:59.989#!#numeric|-|g1|-|342.5|-|4|-|1 + +SELECT * FROM udd_dt; + +DROP TABLE udd_dt; + +DROP TYPE udd_varchar +DROP TYPE udd_nvarchar +DROP TYPE udd_int +DROP TYPE udd_char +DROP TYPE udd_nchar +DROP TYPE udd_datetime +DROP TYPE udd_numeric diff --git a/contrib/test/dotnet/input/Datatypes/TestUID.txt b/contrib/test/dotnet/input/Datatypes/TestUID.txt new file mode 100644 index 00000000000..11f68a296b3 --- /dev/null +++ b/contrib/test/dotnet/input/Datatypes/TestUID.txt @@ -0,0 +1,36 @@ +CREATE TABLE uniqueidentifier_dt (a uniqueidentifier); + +INSERT INTO uniqueidentifier_dt VALUES ('51f178a6-53c7-472c-9be1-1c08942342d7') +INSERT INTO uniqueidentifier_dt VALUES ('dd8cb046-461d-411e-be40-d219252ce849') +INSERT INTO uniqueidentifier_dt VALUES ('b84ebcc9-c927-4cfe-b08e-dc7f25b5087c') +INSERT INTO uniqueidentifier_dt VALUES ('bab96bc8-60b9-40dd-b0de-c90a80f5739e') +INSERT INTO uniqueidentifier_dt VALUES ('d424fdef-1404-4bac-8289-c725b540f93d') +INSERT INTO uniqueidentifier_dt VALUES ('60aeaa5c-e272-4b17-bad0-c25710fd7a60') +INSERT INTO uniqueidentifier_dt VALUES ('253fb146-7e45-45ef-9d92-bbe14a8ad1b2') +INSERT INTO uniqueidentifier_dt VALUES ('dba2726c-2131-409f-aefa-5c8079571623') +INSERT INTO uniqueidentifier_dt VALUES ('b3400fa7-3a60-40ec-b40e-fc85a3eb262d') +INSERT INTO uniqueidentifier_dt VALUES ('851763b5-b068-42ae-88ec-764bfb0e5605') +INSERT INTO uniqueidentifier_dt VALUES (NULL) + +SELECT * FROM uniqueidentifier_dt + +prepst#!#INSERT INTO uniqueidentifier_dt VALUES (@a1)#!#uniqueidentifier|-|a1|-|51f178a6-53c7-472c-9be1-1c08942342d7 +prepst#!#exec#!#uniqueidentifier|-|a1|-|767392df-87d0-450d-9b24-85a86c02811d +prepst#!#exec#!#uniqueidentifier|-|a1|-|9bcb5632-53c3-4695-b617-d9a7055813ce +prepst#!#exec#!#uniqueidentifier|-|a1|-|ac81a140-f686-4259-9b90-dd46f10b355f +prepst#!#exec#!#uniqueidentifier|-|a1|-|3d08372d-770c-48b9-9740-a667d036680e +prepst#!#exec#!#uniqueidentifier|-|a1|-|518d52c7-4d79-4143-ab33-b3765689fdf4 +prepst#!#exec#!#uniqueidentifier|-|a1|-|bc3fa456-7391-4060-b5d8-430048075cf4 +prepst#!#exec#!#uniqueidentifier|-|a1|-|3b75b2dd-01b7-4958-9de7-f92410693547 +prepst#!#exec#!#uniqueidentifier|-|a1|-|ce8af10a-2709-43b0-9e4e-a02753929d17 +prepst#!#exec#!#uniqueidentifier|-|a1|-|5b7c2e8d-6d90-411d-8e19-9a81067e6f6c +prepst#!#exec#!#uniqueidentifier|-|a1|-| + +SELECT * FROM uniqueidentifier_dt; + +# to demonstrate the truncation of data when the value is too long +INSERT INTO uniqueidentifier_dt VALUES ('51f178a6-53c7-472c-9be1-1c08942342d7thisIsTooLong') +prepst#!#INSERT INTO uniqueidentifier_dt VALUES (@a2)#!#uniqueidentifier|-|a2|-|51f178a6-53c7-472c-9be1-1c08942342d7 +#prepst#!#exec#!#uniqueidentifier|-|a2|-|767392df-87d0-450d-9b24-85a86c02811dthisIsTooLong +SELECT * FROM uniqueidentifier_dt; +DROP TABLE uniqueidentifier_dt; \ No newline at end of file diff --git a/contrib/test/dotnet/input/Datatypes/TestVarChar.txt b/contrib/test/dotnet/input/Datatypes/TestVarChar.txt new file mode 100644 index 00000000000..807cb3567f8 --- /dev/null +++ b/contrib/test/dotnet/input/Datatypes/TestVarChar.txt @@ -0,0 +1,6 @@ +CREATE TABLE VARCHAR_dt (a VARCHAR(20), b NVARCHAR(24)) +prepst#!# INSERT INTO VARCHAR_dt(a, b) values(@a, @b) #!#VARCHAR|-|a|-|Dipesh123#!#NVARCHAR|-|b|-|Dhameliya123 +prepst#!#exec#!#VARCHAR|-|a|-|abcdefghijklmnopqrst#!#NVARCHAR|-|b|-|abcdefghijklmnopqrstuvwx +prepst#!#exec#!#VARCHAR|-|a|-|abcdefghijklmnopqrstu#!#NVARCHAR|-|b|-|abcdefghijklmnopqrstuvwxy +select * from VARCHAR_dt +drop table VARCHAR_dt; diff --git a/contrib/test/dotnet/input/Datatypes/TestXML.txt b/contrib/test/dotnet/input/Datatypes/TestXML.txt new file mode 100644 index 00000000000..d459ef3705f --- /dev/null +++ b/contrib/test/dotnet/input/Datatypes/TestXML.txt @@ -0,0 +1,8 @@ +CREATE TABLE XML_dt (a XML) +prepst#!# INSERT INTO XML_dt values(@a) #!#XML|-|a|-|Contact Name 2YYY-YYY-YYYY +prepst#!#exec#!#XML|-|a|-| +prepst#!#exec#!#XML|-|a|-| +SELECT * FROM XML_dt; +INSERT INTO XML_dt values('Contact Name 2YYY-YYY-YYYY') +SELECT * FROM XML_dt; +DROP TABLE XML_dt; \ No newline at end of file diff --git a/contrib/test/dotnet/input/PrepareExec/TestPrepareExec.txt b/contrib/test/dotnet/input/PrepareExec/TestPrepareExec.txt new file mode 100644 index 00000000000..b9f1410c200 --- /dev/null +++ b/contrib/test/dotnet/input/PrepareExec/TestPrepareExec.txt @@ -0,0 +1,61 @@ +#DROP TABLE prep_exec_t1; + +CREATE TABLE prep_exec_t1(a int, b float, c smallint, d real, e int); + + +# TEST SINGLE PREP/EXEC WITH MULTI EXECUTION + +prepst#!#INSERT INTO prep_exec_t1 VALUES(@a, @b, @c, @d, @e)#!#int|-|a|-|100 #!#float|-|b|-|10.1 #!#smallint|-|c|-|10 #!#real|-|d|-|10.1 #!#int|-|e|-| +prepst#!#exec#!#int|-|a|-|200 #!#float|-|b|-|20.2 #!#smallint|-|c|-|20 #!#real|-|d|-|20.2 #!#int|-|e|-| +prepst#!#exec#!#int|-|a|-|200 #!#float|-|b|-|20.2 #!#smallint|-|c|-|20 #!#real|-|d|-|20.2 #!#int|-|e|-| +prepst#!#exec#!#float|-|a|-|300.1 #!#float|-|b|-|30.3 #!#smallint|-|c|-|30 #!#real|-|d|-|30.3 #!#int|-|e|-| +prepst#!#exec#!#int|-|a|-|400 #!#float|-|b|-|40.3 #!#smallint|-|c|-|40 #!#real|-|d|-|40.4 #!#smallint|-|e|-| + +Select * from prep_exec_t1; + +Select * from prep_exec_t1 WHERE a = 100; + +# Not working for babel raised bug relatede to no metadata=true +#prepst#!#SELECT * FROM prep_exec_t1 WHERE a=@x#!#int|-|x|-|100 +#prepst#!#exec#!#int|-|x|-|200 +#prepst#!#exec#!#int|-|x|-|300 +#prepst#!#exec#!#int|-|x|-|400 + + +# TEST SINGLE PREP/EXEC WITH MULTI EXECUTION + +prepst#!#INSERT INTO prep_exec_t1 VALUES(@q, @z, @p, @o, @i);#!#int|-|q|-|100 #!#float|-|z|-| #!#smallint|-|p|-| #!#real|-|o|-| #!#int|-|i|-| +prepst#!#exec#!#int|-|q|-|200 #!#float|-|z|-| #!#smallint|-|p|-| #!#real|-|o|-| #!#int|-|i|-| +prepst#!#exec#!#int|-|q|-|300 #!#float|-|z|-| #!#smallint|-|p|-| #!#real|-|o|-| #!#int|-|i|-| +prepst#!#exec#!#int|-|q|-|400 #!#float|-|z|-| #!#smallint|-|p|-| #!#real|-|o|-| #!#int|-|i|-| + +Select * from prep_exec_t1; + + +# Not working for babel raised bug relatede to no metadata=true + +#prepst#!#SELECT * FROM prep_exec_t1 WHERE a=@y#!#int|-|y|-|100 +#repst#!#exec#!#int|-|y|-|100 +#prepst#!#exec#!#int|-|y|-|200 +#prepst#!#exec#!#int|-|y|-|300 +#repst#!#exec#!#int|-|y|-|400 + + +# TEST ERROR(COMMENTED SINCE IT IS EXPECTED TO FAIL) + +#prepst#!#INSERT1 INTO prep_exec_t1 VALUES(@a1, @b1, @c1, @d1, @e1)#!#int|-|a1|-|100 #!#float|-|b1|-|10.1 #!#smallint|-|c1|-|10 #!#real|-|d1|-|10.1 #!#int|-|e1|-| +#prepst#!#exec#!#int|-|a1|-|200 #!#float|-|b1|-|20.2 #!#smallint|-|c1|-|20 #!#real|-|d1|-|20.2 #!#int|-|e1|-| +#prepst#!#exec#!#int|-|a1|-|300 #!#float|-|b1|-|30.3 #!#smallint|-|c1|-|30 #!#real|-|d1|-|30.3 #!#int|-|e1|-| +#prepst#!#exec#!#int|-|a1|-|400 #!#float|-|b1|-|40.3 #!#smallint|-|c1|-|40 #!#real|-|d1|-|40.4 #!#int|-|e1|-| + +DROP TABLE prep_exec_t1; + +# Random checsks (NOT WORKING ADDED A COMMENT TO A JIRA RELATED TO GRAMMAR) +#prepst#!#select @p as p#!#int|-|p|-|1 +#prepst#!#exec#!#varchar|-|p|-|hello +#repst#!#exec#!#bit|-|p|-|1 +#prepst#!#exec#!#tinyint|-|p|-|2 +#prepst#!#exec#!#int|-|p|-|0 +#prepst#!#exec#!#varchar|-|p|-|0 +#prepst#!#exec#!#varchar|-|p|-| +#prepst#!#exec#!#int|-|p|-| \ No newline at end of file diff --git a/contrib/test/dotnet/input/SQLBatch/TestSQLQueries.txt b/contrib/test/dotnet/input/SQLBatch/TestSQLQueries.txt new file mode 100644 index 00000000000..89e67a074d6 --- /dev/null +++ b/contrib/test/dotnet/input/SQLBatch/TestSQLQueries.txt @@ -0,0 +1,222 @@ +#1 CREATE TABLE with primary and unique keyword +CREATE TABLE tmp(a int PRIMARY KEY, b int UNIQUE); +INSERT INTO tmp(a,b) values(1,1); +INSERT INTO tmp(a,b) values(2,2); +SELECT * FROM tmp; +DROP TABLE tmp; + +#2 2 table with foreign key relation +#CREATE TABLE tmp1(b int PRIMARY KEY); +#CREATE TABLE tmp2(a int PRIMARY KEY, b int FOREIGN KEY REFERENCES tmp1(b)); +#INSERT INTO tmp1(b) VALUES (1); +#INSERT INTO tmp2(a,b) values(1,1); +#SELECT * FROM tmp1; +#SELECT * FROM tmp2; +#DROP TABLE tmp2; +#DROP TABLE tmp1; + +#3 Repeated #2 with CONSTRAINT keyword +#CREATE TABLE tmp1(b int PRIMARY KEY); +#CREATE TABLE tmp2(a int, b int, PRIMARY KEY(a), CONSTRAINT FK_tmp FOREIGN KEY (b) REFERENCES tmp1(b)); +#INSERT INTO tmp1(b) VALUES (1); +#INSERT INTO tmp2(a,b) values(1,1); +#SELECT * FROM tmp1; +#SELECT * FROM tmp2; +#DROP TABLE tmp2; +#DROP TABLE tmp1; + +#4 CREATE TABLE with NOT NULL column +CREATE TABLE tmp(a int PRIMARY KEY,b int NOT NULL); +INSERT INTO tmp(a,b) values(1,1); +INSERT INTO tmp(a,b) values(2,1); +#INSERT INTO tmp(a,b) values(2,NULL); +SELECT * FROM tmp; +DROP TABLE tmp; + +#5 INSERTION and DELETION +CREATE TABLE tmp(a int PRIMARY KEY); +INSERT INTO tmp(a) VALUES(1); +INSERT INTO tmp(a) VALUES(2); +INSERT INTO tmp(a) VALUES(3); +INSERT INTO tmp(a) VALUES(4); +INSERT INTO tmp(a) VALUES(5); +SELECT * FROM tmp; +DELETE FROM tmp WHERE a>2; +SELECT * FROM tmp; +DROP TABLE tmp; + +#6 IS NOT NULL condition in WHERE clause +CREATE TABLE tmp(a int PRIMARY KEY,b int); +INSERT INTO tmp(a,b) values(1,1); +INSERT INTO tmp(a,b) values(2,1); +INSERT INTO tmp(a,b) values(3,NULL); +INSERT INTO tmp(a,b) values(4,NULL); +SELECT * FROM tmp WHERE b IS NOT NULL; +DROP TABLE tmp; + +#7 Add new column using ALTER TABLE +CREATE TABLE tmp(a int PRIMARY KEY); +INSERT INTO tmp(a) VALUES(1); +INSERT INTO tmp(a) VALUES(2); +SELECT * FROM tmp; +#ALTER TABLE tmp ADD b VARCHAR(20) NULL; +SELECT * FROM tmp; +#INSERT INTO tmp(a,b) VALUES(4,'Dipesh'); +#INSERT INTO tmp(a,b) VALUES(5,' Dipesh'); +SELECT * FROM tmp; +DROP TABLE tmp; + +#8 Repeated #8 with default value for newly added col +CREATE TABLE tmp(a int PRIMARY KEY); +INSERT INTO tmp(a) VALUES(1); +INSERT INTO tmp(a) VALUES(2); +SELECT * FROM tmp; +#ALTER TABLE tmp ADD b VARCHAR(20) DEFAULT 'Dipesj'; +SELECT * FROM tmp; +#INSERT INTO tmp(a,b) VALUES(4,'Dipesh'); +#INSERT INTO tmp(a,b) VALUES(5,' Dipesh'); +SELECT * FROM tmp; +DROP TABLE tmp; + +#9 Change datatype of existing column using ALTER TABLE +CREATE TABLE tmp(a int PRIMARY KEY,b int); +INSERT INTO tmp(a,b) VALUES(1,1); +INSERT INTO tmp(a,b) VALUES(2,2); +SELECT * FROM tmp; +#ALTER TABLE tmp ALTER COLUMN b VARCHAR(10); +SELECT * FROM tmp; +#INSERT INTO tmp(a,b) VALUES(4,'Dipesh'); +#INSERT INTO tmp(a,b) VALUES(5,' Dipesh'); +SELECT * FROM tmp; +DROP TABLE tmp; + +#10 UPDATE TABLE with fancy condition +CREATE TABLE tmp(a int PRIMARY KEY,b int); +INSERT INTO tmp(a,b) VALUES(1,1); +INSERT INTO tmp(a,b) VALUES(2,2); +INSERT INTO tmp(a,b) VALUES(3,3); +INSERT INTO tmp(a,b) VALUES(4,4); +INSERT INTO tmp(a,b) VALUES(5,5); +SELECT * FROM tmp; +UPDATE tmp SET b=b+1 WHERE b>2; +SELECT * FROM tmp; +DROP TABLE tmp; + +#11 DROP some column using ALTER TABLE +CREATE TABLE tmp(a int PRIMARY KEY,b int); +INSERT INTO tmp(a,b) VALUES(1,1); +INSERT INTO tmp(a,b) VALUES(2,2); +INSERT INTO tmp(a,b) VALUES(3,3); +INSERT INTO tmp(a,b) VALUES(4,4); +INSERT INTO tmp(a,b) VALUES(5,5); +SELECT * FROM tmp; +#ALTER TABLE tmp DROP COLUMN b; +INSERT INTO tmp(a) values (6); +SELECT * FROM tmp; +DROP TABLE tmp; + +#12 CREATE TABLE with fancy constraint +CREATE TABLE tmp(a int PRIMARY KEY CHECK (a>10),b int); +INSERT INTO tmp(a,b) VALUES(11,1); +INSERT INTO tmp(a,b) VALUES(12,2); +INSERT INTO tmp(a,b) VALUES(13,3); +INSERT INTO tmp(a,b) VALUES(14,4); +INSERT INTO tmp(a,b) VALUES(15,5); +SELECT * FROM tmp; +DROP TABLE tmp; + +CREATE PROCEDURE tmp AS BEGIN CREATE TABLE dip(a int PRIMARY KEY CHECK (a>10),b int); INSERT INTO dip(a,b) VALUES(11,1); INSERT INTO dip(a,b) VALUES(12,2); INSERT INTO dip(a,b) VALUES(13,3); INSERT INTO dip(a,b) VALUES(14,4); INSERT INTO dip(a,b) VALUES(15,5); SELECT * FROM dip; DROP TABLE dip; END; + +#13 invoke simple stored procedure using EXECUTE +#EXECUTE tmp; + +#14 invoke simple stored procedure using EXEC +#EXEC tmp; + +DROP PROCEDURE tmp; + +#15 UPDATE rows in existing table +CREATE TABLE tmp(a int PRIMARY KEY,b int); +INSERT INTO tmp(a,b) VALUES(1,1),(2,2),(3,3),(4,4),(5,5); +SELECT * FROM tmp; +UPDATE tmp SET b=b*2+1 WHERE (a>2); +SELECT * FROM tmp; +DROP TABLE tmp; + +#16 TRUNCATE table +CREATE TABLE tmp(a int PRIMARY KEY,b int); +INSERT INTO tmp(a,b) VALUES(1,1),(2,2),(3,3),(4,4),(5,5); +SELECT * FROM tmp; +TRUNCATE tmp; +SELECT * FROM tmp; +DROP TABLE tmp; + +CREATE TABLE temp1 (i INT,j INT,t TEXT); + +CREATE TABLE temp2 ( i INT,k INT); + +INSERT INTO temp1 VALUES (1, 4, 'one'); +INSERT INTO temp1 VALUES (2, 3, 'two'); +INSERT INTO temp1 VALUES (3, 2, 'three'); +INSERT INTO temp1 VALUES (4, 1, 'four'); +INSERT INTO temp1 VALUES (5, 0, 'five'); +INSERT INTO temp1 VALUES (6, 6, 'six'); +INSERT INTO temp1 VALUES (7, 7, 'seven'); +INSERT INTO temp1 VALUES (8, 8, 'eight'); +INSERT INTO temp1 VALUES (0, NULL, 'zero'); +INSERT INTO temp1 VALUES (NULL, NULL, NULL); +INSERT INTO temp1 VALUES (NULL, 0, 'zero'); + +INSERT INTO temp2 VALUES (1, -1); +INSERT INTO temp2 VALUES (2, 2); +INSERT INTO temp2 VALUES (3, -3); +INSERT INTO temp2 VALUES (2, 4); +INSERT INTO temp2 VALUES (5, -5); +INSERT INTO temp2 VALUES (5, -5); +INSERT INTO temp2 VALUES (0, NULL); +INSERT INTO temp2 VALUES (NULL, NULL); +INSERT INTO temp2 VALUES (NULL, 0); + +#17 CROSS JOIN +#SELECT * FROM temp1 CROSS JOIN temp2; + +#18 INNER JOIN +#SELECT temp1.i, temp1.j, temp1.t, temp2.k FROM temp1 INNER JOIN temp2 ON temp1.i=temp2.i; +#SELECT temp1.i, temp1.j, temp1.t, temp2.k FROM temp1 JOIN temp2 ON temp1.i=temp2.i; + +#19 LEFT JOIN +#SELECT * FROM temp1 LEFT OUTER JOIN temp2 ON temp1.i=temp2.k; + +#20 RIGHT JOIN +#SELECT * FROM temp1 RIGHT OUTER JOIN temp2 ON temp1.i=temp2.i; + +#21 FULL OUTER JOIN +#SELECT * FROM temp1,temp2; + +DROP TABLE temp1; +DROP TABLE temp2; + +#22 dropping all columns +CREATE TABLE tmp(a int PRIMARY KEY,b int); +INSERT INTO tmp(a,b) VALUES(1,1); +INSERT INTO tmp(a,b) VALUES(2,2); +INSERT INTO tmp(a,b) VALUES(3,3); +INSERT INTO tmp(a,b) VALUES(4,4); +INSERT INTO tmp(a,b) VALUES(5,5); +SELECT * FROM tmp; +#ALTER TABLE tmp DROP COLUMN b; +#ALTER TABLE tmp DROP COLUMN a; +SELECT * FROM tmp; +DROP TABLE tmp; + +#23 +CREATE TABLE DATE_dt (a DATE); +INSERT INTO DATE_dt(a) values('2000-12-13'); +INSERT INTO DATE_dt(a) values('1900-02-28'); +INSERT INTO DATE_dt(a) values('0001-01-01'); +INSERT INTO DATE_dt(a) values('9999-12-31'); +INSERT INTO DATE_dt(a) values(NULL); +SELECT * FROM DATE_dt; +#ALTER TABLE DATE_dt ALTER COLUMN a DATETIME; +SELECT * FROM DATE_dt; +DROP TABLE DATE_dt; \ No newline at end of file diff --git a/contrib/test/dotnet/input/ScalarFunctions/ScalarFunctionsSQLBatch.txt b/contrib/test/dotnet/input/ScalarFunctions/ScalarFunctionsSQLBatch.txt new file mode 100644 index 00000000000..aa5844c30ad --- /dev/null +++ b/contrib/test/dotnet/input/ScalarFunctions/ScalarFunctionsSQLBatch.txt @@ -0,0 +1,59 @@ +create schema tests + +CREATE FUNCTION tests.multiply (@a int, @b int) RETURNS int AS BEGIN RETURN @a * @b; END; +Select tests.multiply(1, 1) +Select tests.multiply(1, 0) +Select tests.multiply(1, -1) + +# Testing If it excepts float as args +# BABEL637 +Select tests.multiply(1.1, -1.1) +Select tests.multiply(1, -1.00000001) + +# Testing overflow case +Select tests.multiply(1000000000, 1000000000) + +# nested call +select tests.multiply(-1, tests.multiply(-10,20)) +#passing different types +select tests.multiply(0xe, 0xe) +select tests.multiply('100', '100') + +# testing without params +CREATE FUNCTION tests.multiply1() RETURNS int AS BEGIN RETURN 100 * 1; END; +select tests.multiply1() +select tests.multiply(1, tests.multiply1()); +select tests.multiply(tests.multiply(-1,1), tests.multiply1()) + +# Nesting of functions +CREATE FUNCTION tests.func3() Returns int AS BEGIN RETURN tests.multiply(1,tests.multiply1()); END; +select tests.func3() + +# datatype diff in return +CREATE FUNCTION tests.func4() Returns int AS BEGIN return 1.1 END; +Select tests.func4() + +# some random tests +CREATE FUNCTION tests.func5() Returns varchar As begin RETURN('abc''abc'); END; +select tests.func5() + +CREATE FUNCTION tests.func7(@a int) Returns varchar(100) As begin SET @a = 100 RETURN(@a); END; +select tests.func7(1) + + +# Calls from prepare statements +prepst#!#select tests.multiply(@a,@b)#!#int|-|a|-|10#!#int|-|b|-|-20 +prepst#!#select tests.multiply1()#!# +prepst#!#select tests.func3()#!# +prepst#!#select tests.func4()#!# +prepst#!#select tests.func5()#!# +prepst#!#select tests.func7()#!#int|-|a|-|10 + +DROP FUNCTION tests.mutliply +DROP FUNCTION tests.multiply1 +DROP FUNCTION tests.func3 +DROP FUNCTION tests.func4 +DROP FUNCTION tests.func5 +DROP FUNCTION tests.func7 + +drop schema tests \ No newline at end of file diff --git a/contrib/test/dotnet/input/Storedproc/TestStoredProcedure.txt b/contrib/test/dotnet/input/Storedproc/TestStoredProcedure.txt new file mode 100644 index 00000000000..c6b44d826d6 --- /dev/null +++ b/contrib/test/dotnet/input/Storedproc/TestStoredProcedure.txt @@ -0,0 +1,213 @@ +# PROCEDURE WITH NO BODY, works with babel but not with sql +#create procedure sp_test AS BEGIN END; + +# PROCEDURE WITH NO PARAMS +create table temp_sp2(a int); +CREATE PROCEDURE sp_test AS BEGIN insert into temp_sp2 values(1); END; +storedproc#!#prep#!#sp_test#!# +SELECT * FROM temp_sp2; +drop table temp_sp2; +drop Procedure sp_test; + + +# PROCEDURE WITH INPUT PARAMETER +#drop table temp_sp; +create table temp_sp(a int); + + +Create Procedure stored_proc1 (@a int) As Begin insert into temp_sp values(@a) End; +# NOT WORKING FOR BABEL,RAISED JIRA 444 +storedproc#!#prep#!#stored_proc1#!#int|-|a|-|-100|-|input + +# MISMATCH IN RETURN VALUES +exec stored_proc1 -200 +exec stored_proc1 0 +exec stored_proc1 -1 +exec stored_proc1 2 + +# filed Jira on this, doesnt work for babel +#exec stored_proc1 2.2 + + +SELECT * FROM temp_sp; +DROP table temp_sp; +DROP Procedure stored_proc1 + +# input parameter +CREATE PROCEDURE sp_test1 (@a INT) AS BEGIN SET @a=100; Select @a as a; END; +exec sp_test1 2 +Declare @a int;Set @a=1; exec sp_test1 @a;select @a as a; +storedproc#!#prep#!#sp_test1#!#int|-|a|-|1|-|input +storedproc#!#prep#!#sp_test1#!#int|-|a|-|10|-|input +DROP PROCEDURE sp_test1 + +# TESTING OUT PARAMETERS FOR ALL THE DATATYPES + +# int +CREATE PROCEDURE sp_test1 (@a INT OUTPUT) AS BEGIN SET @a=100; Select @a as a; END; +exec sp_test1 2 +Declare @a int;Set @a=1; exec sp_test1 @a;select @a as a; +storedproc#!#prep#!#sp_test1#!#int|-|a|-|1|-|output +storedproc#!#prep#!#sp_test1#!#int|-|a|-|1|-|inputoutput +DROP PROCEDURE sp_test1 + +# smallint +CREATE PROCEDURE sp_test2 (@a SMALLINT OUTPUT) AS BEGIN SET @a=100; Select @a as a; END; +exec sp_test2 2 +Declare @a smallint;Set @a=1; exec sp_test2 @a;select @a as a; +storedproc#!#prep#!#sp_test2#!#smallint|-|a|-|10|-|output +storedproc#!#prep#!#sp_test2#!#smallint|-|a|-|10|-|inputoutput +DROP PROCEDURE sp_test2 + +# bigint +CREATE PROCEDURE sp_test3 (@a BIGINT OUTPUT) AS BEGIN SET @a=100; Select @a as a; END; +exec sp_test3 2 +Declare @a bigint;Set @a=1; exec sp_test3 @a;select @a as a; +storedproc#!#prep#!#sp_test3#!#bigint|-|a|-|10|-|output +storedproc#!#prep#!#sp_test3#!#bigint|-|a|-|10|-|inputoutput +DROP PROCEDURE sp_test3 + +# tinyint +CREATE PROCEDURE sp_test4 (@a tinyint OUTPUT) AS BEGIN SET @a=100; Select @a as a; END; +exec sp_test4 4 +Declare @a bigint;Set @a=1; exec sp_test4 @a;select @a as a; +storedproc#!#prep#!#sp_test4#!#tinyint|-|a|-|10|-|output +storedproc#!#prep#!#sp_test4#!#tinyint|-|a|-|10|-|inputoutput +DROP PROCEDURE sp_test4 + +# float +CREATE PROCEDURE sp_test5 (@a float OUTPUT) AS BEGIN SET @a=100.12; Select @a as a; END; +exec sp_test5 2.1 +Declare @a float;Set @a=1.1; exec sp_test5 @a;select @a as a; +storedproc#!#prep#!#sp_test5#!#float|-|a|-|10.1|-|output +storedproc#!#prep#!#sp_test5#!#float|-|a|-|10.1|-|inputoutput +DROP PROCEDURE sp_test5 + +# varchar +CREATE PROCEDURE sp_test6 (@a varchar OUTPUT) AS BEGIN SET @a='helloworld'; Select @a as a; END; +exec sp_test6 'hello' +Declare @a varchar;Set @a='hello'; exec sp_test6 @a;select @a as a; +storedproc#!#prep#!#sp_test6#!#varchar|-|a|-|hello|-|output +storedproc#!#prep#!#sp_test6#!#varchar|-|a|-|hello|-|inputoutput +DROP PROCEDURE sp_test6 + +# char BABEL-705 +#CREATE PROCEDURE sp_test7 (@a char OUTPUT) AS BEGIN SET @a='b'; Select @a as a; END; +#exec sp_test7 'a' +#Declare @a varchar;Set @a='h'; exec sp_test7 @a;select @a as a; +#storedproc#!#prep#!#sp_test7#!#char|-|a|-|t|-|output +#storedproc#!#prep#!#sp_test7#!#char|-|a|-|t|-|inputoutput +#DROP PROCEDURE sp_test7 + +# nchar BABEL-708 +#CREATE PROCEDURE sp_test8 (@a nchar OUTPUT) AS BEGIN SET @a='helloworld'; Select @a as a; END; +#exec sp_test8 'a' +#Declare @a nchar;Set @a='hello'; exec sp_test8 @a;select @a as a; +#storedproc#!#prep#!#sp_test8#!#nchar|-|a|-|t|-|output +#storedproc#!#prep#!#sp_test8#!#nchar|-|a|-|t|-|inputoutput +#DROP PROCEDURE sp_test8 + +# nvarchar +CREATE PROCEDURE sp_test9 (@a nvarchar OUTPUT) AS BEGIN SET @a='helloworld'; Select @a as a; END; +exec sp_test9 'hello' +Declare @a nvarchar;Set @a='hello'; exec sp_test9 @a;select @a as a; +storedproc#!#prep#!#sp_test9#!#varchar|-|a|-|hello|-|output +storedproc#!#prep#!#sp_test9#!#varchar|-|a|-|hello|-|inputoutput +DROP PROCEDURE sp_test9 + +# numeric +#CREATE PROCEDURE sp_test10 (@a numeric(10,4) OUTPUT) AS BEGIN SET @a=100.41; Select @a as a; END; +#exec sp_test10 2.000 +#Declare @a numeric(10,4);Set @a=10.04; exec sp_test10 @a;select @a as a; +#storedproc#!#prep#!#sp_test10#!#numeric|-|a|-|123|-|10|-|3|-|output +#storedproc#!#prep#!#sp_test10#!#numeric|-|a|-|123|-|10|-|2|-|inputoutput +#DROP PROCEDURE sp_test10 + +# decimal +CREATE PROCEDURE sp_test11 (@a decimal(10,4) OUTPUT) AS BEGIN SET @a=100.41; Select @a as a; END; +exec sp_test11 2.00 +Declare @a decimal(10,4);Set @a=10.04; exec sp_test11 @a;select @a as a; +storedproc#!#prep#!#sp_test11#!#decimal|-|a|-|123|-|10|-|3|-|output +storedproc#!#prep#!#sp_test11#!#decimal|-|a|-|123|-|10|-|2|-|inputoutput +DROP PROCEDURE sp_test11 + +# binary +#CREATE PROCEDURE sp_test12 (@a binary OUTPUT) AS BEGIN SET @a=0x121; Select @a as a; END; +#exec sp_test12 0x122 +#Declare @a binary;Set @a=0x121; exec sp_test12 @a;select @a as a; +#storedproc#!#prep#!#sp_test12#!#binary|-|a|-|0x122|-|output +#storedproc#!#prep#!#sp_test12#!#binary|-|a|-|0x122|-|inputoutput +#DROP PROCEDURE sp_test12 + +# varbinary BABEL-701 +#CREATE PROCEDURE sp_test13 (@a varbinary OUTPUT) AS BEGIN SET @a=0x121; Select @a as a; END; +#exec sp_test13 0x122 +#Declare @a varbinary;Set @a=0x122; exec sp_test13 @a;select @a as a; +#storedproc#!#prep#!#sp_test13#!#varbinary|-|a|-|0x122|-|output +#storedproc#!#prep#!#sp_test13#!#varbinary|-|a|-|0x122|-|inputoutput +#DROP PROCEDURE sp_test13 + +# date +CREATE PROCEDURE sp_test14 (@a date output) AS BEGIN SET @a='1999-1-3'; Select @a as a; END; +exec sp_test14 '9999-12-31' +Declare @a DATE;Set @a='9999-12-31'; exec sp_test14 @a;select @a as a; +storedproc#!#prep#!#sp_test14#!#DATE|-|a|-|9999-12-31|-|output +storedproc#!#prep#!#sp_test14#!#DATE|-|a|-|9999-12-31|-|inputoutput +DROP PROCEDURE sp_test14 + +# time +CREATE PROCEDURE sp_test15 (@a time(4) OUTPUT) AS BEGIN SET @a='11:25:07.123'; Select @a as a; END; +exec sp_test15 '12:45:37.123' +Declare @a Time;Set @a='12:45:37.123'; exec sp_test15 @a;select @a as a; +storedproc#!#prep#!#sp_test15#!#Time|-|a|-|12:45:37.123|-|3|-|output +storedproc#!#prep#!#sp_test15#!#Time|-|a|-|12:45:37.123|-|3|-|inputoutput +DROP PROCEDURE sp_test15 + +# dateime +CREATE PROCEDURE sp_test16 (@a datetime output) AS BEGIN SET @a='2004-05-18 13:59:59.995'; Select @a as a; END; +exec sp_test16 '2000-02-28 23:59:59.995' +Declare @a DATETIME;Set @a='2000-02-28 23:59:59.995'; exec sp_test16 @a;select @a as a; +storedproc#!#prep#!#sp_test16#!#DATETIME|-|a|-|2000-02-28 23:59:59.995|-|output +storedproc#!#prep#!#sp_test16#!#DATETIME|-|a|-|2000-02-28 23:59:59.995|-|inputoutput +DROP PROCEDURE sp_test16 + +# datetime2 # Mismatch BABEL-708 +CREATE PROCEDURE sp_test17 (@a datetime2(5) OUTPUT) AS BEGIN SET @a='2014-10-2 1:45:37.123456'; Select @a as a; END; +exec sp_test17 '2016-10-23 12:45:37.123456' +Declare @a Datetime2;Set @a='2016-10-23 12:45:37.123456'; exec sp_test17 @a;select @a as a; +storedproc#!#prep#!#sp_test17#!#Datetime2|-|a|-|2016-10-23 12:45:37.123456|-|5|-|output +storedproc#!#prep#!#sp_test17#!#Datetime2|-|a|-|2016-10-23 12:45:37.123456|-|5|-|inputoutput +DROP PROCEDURE sp_test17 + +# smalldatetime +CREATE PROCEDURE sp_test18 (@a smalldatetime output) AS BEGIN SET @a='2010-02-03 12:58:23'; Select @a as a; END; +exec sp_test18 '2005-02-19 02:58:23' +Declare @a SMALLDATETIME;Set @a='2000-12-13 12:58:23'; exec sp_test18 @a;select @a as a; +storedproc#!#prep#!#sp_test18#!#SMALLDATETIME|-|a|-|2000-12-13 12:58:23|-|output +storedproc#!#prep#!#sp_test18#!#SMALLDATETIME|-|a|-|2000-12-13 12:58:23|-|inputoutput +DROP PROCEDURE sp_test18 + +# UID +#CREATE PROCEDURE sp_test19 (@a uniqueidentifier OUTPUT) AS BEGIN SET @a='ce8af10a-2709-43b0-9e4e-a02753929d17'; Select @a as a; END; +#exec sp_test19 '5b7c2e8d-6d90-411d-8e19-9a81067e6f6c' +#Declare @a uniqueidentifier;Set @a='5b7c2e8d-6d90-411d-8e19-9a81067e6f6c'; exec sp_test19 @a;select @a as a; +#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 + +# ALTER STATEMENT FOR babel fails +#Alter procedure sp_test (@a int OUTPUT) AS Begin Set @a=100; Select @a as a; END; + +DROP PROCEDURE sp_test20 +CREATE PROCEDURE sp_test20 ( @one int, @two int ) AS BEGIN SELECT @one, @two; END; +DECLARE @one int = 100; DECLARE @two int = 200; EXECUTE sp_test20 @one = @one, @two = @two; +DECLARE @one int = 100; DECLARE @two int = 200; EXECUTE sp_test20 @one = @two, @two = @one; +storedproc#!#prep#!#sp_test20#!#int|-|one|-|100|-|input#!#int|-|two|-|200|-|input +DROP PROCEDURE sp_test20 + +DROP PROCEDURE sp_test21 +CREATE PROCEDURE sp_test21 ( @one varchar(30), @two int ) AS BEGIN SELECT @one, @two; END; +EXECUTE sp_test21 @one = "hello", @two = 1; +#EXECUTE sp_test21 @two = 1, @one = "hello"; ##### Babel 2392 +storedproc#!#prep#!#sp_test21#!#varchar|-|one|-|hello|-|input#!#int|-|two|-|200|-|input +DROP PROCEDURE sp_test21 \ No newline at end of file diff --git a/contrib/test/dotnet/input/Transaction/TestTransactions.txt b/contrib/test/dotnet/input/Transaction/TestTransactions.txt new file mode 100644 index 00000000000..e7ada9a804f --- /dev/null +++ b/contrib/test/dotnet/input/Transaction/TestTransactions.txt @@ -0,0 +1,189 @@ +create table txntable1(c1 int); + +# Begin transaction -> commit transaction +txn#!#begin +select @@trancount; +#txn#!#begin#!#isolation#!#rc +#select @@trancount; +insert into txntable1 values(1); +txn#!#commit +select @@trancount; +#txn#!#commit +#select @@trancount; +select c1 from txntable1; + +# Begin transaction -> rollback transaction +txn#!#begin +insert into txntable1 values(2); +txn#!#rollback +select c1 from txntable1; + +#Begin tran -> commit tran +txn#!#begin +insert into txntable1 values(2); +txn#!#commit +select c1 from txntable1; + +# Begin tran -> rollback tran +txn#!#begin +select @@trancount; +#txn#!#begin#!#isolation#!#ru +#show transaction_isolation; +#show default_transaction_isolation; +insert into txntable1 values(3); +select @@trancount; +txn#!#rollback +select @@trancount; +select c1 from txntable1; + +# Begin transaction -> commit +txn#!#begin +insert into txntable1 values(4); +txn#!#commit; +select c1 from txntable1; + +# Begin transaction -> commit work +txn#!#begin +insert into txntable1 values(5); +txn#!#commit +select c1 from txntable1; + +# Begin transaction -> rollback +txn#!#begin +insert into txntable1 values(6); +txn#!#rollback +select c1 from txntable1; + +# Begin transaction -> rollback work +txn#!#begin +insert into txntable1 values(7); +txn#!#rollback +select c1 from txntable1; + +# Begin transaction name -> commit transaction name +txn#!#begin#!#tx1 +insert into txntable1 values(8); +txn#!#commit#!#tx1 +select c1 from txntable1; + +# Begin transaction name -> rollback transaction name +txn#!#begin#!#tx1 +insert into txntable1 values(9); +txn#!#rollback#!#tx1 +select c1 from txntable1; + +# Begin tran name -> commit tran name +txn#!#begin#!#tx1 +insert into txntable1 values(10); +txn#!#commit#!#tx1 +select c1 from txntable1; + +# Begin tran name -> rollback tran name +txn#!#begin#!#tx1 +insert into txntable1 values(10); +txn#!#rollback#!#tx1 +select c1 from txntable1; + +truncate table txntable1; + +# save tran name -> rollback tran name +txn#!#begin#!#tx1#!#isolation#!#ss +insert into txntable1 values(1); +txn#!#savepoint#!#sp1 +select @@trancount; +insert into txntable1 values(2); +txn#!#savepoint#!#sp2 +insert into txntable1 values(3); +txn#!#savepoint#!#sp2 +select @@trancount; +insert into txntable1 values(4); +select c1 from txntable1; +txn#!#rollback#!#sp2 +select @@trancount; +select c1 from txntable1; +txn#!#rollback#!#sp2 +select @@trancount; +select c1 from txntable1; +txn#!#rollback#!#sp1 +select @@trancount; +select c1 from txntable1; +txn#!#rollback#!#tx1 +select @@trancount; +select c1 from txntable1; + +# begin transaction name -> save transaction name -> rollback to first savepoint +txn#!#begin#!#tx1 +insert into txntable1 values(1); +txn#!#savepoint#!#sp1 +insert into txntable1 values(2); +txn#!#savepoint#!#sp2 +insert into txntable1 values(3); +txn#!#savepoint#!#sp3 +insert into txntable1 values(4); +txn#!#rollback#!#sp1 +#txn#!#rollback#!#sp1 +txn#!#rollback +select c1 from txntable1; + +# begin transaction name -> save transaction name -> rollback tran name, Rollback whole transaction +txn#!#begin#!#isolation#!#ss#!#tx1 +insert into txntable1 values(1); +txn#!#savepoint#!#sp1 +#txn#!#begin#!#tx1 +insert into txntable1 values(2); +txn#!#savepoint#!#sp1 +insert into txntable1 values(3); +select @@trancount; +txn#!#rollback#!#tx1 +select @@trancount; +select c1 from txntable1; + +# begin transaction -> save transaction name -> rollback to savepoint, commit transaction +txn#!#begin#!#tx1 +insert into txntable1 values(1); +txn#!#savepoint#!#sp1 +insert into txntable1 values(2); +select c1 from txntable1; +txn#!#rollback#!#sp1 +txn#!#rollback#!#tx1 +select c1 from txntable1; + +# begin transaction -> save transaction name -> rollback to savepoint +# save transaction name -> commit transaction +txn#!#begin#!#tx1 +insert into txntable1 values(3); +txn#!#savepoint#!#sp1 +insert into txntable1 values(4); +select c1 from txntable1; +txn#!#rollback#!#sp1 +txn#!#savepoint#!#sp2 +insert into txntable1 values(5); +txn#!#commit ### not working +select c1 from txntable1; + +# begin transaction -> save transaction name -> error -> rollback to savepoint +# commit transaction +txn#!#begin#!#tx1 +insert into txntable1 values(6); +txn#!#savepoint#!#sp1 +insert into txntable1 values(7); +select c1 frm txntable1; +txn#!#rollback#!#sp1 +txn#!#commit +select c1 from txntable1; + +# negative test cases for begin transaction +txn#!#begin#!#1txn +select @@trancount; +txn#!#commit + +txn#!#begin#!#txn1;txn2 +select @@trancount; +txn#!#commit + +txn#!#begin#!#txn1() +select @@trancount; +txn#!#commit + +DROP TABLE txntable1; + diff --git a/contrib/test/dotnet/input/Transaction/TestTransactionsSQLBatch.txt b/contrib/test/dotnet/input/Transaction/TestTransactionsSQLBatch.txt new file mode 100644 index 00000000000..c767fbbaead --- /dev/null +++ b/contrib/test/dotnet/input/Transaction/TestTransactionsSQLBatch.txt @@ -0,0 +1,189 @@ +create table TxnTable(c1 int); + +# Begin transaction -> commit transaction +begin transaction; +select @@trancount; +begin transaction; +select @@trancount; +set transaction isolation level read committed; +#show transaction_isolation; +#show default_transaction_isolation; +insert into TxnTable values(1); +commit transaction; +select @@trancount; +commit transaction; +select @@trancount; +select c1 from TxnTable; + +# Begin transaction -> rollback transaction +begin transaction; +insert into TxnTable values(2); +rollback transaction; +select c1 from TxnTable; + +#Begin tran -> commit tran +begin tran; +insert into TxnTable values(2); +commit tran; +select c1 from TxnTable; + +# Begin tran -> rollback tran +begin tran; +select @@trancount; +begin tran; +set transaction isolation level read uncommitted; +#show transaction_isolation; +#show default_transaction_isolation; +insert into TxnTable values(3); +select @@trancount; +rollback tran; +select @@trancount; +select c1 from TxnTable; + +set transaction isolation level repeatable read; +#show transaction_isolation; +#show default_transaction_isolation; + +# Begin transaction -> commit +begin transaction; +insert into TxnTable values(4); +commit; +select c1 from TxnTable; + +# Begin transaction -> commit work +begin transaction; +insert into TxnTable values(5); +commit work; +select c1 from TxnTable; + +# Begin transaction -> rollback +begin transaction; +insert into TxnTable values(6); +rollback; +select c1 from TxnTable; + +# Begin transaction -> rollback work +begin transaction; +insert into TxnTable values(7); +rollback work; +select c1 from TxnTable; + +# Begin transaction name -> commit transaction name +begin transaction txn1; +insert into TxnTable values(8); +commit transaction txn1; +select c1 from TxnTable; + +# Begin transaction name -> rollback transaction name +begin transaction txn1; +insert into TxnTable values(9); +rollback transaction txn1; +select c1 from TxnTable; + +# Begin tran name -> commit tran name +begin tran txn1; +insert into TxnTable values(10); +commit tran txn1; +select c1 from TxnTable; + +# Begin tran name -> rollback tran name +begin tran txn1; +insert into TxnTable values(10); +rollback tran txn1; +select c1 from TxnTable; + +truncate table TxnTable; + +# save tran name -> rollback tran name +set transaction isolation level snapshot; +#show transaction_isolation; +#show default_transaction_isolation; +begin transaction txn1; +insert into TxnTable values(1); +save transaction sp1; +select @@trancount; +insert into TxnTable values(2); +save tran sp2; +insert into TxnTable values(3); +save tran sp2; +select @@trancount; +insert into TxnTable values(4); +select c1 from TxnTable; +rollback tran sp2; +select @@trancount; +select c1 from TxnTable; +rollback tran sp2; +select @@trancount; +select c1 from TxnTable; +rollback tran sp1; +select @@trancount; +select c1 from TxnTable; +rollback tran txn1; +select @@trancount; +select c1 from TxnTable; + +# begin transaction name -> save transaction name -> rollback to first savepoint +begin transaction txn1; +insert into TxnTable values(1); +save transaction sp1; +insert into TxnTable values(2); +save transaction sp2; +insert into TxnTable values(3); +save transaction sp3; +insert into TxnTable values(4); +rollback tran sp1; +#rollback tran sp1; -- this will give an error +rollback tran; +select c1 from TxnTable; + +# begin transaction name -> save transaction name -> rollback tran name, Rollback whole transaction +set transaction isolation level serializable; +#show transaction_isolation; +#show default_transaction_isolation; +begin transaction txn1; +insert into TxnTable values(1); +save transaction sp1; +begin transaction txn1; +insert into TxnTable values(2); +save transaction sp1; +insert into TxnTable values(3); +select @@trancount; +rollback tran txn1; +select @@trancount; +select c1 from TxnTable; + +# 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; +rollback tran sp1; +commit transaction; +select c1 from TxnTable; + +# 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; +rollback tran sp1; +save transaction sp2; +insert into TxnTable values(5); +commit transaction; +select c1 from TxnTable; + +# 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 +rollback tran sp1; +commit transaction; +select c1 from TxnTable; + +Drop table TxnTable; \ No newline at end of file diff --git a/contrib/test/dotnet/src/BatchRun.cs b/contrib/test/dotnet/src/BatchRun.cs new file mode 100644 index 00000000000..101b0c7a856 --- /dev/null +++ b/contrib/test/dotnet/src/BatchRun.cs @@ -0,0 +1,383 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Data.Common; +using System.Data.SqlClient; +using System.IO; +using Serilog; + +namespace BabelfishDotnetFramework +{ + public class BatchRun + { + public static Dictionary testResults = new Dictionary(); + + /* + * BatchRunner - Backbone of all the tests. From reading the files to executing and + * comparing results, everything is handled here. + */ + bool BatchRunner(DbConnection bblCnn, string queryFilePath, Serilog.Core.Logger logger) + { + TestUtils testUtils = new TestUtils(); + testUtils.PrintToLogsOrConsole("Query file: " + queryFilePath,logger,"info"); + testUtils.PrintToLogsOrConsole("###########################################################################", logger, "information"); + testUtils.PrintToLogsOrConsole("############################ BATCH RUN STARTED ############################", logger, "information"); + testUtils.PrintToLogsOrConsole("###########################################################################\n", logger, "information"); + + DbCommand bblCmd = testUtils.CreateDbCommand(null, bblCnn); + DbTransaction bblTransaction = null; + + bool testFlag = true; + + bool isSql = queryFilePath.Substring( queryFilePath.Length - 3).Equals("sql"); + string[] temp = queryFilePath.Split('/'); + string testName = temp[^1].Substring(0, temp[^1].Length - 4); /* Extract the File Name from the File Path */ + + int testCaseCount = 0; /* Holds the total number of test cases in the file. */ + int stCount = 0; /* Holds the number of tests passed. */ + + try + { + string[] lines = null; + + lines = testUtils.ReadFile(queryFilePath); + if (lines == null) + return false; + + stCount = lines.Length; + testCaseCount = lines.Length; + + for (int i = 0; i < lines.Length; i++) + { + string strLine = lines[i]; + + /* + * If file is an sql script then read all the lines until the next "go". + */ + if(isSql) + { + strLine = ""; + while (i < lines.Length && !lines[i].Equals("go", StringComparison.InvariantCultureIgnoreCase) + && !lines[i].Equals("go;", StringComparison.InvariantCultureIgnoreCase)) + { + strLine += lines[i++] + "\r\n"; + stCount--; + testCaseCount--; + } + } + try + { + if (strLine.Length < 1 || strLine.StartsWith('#')) + { + stCount--; + testCaseCount--; + continue; + } + + string query = null; + + /* If the query is a prepare-exec statement. */ + if (strLine.StartsWith("prepst")) + { + string[] result = new string[10]; + result = strLine.Split("#!#", StringSplitOptions.RemoveEmptyEntries); + + /* Execute an already prepared statement. */ + if (result[1].ToLowerInvariant().StartsWith("exec")) + { + testUtils.PrintToLogsOrConsole("#################################################################", logger, "information"); + testUtils.PrintToLogsOrConsole("############################# EXEC ##############################", logger, "information"); + testUtils.PrintToLogsOrConsole("#################################################################\n", logger, "information"); + testUtils.PrintToLogsOrConsole(String.Format("WITH PARAMETER DEFINATION = " + strLine), logger, "information"); + if (bblTransaction != null) + { + bblCmd.Transaction = bblTransaction; + } + bblCmd = PrepareExecBinding.SetBindParams(result, bblCmd, true, logger); + testUtils.ResultSetWriter(bblCmd, testName, ref stCount); + } + /* To prepare and execute a statement. */ + else if (!result[1].ToLowerInvariant().StartsWith("exec")) + { + bblCmd?.Dispose(); + bblCmd = testUtils.CreateDbCommand(null, bblCnn); + testUtils.PrintToLogsOrConsole( + $"####################### EXECUTING PREPARE/EXEC FOR QUERY- {strLine} #######################", logger, "information"); + query = result[1]; + bblCmd.CommandText = query; + if (bblTransaction != null) + { + bblCmd.Transaction = bblTransaction; + } + bblCmd = PrepareExecBinding.SetBindParams(result, bblCmd, false, logger); + bblCmd.Prepare(); + testUtils.ResultSetWriter(bblCmd, testName, ref stCount); + } + } + /* If the query is a Transaction Manager Request. */ + else if (strLine.ToLowerInvariant().StartsWith("txn")) + { + string[] result = new string[10]; + result = strLine.Split("#!#", StringSplitOptions.RemoveEmptyEntries); + bblCmd?.Dispose(); + bblCmd = testUtils.CreateDbCommand(null, bblCnn); + testUtils.PrintToLogsOrConsole("#################################################################", logger, "information"); + testUtils.PrintToLogsOrConsole( + $"######################### TRANSACTION {result[1]} #######################", logger, "information"); + testUtils.PrintToLogsOrConsole("#################################################################", logger, "information"); + + if (result[1].ToLowerInvariant().StartsWith("begin")) + { + if (result.Length > 2) + { + if (result[2].ToLowerInvariant().StartsWith("isolation")) + { + string tranName = null; + if (result.Length > 4) + tranName = result[4]; + if (result[3] == "rc") /* For Isolation Read-Commited */ + { + bblTransaction = testUtils.GetDbBeginTransaction(bblCnn, + IsolationLevel.ReadCommitted, tranName); + testUtils.PrintToLogsOrConsole("################### ISOLATION READ COMMITED ###################\n", logger, "information"); + } + else if (result[3] == "rr") /* For Isolation Repeatable Read */ + { + bblTransaction = testUtils.GetDbBeginTransaction(bblCnn, + IsolationLevel.RepeatableRead, tranName); + testUtils.PrintToLogsOrConsole("################### ISOLATION REPEATABLE READ ###################\n", logger, "information"); + } + else if (result[3] == "ru") /* For Isolation Read-Uncommited */ + { + bblTransaction = testUtils.GetDbBeginTransaction(bblCnn, + IsolationLevel.ReadUncommitted, tranName); + testUtils.PrintToLogsOrConsole("################### ISOLATION READ UNCOMMITED ###################\n", logger, "information"); + } + else if (result[3] == "s") /* For Isolation Serializable */ + { + bblTransaction = testUtils.GetDbBeginTransaction(bblCnn, + IsolationLevel.Serializable, tranName); + testUtils.PrintToLogsOrConsole("################### ISOLATION SERIALIZABLE ###################\n", logger, "information"); + } + else if (result[3] == "ss") /* For Isolation Snapshot */ + { + bblTransaction = testUtils.GetDbBeginTransaction(bblCnn, + IsolationLevel.Snapshot, tranName); + testUtils.PrintToLogsOrConsole("################### SNAPSHOT ###################\n", logger, "information"); + } + + } + else + { + /* Begin with Transaction Name. */ + bblTransaction = testUtils.GetDbBeginTransaction(bblCnn, + result[2]); + testUtils.PrintToLogsOrConsole( + $"################### TRAN BEGIN WITH NAME- {result[2]} ###################", logger, "information"); + } + + } + else + { + /* Begin without Transaction Name. */ + bblTransaction = bblCnn.BeginTransaction(); + testUtils.PrintToLogsOrConsole("################### TRAN BEGIN ###################", logger, "information"); + } + + } + else if (result[1].ToLowerInvariant().StartsWith("commit")) + { + bblTransaction.Commit(); + } + else if (result[1].ToLowerInvariant().StartsWith("rollback")) + { + if (result.Length > 2) + { + /* Rollback with Name. */ + testUtils.RollbackTransaction(bblTransaction, result[2]); + } + else + { + /* Rollback without Name. */ + bblTransaction.Rollback(); + } + } + else if (result[1].ToLowerInvariant().StartsWith("save")) + { + testUtils.SaveTransaction(bblTransaction, result[2]); + } + } + /* If the query is a Bulk Load Request. */ + else if (strLine.ToLowerInvariant().StartsWith("insertbulk")) + { + var result = strLine.Split("#!#", StringSplitOptions.RemoveEmptyEntries); + testUtils.PrintToLogsOrConsole( + $"########################## INSERT BULK:- {strLine} ##########################", logger, "information"); + string sourceTable = result[1]; + string destinationTable = result[2]; + testFlag &= testUtils.insertBulkCopy(bblCnn, bblCmd, sourceTable, destinationTable, logger, ref stCount); + } + /* Case for sp_customtype RPC. */ + else if (strLine.ToLowerInvariant().StartsWith("storedp")) + { + var result = strLine.Substring(13).Split("#!#", StringSplitOptions.RemoveEmptyEntries); + testUtils.PrintToLogsOrConsole($"#################################################################", logger, "information"); + testUtils.PrintToLogsOrConsole( + $"################### STORED PROCEDURE:- {strLine} ################", logger, "information"); + testUtils.PrintToLogsOrConsole($"#################################################################", logger, "information"); + bblCmd?.Dispose(); + bblCmd = testUtils.CreateDbCommand(null, bblCnn); + if (bblTransaction != null) + { + bblCmd.Transaction = bblTransaction; + } + bblCmd.CommandType = CommandType.StoredProcedure; + bblCmd.CommandText = result[1]; + bblCmd = PrepareExecBinding.SetBindParams(result, bblCmd, false, logger); + + testUtils.ResultSetWriter(bblCmd, testName, ref stCount); + + testUtils.PrintToLogsOrConsole("#################################################################", logger, "information"); + testUtils.PrintToLogsOrConsole("####################### END OF PROCEDURE ########################", logger, "information"); + testUtils.PrintToLogsOrConsole("#################################################################\n", logger, "information"); + } + /* Case for Authentication Steps. */ + else if (strLine.ToLowerInvariant().StartsWith("dotnet_auth")) + { + testUtils.PrintToLogsOrConsole("#################################################################", logger, "information"); + testUtils.PrintToLogsOrConsole("######################## AUTHENTICATION #########################", logger, "information"); + testUtils.PrintToLogsOrConsole("#################################################################\n", logger, "information"); + if (bblCnn.State == ConnectionState.Open) + bblCnn.Close(); + try + { + string conString = testUtils.AuthHelper(strLine); + testUtils.ResultSetWriter(new SqlConnection(conString), testName); + + testUtils.PrintToLogsOrConsole("############## AUTHENTICATION PASSED #########################", logger, "information"); + } + catch (Exception e) + { + testUtils.PrintToLogsOrConsole(String.Format("############## AUTHENTICATION FAILED #########################\n" + e), logger, "information"); + } + } + else + { + /* + * Case for simple select and other DDL and DML queries which are in the domain of "SQL Batch" request. + */ + query = strLine; + testUtils.PrintToLogsOrConsole( + $"####################### EXECUTING SIMPLE QUERY- {query} #######################\n", logger, "information"); + if (query.ToLowerInvariant().StartsWith("select")) + { + bblCmd?.Dispose(); + bblCmd = testUtils.CreateDbCommand(null, bblCnn); + if (bblTransaction != null) + { + bblCmd.Transaction = bblTransaction; + } + bblCmd.CommandText = query; + + testUtils.ResultSetWriter(bblCmd, testName, ref stCount); + } + else if (query.ToLowerInvariant().StartsWith("insert") || query.ToLowerInvariant().StartsWith("update") || query.ToLowerInvariant().StartsWith("alter") + || query.ToLowerInvariant().StartsWith("delete") || query.ToLowerInvariant().StartsWith("begin") || query.ToLowerInvariant().StartsWith("commit") + || query.ToLowerInvariant().StartsWith("rollback") || query.ToLowerInvariant().StartsWith("save") || query.ToLowerInvariant().StartsWith("use") + || query.ToLowerInvariant().StartsWith("create") || query.ToLowerInvariant().StartsWith("drop") || query.ToLowerInvariant().StartsWith("exec") || query.ToLowerInvariant().StartsWith("declare")) + { + bblCmd?.Dispose(); + bblCmd = testUtils.CreateDbCommand(null, bblCnn); + + if (bblTransaction != null) + { + bblCmd.Transaction = bblTransaction; + } + bblCmd.CommandText = query; + + testUtils.ResultSetWriter(bblCmd, testName, ref stCount); + bblCmd.Dispose(); + } + else + { + bblCmd?.Dispose(); + stCount--; + testCaseCount--; + } + + } + } + catch (Exception e) + { + bblCmd?.Dispose(); + testUtils.PrintToLogsOrConsole(String.Format("############### QUERY COULD NOT RUN SUCCESSFULLY WITH ERROR DISPLAYED BELOW ################\n" + e), logger, "information"); + testFlag = false; + stCount--; + } + } + } + catch (Exception e) + { + testUtils.PrintToLogsOrConsole(String.Format("Error: " + e), logger, "information"); + } + finally + { + bblCmd?.Dispose(); + } + + testUtils.PrintToLogsOrConsole("###########################################################################", logger, "information"); + testUtils.PrintToLogsOrConsole("############################# EXIT BATCH RUN ##############################", logger, "information"); + testUtils.PrintToLogsOrConsole("###########################################################################", logger, "information"); + + + testResults[queryFilePath] = ""; + + return testFlag; + } + + /* Helper Function to Execute the batchrunner. */ + public bool Execute(string testName, string time, string queryPath) + { + DbConnection bblCnn = null; + bool flag = false; + TestUtils testUtils = new TestUtils(); + string logsDirectory = Path.Combine(ConfigSetup.InfoFolder, time, testName); + try + { + bblCnn = testUtils.GetDbConnection(ConfigSetup.BblConnectionString); + bblCnn.Open(); + + if(!ConfigSetup.PrintToConsole) + System.IO.Directory.CreateDirectory(logsDirectory); + + Serilog.Core.Logger log = null; + if(!ConfigSetup.PrintToConsole) + log = new LoggerConfiguration().MinimumLevel.Information().WriteTo.File(Path.Combine(logsDirectory, "ResultsCompareLog.log")).CreateLogger(); + try + { + Console.WriteLine("[{0:HH-mm-ss-dd-MM-yyyy}]:- STARTING {1} ", DateTime.Now , testName); + flag = BatchRunner(bblCnn, queryPath, log); + Console.WriteLine("[{0:HH-mm-ss-dd-MM-yyyy}]:- FINISHED RUNNING {1} \n {2}", DateTime.Now, + testName, ""); + + flag = testUtils.GenerateDiff(testName, time, log); + } + catch (Exception e) + { + Console.WriteLine("[{0:HH-mm-ss-dd-MM-yyyy}]:- FINISHED RUNNING {1}", DateTime.Now, testName); + Console.WriteLine(e); + return false; + } + } + catch (Exception e) + { + Console.WriteLine("FAILURE:- " + e); + } + finally + { + bblCnn?.Close(); + } + return flag; + } + } +} diff --git a/contrib/test/dotnet/src/ExecuteTests.cs b/contrib/test/dotnet/src/ExecuteTests.cs new file mode 100644 index 00000000000..40b212e85ab --- /dev/null +++ b/contrib/test/dotnet/src/ExecuteTests.cs @@ -0,0 +1,130 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Serilog; +using Xunit; +using Xunit.Abstractions; + +namespace BabelfishDotnetFramework +{ + + public class RunTests + { + /* + * We create only one Test function to run all the tests to make it more dynamic to add test cases. + * To do so we use a multi task approach. This makes it easier for the user to only add a query-test file in a folder + * and mention its path in the config. + */ + IEnumerable GetFilesByExtensions(DirectoryInfo dir, String[] noExecTests, params string[] extensions) + { + if (extensions == null) + throw new ArgumentNullException(nameof(extensions)); + IEnumerable files = dir.EnumerateFiles("*", SearchOption.AllDirectories); + return files.Where(f => extensions.Contains(f.Extension) && !noExecTests.Contains(f.Name)); + } + [Fact] + public void Test() + { + BatchRun batchRun = new BatchRun(); + DirectoryInfo dir = new DirectoryInfo(ConfigSetup.QueryFolder); + IEnumerable allFiles; + string[] testName = ConfigSetup.TestName.Split("---"); + string[] noExecTests = { }; + if (testName.Length > 1) + noExecTests = testName[1].Split(";"); + if (testName[0] == "all") + allFiles = GetFilesByExtensions(dir, noExecTests, ".sql", ".txt"); + else + { + string[] tests = testName[0].Split(";"); + // allFiles + List tempList = new List(); + foreach (string t in tests) + { + if (noExecTests.Contains(t)) + continue; + if (t.Trim().Length <= 1) + continue; + tempList.Add(new FileInfo(Path.Combine(ConfigSetup.QueryFolder, t.Trim()))); + } + allFiles = tempList; + } + Task[] tasksInParallel = new Task[allFiles.Count()]; + bool [] result = new bool[allFiles.Count()]; + int i = 0; + string time = DateTime.Now.ToString("hh-mm-ss-dd-MM-yy"); + + foreach (FileInfo file in allFiles) + { + /* Delete the Output Files If it exists. */ + if (File.Exists(Path.Combine(ConfigSetup.OutputFolder, file.Name.Substring(0, file.Name.Length - 4) + ".out"))) + { + File.Delete(Path.Combine(ConfigSetup.OutputFolder, file.Name.Substring(0, file.Name.Length - 4) + ".out")); + } + if (ConfigSetup.RunInParallel) + tasksInParallel[i] = Task.Factory.StartNew(() => batchRun.Execute(file.Name.Substring(0, file.Name.Length - 4), time, file.FullName)); + else + result[i] = batchRun.Execute(file.Name.Substring(0, file.Name.Length - 4), time, file.FullName); + i++; + } + if (ConfigSetup.RunInParallel) + { + Task.WaitAll(tasksInParallel); + for (i = 0; i < allFiles.Count(); i++) result[i] = tasksInParallel[i].Result; + PrintAndLogSummary(result, allFiles, time); + } + else + PrintAndLogSummary(result, allFiles, time); + } + static void PrintAndLogSummary(bool[] result, IEnumerable allFiles, string time) + { + /* To print Summary when tests run serially. */ + TestUtils utils = new TestUtils(); + Directory.CreateDirectory(Path.Combine(ConfigSetup.InfoFolder, time)); + var log1 = new LoggerConfiguration().MinimumLevel.Information().WriteTo.File(Path.Combine(ConfigSetup.InfoFolder, time, "SUMMARY.log")).CreateLogger(); + log1.Information("#################################################################################"); + log1.Information("################################# TESTS' STATUS ################################"); + log1.Information("#################################################################################\n"); + + Console.WriteLine("\n#################################################################################"); + Console.WriteLine("################################# TESTS' STATUS ################################"); + Console.WriteLine("#################################################################################\n"); + utils.PrintLine(); + log1.Information(new string('-', utils.tableWidth)); + utils.PrintRow("NAME OF THE TEST", "STATUS"); + + int i = 0; + int testCount = 0; + foreach ( FileInfo file in allFiles) + { + log1.Information(new string('-', utils.tableWidth)); + utils.PrintLine(); + if (result[i++] == false && BatchRun.testResults.Keys.Contains(file.FullName)) + { + Console.ForegroundColor = ConsoleColor.Red; + log1.Information(utils.PrintRow(file.Name, "FAILED" + BatchRun.testResults[file.FullName])); + } + else if (!BatchRun.testResults.Keys.Contains(file.FullName)) + { + Console.ForegroundColor = ConsoleColor.Red; + log1.Information(utils.PrintRow(file.Name, "FAILED OR CRAHSED")); + } + else + { + log1.Information(utils.PrintRow(file.Name, "PASSED" + BatchRun.testResults[file.FullName])); + testCount++; + } + } + Console.ForegroundColor = ConsoleColor.Black; + utils.PrintLine(); + log1.Information(new string('-', utils.tableWidth)); + log1.Information(utils.PrintRow("TOTAL NUMBER OF TESTS PASSED ", testCount + "/" + allFiles.Count())); + utils.PrintLine(); + log1.Information(new string('-', utils.tableWidth)); + Assert.True( (allFiles.Count() == testCount), "###################### NOT ALL TEST FILES PASSED ######################"); + } + } +} diff --git a/contrib/test/dotnet/src/PrepareExecBinding.cs b/contrib/test/dotnet/src/PrepareExecBinding.cs new file mode 100644 index 00000000000..058f6652a4d --- /dev/null +++ b/contrib/test/dotnet/src/PrepareExecBinding.cs @@ -0,0 +1,453 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Data.Common; +using System.Data.OleDb; +using System.Data.SqlClient; +using System.Data.SqlTypes; +using System.IO; +using System.Text; + +namespace BabelfishDotnetFramework +{ + public static class PrepareExecBinding + { + public static List ListOfOutParameters; + + public static DbCommand SetBindParams(string[] result, + DbCommand sqlCmd, + bool execFlag, + Serilog.Core.Logger logger) + { + TestUtils testUtils = new TestUtils(); + try + { + /* If sp_execute then only set value of parameter. */ + if (execFlag) + { + for (int i = 2; i < result.Length; i++) + { + string[] param = result[i].Split("|-|"); + if (param[2].Trim().ToLowerInvariant() == "") + { + sqlCmd.Parameters[param[1]].Value = DBNull.Value; + if (param.Length > 3) + sqlCmd.Parameters[param[1].Trim()].Scale = byte.Parse(param[2]); + } + switch (param[0].Split('-')[0].Trim().ToLowerInvariant()) + { + case "int": + case "smallint": + case "bigint": + case "tinyint": + case "bit": + case "float": + case "real": + case "money": + case "smallmoney": + case "date": + case "datetime": + case "smalldatetime": + case "uniqueidentifier": + sqlCmd.Parameters[param[1].Trim()].Value = GetSqlDbValue(param[0], param[2].Trim()); + break; + case "char": + case "nchar": + case "varchar": + case "nvarchar": + case "text": + case "ntext": + case "string": + case "xml": + { + sqlCmd.Parameters[param[1].Trim()].Value = GetSqlDbValue(param[0], param[2].Trim()); + sqlCmd.Parameters[param[1].Trim()].Size = 100; + /* If Locale id present and the driver is SqlClient then set it. */ + if (param.Length > 3 && ConfigSetup.Database.Equals("sql", StringComparison.InvariantCulture)) + if (param[3].Trim().ToLowerInvariant() != "input" && param[3].Trim().ToLowerInvariant() != "output" + && param[3].Trim().ToLowerInvariant() != "inputoutput" && param[3].Trim().ToLowerInvariant() != "return") + ((SqlParameter) sqlCmd.Parameters[param[1].Trim()]).LocaleId = int.Parse(param[3].Trim()); + } + break; + case "decimal": + case "numeric": + { + sqlCmd.Parameters[param[1].Trim()].Value = GetSqlDbValue(param[0], param[2].Trim()); + sqlCmd.Parameters[param[1].Trim()].Precision = byte.Parse(param[3].Trim()); + sqlCmd.Parameters[param[1].Trim()].Scale = byte.Parse(param[4].Trim()); + } + break; + case "binary": + case "varbinary": + case "image": + { + sqlCmd.Parameters[param[1].Trim()].Value = GetSqlDbValue(param[0], param[2].Trim()); + sqlCmd.Parameters[param[1].Trim()].Size = ((byte[]) sqlCmd.Parameters[param[1].Trim()].Value).Length; + } + break; + case "time": + case "datetime2": + case "datetimeoffset": + { + /* varchar since we want the original value to be asigned and then set the scale. */ + sqlCmd.Parameters[param[1].Trim()].Value = GetSqlDbValue("varchar", param[2].Trim()); + sqlCmd.Parameters[param[1].Trim()].Scale = byte.Parse(param[3].Trim()); + } + break; + case "sql_variant": + { + sqlCmd.Parameters[param[1].Trim()].Size = 100; /* Todo call this recursively inorder to avoid this. */ + sqlCmd.Parameters[param[1].Trim()].Value = param[2].Trim().ToLowerInvariant() == "" ? + DBNull.Value : GetSqlDbValue(param[0].Split('-')[1].Trim(), param[2].Trim()); + } + break; + case "tvp": + { + if (ConfigSetup.Database.Equals("oledb", StringComparison.InvariantCulture)) + { + testUtils.PrintToLogsOrConsole("TVP NOT SUPPORTED BY OLEDB", logger, "error"); + break; + } + ((SqlParameter) sqlCmd.Parameters[param[1].Trim()]).TypeName = param[2].Trim(); + var temp = testUtils.FetchTvpValueUsingSqlDataRecord(param[3].Trim()); + ((SqlParameter) sqlCmd.Parameters[param[1].Trim()]).SqlValue = temp; + sqlCmd.Parameters[param[1].Trim()].Size = 1000; + } + break; + default: + throw new Exception("DATATYPE NOT SUPPORTED:- " + param[0]); + } + } + } + /* If sp_prepexec then create and add Parameters with Value. */ + else + { + ListOfOutParameters = new List(); + + for (int i = 2; i < result.Length; i++) + { + + string[] param = result[i].Split("|-|", StringSplitOptions.RemoveEmptyEntries); + DbParameter parameter = testUtils.CreateDbParameter(param[1].Trim(), param[0].Trim()); + if (ConfigSetup.Database.Equals("oledb", StringComparison.InvariantCulture)) + ReplaceParamNameWithQuestionMark(sqlCmd, param[1].Trim()); + + if (param[^1].Trim().ToLowerInvariant() == "input") + { + parameter.Direction = ParameterDirection.Input; + } + else if (param[^1].Trim().ToLowerInvariant() == "output") + { + ListOfOutParameters.Add(param[1].Trim()); + parameter.Direction = ParameterDirection.Output; + } + else if (param[^1].Trim().ToLowerInvariant() == "inputoutput") + { + ListOfOutParameters.Add(param[1].Trim()); + parameter.Direction = ParameterDirection.InputOutput; + } + else if (param[^1].Trim().ToLowerInvariant() == "return") + { + ListOfOutParameters.Add(param[1].Trim()); + parameter.Direction = ParameterDirection.ReturnValue; + } + + switch (param[0].Split('-')[0].Trim().ToLowerInvariant()) + { + case "int": + case "smallint": + case "bigint": + case "tinyint": + case "bit": + case "float": + case "real": + case "money": + case "smallmoney": + case "date": + case "datetime": + case "smalldatetime": + case "uniqueidentifier": + parameter.Value = GetSqlDbValue(param[0], param[2].Trim()); + break; + case "char": + case "nchar": + case "varchar": + case "nvarchar": + case "text": + case "ntext": + case "string": + case "xml": + { + parameter.Value = GetSqlDbValue(param[0], param[2].Trim()); + parameter.Size = 100; + /* If Locale id present and its sql server then set it. */ + if (param.Length > 3 && ConfigSetup.Database.Equals("sql", StringComparison.InvariantCulture)) + if (param[3].Trim().ToLowerInvariant() != "input" && param[3].Trim().ToLowerInvariant() != "output" + && param[3].Trim().ToLowerInvariant() != "inputoutput" && param[3].Trim().ToLowerInvariant() != "return") + ((SqlParameter) parameter).LocaleId = int.Parse(param[3].Trim()); + } + break; + case "decimal": + case "numeric": + { + parameter.Value = GetSqlDbValue(param[0], param[2].Trim()); + parameter.Precision = byte.Parse(param[3].Trim()); + parameter.Scale = byte.Parse(param[4].Trim()); + } + break; + case "binary": + case "varbinary": + case "image": + { + parameter.Value = GetSqlDbValue(param[0], param[2].Trim()); + parameter.Size = ((byte[]) parameter.Value).Length; + } + break; + case "time": + case "datetime2": + case "datetimeoffset": + { + parameter.Size = -1; + /* varchar since we want the original value to be asigned and then set the scale. */ + parameter.Value = GetSqlDbValue("varchar", param[2].Trim()); + parameter.Scale = byte.Parse(param[3].Trim()); + } + break; + case "sql_variant": + { + parameter.Size = 100; + parameter.Value = param[2].Trim().ToLowerInvariant() == "" ? + DBNull.Value : GetSqlDbValue(param[0].Split('-')[1].Trim(), param[2].Trim()); + } + break; + case "tvp": + { + if (ConfigSetup.Database.Equals("oledb", StringComparison.InvariantCulture)) + { + testUtils.PrintToLogsOrConsole("TVP NOT SUPPORTED BY OLEDB", logger, "error"); + break; + } + ((SqlParameter) parameter).TypeName = param[2].Trim(); + var temp = testUtils.FetchTvpValueUsingSqlDataRecord(param[3].Trim()); + ((SqlParameter) parameter).SqlValue = temp; + parameter.Size = 1000; + } + break; + default: + throw new Exception("DATATYPE NOT SUPPORTED:- " + param[0]); + } + sqlCmd.Parameters.Add(parameter); + } + } + + } + catch (Exception e) + { + testUtils.PrintToLogsOrConsole(String.Format("################### ERROR WITH SETTING PARAMETERS ###################\n" + e), logger, "information"); + } + return sqlCmd; + } + + /* Used for Oledb drivers to convert bind variables from @name to ?. */ + static void ReplaceParamNameWithQuestionMark(DbCommand cmd, string paramName) + { + cmd.CommandText = cmd.CommandText.Replace("@" + paramName, "?"); + } + + /* Returns the OleDb Type for OleDb drivers. */ + public static OleDbType GetOleDbType(string type) + { + switch (type.Split('-')[0].ToLower()) + { + case "int": + return OleDbType.Integer; + case "smallint": + return OleDbType.SmallInt; + case "bigint": + return OleDbType.BigInt; + case "tinyint": + return OleDbType.TinyInt; + case "bit": + return OleDbType.Boolean; + case "nchar": + return OleDbType.WChar; + case "varchar": + return OleDbType.VarChar; + case "char": + return OleDbType.Char; + case "nvarchar": + case "string": + return OleDbType.VarWChar; + case "text": + return OleDbType.VarChar; + case "ntext": + return OleDbType.VarWChar; + case "float": + return OleDbType.Double; + case "decimal": + case "numeric": + return OleDbType.Decimal; + case "real": + return OleDbType.Double; + case "date": + return OleDbType.DBDate; + case "time": + return OleDbType.DBTime; + case "datetime": + return OleDbType.DBTimeStamp; + case "datetime2": + return OleDbType.DBTimeStamp; + case "binary": + return OleDbType.Binary; + case "varbinary": + return OleDbType.VarBinary; + case "uniqueidentifier": + return OleDbType.Guid; + case "sql_variant": + return OleDbType.Variant; + default: + throw new Exception("DATA TYPE NOT SUPPORTED " + type); + } + } + + /* Returns the SqlDb Type for SqlClient drivers. */ + public static SqlDbType GetSqlDbType(string type) + { + switch (type.Split('-')[0].ToLower()) + { + case "int": + return SqlDbType.Int; + case "smallint": + return SqlDbType.SmallInt; + case "bigint": + return SqlDbType.BigInt; + case "tinyint": + return SqlDbType.TinyInt; + case "bit": + return SqlDbType.Bit; + case "nchar": + return SqlDbType.NChar; + case "varchar": + return SqlDbType.VarChar; + case "char": + return SqlDbType.Char; + case "nvarchar": + case "string": + return SqlDbType.NVarChar; + case "text": + return SqlDbType.Text; + case "ntext": + return SqlDbType.NText; + case "float": + return SqlDbType.Float; + case "decimal": + case "numeric": + return SqlDbType.Decimal; + case "money": + return SqlDbType.Money; + case "smallmoney": + return SqlDbType.SmallMoney; + case "real": + return SqlDbType.Real; + case "smalldatetime": + return SqlDbType.SmallDateTime; + case "date": + return SqlDbType.Date; + case "time": + return SqlDbType.Time; + case "datetime": + return SqlDbType.DateTime; + case "datetimeoffset": + return SqlDbType.DateTimeOffset; + case "datetime2": + return SqlDbType.DateTime2; + case "binary": + return SqlDbType.Binary; + case "varbinary": + return SqlDbType.VarBinary; + case "image": + return SqlDbType.Image; + case "xml": + return SqlDbType.Xml; + case "uniqueidentifier": + return SqlDbType.UniqueIdentifier; + case "sql_variant": + return SqlDbType.Variant; + case "tvp": + return SqlDbType.Structured; + case "udt": + return SqlDbType.Udt; + default: + throw new Exception("DATA TYPE NOT SUPPORTED " + type); + } + } + + /* Returns the Value after an appropriate parse for a particular type. */ + public static object GetSqlDbValue(string type, string value) + { + if(value.ToLower() == "") + return DBNull.Value; + switch (type.ToLower()) + { + case "int": + return Int32.Parse(value); + case "smallint": + return Int16.Parse(value); + case "bigint": + return Int64.Parse(value); + case "tinyint": + return byte.Parse(value); + case "bit": + return bool.Parse(value); + case "nchar": + return value; + case "varchar": + return value; + case "char": + case "nvarchar": + case "string": + return value; + case "text": + case "ntext": + string result = ""; + string[] read = File.ReadAllLines(value); + foreach (string line in read) + result += line + '\n'; + result.Remove(result.Length - 1); + return result; + case "float": + return double.Parse(value); + case "decimal": + case "numeric": + return decimal.Parse(value); + case "money": + case "smallmoney": + return SqlMoney.Parse(value); + case "real": + return Single.Parse(value); + case "date": + case "datetime": + case "smalldatetime": + case "datetime2": + return DateTime.Parse(value); + case "time": + return TimeSpan.Parse(value); + case "binary": + case "varbinary": + byte[] byteArray = Encoding.ASCII.GetBytes(value); + return byteArray; + case "image": + FileStream fs = new FileStream(value, FileMode.Open, FileAccess.Read); + BinaryReader br = new BinaryReader(fs); + byteArray = br.ReadBytes((Int32)fs.Length); + return byteArray; + case "xml": + return value; + case "uniqueidentifier": + return new Guid(value); + default: + return value; + } + } + } +} diff --git a/contrib/test/dotnet/utils/ConfigSetup.cs b/contrib/test/dotnet/utils/ConfigSetup.cs new file mode 100644 index 00000000000..611e5c20495 --- /dev/null +++ b/contrib/test/dotnet/utils/ConfigSetup.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.IO; + +namespace BabelfishDotnetFramework +{ + public static class ConfigSetup + { + /* Declaring variables required for a Test Run. */ + static readonly Dictionary Dictionary = LoadConfig(); + public static readonly string BblConnectionString = Dictionary["bblConnectionString"]; + public static readonly string QueryFolder = Dictionary["queryFolder"]; + public static readonly string TestName = Dictionary["testName"]; + public static readonly bool RunInParallel = bool.Parse(Dictionary["runInParallel"]); + public static readonly bool PrintToConsole = bool.Parse(Dictionary["printToConsole"]); + public static string Database; + public static string Provider = Dictionary["provider"]; + + /* Using relative paths to locate some important files and folders. */ + public static string InfoFolder = Path.Combine(Directory.GetCurrentDirectory(), "..", "..", "..", "Info"); + public static string OutputFolder = Path.Combine(Directory.GetCurrentDirectory(), "..", "..", "..", "Output"); + public static string ExpectedOutputFolder = Path.Combine(Directory.GetCurrentDirectory(), "..", "..", "..", "ExpectedOutput"); + + /* Load configurations from config.txt file. */ + public static Dictionary LoadConfig() + { + string ConfigFile = Path.Combine(Directory.GetCurrentDirectory(), "..", "..", "..", "config.txt"); + var lines = File.ReadAllLines(ConfigFile); + + Dictionary dictionary = new Dictionary(); + foreach (string line in lines) + { + if (string.IsNullOrWhiteSpace(line)) continue; + /* Remove extra spaces. */ + string nLine = line.Trim(); + if (nLine[0] == '#') continue; + string[] kvp = nLine.Split('='); + if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable(kvp[0].Trim()))) + dictionary[kvp[0].Trim()] = kvp[1].Trim(); // kvp[0] = key, kvp[1] = value + else + dictionary[kvp[0].Trim()] = Environment.GetEnvironmentVariable(kvp[0].Trim()); + } + Database = dictionary["driver"]; + Provider = dictionary["provider"]; + + /* Creating Server Connection String and Query. */ + dictionary["bblConnectionString"] = BuildConnectionString(dictionary["babel_URL"], dictionary["babel_port"], + dictionary["babel_databaseName"], + dictionary["babel_user"], dictionary["babel_password"]); + return dictionary; + } + + static string BuildConnectionString(string url, string port, string db, string uid, string pwd) + { + switch (ConfigSetup.Database.ToLowerInvariant()) + { + case "oledb": + return @"Provider = " + ConfigSetup.Provider + ";Data Source = " + url + "," + port + "; Initial Catalog = " + db + + "; User ID = " + uid + "; Password = " + pwd + ";Pooling=false;"; + case "sql": + return @"Data Source = " + url + "," + port + "; Initial Catalog = " + db + + "; User ID = " + uid + "; Password = " + pwd + ";Pooling=false;"; + default: + throw new Exception("Driver Not Supported"); + } + } + } +} diff --git a/contrib/test/dotnet/utils/TestUtils.cs b/contrib/test/dotnet/utils/TestUtils.cs new file mode 100644 index 00000000000..1beb1b00b00 --- /dev/null +++ b/contrib/test/dotnet/utils/TestUtils.cs @@ -0,0 +1,563 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Data.Common; +using System.Data.OleDb; +using System.Data.SqlClient; +using System.Data.SqlTypes; +using System.Diagnostics; +using System.IO; +using System.Net.NetworkInformation; +using System.Runtime.InteropServices; +using Microsoft.SqlServer.Server; +using Serilog; +using Serilog.Core; +using Xunit; + +namespace BabelfishDotnetFramework +{ + public class TestUtils + { + public void PrintToLogsOrConsole(string message, Logger logger, string logLevel) + { + if (ConfigSetup.PrintToConsole) + Console.WriteLine(message); + else + { + if (logLevel.ToLower() == "information") + logger.Information(message); + else if (logLevel.ToLower() == "error") + logger.Error(message); + else if (logLevel.ToLower() == "warning") + logger.Warning(message); + } + } + + public bool insertBulkCopy(DbConnection bblCnn, DbCommand bblCmd, String sourceTable, String destinationTable, Logger logger, ref int stCount) + { + bblCmd.CommandText = "Select * from " + sourceTable; + DbDataReader reader = null; + try + { + reader = bblCmd.ExecuteReader(); + SqlBulkCopy bulkCopy = new SqlBulkCopy(ConfigSetup.BblConnectionString); + bulkCopy.DestinationTableName = destinationTable; + bulkCopy.WriteToServer(reader); + } + catch (Exception e) + { + PrintToLogsOrConsole("#################################################################", logger, "information"); + PrintToLogsOrConsole( + $"############# ERROR IN EXECUTING WITH BABEL ####################\n{e}\n", + logger, "information"); + stCount--; + return false; + } + finally + { + reader.Close(); + } + return true; + } + + public void ResultSetWriter(DbConnection cnn, string fileName) + { + // USED TO WRITE THE CONNECTION AUTHENTICATIONS IN ONE FILE + using var file = + new StreamWriter(Path.Combine(ConfigSetup.OutputFolder, fileName + ".out"), true); + file.WriteLine("#Q#" + cnn.ConnectionString); + try + { + cnn.Open(); + file.WriteLine("PASSED"); + } + catch (Exception e) + { + file.WriteLine("#E#" + e.Message); + } + } + public void ResultSetWriter(DbCommand cmd, string fileName, ref int count) + { + // USED TO WRITE THE RESULT-SETS IN ONE FILE + using var file = + new StreamWriter(Path.Combine(ConfigSetup.OutputFolder, fileName + ".out"), true); + file.WriteLine("#Q#" + cmd.CommandText); + DbDataReader rdr = null; + try + { + rdr = cmd.ExecuteReader(); + } + catch (Exception e) + { + file.WriteLine("#E#" + e.Message); + rdr?.Close(); + return; + } + int totalNumberOfCol = rdr.FieldCount; + + try + { + if (rdr.Read()) + { + string temp = null; + int colNumber; + file.Write("#D#"); + for (colNumber = 0; colNumber < totalNumberOfCol - 1; colNumber++) + { + file.Write(rdr.GetDataTypeName(colNumber) + "#!#"); + if (rdr.GetDataTypeName(colNumber).ToLowerInvariant().StartsWith("image") + || rdr.GetDataTypeName(colNumber).ToLowerInvariant().StartsWith("binary") + || rdr.GetDataTypeName(colNumber).ToLowerInvariant().StartsWith("varbinary")) + temp += rdr.GetValue(colNumber) == DBNull.Value + ? null + : BinaryToString((byte[]) rdr.GetValue(colNumber)) + "#!#"; + else + temp += rdr.GetValue(colNumber) + "#!#"; + } + file.WriteLine(rdr.GetDataTypeName(colNumber)); + if (rdr.GetDataTypeName(colNumber).ToLowerInvariant().StartsWith("image") + || rdr.GetDataTypeName(colNumber).ToLowerInvariant().StartsWith("binary") + || rdr.GetDataTypeName(colNumber).ToLowerInvariant().StartsWith("varbinary")) + file.WriteLine(temp + (rdr.GetValue(colNumber) == DBNull.Value + ? null + : BinaryToString((byte[]) rdr.GetValue(colNumber)))); + else + file.WriteLine(temp + rdr.GetValue(colNumber)); + } + + do + { + while (rdr.Read()) + { + //comparing all Column values + int colNumber; + for (colNumber = 0; colNumber < totalNumberOfCol - 1; colNumber++) + { + if (rdr.GetDataTypeName(colNumber).ToLowerInvariant().StartsWith("image") + || rdr.GetDataTypeName(colNumber).ToLowerInvariant().StartsWith("binary") + || rdr.GetDataTypeName(colNumber).ToLowerInvariant().StartsWith("varbinary")) + file.WriteLine(rdr.GetValue(colNumber) == DBNull.Value + ? null + : BinaryToString((byte[]) rdr.GetValue(colNumber)) + "#!#"); + else + file.Write(rdr.GetValue(colNumber) + "#!#"); + } + + if (rdr.GetDataTypeName(colNumber).ToLowerInvariant().StartsWith("image") + || rdr.GetDataTypeName(colNumber).ToLowerInvariant().StartsWith("binary") + || rdr.GetDataTypeName(colNumber).ToLowerInvariant().StartsWith("varbinary")) + file.WriteLine(rdr.GetValue(colNumber) == DBNull.Value + ? null + : BinaryToString((byte[]) rdr.GetValue(colNumber))); + else + file.WriteLine(rdr.GetValue(colNumber)); + } + } while (rdr.NextResult()); + + if (PrepareExecBinding.ListOfOutParameters.Count > 0) + { + file.WriteLine($"--OUT PARAMETERS--"); + foreach (string param in PrepareExecBinding.ListOfOutParameters) + { + file.WriteLine(cmd.Parameters[param]); + file.WriteLine(cmd.Parameters[param].DbType.ToString()); + file.WriteLine(cmd.Parameters[param].Value.ToString() + '\n'); + } + PrepareExecBinding.ListOfOutParameters.Clear(); + } + } + catch + { + count--; + } + finally + { + rdr?.Close(); + } + } + + string BinaryToString(byte[] a) + { + string s = null; + if(a != null) + foreach (var temp in a) + { + s += temp; + } + return s; + } + + private static Type GetDType(string name) + { + // FETCHES THE DATA TYPE FROM THE STRING + Type type = null; + name = name.ToLower(); + if (name.Equals("int", StringComparison.InvariantCultureIgnoreCase)) + { + type = Type.GetType("System.Int32"); + } + else if (name.Equals("smallint", StringComparison.InvariantCultureIgnoreCase)) + { + type = Type.GetType("System.Int16"); + } + else if (name.Equals("bigint", StringComparison.InvariantCultureIgnoreCase)) + { + type = Type.GetType("System.Int64"); + } + else if (name.Equals("tinyint", StringComparison.InvariantCultureIgnoreCase)) + { + // int 32 just to differentiate from Binary types + type = Type.GetType("System.Int32"); + } + else if (name.Equals("nchar", StringComparison.InvariantCultureIgnoreCase)) + { + type = Type.GetType("System.String"); + } + else if (name.Equals("nvarchar", StringComparison.InvariantCultureIgnoreCase)) + { + type = Type.GetType("System.String"); + } + else if (name.Equals("bit", StringComparison.InvariantCultureIgnoreCase)) + { + type = Type.GetType("System.Boolean"); + } + else if (name.Equals("float", StringComparison.InvariantCultureIgnoreCase)) + { + type = Type.GetType("System.Double"); + } + else if (name.Equals("numeric", StringComparison.InvariantCultureIgnoreCase)) + { + type = Type.GetType("System.Decimal"); + } + else if (name.Equals("money", StringComparison.InvariantCultureIgnoreCase)) + { + type = Type.GetType("System.Decimal"); + } + else if (name.Equals("smallmoney", StringComparison.InvariantCultureIgnoreCase)) + { + type = Type.GetType("System.Decimal"); + } + else if (name.Equals("real", StringComparison.InvariantCultureIgnoreCase)) + { + + type = Type.GetType("System.Single"); + } + else if (name.Equals("smalldatetime", StringComparison.InvariantCultureIgnoreCase)) + { + type = Type.GetType("System.DateTime"); + } + else if (name.Equals("datetime", StringComparison.InvariantCultureIgnoreCase)) + { + type = Type.GetType("System.DateTime"); + } + else if (name.Equals("binary", StringComparison.InvariantCultureIgnoreCase)) + { + type = Type.GetType("System.Byte"); + } + else if (name.Equals("varbinary", StringComparison.InvariantCultureIgnoreCase)) + { + type = Type.GetType("System.Byte"); + } + else if (name.Equals("image", StringComparison.InvariantCultureIgnoreCase)) + { + type = Type.GetType("System.Byte"); + } + return type; + } + static List> FetchTvpTableFromFile(string file) + { + var rows = new List>(); + using var reader = new StreamReader(file); + while (!reader.EndOfStream) + { + var columns = new List(); + var line = reader.ReadLine(); + if (line != null) + { + var values = line.Split(','); + + foreach (var value in values) + { + columns.Add(value); + } + } + rows.Add(columns); + } + + return rows; + } + + private static readonly List VarTypes = new List { "varchar", "char", "nvarchar", "nchar", "varbinary", "binary"}; + private static readonly List DecimalTypes = new List { "numeric", "decimal"}; + public SqlDataRecord[] FetchTvpValueUsingSqlDataRecord(string file) + { + List> rows = FetchTvpTableFromFile(file); + int numberOfRows = rows.Count; + int numberOfColumns = rows[0].Count; + SqlDataRecord[] record = new SqlDataRecord[numberOfRows - 1]; + SqlMetaData[] metadata = new SqlMetaData[numberOfColumns]; + + for (var currentCol = 0; currentCol < numberOfColumns; currentCol++) + { + if (VarTypes.Contains(rows[0][currentCol].Split("-")[1].ToLowerInvariant())) + { + metadata[currentCol] = new SqlMetaData(rows[0][currentCol].Split("-")[0], + PrepareExecBinding.GetSqlDbType(rows[0][currentCol].Split("-")[1]), long.Parse(rows[0][currentCol].Split("-")[2])); + } + else if(DecimalTypes.Contains(rows[0][currentCol].Split("-")[1].ToLowerInvariant())) + metadata[currentCol] = new SqlMetaData(rows[0][currentCol].Split("-")[0], + PrepareExecBinding.GetSqlDbType(rows[0][currentCol].Split("-")[1]), byte.Parse(rows[0][currentCol].Split("-")[2]), byte.Parse(rows[0][currentCol].Split("-")[3])); + else + { + metadata[currentCol] = new SqlMetaData(rows[0][currentCol].Split("-")[0], + PrepareExecBinding.GetSqlDbType(rows[0][currentCol].Split("-")[1])); + } + } + + for (var currentRow = 1; currentRow < numberOfRows; currentRow++) + { + record[currentRow - 1] = new SqlDataRecord(metadata); + for (int currentCol = 0; currentCol < numberOfColumns; currentCol++) + record[currentRow - 1].SetValue(currentCol, + PrepareExecBinding.GetSqlDbValue(rows[0][currentCol].Split("-")[1], rows[currentRow][currentCol])); + } + return record; + } + public DataTable FetchTvpValue(string file) + { + List> rows = FetchTvpTableFromFile(file); + int numberOfRows = rows.Count; + int numberOfColumns = rows[0].Count; + DataTable table = new DataTable(); + string[] columnName = new string[numberOfColumns]; + for (int currentCol = 0; currentCol < numberOfColumns; currentCol++) + { + // add the column metadata + table.Columns.Add(rows[0][currentCol].Split("-")[0], GetDType(rows[0][currentCol].Split("-")[1])); + columnName[currentCol] = rows[0][currentCol].Split("-")[0]; + } + + // add the TVP rows + for (int currentRow = 1; currentRow < numberOfRows; currentRow++) + { + DataRow newRow = table.NewRow(); + for (int currentCol = 0; currentCol < numberOfColumns; currentCol++) + { + newRow[columnName[currentCol]] = rows[currentRow][currentCol]; + } + table.Rows.Add(newRow); + } + return table; + } + public string AuthHelper(string strLine) + { + Dictionary dictionary = ConfigSetup.LoadConfig(); + dictionary["url"] = dictionary["babel_URL"]; + dictionary["db"] = dictionary["babel_databaseName"]; + dictionary["user"] = dictionary["babel_user"]; + dictionary["pwd"] = dictionary["babel_password"]; + dictionary["others"] = ""; + + string[] result = new string[10]; + result = strLine.Split("#!#", StringSplitOptions.RemoveEmptyEntries); + for (int i = 1; i < result.Length; i++) + { + if (result[i].ToLowerInvariant().StartsWith("pwd")) + dictionary["pwd"] = result[i].Split("|-|")[1]; + else if (result[i].ToLowerInvariant().StartsWith("db")) + dictionary["db"] = result[i].Split("|-|")[1]; + else if (result[i].ToLowerInvariant().StartsWith("user")) + dictionary["user"] = result[i].Split("|-|")[1]; + else if (result[i].ToLowerInvariant().StartsWith("others")) + dictionary["others"] = result[i].Split("|-|")[1]; + } + return @"Data Source = " + dictionary["url"] + "; Initial Catalog = " + dictionary["db"] + + "; User ID = " + dictionary["user"] + "; Password = " + dictionary["pwd"] + ";Pooling=false;" + dictionary["others"]; + } + + /* Depending on the OS we use the appropriate diff command. */ + ProcessStartInfo GetDiffFileProcessDependingOnOs(string output, string expectedOutput, string diffFile) + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + return new ProcessStartInfo + { + FileName = @"powershell.exe", + Arguments = $"-c \"diff (cat {output}) (cat {expectedOutput}) > {diffFile}\"", + UseShellExecute = false, + CreateNoWindow = false, + RedirectStandardError = true + }; + return new ProcessStartInfo + { + FileName = @"bash", + Arguments = $"-c \"diff {output} {expectedOutput} > {diffFile}\"", + UseShellExecute = false, + CreateNoWindow = false, + RedirectStandardError = true + }; + } + + public bool GenerateDiff(string testName, string time, Logger log) + { + string output = Path.Combine(ConfigSetup.OutputFolder, testName + ".out"); + string expectedOutput = Path.Combine(ConfigSetup.ExpectedOutputFolder, testName + ".out"); + string diffFile = Path.Combine(ConfigSetup.InfoFolder, time, testName + ".diff"); + if (!Directory.Exists(Path.Combine(ConfigSetup.InfoFolder, time))) + Directory.CreateDirectory(Path.Combine(ConfigSetup.InfoFolder, time)); + var ps = GetDiffFileProcessDependingOnOs(output, expectedOutput, diffFile); + var process = Process.Start(ps); + if (process != null) + { + process.WaitForExit(); + process.Kill(); + var tempArray = ReadFile(diffFile); + PrintToLogsOrConsole($"DIFF RETURN VALUE: " + (tempArray.Length > 0 ? "1" :"0"), log, "info"); + if (ConfigSetup.PrintToConsole) + { + string temp = ""; + foreach (var line in tempArray) + { + temp += line+"\r\n"; + } + PrintToLogsOrConsole(temp, log, "info"); + } + return process.ExitCode.ToString().Equals("0"); + } + + return false; + } + public int tableWidth = 73; + + /* USED TO PRINT THE OUTPUT */ + public void PrintLine() + { + Console.ForegroundColor = ConsoleColor.Black; + Console.WriteLine(new string('-', tableWidth)); + } + + public string PrintRow(params string[] columns) + { + int width = (tableWidth - columns.Length) / columns.Length; + string row = "|"; + + foreach (string column in columns) + { + row += AlignCentre(column, width) + "|"; + } + Console.WriteLine(row); + return row; + } + + /* USED TO PRINT THE OUTPUT */ + string AlignCentre(string text, int width) + { + text = text.Length > width ? text.Substring(0, width - 3) + "..." : text; + + if (string.IsNullOrEmpty(text)) + { + return new string(' ', width); + } + + return text.PadRight(width - (width - text.Length) / 2).PadLeft(width); + } + + public DbConnection GetDbConnection(string connectionString) + { + return ConfigSetup.Database.ToLowerInvariant() switch + { + "oledb" => new OleDbConnection(connectionString), + "sql" => new SqlConnection(connectionString), + _ => null + }; + } + + public DbCommand CreateDbCommand(string commandText, DbConnection con) + { + return ConfigSetup.Database.ToLowerInvariant() switch + { + "oledb" => new OleDbCommand(commandText, (OleDbConnection) con), + "sql" => new SqlCommand(commandText, (SqlConnection) con), + _ => null + }; + } + + public DbTransaction GetDbBeginTransaction(DbConnection con, IsolationLevel i, string tranName) + { + switch (ConfigSetup.Database.ToLowerInvariant()) + { + case "oledb": return ((OleDbConnection) con).BeginTransaction(i); + case "sql": return ((SqlConnection) con).BeginTransaction(i, tranName); + default: + return null; + } + } + public DbTransaction GetDbBeginTransaction(DbConnection con, string tranName) + { + switch (ConfigSetup.Database.ToLowerInvariant()) + { + case "oledb": return ((OleDbConnection) con).BeginTransaction(); + case "sql": return ((SqlConnection) con).BeginTransaction(tranName); + default: + return null; + } + } + public void RollbackTransaction(DbTransaction transaction, string tranName) + { + switch (ConfigSetup.Database.ToLowerInvariant()) + { + case "oledb": + ((OleDbTransaction) transaction).Rollback(); + break; + case "sql": + ((SqlTransaction) transaction).Rollback(tranName); + break; + } + } + + public void SaveTransaction(DbTransaction transaction, string tranName) + { + switch (ConfigSetup.Database.ToLowerInvariant()) + { + case "sql": + ((SqlTransaction) transaction).Save(tranName); + break; + } + } + + public DbParameter CreateDbParameter(string parameterName, string dbType) + { + switch (ConfigSetup.Database.ToLowerInvariant()) + { + case "oledb": + return new OleDbParameter + { + ParameterName = parameterName, + OleDbType = PrepareExecBinding.GetOleDbType(dbType), + }; + case "sql": + return new SqlParameter + { + ParameterName = parameterName, + SqlDbType = PrepareExecBinding.GetSqlDbType(dbType) + }; + default: + return null; + } + } + + /* Read Queries from file */ + public string[] ReadFile(string queryFilePath) + { + try + { + return File.ReadAllLines(queryFilePath); + } + catch (Exception e) + { + Console.WriteLine("No such file: " + e); + Console.WriteLine(queryFilePath); + return null; + } + } + } +} diff --git a/contrib/test/dotnet/utils/devanagari.txt b/contrib/test/dotnet/utils/devanagari.txt new file mode 100644 index 00000000000..45f37b695da --- /dev/null +++ b/contrib/test/dotnet/utils/devanagari.txt @@ -0,0 +1 @@ +ऀँंःऄअआइईउऊऋऌऍऎएऐऑऒओऔकखगघङचछजझञटठडढणतथदधनऩपफबभमयरऱलळऴवशषसहऺऻ़ऽािीुूृॄॅॆेैॉॊोौ्ॎॏॐ॒॑॓॔ॕॖॗक़ख़ग़ज़ड़ढ़फ़य़ॠॡॢॣ।॥०१२३४५६७८९॰ॱॲॳॴॵॶॷॹॺॻॼॽॾॿ \ No newline at end of file diff --git a/contrib/test/dotnet/utils/emojisText.txt b/contrib/test/dotnet/utils/emojisText.txt new file mode 100644 index 00000000000..117dfc03289 --- /dev/null +++ b/contrib/test/dotnet/utils/emojisText.txt @@ -0,0 +1 @@ +😀😃😁😎😒😞😍🙂😆😊😉 \ No newline at end of file diff --git a/contrib/test/dotnet/utils/sample.txt b/contrib/test/dotnet/utils/sample.txt new file mode 100644 index 00000000000..352a3fb9297 --- /dev/null +++ b/contrib/test/dotnet/utils/sample.txt @@ -0,0 +1,6 @@ +AAAAAAAAAAAAAAAAAAAA +BBBBBBBBBB +CCCCC +badksjvbajsdcbvjads +sejvhsdbfjhcgvasdhgcvsj +21639812365091264 \ No newline at end of file diff --git a/contrib/test/dotnet/utils/utf16.txt b/contrib/test/dotnet/utils/utf16.txt new file mode 100644 index 00000000000..ee839d6a00c --- /dev/null +++ b/contrib/test/dotnet/utils/utf16.txt @@ -0,0 +1 @@ + !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƻƼƽƾƿǀǁǂǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴǵǶǷǸǹǺǻǼǽǾǿȀȁȂȃȄȅȆȇȈȉȊȋȌȍȎȏȐȑȒȓȔȕȖȗȘșȚțȜȝȞȟȠȡȢȣȤȥȦȧȨȩȪȫȬȭȮȯȰȱȲȳȴȵȶȷȸȹȺȻȼȽȾȿɀɁɂɃɄɅɆɇɈɉɊɋɌɍɎɏɐɑɒɓɔɕɖɗɘəɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯʰʱʲʳʴʵʶʷʸʹʺʻʼʽʾʿˀˁ˂˃˄˅ˆˇˈˉˊˋˌˍˎˏːˑ˒˓˔˕˖˗˘˙˚˛˜˝˞˟ˠˡˢˣˤ˥˦˧˨˩˪˫ˬ˭ˮ˯˰˱˲˳˴˵˶˷˸˹˺˻˼˽˾˿̴̵̶̷̸̡̢̧̨̛̖̗̘̙̜̝̞̟̠̣̤̥̦̩̪̫̬̭̮̯̰̱̲̳̹̺̻̼͇͈͉͍͎̀́̂̃̄̅̆̇̈̉̊̋̌̍̎̏̐̑̒̓̔̽̾̿̀́͂̓̈́͆͊͋͌̕̚ͅ͏͓͔͕͖͙͚͐͑͒͗͛ͣͤͥͦͧͨͩͪͫͬͭͮͯ͘͜͟͢͝͞͠͡ͰͱͲͳʹ͵Ͷͷͺͻͼͽ;΄΅Ά·ΈΉΊΌΎΏΐΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩΪΫάέήίΰαβγδεζηθικλμνξοπρςστυφχψωϊϋόύώϏϐϑϒϓϔϕϖϗϘϙϚϛϜϝϞϟϠϡϢϣϤϥϦϧϨϩϪϫϬϭϮϯϰϱϲϳϴϵ϶ϷϸϹϺϻϼϽϾϿЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяѐёђѓєѕіїјљњћќѝўџѠѡѢѣѤѥѦѧѨѩѪѫѬѭѮѯѰѱѲѳѴѵѶѷѸѹѺѻѼѽѾѿҀҁ҂҃҄҅҆҇҈҉ҊҋҌҍҎҏҐґҒғҔҕҖҗҘҙҚқҜҝҞҟҠҡҢңҤҥҦҧҨҩҪҫҬҭҮүҰұҲҳҴҵҶҷҸҹҺһҼҽҾҿӀӁӂӃӄӅӆӇӈӉӊӋӌӍӎӏӐӑӒӓӔӕӖӗӘәӚӛӜӝӞӟӠӡӢӣӤӥӦӧӨөӪӫӬӭӮӯӰӱӲӳӴӵӶӷӸӹӺӻӼӽӾӿԀԁԂԃԄԅԆԇԈԉԊԋԌԍԎԏԐԑԒԓԔԕԖԗԘԙԚԛԜԝԞԟԠԡԢԣԤԥԦԧԱԲԳԴԵԶԷԸԹԺԻԼԽԾԿՀՁՂՃՄՅՆՇՈՉՊՋՌՍՎՏՐՑՒՓՔՕՖՙ՚՛՜՝՞՟աբգդեզէըթժիլխծկհձղճմյնշոչպջռսվտրցւփքօֆև։֊֏ְֱֲֳִֵֶַָֹֺֻּֽ֑֖֛֢֣֤֥֦֧֪֚֭֮֒֓֔֕֗֘֙֜֝֞֟֠֡֨֩֫֬֯־ֿ׀ׁׂ׃ׅׄ׆ׇאבגדהוזחטיךכלםמןנסעףפץצקרשתװױײ׳״؀؁؂؃؄؆؇؈؉؊؋،؍؎؏ؘؙؚؐؑؒؓؔؕؖؗ؛؞؟ؠءآأؤإئابةتثجحخدذرزسشصضطظعغػؼؽؾؿـفقكلمنهوىيًٌٍَُِّْٕٖٜٟٓٔٗ٘ٙٚٛٝٞ٠١٢٣٤٥٦٧٨٩٪٫٬٭ٮٯٰٱٲٳٴٵٶٷٸٹٺٻټٽپٿڀځڂڃڄڅچڇڈډڊڋڌڍڎڏڐڑڒړڔڕږڗژڙښڛڜڝڞڟڠڡڢڣڤڥڦڧڨکڪګڬڭڮگڰڱڲڳڴڵڶڷڸڹںڻڼڽھڿۀہۂۃۄۅۆۇۈۉۊۋیۍێۏېۑےۓ۔ەۖۗۘۙۚۛۜ۝۞ۣ۟۠ۡۢۤۥۦۧۨ۩۪ۭ۫۬ۮۯ۰۱۲۳۴۵۶۷۸۹ۺۻۼ۽۾ۿ܀܁܂܃܄܅܆܇܈܉܊܋܌܍܏ܐܑܒܓܔܕܖܗܘܙܚܛܜܝܞܟܠܡܢܣܤܥܦܧܨܩܪܫܬܭܮܯܱܴܷܸܹܻܼܾ݂݄݆݈ܰܲܳܵܶܺܽܿ݀݁݃݅݇݉݊ݍݎݏݐݑݒݓݔݕݖݗݘݙݚݛݜݝݞݟݠݡݢݣݤݥݦݧݨݩݪݫݬݭݮݯݰݱݲݳݴݵݶݷݸݹݺݻݼݽݾݿހށނރބޅކއވމފދތލގޏސޑޒޓޔޕޖޗޘޙޚޛޜޝޞޟޠޡޢޣޤޥަާިީުޫެޭޮޯްޱ߀߁߂߃߄߅߆߇߈߉ߊߋߌߍߎߏߐߑߒߓߔߕߖߗߘߙߚߛߜߝߞߟߠߡߢߣߤߥߦߧߨߩߪ߲߫߬߭߮߯߰߱߳ߴߵ߶߷߸߹ߺࠀࠁࠂࠃࠄࠅࠆࠇࠈࠉࠊࠋࠌࠍࠎࠏࠐࠑࠒࠓࠔࠕࠖࠗ࠘࠙ࠚࠛࠜࠝࠞࠟࠠࠡࠢࠣࠤࠥࠦࠧࠨࠩࠪࠫࠬ࠭࠰࠱࠲࠳࠴࠵࠶࠷࠸࠹࠺࠻࠼࠽࠾ࡀࡁࡂࡃࡄࡅࡆࡇࡈࡉࡊࡋࡌࡍࡎࡏࡐࡑࡒࡓࡔࡕࡖࡗࡘ࡙࡚࡛࡞ࢠࢢࢣࢤࢥࢦࢧࢨࢩࢪࢫࢬࣰࣱࣲࣦࣩ࣭࣮࣯ࣶࣹࣺࣤࣥࣧࣨ࣪࣫࣬ࣳࣴࣵࣷࣸࣻࣼࣽࣾऀँंःऄअआइईउऊऋऌऍऎएऐऑऒओऔकखगघङचछजझञटठडढणतथदधनऩपफबभमयरऱलळऴवशषसहऺऻ़ऽािीुूृॄॅॆेैॉॊोौ्ॎॏॐ॒॑॓॔ॕॖॗक़ख़ग़ज़ड़ढ़फ़य़ॠॡॢॣ।॥०१२३४५६७८९॰ॱॲॳॴॵॶॷॹॺॻॼॽॾॿঁংঃঅআইঈউঊঋঌএঐওঔকখগঘঙচছজঝঞটঠডঢণতথদধনপফবভমযরলশষসহ়ঽািীুূৃৄেৈোৌ্ৎৗড়ঢ়য়ৠৡৢৣ০১২৩৪৫৬৭৮৯ৰৱ৲৳৴৵৶৷৸৹৺৻ਁਂਃਅਆਇਈਉਊਏਐਓਔਕਖਗਘਙਚਛਜਝਞਟਠਡਢਣਤਥਦਧਨਪਫਬਭਮਯਰਲਲ਼ਵਸ਼ਸਹ਼ਾਿੀੁੂੇੈੋੌ੍ੑਖ਼ਗ਼ਜ਼ੜਫ਼੦੧੨੩੪੫੬੭੮੯ੰੱੲੳੴੵઁંઃઅઆઇઈઉઊઋઌઍએઐઑઓઔકખગઘઙચછજઝઞટઠડઢણતથદધનપફબભમયરલળવશષસહ઼ઽાિીુૂૃૄૅેૈૉોૌ્ૐૠૡૢૣ૦૧૨૩૪૫૬૭૮૯૰૱ଁଂଃଅଆଇଈଉଊଋଌଏଐଓଔକଖଗଘଙଚଛଜଝଞଟଠଡଢଣତଥଦଧନପଫବଭମଯରଲଳଵଶଷସହ଼ଽାିୀୁୂୃୄେୈୋୌ୍ୖୗଡ଼ଢ଼ୟୠୡୢୣ୦୧୨୩୪୫୬୭୮୯୰ୱ୲୳୴୵୶୷ஂஃஅஆஇஈஉஊஎஏஐஒஓஔகஙசஜஞடணதநனபமயரறலளழவஶஷஸஹாிீுூெேைொோௌ்ௐௗ௦௧௨௩௪௫௬௭௮௯௰௱௲௳௴௵௶௷௸௹௺ఁంఃఅఆఇఈఉఊఋఌఎఏఐఒఓఔకఖగఘఙచఛజఝఞటఠడఢణతథదధనపఫబభమయరఱలళవశషసహఽాిీుూృౄెేైొోౌ్ౕౖౘౙౠౡౢౣ౦౧౨౩౪౫౬౭౮౯౸౹౺౻౼౽౾౿ಂಃಅಆಇಈಉಊಋಌಎಏಐಒಓಔಕಖಗಘಙಚಛಜಝಞಟಠಡಢಣತಥದಧನಪಫಬಭಮಯರಱಲಳವಶಷಸಹ಼ಽಾಿೀುೂೃೄೆೇೈೊೋೌ್ೕೖೞೠೡೢೣ೦೧೨೩೪೫೬೭೮೯ೱೲംഃഅആഇഈഉഊഋഌഎഏഐഒഓഔകഖഗഘങചഛജഝഞടഠഡഢണതഥദധനഩപഫബഭമയരറലളഴവശഷസഹഺഽാിീുൂൃൄെേൈൊോൌ്ൎൗൠൡൢൣ൦൧൨൩൪൫൬൭൮൯൰൱൲൳൴൵൹ൺൻർൽൾൿංඃඅආඇඈඉඊඋඌඍඎඏඐඑඒඓඔඕඖකඛගඝඞඟචඡජඣඤඥඦටඨඩඪණඬතථදධනඳපඵබභමඹයරලවශෂසහළෆ්ාැෑිීුූෘෙේෛොෝෞෟෲෳ෴กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำิีึืฺุู฿เแโใไๅๆ็่้๊๋์ํ๎๏๐๑๒๓๔๕๖๗๘๙๚๛ກຂຄງຈຊຍດຕຖທນບປຜຝພຟມຢຣລວສຫອຮຯະັາຳິີຶືຸູົຼຽເແໂໃໄໆ່້໊໋໌ໍ໐໑໒໓໔໕໖໗໘໙ໜໝໞໟༀ༁༂༃༄༅༆༇༈༉༊་༌།༎༏༐༑༒༓༔༕༖༗༘༙༚༛༜༝༞༟༠༡༢༣༤༥༦༧༨༩༪༫༬༭༮༯༰༱༲༳༴༵༶༷༸༹༺༻༼༽༾༿ཀཁགགྷངཅཆཇཉཊཋཌཌྷཎཏཐདདྷནཔཕབབྷམཙཚཛཛྷཝཞཟའཡརལཤཥསཧཨཀྵཪཫཬཱཱཱིིུུྲྀཷླྀཹེཻོཽཾཿ྄ཱྀྀྂྃ྅྆྇ྈྉྊྋྌྍྎྏྐྑྒྒྷྔྕྖྗྙྚྛྜྜྷྞྟྠྡྡྷྣྤྥྦྦྷྨྩྪྫྫྷྭྮྯྰྱྲླྴྵྶྷྸྐྵྺྻྼ྾྿࿀࿁࿂࿃࿄࿅࿆࿇࿈࿉࿊࿋࿌࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚ကခဂဃငစဆဇဈဉညဋဌဍဎဏတထဒဓနပဖဗဘမယရလဝသဟဠအဢဣဤဥဦဧဨဩဪါာိီုူေဲဳဴဵံ့း္်ျြွှဿ၀၁၂၃၄၅၆၇၈၉၊။၌၍၎၏ၐၑၒၓၔၕၖၗၘၙၚၛၜၝၞၟၠၡၢၣၤၥၦၧၨၩၪၫၬၭၮၯၰၱၲၳၴၵၶၷၸၹၺၻၼၽၾၿႀႁႂႃႄႅႆႇႈႉႊႋႌႍႎႏ႐႑႒႓႔႕႖႗႘႙ႚႛႜႝ႞႟ႠႡႢႣႤႥႦႧႨႩႪႫႬႭႮႯႰႱႲႳႴႵႶႷႸႹႺႻႼႽႾႿჀჁჂჃჄჅჇჍაბგდევზთიკლმნოპჟრსტუფქღყშჩცძწჭხჯჰჱჲჳჴჵჶჷჸჹჺ჻ჼჽჾჿᄀᄁᄂᄃᄄᄅᄆᄇᄈᄉᄊᄋᄌᄍᄎᄏᄐᄑᄒᄓᄔᄕᄖᄗᄘᄙᄚᄛᄜᄝᄞᄟᄠᄡᄢᄣᄤᄥᄦᄧᄨᄩᄪᄫᄬᄭᄮᄯᄰᄱᄲᄳᄴᄵᄶᄷᄸᄹᄺᄻᄼᄽᄾᄿᅀᅁᅂᅃᅄᅅᅆᅇᅈᅉᅊᅋᅌᅍᅎᅏᅐᅑᅒᅓᅔᅕᅖᅗᅘᅙᅚᅛᅜᅝᅞᅟᅠᅡᅢᅣᅤᅥᅦᅧᅨᅩᅪᅫᅬᅭᅮᅯᅰᅱᅲᅳᅴᅵᅶᅷᅸᅹᅺᅻᅼᅽᅾᅿᆀᆁᆂᆃᆄᆅᆆᆇᆈᆉᆊᆋᆌᆍᆎᆏᆐᆑᆒᆓᆔᆕᆖᆗᆘᆙᆚᆛᆜᆝᆞᆟᆠᆡᆢᆣᆤᆥᆦᆧᆨᆩᆪᆫᆬᆭᆮᆯᆰᆱᆲᆳᆴᆵᆶᆷᆸᆹᆺᆻᆼᆽᆾᆿᇀᇁᇂᇃᇄᇅᇆᇇᇈᇉᇊᇋᇌᇍᇎᇏᇐᇑᇒᇓᇔᇕᇖᇗᇘᇙᇚᇛᇜᇝᇞᇟᇠᇡᇢᇣᇤᇥᇦᇧᇨᇩᇪᇫᇬᇭᇮᇯᇰᇱᇲᇳᇴᇵᇶᇷᇸᇹᇺᇻᇼᇽᇾᇿሀሁሂሃሄህሆሇለሉሊላሌልሎሏሐሑሒሓሔሕሖሗመሙሚማሜምሞሟሠሡሢሣሤሥሦሧረሩሪራሬርሮሯሰሱሲሳሴስሶሷሸሹሺሻሼሽሾሿቀቁቂቃቄቅቆቇቈቊቋቌቍቐቑቒቓቔቕቖቘቚቛቜቝበቡቢባቤብቦቧቨቩቪቫቬቭቮቯተቱቲታቴትቶቷቸቹቺቻቼችቾቿኀኁኂኃኄኅኆኇኈኊኋኌኍነኑኒናኔንኖኗኘኙኚኛኜኝኞኟአኡኢኣኤእኦኧከኩኪካኬክኮኯኰኲኳኴኵኸኹኺኻኼኽኾዀዂዃዄዅወዉዊዋዌውዎዏዐዑዒዓዔዕዖዘዙዚዛዜዝዞዟዠዡዢዣዤዥዦዧየዩዪያዬይዮዯደዱዲዳዴድዶዷዸዹዺዻዼዽዾዿጀጁጂጃጄጅጆጇገጉጊጋጌግጎጏጐጒጓጔጕጘጙጚጛጜጝጞጟጠጡጢጣጤጥጦጧጨጩጪጫጬጭጮጯጰጱጲጳጴጵጶጷጸጹጺጻጼጽጾጿፀፁፂፃፄፅፆፇፈፉፊፋፌፍፎፏፐፑፒፓፔፕፖፗፘፙፚ፝፞፟፠፡።፣፤፥፦፧፨፩፪፫፬፭፮፯፰፱፲፳፴፵፶፷፸፹፺፻፼ᎀᎁᎂᎃᎄᎅᎆᎇᎈᎉᎊᎋᎌᎍᎎᎏ᎐᎑᎒᎓᎔᎕᎖᎗᎘᎙ᎠᎡᎢᎣᎤᎥᎦᎧᎨᎩᎪᎫᎬᎭᎮᎯᎰᎱᎲᎳᎴᎵᎶᎷᎸᎹᎺᎻᎼᎽᎾᎿᏀᏁᏂᏃᏄᏅᏆᏇᏈᏉᏊᏋᏌᏍᏎᏏᏐᏑᏒᏓᏔᏕᏖᏗᏘᏙᏚᏛᏜᏝᏞᏟᏠᏡᏢᏣᏤᏥᏦᏧᏨᏩᏪᏫᏬᏭᏮᏯᏰᏱᏲᏳᏴ᐀ᐁᐂᐃᐄᐅᐆᐇᐈᐉᐊᐋᐌᐍᐎᐏᐐᐑᐒᐓᐔᐕᐖᐗᐘᐙᐚᐛᐜᐝᐞᐟᐠᐡᐢᐣᐤᐥᐦᐧᐨᐩᐪᐫᐬᐭᐮᐯᐰᐱᐲᐳᐴᐵᐶᐷᐸᐹᐺᐻᐼᐽᐾᐿᑀᑁᑂᑃᑄᑅᑆᑇᑈᑉᑊᑋᑌᑍᑎᑏᑐᑑᑒᑓᑔᑕᑖᑗᑘᑙᑚᑛᑜᑝᑞᑟᑠᑡᑢᑣᑤᑥᑦᑧᑨᑩᑪᑫᑬᑭᑮᑯᑰᑱᑲᑳᑴᑵᑶᑷᑸᑹᑺᑻᑼᑽᑾᑿᒀᒁᒂᒃᒄᒅᒆᒇᒈᒉᒊᒋᒌᒍᒎᒏᒐᒑᒒᒓᒔᒕᒖᒗᒘᒙᒚᒛᒜᒝᒞᒟᒠᒡᒢᒣᒤᒥᒦᒧᒨᒩᒪᒫᒬᒭᒮᒯᒰᒱᒲᒳᒴᒵᒶᒷᒸᒹᒺᒻᒼᒽᒾᒿᓀᓁᓂᓃᓄᓅᓆᓇᓈᓉᓊᓋᓌᓍᓎᓏᓐᓑᓒᓓᓔᓕᓖᓗᓘᓙᓚᓛᓜᓝᓞᓟᓠᓡᓢᓣᓤᓥᓦᓧᓨᓩᓪᓫᓬᓭᓮᓯᓰᓱᓲᓳᓴᓵᓶᓷᓸᓹᓺᓻᓼᓽᓾᓿᔀᔁᔂᔃᔄᔅᔆᔇᔈᔉᔊᔋᔌᔍᔎᔏᔐᔑᔒᔓᔔᔕᔖᔗᔘᔙᔚᔛᔜᔝᔞᔟᔠᔡᔢᔣᔤᔥᔦᔧᔨᔩᔪᔫᔬᔭᔮᔯᔰᔱᔲᔳᔴᔵᔶᔷᔸᔹᔺᔻᔼᔽᔾᔿᕀᕁᕂᕃᕄᕅᕆᕇᕈᕉᕊᕋᕌᕍᕎᕏᕐᕑᕒᕓᕔᕕᕖᕗᕘᕙᕚᕛᕜᕝᕞᕟᕠᕡᕢᕣᕤᕥᕦᕧᕨᕩᕪᕫᕬᕭᕮᕯᕰᕱᕲᕳᕴᕵᕶᕷᕸᕹᕺᕻᕼᕽᕾᕿᖀᖁᖂᖃᖄᖅᖆᖇᖈᖉᖊᖋᖌᖍᖎᖏᖐᖑᖒᖓᖔᖕᖖᖗᖘᖙᖚᖛᖜᖝᖞᖟᖠᖡᖢᖣᖤᖥᖦᖧᖨᖩᖪᖫᖬᖭᖮᖯᖰᖱᖲᖳᖴᖵᖶᖷᖸᖹᖺᖻᖼᖽᖾᖿᗀᗁᗂᗃᗄᗅᗆᗇᗈᗉᗊᗋᗌᗍᗎᗏᗐᗑᗒᗓᗔᗕᗖᗗᗘᗙᗚᗛᗜᗝᗞᗟᗠᗡᗢᗣᗤᗥᗦᗧᗨᗩᗪᗫᗬᗭᗮᗯᗰᗱᗲᗳᗴᗵᗶᗷᗸᗹᗺᗻᗼᗽᗾᗿᘀᘁᘂᘃᘄᘅᘆᘇᘈᘉᘊᘋᘌᘍᘎᘏᘐᘑᘒᘓᘔᘕᘖᘗᘘᘙᘚᘛᘜᘝᘞᘟᘠᘡᘢᘣᘤᘥᘦᘧᘨᘩᘪᘫᘬᘭᘮᘯᘰᘱᘲᘳᘴᘵᘶᘷᘸᘹᘺᘻᘼᘽᘾᘿᙀᙁᙂᙃᙄᙅᙆᙇᙈᙉᙊᙋᙌᙍᙎᙏᙐᙑᙒᙓᙔᙕᙖᙗᙘᙙᙚᙛᙜᙝᙞᙟᙠᙡᙢᙣᙤᙥᙦᙧᙨᙩᙪᙫᙬ᙭᙮ᙯᙰᙱᙲᙳᙴᙵᙶᙷᙸᙹᙺᙻᙼᙽᙾᙿ ᚁᚂᚃᚄᚅᚆᚇᚈᚉᚊᚋᚌᚍᚎᚏᚐᚑᚒᚓᚔᚕᚖᚗᚘᚙᚚ᚛᚜ᚠᚡᚢᚣᚤᚥᚦᚧᚨᚩᚪᚫᚬᚭᚮᚯᚰᚱᚲᚳᚴᚵᚶᚷᚸᚹᚺᚻᚼᚽᚾᚿᛀᛁᛂᛃᛄᛅᛆᛇᛈᛉᛊᛋᛌᛍᛎᛏᛐᛑᛒᛓᛔᛕᛖᛗᛘᛙᛚᛛᛜᛝᛞᛟᛠᛡᛢᛣᛤᛥᛦᛧᛨᛩᛪ᛫᛬᛭ᛮᛯᛰᜀᜁᜂᜃᜄᜅᜆᜇᜈᜉᜊᜋᜌᜎᜏᜐᜑᜒᜓ᜔ᜠᜡᜢᜣᜤᜥᜦᜧᜨᜩᜪᜫᜬᜭᜮᜯᜰᜱᜲᜳ᜴᜵᜶ᝀᝁᝂᝃᝄᝅᝆᝇᝈᝉᝊᝋᝌᝍᝎᝏᝐᝑᝒᝓᝠᝡᝢᝣᝤᝥᝦᝧᝨᝩᝪᝫᝬᝮᝯᝰᝲᝳកខគឃងចឆជឈញដឋឌឍណតថទធនបផពភមយរលវឝឞសហឡអឣឤឥឦឧឨឩឪឫឬឭឮឯឰឱឲឳ឴឵ាិីឹឺុូួើឿៀេែៃោៅំះៈ៉៊់៌៍៎៏័៑្៓។៕៖ៗ៘៙៚៛ៜ៝០១២៣៤៥៦៧៨៩៰៱៲៳៴៵៶៷៸៹᠀᠁᠂᠃᠄᠅᠆᠇᠈᠉᠊᠋᠌᠍᠎᠐᠑᠒᠓᠔᠕᠖᠗᠘᠙ᠠᠡᠢᠣᠤᠥᠦᠧᠨᠩᠪᠫᠬᠭᠮᠯᠰᠱᠲᠳᠴᠵᠶᠷᠸᠹᠺᠻᠼᠽᠾᠿᡀᡁᡂᡃᡄᡅᡆᡇᡈᡉᡊᡋᡌᡍᡎᡏᡐᡑᡒᡓᡔᡕᡖᡗᡘᡙᡚᡛᡜᡝᡞᡟᡠᡡᡢᡣᡤᡥᡦᡧᡨᡩᡪᡫᡬᡭᡮᡯᡰᡱᡲᡳᡴᡵᡶᡷᢀᢁᢂᢃᢄᢅᢆᢇᢈᢉᢊᢋᢌᢍᢎᢏᢐᢑᢒᢓᢔᢕᢖᢗᢘᢙᢚᢛᢜᢝᢞᢟᢠᢡᢢᢣᢤᢥᢦᢧᢨᢩᢪᢰᢱᢲᢳᢴᢵᢶᢷᢸᢹᢺᢻᢼᢽᢾᢿᣀᣁᣂᣃᣄᣅᣆᣇᣈᣉᣊᣋᣌᣍᣎᣏᣐᣑᣒᣓᣔᣕᣖᣗᣘᣙᣚᣛᣜᣝᣞᣟᣠᣡᣢᣣᣤᣥᣦᣧᣨᣩᣪᣫᣬᣭᣮᣯᣰᣱᣲᣳᣴᣵᤀᤁᤂᤃᤄᤅᤆᤇᤈᤉᤊᤋᤌᤍᤎᤏᤐᤑᤒᤓᤔᤕᤖᤗᤘᤙᤚᤛᤜᤠᤡᤢᤣᤤᤥᤦᤧᤨᤩᤪᤫᤰᤱᤲᤳᤴᤵᤶᤷᤸ᤻᤹᤺᥀᥄᥅᥆᥇᥈᥉᥊᥋᥌᥍᥎᥏ᥐᥑᥒᥓᥔᥕᥖᥗᥘᥙᥚᥛᥜᥝᥞᥟᥠᥡᥢᥣᥤᥥᥦᥧᥨᥩᥪᥫᥬᥭᥰᥱᥲᥳᥴᦀᦁᦂᦃᦄᦅᦆᦇᦈᦉᦊᦋᦌᦍᦎᦏᦐᦑᦒᦓᦔᦕᦖᦗᦘᦙᦚᦛᦜᦝᦞᦟᦠᦡᦢᦣᦤᦥᦦᦧᦨᦩᦪᦫᦰᦱᦲᦳᦴᦵᦶᦷᦸᦹᦺᦻᦼᦽᦾᦿᧀᧁᧂᧃᧄᧅᧆᧇᧈᧉ᧐᧑᧒᧓᧔᧕᧖᧗᧘᧙᧚᧞᧟᧠᧡᧢᧣᧤᧥᧦᧧᧨᧩᧪᧫᧬᧭᧮᧯᧰᧱᧲᧳᧴᧵᧶᧷᧸᧹᧺᧻᧼᧽᧾᧿ᨀᨁᨂᨃᨄᨅᨆᨇᨈᨉᨊᨋᨌᨍᨎᨏᨐᨑᨒᨓᨔᨕᨖᨘᨗᨙᨚᨛ᨞᨟ᨠᨡᨢᨣᨤᨥᨦᨧᨨᨩᨪᨫᨬᨭᨮᨯᨰᨱᨲᨳᨴᨵᨶᨷᨸᨹᨺᨻᨼᨽᨾᨿᩀᩁᩂᩃᩄᩅᩆᩇᩈᩉᩊᩋᩌᩍᩎᩏᩐᩑᩒᩓᩔᩕᩖᩗᩘᩙᩚᩛᩜᩝᩞ᩠ᩡᩢᩣᩤᩥᩦᩧᩨᩩᩪᩫᩬᩭᩮᩯᩰᩱᩲᩳᩴ᩿᩵᩶᩷᩸᩹᩺᩻᩼᪀᪁᪂᪃᪄᪅᪆᪇᪈᪉᪐᪑᪒᪓᪔᪕᪖᪗᪘᪙᪠᪡᪢᪣᪤᪥᪦ᪧ᪨᪩᪪᪫᪬᪭ᬀᬁᬂᬃᬄᬅᬆᬇᬈᬉᬊᬋᬌᬍᬎᬏᬐᬑᬒᬓᬔᬕᬖᬗᬘᬙᬚᬛᬜᬝᬞᬟᬠᬡᬢᬣᬤᬥᬦᬧᬨᬩᬪᬫᬬᬭᬮᬯᬰᬱᬲᬳ᬴ᬵᬶᬷᬸᬹᬺᬻᬼᬽᬾᬿᭀᭁᭂᭃ᭄ᭅᭆᭇᭈᭉᭊᭋ᭐᭑᭒᭓᭔᭕᭖᭗᭘᭙᭚᭛᭜᭝᭞᭟᭠᭡᭢᭣᭤᭥᭦᭧᭨᭩᭪᭬᭫᭭᭮᭯᭰᭱᭲᭳᭴᭵᭶᭷᭸᭹᭺᭻᭼ᮀᮁᮂᮃᮄᮅᮆᮇᮈᮉᮊᮋᮌᮍᮎᮏᮐᮑᮒᮓᮔᮕᮖᮗᮘᮙᮚᮛᮜᮝᮞᮟᮠᮡᮢᮣᮤᮥᮦᮧᮨᮩ᮪᮫ᮬᮭᮮᮯ᮰᮱᮲᮳᮴᮵᮶᮷᮸᮹ᮺᮻᮼᮽᮾᮿᯀᯁᯂᯃᯄᯅᯆᯇᯈᯉᯊᯋᯌᯍᯎᯏᯐᯑᯒᯓᯔᯕᯖᯗᯘᯙᯚᯛᯜᯝᯞᯟᯠᯡᯢᯣᯤᯥ᯦ᯧᯨᯩᯪᯫᯬᯭᯮᯯᯰᯱ᯲᯳᯼᯽᯾᯿ᰀᰁᰂᰃᰄᰅᰆᰇᰈᰉᰊᰋᰌᰍᰎᰏᰐᰑᰒᰓᰔᰕᰖᰗᰘᰙᰚᰛᰜᰝᰞᰟᰠᰡᰢᰣᰤᰥᰦᰧᰨᰩᰪᰫᰬᰭᰮᰯᰰᰱᰲᰳᰴᰵᰶ᰷᰻᰼᰽᰾᰿᱀᱁᱂᱃᱄᱅᱆᱇᱈᱉ᱍᱎᱏ᱐᱑᱒᱓᱔᱕᱖᱗᱘᱙ᱚᱛᱜᱝᱞᱟᱠᱡᱢᱣᱤᱥᱦᱧᱨᱩᱪᱫᱬᱭᱮᱯᱰᱱᱲᱳᱴᱵᱶᱷᱸᱹᱺᱻᱼᱽ᱾᱿᳀᳁᳂᳃᳄᳅᳆᳇᳐᳑᳒᳓᳔᳕᳖᳗᳘᳙᳜᳝᳞᳟᳚᳛᳠᳡᳢᳣᳤᳥᳦᳧᳨ᳩᳪᳫᳬ᳭ᳮᳯᳰᳱᳲᳳ᳴ᳵᳶᴀᴁᴂᴃᴄᴅᴆᴇᴈᴉᴊᴋᴌᴍᴎᴏᴐᴑᴒᴓᴔᴕᴖᴗᴘᴙᴚᴛᴜᴝᴞᴟᴠᴡᴢᴣᴤᴥᴦᴧᴨᴩᴪᴫᴬᴭᴮᴯᴰᴱᴲᴳᴴᴵᴶᴷᴸᴹᴺᴻᴼᴽᴾᴿᵀᵁᵂᵃᵄᵅᵆᵇᵈᵉᵊᵋᵌᵍᵎᵏᵐᵑᵒᵓᵔᵕᵖᵗᵘᵙᵚᵛᵜᵝᵞᵟᵠᵡᵢᵣᵤᵥᵦᵧᵨᵩᵪᵫᵬᵭᵮᵯᵰᵱᵲᵳᵴᵵᵶᵷᵸᵹᵺᵻᵼᵽᵾᵿᶀᶁᶂᶃᶄᶅᶆᶇᶈᶉᶊᶋᶌᶍᶎᶏᶐᶑᶒᶓᶔᶕᶖᶗᶘᶙᶚᶛᶜᶝᶞᶟᶠᶡᶢᶣᶤᶥᶦᶧᶨᶩᶪᶫᶬᶭᶮᶯᶰᶱᶲᶳᶴᶵᶶᶷᶸᶹᶺᶻᶼᶽᶾᶿ᷐᷎᷂᷊᷏᷽᷿᷀᷁᷃᷄᷅᷆᷇᷈᷉᷋᷌᷑᷒ᷓᷔᷕᷖᷗᷘᷙᷚᷛᷜᷝᷞᷟᷠᷡᷢᷣᷤᷥᷦ᷾᷼᷍ḀḁḂḃḄḅḆḇḈḉḊḋḌḍḎḏḐḑḒḓḔḕḖḗḘḙḚḛḜḝḞḟḠḡḢḣḤḥḦḧḨḩḪḫḬḭḮḯḰḱḲḳḴḵḶḷḸḹḺḻḼḽḾḿṀṁṂṃṄṅṆṇṈṉṊṋṌṍṎṏṐṑṒṓṔṕṖṗṘṙṚṛṜṝṞṟṠṡṢṣṤṥṦṧṨṩṪṫṬṭṮṯṰṱṲṳṴṵṶṷṸṹṺṻṼṽṾṿẀẁẂẃẄẅẆẇẈẉẊẋẌẍẎẏẐẑẒẓẔẕẖẗẘẙẚẛẜẝẞẟẠạẢảẤấẦầẨẩẪẫẬậẮắẰằẲẳẴẵẶặẸẹẺẻẼẽẾếỀềỂểỄễỆệỈỉỊịỌọỎỏỐốỒồỔổỖỗỘộỚớỜờỞởỠỡỢợỤụỦủỨứỪừỬửỮữỰựỲỳỴỵỶỷỸỹỺỻỼỽỾỿἀἁἂἃἄἅἆἇἈἉἊἋἌἍἎἏἐἑἒἓἔἕἘἙἚἛἜἝἠἡἢἣἤἥἦἧἨἩἪἫἬἭἮἯἰἱἲἳἴἵἶἷἸἹἺἻἼἽἾἿὀὁὂὃὄὅὈὉὊὋὌὍὐὑὒὓὔὕὖὗὙὛὝὟὠὡὢὣὤὥὦὧὨὩὪὫὬὭὮὯὰάὲέὴήὶίὸόὺύὼώᾀᾁᾂᾃᾄᾅᾆᾇᾈᾉᾊᾋᾌᾍᾎᾏᾐᾑᾒᾓᾔᾕᾖᾗᾘᾙᾚᾛᾜᾝᾞᾟᾠᾡᾢᾣᾤᾥᾦᾧᾨᾩᾪᾫᾬᾭᾮᾯᾰᾱᾲᾳᾴᾶᾷᾸᾹᾺΆᾼ᾽ι᾿῀῁ῂῃῄῆῇῈΈῊΉῌ῍῎῏ῐῑῒΐῖῗῘῙῚΊ῝῞῟ῠῡῢΰῤῥῦῧῨῩῪΎῬ῭΅`ῲῳῴῶῷῸΌῺΏῼ´῾           ​‌‍‎‏‐‑‒–—―‖‗‘’‚‛“”„‟†‡•‣․‥…‧

‪‭‮ ‰‱′″‴‵‶‷‸‹›※‼‽‾‿⁀⁁⁂⁃⁄⁅⁆⁇⁈⁉⁊⁋⁌⁍⁎⁏⁐⁑⁒⁓⁔⁕⁖⁗⁘⁙⁚⁛⁜⁝⁞ ⁠⁡⁢⁣⁤⁰ⁱ⁴⁵⁶⁷⁸⁹⁺⁻⁼⁽⁾ⁿ₀₁₂₃₄₅₆₇₈₉₊₋₌₍₎ₐₑₒₓₔₕₖₗₘₙₚₛₜ₠₡₢₣₤₥₦₧₨₩₪₫€₭₮₯₰₱₲₳₴₵₶₷₸₹₺₻₼₽₾₿⃒⃓⃘⃙⃚⃐⃑⃔⃕⃖⃗⃛⃜⃝⃞⃟⃠⃡⃢⃣⃤⃥⃦⃪⃫⃨⃬⃭⃮⃯⃧⃩⃰℀℁ℂ℃℄℅℆ℇ℈℉ℊℋℌℍℎℏℐℑℒℓ℔ℕ№℗℘ℙℚℛℜℝ℞℟℠℡™℣ℤ℥Ω℧ℨ℩KÅℬℭ℮ℯℰℱℲℳℴℵℶℷℸℹ℺℻ℼℽℾℿ⅀⅁⅂⅃⅄ⅅⅆⅇⅈⅉ⅊⅋⅌⅍ⅎ⅏⅐⅑⅒⅓⅔⅕⅖⅗⅘⅙⅚⅛⅜⅝⅞⅟ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫⅬⅭⅮⅯⅰⅱⅲⅳⅴⅵⅶⅷⅸⅹⅺⅻⅼⅽⅾⅿↀↁↂↃↄↅↆↇↈ↉←↑→↓↔↕↖↗↘↙↚↛↜↝↞↟↠↡↢↣↤↥↦↧↨↩↪↫↬↭↮↯↰↱↲↳↴↵↶↷↸↹↺↻↼↽↾↿⇀⇁⇂⇃⇄⇅⇆⇇⇈⇉⇊⇋⇌⇍⇎⇏⇐⇑⇒⇓⇔⇕⇖⇗⇘⇙⇚⇛⇜⇝⇞⇟⇠⇡⇢⇣⇤⇥⇦⇧⇨⇩⇪⇫⇬⇭⇮⇯⇰⇱⇲⇳⇴⇵⇶⇷⇸⇹⇺⇻⇼⇽⇾⇿∀∁∂∃∄∅∆∇∈∉∊∋∌∍∎∏∐∑−∓∔∕∖∗∘∙√∛∜∝∞∟∠∡∢∣∤∥∦∧∨∩∪∫∬∭∮∯∰∱∲∳∴∵∶∷∸∹∺∻∼∽∾∿≀≁≂≃≄≅≆≇≈≉≊≋≌≍≎≏≐≑≒≓≔≕≖≗≘≙≚≛≜≝≞≟≠≡≢≣≤≥≦≧≨≩≪≫≬≭≮≯≰≱≲≳≴≵≶≷≸≹≺≻≼≽≾≿⊀⊁⊂⊃⊄⊅⊆⊇⊈⊉⊊⊋⊌⊍⊎⊏⊐⊑⊒⊓⊔⊕⊖⊗⊘⊙⊚⊛⊜⊝⊞⊟⊠⊡⊢⊣⊤⊥⊦⊧⊨⊩⊪⊫⊬⊭⊮⊯⊰⊱⊲⊳⊴⊵⊶⊷⊸⊹⊺⊻⊼⊽⊾⊿⋀⋁⋂⋃⋄⋅⋆⋇⋈⋉⋊⋋⋌⋍⋎⋏⋐⋑⋒⋓⋔⋕⋖⋗⋘⋙⋚⋛⋜⋝⋞⋟⋠⋡⋢⋣⋤⋥⋦⋧⋨⋩⋪⋫⋬⋭⋮⋯⋰⋱⋲⋳⋴⋵⋶⋷⋸⋹⋺⋻⋼⋽⋾⋿⌀⌁⌂⌃⌄⌅⌆⌇⌈⌉⌊⌋⌌⌍⌎⌏⌐⌑⌒⌓⌔⌕⌖⌗⌘⌙⌚⌛⌜⌝⌞⌟⌠⌡⌢⌣⌤⌥⌦⌧⌨〈〉⌫⌬⌭⌮⌯⌰⌱⌲⌳⌴⌵⌶⌷⌸⌹⌺⌻⌼⌽⌾⌿⍀⍁⍂⍃⍄⍅⍆⍇⍈⍉⍊⍋⍌⍍⍎⍏⍐⍑⍒⍓⍔⍕⍖⍗⍘⍙⍚⍛⍜⍝⍞⍟⍠⍡⍢⍣⍤⍥⍦⍧⍨⍩⍪⍫⍬⍭⍮⍯⍰⍱⍲⍳⍴⍵⍶⍷⍸⍹⍺⍻⍼⍽⍾⍿⎀⎁⎂⎃⎄⎅⎆⎇⎈⎉⎊⎋⎌⎍⎎⎏⎐⎑⎒⎓⎔⎕⎖⎗⎘⎙⎚⎛⎜⎝⎞⎟⎠⎡⎢⎣⎤⎥⎦⎧⎨⎩⎪⎫⎬⎭⎮⎯⎰⎱⎲⎳⎴⎵⎶⎷⎸⎹⎺⎻⎼⎽⎾⎿⏀⏁⏂⏃⏄⏅⏆⏇⏈⏉⏊⏋⏌⏍⏎⏏⏐⏑⏒⏓⏔⏕⏖⏗⏘⏙⏚⏛⏜⏝⏞⏟⏠⏡⏢⏣⏤⏥⏦⏧⏨⏩⏪⏫⏬⏭⏮⏯⏰⏱⏲⏳␀␁␂␃␄␅␆␇␈␉␊␋␌␍␎␏␐␑␒␓␔␕␖␗␘␙␚␛␜␝␞␟␠␡␢␣␤␥␦⑀⑁⑂⑃⑄⑅⑆⑇⑈⑉⑊①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳⑴⑵⑶⑷⑸⑹⑺⑻⑼⑽⑾⑿⒀⒁⒂⒃⒄⒅⒆⒇⒈⒉⒊⒋⒌⒍⒎⒏⒐⒑⒒⒓⒔⒕⒖⒗⒘⒙⒚⒛⒜⒝⒞⒟⒠⒡⒢⒣⒤⒥⒦⒧⒨⒩⒪⒫⒬⒭⒮⒯⒰⒱⒲⒳⒴⒵ⒶⒷⒸⒹⒺⒻⒼⒽⒾⒿⓀⓁⓂⓃⓄⓅⓆⓇⓈⓉⓊⓋⓌⓍⓎⓏⓐⓑⓒⓓⓔⓕⓖⓗⓘⓙⓚⓛⓜⓝⓞⓟⓠⓡⓢⓣⓤⓥⓦⓧⓨⓩ⓪⓫⓬⓭⓮⓯⓰⓱⓲⓳⓴⓵⓶⓷⓸⓹⓺⓻⓼⓽⓾⓿─━│┃┄┅┆┇┈┉┊┋┌┍┎┏┐┑┒┓└┕┖┗┘┙┚┛├┝┞┟┠┡┢┣┤┥┦┧┨┩┪┫┬┭┮┯┰┱┲┳┴┵┶┷┸┹┺┻┼┽┾┿╀╁╂╃╄╅╆╇╈╉╊╋╌╍╎╏═║╒╓╔╕╖╗╘╙╚╛╜╝╞╟╠╡╢╣╤╥╦╧╨╩╪╫╬╭╮╯╰╱╲╳╴╵╶╷╸╹╺╻╼╽╾╿▀▁▂▃▄▅▆▇█▉▊▋▌▍▎▏▐░▒▓▔▕▖▗▘▙▚▛▜▝▞▟■□▢▣▤▥▦▧▨▩▪▫▬▭▮▯▰▱▲△▴▵▶▷▸▹►▻▼▽▾▿◀◁◂◃◄◅◆◇◈◉◊○◌◍◎●◐◑◒◓◔◕◖◗◘◙◚◛◜◝◞◟◠◡◢◣◤◥◦◧◨◩◪◫◬◭◮◯◰◱◲◳◴◵◶◷◸◹◺◻◼◽◾◿☀☁☂☃☄★☆☇☈☉☊☋☌☍☎☏☐☑☒☓☔☕☖☗☘☙☚☛☜☝☞☟☠☡☢☣☤☥☦☧☨☩☪☫☬☭☮☯☰☱☲☳☴☵☶☷☸☹☺☻☼☽☾☿♀♁♂♃♄♅♆♇♈♉♊♋♌♍♎♏♐♑♒♓♔♕♖♗♘♙♚♛♜♝♞♟♠♡♢♣♤♥♦♧♨♩♪♫♬♭♮♯♰♱♲♳♴♵♶♷♸♹♺♻♼♽♾♿⚀⚁⚂⚃⚄⚅⚆⚇⚈⚉⚊⚋⚌⚍⚎⚏⚐⚑⚒⚓⚔⚕⚖⚗⚘⚙⚚⚛⚜⚝⚞⚟⚠⚡⚢⚣⚤⚥⚦⚧⚨⚩⚪⚫⚬⚭⚮⚯⚰⚱⚲⚳⚴⚵⚶⚷⚸⚹⚺⚻⚼⚽⚾⚿⛀⛁⛂⛃⛄⛅⛆⛇⛈⛉⛊⛋⛌⛍⛎⛏⛐⛑⛒⛓⛔⛕⛖⛗⛘⛙⛚⛛⛜⛝⛞⛟⛠⛡⛢⛣⛤⛥⛦⛧⛨⛩⛪⛫⛬⛭⛮⛯⛰⛱⛲⛳⛴⛵⛶⛷⛸⛹⛺⛻⛼⛽⛾⛿✁✂✃✄✅✆✇✈✉✊✋✌✍✎✏✐✑✒✓✔✕✖✗✘✙✚✛✜✝✞✟✠✡✢✣✤✥✦✧✨✩✪✫✬✭✮✯✰✱✲✳✴✵✶✷✸✹✺✻✼✽✾✿❀❁❂❃❄❅❆❇❈❉❊❋❌❍❎❏❐❑❒❓❔❕❖❗❘❙❚❛❜❝❞❟❠❡❢❣❤❥❦❧❨❩❪❫❬❭❮❯❰❱❲❳❴❵❶❷❸❹❺❻❼❽❾❿➀➁➂➃➄➅➆➇➈➉➊➋➌➍➎➏➐➑➒➓➔➕➖➗➘➙➚➛➜➝➞➟➠➡➢➣➤➥➦➧➨➩➪➫➬➭➮➯➰➱➲➳➴➵➶➷➸➹➺➻➼➽➾➿⟀⟁⟂⟃⟄⟅⟆⟇⟈⟉⟊⟋⟌⟍⟎⟏⟐⟑⟒⟓⟔⟕⟖⟗⟘⟙⟚⟛⟜⟝⟞⟟⟠⟡⟢⟣⟤⟥⟦⟧⟨⟩⟪⟫⟬⟭⟮⟯⟰⟱⟲⟳⟴⟵⟶⟷⟸⟹⟺⟻⟼⟽⟾⟿⠀⠁⠂⠃⠄⠅⠆⠇⠈⠉⠊⠋⠌⠍⠎⠏⠐⠑⠒⠓⠔⠕⠖⠗⠘⠙⠚⠛⠜⠝⠞⠟⠠⠡⠢⠣⠤⠥⠦⠧⠨⠩⠪⠫⠬⠭⠮⠯⠰⠱⠲⠳⠴⠵⠶⠷⠸⠹⠺⠻⠼⠽⠾⠿⡀⡁⡂⡃⡄⡅⡆⡇⡈⡉⡊⡋⡌⡍⡎⡏⡐⡑⡒⡓⡔⡕⡖⡗⡘⡙⡚⡛⡜⡝⡞⡟⡠⡡⡢⡣⡤⡥⡦⡧⡨⡩⡪⡫⡬⡭⡮⡯⡰⡱⡲⡳⡴⡵⡶⡷⡸⡹⡺⡻⡼⡽⡾⡿⢀⢁⢂⢃⢄⢅⢆⢇⢈⢉⢊⢋⢌⢍⢎⢏⢐⢑⢒⢓⢔⢕⢖⢗⢘⢙⢚⢛⢜⢝⢞⢟⢠⢡⢢⢣⢤⢥⢦⢧⢨⢩⢪⢫⢬⢭⢮⢯⢰⢱⢲⢳⢴⢵⢶⢷⢸⢹⢺⢻⢼⢽⢾⢿⣀⣁⣂⣃⣄⣅⣆⣇⣈⣉⣊⣋⣌⣍⣎⣏⣐⣑⣒⣓⣔⣕⣖⣗⣘⣙⣚⣛⣜⣝⣞⣟⣠⣡⣢⣣⣤⣥⣦⣧⣨⣩⣪⣫⣬⣭⣮⣯⣰⣱⣲⣳⣴⣵⣶⣷⣸⣹⣺⣻⣼⣽⣾⣿⤀⤁⤂⤃⤄⤅⤆⤇⤈⤉⤊⤋⤌⤍⤎⤏⤐⤑⤒⤓⤔⤕⤖⤗⤘⤙⤚⤛⤜⤝⤞⤟⤠⤡⤢⤣⤤⤥⤦⤧⤨⤩⤪⤫⤬⤭⤮⤯⤰⤱⤲⤳⤴⤵⤶⤷⤸⤹⤺⤻⤼⤽⤾⤿⥀⥁⥂⥃⥄⥅⥆⥇⥈⥉⥊⥋⥌⥍⥎⥏⥐⥑⥒⥓⥔⥕⥖⥗⥘⥙⥚⥛⥜⥝⥞⥟⥠⥡⥢⥣⥤⥥⥦⥧⥨⥩⥪⥫⥬⥭⥮⥯⥰⥱⥲⥳⥴⥵⥶⥷⥸⥹⥺⥻⥼⥽⥾⥿⦀⦁⦂⦃⦄⦅⦆⦇⦈⦉⦊⦋⦌⦍⦎⦏⦐⦑⦒⦓⦔⦕⦖⦗⦘⦙⦚⦛⦜⦝⦞⦟⦠⦡⦢⦣⦤⦥⦦⦧⦨⦩⦪⦫⦬⦭⦮⦯⦰⦱⦲⦳⦴⦵⦶⦷⦸⦹⦺⦻⦼⦽⦾⦿⧀⧁⧂⧃⧄⧅⧆⧇⧈⧉⧊⧋⧌⧍⧎⧏⧐⧑⧒⧓⧔⧕⧖⧗⧘⧙⧚⧛⧜⧝⧞⧟⧠⧡⧢⧣⧤⧥⧦⧧⧨⧩⧪⧫⧬⧭⧮⧯⧰⧱⧲⧳⧴⧵⧶⧷⧸⧹⧺⧻⧼⧽⧾⧿⨀⨁⨂⨃⨄⨅⨆⨇⨈⨉⨊⨋⨌⨍⨎⨏⨐⨑⨒⨓⨔⨕⨖⨗⨘⨙⨚⨛⨜⨝⨞⨟⨠⨡⨢⨣⨤⨥⨦⨧⨨⨩⨪⨫⨬⨭⨮⨯⨰⨱⨲⨳⨴⨵⨶⨷⨸⨹⨺⨻⨼⨽⨾⨿⩀⩁⩂⩃⩄⩅⩆⩇⩈⩉⩊⩋⩌⩍⩎⩏⩐⩑⩒⩓⩔⩕⩖⩗⩘⩙⩚⩛⩜⩝⩞⩟⩠⩡⩢⩣⩤⩥⩦⩧⩨⩩⩪⩫⩬⩭⩮⩯⩰⩱⩲⩳⩴⩵⩶⩷⩸⩹⩺⩻⩼⩽⩾⩿⪀⪁⪂⪃⪄⪅⪆⪇⪈⪉⪊⪋⪌⪍⪎⪏⪐⪑⪒⪓⪔⪕⪖⪗⪘⪙⪚⪛⪜⪝⪞⪟⪠⪡⪢⪣⪤⪥⪦⪧⪨⪩⪪⪫⪬⪭⪮⪯⪰⪱⪲⪳⪴⪵⪶⪷⪸⪹⪺⪻⪼⪽⪾⪿⫀⫁⫂⫃⫄⫅⫆⫇⫈⫉⫊⫋⫌⫍⫎⫏⫐⫑⫒⫓⫔⫕⫖⫗⫘⫙⫚⫛⫝̸⫝⫞⫟⫠⫡⫢⫣⫤⫥⫦⫧⫨⫩⫪⫫⫬⫭⫮⫯⫰⫱⫲⫳⫴⫵⫶⫷⫸⫹⫺⫻⫼⫽⫾⫿⬀⬁⬂⬃⬄⬅⬆⬇⬈⬉⬊⬋⬌⬍⬎⬏⬐⬑⬒⬓⬔⬕⬖⬗⬘⬙⬚⬛⬜⬝⬞⬟⬠⬡⬢⬣⬤⬥⬦⬧⬨⬩⬪⬫⬬⬭⬮⬯⬰⬱⬲⬳⬴⬵⬶⬷⬸⬹⬺⬻⬼⬽⬾⬿⭀⭁⭂⭃⭄⭅⭆⭇⭈⭉⭊⭋⭌⭐⭑⭒⭓⭔⭕⭖⭗⭘⭙ⰀⰁⰂⰃⰄⰅⰆⰇⰈⰉⰊⰋⰌⰍⰎⰏⰐⰑⰒⰓⰔⰕⰖⰗⰘⰙⰚⰛⰜⰝⰞⰟⰠⰡⰢⰣⰤⰥⰦⰧⰨⰩⰪⰫⰬⰭⰮⰰⰱⰲⰳⰴⰵⰶⰷⰸⰹⰺⰻⰼⰽⰾⰿⱀⱁⱂⱃⱄⱅⱆⱇⱈⱉⱊⱋⱌⱍⱎⱏⱐⱑⱒⱓⱔⱕⱖⱗⱘⱙⱚⱛⱜⱝⱞⱠⱡⱢⱣⱤⱥⱦⱧⱨⱩⱪⱫⱬⱭⱮⱯⱰⱱⱲⱳⱴⱵⱶⱷⱸⱹⱺⱻⱼⱽⱾⱿⲀⲁⲂⲃⲄⲅⲆⲇⲈⲉⲊⲋⲌⲍⲎⲏⲐⲑⲒⲓⲔⲕⲖⲗⲘⲙⲚⲛⲜⲝⲞⲟⲠⲡⲢⲣⲤⲥⲦⲧⲨⲩⲪⲫⲬⲭⲮⲯⲰⲱⲲⲳⲴⲵⲶⲷⲸⲹⲺⲻⲼⲽⲾⲿⳀⳁⳂⳃⳄⳅⳆⳇⳈⳉⳊⳋⳌⳍⳎⳏⳐⳑⳒⳓⳔⳕⳖⳗⳘⳙⳚⳛⳜⳝⳞⳟⳠⳡⳢⳣⳤ⳥⳦⳧⳨⳩⳪ⳫⳬⳭⳮ⳯⳰⳱Ⳳⳳ⳹⳺⳻⳼⳽⳾⳿ⴀⴁⴂⴃⴄⴅⴆⴇⴈⴉⴊⴋⴌⴍⴎⴏⴐⴑⴒⴓⴔⴕⴖⴗⴘⴙⴚⴛⴜⴝⴞⴟⴠⴡⴢⴣⴤⴥⴧⴭⴰⴱⴲⴳⴴⴵⴶⴷⴸⴹⴺⴻⴼⴽⴾⴿⵀⵁⵂⵃⵄⵅⵆⵇⵈⵉⵊⵋⵌⵍⵎⵏⵐⵑⵒⵓⵔⵕⵖⵗⵘⵙⵚⵛⵜⵝⵞⵟⵠⵡⵢⵣⵤⵥⵦⵧⵯ⵰⵿ⶀⶁⶂⶃⶄⶅⶆⶇⶈⶉⶊⶋⶌⶍⶎⶏⶐⶑⶒⶓⶔⶕⶖⶠⶡⶢⶣⶤⶥⶦⶨⶩⶪⶫⶬⶭⶮⶰⶱⶲⶳⶴⶵⶶⶸⶹⶺⶻⶼⶽⶾⷀⷁⷂⷃⷄⷅⷆⷈⷉⷊⷋⷌⷍⷎⷐⷑⷒⷓⷔⷕⷖⷘⷙⷚⷛⷜⷝⷞⷠⷡⷢⷣⷤⷥⷦⷧⷨⷩⷪⷫⷬⷭⷮⷯⷰⷱⷲⷳⷴⷵⷶⷷⷸⷹⷺⷻⷼⷽⷾⷿ⸀⸁⸂⸃⸄⸅⸆⸇⸈⸉⸊⸋⸌⸍⸎⸏⸐⸑⸒⸓⸔⸕⸖⸗⸘⸙⸚⸛⸜⸝⸞⸟⸠⸡⸢⸣⸤⸥⸦⸧⸨⸩⸪⸫⸬⸭⸮ⸯ⸰⸱⸲⸳⸴⸵⸶⸷⸸⸹⸺⸻⺀⺁⺂⺃⺄⺅⺆⺇⺈⺉⺊⺋⺌⺍⺎⺏⺐⺑⺒⺓⺔⺕⺖⺗⺘⺙⺛⺜⺝⺞⺟⺠⺡⺢⺣⺤⺥⺦⺧⺨⺩⺪⺫⺬⺭⺮⺯⺰⺱⺲⺳⺴⺵⺶⺷⺸⺹⺺⺻⺼⺽⺾⺿⻀⻁⻂⻃⻄⻅⻆⻇⻈⻉⻊⻋⻌⻍⻎⻏⻐⻑⻒⻓⻔⻕⻖⻗⻘⻙⻚⻛⻜⻝⻞⻟⻠⻡⻢⻣⻤⻥⻦⻧⻨⻩⻪⻫⻬⻭⻮⻯⻰⻱⻲⻳⼀⼁⼂⼃⼄⼅⼆⼇⼈⼉⼊⼋⼌⼍⼎⼏⼐⼑⼒⼓⼔⼕⼖⼗⼘⼙⼚⼛⼜⼝⼞⼟⼠⼡⼢⼣⼤⼥⼦⼧⼨⼩⼪⼫⼬⼭⼮⼯⼰⼱⼲⼳⼴⼵⼶⼷⼸⼹⼺⼻⼼⼽⼾⼿⽀⽁⽂⽃⽄⽅⽆⽇⽈⽉⽊⽋⽌⽍⽎⽏⽐⽑⽒⽓⽔⽕⽖⽗⽘⽙⽚⽛⽜⽝⽞⽟⽠⽡⽢⽣⽤⽥⽦⽧⽨⽩⽪⽫⽬⽭⽮⽯⽰⽱⽲⽳⽴⽵⽶⽷⽸⽹⽺⽻⽼⽽⽾⽿⾀⾁⾂⾃⾄⾅⾆⾇⾈⾉⾊⾋⾌⾍⾎⾏⾐⾑⾒⾓⾔⾕⾖⾗⾘⾙⾚⾛⾜⾝⾞⾟⾠⾡⾢⾣⾤⾥⾦⾧⾨⾩⾪⾫⾬⾭⾮⾯⾰⾱⾲⾳⾴⾵⾶⾷⾸⾹⾺⾻⾼⾽⾾⾿⿀⿁⿂⿃⿄⿅⿆⿇⿈⿉⿊⿋⿌⿍⿎⿏⿐⿑⿒⿓⿔⿕⿰⿱⿲⿳⿴⿵⿶⿷⿸⿹⿺⿻ 、。〃〄々〆〇〈〉《》「」『』【】〒〓〔〕〖〗〘〙〚〛〜〝〞〟〠〡〢〣〤〥〦〧〨〩〪〭〮〯〫〬〰〱〲〳〴〵〶〷〸〹〺〻〼〽〾〿ぁあぃいぅうぇえぉおかがきぎくぐけげこごさざしじすずせぜそぞただちぢっつづてでとどなにぬねのはばぱひびぴふぶぷへべぺほぼぽまみむめもゃやゅゆょよらりるれろゎわゐゑをんゔゕゖ゙゚゛゜ゝゞゟ゠ァアィイゥウェエォオカガキギクグケゲコゴサザシジスズセゼソゾタダチヂッツヅテデトドナニヌネノハバパヒビピフブプヘベペホボポマミムメモャヤュユョヨラリルレロヮワヰヱヲンヴヵヶヷヸヹヺ・ーヽヾヿㄅㄆㄇㄈㄉㄊㄋㄌㄍㄎㄏㄐㄑㄒㄓㄔㄕㄖㄗㄘㄙㄚㄛㄜㄝㄞㄟㄠㄡㄢㄣㄤㄥㄦㄧㄨㄩㄪㄫㄬㄭㄱㄲㄳㄴㄵㄶㄷㄸㄹㄺㄻㄼㄽㄾㄿㅀㅁㅂㅃㅄㅅㅆㅇㅈㅉㅊㅋㅌㅍㅎㅏㅐㅑㅒㅓㅔㅕㅖㅗㅘㅙㅚㅛㅜㅝㅞㅟㅠㅡㅢㅣㅤㅥㅦㅧㅨㅩㅪㅫㅬㅭㅮㅯㅰㅱㅲㅳㅴㅵㅶㅷㅸㅹㅺㅻㅼㅽㅾㅿㆀㆁㆂㆃㆄㆅㆆㆇㆈㆉㆊㆋㆌㆍㆎ㆐㆑㆒㆓㆔㆕㆖㆗㆘㆙㆚㆛㆜㆝㆞㆟ㆠㆡㆢㆣㆤㆥㆦㆧㆨㆩㆪㆫㆬㆭㆮㆯㆰㆱㆲㆳㆴㆵㆶㆷㆸㆹㆺ㇀㇁㇂㇃㇄㇅㇆㇇㇈㇉㇊㇋㇌㇍㇎㇏㇐㇑㇒㇓㇔㇕㇖㇗㇘㇙㇚㇛㇜㇝㇞㇟㇠㇡㇢㇣ㇰㇱㇲㇳㇴㇵㇶㇷㇸㇹㇺㇻㇼㇽㇾㇿ㈀㈁㈂㈃㈄㈅㈆㈇㈈㈉㈊㈋㈌㈍㈎㈏㈐㈑㈒㈓㈔㈕㈖㈗㈘㈙㈚㈛㈜㈝㈞㈠㈡㈢㈣㈤㈥㈦㈧㈨㈩㈪㈫㈬㈭㈮㈯㈰㈱㈲㈳㈴㈵㈶㈷㈸㈹㈺㈻㈼㈽㈾㈿㉀㉁㉂㉃㉄㉅㉆㉇㉈㉉㉊㉋㉌㉍㉎㉏㉐㉑㉒㉓㉔㉕㉖㉗㉘㉙㉚㉛㉜㉝㉞㉟㉠㉡㉢㉣㉤㉥㉦㉧㉨㉩㉪㉫㉬㉭㉮㉯㉰㉱㉲㉳㉴㉵㉶㉷㉸㉹㉺㉻㉼㉽㉾㉿㊀㊁㊂㊃㊄㊅㊆㊇㊈㊉㊊㊋㊌㊍㊎㊏㊐㊑㊒㊓㊔㊕㊖㊗㊘㊙㊚㊛㊜㊝㊞㊟㊠㊡㊢㊣㊤㊥㊦㊧㊨㊩㊪㊫㊬㊭㊮㊯㊰㊱㊲㊳㊴㊵㊶㊷㊸㊹㊺㊻㊼㊽㊾㊿㋀㋁㋂㋃㋄㋅㋆㋇㋈㋉㋊㋋㋌㋍㋎㋏㋐㋑㋒㋓㋔㋕㋖㋗㋘㋙㋚㋛㋜㋝㋞㋟㋠㋡㋢㋣㋤㋥㋦㋧㋨㋩㋪㋫㋬㋭㋮㋯㋰㋱㋲㋳㋴㋵㋶㋷㋸㋹㋺㋻㋼㋽㋾㋿㌀㌁㌂㌃㌄㌅㌆㌇㌈㌉㌊㌋㌌㌍㌎㌏㌐㌑㌒㌓㌔㌕㌖㌗㌘㌙㌚㌛㌜㌝㌞㌟㌠㌡㌢㌣㌤㌥㌦㌧㌨㌩㌪㌫㌬㌭㌮㌯㌰㌱㌲㌳㌴㌵㌶㌷㌸㌹㌺㌻㌼㌽㌾㌿㍀㍁㍂㍃㍄㍅㍆㍇㍈㍉㍊㍋㍌㍍㍎㍏㍐㍑㍒㍓㍔㍕㍖㍗㍘㍙㍚㍛㍜㍝㍞㍟㍠㍡㍢㍣㍤㍥㍦㍧㍨㍩㍪㍫㍬㍭㍮㍯㍰㍱㍲㍳㍴㍵㍶㍷㍸㍹㍺㍻㍼㍽㍾㍿㎀㎁㎂㎃㎄㎅㎆㎇㎈㎉㎊㎋㎌㎍㎎㎏㎐㎑㎒㎓㎔㎕㎖㎗㎘㎙㎚㎛㎜㎝㎞㎟㎠㎡㎢㎣㎤㎥㎦㎧㎨㎩㎪㎫㎬㎭㎮㎯㎰㎱㎲㎳㎴㎵㎶㎷㎸㎹㎺㎻㎼㎽㎾㎿㏀㏁㏂㏃㏄㏅㏆㏇㏈㏉㏊㏋㏌㏍㏎㏏㏐㏑㏒㏓㏔㏕㏖㏗㏘㏙㏚㏛㏜㏝㏞㏟㏠㏡㏢㏣㏤㏥㏦㏧㏨㏩㏪㏫㏬㏭㏮㏯㏰㏱㏲㏳㏴㏵㏶㏷㏸㏹㏺㏻㏼㏽㏾㏿㐀㐁㐂㐃㐄㐅㐆㐇㐈㐉㐊㐋㐌㐍㐎㐏㐐㐑㐒㐓㐔㐕㐖㐗㐘㐙㐚㐛㐜㐝㐞㐟㐠㐡㐢㐣㐤㐥㐦㐧㐨㐩㐪㐫㐬㐭㐮㐯㐰㐱㐲㐳㐴㐵㐶㐷㐸㐹㐺㐻㐼㐽㐾㐿㑀㑁㑂㑃㑄㑅㑆㑇㑈㑉㑊㑋㑌㑍㑎㑏㑐㑑㑒㑓㑔㑕㑖㑗㑘㑙㑚㑛㑜㑝㑞㑟㑠㑡㑢㑣㑤㑥㑦㑧㑨㑩㑪㑫㑬㑭㑮㑯㑰㑱㑲㑳㑴㑵㑶㑷㑸㑹㑺㑻㑼㑽㑾㑿㒀㒁㒂㒃㒄㒅㒆㒇㒈㒉㒊㒋㒌㒍㒎㒏㒐㒑㒒㒓㒔㒕㒖㒗㒘㒙㒚㒛㒜㒝㒞㒟㒠㒡㒢㒣㒤㒥㒦㒧㒨㒩㒪㒫㒬㒭㒮㒯㒰㒱㒲㒳㒴㒵㒶㒷㒸㒹㒺㒻㒼㒽㒾㒿㓀㓁㓂㓃㓄㓅㓆㓇㓈㓉㓊㓋㓌㓍㓎㓏㓐㓑㓒㓓㓔㓕㓖㓗㓘㓙㓚㓛㓜㓝㓞㓟㓠㓡㓢㓣㓤㓥㓦㓧㓨㓩㓪㓫㓬㓭㓮㓯㓰㓱㓲㓳㓴㓵㓶㓷㓸㓹㓺㓻㓼㓽㓾㓿㔀㔁㔂㔃㔄㔅㔆㔇㔈㔉㔊㔋㔌㔍㔎㔏㔐㔑㔒㔓㔔㔕㔖㔗㔘㔙㔚㔛㔜㔝㔞㔟㔠㔡㔢㔣㔤㔥㔦㔧㔨㔩㔪㔫㔬㔭㔮㔯㔰㔱㔲㔳㔴㔵㔶㔷㔸㔹㔺㔻㔼㔽㔾㔿㕀㕁㕂㕃㕄㕅㕆㕇㕈㕉㕊㕋㕌㕍㕎㕏㕐㕑㕒㕓㕔㕕㕖㕗㕘㕙㕚㕛㕜㕝㕞㕟㕠㕡㕢㕣㕤㕥㕦㕧㕨㕩㕪㕫㕬㕭㕮㕯㕰㕱㕲㕳㕴㕵㕶㕷㕸㕹㕺㕻㕼㕽㕾㕿㖀㖁㖂㖃㖄㖅㖆㖇㖈㖉㖊㖋㖌㖍㖎㖏㖐㖑㖒㖓㖔㖕㖖㖗㖘㖙㖚㖛㖜㖝㖞㖟㖠㖡㖢㖣㖤㖥㖦㖧㖨㖩㖪㖫㖬㖭㖮㖯㖰㖱㖲㖳㖴㖵㖶㖷㖸㖹㖺㖻㖼㖽㖾㖿㗀㗁㗂㗃㗄㗅㗆㗇㗈㗉㗊㗋㗌㗍㗎㗏㗐㗑㗒㗓㗔㗕㗖㗗㗘㗙㗚㗛㗜㗝㗞㗟㗠㗡㗢㗣㗤㗥㗦㗧㗨㗩㗪㗫㗬㗭㗮㗯㗰㗱㗲㗳㗴㗵㗶㗷㗸㗹㗺㗻㗼㗽㗾㗿㘀㘁㘂㘃㘄㘅㘆㘇㘈㘉㘊㘋㘌㘍㘎㘏㘐㘑㘒㘓㘔㘕㘖㘗㘘㘙㘚㘛㘜㘝㘞㘟㘠㘡㘢㘣㘤㘥㘦㘧㘨㘩㘪㘫㘬㘭㘮㘯㘰㘱㘲㘳㘴㘵㘶㘷㘸㘹㘺㘻㘼㘽㘾㘿㙀㙁㙂㙃㙄㙅㙆㙇㙈㙉㙊㙋㙌㙍㙎㙏㙐㙑㙒㙓㙔㙕㙖㙗㙘㙙㙚㙛㙜㙝㙞㙟㙠㙡㙢㙣㙤㙥㙦㙧㙨㙩㙪㙫㙬㙭㙮㙯㙰㙱㙲㙳㙴㙵㙶㙷㙸㙹㙺㙻㙼㙽㙾㙿㚀㚁㚂㚃㚄㚅㚆㚇㚈㚉㚊㚋㚌㚍㚎㚏㚐㚑㚒㚓㚔㚕㚖㚗㚘㚙㚚㚛㚜㚝㚞㚟㚠㚡㚢㚣㚤㚥㚦㚧㚨㚩㚪㚫㚬㚭㚮㚯㚰㚱㚲㚳㚴㚵㚶㚷㚸㚹㚺㚻㚼㚽㚾㚿㛀㛁㛂㛃㛄㛅㛆㛇㛈㛉㛊㛋㛌㛍㛎㛏㛐㛑㛒㛓㛔㛕㛖㛗㛘㛙㛚㛛㛜㛝㛞㛟㛠㛡㛢㛣㛤㛥㛦㛧㛨㛩㛪㛫㛬㛭㛮㛯㛰㛱㛲㛳㛴㛵㛶㛷㛸㛹㛺㛻㛼㛽㛾㛿㜀㜁㜂㜃㜄㜅㜆㜇㜈㜉㜊㜋㜌㜍㜎㜏㜐㜑㜒㜓㜔㜕㜖㜗㜘㜙㜚㜛㜜㜝㜞㜟㜠㜡㜢㜣㜤㜥㜦㜧㜨㜩㜪㜫㜬㜭㜮㜯㜰㜱㜲㜳㜴㜵㜶㜷㜸㜹㜺㜻㜼㜽㜾㜿㝀㝁㝂㝃㝄㝅㝆㝇㝈㝉㝊㝋㝌㝍㝎㝏㝐㝑㝒㝓㝔㝕㝖㝗㝘㝙㝚㝛㝜㝝㝞㝟㝠㝡㝢㝣㝤㝥㝦㝧㝨㝩㝪㝫㝬㝭㝮㝯㝰㝱㝲㝳㝴㝵㝶㝷㝸㝹㝺㝻㝼㝽㝾㝿㞀㞁㞂㞃㞄㞅㞆㞇㞈㞉㞊㞋㞌㞍㞎㞏㞐㞑㞒㞓㞔㞕㞖㞗㞘㞙㞚㞛㞜㞝㞞㞟㞠㞡㞢㞣㞤㞥㞦㞧㞨㞩㞪㞫㞬㞭㞮㞯㞰㞱㞲㞳㞴㞵㞶㞷㞸㞹㞺㞻㞼㞽㞾㞿㟀㟁㟂㟃㟄㟅㟆㟇㟈㟉㟊㟋㟌㟍㟎㟏㟐㟑㟒㟓㟔㟕㟖㟗㟘㟙㟚㟛㟜㟝㟞㟟㟠㟡㟢㟣㟤㟥㟦㟧㟨㟩㟪㟫㟬㟭㟮㟯㟰㟱㟲㟳㟴㟵㟶㟷㟸㟹㟺㟻㟼㟽㟾㟿㠀㠁㠂㠃㠄㠅㠆㠇㠈㠉㠊㠋㠌㠍㠎㠏㠐㠑㠒㠓㠔㠕㠖㠗㠘㠙㠚㠛㠜㠝㠞㠟㠠㠡㠢㠣㠤㠥㠦㠧㠨㠩㠪㠫㠬㠭㠮㠯㠰㠱㠲㠳㠴㠵㠶㠷㠸㠹㠺㠻㠼㠽㠾㠿㡀㡁㡂㡃㡄㡅㡆㡇㡈㡉㡊㡋㡌㡍㡎㡏㡐㡑㡒㡓㡔㡕㡖㡗㡘㡙㡚㡛㡜㡝㡞㡟㡠㡡㡢㡣㡤㡥㡦㡧㡨㡩㡪㡫㡬㡭㡮㡯㡰㡱㡲㡳㡴㡵㡶㡷㡸㡹㡺㡻㡼㡽㡾㡿㢀㢁㢂㢃㢄㢅㢆㢇㢈㢉㢊㢋㢌㢍㢎㢏㢐㢑㢒㢓㢔㢕㢖㢗㢘㢙㢚㢛㢜㢝㢞㢟㢠㢡㢢㢣㢤㢥㢦㢧㢨㢩㢪㢫㢬㢭㢮㢯㢰㢱㢲㢳㢴㢵㢶㢷㢸㢹㢺㢻㢼㢽㢾㢿㣀㣁㣂㣃㣄㣅㣆㣇㣈㣉㣊㣋㣌㣍㣎㣏㣐㣑㣒㣓㣔㣕㣖㣗㣘㣙㣚㣛㣜㣝㣞㣟㣠㣡㣢㣣㣤㣥㣦㣧㣨㣩㣪㣫㣬㣭㣮㣯㣰㣱㣲㣳㣴㣵㣶㣷㣸㣹㣺㣻㣼㣽㣾㣿㤀㤁㤂㤃㤄㤅㤆㤇㤈㤉㤊㤋㤌㤍㤎㤏㤐㤑㤒㤓㤔㤕㤖㤗㤘㤙㤚㤛㤜㤝㤞㤟㤠㤡㤢㤣㤤㤥㤦㤧㤨㤩㤪㤫㤬㤭㤮㤯㤰㤱㤲㤳㤴㤵㤶㤷㤸㤹㤺㤻㤼㤽㤾㤿㥀㥁㥂㥃㥄㥅㥆㥇㥈㥉㥊㥋㥌㥍㥎㥏㥐㥑㥒㥓㥔㥕㥖㥗㥘㥙㥚㥛㥜㥝㥞㥟㥠㥡㥢㥣㥤㥥㥦㥧㥨㥩㥪㥫㥬㥭㥮㥯㥰㥱㥲㥳㥴㥵㥶㥷㥸㥹㥺㥻㥼㥽㥾㥿㦀㦁㦂㦃㦄㦅㦆㦇㦈㦉㦊㦋㦌㦍㦎㦏㦐㦑㦒㦓㦔㦕㦖㦗㦘㦙㦚㦛㦜㦝㦞㦟㦠㦡㦢㦣㦤㦥㦦㦧㦨㦩㦪㦫㦬㦭㦮㦯㦰㦱㦲㦳㦴㦵㦶㦷㦸㦹㦺㦻㦼㦽㦾㦿㧀㧁㧂㧃㧄㧅㧆㧇㧈㧉㧊㧋㧌㧍㧎㧏㧐㧑㧒㧓㧔㧕㧖㧗㧘㧙㧚㧛㧜㧝㧞㧟㧠㧡㧢㧣㧤㧥㧦㧧㧨㧩㧪㧫㧬㧭㧮㧯㧰㧱㧲㧳㧴㧵㧶㧷㧸㧹㧺㧻㧼㧽㧾㧿㨀㨁㨂㨃㨄㨅㨆㨇㨈㨉㨊㨋㨌㨍㨎㨏㨐㨑㨒㨓㨔㨕㨖㨗㨘㨙㨚㨛㨜㨝㨞㨟㨠㨡㨢㨣㨤㨥㨦㨧㨨㨩㨪㨫㨬㨭㨮㨯㨰㨱㨲㨳㨴㨵㨶㨷㨸㨹㨺㨻㨼㨽㨾㨿㩀㩁㩂㩃㩄㩅㩆㩇㩈㩉㩊㩋㩌㩍㩎㩏㩐㩑㩒㩓㩔㩕㩖㩗㩘㩙㩚㩛㩜㩝㩞㩟㩠㩡㩢㩣㩤㩥㩦㩧㩨㩩㩪㩫㩬㩭㩮㩯㩰㩱㩲㩳㩴㩵㩶㩷㩸㩹㩺㩻㩼㩽㩾㩿㪀㪁㪂㪃㪄㪅㪆㪇㪈㪉㪊㪋㪌㪍㪎㪏㪐㪑㪒㪓㪔㪕㪖㪗㪘㪙㪚㪛㪜㪝㪞㪟㪠㪡㪢㪣㪤㪥㪦㪧㪨㪩㪪㪫㪬㪭㪮㪯㪰㪱㪲㪳㪴㪵㪶㪷㪸㪹㪺㪻㪼㪽㪾㪿㫀㫁㫂㫃㫄㫅㫆㫇㫈㫉㫊㫋㫌㫍㫎㫏㫐㫑㫒㫓㫔㫕㫖㫗㫘㫙㫚㫛㫜㫝㫞㫟㫠㫡㫢㫣㫤㫥㫦㫧㫨㫩㫪㫫㫬㫭㫮㫯㫰㫱㫲㫳㫴㫵㫶㫷㫸㫹㫺㫻㫼㫽㫾㫿㬀㬁㬂㬃㬄㬅㬆㬇㬈㬉㬊㬋㬌㬍㬎㬏㬐㬑㬒㬓㬔㬕㬖㬗㬘㬙㬚㬛㬜㬝㬞㬟㬠㬡㬢㬣㬤㬥㬦㬧㬨㬩㬪㬫㬬㬭㬮㬯㬰㬱㬲㬳㬴㬵㬶㬷㬸㬹㬺㬻㬼㬽㬾㬿㭀㭁㭂㭃㭄㭅㭆㭇㭈㭉㭊㭋㭌㭍㭎㭏㭐㭑㭒㭓㭔㭕㭖㭗㭘㭙㭚㭛㭜㭝㭞㭟㭠㭡㭢㭣㭤㭥㭦㭧㭨㭩㭪㭫㭬㭭㭮㭯㭰㭱㭲㭳㭴㭵㭶㭷㭸㭹㭺㭻㭼㭽㭾㭿㮀㮁㮂㮃㮄㮅㮆㮇㮈㮉㮊㮋㮌㮍㮎㮏㮐㮑㮒㮓㮔㮕㮖㮗㮘㮙㮚㮛㮜㮝㮞㮟㮠㮡㮢㮣㮤㮥㮦㮧㮨㮩㮪㮫㮬㮭㮮㮯㮰㮱㮲㮳㮴㮵㮶㮷㮸㮹㮺㮻㮼㮽㮾㮿㯀㯁㯂㯃㯄㯅㯆㯇㯈㯉㯊㯋㯌㯍㯎㯏㯐㯑㯒㯓㯔㯕㯖㯗㯘㯙㯚㯛㯜㯝㯞㯟㯠㯡㯢㯣㯤㯥㯦㯧㯨㯩㯪㯫㯬㯭㯮㯯㯰㯱㯲㯳㯴㯵㯶㯷㯸㯹㯺㯻㯼㯽㯾㯿㰀㰁㰂㰃㰄㰅㰆㰇㰈㰉㰊㰋㰌㰍㰎㰏㰐㰑㰒㰓㰔㰕㰖㰗㰘㰙㰚㰛㰜㰝㰞㰟㰠㰡㰢㰣㰤㰥㰦㰧㰨㰩㰪㰫㰬㰭㰮㰯㰰㰱㰲㰳㰴㰵㰶㰷㰸㰹㰺㰻㰼㰽㰾㰿㱀㱁㱂㱃㱄㱅㱆㱇㱈㱉㱊㱋㱌㱍㱎㱏㱐㱑㱒㱓㱔㱕㱖㱗㱘㱙㱚㱛㱜㱝㱞㱟㱠㱡㱢㱣㱤㱥㱦㱧㱨㱩㱪㱫㱬㱭㱮㱯㱰㱱㱲㱳㱴㱵㱶㱷㱸㱹㱺㱻㱼㱽㱾㱿㲀㲁㲂㲃㲄㲅㲆㲇㲈㲉㲊㲋㲌㲍㲎㲏㲐㲑㲒㲓㲔㲕㲖㲗㲘㲙㲚㲛㲜㲝㲞㲟㲠㲡㲢㲣㲤㲥㲦㲧㲨㲩㲪㲫㲬㲭㲮㲯㲰㲱㲲㲳㲴㲵㲶㲷㲸㲹㲺㲻㲼㲽㲾㲿㳀㳁㳂㳃㳄㳅㳆㳇㳈㳉㳊㳋㳌㳍㳎㳏㳐㳑㳒㳓㳔㳕㳖㳗㳘㳙㳚㳛㳜㳝㳞㳟㳠㳡㳢㳣㳤㳥㳦㳧㳨㳩㳪㳫㳬㳭㳮㳯㳰㳱㳲㳳㳴㳵㳶㳷㳸㳹㳺㳻㳼㳽㳾㳿㴀㴁㴂㴃㴄㴅㴆㴇㴈㴉㴊㴋㴌㴍㴎㴏㴐㴑㴒㴓㴔㴕㴖㴗㴘㴙㴚㴛㴜㴝㴞㴟㴠㴡㴢㴣㴤㴥㴦㴧㴨㴩㴪㴫㴬㴭㴮㴯㴰㴱㴲㴳㴴㴵㴶㴷㴸㴹㴺㴻㴼㴽㴾㴿㵀㵁㵂㵃㵄㵅㵆㵇㵈㵉㵊㵋㵌㵍㵎㵏㵐㵑㵒㵓㵔㵕㵖㵗㵘㵙㵚㵛㵜㵝㵞㵟㵠㵡㵢㵣㵤㵥㵦㵧㵨㵩㵪㵫㵬㵭㵮㵯㵰㵱㵲㵳㵴㵵㵶㵷㵸㵹㵺㵻㵼㵽㵾㵿㶀㶁㶂㶃㶄㶅㶆㶇㶈㶉㶊㶋㶌㶍㶎㶏㶐㶑㶒㶓㶔㶕㶖㶗㶘㶙㶚㶛㶜㶝㶞㶟㶠㶡㶢㶣㶤㶥㶦㶧㶨㶩㶪㶫㶬㶭㶮㶯㶰㶱㶲㶳㶴㶵㶶㶷㶸㶹㶺㶻㶼㶽㶾㶿㷀㷁㷂㷃㷄㷅㷆㷇㷈㷉㷊㷋㷌㷍㷎㷏㷐㷑㷒㷓㷔㷕㷖㷗㷘㷙㷚㷛㷜㷝㷞㷟㷠㷡㷢㷣㷤㷥㷦㷧㷨㷩㷪㷫㷬㷭㷮㷯㷰㷱㷲㷳㷴㷵㷶㷷㷸㷹㷺㷻㷼㷽㷾㷿㸀㸁㸂㸃㸄㸅㸆㸇㸈㸉㸊㸋㸌㸍㸎㸏㸐㸑㸒㸓㸔㸕㸖㸗㸘㸙㸚㸛㸜㸝㸞㸟㸠㸡㸢㸣㸤㸥㸦㸧㸨㸩㸪㸫㸬㸭㸮㸯㸰㸱㸲㸳㸴㸵㸶㸷㸸㸹㸺㸻㸼㸽㸾㸿㹀㹁㹂㹃㹄㹅㹆㹇㹈㹉㹊㹋㹌㹍㹎㹏㹐㹑㹒㹓㹔㹕㹖㹗㹘㹙㹚㹛㹜㹝㹞㹟㹠㹡㹢㹣㹤㹥㹦㹧㹨㹩㹪㹫㹬㹭㹮㹯㹰㹱㹲㹳㹴㹵㹶㹷㹸㹹㹺㹻㹼㹽㹾㹿㺀㺁㺂㺃㺄㺅㺆㺇㺈㺉㺊㺋㺌㺍㺎㺏㺐㺑㺒㺓㺔㺕㺖㺗㺘㺙㺚㺛㺜㺝㺞㺟㺠㺡㺢㺣㺤㺥㺦㺧㺨㺩㺪㺫㺬㺭㺮㺯㺰㺱㺲㺳㺴㺵㺶㺷㺸㺹㺺㺻㺼㺽㺾㺿㻀㻁㻂㻃㻄㻅㻆㻇㻈㻉㻊㻋㻌㻍㻎㻏㻐㻑㻒㻓㻔㻕㻖㻗㻘㻙㻚㻛㻜㻝㻞㻟㻠㻡㻢㻣㻤㻥㻦㻧㻨㻩㻪㻫㻬㻭㻮㻯㻰㻱㻲㻳㻴㻵㻶㻷㻸㻹㻺㻻㻼㻽㻾㻿㼀㼁㼂㼃㼄㼅㼆㼇㼈㼉㼊㼋㼌㼍㼎㼏㼐㼑㼒㼓㼔㼕㼖㼗㼘㼙㼚㼛㼜㼝㼞㼟㼠㼡㼢㼣㼤㼥㼦㼧㼨㼩㼪㼫㼬㼭㼮㼯㼰㼱㼲㼳㼴㼵㼶㼷㼸㼹㼺㼻㼼㼽㼾㼿㽀㽁㽂㽃㽄㽅㽆㽇㽈㽉㽊㽋㽌㽍㽎㽏㽐㽑㽒㽓㽔㽕㽖㽗㽘㽙㽚㽛㽜㽝㽞㽟㽠㽡㽢㽣㽤㽥㽦㽧㽨㽩㽪㽫㽬㽭㽮㽯㽰㽱㽲㽳㽴㽵㽶㽷㽸㽹㽺㽻㽼㽽㽾㽿㾀㾁㾂㾃㾄㾅㾆㾇㾈㾉㾊㾋㾌㾍㾎㾏㾐㾑㾒㾓㾔㾕㾖㾗㾘㾙㾚㾛㾜㾝㾞㾟㾠㾡㾢㾣㾤㾥㾦㾧㾨㾩㾪㾫㾬㾭㾮㾯㾰㾱㾲㾳㾴㾵㾶㾷㾸㾹㾺㾻㾼㾽㾾㾿㿀㿁㿂㿃㿄㿅㿆㿇㿈㿉㿊㿋㿌㿍㿎㿏㿐㿑㿒㿓㿔㿕㿖㿗㿘㿙㿚㿛㿜㿝㿞㿟㿠㿡㿢㿣㿤㿥㿦㿧㿨㿩㿪㿫㿬㿭㿮㿯㿰㿱㿲㿳㿴㿵㿶㿷㿸㿹㿺㿻㿼㿽㿾㿿䀀䀁䀂䀃䀄䀅䀆䀇䀈䀉䀊䀋䀌䀍䀎䀏䀐䀑䀒䀓䀔䀕䀖䀗䀘䀙䀚䀛䀜䀝䀞䀟䀠䀡䀢䀣䀤䀥䀦䀧䀨䀩䀪䀫䀬䀭䀮䀯䀰䀱䀲䀳䀴䀵䀶䀷䀸䀹䀺䀻䀼䀽䀾䀿䁀䁁䁂䁃䁄䁅䁆䁇䁈䁉䁊䁋䁌䁍䁎䁏䁐䁑䁒䁓䁔䁕䁖䁗䁘䁙䁚䁛䁜䁝䁞䁟䁠䁡䁢䁣䁤䁥䁦䁧䁨䁩䁪䁫䁬䁭䁮䁯䁰䁱䁲䁳䁴䁵䁶䁷䁸䁹䁺䁻䁼䁽䁾䁿䂀䂁䂂䂃䂄䂅䂆䂇䂈䂉䂊䂋䂌䂍䂎䂏䂐䂑䂒䂓䂔䂕䂖䂗䂘䂙䂚䂛䂜䂝䂞䂟䂠䂡䂢䂣䂤䂥䂦䂧䂨䂩䂪䂫䂬䂭䂮䂯䂰䂱䂲䂳䂴䂵䂶䂷䂸䂹䂺䂻䂼䂽䂾䂿䃀䃁䃂䃃䃄䃅䃆䃇䃈䃉䃊䃋䃌䃍䃎䃏䃐䃑䃒䃓䃔䃕䃖䃗䃘䃙䃚䃛䃜䃝䃞䃟䃠䃡䃢䃣䃤䃥䃦䃧䃨䃩䃪䃫䃬䃭䃮䃯䃰䃱䃲䃳䃴䃵䃶䃷䃸䃹䃺䃻䃼䃽䃾䃿䄀䄁䄂䄃䄄䄅䄆䄇䄈䄉䄊䄋䄌䄍䄎䄏䄐䄑䄒䄓䄔䄕䄖䄗䄘䄙䄚䄛䄜䄝䄞䄟䄠䄡䄢䄣䄤䄥䄦䄧䄨䄩䄪䄫䄬䄭䄮䄯䄰䄱䄲䄳䄴䄵䄶䄷䄸䄹䄺䄻䄼䄽䄾䄿䅀䅁䅂䅃䅄䅅䅆䅇䅈䅉䅊䅋䅌䅍䅎䅏䅐䅑䅒䅓䅔䅕䅖䅗䅘䅙䅚䅛䅜䅝䅞䅟䅠䅡䅢䅣䅤䅥䅦䅧䅨䅩䅪䅫䅬䅭䅮䅯䅰䅱䅲䅳䅴䅵䅶䅷䅸䅹䅺䅻䅼䅽䅾䅿䆀䆁䆂䆃䆄䆅䆆䆇䆈䆉䆊䆋䆌䆍䆎䆏䆐䆑䆒䆓䆔䆕䆖䆗䆘䆙䆚䆛䆜䆝䆞䆟䆠䆡䆢䆣䆤䆥䆦䆧䆨䆩䆪䆫䆬䆭䆮䆯䆰䆱䆲䆳䆴䆵䆶䆷䆸䆹䆺䆻䆼䆽䆾䆿䇀䇁䇂䇃䇄䇅䇆䇇䇈䇉䇊䇋䇌䇍䇎䇏䇐䇑䇒䇓䇔䇕䇖䇗䇘䇙䇚䇛䇜䇝䇞䇟䇠䇡䇢䇣䇤䇥䇦䇧䇨䇩䇪䇫䇬䇭䇮䇯䇰䇱䇲䇳䇴䇵䇶䇷䇸䇹䇺䇻䇼䇽䇾䇿䈀䈁䈂䈃䈄䈅䈆䈇䈈䈉䈊䈋䈌䈍䈎䈏䈐䈑䈒䈓䈔䈕䈖䈗䈘䈙䈚䈛䈜䈝䈞䈟䈠䈡䈢䈣䈤䈥䈦䈧䈨䈩䈪䈫䈬䈭䈮䈯䈰䈱䈲䈳䈴䈵䈶䈷䈸䈹䈺䈻䈼䈽䈾䈿䉀䉁䉂䉃䉄䉅䉆䉇䉈䉉䉊䉋䉌䉍䉎䉏䉐䉑䉒䉓䉔䉕䉖䉗䉘䉙䉚䉛䉜䉝䉞䉟䉠䉡䉢䉣䉤䉥䉦䉧䉨䉩䉪䉫䉬䉭䉮䉯䉰䉱䉲䉳䉴䉵䉶䉷䉸䉹䉺䉻䉼䉽䉾䉿䊀䊁䊂䊃䊄䊅䊆䊇䊈䊉䊊䊋䊌䊍䊎䊏䊐䊑䊒䊓䊔䊕䊖䊗䊘䊙䊚䊛䊜䊝䊞䊟䊠䊡䊢䊣䊤䊥䊦䊧䊨䊩䊪䊫䊬䊭䊮䊯䊰䊱䊲䊳䊴䊵䊶䊷䊸䊹䊺䊻䊼䊽䊾䊿䋀䋁䋂䋃䋄䋅䋆䋇䋈䋉䋊䋋䋌䋍䋎䋏䋐䋑䋒䋓䋔䋕䋖䋗䋘䋙䋚䋛䋜䋝䋞䋟䋠䋡䋢䋣䋤䋥䋦䋧䋨䋩䋪䋫䋬䋭䋮䋯䋰䋱䋲䋳䋴䋵䋶䋷䋸䋹䋺䋻䋼䋽䋾䋿䌀䌁䌂䌃䌄䌅䌆䌇䌈䌉䌊䌋䌌䌍䌎䌏䌐䌑䌒䌓䌔䌕䌖䌗䌘䌙䌚䌛䌜䌝䌞䌟䌠䌡䌢䌣䌤䌥䌦䌧䌨䌩䌪䌫䌬䌭䌮䌯䌰䌱䌲䌳䌴䌵䌶䌷䌸䌹䌺䌻䌼䌽䌾䌿䍀䍁䍂䍃䍄䍅䍆䍇䍈䍉䍊䍋䍌䍍䍎䍏䍐䍑䍒䍓䍔䍕䍖䍗䍘䍙䍚䍛䍜䍝䍞䍟䍠䍡䍢䍣䍤䍥䍦䍧䍨䍩䍪䍫䍬䍭䍮䍯䍰䍱䍲䍳䍴䍵䍶䍷䍸䍹䍺䍻䍼䍽䍾䍿䎀䎁䎂䎃䎄䎅䎆䎇䎈䎉䎊䎋䎌䎍䎎䎏䎐䎑䎒䎓䎔䎕䎖䎗䎘䎙䎚䎛䎜䎝䎞䎟䎠䎡䎢䎣䎤䎥䎦䎧䎨䎩䎪䎫䎬䎭䎮䎯䎰䎱䎲䎳䎴䎵䎶䎷䎸䎹䎺䎻䎼䎽䎾䎿䏀䏁䏂䏃䏄䏅䏆䏇䏈䏉䏊䏋䏌䏍䏎䏏䏐䏑䏒䏓䏔䏕䏖䏗䏘䏙䏚䏛䏜䏝䏞䏟䏠䏡䏢䏣䏤䏥䏦䏧䏨䏩䏪䏫䏬䏭䏮䏯䏰䏱䏲䏳䏴䏵䏶䏷䏸䏹䏺䏻䏼䏽䏾䏿䐀䐁䐂䐃䐄䐅䐆䐇䐈䐉䐊䐋䐌䐍䐎䐏䐐䐑䐒䐓䐔䐕䐖䐗䐘䐙䐚䐛䐜䐝䐞䐟䐠䐡䐢䐣䐤䐥䐦䐧䐨䐩䐪䐫䐬䐭䐮䐯䐰䐱䐲䐳䐴䐵䐶䐷䐸䐹䐺䐻䐼䐽䐾䐿䑀䑁䑂䑃䑄䑅䑆䑇䑈䑉䑊䑋䑌䑍䑎䑏䑐䑑䑒䑓䑔䑕䑖䑗䑘䑙䑚䑛䑜䑝䑞䑟䑠䑡䑢䑣䑤䑥䑦䑧䑨䑩䑪䑫䑬䑭䑮䑯䑰䑱䑲䑳䑴䑵䑶䑷䑸䑹䑺䑻䑼䑽䑾䑿䒀䒁䒂䒃䒄䒅䒆䒇䒈䒉䒊䒋䒌䒍䒎䒏䒐䒑䒒䒓䒔䒕䒖䒗䒘䒙䒚䒛䒜䒝䒞䒟䒠䒡䒢䒣䒤䒥䒦䒧䒨䒩䒪䒫䒬䒭䒮䒯䒰䒱䒲䒳䒴䒵䒶䒷䒸䒹䒺䒻䒼䒽䒾䒿䓀䓁䓂䓃䓄䓅䓆䓇䓈䓉䓊䓋䓌䓍䓎䓏䓐䓑䓒䓓䓔䓕䓖䓗䓘䓙䓚䓛䓜䓝䓞䓟䓠䓡䓢䓣䓤䓥䓦䓧䓨䓩䓪䓫䓬䓭䓮䓯䓰䓱䓲䓳䓴䓵䓶䓷䓸䓹䓺䓻䓼䓽䓾䓿䔀䔁䔂䔃䔄䔅䔆䔇䔈䔉䔊䔋䔌䔍䔎䔏䔐䔑䔒䔓䔔䔕䔖䔗䔘䔙䔚䔛䔜䔝䔞䔟䔠䔡䔢䔣䔤䔥䔦䔧䔨䔩䔪䔫䔬䔭䔮䔯䔰䔱䔲䔳䔴䔵䔶䔷䔸䔹䔺䔻䔼䔽䔾䔿䕀䕁䕂䕃䕄䕅䕆䕇䕈䕉䕊䕋䕌䕍䕎䕏䕐䕑䕒䕓䕔䕕䕖䕗䕘䕙䕚䕛䕜䕝䕞䕟䕠䕡䕢䕣䕤䕥䕦䕧䕨䕩䕪䕫䕬䕭䕮䕯䕰䕱䕲䕳䕴䕵䕶䕷䕸䕹䕺䕻䕼䕽䕾䕿䖀䖁䖂䖃䖄䖅䖆䖇䖈䖉䖊䖋䖌䖍䖎䖏䖐䖑䖒䖓䖔䖕䖖䖗䖘䖙䖚䖛䖜䖝䖞䖟䖠䖡䖢䖣䖤䖥䖦䖧䖨䖩䖪䖫䖬䖭䖮䖯䖰䖱䖲䖳䖴䖵䖶䖷䖸䖹䖺䖻䖼䖽䖾䖿䗀䗁䗂䗃䗄䗅䗆䗇䗈䗉䗊䗋䗌䗍䗎䗏䗐䗑䗒䗓䗔䗕䗖䗗䗘䗙䗚䗛䗜䗝䗞䗟䗠䗡䗢䗣䗤䗥䗦䗧䗨䗩䗪䗫䗬䗭䗮䗯䗰䗱䗲䗳䗴䗵䗶䗷䗸䗹䗺䗻䗼䗽䗾䗿䘀䘁䘂䘃䘄䘅䘆䘇䘈䘉䘊䘋䘌䘍䘎䘏䘐䘑䘒䘓䘔䘕䘖䘗䘘䘙䘚䘛䘜䘝䘞䘟䘠䘡䘢䘣䘤䘥䘦䘧䘨䘩䘪䘫䘬䘭䘮䘯䘰䘱䘲䘳䘴䘵䘶䘷䘸䘹䘺䘻䘼䘽䘾䘿䙀䙁䙂䙃䙄䙅䙆䙇䙈䙉䙊䙋䙌䙍䙎䙏䙐䙑䙒䙓䙔䙕䙖䙗䙘䙙䙚䙛䙜䙝䙞䙟䙠䙡䙢䙣䙤䙥䙦䙧䙨䙩䙪䙫䙬䙭䙮䙯䙰䙱䙲䙳䙴䙵䙶䙷䙸䙹䙺䙻䙼䙽䙾䙿䚀䚁䚂䚃䚄䚅䚆䚇䚈䚉䚊䚋䚌䚍䚎䚏䚐䚑䚒䚓䚔䚕䚖䚗䚘䚙䚚䚛䚜䚝䚞䚟䚠䚡䚢䚣䚤䚥䚦䚧䚨䚩䚪䚫䚬䚭䚮䚯䚰䚱䚲䚳䚴䚵䚶䚷䚸䚹䚺䚻䚼䚽䚾䚿䛀䛁䛂䛃䛄䛅䛆䛇䛈䛉䛊䛋䛌䛍䛎䛏䛐䛑䛒䛓䛔䛕䛖䛗䛘䛙䛚䛛䛜䛝䛞䛟䛠䛡䛢䛣䛤䛥䛦䛧䛨䛩䛪䛫䛬䛭䛮䛯䛰䛱䛲䛳䛴䛵䛶䛷䛸䛹䛺䛻䛼䛽䛾䛿䜀䜁䜂䜃䜄䜅䜆䜇䜈䜉䜊䜋䜌䜍䜎䜏䜐䜑䜒䜓䜔䜕䜖䜗䜘䜙䜚䜛䜜䜝䜞䜟䜠䜡䜢䜣䜤䜥䜦䜧䜨䜩䜪䜫䜬䜭䜮䜯䜰䜱䜲䜳䜴䜵䜶䜷䜸䜹䜺䜻䜼䜽䜾䜿䝀䝁䝂䝃䝄䝅䝆䝇䝈䝉䝊䝋䝌䝍䝎䝏䝐䝑䝒䝓䝔䝕䝖䝗䝘䝙䝚䝛䝜䝝䝞䝟䝠䝡䝢䝣䝤䝥䝦䝧䝨䝩䝪䝫䝬䝭䝮䝯䝰䝱䝲䝳䝴䝵䝶䝷䝸䝹䝺䝻䝼䝽䝾䝿䞀䞁䞂䞃䞄䞅䞆䞇䞈䞉䞊䞋䞌䞍䞎䞏䞐䞑䞒䞓䞔䞕䞖䞗䞘䞙䞚䞛䞜䞝䞞䞟䞠䞡䞢䞣䞤䞥䞦䞧䞨䞩䞪䞫䞬䞭䞮䞯䞰䞱䞲䞳䞴䞵䞶䞷䞸䞹䞺䞻䞼䞽䞾䞿䟀䟁䟂䟃䟄䟅䟆䟇䟈䟉䟊䟋䟌䟍䟎䟏䟐䟑䟒䟓䟔䟕䟖䟗䟘䟙䟚䟛䟜䟝䟞䟟䟠䟡䟢䟣䟤䟥䟦䟧䟨䟩䟪䟫䟬䟭䟮䟯䟰䟱䟲䟳䟴䟵䟶䟷䟸䟹䟺䟻䟼䟽䟾䟿䠀䠁䠂䠃䠄䠅䠆䠇䠈䠉䠊䠋䠌䠍䠎䠏䠐䠑䠒䠓䠔䠕䠖䠗䠘䠙䠚䠛䠜䠝䠞䠟䠠䠡䠢䠣䠤䠥䠦䠧䠨䠩䠪䠫䠬䠭䠮䠯䠰䠱䠲䠳䠴䠵䠶䠷䠸䠹䠺䠻䠼䠽䠾䠿䡀䡁䡂䡃䡄䡅䡆䡇䡈䡉䡊䡋䡌䡍䡎䡏䡐䡑䡒䡓䡔䡕䡖䡗䡘䡙䡚䡛䡜䡝䡞䡟䡠䡡䡢䡣䡤䡥䡦䡧䡨䡩䡪䡫䡬䡭䡮䡯䡰䡱䡲䡳䡴䡵䡶䡷䡸䡹䡺䡻䡼䡽䡾䡿䢀䢁䢂䢃䢄䢅䢆䢇䢈䢉䢊䢋䢌䢍䢎䢏䢐䢑䢒䢓䢔䢕䢖䢗䢘䢙䢚䢛䢜䢝䢞䢟䢠䢡䢢䢣䢤䢥䢦䢧䢨䢩䢪䢫䢬䢭䢮䢯䢰䢱䢲䢳䢴䢵䢶䢷䢸䢹䢺䢻䢼䢽䢾䢿䣀䣁䣂䣃䣄䣅䣆䣇䣈䣉䣊䣋䣌䣍䣎䣏䣐䣑䣒䣓䣔䣕䣖䣗䣘䣙䣚䣛䣜䣝䣞䣟䣠䣡䣢䣣䣤䣥䣦䣧䣨䣩䣪䣫䣬䣭䣮䣯䣰䣱䣲䣳䣴䣵䣶䣷䣸䣹䣺䣻䣼䣽䣾䣿䤀䤁䤂䤃䤄䤅䤆䤇䤈䤉䤊䤋䤌䤍䤎䤏䤐䤑䤒䤓䤔䤕䤖䤗䤘䤙䤚䤛䤜䤝䤞䤟䤠䤡䤢䤣䤤䤥䤦䤧䤨䤩䤪䤫䤬䤭䤮䤯䤰䤱䤲䤳䤴䤵䤶䤷䤸䤹䤺䤻䤼䤽䤾䤿䥀䥁䥂䥃䥄䥅䥆䥇䥈䥉䥊䥋䥌䥍䥎䥏䥐䥑䥒䥓䥔䥕䥖䥗䥘䥙䥚䥛䥜䥝䥞䥟䥠䥡䥢䥣䥤䥥䥦䥧䥨䥩䥪䥫䥬䥭䥮䥯䥰䥱䥲䥳䥴䥵䥶䥷䥸䥹䥺䥻䥼䥽䥾䥿䦀䦁䦂䦃䦄䦅䦆䦇䦈䦉䦊䦋䦌䦍䦎䦏䦐䦑䦒䦓䦔䦕䦖䦗䦘䦙䦚䦛䦜䦝䦞䦟䦠䦡䦢䦣䦤䦥䦦䦧䦨䦩䦪䦫䦬䦭䦮䦯䦰䦱䦲䦳䦴䦵䦶䦷䦸䦹䦺䦻䦼䦽䦾䦿䧀䧁䧂䧃䧄䧅䧆䧇䧈䧉䧊䧋䧌䧍䧎䧏䧐䧑䧒䧓䧔䧕䧖䧗䧘䧙䧚䧛䧜䧝䧞䧟䧠䧡䧢䧣䧤䧥䧦䧧䧨䧩䧪䧫䧬䧭䧮䧯䧰䧱䧲䧳䧴䧵䧶䧷䧸䧹䧺䧻䧼䧽䧾䧿䨀䨁䨂䨃䨄䨅䨆䨇䨈䨉䨊䨋䨌䨍䨎䨏䨐䨑䨒䨓䨔䨕䨖䨗䨘䨙䨚䨛䨜䨝䨞䨟䨠䨡䨢䨣䨤䨥䨦䨧䨨䨩䨪䨫䨬䨭䨮䨯䨰䨱䨲䨳䨴䨵䨶䨷䨸䨹䨺䨻䨼䨽䨾䨿䩀䩁䩂䩃䩄䩅䩆䩇䩈䩉䩊䩋䩌䩍䩎䩏䩐䩑䩒䩓䩔䩕䩖䩗䩘䩙䩚䩛䩜䩝䩞䩟䩠䩡䩢䩣䩤䩥䩦䩧䩨䩩䩪䩫䩬䩭䩮䩯䩰䩱䩲䩳䩴䩵䩶䩷䩸䩹䩺䩻䩼䩽䩾䩿䪀䪁䪂䪃䪄䪅䪆䪇䪈䪉䪊䪋䪌䪍䪎䪏䪐䪑䪒䪓䪔䪕䪖䪗䪘䪙䪚䪛䪜䪝䪞䪟䪠䪡䪢䪣䪤䪥䪦䪧䪨䪩䪪䪫䪬䪭䪮䪯䪰䪱䪲䪳䪴䪵䪶䪷䪸䪹䪺䪻䪼䪽䪾䪿䫀䫁䫂䫃䫄䫅䫆䫇䫈䫉䫊䫋䫌䫍䫎䫏䫐䫑䫒䫓䫔䫕䫖䫗䫘䫙䫚䫛䫜䫝䫞䫟䫠䫡䫢䫣䫤䫥䫦䫧䫨䫩䫪䫫䫬䫭䫮䫯䫰䫱䫲䫳䫴䫵䫶䫷䫸䫹䫺䫻䫼䫽䫾䫿䬀䬁䬂䬃䬄䬅䬆䬇䬈䬉䬊䬋䬌䬍䬎䬏䬐䬑䬒䬓䬔䬕䬖䬗䬘䬙䬚䬛䬜䬝䬞䬟䬠䬡䬢䬣䬤䬥䬦䬧䬨䬩䬪䬫䬬䬭䬮䬯䬰䬱䬲䬳䬴䬵䬶䬷䬸䬹䬺䬻䬼䬽䬾䬿䭀䭁䭂䭃䭄䭅䭆䭇䭈䭉䭊䭋䭌䭍䭎䭏䭐䭑䭒䭓䭔䭕䭖䭗䭘䭙䭚䭛䭜䭝䭞䭟䭠䭡䭢䭣䭤䭥䭦䭧䭨䭩䭪䭫䭬䭭䭮䭯䭰䭱䭲䭳䭴䭵䭶䭷䭸䭹䭺䭻䭼䭽䭾䭿䮀䮁䮂䮃䮄䮅䮆䮇䮈䮉䮊䮋䮌䮍䮎䮏䮐䮑䮒䮓䮔䮕䮖䮗䮘䮙䮚䮛䮜䮝䮞䮟䮠䮡䮢䮣䮤䮥䮦䮧䮨䮩䮪䮫䮬䮭䮮䮯䮰䮱䮲䮳䮴䮵䮶䮷䮸䮹䮺䮻䮼䮽䮾䮿䯀䯁䯂䯃䯄䯅䯆䯇䯈䯉䯊䯋䯌䯍䯎䯏䯐䯑䯒䯓䯔䯕䯖䯗䯘䯙䯚䯛䯜䯝䯞䯟䯠䯡䯢䯣䯤䯥䯦䯧䯨䯩䯪䯫䯬䯭䯮䯯䯰䯱䯲䯳䯴䯵䯶䯷䯸䯹䯺䯻䯼䯽䯾䯿䰀䰁䰂䰃䰄䰅䰆䰇䰈䰉䰊䰋䰌䰍䰎䰏䰐䰑䰒䰓䰔䰕䰖䰗䰘䰙䰚䰛䰜䰝䰞䰟䰠䰡䰢䰣䰤䰥䰦䰧䰨䰩䰪䰫䰬䰭䰮䰯䰰䰱䰲䰳䰴䰵䰶䰷䰸䰹䰺䰻䰼䰽䰾䰿䱀䱁䱂䱃䱄䱅䱆䱇䱈䱉䱊䱋䱌䱍䱎䱏䱐䱑䱒䱓䱔䱕䱖䱗䱘䱙䱚䱛䱜䱝䱞䱟䱠䱡䱢䱣䱤䱥䱦䱧䱨䱩䱪䱫䱬䱭䱮䱯䱰䱱䱲䱳䱴䱵䱶䱷䱸䱹䱺䱻䱼䱽䱾䱿䲀䲁䲂䲃䲄䲅䲆䲇䲈䲉䲊䲋䲌䲍䲎䲏䲐䲑䲒䲓䲔䲕䲖䲗䲘䲙䲚䲛䲜䲝䲞䲟䲠䲡䲢䲣䲤䲥䲦䲧䲨䲩䲪䲫䲬䲭䲮䲯䲰䲱䲲䲳䲴䲵䲶䲷䲸䲹䲺䲻䲼䲽䲾䲿䳀䳁䳂䳃䳄䳅䳆䳇䳈䳉䳊䳋䳌䳍䳎䳏䳐䳑䳒䳓䳔䳕䳖䳗䳘䳙䳚䳛䳜䳝䳞䳟䳠䳡䳢䳣䳤䳥䳦䳧䳨䳩䳪䳫䳬䳭䳮䳯䳰䳱䳲䳳䳴䳵䳶䳷䳸䳹䳺䳻䳼䳽䳾䳿䴀䴁䴂䴃䴄䴅䴆䴇䴈䴉䴊䴋䴌䴍䴎䴏䴐䴑䴒䴓䴔䴕䴖䴗䴘䴙䴚䴛䴜䴝䴞䴟䴠䴡䴢䴣䴤䴥䴦䴧䴨䴩䴪䴫䴬䴭䴮䴯䴰䴱䴲䴳䴴䴵䴶䴷䴸䴹䴺䴻䴼䴽䴾䴿䵀䵁䵂䵃䵄䵅䵆䵇䵈䵉䵊䵋䵌䵍䵎䵏䵐䵑䵒䵓䵔䵕䵖䵗䵘䵙䵚䵛䵜䵝䵞䵟䵠䵡䵢䵣䵤䵥䵦䵧䵨䵩䵪䵫䵬䵭䵮䵯䵰䵱䵲䵳䵴䵵䵶䵷䵸䵹䵺䵻䵼䵽䵾䵿䶀䶁䶂䶃䶄䶅䶆䶇䶈䶉䶊䶋䶌䶍䶎䶏䶐䶑䶒䶓䶔䶕䶖䶗䶘䶙䶚䶛䶜䶝䶞䶟䶠䶡䶢䶣䶤䶥䶦䶧䶨䶩䶪䶫䶬䶭䶮䶯䶰䶱䶲䶳䶴䶵䷀䷁䷂䷃䷄䷅䷆䷇䷈䷉䷊䷋䷌䷍䷎䷏䷐䷑䷒䷓䷔䷕䷖䷗䷘䷙䷚䷛䷜䷝䷞䷟䷠䷡䷢䷣䷤䷥䷦䷧䷨䷩䷪䷫䷬䷭䷮䷯䷰䷱䷲䷳䷴䷵䷶䷷䷸䷹䷺䷻䷼䷽䷾䷿一丁丂七丄丅丆万丈三上下丌不与丏丐丑丒专且丕世丗丘丙业丛东丝丞丟丠両丢丣两严並丧丨丩个丫丬中丮丯丰丱串丳临丵丶丷丸丹为主丼丽举丿乀乁乂乃乄久乆乇么义乊之乌乍乎乏乐乑乒乓乔乕乖乗乘乙乚乛乜九乞也习乡乢乣乤乥书乧乨乩乪乫乬乭乮乯买乱乲乳乴乵乶乷乸乹乺乻乼乽乾乿亀亁亂亃亄亅了亇予争亊事二亍于亏亐云互亓五井亖亗亘亙亚些亜亝亞亟亠亡亢亣交亥亦产亨亩亪享京亭亮亯亰亱亲亳亴亵亶亷亸亹人亻亼亽亾亿什仁仂仃仄仅仆仇仈仉今介仌仍从仏仐仑仒仓仔仕他仗付仙仚仛仜仝仞仟仠仡仢代令以仦仧仨仩仪仫们仭仮仯仰仱仲仳仴仵件价仸仹仺任仼份仾仿伀企伂伃伄伅伆伇伈伉伊伋伌伍伎伏伐休伒伓伔伕伖众优伙会伛伜伝伞伟传伡伢伣伤伥伦伧伨伩伪伫伬伭伮伯估伱伲伳伴伵伶伷伸伹伺伻似伽伾伿佀佁佂佃佄佅但佇佈佉佊佋佌位低住佐佑佒体佔何佖佗佘余佚佛作佝佞佟你佡佢佣佤佥佦佧佨佩佪佫佬佭佮佯佰佱佲佳佴併佶佷佸佹佺佻佼佽佾使侀侁侂侃侄侅來侇侈侉侊例侌侍侎侏侐侑侒侓侔侕侖侗侘侙侚供侜依侞侟侠価侢侣侤侥侦侧侨侩侪侫侬侭侮侯侰侱侲侳侴侵侶侷侸侹侺侻侼侽侾便俀俁係促俄俅俆俇俈俉俊俋俌俍俎俏俐俑俒俓俔俕俖俗俘俙俚俛俜保俞俟俠信俢俣俤俥俦俧俨俩俪俫俬俭修俯俰俱俲俳俴俵俶俷俸俹俺俻俼俽俾俿倀倁倂倃倄倅倆倇倈倉倊個倌倍倎倏倐們倒倓倔倕倖倗倘候倚倛倜倝倞借倠倡倢倣値倥倦倧倨倩倪倫倬倭倮倯倰倱倲倳倴倵倶倷倸倹债倻值倽倾倿偀偁偂偃偄偅偆假偈偉偊偋偌偍偎偏偐偑偒偓偔偕偖偗偘偙做偛停偝偞偟偠偡偢偣偤健偦偧偨偩偪偫偬偭偮偯偰偱偲偳側偵偶偷偸偹偺偻偼偽偾偿傀傁傂傃傄傅傆傇傈傉傊傋傌傍傎傏傐傑傒傓傔傕傖傗傘備傚傛傜傝傞傟傠傡傢傣傤傥傦傧储傩傪傫催傭傮傯傰傱傲傳傴債傶傷傸傹傺傻傼傽傾傿僀僁僂僃僄僅僆僇僈僉僊僋僌働僎像僐僑僒僓僔僕僖僗僘僙僚僛僜僝僞僟僠僡僢僣僤僥僦僧僨僩僪僫僬僭僮僯僰僱僲僳僴僵僶僷僸價僺僻僼僽僾僿儀儁儂儃億儅儆儇儈儉儊儋儌儍儎儏儐儑儒儓儔儕儖儗儘儙儚儛儜儝儞償儠儡儢儣儤儥儦儧儨儩優儫儬儭儮儯儰儱儲儳儴儵儶儷儸儹儺儻儼儽儾儿兀允兂元兄充兆兇先光兊克兌免兎兏児兑兒兓兔兕兖兗兘兙党兛兜兝兞兟兠兡兢兣兤入兦內全兩兪八公六兮兯兰共兲关兴兵其具典兹兺养兼兽兾兿冀冁冂冃冄内円冇冈冉冊冋册再冎冏冐冑冒冓冔冕冖冗冘写冚军农冝冞冟冠冡冢冣冤冥冦冧冨冩冪冫冬冭冮冯冰冱冲决冴况冶冷冸冹冺冻冼冽冾冿净凁凂凃凄凅准凇凈凉凊凋凌凍凎减凐凑凒凓凔凕凖凗凘凙凚凛凜凝凞凟几凡凢凣凤凥処凧凨凩凪凫凬凭凮凯凰凱凲凳凴凵凶凷凸凹出击凼函凾凿刀刁刂刃刄刅分切刈刉刊刋刌刍刎刏刐刑划刓刔刕刖列刘则刚创刜初刞刟删刡刢刣判別刦刧刨利刪别刬刭刮刯到刱刲刳刴刵制刷券刹刺刻刼刽刾刿剀剁剂剃剄剅剆則剈剉削剋剌前剎剏剐剑剒剓剔剕剖剗剘剙剚剛剜剝剞剟剠剡剢剣剤剥剦剧剨剩剪剫剬剭剮副剰剱割剳剴創剶剷剸剹剺剻剼剽剾剿劀劁劂劃劄劅劆劇劈劉劊劋劌劍劎劏劐劑劒劓劔劕劖劗劘劙劚力劜劝办功加务劢劣劤劥劦劧动助努劫劬劭劮劯劰励劲劳労劵劶劷劸効劺劻劼劽劾势勀勁勂勃勄勅勆勇勈勉勊勋勌勍勎勏勐勑勒勓勔動勖勗勘務勚勛勜勝勞募勠勡勢勣勤勥勦勧勨勩勪勫勬勭勮勯勰勱勲勳勴勵勶勷勸勹勺勻勼勽勾勿匀匁匂匃匄包匆匇匈匉匊匋匌匍匎匏匐匑匒匓匔匕化北匘匙匚匛匜匝匞匟匠匡匢匣匤匥匦匧匨匩匪匫匬匭匮匯匰匱匲匳匴匵匶匷匸匹区医匼匽匾匿區十卂千卄卅卆升午卉半卋卌卍华协卐卑卒卓協单卖南単卙博卛卜卝卞卟占卡卢卣卤卥卦卧卨卩卪卫卬卭卮卯印危卲即却卵卶卷卸卹卺卻卼卽卾卿厀厁厂厃厄厅历厇厈厉厊压厌厍厎厏厐厑厒厓厔厕厖厗厘厙厚厛厜厝厞原厠厡厢厣厤厥厦厧厨厩厪厫厬厭厮厯厰厱厲厳厴厵厶厷厸厹厺去厼厽厾县叀叁参參叄叅叆叇又叉及友双反収叏叐发叒叓叔叕取受变叙叚叛叜叝叞叟叠叡叢口古句另叧叨叩只叫召叭叮可台叱史右叴叵叶号司叹叺叻叼叽叾叿吀吁吂吃各吅吆吇合吉吊吋同名后吏吐向吒吓吔吕吖吗吘吙吚君吜吝吞吟吠吡吢吣吤吥否吧吨吩吪含听吭吮启吰吱吲吳吴吵吶吷吸吹吺吻吼吽吾吿呀呁呂呃呄呅呆呇呈呉告呋呌呍呎呏呐呑呒呓呔呕呖呗员呙呚呛呜呝呞呟呠呡呢呣呤呥呦呧周呩呪呫呬呭呮呯呰呱呲味呴呵呶呷呸呹呺呻呼命呾呿咀咁咂咃咄咅咆咇咈咉咊咋和咍咎咏咐咑咒咓咔咕咖咗咘咙咚咛咜咝咞咟咠咡咢咣咤咥咦咧咨咩咪咫咬咭咮咯咰咱咲咳咴咵咶咷咸咹咺咻咼咽咾咿哀品哂哃哄哅哆哇哈哉哊哋哌响哎哏哐哑哒哓哔哕哖哗哘哙哚哛哜哝哞哟哠員哢哣哤哥哦哧哨哩哪哫哬哭哮哯哰哱哲哳哴哵哶哷哸哹哺哻哼哽哾哿唀唁唂唃唄唅唆唇唈唉唊唋唌唍唎唏唐唑唒唓唔唕唖唗唘唙唚唛唜唝唞唟唠唡唢唣唤唥唦唧唨唩唪唫唬唭售唯唰唱唲唳唴唵唶唷唸唹唺唻唼唽唾唿啀啁啂啃啄啅商啇啈啉啊啋啌啍啎問啐啑啒啓啔啕啖啗啘啙啚啛啜啝啞啟啠啡啢啣啤啥啦啧啨啩啪啫啬啭啮啯啰啱啲啳啴啵啶啷啸啹啺啻啼啽啾啿喀喁喂喃善喅喆喇喈喉喊喋喌喍喎喏喐喑喒喓喔喕喖喗喘喙喚喛喜喝喞喟喠喡喢喣喤喥喦喧喨喩喪喫喬喭單喯喰喱喲喳喴喵営喷喸喹喺喻喼喽喾喿嗀嗁嗂嗃嗄嗅嗆嗇嗈嗉嗊嗋嗌嗍嗎嗏嗐嗑嗒嗓嗔嗕嗖嗗嗘嗙嗚嗛嗜嗝嗞嗟嗠嗡嗢嗣嗤嗥嗦嗧嗨嗩嗪嗫嗬嗭嗮嗯嗰嗱嗲嗳嗴嗵嗶嗷嗸嗹嗺嗻嗼嗽嗾嗿嘀嘁嘂嘃嘄嘅嘆嘇嘈嘉嘊嘋嘌嘍嘎嘏嘐嘑嘒嘓嘔嘕嘖嘗嘘嘙嘚嘛嘜嘝嘞嘟嘠嘡嘢嘣嘤嘥嘦嘧嘨嘩嘪嘫嘬嘭嘮嘯嘰嘱嘲嘳嘴嘵嘶嘷嘸嘹嘺嘻嘼嘽嘾嘿噀噁噂噃噄噅噆噇噈噉噊噋噌噍噎噏噐噑噒噓噔噕噖噗噘噙噚噛噜噝噞噟噠噡噢噣噤噥噦噧器噩噪噫噬噭噮噯噰噱噲噳噴噵噶噷噸噹噺噻噼噽噾噿嚀嚁嚂嚃嚄嚅嚆嚇嚈嚉嚊嚋嚌嚍嚎嚏嚐嚑嚒嚓嚔嚕嚖嚗嚘嚙嚚嚛嚜嚝嚞嚟嚠嚡嚢嚣嚤嚥嚦嚧嚨嚩嚪嚫嚬嚭嚮嚯嚰嚱嚲嚳嚴嚵嚶嚷嚸嚹嚺嚻嚼嚽嚾嚿囀囁囂囃囄囅囆囇囈囉囊囋囌囍囎囏囐囑囒囓囔囕囖囗囘囙囚四囜囝回囟因囡团団囤囥囦囧囨囩囪囫囬园囮囯困囱囲図围囵囶囷囸囹固囻囼国图囿圀圁圂圃圄圅圆圇圈圉圊國圌圍圎圏圐圑園圓圔圕圖圗團圙圚圛圜圝圞土圠圡圢圣圤圥圦圧在圩圪圫圬圭圮圯地圱圲圳圴圵圶圷圸圹场圻圼圽圾圿址坁坂坃坄坅坆均坈坉坊坋坌坍坎坏坐坑坒坓坔坕坖块坘坙坚坛坜坝坞坟坠坡坢坣坤坥坦坧坨坩坪坫坬坭坮坯坰坱坲坳坴坵坶坷坸坹坺坻坼坽坾坿垀垁垂垃垄垅垆垇垈垉垊型垌垍垎垏垐垑垒垓垔垕垖垗垘垙垚垛垜垝垞垟垠垡垢垣垤垥垦垧垨垩垪垫垬垭垮垯垰垱垲垳垴垵垶垷垸垹垺垻垼垽垾垿埀埁埂埃埄埅埆埇埈埉埊埋埌埍城埏埐埑埒埓埔埕埖埗埘埙埚埛埜埝埞域埠埡埢埣埤埥埦埧埨埩埪埫埬埭埮埯埰埱埲埳埴埵埶執埸培基埻埼埽埾埿堀堁堂堃堄堅堆堇堈堉堊堋堌堍堎堏堐堑堒堓堔堕堖堗堘堙堚堛堜堝堞堟堠堡堢堣堤堥堦堧堨堩堪堫堬堭堮堯堰報堲堳場堵堶堷堸堹堺堻堼堽堾堿塀塁塂塃塄塅塆塇塈塉塊塋塌塍塎塏塐塑塒塓塔塕塖塗塘塙塚塛塜塝塞塟塠塡塢塣塤塥塦塧塨塩塪填塬塭塮塯塰塱塲塳塴塵塶塷塸塹塺塻塼塽塾塿墀墁墂境墄墅墆墇墈墉墊墋墌墍墎墏墐墑墒墓墔墕墖増墘墙墚墛墜墝增墟墠墡墢墣墤墥墦墧墨墩墪墫墬墭墮墯墰墱墲墳墴墵墶墷墸墹墺墻墼墽墾墿壀壁壂壃壄壅壆壇壈壉壊壋壌壍壎壏壐壑壒壓壔壕壖壗壘壙壚壛壜壝壞壟壠壡壢壣壤壥壦壧壨壩壪士壬壭壮壯声壱売壳壴壵壶壷壸壹壺壻壼壽壾壿夀夁夂夃处夅夆备夈変夊夋夌复夎夏夐夑夒夓夔夕外夗夘夙多夛夜夝夞够夠夡夢夣夤夥夦大夨天太夫夬夭央夯夰失夲夳头夵夶夷夸夹夺夻夼夽夾夿奀奁奂奃奄奅奆奇奈奉奊奋奌奍奎奏奐契奒奓奔奕奖套奘奙奚奛奜奝奞奟奠奡奢奣奤奥奦奧奨奩奪奫奬奭奮奯奰奱奲女奴奵奶奷奸她奺奻奼好奾奿妀妁如妃妄妅妆妇妈妉妊妋妌妍妎妏妐妑妒妓妔妕妖妗妘妙妚妛妜妝妞妟妠妡妢妣妤妥妦妧妨妩妪妫妬妭妮妯妰妱妲妳妴妵妶妷妸妹妺妻妼妽妾妿姀姁姂姃姄姅姆姇姈姉姊始姌姍姎姏姐姑姒姓委姕姖姗姘姙姚姛姜姝姞姟姠姡姢姣姤姥姦姧姨姩姪姫姬姭姮姯姰姱姲姳姴姵姶姷姸姹姺姻姼姽姾姿娀威娂娃娄娅娆娇娈娉娊娋娌娍娎娏娐娑娒娓娔娕娖娗娘娙娚娛娜娝娞娟娠娡娢娣娤娥娦娧娨娩娪娫娬娭娮娯娰娱娲娳娴娵娶娷娸娹娺娻娼娽娾娿婀婁婂婃婄婅婆婇婈婉婊婋婌婍婎婏婐婑婒婓婔婕婖婗婘婙婚婛婜婝婞婟婠婡婢婣婤婥婦婧婨婩婪婫婬婭婮婯婰婱婲婳婴婵婶婷婸婹婺婻婼婽婾婿媀媁媂媃媄媅媆媇媈媉媊媋媌媍媎媏媐媑媒媓媔媕媖媗媘媙媚媛媜媝媞媟媠媡媢媣媤媥媦媧媨媩媪媫媬媭媮媯媰媱媲媳媴媵媶媷媸媹媺媻媼媽媾媿嫀嫁嫂嫃嫄嫅嫆嫇嫈嫉嫊嫋嫌嫍嫎嫏嫐嫑嫒嫓嫔嫕嫖嫗嫘嫙嫚嫛嫜嫝嫞嫟嫠嫡嫢嫣嫤嫥嫦嫧嫨嫩嫪嫫嫬嫭嫮嫯嫰嫱嫲嫳嫴嫵嫶嫷嫸嫹嫺嫻嫼嫽嫾嫿嬀嬁嬂嬃嬄嬅嬆嬇嬈嬉嬊嬋嬌嬍嬎嬏嬐嬑嬒嬓嬔嬕嬖嬗嬘嬙嬚嬛嬜嬝嬞嬟嬠嬡嬢嬣嬤嬥嬦嬧嬨嬩嬪嬫嬬嬭嬮嬯嬰嬱嬲嬳嬴嬵嬶嬷嬸嬹嬺嬻嬼嬽嬾嬿孀孁孂孃孄孅孆孇孈孉孊孋孌孍孎孏子孑孒孓孔孕孖字存孙孚孛孜孝孞孟孠孡孢季孤孥学孧孨孩孪孫孬孭孮孯孰孱孲孳孴孵孶孷學孹孺孻孼孽孾孿宀宁宂它宄宅宆宇守安宊宋完宍宎宏宐宑宒宓宔宕宖宗官宙定宛宜宝实実宠审客宣室宥宦宧宨宩宪宫宬宭宮宯宰宱宲害宴宵家宷宸容宺宻宼宽宾宿寀寁寂寃寄寅密寇寈寉寊寋富寍寎寏寐寑寒寓寔寕寖寗寘寙寚寛寜寝寞察寠寡寢寣寤寥實寧寨審寪寫寬寭寮寯寰寱寲寳寴寵寶寷寸对寺寻导寽対寿尀封専尃射尅将將專尉尊尋尌對導小尐少尒尓尔尕尖尗尘尙尚尛尜尝尞尟尠尡尢尣尤尥尦尧尨尩尪尫尬尭尮尯尰就尲尳尴尵尶尷尸尹尺尻尼尽尾尿局屁层屃屄居屆屇屈屉届屋屌屍屎屏屐屑屒屓屔展屖屗屘屙屚屛屜屝属屟屠屡屢屣層履屦屧屨屩屪屫屬屭屮屯屰山屲屳屴屵屶屷屸屹屺屻屼屽屾屿岀岁岂岃岄岅岆岇岈岉岊岋岌岍岎岏岐岑岒岓岔岕岖岗岘岙岚岛岜岝岞岟岠岡岢岣岤岥岦岧岨岩岪岫岬岭岮岯岰岱岲岳岴岵岶岷岸岹岺岻岼岽岾岿峀峁峂峃峄峅峆峇峈峉峊峋峌峍峎峏峐峑峒峓峔峕峖峗峘峙峚峛峜峝峞峟峠峡峢峣峤峥峦峧峨峩峪峫峬峭峮峯峰峱峲峳峴峵島峷峸峹峺峻峼峽峾峿崀崁崂崃崄崅崆崇崈崉崊崋崌崍崎崏崐崑崒崓崔崕崖崗崘崙崚崛崜崝崞崟崠崡崢崣崤崥崦崧崨崩崪崫崬崭崮崯崰崱崲崳崴崵崶崷崸崹崺崻崼崽崾崿嵀嵁嵂嵃嵄嵅嵆嵇嵈嵉嵊嵋嵌嵍嵎嵏嵐嵑嵒嵓嵔嵕嵖嵗嵘嵙嵚嵛嵜嵝嵞嵟嵠嵡嵢嵣嵤嵥嵦嵧嵨嵩嵪嵫嵬嵭嵮嵯嵰嵱嵲嵳嵴嵵嵶嵷嵸嵹嵺嵻嵼嵽嵾嵿嶀嶁嶂嶃嶄嶅嶆嶇嶈嶉嶊嶋嶌嶍嶎嶏嶐嶑嶒嶓嶔嶕嶖嶗嶘嶙嶚嶛嶜嶝嶞嶟嶠嶡嶢嶣嶤嶥嶦嶧嶨嶩嶪嶫嶬嶭嶮嶯嶰嶱嶲嶳嶴嶵嶶嶷嶸嶹嶺嶻嶼嶽嶾嶿巀巁巂巃巄巅巆巇巈巉巊巋巌巍巎巏巐巑巒巓巔巕巖巗巘巙巚巛巜川州巟巠巡巢巣巤工左巧巨巩巪巫巬巭差巯巰己已巳巴巵巶巷巸巹巺巻巼巽巾巿帀币市布帄帅帆帇师帉帊帋希帍帎帏帐帑帒帓帔帕帖帗帘帙帚帛帜帝帞帟帠帡帢帣帤帥带帧帨帩帪師帬席帮帯帰帱帲帳帴帵帶帷常帹帺帻帼帽帾帿幀幁幂幃幄幅幆幇幈幉幊幋幌幍幎幏幐幑幒幓幔幕幖幗幘幙幚幛幜幝幞幟幠幡幢幣幤幥幦幧幨幩幪幫幬幭幮幯幰幱干平年幵并幷幸幹幺幻幼幽幾广庀庁庂広庄庅庆庇庈庉床庋庌庍庎序庐庑庒库应底庖店庘庙庚庛府庝庞废庠庡庢庣庤庥度座庨庩庪庫庬庭庮庯庰庱庲庳庴庵庶康庸庹庺庻庼庽庾庿廀廁廂廃廄廅廆廇廈廉廊廋廌廍廎廏廐廑廒廓廔廕廖廗廘廙廚廛廜廝廞廟廠廡廢廣廤廥廦廧廨廩廪廫廬廭廮廯廰廱廲廳廴廵延廷廸廹建廻廼廽廾廿开弁异弃弄弅弆弇弈弉弊弋弌弍弎式弐弑弒弓弔引弖弗弘弙弚弛弜弝弞弟张弡弢弣弤弥弦弧弨弩弪弫弬弭弮弯弰弱弲弳弴張弶強弸弹强弻弼弽弾弿彀彁彂彃彄彅彆彇彈彉彊彋彌彍彎彏彐彑归当彔录彖彗彘彙彚彛彜彝彞彟彠彡形彣彤彥彦彧彨彩彪彫彬彭彮彯彰影彲彳彴彵彶彷彸役彺彻彼彽彾彿往征徂徃径待徆徇很徉徊律後徍徎徏徐徑徒従徔徕徖得徘徙徚徛徜徝從徟徠御徢徣徤徥徦徧徨復循徫徬徭微徯徰徱徲徳徴徵徶德徸徹徺徻徼徽徾徿忀忁忂心忄必忆忇忈忉忊忋忌忍忎忏忐忑忒忓忔忕忖志忘忙忚忛応忝忞忟忠忡忢忣忤忥忦忧忨忩忪快忬忭忮忯忰忱忲忳忴念忶忷忸忹忺忻忼忽忾忿怀态怂怃怄怅怆怇怈怉怊怋怌怍怎怏怐怑怒怓怔怕怖怗怘怙怚怛怜思怞怟怠怡怢怣怤急怦性怨怩怪怫怬怭怮怯怰怱怲怳怴怵怶怷怸怹怺总怼怽怾怿恀恁恂恃恄恅恆恇恈恉恊恋恌恍恎恏恐恑恒恓恔恕恖恗恘恙恚恛恜恝恞恟恠恡恢恣恤恥恦恧恨恩恪恫恬恭恮息恰恱恲恳恴恵恶恷恸恹恺恻恼恽恾恿悀悁悂悃悄悅悆悇悈悉悊悋悌悍悎悏悐悑悒悓悔悕悖悗悘悙悚悛悜悝悞悟悠悡悢患悤悥悦悧您悩悪悫悬悭悮悯悰悱悲悳悴悵悶悷悸悹悺悻悼悽悾悿惀惁惂惃惄情惆惇惈惉惊惋惌惍惎惏惐惑惒惓惔惕惖惗惘惙惚惛惜惝惞惟惠惡惢惣惤惥惦惧惨惩惪惫惬惭惮惯惰惱惲想惴惵惶惷惸惹惺惻惼惽惾惿愀愁愂愃愄愅愆愇愈愉愊愋愌愍愎意愐愑愒愓愔愕愖愗愘愙愚愛愜愝愞感愠愡愢愣愤愥愦愧愨愩愪愫愬愭愮愯愰愱愲愳愴愵愶愷愸愹愺愻愼愽愾愿慀慁慂慃慄慅慆慇慈慉慊態慌慍慎慏慐慑慒慓慔慕慖慗慘慙慚慛慜慝慞慟慠慡慢慣慤慥慦慧慨慩慪慫慬慭慮慯慰慱慲慳慴慵慶慷慸慹慺慻慼慽慾慿憀憁憂憃憄憅憆憇憈憉憊憋憌憍憎憏憐憑憒憓憔憕憖憗憘憙憚憛憜憝憞憟憠憡憢憣憤憥憦憧憨憩憪憫憬憭憮憯憰憱憲憳憴憵憶憷憸憹憺憻憼憽憾憿懀懁懂懃懄懅懆懇懈應懊懋懌懍懎懏懐懑懒懓懔懕懖懗懘懙懚懛懜懝懞懟懠懡懢懣懤懥懦懧懨懩懪懫懬懭懮懯懰懱懲懳懴懵懶懷懸懹懺懻懼懽懾懿戀戁戂戃戄戅戆戇戈戉戊戋戌戍戎戏成我戒戓戔戕或戗战戙戚戛戜戝戞戟戠戡戢戣戤戥戦戧戨戩截戫戬戭戮戯戰戱戲戳戴戵戶户戸戹戺戻戼戽戾房所扁扂扃扄扅扆扇扈扉扊手扌才扎扏扐扑扒打扔払扖扗托扙扚扛扜扝扞扟扠扡扢扣扤扥扦执扨扩扪扫扬扭扮扯扰扱扲扳扴扵扶扷扸批扺扻扼扽找承技抁抂抃抄抅抆抇抈抉把抋抌抍抎抏抐抑抒抓抔投抖抗折抙抚抛抜抝択抟抠抡抢抣护报抦抧抨抩抪披抬抭抮抯抰抱抲抳抴抵抶抷抸抹抺抻押抽抾抿拀拁拂拃拄担拆拇拈拉拊拋拌拍拎拏拐拑拒拓拔拕拖拗拘拙拚招拜拝拞拟拠拡拢拣拤拥拦拧拨择拪拫括拭拮拯拰拱拲拳拴拵拶拷拸拹拺拻拼拽拾拿挀持挂挃挄挅挆指挈按挊挋挌挍挎挏挐挑挒挓挔挕挖挗挘挙挚挛挜挝挞挟挠挡挢挣挤挥挦挧挨挩挪挫挬挭挮振挰挱挲挳挴挵挶挷挸挹挺挻挼挽挾挿捀捁捂捃捄捅捆捇捈捉捊捋捌捍捎捏捐捑捒捓捔捕捖捗捘捙捚捛捜捝捞损捠捡换捣捤捥捦捧捨捩捪捫捬捭据捯捰捱捲捳捴捵捶捷捸捹捺捻捼捽捾捿掀掁掂掃掄掅掆掇授掉掊掋掌掍掎掏掐掑排掓掔掕掖掗掘掙掚掛掜掝掞掟掠採探掣掤接掦控推掩措掫掬掭掮掯掰掱掲掳掴掵掶掷掸掹掺掻掼掽掾掿揀揁揂揃揄揅揆揇揈揉揊揋揌揍揎描提揑插揓揔揕揖揗揘揙揚換揜揝揞揟揠握揢揣揤揥揦揧揨揩揪揫揬揭揮揯揰揱揲揳援揵揶揷揸揹揺揻揼揽揾揿搀搁搂搃搄搅搆搇搈搉搊搋搌損搎搏搐搑搒搓搔搕搖搗搘搙搚搛搜搝搞搟搠搡搢搣搤搥搦搧搨搩搪搫搬搭搮搯搰搱搲搳搴搵搶搷搸搹携搻搼搽搾搿摀摁摂摃摄摅摆摇摈摉摊摋摌摍摎摏摐摑摒摓摔摕摖摗摘摙摚摛摜摝摞摟摠摡摢摣摤摥摦摧摨摩摪摫摬摭摮摯摰摱摲摳摴摵摶摷摸摹摺摻摼摽摾摿撀撁撂撃撄撅撆撇撈撉撊撋撌撍撎撏撐撑撒撓撔撕撖撗撘撙撚撛撜撝撞撟撠撡撢撣撤撥撦撧撨撩撪撫撬播撮撯撰撱撲撳撴撵撶撷撸撹撺撻撼撽撾撿擀擁擂擃擄擅擆擇擈擉擊擋擌操擎擏擐擑擒擓擔擕擖擗擘擙據擛擜擝擞擟擠擡擢擣擤擥擦擧擨擩擪擫擬擭擮擯擰擱擲擳擴擵擶擷擸擹擺擻擼擽擾擿攀攁攂攃攄攅攆攇攈攉攊攋攌攍攎攏攐攑攒攓攔攕攖攗攘攙攚攛攜攝攞攟攠攡攢攣攤攥攦攧攨攩攪攫攬攭攮支攰攱攲攳攴攵收攷攸改攺攻攼攽放政敀敁敂敃敄故敆敇效敉敊敋敌敍敎敏敐救敒敓敔敕敖敗敘教敚敛敜敝敞敟敠敡敢散敤敥敦敧敨敩敪敫敬敭敮敯数敱敲敳整敵敶敷數敹敺敻敼敽敾敿斀斁斂斃斄斅斆文斈斉斊斋斌斍斎斏斐斑斒斓斔斕斖斗斘料斚斛斜斝斞斟斠斡斢斣斤斥斦斧斨斩斪斫斬断斮斯新斱斲斳斴斵斶斷斸方斺斻於施斾斿旀旁旂旃旄旅旆旇旈旉旊旋旌旍旎族旐旑旒旓旔旕旖旗旘旙旚旛旜旝旞旟无旡既旣旤日旦旧旨早旪旫旬旭旮旯旰旱旲旳旴旵时旷旸旹旺旻旼旽旾旿昀昁昂昃昄昅昆昇昈昉昊昋昌昍明昏昐昑昒易昔昕昖昗昘昙昚昛昜昝昞星映昡昢昣昤春昦昧昨昩昪昫昬昭昮是昰昱昲昳昴昵昶昷昸昹昺昻昼昽显昿晀晁時晃晄晅晆晇晈晉晊晋晌晍晎晏晐晑晒晓晔晕晖晗晘晙晚晛晜晝晞晟晠晡晢晣晤晥晦晧晨晩晪晫晬晭普景晰晱晲晳晴晵晶晷晸晹智晻晼晽晾晿暀暁暂暃暄暅暆暇暈暉暊暋暌暍暎暏暐暑暒暓暔暕暖暗暘暙暚暛暜暝暞暟暠暡暢暣暤暥暦暧暨暩暪暫暬暭暮暯暰暱暲暳暴暵暶暷暸暹暺暻暼暽暾暿曀曁曂曃曄曅曆曇曈曉曊曋曌曍曎曏曐曑曒曓曔曕曖曗曘曙曚曛曜曝曞曟曠曡曢曣曤曥曦曧曨曩曪曫曬曭曮曯曰曱曲曳更曵曶曷書曹曺曻曼曽曾替最朁朂會朄朅朆朇月有朊朋朌服朎朏朐朑朒朓朔朕朖朗朘朙朚望朜朝朞期朠朡朢朣朤朥朦朧木朩未末本札朮术朰朱朲朳朴朵朶朷朸朹机朻朼朽朾朿杀杁杂权杄杅杆杇杈杉杊杋杌杍李杏材村杒杓杔杕杖杗杘杙杚杛杜杝杞束杠条杢杣杤来杦杧杨杩杪杫杬杭杮杯杰東杲杳杴杵杶杷杸杹杺杻杼杽松板枀极枂枃构枅枆枇枈枉枊枋枌枍枎枏析枑枒枓枔枕枖林枘枙枚枛果枝枞枟枠枡枢枣枤枥枦枧枨枩枪枫枬枭枮枯枰枱枲枳枴枵架枷枸枹枺枻枼枽枾枿柀柁柂柃柄柅柆柇柈柉柊柋柌柍柎柏某柑柒染柔柕柖柗柘柙柚柛柜柝柞柟柠柡柢柣柤查柦柧柨柩柪柫柬柭柮柯柰柱柲柳柴柵柶柷柸柹柺査柼柽柾柿栀栁栂栃栄栅栆标栈栉栊栋栌栍栎栏栐树栒栓栔栕栖栗栘栙栚栛栜栝栞栟栠校栢栣栤栥栦栧栨栩株栫栬栭栮栯栰栱栲栳栴栵栶样核根栺栻格栽栾栿桀桁桂桃桄桅框桇案桉桊桋桌桍桎桏桐桑桒桓桔桕桖桗桘桙桚桛桜桝桞桟桠桡桢档桤桥桦桧桨桩桪桫桬桭桮桯桰桱桲桳桴桵桶桷桸桹桺桻桼桽桾桿梀梁梂梃梄梅梆梇梈梉梊梋梌梍梎梏梐梑梒梓梔梕梖梗梘梙梚梛梜條梞梟梠梡梢梣梤梥梦梧梨梩梪梫梬梭梮梯械梱梲梳梴梵梶梷梸梹梺梻梼梽梾梿检棁棂棃棄棅棆棇棈棉棊棋棌棍棎棏棐棑棒棓棔棕棖棗棘棙棚棛棜棝棞棟棠棡棢棣棤棥棦棧棨棩棪棫棬棭森棯棰棱棲棳棴棵棶棷棸棹棺棻棼棽棾棿椀椁椂椃椄椅椆椇椈椉椊椋椌植椎椏椐椑椒椓椔椕椖椗椘椙椚椛検椝椞椟椠椡椢椣椤椥椦椧椨椩椪椫椬椭椮椯椰椱椲椳椴椵椶椷椸椹椺椻椼椽椾椿楀楁楂楃楄楅楆楇楈楉楊楋楌楍楎楏楐楑楒楓楔楕楖楗楘楙楚楛楜楝楞楟楠楡楢楣楤楥楦楧楨楩楪楫楬業楮楯楰楱楲楳楴極楶楷楸楹楺楻楼楽楾楿榀榁概榃榄榅榆榇榈榉榊榋榌榍榎榏榐榑榒榓榔榕榖榗榘榙榚榛榜榝榞榟榠榡榢榣榤榥榦榧榨榩榪榫榬榭榮榯榰榱榲榳榴榵榶榷榸榹榺榻榼榽榾榿槀槁槂槃槄槅槆槇槈槉槊構槌槍槎槏槐槑槒槓槔槕槖槗様槙槚槛槜槝槞槟槠槡槢槣槤槥槦槧槨槩槪槫槬槭槮槯槰槱槲槳槴槵槶槷槸槹槺槻槼槽槾槿樀樁樂樃樄樅樆樇樈樉樊樋樌樍樎樏樐樑樒樓樔樕樖樗樘標樚樛樜樝樞樟樠模樢樣樤樥樦樧樨権横樫樬樭樮樯樰樱樲樳樴樵樶樷樸樹樺樻樼樽樾樿橀橁橂橃橄橅橆橇橈橉橊橋橌橍橎橏橐橑橒橓橔橕橖橗橘橙橚橛橜橝橞機橠橡橢橣橤橥橦橧橨橩橪橫橬橭橮橯橰橱橲橳橴橵橶橷橸橹橺橻橼橽橾橿檀檁檂檃檄檅檆檇檈檉檊檋檌檍檎檏檐檑檒檓檔檕檖檗檘檙檚檛檜檝檞檟檠檡檢檣檤檥檦檧檨檩檪檫檬檭檮檯檰檱檲檳檴檵檶檷檸檹檺檻檼檽檾檿櫀櫁櫂櫃櫄櫅櫆櫇櫈櫉櫊櫋櫌櫍櫎櫏櫐櫑櫒櫓櫔櫕櫖櫗櫘櫙櫚櫛櫜櫝櫞櫟櫠櫡櫢櫣櫤櫥櫦櫧櫨櫩櫪櫫櫬櫭櫮櫯櫰櫱櫲櫳櫴櫵櫶櫷櫸櫹櫺櫻櫼櫽櫾櫿欀欁欂欃欄欅欆欇欈欉權欋欌欍欎欏欐欑欒欓欔欕欖欗欘欙欚欛欜欝欞欟欠次欢欣欤欥欦欧欨欩欪欫欬欭欮欯欰欱欲欳欴欵欶欷欸欹欺欻欼欽款欿歀歁歂歃歄歅歆歇歈歉歊歋歌歍歎歏歐歑歒歓歔歕歖歗歘歙歚歛歜歝歞歟歠歡止正此步武歧歨歩歪歫歬歭歮歯歰歱歲歳歴歵歶歷歸歹歺死歼歽歾歿殀殁殂殃殄殅殆殇殈殉殊残殌殍殎殏殐殑殒殓殔殕殖殗殘殙殚殛殜殝殞殟殠殡殢殣殤殥殦殧殨殩殪殫殬殭殮殯殰殱殲殳殴段殶殷殸殹殺殻殼殽殾殿毀毁毂毃毄毅毆毇毈毉毊毋毌母毎每毐毑毒毓比毕毖毗毘毙毚毛毜毝毞毟毠毡毢毣毤毥毦毧毨毩毪毫毬毭毮毯毰毱毲毳毴毵毶毷毸毹毺毻毼毽毾毿氀氁氂氃氄氅氆氇氈氉氊氋氌氍氎氏氐民氒氓气氕氖気氘氙氚氛氜氝氞氟氠氡氢氣氤氥氦氧氨氩氪氫氬氭氮氯氰氱氲氳水氵氶氷永氹氺氻氼氽氾氿汀汁求汃汄汅汆汇汈汉汊汋汌汍汎汏汐汑汒汓汔汕汖汗汘汙汚汛汜汝汞江池污汢汣汤汥汦汧汨汩汪汫汬汭汮汯汰汱汲汳汴汵汶汷汸汹決汻汼汽汾汿沀沁沂沃沄沅沆沇沈沉沊沋沌沍沎沏沐沑沒沓沔沕沖沗沘沙沚沛沜沝沞沟沠没沢沣沤沥沦沧沨沩沪沫沬沭沮沯沰沱沲河沴沵沶沷沸油沺治沼沽沾沿泀況泂泃泄泅泆泇泈泉泊泋泌泍泎泏泐泑泒泓泔法泖泗泘泙泚泛泜泝泞泟泠泡波泣泤泥泦泧注泩泪泫泬泭泮泯泰泱泲泳泴泵泶泷泸泹泺泻泼泽泾泿洀洁洂洃洄洅洆洇洈洉洊洋洌洍洎洏洐洑洒洓洔洕洖洗洘洙洚洛洜洝洞洟洠洡洢洣洤津洦洧洨洩洪洫洬洭洮洯洰洱洲洳洴洵洶洷洸洹洺活洼洽派洿浀流浂浃浄浅浆浇浈浉浊测浌浍济浏浐浑浒浓浔浕浖浗浘浙浚浛浜浝浞浟浠浡浢浣浤浥浦浧浨浩浪浫浬浭浮浯浰浱浲浳浴浵浶海浸浹浺浻浼浽浾浿涀涁涂涃涄涅涆涇消涉涊涋涌涍涎涏涐涑涒涓涔涕涖涗涘涙涚涛涜涝涞涟涠涡涢涣涤涥润涧涨涩涪涫涬涭涮涯涰涱液涳涴涵涶涷涸涹涺涻涼涽涾涿淀淁淂淃淄淅淆淇淈淉淊淋淌淍淎淏淐淑淒淓淔淕淖淗淘淙淚淛淜淝淞淟淠淡淢淣淤淥淦淧淨淩淪淫淬淭淮淯淰深淲淳淴淵淶混淸淹淺添淼淽淾淿渀渁渂渃渄清渆渇済渉渊渋渌渍渎渏渐渑渒渓渔渕渖渗渘渙渚減渜渝渞渟渠渡渢渣渤渥渦渧渨温渪渫測渭渮港渰渱渲渳渴渵渶渷游渹渺渻渼渽渾渿湀湁湂湃湄湅湆湇湈湉湊湋湌湍湎湏湐湑湒湓湔湕湖湗湘湙湚湛湜湝湞湟湠湡湢湣湤湥湦湧湨湩湪湫湬湭湮湯湰湱湲湳湴湵湶湷湸湹湺湻湼湽湾湿満溁溂溃溄溅溆溇溈溉溊溋溌溍溎溏源溑溒溓溔溕準溗溘溙溚溛溜溝溞溟溠溡溢溣溤溥溦溧溨溩溪溫溬溭溮溯溰溱溲溳溴溵溶溷溸溹溺溻溼溽溾溿滀滁滂滃滄滅滆滇滈滉滊滋滌滍滎滏滐滑滒滓滔滕滖滗滘滙滚滛滜滝滞滟滠满滢滣滤滥滦滧滨滩滪滫滬滭滮滯滰滱滲滳滴滵滶滷滸滹滺滻滼滽滾滿漀漁漂漃漄漅漆漇漈漉漊漋漌漍漎漏漐漑漒漓演漕漖漗漘漙漚漛漜漝漞漟漠漡漢漣漤漥漦漧漨漩漪漫漬漭漮漯漰漱漲漳漴漵漶漷漸漹漺漻漼漽漾漿潀潁潂潃潄潅潆潇潈潉潊潋潌潍潎潏潐潑潒潓潔潕潖潗潘潙潚潛潜潝潞潟潠潡潢潣潤潥潦潧潨潩潪潫潬潭潮潯潰潱潲潳潴潵潶潷潸潹潺潻潼潽潾潿澀澁澂澃澄澅澆澇澈澉澊澋澌澍澎澏澐澑澒澓澔澕澖澗澘澙澚澛澜澝澞澟澠澡澢澣澤澥澦澧澨澩澪澫澬澭澮澯澰澱澲澳澴澵澶澷澸澹澺澻澼澽澾澿激濁濂濃濄濅濆濇濈濉濊濋濌濍濎濏濐濑濒濓濔濕濖濗濘濙濚濛濜濝濞濟濠濡濢濣濤濥濦濧濨濩濪濫濬濭濮濯濰濱濲濳濴濵濶濷濸濹濺濻濼濽濾濿瀀瀁瀂瀃瀄瀅瀆瀇瀈瀉瀊瀋瀌瀍瀎瀏瀐瀑瀒瀓瀔瀕瀖瀗瀘瀙瀚瀛瀜瀝瀞瀟瀠瀡瀢瀣瀤瀥瀦瀧瀨瀩瀪瀫瀬瀭瀮瀯瀰瀱瀲瀳瀴瀵瀶瀷瀸瀹瀺瀻瀼瀽瀾瀿灀灁灂灃灄灅灆灇灈灉灊灋灌灍灎灏灐灑灒灓灔灕灖灗灘灙灚灛灜灝灞灟灠灡灢灣灤灥灦灧灨灩灪火灬灭灮灯灰灱灲灳灴灵灶灷灸灹灺灻灼災灾灿炀炁炂炃炄炅炆炇炈炉炊炋炌炍炎炏炐炑炒炓炔炕炖炗炘炙炚炛炜炝炞炟炠炡炢炣炤炥炦炧炨炩炪炫炬炭炮炯炰炱炲炳炴炵炶炷炸点為炻炼炽炾炿烀烁烂烃烄烅烆烇烈烉烊烋烌烍烎烏烐烑烒烓烔烕烖烗烘烙烚烛烜烝烞烟烠烡烢烣烤烥烦烧烨烩烪烫烬热烮烯烰烱烲烳烴烵烶烷烸烹烺烻烼烽烾烿焀焁焂焃焄焅焆焇焈焉焊焋焌焍焎焏焐焑焒焓焔焕焖焗焘焙焚焛焜焝焞焟焠無焢焣焤焥焦焧焨焩焪焫焬焭焮焯焰焱焲焳焴焵然焷焸焹焺焻焼焽焾焿煀煁煂煃煄煅煆煇煈煉煊煋煌煍煎煏煐煑煒煓煔煕煖煗煘煙煚煛煜煝煞煟煠煡煢煣煤煥煦照煨煩煪煫煬煭煮煯煰煱煲煳煴煵煶煷煸煹煺煻煼煽煾煿熀熁熂熃熄熅熆熇熈熉熊熋熌熍熎熏熐熑熒熓熔熕熖熗熘熙熚熛熜熝熞熟熠熡熢熣熤熥熦熧熨熩熪熫熬熭熮熯熰熱熲熳熴熵熶熷熸熹熺熻熼熽熾熿燀燁燂燃燄燅燆燇燈燉燊燋燌燍燎燏燐燑燒燓燔燕燖燗燘燙燚燛燜燝燞營燠燡燢燣燤燥燦燧燨燩燪燫燬燭燮燯燰燱燲燳燴燵燶燷燸燹燺燻燼燽燾燿爀爁爂爃爄爅爆爇爈爉爊爋爌爍爎爏爐爑爒爓爔爕爖爗爘爙爚爛爜爝爞爟爠爡爢爣爤爥爦爧爨爩爪爫爬爭爮爯爰爱爲爳爴爵父爷爸爹爺爻爼爽爾爿牀牁牂牃牄牅牆片版牉牊牋牌牍牎牏牐牑牒牓牔牕牖牗牘牙牚牛牜牝牞牟牠牡牢牣牤牥牦牧牨物牪牫牬牭牮牯牰牱牲牳牴牵牶牷牸特牺牻牼牽牾牿犀犁犂犃犄犅犆犇犈犉犊犋犌犍犎犏犐犑犒犓犔犕犖犗犘犙犚犛犜犝犞犟犠犡犢犣犤犥犦犧犨犩犪犫犬犭犮犯犰犱犲犳犴犵状犷犸犹犺犻犼犽犾犿狀狁狂狃狄狅狆狇狈狉狊狋狌狍狎狏狐狑狒狓狔狕狖狗狘狙狚狛狜狝狞狟狠狡狢狣狤狥狦狧狨狩狪狫独狭狮狯狰狱狲狳狴狵狶狷狸狹狺狻狼狽狾狿猀猁猂猃猄猅猆猇猈猉猊猋猌猍猎猏猐猑猒猓猔猕猖猗猘猙猚猛猜猝猞猟猠猡猢猣猤猥猦猧猨猩猪猫猬猭献猯猰猱猲猳猴猵猶猷猸猹猺猻猼猽猾猿獀獁獂獃獄獅獆獇獈獉獊獋獌獍獎獏獐獑獒獓獔獕獖獗獘獙獚獛獜獝獞獟獠獡獢獣獤獥獦獧獨獩獪獫獬獭獮獯獰獱獲獳獴獵獶獷獸獹獺獻獼獽獾獿玀玁玂玃玄玅玆率玈玉玊王玌玍玎玏玐玑玒玓玔玕玖玗玘玙玚玛玜玝玞玟玠玡玢玣玤玥玦玧玨玩玪玫玬玭玮环现玱玲玳玴玵玶玷玸玹玺玻玼玽玾玿珀珁珂珃珄珅珆珇珈珉珊珋珌珍珎珏珐珑珒珓珔珕珖珗珘珙珚珛珜珝珞珟珠珡珢珣珤珥珦珧珨珩珪珫珬班珮珯珰珱珲珳珴珵珶珷珸珹珺珻珼珽現珿琀琁琂球琄琅理琇琈琉琊琋琌琍琎琏琐琑琒琓琔琕琖琗琘琙琚琛琜琝琞琟琠琡琢琣琤琥琦琧琨琩琪琫琬琭琮琯琰琱琲琳琴琵琶琷琸琹琺琻琼琽琾琿瑀瑁瑂瑃瑄瑅瑆瑇瑈瑉瑊瑋瑌瑍瑎瑏瑐瑑瑒瑓瑔瑕瑖瑗瑘瑙瑚瑛瑜瑝瑞瑟瑠瑡瑢瑣瑤瑥瑦瑧瑨瑩瑪瑫瑬瑭瑮瑯瑰瑱瑲瑳瑴瑵瑶瑷瑸瑹瑺瑻瑼瑽瑾瑿璀璁璂璃璄璅璆璇璈璉璊璋璌璍璎璏璐璑璒璓璔璕璖璗璘璙璚璛璜璝璞璟璠璡璢璣璤璥璦璧璨璩璪璫璬璭璮璯環璱璲璳璴璵璶璷璸璹璺璻璼璽璾璿瓀瓁瓂瓃瓄瓅瓆瓇瓈瓉瓊瓋瓌瓍瓎瓏瓐瓑瓒瓓瓔瓕瓖瓗瓘瓙瓚瓛瓜瓝瓞瓟瓠瓡瓢瓣瓤瓥瓦瓧瓨瓩瓪瓫瓬瓭瓮瓯瓰瓱瓲瓳瓴瓵瓶瓷瓸瓹瓺瓻瓼瓽瓾瓿甀甁甂甃甄甅甆甇甈甉甊甋甌甍甎甏甐甑甒甓甔甕甖甗甘甙甚甛甜甝甞生甠甡產産甤甥甦甧用甩甪甫甬甭甮甯田由甲申甴电甶男甸甹町画甼甽甾甿畀畁畂畃畄畅畆畇畈畉畊畋界畍畎畏畐畑畒畓畔畕畖畗畘留畚畛畜畝畞畟畠畡畢畣畤略畦畧畨畩番畫畬畭畮畯異畱畲畳畴畵當畷畸畹畺畻畼畽畾畿疀疁疂疃疄疅疆疇疈疉疊疋疌疍疎疏疐疑疒疓疔疕疖疗疘疙疚疛疜疝疞疟疠疡疢疣疤疥疦疧疨疩疪疫疬疭疮疯疰疱疲疳疴疵疶疷疸疹疺疻疼疽疾疿痀痁痂痃痄病痆症痈痉痊痋痌痍痎痏痐痑痒痓痔痕痖痗痘痙痚痛痜痝痞痟痠痡痢痣痤痥痦痧痨痩痪痫痬痭痮痯痰痱痲痳痴痵痶痷痸痹痺痻痼痽痾痿瘀瘁瘂瘃瘄瘅瘆瘇瘈瘉瘊瘋瘌瘍瘎瘏瘐瘑瘒瘓瘔瘕瘖瘗瘘瘙瘚瘛瘜瘝瘞瘟瘠瘡瘢瘣瘤瘥瘦瘧瘨瘩瘪瘫瘬瘭瘮瘯瘰瘱瘲瘳瘴瘵瘶瘷瘸瘹瘺瘻瘼瘽瘾瘿癀癁療癃癄癅癆癇癈癉癊癋癌癍癎癏癐癑癒癓癔癕癖癗癘癙癚癛癜癝癞癟癠癡癢癣癤癥癦癧癨癩癪癫癬癭癮癯癰癱癲癳癴癵癶癷癸癹発登發白百癿皀皁皂皃的皅皆皇皈皉皊皋皌皍皎皏皐皑皒皓皔皕皖皗皘皙皚皛皜皝皞皟皠皡皢皣皤皥皦皧皨皩皪皫皬皭皮皯皰皱皲皳皴皵皶皷皸皹皺皻皼皽皾皿盀盁盂盃盄盅盆盇盈盉益盋盌盍盎盏盐监盒盓盔盕盖盗盘盙盚盛盜盝盞盟盠盡盢監盤盥盦盧盨盩盪盫盬盭目盯盰盱盲盳直盵盶盷相盹盺盻盼盽盾盿眀省眂眃眄眅眆眇眈眉眊看県眍眎眏眐眑眒眓眔眕眖眗眘眙眚眛眜眝眞真眠眡眢眣眤眥眦眧眨眩眪眫眬眭眮眯眰眱眲眳眴眵眶眷眸眹眺眻眼眽眾眿着睁睂睃睄睅睆睇睈睉睊睋睌睍睎睏睐睑睒睓睔睕睖睗睘睙睚睛睜睝睞睟睠睡睢督睤睥睦睧睨睩睪睫睬睭睮睯睰睱睲睳睴睵睶睷睸睹睺睻睼睽睾睿瞀瞁瞂瞃瞄瞅瞆瞇瞈瞉瞊瞋瞌瞍瞎瞏瞐瞑瞒瞓瞔瞕瞖瞗瞘瞙瞚瞛瞜瞝瞞瞟瞠瞡瞢瞣瞤瞥瞦瞧瞨瞩瞪瞫瞬瞭瞮瞯瞰瞱瞲瞳瞴瞵瞶瞷瞸瞹瞺瞻瞼瞽瞾瞿矀矁矂矃矄矅矆矇矈矉矊矋矌矍矎矏矐矑矒矓矔矕矖矗矘矙矚矛矜矝矞矟矠矡矢矣矤知矦矧矨矩矪矫矬短矮矯矰矱矲石矴矵矶矷矸矹矺矻矼矽矾矿砀码砂砃砄砅砆砇砈砉砊砋砌砍砎砏砐砑砒砓研砕砖砗砘砙砚砛砜砝砞砟砠砡砢砣砤砥砦砧砨砩砪砫砬砭砮砯砰砱砲砳破砵砶砷砸砹砺砻砼砽砾砿础硁硂硃硄硅硆硇硈硉硊硋硌硍硎硏硐硑硒硓硔硕硖硗硘硙硚硛硜硝硞硟硠硡硢硣硤硥硦硧硨硩硪硫硬硭确硯硰硱硲硳硴硵硶硷硸硹硺硻硼硽硾硿碀碁碂碃碄碅碆碇碈碉碊碋碌碍碎碏碐碑碒碓碔碕碖碗碘碙碚碛碜碝碞碟碠碡碢碣碤碥碦碧碨碩碪碫碬碭碮碯碰碱碲碳碴碵碶碷碸碹確碻碼碽碾碿磀磁磂磃磄磅磆磇磈磉磊磋磌磍磎磏磐磑磒磓磔磕磖磗磘磙磚磛磜磝磞磟磠磡磢磣磤磥磦磧磨磩磪磫磬磭磮磯磰磱磲磳磴磵磶磷磸磹磺磻磼磽磾磿礀礁礂礃礄礅礆礇礈礉礊礋礌礍礎礏礐礑礒礓礔礕礖礗礘礙礚礛礜礝礞礟礠礡礢礣礤礥礦礧礨礩礪礫礬礭礮礯礰礱礲礳礴礵礶礷礸礹示礻礼礽社礿祀祁祂祃祄祅祆祇祈祉祊祋祌祍祎祏祐祑祒祓祔祕祖祗祘祙祚祛祜祝神祟祠祡祢祣祤祥祦祧票祩祪祫祬祭祮祯祰祱祲祳祴祵祶祷祸祹祺祻祼祽祾祿禀禁禂禃禄禅禆禇禈禉禊禋禌禍禎福禐禑禒禓禔禕禖禗禘禙禚禛禜禝禞禟禠禡禢禣禤禥禦禧禨禩禪禫禬禭禮禯禰禱禲禳禴禵禶禷禸禹禺离禼禽禾禿秀私秂秃秄秅秆秇秈秉秊秋秌种秎秏秐科秒秓秔秕秖秗秘秙秚秛秜秝秞租秠秡秢秣秤秥秦秧秨秩秪秫秬秭秮积称秱秲秳秴秵秶秷秸秹秺移秼秽秾秿稀稁稂稃稄稅稆稇稈稉稊程稌稍税稏稐稑稒稓稔稕稖稗稘稙稚稛稜稝稞稟稠稡稢稣稤稥稦稧稨稩稪稫稬稭種稯稰稱稲稳稴稵稶稷稸稹稺稻稼稽稾稿穀穁穂穃穄穅穆穇穈穉穊穋穌積穎穏穐穑穒穓穔穕穖穗穘穙穚穛穜穝穞穟穠穡穢穣穤穥穦穧穨穩穪穫穬穭穮穯穰穱穲穳穴穵究穷穸穹空穻穼穽穾穿窀突窂窃窄窅窆窇窈窉窊窋窌窍窎窏窐窑窒窓窔窕窖窗窘窙窚窛窜窝窞窟窠窡窢窣窤窥窦窧窨窩窪窫窬窭窮窯窰窱窲窳窴窵窶窷窸窹窺窻窼窽窾窿竀竁竂竃竄竅竆竇竈竉竊立竌竍竎竏竐竑竒竓竔竕竖竗竘站竚竛竜竝竞竟章竡竢竣竤童竦竧竨竩竪竫竬竭竮端竰竱竲竳竴竵競竷竸竹竺竻竼竽竾竿笀笁笂笃笄笅笆笇笈笉笊笋笌笍笎笏笐笑笒笓笔笕笖笗笘笙笚笛笜笝笞笟笠笡笢笣笤笥符笧笨笩笪笫第笭笮笯笰笱笲笳笴笵笶笷笸笹笺笻笼笽笾笿筀筁筂筃筄筅筆筇筈等筊筋筌筍筎筏筐筑筒筓答筕策筗筘筙筚筛筜筝筞筟筠筡筢筣筤筥筦筧筨筩筪筫筬筭筮筯筰筱筲筳筴筵筶筷筸筹筺筻筼筽签筿简箁箂箃箄箅箆箇箈箉箊箋箌箍箎箏箐箑箒箓箔箕箖算箘箙箚箛箜箝箞箟箠管箢箣箤箥箦箧箨箩箪箫箬箭箮箯箰箱箲箳箴箵箶箷箸箹箺箻箼箽箾箿節篁篂篃範篅篆篇篈築篊篋篌篍篎篏篐篑篒篓篔篕篖篗篘篙篚篛篜篝篞篟篠篡篢篣篤篥篦篧篨篩篪篫篬篭篮篯篰篱篲篳篴篵篶篷篸篹篺篻篼篽篾篿簀簁簂簃簄簅簆簇簈簉簊簋簌簍簎簏簐簑簒簓簔簕簖簗簘簙簚簛簜簝簞簟簠簡簢簣簤簥簦簧簨簩簪簫簬簭簮簯簰簱簲簳簴簵簶簷簸簹簺簻簼簽簾簿籀籁籂籃籄籅籆籇籈籉籊籋籌籍籎籏籐籑籒籓籔籕籖籗籘籙籚籛籜籝籞籟籠籡籢籣籤籥籦籧籨籩籪籫籬籭籮籯籰籱籲米籴籵籶籷籸籹籺类籼籽籾籿粀粁粂粃粄粅粆粇粈粉粊粋粌粍粎粏粐粑粒粓粔粕粖粗粘粙粚粛粜粝粞粟粠粡粢粣粤粥粦粧粨粩粪粫粬粭粮粯粰粱粲粳粴粵粶粷粸粹粺粻粼粽精粿糀糁糂糃糄糅糆糇糈糉糊糋糌糍糎糏糐糑糒糓糔糕糖糗糘糙糚糛糜糝糞糟糠糡糢糣糤糥糦糧糨糩糪糫糬糭糮糯糰糱糲糳糴糵糶糷糸糹糺系糼糽糾糿紀紁紂紃約紅紆紇紈紉紊紋紌納紎紏紐紑紒紓純紕紖紗紘紙級紛紜紝紞紟素紡索紣紤紥紦紧紨紩紪紫紬紭紮累細紱紲紳紴紵紶紷紸紹紺紻紼紽紾紿絀絁終絃組絅絆絇絈絉絊絋経絍絎絏結絑絒絓絔絕絖絗絘絙絚絛絜絝絞絟絠絡絢絣絤絥給絧絨絩絪絫絬絭絮絯絰統絲絳絴絵絶絷絸絹絺絻絼絽絾絿綀綁綂綃綄綅綆綇綈綉綊綋綌綍綎綏綐綑綒經綔綕綖綗綘継続綛綜綝綞綟綠綡綢綣綤綥綦綧綨綩綪綫綬維綮綯綰綱網綳綴綵綶綷綸綹綺綻綼綽綾綿緀緁緂緃緄緅緆緇緈緉緊緋緌緍緎総緐緑緒緓緔緕緖緗緘緙線緛緜緝緞緟締緡緢緣緤緥緦緧編緩緪緫緬緭緮緯緰緱緲緳練緵緶緷緸緹緺緻緼緽緾緿縀縁縂縃縄縅縆縇縈縉縊縋縌縍縎縏縐縑縒縓縔縕縖縗縘縙縚縛縜縝縞縟縠縡縢縣縤縥縦縧縨縩縪縫縬縭縮縯縰縱縲縳縴縵縶縷縸縹縺縻縼總績縿繀繁繂繃繄繅繆繇繈繉繊繋繌繍繎繏繐繑繒繓織繕繖繗繘繙繚繛繜繝繞繟繠繡繢繣繤繥繦繧繨繩繪繫繬繭繮繯繰繱繲繳繴繵繶繷繸繹繺繻繼繽繾繿纀纁纂纃纄纅纆纇纈纉纊纋續纍纎纏纐纑纒纓纔纕纖纗纘纙纚纛纜纝纞纟纠纡红纣纤纥约级纨纩纪纫纬纭纮纯纰纱纲纳纴纵纶纷纸纹纺纻纼纽纾线绀绁绂练组绅细织终绉绊绋绌绍绎经绐绑绒结绔绕绖绗绘给绚绛络绝绞统绠绡绢绣绤绥绦继绨绩绪绫绬续绮绯绰绱绲绳维绵绶绷绸绹绺绻综绽绾绿缀缁缂缃缄缅缆缇缈缉缊缋缌缍缎缏缐缑缒缓缔缕编缗缘缙缚缛缜缝缞缟缠缡缢缣缤缥缦缧缨缩缪缫缬缭缮缯缰缱缲缳缴缵缶缷缸缹缺缻缼缽缾缿罀罁罂罃罄罅罆罇罈罉罊罋罌罍罎罏罐网罒罓罔罕罖罗罘罙罚罛罜罝罞罟罠罡罢罣罤罥罦罧罨罩罪罫罬罭置罯罰罱署罳罴罵罶罷罸罹罺罻罼罽罾罿羀羁羂羃羄羅羆羇羈羉羊羋羌羍美羏羐羑羒羓羔羕羖羗羘羙羚羛羜羝羞羟羠羡羢羣群羥羦羧羨義羪羫羬羭羮羯羰羱羲羳羴羵羶羷羸羹羺羻羼羽羾羿翀翁翂翃翄翅翆翇翈翉翊翋翌翍翎翏翐翑習翓翔翕翖翗翘翙翚翛翜翝翞翟翠翡翢翣翤翥翦翧翨翩翪翫翬翭翮翯翰翱翲翳翴翵翶翷翸翹翺翻翼翽翾翿耀老耂考耄者耆耇耈耉耊耋而耍耎耏耐耑耒耓耔耕耖耗耘耙耚耛耜耝耞耟耠耡耢耣耤耥耦耧耨耩耪耫耬耭耮耯耰耱耲耳耴耵耶耷耸耹耺耻耼耽耾耿聀聁聂聃聄聅聆聇聈聉聊聋职聍聎聏聐聑聒聓联聕聖聗聘聙聚聛聜聝聞聟聠聡聢聣聤聥聦聧聨聩聪聫聬聭聮聯聰聱聲聳聴聵聶職聸聹聺聻聼聽聾聿肀肁肂肃肄肅肆肇肈肉肊肋肌肍肎肏肐肑肒肓肔肕肖肗肘肙肚肛肜肝肞肟肠股肢肣肤肥肦肧肨肩肪肫肬肭肮肯肰肱育肳肴肵肶肷肸肹肺肻肼肽肾肿胀胁胂胃胄胅胆胇胈胉胊胋背胍胎胏胐胑胒胓胔胕胖胗胘胙胚胛胜胝胞胟胠胡胢胣胤胥胦胧胨胩胪胫胬胭胮胯胰胱胲胳胴胵胶胷胸胹胺胻胼能胾胿脀脁脂脃脄脅脆脇脈脉脊脋脌脍脎脏脐脑脒脓脔脕脖脗脘脙脚脛脜脝脞脟脠脡脢脣脤脥脦脧脨脩脪脫脬脭脮脯脰脱脲脳脴脵脶脷脸脹脺脻脼脽脾脿腀腁腂腃腄腅腆腇腈腉腊腋腌腍腎腏腐腑腒腓腔腕腖腗腘腙腚腛腜腝腞腟腠腡腢腣腤腥腦腧腨腩腪腫腬腭腮腯腰腱腲腳腴腵腶腷腸腹腺腻腼腽腾腿膀膁膂膃膄膅膆膇膈膉膊膋膌膍膎膏膐膑膒膓膔膕膖膗膘膙膚膛膜膝膞膟膠膡膢膣膤膥膦膧膨膩膪膫膬膭膮膯膰膱膲膳膴膵膶膷膸膹膺膻膼膽膾膿臀臁臂臃臄臅臆臇臈臉臊臋臌臍臎臏臐臑臒臓臔臕臖臗臘臙臚臛臜臝臞臟臠臡臢臣臤臥臦臧臨臩自臫臬臭臮臯臰臱臲至致臵臶臷臸臹臺臻臼臽臾臿舀舁舂舃舄舅舆與興舉舊舋舌舍舎舏舐舑舒舓舔舕舖舗舘舙舚舛舜舝舞舟舠舡舢舣舤舥舦舧舨舩航舫般舭舮舯舰舱舲舳舴舵舶舷舸船舺舻舼舽舾舿艀艁艂艃艄艅艆艇艈艉艊艋艌艍艎艏艐艑艒艓艔艕艖艗艘艙艚艛艜艝艞艟艠艡艢艣艤艥艦艧艨艩艪艫艬艭艮良艰艱色艳艴艵艶艷艸艹艺艻艼艽艾艿芀芁节芃芄芅芆芇芈芉芊芋芌芍芎芏芐芑芒芓芔芕芖芗芘芙芚芛芜芝芞芟芠芡芢芣芤芥芦芧芨芩芪芫芬芭芮芯芰花芲芳芴芵芶芷芸芹芺芻芼芽芾芿苀苁苂苃苄苅苆苇苈苉苊苋苌苍苎苏苐苑苒苓苔苕苖苗苘苙苚苛苜苝苞苟苠苡苢苣苤若苦苧苨苩苪苫苬苭苮苯苰英苲苳苴苵苶苷苸苹苺苻苼苽苾苿茀茁茂范茄茅茆茇茈茉茊茋茌茍茎茏茐茑茒茓茔茕茖茗茘茙茚茛茜茝茞茟茠茡茢茣茤茥茦茧茨茩茪茫茬茭茮茯茰茱茲茳茴茵茶茷茸茹茺茻茼茽茾茿荀荁荂荃荄荅荆荇荈草荊荋荌荍荎荏荐荑荒荓荔荕荖荗荘荙荚荛荜荝荞荟荠荡荢荣荤荥荦荧荨荩荪荫荬荭荮药荰荱荲荳荴荵荶荷荸荹荺荻荼荽荾荿莀莁莂莃莄莅莆莇莈莉莊莋莌莍莎莏莐莑莒莓莔莕莖莗莘莙莚莛莜莝莞莟莠莡莢莣莤莥莦莧莨莩莪莫莬莭莮莯莰莱莲莳莴莵莶获莸莹莺莻莼莽莾莿菀菁菂菃菄菅菆菇菈菉菊菋菌菍菎菏菐菑菒菓菔菕菖菗菘菙菚菛菜菝菞菟菠菡菢菣菤菥菦菧菨菩菪菫菬菭菮華菰菱菲菳菴菵菶菷菸菹菺菻菼菽菾菿萀萁萂萃萄萅萆萇萈萉萊萋萌萍萎萏萐萑萒萓萔萕萖萗萘萙萚萛萜萝萞萟萠萡萢萣萤营萦萧萨萩萪萫萬萭萮萯萰萱萲萳萴萵萶萷萸萹萺萻萼落萾萿葀葁葂葃葄葅葆葇葈葉葊葋葌葍葎葏葐葑葒葓葔葕葖著葘葙葚葛葜葝葞葟葠葡葢董葤葥葦葧葨葩葪葫葬葭葮葯葰葱葲葳葴葵葶葷葸葹葺葻葼葽葾葿蒀蒁蒂蒃蒄蒅蒆蒇蒈蒉蒊蒋蒌蒍蒎蒏蒐蒑蒒蒓蒔蒕蒖蒗蒘蒙蒚蒛蒜蒝蒞蒟蒠蒡蒢蒣蒤蒥蒦蒧蒨蒩蒪蒫蒬蒭蒮蒯蒰蒱蒲蒳蒴蒵蒶蒷蒸蒹蒺蒻蒼蒽蒾蒿蓀蓁蓂蓃蓄蓅蓆蓇蓈蓉蓊蓋蓌蓍蓎蓏蓐蓑蓒蓓蓔蓕蓖蓗蓘蓙蓚蓛蓜蓝蓞蓟蓠蓡蓢蓣蓤蓥蓦蓧蓨蓩蓪蓫蓬蓭蓮蓯蓰蓱蓲蓳蓴蓵蓶蓷蓸蓹蓺蓻蓼蓽蓾蓿蔀蔁蔂蔃蔄蔅蔆蔇蔈蔉蔊蔋蔌蔍蔎蔏蔐蔑蔒蔓蔔蔕蔖蔗蔘蔙蔚蔛蔜蔝蔞蔟蔠蔡蔢蔣蔤蔥蔦蔧蔨蔩蔪蔫蔬蔭蔮蔯蔰蔱蔲蔳蔴蔵蔶蔷蔸蔹蔺蔻蔼蔽蔾蔿蕀蕁蕂蕃蕄蕅蕆蕇蕈蕉蕊蕋蕌蕍蕎蕏蕐蕑蕒蕓蕔蕕蕖蕗蕘蕙蕚蕛蕜蕝蕞蕟蕠蕡蕢蕣蕤蕥蕦蕧蕨蕩蕪蕫蕬蕭蕮蕯蕰蕱蕲蕳蕴蕵蕶蕷蕸蕹蕺蕻蕼蕽蕾蕿薀薁薂薃薄薅薆薇薈薉薊薋薌薍薎薏薐薑薒薓薔薕薖薗薘薙薚薛薜薝薞薟薠薡薢薣薤薥薦薧薨薩薪薫薬薭薮薯薰薱薲薳薴薵薶薷薸薹薺薻薼薽薾薿藀藁藂藃藄藅藆藇藈藉藊藋藌藍藎藏藐藑藒藓藔藕藖藗藘藙藚藛藜藝藞藟藠藡藢藣藤藥藦藧藨藩藪藫藬藭藮藯藰藱藲藳藴藵藶藷藸藹藺藻藼藽藾藿蘀蘁蘂蘃蘄蘅蘆蘇蘈蘉蘊蘋蘌蘍蘎蘏蘐蘑蘒蘓蘔蘕蘖蘗蘘蘙蘚蘛蘜蘝蘞蘟蘠蘡蘢蘣蘤蘥蘦蘧蘨蘩蘪蘫蘬蘭蘮蘯蘰蘱蘲蘳蘴蘵蘶蘷蘸蘹蘺蘻蘼蘽蘾蘿虀虁虂虃虄虅虆虇虈虉虊虋虌虍虎虏虐虑虒虓虔處虖虗虘虙虚虛虜虝虞號虠虡虢虣虤虥虦虧虨虩虪虫虬虭虮虯虰虱虲虳虴虵虶虷虸虹虺虻虼虽虾虿蚀蚁蚂蚃蚄蚅蚆蚇蚈蚉蚊蚋蚌蚍蚎蚏蚐蚑蚒蚓蚔蚕蚖蚗蚘蚙蚚蚛蚜蚝蚞蚟蚠蚡蚢蚣蚤蚥蚦蚧蚨蚩蚪蚫蚬蚭蚮蚯蚰蚱蚲蚳蚴蚵蚶蚷蚸蚹蚺蚻蚼蚽蚾蚿蛀蛁蛂蛃蛄蛅蛆蛇蛈蛉蛊蛋蛌蛍蛎蛏蛐蛑蛒蛓蛔蛕蛖蛗蛘蛙蛚蛛蛜蛝蛞蛟蛠蛡蛢蛣蛤蛥蛦蛧蛨蛩蛪蛫蛬蛭蛮蛯蛰蛱蛲蛳蛴蛵蛶蛷蛸蛹蛺蛻蛼蛽蛾蛿蜀蜁蜂蜃蜄蜅蜆蜇蜈蜉蜊蜋蜌蜍蜎蜏蜐蜑蜒蜓蜔蜕蜖蜗蜘蜙蜚蜛蜜蜝蜞蜟蜠蜡蜢蜣蜤蜥蜦蜧蜨蜩蜪蜫蜬蜭蜮蜯蜰蜱蜲蜳蜴蜵蜶蜷蜸蜹蜺蜻蜼蜽蜾蜿蝀蝁蝂蝃蝄蝅蝆蝇蝈蝉蝊蝋蝌蝍蝎蝏蝐蝑蝒蝓蝔蝕蝖蝗蝘蝙蝚蝛蝜蝝蝞蝟蝠蝡蝢蝣蝤蝥蝦蝧蝨蝩蝪蝫蝬蝭蝮蝯蝰蝱蝲蝳蝴蝵蝶蝷蝸蝹蝺蝻蝼蝽蝾蝿螀螁螂螃螄螅螆螇螈螉螊螋螌融螎螏螐螑螒螓螔螕螖螗螘螙螚螛螜螝螞螟螠螡螢螣螤螥螦螧螨螩螪螫螬螭螮螯螰螱螲螳螴螵螶螷螸螹螺螻螼螽螾螿蟀蟁蟂蟃蟄蟅蟆蟇蟈蟉蟊蟋蟌蟍蟎蟏蟐蟑蟒蟓蟔蟕蟖蟗蟘蟙蟚蟛蟜蟝蟞蟟蟠蟡蟢蟣蟤蟥蟦蟧蟨蟩蟪蟫蟬蟭蟮蟯蟰蟱蟲蟳蟴蟵蟶蟷蟸蟹蟺蟻蟼蟽蟾蟿蠀蠁蠂蠃蠄蠅蠆蠇蠈蠉蠊蠋蠌蠍蠎蠏蠐蠑蠒蠓蠔蠕蠖蠗蠘蠙蠚蠛蠜蠝蠞蠟蠠蠡蠢蠣蠤蠥蠦蠧蠨蠩蠪蠫蠬蠭蠮蠯蠰蠱蠲蠳蠴蠵蠶蠷蠸蠹蠺蠻蠼蠽蠾蠿血衁衂衃衄衅衆衇衈衉衊衋行衍衎衏衐衑衒術衔衕衖街衘衙衚衛衜衝衞衟衠衡衢衣衤补衦衧表衩衪衫衬衭衮衯衰衱衲衳衴衵衶衷衸衹衺衻衼衽衾衿袀袁袂袃袄袅袆袇袈袉袊袋袌袍袎袏袐袑袒袓袔袕袖袗袘袙袚袛袜袝袞袟袠袡袢袣袤袥袦袧袨袩袪被袬袭袮袯袰袱袲袳袴袵袶袷袸袹袺袻袼袽袾袿裀裁裂裃裄装裆裇裈裉裊裋裌裍裎裏裐裑裒裓裔裕裖裗裘裙裚裛補裝裞裟裠裡裢裣裤裥裦裧裨裩裪裫裬裭裮裯裰裱裲裳裴裵裶裷裸裹裺裻裼製裾裿褀褁褂褃褄褅褆複褈褉褊褋褌褍褎褏褐褑褒褓褔褕褖褗褘褙褚褛褜褝褞褟褠褡褢褣褤褥褦褧褨褩褪褫褬褭褮褯褰褱褲褳褴褵褶褷褸褹褺褻褼褽褾褿襀襁襂襃襄襅襆襇襈襉襊襋襌襍襎襏襐襑襒襓襔襕襖襗襘襙襚襛襜襝襞襟襠襡襢襣襤襥襦襧襨襩襪襫襬襭襮襯襰襱襲襳襴襵襶襷襸襹襺襻襼襽襾西覀要覂覃覄覅覆覇覈覉覊見覌覍覎規覐覑覒覓覔覕視覗覘覙覚覛覜覝覞覟覠覡覢覣覤覥覦覧覨覩親覫覬覭覮覯覰覱覲観覴覵覶覷覸覹覺覻覼覽覾覿觀见观觃规觅视觇览觉觊觋觌觍觎觏觐觑角觓觔觕觖觗觘觙觚觛觜觝觞觟觠觡觢解觤觥触觧觨觩觪觫觬觭觮觯觰觱觲觳觴觵觶觷觸觹觺觻觼觽觾觿言訁訂訃訄訅訆訇計訉訊訋訌訍討訏訐訑訒訓訔訕訖託記訙訚訛訜訝訞訟訠訡訢訣訤訥訦訧訨訩訪訫訬設訮訯訰許訲訳訴訵訶訷訸訹診註証訽訾訿詀詁詂詃詄詅詆詇詈詉詊詋詌詍詎詏詐詑詒詓詔評詖詗詘詙詚詛詜詝詞詟詠詡詢詣詤詥試詧詨詩詪詫詬詭詮詯詰話該詳詴詵詶詷詸詹詺詻詼詽詾詿誀誁誂誃誄誅誆誇誈誉誊誋誌認誎誏誐誑誒誓誔誕誖誗誘誙誚誛誜誝語誟誠誡誢誣誤誥誦誧誨誩說誫説読誮誯誰誱課誳誴誵誶誷誸誹誺誻誼誽誾調諀諁諂諃諄諅諆談諈諉諊請諌諍諎諏諐諑諒諓諔諕論諗諘諙諚諛諜諝諞諟諠諡諢諣諤諥諦諧諨諩諪諫諬諭諮諯諰諱諲諳諴諵諶諷諸諹諺諻諼諽諾諿謀謁謂謃謄謅謆謇謈謉謊謋謌謍謎謏謐謑謒謓謔謕謖謗謘謙謚講謜謝謞謟謠謡謢謣謤謥謦謧謨謩謪謫謬謭謮謯謰謱謲謳謴謵謶謷謸謹謺謻謼謽謾謿譀譁譂譃譄譅譆譇譈證譊譋譌譍譎譏譐譑譒譓譔譕譖譗識譙譚譛譜譝譞譟譠譡譢譣譤譥警譧譨譩譪譫譬譭譮譯議譱譲譳譴譵譶護譸譹譺譻譼譽譾譿讀讁讂讃讄讅讆讇讈讉變讋讌讍讎讏讐讑讒讓讔讕讖讗讘讙讚讛讜讝讞讟讠计订讣认讥讦讧讨让讪讫讬训议讯记讱讲讳讴讵讶讷许讹论讻讼讽设访诀证诂诃评诅识诇诈诉诊诋诌词诎诏诐译诒诓诔试诖诗诘诙诚诛诜话诞诟诠诡询诣诤该详诧诨诩诪诫诬语诮误诰诱诲诳说诵诶请诸诹诺读诼诽课诿谀谁谂调谄谅谆谇谈谉谊谋谌谍谎谏谐谑谒谓谔谕谖谗谘谙谚谛谜谝谞谟谠谡谢谣谤谥谦谧谨谩谪谫谬谭谮谯谰谱谲谳谴谵谶谷谸谹谺谻谼谽谾谿豀豁豂豃豄豅豆豇豈豉豊豋豌豍豎豏豐豑豒豓豔豕豖豗豘豙豚豛豜豝豞豟豠象豢豣豤豥豦豧豨豩豪豫豬豭豮豯豰豱豲豳豴豵豶豷豸豹豺豻豼豽豾豿貀貁貂貃貄貅貆貇貈貉貊貋貌貍貎貏貐貑貒貓貔貕貖貗貘貙貚貛貜貝貞貟負財貢貣貤貥貦貧貨販貪貫責貭貮貯貰貱貲貳貴貵貶買貸貹貺費貼貽貾貿賀賁賂賃賄賅賆資賈賉賊賋賌賍賎賏賐賑賒賓賔賕賖賗賘賙賚賛賜賝賞賟賠賡賢賣賤賥賦賧賨賩質賫賬賭賮賯賰賱賲賳賴賵賶賷賸賹賺賻購賽賾賿贀贁贂贃贄贅贆贇贈贉贊贋贌贍贎贏贐贑贒贓贔贕贖贗贘贙贚贛贜贝贞负贠贡财责贤败账货质贩贪贫贬购贮贯贰贱贲贳贴贵贶贷贸费贺贻贼贽贾贿赀赁赂赃资赅赆赇赈赉赊赋赌赍赎赏赐赑赒赓赔赕赖赗赘赙赚赛赜赝赞赟赠赡赢赣赤赥赦赧赨赩赪赫赬赭赮赯走赱赲赳赴赵赶起赸赹赺赻赼赽赾赿趀趁趂趃趄超趆趇趈趉越趋趌趍趎趏趐趑趒趓趔趕趖趗趘趙趚趛趜趝趞趟趠趡趢趣趤趥趦趧趨趩趪趫趬趭趮趯趰趱趲足趴趵趶趷趸趹趺趻趼趽趾趿跀跁跂跃跄跅跆跇跈跉跊跋跌跍跎跏跐跑跒跓跔跕跖跗跘跙跚跛跜距跞跟跠跡跢跣跤跥跦跧跨跩跪跫跬跭跮路跰跱跲跳跴践跶跷跸跹跺跻跼跽跾跿踀踁踂踃踄踅踆踇踈踉踊踋踌踍踎踏踐踑踒踓踔踕踖踗踘踙踚踛踜踝踞踟踠踡踢踣踤踥踦踧踨踩踪踫踬踭踮踯踰踱踲踳踴踵踶踷踸踹踺踻踼踽踾踿蹀蹁蹂蹃蹄蹅蹆蹇蹈蹉蹊蹋蹌蹍蹎蹏蹐蹑蹒蹓蹔蹕蹖蹗蹘蹙蹚蹛蹜蹝蹞蹟蹠蹡蹢蹣蹤蹥蹦蹧蹨蹩蹪蹫蹬蹭蹮蹯蹰蹱蹲蹳蹴蹵蹶蹷蹸蹹蹺蹻蹼蹽蹾蹿躀躁躂躃躄躅躆躇躈躉躊躋躌躍躎躏躐躑躒躓躔躕躖躗躘躙躚躛躜躝躞躟躠躡躢躣躤躥躦躧躨躩躪身躬躭躮躯躰躱躲躳躴躵躶躷躸躹躺躻躼躽躾躿軀軁軂軃軄軅軆軇軈軉車軋軌軍軎軏軐軑軒軓軔軕軖軗軘軙軚軛軜軝軞軟軠軡転軣軤軥軦軧軨軩軪軫軬軭軮軯軰軱軲軳軴軵軶軷軸軹軺軻軼軽軾軿輀輁輂較輄輅輆輇輈載輊輋輌輍輎輏輐輑輒輓輔輕輖輗輘輙輚輛輜輝輞輟輠輡輢輣輤輥輦輧輨輩輪輫輬輭輮輯輰輱輲輳輴輵輶輷輸輹輺輻輼輽輾輿轀轁轂轃轄轅轆轇轈轉轊轋轌轍轎轏轐轑轒轓轔轕轖轗轘轙轚轛轜轝轞轟轠轡轢轣轤轥车轧轨轩轪轫转轭轮软轰轱轲轳轴轵轶轷轸轹轺轻轼载轾轿辀辁辂较辄辅辆辇辈辉辊辋辌辍辎辏辐辑辒输辔辕辖辗辘辙辚辛辜辝辞辟辠辡辢辣辤辥辦辧辨辩辪辫辬辭辮辯辰辱農辳辴辵辶辷辸边辺辻込辽达辿迀迁迂迃迄迅迆过迈迉迊迋迌迍迎迏运近迒迓返迕迖迗还这迚进远违连迟迠迡迢迣迤迥迦迧迨迩迪迫迬迭迮迯述迱迲迳迴迵迶迷迸迹迺迻迼追迾迿退送适逃逄逅逆逇逈选逊逋逌逍逎透逐逑递逓途逕逖逗逘這通逛逜逝逞速造逡逢連逤逥逦逧逨逩逪逫逬逭逮逯逰週進逳逴逵逶逷逸逹逺逻逼逽逾逿遀遁遂遃遄遅遆遇遈遉遊運遌遍過遏遐遑遒道達違遖遗遘遙遚遛遜遝遞遟遠遡遢遣遤遥遦遧遨適遪遫遬遭遮遯遰遱遲遳遴遵遶遷選遹遺遻遼遽遾避邀邁邂邃還邅邆邇邈邉邊邋邌邍邎邏邐邑邒邓邔邕邖邗邘邙邚邛邜邝邞邟邠邡邢那邤邥邦邧邨邩邪邫邬邭邮邯邰邱邲邳邴邵邶邷邸邹邺邻邼邽邾邿郀郁郂郃郄郅郆郇郈郉郊郋郌郍郎郏郐郑郒郓郔郕郖郗郘郙郚郛郜郝郞郟郠郡郢郣郤郥郦郧部郩郪郫郬郭郮郯郰郱郲郳郴郵郶郷郸郹郺郻郼都郾郿鄀鄁鄂鄃鄄鄅鄆鄇鄈鄉鄊鄋鄌鄍鄎鄏鄐鄑鄒鄓鄔鄕鄖鄗鄘鄙鄚鄛鄜鄝鄞鄟鄠鄡鄢鄣鄤鄥鄦鄧鄨鄩鄪鄫鄬鄭鄮鄯鄰鄱鄲鄳鄴鄵鄶鄷鄸鄹鄺鄻鄼鄽鄾鄿酀酁酂酃酄酅酆酇酈酉酊酋酌配酎酏酐酑酒酓酔酕酖酗酘酙酚酛酜酝酞酟酠酡酢酣酤酥酦酧酨酩酪酫酬酭酮酯酰酱酲酳酴酵酶酷酸酹酺酻酼酽酾酿醀醁醂醃醄醅醆醇醈醉醊醋醌醍醎醏醐醑醒醓醔醕醖醗醘醙醚醛醜醝醞醟醠醡醢醣醤醥醦醧醨醩醪醫醬醭醮醯醰醱醲醳醴醵醶醷醸醹醺醻醼醽醾醿釀釁釂釃釄釅釆采釈釉释釋里重野量釐金釒釓釔釕釖釗釘釙釚釛釜針釞釟釠釡釢釣釤釥釦釧釨釩釪釫釬釭釮釯釰釱釲釳釴釵釶釷釸釹釺釻釼釽釾釿鈀鈁鈂鈃鈄鈅鈆鈇鈈鈉鈊鈋鈌鈍鈎鈏鈐鈑鈒鈓鈔鈕鈖鈗鈘鈙鈚鈛鈜鈝鈞鈟鈠鈡鈢鈣鈤鈥鈦鈧鈨鈩鈪鈫鈬鈭鈮鈯鈰鈱鈲鈳鈴鈵鈶鈷鈸鈹鈺鈻鈼鈽鈾鈿鉀鉁鉂鉃鉄鉅鉆鉇鉈鉉鉊鉋鉌鉍鉎鉏鉐鉑鉒鉓鉔鉕鉖鉗鉘鉙鉚鉛鉜鉝鉞鉟鉠鉡鉢鉣鉤鉥鉦鉧鉨鉩鉪鉫鉬鉭鉮鉯鉰鉱鉲鉳鉴鉵鉶鉷鉸鉹鉺鉻鉼鉽鉾鉿銀銁銂銃銄銅銆銇銈銉銊銋銌銍銎銏銐銑銒銓銔銕銖銗銘銙銚銛銜銝銞銟銠銡銢銣銤銥銦銧銨銩銪銫銬銭銮銯銰銱銲銳銴銵銶銷銸銹銺銻銼銽銾銿鋀鋁鋂鋃鋄鋅鋆鋇鋈鋉鋊鋋鋌鋍鋎鋏鋐鋑鋒鋓鋔鋕鋖鋗鋘鋙鋚鋛鋜鋝鋞鋟鋠鋡鋢鋣鋤鋥鋦鋧鋨鋩鋪鋫鋬鋭鋮鋯鋰鋱鋲鋳鋴鋵鋶鋷鋸鋹鋺鋻鋼鋽鋾鋿錀錁錂錃錄錅錆錇錈錉錊錋錌錍錎錏錐錑錒錓錔錕錖錗錘錙錚錛錜錝錞錟錠錡錢錣錤錥錦錧錨錩錪錫錬錭錮錯錰錱録錳錴錵錶錷錸錹錺錻錼錽錾錿鍀鍁鍂鍃鍄鍅鍆鍇鍈鍉鍊鍋鍌鍍鍎鍏鍐鍑鍒鍓鍔鍕鍖鍗鍘鍙鍚鍛鍜鍝鍞鍟鍠鍡鍢鍣鍤鍥鍦鍧鍨鍩鍪鍫鍬鍭鍮鍯鍰鍱鍲鍳鍴鍵鍶鍷鍸鍹鍺鍻鍼鍽鍾鍿鎀鎁鎂鎃鎄鎅鎆鎇鎈鎉鎊鎋鎌鎍鎎鎏鎐鎑鎒鎓鎔鎕鎖鎗鎘鎙鎚鎛鎜鎝鎞鎟鎠鎡鎢鎣鎤鎥鎦鎧鎨鎩鎪鎫鎬鎭鎮鎯鎰鎱鎲鎳鎴鎵鎶鎷鎸鎹鎺鎻鎼鎽鎾鎿鏀鏁鏂鏃鏄鏅鏆鏇鏈鏉鏊鏋鏌鏍鏎鏏鏐鏑鏒鏓鏔鏕鏖鏗鏘鏙鏚鏛鏜鏝鏞鏟鏠鏡鏢鏣鏤鏥鏦鏧鏨鏩鏪鏫鏬鏭鏮鏯鏰鏱鏲鏳鏴鏵鏶鏷鏸鏹鏺鏻鏼鏽鏾鏿鐀鐁鐂鐃鐄鐅鐆鐇鐈鐉鐊鐋鐌鐍鐎鐏鐐鐑鐒鐓鐔鐕鐖鐗鐘鐙鐚鐛鐜鐝鐞鐟鐠鐡鐢鐣鐤鐥鐦鐧鐨鐩鐪鐫鐬鐭鐮鐯鐰鐱鐲鐳鐴鐵鐶鐷鐸鐹鐺鐻鐼鐽鐾鐿鑀鑁鑂鑃鑄鑅鑆鑇鑈鑉鑊鑋鑌鑍鑎鑏鑐鑑鑒鑓鑔鑕鑖鑗鑘鑙鑚鑛鑜鑝鑞鑟鑠鑡鑢鑣鑤鑥鑦鑧鑨鑩鑪鑫鑬鑭鑮鑯鑰鑱鑲鑳鑴鑵鑶鑷鑸鑹鑺鑻鑼鑽鑾鑿钀钁钂钃钄钅钆钇针钉钊钋钌钍钎钏钐钑钒钓钔钕钖钗钘钙钚钛钜钝钞钟钠钡钢钣钤钥钦钧钨钩钪钫钬钭钮钯钰钱钲钳钴钵钶钷钸钹钺钻钼钽钾钿铀铁铂铃铄铅铆铇铈铉铊铋铌铍铎铏铐铑铒铓铔铕铖铗铘铙铚铛铜铝铞铟铠铡铢铣铤铥铦铧铨铩铪铫铬铭铮铯铰铱铲铳铴铵银铷铸铹铺铻铼铽链铿销锁锂锃锄锅锆锇锈锉锊锋锌锍锎锏锐锑锒锓锔锕锖锗锘错锚锛锜锝锞锟锠锡锢锣锤锥锦锧锨锩锪锫锬锭键锯锰锱锲锳锴锵锶锷锸锹锺锻锼锽锾锿镀镁镂镃镄镅镆镇镈镉镊镋镌镍镎镏镐镑镒镓镔镕镖镗镘镙镚镛镜镝镞镟镠镡镢镣镤镥镦镧镨镩镪镫镬镭镮镯镰镱镲镳镴镵镶長镸镹镺镻镼镽镾长門閁閂閃閄閅閆閇閈閉閊開閌閍閎閏閐閑閒間閔閕閖閗閘閙閚閛閜閝閞閟閠閡関閣閤閥閦閧閨閩閪閫閬閭閮閯閰閱閲閳閴閵閶閷閸閹閺閻閼閽閾閿闀闁闂闃闄闅闆闇闈闉闊闋闌闍闎闏闐闑闒闓闔闕闖闗闘闙闚闛關闝闞闟闠闡闢闣闤闥闦闧门闩闪闫闬闭问闯闰闱闲闳间闵闶闷闸闹闺闻闼闽闾闿阀阁阂阃阄阅阆阇阈阉阊阋阌阍阎阏阐阑阒阓阔阕阖阗阘阙阚阛阜阝阞队阠阡阢阣阤阥阦阧阨阩阪阫阬阭阮阯阰阱防阳阴阵阶阷阸阹阺阻阼阽阾阿陀陁陂陃附际陆陇陈陉陊陋陌降陎陏限陑陒陓陔陕陖陗陘陙陚陛陜陝陞陟陠陡院陣除陥陦陧陨险陪陫陬陭陮陯陰陱陲陳陴陵陶陷陸陹険陻陼陽陾陿隀隁隂隃隄隅隆隇隈隉隊隋隌隍階随隐隑隒隓隔隕隖隗隘隙隚際障隝隞隟隠隡隢隣隤隥隦隧隨隩險隫隬隭隮隯隰隱隲隳隴隵隶隷隸隹隺隻隼隽难隿雀雁雂雃雄雅集雇雈雉雊雋雌雍雎雏雐雑雒雓雔雕雖雗雘雙雚雛雜雝雞雟雠雡離難雤雥雦雧雨雩雪雫雬雭雮雯雰雱雲雳雴雵零雷雸雹雺電雼雽雾雿需霁霂霃霄霅霆震霈霉霊霋霌霍霎霏霐霑霒霓霔霕霖霗霘霙霚霛霜霝霞霟霠霡霢霣霤霥霦霧霨霩霪霫霬霭霮霯霰霱露霳霴霵霶霷霸霹霺霻霼霽霾霿靀靁靂靃靄靅靆靇靈靉靊靋靌靍靎靏靐靑青靓靔靕靖靗靘静靚靛靜靝非靟靠靡面靣靤靥靦靧靨革靪靫靬靭靮靯靰靱靲靳靴靵靶靷靸靹靺靻靼靽靾靿鞀鞁鞂鞃鞄鞅鞆鞇鞈鞉鞊鞋鞌鞍鞎鞏鞐鞑鞒鞓鞔鞕鞖鞗鞘鞙鞚鞛鞜鞝鞞鞟鞠鞡鞢鞣鞤鞥鞦鞧鞨鞩鞪鞫鞬鞭鞮鞯鞰鞱鞲鞳鞴鞵鞶鞷鞸鞹鞺鞻鞼鞽鞾鞿韀韁韂韃韄韅韆韇韈韉韊韋韌韍韎韏韐韑韒韓韔韕韖韗韘韙韚韛韜韝韞韟韠韡韢韣韤韥韦韧韨韩韪韫韬韭韮韯韰韱韲音韴韵韶韷韸韹韺韻韼韽韾響頀頁頂頃頄項順頇須頉頊頋頌頍頎頏預頑頒頓頔頕頖頗領頙頚頛頜頝頞頟頠頡頢頣頤頥頦頧頨頩頪頫頬頭頮頯頰頱頲頳頴頵頶頷頸頹頺頻頼頽頾頿顀顁顂顃顄顅顆顇顈顉顊顋題額顎顏顐顑顒顓顔顕顖顗願顙顚顛顜顝類顟顠顡顢顣顤顥顦顧顨顩顪顫顬顭顮顯顰顱顲顳顴页顶顷顸项顺须顼顽顾顿颀颁颂颃预颅领颇颈颉颊颋颌颍颎颏颐频颒颓颔颕颖颗题颙颚颛颜额颞颟颠颡颢颣颤颥颦颧風颩颪颫颬颭颮颯颰颱颲颳颴颵颶颷颸颹颺颻颼颽颾颿飀飁飂飃飄飅飆飇飈飉飊飋飌飍风飏飐飑飒飓飔飕飖飗飘飙飚飛飜飝飞食飠飡飢飣飤飥飦飧飨飩飪飫飬飭飮飯飰飱飲飳飴飵飶飷飸飹飺飻飼飽飾飿餀餁餂餃餄餅餆餇餈餉養餋餌餍餎餏餐餑餒餓餔餕餖餗餘餙餚餛餜餝餞餟餠餡餢餣餤餥餦餧館餩餪餫餬餭餮餯餰餱餲餳餴餵餶餷餸餹餺餻餼餽餾餿饀饁饂饃饄饅饆饇饈饉饊饋饌饍饎饏饐饑饒饓饔饕饖饗饘饙饚饛饜饝饞饟饠饡饢饣饤饥饦饧饨饩饪饫饬饭饮饯饰饱饲饳饴饵饶饷饸饹饺饻饼饽饾饿馀馁馂馃馄馅馆馇馈馉馊馋馌馍馎馏馐馑馒馓馔馕首馗馘香馚馛馜馝馞馟馠馡馢馣馤馥馦馧馨馩馪馫馬馭馮馯馰馱馲馳馴馵馶馷馸馹馺馻馼馽馾馿駀駁駂駃駄駅駆駇駈駉駊駋駌駍駎駏駐駑駒駓駔駕駖駗駘駙駚駛駜駝駞駟駠駡駢駣駤駥駦駧駨駩駪駫駬駭駮駯駰駱駲駳駴駵駶駷駸駹駺駻駼駽駾駿騀騁騂騃騄騅騆騇騈騉騊騋騌騍騎騏騐騑騒験騔騕騖騗騘騙騚騛騜騝騞騟騠騡騢騣騤騥騦騧騨騩騪騫騬騭騮騯騰騱騲騳騴騵騶騷騸騹騺騻騼騽騾騿驀驁驂驃驄驅驆驇驈驉驊驋驌驍驎驏驐驑驒驓驔驕驖驗驘驙驚驛驜驝驞驟驠驡驢驣驤驥驦驧驨驩驪驫马驭驮驯驰驱驲驳驴驵驶驷驸驹驺驻驼驽驾驿骀骁骂骃骄骅骆骇骈骉骊骋验骍骎骏骐骑骒骓骔骕骖骗骘骙骚骛骜骝骞骟骠骡骢骣骤骥骦骧骨骩骪骫骬骭骮骯骰骱骲骳骴骵骶骷骸骹骺骻骼骽骾骿髀髁髂髃髄髅髆髇髈髉髊髋髌髍髎髏髐髑髒髓體髕髖髗高髙髚髛髜髝髞髟髠髡髢髣髤髥髦髧髨髩髪髫髬髭髮髯髰髱髲髳髴髵髶髷髸髹髺髻髼髽髾髿鬀鬁鬂鬃鬄鬅鬆鬇鬈鬉鬊鬋鬌鬍鬎鬏鬐鬑鬒鬓鬔鬕鬖鬗鬘鬙鬚鬛鬜鬝鬞鬟鬠鬡鬢鬣鬤鬥鬦鬧鬨鬩鬪鬫鬬鬭鬮鬯鬰鬱鬲鬳鬴鬵鬶鬷鬸鬹鬺鬻鬼鬽鬾鬿魀魁魂魃魄魅魆魇魈魉魊魋魌魍魎魏魐魑魒魓魔魕魖魗魘魙魚魛魜魝魞魟魠魡魢魣魤魥魦魧魨魩魪魫魬魭魮魯魰魱魲魳魴魵魶魷魸魹魺魻魼魽魾魿鮀鮁鮂鮃鮄鮅鮆鮇鮈鮉鮊鮋鮌鮍鮎鮏鮐鮑鮒鮓鮔鮕鮖鮗鮘鮙鮚鮛鮜鮝鮞鮟鮠鮡鮢鮣鮤鮥鮦鮧鮨鮩鮪鮫鮬鮭鮮鮯鮰鮱鮲鮳鮴鮵鮶鮷鮸鮹鮺鮻鮼鮽鮾鮿鯀鯁鯂鯃鯄鯅鯆鯇鯈鯉鯊鯋鯌鯍鯎鯏鯐鯑鯒鯓鯔鯕鯖鯗鯘鯙鯚鯛鯜鯝鯞鯟鯠鯡鯢鯣鯤鯥鯦鯧鯨鯩鯪鯫鯬鯭鯮鯯鯰鯱鯲鯳鯴鯵鯶鯷鯸鯹鯺鯻鯼鯽鯾鯿鰀鰁鰂鰃鰄鰅鰆鰇鰈鰉鰊鰋鰌鰍鰎鰏鰐鰑鰒鰓鰔鰕鰖鰗鰘鰙鰚鰛鰜鰝鰞鰟鰠鰡鰢鰣鰤鰥鰦鰧鰨鰩鰪鰫鰬鰭鰮鰯鰰鰱鰲鰳鰴鰵鰶鰷鰸鰹鰺鰻鰼鰽鰾鰿鱀鱁鱂鱃鱄鱅鱆鱇鱈鱉鱊鱋鱌鱍鱎鱏鱐鱑鱒鱓鱔鱕鱖鱗鱘鱙鱚鱛鱜鱝鱞鱟鱠鱡鱢鱣鱤鱥鱦鱧鱨鱩鱪鱫鱬鱭鱮鱯鱰鱱鱲鱳鱴鱵鱶鱷鱸鱹鱺鱻鱼鱽鱾鱿鲀鲁鲂鲃鲄鲅鲆鲇鲈鲉鲊鲋鲌鲍鲎鲏鲐鲑鲒鲓鲔鲕鲖鲗鲘鲙鲚鲛鲜鲝鲞鲟鲠鲡鲢鲣鲤鲥鲦鲧鲨鲩鲪鲫鲬鲭鲮鲯鲰鲱鲲鲳鲴鲵鲶鲷鲸鲹鲺鲻鲼鲽鲾鲿鳀鳁鳂鳃鳄鳅鳆鳇鳈鳉鳊鳋鳌鳍鳎鳏鳐鳑鳒鳓鳔鳕鳖鳗鳘鳙鳚鳛鳜鳝鳞鳟鳠鳡鳢鳣鳤鳥鳦鳧鳨鳩鳪鳫鳬鳭鳮鳯鳰鳱鳲鳳鳴鳵鳶鳷鳸鳹鳺鳻鳼鳽鳾鳿鴀鴁鴂鴃鴄鴅鴆鴇鴈鴉鴊鴋鴌鴍鴎鴏鴐鴑鴒鴓鴔鴕鴖鴗鴘鴙鴚鴛鴜鴝鴞鴟鴠鴡鴢鴣鴤鴥鴦鴧鴨鴩鴪鴫鴬鴭鴮鴯鴰鴱鴲鴳鴴鴵鴶鴷鴸鴹鴺鴻鴼鴽鴾鴿鵀鵁鵂鵃鵄鵅鵆鵇鵈鵉鵊鵋鵌鵍鵎鵏鵐鵑鵒鵓鵔鵕鵖鵗鵘鵙鵚鵛鵜鵝鵞鵟鵠鵡鵢鵣鵤鵥鵦鵧鵨鵩鵪鵫鵬鵭鵮鵯鵰鵱鵲鵳鵴鵵鵶鵷鵸鵹鵺鵻鵼鵽鵾鵿鶀鶁鶂鶃鶄鶅鶆鶇鶈鶉鶊鶋鶌鶍鶎鶏鶐鶑鶒鶓鶔鶕鶖鶗鶘鶙鶚鶛鶜鶝鶞鶟鶠鶡鶢鶣鶤鶥鶦鶧鶨鶩鶪鶫鶬鶭鶮鶯鶰鶱鶲鶳鶴鶵鶶鶷鶸鶹鶺鶻鶼鶽鶾鶿鷀鷁鷂鷃鷄鷅鷆鷇鷈鷉鷊鷋鷌鷍鷎鷏鷐鷑鷒鷓鷔鷕鷖鷗鷘鷙鷚鷛鷜鷝鷞鷟鷠鷡鷢鷣鷤鷥鷦鷧鷨鷩鷪鷫鷬鷭鷮鷯鷰鷱鷲鷳鷴鷵鷶鷷鷸鷹鷺鷻鷼鷽鷾鷿鸀鸁鸂鸃鸄鸅鸆鸇鸈鸉鸊鸋鸌鸍鸎鸏鸐鸑鸒鸓鸔鸕鸖鸗鸘鸙鸚鸛鸜鸝鸞鸟鸠鸡鸢鸣鸤鸥鸦鸧鸨鸩鸪鸫鸬鸭鸮鸯鸰鸱鸲鸳鸴鸵鸶鸷鸸鸹鸺鸻鸼鸽鸾鸿鹀鹁鹂鹃鹄鹅鹆鹇鹈鹉鹊鹋鹌鹍鹎鹏鹐鹑鹒鹓鹔鹕鹖鹗鹘鹙鹚鹛鹜鹝鹞鹟鹠鹡鹢鹣鹤鹥鹦鹧鹨鹩鹪鹫鹬鹭鹮鹯鹰鹱鹲鹳鹴鹵鹶鹷鹸鹹鹺鹻鹼鹽鹾鹿麀麁麂麃麄麅麆麇麈麉麊麋麌麍麎麏麐麑麒麓麔麕麖麗麘麙麚麛麜麝麞麟麠麡麢麣麤麥麦麧麨麩麪麫麬麭麮麯麰麱麲麳麴麵麶麷麸麹麺麻麼麽麾麿黀黁黂黃黄黅黆黇黈黉黊黋黌黍黎黏黐黑黒黓黔黕黖黗默黙黚黛黜黝點黟黠黡黢黣黤黥黦黧黨黩黪黫黬黭黮黯黰黱黲黳黴黵黶黷黸黹黺黻黼黽黾黿鼀鼁鼂鼃鼄鼅鼆鼇鼈鼉鼊鼋鼌鼍鼎鼏鼐鼑鼒鼓鼔鼕鼖鼗鼘鼙鼚鼛鼜鼝鼞鼟鼠鼡鼢鼣鼤鼥鼦鼧鼨鼩鼪鼫鼬鼭鼮鼯鼰鼱鼲鼳鼴鼵鼶鼷鼸鼹鼺鼻鼼鼽鼾鼿齀齁齂齃齄齅齆齇齈齉齊齋齌齍齎齏齐齑齒齓齔齕齖齗齘齙齚齛齜齝齞齟齠齡齢齣齤齥齦齧齨齩齪齫齬齭齮齯齰齱齲齳齴齵齶齷齸齹齺齻齼齽齾齿龀龁龂龃龄龅龆龇龈龉龊龋龌龍龎龏龐龑龒龓龔龕龖龗龘龙龚龛龜龝龞龟龠龡龢龣龤龥龦龧龨龩龪龫龬龭龮龯龰龱龲龳龴龵龶龷龸龹龺龻龼龽龾龿鿀鿁鿂鿃鿄鿅鿆鿇鿈鿉鿊鿋鿌ꀀꀁꀂꀃꀄꀅꀆꀇꀈꀉꀊꀋꀌꀍꀎꀏꀐꀑꀒꀓꀔꀕꀖꀗꀘꀙꀚꀛꀜꀝꀞꀟꀠꀡꀢꀣꀤꀥꀦꀧꀨꀩꀪꀫꀬꀭꀮꀯꀰꀱꀲꀳꀴꀵꀶꀷꀸꀹꀺꀻꀼꀽꀾꀿꁀꁁꁂꁃꁄꁅꁆꁇꁈꁉꁊꁋꁌꁍꁎꁏꁐꁑꁒꁓꁔꁕꁖꁗꁘꁙꁚꁛꁜꁝꁞꁟꁠꁡꁢꁣꁤꁥꁦꁧꁨꁩꁪꁫꁬꁭꁮꁯꁰꁱꁲꁳꁴꁵꁶꁷꁸꁹꁺꁻꁼꁽꁾꁿꂀꂁꂂꂃꂄꂅꂆꂇꂈꂉꂊꂋꂌꂍꂎꂏꂐꂑꂒꂓꂔꂕꂖꂗꂘꂙꂚꂛꂜꂝꂞꂟꂠꂡꂢꂣꂤꂥꂦꂧꂨꂩꂪꂫꂬꂭꂮꂯꂰꂱꂲꂳꂴꂵꂶꂷꂸꂹꂺꂻꂼꂽꂾꂿꃀꃁꃂꃃꃄꃅꃆꃇꃈꃉꃊꃋꃌꃍꃎꃏꃐꃑꃒꃓꃔꃕꃖꃗꃘꃙꃚꃛꃜꃝꃞꃟꃠꃡꃢꃣꃤꃥꃦꃧꃨꃩꃪꃫꃬꃭꃮꃯꃰꃱꃲꃳꃴꃵꃶꃷꃸꃹꃺꃻꃼꃽꃾꃿꄀꄁꄂꄃꄄꄅꄆꄇꄈꄉꄊꄋꄌꄍꄎꄏꄐꄑꄒꄓꄔꄕꄖꄗꄘꄙꄚꄛꄜꄝꄞꄟꄠꄡꄢꄣꄤꄥꄦꄧꄨꄩꄪꄫꄬꄭꄮꄯꄰꄱꄲꄳꄴꄵꄶꄷꄸꄹꄺꄻꄼꄽꄾꄿꅀꅁꅂꅃꅄꅅꅆꅇꅈꅉꅊꅋꅌꅍꅎꅏꅐꅑꅒꅓꅔꅕꅖꅗꅘꅙꅚꅛꅜꅝꅞꅟꅠꅡꅢꅣꅤꅥꅦꅧꅨꅩꅪꅫꅬꅭꅮꅯꅰꅱꅲꅳꅴꅵꅶꅷꅸꅹꅺꅻꅼꅽꅾꅿꆀꆁꆂꆃꆄꆅꆆꆇꆈꆉꆊꆋꆌꆍꆎꆏꆐꆑꆒꆓꆔꆕꆖꆗꆘꆙꆚꆛꆜꆝꆞꆟꆠꆡꆢꆣꆤꆥꆦꆧꆨꆩꆪꆫꆬꆭꆮꆯꆰꆱꆲꆳꆴꆵꆶꆷꆸꆹꆺꆻꆼꆽꆾꆿꇀꇁꇂꇃꇄꇅꇆꇇꇈꇉꇊꇋꇌꇍꇎꇏꇐꇑꇒꇓꇔꇕꇖꇗꇘꇙꇚꇛꇜꇝꇞꇟꇠꇡꇢꇣꇤꇥꇦꇧꇨꇩꇪꇫꇬꇭꇮꇯꇰꇱꇲꇳꇴꇵꇶꇷꇸꇹꇺꇻꇼꇽꇾꇿꈀꈁꈂꈃꈄꈅꈆꈇꈈꈉꈊꈋꈌꈍꈎꈏꈐꈑꈒꈓꈔꈕꈖꈗꈘꈙꈚꈛꈜꈝꈞꈟꈠꈡꈢꈣꈤꈥꈦꈧꈨꈩꈪꈫꈬꈭꈮꈯꈰꈱꈲꈳꈴꈵꈶꈷꈸꈹꈺꈻꈼꈽꈾꈿꉀꉁꉂꉃꉄꉅꉆꉇꉈꉉꉊꉋꉌꉍꉎꉏꉐꉑꉒꉓꉔꉕꉖꉗꉘꉙꉚꉛꉜꉝꉞꉟꉠꉡꉢꉣꉤꉥꉦꉧꉨꉩꉪꉫꉬꉭꉮꉯꉰꉱꉲꉳꉴꉵꉶꉷꉸꉹꉺꉻꉼꉽꉾꉿꊀꊁꊂꊃꊄꊅꊆꊇꊈꊉꊊꊋꊌꊍꊎꊏꊐꊑꊒꊓꊔꊕꊖꊗꊘꊙꊚꊛꊜꊝꊞꊟꊠꊡꊢꊣꊤꊥꊦꊧꊨꊩꊪꊫꊬꊭꊮꊯꊰꊱꊲꊳꊴꊵꊶꊷꊸꊹꊺꊻꊼꊽꊾꊿꋀꋁꋂꋃꋄꋅꋆꋇꋈꋉꋊꋋꋌꋍꋎꋏꋐꋑꋒꋓꋔꋕꋖꋗꋘꋙꋚꋛꋜꋝꋞꋟꋠꋡꋢꋣꋤꋥꋦꋧꋨꋩꋪꋫꋬꋭꋮꋯꋰꋱꋲꋳꋴꋵꋶꋷꋸꋹꋺꋻꋼꋽꋾꋿꌀꌁꌂꌃꌄꌅꌆꌇꌈꌉꌊꌋꌌꌍꌎꌏꌐꌑꌒꌓꌔꌕꌖꌗꌘꌙꌚꌛꌜꌝꌞꌟꌠꌡꌢꌣꌤꌥꌦꌧꌨꌩꌪꌫꌬꌭꌮꌯꌰꌱꌲꌳꌴꌵꌶꌷꌸꌹꌺꌻꌼꌽꌾꌿꍀꍁꍂꍃꍄꍅꍆꍇꍈꍉꍊꍋꍌꍍꍎꍏꍐꍑꍒꍓꍔꍕꍖꍗꍘꍙꍚꍛꍜꍝꍞꍟꍠꍡꍢꍣꍤꍥꍦꍧꍨꍩꍪꍫꍬꍭꍮꍯꍰꍱꍲꍳꍴꍵꍶꍷꍸꍹꍺꍻꍼꍽꍾꍿꎀꎁꎂꎃꎄꎅꎆꎇꎈꎉꎊꎋꎌꎍꎎꎏꎐꎑꎒꎓꎔꎕꎖꎗꎘꎙꎚꎛꎜꎝꎞꎟꎠꎡꎢꎣꎤꎥꎦꎧꎨꎩꎪꎫꎬꎭꎮꎯꎰꎱꎲꎳꎴꎵꎶꎷꎸꎹꎺꎻꎼꎽꎾꎿꏀꏁꏂꏃꏄꏅꏆꏇꏈꏉꏊꏋꏌꏍꏎꏏꏐꏑꏒꏓꏔꏕꏖꏗꏘꏙꏚꏛꏜꏝꏞꏟꏠꏡꏢꏣꏤꏥꏦꏧꏨꏩꏪꏫꏬꏭꏮꏯꏰꏱꏲꏳꏴꏵꏶꏷꏸꏹꏺꏻꏼꏽꏾꏿꐀꐁꐂꐃꐄꐅꐆꐇꐈꐉꐊꐋꐌꐍꐎꐏꐐꐑꐒꐓꐔꐕꐖꐗꐘꐙꐚꐛꐜꐝꐞꐟꐠꐡꐢꐣꐤꐥꐦꐧꐨꐩꐪꐫꐬꐭꐮꐯꐰꐱꐲꐳꐴꐵꐶꐷꐸꐹꐺꐻꐼꐽꐾꐿꑀꑁꑂꑃꑄꑅꑆꑇꑈꑉꑊꑋꑌꑍꑎꑏꑐꑑꑒꑓꑔꑕꑖꑗꑘꑙꑚꑛꑜꑝꑞꑟꑠꑡꑢꑣꑤꑥꑦꑧꑨꑩꑪꑫꑬꑭꑮꑯꑰꑱꑲꑳꑴꑵꑶꑷꑸꑹꑺꑻꑼꑽꑾꑿꒀꒁꒂꒃꒄꒅꒆꒇꒈꒉꒊꒋꒌ꒐꒑꒒꒓꒔꒕꒖꒗꒘꒙꒚꒛꒜꒝꒞꒟꒠꒡꒢꒣꒤꒥꒦꒧꒨꒩꒪꒫꒬꒭꒮꒯꒰꒱꒲꒳꒴꒵꒶꒷꒸꒹꒺꒻꒼꒽꒾꒿꓀꓁꓂꓃꓄꓅꓆ꓐꓑꓒꓓꓔꓕꓖꓗꓘꓙꓚꓛꓜꓝꓞꓟꓠꓡꓢꓣꓤꓥꓦꓧꓨꓩꓪꓫꓬꓭꓮꓯꓰꓱꓲꓳꓴꓵꓶꓷꓸꓹꓺꓻꓼꓽ꓾꓿ꔀꔁꔂꔃꔄꔅꔆꔇꔈꔉꔊꔋꔌꔍꔎꔏꔐꔑꔒꔓꔔꔕꔖꔗꔘꔙꔚꔛꔜꔝꔞꔟꔠꔡꔢꔣꔤꔥꔦꔧꔨꔩꔪꔫꔬꔭꔮꔯꔰꔱꔲꔳꔴꔵꔶꔷꔸꔹꔺꔻꔼꔽꔾꔿꕀꕁꕂꕃꕄꕅꕆꕇꕈꕉꕊꕋꕌꕍꕎꕏꕐꕑꕒꕓꕔꕕꕖꕗꕘꕙꕚꕛꕜꕝꕞꕟꕠꕡꕢꕣꕤꕥꕦꕧꕨꕩꕪꕫꕬꕭꕮꕯꕰꕱꕲꕳꕴꕵꕶꕷꕸꕹꕺꕻꕼꕽꕾꕿꖀꖁꖂꖃꖄꖅꖆꖇꖈꖉꖊꖋꖌꖍꖎꖏꖐꖑꖒꖓꖔꖕꖖꖗꖘꖙꖚꖛꖜꖝꖞꖟꖠꖡꖢꖣꖤꖥꖦꖧꖨꖩꖪꖫꖬꖭꖮꖯꖰꖱꖲꖳꖴꖵꖶꖷꖸꖹꖺꖻꖼꖽꖾꖿꗀꗁꗂꗃꗄꗅꗆꗇꗈꗉꗊꗋꗌꗍꗎꗏꗐꗑꗒꗓꗔꗕꗖꗗꗘꗙꗚꗛꗜꗝꗞꗟꗠꗡꗢꗣꗤꗥꗦꗧꗨꗩꗪꗫꗬꗭꗮꗯꗰꗱꗲꗳꗴꗵꗶꗷꗸꗹꗺꗻꗼꗽꗾꗿꘀꘁꘂꘃꘄꘅꘆꘇꘈꘉꘊꘋꘌ꘍꘎꘏ꘐꘑꘒꘓꘔꘕꘖꘗꘘꘙꘚꘛꘜꘝꘞꘟ꘠꘡꘢꘣꘤꘥꘦꘧꘨꘩ꘪꘫꙀꙁꙂꙃꙄꙅꙆꙇꙈꙉꙊꙋꙌꙍꙎꙏꙐꙑꙒꙓꙔꙕꙖꙗꙘꙙꙚꙛꙜꙝꙞꙟꙠꙡꙢꙣꙤꙥꙦꙧꙨꙩꙪꙫꙬꙭꙮ꙯꙰꙱꙲꙳ꙴꙵꙶꙷꙸꙹꙺꙻ꙼꙽꙾ꙿꚀꚁꚂꚃꚄꚅꚆꚇꚈꚉꚊꚋꚌꚍꚎꚏꚐꚑꚒꚓꚔꚕꚖꚗꚟꚠꚡꚢꚣꚤꚥꚦꚧꚨꚩꚪꚫꚬꚭꚮꚯꚰꚱꚲꚳꚴꚵꚶꚷꚸꚹꚺꚻꚼꚽꚾꚿꛀꛁꛂꛃꛄꛅꛆꛇꛈꛉꛊꛋꛌꛍꛎꛏꛐꛑꛒꛓꛔꛕꛖꛗꛘꛙꛚꛛꛜꛝꛞꛟꛠꛡꛢꛣꛤꛥꛦꛧꛨꛩꛪꛫꛬꛭꛮꛯ꛰꛱꛲꛳꛴꛵꛶꛷꜀꜁꜂꜃꜄꜅꜆꜇꜈꜉꜊꜋꜌꜍꜎꜏꜐꜑꜒꜓꜔꜕꜖ꜗꜘꜙꜚꜛꜜꜝꜞꜟ꜠꜡ꜢꜣꜤꜥꜦꜧꜨꜩꜪꜫꜬꜭꜮꜯꜰꜱꜲꜳꜴꜵꜶꜷꜸꜹꜺꜻꜼꜽꜾꜿꝀꝁꝂꝃꝄꝅꝆꝇꝈꝉꝊꝋꝌꝍꝎꝏꝐꝑꝒꝓꝔꝕꝖꝗꝘꝙꝚꝛꝜꝝꝞꝟꝠꝡꝢꝣꝤꝥꝦꝧꝨꝩꝪꝫꝬꝭꝮꝯꝰꝱꝲꝳꝴꝵꝶꝷꝸꝹꝺꝻꝼꝽꝾꝿꞀꞁꞂꞃꞄꞅꞆꞇꞈ꞉꞊ꞋꞌꞍꞎꞐꞑꞒꞓꞠꞡꞢꞣꞤꞥꞦꞧꞨꞩꞪꟸꟹꟺꟻꟼꟽꟾꟿꠀꠁꠂꠃꠄꠅ꠆ꠇꠈꠉꠊꠋꠌꠍꠎꠏꠐꠑꠒꠓꠔꠕꠖꠗꠘꠙꠚꠛꠜꠝꠞꠟꠠꠡꠢꠣꠤꠥꠦꠧ꠨꠩꠪꠫꠰꠱꠲꠳꠴꠵꠶꠷꠸꠹ꡀꡁꡂꡃꡄꡅꡆꡇꡈꡉꡊꡋꡌꡍꡎꡏꡐꡑꡒꡓꡔꡕꡖꡗꡘꡙꡚꡛꡜꡝꡞꡟꡠꡡꡢꡣꡤꡥꡦꡧꡨꡩꡪꡫꡬꡭꡮꡯꡰꡱꡲꡳ꡴꡵꡶꡷ꢀꢁꢂꢃꢄꢅꢆꢇꢈꢉꢊꢋꢌꢍꢎꢏꢐꢑꢒꢓꢔꢕꢖꢗꢘꢙꢚꢛꢜꢝꢞꢟꢠꢡꢢꢣꢤꢥꢦꢧꢨꢩꢪꢫꢬꢭꢮꢯꢰꢱꢲꢳꢴꢵꢶꢷꢸꢹꢺꢻꢼꢽꢾꢿꣀꣁꣂꣃ꣄꣎꣏꣐꣑꣒꣓꣔꣕꣖꣗꣘꣙꣠꣡꣢꣣꣤꣥꣦꣧꣨꣩꣪꣫꣬꣭꣮꣯꣰꣱ꣲꣳꣴꣵꣶꣷ꣸꣹꣺ꣻ꤀꤁꤂꤃꤄꤅꤆꤇꤈꤉ꤊꤋꤌꤍꤎꤏꤐꤑꤒꤓꤔꤕꤖꤗꤘꤙꤚꤛꤜꤝꤞꤟꤠꤡꤢꤣꤤꤥꤦꤧꤨꤩꤪ꤫꤬꤭꤮꤯ꤰꤱꤲꤳꤴꤵꤶꤷꤸꤹꤺꤻꤼꤽꤾꤿꥀꥁꥂꥃꥄꥅꥆꥇꥈꥉꥊꥋꥌꥍꥎꥏꥐꥑꥒ꥓꥟ꥠꥡꥢꥣꥤꥥꥦꥧꥨꥩꥪꥫꥬꥭꥮꥯꥰꥱꥲꥳꥴꥵꥶꥷꥸꥹꥺꥻꥼꦀꦁꦂꦃꦄꦅꦆꦇꦈꦉꦊꦋꦌꦍꦎꦏꦐꦑꦒꦓꦔꦕꦖꦗꦘꦙꦚꦛꦜꦝꦞꦟꦠꦡꦢꦣꦤꦥꦦꦧꦨꦩꦪꦫꦬꦭꦮꦯꦰꦱꦲ꦳ꦴꦵꦶꦷꦸꦹꦺꦻꦼꦽꦾꦿ꧀꧁꧂꧃꧄꧅꧆꧇꧈꧉꧊꧋꧌꧍ꧏ꧐꧑꧒꧓꧔꧕꧖꧗꧘꧙꧞꧟ꨀꨁꨂꨃꨄꨅꨆꨇꨈꨉꨊꨋꨌꨍꨎꨏꨐꨑꨒꨓꨔꨕꨖꨗꨘꨙꨚꨛꨜꨝꨞꨟꨠꨡꨢꨣꨤꨥꨦꨧꨨꨩꨪꨫꨬꨭꨮꨯꨰꨱꨲꨳꨴꨵꨶꩀꩁꩂꩃꩄꩅꩆꩇꩈꩉꩊꩋꩌꩍ꩐꩑꩒꩓꩔꩕꩖꩗꩘꩙꩜꩝꩞꩟ꩠꩡꩢꩣꩤꩥꩦꩧꩨꩩꩪꩫꩬꩭꩮꩯꩰꩱꩲꩳꩴꩵꩶ꩷꩸꩹ꩺꩻꪀꪁꪂꪃꪄꪅꪆꪇꪈꪉꪊꪋꪌꪍꪎꪏꪐꪑꪒꪓꪔꪕꪖꪗꪘꪙꪚꪛꪜꪝꪞꪟꪠꪡꪢꪣꪤꪥꪦꪧꪨꪩꪪꪫꪬꪭꪮꪯꪰꪱꪴꪲꪳꪵꪶꪷꪸꪹꪺꪻꪼꪽꪾ꪿ꫀ꫁ꫂꫛꫜꫝ꫞꫟ꫠꫡꫢꫣꫤꫥꫦꫧꫨꫩꫪꫫꫬꫭꫮꫯ꫰꫱ꫲꫳꫴꫵ꫶ꬁꬂꬃꬄꬅꬆꬉꬊꬋꬌꬍꬎꬑꬒꬓꬔꬕꬖꬠꬡꬢꬣꬤꬥꬦꬨꬩꬪꬫꬬꬭꬮꯀꯁꯂꯃꯄꯅꯆꯇꯈꯉꯊꯋꯌꯍꯎꯏꯐꯑꯒꯓꯔꯕꯖꯗꯘꯙꯚꯛꯜꯝꯞꯟꯠꯡꯢꯣꯤꯥꯦꯧꯨꯩꯪ꯫꯬꯭꯰꯱꯲꯳꯴꯵꯶꯷꯸꯹가각갂갃간갅갆갇갈갉갊갋갌갍갎갏감갑값갓갔강갖갗갘같갚갛개객갞갟갠갡갢갣갤갥갦갧갨갩갪갫갬갭갮갯갰갱갲갳갴갵갶갷갸갹갺갻갼갽갾갿걀걁걂걃걄걅걆걇걈걉걊걋걌걍걎걏걐걑걒걓걔걕걖걗걘걙걚걛걜걝걞걟걠걡걢걣걤걥걦걧걨걩걪걫걬걭걮걯거걱걲걳건걵걶걷걸걹걺걻걼걽걾걿검겁겂것겄겅겆겇겈겉겊겋게겍겎겏겐겑겒겓겔겕겖겗겘겙겚겛겜겝겞겟겠겡겢겣겤겥겦겧겨격겪겫견겭겮겯결겱겲겳겴겵겶겷겸겹겺겻겼경겾겿곀곁곂곃계곅곆곇곈곉곊곋곌곍곎곏곐곑곒곓곔곕곖곗곘곙곚곛곜곝곞곟고곡곢곣곤곥곦곧골곩곪곫곬곭곮곯곰곱곲곳곴공곶곷곸곹곺곻과곽곾곿관괁괂괃괄괅괆괇괈괉괊괋괌괍괎괏괐광괒괓괔괕괖괗괘괙괚괛괜괝괞괟괠괡괢괣괤괥괦괧괨괩괪괫괬괭괮괯괰괱괲괳괴괵괶괷괸괹괺괻괼괽괾괿굀굁굂굃굄굅굆굇굈굉굊굋굌굍굎굏교굑굒굓굔굕굖굗굘굙굚굛굜굝굞굟굠굡굢굣굤굥굦굧굨굩굪굫구국굮굯군굱굲굳굴굵굶굷굸굹굺굻굼굽굾굿궀궁궂궃궄궅궆궇궈궉궊궋권궍궎궏궐궑궒궓궔궕궖궗궘궙궚궛궜궝궞궟궠궡궢궣궤궥궦궧궨궩궪궫궬궭궮궯궰궱궲궳궴궵궶궷궸궹궺궻궼궽궾궿귀귁귂귃귄귅귆귇귈귉귊귋귌귍귎귏귐귑귒귓귔귕귖귗귘귙귚귛규귝귞귟균귡귢귣귤귥귦귧귨귩귪귫귬귭귮귯귰귱귲귳귴귵귶귷그극귺귻근귽귾귿글긁긂긃긄긅긆긇금급긊긋긌긍긎긏긐긑긒긓긔긕긖긗긘긙긚긛긜긝긞긟긠긡긢긣긤긥긦긧긨긩긪긫긬긭긮긯기긱긲긳긴긵긶긷길긹긺긻긼긽긾긿김깁깂깃깄깅깆깇깈깉깊깋까깍깎깏깐깑깒깓깔깕깖깗깘깙깚깛깜깝깞깟깠깡깢깣깤깥깦깧깨깩깪깫깬깭깮깯깰깱깲깳깴깵깶깷깸깹깺깻깼깽깾깿꺀꺁꺂꺃꺄꺅꺆꺇꺈꺉꺊꺋꺌꺍꺎꺏꺐꺑꺒꺓꺔꺕꺖꺗꺘꺙꺚꺛꺜꺝꺞꺟꺠꺡꺢꺣꺤꺥꺦꺧꺨꺩꺪꺫꺬꺭꺮꺯꺰꺱꺲꺳꺴꺵꺶꺷꺸꺹꺺꺻꺼꺽꺾꺿껀껁껂껃껄껅껆껇껈껉껊껋껌껍껎껏껐껑껒껓껔껕껖껗께껙껚껛껜껝껞껟껠껡껢껣껤껥껦껧껨껩껪껫껬껭껮껯껰껱껲껳껴껵껶껷껸껹껺껻껼껽껾껿꼀꼁꼂꼃꼄꼅꼆꼇꼈꼉꼊꼋꼌꼍꼎꼏꼐꼑꼒꼓꼔꼕꼖꼗꼘꼙꼚꼛꼜꼝꼞꼟꼠꼡꼢꼣꼤꼥꼦꼧꼨꼩꼪꼫꼬꼭꼮꼯꼰꼱꼲꼳꼴꼵꼶꼷꼸꼹꼺꼻꼼꼽꼾꼿꽀꽁꽂꽃꽄꽅꽆꽇꽈꽉꽊꽋꽌꽍꽎꽏꽐꽑꽒꽓꽔꽕꽖꽗꽘꽙꽚꽛꽜꽝꽞꽟꽠꽡꽢꽣꽤꽥꽦꽧꽨꽩꽪꽫꽬꽭꽮꽯꽰꽱꽲꽳꽴꽵꽶꽷꽸꽹꽺꽻꽼꽽꽾꽿꾀꾁꾂꾃꾄꾅꾆꾇꾈꾉꾊꾋꾌꾍꾎꾏꾐꾑꾒꾓꾔꾕꾖꾗꾘꾙꾚꾛꾜꾝꾞꾟꾠꾡꾢꾣꾤꾥꾦꾧꾨꾩꾪꾫꾬꾭꾮꾯꾰꾱꾲꾳꾴꾵꾶꾷꾸꾹꾺꾻꾼꾽꾾꾿꿀꿁꿂꿃꿄꿅꿆꿇꿈꿉꿊꿋꿌꿍꿎꿏꿐꿑꿒꿓꿔꿕꿖꿗꿘꿙꿚꿛꿜꿝꿞꿟꿠꿡꿢꿣꿤꿥꿦꿧꿨꿩꿪꿫꿬꿭꿮꿯꿰꿱꿲꿳꿴꿵꿶꿷꿸꿹꿺꿻꿼꿽꿾꿿뀀뀁뀂뀃뀄뀅뀆뀇뀈뀉뀊뀋뀌뀍뀎뀏뀐뀑뀒뀓뀔뀕뀖뀗뀘뀙뀚뀛뀜뀝뀞뀟뀠뀡뀢뀣뀤뀥뀦뀧뀨뀩뀪뀫뀬뀭뀮뀯뀰뀱뀲뀳뀴뀵뀶뀷뀸뀹뀺뀻뀼뀽뀾뀿끀끁끂끃끄끅끆끇끈끉끊끋끌끍끎끏끐끑끒끓끔끕끖끗끘끙끚끛끜끝끞끟끠끡끢끣끤끥끦끧끨끩끪끫끬끭끮끯끰끱끲끳끴끵끶끷끸끹끺끻끼끽끾끿낀낁낂낃낄낅낆낇낈낉낊낋낌낍낎낏낐낑낒낓낔낕낖낗나낙낚낛난낝낞낟날낡낢낣낤낥낦낧남납낪낫났낭낮낯낰낱낲낳내낵낶낷낸낹낺낻낼낽낾낿냀냁냂냃냄냅냆냇냈냉냊냋냌냍냎냏냐냑냒냓냔냕냖냗냘냙냚냛냜냝냞냟냠냡냢냣냤냥냦냧냨냩냪냫냬냭냮냯냰냱냲냳냴냵냶냷냸냹냺냻냼냽냾냿넀넁넂넃넄넅넆넇너넉넊넋넌넍넎넏널넑넒넓넔넕넖넗넘넙넚넛넜넝넞넟넠넡넢넣네넥넦넧넨넩넪넫넬넭넮넯넰넱넲넳넴넵넶넷넸넹넺넻넼넽넾넿녀녁녂녃년녅녆녇녈녉녊녋녌녍녎녏념녑녒녓녔녕녖녗녘녙녚녛녜녝녞녟녠녡녢녣녤녥녦녧녨녩녪녫녬녭녮녯녰녱녲녳녴녵녶녷노녹녺녻논녽녾녿놀놁놂놃놄놅놆놇놈놉놊놋놌농놎놏놐놑높놓놔놕놖놗놘놙놚놛놜놝놞놟놠놡놢놣놤놥놦놧놨놩놪놫놬놭놮놯놰놱놲놳놴놵놶놷놸놹놺놻놼놽놾놿뇀뇁뇂뇃뇄뇅뇆뇇뇈뇉뇊뇋뇌뇍뇎뇏뇐뇑뇒뇓뇔뇕뇖뇗뇘뇙뇚뇛뇜뇝뇞뇟뇠뇡뇢뇣뇤뇥뇦뇧뇨뇩뇪뇫뇬뇭뇮뇯뇰뇱뇲뇳뇴뇵뇶뇷뇸뇹뇺뇻뇼뇽뇾뇿눀눁눂눃누눅눆눇눈눉눊눋눌눍눎눏눐눑눒눓눔눕눖눗눘눙눚눛눜눝눞눟눠눡눢눣눤눥눦눧눨눩눪눫눬눭눮눯눰눱눲눳눴눵눶눷눸눹눺눻눼눽눾눿뉀뉁뉂뉃뉄뉅뉆뉇뉈뉉뉊뉋뉌뉍뉎뉏뉐뉑뉒뉓뉔뉕뉖뉗뉘뉙뉚뉛뉜뉝뉞뉟뉠뉡뉢뉣뉤뉥뉦뉧뉨뉩뉪뉫뉬뉭뉮뉯뉰뉱뉲뉳뉴뉵뉶뉷뉸뉹뉺뉻뉼뉽뉾뉿늀늁늂늃늄늅늆늇늈늉늊늋늌늍늎늏느늑늒늓는늕늖늗늘늙늚늛늜늝늞늟늠늡늢늣늤능늦늧늨늩늪늫늬늭늮늯늰늱늲늳늴늵늶늷늸늹늺늻늼늽늾늿닀닁닂닃닄닅닆닇니닉닊닋닌닍닎닏닐닑닒닓닔닕닖닗님닙닚닛닜닝닞닟닠닡닢닣다닥닦닧단닩닪닫달닭닮닯닰닱닲닳담답닶닷닸당닺닻닼닽닾닿대댁댂댃댄댅댆댇댈댉댊댋댌댍댎댏댐댑댒댓댔댕댖댗댘댙댚댛댜댝댞댟댠댡댢댣댤댥댦댧댨댩댪댫댬댭댮댯댰댱댲댳댴댵댶댷댸댹댺댻댼댽댾댿덀덁덂덃덄덅덆덇덈덉덊덋덌덍덎덏덐덑덒덓더덕덖덗던덙덚덛덜덝덞덟덠덡덢덣덤덥덦덧덨덩덪덫덬덭덮덯데덱덲덳덴덵덶덷델덹덺덻덼덽덾덿뎀뎁뎂뎃뎄뎅뎆뎇뎈뎉뎊뎋뎌뎍뎎뎏뎐뎑뎒뎓뎔뎕뎖뎗뎘뎙뎚뎛뎜뎝뎞뎟뎠뎡뎢뎣뎤뎥뎦뎧뎨뎩뎪뎫뎬뎭뎮뎯뎰뎱뎲뎳뎴뎵뎶뎷뎸뎹뎺뎻뎼뎽뎾뎿돀돁돂돃도독돆돇돈돉돊돋돌돍돎돏돐돑돒돓돔돕돖돗돘동돚돛돜돝돞돟돠돡돢돣돤돥돦돧돨돩돪돫돬돭돮돯돰돱돲돳돴돵돶돷돸돹돺돻돼돽돾돿됀됁됂됃됄됅됆됇됈됉됊됋됌됍됎됏됐됑됒됓됔됕됖됗되됙됚됛된됝됞됟될됡됢됣됤됥됦됧됨됩됪됫됬됭됮됯됰됱됲됳됴됵됶됷됸됹됺됻됼됽됾됿둀둁둂둃둄둅둆둇둈둉둊둋둌둍둎둏두둑둒둓둔둕둖둗둘둙둚둛둜둝둞둟둠둡둢둣둤둥둦둧둨둩둪둫둬둭둮둯둰둱둲둳둴둵둶둷둸둹둺둻둼둽둾둿뒀뒁뒂뒃뒄뒅뒆뒇뒈뒉뒊뒋뒌뒍뒎뒏뒐뒑뒒뒓뒔뒕뒖뒗뒘뒙뒚뒛뒜뒝뒞뒟뒠뒡뒢뒣뒤뒥뒦뒧뒨뒩뒪뒫뒬뒭뒮뒯뒰뒱뒲뒳뒴뒵뒶뒷뒸뒹뒺뒻뒼뒽뒾뒿듀듁듂듃듄듅듆듇듈듉듊듋듌듍듎듏듐듑듒듓듔듕듖듗듘듙듚듛드득듞듟든듡듢듣들듥듦듧듨듩듪듫듬듭듮듯듰등듲듳듴듵듶듷듸듹듺듻듼듽듾듿딀딁딂딃딄딅딆딇딈딉딊딋딌딍딎딏딐딑딒딓디딕딖딗딘딙딚딛딜딝딞딟딠딡딢딣딤딥딦딧딨딩딪딫딬딭딮딯따딱딲딳딴딵딶딷딸딹딺딻딼딽딾딿땀땁땂땃땄땅땆땇땈땉땊땋때땍땎땏땐땑땒땓땔땕땖땗땘땙땚땛땜땝땞땟땠땡땢땣땤땥땦땧땨땩땪땫땬땭땮땯땰땱땲땳땴땵땶땷땸땹땺땻땼땽땾땿떀떁떂떃떄떅떆떇떈떉떊떋떌떍떎떏떐떑떒떓떔떕떖떗떘떙떚떛떜떝떞떟떠떡떢떣떤떥떦떧떨떩떪떫떬떭떮떯떰떱떲떳떴떵떶떷떸떹떺떻떼떽떾떿뗀뗁뗂뗃뗄뗅뗆뗇뗈뗉뗊뗋뗌뗍뗎뗏뗐뗑뗒뗓뗔뗕뗖뗗뗘뗙뗚뗛뗜뗝뗞뗟뗠뗡뗢뗣뗤뗥뗦뗧뗨뗩뗪뗫뗬뗭뗮뗯뗰뗱뗲뗳뗴뗵뗶뗷뗸뗹뗺뗻뗼뗽뗾뗿똀똁똂똃똄똅똆똇똈똉똊똋똌똍똎똏또똑똒똓똔똕똖똗똘똙똚똛똜똝똞똟똠똡똢똣똤똥똦똧똨똩똪똫똬똭똮똯똰똱똲똳똴똵똶똷똸똹똺똻똼똽똾똿뙀뙁뙂뙃뙄뙅뙆뙇뙈뙉뙊뙋뙌뙍뙎뙏뙐뙑뙒뙓뙔뙕뙖뙗뙘뙙뙚뙛뙜뙝뙞뙟뙠뙡뙢뙣뙤뙥뙦뙧뙨뙩뙪뙫뙬뙭뙮뙯뙰뙱뙲뙳뙴뙵뙶뙷뙸뙹뙺뙻뙼뙽뙾뙿뚀뚁뚂뚃뚄뚅뚆뚇뚈뚉뚊뚋뚌뚍뚎뚏뚐뚑뚒뚓뚔뚕뚖뚗뚘뚙뚚뚛뚜뚝뚞뚟뚠뚡뚢뚣뚤뚥뚦뚧뚨뚩뚪뚫뚬뚭뚮뚯뚰뚱뚲뚳뚴뚵뚶뚷뚸뚹뚺뚻뚼뚽뚾뚿뛀뛁뛂뛃뛄뛅뛆뛇뛈뛉뛊뛋뛌뛍뛎뛏뛐뛑뛒뛓뛔뛕뛖뛗뛘뛙뛚뛛뛜뛝뛞뛟뛠뛡뛢뛣뛤뛥뛦뛧뛨뛩뛪뛫뛬뛭뛮뛯뛰뛱뛲뛳뛴뛵뛶뛷뛸뛹뛺뛻뛼뛽뛾뛿뜀뜁뜂뜃뜄뜅뜆뜇뜈뜉뜊뜋뜌뜍뜎뜏뜐뜑뜒뜓뜔뜕뜖뜗뜘뜙뜚뜛뜜뜝뜞뜟뜠뜡뜢뜣뜤뜥뜦뜧뜨뜩뜪뜫뜬뜭뜮뜯뜰뜱뜲뜳뜴뜵뜶뜷뜸뜹뜺뜻뜼뜽뜾뜿띀띁띂띃띄띅띆띇띈띉띊띋띌띍띎띏띐띑띒띓띔띕띖띗띘띙띚띛띜띝띞띟띠띡띢띣띤띥띦띧띨띩띪띫띬띭띮띯띰띱띲띳띴띵띶띷띸띹띺띻라락띾띿란랁랂랃랄랅랆랇랈랉랊랋람랍랎랏랐랑랒랓랔랕랖랗래랙랚랛랜랝랞랟랠랡랢랣랤랥랦랧램랩랪랫랬랭랮랯랰랱랲랳랴략랶랷랸랹랺랻랼랽랾랿럀럁럂럃럄럅럆럇럈량럊럋럌럍럎럏럐럑럒럓럔럕럖럗럘럙럚럛럜럝럞럟럠럡럢럣럤럥럦럧럨럩럪럫러럭럮럯런럱럲럳럴럵럶럷럸럹럺럻럼럽럾럿렀렁렂렃렄렅렆렇레렉렊렋렌렍렎렏렐렑렒렓렔렕렖렗렘렙렚렛렜렝렞렟렠렡렢렣려력렦렧련렩렪렫렬렭렮렯렰렱렲렳렴렵렶렷렸령렺렻렼렽렾렿례롁롂롃롄롅롆롇롈롉롊롋롌롍롎롏롐롑롒롓롔롕롖롗롘롙롚롛로록롞롟론롡롢롣롤롥롦롧롨롩롪롫롬롭롮롯롰롱롲롳롴롵롶롷롸롹롺롻롼롽롾롿뢀뢁뢂뢃뢄뢅뢆뢇뢈뢉뢊뢋뢌뢍뢎뢏뢐뢑뢒뢓뢔뢕뢖뢗뢘뢙뢚뢛뢜뢝뢞뢟뢠뢡뢢뢣뢤뢥뢦뢧뢨뢩뢪뢫뢬뢭뢮뢯뢰뢱뢲뢳뢴뢵뢶뢷뢸뢹뢺뢻뢼뢽뢾뢿룀룁룂룃룄룅룆룇룈룉룊룋료룍룎룏룐룑룒룓룔룕룖룗룘룙룚룛룜룝룞룟룠룡룢룣룤룥룦룧루룩룪룫룬룭룮룯룰룱룲룳룴룵룶룷룸룹룺룻룼룽룾룿뤀뤁뤂뤃뤄뤅뤆뤇뤈뤉뤊뤋뤌뤍뤎뤏뤐뤑뤒뤓뤔뤕뤖뤗뤘뤙뤚뤛뤜뤝뤞뤟뤠뤡뤢뤣뤤뤥뤦뤧뤨뤩뤪뤫뤬뤭뤮뤯뤰뤱뤲뤳뤴뤵뤶뤷뤸뤹뤺뤻뤼뤽뤾뤿륀륁륂륃륄륅륆륇륈륉륊륋륌륍륎륏륐륑륒륓륔륕륖륗류륙륚륛륜륝륞륟률륡륢륣륤륥륦륧륨륩륪륫륬륭륮륯륰륱륲륳르륵륶륷른륹륺륻를륽륾륿릀릁릂릃름릅릆릇릈릉릊릋릌릍릎릏릐릑릒릓릔릕릖릗릘릙릚릛릜릝릞릟릠릡릢릣릤릥릦릧릨릩릪릫리릭릮릯린릱릲릳릴릵릶릷릸릹릺릻림립릾릿맀링맂맃맄맅맆맇마막맊맋만맍많맏말맑맒맓맔맕맖맗맘맙맚맛맜망맞맟맠맡맢맣매맥맦맧맨맩맪맫맬맭맮맯맰맱맲맳맴맵맶맷맸맹맺맻맼맽맾맿먀먁먂먃먄먅먆먇먈먉먊먋먌먍먎먏먐먑먒먓먔먕먖먗먘먙먚먛먜먝먞먟먠먡먢먣먤먥먦먧먨먩먪먫먬먭먮먯먰먱먲먳먴먵먶먷머먹먺먻먼먽먾먿멀멁멂멃멄멅멆멇멈멉멊멋멌멍멎멏멐멑멒멓메멕멖멗멘멙멚멛멜멝멞멟멠멡멢멣멤멥멦멧멨멩멪멫멬멭멮멯며멱멲멳면멵멶멷멸멹멺멻멼멽멾멿몀몁몂몃몄명몆몇몈몉몊몋몌몍몎몏몐몑몒몓몔몕몖몗몘몙몚몛몜몝몞몟몠몡몢몣몤몥몦몧모목몪몫몬몭몮몯몰몱몲몳몴몵몶몷몸몹몺못몼몽몾몿뫀뫁뫂뫃뫄뫅뫆뫇뫈뫉뫊뫋뫌뫍뫎뫏뫐뫑뫒뫓뫔뫕뫖뫗뫘뫙뫚뫛뫜뫝뫞뫟뫠뫡뫢뫣뫤뫥뫦뫧뫨뫩뫪뫫뫬뫭뫮뫯뫰뫱뫲뫳뫴뫵뫶뫷뫸뫹뫺뫻뫼뫽뫾뫿묀묁묂묃묄묅묆묇묈묉묊묋묌묍묎묏묐묑묒묓묔묕묖묗묘묙묚묛묜묝묞묟묠묡묢묣묤묥묦묧묨묩묪묫묬묭묮묯묰묱묲묳무묵묶묷문묹묺묻물묽묾묿뭀뭁뭂뭃뭄뭅뭆뭇뭈뭉뭊뭋뭌뭍뭎뭏뭐뭑뭒뭓뭔뭕뭖뭗뭘뭙뭚뭛뭜뭝뭞뭟뭠뭡뭢뭣뭤뭥뭦뭧뭨뭩뭪뭫뭬뭭뭮뭯뭰뭱뭲뭳뭴뭵뭶뭷뭸뭹뭺뭻뭼뭽뭾뭿뮀뮁뮂뮃뮄뮅뮆뮇뮈뮉뮊뮋뮌뮍뮎뮏뮐뮑뮒뮓뮔뮕뮖뮗뮘뮙뮚뮛뮜뮝뮞뮟뮠뮡뮢뮣뮤뮥뮦뮧뮨뮩뮪뮫뮬뮭뮮뮯뮰뮱뮲뮳뮴뮵뮶뮷뮸뮹뮺뮻뮼뮽뮾뮿므믁믂믃믄믅믆믇믈믉믊믋믌믍믎믏믐믑믒믓믔믕믖믗믘믙믚믛믜믝믞믟믠믡믢믣믤믥믦믧믨믩믪믫믬믭믮믯믰믱믲믳믴믵믶믷미믹믺믻민믽믾믿밀밁밂밃밄밅밆밇밈밉밊밋밌밍밎및밐밑밒밓바박밖밗반밙밚받발밝밞밟밠밡밢밣밤밥밦밧밨방밪밫밬밭밮밯배백밲밳밴밵밶밷밸밹밺밻밼밽밾밿뱀뱁뱂뱃뱄뱅뱆뱇뱈뱉뱊뱋뱌뱍뱎뱏뱐뱑뱒뱓뱔뱕뱖뱗뱘뱙뱚뱛뱜뱝뱞뱟뱠뱡뱢뱣뱤뱥뱦뱧뱨뱩뱪뱫뱬뱭뱮뱯뱰뱱뱲뱳뱴뱵뱶뱷뱸뱹뱺뱻뱼뱽뱾뱿벀벁벂벃버벅벆벇번벉벊벋벌벍벎벏벐벑벒벓범법벖벗벘벙벚벛벜벝벞벟베벡벢벣벤벥벦벧벨벩벪벫벬벭벮벯벰벱벲벳벴벵벶벷벸벹벺벻벼벽벾벿변볁볂볃별볅볆볇볈볉볊볋볌볍볎볏볐병볒볓볔볕볖볗볘볙볚볛볜볝볞볟볠볡볢볣볤볥볦볧볨볩볪볫볬볭볮볯볰볱볲볳보복볶볷본볹볺볻볼볽볾볿봀봁봂봃봄봅봆봇봈봉봊봋봌봍봎봏봐봑봒봓봔봕봖봗봘봙봚봛봜봝봞봟봠봡봢봣봤봥봦봧봨봩봪봫봬봭봮봯봰봱봲봳봴봵봶봷봸봹봺봻봼봽봾봿뵀뵁뵂뵃뵄뵅뵆뵇뵈뵉뵊뵋뵌뵍뵎뵏뵐뵑뵒뵓뵔뵕뵖뵗뵘뵙뵚뵛뵜뵝뵞뵟뵠뵡뵢뵣뵤뵥뵦뵧뵨뵩뵪뵫뵬뵭뵮뵯뵰뵱뵲뵳뵴뵵뵶뵷뵸뵹뵺뵻뵼뵽뵾뵿부북붂붃분붅붆붇불붉붊붋붌붍붎붏붐붑붒붓붔붕붖붗붘붙붚붛붜붝붞붟붠붡붢붣붤붥붦붧붨붩붪붫붬붭붮붯붰붱붲붳붴붵붶붷붸붹붺붻붼붽붾붿뷀뷁뷂뷃뷄뷅뷆뷇뷈뷉뷊뷋뷌뷍뷎뷏뷐뷑뷒뷓뷔뷕뷖뷗뷘뷙뷚뷛뷜뷝뷞뷟뷠뷡뷢뷣뷤뷥뷦뷧뷨뷩뷪뷫뷬뷭뷮뷯뷰뷱뷲뷳뷴뷵뷶뷷뷸뷹뷺뷻뷼뷽뷾뷿븀븁븂븃븄븅븆븇븈븉븊븋브븍븎븏븐븑븒븓블븕븖븗븘븙븚븛븜븝븞븟븠븡븢븣븤븥븦븧븨븩븪븫븬븭븮븯븰븱븲븳븴븵븶븷븸븹븺븻븼븽븾븿빀빁빂빃비빅빆빇빈빉빊빋빌빍빎빏빐빑빒빓빔빕빖빗빘빙빚빛빜빝빞빟빠빡빢빣빤빥빦빧빨빩빪빫빬빭빮빯빰빱빲빳빴빵빶빷빸빹빺빻빼빽빾빿뺀뺁뺂뺃뺄뺅뺆뺇뺈뺉뺊뺋뺌뺍뺎뺏뺐뺑뺒뺓뺔뺕뺖뺗뺘뺙뺚뺛뺜뺝뺞뺟뺠뺡뺢뺣뺤뺥뺦뺧뺨뺩뺪뺫뺬뺭뺮뺯뺰뺱뺲뺳뺴뺵뺶뺷뺸뺹뺺뺻뺼뺽뺾뺿뻀뻁뻂뻃뻄뻅뻆뻇뻈뻉뻊뻋뻌뻍뻎뻏뻐뻑뻒뻓뻔뻕뻖뻗뻘뻙뻚뻛뻜뻝뻞뻟뻠뻡뻢뻣뻤뻥뻦뻧뻨뻩뻪뻫뻬뻭뻮뻯뻰뻱뻲뻳뻴뻵뻶뻷뻸뻹뻺뻻뻼뻽뻾뻿뼀뼁뼂뼃뼄뼅뼆뼇뼈뼉뼊뼋뼌뼍뼎뼏뼐뼑뼒뼓뼔뼕뼖뼗뼘뼙뼚뼛뼜뼝뼞뼟뼠뼡뼢뼣뼤뼥뼦뼧뼨뼩뼪뼫뼬뼭뼮뼯뼰뼱뼲뼳뼴뼵뼶뼷뼸뼹뼺뼻뼼뼽뼾뼿뽀뽁뽂뽃뽄뽅뽆뽇뽈뽉뽊뽋뽌뽍뽎뽏뽐뽑뽒뽓뽔뽕뽖뽗뽘뽙뽚뽛뽜뽝뽞뽟뽠뽡뽢뽣뽤뽥뽦뽧뽨뽩뽪뽫뽬뽭뽮뽯뽰뽱뽲뽳뽴뽵뽶뽷뽸뽹뽺뽻뽼뽽뽾뽿뾀뾁뾂뾃뾄뾅뾆뾇뾈뾉뾊뾋뾌뾍뾎뾏뾐뾑뾒뾓뾔뾕뾖뾗뾘뾙뾚뾛뾜뾝뾞뾟뾠뾡뾢뾣뾤뾥뾦뾧뾨뾩뾪뾫뾬뾭뾮뾯뾰뾱뾲뾳뾴뾵뾶뾷뾸뾹뾺뾻뾼뾽뾾뾿뿀뿁뿂뿃뿄뿅뿆뿇뿈뿉뿊뿋뿌뿍뿎뿏뿐뿑뿒뿓뿔뿕뿖뿗뿘뿙뿚뿛뿜뿝뿞뿟뿠뿡뿢뿣뿤뿥뿦뿧뿨뿩뿪뿫뿬뿭뿮뿯뿰뿱뿲뿳뿴뿵뿶뿷뿸뿹뿺뿻뿼뿽뿾뿿쀀쀁쀂쀃쀄쀅쀆쀇쀈쀉쀊쀋쀌쀍쀎쀏쀐쀑쀒쀓쀔쀕쀖쀗쀘쀙쀚쀛쀜쀝쀞쀟쀠쀡쀢쀣쀤쀥쀦쀧쀨쀩쀪쀫쀬쀭쀮쀯쀰쀱쀲쀳쀴쀵쀶쀷쀸쀹쀺쀻쀼쀽쀾쀿쁀쁁쁂쁃쁄쁅쁆쁇쁈쁉쁊쁋쁌쁍쁎쁏쁐쁑쁒쁓쁔쁕쁖쁗쁘쁙쁚쁛쁜쁝쁞쁟쁠쁡쁢쁣쁤쁥쁦쁧쁨쁩쁪쁫쁬쁭쁮쁯쁰쁱쁲쁳쁴쁵쁶쁷쁸쁹쁺쁻쁼쁽쁾쁿삀삁삂삃삄삅삆삇삈삉삊삋삌삍삎삏삐삑삒삓삔삕삖삗삘삙삚삛삜삝삞삟삠삡삢삣삤삥삦삧삨삩삪삫사삭삮삯산삱삲삳살삵삶삷삸삹삺삻삼삽삾삿샀상샂샃샄샅샆샇새색샊샋샌샍샎샏샐샑샒샓샔샕샖샗샘샙샚샛샜생샞샟샠샡샢샣샤샥샦샧샨샩샪샫샬샭샮샯샰샱샲샳샴샵샶샷샸샹샺샻샼샽샾샿섀섁섂섃섄섅섆섇섈섉섊섋섌섍섎섏섐섑섒섓섔섕섖섗섘섙섚섛서석섞섟선섡섢섣설섥섦섧섨섩섪섫섬섭섮섯섰성섲섳섴섵섶섷세섹섺섻센섽섾섿셀셁셂셃셄셅셆셇셈셉셊셋셌셍셎셏셐셑셒셓셔셕셖셗션셙셚셛셜셝셞셟셠셡셢셣셤셥셦셧셨셩셪셫셬셭셮셯셰셱셲셳셴셵셶셷셸셹셺셻셼셽셾셿솀솁솂솃솄솅솆솇솈솉솊솋소속솎솏손솑솒솓솔솕솖솗솘솙솚솛솜솝솞솟솠송솢솣솤솥솦솧솨솩솪솫솬솭솮솯솰솱솲솳솴솵솶솷솸솹솺솻솼솽솾솿쇀쇁쇂쇃쇄쇅쇆쇇쇈쇉쇊쇋쇌쇍쇎쇏쇐쇑쇒쇓쇔쇕쇖쇗쇘쇙쇚쇛쇜쇝쇞쇟쇠쇡쇢쇣쇤쇥쇦쇧쇨쇩쇪쇫쇬쇭쇮쇯쇰쇱쇲쇳쇴쇵쇶쇷쇸쇹쇺쇻쇼쇽쇾쇿숀숁숂숃숄숅숆숇숈숉숊숋숌숍숎숏숐숑숒숓숔숕숖숗수숙숚숛순숝숞숟술숡숢숣숤숥숦숧숨숩숪숫숬숭숮숯숰숱숲숳숴숵숶숷숸숹숺숻숼숽숾숿쉀쉁쉂쉃쉄쉅쉆쉇쉈쉉쉊쉋쉌쉍쉎쉏쉐쉑쉒쉓쉔쉕쉖쉗쉘쉙쉚쉛쉜쉝쉞쉟쉠쉡쉢쉣쉤쉥쉦쉧쉨쉩쉪쉫쉬쉭쉮쉯쉰쉱쉲쉳쉴쉵쉶쉷쉸쉹쉺쉻쉼쉽쉾쉿슀슁슂슃슄슅슆슇슈슉슊슋슌슍슎슏슐슑슒슓슔슕슖슗슘슙슚슛슜슝슞슟슠슡슢슣스슥슦슧슨슩슪슫슬슭슮슯슰슱슲슳슴습슶슷슸승슺슻슼슽슾슿싀싁싂싃싄싅싆싇싈싉싊싋싌싍싎싏싐싑싒싓싔싕싖싗싘싙싚싛시식싞싟신싡싢싣실싥싦싧싨싩싪싫심십싮싯싰싱싲싳싴싵싶싷싸싹싺싻싼싽싾싿쌀쌁쌂쌃쌄쌅쌆쌇쌈쌉쌊쌋쌌쌍쌎쌏쌐쌑쌒쌓쌔쌕쌖쌗쌘쌙쌚쌛쌜쌝쌞쌟쌠쌡쌢쌣쌤쌥쌦쌧쌨쌩쌪쌫쌬쌭쌮쌯쌰쌱쌲쌳쌴쌵쌶쌷쌸쌹쌺쌻쌼쌽쌾쌿썀썁썂썃썄썅썆썇썈썉썊썋썌썍썎썏썐썑썒썓썔썕썖썗썘썙썚썛썜썝썞썟썠썡썢썣썤썥썦썧써썩썪썫썬썭썮썯썰썱썲썳썴썵썶썷썸썹썺썻썼썽썾썿쎀쎁쎂쎃쎄쎅쎆쎇쎈쎉쎊쎋쎌쎍쎎쎏쎐쎑쎒쎓쎔쎕쎖쎗쎘쎙쎚쎛쎜쎝쎞쎟쎠쎡쎢쎣쎤쎥쎦쎧쎨쎩쎪쎫쎬쎭쎮쎯쎰쎱쎲쎳쎴쎵쎶쎷쎸쎹쎺쎻쎼쎽쎾쎿쏀쏁쏂쏃쏄쏅쏆쏇쏈쏉쏊쏋쏌쏍쏎쏏쏐쏑쏒쏓쏔쏕쏖쏗쏘쏙쏚쏛쏜쏝쏞쏟쏠쏡쏢쏣쏤쏥쏦쏧쏨쏩쏪쏫쏬쏭쏮쏯쏰쏱쏲쏳쏴쏵쏶쏷쏸쏹쏺쏻쏼쏽쏾쏿쐀쐁쐂쐃쐄쐅쐆쐇쐈쐉쐊쐋쐌쐍쐎쐏쐐쐑쐒쐓쐔쐕쐖쐗쐘쐙쐚쐛쐜쐝쐞쐟쐠쐡쐢쐣쐤쐥쐦쐧쐨쐩쐪쐫쐬쐭쐮쐯쐰쐱쐲쐳쐴쐵쐶쐷쐸쐹쐺쐻쐼쐽쐾쐿쑀쑁쑂쑃쑄쑅쑆쑇쑈쑉쑊쑋쑌쑍쑎쑏쑐쑑쑒쑓쑔쑕쑖쑗쑘쑙쑚쑛쑜쑝쑞쑟쑠쑡쑢쑣쑤쑥쑦쑧쑨쑩쑪쑫쑬쑭쑮쑯쑰쑱쑲쑳쑴쑵쑶쑷쑸쑹쑺쑻쑼쑽쑾쑿쒀쒁쒂쒃쒄쒅쒆쒇쒈쒉쒊쒋쒌쒍쒎쒏쒐쒑쒒쒓쒔쒕쒖쒗쒘쒙쒚쒛쒜쒝쒞쒟쒠쒡쒢쒣쒤쒥쒦쒧쒨쒩쒪쒫쒬쒭쒮쒯쒰쒱쒲쒳쒴쒵쒶쒷쒸쒹쒺쒻쒼쒽쒾쒿쓀쓁쓂쓃쓄쓅쓆쓇쓈쓉쓊쓋쓌쓍쓎쓏쓐쓑쓒쓓쓔쓕쓖쓗쓘쓙쓚쓛쓜쓝쓞쓟쓠쓡쓢쓣쓤쓥쓦쓧쓨쓩쓪쓫쓬쓭쓮쓯쓰쓱쓲쓳쓴쓵쓶쓷쓸쓹쓺쓻쓼쓽쓾쓿씀씁씂씃씄씅씆씇씈씉씊씋씌씍씎씏씐씑씒씓씔씕씖씗씘씙씚씛씜씝씞씟씠씡씢씣씤씥씦씧씨씩씪씫씬씭씮씯씰씱씲씳씴씵씶씷씸씹씺씻씼씽씾씿앀앁앂앃아악앆앇안앉않앋알앍앎앏앐앑앒앓암압앖앗았앙앚앛앜앝앞앟애액앢앣앤앥앦앧앨앩앪앫앬앭앮앯앰앱앲앳앴앵앶앷앸앹앺앻야약앾앿얀얁얂얃얄얅얆얇얈얉얊얋얌얍얎얏얐양얒얓얔얕얖얗얘얙얚얛얜얝얞얟얠얡얢얣얤얥얦얧얨얩얪얫얬얭얮얯얰얱얲얳어억얶얷언얹얺얻얼얽얾얿엀엁엂엃엄업없엇었엉엊엋엌엍엎엏에엑엒엓엔엕엖엗엘엙엚엛엜엝엞엟엠엡엢엣엤엥엦엧엨엩엪엫여역엮엯연엱엲엳열엵엶엷엸엹엺엻염엽엾엿였영옂옃옄옅옆옇예옉옊옋옌옍옎옏옐옑옒옓옔옕옖옗옘옙옚옛옜옝옞옟옠옡옢옣오옥옦옧온옩옪옫올옭옮옯옰옱옲옳옴옵옶옷옸옹옺옻옼옽옾옿와왁왂왃완왅왆왇왈왉왊왋왌왍왎왏왐왑왒왓왔왕왖왗왘왙왚왛왜왝왞왟왠왡왢왣왤왥왦왧왨왩왪왫왬왭왮왯왰왱왲왳왴왵왶왷외왹왺왻왼왽왾왿욀욁욂욃욄욅욆욇욈욉욊욋욌욍욎욏욐욑욒욓요욕욖욗욘욙욚욛욜욝욞욟욠욡욢욣욤욥욦욧욨용욪욫욬욭욮욯우욱욲욳운욵욶욷울욹욺욻욼욽욾욿움웁웂웃웄웅웆웇웈웉웊웋워웍웎웏원웑웒웓월웕웖웗웘웙웚웛웜웝웞웟웠웡웢웣웤웥웦웧웨웩웪웫웬웭웮웯웰웱웲웳웴웵웶웷웸웹웺웻웼웽웾웿윀윁윂윃위윅윆윇윈윉윊윋윌윍윎윏윐윑윒윓윔윕윖윗윘윙윚윛윜윝윞윟유육윢윣윤윥윦윧율윩윪윫윬윭윮윯윰윱윲윳윴융윶윷윸윹윺윻으윽윾윿은읁읂읃을읅읆읇읈읉읊읋음읍읎읏읐응읒읓읔읕읖읗의읙읚읛읜읝읞읟읠읡읢읣읤읥읦읧읨읩읪읫읬읭읮읯읰읱읲읳이익읶읷인읹읺읻일읽읾읿잀잁잂잃임입잆잇있잉잊잋잌잍잎잏자작잒잓잔잕잖잗잘잙잚잛잜잝잞잟잠잡잢잣잤장잦잧잨잩잪잫재잭잮잯잰잱잲잳잴잵잶잷잸잹잺잻잼잽잾잿쟀쟁쟂쟃쟄쟅쟆쟇쟈쟉쟊쟋쟌쟍쟎쟏쟐쟑쟒쟓쟔쟕쟖쟗쟘쟙쟚쟛쟜쟝쟞쟟쟠쟡쟢쟣쟤쟥쟦쟧쟨쟩쟪쟫쟬쟭쟮쟯쟰쟱쟲쟳쟴쟵쟶쟷쟸쟹쟺쟻쟼쟽쟾쟿저적젂젃전젅젆젇절젉젊젋젌젍젎젏점접젒젓젔정젖젗젘젙젚젛제젝젞젟젠젡젢젣젤젥젦젧젨젩젪젫젬젭젮젯젰젱젲젳젴젵젶젷져젹젺젻젼젽젾젿졀졁졂졃졄졅졆졇졈졉졊졋졌졍졎졏졐졑졒졓졔졕졖졗졘졙졚졛졜졝졞졟졠졡졢졣졤졥졦졧졨졩졪졫졬졭졮졯조족졲졳존졵졶졷졸졹졺졻졼졽졾졿좀좁좂좃좄종좆좇좈좉좊좋좌좍좎좏좐좑좒좓좔좕좖좗좘좙좚좛좜좝좞좟좠좡좢좣좤좥좦좧좨좩좪좫좬좭좮좯좰좱좲좳좴좵좶좷좸좹좺좻좼좽좾좿죀죁죂죃죄죅죆죇죈죉죊죋죌죍죎죏죐죑죒죓죔죕죖죗죘죙죚죛죜죝죞죟죠죡죢죣죤죥죦죧죨죩죪죫죬죭죮죯죰죱죲죳죴죵죶죷죸죹죺죻주죽죾죿준줁줂줃줄줅줆줇줈줉줊줋줌줍줎줏줐중줒줓줔줕줖줗줘줙줚줛줜줝줞줟줠줡줢줣줤줥줦줧줨줩줪줫줬줭줮줯줰줱줲줳줴줵줶줷줸줹줺줻줼줽줾줿쥀쥁쥂쥃쥄쥅쥆쥇쥈쥉쥊쥋쥌쥍쥎쥏쥐쥑쥒쥓쥔쥕쥖쥗쥘쥙쥚쥛쥜쥝쥞쥟쥠쥡쥢쥣쥤쥥쥦쥧쥨쥩쥪쥫쥬쥭쥮쥯쥰쥱쥲쥳쥴쥵쥶쥷쥸쥹쥺쥻쥼쥽쥾쥿즀즁즂즃즄즅즆즇즈즉즊즋즌즍즎즏즐즑즒즓즔즕즖즗즘즙즚즛즜증즞즟즠즡즢즣즤즥즦즧즨즩즪즫즬즭즮즯즰즱즲즳즴즵즶즷즸즹즺즻즼즽즾즿지직짂짃진짅짆짇질짉짊짋짌짍짎짏짐집짒짓짔징짖짗짘짙짚짛짜짝짞짟짠짡짢짣짤짥짦짧짨짩짪짫짬짭짮짯짰짱짲짳짴짵짶짷째짹짺짻짼짽짾짿쨀쨁쨂쨃쨄쨅쨆쨇쨈쨉쨊쨋쨌쨍쨎쨏쨐쨑쨒쨓쨔쨕쨖쨗쨘쨙쨚쨛쨜쨝쨞쨟쨠쨡쨢쨣쨤쨥쨦쨧쨨쨩쨪쨫쨬쨭쨮쨯쨰쨱쨲쨳쨴쨵쨶쨷쨸쨹쨺쨻쨼쨽쨾쨿쩀쩁쩂쩃쩄쩅쩆쩇쩈쩉쩊쩋쩌쩍쩎쩏쩐쩑쩒쩓쩔쩕쩖쩗쩘쩙쩚쩛쩜쩝쩞쩟쩠쩡쩢쩣쩤쩥쩦쩧쩨쩩쩪쩫쩬쩭쩮쩯쩰쩱쩲쩳쩴쩵쩶쩷쩸쩹쩺쩻쩼쩽쩾쩿쪀쪁쪂쪃쪄쪅쪆쪇쪈쪉쪊쪋쪌쪍쪎쪏쪐쪑쪒쪓쪔쪕쪖쪗쪘쪙쪚쪛쪜쪝쪞쪟쪠쪡쪢쪣쪤쪥쪦쪧쪨쪩쪪쪫쪬쪭쪮쪯쪰쪱쪲쪳쪴쪵쪶쪷쪸쪹쪺쪻쪼쪽쪾쪿쫀쫁쫂쫃쫄쫅쫆쫇쫈쫉쫊쫋쫌쫍쫎쫏쫐쫑쫒쫓쫔쫕쫖쫗쫘쫙쫚쫛쫜쫝쫞쫟쫠쫡쫢쫣쫤쫥쫦쫧쫨쫩쫪쫫쫬쫭쫮쫯쫰쫱쫲쫳쫴쫵쫶쫷쫸쫹쫺쫻쫼쫽쫾쫿쬀쬁쬂쬃쬄쬅쬆쬇쬈쬉쬊쬋쬌쬍쬎쬏쬐쬑쬒쬓쬔쬕쬖쬗쬘쬙쬚쬛쬜쬝쬞쬟쬠쬡쬢쬣쬤쬥쬦쬧쬨쬩쬪쬫쬬쬭쬮쬯쬰쬱쬲쬳쬴쬵쬶쬷쬸쬹쬺쬻쬼쬽쬾쬿쭀쭁쭂쭃쭄쭅쭆쭇쭈쭉쭊쭋쭌쭍쭎쭏쭐쭑쭒쭓쭔쭕쭖쭗쭘쭙쭚쭛쭜쭝쭞쭟쭠쭡쭢쭣쭤쭥쭦쭧쭨쭩쭪쭫쭬쭭쭮쭯쭰쭱쭲쭳쭴쭵쭶쭷쭸쭹쭺쭻쭼쭽쭾쭿쮀쮁쮂쮃쮄쮅쮆쮇쮈쮉쮊쮋쮌쮍쮎쮏쮐쮑쮒쮓쮔쮕쮖쮗쮘쮙쮚쮛쮜쮝쮞쮟쮠쮡쮢쮣쮤쮥쮦쮧쮨쮩쮪쮫쮬쮭쮮쮯쮰쮱쮲쮳쮴쮵쮶쮷쮸쮹쮺쮻쮼쮽쮾쮿쯀쯁쯂쯃쯄쯅쯆쯇쯈쯉쯊쯋쯌쯍쯎쯏쯐쯑쯒쯓쯔쯕쯖쯗쯘쯙쯚쯛쯜쯝쯞쯟쯠쯡쯢쯣쯤쯥쯦쯧쯨쯩쯪쯫쯬쯭쯮쯯쯰쯱쯲쯳쯴쯵쯶쯷쯸쯹쯺쯻쯼쯽쯾쯿찀찁찂찃찄찅찆찇찈찉찊찋찌찍찎찏찐찑찒찓찔찕찖찗찘찙찚찛찜찝찞찟찠찡찢찣찤찥찦찧차착찪찫찬찭찮찯찰찱찲찳찴찵찶찷참찹찺찻찼창찾찿챀챁챂챃채책챆챇챈챉챊챋챌챍챎챏챐챑챒챓챔챕챖챗챘챙챚챛챜챝챞챟챠챡챢챣챤챥챦챧챨챩챪챫챬챭챮챯챰챱챲챳챴챵챶챷챸챹챺챻챼챽챾챿첀첁첂첃첄첅첆첇첈첉첊첋첌첍첎첏첐첑첒첓첔첕첖첗처척첚첛천첝첞첟철첡첢첣첤첥첦첧첨첩첪첫첬청첮첯첰첱첲첳체첵첶첷첸첹첺첻첼첽첾첿쳀쳁쳂쳃쳄쳅쳆쳇쳈쳉쳊쳋쳌쳍쳎쳏쳐쳑쳒쳓쳔쳕쳖쳗쳘쳙쳚쳛쳜쳝쳞쳟쳠쳡쳢쳣쳤쳥쳦쳧쳨쳩쳪쳫쳬쳭쳮쳯쳰쳱쳲쳳쳴쳵쳶쳷쳸쳹쳺쳻쳼쳽쳾쳿촀촁촂촃촄촅촆촇초촉촊촋촌촍촎촏촐촑촒촓촔촕촖촗촘촙촚촛촜총촞촟촠촡촢촣촤촥촦촧촨촩촪촫촬촭촮촯촰촱촲촳촴촵촶촷촸촹촺촻촼촽촾촿쵀쵁쵂쵃쵄쵅쵆쵇쵈쵉쵊쵋쵌쵍쵎쵏쵐쵑쵒쵓쵔쵕쵖쵗쵘쵙쵚쵛최쵝쵞쵟쵠쵡쵢쵣쵤쵥쵦쵧쵨쵩쵪쵫쵬쵭쵮쵯쵰쵱쵲쵳쵴쵵쵶쵷쵸쵹쵺쵻쵼쵽쵾쵿춀춁춂춃춄춅춆춇춈춉춊춋춌춍춎춏춐춑춒춓추축춖춗춘춙춚춛출춝춞춟춠춡춢춣춤춥춦춧춨충춪춫춬춭춮춯춰춱춲춳춴춵춶춷춸춹춺춻춼춽춾춿췀췁췂췃췄췅췆췇췈췉췊췋췌췍췎췏췐췑췒췓췔췕췖췗췘췙췚췛췜췝췞췟췠췡췢췣췤췥췦췧취췩췪췫췬췭췮췯췰췱췲췳췴췵췶췷췸췹췺췻췼췽췾췿츀츁츂츃츄츅츆츇츈츉츊츋츌츍츎츏츐츑츒츓츔츕츖츗츘츙츚츛츜츝츞츟츠측츢츣츤츥츦츧츨츩츪츫츬츭츮츯츰츱츲츳츴층츶츷츸츹츺츻츼츽츾츿칀칁칂칃칄칅칆칇칈칉칊칋칌칍칎칏칐칑칒칓칔칕칖칗치칙칚칛친칝칞칟칠칡칢칣칤칥칦칧침칩칪칫칬칭칮칯칰칱칲칳카칵칶칷칸칹칺칻칼칽칾칿캀캁캂캃캄캅캆캇캈캉캊캋캌캍캎캏캐캑캒캓캔캕캖캗캘캙캚캛캜캝캞캟캠캡캢캣캤캥캦캧캨캩캪캫캬캭캮캯캰캱캲캳캴캵캶캷캸캹캺캻캼캽캾캿컀컁컂컃컄컅컆컇컈컉컊컋컌컍컎컏컐컑컒컓컔컕컖컗컘컙컚컛컜컝컞컟컠컡컢컣커컥컦컧컨컩컪컫컬컭컮컯컰컱컲컳컴컵컶컷컸컹컺컻컼컽컾컿케켁켂켃켄켅켆켇켈켉켊켋켌켍켎켏켐켑켒켓켔켕켖켗켘켙켚켛켜켝켞켟켠켡켢켣켤켥켦켧켨켩켪켫켬켭켮켯켰켱켲켳켴켵켶켷켸켹켺켻켼켽켾켿콀콁콂콃콄콅콆콇콈콉콊콋콌콍콎콏콐콑콒콓코콕콖콗콘콙콚콛콜콝콞콟콠콡콢콣콤콥콦콧콨콩콪콫콬콭콮콯콰콱콲콳콴콵콶콷콸콹콺콻콼콽콾콿쾀쾁쾂쾃쾄쾅쾆쾇쾈쾉쾊쾋쾌쾍쾎쾏쾐쾑쾒쾓쾔쾕쾖쾗쾘쾙쾚쾛쾜쾝쾞쾟쾠쾡쾢쾣쾤쾥쾦쾧쾨쾩쾪쾫쾬쾭쾮쾯쾰쾱쾲쾳쾴쾵쾶쾷쾸쾹쾺쾻쾼쾽쾾쾿쿀쿁쿂쿃쿄쿅쿆쿇쿈쿉쿊쿋쿌쿍쿎쿏쿐쿑쿒쿓쿔쿕쿖쿗쿘쿙쿚쿛쿜쿝쿞쿟쿠쿡쿢쿣쿤쿥쿦쿧쿨쿩쿪쿫쿬쿭쿮쿯쿰쿱쿲쿳쿴쿵쿶쿷쿸쿹쿺쿻쿼쿽쿾쿿퀀퀁퀂퀃퀄퀅퀆퀇퀈퀉퀊퀋퀌퀍퀎퀏퀐퀑퀒퀓퀔퀕퀖퀗퀘퀙퀚퀛퀜퀝퀞퀟퀠퀡퀢퀣퀤퀥퀦퀧퀨퀩퀪퀫퀬퀭퀮퀯퀰퀱퀲퀳퀴퀵퀶퀷퀸퀹퀺퀻퀼퀽퀾퀿큀큁큂큃큄큅큆큇큈큉큊큋큌큍큎큏큐큑큒큓큔큕큖큗큘큙큚큛큜큝큞큟큠큡큢큣큤큥큦큧큨큩큪큫크큭큮큯큰큱큲큳클큵큶큷큸큹큺큻큼큽큾큿킀킁킂킃킄킅킆킇킈킉킊킋킌킍킎킏킐킑킒킓킔킕킖킗킘킙킚킛킜킝킞킟킠킡킢킣키킥킦킧킨킩킪킫킬킭킮킯킰킱킲킳킴킵킶킷킸킹킺킻킼킽킾킿타탁탂탃탄탅탆탇탈탉탊탋탌탍탎탏탐탑탒탓탔탕탖탗탘탙탚탛태택탞탟탠탡탢탣탤탥탦탧탨탩탪탫탬탭탮탯탰탱탲탳탴탵탶탷탸탹탺탻탼탽탾탿턀턁턂턃턄턅턆턇턈턉턊턋턌턍턎턏턐턑턒턓턔턕턖턗턘턙턚턛턜턝턞턟턠턡턢턣턤턥턦턧턨턩턪턫턬턭턮턯터턱턲턳턴턵턶턷털턹턺턻턼턽턾턿텀텁텂텃텄텅텆텇텈텉텊텋테텍텎텏텐텑텒텓텔텕텖텗텘텙텚텛템텝텞텟텠텡텢텣텤텥텦텧텨텩텪텫텬텭텮텯텰텱텲텳텴텵텶텷텸텹텺텻텼텽텾텿톀톁톂톃톄톅톆톇톈톉톊톋톌톍톎톏톐톑톒톓톔톕톖톗톘톙톚톛톜톝톞톟토톡톢톣톤톥톦톧톨톩톪톫톬톭톮톯톰톱톲톳톴통톶톷톸톹톺톻톼톽톾톿퇀퇁퇂퇃퇄퇅퇆퇇퇈퇉퇊퇋퇌퇍퇎퇏퇐퇑퇒퇓퇔퇕퇖퇗퇘퇙퇚퇛퇜퇝퇞퇟퇠퇡퇢퇣퇤퇥퇦퇧퇨퇩퇪퇫퇬퇭퇮퇯퇰퇱퇲퇳퇴퇵퇶퇷퇸퇹퇺퇻퇼퇽퇾퇿툀툁툂툃툄툅툆툇툈툉툊툋툌툍툎툏툐툑툒툓툔툕툖툗툘툙툚툛툜툝툞툟툠툡툢툣툤툥툦툧툨툩툪툫투툭툮툯툰툱툲툳툴툵툶툷툸툹툺툻툼툽툾툿퉀퉁퉂퉃퉄퉅퉆퉇퉈퉉퉊퉋퉌퉍퉎퉏퉐퉑퉒퉓퉔퉕퉖퉗퉘퉙퉚퉛퉜퉝퉞퉟퉠퉡퉢퉣퉤퉥퉦퉧퉨퉩퉪퉫퉬퉭퉮퉯퉰퉱퉲퉳퉴퉵퉶퉷퉸퉹퉺퉻퉼퉽퉾퉿튀튁튂튃튄튅튆튇튈튉튊튋튌튍튎튏튐튑튒튓튔튕튖튗튘튙튚튛튜튝튞튟튠튡튢튣튤튥튦튧튨튩튪튫튬튭튮튯튰튱튲튳튴튵튶튷트특튺튻튼튽튾튿틀틁틂틃틄틅틆틇틈틉틊틋틌틍틎틏틐틑틒틓틔틕틖틗틘틙틚틛틜틝틞틟틠틡틢틣틤틥틦틧틨틩틪틫틬틭틮틯티틱틲틳틴틵틶틷틸틹틺틻틼틽틾틿팀팁팂팃팄팅팆팇팈팉팊팋파팍팎팏판팑팒팓팔팕팖팗팘팙팚팛팜팝팞팟팠팡팢팣팤팥팦팧패팩팪팫팬팭팮팯팰팱팲팳팴팵팶팷팸팹팺팻팼팽팾팿퍀퍁퍂퍃퍄퍅퍆퍇퍈퍉퍊퍋퍌퍍퍎퍏퍐퍑퍒퍓퍔퍕퍖퍗퍘퍙퍚퍛퍜퍝퍞퍟퍠퍡퍢퍣퍤퍥퍦퍧퍨퍩퍪퍫퍬퍭퍮퍯퍰퍱퍲퍳퍴퍵퍶퍷퍸퍹퍺퍻퍼퍽퍾퍿펀펁펂펃펄펅펆펇펈펉펊펋펌펍펎펏펐펑펒펓펔펕펖펗페펙펚펛펜펝펞펟펠펡펢펣펤펥펦펧펨펩펪펫펬펭펮펯펰펱펲펳펴펵펶펷편펹펺펻펼펽펾펿폀폁폂폃폄폅폆폇폈평폊폋폌폍폎폏폐폑폒폓폔폕폖폗폘폙폚폛폜폝폞폟폠폡폢폣폤폥폦폧폨폩폪폫포폭폮폯폰폱폲폳폴폵폶폷폸폹폺폻폼폽폾폿퐀퐁퐂퐃퐄퐅퐆퐇퐈퐉퐊퐋퐌퐍퐎퐏퐐퐑퐒퐓퐔퐕퐖퐗퐘퐙퐚퐛퐜퐝퐞퐟퐠퐡퐢퐣퐤퐥퐦퐧퐨퐩퐪퐫퐬퐭퐮퐯퐰퐱퐲퐳퐴퐵퐶퐷퐸퐹퐺퐻퐼퐽퐾퐿푀푁푂푃푄푅푆푇푈푉푊푋푌푍푎푏푐푑푒푓푔푕푖푗푘푙푚푛표푝푞푟푠푡푢푣푤푥푦푧푨푩푪푫푬푭푮푯푰푱푲푳푴푵푶푷푸푹푺푻푼푽푾푿풀풁풂풃풄풅풆풇품풉풊풋풌풍풎풏풐풑풒풓풔풕풖풗풘풙풚풛풜풝풞풟풠풡풢풣풤풥풦풧풨풩풪풫풬풭풮풯풰풱풲풳풴풵풶풷풸풹풺풻풼풽풾풿퓀퓁퓂퓃퓄퓅퓆퓇퓈퓉퓊퓋퓌퓍퓎퓏퓐퓑퓒퓓퓔퓕퓖퓗퓘퓙퓚퓛퓜퓝퓞퓟퓠퓡퓢퓣퓤퓥퓦퓧퓨퓩퓪퓫퓬퓭퓮퓯퓰퓱퓲퓳퓴퓵퓶퓷퓸퓹퓺퓻퓼퓽퓾퓿픀픁픂픃프픅픆픇픈픉픊픋플픍픎픏픐픑픒픓픔픕픖픗픘픙픚픛픜픝픞픟픠픡픢픣픤픥픦픧픨픩픪픫픬픭픮픯픰픱픲픳픴픵픶픷픸픹픺픻피픽픾픿핀핁핂핃필핅핆핇핈핉핊핋핌핍핎핏핐핑핒핓핔핕핖핗하학핚핛한핝핞핟할핡핢핣핤핥핦핧함합핪핫핬항핮핯핰핱핲핳해핵핶핷핸핹핺핻핼핽핾핿햀햁햂햃햄햅햆햇했행햊햋햌햍햎햏햐햑햒햓햔햕햖햗햘햙햚햛햜햝햞햟햠햡햢햣햤향햦햧햨햩햪햫햬햭햮햯햰햱햲햳햴햵햶햷햸햹햺햻햼햽햾햿헀헁헂헃헄헅헆헇허헉헊헋헌헍헎헏헐헑헒헓헔헕헖헗험헙헚헛헜헝헞헟헠헡헢헣헤헥헦헧헨헩헪헫헬헭헮헯헰헱헲헳헴헵헶헷헸헹헺헻헼헽헾헿혀혁혂혃현혅혆혇혈혉혊혋혌혍혎혏혐협혒혓혔형혖혗혘혙혚혛혜혝혞혟혠혡혢혣혤혥혦혧혨혩혪혫혬혭혮혯혰혱혲혳혴혵혶혷호혹혺혻혼혽혾혿홀홁홂홃홄홅홆홇홈홉홊홋홌홍홎홏홐홑홒홓화확홖홗환홙홚홛활홝홞홟홠홡홢홣홤홥홦홧홨황홪홫홬홭홮홯홰홱홲홳홴홵홶홷홸홹홺홻홼홽홾홿횀횁횂횃횄횅횆횇횈횉횊횋회획횎횏횐횑횒횓횔횕횖횗횘횙횚횛횜횝횞횟횠횡횢횣횤횥횦횧효횩횪횫횬횭횮횯횰횱횲횳횴횵횶횷횸횹횺횻횼횽횾횿훀훁훂훃후훅훆훇훈훉훊훋훌훍훎훏훐훑훒훓훔훕훖훗훘훙훚훛훜훝훞훟훠훡훢훣훤훥훦훧훨훩훪훫훬훭훮훯훰훱훲훳훴훵훶훷훸훹훺훻훼훽훾훿휀휁휂휃휄휅휆휇휈휉휊휋휌휍휎휏휐휑휒휓휔휕휖휗휘휙휚휛휜휝휞휟휠휡휢휣휤휥휦휧휨휩휪휫휬휭휮휯휰휱휲휳휴휵휶휷휸휹휺휻휼휽휾휿흀흁흂흃흄흅흆흇흈흉흊흋흌흍흎흏흐흑흒흓흔흕흖흗흘흙흚흛흜흝흞흟흠흡흢흣흤흥흦흧흨흩흪흫희흭흮흯흰흱흲흳흴흵흶흷흸흹흺흻흼흽흾흿힀힁힂힃힄힅힆힇히힉힊힋힌힍힎힏힐힑힒힓힔힕힖힗힘힙힚힛힜힝힞힟힠힡힢힣ힰힱힲힳힴힵힶힷힸힹힺힻힼힽힾힿퟀퟁퟂퟃퟄퟅퟆퟋퟌퟍퟎퟏퟐퟑퟒퟓퟔퟕퟖퟗퟘퟙퟚퟛퟜퟝퟞퟟퟠퟡퟢퟣퟤퟥퟦퟧퟨퟩퟪퟫퟬퟭퟮퟯퟰퟱퟲퟳퟴퟵퟶퟷퟸퟹퟺퟻ???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????􏰀???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????豈更車賈滑串句龜龜契金喇奈懶癩羅蘿螺裸邏樂洛烙珞落酪駱亂卵欄爛蘭鸞嵐濫藍襤拉臘蠟廊朗浪狼郎來冷勞擄櫓爐盧老蘆虜路露魯鷺碌祿綠菉錄鹿論壟弄籠聾牢磊賂雷壘屢樓淚漏累縷陋勒肋凜凌稜綾菱陵讀拏樂諾丹寧怒率異北磻便復不泌數索參塞省葉說殺辰沈拾若掠略亮兩凉梁糧良諒量勵呂女廬旅濾礪閭驪麗黎力曆歷轢年憐戀撚漣煉璉秊練聯輦蓮連鍊列劣咽烈裂說廉念捻殮簾獵令囹寧嶺怜玲瑩羚聆鈴零靈領例禮醴隸惡了僚寮尿料樂燎療蓼遼龍暈阮劉杻柳流溜琉留硫紐類六戮陸倫崙淪輪律慄栗率隆利吏履易李梨泥理痢罹裏裡里離匿溺吝燐璘藺隣鱗麟林淋臨立笠粒狀炙識什茶刺切度拓糖宅洞暴輻行降見廓兀嗀﨎﨏塚﨑晴﨓﨔凞猪益礼神祥福靖精羽﨟蘒﨡諸﨣﨤逸都﨧﨨﨩飯飼館鶴郞隷侮僧免勉勤卑喝嘆器塀墨層屮悔慨憎懲敏既暑梅海渚漢煮爫琢碑社祉祈祐祖祝禍禎穀突節練縉繁署者臭艹艹著褐視謁謹賓贈辶逸難響頻恵𤋮舘並况全侀充冀勇勺喝啕喙嗢塚墳奄奔婢嬨廒廙彩徭惘慎愈憎慠懲戴揄搜摒敖晴朗望杖歹殺流滛滋漢瀞煮瞧爵犯猪瑱甆画瘝瘟益盛直睊着磌窱節类絛練缾者荒華蝹襁覆視調諸請謁諾諭謹變贈輸遲醙鉶陼難靖韛響頋頻鬒龜𢡊𢡄𣏕㮝䀘䀹𥉉𥳐𧻓齃龎fffiflffifflſtstﬓﬔﬕﬖﬗיִﬞײַﬠﬡﬢﬣﬤﬥﬦﬧﬨ﬩שׁשׂשּׁשּׂאַאָאּבּגּדּהּוּזּטּיּךּכּלּמּנּסּףּפּצּקּרּשּתּוֹבֿכֿפֿﭏﭐﭑﭒﭓﭔﭕﭖﭗﭘﭙﭚﭛﭜﭝﭞﭟﭠﭡﭢﭣﭤﭥﭦﭧﭨﭩﭪﭫﭬﭭﭮﭯﭰﭱﭲﭳﭴﭵﭶﭷﭸﭹﭺﭻﭼﭽﭾﭿﮀﮁﮂﮃﮄﮅﮆﮇﮈﮉﮊﮋﮌﮍﮎﮏﮐﮑﮒﮓﮔﮕﮖﮗﮘﮙﮚﮛﮜﮝﮞﮟﮠﮡﮢﮣﮤﮥﮦﮧﮨﮩﮪﮫﮬﮭﮮﮯﮰﮱ﮲﮳﮴﮵﮶﮷﮸﮹﮺﮻﮼﮽﮾﮿﯀﯁ﯓﯔﯕﯖﯗﯘﯙﯚﯛﯜﯝﯞﯟﯠﯡﯢﯣﯤﯥﯦﯧﯨﯩﯪﯫﯬﯭﯮﯯﯰﯱﯲﯳﯴﯵﯶﯷﯸﯹﯺﯻﯼﯽﯾﯿﰀﰁﰂﰃﰄﰅﰆﰇﰈﰉﰊﰋﰌﰍﰎﰏﰐﰑﰒﰓﰔﰕﰖﰗﰘﰙﰚﰛﰜﰝﰞﰟﰠﰡﰢﰣﰤﰥﰦﰧﰨﰩﰪﰫﰬﰭﰮﰯﰰﰱﰲﰳﰴﰵﰶﰷﰸﰹﰺﰻﰼﰽﰾﰿﱀﱁﱂﱃﱄﱅﱆﱇﱈﱉﱊﱋﱌﱍﱎﱏﱐﱑﱒﱓﱔﱕﱖﱗﱘﱙﱚﱛﱜﱝﱞﱟﱠﱡﱢﱣﱤﱥﱦﱧﱨﱩﱪﱫﱬﱭﱮﱯﱰﱱﱲﱳﱴﱵﱶﱷﱸﱹﱺﱻﱼﱽﱾﱿﲀﲁﲂﲃﲄﲅﲆﲇﲈﲉﲊﲋﲌﲍﲎﲏﲐﲑﲒﲓﲔﲕﲖﲗﲘﲙﲚﲛﲜﲝﲞﲟﲠﲡﲢﲣﲤﲥﲦﲧﲨﲩﲪﲫﲬﲭﲮﲯﲰﲱﲲﲳﲴﲵﲶﲷﲸﲹﲺﲻﲼﲽﲾﲿﳀﳁﳂﳃﳄﳅﳆﳇﳈﳉﳊﳋﳌﳍﳎﳏﳐﳑﳒﳓﳔﳕﳖﳗﳘﳙﳚﳛﳜﳝﳞﳟﳠﳡﳢﳣﳤﳥﳦﳧﳨﳩﳪﳫﳬﳭﳮﳯﳰﳱﳲﳳﳴﳵﳶﳷﳸﳹﳺﳻﳼﳽﳾﳿﴀﴁﴂﴃﴄﴅﴆﴇﴈﴉﴊﴋﴌﴍﴎﴏﴐﴑﴒﴓﴔﴕﴖﴗﴘﴙﴚﴛﴜﴝﴞﴟﴠﴡﴢﴣﴤﴥﴦﴧﴨﴩﴪﴫﴬﴭﴮﴯﴰﴱﴲﴳﴴﴵﴶﴷﴸﴹﴺﴻﴼﴽ﴾﴿ﵐﵑﵒﵓﵔﵕﵖﵗﵘﵙﵚﵛﵜﵝﵞﵟﵠﵡﵢﵣﵤﵥﵦﵧﵨﵩﵪﵫﵬﵭﵮﵯﵰﵱﵲﵳﵴﵵﵶﵷﵸﵹﵺﵻﵼﵽﵾﵿﶀﶁﶂﶃﶄﶅﶆﶇﶈﶉﶊﶋﶌﶍﶎﶏﶒﶓﶔﶕﶖﶗﶘﶙﶚﶛﶜﶝﶞﶟﶠﶡﶢﶣﶤﶥﶦﶧﶨﶩﶪﶫﶬﶭﶮﶯﶰﶱﶲﶳﶴﶵﶶﶷﶸﶹﶺﶻﶼﶽﶾﶿﷀﷁﷂﷃﷄﷅﷆﷇﷰﷱﷲﷳﷴﷵﷶﷷﷸﷹﷺﷻ﷼﷽︀︁︂︃︄︅︆︇︈︉︊︋︌︍︎️︐︑︒︓︔︕︖︗︘︙︠︡︢︣︤︥︦︰︱︲︳︴︵︶︷︸︹︺︻︼︽︾︿﹀﹁﹂﹃﹄﹅﹆﹇﹈﹉﹊﹋﹌﹍﹎﹏﹐﹑﹒﹔﹕﹖﹗﹘﹙﹚﹛﹜﹝﹞﹟﹠﹡﹢﹣﹤﹥﹦﹨﹩﹪﹫ﹰﹱﹲﹳﹴﹶﹷﹸﹹﹺﹻﹼﹽﹾﹿﺀﺁﺂﺃﺄﺅﺆﺇﺈﺉﺊﺋﺌﺍﺎﺏﺐﺑﺒﺓﺔﺕﺖﺗﺘﺙﺚﺛﺜﺝﺞﺟﺠﺡﺢﺣﺤﺥﺦﺧﺨﺩﺪﺫﺬﺭﺮﺯﺰﺱﺲﺳﺴﺵﺶﺷﺸﺹﺺﺻﺼﺽﺾﺿﻀﻁﻂﻃﻄﻅﻆﻇﻈﻉﻊﻋﻌﻍﻎﻏﻐﻑﻒﻓﻔﻕﻖﻗﻘﻙﻚﻛﻜﻝﻞﻟﻠﻡﻢﻣﻤﻥﻦﻧﻨﻩﻪﻫﻬﻭﻮﻯﻰﻱﻲﻳﻴﻵﻶﻷﻸﻹﻺﻻﻼ!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~⦅⦆。「」、・ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙゚ᅠᄀᄁᆪᄂᆬᆭᄃᄄᄅᆰᆱᆲᆳᆴᆵᄚᄆᄇᄈᄡᄉᄊᄋᄌᄍᄎᄏᄐᄑ하ᅢᅣᅤᅥᅦᅧᅨᅩᅪᅫᅬᅭᅮᅯᅰᅱᅲᅳᅴᅵ¢£¬ ̄¦¥₩│←↑→↓■○�‬‬‬ diff --git a/contrib/test/odbc/CMakeLists.txt b/contrib/test/odbc/CMakeLists.txt new file mode 100644 index 00000000000..876f54c637e --- /dev/null +++ b/contrib/test/odbc/CMakeLists.txt @@ -0,0 +1,48 @@ +cmake_minimum_required(VERSION 3.17) +project(odbc) + +# GoogleTest requires at least C++11 +set(CMAKE_CXX_STANDARD 17) + +# Retrieve GoogleTests +include(FetchContent) +FetchContent_Declare( + googletest + URL https://github.com/google/googletest/archive/refs/tags/release-1.11.0.zip +) + +# For Windows: Prevent overriding the parent project's compiler/linker settings +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) +FetchContent_MakeAvailable(googletest) + +find_package(ODBC REQUIRED) + +enable_testing() + +add_executable( + + main + constants.cpp + database_objects.cpp + odbc_handler.cpp + query_generator.cpp + test_connection.cpp + test_data_types.cpp + test_diagnostics.cpp + test_direct_executed_statements.cpp + test_transactions.cpp + test_resultset.cpp + test_metadata.cpp + test_prepared_statements.cpp + test_sqlgetinfo.cpp + main.cpp +) + +target_link_libraries( + main + gtest_main + odbc +) + +include(GoogleTest) +gtest_add_tests(TARGET main) \ No newline at end of file diff --git a/contrib/test/odbc/README.md b/contrib/test/odbc/README.md new file mode 100644 index 00000000000..1c2474b811a --- /dev/null +++ b/contrib/test/odbc/README.md @@ -0,0 +1,54 @@ +# Instructions to run locally with a pre-existing db + +To run thed ODBC test framework suite for babelfish locally, +you will have to: + +1. Setup the database information +2. Run the build commands. + +## Setting up database information + +There are 2 ways of providing the database command: setting environment variables or altering the config files (environment variables will take higher priority over the config.txt file). + +### Using config.txt +The config.txt should be filled like the example below. The ```ODBC_DRIVER_NAME``` can be left blank and the default value will result in using the ```ODBC Driver 17 for SQL Server`` + + +``` +ODBC_DRIVER_NAME= +BABEL_DB_SERVER=localhost +BABEL_DB_PORT=1433 +BABEL_DB_USER=sa +BABEL_DB_PASSWORD= +BABEL_DB_NAME=master +``` + +NOTE: There may be some fields that are pre-fixed with ```SQL_DB_```. Please ignore these for now. They were left in from the previous state of these tests but will most likely not be used and removed in the future. + +### Using environment variables + +The environment variables will have the same name as the keys in the config file (e.g. BABEL_DB_SERVER will correspond with the server name). When running the build commands, you may set the environment variable in you .zshrc file (or .bashprofile) or before executing the main file like the example below. + +``` +// In the odbc directory +BABEL_DB_SERVER=localhost BABEL_DB_PORT=1433 ./build/main +``` + + +## Build commands +To build these run these set of commands + + +``` +// Make sure you are in the odbc directory +cmake -D CMAKE_C_COMPILER=gcc-10 -D CMAKE_CXX_COMPILER=g++-10 -S . -B build +cmake --build build +./build/main +``` + +## Disabling a test + +To disable a test, simply put "DISABLED_" on the second parameter of the TEST_F descriptor. + +For example, if I wanted to disable a test labled TEST_F(testsuite, notWorkingTest). I would change it to +TEST_F(testsuite, DISABLED_notWorkingTest) \ No newline at end of file diff --git a/contrib/test/odbc/config.txt b/contrib/test/odbc/config.txt new file mode 100644 index 00000000000..4ffd541c30e --- /dev/null +++ b/contrib/test/odbc/config.txt @@ -0,0 +1,6 @@ +ODBC_DRIVER_NAME= +BABEL_DB_SERVER= +BABEL_DB_PORT= +BABEL_DB_USER= +BABEL_DB_PASSWORD= +BABEL_DB_NAME=master \ No newline at end of file diff --git a/contrib/test/odbc/constants.cpp b/contrib/test/odbc/constants.cpp new file mode 100644 index 00000000000..abc9d266360 --- /dev/null +++ b/contrib/test/odbc/constants.cpp @@ -0,0 +1,19 @@ +#include "constants.h" +using std::string; + +string constants::INPUT_SOURCE = "input"; +string constants::ODBC_DRIVER_NAME = "ODBC Driver 17 for SQL Server"; + +string constants::BABEL_DB_SERVER = "localhost"; +string constants::BABEL_DB_PORT = "1433"; +string constants::BABEL_DB_USER = "admin"; +string constants::BABEL_DB_PASSWORD = ""; +string constants::BABEL_DB_NAME = "master"; + +string constants::SQL_DB_SERVER = "localhost"; +string constants::SQL_DB_PORT = "1433"; +string constants::SQL_DB_USER = "admin"; +string constants::SQL_DB_PASSWORD = ""; +string constants::SQL_DB_NAME = "master"; + +string constants::null_str = ""; \ No newline at end of file diff --git a/contrib/test/odbc/constants.h b/contrib/test/odbc/constants.h new file mode 100644 index 00000000000..468cdb603a4 --- /dev/null +++ b/contrib/test/odbc/constants.h @@ -0,0 +1,34 @@ +#ifndef ODBC__constants_H_ +#define ODBC__constants_H_ + +#include + +using std::string; + +namespace constants{ + +enum class ServerType { + Babel, + SQL, +}; + +extern string INPUT_SOURCE; +extern string ODBC_DRIVER_NAME; + +extern string BABEL_DB_SERVER; +extern string BABEL_DB_PORT; +extern string BABEL_DB_USER; +extern string BABEL_DB_PASSWORD; +extern string BABEL_DB_NAME; + +extern string SQL_DB_SERVER; +extern string SQL_DB_PORT; +extern string SQL_DB_USER; +extern string SQL_DB_PASSWORD; +extern string SQL_DB_NAME; + +extern string null_str; + +} + +#endif diff --git a/contrib/test/odbc/database_objects.cpp b/contrib/test/odbc/database_objects.cpp new file mode 100644 index 00000000000..2b57cfb6401 --- /dev/null +++ b/contrib/test/odbc/database_objects.cpp @@ -0,0 +1,82 @@ +#include "database_objects.h" +#include "query_generator.h" + +#include + +using std::string; +using std::vector; +using std::pair; + +DatabaseObjects::DatabaseObjects() { + + odbcHandler.Connect(true); +} + +DatabaseObjects::~DatabaseObjects() { + + DropObjects("PROCEDURE", procedures); + DropObjects("FUNCTION", functions); + + DropObjects("VIEW", views); + DropObjects("TABLE", tables); + DropObjects("SCHEMA", schemas); +} + +void DatabaseObjects::CreateSchema(const string &schema_name) { + + DropObject("SCHEMA", schema_name); + odbcHandler.ExecQuery(CreateSchemaStatement(schema_name)); + schemas.push_back(schema_name); +} + +void DatabaseObjects::CreateTable(const string &table_name, const vector> &columns, const string constraints) { + + DropObject("TABLE", table_name); + odbcHandler.ExecQuery(CreateTableStatement(table_name, columns, constraints)); + tables.push_back(table_name); +} + +void DatabaseObjects::DatabaseObjects::CreateView(const string &view_name, const string &select_statement) { + + DropObject("VIEW",view_name); + odbcHandler.ExecQuery(CreateViewStatement(view_name, select_statement)); + views.push_back(view_name); +} + +void DatabaseObjects::CreateProcedure(const string &procedure_name, const string &procedure_definition, const string parameters) { + + DropObject("PROCEDURE",procedure_name); + odbcHandler.ExecQuery(CreateProcedureStatement(procedure_name, procedure_definition, parameters)); + procedures.push_back(procedure_name); +} + +void DatabaseObjects::CreateFunction(const string &function_name, const string &function_definition) { + + DropObject("FUNCTION",function_name); + odbcHandler.ExecQuery(CreateFunctionStatement(function_name, function_definition)); + functions.push_back(function_name); +} + +void DatabaseObjects::Insert(const string &table_name,const string &values) { + odbcHandler.ExecQuery(InsertStatement(table_name, values)); +} + +void DatabaseObjects::Insert(const string &table_name, const vector &values) { + + odbcHandler.ExecQuery(InsertStatement(table_name, values)); +} + +void DatabaseObjects::DropObject(const string &object_kind, const string &object_name, bool check_exists) { + + odbcHandler.ExecQuery(DropObjectStatement(object_kind,object_name,check_exists)); +} + +void DatabaseObjects::DropObjects(const string &object_kind, const vector &names) { + + // Drop objects in reverse order from the one they were created. + // This is in case the later objects have dependency on earlier ones(e.g. foreign key) + for (auto it = names.rbegin(); it != names.rend(); ++it) { + DropObject(object_kind, *it); + } +} + diff --git a/contrib/test/odbc/database_objects.h b/contrib/test/odbc/database_objects.h new file mode 100644 index 00000000000..aafc074cde5 --- /dev/null +++ b/contrib/test/odbc/database_objects.h @@ -0,0 +1,54 @@ +#ifndef DATABASE_OBJECTS_H +#define DATABASE_OBJECTS_H + +#include "odbc_handler.h" +#include +#include +#include + + +class DatabaseObjects { + + public: + + DatabaseObjects(); + ~DatabaseObjects(); + + void CreateSchema(const std::string &schema_name); + // table_name may include database and/or schema name, e.g. schema_name.table_name + void CreateTable(const std::string &table_name, const std::vector> &columns, const std::string constraints = ""); + // view_name may include database and/or schema name, e.g. schema_name.view_name + void CreateView(const std::string &view_name, const std::string &select_statement); + // procedure_name may include database and/or schema name, e.g. schema_name.procedure_name + void CreateProcedure(const std::string &procedure_name, const std::string &procedure_definition, const std::string parameters = ""); + // function_name may include database and/or schema name, e.g. schema_name.function_name + void CreateFunction(const std::string &function_name, const std::string &function_definition); + + // Drop object. Object type can be "TABLE", "VIEW", "PROCEDURE", etc. Any valid database object type. + // If check_exists is true, the statement will contain 'IF EXISTS' + void DropObject(const std::string &object_kind, const std::string &object_name, bool check_exists = true); + + // values contain valid values expression for all values to be inserted. + // e.g. "(1), (2), (3)" - for a single column table + // e.g. "(1, 'hello1', 1.1), (2, 'hello2', 2.2) - for a three-column table + void Insert(const std::string &table_name,const std::string &values); + + // Each element in the values vector contains data for a single row with no (). + // e.g. values[0] = "1"; values[1] = "2" - for a single column table + // e.g. values[0] = "1, 'hello1', 1.1"; values[1] = "2, 'hello2', 2.2" - for a three-column table + void Insert(const std::string &table_name, const std::vector &values); + + private: + + OdbcHandler odbcHandler; + std::vector schemas; + std::vector tables; + std::vector views; + std::vector functions; + std::vector procedures; + + void DropObjects(const std::string &object_kind, const std::vector &names); +}; + +#endif + diff --git a/contrib/test/odbc/main.cpp b/contrib/test/odbc/main.cpp new file mode 100644 index 00000000000..38700797032 --- /dev/null +++ b/contrib/test/odbc/main.cpp @@ -0,0 +1,8 @@ +#include +#include "odbc_handler.h" + +int main(int argc, char **argv) { + + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} \ No newline at end of file diff --git a/contrib/test/odbc/odbc_handler.cpp b/contrib/test/odbc/odbc_handler.cpp new file mode 100644 index 00000000000..5ec3704a988 --- /dev/null +++ b/contrib/test/odbc/odbc_handler.cpp @@ -0,0 +1,311 @@ + +#include "odbc_handler.h" +#include +#include +#include + +using std::pair; + +OdbcHandler::OdbcHandler() { + SetConnectionString(ServerType::Babel); +} + +OdbcHandler::~OdbcHandler() { + FreeStmtHandle(); + FreeConnectionHandle(); + FreeEnvironmentHandle(); +} + +void OdbcHandler::Connect(bool allocate_statement_handle) { + + const int MAX_ATTEMPTS = 4; + int attempts = 0; + string connection_str = GetConnectionString(); + AllocateEnvironmentHandle(); + AllocateConnectionHandle(); + SQLSetConnectAttr(hdbc_, SQL_ATTR_LOGIN_TIMEOUT, (SQLPOINTER)5, 0); // 5 seconds + + do { + attempts++; + retcode_ = SQLDriverConnect(hdbc_, nullptr, (SQLCHAR *) connection_str.c_str(), SQL_NTS, nullptr, 0, nullptr, SQL_DRIVER_COMPLETE); + } while (retcode_ != SQL_SUCCESS && retcode_ != SQL_SUCCESS_WITH_INFO && attempts < MAX_ATTEMPTS ); + + AssertSqlSuccess(retcode_, "CONNECTION FAILED"); + + if (allocate_statement_handle) { + AllocateStmtHandle(); + } +} + +SQLHENV OdbcHandler::GetEnvironmentHandle() { + return this->henv_; +} + +SQLHDBC OdbcHandler::GetConnectionHandle() { + return this->hdbc_; +} + +SQLHSTMT OdbcHandler::GetStatementHandle() { + return this->hstmt_; +} + +RETCODE OdbcHandler::GetReturnCode() { + return this->retcode_; +} + +string OdbcHandler::GetConnectionString() { + return this->connection_string_; +} + +string OdbcHandler::GetDriver() { + return this->db_driver_; +} + +string OdbcHandler::GetServer() { + return this->db_server_; +} + +string OdbcHandler::GetPort() { + return this->db_port_; +} + +string OdbcHandler::GetUid() { + return this->db_uid_; +} + +string OdbcHandler::GetPwd() { + return this->db_pwd_; +} + +string OdbcHandler::GetDbname() { + return this->db_dbname_; +} + +void OdbcHandler::AllocateEnvironmentHandle() { + + if (henv_ != NULL) { + FAIL() << "ERROR: There was an attempt to allocate an already allocated environment handle"; + } + + AssertSqlSuccess(SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv_), + "ERROR: Failed to allocate the environment handle"); + + SQLSetEnvAttr(henv_, + SQL_ATTR_ODBC_VERSION, + (SQLPOINTER)SQL_OV_ODBC3, + 0); +} + +void OdbcHandler::AllocateConnectionHandle() { + + if (hdbc_ != NULL) { + FAIL() << "ERROR: There was an attempt to allocate an already allocated connection handle"; + } + + AssertSqlSuccess( + SQLAllocHandle(SQL_HANDLE_DBC, henv_, &hdbc_), + "ERROR: Failed to allocate connection handle"); + +} + +void OdbcHandler::AllocateStmtHandle() { + if (hstmt_ != NULL) { + FAIL() << "ERROR: There was an attempt to allocate an already allocated statement handle"; + } + + AssertSqlSuccess( + SQLAllocHandle(SQL_HANDLE_STMT, hdbc_, &hstmt_), + "ERROR: Failed to allocate connection handle"); +} + +void OdbcHandler::FreeEnvironmentHandle() { + if (henv_) { + SQLFreeHandle(SQL_HANDLE_ENV, henv_); + henv_ = NULL; + } +} + +void OdbcHandler::FreeConnectionHandle() { + if (hdbc_) { + SQLDisconnect(hdbc_); + SQLFreeHandle(SQL_HANDLE_DBC, hdbc_); + hdbc_ = NULL; + } +} + +void OdbcHandler::FreeStmtHandle() { + if (hstmt_) { + SQLFreeStmt(hstmt_, SQL_CLOSE); + SQLFreeHandle(SQL_HANDLE_STMT, hstmt_); + hstmt_ = NULL; + } +} + +void OdbcHandler::FreeAllHandles() { + FreeStmtHandle(); + FreeConnectionHandle(); + FreeEnvironmentHandle(); +} + +void OdbcHandler::CloseStmt() { + if (hstmt_) { + SQLFreeStmt(hstmt_, SQL_CLOSE); + } +} + +void OdbcHandler::SetConnectionString (ServerType server_type) { + + map config_file_values = ParseConfigFile(); + db_driver_ = getenv("ODBC_DRIVER_NAME") ? string(getenv("BABEL_DB_SERVER")) : + config_file_values.find("ODBC_DRIVER_NAME") != config_file_values.end() ? config_file_values["ODBC_DRIVER_NAME"] : ODBC_DRIVER_NAME; + switch (server_type) { + case ServerType::Babel: + db_server_ = getenv("BABEL_DB_SERVER") ? string(getenv("BABEL_DB_SERVER")) : + config_file_values.find("BABEL_DB_SERVER") != config_file_values.end() ? config_file_values["BABEL_DB_SERVER"] : BABEL_DB_SERVER; + db_port_ = getenv("BABEL_DB_PORT") ? string(getenv("BABEL_DB_PORT")) : + config_file_values.find("BABEL_DB_PORT") != config_file_values.end() ? config_file_values["BABEL_DB_PORT"] : BABEL_DB_PORT; + db_uid_ = getenv("BABEL_DB_USER") ? string(getenv("BABEL_DB_USER")) : + config_file_values.find("BABEL_DB_USER") != config_file_values.end() ? config_file_values["BABEL_DB_USER"] : BABEL_DB_USER; + db_pwd_ = getenv("BABEL_DB_PASSWORD") ? string(getenv("BABEL_DB_PASSWORD")) : + config_file_values.find("BABEL_DB_PASSWORD") != config_file_values.end() ? config_file_values["BABEL_DB_PASSWORD"] : BABEL_DB_PASSWORD; + db_dbname_ = getenv("BABEL_DB_NAME") ? string(getenv("BABEL_DB_NAME")) : + config_file_values.find("BABEL_DB_NAME") != config_file_values.end() ? config_file_values["BABEL_DB_NAME"] : BABEL_DB_NAME; + break; + case ServerType::SQL: + db_server_ = getenv("SQL_DB_SERVER") ? string(getenv("SQL_DB_SERVER")) : + config_file_values.find("SQL_DB_SERVER") != config_file_values.end() ? config_file_values["SQL_DB_SERVER"] : SQL_DB_SERVER; + db_port_ = getenv("SQL_DB_PORT") ? string(getenv("SQL_DB_PORT")) : + config_file_values.find("SQL_DB_PORT") != config_file_values.end() ? config_file_values["SQL_DB_PORT"] : SQL_DB_PORT; + db_uid_ = getenv("SQL_DB_USER") ? string(getenv("SQL_DB_USER")) : + config_file_values.find("SQL_DB_USER") != config_file_values.end() ? config_file_values["SQL_DB_USER"] : SQL_DB_USER; + db_pwd_ = getenv("SQL_DB_PASSWORD") ? string(getenv("SQL_DB_PASSWORD")) : + config_file_values.find("SQL_DB_PASSWORD") != config_file_values.end() ? config_file_values["SQL_DB_PASSWORD"] : SQL_DB_PASSWORD; + db_dbname_ = getenv("SQL_DB_NAME") ? string(getenv("SQL_DB_NAME")) : + config_file_values.find("SQL_DB_NAME") != config_file_values.end() ? config_file_values["SQL_DB_NAME"] : SQL_DB_NAME; + break; + } + connection_string_ = "DRIVER={" + db_driver_ + "};SERVER=" + db_server_ + "," + db_port_ + ";UID=" + db_uid_ + ";PWD=" + db_pwd_ + ";DATABASE=" + db_dbname_; + return; +} + +void OdbcHandler::AssertSqlSuccess(RETCODE retcode, const string& error_msg) { + if (!IsSqlSuccess(retcode)) { + FAIL() << error_msg << std::endl << "Return code was: " << retcode << "\n" << "SQL Status of: " << GetSqlState(SQL_HANDLE_DBC, hdbc_); + } +} + +bool OdbcHandler::IsSqlSuccess(RETCODE retcode) { + return retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO; +} + +map OdbcHandler::ParseConfigFile() { + + string line{}; + map config_file_values{}; + std::ifstream config_file; + config_file.open("config.txt"); + + if (!config_file.is_open()) { + // ERROR: Cannot open config file + return config_file_values; + } + + while (std::getline(config_file, line)) { + + size_t index = line.find("="); + + if (index == string::npos || index == (line.length() - 1)) { + // an empty line + continue; + } + + string key = line.substr(0,index); + string value = line.substr(index+1); + + if (value.find_first_not_of(' ') == string::npos) { + // value consists of only empty spaces + continue; + } + config_file_values.insert(pair(key,value)); + + } + return config_file_values; +} + +void OdbcHandler::ExecQuery(const string& query) { + + AssertSqlSuccess( + SQLExecDirect(hstmt_, (SQLCHAR*) query.c_str(), SQL_NTS), + "ERROR: was not able to run query: " + query); + +} + +void OdbcHandler::ConnectAndExecQuery(const string& query){ + + this->Connect(true); + this->ExecQuery(query); +} + + +string OdbcHandler::GetSqlState(SQLSMALLINT HandleType, SQLHANDLE Handle) { + + SQLINTEGER native_error_ptr; + SQLCHAR sql_error_msg[1024]; + SQLCHAR sql_state[SQL_SQLSTATE_SIZE+1]; + + SQLGetDiagRec(HandleType, + Handle, + 1, + sql_state, + &native_error_ptr, + sql_error_msg, + (SQLSMALLINT)(sizeof(sql_error_msg) / sizeof(SQLCHAR)), + nullptr); + return string(reinterpret_cast(sql_state)); +} + +string OdbcHandler::GetErrorMessage(SQLSMALLINT HandleType, const RETCODE& retcode) { + + SQLINTEGER native_error_ptr; + SQLCHAR sql_error_msg[1024] = "(Unable to retrieve error message)"; + SQLCHAR sql_state[SQL_SQLSTATE_SIZE+1] = ""; + SQLHANDLE handle; + + if (retcode == SQL_SUCCESS) { + return "SQL_SUCCESS was returned but was not expected"; + } + + switch(HandleType) { + case SQL_HANDLE_ENV: + handle = henv_; + break; + case SQL_HANDLE_DBC: + handle = hdbc_; + break; + case SQL_HANDLE_STMT: + handle = hstmt_; + break; + default: + return "(Unable to retrieve error message - an invalid handle type was passed. Please ensure you are passing SQL_HANDLE_ENV, SQL_HANDLE_DBC, or SQL_HANDLE_STMT"; + } + + SQLGetDiagRec(HandleType, + handle, + 1, + sql_state, + &native_error_ptr, + sql_error_msg, + (SQLSMALLINT)(sizeof(sql_error_msg) / sizeof(SQLCHAR)), + nullptr); + return "[Return value: " + std::to_string(retcode) + "][SQLState: " + std::string((const char *) sql_state) + "] ERROR: " + std::string((const char*) sql_error_msg) + "\n"; +} + +void OdbcHandler::BindColumns(vector> columns) { + RETCODE rcode; + + for (auto column : columns) { + auto& [col_num, c_type, target, target_size] = column; + rcode = SQLBindCol(GetStatementHandle(), col_num, c_type, target, target_size, 0); + ASSERT_EQ(rcode, SQL_SUCCESS) << GetErrorMessage(SQL_HANDLE_STMT, rcode); + } +} diff --git a/contrib/test/odbc/odbc_handler.h b/contrib/test/odbc/odbc_handler.h new file mode 100644 index 00000000000..b04fdd64bf5 --- /dev/null +++ b/contrib/test/odbc/odbc_handler.h @@ -0,0 +1,138 @@ +#ifndef ODBC_HANDLER_H +#define ODBC_HANDLER_H + +#include +#include +#include +#include +#include +#include "constants.h" + +using std::string; +using std::map; +using std::vector; +using std::tuple; +using namespace constants; + +class OdbcHandler { + + public: + + // Constructor + explicit OdbcHandler(); + + // Destructor + ~OdbcHandler(); + + // Sets the connection string based on server type + void SetConnectionString(ServerType server_type); + + // Connects to Database + void Connect(bool allocate_statement_handle = false); + + // Returns the environment handle + SQLHENV GetEnvironmentHandle(); + + // Returns the connection handle + SQLHDBC GetConnectionHandle(); + + // Returns the statement handle + SQLHSTMT GetStatementHandle(); + + // Returns the return code + RETCODE GetReturnCode(); + + // Returns the connection string + string GetConnectionString(); + + // Returns the driver name + string GetDriver(); + + // Returns the server name + string GetServer(); + + // Returns the port + string GetPort(); + + // Returns the username/uid used for database login + string GetUid(); + + // Returns the password used for database login + string GetPwd(); + + // Returns the database used + string GetDbname(); + + // Allocates the connection handle and sets the environment attribute + void AllocateEnvironmentHandle(); + + // Allocates the connection handle + void AllocateConnectionHandle(); + + // Allocates the statement handle + void AllocateStmtHandle(); + + // Frees the environment handle + void FreeEnvironmentHandle(); + + // Frees the connection handle + void FreeConnectionHandle(); + + // Frees the statement handle + void FreeStmtHandle(); + + // Free all handles (without freeing the instance itself) + void FreeAllHandles(); + + // Calls FreeStmt() with SQL_CLOSE option + void CloseStmt(); + + // Asserts the return code (based on a given return code) and fails the test if an error is found + void AssertSqlSuccess(RETCODE retcode, const string& error_msg); + + // Returns whether or not the return code is SQL_SUCCESS or SQL_SUCCESS_WITH_INFO (does not fail test) + bool IsSqlSuccess(RETCODE retcode); + + // Execute a query (assuming the OdbcHandler is already connected). Will fail the test if query is unsuccessful + void ExecQuery(const string& query); + + // This function will connect to the db, allocate a statement handle, + // and execute the given query. Will fail test if query is unsuccessful. + void ConnectAndExecQuery(const string& query); + + // Retrieves the SQLState code as a string + string GetSqlState(SQLSMALLINT HandleType, SQLHANDLE Handle); + + // Creates and returns an error message containing diagnostic information + string GetErrorMessage(SQLSMALLINT HandleType, const RETCODE& retcode); + + void BindColumns(vector> columns); + + private: + // ODBC-defined SQL variables + SQLHENV henv_{}; + SQLHDBC hdbc_{}; + SQLHSTMT hstmt_{}; + RETCODE retcode_{}; + + // DB Information + string db_driver_{}; + string db_server_{}; + string db_port_{}; + string db_uid_{}; + string db_pwd_{}; + string db_dbname_{}; + + // Build the connection string for SQLDriverConnect + string connection_string_{}; + + // A map that contains values from the configuration file + map config_file_values_{}; + + // Goes through config.txt and returns a map with values from the configuration file + map ParseConfigFile(); + +}; + +#endif + diff --git a/contrib/test/odbc/query_generator.cpp b/contrib/test/odbc/query_generator.cpp new file mode 100644 index 00000000000..506fe7b82c2 --- /dev/null +++ b/contrib/test/odbc/query_generator.cpp @@ -0,0 +1,124 @@ +#include "query_generator.h" + +#include + +using std::string; +using std::map; +using std::vector; +using std::pair; + +string CreateColumnsString(const vector &columns) { + string result {}; + string comma{}; + + for (auto column : columns) { + result += comma + column; + comma = ","; + } + return result; +} + +string CreateColumnsString(const vector> &columns) { + string result{}; + string comma{}; + + for (auto column : columns) { + result += comma + column.first + " " + column.second; + comma = ","; + } + return result; +} + +string CreateInsertValuesString(const vector &values) { + string result{}; + string comma{}; + + for (auto value : values) { + result += comma + "(" + value + ")"; + comma = ","; + } + return result; +} + +// Convenience overload of the 'full' Select statement so that empty reference parameters are not required by callers. +string SelectStatement(const string &table_name, const vector &select_columns) { + return SelectStatement(table_name, select_columns, vector {}); +} + +// Simple select form one table or view. No joins. +string SelectStatement(const string &table_name, const vector &select_columns, const vector &orderby_columns, const string where_clause) { + string result {"SELECT " + CreateColumnsString(select_columns) + + "\nFROM " + table_name}; + + if (where_clause != "") { + result += "\nWHERE " + where_clause; + } + + if (!orderby_columns.empty()) { + result += "\nORDER BY " + CreateColumnsString(orderby_columns); + } + + return result; +} + +// Rudimentary insert statement +// The values string contains 'full' values string for all data, e.g. +// "(NULL, NULL), (' ',' '), (' John',' Doe'), ('John','Doe')" +string InsertStatement(const string &table_name, const string &values) { + return {"INSERT INTO " + table_name + " VALUES " + values}; +} + +// Rudimentary insert statement +// Each string in values vector represents values for a single row without the (), e.g. +//{"NULL, NULL, NULL", "1, 'hello1', 1.1", "2, 'hello2', 2.2"} +string InsertStatement(const string &table_name, const vector &values) { + return {"INSERT INTO " + table_name + " VALUES " + CreateInsertValuesString(values)}; +} + +string CreateSchemaStatement(const string &schema_name) { + return string {"CREATE SCHEMA " + schema_name}; +} + +//TODO Perhaps create 'Alter table ADD Constraint' function so that constraints can be added after the table was created. +string CreateTableStatement(const string &table_name, const vector> &columns, string constraints) { + + return string {"CREATE TABLE " + table_name + "(\n" + CreateColumnsString(columns) + + string { constraints.empty() ? "" : " \n, " + constraints } + "\n);"}; +} + +string CreateViewStatement(const string &view_name, const string &select_statement) { + + return string {"CREATE VIEW " + view_name + " AS \n " + select_statement + ";"}; +} + + +string CreateProcedureStatement(const string &procedure_name, const string &procedure_definition, const string ¶meters) { + + return string {"CREATE PROCEDURE " + procedure_name + " " + parameters + " AS \n " + procedure_definition + ";"}; +} + + +string CreateFunctionStatement(const string &function_name, const string &function_definition) { + + return string {"CREATE FUNCTION " + function_name + " \n" + function_definition + ";"}; +} + + +string DropObjectStatement(const string &object_kind, const string &object_name, bool check_exists) { + + return string { "DROP " + object_kind + string { check_exists ? " IF EXISTS " : " "} + object_name }; +} + +string PrimaryKeyConstraintSpec(const string &pk_name, const vector &columns) { + + return string {" CONSTRAINT " + pk_name + " PRIMARY KEY(" + CreateColumnsString(columns) + ")"}; +} + +string ForeignKeyConstraintSpec(const string &fk_name, + const vector &columns, + const string &ref_table, + const vector &ref_columns) { + + return string {" CONSTRAINT " + fk_name + " FOREIGN KEY(" + CreateColumnsString(columns) + ") \nREFERENCES " + + ref_table + "(" + CreateColumnsString(ref_columns) + ")"}; +} diff --git a/contrib/test/odbc/query_generator.h b/contrib/test/odbc/query_generator.h new file mode 100644 index 00000000000..5eeac58a93c --- /dev/null +++ b/contrib/test/odbc/query_generator.h @@ -0,0 +1,67 @@ +#ifndef QUERY_GENERATOR_H +#define QUERY_GENERATOR_H + +#include +#include +#include +#include + +std::string CreateSchemaStatement(const std::string &schema_name); + +// table_name may include database and/or schema name, e.g. schema_name.table_name +// columns map contains pairs column name : data type +// data type optionally may contain additional specification, e.g. NULL, not NULL, identity, default specifications, etc. +//std::string CreateTableStatement(std::string &table_name, std::map &columns); +std::string CreateTableStatement(const std::string &table_name, + const std::vector> &columns, + std::string constraints = ""); + +// view_name may include database and/or schema name, e.g. schema_name.view_name +std::string CreateViewStatement(const std::string &view_name, const std::string &select_statement); + +// procedure_name may include database and/or schema name, e.g. schema_name.procedure_name +std::string CreateProcedureStatement(const std::string &procedure_name, const std::string &procedure_definition, const std::string ¶meters); + +// function_name may include database and/or schema name, e.g. schema_name.function_name +std::string CreateFunctionStatement(const std::string &function_name, const std::string &function_definition); + +// Object type can be "TABLE", "VIEW", "PROCEDURE", etc. Any valid database object type. +// If check_exists is true, the statement will contain 'IF EXISTS' +std::string DropObjectStatement(const std::string &object_kind, const std::string &object_name, bool check_exists = true); + +// select_columns contain column names to be included in the select statement +std::string SelectStatement(const std::string &table_name, + const std::vector &select_columns); + +// select_columns contain column names to be included in the select statement +// orderby_columns contain column names to be included in the order by clause +// where clause is a valid list of conditions without the 'where keyword', e.g. "id=123 and name='John'" +std::string SelectStatement(const std::string &table_name, + const std::vector &select_columns, + const std::vector &orderby_columns, + const std::string where_clause = ""); + +// values contain valid values expression for all values to be inserted. +// e.g. "(1), (2), (3)" - for a single column table +// e.g. "(1, 'hello1', 1.1), (2, 'hello2', 2.2) - for a three-column table +std::string InsertStatement(const std::string &table_name, const std::string &values); + +// Each element in the values vector contains data for a single row with no (). +// e.g. values[0] = "1"; values[1] = "2" - for a single column table +// e.g. values[0] = "1, 'hello1', 1.1"; values[1] = "2, 'hello2', 2.2" - for a three-column table +std::string InsertStatement(const std::string &table_name, const std::vector &values); + +// Generate a primary key constraint part of SQL statement. +// columns contain column names that are part of the primary key. +std::string PrimaryKeyConstraintSpec(const std::string &pk_name, const std::vector &columns); + +// Generate a foreign key constraint part of SQL statement. +// columns contain column names that are part of the foreign key. +// ref_table is the table name that the foreign key is referencing +// ref_columns contain column names in the referenced table. +std::string ForeignKeyConstraintSpec(const std::string &fk_name, + const std::vector &columns, + const std::string &ref_table, + const std::vector &ref_columns); + +#endif diff --git a/contrib/test/odbc/test_connection.cpp b/contrib/test/odbc/test_connection.cpp new file mode 100644 index 00000000000..32ca54c8688 --- /dev/null +++ b/contrib/test/odbc/test_connection.cpp @@ -0,0 +1,29 @@ +#include "odbc_handler.h" +#include +#include +#include + +using std::unique_ptr; + +class Connection : public testing::Test{ + +}; + +TEST_F(Connection, SQLDriverConnect_1_SuccessfulConnectionTest) { + + OdbcHandler odbcHandler; + + odbcHandler.AllocateEnvironmentHandle(); + odbcHandler.AllocateConnectionHandle(); + + RETCODE rcode = SQLDriverConnect(odbcHandler.GetConnectionHandle(), + nullptr, + (SQLCHAR *) odbcHandler.GetConnectionString().c_str(), + SQL_NTS, + nullptr, + 0, + nullptr, + SQL_DRIVER_COMPLETE); + + ASSERT_TRUE(rcode == SQL_SUCCESS_WITH_INFO || rcode == SQL_SUCCESS); +} diff --git a/contrib/test/odbc/test_data_types.cpp b/contrib/test/odbc/test_data_types.cpp new file mode 100644 index 00000000000..fc513f9c788 --- /dev/null +++ b/contrib/test/odbc/test_data_types.cpp @@ -0,0 +1,457 @@ +#include "odbc_handler.h" +#include "database_objects.h" +#include "query_generator.h" + +#include +#include +#include +#include + +using std::vector; +using std::map; +using std::pair; + +const string NULL_STR = ""; + +class Data_Types : public testing::Test { + + protected: + + // Called before the first test in this test suite. + static void SetUpTestSuite() { + } + + // Called after the last test in this test suite + static void TearDownTestSuite() { + } +}; + +// Helper method that takes a string of values to be inserted and returns a string of those values with order of +// column data appended. +// SAMPLE INPUT: "("c"), ("b"), ("a")" +// SAMPLE OUTPUT: "("c", 1), ("b", 2), ("a", 3)" +string processInsertedValuesString(string insertedValues) { + string processedString = ""; + int orderOfInsertion = 1; + for (auto iterator = insertedValues.begin(); iterator < insertedValues.end(); iterator++) { + string getStr(1, *iterator); + if (getStr.compare(")") == 0) { + processedString = processedString + ", " + std::to_string(orderOfInsertion); + orderOfInsertion++; + } + processedString+=(*iterator); + } + return processedString; +} + +// Checks if a file is empty +bool is_empty(std::ifstream& pFile) +{ + return pFile.peek() == std::ifstream::traits_type::eof(); +} + +// Helper function that reads from a file and returns the contents as a string +string readFromFile(string relativePath) { + int bufferLen = 1024; + char * buffer = new char [bufferLen]; + char * fname; + + std::ifstream dataFile(relativePath); + if (is_empty(dataFile)) { + return ""; + } + + std::filesystem::path fp{relativePath}; + int fsize = std::filesystem::file_size(fp); + while (fsize > bufferLen){ + dataFile.read(buffer, bufferLen); + fsize -= bufferLen; + } + dataFile.read(buffer, fsize); + dataFile.close(); + return string(buffer); +} + +// Helper function that iterates over & fetches data, and compares retrieved value to expected value +void fetchAndCompare(OdbcHandler& odbcHandler, vector> expectedValues) { + SQLLEN cb = SQL_NO_TOTAL; + RETCODE rcode; + + int bufferLen = 1024; + char buffer[1024]; + int totalNumRows = expectedValues[0].size(); + int totalNumCols = expectedValues.size(); + + for (short row = 0; row < totalNumRows; row++) { + rcode = SQLFetch(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + for (short col = 0; col < totalNumCols; col++) { + rcode = SQLGetData(odbcHandler.GetStatementHandle(), col+1, SQL_C_CHAR, buffer, bufferLen, &cb); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + if (expectedValues[col][row].compare(NULL_STR) == 0) { + ASSERT_EQ(cb, SQL_NULL_DATA); + break; + } + ASSERT_EQ(expectedValues[col][row], buffer); + } + } +} + +// Common code for data types tests +void DataTypesTestCommon(const string &table_name, + vector> &table_columns, + const string &inserted_values, + const vector> &expected_values) { + + OdbcHandler odbcHandler; + + const string ORDER_BY_COLS = "OrderOfInsertion"; + table_columns.push_back({ORDER_BY_COLS, "INT"}); + + DatabaseObjects dbObjects; + ASSERT_NO_FATAL_FAILURE(dbObjects.CreateTable(table_name, table_columns)); + + ASSERT_NO_FATAL_FAILURE(odbcHandler.Connect(true)); + if (!inserted_values.empty()) { + ASSERT_NO_FATAL_FAILURE( + odbcHandler.ExecQuery(InsertStatement(table_name, processInsertedValuesString(inserted_values))) + ); + } + ASSERT_NO_FATAL_FAILURE(odbcHandler.ExecQuery(SelectStatement(table_name, { "*" }, { ORDER_BY_COLS }))); + + SQLSMALLINT sNumCols; + SQLNumResultCols(odbcHandler.GetStatementHandle(), &sNumCols); + ASSERT_EQ(sNumCols, table_columns.size()); + + fetchAndCompare(odbcHandler, expected_values); +} + +// Test retrieval of type BigInt +TEST_F(Data_Types, BigInt) { + + const string TEST_TABLE = "BIGINT_dt"; + vector> TABLE_COLUMNS = { + {"a", "BIGINT"} + }; + const string INSERTED_VALUES = + "(NULL), (-9223372036854775808), (-024112329), (-10), (-0000000000000000002), (0), (0000000000000000086), (0001202), (122100), " + "(9223372036854775807)"; + + const vector> EXPECTED_VALUES = { + {NULL_STR, "-9223372036854775808", "-24112329", "-10", "-2", "0", "86", "1202", "122100", "9223372036854775807"} + }; + + DataTypesTestCommon(TEST_TABLE, TABLE_COLUMNS, INSERTED_VALUES, EXPECTED_VALUES); +} + +// Test retrieval of type Bit +TEST_F(Data_Types, Bit) { + + const string TEST_TABLE = "BIT_dt"; + vector> TABLE_COLUMNS = { + {"a", "BIT"} + }; + const string INSERTED_VALUES = "(NULL), (0), (1)"; + const vector> EXPECTED_VALUES = { + {NULL_STR, "0", "1"} + }; + + DataTypesTestCommon(TEST_TABLE, TABLE_COLUMNS, INSERTED_VALUES, EXPECTED_VALUES); +} + +// Test retrieval of type Char +TEST_F(Data_Types, Char) { + + const string TEST_TABLE = "CHAR_dt"; + vector> TABLE_COLUMNS = { + {"a", "CHAR(24)"}, + {"b", "NCHAR(24)"} + }; + const string INSERTED_VALUES = "(NULL, NULL), (' ',' '), (' John',' Doe'), ('John','Doe')"; + const vector> EXPECTED_VALUES = { + {NULL_STR, " ", " John ", "John "}, + {NULL_STR, " ", " Doe ", "Doe "} + }; + + DataTypesTestCommon(TEST_TABLE, TABLE_COLUMNS, INSERTED_VALUES, EXPECTED_VALUES); +} + +// Test retrieval of type Date +TEST_F(Data_Types, Date) { + + const string TEST_TABLE = "DATE_dt"; + vector> TABLE_COLUMNS = { + {"a", "DATE"} + }; + const string INSERTED_VALUES = "(NULL), ('0001-01-01'), ('1900-02-28'), ('2000-12-13'), ('9999-12-31')"; + const vector> EXPECTED_VALUES = { + {NULL_STR, "0001-01-01", "1900-02-28", "2000-12-13", "9999-12-31"} + }; + + DataTypesTestCommon(TEST_TABLE, TABLE_COLUMNS, INSERTED_VALUES, EXPECTED_VALUES); +} + +// Test retrieval of type DateTime +TEST_F(Data_Types, DateTime) { + + const string TEST_TABLE = "DATETIME_dt"; + vector> TABLE_COLUMNS = { + {"a", "DATETIME"} + }; + + const string INSERTED_VALUES = + "(NULL), ('1753-01-01 00:00:00.000'), ('1900-02-28 23:59:59.989'), ('1900-02-28 23:59:59.990'), ('1900-02-28 23:59:59.991'), " + "('1900-02-28 23:59:59.992'), ('1900-02-28 23:59:59.993'), ('1900-02-28 23:59:59.994'), ('1900-02-28 23:59:59.995'), " + "('1900-02-28 23:59:59.996'), ('1900-02-28 23:59:59.997'), ('1900-02-28 23:59:59.998'), ('1900-02-28 23:59:59.999'), " + "('2000-02-28 23:59:59.989'), ('2000-12-13 12:58:23.123'), ('9999-12-31 23:59:59.997')"; + const vector> EXPECTED_VALUES = { + {NULL_STR, "1753-01-01 00:00:00.000", "1900-02-28 23:59:59.990", "1900-02-28 23:59:59.990", "1900-02-28 23:59:59.990", + "1900-02-28 23:59:59.993", "1900-02-28 23:59:59.993", "1900-02-28 23:59:59.993", "1900-02-28 23:59:59.997", + "1900-02-28 23:59:59.997", "1900-02-28 23:59:59.997", "1900-02-28 23:59:59.997", "1900-03-01 00:00:00.000", + "2000-02-28 23:59:59.990", "2000-12-13 12:58:23.123", "9999-12-31 23:59:59.997"} + }; + + DataTypesTestCommon(TEST_TABLE, TABLE_COLUMNS, INSERTED_VALUES, EXPECTED_VALUES); +} +// Test retrieval of type Float +TEST_F(Data_Types, Float) { + + const string TEST_TABLE = "FLOAT_dt"; + vector> TABLE_COLUMNS = { + {"a", "FLOAT"} + }; + + const string INSERTED_VALUES = + "(NULL), (-1.79E+308), (-0122455324.5), (-004), (-000002), (0), (1.050), (01.05), (0000000000000000086), (1.79E+308)"; + const vector> EXPECTED_VALUES = { + {NULL_STR, "-1.79E+308", "-122455324.5", "-4.0", "-2.0", "0.0", "1.05", "1.05", "86.0", "1.79E+308"} + }; + + DataTypesTestCommon(TEST_TABLE, TABLE_COLUMNS, INSERTED_VALUES, EXPECTED_VALUES); +} + +// Test retrieval of type Int +TEST_F(Data_Types, Int) { + + const string TEST_TABLE = "INT_dt"; + vector> TABLE_COLUMNS = { + {"a", "INT"} + }; + + const string INSERTED_VALUES = + "(NULL), (-2147483648), (-12345), (-01645), (-10), (0), (004), (10), (22), (2147483647)"; + const vector> EXPECTED_VALUES = { + {NULL_STR, "-2147483648", "-12345", "-1645", "-10", "0", "4", "10", "22", "2147483647"} + }; + + DataTypesTestCommon(TEST_TABLE, TABLE_COLUMNS, INSERTED_VALUES, EXPECTED_VALUES); +} + +// Test retrieval of type Money +// This test differs from others in the following: +// 1. the way the INSERTED_VALUES are defined - they already contain the 'order of insertion' values +// 2. the way the INSERTED_VALUES are inserted - loop through the 'literal' inserted values since they 'hard code' the 'order of insertions' values +// The reason it was done this way is because in SQL Server you cannot mix & match certain different money type syntax in an insert. +// For example, if I had a table with 1 column of type MONEY I cannot do a single insert of the values ('$10'), (4) without getting a conversion error. +TEST_F(Data_Types, Money) { + OdbcHandler odbcHandler; + + const string TEST_TABLE = "MONEY_dt"; + const string ORDER_BY_COLS = "OrderOfInsertion"; + const vector> TABLE_COLUMNS = { + {"a", "smallmoney"}, + {"b", "money"}, + {ORDER_BY_COLS, "INT"} + }; + + const vector INSERTED_VALUES = { + "(NULL, NULL, 1)", "('-214,748.3648','-922,337,203,685,477.5808', 2)", "(-214748.3648,'-10.0', 3)", + "('-10.05','-10.0', 4)", "('$10','$10', 5)", "('10.05','10.0', 6)", "(100.5,10.05, 7)", "(14748.3647,-922337203685477.5808, 8)", + "('$214748.3647','$22337203685477.5807', 9)", "('214,748.3647','922,337,203,685,477.5807', 10)", "('$214,748.3647','$922,337,203,685,477.5807', 11)" + }; + + vector> expectedValues = { + {NULL_STR, "-214748.3648", "-214748.3648", "-10.0500", "10.0000", "10.0500", "100.5000", "14748.3647", "214748.3647", + "214748.3647", "214748.3647"}, + {NULL_STR, "-922337203685477.5808", "-10.0000", "-10.0000", "10.0000", "10.0000", "10.0500", "-922337203685477.5808", "22337203685477.5807", + "922337203685477.5807", "922337203685477.5807"} + }; + + DatabaseObjects dbObjects; + ASSERT_NO_FATAL_FAILURE(dbObjects.CreateTable(TEST_TABLE, TABLE_COLUMNS)); + + ASSERT_NO_FATAL_FAILURE(odbcHandler.Connect(true)); + + for (short i = 0; i < INSERTED_VALUES.size(); i++) { + ASSERT_NO_FATAL_FAILURE(odbcHandler.ExecQuery(InsertStatement(TEST_TABLE, INSERTED_VALUES[i]))); + + } + ASSERT_NO_FATAL_FAILURE(odbcHandler.ExecQuery(SelectStatement(TEST_TABLE, { "*" }, { ORDER_BY_COLS }))); + + SQLSMALLINT sNumResults; + SQLNumResultCols(odbcHandler.GetStatementHandle(), &sNumResults); + ASSERT_EQ(sNumResults, TABLE_COLUMNS.size()); + + fetchAndCompare(odbcHandler, expectedValues); +} + +// Test retrieval of type Real +TEST_F(Data_Types, Real) { + + const string TEST_TABLE = "REAL_dt"; + vector> TABLE_COLUMNS = { + {"a", "REAL"} + }; + + const string INSERTED_VALUES = + "(NULL), (-3.40E+38), (-0122455324.5), (-004), (-000002), (0), (1.050), (01.05), (0000000000000000086), (3.40E+38)"; + const vector> EXPECTED_VALUES = { + {NULL_STR, "-3.4E+38", "-1.2245533E+8", "-4.0", "-2.0", "0.0", "1.05", "1.05", "86.0", "3.4E+38"} + }; + + DataTypesTestCommon(TEST_TABLE, TABLE_COLUMNS, INSERTED_VALUES, EXPECTED_VALUES); +} + +// Test retrieval of type SmallDatetime +TEST_F(Data_Types, SmallDatetime) { + + const string TEST_TABLE = "SMALLDATETIME_dt"; + vector> TABLE_COLUMNS = { + {"a", "SMALLDATETIME"} + }; + + const string INSERTED_VALUES = + "(NULL), ('1900-01-01 00:00:00'), ('1900-02-28 23:45:29'), ('1900-02-28 23:59:59.999'), " + "('1900-12-13 12:58:30'), ('2000-02-28 23:45:29'), ('2000-02-28 23:45:29.998'), ('2000-02-28 23:45:29.999'), " + "('2000-02-28 23:45:30'), ('2000-02-28 23:59:59.999'), ('2000-12-13 12:58:23'), ('2007-05-08 12:35:29'), " + "('2007-05-08 12:35:30'), ('2007-05-08 12:59:59.998'), ('2079-06-06 23:59:29')"; + const vector> EXPECTED_VALUES = { + {NULL_STR, "1900-01-01 00:00:00", "1900-02-28 23:45:00", "1900-03-01 00:00:00", + "1900-12-13 12:59:00", "2000-02-28 23:45:00", "2000-02-28 23:45:00", "2000-02-28 23:46:00", + "2000-02-28 23:46:00", "2000-02-29 00:00:00", "2000-12-13 12:58:00", "2007-05-08 12:35:00", + "2007-05-08 12:36:00", "2007-05-08 13:00:00", "2079-06-06 23:59:00"} + }; + + DataTypesTestCommon(TEST_TABLE, TABLE_COLUMNS, INSERTED_VALUES, EXPECTED_VALUES); +} + +// Test retrieval of type SmallInt +TEST_F(Data_Types, SmallInt) { + + const string TEST_TABLE = "SMALLINT_dt"; + vector> TABLE_COLUMNS = { + {"a", "SMALLINT"} + }; + + const string INSERTED_VALUES = + "(NULL), (-32768), (-1234), (-029), (-10), (0), (002), (100), (876), (32767)"; + const vector> EXPECTED_VALUES = { + {NULL_STR, "-32768", "-1234", "-29", "-10", "0", "2", "100", "876", "32767"} + }; + + DataTypesTestCommon(TEST_TABLE, TABLE_COLUMNS, INSERTED_VALUES, EXPECTED_VALUES); +} + +// Test retrieval of type TableType +TEST_F(Data_Types, TableType) { + + const string TEST_TABLE = "tableType"; + vector> TABLE_COLUMNS = { + {"a", "text not null"}, + {"b", "int primary key"}, + {"c", "int"} + }; + + const vector> EXPECTED_VALUES = { + {} + }; + + DataTypesTestCommon(TEST_TABLE, TABLE_COLUMNS, "", EXPECTED_VALUES); +} + +// Test retrieval of type Text +TEST_F(Data_Types, Text) { + + const string TEST_TABLE = "TEXT_dt"; + vector> TABLE_COLUMNS = { + {"a", "text"}, + {"b", "ntext"} + }; + + string blankFileData = readFromFile("utils/blank.txt"); + string sampleFileData = readFromFile("utils/sample.txt"); + string devanagariFileData = readFromFile("utils/devanagari.txt"); + + const string INSERTED_VALUES = + "(NULL, NULL), " + "(\'" + blankFileData + "\', \'" + blankFileData + "\'), " + "(\'" + sampleFileData + "\', \'" + sampleFileData + "\'), " + "(NULL, \'" + devanagariFileData + "\')"; + + const vector> EXPECTED_VALUES = { + {NULL_STR, "", "AAAAAAAAAAAAAAAAAAAA\nBBBBBBBBBB\nCCCCC\nbadksjvbajsdcbvjads\nsejvhsdbfjhcgvasdhgcvsj\n21639812365091264", + NULL_STR}, + {NULL_STR, "", "AAAAAAAAAAAAAAAAAAAA\nBBBBBBBBBB\nCCCCC\nbadksjvbajsdcbvjads\nsejvhsdbfjhcgvasdhgcvsj\n21639812365091264", + "ऀँंःऄअआइईउऊऋऌऍऎएऐऑऒओऔकखगघङचछजझञटठडढणतथदधनऩपफबभमयरऱलळऴवशषसहऺऻ़ऽािीुूृॄॅॆेैॉॊोौ्ॎॏॐ॒॑॓॔ॕॖॗक़ख़ग़ज़ड़ढ़फ़य़ॠॡॢॣ।॥०१२३४५६७८९॰ॱॲॳॴॵॶॷॹॺॻॼॽॾॿ"} + }; + + DataTypesTestCommon(TEST_TABLE, TABLE_COLUMNS, INSERTED_VALUES, EXPECTED_VALUES); +} + +// Test retrieval of type TinyInt +TEST_F(Data_Types, TinyInt) { + + const string TEST_TABLE = "TINYINT_dt"; + vector> TABLE_COLUMNS = { + {"a", "TINYINT"} + }; + + const string INSERTED_VALUES = "(NULL), (0), (0), (0), (002), (004), (86), (100), (120), (255)"; + const vector> EXPECTED_VALUES = { + {NULL_STR, "0", "0", "0", "2", "4", "86", "100", "120", "255"} + }; + + DataTypesTestCommon(TEST_TABLE, TABLE_COLUMNS, INSERTED_VALUES, EXPECTED_VALUES); +} + +// Test retrieval of type UniqueIdentifier +TEST_F(Data_Types, UniqueIdentifier) { + + const string TEST_TABLE = "UNIQUEIDENTIFIER_dt"; + vector> TABLE_COLUMNS = { + {"a", "UNIQUEIDENTIFIER"} + }; + + const string INSERTED_VALUES = + "(NULL), ('51f178a6-53c7-472c-9be1-1c08942342d7'), ('dba2726c-2131-409f-aefa-5c8079571623'), ('851763b5-b068-42ae-88ec-764bfb0e5605'), " + "('253fb146-7e45-45ef-9d92-bbe14a8ad1b2'), ('60aeaa5c-e272-4b17-bad0-c25710fd7a60'), ('d424fdef-1404-4bac-8289-c725b540f93d'), " + "('bab96bc8-60b9-40dd-b0de-c90a80f5739e'), ('dd8cb046-461d-411e-be40-d219252ce849'), ('b84ebcc9-c927-4cfe-b08e-dc7f25b5087c'), " + "('b3400fa7-3a60-40ec-b40e-fc85a3eb262d')"; + const vector> EXPECTED_VALUES = { + {NULL_STR, "51F178A6-53C7-472C-9BE1-1C08942342D7", "DBA2726C-2131-409F-AEFA-5C8079571623", "851763B5-B068-42AE-88EC-764BFB0E5605", + "253FB146-7E45-45EF-9D92-BBE14A8AD1B2", "60AEAA5C-E272-4B17-BAD0-C25710FD7A60", "D424FDEF-1404-4BAC-8289-C725B540F93D", + "BAB96BC8-60B9-40DD-B0DE-C90A80F5739E", "DD8CB046-461D-411E-BE40-D219252CE849", "B84EBCC9-C927-4CFE-B08E-DC7F25B5087C", + "B3400FA7-3A60-40EC-B40E-FC85A3EB262D"} + }; + + DataTypesTestCommon(TEST_TABLE, TABLE_COLUMNS, INSERTED_VALUES, EXPECTED_VALUES); +} + +// Test retrieval of type Varchar +TEST_F(Data_Types, Varchar) { + + const string TEST_TABLE = "VARCHAR_dt"; + vector> TABLE_COLUMNS = { + {"a", "VARCHAR(24)"}, + {"b", "NVARCHAR(24)"} + }; + + const string INSERTED_VALUES = "(NULL, NULL), (' ',' '), (' John',' Doe'), ('John','Doe')"; + const vector> EXPECTED_VALUES = { + {NULL_STR, " ", " John", "John"}, + {NULL_STR, " ", " Doe", "Doe"} + }; + + DataTypesTestCommon(TEST_TABLE, TABLE_COLUMNS, INSERTED_VALUES, EXPECTED_VALUES); +} diff --git a/contrib/test/odbc/test_diagnostics.cpp b/contrib/test/odbc/test_diagnostics.cpp new file mode 100644 index 00000000000..6c948653775 --- /dev/null +++ b/contrib/test/odbc/test_diagnostics.cpp @@ -0,0 +1,140 @@ +#include "odbc_handler.h" +#include "database_objects.h" +#include "query_generator.h" +#include +#include + +class Diagnostics : public testing::Test { + protected: + + static void SetUpTestSuite() { + } + + static void TearDownTestSuite() { + } +}; + +TEST_F(Diagnostics, SQLGetDiagRec_Connection) { + OdbcHandler odbcHandler; + RETCODE rcode; + SQLINTEGER rec_num = 0; + SQLINTEGER native; + SQLCHAR state[7]; + SQLCHAR info[256]; + SQLSMALLINT len; + string conn_str_incorrect_creds = "DRIVER={" + odbcHandler.GetDriver() + "};SERVER=" + odbcHandler.GetServer() + "," + odbcHandler.GetPort() + ";UID=nonexistentuser;PWD=incorrectpassword;DATABASE=" + odbcHandler.GetDbname(); + + ASSERT_NO_FATAL_FAILURE(odbcHandler.AllocateEnvironmentHandle()); + ASSERT_NO_FATAL_FAILURE(odbcHandler.AllocateConnectionHandle()); + rcode = SQLDriverConnect(odbcHandler.GetConnectionHandle(), nullptr, (SQLCHAR *) conn_str_incorrect_creds.c_str(), SQL_NTS, nullptr, 0, nullptr, SQL_DRIVER_NOPROMPT); + ASSERT_EQ(rcode, SQL_ERROR); + + rcode = SQLGetDiagRec(SQL_HANDLE_DBC, odbcHandler.GetConnectionHandle(), ++rec_num, state, &native, info, sizeof(info), &len); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_DBC, rcode); + // The SQL Server and BBF SQL State errors differ, but that's okay; these tests are intended to test ODBC functionality, not error mapping + // Thus, we are not asserting error state equality. BBF should at least return some sort of state though, so we check for a non-empty string + ASSERT_TRUE(string((const char*) state).length() > 0); +} + +TEST_F(Diagnostics, SQLGetDiagRec_UnsuccessfulStatement) { + OdbcHandler odbcHandler; + RETCODE rcode; + SQLINTEGER rec_num = 0; + SQLINTEGER native; + SQLCHAR state[7]; + SQLCHAR info[256]; + SQLSMALLINT len; + string query = "SELECT ORDER BY INCORRECT SYNTAX"; + + ASSERT_NO_FATAL_FAILURE(odbcHandler.Connect(true)); + rcode = SQLExecDirect(odbcHandler.GetStatementHandle(), (SQLCHAR*) query.c_str(), SQL_NTS); + ASSERT_EQ(rcode, SQL_ERROR); + + rcode = SQLGetDiagRec(SQL_HANDLE_STMT, odbcHandler.GetStatementHandle(), ++rec_num, state, &native, info, sizeof(info), &len); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + ASSERT_STREQ((const char*) state, "42000"); + + rcode = SQLGetDiagRec(SQL_HANDLE_STMT, odbcHandler.GetStatementHandle(), ++rec_num, state, &native, info, sizeof(info), &len); + ASSERT_EQ(rcode, SQL_NO_DATA); +} + +TEST_F(Diagnostics, SQLGetDiagRec_Error) { + OdbcHandler odbcHandler; + RETCODE rcode; + SQLINTEGER native; + SQLCHAR state[7]; + SQLCHAR info[256]; + SQLSMALLINT len; + string query = "SELECT ORDER BY INCORRECT SYNTAX"; + + ASSERT_NO_FATAL_FAILURE(odbcHandler.Connect(true)); + rcode = SQLExecDirect(odbcHandler.GetStatementHandle(), (SQLCHAR*) query.c_str(), SQL_NTS); + ASSERT_EQ(rcode, SQL_ERROR); + + // Record number must be > 0 + SQLINTEGER rec_num = -1; + rcode = SQLGetDiagRec(SQL_HANDLE_STMT, odbcHandler.GetStatementHandle(), rec_num, state, &native, info, sizeof(info), &len); + ASSERT_EQ(rcode, SQL_ERROR); +} + +TEST_F(Diagnostics, SQLGetDiagField_SuccessfulStatement) { + OdbcHandler odbcHandler; + RETCODE rcode; + SQLINTEGER rec_num = 1; + SQLLEN row_count; + SQLSMALLINT len; + + const string DIAGNOSTICS_W_TABLE = "DIAGNOSTICS_TABLE_W_1"; + + DatabaseObjects dbObjects; + ASSERT_NO_FATAL_FAILURE(dbObjects.CreateTable(DIAGNOSTICS_W_TABLE, {{"id", "INT"}})); + + string query = InsertStatement(DIAGNOSTICS_W_TABLE, "(1)"); + + ASSERT_NO_FATAL_FAILURE(odbcHandler.Connect(true)); + rcode = SQLExecDirect(odbcHandler.GetStatementHandle(), (SQLCHAR*) query.c_str(), SQL_NTS); + ASSERT_TRUE(odbcHandler.IsSqlSuccess(rcode)) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + rcode = SQLGetDiagField(SQL_HANDLE_STMT, odbcHandler.GetStatementHandle(), 0, SQL_DIAG_ROW_COUNT, &row_count, 0, &len); + ASSERT_TRUE(odbcHandler.IsSqlSuccess(rcode)) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + ASSERT_EQ(row_count, 1); +} + +TEST_F(Diagnostics, SQLGetDiagField_UnsuccessfulStatement) { + OdbcHandler odbcHandler; + RETCODE rcode; + SQLINTEGER rec_num = 1; + SQLCHAR info[256]; + SQLSMALLINT len; + string query = "SELECT ORDER BY INCORRECT SYNTAX"; + + ASSERT_NO_FATAL_FAILURE(odbcHandler.Connect(true)); + rcode = SQLExecDirect(odbcHandler.GetStatementHandle(), (SQLCHAR*) query.c_str(), SQL_NTS); + ASSERT_EQ(rcode, SQL_ERROR); + + rcode = SQLGetDiagField(SQL_HANDLE_STMT, odbcHandler.GetStatementHandle(), rec_num, SQL_DIAG_SQLSTATE, info, sizeof(info), &len); + ASSERT_TRUE(odbcHandler.IsSqlSuccess(rcode)) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + ASSERT_STREQ((const char*) info, "42000"); +} + +TEST_F(Diagnostics, SQLGetDiagField_Error) { + OdbcHandler odbcHandler; + RETCODE rcode; + SQLINTEGER rec_num = 1; + SQLCHAR info[256]; + SQLSMALLINT len; + + const string DIAGNOSTICS_RO_TABLE = "DIAGNOSTICS_TABLE_RO_1"; + string query = SelectStatement(DIAGNOSTICS_RO_TABLE, { "*" }); + + DatabaseObjects dbObjects; + ASSERT_NO_FATAL_FAILURE(dbObjects.CreateTable(DIAGNOSTICS_RO_TABLE, {{"id", "INT"}})); + + ASSERT_NO_FATAL_FAILURE(odbcHandler.Connect(true)); + rcode = SQLExecDirect(odbcHandler.GetStatementHandle(), (SQLCHAR*) query.c_str(), SQL_NTS); + ASSERT_TRUE(odbcHandler.IsSqlSuccess(rcode)) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + // The handle passed should be a statement handle when the field is SQL_DIAG_DYNAMIC_FUNCTION + rcode = SQLGetDiagField(SQL_HANDLE_DBC, odbcHandler.GetConnectionHandle(), rec_num, SQL_DIAG_DYNAMIC_FUNCTION, info, sizeof(info), &len); + ASSERT_EQ(rcode, SQL_ERROR); +} diff --git a/contrib/test/odbc/test_direct_executed_statements.cpp b/contrib/test/odbc/test_direct_executed_statements.cpp new file mode 100644 index 00000000000..8b84c272245 --- /dev/null +++ b/contrib/test/odbc/test_direct_executed_statements.cpp @@ -0,0 +1,268 @@ +#include "odbc_handler.h" +#include "database_objects.h" +#include "query_generator.h" +#include +#include + +// Read Only table +static const string DIR_STMT_RO_TABLE1 = "DIR_EXEC_STMT_TABLE_RO_1"; + +class Direct_Executed_Statements : public testing::Test{ + + protected: + + static void SetUpTestSuite() { + OdbcHandler test_setup; + + test_setup.ConnectAndExecQuery(DropObjectStatement("TABLE",DIR_STMT_RO_TABLE1)); + test_setup.ExecQuery(CreateTableStatement(DIR_STMT_RO_TABLE1, {{"id", "int"}})); + test_setup.ExecQuery(InsertStatement(DIR_STMT_RO_TABLE1, "(1), (2), (3)")); + } + + static void TearDownTestSuite() { + OdbcHandler test_cleanup; + + test_cleanup.ConnectAndExecQuery(DropObjectStatement("TABLE",DIR_STMT_RO_TABLE1)); + } +}; + +// Create statement, execute query, call with SQL_CLOSE option +TEST_F(Direct_Executed_Statements, SQLFreeStmt_SQL_CLOSE_1) { + OdbcHandler odbcHandler; + RETCODE rcode; + + ASSERT_NO_FATAL_FAILURE(odbcHandler.ConnectAndExecQuery(SelectStatement(DIR_STMT_RO_TABLE1, { "*" }))); + + rcode = SQLFreeStmt(odbcHandler.GetStatementHandle(), SQL_CLOSE); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); +} + +// Create statement, execute query, bind column, call SQL_CLOSE option +TEST_F(Direct_Executed_Statements, SQLFreeStmt_SQL_CLOSE_2) { + OdbcHandler odbcHandler; + RETCODE rcode; + string sql_state; + SQLINTEGER id; + SQLLEN id_indicator; + + ASSERT_NO_FATAL_FAILURE(odbcHandler.ConnectAndExecQuery(SelectStatement(DIR_STMT_RO_TABLE1, { "*" }))); + + rcode = SQLBindCol(odbcHandler.GetStatementHandle(), 1, SQL_C_ULONG, &id, 0, &id_indicator); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + rcode = SQLFetch(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + ASSERT_EQ(id, 1); + + // Assert SQL_CLOSE to be succesful + rcode = SQLFreeStmt(odbcHandler.GetStatementHandle(), SQL_CLOSE); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + // Assert that statement is closed and cannot fetch new data after another bindcol call. + rcode = SQLBindCol(odbcHandler.GetStatementHandle(), 1, SQL_C_ULONG, &id, 0, &id_indicator); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + rcode = SQLFetch(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_ERROR); + + sql_state = odbcHandler.GetSqlState(SQL_HANDLE_STMT, odbcHandler.GetStatementHandle()); + ASSERT_EQ(sql_state, "HY010"); +} + +// Tests SQLFreeStmt with unbind option +TEST_F(Direct_Executed_Statements, SQLFreeStmt_2_SQL_UNBIND) { + OdbcHandler odbcHandler; + RETCODE rcode; + string sql_state; + SQLINTEGER id; + SQLLEN id_indicator; + + ASSERT_NO_FATAL_FAILURE(odbcHandler.ConnectAndExecQuery(SelectStatement(DIR_STMT_RO_TABLE1, { "*" }))); + + rcode = SQLBindCol(odbcHandler.GetStatementHandle(), 1, SQL_C_ULONG, &id, 0, &id_indicator); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + rcode = SQLFetch(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + ASSERT_EQ(id, 1); + + // Assert SQL_UNBIND to be succesful and SQLFetch will result in retrieving + // the first result (id == 1). + rcode = SQLFreeStmt(odbcHandler.GetStatementHandle(), SQL_UNBIND); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + rcode = SQLFetch(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + ASSERT_EQ(id, 1); + + // Assert that we can still bind a column and fetch and it will not result in an error + rcode = SQLBindCol(odbcHandler.GetStatementHandle(), 1, SQL_C_ULONG, &id, 0, &id_indicator); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + rcode = SQLFetch(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); +} + +// Tests SQLExecDirect when refering to a non-existant table +TEST_F(Direct_Executed_Statements,SQLExecDirect_InvalidTable ) { + OdbcHandler odbcHandler; + RETCODE rcode; + string sql_state; + string query = "SELECT * FROM NonExistantTable"; + + ASSERT_NO_FATAL_FAILURE(odbcHandler.Connect(true)); + + rcode = SQLExecDirect(odbcHandler.GetStatementHandle(), + (SQLCHAR*) query.c_str(), + SQL_NTS); + + ASSERT_EQ(rcode, SQL_ERROR); + sql_state = odbcHandler.GetSqlState(SQL_HANDLE_STMT, odbcHandler.GetStatementHandle()); + ASSERT_EQ(sql_state, "42000"); +} + +// Tests SQLExecDirect when creating an already existing table +TEST_F(Direct_Executed_Statements,SQLExecDirect_AlreadyExistingTable) { + OdbcHandler odbcHandler; + RETCODE rcode; + string sql_state; + string query = "CREATE TABLE " + DIR_STMT_RO_TABLE1 + "(id int)"; + ASSERT_NO_FATAL_FAILURE(odbcHandler.Connect(true)); + + rcode = SQLExecDirect(odbcHandler.GetStatementHandle(), + (SQLCHAR*) query.c_str(), + SQL_NTS); + ASSERT_EQ(rcode, SQL_ERROR); + sql_state = odbcHandler.GetSqlState(SQL_HANDLE_STMT, odbcHandler.GetStatementHandle()); + ASSERT_EQ(sql_state, "42S01"); +} + +// Tests SQLExecDirect when using a non-valid sql statement +TEST_F(Direct_Executed_Statements, SQLExecDirect_NotValidSqlStatement) { + OdbcHandler odbcHandler; + RETCODE rcode; + string sql_state; + string query = "ABC"; + + ASSERT_NO_FATAL_FAILURE(odbcHandler.Connect(true)); + + rcode = SQLExecDirect(odbcHandler.GetStatementHandle(), + (SQLCHAR*) query.c_str(), + SQL_NTS); + ASSERT_EQ(rcode, SQL_ERROR); + + sql_state = odbcHandler.GetSqlState(SQL_HANDLE_STMT, odbcHandler.GetStatementHandle()); + ASSERT_EQ(sql_state, "42000"); +} + +// Tests SQLExecDirect when dividing by zero +TEST_F(Direct_Executed_Statements, SQLExecDirect_DivisionByZero) { + + OdbcHandler odbcHandler; + RETCODE rcode; + string sql_state; + string query = "SELECT (10/0)"; + + ASSERT_NO_FATAL_FAILURE(odbcHandler.Connect(true)); + + rcode = SQLExecDirect(odbcHandler.GetStatementHandle(), + (SQLCHAR*) query.c_str(), + SQL_NTS); + ASSERT_EQ(rcode, SQL_ERROR); + + sql_state = odbcHandler.GetSqlState(SQL_HANDLE_STMT, odbcHandler.GetStatementHandle()); + ASSERT_EQ(sql_state, "22012"); +} + +// Tests SQLRowCount when using an update statement +TEST_F(Direct_Executed_Statements, SQLRowCount_UPDATE) { + OdbcHandler odbcHandler; + SQLLEN row_count; + + const string TEST_TABLE = "DIR_EXEC_STMT_TABLE_UPDATE"; + + DatabaseObjects dbObjects; + ASSERT_NO_FATAL_FAILURE(dbObjects.CreateTable(TEST_TABLE, {{"id", "INT"}})); + ASSERT_NO_FATAL_FAILURE(dbObjects.Insert(TEST_TABLE,"(0), (0), (1)")); + + string query = "UPDATE " + TEST_TABLE + " SET id = 100 where id=0"; + ASSERT_NO_FATAL_FAILURE(odbcHandler.Connect(true)); + ASSERT_NO_FATAL_FAILURE(odbcHandler.ExecQuery(query)); + + SQLRowCount(odbcHandler.GetStatementHandle(), &row_count); + ASSERT_EQ(row_count, 2); +} + +// Tests SQLRowCount when using an insert statement +TEST_F(Direct_Executed_Statements, SQLRowCount_INSERT) { + OdbcHandler odbcHandler; + SQLLEN row_count; + + const string TEST_TABLE = "DIR_EXEC_STMT_TABLE_INSERT"; + + DatabaseObjects dbObjects; + ASSERT_NO_FATAL_FAILURE(dbObjects.CreateTable(TEST_TABLE, {{"id", "INT"}})); + + ASSERT_NO_FATAL_FAILURE(odbcHandler.Connect(true)); + ASSERT_NO_FATAL_FAILURE(odbcHandler.ExecQuery(InsertStatement(TEST_TABLE, "(100)"))); + + SQLRowCount(odbcHandler.GetStatementHandle(), &row_count); + ASSERT_EQ(row_count, 1); +} + +// Tests SQLRowCount when using a Delete statement +TEST_F(Direct_Executed_Statements, SQLRowCount_DELETE) { + OdbcHandler odbcHandler; + SQLLEN row_count; + + const string TEST_TABLE = "DIR_EXEC_STMT_TABLE_DELETE"; + DatabaseObjects dbObjects; + ASSERT_NO_FATAL_FAILURE(dbObjects.CreateTable(TEST_TABLE, {{"id", "INT"}})); + ASSERT_NO_FATAL_FAILURE(dbObjects.Insert(TEST_TABLE,"(0), (0), (1)")); + + string query = "DELETE FROM " + TEST_TABLE + " WHERE id = 1"; + ASSERT_NO_FATAL_FAILURE(odbcHandler.Connect(true)); + ASSERT_NO_FATAL_FAILURE(odbcHandler.ExecQuery(query)); + + SQLRowCount(odbcHandler.GetStatementHandle(), &row_count); + ASSERT_EQ(row_count, 1); +} + +// Tests SQLRowCount when using a select statement +TEST_F(Direct_Executed_Statements, SQLRowCount_SELECT) { + OdbcHandler odbcHandler; + SQLLEN row_count; + + const string TEST_TABLE = "DIR_EXEC_STMT_TABLE_SELECT"; + DatabaseObjects dbObjects; + ASSERT_NO_FATAL_FAILURE(dbObjects.CreateTable(TEST_TABLE, {{"id", "INT"}})); + ASSERT_NO_FATAL_FAILURE(dbObjects.Insert(TEST_TABLE,"(0), (0), (1)")); + + ASSERT_NO_FATAL_FAILURE(odbcHandler.Connect(true)); + ASSERT_NO_FATAL_FAILURE(odbcHandler.ExecQuery(SelectStatement(TEST_TABLE, { "*" }))); + + SQLRowCount(odbcHandler.GetStatementHandle(), &row_count); + ASSERT_EQ(row_count, -1); +} + +// Tests SQLRowCount when using a select statement and retrieving selected rows +// SQLRowCount reports number of rows when all rows were 'consumed' +// DISABLED: Investigate the expected difference. +TEST_F(Direct_Executed_Statements, DISABLED_SQLRowCount_SELECT_CONSUME_ROWS) { + OdbcHandler odbcHandler; + SQLLEN row_count; + RETCODE rcode; + + const string TEST_TABLE = "DIR_EXEC_STMT_TABLE_SELECT_CONSUME_ROWS"; + DatabaseObjects dbObjects; + ASSERT_NO_FATAL_FAILURE(dbObjects.CreateTable(TEST_TABLE, {{"id", "INT"}})); + ASSERT_NO_FATAL_FAILURE(dbObjects.Insert(TEST_TABLE,"(0), (0), (1)")); + + ASSERT_NO_FATAL_FAILURE(odbcHandler.Connect(true)); + ASSERT_NO_FATAL_FAILURE(odbcHandler.ExecQuery(SelectStatement(TEST_TABLE, { "*" }))); + while ((rcode = SQLFetch(odbcHandler.GetStatementHandle())) == SQL_SUCCESS) { + } + + EXPECT_EQ(rcode, SQL_NO_DATA) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + SQLRowCount(odbcHandler.GetStatementHandle(), &row_count); + ASSERT_EQ(row_count, 3); +} diff --git a/contrib/test/odbc/test_metadata.cpp b/contrib/test/odbc/test_metadata.cpp new file mode 100644 index 00000000000..826d5597a33 --- /dev/null +++ b/contrib/test/odbc/test_metadata.cpp @@ -0,0 +1,949 @@ +#include "odbc_handler.h" +#include "database_objects.h" +#include "query_generator.h" + +#include +#include + +#include +#include +#include + +using std::vector; +using std::map; +using std::pair; +using std::tuple; + +class Metadata: public testing::Test { + + protected: + static void SetUpTestSuite() { + } + + static void TearDownTestSuite() { + } +}; + +void GetCurrentUser(char* current_user, const int CHARSIZE) { + + OdbcHandler odbcHandler; + RETCODE rcode; + + odbcHandler.ConnectAndExecQuery("SELECT CURRENT_USER"); + rcode = SQLFetch(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + rcode = SQLGetData(odbcHandler.GetStatementHandle(), 1, SQL_C_CHAR, current_user, CHARSIZE, 0); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); +} + +// Helper function. It fetches data from a column indicated and checks if the retrieved value matches a key in the given map. +// If yes, the corresponding map value is set to true. +void FetchAndMatchValues(OdbcHandler& odbcHandler, map &values, int column) { + + RETCODE rcode; + SQLLEN bufferLen = 2048; // Is this sufficient length in general? Perhaps the bufferLen could be passed as function parameter + char buffer[bufferLen]; + SQLLEN indicator = SQL_NO_TOTAL; //it seems that the indicator is required by the SQL server driver to be passed to SQLGetData in some cases, even though not used here + + while((rcode = SQLFetch(odbcHandler.GetStatementHandle())) == SQL_SUCCESS) { + rcode = SQLGetData(odbcHandler.GetStatementHandle(), column, SQL_C_CHAR, buffer, bufferLen, &indicator); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + auto value = values.find(string(buffer)); + if (value != values.end()) { + value->second = true; + } + } + + ASSERT_EQ(rcode, SQL_NO_DATA); +} + +// Common code for SQLPrimaryKeys tests +void SQLPrimaryKeysTestCommon(const string &pktable_name, + const vector> &table_columns, + const string &constraint_name, + const vector &pk_columns) { + + OdbcHandler odbcHandler; + RETCODE rcode; + + const int CHARSIZE = 255; + char table_name[CHARSIZE]; + char column_name[CHARSIZE]; + int key_sq{}; + char pk_name[CHARSIZE]; + + vector> bind_columns = { + {3, SQL_C_CHAR, table_name, CHARSIZE}, + {4, SQL_C_CHAR, column_name, CHARSIZE}, + {5, SQL_C_ULONG, &key_sq, CHARSIZE}, + {6, SQL_C_CHAR, pk_name, CHARSIZE} + }; + + DatabaseObjects dbObjects; + ASSERT_NO_FATAL_FAILURE(dbObjects.CreateTable(pktable_name, table_columns, PrimaryKeyConstraintSpec(constraint_name, pk_columns))); + ASSERT_NO_FATAL_FAILURE(odbcHandler.Connect(true)); + + ASSERT_NO_FATAL_FAILURE(odbcHandler.BindColumns(bind_columns)); + + rcode = SQLPrimaryKeys(odbcHandler.GetStatementHandle(), NULL, 0, NULL, 0, (SQLCHAR*) pktable_name.c_str(), SQL_NTS); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + int curr_sq {0}; + for (auto columnName : pk_columns) { + ++curr_sq; + rcode = SQLFetch(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + ASSERT_EQ(string(table_name), pktable_name); + ASSERT_EQ(string(column_name), columnName); + ASSERT_EQ(key_sq, curr_sq); + ASSERT_EQ(pk_name, constraint_name); + } + + rcode = SQLFetch(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_NO_DATA); +} + +// Common code for SQLForeignKeys tests +// The refer_pk_table parameter indicates whether the call to SQLForeignKeys should specify +// primary key table (the referenced table) or the foreign key table (the referencing table). +void SQLForeignKeysTestCommon(bool refer_pk_table) { + + OdbcHandler odbcHandler; + RETCODE rcode; + const int CHARSIZE = 255; + char pk_table[CHARSIZE]; + char fk_table[CHARSIZE]; + char pk_col[CHARSIZE]; + char fk_col[CHARSIZE]; + char fk_name[CHARSIZE]; + char pk_name[CHARSIZE]; + SQLSMALLINT update_rule; + SQLSMALLINT delete_rule; + + const string FK_TABLE_PRIMARY = "primary_key_table"; + const string FK_TABLE_FOREIGN = "foreign_key_table"; + const string T1_COL1 = "id"; + const string T1_CONSTRAINT_NAME = "SQLFK_PK_CONSTRAINT1"; + const string T2_COL2 = "id_f"; + const string T2_CONSTRAINT_NAME = "SQLFK_FK_CONSTRAINT1"; + + // columns for the 'primary key' test table + vector> pktColumns = { + {T1_COL1, "INT"} + }; + // primary key column names + vector pkColumns {{T1_COL1}}; + + // columns for the 'foreign key' test table + vector> fktColumns = { + {T2_COL2, "INT"} + }; + // foreign key column names + vector fkColumns {{T2_COL2}}; + + vector> bind_columns = { + {3, SQL_C_CHAR, pk_table, CHARSIZE}, + {4, SQL_C_CHAR, pk_col, CHARSIZE}, + {7, SQL_C_CHAR, fk_table, CHARSIZE}, + {8, SQL_C_CHAR, fk_col, CHARSIZE}, + {10, SQL_C_SHORT, &update_rule, 0}, + {11, SQL_C_SHORT, &delete_rule, 0}, + {12, SQL_C_CHAR, fk_name, CHARSIZE}, + {13, SQL_C_CHAR, pk_name, CHARSIZE} + }; + + DatabaseObjects dbObjects; + ASSERT_NO_FATAL_FAILURE(dbObjects.DropObject("TABLE",FK_TABLE_FOREIGN)); // this is in case things were not cleaned up properly previously, e.g. connection lost, etc. + ASSERT_NO_FATAL_FAILURE(dbObjects.CreateTable(FK_TABLE_PRIMARY, pktColumns, PrimaryKeyConstraintSpec(T1_CONSTRAINT_NAME, pkColumns))); + ASSERT_NO_FATAL_FAILURE(dbObjects.CreateTable(FK_TABLE_FOREIGN, fktColumns, ForeignKeyConstraintSpec(T2_CONSTRAINT_NAME, fkColumns,FK_TABLE_PRIMARY, pkColumns))); + + ASSERT_NO_FATAL_FAILURE(odbcHandler.Connect(true)); + + ASSERT_NO_FATAL_FAILURE(odbcHandler.BindColumns(bind_columns)); + + if (refer_pk_table) { + rcode = SQLForeignKeys(odbcHandler.GetStatementHandle(), + NULL, 0, + NULL, 0, + (SQLCHAR*) FK_TABLE_PRIMARY.c_str(), SQL_NTS, + NULL, 0, + NULL, 0, + NULL, 0); + } else { + rcode = SQLForeignKeys(odbcHandler.GetStatementHandle(), + NULL, 0, + NULL, 0, + NULL, 0, + NULL, 0, + NULL, 0, + (SQLCHAR*) FK_TABLE_FOREIGN.c_str(), SQL_NTS + ); + } + + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + rcode = SQLFetch(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode,SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + EXPECT_EQ(string(pk_table), FK_TABLE_PRIMARY); + EXPECT_EQ(string(pk_col), T1_COL1); + EXPECT_EQ(string(pk_name), T1_CONSTRAINT_NAME); + EXPECT_EQ(string(fk_table), FK_TABLE_FOREIGN); + EXPECT_EQ(string(fk_col), T2_COL2); + EXPECT_EQ(string(fk_name), T2_CONSTRAINT_NAME); + EXPECT_EQ(update_rule, SQL_RESTRICT); + EXPECT_EQ(delete_rule, SQL_RESTRICT); +} + +// Tests SQLPrimaryKeys for success +// DISABLED: PLEASE SEE BABELFISH-112 +TEST_F(Metadata, DISABLED_SQLPrimaryKeys_SingleKey) { + + const string PK_COLUMN_NAME = "id"; + + // columns for the test table + vector> columns = { + {PK_COLUMN_NAME, "INT"}, + {"name", "VARCHAR(256)"} + }; + + // primary key columns + vector pkColumns {{PK_COLUMN_NAME}}; + SQLPrimaryKeysTestCommon("pk_table_1", columns, "single_col_pk", pkColumns); +} + +// Tests SQLPrimaryKeys for Composite keys +// DISABLED: PLEASE SEE BABELFISH-112 +TEST_F(Metadata, DISABLED_SQLPrimaryKeys_CompositeKeys) { + + // columns for the test table + vector> columns = { + {"id", "INT"}, + {"name", "VARCHAR(256)"} + }; + + // primary key columns + vector pkColumns; + for (auto column : columns) { + pkColumns.push_back(column.first); + } + + SQLPrimaryKeysTestCommon("composite_pk_table", columns, "composite_pk", pkColumns); +} + +// Retrieve foreign keys in other tables that reference primary key of the src table +// DISABLED: PLEASE SEE BABELFISH-122 +TEST_F(Metadata, DISABLED_SQLForeignKeys_ReferSourceTable) { + + SQLForeignKeysTestCommon(true); //Use Primary Table in SQLForeignKeys call +} + +// Retrieve the foreign keys in the src table that Refer to the primary keys of other tables +// DISABLED PLEASE SEE BABELFISH-122 +TEST_F(Metadata, DISABLED_SQLForeignKeys_ReferFromOtherTables) { + + SQLForeignKeysTestCommon(false); //Use Foreign Table in SQLForeignKeys call +} + +// Tests if SQLTablePrivileges works properly +// DISABLED PLEASE SEE BABELFISH-123 +TEST_F(Metadata, DISABLED_SQLTablePrivileges) { + + const int CHARSIZE = 255; + + OdbcHandler odbcHandler; + RETCODE rcode; + + const string PRIV_TABLE1 = "table_priv"; + char table_name[CHARSIZE]; + char grantor[CHARSIZE]; + char grantee[CHARSIZE]; + char privilege[CHARSIZE]; + char is_grantable[CHARSIZE]; + + char current_user[CHARSIZE]; + ASSERT_NO_FATAL_FAILURE(GetCurrentUser(current_user, CHARSIZE)); + + map permissions = { {"UPDATE",0}, {"DELETE",0}, {"INSERT",0}, {"SELECT",0}, {"REFERENCES", 0} }; + + // columns for the test table + vector> columns = { + {"id", "INT"} + }; + + vector> bind_columns = { + {3, SQL_C_CHAR, table_name, CHARSIZE}, + {4, SQL_C_CHAR, grantor, CHARSIZE}, + {5, SQL_C_CHAR, grantee, CHARSIZE}, + {6, SQL_C_CHAR, privilege, CHARSIZE}, + {7, SQL_C_CHAR, is_grantable, CHARSIZE} + }; + + DatabaseObjects dbObjects; + ASSERT_NO_FATAL_FAILURE(dbObjects.CreateTable(PRIV_TABLE1, columns)); + + ASSERT_NO_FATAL_FAILURE(odbcHandler.Connect(true)); + + ASSERT_NO_FATAL_FAILURE(odbcHandler.BindColumns(bind_columns)); + + rcode = SQLTablePrivileges(odbcHandler.GetStatementHandle(), NULL, 0, NULL, 0, (SQLCHAR*)PRIV_TABLE1.c_str(), SQL_NTS); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + while (SQLFetch(odbcHandler.GetStatementHandle()) == SQL_SUCCESS) { + + EXPECT_EQ(string(table_name), PRIV_TABLE1); + EXPECT_EQ(string(grantor), string(current_user)); + EXPECT_EQ(string(grantee), string(current_user)); + EXPECT_EQ(string(is_grantable), "YES"); + + permissions[string(privilege)]++; + } + + EXPECT_EQ(permissions["UPDATE"], 1); + EXPECT_EQ(permissions["DELETE"], 1); + EXPECT_EQ(permissions["INSERT"], 1); + EXPECT_EQ(permissions["REFERENCES"], 1); + EXPECT_EQ(permissions["SELECT"], 1); +} + +// Tests if SQLTableColumnPrivileges works properly +// DISABLED PLEASE SEE BABELFISH-124 +TEST_F(Metadata, DISABLED_SQLTableColumnPrivileges) { + + const int CHARSIZE = 255; + const string PRIV_COL_TABLE1 = "table_col_priv"; + const string COL_1 = "id1"; + const string COL_2 = "id2"; + + OdbcHandler odbcHandler; + RETCODE rcode; + int col1_count = 0; + int col2_count = 0; + char table_name[CHARSIZE]; + char grantor[CHARSIZE]; + char grantee[CHARSIZE]; + char privilege[CHARSIZE]; + char column_name[CHARSIZE]; + char is_grantable[CHARSIZE]; + + char current_user[CHARSIZE]; + ASSERT_NO_FATAL_FAILURE(GetCurrentUser(current_user, CHARSIZE)); + + map permissions = { {"UPDATE",0}, {"REFERENCES",0}, {"INSERT",0}, {"SELECT",0} }; + + // columns for the test table + vector> columns = { + {COL_1, "INT"}, + {COL_2, "INT"} + }; + + vector> bind_columns = { + {3, SQL_C_CHAR, table_name, CHARSIZE}, + {4, SQL_C_CHAR, column_name, CHARSIZE}, + {5, SQL_C_CHAR, grantor, CHARSIZE}, + {6, SQL_C_CHAR, grantee, CHARSIZE}, + {7, SQL_C_CHAR, privilege, CHARSIZE}, + {8, SQL_C_CHAR, is_grantable, CHARSIZE} + }; + + DatabaseObjects dbObjects; + ASSERT_NO_FATAL_FAILURE(dbObjects.CreateTable(PRIV_COL_TABLE1, columns)); + + ASSERT_NO_FATAL_FAILURE(odbcHandler.Connect(true)); + + ASSERT_NO_FATAL_FAILURE(odbcHandler.BindColumns(bind_columns)); + + rcode = SQLColumnPrivileges(odbcHandler.GetStatementHandle(), NULL, 0, NULL, 0, (SQLCHAR*)PRIV_COL_TABLE1.c_str(), SQL_NTS, NULL, 0); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + while (SQLFetch(odbcHandler.GetStatementHandle()) == SQL_SUCCESS) { + + EXPECT_TRUE( string(column_name) == COL_1 || string(column_name) == COL_2); + if (string(column_name) == COL_1) { + col1_count++; + } else if (string(column_name) == COL_2) { + col2_count++; + } + EXPECT_EQ(string(table_name), PRIV_COL_TABLE1); + EXPECT_EQ(string(grantor), string(current_user)); + EXPECT_EQ(string(grantee), string(current_user)); + EXPECT_EQ(string(is_grantable), "YES"); + + permissions[string(privilege)]++; + } + EXPECT_EQ(permissions["UPDATE"], 2); + EXPECT_EQ(permissions["INSERT"], 2); + EXPECT_EQ(permissions["REFERENCES"], 2); + EXPECT_EQ(permissions["SELECT"], 2); + EXPECT_EQ(col1_count, 4); + EXPECT_EQ(col2_count, 4); +} + +// Tests SQLColumns for success +// DISABLED: PLEASE SEE BABELFISH-118 +TEST_F(Metadata, DISABLED_SQLColumns) { + + OdbcHandler odbcHandler; + RETCODE rcode; + const string COL_TABLE1 = "col_table_1"; + const string CONSTRAINT_NAME = "PK_constraint"; + const string PK_INT_COLUMN_NAME = "IntCol"; + const string CHAR_COLUMN_NAME = "CharCol"; + const string BIT_COLUMN_NAME = "BitCol"; + const string MONEY_COLUMN_NAME = "MoneyCol"; + const string VARCHAR_NOTNULL_COLUMN_NAME = "VarcharCol"; + const string DATETIME_COLUMN_NAME = "DatetimeCol"; + + const int CHARSIZE = 255; + char table_name[CHARSIZE]; + char column_name[CHARSIZE]; + char type_name[CHARSIZE]; + SQLSMALLINT sql_data_type; + SQLSMALLINT ordinal_position; + char is_nullable[CHARSIZE]; + + + // columns for the test table + vector> columns = { + {PK_INT_COLUMN_NAME, "INT"}, + {CHAR_COLUMN_NAME, "CHAR(24)"}, + {BIT_COLUMN_NAME, "BIT"}, + {MONEY_COLUMN_NAME, "MONEY"}, + {DATETIME_COLUMN_NAME, "DATETIME"}, + {VARCHAR_NOTNULL_COLUMN_NAME, "VARCHAR(24) NOT NULL"} + }; + + vector> bind_columns = { + {3, SQL_C_CHAR, table_name, CHARSIZE}, + {4, SQL_C_CHAR, column_name, CHARSIZE}, + {6, SQL_C_CHAR, type_name, CHARSIZE}, + {14, SQL_C_SHORT, &sql_data_type, 0}, + {17, SQL_C_SHORT, &ordinal_position, 0}, + {18, SQL_C_CHAR, is_nullable, CHARSIZE} + }; + + DatabaseObjects dbObjects; + ASSERT_NO_FATAL_FAILURE(dbObjects.CreateTable(COL_TABLE1, columns, PrimaryKeyConstraintSpec(CONSTRAINT_NAME, {{PK_INT_COLUMN_NAME}}))); + ASSERT_NO_FATAL_FAILURE(odbcHandler.Connect(true)); + + ASSERT_NO_FATAL_FAILURE(odbcHandler.BindColumns(bind_columns)); + + rcode = SQLColumns(odbcHandler.GetStatementHandle(), NULL, 0, NULL, 0, (SQLCHAR*) COL_TABLE1.c_str(), SQL_NTS, NULL, 0); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + int position {0}; + vector> expected_values = { + {PK_INT_COLUMN_NAME, "int", SQL_INTEGER, "NO"}, + {CHAR_COLUMN_NAME, "char", SQL_CHAR, "YES"}, + {BIT_COLUMN_NAME, "bit", SQL_BIT, "YES"}, + {MONEY_COLUMN_NAME, "money", SQL_DECIMAL, "YES"}, + {DATETIME_COLUMN_NAME, "datetime", SQL_DATETIME, "YES"}, + {VARCHAR_NOTNULL_COLUMN_NAME, "varchar",SQL_VARCHAR, "NO"} + }; + + for (auto col_values : expected_values) { + rcode = SQLFetch(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + ++position; + auto& [col_name, col_type, sql_type, nullable] = col_values; + + EXPECT_EQ(string(table_name), COL_TABLE1); + EXPECT_EQ(string(column_name), col_name); + EXPECT_EQ(string(type_name), col_type); + EXPECT_EQ(sql_data_type, sql_type); + EXPECT_EQ(SQLINTEGER(ordinal_position), position); + EXPECT_EQ(string(is_nullable), nullable); + } + + rcode = SQLFetch(odbcHandler.GetStatementHandle()); + EXPECT_EQ(rcode, SQL_NO_DATA); +} + +// Tests SQLProcedures for success +// DISABLED: PLEASE SEE BABELFISH-119 +TEST_F(Metadata, DISABLED_SQLProcedures) { + + OdbcHandler odbcHandler; + RETCODE rcode; + + const string SCHEMA_NAME = "schema_1"; + const string PROC_TABLE = "proc_table_1"; + const string PROCEDURE_NAME = "proc_1"; + const string FUNCTION_NAME = "func_1"; + + const int CHARSIZE = 255; + char schema_name[CHARSIZE]; + char procedure_name[CHARSIZE]; + SQLSMALLINT procedure_type; + + // Test table columns. + const vector> columns = { + {"id", "INT"} + }; + + vector> bind_columns = { + {2, SQL_C_CHAR, schema_name, CHARSIZE}, + {3, SQL_C_CHAR, procedure_name, CHARSIZE}, + {8, SQL_C_SHORT, &procedure_type, 0} + }; + + DatabaseObjects dbObjects; + ASSERT_NO_FATAL_FAILURE(dbObjects.CreateTable(PROC_TABLE, columns)); + ASSERT_NO_FATAL_FAILURE(dbObjects.CreateSchema(SCHEMA_NAME)); + ASSERT_NO_FATAL_FAILURE(dbObjects.CreateProcedure(SCHEMA_NAME + "." + PROCEDURE_NAME, + SelectStatement(PROC_TABLE, {"*"}))); + ASSERT_NO_FATAL_FAILURE(dbObjects.CreateFunction(SCHEMA_NAME + "." + FUNCTION_NAME, + "() RETURNS BIT AS BEGIN DECLARE @var BIT SET @var = 1 RETURN @var END")); + ASSERT_NO_FATAL_FAILURE(odbcHandler.Connect(true)); + + ASSERT_NO_FATAL_FAILURE(odbcHandler.BindColumns(bind_columns)); + + rcode = SQLProcedures(odbcHandler.GetStatementHandle(), NULL, 0, (SQLCHAR*) SCHEMA_NAME.c_str(), SQL_NTS, NULL, 0); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + // Expected values contain names and types of procedures/functions. + map expected_values = { + {PROCEDURE_NAME,SQL_PT_FUNCTION }, // Curiously, SQL Server returns SQL_PT_FUNCTION for procedures rather than SQL_PT_PROCEDURE + {FUNCTION_NAME,SQL_PT_FUNCTION } + }; + + while((rcode = SQLFetch(odbcHandler.GetStatementHandle())) == SQL_SUCCESS ) { + EXPECT_EQ(string(schema_name), SCHEMA_NAME); + // SQL Server appends ';0' or ';1' to names. It appears that ';0' is used for functions and ';1' for procedures. + // Trimming these here. For the purpose of this test, they are irrelevant and make it harder to compare expected values. + // If BBF does not append these characters this needs to be handled here. It will be determined when the test is not disabled. + procedure_name[strlen(procedure_name)-2] = 0; + auto value = expected_values.find(procedure_name); + if (value != expected_values.end()) { + EXPECT_EQ(procedure_type, value->second); + expected_values.erase(value->first); + } + else { + // Expected values not updated properly? Or SCHEMA_NAME modified outside of this test? + EXPECT_TRUE(false) << procedure_name << " was NOT expected but found"; + } + } + + EXPECT_EQ(rcode, SQL_NO_DATA) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + // Check and assert expected values that were not found. + // All are expected to be found. Thus, in successful case the for loop would not do anything as the map should be empty. + for (auto value : expected_values) { + EXPECT_TRUE(false) << value.first << " was expected but not found"; + } +} + +// Tests SQLProcedureColumns for success +// DISABLED: PLEASE SEE BABELFISH-120 +TEST_F(Metadata, DISABLED_SQLProcedureColumns) { + + OdbcHandler odbcHandler; + RETCODE rcode; + + const string SCHEMA_NAME = "schema_2"; + const string PROC_TABLE = "proc_table_2"; + const string PROCEDURE_NAME = "proc_1"; + const string FUNCTION_NAME = "func_1"; + + const int CHARSIZE = 255; + char schema_name[CHARSIZE]; + char procedure_name[CHARSIZE]; + char column_name[CHARSIZE]; + char type_name[CHARSIZE]; + SQLSMALLINT sql_data_type; + SQLSMALLINT ordinal_position; + char is_nullable[CHARSIZE]; + + // Test table columns. + const vector> columns = { + {"id", "VARCHAR(80)"} + }; + + vector> bind_columns = { + {2, SQL_C_CHAR, schema_name, CHARSIZE}, + {3, SQL_C_CHAR, procedure_name, CHARSIZE}, + {4, SQL_C_CHAR, column_name, CHARSIZE}, + {7, SQL_C_CHAR, type_name, CHARSIZE}, + {15, SQL_C_SHORT, &sql_data_type, 0}, + {18, SQL_C_SHORT, &ordinal_position, 0}, + {19, SQL_C_CHAR, is_nullable, CHARSIZE} + }; + + DatabaseObjects dbObjects; + ASSERT_NO_FATAL_FAILURE(dbObjects.CreateTable(PROC_TABLE, columns)); + ASSERT_NO_FATAL_FAILURE(dbObjects.CreateSchema(SCHEMA_NAME)); + ASSERT_NO_FATAL_FAILURE(dbObjects.CreateProcedure(SCHEMA_NAME + "." + PROCEDURE_NAME, + SelectStatement(PROC_TABLE, {"*"} ,{}, "id = @id"), + " @id VARCHAR(80) ")); + ASSERT_NO_FATAL_FAILURE(dbObjects.CreateFunction(SCHEMA_NAME + "." + FUNCTION_NAME, + "(@par INT, @par2 VARCHAR(80)) RETURNS BIT AS BEGIN DECLARE @var BIT SET @var = @par RETURN @var END" + )); + ASSERT_NO_FATAL_FAILURE(odbcHandler.Connect(true)); + + ASSERT_NO_FATAL_FAILURE(odbcHandler.BindColumns(bind_columns)); + + rcode = SQLProcedureColumns(odbcHandler.GetStatementHandle(), NULL, 0, (SQLCHAR*) SCHEMA_NAME.c_str(), SQL_NTS, NULL, 0, NULL, 0); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + // The expected values is a map where a key is a procedure_name,column_name pair + // The map values are tuples holding the corresponding values for a column: data type, sqlType, position, is nullable + map< pair, tuple> expected_values = { + { {FUNCTION_NAME, "@RETURN_VALUE"}, {"bit", SQL_BIT, 0, "YES"}}, + { {FUNCTION_NAME, "@par"}, {"int", SQL_INTEGER, 1, "YES"}}, + { {FUNCTION_NAME, "@par2"}, {"varchar", SQL_VARCHAR, 2, "YES"}}, + + { {PROCEDURE_NAME, "@RETURN_VALUE"}, {"int", SQL_INTEGER, 0, "NO"}}, + { {PROCEDURE_NAME, "@id"}, {"varchar", SQL_VARCHAR, 1, "YES"}} + }; + + while((rcode = SQLFetch(odbcHandler.GetStatementHandle())) == SQL_SUCCESS ) { + EXPECT_EQ(string(schema_name), SCHEMA_NAME); + // SQL Server appends ';0' or ';1' to names. It appears that ';0' is used for functions and ';1' for procedures. + // Trimming these here. For the purpose of this test, they are irrelevant and make it harder to compare expected values. + // If BBF does not append these characters this needs to be handled here. It will be determined when the test is not disabled. + procedure_name[strlen(procedure_name)-2] = 0; + + auto colData = expected_values.find({procedure_name, column_name}); + if (colData != expected_values.end()) { + auto& [type, sqlType, position, nullable] = colData->second; + EXPECT_EQ(string(type_name), type); + EXPECT_EQ(sql_data_type, sqlType); + EXPECT_EQ(SQLINTEGER(ordinal_position), position); + EXPECT_EQ(string(is_nullable), nullable); + + // remove from the found ones from the map + expected_values.erase({procedure_name, column_name}); + } + else { + // Expected values not updated properly? Or SCHEMA_NAME modified outside of this test? + EXPECT_TRUE(false) << "Procedure: " << procedure_name << " Column: " << column_name << " data was NOT expected but found"; + } + } + + EXPECT_EQ(rcode, SQL_NO_DATA) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + // Check and assert expected values that were not found. + // All are expected to be found. Thus, in successful case the for loop would not do anything as the map should be empty. + for (auto value : expected_values) { + auto& [procedure, column] = value.first; + EXPECT_TRUE(false) << "Procedure: " << procedure << " Column: " << column << " data was expected but not found"; + + } +} + +// Tests SQLProcedureColumns for success with primary keys +// DISABLED: PLEASE SEE BABELFISH-121 +TEST_F(Metadata, DISABLED_SQLSpecialColumns_PrimaryKeys) { + + OdbcHandler odbcHandler; + RETCODE rcode; + const string COL_TABLE = "col_table_primary_keys"; + const string CONSTRAINT_NAME = "PK_constraint_1"; + const string PK_INT_COLUMN_NAME = "IntCol"; + const string CHAR_COLUMN_NAME = "CharCol"; + + const int CHARSIZE = 255; + char column_name[CHARSIZE]; + char type_name[CHARSIZE]; + + // The test table columns + vector> columns = { + {PK_INT_COLUMN_NAME, "INT"}, + {CHAR_COLUMN_NAME, "VARCHAR(24)"} + }; + // primary key columns + vector pkColumns {{PK_INT_COLUMN_NAME}}; + + vector> bind_columns = { + {2, SQL_C_CHAR, column_name, CHARSIZE}, + {4, SQL_C_CHAR, type_name, CHARSIZE} + }; + + DatabaseObjects dbObjects; + ASSERT_NO_FATAL_FAILURE(dbObjects.CreateTable(COL_TABLE, columns, PrimaryKeyConstraintSpec(CONSTRAINT_NAME, pkColumns))); + ASSERT_NO_FATAL_FAILURE(odbcHandler.Connect(true)); + + ASSERT_NO_FATAL_FAILURE(odbcHandler.BindColumns(bind_columns)); + + rcode = SQLSpecialColumns(odbcHandler.GetStatementHandle(), SQL_BEST_ROWID, NULL, 0, NULL, 0, (SQLCHAR*) COL_TABLE.c_str(), SQL_NTS, 0, 0); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + rcode = SQLFetch(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + EXPECT_EQ(string(column_name), PK_INT_COLUMN_NAME); + EXPECT_EQ(string(type_name), "int"); + + rcode = SQLFetch(odbcHandler.GetStatementHandle()); + EXPECT_EQ(rcode, SQL_NO_DATA); +} + +// Tests SQLProcedureColumns for success with automatically updated columns +// DISABLED: PLEASE SEE BABELFISH-121 +TEST_F(Metadata, DISABLED_SQLSpecialColumns_AutoUpdatedColumns) { + + OdbcHandler odbcHandler; + RETCODE rcode; + const string COL_TABLE = "col_table_auto_update"; + const string INT_COLUMN_NAME = "IntCol"; + const string TIMESTAMP_COLUMN_NAME = "TimestampCol"; + const int CHARSIZE = 255; + char column_name[CHARSIZE]; + char type_name[CHARSIZE]; + + // The test table columns + vector> columns = { + {INT_COLUMN_NAME, "INT"}, + {TIMESTAMP_COLUMN_NAME, "TIMESTAMP"} + }; + + vector> bind_columns = { + {2, SQL_C_CHAR, column_name, CHARSIZE}, + {4, SQL_C_CHAR, type_name, CHARSIZE} + }; + + DatabaseObjects dbObjects; + ASSERT_NO_FATAL_FAILURE(dbObjects.CreateTable(COL_TABLE, columns)); + ASSERT_NO_FATAL_FAILURE(odbcHandler.Connect(true)); + + ASSERT_NO_FATAL_FAILURE(odbcHandler.BindColumns(bind_columns)); + + rcode = SQLSpecialColumns(odbcHandler.GetStatementHandle(), SQL_ROWVER, NULL, 0, NULL, 0, (SQLCHAR*) COL_TABLE.c_str(), SQL_NTS, 0, 0); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + rcode = SQLFetch(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + EXPECT_EQ(string(column_name), TIMESTAMP_COLUMN_NAME); + EXPECT_EQ(string(type_name), "timestamp"); + + rcode = SQLFetch(odbcHandler.GetStatementHandle()); + EXPECT_EQ(rcode, SQL_NO_DATA); +} + +// Tests SQLSetEnvAttr for success with SQL_ATTR_ODBC_VERSION +TEST_F(Metadata, SQLSetEnvAttr_SQL_ATTR_ODBC_VERSION) { + + RETCODE rcode; + SQLHENV henv_{}; + rcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv_); + ASSERT_EQ(rcode, SQL_SUCCESS); + + rcode = SQLSetEnvAttr(henv_, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0); + ASSERT_EQ(rcode, SQL_SUCCESS); + + rcode = SQLFreeHandle(SQL_HANDLE_ENV, henv_); + ASSERT_EQ(rcode, SQL_SUCCESS); +} + +// Tests SQLSetEnvAttr for success with SQL_ATTR_OUTPUT_NTS +TEST_F(Metadata, SQLSetEnvAttr_SQL_ATTR_OUTPUT_NTS) { + + RETCODE rcode; + SQLHENV henv_{}; + rcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv_); + ASSERT_EQ(rcode, SQL_SUCCESS); + + rcode = SQLSetEnvAttr(henv_, SQL_ATTR_OUTPUT_NTS, (SQLPOINTER)SQL_TRUE, 0); + ASSERT_EQ(rcode, SQL_SUCCESS); + + rcode = SQLFreeHandle(SQL_HANDLE_ENV, henv_); + ASSERT_EQ(rcode, SQL_SUCCESS); +} + +// Tests SQLSetEnvAttr for success with SQL_ATTR_CONNECTION_POOLING +TEST_F(Metadata, SQLSetEnvAttr_SQL_ATTR_CONNECTION_POOLING) { + + RETCODE rcode; + SQLHENV henv_{}; + rcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv_); + ASSERT_EQ(rcode, SQL_SUCCESS); + + rcode = SQLSetEnvAttr(henv_, SQL_ATTR_CONNECTION_POOLING, (SQLPOINTER)SQL_CP_ONE_PER_DRIVER, 0); + ASSERT_EQ(rcode, SQL_SUCCESS); + + rcode = SQLFreeHandle(SQL_HANDLE_ENV, henv_); + ASSERT_EQ(rcode, SQL_SUCCESS); +} + +// Tests SQLSetEnvAttr for success with SQL_ATTR_CP_MATCH +TEST_F(Metadata, SQLSetEnvAttr_SQL_ATTR_CP_MATCH) { + + RETCODE rcode; + SQLHENV henv_{}; + rcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv_); + ASSERT_EQ(rcode, SQL_SUCCESS); + + rcode = SQLSetEnvAttr(henv_, SQL_ATTR_CP_MATCH, (SQLPOINTER)SQL_CP_STRICT_MATCH, 0); + ASSERT_EQ(rcode, SQL_SUCCESS); + + rcode = SQLFreeHandle(SQL_HANDLE_ENV, henv_); + ASSERT_EQ(rcode, SQL_SUCCESS); +} + +// Tests SQLGetTypeInfo for success +TEST_F(Metadata, SQLGetTypeInfo) { + + OdbcHandler odbcHandler; + RETCODE rcode; + const int CHARSIZE = 255; + char type_name[CHARSIZE]; + SQLSMALLINT case_sensitive; + SQLSMALLINT sql_data_type; + + vector> bind_columns = { + {1, SQL_C_CHAR, type_name, CHARSIZE}, + {8, SQL_C_SHORT, &case_sensitive, 0}, + {16, SQL_C_SHORT, &sql_data_type, 0} + }; + + ASSERT_NO_FATAL_FAILURE(odbcHandler.ConnectAndExecQuery("")); + + ASSERT_NO_FATAL_FAILURE(odbcHandler.BindColumns(bind_columns)); + + rcode = SQLGetTypeInfo(odbcHandler.GetStatementHandle(), SQL_CHAR); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + rcode = SQLFetch(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + EXPECT_EQ(string(type_name), "char"); + EXPECT_EQ(case_sensitive, SQL_TRUE); // This will fail if testing on SQL Server because SQL_CHAR is case insensitive but SQL_CHAR is case sensitive in Postgres + BBF. + EXPECT_EQ(sql_data_type, SQL_CHAR); + + rcode = SQLFetch(odbcHandler.GetStatementHandle()); + EXPECT_EQ(rcode, SQL_NO_DATA); +} + +// Test SQLTables to retrieve catalogs +// DISABLED: PLEASE SEE BABELFISH-132 +TEST_F(Metadata, DISABLED_SQLTables_Catalogs) { + + OdbcHandler odbcHandler; + RETCODE rcode = -1; + + ASSERT_NO_FATAL_FAILURE(odbcHandler.Connect(true)); + rcode = SQLTables( odbcHandler.GetStatementHandle(), (SQLCHAR*)SQL_ALL_CATALOGS, SQL_NTS, (SQLCHAR*)"", SQL_NTS, (SQLCHAR*)"", SQL_NTS, (SQLCHAR*)"", SQL_NTS ); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + // In general, we don't know what catalogs are going to exist. + // But we should at least be able to verify that the current catalog/database was on the list + map values = { + {odbcHandler.GetDbname(),false} + }; + // Catalog/Database information is returned in column 1 + ASSERT_NO_FATAL_FAILURE(FetchAndMatchValues(odbcHandler, values, 1)); + + for (auto value : values) { + EXPECT_EQ(value.second, true) << value.first << " was expected but not found"; + } +} + +// Test SQLTables to retrieve tables +// DISABLED: PLEASE SEE BABELFISH-132 +TEST_F(Metadata, DISABLED_SQLTables_Tables) { + + OdbcHandler odbcHandler; + RETCODE rcode = -1; + + const vector testTables = { + {"meta_table1"}, + {"meta_table2"}, + {"meta_table3"} + }; + + // A few 'random' columns for a test tables. The columns are not relevant for this test. + vector> columns = { + {"id", "INT"}, + {"info", "VARCHAR(256) NOT NULL"}, + {"decivar", "NUMERIC(38,16) NOT NULL"} + }; + + DatabaseObjects dbObjects; + + for (auto table : testTables) { + ASSERT_NO_FATAL_FAILURE(dbObjects.CreateTable(table, columns)); + } + + ASSERT_NO_FATAL_FAILURE(odbcHandler.Connect(true)); + + rcode = SQLTables(odbcHandler.GetStatementHandle(), + NULL, 0, NULL, 0, NULL, 0, (SQLCHAR*) "TABLE", SQL_NTS); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + // In general, we don't know what tables are going to exist. + // But we should at least be able to verify that tables we created were on the list + map values; + for (auto table : testTables) { + values[table] = false; + } + + // Table/View information is returned in column 3 + ASSERT_NO_FATAL_FAILURE(FetchAndMatchValues(odbcHandler, values, 3)); + + for (auto value : values) { + EXPECT_TRUE(value.second) << value.first << " was expected but not found"; + } +} + +// Test SQLTables to retrieve views +// DISABLED: PLEASE SEE BABELFISH-132 +TEST_F(Metadata, DISABLED_SQLTables_Views) { + + OdbcHandler odbcHandler; + RETCODE rcode = -1; + + const string testTable {"meta_table"}; + + // A few 'random' columns for a test table. The columns are not relevant for this test. + const vector> columns = { + {"id", "INT"}, + {"info", "VARCHAR(256)"}, + {"decivar", "NUMERIC(38,16)"} + }; + + vector columnNames; + for (auto column : columns) { + columnNames.push_back(column.first); + } + + // View definitions used in this test. + // The vector pairs contain a view name and the select statement used to create the view. + const vector> testViews = { + {"meta_view1", SelectStatement(testTable, columnNames)}, + {"meta_view2", SelectStatement(testTable, {"*"})} + }; + + DatabaseObjects dbObjects; + + // Normally CreateTable and CreateView functions of DatabaseObjects try to drop the object before creating. + // Here we need to drop views explicitly, because the CreateTable below would attempt to drop the table first. + // If the views still existed, the drop table would fail in Postgres. It would work ok with SQL Server. + for (auto view : testViews) { + ASSERT_NO_FATAL_FAILURE(dbObjects.DropObject("VIEW",view.first)); + } + + ASSERT_NO_FATAL_FAILURE(dbObjects.CreateTable(testTable, columns)); + for (auto view : testViews) { + ASSERT_NO_FATAL_FAILURE(dbObjects.CreateView(view.first, view.second)); + } + + ASSERT_NO_FATAL_FAILURE(odbcHandler.Connect(true)); + + rcode = SQLTables(odbcHandler.GetStatementHandle(), + NULL, 0, NULL, 0, NULL, 0, (SQLCHAR*) "VIEW", SQL_NTS); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + // In general, we don't know what views are going to exist. + // But we should at least be able to verify that views we created were on the list + map values; + for (auto view : testViews) { + values[view.first] = false; + } + + // Table/View information is returned in column 3 + ASSERT_NO_FATAL_FAILURE(FetchAndMatchValues(odbcHandler, values, 3)); + + for (auto value : values) { + EXPECT_TRUE(value.second) << value.first << " was expected but not found"; + } +} diff --git a/contrib/test/odbc/test_prepared_statements.cpp b/contrib/test/odbc/test_prepared_statements.cpp new file mode 100644 index 00000000000..19e8a984d13 --- /dev/null +++ b/contrib/test/odbc/test_prepared_statements.cpp @@ -0,0 +1,367 @@ +#include "odbc_handler.h" +#include "database_objects.h" +#include "query_generator.h" +#include +#include + +using std::vector; +using std::pair; + +static const string SQLPREPTABLE_RO_1 = "sqlprepstmts_ro"; +// Columns for the test table +static const vector> RO_TABLE_COLUMNS = { + {"id", "INT"}, + {"info", "VARCHAR(256) NOT NULL"}, + {"decivar", "NUMERIC(38,16)"} + }; + +class Prepared_Statements : public testing::Test{ + + protected: + + static void SetUpTestSuite() { + + OdbcHandler test_setup; + test_setup.ConnectAndExecQuery(DropObjectStatement("TABLE",SQLPREPTABLE_RO_1)); + test_setup.ExecQuery(CreateTableStatement(SQLPREPTABLE_RO_1, RO_TABLE_COLUMNS)); + test_setup.ExecQuery(InsertStatement(SQLPREPTABLE_RO_1, "(1, 'hello1', 1.1), (2, 'hello2', 2.2), (3, 'hello3', 3.3), (4, 'hello4', 4.4)")); + } + + static void TearDownTestSuite() { + + OdbcHandler test_cleanup; + test_cleanup.ConnectAndExecQuery(DropObjectStatement("TABLE",SQLPREPTABLE_RO_1)); + } +}; + +RETCODE SetupPreparedStatements(OdbcHandler& odbcHandler, const string& query) { + + odbcHandler.Connect(true); + + return SQLPrepare(odbcHandler.GetStatementHandle(), (SQLCHAR*) query.c_str(), SQL_NTS); +} + +// Tests SQLPrepare is successful +TEST_F(Prepared_Statements, SQLPrepare_Success) { + + OdbcHandler odbcHandler; + RETCODE rcode; + string query = "SELECT * FROM " + SQLPREPTABLE_RO_1; + + rcode = SetupPreparedStatements(odbcHandler, query); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); +} + +// Tests SQLNumParams for an error when it is called before SQLPrepare +TEST_F(Prepared_Statements, SQLNumParams_Error) { + + OdbcHandler odbcHandler; + RETCODE rcode; + int num_params; + string sql_state; + + ASSERT_NO_FATAL_FAILURE(odbcHandler.Connect(true)); + + rcode = SQLNumParams(odbcHandler.GetStatementHandle(), (SQLSMALLINT*) &num_params); + ASSERT_EQ(rcode, SQL_ERROR); + sql_state = odbcHandler.GetSqlState(SQL_HANDLE_STMT, odbcHandler.GetStatementHandle()); + + ASSERT_EQ(sql_state, "HY010"); +} + +// Tests SQLNumParams succesfully for 1 paramater +TEST_F(Prepared_Statements, SQLNumParams_Success1) { + + OdbcHandler odbcHandler; + RETCODE rcode; + SQLSMALLINT num_params; + string query = "SELECT * FROM " + SQLPREPTABLE_RO_1 + " WHERE id = ?"; + + rcode = SetupPreparedStatements(odbcHandler, query); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + rcode = SQLNumParams(odbcHandler.GetStatementHandle(), &num_params); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + ASSERT_EQ(num_params, 1); +} + +// Tests SQLNumParams succesfully for 2 parameters +TEST_F(Prepared_Statements, SQLNumParams_Success2) { + + OdbcHandler odbcHandler; + RETCODE rcode; + SQLSMALLINT num_params; + string query = "SELECT * FROM " + SQLPREPTABLE_RO_1 + " WHERE id = ? AND info = ?"; + + rcode = SetupPreparedStatements(odbcHandler, query); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + rcode = SQLNumParams(odbcHandler.GetStatementHandle(), &num_params); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + ASSERT_EQ(num_params, 2); +} + +// Tests SQLNumParams succesfully for 3 parameters +TEST_F(Prepared_Statements, SQLNumParams_Success3) { + + OdbcHandler odbcHandler; + RETCODE rcode; + SQLSMALLINT num_params; + string query = "SELECT * FROM " + SQLPREPTABLE_RO_1 + " WHERE id = ? AND info = ? AND decivar = ?"; + + rcode = SetupPreparedStatements(odbcHandler, query); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + rcode = SQLNumParams(odbcHandler.GetStatementHandle(), &num_params); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + ASSERT_EQ(num_params, 3); +} + +// Tests SQLDescribeParam for on success +// DISABLED: PLEASE SEE BABELFISH-109 +TEST_F(Prepared_Statements, DISABLED_SQLDescribeParam_Success) { + + OdbcHandler odbcHandler; + RETCODE rcode; + SQLSMALLINT data_type, decimal_digits, nullable; + SQLULEN param_size; + string query = "SELECT * FROM " + SQLPREPTABLE_RO_1 + " WHERE id = ? AND info = ? AND decivar = ?"; + + rcode = SetupPreparedStatements(odbcHandler, query); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + // Does not check for nullable because SQLDescribeParam uses the IPD descriptor handle. Not all drivers support automatic + // population of the IPD. Asserting for nullness or non-nullness will be driver dependant. + rcode = SQLDescribeParam(odbcHandler.GetStatementHandle(), 1, &data_type, ¶m_size, &decimal_digits, &nullable ); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + ASSERT_EQ(data_type, SQL_INTEGER); + ASSERT_EQ(param_size, 10); + ASSERT_EQ(decimal_digits, 0); + + rcode = SQLDescribeParam(odbcHandler.GetStatementHandle(), 2, &data_type, ¶m_size, &decimal_digits, &nullable ); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + ASSERT_EQ(data_type, SQL_VARCHAR); + ASSERT_EQ(param_size, 256); + ASSERT_EQ(decimal_digits, 0); + + rcode = SQLDescribeParam(odbcHandler.GetStatementHandle(), 3, &data_type, ¶m_size, &decimal_digits, &nullable ); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + ASSERT_EQ(data_type, SQL_NUMERIC); + ASSERT_EQ(param_size, 38); + ASSERT_EQ(decimal_digits, 16); + +} + +// Tests SQLDescribeParam for error 21S01 +// DISABLED: PLEASE SEE BABELFISH-110 +TEST_F(Prepared_Statements, DISABLED_SQLDescribeParam_21S01) { + + OdbcHandler odbcHandler; + RETCODE rcode; + string sql_state; + SQLSMALLINT data_type, decimal_digits, nullable; + SQLULEN param_size; + string query = "INSERT INTO " + SQLPREPTABLE_RO_1 + " VALUES (?, ?, ?, ?)"; + + rcode = SetupPreparedStatements(odbcHandler, query); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + rcode = SQLDescribeParam(odbcHandler.GetStatementHandle(), 3, &data_type, ¶m_size, &decimal_digits, &nullable ); + ASSERT_EQ(rcode, SQL_ERROR); + sql_state = odbcHandler.GetSqlState(SQL_HANDLE_STMT, odbcHandler.GetStatementHandle()); + ASSERT_EQ(sql_state, "21S01"); + +} + +// Tests SQLDescribeParam for error 07009 (no parameters) +TEST_F(Prepared_Statements, SQLDescribeParam_Noparams) { + + OdbcHandler odbcHandler; + RETCODE rcode; + SQLSMALLINT data_type, decimal_digits, nullable; + SQLULEN param_size; + string sql_state; + string query = "SELECT * FROM " + SQLPREPTABLE_RO_1 + " "; + + rcode = SetupPreparedStatements(odbcHandler, query); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + rcode = SQLDescribeParam(odbcHandler.GetStatementHandle(), 1, &data_type, ¶m_size, &decimal_digits, &nullable ); + ASSERT_EQ(rcode, SQL_ERROR); + sql_state = odbcHandler.GetSqlState(SQL_HANDLE_STMT, odbcHandler.GetStatementHandle()); + ASSERT_EQ(sql_state, "07009"); +} + +// Tests bind parameters when parameters are binded successfully. +TEST_F(Prepared_Statements, SQLBindParameter_Success) { + + OdbcHandler odbcHandler; + RETCODE rcode; + + SQLUINTEGER id_input = 1; + SQLCHAR info_input[256] = "hello1"; + SQLFLOAT decivar_input = 1.1; + string query = "SELECT * FROM " + SQLPREPTABLE_RO_1 + " WHERE id = ? AND info = ? AND decivar = ?"; + + rcode = SetupPreparedStatements(odbcHandler, query); + + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + rcode = SQLBindParameter(odbcHandler.GetStatementHandle(), 1,SQL_PARAM_INPUT, SQL_C_ULONG, SQL_INTEGER, 10, 0, + &id_input,0,0); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + rcode = SQLBindParameter(odbcHandler.GetStatementHandle(), 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, 256, 0, + info_input,256, 0); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + rcode = SQLBindParameter(odbcHandler.GetStatementHandle(), 3, SQL_PARAM_INPUT, SQL_C_NUMERIC, SQL_NUMERIC, 38, 16, + &decivar_input, 0, 0); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); +} + +// Tests SQLExecute when it is used successfully. +TEST_F(Prepared_Statements, SQLExecute_Success) { + + OdbcHandler odbcHandler; + RETCODE rcode; + SQLUINTEGER id_input = 1; + SQLCHAR info_input[256] = "hello1"; + + int id_out; + SQLCHAR info_out[256]; + string query = "SELECT * FROM " + SQLPREPTABLE_RO_1 + " WHERE id = ? AND info = ?"; + + rcode = SetupPreparedStatements(odbcHandler, query); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + rcode = SQLBindParameter(odbcHandler.GetStatementHandle(), 1,SQL_PARAM_INPUT, SQL_C_ULONG, SQL_INTEGER, 10, 0, + &id_input,0,0); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + rcode = SQLBindParameter(odbcHandler.GetStatementHandle(), 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, 256, 0, + info_input,256, 0); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + rcode = SQLExecute(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + rcode = SQLFetch(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode);; + + rcode = SQLGetData(odbcHandler.GetStatementHandle(), 1, SQL_C_ULONG, &id_out, 0, 0); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + ASSERT_EQ(id_out, id_input); + + rcode = SQLGetData(odbcHandler.GetStatementHandle(), 2, SQL_C_CHAR, info_out, sizeof(info_out), 0); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + ASSERT_EQ(string((char*) info_out), string((char*)info_input)); +} + +// Tests SQLExecute with division by zero +TEST_F(Prepared_Statements, SQLExecute_DivisionByZero) { + + OdbcHandler odbcHandler; + RETCODE rcode; + string sql_state; + string query = "SELECT (10/0)"; + + rcode = SetupPreparedStatements(odbcHandler, query); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + rcode = SQLExecute(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_ERROR); + sql_state = odbcHandler.GetSqlState(SQL_HANDLE_STMT, odbcHandler.GetStatementHandle()); + ASSERT_EQ(sql_state, "22012"); + +} + +// Tests SQLExecute with an already existing table +TEST_F(Prepared_Statements, SQLExecute_AlreadyExistingTable) { + + OdbcHandler odbcHandler; + RETCODE rcode; + string sql_state; + string query = "CREATE TABLE " + SQLPREPTABLE_RO_1 + " (id int);"; + + rcode = SetupPreparedStatements(odbcHandler, query); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + rcode = SQLExecute(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_ERROR); + sql_state = odbcHandler.GetSqlState(SQL_HANDLE_STMT, odbcHandler.GetStatementHandle()); + ASSERT_EQ(sql_state, "42S01"); + +} + +// Tests SQLExecute with a not valid sql statement +// DISABLED: PLEASE SEE: BABELFISH-111 +TEST_F(Prepared_Statements, DISABLED_SQLExecute_NotValidSqlStatement) { + + OdbcHandler odbcHandler; + RETCODE rcode; + string sql_state; + + ASSERT_NO_FATAL_FAILURE(odbcHandler.Connect(true)); + + rcode = SQLPrepare(odbcHandler.GetStatementHandle(),(SQLCHAR*) "ABC", SQL_NTS); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + rcode = SQLExecute(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_ERROR); + sql_state = odbcHandler.GetSqlState(SQL_HANDLE_STMT, odbcHandler.GetStatementHandle()); + ASSERT_EQ(sql_state, "42000"); + +} + +// SQLMoreResults with an array as an input for a prepared statement +TEST_F(Prepared_Statements, SQLMoreResults_BatchedArrayParamQueries) { + + OdbcHandler odbcHandler; + RETCODE rcode; + string sql_state; + const int ARRAY_SIZE = 4; + int id_input[4] = {1,2,3,4}; + string query = "SELECT * FROM " + SQLPREPTABLE_RO_1 + " WHERE id = ?"; + int id_out; + + ASSERT_NO_FATAL_FAILURE(odbcHandler.Connect(true)); + + rcode = SQLSetStmtAttr(odbcHandler.GetStatementHandle(), SQL_ATTR_PARAM_BIND_TYPE, SQL_PARAM_BIND_BY_COLUMN, 0); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + rcode = SQLSetStmtAttr(odbcHandler.GetStatementHandle(), SQL_ATTR_PARAMSET_SIZE, (SQLPOINTER) ARRAY_SIZE, 0); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + rcode = SQLPrepare(odbcHandler.GetStatementHandle(), (SQLCHAR*) query.c_str(), SQL_NTS); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + rcode = SQLBindParameter(odbcHandler.GetStatementHandle(), 1, SQL_PARAM_INPUT, SQL_C_ULONG, SQL_INTEGER, 10, 0, id_input, 0, 0); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + rcode = SQLExecute(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + rcode = SQLFetch(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + rcode = SQLGetData(odbcHandler.GetStatementHandle(), 1, SQL_C_ULONG, &id_out, 0, 0); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + ASSERT_EQ(id_out, 1); + rcode = SQLFetch(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_NO_DATA); + + // Should be able to call SQLMoreResults ARRAY_SIZE -1 times (since SQLExecute should call the first result set); + for(int i = 0; i < ARRAY_SIZE - 1; i++) { + + rcode = SQLMoreResults(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + rcode = SQLFetch(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + rcode = SQLGetData(odbcHandler.GetStatementHandle(), 1, SQL_C_ULONG, &id_out, 0, 0); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + ASSERT_EQ(id_out, i + 2); + + rcode = SQLFetch(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_NO_DATA); + } + + rcode = SQLMoreResults(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_NO_DATA); +} \ No newline at end of file diff --git a/contrib/test/odbc/test_resultset.cpp b/contrib/test/odbc/test_resultset.cpp new file mode 100644 index 00000000000..782a3620332 --- /dev/null +++ b/contrib/test/odbc/test_resultset.cpp @@ -0,0 +1,760 @@ +#include "odbc_handler.h" +#include "database_objects.h" +#include "query_generator.h" +#include +#include + +using std::vector; +using std::pair; +using std::tuple; + +// Read Only table +static const string RESULT_SET_RO_TABLE1 = "RESULT_SET_RO"; + +// Columns for the test table +static const vector> RO_TABLE_COLUMNS = { + {"id", "INT"}, + {"info", "VARCHAR(256) NOT NULL"}, + {"decivar", "NUMERIC(38,16)"} + }; + +static const vector> RO_TABLE_VALUES = { + {1, "hello1", 1.1}, + {2, "hello2", 2.2}, + {3, "hello3", 3.3}, + {4, "hello4", 4.4} + }; + +const string SELECT_RESULT_SET_RO_TABLE1 = SelectStatement(RESULT_SET_RO_TABLE1, { "*" }, {"id"}); // order by id + +class Result_Set : public testing::Test { + + protected: + static void SetUpTestSuite() { + OdbcHandler test_setup; + + test_setup.ConnectAndExecQuery(DropObjectStatement("TABLE",RESULT_SET_RO_TABLE1)); + test_setup.ExecQuery(CreateTableStatement(RESULT_SET_RO_TABLE1, RO_TABLE_COLUMNS)); + test_setup.ExecQuery(InsertStatement(RESULT_SET_RO_TABLE1, "(1, 'hello1', 1.1), (2, 'hello2', 2.2), (3, 'hello3', 3.3), (4, 'hello4', 4.4)")); + } + + static void TearDownTestSuite() { + OdbcHandler test_cleanup; + + test_cleanup.ConnectAndExecQuery(DropObjectStatement("TABLE",RESULT_SET_RO_TABLE1)); + } + +}; + +// Setup function for SQLBindcol tests. +// Execute query on the read only table and calls BindCol with a given col num as the argument. +// It will also assert the given expected rcode and output the sql state. +void SQLBindColTestSetup(const int col_num, const RETCODE expected_rcode, string* sql_state) { + OdbcHandler odbcHandler; + RETCODE rcode; + SQLINTEGER id; + SQLLEN id_indicator; + + odbcHandler.ConnectAndExecQuery(SELECT_RESULT_SET_RO_TABLE1); + + rcode = SQLBindCol(odbcHandler.GetStatementHandle(), col_num, SQL_C_ULONG, &id, 0, &id_indicator); + ASSERT_EQ(rcode, expected_rcode); + + *sql_state = odbcHandler.GetSqlState(SQL_HANDLE_STMT, odbcHandler.GetStatementHandle()); +} + +// Connects the odbcHandler, allocate the stmt handle, and set the stmt handle to be scrollable +void ConnectAndSetScrollable(OdbcHandler* odbcHandler) { + RETCODE rcode; + odbcHandler->Connect(true); + rcode = SQLSetStmtAttr(odbcHandler->GetStatementHandle(), + SQL_ATTR_CURSOR_SCROLLABLE, + (SQLPOINTER) SQL_SCROLLABLE, + 0); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler->GetErrorMessage(SQL_HANDLE_STMT, rcode); +} + +void ConnectAndSetScrollableWithConcurLock(OdbcHandler* odbcHandler) { + RETCODE rcode; + + ConnectAndSetScrollable(odbcHandler); + rcode = SQLSetStmtAttr(odbcHandler->GetStatementHandle(), SQL_ATTR_CONCURRENCY, + (SQLPOINTER)SQL_CONCUR_LOCK ,0); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler->GetErrorMessage(SQL_HANDLE_STMT, rcode); +} + +// Tests SQLBindCol on a succesful state. +TEST_F(Result_Set, SQLBindCol_Successful) { + string sql_state; + + SQLBindColTestSetup(1, SQL_SUCCESS, &sql_state); + ASSERT_EQ(sql_state, "00000"); +} + +// Tests SQLBindCol when ColumnNumber is 0 and it is not a bookmark column +TEST_F(Result_Set, SQLBindCol_NotBookmark) { + string sql_state; + + // Bind column and assert that it returns error 07006 + SQLBindColTestSetup(0, SQL_ERROR, &sql_state); + ASSERT_EQ(sql_state, "07006"); +} + +// Tests SQLBindCol when ColumnNumber argument exceeds max number of columns in result set +TEST_F(Result_Set, SQLBindCol_ExceedMaxCol) { + string sql_state; + + // Bind column and assert that it returns error 07009 + SQLBindColTestSetup(10000, SQL_ERROR, &sql_state); + ASSERT_EQ(sql_state, "07009"); +} + +// Tests SQLFetch when it iterates through all results +TEST_F(Result_Set, SQLFetch_SuccessfulIteration) { + OdbcHandler odbcHandler; + RETCODE rcode; + string sql_state; + SQLINTEGER id; + SQLCHAR info[256]; + SQLLEN info_indicator; + SQLLEN id_indicator; + + vector> bind_columns = { + {1, SQL_C_ULONG, &id, 0}, + {2, SQL_C_CHAR, &info, sizeof(info)} + }; + + ASSERT_NO_FATAL_FAILURE(odbcHandler.ConnectAndExecQuery(SELECT_RESULT_SET_RO_TABLE1)); + + ASSERT_NO_FATAL_FAILURE(odbcHandler.BindColumns(bind_columns)); + + for (auto row_values : RO_TABLE_VALUES) { + // Assert that it is able to fetch all rows with the correct values + rcode = SQLFetch(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + auto& [id_val, info_val, decivar_val] = row_values; + EXPECT_EQ(id, id_val); + EXPECT_EQ(string((char*) info),info_val); + } + + // Assert that SQLFetch returns SQL_NO_DATA + rcode = SQLFetch(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_NO_DATA); +} + +// Tests SQLFetch when a varchar variable gets truncated +TEST_F(Result_Set, SQLFetch_TruncatedVarchar) { + OdbcHandler odbcHandler; + RETCODE rcode; + string sql_state; + SQLCHAR info[2]; + SQLLEN info_indicator; + + ASSERT_NO_FATAL_FAILURE(odbcHandler.ConnectAndExecQuery(SELECT_RESULT_SET_RO_TABLE1)); + + // Bind the columns to variables + rcode = SQLBindCol(odbcHandler.GetStatementHandle(), 2, SQL_C_CHAR, &info, sizeof(info), &info_indicator); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + // Assert that we get sql state 01004 when a varchar variable is truncated + rcode = SQLFetch(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_SUCCESS_WITH_INFO) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + sql_state = odbcHandler.GetSqlState(SQL_HANDLE_STMT,odbcHandler.GetStatementHandle()); + ASSERT_EQ(sql_state, "01004"); +} + +// Tests SQLFetch when a numeric datatype gets truncated +TEST_F(Result_Set, SQLFetch_TruncatedNumeric) { + OdbcHandler odbcHandler; + RETCODE rcode; + string sql_state; + SQLINTEGER decivar; + SQLLEN decivar_indicator; + + ASSERT_NO_FATAL_FAILURE(odbcHandler.ConnectAndExecQuery(SELECT_RESULT_SET_RO_TABLE1)); + + // Bind the columns to variables + rcode = SQLBindCol(odbcHandler.GetStatementHandle(), 3, SQL_C_ULONG, &decivar, 0, &decivar_indicator); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + rcode = SQLFetch(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_SUCCESS_WITH_INFO) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + // Assert that we get sql state 01S07 when a numeric datatype is truncated + sql_state = odbcHandler.GetSqlState(SQL_HANDLE_STMT,odbcHandler.GetStatementHandle()); + ASSERT_EQ(sql_state, "01S07"); +} + +// Tests SQLFetch when there is an invalid cast during bindcol. +TEST_F(Result_Set, SQLFetch_InvalidCast) { + OdbcHandler odbcHandler; + RETCODE rcode; + string sql_state; + SQLINTEGER id; + SQLLEN id_indicator; + + ASSERT_NO_FATAL_FAILURE(odbcHandler.ConnectAndExecQuery(SELECT_RESULT_SET_RO_TABLE1)); + + // Bind the columns to variables + rcode = SQLBindCol(odbcHandler.GetStatementHandle(), 2, SQL_C_ULONG, &id, 0, &id_indicator); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + // Assert that we get sql state 22018 when there is an invalid cast + rcode = SQLFetch(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_ERROR); + sql_state = odbcHandler.GetSqlState(SQL_HANDLE_STMT,odbcHandler.GetStatementHandle()); + ASSERT_EQ(sql_state, "22018"); +} + +// Tests SQLSetPos when SQL_ATTR_ROW_ARRAY_SIZE is set to 1. +// DISABLED: PLEASE SEE BABELFISH-97 +TEST_F(Result_Set, DISABLED_SQLSetPos_ResultRowSize1) { + OdbcHandler odbcHandler; + RETCODE rcode; + string sql_state; + int id; + SQLLEN id_indicator; + + // Setup, connect and set attributes for SQLSetPos + ASSERT_NO_FATAL_FAILURE(ConnectAndSetScrollable(&odbcHandler)); + ASSERT_NO_FATAL_FAILURE(odbcHandler.ExecQuery(SELECT_RESULT_SET_RO_TABLE1)); + + // Assert that we can retrieve the first row of the results but not the second. + rcode = SQLFetch(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + rcode = SQLSetPos(odbcHandler.GetStatementHandle(), 1, SQL_POSITION, SQL_LOCK_NO_CHANGE); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + rcode = SQLGetData(odbcHandler.GetStatementHandle(), 1, SQL_C_ULONG, &id, 0, &id_indicator); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + ASSERT_EQ(id, 1); + rcode = SQLSetPos(odbcHandler.GetStatementHandle(), 2, SQL_POSITION, SQL_LOCK_NO_CHANGE); + ASSERT_EQ(rcode, SQL_ERROR); + + sql_state = odbcHandler.GetSqlState(SQL_HANDLE_STMT, odbcHandler.GetStatementHandle()); + ASSERT_EQ(sql_state, "HY107"); +} + +// Tests SQLSetPos when SQL_ATTR_ROW_ARRAY_SIZE is set to 2. +// DISABLED: PLEASE SEE BABELFISH-97 +TEST_F(Result_Set, DISABLED_SQLSetPos_ResultRowSize2) { + OdbcHandler odbcHandler; + RETCODE rcode; + string sql_state; + int id; + SQLLEN id_indicator; + + ASSERT_NO_FATAL_FAILURE(ConnectAndSetScrollable(&odbcHandler)); + rcode = SQLSetStmtAttr(odbcHandler.GetStatementHandle(), + SQL_ATTR_ROW_ARRAY_SIZE, + (SQLPOINTER) 2, + SQL_IS_INTEGER); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + ASSERT_NO_FATAL_FAILURE(odbcHandler.ExecQuery(SELECT_RESULT_SET_RO_TABLE1)); + + rcode = SQLFetch(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + // Assert that we can retrieve the first and second row of the results but not the third. + rcode = SQLSetPos(odbcHandler.GetStatementHandle(), 1, SQL_POSITION, SQL_LOCK_NO_CHANGE); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + rcode = SQLSetPos(odbcHandler.GetStatementHandle(), 2, SQL_POSITION, SQL_LOCK_NO_CHANGE); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + rcode = SQLSetPos(odbcHandler.GetStatementHandle(), 3, SQL_POSITION, SQL_LOCK_NO_CHANGE); + ASSERT_EQ(rcode, SQL_ERROR); + sql_state = odbcHandler.GetSqlState(SQL_HANDLE_STMT, odbcHandler.GetStatementHandle()); + ASSERT_EQ(sql_state, "HY107"); + + // Assert that we can get the last set of items by calling another SQLFetch + rcode = SQLFetch(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + rcode = SQLSetPos(odbcHandler.GetStatementHandle(), 1, SQL_POSITION, SQL_LOCK_NO_CHANGE); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + rcode = SQLGetData(odbcHandler.GetStatementHandle(), 1, SQL_C_ULONG, &id, 0, &id_indicator); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + ASSERT_EQ(id, 3); +} + +// Tests that SQL_UPDATE OR SQL_DELETE option would not work when +// SQL_ATTR_CONCURRENCY is set to read only (which should be the default value) +// DISABLED: PLEASE SEE BABELFISH-97 +TEST_F(Result_Set, DISABLED_SQLSetPos_ErrorSqlAttrConcurrencyReadOnly) { + OdbcHandler odbcHandler; + RETCODE rcode; + string sql_state; + + // Setup statement attributes and run the initial query + ASSERT_NO_FATAL_FAILURE(ConnectAndSetScrollable(&odbcHandler)); + + ASSERT_NO_FATAL_FAILURE(odbcHandler.ExecQuery(SELECT_RESULT_SET_RO_TABLE1)); + + // Fetch result and assert that there is an error of state HY0902 when using SQL_UPDATE + rcode = SQLFetch(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + rcode = SQLSetPos(odbcHandler.GetStatementHandle(), 1, SQL_UPDATE, SQL_LOCK_NO_CHANGE); + ASSERT_EQ(rcode, SQL_ERROR); + sql_state = odbcHandler.GetSqlState(SQL_HANDLE_STMT, odbcHandler.GetStatementHandle()); + ASSERT_EQ(sql_state, "HY092"); + + // Fetch result and assert that there is an error of state HY0902 when using SQL_DELETE + rcode = SQLSetPos(odbcHandler.GetStatementHandle(), 1, SQL_DELETE, SQL_LOCK_NO_CHANGE); + ASSERT_EQ(rcode, SQL_ERROR); + sql_state = odbcHandler.GetSqlState(SQL_HANDLE_STMT, odbcHandler.GetStatementHandle()); + ASSERT_EQ(sql_state, "HY092"); +} + +// Tests that SQL_UPDATE option gives error 21S02 +// DISABLED: PLEASE SEE BABELFISH-97 +TEST_F(Result_Set, DISABLED_SQLSetPos_Sqlupdate21S02) { + + const string TEST_TABLE = "RESULT_SET_UPDATE21S02"; + const string TEST_SELECT = SelectStatement(TEST_TABLE, { "*" }); + + DatabaseObjects dbObjects; + ASSERT_NO_FATAL_FAILURE(dbObjects.CreateTable(TEST_TABLE, {{"id", "INT"}})); + ASSERT_NO_FATAL_FAILURE(dbObjects.Insert(TEST_TABLE,"(1), (2), (3), (4)")); + + OdbcHandler odbcHandler; + RETCODE rcode; + string sql_state; + + // Setup attributes and initial query + ASSERT_NO_FATAL_FAILURE(ConnectAndSetScrollableWithConcurLock(&odbcHandler)); + ASSERT_NO_FATAL_FAILURE(odbcHandler.ExecQuery(TEST_SELECT)); + + // Fetch results and assert that a state of 21S02 is returned due to no variables being bounded + rcode = SQLFetch(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + rcode = SQLSetPos(odbcHandler.GetStatementHandle(), 1, SQL_UPDATE, SQL_LOCK_NO_CHANGE); + ASSERT_EQ(rcode, SQL_ERROR); + sql_state = odbcHandler.GetSqlState(SQL_HANDLE_STMT, odbcHandler.GetStatementHandle()); + ASSERT_EQ(sql_state, "21S02"); + odbcHandler.FreeAllHandles(); // This is to release the concurrent lock. Otherwise dbObjects trying to drop the test table may block. +} + +// Tests that SQL_UPDATE option works correctly +// DISABLED: PLEASE SEE BABELFISH-97 +TEST_F(Result_Set, DISABLED_SQLSetPos_SqlupdateSuccessful) { + + const string TEST_TABLE = "RESULT_SET_UPDATE"; + const string TEST_SELECT = SelectStatement(TEST_TABLE, { "*" }); + + DatabaseObjects dbObjects; + ASSERT_NO_FATAL_FAILURE(dbObjects.CreateTable(TEST_TABLE, {{"id", "INT"}})); + ASSERT_NO_FATAL_FAILURE(dbObjects.Insert(TEST_TABLE,"(1), (2), (3), (4)")); + + OdbcHandler odbcHandler; + RETCODE rcode; + SQLINTEGER id = 10; + SQLLEN id_indicator; + + // Setup + ASSERT_NO_FATAL_FAILURE(ConnectAndSetScrollableWithConcurLock(&odbcHandler)); + ASSERT_NO_FATAL_FAILURE(odbcHandler.ExecQuery(TEST_SELECT)); + + // Fetch and bind column to id and call SQLSetPos with SQL_UPDATE option + rcode = SQLFetch(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + rcode = SQLBindCol(odbcHandler.GetStatementHandle(), 1, SQL_C_ULONG, &id, 0, &id_indicator); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + rcode = SQLSetPos(odbcHandler.GetStatementHandle(), 1, SQL_UPDATE, SQL_LOCK_NO_CHANGE); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + ASSERT_NO_FATAL_FAILURE(odbcHandler.FreeAllHandles()); + + // Assert that the first item has changed to 10 + ASSERT_NO_FATAL_FAILURE(odbcHandler.ConnectAndExecQuery(TEST_SELECT)); + rcode = SQLBindCol(odbcHandler.GetStatementHandle(), 1, SQL_C_ULONG, &id, 0, &id_indicator); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + rcode = SQLFetch(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + ASSERT_EQ(id, 10); +} + +// Ensures that SQL_DELETE works correctly +// DISABLED: PLEASE SEE BABELFISH-97 +TEST_F(Result_Set, DISABLED_SQLSetPos_SqldeleteSuccessful) { + OdbcHandler odbcHandler; + RETCODE rcode; + SQLINTEGER id; + SQLLEN id_indicator; + int num_rows_before = 0; + int num_rows_after = 0; + + const string TEST_TABLE = "RESULT_SET_DELETE"; + const string TEST_SELECT = SelectStatement(TEST_TABLE, { "*" }); + + DatabaseObjects dbObjects; + ASSERT_NO_FATAL_FAILURE(dbObjects.CreateTable(TEST_TABLE, {{"id", "INT"}})); + ASSERT_NO_FATAL_FAILURE(dbObjects.Insert(TEST_TABLE,"(1), (2), (3), (4)")); + + // Setup num_rows_before + ASSERT_NO_FATAL_FAILURE(odbcHandler.Connect(true)); + ASSERT_NO_FATAL_FAILURE(odbcHandler.ExecQuery(TEST_SELECT)); + + // Count all the rows before delete for setup + while (SQLFetch(odbcHandler.GetStatementHandle()) != SQL_NO_DATA) { + num_rows_before++; + } + + // Setup for SQLSetpos with SQL_Delete option + ASSERT_NO_FATAL_FAILURE(odbcHandler.FreeAllHandles()); + ASSERT_NO_FATAL_FAILURE(ConnectAndSetScrollableWithConcurLock(&odbcHandler)); + ASSERT_NO_FATAL_FAILURE(odbcHandler.ExecQuery(TEST_SELECT)); + + // Call SQLSetPos with SQL_DELETE option and ensure that it is succesful + rcode = SQLFetch(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + rcode = SQLSetPos(odbcHandler.GetStatementHandle(), 1, SQL_DELETE, SQL_LOCK_NO_CHANGE); + EXPECT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + + ASSERT_NO_FATAL_FAILURE(odbcHandler.FreeAllHandles()); + + // Recount all rows and assert that there is one less than before + ASSERT_NO_FATAL_FAILURE(odbcHandler.ConnectAndExecQuery(TEST_SELECT)); + while (SQLFetch(odbcHandler.GetStatementHandle()) != SQL_NO_DATA) { + num_rows_after++; + } + ASSERT_EQ(num_rows_after, num_rows_before -1); +} + +// Ensures that SQLGetData works correctly +TEST_F(Result_Set, SQLGetData_Successful) { + OdbcHandler odbcHandler; + RETCODE rcode; + SQLINTEGER id; + SQLLEN id_indicator; + + // Setup + ASSERT_NO_FATAL_FAILURE(odbcHandler.ConnectAndExecQuery(SELECT_RESULT_SET_RO_TABLE1)); + rcode = SQLFetch(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + // Assert that SQLGetData retrieves the correct value + rcode = SQLGetData(odbcHandler.GetStatementHandle(), 1, SQL_C_ULONG, &id, 0, &id_indicator); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + ASSERT_EQ(id, 1); +} + +// Tests SQLGetData when a varchar variable gets truncated +TEST_F(Result_Set, SQLGetData_TruncatedVarchar) { + OdbcHandler odbcHandler; + RETCODE rcode; + string sql_state; + SQLCHAR info[2]; + SQLLEN info_indicator; + + // Setup + ASSERT_NO_FATAL_FAILURE(odbcHandler.ConnectAndExecQuery(SELECT_RESULT_SET_RO_TABLE1)); + rcode = SQLFetch(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + // Assert that we get sql state 01004 when a varchar variable is truncated + rcode = SQLGetData(odbcHandler.GetStatementHandle(), 2, SQL_C_CHAR, &info, sizeof(info), &info_indicator); + ASSERT_EQ(rcode, SQL_SUCCESS_WITH_INFO) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + sql_state = odbcHandler.GetSqlState(SQL_HANDLE_STMT,odbcHandler.GetStatementHandle()); + ASSERT_EQ(sql_state, "01004"); +} + +// Tests SQLGetData when a numeric datatype gets truncated +TEST_F(Result_Set, SQLGetData_TruncatedNumeric) { + OdbcHandler odbcHandler; + RETCODE rcode; + string sql_state; + SQLINTEGER decivar; + SQLLEN decivar_indicator; + + // Setup + ASSERT_NO_FATAL_FAILURE(odbcHandler.ConnectAndExecQuery(SELECT_RESULT_SET_RO_TABLE1)); + rcode = SQLFetch(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + // Assert that we get sql state 01004 when a numeric datatype is truncated + rcode = SQLGetData(odbcHandler.GetStatementHandle(), 3, SQL_C_ULONG, &decivar, 0, &decivar_indicator); + ASSERT_EQ(rcode, SQL_SUCCESS_WITH_INFO) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + sql_state = odbcHandler.GetSqlState(SQL_HANDLE_STMT,odbcHandler.GetStatementHandle()); + ASSERT_EQ(sql_state, "01S07"); +} + +// Tests SQLGetData when there is an invalid cast during bindcol. +TEST_F(Result_Set, SQLGetData_InvalidCast) { + OdbcHandler odbcHandler; + RETCODE rcode; + string sql_state; + SQLINTEGER id; + SQLLEN id_indicator; + + ASSERT_NO_FATAL_FAILURE(odbcHandler.ConnectAndExecQuery(SELECT_RESULT_SET_RO_TABLE1)); + + // Assert that we get sql state 22018 when there is an invalid cast + rcode = SQLFetch(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + rcode = SQLGetData(odbcHandler.GetStatementHandle(), 2, SQL_C_ULONG, &id, 0, &id_indicator); + ASSERT_EQ(rcode, SQL_ERROR); + sql_state = odbcHandler.GetSqlState(SQL_HANDLE_STMT,odbcHandler.GetStatementHandle()); + ASSERT_EQ(sql_state, "22018"); +} + +// Test SQLFetchScroll with Fetch First and Fetch Last options +// DISABLED: PLEASE SEE BABELFISH-98 +TEST_F(Result_Set, DISABLED_SQLFetchScroll_FetchFirstAndFetchLast) { + OdbcHandler odbcHandler; + RETCODE rcode; + string sql_state; + SQLINTEGER id; + SQLLEN id_indicator; + + int firstValue = std::get<0>(RO_TABLE_VALUES[0]); + int lastValue = std::get<0>(RO_TABLE_VALUES[RO_TABLE_VALUES.size()-1]); + + // Setup + ASSERT_NO_FATAL_FAILURE(ConnectAndSetScrollable(&odbcHandler)); + ASSERT_NO_FATAL_FAILURE(odbcHandler.ExecQuery(SELECT_RESULT_SET_RO_TABLE1)); + + // Call SQLFetchScroll with SQL_FETCH_FIRST option and assert that the correct value is being returned + rcode = SQLFetchScroll(odbcHandler.GetStatementHandle(), SQL_FETCH_FIRST, 0); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + rcode = SQLGetData(odbcHandler.GetStatementHandle(), 1, SQL_C_ULONG, &id, 0, &id_indicator); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + ASSERT_EQ(id, firstValue); + + // Call SQLFetchScroll with SQL_FETCH_LAST option and assert that the correct value is being returned + rcode = SQLFetchScroll(odbcHandler.GetStatementHandle(), SQL_FETCH_LAST, 0); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + rcode = SQLGetData(odbcHandler.GetStatementHandle(), 1, SQL_C_ULONG, &id, 0, &id_indicator); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + ASSERT_EQ(id, lastValue); +} + +// Test SQLFetchScroll with SQL_FETCH_NEXT and SQL_FETCH_PRIOR +// DISABLED: PLEASE SEE BABELFISH-98 +TEST_F(Result_Set, DISABLED_SQLFetchScroll_FetchNextAndFetchPrior) { + OdbcHandler odbcHandler; + RETCODE rcode; + string sql_state; + SQLINTEGER id; + SQLLEN id_indicator; + + // setup + ASSERT_NO_FATAL_FAILURE(ConnectAndSetScrollable(&odbcHandler)); + ASSERT_NO_FATAL_FAILURE(odbcHandler.ExecQuery(SELECT_RESULT_SET_RO_TABLE1)); + + int num_results = RO_TABLE_VALUES.size(); + // Move the cursor forward through all the results and assert the values retrieved are correct + for (int i = 1; i <= num_results; i++) { + rcode = SQLFetchScroll(odbcHandler.GetStatementHandle(), SQL_FETCH_NEXT, 0); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + rcode = SQLGetData(odbcHandler.GetStatementHandle(), 1, SQL_C_ULONG, &id, 0, &id_indicator); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + ASSERT_EQ(id, std::get<0>(RO_TABLE_VALUES[i-1])); + } + + // Assert that there is no more data past the end + rcode = SQLFetchScroll(odbcHandler.GetStatementHandle(), SQL_FETCH_NEXT, 0); + ASSERT_EQ(rcode, SQL_NO_DATA); + + // Move the cursor backwards through all the results and assert the values retrieved are correct + for (int i = num_results; i > 0; i--) { + rcode = SQLFetchScroll(odbcHandler.GetStatementHandle(), SQL_FETCH_PRIOR, 0); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + rcode = SQLGetData(odbcHandler.GetStatementHandle(), 1, SQL_C_ULONG, &id, 0, &id_indicator); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + ASSERT_EQ(id, std::get<0>(RO_TABLE_VALUES[i-1])); + } + + // Assert that there is no more data before the beginning of the result set + rcode = SQLFetchScroll(odbcHandler.GetStatementHandle(), SQL_FETCH_PRIOR, 0); + ASSERT_EQ(rcode, SQL_NO_DATA); +} + +// Test SQLFetchScroll with SQL_FETCH_ABSOLUTE +// DISABLED: PLEASE SEE BABELFISH-98 +TEST_F(Result_Set, DISABLED_SQLFetchScroll_FetchAbsolute) { + OdbcHandler odbcHandler; + RETCODE rcode; + SQLINTEGER id; + SQLLEN id_indicator; + + // Setup connection + ASSERT_NO_FATAL_FAILURE(ConnectAndSetScrollable(&odbcHandler)); + ASSERT_NO_FATAL_FAILURE(odbcHandler.ExecQuery(SELECT_RESULT_SET_RO_TABLE1)); + + int num_results = RO_TABLE_VALUES.size(); + // Go through the whole table and assert that the correct values are retrieved + for (int i = 1; i <= num_results; i++) { + rcode = SQLFetchScroll(odbcHandler.GetStatementHandle(), SQL_FETCH_ABSOLUTE, i); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + rcode = SQLGetData(odbcHandler.GetStatementHandle(), 1, SQL_C_ULONG, &id, 0, &id_indicator); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + ASSERT_EQ(id, std::get<0>(RO_TABLE_VALUES[i-1])); + } + + // Assert that we will move to row 2 and that the value of id is correct + rcode = SQLFetchScroll(odbcHandler.GetStatementHandle(), SQL_FETCH_ABSOLUTE, 2); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + rcode = SQLGetData(odbcHandler.GetStatementHandle(), 1, SQL_C_ULONG, &id, 0, &id_indicator); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + ASSERT_EQ(id, std::get<0>(RO_TABLE_VALUES[1])); +} + +// Test SQLFetchScroll with SQL_FETCH_RELATIVE +// DISABLED: PLEASE SEE BABELFISH-98 +TEST_F(Result_Set, DISABLED_SQLFetchScroll_FetchRelative) { + OdbcHandler odbcHandler; + RETCODE rcode; + SQLINTEGER id; + SQLLEN id_indicator; + + // Setup + ASSERT_NO_FATAL_FAILURE(ConnectAndSetScrollable(&odbcHandler)); + ASSERT_NO_FATAL_FAILURE(odbcHandler.ExecQuery(SELECT_RESULT_SET_RO_TABLE1)); + + int num_results = RO_TABLE_VALUES.size(); + // Go through all the results and assert that the correct value for id is fetched + for (int i = 1; i <= num_results; i++) { + rcode = SQLFetchScroll(odbcHandler.GetStatementHandle(), SQL_FETCH_RELATIVE, 1); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + rcode = SQLGetData(odbcHandler.GetStatementHandle(), 1, SQL_C_ULONG, &id, 0, &id_indicator); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + ASSERT_EQ(id, std::get<0>(RO_TABLE_VALUES[i-1])); + } + + // Move the cursor back by 2 rows and assert that the correct result is fetched + rcode = SQLFetchScroll(odbcHandler.GetStatementHandle(), SQL_FETCH_RELATIVE, -2); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + rcode = SQLGetData(odbcHandler.GetStatementHandle(), 1, SQL_C_ULONG, &id, 0, &id_indicator); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + ASSERT_EQ(id, std::get<0>(RO_TABLE_VALUES[1])); + + // Assert that SQL_NO_DATA is returned when the cursor is moved past before the beginning + rcode = SQLFetchScroll(odbcHandler.GetStatementHandle(), SQL_FETCH_RELATIVE, -2); + ASSERT_EQ(rcode, SQL_NO_DATA); +} + +// Tests SQLNumResultCols +TEST_F(Result_Set, SQLNumResultCols) { + OdbcHandler odbcHandler; + RETCODE rcode; + string sql_state; + SQLSMALLINT num_cols; + + ASSERT_NO_FATAL_FAILURE(odbcHandler.ConnectAndExecQuery(SELECT_RESULT_SET_RO_TABLE1)); + + rcode = SQLNumResultCols(odbcHandler.GetStatementHandle(), &num_cols); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + ASSERT_EQ(num_cols, RO_TABLE_COLUMNS.size()); +} + +// Tests SQLCloseCursor +// DISABLED: PLEASE SEE BABELFISH-99 +TEST_F(Result_Set, DISABLED_SQLCloseCursor) { + OdbcHandler odbcHandler; + RETCODE rcode; + string sql_state; + SQLINTEGER id; + SQLLEN id_indicator; + + // setup + ASSERT_NO_FATAL_FAILURE(ConnectAndSetScrollable(&odbcHandler)); + ASSERT_NO_FATAL_FAILURE(odbcHandler.ExecQuery(SELECT_RESULT_SET_RO_TABLE1)); + + // Assert that it is unable the fetch after closing the cursor and that the correct sql state + // has been produced + rcode = SQLFetchScroll(odbcHandler.GetStatementHandle(), SQL_FETCH_ABSOLUTE, 1); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + rcode = SQLCloseCursor(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + rcode = SQLFetchScroll(odbcHandler.GetStatementHandle(), SQL_FETCH_ABSOLUTE, 2); + ASSERT_EQ(rcode, SQL_ERROR); + + sql_state = odbcHandler.GetSqlState(SQL_HANDLE_STMT, odbcHandler.GetStatementHandle()); + ASSERT_EQ(sql_state, "HY010"); +} + +// Test SQLDescribeCol +// DISABLED: PLEASE SEE BABELFISH-100 +TEST_F(Result_Set, DISABLED_SQLDescribeCol) { + OdbcHandler odbcHandler; + SQLCHAR col_name[256]; + SQLSMALLINT name_length; + SQLSMALLINT data_type; + SQLULEN col_size; + SQLSMALLINT dec_digits; + SQLSMALLINT nullable_ptr; + RETCODE rcode; + + // Setup + ASSERT_NO_FATAL_FAILURE(odbcHandler.ConnectAndExecQuery(SELECT_RESULT_SET_RO_TABLE1)); + rcode = SQLFetch(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + // The expected values would need to be updated if the RO_TABLE_COLUMNS change. + vector> expected_values = { + {"id", 2, SQL_INTEGER, 10, 0, SQL_NULLABLE}, + {"info", 4, SQL_VARCHAR, 256, 0, SQL_NO_NULLS}, + {"decivar", 7, SQL_NUMERIC, 38, 16, SQL_NULLABLE} + }; + + int ordinal {0}; + for (auto column_info : expected_values) { + ++ordinal; + rcode = SQLDescribeCol(odbcHandler.GetStatementHandle(), + ordinal, + col_name, + sizeof(col_name), + &name_length, + &data_type, + &col_size, + &dec_digits, + &nullable_ptr); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + auto& [name, name_len, sql_type, size, digits, nullable] = column_info; + EXPECT_EQ(string( (char*) col_name), name); + EXPECT_EQ(name_length, name_len); + EXPECT_EQ(data_type,sql_type ); + EXPECT_EQ(col_size, size); + EXPECT_EQ(dec_digits,digits); + EXPECT_EQ(nullable_ptr,nullable); + } +} + +TEST_F(Result_Set, SQLMoreResults_BatchedQueries) { + OdbcHandler odbcHandler; + RETCODE rcode; + SQLLEN id_indciator = 0; + string sql_state; + int id = 0; + + string batch_query = SelectStatement(RESULT_SET_RO_TABLE1, { "*" }, {}, "id = 1") + " ; " + + SelectStatement(RESULT_SET_RO_TABLE1, { "*" }, {}, "id = 2"); + + ASSERT_NO_FATAL_FAILURE(odbcHandler.Connect(true)); + + rcode = SQLPrepare(odbcHandler.GetStatementHandle(),(SQLCHAR*) batch_query.c_str(), SQL_NTS); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + rcode = SQLExecute(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + rcode = SQLFetch(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + rcode = SQLGetData(odbcHandler.GetStatementHandle(), 1, SQL_C_ULONG, &id, 0, 0); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + ASSERT_EQ(id, 1); + + rcode = SQLMoreResults(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + rcode = SQLFetch(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + rcode = SQLGetData(odbcHandler.GetStatementHandle(), 1, SQL_C_ULONG, &id, 0, 0); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + ASSERT_EQ(id, 2); + + rcode = SQLMoreResults(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_NO_DATA); +} diff --git a/contrib/test/odbc/test_sqlgetinfo.cpp b/contrib/test/odbc/test_sqlgetinfo.cpp new file mode 100644 index 00000000000..936783d8719 --- /dev/null +++ b/contrib/test/odbc/test_sqlgetinfo.cpp @@ -0,0 +1,146 @@ +#include "odbc_handler.h" +#include +#include + +static const int BUFFER = 255; + +class SQLGetInfoTest : public testing::Test{ + +}; + +// Sets up SQLGetInfo test whose option returns a character string +void SqlGetInfoTestSetupString(OdbcHandler &odbcHandler, SQLSMALLINT info_type, + char* output, SQLSMALLINT* str_length) { + + RETCODE rcode; + odbcHandler.Connect(); + + rcode = SQLGetInfo(odbcHandler.GetConnectionHandle(), info_type, output, BUFFER, str_length); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_DBC, rcode); +} + +// Sets up SQLGetInfo test whose option returns a integer +void SqlGetInfoTestSetupInteger(OdbcHandler &odbcHandler, SQLSMALLINT info_type, + SQLUINTEGER* output) { + + RETCODE rcode; + odbcHandler.Connect(); + + rcode = SQLGetInfo(odbcHandler.GetConnectionHandle(), info_type, output, sizeof(SQLINTEGER), 0); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_DBC, rcode); +} + +// Get the server name through a query +void GetServerName(char* servername) { + + RETCODE rcode; + OdbcHandler odbcHandler; + odbcHandler.ConnectAndExecQuery("SELECT @@SERVERNAME"); + rcode = SQLFetch(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + rcode = SQLGetData(odbcHandler.GetStatementHandle(), 1, SQL_C_CHAR, servername, BUFFER, 0); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); +} + +// Get the username through a query +void GetUserName(char* username) { + + RETCODE rcode; + OdbcHandler odbcHandler; + odbcHandler.ConnectAndExecQuery("SELECT CURRENT_USER"); + rcode = SQLFetch(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + rcode = SQLGetData(odbcHandler.GetStatementHandle(), 1, SQL_C_CHAR, username, BUFFER, 0); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); +} + +// Helper function to print out error messages for SQLGetInfoTests +string SqlGetInfoSupportError(string sqlgetinfo_option, string supported_feature) { + + return "SQLGetInfo with " + sqlgetinfo_option + " stated that it does not support " + + supported_feature + " when it should"; +} + +// Tests if SQLGetInfo retrieves the correct server name with SQL_SERVER_NAME option +// DISABLED: PLEASE SEE BABELFISH-125 +TEST_F(SQLGetInfoTest, DISABLED_SQLGetInfo_SQL_SERVER_NAME) { + + OdbcHandler odbcHandler; + char output[BUFFER]; + char expected[BUFFER]; + + ASSERT_NO_FATAL_FAILURE(GetServerName(expected)); + ASSERT_NO_FATAL_FAILURE(SqlGetInfoTestSetupString(odbcHandler, SQL_SERVER_NAME, output, 0)); + ASSERT_EQ(string(output), string(expected)); +} + +// Tests if SQLGetInfo retrieves the correct server name with SQL_USER_NAME option +// DISABLED: PLEASE SEE BABELFISH-126 +TEST_F(SQLGetInfoTest, DISABLED_SQLGetInfo_SQL_USER_NAME) { + + OdbcHandler odbcHandler; + char output[BUFFER]; + char expected[BUFFER]; + + ASSERT_NO_FATAL_FAILURE(GetUserName(expected)); + ASSERT_NO_FATAL_FAILURE(SqlGetInfoTestSetupString(odbcHandler, SQL_USER_NAME, output, 0)); + ASSERT_EQ(string(output), string(expected)); +} + +// Tests if SQLGetInfo retrieves the correct value for SQL_DATA_SOURCE_READ_ONLY +TEST_F(SQLGetInfoTest, SQLGetInfo_SQL_DATA_SOURCE_READ_ONLY) { + + OdbcHandler odbcHandler; + char output[BUFFER]; + string expected = "N"; //The BBF cluster used for test should not be read only + + ASSERT_NO_FATAL_FAILURE(SqlGetInfoTestSetupString(odbcHandler, SQL_DATA_SOURCE_READ_ONLY, output, 0)); + ASSERT_EQ(string(output), expected); +} + +// Tests if SQLGetInfo retrieves the correct values for SQL_CREATE_TABLE. +// NOTE: Assertions may need to be redefined based on BBF settings +TEST_F(SQLGetInfoTest, SQLGetInfo_SQL_CREATE_TABLE) { + OdbcHandler odbcHandler; + SQLUINTEGER output; + string sqlgetinfo_option = "SQL_CREATE_TABLE"; + ASSERT_NO_FATAL_FAILURE(SqlGetInfoTestSetupInteger(odbcHandler, SQL_CREATE_TABLE, &output)); + EXPECT_TRUE(output & SQL_CT_CREATE_TABLE) << SqlGetInfoSupportError(sqlgetinfo_option, "SQL_CT_CREATE_TABLE"); +} + +// Tests if SQLGetInfo retrieves the correct values for SQL_DROP_TABLE. +// NOTE: Assertions may need to be redefined based on BBF settings +TEST_F(SQLGetInfoTest, SQLGetInfo_SQL_DROP_TABLE) { + OdbcHandler odbcHandler; + SQLUINTEGER output = 0; + string sqlgetinfo_option = "SQL_DROP_TABLE"; + ASSERT_NO_FATAL_FAILURE(SqlGetInfoTestSetupInteger(odbcHandler, SQL_DROP_TABLE, &output)); + EXPECT_TRUE(output & SQL_DT_DROP_TABLE) << SqlGetInfoSupportError(sqlgetinfo_option, "SQL_DT_DROP_TABLE"); +} + +// Tests if SQLGetInfo retrieves the correct values for SQL_ALTER_TABLE. +// NOTE: Assertions may need to be redefined based on BBF settings +TEST_F(SQLGetInfoTest, SQLGetInfo_SQL_ALTER_TABLE) { + OdbcHandler odbcHandler; + SQLUINTEGER output = 0; + string sqlgetinfo_option = "SQL_ALTER_TABLE"; + ASSERT_NO_FATAL_FAILURE(SqlGetInfoTestSetupInteger(odbcHandler, SQL_ALTER_TABLE, &output)); + EXPECT_TRUE(output & SQL_AT_CONSTRAINT_NAME_DEFINITION) << SqlGetInfoSupportError(sqlgetinfo_option, "SQL_AT_CONSTRAINT_NAME_DEFINITION"); + EXPECT_TRUE(output & SQL_AT_ADD_COLUMN_SINGLE) << SqlGetInfoSupportError(sqlgetinfo_option, "SQL_AT_ADD_COLUMN_SINGLE"); + EXPECT_TRUE(output & SQL_AT_ADD_CONSTRAINT) << SqlGetInfoSupportError(sqlgetinfo_option, "SQL_AT_ADD_CONSTRAINT"); + EXPECT_TRUE(output & SQL_AT_ADD_TABLE_CONSTRAINT) << SqlGetInfoSupportError(sqlgetinfo_option, "SQL_AT_ADD_TABLE_CONSTRAINT"); + EXPECT_TRUE(output & SQL_AT_CONSTRAINT_NAME_DEFINITION) << SqlGetInfoSupportError(sqlgetinfo_option, "SQL_AT_CONSTRAINT_NAME_DEFINITION"); +} + +// Tests if SQLGetInfo retrieves the correct values for SQL_INSERT_STATEMENT. +// NOTE: Assertions may need to be redefined based on BBF settings +TEST_F(SQLGetInfoTest, SQLGetInfo_SQL_INSERT_STATEMENT) { + + OdbcHandler odbcHandler; + SQLUINTEGER output = 0; + string sqlgetinfo_option = "SQL_INSERT_STATEMENT"; + ASSERT_NO_FATAL_FAILURE(SqlGetInfoTestSetupInteger(odbcHandler, SQL_INSERT_STATEMENT, &output)); + EXPECT_TRUE(output & SQL_IS_INSERT_LITERALS) << SqlGetInfoSupportError(sqlgetinfo_option, "SQL_IS_INSERT_LITERALS"); + EXPECT_TRUE(output & SQL_IS_INSERT_SEARCHED) << SqlGetInfoSupportError(sqlgetinfo_option, "SQL_IS_INSERT_SEARCHED"); + EXPECT_TRUE(output & SQL_IS_SELECT_INTO) << SqlGetInfoSupportError(sqlgetinfo_option, "SQL_IS_SELECT_INTO"); +} diff --git a/contrib/test/odbc/test_transactions.cpp b/contrib/test/odbc/test_transactions.cpp new file mode 100644 index 00000000000..367bd0be52b --- /dev/null +++ b/contrib/test/odbc/test_transactions.cpp @@ -0,0 +1,129 @@ +#include "odbc_handler.h" +#include "database_objects.h" +#include "query_generator.h" +#include +#include + +class Transactions : public testing::Test { + + protected: + + static void SetUpTestSuite() { + } + + static void TearDownTestSuite() { + } +}; + +// Complete a transaction and assert that the values were correctly inserted +// DISABLED: Please see BABELFISH-113 +TEST_F(Transactions, DISABLED_SQLEndTran_Commit) { + OdbcHandler odbcHandler; + RETCODE rcode; + string query{}; + + const string TEST_TABLE = "TRANSACTION_TABLE_W_1"; + const string ID_COL = "id"; + + DatabaseObjects dbObjects; + ASSERT_NO_FATAL_FAILURE(dbObjects.CreateTable(TEST_TABLE, {{ID_COL, "INT"}})); + + ASSERT_NO_FATAL_FAILURE(odbcHandler.Connect()); + + // Disable autocommit + rcode = SQLSetConnectAttr(odbcHandler.GetConnectionHandle(), SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF, SQL_IS_UINTEGER); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_DBC, rcode); + + ASSERT_NO_FATAL_FAILURE(odbcHandler.AllocateStmtHandle()); + ASSERT_NO_FATAL_FAILURE(odbcHandler.ExecQuery(InsertStatement(TEST_TABLE, "(1)"))); + ASSERT_NO_FATAL_FAILURE(odbcHandler.ExecQuery(InsertStatement(TEST_TABLE, "(2)"))); + + // Commit the transaction + rcode = SQLEndTran(SQL_HANDLE_DBC, odbcHandler.GetConnectionHandle(), SQL_COMMIT); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_DBC, rcode); + + ASSERT_NO_FATAL_FAILURE(odbcHandler.ExecQuery(SelectStatement(TEST_TABLE, { "*" }, {ID_COL}))); // order by id + + rcode = SQLFetch(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + int col_num = 1; + int buf; + rcode = SQLGetData(odbcHandler.GetStatementHandle(), col_num, SQL_C_ULONG, &buf, 0, nullptr); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + ASSERT_EQ(buf, 1); + + rcode = SQLFetch(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + + rcode = SQLGetData(odbcHandler.GetStatementHandle(), col_num, SQL_C_ULONG, &buf, 0, nullptr); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_STMT, rcode); + ASSERT_EQ(buf, 2); +} + +// Rollbacks back the transaction and assert that nothing was created +// DISABLED: Please see BABELFISH-113 +TEST_F(Transactions, DISABLED_SQLEndTran_Rollback) { + OdbcHandler odbcHandler; + RETCODE rcode; + + const string TEST_TABLE = "TRANSACTION_TABLE_RO_1"; + + DatabaseObjects dbObjects; + ASSERT_NO_FATAL_FAILURE(dbObjects.CreateTable(TEST_TABLE, {{"id", "INT"}})); + + ASSERT_NO_FATAL_FAILURE(odbcHandler.Connect()); + + // Disable autocommit + rcode = SQLSetConnectAttr(odbcHandler.GetConnectionHandle(), SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF, SQL_IS_UINTEGER); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_DBC, rcode); + + ASSERT_NO_FATAL_FAILURE(odbcHandler.AllocateStmtHandle()); + ASSERT_NO_FATAL_FAILURE(odbcHandler.ExecQuery(InsertStatement(TEST_TABLE, "(1)"))); + + // Rollback the transaction + rcode = SQLEndTran(SQL_HANDLE_DBC, odbcHandler.GetConnectionHandle(), SQL_ROLLBACK); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_DBC, rcode); + + ASSERT_NO_FATAL_FAILURE(odbcHandler.ExecQuery(SelectStatement(TEST_TABLE, { "*" }))); + + rcode = SQLFetch(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_NO_DATA); +} + +// Attempt to disconnect during a transaction +// DISABLED: Please see BABELFISH-113 +TEST_F(Transactions, DISABLED_SQL_DisconnectAttemptDuringTransaction) { + OdbcHandler odbcHandler; + RETCODE rcode; + string sql_state; + + const string TEST_TABLE = "TRANSACTION_TABLE_RO_2"; + + DatabaseObjects dbObjects; + ASSERT_NO_FATAL_FAILURE(dbObjects.CreateTable(TEST_TABLE, {{"id", "INT"}})); + + ASSERT_NO_FATAL_FAILURE(odbcHandler.Connect()); + + // Disable autocommit + rcode = SQLSetConnectAttr(odbcHandler.GetConnectionHandle(), SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF, SQL_IS_UINTEGER); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_DBC, rcode); + + ASSERT_NO_FATAL_FAILURE(odbcHandler.AllocateStmtHandle()); + ASSERT_NO_FATAL_FAILURE(odbcHandler.ExecQuery(InsertStatement(TEST_TABLE, "(1)"))); + + rcode = SQLDisconnect(odbcHandler.GetConnectionHandle()); + ASSERT_EQ(rcode, SQL_ERROR); + + sql_state = odbcHandler.GetSqlState(SQL_HANDLE_DBC, odbcHandler.GetConnectionHandle()); + ASSERT_EQ(sql_state, "25000"); + + // Rollback transaction + rcode = SQLEndTran(SQL_HANDLE_DBC, odbcHandler.GetConnectionHandle(), SQL_ROLLBACK); + ASSERT_EQ(rcode, SQL_SUCCESS) << odbcHandler.GetErrorMessage(SQL_HANDLE_DBC, rcode); + + ASSERT_NO_FATAL_FAILURE(odbcHandler.ExecQuery(SelectStatement(TEST_TABLE, { "*" }))); + + rcode = SQLFetch(odbcHandler.GetStatementHandle()); + ASSERT_EQ(rcode, SQL_NO_DATA); +} diff --git a/contrib/test/odbc/utils/blank.txt b/contrib/test/odbc/utils/blank.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/contrib/test/odbc/utils/devanagari.txt b/contrib/test/odbc/utils/devanagari.txt new file mode 100644 index 00000000000..45f37b695da --- /dev/null +++ b/contrib/test/odbc/utils/devanagari.txt @@ -0,0 +1 @@ +ऀँंःऄअआइईउऊऋऌऍऎएऐऑऒओऔकखगघङचछजझञटठडढणतथदधनऩपफबभमयरऱलळऴवशषसहऺऻ़ऽािीुूृॄॅॆेैॉॊोौ्ॎॏॐ॒॑॓॔ॕॖॗक़ख़ग़ज़ड़ढ़फ़य़ॠॡॢॣ।॥०१२३४५६७८९॰ॱॲॳॴॵॶॷॹॺॻॼॽॾॿ \ No newline at end of file diff --git a/contrib/test/odbc/utils/sample.txt b/contrib/test/odbc/utils/sample.txt new file mode 100644 index 00000000000..352a3fb9297 --- /dev/null +++ b/contrib/test/odbc/utils/sample.txt @@ -0,0 +1,6 @@ +AAAAAAAAAAAAAAAAAAAA +BBBBBBBBBB +CCCCC +badksjvbajsdcbvjads +sejvhsdbfjhcgvasdhgcvsj +21639812365091264 \ No newline at end of file diff --git a/contrib/test/python/batch_run.py b/contrib/test/python/batch_run.py new file mode 100644 index 00000000000..fe3b47a36c3 --- /dev/null +++ b/contrib/test/python/batch_run.py @@ -0,0 +1,94 @@ +from execute_query import parse_prepared_statement, parse_stored_procedures, process_transaction_statement,process_statement_in_file_mode +from python_authentication import py_authentication +import os + + +#categorise statements based on prefixes and accordingly process them +def batch_run(bbl_cnxn, file_handler, file, logger): + passed = 0 + failed = 0 + + filename = file.name + f_type = filename.split(".")[1] + + + if f_type == "sql": + with open(file, "r") as f: + + sqlbatch = "" + + line = f.readline() + while line: + line = line.replace("\n", "") + #ignore empty lines + if len(line) < 1: + line = f.readline() + continue + else: + if line.lower() == "go" or line.lower() == "go;": + flag = True + flag = process_statement_in_file_mode(bbl_cnxn, file_handler, sqlbatch, True) + + if flag: + passed += 1 + else: + failed += 1 + + sqlbatch = "" + else: + sqlbatch += line + os.linesep + line = f.readline() + + elif f_type == "txt": + + with open(file,"r") as f: + lines = f.readlines() + + lines = [line.replace("\n", "") for line in lines] + + prep_statement = None + trans_list = [] + for line in lines: + flag = True + #commented line or empty + if line.startswith("#") or len(line) < 1: + file_handler.write(line) + file_handler.write("\n") + continue + + #run auth_test + elif line.startswith("py_auth"): + flag = py_authentication(file_handler, line, logger) + + #run prepared_statements + elif line.startswith("prepst"): + flag,prep_statement = parse_prepared_statement(bbl_cnxn, file_handler, line, prep_statement, logger) + + #run stored procedure + elif line.startswith("storedproc"): + flag = parse_stored_procedures(bbl_cnxn, file_handler, line, logger) + + #run the transaction statements + elif line.startswith("txn"): + flag,trans_list = process_transaction_statement(bbl_cnxn, line, trans_list, file_handler, logger) + + # skip cursor operations + elif line.startswith("cursor"): + flag = True + logger.info("Skipping statement " + line + " as cursor operations are not supported currently by pyodbc/pymssql") + + # run as normal sql statement + else: + flag= process_statement_in_file_mode(bbl_cnxn, file_handler, line, False) + + if flag: + passed += 1 + else: + failed += 1 + + return (passed, failed) + + + + + diff --git a/contrib/test/python/compare_results.py b/contrib/test/python/compare_results.py new file mode 100644 index 00000000000..687b67db2db --- /dev/null +++ b/contrib/test/python/compare_results.py @@ -0,0 +1,139 @@ +#compare result sets using simple assertions + +import re +import pymssql +import pyodbc +from utils.config import config_dict as cfg + + +#function to write output of sql query to a file +def write_results_to_file(file_writer, bbl_data, bbl_rs): + try: + file_writer.write("~~START~~") + file_writer.write("\n") + + metadata = bbl_rs.description + columns = len(metadata) + + if cfg["outputColumnName"] == "true": + for i in range(columns): + file_writer.write(metadata[i][0]) + if i != (columns -1): + file_writer.write("#!#") + + file_writer.write("\n") + + + for i in range(columns): + if cfg["driver"] == "pyodbc": + file_writer.write(metadata[i][1].__name__) + elif cfg["driver"] == "pymssql": + file_writer.write(type(metadata[i][1]).__name__) + + if i != (columns - 1): + file_writer.write("#!#") + + file_writer.write("\n") + + for i in range(len(bbl_data)): + for j in range(columns): + if bbl_data[i][j] is None: + file_writer.write("") + else: + str_data = str(bbl_data[i][j]) + str_data = re.sub("[\r\n]+", "",str_data) + file_writer.write(str_data) + + if j != (columns - 1): + file_writer.write("#!#") + + file_writer.write("\n") + + file_writer.write("~~END~~") + file_writer.write("\n") + file_writer.write("\n") + + + except (IOError, OSError) as e: + print(str(e)) + + except Exception as e: + handle_exception_in_file(e, file_writer) + +#function to handle exception +def handle_exception_in_file(e, file_writer): + try: + if cfg["outputErrorCode"] == "true": + if issubclass(type(e), pyodbc.Error): + code = re.findall(r"\(\d+\)", e.args[1]) + if len(code) > 0: + ecode = code[0][1:-1] + file_writer.write("~~ERROR (Code: " + str(ecode) + ")~~") + file_writer.write("\n") + + file_writer.write("~~ERROR (Message: "+ e.args[1] + ")~~") + + elif issubclass(type(e), pymssql.Error): + + file_writer.write("~~ERROR (Code: " + str(e.args[0]) + ")~~") + file_writer.write("\n") + file_writer.write("~~ERROR (Message: " + repr(str(e.args[1].decode())) + ")~~") + + file_writer.write("\n") + file_writer.write("\n") + else: + file_writer.write("~~ERROR~~") + file_writer.write("\n") + file_writer.write("\n") + + except Exception as err: + print(str(err)) + +#processes all the result sets sequentially that we get from executing a sql query +def process_multiple_resultsets(bbl_rs, file_writer, result_processed, result_set_exist): + #not possible initial value + count = -10 + + while True: + + exception_raised = True + + while exception_raised: + try: + if result_processed > 0: + result_set_exist = bbl_rs.nextset() + + exception_raised = False + count = bbl_rs.rowcount + + except Exception as e: + handle_exception_in_file(e, file_writer) + + result_processed += 1 + + + if not result_set_exist and count == -1 and cfg["driver"] == "pyodbc": + break + + + if result_set_exist: + try: + bbl_data = bbl_rs.fetchall() + write_results_to_file(file_writer, bbl_data, bbl_rs) + except Exception as e: + handle_exception_in_file(e, file_writer) + else: + if count > 0: + try: + file_writer.write("~~ROW COUNT: " + str(count) + "~~") + file_writer.write("\n") + file_writer.write("\n") + except Exception as e: + print(str(e)) + + if not result_set_exist and cfg["driver"] == "pymssql": + break + + + + diff --git a/contrib/test/python/config.txt b/contrib/test/python/config.txt new file mode 100644 index 00000000000..d511f1de593 --- /dev/null +++ b/contrib/test/python/config.txt @@ -0,0 +1,44 @@ +# SET THIS CONNECTION STRING TO GENERATE THE EXPECTED OUTPUT FILE +fileGenerator_URL = +fileGenerator_port = +fileGenerator_databaseName = +fileGenerator_user = +fileGenerator_password = + +# PATH TO INPUT TEST FILES FOLDER +inputFilesPath = ./input + +# SPECIFY IF YOU WISH TO EXECUTE TEST FILES SEQUENTIALLY OR IN PARALLEL +runInParallel = false + +# SPECIFY IF YOU WISH TO PRINT ALL THE LOGS/DIFF TO CONSOLE +printLogsToConsole = true + +# SPECIFY WHICH JDBC DRIVER TO USE. CHOOSE FROM "pyodbc" OR "pymssql" +driver = pyodbc + +provider = ODBC Driver 17 for SQL Server + +# SPECIFY IF YOU WANT TO GENERATE A PERFORMANCE REPORT +performanceTest = false + + +# TO OVERCOME CERTAIN LIMITATIONS OF BABELFISH, INTRODUCED THE FOLLOWING 2 FLAGS +# SET THESE FLAGS TO "false" WHILE GENERATING OUTPUT FILES YOU WISH TO CHECK INSIDE +# THE "expected" FOLDER. THESE FLAGS ARE ONLY THERE FOR PURPOSE OF DEBUGGING + +# BABEL-415 AND BABEL-681 +# SPECIFY IF COLUMN NAMES SHOULD BE ACCOMPANYING RESULT SETS IN OUTPUT FILE +outputColumnName = false + +# BABEL-780 AND BABEL-1012 +# SPECIFY IF ERROR CODE SHOULD BE DISPLAYED IN OUTPUT FILE +outputErrorCode = true + +############################################ WHICH TEST TO RUN ############################################ + +# SET AS "all" TO RUN ALL THE TESTS FOR THE INPUT FILES INSIDE DIRECTORY WHOSE PATH IS SPECIFIED BY +# "inputFilesPath" OR SET AS THE NAME OF THE QUERY FILE YOU WANT TO TEST/CREATE EXPECTED OUTCOME FOR +# MULTIPLE INPUT TETS FILE NAMES CAN BE GIVEN SEPARATED WITH A SEMICOLON AND NO SPACES +testName = all + diff --git a/contrib/test/python/execute_query.py b/contrib/test/python/execute_query.py new file mode 100644 index 00000000000..76c0d8eba42 --- /dev/null +++ b/contrib/test/python/execute_query.py @@ -0,0 +1,376 @@ +import re +import pyodbc +from compare_results import handle_exception_in_file, process_multiple_resultsets +from datetime import date, datetime, time +from decimal import Decimal +from uuid import UUID +from xml.dom.minidom import parseString +from utils.config import config_dict as cfg +from utils.base import handle_babel_exception + +#based on the keyword process the given prefixes set or simply execute the prepared statements +def parse_prepared_statement(bbl_cnxn, file_writer, query, prep_statement, logger): + + + if cfg["driver"] == "pyodbc": + query = re.sub(r"@[a-zA-Z0-9]+", "?", query) + elif cfg["driver"] == "pymssql": + query = re.sub(r"@[a-zA-Z0-9]+", "%s", query) + + result = query.split("#!#") + + keyword = result[1] + + #use already initialised prepared statement + if keyword.startswith("exec"): + params = [] + + for i in range(2, len(result)): + params.append(result[i]) + if i < len(result) - 1: + params.append(", ") + + logger.info("Executing prepared statement " + repr(prep_statement) + " with the following bind variables: " + "".join(params)) + + flag = process_prepared_statement_in_file_mode(bbl_cnxn, file_writer, query, prep_statement, result, logger) + + elif not keyword.startswith("exec"): + prep_statement = result[1] + logger.info("Preparing the query: " + repr(prep_statement)) + + params = [] + + for i in range(2, len(result)): + params.append(result[i]) + if i < len(result) - 1: + params.append(", ") + + logger.info("Executing with the bind variables " + "".join(params)) + + flag = process_prepared_statement_in_file_mode(bbl_cnxn, file_writer, query, prep_statement, result, logger) + + return (flag, prep_statement) + +#TODO add more data types +# parse the prefixes and return tuple of bind values +def set_bind_values(result, logger): + inttype = ["int", "smallint", "tinyint", "bigint"] + floattype = ["real", "float"] + bytestype = ["binary", "varbinary"] + strtype = ["string", "char", "nchar", "varchar", "nvarchar"] + booltype = ["boolean", "bit"] + datetype = ["date"] + datetimetype = ["datetime", "datetime2", "smalldatetime"] + decimaltype = ["decimal", "numeric", "money", "smallmoney"] + uuidtype = ["uniqueidentifier"] + timetype = ["time"] + xmltype = ["xml"] + texttype = ["text", "ntext"] + + lst = [] + + + if result[0] == "storedproc": + start=3 + elif result[0] == "prepst": + start=2 + + for i in range(start, len(result)): + params = result[i].split("|-|") + if len(params) < 2: + continue + try: + if "" in params[2]: + lst.append(None) + elif params[0].lower() in floattype: + lst.append(float(params[2])) + elif params[0].lower() in inttype: + if "." in params[2]: + lst.append(int(float(params[2]))) + else: + lst.append(int(params[2])) + elif params[0].lower() in bytestype: + lst.append(params[2].encode()) + elif params[0].lower() in strtype: + lst.append(str(params[2])) + elif params[0].lower() in booltype: + if "false" in params[2].lower(): + lst.append(False) + else: + lst.append(True) + elif params[0].lower() in datetype: + lst.append(date.fromisoformat(params[2].strip())) + elif params[0].lower() in datetimetype: + try: + lst.append(datetime.strptime(params[2].strip(), "%Y-%m-%d %H:%M:%S.%f")) + except ValueError as e: + lst.append(datetime.strptime(params[2].strip(), "%Y-%m-%d %H:%M:%S")) + elif params[0].lower() in decimaltype: + lst.append(Decimal(params[2].replace("$", "").replace(",", "").strip())) + elif params[0].lower() in uuidtype: + lst.append(UUID(params[2].strip())) + elif params[0].lower() in timetype: + dt_obj = datetime.strptime(params[2].strip(), "%H:%M:%S.%f") + time_obj = time(hour = dt_obj.hour, minute = dt_obj.minute, second = dt_obj.second, microsecond = dt_obj.microsecond) + lst.append(time_obj) + elif params[0].lower() in xmltype: + dom = parseString(params[2].strip()) + lst.append(dom.toxml()) + elif params[0].lower() in texttype: + with open(params[2].strip(), "r") as f: + data = f.read() + lst.append(data) + + else: + raise Exception("Data type " + params[0] + " is not supportted currently") + except Exception as e: + logger.error(str(e)) + + return tuple(lst) + +#function to parse the prefixes and ignore the cases that are not supported +def parse_stored_procedures(bbl_cnxn, file_writer, query, logger): + flag = True + + result=query.split("#!#") + + lst=["output", "inputoutput", "return"] + #skipping cases as not supported by pyodbc/pymssql yet + if any(word in query for word in lst): + logger.info("Skipping statement " + repr(query) + " as out/inout/return parameters are not supported currently by pyodbc") + return True + + bindparam = "" + + for i in range(0, len(result)-3): + if i != len(result)-4: + bindparam+="?," + else: + bindparam+="?" + + values = set_bind_values(result, logger) + + if len(values)<1: + stored_proc = "exec " + result[2] + else: + stored_proc = "exec " + result[2]+ " " + bindparam + + logger.info("Executing stored procedure " + repr(stored_proc) + " with the following input parameters: " + str(values)) + flag = process_stored_procedure_in_file_mode(bbl_cnxn, file_writer, query, stored_proc, values) + + return flag + +#function to begin,rollback,commit transactions , set savepoints +def process_transaction_statement(bbl_cnxn, query, trans_list,file_writer, logger): + flag = True + result = query.split("#!#") + + #begin transaction + if result[1].startswith("begin"): + logger.info("Beginning Transaction") + + #if the statement has isolation prefixes as well + if len(result) > 2: + #isolation prefixes only supported in pyodbc + if result[2].startswith("isolation") and cfg["driver"] == "pyodbc": + #append name to transaction list if given in the statement + if len(result) > 4: + tran_name = result[4] + trans_list.append(tran_name) + + #if-elif ladder to set the transaction isolation level + if result[3] == "ru": + logger.info("Transaction isolation level set to TRANSACTION_READ_UNCOMMITTED") + + try: + bbl_cnxn.set_isolation(pyodbc.SQL_TXN_READ_UNCOMMITTED) + except Exception as e: + handle_babel_exception(e, logger) + + elif result[3] == "rc": + logger.info("Transaction isolation level set to SQL_TXN_READ_COMMITTED") + + try: + bbl_cnxn.set_isolation( pyodbc.SQL_TXN_READ_COMMITTED) + except Exception as e: + handle_babel_exception(e, logger) + + elif result[3] == "rr": + logger.info("Transaction isolation level set to SQL_TXN_REPEATABLE_READ") + + try: + bbl_cnxn.set_isolation( pyodbc.SQL_TXN_REPEATABLE_READ) + except Exception as e: + handle_babel_exception(e, logger) + + elif result[3] == "se": + logger.info("Transaction isolation level set to SQL_TXN_SERIALIZABLE") + + try: + bbl_cnxn.set_isolation(pyodbc.SQL_TXN_SERIALIZABLE) + except Exception as e: + handle_babel_exception(e, logger) + + #use sqlbatch to set snapshot isolation as not supported by pyodbc + elif result[3] == "ss": + logger.info("Transaction isolation level set to Snapshot") + flag = process_statement_in_file_mode(bbl_cnxn, file_writer, "SET TRANSACTION ISOLATION LEVEL SNAPSHOT", False) + #if no isolation prefix add the transaction name to the list + else: + trans_list.append(result[2]) + + #set autocommit to false to start the transaction + try: + bbl_cnxn.set_autocommit(False) + except Exception as e: + handle_exception_in_file(e, file_writer) + + #commit transaction + elif result[1].startswith("commit"): + logger.info("Committing transaction") + + #if the transaction list not empty pop the first element + if len(trans_list) > 0: + trans_list.pop() + + try: + bbl_cnxn.commit() + bbl_cnxn.set_autocommit(True) + except Exception as e: + handle_exception_in_file(e, file_writer) + + #rollback transaction + elif result[1].startswith("rollback"): + #if the rollback statement exist with transaction name or simply without any name + if len(result) < 3 or result[2] in trans_list: + + logger.info("Rolling back the transaction") + #try to pop the transaction name from the list if it exist in the list + try: + if result[2] in trans_list: + trans_list.pop() + except: + pass + + try: + bbl_cnxn.rollback() + bbl_cnxn.set_autocommit(True) + except Exception as e: + handle_exception_in_file(e, file_writer) + + #else rollback to savepoint + else: + + logger.info("Rolling back to savepoint" + result[2]) + #using sql batch as the pyodbc/pymssql doesnt have methods for rolling back to savepoint + flag = process_statement_in_file_mode(bbl_cnxn, file_writer, "rollback tran " + result[2], False) + + elif result[1].startswith("savepoint"): + #using sql batch as the pyodbc/pymssql doesnt have methods for setting savepoint + flag = process_statement_in_file_mode(bbl_cnxn, file_writer, "save tran " + result[2], False) + + return (flag, trans_list) + +#function to generate output files for sqlbatch statements +def process_statement_in_file_mode(bbl_cnxn, file_writer, query, is_sql_batch): + try: + + #different formatting for sqlbatch and single sql statement + if is_sql_batch: + file_writer.write(query) + file_writer.write("GO") + file_writer.write("\n") + else: + file_writer.write(query) + file_writer.write("\n") + + result_set_exist = True + result_processed = 0 + + try: + bbl_cursor = bbl_cnxn.get_cursor() + bbl_cursor.execute(query) + result_set_exist = bbl_cursor.description + except Exception as e: + handle_exception_in_file(e, file_writer) + result_processed += 1 + + process_multiple_resultsets(bbl_cursor, file_writer, result_processed, result_set_exist) + + try: + bbl_cursor.close() + except Exception as e: + print(str(e)) + + except Exception as e: + + print(str(e)) + + return True + +#function to generate output files for prepared statements +def process_prepared_statement_in_file_mode(bbl_cnxn, file_writer, query, prep_statement, result, logger): + try: + + file_writer.write(query) + file_writer.write("\n") + + values=set_bind_values(result, logger) + + result_set_exist = True + result_processed = 0 + + try: + bbl_cursor = bbl_cnxn.get_cursor() + bbl_cursor.execute(prep_statement, values) + result_set_exist = bbl_cursor.description + + except Exception as e: + handle_exception_in_file(e, file_writer) + result_processed += 1 + + process_multiple_resultsets(bbl_cursor, file_writer, result_processed, result_set_exist) + + try: + bbl_cursor.close() + except Exception as e: + print(str(e)) + + + except Exception as e: + print(str(e)) + + return True + +#function to generate output files for stored procedures +def process_stored_procedure_in_file_mode(bbl_cnxn, file_writer, query, stored_proc, values): + try: + + file_writer.write(query) + file_writer.write("\n") + + result_set_exist = True + result_processed = 0 + + try: + bbl_cursor = bbl_cnxn.get_cursor() + bbl_cursor.execute(stored_proc, values) + result_set_exist = bbl_cursor.description + + except Exception as e: + handle_exception_in_file(e, file_writer) + result_processed += 1 + + process_multiple_resultsets(bbl_cursor, file_writer, result_processed, result_set_exist) + + try: + bbl_cursor.close() + except Exception as e: + print(str(e)) + + except Exception as e: + print(str(e)) + + return True + + \ No newline at end of file diff --git a/contrib/test/python/expected/pymssql/BABEL-1056.out b/contrib/test/python/expected/pymssql/BABEL-1056.out new file mode 100644 index 00000000000..1f59f7adc82 --- /dev/null +++ b/contrib/test/python/expected/pymssql/BABEL-1056.out @@ -0,0 +1,23 @@ +CREATE SCHEMA [Babelfish_1056]; + +CREATE TABLE [Babelfish_1056].[employees] (person_id int IDENTITY PRIMARY KEY, firstname nvarchar(20), lastname nvarchar(30), salary money) +CREATE PROCEDURE p_employee_insert @fname nvarchar(20), @lname nvarchar(30), @sal money AS BEGIN DECLARE @next_pers_id INT; SELECT @next_pers_id = MAX(person_id) FROM [Babelfish_1056].[employees]; IF (@next_pers_id IS NULL) SET @next_pers_id = 0 INSERT INTO [Babelfish_1056].[employees] (person_id, firstname, lastname, salary) VALUES (@next_pers_id+1, @fname, @lname, @sal); END + +SET IDENTITY_INSERT [Babelfish_1056].[employees] ON EXEC p_employee_insert @fname='First', @lname='Employee', @sal=123.1231; SET IDENTITY_INSERT [Babelfish_1056].[employees] OFF +SET IDENTITY_INSERT [Babelfish_1056].[employees] ON EXEC p_employee_insert @fname='Second', @lname='Employee', @sal=123.1232; SET IDENTITY_INSERT [Babelfish_1056].[employees] OFF +SET IDENTITY_INSERT [Babelfish_1056].[employees] ON EXEC p_employee_insert @fname='Third', @lname='Employee', @sal=123.1233; SET IDENTITY_INSERT [Babelfish_1056].[employees] OFF + +SELECT * FROM [Babelfish_1056].[employees] +~~START~~ +int#!#int#!#int#!#int +1#!#First#!#Employee#!#123.1231 +2#!#Second#!#Employee#!#123.1232 +3#!#Third#!#Employee#!#123.1233 +~~END~~ + +~~ROW COUNT: 3~~ + + +DROP PROCEDURE p_employee_insert +DROP TABLE [Babelfish_1056].[employees] +DROP SCHEMA [Babelfish_1056]; diff --git a/contrib/test/python/expected/pymssql/BABEL-1270.out b/contrib/test/python/expected/pymssql/BABEL-1270.out new file mode 100644 index 00000000000..f96d478661e --- /dev/null +++ b/contrib/test/python/expected/pymssql/BABEL-1270.out @@ -0,0 +1,14 @@ +CREATE TABLE test_cursors_fetch_next(a INT, b SMALLINT, c BIGINT, d TINYINT, e BIT); +INSERT INTO test_cursors_fetch_next values(0, 0, 0, 0, 0) +~~ROW COUNT: 1~~ + +INSERT INTO test_cursors_fetch_next values(NULL, NULL, NULL, NULL, NULL) +~~ROW COUNT: 1~~ + +INSERT INTO test_cursors_fetch_next values(1, 2, 3, 4, 1) +~~ROW COUNT: 1~~ + +INSERT INTO test_cursors_fetch_next values(211234, 9780, 891372401, 56, 1) +~~ROW COUNT: 1~~ + +DROP TABLE test_cursors_fetch_next diff --git a/contrib/test/python/expected/pymssql/BABEL-1365.out b/contrib/test/python/expected/pymssql/BABEL-1365.out new file mode 100644 index 00000000000..7ba24095755 --- /dev/null +++ b/contrib/test/python/expected/pymssql/BABEL-1365.out @@ -0,0 +1,52 @@ +-- Test normal case: @v = SP_EXECUTESQL 'SQL' +DECLARE @SQLString NVARCHAR(100); +DECLARE @P0 int; +set @SQLString = N'SELECT 123;' +EXEC @P0 = sp_executesql @SQLString; +SELECT @P0; +GO +~~START~~ +int +123 +~~END~~ + +~~START~~ +int +0 +~~END~~ + +~~ROW COUNT: 1~~ + +-- Test case: @v = SP_EXECUTESQL 'SQL' where @v is implicitly casted to varchar +DECLARE @SQLString NVARCHAR(100); +DECLARE @P0 varchar(3); +set @SQLString = N'SELECT 321;' +EXEC @P0 = sp_executesql @SQLString; +SELECT @P0; +GO +~~START~~ +int +321 +~~END~~ + +~~START~~ +int +0 +~~END~~ + +~~ROW COUNT: 1~~ + +-- Test case: @v = SP_EXECUTESQL 'SQL' where 'SQL' statement does not return result set +DECLARE @SQLString NVARCHAR(100); +DECLARE @P0 int; +set @SQLString = N'CREATE TABLE t(a INT); DROP TABLE t;'; +EXEC @P0 = sp_executesql @SQLString; +SELECT @P0; +GO +~~START~~ +int +0 +~~END~~ + +~~ROW COUNT: 1~~ + diff --git a/contrib/test/python/expected/pymssql/BABEL-1390.out b/contrib/test/python/expected/pymssql/BABEL-1390.out new file mode 100644 index 00000000000..0331af05f7d --- /dev/null +++ b/contrib/test/python/expected/pymssql/BABEL-1390.out @@ -0,0 +1,25 @@ +# Setup a table with some data +CREATE TABLE updatable_cursor_table(a INT, b SMALLINT, c BIGINT, d TINYINT, e BIT); +INSERT INTO updatable_cursor_table values(0, 0, 0, 0, 0) +~~ROW COUNT: 1~~ + +INSERT INTO updatable_cursor_table values(NULL, NULL, NULL, NULL, NULL) +~~ROW COUNT: 1~~ + +INSERT INTO updatable_cursor_table values(1, 2, 3, 4, 1) +~~ROW COUNT: 1~~ + +INSERT INTO updatable_cursor_table values(211234, 9780, 891372401, 56, 1) +~~ROW COUNT: 1~~ + + +# Try opening an updatable cursor using JDBC API + +# Try opening an updatable (i.e. dynamic) cursor using SQL Batch +DECLARE updatable_cursor CURSOR DYNAMIC FOR SELECT a FROM updatable_cursor_table; OPEN updatable_cursor; CLOSE updatable_cursor; DEALLOCATE updatable_cursor; +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: "'DYNAMIC CURSOR' is not currently supported in BabelfishDB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n")~~ + + +# Drop table +DROP TABLE updatable_cursor_table diff --git a/contrib/test/python/expected/pymssql/BABEL-1643.out b/contrib/test/python/expected/pymssql/BABEL-1643.out new file mode 100644 index 00000000000..fadc57058b1 --- /dev/null +++ b/contrib/test/python/expected/pymssql/BABEL-1643.out @@ -0,0 +1,18 @@ +exec sp_datatype_info_100 @data_type = 1; +~~START~~ +int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int +char#!#1#!#8000#!#'#!#'#!#length #!#1#!#1#!#3#!##!#0#!##!#char#!##!##!#1#!##!##!##!#1 +~~END~~ + +~~ROW COUNT: 1~~ + + +exec sp_datatype_info @data_type = 2; +~~START~~ +int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int +numeric#!#2#!#38#!##!##!#precision,scale #!#1#!#0#!#2#!#0#!#0#!#0#!#numeric#!#0#!#38#!#2#!##!#10#!##!#10 +numeric() identity#!#2#!#38#!##!##!#precision #!#0#!#0#!#2#!#0#!#0#!#1#!#numeric() identity#!#0#!#0#!#2#!##!#10#!##!#10 +~~END~~ + +~~ROW COUNT: 2~~ + diff --git a/contrib/test/python/expected/pymssql/TestAuth.out b/contrib/test/python/expected/pymssql/TestAuth.out new file mode 100644 index 00000000000..1183736980e --- /dev/null +++ b/contrib/test/python/expected/pymssql/TestAuth.out @@ -0,0 +1,4 @@ +#database name, username and password should not exceed 128 characters +#not sure why any password is accepted during authentication through cloud desktop +#This test should throw error but from cloud desktop a connection is successfully established +#py_auth#!#password|-|11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 diff --git a/contrib/test/python/expected/pymssql/TestBIT.out b/contrib/test/python/expected/pymssql/TestBIT.out new file mode 100644 index 00000000000..99058a01c62 --- /dev/null +++ b/contrib/test/python/expected/pymssql/TestBIT.out @@ -0,0 +1,49 @@ +CREATE TABLE BIT_dt (a BIT) +prepst#!# INSERT INTO BIT_dt(a) values(%s) #!#BIT|-|a|-|false +~~ROW COUNT: 1~~ + +prepst#!#exec#!#BIT|-|a|-|true +~~ROW COUNT: 1~~ + +#next two lines are not allowed +#prepst#!#exec#!#BIT|-|a|-|0 +#prepst#!#exec#!#BIT|-|a|-|1 +prepst#!#exec#!#BIT|-|a|-| +~~ROW COUNT: 1~~ + +SELECT * FROM BIT_dt; +~~START~~ +int +False +True + +~~END~~ + +~~ROW COUNT: 3~~ + +INSERT INTO BIT_dt(a) values(1) +~~ROW COUNT: 1~~ + +INSERT INTO BIT_dt(a) values(0) +~~ROW COUNT: 1~~ + +#next two lines are not allowed +#INSERT INTO BIT_dt(a) values(false) +#INSERT INTO BIT_dt(a) values(true) +INSERT INTO BIT_dt(a) values(NULL) +~~ROW COUNT: 1~~ + +SELECT * FROM BIT_dt; +~~START~~ +int +False +True + +True +False + +~~END~~ + +~~ROW COUNT: 6~~ + +DROP TABLE BIT_dt; diff --git a/contrib/test/python/expected/pymssql/TestBigInt.out b/contrib/test/python/expected/pymssql/TestBigInt.out new file mode 100644 index 00000000000..8690ea2efbe --- /dev/null +++ b/contrib/test/python/expected/pymssql/TestBigInt.out @@ -0,0 +1,106 @@ +CREATE TABLE BIGINT_dt (a BIGINT) +prepst#!# INSERT INTO BIGINT_dt(a) values(%s) #!#BIGINT|-|a|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#BIGINT|-|a|-|-10 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#BIGINT|-|a|-|122100 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#BIGINT|-|a|-|0001202 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#BIGINT|-|a|-|-024112329 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#BIGINT|-|a|-|-0000000000000000002 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#BIGINT|-|a|-|0000000000000000086 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#BIGINT|-|a|-|-9223372036854775808 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#BIGINT|-|a|-|9223372036854775807 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#BIGINT|-|a|-| +~~ROW COUNT: 1~~ + +SELECT * FROM BIGINT_dt; +~~START~~ +int +0 +-10 +122100 +1202 +-24112329 +-2 +86 +-9223372036854775808 +9223372036854775807 + +~~END~~ + +~~ROW COUNT: 10~~ + +INSERT INTO BIGINT_dt(a) values(0) +~~ROW COUNT: 1~~ + +INSERT INTO BIGINT_dt(a) values(-120) +~~ROW COUNT: 1~~ + +INSERT INTO BIGINT_dt(a) values(00100) +~~ROW COUNT: 1~~ + +INSERT INTO BIGINT_dt(a) values(-004) +~~ROW COUNT: 1~~ + +INSERT INTO BIGINT_dt(a) values(-012245532534) +~~ROW COUNT: 1~~ + +INSERT INTO BIGINT_dt(a) values(-0000000000000000002) +~~ROW COUNT: 1~~ + +INSERT INTO BIGINT_dt(a) values(0000000000000000086) +~~ROW COUNT: 1~~ + +INSERT INTO BIGINT_dt(a) values(-9223372036854775808) +~~ROW COUNT: 1~~ + +INSERT INTO BIGINT_dt(a) values(9223372036854775807) +~~ROW COUNT: 1~~ + +INSERT INTO BIGINT_dt(a) values(NULL) +~~ROW COUNT: 1~~ + +SELECT * FROM BIGINT_dt; +~~START~~ +int +0 +-10 +122100 +1202 +-24112329 +-2 +86 +-9223372036854775808 +9223372036854775807 + +0 +-120 +100 +-4 +-12245532534 +-2 +86 +-9223372036854775808 +9223372036854775807 + +~~END~~ + +~~ROW COUNT: 20~~ + +DROP TABLE BIGINT_dt; diff --git a/contrib/test/python/expected/pymssql/TestBinary.out b/contrib/test/python/expected/pymssql/TestBinary.out new file mode 100644 index 00000000000..da719094b0d --- /dev/null +++ b/contrib/test/python/expected/pymssql/TestBinary.out @@ -0,0 +1,49 @@ +CREATE TABLE BINARY_dt(a BINARY(8), b VARBINARY(10)); +#inserting random values +INSERT INTO BINARY_dt(a, b) values (1234, 12345); +~~ROW COUNT: 1~~ + +INSERT INTO BINARY_dt(a, b) values (NULL, NULL); +~~ROW COUNT: 1~~ + +#INSERT INTO BINARY_dt(a, b) values (0x31323334, 0x3132333435); +SELECT * FROM BINARY_dt +~~START~~ +int#!#int +b'\x00\x00\x00\x00\x00\x00\x04\xd2'#!#b'\x00\x0009' +#!# +~~END~~ + +~~ROW COUNT: 2~~ + +#prepst#!# INSERT INTO BINARY_dt(a, b) values(@a, @b) #!#binary|-|a|-|1234#!#varbinary|-|b|-|12345 +DROP TABLE BINARY_dt + + +CREATE TABLE BINARY_dt(a VARBINARY(max)); +INSERT INTO BINARY_dt(a) values (NULL); +~~ROW COUNT: 1~~ + +SELECT * FROM BINARY_dt; +~~START~~ +int + +~~END~~ + +~~ROW COUNT: 1~~ + +DROP TABLE BINARY_dt; + +create table BINARY_dt (a VARBINARY(max), b int, c int, d int, e int ,f int, g int, h int, i int); +insert into BINARY_dt (a,b,c,d,e,f,g,h,i) values (NULL,1,2,3,4,5,6,7,8); +~~ROW COUNT: 1~~ + +select * from BINARY_dt; +~~START~~ +int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int +#!#1#!#2#!#3#!#4#!#5#!#6#!#7#!#8 +~~END~~ + +~~ROW COUNT: 1~~ + +drop table BINARY_dt; diff --git a/contrib/test/python/expected/pymssql/TestChar.out b/contrib/test/python/expected/pymssql/TestChar.out new file mode 100644 index 00000000000..47a6ebf68b5 --- /dev/null +++ b/contrib/test/python/expected/pymssql/TestChar.out @@ -0,0 +1,64 @@ +CREATE TABLE CHAR_dt (a CHAR(24), b NCHAR(24)) +prepst#!# INSERT INTO CHAR_dt(a, b) values(%s, %s) #!#CHAR|-|a|-|Dipesh#!#NCHAR|-|b|-|Dhameliya +~~ROW COUNT: 1~~ + +prepst#!#exec#!#CHAR|-|a|-| Dipesh #!#NCHAR|-|b|-| Dhameliya +~~ROW COUNT: 1~~ + +prepst#!#exec#!#CHAR|-|a|-| D#!#NCHAR|-|b|-| 🤣😃 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#CHAR|-|a|-| #!#NCHAR|-|b|-| +~~ROW COUNT: 1~~ + +prepst#!#exec#!#CHAR|-|a|-| #!#NCHAR|-|b|-|😊😋😎😍😅😆 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#CHAR|-|a|-|#!#NCHAR|-|b|-| +~~ROW COUNT: 1~~ + +SELECT * FROM CHAR_dt; +~~START~~ +int#!#int +Dipesh #!#Dhameliya + Dipesh #!# Dhameliya + D #!# 🤣😃 + #!# + #!#😊😋😎😍😅😆 +#!# +~~END~~ + +~~ROW COUNT: 6~~ + +INSERT INTO CHAR_dt(a,b) values('Dipesh','Dhameliya') +~~ROW COUNT: 1~~ + +INSERT INTO CHAR_dt(a,b) values(' Dipesh',' Dhameliya') +~~ROW COUNT: 1~~ + +#INSERT INTO CHAR_dt(a,b) values(' D',N' 🤣😃') +INSERT INTO CHAR_dt(a,b) values(' ',' ') +~~ROW COUNT: 1~~ + +#INSERT INTO CHAR_dt(a,b) values(' ',N'😊😋😎😍😅😆') +INSERT INTO CHAR_dt(a,b) values(NULL,NULL) +~~ROW COUNT: 1~~ + +SELECT * FROM CHAR_dt; +~~START~~ +int#!#int +Dipesh #!#Dhameliya + Dipesh #!# Dhameliya + D #!# 🤣😃 + #!# + #!#😊😋😎😍😅😆 +#!# +Dipesh #!#Dhameliya + Dipesh #!# Dhameliya + #!# +#!# +~~END~~ + +~~ROW COUNT: 10~~ + +DROP TABLE CHAR_dt; diff --git a/contrib/test/python/expected/pymssql/TestCursorFetchNext.out b/contrib/test/python/expected/pymssql/TestCursorFetchNext.out new file mode 100644 index 00000000000..38a542183a7 --- /dev/null +++ b/contrib/test/python/expected/pymssql/TestCursorFetchNext.out @@ -0,0 +1,83 @@ +CREATE TABLE test_cursors_fetch_next(a INT, b SMALLINT, c BIGINT, d TINYINT, e BIT); +INSERT INTO test_cursors_fetch_next values(0, 0, 0, 0, 0) +~~ROW COUNT: 1~~ + +INSERT INTO test_cursors_fetch_next values(NULL, NULL, NULL, NULL, NULL) +~~ROW COUNT: 1~~ + +INSERT INTO test_cursors_fetch_next values(1, 2, 3, 4, 1) +~~ROW COUNT: 1~~ + +INSERT INTO test_cursors_fetch_next values(211234, 9780, 891372401, 56, 1) +~~ROW COUNT: 1~~ + +#cursor#!#fetch#!#prev +#cursor#!#fetch#!#next +#cursor#!#fetch#!#beforefirst +#cursor#!#fetch#!#next +#cursor#!#fetch#!#afterlast +#cursor#!#fetch#!#next +DROP TABLE test_cursors_fetch_next + +CREATE TABLE test_cursors_fetch_next(a CHAR(30), b VARCHAR(30), c NCHAR(30), d NVARCHAR(30)); +INSERT INTO test_cursors_fetch_next values(' ', ' ', ' ', ' ') +~~ROW COUNT: 1~~ + +INSERT INTO test_cursors_fetch_next values(NULL, NULL, NULL, NULL) +~~ROW COUNT: 1~~ + +INSERT INTO test_cursors_fetch_next values('hello', 'from the', N'server', N'side 😆') +~~ROW COUNT: 1~~ + +INSERT INTO test_cursors_fetch_next values('Its', 'always', N'day', N'1') +~~ROW COUNT: 1~~ + +#cursor#!#fetch#!#prev +#cursor#!#fetch#!#next +#cursor#!#fetch#!#beforefirst +#cursor#!#fetch#!#next +#cursor#!#fetch#!#afterlast +#cursor#!#fetch#!#next +DROP TABLE test_cursors_fetch_next + +CREATE TABLE test_cursors_fetch_next(a DATE, b DATETIME, c SMALLDATETIME); +INSERT INTO test_cursors_fetch_next values('2000-12-13', '1900-02-28 23:59:59.989', '2000-12-13 12:58:23') +~~ROW COUNT: 1~~ + +INSERT INTO test_cursors_fetch_next values(NULL, NULL, NULL) +~~ROW COUNT: 1~~ + +INSERT INTO test_cursors_fetch_next values('1997-05-07', '1900-02-28 11:23:17.895', '2000-12-13 10:23:44') +~~ROW COUNT: 1~~ + +INSERT INTO test_cursors_fetch_next values('1876-08-07', '1980-02-05 16:11:45.215', '1987-10-01 07:55:24') +~~ROW COUNT: 1~~ + +#cursor#!#fetch#!#prev +#cursor#!#fetch#!#next +#cursor#!#fetch#!#beforefirst +#cursor#!#fetch#!#next +#cursor#!#fetch#!#afterlast +#cursor#!#fetch#!#next +DROP TABLE test_cursors_fetch_next + +CREATE TABLE test_cursors_fetch_next(a FLOAT, b REAL, c MONEY, d SMALLMONEY); +INSERT INTO test_cursors_fetch_next values(0, 0, '$0', '$0') +~~ROW COUNT: 1~~ + +INSERT INTO test_cursors_fetch_next values(NULL, NULL, NULL, NULL) +~~ROW COUNT: 1~~ + +INSERT INTO test_cursors_fetch_next values(241.7832, 1214.691236, '62,514.00', '690.817') +~~ROW COUNT: 1~~ + +INSERT INTO test_cursors_fetch_next values('32546', '980.709', '1,988,232.08', '$86,798') +~~ROW COUNT: 1~~ + +#cursor#!#fetch#!#prev +#cursor#!#fetch#!#next +#cursor#!#fetch#!#beforefirst +#cursor#!#fetch#!#next +#cursor#!#fetch#!#afterlast +#cursor#!#fetch#!#next +DROP TABLE test_cursors_fetch_next diff --git a/contrib/test/python/expected/pymssql/TestCursorPrepExecFetchNext.out b/contrib/test/python/expected/pymssql/TestCursorPrepExecFetchNext.out new file mode 100644 index 00000000000..06bb45df745 --- /dev/null +++ b/contrib/test/python/expected/pymssql/TestCursorPrepExecFetchNext.out @@ -0,0 +1,83 @@ +CREATE TABLE test_cursor_prep_exec_fetch_next(a INT, b SMALLINT, c BIGINT, d TINYINT, e BIT); +INSERT INTO test_cursor_prep_exec_fetch_next values(0, 0, 0, 0, 0) +~~ROW COUNT: 1~~ + +INSERT INTO test_cursor_prep_exec_fetch_next values(NULL, NULL, NULL, NULL, NULL) +~~ROW COUNT: 1~~ + +INSERT INTO test_cursor_prep_exec_fetch_next values(1, 2, 3, 4, 1) +~~ROW COUNT: 1~~ + +INSERT INTO test_cursor_prep_exec_fetch_next values(211234, 9780, 891372401, 56, 1) +~~ROW COUNT: 1~~ + +#cursor#!#fetch#!#prev +#cursor#!#fetch#!#next +#cursor#!#fetch#!#beforefirst +#cursor#!#fetch#!#next +#cursor#!#fetch#!#afterlast +#cursor#!#fetch#!#next +DROP TABLE test_cursor_prep_exec_fetch_next + +CREATE TABLE test_cursor_prep_exec_fetch_next(a CHAR(30), b VARCHAR(30), c NCHAR(30), d NVARCHAR(30)); +INSERT INTO test_cursor_prep_exec_fetch_next values(' ', ' ', ' ', ' ') +~~ROW COUNT: 1~~ + +INSERT INTO test_cursor_prep_exec_fetch_next values(NULL, NULL, NULL, NULL) +~~ROW COUNT: 1~~ + +INSERT INTO test_cursor_prep_exec_fetch_next values('hello', 'from the', N'server', N'side 😆') +~~ROW COUNT: 1~~ + +INSERT INTO test_cursor_prep_exec_fetch_next values('Its', 'always', N'day', N'1') +~~ROW COUNT: 1~~ + +#cursor#!#fetch#!#prev +#cursor#!#fetch#!#next +#cursor#!#fetch#!#beforefirst +#cursor#!#fetch#!#next +#cursor#!#fetch#!#afterlast +#cursor#!#fetch#!#next +DROP TABLE test_cursor_prep_exec_fetch_next + +CREATE TABLE test_cursor_prep_exec_fetch_next(a DATE, b DATETIME, c SMALLDATETIME); +INSERT INTO test_cursor_prep_exec_fetch_next values('2000-12-13', '1900-02-28 23:59:59.989', '2000-12-13 12:58:23') +~~ROW COUNT: 1~~ + +INSERT INTO test_cursor_prep_exec_fetch_next values(NULL, NULL, NULL) +~~ROW COUNT: 1~~ + +INSERT INTO test_cursor_prep_exec_fetch_next values('1997-05-07', '1900-02-28 11:23:17.895', '2000-12-13 10:23:44') +~~ROW COUNT: 1~~ + +INSERT INTO test_cursor_prep_exec_fetch_next values('1876-08-07', '1980-02-05 16:11:45.215', '1987-10-01 07:55:24') +~~ROW COUNT: 1~~ + +#cursor#!#fetch#!#prev +#cursor#!#fetch#!#next +#cursor#!#fetch#!#beforefirst +#cursor#!#fetch#!#next +#cursor#!#fetch#!#afterlast +#cursor#!#fetch#!#next +DROP TABLE test_cursor_prep_exec_fetch_next + +CREATE TABLE test_cursor_prep_exec_fetch_next(a FLOAT, b REAL, c MONEY, d SMALLMONEY); +INSERT INTO test_cursor_prep_exec_fetch_next values(0, 0, '$0', '$0') +~~ROW COUNT: 1~~ + +INSERT INTO test_cursor_prep_exec_fetch_next values(NULL, NULL, NULL, NULL) +~~ROW COUNT: 1~~ + +INSERT INTO test_cursor_prep_exec_fetch_next values(241.7832, 1214.691236, '62,514.00', '690.817') +~~ROW COUNT: 1~~ + +INSERT INTO test_cursor_prep_exec_fetch_next values('32546', '980.709', '1,988,232.08', '$86,798') +~~ROW COUNT: 1~~ + +#cursor#!#fetch#!#prev +#cursor#!#fetch#!#next +#cursor#!#fetch#!#beforefirst +#cursor#!#fetch#!#next +#cursor#!#fetch#!#afterlast +#cursor#!#fetch#!#next +DROP TABLE test_cursor_prep_exec_fetch_next diff --git a/contrib/test/python/expected/pymssql/TestDate.out b/contrib/test/python/expected/pymssql/TestDate.out new file mode 100644 index 00000000000..c1005d1c314 --- /dev/null +++ b/contrib/test/python/expected/pymssql/TestDate.out @@ -0,0 +1,61 @@ +CREATE TABLE DATE_dt (a DATE) +prepst#!# INSERT INTO DATE_dt(a) values(%s) #!#DATE|-|a|-|2000-12-13 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#DATE|-|a|-|2000-02-28 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#DATE|-|a|-|0001-01-01 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#DATE|-|a|-|9999-12-31 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#DATE|-|a|-| +~~ROW COUNT: 1~~ + +SELECT * FROM DATE_dt; +~~START~~ +int +2000-12-13 +2000-02-28 +0001-01-01 +9999-12-31 + +~~END~~ + +~~ROW COUNT: 5~~ + +INSERT INTO DATE_dt(a) values('2000-12-13') +~~ROW COUNT: 1~~ + +INSERT INTO DATE_dt(a) values('1900-02-28') +~~ROW COUNT: 1~~ + +INSERT INTO DATE_dt(a) values('0001-01-01') +~~ROW COUNT: 1~~ + +INSERT INTO DATE_dt(a) values('9999-12-31') +~~ROW COUNT: 1~~ + +INSERT INTO DATE_dt(a) values(NULL) +~~ROW COUNT: 1~~ + +SELECT * FROM DATE_dt; +~~START~~ +int +2000-12-13 +2000-02-28 +0001-01-01 +9999-12-31 + +2000-12-13 +1900-02-28 +0001-01-01 +9999-12-31 + +~~END~~ + +~~ROW COUNT: 10~~ + +DROP TABLE DATE_dt; diff --git a/contrib/test/python/expected/pymssql/TestDatetime.out b/contrib/test/python/expected/pymssql/TestDatetime.out new file mode 100644 index 00000000000..d96a30f9d87 --- /dev/null +++ b/contrib/test/python/expected/pymssql/TestDatetime.out @@ -0,0 +1,160 @@ +CREATE TABLE DATETIME_dt (a DATETIME) +prepst#!# INSERT INTO DATETIME_dt(a) values(%s) #!#DATETIME|-|a|-|2000-12-13 12:58:23.123 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.989 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.990 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.991 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.992 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.993 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.994 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.995 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.996 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.997 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.998 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.999 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#DATETIME|-|a|-|1900-02-28 23:59:59.989 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#DATETIME|-|a|-|1753-01-01 00:00:00.000 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#DATETIME|-|a|-|9999-12-31 23:59:59.997 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#DATETIME|-|a|-| +~~ROW COUNT: 1~~ + +SELECT * FROM DATETIME_dt; +~~START~~ +int +2000-12-13 12:58:23.123000 +2000-02-28 23:59:59.990000 +2000-02-28 23:59:59.990000 +2000-02-28 23:59:59.990000 +2000-02-28 23:59:59.993000 +2000-02-28 23:59:59.993000 +2000-02-28 23:59:59.993000 +2000-02-28 23:59:59.997000 +2000-02-28 23:59:59.997000 +2000-02-28 23:59:59.997000 +2000-02-28 23:59:59.997000 +2000-02-29 00:00:00 +1900-02-28 23:59:59.990000 +1753-01-01 00:00:00 +9999-12-31 23:59:59.997000 + +~~END~~ + +~~ROW COUNT: 16~~ + +INSERT INTO DATETIME_dt(a) values('2000-12-13 12:58:23.123') +~~ROW COUNT: 1~~ + +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.989') +~~ROW COUNT: 1~~ + +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.990') +~~ROW COUNT: 1~~ + +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.991') +~~ROW COUNT: 1~~ + +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.992') +~~ROW COUNT: 1~~ + +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.993') +~~ROW COUNT: 1~~ + +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.994') +~~ROW COUNT: 1~~ + +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.995') +~~ROW COUNT: 1~~ + +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.996') +~~ROW COUNT: 1~~ + +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.997') +~~ROW COUNT: 1~~ + +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.998') +~~ROW COUNT: 1~~ + +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.999') +~~ROW COUNT: 1~~ + +INSERT INTO DATETIME_dt(a) values('2000-02-28 23:59:59.989') +~~ROW COUNT: 1~~ + +INSERT INTO DATETIME_dt(a) values('1753-01-01 00:00:00.000') +~~ROW COUNT: 1~~ + +INSERT INTO DATETIME_dt(a) values('9999-12-31 23:59:59.997') +~~ROW COUNT: 1~~ + +INSERT INTO DATETIME_dt(a) values(NULL) +~~ROW COUNT: 1~~ + +SELECT * FROM DATETIME_dt; +~~START~~ +int +2000-12-13 12:58:23.123000 +2000-02-28 23:59:59.990000 +2000-02-28 23:59:59.990000 +2000-02-28 23:59:59.990000 +2000-02-28 23:59:59.993000 +2000-02-28 23:59:59.993000 +2000-02-28 23:59:59.993000 +2000-02-28 23:59:59.997000 +2000-02-28 23:59:59.997000 +2000-02-28 23:59:59.997000 +2000-02-28 23:59:59.997000 +2000-02-29 00:00:00 +1900-02-28 23:59:59.990000 +1753-01-01 00:00:00 +9999-12-31 23:59:59.997000 + +2000-12-13 12:58:23.123000 +1900-02-28 23:59:59.990000 +1900-02-28 23:59:59.990000 +1900-02-28 23:59:59.990000 +1900-02-28 23:59:59.993000 +1900-02-28 23:59:59.993000 +1900-02-28 23:59:59.993000 +1900-02-28 23:59:59.997000 +1900-02-28 23:59:59.997000 +1900-02-28 23:59:59.997000 +1900-02-28 23:59:59.997000 +1900-03-01 00:00:00 +2000-02-28 23:59:59.990000 +1753-01-01 00:00:00 +9999-12-31 23:59:59.997000 + +~~END~~ + +~~ROW COUNT: 32~~ + +DROP TABLE DATETIME_dt; diff --git a/contrib/test/python/expected/pymssql/TestDatetime2.out b/contrib/test/python/expected/pymssql/TestDatetime2.out new file mode 100644 index 00000000000..62d7af5a2bd --- /dev/null +++ b/contrib/test/python/expected/pymssql/TestDatetime2.out @@ -0,0 +1,45 @@ +Create table TestDatetime2(a Datetime2(6)) + +prepst#!# Insert into TestDatetime2 Values(%s) #!#Datetime2|-|a|-|2016-10-23 12:45:37.123|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Datetime2|-|a|-|2016-10-23 12:45:37.123|-|3 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Datetime2|-|a|-|2016-10-23 12:45:37.12|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Datetime2|-|a|-|2016-10-23 12:45:37.1|-|1 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Datetime2|-|a|-|2016-10-23 12:45:37.1234|-|4 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Datetime2|-|a|-|2016-10-23 12:45:37.123456|-|6 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Datetime2|-|a|-|2016-10-23 12:45:37.123456|-|5 +~~ROW COUNT: 1~~ + +#prepst#!#exec#!#Datetime2|-|a|-|12:45:37.123456|-|5 +prepst#!#exec#!#Datetime2|-|a|-| +~~ROW COUNT: 1~~ + + +select * from TestDatetime2 +~~START~~ +int +2016-10-23 12:45:37.123000 +2016-10-23 12:45:37.123000 +2016-10-23 12:45:37.120000 +2016-10-23 12:45:37.100000 +2016-10-23 12:45:37.123000 +2016-10-23 12:45:37.123000 +2016-10-23 12:45:37.123000 + +~~END~~ + +~~ROW COUNT: 8~~ + + +Drop table TestDatetime2 diff --git a/contrib/test/python/expected/pymssql/TestDecimal.out b/contrib/test/python/expected/pymssql/TestDecimal.out new file mode 100644 index 00000000000..d9ff61533de --- /dev/null +++ b/contrib/test/python/expected/pymssql/TestDecimal.out @@ -0,0 +1,564 @@ +CREATE TABLE decimal_table(num decimal(5, 2)); + +prepst#!#INSERT INTO decimal_table(num) VALUES(%s) #!#decimal|-|a|-|3|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a|-|123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a|-|123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a|-|123|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a|-|123.45|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a|-||-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a|-|-123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a|-|-123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a|-|-123|-|5|-|2 +~~ROW COUNT: 1~~ + +#prepst#!#exec#!#decimal|-|a|-|0|-|5|-|2 +prepst#!#exec#!#decimal|-|a|-|-1|-|3|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a|-|-123|-|9|-|2 +~~ROW COUNT: 1~~ + + +SELECT * FROM decimal_table; +~~START~~ +int +3.00 +123.46 +123.40 +123.00 +123.45 + +-123.46 +-123.40 +-123.00 +-1.00 +-123.00 +~~END~~ + +~~ROW COUNT: 11~~ + + +DROP TABLE decimal_table; + +CREATE TABLE decimal_table(num decimal(38, 3)); + +prepst#!#INSERT INTO decimal_table(num) VALUES(%s) #!#decimal|-|a1|-|3|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a1|-|123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a1|-|123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a1|-|123|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a1|-|123.45|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a1|-||-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a1|-|-123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a1|-|-123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a1|-|-123|-|5|-|2 +~~ROW COUNT: 1~~ + +#prepst#!#exec#!#decimal|-|a1|-|0|-|5|-|2 +prepst#!#exec#!#decimal|-|a1|-|-1|-|3|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a1|-|-123|-|9|-|2 +~~ROW COUNT: 1~~ + + +prepst#!#exec#!#decimal|-|a1|-|2147483647|-|10|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a1|-|-2147483647|-|10|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a1|-|2147483646|-|10|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a1|-|-2147483646|-|10|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a1|-|2147483648|-|10|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a1|-|-2147483648|-|10|-|0 +~~ROW COUNT: 1~~ + + +SELECT * FROM decimal_table; +~~START~~ +int +3.000 +123.456 +123.400 +123.000 +123.450 + +-123.456 +-123.400 +-123.000 +-1.000 +-123.000 +2147483647.000 +-2147483647.000 +2147483646.000 +-2147483646.000 +2147483648.000 +-2147483648.000 +~~END~~ + +~~ROW COUNT: 17~~ + + +DROP TABLE decimal_table; + +# JIRA 507, WORKING FOR BABEL +#CREATE TABLE decimal_table(num decimal(39, 20)); + +CREATE TABLE decimal_table(num decimal(38, 20)); + +prepst#!#INSERT INTO decimal_table(num) VALUES(%s) #!#decimal|-|a2|-|3|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a2|-|123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a2|-|123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a2|-|123|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a2|-|123.45|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a2|-||-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a2|-|-123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a2|-|-123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a2|-|-123|-|5|-|2 +~~ROW COUNT: 1~~ + +#prepst#!#exec#!#decimal|-|a2|-|0|-|5|-|2 +prepst#!#exec#!#decimal|-|a2|-|-1|-|3|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a2|-|-123|-|9|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a2|-|2147483647|-|10|-|0 +~~ROW COUNT: 1~~ + +SELECT * FROM decimal_table; +~~START~~ +int +3.00000000000000000000 +123.45600000000000000000 +123.40000000000000000000 +123.00000000000000000000 +123.45000000000000000000 + +-123.45600000000000000000 +-123.40000000000000000000 +-123.00000000000000000000 +-1.00000000000000000000 +-123.00000000000000000000 +2147483647.00000000000000000000 +~~END~~ + +~~ROW COUNT: 12~~ + + +DROP TABLE decimal_table; + +CREATE TABLE decimal_table(num decimal(38, 20)); +prepst#!#INSERT INTO decimal_table(num) VALUES(%s) #!#decimal|-|a3|-|3|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a3|-|123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a3|-|123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a3|-|123|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a3|-|123.45|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a3|-||-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a3|-|-123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a3|-|-123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a3|-|-123|-|5|-|2 +~~ROW COUNT: 1~~ + +#prepst#!#exec#!#decimal|-|a3|-|0|-|5|-|2 +prepst#!#exec#!#decimal|-|a3|-|-1|-|3|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a3|-|-123|-|9|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a3|-|2147483647|-|10|-|0 +~~ROW COUNT: 1~~ + +SELECT * FROM decimal_table; +~~START~~ +int +3.00000000000000000000 +123.45600000000000000000 +123.40000000000000000000 +123.00000000000000000000 +123.45000000000000000000 + +-123.45600000000000000000 +-123.40000000000000000000 +-123.00000000000000000000 +-1.00000000000000000000 +-123.00000000000000000000 +2147483647.00000000000000000000 +~~END~~ + +~~ROW COUNT: 12~~ + + +DROP TABLE decimal_table; + +CREATE TABLE decimal_table(num decimal(38, 21)); +prepst#!#INSERT INTO decimal_table(num) VALUES(%s) #!#decimal|-|a4|-|3|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a4|-|123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a4|-|123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a4|-|123|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a4|-|123.45|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a4|-||-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a4|-|-123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a4|-|-123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a4|-|-123|-|5|-|2 +~~ROW COUNT: 1~~ + +#prepst#!#exec#!#decimal|-|a4|-|0|-|5|-|2 +prepst#!#exec#!#decimal|-|a4|-|-1|-|3|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a4|-|-123|-|9|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a4|-|2147483647|-|10|-|0 +~~ROW COUNT: 1~~ + +SELECT * FROM decimal_table; +~~START~~ +int +3.000000000000000000000 +123.456000000000000000000 +123.400000000000000000000 +123.000000000000000000000 +123.450000000000000000000 + +-123.456000000000000000000 +-123.400000000000000000000 +-123.000000000000000000000 +-1.000000000000000000000 +-123.000000000000000000000 +2147483647.000000000000000000000 +~~END~~ + +~~ROW COUNT: 12~~ + + +DROP TABLE decimal_table; + +CREATE TABLE decimal_table(num decimal(38, 22)); +prepst#!#INSERT INTO decimal_table(num) VALUES(%s) #!#decimal|-|a5|-|3|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a5|-|123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a5|-|123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a5|-|123|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a5|-|123.45|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a5|-||-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a5|-|-123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a5|-|-123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a5|-|-123|-|5|-|2 +~~ROW COUNT: 1~~ + +#prepst#!#exec#!#decimal|-|a5|-|0|-|5|-|2 +prepst#!#exec#!#decimal|-|a5|-|-1|-|3|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a5|-|-123|-|9|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a5|-|2147483647|-|10|-|0 +~~ROW COUNT: 1~~ + +SELECT * FROM decimal_table; +~~START~~ +int +3.0000000000000000000000 +123.4560000000000000000000 +123.4000000000000000000000 +123.0000000000000000000000 +123.4500000000000000000000 + +-123.4560000000000000000000 +-123.4000000000000000000000 +-123.0000000000000000000000 +-1.0000000000000000000000 +-123.0000000000000000000000 +2147483647.0000000000000000000000 +~~END~~ + +~~ROW COUNT: 12~~ + + +DROP TABLE decimal_table; + +CREATE TABLE decimal_table(num decimal(38, 23)); +prepst#!#INSERT INTO decimal_table(num) VALUES(%s) #!#decimal|-|a6|-|3|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a6|-|123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a6|-|123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a6|-|123|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a6|-|123.45|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a6|-||-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a6|-|-123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a6|-|-123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a6|-|-123|-|5|-|2 +~~ROW COUNT: 1~~ + +#prepst#!#exec#!#decimal|-|a6|-|0|-|5|-|2 +prepst#!#exec#!#decimal|-|a6|-|-1|-|3|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a6|-|-123|-|9|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a6|-|2147483647|-|10|-|0 +~~ROW COUNT: 1~~ + +SELECT * FROM decimal_table; +~~START~~ +int +3.00000000000000000000000 +123.45600000000000000000000 +123.40000000000000000000000 +123.00000000000000000000000 +123.45000000000000000000000 + +-123.45600000000000000000000 +-123.40000000000000000000000 +-123.00000000000000000000000 +-1.00000000000000000000000 +-123.00000000000000000000000 +2147483647.00000000000000000000000 +~~END~~ + +~~ROW COUNT: 12~~ + + +DROP TABLE decimal_table; + +CREATE TABLE decimal_table(num decimal(38, 25)); +prepst#!#INSERT INTO decimal_table(num) VALUES(%s) #!#decimal|-|a7|-|3|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a7|-|123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a7|-|123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a7|-|123|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a7|-|123.45|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a7|-||-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a7|-|-123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a7|-|-123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a7|-|-123|-|5|-|2 +~~ROW COUNT: 1~~ + +#prepst#!#exec#!#decimal|-|a7|-|0|-|5|-|2 +prepst#!#exec#!#decimal|-|a7|-|-1|-|3|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a7|-|-123|-|9|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a7|-|247483647|-|10|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a7|-|-247483647|-|10|-|0 +~~ROW COUNT: 1~~ + +SELECT * FROM decimal_table; +~~START~~ +int +3.0000000000000000000000000 +123.4560000000000000000000000 +123.4000000000000000000000000 +123.0000000000000000000000000 +123.4500000000000000000000000 + +-123.4560000000000000000000000 +-123.4000000000000000000000000 +-123.0000000000000000000000000 +-1.0000000000000000000000000 +-123.0000000000000000000000000 +247483647.0000000000000000000000000 +-247483647.0000000000000000000000000 +~~END~~ + +~~ROW COUNT: 13~~ + + +DROP TABLE decimal_table; + + +CREATE TABLE decimal_table(num decimal(38, 25)); + +insert into decimal_table values (2147483647) +~~ROW COUNT: 1~~ + +insert into decimal_table values (-2147483647) +~~ROW COUNT: 1~~ + + +insert into decimal_table values (2147483646) +~~ROW COUNT: 1~~ + +insert into decimal_table values (-2147483646) +~~ROW COUNT: 1~~ + + +insert into decimal_table values (2147483648) +~~ROW COUNT: 1~~ + +insert into decimal_table values (-2147483648) +~~ROW COUNT: 1~~ + + +#insert into decimal_table values(123456789123456789.1234567891234567891234567); +#insert into decimal_table values(1234567891234567891.1234567891234567891234567); +#insert into decimal_table values(123456789123456789.12345678912345678912345678); +insert into decimal_table values(0.0); +~~ROW COUNT: 1~~ + +insert into decimal_table values(0.0000000000000000000000000); +~~ROW COUNT: 1~~ + +insert into decimal_table values(0.00000000000000000000000000); +~~ROW COUNT: 1~~ + + +SELECT * FROM decimal_table; +~~START~~ +int +2147483647.0000000000000000000000000 +-2147483647.0000000000000000000000000 +2147483646.0000000000000000000000000 +-2147483646.0000000000000000000000000 +2147483648.0000000000000000000000000 +-2147483648.0000000000000000000000000 +0E-25 +0E-25 +0E-25 +~~END~~ + +~~ROW COUNT: 9~~ + + +DROP TABLE decimal_table; diff --git a/contrib/test/python/expected/pymssql/TestFloat.out b/contrib/test/python/expected/pymssql/TestFloat.out new file mode 100644 index 00000000000..7bdb9eb8773 --- /dev/null +++ b/contrib/test/python/expected/pymssql/TestFloat.out @@ -0,0 +1,106 @@ +CREATE TABLE FLOAT_dt (a FLOAT) +prepst#!# INSERT INTO FLOAT_dt(a) values(%s) #!#FLOAT|-|a|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#FLOAT|-|a|-|1.050 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#FLOAT|-|a|-|01.05 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#FLOAT|-|a|-|0001202 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#FLOAT|-|a|-|-024112329 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#FLOAT|-|a|-|-02.5 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#FLOAT|-|a|-|0000000000000000086 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#FLOAT|-|a|-|-1.79E+308 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#FLOAT|-|a|-|1.79E+308 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#FLOAT|-|a|-| +~~ROW COUNT: 1~~ + +SELECT * FROM FLOAT_dt; +~~START~~ +int +0.0 +1.05 +1.05 +1202.0 +-24112329.0 +-2.5 +86.0 +-1.79e+308 +1.79e+308 + +~~END~~ + +~~ROW COUNT: 10~~ + +INSERT INTO FLOAT_dt(a) values(0) +~~ROW COUNT: 1~~ + +INSERT INTO FLOAT_dt(a) values(1.050) +~~ROW COUNT: 1~~ + +INSERT INTO FLOAT_dt(a) values(01.05) +~~ROW COUNT: 1~~ + +INSERT INTO FLOAT_dt(a) values(-004) +~~ROW COUNT: 1~~ + +INSERT INTO FLOAT_dt(a) values(-0122455324.5) +~~ROW COUNT: 1~~ + +INSERT INTO FLOAT_dt(a) values(-000002) +~~ROW COUNT: 1~~ + +INSERT INTO FLOAT_dt(a) values(0000000000000000086) +~~ROW COUNT: 1~~ + +INSERT INTO FLOAT_dt(a) values(-1.79E+308) +~~ROW COUNT: 1~~ + +INSERT INTO FLOAT_dt(a) values(1.79E+308) +~~ROW COUNT: 1~~ + +INSERT INTO FLOAT_dt(a) values(NULL) +~~ROW COUNT: 1~~ + +SELECT * FROM FLOAT_dt; +~~START~~ +int +0.0 +1.05 +1.05 +1202.0 +-24112329.0 +-2.5 +86.0 +-1.79e+308 +1.79e+308 + +0.0 +1.05 +1.05 +-4.0 +-122455324.5 +-2.0 +86.0 +-1.79e+308 +1.79e+308 + +~~END~~ + +~~ROW COUNT: 20~~ + +DROP TABLE FLOAT_dt; diff --git a/contrib/test/python/expected/pymssql/TestInt.out b/contrib/test/python/expected/pymssql/TestInt.out new file mode 100644 index 00000000000..b14c6649bab --- /dev/null +++ b/contrib/test/python/expected/pymssql/TestInt.out @@ -0,0 +1,115 @@ +CREATE TABLE INT_dt(a INT); +prepst#!#INSERT INTO INT_dt(a) values(%s) #!#INT|-|a|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#INT|-|a|-|-10 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#INT|-|a|-|10 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#INT|-|a|-|-12234 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#INT|-|a|-|22 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#INT|-|a|-|003 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#INT|-|a|-|9864 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#INT|-|a|-|-01625 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#INT|-|a|-|-2147483648 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#INT|-|a|-|2147483647 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#INT|-|a|-| +~~ROW COUNT: 1~~ + + +SELECT * FROM INT_dt; +~~START~~ +int +0 +-10 +10 +-12234 +22 +3 +9864 +-1625 +-2147483648 +2147483647 + +~~END~~ + +~~ROW COUNT: 11~~ + + +INSERT INTO INT_dt(a) values(0) +~~ROW COUNT: 1~~ + +INSERT INTO INT_dt(a) values(-10) +~~ROW COUNT: 1~~ + +INSERT INTO INT_dt(a) values(10) +~~ROW COUNT: 1~~ + +INSERT INTO INT_dt(a) values(-12345) +~~ROW COUNT: 1~~ + +INSERT INTO INT_dt(a) values(22) +~~ROW COUNT: 1~~ + +INSERT INTO INT_dt(a) values(004) +~~ROW COUNT: 1~~ + +INSERT INTO INT_dt(a) values(-01645) +~~ROW COUNT: 1~~ + +INSERT INTO INT_dt(a) values(-2147483648) +~~ROW COUNT: 1~~ + +INSERT INTO INT_dt(a) values(2147483647) +~~ROW COUNT: 1~~ + +INSERT INTO INT_dt(a) values(NULL) +~~ROW COUNT: 1~~ + + +SELECT * FROM INT_dt; +~~START~~ +int +0 +-10 +10 +-12234 +22 +3 +9864 +-1625 +-2147483648 +2147483647 + +0 +-10 +10 +-12345 +22 +4 +-1645 +-2147483648 +2147483647 + +~~END~~ + +~~ROW COUNT: 21~~ + + +DROP TABLE INT_dt; diff --git a/contrib/test/python/expected/pymssql/TestMoney.out b/contrib/test/python/expected/pymssql/TestMoney.out new file mode 100644 index 00000000000..abf66cc3b3c --- /dev/null +++ b/contrib/test/python/expected/pymssql/TestMoney.out @@ -0,0 +1,115 @@ +CREATE TABLE money_dt(a smallmoney, b money); + +prepst#!#INSERT INTO money_dt(a, b) VALUES (%s, %s) #!#smallmoney|-|a|-|100.5#!#money|-|b|-|10.05 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#smallmoney|-|a|-|10#!#money|-|b|-|10 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#smallmoney|-|a|-|-10.05 #!#money|-|b|-|-10.0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#smallmoney|-|a|-|-214748.3648#!#money|-|b|-|-922337203685477.5808 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#smallmoney|-|a|-|214748.3647#!#money|-|b|-|22337203685477.5807 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#smallmoney|-|a|-|214748.3647#!#money|-|b|-|22337203685477.5807 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#smallmoney|-|a|-|-214,748.3648#!#money|-|b|-|-922,337,203,685,477.5808 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#smallmoney|-|a|-|214,748.3647#!#money|-|b|-|922,337,203,685,477.5807 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#smallmoney|-|a|-|214,748.3647#!#money|-|b|-|922,337,203,685,477.5807 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#smallmoney|-|a|-|#!#money|-|b|-| +~~ROW COUNT: 1~~ + + +SELECT * FROM money_dt; +~~START~~ +int#!#int +100.5000#!#10.0500 +10.0000#!#10.0000 +-10.0500#!#-10.0000 +-214748.3648#!#-922337203685477.5808 +214748.3647#!#22337203685477.5807 +214748.3647#!#22337203685477.5807 +-214748.3648#!#-922337203685477.5808 +214748.3647#!#922337203685477.5807 +214748.3647#!#922337203685477.5807 +#!# +~~END~~ + +~~ROW COUNT: 10~~ + + +INSERT INTO money_dt(a,b) values(100.5,10.05); +~~ROW COUNT: 1~~ + +INSERT INTO money_dt(a,b) values('$10','$10'); +~~ROW COUNT: 1~~ + +INSERT INTO money_dt(a,b) values('-10.05','-10.0'); +~~ROW COUNT: 1~~ + +INSERT INTO money_dt(a,b) values('10.05','10.0'); +~~ROW COUNT: 1~~ + +INSERT INTO money_dt(a,b) values(-214748.3648,'-10.0'); +~~ROW COUNT: 1~~ + +INSERT INTO money_dt(a,b) values(14748.3647,-922337203685477.5808); +~~ROW COUNT: 1~~ + +INSERT INTO money_dt(a,b) values('$214748.3647','$22337203685477.5807'); +~~ROW COUNT: 1~~ + +INSERT INTO money_dt(a,b) values('-214,748.3648','-922,337,203,685,477.5808'); +~~ROW COUNT: 1~~ + +INSERT INTO money_dt(a,b) values('214,748.3647','922,337,203,685,477.5807'); +~~ROW COUNT: 1~~ + +INSERT INTO money_dt(a,b) values('$214,748.3647','$922,337,203,685,477.5807'); +~~ROW COUNT: 1~~ + +INSERT INTO money_dt(a,b) values(NULL,NULL); +~~ROW COUNT: 1~~ + + + +SELECT * FROM money_dt; +~~START~~ +int#!#int +100.5000#!#10.0500 +10.0000#!#10.0000 +-10.0500#!#-10.0000 +-214748.3648#!#-922337203685477.5808 +214748.3647#!#22337203685477.5807 +214748.3647#!#22337203685477.5807 +-214748.3648#!#-922337203685477.5808 +214748.3647#!#922337203685477.5807 +214748.3647#!#922337203685477.5807 +#!# +100.5000#!#10.0500 +10.0000#!#10.0000 +-10.0500#!#-10.0000 +10.0500#!#10.0000 +-214748.3648#!#-10.0000 +14748.3647#!#-922337203685477.5808 +214748.3647#!#22337203685477.5807 +-214748.3648#!#-922337203685477.5808 +214748.3647#!#922337203685477.5807 +214748.3647#!#922337203685477.5807 +#!# +~~END~~ + +~~ROW COUNT: 21~~ + +DROP TABLE money_dt; diff --git a/contrib/test/python/expected/pymssql/TestNumeric.out b/contrib/test/python/expected/pymssql/TestNumeric.out new file mode 100644 index 00000000000..c346b7d9f99 --- /dev/null +++ b/contrib/test/python/expected/pymssql/TestNumeric.out @@ -0,0 +1,606 @@ +CREATE TABLE numeric_table(num numeric(5, 2)); + +prepst#!#INSERT INTO numeric_table(num) VALUES(%s) #!#numeric|-|a|-|3|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a|-|123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a|-|123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a|-|123|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a|-|123.45|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a|-||-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a|-|-123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a|-|-123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a|-|-123|-|5|-|2 +~~ROW COUNT: 1~~ + +#prepst#!#exec#!#numeric|-|a|-|0|-|5|-|2 +prepst#!#exec#!#numeric|-|a|-|-1|-|3|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a|-|-123|-|9|-|2 +~~ROW COUNT: 1~~ + + +SELECT * FROM numeric_table; +~~START~~ +int +3.00 +123.46 +123.40 +123.00 +123.45 + +-123.46 +-123.40 +-123.00 +-1.00 +-123.00 +~~END~~ + +~~ROW COUNT: 11~~ + + +DROP TABLE numeric_table; + +CREATE TABLE numeric_table(num numeric(38, 3)); + +prepst#!#INSERT INTO numeric_table(num) VALUES(%s) #!#numeric|-|a1|-|3|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a1|-|123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a1|-|123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a1|-|123|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a1|-|123.45|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a1|-||-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a1|-|-123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a1|-|-123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a1|-|-123|-|5|-|2 +~~ROW COUNT: 1~~ + +#prepst#!#exec#!#numeric|-|a1|-|0|-|5|-|2 +prepst#!#exec#!#numeric|-|a1|-|-1|-|3|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a1|-|-123|-|9|-|2 +~~ROW COUNT: 1~~ + + +prepst#!#exec#!#numeric|-|a1|-|2147483647|-|10|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a1|-|-2147483647|-|10|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a1|-|2147483646|-|10|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a1|-|-2147483646|-|10|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a1|-|2147483648|-|10|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a1|-|-2147483648|-|10|-|0 +~~ROW COUNT: 1~~ + + +SELECT * FROM numeric_table; +~~START~~ +int +3.000 +123.456 +123.400 +123.000 +123.450 + +-123.456 +-123.400 +-123.000 +-1.000 +-123.000 +2147483647.000 +-2147483647.000 +2147483646.000 +-2147483646.000 +2147483648.000 +-2147483648.000 +~~END~~ + +~~ROW COUNT: 17~~ + + +DROP TABLE numeric_table; + +# JIRA 507, WORKING FOR BABEL +#CREATE TABLE numeric_table(num numeric(39, 20)); + +CREATE TABLE numeric_table(num numeric(38, 20)); + +prepst#!#INSERT INTO numeric_table(num) VALUES(%s) #!#numeric|-|a2|-|3|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a2|-|123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a2|-|123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a2|-|123|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a2|-|123.45|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a2|-||-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a2|-|-123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a2|-|-123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a2|-|-123|-|5|-|2 +~~ROW COUNT: 1~~ + +#prepst#!#exec#!#numeric|-|a2|-|0|-|5|-|2 +prepst#!#exec#!#numeric|-|a2|-|-1|-|3|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a2|-|-123|-|9|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a2|-|2147483647|-|10|-|0 +~~ROW COUNT: 1~~ + +SELECT * FROM numeric_table; +~~START~~ +int +3.00000000000000000000 +123.45600000000000000000 +123.40000000000000000000 +123.00000000000000000000 +123.45000000000000000000 + +-123.45600000000000000000 +-123.40000000000000000000 +-123.00000000000000000000 +-1.00000000000000000000 +-123.00000000000000000000 +2147483647.00000000000000000000 +~~END~~ + +~~ROW COUNT: 12~~ + + +DROP TABLE numeric_table; + +CREATE TABLE numeric_table(num numeric(38, 20)); +prepst#!#INSERT INTO numeric_table(num) VALUES(%s) #!#numeric|-|a3|-|3|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a3|-|123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a3|-|123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a3|-|123|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a3|-|123.45|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a3|-||-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a3|-|-123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a3|-|-123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a3|-|-123|-|5|-|2 +~~ROW COUNT: 1~~ + +#prepst#!#exec#!#numeric|-|a3|-|0|-|5|-|2 +prepst#!#exec#!#numeric|-|a3|-|-1|-|3|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a3|-|-123|-|9|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a3|-|2147483647|-|10|-|0 +~~ROW COUNT: 1~~ + +SELECT * FROM numeric_table; +~~START~~ +int +3.00000000000000000000 +123.45600000000000000000 +123.40000000000000000000 +123.00000000000000000000 +123.45000000000000000000 + +-123.45600000000000000000 +-123.40000000000000000000 +-123.00000000000000000000 +-1.00000000000000000000 +-123.00000000000000000000 +2147483647.00000000000000000000 +~~END~~ + +~~ROW COUNT: 12~~ + + +DROP TABLE numeric_table; + +CREATE TABLE numeric_table(num numeric(38, 21)); +prepst#!#INSERT INTO numeric_table(num) VALUES(%s) #!#numeric|-|a4|-|3|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a4|-|123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a4|-|123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a4|-|123|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a4|-|123.45|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a4|-||-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a4|-|-123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a4|-|-123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a4|-|-123|-|5|-|2 +~~ROW COUNT: 1~~ + +#prepst#!#exec#!#numeric|-|a4|-|0|-|5|-|2 +prepst#!#exec#!#numeric|-|a4|-|-1|-|3|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a4|-|-123|-|9|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a4|-|2147483647|-|10|-|0 +~~ROW COUNT: 1~~ + +SELECT * FROM numeric_table; +~~START~~ +int +3.000000000000000000000 +123.456000000000000000000 +123.400000000000000000000 +123.000000000000000000000 +123.450000000000000000000 + +-123.456000000000000000000 +-123.400000000000000000000 +-123.000000000000000000000 +-1.000000000000000000000 +-123.000000000000000000000 +2147483647.000000000000000000000 +~~END~~ + +~~ROW COUNT: 12~~ + + +DROP TABLE numeric_table; + +CREATE TABLE numeric_table(num numeric(38, 22)); +prepst#!#INSERT INTO numeric_table(num) VALUES(%s) #!#numeric|-|a5|-|3|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a5|-|123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a5|-|123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a5|-|123|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a5|-|123.45|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a5|-||-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a5|-|-123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a5|-|-123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a5|-|-123|-|5|-|2 +~~ROW COUNT: 1~~ + +#prepst#!#exec#!#numeric|-|a5|-|0|-|5|-|2 +prepst#!#exec#!#numeric|-|a5|-|-1|-|3|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a5|-|-123|-|9|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a5|-|2147483647|-|10|-|0 +~~ROW COUNT: 1~~ + +SELECT * FROM numeric_table; +~~START~~ +int +3.0000000000000000000000 +123.4560000000000000000000 +123.4000000000000000000000 +123.0000000000000000000000 +123.4500000000000000000000 + +-123.4560000000000000000000 +-123.4000000000000000000000 +-123.0000000000000000000000 +-1.0000000000000000000000 +-123.0000000000000000000000 +2147483647.0000000000000000000000 +~~END~~ + +~~ROW COUNT: 12~~ + + +DROP TABLE numeric_table; + +CREATE TABLE numeric_table(num numeric(38, 23)); +prepst#!#INSERT INTO numeric_table(num) VALUES(%s) #!#numeric|-|a6|-|3|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a6|-|123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a6|-|123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a6|-|123|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a6|-|123.45|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a6|-||-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a6|-|-123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a6|-|-123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a6|-|-123|-|5|-|2 +~~ROW COUNT: 1~~ + +#prepst#!#exec#!#numeric|-|a6|-|0|-|5|-|2 +prepst#!#exec#!#numeric|-|a6|-|-1|-|3|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a6|-|-123|-|9|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a6|-|2147483647|-|10|-|0 +~~ROW COUNT: 1~~ + +SELECT * FROM numeric_table; +~~START~~ +int +3.00000000000000000000000 +123.45600000000000000000000 +123.40000000000000000000000 +123.00000000000000000000000 +123.45000000000000000000000 + +-123.45600000000000000000000 +-123.40000000000000000000000 +-123.00000000000000000000000 +-1.00000000000000000000000 +-123.00000000000000000000000 +2147483647.00000000000000000000000 +~~END~~ + +~~ROW COUNT: 12~~ + + +DROP TABLE numeric_table; + +CREATE TABLE numeric_table(num numeric(38, 25)); +prepst#!#INSERT INTO numeric_table(num) VALUES(%s) #!#numeric|-|a7|-|3|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a7|-|123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a7|-|123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a7|-|123|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a7|-|123.45|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a7|-||-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a7|-|-123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a7|-|-123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a7|-|-123|-|5|-|2 +~~ROW COUNT: 1~~ + +#prepst#!#exec#!#numeric|-|a7|-|0|-|5|-|2 +prepst#!#exec#!#numeric|-|a7|-|-1|-|3|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a7|-|-123|-|9|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a7|-|247483647|-|10|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a7|-|-247483647|-|10|-|0 +~~ROW COUNT: 1~~ + +SELECT * FROM numeric_table; +~~START~~ +int +3.0000000000000000000000000 +123.4560000000000000000000000 +123.4000000000000000000000000 +123.0000000000000000000000000 +123.4500000000000000000000000 + +-123.4560000000000000000000000 +-123.4000000000000000000000000 +-123.0000000000000000000000000 +-1.0000000000000000000000000 +-123.0000000000000000000000000 +247483647.0000000000000000000000000 +-247483647.0000000000000000000000000 +~~END~~ + +~~ROW COUNT: 13~~ + + +DROP TABLE numeric_table; + + +CREATE TABLE numeric_table(num numeric(38, 25)); + +insert into numeric_table values (2147483647) +~~ROW COUNT: 1~~ + +insert into numeric_table values (-2147483647) +~~ROW COUNT: 1~~ + + +insert into numeric_table values (2147483646) +~~ROW COUNT: 1~~ + +insert into numeric_table values (-2147483646) +~~ROW COUNT: 1~~ + + +insert into numeric_table values (2147483648) +~~ROW COUNT: 1~~ + +insert into numeric_table values (-2147483648) +~~ROW COUNT: 1~~ + + +#insert into numeric_table values(123456789123456789.1234567891234567891234567); +#insert into numeric_table values(1234567891234567891.1234567891234567891234567); +#insert into numeric_table values(123456789123456789.12345678912345678912345678); +insert into numeric_table values(0.0); +~~ROW COUNT: 1~~ + +insert into numeric_table values(0.0000000000000000000000000); +~~ROW COUNT: 1~~ + +insert into numeric_table values(0.00000000000000000000000000); +~~ROW COUNT: 1~~ + + +SELECT * FROM numeric_table; +~~START~~ +int +2147483647.0000000000000000000000000 +-2147483647.0000000000000000000000000 +2147483646.0000000000000000000000000 +-2147483646.0000000000000000000000000 +2147483648.0000000000000000000000000 +-2147483648.0000000000000000000000000 +0E-25 +0E-25 +0E-25 +~~END~~ + +~~ROW COUNT: 9~~ + + +DROP TABLE numeric_table; + +# BABEL-1459 +declare @numvar numeric(5,4); set @numvar=-0.010; SELECT @numvar as N'@var'; +~~START~~ +int +-0.0100 +~~END~~ + +~~ROW COUNT: 1~~ + +declare @numvar numeric(4,4); set @numvar=-0.010; SELECT @numvar as N'@var'; +~~START~~ +int +-0.0100 +~~END~~ + +~~ROW COUNT: 1~~ + +declare @numvar numeric(5,4); set @numvar=1.01; SELECT @numvar as N'@var'; +~~START~~ +int +1.0100 +~~END~~ + +~~ROW COUNT: 1~~ + +declare @numvar numeric(4,4); set @numvar=0.01; SELECT @numvar as N'@var'; +~~START~~ +int +0.0100 +~~END~~ + +~~ROW COUNT: 1~~ + +declare @numvar numeric(4,4); set @numvar=0; SELECT @numvar as N'@var'; +~~START~~ +int +0.0000 +~~END~~ + +~~ROW COUNT: 1~~ + diff --git a/contrib/test/python/expected/pymssql/TestReal.out b/contrib/test/python/expected/pymssql/TestReal.out new file mode 100644 index 00000000000..8b388648205 --- /dev/null +++ b/contrib/test/python/expected/pymssql/TestReal.out @@ -0,0 +1,106 @@ +CREATE TABLE REAL_dt (a REAL) +prepst#!# INSERT INTO REAL_dt(a) values(%s) #!#REAL|-|a|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#REAL|-|a|-|1.050 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#REAL|-|a|-|01.05 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#REAL|-|a|-|0001202 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#REAL|-|a|-|-024112329 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#REAL|-|a|-|-02.5 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#REAL|-|a|-|0000000000000000086 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#REAL|-|a|-|-3.40E+38 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#REAL|-|a|-|3.40E+38 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#REAL|-|a|-| +~~ROW COUNT: 1~~ + +SELECT * FROM REAL_dt; +~~START~~ +int +0.0 +1.0499999523162842 +1.0499999523162842 +1202.0 +-24112328.0 +-2.5 +86.0 +-3.3999999521443642e+38 +3.3999999521443642e+38 + +~~END~~ + +~~ROW COUNT: 10~~ + +INSERT INTO REAL_dt(a) values(0) +~~ROW COUNT: 1~~ + +INSERT INTO REAL_dt(a) values(1.050) +~~ROW COUNT: 1~~ + +INSERT INTO REAL_dt(a) values(01.05) +~~ROW COUNT: 1~~ + +INSERT INTO REAL_dt(a) values(-004) +~~ROW COUNT: 1~~ + +INSERT INTO REAL_dt(a) values(-0122455324.5) +~~ROW COUNT: 1~~ + +INSERT INTO REAL_dt(a) values(-000002) +~~ROW COUNT: 1~~ + +INSERT INTO REAL_dt(a) values(0000000000000000086) +~~ROW COUNT: 1~~ + +INSERT INTO REAL_dt(a) values(-3.40E+38) +~~ROW COUNT: 1~~ + +INSERT INTO REAL_dt(a) values(3.40E+38) +~~ROW COUNT: 1~~ + +INSERT INTO REAL_dt(a) values(NULL) +~~ROW COUNT: 1~~ + +SELECT * FROM REAL_dt; +~~START~~ +int +0.0 +1.0499999523162842 +1.0499999523162842 +1202.0 +-24112328.0 +-2.5 +86.0 +-3.3999999521443642e+38 +3.3999999521443642e+38 + +0.0 +1.0499999523162842 +1.0499999523162842 +-4.0 +-122455328.0 +-2.0 +86.0 +-3.3999999521443642e+38 +3.3999999521443642e+38 + +~~END~~ + +~~ROW COUNT: 20~~ + +DROP TABLE REAL_dt; diff --git a/contrib/test/python/expected/pymssql/TestSPExecutesql.out b/contrib/test/python/expected/pymssql/TestSPExecutesql.out new file mode 100644 index 00000000000..7e849fefb52 --- /dev/null +++ b/contrib/test/python/expected/pymssql/TestSPExecutesql.out @@ -0,0 +1,253 @@ +CREATE TABLE spExecutesqlTable1 (a INT, b VARCHAR(10)); +CREATE TABLE spExecutesqlTable2 (a INT, b INT, c INT, d INT); +GO +/* 1. Execute a string of statement */ +DECLARE @SQLString NVARCHAR(100); +SET @SQLString = N'SELECT N''hello world'';'; +EXEC sp_executesql @SQLString; +GO +~~START~~ +int +hello world +~~END~~ + +~~ROW COUNT: 1~~ + +/* 2. Execute a statement string with parameters */ +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'INSERT INTO spExecutesqlTable1 VALUES (@a, @b);'; +SET @ParamDef = N'@a INT, @b VARCHAR(10)'; +DECLARE @p INT = 1; +EXEC sp_executesql @SQLString, @ParamDef, @p, @b = N'hello'; +SELECT * FROM spExecutesqlTable1; +GO +~~START~~ +int#!#int +1#!#hello +~~END~~ + +~~ROW COUNT: 1~~ + +TRUNCATE TABLE spExecutesqlTable1; +GO +/* 3. Execute a statement string with both unnamed params and named params */ +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'INSERT INTO spExecutesqlTable2 VALUES (@a, @b, @c, @d);'; +SET @ParamDef = N'@a INT, @b INT, @c INT, @d INT'; +EXEC sp_executesql @SQLString, @ParamDef, 1, 2, @d = 4, @c = 3; +SELECT * FROM spExecutesqlTable2; +GO +~~START~~ +int#!#int#!#int#!#int +1#!#2#!#3#!#4 +~~END~~ + +~~ROW COUNT: 1~~ + +TRUNCATE TABLE spExecutesqlTable2; +GO +/* 4. Nested sp_executesql */ +DECLARE @SQLString1 NVARCHAR(100); +DECLARE @SQLString2 NVARCHAR(max); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString1 = N'INSERT INTO spExecutesqlTable1 VALUES (@a, @b);' +SET @SQLString2 = @SQLString1 + N'EXEC sp_executesql N''INSERT INTO spExecutesqlTable1 VALUES (@c + @c, @d + @d);'', N''@c INT, @d VARCHAR(10)'', @a, @b;' +SET @ParamDef = N'@a INT, @b VARCHAR(10)'; +EXEC sp_executesql @SQLString2, @ParamDef, @a = 10, @b = N'str'; +SELECT * FROM spExecutesqlTable1; +GO +~~START~~ +int#!#int +10#!#str +20#!#strstr +~~END~~ + +~~ROW COUNT: 2~~ + +TRUNCATE TABLE spExecutesqlTable1; +GO +-- Nested with param name collision +DECLARE @SQLString1 NVARCHAR(100); +DECLARE @SQLString2 NVARCHAR(max); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString1 = N'INSERT INTO spExecutesqlTable1 VALUES (@a, @b);' +SET @SQLString2 = @SQLString1 + N'EXEC sp_executesql N''INSERT INTO spExecutesqlTable1 VALUES (@a + @a, @b + @b);'', N''@a INT, @b VARCHAR(10)'', @a, @b;' +SET @ParamDef = N'@a INT, @b VARCHAR(10)'; +EXEC sp_executesql @SQLString2, @ParamDef, @a = 11, @b = N'rts'; +SELECT * FROM spExecutesqlTable1; +GO +~~START~~ +int#!#int +11#!#rts +22#!#rtsrts +~~END~~ + +~~ROW COUNT: 2~~ + +TRUNCATE TABLE spExecutesqlTable1; +GO +/* 5. Execute a statement string with OUT/INOUT param */ +DECLARE @SQLString1 NVARCHAR(100); +DECLARE @SQLString2 NVARCHAR(max); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString1 = N'SET @a = @b + @b'; +SET @SQLString2 = N'EXEC sp_executesql N''SET @a = @b + @b'', N''@a INT OUT, @b INT'', @a OUT, @b;'; +SET @ParamDef = N'@a INT OUTPUT, @b INT'; +DECLARE @p INT; +DECLARE @a INT; +-- OUT param +EXEC sp_executesql @SQLString1, @ParamDef, @a = @p OUT, @b = 10; +-- Nested with OUT param name collision +EXEC sp_executesql @SQLString2, @ParamDef, @a = @a OUT, @b = 11; +SELECT @p, @a; +GO +~~START~~ +int#!#int +20#!#22 +~~END~~ + +~~ROW COUNT: 1~~ + +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'SET @a = @a + 1;'; +SET @ParamDef = N'@a INT OUT'; +DECLARE @p1 INT = 1; +DECLARE @p2 INT = 1; +-- Declared as INOUT and called as OUT +EXEC sp_executesql @SQLString, @ParamDef, @a = @p1 OUT; +-- Declared as INOUT and called as IN +EXEC sp_executesql @SQLString, @ParamDef, @a = @p2; +SELECT @p1, @p2; +GO +~~START~~ +int#!#int +2#!#1 +~~END~~ + +~~ROW COUNT: 1~~ + +/* 6. Implicit cast for IN param */ +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'SET @b = @a;'; +SET @ParamDef = N'@a FLOAT, @b FLOAT OUT'; +DECLARE @p FLOAT; +DECLARE @a MONEY = 3.14; +EXEC sp_executesql @SQLString, @ParamDef, @a = @a, @b = @p OUTPUT; +SELECT @p; +GO +~~START~~ +int +3.14 +~~END~~ + +~~ROW COUNT: 1~~ + +/* 7. Implicit cast for OUT param */ +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'SET @a = CAST(''2020-01-01'' AS DATE); SET @b = @a;'; +SET @ParamDef = N'@a DATE OUT, @b DATETIME OUT'; +DECLARE @p1 DATETIME; +DECLARE @p2 DATETIME; +EXEC sp_executesql @SQLString, @ParamDef, @a = @p1 OUT, @b = @p2 OUT; +SELECT @p1, @p2; +GO +~~START~~ +int#!#int +2020-01-01 00:00:00#!#2020-01-01 00:00:00 +~~END~~ + +~~ROW COUNT: 1~~ + +/* Exceptions */ +/* 1. Wrong order of named/unnamed params */ +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'INSERT INTO spExecutesqlTable2 VALUES (@a, @b, @c, @d);'; +SET @ParamDef = N'@a INT, @b INT, @c INT, @d INT'; +EXEC sp_executesql @SQLString, @ParamDef, @b = 2, @c = 3, 1, @d = 4; +GO +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: "syntax error near '1' at line 7 and character position 58DB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n")~~ + +/* 2. Number mismatch of param defs and given params */ +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'INSERT INTO spExecutesqlTable2 VALUES (@a, @b, @c, @d);'; +SET @ParamDef = N'@a INT, @b INT, @c INT, @d INT'; +EXEC sp_executesql @SQLString, @ParamDef, 1, 2, 3; +GO +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: 'param definition mismatches with inputsDB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n')~~ + +/* 3. Invalid param name */ +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'INSERT INTO spExecutesqlTable2 VALUES (@a, @b, @c, @d);'; +SET @ParamDef = N'@a INT, @b INT, @c INT, @d INT'; +EXEC sp_executesql @SQLString, @ParamDef, @a = 1, @b = 2, @c = 3, @e = 4; +GO +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: 'param "@e" not definedDB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n')~~ + +/* 4. Invalid param def */ +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'INSERT INTO spExecutesqlTable2 VALUES (@a, @b, @c, @d);'; +SET @ParamDef = N'@a INT, @b INT, @c, @d INT'; +EXEC sp_executesql @SQLString, @ParamDef, 1, 2, 3, 4; +GO +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: 'syntax error at or near ","DB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n')~~ + +/* 5. Unsupported implicit cast */ +-- IN param +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'INSERT INTO spExecutesqlTable2 VALUES (@a, @b, @c, @d);'; +SET @ParamDef = N'@a INT, @b INT, @c INT, @d INT'; +EXEC sp_executesql @SQLString, @ParamDef, 1, 3.14, 'hello', 4; +GO +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: 'invalid input syntax for type integer: "hello"DB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n')~~ + +-- OUT param +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'SET @a = CAST(''abc'' AS VARCHAR(3));'; +SET @ParamDef = N'@a FLOAT OUT'; +DECLARE @p FLOAT; +EXEC sp_executesql @SQLString, @ParamDef, @a = @p OUT; +GO +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: 'invalid input syntax for type double precision: "abc"DB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n')~~ + +/* 6. Invalid OUT param */ +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'SET @a = 20'; +SET @ParamDef = N'@a INT OUT'; +EXEC sp_executesql @SQLString, @ParamDef, @a = 10 OUT; +GO +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: "syntax error near ';' at line 6 and character position 53DB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n")~~ + +/* 7. Param declared as IN but called as OUT */ +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'SET @a = 20'; +SET @ParamDef = N'@a INT'; +DECLARE @p INT; +EXEC sp_executesql @SQLString, @ParamDef, @a = @p OUT; +GO +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: 'param @a defined as mode i but received mode bDB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n')~~ + +/* Clean up */ +DROP TABLE spExecutesqlTable1; +DROP TABLE spExecutesqlTable2; +GO diff --git a/contrib/test/python/expected/pymssql/TestSPPrepare.out b/contrib/test/python/expected/pymssql/TestSPPrepare.out new file mode 100644 index 00000000000..9cbee8c3520 --- /dev/null +++ b/contrib/test/python/expected/pymssql/TestSPPrepare.out @@ -0,0 +1,601 @@ +--- Simple SP_PREPARE +DECLARE @handle int; +EXEC SP_PREPARE @handle, NULL, 'SELECT ''OK''' +EXEC SP_EXECUTE @handle +EXEC SP_EXECUTE @handle +EXEC SP_EXECUTE @handle +EXEC SP_UNPREPARE @handle +GO +~~START~~ +int +~~END~~ + +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: 'handle argument of sp_execute is nullDB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n')~~ + +--- Simple SP_PREPEXEC +DECLARE @handle int; +EXEC SP_PREPEXEC @handle OUT, NULL, 'SELECT ''OK''' +EXEC SP_EXECUTE @handle +EXEC SP_EXECUTE @handle +EXEC SP_EXECUTE @handle +EXEC SP_UNPREPARE @handle +GO +~~START~~ +int +OK +~~END~~ + +~~START~~ +int +OK +~~END~~ + +~~START~~ +int +OK +~~END~~ + +~~START~~ +int +OK +~~END~~ + +~~ROW COUNT: 1~~ + +--- Basic SP_PREPARE with args +DECLARE @handle int; +EXEC SP_PREPARE @handle out, N'@a int, @b int', N'select @a, @b', 10; +EXEC SP_EXECUTE @handle, 1, 2 +EXEC SP_EXECUTE @handle, 1, 2 +EXEC SP_EXECUTE @handle, 1, 2 +EXEC SP_UNPREPARE @handle; +GO +~~START~~ +int#!#int +~~END~~ + +~~START~~ +int#!#int +1#!#2 +~~END~~ + +~~START~~ +int#!#int +1#!#2 +~~END~~ + +~~START~~ +int#!#int +1#!#2 +~~END~~ + +~~ROW COUNT: 1~~ + +--- Basic SP_PREPARE with args +DECLARE @handle int; +EXEC SP_PREPEXEC @handle out, N'@a int, @b int', N'select @a, @b', 1, 2; +EXEC SP_EXECUTE @handle, 1, 2 +EXEC SP_EXECUTE @handle, 1, 2 +EXEC SP_EXECUTE @handle, 1, 2 +EXEC SP_UNPREPARE @handle; +GO +~~START~~ +int#!#int +1#!#2 +~~END~~ + +~~START~~ +int#!#int +1#!#2 +~~END~~ + +~~START~~ +int#!#int +1#!#2 +~~END~~ + +~~START~~ +int#!#int +1#!#2 +~~END~~ + +~~ROW COUNT: 1~~ + +--- SP_PREPARE Batch Support +DECLARE @handle int; +DECLARE @batch nvarchar(500); +DECLARE @paramdef nvarchar(500); +DECLARE @var int; +SET @batch = 'IF (@cond > 0) SELECT @o = @a ELSE SELECT @o = @b' +SET @paramdef = '@cond int, @a int, @b int, @o int OUTPUT' +EXEC SP_PREPARE @handle, @paramdef, @batch +EXEC SP_EXECUTE @handle, -1, 10, 20, @var OUTPUT +SELECT @var +EXEC SP_EXECUTE @handle, 1, 10, 20, @var OUTPUT +SELECT @var +EXEC SP_UNPREPARE @handle; +GO +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: 'handle argument of sp_execute is nullDB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n')~~ + +--- SP_PREPEXEC Batch Support +DECLARE @handle int; +DECLARE @batch nvarchar(500); +DECLARE @paramdef nvarchar(500); +DECLARE @var int; +SET @batch = 'IF (@cond > 0) SELECT @o = @a ELSE SELECT @o = @b' +SET @paramdef = '@cond int, @a int, @b int, @o int OUTPUT' +EXEC SP_PREPEXEC @handle out, @paramdef, @batch, 1, 30, 40, @var OUTPUT +SELECT @var +EXEC SP_EXECUTE @handle, -1, 10, 20, @var OUTPUT +SELECT @var +EXEC SP_EXECUTE @handle, 1, 10, 20, @var OUTPUT +SELECT @var +EXEC SP_UNPREPARE @handle; +GO +~~START~~ +int +30 +~~END~~ + +~~START~~ +int +20 +~~END~~ + +~~START~~ +int +10 +~~END~~ + +~~ROW COUNT: 1~~ + +--- Parsing specific +DECLARE @handle int; +EXEC SP_PREPEXEC @handle + 1 OUTPUT, NULL, 'SELECT 1' +GO +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: "syntax error near '+' at line 3 and character position 25DB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n")~~ + +DECLARE @handle VARCHAR(20) +EXEC SP_PREPEXEC @handle OUTPUT, NULL, 'SELECT 1' +GO +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: 'invalid prepared_handle param datatypeDB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n')~~ + +DECLARE @handle int; +EXEC SP_PREPEXEC @handle, NULL, 'SELECT 1' +GO +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: 'prepared_handle param is not specified as OUTPUTDB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n')~~ + +--- Corner case 1: empty batch +DECLARE @handle int; +EXEC SP_PREPARE @handle out, NULL, NULL +EXEC SP_EXECUTE @handle +EXEC SP_UNPREPARE @handle +GO +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: 'query argument of sp_prepare is nullDB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n')~~ + +DECLARE @handle int; +EXEC SP_PREPEXEC @handle out, NULL, NULL +EXEC SP_EXECUTE @handle +EXEC SP_UNPREPARE @handle +GO +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: 'batch string argument of sp_prepexec is nullDB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n')~~ + +--- Corner case 2: nested prepare +DECLARE @handle int; +DECLARE @inner_handle int; +DECLARE @batch VARCHAR(500); +SET @batch = 'EXEC SP_PREPARE @inner_handle OUT, NULL, ''SELECT 1'' ' +EXEC SP_PREPARE @handle out, '@inner_handle int OUT', @batch +EXEC SP_EXECUTE @handle, @inner_handle OUT +EXEC SP_EXECUTE @inner_handle +EXEC SP_UNPREPARE @inner_handle -- unprepare inner first +EXEC SP_UNPREPARE @handle +GO +~~START~~ +int +~~END~~ + +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +DECLARE @handle int; +DECLARE @inner_handle int; +DECLARE @batch VARCHAR(500); +SET @batch = 'EXEC SP_PREPARE @inner_handle OUT, NULL, ''SELECT 1'' ' +EXEC SP_PREPARE @handle out, '@inner_handle int OUT', @batch +EXEC SP_EXECUTE @handle, @inner_handle OUT +EXEC SP_EXECUTE @inner_handle +EXEC SP_UNPREPARE @handle --unprepare outer first +EXEC SP_EXECUTE @inner_handle +EXEC SP_UNPREPARE @inner_handle +GO +~~START~~ +int +~~END~~ + +~~START~~ +int +1 +~~END~~ + +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +--- Corner case 3: mismatch paramdef and params +DECLARE @handle int; +DECLARE @var int; +DECLARE @batch VARCHAR(500); +DECLARE @paramdef VARCHAR(500); +SET @batch = 'SELECT @a'; +SET @paramdef = '@a int'; +EXEC SP_PREPARE @handle OUT, @paramdef, @batch +EXEC SP_EXECUTE @handle, 100 +EXEC SP_EXECUTE @handle, @var OUT +EXEC SP_UNPREPARE @handle +GO +~~START~~ +int +~~END~~ + +~~START~~ +int +100 +~~END~~ + +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: 'param 1 defined as mode i but received mode bDB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n')~~ + +~~ROW COUNT: 1~~ + +--- Prepare DML statement +CREATE TABLE t1 (a int, b int); +GO +DECLARE @handle int; +DECLARE @batch VARCHAR(500); +DECLARE @paramdef VARCHAR(500); +SET @batch = ' +INSERT INTO t1 VALUES (@v1, @v2) +INSERT INTO t1 VALUES (@v3, @v4) +' +SET @paramdef = '@v1 int, @v2 int, @v3 int, @v4 int' +EXEC SP_PREPARE @handle OUT, @paramdef, @batch +EXEC SP_EXECUTE @handle, 1, 2, 2, 3 +EXEC SP_EXECUTE @handle, 3, 4, 4, 5 +SELECT * FROM t1 ORDER BY 1, 2; +GO +~~START~~ +int#!#int +1#!#2 +2#!#3 +3#!#4 +4#!#5 +~~END~~ + +~~ROW COUNT: 4~~ + +DECLARE @handle int; +DECLARE @batch VARCHAR(500); +DECLARE @paramdef VARCHAR(500); +SET @batch = ' +UPDATE t1 SET a = a * 10, b = b *10 where a = @var1; +UPDATE t1 SET a = a * 10, b = b *10 where a = @var2; +' +SET @paramdef = '@var1 int, @var2 int' +EXEC SP_PREPARE @handle OUT, @paramdef, @batch +EXEC SP_EXECUTE @handle, 1, 2 +EXEC SP_EXECUTE @handle, 3, 4 +SELECT * FROM t1 ORDER BY 1, 2; +EXEC SP_UNPREPARE @handle +DROP TABLE t1; +GO +~~START~~ +int#!#int +10#!#20 +20#!#30 +30#!#40 +40#!#50 +~~END~~ + +~~ROW COUNT: 4~~ + +--- Transaction with SP_EXECUTE +CREATE TABLE t1 (a int, b int); +GO +DECLARE @handle int; +DECLARE @batch VARCHAR(500); +DECLARE @paramdef VARCHAR(500); +SET @batch = ' +INSERT INTO t1 VALUES (@v1, @v2); +INSERT INTO t1 VALUES (@v3, @v4); +' +SET @paramdef = '@v1 int, @v2 int, @v3 int, @v4 int' +EXEC SP_PREPARE @handle OUT, @paramdef, @batch +BEGIN TRANSACTION; +EXEC SP_EXECUTE @handle, 1, 2, 2, 3 +SELECT * FROM t1 ORDER BY 1, 2; +COMMIT; +SELECT * FROM t1 ORDER BY 1, 2; +BEGIN TRANSACTION; +EXEC SP_EXECUTE @handle, 3, 4, 4, 5 +SELECT * FROM t1 ORDER BY 1, 2; +ROLLBACK; +SELECT * FROM t1 ORDER BY 1, 2; +EXEC SP_UNPREPARE @handle +GO +~~START~~ +int#!#int +1#!#2 +2#!#3 +~~END~~ + +~~START~~ +int#!#int +1#!#2 +2#!#3 +~~END~~ + +~~START~~ +int#!#int +1#!#2 +2#!#3 +3#!#4 +4#!#5 +~~END~~ + +~~START~~ +int#!#int +1#!#2 +2#!#3 +~~END~~ + +~~ROW COUNT: 2~~ + +DROP TABLE t1; +GO +--- PREPARE Batch with Transaction +CREATE TABLE t1 (a int, b int); +GO +DECLARE @handle int; +DECLARE @batch VARCHAR(500); +DECLARE @paramdef VARCHAR(500); +SET @batch = ' +BEGIN TRANSACTION +INSERT INTO t1 VALUES (@v1, @v2); +INSERT INTO t1 VALUES (@v3, @v4); +SELECT * FROM t1 ORDER BY 1, 2; +IF (@v1 = 10) + COMMIT; +ELSE + ROLLBACK; +' +SET @paramdef = '@v1 int, @v2 int, @v3 int, @v4 int' +EXEC SP_PREPARE @handle OUT, @paramdef, @batch +EXEC SP_EXECUTE @handle, 10, 20, 30, 40 +SELECT * FROM t1 ORDER BY 1, 2; +EXEC SP_EXECUTE @handle, 50, 60, 70, 80 +SELECT * FROM t1 ORDER BY 1, 2; +EXEC SP_UNPREPARE @handle +GO +~~START~~ +int#!#int +10#!#20 +30#!#40 +~~END~~ + +~~START~~ +int#!#int +10#!#20 +30#!#40 +~~END~~ + +~~START~~ +int#!#int +10#!#20 +30#!#40 +50#!#60 +70#!#80 +~~END~~ + +~~START~~ +int#!#int +10#!#20 +30#!#40 +~~END~~ + +~~ROW COUNT: 2~~ + +DROP TABLE t1; +GO +-- Test Save Point +CREATE TABLE t1 ( a int, b int); +GO +DECLARE @handle int; +DECLARE @batch VARCHAR(500); +SET @batch = ' +DECLARE @handle int; +BEGIN TRANSACTION; +INSERT INTO t1 VALUES (1, 2); +SAVE TRANSACTION my_savept; +EXEC SP_PREPEXEC @handle OUT, NULL, +''INSERT INTO t1 VALUES (3, 4); + SELECT * FROM t1 ORDER BY 1, 2; + ROLLBACK TRANSACTION my_savept; + SELECT * FROM t1 ORDER BY 1, 2; +''; +SELECT * FROM t1 ORDER BY 1, 2; +ROLLBACK; +SELECT * FROM t1 ORDER BY 1, 2; +EXEC SP_UNPREPARE @handle; +' +EXEC SP_PREPARE @handle OUT, NULL, @batch; +PRINT @handle +EXEC SP_EXECUTE @handle; +EXEC SP_UNPREPARE @handle; +GO +~~START~~ +int#!#int +1#!#2 +3#!#4 +~~END~~ + +~~START~~ +int#!#int +1#!#2 +~~END~~ + +~~START~~ +int#!#int +1#!#2 +~~END~~ + +~~START~~ +int#!#int +~~END~~ + +DROP TABLE t1; +GO +--- Test string type +CREATE TABLE t1 ( a VARCHAR(10), b VARCHAR(10)); +GO +DECLARE @handle int; +EXEC SP_PREPEXEC @handle OUT, '@v1 VARCHAR(10), @v2 VARCHAR(10)', 'INSERT INTO t1 VALUES (@v1,@v2)', 'abc', 'efg' +EXEC SP_EXECUTE @handle, 'lmn', 'opq' +EXEC SP_UNPREPARE @handle +SELECT * FROM t1 ORDER BY 1, 2; +GO +~~START~~ +int#!#int +abc#!#efg +lmn#!#opq +~~END~~ + +~~ROW COUNT: 2~~ + +DROP TABLE t1; +GO +-- Test transaction begins outside the batch and commited/rollbacked inside the batch +CREATE TABLE t1 (a INT); +GO +BEGIN TRAN; +GO +DECLARE @handle INT; +DECLARE @batch VARCHAR(500); +SET @batch = 'insert into t1 values(1); commit; begin tran;' +EXEC sp_prepare @handle OUT, NULL, @batch +EXEC sp_execute @handle +EXEC sp_execute @handle +EXEC SP_UNPREPARE @handle; +COMMIT; +SELECT COUNT(*) FROM t1; +GO +~~START~~ +int +2 +~~END~~ + +~~ROW COUNT: 1~~ + +BEGIN TRAN; +GO +DECLARE @handle INT; +DECLARE @batch VARCHAR(500); +SET @batch = 'insert into t1 values(1); rollback tran; begin tran;' +EXEC sp_prepare @handle OUT, NULL, @batch +EXEC sp_execute @handle +EXEC sp_execute @handle +EXEC SP_UNPREPARE @handle; +COMMIT; +SELECT COUNT(*) FROM t1; +GO +~~START~~ +int +2 +~~END~~ + +~~ROW COUNT: 1~~ + +DROP TABLE t1; +GO +-- prepare time error 1 +DECLARE @handle int; +EXEC SP_PREPARE @handle OUT, NULL, 'SELECT * FROM t1' +SELECT @handle IS NOT NULL as 'Prepared' +GO +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: "syntax error near 'IS' at line 4 and character position 15DB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n")~~ + +-- prepare time error 1-2 +DECLARE @handle int; +EXEC SP_PREPARE @handle OUT, NULL, 'DECLARE @var int; SELECT * FROM t1 WHERE c = @var' +SELECT @handle IS NOT NULL as 'Prepared' +GO +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: "syntax error near 'IS' at line 4 and character position 15DB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n")~~ + +-- prepare time error 2 +DECLARE @handle int; +EXEC SP_PREPARE @handle OUT, NULL, 'EXEC my_proc' +SELECT @handle IS NOT NULL as 'Prepared' +GO +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: "syntax error near 'IS' at line 4 and character position 15DB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n")~~ + +-- prepare time error 2-2 +DECLARE @handle int; +EXEC SP_PREPARE @handle OUT, NULL, 'DECLARE @var int; EXEC my_proc @var' +SELECT @handle IS NOT NULL as 'Prepared' +GO +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: "syntax error near 'IS' at line 4 and character position 15DB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n")~~ + +-- runtime error 1 +DECLARE @handle int; +EXEC SP_PREPARE @handle OUT, NULL, 'SELECT * FROM t1; SELECT * FROM t1;' +SELECT @handle IS NOT NULL as 'Prepared' +EXEC SP_EXECUTE @handle +GO +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: "syntax error near 'IS' at line 4 and character position 15DB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n")~~ + +-- runtime error 2 +DECLARE @handle int; +EXEC SP_PREPARE @handle OUT, NULL, 'EXEC my_proc; EXEC my_proc;' +SELECT @handle IS NOT NULL as 'Prepared' +EXEC SP_EXECUTE @handle +GO +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: "syntax error near 'IS' at line 4 and character position 15DB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n")~~ + +-- runtime error 3 +DECLARE @handle int; +EXEC SP_PREPARE @handle OUT, NULL, 'IF (1=1) SELECT * FROM t1;' +SELECT @handle IS NOT NULL as 'Prepared' +EXEC SP_EXECUTE @handle +GO +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: "syntax error near 'IS' at line 4 and character position 15DB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n")~~ + +-- runtime error 4 +DECLARE @handle int; +EXEC SP_PREPARE @handle OUT, NULL, 'DECLARE @var int; SET @var = 1; select * from t1 where c = @var' +SELECT @handle IS NOT NULL as 'Prepared' +EXEC SP_EXECUTE @handle +GO +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: "syntax error near 'IS' at line 4 and character position 15DB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n")~~ + diff --git a/contrib/test/python/expected/pymssql/TestSQLQueries.out b/contrib/test/python/expected/pymssql/TestSQLQueries.out new file mode 100644 index 00000000000..268471c6de2 --- /dev/null +++ b/contrib/test/python/expected/pymssql/TestSQLQueries.out @@ -0,0 +1,897 @@ +#1 CREATE TABLE with primary and unique keyword +CREATE TABLE tmp(a int PRIMARY KEY, b int UNIQUE); +~~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 constraintDB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n')~~ + +INSERT INTO tmp(a,b) values(1,1); +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: 'relation "tmp" does not existDB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n')~~ + +INSERT INTO tmp(a,b) values(2,2); +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: 'relation "tmp" does not existDB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n')~~ + +SELECT * FROM tmp; +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: 'relation "tmp" does not existDB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n')~~ + +DROP TABLE tmp; +~~ERROR (Code: 3701)~~ +~~ERROR (Message: 'table "tmp" does not existDB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n')~~ + + +#2 2 table with foreign key relation +#CREATE TABLE tmp1(b int PRIMARY KEY); +#CREATE TABLE tmp2(a int PRIMARY KEY, b int FOREIGN KEY REFERENCES tmp1(b)); +#INSERT INTO tmp1(b) VALUES (1); +#INSERT INTO tmp2(a,b) values(1,1); +#SELECT * FROM tmp1; +#SELECT * FROM tmp2; +#DROP TABLE tmp2; +#DROP TABLE tmp1; + +#3 Repeated #2 with CONSTRAINT keyword +#CREATE TABLE tmp1(b int PRIMARY KEY); +#CREATE TABLE tmp2(a int, b int, PRIMARY KEY(a), CONSTRAINT FK_tmp FOREIGN KEY (b) REFERENCES tmp1(b)); +#INSERT INTO tmp1(b) VALUES (1); +#INSERT INTO tmp2(a,b) values(1,1); +#SELECT * FROM tmp1; +#SELECT * FROM tmp2; +#DROP TABLE tmp2; +#DROP TABLE tmp1; + +#4 CREATE TABLE with NOT NULL column +CREATE TABLE tmp(a int PRIMARY KEY,b int NOT NULL); +INSERT INTO tmp(a,b) values(1,1); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) values(2,1); +~~ROW COUNT: 1~~ + +#INSERT INTO tmp(a,b) values(2,NULL); +SELECT * FROM tmp; +~~START~~ +int#!#int +1#!#1 +2#!#1 +~~END~~ + +~~ROW COUNT: 2~~ + +DROP TABLE tmp; + +#5 INSERTION and DELETION +CREATE TABLE tmp(a int PRIMARY KEY); +INSERT INTO tmp(a) VALUES(1); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a) VALUES(2); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a) VALUES(3); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a) VALUES(4); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a) VALUES(5); +~~ROW COUNT: 1~~ + +SELECT * FROM tmp; +~~START~~ +int +1 +2 +3 +4 +5 +~~END~~ + +~~ROW COUNT: 5~~ + +DELETE FROM tmp WHERE a>2; +~~ROW COUNT: 3~~ + +SELECT * FROM tmp; +~~START~~ +int +1 +2 +~~END~~ + +~~ROW COUNT: 2~~ + +DROP TABLE tmp; + +#6 IS NOT NULL condition in WHERE clause +CREATE TABLE tmp(a int PRIMARY KEY,b int); +INSERT INTO tmp(a,b) values(1,1); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) values(2,1); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) values(3,NULL); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) values(4,NULL); +~~ROW COUNT: 1~~ + +SELECT * FROM tmp WHERE b IS NOT NULL; +~~START~~ +int#!#int +1#!#1 +2#!#1 +~~END~~ + +~~ROW COUNT: 2~~ + +DROP TABLE tmp; + +#7 Add new column using ALTER TABLE +CREATE TABLE tmp(a int PRIMARY KEY); +INSERT INTO tmp(a) VALUES(1); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a) VALUES(2); +~~ROW COUNT: 1~~ + +SELECT * FROM tmp; +~~START~~ +int +1 +2 +~~END~~ + +~~ROW COUNT: 2~~ + +ALTER TABLE tmp ADD b VARCHAR(20) NULL; +SELECT * FROM tmp; +~~START~~ +int#!#int +1#!# +2#!# +~~END~~ + +~~ROW COUNT: 2~~ + +INSERT INTO tmp(a,b) VALUES(4,'Dipesh'); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(5,' Dipesh'); +~~ROW COUNT: 1~~ + +SELECT * FROM tmp; +~~START~~ +int#!#int +1#!# +2#!# +4#!#Dipesh +5#!# Dipesh +~~END~~ + +~~ROW COUNT: 4~~ + +DROP TABLE tmp; + +#8 Repeated #8 with default value for newly added col +CREATE TABLE tmp(a int PRIMARY KEY); +INSERT INTO tmp(a) VALUES(1); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a) VALUES(2); +~~ROW COUNT: 1~~ + +SELECT * FROM tmp; +~~START~~ +int +1 +2 +~~END~~ + +~~ROW COUNT: 2~~ + +ALTER TABLE tmp ADD b VARCHAR(20) DEFAULT 'Dipesj'; +SELECT * FROM tmp; +~~START~~ +int#!#int +1#!#Dipesj +2#!#Dipesj +~~END~~ + +~~ROW COUNT: 2~~ + +INSERT INTO tmp(a,b) VALUES(4,'Dipesh'); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(5,' Dipesh'); +~~ROW COUNT: 1~~ + +SELECT * FROM tmp; +~~START~~ +int#!#int +1#!#Dipesj +2#!#Dipesj +4#!#Dipesh +5#!# Dipesh +~~END~~ + +~~ROW COUNT: 4~~ + +DROP TABLE tmp; + +#9 Change datatype of existing column using ALTER TABLE +CREATE TABLE tmp(a int PRIMARY KEY,b int); +INSERT INTO tmp(a,b) VALUES(1,1); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(2,2); +~~ROW COUNT: 1~~ + +SELECT * FROM tmp; +~~START~~ +int#!#int +1#!#1 +2#!#2 +~~END~~ + +~~ROW COUNT: 2~~ + +ALTER TABLE tmp ALTER COLUMN b VARCHAR(10); +SELECT * FROM tmp; +~~START~~ +int#!#int +1#!#1 +2#!#2 +~~END~~ + +~~ROW COUNT: 2~~ + +INSERT INTO tmp(a,b) VALUES(4,'Dipesh'); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(5,' Dipesh'); +~~ROW COUNT: 1~~ + +SELECT * FROM tmp; +~~START~~ +int#!#int +1#!#1 +2#!#2 +4#!#Dipesh +5#!# Dipesh +~~END~~ + +~~ROW COUNT: 4~~ + +DROP TABLE tmp; + +#10 UPDATE TABLE with fancy condition +CREATE TABLE tmp(a int PRIMARY KEY,b int); +INSERT INTO tmp(a,b) VALUES(1,1); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(2,2); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(3,3); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(4,4); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(5,5); +~~ROW COUNT: 1~~ + +SELECT * FROM tmp; +~~START~~ +int#!#int +1#!#1 +2#!#2 +3#!#3 +4#!#4 +5#!#5 +~~END~~ + +~~ROW COUNT: 5~~ + +UPDATE tmp SET b=b+1 WHERE b>2; +~~ROW COUNT: 3~~ + +SELECT * FROM tmp; +~~START~~ +int#!#int +1#!#1 +2#!#2 +3#!#4 +4#!#5 +5#!#6 +~~END~~ + +~~ROW COUNT: 5~~ + +DROP TABLE tmp; + +#11 DROP some column using ALTER TABLE +CREATE TABLE tmp(a int PRIMARY KEY,b int); +INSERT INTO tmp(a,b) VALUES(1,1); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(2,2); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(3,3); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(4,4); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(5,5); +~~ROW COUNT: 1~~ + +SELECT * FROM tmp; +~~START~~ +int#!#int +1#!#1 +2#!#2 +3#!#3 +4#!#4 +5#!#5 +~~END~~ + +~~ROW COUNT: 5~~ + +#ALTER TABLE tmp DROP COLUMN b; +#INSERT INTO tmp(a) values (6); +#SELECT * FROM tmp; +DROP TABLE tmp; + +#12 CREATE TABLE with fancy constraint +CREATE TABLE tmp(a int PRIMARY KEY CHECK (a>10),b int); +INSERT INTO tmp(a,b) VALUES(11,1); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(12,2); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(13,3); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(14,4); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(15,5); +~~ROW COUNT: 1~~ + +SELECT * FROM tmp; +~~START~~ +int#!#int +11#!#1 +12#!#2 +13#!#3 +14#!#4 +15#!#5 +~~END~~ + +~~ROW COUNT: 5~~ + +DROP TABLE tmp; + +#CREATE PROCEDURE tmp AS +#BEGIN +# CREATE TABLE dip(a int PRIMARY KEY CHECK (a>10),b int); +# INSERT INTO dip(a,b) VALUES(11,1); +# INSERT INTO dip(a,b) VALUES(12,2); +# INSERT INTO dip(a,b) VALUES(13,3); +# INSERT INTO dip(a,b) VALUES(14,4); +# INSERT INTO dip(a,b) VALUES(15,5); +# SELECT * FROM dip; +# DROP TABLE dip; +#END; + +#13 invoke simple stored procedure using EXECUTE +EXECUTE tmp; +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: 'procedure tmp() does not existDB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n')~~ + + +#14 invoke simple stored procedure using EXEC +EXEC tmp; +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: 'procedure tmp() does not existDB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n')~~ + + +#DROP PROCEDURE tmp; + +#15 UPDATE rows in existing table +CREATE TABLE tmp(a int PRIMARY KEY,b int); +INSERT INTO tmp(a,b) VALUES(1,1),(2,2),(3,3),(4,4),(5,5); +~~ROW COUNT: 5~~ + +SELECT * FROM tmp; +~~START~~ +int#!#int +1#!#1 +2#!#2 +3#!#3 +4#!#4 +5#!#5 +~~END~~ + +~~ROW COUNT: 5~~ + +UPDATE tmp SET b=b*2+1 WHERE (a>2); +~~ROW COUNT: 3~~ + +SELECT * FROM tmp; +~~START~~ +int#!#int +1#!#1 +2#!#2 +3#!#7 +4#!#9 +5#!#11 +~~END~~ + +~~ROW COUNT: 5~~ + +DROP TABLE tmp; + +#16 TRUNCATE table +CREATE TABLE tmp(a int PRIMARY KEY,b int); +INSERT INTO tmp(a,b) VALUES(1,1),(2,2),(3,3),(4,4),(5,5); +~~ROW COUNT: 5~~ + +SELECT * FROM tmp; +~~START~~ +int#!#int +1#!#1 +2#!#2 +3#!#3 +4#!#4 +5#!#5 +~~END~~ + +~~ROW COUNT: 5~~ + +TRUNCATE TABLE tmp; +SELECT * FROM tmp; +~~START~~ +int#!#int +~~END~~ + +DROP TABLE tmp; + +CREATE TABLE temp1 (i INT,j INT,t TEXT); + +CREATE TABLE temp2 ( i INT,k INT); + +INSERT INTO temp1 VALUES (1, 4, 'one'); +~~ROW COUNT: 1~~ + +INSERT INTO temp1 VALUES (2, 3, 'two'); +~~ROW COUNT: 1~~ + +INSERT INTO temp1 VALUES (3, 2, 'three'); +~~ROW COUNT: 1~~ + +INSERT INTO temp1 VALUES (4, 1, 'four'); +~~ROW COUNT: 1~~ + +INSERT INTO temp1 VALUES (5, 0, 'five'); +~~ROW COUNT: 1~~ + +INSERT INTO temp1 VALUES (6, 6, 'six'); +~~ROW COUNT: 1~~ + +INSERT INTO temp1 VALUES (7, 7, 'seven'); +~~ROW COUNT: 1~~ + +INSERT INTO temp1 VALUES (8, 8, 'eight'); +~~ROW COUNT: 1~~ + +INSERT INTO temp1 VALUES (0, NULL, 'zero'); +~~ROW COUNT: 1~~ + +INSERT INTO temp1 VALUES (NULL, NULL, NULL); +~~ROW COUNT: 1~~ + +INSERT INTO temp1 VALUES (NULL, 0, 'zero'); +~~ROW COUNT: 1~~ + + +INSERT INTO temp2 VALUES (1, -1); +~~ROW COUNT: 1~~ + +INSERT INTO temp2 VALUES (2, 2); +~~ROW COUNT: 1~~ + +INSERT INTO temp2 VALUES (3, -3); +~~ROW COUNT: 1~~ + +INSERT INTO temp2 VALUES (2, 4); +~~ROW COUNT: 1~~ + +INSERT INTO temp2 VALUES (5, -5); +~~ROW COUNT: 1~~ + +INSERT INTO temp2 VALUES (5, -5); +~~ROW COUNT: 1~~ + +INSERT INTO temp2 VALUES (0, NULL); +~~ROW COUNT: 1~~ + +INSERT INTO temp2 VALUES (NULL, NULL); +~~ROW COUNT: 1~~ + +INSERT INTO temp2 VALUES (NULL, 0); +~~ROW COUNT: 1~~ + + +#17 CROSS JOIN +SELECT * FROM temp1 CROSS JOIN temp2; +~~START~~ +int#!#int#!#int#!#int#!#int +1#!#4#!#one#!#1#!#-1 +2#!#3#!#two#!#1#!#-1 +3#!#2#!#three#!#1#!#-1 +4#!#1#!#four#!#1#!#-1 +5#!#0#!#five#!#1#!#-1 +6#!#6#!#six#!#1#!#-1 +7#!#7#!#seven#!#1#!#-1 +8#!#8#!#eight#!#1#!#-1 +0#!##!#zero#!#1#!#-1 +#!##!##!#1#!#-1 +#!#0#!#zero#!#1#!#-1 +1#!#4#!#one#!#2#!#2 +2#!#3#!#two#!#2#!#2 +3#!#2#!#three#!#2#!#2 +4#!#1#!#four#!#2#!#2 +5#!#0#!#five#!#2#!#2 +6#!#6#!#six#!#2#!#2 +7#!#7#!#seven#!#2#!#2 +8#!#8#!#eight#!#2#!#2 +0#!##!#zero#!#2#!#2 +#!##!##!#2#!#2 +#!#0#!#zero#!#2#!#2 +1#!#4#!#one#!#3#!#-3 +2#!#3#!#two#!#3#!#-3 +3#!#2#!#three#!#3#!#-3 +4#!#1#!#four#!#3#!#-3 +5#!#0#!#five#!#3#!#-3 +6#!#6#!#six#!#3#!#-3 +7#!#7#!#seven#!#3#!#-3 +8#!#8#!#eight#!#3#!#-3 +0#!##!#zero#!#3#!#-3 +#!##!##!#3#!#-3 +#!#0#!#zero#!#3#!#-3 +1#!#4#!#one#!#2#!#4 +2#!#3#!#two#!#2#!#4 +3#!#2#!#three#!#2#!#4 +4#!#1#!#four#!#2#!#4 +5#!#0#!#five#!#2#!#4 +6#!#6#!#six#!#2#!#4 +7#!#7#!#seven#!#2#!#4 +8#!#8#!#eight#!#2#!#4 +0#!##!#zero#!#2#!#4 +#!##!##!#2#!#4 +#!#0#!#zero#!#2#!#4 +1#!#4#!#one#!#5#!#-5 +2#!#3#!#two#!#5#!#-5 +3#!#2#!#three#!#5#!#-5 +4#!#1#!#four#!#5#!#-5 +5#!#0#!#five#!#5#!#-5 +6#!#6#!#six#!#5#!#-5 +7#!#7#!#seven#!#5#!#-5 +8#!#8#!#eight#!#5#!#-5 +0#!##!#zero#!#5#!#-5 +#!##!##!#5#!#-5 +#!#0#!#zero#!#5#!#-5 +1#!#4#!#one#!#5#!#-5 +2#!#3#!#two#!#5#!#-5 +3#!#2#!#three#!#5#!#-5 +4#!#1#!#four#!#5#!#-5 +5#!#0#!#five#!#5#!#-5 +6#!#6#!#six#!#5#!#-5 +7#!#7#!#seven#!#5#!#-5 +8#!#8#!#eight#!#5#!#-5 +0#!##!#zero#!#5#!#-5 +#!##!##!#5#!#-5 +#!#0#!#zero#!#5#!#-5 +1#!#4#!#one#!#0#!# +2#!#3#!#two#!#0#!# +3#!#2#!#three#!#0#!# +4#!#1#!#four#!#0#!# +5#!#0#!#five#!#0#!# +6#!#6#!#six#!#0#!# +7#!#7#!#seven#!#0#!# +8#!#8#!#eight#!#0#!# +0#!##!#zero#!#0#!# +#!##!##!#0#!# +#!#0#!#zero#!#0#!# +1#!#4#!#one#!##!# +2#!#3#!#two#!##!# +3#!#2#!#three#!##!# +4#!#1#!#four#!##!# +5#!#0#!#five#!##!# +6#!#6#!#six#!##!# +7#!#7#!#seven#!##!# +8#!#8#!#eight#!##!# +0#!##!#zero#!##!# +#!##!##!##!# +#!#0#!#zero#!##!# +1#!#4#!#one#!##!#0 +2#!#3#!#two#!##!#0 +3#!#2#!#three#!##!#0 +4#!#1#!#four#!##!#0 +5#!#0#!#five#!##!#0 +6#!#6#!#six#!##!#0 +7#!#7#!#seven#!##!#0 +8#!#8#!#eight#!##!#0 +0#!##!#zero#!##!#0 +#!##!##!##!#0 +#!#0#!#zero#!##!#0 +~~END~~ + +~~ROW COUNT: 99~~ + + +#18 INNER JOIN +SELECT temp1.i, temp1.j, temp1.t, temp2.k FROM temp1 INNER JOIN temp2 ON temp1.i=temp2.i; +~~START~~ +int#!#int#!#int#!#int +0#!##!#zero#!# +1#!#4#!#one#!#-1 +2#!#3#!#two#!#2 +2#!#3#!#two#!#4 +3#!#2#!#three#!#-3 +5#!#0#!#five#!#-5 +5#!#0#!#five#!#-5 +~~END~~ + +~~ROW COUNT: 7~~ + +SELECT temp1.i, temp1.j, temp1.t, temp2.k FROM temp1 JOIN temp2 ON temp1.i=temp2.i; +~~START~~ +int#!#int#!#int#!#int +0#!##!#zero#!# +1#!#4#!#one#!#-1 +2#!#3#!#two#!#2 +2#!#3#!#two#!#4 +3#!#2#!#three#!#-3 +5#!#0#!#five#!#-5 +5#!#0#!#five#!#-5 +~~END~~ + +~~ROW COUNT: 7~~ + + +#19 LEFT JOIN +SELECT * FROM temp1 LEFT OUTER JOIN temp2 ON temp1.i=temp2.k; +~~START~~ +int#!#int#!#int#!#int#!#int +0#!##!#zero#!##!#0 +1#!#4#!#one#!##!# +2#!#3#!#two#!#2#!#2 +3#!#2#!#three#!##!# +4#!#1#!#four#!#2#!#4 +5#!#0#!#five#!##!# +6#!#6#!#six#!##!# +7#!#7#!#seven#!##!# +8#!#8#!#eight#!##!# +#!##!##!##!# +#!#0#!#zero#!##!# +~~END~~ + +~~ROW COUNT: 11~~ + + +#20 RIGHT JOIN +SELECT * FROM temp1 RIGHT OUTER JOIN temp2 ON temp1.i=temp2.i; +~~START~~ +int#!#int#!#int#!#int#!#int +0#!##!#zero#!#0#!# +1#!#4#!#one#!#1#!#-1 +2#!#3#!#two#!#2#!#2 +2#!#3#!#two#!#2#!#4 +3#!#2#!#three#!#3#!#-3 +5#!#0#!#five#!#5#!#-5 +5#!#0#!#five#!#5#!#-5 +#!##!##!##!# +#!##!##!##!#0 +~~END~~ + +~~ROW COUNT: 9~~ + + +#21 FULL OUTER JOIN +SELECT * FROM temp1,temp2; +~~START~~ +int#!#int#!#int#!#int#!#int +1#!#4#!#one#!#1#!#-1 +2#!#3#!#two#!#1#!#-1 +3#!#2#!#three#!#1#!#-1 +4#!#1#!#four#!#1#!#-1 +5#!#0#!#five#!#1#!#-1 +6#!#6#!#six#!#1#!#-1 +7#!#7#!#seven#!#1#!#-1 +8#!#8#!#eight#!#1#!#-1 +0#!##!#zero#!#1#!#-1 +#!##!##!#1#!#-1 +#!#0#!#zero#!#1#!#-1 +1#!#4#!#one#!#2#!#2 +2#!#3#!#two#!#2#!#2 +3#!#2#!#three#!#2#!#2 +4#!#1#!#four#!#2#!#2 +5#!#0#!#five#!#2#!#2 +6#!#6#!#six#!#2#!#2 +7#!#7#!#seven#!#2#!#2 +8#!#8#!#eight#!#2#!#2 +0#!##!#zero#!#2#!#2 +#!##!##!#2#!#2 +#!#0#!#zero#!#2#!#2 +1#!#4#!#one#!#3#!#-3 +2#!#3#!#two#!#3#!#-3 +3#!#2#!#three#!#3#!#-3 +4#!#1#!#four#!#3#!#-3 +5#!#0#!#five#!#3#!#-3 +6#!#6#!#six#!#3#!#-3 +7#!#7#!#seven#!#3#!#-3 +8#!#8#!#eight#!#3#!#-3 +0#!##!#zero#!#3#!#-3 +#!##!##!#3#!#-3 +#!#0#!#zero#!#3#!#-3 +1#!#4#!#one#!#2#!#4 +2#!#3#!#two#!#2#!#4 +3#!#2#!#three#!#2#!#4 +4#!#1#!#four#!#2#!#4 +5#!#0#!#five#!#2#!#4 +6#!#6#!#six#!#2#!#4 +7#!#7#!#seven#!#2#!#4 +8#!#8#!#eight#!#2#!#4 +0#!##!#zero#!#2#!#4 +#!##!##!#2#!#4 +#!#0#!#zero#!#2#!#4 +1#!#4#!#one#!#5#!#-5 +2#!#3#!#two#!#5#!#-5 +3#!#2#!#three#!#5#!#-5 +4#!#1#!#four#!#5#!#-5 +5#!#0#!#five#!#5#!#-5 +6#!#6#!#six#!#5#!#-5 +7#!#7#!#seven#!#5#!#-5 +8#!#8#!#eight#!#5#!#-5 +0#!##!#zero#!#5#!#-5 +#!##!##!#5#!#-5 +#!#0#!#zero#!#5#!#-5 +1#!#4#!#one#!#5#!#-5 +2#!#3#!#two#!#5#!#-5 +3#!#2#!#three#!#5#!#-5 +4#!#1#!#four#!#5#!#-5 +5#!#0#!#five#!#5#!#-5 +6#!#6#!#six#!#5#!#-5 +7#!#7#!#seven#!#5#!#-5 +8#!#8#!#eight#!#5#!#-5 +0#!##!#zero#!#5#!#-5 +#!##!##!#5#!#-5 +#!#0#!#zero#!#5#!#-5 +1#!#4#!#one#!#0#!# +2#!#3#!#two#!#0#!# +3#!#2#!#three#!#0#!# +4#!#1#!#four#!#0#!# +5#!#0#!#five#!#0#!# +6#!#6#!#six#!#0#!# +7#!#7#!#seven#!#0#!# +8#!#8#!#eight#!#0#!# +0#!##!#zero#!#0#!# +#!##!##!#0#!# +#!#0#!#zero#!#0#!# +1#!#4#!#one#!##!# +2#!#3#!#two#!##!# +3#!#2#!#three#!##!# +4#!#1#!#four#!##!# +5#!#0#!#five#!##!# +6#!#6#!#six#!##!# +7#!#7#!#seven#!##!# +8#!#8#!#eight#!##!# +0#!##!#zero#!##!# +#!##!##!##!# +#!#0#!#zero#!##!# +1#!#4#!#one#!##!#0 +2#!#3#!#two#!##!#0 +3#!#2#!#three#!##!#0 +4#!#1#!#four#!##!#0 +5#!#0#!#five#!##!#0 +6#!#6#!#six#!##!#0 +7#!#7#!#seven#!##!#0 +8#!#8#!#eight#!##!#0 +0#!##!#zero#!##!#0 +#!##!##!##!#0 +#!#0#!#zero#!##!#0 +~~END~~ + +~~ROW COUNT: 99~~ + + +DROP TABLE temp1; +DROP TABLE temp2; + +#22 dropping all columns +CREATE TABLE tmp(a int PRIMARY KEY,b int); +INSERT INTO tmp(a,b) VALUES(1,1); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(2,2); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(3,3); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(4,4); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(5,5); +~~ROW COUNT: 1~~ + +SELECT * FROM tmp; +~~START~~ +int#!#int +1#!#1 +2#!#2 +3#!#3 +4#!#4 +5#!#5 +~~END~~ + +~~ROW COUNT: 5~~ + +#ALTER TABLE tmp DROP COLUMN b; +#ALTER TABLE tmp DROP COLUMN a; +#SELECT * FROM tmp; +DROP TABLE tmp; + +#23 +CREATE TABLE DATE_dt (a DATE); +INSERT INTO DATE_dt(a) values('2000-12-13'); +~~ROW COUNT: 1~~ + +INSERT INTO DATE_dt(a) values('1900-02-28'); +~~ROW COUNT: 1~~ + +INSERT INTO DATE_dt(a) values('0001-01-01'); +~~ROW COUNT: 1~~ + +INSERT INTO DATE_dt(a) values('9999-12-31'); +~~ROW COUNT: 1~~ + +INSERT INTO DATE_dt(a) values(NULL); +~~ROW COUNT: 1~~ + +SELECT * FROM DATE_dt; +~~START~~ +int +2000-12-13 +1900-02-28 +0001-01-01 +9999-12-31 + +~~END~~ + +~~ROW COUNT: 5~~ + +ALTER TABLE DATE_dt ALTER COLUMN a DATETIME; +~~ERROR (Code: 517)~~ +~~ERROR (Message: 'data out of range for datetimeDB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n')~~ + +SELECT * FROM DATE_dt; +~~START~~ +int +2000-12-13 +1900-02-28 +0001-01-01 +9999-12-31 + +~~END~~ + +~~ROW COUNT: 5~~ + +DROP TABLE DATE_dt; diff --git a/contrib/test/python/expected/pymssql/TestSimpleErrorsWithImplicitTran.out b/contrib/test/python/expected/pymssql/TestSimpleErrorsWithImplicitTran.out new file mode 100644 index 00000000000..73edd6b9ed2 --- /dev/null +++ b/contrib/test/python/expected/pymssql/TestSimpleErrorsWithImplicitTran.out @@ -0,0 +1,20 @@ +#Setup +CREATE TABLE simpleErrorTable (a varchar(15) UNIQUE, b nvarchar(25), c int PRIMARY KEY, d char(15) DEFAULT 'Whoops!', e nchar(25), f datetime, g numeric(4,1) CHECK (g >= 103.5)) +~~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 constraintDB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n')~~ + +SET IMPLICIT_TRANSACTIONS ON + +#Run error handling tests +include#!#input/errorHandling/TestSimpleErrors.sql +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: "syntax error near '!' at line 1 and character position 8DB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n")~~ + + +#Cleanup +IF @@trancount > 0 ROLLBACK +SET IMPLICIT_TRANSACTIONS OFF +DROP TABLE simpleerrortable +~~ERROR (Code: 3701)~~ +~~ERROR (Message: 'table "simpleerrortable" does not existDB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n')~~ + diff --git a/contrib/test/python/expected/pymssql/TestSmallDatetime.out b/contrib/test/python/expected/pymssql/TestSmallDatetime.out new file mode 100644 index 00000000000..68f1960bc8c --- /dev/null +++ b/contrib/test/python/expected/pymssql/TestSmallDatetime.out @@ -0,0 +1,152 @@ +CREATE TABLE SMALLDATETIME_dt (a SMALLDATETIME) +prepst#!# INSERT INTO SMALLDATETIME_dt(a) values(%s) #!#SMALLDATETIME|-|a|-|2000-12-13 12:58:23 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLDATETIME|-|a|-|2007-05-08 12:35:29 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLDATETIME|-|a|-|2007-05-08 12:35:30 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLDATETIME|-|a|-|2007-05-08 12:59:59.998 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLDATETIME|-|a|-|2000-02-28 23:59:59.999 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLDATETIME|-|a|-|1900-02-28 23:59:59.999 +~~ROW COUNT: 1~~ + +#prepst#!#exec#!#SMALLDATETIME|-|a|-|2000-02-28 23:45:29.999 +prepst#!#exec#!#SMALLDATETIME|-|a|-|2000-02-28 23:45:30 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLDATETIME|-|a|-|2000-02-28 23:45:29 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLDATETIME|-|a|-|1900-02-28 23:45:30 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLDATETIME|-|a|-|1900-02-28 23:45:29 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLDATETIME|-|a|-|2000-12-13 12:58:30 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLDATETIME|-|a|-|2000-02-28 23:45:29.998 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLDATETIME|-|a|-|1900-01-01 00:00:00 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLDATETIME|-|a|-|2079-06-06 23:59:29 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLDATETIME|-|a|-| +~~ROW COUNT: 1~~ + +SELECT * FROM SMALLDATETIME_dt; +~~START~~ +int +2000-12-13 12:58:00 +2007-05-08 12:35:00 +2007-05-08 12:36:00 +2007-05-08 13:00:00 +2000-02-29 00:00:00 +1900-03-01 00:00:00 +2000-02-28 23:46:00 +2000-02-28 23:45:00 +1900-02-28 23:46:00 +1900-02-28 23:45:00 +2000-12-13 12:59:00 +2000-02-28 23:45:00 +1900-01-01 00:00:00 +2079-06-06 23:59:00 + +~~END~~ + +~~ROW COUNT: 15~~ + +INSERT INTO SMALLDATETIME_dt(a) values('2000-12-13 12:58:23'); +~~ROW COUNT: 1~~ + +INSERT INTO SMALLDATETIME_dt(a) values('2007-05-08 12:35:29'); +~~ROW COUNT: 1~~ + +INSERT INTO SMALLDATETIME_dt(a) values('2007-05-08 12:35:30'); +~~ROW COUNT: 1~~ + +INSERT INTO SMALLDATETIME_dt(a) values('2007-05-08 12:59:59.998'); +~~ROW COUNT: 1~~ + +INSERT INTO SMALLDATETIME_dt(a) values('2000-02-28 23:59:59.999'); +~~ROW COUNT: 1~~ + +INSERT INTO SMALLDATETIME_dt(a) values('1900-02-28 23:59:59.999'); +~~ROW COUNT: 1~~ + +INSERT INTO SMALLDATETIME_dt(a) values('2000-02-28 23:45:29.999'); +~~ROW COUNT: 1~~ + +INSERT INTO SMALLDATETIME_dt(a) values('2000-02-28 23:45:30'); +~~ROW COUNT: 1~~ + +INSERT INTO SMALLDATETIME_dt(a) values('2000-02-28 23:45:29'); +~~ROW COUNT: 1~~ + +INSERT INTO SMALLDATETIME_dt(a) values('1900-02-28 23:45:29'); +~~ROW COUNT: 1~~ + +INSERT INTO SMALLDATETIME_dt(a) values('1900-12-13 12:58:30'); +~~ROW COUNT: 1~~ + +INSERT INTO SMALLDATETIME_dt(a) values('2000-02-28 23:45:29.998'); +~~ROW COUNT: 1~~ + +INSERT INTO SMALLDATETIME_dt(a) values('1900-01-01 00:00:00'); +~~ROW COUNT: 1~~ + +INSERT INTO SMALLDATETIME_dt(a) values('2079-06-06 23:59:29'); +~~ROW COUNT: 1~~ + +INSERT INTO SMALLDATETIME_dt(a) values(NULL); +~~ROW COUNT: 1~~ + +SELECT * FROM SMALLDATETIME_dt; +~~START~~ +int +2000-12-13 12:58:00 +2007-05-08 12:35:00 +2007-05-08 12:36:00 +2007-05-08 13:00:00 +2000-02-29 00:00:00 +1900-03-01 00:00:00 +2000-02-28 23:46:00 +2000-02-28 23:45:00 +1900-02-28 23:46:00 +1900-02-28 23:45:00 +2000-12-13 12:59:00 +2000-02-28 23:45:00 +1900-01-01 00:00:00 +2079-06-06 23:59:00 + +2000-12-13 12:58:00 +2007-05-08 12:35:00 +2007-05-08 12:36:00 +2007-05-08 13:00:00 +2000-02-29 00:00:00 +1900-03-01 00:00:00 +2000-02-28 23:46:00 +2000-02-28 23:46:00 +2000-02-28 23:45:00 +1900-02-28 23:45:00 +1900-12-13 12:59:00 +2000-02-28 23:45:00 +1900-01-01 00:00:00 +2079-06-06 23:59:00 + +~~END~~ + +~~ROW COUNT: 30~~ + +DROP TABLE SMALLDATETIME_dt; diff --git a/contrib/test/python/expected/pymssql/TestSmallInt.out b/contrib/test/python/expected/pymssql/TestSmallInt.out new file mode 100644 index 00000000000..d2b7f764c6e --- /dev/null +++ b/contrib/test/python/expected/pymssql/TestSmallInt.out @@ -0,0 +1,106 @@ +CREATE TABLE SMALLINT_dt (a SMALLINT) +prepst#!# INSERT INTO SMALLINT_dt(a) values(%s) #!#SMALLINT|-|a|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLINT|-|a|-|-10 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLINT|-|a|-|100 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLINT|-|a|-|002 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLINT|-|a|-|-029 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLINT|-|a|-|-1234 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLINT|-|a|-|876 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLINT|-|a|-|-32768 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLINT|-|a|-|32767 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLINT|-|a|-| +~~ROW COUNT: 1~~ + +SELECT * FROM SMALLINT_dt; +~~START~~ +int +0 +-10 +100 +2 +-29 +-1234 +876 +-32768 +32767 + +~~END~~ + +~~ROW COUNT: 10~~ + +INSERT INTO SMALLINT_dt(a) values(0) +~~ROW COUNT: 1~~ + +INSERT INTO SMALLINT_dt(a) values(-10) +~~ROW COUNT: 1~~ + +INSERT INTO SMALLINT_dt(a) values(100) +~~ROW COUNT: 1~~ + +INSERT INTO SMALLINT_dt(a) values(002) +~~ROW COUNT: 1~~ + +INSERT INTO SMALLINT_dt(a) values(-029) +~~ROW COUNT: 1~~ + +INSERT INTO SMALLINT_dt(a) values(-1234) +~~ROW COUNT: 1~~ + +INSERT INTO SMALLINT_dt(a) values(876) +~~ROW COUNT: 1~~ + +INSERT INTO SMALLINT_dt(a) values(-32768) +~~ROW COUNT: 1~~ + +INSERT INTO SMALLINT_dt(a) values(32767) +~~ROW COUNT: 1~~ + +INSERT INTO SMALLINT_dt(a) values(NULL) +~~ROW COUNT: 1~~ + +SELECT * FROM SMALLINT_dt; +~~START~~ +int +0 +-10 +100 +2 +-29 +-1234 +876 +-32768 +32767 + +0 +-10 +100 +2 +-29 +-1234 +876 +-32768 +32767 + +~~END~~ + +~~ROW COUNT: 20~~ + +DROP TABLE SMALLINT_dt; diff --git a/contrib/test/python/expected/pymssql/TestStoredProcedures.out b/contrib/test/python/expected/pymssql/TestStoredProcedures.out new file mode 100644 index 00000000000..ae3f61c4add --- /dev/null +++ b/contrib/test/python/expected/pymssql/TestStoredProcedures.out @@ -0,0 +1,185 @@ +# PROCEDURE WITH NO BODY, works with babel but not with sql +#create procedure sp_test AS BEGIN END; +# PROCEDURE WITH NO PARAMS +create table temp_sp2(a int); +CREATE PROCEDURE sp_test AS BEGIN insert into temp_sp2 values(1); END; +storedproc#!#prep#!#sp_test#!# +~~ROW COUNT: 1~~ + +SELECT * FROM temp_sp2; +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +drop table temp_sp2; +drop Procedure sp_test; +# PROCEDURE WITH INPUT PARAMETER +#drop table temp_sp; +create table temp_sp(a int); +Create Procedure stored_proc1 (@a int) As Begin insert into temp_sp values(@a) End; +# NOT WORKING FOR BABEL,RAISED JIRA 444 +storedproc#!#prep#!#stored_proc1#!#int|-|a|-|-100|-|input +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: "syntax error near '?' at line 1 and character position 18DB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n")~~ + +# MISMATCH IN RETURN VALUES +exec stored_proc1 -200 +~~ROW COUNT: 1~~ + +exec stored_proc1 0 +~~ROW COUNT: 1~~ + +exec stored_proc1 -1 +~~ROW COUNT: 1~~ + +exec stored_proc1 2 +~~ROW COUNT: 1~~ + +# filed Jira on this, doesnt work for babel +#exec stored_proc1 2.2 +SELECT * FROM temp_sp; +~~START~~ +int +-200 +0 +-1 +2 +~~END~~ + +~~ROW COUNT: 4~~ + +DROP table temp_sp; +DROP Procedure stored_proc1 +# input parameter +CREATE PROCEDURE sp_test1 (@a INT) AS BEGIN SET @a=100; Select @a as a; END; +exec sp_test1 2 +~~START~~ +int +100 +~~END~~ + +~~ROW COUNT: 1~~ + +Declare @a int;Set @a=1; exec sp_test1 @a;select @a as a; +~~START~~ +int +100 +~~END~~ + +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +storedproc#!#prep#!#sp_test1#!#int|-|a|-|1|-|input +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: "syntax error near '?' at line 1 and character position 14DB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n")~~ + +storedproc#!#prep#!#sp_test1#!#int|-|a|-|10|-|input +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: "syntax error near '?' at line 1 and character position 14DB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n")~~ + +DROP PROCEDURE sp_test1 +# TESTING OUT PARAMETERS FOR ALL THE DATATYPES +# int +CREATE PROCEDURE sp_test1 (@a INT OUTPUT) AS BEGIN SET @a=100; Select @a as a; END; +#Declare @a int;Set @a=1; exec sp_test1 @a;select @a as a; +DROP PROCEDURE sp_test1 +# smallint +CREATE PROCEDURE sp_test2 (@a SMALLINT OUTPUT) AS BEGIN SET @a=100; Select @a as a; END; +#Declare @a smallint;Set @a=1; exec sp_test2 @a;select @a as a; +DROP PROCEDURE sp_test2 +# bigint +CREATE PROCEDURE sp_test3 (@a BIGINT OUTPUT) AS BEGIN SET @a=100; Select @a as a; END; +DROP PROCEDURE sp_test3 +# tinyint +#CREATE PROCEDURE sp_test4 (@a tinyint OUTPUT) AS BEGIN SET @a=100; Select @a as a; END; +#storedproc#!#prep#!#sp_test4#!#tinyint|-|a|-|10|-|output +#storedproc#!#prep#!#sp_test4#!#tinyint|-|a|-|10|-|inputoutput +#DROP PROCEDURE sp_test4 +# float +CREATE PROCEDURE sp_test5 (@a float OUTPUT) AS BEGIN SET @a=100.12; Select @a as a; END; +#Declare @a float;Set @a=1.1; exec sp_test5 @a;select @a as a; +DROP PROCEDURE sp_test5 +# varchar +#CREATE PROCEDURE sp_test6 (@a varchar OUTPUT) AS BEGIN SET @a='helloworld'; Select @a as a; END; +#storedproc#!#prep#!#sp_test6#!#varchar|-|a|-|hello|-|output +#storedproc#!#prep#!#sp_test6#!#varchar|-|a|-|hello|-|inputoutput +#DROP PROCEDURE sp_test6 +# char BABEL-705 +#CREATE PROCEDURE sp_test7 (@a char OUTPUT) AS BEGIN SET @a='b'; Select @a as a; END; +#Declare @a varchar;Set @a='h'; exec sp_test7 @a;select @a as a; +#storedproc#!#prep#!#sp_test7#!#char|-|a|-|t|-|output +#storedproc#!#prep#!#sp_test7#!#char|-|a|-|t|-|inputoutput +#DROP PROCEDURE sp_test7 +# nvarchar +#CREATE PROCEDURE sp_test9 (@a nvarchar OUTPUT) AS BEGIN SET @a='helloworld'; Select @a as a; END; +#Declare @a nvarchar;Set @a='hello'; exec sp_test9 @a;select @a as a; +#storedproc#!#prep#!#sp_test9#!#varchar|-|a|-|hello|-|output +#storedproc#!#prep#!#sp_test9#!#varchar|-|a|-|hello|-|inputoutput +#DROP PROCEDURE sp_test9 +# numeric +CREATE PROCEDURE sp_test10 (@a numeric(10,4) OUTPUT) AS BEGIN SET @a=100.41; Select @a as a; END; +#Declare @a numeric(10,4);Set @a=10.04; exec sp_test10 @a;select @a as a; +#storedproc#!#prep#!#sp_test10#!#numeric|-|a|-|123|-|10|-|3|-|output +#storedproc#!#prep#!#sp_test10#!#numeric|-|a|-|123|-|10|-|2|-|inputoutput +DROP PROCEDURE sp_test10 +# decimal +CREATE PROCEDURE sp_test11 (@a decimal(10,4) OUTPUT) AS BEGIN SET @a=100.41; Select @a as a; END; +#Declare @a decimal(10,4);Set @a=10.04; exec sp_test11 @a;select @a as a; +#storedproc#!#prep#!#sp_test11#!#decimal|-|a|-|123|-|10|-|3|-|output +#storedproc#!#prep#!#sp_test11#!#decimal|-|a|-|123|-|10|-|2|-|inputoutput +DROP PROCEDURE sp_test11 +# binary +#CREATE PROCEDURE sp_test12 (@a binary OUTPUT) AS BEGIN SET @a=0x121; Select @a as a; END; +#exec sp_test12 0x122 +#Declare @a binary;Set @a=0x121; exec sp_test12 @a;select @a as a; +#storedproc#!#prep#!#sp_test12#!#binary|-|a|-|0x122|-|output +#storedproc#!#prep#!#sp_test12#!#binary|-|a|-|0x122|-|inputoutput +#DROP PROCEDURE sp_test12 +# varbinary BABEL-701 +#CREATE PROCEDURE sp_test13 (@a varbinary OUTPUT) AS BEGIN SET @a=0x121; Select @a as a; END; +#exec sp_test13 0x122 +#Declare @a varbinary;Set @a=0x122; exec sp_test13 @a;select @a as a; +#storedproc#!#prep#!#sp_test13#!#varbinary|-|a|-|0x122|-|output +#storedproc#!#prep#!#sp_test13#!#varbinary|-|a|-|0x122|-|inputoutput +#DROP PROCEDURE sp_test13 +# date +CREATE PROCEDURE sp_test14 (@a date output) AS BEGIN SET @a='1999-1-3'; Select @a as a; END; +#Declare @a DATE;Set @a='9999-12-31'; exec sp_test14 @a;select @a as a; +DROP PROCEDURE sp_test14 +# time +#CREATE PROCEDURE sp_test15 (@a time(4) OUTPUT) AS BEGIN SET @a='11:25:07.123'; Select @a as a; END; +#Declare @a Time;Set @a='12:45:37.123'; exec sp_test15 @a;select @a as a; +#storedproc#!#prep#!#sp_test15#!#Time|-|a|-|12:45:37.123|-|3|-|output +#storedproc#!#prep#!#sp_test15#!#Time|-|a|-|12:45:37.123|-|3|-|inputoutput +#DROP PROCEDURE sp_test15 +# dateime BABEL-694 +#CREATE PROCEDURE sp_test16 (@a datetime output) AS BEGIN SET @a='2004-05-18 13:59:59.995'; Select @a as a; END; +#Declare @a DATETIME;Set @a='2000-02-28 23:59:59.995'; exec sp_test16 @a;select @a as a; +#storedproc#!#prep#!#sp_test16#!#DATETIME|-|a|-|2000-02-28 23:59:59.995|-|output +#storedproc#!#prep#!#sp_test16#!#DATETIME|-|a|-|2000-02-28 23:59:59.995|-|inputoutput +#DROP PROCEDURE sp_test16 +# datetime2 +#CREATE PROCEDURE sp_test17 (@a datetime2(5) OUTPUT) AS BEGIN SET @a='2014-10-2 1:45:37.123456'; Select @a as a; END; +#Declare @a Datetime2;Set @a='2016-10-23 12:45:37.123456'; exec sp_test17 @a;select @a as a; +#storedproc#!#prep#!#sp_test17#!#Datetime2|-|a|-|2016-10-23 12:45:37.123456|-|5|-|output +#storedproc#!#prep#!#sp_test17#!#Datetime2|-|a|-|2016-10-23 12:45:37.123456|-|5|-|inputoutput +#DROP PROCEDURE sp_test17 +# smalldatetime BABEL-694 +#CREATE PROCEDURE sp_test18 (@a smalldatetime output) AS BEGIN SET @a='2010-02-03 12:58:23'; Select @a as a; END; +#Declare @a SMALLDATETIME;Set @a='2000-12-13 12:58:23'; exec sp_test18 @a;select @a as a; +#storedproc#!#prep#!#sp_test18#!#SMALLDATETIME|-|a|-|2000-12-13 12:58:23|-|output +#storedproc#!#prep#!#sp_test18#!#SMALLDATETIME|-|a|-|2000-12-13 12:58:23|-|inputoutput +#DROP PROCEDURE sp_test18 +# UID +#CREATE PROCEDURE sp_test19 (@a uniqueidentifier OUTPUT) AS BEGIN SET @a='ce8af10a-2709-43b0-9e4e-a02753929d17'; Select @a as a; END; +#Declare @a uniqueidentifier;Set @a='5b7c2e8d-6d90-411d-8e19-9a81067e6f6c'; exec sp_test19 @a;select @a as a; +#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 diff --git a/contrib/test/python/expected/pymssql/TestText.out b/contrib/test/python/expected/pymssql/TestText.out new file mode 100644 index 00000000000..d7df8afb030 --- /dev/null +++ b/contrib/test/python/expected/pymssql/TestText.out @@ -0,0 +1,34 @@ +CREATE TABLE TEXT_dt (a text, b ntext) +#path to file should be with respect to root of test suite +prepst#!# INSERT INTO TEXT_dt(a, b) values(%s, %s) #!#TEXT|-|a|-|utils/sample.txt#!#NTEXT|-|b|-|utils/sample.txt +~~ROW COUNT: 1~~ + +prepst#!#exec#!#TEXT|-|a|-|utils/blank.txt#!#NTEXT|-|b|-|utils/blank.txt +~~ROW COUNT: 1~~ + +prepst#!#exec#!#TEXT|-|a|-|#!#NTEXT|-|b|-| +~~ROW COUNT: 1~~ + +prepst#!#exec#!#TEXT|-|a|-|#!#NTEXT|-|b|-|utils/utf16.txt +~~ROW COUNT: 1~~ + +prepst#!#exec#!#TEXT|-|a|-|#!#NTEXT|-|b|-|utils/emojisText.txt +~~ROW COUNT: 1~~ + +prepst#!#exec#!#TEXT|-|a|-|#!#NTEXT|-|b|-|utils/devanagari.txt +~~ROW COUNT: 1~~ + +SELECT * FROM TEXT_dt; +~~START~~ +int#!#int +AAAAAAAAAAAAAAAAAAAABBBBBBBBBBCCCCCbadksjvbajsdcbvjadssejvhsdbfjhcgvasdhgcvsj21639812365091264#!#AAAAAAAAAAAAAAAAAAAABBBBBBBBBBCCCCCbadksjvbajsdcbvjadssejvhsdbfjhcgvasdhgcvsj21639812365091264 +#!# +#!# +#!# !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƻƼƽƾƿǀǁǂǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴǵǶǷǸǹǺǻǼǽǾǿȀȁȂȃȄȅȆȇȈȉȊȋȌȍȎȏȐȑȒȓȔȕȖȗȘșȚțȜȝȞȟȠȡȢȣȤȥȦȧȨȩȪȫȬȭȮȯȰȱȲȳȴȵȶȷȸȹȺȻȼȽȾȿɀɁɂɃɄɅɆɇɈɉɊɋɌɍɎɏɐɑɒɓɔɕɖɗɘəɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯʰʱʲʳʴʵʶʷʸʹʺʻʼʽʾʿˀˁ˂˃˄˅ˆˇˈˉˊˋˌˍˎˏːˑ˒˓˔˕˖˗˘˙˚˛˜˝˞˟ˠˡˢˣˤ˥˦˧˨˩˪˫ˬ˭ˮ˯˰˱˲˳˴˵˶˷˸˹˺˻˼˽˾˿̴̵̶̷̸̡̢̧̨̛̖̗̘̙̜̝̞̟̠̣̤̥̦̩̪̫̬̭̮̯̰̱̲̳̹̺̻̼͇͈͉͍͎̀́̂̃̄̅̆̇̈̉̊̋̌̍̎̏̐̑̒̓̔̽̾̿̀́͂̓̈́͆͊͋͌̕̚ͅ͏͓͔͕͖͙͚͐͑͒͗͛ͣͤͥͦͧͨͩͪͫͬͭͮͯ͘͜͟͢͝͞͠͡ͰͱͲͳʹ͵Ͷͷͺͻͼͽ;΄΅Ά·ΈΉΊΌΎΏΐΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩΪΫάέήίΰαβγδεζηθικλμνξοπρςστυφχψωϊϋόύώϏϐϑϒϓϔϕϖϗϘϙϚϛϜϝϞϟϠϡϢϣϤϥϦϧϨϩϪϫϬϭϮϯϰϱϲϳϴϵ϶ϷϸϹϺϻϼϽϾϿЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяѐёђѓєѕіїјљњћќѝўџѠѡѢѣѤѥѦѧѨѩѪѫѬѭѮѯѰѱѲѳѴѵѶѷѸѹѺѻѼѽѾѿҀҁ҂҃҄҅҆҇҈҉ҊҋҌҍҎҏҐґҒғҔҕҖҗҘҙҚқҜҝҞҟҠҡҢңҤҥҦҧҨҩҪҫҬҭҮүҰұҲҳҴҵҶҷҸҹҺһҼҽҾҿӀӁӂӃӄӅӆӇӈӉӊӋӌӍӎӏӐӑӒӓӔӕӖӗӘәӚӛӜӝӞӟӠӡӢӣӤӥӦӧӨөӪӫӬӭӮӯӰӱӲӳӴӵӶӷӸӹӺӻӼӽӾӿԀԁԂԃԄԅԆԇԈԉԊԋԌԍԎԏԐԑԒԓԔԕԖԗԘԙԚԛԜԝԞԟԠԡԢԣԤԥԦԧԱԲԳԴԵԶԷԸԹԺԻԼԽԾԿՀՁՂՃՄՅՆՇՈՉՊՋՌՍՎՏՐՑՒՓՔՕՖՙ՚՛՜՝՞՟աբգդեզէըթժիլխծկհձղճմյնշոչպջռսվտրցւփքօֆև։֊֏ְֱֲֳִֵֶַָֹֺֻּֽ֑֖֛֢֣֤֥֦֧֪֚֭֮֒֓֔֕֗֘֙֜֝֞֟֠֡֨֩֫֬֯־ֿ׀ׁׂ׃ׅׄ׆ׇאבגדהוזחטיךכלםמןנסעףפץצקרשתװױײ׳״؀؁؂؃؄؆؇؈؉؊؋،؍؎؏ؘؙؚؐؑؒؓؔؕؖؗ؛؞؟ؠءآأؤإئابةتثجحخدذرزسشصضطظعغػؼؽؾؿـفقكلمنهوىيًٌٍَُِّْٕٖٜٟٓٔٗ٘ٙٚٛٝٞ٠١٢٣٤٥٦٧٨٩٪٫٬٭ٮٯٰٱٲٳٴٵٶٷٸٹٺٻټٽپٿڀځڂڃڄڅچڇڈډڊڋڌڍڎڏڐڑڒړڔڕږڗژڙښڛڜڝڞڟڠڡڢڣڤڥڦڧڨکڪګڬڭڮگڰڱڲڳڴڵڶڷڸڹںڻڼڽھڿۀہۂۃۄۅۆۇۈۉۊۋیۍێۏېۑےۓ۔ەۖۗۘۙۚۛۜ۝۞ۣ۟۠ۡۢۤۥۦۧۨ۩۪ۭ۫۬ۮۯ۰۱۲۳۴۵۶۷۸۹ۺۻۼ۽۾ۿ܀܁܂܃܄܅܆܇܈܉܊܋܌܍܏ܐܑܒܓܔܕܖܗܘܙܚܛܜܝܞܟܠܡܢܣܤܥܦܧܨܩܪܫܬܭܮܯܱܴܷܸܹܻܼܾ݂݄݆݈ܰܲܳܵܶܺܽܿ݀݁݃݅݇݉݊ݍݎݏݐݑݒݓݔݕݖݗݘݙݚݛݜݝݞݟݠݡݢݣݤݥݦݧݨݩݪݫݬݭݮݯݰݱݲݳݴݵݶݷݸݹݺݻݼݽݾݿހށނރބޅކއވމފދތލގޏސޑޒޓޔޕޖޗޘޙޚޛޜޝޞޟޠޡޢޣޤޥަާިީުޫެޭޮޯްޱ߀߁߂߃߄߅߆߇߈߉ߊߋߌߍߎߏߐߑߒߓߔߕߖߗߘߙߚߛߜߝߞߟߠߡߢߣߤߥߦߧߨߩߪ߲߫߬߭߮߯߰߱߳ߴߵ߶߷߸߹ߺࠀࠁࠂࠃࠄࠅࠆࠇࠈࠉࠊࠋࠌࠍࠎࠏࠐࠑࠒࠓࠔࠕࠖࠗ࠘࠙ࠚࠛࠜࠝࠞࠟࠠࠡࠢࠣࠤࠥࠦࠧࠨࠩࠪࠫࠬ࠭࠰࠱࠲࠳࠴࠵࠶࠷࠸࠹࠺࠻࠼࠽࠾ࡀࡁࡂࡃࡄࡅࡆࡇࡈࡉࡊࡋࡌࡍࡎࡏࡐࡑࡒࡓࡔࡕࡖࡗࡘ࡙࡚࡛࡞ࢠࢢࢣࢤࢥࢦࢧࢨࢩࢪࢫࢬࣰࣱࣲࣦࣩ࣭࣮࣯ࣶࣹࣺࣤࣥࣧࣨ࣪࣫࣬ࣳࣴࣵࣷࣸࣻࣼࣽࣾऀँंःऄअआइईउऊऋऌऍऎएऐऑऒओऔकखगघङचछजझञटठडढणतथदधनऩपफबभमयरऱलळऴवशषसहऺऻ़ऽािीुूृॄॅॆेैॉॊोौ्ॎॏॐ॒॑॓॔ॕॖॗक़ख़ग़ज़ड़ढ़फ़य़ॠॡॢॣ।॥०१२३४५६७८९॰ॱॲॳॴॵॶॷॹॺॻॼॽॾॿঁংঃঅআইঈউঊঋঌএঐওঔকখগঘঙচছজঝঞটঠডঢণতথদধনপফবভমযরলশষসহ়ঽািীুূৃৄেৈোৌ্ৎৗড়ঢ়য়ৠৡৢৣ০১২৩৪৫৬৭৮৯ৰৱ৲৳৴৵৶৷৸৹৺৻ਁਂਃਅਆਇਈਉਊਏਐਓਔਕਖਗਘਙਚਛਜਝਞਟਠਡਢਣਤਥਦਧਨਪਫਬਭਮਯਰਲਲ਼ਵਸ਼ਸਹ਼ਾਿੀੁੂੇੈੋੌ੍ੑਖ਼ਗ਼ਜ਼ੜਫ਼੦੧੨੩੪੫੬੭੮੯ੰੱੲੳੴੵઁંઃઅઆઇઈઉઊઋઌઍએઐઑઓઔકખગઘઙચછજઝઞટઠડઢણતથદધનપફબભમયરલળવશષસહ઼ઽાિીુૂૃૄૅેૈૉોૌ્ૐૠૡૢૣ૦૧૨૩૪૫૬૭૮૯૰૱ଁଂଃଅଆଇଈଉଊଋଌଏଐଓଔକଖଗଘଙଚଛଜଝଞଟଠଡଢଣତଥଦଧନପଫବଭମଯରଲଳଵଶଷସହ଼ଽାିୀୁୂୃୄେୈୋୌ୍ୖୗଡ଼ଢ଼ୟୠୡୢୣ୦୧୨୩୪୫୬୭୮୯୰ୱ୲୳୴୵୶୷ஂஃஅஆஇஈஉஊஎஏஐஒஓஔகஙசஜஞடணதநனபமயரறலளழவஶஷஸஹாிீுூெேைொோௌ்ௐௗ௦௧௨௩௪௫௬௭௮௯௰௱௲௳௴௵௶௷௸௹௺ఁంఃఅఆఇఈఉఊఋఌఎఏఐఒఓఔకఖగఘఙచఛజఝఞటఠడఢణతథదధనపఫబభమయరఱలళవశషసహఽాిీుూృౄెేైొోౌ్ౕౖౘౙౠౡౢౣ౦౧౨౩౪౫౬౭౮౯౸౹౺౻౼౽౾౿ಂಃಅಆಇಈಉಊಋಌಎಏಐಒಓಔಕಖಗಘಙಚಛಜಝಞಟಠಡಢಣತಥದಧನಪಫಬಭಮಯರಱಲಳವಶಷಸಹ಼ಽಾಿೀುೂೃೄೆೇೈೊೋೌ್ೕೖೞೠೡೢೣ೦೧೨೩೪೫೬೭೮೯ೱೲംഃഅആഇഈഉഊഋഌഎഏഐഒഓഔകഖഗഘങചഛജഝഞടഠഡഢണതഥദധനഩപഫബഭമയരറലളഴവശഷസഹഺഽാിീുൂൃൄെേൈൊോൌ്ൎൗൠൡൢൣ൦൧൨൩൪൫൬൭൮൯൰൱൲൳൴൵൹ൺൻർൽൾൿංඃඅආඇඈඉඊඋඌඍඎඏඐඑඒඓඔඕඖකඛගඝඞඟචඡජඣඤඥඦටඨඩඪණඬතථදධනඳපඵබභමඹයරලවශෂසහළෆ්ාැෑිීුූෘෙේෛොෝෞෟෲෳ෴กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำิีึืฺุู฿เแโใไๅๆ็่้๊๋์ํ๎๏๐๑๒๓๔๕๖๗๘๙๚๛ກຂຄງຈຊຍດຕຖທນບປຜຝພຟມຢຣລວສຫອຮຯະັາຳິີຶືຸູົຼຽເແໂໃໄໆ່້໊໋໌ໍ໐໑໒໓໔໕໖໗໘໙ໜໝໞໟༀ༁༂༃༄༅༆༇༈༉༊་༌།༎༏༐༑༒༓༔༕༖༗༘༙༚༛༜༝༞༟༠༡༢༣༤༥༦༧༨༩༪༫༬༭༮༯༰༱༲༳༴༵༶༷༸༹༺༻༼༽༾༿ཀཁགགྷངཅཆཇཉཊཋཌཌྷཎཏཐདདྷནཔཕབབྷམཙཚཛཛྷཝཞཟའཡརལཤཥསཧཨཀྵཪཫཬཱཱཱིིུུྲྀཷླྀཹེཻོཽཾཿ྄ཱྀྀྂྃ྅྆྇ྈྉྊྋྌྍྎྏྐྑྒྒྷྔྕྖྗྙྚྛྜྜྷྞྟྠྡྡྷྣྤྥྦྦྷྨྩྪྫྫྷྭྮྯྰྱྲླྴྵྶྷྸྐྵྺྻྼ྾྿࿀࿁࿂࿃࿄࿅࿆࿇࿈࿉࿊࿋࿌࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚ကခဂဃငစဆဇဈဉညဋဌဍဎဏတထဒဓနပဖဗဘမယရလဝသဟဠအဢဣဤဥဦဧဨဩဪါာိီုူေဲဳဴဵံ့း္်ျြွှဿ၀၁၂၃၄၅၆၇၈၉၊။၌၍၎၏ၐၑၒၓၔၕၖၗၘၙၚၛၜၝၞၟၠၡၢၣၤၥၦၧၨၩၪၫၬၭၮၯၰၱၲၳၴၵၶၷၸၹၺၻၼၽၾၿႀႁႂႃႄႅႆႇႈႉႊႋႌႍႎႏ႐႑႒႓႔႕႖႗႘႙ႚႛႜႝ႞႟ႠႡႢႣႤႥႦႧႨႩႪႫႬႭႮႯႰႱႲႳႴႵႶႷႸႹႺႻႼႽႾႿჀჁჂჃჄჅჇჍაბგდევზთიკლმნოპჟრსტუფქღყშჩცძწჭხჯჰჱჲჳჴჵჶჷჸჹჺ჻ჼჽჾჿᄀᄁᄂᄃᄄᄅᄆᄇᄈᄉᄊᄋᄌᄍᄎᄏᄐᄑᄒᄓᄔᄕᄖᄗᄘᄙᄚᄛᄜᄝᄞᄟᄠᄡᄢᄣᄤᄥᄦᄧᄨᄩᄪᄫᄬᄭᄮᄯᄰᄱᄲᄳᄴᄵᄶᄷᄸᄹᄺᄻᄼᄽᄾᄿᅀᅁᅂᅃᅄᅅᅆᅇᅈᅉᅊᅋᅌᅍᅎᅏᅐᅑᅒᅓᅔᅕᅖᅗᅘᅙᅚᅛᅜᅝᅞᅟᅠᅡᅢᅣᅤᅥᅦᅧᅨᅩᅪᅫᅬᅭᅮᅯᅰᅱᅲᅳᅴᅵᅶᅷᅸᅹᅺᅻᅼᅽᅾᅿᆀᆁᆂᆃᆄᆅᆆᆇᆈᆉᆊᆋᆌᆍᆎᆏᆐᆑᆒᆓᆔᆕᆖᆗᆘᆙᆚᆛᆜᆝᆞᆟᆠᆡᆢᆣᆤᆥᆦᆧᆨᆩᆪᆫᆬᆭᆮᆯᆰᆱᆲᆳᆴᆵᆶᆷᆸᆹᆺᆻᆼᆽᆾᆿᇀᇁᇂᇃᇄᇅᇆᇇᇈᇉᇊᇋᇌᇍᇎᇏᇐᇑᇒᇓᇔᇕᇖᇗᇘᇙᇚᇛᇜᇝᇞᇟᇠᇡᇢᇣᇤᇥᇦᇧᇨᇩᇪᇫᇬᇭᇮᇯᇰᇱᇲᇳᇴᇵᇶᇷᇸᇹᇺᇻᇼᇽᇾᇿሀሁሂሃሄህሆሇለሉሊላሌልሎሏሐሑሒሓሔሕሖሗመሙሚማሜምሞሟሠሡሢሣሤሥሦሧረሩሪራሬርሮሯሰሱሲሳሴስሶሷሸሹሺሻሼሽሾሿቀቁቂቃቄቅቆቇቈቊቋቌቍቐቑቒቓቔቕቖቘቚቛቜቝበቡቢባቤብቦቧቨቩቪቫቬቭቮቯተቱቲታቴትቶቷቸቹቺቻቼችቾቿኀኁኂኃኄኅኆኇኈኊኋኌኍነኑኒናኔንኖኗኘኙኚኛኜኝኞኟአኡኢኣኤእኦኧከኩኪካኬክኮኯኰኲኳኴኵኸኹኺኻኼኽኾዀዂዃዄዅወዉዊዋዌውዎዏዐዑዒዓዔዕዖዘዙዚዛዜዝዞዟዠዡዢዣዤዥዦዧየዩዪያዬይዮዯደዱዲዳዴድዶዷዸዹዺዻዼዽዾዿጀጁጂጃጄጅጆጇገጉጊጋጌግጎጏጐጒጓጔጕጘጙጚጛጜጝጞጟጠጡጢጣጤጥጦጧጨጩጪጫጬጭጮጯጰጱጲጳጴጵጶጷጸጹጺጻጼጽጾጿፀፁፂፃፄፅፆፇፈፉፊፋፌፍፎፏፐፑፒፓፔፕፖፗፘፙፚ፝፞፟፠፡።፣፤፥፦፧፨፩፪፫፬፭፮፯፰፱፲፳፴፵፶፷፸፹፺፻፼ᎀᎁᎂᎃᎄᎅᎆᎇᎈᎉᎊᎋᎌᎍᎎᎏ᎐᎑᎒᎓᎔᎕᎖᎗᎘᎙ᎠᎡᎢᎣᎤᎥᎦᎧᎨᎩᎪᎫᎬᎭᎮᎯᎰᎱᎲᎳᎴᎵᎶᎷᎸᎹᎺᎻᎼᎽᎾᎿᏀᏁᏂᏃᏄᏅᏆᏇᏈᏉᏊᏋᏌᏍᏎᏏᏐᏑᏒᏓᏔᏕᏖᏗᏘᏙᏚᏛᏜᏝᏞᏟᏠᏡᏢᏣᏤᏥᏦᏧᏨᏩᏪᏫᏬᏭᏮᏯᏰᏱᏲᏳᏴ᐀ᐁᐂᐃᐄᐅᐆᐇᐈᐉᐊᐋᐌᐍᐎᐏᐐᐑᐒᐓᐔᐕᐖᐗᐘᐙᐚᐛᐜᐝᐞᐟᐠᐡᐢᐣᐤᐥᐦᐧᐨᐩᐪᐫᐬᐭᐮᐯᐰᐱᐲᐳᐴᐵᐶᐷᐸᐹᐺᐻᐼᐽᐾᐿᑀᑁᑂᑃᑄᑅᑆᑇᑈᑉᑊᑋᑌᑍᑎᑏᑐᑑᑒᑓᑔᑕᑖᑗᑘᑙᑚᑛᑜᑝᑞᑟᑠᑡᑢᑣᑤᑥᑦᑧᑨᑩᑪᑫᑬᑭᑮᑯᑰᑱᑲᑳᑴᑵᑶᑷᑸᑹᑺᑻᑼᑽᑾᑿᒀᒁᒂᒃᒄᒅᒆᒇᒈᒉᒊᒋᒌᒍᒎᒏᒐᒑᒒᒓᒔᒕᒖᒗᒘᒙᒚᒛᒜᒝᒞᒟᒠᒡᒢᒣᒤᒥᒦᒧᒨᒩᒪᒫᒬᒭᒮᒯᒰᒱᒲᒳᒴᒵᒶᒷᒸᒹᒺᒻᒼᒽᒾᒿᓀᓁᓂᓃᓄᓅᓆᓇᓈᓉᓊᓋᓌᓍᓎᓏᓐᓑᓒᓓᓔᓕᓖᓗᓘᓙᓚᓛᓜᓝᓞᓟᓠᓡᓢᓣᓤᓥᓦᓧᓨᓩᓪᓫᓬᓭᓮᓯᓰᓱᓲᓳᓴᓵᓶᓷᓸᓹᓺᓻᓼᓽᓾᓿᔀᔁᔂᔃᔄᔅᔆᔇᔈᔉᔊᔋᔌᔍᔎᔏᔐᔑᔒᔓᔔᔕᔖᔗᔘᔙᔚᔛᔜᔝᔞᔟᔠᔡᔢᔣᔤᔥᔦᔧᔨᔩᔪᔫᔬᔭᔮᔯᔰᔱᔲᔳᔴᔵᔶᔷᔸᔹᔺᔻᔼᔽᔾᔿᕀᕁᕂᕃᕄᕅᕆᕇᕈᕉᕊᕋᕌᕍᕎᕏᕐᕑᕒᕓᕔᕕᕖᕗᕘᕙᕚᕛᕜᕝᕞᕟᕠᕡᕢᕣᕤᕥᕦᕧᕨᕩᕪᕫᕬᕭᕮᕯᕰᕱᕲᕳᕴᕵᕶᕷᕸᕹᕺᕻᕼᕽᕾᕿᖀᖁᖂᖃᖄᖅᖆᖇᖈᖉᖊᖋᖌᖍᖎᖏᖐᖑᖒᖓᖔᖕᖖᖗᖘᖙᖚᖛᖜᖝᖞᖟᖠᖡᖢᖣᖤᖥᖦᖧᖨᖩᖪᖫᖬᖭᖮᖯᖰᖱᖲᖳᖴᖵᖶᖷᖸᖹᖺᖻᖼᖽᖾᖿᗀᗁᗂᗃᗄᗅᗆᗇᗈᗉᗊᗋᗌᗍᗎᗏᗐᗑᗒᗓᗔᗕᗖᗗᗘᗙᗚᗛᗜᗝᗞᗟᗠᗡᗢᗣᗤᗥᗦᗧᗨᗩᗪᗫᗬᗭᗮᗯᗰᗱᗲᗳᗴᗵᗶᗷᗸᗹᗺᗻᗼᗽᗾᗿᘀᘁᘂᘃᘄᘅᘆᘇᘈᘉᘊᘋᘌᘍᘎᘏᘐᘑᘒᘓᘔᘕᘖᘗᘘᘙᘚᘛᘜᘝᘞᘟᘠᘡᘢᘣᘤᘥᘦᘧᘨᘩᘪᘫᘬᘭᘮᘯᘰᘱᘲᘳᘴᘵᘶᘷᘸᘹᘺᘻᘼᘽᘾᘿᙀᙁᙂᙃᙄᙅᙆᙇᙈᙉᙊᙋᙌᙍᙎᙏᙐᙑᙒᙓᙔᙕᙖᙗᙘᙙᙚᙛᙜᙝᙞᙟᙠᙡᙢᙣᙤᙥᙦᙧᙨᙩᙪᙫᙬ᙭᙮ᙯᙰᙱᙲᙳᙴᙵᙶᙷᙸᙹᙺᙻᙼᙽᙾᙿ ᚁᚂᚃᚄᚅᚆᚇᚈᚉᚊᚋᚌᚍᚎᚏᚐᚑᚒᚓᚔᚕᚖᚗᚘᚙᚚ᚛᚜ᚠᚡᚢᚣᚤᚥᚦᚧᚨᚩᚪᚫᚬᚭᚮᚯᚰᚱᚲᚳᚴᚵᚶᚷᚸᚹᚺᚻᚼᚽᚾᚿᛀᛁᛂᛃᛄᛅᛆᛇᛈᛉᛊᛋᛌᛍᛎᛏᛐᛑᛒᛓᛔᛕᛖᛗᛘᛙᛚᛛᛜᛝᛞᛟᛠᛡᛢᛣᛤᛥᛦᛧᛨᛩᛪ᛫᛬᛭ᛮᛯᛰᜀᜁᜂᜃᜄᜅᜆᜇᜈᜉᜊᜋᜌᜎᜏᜐᜑᜒᜓ᜔ᜠᜡᜢᜣᜤᜥᜦᜧᜨᜩᜪᜫᜬᜭᜮᜯᜰᜱᜲᜳ᜴᜵᜶ᝀᝁᝂᝃᝄᝅᝆᝇᝈᝉᝊᝋᝌᝍᝎᝏᝐᝑᝒᝓᝠᝡᝢᝣᝤᝥᝦᝧᝨᝩᝪᝫᝬᝮᝯᝰᝲᝳកខគឃងចឆជឈញដឋឌឍណតថទធនបផពភមយរលវឝឞសហឡអឣឤឥឦឧឨឩឪឫឬឭឮឯឰឱឲឳ឴឵ាិីឹឺុូួើឿៀេែៃោៅំះៈ៉៊់៌៍៎៏័៑្៓។៕៖ៗ៘៙៚៛ៜ៝០១២៣៤៥៦៧៨៩៰៱៲៳៴៵៶៷៸៹᠀᠁᠂᠃᠄᠅᠆᠇᠈᠉᠊᠋᠌᠍᠎᠐᠑᠒᠓᠔᠕᠖᠗᠘᠙ᠠᠡᠢᠣᠤᠥᠦᠧᠨᠩᠪᠫᠬᠭᠮᠯᠰᠱᠲᠳᠴᠵᠶᠷᠸᠹᠺᠻᠼᠽᠾᠿᡀᡁᡂᡃᡄᡅᡆᡇᡈᡉᡊᡋᡌᡍᡎᡏᡐᡑᡒᡓᡔᡕᡖᡗᡘᡙᡚᡛᡜᡝᡞᡟᡠᡡᡢᡣᡤᡥᡦᡧᡨᡩᡪᡫᡬᡭᡮᡯᡰᡱᡲᡳᡴᡵᡶᡷᢀᢁᢂᢃᢄᢅᢆᢇᢈᢉᢊᢋᢌᢍᢎᢏᢐᢑᢒᢓᢔᢕᢖᢗᢘᢙᢚᢛᢜᢝᢞᢟᢠᢡᢢᢣᢤᢥᢦᢧᢨᢩᢪᢰᢱᢲᢳᢴᢵᢶᢷᢸᢹᢺᢻᢼᢽᢾᢿᣀᣁᣂᣃᣄᣅᣆᣇᣈᣉᣊᣋᣌᣍᣎᣏᣐᣑᣒᣓᣔᣕᣖᣗᣘᣙᣚᣛᣜᣝᣞᣟᣠᣡᣢᣣᣤᣥᣦᣧᣨᣩᣪᣫᣬᣭᣮᣯᣰᣱᣲᣳᣴᣵᤀᤁᤂᤃᤄᤅᤆᤇᤈᤉᤊᤋᤌᤍᤎᤏᤐᤑᤒᤓᤔᤕᤖᤗᤘᤙᤚᤛᤜᤠᤡᤢᤣᤤᤥᤦᤧᤨᤩᤪᤫᤰᤱᤲᤳᤴᤵᤶᤷᤸ᤻᤹᤺᥀᥄᥅᥆᥇᥈᥉᥊᥋᥌᥍᥎᥏ᥐᥑᥒᥓᥔᥕᥖᥗᥘᥙᥚᥛᥜᥝᥞᥟᥠᥡᥢᥣᥤᥥᥦᥧᥨᥩᥪᥫᥬᥭᥰᥱᥲᥳᥴᦀᦁᦂᦃᦄᦅᦆᦇᦈᦉᦊᦋᦌᦍᦎᦏᦐᦑᦒᦓᦔᦕᦖᦗᦘᦙᦚᦛᦜᦝᦞᦟᦠᦡᦢᦣᦤᦥᦦᦧᦨᦩᦪᦫᦰᦱᦲᦳᦴᦵᦶᦷᦸᦹᦺᦻᦼᦽᦾᦿᧀᧁᧂᧃᧄᧅᧆᧇᧈᧉ᧐᧑᧒᧓᧔᧕᧖᧗᧘᧙᧚᧞᧟᧠᧡᧢᧣᧤᧥᧦᧧᧨᧩᧪᧫᧬᧭᧮᧯᧰᧱᧲᧳᧴᧵᧶᧷᧸᧹᧺᧻᧼᧽᧾᧿ᨀᨁᨂᨃᨄᨅᨆᨇᨈᨉᨊᨋᨌᨍᨎᨏᨐᨑᨒᨓᨔᨕᨖᨘᨗᨙᨚᨛ᨞᨟ᨠᨡᨢᨣᨤᨥᨦᨧᨨᨩᨪᨫᨬᨭᨮᨯᨰᨱᨲᨳᨴᨵᨶᨷᨸᨹᨺᨻᨼᨽᨾᨿᩀᩁᩂᩃᩄᩅᩆᩇᩈᩉᩊᩋᩌᩍᩎᩏᩐᩑᩒᩓᩔᩕᩖᩗᩘᩙᩚᩛᩜᩝᩞ᩠ᩡᩢᩣᩤᩥᩦᩧᩨᩩᩪᩫᩬᩭᩮᩯᩰᩱᩲᩳᩴ᩿᩵᩶᩷᩸᩹᩺᩻᩼᪀᪁᪂᪃᪄᪅᪆᪇᪈᪉᪐᪑᪒᪓᪔᪕᪖᪗᪘᪙᪠᪡᪢᪣᪤᪥᪦ᪧ᪨᪩᪪᪫᪬᪭ᬀᬁᬂᬃᬄᬅᬆᬇᬈᬉᬊᬋᬌᬍᬎᬏᬐᬑᬒᬓᬔᬕᬖᬗᬘᬙᬚᬛᬜᬝᬞᬟᬠᬡᬢᬣᬤᬥᬦᬧᬨᬩᬪᬫᬬᬭᬮᬯᬰᬱᬲᬳ᬴ᬵᬶᬷᬸᬹᬺᬻᬼᬽᬾᬿᭀᭁᭂᭃ᭄ᭅᭆᭇᭈᭉᭊᭋ᭐᭑᭒᭓᭔᭕᭖᭗᭘᭙᭚᭛᭜᭝᭞᭟᭠᭡᭢᭣᭤᭥᭦᭧᭨᭩᭪᭬᭫᭭᭮᭯᭰᭱᭲᭳᭴᭵᭶᭷᭸᭹᭺᭻᭼ᮀᮁᮂᮃᮄᮅᮆᮇᮈᮉᮊᮋᮌᮍᮎᮏᮐᮑᮒᮓᮔᮕᮖᮗᮘᮙᮚᮛᮜᮝᮞᮟᮠᮡᮢᮣᮤᮥᮦᮧᮨᮩ᮪᮫ᮬᮭᮮᮯ᮰᮱᮲᮳᮴᮵᮶᮷᮸᮹ᮺᮻᮼᮽᮾᮿᯀᯁᯂᯃᯄᯅᯆᯇᯈᯉᯊᯋᯌᯍᯎᯏᯐᯑᯒᯓᯔᯕᯖᯗᯘᯙᯚᯛᯜᯝᯞᯟᯠᯡᯢᯣᯤᯥ᯦ᯧᯨᯩᯪᯫᯬᯭᯮᯯᯰᯱ᯲᯳᯼᯽᯾᯿ᰀᰁᰂᰃᰄᰅᰆᰇᰈᰉᰊᰋᰌᰍᰎᰏᰐᰑᰒᰓᰔᰕᰖᰗᰘᰙᰚᰛᰜᰝᰞᰟᰠᰡᰢᰣᰤᰥᰦᰧᰨᰩᰪᰫᰬᰭᰮᰯᰰᰱᰲᰳᰴᰵᰶ᰷᰻᰼᰽᰾᰿᱀᱁᱂᱃᱄᱅᱆᱇᱈᱉ᱍᱎᱏ᱐᱑᱒᱓᱔᱕᱖᱗᱘᱙ᱚᱛᱜᱝᱞᱟᱠᱡᱢᱣᱤᱥᱦᱧᱨᱩᱪᱫᱬᱭᱮᱯᱰᱱᱲᱳᱴᱵᱶᱷᱸᱹᱺᱻᱼᱽ᱾᱿᳀᳁᳂᳃᳄᳅᳆᳇᳐᳑᳒᳓᳔᳕᳖᳗᳘᳙᳜᳝᳞᳟᳚᳛᳠᳡᳢᳣᳤᳥᳦᳧᳨ᳩᳪᳫᳬ᳭ᳮᳯᳰᳱᳲᳳ᳴ᳵᳶᴀᴁᴂᴃᴄᴅᴆᴇᴈᴉᴊᴋᴌᴍᴎᴏᴐᴑᴒᴓᴔᴕᴖᴗᴘᴙᴚᴛᴜᴝᴞᴟᴠᴡᴢᴣᴤᴥᴦᴧᴨᴩᴪᴫᴬᴭᴮᴯᴰᴱᴲᴳᴴᴵᴶᴷᴸᴹᴺᴻᴼᴽᴾᴿᵀᵁᵂᵃᵄᵅᵆᵇᵈᵉᵊᵋᵌᵍᵎᵏᵐᵑᵒᵓᵔᵕᵖᵗᵘᵙᵚᵛᵜᵝᵞᵟᵠᵡᵢᵣᵤᵥᵦᵧᵨᵩᵪᵫᵬᵭᵮᵯᵰᵱᵲᵳᵴᵵᵶᵷᵸᵹᵺᵻᵼᵽᵾᵿᶀᶁᶂᶃᶄᶅᶆᶇᶈᶉᶊᶋᶌᶍᶎᶏᶐᶑᶒᶓᶔᶕᶖᶗᶘᶙᶚᶛᶜᶝᶞᶟᶠᶡᶢᶣᶤᶥᶦᶧᶨᶩᶪᶫᶬᶭᶮᶯᶰᶱᶲᶳᶴᶵᶶᶷᶸᶹᶺᶻᶼᶽᶾᶿ᷐᷎᷂᷊᷏᷽᷿᷀᷁᷃᷄᷅᷆᷇᷈᷉᷋᷌᷑᷒ᷓᷔᷕᷖᷗᷘᷙᷚᷛᷜᷝᷞᷟᷠᷡᷢᷣᷤᷥᷦ᷾᷼᷍ḀḁḂḃḄḅḆḇḈḉḊḋḌḍḎḏḐḑḒḓḔḕḖḗḘḙḚḛḜḝḞḟḠḡḢḣḤḥḦḧḨḩḪḫḬḭḮḯḰḱḲḳḴḵḶḷḸḹḺḻḼḽḾḿṀṁṂṃṄṅṆṇṈṉṊṋṌṍṎṏṐṑṒṓṔṕṖṗṘṙṚṛṜṝṞṟṠṡṢṣṤṥṦṧṨṩṪṫṬṭṮṯṰṱṲṳṴṵṶṷṸṹṺṻṼṽṾṿẀẁẂẃẄẅẆẇẈẉẊẋẌẍẎẏẐẑẒẓẔẕẖẗẘẙẚẛẜẝẞẟẠạẢảẤấẦầẨẩẪẫẬậẮắẰằẲẳẴẵẶặẸẹẺẻẼẽẾếỀềỂểỄễỆệỈỉỊịỌọỎỏỐốỒồỔổỖỗỘộỚớỜờỞởỠỡỢợỤụỦủỨứỪừỬửỮữỰựỲỳỴỵỶỷỸỹỺỻỼỽỾỿἀἁἂἃἄἅἆἇἈἉἊἋἌἍἎἏἐἑἒἓἔἕἘἙἚἛἜἝἠἡἢἣἤἥἦἧἨἩἪἫἬἭἮἯἰἱἲἳἴἵἶἷἸἹἺἻἼἽἾἿὀὁὂὃὄὅὈὉὊὋὌὍὐὑὒὓὔὕὖὗὙὛὝὟὠὡὢὣὤὥὦὧὨὩὪὫὬὭὮὯὰάὲέὴήὶίὸόὺύὼώᾀᾁᾂᾃᾄᾅᾆᾇᾈᾉᾊᾋᾌᾍᾎᾏᾐᾑᾒᾓᾔᾕᾖᾗᾘᾙᾚᾛᾜᾝᾞᾟᾠᾡᾢᾣᾤᾥᾦᾧᾨᾩᾪᾫᾬᾭᾮᾯᾰᾱᾲᾳᾴᾶᾷᾸᾹᾺΆᾼ᾽ι᾿῀῁ῂῃῄῆῇῈΈῊΉῌ῍῎῏ῐῑῒΐῖῗῘῙῚΊ῝῞῟ῠῡῢΰῤῥῦῧῨῩῪΎῬ῭΅`ῲῳῴῶῷῸΌῺΏῼ´῾           ​‌‍‎‏‐‑‒–—―‖‗‘’‚‛“”„‟†‡•‣․‥…‧

‪‭‮ ‰‱′″‴‵‶‷‸‹›※‼‽‾‿⁀⁁⁂⁃⁄⁅⁆⁇⁈⁉⁊⁋⁌⁍⁎⁏⁐⁑⁒⁓⁔⁕⁖⁗⁘⁙⁚⁛⁜⁝⁞ ⁠⁡⁢⁣⁤⁰ⁱ⁴⁵⁶⁷⁸⁹⁺⁻⁼⁽⁾ⁿ₀₁₂₃₄₅₆₇₈₉₊₋₌₍₎ₐₑₒₓₔₕₖₗₘₙₚₛₜ₠₡₢₣₤₥₦₧₨₩₪₫€₭₮₯₰₱₲₳₴₵₶₷₸₹₺₻₼₽₾₿⃒⃓⃘⃙⃚⃐⃑⃔⃕⃖⃗⃛⃜⃝⃞⃟⃠⃡⃢⃣⃤⃥⃦⃪⃫⃨⃬⃭⃮⃯⃧⃩⃰℀℁ℂ℃℄℅℆ℇ℈℉ℊℋℌℍℎℏℐℑℒℓ℔ℕ№℗℘ℙℚℛℜℝ℞℟℠℡™℣ℤ℥Ω℧ℨ℩KÅℬℭ℮ℯℰℱℲℳℴℵℶℷℸℹ℺℻ℼℽℾℿ⅀⅁⅂⅃⅄ⅅⅆⅇⅈⅉ⅊⅋⅌⅍ⅎ⅏⅐⅑⅒⅓⅔⅕⅖⅗⅘⅙⅚⅛⅜⅝⅞⅟ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫⅬⅭⅮⅯⅰⅱⅲⅳⅴⅵⅶⅷⅸⅹⅺⅻⅼⅽⅾⅿↀↁↂↃↄↅↆↇↈ↉←↑→↓↔↕↖↗↘↙↚↛↜↝↞↟↠↡↢↣↤↥↦↧↨↩↪↫↬↭↮↯↰↱↲↳↴↵↶↷↸↹↺↻↼↽↾↿⇀⇁⇂⇃⇄⇅⇆⇇⇈⇉⇊⇋⇌⇍⇎⇏⇐⇑⇒⇓⇔⇕⇖⇗⇘⇙⇚⇛⇜⇝⇞⇟⇠⇡⇢⇣⇤⇥⇦⇧⇨⇩⇪⇫⇬⇭⇮⇯⇰⇱⇲⇳⇴⇵⇶⇷⇸⇹⇺⇻⇼⇽⇾⇿∀∁∂∃∄∅∆∇∈∉∊∋∌∍∎∏∐∑−∓∔∕∖∗∘∙√∛∜∝∞∟∠∡∢∣∤∥∦∧∨∩∪∫∬∭∮∯∰∱∲∳∴∵∶∷∸∹∺∻∼∽∾∿≀≁≂≃≄≅≆≇≈≉≊≋≌≍≎≏≐≑≒≓≔≕≖≗≘≙≚≛≜≝≞≟≠≡≢≣≤≥≦≧≨≩≪≫≬≭≮≯≰≱≲≳≴≵≶≷≸≹≺≻≼≽≾≿⊀⊁⊂⊃⊄⊅⊆⊇⊈⊉⊊⊋⊌⊍⊎⊏⊐⊑⊒⊓⊔⊕⊖⊗⊘⊙⊚⊛⊜⊝⊞⊟⊠⊡⊢⊣⊤⊥⊦⊧⊨⊩⊪⊫⊬⊭⊮⊯⊰⊱⊲⊳⊴⊵⊶⊷⊸⊹⊺⊻⊼⊽⊾⊿⋀⋁⋂⋃⋄⋅⋆⋇⋈⋉⋊⋋⋌⋍⋎⋏⋐⋑⋒⋓⋔⋕⋖⋗⋘⋙⋚⋛⋜⋝⋞⋟⋠⋡⋢⋣⋤⋥⋦⋧⋨⋩⋪⋫⋬⋭⋮⋯⋰⋱⋲⋳⋴⋵⋶⋷⋸⋹⋺⋻⋼⋽⋾⋿⌀⌁⌂⌃⌄⌅⌆⌇⌈⌉⌊⌋⌌⌍⌎⌏⌐⌑⌒⌓⌔⌕⌖⌗⌘⌙⌚⌛⌜⌝⌞⌟⌠⌡⌢⌣⌤⌥⌦⌧⌨〈〉⌫⌬⌭⌮⌯⌰⌱⌲⌳⌴⌵⌶⌷⌸⌹⌺⌻⌼⌽⌾⌿⍀⍁⍂⍃⍄⍅⍆⍇⍈⍉⍊⍋⍌⍍⍎⍏⍐⍑⍒⍓⍔⍕⍖⍗⍘⍙⍚⍛⍜⍝⍞⍟⍠⍡⍢⍣⍤⍥⍦⍧⍨⍩⍪⍫⍬⍭⍮⍯⍰⍱⍲⍳⍴⍵⍶⍷⍸⍹⍺⍻⍼⍽⍾⍿⎀⎁⎂⎃⎄⎅⎆⎇⎈⎉⎊⎋⎌⎍⎎⎏⎐⎑⎒⎓⎔⎕⎖⎗⎘⎙⎚⎛⎜⎝⎞⎟⎠⎡⎢⎣⎤⎥⎦⎧⎨⎩⎪⎫⎬⎭⎮⎯⎰⎱⎲⎳⎴⎵⎶⎷⎸⎹⎺⎻⎼⎽⎾⎿⏀⏁⏂⏃⏄⏅⏆⏇⏈⏉⏊⏋⏌⏍⏎⏏⏐⏑⏒⏓⏔⏕⏖⏗⏘⏙⏚⏛⏜⏝⏞⏟⏠⏡⏢⏣⏤⏥⏦⏧⏨⏩⏪⏫⏬⏭⏮⏯⏰⏱⏲⏳␀␁␂␃␄␅␆␇␈␉␊␋␌␍␎␏␐␑␒␓␔␕␖␗␘␙␚␛␜␝␞␟␠␡␢␣␤␥␦⑀⑁⑂⑃⑄⑅⑆⑇⑈⑉⑊①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳⑴⑵⑶⑷⑸⑹⑺⑻⑼⑽⑾⑿⒀⒁⒂⒃⒄⒅⒆⒇⒈⒉⒊⒋⒌⒍⒎⒏⒐⒑⒒⒓⒔⒕⒖⒗⒘⒙⒚⒛⒜⒝⒞⒟⒠⒡⒢⒣⒤⒥⒦⒧⒨⒩⒪⒫⒬⒭⒮⒯⒰⒱⒲⒳⒴⒵ⒶⒷⒸⒹⒺⒻⒼⒽⒾⒿⓀⓁⓂⓃⓄⓅⓆⓇⓈⓉⓊⓋⓌⓍⓎⓏⓐⓑⓒⓓⓔⓕⓖⓗⓘⓙⓚⓛⓜⓝⓞⓟⓠⓡⓢⓣⓤⓥⓦⓧⓨⓩ⓪⓫⓬⓭⓮⓯⓰⓱⓲⓳⓴⓵⓶⓷⓸⓹⓺⓻⓼⓽⓾⓿─━│┃┄┅┆┇┈┉┊┋┌┍┎┏┐┑┒┓└┕┖┗┘┙┚┛├┝┞┟┠┡┢┣┤┥┦┧┨┩┪┫┬┭┮┯┰┱┲┳┴┵┶┷┸┹┺┻┼┽┾┿╀╁╂╃╄╅╆╇╈╉╊╋╌╍╎╏═║╒╓╔╕╖╗╘╙╚╛╜╝╞╟╠╡╢╣╤╥╦╧╨╩╪╫╬╭╮╯╰╱╲╳╴╵╶╷╸╹╺╻╼╽╾╿▀▁▂▃▄▅▆▇█▉▊▋▌▍▎▏▐░▒▓▔▕▖▗▘▙▚▛▜▝▞▟■□▢▣▤▥▦▧▨▩▪▫▬▭▮▯▰▱▲△▴▵▶▷▸▹►▻▼▽▾▿◀◁◂◃◄◅◆◇◈◉◊○◌◍◎●◐◑◒◓◔◕◖◗◘◙◚◛◜◝◞◟◠◡◢◣◤◥◦◧◨◩◪◫◬◭◮◯◰◱◲◳◴◵◶◷◸◹◺◻◼◽◾◿☀☁☂☃☄★☆☇☈☉☊☋☌☍☎☏☐☑☒☓☔☕☖☗☘☙☚☛☜☝☞☟☠☡☢☣☤☥☦☧☨☩☪☫☬☭☮☯☰☱☲☳☴☵☶☷☸☹☺☻☼☽☾☿♀♁♂♃♄♅♆♇♈♉♊♋♌♍♎♏♐♑♒♓♔♕♖♗♘♙♚♛♜♝♞♟♠♡♢♣♤♥♦♧♨♩♪♫♬♭♮♯♰♱♲♳♴♵♶♷♸♹♺♻♼♽♾♿⚀⚁⚂⚃⚄⚅⚆⚇⚈⚉⚊⚋⚌⚍⚎⚏⚐⚑⚒⚓⚔⚕⚖⚗⚘⚙⚚⚛⚜⚝⚞⚟⚠⚡⚢⚣⚤⚥⚦⚧⚨⚩⚪⚫⚬⚭⚮⚯⚰⚱⚲⚳⚴⚵⚶⚷⚸⚹⚺⚻⚼⚽⚾⚿⛀⛁⛂⛃⛄⛅⛆⛇⛈⛉⛊⛋⛌⛍⛎⛏⛐⛑⛒⛓⛔⛕⛖⛗⛘⛙⛚⛛⛜⛝⛞⛟⛠⛡⛢⛣⛤⛥⛦⛧⛨⛩⛪⛫⛬⛭⛮⛯⛰⛱⛲⛳⛴⛵⛶⛷⛸⛹⛺⛻⛼⛽⛾⛿✁✂✃✄✅✆✇✈✉✊✋✌✍✎✏✐✑✒✓✔✕✖✗✘✙✚✛✜✝✞✟✠✡✢✣✤✥✦✧✨✩✪✫✬✭✮✯✰✱✲✳✴✵✶✷✸✹✺✻✼✽✾✿❀❁❂❃❄❅❆❇❈❉❊❋❌❍❎❏❐❑❒❓❔❕❖❗❘❙❚❛❜❝❞❟❠❡❢❣❤❥❦❧❨❩❪❫❬❭❮❯❰❱❲❳❴❵❶❷❸❹❺❻❼❽❾❿➀➁➂➃➄➅➆➇➈➉➊➋➌➍➎➏➐➑➒➓➔➕➖➗➘➙➚➛➜➝➞➟➠➡➢➣➤➥➦➧➨➩➪➫➬➭➮➯➰➱➲➳➴➵➶➷➸➹➺➻➼➽➾➿⟀⟁⟂⟃⟄⟅⟆⟇⟈⟉⟊⟋⟌⟍⟎⟏⟐⟑⟒⟓⟔⟕⟖⟗⟘⟙⟚⟛⟜⟝⟞⟟⟠⟡⟢⟣⟤⟥⟦⟧⟨⟩⟪⟫⟬⟭⟮⟯⟰⟱⟲⟳⟴⟵⟶⟷⟸⟹⟺⟻⟼⟽⟾⟿⠀⠁⠂⠃⠄⠅⠆⠇⠈⠉⠊⠋⠌⠍⠎⠏⠐⠑⠒⠓⠔⠕⠖⠗⠘⠙⠚⠛⠜⠝⠞⠟⠠⠡⠢⠣⠤⠥⠦⠧⠨⠩⠪⠫⠬⠭⠮⠯⠰⠱⠲⠳⠴⠵⠶⠷⠸⠹⠺⠻⠼⠽⠾⠿⡀⡁⡂⡃⡄⡅⡆⡇⡈⡉⡊⡋⡌⡍⡎⡏⡐⡑⡒⡓⡔⡕⡖⡗⡘⡙⡚⡛⡜⡝⡞⡟⡠⡡⡢⡣⡤⡥⡦⡧⡨⡩⡪⡫⡬⡭⡮⡯⡰⡱⡲⡳⡴⡵⡶⡷⡸⡹⡺⡻⡼⡽⡾⡿⢀⢁⢂⢃⢄⢅⢆⢇⢈⢉⢊⢋⢌⢍⢎⢏⢐⢑⢒⢓⢔⢕⢖⢗⢘⢙⢚⢛⢜⢝⢞⢟⢠⢡⢢⢣⢤⢥⢦⢧⢨⢩⢪⢫⢬⢭⢮⢯⢰⢱⢲⢳⢴⢵⢶⢷⢸⢹⢺⢻⢼⢽⢾⢿⣀⣁⣂⣃⣄⣅⣆⣇⣈⣉⣊⣋⣌⣍⣎⣏⣐⣑⣒⣓⣔⣕⣖⣗⣘⣙⣚⣛⣜⣝⣞⣟⣠⣡⣢⣣⣤⣥⣦⣧⣨⣩⣪⣫⣬⣭⣮⣯⣰⣱⣲⣳⣴⣵⣶⣷⣸⣹⣺⣻⣼⣽⣾⣿⤀⤁⤂⤃⤄⤅⤆⤇⤈⤉⤊⤋⤌⤍⤎⤏⤐⤑⤒⤓⤔⤕⤖⤗⤘⤙⤚⤛⤜⤝⤞⤟⤠⤡⤢⤣⤤⤥⤦⤧⤨⤩⤪⤫⤬⤭⤮⤯⤰⤱⤲⤳⤴⤵⤶⤷⤸⤹⤺⤻⤼⤽⤾⤿⥀⥁⥂⥃⥄⥅⥆⥇⥈⥉⥊⥋⥌⥍⥎⥏⥐⥑⥒⥓⥔⥕⥖⥗⥘⥙⥚⥛⥜⥝⥞⥟⥠⥡⥢⥣⥤⥥⥦⥧⥨⥩⥪⥫⥬⥭⥮⥯⥰⥱⥲⥳⥴⥵⥶⥷⥸⥹⥺⥻⥼⥽⥾⥿⦀⦁⦂⦃⦄⦅⦆⦇⦈⦉⦊⦋⦌⦍⦎⦏⦐⦑⦒⦓⦔⦕⦖⦗⦘⦙⦚⦛⦜⦝⦞⦟⦠⦡⦢⦣⦤⦥⦦⦧⦨⦩⦪⦫⦬⦭⦮⦯⦰⦱⦲⦳⦴⦵⦶⦷⦸⦹⦺⦻⦼⦽⦾⦿⧀⧁⧂⧃⧄⧅⧆⧇⧈⧉⧊⧋⧌⧍⧎⧏⧐⧑⧒⧓⧔⧕⧖⧗⧘⧙⧚⧛⧜⧝⧞⧟⧠⧡⧢⧣⧤⧥⧦⧧⧨⧩⧪⧫⧬⧭⧮⧯⧰⧱⧲⧳⧴⧵⧶⧷⧸⧹⧺⧻⧼⧽⧾⧿⨀⨁⨂⨃⨄⨅⨆⨇⨈⨉⨊⨋⨌⨍⨎⨏⨐⨑⨒⨓⨔⨕⨖⨗⨘⨙⨚⨛⨜⨝⨞⨟⨠⨡⨢⨣⨤⨥⨦⨧⨨⨩⨪⨫⨬⨭⨮⨯⨰⨱⨲⨳⨴⨵⨶⨷⨸⨹⨺⨻⨼⨽⨾⨿⩀⩁⩂⩃⩄⩅⩆⩇⩈⩉⩊⩋⩌⩍⩎⩏⩐⩑⩒⩓⩔⩕⩖⩗⩘⩙⩚⩛⩜⩝⩞⩟⩠⩡⩢⩣⩤⩥⩦⩧⩨⩩⩪⩫⩬⩭⩮⩯⩰⩱⩲⩳⩴⩵⩶⩷⩸⩹⩺⩻⩼⩽⩾⩿⪀⪁⪂⪃⪄⪅⪆⪇⪈⪉⪊⪋⪌⪍⪎⪏⪐⪑⪒⪓⪔⪕⪖⪗⪘⪙⪚⪛⪜⪝⪞⪟⪠⪡⪢⪣⪤⪥⪦⪧⪨⪩⪪⪫⪬⪭⪮⪯⪰⪱⪲⪳⪴⪵⪶⪷⪸⪹⪺⪻⪼⪽⪾⪿⫀⫁⫂⫃⫄⫅⫆⫇⫈⫉⫊⫋⫌⫍⫎⫏⫐⫑⫒⫓⫔⫕⫖⫗⫘⫙⫚⫛⫝̸⫝⫞⫟⫠⫡⫢⫣⫤⫥⫦⫧⫨⫩⫪⫫⫬⫭⫮⫯⫰⫱⫲⫳⫴⫵⫶⫷⫸⫹⫺⫻⫼⫽⫾⫿⬀⬁⬂⬃⬄⬅⬆⬇⬈⬉⬊⬋⬌⬍⬎⬏⬐⬑⬒⬓⬔⬕⬖⬗⬘⬙⬚⬛⬜⬝⬞⬟⬠⬡⬢⬣⬤⬥⬦⬧⬨⬩⬪⬫⬬⬭⬮⬯⬰⬱⬲⬳⬴⬵⬶⬷⬸⬹⬺⬻⬼⬽⬾⬿⭀⭁⭂⭃⭄⭅⭆⭇⭈⭉⭊⭋⭌⭐⭑⭒⭓⭔⭕⭖⭗⭘⭙ⰀⰁⰂⰃⰄⰅⰆⰇⰈⰉⰊⰋⰌⰍⰎⰏⰐⰑⰒⰓⰔⰕⰖⰗⰘⰙⰚⰛⰜⰝⰞⰟⰠⰡⰢⰣⰤⰥⰦⰧⰨⰩⰪⰫⰬⰭⰮⰰⰱⰲⰳⰴⰵⰶⰷⰸⰹⰺⰻⰼⰽⰾⰿⱀⱁⱂⱃⱄⱅⱆⱇⱈⱉⱊⱋⱌⱍⱎⱏⱐⱑⱒⱓⱔⱕⱖⱗⱘⱙⱚⱛⱜⱝⱞⱠⱡⱢⱣⱤⱥⱦⱧⱨⱩⱪⱫⱬⱭⱮⱯⱰⱱⱲⱳⱴⱵⱶⱷⱸⱹⱺⱻⱼⱽⱾⱿⲀⲁⲂⲃⲄⲅⲆⲇⲈⲉⲊⲋⲌⲍⲎⲏⲐⲑⲒⲓⲔⲕⲖⲗⲘⲙⲚⲛⲜⲝⲞⲟⲠⲡⲢⲣⲤⲥⲦⲧⲨⲩⲪⲫⲬⲭⲮⲯⲰⲱⲲⲳⲴⲵⲶⲷⲸⲹⲺⲻⲼⲽⲾⲿⳀⳁⳂⳃⳄⳅⳆⳇⳈⳉⳊⳋⳌⳍⳎⳏⳐⳑⳒⳓⳔⳕⳖⳗⳘⳙⳚⳛⳜⳝⳞⳟⳠⳡⳢⳣⳤ⳥⳦⳧⳨⳩⳪ⳫⳬⳭⳮ⳯⳰⳱Ⳳⳳ⳹⳺⳻⳼⳽⳾⳿ⴀⴁⴂⴃⴄⴅⴆⴇⴈⴉⴊⴋⴌⴍⴎⴏⴐⴑⴒⴓⴔⴕⴖⴗⴘⴙⴚⴛⴜⴝⴞⴟⴠⴡⴢⴣⴤⴥⴧⴭⴰⴱⴲⴳⴴⴵⴶⴷⴸⴹⴺⴻⴼⴽⴾⴿⵀⵁⵂⵃⵄⵅⵆⵇⵈⵉⵊⵋⵌⵍⵎⵏⵐⵑⵒⵓⵔⵕⵖⵗⵘⵙⵚⵛⵜⵝⵞⵟⵠⵡⵢⵣⵤⵥⵦⵧⵯ⵰⵿ⶀⶁⶂⶃⶄⶅⶆⶇⶈⶉⶊⶋⶌⶍⶎⶏⶐⶑⶒⶓⶔⶕⶖⶠⶡⶢⶣⶤⶥⶦⶨⶩⶪⶫⶬⶭⶮⶰⶱⶲⶳⶴⶵⶶⶸⶹⶺⶻⶼⶽⶾⷀⷁⷂⷃⷄⷅⷆⷈⷉⷊⷋⷌⷍⷎⷐⷑⷒⷓⷔⷕⷖⷘⷙⷚⷛⷜⷝⷞⷠⷡⷢⷣⷤⷥⷦⷧⷨⷩⷪⷫⷬⷭⷮⷯⷰⷱⷲⷳⷴⷵⷶⷷⷸⷹⷺⷻⷼⷽⷾⷿ⸀⸁⸂⸃⸄⸅⸆⸇⸈⸉⸊⸋⸌⸍⸎⸏⸐⸑⸒⸓⸔⸕⸖⸗⸘⸙⸚⸛⸜⸝⸞⸟⸠⸡⸢⸣⸤⸥⸦⸧⸨⸩⸪⸫⸬⸭⸮ⸯ⸰⸱⸲⸳⸴⸵⸶⸷⸸⸹⸺⸻⺀⺁⺂⺃⺄⺅⺆⺇⺈⺉⺊⺋⺌⺍⺎⺏⺐⺑⺒⺓⺔⺕⺖⺗⺘⺙⺛⺜⺝⺞⺟⺠⺡⺢⺣⺤⺥⺦⺧⺨⺩⺪⺫⺬⺭⺮⺯⺰⺱⺲⺳⺴⺵⺶⺷⺸⺹⺺⺻⺼⺽⺾⺿⻀⻁⻂⻃⻄⻅⻆⻇⻈⻉⻊⻋⻌⻍⻎⻏⻐⻑⻒⻓⻔⻕⻖⻗⻘⻙⻚⻛⻜⻝⻞⻟⻠⻡⻢⻣⻤⻥⻦⻧⻨⻩⻪⻫⻬⻭⻮⻯⻰⻱⻲⻳⼀⼁⼂⼃⼄⼅⼆⼇⼈⼉⼊⼋⼌⼍⼎⼏⼐⼑⼒⼓⼔⼕⼖⼗⼘⼙⼚⼛⼜⼝⼞⼟⼠⼡⼢⼣⼤⼥⼦⼧⼨⼩⼪⼫⼬⼭⼮⼯⼰⼱⼲⼳⼴⼵⼶⼷⼸⼹⼺⼻⼼⼽⼾⼿⽀⽁⽂⽃⽄⽅⽆⽇⽈⽉⽊⽋⽌⽍⽎⽏⽐⽑⽒⽓⽔⽕⽖⽗⽘⽙⽚⽛⽜⽝⽞⽟⽠⽡⽢⽣⽤⽥⽦⽧⽨⽩⽪⽫⽬⽭⽮⽯⽰⽱⽲⽳⽴⽵⽶⽷⽸⽹⽺⽻⽼⽽⽾⽿⾀⾁⾂⾃⾄⾅⾆⾇⾈⾉⾊⾋⾌⾍⾎⾏⾐⾑⾒⾓⾔⾕⾖⾗⾘⾙⾚⾛⾜⾝⾞⾟⾠⾡⾢⾣⾤⾥⾦⾧⾨⾩⾪⾫⾬⾭⾮⾯⾰⾱⾲⾳⾴⾵⾶⾷⾸⾹⾺⾻⾼⾽⾾⾿⿀⿁⿂⿃⿄⿅⿆⿇⿈⿉⿊⿋⿌⿍⿎⿏⿐⿑⿒⿓⿔⿕⿰⿱⿲⿳⿴⿵⿶⿷⿸⿹⿺⿻ 、。〃〄々〆〇〈〉《》「」『』【】〒〓〔〕〖〗〘〙〚〛〜〝〞〟〠〡〢〣〤〥〦〧〨〩〪〭〮〯〫〬〰〱〲〳〴〵〶〷〸〹〺〻〼〽〾〿ぁあぃいぅうぇえぉおかがきぎくぐけげこごさざしじすずせぜそぞただちぢっつづてでとどなにぬねのはばぱひびぴふぶぷへべぺほぼぽまみむめもゃやゅゆょよらりるれろゎわゐゑをんゔゕゖ゙゚゛゜ゝゞゟ゠ァアィイゥウェエォオカガキギクグケゲコゴサザシジスズセゼソゾタダチヂッツヅテデトドナニヌネノハバパヒビピフブプヘベペホボポマミムメモャヤュユョヨラリルレロヮワヰヱヲンヴヵヶヷヸヹヺ・ーヽヾヿㄅㄆㄇㄈㄉㄊㄋㄌㄍㄎㄏㄐㄑㄒㄓㄔㄕㄖㄗㄘㄙㄚㄛㄜㄝㄞㄟㄠㄡㄢㄣㄤㄥㄦㄧㄨㄩㄪㄫㄬㄭㄱㄲㄳㄴㄵㄶㄷㄸㄹㄺㄻㄼㄽㄾㄿㅀㅁㅂㅃㅄㅅㅆㅇㅈㅉㅊㅋㅌㅍㅎㅏㅐㅑㅒㅓㅔㅕㅖㅗㅘㅙㅚㅛㅜㅝㅞㅟㅠㅡㅢㅣㅤㅥㅦㅧㅨㅩㅪㅫㅬㅭㅮㅯㅰㅱㅲㅳㅴㅵㅶㅷㅸㅹㅺㅻㅼㅽㅾㅿㆀㆁㆂㆃㆄㆅㆆㆇㆈㆉㆊㆋㆌㆍㆎ㆐㆑㆒㆓㆔㆕㆖㆗㆘㆙㆚㆛㆜㆝㆞㆟ㆠㆡㆢㆣㆤㆥㆦㆧㆨㆩㆪㆫㆬㆭㆮㆯㆰㆱㆲㆳㆴㆵㆶㆷㆸㆹㆺ㇀㇁㇂㇃㇄㇅㇆㇇㇈㇉㇊㇋㇌㇍㇎㇏㇐㇑㇒㇓㇔㇕㇖㇗㇘㇙㇚㇛㇜㇝㇞㇟㇠㇡㇢㇣ㇰㇱㇲㇳㇴㇵㇶㇷㇸㇹㇺㇻㇼㇽㇾㇿ㈀㈁㈂㈃㈄㈅㈆㈇㈈㈉㈊㈋㈌㈍㈎㈏㈐㈑㈒㈓㈔㈕㈖㈗㈘㈙㈚㈛㈜㈝㈞㈠㈡㈢㈣㈤㈥㈦㈧㈨㈩㈪㈫㈬㈭㈮㈯㈰㈱㈲㈳㈴㈵㈶㈷㈸㈹㈺㈻㈼㈽㈾㈿㉀㉁㉂㉃㉄㉅㉆㉇㉈㉉㉊㉋㉌㉍㉎㉏㉐㉑㉒㉓㉔㉕㉖㉗㉘㉙㉚㉛㉜㉝㉞㉟㉠㉡㉢㉣㉤㉥㉦㉧㉨㉩㉪㉫㉬㉭㉮㉯㉰㉱㉲㉳㉴㉵㉶㉷㉸㉹㉺㉻㉼㉽㉾㉿㊀㊁㊂㊃㊄㊅㊆㊇㊈㊉㊊㊋㊌㊍㊎㊏㊐㊑㊒㊓㊔㊕㊖㊗㊘㊙㊚㊛㊜㊝㊞㊟㊠㊡㊢㊣㊤㊥㊦㊧㊨㊩㊪㊫㊬㊭㊮㊯㊰㊱㊲㊳㊴㊵㊶㊷㊸㊹㊺㊻㊼㊽㊾㊿㋀㋁㋂㋃㋄㋅㋆㋇㋈㋉㋊㋋㋌㋍㋎㋏㋐㋑㋒㋓㋔㋕㋖㋗㋘㋙㋚㋛㋜㋝㋞㋟㋠㋡㋢㋣㋤㋥㋦㋧㋨㋩㋪㋫㋬㋭㋮㋯㋰㋱㋲㋳㋴㋵㋶㋷㋸㋹㋺㋻㋼㋽㋾㋿㌀㌁㌂㌃㌄㌅㌆㌇㌈㌉㌊㌋㌌㌍㌎㌏㌐㌑㌒㌓㌔㌕㌖㌗㌘㌙㌚㌛㌜㌝㌞㌟㌠㌡㌢㌣㌤㌥㌦㌧㌨㌩㌪㌫㌬㌭㌮㌯㌰㌱㌲㌳㌴㌵㌶㌷㌸㌹㌺㌻㌼㌽㌾㌿㍀㍁㍂㍃㍄㍅㍆㍇㍈㍉㍊㍋㍌㍍㍎㍏㍐㍑㍒㍓㍔㍕㍖㍗㍘㍙㍚㍛㍜㍝㍞㍟㍠㍡㍢㍣㍤㍥㍦㍧㍨㍩㍪㍫㍬㍭㍮㍯㍰㍱㍲㍳㍴㍵㍶㍷㍸㍹㍺㍻㍼㍽㍾㍿㎀㎁㎂㎃㎄㎅㎆㎇㎈㎉㎊㎋㎌㎍㎎㎏㎐㎑㎒㎓㎔㎕㎖㎗㎘㎙㎚㎛㎜㎝㎞㎟㎠㎡㎢㎣㎤㎥㎦㎧㎨㎩㎪㎫㎬㎭㎮㎯㎰㎱㎲㎳㎴㎵㎶㎷㎸㎹㎺㎻㎼㎽㎾㎿㏀㏁㏂㏃㏄㏅㏆㏇㏈㏉㏊㏋㏌㏍㏎㏏㏐㏑㏒㏓㏔㏕㏖㏗㏘㏙㏚㏛㏜㏝㏞㏟㏠㏡㏢㏣㏤㏥㏦㏧㏨㏩㏪㏫㏬㏭㏮㏯㏰㏱㏲㏳㏴㏵㏶㏷㏸㏹㏺㏻㏼㏽㏾㏿㐀㐁㐂㐃㐄㐅㐆㐇㐈㐉㐊㐋㐌㐍㐎㐏㐐㐑㐒㐓㐔㐕㐖㐗㐘㐙㐚㐛㐜㐝㐞㐟㐠㐡㐢㐣㐤㐥㐦㐧㐨㐩㐪㐫㐬㐭㐮㐯㐰㐱㐲㐳㐴㐵㐶㐷㐸㐹㐺㐻㐼㐽㐾㐿㑀㑁㑂㑃㑄㑅㑆㑇㑈㑉㑊㑋㑌㑍㑎㑏㑐㑑㑒㑓㑔㑕㑖㑗㑘㑙㑚㑛㑜㑝㑞㑟㑠㑡㑢㑣㑤㑥㑦㑧㑨㑩㑪㑫㑬㑭㑮㑯㑰㑱㑲㑳㑴㑵㑶㑷㑸㑹㑺㑻㑼㑽㑾㑿㒀㒁㒂㒃㒄㒅㒆㒇㒈㒉㒊㒋㒌㒍㒎㒏㒐㒑㒒㒓㒔㒕㒖㒗㒘㒙㒚㒛㒜㒝㒞㒟㒠㒡㒢㒣㒤㒥㒦㒧㒨㒩㒪㒫㒬㒭㒮㒯㒰㒱㒲㒳㒴㒵㒶㒷㒸㒹㒺㒻㒼㒽㒾㒿㓀㓁㓂㓃㓄㓅㓆㓇㓈㓉㓊㓋㓌㓍㓎㓏㓐㓑㓒㓓㓔㓕㓖㓗㓘㓙㓚㓛㓜㓝㓞㓟㓠㓡㓢㓣㓤㓥㓦㓧㓨㓩㓪㓫㓬㓭㓮㓯㓰㓱㓲㓳㓴㓵㓶㓷㓸㓹㓺㓻㓼㓽㓾㓿㔀㔁㔂㔃㔄㔅㔆㔇㔈㔉㔊㔋㔌㔍㔎㔏㔐㔑㔒㔓㔔㔕㔖㔗㔘㔙㔚㔛㔜㔝㔞㔟㔠㔡㔢㔣㔤㔥㔦㔧㔨㔩㔪㔫㔬㔭㔮㔯㔰㔱㔲㔳㔴㔵㔶㔷㔸㔹㔺㔻㔼㔽㔾㔿㕀㕁㕂㕃㕄㕅㕆㕇㕈㕉㕊㕋㕌㕍㕎㕏㕐㕑㕒㕓㕔㕕㕖㕗㕘㕙㕚㕛㕜㕝㕞㕟㕠㕡㕢㕣㕤㕥㕦㕧㕨㕩㕪㕫㕬㕭㕮㕯㕰㕱㕲㕳㕴㕵㕶㕷㕸㕹㕺㕻㕼㕽㕾㕿㖀㖁㖂㖃㖄㖅㖆㖇㖈㖉㖊㖋㖌㖍㖎㖏㖐㖑㖒㖓㖔㖕㖖㖗㖘㖙㖚㖛㖜㖝㖞㖟㖠㖡㖢㖣㖤㖥㖦㖧㖨㖩㖪㖫㖬㖭㖮㖯㖰㖱㖲㖳㖴㖵㖶㖷㖸㖹㖺㖻㖼㖽㖾㖿㗀㗁㗂㗃㗄㗅㗆㗇㗈㗉㗊㗋㗌㗍㗎㗏㗐㗑㗒㗓㗔㗕㗖㗗㗘㗙㗚㗛㗜㗝㗞㗟㗠㗡㗢㗣㗤㗥㗦㗧㗨㗩㗪㗫㗬㗭㗮㗯㗰㗱㗲㗳㗴㗵㗶㗷㗸㗹㗺㗻㗼㗽㗾㗿㘀㘁㘂㘃㘄㘅㘆㘇㘈㘉㘊㘋㘌㘍㘎㘏㘐㘑㘒㘓㘔㘕㘖㘗㘘㘙㘚㘛㘜㘝㘞㘟㘠㘡㘢㘣㘤㘥㘦㘧㘨㘩㘪㘫㘬㘭㘮㘯㘰㘱㘲㘳㘴㘵㘶㘷㘸㘹㘺㘻㘼㘽㘾㘿㙀㙁㙂㙃㙄㙅㙆㙇㙈㙉㙊㙋㙌㙍㙎㙏㙐㙑㙒㙓㙔㙕㙖㙗㙘㙙㙚㙛㙜㙝㙞㙟㙠㙡㙢㙣㙤㙥㙦㙧㙨㙩㙪㙫㙬㙭㙮㙯㙰㙱㙲㙳㙴㙵㙶㙷㙸㙹㙺㙻㙼㙽㙾㙿㚀㚁㚂㚃㚄㚅㚆㚇㚈㚉㚊㚋㚌㚍㚎㚏㚐㚑㚒㚓㚔㚕㚖㚗㚘㚙㚚㚛㚜㚝㚞㚟㚠㚡㚢㚣㚤㚥㚦㚧㚨㚩㚪㚫㚬㚭㚮㚯㚰㚱㚲㚳㚴㚵㚶㚷㚸㚹㚺㚻㚼㚽㚾㚿㛀㛁㛂㛃㛄㛅㛆㛇㛈㛉㛊㛋㛌㛍㛎㛏㛐㛑㛒㛓㛔㛕㛖㛗㛘㛙㛚㛛㛜㛝㛞㛟㛠㛡㛢㛣㛤㛥㛦㛧㛨㛩㛪㛫㛬㛭㛮㛯㛰㛱㛲㛳㛴㛵㛶㛷㛸㛹㛺㛻㛼㛽㛾㛿㜀㜁㜂㜃㜄㜅㜆㜇㜈㜉㜊㜋㜌㜍㜎㜏㜐㜑㜒㜓㜔㜕㜖㜗㜘㜙㜚㜛㜜㜝㜞㜟㜠㜡㜢㜣㜤㜥㜦㜧㜨㜩㜪㜫㜬㜭㜮㜯㜰㜱㜲㜳㜴㜵㜶㜷㜸㜹㜺㜻㜼㜽㜾㜿㝀㝁㝂㝃㝄㝅㝆㝇㝈㝉㝊㝋㝌㝍㝎㝏㝐㝑㝒㝓㝔㝕㝖㝗㝘㝙㝚㝛㝜㝝㝞㝟㝠㝡㝢㝣㝤㝥㝦㝧㝨㝩㝪㝫㝬㝭㝮㝯㝰㝱㝲㝳㝴㝵㝶㝷㝸㝹㝺㝻㝼㝽㝾㝿㞀㞁㞂㞃㞄㞅㞆㞇㞈㞉㞊㞋㞌㞍㞎㞏㞐㞑㞒㞓㞔㞕㞖㞗㞘㞙㞚㞛㞜㞝㞞㞟㞠㞡㞢㞣㞤㞥㞦㞧㞨㞩㞪㞫㞬㞭㞮㞯㞰㞱㞲㞳㞴㞵㞶㞷㞸㞹㞺㞻㞼㞽㞾㞿㟀㟁㟂㟃㟄㟅㟆㟇㟈㟉㟊㟋㟌㟍㟎㟏㟐㟑㟒㟓㟔㟕㟖㟗㟘㟙㟚㟛㟜㟝㟞㟟㟠㟡㟢㟣㟤㟥㟦㟧㟨㟩㟪㟫㟬㟭㟮㟯㟰㟱㟲㟳㟴㟵㟶㟷㟸㟹㟺㟻㟼㟽㟾㟿㠀㠁㠂㠃㠄㠅㠆㠇㠈㠉㠊㠋㠌㠍㠎㠏㠐㠑㠒㠓㠔㠕㠖㠗㠘㠙㠚㠛㠜㠝㠞㠟㠠㠡㠢㠣㠤㠥㠦㠧㠨㠩㠪㠫㠬㠭㠮㠯㠰㠱㠲㠳㠴㠵㠶㠷㠸㠹㠺㠻㠼㠽㠾㠿㡀㡁㡂㡃㡄㡅㡆㡇㡈㡉㡊㡋㡌㡍㡎㡏㡐㡑㡒㡓㡔㡕㡖㡗㡘㡙㡚㡛㡜㡝㡞㡟㡠㡡㡢㡣㡤㡥㡦㡧㡨㡩㡪㡫㡬㡭㡮㡯㡰㡱㡲㡳㡴㡵㡶㡷㡸㡹㡺㡻㡼㡽㡾㡿㢀㢁㢂㢃㢄㢅㢆㢇㢈㢉㢊㢋㢌㢍㢎㢏㢐㢑㢒㢓㢔㢕㢖㢗㢘㢙㢚㢛㢜㢝㢞㢟㢠㢡㢢㢣㢤㢥㢦㢧㢨㢩㢪㢫㢬㢭㢮㢯㢰㢱㢲㢳㢴㢵㢶㢷㢸㢹㢺㢻㢼㢽㢾㢿㣀㣁㣂㣃㣄㣅㣆㣇㣈㣉㣊㣋㣌㣍㣎㣏㣐㣑㣒㣓㣔㣕㣖㣗㣘㣙㣚㣛㣜㣝㣞㣟㣠㣡㣢㣣㣤㣥㣦㣧㣨㣩㣪㣫㣬㣭㣮㣯㣰㣱㣲㣳㣴㣵㣶㣷㣸㣹㣺㣻㣼㣽㣾㣿㤀㤁㤂㤃㤄㤅㤆㤇㤈㤉㤊㤋㤌㤍㤎㤏㤐㤑㤒㤓㤔㤕㤖㤗㤘㤙㤚㤛㤜㤝㤞㤟㤠㤡㤢㤣㤤㤥㤦㤧㤨㤩㤪㤫㤬㤭㤮㤯㤰㤱㤲㤳㤴㤵㤶㤷㤸㤹㤺㤻㤼㤽㤾㤿㥀㥁㥂㥃㥄㥅㥆㥇㥈㥉㥊㥋㥌㥍㥎㥏㥐㥑㥒㥓㥔㥕㥖㥗㥘㥙㥚㥛㥜㥝㥞㥟㥠㥡㥢㥣㥤㥥㥦㥧㥨㥩㥪㥫㥬㥭㥮㥯㥰㥱㥲㥳㥴㥵㥶㥷㥸㥹㥺㥻㥼㥽㥾㥿㦀㦁㦂㦃㦄㦅㦆㦇㦈㦉㦊㦋㦌㦍㦎㦏㦐㦑㦒㦓㦔㦕㦖㦗㦘㦙㦚㦛㦜㦝㦞㦟㦠㦡㦢㦣㦤㦥㦦㦧㦨㦩㦪㦫㦬㦭㦮㦯㦰㦱㦲㦳㦴㦵㦶㦷㦸㦹㦺㦻㦼㦽㦾㦿㧀㧁㧂㧃㧄㧅㧆㧇㧈㧉㧊㧋㧌㧍㧎㧏㧐㧑㧒㧓㧔㧕㧖㧗㧘㧙㧚㧛㧜㧝㧞㧟㧠㧡㧢㧣㧤㧥㧦㧧㧨㧩㧪㧫㧬㧭㧮㧯㧰㧱㧲㧳㧴㧵㧶㧷㧸㧹㧺㧻㧼㧽㧾㧿㨀㨁㨂㨃㨄㨅㨆㨇㨈㨉㨊㨋㨌㨍㨎㨏㨐㨑㨒㨓㨔㨕㨖㨗㨘㨙㨚㨛㨜㨝㨞㨟㨠㨡㨢㨣㨤㨥㨦㨧㨨㨩㨪㨫㨬㨭㨮㨯㨰㨱㨲㨳㨴㨵㨶㨷㨸㨹㨺㨻㨼㨽㨾㨿㩀㩁㩂㩃㩄㩅㩆㩇㩈㩉㩊㩋㩌㩍㩎㩏㩐㩑㩒㩓㩔㩕㩖㩗㩘㩙㩚㩛㩜㩝㩞㩟㩠㩡㩢㩣㩤㩥㩦㩧㩨㩩㩪㩫㩬㩭㩮㩯㩰㩱㩲㩳㩴㩵㩶㩷㩸㩹㩺㩻㩼㩽㩾㩿㪀㪁㪂㪃㪄㪅㪆㪇㪈㪉㪊㪋㪌㪍㪎㪏㪐㪑㪒㪓㪔㪕㪖㪗㪘㪙㪚㪛㪜㪝㪞㪟㪠㪡㪢㪣㪤㪥㪦㪧㪨㪩㪪㪫㪬㪭㪮㪯㪰㪱㪲㪳㪴㪵㪶㪷㪸㪹㪺㪻㪼㪽㪾㪿㫀㫁㫂㫃㫄㫅㫆㫇㫈㫉㫊㫋㫌㫍㫎㫏㫐㫑㫒㫓㫔㫕㫖㫗㫘㫙㫚㫛㫜㫝㫞㫟㫠㫡㫢㫣㫤㫥㫦㫧㫨㫩㫪㫫㫬㫭㫮㫯㫰㫱㫲㫳㫴㫵㫶㫷㫸㫹㫺㫻㫼㫽㫾㫿㬀㬁㬂㬃㬄㬅㬆㬇㬈㬉㬊㬋㬌㬍㬎㬏㬐㬑㬒㬓㬔㬕㬖㬗㬘㬙㬚㬛㬜㬝㬞㬟㬠㬡㬢㬣㬤㬥㬦㬧㬨㬩㬪㬫㬬㬭㬮㬯㬰㬱㬲㬳㬴㬵㬶㬷㬸㬹㬺㬻㬼㬽㬾㬿㭀㭁㭂㭃㭄㭅㭆㭇㭈㭉㭊㭋㭌㭍㭎㭏㭐㭑㭒㭓㭔㭕㭖㭗㭘㭙㭚㭛㭜㭝㭞㭟㭠㭡㭢㭣㭤㭥㭦㭧㭨㭩㭪㭫㭬㭭㭮㭯㭰㭱㭲㭳㭴㭵㭶㭷㭸㭹㭺㭻㭼㭽㭾㭿㮀㮁㮂㮃㮄㮅㮆㮇㮈㮉㮊㮋㮌㮍㮎㮏㮐㮑㮒㮓㮔㮕㮖㮗㮘㮙㮚㮛㮜㮝㮞㮟㮠㮡㮢㮣㮤㮥㮦㮧㮨㮩㮪㮫㮬㮭㮮㮯㮰㮱㮲㮳㮴㮵㮶㮷㮸㮹㮺㮻㮼㮽㮾㮿㯀㯁㯂㯃㯄㯅㯆㯇㯈㯉㯊㯋㯌㯍㯎㯏㯐㯑㯒㯓㯔㯕㯖㯗㯘㯙㯚㯛㯜㯝㯞㯟㯠㯡㯢㯣㯤㯥㯦㯧㯨㯩㯪㯫㯬㯭㯮㯯㯰㯱㯲㯳㯴㯵㯶㯷㯸㯹㯺㯻㯼㯽㯾㯿㰀㰁㰂㰃㰄㰅㰆㰇㰈㰉㰊㰋㰌㰍㰎㰏㰐㰑㰒㰓㰔㰕㰖㰗㰘㰙㰚㰛㰜㰝㰞㰟㰠㰡㰢㰣㰤㰥㰦㰧㰨㰩㰪㰫㰬㰭㰮㰯㰰㰱㰲㰳㰴㰵㰶㰷㰸㰹㰺㰻㰼㰽㰾㰿㱀㱁㱂㱃㱄㱅㱆㱇㱈㱉㱊㱋㱌㱍㱎㱏㱐㱑㱒㱓㱔㱕㱖㱗㱘㱙㱚㱛㱜㱝㱞㱟㱠㱡㱢㱣㱤㱥㱦㱧㱨㱩㱪㱫㱬㱭㱮㱯㱰㱱㱲㱳㱴㱵㱶㱷㱸㱹㱺㱻㱼㱽㱾㱿㲀㲁㲂㲃㲄㲅㲆㲇㲈㲉㲊㲋㲌㲍㲎㲏㲐㲑㲒㲓㲔㲕㲖㲗㲘㲙㲚㲛㲜㲝㲞㲟㲠㲡㲢㲣㲤㲥㲦㲧㲨㲩㲪㲫㲬㲭㲮㲯㲰㲱㲲㲳㲴㲵㲶㲷㲸㲹㲺㲻㲼㲽㲾㲿㳀㳁㳂㳃㳄㳅㳆㳇㳈㳉㳊㳋㳌㳍㳎㳏㳐㳑㳒㳓㳔㳕㳖㳗㳘㳙㳚㳛㳜㳝㳞㳟㳠㳡㳢㳣㳤㳥㳦㳧㳨㳩㳪㳫㳬㳭㳮㳯㳰㳱㳲㳳㳴㳵㳶㳷㳸㳹㳺㳻㳼㳽㳾㳿㴀㴁㴂㴃㴄㴅㴆㴇㴈㴉㴊㴋㴌㴍㴎㴏㴐㴑㴒㴓㴔㴕㴖㴗㴘㴙㴚㴛㴜㴝㴞㴟㴠㴡㴢㴣㴤㴥㴦㴧㴨㴩㴪㴫㴬㴭㴮㴯㴰㴱㴲㴳㴴㴵㴶㴷㴸㴹㴺㴻㴼㴽㴾㴿㵀㵁㵂㵃㵄㵅㵆㵇㵈㵉㵊㵋㵌㵍㵎㵏㵐㵑㵒㵓㵔㵕㵖㵗㵘㵙㵚㵛㵜㵝㵞㵟㵠㵡㵢㵣㵤㵥㵦㵧㵨㵩㵪㵫㵬㵭㵮㵯㵰㵱㵲㵳㵴㵵㵶㵷㵸㵹㵺㵻㵼㵽㵾㵿㶀㶁㶂㶃㶄㶅㶆㶇㶈㶉㶊㶋㶌㶍㶎㶏㶐㶑㶒㶓㶔㶕㶖㶗㶘㶙㶚㶛㶜㶝㶞㶟㶠㶡㶢㶣㶤㶥㶦㶧㶨㶩㶪㶫㶬㶭㶮㶯㶰㶱㶲㶳㶴㶵㶶㶷㶸㶹㶺㶻㶼㶽㶾㶿㷀㷁㷂㷃㷄㷅㷆㷇㷈㷉㷊㷋㷌㷍㷎㷏㷐㷑㷒㷓㷔㷕㷖㷗㷘㷙㷚㷛㷜㷝㷞㷟㷠㷡㷢㷣㷤㷥㷦㷧㷨㷩㷪㷫㷬㷭㷮㷯㷰㷱㷲㷳㷴㷵㷶㷷㷸㷹㷺㷻㷼㷽㷾㷿㸀㸁㸂㸃㸄㸅㸆㸇㸈㸉㸊㸋㸌㸍㸎㸏㸐㸑㸒㸓㸔㸕㸖㸗㸘㸙㸚㸛㸜㸝㸞㸟㸠㸡㸢㸣㸤㸥㸦㸧㸨㸩㸪㸫㸬㸭㸮㸯㸰㸱㸲㸳㸴㸵㸶㸷㸸㸹㸺㸻㸼㸽㸾㸿㹀㹁㹂㹃㹄㹅㹆㹇㹈㹉㹊㹋㹌㹍㹎㹏㹐㹑㹒㹓㹔㹕㹖㹗㹘㹙㹚㹛㹜㹝㹞㹟㹠㹡㹢㹣㹤㹥㹦㹧㹨㹩㹪㹫㹬㹭㹮㹯㹰㹱㹲㹳㹴㹵㹶㹷㹸㹹㹺㹻㹼㹽㹾㹿㺀㺁㺂㺃㺄㺅㺆㺇㺈㺉㺊㺋㺌㺍㺎㺏㺐㺑㺒㺓㺔㺕㺖㺗㺘㺙㺚㺛㺜㺝㺞㺟㺠㺡㺢㺣㺤㺥㺦㺧㺨㺩㺪㺫㺬㺭㺮㺯㺰㺱㺲㺳㺴㺵㺶㺷㺸㺹㺺㺻㺼㺽㺾㺿㻀㻁㻂㻃㻄㻅㻆㻇㻈㻉㻊㻋㻌㻍㻎㻏㻐㻑㻒㻓㻔㻕㻖㻗㻘㻙㻚㻛㻜㻝㻞㻟㻠㻡㻢㻣㻤㻥㻦㻧㻨㻩㻪㻫㻬㻭㻮㻯㻰㻱㻲㻳㻴㻵㻶㻷㻸㻹㻺㻻㻼㻽㻾㻿㼀㼁㼂㼃㼄㼅㼆㼇㼈㼉㼊㼋㼌㼍㼎㼏㼐㼑㼒㼓㼔㼕㼖㼗㼘㼙㼚㼛㼜㼝㼞㼟㼠㼡㼢㼣㼤㼥㼦㼧㼨㼩㼪㼫㼬㼭㼮㼯㼰㼱㼲㼳㼴㼵㼶㼷㼸㼹㼺㼻㼼㼽㼾㼿㽀㽁㽂㽃㽄㽅㽆㽇㽈㽉㽊㽋㽌㽍㽎㽏㽐㽑㽒㽓㽔㽕㽖㽗㽘㽙㽚㽛㽜㽝㽞㽟㽠㽡㽢㽣㽤㽥㽦㽧㽨㽩㽪㽫㽬㽭㽮㽯㽰㽱㽲㽳㽴㽵㽶㽷㽸㽹㽺㽻㽼㽽㽾㽿㾀㾁㾂㾃㾄㾅㾆㾇㾈㾉㾊㾋㾌㾍㾎㾏㾐㾑㾒㾓㾔㾕㾖㾗㾘㾙㾚㾛㾜㾝㾞㾟㾠㾡㾢㾣㾤㾥㾦㾧㾨㾩㾪㾫㾬㾭㾮㾯㾰㾱㾲㾳㾴㾵㾶㾷㾸㾹㾺㾻㾼㾽㾾㾿㿀㿁㿂㿃㿄㿅㿆㿇㿈㿉㿊㿋㿌㿍㿎㿏㿐㿑㿒㿓㿔㿕㿖㿗㿘㿙㿚㿛㿜㿝㿞㿟㿠㿡㿢㿣㿤㿥㿦㿧㿨㿩㿪㿫㿬㿭㿮㿯㿰㿱㿲㿳㿴㿵㿶㿷㿸㿹㿺㿻㿼㿽㿾㿿䀀䀁䀂䀃䀄䀅䀆䀇䀈䀉䀊䀋䀌䀍䀎䀏䀐䀑䀒䀓䀔䀕䀖䀗䀘䀙䀚䀛䀜䀝䀞䀟䀠䀡䀢䀣䀤䀥䀦䀧䀨䀩䀪䀫䀬䀭䀮䀯䀰䀱䀲䀳䀴䀵䀶䀷䀸䀹䀺䀻䀼䀽䀾䀿䁀䁁䁂䁃䁄䁅䁆䁇䁈䁉䁊䁋䁌䁍䁎䁏䁐䁑䁒䁓䁔䁕䁖䁗䁘䁙䁚䁛䁜䁝䁞䁟䁠䁡䁢䁣䁤䁥䁦䁧䁨䁩䁪䁫䁬䁭䁮䁯䁰䁱䁲䁳䁴䁵䁶䁷䁸䁹䁺䁻䁼䁽䁾䁿䂀䂁䂂䂃䂄䂅䂆䂇䂈䂉䂊䂋䂌䂍䂎䂏䂐䂑䂒䂓䂔䂕䂖䂗䂘䂙䂚䂛䂜䂝䂞䂟䂠䂡䂢䂣䂤䂥䂦䂧䂨䂩䂪䂫䂬䂭䂮䂯䂰䂱䂲䂳䂴䂵䂶䂷䂸䂹䂺䂻䂼䂽䂾䂿䃀䃁䃂䃃䃄䃅䃆䃇䃈䃉䃊䃋䃌䃍䃎䃏䃐䃑䃒䃓䃔䃕䃖䃗䃘䃙䃚䃛䃜䃝䃞䃟䃠䃡䃢䃣䃤䃥䃦䃧䃨䃩䃪䃫䃬䃭䃮䃯䃰䃱䃲䃳䃴䃵䃶䃷䃸䃹䃺䃻䃼䃽䃾䃿䄀䄁䄂䄃䄄䄅䄆䄇䄈䄉䄊䄋䄌䄍䄎䄏䄐䄑䄒䄓䄔䄕䄖䄗䄘䄙䄚䄛䄜䄝䄞䄟䄠䄡䄢䄣䄤䄥䄦䄧䄨䄩䄪䄫䄬䄭䄮䄯䄰䄱䄲䄳䄴䄵䄶䄷䄸䄹䄺䄻䄼䄽䄾䄿䅀䅁䅂䅃䅄䅅䅆䅇䅈䅉䅊䅋䅌䅍䅎䅏䅐䅑䅒䅓䅔䅕䅖䅗䅘䅙䅚䅛䅜䅝䅞䅟䅠䅡䅢䅣䅤䅥䅦䅧䅨䅩䅪䅫䅬䅭䅮䅯䅰䅱䅲䅳䅴䅵䅶䅷䅸䅹䅺䅻䅼䅽䅾䅿䆀䆁䆂䆃䆄䆅䆆䆇䆈䆉䆊䆋䆌䆍䆎䆏䆐䆑䆒䆓䆔䆕䆖䆗䆘䆙䆚䆛䆜䆝䆞䆟䆠䆡䆢䆣䆤䆥䆦䆧䆨䆩䆪䆫䆬䆭䆮䆯䆰䆱䆲䆳䆴䆵䆶䆷䆸䆹䆺䆻䆼䆽䆾䆿䇀䇁䇂䇃䇄䇅䇆䇇䇈䇉䇊䇋䇌䇍䇎䇏䇐䇑䇒䇓䇔䇕䇖䇗䇘䇙䇚䇛䇜䇝䇞䇟䇠䇡䇢䇣䇤䇥䇦䇧䇨䇩䇪䇫䇬䇭䇮䇯䇰䇱䇲䇳䇴䇵䇶䇷䇸䇹䇺䇻䇼䇽䇾䇿䈀䈁䈂䈃䈄䈅䈆䈇䈈䈉䈊䈋䈌䈍䈎䈏䈐䈑䈒䈓䈔䈕䈖䈗䈘䈙䈚䈛䈜䈝䈞䈟䈠䈡䈢䈣䈤䈥䈦䈧䈨䈩䈪䈫䈬䈭䈮䈯䈰䈱䈲䈳䈴䈵䈶䈷䈸䈹䈺䈻䈼䈽䈾䈿䉀䉁䉂䉃䉄䉅䉆䉇䉈䉉䉊䉋䉌䉍䉎䉏䉐䉑䉒䉓䉔䉕䉖䉗䉘䉙䉚䉛䉜䉝䉞䉟䉠䉡䉢䉣䉤䉥䉦䉧䉨䉩䉪䉫䉬䉭䉮䉯䉰䉱䉲䉳䉴䉵䉶䉷䉸䉹䉺䉻䉼䉽䉾䉿䊀䊁䊂䊃䊄䊅䊆䊇䊈䊉䊊䊋䊌䊍䊎䊏䊐䊑䊒䊓䊔䊕䊖䊗䊘䊙䊚䊛䊜䊝䊞䊟䊠䊡䊢䊣䊤䊥䊦䊧䊨䊩䊪䊫䊬䊭䊮䊯䊰䊱䊲䊳䊴䊵䊶䊷䊸䊹䊺䊻䊼䊽䊾䊿䋀䋁䋂䋃䋄䋅䋆䋇䋈䋉䋊䋋䋌䋍䋎䋏䋐䋑䋒䋓䋔䋕䋖䋗䋘䋙䋚䋛䋜䋝䋞䋟䋠䋡䋢䋣䋤䋥䋦䋧䋨䋩䋪䋫䋬䋭䋮䋯䋰䋱䋲䋳䋴䋵䋶䋷䋸䋹䋺䋻䋼䋽䋾䋿䌀䌁䌂䌃䌄䌅䌆䌇䌈䌉䌊䌋䌌䌍䌎䌏䌐䌑䌒䌓䌔䌕䌖䌗䌘䌙䌚䌛䌜䌝䌞䌟䌠䌡䌢䌣䌤䌥䌦䌧䌨䌩䌪䌫䌬䌭䌮䌯䌰䌱䌲䌳䌴䌵䌶䌷䌸䌹䌺䌻䌼䌽䌾䌿䍀䍁䍂䍃䍄䍅䍆䍇䍈䍉䍊䍋䍌䍍䍎䍏䍐䍑䍒䍓䍔䍕䍖䍗䍘䍙䍚䍛䍜䍝䍞䍟䍠䍡䍢䍣䍤䍥䍦䍧䍨䍩䍪䍫䍬䍭䍮䍯䍰䍱䍲䍳䍴䍵䍶䍷䍸䍹䍺䍻䍼䍽䍾䍿䎀䎁䎂䎃䎄䎅䎆䎇䎈䎉䎊䎋䎌䎍䎎䎏䎐䎑䎒䎓䎔䎕䎖䎗䎘䎙䎚䎛䎜䎝䎞䎟䎠䎡䎢䎣䎤䎥䎦䎧䎨䎩䎪䎫䎬䎭䎮䎯䎰䎱䎲䎳䎴䎵䎶䎷䎸䎹䎺䎻䎼䎽䎾䎿䏀䏁䏂䏃䏄䏅䏆䏇䏈䏉䏊䏋䏌䏍䏎䏏䏐䏑䏒䏓䏔䏕䏖䏗䏘䏙䏚䏛䏜䏝䏞䏟䏠䏡䏢䏣䏤䏥䏦䏧䏨䏩䏪䏫䏬䏭䏮䏯䏰䏱䏲䏳䏴䏵䏶䏷䏸䏹䏺䏻䏼䏽䏾䏿䐀䐁䐂䐃䐄䐅䐆䐇䐈䐉䐊䐋䐌䐍䐎䐏䐐䐑䐒䐓䐔䐕䐖䐗䐘䐙䐚䐛䐜䐝䐞䐟䐠䐡䐢䐣䐤䐥䐦䐧䐨䐩䐪䐫䐬䐭䐮䐯䐰䐱䐲䐳䐴䐵䐶䐷䐸䐹䐺䐻䐼䐽䐾䐿䑀䑁䑂䑃䑄䑅䑆䑇䑈䑉䑊䑋䑌䑍䑎䑏䑐䑑䑒䑓䑔䑕䑖䑗䑘䑙䑚䑛䑜䑝䑞䑟䑠䑡䑢䑣䑤䑥䑦䑧䑨䑩䑪䑫䑬䑭䑮䑯䑰䑱䑲䑳䑴䑵䑶䑷䑸䑹䑺䑻䑼䑽䑾䑿䒀䒁䒂䒃䒄䒅䒆䒇䒈䒉䒊䒋䒌䒍䒎䒏䒐䒑䒒䒓䒔䒕䒖䒗䒘䒙䒚䒛䒜䒝䒞䒟䒠䒡䒢䒣䒤䒥䒦䒧䒨䒩䒪䒫䒬䒭䒮䒯䒰䒱䒲䒳䒴䒵䒶䒷䒸䒹䒺䒻䒼䒽䒾䒿䓀䓁䓂䓃䓄䓅䓆䓇䓈䓉䓊䓋䓌䓍䓎䓏䓐䓑䓒䓓䓔䓕䓖䓗䓘䓙䓚䓛䓜䓝䓞䓟䓠䓡䓢䓣䓤䓥䓦䓧䓨䓩䓪䓫䓬䓭䓮䓯䓰䓱䓲䓳䓴䓵䓶䓷䓸䓹䓺䓻䓼䓽䓾䓿䔀䔁䔂䔃䔄䔅䔆䔇䔈䔉䔊䔋䔌䔍䔎䔏䔐䔑䔒䔓䔔䔕䔖䔗䔘䔙䔚䔛䔜䔝䔞䔟䔠䔡䔢䔣䔤䔥䔦䔧䔨䔩䔪䔫䔬䔭䔮䔯䔰䔱䔲䔳䔴䔵䔶䔷䔸䔹䔺䔻䔼䔽䔾䔿䕀䕁䕂䕃䕄䕅䕆䕇䕈䕉䕊䕋䕌䕍䕎䕏䕐䕑䕒䕓䕔䕕䕖䕗䕘䕙䕚䕛䕜䕝䕞䕟䕠䕡䕢䕣䕤䕥䕦䕧䕨䕩䕪䕫䕬䕭䕮䕯䕰䕱䕲䕳䕴䕵䕶䕷䕸䕹䕺䕻䕼䕽䕾䕿䖀䖁䖂䖃䖄䖅䖆䖇䖈䖉䖊䖋䖌䖍䖎䖏䖐䖑䖒䖓䖔䖕䖖䖗䖘䖙䖚䖛䖜䖝䖞䖟䖠䖡䖢䖣䖤䖥䖦䖧䖨䖩䖪䖫䖬䖭䖮䖯䖰䖱䖲䖳䖴䖵䖶䖷䖸䖹䖺䖻䖼䖽䖾䖿䗀䗁䗂䗃䗄䗅䗆䗇䗈䗉䗊䗋䗌䗍䗎䗏䗐䗑䗒䗓䗔䗕䗖䗗䗘䗙䗚䗛䗜䗝䗞䗟䗠䗡䗢䗣䗤䗥䗦䗧䗨䗩䗪䗫䗬䗭䗮䗯䗰䗱䗲䗳䗴䗵䗶䗷䗸䗹䗺䗻䗼䗽䗾䗿䘀䘁䘂䘃䘄䘅䘆䘇䘈䘉䘊䘋䘌䘍䘎䘏䘐䘑䘒䘓䘔䘕䘖䘗䘘䘙䘚䘛䘜䘝䘞䘟䘠䘡䘢䘣䘤䘥䘦䘧䘨䘩䘪䘫䘬䘭䘮䘯䘰䘱䘲䘳䘴䘵䘶䘷䘸䘹䘺䘻䘼䘽䘾䘿䙀䙁䙂䙃䙄䙅䙆䙇䙈䙉䙊䙋䙌䙍䙎䙏䙐䙑䙒䙓䙔䙕䙖䙗䙘䙙䙚䙛䙜䙝䙞䙟䙠䙡䙢䙣䙤䙥䙦䙧䙨䙩䙪䙫䙬䙭䙮䙯䙰䙱䙲䙳䙴䙵䙶䙷䙸䙹䙺䙻䙼䙽䙾䙿䚀䚁䚂䚃䚄䚅䚆䚇䚈䚉䚊䚋䚌䚍䚎䚏䚐䚑䚒䚓䚔䚕䚖䚗䚘䚙䚚䚛䚜䚝䚞䚟䚠䚡䚢䚣䚤䚥䚦䚧䚨䚩䚪䚫䚬䚭䚮䚯䚰䚱䚲䚳䚴䚵䚶䚷䚸䚹䚺䚻䚼䚽䚾䚿䛀䛁䛂䛃䛄䛅䛆䛇䛈䛉䛊䛋䛌䛍䛎䛏䛐䛑䛒䛓䛔䛕䛖䛗䛘䛙䛚䛛䛜䛝䛞䛟䛠䛡䛢䛣䛤䛥䛦䛧䛨䛩䛪䛫䛬䛭䛮䛯䛰䛱䛲䛳䛴䛵䛶䛷䛸䛹䛺䛻䛼䛽䛾䛿䜀䜁䜂䜃䜄䜅䜆䜇䜈䜉䜊䜋䜌䜍䜎䜏䜐䜑䜒䜓䜔䜕䜖䜗䜘䜙䜚䜛䜜䜝䜞䜟䜠䜡䜢䜣䜤䜥䜦䜧䜨䜩䜪䜫䜬䜭䜮䜯䜰䜱䜲䜳䜴䜵䜶䜷䜸䜹䜺䜻䜼䜽䜾䜿䝀䝁䝂䝃䝄䝅䝆䝇䝈䝉䝊䝋䝌䝍䝎䝏䝐䝑䝒䝓䝔䝕䝖䝗䝘䝙䝚䝛䝜䝝䝞䝟䝠䝡䝢䝣䝤䝥䝦䝧䝨䝩䝪䝫䝬䝭䝮䝯䝰䝱䝲䝳䝴䝵䝶䝷䝸䝹䝺䝻䝼䝽䝾䝿䞀䞁䞂䞃䞄䞅䞆䞇䞈䞉䞊䞋䞌䞍䞎䞏䞐䞑䞒䞓䞔䞕䞖䞗䞘䞙䞚䞛䞜䞝䞞䞟䞠䞡䞢䞣䞤䞥䞦䞧䞨䞩䞪䞫䞬䞭䞮䞯䞰䞱䞲䞳䞴䞵䞶䞷䞸䞹䞺䞻䞼䞽䞾䞿䟀䟁䟂䟃䟄䟅䟆䟇䟈䟉䟊䟋䟌䟍䟎䟏䟐䟑䟒䟓䟔䟕䟖䟗䟘䟙䟚䟛䟜䟝䟞䟟䟠䟡䟢䟣䟤䟥䟦䟧䟨䟩䟪䟫䟬䟭䟮䟯䟰䟱䟲䟳䟴䟵䟶䟷䟸䟹䟺䟻䟼䟽䟾䟿䠀䠁䠂䠃䠄䠅䠆䠇䠈䠉䠊䠋䠌䠍䠎䠏䠐䠑䠒䠓䠔䠕䠖䠗䠘䠙䠚䠛䠜䠝䠞䠟䠠䠡䠢䠣䠤䠥䠦䠧䠨䠩䠪䠫䠬䠭䠮䠯䠰䠱䠲䠳䠴䠵䠶䠷䠸䠹䠺䠻䠼䠽䠾䠿䡀䡁䡂䡃䡄䡅䡆䡇䡈䡉䡊䡋䡌䡍䡎䡏䡐䡑䡒䡓䡔䡕䡖䡗䡘䡙䡚䡛䡜䡝䡞䡟䡠䡡䡢䡣䡤䡥䡦䡧䡨䡩䡪䡫䡬䡭䡮䡯䡰䡱䡲䡳䡴䡵䡶䡷䡸䡹䡺䡻䡼䡽䡾䡿䢀䢁䢂䢃䢄䢅䢆䢇䢈䢉䢊䢋䢌䢍䢎䢏䢐䢑䢒䢓䢔䢕䢖䢗䢘䢙䢚䢛䢜䢝䢞䢟䢠䢡䢢䢣䢤䢥䢦䢧䢨䢩䢪䢫䢬䢭䢮䢯䢰䢱䢲䢳䢴䢵䢶䢷䢸䢹䢺䢻䢼䢽䢾䢿䣀䣁䣂䣃䣄䣅䣆䣇䣈䣉䣊䣋䣌䣍䣎䣏䣐䣑䣒䣓䣔䣕䣖䣗䣘䣙䣚䣛䣜䣝䣞䣟䣠䣡䣢䣣䣤䣥䣦䣧䣨䣩䣪䣫䣬䣭䣮䣯䣰䣱䣲䣳䣴䣵䣶䣷䣸䣹䣺䣻䣼䣽䣾䣿䤀䤁䤂䤃䤄䤅䤆䤇䤈䤉䤊䤋䤌䤍䤎䤏䤐䤑䤒䤓䤔䤕䤖䤗䤘䤙䤚䤛䤜䤝䤞䤟䤠䤡䤢䤣䤤䤥䤦䤧䤨䤩䤪䤫䤬䤭䤮䤯䤰䤱䤲䤳䤴䤵䤶䤷䤸䤹䤺䤻䤼䤽䤾䤿䥀䥁䥂䥃䥄䥅䥆䥇䥈䥉䥊䥋䥌䥍䥎䥏䥐䥑䥒䥓䥔䥕䥖䥗䥘䥙䥚䥛䥜䥝䥞䥟䥠䥡䥢䥣䥤䥥䥦䥧䥨䥩䥪䥫䥬䥭䥮䥯䥰䥱䥲䥳䥴䥵䥶䥷䥸䥹䥺䥻䥼䥽䥾䥿䦀䦁䦂䦃䦄䦅䦆䦇䦈䦉䦊䦋䦌䦍䦎䦏䦐䦑䦒䦓䦔䦕䦖䦗䦘䦙䦚䦛䦜䦝䦞䦟䦠䦡䦢䦣䦤䦥䦦䦧䦨䦩䦪䦫䦬䦭䦮䦯䦰䦱䦲䦳䦴䦵䦶䦷䦸䦹䦺䦻䦼䦽䦾䦿䧀䧁䧂䧃䧄䧅䧆䧇䧈䧉䧊䧋䧌䧍䧎䧏䧐䧑䧒䧓䧔䧕䧖䧗䧘䧙䧚䧛䧜䧝䧞䧟䧠䧡䧢䧣䧤䧥䧦䧧䧨䧩䧪䧫䧬䧭䧮䧯䧰䧱䧲䧳䧴䧵䧶䧷䧸䧹䧺䧻䧼䧽䧾䧿䨀䨁䨂䨃䨄䨅䨆䨇䨈䨉䨊䨋䨌䨍䨎䨏䨐䨑䨒䨓䨔䨕䨖䨗䨘䨙䨚䨛䨜䨝䨞䨟䨠䨡䨢䨣䨤䨥䨦䨧䨨䨩䨪䨫䨬䨭䨮䨯䨰䨱䨲䨳䨴䨵䨶䨷䨸䨹䨺䨻䨼䨽䨾䨿䩀䩁䩂䩃䩄䩅䩆䩇䩈䩉䩊䩋䩌䩍䩎䩏䩐䩑䩒䩓䩔䩕䩖䩗䩘䩙䩚䩛䩜䩝䩞䩟䩠䩡䩢䩣䩤䩥䩦䩧䩨䩩䩪䩫䩬䩭䩮䩯䩰䩱䩲䩳䩴䩵䩶䩷䩸䩹䩺䩻䩼䩽䩾䩿䪀䪁䪂䪃䪄䪅䪆䪇䪈䪉䪊䪋䪌䪍䪎䪏䪐䪑䪒䪓䪔䪕䪖䪗䪘䪙䪚䪛䪜䪝䪞䪟䪠䪡䪢䪣䪤䪥䪦䪧䪨䪩䪪䪫䪬䪭䪮䪯䪰䪱䪲䪳䪴䪵䪶䪷䪸䪹䪺䪻䪼䪽䪾䪿䫀䫁䫂䫃䫄䫅䫆䫇䫈䫉䫊䫋䫌䫍䫎䫏䫐䫑䫒䫓䫔䫕䫖䫗䫘䫙䫚䫛䫜䫝䫞䫟䫠䫡䫢䫣䫤䫥䫦䫧䫨䫩䫪䫫䫬䫭䫮䫯䫰䫱䫲䫳䫴䫵䫶䫷䫸䫹䫺䫻䫼䫽䫾䫿䬀䬁䬂䬃䬄䬅䬆䬇䬈䬉䬊䬋䬌䬍䬎䬏䬐䬑䬒䬓䬔䬕䬖䬗䬘䬙䬚䬛䬜䬝䬞䬟䬠䬡䬢䬣䬤䬥䬦䬧䬨䬩䬪䬫䬬䬭䬮䬯䬰䬱䬲䬳䬴䬵䬶䬷䬸䬹䬺䬻䬼䬽䬾䬿䭀䭁䭂䭃䭄䭅䭆䭇䭈䭉䭊䭋䭌䭍䭎䭏䭐䭑䭒䭓䭔䭕䭖䭗䭘䭙䭚䭛䭜䭝䭞䭟䭠䭡䭢䭣䭤䭥䭦䭧䭨䭩䭪䭫䭬䭭䭮䭯䭰䭱䭲䭳䭴䭵䭶䭷䭸䭹䭺䭻䭼䭽䭾䭿䮀䮁䮂䮃䮄䮅䮆䮇䮈䮉䮊䮋䮌䮍䮎䮏䮐䮑䮒䮓䮔䮕䮖䮗䮘䮙䮚䮛䮜䮝䮞䮟䮠䮡䮢䮣䮤䮥䮦䮧䮨䮩䮪䮫䮬䮭䮮䮯䮰䮱䮲䮳䮴䮵䮶䮷䮸䮹䮺䮻䮼䮽䮾䮿䯀䯁䯂䯃䯄䯅䯆䯇䯈䯉䯊䯋䯌䯍䯎䯏䯐䯑䯒䯓䯔䯕䯖䯗䯘䯙䯚䯛䯜䯝䯞䯟䯠䯡䯢䯣䯤䯥䯦䯧䯨䯩䯪䯫䯬䯭䯮䯯䯰䯱䯲䯳䯴䯵䯶䯷䯸䯹䯺䯻䯼䯽䯾䯿䰀䰁䰂䰃䰄䰅䰆䰇䰈䰉䰊䰋䰌䰍䰎䰏䰐䰑䰒䰓䰔䰕䰖䰗䰘䰙䰚䰛䰜䰝䰞䰟䰠䰡䰢䰣䰤䰥䰦䰧䰨䰩䰪䰫䰬䰭䰮䰯䰰䰱䰲䰳䰴䰵䰶䰷䰸䰹䰺䰻䰼䰽䰾䰿䱀䱁䱂䱃䱄䱅䱆䱇䱈䱉䱊䱋䱌䱍䱎䱏䱐䱑䱒䱓䱔䱕䱖䱗䱘䱙䱚䱛䱜䱝䱞䱟䱠䱡䱢䱣䱤䱥䱦䱧䱨䱩䱪䱫䱬䱭䱮䱯䱰䱱䱲䱳䱴䱵䱶䱷䱸䱹䱺䱻䱼䱽䱾䱿䲀䲁䲂䲃䲄䲅䲆䲇䲈䲉䲊䲋䲌䲍䲎䲏䲐䲑䲒䲓䲔䲕䲖䲗䲘䲙䲚䲛䲜䲝䲞䲟䲠䲡䲢䲣䲤䲥䲦䲧䲨䲩䲪䲫䲬䲭䲮䲯䲰䲱䲲䲳䲴䲵䲶䲷䲸䲹䲺䲻䲼䲽䲾䲿䳀䳁䳂䳃䳄䳅䳆䳇䳈䳉䳊䳋䳌䳍䳎䳏䳐䳑䳒䳓䳔䳕䳖䳗䳘䳙䳚䳛䳜䳝䳞䳟䳠䳡䳢䳣䳤䳥䳦䳧䳨䳩䳪䳫䳬䳭䳮䳯䳰䳱䳲䳳䳴䳵䳶䳷䳸䳹䳺䳻䳼䳽䳾䳿䴀䴁䴂䴃䴄䴅䴆䴇䴈䴉䴊䴋䴌䴍䴎䴏䴐䴑䴒䴓䴔䴕䴖䴗䴘䴙䴚䴛䴜䴝䴞䴟䴠䴡䴢䴣䴤䴥䴦䴧䴨䴩䴪䴫䴬䴭䴮䴯䴰䴱䴲䴳䴴䴵䴶䴷䴸䴹䴺䴻䴼䴽䴾䴿䵀䵁䵂䵃䵄䵅䵆䵇䵈䵉䵊䵋䵌䵍䵎䵏䵐䵑䵒䵓䵔䵕䵖䵗䵘䵙䵚䵛䵜䵝䵞䵟䵠䵡䵢䵣䵤䵥䵦䵧䵨䵩䵪䵫䵬䵭䵮䵯䵰䵱䵲䵳䵴䵵䵶䵷䵸䵹䵺䵻䵼䵽䵾䵿䶀䶁䶂䶃䶄䶅䶆䶇䶈䶉䶊䶋䶌䶍䶎䶏䶐䶑䶒䶓䶔䶕䶖䶗䶘䶙䶚䶛䶜䶝䶞䶟䶠䶡䶢䶣䶤䶥䶦䶧䶨䶩䶪䶫䶬䶭䶮䶯䶰䶱䶲䶳䶴䶵䷀䷁䷂䷃䷄䷅䷆䷇䷈䷉䷊䷋䷌䷍䷎䷏䷐䷑䷒䷓䷔䷕䷖䷗䷘䷙䷚䷛䷜䷝䷞䷟䷠䷡䷢䷣䷤䷥䷦䷧䷨䷩䷪䷫䷬䷭䷮䷯䷰䷱䷲䷳䷴䷵䷶䷷䷸䷹䷺䷻䷼䷽䷾䷿一丁丂七丄丅丆万丈三上下丌不与丏丐丑丒专且丕世丗丘丙业丛东丝丞丟丠両丢丣两严並丧丨丩个丫丬中丮丯丰丱串丳临丵丶丷丸丹为主丼丽举丿乀乁乂乃乄久乆乇么义乊之乌乍乎乏乐乑乒乓乔乕乖乗乘乙乚乛乜九乞也习乡乢乣乤乥书乧乨乩乪乫乬乭乮乯买乱乲乳乴乵乶乷乸乹乺乻乼乽乾乿亀亁亂亃亄亅了亇予争亊事二亍于亏亐云互亓五井亖亗亘亙亚些亜亝亞亟亠亡亢亣交亥亦产亨亩亪享京亭亮亯亰亱亲亳亴亵亶亷亸亹人亻亼亽亾亿什仁仂仃仄仅仆仇仈仉今介仌仍从仏仐仑仒仓仔仕他仗付仙仚仛仜仝仞仟仠仡仢代令以仦仧仨仩仪仫们仭仮仯仰仱仲仳仴仵件价仸仹仺任仼份仾仿伀企伂伃伄伅伆伇伈伉伊伋伌伍伎伏伐休伒伓伔伕伖众优伙会伛伜伝伞伟传伡伢伣伤伥伦伧伨伩伪伫伬伭伮伯估伱伲伳伴伵伶伷伸伹伺伻似伽伾伿佀佁佂佃佄佅但佇佈佉佊佋佌位低住佐佑佒体佔何佖佗佘余佚佛作佝佞佟你佡佢佣佤佥佦佧佨佩佪佫佬佭佮佯佰佱佲佳佴併佶佷佸佹佺佻佼佽佾使侀侁侂侃侄侅來侇侈侉侊例侌侍侎侏侐侑侒侓侔侕侖侗侘侙侚供侜依侞侟侠価侢侣侤侥侦侧侨侩侪侫侬侭侮侯侰侱侲侳侴侵侶侷侸侹侺侻侼侽侾便俀俁係促俄俅俆俇俈俉俊俋俌俍俎俏俐俑俒俓俔俕俖俗俘俙俚俛俜保俞俟俠信俢俣俤俥俦俧俨俩俪俫俬俭修俯俰俱俲俳俴俵俶俷俸俹俺俻俼俽俾俿倀倁倂倃倄倅倆倇倈倉倊個倌倍倎倏倐們倒倓倔倕倖倗倘候倚倛倜倝倞借倠倡倢倣値倥倦倧倨倩倪倫倬倭倮倯倰倱倲倳倴倵倶倷倸倹债倻值倽倾倿偀偁偂偃偄偅偆假偈偉偊偋偌偍偎偏偐偑偒偓偔偕偖偗偘偙做偛停偝偞偟偠偡偢偣偤健偦偧偨偩偪偫偬偭偮偯偰偱偲偳側偵偶偷偸偹偺偻偼偽偾偿傀傁傂傃傄傅傆傇傈傉傊傋傌傍傎傏傐傑傒傓傔傕傖傗傘備傚傛傜傝傞傟傠傡傢傣傤傥傦傧储傩傪傫催傭傮傯傰傱傲傳傴債傶傷傸傹傺傻傼傽傾傿僀僁僂僃僄僅僆僇僈僉僊僋僌働僎像僐僑僒僓僔僕僖僗僘僙僚僛僜僝僞僟僠僡僢僣僤僥僦僧僨僩僪僫僬僭僮僯僰僱僲僳僴僵僶僷僸價僺僻僼僽僾僿儀儁儂儃億儅儆儇儈儉儊儋儌儍儎儏儐儑儒儓儔儕儖儗儘儙儚儛儜儝儞償儠儡儢儣儤儥儦儧儨儩優儫儬儭儮儯儰儱儲儳儴儵儶儷儸儹儺儻儼儽儾儿兀允兂元兄充兆兇先光兊克兌免兎兏児兑兒兓兔兕兖兗兘兙党兛兜兝兞兟兠兡兢兣兤入兦內全兩兪八公六兮兯兰共兲关兴兵其具典兹兺养兼兽兾兿冀冁冂冃冄内円冇冈冉冊冋册再冎冏冐冑冒冓冔冕冖冗冘写冚军农冝冞冟冠冡冢冣冤冥冦冧冨冩冪冫冬冭冮冯冰冱冲决冴况冶冷冸冹冺冻冼冽冾冿净凁凂凃凄凅准凇凈凉凊凋凌凍凎减凐凑凒凓凔凕凖凗凘凙凚凛凜凝凞凟几凡凢凣凤凥処凧凨凩凪凫凬凭凮凯凰凱凲凳凴凵凶凷凸凹出击凼函凾凿刀刁刂刃刄刅分切刈刉刊刋刌刍刎刏刐刑划刓刔刕刖列刘则刚创刜初刞刟删刡刢刣判別刦刧刨利刪别刬刭刮刯到刱刲刳刴刵制刷券刹刺刻刼刽刾刿剀剁剂剃剄剅剆則剈剉削剋剌前剎剏剐剑剒剓剔剕剖剗剘剙剚剛剜剝剞剟剠剡剢剣剤剥剦剧剨剩剪剫剬剭剮副剰剱割剳剴創剶剷剸剹剺剻剼剽剾剿劀劁劂劃劄劅劆劇劈劉劊劋劌劍劎劏劐劑劒劓劔劕劖劗劘劙劚力劜劝办功加务劢劣劤劥劦劧动助努劫劬劭劮劯劰励劲劳労劵劶劷劸効劺劻劼劽劾势勀勁勂勃勄勅勆勇勈勉勊勋勌勍勎勏勐勑勒勓勔動勖勗勘務勚勛勜勝勞募勠勡勢勣勤勥勦勧勨勩勪勫勬勭勮勯勰勱勲勳勴勵勶勷勸勹勺勻勼勽勾勿匀匁匂匃匄包匆匇匈匉匊匋匌匍匎匏匐匑匒匓匔匕化北匘匙匚匛匜匝匞匟匠匡匢匣匤匥匦匧匨匩匪匫匬匭匮匯匰匱匲匳匴匵匶匷匸匹区医匼匽匾匿區十卂千卄卅卆升午卉半卋卌卍华协卐卑卒卓協单卖南単卙博卛卜卝卞卟占卡卢卣卤卥卦卧卨卩卪卫卬卭卮卯印危卲即却卵卶卷卸卹卺卻卼卽卾卿厀厁厂厃厄厅历厇厈厉厊压厌厍厎厏厐厑厒厓厔厕厖厗厘厙厚厛厜厝厞原厠厡厢厣厤厥厦厧厨厩厪厫厬厭厮厯厰厱厲厳厴厵厶厷厸厹厺去厼厽厾县叀叁参參叄叅叆叇又叉及友双反収叏叐发叒叓叔叕取受变叙叚叛叜叝叞叟叠叡叢口古句另叧叨叩只叫召叭叮可台叱史右叴叵叶号司叹叺叻叼叽叾叿吀吁吂吃各吅吆吇合吉吊吋同名后吏吐向吒吓吔吕吖吗吘吙吚君吜吝吞吟吠吡吢吣吤吥否吧吨吩吪含听吭吮启吰吱吲吳吴吵吶吷吸吹吺吻吼吽吾吿呀呁呂呃呄呅呆呇呈呉告呋呌呍呎呏呐呑呒呓呔呕呖呗员呙呚呛呜呝呞呟呠呡呢呣呤呥呦呧周呩呪呫呬呭呮呯呰呱呲味呴呵呶呷呸呹呺呻呼命呾呿咀咁咂咃咄咅咆咇咈咉咊咋和咍咎咏咐咑咒咓咔咕咖咗咘咙咚咛咜咝咞咟咠咡咢咣咤咥咦咧咨咩咪咫咬咭咮咯咰咱咲咳咴咵咶咷咸咹咺咻咼咽咾咿哀品哂哃哄哅哆哇哈哉哊哋哌响哎哏哐哑哒哓哔哕哖哗哘哙哚哛哜哝哞哟哠員哢哣哤哥哦哧哨哩哪哫哬哭哮哯哰哱哲哳哴哵哶哷哸哹哺哻哼哽哾哿唀唁唂唃唄唅唆唇唈唉唊唋唌唍唎唏唐唑唒唓唔唕唖唗唘唙唚唛唜唝唞唟唠唡唢唣唤唥唦唧唨唩唪唫唬唭售唯唰唱唲唳唴唵唶唷唸唹唺唻唼唽唾唿啀啁啂啃啄啅商啇啈啉啊啋啌啍啎問啐啑啒啓啔啕啖啗啘啙啚啛啜啝啞啟啠啡啢啣啤啥啦啧啨啩啪啫啬啭啮啯啰啱啲啳啴啵啶啷啸啹啺啻啼啽啾啿喀喁喂喃善喅喆喇喈喉喊喋喌喍喎喏喐喑喒喓喔喕喖喗喘喙喚喛喜喝喞喟喠喡喢喣喤喥喦喧喨喩喪喫喬喭單喯喰喱喲喳喴喵営喷喸喹喺喻喼喽喾喿嗀嗁嗂嗃嗄嗅嗆嗇嗈嗉嗊嗋嗌嗍嗎嗏嗐嗑嗒嗓嗔嗕嗖嗗嗘嗙嗚嗛嗜嗝嗞嗟嗠嗡嗢嗣嗤嗥嗦嗧嗨嗩嗪嗫嗬嗭嗮嗯嗰嗱嗲嗳嗴嗵嗶嗷嗸嗹嗺嗻嗼嗽嗾嗿嘀嘁嘂嘃嘄嘅嘆嘇嘈嘉嘊嘋嘌嘍嘎嘏嘐嘑嘒嘓嘔嘕嘖嘗嘘嘙嘚嘛嘜嘝嘞嘟嘠嘡嘢嘣嘤嘥嘦嘧嘨嘩嘪嘫嘬嘭嘮嘯嘰嘱嘲嘳嘴嘵嘶嘷嘸嘹嘺嘻嘼嘽嘾嘿噀噁噂噃噄噅噆噇噈噉噊噋噌噍噎噏噐噑噒噓噔噕噖噗噘噙噚噛噜噝噞噟噠噡噢噣噤噥噦噧器噩噪噫噬噭噮噯噰噱噲噳噴噵噶噷噸噹噺噻噼噽噾噿嚀嚁嚂嚃嚄嚅嚆嚇嚈嚉嚊嚋嚌嚍嚎嚏嚐嚑嚒嚓嚔嚕嚖嚗嚘嚙嚚嚛嚜嚝嚞嚟嚠嚡嚢嚣嚤嚥嚦嚧嚨嚩嚪嚫嚬嚭嚮嚯嚰嚱嚲嚳嚴嚵嚶嚷嚸嚹嚺嚻嚼嚽嚾嚿囀囁囂囃囄囅囆囇囈囉囊囋囌囍囎囏囐囑囒囓囔囕囖囗囘囙囚四囜囝回囟因囡团団囤囥囦囧囨囩囪囫囬园囮囯困囱囲図围囵囶囷囸囹固囻囼国图囿圀圁圂圃圄圅圆圇圈圉圊國圌圍圎圏圐圑園圓圔圕圖圗團圙圚圛圜圝圞土圠圡圢圣圤圥圦圧在圩圪圫圬圭圮圯地圱圲圳圴圵圶圷圸圹场圻圼圽圾圿址坁坂坃坄坅坆均坈坉坊坋坌坍坎坏坐坑坒坓坔坕坖块坘坙坚坛坜坝坞坟坠坡坢坣坤坥坦坧坨坩坪坫坬坭坮坯坰坱坲坳坴坵坶坷坸坹坺坻坼坽坾坿垀垁垂垃垄垅垆垇垈垉垊型垌垍垎垏垐垑垒垓垔垕垖垗垘垙垚垛垜垝垞垟垠垡垢垣垤垥垦垧垨垩垪垫垬垭垮垯垰垱垲垳垴垵垶垷垸垹垺垻垼垽垾垿埀埁埂埃埄埅埆埇埈埉埊埋埌埍城埏埐埑埒埓埔埕埖埗埘埙埚埛埜埝埞域埠埡埢埣埤埥埦埧埨埩埪埫埬埭埮埯埰埱埲埳埴埵埶執埸培基埻埼埽埾埿堀堁堂堃堄堅堆堇堈堉堊堋堌堍堎堏堐堑堒堓堔堕堖堗堘堙堚堛堜堝堞堟堠堡堢堣堤堥堦堧堨堩堪堫堬堭堮堯堰報堲堳場堵堶堷堸堹堺堻堼堽堾堿塀塁塂塃塄塅塆塇塈塉塊塋塌塍塎塏塐塑塒塓塔塕塖塗塘塙塚塛塜塝塞塟塠塡塢塣塤塥塦塧塨塩塪填塬塭塮塯塰塱塲塳塴塵塶塷塸塹塺塻塼塽塾塿墀墁墂境墄墅墆墇墈墉墊墋墌墍墎墏墐墑墒墓墔墕墖増墘墙墚墛墜墝增墟墠墡墢墣墤墥墦墧墨墩墪墫墬墭墮墯墰墱墲墳墴墵墶墷墸墹墺墻墼墽墾墿壀壁壂壃壄壅壆壇壈壉壊壋壌壍壎壏壐壑壒壓壔壕壖壗壘壙壚壛壜壝壞壟壠壡壢壣壤壥壦壧壨壩壪士壬壭壮壯声壱売壳壴壵壶壷壸壹壺壻壼壽壾壿夀夁夂夃处夅夆备夈変夊夋夌复夎夏夐夑夒夓夔夕外夗夘夙多夛夜夝夞够夠夡夢夣夤夥夦大夨天太夫夬夭央夯夰失夲夳头夵夶夷夸夹夺夻夼夽夾夿奀奁奂奃奄奅奆奇奈奉奊奋奌奍奎奏奐契奒奓奔奕奖套奘奙奚奛奜奝奞奟奠奡奢奣奤奥奦奧奨奩奪奫奬奭奮奯奰奱奲女奴奵奶奷奸她奺奻奼好奾奿妀妁如妃妄妅妆妇妈妉妊妋妌妍妎妏妐妑妒妓妔妕妖妗妘妙妚妛妜妝妞妟妠妡妢妣妤妥妦妧妨妩妪妫妬妭妮妯妰妱妲妳妴妵妶妷妸妹妺妻妼妽妾妿姀姁姂姃姄姅姆姇姈姉姊始姌姍姎姏姐姑姒姓委姕姖姗姘姙姚姛姜姝姞姟姠姡姢姣姤姥姦姧姨姩姪姫姬姭姮姯姰姱姲姳姴姵姶姷姸姹姺姻姼姽姾姿娀威娂娃娄娅娆娇娈娉娊娋娌娍娎娏娐娑娒娓娔娕娖娗娘娙娚娛娜娝娞娟娠娡娢娣娤娥娦娧娨娩娪娫娬娭娮娯娰娱娲娳娴娵娶娷娸娹娺娻娼娽娾娿婀婁婂婃婄婅婆婇婈婉婊婋婌婍婎婏婐婑婒婓婔婕婖婗婘婙婚婛婜婝婞婟婠婡婢婣婤婥婦婧婨婩婪婫婬婭婮婯婰婱婲婳婴婵婶婷婸婹婺婻婼婽婾婿媀媁媂媃媄媅媆媇媈媉媊媋媌媍媎媏媐媑媒媓媔媕媖媗媘媙媚媛媜媝媞媟媠媡媢媣媤媥媦媧媨媩媪媫媬媭媮媯媰媱媲媳媴媵媶媷媸媹媺媻媼媽媾媿嫀嫁嫂嫃嫄嫅嫆嫇嫈嫉嫊嫋嫌嫍嫎嫏嫐嫑嫒嫓嫔嫕嫖嫗嫘嫙嫚嫛嫜嫝嫞嫟嫠嫡嫢嫣嫤嫥嫦嫧嫨嫩嫪嫫嫬嫭嫮嫯嫰嫱嫲嫳嫴嫵嫶嫷嫸嫹嫺嫻嫼嫽嫾嫿嬀嬁嬂嬃嬄嬅嬆嬇嬈嬉嬊嬋嬌嬍嬎嬏嬐嬑嬒嬓嬔嬕嬖嬗嬘嬙嬚嬛嬜嬝嬞嬟嬠嬡嬢嬣嬤嬥嬦嬧嬨嬩嬪嬫嬬嬭嬮嬯嬰嬱嬲嬳嬴嬵嬶嬷嬸嬹嬺嬻嬼嬽嬾嬿孀孁孂孃孄孅孆孇孈孉孊孋孌孍孎孏子孑孒孓孔孕孖字存孙孚孛孜孝孞孟孠孡孢季孤孥学孧孨孩孪孫孬孭孮孯孰孱孲孳孴孵孶孷學孹孺孻孼孽孾孿宀宁宂它宄宅宆宇守安宊宋完宍宎宏宐宑宒宓宔宕宖宗官宙定宛宜宝实実宠审客宣室宥宦宧宨宩宪宫宬宭宮宯宰宱宲害宴宵家宷宸容宺宻宼宽宾宿寀寁寂寃寄寅密寇寈寉寊寋富寍寎寏寐寑寒寓寔寕寖寗寘寙寚寛寜寝寞察寠寡寢寣寤寥實寧寨審寪寫寬寭寮寯寰寱寲寳寴寵寶寷寸对寺寻导寽対寿尀封専尃射尅将將專尉尊尋尌對導小尐少尒尓尔尕尖尗尘尙尚尛尜尝尞尟尠尡尢尣尤尥尦尧尨尩尪尫尬尭尮尯尰就尲尳尴尵尶尷尸尹尺尻尼尽尾尿局屁层屃屄居屆屇屈屉届屋屌屍屎屏屐屑屒屓屔展屖屗屘屙屚屛屜屝属屟屠屡屢屣層履屦屧屨屩屪屫屬屭屮屯屰山屲屳屴屵屶屷屸屹屺屻屼屽屾屿岀岁岂岃岄岅岆岇岈岉岊岋岌岍岎岏岐岑岒岓岔岕岖岗岘岙岚岛岜岝岞岟岠岡岢岣岤岥岦岧岨岩岪岫岬岭岮岯岰岱岲岳岴岵岶岷岸岹岺岻岼岽岾岿峀峁峂峃峄峅峆峇峈峉峊峋峌峍峎峏峐峑峒峓峔峕峖峗峘峙峚峛峜峝峞峟峠峡峢峣峤峥峦峧峨峩峪峫峬峭峮峯峰峱峲峳峴峵島峷峸峹峺峻峼峽峾峿崀崁崂崃崄崅崆崇崈崉崊崋崌崍崎崏崐崑崒崓崔崕崖崗崘崙崚崛崜崝崞崟崠崡崢崣崤崥崦崧崨崩崪崫崬崭崮崯崰崱崲崳崴崵崶崷崸崹崺崻崼崽崾崿嵀嵁嵂嵃嵄嵅嵆嵇嵈嵉嵊嵋嵌嵍嵎嵏嵐嵑嵒嵓嵔嵕嵖嵗嵘嵙嵚嵛嵜嵝嵞嵟嵠嵡嵢嵣嵤嵥嵦嵧嵨嵩嵪嵫嵬嵭嵮嵯嵰嵱嵲嵳嵴嵵嵶嵷嵸嵹嵺嵻嵼嵽嵾嵿嶀嶁嶂嶃嶄嶅嶆嶇嶈嶉嶊嶋嶌嶍嶎嶏嶐嶑嶒嶓嶔嶕嶖嶗嶘嶙嶚嶛嶜嶝嶞嶟嶠嶡嶢嶣嶤嶥嶦嶧嶨嶩嶪嶫嶬嶭嶮嶯嶰嶱嶲嶳嶴嶵嶶嶷嶸嶹嶺嶻嶼嶽嶾嶿巀巁巂巃巄巅巆巇巈巉巊巋巌巍巎巏巐巑巒巓巔巕巖巗巘巙巚巛巜川州巟巠巡巢巣巤工左巧巨巩巪巫巬巭差巯巰己已巳巴巵巶巷巸巹巺巻巼巽巾巿帀币市布帄帅帆帇师帉帊帋希帍帎帏帐帑帒帓帔帕帖帗帘帙帚帛帜帝帞帟帠帡帢帣帤帥带帧帨帩帪師帬席帮帯帰帱帲帳帴帵帶帷常帹帺帻帼帽帾帿幀幁幂幃幄幅幆幇幈幉幊幋幌幍幎幏幐幑幒幓幔幕幖幗幘幙幚幛幜幝幞幟幠幡幢幣幤幥幦幧幨幩幪幫幬幭幮幯幰幱干平年幵并幷幸幹幺幻幼幽幾广庀庁庂広庄庅庆庇庈庉床庋庌庍庎序庐庑庒库应底庖店庘庙庚庛府庝庞废庠庡庢庣庤庥度座庨庩庪庫庬庭庮庯庰庱庲庳庴庵庶康庸庹庺庻庼庽庾庿廀廁廂廃廄廅廆廇廈廉廊廋廌廍廎廏廐廑廒廓廔廕廖廗廘廙廚廛廜廝廞廟廠廡廢廣廤廥廦廧廨廩廪廫廬廭廮廯廰廱廲廳廴廵延廷廸廹建廻廼廽廾廿开弁异弃弄弅弆弇弈弉弊弋弌弍弎式弐弑弒弓弔引弖弗弘弙弚弛弜弝弞弟张弡弢弣弤弥弦弧弨弩弪弫弬弭弮弯弰弱弲弳弴張弶強弸弹强弻弼弽弾弿彀彁彂彃彄彅彆彇彈彉彊彋彌彍彎彏彐彑归当彔录彖彗彘彙彚彛彜彝彞彟彠彡形彣彤彥彦彧彨彩彪彫彬彭彮彯彰影彲彳彴彵彶彷彸役彺彻彼彽彾彿往征徂徃径待徆徇很徉徊律後徍徎徏徐徑徒従徔徕徖得徘徙徚徛徜徝從徟徠御徢徣徤徥徦徧徨復循徫徬徭微徯徰徱徲徳徴徵徶德徸徹徺徻徼徽徾徿忀忁忂心忄必忆忇忈忉忊忋忌忍忎忏忐忑忒忓忔忕忖志忘忙忚忛応忝忞忟忠忡忢忣忤忥忦忧忨忩忪快忬忭忮忯忰忱忲忳忴念忶忷忸忹忺忻忼忽忾忿怀态怂怃怄怅怆怇怈怉怊怋怌怍怎怏怐怑怒怓怔怕怖怗怘怙怚怛怜思怞怟怠怡怢怣怤急怦性怨怩怪怫怬怭怮怯怰怱怲怳怴怵怶怷怸怹怺总怼怽怾怿恀恁恂恃恄恅恆恇恈恉恊恋恌恍恎恏恐恑恒恓恔恕恖恗恘恙恚恛恜恝恞恟恠恡恢恣恤恥恦恧恨恩恪恫恬恭恮息恰恱恲恳恴恵恶恷恸恹恺恻恼恽恾恿悀悁悂悃悄悅悆悇悈悉悊悋悌悍悎悏悐悑悒悓悔悕悖悗悘悙悚悛悜悝悞悟悠悡悢患悤悥悦悧您悩悪悫悬悭悮悯悰悱悲悳悴悵悶悷悸悹悺悻悼悽悾悿惀惁惂惃惄情惆惇惈惉惊惋惌惍惎惏惐惑惒惓惔惕惖惗惘惙惚惛惜惝惞惟惠惡惢惣惤惥惦惧惨惩惪惫惬惭惮惯惰惱惲想惴惵惶惷惸惹惺惻惼惽惾惿愀愁愂愃愄愅愆愇愈愉愊愋愌愍愎意愐愑愒愓愔愕愖愗愘愙愚愛愜愝愞感愠愡愢愣愤愥愦愧愨愩愪愫愬愭愮愯愰愱愲愳愴愵愶愷愸愹愺愻愼愽愾愿慀慁慂慃慄慅慆慇慈慉慊態慌慍慎慏慐慑慒慓慔慕慖慗慘慙慚慛慜慝慞慟慠慡慢慣慤慥慦慧慨慩慪慫慬慭慮慯慰慱慲慳慴慵慶慷慸慹慺慻慼慽慾慿憀憁憂憃憄憅憆憇憈憉憊憋憌憍憎憏憐憑憒憓憔憕憖憗憘憙憚憛憜憝憞憟憠憡憢憣憤憥憦憧憨憩憪憫憬憭憮憯憰憱憲憳憴憵憶憷憸憹憺憻憼憽憾憿懀懁懂懃懄懅懆懇懈應懊懋懌懍懎懏懐懑懒懓懔懕懖懗懘懙懚懛懜懝懞懟懠懡懢懣懤懥懦懧懨懩懪懫懬懭懮懯懰懱懲懳懴懵懶懷懸懹懺懻懼懽懾懿戀戁戂戃戄戅戆戇戈戉戊戋戌戍戎戏成我戒戓戔戕或戗战戙戚戛戜戝戞戟戠戡戢戣戤戥戦戧戨戩截戫戬戭戮戯戰戱戲戳戴戵戶户戸戹戺戻戼戽戾房所扁扂扃扄扅扆扇扈扉扊手扌才扎扏扐扑扒打扔払扖扗托扙扚扛扜扝扞扟扠扡扢扣扤扥扦执扨扩扪扫扬扭扮扯扰扱扲扳扴扵扶扷扸批扺扻扼扽找承技抁抂抃抄抅抆抇抈抉把抋抌抍抎抏抐抑抒抓抔投抖抗折抙抚抛抜抝択抟抠抡抢抣护报抦抧抨抩抪披抬抭抮抯抰抱抲抳抴抵抶抷抸抹抺抻押抽抾抿拀拁拂拃拄担拆拇拈拉拊拋拌拍拎拏拐拑拒拓拔拕拖拗拘拙拚招拜拝拞拟拠拡拢拣拤拥拦拧拨择拪拫括拭拮拯拰拱拲拳拴拵拶拷拸拹拺拻拼拽拾拿挀持挂挃挄挅挆指挈按挊挋挌挍挎挏挐挑挒挓挔挕挖挗挘挙挚挛挜挝挞挟挠挡挢挣挤挥挦挧挨挩挪挫挬挭挮振挰挱挲挳挴挵挶挷挸挹挺挻挼挽挾挿捀捁捂捃捄捅捆捇捈捉捊捋捌捍捎捏捐捑捒捓捔捕捖捗捘捙捚捛捜捝捞损捠捡换捣捤捥捦捧捨捩捪捫捬捭据捯捰捱捲捳捴捵捶捷捸捹捺捻捼捽捾捿掀掁掂掃掄掅掆掇授掉掊掋掌掍掎掏掐掑排掓掔掕掖掗掘掙掚掛掜掝掞掟掠採探掣掤接掦控推掩措掫掬掭掮掯掰掱掲掳掴掵掶掷掸掹掺掻掼掽掾掿揀揁揂揃揄揅揆揇揈揉揊揋揌揍揎描提揑插揓揔揕揖揗揘揙揚換揜揝揞揟揠握揢揣揤揥揦揧揨揩揪揫揬揭揮揯揰揱揲揳援揵揶揷揸揹揺揻揼揽揾揿搀搁搂搃搄搅搆搇搈搉搊搋搌損搎搏搐搑搒搓搔搕搖搗搘搙搚搛搜搝搞搟搠搡搢搣搤搥搦搧搨搩搪搫搬搭搮搯搰搱搲搳搴搵搶搷搸搹携搻搼搽搾搿摀摁摂摃摄摅摆摇摈摉摊摋摌摍摎摏摐摑摒摓摔摕摖摗摘摙摚摛摜摝摞摟摠摡摢摣摤摥摦摧摨摩摪摫摬摭摮摯摰摱摲摳摴摵摶摷摸摹摺摻摼摽摾摿撀撁撂撃撄撅撆撇撈撉撊撋撌撍撎撏撐撑撒撓撔撕撖撗撘撙撚撛撜撝撞撟撠撡撢撣撤撥撦撧撨撩撪撫撬播撮撯撰撱撲撳撴撵撶撷撸撹撺撻撼撽撾撿擀擁擂擃擄擅擆擇擈擉擊擋擌操擎擏擐擑擒擓擔擕擖擗擘擙據擛擜擝擞擟擠擡擢擣擤擥擦擧擨擩擪擫擬擭擮擯擰擱擲擳擴擵擶擷擸擹擺擻擼擽擾擿攀攁攂攃攄攅攆攇攈攉攊攋攌攍攎攏攐攑攒攓攔攕攖攗攘攙攚攛攜攝攞攟攠攡攢攣攤攥攦攧攨攩攪攫攬攭攮支攰攱攲攳攴攵收攷攸改攺攻攼攽放政敀敁敂敃敄故敆敇效敉敊敋敌敍敎敏敐救敒敓敔敕敖敗敘教敚敛敜敝敞敟敠敡敢散敤敥敦敧敨敩敪敫敬敭敮敯数敱敲敳整敵敶敷數敹敺敻敼敽敾敿斀斁斂斃斄斅斆文斈斉斊斋斌斍斎斏斐斑斒斓斔斕斖斗斘料斚斛斜斝斞斟斠斡斢斣斤斥斦斧斨斩斪斫斬断斮斯新斱斲斳斴斵斶斷斸方斺斻於施斾斿旀旁旂旃旄旅旆旇旈旉旊旋旌旍旎族旐旑旒旓旔旕旖旗旘旙旚旛旜旝旞旟无旡既旣旤日旦旧旨早旪旫旬旭旮旯旰旱旲旳旴旵时旷旸旹旺旻旼旽旾旿昀昁昂昃昄昅昆昇昈昉昊昋昌昍明昏昐昑昒易昔昕昖昗昘昙昚昛昜昝昞星映昡昢昣昤春昦昧昨昩昪昫昬昭昮是昰昱昲昳昴昵昶昷昸昹昺昻昼昽显昿晀晁時晃晄晅晆晇晈晉晊晋晌晍晎晏晐晑晒晓晔晕晖晗晘晙晚晛晜晝晞晟晠晡晢晣晤晥晦晧晨晩晪晫晬晭普景晰晱晲晳晴晵晶晷晸晹智晻晼晽晾晿暀暁暂暃暄暅暆暇暈暉暊暋暌暍暎暏暐暑暒暓暔暕暖暗暘暙暚暛暜暝暞暟暠暡暢暣暤暥暦暧暨暩暪暫暬暭暮暯暰暱暲暳暴暵暶暷暸暹暺暻暼暽暾暿曀曁曂曃曄曅曆曇曈曉曊曋曌曍曎曏曐曑曒曓曔曕曖曗曘曙曚曛曜曝曞曟曠曡曢曣曤曥曦曧曨曩曪曫曬曭曮曯曰曱曲曳更曵曶曷書曹曺曻曼曽曾替最朁朂會朄朅朆朇月有朊朋朌服朎朏朐朑朒朓朔朕朖朗朘朙朚望朜朝朞期朠朡朢朣朤朥朦朧木朩未末本札朮术朰朱朲朳朴朵朶朷朸朹机朻朼朽朾朿杀杁杂权杄杅杆杇杈杉杊杋杌杍李杏材村杒杓杔杕杖杗杘杙杚杛杜杝杞束杠条杢杣杤来杦杧杨杩杪杫杬杭杮杯杰東杲杳杴杵杶杷杸杹杺杻杼杽松板枀极枂枃构枅枆枇枈枉枊枋枌枍枎枏析枑枒枓枔枕枖林枘枙枚枛果枝枞枟枠枡枢枣枤枥枦枧枨枩枪枫枬枭枮枯枰枱枲枳枴枵架枷枸枹枺枻枼枽枾枿柀柁柂柃柄柅柆柇柈柉柊柋柌柍柎柏某柑柒染柔柕柖柗柘柙柚柛柜柝柞柟柠柡柢柣柤查柦柧柨柩柪柫柬柭柮柯柰柱柲柳柴柵柶柷柸柹柺査柼柽柾柿栀栁栂栃栄栅栆标栈栉栊栋栌栍栎栏栐树栒栓栔栕栖栗栘栙栚栛栜栝栞栟栠校栢栣栤栥栦栧栨栩株栫栬栭栮栯栰栱栲栳栴栵栶样核根栺栻格栽栾栿桀桁桂桃桄桅框桇案桉桊桋桌桍桎桏桐桑桒桓桔桕桖桗桘桙桚桛桜桝桞桟桠桡桢档桤桥桦桧桨桩桪桫桬桭桮桯桰桱桲桳桴桵桶桷桸桹桺桻桼桽桾桿梀梁梂梃梄梅梆梇梈梉梊梋梌梍梎梏梐梑梒梓梔梕梖梗梘梙梚梛梜條梞梟梠梡梢梣梤梥梦梧梨梩梪梫梬梭梮梯械梱梲梳梴梵梶梷梸梹梺梻梼梽梾梿检棁棂棃棄棅棆棇棈棉棊棋棌棍棎棏棐棑棒棓棔棕棖棗棘棙棚棛棜棝棞棟棠棡棢棣棤棥棦棧棨棩棪棫棬棭森棯棰棱棲棳棴棵棶棷棸棹棺棻棼棽棾棿椀椁椂椃椄椅椆椇椈椉椊椋椌植椎椏椐椑椒椓椔椕椖椗椘椙椚椛検椝椞椟椠椡椢椣椤椥椦椧椨椩椪椫椬椭椮椯椰椱椲椳椴椵椶椷椸椹椺椻椼椽椾椿楀楁楂楃楄楅楆楇楈楉楊楋楌楍楎楏楐楑楒楓楔楕楖楗楘楙楚楛楜楝楞楟楠楡楢楣楤楥楦楧楨楩楪楫楬業楮楯楰楱楲楳楴極楶楷楸楹楺楻楼楽楾楿榀榁概榃榄榅榆榇榈榉榊榋榌榍榎榏榐榑榒榓榔榕榖榗榘榙榚榛榜榝榞榟榠榡榢榣榤榥榦榧榨榩榪榫榬榭榮榯榰榱榲榳榴榵榶榷榸榹榺榻榼榽榾榿槀槁槂槃槄槅槆槇槈槉槊構槌槍槎槏槐槑槒槓槔槕槖槗様槙槚槛槜槝槞槟槠槡槢槣槤槥槦槧槨槩槪槫槬槭槮槯槰槱槲槳槴槵槶槷槸槹槺槻槼槽槾槿樀樁樂樃樄樅樆樇樈樉樊樋樌樍樎樏樐樑樒樓樔樕樖樗樘標樚樛樜樝樞樟樠模樢樣樤樥樦樧樨権横樫樬樭樮樯樰樱樲樳樴樵樶樷樸樹樺樻樼樽樾樿橀橁橂橃橄橅橆橇橈橉橊橋橌橍橎橏橐橑橒橓橔橕橖橗橘橙橚橛橜橝橞機橠橡橢橣橤橥橦橧橨橩橪橫橬橭橮橯橰橱橲橳橴橵橶橷橸橹橺橻橼橽橾橿檀檁檂檃檄檅檆檇檈檉檊檋檌檍檎檏檐檑檒檓檔檕檖檗檘檙檚檛檜檝檞檟檠檡檢檣檤檥檦檧檨檩檪檫檬檭檮檯檰檱檲檳檴檵檶檷檸檹檺檻檼檽檾檿櫀櫁櫂櫃櫄櫅櫆櫇櫈櫉櫊櫋櫌櫍櫎櫏櫐櫑櫒櫓櫔櫕櫖櫗櫘櫙櫚櫛櫜櫝櫞櫟櫠櫡櫢櫣櫤櫥櫦櫧櫨櫩櫪櫫櫬櫭櫮櫯櫰櫱櫲櫳櫴櫵櫶櫷櫸櫹櫺櫻櫼櫽櫾櫿欀欁欂欃欄欅欆欇欈欉權欋欌欍欎欏欐欑欒欓欔欕欖欗欘欙欚欛欜欝欞欟欠次欢欣欤欥欦欧欨欩欪欫欬欭欮欯欰欱欲欳欴欵欶欷欸欹欺欻欼欽款欿歀歁歂歃歄歅歆歇歈歉歊歋歌歍歎歏歐歑歒歓歔歕歖歗歘歙歚歛歜歝歞歟歠歡止正此步武歧歨歩歪歫歬歭歮歯歰歱歲歳歴歵歶歷歸歹歺死歼歽歾歿殀殁殂殃殄殅殆殇殈殉殊残殌殍殎殏殐殑殒殓殔殕殖殗殘殙殚殛殜殝殞殟殠殡殢殣殤殥殦殧殨殩殪殫殬殭殮殯殰殱殲殳殴段殶殷殸殹殺殻殼殽殾殿毀毁毂毃毄毅毆毇毈毉毊毋毌母毎每毐毑毒毓比毕毖毗毘毙毚毛毜毝毞毟毠毡毢毣毤毥毦毧毨毩毪毫毬毭毮毯毰毱毲毳毴毵毶毷毸毹毺毻毼毽毾毿氀氁氂氃氄氅氆氇氈氉氊氋氌氍氎氏氐民氒氓气氕氖気氘氙氚氛氜氝氞氟氠氡氢氣氤氥氦氧氨氩氪氫氬氭氮氯氰氱氲氳水氵氶氷永氹氺氻氼氽氾氿汀汁求汃汄汅汆汇汈汉汊汋汌汍汎汏汐汑汒汓汔汕汖汗汘汙汚汛汜汝汞江池污汢汣汤汥汦汧汨汩汪汫汬汭汮汯汰汱汲汳汴汵汶汷汸汹決汻汼汽汾汿沀沁沂沃沄沅沆沇沈沉沊沋沌沍沎沏沐沑沒沓沔沕沖沗沘沙沚沛沜沝沞沟沠没沢沣沤沥沦沧沨沩沪沫沬沭沮沯沰沱沲河沴沵沶沷沸油沺治沼沽沾沿泀況泂泃泄泅泆泇泈泉泊泋泌泍泎泏泐泑泒泓泔法泖泗泘泙泚泛泜泝泞泟泠泡波泣泤泥泦泧注泩泪泫泬泭泮泯泰泱泲泳泴泵泶泷泸泹泺泻泼泽泾泿洀洁洂洃洄洅洆洇洈洉洊洋洌洍洎洏洐洑洒洓洔洕洖洗洘洙洚洛洜洝洞洟洠洡洢洣洤津洦洧洨洩洪洫洬洭洮洯洰洱洲洳洴洵洶洷洸洹洺活洼洽派洿浀流浂浃浄浅浆浇浈浉浊测浌浍济浏浐浑浒浓浔浕浖浗浘浙浚浛浜浝浞浟浠浡浢浣浤浥浦浧浨浩浪浫浬浭浮浯浰浱浲浳浴浵浶海浸浹浺浻浼浽浾浿涀涁涂涃涄涅涆涇消涉涊涋涌涍涎涏涐涑涒涓涔涕涖涗涘涙涚涛涜涝涞涟涠涡涢涣涤涥润涧涨涩涪涫涬涭涮涯涰涱液涳涴涵涶涷涸涹涺涻涼涽涾涿淀淁淂淃淄淅淆淇淈淉淊淋淌淍淎淏淐淑淒淓淔淕淖淗淘淙淚淛淜淝淞淟淠淡淢淣淤淥淦淧淨淩淪淫淬淭淮淯淰深淲淳淴淵淶混淸淹淺添淼淽淾淿渀渁渂渃渄清渆渇済渉渊渋渌渍渎渏渐渑渒渓渔渕渖渗渘渙渚減渜渝渞渟渠渡渢渣渤渥渦渧渨温渪渫測渭渮港渰渱渲渳渴渵渶渷游渹渺渻渼渽渾渿湀湁湂湃湄湅湆湇湈湉湊湋湌湍湎湏湐湑湒湓湔湕湖湗湘湙湚湛湜湝湞湟湠湡湢湣湤湥湦湧湨湩湪湫湬湭湮湯湰湱湲湳湴湵湶湷湸湹湺湻湼湽湾湿満溁溂溃溄溅溆溇溈溉溊溋溌溍溎溏源溑溒溓溔溕準溗溘溙溚溛溜溝溞溟溠溡溢溣溤溥溦溧溨溩溪溫溬溭溮溯溰溱溲溳溴溵溶溷溸溹溺溻溼溽溾溿滀滁滂滃滄滅滆滇滈滉滊滋滌滍滎滏滐滑滒滓滔滕滖滗滘滙滚滛滜滝滞滟滠满滢滣滤滥滦滧滨滩滪滫滬滭滮滯滰滱滲滳滴滵滶滷滸滹滺滻滼滽滾滿漀漁漂漃漄漅漆漇漈漉漊漋漌漍漎漏漐漑漒漓演漕漖漗漘漙漚漛漜漝漞漟漠漡漢漣漤漥漦漧漨漩漪漫漬漭漮漯漰漱漲漳漴漵漶漷漸漹漺漻漼漽漾漿潀潁潂潃潄潅潆潇潈潉潊潋潌潍潎潏潐潑潒潓潔潕潖潗潘潙潚潛潜潝潞潟潠潡潢潣潤潥潦潧潨潩潪潫潬潭潮潯潰潱潲潳潴潵潶潷潸潹潺潻潼潽潾潿澀澁澂澃澄澅澆澇澈澉澊澋澌澍澎澏澐澑澒澓澔澕澖澗澘澙澚澛澜澝澞澟澠澡澢澣澤澥澦澧澨澩澪澫澬澭澮澯澰澱澲澳澴澵澶澷澸澹澺澻澼澽澾澿激濁濂濃濄濅濆濇濈濉濊濋濌濍濎濏濐濑濒濓濔濕濖濗濘濙濚濛濜濝濞濟濠濡濢濣濤濥濦濧濨濩濪濫濬濭濮濯濰濱濲濳濴濵濶濷濸濹濺濻濼濽濾濿瀀瀁瀂瀃瀄瀅瀆瀇瀈瀉瀊瀋瀌瀍瀎瀏瀐瀑瀒瀓瀔瀕瀖瀗瀘瀙瀚瀛瀜瀝瀞瀟瀠瀡瀢瀣瀤瀥瀦瀧瀨瀩瀪瀫瀬瀭瀮瀯瀰瀱瀲瀳瀴瀵瀶瀷瀸瀹瀺瀻瀼瀽瀾瀿灀灁灂灃灄灅灆灇灈灉灊灋灌灍灎灏灐灑灒灓灔灕灖灗灘灙灚灛灜灝灞灟灠灡灢灣灤灥灦灧灨灩灪火灬灭灮灯灰灱灲灳灴灵灶灷灸灹灺灻灼災灾灿炀炁炂炃炄炅炆炇炈炉炊炋炌炍炎炏炐炑炒炓炔炕炖炗炘炙炚炛炜炝炞炟炠炡炢炣炤炥炦炧炨炩炪炫炬炭炮炯炰炱炲炳炴炵炶炷炸点為炻炼炽炾炿烀烁烂烃烄烅烆烇烈烉烊烋烌烍烎烏烐烑烒烓烔烕烖烗烘烙烚烛烜烝烞烟烠烡烢烣烤烥烦烧烨烩烪烫烬热烮烯烰烱烲烳烴烵烶烷烸烹烺烻烼烽烾烿焀焁焂焃焄焅焆焇焈焉焊焋焌焍焎焏焐焑焒焓焔焕焖焗焘焙焚焛焜焝焞焟焠無焢焣焤焥焦焧焨焩焪焫焬焭焮焯焰焱焲焳焴焵然焷焸焹焺焻焼焽焾焿煀煁煂煃煄煅煆煇煈煉煊煋煌煍煎煏煐煑煒煓煔煕煖煗煘煙煚煛煜煝煞煟煠煡煢煣煤煥煦照煨煩煪煫煬煭煮煯煰煱煲煳煴煵煶煷煸煹煺煻煼煽煾煿熀熁熂熃熄熅熆熇熈熉熊熋熌熍熎熏熐熑熒熓熔熕熖熗熘熙熚熛熜熝熞熟熠熡熢熣熤熥熦熧熨熩熪熫熬熭熮熯熰熱熲熳熴熵熶熷熸熹熺熻熼熽熾熿燀燁燂燃燄燅燆燇燈燉燊燋燌燍燎燏燐燑燒燓燔燕燖燗燘燙燚燛燜燝燞營燠燡燢燣燤燥燦燧燨燩燪燫燬燭燮燯燰燱燲燳燴燵燶燷燸燹燺燻燼燽燾燿爀爁爂爃爄爅爆爇爈爉爊爋爌爍爎爏爐爑爒爓爔爕爖爗爘爙爚爛爜爝爞爟爠爡爢爣爤爥爦爧爨爩爪爫爬爭爮爯爰爱爲爳爴爵父爷爸爹爺爻爼爽爾爿牀牁牂牃牄牅牆片版牉牊牋牌牍牎牏牐牑牒牓牔牕牖牗牘牙牚牛牜牝牞牟牠牡牢牣牤牥牦牧牨物牪牫牬牭牮牯牰牱牲牳牴牵牶牷牸特牺牻牼牽牾牿犀犁犂犃犄犅犆犇犈犉犊犋犌犍犎犏犐犑犒犓犔犕犖犗犘犙犚犛犜犝犞犟犠犡犢犣犤犥犦犧犨犩犪犫犬犭犮犯犰犱犲犳犴犵状犷犸犹犺犻犼犽犾犿狀狁狂狃狄狅狆狇狈狉狊狋狌狍狎狏狐狑狒狓狔狕狖狗狘狙狚狛狜狝狞狟狠狡狢狣狤狥狦狧狨狩狪狫独狭狮狯狰狱狲狳狴狵狶狷狸狹狺狻狼狽狾狿猀猁猂猃猄猅猆猇猈猉猊猋猌猍猎猏猐猑猒猓猔猕猖猗猘猙猚猛猜猝猞猟猠猡猢猣猤猥猦猧猨猩猪猫猬猭献猯猰猱猲猳猴猵猶猷猸猹猺猻猼猽猾猿獀獁獂獃獄獅獆獇獈獉獊獋獌獍獎獏獐獑獒獓獔獕獖獗獘獙獚獛獜獝獞獟獠獡獢獣獤獥獦獧獨獩獪獫獬獭獮獯獰獱獲獳獴獵獶獷獸獹獺獻獼獽獾獿玀玁玂玃玄玅玆率玈玉玊王玌玍玎玏玐玑玒玓玔玕玖玗玘玙玚玛玜玝玞玟玠玡玢玣玤玥玦玧玨玩玪玫玬玭玮环现玱玲玳玴玵玶玷玸玹玺玻玼玽玾玿珀珁珂珃珄珅珆珇珈珉珊珋珌珍珎珏珐珑珒珓珔珕珖珗珘珙珚珛珜珝珞珟珠珡珢珣珤珥珦珧珨珩珪珫珬班珮珯珰珱珲珳珴珵珶珷珸珹珺珻珼珽現珿琀琁琂球琄琅理琇琈琉琊琋琌琍琎琏琐琑琒琓琔琕琖琗琘琙琚琛琜琝琞琟琠琡琢琣琤琥琦琧琨琩琪琫琬琭琮琯琰琱琲琳琴琵琶琷琸琹琺琻琼琽琾琿瑀瑁瑂瑃瑄瑅瑆瑇瑈瑉瑊瑋瑌瑍瑎瑏瑐瑑瑒瑓瑔瑕瑖瑗瑘瑙瑚瑛瑜瑝瑞瑟瑠瑡瑢瑣瑤瑥瑦瑧瑨瑩瑪瑫瑬瑭瑮瑯瑰瑱瑲瑳瑴瑵瑶瑷瑸瑹瑺瑻瑼瑽瑾瑿璀璁璂璃璄璅璆璇璈璉璊璋璌璍璎璏璐璑璒璓璔璕璖璗璘璙璚璛璜璝璞璟璠璡璢璣璤璥璦璧璨璩璪璫璬璭璮璯環璱璲璳璴璵璶璷璸璹璺璻璼璽璾璿瓀瓁瓂瓃瓄瓅瓆瓇瓈瓉瓊瓋瓌瓍瓎瓏瓐瓑瓒瓓瓔瓕瓖瓗瓘瓙瓚瓛瓜瓝瓞瓟瓠瓡瓢瓣瓤瓥瓦瓧瓨瓩瓪瓫瓬瓭瓮瓯瓰瓱瓲瓳瓴瓵瓶瓷瓸瓹瓺瓻瓼瓽瓾瓿甀甁甂甃甄甅甆甇甈甉甊甋甌甍甎甏甐甑甒甓甔甕甖甗甘甙甚甛甜甝甞生甠甡產産甤甥甦甧用甩甪甫甬甭甮甯田由甲申甴电甶男甸甹町画甼甽甾甿畀畁畂畃畄畅畆畇畈畉畊畋界畍畎畏畐畑畒畓畔畕畖畗畘留畚畛畜畝畞畟畠畡畢畣畤略畦畧畨畩番畫畬畭畮畯異畱畲畳畴畵當畷畸畹畺畻畼畽畾畿疀疁疂疃疄疅疆疇疈疉疊疋疌疍疎疏疐疑疒疓疔疕疖疗疘疙疚疛疜疝疞疟疠疡疢疣疤疥疦疧疨疩疪疫疬疭疮疯疰疱疲疳疴疵疶疷疸疹疺疻疼疽疾疿痀痁痂痃痄病痆症痈痉痊痋痌痍痎痏痐痑痒痓痔痕痖痗痘痙痚痛痜痝痞痟痠痡痢痣痤痥痦痧痨痩痪痫痬痭痮痯痰痱痲痳痴痵痶痷痸痹痺痻痼痽痾痿瘀瘁瘂瘃瘄瘅瘆瘇瘈瘉瘊瘋瘌瘍瘎瘏瘐瘑瘒瘓瘔瘕瘖瘗瘘瘙瘚瘛瘜瘝瘞瘟瘠瘡瘢瘣瘤瘥瘦瘧瘨瘩瘪瘫瘬瘭瘮瘯瘰瘱瘲瘳瘴瘵瘶瘷瘸瘹瘺瘻瘼瘽瘾瘿癀癁療癃癄癅癆癇癈癉癊癋癌癍癎癏癐癑癒癓癔癕癖癗癘癙癚癛癜癝癞癟癠癡癢癣癤癥癦癧癨癩癪癫癬癭癮癯癰癱癲癳癴癵癶癷癸癹発登發白百癿皀皁皂皃的皅皆皇皈皉皊皋皌皍皎皏皐皑皒皓皔皕皖皗皘皙皚皛皜皝皞皟皠皡皢皣皤皥皦皧皨皩皪皫皬皭皮皯皰皱皲皳皴皵皶皷皸皹皺皻皼皽皾皿盀盁盂盃盄盅盆盇盈盉益盋盌盍盎盏盐监盒盓盔盕盖盗盘盙盚盛盜盝盞盟盠盡盢監盤盥盦盧盨盩盪盫盬盭目盯盰盱盲盳直盵盶盷相盹盺盻盼盽盾盿眀省眂眃眄眅眆眇眈眉眊看県眍眎眏眐眑眒眓眔眕眖眗眘眙眚眛眜眝眞真眠眡眢眣眤眥眦眧眨眩眪眫眬眭眮眯眰眱眲眳眴眵眶眷眸眹眺眻眼眽眾眿着睁睂睃睄睅睆睇睈睉睊睋睌睍睎睏睐睑睒睓睔睕睖睗睘睙睚睛睜睝睞睟睠睡睢督睤睥睦睧睨睩睪睫睬睭睮睯睰睱睲睳睴睵睶睷睸睹睺睻睼睽睾睿瞀瞁瞂瞃瞄瞅瞆瞇瞈瞉瞊瞋瞌瞍瞎瞏瞐瞑瞒瞓瞔瞕瞖瞗瞘瞙瞚瞛瞜瞝瞞瞟瞠瞡瞢瞣瞤瞥瞦瞧瞨瞩瞪瞫瞬瞭瞮瞯瞰瞱瞲瞳瞴瞵瞶瞷瞸瞹瞺瞻瞼瞽瞾瞿矀矁矂矃矄矅矆矇矈矉矊矋矌矍矎矏矐矑矒矓矔矕矖矗矘矙矚矛矜矝矞矟矠矡矢矣矤知矦矧矨矩矪矫矬短矮矯矰矱矲石矴矵矶矷矸矹矺矻矼矽矾矿砀码砂砃砄砅砆砇砈砉砊砋砌砍砎砏砐砑砒砓研砕砖砗砘砙砚砛砜砝砞砟砠砡砢砣砤砥砦砧砨砩砪砫砬砭砮砯砰砱砲砳破砵砶砷砸砹砺砻砼砽砾砿础硁硂硃硄硅硆硇硈硉硊硋硌硍硎硏硐硑硒硓硔硕硖硗硘硙硚硛硜硝硞硟硠硡硢硣硤硥硦硧硨硩硪硫硬硭确硯硰硱硲硳硴硵硶硷硸硹硺硻硼硽硾硿碀碁碂碃碄碅碆碇碈碉碊碋碌碍碎碏碐碑碒碓碔碕碖碗碘碙碚碛碜碝碞碟碠碡碢碣碤碥碦碧碨碩碪碫碬碭碮碯碰碱碲碳碴碵碶碷碸碹確碻碼碽碾碿磀磁磂磃磄磅磆磇磈磉磊磋磌磍磎磏磐磑磒磓磔磕磖磗磘磙磚磛磜磝磞磟磠磡磢磣磤磥磦磧磨磩磪磫磬磭磮磯磰磱磲磳磴磵磶磷磸磹磺磻磼磽磾磿礀礁礂礃礄礅礆礇礈礉礊礋礌礍礎礏礐礑礒礓礔礕礖礗礘礙礚礛礜礝礞礟礠礡礢礣礤礥礦礧礨礩礪礫礬礭礮礯礰礱礲礳礴礵礶礷礸礹示礻礼礽社礿祀祁祂祃祄祅祆祇祈祉祊祋祌祍祎祏祐祑祒祓祔祕祖祗祘祙祚祛祜祝神祟祠祡祢祣祤祥祦祧票祩祪祫祬祭祮祯祰祱祲祳祴祵祶祷祸祹祺祻祼祽祾祿禀禁禂禃禄禅禆禇禈禉禊禋禌禍禎福禐禑禒禓禔禕禖禗禘禙禚禛禜禝禞禟禠禡禢禣禤禥禦禧禨禩禪禫禬禭禮禯禰禱禲禳禴禵禶禷禸禹禺离禼禽禾禿秀私秂秃秄秅秆秇秈秉秊秋秌种秎秏秐科秒秓秔秕秖秗秘秙秚秛秜秝秞租秠秡秢秣秤秥秦秧秨秩秪秫秬秭秮积称秱秲秳秴秵秶秷秸秹秺移秼秽秾秿稀稁稂稃稄稅稆稇稈稉稊程稌稍税稏稐稑稒稓稔稕稖稗稘稙稚稛稜稝稞稟稠稡稢稣稤稥稦稧稨稩稪稫稬稭種稯稰稱稲稳稴稵稶稷稸稹稺稻稼稽稾稿穀穁穂穃穄穅穆穇穈穉穊穋穌積穎穏穐穑穒穓穔穕穖穗穘穙穚穛穜穝穞穟穠穡穢穣穤穥穦穧穨穩穪穫穬穭穮穯穰穱穲穳穴穵究穷穸穹空穻穼穽穾穿窀突窂窃窄窅窆窇窈窉窊窋窌窍窎窏窐窑窒窓窔窕窖窗窘窙窚窛窜窝窞窟窠窡窢窣窤窥窦窧窨窩窪窫窬窭窮窯窰窱窲窳窴窵窶窷窸窹窺窻窼窽窾窿竀竁竂竃竄竅竆竇竈竉竊立竌竍竎竏竐竑竒竓竔竕竖竗竘站竚竛竜竝竞竟章竡竢竣竤童竦竧竨竩竪竫竬竭竮端竰竱竲竳竴竵競竷竸竹竺竻竼竽竾竿笀笁笂笃笄笅笆笇笈笉笊笋笌笍笎笏笐笑笒笓笔笕笖笗笘笙笚笛笜笝笞笟笠笡笢笣笤笥符笧笨笩笪笫第笭笮笯笰笱笲笳笴笵笶笷笸笹笺笻笼笽笾笿筀筁筂筃筄筅筆筇筈等筊筋筌筍筎筏筐筑筒筓答筕策筗筘筙筚筛筜筝筞筟筠筡筢筣筤筥筦筧筨筩筪筫筬筭筮筯筰筱筲筳筴筵筶筷筸筹筺筻筼筽签筿简箁箂箃箄箅箆箇箈箉箊箋箌箍箎箏箐箑箒箓箔箕箖算箘箙箚箛箜箝箞箟箠管箢箣箤箥箦箧箨箩箪箫箬箭箮箯箰箱箲箳箴箵箶箷箸箹箺箻箼箽箾箿節篁篂篃範篅篆篇篈築篊篋篌篍篎篏篐篑篒篓篔篕篖篗篘篙篚篛篜篝篞篟篠篡篢篣篤篥篦篧篨篩篪篫篬篭篮篯篰篱篲篳篴篵篶篷篸篹篺篻篼篽篾篿簀簁簂簃簄簅簆簇簈簉簊簋簌簍簎簏簐簑簒簓簔簕簖簗簘簙簚簛簜簝簞簟簠簡簢簣簤簥簦簧簨簩簪簫簬簭簮簯簰簱簲簳簴簵簶簷簸簹簺簻簼簽簾簿籀籁籂籃籄籅籆籇籈籉籊籋籌籍籎籏籐籑籒籓籔籕籖籗籘籙籚籛籜籝籞籟籠籡籢籣籤籥籦籧籨籩籪籫籬籭籮籯籰籱籲米籴籵籶籷籸籹籺类籼籽籾籿粀粁粂粃粄粅粆粇粈粉粊粋粌粍粎粏粐粑粒粓粔粕粖粗粘粙粚粛粜粝粞粟粠粡粢粣粤粥粦粧粨粩粪粫粬粭粮粯粰粱粲粳粴粵粶粷粸粹粺粻粼粽精粿糀糁糂糃糄糅糆糇糈糉糊糋糌糍糎糏糐糑糒糓糔糕糖糗糘糙糚糛糜糝糞糟糠糡糢糣糤糥糦糧糨糩糪糫糬糭糮糯糰糱糲糳糴糵糶糷糸糹糺系糼糽糾糿紀紁紂紃約紅紆紇紈紉紊紋紌納紎紏紐紑紒紓純紕紖紗紘紙級紛紜紝紞紟素紡索紣紤紥紦紧紨紩紪紫紬紭紮累細紱紲紳紴紵紶紷紸紹紺紻紼紽紾紿絀絁終絃組絅絆絇絈絉絊絋経絍絎絏結絑絒絓絔絕絖絗絘絙絚絛絜絝絞絟絠絡絢絣絤絥給絧絨絩絪絫絬絭絮絯絰統絲絳絴絵絶絷絸絹絺絻絼絽絾絿綀綁綂綃綄綅綆綇綈綉綊綋綌綍綎綏綐綑綒經綔綕綖綗綘継続綛綜綝綞綟綠綡綢綣綤綥綦綧綨綩綪綫綬維綮綯綰綱網綳綴綵綶綷綸綹綺綻綼綽綾綿緀緁緂緃緄緅緆緇緈緉緊緋緌緍緎総緐緑緒緓緔緕緖緗緘緙線緛緜緝緞緟締緡緢緣緤緥緦緧編緩緪緫緬緭緮緯緰緱緲緳練緵緶緷緸緹緺緻緼緽緾緿縀縁縂縃縄縅縆縇縈縉縊縋縌縍縎縏縐縑縒縓縔縕縖縗縘縙縚縛縜縝縞縟縠縡縢縣縤縥縦縧縨縩縪縫縬縭縮縯縰縱縲縳縴縵縶縷縸縹縺縻縼總績縿繀繁繂繃繄繅繆繇繈繉繊繋繌繍繎繏繐繑繒繓織繕繖繗繘繙繚繛繜繝繞繟繠繡繢繣繤繥繦繧繨繩繪繫繬繭繮繯繰繱繲繳繴繵繶繷繸繹繺繻繼繽繾繿纀纁纂纃纄纅纆纇纈纉纊纋續纍纎纏纐纑纒纓纔纕纖纗纘纙纚纛纜纝纞纟纠纡红纣纤纥约级纨纩纪纫纬纭纮纯纰纱纲纳纴纵纶纷纸纹纺纻纼纽纾线绀绁绂练组绅细织终绉绊绋绌绍绎经绐绑绒结绔绕绖绗绘给绚绛络绝绞统绠绡绢绣绤绥绦继绨绩绪绫绬续绮绯绰绱绲绳维绵绶绷绸绹绺绻综绽绾绿缀缁缂缃缄缅缆缇缈缉缊缋缌缍缎缏缐缑缒缓缔缕编缗缘缙缚缛缜缝缞缟缠缡缢缣缤缥缦缧缨缩缪缫缬缭缮缯缰缱缲缳缴缵缶缷缸缹缺缻缼缽缾缿罀罁罂罃罄罅罆罇罈罉罊罋罌罍罎罏罐网罒罓罔罕罖罗罘罙罚罛罜罝罞罟罠罡罢罣罤罥罦罧罨罩罪罫罬罭置罯罰罱署罳罴罵罶罷罸罹罺罻罼罽罾罿羀羁羂羃羄羅羆羇羈羉羊羋羌羍美羏羐羑羒羓羔羕羖羗羘羙羚羛羜羝羞羟羠羡羢羣群羥羦羧羨義羪羫羬羭羮羯羰羱羲羳羴羵羶羷羸羹羺羻羼羽羾羿翀翁翂翃翄翅翆翇翈翉翊翋翌翍翎翏翐翑習翓翔翕翖翗翘翙翚翛翜翝翞翟翠翡翢翣翤翥翦翧翨翩翪翫翬翭翮翯翰翱翲翳翴翵翶翷翸翹翺翻翼翽翾翿耀老耂考耄者耆耇耈耉耊耋而耍耎耏耐耑耒耓耔耕耖耗耘耙耚耛耜耝耞耟耠耡耢耣耤耥耦耧耨耩耪耫耬耭耮耯耰耱耲耳耴耵耶耷耸耹耺耻耼耽耾耿聀聁聂聃聄聅聆聇聈聉聊聋职聍聎聏聐聑聒聓联聕聖聗聘聙聚聛聜聝聞聟聠聡聢聣聤聥聦聧聨聩聪聫聬聭聮聯聰聱聲聳聴聵聶職聸聹聺聻聼聽聾聿肀肁肂肃肄肅肆肇肈肉肊肋肌肍肎肏肐肑肒肓肔肕肖肗肘肙肚肛肜肝肞肟肠股肢肣肤肥肦肧肨肩肪肫肬肭肮肯肰肱育肳肴肵肶肷肸肹肺肻肼肽肾肿胀胁胂胃胄胅胆胇胈胉胊胋背胍胎胏胐胑胒胓胔胕胖胗胘胙胚胛胜胝胞胟胠胡胢胣胤胥胦胧胨胩胪胫胬胭胮胯胰胱胲胳胴胵胶胷胸胹胺胻胼能胾胿脀脁脂脃脄脅脆脇脈脉脊脋脌脍脎脏脐脑脒脓脔脕脖脗脘脙脚脛脜脝脞脟脠脡脢脣脤脥脦脧脨脩脪脫脬脭脮脯脰脱脲脳脴脵脶脷脸脹脺脻脼脽脾脿腀腁腂腃腄腅腆腇腈腉腊腋腌腍腎腏腐腑腒腓腔腕腖腗腘腙腚腛腜腝腞腟腠腡腢腣腤腥腦腧腨腩腪腫腬腭腮腯腰腱腲腳腴腵腶腷腸腹腺腻腼腽腾腿膀膁膂膃膄膅膆膇膈膉膊膋膌膍膎膏膐膑膒膓膔膕膖膗膘膙膚膛膜膝膞膟膠膡膢膣膤膥膦膧膨膩膪膫膬膭膮膯膰膱膲膳膴膵膶膷膸膹膺膻膼膽膾膿臀臁臂臃臄臅臆臇臈臉臊臋臌臍臎臏臐臑臒臓臔臕臖臗臘臙臚臛臜臝臞臟臠臡臢臣臤臥臦臧臨臩自臫臬臭臮臯臰臱臲至致臵臶臷臸臹臺臻臼臽臾臿舀舁舂舃舄舅舆與興舉舊舋舌舍舎舏舐舑舒舓舔舕舖舗舘舙舚舛舜舝舞舟舠舡舢舣舤舥舦舧舨舩航舫般舭舮舯舰舱舲舳舴舵舶舷舸船舺舻舼舽舾舿艀艁艂艃艄艅艆艇艈艉艊艋艌艍艎艏艐艑艒艓艔艕艖艗艘艙艚艛艜艝艞艟艠艡艢艣艤艥艦艧艨艩艪艫艬艭艮良艰艱色艳艴艵艶艷艸艹艺艻艼艽艾艿芀芁节芃芄芅芆芇芈芉芊芋芌芍芎芏芐芑芒芓芔芕芖芗芘芙芚芛芜芝芞芟芠芡芢芣芤芥芦芧芨芩芪芫芬芭芮芯芰花芲芳芴芵芶芷芸芹芺芻芼芽芾芿苀苁苂苃苄苅苆苇苈苉苊苋苌苍苎苏苐苑苒苓苔苕苖苗苘苙苚苛苜苝苞苟苠苡苢苣苤若苦苧苨苩苪苫苬苭苮苯苰英苲苳苴苵苶苷苸苹苺苻苼苽苾苿茀茁茂范茄茅茆茇茈茉茊茋茌茍茎茏茐茑茒茓茔茕茖茗茘茙茚茛茜茝茞茟茠茡茢茣茤茥茦茧茨茩茪茫茬茭茮茯茰茱茲茳茴茵茶茷茸茹茺茻茼茽茾茿荀荁荂荃荄荅荆荇荈草荊荋荌荍荎荏荐荑荒荓荔荕荖荗荘荙荚荛荜荝荞荟荠荡荢荣荤荥荦荧荨荩荪荫荬荭荮药荰荱荲荳荴荵荶荷荸荹荺荻荼荽荾荿莀莁莂莃莄莅莆莇莈莉莊莋莌莍莎莏莐莑莒莓莔莕莖莗莘莙莚莛莜莝莞莟莠莡莢莣莤莥莦莧莨莩莪莫莬莭莮莯莰莱莲莳莴莵莶获莸莹莺莻莼莽莾莿菀菁菂菃菄菅菆菇菈菉菊菋菌菍菎菏菐菑菒菓菔菕菖菗菘菙菚菛菜菝菞菟菠菡菢菣菤菥菦菧菨菩菪菫菬菭菮華菰菱菲菳菴菵菶菷菸菹菺菻菼菽菾菿萀萁萂萃萄萅萆萇萈萉萊萋萌萍萎萏萐萑萒萓萔萕萖萗萘萙萚萛萜萝萞萟萠萡萢萣萤营萦萧萨萩萪萫萬萭萮萯萰萱萲萳萴萵萶萷萸萹萺萻萼落萾萿葀葁葂葃葄葅葆葇葈葉葊葋葌葍葎葏葐葑葒葓葔葕葖著葘葙葚葛葜葝葞葟葠葡葢董葤葥葦葧葨葩葪葫葬葭葮葯葰葱葲葳葴葵葶葷葸葹葺葻葼葽葾葿蒀蒁蒂蒃蒄蒅蒆蒇蒈蒉蒊蒋蒌蒍蒎蒏蒐蒑蒒蒓蒔蒕蒖蒗蒘蒙蒚蒛蒜蒝蒞蒟蒠蒡蒢蒣蒤蒥蒦蒧蒨蒩蒪蒫蒬蒭蒮蒯蒰蒱蒲蒳蒴蒵蒶蒷蒸蒹蒺蒻蒼蒽蒾蒿蓀蓁蓂蓃蓄蓅蓆蓇蓈蓉蓊蓋蓌蓍蓎蓏蓐蓑蓒蓓蓔蓕蓖蓗蓘蓙蓚蓛蓜蓝蓞蓟蓠蓡蓢蓣蓤蓥蓦蓧蓨蓩蓪蓫蓬蓭蓮蓯蓰蓱蓲蓳蓴蓵蓶蓷蓸蓹蓺蓻蓼蓽蓾蓿蔀蔁蔂蔃蔄蔅蔆蔇蔈蔉蔊蔋蔌蔍蔎蔏蔐蔑蔒蔓蔔蔕蔖蔗蔘蔙蔚蔛蔜蔝蔞蔟蔠蔡蔢蔣蔤蔥蔦蔧蔨蔩蔪蔫蔬蔭蔮蔯蔰蔱蔲蔳蔴蔵蔶蔷蔸蔹蔺蔻蔼蔽蔾蔿蕀蕁蕂蕃蕄蕅蕆蕇蕈蕉蕊蕋蕌蕍蕎蕏蕐蕑蕒蕓蕔蕕蕖蕗蕘蕙蕚蕛蕜蕝蕞蕟蕠蕡蕢蕣蕤蕥蕦蕧蕨蕩蕪蕫蕬蕭蕮蕯蕰蕱蕲蕳蕴蕵蕶蕷蕸蕹蕺蕻蕼蕽蕾蕿薀薁薂薃薄薅薆薇薈薉薊薋薌薍薎薏薐薑薒薓薔薕薖薗薘薙薚薛薜薝薞薟薠薡薢薣薤薥薦薧薨薩薪薫薬薭薮薯薰薱薲薳薴薵薶薷薸薹薺薻薼薽薾薿藀藁藂藃藄藅藆藇藈藉藊藋藌藍藎藏藐藑藒藓藔藕藖藗藘藙藚藛藜藝藞藟藠藡藢藣藤藥藦藧藨藩藪藫藬藭藮藯藰藱藲藳藴藵藶藷藸藹藺藻藼藽藾藿蘀蘁蘂蘃蘄蘅蘆蘇蘈蘉蘊蘋蘌蘍蘎蘏蘐蘑蘒蘓蘔蘕蘖蘗蘘蘙蘚蘛蘜蘝蘞蘟蘠蘡蘢蘣蘤蘥蘦蘧蘨蘩蘪蘫蘬蘭蘮蘯蘰蘱蘲蘳蘴蘵蘶蘷蘸蘹蘺蘻蘼蘽蘾蘿虀虁虂虃虄虅虆虇虈虉虊虋虌虍虎虏虐虑虒虓虔處虖虗虘虙虚虛虜虝虞號虠虡虢虣虤虥虦虧虨虩虪虫虬虭虮虯虰虱虲虳虴虵虶虷虸虹虺虻虼虽虾虿蚀蚁蚂蚃蚄蚅蚆蚇蚈蚉蚊蚋蚌蚍蚎蚏蚐蚑蚒蚓蚔蚕蚖蚗蚘蚙蚚蚛蚜蚝蚞蚟蚠蚡蚢蚣蚤蚥蚦蚧蚨蚩蚪蚫蚬蚭蚮蚯蚰蚱蚲蚳蚴蚵蚶蚷蚸蚹蚺蚻蚼蚽蚾蚿蛀蛁蛂蛃蛄蛅蛆蛇蛈蛉蛊蛋蛌蛍蛎蛏蛐蛑蛒蛓蛔蛕蛖蛗蛘蛙蛚蛛蛜蛝蛞蛟蛠蛡蛢蛣蛤蛥蛦蛧蛨蛩蛪蛫蛬蛭蛮蛯蛰蛱蛲蛳蛴蛵蛶蛷蛸蛹蛺蛻蛼蛽蛾蛿蜀蜁蜂蜃蜄蜅蜆蜇蜈蜉蜊蜋蜌蜍蜎蜏蜐蜑蜒蜓蜔蜕蜖蜗蜘蜙蜚蜛蜜蜝蜞蜟蜠蜡蜢蜣蜤蜥蜦蜧蜨蜩蜪蜫蜬蜭蜮蜯蜰蜱蜲蜳蜴蜵蜶蜷蜸蜹蜺蜻蜼蜽蜾蜿蝀蝁蝂蝃蝄蝅蝆蝇蝈蝉蝊蝋蝌蝍蝎蝏蝐蝑蝒蝓蝔蝕蝖蝗蝘蝙蝚蝛蝜蝝蝞蝟蝠蝡蝢蝣蝤蝥蝦蝧蝨蝩蝪蝫蝬蝭蝮蝯蝰蝱蝲蝳蝴蝵蝶蝷蝸蝹蝺蝻蝼蝽蝾蝿螀螁螂螃螄螅螆螇螈螉螊螋螌融螎螏螐螑螒螓螔螕螖螗螘螙螚螛螜螝螞螟螠螡螢螣螤螥螦螧螨螩螪螫螬螭螮螯螰螱螲螳螴螵螶螷螸螹螺螻螼螽螾螿蟀蟁蟂蟃蟄蟅蟆蟇蟈蟉蟊蟋蟌蟍蟎蟏蟐蟑蟒蟓蟔蟕蟖蟗蟘蟙蟚蟛蟜蟝蟞蟟蟠蟡蟢蟣蟤蟥蟦蟧蟨蟩蟪蟫蟬蟭蟮蟯蟰蟱蟲蟳蟴蟵蟶蟷蟸蟹蟺蟻蟼蟽蟾蟿蠀蠁蠂蠃蠄蠅蠆蠇蠈蠉蠊蠋蠌蠍蠎蠏蠐蠑蠒蠓蠔蠕蠖蠗蠘蠙蠚蠛蠜蠝蠞蠟蠠蠡蠢蠣蠤蠥蠦蠧蠨蠩蠪蠫蠬蠭蠮蠯蠰蠱蠲蠳蠴蠵蠶蠷蠸蠹蠺蠻蠼蠽蠾蠿血衁衂衃衄衅衆衇衈衉衊衋行衍衎衏衐衑衒術衔衕衖街衘衙衚衛衜衝衞衟衠衡衢衣衤补衦衧表衩衪衫衬衭衮衯衰衱衲衳衴衵衶衷衸衹衺衻衼衽衾衿袀袁袂袃袄袅袆袇袈袉袊袋袌袍袎袏袐袑袒袓袔袕袖袗袘袙袚袛袜袝袞袟袠袡袢袣袤袥袦袧袨袩袪被袬袭袮袯袰袱袲袳袴袵袶袷袸袹袺袻袼袽袾袿裀裁裂裃裄装裆裇裈裉裊裋裌裍裎裏裐裑裒裓裔裕裖裗裘裙裚裛補裝裞裟裠裡裢裣裤裥裦裧裨裩裪裫裬裭裮裯裰裱裲裳裴裵裶裷裸裹裺裻裼製裾裿褀褁褂褃褄褅褆複褈褉褊褋褌褍褎褏褐褑褒褓褔褕褖褗褘褙褚褛褜褝褞褟褠褡褢褣褤褥褦褧褨褩褪褫褬褭褮褯褰褱褲褳褴褵褶褷褸褹褺褻褼褽褾褿襀襁襂襃襄襅襆襇襈襉襊襋襌襍襎襏襐襑襒襓襔襕襖襗襘襙襚襛襜襝襞襟襠襡襢襣襤襥襦襧襨襩襪襫襬襭襮襯襰襱襲襳襴襵襶襷襸襹襺襻襼襽襾西覀要覂覃覄覅覆覇覈覉覊見覌覍覎規覐覑覒覓覔覕視覗覘覙覚覛覜覝覞覟覠覡覢覣覤覥覦覧覨覩親覫覬覭覮覯覰覱覲観覴覵覶覷覸覹覺覻覼覽覾覿觀见观觃规觅视觇览觉觊觋觌觍觎觏觐觑角觓觔觕觖觗觘觙觚觛觜觝觞觟觠觡觢解觤觥触觧觨觩觪觫觬觭觮觯觰觱觲觳觴觵觶觷觸觹觺觻觼觽觾觿言訁訂訃訄訅訆訇計訉訊訋訌訍討訏訐訑訒訓訔訕訖託記訙訚訛訜訝訞訟訠訡訢訣訤訥訦訧訨訩訪訫訬設訮訯訰許訲訳訴訵訶訷訸訹診註証訽訾訿詀詁詂詃詄詅詆詇詈詉詊詋詌詍詎詏詐詑詒詓詔評詖詗詘詙詚詛詜詝詞詟詠詡詢詣詤詥試詧詨詩詪詫詬詭詮詯詰話該詳詴詵詶詷詸詹詺詻詼詽詾詿誀誁誂誃誄誅誆誇誈誉誊誋誌認誎誏誐誑誒誓誔誕誖誗誘誙誚誛誜誝語誟誠誡誢誣誤誥誦誧誨誩說誫説読誮誯誰誱課誳誴誵誶誷誸誹誺誻誼誽誾調諀諁諂諃諄諅諆談諈諉諊請諌諍諎諏諐諑諒諓諔諕論諗諘諙諚諛諜諝諞諟諠諡諢諣諤諥諦諧諨諩諪諫諬諭諮諯諰諱諲諳諴諵諶諷諸諹諺諻諼諽諾諿謀謁謂謃謄謅謆謇謈謉謊謋謌謍謎謏謐謑謒謓謔謕謖謗謘謙謚講謜謝謞謟謠謡謢謣謤謥謦謧謨謩謪謫謬謭謮謯謰謱謲謳謴謵謶謷謸謹謺謻謼謽謾謿譀譁譂譃譄譅譆譇譈證譊譋譌譍譎譏譐譑譒譓譔譕譖譗識譙譚譛譜譝譞譟譠譡譢譣譤譥警譧譨譩譪譫譬譭譮譯議譱譲譳譴譵譶護譸譹譺譻譼譽譾譿讀讁讂讃讄讅讆讇讈讉變讋讌讍讎讏讐讑讒讓讔讕讖讗讘讙讚讛讜讝讞讟讠计订讣认讥讦讧讨让讪讫讬训议讯记讱讲讳讴讵讶讷许讹论讻讼讽设访诀证诂诃评诅识诇诈诉诊诋诌词诎诏诐译诒诓诔试诖诗诘诙诚诛诜话诞诟诠诡询诣诤该详诧诨诩诪诫诬语诮误诰诱诲诳说诵诶请诸诹诺读诼诽课诿谀谁谂调谄谅谆谇谈谉谊谋谌谍谎谏谐谑谒谓谔谕谖谗谘谙谚谛谜谝谞谟谠谡谢谣谤谥谦谧谨谩谪谫谬谭谮谯谰谱谲谳谴谵谶谷谸谹谺谻谼谽谾谿豀豁豂豃豄豅豆豇豈豉豊豋豌豍豎豏豐豑豒豓豔豕豖豗豘豙豚豛豜豝豞豟豠象豢豣豤豥豦豧豨豩豪豫豬豭豮豯豰豱豲豳豴豵豶豷豸豹豺豻豼豽豾豿貀貁貂貃貄貅貆貇貈貉貊貋貌貍貎貏貐貑貒貓貔貕貖貗貘貙貚貛貜貝貞貟負財貢貣貤貥貦貧貨販貪貫責貭貮貯貰貱貲貳貴貵貶買貸貹貺費貼貽貾貿賀賁賂賃賄賅賆資賈賉賊賋賌賍賎賏賐賑賒賓賔賕賖賗賘賙賚賛賜賝賞賟賠賡賢賣賤賥賦賧賨賩質賫賬賭賮賯賰賱賲賳賴賵賶賷賸賹賺賻購賽賾賿贀贁贂贃贄贅贆贇贈贉贊贋贌贍贎贏贐贑贒贓贔贕贖贗贘贙贚贛贜贝贞负贠贡财责贤败账货质贩贪贫贬购贮贯贰贱贲贳贴贵贶贷贸费贺贻贼贽贾贿赀赁赂赃资赅赆赇赈赉赊赋赌赍赎赏赐赑赒赓赔赕赖赗赘赙赚赛赜赝赞赟赠赡赢赣赤赥赦赧赨赩赪赫赬赭赮赯走赱赲赳赴赵赶起赸赹赺赻赼赽赾赿趀趁趂趃趄超趆趇趈趉越趋趌趍趎趏趐趑趒趓趔趕趖趗趘趙趚趛趜趝趞趟趠趡趢趣趤趥趦趧趨趩趪趫趬趭趮趯趰趱趲足趴趵趶趷趸趹趺趻趼趽趾趿跀跁跂跃跄跅跆跇跈跉跊跋跌跍跎跏跐跑跒跓跔跕跖跗跘跙跚跛跜距跞跟跠跡跢跣跤跥跦跧跨跩跪跫跬跭跮路跰跱跲跳跴践跶跷跸跹跺跻跼跽跾跿踀踁踂踃踄踅踆踇踈踉踊踋踌踍踎踏踐踑踒踓踔踕踖踗踘踙踚踛踜踝踞踟踠踡踢踣踤踥踦踧踨踩踪踫踬踭踮踯踰踱踲踳踴踵踶踷踸踹踺踻踼踽踾踿蹀蹁蹂蹃蹄蹅蹆蹇蹈蹉蹊蹋蹌蹍蹎蹏蹐蹑蹒蹓蹔蹕蹖蹗蹘蹙蹚蹛蹜蹝蹞蹟蹠蹡蹢蹣蹤蹥蹦蹧蹨蹩蹪蹫蹬蹭蹮蹯蹰蹱蹲蹳蹴蹵蹶蹷蹸蹹蹺蹻蹼蹽蹾蹿躀躁躂躃躄躅躆躇躈躉躊躋躌躍躎躏躐躑躒躓躔躕躖躗躘躙躚躛躜躝躞躟躠躡躢躣躤躥躦躧躨躩躪身躬躭躮躯躰躱躲躳躴躵躶躷躸躹躺躻躼躽躾躿軀軁軂軃軄軅軆軇軈軉車軋軌軍軎軏軐軑軒軓軔軕軖軗軘軙軚軛軜軝軞軟軠軡転軣軤軥軦軧軨軩軪軫軬軭軮軯軰軱軲軳軴軵軶軷軸軹軺軻軼軽軾軿輀輁輂較輄輅輆輇輈載輊輋輌輍輎輏輐輑輒輓輔輕輖輗輘輙輚輛輜輝輞輟輠輡輢輣輤輥輦輧輨輩輪輫輬輭輮輯輰輱輲輳輴輵輶輷輸輹輺輻輼輽輾輿轀轁轂轃轄轅轆轇轈轉轊轋轌轍轎轏轐轑轒轓轔轕轖轗轘轙轚轛轜轝轞轟轠轡轢轣轤轥车轧轨轩轪轫转轭轮软轰轱轲轳轴轵轶轷轸轹轺轻轼载轾轿辀辁辂较辄辅辆辇辈辉辊辋辌辍辎辏辐辑辒输辔辕辖辗辘辙辚辛辜辝辞辟辠辡辢辣辤辥辦辧辨辩辪辫辬辭辮辯辰辱農辳辴辵辶辷辸边辺辻込辽达辿迀迁迂迃迄迅迆过迈迉迊迋迌迍迎迏运近迒迓返迕迖迗还这迚进远违连迟迠迡迢迣迤迥迦迧迨迩迪迫迬迭迮迯述迱迲迳迴迵迶迷迸迹迺迻迼追迾迿退送适逃逄逅逆逇逈选逊逋逌逍逎透逐逑递逓途逕逖逗逘這通逛逜逝逞速造逡逢連逤逥逦逧逨逩逪逫逬逭逮逯逰週進逳逴逵逶逷逸逹逺逻逼逽逾逿遀遁遂遃遄遅遆遇遈遉遊運遌遍過遏遐遑遒道達違遖遗遘遙遚遛遜遝遞遟遠遡遢遣遤遥遦遧遨適遪遫遬遭遮遯遰遱遲遳遴遵遶遷選遹遺遻遼遽遾避邀邁邂邃還邅邆邇邈邉邊邋邌邍邎邏邐邑邒邓邔邕邖邗邘邙邚邛邜邝邞邟邠邡邢那邤邥邦邧邨邩邪邫邬邭邮邯邰邱邲邳邴邵邶邷邸邹邺邻邼邽邾邿郀郁郂郃郄郅郆郇郈郉郊郋郌郍郎郏郐郑郒郓郔郕郖郗郘郙郚郛郜郝郞郟郠郡郢郣郤郥郦郧部郩郪郫郬郭郮郯郰郱郲郳郴郵郶郷郸郹郺郻郼都郾郿鄀鄁鄂鄃鄄鄅鄆鄇鄈鄉鄊鄋鄌鄍鄎鄏鄐鄑鄒鄓鄔鄕鄖鄗鄘鄙鄚鄛鄜鄝鄞鄟鄠鄡鄢鄣鄤鄥鄦鄧鄨鄩鄪鄫鄬鄭鄮鄯鄰鄱鄲鄳鄴鄵鄶鄷鄸鄹鄺鄻鄼鄽鄾鄿酀酁酂酃酄酅酆酇酈酉酊酋酌配酎酏酐酑酒酓酔酕酖酗酘酙酚酛酜酝酞酟酠酡酢酣酤酥酦酧酨酩酪酫酬酭酮酯酰酱酲酳酴酵酶酷酸酹酺酻酼酽酾酿醀醁醂醃醄醅醆醇醈醉醊醋醌醍醎醏醐醑醒醓醔醕醖醗醘醙醚醛醜醝醞醟醠醡醢醣醤醥醦醧醨醩醪醫醬醭醮醯醰醱醲醳醴醵醶醷醸醹醺醻醼醽醾醿釀釁釂釃釄釅釆采釈釉释釋里重野量釐金釒釓釔釕釖釗釘釙釚釛釜針釞釟釠釡釢釣釤釥釦釧釨釩釪釫釬釭釮釯釰釱釲釳釴釵釶釷釸釹釺釻釼釽釾釿鈀鈁鈂鈃鈄鈅鈆鈇鈈鈉鈊鈋鈌鈍鈎鈏鈐鈑鈒鈓鈔鈕鈖鈗鈘鈙鈚鈛鈜鈝鈞鈟鈠鈡鈢鈣鈤鈥鈦鈧鈨鈩鈪鈫鈬鈭鈮鈯鈰鈱鈲鈳鈴鈵鈶鈷鈸鈹鈺鈻鈼鈽鈾鈿鉀鉁鉂鉃鉄鉅鉆鉇鉈鉉鉊鉋鉌鉍鉎鉏鉐鉑鉒鉓鉔鉕鉖鉗鉘鉙鉚鉛鉜鉝鉞鉟鉠鉡鉢鉣鉤鉥鉦鉧鉨鉩鉪鉫鉬鉭鉮鉯鉰鉱鉲鉳鉴鉵鉶鉷鉸鉹鉺鉻鉼鉽鉾鉿銀銁銂銃銄銅銆銇銈銉銊銋銌銍銎銏銐銑銒銓銔銕銖銗銘銙銚銛銜銝銞銟銠銡銢銣銤銥銦銧銨銩銪銫銬銭銮銯銰銱銲銳銴銵銶銷銸銹銺銻銼銽銾銿鋀鋁鋂鋃鋄鋅鋆鋇鋈鋉鋊鋋鋌鋍鋎鋏鋐鋑鋒鋓鋔鋕鋖鋗鋘鋙鋚鋛鋜鋝鋞鋟鋠鋡鋢鋣鋤鋥鋦鋧鋨鋩鋪鋫鋬鋭鋮鋯鋰鋱鋲鋳鋴鋵鋶鋷鋸鋹鋺鋻鋼鋽鋾鋿錀錁錂錃錄錅錆錇錈錉錊錋錌錍錎錏錐錑錒錓錔錕錖錗錘錙錚錛錜錝錞錟錠錡錢錣錤錥錦錧錨錩錪錫錬錭錮錯錰錱録錳錴錵錶錷錸錹錺錻錼錽錾錿鍀鍁鍂鍃鍄鍅鍆鍇鍈鍉鍊鍋鍌鍍鍎鍏鍐鍑鍒鍓鍔鍕鍖鍗鍘鍙鍚鍛鍜鍝鍞鍟鍠鍡鍢鍣鍤鍥鍦鍧鍨鍩鍪鍫鍬鍭鍮鍯鍰鍱鍲鍳鍴鍵鍶鍷鍸鍹鍺鍻鍼鍽鍾鍿鎀鎁鎂鎃鎄鎅鎆鎇鎈鎉鎊鎋鎌鎍鎎鎏鎐鎑鎒鎓鎔鎕鎖鎗鎘鎙鎚鎛鎜鎝鎞鎟鎠鎡鎢鎣鎤鎥鎦鎧鎨鎩鎪鎫鎬鎭鎮鎯鎰鎱鎲鎳鎴鎵鎶鎷鎸鎹鎺鎻鎼鎽鎾鎿鏀鏁鏂鏃鏄鏅鏆鏇鏈鏉鏊鏋鏌鏍鏎鏏鏐鏑鏒鏓鏔鏕鏖鏗鏘鏙鏚鏛鏜鏝鏞鏟鏠鏡鏢鏣鏤鏥鏦鏧鏨鏩鏪鏫鏬鏭鏮鏯鏰鏱鏲鏳鏴鏵鏶鏷鏸鏹鏺鏻鏼鏽鏾鏿鐀鐁鐂鐃鐄鐅鐆鐇鐈鐉鐊鐋鐌鐍鐎鐏鐐鐑鐒鐓鐔鐕鐖鐗鐘鐙鐚鐛鐜鐝鐞鐟鐠鐡鐢鐣鐤鐥鐦鐧鐨鐩鐪鐫鐬鐭鐮鐯鐰鐱鐲鐳鐴鐵鐶鐷鐸鐹鐺鐻鐼鐽鐾鐿鑀鑁鑂鑃鑄鑅鑆鑇鑈鑉鑊鑋鑌鑍鑎鑏鑐鑑鑒鑓鑔鑕鑖鑗鑘鑙鑚鑛鑜鑝鑞鑟鑠鑡鑢鑣鑤鑥鑦鑧鑨鑩鑪鑫鑬鑭鑮鑯鑰鑱鑲鑳鑴鑵鑶鑷鑸鑹鑺鑻鑼鑽鑾鑿钀钁钂钃钄钅钆钇针钉钊钋钌钍钎钏钐钑钒钓钔钕钖钗钘钙钚钛钜钝钞钟钠钡钢钣钤钥钦钧钨钩钪钫钬钭钮钯钰钱钲钳钴钵钶钷钸钹钺钻钼钽钾钿铀铁铂铃铄铅铆铇铈铉铊铋铌铍铎铏铐铑铒铓铔铕铖铗铘铙铚铛铜铝铞铟铠铡铢铣铤铥铦铧铨铩铪铫铬铭铮铯铰铱铲铳铴铵银铷铸铹铺铻铼铽链铿销锁锂锃锄锅锆锇锈锉锊锋锌锍锎锏锐锑锒锓锔锕锖锗锘错锚锛锜锝锞锟锠锡锢锣锤锥锦锧锨锩锪锫锬锭键锯锰锱锲锳锴锵锶锷锸锹锺锻锼锽锾锿镀镁镂镃镄镅镆镇镈镉镊镋镌镍镎镏镐镑镒镓镔镕镖镗镘镙镚镛镜镝镞镟镠镡镢镣镤镥镦镧镨镩镪镫镬镭镮镯镰镱镲镳镴镵镶長镸镹镺镻镼镽镾长門閁閂閃閄閅閆閇閈閉閊開閌閍閎閏閐閑閒間閔閕閖閗閘閙閚閛閜閝閞閟閠閡関閣閤閥閦閧閨閩閪閫閬閭閮閯閰閱閲閳閴閵閶閷閸閹閺閻閼閽閾閿闀闁闂闃闄闅闆闇闈闉闊闋闌闍闎闏闐闑闒闓闔闕闖闗闘闙闚闛關闝闞闟闠闡闢闣闤闥闦闧门闩闪闫闬闭问闯闰闱闲闳间闵闶闷闸闹闺闻闼闽闾闿阀阁阂阃阄阅阆阇阈阉阊阋阌阍阎阏阐阑阒阓阔阕阖阗阘阙阚阛阜阝阞队阠阡阢阣阤阥阦阧阨阩阪阫阬阭阮阯阰阱防阳阴阵阶阷阸阹阺阻阼阽阾阿陀陁陂陃附际陆陇陈陉陊陋陌降陎陏限陑陒陓陔陕陖陗陘陙陚陛陜陝陞陟陠陡院陣除陥陦陧陨险陪陫陬陭陮陯陰陱陲陳陴陵陶陷陸陹険陻陼陽陾陿隀隁隂隃隄隅隆隇隈隉隊隋隌隍階随隐隑隒隓隔隕隖隗隘隙隚際障隝隞隟隠隡隢隣隤隥隦隧隨隩險隫隬隭隮隯隰隱隲隳隴隵隶隷隸隹隺隻隼隽难隿雀雁雂雃雄雅集雇雈雉雊雋雌雍雎雏雐雑雒雓雔雕雖雗雘雙雚雛雜雝雞雟雠雡離難雤雥雦雧雨雩雪雫雬雭雮雯雰雱雲雳雴雵零雷雸雹雺電雼雽雾雿需霁霂霃霄霅霆震霈霉霊霋霌霍霎霏霐霑霒霓霔霕霖霗霘霙霚霛霜霝霞霟霠霡霢霣霤霥霦霧霨霩霪霫霬霭霮霯霰霱露霳霴霵霶霷霸霹霺霻霼霽霾霿靀靁靂靃靄靅靆靇靈靉靊靋靌靍靎靏靐靑青靓靔靕靖靗靘静靚靛靜靝非靟靠靡面靣靤靥靦靧靨革靪靫靬靭靮靯靰靱靲靳靴靵靶靷靸靹靺靻靼靽靾靿鞀鞁鞂鞃鞄鞅鞆鞇鞈鞉鞊鞋鞌鞍鞎鞏鞐鞑鞒鞓鞔鞕鞖鞗鞘鞙鞚鞛鞜鞝鞞鞟鞠鞡鞢鞣鞤鞥鞦鞧鞨鞩鞪鞫鞬鞭鞮鞯鞰鞱鞲鞳鞴鞵鞶鞷鞸鞹鞺鞻鞼鞽鞾鞿韀韁韂韃韄韅韆韇韈韉韊韋韌韍韎韏韐韑韒韓韔韕韖韗韘韙韚韛韜韝韞韟韠韡韢韣韤韥韦韧韨韩韪韫韬韭韮韯韰韱韲音韴韵韶韷韸韹韺韻韼韽韾響頀頁頂頃頄項順頇須頉頊頋頌頍頎頏預頑頒頓頔頕頖頗領頙頚頛頜頝頞頟頠頡頢頣頤頥頦頧頨頩頪頫頬頭頮頯頰頱頲頳頴頵頶頷頸頹頺頻頼頽頾頿顀顁顂顃顄顅顆顇顈顉顊顋題額顎顏顐顑顒顓顔顕顖顗願顙顚顛顜顝類顟顠顡顢顣顤顥顦顧顨顩顪顫顬顭顮顯顰顱顲顳顴页顶顷顸项顺须顼顽顾顿颀颁颂颃预颅领颇颈颉颊颋颌颍颎颏颐频颒颓颔颕颖颗题颙颚颛颜额颞颟颠颡颢颣颤颥颦颧風颩颪颫颬颭颮颯颰颱颲颳颴颵颶颷颸颹颺颻颼颽颾颿飀飁飂飃飄飅飆飇飈飉飊飋飌飍风飏飐飑飒飓飔飕飖飗飘飙飚飛飜飝飞食飠飡飢飣飤飥飦飧飨飩飪飫飬飭飮飯飰飱飲飳飴飵飶飷飸飹飺飻飼飽飾飿餀餁餂餃餄餅餆餇餈餉養餋餌餍餎餏餐餑餒餓餔餕餖餗餘餙餚餛餜餝餞餟餠餡餢餣餤餥餦餧館餩餪餫餬餭餮餯餰餱餲餳餴餵餶餷餸餹餺餻餼餽餾餿饀饁饂饃饄饅饆饇饈饉饊饋饌饍饎饏饐饑饒饓饔饕饖饗饘饙饚饛饜饝饞饟饠饡饢饣饤饥饦饧饨饩饪饫饬饭饮饯饰饱饲饳饴饵饶饷饸饹饺饻饼饽饾饿馀馁馂馃馄馅馆馇馈馉馊馋馌馍馎馏馐馑馒馓馔馕首馗馘香馚馛馜馝馞馟馠馡馢馣馤馥馦馧馨馩馪馫馬馭馮馯馰馱馲馳馴馵馶馷馸馹馺馻馼馽馾馿駀駁駂駃駄駅駆駇駈駉駊駋駌駍駎駏駐駑駒駓駔駕駖駗駘駙駚駛駜駝駞駟駠駡駢駣駤駥駦駧駨駩駪駫駬駭駮駯駰駱駲駳駴駵駶駷駸駹駺駻駼駽駾駿騀騁騂騃騄騅騆騇騈騉騊騋騌騍騎騏騐騑騒験騔騕騖騗騘騙騚騛騜騝騞騟騠騡騢騣騤騥騦騧騨騩騪騫騬騭騮騯騰騱騲騳騴騵騶騷騸騹騺騻騼騽騾騿驀驁驂驃驄驅驆驇驈驉驊驋驌驍驎驏驐驑驒驓驔驕驖驗驘驙驚驛驜驝驞驟驠驡驢驣驤驥驦驧驨驩驪驫马驭驮驯驰驱驲驳驴驵驶驷驸驹驺驻驼驽驾驿骀骁骂骃骄骅骆骇骈骉骊骋验骍骎骏骐骑骒骓骔骕骖骗骘骙骚骛骜骝骞骟骠骡骢骣骤骥骦骧骨骩骪骫骬骭骮骯骰骱骲骳骴骵骶骷骸骹骺骻骼骽骾骿髀髁髂髃髄髅髆髇髈髉髊髋髌髍髎髏髐髑髒髓體髕髖髗高髙髚髛髜髝髞髟髠髡髢髣髤髥髦髧髨髩髪髫髬髭髮髯髰髱髲髳髴髵髶髷髸髹髺髻髼髽髾髿鬀鬁鬂鬃鬄鬅鬆鬇鬈鬉鬊鬋鬌鬍鬎鬏鬐鬑鬒鬓鬔鬕鬖鬗鬘鬙鬚鬛鬜鬝鬞鬟鬠鬡鬢鬣鬤鬥鬦鬧鬨鬩鬪鬫鬬鬭鬮鬯鬰鬱鬲鬳鬴鬵鬶鬷鬸鬹鬺鬻鬼鬽鬾鬿魀魁魂魃魄魅魆魇魈魉魊魋魌魍魎魏魐魑魒魓魔魕魖魗魘魙魚魛魜魝魞魟魠魡魢魣魤魥魦魧魨魩魪魫魬魭魮魯魰魱魲魳魴魵魶魷魸魹魺魻魼魽魾魿鮀鮁鮂鮃鮄鮅鮆鮇鮈鮉鮊鮋鮌鮍鮎鮏鮐鮑鮒鮓鮔鮕鮖鮗鮘鮙鮚鮛鮜鮝鮞鮟鮠鮡鮢鮣鮤鮥鮦鮧鮨鮩鮪鮫鮬鮭鮮鮯鮰鮱鮲鮳鮴鮵鮶鮷鮸鮹鮺鮻鮼鮽鮾鮿鯀鯁鯂鯃鯄鯅鯆鯇鯈鯉鯊鯋鯌鯍鯎鯏鯐鯑鯒鯓鯔鯕鯖鯗鯘鯙鯚鯛鯜鯝鯞鯟鯠鯡鯢鯣鯤鯥鯦鯧鯨鯩鯪鯫鯬鯭鯮鯯鯰鯱鯲鯳鯴鯵鯶鯷鯸鯹鯺鯻鯼鯽鯾鯿鰀鰁鰂鰃鰄鰅鰆鰇鰈鰉鰊鰋鰌鰍鰎鰏鰐鰑鰒鰓鰔鰕鰖鰗鰘鰙鰚鰛鰜鰝鰞鰟鰠鰡鰢鰣鰤鰥鰦鰧鰨鰩鰪鰫鰬鰭鰮鰯鰰鰱鰲鰳鰴鰵鰶鰷鰸鰹鰺鰻鰼鰽鰾鰿鱀鱁鱂鱃鱄鱅鱆鱇鱈鱉鱊鱋鱌鱍鱎鱏鱐鱑鱒鱓鱔鱕鱖鱗鱘鱙鱚鱛鱜鱝鱞鱟鱠鱡鱢鱣鱤鱥鱦鱧鱨鱩鱪鱫鱬鱭鱮鱯鱰鱱鱲鱳鱴鱵鱶鱷鱸鱹鱺鱻鱼鱽鱾鱿鲀鲁鲂鲃鲄鲅鲆鲇鲈鲉鲊鲋鲌鲍鲎鲏鲐鲑鲒鲓鲔鲕鲖鲗鲘鲙鲚鲛鲜鲝鲞鲟鲠鲡鲢鲣鲤鲥鲦鲧鲨鲩鲪鲫鲬鲭鲮鲯鲰鲱鲲鲳鲴鲵鲶鲷鲸鲹鲺鲻鲼鲽鲾鲿鳀鳁鳂鳃鳄鳅鳆鳇鳈鳉鳊鳋鳌鳍鳎鳏鳐鳑鳒鳓鳔鳕鳖鳗鳘鳙鳚鳛鳜鳝鳞鳟鳠鳡鳢鳣鳤鳥鳦鳧鳨鳩鳪鳫鳬鳭鳮鳯鳰鳱鳲鳳鳴鳵鳶鳷鳸鳹鳺鳻鳼鳽鳾鳿鴀鴁鴂鴃鴄鴅鴆鴇鴈鴉鴊鴋鴌鴍鴎鴏鴐鴑鴒鴓鴔鴕鴖鴗鴘鴙鴚鴛鴜鴝鴞鴟鴠鴡鴢鴣鴤鴥鴦鴧鴨鴩鴪鴫鴬鴭鴮鴯鴰鴱鴲鴳鴴鴵鴶鴷鴸鴹鴺鴻鴼鴽鴾鴿鵀鵁鵂鵃鵄鵅鵆鵇鵈鵉鵊鵋鵌鵍鵎鵏鵐鵑鵒鵓鵔鵕鵖鵗鵘鵙鵚鵛鵜鵝鵞鵟鵠鵡鵢鵣鵤鵥鵦鵧鵨鵩鵪鵫鵬鵭鵮鵯鵰鵱鵲鵳鵴鵵鵶鵷鵸鵹鵺鵻鵼鵽鵾鵿鶀鶁鶂鶃鶄鶅鶆鶇鶈鶉鶊鶋鶌鶍鶎鶏鶐鶑鶒鶓鶔鶕鶖鶗鶘鶙鶚鶛鶜鶝鶞鶟鶠鶡鶢鶣鶤鶥鶦鶧鶨鶩鶪鶫鶬鶭鶮鶯鶰鶱鶲鶳鶴鶵鶶鶷鶸鶹鶺鶻鶼鶽鶾鶿鷀鷁鷂鷃鷄鷅鷆鷇鷈鷉鷊鷋鷌鷍鷎鷏鷐鷑鷒鷓鷔鷕鷖鷗鷘鷙鷚鷛鷜鷝鷞鷟鷠鷡鷢鷣鷤鷥鷦鷧鷨鷩鷪鷫鷬鷭鷮鷯鷰鷱鷲鷳鷴鷵鷶鷷鷸鷹鷺鷻鷼鷽鷾鷿鸀鸁鸂鸃鸄鸅鸆鸇鸈鸉鸊鸋鸌鸍鸎鸏鸐鸑鸒鸓鸔鸕鸖鸗鸘鸙鸚鸛鸜鸝鸞鸟鸠鸡鸢鸣鸤鸥鸦鸧鸨鸩鸪鸫鸬鸭鸮鸯鸰鸱鸲鸳鸴鸵鸶鸷鸸鸹鸺鸻鸼鸽鸾鸿鹀鹁鹂鹃鹄鹅鹆鹇鹈鹉鹊鹋鹌鹍鹎鹏鹐鹑鹒鹓鹔鹕鹖鹗鹘鹙鹚鹛鹜鹝鹞鹟鹠鹡鹢鹣鹤鹥鹦鹧鹨鹩鹪鹫鹬鹭鹮鹯鹰鹱鹲鹳鹴鹵鹶鹷鹸鹹鹺鹻鹼鹽鹾鹿麀麁麂麃麄麅麆麇麈麉麊麋麌麍麎麏麐麑麒麓麔麕麖麗麘麙麚麛麜麝麞麟麠麡麢麣麤麥麦麧麨麩麪麫麬麭麮麯麰麱麲麳麴麵麶麷麸麹麺麻麼麽麾麿黀黁黂黃黄黅黆黇黈黉黊黋黌黍黎黏黐黑黒黓黔黕黖黗默黙黚黛黜黝點黟黠黡黢黣黤黥黦黧黨黩黪黫黬黭黮黯黰黱黲黳黴黵黶黷黸黹黺黻黼黽黾黿鼀鼁鼂鼃鼄鼅鼆鼇鼈鼉鼊鼋鼌鼍鼎鼏鼐鼑鼒鼓鼔鼕鼖鼗鼘鼙鼚鼛鼜鼝鼞鼟鼠鼡鼢鼣鼤鼥鼦鼧鼨鼩鼪鼫鼬鼭鼮鼯鼰鼱鼲鼳鼴鼵鼶鼷鼸鼹鼺鼻鼼鼽鼾鼿齀齁齂齃齄齅齆齇齈齉齊齋齌齍齎齏齐齑齒齓齔齕齖齗齘齙齚齛齜齝齞齟齠齡齢齣齤齥齦齧齨齩齪齫齬齭齮齯齰齱齲齳齴齵齶齷齸齹齺齻齼齽齾齿龀龁龂龃龄龅龆龇龈龉龊龋龌龍龎龏龐龑龒龓龔龕龖龗龘龙龚龛龜龝龞龟龠龡龢龣龤龥龦龧龨龩龪龫龬龭龮龯龰龱龲龳龴龵龶龷龸龹龺龻龼龽龾龿鿀鿁鿂鿃鿄鿅鿆鿇鿈鿉鿊鿋鿌ꀀꀁꀂꀃꀄꀅꀆꀇꀈꀉꀊꀋꀌꀍꀎꀏꀐꀑꀒꀓꀔꀕꀖꀗꀘꀙꀚꀛꀜꀝꀞꀟꀠꀡꀢꀣꀤꀥꀦꀧꀨꀩꀪꀫꀬꀭꀮꀯꀰꀱꀲꀳꀴꀵꀶꀷꀸꀹꀺꀻꀼꀽꀾꀿꁀꁁꁂꁃꁄꁅꁆꁇꁈꁉꁊꁋꁌꁍꁎꁏꁐꁑꁒꁓꁔꁕꁖꁗꁘꁙꁚꁛꁜꁝꁞꁟꁠꁡꁢꁣꁤꁥꁦꁧꁨꁩꁪꁫꁬꁭꁮꁯꁰꁱꁲꁳꁴꁵꁶꁷꁸꁹꁺꁻꁼꁽꁾꁿꂀꂁꂂꂃꂄꂅꂆꂇꂈꂉꂊꂋꂌꂍꂎꂏꂐꂑꂒꂓꂔꂕꂖꂗꂘꂙꂚꂛꂜꂝꂞꂟꂠꂡꂢꂣꂤꂥꂦꂧꂨꂩꂪꂫꂬꂭꂮꂯꂰꂱꂲꂳꂴꂵꂶꂷꂸꂹꂺꂻꂼꂽꂾꂿꃀꃁꃂꃃꃄꃅꃆꃇꃈꃉꃊꃋꃌꃍꃎꃏꃐꃑꃒꃓꃔꃕꃖꃗꃘꃙꃚꃛꃜꃝꃞꃟꃠꃡꃢꃣꃤꃥꃦꃧꃨꃩꃪꃫꃬꃭꃮꃯꃰꃱꃲꃳꃴꃵꃶꃷꃸꃹꃺꃻꃼꃽꃾꃿꄀꄁꄂꄃꄄꄅꄆꄇꄈꄉꄊꄋꄌꄍꄎꄏꄐꄑꄒꄓꄔꄕꄖꄗꄘꄙꄚꄛꄜꄝꄞꄟꄠꄡꄢꄣꄤꄥꄦꄧꄨꄩꄪꄫꄬꄭꄮꄯꄰꄱꄲꄳꄴꄵꄶꄷꄸꄹꄺꄻꄼꄽꄾꄿꅀꅁꅂꅃꅄꅅꅆꅇꅈꅉꅊꅋꅌꅍꅎꅏꅐꅑꅒꅓꅔꅕꅖꅗꅘꅙꅚꅛꅜꅝꅞꅟꅠꅡꅢꅣꅤꅥꅦꅧꅨꅩꅪꅫꅬꅭꅮꅯꅰꅱꅲꅳꅴꅵꅶꅷꅸꅹꅺꅻꅼꅽꅾꅿꆀꆁꆂꆃꆄꆅꆆꆇꆈꆉꆊꆋꆌꆍꆎꆏꆐꆑꆒꆓꆔꆕꆖꆗꆘꆙꆚꆛꆜꆝꆞꆟꆠꆡꆢꆣꆤꆥꆦꆧꆨꆩꆪꆫꆬꆭꆮꆯꆰꆱꆲꆳꆴꆵꆶꆷꆸꆹꆺꆻꆼꆽꆾꆿꇀꇁꇂꇃꇄꇅꇆꇇꇈꇉꇊꇋꇌꇍꇎꇏꇐꇑꇒꇓꇔꇕꇖꇗꇘꇙꇚꇛꇜꇝꇞꇟꇠꇡꇢꇣꇤꇥꇦꇧꇨꇩꇪꇫꇬꇭꇮꇯꇰꇱꇲꇳꇴꇵꇶꇷꇸꇹꇺꇻꇼꇽꇾꇿꈀꈁꈂꈃꈄꈅꈆꈇꈈꈉꈊꈋꈌꈍꈎꈏꈐꈑꈒꈓꈔꈕꈖꈗꈘꈙꈚꈛꈜꈝꈞꈟꈠꈡꈢꈣꈤꈥꈦꈧꈨꈩꈪꈫꈬꈭꈮꈯꈰꈱꈲꈳꈴꈵꈶꈷꈸꈹꈺꈻꈼꈽꈾꈿꉀꉁꉂꉃꉄꉅꉆꉇꉈꉉꉊꉋꉌꉍꉎꉏꉐꉑꉒꉓꉔꉕꉖꉗꉘꉙꉚꉛꉜꉝꉞꉟꉠꉡꉢꉣꉤꉥꉦꉧꉨꉩꉪꉫꉬꉭꉮꉯꉰꉱꉲꉳꉴꉵꉶꉷꉸꉹꉺꉻꉼꉽꉾꉿꊀꊁꊂꊃꊄꊅꊆꊇꊈꊉꊊꊋꊌꊍꊎꊏꊐꊑꊒꊓꊔꊕꊖꊗꊘꊙꊚꊛꊜꊝꊞꊟꊠꊡꊢꊣꊤꊥꊦꊧꊨꊩꊪꊫꊬꊭꊮꊯꊰꊱꊲꊳꊴꊵꊶꊷꊸꊹꊺꊻꊼꊽꊾꊿꋀꋁꋂꋃꋄꋅꋆꋇꋈꋉꋊꋋꋌꋍꋎꋏꋐꋑꋒꋓꋔꋕꋖꋗꋘꋙꋚꋛꋜꋝꋞꋟꋠꋡꋢꋣꋤꋥꋦꋧꋨꋩꋪꋫꋬꋭꋮꋯꋰꋱꋲꋳꋴꋵꋶꋷꋸꋹꋺꋻꋼꋽꋾꋿꌀꌁꌂꌃꌄꌅꌆꌇꌈꌉꌊꌋꌌꌍꌎꌏꌐꌑꌒꌓꌔꌕꌖꌗꌘꌙꌚꌛꌜꌝꌞꌟꌠꌡꌢꌣꌤꌥꌦꌧꌨꌩꌪꌫꌬꌭꌮꌯꌰꌱꌲꌳꌴꌵꌶꌷꌸꌹꌺꌻꌼꌽꌾꌿꍀꍁꍂꍃꍄꍅꍆꍇꍈꍉꍊꍋꍌꍍꍎꍏꍐꍑꍒꍓꍔꍕꍖꍗꍘꍙꍚꍛꍜꍝꍞꍟꍠꍡꍢꍣꍤꍥꍦꍧꍨꍩꍪꍫꍬꍭꍮꍯꍰꍱꍲꍳꍴꍵꍶꍷꍸꍹꍺꍻꍼꍽꍾꍿꎀꎁꎂꎃꎄꎅꎆꎇꎈꎉꎊꎋꎌꎍꎎꎏꎐꎑꎒꎓꎔꎕꎖꎗꎘꎙꎚꎛꎜꎝꎞꎟꎠꎡꎢꎣꎤꎥꎦꎧꎨꎩꎪꎫꎬꎭꎮꎯꎰꎱꎲꎳꎴꎵꎶꎷꎸꎹꎺꎻꎼꎽꎾꎿꏀꏁꏂꏃꏄꏅꏆꏇꏈꏉꏊꏋꏌꏍꏎꏏꏐꏑꏒꏓꏔꏕꏖꏗꏘꏙꏚꏛꏜꏝꏞꏟꏠꏡꏢꏣꏤꏥꏦꏧꏨꏩꏪꏫꏬꏭꏮꏯꏰꏱꏲꏳꏴꏵꏶꏷꏸꏹꏺꏻꏼꏽꏾꏿꐀꐁꐂꐃꐄꐅꐆꐇꐈꐉꐊꐋꐌꐍꐎꐏꐐꐑꐒꐓꐔꐕꐖꐗꐘꐙꐚꐛꐜꐝꐞꐟꐠꐡꐢꐣꐤꐥꐦꐧꐨꐩꐪꐫꐬꐭꐮꐯꐰꐱꐲꐳꐴꐵꐶꐷꐸꐹꐺꐻꐼꐽꐾꐿꑀꑁꑂꑃꑄꑅꑆꑇꑈꑉꑊꑋꑌꑍꑎꑏꑐꑑꑒꑓꑔꑕꑖꑗꑘꑙꑚꑛꑜꑝꑞꑟꑠꑡꑢꑣꑤꑥꑦꑧꑨꑩꑪꑫꑬꑭꑮꑯꑰꑱꑲꑳꑴꑵꑶꑷꑸꑹꑺꑻꑼꑽꑾꑿꒀꒁꒂꒃꒄꒅꒆꒇꒈꒉꒊꒋꒌ꒐꒑꒒꒓꒔꒕꒖꒗꒘꒙꒚꒛꒜꒝꒞꒟꒠꒡꒢꒣꒤꒥꒦꒧꒨꒩꒪꒫꒬꒭꒮꒯꒰꒱꒲꒳꒴꒵꒶꒷꒸꒹꒺꒻꒼꒽꒾꒿꓀꓁꓂꓃꓄꓅꓆ꓐꓑꓒꓓꓔꓕꓖꓗꓘꓙꓚꓛꓜꓝꓞꓟꓠꓡꓢꓣꓤꓥꓦꓧꓨꓩꓪꓫꓬꓭꓮꓯꓰꓱꓲꓳꓴꓵꓶꓷꓸꓹꓺꓻꓼꓽ꓾꓿ꔀꔁꔂꔃꔄꔅꔆꔇꔈꔉꔊꔋꔌꔍꔎꔏꔐꔑꔒꔓꔔꔕꔖꔗꔘꔙꔚꔛꔜꔝꔞꔟꔠꔡꔢꔣꔤꔥꔦꔧꔨꔩꔪꔫꔬꔭꔮꔯꔰꔱꔲꔳꔴꔵꔶꔷꔸꔹꔺꔻꔼꔽꔾꔿꕀꕁꕂꕃꕄꕅꕆꕇꕈꕉꕊꕋꕌꕍꕎꕏꕐꕑꕒꕓꕔꕕꕖꕗꕘꕙꕚꕛꕜꕝꕞꕟꕠꕡꕢꕣꕤꕥꕦꕧꕨꕩꕪꕫꕬꕭꕮꕯꕰꕱꕲꕳꕴꕵꕶꕷꕸꕹꕺꕻꕼꕽꕾꕿꖀꖁꖂꖃꖄꖅꖆꖇꖈꖉꖊꖋꖌꖍꖎꖏꖐꖑꖒꖓꖔꖕꖖꖗꖘꖙꖚꖛꖜꖝꖞꖟꖠꖡꖢꖣꖤꖥꖦꖧꖨꖩꖪꖫꖬꖭꖮꖯꖰꖱꖲꖳꖴꖵꖶꖷꖸꖹꖺꖻꖼꖽꖾꖿꗀꗁꗂꗃꗄꗅꗆꗇꗈꗉꗊꗋꗌꗍꗎꗏꗐꗑꗒꗓꗔꗕꗖꗗꗘꗙꗚꗛꗜꗝꗞꗟꗠꗡꗢꗣꗤꗥꗦꗧꗨꗩꗪꗫꗬꗭꗮꗯꗰꗱꗲꗳꗴꗵꗶꗷꗸꗹꗺꗻꗼꗽꗾꗿꘀꘁꘂꘃꘄꘅꘆꘇꘈꘉꘊꘋꘌ꘍꘎꘏ꘐꘑꘒꘓꘔꘕꘖꘗꘘꘙꘚꘛꘜꘝꘞꘟ꘠꘡꘢꘣꘤꘥꘦꘧꘨꘩ꘪꘫꙀꙁꙂꙃꙄꙅꙆꙇꙈꙉꙊꙋꙌꙍꙎꙏꙐꙑꙒꙓꙔꙕꙖꙗꙘꙙꙚꙛꙜꙝꙞꙟꙠꙡꙢꙣꙤꙥꙦꙧꙨꙩꙪꙫꙬꙭꙮ꙯꙰꙱꙲꙳ꙴꙵꙶꙷꙸꙹꙺꙻ꙼꙽꙾ꙿꚀꚁꚂꚃꚄꚅꚆꚇꚈꚉꚊꚋꚌꚍꚎꚏꚐꚑꚒꚓꚔꚕꚖꚗꚟꚠꚡꚢꚣꚤꚥꚦꚧꚨꚩꚪꚫꚬꚭꚮꚯꚰꚱꚲꚳꚴꚵꚶꚷꚸꚹꚺꚻꚼꚽꚾꚿꛀꛁꛂꛃꛄꛅꛆꛇꛈꛉꛊꛋꛌꛍꛎꛏꛐꛑꛒꛓꛔꛕꛖꛗꛘꛙꛚꛛꛜꛝꛞꛟꛠꛡꛢꛣꛤꛥꛦꛧꛨꛩꛪꛫꛬꛭꛮꛯ꛰꛱꛲꛳꛴꛵꛶꛷꜀꜁꜂꜃꜄꜅꜆꜇꜈꜉꜊꜋꜌꜍꜎꜏꜐꜑꜒꜓꜔꜕꜖ꜗꜘꜙꜚꜛꜜꜝꜞꜟ꜠꜡ꜢꜣꜤꜥꜦꜧꜨꜩꜪꜫꜬꜭꜮꜯꜰꜱꜲꜳꜴꜵꜶꜷꜸꜹꜺꜻꜼꜽꜾꜿꝀꝁꝂꝃꝄꝅꝆꝇꝈꝉꝊꝋꝌꝍꝎꝏꝐꝑꝒꝓꝔꝕꝖꝗꝘꝙꝚꝛꝜꝝꝞꝟꝠꝡꝢꝣꝤꝥꝦꝧꝨꝩꝪꝫꝬꝭꝮꝯꝰꝱꝲꝳꝴꝵꝶꝷꝸꝹꝺꝻꝼꝽꝾꝿꞀꞁꞂꞃꞄꞅꞆꞇꞈ꞉꞊ꞋꞌꞍꞎꞐꞑꞒꞓꞠꞡꞢꞣꞤꞥꞦꞧꞨꞩꞪꟸꟹꟺꟻꟼꟽꟾꟿꠀꠁꠂꠃꠄꠅ꠆ꠇꠈꠉꠊꠋꠌꠍꠎꠏꠐꠑꠒꠓꠔꠕꠖꠗꠘꠙꠚꠛꠜꠝꠞꠟꠠꠡꠢꠣꠤꠥꠦꠧ꠨꠩꠪꠫꠰꠱꠲꠳꠴꠵꠶꠷꠸꠹ꡀꡁꡂꡃꡄꡅꡆꡇꡈꡉꡊꡋꡌꡍꡎꡏꡐꡑꡒꡓꡔꡕꡖꡗꡘꡙꡚꡛꡜꡝꡞꡟꡠꡡꡢꡣꡤꡥꡦꡧꡨꡩꡪꡫꡬꡭꡮꡯꡰꡱꡲꡳ꡴꡵꡶꡷ꢀꢁꢂꢃꢄꢅꢆꢇꢈꢉꢊꢋꢌꢍꢎꢏꢐꢑꢒꢓꢔꢕꢖꢗꢘꢙꢚꢛꢜꢝꢞꢟꢠꢡꢢꢣꢤꢥꢦꢧꢨꢩꢪꢫꢬꢭꢮꢯꢰꢱꢲꢳꢴꢵꢶꢷꢸꢹꢺꢻꢼꢽꢾꢿꣀꣁꣂꣃ꣄꣎꣏꣐꣑꣒꣓꣔꣕꣖꣗꣘꣙꣠꣡꣢꣣꣤꣥꣦꣧꣨꣩꣪꣫꣬꣭꣮꣯꣰꣱ꣲꣳꣴꣵꣶꣷ꣸꣹꣺ꣻ꤀꤁꤂꤃꤄꤅꤆꤇꤈꤉ꤊꤋꤌꤍꤎꤏꤐꤑꤒꤓꤔꤕꤖꤗꤘꤙꤚꤛꤜꤝꤞꤟꤠꤡꤢꤣꤤꤥꤦꤧꤨꤩꤪ꤫꤬꤭꤮꤯ꤰꤱꤲꤳꤴꤵꤶꤷꤸꤹꤺꤻꤼꤽꤾꤿꥀꥁꥂꥃꥄꥅꥆꥇꥈꥉꥊꥋꥌꥍꥎꥏꥐꥑꥒ꥓꥟ꥠꥡꥢꥣꥤꥥꥦꥧꥨꥩꥪꥫꥬꥭꥮꥯꥰꥱꥲꥳꥴꥵꥶꥷꥸꥹꥺꥻꥼꦀꦁꦂꦃꦄꦅꦆꦇꦈꦉꦊꦋꦌꦍꦎꦏꦐꦑꦒꦓꦔꦕꦖꦗꦘꦙꦚꦛꦜꦝꦞꦟꦠꦡꦢꦣꦤꦥꦦꦧꦨꦩꦪꦫꦬꦭꦮꦯꦰꦱꦲ꦳ꦴꦵꦶꦷꦸꦹꦺꦻꦼꦽꦾꦿ꧀꧁꧂꧃꧄꧅꧆꧇꧈꧉꧊꧋꧌꧍ꧏ꧐꧑꧒꧓꧔꧕꧖꧗꧘꧙꧞꧟ꨀꨁꨂꨃꨄꨅꨆꨇꨈꨉꨊꨋꨌꨍꨎꨏꨐꨑꨒꨓꨔꨕꨖꨗꨘꨙꨚꨛꨜꨝꨞꨟꨠꨡꨢꨣꨤꨥꨦꨧꨨꨩꨪꨫꨬꨭꨮꨯꨰꨱꨲꨳꨴꨵꨶꩀꩁꩂꩃꩄꩅꩆꩇꩈꩉꩊꩋꩌꩍ꩐꩑꩒꩓꩔꩕꩖꩗꩘꩙꩜꩝꩞꩟ꩠꩡꩢꩣꩤꩥꩦꩧꩨꩩꩪꩫꩬꩭꩮꩯꩰꩱꩲꩳꩴꩵꩶ꩷꩸꩹ꩺꩻꪀꪁꪂꪃꪄꪅꪆꪇꪈꪉꪊꪋꪌꪍꪎꪏꪐꪑꪒꪓꪔꪕꪖꪗꪘꪙꪚꪛꪜꪝꪞꪟꪠꪡꪢꪣꪤꪥꪦꪧꪨꪩꪪꪫꪬꪭꪮꪯꪰꪱꪴꪲꪳꪵꪶꪷꪸꪹꪺꪻꪼꪽꪾ꪿ꫀ꫁ꫂꫛꫜꫝ꫞꫟ꫠꫡꫢꫣꫤꫥꫦꫧꫨꫩꫪꫫꫬꫭꫮꫯ꫰꫱ꫲꫳꫴꫵ꫶ꬁꬂꬃꬄꬅꬆꬉꬊꬋꬌꬍꬎꬑꬒꬓꬔꬕꬖꬠꬡꬢꬣꬤꬥꬦꬨꬩꬪꬫꬬꬭꬮꯀꯁꯂꯃꯄꯅꯆꯇꯈꯉꯊꯋꯌꯍꯎꯏꯐꯑꯒꯓꯔꯕꯖꯗꯘꯙꯚꯛꯜꯝꯞꯟꯠꯡꯢꯣꯤꯥꯦꯧꯨꯩꯪ꯫꯬꯭꯰꯱꯲꯳꯴꯵꯶꯷꯸꯹가각갂갃간갅갆갇갈갉갊갋갌갍갎갏감갑값갓갔강갖갗갘같갚갛개객갞갟갠갡갢갣갤갥갦갧갨갩갪갫갬갭갮갯갰갱갲갳갴갵갶갷갸갹갺갻갼갽갾갿걀걁걂걃걄걅걆걇걈걉걊걋걌걍걎걏걐걑걒걓걔걕걖걗걘걙걚걛걜걝걞걟걠걡걢걣걤걥걦걧걨걩걪걫걬걭걮걯거걱걲걳건걵걶걷걸걹걺걻걼걽걾걿검겁겂것겄겅겆겇겈겉겊겋게겍겎겏겐겑겒겓겔겕겖겗겘겙겚겛겜겝겞겟겠겡겢겣겤겥겦겧겨격겪겫견겭겮겯결겱겲겳겴겵겶겷겸겹겺겻겼경겾겿곀곁곂곃계곅곆곇곈곉곊곋곌곍곎곏곐곑곒곓곔곕곖곗곘곙곚곛곜곝곞곟고곡곢곣곤곥곦곧골곩곪곫곬곭곮곯곰곱곲곳곴공곶곷곸곹곺곻과곽곾곿관괁괂괃괄괅괆괇괈괉괊괋괌괍괎괏괐광괒괓괔괕괖괗괘괙괚괛괜괝괞괟괠괡괢괣괤괥괦괧괨괩괪괫괬괭괮괯괰괱괲괳괴괵괶괷괸괹괺괻괼괽괾괿굀굁굂굃굄굅굆굇굈굉굊굋굌굍굎굏교굑굒굓굔굕굖굗굘굙굚굛굜굝굞굟굠굡굢굣굤굥굦굧굨굩굪굫구국굮굯군굱굲굳굴굵굶굷굸굹굺굻굼굽굾굿궀궁궂궃궄궅궆궇궈궉궊궋권궍궎궏궐궑궒궓궔궕궖궗궘궙궚궛궜궝궞궟궠궡궢궣궤궥궦궧궨궩궪궫궬궭궮궯궰궱궲궳궴궵궶궷궸궹궺궻궼궽궾궿귀귁귂귃귄귅귆귇귈귉귊귋귌귍귎귏귐귑귒귓귔귕귖귗귘귙귚귛규귝귞귟균귡귢귣귤귥귦귧귨귩귪귫귬귭귮귯귰귱귲귳귴귵귶귷그극귺귻근귽귾귿글긁긂긃긄긅긆긇금급긊긋긌긍긎긏긐긑긒긓긔긕긖긗긘긙긚긛긜긝긞긟긠긡긢긣긤긥긦긧긨긩긪긫긬긭긮긯기긱긲긳긴긵긶긷길긹긺긻긼긽긾긿김깁깂깃깄깅깆깇깈깉깊깋까깍깎깏깐깑깒깓깔깕깖깗깘깙깚깛깜깝깞깟깠깡깢깣깤깥깦깧깨깩깪깫깬깭깮깯깰깱깲깳깴깵깶깷깸깹깺깻깼깽깾깿꺀꺁꺂꺃꺄꺅꺆꺇꺈꺉꺊꺋꺌꺍꺎꺏꺐꺑꺒꺓꺔꺕꺖꺗꺘꺙꺚꺛꺜꺝꺞꺟꺠꺡꺢꺣꺤꺥꺦꺧꺨꺩꺪꺫꺬꺭꺮꺯꺰꺱꺲꺳꺴꺵꺶꺷꺸꺹꺺꺻꺼꺽꺾꺿껀껁껂껃껄껅껆껇껈껉껊껋껌껍껎껏껐껑껒껓껔껕껖껗께껙껚껛껜껝껞껟껠껡껢껣껤껥껦껧껨껩껪껫껬껭껮껯껰껱껲껳껴껵껶껷껸껹껺껻껼껽껾껿꼀꼁꼂꼃꼄꼅꼆꼇꼈꼉꼊꼋꼌꼍꼎꼏꼐꼑꼒꼓꼔꼕꼖꼗꼘꼙꼚꼛꼜꼝꼞꼟꼠꼡꼢꼣꼤꼥꼦꼧꼨꼩꼪꼫꼬꼭꼮꼯꼰꼱꼲꼳꼴꼵꼶꼷꼸꼹꼺꼻꼼꼽꼾꼿꽀꽁꽂꽃꽄꽅꽆꽇꽈꽉꽊꽋꽌꽍꽎꽏꽐꽑꽒꽓꽔꽕꽖꽗꽘꽙꽚꽛꽜꽝꽞꽟꽠꽡꽢꽣꽤꽥꽦꽧꽨꽩꽪꽫꽬꽭꽮꽯꽰꽱꽲꽳꽴꽵꽶꽷꽸꽹꽺꽻꽼꽽꽾꽿꾀꾁꾂꾃꾄꾅꾆꾇꾈꾉꾊꾋꾌꾍꾎꾏꾐꾑꾒꾓꾔꾕꾖꾗꾘꾙꾚꾛꾜꾝꾞꾟꾠꾡꾢꾣꾤꾥꾦꾧꾨꾩꾪꾫꾬꾭꾮꾯꾰꾱꾲꾳꾴꾵꾶꾷꾸꾹꾺꾻꾼꾽꾾꾿꿀꿁꿂꿃꿄꿅꿆꿇꿈꿉꿊꿋꿌꿍꿎꿏꿐꿑꿒꿓꿔꿕꿖꿗꿘꿙꿚꿛꿜꿝꿞꿟꿠꿡꿢꿣꿤꿥꿦꿧꿨꿩꿪꿫꿬꿭꿮꿯꿰꿱꿲꿳꿴꿵꿶꿷꿸꿹꿺꿻꿼꿽꿾꿿뀀뀁뀂뀃뀄뀅뀆뀇뀈뀉뀊뀋뀌뀍뀎뀏뀐뀑뀒뀓뀔뀕뀖뀗뀘뀙뀚뀛뀜뀝뀞뀟뀠뀡뀢뀣뀤뀥뀦뀧뀨뀩뀪뀫뀬뀭뀮뀯뀰뀱뀲뀳뀴뀵뀶뀷뀸뀹뀺뀻뀼뀽뀾뀿끀끁끂끃끄끅끆끇끈끉끊끋끌끍끎끏끐끑끒끓끔끕끖끗끘끙끚끛끜끝끞끟끠끡끢끣끤끥끦끧끨끩끪끫끬끭끮끯끰끱끲끳끴끵끶끷끸끹끺끻끼끽끾끿낀낁낂낃낄낅낆낇낈낉낊낋낌낍낎낏낐낑낒낓낔낕낖낗나낙낚낛난낝낞낟날낡낢낣낤낥낦낧남납낪낫났낭낮낯낰낱낲낳내낵낶낷낸낹낺낻낼낽낾낿냀냁냂냃냄냅냆냇냈냉냊냋냌냍냎냏냐냑냒냓냔냕냖냗냘냙냚냛냜냝냞냟냠냡냢냣냤냥냦냧냨냩냪냫냬냭냮냯냰냱냲냳냴냵냶냷냸냹냺냻냼냽냾냿넀넁넂넃넄넅넆넇너넉넊넋넌넍넎넏널넑넒넓넔넕넖넗넘넙넚넛넜넝넞넟넠넡넢넣네넥넦넧넨넩넪넫넬넭넮넯넰넱넲넳넴넵넶넷넸넹넺넻넼넽넾넿녀녁녂녃년녅녆녇녈녉녊녋녌녍녎녏념녑녒녓녔녕녖녗녘녙녚녛녜녝녞녟녠녡녢녣녤녥녦녧녨녩녪녫녬녭녮녯녰녱녲녳녴녵녶녷노녹녺녻논녽녾녿놀놁놂놃놄놅놆놇놈놉놊놋놌농놎놏놐놑높놓놔놕놖놗놘놙놚놛놜놝놞놟놠놡놢놣놤놥놦놧놨놩놪놫놬놭놮놯놰놱놲놳놴놵놶놷놸놹놺놻놼놽놾놿뇀뇁뇂뇃뇄뇅뇆뇇뇈뇉뇊뇋뇌뇍뇎뇏뇐뇑뇒뇓뇔뇕뇖뇗뇘뇙뇚뇛뇜뇝뇞뇟뇠뇡뇢뇣뇤뇥뇦뇧뇨뇩뇪뇫뇬뇭뇮뇯뇰뇱뇲뇳뇴뇵뇶뇷뇸뇹뇺뇻뇼뇽뇾뇿눀눁눂눃누눅눆눇눈눉눊눋눌눍눎눏눐눑눒눓눔눕눖눗눘눙눚눛눜눝눞눟눠눡눢눣눤눥눦눧눨눩눪눫눬눭눮눯눰눱눲눳눴눵눶눷눸눹눺눻눼눽눾눿뉀뉁뉂뉃뉄뉅뉆뉇뉈뉉뉊뉋뉌뉍뉎뉏뉐뉑뉒뉓뉔뉕뉖뉗뉘뉙뉚뉛뉜뉝뉞뉟뉠뉡뉢뉣뉤뉥뉦뉧뉨뉩뉪뉫뉬뉭뉮뉯뉰뉱뉲뉳뉴뉵뉶뉷뉸뉹뉺뉻뉼뉽뉾뉿늀늁늂늃늄늅늆늇늈늉늊늋늌늍늎늏느늑늒늓는늕늖늗늘늙늚늛늜늝늞늟늠늡늢늣늤능늦늧늨늩늪늫늬늭늮늯늰늱늲늳늴늵늶늷늸늹늺늻늼늽늾늿닀닁닂닃닄닅닆닇니닉닊닋닌닍닎닏닐닑닒닓닔닕닖닗님닙닚닛닜닝닞닟닠닡닢닣다닥닦닧단닩닪닫달닭닮닯닰닱닲닳담답닶닷닸당닺닻닼닽닾닿대댁댂댃댄댅댆댇댈댉댊댋댌댍댎댏댐댑댒댓댔댕댖댗댘댙댚댛댜댝댞댟댠댡댢댣댤댥댦댧댨댩댪댫댬댭댮댯댰댱댲댳댴댵댶댷댸댹댺댻댼댽댾댿덀덁덂덃덄덅덆덇덈덉덊덋덌덍덎덏덐덑덒덓더덕덖덗던덙덚덛덜덝덞덟덠덡덢덣덤덥덦덧덨덩덪덫덬덭덮덯데덱덲덳덴덵덶덷델덹덺덻덼덽덾덿뎀뎁뎂뎃뎄뎅뎆뎇뎈뎉뎊뎋뎌뎍뎎뎏뎐뎑뎒뎓뎔뎕뎖뎗뎘뎙뎚뎛뎜뎝뎞뎟뎠뎡뎢뎣뎤뎥뎦뎧뎨뎩뎪뎫뎬뎭뎮뎯뎰뎱뎲뎳뎴뎵뎶뎷뎸뎹뎺뎻뎼뎽뎾뎿돀돁돂돃도독돆돇돈돉돊돋돌돍돎돏돐돑돒돓돔돕돖돗돘동돚돛돜돝돞돟돠돡돢돣돤돥돦돧돨돩돪돫돬돭돮돯돰돱돲돳돴돵돶돷돸돹돺돻돼돽돾돿됀됁됂됃됄됅됆됇됈됉됊됋됌됍됎됏됐됑됒됓됔됕됖됗되됙됚됛된됝됞됟될됡됢됣됤됥됦됧됨됩됪됫됬됭됮됯됰됱됲됳됴됵됶됷됸됹됺됻됼됽됾됿둀둁둂둃둄둅둆둇둈둉둊둋둌둍둎둏두둑둒둓둔둕둖둗둘둙둚둛둜둝둞둟둠둡둢둣둤둥둦둧둨둩둪둫둬둭둮둯둰둱둲둳둴둵둶둷둸둹둺둻둼둽둾둿뒀뒁뒂뒃뒄뒅뒆뒇뒈뒉뒊뒋뒌뒍뒎뒏뒐뒑뒒뒓뒔뒕뒖뒗뒘뒙뒚뒛뒜뒝뒞뒟뒠뒡뒢뒣뒤뒥뒦뒧뒨뒩뒪뒫뒬뒭뒮뒯뒰뒱뒲뒳뒴뒵뒶뒷뒸뒹뒺뒻뒼뒽뒾뒿듀듁듂듃듄듅듆듇듈듉듊듋듌듍듎듏듐듑듒듓듔듕듖듗듘듙듚듛드득듞듟든듡듢듣들듥듦듧듨듩듪듫듬듭듮듯듰등듲듳듴듵듶듷듸듹듺듻듼듽듾듿딀딁딂딃딄딅딆딇딈딉딊딋딌딍딎딏딐딑딒딓디딕딖딗딘딙딚딛딜딝딞딟딠딡딢딣딤딥딦딧딨딩딪딫딬딭딮딯따딱딲딳딴딵딶딷딸딹딺딻딼딽딾딿땀땁땂땃땄땅땆땇땈땉땊땋때땍땎땏땐땑땒땓땔땕땖땗땘땙땚땛땜땝땞땟땠땡땢땣땤땥땦땧땨땩땪땫땬땭땮땯땰땱땲땳땴땵땶땷땸땹땺땻땼땽땾땿떀떁떂떃떄떅떆떇떈떉떊떋떌떍떎떏떐떑떒떓떔떕떖떗떘떙떚떛떜떝떞떟떠떡떢떣떤떥떦떧떨떩떪떫떬떭떮떯떰떱떲떳떴떵떶떷떸떹떺떻떼떽떾떿뗀뗁뗂뗃뗄뗅뗆뗇뗈뗉뗊뗋뗌뗍뗎뗏뗐뗑뗒뗓뗔뗕뗖뗗뗘뗙뗚뗛뗜뗝뗞뗟뗠뗡뗢뗣뗤뗥뗦뗧뗨뗩뗪뗫뗬뗭뗮뗯뗰뗱뗲뗳뗴뗵뗶뗷뗸뗹뗺뗻뗼뗽뗾뗿똀똁똂똃똄똅똆똇똈똉똊똋똌똍똎똏또똑똒똓똔똕똖똗똘똙똚똛똜똝똞똟똠똡똢똣똤똥똦똧똨똩똪똫똬똭똮똯똰똱똲똳똴똵똶똷똸똹똺똻똼똽똾똿뙀뙁뙂뙃뙄뙅뙆뙇뙈뙉뙊뙋뙌뙍뙎뙏뙐뙑뙒뙓뙔뙕뙖뙗뙘뙙뙚뙛뙜뙝뙞뙟뙠뙡뙢뙣뙤뙥뙦뙧뙨뙩뙪뙫뙬뙭뙮뙯뙰뙱뙲뙳뙴뙵뙶뙷뙸뙹뙺뙻뙼뙽뙾뙿뚀뚁뚂뚃뚄뚅뚆뚇뚈뚉뚊뚋뚌뚍뚎뚏뚐뚑뚒뚓뚔뚕뚖뚗뚘뚙뚚뚛뚜뚝뚞뚟뚠뚡뚢뚣뚤뚥뚦뚧뚨뚩뚪뚫뚬뚭뚮뚯뚰뚱뚲뚳뚴뚵뚶뚷뚸뚹뚺뚻뚼뚽뚾뚿뛀뛁뛂뛃뛄뛅뛆뛇뛈뛉뛊뛋뛌뛍뛎뛏뛐뛑뛒뛓뛔뛕뛖뛗뛘뛙뛚뛛뛜뛝뛞뛟뛠뛡뛢뛣뛤뛥뛦뛧뛨뛩뛪뛫뛬뛭뛮뛯뛰뛱뛲뛳뛴뛵뛶뛷뛸뛹뛺뛻뛼뛽뛾뛿뜀뜁뜂뜃뜄뜅뜆뜇뜈뜉뜊뜋뜌뜍뜎뜏뜐뜑뜒뜓뜔뜕뜖뜗뜘뜙뜚뜛뜜뜝뜞뜟뜠뜡뜢뜣뜤뜥뜦뜧뜨뜩뜪뜫뜬뜭뜮뜯뜰뜱뜲뜳뜴뜵뜶뜷뜸뜹뜺뜻뜼뜽뜾뜿띀띁띂띃띄띅띆띇띈띉띊띋띌띍띎띏띐띑띒띓띔띕띖띗띘띙띚띛띜띝띞띟띠띡띢띣띤띥띦띧띨띩띪띫띬띭띮띯띰띱띲띳띴띵띶띷띸띹띺띻라락띾띿란랁랂랃랄랅랆랇랈랉랊랋람랍랎랏랐랑랒랓랔랕랖랗래랙랚랛랜랝랞랟랠랡랢랣랤랥랦랧램랩랪랫랬랭랮랯랰랱랲랳랴략랶랷랸랹랺랻랼랽랾랿럀럁럂럃럄럅럆럇럈량럊럋럌럍럎럏럐럑럒럓럔럕럖럗럘럙럚럛럜럝럞럟럠럡럢럣럤럥럦럧럨럩럪럫러럭럮럯런럱럲럳럴럵럶럷럸럹럺럻럼럽럾럿렀렁렂렃렄렅렆렇레렉렊렋렌렍렎렏렐렑렒렓렔렕렖렗렘렙렚렛렜렝렞렟렠렡렢렣려력렦렧련렩렪렫렬렭렮렯렰렱렲렳렴렵렶렷렸령렺렻렼렽렾렿례롁롂롃롄롅롆롇롈롉롊롋롌롍롎롏롐롑롒롓롔롕롖롗롘롙롚롛로록롞롟론롡롢롣롤롥롦롧롨롩롪롫롬롭롮롯롰롱롲롳롴롵롶롷롸롹롺롻롼롽롾롿뢀뢁뢂뢃뢄뢅뢆뢇뢈뢉뢊뢋뢌뢍뢎뢏뢐뢑뢒뢓뢔뢕뢖뢗뢘뢙뢚뢛뢜뢝뢞뢟뢠뢡뢢뢣뢤뢥뢦뢧뢨뢩뢪뢫뢬뢭뢮뢯뢰뢱뢲뢳뢴뢵뢶뢷뢸뢹뢺뢻뢼뢽뢾뢿룀룁룂룃룄룅룆룇룈룉룊룋료룍룎룏룐룑룒룓룔룕룖룗룘룙룚룛룜룝룞룟룠룡룢룣룤룥룦룧루룩룪룫룬룭룮룯룰룱룲룳룴룵룶룷룸룹룺룻룼룽룾룿뤀뤁뤂뤃뤄뤅뤆뤇뤈뤉뤊뤋뤌뤍뤎뤏뤐뤑뤒뤓뤔뤕뤖뤗뤘뤙뤚뤛뤜뤝뤞뤟뤠뤡뤢뤣뤤뤥뤦뤧뤨뤩뤪뤫뤬뤭뤮뤯뤰뤱뤲뤳뤴뤵뤶뤷뤸뤹뤺뤻뤼뤽뤾뤿륀륁륂륃륄륅륆륇륈륉륊륋륌륍륎륏륐륑륒륓륔륕륖륗류륙륚륛륜륝륞륟률륡륢륣륤륥륦륧륨륩륪륫륬륭륮륯륰륱륲륳르륵륶륷른륹륺륻를륽륾륿릀릁릂릃름릅릆릇릈릉릊릋릌릍릎릏릐릑릒릓릔릕릖릗릘릙릚릛릜릝릞릟릠릡릢릣릤릥릦릧릨릩릪릫리릭릮릯린릱릲릳릴릵릶릷릸릹릺릻림립릾릿맀링맂맃맄맅맆맇마막맊맋만맍많맏말맑맒맓맔맕맖맗맘맙맚맛맜망맞맟맠맡맢맣매맥맦맧맨맩맪맫맬맭맮맯맰맱맲맳맴맵맶맷맸맹맺맻맼맽맾맿먀먁먂먃먄먅먆먇먈먉먊먋먌먍먎먏먐먑먒먓먔먕먖먗먘먙먚먛먜먝먞먟먠먡먢먣먤먥먦먧먨먩먪먫먬먭먮먯먰먱먲먳먴먵먶먷머먹먺먻먼먽먾먿멀멁멂멃멄멅멆멇멈멉멊멋멌멍멎멏멐멑멒멓메멕멖멗멘멙멚멛멜멝멞멟멠멡멢멣멤멥멦멧멨멩멪멫멬멭멮멯며멱멲멳면멵멶멷멸멹멺멻멼멽멾멿몀몁몂몃몄명몆몇몈몉몊몋몌몍몎몏몐몑몒몓몔몕몖몗몘몙몚몛몜몝몞몟몠몡몢몣몤몥몦몧모목몪몫몬몭몮몯몰몱몲몳몴몵몶몷몸몹몺못몼몽몾몿뫀뫁뫂뫃뫄뫅뫆뫇뫈뫉뫊뫋뫌뫍뫎뫏뫐뫑뫒뫓뫔뫕뫖뫗뫘뫙뫚뫛뫜뫝뫞뫟뫠뫡뫢뫣뫤뫥뫦뫧뫨뫩뫪뫫뫬뫭뫮뫯뫰뫱뫲뫳뫴뫵뫶뫷뫸뫹뫺뫻뫼뫽뫾뫿묀묁묂묃묄묅묆묇묈묉묊묋묌묍묎묏묐묑묒묓묔묕묖묗묘묙묚묛묜묝묞묟묠묡묢묣묤묥묦묧묨묩묪묫묬묭묮묯묰묱묲묳무묵묶묷문묹묺묻물묽묾묿뭀뭁뭂뭃뭄뭅뭆뭇뭈뭉뭊뭋뭌뭍뭎뭏뭐뭑뭒뭓뭔뭕뭖뭗뭘뭙뭚뭛뭜뭝뭞뭟뭠뭡뭢뭣뭤뭥뭦뭧뭨뭩뭪뭫뭬뭭뭮뭯뭰뭱뭲뭳뭴뭵뭶뭷뭸뭹뭺뭻뭼뭽뭾뭿뮀뮁뮂뮃뮄뮅뮆뮇뮈뮉뮊뮋뮌뮍뮎뮏뮐뮑뮒뮓뮔뮕뮖뮗뮘뮙뮚뮛뮜뮝뮞뮟뮠뮡뮢뮣뮤뮥뮦뮧뮨뮩뮪뮫뮬뮭뮮뮯뮰뮱뮲뮳뮴뮵뮶뮷뮸뮹뮺뮻뮼뮽뮾뮿므믁믂믃믄믅믆믇믈믉믊믋믌믍믎믏믐믑믒믓믔믕믖믗믘믙믚믛믜믝믞믟믠믡믢믣믤믥믦믧믨믩믪믫믬믭믮믯믰믱믲믳믴믵믶믷미믹믺믻민믽믾믿밀밁밂밃밄밅밆밇밈밉밊밋밌밍밎및밐밑밒밓바박밖밗반밙밚받발밝밞밟밠밡밢밣밤밥밦밧밨방밪밫밬밭밮밯배백밲밳밴밵밶밷밸밹밺밻밼밽밾밿뱀뱁뱂뱃뱄뱅뱆뱇뱈뱉뱊뱋뱌뱍뱎뱏뱐뱑뱒뱓뱔뱕뱖뱗뱘뱙뱚뱛뱜뱝뱞뱟뱠뱡뱢뱣뱤뱥뱦뱧뱨뱩뱪뱫뱬뱭뱮뱯뱰뱱뱲뱳뱴뱵뱶뱷뱸뱹뱺뱻뱼뱽뱾뱿벀벁벂벃버벅벆벇번벉벊벋벌벍벎벏벐벑벒벓범법벖벗벘벙벚벛벜벝벞벟베벡벢벣벤벥벦벧벨벩벪벫벬벭벮벯벰벱벲벳벴벵벶벷벸벹벺벻벼벽벾벿변볁볂볃별볅볆볇볈볉볊볋볌볍볎볏볐병볒볓볔볕볖볗볘볙볚볛볜볝볞볟볠볡볢볣볤볥볦볧볨볩볪볫볬볭볮볯볰볱볲볳보복볶볷본볹볺볻볼볽볾볿봀봁봂봃봄봅봆봇봈봉봊봋봌봍봎봏봐봑봒봓봔봕봖봗봘봙봚봛봜봝봞봟봠봡봢봣봤봥봦봧봨봩봪봫봬봭봮봯봰봱봲봳봴봵봶봷봸봹봺봻봼봽봾봿뵀뵁뵂뵃뵄뵅뵆뵇뵈뵉뵊뵋뵌뵍뵎뵏뵐뵑뵒뵓뵔뵕뵖뵗뵘뵙뵚뵛뵜뵝뵞뵟뵠뵡뵢뵣뵤뵥뵦뵧뵨뵩뵪뵫뵬뵭뵮뵯뵰뵱뵲뵳뵴뵵뵶뵷뵸뵹뵺뵻뵼뵽뵾뵿부북붂붃분붅붆붇불붉붊붋붌붍붎붏붐붑붒붓붔붕붖붗붘붙붚붛붜붝붞붟붠붡붢붣붤붥붦붧붨붩붪붫붬붭붮붯붰붱붲붳붴붵붶붷붸붹붺붻붼붽붾붿뷀뷁뷂뷃뷄뷅뷆뷇뷈뷉뷊뷋뷌뷍뷎뷏뷐뷑뷒뷓뷔뷕뷖뷗뷘뷙뷚뷛뷜뷝뷞뷟뷠뷡뷢뷣뷤뷥뷦뷧뷨뷩뷪뷫뷬뷭뷮뷯뷰뷱뷲뷳뷴뷵뷶뷷뷸뷹뷺뷻뷼뷽뷾뷿븀븁븂븃븄븅븆븇븈븉븊븋브븍븎븏븐븑븒븓블븕븖븗븘븙븚븛븜븝븞븟븠븡븢븣븤븥븦븧븨븩븪븫븬븭븮븯븰븱븲븳븴븵븶븷븸븹븺븻븼븽븾븿빀빁빂빃비빅빆빇빈빉빊빋빌빍빎빏빐빑빒빓빔빕빖빗빘빙빚빛빜빝빞빟빠빡빢빣빤빥빦빧빨빩빪빫빬빭빮빯빰빱빲빳빴빵빶빷빸빹빺빻빼빽빾빿뺀뺁뺂뺃뺄뺅뺆뺇뺈뺉뺊뺋뺌뺍뺎뺏뺐뺑뺒뺓뺔뺕뺖뺗뺘뺙뺚뺛뺜뺝뺞뺟뺠뺡뺢뺣뺤뺥뺦뺧뺨뺩뺪뺫뺬뺭뺮뺯뺰뺱뺲뺳뺴뺵뺶뺷뺸뺹뺺뺻뺼뺽뺾뺿뻀뻁뻂뻃뻄뻅뻆뻇뻈뻉뻊뻋뻌뻍뻎뻏뻐뻑뻒뻓뻔뻕뻖뻗뻘뻙뻚뻛뻜뻝뻞뻟뻠뻡뻢뻣뻤뻥뻦뻧뻨뻩뻪뻫뻬뻭뻮뻯뻰뻱뻲뻳뻴뻵뻶뻷뻸뻹뻺뻻뻼뻽뻾뻿뼀뼁뼂뼃뼄뼅뼆뼇뼈뼉뼊뼋뼌뼍뼎뼏뼐뼑뼒뼓뼔뼕뼖뼗뼘뼙뼚뼛뼜뼝뼞뼟뼠뼡뼢뼣뼤뼥뼦뼧뼨뼩뼪뼫뼬뼭뼮뼯뼰뼱뼲뼳뼴뼵뼶뼷뼸뼹뼺뼻뼼뼽뼾뼿뽀뽁뽂뽃뽄뽅뽆뽇뽈뽉뽊뽋뽌뽍뽎뽏뽐뽑뽒뽓뽔뽕뽖뽗뽘뽙뽚뽛뽜뽝뽞뽟뽠뽡뽢뽣뽤뽥뽦뽧뽨뽩뽪뽫뽬뽭뽮뽯뽰뽱뽲뽳뽴뽵뽶뽷뽸뽹뽺뽻뽼뽽뽾뽿뾀뾁뾂뾃뾄뾅뾆뾇뾈뾉뾊뾋뾌뾍뾎뾏뾐뾑뾒뾓뾔뾕뾖뾗뾘뾙뾚뾛뾜뾝뾞뾟뾠뾡뾢뾣뾤뾥뾦뾧뾨뾩뾪뾫뾬뾭뾮뾯뾰뾱뾲뾳뾴뾵뾶뾷뾸뾹뾺뾻뾼뾽뾾뾿뿀뿁뿂뿃뿄뿅뿆뿇뿈뿉뿊뿋뿌뿍뿎뿏뿐뿑뿒뿓뿔뿕뿖뿗뿘뿙뿚뿛뿜뿝뿞뿟뿠뿡뿢뿣뿤뿥뿦뿧뿨뿩뿪뿫뿬뿭뿮뿯뿰뿱뿲뿳뿴뿵뿶뿷뿸뿹뿺뿻뿼뿽뿾뿿쀀쀁쀂쀃쀄쀅쀆쀇쀈쀉쀊쀋쀌쀍쀎쀏쀐쀑쀒쀓쀔쀕쀖쀗쀘쀙쀚쀛쀜쀝쀞쀟쀠쀡쀢쀣쀤쀥쀦쀧쀨쀩쀪쀫쀬쀭쀮쀯쀰쀱쀲쀳쀴쀵쀶쀷쀸쀹쀺쀻쀼쀽쀾쀿쁀쁁쁂쁃쁄쁅쁆쁇쁈쁉쁊쁋쁌쁍쁎쁏쁐쁑쁒쁓쁔쁕쁖쁗쁘쁙쁚쁛쁜쁝쁞쁟쁠쁡쁢쁣쁤쁥쁦쁧쁨쁩쁪쁫쁬쁭쁮쁯쁰쁱쁲쁳쁴쁵쁶쁷쁸쁹쁺쁻쁼쁽쁾쁿삀삁삂삃삄삅삆삇삈삉삊삋삌삍삎삏삐삑삒삓삔삕삖삗삘삙삚삛삜삝삞삟삠삡삢삣삤삥삦삧삨삩삪삫사삭삮삯산삱삲삳살삵삶삷삸삹삺삻삼삽삾삿샀상샂샃샄샅샆샇새색샊샋샌샍샎샏샐샑샒샓샔샕샖샗샘샙샚샛샜생샞샟샠샡샢샣샤샥샦샧샨샩샪샫샬샭샮샯샰샱샲샳샴샵샶샷샸샹샺샻샼샽샾샿섀섁섂섃섄섅섆섇섈섉섊섋섌섍섎섏섐섑섒섓섔섕섖섗섘섙섚섛서석섞섟선섡섢섣설섥섦섧섨섩섪섫섬섭섮섯섰성섲섳섴섵섶섷세섹섺섻센섽섾섿셀셁셂셃셄셅셆셇셈셉셊셋셌셍셎셏셐셑셒셓셔셕셖셗션셙셚셛셜셝셞셟셠셡셢셣셤셥셦셧셨셩셪셫셬셭셮셯셰셱셲셳셴셵셶셷셸셹셺셻셼셽셾셿솀솁솂솃솄솅솆솇솈솉솊솋소속솎솏손솑솒솓솔솕솖솗솘솙솚솛솜솝솞솟솠송솢솣솤솥솦솧솨솩솪솫솬솭솮솯솰솱솲솳솴솵솶솷솸솹솺솻솼솽솾솿쇀쇁쇂쇃쇄쇅쇆쇇쇈쇉쇊쇋쇌쇍쇎쇏쇐쇑쇒쇓쇔쇕쇖쇗쇘쇙쇚쇛쇜쇝쇞쇟쇠쇡쇢쇣쇤쇥쇦쇧쇨쇩쇪쇫쇬쇭쇮쇯쇰쇱쇲쇳쇴쇵쇶쇷쇸쇹쇺쇻쇼쇽쇾쇿숀숁숂숃숄숅숆숇숈숉숊숋숌숍숎숏숐숑숒숓숔숕숖숗수숙숚숛순숝숞숟술숡숢숣숤숥숦숧숨숩숪숫숬숭숮숯숰숱숲숳숴숵숶숷숸숹숺숻숼숽숾숿쉀쉁쉂쉃쉄쉅쉆쉇쉈쉉쉊쉋쉌쉍쉎쉏쉐쉑쉒쉓쉔쉕쉖쉗쉘쉙쉚쉛쉜쉝쉞쉟쉠쉡쉢쉣쉤쉥쉦쉧쉨쉩쉪쉫쉬쉭쉮쉯쉰쉱쉲쉳쉴쉵쉶쉷쉸쉹쉺쉻쉼쉽쉾쉿슀슁슂슃슄슅슆슇슈슉슊슋슌슍슎슏슐슑슒슓슔슕슖슗슘슙슚슛슜슝슞슟슠슡슢슣스슥슦슧슨슩슪슫슬슭슮슯슰슱슲슳슴습슶슷슸승슺슻슼슽슾슿싀싁싂싃싄싅싆싇싈싉싊싋싌싍싎싏싐싑싒싓싔싕싖싗싘싙싚싛시식싞싟신싡싢싣실싥싦싧싨싩싪싫심십싮싯싰싱싲싳싴싵싶싷싸싹싺싻싼싽싾싿쌀쌁쌂쌃쌄쌅쌆쌇쌈쌉쌊쌋쌌쌍쌎쌏쌐쌑쌒쌓쌔쌕쌖쌗쌘쌙쌚쌛쌜쌝쌞쌟쌠쌡쌢쌣쌤쌥쌦쌧쌨쌩쌪쌫쌬쌭쌮쌯쌰쌱쌲쌳쌴쌵쌶쌷쌸쌹쌺쌻쌼쌽쌾쌿썀썁썂썃썄썅썆썇썈썉썊썋썌썍썎썏썐썑썒썓썔썕썖썗썘썙썚썛썜썝썞썟썠썡썢썣썤썥썦썧써썩썪썫썬썭썮썯썰썱썲썳썴썵썶썷썸썹썺썻썼썽썾썿쎀쎁쎂쎃쎄쎅쎆쎇쎈쎉쎊쎋쎌쎍쎎쎏쎐쎑쎒쎓쎔쎕쎖쎗쎘쎙쎚쎛쎜쎝쎞쎟쎠쎡쎢쎣쎤쎥쎦쎧쎨쎩쎪쎫쎬쎭쎮쎯쎰쎱쎲쎳쎴쎵쎶쎷쎸쎹쎺쎻쎼쎽쎾쎿쏀쏁쏂쏃쏄쏅쏆쏇쏈쏉쏊쏋쏌쏍쏎쏏쏐쏑쏒쏓쏔쏕쏖쏗쏘쏙쏚쏛쏜쏝쏞쏟쏠쏡쏢쏣쏤쏥쏦쏧쏨쏩쏪쏫쏬쏭쏮쏯쏰쏱쏲쏳쏴쏵쏶쏷쏸쏹쏺쏻쏼쏽쏾쏿쐀쐁쐂쐃쐄쐅쐆쐇쐈쐉쐊쐋쐌쐍쐎쐏쐐쐑쐒쐓쐔쐕쐖쐗쐘쐙쐚쐛쐜쐝쐞쐟쐠쐡쐢쐣쐤쐥쐦쐧쐨쐩쐪쐫쐬쐭쐮쐯쐰쐱쐲쐳쐴쐵쐶쐷쐸쐹쐺쐻쐼쐽쐾쐿쑀쑁쑂쑃쑄쑅쑆쑇쑈쑉쑊쑋쑌쑍쑎쑏쑐쑑쑒쑓쑔쑕쑖쑗쑘쑙쑚쑛쑜쑝쑞쑟쑠쑡쑢쑣쑤쑥쑦쑧쑨쑩쑪쑫쑬쑭쑮쑯쑰쑱쑲쑳쑴쑵쑶쑷쑸쑹쑺쑻쑼쑽쑾쑿쒀쒁쒂쒃쒄쒅쒆쒇쒈쒉쒊쒋쒌쒍쒎쒏쒐쒑쒒쒓쒔쒕쒖쒗쒘쒙쒚쒛쒜쒝쒞쒟쒠쒡쒢쒣쒤쒥쒦쒧쒨쒩쒪쒫쒬쒭쒮쒯쒰쒱쒲쒳쒴쒵쒶쒷쒸쒹쒺쒻쒼쒽쒾쒿쓀쓁쓂쓃쓄쓅쓆쓇쓈쓉쓊쓋쓌쓍쓎쓏쓐쓑쓒쓓쓔쓕쓖쓗쓘쓙쓚쓛쓜쓝쓞쓟쓠쓡쓢쓣쓤쓥쓦쓧쓨쓩쓪쓫쓬쓭쓮쓯쓰쓱쓲쓳쓴쓵쓶쓷쓸쓹쓺쓻쓼쓽쓾쓿씀씁씂씃씄씅씆씇씈씉씊씋씌씍씎씏씐씑씒씓씔씕씖씗씘씙씚씛씜씝씞씟씠씡씢씣씤씥씦씧씨씩씪씫씬씭씮씯씰씱씲씳씴씵씶씷씸씹씺씻씼씽씾씿앀앁앂앃아악앆앇안앉않앋알앍앎앏앐앑앒앓암압앖앗았앙앚앛앜앝앞앟애액앢앣앤앥앦앧앨앩앪앫앬앭앮앯앰앱앲앳앴앵앶앷앸앹앺앻야약앾앿얀얁얂얃얄얅얆얇얈얉얊얋얌얍얎얏얐양얒얓얔얕얖얗얘얙얚얛얜얝얞얟얠얡얢얣얤얥얦얧얨얩얪얫얬얭얮얯얰얱얲얳어억얶얷언얹얺얻얼얽얾얿엀엁엂엃엄업없엇었엉엊엋엌엍엎엏에엑엒엓엔엕엖엗엘엙엚엛엜엝엞엟엠엡엢엣엤엥엦엧엨엩엪엫여역엮엯연엱엲엳열엵엶엷엸엹엺엻염엽엾엿였영옂옃옄옅옆옇예옉옊옋옌옍옎옏옐옑옒옓옔옕옖옗옘옙옚옛옜옝옞옟옠옡옢옣오옥옦옧온옩옪옫올옭옮옯옰옱옲옳옴옵옶옷옸옹옺옻옼옽옾옿와왁왂왃완왅왆왇왈왉왊왋왌왍왎왏왐왑왒왓왔왕왖왗왘왙왚왛왜왝왞왟왠왡왢왣왤왥왦왧왨왩왪왫왬왭왮왯왰왱왲왳왴왵왶왷외왹왺왻왼왽왾왿욀욁욂욃욄욅욆욇욈욉욊욋욌욍욎욏욐욑욒욓요욕욖욗욘욙욚욛욜욝욞욟욠욡욢욣욤욥욦욧욨용욪욫욬욭욮욯우욱욲욳운욵욶욷울욹욺욻욼욽욾욿움웁웂웃웄웅웆웇웈웉웊웋워웍웎웏원웑웒웓월웕웖웗웘웙웚웛웜웝웞웟웠웡웢웣웤웥웦웧웨웩웪웫웬웭웮웯웰웱웲웳웴웵웶웷웸웹웺웻웼웽웾웿윀윁윂윃위윅윆윇윈윉윊윋윌윍윎윏윐윑윒윓윔윕윖윗윘윙윚윛윜윝윞윟유육윢윣윤윥윦윧율윩윪윫윬윭윮윯윰윱윲윳윴융윶윷윸윹윺윻으윽윾윿은읁읂읃을읅읆읇읈읉읊읋음읍읎읏읐응읒읓읔읕읖읗의읙읚읛읜읝읞읟읠읡읢읣읤읥읦읧읨읩읪읫읬읭읮읯읰읱읲읳이익읶읷인읹읺읻일읽읾읿잀잁잂잃임입잆잇있잉잊잋잌잍잎잏자작잒잓잔잕잖잗잘잙잚잛잜잝잞잟잠잡잢잣잤장잦잧잨잩잪잫재잭잮잯잰잱잲잳잴잵잶잷잸잹잺잻잼잽잾잿쟀쟁쟂쟃쟄쟅쟆쟇쟈쟉쟊쟋쟌쟍쟎쟏쟐쟑쟒쟓쟔쟕쟖쟗쟘쟙쟚쟛쟜쟝쟞쟟쟠쟡쟢쟣쟤쟥쟦쟧쟨쟩쟪쟫쟬쟭쟮쟯쟰쟱쟲쟳쟴쟵쟶쟷쟸쟹쟺쟻쟼쟽쟾쟿저적젂젃전젅젆젇절젉젊젋젌젍젎젏점접젒젓젔정젖젗젘젙젚젛제젝젞젟젠젡젢젣젤젥젦젧젨젩젪젫젬젭젮젯젰젱젲젳젴젵젶젷져젹젺젻젼젽젾젿졀졁졂졃졄졅졆졇졈졉졊졋졌졍졎졏졐졑졒졓졔졕졖졗졘졙졚졛졜졝졞졟졠졡졢졣졤졥졦졧졨졩졪졫졬졭졮졯조족졲졳존졵졶졷졸졹졺졻졼졽졾졿좀좁좂좃좄종좆좇좈좉좊좋좌좍좎좏좐좑좒좓좔좕좖좗좘좙좚좛좜좝좞좟좠좡좢좣좤좥좦좧좨좩좪좫좬좭좮좯좰좱좲좳좴좵좶좷좸좹좺좻좼좽좾좿죀죁죂죃죄죅죆죇죈죉죊죋죌죍죎죏죐죑죒죓죔죕죖죗죘죙죚죛죜죝죞죟죠죡죢죣죤죥죦죧죨죩죪죫죬죭죮죯죰죱죲죳죴죵죶죷죸죹죺죻주죽죾죿준줁줂줃줄줅줆줇줈줉줊줋줌줍줎줏줐중줒줓줔줕줖줗줘줙줚줛줜줝줞줟줠줡줢줣줤줥줦줧줨줩줪줫줬줭줮줯줰줱줲줳줴줵줶줷줸줹줺줻줼줽줾줿쥀쥁쥂쥃쥄쥅쥆쥇쥈쥉쥊쥋쥌쥍쥎쥏쥐쥑쥒쥓쥔쥕쥖쥗쥘쥙쥚쥛쥜쥝쥞쥟쥠쥡쥢쥣쥤쥥쥦쥧쥨쥩쥪쥫쥬쥭쥮쥯쥰쥱쥲쥳쥴쥵쥶쥷쥸쥹쥺쥻쥼쥽쥾쥿즀즁즂즃즄즅즆즇즈즉즊즋즌즍즎즏즐즑즒즓즔즕즖즗즘즙즚즛즜증즞즟즠즡즢즣즤즥즦즧즨즩즪즫즬즭즮즯즰즱즲즳즴즵즶즷즸즹즺즻즼즽즾즿지직짂짃진짅짆짇질짉짊짋짌짍짎짏짐집짒짓짔징짖짗짘짙짚짛짜짝짞짟짠짡짢짣짤짥짦짧짨짩짪짫짬짭짮짯짰짱짲짳짴짵짶짷째짹짺짻짼짽짾짿쨀쨁쨂쨃쨄쨅쨆쨇쨈쨉쨊쨋쨌쨍쨎쨏쨐쨑쨒쨓쨔쨕쨖쨗쨘쨙쨚쨛쨜쨝쨞쨟쨠쨡쨢쨣쨤쨥쨦쨧쨨쨩쨪쨫쨬쨭쨮쨯쨰쨱쨲쨳쨴쨵쨶쨷쨸쨹쨺쨻쨼쨽쨾쨿쩀쩁쩂쩃쩄쩅쩆쩇쩈쩉쩊쩋쩌쩍쩎쩏쩐쩑쩒쩓쩔쩕쩖쩗쩘쩙쩚쩛쩜쩝쩞쩟쩠쩡쩢쩣쩤쩥쩦쩧쩨쩩쩪쩫쩬쩭쩮쩯쩰쩱쩲쩳쩴쩵쩶쩷쩸쩹쩺쩻쩼쩽쩾쩿쪀쪁쪂쪃쪄쪅쪆쪇쪈쪉쪊쪋쪌쪍쪎쪏쪐쪑쪒쪓쪔쪕쪖쪗쪘쪙쪚쪛쪜쪝쪞쪟쪠쪡쪢쪣쪤쪥쪦쪧쪨쪩쪪쪫쪬쪭쪮쪯쪰쪱쪲쪳쪴쪵쪶쪷쪸쪹쪺쪻쪼쪽쪾쪿쫀쫁쫂쫃쫄쫅쫆쫇쫈쫉쫊쫋쫌쫍쫎쫏쫐쫑쫒쫓쫔쫕쫖쫗쫘쫙쫚쫛쫜쫝쫞쫟쫠쫡쫢쫣쫤쫥쫦쫧쫨쫩쫪쫫쫬쫭쫮쫯쫰쫱쫲쫳쫴쫵쫶쫷쫸쫹쫺쫻쫼쫽쫾쫿쬀쬁쬂쬃쬄쬅쬆쬇쬈쬉쬊쬋쬌쬍쬎쬏쬐쬑쬒쬓쬔쬕쬖쬗쬘쬙쬚쬛쬜쬝쬞쬟쬠쬡쬢쬣쬤쬥쬦쬧쬨쬩쬪쬫쬬쬭쬮쬯쬰쬱쬲쬳쬴쬵쬶쬷쬸쬹쬺쬻쬼쬽쬾쬿쭀쭁쭂쭃쭄쭅쭆쭇쭈쭉쭊쭋쭌쭍쭎쭏쭐쭑쭒쭓쭔쭕쭖쭗쭘쭙쭚쭛쭜쭝쭞쭟쭠쭡쭢쭣쭤쭥쭦쭧쭨쭩쭪쭫쭬쭭쭮쭯쭰쭱쭲쭳쭴쭵쭶쭷쭸쭹쭺쭻쭼쭽쭾쭿쮀쮁쮂쮃쮄쮅쮆쮇쮈쮉쮊쮋쮌쮍쮎쮏쮐쮑쮒쮓쮔쮕쮖쮗쮘쮙쮚쮛쮜쮝쮞쮟쮠쮡쮢쮣쮤쮥쮦쮧쮨쮩쮪쮫쮬쮭쮮쮯쮰쮱쮲쮳쮴쮵쮶쮷쮸쮹쮺쮻쮼쮽쮾쮿쯀쯁쯂쯃쯄쯅쯆쯇쯈쯉쯊쯋쯌쯍쯎쯏쯐쯑쯒쯓쯔쯕쯖쯗쯘쯙쯚쯛쯜쯝쯞쯟쯠쯡쯢쯣쯤쯥쯦쯧쯨쯩쯪쯫쯬쯭쯮쯯쯰쯱쯲쯳쯴쯵쯶쯷쯸쯹쯺쯻쯼쯽쯾쯿찀찁찂찃찄찅찆찇찈찉찊찋찌찍찎찏찐찑찒찓찔찕찖찗찘찙찚찛찜찝찞찟찠찡찢찣찤찥찦찧차착찪찫찬찭찮찯찰찱찲찳찴찵찶찷참찹찺찻찼창찾찿챀챁챂챃채책챆챇챈챉챊챋챌챍챎챏챐챑챒챓챔챕챖챗챘챙챚챛챜챝챞챟챠챡챢챣챤챥챦챧챨챩챪챫챬챭챮챯챰챱챲챳챴챵챶챷챸챹챺챻챼챽챾챿첀첁첂첃첄첅첆첇첈첉첊첋첌첍첎첏첐첑첒첓첔첕첖첗처척첚첛천첝첞첟철첡첢첣첤첥첦첧첨첩첪첫첬청첮첯첰첱첲첳체첵첶첷첸첹첺첻첼첽첾첿쳀쳁쳂쳃쳄쳅쳆쳇쳈쳉쳊쳋쳌쳍쳎쳏쳐쳑쳒쳓쳔쳕쳖쳗쳘쳙쳚쳛쳜쳝쳞쳟쳠쳡쳢쳣쳤쳥쳦쳧쳨쳩쳪쳫쳬쳭쳮쳯쳰쳱쳲쳳쳴쳵쳶쳷쳸쳹쳺쳻쳼쳽쳾쳿촀촁촂촃촄촅촆촇초촉촊촋촌촍촎촏촐촑촒촓촔촕촖촗촘촙촚촛촜총촞촟촠촡촢촣촤촥촦촧촨촩촪촫촬촭촮촯촰촱촲촳촴촵촶촷촸촹촺촻촼촽촾촿쵀쵁쵂쵃쵄쵅쵆쵇쵈쵉쵊쵋쵌쵍쵎쵏쵐쵑쵒쵓쵔쵕쵖쵗쵘쵙쵚쵛최쵝쵞쵟쵠쵡쵢쵣쵤쵥쵦쵧쵨쵩쵪쵫쵬쵭쵮쵯쵰쵱쵲쵳쵴쵵쵶쵷쵸쵹쵺쵻쵼쵽쵾쵿춀춁춂춃춄춅춆춇춈춉춊춋춌춍춎춏춐춑춒춓추축춖춗춘춙춚춛출춝춞춟춠춡춢춣춤춥춦춧춨충춪춫춬춭춮춯춰춱춲춳춴춵춶춷춸춹춺춻춼춽춾춿췀췁췂췃췄췅췆췇췈췉췊췋췌췍췎췏췐췑췒췓췔췕췖췗췘췙췚췛췜췝췞췟췠췡췢췣췤췥췦췧취췩췪췫췬췭췮췯췰췱췲췳췴췵췶췷췸췹췺췻췼췽췾췿츀츁츂츃츄츅츆츇츈츉츊츋츌츍츎츏츐츑츒츓츔츕츖츗츘츙츚츛츜츝츞츟츠측츢츣츤츥츦츧츨츩츪츫츬츭츮츯츰츱츲츳츴층츶츷츸츹츺츻츼츽츾츿칀칁칂칃칄칅칆칇칈칉칊칋칌칍칎칏칐칑칒칓칔칕칖칗치칙칚칛친칝칞칟칠칡칢칣칤칥칦칧침칩칪칫칬칭칮칯칰칱칲칳카칵칶칷칸칹칺칻칼칽칾칿캀캁캂캃캄캅캆캇캈캉캊캋캌캍캎캏캐캑캒캓캔캕캖캗캘캙캚캛캜캝캞캟캠캡캢캣캤캥캦캧캨캩캪캫캬캭캮캯캰캱캲캳캴캵캶캷캸캹캺캻캼캽캾캿컀컁컂컃컄컅컆컇컈컉컊컋컌컍컎컏컐컑컒컓컔컕컖컗컘컙컚컛컜컝컞컟컠컡컢컣커컥컦컧컨컩컪컫컬컭컮컯컰컱컲컳컴컵컶컷컸컹컺컻컼컽컾컿케켁켂켃켄켅켆켇켈켉켊켋켌켍켎켏켐켑켒켓켔켕켖켗켘켙켚켛켜켝켞켟켠켡켢켣켤켥켦켧켨켩켪켫켬켭켮켯켰켱켲켳켴켵켶켷켸켹켺켻켼켽켾켿콀콁콂콃콄콅콆콇콈콉콊콋콌콍콎콏콐콑콒콓코콕콖콗콘콙콚콛콜콝콞콟콠콡콢콣콤콥콦콧콨콩콪콫콬콭콮콯콰콱콲콳콴콵콶콷콸콹콺콻콼콽콾콿쾀쾁쾂쾃쾄쾅쾆쾇쾈쾉쾊쾋쾌쾍쾎쾏쾐쾑쾒쾓쾔쾕쾖쾗쾘쾙쾚쾛쾜쾝쾞쾟쾠쾡쾢쾣쾤쾥쾦쾧쾨쾩쾪쾫쾬쾭쾮쾯쾰쾱쾲쾳쾴쾵쾶쾷쾸쾹쾺쾻쾼쾽쾾쾿쿀쿁쿂쿃쿄쿅쿆쿇쿈쿉쿊쿋쿌쿍쿎쿏쿐쿑쿒쿓쿔쿕쿖쿗쿘쿙쿚쿛쿜쿝쿞쿟쿠쿡쿢쿣쿤쿥쿦쿧쿨쿩쿪쿫쿬쿭쿮쿯쿰쿱쿲쿳쿴쿵쿶쿷쿸쿹쿺쿻쿼쿽쿾쿿퀀퀁퀂퀃퀄퀅퀆퀇퀈퀉퀊퀋퀌퀍퀎퀏퀐퀑퀒퀓퀔퀕퀖퀗퀘퀙퀚퀛퀜퀝퀞퀟퀠퀡퀢퀣퀤퀥퀦퀧퀨퀩퀪퀫퀬퀭퀮퀯퀰퀱퀲퀳퀴퀵퀶퀷퀸퀹퀺퀻퀼퀽퀾퀿큀큁큂큃큄큅큆큇큈큉큊큋큌큍큎큏큐큑큒큓큔큕큖큗큘큙큚큛큜큝큞큟큠큡큢큣큤큥큦큧큨큩큪큫크큭큮큯큰큱큲큳클큵큶큷큸큹큺큻큼큽큾큿킀킁킂킃킄킅킆킇킈킉킊킋킌킍킎킏킐킑킒킓킔킕킖킗킘킙킚킛킜킝킞킟킠킡킢킣키킥킦킧킨킩킪킫킬킭킮킯킰킱킲킳킴킵킶킷킸킹킺킻킼킽킾킿타탁탂탃탄탅탆탇탈탉탊탋탌탍탎탏탐탑탒탓탔탕탖탗탘탙탚탛태택탞탟탠탡탢탣탤탥탦탧탨탩탪탫탬탭탮탯탰탱탲탳탴탵탶탷탸탹탺탻탼탽탾탿턀턁턂턃턄턅턆턇턈턉턊턋턌턍턎턏턐턑턒턓턔턕턖턗턘턙턚턛턜턝턞턟턠턡턢턣턤턥턦턧턨턩턪턫턬턭턮턯터턱턲턳턴턵턶턷털턹턺턻턼턽턾턿텀텁텂텃텄텅텆텇텈텉텊텋테텍텎텏텐텑텒텓텔텕텖텗텘텙텚텛템텝텞텟텠텡텢텣텤텥텦텧텨텩텪텫텬텭텮텯텰텱텲텳텴텵텶텷텸텹텺텻텼텽텾텿톀톁톂톃톄톅톆톇톈톉톊톋톌톍톎톏톐톑톒톓톔톕톖톗톘톙톚톛톜톝톞톟토톡톢톣톤톥톦톧톨톩톪톫톬톭톮톯톰톱톲톳톴통톶톷톸톹톺톻톼톽톾톿퇀퇁퇂퇃퇄퇅퇆퇇퇈퇉퇊퇋퇌퇍퇎퇏퇐퇑퇒퇓퇔퇕퇖퇗퇘퇙퇚퇛퇜퇝퇞퇟퇠퇡퇢퇣퇤퇥퇦퇧퇨퇩퇪퇫퇬퇭퇮퇯퇰퇱퇲퇳퇴퇵퇶퇷퇸퇹퇺퇻퇼퇽퇾퇿툀툁툂툃툄툅툆툇툈툉툊툋툌툍툎툏툐툑툒툓툔툕툖툗툘툙툚툛툜툝툞툟툠툡툢툣툤툥툦툧툨툩툪툫투툭툮툯툰툱툲툳툴툵툶툷툸툹툺툻툼툽툾툿퉀퉁퉂퉃퉄퉅퉆퉇퉈퉉퉊퉋퉌퉍퉎퉏퉐퉑퉒퉓퉔퉕퉖퉗퉘퉙퉚퉛퉜퉝퉞퉟퉠퉡퉢퉣퉤퉥퉦퉧퉨퉩퉪퉫퉬퉭퉮퉯퉰퉱퉲퉳퉴퉵퉶퉷퉸퉹퉺퉻퉼퉽퉾퉿튀튁튂튃튄튅튆튇튈튉튊튋튌튍튎튏튐튑튒튓튔튕튖튗튘튙튚튛튜튝튞튟튠튡튢튣튤튥튦튧튨튩튪튫튬튭튮튯튰튱튲튳튴튵튶튷트특튺튻튼튽튾튿틀틁틂틃틄틅틆틇틈틉틊틋틌틍틎틏틐틑틒틓틔틕틖틗틘틙틚틛틜틝틞틟틠틡틢틣틤틥틦틧틨틩틪틫틬틭틮틯티틱틲틳틴틵틶틷틸틹틺틻틼틽틾틿팀팁팂팃팄팅팆팇팈팉팊팋파팍팎팏판팑팒팓팔팕팖팗팘팙팚팛팜팝팞팟팠팡팢팣팤팥팦팧패팩팪팫팬팭팮팯팰팱팲팳팴팵팶팷팸팹팺팻팼팽팾팿퍀퍁퍂퍃퍄퍅퍆퍇퍈퍉퍊퍋퍌퍍퍎퍏퍐퍑퍒퍓퍔퍕퍖퍗퍘퍙퍚퍛퍜퍝퍞퍟퍠퍡퍢퍣퍤퍥퍦퍧퍨퍩퍪퍫퍬퍭퍮퍯퍰퍱퍲퍳퍴퍵퍶퍷퍸퍹퍺퍻퍼퍽퍾퍿펀펁펂펃펄펅펆펇펈펉펊펋펌펍펎펏펐펑펒펓펔펕펖펗페펙펚펛펜펝펞펟펠펡펢펣펤펥펦펧펨펩펪펫펬펭펮펯펰펱펲펳펴펵펶펷편펹펺펻펼펽펾펿폀폁폂폃폄폅폆폇폈평폊폋폌폍폎폏폐폑폒폓폔폕폖폗폘폙폚폛폜폝폞폟폠폡폢폣폤폥폦폧폨폩폪폫포폭폮폯폰폱폲폳폴폵폶폷폸폹폺폻폼폽폾폿퐀퐁퐂퐃퐄퐅퐆퐇퐈퐉퐊퐋퐌퐍퐎퐏퐐퐑퐒퐓퐔퐕퐖퐗퐘퐙퐚퐛퐜퐝퐞퐟퐠퐡퐢퐣퐤퐥퐦퐧퐨퐩퐪퐫퐬퐭퐮퐯퐰퐱퐲퐳퐴퐵퐶퐷퐸퐹퐺퐻퐼퐽퐾퐿푀푁푂푃푄푅푆푇푈푉푊푋푌푍푎푏푐푑푒푓푔푕푖푗푘푙푚푛표푝푞푟푠푡푢푣푤푥푦푧푨푩푪푫푬푭푮푯푰푱푲푳푴푵푶푷푸푹푺푻푼푽푾푿풀풁풂풃풄풅풆풇품풉풊풋풌풍풎풏풐풑풒풓풔풕풖풗풘풙풚풛풜풝풞풟풠풡풢풣풤풥풦풧풨풩풪풫풬풭풮풯풰풱풲풳풴풵풶풷풸풹풺풻풼풽풾풿퓀퓁퓂퓃퓄퓅퓆퓇퓈퓉퓊퓋퓌퓍퓎퓏퓐퓑퓒퓓퓔퓕퓖퓗퓘퓙퓚퓛퓜퓝퓞퓟퓠퓡퓢퓣퓤퓥퓦퓧퓨퓩퓪퓫퓬퓭퓮퓯퓰퓱퓲퓳퓴퓵퓶퓷퓸퓹퓺퓻퓼퓽퓾퓿픀픁픂픃프픅픆픇픈픉픊픋플픍픎픏픐픑픒픓픔픕픖픗픘픙픚픛픜픝픞픟픠픡픢픣픤픥픦픧픨픩픪픫픬픭픮픯픰픱픲픳픴픵픶픷픸픹픺픻피픽픾픿핀핁핂핃필핅핆핇핈핉핊핋핌핍핎핏핐핑핒핓핔핕핖핗하학핚핛한핝핞핟할핡핢핣핤핥핦핧함합핪핫핬항핮핯핰핱핲핳해핵핶핷핸핹핺핻핼핽핾핿햀햁햂햃햄햅햆햇했행햊햋햌햍햎햏햐햑햒햓햔햕햖햗햘햙햚햛햜햝햞햟햠햡햢햣햤향햦햧햨햩햪햫햬햭햮햯햰햱햲햳햴햵햶햷햸햹햺햻햼햽햾햿헀헁헂헃헄헅헆헇허헉헊헋헌헍헎헏헐헑헒헓헔헕헖헗험헙헚헛헜헝헞헟헠헡헢헣헤헥헦헧헨헩헪헫헬헭헮헯헰헱헲헳헴헵헶헷헸헹헺헻헼헽헾헿혀혁혂혃현혅혆혇혈혉혊혋혌혍혎혏혐협혒혓혔형혖혗혘혙혚혛혜혝혞혟혠혡혢혣혤혥혦혧혨혩혪혫혬혭혮혯혰혱혲혳혴혵혶혷호혹혺혻혼혽혾혿홀홁홂홃홄홅홆홇홈홉홊홋홌홍홎홏홐홑홒홓화확홖홗환홙홚홛활홝홞홟홠홡홢홣홤홥홦홧홨황홪홫홬홭홮홯홰홱홲홳홴홵홶홷홸홹홺홻홼홽홾홿횀횁횂횃횄횅횆횇횈횉횊횋회획횎횏횐횑횒횓횔횕횖횗횘횙횚횛횜횝횞횟횠횡횢횣횤횥횦횧효횩횪횫횬횭횮횯횰횱횲횳횴횵횶횷횸횹횺횻횼횽횾횿훀훁훂훃후훅훆훇훈훉훊훋훌훍훎훏훐훑훒훓훔훕훖훗훘훙훚훛훜훝훞훟훠훡훢훣훤훥훦훧훨훩훪훫훬훭훮훯훰훱훲훳훴훵훶훷훸훹훺훻훼훽훾훿휀휁휂휃휄휅휆휇휈휉휊휋휌휍휎휏휐휑휒휓휔휕휖휗휘휙휚휛휜휝휞휟휠휡휢휣휤휥휦휧휨휩휪휫휬휭휮휯휰휱휲휳휴휵휶휷휸휹휺휻휼휽휾휿흀흁흂흃흄흅흆흇흈흉흊흋흌흍흎흏흐흑흒흓흔흕흖흗흘흙흚흛흜흝흞흟흠흡흢흣흤흥흦흧흨흩흪흫희흭흮흯흰흱흲흳흴흵흶흷흸흹흺흻흼흽흾흿힀힁힂힃힄힅힆힇히힉힊힋힌힍힎힏힐힑힒힓힔힕힖힗힘힙힚힛힜힝힞힟힠힡힢힣ힰힱힲힳힴힵힶힷힸힹힺힻힼힽힾힿퟀퟁퟂퟃퟄퟅퟆퟋퟌퟍퟎퟏퟐퟑퟒퟓퟔퟕퟖퟗퟘퟙퟚퟛퟜퟝퟞퟟퟠퟡퟢퟣퟤퟥퟦퟧퟨퟩퟪퟫퟬퟭퟮퟯퟰퟱퟲퟳퟴퟵퟶퟷퟸퟹퟺퟻ???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????􏰀???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????豈更車賈滑串句龜龜契金喇奈懶癩羅蘿螺裸邏樂洛烙珞落酪駱亂卵欄爛蘭鸞嵐濫藍襤拉臘蠟廊朗浪狼郎來冷勞擄櫓爐盧老蘆虜路露魯鷺碌祿綠菉錄鹿論壟弄籠聾牢磊賂雷壘屢樓淚漏累縷陋勒肋凜凌稜綾菱陵讀拏樂諾丹寧怒率異北磻便復不泌數索參塞省葉說殺辰沈拾若掠略亮兩凉梁糧良諒量勵呂女廬旅濾礪閭驪麗黎力曆歷轢年憐戀撚漣煉璉秊練聯輦蓮連鍊列劣咽烈裂說廉念捻殮簾獵令囹寧嶺怜玲瑩羚聆鈴零靈領例禮醴隸惡了僚寮尿料樂燎療蓼遼龍暈阮劉杻柳流溜琉留硫紐類六戮陸倫崙淪輪律慄栗率隆利吏履易李梨泥理痢罹裏裡里離匿溺吝燐璘藺隣鱗麟林淋臨立笠粒狀炙識什茶刺切度拓糖宅洞暴輻行降見廓兀嗀﨎﨏塚﨑晴﨓﨔凞猪益礼神祥福靖精羽﨟蘒﨡諸﨣﨤逸都﨧﨨﨩飯飼館鶴郞隷侮僧免勉勤卑喝嘆器塀墨層屮悔慨憎懲敏既暑梅海渚漢煮爫琢碑社祉祈祐祖祝禍禎穀突節練縉繁署者臭艹艹著褐視謁謹賓贈辶逸難響頻恵𤋮舘並况全侀充冀勇勺喝啕喙嗢塚墳奄奔婢嬨廒廙彩徭惘慎愈憎慠懲戴揄搜摒敖晴朗望杖歹殺流滛滋漢瀞煮瞧爵犯猪瑱甆画瘝瘟益盛直睊着磌窱節类絛練缾者荒華蝹襁覆視調諸請謁諾諭謹變贈輸遲醙鉶陼難靖韛響頋頻鬒龜𢡊𢡄𣏕㮝䀘䀹𥉉𥳐𧻓齃龎fffiflffifflſtstﬓﬔﬕﬖﬗיִﬞײַﬠﬡﬢﬣﬤﬥﬦﬧﬨ﬩שׁשׂשּׁשּׂאַאָאּבּגּדּהּוּזּטּיּךּכּלּמּנּסּףּפּצּקּרּשּתּוֹבֿכֿפֿﭏﭐﭑﭒﭓﭔﭕﭖﭗﭘﭙﭚﭛﭜﭝﭞﭟﭠﭡﭢﭣﭤﭥﭦﭧﭨﭩﭪﭫﭬﭭﭮﭯﭰﭱﭲﭳﭴﭵﭶﭷﭸﭹﭺﭻﭼﭽﭾﭿﮀﮁﮂﮃﮄﮅﮆﮇﮈﮉﮊﮋﮌﮍﮎﮏﮐﮑﮒﮓﮔﮕﮖﮗﮘﮙﮚﮛﮜﮝﮞﮟﮠﮡﮢﮣﮤﮥﮦﮧﮨﮩﮪﮫﮬﮭﮮﮯﮰﮱ﮲﮳﮴﮵﮶﮷﮸﮹﮺﮻﮼﮽﮾﮿﯀﯁ﯓﯔﯕﯖﯗﯘﯙﯚﯛﯜﯝﯞﯟﯠﯡﯢﯣﯤﯥﯦﯧﯨﯩﯪﯫﯬﯭﯮﯯﯰﯱﯲﯳﯴﯵﯶﯷﯸﯹﯺﯻﯼﯽﯾﯿﰀﰁﰂﰃﰄﰅﰆﰇﰈﰉﰊﰋﰌﰍﰎﰏﰐﰑﰒﰓﰔﰕﰖﰗﰘﰙﰚﰛﰜﰝﰞﰟﰠﰡﰢﰣﰤﰥﰦﰧﰨﰩﰪﰫﰬﰭﰮﰯﰰﰱﰲﰳﰴﰵﰶﰷﰸﰹﰺﰻﰼﰽﰾﰿﱀﱁﱂﱃﱄﱅﱆﱇﱈﱉﱊﱋﱌﱍﱎﱏﱐﱑﱒﱓﱔﱕﱖﱗﱘﱙﱚﱛﱜﱝﱞﱟﱠﱡﱢﱣﱤﱥﱦﱧﱨﱩﱪﱫﱬﱭﱮﱯﱰﱱﱲﱳﱴﱵﱶﱷﱸﱹﱺﱻﱼﱽﱾﱿﲀﲁﲂﲃﲄﲅﲆﲇﲈﲉﲊﲋﲌﲍﲎﲏﲐﲑﲒﲓﲔﲕﲖﲗﲘﲙﲚﲛﲜﲝﲞﲟﲠﲡﲢﲣﲤﲥﲦﲧﲨﲩﲪﲫﲬﲭﲮﲯﲰﲱﲲﲳﲴﲵﲶﲷﲸﲹﲺﲻﲼﲽﲾﲿﳀﳁﳂﳃﳄﳅﳆﳇﳈﳉﳊﳋﳌﳍﳎﳏﳐﳑﳒﳓﳔﳕﳖﳗﳘﳙﳚﳛﳜﳝﳞﳟﳠﳡﳢﳣﳤﳥﳦﳧﳨﳩﳪﳫﳬﳭﳮﳯﳰﳱﳲﳳﳴﳵﳶﳷﳸﳹﳺﳻﳼﳽﳾﳿﴀﴁﴂﴃﴄﴅﴆﴇﴈﴉﴊﴋﴌﴍﴎﴏﴐﴑﴒﴓﴔﴕﴖﴗﴘﴙﴚﴛﴜﴝﴞﴟﴠﴡﴢﴣﴤﴥﴦﴧﴨﴩﴪﴫﴬﴭﴮﴯﴰﴱﴲﴳﴴﴵﴶﴷﴸﴹﴺﴻﴼﴽ﴾﴿ﵐﵑﵒﵓﵔﵕﵖﵗﵘﵙﵚﵛﵜﵝﵞﵟﵠﵡﵢﵣﵤﵥﵦﵧﵨﵩﵪﵫﵬﵭﵮﵯﵰﵱﵲﵳﵴﵵﵶﵷﵸﵹﵺﵻﵼﵽﵾﵿﶀﶁﶂﶃﶄﶅﶆﶇﶈﶉﶊﶋﶌﶍﶎﶏﶒﶓﶔﶕﶖﶗﶘﶙﶚﶛﶜﶝﶞﶟﶠﶡﶢﶣﶤﶥﶦﶧﶨﶩﶪﶫﶬﶭﶮﶯﶰﶱﶲﶳﶴﶵﶶﶷﶸﶹﶺﶻﶼﶽﶾﶿﷀﷁﷂﷃﷄﷅﷆﷇﷰﷱﷲﷳﷴﷵﷶﷷﷸﷹﷺﷻ﷼﷽︀︁︂︃︄︅︆︇︈︉︊︋︌︍︎️︐︑︒︓︔︕︖︗︘︙︠︡︢︣︤︥︦︰︱︲︳︴︵︶︷︸︹︺︻︼︽︾︿﹀﹁﹂﹃﹄﹅﹆﹇﹈﹉﹊﹋﹌﹍﹎﹏﹐﹑﹒﹔﹕﹖﹗﹘﹙﹚﹛﹜﹝﹞﹟﹠﹡﹢﹣﹤﹥﹦﹨﹩﹪﹫ﹰﹱﹲﹳﹴﹶﹷﹸﹹﹺﹻﹼﹽﹾﹿﺀﺁﺂﺃﺄﺅﺆﺇﺈﺉﺊﺋﺌﺍﺎﺏﺐﺑﺒﺓﺔﺕﺖﺗﺘﺙﺚﺛﺜﺝﺞﺟﺠﺡﺢﺣﺤﺥﺦﺧﺨﺩﺪﺫﺬﺭﺮﺯﺰﺱﺲﺳﺴﺵﺶﺷﺸﺹﺺﺻﺼﺽﺾﺿﻀﻁﻂﻃﻄﻅﻆﻇﻈﻉﻊﻋﻌﻍﻎﻏﻐﻑﻒﻓﻔﻕﻖﻗﻘﻙﻚﻛﻜﻝﻞﻟﻠﻡﻢﻣﻤﻥﻦﻧﻨﻩﻪﻫﻬﻭﻮﻯﻰﻱﻲﻳﻴﻵﻶﻷﻸﻹﻺﻻﻼ!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~⦅⦆。「」、・ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙゚ᅠᄀᄁᆪᄂᆬᆭᄃᄄᄅᆰᆱᆲᆳᆴᆵᄚᄆᄇᄈᄡᄉᄊᄋᄌᄍᄎᄏᄐᄑ하ᅢᅣᅤᅥᅦᅧᅨᅩᅪᅫᅬᅭᅮᅯᅰᅱᅲᅳᅴᅵ¢£¬ ̄¦¥₩│←↑→↓■○�‬‬‬ +#!#😀😃😁😎😒😞😍🙂😆😊😉 +#!#ऀँंःऄअआइईउऊऋऌऍऎएऐऑऒओऔकखगघङचछजझञटठडढणतथदधनऩपफबभमयरऱलळऴवशषसहऺऻ़ऽािीुूृॄॅॆेैॉॊोौ्ॎॏॐ॒॑॓॔ॕॖॗक़ख़ग़ज़ड़ढ़फ़य़ॠॡॢॣ।॥०१२३४५६७८९॰ॱॲॳॴॵॶॷॹॺॻॼॽॾॿ +~~END~~ + +~~ROW COUNT: 6~~ + +DROP TABLE TEXT_dt; diff --git a/contrib/test/python/expected/pymssql/TestTime.out b/contrib/test/python/expected/pymssql/TestTime.out new file mode 100644 index 00000000000..b30a237b822 --- /dev/null +++ b/contrib/test/python/expected/pymssql/TestTime.out @@ -0,0 +1,265 @@ +Create table TestTime(a time(6)) + +prepst#!# Insert into TestTime Values(%s) #!#Time|-|a|-|12:45:37.123|-|0 + + +prepst#!#exec#!#Time|-|a|-|12:45:37.123|-|3 + + +prepst#!#exec#!#Time|-|a|-|12:45:37.12|-|2 + + +prepst#!#exec#!#Time|-|a|-|12:45:37.1|-|1 + + +prepst#!#exec#!#Time|-|a|-|12:45:37.1234|-|4 + + +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|6 + + +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|5 + + +prepst#!#exec#!#Time|-|a|-| +~~ROW COUNT: 1~~ + + +select * from TestTime +~~START~~ +int + +~~END~~ + +~~ROW COUNT: 1~~ + + +Drop table TestTime + +Create table TestTime(a time(5)) + +prepst#!# Insert into TestTime Values(%s) #!#Time|-|a|-|12:45:37.123|-|0 + + +prepst#!#exec#!#Time|-|a|-|12:45:37.123|-|3 + + +prepst#!#exec#!#Time|-|a|-|12:45:37.12|-|2 + + +prepst#!#exec#!#Time|-|a|-|12:45:37.1|-|1 + + +prepst#!#exec#!#Time|-|a|-|12:45:37.1234|-|4 + + +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|6 + + +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|5 + + +prepst#!#exec#!#Time|-|a|-| +~~ROW COUNT: 1~~ + + +select * from TestTime +~~START~~ +int + +~~END~~ + +~~ROW COUNT: 1~~ + + +Drop table TestTime + +Create table TestTime(a time(4)) + +prepst#!# Insert into TestTime Values(%s) #!#Time|-|a|-|12:45:37.123|-|0 + + +prepst#!#exec#!#Time|-|a|-|12:45:37.123|-|3 + + +prepst#!#exec#!#Time|-|a|-|12:45:37.12|-|2 + + +prepst#!#exec#!#Time|-|a|-|12:45:37.1|-|1 + + +prepst#!#exec#!#Time|-|a|-|12:45:37.1234|-|4 + + +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|6 + + +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|5 + + +prepst#!#exec#!#Time|-|a|-| +~~ROW COUNT: 1~~ + + +select * from TestTime +~~START~~ +int + +~~END~~ + +~~ROW COUNT: 1~~ + + +Drop table TestTime + +Create table TestTime(a time(3)) + +prepst#!# Insert into TestTime Values(%s) #!#Time|-|a|-|12:45:37.123|-|0 + + +prepst#!#exec#!#Time|-|a|-|12:45:37.123|-|3 + + +prepst#!#exec#!#Time|-|a|-|12:45:37.12|-|2 + + +prepst#!#exec#!#Time|-|a|-|12:45:37.1|-|1 + + +prepst#!#exec#!#Time|-|a|-|12:45:37.1234|-|4 + + +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|6 + + +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|5 + + +prepst#!#exec#!#Time|-|a|-| +~~ROW COUNT: 1~~ + + +select * from TestTime +~~START~~ +int + +~~END~~ + +~~ROW COUNT: 1~~ + + +Drop table TestTime + +Create table TestTime(a time(2)) + +prepst#!# Insert into TestTime Values(%s) #!#Time|-|a|-|12:45:37.123|-|0 + + +prepst#!#exec#!#Time|-|a|-|12:45:37.123|-|3 + + +prepst#!#exec#!#Time|-|a|-|12:45:37.12|-|2 + + +prepst#!#exec#!#Time|-|a|-|12:45:37.1|-|1 + + +prepst#!#exec#!#Time|-|a|-|12:45:37.1234|-|4 + + +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|6 + + +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|5 + + +prepst#!#exec#!#Time|-|a|-| +~~ROW COUNT: 1~~ + + +select * from TestTime +~~START~~ +int + +~~END~~ + +~~ROW COUNT: 1~~ + + +Drop table TestTime + +Create table TestTime(a time(1)) + +prepst#!# Insert into TestTime Values(%s) #!#Time|-|a|-|12:45:37.123|-|0 + + +prepst#!#exec#!#Time|-|a|-|12:45:37.123|-|3 + + +prepst#!#exec#!#Time|-|a|-|12:45:37.12|-|2 + + +prepst#!#exec#!#Time|-|a|-|12:45:37.1|-|1 + + +prepst#!#exec#!#Time|-|a|-|12:45:37.1234|-|4 + + +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|6 + + +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|5 + + +prepst#!#exec#!#Time|-|a|-| +~~ROW COUNT: 1~~ + + +select * from TestTime +~~START~~ +int + +~~END~~ + +~~ROW COUNT: 1~~ + + +Drop table TestTime + +Create table TestTime(a time(0)) + +prepst#!# Insert into TestTime Values(%s) #!#Time|-|a|-|12:45:37.123|-|0 + + +prepst#!#exec#!#Time|-|a|-|12:45:37.123|-|3 + + +prepst#!#exec#!#Time|-|a|-|12:45:37.12|-|2 + + +prepst#!#exec#!#Time|-|a|-|12:45:37.1|-|1 + + +prepst#!#exec#!#Time|-|a|-|12:45:37.1234|-|4 + + +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|6 + + +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|5 + + +prepst#!#exec#!#Time|-|a|-| +~~ROW COUNT: 1~~ + + +select * from TestTime +~~START~~ +int + +~~END~~ + +~~ROW COUNT: 1~~ + + +Drop table TestTime diff --git a/contrib/test/python/expected/pymssql/TestTinyInt.out b/contrib/test/python/expected/pymssql/TestTinyInt.out new file mode 100644 index 00000000000..ff8ac5af53c --- /dev/null +++ b/contrib/test/python/expected/pymssql/TestTinyInt.out @@ -0,0 +1,105 @@ +CREATE TABLE TINYINT_dt (a TINYINT) +prepst#!# INSERT INTO TINYINT_dt(a) values(%s) #!#TINYINT|-|a|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#TINYINT|-|a|-|-10 +~~ERROR (Code: 220)~~ +~~ERROR (Message: 'value for domain tinyint violates check constraint "tinyint_check"DB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n')~~ + +prepst#!#exec#!#TINYINT|-|a|-|100 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#TINYINT|-|a|-|002 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#TINYINT|-|a|-|029 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#TINYINT|-|a|-|004 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#TINYINT|-|a|-|87 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#TINYINT|-|a|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#TINYINT|-|a|-|255 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#TINYINT|-|a|-| +~~ROW COUNT: 1~~ + +SELECT * FROM TINYINT_dt; +~~START~~ +int +0 +100 +2 +29 +4 +87 +0 +255 + +~~END~~ + +~~ROW COUNT: 9~~ + +INSERT INTO TINYINT_dt(a) values(0) +~~ROW COUNT: 1~~ + +INSERT INTO TINYINT_dt(a) values(120) +~~ROW COUNT: 1~~ + +INSERT INTO TINYINT_dt(a) values(100) +~~ROW COUNT: 1~~ + +INSERT INTO TINYINT_dt(a) values(004) +~~ROW COUNT: 1~~ + +INSERT INTO TINYINT_dt(a) values(0) +~~ROW COUNT: 1~~ + +INSERT INTO TINYINT_dt(a) values(002) +~~ROW COUNT: 1~~ + +INSERT INTO TINYINT_dt(a) values(86) +~~ROW COUNT: 1~~ + +INSERT INTO TINYINT_dt(a) values(1000) +~~ERROR (Code: 220)~~ +~~ERROR (Message: 'value for domain tinyint violates check constraint "tinyint_check"DB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n')~~ + +INSERT INTO TINYINT_dt(a) values(255) +~~ROW COUNT: 1~~ + +INSERT INTO TINYINT_dt(a) values(NULL) +~~ROW COUNT: 1~~ + +SELECT * FROM TINYINT_dt; +~~START~~ +int +0 +100 +2 +29 +4 +87 +0 +255 + +0 +120 +100 +4 +0 +2 +86 +255 + +~~END~~ + +~~ROW COUNT: 18~~ + +DROP TABLE TINYINT_dt; diff --git a/contrib/test/python/expected/pymssql/TestTransactionSupportForProcedure.out b/contrib/test/python/expected/pymssql/TestTransactionSupportForProcedure.out new file mode 100644 index 00000000000..e84887c7c02 --- /dev/null +++ b/contrib/test/python/expected/pymssql/TestTransactionSupportForProcedure.out @@ -0,0 +1,1096 @@ +#setup +create table txnproctable (c1 int not null, c2 varchar(100)) + +# PROC +# BEGIN TRAN +# SAVEPOINT +# ROLLBACK SAVEPOINT +# COMMIT +create procedure txnproc1 as begin tran; insert into txnproctable values (1, 'abc'); save tran sp1; update txnproctable set c1 = c1 + 1; rollback tran sp1; commit tran; +select @@trancount; +~~START~~ +int +0 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#int +~~END~~ + +exec txnproc1; +select @@trancount; +~~START~~ +int +0 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#int +1#!#abc +~~END~~ + +~~ROW COUNT: 1~~ + + + +# PROC +# BEGIN TRAN +# SAVEPOINT +# ROLLBACK SAVEPOINT +# ROLLBACK +drop procedure txnproc1; +create procedure txnproc1 as begin tran; insert into txnproctable values(2, 'xyz'); save tran sp1; delete from txnproctable; rollback tran sp1; rollback tran; +select @@trancount; +~~START~~ +int +0 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#int +1#!#abc +~~END~~ + +~~ROW COUNT: 1~~ + +exec txnproc1; +select @@trancount; +~~START~~ +int +0 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#int +1#!#abc +~~END~~ + +~~ROW COUNT: 1~~ + + + +# PROC +# BEGIN TRAN +# SAVEPOINT +# ROLLBACK SAVEPOINT +# COMMIT +drop procedure txnproc1 +create procedure txnproc1 as begin tran; insert into txnproctable values(3, 'dbd'); save tran sp1; update txnproctable set c1 = c1 + 1; rollback tran sp1; +select @@trancount +~~START~~ +int +0 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#int +1#!#abc +~~END~~ + +~~ROW COUNT: 1~~ + +exec txnproc1; +~~ERROR (Code: 266)~~ +~~ERROR (Message: 'Transaction count after execution indicates a mismatch number of BEGIN and COMMIT statements. Previous count 0 current count 1DB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n')~~ + +select @@trancount +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#int +1#!#abc +3#!#dbd +~~END~~ + +~~ROW COUNT: 2~~ + +commit tran; +select @@trancount +~~START~~ +int +0 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#int +1#!#abc +3#!#dbd +~~END~~ + +~~ROW COUNT: 2~~ + + + +# PROC +# BEGIN TRAN +# SAVEPOINT +# ROLLBACK SAVEPOINT +# COMMIT +drop procedure txnproc1 +create procedure txnproc1 as begin tran; insert into txnproctable values(4, 'sbd'); save tran sp1; update txnproctable set c1 = c1 + 1; +select @@trancount +~~START~~ +int +0 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#int +1#!#abc +3#!#dbd +~~END~~ + +~~ROW COUNT: 2~~ + +exec txnproc1; +~~ERROR (Code: 266)~~ +~~ERROR (Message: 'Transaction count after execution indicates a mismatch number of BEGIN and COMMIT statements. Previous count 0 current count 1DB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n')~~ + +select @@trancount +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#int +2#!#abc +4#!#dbd +5#!#sbd +~~END~~ + +~~ROW COUNT: 3~~ + +rollback tran sp1; +select @@trancount +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#int +1#!#abc +3#!#dbd +4#!#sbd +~~END~~ + +~~ROW COUNT: 3~~ + +commit tran; +select @@trancount +~~START~~ +int +0 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#int +1#!#abc +3#!#dbd +4#!#sbd +~~END~~ + +~~ROW COUNT: 3~~ + + + +# BEGIN TRAN +# PROC +# SAVEPOINT +# ROLLBACK SAVEPOINT +# COMMIT +begin tran; +select @@trancount +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#int +1#!#abc +3#!#dbd +4#!#sbd +~~END~~ + +~~ROW COUNT: 3~~ + +drop procedure txnproc1 +create procedure txnproc1 as insert into txnproctable values(5, 'abc'); save tran sp1; update txnproctable set c1 = c1 + 1; rollback tran sp1; +select @@trancount +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#int +1#!#abc +3#!#dbd +4#!#sbd +~~END~~ + +~~ROW COUNT: 3~~ + +exec txnproc1; +select @@trancount +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#int +1#!#abc +3#!#dbd +4#!#sbd +5#!#abc +~~END~~ + +~~ROW COUNT: 4~~ + +commit tran; +select @@trancount +~~START~~ +int +0 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#int +1#!#abc +3#!#dbd +4#!#sbd +5#!#abc +~~END~~ + +~~ROW COUNT: 4~~ + + + +# BEGIN TRAN +# PROC +# SAVEPOINT +# ROLLBACK SAVEPOINT +# ROLLBACK +begin tran; +select @@trancount +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#int +1#!#abc +3#!#dbd +4#!#sbd +5#!#abc +~~END~~ + +~~ROW COUNT: 4~~ + +drop procedure txnproc1 +create procedure txnproc1 as insert into txnproctable values(6, 'abc'); save tran sp1; update txnproctable set c1 = c1 + 1; rollback tran sp1; +select @@trancount +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#int +1#!#abc +3#!#dbd +4#!#sbd +5#!#abc +~~END~~ + +~~ROW COUNT: 4~~ + +exec txnproc1; +select @@trancount +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#int +1#!#abc +3#!#dbd +4#!#sbd +5#!#abc +6#!#abc +~~END~~ + +~~ROW COUNT: 5~~ + +commit tran; +select @@trancount +~~START~~ +int +0 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#int +1#!#abc +3#!#dbd +4#!#sbd +5#!#abc +6#!#abc +~~END~~ + +~~ROW COUNT: 5~~ + + +# BEGIN TRAN +# PROC +# SAVEPOINT +# ROLLBACK SAVEPOINT +# COMMIT +begin tran; +select @@trancount +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#int +1#!#abc +3#!#dbd +4#!#sbd +5#!#abc +6#!#abc +~~END~~ + +~~ROW COUNT: 5~~ + +drop procedure txnproc1 +create procedure txnproc1 as insert into txnproctable values(7, 'abc'); save tran sp1; update txnproctable set c1 = c1 + 1; rollback tran sp1; update txnproctable set c1 = c1 + 1; commit tran; +select @@trancount +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#int +1#!#abc +3#!#dbd +4#!#sbd +5#!#abc +6#!#abc +~~END~~ + +~~ROW COUNT: 5~~ + +exec txnproc1; +~~ERROR (Code: 266)~~ +~~ERROR (Message: 'Transaction count after execution indicates a mismatch number of BEGIN and COMMIT statements. Previous count 1 current count 0DB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n')~~ + +select @@trancount +~~START~~ +int +0 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#int +2#!#abc +4#!#dbd +5#!#sbd +6#!#abc +7#!#abc +8#!#abc +~~END~~ + +~~ROW COUNT: 6~~ + + +# BEGIN TRAN +# PROC +# SAVEPOINT +# ROLLBACK SAVEPOINT +# ROLLBACK +begin tran; +select @@trancount +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#int +2#!#abc +4#!#dbd +5#!#sbd +6#!#abc +7#!#abc +8#!#abc +~~END~~ + +~~ROW COUNT: 6~~ + +drop procedure txnproc1 +create procedure txnproc1 as insert into txnproctable values(8, 'abc'); save tran sp1; update txnproctable set c1 = c1 + 1; rollback tran sp1; update txnproctable set c1 = c1 + 1; rollback tran; +select @@trancount +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#int +2#!#abc +4#!#dbd +5#!#sbd +6#!#abc +7#!#abc +8#!#abc +~~END~~ + +~~ROW COUNT: 6~~ + +exec txnproc1; +~~ERROR (Code: 266)~~ +~~ERROR (Message: 'Transaction count after execution indicates a mismatch number of BEGIN and COMMIT statements. Previous count 1 current count 0DB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n')~~ + +select @@trancount +~~START~~ +int +0 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#int +2#!#abc +4#!#dbd +5#!#sbd +6#!#abc +7#!#abc +8#!#abc +~~END~~ + +~~ROW COUNT: 6~~ + + +# BEGIN TRAN +# START SAVEPOINT +# PROC +# ROLLBACK SAVEPOINT +# ROLLBACK +begin tran; +select @@trancount +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#int +2#!#abc +4#!#dbd +5#!#sbd +6#!#abc +7#!#abc +8#!#abc +~~END~~ + +~~ROW COUNT: 6~~ + +save tran sp1; +select @@trancount +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#int +2#!#abc +4#!#dbd +5#!#sbd +6#!#abc +7#!#abc +8#!#abc +~~END~~ + +~~ROW COUNT: 6~~ + +drop procedure txnproc1 +create procedure txnproc1 as insert into txnproctable values(9, 'abc'); update txnproctable set c1 = c1 + 1; +select @@trancount +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#int +2#!#abc +4#!#dbd +5#!#sbd +6#!#abc +7#!#abc +8#!#abc +~~END~~ + +~~ROW COUNT: 6~~ + +exec txnproc1; +~~ROW COUNT: 7~~ + +rollback tran sp1; +select @@trancount +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#int +2#!#abc +4#!#dbd +5#!#sbd +6#!#abc +7#!#abc +8#!#abc +~~END~~ + +~~ROW COUNT: 6~~ + +rollback tran; +select @@trancount +~~START~~ +int +0 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#int +2#!#abc +4#!#dbd +5#!#sbd +6#!#abc +7#!#abc +8#!#abc +~~END~~ + +~~ROW COUNT: 6~~ + + +# BEGIN TRAN +# START SAVEPOINT +# PROC +# ROLLBACK SAVEPOINT +# ROLLBACK +begin tran; +select @@trancount +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#int +2#!#abc +4#!#dbd +5#!#sbd +6#!#abc +7#!#abc +8#!#abc +~~END~~ + +~~ROW COUNT: 6~~ + +save tran sp1; +select @@trancount +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#int +2#!#abc +4#!#dbd +5#!#sbd +6#!#abc +7#!#abc +8#!#abc +~~END~~ + +~~ROW COUNT: 6~~ + +drop procedure txnproc1 +create procedure txnproc1 as insert into txnproctable values(10, 'abc'); update txnproctable set c1 = c1 + 1; +select @@trancount +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#int +2#!#abc +4#!#dbd +5#!#sbd +6#!#abc +7#!#abc +8#!#abc +~~END~~ + +~~ROW COUNT: 6~~ + +exec txnproc1; +~~ROW COUNT: 7~~ + +rollback tran sp1; +select @@trancount +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#int +2#!#abc +4#!#dbd +5#!#sbd +6#!#abc +7#!#abc +8#!#abc +~~END~~ + +~~ROW COUNT: 6~~ + +commit tran; +select @@trancount +~~START~~ +int +0 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#int +2#!#abc +4#!#dbd +5#!#sbd +6#!#abc +7#!#abc +8#!#abc +~~END~~ + +~~ROW COUNT: 6~~ + + +# BEGIN TRAN +# START SAVEPOINT +# PROC +# ROLLBACK SAVEPOINT +# ROLLBACK +begin tran; +select @@trancount +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#int +2#!#abc +4#!#dbd +5#!#sbd +6#!#abc +7#!#abc +8#!#abc +~~END~~ + +~~ROW COUNT: 6~~ + +save tran sp1; +select @@trancount +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#int +2#!#abc +4#!#dbd +5#!#sbd +6#!#abc +7#!#abc +8#!#abc +~~END~~ + +~~ROW COUNT: 6~~ + +drop procedure txnproc1 +create procedure txnproc1 as insert into txnproctable values(11, 'abc'); rollback tran sp1; update txnproctable set c1 = c1 + 1; +select @@trancount +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#int +2#!#abc +4#!#dbd +5#!#sbd +6#!#abc +7#!#abc +8#!#abc +~~END~~ + +~~ROW COUNT: 6~~ + +exec txnproc1; +~~ROW COUNT: 6~~ + +commit tran; +select @@trancount +~~START~~ +int +0 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#int +3#!#abc +5#!#dbd +6#!#sbd +7#!#abc +8#!#abc +9#!#abc +~~END~~ + +~~ROW COUNT: 6~~ + + +# PROC1 +# BEGIN TRAN +# PROC2 +# PROC3 +# BEGIN TRAN +# START SAVEPOINT +# ROLLBACK SAVEPOINT +# COMMIT +# COMMIT +create procedure txnProc3 as begin tran; insert into txnproctable values (16, 'abc'); save tran sp1; update txnproctable set c1 = c1 + 1; rollback tran sp1; +select @@trancount +~~START~~ +int +0 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#int +3#!#abc +5#!#dbd +6#!#sbd +7#!#abc +8#!#abc +9#!#abc +~~END~~ + +~~ROW COUNT: 6~~ + +create procedure txnProc2 as update txnproctable set c1 = c1 + 1; exec txnProc3; commit tran; +select @@trancount +~~START~~ +int +0 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#int +3#!#abc +5#!#dbd +6#!#sbd +7#!#abc +8#!#abc +9#!#abc +~~END~~ + +~~ROW COUNT: 6~~ + +drop procedure txnproc1 +create procedure txnproc1 as delete from txnproctable; begin tran; exec txnProc2; +select @@trancount +~~START~~ +int +0 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#int +3#!#abc +5#!#dbd +6#!#sbd +7#!#abc +8#!#abc +9#!#abc +~~END~~ + +~~ROW COUNT: 6~~ + +exec txnproc1; +~~ERROR (Code: 266)~~ +~~ERROR (Message: 'Transaction count after execution indicates a mismatch number of BEGIN and COMMIT statements. Previous count 1 current count 2DB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\nDB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n')~~ + +select @@trancount +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#int +16#!#abc +~~END~~ + +~~ROW COUNT: 1~~ + +commit tran; +select @@trancount +~~START~~ +int +0 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#int +16#!#abc +~~END~~ + +~~ROW COUNT: 1~~ + + +# PROC1 +# BEGIN TRAN +# PROC2 +# PROC3 +# BEGIN TRAN +# START SAVEPOINT +# ROLLBACK SAVEPOINT +# ROLLBACK TRAN +# COMMIT +drop procedure txnproc3 +create procedure txnProc3 as begin tran; insert into txnproctable values (20, 'abc'); save tran sp1; update txnproctable set c1 = c1 + 1; rollback tran sp1; +select @@trancount +~~START~~ +int +0 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#int +16#!#abc +~~END~~ + +~~ROW COUNT: 1~~ + +drop procedure txnproc2 +create procedure txnProc2 as update txnproctable set c1 = c1 + 1; exec txnProc3; rollback tran; +select @@trancount +~~START~~ +int +0 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#int +16#!#abc +~~END~~ + +~~ROW COUNT: 1~~ + +drop procedure txnproc1 +create procedure txnproc1 as delete from txnproctable; begin tran; exec txnProc2; +select @@trancount +~~START~~ +int +0 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#int +16#!#abc +~~END~~ + +~~ROW COUNT: 1~~ + +exec txnproc1; +~~ERROR (Code: 266)~~ +~~ERROR (Message: 'Transaction count after execution indicates a mismatch number of BEGIN and COMMIT statements. Previous count 1 current count 2DB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\nDB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n')~~ + +select @@trancount +~~START~~ +int +0 +~~END~~ + +~~ROW COUNT: 1~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#int +~~END~~ + + +#cleanup +drop procedure txnproc3 +drop procedure txnproc2 +drop procedure txnproc1 +drop table txnproctable diff --git a/contrib/test/python/expected/pymssql/TestTransactionsSQLBatch.out b/contrib/test/python/expected/pymssql/TestTransactionsSQLBatch.out new file mode 100644 index 00000000000..f0c991b7a91 --- /dev/null +++ b/contrib/test/python/expected/pymssql/TestTransactionsSQLBatch.out @@ -0,0 +1,564 @@ +create table TxnTable(c1 int); + +# Begin transaction -> commit transaction +begin transaction; +select @@trancount; +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +begin transaction; +select @@trancount; +~~START~~ +int +2 +~~END~~ + +~~ROW COUNT: 1~~ + +set transaction isolation level read committed; +#show transaction_isolation; +#show default_transaction_isolation; +insert into TxnTable values(1); +~~ROW COUNT: 1~~ + +commit transaction; +select @@trancount; +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +commit transaction; +select @@trancount; +~~START~~ +int +0 +~~END~~ + +~~ROW COUNT: 1~~ + +select c1 from TxnTable; +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + + +# Begin transaction -> rollback transaction +begin transaction; +insert into TxnTable values(2); +~~ROW COUNT: 1~~ + +rollback transaction; +select c1 from TxnTable; +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + + +#Begin tran -> commit tran +begin tran; +insert into TxnTable values(2); +~~ROW COUNT: 1~~ + +commit tran; +select c1 from TxnTable; +~~START~~ +int +1 +2 +~~END~~ + +~~ROW COUNT: 2~~ + + +# Begin tran -> rollback tran +begin tran; +select @@trancount; +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +begin tran; +set transaction isolation level read uncommitted; +#show transaction_isolation; +#show default_transaction_isolation; +insert into TxnTable values(3); +~~ROW COUNT: 1~~ + +select @@trancount; +~~START~~ +int +2 +~~END~~ + +~~ROW COUNT: 1~~ + +rollback tran; +select @@trancount; +~~START~~ +int +0 +~~END~~ + +~~ROW COUNT: 1~~ + +select c1 from TxnTable; +~~START~~ +int +1 +2 +~~END~~ + +~~ROW COUNT: 2~~ + + +set transaction isolation level repeatable read; +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: 'REPEATABLE READ isolation level is not supportedDB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n')~~ + +#show transaction_isolation; +#show default_transaction_isolation; + +# Begin transaction -> commit +begin transaction; +insert into TxnTable values(4); +~~ROW COUNT: 1~~ + +commit; +select c1 from TxnTable; +~~START~~ +int +1 +2 +4 +~~END~~ + +~~ROW COUNT: 3~~ + + +# Begin transaction -> commit work +begin transaction; +insert into TxnTable values(5); +~~ROW COUNT: 1~~ + +commit work; +select c1 from TxnTable; +~~START~~ +int +1 +2 +4 +5 +~~END~~ + +~~ROW COUNT: 4~~ + + +# Begin transaction -> rollback +begin transaction; +insert into TxnTable values(6); +~~ROW COUNT: 1~~ + +rollback; +select c1 from TxnTable; +~~START~~ +int +1 +2 +4 +5 +~~END~~ + +~~ROW COUNT: 4~~ + + +# Begin transaction -> rollback work +begin transaction; +insert into TxnTable values(7); +~~ROW COUNT: 1~~ + +rollback work; +select c1 from TxnTable; +~~START~~ +int +1 +2 +4 +5 +~~END~~ + +~~ROW COUNT: 4~~ + + +# Begin transaction name -> commit transaction name +begin transaction txn1; +insert into TxnTable values(8); +~~ROW COUNT: 1~~ + +commit transaction txn1; +select c1 from TxnTable; +~~START~~ +int +1 +2 +4 +5 +8 +~~END~~ + +~~ROW COUNT: 5~~ + + +# Begin transaction name -> rollback transaction name +begin transaction txn1; +insert into TxnTable values(9); +~~ROW COUNT: 1~~ + +rollback transaction txn1; +select c1 from TxnTable; +~~START~~ +int +1 +2 +4 +5 +8 +~~END~~ + +~~ROW COUNT: 5~~ + + +# Begin tran name -> commit tran name +begin tran txn1; +insert into TxnTable values(10); +~~ROW COUNT: 1~~ + +commit tran txn1; +select c1 from TxnTable; +~~START~~ +int +1 +2 +4 +5 +8 +10 +~~END~~ + +~~ROW COUNT: 6~~ + + +# Begin tran name -> rollback tran name +begin tran txn1; +insert into TxnTable values(10); +~~ROW COUNT: 1~~ + +rollback tran txn1; +select c1 from TxnTable; +~~START~~ +int +1 +2 +4 +5 +8 +10 +~~END~~ + +~~ROW COUNT: 6~~ + + +truncate table TxnTable; + +# save tran name -> rollback tran name +set transaction isolation level snapshot; +#show transaction_isolation; +#show default_transaction_isolation; +begin transaction txn1; +insert into TxnTable values(1); +~~ROW COUNT: 1~~ + +save transaction sp1; +select @@trancount; +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +insert into TxnTable values(2); +~~ROW COUNT: 1~~ + +save tran sp2; +insert into TxnTable values(3); +~~ROW COUNT: 1~~ + +save tran sp2; +select @@trancount; +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +insert into TxnTable values(4); +~~ROW COUNT: 1~~ + +select c1 from TxnTable; +~~START~~ +int +1 +2 +3 +4 +~~END~~ + +~~ROW COUNT: 4~~ + +rollback tran sp2; +select @@trancount; +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +select c1 from TxnTable; +~~START~~ +int +1 +2 +3 +~~END~~ + +~~ROW COUNT: 3~~ + +rollback tran sp2; +select @@trancount; +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +select c1 from TxnTable; +~~START~~ +int +1 +2 +~~END~~ + +~~ROW COUNT: 2~~ + +rollback tran sp1; +select @@trancount; +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +select c1 from TxnTable; +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +rollback tran txn1; +select @@trancount; +~~START~~ +int +0 +~~END~~ + +~~ROW COUNT: 1~~ + +select c1 from TxnTable; +~~START~~ +int +~~END~~ + + +# begin transaction name -> save transaction name -> rollback to first savepoint +begin transaction txn1; +insert into TxnTable values(1); +~~ROW COUNT: 1~~ + +save transaction sp1; +insert into TxnTable values(2); +~~ROW COUNT: 1~~ + +save transaction sp2; +insert into TxnTable values(3); +~~ROW COUNT: 1~~ + +save transaction sp3; +insert into TxnTable values(4); +~~ROW COUNT: 1~~ + +rollback tran sp1; +#rollback tran sp1; -- this will give an error +rollback tran; +select c1 from TxnTable; +~~START~~ +int +~~END~~ + + +# begin transaction name -> save transaction name -> rollback tran name, Rollback whole transaction +set transaction isolation level serializable; +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: 'SERIALIZABLE isolation level is not supportedDB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n')~~ + +#show transaction_isolation; +#show default_transaction_isolation; +begin transaction txn1; +insert into TxnTable values(1); +~~ROW COUNT: 1~~ + +save transaction sp1; +begin transaction txn1; +insert into TxnTable values(2); +~~ROW COUNT: 1~~ + +save transaction sp1; +insert into TxnTable values(3); +~~ROW COUNT: 1~~ + +select @@trancount; +~~START~~ +int +2 +~~END~~ + +~~ROW COUNT: 1~~ + +rollback tran txn1; +select @@trancount; +~~START~~ +int +0 +~~END~~ + +~~ROW COUNT: 1~~ + +select c1 from TxnTable; +~~START~~ +int +~~END~~ + + +# begin transaction -> save transaction name -> rollback to savepoint, commit transaction +begin transaction txn1; +insert into TxnTable values(1); +~~ROW COUNT: 1~~ + +save transaction sp1; +insert into TxnTable values(2); +~~ROW COUNT: 1~~ + +select c1 from TxnTable; +~~START~~ +int +1 +2 +~~END~~ + +~~ROW COUNT: 2~~ + +rollback tran sp1; +commit transaction; +select c1 from TxnTable; +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + + +# begin transaction -> save transaction name -> rollback to savepoint +# save transaction name -> commit transaction +begin transaction txn1; +insert into TxnTable values(3); +~~ROW COUNT: 1~~ + +save transaction sp1; +insert into TxnTable values(4); +~~ROW COUNT: 1~~ + +select c1 from TxnTable; +~~START~~ +int +1 +3 +4 +~~END~~ + +~~ROW COUNT: 3~~ + +rollback tran sp1; +save transaction sp2; +insert into TxnTable values(5); +~~ROW COUNT: 1~~ + +commit transaction; +select c1 from TxnTable; +~~START~~ +int +1 +3 +5 +~~END~~ + +~~ROW COUNT: 3~~ + + +# begin transaction -> save transaction name -> error -> rollback to savepoint +# commit transaction +begin transaction txn1; +insert into TxnTable values(6); +~~ROW COUNT: 1~~ + +save transaction sp1; +insert into TxnTable values(7); +~~ROW COUNT: 1~~ + +#select c1 frm TxnTable; -- error +rollback tran sp1; +commit transaction; +select c1 from TxnTable; +~~START~~ +int +1 +3 +5 +6 +~~END~~ + +~~ROW COUNT: 4~~ + + +Drop table TxnTable; diff --git a/contrib/test/python/expected/pymssql/TestUDD.out b/contrib/test/python/expected/pymssql/TestUDD.out new file mode 100644 index 00000000000..7a013bfaed6 --- /dev/null +++ b/contrib/test/python/expected/pymssql/TestUDD.out @@ -0,0 +1,132 @@ +CREATE TYPE udd_varchar from varchar(15); +CREATE TYPE udd_nvarchar from nvarchar(15); +CREATE TYPE udd_int from int; +CREATE TYPE udd_char from char(25); +CREATE TYPE udd_nchar from nchar(20) NOT NULL; +CREATE TYPE udd_datetime from datetime; +CREATE TYPE udd_numeric from numeric(4,1); + +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_unique_constraint', 'ignore'; +CREATE TABLE udd_dt (a udd_varchar UNIQUE, b udd_nvarchar, c udd_int PRIMARY KEY, d udd_char DEFAULT 'Whoops!', e udd_nchar, f udd_datetime, g udd_numeric CHECK (g >= 103.5)) + +INSERT INTO udd_dt VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +~~ROW COUNT: 1~~ + + +#passing a non unique value in column a +#throws error: duplicate key value violates unique constraint +INSERT INTO udd_dt VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); +~~ERROR (Code: 2627)~~ +~~ERROR (Message: 'duplicate key value violates unique constraint "udd_dt_a_key"DB-Lib error message 20018, severity 14:\nGeneral SQL Server error: Check messages from the SQL Server\n')~~ + + +#passing a non unique value in column c +#throws error: duplicate key value violates unique constraint +INSERT INTO udd_dt VALUES ('Banana', N'green', 1, 'Bangalore', N'Crying😭', '2007-01-14 23:34:23.749', 908.7); +~~ERROR (Code: 2627)~~ +~~ERROR (Message: 'duplicate key value violates unique constraint "udd_dt_pkey"DB-Lib error message 20018, severity 14:\nGeneral SQL Server error: Check messages from the SQL Server\n')~~ + + +#passing a NULL value in column c +#throws error: null value in column "c" violates not-null constraint +INSERT INTO udd_dt VALUES ('Guava', N'yellow', NULL, 'Mumbai', N'Smirk😏', '1907-05-09 11:14:13.749', 245.6); +~~ERROR (Code: 515)~~ +~~ERROR (Message: 'null value in column "c" of relation "udd_dt" violates not-null constraintDB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n')~~ + + +#passing no value for column d +INSERT INTO udd_dt(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +~~ROW COUNT: 1~~ + + +#passing a NULL value in column e +#throws error: domain udd_nchar does not allow null values +INSERT INTO udd_dt VALUES ('Kiwi', N'purple', 4, 'Kolkata', NULL, '1907-05-09 11:14:13.749', 874.0); +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: 'domain udd_nchar does not allow null valuesDB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n')~~ + + +#passing a value less than 103.5 in column g +#throws error: new row for relation "udd_dt" violates check constraint "udd_dt_g_check" +INSERT INTO udd_dt VALUES ('Grape', N'white', 5, 'Pune', N'Angry😠', '2000-02-28 23:59:59.989', 100.1); +~~ERROR (Code: 547)~~ +~~ERROR (Message: 'new row for relation "udd_dt" violates check constraint "udd_dt_g_check"DB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n')~~ + + +SELECT * FROM udd_dt; +~~START~~ +int#!#int#!#int#!#int#!#int#!#int#!#int +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123000#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.990000#!#342.5 +~~END~~ + +~~ROW COUNT: 2~~ + + +DROP TABLE udd_dt; + +CREATE TABLE udd_dt (a udd_varchar UNIQUE, b udd_nvarchar, c udd_int PRIMARY KEY, d udd_char DEFAULT 'Whoops!', e udd_nchar, f udd_datetime, g udd_numeric CHECK (g >= 103.5)) + +prepst#!#INSERT INTO udd_dt VALUES (%s, %s, %s, %s, %s, %s, %s)#!#varchar|-|a|-|Apple#!#nvarchar|-|b|-|red#!#int|-|c|-|1#!#char|-|d|-|Delhi#!#nchar|-|e|-|Sad😞#!#datetime|-|f|-|2000-12-13 12:58:23.123#!#numeric|-|g|-|123.1|-|4|-|1 +~~ROW COUNT: 1~~ + + +#passing a non unique value in column a +#throws error: duplicate key value violates unique constraint +prepst#!#exec#!#varchar|-|a|-|Apple#!#nvarchar|-|b|-|blue#!#int|-|c|-|2#!#char|-|d|-|Chennai#!#nchar|-|e|-|Neutral😐#!#datetime|-|f|-|2006-11-11 22:47:23.128#!#numeric|-|g|-|512.4|-|4|-|1 +~~ERROR (Code: 2627)~~ +~~ERROR (Message: 'duplicate key value violates unique constraint "udd_dt_a_key"DB-Lib error message 20018, severity 14:\nGeneral SQL Server error: Check messages from the SQL Server\n')~~ + + +#passing a non unique value in column c +#throws error: duplicate key value violates unique constraint +prepst#!#exec#!#varchar|-|a|-|Banana#!#nvarchar|-|b|-|green#!#int|-|c|-|1#!#char|-|d|-|Bangalore#!#nchar|-|e|-|Crying😭#!#datetime|-|f|-|2007-01-14 23:34:23.749#!#numeric|-|g|-|908.7|-|4|-|1 +~~ERROR (Code: 2627)~~ +~~ERROR (Message: 'duplicate key value violates unique constraint "udd_dt_pkey"DB-Lib error message 20018, severity 14:\nGeneral SQL Server error: Check messages from the SQL Server\n')~~ + + +#passing a NULL value in column c +#throws error: null value in column "c" violates not-null constraint +prepst#!#exec#!#varchar|-|a|-|Guava#!#nvarchar|-|b|-|yellow#!#int|-|c|-|#!#char|-|d|-|Mumbai#!#nchar|-|e|-|Smirk😏'#!#datetime|-|f|-|1907-05-09 11:14:13.749#!#numeric|-|g|-|245.6|-|4|-|1 +~~ERROR (Code: 515)~~ +~~ERROR (Message: 'null value in column "c" of relation "udd_dt" violates not-null constraintDB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n')~~ + + +#passing a NULL value in column e +#throws error: domain udd_nchar does not allow null values +prepst#!#exec#!#varchar|-|a|-|Kiwi#!#nvarchar|-|b|-|purple#!#int|-|c|-|4#!#char|-|d|-|Kolkata#!#nchar|-|e|-|#!#datetime|-|f|-|1907-05-09 11:14:13.749#!#numeric|-|g|-|874.0|-|4|-|1 +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: 'domain udd_nchar does not allow null valuesDB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n')~~ + + +#passing a value less than 103.5 in column g +#throws error: new row for relation "udd_dt" violates check constraint "udd_dt_g_check" +prepst#!#exec#!#varchar|-|a|-|Grape#!#nvarchar|-|b|-|white#!#int|-|c|-|5#!#char|-|d|-|Pune#!#nchar|-|e|-|Angry😠#!#datetime|-|f|-|2000-02-28 23:59:59.989#!#numeric|-|g|-|100.1|-|4|-|1 +~~ERROR (Code: 547)~~ +~~ERROR (Message: 'new row for relation "udd_dt" violates check constraint "udd_dt_g_check"DB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n')~~ + + +#passing no value for column d +prepst#!#INSERT INTO udd_dt(a, b, c, e, f, g) VALUES (%s, %s, %s, %s, %s, %s)#!#varchar|-|a1|-|Orange#!#nvarchar|-|b1|-|#!#int|-|c1|-|5#!#nchar|-|e1|-|Happy😀#!#datetime|-|f1|-|1900-02-28 23:59:59.989#!#numeric|-|g1|-|342.5|-|4|-|1 +~~ROW COUNT: 1~~ + + +SELECT * FROM udd_dt; +~~START~~ +int#!#int#!#int#!#int#!#int#!#int#!#int +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123000#!#123.1 +Orange#!##!#5#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.990000#!#342.5 +~~END~~ + +~~ROW COUNT: 2~~ + + +DROP TABLE udd_dt; + +DROP TYPE udd_varchar +DROP TYPE udd_nvarchar +DROP TYPE udd_int +DROP TYPE udd_char +DROP TYPE udd_nchar +DROP TYPE udd_datetime +DROP TYPE udd_numeric diff --git a/contrib/test/python/expected/pymssql/TestUniqueIdentifier.out b/contrib/test/python/expected/pymssql/TestUniqueIdentifier.out new file mode 100644 index 00000000000..08bb4adfc1b --- /dev/null +++ b/contrib/test/python/expected/pymssql/TestUniqueIdentifier.out @@ -0,0 +1,157 @@ +CREATE TABLE uniqueidentifier_dt (a uniqueidentifier); + +INSERT INTO uniqueidentifier_dt VALUES ('51f178a6-53c7-472c-9be1-1c08942342d7') +~~ROW COUNT: 1~~ + +INSERT INTO uniqueidentifier_dt VALUES ('dd8cb046-461d-411e-be40-d219252ce849') +~~ROW COUNT: 1~~ + +INSERT INTO uniqueidentifier_dt VALUES ('b84ebcc9-c927-4cfe-b08e-dc7f25b5087c') +~~ROW COUNT: 1~~ + +INSERT INTO uniqueidentifier_dt VALUES ('bab96bc8-60b9-40dd-b0de-c90a80f5739e') +~~ROW COUNT: 1~~ + +INSERT INTO uniqueidentifier_dt VALUES ('d424fdef-1404-4bac-8289-c725b540f93d') +~~ROW COUNT: 1~~ + +INSERT INTO uniqueidentifier_dt VALUES ('60aeaa5c-e272-4b17-bad0-c25710fd7a60') +~~ROW COUNT: 1~~ + +INSERT INTO uniqueidentifier_dt VALUES ('253fb146-7e45-45ef-9d92-bbe14a8ad1b2') +~~ROW COUNT: 1~~ + +INSERT INTO uniqueidentifier_dt VALUES ('dba2726c-2131-409f-aefa-5c8079571623') +~~ROW COUNT: 1~~ + +INSERT INTO uniqueidentifier_dt VALUES ('b3400fa7-3a60-40ec-b40e-fc85a3eb262d') +~~ROW COUNT: 1~~ + +INSERT INTO uniqueidentifier_dt VALUES ('851763b5-b068-42ae-88ec-764bfb0e5605') +~~ROW COUNT: 1~~ + +INSERT INTO uniqueidentifier_dt VALUES (NULL) +~~ROW COUNT: 1~~ + +SELECT * FROM uniqueidentifier_dt +~~START~~ +int +51f178a6-53c7-472c-9be1-1c08942342d7 +dd8cb046-461d-411e-be40-d219252ce849 +b84ebcc9-c927-4cfe-b08e-dc7f25b5087c +bab96bc8-60b9-40dd-b0de-c90a80f5739e +d424fdef-1404-4bac-8289-c725b540f93d +60aeaa5c-e272-4b17-bad0-c25710fd7a60 +253fb146-7e45-45ef-9d92-bbe14a8ad1b2 +dba2726c-2131-409f-aefa-5c8079571623 +b3400fa7-3a60-40ec-b40e-fc85a3eb262d +851763b5-b068-42ae-88ec-764bfb0e5605 + +~~END~~ + +~~ROW COUNT: 11~~ + + +prepst#!#INSERT INTO uniqueidentifier_dt VALUES (%s)#!#uniqueidentifier|-|a|-|51f178a6-53c7-472c-9be1-1c08942342d7 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#uniqueidentifier|-|a|-|767392df-87d0-450d-9b24-85a86c02811d +~~ROW COUNT: 1~~ + +prepst#!#exec#!#uniqueidentifier|-|a|-|9bcb5632-53c3-4695-b617-d9a7055813ce +~~ROW COUNT: 1~~ + +prepst#!#exec#!#uniqueidentifier|-|a|-|ac81a140-f686-4259-9b90-dd46f10b355f +~~ROW COUNT: 1~~ + +prepst#!#exec#!#uniqueidentifier|-|a|-|3d08372d-770c-48b9-9740-a667d036680e +~~ROW COUNT: 1~~ + +prepst#!#exec#!#uniqueidentifier|-|a|-|518d52c7-4d79-4143-ab33-b3765689fdf4 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#uniqueidentifier|-|a|-|bc3fa456-7391-4060-b5d8-430048075cf4 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#uniqueidentifier|-|a|-|3b75b2dd-01b7-4958-9de7-f92410693547 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#uniqueidentifier|-|a|-|ce8af10a-2709-43b0-9e4e-a02753929d17 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#uniqueidentifier|-|a|-|5b7c2e8d-6d90-411d-8e19-9a81067e6f6c +~~ROW COUNT: 1~~ + +prepst#!#exec#!#uniqueidentifier|-|a|-| +~~ROW COUNT: 1~~ + +SELECT * FROM uniqueidentifier_dt; +~~START~~ +int +51f178a6-53c7-472c-9be1-1c08942342d7 +dd8cb046-461d-411e-be40-d219252ce849 +b84ebcc9-c927-4cfe-b08e-dc7f25b5087c +bab96bc8-60b9-40dd-b0de-c90a80f5739e +d424fdef-1404-4bac-8289-c725b540f93d +60aeaa5c-e272-4b17-bad0-c25710fd7a60 +253fb146-7e45-45ef-9d92-bbe14a8ad1b2 +dba2726c-2131-409f-aefa-5c8079571623 +b3400fa7-3a60-40ec-b40e-fc85a3eb262d +851763b5-b068-42ae-88ec-764bfb0e5605 + +51f178a6-53c7-472c-9be1-1c08942342d7 +767392df-87d0-450d-9b24-85a86c02811d +9bcb5632-53c3-4695-b617-d9a7055813ce +ac81a140-f686-4259-9b90-dd46f10b355f +3d08372d-770c-48b9-9740-a667d036680e +518d52c7-4d79-4143-ab33-b3765689fdf4 +bc3fa456-7391-4060-b5d8-430048075cf4 +3b75b2dd-01b7-4958-9de7-f92410693547 +ce8af10a-2709-43b0-9e4e-a02753929d17 +5b7c2e8d-6d90-411d-8e19-9a81067e6f6c + +~~END~~ + +~~ROW COUNT: 22~~ + + +# to demonstrate the truncation of data when the value is too long +INSERT INTO uniqueidentifier_dt VALUES ('51f178a6-53c7-472c-9be1-1c08942342d7thisIsTooLong') +~~ROW COUNT: 1~~ + +prepst#!#exec#!#uniqueidentifier|-|a|-|767392df-87d0-450d-9b24-85a86c02811dthisIsTooLong +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: "syntax error near '%' at line 1 and character position 40DB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n")~~ + +SELECT * FROM uniqueidentifier_dt; +~~START~~ +int +51f178a6-53c7-472c-9be1-1c08942342d7 +dd8cb046-461d-411e-be40-d219252ce849 +b84ebcc9-c927-4cfe-b08e-dc7f25b5087c +bab96bc8-60b9-40dd-b0de-c90a80f5739e +d424fdef-1404-4bac-8289-c725b540f93d +60aeaa5c-e272-4b17-bad0-c25710fd7a60 +253fb146-7e45-45ef-9d92-bbe14a8ad1b2 +dba2726c-2131-409f-aefa-5c8079571623 +b3400fa7-3a60-40ec-b40e-fc85a3eb262d +851763b5-b068-42ae-88ec-764bfb0e5605 + +51f178a6-53c7-472c-9be1-1c08942342d7 +767392df-87d0-450d-9b24-85a86c02811d +9bcb5632-53c3-4695-b617-d9a7055813ce +ac81a140-f686-4259-9b90-dd46f10b355f +3d08372d-770c-48b9-9740-a667d036680e +518d52c7-4d79-4143-ab33-b3765689fdf4 +bc3fa456-7391-4060-b5d8-430048075cf4 +3b75b2dd-01b7-4958-9de7-f92410693547 +ce8af10a-2709-43b0-9e4e-a02753929d17 +5b7c2e8d-6d90-411d-8e19-9a81067e6f6c + +51f178a6-53c7-472c-9be1-1c08942342d7 +~~END~~ + +~~ROW COUNT: 23~~ + + +DROP TABLE uniqueidentifier_dt; diff --git a/contrib/test/python/expected/pymssql/TestVarChar.out b/contrib/test/python/expected/pymssql/TestVarChar.out new file mode 100644 index 00000000000..7f8911a1ace --- /dev/null +++ b/contrib/test/python/expected/pymssql/TestVarChar.out @@ -0,0 +1,168 @@ +CREATE TABLE VARCHAR_dt (a VARCHAR(20), b NVARCHAR(24)) +prepst#!# INSERT INTO VARCHAR_dt(a, b) values(%s, %s) #!#VARCHAR|-|a|-|Dipesh#!#NVARCHAR|-|b|-|Dhameliya +~~ROW COUNT: 1~~ + +prepst#!#exec#!#VARCHAR|-|a|-| Dipesh #!#NVARCHAR|-|b|-| Dhameliya +~~ROW COUNT: 1~~ + +prepst#!#exec#!#VARCHAR|-|a|-| D#!#NVARCHAR|-|b|-| 🤣😃 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#VARCHAR|-|a|-| #!#NVARCHAR|-|b|-| +~~ROW COUNT: 1~~ + +prepst#!#exec#!#VARCHAR|-|a|-|#!#NVARCHAR|-|b|-| +~~ROW COUNT: 1~~ + +prepst#!#exec#!#VARCHAR|-|a|-|d#!#NVARCHAR|-|b|-|D +~~ROW COUNT: 1~~ + +prepst#!#exec#!#VARCHAR|-|a|-|abcdefghijklmnopqrst#!#NVARCHAR|-|b|-|abcdefghijklmnopqrstuvwx +~~ROW COUNT: 1~~ + +prepst#!#exec#!#VARCHAR|-|a|-|abcdefghijklmnopqrstu#!#NVARCHAR|-|b|-|abcdefghijklmnopqrstuvwxy +~~ERROR (Code: 8152)~~ +~~ERROR (Message: 'value too long for type character varying(20)DB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n')~~ + +prepst#!#exec#!#VARCHAR|-|a|-| #!#NVARCHAR|-|b|-|😊😋😎😍😅😆 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#VARCHAR|-|a|-|#!#NVARCHAR|-|b|-| +~~ROW COUNT: 1~~ + +SELECT * FROM VARCHAR_dt; +~~START~~ +int#!#int +Dipesh#!#Dhameliya + Dipesh #!# Dhameliya + D#!# 🤣😃 + #!# +#!# +d#!#D +abcdefghijklmnopqrst#!#abcdefghijklmnopqrstuvwx + #!#😊😋😎😍😅😆 +#!# +~~END~~ + +~~ROW COUNT: 9~~ + +INSERT INTO VARCHAR_dt(a,b) values('Dipesh','Dhameliya') +~~ROW COUNT: 1~~ + +INSERT INTO VARCHAR_dt(a,b) values(' Dipesh',' Dhameliya') +~~ROW COUNT: 1~~ + +INSERT INTO VARCHAR_dt(a,b) values(' D',N' 🤣😃') +~~ROW COUNT: 1~~ + +INSERT INTO VARCHAR_dt(a,b) values(' ',' ') +~~ROW COUNT: 1~~ + +INSERT INTO VARCHAR_dt(a,b) values(' ',N'😊😋😎😍😅😆') +~~ROW COUNT: 1~~ + +INSERT INTO VARCHAR_dt(a,b) values('','') +~~ROW COUNT: 1~~ + +INSERT INTO VARCHAR_dt(a,b) values('d','D') +~~ROW COUNT: 1~~ + +INSERT INTO VARCHAR_dt(a,b) values('abcdefghijklmnopqrst','abcdefghijklmnopqrstuvwx') +~~ROW COUNT: 1~~ + +#INSERT INTO VARCHAR_dt(a,b) values('abcdefghijklmnopqrstu','abcdefghijklmnopqrstuvwxy') -- for this case, BABEL and SQL both will throw an error +INSERT INTO VARCHAR_dt(a,b) values(NULL,NULL) +~~ROW COUNT: 1~~ + +SELECT * FROM VARCHAR_dt; +~~START~~ +int#!#int +Dipesh#!#Dhameliya + Dipesh #!# Dhameliya + D#!# 🤣😃 + #!# +#!# +d#!#D +abcdefghijklmnopqrst#!#abcdefghijklmnopqrstuvwx + #!#😊😋😎😍😅😆 +#!# +Dipesh#!#Dhameliya + Dipesh#!# Dhameliya + D#!# 🤣😃 + #!# + #!#😊😋😎😍😅😆 +#!# +d#!#D +abcdefghijklmnopqrst#!#abcdefghijklmnopqrstuvwx +#!# +~~END~~ + +~~ROW COUNT: 18~~ + +DROP TABLE VARCHAR_dt; + +CREATE TABLE VARCHAR_dt (a varchar(max), b nvarchar(max)); +INSERT INTO VARCHAR_dt values ('hello', N'hello😃'); +~~ROW COUNT: 1~~ + + +#checking with string of length > 65535 +INSERT INTO VARCHAR_dt values ('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', N'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😃'); +~~ROW COUNT: 1~~ + +INSERT INTO VARCHAR_dt values (NULL, NULL); +~~ROW COUNT: 1~~ + +prepst#!#INSERT INTO VARCHAR_dt values(%s, %s)#!#varchar|-|a|-|hello#!#nvarchar|-|b|-|hello😃 +~~ROW COUNT: 1~~ + + +#checking with string of length > 65535 via prep-exec +prepst#!#exec#!#varchar|-|a|-|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#!#nvarchar|-|b|-|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😃 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#varchar|-|a|-|#!#nvarchar|-|b|-| +~~ROW COUNT: 1~~ + +select * from VARCHAR_dt +~~START~~ +int#!#int +hello#!#hello😃 +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#!#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😃 +#!# +hello#!#hello😃 +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#!#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😃 +#!# +~~END~~ + +~~ROW COUNT: 6~~ + +drop table VARCHAR_dt; + +create table VARCHAR_dt (a varchar(max), b int, c int, d int, e int ,f int, g int, h int, i int); +insert into VARCHAR_dt (a,b,c,d,e,f,g,h,i) values (NULL,1,2,3,4,5,6,7,8); +~~ROW COUNT: 1~~ + +select * from VARCHAR_dt; +~~START~~ +int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int +#!#1#!#2#!#3#!#4#!#5#!#6#!#7#!#8 +~~END~~ + +~~ROW COUNT: 1~~ + +drop table VARCHAR_dt; + +create table VARCHAR_dt (a varchar(10), b int, c int, d int, e int ,f int, g int, h int, i int); +insert into VARCHAR_dt (a,b,c,d,e,f,g,h,i) values (NULL,1,2,3,4,5,6,7,8); +~~ROW COUNT: 1~~ + +select * from VARCHAR_dt; +~~START~~ +int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int +#!#1#!#2#!#3#!#4#!#5#!#6#!#7#!#8 +~~END~~ + +~~ROW COUNT: 1~~ + +drop table VARCHAR_dt; diff --git a/contrib/test/python/expected/pymssql/TestXML.out b/contrib/test/python/expected/pymssql/TestXML.out new file mode 100644 index 00000000000..952a0f145d8 --- /dev/null +++ b/contrib/test/python/expected/pymssql/TestXML.out @@ -0,0 +1,30 @@ +CREATE TABLE XML_dt (a XML) +#prepst#!# INSERT INTO XML_dt values(@a) #!#XML|-|a|-| +#prepst#!# INSERT INTO XML_dt values(@a) #!#XML|-|a|-|Contact Name 2YYY-YYY-YYYY +#prepst#!#exec#!#XML|-|a|-| +SELECT * FROM XML_dt; +~~START~~ +int +~~END~~ + +INSERT INTO XML_dt values('Contact Name 2YYY-YYY-YYYY') +~~ROW COUNT: 1~~ + +INSERT INTO XML_dt values(NULL) +~~ROW COUNT: 1~~ + +#INSERT INTO XML_dt values('') +INSERT INTO XML_dt values(Contact Name 2YYY-YYY-YYYY) +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: "syntax error near '<' at line 1 and character position 26DB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n")~~ + +SELECT * FROM XML_dt; +~~START~~ +int +Contact Name 2YYY-YYY-YYYY + +~~END~~ + +~~ROW COUNT: 2~~ + +DROP TABLE XML_dt; diff --git a/contrib/test/python/expected/pymssql/pg_stat_activity.out b/contrib/test/python/expected/pymssql/pg_stat_activity.out new file mode 100644 index 00000000000..3799f6aa2c3 --- /dev/null +++ b/contrib/test/python/expected/pymssql/pg_stat_activity.out @@ -0,0 +1,79 @@ +SELECT sys.babelfish_set_role(session_user); +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + + +# Babel-1294 Support application_name in pg_stat_activity +select count(*) from pg_stat_activity where pid = pg_backend_pid() and lower(application_name) like 'python%'; +~~START~~ +int +0 +~~END~~ + +~~ROW COUNT: 1~~ + + +# BABEL-1326: Support query in pg_stat_activity +select query from pg_stat_activity where pid = pg_backend_pid(); +~~START~~ +int +select query from pg_stat_activity where pid = pg_backend_pid(); +~~END~~ + +~~ROW COUNT: 1~~ + + +# BABEL-1326: Checking if the right query is returned for Prepexec with batch too +prepst#!#select query from pg_stat_activity where pid = pg_backend_pid();select %s as a#!#int|-|a|-|1 +~~START~~ +int +select query from pg_stat_activity where pid = pg_backend_pid();select 1 as a +~~END~~ + +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +prepst#!#exec#!#int|-|a|-|1 +~~START~~ +int +select query from pg_stat_activity where pid = pg_backend_pid();select 1 as a +~~END~~ + +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + + +# BABEL-1326: Checking if the right query is returned from a procedure and a nested procedure as well +Create procedure proc_pg_stat_activity as begin select query from pg_stat_activity where pid = pg_backend_pid(); end; +exec proc_pg_stat_activity; +~~START~~ +int +exec proc_pg_stat_activity; +~~END~~ + +~~ROW COUNT: 1~~ + +Create procedure proc1_pg_stat_activity as begin exec proc_pg_stat_activity end; +exec proc1_pg_stat_activity; +~~START~~ +int +exec proc1_pg_stat_activity; +~~END~~ + +~~ROW COUNT: 1~~ + + +drop procedure proc_pg_stat_activity; +drop procedure proc1_pg_stat_activity; diff --git a/contrib/test/python/expected/pyodbc/BABEL-1056.out b/contrib/test/python/expected/pyodbc/BABEL-1056.out new file mode 100644 index 00000000000..98d81346f26 --- /dev/null +++ b/contrib/test/python/expected/pyodbc/BABEL-1056.out @@ -0,0 +1,27 @@ +CREATE SCHEMA [Babelfish_1056]; + +CREATE TABLE [Babelfish_1056].[employees] (person_id int IDENTITY PRIMARY KEY, firstname nvarchar(20), lastname nvarchar(30), salary money) +CREATE PROCEDURE p_employee_insert @fname nvarchar(20), @lname nvarchar(30), @sal money AS BEGIN DECLARE @next_pers_id INT; SELECT @next_pers_id = MAX(person_id) FROM [Babelfish_1056].[employees]; IF (@next_pers_id IS NULL) SET @next_pers_id = 0 INSERT INTO [Babelfish_1056].[employees] (person_id, firstname, lastname, salary) VALUES (@next_pers_id+1, @fname, @lname, @sal); END + +SET IDENTITY_INSERT [Babelfish_1056].[employees] ON EXEC p_employee_insert @fname='First', @lname='Employee', @sal=123.1231; SET IDENTITY_INSERT [Babelfish_1056].[employees] OFF +~~ROW COUNT: 1~~ + +SET IDENTITY_INSERT [Babelfish_1056].[employees] ON EXEC p_employee_insert @fname='Second', @lname='Employee', @sal=123.1232; SET IDENTITY_INSERT [Babelfish_1056].[employees] OFF +~~ROW COUNT: 1~~ + +SET IDENTITY_INSERT [Babelfish_1056].[employees] ON EXEC p_employee_insert @fname='Third', @lname='Employee', @sal=123.1233; SET IDENTITY_INSERT [Babelfish_1056].[employees] OFF +~~ROW COUNT: 1~~ + + +SELECT * FROM [Babelfish_1056].[employees] +~~START~~ +int#!#str#!#str#!#Decimal +1#!#First#!#Employee#!#123.1231 +2#!#Second#!#Employee#!#123.1232 +3#!#Third#!#Employee#!#123.1233 +~~END~~ + + +DROP PROCEDURE p_employee_insert +DROP TABLE [Babelfish_1056].[employees] +DROP SCHEMA [Babelfish_1056]; diff --git a/contrib/test/python/expected/pyodbc/BABEL-1270.out b/contrib/test/python/expected/pyodbc/BABEL-1270.out new file mode 100644 index 00000000000..f96d478661e --- /dev/null +++ b/contrib/test/python/expected/pyodbc/BABEL-1270.out @@ -0,0 +1,14 @@ +CREATE TABLE test_cursors_fetch_next(a INT, b SMALLINT, c BIGINT, d TINYINT, e BIT); +INSERT INTO test_cursors_fetch_next values(0, 0, 0, 0, 0) +~~ROW COUNT: 1~~ + +INSERT INTO test_cursors_fetch_next values(NULL, NULL, NULL, NULL, NULL) +~~ROW COUNT: 1~~ + +INSERT INTO test_cursors_fetch_next values(1, 2, 3, 4, 1) +~~ROW COUNT: 1~~ + +INSERT INTO test_cursors_fetch_next values(211234, 9780, 891372401, 56, 1) +~~ROW COUNT: 1~~ + +DROP TABLE test_cursors_fetch_next diff --git a/contrib/test/python/expected/pyodbc/BABEL-1365.out b/contrib/test/python/expected/pyodbc/BABEL-1365.out new file mode 100644 index 00000000000..696904e427c --- /dev/null +++ b/contrib/test/python/expected/pyodbc/BABEL-1365.out @@ -0,0 +1,46 @@ +-- Test normal case: @v = SP_EXECUTESQL 'SQL' +DECLARE @SQLString NVARCHAR(100); +DECLARE @P0 int; +set @SQLString = N'SELECT 123;' +EXEC @P0 = sp_executesql @SQLString; +SELECT @P0; +GO +~~START~~ +int +123 +~~END~~ + +~~START~~ +int +0 +~~END~~ + +-- Test case: @v = SP_EXECUTESQL 'SQL' where @v is implicitly casted to varchar +DECLARE @SQLString NVARCHAR(100); +DECLARE @P0 varchar(3); +set @SQLString = N'SELECT 321;' +EXEC @P0 = sp_executesql @SQLString; +SELECT @P0; +GO +~~START~~ +int +321 +~~END~~ + +~~START~~ +str +0 +~~END~~ + +-- Test case: @v = SP_EXECUTESQL 'SQL' where 'SQL' statement does not return result set +DECLARE @SQLString NVARCHAR(100); +DECLARE @P0 int; +set @SQLString = N'CREATE TABLE t(a INT); DROP TABLE t;'; +EXEC @P0 = sp_executesql @SQLString; +SELECT @P0; +GO +~~START~~ +int +0 +~~END~~ + diff --git a/contrib/test/python/expected/pyodbc/BABEL-1390.out b/contrib/test/python/expected/pyodbc/BABEL-1390.out new file mode 100644 index 00000000000..d308d17bae1 --- /dev/null +++ b/contrib/test/python/expected/pyodbc/BABEL-1390.out @@ -0,0 +1,25 @@ +# Setup a table with some data +CREATE TABLE updatable_cursor_table(a INT, b SMALLINT, c BIGINT, d TINYINT, e BIT); +INSERT INTO updatable_cursor_table values(0, 0, 0, 0, 0) +~~ROW COUNT: 1~~ + +INSERT INTO updatable_cursor_table values(NULL, NULL, NULL, NULL, NULL) +~~ROW COUNT: 1~~ + +INSERT INTO updatable_cursor_table values(1, 2, 3, 4, 1) +~~ROW COUNT: 1~~ + +INSERT INTO updatable_cursor_table values(211234, 9780, 891372401, 56, 1) +~~ROW COUNT: 1~~ + + +# Try opening an updatable cursor using JDBC API + +# Try opening an updatable (i.e. dynamic) cursor using SQL Batch +DECLARE updatable_cursor CURSOR DYNAMIC FOR SELECT a FROM updatable_cursor_table; OPEN updatable_cursor; CLOSE updatable_cursor; DEALLOCATE updatable_cursor; +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]'DYNAMIC CURSOR' is not currently supported in Babelfish (33557097) (SQLExecDirectW))~~ + + +# Drop table +DROP TABLE updatable_cursor_table diff --git a/contrib/test/python/expected/pyodbc/BABEL-1643.out b/contrib/test/python/expected/pyodbc/BABEL-1643.out new file mode 100644 index 00000000000..b25b210391d --- /dev/null +++ b/contrib/test/python/expected/pyodbc/BABEL-1643.out @@ -0,0 +1,14 @@ +exec sp_datatype_info_100 @data_type = 1; +~~START~~ +str#!#int#!#int#!#str#!#str#!#str#!#int#!#int#!#int#!#int#!#int#!#int#!#str#!#int#!#int#!#int#!#int#!#int#!#int#!#int +char#!#1#!#8000#!#'#!#'#!#length #!#1#!#1#!#3#!##!#0#!##!#char#!##!##!#1#!##!##!##!#1 +~~END~~ + + +exec sp_datatype_info @data_type = 2; +~~START~~ +str#!#int#!#int#!#str#!#str#!#str#!#int#!#int#!#int#!#int#!#int#!#int#!#str#!#int#!#int#!#int#!#int#!#int#!#int#!#int +numeric#!#2#!#38#!##!##!#precision,scale #!#1#!#0#!#2#!#0#!#0#!#0#!#numeric#!#0#!#38#!#2#!##!#10#!##!#10 +numeric() identity#!#2#!#38#!##!##!#precision #!#0#!#0#!#2#!#0#!#0#!#1#!#numeric() identity#!#0#!#0#!#2#!##!#10#!##!#10 +~~END~~ + diff --git a/contrib/test/python/expected/pyodbc/TestAuth.out b/contrib/test/python/expected/pyodbc/TestAuth.out new file mode 100644 index 00000000000..3e00aef7f59 --- /dev/null +++ b/contrib/test/python/expected/pyodbc/TestAuth.out @@ -0,0 +1,34 @@ +#database name, username and password should not exceed 128 characters +py_auth#!#database|-|11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +~~ERROR (Code: 3701)~~ +~~ERROR (Message: [42S02] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]database "11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" does not exist (3701) (SQLDriverConnect))~~ + +py_auth#!#database|-|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112 +~~ERROR (Code: 0)~~ +~~ERROR (Message: [08001] [Microsoft][ODBC Driver 17 for SQL Server]Invalid value specified for connection string attribute 'DATABASE' (0) (SQLDriverConnect))~~ + +py_auth#!#user|-|11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]role "111111111111111111111111111111111111111111111111111111111111111" does not exist (33557097) (SQLDriverConnect))~~ + +py_auth#!#user|-|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112 +~~ERROR (Code: 0)~~ +~~ERROR (Message: [08001] [Microsoft][ODBC Driver 17 for SQL Server]Invalid value specified for connection string attribute 'UID' (0) (SQLDriverConnect))~~ + +#not sure why any password is accepted during authentication through cloud desktop +#This test should throw error but from cloud desktop a connection is successfully established +#py_auth#!#password|-|11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +py_auth#!#password|-|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112 +~~ERROR (Code: 0)~~ +~~ERROR (Message: [08001] [Microsoft][ODBC Driver 17 for SQL Server]Invalid value specified for connection string attribute 'PWD' (0) (SQLDriverConnect))~~ + +py_auth#!#others|-|packetSize=0 +~~SUCCESS~~ +py_auth#!#others|-|packetSize=-1 +~~SUCCESS~~ +py_auth#!#others|-|packetSize=4096 +~~SUCCESS~~ +py_auth#!#database|-|test1 SELECT 1 +~~ERROR (Code: 3701)~~ +~~ERROR (Message: [42S02] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]database "test1 select 1" does not exist (3701) (SQLDriverConnect))~~ + diff --git a/contrib/test/python/expected/pyodbc/TestBIT.out b/contrib/test/python/expected/pyodbc/TestBIT.out new file mode 100644 index 00000000000..6eee66b0232 --- /dev/null +++ b/contrib/test/python/expected/pyodbc/TestBIT.out @@ -0,0 +1,44 @@ +CREATE TABLE BIT_dt (a BIT) +prepst#!# INSERT INTO BIT_dt(a) values(?) #!#BIT|-|a|-|false +~~ROW COUNT: 1~~ + +prepst#!#exec#!#BIT|-|a|-|true +~~ROW COUNT: 1~~ + +#next two lines are not allowed +#prepst#!#exec#!#BIT|-|a|-|0 +#prepst#!#exec#!#BIT|-|a|-|1 +prepst#!#exec#!#BIT|-|a|-| +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]column "a" is of type "bit" but expression is of type "varchar" (33557097) (SQLExecDirectW))~~ + +SELECT * FROM BIT_dt; +~~START~~ +bool +False +True +~~END~~ + +INSERT INTO BIT_dt(a) values(1) +~~ROW COUNT: 1~~ + +INSERT INTO BIT_dt(a) values(0) +~~ROW COUNT: 1~~ + +#next two lines are not allowed +#INSERT INTO BIT_dt(a) values(false) +#INSERT INTO BIT_dt(a) values(true) +INSERT INTO BIT_dt(a) values(NULL) +~~ROW COUNT: 1~~ + +SELECT * FROM BIT_dt; +~~START~~ +bool +False +True +True +False + +~~END~~ + +DROP TABLE BIT_dt; diff --git a/contrib/test/python/expected/pyodbc/TestBigInt.out b/contrib/test/python/expected/pyodbc/TestBigInt.out new file mode 100644 index 00000000000..7c9a698fff3 --- /dev/null +++ b/contrib/test/python/expected/pyodbc/TestBigInt.out @@ -0,0 +1,102 @@ +CREATE TABLE BIGINT_dt (a BIGINT) +prepst#!# INSERT INTO BIGINT_dt(a) values(?) #!#BIGINT|-|a|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#BIGINT|-|a|-|-10 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#BIGINT|-|a|-|122100 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#BIGINT|-|a|-|0001202 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#BIGINT|-|a|-|-024112329 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#BIGINT|-|a|-|-0000000000000000002 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#BIGINT|-|a|-|0000000000000000086 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#BIGINT|-|a|-|-9223372036854775808 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#BIGINT|-|a|-|9223372036854775807 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#BIGINT|-|a|-| +~~ROW COUNT: 1~~ + +SELECT * FROM BIGINT_dt; +~~START~~ +int +0 +-10 +122100 +1202 +-24112329 +-2 +86 +-9223372036854775808 +9223372036854775807 + +~~END~~ + +INSERT INTO BIGINT_dt(a) values(0) +~~ROW COUNT: 1~~ + +INSERT INTO BIGINT_dt(a) values(-120) +~~ROW COUNT: 1~~ + +INSERT INTO BIGINT_dt(a) values(00100) +~~ROW COUNT: 1~~ + +INSERT INTO BIGINT_dt(a) values(-004) +~~ROW COUNT: 1~~ + +INSERT INTO BIGINT_dt(a) values(-012245532534) +~~ROW COUNT: 1~~ + +INSERT INTO BIGINT_dt(a) values(-0000000000000000002) +~~ROW COUNT: 1~~ + +INSERT INTO BIGINT_dt(a) values(0000000000000000086) +~~ROW COUNT: 1~~ + +INSERT INTO BIGINT_dt(a) values(-9223372036854775808) +~~ROW COUNT: 1~~ + +INSERT INTO BIGINT_dt(a) values(9223372036854775807) +~~ROW COUNT: 1~~ + +INSERT INTO BIGINT_dt(a) values(NULL) +~~ROW COUNT: 1~~ + +SELECT * FROM BIGINT_dt; +~~START~~ +int +0 +-10 +122100 +1202 +-24112329 +-2 +86 +-9223372036854775808 +9223372036854775807 + +0 +-120 +100 +-4 +-12245532534 +-2 +86 +-9223372036854775808 +9223372036854775807 + +~~END~~ + +DROP TABLE BIGINT_dt; diff --git a/contrib/test/python/expected/pyodbc/TestBinary.out b/contrib/test/python/expected/pyodbc/TestBinary.out new file mode 100644 index 00000000000..7c22cc7ce16 --- /dev/null +++ b/contrib/test/python/expected/pyodbc/TestBinary.out @@ -0,0 +1,43 @@ +CREATE TABLE BINARY_dt(a BINARY(8), b VARBINARY(10)); +#inserting random values +INSERT INTO BINARY_dt(a, b) values (1234, 12345); +~~ROW COUNT: 1~~ + +INSERT INTO BINARY_dt(a, b) values (NULL, NULL); +~~ROW COUNT: 1~~ + +#INSERT INTO BINARY_dt(a, b) values (0x31323334, 0x3132333435); +SELECT * FROM BINARY_dt +~~START~~ +bytearray#!#bytearray +b'\x00\x00\x00\x00\x00\x00\x04\xd2'#!#b'\x00\x0009' +#!# +~~END~~ + +#prepst#!# INSERT INTO BINARY_dt(a, b) values(@a, @b) #!#binary|-|a|-|1234#!#varbinary|-|b|-|12345 +DROP TABLE BINARY_dt + + +CREATE TABLE BINARY_dt(a VARBINARY(max)); +INSERT INTO BINARY_dt(a) values (NULL); +~~ROW COUNT: 1~~ + +SELECT * FROM BINARY_dt; +~~START~~ +bytearray + +~~END~~ + +DROP TABLE BINARY_dt; + +create table BINARY_dt (a VARBINARY(max), b int, c int, d int, e int ,f int, g int, h int, i int); +insert into BINARY_dt (a,b,c,d,e,f,g,h,i) values (NULL,1,2,3,4,5,6,7,8); +~~ROW COUNT: 1~~ + +select * from BINARY_dt; +~~START~~ +bytearray#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int +#!#1#!#2#!#3#!#4#!#5#!#6#!#7#!#8 +~~END~~ + +drop table BINARY_dt; diff --git a/contrib/test/python/expected/pyodbc/TestChar.out b/contrib/test/python/expected/pyodbc/TestChar.out new file mode 100644 index 00000000000..19649a9ce4d --- /dev/null +++ b/contrib/test/python/expected/pyodbc/TestChar.out @@ -0,0 +1,60 @@ +CREATE TABLE CHAR_dt (a CHAR(24), b NCHAR(24)) +prepst#!# INSERT INTO CHAR_dt(a, b) values(?, ?) #!#CHAR|-|a|-|Dipesh#!#NCHAR|-|b|-|Dhameliya +~~ROW COUNT: 1~~ + +prepst#!#exec#!#CHAR|-|a|-| Dipesh #!#NCHAR|-|b|-| Dhameliya +~~ROW COUNT: 1~~ + +prepst#!#exec#!#CHAR|-|a|-| D#!#NCHAR|-|b|-| 🤣😃 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#CHAR|-|a|-| #!#NCHAR|-|b|-| +~~ROW COUNT: 1~~ + +prepst#!#exec#!#CHAR|-|a|-| #!#NCHAR|-|b|-|😊😋😎😍😅😆 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#CHAR|-|a|-|#!#NCHAR|-|b|-| +~~ROW COUNT: 1~~ + +SELECT * FROM CHAR_dt; +~~START~~ +str#!#str +Dipesh #!#Dhameliya + Dipesh #!# Dhameliya + D #!# 🤣😃 + #!# + #!#😊😋😎😍😅😆 +#!# +~~END~~ + +INSERT INTO CHAR_dt(a,b) values('Dipesh','Dhameliya') +~~ROW COUNT: 1~~ + +INSERT INTO CHAR_dt(a,b) values(' Dipesh',' Dhameliya') +~~ROW COUNT: 1~~ + +#INSERT INTO CHAR_dt(a,b) values(' D',N' 🤣😃') +INSERT INTO CHAR_dt(a,b) values(' ',' ') +~~ROW COUNT: 1~~ + +#INSERT INTO CHAR_dt(a,b) values(' ',N'😊😋😎😍😅😆') +INSERT INTO CHAR_dt(a,b) values(NULL,NULL) +~~ROW COUNT: 1~~ + +SELECT * FROM CHAR_dt; +~~START~~ +str#!#str +Dipesh #!#Dhameliya + Dipesh #!# Dhameliya + D #!# 🤣😃 + #!# + #!#😊😋😎😍😅😆 +#!# +Dipesh #!#Dhameliya + Dipesh #!# Dhameliya + #!# +#!# +~~END~~ + +DROP TABLE CHAR_dt; diff --git a/contrib/test/python/expected/pyodbc/TestCursorFetchNext.out b/contrib/test/python/expected/pyodbc/TestCursorFetchNext.out new file mode 100644 index 00000000000..38a542183a7 --- /dev/null +++ b/contrib/test/python/expected/pyodbc/TestCursorFetchNext.out @@ -0,0 +1,83 @@ +CREATE TABLE test_cursors_fetch_next(a INT, b SMALLINT, c BIGINT, d TINYINT, e BIT); +INSERT INTO test_cursors_fetch_next values(0, 0, 0, 0, 0) +~~ROW COUNT: 1~~ + +INSERT INTO test_cursors_fetch_next values(NULL, NULL, NULL, NULL, NULL) +~~ROW COUNT: 1~~ + +INSERT INTO test_cursors_fetch_next values(1, 2, 3, 4, 1) +~~ROW COUNT: 1~~ + +INSERT INTO test_cursors_fetch_next values(211234, 9780, 891372401, 56, 1) +~~ROW COUNT: 1~~ + +#cursor#!#fetch#!#prev +#cursor#!#fetch#!#next +#cursor#!#fetch#!#beforefirst +#cursor#!#fetch#!#next +#cursor#!#fetch#!#afterlast +#cursor#!#fetch#!#next +DROP TABLE test_cursors_fetch_next + +CREATE TABLE test_cursors_fetch_next(a CHAR(30), b VARCHAR(30), c NCHAR(30), d NVARCHAR(30)); +INSERT INTO test_cursors_fetch_next values(' ', ' ', ' ', ' ') +~~ROW COUNT: 1~~ + +INSERT INTO test_cursors_fetch_next values(NULL, NULL, NULL, NULL) +~~ROW COUNT: 1~~ + +INSERT INTO test_cursors_fetch_next values('hello', 'from the', N'server', N'side 😆') +~~ROW COUNT: 1~~ + +INSERT INTO test_cursors_fetch_next values('Its', 'always', N'day', N'1') +~~ROW COUNT: 1~~ + +#cursor#!#fetch#!#prev +#cursor#!#fetch#!#next +#cursor#!#fetch#!#beforefirst +#cursor#!#fetch#!#next +#cursor#!#fetch#!#afterlast +#cursor#!#fetch#!#next +DROP TABLE test_cursors_fetch_next + +CREATE TABLE test_cursors_fetch_next(a DATE, b DATETIME, c SMALLDATETIME); +INSERT INTO test_cursors_fetch_next values('2000-12-13', '1900-02-28 23:59:59.989', '2000-12-13 12:58:23') +~~ROW COUNT: 1~~ + +INSERT INTO test_cursors_fetch_next values(NULL, NULL, NULL) +~~ROW COUNT: 1~~ + +INSERT INTO test_cursors_fetch_next values('1997-05-07', '1900-02-28 11:23:17.895', '2000-12-13 10:23:44') +~~ROW COUNT: 1~~ + +INSERT INTO test_cursors_fetch_next values('1876-08-07', '1980-02-05 16:11:45.215', '1987-10-01 07:55:24') +~~ROW COUNT: 1~~ + +#cursor#!#fetch#!#prev +#cursor#!#fetch#!#next +#cursor#!#fetch#!#beforefirst +#cursor#!#fetch#!#next +#cursor#!#fetch#!#afterlast +#cursor#!#fetch#!#next +DROP TABLE test_cursors_fetch_next + +CREATE TABLE test_cursors_fetch_next(a FLOAT, b REAL, c MONEY, d SMALLMONEY); +INSERT INTO test_cursors_fetch_next values(0, 0, '$0', '$0') +~~ROW COUNT: 1~~ + +INSERT INTO test_cursors_fetch_next values(NULL, NULL, NULL, NULL) +~~ROW COUNT: 1~~ + +INSERT INTO test_cursors_fetch_next values(241.7832, 1214.691236, '62,514.00', '690.817') +~~ROW COUNT: 1~~ + +INSERT INTO test_cursors_fetch_next values('32546', '980.709', '1,988,232.08', '$86,798') +~~ROW COUNT: 1~~ + +#cursor#!#fetch#!#prev +#cursor#!#fetch#!#next +#cursor#!#fetch#!#beforefirst +#cursor#!#fetch#!#next +#cursor#!#fetch#!#afterlast +#cursor#!#fetch#!#next +DROP TABLE test_cursors_fetch_next diff --git a/contrib/test/python/expected/pyodbc/TestCursorPrepExecFetchNext.out b/contrib/test/python/expected/pyodbc/TestCursorPrepExecFetchNext.out new file mode 100644 index 00000000000..06bb45df745 --- /dev/null +++ b/contrib/test/python/expected/pyodbc/TestCursorPrepExecFetchNext.out @@ -0,0 +1,83 @@ +CREATE TABLE test_cursor_prep_exec_fetch_next(a INT, b SMALLINT, c BIGINT, d TINYINT, e BIT); +INSERT INTO test_cursor_prep_exec_fetch_next values(0, 0, 0, 0, 0) +~~ROW COUNT: 1~~ + +INSERT INTO test_cursor_prep_exec_fetch_next values(NULL, NULL, NULL, NULL, NULL) +~~ROW COUNT: 1~~ + +INSERT INTO test_cursor_prep_exec_fetch_next values(1, 2, 3, 4, 1) +~~ROW COUNT: 1~~ + +INSERT INTO test_cursor_prep_exec_fetch_next values(211234, 9780, 891372401, 56, 1) +~~ROW COUNT: 1~~ + +#cursor#!#fetch#!#prev +#cursor#!#fetch#!#next +#cursor#!#fetch#!#beforefirst +#cursor#!#fetch#!#next +#cursor#!#fetch#!#afterlast +#cursor#!#fetch#!#next +DROP TABLE test_cursor_prep_exec_fetch_next + +CREATE TABLE test_cursor_prep_exec_fetch_next(a CHAR(30), b VARCHAR(30), c NCHAR(30), d NVARCHAR(30)); +INSERT INTO test_cursor_prep_exec_fetch_next values(' ', ' ', ' ', ' ') +~~ROW COUNT: 1~~ + +INSERT INTO test_cursor_prep_exec_fetch_next values(NULL, NULL, NULL, NULL) +~~ROW COUNT: 1~~ + +INSERT INTO test_cursor_prep_exec_fetch_next values('hello', 'from the', N'server', N'side 😆') +~~ROW COUNT: 1~~ + +INSERT INTO test_cursor_prep_exec_fetch_next values('Its', 'always', N'day', N'1') +~~ROW COUNT: 1~~ + +#cursor#!#fetch#!#prev +#cursor#!#fetch#!#next +#cursor#!#fetch#!#beforefirst +#cursor#!#fetch#!#next +#cursor#!#fetch#!#afterlast +#cursor#!#fetch#!#next +DROP TABLE test_cursor_prep_exec_fetch_next + +CREATE TABLE test_cursor_prep_exec_fetch_next(a DATE, b DATETIME, c SMALLDATETIME); +INSERT INTO test_cursor_prep_exec_fetch_next values('2000-12-13', '1900-02-28 23:59:59.989', '2000-12-13 12:58:23') +~~ROW COUNT: 1~~ + +INSERT INTO test_cursor_prep_exec_fetch_next values(NULL, NULL, NULL) +~~ROW COUNT: 1~~ + +INSERT INTO test_cursor_prep_exec_fetch_next values('1997-05-07', '1900-02-28 11:23:17.895', '2000-12-13 10:23:44') +~~ROW COUNT: 1~~ + +INSERT INTO test_cursor_prep_exec_fetch_next values('1876-08-07', '1980-02-05 16:11:45.215', '1987-10-01 07:55:24') +~~ROW COUNT: 1~~ + +#cursor#!#fetch#!#prev +#cursor#!#fetch#!#next +#cursor#!#fetch#!#beforefirst +#cursor#!#fetch#!#next +#cursor#!#fetch#!#afterlast +#cursor#!#fetch#!#next +DROP TABLE test_cursor_prep_exec_fetch_next + +CREATE TABLE test_cursor_prep_exec_fetch_next(a FLOAT, b REAL, c MONEY, d SMALLMONEY); +INSERT INTO test_cursor_prep_exec_fetch_next values(0, 0, '$0', '$0') +~~ROW COUNT: 1~~ + +INSERT INTO test_cursor_prep_exec_fetch_next values(NULL, NULL, NULL, NULL) +~~ROW COUNT: 1~~ + +INSERT INTO test_cursor_prep_exec_fetch_next values(241.7832, 1214.691236, '62,514.00', '690.817') +~~ROW COUNT: 1~~ + +INSERT INTO test_cursor_prep_exec_fetch_next values('32546', '980.709', '1,988,232.08', '$86,798') +~~ROW COUNT: 1~~ + +#cursor#!#fetch#!#prev +#cursor#!#fetch#!#next +#cursor#!#fetch#!#beforefirst +#cursor#!#fetch#!#next +#cursor#!#fetch#!#afterlast +#cursor#!#fetch#!#next +DROP TABLE test_cursor_prep_exec_fetch_next diff --git a/contrib/test/python/expected/pyodbc/TestDate.out b/contrib/test/python/expected/pyodbc/TestDate.out new file mode 100644 index 00000000000..3c95bc9b7bb --- /dev/null +++ b/contrib/test/python/expected/pyodbc/TestDate.out @@ -0,0 +1,56 @@ +CREATE TABLE DATE_dt (a DATE) +prepst#!# INSERT INTO DATE_dt(a) values(?) #!#DATE|-|a|-|2000-12-13 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#DATE|-|a|-|2000-02-28 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#DATE|-|a|-|0001-01-01 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#DATE|-|a|-|9999-12-31 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#DATE|-|a|-| +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]column "a" is of type date but expression is of type "varchar" (33557097) (SQLExecDirectW))~~ + +SELECT * FROM DATE_dt; +~~START~~ +date +2000-12-13 +2000-02-28 +0001-01-01 +9999-12-31 +~~END~~ + +INSERT INTO DATE_dt(a) values('2000-12-13') +~~ROW COUNT: 1~~ + +INSERT INTO DATE_dt(a) values('1900-02-28') +~~ROW COUNT: 1~~ + +INSERT INTO DATE_dt(a) values('0001-01-01') +~~ROW COUNT: 1~~ + +INSERT INTO DATE_dt(a) values('9999-12-31') +~~ROW COUNT: 1~~ + +INSERT INTO DATE_dt(a) values(NULL) +~~ROW COUNT: 1~~ + +SELECT * FROM DATE_dt; +~~START~~ +date +2000-12-13 +2000-02-28 +0001-01-01 +9999-12-31 +2000-12-13 +1900-02-28 +0001-01-01 +9999-12-31 + +~~END~~ + +DROP TABLE DATE_dt; diff --git a/contrib/test/python/expected/pyodbc/TestDatetime.out b/contrib/test/python/expected/pyodbc/TestDatetime.out new file mode 100644 index 00000000000..f0c5e9adeff --- /dev/null +++ b/contrib/test/python/expected/pyodbc/TestDatetime.out @@ -0,0 +1,156 @@ +CREATE TABLE DATETIME_dt (a DATETIME) +prepst#!# INSERT INTO DATETIME_dt(a) values(?) #!#DATETIME|-|a|-|2000-12-13 12:58:23.123 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.989 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.990 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.991 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.992 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.993 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.994 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.995 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.996 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.997 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.998 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.999 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#DATETIME|-|a|-|1900-02-28 23:59:59.989 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#DATETIME|-|a|-|1753-01-01 00:00:00.000 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#DATETIME|-|a|-|9999-12-31 23:59:59.997 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#DATETIME|-|a|-| +~~ROW COUNT: 1~~ + +SELECT * FROM DATETIME_dt; +~~START~~ +datetime +2000-12-13 12:58:23.123000 +2000-02-28 23:59:59.990000 +2000-02-28 23:59:59.990000 +2000-02-28 23:59:59.990000 +2000-02-28 23:59:59.993000 +2000-02-28 23:59:59.993000 +2000-02-28 23:59:59.993000 +2000-02-28 23:59:59.997000 +2000-02-28 23:59:59.997000 +2000-02-28 23:59:59.997000 +2000-02-28 23:59:59.997000 +2000-02-29 00:00:00 +1900-02-28 23:59:59.990000 +1753-01-01 00:00:00 +9999-12-31 23:59:59.997000 + +~~END~~ + +INSERT INTO DATETIME_dt(a) values('2000-12-13 12:58:23.123') +~~ROW COUNT: 1~~ + +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.989') +~~ROW COUNT: 1~~ + +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.990') +~~ROW COUNT: 1~~ + +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.991') +~~ROW COUNT: 1~~ + +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.992') +~~ROW COUNT: 1~~ + +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.993') +~~ROW COUNT: 1~~ + +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.994') +~~ROW COUNT: 1~~ + +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.995') +~~ROW COUNT: 1~~ + +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.996') +~~ROW COUNT: 1~~ + +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.997') +~~ROW COUNT: 1~~ + +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.998') +~~ROW COUNT: 1~~ + +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.999') +~~ROW COUNT: 1~~ + +INSERT INTO DATETIME_dt(a) values('2000-02-28 23:59:59.989') +~~ROW COUNT: 1~~ + +INSERT INTO DATETIME_dt(a) values('1753-01-01 00:00:00.000') +~~ROW COUNT: 1~~ + +INSERT INTO DATETIME_dt(a) values('9999-12-31 23:59:59.997') +~~ROW COUNT: 1~~ + +INSERT INTO DATETIME_dt(a) values(NULL) +~~ROW COUNT: 1~~ + +SELECT * FROM DATETIME_dt; +~~START~~ +datetime +2000-12-13 12:58:23.123000 +2000-02-28 23:59:59.990000 +2000-02-28 23:59:59.990000 +2000-02-28 23:59:59.990000 +2000-02-28 23:59:59.993000 +2000-02-28 23:59:59.993000 +2000-02-28 23:59:59.993000 +2000-02-28 23:59:59.997000 +2000-02-28 23:59:59.997000 +2000-02-28 23:59:59.997000 +2000-02-28 23:59:59.997000 +2000-02-29 00:00:00 +1900-02-28 23:59:59.990000 +1753-01-01 00:00:00 +9999-12-31 23:59:59.997000 + +2000-12-13 12:58:23.123000 +1900-02-28 23:59:59.990000 +1900-02-28 23:59:59.990000 +1900-02-28 23:59:59.990000 +1900-02-28 23:59:59.993000 +1900-02-28 23:59:59.993000 +1900-02-28 23:59:59.993000 +1900-02-28 23:59:59.997000 +1900-02-28 23:59:59.997000 +1900-02-28 23:59:59.997000 +1900-02-28 23:59:59.997000 +1900-03-01 00:00:00 +2000-02-28 23:59:59.990000 +1753-01-01 00:00:00 +9999-12-31 23:59:59.997000 + +~~END~~ + +DROP TABLE DATETIME_dt; diff --git a/contrib/test/python/expected/pyodbc/TestDatetime2.out b/contrib/test/python/expected/pyodbc/TestDatetime2.out new file mode 100644 index 00000000000..88bf5f94d67 --- /dev/null +++ b/contrib/test/python/expected/pyodbc/TestDatetime2.out @@ -0,0 +1,43 @@ +Create table TestDatetime2(a Datetime2(6)) + +prepst#!# Insert into TestDatetime2 Values(?) #!#Datetime2|-|a|-|2016-10-23 12:45:37.123|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Datetime2|-|a|-|2016-10-23 12:45:37.123|-|3 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Datetime2|-|a|-|2016-10-23 12:45:37.12|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Datetime2|-|a|-|2016-10-23 12:45:37.1|-|1 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Datetime2|-|a|-|2016-10-23 12:45:37.1234|-|4 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Datetime2|-|a|-|2016-10-23 12:45:37.123456|-|6 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Datetime2|-|a|-|2016-10-23 12:45:37.123456|-|5 +~~ROW COUNT: 1~~ + +#prepst#!#exec#!#Datetime2|-|a|-|12:45:37.123456|-|5 +prepst#!#exec#!#Datetime2|-|a|-| +~~ROW COUNT: 1~~ + + +select * from TestDatetime2 +~~START~~ +datetime +2016-10-23 12:45:37.123000 +2016-10-23 12:45:37.123000 +2016-10-23 12:45:37.120000 +2016-10-23 12:45:37.100000 +2016-10-23 12:45:37.123400 +2016-10-23 12:45:37.123456 +2016-10-23 12:45:37.123456 + +~~END~~ + + +Drop table TestDatetime2 diff --git a/contrib/test/python/expected/pyodbc/TestDecimal.out b/contrib/test/python/expected/pyodbc/TestDecimal.out new file mode 100644 index 00000000000..5e5234a25ce --- /dev/null +++ b/contrib/test/python/expected/pyodbc/TestDecimal.out @@ -0,0 +1,546 @@ +CREATE TABLE decimal_table(num decimal(5, 2)); + +prepst#!#INSERT INTO decimal_table(num) VALUES(?) #!#decimal|-|a|-|3|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a|-|123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a|-|123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a|-|123|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a|-|123.45|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a|-||-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a|-|-123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a|-|-123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a|-|-123|-|5|-|2 +~~ROW COUNT: 1~~ + +#prepst#!#exec#!#decimal|-|a|-|0|-|5|-|2 +prepst#!#exec#!#decimal|-|a|-|-1|-|3|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a|-|-123|-|9|-|2 +~~ROW COUNT: 1~~ + + +SELECT * FROM decimal_table; +~~START~~ +Decimal +3.00 +123.46 +123.40 +123.00 +123.45 + +-123.46 +-123.40 +-123.00 +-1.00 +-123.00 +~~END~~ + + +DROP TABLE decimal_table; + +CREATE TABLE decimal_table(num decimal(38, 3)); + +prepst#!#INSERT INTO decimal_table(num) VALUES(?) #!#decimal|-|a1|-|3|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a1|-|123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a1|-|123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a1|-|123|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a1|-|123.45|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a1|-||-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a1|-|-123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a1|-|-123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a1|-|-123|-|5|-|2 +~~ROW COUNT: 1~~ + +#prepst#!#exec#!#decimal|-|a1|-|0|-|5|-|2 +prepst#!#exec#!#decimal|-|a1|-|-1|-|3|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a1|-|-123|-|9|-|2 +~~ROW COUNT: 1~~ + + +prepst#!#exec#!#decimal|-|a1|-|2147483647|-|10|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a1|-|-2147483647|-|10|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a1|-|2147483646|-|10|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a1|-|-2147483646|-|10|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a1|-|2147483648|-|10|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a1|-|-2147483648|-|10|-|0 +~~ROW COUNT: 1~~ + + +SELECT * FROM decimal_table; +~~START~~ +Decimal +3.000 +123.456 +123.400 +123.000 +123.450 + +-123.456 +-123.400 +-123.000 +-1.000 +-123.000 +2147483647.000 +-2147483647.000 +2147483646.000 +-2147483646.000 +2147483648.000 +-2147483648.000 +~~END~~ + + +DROP TABLE decimal_table; + +# JIRA 507, WORKING FOR BABEL +#CREATE TABLE decimal_table(num decimal(39, 20)); + +CREATE TABLE decimal_table(num decimal(38, 20)); + +prepst#!#INSERT INTO decimal_table(num) VALUES(?) #!#decimal|-|a2|-|3|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a2|-|123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a2|-|123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a2|-|123|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a2|-|123.45|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a2|-||-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a2|-|-123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a2|-|-123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a2|-|-123|-|5|-|2 +~~ROW COUNT: 1~~ + +#prepst#!#exec#!#decimal|-|a2|-|0|-|5|-|2 +prepst#!#exec#!#decimal|-|a2|-|-1|-|3|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a2|-|-123|-|9|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a2|-|2147483647|-|10|-|0 +~~ROW COUNT: 1~~ + +SELECT * FROM decimal_table; +~~START~~ +Decimal +3.00000000000000000000 +123.45600000000000000000 +123.40000000000000000000 +123.00000000000000000000 +123.45000000000000000000 + +-123.45600000000000000000 +-123.40000000000000000000 +-123.00000000000000000000 +-1.00000000000000000000 +-123.00000000000000000000 +2147483647.00000000000000000000 +~~END~~ + + +DROP TABLE decimal_table; + +CREATE TABLE decimal_table(num decimal(38, 20)); +prepst#!#INSERT INTO decimal_table(num) VALUES(?) #!#decimal|-|a3|-|3|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a3|-|123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a3|-|123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a3|-|123|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a3|-|123.45|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a3|-||-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a3|-|-123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a3|-|-123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a3|-|-123|-|5|-|2 +~~ROW COUNT: 1~~ + +#prepst#!#exec#!#decimal|-|a3|-|0|-|5|-|2 +prepst#!#exec#!#decimal|-|a3|-|-1|-|3|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a3|-|-123|-|9|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a3|-|2147483647|-|10|-|0 +~~ROW COUNT: 1~~ + +SELECT * FROM decimal_table; +~~START~~ +Decimal +3.00000000000000000000 +123.45600000000000000000 +123.40000000000000000000 +123.00000000000000000000 +123.45000000000000000000 + +-123.45600000000000000000 +-123.40000000000000000000 +-123.00000000000000000000 +-1.00000000000000000000 +-123.00000000000000000000 +2147483647.00000000000000000000 +~~END~~ + + +DROP TABLE decimal_table; + +CREATE TABLE decimal_table(num decimal(38, 21)); +prepst#!#INSERT INTO decimal_table(num) VALUES(?) #!#decimal|-|a4|-|3|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a4|-|123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a4|-|123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a4|-|123|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a4|-|123.45|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a4|-||-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a4|-|-123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a4|-|-123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a4|-|-123|-|5|-|2 +~~ROW COUNT: 1~~ + +#prepst#!#exec#!#decimal|-|a4|-|0|-|5|-|2 +prepst#!#exec#!#decimal|-|a4|-|-1|-|3|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a4|-|-123|-|9|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a4|-|2147483647|-|10|-|0 +~~ROW COUNT: 1~~ + +SELECT * FROM decimal_table; +~~START~~ +Decimal +3.000000000000000000000 +123.456000000000000000000 +123.400000000000000000000 +123.000000000000000000000 +123.450000000000000000000 + +-123.456000000000000000000 +-123.400000000000000000000 +-123.000000000000000000000 +-1.000000000000000000000 +-123.000000000000000000000 +2147483647.000000000000000000000 +~~END~~ + + +DROP TABLE decimal_table; + +CREATE TABLE decimal_table(num decimal(38, 22)); +prepst#!#INSERT INTO decimal_table(num) VALUES(?) #!#decimal|-|a5|-|3|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a5|-|123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a5|-|123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a5|-|123|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a5|-|123.45|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a5|-||-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a5|-|-123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a5|-|-123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a5|-|-123|-|5|-|2 +~~ROW COUNT: 1~~ + +#prepst#!#exec#!#decimal|-|a5|-|0|-|5|-|2 +prepst#!#exec#!#decimal|-|a5|-|-1|-|3|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a5|-|-123|-|9|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a5|-|2147483647|-|10|-|0 +~~ROW COUNT: 1~~ + +SELECT * FROM decimal_table; +~~START~~ +Decimal +3.0000000000000000000000 +123.4560000000000000000000 +123.4000000000000000000000 +123.0000000000000000000000 +123.4500000000000000000000 + +-123.4560000000000000000000 +-123.4000000000000000000000 +-123.0000000000000000000000 +-1.0000000000000000000000 +-123.0000000000000000000000 +2147483647.0000000000000000000000 +~~END~~ + + +DROP TABLE decimal_table; + +CREATE TABLE decimal_table(num decimal(38, 23)); +prepst#!#INSERT INTO decimal_table(num) VALUES(?) #!#decimal|-|a6|-|3|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a6|-|123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a6|-|123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a6|-|123|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a6|-|123.45|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a6|-||-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a6|-|-123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a6|-|-123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a6|-|-123|-|5|-|2 +~~ROW COUNT: 1~~ + +#prepst#!#exec#!#decimal|-|a6|-|0|-|5|-|2 +prepst#!#exec#!#decimal|-|a6|-|-1|-|3|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a6|-|-123|-|9|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a6|-|2147483647|-|10|-|0 +~~ROW COUNT: 1~~ + +SELECT * FROM decimal_table; +~~START~~ +Decimal +3.00000000000000000000000 +123.45600000000000000000000 +123.40000000000000000000000 +123.00000000000000000000000 +123.45000000000000000000000 + +-123.45600000000000000000000 +-123.40000000000000000000000 +-123.00000000000000000000000 +-1.00000000000000000000000 +-123.00000000000000000000000 +2147483647.00000000000000000000000 +~~END~~ + + +DROP TABLE decimal_table; + +CREATE TABLE decimal_table(num decimal(38, 25)); +prepst#!#INSERT INTO decimal_table(num) VALUES(?) #!#decimal|-|a7|-|3|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a7|-|123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a7|-|123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a7|-|123|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a7|-|123.45|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a7|-||-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a7|-|-123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a7|-|-123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a7|-|-123|-|5|-|2 +~~ROW COUNT: 1~~ + +#prepst#!#exec#!#decimal|-|a7|-|0|-|5|-|2 +prepst#!#exec#!#decimal|-|a7|-|-1|-|3|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a7|-|-123|-|9|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a7|-|247483647|-|10|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#decimal|-|a7|-|-247483647|-|10|-|0 +~~ROW COUNT: 1~~ + +SELECT * FROM decimal_table; +~~START~~ +Decimal +3.0000000000000000000000000 +123.4560000000000000000000000 +123.4000000000000000000000000 +123.0000000000000000000000000 +123.4500000000000000000000000 + +-123.4560000000000000000000000 +-123.4000000000000000000000000 +-123.0000000000000000000000000 +-1.0000000000000000000000000 +-123.0000000000000000000000000 +247483647.0000000000000000000000000 +-247483647.0000000000000000000000000 +~~END~~ + + +DROP TABLE decimal_table; + + +CREATE TABLE decimal_table(num decimal(38, 25)); + +insert into decimal_table values (2147483647) +~~ROW COUNT: 1~~ + +insert into decimal_table values (-2147483647) +~~ROW COUNT: 1~~ + + +insert into decimal_table values (2147483646) +~~ROW COUNT: 1~~ + +insert into decimal_table values (-2147483646) +~~ROW COUNT: 1~~ + + +insert into decimal_table values (2147483648) +~~ROW COUNT: 1~~ + +insert into decimal_table values (-2147483648) +~~ROW COUNT: 1~~ + + +#insert into decimal_table values(123456789123456789.1234567891234567891234567); +#insert into decimal_table values(1234567891234567891.1234567891234567891234567); +#insert into decimal_table values(123456789123456789.12345678912345678912345678); +insert into decimal_table values(0.0); +~~ROW COUNT: 1~~ + +insert into decimal_table values(0.0000000000000000000000000); +~~ROW COUNT: 1~~ + +insert into decimal_table values(0.00000000000000000000000000); +~~ROW COUNT: 1~~ + + +SELECT * FROM decimal_table; +~~START~~ +Decimal +2147483647.0000000000000000000000000 +-2147483647.0000000000000000000000000 +2147483646.0000000000000000000000000 +-2147483646.0000000000000000000000000 +2147483648.0000000000000000000000000 +-2147483648.0000000000000000000000000 +0E-25 +0E-25 +0E-25 +~~END~~ + + +DROP TABLE decimal_table; diff --git a/contrib/test/python/expected/pyodbc/TestFloat.out b/contrib/test/python/expected/pyodbc/TestFloat.out new file mode 100644 index 00000000000..3c5377264fc --- /dev/null +++ b/contrib/test/python/expected/pyodbc/TestFloat.out @@ -0,0 +1,102 @@ +CREATE TABLE FLOAT_dt (a FLOAT) +prepst#!# INSERT INTO FLOAT_dt(a) values(?) #!#FLOAT|-|a|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#FLOAT|-|a|-|1.050 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#FLOAT|-|a|-|01.05 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#FLOAT|-|a|-|0001202 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#FLOAT|-|a|-|-024112329 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#FLOAT|-|a|-|-02.5 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#FLOAT|-|a|-|0000000000000000086 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#FLOAT|-|a|-|-1.79E+308 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#FLOAT|-|a|-|1.79E+308 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#FLOAT|-|a|-| +~~ROW COUNT: 1~~ + +SELECT * FROM FLOAT_dt; +~~START~~ +float +0.0 +1.05 +1.05 +1202.0 +-24112329.0 +-2.5 +86.0 +-1.79e+308 +1.79e+308 + +~~END~~ + +INSERT INTO FLOAT_dt(a) values(0) +~~ROW COUNT: 1~~ + +INSERT INTO FLOAT_dt(a) values(1.050) +~~ROW COUNT: 1~~ + +INSERT INTO FLOAT_dt(a) values(01.05) +~~ROW COUNT: 1~~ + +INSERT INTO FLOAT_dt(a) values(-004) +~~ROW COUNT: 1~~ + +INSERT INTO FLOAT_dt(a) values(-0122455324.5) +~~ROW COUNT: 1~~ + +INSERT INTO FLOAT_dt(a) values(-000002) +~~ROW COUNT: 1~~ + +INSERT INTO FLOAT_dt(a) values(0000000000000000086) +~~ROW COUNT: 1~~ + +INSERT INTO FLOAT_dt(a) values(-1.79E+308) +~~ROW COUNT: 1~~ + +INSERT INTO FLOAT_dt(a) values(1.79E+308) +~~ROW COUNT: 1~~ + +INSERT INTO FLOAT_dt(a) values(NULL) +~~ROW COUNT: 1~~ + +SELECT * FROM FLOAT_dt; +~~START~~ +float +0.0 +1.05 +1.05 +1202.0 +-24112329.0 +-2.5 +86.0 +-1.79e+308 +1.79e+308 + +0.0 +1.05 +1.05 +-4.0 +-122455324.5 +-2.0 +86.0 +-1.79e+308 +1.79e+308 + +~~END~~ + +DROP TABLE FLOAT_dt; diff --git a/contrib/test/python/expected/pyodbc/TestInt.out b/contrib/test/python/expected/pyodbc/TestInt.out new file mode 100644 index 00000000000..8a0c9319a57 --- /dev/null +++ b/contrib/test/python/expected/pyodbc/TestInt.out @@ -0,0 +1,111 @@ +CREATE TABLE INT_dt(a INT); +prepst#!#INSERT INTO INT_dt(a) values(?) #!#INT|-|a|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#INT|-|a|-|-10 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#INT|-|a|-|10 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#INT|-|a|-|-12234 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#INT|-|a|-|22 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#INT|-|a|-|003 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#INT|-|a|-|9864 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#INT|-|a|-|-01625 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#INT|-|a|-|-2147483648 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#INT|-|a|-|2147483647 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#INT|-|a|-| +~~ROW COUNT: 1~~ + + +SELECT * FROM INT_dt; +~~START~~ +int +0 +-10 +10 +-12234 +22 +3 +9864 +-1625 +-2147483648 +2147483647 + +~~END~~ + + +INSERT INTO INT_dt(a) values(0) +~~ROW COUNT: 1~~ + +INSERT INTO INT_dt(a) values(-10) +~~ROW COUNT: 1~~ + +INSERT INTO INT_dt(a) values(10) +~~ROW COUNT: 1~~ + +INSERT INTO INT_dt(a) values(-12345) +~~ROW COUNT: 1~~ + +INSERT INTO INT_dt(a) values(22) +~~ROW COUNT: 1~~ + +INSERT INTO INT_dt(a) values(004) +~~ROW COUNT: 1~~ + +INSERT INTO INT_dt(a) values(-01645) +~~ROW COUNT: 1~~ + +INSERT INTO INT_dt(a) values(-2147483648) +~~ROW COUNT: 1~~ + +INSERT INTO INT_dt(a) values(2147483647) +~~ROW COUNT: 1~~ + +INSERT INTO INT_dt(a) values(NULL) +~~ROW COUNT: 1~~ + + +SELECT * FROM INT_dt; +~~START~~ +int +0 +-10 +10 +-12234 +22 +3 +9864 +-1625 +-2147483648 +2147483647 + +0 +-10 +10 +-12345 +22 +4 +-1645 +-2147483648 +2147483647 + +~~END~~ + + +DROP TABLE INT_dt; diff --git a/contrib/test/python/expected/pyodbc/TestMoney.out b/contrib/test/python/expected/pyodbc/TestMoney.out new file mode 100644 index 00000000000..fd6bd6097df --- /dev/null +++ b/contrib/test/python/expected/pyodbc/TestMoney.out @@ -0,0 +1,111 @@ +CREATE TABLE money_dt(a smallmoney, b money); + +prepst#!#INSERT INTO money_dt(a, b) VALUES (?, ?) #!#smallmoney|-|a|-|100.5#!#money|-|b|-|10.05 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#smallmoney|-|a|-|10#!#money|-|b|-|10 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#smallmoney|-|a|-|-10.05 #!#money|-|b|-|-10.0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#smallmoney|-|a|-|-214748.3648#!#money|-|b|-|-922337203685477.5808 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#smallmoney|-|a|-|214748.3647#!#money|-|b|-|22337203685477.5807 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#smallmoney|-|a|-|214748.3647#!#money|-|b|-|22337203685477.5807 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#smallmoney|-|a|-|-214,748.3648#!#money|-|b|-|-922,337,203,685,477.5808 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#smallmoney|-|a|-|214,748.3647#!#money|-|b|-|922,337,203,685,477.5807 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#smallmoney|-|a|-|214,748.3647#!#money|-|b|-|922,337,203,685,477.5807 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#smallmoney|-|a|-|#!#money|-|b|-| +~~ROW COUNT: 1~~ + + +SELECT * FROM money_dt; +~~START~~ +Decimal#!#Decimal +100.5000#!#10.0500 +10.0000#!#10.0000 +-10.0500#!#-10.0000 +-214748.3648#!#-922337203685477.5808 +214748.3647#!#22337203685477.5807 +214748.3647#!#22337203685477.5807 +-214748.3648#!#-922337203685477.5808 +214748.3647#!#922337203685477.5807 +214748.3647#!#922337203685477.5807 +#!# +~~END~~ + + +INSERT INTO money_dt(a,b) values(100.5,10.05); +~~ROW COUNT: 1~~ + +INSERT INTO money_dt(a,b) values('$10','$10'); +~~ROW COUNT: 1~~ + +INSERT INTO money_dt(a,b) values('-10.05','-10.0'); +~~ROW COUNT: 1~~ + +INSERT INTO money_dt(a,b) values('10.05','10.0'); +~~ROW COUNT: 1~~ + +INSERT INTO money_dt(a,b) values(-214748.3648,'-10.0'); +~~ROW COUNT: 1~~ + +INSERT INTO money_dt(a,b) values(14748.3647,-922337203685477.5808); +~~ROW COUNT: 1~~ + +INSERT INTO money_dt(a,b) values('$214748.3647','$22337203685477.5807'); +~~ROW COUNT: 1~~ + +INSERT INTO money_dt(a,b) values('-214,748.3648','-922,337,203,685,477.5808'); +~~ROW COUNT: 1~~ + +INSERT INTO money_dt(a,b) values('214,748.3647','922,337,203,685,477.5807'); +~~ROW COUNT: 1~~ + +INSERT INTO money_dt(a,b) values('$214,748.3647','$922,337,203,685,477.5807'); +~~ROW COUNT: 1~~ + +INSERT INTO money_dt(a,b) values(NULL,NULL); +~~ROW COUNT: 1~~ + + + +SELECT * FROM money_dt; +~~START~~ +Decimal#!#Decimal +100.5000#!#10.0500 +10.0000#!#10.0000 +-10.0500#!#-10.0000 +-214748.3648#!#-922337203685477.5808 +214748.3647#!#22337203685477.5807 +214748.3647#!#22337203685477.5807 +-214748.3648#!#-922337203685477.5808 +214748.3647#!#922337203685477.5807 +214748.3647#!#922337203685477.5807 +#!# +100.5000#!#10.0500 +10.0000#!#10.0000 +-10.0500#!#-10.0000 +10.0500#!#10.0000 +-214748.3648#!#-10.0000 +14748.3647#!#-922337203685477.5808 +214748.3647#!#22337203685477.5807 +-214748.3648#!#-922337203685477.5808 +214748.3647#!#922337203685477.5807 +214748.3647#!#922337203685477.5807 +#!# +~~END~~ + +DROP TABLE money_dt; diff --git a/contrib/test/python/expected/pyodbc/TestNumeric.out b/contrib/test/python/expected/pyodbc/TestNumeric.out new file mode 100644 index 00000000000..a190784eb02 --- /dev/null +++ b/contrib/test/python/expected/pyodbc/TestNumeric.out @@ -0,0 +1,578 @@ +CREATE TABLE numeric_table(num numeric(5, 2)); + +prepst#!#INSERT INTO numeric_table(num) VALUES(?) #!#numeric|-|a|-|3|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a|-|123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a|-|123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a|-|123|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a|-|123.45|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a|-||-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a|-|-123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a|-|-123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a|-|-123|-|5|-|2 +~~ROW COUNT: 1~~ + +#prepst#!#exec#!#numeric|-|a|-|0|-|5|-|2 +prepst#!#exec#!#numeric|-|a|-|-1|-|3|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a|-|-123|-|9|-|2 +~~ROW COUNT: 1~~ + + +SELECT * FROM numeric_table; +~~START~~ +Decimal +3.00 +123.46 +123.40 +123.00 +123.45 + +-123.46 +-123.40 +-123.00 +-1.00 +-123.00 +~~END~~ + + +DROP TABLE numeric_table; + +CREATE TABLE numeric_table(num numeric(38, 3)); + +prepst#!#INSERT INTO numeric_table(num) VALUES(?) #!#numeric|-|a1|-|3|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a1|-|123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a1|-|123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a1|-|123|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a1|-|123.45|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a1|-||-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a1|-|-123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a1|-|-123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a1|-|-123|-|5|-|2 +~~ROW COUNT: 1~~ + +#prepst#!#exec#!#numeric|-|a1|-|0|-|5|-|2 +prepst#!#exec#!#numeric|-|a1|-|-1|-|3|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a1|-|-123|-|9|-|2 +~~ROW COUNT: 1~~ + + +prepst#!#exec#!#numeric|-|a1|-|2147483647|-|10|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a1|-|-2147483647|-|10|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a1|-|2147483646|-|10|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a1|-|-2147483646|-|10|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a1|-|2147483648|-|10|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a1|-|-2147483648|-|10|-|0 +~~ROW COUNT: 1~~ + + +SELECT * FROM numeric_table; +~~START~~ +Decimal +3.000 +123.456 +123.400 +123.000 +123.450 + +-123.456 +-123.400 +-123.000 +-1.000 +-123.000 +2147483647.000 +-2147483647.000 +2147483646.000 +-2147483646.000 +2147483648.000 +-2147483648.000 +~~END~~ + + +DROP TABLE numeric_table; + +# JIRA 507, WORKING FOR BABEL +#CREATE TABLE numeric_table(num numeric(39, 20)); + +CREATE TABLE numeric_table(num numeric(38, 20)); + +prepst#!#INSERT INTO numeric_table(num) VALUES(?) #!#numeric|-|a2|-|3|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a2|-|123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a2|-|123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a2|-|123|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a2|-|123.45|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a2|-||-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a2|-|-123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a2|-|-123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a2|-|-123|-|5|-|2 +~~ROW COUNT: 1~~ + +#prepst#!#exec#!#numeric|-|a2|-|0|-|5|-|2 +prepst#!#exec#!#numeric|-|a2|-|-1|-|3|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a2|-|-123|-|9|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a2|-|2147483647|-|10|-|0 +~~ROW COUNT: 1~~ + +SELECT * FROM numeric_table; +~~START~~ +Decimal +3.00000000000000000000 +123.45600000000000000000 +123.40000000000000000000 +123.00000000000000000000 +123.45000000000000000000 + +-123.45600000000000000000 +-123.40000000000000000000 +-123.00000000000000000000 +-1.00000000000000000000 +-123.00000000000000000000 +2147483647.00000000000000000000 +~~END~~ + + +DROP TABLE numeric_table; + +CREATE TABLE numeric_table(num numeric(38, 20)); +prepst#!#INSERT INTO numeric_table(num) VALUES(?) #!#numeric|-|a3|-|3|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a3|-|123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a3|-|123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a3|-|123|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a3|-|123.45|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a3|-||-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a3|-|-123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a3|-|-123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a3|-|-123|-|5|-|2 +~~ROW COUNT: 1~~ + +#prepst#!#exec#!#numeric|-|a3|-|0|-|5|-|2 +prepst#!#exec#!#numeric|-|a3|-|-1|-|3|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a3|-|-123|-|9|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a3|-|2147483647|-|10|-|0 +~~ROW COUNT: 1~~ + +SELECT * FROM numeric_table; +~~START~~ +Decimal +3.00000000000000000000 +123.45600000000000000000 +123.40000000000000000000 +123.00000000000000000000 +123.45000000000000000000 + +-123.45600000000000000000 +-123.40000000000000000000 +-123.00000000000000000000 +-1.00000000000000000000 +-123.00000000000000000000 +2147483647.00000000000000000000 +~~END~~ + + +DROP TABLE numeric_table; + +CREATE TABLE numeric_table(num numeric(38, 21)); +prepst#!#INSERT INTO numeric_table(num) VALUES(?) #!#numeric|-|a4|-|3|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a4|-|123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a4|-|123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a4|-|123|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a4|-|123.45|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a4|-||-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a4|-|-123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a4|-|-123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a4|-|-123|-|5|-|2 +~~ROW COUNT: 1~~ + +#prepst#!#exec#!#numeric|-|a4|-|0|-|5|-|2 +prepst#!#exec#!#numeric|-|a4|-|-1|-|3|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a4|-|-123|-|9|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a4|-|2147483647|-|10|-|0 +~~ROW COUNT: 1~~ + +SELECT * FROM numeric_table; +~~START~~ +Decimal +3.000000000000000000000 +123.456000000000000000000 +123.400000000000000000000 +123.000000000000000000000 +123.450000000000000000000 + +-123.456000000000000000000 +-123.400000000000000000000 +-123.000000000000000000000 +-1.000000000000000000000 +-123.000000000000000000000 +2147483647.000000000000000000000 +~~END~~ + + +DROP TABLE numeric_table; + +CREATE TABLE numeric_table(num numeric(38, 22)); +prepst#!#INSERT INTO numeric_table(num) VALUES(?) #!#numeric|-|a5|-|3|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a5|-|123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a5|-|123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a5|-|123|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a5|-|123.45|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a5|-||-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a5|-|-123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a5|-|-123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a5|-|-123|-|5|-|2 +~~ROW COUNT: 1~~ + +#prepst#!#exec#!#numeric|-|a5|-|0|-|5|-|2 +prepst#!#exec#!#numeric|-|a5|-|-1|-|3|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a5|-|-123|-|9|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a5|-|2147483647|-|10|-|0 +~~ROW COUNT: 1~~ + +SELECT * FROM numeric_table; +~~START~~ +Decimal +3.0000000000000000000000 +123.4560000000000000000000 +123.4000000000000000000000 +123.0000000000000000000000 +123.4500000000000000000000 + +-123.4560000000000000000000 +-123.4000000000000000000000 +-123.0000000000000000000000 +-1.0000000000000000000000 +-123.0000000000000000000000 +2147483647.0000000000000000000000 +~~END~~ + + +DROP TABLE numeric_table; + +CREATE TABLE numeric_table(num numeric(38, 23)); +prepst#!#INSERT INTO numeric_table(num) VALUES(?) #!#numeric|-|a6|-|3|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a6|-|123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a6|-|123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a6|-|123|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a6|-|123.45|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a6|-||-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a6|-|-123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a6|-|-123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a6|-|-123|-|5|-|2 +~~ROW COUNT: 1~~ + +#prepst#!#exec#!#numeric|-|a6|-|0|-|5|-|2 +prepst#!#exec#!#numeric|-|a6|-|-1|-|3|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a6|-|-123|-|9|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a6|-|2147483647|-|10|-|0 +~~ROW COUNT: 1~~ + +SELECT * FROM numeric_table; +~~START~~ +Decimal +3.00000000000000000000000 +123.45600000000000000000000 +123.40000000000000000000000 +123.00000000000000000000000 +123.45000000000000000000000 + +-123.45600000000000000000000 +-123.40000000000000000000000 +-123.00000000000000000000000 +-1.00000000000000000000000 +-123.00000000000000000000000 +2147483647.00000000000000000000000 +~~END~~ + + +DROP TABLE numeric_table; + +CREATE TABLE numeric_table(num numeric(38, 25)); +prepst#!#INSERT INTO numeric_table(num) VALUES(?) #!#numeric|-|a7|-|3|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a7|-|123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a7|-|123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a7|-|123|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a7|-|123.45|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a7|-||-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a7|-|-123.456|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a7|-|-123.4|-|5|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a7|-|-123|-|5|-|2 +~~ROW COUNT: 1~~ + +#prepst#!#exec#!#numeric|-|a7|-|0|-|5|-|2 +prepst#!#exec#!#numeric|-|a7|-|-1|-|3|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a7|-|-123|-|9|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a7|-|247483647|-|10|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#numeric|-|a7|-|-247483647|-|10|-|0 +~~ROW COUNT: 1~~ + +SELECT * FROM numeric_table; +~~START~~ +Decimal +3.0000000000000000000000000 +123.4560000000000000000000000 +123.4000000000000000000000000 +123.0000000000000000000000000 +123.4500000000000000000000000 + +-123.4560000000000000000000000 +-123.4000000000000000000000000 +-123.0000000000000000000000000 +-1.0000000000000000000000000 +-123.0000000000000000000000000 +247483647.0000000000000000000000000 +-247483647.0000000000000000000000000 +~~END~~ + + +DROP TABLE numeric_table; + + +CREATE TABLE numeric_table(num numeric(38, 25)); + +insert into numeric_table values (2147483647) +~~ROW COUNT: 1~~ + +insert into numeric_table values (-2147483647) +~~ROW COUNT: 1~~ + + +insert into numeric_table values (2147483646) +~~ROW COUNT: 1~~ + +insert into numeric_table values (-2147483646) +~~ROW COUNT: 1~~ + + +insert into numeric_table values (2147483648) +~~ROW COUNT: 1~~ + +insert into numeric_table values (-2147483648) +~~ROW COUNT: 1~~ + + +#insert into numeric_table values(123456789123456789.1234567891234567891234567); +#insert into numeric_table values(1234567891234567891.1234567891234567891234567); +#insert into numeric_table values(123456789123456789.12345678912345678912345678); +insert into numeric_table values(0.0); +~~ROW COUNT: 1~~ + +insert into numeric_table values(0.0000000000000000000000000); +~~ROW COUNT: 1~~ + +insert into numeric_table values(0.00000000000000000000000000); +~~ROW COUNT: 1~~ + + +SELECT * FROM numeric_table; +~~START~~ +Decimal +2147483647.0000000000000000000000000 +-2147483647.0000000000000000000000000 +2147483646.0000000000000000000000000 +-2147483646.0000000000000000000000000 +2147483648.0000000000000000000000000 +-2147483648.0000000000000000000000000 +0E-25 +0E-25 +0E-25 +~~END~~ + + +DROP TABLE numeric_table; + +# BABEL-1459 +declare @numvar numeric(5,4); set @numvar=-0.010; SELECT @numvar as N'@var'; +~~START~~ +Decimal +-0.0100 +~~END~~ + +declare @numvar numeric(4,4); set @numvar=-0.010; SELECT @numvar as N'@var'; +~~START~~ +Decimal +-0.0100 +~~END~~ + +declare @numvar numeric(5,4); set @numvar=1.01; SELECT @numvar as N'@var'; +~~START~~ +Decimal +1.0100 +~~END~~ + +declare @numvar numeric(4,4); set @numvar=0.01; SELECT @numvar as N'@var'; +~~START~~ +Decimal +0.0100 +~~END~~ + +declare @numvar numeric(4,4); set @numvar=0; SELECT @numvar as N'@var'; +~~START~~ +Decimal +0.0000 +~~END~~ + diff --git a/contrib/test/python/expected/pyodbc/TestReal.out b/contrib/test/python/expected/pyodbc/TestReal.out new file mode 100644 index 00000000000..3fb792e349f --- /dev/null +++ b/contrib/test/python/expected/pyodbc/TestReal.out @@ -0,0 +1,102 @@ +CREATE TABLE REAL_dt (a REAL) +prepst#!# INSERT INTO REAL_dt(a) values(?) #!#REAL|-|a|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#REAL|-|a|-|1.050 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#REAL|-|a|-|01.05 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#REAL|-|a|-|0001202 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#REAL|-|a|-|-024112329 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#REAL|-|a|-|-02.5 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#REAL|-|a|-|0000000000000000086 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#REAL|-|a|-|-3.40E+38 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#REAL|-|a|-|3.40E+38 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#REAL|-|a|-| +~~ROW COUNT: 1~~ + +SELECT * FROM REAL_dt; +~~START~~ +float +0.0 +1.0499999523162842 +1.0499999523162842 +1202.0 +-24112328.0 +-2.5 +86.0 +-3.3999999521443642e+38 +3.3999999521443642e+38 + +~~END~~ + +INSERT INTO REAL_dt(a) values(0) +~~ROW COUNT: 1~~ + +INSERT INTO REAL_dt(a) values(1.050) +~~ROW COUNT: 1~~ + +INSERT INTO REAL_dt(a) values(01.05) +~~ROW COUNT: 1~~ + +INSERT INTO REAL_dt(a) values(-004) +~~ROW COUNT: 1~~ + +INSERT INTO REAL_dt(a) values(-0122455324.5) +~~ROW COUNT: 1~~ + +INSERT INTO REAL_dt(a) values(-000002) +~~ROW COUNT: 1~~ + +INSERT INTO REAL_dt(a) values(0000000000000000086) +~~ROW COUNT: 1~~ + +INSERT INTO REAL_dt(a) values(-3.40E+38) +~~ROW COUNT: 1~~ + +INSERT INTO REAL_dt(a) values(3.40E+38) +~~ROW COUNT: 1~~ + +INSERT INTO REAL_dt(a) values(NULL) +~~ROW COUNT: 1~~ + +SELECT * FROM REAL_dt; +~~START~~ +float +0.0 +1.0499999523162842 +1.0499999523162842 +1202.0 +-24112328.0 +-2.5 +86.0 +-3.3999999521443642e+38 +3.3999999521443642e+38 + +0.0 +1.0499999523162842 +1.0499999523162842 +-4.0 +-122455328.0 +-2.0 +86.0 +-3.3999999521443642e+38 +3.3999999521443642e+38 + +~~END~~ + +DROP TABLE REAL_dt; diff --git a/contrib/test/python/expected/pyodbc/TestSPExecutesql.out b/contrib/test/python/expected/pyodbc/TestSPExecutesql.out new file mode 100644 index 00000000000..d5d9ad98484 --- /dev/null +++ b/contrib/test/python/expected/pyodbc/TestSPExecutesql.out @@ -0,0 +1,243 @@ +CREATE TABLE spExecutesqlTable1 (a INT, b VARCHAR(10)); +CREATE TABLE spExecutesqlTable2 (a INT, b INT, c INT, d INT); +GO +/* 1. Execute a string of statement */ +DECLARE @SQLString NVARCHAR(100); +SET @SQLString = N'SELECT N''hello world'';'; +EXEC sp_executesql @SQLString; +GO +~~START~~ +str +hello world +~~END~~ + +/* 2. Execute a statement string with parameters */ +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'INSERT INTO spExecutesqlTable1 VALUES (@a, @b);'; +SET @ParamDef = N'@a INT, @b VARCHAR(10)'; +DECLARE @p INT = 1; +EXEC sp_executesql @SQLString, @ParamDef, @p, @b = N'hello'; +SELECT * FROM spExecutesqlTable1; +GO +~~ROW COUNT: 1~~ + +~~START~~ +int#!#str +1#!#hello +~~END~~ + +TRUNCATE TABLE spExecutesqlTable1; +GO +/* 3. Execute a statement string with both unnamed params and named params */ +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'INSERT INTO spExecutesqlTable2 VALUES (@a, @b, @c, @d);'; +SET @ParamDef = N'@a INT, @b INT, @c INT, @d INT'; +EXEC sp_executesql @SQLString, @ParamDef, 1, 2, @d = 4, @c = 3; +SELECT * FROM spExecutesqlTable2; +GO +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int#!#int#!#int +1#!#2#!#3#!#4 +~~END~~ + +TRUNCATE TABLE spExecutesqlTable2; +GO +/* 4. Nested sp_executesql */ +DECLARE @SQLString1 NVARCHAR(100); +DECLARE @SQLString2 NVARCHAR(max); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString1 = N'INSERT INTO spExecutesqlTable1 VALUES (@a, @b);' +SET @SQLString2 = @SQLString1 + N'EXEC sp_executesql N''INSERT INTO spExecutesqlTable1 VALUES (@c + @c, @d + @d);'', N''@c INT, @d VARCHAR(10)'', @a, @b;' +SET @ParamDef = N'@a INT, @b VARCHAR(10)'; +EXEC sp_executesql @SQLString2, @ParamDef, @a = 10, @b = N'str'; +SELECT * FROM spExecutesqlTable1; +GO +~~ROW COUNT: 1~~ + +~~START~~ +int#!#str +10#!#str +20#!#strstr +~~END~~ + +TRUNCATE TABLE spExecutesqlTable1; +GO +-- Nested with param name collision +DECLARE @SQLString1 NVARCHAR(100); +DECLARE @SQLString2 NVARCHAR(max); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString1 = N'INSERT INTO spExecutesqlTable1 VALUES (@a, @b);' +SET @SQLString2 = @SQLString1 + N'EXEC sp_executesql N''INSERT INTO spExecutesqlTable1 VALUES (@a + @a, @b + @b);'', N''@a INT, @b VARCHAR(10)'', @a, @b;' +SET @ParamDef = N'@a INT, @b VARCHAR(10)'; +EXEC sp_executesql @SQLString2, @ParamDef, @a = 11, @b = N'rts'; +SELECT * FROM spExecutesqlTable1; +GO +~~ROW COUNT: 1~~ + +~~START~~ +int#!#str +11#!#rts +22#!#rtsrts +~~END~~ + +TRUNCATE TABLE spExecutesqlTable1; +GO +/* 5. Execute a statement string with OUT/INOUT param */ +DECLARE @SQLString1 NVARCHAR(100); +DECLARE @SQLString2 NVARCHAR(max); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString1 = N'SET @a = @b + @b'; +SET @SQLString2 = N'EXEC sp_executesql N''SET @a = @b + @b'', N''@a INT OUT, @b INT'', @a OUT, @b;'; +SET @ParamDef = N'@a INT OUTPUT, @b INT'; +DECLARE @p INT; +DECLARE @a INT; +-- OUT param +EXEC sp_executesql @SQLString1, @ParamDef, @a = @p OUT, @b = 10; +-- Nested with OUT param name collision +EXEC sp_executesql @SQLString2, @ParamDef, @a = @a OUT, @b = 11; +SELECT @p, @a; +GO +~~START~~ +int#!#int +20#!#22 +~~END~~ + +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'SET @a = @a + 1;'; +SET @ParamDef = N'@a INT OUT'; +DECLARE @p1 INT = 1; +DECLARE @p2 INT = 1; +-- Declared as INOUT and called as OUT +EXEC sp_executesql @SQLString, @ParamDef, @a = @p1 OUT; +-- Declared as INOUT and called as IN +EXEC sp_executesql @SQLString, @ParamDef, @a = @p2; +SELECT @p1, @p2; +GO +~~START~~ +int#!#int +2#!#1 +~~END~~ + +/* 6. Implicit cast for IN param */ +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'SET @b = @a;'; +SET @ParamDef = N'@a FLOAT, @b FLOAT OUT'; +DECLARE @p FLOAT; +DECLARE @a MONEY = 3.14; +EXEC sp_executesql @SQLString, @ParamDef, @a = @a, @b = @p OUTPUT; +SELECT @p; +GO +~~START~~ +float +3.14 +~~END~~ + +/* 7. Implicit cast for OUT param */ +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'SET @a = CAST(''2020-01-01'' AS DATE); SET @b = @a;'; +SET @ParamDef = N'@a DATE OUT, @b DATETIME OUT'; +DECLARE @p1 DATETIME; +DECLARE @p2 DATETIME; +EXEC sp_executesql @SQLString, @ParamDef, @a = @p1 OUT, @b = @p2 OUT; +SELECT @p1, @p2; +GO +~~START~~ +datetime#!#datetime +2020-01-01 00:00:00#!#2020-01-01 00:00:00 +~~END~~ + +/* Exceptions */ +/* 1. Wrong order of named/unnamed params */ +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'INSERT INTO spExecutesqlTable2 VALUES (@a, @b, @c, @d);'; +SET @ParamDef = N'@a INT, @b INT, @c INT, @d INT'; +EXEC sp_executesql @SQLString, @ParamDef, @b = 2, @c = 3, 1, @d = 4; +GO +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]syntax error near '1' at line 7 and character position 58 (33557097) (SQLExecDirectW))~~ + +/* 2. Number mismatch of param defs and given params */ +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'INSERT INTO spExecutesqlTable2 VALUES (@a, @b, @c, @d);'; +SET @ParamDef = N'@a INT, @b INT, @c INT, @d INT'; +EXEC sp_executesql @SQLString, @ParamDef, 1, 2, 3; +GO +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]param definition mismatches with inputs (33557097) (SQLExecDirectW))~~ + +/* 3. Invalid param name */ +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'INSERT INTO spExecutesqlTable2 VALUES (@a, @b, @c, @d);'; +SET @ParamDef = N'@a INT, @b INT, @c INT, @d INT'; +EXEC sp_executesql @SQLString, @ParamDef, @a = 1, @b = 2, @c = 3, @e = 4; +GO +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]param "@e" not defined (33557097) (SQLExecDirectW))~~ + +/* 4. Invalid param def */ +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'INSERT INTO spExecutesqlTable2 VALUES (@a, @b, @c, @d);'; +SET @ParamDef = N'@a INT, @b INT, @c, @d INT'; +EXEC sp_executesql @SQLString, @ParamDef, 1, 2, 3, 4; +GO +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]syntax error at or near "," (33557097) (SQLExecDirectW))~~ + +/* 5. Unsupported implicit cast */ +-- IN param +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'INSERT INTO spExecutesqlTable2 VALUES (@a, @b, @c, @d);'; +SET @ParamDef = N'@a INT, @b INT, @c INT, @d INT'; +EXEC sp_executesql @SQLString, @ParamDef, 1, 3.14, 'hello', 4; +GO +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]invalid input syntax for type integer: "hello" (33557097) (SQLExecDirectW))~~ + +-- OUT param +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'SET @a = CAST(''abc'' AS VARCHAR(3));'; +SET @ParamDef = N'@a FLOAT OUT'; +DECLARE @p FLOAT; +EXEC sp_executesql @SQLString, @ParamDef, @a = @p OUT; +GO +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]invalid input syntax for type double precision: "abc" (33557097) (SQLExecDirectW))~~ + +/* 6. Invalid OUT param */ +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'SET @a = 20'; +SET @ParamDef = N'@a INT OUT'; +EXEC sp_executesql @SQLString, @ParamDef, @a = 10 OUT; +GO +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]syntax error near ';' at line 6 and character position 53 (33557097) (SQLExecDirectW))~~ + +/* 7. Param declared as IN but called as OUT */ +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'SET @a = 20'; +SET @ParamDef = N'@a INT'; +DECLARE @p INT; +EXEC sp_executesql @SQLString, @ParamDef, @a = @p OUT; +GO +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]param @a defined as mode i but received mode b (33557097) (SQLExecDirectW))~~ + +/* Clean up */ +DROP TABLE spExecutesqlTable1; +DROP TABLE spExecutesqlTable2; +GO diff --git a/contrib/test/python/expected/pyodbc/TestSPPrepare.out b/contrib/test/python/expected/pyodbc/TestSPPrepare.out new file mode 100644 index 00000000000..6ecd7d85e2e --- /dev/null +++ b/contrib/test/python/expected/pyodbc/TestSPPrepare.out @@ -0,0 +1,567 @@ +--- Simple SP_PREPARE +DECLARE @handle int; +EXEC SP_PREPARE @handle, NULL, 'SELECT ''OK''' +EXEC SP_EXECUTE @handle +EXEC SP_EXECUTE @handle +EXEC SP_EXECUTE @handle +EXEC SP_UNPREPARE @handle +GO +~~START~~ +str +~~END~~ + +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]handle argument of sp_execute is null (33557097) (SQLMoreResults))~~ + +--- Simple SP_PREPEXEC +DECLARE @handle int; +EXEC SP_PREPEXEC @handle OUT, NULL, 'SELECT ''OK''' +EXEC SP_EXECUTE @handle +EXEC SP_EXECUTE @handle +EXEC SP_EXECUTE @handle +EXEC SP_UNPREPARE @handle +GO +~~START~~ +str +OK +~~END~~ + +~~START~~ +str +OK +~~END~~ + +~~START~~ +str +OK +~~END~~ + +~~START~~ +str +OK +~~END~~ + +--- Basic SP_PREPARE with args +DECLARE @handle int; +EXEC SP_PREPARE @handle out, N'@a int, @b int', N'select @a, @b', 10; +EXEC SP_EXECUTE @handle, 1, 2 +EXEC SP_EXECUTE @handle, 1, 2 +EXEC SP_EXECUTE @handle, 1, 2 +EXEC SP_UNPREPARE @handle; +GO +~~START~~ +int#!#int +~~END~~ + +~~START~~ +int#!#int +1#!#2 +~~END~~ + +~~START~~ +int#!#int +1#!#2 +~~END~~ + +~~START~~ +int#!#int +1#!#2 +~~END~~ + +--- Basic SP_PREPARE with args +DECLARE @handle int; +EXEC SP_PREPEXEC @handle out, N'@a int, @b int', N'select @a, @b', 1, 2; +EXEC SP_EXECUTE @handle, 1, 2 +EXEC SP_EXECUTE @handle, 1, 2 +EXEC SP_EXECUTE @handle, 1, 2 +EXEC SP_UNPREPARE @handle; +GO +~~START~~ +int#!#int +1#!#2 +~~END~~ + +~~START~~ +int#!#int +1#!#2 +~~END~~ + +~~START~~ +int#!#int +1#!#2 +~~END~~ + +~~START~~ +int#!#int +1#!#2 +~~END~~ + +--- SP_PREPARE Batch Support +DECLARE @handle int; +DECLARE @batch nvarchar(500); +DECLARE @paramdef nvarchar(500); +DECLARE @var int; +SET @batch = 'IF (@cond > 0) SELECT @o = @a ELSE SELECT @o = @b' +SET @paramdef = '@cond int, @a int, @b int, @o int OUTPUT' +EXEC SP_PREPARE @handle, @paramdef, @batch +EXEC SP_EXECUTE @handle, -1, 10, 20, @var OUTPUT +SELECT @var +EXEC SP_EXECUTE @handle, 1, 10, 20, @var OUTPUT +SELECT @var +EXEC SP_UNPREPARE @handle; +GO +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]handle argument of sp_execute is null (33557097) (SQLExecDirectW))~~ + +--- SP_PREPEXEC Batch Support +DECLARE @handle int; +DECLARE @batch nvarchar(500); +DECLARE @paramdef nvarchar(500); +DECLARE @var int; +SET @batch = 'IF (@cond > 0) SELECT @o = @a ELSE SELECT @o = @b' +SET @paramdef = '@cond int, @a int, @b int, @o int OUTPUT' +EXEC SP_PREPEXEC @handle out, @paramdef, @batch, 1, 30, 40, @var OUTPUT +SELECT @var +EXEC SP_EXECUTE @handle, -1, 10, 20, @var OUTPUT +SELECT @var +EXEC SP_EXECUTE @handle, 1, 10, 20, @var OUTPUT +SELECT @var +EXEC SP_UNPREPARE @handle; +GO +~~START~~ +int +30 +~~END~~ + +~~START~~ +int +20 +~~END~~ + +~~START~~ +int +10 +~~END~~ + +--- Parsing specific +DECLARE @handle int; +EXEC SP_PREPEXEC @handle + 1 OUTPUT, NULL, 'SELECT 1' +GO +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]syntax error near '+' at line 3 and character position 25 (33557097) (SQLExecDirectW))~~ + +DECLARE @handle VARCHAR(20) +EXEC SP_PREPEXEC @handle OUTPUT, NULL, 'SELECT 1' +GO +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]invalid prepared_handle param datatype (33557097) (SQLExecDirectW))~~ + +DECLARE @handle int; +EXEC SP_PREPEXEC @handle, NULL, 'SELECT 1' +GO +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]prepared_handle param is not specified as OUTPUT (33557097) (SQLExecDirectW))~~ + +--- Corner case 1: empty batch +DECLARE @handle int; +EXEC SP_PREPARE @handle out, NULL, NULL +EXEC SP_EXECUTE @handle +EXEC SP_UNPREPARE @handle +GO +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]query argument of sp_prepare is null (33557097) (SQLExecDirectW))~~ + +DECLARE @handle int; +EXEC SP_PREPEXEC @handle out, NULL, NULL +EXEC SP_EXECUTE @handle +EXEC SP_UNPREPARE @handle +GO +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]batch string argument of sp_prepexec is null (33557097) (SQLExecDirectW))~~ + +--- Corner case 2: nested prepare +DECLARE @handle int; +DECLARE @inner_handle int; +DECLARE @batch VARCHAR(500); +SET @batch = 'EXEC SP_PREPARE @inner_handle OUT, NULL, ''SELECT 1'' ' +EXEC SP_PREPARE @handle out, '@inner_handle int OUT', @batch +EXEC SP_EXECUTE @handle, @inner_handle OUT +EXEC SP_EXECUTE @inner_handle +EXEC SP_UNPREPARE @inner_handle -- unprepare inner first +EXEC SP_UNPREPARE @handle +GO +~~START~~ +int +~~END~~ + +~~START~~ +int +1 +~~END~~ + +DECLARE @handle int; +DECLARE @inner_handle int; +DECLARE @batch VARCHAR(500); +SET @batch = 'EXEC SP_PREPARE @inner_handle OUT, NULL, ''SELECT 1'' ' +EXEC SP_PREPARE @handle out, '@inner_handle int OUT', @batch +EXEC SP_EXECUTE @handle, @inner_handle OUT +EXEC SP_EXECUTE @inner_handle +EXEC SP_UNPREPARE @handle --unprepare outer first +EXEC SP_EXECUTE @inner_handle +EXEC SP_UNPREPARE @inner_handle +GO +~~START~~ +int +~~END~~ + +~~START~~ +int +1 +~~END~~ + +~~START~~ +int +1 +~~END~~ + +--- Corner case 3: mismatch paramdef and params +DECLARE @handle int; +DECLARE @var int; +DECLARE @batch VARCHAR(500); +DECLARE @paramdef VARCHAR(500); +SET @batch = 'SELECT @a'; +SET @paramdef = '@a int'; +EXEC SP_PREPARE @handle OUT, @paramdef, @batch +EXEC SP_EXECUTE @handle, 100 +EXEC SP_EXECUTE @handle, @var OUT +EXEC SP_UNPREPARE @handle +GO +~~START~~ +int +~~END~~ + +~~START~~ +int +100 +~~END~~ + +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]param 1 defined as mode i but received mode b (33557097) (SQLMoreResults))~~ + +--- Prepare DML statement +CREATE TABLE t1 (a int, b int); +GO +DECLARE @handle int; +DECLARE @batch VARCHAR(500); +DECLARE @paramdef VARCHAR(500); +SET @batch = ' +INSERT INTO t1 VALUES (@v1, @v2) +INSERT INTO t1 VALUES (@v3, @v4) +' +SET @paramdef = '@v1 int, @v2 int, @v3 int, @v4 int' +EXEC SP_PREPARE @handle OUT, @paramdef, @batch +EXEC SP_EXECUTE @handle, 1, 2, 2, 3 +EXEC SP_EXECUTE @handle, 3, 4, 4, 5 +SELECT * FROM t1 ORDER BY 1, 2; +GO +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +1#!#2 +2#!#3 +3#!#4 +4#!#5 +~~END~~ + +DECLARE @handle int; +DECLARE @batch VARCHAR(500); +DECLARE @paramdef VARCHAR(500); +SET @batch = ' +UPDATE t1 SET a = a * 10, b = b *10 where a = @var1; +UPDATE t1 SET a = a * 10, b = b *10 where a = @var2; +' +SET @paramdef = '@var1 int, @var2 int' +EXEC SP_PREPARE @handle OUT, @paramdef, @batch +EXEC SP_EXECUTE @handle, 1, 2 +EXEC SP_EXECUTE @handle, 3, 4 +SELECT * FROM t1 ORDER BY 1, 2; +EXEC SP_UNPREPARE @handle +DROP TABLE t1; +GO +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +10#!#20 +20#!#30 +30#!#40 +40#!#50 +~~END~~ + +--- Transaction with SP_EXECUTE +CREATE TABLE t1 (a int, b int); +GO +DECLARE @handle int; +DECLARE @batch VARCHAR(500); +DECLARE @paramdef VARCHAR(500); +SET @batch = ' +INSERT INTO t1 VALUES (@v1, @v2); +INSERT INTO t1 VALUES (@v3, @v4); +' +SET @paramdef = '@v1 int, @v2 int, @v3 int, @v4 int' +EXEC SP_PREPARE @handle OUT, @paramdef, @batch +BEGIN TRANSACTION; +EXEC SP_EXECUTE @handle, 1, 2, 2, 3 +SELECT * FROM t1 ORDER BY 1, 2; +COMMIT; +SELECT * FROM t1 ORDER BY 1, 2; +BEGIN TRANSACTION; +EXEC SP_EXECUTE @handle, 3, 4, 4, 5 +SELECT * FROM t1 ORDER BY 1, 2; +ROLLBACK; +SELECT * FROM t1 ORDER BY 1, 2; +EXEC SP_UNPREPARE @handle +GO +~~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 +3#!#4 +4#!#5 +~~END~~ + +~~START~~ +int#!#int +1#!#2 +2#!#3 +~~END~~ + +DROP TABLE t1; +GO +--- PREPARE Batch with Transaction +CREATE TABLE t1 (a int, b int); +GO +DECLARE @handle int; +DECLARE @batch VARCHAR(500); +DECLARE @paramdef VARCHAR(500); +SET @batch = ' +BEGIN TRANSACTION +INSERT INTO t1 VALUES (@v1, @v2); +INSERT INTO t1 VALUES (@v3, @v4); +SELECT * FROM t1 ORDER BY 1, 2; +IF (@v1 = 10) + COMMIT; +ELSE + ROLLBACK; +' +SET @paramdef = '@v1 int, @v2 int, @v3 int, @v4 int' +EXEC SP_PREPARE @handle OUT, @paramdef, @batch +EXEC SP_EXECUTE @handle, 10, 20, 30, 40 +SELECT * FROM t1 ORDER BY 1, 2; +EXEC SP_EXECUTE @handle, 50, 60, 70, 80 +SELECT * FROM t1 ORDER BY 1, 2; +EXEC SP_UNPREPARE @handle +GO +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +10#!#20 +30#!#40 +~~END~~ + +~~START~~ +int#!#int +10#!#20 +30#!#40 +~~END~~ + +~~START~~ +int#!#int +10#!#20 +30#!#40 +50#!#60 +70#!#80 +~~END~~ + +~~START~~ +int#!#int +10#!#20 +30#!#40 +~~END~~ + +DROP TABLE t1; +GO +-- Test Save Point +CREATE TABLE t1 ( a int, b int); +GO +DECLARE @handle int; +DECLARE @batch VARCHAR(500); +SET @batch = ' +DECLARE @handle int; +BEGIN TRANSACTION; +INSERT INTO t1 VALUES (1, 2); +SAVE TRANSACTION my_savept; +EXEC SP_PREPEXEC @handle OUT, NULL, +''INSERT INTO t1 VALUES (3, 4); + SELECT * FROM t1 ORDER BY 1, 2; + ROLLBACK TRANSACTION my_savept; + SELECT * FROM t1 ORDER BY 1, 2; +''; +SELECT * FROM t1 ORDER BY 1, 2; +ROLLBACK; +SELECT * FROM t1 ORDER BY 1, 2; +EXEC SP_UNPREPARE @handle; +' +EXEC SP_PREPARE @handle OUT, NULL, @batch; +PRINT @handle +EXEC SP_EXECUTE @handle; +EXEC SP_UNPREPARE @handle; +GO +DROP TABLE t1; +GO +--- Test string type +CREATE TABLE t1 ( a VARCHAR(10), b VARCHAR(10)); +GO +DECLARE @handle int; +EXEC SP_PREPEXEC @handle OUT, '@v1 VARCHAR(10), @v2 VARCHAR(10)', 'INSERT INTO t1 VALUES (@v1,@v2)', 'abc', 'efg' +EXEC SP_EXECUTE @handle, 'lmn', 'opq' +EXEC SP_UNPREPARE @handle +SELECT * FROM t1 ORDER BY 1, 2; +GO +~~ROW COUNT: 1~~ + +~~START~~ +str#!#str +abc#!#efg +lmn#!#opq +~~END~~ + +DROP TABLE t1; +GO +-- Test transaction begins outside the batch and commited/rollbacked inside the batch +CREATE TABLE t1 (a INT); +GO +BEGIN TRAN; +GO +DECLARE @handle INT; +DECLARE @batch VARCHAR(500); +SET @batch = 'insert into t1 values(1); commit; begin tran;' +EXEC sp_prepare @handle OUT, NULL, @batch +EXEC sp_execute @handle +EXEC sp_execute @handle +EXEC SP_UNPREPARE @handle; +COMMIT; +SELECT COUNT(*) FROM t1; +GO +~~ROW COUNT: 1~~ + +~~START~~ +int +2 +~~END~~ + +BEGIN TRAN; +GO +DECLARE @handle INT; +DECLARE @batch VARCHAR(500); +SET @batch = 'insert into t1 values(1); rollback tran; begin tran;' +EXEC sp_prepare @handle OUT, NULL, @batch +EXEC sp_execute @handle +EXEC sp_execute @handle +EXEC SP_UNPREPARE @handle; +COMMIT; +SELECT COUNT(*) FROM t1; +GO +~~ROW COUNT: 1~~ + +~~START~~ +int +2 +~~END~~ + +DROP TABLE t1; +GO +-- prepare time error 1 +DECLARE @handle int; +EXEC SP_PREPARE @handle OUT, NULL, 'SELECT * FROM t1' +SELECT @handle IS NOT NULL as 'Prepared' +GO +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]syntax error near 'IS' at line 4 and character position 15 (33557097) (SQLExecDirectW))~~ + +-- prepare time error 1-2 +DECLARE @handle int; +EXEC SP_PREPARE @handle OUT, NULL, 'DECLARE @var int; SELECT * FROM t1 WHERE c = @var' +SELECT @handle IS NOT NULL as 'Prepared' +GO +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]syntax error near 'IS' at line 4 and character position 15 (33557097) (SQLExecDirectW))~~ + +-- prepare time error 2 +DECLARE @handle int; +EXEC SP_PREPARE @handle OUT, NULL, 'EXEC my_proc' +SELECT @handle IS NOT NULL as 'Prepared' +GO +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]syntax error near 'IS' at line 4 and character position 15 (33557097) (SQLExecDirectW))~~ + +-- prepare time error 2-2 +DECLARE @handle int; +EXEC SP_PREPARE @handle OUT, NULL, 'DECLARE @var int; EXEC my_proc @var' +SELECT @handle IS NOT NULL as 'Prepared' +GO +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]syntax error near 'IS' at line 4 and character position 15 (33557097) (SQLExecDirectW))~~ + +-- runtime error 1 +DECLARE @handle int; +EXEC SP_PREPARE @handle OUT, NULL, 'SELECT * FROM t1; SELECT * FROM t1;' +SELECT @handle IS NOT NULL as 'Prepared' +EXEC SP_EXECUTE @handle +GO +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]syntax error near 'IS' at line 4 and character position 15 (33557097) (SQLExecDirectW))~~ + +-- runtime error 2 +DECLARE @handle int; +EXEC SP_PREPARE @handle OUT, NULL, 'EXEC my_proc; EXEC my_proc;' +SELECT @handle IS NOT NULL as 'Prepared' +EXEC SP_EXECUTE @handle +GO +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]syntax error near 'IS' at line 4 and character position 15 (33557097) (SQLExecDirectW))~~ + +-- runtime error 3 +DECLARE @handle int; +EXEC SP_PREPARE @handle OUT, NULL, 'IF (1=1) SELECT * FROM t1;' +SELECT @handle IS NOT NULL as 'Prepared' +EXEC SP_EXECUTE @handle +GO +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]syntax error near 'IS' at line 4 and character position 15 (33557097) (SQLExecDirectW))~~ + +-- runtime error 4 +DECLARE @handle int; +EXEC SP_PREPARE @handle OUT, NULL, 'DECLARE @var int; SET @var = 1; select * from t1 where c = @var' +SELECT @handle IS NOT NULL as 'Prepared' +EXEC SP_EXECUTE @handle +GO +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]syntax error near 'IS' at line 4 and character position 15 (33557097) (SQLExecDirectW))~~ + diff --git a/contrib/test/python/expected/pyodbc/TestSQLQueries.out b/contrib/test/python/expected/pyodbc/TestSQLQueries.out new file mode 100644 index 00000000000..49a6e2073d7 --- /dev/null +++ b/contrib/test/python/expected/pyodbc/TestSQLQueries.out @@ -0,0 +1,839 @@ +#1 CREATE TABLE with primary and unique keyword +CREATE TABLE tmp(a int PRIMARY KEY, b int UNIQUE); +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Nullable UNIQUE constraint is not supported. Please use babelfishpg_tsql.escape_hatch_unique_constraint to ignore or add a NOT NULL constraint (33557097) (SQLExecDirectW))~~ + +INSERT INTO tmp(a,b) values(1,1); +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]relation "tmp" does not exist (33557097) (SQLExecDirectW))~~ + +INSERT INTO tmp(a,b) values(2,2); +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]relation "tmp" does not exist (33557097) (SQLExecDirectW))~~ + +SELECT * FROM tmp; +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]relation "tmp" does not exist (33557097) (SQLExecDirectW))~~ + +DROP TABLE tmp; +~~ERROR (Code: 3701)~~ +~~ERROR (Message: [42S02] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]table "tmp" does not exist (3701) (SQLExecDirectW))~~ + + +#2 2 table with foreign key relation +#CREATE TABLE tmp1(b int PRIMARY KEY); +#CREATE TABLE tmp2(a int PRIMARY KEY, b int FOREIGN KEY REFERENCES tmp1(b)); +#INSERT INTO tmp1(b) VALUES (1); +#INSERT INTO tmp2(a,b) values(1,1); +#SELECT * FROM tmp1; +#SELECT * FROM tmp2; +#DROP TABLE tmp2; +#DROP TABLE tmp1; + +#3 Repeated #2 with CONSTRAINT keyword +#CREATE TABLE tmp1(b int PRIMARY KEY); +#CREATE TABLE tmp2(a int, b int, PRIMARY KEY(a), CONSTRAINT FK_tmp FOREIGN KEY (b) REFERENCES tmp1(b)); +#INSERT INTO tmp1(b) VALUES (1); +#INSERT INTO tmp2(a,b) values(1,1); +#SELECT * FROM tmp1; +#SELECT * FROM tmp2; +#DROP TABLE tmp2; +#DROP TABLE tmp1; + +#4 CREATE TABLE with NOT NULL column +CREATE TABLE tmp(a int PRIMARY KEY,b int NOT NULL); +INSERT INTO tmp(a,b) values(1,1); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) values(2,1); +~~ROW COUNT: 1~~ + +#INSERT INTO tmp(a,b) values(2,NULL); +SELECT * FROM tmp; +~~START~~ +int#!#int +1#!#1 +2#!#1 +~~END~~ + +DROP TABLE tmp; + +#5 INSERTION and DELETION +CREATE TABLE tmp(a int PRIMARY KEY); +INSERT INTO tmp(a) VALUES(1); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a) VALUES(2); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a) VALUES(3); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a) VALUES(4); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a) VALUES(5); +~~ROW COUNT: 1~~ + +SELECT * FROM tmp; +~~START~~ +int +1 +2 +3 +4 +5 +~~END~~ + +DELETE FROM tmp WHERE a>2; +~~ROW COUNT: 3~~ + +SELECT * FROM tmp; +~~START~~ +int +1 +2 +~~END~~ + +DROP TABLE tmp; + +#6 IS NOT NULL condition in WHERE clause +CREATE TABLE tmp(a int PRIMARY KEY,b int); +INSERT INTO tmp(a,b) values(1,1); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) values(2,1); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) values(3,NULL); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) values(4,NULL); +~~ROW COUNT: 1~~ + +SELECT * FROM tmp WHERE b IS NOT NULL; +~~START~~ +int#!#int +1#!#1 +2#!#1 +~~END~~ + +DROP TABLE tmp; + +#7 Add new column using ALTER TABLE +CREATE TABLE tmp(a int PRIMARY KEY); +INSERT INTO tmp(a) VALUES(1); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a) VALUES(2); +~~ROW COUNT: 1~~ + +SELECT * FROM tmp; +~~START~~ +int +1 +2 +~~END~~ + +ALTER TABLE tmp ADD b VARCHAR(20) NULL; +SELECT * FROM tmp; +~~START~~ +int#!#str +1#!# +2#!# +~~END~~ + +INSERT INTO tmp(a,b) VALUES(4,'Dipesh'); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(5,' Dipesh'); +~~ROW COUNT: 1~~ + +SELECT * FROM tmp; +~~START~~ +int#!#str +1#!# +2#!# +4#!#Dipesh +5#!# Dipesh +~~END~~ + +DROP TABLE tmp; + +#8 Repeated #8 with default value for newly added col +CREATE TABLE tmp(a int PRIMARY KEY); +INSERT INTO tmp(a) VALUES(1); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a) VALUES(2); +~~ROW COUNT: 1~~ + +SELECT * FROM tmp; +~~START~~ +int +1 +2 +~~END~~ + +ALTER TABLE tmp ADD b VARCHAR(20) DEFAULT 'Dipesj'; +SELECT * FROM tmp; +~~START~~ +int#!#str +1#!#Dipesj +2#!#Dipesj +~~END~~ + +INSERT INTO tmp(a,b) VALUES(4,'Dipesh'); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(5,' Dipesh'); +~~ROW COUNT: 1~~ + +SELECT * FROM tmp; +~~START~~ +int#!#str +1#!#Dipesj +2#!#Dipesj +4#!#Dipesh +5#!# Dipesh +~~END~~ + +DROP TABLE tmp; + +#9 Change datatype of existing column using ALTER TABLE +CREATE TABLE tmp(a int PRIMARY KEY,b int); +INSERT INTO tmp(a,b) VALUES(1,1); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(2,2); +~~ROW COUNT: 1~~ + +SELECT * FROM tmp; +~~START~~ +int#!#int +1#!#1 +2#!#2 +~~END~~ + +ALTER TABLE tmp ALTER COLUMN b VARCHAR(10); +SELECT * FROM tmp; +~~START~~ +int#!#str +1#!#1 +2#!#2 +~~END~~ + +INSERT INTO tmp(a,b) VALUES(4,'Dipesh'); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(5,' Dipesh'); +~~ROW COUNT: 1~~ + +SELECT * FROM tmp; +~~START~~ +int#!#str +1#!#1 +2#!#2 +4#!#Dipesh +5#!# Dipesh +~~END~~ + +DROP TABLE tmp; + +#10 UPDATE TABLE with fancy condition +CREATE TABLE tmp(a int PRIMARY KEY,b int); +INSERT INTO tmp(a,b) VALUES(1,1); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(2,2); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(3,3); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(4,4); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(5,5); +~~ROW COUNT: 1~~ + +SELECT * FROM tmp; +~~START~~ +int#!#int +1#!#1 +2#!#2 +3#!#3 +4#!#4 +5#!#5 +~~END~~ + +UPDATE tmp SET b=b+1 WHERE b>2; +~~ROW COUNT: 3~~ + +SELECT * FROM tmp; +~~START~~ +int#!#int +1#!#1 +2#!#2 +3#!#4 +4#!#5 +5#!#6 +~~END~~ + +DROP TABLE tmp; + +#11 DROP some column using ALTER TABLE +CREATE TABLE tmp(a int PRIMARY KEY,b int); +INSERT INTO tmp(a,b) VALUES(1,1); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(2,2); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(3,3); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(4,4); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(5,5); +~~ROW COUNT: 1~~ + +SELECT * FROM tmp; +~~START~~ +int#!#int +1#!#1 +2#!#2 +3#!#3 +4#!#4 +5#!#5 +~~END~~ + +#ALTER TABLE tmp DROP COLUMN b; +#INSERT INTO tmp(a) values (6); +#SELECT * FROM tmp; +DROP TABLE tmp; + +#12 CREATE TABLE with fancy constraint +CREATE TABLE tmp(a int PRIMARY KEY CHECK (a>10),b int); +INSERT INTO tmp(a,b) VALUES(11,1); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(12,2); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(13,3); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(14,4); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(15,5); +~~ROW COUNT: 1~~ + +SELECT * FROM tmp; +~~START~~ +int#!#int +11#!#1 +12#!#2 +13#!#3 +14#!#4 +15#!#5 +~~END~~ + +DROP TABLE tmp; + +#CREATE PROCEDURE tmp AS +#BEGIN +# CREATE TABLE dip(a int PRIMARY KEY CHECK (a>10),b int); +# INSERT INTO dip(a,b) VALUES(11,1); +# INSERT INTO dip(a,b) VALUES(12,2); +# INSERT INTO dip(a,b) VALUES(13,3); +# INSERT INTO dip(a,b) VALUES(14,4); +# INSERT INTO dip(a,b) VALUES(15,5); +# SELECT * FROM dip; +# DROP TABLE dip; +#END; + +#13 invoke simple stored procedure using EXECUTE +EXECUTE tmp; +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]procedure tmp() does not exist (33557097) (SQLExecDirectW))~~ + + +#14 invoke simple stored procedure using EXEC +EXEC tmp; +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]procedure tmp() does not exist (33557097) (SQLExecDirectW))~~ + + +#DROP PROCEDURE tmp; + +#15 UPDATE rows in existing table +CREATE TABLE tmp(a int PRIMARY KEY,b int); +INSERT INTO tmp(a,b) VALUES(1,1),(2,2),(3,3),(4,4),(5,5); +~~ROW COUNT: 5~~ + +SELECT * FROM tmp; +~~START~~ +int#!#int +1#!#1 +2#!#2 +3#!#3 +4#!#4 +5#!#5 +~~END~~ + +UPDATE tmp SET b=b*2+1 WHERE (a>2); +~~ROW COUNT: 3~~ + +SELECT * FROM tmp; +~~START~~ +int#!#int +1#!#1 +2#!#2 +3#!#7 +4#!#9 +5#!#11 +~~END~~ + +DROP TABLE tmp; + +#16 TRUNCATE table +CREATE TABLE tmp(a int PRIMARY KEY,b int); +INSERT INTO tmp(a,b) VALUES(1,1),(2,2),(3,3),(4,4),(5,5); +~~ROW COUNT: 5~~ + +SELECT * FROM tmp; +~~START~~ +int#!#int +1#!#1 +2#!#2 +3#!#3 +4#!#4 +5#!#5 +~~END~~ + +TRUNCATE TABLE tmp; +SELECT * FROM tmp; +~~START~~ +int#!#int +~~END~~ + +DROP TABLE tmp; + +CREATE TABLE temp1 (i INT,j INT,t TEXT); + +CREATE TABLE temp2 ( i INT,k INT); + +INSERT INTO temp1 VALUES (1, 4, 'one'); +~~ROW COUNT: 1~~ + +INSERT INTO temp1 VALUES (2, 3, 'two'); +~~ROW COUNT: 1~~ + +INSERT INTO temp1 VALUES (3, 2, 'three'); +~~ROW COUNT: 1~~ + +INSERT INTO temp1 VALUES (4, 1, 'four'); +~~ROW COUNT: 1~~ + +INSERT INTO temp1 VALUES (5, 0, 'five'); +~~ROW COUNT: 1~~ + +INSERT INTO temp1 VALUES (6, 6, 'six'); +~~ROW COUNT: 1~~ + +INSERT INTO temp1 VALUES (7, 7, 'seven'); +~~ROW COUNT: 1~~ + +INSERT INTO temp1 VALUES (8, 8, 'eight'); +~~ROW COUNT: 1~~ + +INSERT INTO temp1 VALUES (0, NULL, 'zero'); +~~ROW COUNT: 1~~ + +INSERT INTO temp1 VALUES (NULL, NULL, NULL); +~~ROW COUNT: 1~~ + +INSERT INTO temp1 VALUES (NULL, 0, 'zero'); +~~ROW COUNT: 1~~ + + +INSERT INTO temp2 VALUES (1, -1); +~~ROW COUNT: 1~~ + +INSERT INTO temp2 VALUES (2, 2); +~~ROW COUNT: 1~~ + +INSERT INTO temp2 VALUES (3, -3); +~~ROW COUNT: 1~~ + +INSERT INTO temp2 VALUES (2, 4); +~~ROW COUNT: 1~~ + +INSERT INTO temp2 VALUES (5, -5); +~~ROW COUNT: 1~~ + +INSERT INTO temp2 VALUES (5, -5); +~~ROW COUNT: 1~~ + +INSERT INTO temp2 VALUES (0, NULL); +~~ROW COUNT: 1~~ + +INSERT INTO temp2 VALUES (NULL, NULL); +~~ROW COUNT: 1~~ + +INSERT INTO temp2 VALUES (NULL, 0); +~~ROW COUNT: 1~~ + + +#17 CROSS JOIN +SELECT * FROM temp1 CROSS JOIN temp2; +~~START~~ +int#!#int#!#str#!#int#!#int +1#!#4#!#one#!#1#!#-1 +2#!#3#!#two#!#1#!#-1 +3#!#2#!#three#!#1#!#-1 +4#!#1#!#four#!#1#!#-1 +5#!#0#!#five#!#1#!#-1 +6#!#6#!#six#!#1#!#-1 +7#!#7#!#seven#!#1#!#-1 +8#!#8#!#eight#!#1#!#-1 +0#!##!#zero#!#1#!#-1 +#!##!##!#1#!#-1 +#!#0#!#zero#!#1#!#-1 +1#!#4#!#one#!#2#!#2 +2#!#3#!#two#!#2#!#2 +3#!#2#!#three#!#2#!#2 +4#!#1#!#four#!#2#!#2 +5#!#0#!#five#!#2#!#2 +6#!#6#!#six#!#2#!#2 +7#!#7#!#seven#!#2#!#2 +8#!#8#!#eight#!#2#!#2 +0#!##!#zero#!#2#!#2 +#!##!##!#2#!#2 +#!#0#!#zero#!#2#!#2 +1#!#4#!#one#!#3#!#-3 +2#!#3#!#two#!#3#!#-3 +3#!#2#!#three#!#3#!#-3 +4#!#1#!#four#!#3#!#-3 +5#!#0#!#five#!#3#!#-3 +6#!#6#!#six#!#3#!#-3 +7#!#7#!#seven#!#3#!#-3 +8#!#8#!#eight#!#3#!#-3 +0#!##!#zero#!#3#!#-3 +#!##!##!#3#!#-3 +#!#0#!#zero#!#3#!#-3 +1#!#4#!#one#!#2#!#4 +2#!#3#!#two#!#2#!#4 +3#!#2#!#three#!#2#!#4 +4#!#1#!#four#!#2#!#4 +5#!#0#!#five#!#2#!#4 +6#!#6#!#six#!#2#!#4 +7#!#7#!#seven#!#2#!#4 +8#!#8#!#eight#!#2#!#4 +0#!##!#zero#!#2#!#4 +#!##!##!#2#!#4 +#!#0#!#zero#!#2#!#4 +1#!#4#!#one#!#5#!#-5 +2#!#3#!#two#!#5#!#-5 +3#!#2#!#three#!#5#!#-5 +4#!#1#!#four#!#5#!#-5 +5#!#0#!#five#!#5#!#-5 +6#!#6#!#six#!#5#!#-5 +7#!#7#!#seven#!#5#!#-5 +8#!#8#!#eight#!#5#!#-5 +0#!##!#zero#!#5#!#-5 +#!##!##!#5#!#-5 +#!#0#!#zero#!#5#!#-5 +1#!#4#!#one#!#5#!#-5 +2#!#3#!#two#!#5#!#-5 +3#!#2#!#three#!#5#!#-5 +4#!#1#!#four#!#5#!#-5 +5#!#0#!#five#!#5#!#-5 +6#!#6#!#six#!#5#!#-5 +7#!#7#!#seven#!#5#!#-5 +8#!#8#!#eight#!#5#!#-5 +0#!##!#zero#!#5#!#-5 +#!##!##!#5#!#-5 +#!#0#!#zero#!#5#!#-5 +1#!#4#!#one#!#0#!# +2#!#3#!#two#!#0#!# +3#!#2#!#three#!#0#!# +4#!#1#!#four#!#0#!# +5#!#0#!#five#!#0#!# +6#!#6#!#six#!#0#!# +7#!#7#!#seven#!#0#!# +8#!#8#!#eight#!#0#!# +0#!##!#zero#!#0#!# +#!##!##!#0#!# +#!#0#!#zero#!#0#!# +1#!#4#!#one#!##!# +2#!#3#!#two#!##!# +3#!#2#!#three#!##!# +4#!#1#!#four#!##!# +5#!#0#!#five#!##!# +6#!#6#!#six#!##!# +7#!#7#!#seven#!##!# +8#!#8#!#eight#!##!# +0#!##!#zero#!##!# +#!##!##!##!# +#!#0#!#zero#!##!# +1#!#4#!#one#!##!#0 +2#!#3#!#two#!##!#0 +3#!#2#!#three#!##!#0 +4#!#1#!#four#!##!#0 +5#!#0#!#five#!##!#0 +6#!#6#!#six#!##!#0 +7#!#7#!#seven#!##!#0 +8#!#8#!#eight#!##!#0 +0#!##!#zero#!##!#0 +#!##!##!##!#0 +#!#0#!#zero#!##!#0 +~~END~~ + + +#18 INNER JOIN +SELECT temp1.i, temp1.j, temp1.t, temp2.k FROM temp1 INNER JOIN temp2 ON temp1.i=temp2.i; +~~START~~ +int#!#int#!#str#!#int +0#!##!#zero#!# +1#!#4#!#one#!#-1 +2#!#3#!#two#!#2 +2#!#3#!#two#!#4 +3#!#2#!#three#!#-3 +5#!#0#!#five#!#-5 +5#!#0#!#five#!#-5 +~~END~~ + +SELECT temp1.i, temp1.j, temp1.t, temp2.k FROM temp1 JOIN temp2 ON temp1.i=temp2.i; +~~START~~ +int#!#int#!#str#!#int +0#!##!#zero#!# +1#!#4#!#one#!#-1 +2#!#3#!#two#!#2 +2#!#3#!#two#!#4 +3#!#2#!#three#!#-3 +5#!#0#!#five#!#-5 +5#!#0#!#five#!#-5 +~~END~~ + + +#19 LEFT JOIN +SELECT * FROM temp1 LEFT OUTER JOIN temp2 ON temp1.i=temp2.k; +~~START~~ +int#!#int#!#str#!#int#!#int +0#!##!#zero#!##!#0 +1#!#4#!#one#!##!# +2#!#3#!#two#!#2#!#2 +3#!#2#!#three#!##!# +4#!#1#!#four#!#2#!#4 +5#!#0#!#five#!##!# +6#!#6#!#six#!##!# +7#!#7#!#seven#!##!# +8#!#8#!#eight#!##!# +#!##!##!##!# +#!#0#!#zero#!##!# +~~END~~ + + +#20 RIGHT JOIN +SELECT * FROM temp1 RIGHT OUTER JOIN temp2 ON temp1.i=temp2.i; +~~START~~ +int#!#int#!#str#!#int#!#int +0#!##!#zero#!#0#!# +1#!#4#!#one#!#1#!#-1 +2#!#3#!#two#!#2#!#2 +2#!#3#!#two#!#2#!#4 +3#!#2#!#three#!#3#!#-3 +5#!#0#!#five#!#5#!#-5 +5#!#0#!#five#!#5#!#-5 +#!##!##!##!# +#!##!##!##!#0 +~~END~~ + + +#21 FULL OUTER JOIN +SELECT * FROM temp1,temp2; +~~START~~ +int#!#int#!#str#!#int#!#int +1#!#4#!#one#!#1#!#-1 +2#!#3#!#two#!#1#!#-1 +3#!#2#!#three#!#1#!#-1 +4#!#1#!#four#!#1#!#-1 +5#!#0#!#five#!#1#!#-1 +6#!#6#!#six#!#1#!#-1 +7#!#7#!#seven#!#1#!#-1 +8#!#8#!#eight#!#1#!#-1 +0#!##!#zero#!#1#!#-1 +#!##!##!#1#!#-1 +#!#0#!#zero#!#1#!#-1 +1#!#4#!#one#!#2#!#2 +2#!#3#!#two#!#2#!#2 +3#!#2#!#three#!#2#!#2 +4#!#1#!#four#!#2#!#2 +5#!#0#!#five#!#2#!#2 +6#!#6#!#six#!#2#!#2 +7#!#7#!#seven#!#2#!#2 +8#!#8#!#eight#!#2#!#2 +0#!##!#zero#!#2#!#2 +#!##!##!#2#!#2 +#!#0#!#zero#!#2#!#2 +1#!#4#!#one#!#3#!#-3 +2#!#3#!#two#!#3#!#-3 +3#!#2#!#three#!#3#!#-3 +4#!#1#!#four#!#3#!#-3 +5#!#0#!#five#!#3#!#-3 +6#!#6#!#six#!#3#!#-3 +7#!#7#!#seven#!#3#!#-3 +8#!#8#!#eight#!#3#!#-3 +0#!##!#zero#!#3#!#-3 +#!##!##!#3#!#-3 +#!#0#!#zero#!#3#!#-3 +1#!#4#!#one#!#2#!#4 +2#!#3#!#two#!#2#!#4 +3#!#2#!#three#!#2#!#4 +4#!#1#!#four#!#2#!#4 +5#!#0#!#five#!#2#!#4 +6#!#6#!#six#!#2#!#4 +7#!#7#!#seven#!#2#!#4 +8#!#8#!#eight#!#2#!#4 +0#!##!#zero#!#2#!#4 +#!##!##!#2#!#4 +#!#0#!#zero#!#2#!#4 +1#!#4#!#one#!#5#!#-5 +2#!#3#!#two#!#5#!#-5 +3#!#2#!#three#!#5#!#-5 +4#!#1#!#four#!#5#!#-5 +5#!#0#!#five#!#5#!#-5 +6#!#6#!#six#!#5#!#-5 +7#!#7#!#seven#!#5#!#-5 +8#!#8#!#eight#!#5#!#-5 +0#!##!#zero#!#5#!#-5 +#!##!##!#5#!#-5 +#!#0#!#zero#!#5#!#-5 +1#!#4#!#one#!#5#!#-5 +2#!#3#!#two#!#5#!#-5 +3#!#2#!#three#!#5#!#-5 +4#!#1#!#four#!#5#!#-5 +5#!#0#!#five#!#5#!#-5 +6#!#6#!#six#!#5#!#-5 +7#!#7#!#seven#!#5#!#-5 +8#!#8#!#eight#!#5#!#-5 +0#!##!#zero#!#5#!#-5 +#!##!##!#5#!#-5 +#!#0#!#zero#!#5#!#-5 +1#!#4#!#one#!#0#!# +2#!#3#!#two#!#0#!# +3#!#2#!#three#!#0#!# +4#!#1#!#four#!#0#!# +5#!#0#!#five#!#0#!# +6#!#6#!#six#!#0#!# +7#!#7#!#seven#!#0#!# +8#!#8#!#eight#!#0#!# +0#!##!#zero#!#0#!# +#!##!##!#0#!# +#!#0#!#zero#!#0#!# +1#!#4#!#one#!##!# +2#!#3#!#two#!##!# +3#!#2#!#three#!##!# +4#!#1#!#four#!##!# +5#!#0#!#five#!##!# +6#!#6#!#six#!##!# +7#!#7#!#seven#!##!# +8#!#8#!#eight#!##!# +0#!##!#zero#!##!# +#!##!##!##!# +#!#0#!#zero#!##!# +1#!#4#!#one#!##!#0 +2#!#3#!#two#!##!#0 +3#!#2#!#three#!##!#0 +4#!#1#!#four#!##!#0 +5#!#0#!#five#!##!#0 +6#!#6#!#six#!##!#0 +7#!#7#!#seven#!##!#0 +8#!#8#!#eight#!##!#0 +0#!##!#zero#!##!#0 +#!##!##!##!#0 +#!#0#!#zero#!##!#0 +~~END~~ + + +DROP TABLE temp1; +DROP TABLE temp2; + +#22 dropping all columns +CREATE TABLE tmp(a int PRIMARY KEY,b int); +INSERT INTO tmp(a,b) VALUES(1,1); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(2,2); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(3,3); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(4,4); +~~ROW COUNT: 1~~ + +INSERT INTO tmp(a,b) VALUES(5,5); +~~ROW COUNT: 1~~ + +SELECT * FROM tmp; +~~START~~ +int#!#int +1#!#1 +2#!#2 +3#!#3 +4#!#4 +5#!#5 +~~END~~ + +#ALTER TABLE tmp DROP COLUMN b; +#ALTER TABLE tmp DROP COLUMN a; +#SELECT * FROM tmp; +DROP TABLE tmp; + +#23 +CREATE TABLE DATE_dt (a DATE); +INSERT INTO DATE_dt(a) values('2000-12-13'); +~~ROW COUNT: 1~~ + +INSERT INTO DATE_dt(a) values('1900-02-28'); +~~ROW COUNT: 1~~ + +INSERT INTO DATE_dt(a) values('0001-01-01'); +~~ROW COUNT: 1~~ + +INSERT INTO DATE_dt(a) values('9999-12-31'); +~~ROW COUNT: 1~~ + +INSERT INTO DATE_dt(a) values(NULL); +~~ROW COUNT: 1~~ + +SELECT * FROM DATE_dt; +~~START~~ +date +2000-12-13 +1900-02-28 +0001-01-01 +9999-12-31 + +~~END~~ + +ALTER TABLE DATE_dt ALTER COLUMN a DATETIME; +~~ERROR (Code: 517)~~ +~~ERROR (Message: [22007] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]data out of range for datetime (517) (SQLExecDirectW))~~ + +SELECT * FROM DATE_dt; +~~START~~ +date +2000-12-13 +1900-02-28 +0001-01-01 +9999-12-31 + +~~END~~ + +DROP TABLE DATE_dt; diff --git a/contrib/test/python/expected/pyodbc/TestSimpleErrorsWithImplicitTran.out b/contrib/test/python/expected/pyodbc/TestSimpleErrorsWithImplicitTran.out new file mode 100644 index 00000000000..24cffbdd7b7 --- /dev/null +++ b/contrib/test/python/expected/pyodbc/TestSimpleErrorsWithImplicitTran.out @@ -0,0 +1,20 @@ +#Setup +CREATE TABLE simpleErrorTable (a varchar(15) UNIQUE, b nvarchar(25), c int PRIMARY KEY, d char(15) DEFAULT 'Whoops!', e nchar(25), f datetime, g numeric(4,1) CHECK (g >= 103.5)) +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Nullable UNIQUE constraint is not supported. Please use babelfishpg_tsql.escape_hatch_unique_constraint to ignore or add a NOT NULL constraint (33557097) (SQLExecDirectW))~~ + +SET IMPLICIT_TRANSACTIONS ON + +#Run error handling tests +include#!#input/errorHandling/TestSimpleErrors.sql +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]syntax error near '!' at line 1 and character position 8 (33557097) (SQLExecDirectW))~~ + + +#Cleanup +IF @@trancount > 0 ROLLBACK +SET IMPLICIT_TRANSACTIONS OFF +DROP TABLE simpleerrortable +~~ERROR (Code: 3701)~~ +~~ERROR (Message: [42S02] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]table "simpleerrortable" does not exist (3701) (SQLExecDirectW))~~ + diff --git a/contrib/test/python/expected/pyodbc/TestSmallDatetime.out b/contrib/test/python/expected/pyodbc/TestSmallDatetime.out new file mode 100644 index 00000000000..eae3209bac3 --- /dev/null +++ b/contrib/test/python/expected/pyodbc/TestSmallDatetime.out @@ -0,0 +1,148 @@ +CREATE TABLE SMALLDATETIME_dt (a SMALLDATETIME) +prepst#!# INSERT INTO SMALLDATETIME_dt(a) values(?) #!#SMALLDATETIME|-|a|-|2000-12-13 12:58:23 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLDATETIME|-|a|-|2007-05-08 12:35:29 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLDATETIME|-|a|-|2007-05-08 12:35:30 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLDATETIME|-|a|-|2007-05-08 12:59:59.998 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLDATETIME|-|a|-|2000-02-28 23:59:59.999 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLDATETIME|-|a|-|1900-02-28 23:59:59.999 +~~ROW COUNT: 1~~ + +#prepst#!#exec#!#SMALLDATETIME|-|a|-|2000-02-28 23:45:29.999 +prepst#!#exec#!#SMALLDATETIME|-|a|-|2000-02-28 23:45:30 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLDATETIME|-|a|-|2000-02-28 23:45:29 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLDATETIME|-|a|-|1900-02-28 23:45:30 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLDATETIME|-|a|-|1900-02-28 23:45:29 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLDATETIME|-|a|-|2000-12-13 12:58:30 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLDATETIME|-|a|-|2000-02-28 23:45:29.998 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLDATETIME|-|a|-|1900-01-01 00:00:00 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLDATETIME|-|a|-|2079-06-06 23:59:29 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLDATETIME|-|a|-| +~~ROW COUNT: 1~~ + +SELECT * FROM SMALLDATETIME_dt; +~~START~~ +datetime +2000-12-13 12:58:00 +2007-05-08 12:35:00 +2007-05-08 12:36:00 +2007-05-08 13:00:00 +2000-02-29 00:00:00 +1900-03-01 00:00:00 +2000-02-28 23:46:00 +2000-02-28 23:45:00 +1900-02-28 23:46:00 +1900-02-28 23:45:00 +2000-12-13 12:59:00 +2000-02-28 23:45:00 +1900-01-01 00:00:00 +2079-06-06 23:59:00 + +~~END~~ + +INSERT INTO SMALLDATETIME_dt(a) values('2000-12-13 12:58:23'); +~~ROW COUNT: 1~~ + +INSERT INTO SMALLDATETIME_dt(a) values('2007-05-08 12:35:29'); +~~ROW COUNT: 1~~ + +INSERT INTO SMALLDATETIME_dt(a) values('2007-05-08 12:35:30'); +~~ROW COUNT: 1~~ + +INSERT INTO SMALLDATETIME_dt(a) values('2007-05-08 12:59:59.998'); +~~ROW COUNT: 1~~ + +INSERT INTO SMALLDATETIME_dt(a) values('2000-02-28 23:59:59.999'); +~~ROW COUNT: 1~~ + +INSERT INTO SMALLDATETIME_dt(a) values('1900-02-28 23:59:59.999'); +~~ROW COUNT: 1~~ + +INSERT INTO SMALLDATETIME_dt(a) values('2000-02-28 23:45:29.999'); +~~ROW COUNT: 1~~ + +INSERT INTO SMALLDATETIME_dt(a) values('2000-02-28 23:45:30'); +~~ROW COUNT: 1~~ + +INSERT INTO SMALLDATETIME_dt(a) values('2000-02-28 23:45:29'); +~~ROW COUNT: 1~~ + +INSERT INTO SMALLDATETIME_dt(a) values('1900-02-28 23:45:29'); +~~ROW COUNT: 1~~ + +INSERT INTO SMALLDATETIME_dt(a) values('1900-12-13 12:58:30'); +~~ROW COUNT: 1~~ + +INSERT INTO SMALLDATETIME_dt(a) values('2000-02-28 23:45:29.998'); +~~ROW COUNT: 1~~ + +INSERT INTO SMALLDATETIME_dt(a) values('1900-01-01 00:00:00'); +~~ROW COUNT: 1~~ + +INSERT INTO SMALLDATETIME_dt(a) values('2079-06-06 23:59:29'); +~~ROW COUNT: 1~~ + +INSERT INTO SMALLDATETIME_dt(a) values(NULL); +~~ROW COUNT: 1~~ + +SELECT * FROM SMALLDATETIME_dt; +~~START~~ +datetime +2000-12-13 12:58:00 +2007-05-08 12:35:00 +2007-05-08 12:36:00 +2007-05-08 13:00:00 +2000-02-29 00:00:00 +1900-03-01 00:00:00 +2000-02-28 23:46:00 +2000-02-28 23:45:00 +1900-02-28 23:46:00 +1900-02-28 23:45:00 +2000-12-13 12:59:00 +2000-02-28 23:45:00 +1900-01-01 00:00:00 +2079-06-06 23:59:00 + +2000-12-13 12:58:00 +2007-05-08 12:35:00 +2007-05-08 12:36:00 +2007-05-08 13:00:00 +2000-02-29 00:00:00 +1900-03-01 00:00:00 +2000-02-28 23:46:00 +2000-02-28 23:46:00 +2000-02-28 23:45:00 +1900-02-28 23:45:00 +1900-12-13 12:59:00 +2000-02-28 23:45:00 +1900-01-01 00:00:00 +2079-06-06 23:59:00 + +~~END~~ + +DROP TABLE SMALLDATETIME_dt; diff --git a/contrib/test/python/expected/pyodbc/TestSmallInt.out b/contrib/test/python/expected/pyodbc/TestSmallInt.out new file mode 100644 index 00000000000..9a3e0fb3507 --- /dev/null +++ b/contrib/test/python/expected/pyodbc/TestSmallInt.out @@ -0,0 +1,102 @@ +CREATE TABLE SMALLINT_dt (a SMALLINT) +prepst#!# INSERT INTO SMALLINT_dt(a) values(?) #!#SMALLINT|-|a|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLINT|-|a|-|-10 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLINT|-|a|-|100 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLINT|-|a|-|002 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLINT|-|a|-|-029 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLINT|-|a|-|-1234 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLINT|-|a|-|876 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLINT|-|a|-|-32768 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLINT|-|a|-|32767 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#SMALLINT|-|a|-| +~~ROW COUNT: 1~~ + +SELECT * FROM SMALLINT_dt; +~~START~~ +int +0 +-10 +100 +2 +-29 +-1234 +876 +-32768 +32767 + +~~END~~ + +INSERT INTO SMALLINT_dt(a) values(0) +~~ROW COUNT: 1~~ + +INSERT INTO SMALLINT_dt(a) values(-10) +~~ROW COUNT: 1~~ + +INSERT INTO SMALLINT_dt(a) values(100) +~~ROW COUNT: 1~~ + +INSERT INTO SMALLINT_dt(a) values(002) +~~ROW COUNT: 1~~ + +INSERT INTO SMALLINT_dt(a) values(-029) +~~ROW COUNT: 1~~ + +INSERT INTO SMALLINT_dt(a) values(-1234) +~~ROW COUNT: 1~~ + +INSERT INTO SMALLINT_dt(a) values(876) +~~ROW COUNT: 1~~ + +INSERT INTO SMALLINT_dt(a) values(-32768) +~~ROW COUNT: 1~~ + +INSERT INTO SMALLINT_dt(a) values(32767) +~~ROW COUNT: 1~~ + +INSERT INTO SMALLINT_dt(a) values(NULL) +~~ROW COUNT: 1~~ + +SELECT * FROM SMALLINT_dt; +~~START~~ +int +0 +-10 +100 +2 +-29 +-1234 +876 +-32768 +32767 + +0 +-10 +100 +2 +-29 +-1234 +876 +-32768 +32767 + +~~END~~ + +DROP TABLE SMALLINT_dt; diff --git a/contrib/test/python/expected/pyodbc/TestStoredProcedures.out b/contrib/test/python/expected/pyodbc/TestStoredProcedures.out new file mode 100644 index 00000000000..fb247b2612a --- /dev/null +++ b/contrib/test/python/expected/pyodbc/TestStoredProcedures.out @@ -0,0 +1,181 @@ +# PROCEDURE WITH NO BODY, works with babel but not with sql +#create procedure sp_test AS BEGIN END; +# PROCEDURE WITH NO PARAMS +create table temp_sp2(a int); +CREATE PROCEDURE sp_test AS BEGIN insert into temp_sp2 values(1); END; +storedproc#!#prep#!#sp_test#!# +~~ROW COUNT: 1~~ + +SELECT * FROM temp_sp2; +~~START~~ +int +1 +~~END~~ + +drop table temp_sp2; +drop Procedure sp_test; +# PROCEDURE WITH INPUT PARAMETER +#drop table temp_sp; +create table temp_sp(a int); +Create Procedure stored_proc1 (@a int) As Begin insert into temp_sp values(@a) End; +# NOT WORKING FOR BABEL,RAISED JIRA 444 +storedproc#!#prep#!#stored_proc1#!#int|-|a|-|-100|-|input +~~ROW COUNT: 1~~ + +# MISMATCH IN RETURN VALUES +exec stored_proc1 -200 +~~ROW COUNT: 1~~ + +exec stored_proc1 0 +~~ROW COUNT: 1~~ + +exec stored_proc1 -1 +~~ROW COUNT: 1~~ + +exec stored_proc1 2 +~~ROW COUNT: 1~~ + +# filed Jira on this, doesnt work for babel +#exec stored_proc1 2.2 +SELECT * FROM temp_sp; +~~START~~ +int +-100 +-200 +0 +-1 +2 +~~END~~ + +DROP table temp_sp; +DROP Procedure stored_proc1 +# input parameter +CREATE PROCEDURE sp_test1 (@a INT) AS BEGIN SET @a=100; Select @a as a; END; +exec sp_test1 2 +~~START~~ +int +100 +~~END~~ + +Declare @a int;Set @a=1; exec sp_test1 @a;select @a as a; +~~START~~ +int +100 +~~END~~ + +~~START~~ +int +1 +~~END~~ + +storedproc#!#prep#!#sp_test1#!#int|-|a|-|1|-|input +~~START~~ +int +100 +~~END~~ + +storedproc#!#prep#!#sp_test1#!#int|-|a|-|10|-|input +~~START~~ +int +100 +~~END~~ + +DROP PROCEDURE sp_test1 +# TESTING OUT PARAMETERS FOR ALL THE DATATYPES +# int +CREATE PROCEDURE sp_test1 (@a INT OUTPUT) AS BEGIN SET @a=100; Select @a as a; END; +#Declare @a int;Set @a=1; exec sp_test1 @a;select @a as a; +DROP PROCEDURE sp_test1 +# smallint +CREATE PROCEDURE sp_test2 (@a SMALLINT OUTPUT) AS BEGIN SET @a=100; Select @a as a; END; +#Declare @a smallint;Set @a=1; exec sp_test2 @a;select @a as a; +DROP PROCEDURE sp_test2 +# bigint +CREATE PROCEDURE sp_test3 (@a BIGINT OUTPUT) AS BEGIN SET @a=100; Select @a as a; END; +DROP PROCEDURE sp_test3 +# tinyint +#CREATE PROCEDURE sp_test4 (@a tinyint OUTPUT) AS BEGIN SET @a=100; Select @a as a; END; +#storedproc#!#prep#!#sp_test4#!#tinyint|-|a|-|10|-|output +#storedproc#!#prep#!#sp_test4#!#tinyint|-|a|-|10|-|inputoutput +#DROP PROCEDURE sp_test4 +# float +CREATE PROCEDURE sp_test5 (@a float OUTPUT) AS BEGIN SET @a=100.12; Select @a as a; END; +#Declare @a float;Set @a=1.1; exec sp_test5 @a;select @a as a; +DROP PROCEDURE sp_test5 +# varchar +#CREATE PROCEDURE sp_test6 (@a varchar OUTPUT) AS BEGIN SET @a='helloworld'; Select @a as a; END; +#storedproc#!#prep#!#sp_test6#!#varchar|-|a|-|hello|-|output +#storedproc#!#prep#!#sp_test6#!#varchar|-|a|-|hello|-|inputoutput +#DROP PROCEDURE sp_test6 +# char BABEL-705 +#CREATE PROCEDURE sp_test7 (@a char OUTPUT) AS BEGIN SET @a='b'; Select @a as a; END; +#Declare @a varchar;Set @a='h'; exec sp_test7 @a;select @a as a; +#storedproc#!#prep#!#sp_test7#!#char|-|a|-|t|-|output +#storedproc#!#prep#!#sp_test7#!#char|-|a|-|t|-|inputoutput +#DROP PROCEDURE sp_test7 +# nvarchar +#CREATE PROCEDURE sp_test9 (@a nvarchar OUTPUT) AS BEGIN SET @a='helloworld'; Select @a as a; END; +#Declare @a nvarchar;Set @a='hello'; exec sp_test9 @a;select @a as a; +#storedproc#!#prep#!#sp_test9#!#varchar|-|a|-|hello|-|output +#storedproc#!#prep#!#sp_test9#!#varchar|-|a|-|hello|-|inputoutput +#DROP PROCEDURE sp_test9 +# numeric +CREATE PROCEDURE sp_test10 (@a numeric(10,4) OUTPUT) AS BEGIN SET @a=100.41; Select @a as a; END; +#Declare @a numeric(10,4);Set @a=10.04; exec sp_test10 @a;select @a as a; +#storedproc#!#prep#!#sp_test10#!#numeric|-|a|-|123|-|10|-|3|-|output +#storedproc#!#prep#!#sp_test10#!#numeric|-|a|-|123|-|10|-|2|-|inputoutput +DROP PROCEDURE sp_test10 +# decimal +CREATE PROCEDURE sp_test11 (@a decimal(10,4) OUTPUT) AS BEGIN SET @a=100.41; Select @a as a; END; +#Declare @a decimal(10,4);Set @a=10.04; exec sp_test11 @a;select @a as a; +#storedproc#!#prep#!#sp_test11#!#decimal|-|a|-|123|-|10|-|3|-|output +#storedproc#!#prep#!#sp_test11#!#decimal|-|a|-|123|-|10|-|2|-|inputoutput +DROP PROCEDURE sp_test11 +# binary +#CREATE PROCEDURE sp_test12 (@a binary OUTPUT) AS BEGIN SET @a=0x121; Select @a as a; END; +#exec sp_test12 0x122 +#Declare @a binary;Set @a=0x121; exec sp_test12 @a;select @a as a; +#storedproc#!#prep#!#sp_test12#!#binary|-|a|-|0x122|-|output +#storedproc#!#prep#!#sp_test12#!#binary|-|a|-|0x122|-|inputoutput +#DROP PROCEDURE sp_test12 +# varbinary BABEL-701 +#CREATE PROCEDURE sp_test13 (@a varbinary OUTPUT) AS BEGIN SET @a=0x121; Select @a as a; END; +#exec sp_test13 0x122 +#Declare @a varbinary;Set @a=0x122; exec sp_test13 @a;select @a as a; +#storedproc#!#prep#!#sp_test13#!#varbinary|-|a|-|0x122|-|output +#storedproc#!#prep#!#sp_test13#!#varbinary|-|a|-|0x122|-|inputoutput +#DROP PROCEDURE sp_test13 +# date +CREATE PROCEDURE sp_test14 (@a date output) AS BEGIN SET @a='1999-1-3'; Select @a as a; END; +#Declare @a DATE;Set @a='9999-12-31'; exec sp_test14 @a;select @a as a; +DROP PROCEDURE sp_test14 +# time +#CREATE PROCEDURE sp_test15 (@a time(4) OUTPUT) AS BEGIN SET @a='11:25:07.123'; Select @a as a; END; +#Declare @a Time;Set @a='12:45:37.123'; exec sp_test15 @a;select @a as a; +#storedproc#!#prep#!#sp_test15#!#Time|-|a|-|12:45:37.123|-|3|-|output +#storedproc#!#prep#!#sp_test15#!#Time|-|a|-|12:45:37.123|-|3|-|inputoutput +#DROP PROCEDURE sp_test15 +# dateime BABEL-694 +#CREATE PROCEDURE sp_test16 (@a datetime output) AS BEGIN SET @a='2004-05-18 13:59:59.995'; Select @a as a; END; +#Declare @a DATETIME;Set @a='2000-02-28 23:59:59.995'; exec sp_test16 @a;select @a as a; +#storedproc#!#prep#!#sp_test16#!#DATETIME|-|a|-|2000-02-28 23:59:59.995|-|output +#storedproc#!#prep#!#sp_test16#!#DATETIME|-|a|-|2000-02-28 23:59:59.995|-|inputoutput +#DROP PROCEDURE sp_test16 +# datetime2 +#CREATE PROCEDURE sp_test17 (@a datetime2(5) OUTPUT) AS BEGIN SET @a='2014-10-2 1:45:37.123456'; Select @a as a; END; +#Declare @a Datetime2;Set @a='2016-10-23 12:45:37.123456'; exec sp_test17 @a;select @a as a; +#storedproc#!#prep#!#sp_test17#!#Datetime2|-|a|-|2016-10-23 12:45:37.123456|-|5|-|output +#storedproc#!#prep#!#sp_test17#!#Datetime2|-|a|-|2016-10-23 12:45:37.123456|-|5|-|inputoutput +#DROP PROCEDURE sp_test17 +# smalldatetime BABEL-694 +#CREATE PROCEDURE sp_test18 (@a smalldatetime output) AS BEGIN SET @a='2010-02-03 12:58:23'; Select @a as a; END; +#Declare @a SMALLDATETIME;Set @a='2000-12-13 12:58:23'; exec sp_test18 @a;select @a as a; +#storedproc#!#prep#!#sp_test18#!#SMALLDATETIME|-|a|-|2000-12-13 12:58:23|-|output +#storedproc#!#prep#!#sp_test18#!#SMALLDATETIME|-|a|-|2000-12-13 12:58:23|-|inputoutput +#DROP PROCEDURE sp_test18 +# UID +#CREATE PROCEDURE sp_test19 (@a uniqueidentifier OUTPUT) AS BEGIN SET @a='ce8af10a-2709-43b0-9e4e-a02753929d17'; Select @a as a; END; +#Declare @a uniqueidentifier;Set @a='5b7c2e8d-6d90-411d-8e19-9a81067e6f6c'; exec sp_test19 @a;select @a as a; +#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 diff --git a/contrib/test/python/expected/pyodbc/TestText.out b/contrib/test/python/expected/pyodbc/TestText.out new file mode 100644 index 00000000000..0cd4790e6fc --- /dev/null +++ b/contrib/test/python/expected/pyodbc/TestText.out @@ -0,0 +1,32 @@ +CREATE TABLE TEXT_dt (a text, b ntext) +#path to file should be with respect to root of test suite +prepst#!# INSERT INTO TEXT_dt(a, b) values(?, ?) #!#TEXT|-|a|-|utils/sample.txt#!#NTEXT|-|b|-|utils/sample.txt +~~ROW COUNT: 1~~ + +prepst#!#exec#!#TEXT|-|a|-|utils/blank.txt#!#NTEXT|-|b|-|utils/blank.txt +~~ROW COUNT: 1~~ + +prepst#!#exec#!#TEXT|-|a|-|#!#NTEXT|-|b|-| +~~ROW COUNT: 1~~ + +prepst#!#exec#!#TEXT|-|a|-|#!#NTEXT|-|b|-|utils/utf16.txt +~~ROW COUNT: 1~~ + +prepst#!#exec#!#TEXT|-|a|-|#!#NTEXT|-|b|-|utils/emojisText.txt +~~ROW COUNT: 1~~ + +prepst#!#exec#!#TEXT|-|a|-|#!#NTEXT|-|b|-|utils/devanagari.txt +~~ROW COUNT: 1~~ + +SELECT * FROM TEXT_dt; +~~START~~ +str#!#str +AAAAAAAAAAAAAAAAAAAABBBBBBBBBBCCCCCbadksjvbajsdcbvjadssejvhsdbfjhcgvasdhgcvsj21639812365091264#!#AAAAAAAAAAAAAAAAAAAABBBBBBBBBBCCCCCbadksjvbajsdcbvjadssejvhsdbfjhcgvasdhgcvsj21639812365091264 +#!# +#!# +#!# !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƻƼƽƾƿǀǁǂǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴǵǶǷǸǹǺǻǼǽǾǿȀȁȂȃȄȅȆȇȈȉȊȋȌȍȎȏȐȑȒȓȔȕȖȗȘșȚțȜȝȞȟȠȡȢȣȤȥȦȧȨȩȪȫȬȭȮȯȰȱȲȳȴȵȶȷȸȹȺȻȼȽȾȿɀɁɂɃɄɅɆɇɈɉɊɋɌɍɎɏɐɑɒɓɔɕɖɗɘəɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯʰʱʲʳʴʵʶʷʸʹʺʻʼʽʾʿˀˁ˂˃˄˅ˆˇˈˉˊˋˌˍˎˏːˑ˒˓˔˕˖˗˘˙˚˛˜˝˞˟ˠˡˢˣˤ˥˦˧˨˩˪˫ˬ˭ˮ˯˰˱˲˳˴˵˶˷˸˹˺˻˼˽˾˿̴̵̶̷̸̡̢̧̨̛̖̗̘̙̜̝̞̟̠̣̤̥̦̩̪̫̬̭̮̯̰̱̲̳̹̺̻̼͇͈͉͍͎̀́̂̃̄̅̆̇̈̉̊̋̌̍̎̏̐̑̒̓̔̽̾̿̀́͂̓̈́͆͊͋͌̕̚ͅ͏͓͔͕͖͙͚͐͑͒͗͛ͣͤͥͦͧͨͩͪͫͬͭͮͯ͘͜͟͢͝͞͠͡ͰͱͲͳʹ͵Ͷͷͺͻͼͽ;΄΅Ά·ΈΉΊΌΎΏΐΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩΪΫάέήίΰαβγδεζηθικλμνξοπρςστυφχψωϊϋόύώϏϐϑϒϓϔϕϖϗϘϙϚϛϜϝϞϟϠϡϢϣϤϥϦϧϨϩϪϫϬϭϮϯϰϱϲϳϴϵ϶ϷϸϹϺϻϼϽϾϿЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяѐёђѓєѕіїјљњћќѝўџѠѡѢѣѤѥѦѧѨѩѪѫѬѭѮѯѰѱѲѳѴѵѶѷѸѹѺѻѼѽѾѿҀҁ҂҃҄҅҆҇҈҉ҊҋҌҍҎҏҐґҒғҔҕҖҗҘҙҚқҜҝҞҟҠҡҢңҤҥҦҧҨҩҪҫҬҭҮүҰұҲҳҴҵҶҷҸҹҺһҼҽҾҿӀӁӂӃӄӅӆӇӈӉӊӋӌӍӎӏӐӑӒӓӔӕӖӗӘәӚӛӜӝӞӟӠӡӢӣӤӥӦӧӨөӪӫӬӭӮӯӰӱӲӳӴӵӶӷӸӹӺӻӼӽӾӿԀԁԂԃԄԅԆԇԈԉԊԋԌԍԎԏԐԑԒԓԔԕԖԗԘԙԚԛԜԝԞԟԠԡԢԣԤԥԦԧԱԲԳԴԵԶԷԸԹԺԻԼԽԾԿՀՁՂՃՄՅՆՇՈՉՊՋՌՍՎՏՐՑՒՓՔՕՖՙ՚՛՜՝՞՟աբգդեզէըթժիլխծկհձղճմյնշոչպջռսվտրցւփքօֆև։֊֏ְֱֲֳִֵֶַָֹֺֻּֽ֑֖֛֢֣֤֥֦֧֪֚֭֮֒֓֔֕֗֘֙֜֝֞֟֠֡֨֩֫֬֯־ֿ׀ׁׂ׃ׅׄ׆ׇאבגדהוזחטיךכלםמןנסעףפץצקרשתװױײ׳״؀؁؂؃؄؆؇؈؉؊؋،؍؎؏ؘؙؚؐؑؒؓؔؕؖؗ؛؞؟ؠءآأؤإئابةتثجحخدذرزسشصضطظعغػؼؽؾؿـفقكلمنهوىيًٌٍَُِّْٕٖٜٟٓٔٗ٘ٙٚٛٝٞ٠١٢٣٤٥٦٧٨٩٪٫٬٭ٮٯٰٱٲٳٴٵٶٷٸٹٺٻټٽپٿڀځڂڃڄڅچڇڈډڊڋڌڍڎڏڐڑڒړڔڕږڗژڙښڛڜڝڞڟڠڡڢڣڤڥڦڧڨکڪګڬڭڮگڰڱڲڳڴڵڶڷڸڹںڻڼڽھڿۀہۂۃۄۅۆۇۈۉۊۋیۍێۏېۑےۓ۔ەۖۗۘۙۚۛۜ۝۞ۣ۟۠ۡۢۤۥۦۧۨ۩۪ۭ۫۬ۮۯ۰۱۲۳۴۵۶۷۸۹ۺۻۼ۽۾ۿ܀܁܂܃܄܅܆܇܈܉܊܋܌܍܏ܐܑܒܓܔܕܖܗܘܙܚܛܜܝܞܟܠܡܢܣܤܥܦܧܨܩܪܫܬܭܮܯܱܴܷܸܹܻܼܾ݂݄݆݈ܰܲܳܵܶܺܽܿ݀݁݃݅݇݉݊ݍݎݏݐݑݒݓݔݕݖݗݘݙݚݛݜݝݞݟݠݡݢݣݤݥݦݧݨݩݪݫݬݭݮݯݰݱݲݳݴݵݶݷݸݹݺݻݼݽݾݿހށނރބޅކއވމފދތލގޏސޑޒޓޔޕޖޗޘޙޚޛޜޝޞޟޠޡޢޣޤޥަާިީުޫެޭޮޯްޱ߀߁߂߃߄߅߆߇߈߉ߊߋߌߍߎߏߐߑߒߓߔߕߖߗߘߙߚߛߜߝߞߟߠߡߢߣߤߥߦߧߨߩߪ߲߫߬߭߮߯߰߱߳ߴߵ߶߷߸߹ߺࠀࠁࠂࠃࠄࠅࠆࠇࠈࠉࠊࠋࠌࠍࠎࠏࠐࠑࠒࠓࠔࠕࠖࠗ࠘࠙ࠚࠛࠜࠝࠞࠟࠠࠡࠢࠣࠤࠥࠦࠧࠨࠩࠪࠫࠬ࠭࠰࠱࠲࠳࠴࠵࠶࠷࠸࠹࠺࠻࠼࠽࠾ࡀࡁࡂࡃࡄࡅࡆࡇࡈࡉࡊࡋࡌࡍࡎࡏࡐࡑࡒࡓࡔࡕࡖࡗࡘ࡙࡚࡛࡞ࢠࢢࢣࢤࢥࢦࢧࢨࢩࢪࢫࢬࣰࣱࣲࣦࣩ࣭࣮࣯ࣶࣹࣺࣤࣥࣧࣨ࣪࣫࣬ࣳࣴࣵࣷࣸࣻࣼࣽࣾऀँंःऄअआइईउऊऋऌऍऎएऐऑऒओऔकखगघङचछजझञटठडढणतथदधनऩपफबभमयरऱलळऴवशषसहऺऻ़ऽािीुूृॄॅॆेैॉॊोौ्ॎॏॐ॒॑॓॔ॕॖॗक़ख़ग़ज़ड़ढ़फ़य़ॠॡॢॣ।॥०१२३४५६७८९॰ॱॲॳॴॵॶॷॹॺॻॼॽॾॿঁংঃঅআইঈউঊঋঌএঐওঔকখগঘঙচছজঝঞটঠডঢণতথদধনপফবভমযরলশষসহ়ঽািীুূৃৄেৈোৌ্ৎৗড়ঢ়য়ৠৡৢৣ০১২৩৪৫৬৭৮৯ৰৱ৲৳৴৵৶৷৸৹৺৻ਁਂਃਅਆਇਈਉਊਏਐਓਔਕਖਗਘਙਚਛਜਝਞਟਠਡਢਣਤਥਦਧਨਪਫਬਭਮਯਰਲਲ਼ਵਸ਼ਸਹ਼ਾਿੀੁੂੇੈੋੌ੍ੑਖ਼ਗ਼ਜ਼ੜਫ਼੦੧੨੩੪੫੬੭੮੯ੰੱੲੳੴੵઁંઃઅઆઇઈઉઊઋઌઍએઐઑઓઔકખગઘઙચછજઝઞટઠડઢણતથદધનપફબભમયરલળવશષસહ઼ઽાિીુૂૃૄૅેૈૉોૌ્ૐૠૡૢૣ૦૧૨૩૪૫૬૭૮૯૰૱ଁଂଃଅଆଇଈଉଊଋଌଏଐଓଔକଖଗଘଙଚଛଜଝଞଟଠଡଢଣତଥଦଧନପଫବଭମଯରଲଳଵଶଷସହ଼ଽାିୀୁୂୃୄେୈୋୌ୍ୖୗଡ଼ଢ଼ୟୠୡୢୣ୦୧୨୩୪୫୬୭୮୯୰ୱ୲୳୴୵୶୷ஂஃஅஆஇஈஉஊஎஏஐஒஓஔகஙசஜஞடணதநனபமயரறலளழவஶஷஸஹாிீுூெேைொோௌ்ௐௗ௦௧௨௩௪௫௬௭௮௯௰௱௲௳௴௵௶௷௸௹௺ఁంఃఅఆఇఈఉఊఋఌఎఏఐఒఓఔకఖగఘఙచఛజఝఞటఠడఢణతథదధనపఫబభమయరఱలళవశషసహఽాిీుూృౄెేైొోౌ్ౕౖౘౙౠౡౢౣ౦౧౨౩౪౫౬౭౮౯౸౹౺౻౼౽౾౿ಂಃಅಆಇಈಉಊಋಌಎಏಐಒಓಔಕಖಗಘಙಚಛಜಝಞಟಠಡಢಣತಥದಧನಪಫಬಭಮಯರಱಲಳವಶಷಸಹ಼ಽಾಿೀುೂೃೄೆೇೈೊೋೌ್ೕೖೞೠೡೢೣ೦೧೨೩೪೫೬೭೮೯ೱೲംഃഅആഇഈഉഊഋഌഎഏഐഒഓഔകഖഗഘങചഛജഝഞടഠഡഢണതഥദധനഩപഫബഭമയരറലളഴവശഷസഹഺഽാിീുൂൃൄെേൈൊോൌ്ൎൗൠൡൢൣ൦൧൨൩൪൫൬൭൮൯൰൱൲൳൴൵൹ൺൻർൽൾൿංඃඅආඇඈඉඊඋඌඍඎඏඐඑඒඓඔඕඖකඛගඝඞඟචඡජඣඤඥඦටඨඩඪණඬතථදධනඳපඵබභමඹයරලවශෂසහළෆ්ාැෑිීුූෘෙේෛොෝෞෟෲෳ෴กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำิีึืฺุู฿เแโใไๅๆ็่้๊๋์ํ๎๏๐๑๒๓๔๕๖๗๘๙๚๛ກຂຄງຈຊຍດຕຖທນບປຜຝພຟມຢຣລວສຫອຮຯະັາຳິີຶືຸູົຼຽເແໂໃໄໆ່້໊໋໌ໍ໐໑໒໓໔໕໖໗໘໙ໜໝໞໟༀ༁༂༃༄༅༆༇༈༉༊་༌།༎༏༐༑༒༓༔༕༖༗༘༙༚༛༜༝༞༟༠༡༢༣༤༥༦༧༨༩༪༫༬༭༮༯༰༱༲༳༴༵༶༷༸༹༺༻༼༽༾༿ཀཁགགྷངཅཆཇཉཊཋཌཌྷཎཏཐདདྷནཔཕབབྷམཙཚཛཛྷཝཞཟའཡརལཤཥསཧཨཀྵཪཫཬཱཱཱིིུུྲྀཷླྀཹེཻོཽཾཿ྄ཱྀྀྂྃ྅྆྇ྈྉྊྋྌྍྎྏྐྑྒྒྷྔྕྖྗྙྚྛྜྜྷྞྟྠྡྡྷྣྤྥྦྦྷྨྩྪྫྫྷྭྮྯྰྱྲླྴྵྶྷྸྐྵྺྻྼ྾྿࿀࿁࿂࿃࿄࿅࿆࿇࿈࿉࿊࿋࿌࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚ကခဂဃငစဆဇဈဉညဋဌဍဎဏတထဒဓနပဖဗဘမယရလဝသဟဠအဢဣဤဥဦဧဨဩဪါာိီုူေဲဳဴဵံ့း္်ျြွှဿ၀၁၂၃၄၅၆၇၈၉၊။၌၍၎၏ၐၑၒၓၔၕၖၗၘၙၚၛၜၝၞၟၠၡၢၣၤၥၦၧၨၩၪၫၬၭၮၯၰၱၲၳၴၵၶၷၸၹၺၻၼၽၾၿႀႁႂႃႄႅႆႇႈႉႊႋႌႍႎႏ႐႑႒႓႔႕႖႗႘႙ႚႛႜႝ႞႟ႠႡႢႣႤႥႦႧႨႩႪႫႬႭႮႯႰႱႲႳႴႵႶႷႸႹႺႻႼႽႾႿჀჁჂჃჄჅჇჍაბგდევზთიკლმნოპჟრსტუფქღყშჩცძწჭხჯჰჱჲჳჴჵჶჷჸჹჺ჻ჼჽჾჿᄀᄁᄂᄃᄄᄅᄆᄇᄈᄉᄊᄋᄌᄍᄎᄏᄐᄑᄒᄓᄔᄕᄖᄗᄘᄙᄚᄛᄜᄝᄞᄟᄠᄡᄢᄣᄤᄥᄦᄧᄨᄩᄪᄫᄬᄭᄮᄯᄰᄱᄲᄳᄴᄵᄶᄷᄸᄹᄺᄻᄼᄽᄾᄿᅀᅁᅂᅃᅄᅅᅆᅇᅈᅉᅊᅋᅌᅍᅎᅏᅐᅑᅒᅓᅔᅕᅖᅗᅘᅙᅚᅛᅜᅝᅞᅟᅠᅡᅢᅣᅤᅥᅦᅧᅨᅩᅪᅫᅬᅭᅮᅯᅰᅱᅲᅳᅴᅵᅶᅷᅸᅹᅺᅻᅼᅽᅾᅿᆀᆁᆂᆃᆄᆅᆆᆇᆈᆉᆊᆋᆌᆍᆎᆏᆐᆑᆒᆓᆔᆕᆖᆗᆘᆙᆚᆛᆜᆝᆞᆟᆠᆡᆢᆣᆤᆥᆦᆧᆨᆩᆪᆫᆬᆭᆮᆯᆰᆱᆲᆳᆴᆵᆶᆷᆸᆹᆺᆻᆼᆽᆾᆿᇀᇁᇂᇃᇄᇅᇆᇇᇈᇉᇊᇋᇌᇍᇎᇏᇐᇑᇒᇓᇔᇕᇖᇗᇘᇙᇚᇛᇜᇝᇞᇟᇠᇡᇢᇣᇤᇥᇦᇧᇨᇩᇪᇫᇬᇭᇮᇯᇰᇱᇲᇳᇴᇵᇶᇷᇸᇹᇺᇻᇼᇽᇾᇿሀሁሂሃሄህሆሇለሉሊላሌልሎሏሐሑሒሓሔሕሖሗመሙሚማሜምሞሟሠሡሢሣሤሥሦሧረሩሪራሬርሮሯሰሱሲሳሴስሶሷሸሹሺሻሼሽሾሿቀቁቂቃቄቅቆቇቈቊቋቌቍቐቑቒቓቔቕቖቘቚቛቜቝበቡቢባቤብቦቧቨቩቪቫቬቭቮቯተቱቲታቴትቶቷቸቹቺቻቼችቾቿኀኁኂኃኄኅኆኇኈኊኋኌኍነኑኒናኔንኖኗኘኙኚኛኜኝኞኟአኡኢኣኤእኦኧከኩኪካኬክኮኯኰኲኳኴኵኸኹኺኻኼኽኾዀዂዃዄዅወዉዊዋዌውዎዏዐዑዒዓዔዕዖዘዙዚዛዜዝዞዟዠዡዢዣዤዥዦዧየዩዪያዬይዮዯደዱዲዳዴድዶዷዸዹዺዻዼዽዾዿጀጁጂጃጄጅጆጇገጉጊጋጌግጎጏጐጒጓጔጕጘጙጚጛጜጝጞጟጠጡጢጣጤጥጦጧጨጩጪጫጬጭጮጯጰጱጲጳጴጵጶጷጸጹጺጻጼጽጾጿፀፁፂፃፄፅፆፇፈፉፊፋፌፍፎፏፐፑፒፓፔፕፖፗፘፙፚ፝፞፟፠፡።፣፤፥፦፧፨፩፪፫፬፭፮፯፰፱፲፳፴፵፶፷፸፹፺፻፼ᎀᎁᎂᎃᎄᎅᎆᎇᎈᎉᎊᎋᎌᎍᎎᎏ᎐᎑᎒᎓᎔᎕᎖᎗᎘᎙ᎠᎡᎢᎣᎤᎥᎦᎧᎨᎩᎪᎫᎬᎭᎮᎯᎰᎱᎲᎳᎴᎵᎶᎷᎸᎹᎺᎻᎼᎽᎾᎿᏀᏁᏂᏃᏄᏅᏆᏇᏈᏉᏊᏋᏌᏍᏎᏏᏐᏑᏒᏓᏔᏕᏖᏗᏘᏙᏚᏛᏜᏝᏞᏟᏠᏡᏢᏣᏤᏥᏦᏧᏨᏩᏪᏫᏬᏭᏮᏯᏰᏱᏲᏳᏴ᐀ᐁᐂᐃᐄᐅᐆᐇᐈᐉᐊᐋᐌᐍᐎᐏᐐᐑᐒᐓᐔᐕᐖᐗᐘᐙᐚᐛᐜᐝᐞᐟᐠᐡᐢᐣᐤᐥᐦᐧᐨᐩᐪᐫᐬᐭᐮᐯᐰᐱᐲᐳᐴᐵᐶᐷᐸᐹᐺᐻᐼᐽᐾᐿᑀᑁᑂᑃᑄᑅᑆᑇᑈᑉᑊᑋᑌᑍᑎᑏᑐᑑᑒᑓᑔᑕᑖᑗᑘᑙᑚᑛᑜᑝᑞᑟᑠᑡᑢᑣᑤᑥᑦᑧᑨᑩᑪᑫᑬᑭᑮᑯᑰᑱᑲᑳᑴᑵᑶᑷᑸᑹᑺᑻᑼᑽᑾᑿᒀᒁᒂᒃᒄᒅᒆᒇᒈᒉᒊᒋᒌᒍᒎᒏᒐᒑᒒᒓᒔᒕᒖᒗᒘᒙᒚᒛᒜᒝᒞᒟᒠᒡᒢᒣᒤᒥᒦᒧᒨᒩᒪᒫᒬᒭᒮᒯᒰᒱᒲᒳᒴᒵᒶᒷᒸᒹᒺᒻᒼᒽᒾᒿᓀᓁᓂᓃᓄᓅᓆᓇᓈᓉᓊᓋᓌᓍᓎᓏᓐᓑᓒᓓᓔᓕᓖᓗᓘᓙᓚᓛᓜᓝᓞᓟᓠᓡᓢᓣᓤᓥᓦᓧᓨᓩᓪᓫᓬᓭᓮᓯᓰᓱᓲᓳᓴᓵᓶᓷᓸᓹᓺᓻᓼᓽᓾᓿᔀᔁᔂᔃᔄᔅᔆᔇᔈᔉᔊᔋᔌᔍᔎᔏᔐᔑᔒᔓᔔᔕᔖᔗᔘᔙᔚᔛᔜᔝᔞᔟᔠᔡᔢᔣᔤᔥᔦᔧᔨᔩᔪᔫᔬᔭᔮᔯᔰᔱᔲᔳᔴᔵᔶᔷᔸᔹᔺᔻᔼᔽᔾᔿᕀᕁᕂᕃᕄᕅᕆᕇᕈᕉᕊᕋᕌᕍᕎᕏᕐᕑᕒᕓᕔᕕᕖᕗᕘᕙᕚᕛᕜᕝᕞᕟᕠᕡᕢᕣᕤᕥᕦᕧᕨᕩᕪᕫᕬᕭᕮᕯᕰᕱᕲᕳᕴᕵᕶᕷᕸᕹᕺᕻᕼᕽᕾᕿᖀᖁᖂᖃᖄᖅᖆᖇᖈᖉᖊᖋᖌᖍᖎᖏᖐᖑᖒᖓᖔᖕᖖᖗᖘᖙᖚᖛᖜᖝᖞᖟᖠᖡᖢᖣᖤᖥᖦᖧᖨᖩᖪᖫᖬᖭᖮᖯᖰᖱᖲᖳᖴᖵᖶᖷᖸᖹᖺᖻᖼᖽᖾᖿᗀᗁᗂᗃᗄᗅᗆᗇᗈᗉᗊᗋᗌᗍᗎᗏᗐᗑᗒᗓᗔᗕᗖᗗᗘᗙᗚᗛᗜᗝᗞᗟᗠᗡᗢᗣᗤᗥᗦᗧᗨᗩᗪᗫᗬᗭᗮᗯᗰᗱᗲᗳᗴᗵᗶᗷᗸᗹᗺᗻᗼᗽᗾᗿᘀᘁᘂᘃᘄᘅᘆᘇᘈᘉᘊᘋᘌᘍᘎᘏᘐᘑᘒᘓᘔᘕᘖᘗᘘᘙᘚᘛᘜᘝᘞᘟᘠᘡᘢᘣᘤᘥᘦᘧᘨᘩᘪᘫᘬᘭᘮᘯᘰᘱᘲᘳᘴᘵᘶᘷᘸᘹᘺᘻᘼᘽᘾᘿᙀᙁᙂᙃᙄᙅᙆᙇᙈᙉᙊᙋᙌᙍᙎᙏᙐᙑᙒᙓᙔᙕᙖᙗᙘᙙᙚᙛᙜᙝᙞᙟᙠᙡᙢᙣᙤᙥᙦᙧᙨᙩᙪᙫᙬ᙭᙮ᙯᙰᙱᙲᙳᙴᙵᙶᙷᙸᙹᙺᙻᙼᙽᙾᙿ ᚁᚂᚃᚄᚅᚆᚇᚈᚉᚊᚋᚌᚍᚎᚏᚐᚑᚒᚓᚔᚕᚖᚗᚘᚙᚚ᚛᚜ᚠᚡᚢᚣᚤᚥᚦᚧᚨᚩᚪᚫᚬᚭᚮᚯᚰᚱᚲᚳᚴᚵᚶᚷᚸᚹᚺᚻᚼᚽᚾᚿᛀᛁᛂᛃᛄᛅᛆᛇᛈᛉᛊᛋᛌᛍᛎᛏᛐᛑᛒᛓᛔᛕᛖᛗᛘᛙᛚᛛᛜᛝᛞᛟᛠᛡᛢᛣᛤᛥᛦᛧᛨᛩᛪ᛫᛬᛭ᛮᛯᛰᜀᜁᜂᜃᜄᜅᜆᜇᜈᜉᜊᜋᜌᜎᜏᜐᜑᜒᜓ᜔ᜠᜡᜢᜣᜤᜥᜦᜧᜨᜩᜪᜫᜬᜭᜮᜯᜰᜱᜲᜳ᜴᜵᜶ᝀᝁᝂᝃᝄᝅᝆᝇᝈᝉᝊᝋᝌᝍᝎᝏᝐᝑᝒᝓᝠᝡᝢᝣᝤᝥᝦᝧᝨᝩᝪᝫᝬᝮᝯᝰᝲᝳកខគឃងចឆជឈញដឋឌឍណតថទធនបផពភមយរលវឝឞសហឡអឣឤឥឦឧឨឩឪឫឬឭឮឯឰឱឲឳ឴឵ាិីឹឺុូួើឿៀេែៃោៅំះៈ៉៊់៌៍៎៏័៑្៓។៕៖ៗ៘៙៚៛ៜ៝០១២៣៤៥៦៧៨៩៰៱៲៳៴៵៶៷៸៹᠀᠁᠂᠃᠄᠅᠆᠇᠈᠉᠊᠋᠌᠍᠎᠐᠑᠒᠓᠔᠕᠖᠗᠘᠙ᠠᠡᠢᠣᠤᠥᠦᠧᠨᠩᠪᠫᠬᠭᠮᠯᠰᠱᠲᠳᠴᠵᠶᠷᠸᠹᠺᠻᠼᠽᠾᠿᡀᡁᡂᡃᡄᡅᡆᡇᡈᡉᡊᡋᡌᡍᡎᡏᡐᡑᡒᡓᡔᡕᡖᡗᡘᡙᡚᡛᡜᡝᡞᡟᡠᡡᡢᡣᡤᡥᡦᡧᡨᡩᡪᡫᡬᡭᡮᡯᡰᡱᡲᡳᡴᡵᡶᡷᢀᢁᢂᢃᢄᢅᢆᢇᢈᢉᢊᢋᢌᢍᢎᢏᢐᢑᢒᢓᢔᢕᢖᢗᢘᢙᢚᢛᢜᢝᢞᢟᢠᢡᢢᢣᢤᢥᢦᢧᢨᢩᢪᢰᢱᢲᢳᢴᢵᢶᢷᢸᢹᢺᢻᢼᢽᢾᢿᣀᣁᣂᣃᣄᣅᣆᣇᣈᣉᣊᣋᣌᣍᣎᣏᣐᣑᣒᣓᣔᣕᣖᣗᣘᣙᣚᣛᣜᣝᣞᣟᣠᣡᣢᣣᣤᣥᣦᣧᣨᣩᣪᣫᣬᣭᣮᣯᣰᣱᣲᣳᣴᣵᤀᤁᤂᤃᤄᤅᤆᤇᤈᤉᤊᤋᤌᤍᤎᤏᤐᤑᤒᤓᤔᤕᤖᤗᤘᤙᤚᤛᤜᤠᤡᤢᤣᤤᤥᤦᤧᤨᤩᤪᤫᤰᤱᤲᤳᤴᤵᤶᤷᤸ᤻᤹᤺᥀᥄᥅᥆᥇᥈᥉᥊᥋᥌᥍᥎᥏ᥐᥑᥒᥓᥔᥕᥖᥗᥘᥙᥚᥛᥜᥝᥞᥟᥠᥡᥢᥣᥤᥥᥦᥧᥨᥩᥪᥫᥬᥭᥰᥱᥲᥳᥴᦀᦁᦂᦃᦄᦅᦆᦇᦈᦉᦊᦋᦌᦍᦎᦏᦐᦑᦒᦓᦔᦕᦖᦗᦘᦙᦚᦛᦜᦝᦞᦟᦠᦡᦢᦣᦤᦥᦦᦧᦨᦩᦪᦫᦰᦱᦲᦳᦴᦵᦶᦷᦸᦹᦺᦻᦼᦽᦾᦿᧀᧁᧂᧃᧄᧅᧆᧇᧈᧉ᧐᧑᧒᧓᧔᧕᧖᧗᧘᧙᧚᧞᧟᧠᧡᧢᧣᧤᧥᧦᧧᧨᧩᧪᧫᧬᧭᧮᧯᧰᧱᧲᧳᧴᧵᧶᧷᧸᧹᧺᧻᧼᧽᧾᧿ᨀᨁᨂᨃᨄᨅᨆᨇᨈᨉᨊᨋᨌᨍᨎᨏᨐᨑᨒᨓᨔᨕᨖᨘᨗᨙᨚᨛ᨞᨟ᨠᨡᨢᨣᨤᨥᨦᨧᨨᨩᨪᨫᨬᨭᨮᨯᨰᨱᨲᨳᨴᨵᨶᨷᨸᨹᨺᨻᨼᨽᨾᨿᩀᩁᩂᩃᩄᩅᩆᩇᩈᩉᩊᩋᩌᩍᩎᩏᩐᩑᩒᩓᩔᩕᩖᩗᩘᩙᩚᩛᩜᩝᩞ᩠ᩡᩢᩣᩤᩥᩦᩧᩨᩩᩪᩫᩬᩭᩮᩯᩰᩱᩲᩳᩴ᩿᩵᩶᩷᩸᩹᩺᩻᩼᪀᪁᪂᪃᪄᪅᪆᪇᪈᪉᪐᪑᪒᪓᪔᪕᪖᪗᪘᪙᪠᪡᪢᪣᪤᪥᪦ᪧ᪨᪩᪪᪫᪬᪭ᬀᬁᬂᬃᬄᬅᬆᬇᬈᬉᬊᬋᬌᬍᬎᬏᬐᬑᬒᬓᬔᬕᬖᬗᬘᬙᬚᬛᬜᬝᬞᬟᬠᬡᬢᬣᬤᬥᬦᬧᬨᬩᬪᬫᬬᬭᬮᬯᬰᬱᬲᬳ᬴ᬵᬶᬷᬸᬹᬺᬻᬼᬽᬾᬿᭀᭁᭂᭃ᭄ᭅᭆᭇᭈᭉᭊᭋ᭐᭑᭒᭓᭔᭕᭖᭗᭘᭙᭚᭛᭜᭝᭞᭟᭠᭡᭢᭣᭤᭥᭦᭧᭨᭩᭪᭬᭫᭭᭮᭯᭰᭱᭲᭳᭴᭵᭶᭷᭸᭹᭺᭻᭼ᮀᮁᮂᮃᮄᮅᮆᮇᮈᮉᮊᮋᮌᮍᮎᮏᮐᮑᮒᮓᮔᮕᮖᮗᮘᮙᮚᮛᮜᮝᮞᮟᮠᮡᮢᮣᮤᮥᮦᮧᮨᮩ᮪᮫ᮬᮭᮮᮯ᮰᮱᮲᮳᮴᮵᮶᮷᮸᮹ᮺᮻᮼᮽᮾᮿᯀᯁᯂᯃᯄᯅᯆᯇᯈᯉᯊᯋᯌᯍᯎᯏᯐᯑᯒᯓᯔᯕᯖᯗᯘᯙᯚᯛᯜᯝᯞᯟᯠᯡᯢᯣᯤᯥ᯦ᯧᯨᯩᯪᯫᯬᯭᯮᯯᯰᯱ᯲᯳᯼᯽᯾᯿ᰀᰁᰂᰃᰄᰅᰆᰇᰈᰉᰊᰋᰌᰍᰎᰏᰐᰑᰒᰓᰔᰕᰖᰗᰘᰙᰚᰛᰜᰝᰞᰟᰠᰡᰢᰣᰤᰥᰦᰧᰨᰩᰪᰫᰬᰭᰮᰯᰰᰱᰲᰳᰴᰵᰶ᰷᰻᰼᰽᰾᰿᱀᱁᱂᱃᱄᱅᱆᱇᱈᱉ᱍᱎᱏ᱐᱑᱒᱓᱔᱕᱖᱗᱘᱙ᱚᱛᱜᱝᱞᱟᱠᱡᱢᱣᱤᱥᱦᱧᱨᱩᱪᱫᱬᱭᱮᱯᱰᱱᱲᱳᱴᱵᱶᱷᱸᱹᱺᱻᱼᱽ᱾᱿᳀᳁᳂᳃᳄᳅᳆᳇᳐᳑᳒᳓᳔᳕᳖᳗᳘᳙᳜᳝᳞᳟᳚᳛᳠᳡᳢᳣᳤᳥᳦᳧᳨ᳩᳪᳫᳬ᳭ᳮᳯᳰᳱᳲᳳ᳴ᳵᳶᴀᴁᴂᴃᴄᴅᴆᴇᴈᴉᴊᴋᴌᴍᴎᴏᴐᴑᴒᴓᴔᴕᴖᴗᴘᴙᴚᴛᴜᴝᴞᴟᴠᴡᴢᴣᴤᴥᴦᴧᴨᴩᴪᴫᴬᴭᴮᴯᴰᴱᴲᴳᴴᴵᴶᴷᴸᴹᴺᴻᴼᴽᴾᴿᵀᵁᵂᵃᵄᵅᵆᵇᵈᵉᵊᵋᵌᵍᵎᵏᵐᵑᵒᵓᵔᵕᵖᵗᵘᵙᵚᵛᵜᵝᵞᵟᵠᵡᵢᵣᵤᵥᵦᵧᵨᵩᵪᵫᵬᵭᵮᵯᵰᵱᵲᵳᵴᵵᵶᵷᵸᵹᵺᵻᵼᵽᵾᵿᶀᶁᶂᶃᶄᶅᶆᶇᶈᶉᶊᶋᶌᶍᶎᶏᶐᶑᶒᶓᶔᶕᶖᶗᶘᶙᶚᶛᶜᶝᶞᶟᶠᶡᶢᶣᶤᶥᶦᶧᶨᶩᶪᶫᶬᶭᶮᶯᶰᶱᶲᶳᶴᶵᶶᶷᶸᶹᶺᶻᶼᶽᶾᶿ᷐᷎᷂᷊᷏᷽᷿᷀᷁᷃᷄᷅᷆᷇᷈᷉᷋᷌᷑᷒ᷓᷔᷕᷖᷗᷘᷙᷚᷛᷜᷝᷞᷟᷠᷡᷢᷣᷤᷥᷦ᷾᷼᷍ḀḁḂḃḄḅḆḇḈḉḊḋḌḍḎḏḐḑḒḓḔḕḖḗḘḙḚḛḜḝḞḟḠḡḢḣḤḥḦḧḨḩḪḫḬḭḮḯḰḱḲḳḴḵḶḷḸḹḺḻḼḽḾḿṀṁṂṃṄṅṆṇṈṉṊṋṌṍṎṏṐṑṒṓṔṕṖṗṘṙṚṛṜṝṞṟṠṡṢṣṤṥṦṧṨṩṪṫṬṭṮṯṰṱṲṳṴṵṶṷṸṹṺṻṼṽṾṿẀẁẂẃẄẅẆẇẈẉẊẋẌẍẎẏẐẑẒẓẔẕẖẗẘẙẚẛẜẝẞẟẠạẢảẤấẦầẨẩẪẫẬậẮắẰằẲẳẴẵẶặẸẹẺẻẼẽẾếỀềỂểỄễỆệỈỉỊịỌọỎỏỐốỒồỔổỖỗỘộỚớỜờỞởỠỡỢợỤụỦủỨứỪừỬửỮữỰựỲỳỴỵỶỷỸỹỺỻỼỽỾỿἀἁἂἃἄἅἆἇἈἉἊἋἌἍἎἏἐἑἒἓἔἕἘἙἚἛἜἝἠἡἢἣἤἥἦἧἨἩἪἫἬἭἮἯἰἱἲἳἴἵἶἷἸἹἺἻἼἽἾἿὀὁὂὃὄὅὈὉὊὋὌὍὐὑὒὓὔὕὖὗὙὛὝὟὠὡὢὣὤὥὦὧὨὩὪὫὬὭὮὯὰάὲέὴήὶίὸόὺύὼώᾀᾁᾂᾃᾄᾅᾆᾇᾈᾉᾊᾋᾌᾍᾎᾏᾐᾑᾒᾓᾔᾕᾖᾗᾘᾙᾚᾛᾜᾝᾞᾟᾠᾡᾢᾣᾤᾥᾦᾧᾨᾩᾪᾫᾬᾭᾮᾯᾰᾱᾲᾳᾴᾶᾷᾸᾹᾺΆᾼ᾽ι᾿῀῁ῂῃῄῆῇῈΈῊΉῌ῍῎῏ῐῑῒΐῖῗῘῙῚΊ῝῞῟ῠῡῢΰῤῥῦῧῨῩῪΎῬ῭΅`ῲῳῴῶῷῸΌῺΏῼ´῾           ​‌‍‎‏‐‑‒–—―‖‗‘’‚‛“”„‟†‡•‣․‥…‧

‪‭‮ ‰‱′″‴‵‶‷‸‹›※‼‽‾‿⁀⁁⁂⁃⁄⁅⁆⁇⁈⁉⁊⁋⁌⁍⁎⁏⁐⁑⁒⁓⁔⁕⁖⁗⁘⁙⁚⁛⁜⁝⁞ ⁠⁡⁢⁣⁤⁰ⁱ⁴⁵⁶⁷⁸⁹⁺⁻⁼⁽⁾ⁿ₀₁₂₃₄₅₆₇₈₉₊₋₌₍₎ₐₑₒₓₔₕₖₗₘₙₚₛₜ₠₡₢₣₤₥₦₧₨₩₪₫€₭₮₯₰₱₲₳₴₵₶₷₸₹₺₻₼₽₾₿⃒⃓⃘⃙⃚⃐⃑⃔⃕⃖⃗⃛⃜⃝⃞⃟⃠⃡⃢⃣⃤⃥⃦⃪⃫⃨⃬⃭⃮⃯⃧⃩⃰℀℁ℂ℃℄℅℆ℇ℈℉ℊℋℌℍℎℏℐℑℒℓ℔ℕ№℗℘ℙℚℛℜℝ℞℟℠℡™℣ℤ℥Ω℧ℨ℩KÅℬℭ℮ℯℰℱℲℳℴℵℶℷℸℹ℺℻ℼℽℾℿ⅀⅁⅂⅃⅄ⅅⅆⅇⅈⅉ⅊⅋⅌⅍ⅎ⅏⅐⅑⅒⅓⅔⅕⅖⅗⅘⅙⅚⅛⅜⅝⅞⅟ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫⅬⅭⅮⅯⅰⅱⅲⅳⅴⅵⅶⅷⅸⅹⅺⅻⅼⅽⅾⅿↀↁↂↃↄↅↆↇↈ↉←↑→↓↔↕↖↗↘↙↚↛↜↝↞↟↠↡↢↣↤↥↦↧↨↩↪↫↬↭↮↯↰↱↲↳↴↵↶↷↸↹↺↻↼↽↾↿⇀⇁⇂⇃⇄⇅⇆⇇⇈⇉⇊⇋⇌⇍⇎⇏⇐⇑⇒⇓⇔⇕⇖⇗⇘⇙⇚⇛⇜⇝⇞⇟⇠⇡⇢⇣⇤⇥⇦⇧⇨⇩⇪⇫⇬⇭⇮⇯⇰⇱⇲⇳⇴⇵⇶⇷⇸⇹⇺⇻⇼⇽⇾⇿∀∁∂∃∄∅∆∇∈∉∊∋∌∍∎∏∐∑−∓∔∕∖∗∘∙√∛∜∝∞∟∠∡∢∣∤∥∦∧∨∩∪∫∬∭∮∯∰∱∲∳∴∵∶∷∸∹∺∻∼∽∾∿≀≁≂≃≄≅≆≇≈≉≊≋≌≍≎≏≐≑≒≓≔≕≖≗≘≙≚≛≜≝≞≟≠≡≢≣≤≥≦≧≨≩≪≫≬≭≮≯≰≱≲≳≴≵≶≷≸≹≺≻≼≽≾≿⊀⊁⊂⊃⊄⊅⊆⊇⊈⊉⊊⊋⊌⊍⊎⊏⊐⊑⊒⊓⊔⊕⊖⊗⊘⊙⊚⊛⊜⊝⊞⊟⊠⊡⊢⊣⊤⊥⊦⊧⊨⊩⊪⊫⊬⊭⊮⊯⊰⊱⊲⊳⊴⊵⊶⊷⊸⊹⊺⊻⊼⊽⊾⊿⋀⋁⋂⋃⋄⋅⋆⋇⋈⋉⋊⋋⋌⋍⋎⋏⋐⋑⋒⋓⋔⋕⋖⋗⋘⋙⋚⋛⋜⋝⋞⋟⋠⋡⋢⋣⋤⋥⋦⋧⋨⋩⋪⋫⋬⋭⋮⋯⋰⋱⋲⋳⋴⋵⋶⋷⋸⋹⋺⋻⋼⋽⋾⋿⌀⌁⌂⌃⌄⌅⌆⌇⌈⌉⌊⌋⌌⌍⌎⌏⌐⌑⌒⌓⌔⌕⌖⌗⌘⌙⌚⌛⌜⌝⌞⌟⌠⌡⌢⌣⌤⌥⌦⌧⌨〈〉⌫⌬⌭⌮⌯⌰⌱⌲⌳⌴⌵⌶⌷⌸⌹⌺⌻⌼⌽⌾⌿⍀⍁⍂⍃⍄⍅⍆⍇⍈⍉⍊⍋⍌⍍⍎⍏⍐⍑⍒⍓⍔⍕⍖⍗⍘⍙⍚⍛⍜⍝⍞⍟⍠⍡⍢⍣⍤⍥⍦⍧⍨⍩⍪⍫⍬⍭⍮⍯⍰⍱⍲⍳⍴⍵⍶⍷⍸⍹⍺⍻⍼⍽⍾⍿⎀⎁⎂⎃⎄⎅⎆⎇⎈⎉⎊⎋⎌⎍⎎⎏⎐⎑⎒⎓⎔⎕⎖⎗⎘⎙⎚⎛⎜⎝⎞⎟⎠⎡⎢⎣⎤⎥⎦⎧⎨⎩⎪⎫⎬⎭⎮⎯⎰⎱⎲⎳⎴⎵⎶⎷⎸⎹⎺⎻⎼⎽⎾⎿⏀⏁⏂⏃⏄⏅⏆⏇⏈⏉⏊⏋⏌⏍⏎⏏⏐⏑⏒⏓⏔⏕⏖⏗⏘⏙⏚⏛⏜⏝⏞⏟⏠⏡⏢⏣⏤⏥⏦⏧⏨⏩⏪⏫⏬⏭⏮⏯⏰⏱⏲⏳␀␁␂␃␄␅␆␇␈␉␊␋␌␍␎␏␐␑␒␓␔␕␖␗␘␙␚␛␜␝␞␟␠␡␢␣␤␥␦⑀⑁⑂⑃⑄⑅⑆⑇⑈⑉⑊①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳⑴⑵⑶⑷⑸⑹⑺⑻⑼⑽⑾⑿⒀⒁⒂⒃⒄⒅⒆⒇⒈⒉⒊⒋⒌⒍⒎⒏⒐⒑⒒⒓⒔⒕⒖⒗⒘⒙⒚⒛⒜⒝⒞⒟⒠⒡⒢⒣⒤⒥⒦⒧⒨⒩⒪⒫⒬⒭⒮⒯⒰⒱⒲⒳⒴⒵ⒶⒷⒸⒹⒺⒻⒼⒽⒾⒿⓀⓁⓂⓃⓄⓅⓆⓇⓈⓉⓊⓋⓌⓍⓎⓏⓐⓑⓒⓓⓔⓕⓖⓗⓘⓙⓚⓛⓜⓝⓞⓟⓠⓡⓢⓣⓤⓥⓦⓧⓨⓩ⓪⓫⓬⓭⓮⓯⓰⓱⓲⓳⓴⓵⓶⓷⓸⓹⓺⓻⓼⓽⓾⓿─━│┃┄┅┆┇┈┉┊┋┌┍┎┏┐┑┒┓└┕┖┗┘┙┚┛├┝┞┟┠┡┢┣┤┥┦┧┨┩┪┫┬┭┮┯┰┱┲┳┴┵┶┷┸┹┺┻┼┽┾┿╀╁╂╃╄╅╆╇╈╉╊╋╌╍╎╏═║╒╓╔╕╖╗╘╙╚╛╜╝╞╟╠╡╢╣╤╥╦╧╨╩╪╫╬╭╮╯╰╱╲╳╴╵╶╷╸╹╺╻╼╽╾╿▀▁▂▃▄▅▆▇█▉▊▋▌▍▎▏▐░▒▓▔▕▖▗▘▙▚▛▜▝▞▟■□▢▣▤▥▦▧▨▩▪▫▬▭▮▯▰▱▲△▴▵▶▷▸▹►▻▼▽▾▿◀◁◂◃◄◅◆◇◈◉◊○◌◍◎●◐◑◒◓◔◕◖◗◘◙◚◛◜◝◞◟◠◡◢◣◤◥◦◧◨◩◪◫◬◭◮◯◰◱◲◳◴◵◶◷◸◹◺◻◼◽◾◿☀☁☂☃☄★☆☇☈☉☊☋☌☍☎☏☐☑☒☓☔☕☖☗☘☙☚☛☜☝☞☟☠☡☢☣☤☥☦☧☨☩☪☫☬☭☮☯☰☱☲☳☴☵☶☷☸☹☺☻☼☽☾☿♀♁♂♃♄♅♆♇♈♉♊♋♌♍♎♏♐♑♒♓♔♕♖♗♘♙♚♛♜♝♞♟♠♡♢♣♤♥♦♧♨♩♪♫♬♭♮♯♰♱♲♳♴♵♶♷♸♹♺♻♼♽♾♿⚀⚁⚂⚃⚄⚅⚆⚇⚈⚉⚊⚋⚌⚍⚎⚏⚐⚑⚒⚓⚔⚕⚖⚗⚘⚙⚚⚛⚜⚝⚞⚟⚠⚡⚢⚣⚤⚥⚦⚧⚨⚩⚪⚫⚬⚭⚮⚯⚰⚱⚲⚳⚴⚵⚶⚷⚸⚹⚺⚻⚼⚽⚾⚿⛀⛁⛂⛃⛄⛅⛆⛇⛈⛉⛊⛋⛌⛍⛎⛏⛐⛑⛒⛓⛔⛕⛖⛗⛘⛙⛚⛛⛜⛝⛞⛟⛠⛡⛢⛣⛤⛥⛦⛧⛨⛩⛪⛫⛬⛭⛮⛯⛰⛱⛲⛳⛴⛵⛶⛷⛸⛹⛺⛻⛼⛽⛾⛿✁✂✃✄✅✆✇✈✉✊✋✌✍✎✏✐✑✒✓✔✕✖✗✘✙✚✛✜✝✞✟✠✡✢✣✤✥✦✧✨✩✪✫✬✭✮✯✰✱✲✳✴✵✶✷✸✹✺✻✼✽✾✿❀❁❂❃❄❅❆❇❈❉❊❋❌❍❎❏❐❑❒❓❔❕❖❗❘❙❚❛❜❝❞❟❠❡❢❣❤❥❦❧❨❩❪❫❬❭❮❯❰❱❲❳❴❵❶❷❸❹❺❻❼❽❾❿➀➁➂➃➄➅➆➇➈➉➊➋➌➍➎➏➐➑➒➓➔➕➖➗➘➙➚➛➜➝➞➟➠➡➢➣➤➥➦➧➨➩➪➫➬➭➮➯➰➱➲➳➴➵➶➷➸➹➺➻➼➽➾➿⟀⟁⟂⟃⟄⟅⟆⟇⟈⟉⟊⟋⟌⟍⟎⟏⟐⟑⟒⟓⟔⟕⟖⟗⟘⟙⟚⟛⟜⟝⟞⟟⟠⟡⟢⟣⟤⟥⟦⟧⟨⟩⟪⟫⟬⟭⟮⟯⟰⟱⟲⟳⟴⟵⟶⟷⟸⟹⟺⟻⟼⟽⟾⟿⠀⠁⠂⠃⠄⠅⠆⠇⠈⠉⠊⠋⠌⠍⠎⠏⠐⠑⠒⠓⠔⠕⠖⠗⠘⠙⠚⠛⠜⠝⠞⠟⠠⠡⠢⠣⠤⠥⠦⠧⠨⠩⠪⠫⠬⠭⠮⠯⠰⠱⠲⠳⠴⠵⠶⠷⠸⠹⠺⠻⠼⠽⠾⠿⡀⡁⡂⡃⡄⡅⡆⡇⡈⡉⡊⡋⡌⡍⡎⡏⡐⡑⡒⡓⡔⡕⡖⡗⡘⡙⡚⡛⡜⡝⡞⡟⡠⡡⡢⡣⡤⡥⡦⡧⡨⡩⡪⡫⡬⡭⡮⡯⡰⡱⡲⡳⡴⡵⡶⡷⡸⡹⡺⡻⡼⡽⡾⡿⢀⢁⢂⢃⢄⢅⢆⢇⢈⢉⢊⢋⢌⢍⢎⢏⢐⢑⢒⢓⢔⢕⢖⢗⢘⢙⢚⢛⢜⢝⢞⢟⢠⢡⢢⢣⢤⢥⢦⢧⢨⢩⢪⢫⢬⢭⢮⢯⢰⢱⢲⢳⢴⢵⢶⢷⢸⢹⢺⢻⢼⢽⢾⢿⣀⣁⣂⣃⣄⣅⣆⣇⣈⣉⣊⣋⣌⣍⣎⣏⣐⣑⣒⣓⣔⣕⣖⣗⣘⣙⣚⣛⣜⣝⣞⣟⣠⣡⣢⣣⣤⣥⣦⣧⣨⣩⣪⣫⣬⣭⣮⣯⣰⣱⣲⣳⣴⣵⣶⣷⣸⣹⣺⣻⣼⣽⣾⣿⤀⤁⤂⤃⤄⤅⤆⤇⤈⤉⤊⤋⤌⤍⤎⤏⤐⤑⤒⤓⤔⤕⤖⤗⤘⤙⤚⤛⤜⤝⤞⤟⤠⤡⤢⤣⤤⤥⤦⤧⤨⤩⤪⤫⤬⤭⤮⤯⤰⤱⤲⤳⤴⤵⤶⤷⤸⤹⤺⤻⤼⤽⤾⤿⥀⥁⥂⥃⥄⥅⥆⥇⥈⥉⥊⥋⥌⥍⥎⥏⥐⥑⥒⥓⥔⥕⥖⥗⥘⥙⥚⥛⥜⥝⥞⥟⥠⥡⥢⥣⥤⥥⥦⥧⥨⥩⥪⥫⥬⥭⥮⥯⥰⥱⥲⥳⥴⥵⥶⥷⥸⥹⥺⥻⥼⥽⥾⥿⦀⦁⦂⦃⦄⦅⦆⦇⦈⦉⦊⦋⦌⦍⦎⦏⦐⦑⦒⦓⦔⦕⦖⦗⦘⦙⦚⦛⦜⦝⦞⦟⦠⦡⦢⦣⦤⦥⦦⦧⦨⦩⦪⦫⦬⦭⦮⦯⦰⦱⦲⦳⦴⦵⦶⦷⦸⦹⦺⦻⦼⦽⦾⦿⧀⧁⧂⧃⧄⧅⧆⧇⧈⧉⧊⧋⧌⧍⧎⧏⧐⧑⧒⧓⧔⧕⧖⧗⧘⧙⧚⧛⧜⧝⧞⧟⧠⧡⧢⧣⧤⧥⧦⧧⧨⧩⧪⧫⧬⧭⧮⧯⧰⧱⧲⧳⧴⧵⧶⧷⧸⧹⧺⧻⧼⧽⧾⧿⨀⨁⨂⨃⨄⨅⨆⨇⨈⨉⨊⨋⨌⨍⨎⨏⨐⨑⨒⨓⨔⨕⨖⨗⨘⨙⨚⨛⨜⨝⨞⨟⨠⨡⨢⨣⨤⨥⨦⨧⨨⨩⨪⨫⨬⨭⨮⨯⨰⨱⨲⨳⨴⨵⨶⨷⨸⨹⨺⨻⨼⨽⨾⨿⩀⩁⩂⩃⩄⩅⩆⩇⩈⩉⩊⩋⩌⩍⩎⩏⩐⩑⩒⩓⩔⩕⩖⩗⩘⩙⩚⩛⩜⩝⩞⩟⩠⩡⩢⩣⩤⩥⩦⩧⩨⩩⩪⩫⩬⩭⩮⩯⩰⩱⩲⩳⩴⩵⩶⩷⩸⩹⩺⩻⩼⩽⩾⩿⪀⪁⪂⪃⪄⪅⪆⪇⪈⪉⪊⪋⪌⪍⪎⪏⪐⪑⪒⪓⪔⪕⪖⪗⪘⪙⪚⪛⪜⪝⪞⪟⪠⪡⪢⪣⪤⪥⪦⪧⪨⪩⪪⪫⪬⪭⪮⪯⪰⪱⪲⪳⪴⪵⪶⪷⪸⪹⪺⪻⪼⪽⪾⪿⫀⫁⫂⫃⫄⫅⫆⫇⫈⫉⫊⫋⫌⫍⫎⫏⫐⫑⫒⫓⫔⫕⫖⫗⫘⫙⫚⫛⫝̸⫝⫞⫟⫠⫡⫢⫣⫤⫥⫦⫧⫨⫩⫪⫫⫬⫭⫮⫯⫰⫱⫲⫳⫴⫵⫶⫷⫸⫹⫺⫻⫼⫽⫾⫿⬀⬁⬂⬃⬄⬅⬆⬇⬈⬉⬊⬋⬌⬍⬎⬏⬐⬑⬒⬓⬔⬕⬖⬗⬘⬙⬚⬛⬜⬝⬞⬟⬠⬡⬢⬣⬤⬥⬦⬧⬨⬩⬪⬫⬬⬭⬮⬯⬰⬱⬲⬳⬴⬵⬶⬷⬸⬹⬺⬻⬼⬽⬾⬿⭀⭁⭂⭃⭄⭅⭆⭇⭈⭉⭊⭋⭌⭐⭑⭒⭓⭔⭕⭖⭗⭘⭙ⰀⰁⰂⰃⰄⰅⰆⰇⰈⰉⰊⰋⰌⰍⰎⰏⰐⰑⰒⰓⰔⰕⰖⰗⰘⰙⰚⰛⰜⰝⰞⰟⰠⰡⰢⰣⰤⰥⰦⰧⰨⰩⰪⰫⰬⰭⰮⰰⰱⰲⰳⰴⰵⰶⰷⰸⰹⰺⰻⰼⰽⰾⰿⱀⱁⱂⱃⱄⱅⱆⱇⱈⱉⱊⱋⱌⱍⱎⱏⱐⱑⱒⱓⱔⱕⱖⱗⱘⱙⱚⱛⱜⱝⱞⱠⱡⱢⱣⱤⱥⱦⱧⱨⱩⱪⱫⱬⱭⱮⱯⱰⱱⱲⱳⱴⱵⱶⱷⱸⱹⱺⱻⱼⱽⱾⱿⲀⲁⲂⲃⲄⲅⲆⲇⲈⲉⲊⲋⲌⲍⲎⲏⲐⲑⲒⲓⲔⲕⲖⲗⲘⲙⲚⲛⲜⲝⲞⲟⲠⲡⲢⲣⲤⲥⲦⲧⲨⲩⲪⲫⲬⲭⲮⲯⲰⲱⲲⲳⲴⲵⲶⲷⲸⲹⲺⲻⲼⲽⲾⲿⳀⳁⳂⳃⳄⳅⳆⳇⳈⳉⳊⳋⳌⳍⳎⳏⳐⳑⳒⳓⳔⳕⳖⳗⳘⳙⳚⳛⳜⳝⳞⳟⳠⳡⳢⳣⳤ⳥⳦⳧⳨⳩⳪ⳫⳬⳭⳮ⳯⳰⳱Ⳳⳳ⳹⳺⳻⳼⳽⳾⳿ⴀⴁⴂⴃⴄⴅⴆⴇⴈⴉⴊⴋⴌⴍⴎⴏⴐⴑⴒⴓⴔⴕⴖⴗⴘⴙⴚⴛⴜⴝⴞⴟⴠⴡⴢⴣⴤⴥⴧⴭⴰⴱⴲⴳⴴⴵⴶⴷⴸⴹⴺⴻⴼⴽⴾⴿⵀⵁⵂⵃⵄⵅⵆⵇⵈⵉⵊⵋⵌⵍⵎⵏⵐⵑⵒⵓⵔⵕⵖⵗⵘⵙⵚⵛⵜⵝⵞⵟⵠⵡⵢⵣⵤⵥⵦⵧⵯ⵰⵿ⶀⶁⶂⶃⶄⶅⶆⶇⶈⶉⶊⶋⶌⶍⶎⶏⶐⶑⶒⶓⶔⶕⶖⶠⶡⶢⶣⶤⶥⶦⶨⶩⶪⶫⶬⶭⶮⶰⶱⶲⶳⶴⶵⶶⶸⶹⶺⶻⶼⶽⶾⷀⷁⷂⷃⷄⷅⷆⷈⷉⷊⷋⷌⷍⷎⷐⷑⷒⷓⷔⷕⷖⷘⷙⷚⷛⷜⷝⷞⷠⷡⷢⷣⷤⷥⷦⷧⷨⷩⷪⷫⷬⷭⷮⷯⷰⷱⷲⷳⷴⷵⷶⷷⷸⷹⷺⷻⷼⷽⷾⷿ⸀⸁⸂⸃⸄⸅⸆⸇⸈⸉⸊⸋⸌⸍⸎⸏⸐⸑⸒⸓⸔⸕⸖⸗⸘⸙⸚⸛⸜⸝⸞⸟⸠⸡⸢⸣⸤⸥⸦⸧⸨⸩⸪⸫⸬⸭⸮ⸯ⸰⸱⸲⸳⸴⸵⸶⸷⸸⸹⸺⸻⺀⺁⺂⺃⺄⺅⺆⺇⺈⺉⺊⺋⺌⺍⺎⺏⺐⺑⺒⺓⺔⺕⺖⺗⺘⺙⺛⺜⺝⺞⺟⺠⺡⺢⺣⺤⺥⺦⺧⺨⺩⺪⺫⺬⺭⺮⺯⺰⺱⺲⺳⺴⺵⺶⺷⺸⺹⺺⺻⺼⺽⺾⺿⻀⻁⻂⻃⻄⻅⻆⻇⻈⻉⻊⻋⻌⻍⻎⻏⻐⻑⻒⻓⻔⻕⻖⻗⻘⻙⻚⻛⻜⻝⻞⻟⻠⻡⻢⻣⻤⻥⻦⻧⻨⻩⻪⻫⻬⻭⻮⻯⻰⻱⻲⻳⼀⼁⼂⼃⼄⼅⼆⼇⼈⼉⼊⼋⼌⼍⼎⼏⼐⼑⼒⼓⼔⼕⼖⼗⼘⼙⼚⼛⼜⼝⼞⼟⼠⼡⼢⼣⼤⼥⼦⼧⼨⼩⼪⼫⼬⼭⼮⼯⼰⼱⼲⼳⼴⼵⼶⼷⼸⼹⼺⼻⼼⼽⼾⼿⽀⽁⽂⽃⽄⽅⽆⽇⽈⽉⽊⽋⽌⽍⽎⽏⽐⽑⽒⽓⽔⽕⽖⽗⽘⽙⽚⽛⽜⽝⽞⽟⽠⽡⽢⽣⽤⽥⽦⽧⽨⽩⽪⽫⽬⽭⽮⽯⽰⽱⽲⽳⽴⽵⽶⽷⽸⽹⽺⽻⽼⽽⽾⽿⾀⾁⾂⾃⾄⾅⾆⾇⾈⾉⾊⾋⾌⾍⾎⾏⾐⾑⾒⾓⾔⾕⾖⾗⾘⾙⾚⾛⾜⾝⾞⾟⾠⾡⾢⾣⾤⾥⾦⾧⾨⾩⾪⾫⾬⾭⾮⾯⾰⾱⾲⾳⾴⾵⾶⾷⾸⾹⾺⾻⾼⾽⾾⾿⿀⿁⿂⿃⿄⿅⿆⿇⿈⿉⿊⿋⿌⿍⿎⿏⿐⿑⿒⿓⿔⿕⿰⿱⿲⿳⿴⿵⿶⿷⿸⿹⿺⿻ 、。〃〄々〆〇〈〉《》「」『』【】〒〓〔〕〖〗〘〙〚〛〜〝〞〟〠〡〢〣〤〥〦〧〨〩〪〭〮〯〫〬〰〱〲〳〴〵〶〷〸〹〺〻〼〽〾〿ぁあぃいぅうぇえぉおかがきぎくぐけげこごさざしじすずせぜそぞただちぢっつづてでとどなにぬねのはばぱひびぴふぶぷへべぺほぼぽまみむめもゃやゅゆょよらりるれろゎわゐゑをんゔゕゖ゙゚゛゜ゝゞゟ゠ァアィイゥウェエォオカガキギクグケゲコゴサザシジスズセゼソゾタダチヂッツヅテデトドナニヌネノハバパヒビピフブプヘベペホボポマミムメモャヤュユョヨラリルレロヮワヰヱヲンヴヵヶヷヸヹヺ・ーヽヾヿㄅㄆㄇㄈㄉㄊㄋㄌㄍㄎㄏㄐㄑㄒㄓㄔㄕㄖㄗㄘㄙㄚㄛㄜㄝㄞㄟㄠㄡㄢㄣㄤㄥㄦㄧㄨㄩㄪㄫㄬㄭㄱㄲㄳㄴㄵㄶㄷㄸㄹㄺㄻㄼㄽㄾㄿㅀㅁㅂㅃㅄㅅㅆㅇㅈㅉㅊㅋㅌㅍㅎㅏㅐㅑㅒㅓㅔㅕㅖㅗㅘㅙㅚㅛㅜㅝㅞㅟㅠㅡㅢㅣㅤㅥㅦㅧㅨㅩㅪㅫㅬㅭㅮㅯㅰㅱㅲㅳㅴㅵㅶㅷㅸㅹㅺㅻㅼㅽㅾㅿㆀㆁㆂㆃㆄㆅㆆㆇㆈㆉㆊㆋㆌㆍㆎ㆐㆑㆒㆓㆔㆕㆖㆗㆘㆙㆚㆛㆜㆝㆞㆟ㆠㆡㆢㆣㆤㆥㆦㆧㆨㆩㆪㆫㆬㆭㆮㆯㆰㆱㆲㆳㆴㆵㆶㆷㆸㆹㆺ㇀㇁㇂㇃㇄㇅㇆㇇㇈㇉㇊㇋㇌㇍㇎㇏㇐㇑㇒㇓㇔㇕㇖㇗㇘㇙㇚㇛㇜㇝㇞㇟㇠㇡㇢㇣ㇰㇱㇲㇳㇴㇵㇶㇷㇸㇹㇺㇻㇼㇽㇾㇿ㈀㈁㈂㈃㈄㈅㈆㈇㈈㈉㈊㈋㈌㈍㈎㈏㈐㈑㈒㈓㈔㈕㈖㈗㈘㈙㈚㈛㈜㈝㈞㈠㈡㈢㈣㈤㈥㈦㈧㈨㈩㈪㈫㈬㈭㈮㈯㈰㈱㈲㈳㈴㈵㈶㈷㈸㈹㈺㈻㈼㈽㈾㈿㉀㉁㉂㉃㉄㉅㉆㉇㉈㉉㉊㉋㉌㉍㉎㉏㉐㉑㉒㉓㉔㉕㉖㉗㉘㉙㉚㉛㉜㉝㉞㉟㉠㉡㉢㉣㉤㉥㉦㉧㉨㉩㉪㉫㉬㉭㉮㉯㉰㉱㉲㉳㉴㉵㉶㉷㉸㉹㉺㉻㉼㉽㉾㉿㊀㊁㊂㊃㊄㊅㊆㊇㊈㊉㊊㊋㊌㊍㊎㊏㊐㊑㊒㊓㊔㊕㊖㊗㊘㊙㊚㊛㊜㊝㊞㊟㊠㊡㊢㊣㊤㊥㊦㊧㊨㊩㊪㊫㊬㊭㊮㊯㊰㊱㊲㊳㊴㊵㊶㊷㊸㊹㊺㊻㊼㊽㊾㊿㋀㋁㋂㋃㋄㋅㋆㋇㋈㋉㋊㋋㋌㋍㋎㋏㋐㋑㋒㋓㋔㋕㋖㋗㋘㋙㋚㋛㋜㋝㋞㋟㋠㋡㋢㋣㋤㋥㋦㋧㋨㋩㋪㋫㋬㋭㋮㋯㋰㋱㋲㋳㋴㋵㋶㋷㋸㋹㋺㋻㋼㋽㋾㋿㌀㌁㌂㌃㌄㌅㌆㌇㌈㌉㌊㌋㌌㌍㌎㌏㌐㌑㌒㌓㌔㌕㌖㌗㌘㌙㌚㌛㌜㌝㌞㌟㌠㌡㌢㌣㌤㌥㌦㌧㌨㌩㌪㌫㌬㌭㌮㌯㌰㌱㌲㌳㌴㌵㌶㌷㌸㌹㌺㌻㌼㌽㌾㌿㍀㍁㍂㍃㍄㍅㍆㍇㍈㍉㍊㍋㍌㍍㍎㍏㍐㍑㍒㍓㍔㍕㍖㍗㍘㍙㍚㍛㍜㍝㍞㍟㍠㍡㍢㍣㍤㍥㍦㍧㍨㍩㍪㍫㍬㍭㍮㍯㍰㍱㍲㍳㍴㍵㍶㍷㍸㍹㍺㍻㍼㍽㍾㍿㎀㎁㎂㎃㎄㎅㎆㎇㎈㎉㎊㎋㎌㎍㎎㎏㎐㎑㎒㎓㎔㎕㎖㎗㎘㎙㎚㎛㎜㎝㎞㎟㎠㎡㎢㎣㎤㎥㎦㎧㎨㎩㎪㎫㎬㎭㎮㎯㎰㎱㎲㎳㎴㎵㎶㎷㎸㎹㎺㎻㎼㎽㎾㎿㏀㏁㏂㏃㏄㏅㏆㏇㏈㏉㏊㏋㏌㏍㏎㏏㏐㏑㏒㏓㏔㏕㏖㏗㏘㏙㏚㏛㏜㏝㏞㏟㏠㏡㏢㏣㏤㏥㏦㏧㏨㏩㏪㏫㏬㏭㏮㏯㏰㏱㏲㏳㏴㏵㏶㏷㏸㏹㏺㏻㏼㏽㏾㏿㐀㐁㐂㐃㐄㐅㐆㐇㐈㐉㐊㐋㐌㐍㐎㐏㐐㐑㐒㐓㐔㐕㐖㐗㐘㐙㐚㐛㐜㐝㐞㐟㐠㐡㐢㐣㐤㐥㐦㐧㐨㐩㐪㐫㐬㐭㐮㐯㐰㐱㐲㐳㐴㐵㐶㐷㐸㐹㐺㐻㐼㐽㐾㐿㑀㑁㑂㑃㑄㑅㑆㑇㑈㑉㑊㑋㑌㑍㑎㑏㑐㑑㑒㑓㑔㑕㑖㑗㑘㑙㑚㑛㑜㑝㑞㑟㑠㑡㑢㑣㑤㑥㑦㑧㑨㑩㑪㑫㑬㑭㑮㑯㑰㑱㑲㑳㑴㑵㑶㑷㑸㑹㑺㑻㑼㑽㑾㑿㒀㒁㒂㒃㒄㒅㒆㒇㒈㒉㒊㒋㒌㒍㒎㒏㒐㒑㒒㒓㒔㒕㒖㒗㒘㒙㒚㒛㒜㒝㒞㒟㒠㒡㒢㒣㒤㒥㒦㒧㒨㒩㒪㒫㒬㒭㒮㒯㒰㒱㒲㒳㒴㒵㒶㒷㒸㒹㒺㒻㒼㒽㒾㒿㓀㓁㓂㓃㓄㓅㓆㓇㓈㓉㓊㓋㓌㓍㓎㓏㓐㓑㓒㓓㓔㓕㓖㓗㓘㓙㓚㓛㓜㓝㓞㓟㓠㓡㓢㓣㓤㓥㓦㓧㓨㓩㓪㓫㓬㓭㓮㓯㓰㓱㓲㓳㓴㓵㓶㓷㓸㓹㓺㓻㓼㓽㓾㓿㔀㔁㔂㔃㔄㔅㔆㔇㔈㔉㔊㔋㔌㔍㔎㔏㔐㔑㔒㔓㔔㔕㔖㔗㔘㔙㔚㔛㔜㔝㔞㔟㔠㔡㔢㔣㔤㔥㔦㔧㔨㔩㔪㔫㔬㔭㔮㔯㔰㔱㔲㔳㔴㔵㔶㔷㔸㔹㔺㔻㔼㔽㔾㔿㕀㕁㕂㕃㕄㕅㕆㕇㕈㕉㕊㕋㕌㕍㕎㕏㕐㕑㕒㕓㕔㕕㕖㕗㕘㕙㕚㕛㕜㕝㕞㕟㕠㕡㕢㕣㕤㕥㕦㕧㕨㕩㕪㕫㕬㕭㕮㕯㕰㕱㕲㕳㕴㕵㕶㕷㕸㕹㕺㕻㕼㕽㕾㕿㖀㖁㖂㖃㖄㖅㖆㖇㖈㖉㖊㖋㖌㖍㖎㖏㖐㖑㖒㖓㖔㖕㖖㖗㖘㖙㖚㖛㖜㖝㖞㖟㖠㖡㖢㖣㖤㖥㖦㖧㖨㖩㖪㖫㖬㖭㖮㖯㖰㖱㖲㖳㖴㖵㖶㖷㖸㖹㖺㖻㖼㖽㖾㖿㗀㗁㗂㗃㗄㗅㗆㗇㗈㗉㗊㗋㗌㗍㗎㗏㗐㗑㗒㗓㗔㗕㗖㗗㗘㗙㗚㗛㗜㗝㗞㗟㗠㗡㗢㗣㗤㗥㗦㗧㗨㗩㗪㗫㗬㗭㗮㗯㗰㗱㗲㗳㗴㗵㗶㗷㗸㗹㗺㗻㗼㗽㗾㗿㘀㘁㘂㘃㘄㘅㘆㘇㘈㘉㘊㘋㘌㘍㘎㘏㘐㘑㘒㘓㘔㘕㘖㘗㘘㘙㘚㘛㘜㘝㘞㘟㘠㘡㘢㘣㘤㘥㘦㘧㘨㘩㘪㘫㘬㘭㘮㘯㘰㘱㘲㘳㘴㘵㘶㘷㘸㘹㘺㘻㘼㘽㘾㘿㙀㙁㙂㙃㙄㙅㙆㙇㙈㙉㙊㙋㙌㙍㙎㙏㙐㙑㙒㙓㙔㙕㙖㙗㙘㙙㙚㙛㙜㙝㙞㙟㙠㙡㙢㙣㙤㙥㙦㙧㙨㙩㙪㙫㙬㙭㙮㙯㙰㙱㙲㙳㙴㙵㙶㙷㙸㙹㙺㙻㙼㙽㙾㙿㚀㚁㚂㚃㚄㚅㚆㚇㚈㚉㚊㚋㚌㚍㚎㚏㚐㚑㚒㚓㚔㚕㚖㚗㚘㚙㚚㚛㚜㚝㚞㚟㚠㚡㚢㚣㚤㚥㚦㚧㚨㚩㚪㚫㚬㚭㚮㚯㚰㚱㚲㚳㚴㚵㚶㚷㚸㚹㚺㚻㚼㚽㚾㚿㛀㛁㛂㛃㛄㛅㛆㛇㛈㛉㛊㛋㛌㛍㛎㛏㛐㛑㛒㛓㛔㛕㛖㛗㛘㛙㛚㛛㛜㛝㛞㛟㛠㛡㛢㛣㛤㛥㛦㛧㛨㛩㛪㛫㛬㛭㛮㛯㛰㛱㛲㛳㛴㛵㛶㛷㛸㛹㛺㛻㛼㛽㛾㛿㜀㜁㜂㜃㜄㜅㜆㜇㜈㜉㜊㜋㜌㜍㜎㜏㜐㜑㜒㜓㜔㜕㜖㜗㜘㜙㜚㜛㜜㜝㜞㜟㜠㜡㜢㜣㜤㜥㜦㜧㜨㜩㜪㜫㜬㜭㜮㜯㜰㜱㜲㜳㜴㜵㜶㜷㜸㜹㜺㜻㜼㜽㜾㜿㝀㝁㝂㝃㝄㝅㝆㝇㝈㝉㝊㝋㝌㝍㝎㝏㝐㝑㝒㝓㝔㝕㝖㝗㝘㝙㝚㝛㝜㝝㝞㝟㝠㝡㝢㝣㝤㝥㝦㝧㝨㝩㝪㝫㝬㝭㝮㝯㝰㝱㝲㝳㝴㝵㝶㝷㝸㝹㝺㝻㝼㝽㝾㝿㞀㞁㞂㞃㞄㞅㞆㞇㞈㞉㞊㞋㞌㞍㞎㞏㞐㞑㞒㞓㞔㞕㞖㞗㞘㞙㞚㞛㞜㞝㞞㞟㞠㞡㞢㞣㞤㞥㞦㞧㞨㞩㞪㞫㞬㞭㞮㞯㞰㞱㞲㞳㞴㞵㞶㞷㞸㞹㞺㞻㞼㞽㞾㞿㟀㟁㟂㟃㟄㟅㟆㟇㟈㟉㟊㟋㟌㟍㟎㟏㟐㟑㟒㟓㟔㟕㟖㟗㟘㟙㟚㟛㟜㟝㟞㟟㟠㟡㟢㟣㟤㟥㟦㟧㟨㟩㟪㟫㟬㟭㟮㟯㟰㟱㟲㟳㟴㟵㟶㟷㟸㟹㟺㟻㟼㟽㟾㟿㠀㠁㠂㠃㠄㠅㠆㠇㠈㠉㠊㠋㠌㠍㠎㠏㠐㠑㠒㠓㠔㠕㠖㠗㠘㠙㠚㠛㠜㠝㠞㠟㠠㠡㠢㠣㠤㠥㠦㠧㠨㠩㠪㠫㠬㠭㠮㠯㠰㠱㠲㠳㠴㠵㠶㠷㠸㠹㠺㠻㠼㠽㠾㠿㡀㡁㡂㡃㡄㡅㡆㡇㡈㡉㡊㡋㡌㡍㡎㡏㡐㡑㡒㡓㡔㡕㡖㡗㡘㡙㡚㡛㡜㡝㡞㡟㡠㡡㡢㡣㡤㡥㡦㡧㡨㡩㡪㡫㡬㡭㡮㡯㡰㡱㡲㡳㡴㡵㡶㡷㡸㡹㡺㡻㡼㡽㡾㡿㢀㢁㢂㢃㢄㢅㢆㢇㢈㢉㢊㢋㢌㢍㢎㢏㢐㢑㢒㢓㢔㢕㢖㢗㢘㢙㢚㢛㢜㢝㢞㢟㢠㢡㢢㢣㢤㢥㢦㢧㢨㢩㢪㢫㢬㢭㢮㢯㢰㢱㢲㢳㢴㢵㢶㢷㢸㢹㢺㢻㢼㢽㢾㢿㣀㣁㣂㣃㣄㣅㣆㣇㣈㣉㣊㣋㣌㣍㣎㣏㣐㣑㣒㣓㣔㣕㣖㣗㣘㣙㣚㣛㣜㣝㣞㣟㣠㣡㣢㣣㣤㣥㣦㣧㣨㣩㣪㣫㣬㣭㣮㣯㣰㣱㣲㣳㣴㣵㣶㣷㣸㣹㣺㣻㣼㣽㣾㣿㤀㤁㤂㤃㤄㤅㤆㤇㤈㤉㤊㤋㤌㤍㤎㤏㤐㤑㤒㤓㤔㤕㤖㤗㤘㤙㤚㤛㤜㤝㤞㤟㤠㤡㤢㤣㤤㤥㤦㤧㤨㤩㤪㤫㤬㤭㤮㤯㤰㤱㤲㤳㤴㤵㤶㤷㤸㤹㤺㤻㤼㤽㤾㤿㥀㥁㥂㥃㥄㥅㥆㥇㥈㥉㥊㥋㥌㥍㥎㥏㥐㥑㥒㥓㥔㥕㥖㥗㥘㥙㥚㥛㥜㥝㥞㥟㥠㥡㥢㥣㥤㥥㥦㥧㥨㥩㥪㥫㥬㥭㥮㥯㥰㥱㥲㥳㥴㥵㥶㥷㥸㥹㥺㥻㥼㥽㥾㥿㦀㦁㦂㦃㦄㦅㦆㦇㦈㦉㦊㦋㦌㦍㦎㦏㦐㦑㦒㦓㦔㦕㦖㦗㦘㦙㦚㦛㦜㦝㦞㦟㦠㦡㦢㦣㦤㦥㦦㦧㦨㦩㦪㦫㦬㦭㦮㦯㦰㦱㦲㦳㦴㦵㦶㦷㦸㦹㦺㦻㦼㦽㦾㦿㧀㧁㧂㧃㧄㧅㧆㧇㧈㧉㧊㧋㧌㧍㧎㧏㧐㧑㧒㧓㧔㧕㧖㧗㧘㧙㧚㧛㧜㧝㧞㧟㧠㧡㧢㧣㧤㧥㧦㧧㧨㧩㧪㧫㧬㧭㧮㧯㧰㧱㧲㧳㧴㧵㧶㧷㧸㧹㧺㧻㧼㧽㧾㧿㨀㨁㨂㨃㨄㨅㨆㨇㨈㨉㨊㨋㨌㨍㨎㨏㨐㨑㨒㨓㨔㨕㨖㨗㨘㨙㨚㨛㨜㨝㨞㨟㨠㨡㨢㨣㨤㨥㨦㨧㨨㨩㨪㨫㨬㨭㨮㨯㨰㨱㨲㨳㨴㨵㨶㨷㨸㨹㨺㨻㨼㨽㨾㨿㩀㩁㩂㩃㩄㩅㩆㩇㩈㩉㩊㩋㩌㩍㩎㩏㩐㩑㩒㩓㩔㩕㩖㩗㩘㩙㩚㩛㩜㩝㩞㩟㩠㩡㩢㩣㩤㩥㩦㩧㩨㩩㩪㩫㩬㩭㩮㩯㩰㩱㩲㩳㩴㩵㩶㩷㩸㩹㩺㩻㩼㩽㩾㩿㪀㪁㪂㪃㪄㪅㪆㪇㪈㪉㪊㪋㪌㪍㪎㪏㪐㪑㪒㪓㪔㪕㪖㪗㪘㪙㪚㪛㪜㪝㪞㪟㪠㪡㪢㪣㪤㪥㪦㪧㪨㪩㪪㪫㪬㪭㪮㪯㪰㪱㪲㪳㪴㪵㪶㪷㪸㪹㪺㪻㪼㪽㪾㪿㫀㫁㫂㫃㫄㫅㫆㫇㫈㫉㫊㫋㫌㫍㫎㫏㫐㫑㫒㫓㫔㫕㫖㫗㫘㫙㫚㫛㫜㫝㫞㫟㫠㫡㫢㫣㫤㫥㫦㫧㫨㫩㫪㫫㫬㫭㫮㫯㫰㫱㫲㫳㫴㫵㫶㫷㫸㫹㫺㫻㫼㫽㫾㫿㬀㬁㬂㬃㬄㬅㬆㬇㬈㬉㬊㬋㬌㬍㬎㬏㬐㬑㬒㬓㬔㬕㬖㬗㬘㬙㬚㬛㬜㬝㬞㬟㬠㬡㬢㬣㬤㬥㬦㬧㬨㬩㬪㬫㬬㬭㬮㬯㬰㬱㬲㬳㬴㬵㬶㬷㬸㬹㬺㬻㬼㬽㬾㬿㭀㭁㭂㭃㭄㭅㭆㭇㭈㭉㭊㭋㭌㭍㭎㭏㭐㭑㭒㭓㭔㭕㭖㭗㭘㭙㭚㭛㭜㭝㭞㭟㭠㭡㭢㭣㭤㭥㭦㭧㭨㭩㭪㭫㭬㭭㭮㭯㭰㭱㭲㭳㭴㭵㭶㭷㭸㭹㭺㭻㭼㭽㭾㭿㮀㮁㮂㮃㮄㮅㮆㮇㮈㮉㮊㮋㮌㮍㮎㮏㮐㮑㮒㮓㮔㮕㮖㮗㮘㮙㮚㮛㮜㮝㮞㮟㮠㮡㮢㮣㮤㮥㮦㮧㮨㮩㮪㮫㮬㮭㮮㮯㮰㮱㮲㮳㮴㮵㮶㮷㮸㮹㮺㮻㮼㮽㮾㮿㯀㯁㯂㯃㯄㯅㯆㯇㯈㯉㯊㯋㯌㯍㯎㯏㯐㯑㯒㯓㯔㯕㯖㯗㯘㯙㯚㯛㯜㯝㯞㯟㯠㯡㯢㯣㯤㯥㯦㯧㯨㯩㯪㯫㯬㯭㯮㯯㯰㯱㯲㯳㯴㯵㯶㯷㯸㯹㯺㯻㯼㯽㯾㯿㰀㰁㰂㰃㰄㰅㰆㰇㰈㰉㰊㰋㰌㰍㰎㰏㰐㰑㰒㰓㰔㰕㰖㰗㰘㰙㰚㰛㰜㰝㰞㰟㰠㰡㰢㰣㰤㰥㰦㰧㰨㰩㰪㰫㰬㰭㰮㰯㰰㰱㰲㰳㰴㰵㰶㰷㰸㰹㰺㰻㰼㰽㰾㰿㱀㱁㱂㱃㱄㱅㱆㱇㱈㱉㱊㱋㱌㱍㱎㱏㱐㱑㱒㱓㱔㱕㱖㱗㱘㱙㱚㱛㱜㱝㱞㱟㱠㱡㱢㱣㱤㱥㱦㱧㱨㱩㱪㱫㱬㱭㱮㱯㱰㱱㱲㱳㱴㱵㱶㱷㱸㱹㱺㱻㱼㱽㱾㱿㲀㲁㲂㲃㲄㲅㲆㲇㲈㲉㲊㲋㲌㲍㲎㲏㲐㲑㲒㲓㲔㲕㲖㲗㲘㲙㲚㲛㲜㲝㲞㲟㲠㲡㲢㲣㲤㲥㲦㲧㲨㲩㲪㲫㲬㲭㲮㲯㲰㲱㲲㲳㲴㲵㲶㲷㲸㲹㲺㲻㲼㲽㲾㲿㳀㳁㳂㳃㳄㳅㳆㳇㳈㳉㳊㳋㳌㳍㳎㳏㳐㳑㳒㳓㳔㳕㳖㳗㳘㳙㳚㳛㳜㳝㳞㳟㳠㳡㳢㳣㳤㳥㳦㳧㳨㳩㳪㳫㳬㳭㳮㳯㳰㳱㳲㳳㳴㳵㳶㳷㳸㳹㳺㳻㳼㳽㳾㳿㴀㴁㴂㴃㴄㴅㴆㴇㴈㴉㴊㴋㴌㴍㴎㴏㴐㴑㴒㴓㴔㴕㴖㴗㴘㴙㴚㴛㴜㴝㴞㴟㴠㴡㴢㴣㴤㴥㴦㴧㴨㴩㴪㴫㴬㴭㴮㴯㴰㴱㴲㴳㴴㴵㴶㴷㴸㴹㴺㴻㴼㴽㴾㴿㵀㵁㵂㵃㵄㵅㵆㵇㵈㵉㵊㵋㵌㵍㵎㵏㵐㵑㵒㵓㵔㵕㵖㵗㵘㵙㵚㵛㵜㵝㵞㵟㵠㵡㵢㵣㵤㵥㵦㵧㵨㵩㵪㵫㵬㵭㵮㵯㵰㵱㵲㵳㵴㵵㵶㵷㵸㵹㵺㵻㵼㵽㵾㵿㶀㶁㶂㶃㶄㶅㶆㶇㶈㶉㶊㶋㶌㶍㶎㶏㶐㶑㶒㶓㶔㶕㶖㶗㶘㶙㶚㶛㶜㶝㶞㶟㶠㶡㶢㶣㶤㶥㶦㶧㶨㶩㶪㶫㶬㶭㶮㶯㶰㶱㶲㶳㶴㶵㶶㶷㶸㶹㶺㶻㶼㶽㶾㶿㷀㷁㷂㷃㷄㷅㷆㷇㷈㷉㷊㷋㷌㷍㷎㷏㷐㷑㷒㷓㷔㷕㷖㷗㷘㷙㷚㷛㷜㷝㷞㷟㷠㷡㷢㷣㷤㷥㷦㷧㷨㷩㷪㷫㷬㷭㷮㷯㷰㷱㷲㷳㷴㷵㷶㷷㷸㷹㷺㷻㷼㷽㷾㷿㸀㸁㸂㸃㸄㸅㸆㸇㸈㸉㸊㸋㸌㸍㸎㸏㸐㸑㸒㸓㸔㸕㸖㸗㸘㸙㸚㸛㸜㸝㸞㸟㸠㸡㸢㸣㸤㸥㸦㸧㸨㸩㸪㸫㸬㸭㸮㸯㸰㸱㸲㸳㸴㸵㸶㸷㸸㸹㸺㸻㸼㸽㸾㸿㹀㹁㹂㹃㹄㹅㹆㹇㹈㹉㹊㹋㹌㹍㹎㹏㹐㹑㹒㹓㹔㹕㹖㹗㹘㹙㹚㹛㹜㹝㹞㹟㹠㹡㹢㹣㹤㹥㹦㹧㹨㹩㹪㹫㹬㹭㹮㹯㹰㹱㹲㹳㹴㹵㹶㹷㹸㹹㹺㹻㹼㹽㹾㹿㺀㺁㺂㺃㺄㺅㺆㺇㺈㺉㺊㺋㺌㺍㺎㺏㺐㺑㺒㺓㺔㺕㺖㺗㺘㺙㺚㺛㺜㺝㺞㺟㺠㺡㺢㺣㺤㺥㺦㺧㺨㺩㺪㺫㺬㺭㺮㺯㺰㺱㺲㺳㺴㺵㺶㺷㺸㺹㺺㺻㺼㺽㺾㺿㻀㻁㻂㻃㻄㻅㻆㻇㻈㻉㻊㻋㻌㻍㻎㻏㻐㻑㻒㻓㻔㻕㻖㻗㻘㻙㻚㻛㻜㻝㻞㻟㻠㻡㻢㻣㻤㻥㻦㻧㻨㻩㻪㻫㻬㻭㻮㻯㻰㻱㻲㻳㻴㻵㻶㻷㻸㻹㻺㻻㻼㻽㻾㻿㼀㼁㼂㼃㼄㼅㼆㼇㼈㼉㼊㼋㼌㼍㼎㼏㼐㼑㼒㼓㼔㼕㼖㼗㼘㼙㼚㼛㼜㼝㼞㼟㼠㼡㼢㼣㼤㼥㼦㼧㼨㼩㼪㼫㼬㼭㼮㼯㼰㼱㼲㼳㼴㼵㼶㼷㼸㼹㼺㼻㼼㼽㼾㼿㽀㽁㽂㽃㽄㽅㽆㽇㽈㽉㽊㽋㽌㽍㽎㽏㽐㽑㽒㽓㽔㽕㽖㽗㽘㽙㽚㽛㽜㽝㽞㽟㽠㽡㽢㽣㽤㽥㽦㽧㽨㽩㽪㽫㽬㽭㽮㽯㽰㽱㽲㽳㽴㽵㽶㽷㽸㽹㽺㽻㽼㽽㽾㽿㾀㾁㾂㾃㾄㾅㾆㾇㾈㾉㾊㾋㾌㾍㾎㾏㾐㾑㾒㾓㾔㾕㾖㾗㾘㾙㾚㾛㾜㾝㾞㾟㾠㾡㾢㾣㾤㾥㾦㾧㾨㾩㾪㾫㾬㾭㾮㾯㾰㾱㾲㾳㾴㾵㾶㾷㾸㾹㾺㾻㾼㾽㾾㾿㿀㿁㿂㿃㿄㿅㿆㿇㿈㿉㿊㿋㿌㿍㿎㿏㿐㿑㿒㿓㿔㿕㿖㿗㿘㿙㿚㿛㿜㿝㿞㿟㿠㿡㿢㿣㿤㿥㿦㿧㿨㿩㿪㿫㿬㿭㿮㿯㿰㿱㿲㿳㿴㿵㿶㿷㿸㿹㿺㿻㿼㿽㿾㿿䀀䀁䀂䀃䀄䀅䀆䀇䀈䀉䀊䀋䀌䀍䀎䀏䀐䀑䀒䀓䀔䀕䀖䀗䀘䀙䀚䀛䀜䀝䀞䀟䀠䀡䀢䀣䀤䀥䀦䀧䀨䀩䀪䀫䀬䀭䀮䀯䀰䀱䀲䀳䀴䀵䀶䀷䀸䀹䀺䀻䀼䀽䀾䀿䁀䁁䁂䁃䁄䁅䁆䁇䁈䁉䁊䁋䁌䁍䁎䁏䁐䁑䁒䁓䁔䁕䁖䁗䁘䁙䁚䁛䁜䁝䁞䁟䁠䁡䁢䁣䁤䁥䁦䁧䁨䁩䁪䁫䁬䁭䁮䁯䁰䁱䁲䁳䁴䁵䁶䁷䁸䁹䁺䁻䁼䁽䁾䁿䂀䂁䂂䂃䂄䂅䂆䂇䂈䂉䂊䂋䂌䂍䂎䂏䂐䂑䂒䂓䂔䂕䂖䂗䂘䂙䂚䂛䂜䂝䂞䂟䂠䂡䂢䂣䂤䂥䂦䂧䂨䂩䂪䂫䂬䂭䂮䂯䂰䂱䂲䂳䂴䂵䂶䂷䂸䂹䂺䂻䂼䂽䂾䂿䃀䃁䃂䃃䃄䃅䃆䃇䃈䃉䃊䃋䃌䃍䃎䃏䃐䃑䃒䃓䃔䃕䃖䃗䃘䃙䃚䃛䃜䃝䃞䃟䃠䃡䃢䃣䃤䃥䃦䃧䃨䃩䃪䃫䃬䃭䃮䃯䃰䃱䃲䃳䃴䃵䃶䃷䃸䃹䃺䃻䃼䃽䃾䃿䄀䄁䄂䄃䄄䄅䄆䄇䄈䄉䄊䄋䄌䄍䄎䄏䄐䄑䄒䄓䄔䄕䄖䄗䄘䄙䄚䄛䄜䄝䄞䄟䄠䄡䄢䄣䄤䄥䄦䄧䄨䄩䄪䄫䄬䄭䄮䄯䄰䄱䄲䄳䄴䄵䄶䄷䄸䄹䄺䄻䄼䄽䄾䄿䅀䅁䅂䅃䅄䅅䅆䅇䅈䅉䅊䅋䅌䅍䅎䅏䅐䅑䅒䅓䅔䅕䅖䅗䅘䅙䅚䅛䅜䅝䅞䅟䅠䅡䅢䅣䅤䅥䅦䅧䅨䅩䅪䅫䅬䅭䅮䅯䅰䅱䅲䅳䅴䅵䅶䅷䅸䅹䅺䅻䅼䅽䅾䅿䆀䆁䆂䆃䆄䆅䆆䆇䆈䆉䆊䆋䆌䆍䆎䆏䆐䆑䆒䆓䆔䆕䆖䆗䆘䆙䆚䆛䆜䆝䆞䆟䆠䆡䆢䆣䆤䆥䆦䆧䆨䆩䆪䆫䆬䆭䆮䆯䆰䆱䆲䆳䆴䆵䆶䆷䆸䆹䆺䆻䆼䆽䆾䆿䇀䇁䇂䇃䇄䇅䇆䇇䇈䇉䇊䇋䇌䇍䇎䇏䇐䇑䇒䇓䇔䇕䇖䇗䇘䇙䇚䇛䇜䇝䇞䇟䇠䇡䇢䇣䇤䇥䇦䇧䇨䇩䇪䇫䇬䇭䇮䇯䇰䇱䇲䇳䇴䇵䇶䇷䇸䇹䇺䇻䇼䇽䇾䇿䈀䈁䈂䈃䈄䈅䈆䈇䈈䈉䈊䈋䈌䈍䈎䈏䈐䈑䈒䈓䈔䈕䈖䈗䈘䈙䈚䈛䈜䈝䈞䈟䈠䈡䈢䈣䈤䈥䈦䈧䈨䈩䈪䈫䈬䈭䈮䈯䈰䈱䈲䈳䈴䈵䈶䈷䈸䈹䈺䈻䈼䈽䈾䈿䉀䉁䉂䉃䉄䉅䉆䉇䉈䉉䉊䉋䉌䉍䉎䉏䉐䉑䉒䉓䉔䉕䉖䉗䉘䉙䉚䉛䉜䉝䉞䉟䉠䉡䉢䉣䉤䉥䉦䉧䉨䉩䉪䉫䉬䉭䉮䉯䉰䉱䉲䉳䉴䉵䉶䉷䉸䉹䉺䉻䉼䉽䉾䉿䊀䊁䊂䊃䊄䊅䊆䊇䊈䊉䊊䊋䊌䊍䊎䊏䊐䊑䊒䊓䊔䊕䊖䊗䊘䊙䊚䊛䊜䊝䊞䊟䊠䊡䊢䊣䊤䊥䊦䊧䊨䊩䊪䊫䊬䊭䊮䊯䊰䊱䊲䊳䊴䊵䊶䊷䊸䊹䊺䊻䊼䊽䊾䊿䋀䋁䋂䋃䋄䋅䋆䋇䋈䋉䋊䋋䋌䋍䋎䋏䋐䋑䋒䋓䋔䋕䋖䋗䋘䋙䋚䋛䋜䋝䋞䋟䋠䋡䋢䋣䋤䋥䋦䋧䋨䋩䋪䋫䋬䋭䋮䋯䋰䋱䋲䋳䋴䋵䋶䋷䋸䋹䋺䋻䋼䋽䋾䋿䌀䌁䌂䌃䌄䌅䌆䌇䌈䌉䌊䌋䌌䌍䌎䌏䌐䌑䌒䌓䌔䌕䌖䌗䌘䌙䌚䌛䌜䌝䌞䌟䌠䌡䌢䌣䌤䌥䌦䌧䌨䌩䌪䌫䌬䌭䌮䌯䌰䌱䌲䌳䌴䌵䌶䌷䌸䌹䌺䌻䌼䌽䌾䌿䍀䍁䍂䍃䍄䍅䍆䍇䍈䍉䍊䍋䍌䍍䍎䍏䍐䍑䍒䍓䍔䍕䍖䍗䍘䍙䍚䍛䍜䍝䍞䍟䍠䍡䍢䍣䍤䍥䍦䍧䍨䍩䍪䍫䍬䍭䍮䍯䍰䍱䍲䍳䍴䍵䍶䍷䍸䍹䍺䍻䍼䍽䍾䍿䎀䎁䎂䎃䎄䎅䎆䎇䎈䎉䎊䎋䎌䎍䎎䎏䎐䎑䎒䎓䎔䎕䎖䎗䎘䎙䎚䎛䎜䎝䎞䎟䎠䎡䎢䎣䎤䎥䎦䎧䎨䎩䎪䎫䎬䎭䎮䎯䎰䎱䎲䎳䎴䎵䎶䎷䎸䎹䎺䎻䎼䎽䎾䎿䏀䏁䏂䏃䏄䏅䏆䏇䏈䏉䏊䏋䏌䏍䏎䏏䏐䏑䏒䏓䏔䏕䏖䏗䏘䏙䏚䏛䏜䏝䏞䏟䏠䏡䏢䏣䏤䏥䏦䏧䏨䏩䏪䏫䏬䏭䏮䏯䏰䏱䏲䏳䏴䏵䏶䏷䏸䏹䏺䏻䏼䏽䏾䏿䐀䐁䐂䐃䐄䐅䐆䐇䐈䐉䐊䐋䐌䐍䐎䐏䐐䐑䐒䐓䐔䐕䐖䐗䐘䐙䐚䐛䐜䐝䐞䐟䐠䐡䐢䐣䐤䐥䐦䐧䐨䐩䐪䐫䐬䐭䐮䐯䐰䐱䐲䐳䐴䐵䐶䐷䐸䐹䐺䐻䐼䐽䐾䐿䑀䑁䑂䑃䑄䑅䑆䑇䑈䑉䑊䑋䑌䑍䑎䑏䑐䑑䑒䑓䑔䑕䑖䑗䑘䑙䑚䑛䑜䑝䑞䑟䑠䑡䑢䑣䑤䑥䑦䑧䑨䑩䑪䑫䑬䑭䑮䑯䑰䑱䑲䑳䑴䑵䑶䑷䑸䑹䑺䑻䑼䑽䑾䑿䒀䒁䒂䒃䒄䒅䒆䒇䒈䒉䒊䒋䒌䒍䒎䒏䒐䒑䒒䒓䒔䒕䒖䒗䒘䒙䒚䒛䒜䒝䒞䒟䒠䒡䒢䒣䒤䒥䒦䒧䒨䒩䒪䒫䒬䒭䒮䒯䒰䒱䒲䒳䒴䒵䒶䒷䒸䒹䒺䒻䒼䒽䒾䒿䓀䓁䓂䓃䓄䓅䓆䓇䓈䓉䓊䓋䓌䓍䓎䓏䓐䓑䓒䓓䓔䓕䓖䓗䓘䓙䓚䓛䓜䓝䓞䓟䓠䓡䓢䓣䓤䓥䓦䓧䓨䓩䓪䓫䓬䓭䓮䓯䓰䓱䓲䓳䓴䓵䓶䓷䓸䓹䓺䓻䓼䓽䓾䓿䔀䔁䔂䔃䔄䔅䔆䔇䔈䔉䔊䔋䔌䔍䔎䔏䔐䔑䔒䔓䔔䔕䔖䔗䔘䔙䔚䔛䔜䔝䔞䔟䔠䔡䔢䔣䔤䔥䔦䔧䔨䔩䔪䔫䔬䔭䔮䔯䔰䔱䔲䔳䔴䔵䔶䔷䔸䔹䔺䔻䔼䔽䔾䔿䕀䕁䕂䕃䕄䕅䕆䕇䕈䕉䕊䕋䕌䕍䕎䕏䕐䕑䕒䕓䕔䕕䕖䕗䕘䕙䕚䕛䕜䕝䕞䕟䕠䕡䕢䕣䕤䕥䕦䕧䕨䕩䕪䕫䕬䕭䕮䕯䕰䕱䕲䕳䕴䕵䕶䕷䕸䕹䕺䕻䕼䕽䕾䕿䖀䖁䖂䖃䖄䖅䖆䖇䖈䖉䖊䖋䖌䖍䖎䖏䖐䖑䖒䖓䖔䖕䖖䖗䖘䖙䖚䖛䖜䖝䖞䖟䖠䖡䖢䖣䖤䖥䖦䖧䖨䖩䖪䖫䖬䖭䖮䖯䖰䖱䖲䖳䖴䖵䖶䖷䖸䖹䖺䖻䖼䖽䖾䖿䗀䗁䗂䗃䗄䗅䗆䗇䗈䗉䗊䗋䗌䗍䗎䗏䗐䗑䗒䗓䗔䗕䗖䗗䗘䗙䗚䗛䗜䗝䗞䗟䗠䗡䗢䗣䗤䗥䗦䗧䗨䗩䗪䗫䗬䗭䗮䗯䗰䗱䗲䗳䗴䗵䗶䗷䗸䗹䗺䗻䗼䗽䗾䗿䘀䘁䘂䘃䘄䘅䘆䘇䘈䘉䘊䘋䘌䘍䘎䘏䘐䘑䘒䘓䘔䘕䘖䘗䘘䘙䘚䘛䘜䘝䘞䘟䘠䘡䘢䘣䘤䘥䘦䘧䘨䘩䘪䘫䘬䘭䘮䘯䘰䘱䘲䘳䘴䘵䘶䘷䘸䘹䘺䘻䘼䘽䘾䘿䙀䙁䙂䙃䙄䙅䙆䙇䙈䙉䙊䙋䙌䙍䙎䙏䙐䙑䙒䙓䙔䙕䙖䙗䙘䙙䙚䙛䙜䙝䙞䙟䙠䙡䙢䙣䙤䙥䙦䙧䙨䙩䙪䙫䙬䙭䙮䙯䙰䙱䙲䙳䙴䙵䙶䙷䙸䙹䙺䙻䙼䙽䙾䙿䚀䚁䚂䚃䚄䚅䚆䚇䚈䚉䚊䚋䚌䚍䚎䚏䚐䚑䚒䚓䚔䚕䚖䚗䚘䚙䚚䚛䚜䚝䚞䚟䚠䚡䚢䚣䚤䚥䚦䚧䚨䚩䚪䚫䚬䚭䚮䚯䚰䚱䚲䚳䚴䚵䚶䚷䚸䚹䚺䚻䚼䚽䚾䚿䛀䛁䛂䛃䛄䛅䛆䛇䛈䛉䛊䛋䛌䛍䛎䛏䛐䛑䛒䛓䛔䛕䛖䛗䛘䛙䛚䛛䛜䛝䛞䛟䛠䛡䛢䛣䛤䛥䛦䛧䛨䛩䛪䛫䛬䛭䛮䛯䛰䛱䛲䛳䛴䛵䛶䛷䛸䛹䛺䛻䛼䛽䛾䛿䜀䜁䜂䜃䜄䜅䜆䜇䜈䜉䜊䜋䜌䜍䜎䜏䜐䜑䜒䜓䜔䜕䜖䜗䜘䜙䜚䜛䜜䜝䜞䜟䜠䜡䜢䜣䜤䜥䜦䜧䜨䜩䜪䜫䜬䜭䜮䜯䜰䜱䜲䜳䜴䜵䜶䜷䜸䜹䜺䜻䜼䜽䜾䜿䝀䝁䝂䝃䝄䝅䝆䝇䝈䝉䝊䝋䝌䝍䝎䝏䝐䝑䝒䝓䝔䝕䝖䝗䝘䝙䝚䝛䝜䝝䝞䝟䝠䝡䝢䝣䝤䝥䝦䝧䝨䝩䝪䝫䝬䝭䝮䝯䝰䝱䝲䝳䝴䝵䝶䝷䝸䝹䝺䝻䝼䝽䝾䝿䞀䞁䞂䞃䞄䞅䞆䞇䞈䞉䞊䞋䞌䞍䞎䞏䞐䞑䞒䞓䞔䞕䞖䞗䞘䞙䞚䞛䞜䞝䞞䞟䞠䞡䞢䞣䞤䞥䞦䞧䞨䞩䞪䞫䞬䞭䞮䞯䞰䞱䞲䞳䞴䞵䞶䞷䞸䞹䞺䞻䞼䞽䞾䞿䟀䟁䟂䟃䟄䟅䟆䟇䟈䟉䟊䟋䟌䟍䟎䟏䟐䟑䟒䟓䟔䟕䟖䟗䟘䟙䟚䟛䟜䟝䟞䟟䟠䟡䟢䟣䟤䟥䟦䟧䟨䟩䟪䟫䟬䟭䟮䟯䟰䟱䟲䟳䟴䟵䟶䟷䟸䟹䟺䟻䟼䟽䟾䟿䠀䠁䠂䠃䠄䠅䠆䠇䠈䠉䠊䠋䠌䠍䠎䠏䠐䠑䠒䠓䠔䠕䠖䠗䠘䠙䠚䠛䠜䠝䠞䠟䠠䠡䠢䠣䠤䠥䠦䠧䠨䠩䠪䠫䠬䠭䠮䠯䠰䠱䠲䠳䠴䠵䠶䠷䠸䠹䠺䠻䠼䠽䠾䠿䡀䡁䡂䡃䡄䡅䡆䡇䡈䡉䡊䡋䡌䡍䡎䡏䡐䡑䡒䡓䡔䡕䡖䡗䡘䡙䡚䡛䡜䡝䡞䡟䡠䡡䡢䡣䡤䡥䡦䡧䡨䡩䡪䡫䡬䡭䡮䡯䡰䡱䡲䡳䡴䡵䡶䡷䡸䡹䡺䡻䡼䡽䡾䡿䢀䢁䢂䢃䢄䢅䢆䢇䢈䢉䢊䢋䢌䢍䢎䢏䢐䢑䢒䢓䢔䢕䢖䢗䢘䢙䢚䢛䢜䢝䢞䢟䢠䢡䢢䢣䢤䢥䢦䢧䢨䢩䢪䢫䢬䢭䢮䢯䢰䢱䢲䢳䢴䢵䢶䢷䢸䢹䢺䢻䢼䢽䢾䢿䣀䣁䣂䣃䣄䣅䣆䣇䣈䣉䣊䣋䣌䣍䣎䣏䣐䣑䣒䣓䣔䣕䣖䣗䣘䣙䣚䣛䣜䣝䣞䣟䣠䣡䣢䣣䣤䣥䣦䣧䣨䣩䣪䣫䣬䣭䣮䣯䣰䣱䣲䣳䣴䣵䣶䣷䣸䣹䣺䣻䣼䣽䣾䣿䤀䤁䤂䤃䤄䤅䤆䤇䤈䤉䤊䤋䤌䤍䤎䤏䤐䤑䤒䤓䤔䤕䤖䤗䤘䤙䤚䤛䤜䤝䤞䤟䤠䤡䤢䤣䤤䤥䤦䤧䤨䤩䤪䤫䤬䤭䤮䤯䤰䤱䤲䤳䤴䤵䤶䤷䤸䤹䤺䤻䤼䤽䤾䤿䥀䥁䥂䥃䥄䥅䥆䥇䥈䥉䥊䥋䥌䥍䥎䥏䥐䥑䥒䥓䥔䥕䥖䥗䥘䥙䥚䥛䥜䥝䥞䥟䥠䥡䥢䥣䥤䥥䥦䥧䥨䥩䥪䥫䥬䥭䥮䥯䥰䥱䥲䥳䥴䥵䥶䥷䥸䥹䥺䥻䥼䥽䥾䥿䦀䦁䦂䦃䦄䦅䦆䦇䦈䦉䦊䦋䦌䦍䦎䦏䦐䦑䦒䦓䦔䦕䦖䦗䦘䦙䦚䦛䦜䦝䦞䦟䦠䦡䦢䦣䦤䦥䦦䦧䦨䦩䦪䦫䦬䦭䦮䦯䦰䦱䦲䦳䦴䦵䦶䦷䦸䦹䦺䦻䦼䦽䦾䦿䧀䧁䧂䧃䧄䧅䧆䧇䧈䧉䧊䧋䧌䧍䧎䧏䧐䧑䧒䧓䧔䧕䧖䧗䧘䧙䧚䧛䧜䧝䧞䧟䧠䧡䧢䧣䧤䧥䧦䧧䧨䧩䧪䧫䧬䧭䧮䧯䧰䧱䧲䧳䧴䧵䧶䧷䧸䧹䧺䧻䧼䧽䧾䧿䨀䨁䨂䨃䨄䨅䨆䨇䨈䨉䨊䨋䨌䨍䨎䨏䨐䨑䨒䨓䨔䨕䨖䨗䨘䨙䨚䨛䨜䨝䨞䨟䨠䨡䨢䨣䨤䨥䨦䨧䨨䨩䨪䨫䨬䨭䨮䨯䨰䨱䨲䨳䨴䨵䨶䨷䨸䨹䨺䨻䨼䨽䨾䨿䩀䩁䩂䩃䩄䩅䩆䩇䩈䩉䩊䩋䩌䩍䩎䩏䩐䩑䩒䩓䩔䩕䩖䩗䩘䩙䩚䩛䩜䩝䩞䩟䩠䩡䩢䩣䩤䩥䩦䩧䩨䩩䩪䩫䩬䩭䩮䩯䩰䩱䩲䩳䩴䩵䩶䩷䩸䩹䩺䩻䩼䩽䩾䩿䪀䪁䪂䪃䪄䪅䪆䪇䪈䪉䪊䪋䪌䪍䪎䪏䪐䪑䪒䪓䪔䪕䪖䪗䪘䪙䪚䪛䪜䪝䪞䪟䪠䪡䪢䪣䪤䪥䪦䪧䪨䪩䪪䪫䪬䪭䪮䪯䪰䪱䪲䪳䪴䪵䪶䪷䪸䪹䪺䪻䪼䪽䪾䪿䫀䫁䫂䫃䫄䫅䫆䫇䫈䫉䫊䫋䫌䫍䫎䫏䫐䫑䫒䫓䫔䫕䫖䫗䫘䫙䫚䫛䫜䫝䫞䫟䫠䫡䫢䫣䫤䫥䫦䫧䫨䫩䫪䫫䫬䫭䫮䫯䫰䫱䫲䫳䫴䫵䫶䫷䫸䫹䫺䫻䫼䫽䫾䫿䬀䬁䬂䬃䬄䬅䬆䬇䬈䬉䬊䬋䬌䬍䬎䬏䬐䬑䬒䬓䬔䬕䬖䬗䬘䬙䬚䬛䬜䬝䬞䬟䬠䬡䬢䬣䬤䬥䬦䬧䬨䬩䬪䬫䬬䬭䬮䬯䬰䬱䬲䬳䬴䬵䬶䬷䬸䬹䬺䬻䬼䬽䬾䬿䭀䭁䭂䭃䭄䭅䭆䭇䭈䭉䭊䭋䭌䭍䭎䭏䭐䭑䭒䭓䭔䭕䭖䭗䭘䭙䭚䭛䭜䭝䭞䭟䭠䭡䭢䭣䭤䭥䭦䭧䭨䭩䭪䭫䭬䭭䭮䭯䭰䭱䭲䭳䭴䭵䭶䭷䭸䭹䭺䭻䭼䭽䭾䭿䮀䮁䮂䮃䮄䮅䮆䮇䮈䮉䮊䮋䮌䮍䮎䮏䮐䮑䮒䮓䮔䮕䮖䮗䮘䮙䮚䮛䮜䮝䮞䮟䮠䮡䮢䮣䮤䮥䮦䮧䮨䮩䮪䮫䮬䮭䮮䮯䮰䮱䮲䮳䮴䮵䮶䮷䮸䮹䮺䮻䮼䮽䮾䮿䯀䯁䯂䯃䯄䯅䯆䯇䯈䯉䯊䯋䯌䯍䯎䯏䯐䯑䯒䯓䯔䯕䯖䯗䯘䯙䯚䯛䯜䯝䯞䯟䯠䯡䯢䯣䯤䯥䯦䯧䯨䯩䯪䯫䯬䯭䯮䯯䯰䯱䯲䯳䯴䯵䯶䯷䯸䯹䯺䯻䯼䯽䯾䯿䰀䰁䰂䰃䰄䰅䰆䰇䰈䰉䰊䰋䰌䰍䰎䰏䰐䰑䰒䰓䰔䰕䰖䰗䰘䰙䰚䰛䰜䰝䰞䰟䰠䰡䰢䰣䰤䰥䰦䰧䰨䰩䰪䰫䰬䰭䰮䰯䰰䰱䰲䰳䰴䰵䰶䰷䰸䰹䰺䰻䰼䰽䰾䰿䱀䱁䱂䱃䱄䱅䱆䱇䱈䱉䱊䱋䱌䱍䱎䱏䱐䱑䱒䱓䱔䱕䱖䱗䱘䱙䱚䱛䱜䱝䱞䱟䱠䱡䱢䱣䱤䱥䱦䱧䱨䱩䱪䱫䱬䱭䱮䱯䱰䱱䱲䱳䱴䱵䱶䱷䱸䱹䱺䱻䱼䱽䱾䱿䲀䲁䲂䲃䲄䲅䲆䲇䲈䲉䲊䲋䲌䲍䲎䲏䲐䲑䲒䲓䲔䲕䲖䲗䲘䲙䲚䲛䲜䲝䲞䲟䲠䲡䲢䲣䲤䲥䲦䲧䲨䲩䲪䲫䲬䲭䲮䲯䲰䲱䲲䲳䲴䲵䲶䲷䲸䲹䲺䲻䲼䲽䲾䲿䳀䳁䳂䳃䳄䳅䳆䳇䳈䳉䳊䳋䳌䳍䳎䳏䳐䳑䳒䳓䳔䳕䳖䳗䳘䳙䳚䳛䳜䳝䳞䳟䳠䳡䳢䳣䳤䳥䳦䳧䳨䳩䳪䳫䳬䳭䳮䳯䳰䳱䳲䳳䳴䳵䳶䳷䳸䳹䳺䳻䳼䳽䳾䳿䴀䴁䴂䴃䴄䴅䴆䴇䴈䴉䴊䴋䴌䴍䴎䴏䴐䴑䴒䴓䴔䴕䴖䴗䴘䴙䴚䴛䴜䴝䴞䴟䴠䴡䴢䴣䴤䴥䴦䴧䴨䴩䴪䴫䴬䴭䴮䴯䴰䴱䴲䴳䴴䴵䴶䴷䴸䴹䴺䴻䴼䴽䴾䴿䵀䵁䵂䵃䵄䵅䵆䵇䵈䵉䵊䵋䵌䵍䵎䵏䵐䵑䵒䵓䵔䵕䵖䵗䵘䵙䵚䵛䵜䵝䵞䵟䵠䵡䵢䵣䵤䵥䵦䵧䵨䵩䵪䵫䵬䵭䵮䵯䵰䵱䵲䵳䵴䵵䵶䵷䵸䵹䵺䵻䵼䵽䵾䵿䶀䶁䶂䶃䶄䶅䶆䶇䶈䶉䶊䶋䶌䶍䶎䶏䶐䶑䶒䶓䶔䶕䶖䶗䶘䶙䶚䶛䶜䶝䶞䶟䶠䶡䶢䶣䶤䶥䶦䶧䶨䶩䶪䶫䶬䶭䶮䶯䶰䶱䶲䶳䶴䶵䷀䷁䷂䷃䷄䷅䷆䷇䷈䷉䷊䷋䷌䷍䷎䷏䷐䷑䷒䷓䷔䷕䷖䷗䷘䷙䷚䷛䷜䷝䷞䷟䷠䷡䷢䷣䷤䷥䷦䷧䷨䷩䷪䷫䷬䷭䷮䷯䷰䷱䷲䷳䷴䷵䷶䷷䷸䷹䷺䷻䷼䷽䷾䷿一丁丂七丄丅丆万丈三上下丌不与丏丐丑丒专且丕世丗丘丙业丛东丝丞丟丠両丢丣两严並丧丨丩个丫丬中丮丯丰丱串丳临丵丶丷丸丹为主丼丽举丿乀乁乂乃乄久乆乇么义乊之乌乍乎乏乐乑乒乓乔乕乖乗乘乙乚乛乜九乞也习乡乢乣乤乥书乧乨乩乪乫乬乭乮乯买乱乲乳乴乵乶乷乸乹乺乻乼乽乾乿亀亁亂亃亄亅了亇予争亊事二亍于亏亐云互亓五井亖亗亘亙亚些亜亝亞亟亠亡亢亣交亥亦产亨亩亪享京亭亮亯亰亱亲亳亴亵亶亷亸亹人亻亼亽亾亿什仁仂仃仄仅仆仇仈仉今介仌仍从仏仐仑仒仓仔仕他仗付仙仚仛仜仝仞仟仠仡仢代令以仦仧仨仩仪仫们仭仮仯仰仱仲仳仴仵件价仸仹仺任仼份仾仿伀企伂伃伄伅伆伇伈伉伊伋伌伍伎伏伐休伒伓伔伕伖众优伙会伛伜伝伞伟传伡伢伣伤伥伦伧伨伩伪伫伬伭伮伯估伱伲伳伴伵伶伷伸伹伺伻似伽伾伿佀佁佂佃佄佅但佇佈佉佊佋佌位低住佐佑佒体佔何佖佗佘余佚佛作佝佞佟你佡佢佣佤佥佦佧佨佩佪佫佬佭佮佯佰佱佲佳佴併佶佷佸佹佺佻佼佽佾使侀侁侂侃侄侅來侇侈侉侊例侌侍侎侏侐侑侒侓侔侕侖侗侘侙侚供侜依侞侟侠価侢侣侤侥侦侧侨侩侪侫侬侭侮侯侰侱侲侳侴侵侶侷侸侹侺侻侼侽侾便俀俁係促俄俅俆俇俈俉俊俋俌俍俎俏俐俑俒俓俔俕俖俗俘俙俚俛俜保俞俟俠信俢俣俤俥俦俧俨俩俪俫俬俭修俯俰俱俲俳俴俵俶俷俸俹俺俻俼俽俾俿倀倁倂倃倄倅倆倇倈倉倊個倌倍倎倏倐們倒倓倔倕倖倗倘候倚倛倜倝倞借倠倡倢倣値倥倦倧倨倩倪倫倬倭倮倯倰倱倲倳倴倵倶倷倸倹债倻值倽倾倿偀偁偂偃偄偅偆假偈偉偊偋偌偍偎偏偐偑偒偓偔偕偖偗偘偙做偛停偝偞偟偠偡偢偣偤健偦偧偨偩偪偫偬偭偮偯偰偱偲偳側偵偶偷偸偹偺偻偼偽偾偿傀傁傂傃傄傅傆傇傈傉傊傋傌傍傎傏傐傑傒傓傔傕傖傗傘備傚傛傜傝傞傟傠傡傢傣傤傥傦傧储傩傪傫催傭傮傯傰傱傲傳傴債傶傷傸傹傺傻傼傽傾傿僀僁僂僃僄僅僆僇僈僉僊僋僌働僎像僐僑僒僓僔僕僖僗僘僙僚僛僜僝僞僟僠僡僢僣僤僥僦僧僨僩僪僫僬僭僮僯僰僱僲僳僴僵僶僷僸價僺僻僼僽僾僿儀儁儂儃億儅儆儇儈儉儊儋儌儍儎儏儐儑儒儓儔儕儖儗儘儙儚儛儜儝儞償儠儡儢儣儤儥儦儧儨儩優儫儬儭儮儯儰儱儲儳儴儵儶儷儸儹儺儻儼儽儾儿兀允兂元兄充兆兇先光兊克兌免兎兏児兑兒兓兔兕兖兗兘兙党兛兜兝兞兟兠兡兢兣兤入兦內全兩兪八公六兮兯兰共兲关兴兵其具典兹兺养兼兽兾兿冀冁冂冃冄内円冇冈冉冊冋册再冎冏冐冑冒冓冔冕冖冗冘写冚军农冝冞冟冠冡冢冣冤冥冦冧冨冩冪冫冬冭冮冯冰冱冲决冴况冶冷冸冹冺冻冼冽冾冿净凁凂凃凄凅准凇凈凉凊凋凌凍凎减凐凑凒凓凔凕凖凗凘凙凚凛凜凝凞凟几凡凢凣凤凥処凧凨凩凪凫凬凭凮凯凰凱凲凳凴凵凶凷凸凹出击凼函凾凿刀刁刂刃刄刅分切刈刉刊刋刌刍刎刏刐刑划刓刔刕刖列刘则刚创刜初刞刟删刡刢刣判別刦刧刨利刪别刬刭刮刯到刱刲刳刴刵制刷券刹刺刻刼刽刾刿剀剁剂剃剄剅剆則剈剉削剋剌前剎剏剐剑剒剓剔剕剖剗剘剙剚剛剜剝剞剟剠剡剢剣剤剥剦剧剨剩剪剫剬剭剮副剰剱割剳剴創剶剷剸剹剺剻剼剽剾剿劀劁劂劃劄劅劆劇劈劉劊劋劌劍劎劏劐劑劒劓劔劕劖劗劘劙劚力劜劝办功加务劢劣劤劥劦劧动助努劫劬劭劮劯劰励劲劳労劵劶劷劸効劺劻劼劽劾势勀勁勂勃勄勅勆勇勈勉勊勋勌勍勎勏勐勑勒勓勔動勖勗勘務勚勛勜勝勞募勠勡勢勣勤勥勦勧勨勩勪勫勬勭勮勯勰勱勲勳勴勵勶勷勸勹勺勻勼勽勾勿匀匁匂匃匄包匆匇匈匉匊匋匌匍匎匏匐匑匒匓匔匕化北匘匙匚匛匜匝匞匟匠匡匢匣匤匥匦匧匨匩匪匫匬匭匮匯匰匱匲匳匴匵匶匷匸匹区医匼匽匾匿區十卂千卄卅卆升午卉半卋卌卍华协卐卑卒卓協单卖南単卙博卛卜卝卞卟占卡卢卣卤卥卦卧卨卩卪卫卬卭卮卯印危卲即却卵卶卷卸卹卺卻卼卽卾卿厀厁厂厃厄厅历厇厈厉厊压厌厍厎厏厐厑厒厓厔厕厖厗厘厙厚厛厜厝厞原厠厡厢厣厤厥厦厧厨厩厪厫厬厭厮厯厰厱厲厳厴厵厶厷厸厹厺去厼厽厾县叀叁参參叄叅叆叇又叉及友双反収叏叐发叒叓叔叕取受变叙叚叛叜叝叞叟叠叡叢口古句另叧叨叩只叫召叭叮可台叱史右叴叵叶号司叹叺叻叼叽叾叿吀吁吂吃各吅吆吇合吉吊吋同名后吏吐向吒吓吔吕吖吗吘吙吚君吜吝吞吟吠吡吢吣吤吥否吧吨吩吪含听吭吮启吰吱吲吳吴吵吶吷吸吹吺吻吼吽吾吿呀呁呂呃呄呅呆呇呈呉告呋呌呍呎呏呐呑呒呓呔呕呖呗员呙呚呛呜呝呞呟呠呡呢呣呤呥呦呧周呩呪呫呬呭呮呯呰呱呲味呴呵呶呷呸呹呺呻呼命呾呿咀咁咂咃咄咅咆咇咈咉咊咋和咍咎咏咐咑咒咓咔咕咖咗咘咙咚咛咜咝咞咟咠咡咢咣咤咥咦咧咨咩咪咫咬咭咮咯咰咱咲咳咴咵咶咷咸咹咺咻咼咽咾咿哀品哂哃哄哅哆哇哈哉哊哋哌响哎哏哐哑哒哓哔哕哖哗哘哙哚哛哜哝哞哟哠員哢哣哤哥哦哧哨哩哪哫哬哭哮哯哰哱哲哳哴哵哶哷哸哹哺哻哼哽哾哿唀唁唂唃唄唅唆唇唈唉唊唋唌唍唎唏唐唑唒唓唔唕唖唗唘唙唚唛唜唝唞唟唠唡唢唣唤唥唦唧唨唩唪唫唬唭售唯唰唱唲唳唴唵唶唷唸唹唺唻唼唽唾唿啀啁啂啃啄啅商啇啈啉啊啋啌啍啎問啐啑啒啓啔啕啖啗啘啙啚啛啜啝啞啟啠啡啢啣啤啥啦啧啨啩啪啫啬啭啮啯啰啱啲啳啴啵啶啷啸啹啺啻啼啽啾啿喀喁喂喃善喅喆喇喈喉喊喋喌喍喎喏喐喑喒喓喔喕喖喗喘喙喚喛喜喝喞喟喠喡喢喣喤喥喦喧喨喩喪喫喬喭單喯喰喱喲喳喴喵営喷喸喹喺喻喼喽喾喿嗀嗁嗂嗃嗄嗅嗆嗇嗈嗉嗊嗋嗌嗍嗎嗏嗐嗑嗒嗓嗔嗕嗖嗗嗘嗙嗚嗛嗜嗝嗞嗟嗠嗡嗢嗣嗤嗥嗦嗧嗨嗩嗪嗫嗬嗭嗮嗯嗰嗱嗲嗳嗴嗵嗶嗷嗸嗹嗺嗻嗼嗽嗾嗿嘀嘁嘂嘃嘄嘅嘆嘇嘈嘉嘊嘋嘌嘍嘎嘏嘐嘑嘒嘓嘔嘕嘖嘗嘘嘙嘚嘛嘜嘝嘞嘟嘠嘡嘢嘣嘤嘥嘦嘧嘨嘩嘪嘫嘬嘭嘮嘯嘰嘱嘲嘳嘴嘵嘶嘷嘸嘹嘺嘻嘼嘽嘾嘿噀噁噂噃噄噅噆噇噈噉噊噋噌噍噎噏噐噑噒噓噔噕噖噗噘噙噚噛噜噝噞噟噠噡噢噣噤噥噦噧器噩噪噫噬噭噮噯噰噱噲噳噴噵噶噷噸噹噺噻噼噽噾噿嚀嚁嚂嚃嚄嚅嚆嚇嚈嚉嚊嚋嚌嚍嚎嚏嚐嚑嚒嚓嚔嚕嚖嚗嚘嚙嚚嚛嚜嚝嚞嚟嚠嚡嚢嚣嚤嚥嚦嚧嚨嚩嚪嚫嚬嚭嚮嚯嚰嚱嚲嚳嚴嚵嚶嚷嚸嚹嚺嚻嚼嚽嚾嚿囀囁囂囃囄囅囆囇囈囉囊囋囌囍囎囏囐囑囒囓囔囕囖囗囘囙囚四囜囝回囟因囡团団囤囥囦囧囨囩囪囫囬园囮囯困囱囲図围囵囶囷囸囹固囻囼国图囿圀圁圂圃圄圅圆圇圈圉圊國圌圍圎圏圐圑園圓圔圕圖圗團圙圚圛圜圝圞土圠圡圢圣圤圥圦圧在圩圪圫圬圭圮圯地圱圲圳圴圵圶圷圸圹场圻圼圽圾圿址坁坂坃坄坅坆均坈坉坊坋坌坍坎坏坐坑坒坓坔坕坖块坘坙坚坛坜坝坞坟坠坡坢坣坤坥坦坧坨坩坪坫坬坭坮坯坰坱坲坳坴坵坶坷坸坹坺坻坼坽坾坿垀垁垂垃垄垅垆垇垈垉垊型垌垍垎垏垐垑垒垓垔垕垖垗垘垙垚垛垜垝垞垟垠垡垢垣垤垥垦垧垨垩垪垫垬垭垮垯垰垱垲垳垴垵垶垷垸垹垺垻垼垽垾垿埀埁埂埃埄埅埆埇埈埉埊埋埌埍城埏埐埑埒埓埔埕埖埗埘埙埚埛埜埝埞域埠埡埢埣埤埥埦埧埨埩埪埫埬埭埮埯埰埱埲埳埴埵埶執埸培基埻埼埽埾埿堀堁堂堃堄堅堆堇堈堉堊堋堌堍堎堏堐堑堒堓堔堕堖堗堘堙堚堛堜堝堞堟堠堡堢堣堤堥堦堧堨堩堪堫堬堭堮堯堰報堲堳場堵堶堷堸堹堺堻堼堽堾堿塀塁塂塃塄塅塆塇塈塉塊塋塌塍塎塏塐塑塒塓塔塕塖塗塘塙塚塛塜塝塞塟塠塡塢塣塤塥塦塧塨塩塪填塬塭塮塯塰塱塲塳塴塵塶塷塸塹塺塻塼塽塾塿墀墁墂境墄墅墆墇墈墉墊墋墌墍墎墏墐墑墒墓墔墕墖増墘墙墚墛墜墝增墟墠墡墢墣墤墥墦墧墨墩墪墫墬墭墮墯墰墱墲墳墴墵墶墷墸墹墺墻墼墽墾墿壀壁壂壃壄壅壆壇壈壉壊壋壌壍壎壏壐壑壒壓壔壕壖壗壘壙壚壛壜壝壞壟壠壡壢壣壤壥壦壧壨壩壪士壬壭壮壯声壱売壳壴壵壶壷壸壹壺壻壼壽壾壿夀夁夂夃处夅夆备夈変夊夋夌复夎夏夐夑夒夓夔夕外夗夘夙多夛夜夝夞够夠夡夢夣夤夥夦大夨天太夫夬夭央夯夰失夲夳头夵夶夷夸夹夺夻夼夽夾夿奀奁奂奃奄奅奆奇奈奉奊奋奌奍奎奏奐契奒奓奔奕奖套奘奙奚奛奜奝奞奟奠奡奢奣奤奥奦奧奨奩奪奫奬奭奮奯奰奱奲女奴奵奶奷奸她奺奻奼好奾奿妀妁如妃妄妅妆妇妈妉妊妋妌妍妎妏妐妑妒妓妔妕妖妗妘妙妚妛妜妝妞妟妠妡妢妣妤妥妦妧妨妩妪妫妬妭妮妯妰妱妲妳妴妵妶妷妸妹妺妻妼妽妾妿姀姁姂姃姄姅姆姇姈姉姊始姌姍姎姏姐姑姒姓委姕姖姗姘姙姚姛姜姝姞姟姠姡姢姣姤姥姦姧姨姩姪姫姬姭姮姯姰姱姲姳姴姵姶姷姸姹姺姻姼姽姾姿娀威娂娃娄娅娆娇娈娉娊娋娌娍娎娏娐娑娒娓娔娕娖娗娘娙娚娛娜娝娞娟娠娡娢娣娤娥娦娧娨娩娪娫娬娭娮娯娰娱娲娳娴娵娶娷娸娹娺娻娼娽娾娿婀婁婂婃婄婅婆婇婈婉婊婋婌婍婎婏婐婑婒婓婔婕婖婗婘婙婚婛婜婝婞婟婠婡婢婣婤婥婦婧婨婩婪婫婬婭婮婯婰婱婲婳婴婵婶婷婸婹婺婻婼婽婾婿媀媁媂媃媄媅媆媇媈媉媊媋媌媍媎媏媐媑媒媓媔媕媖媗媘媙媚媛媜媝媞媟媠媡媢媣媤媥媦媧媨媩媪媫媬媭媮媯媰媱媲媳媴媵媶媷媸媹媺媻媼媽媾媿嫀嫁嫂嫃嫄嫅嫆嫇嫈嫉嫊嫋嫌嫍嫎嫏嫐嫑嫒嫓嫔嫕嫖嫗嫘嫙嫚嫛嫜嫝嫞嫟嫠嫡嫢嫣嫤嫥嫦嫧嫨嫩嫪嫫嫬嫭嫮嫯嫰嫱嫲嫳嫴嫵嫶嫷嫸嫹嫺嫻嫼嫽嫾嫿嬀嬁嬂嬃嬄嬅嬆嬇嬈嬉嬊嬋嬌嬍嬎嬏嬐嬑嬒嬓嬔嬕嬖嬗嬘嬙嬚嬛嬜嬝嬞嬟嬠嬡嬢嬣嬤嬥嬦嬧嬨嬩嬪嬫嬬嬭嬮嬯嬰嬱嬲嬳嬴嬵嬶嬷嬸嬹嬺嬻嬼嬽嬾嬿孀孁孂孃孄孅孆孇孈孉孊孋孌孍孎孏子孑孒孓孔孕孖字存孙孚孛孜孝孞孟孠孡孢季孤孥学孧孨孩孪孫孬孭孮孯孰孱孲孳孴孵孶孷學孹孺孻孼孽孾孿宀宁宂它宄宅宆宇守安宊宋完宍宎宏宐宑宒宓宔宕宖宗官宙定宛宜宝实実宠审客宣室宥宦宧宨宩宪宫宬宭宮宯宰宱宲害宴宵家宷宸容宺宻宼宽宾宿寀寁寂寃寄寅密寇寈寉寊寋富寍寎寏寐寑寒寓寔寕寖寗寘寙寚寛寜寝寞察寠寡寢寣寤寥實寧寨審寪寫寬寭寮寯寰寱寲寳寴寵寶寷寸对寺寻导寽対寿尀封専尃射尅将將專尉尊尋尌對導小尐少尒尓尔尕尖尗尘尙尚尛尜尝尞尟尠尡尢尣尤尥尦尧尨尩尪尫尬尭尮尯尰就尲尳尴尵尶尷尸尹尺尻尼尽尾尿局屁层屃屄居屆屇屈屉届屋屌屍屎屏屐屑屒屓屔展屖屗屘屙屚屛屜屝属屟屠屡屢屣層履屦屧屨屩屪屫屬屭屮屯屰山屲屳屴屵屶屷屸屹屺屻屼屽屾屿岀岁岂岃岄岅岆岇岈岉岊岋岌岍岎岏岐岑岒岓岔岕岖岗岘岙岚岛岜岝岞岟岠岡岢岣岤岥岦岧岨岩岪岫岬岭岮岯岰岱岲岳岴岵岶岷岸岹岺岻岼岽岾岿峀峁峂峃峄峅峆峇峈峉峊峋峌峍峎峏峐峑峒峓峔峕峖峗峘峙峚峛峜峝峞峟峠峡峢峣峤峥峦峧峨峩峪峫峬峭峮峯峰峱峲峳峴峵島峷峸峹峺峻峼峽峾峿崀崁崂崃崄崅崆崇崈崉崊崋崌崍崎崏崐崑崒崓崔崕崖崗崘崙崚崛崜崝崞崟崠崡崢崣崤崥崦崧崨崩崪崫崬崭崮崯崰崱崲崳崴崵崶崷崸崹崺崻崼崽崾崿嵀嵁嵂嵃嵄嵅嵆嵇嵈嵉嵊嵋嵌嵍嵎嵏嵐嵑嵒嵓嵔嵕嵖嵗嵘嵙嵚嵛嵜嵝嵞嵟嵠嵡嵢嵣嵤嵥嵦嵧嵨嵩嵪嵫嵬嵭嵮嵯嵰嵱嵲嵳嵴嵵嵶嵷嵸嵹嵺嵻嵼嵽嵾嵿嶀嶁嶂嶃嶄嶅嶆嶇嶈嶉嶊嶋嶌嶍嶎嶏嶐嶑嶒嶓嶔嶕嶖嶗嶘嶙嶚嶛嶜嶝嶞嶟嶠嶡嶢嶣嶤嶥嶦嶧嶨嶩嶪嶫嶬嶭嶮嶯嶰嶱嶲嶳嶴嶵嶶嶷嶸嶹嶺嶻嶼嶽嶾嶿巀巁巂巃巄巅巆巇巈巉巊巋巌巍巎巏巐巑巒巓巔巕巖巗巘巙巚巛巜川州巟巠巡巢巣巤工左巧巨巩巪巫巬巭差巯巰己已巳巴巵巶巷巸巹巺巻巼巽巾巿帀币市布帄帅帆帇师帉帊帋希帍帎帏帐帑帒帓帔帕帖帗帘帙帚帛帜帝帞帟帠帡帢帣帤帥带帧帨帩帪師帬席帮帯帰帱帲帳帴帵帶帷常帹帺帻帼帽帾帿幀幁幂幃幄幅幆幇幈幉幊幋幌幍幎幏幐幑幒幓幔幕幖幗幘幙幚幛幜幝幞幟幠幡幢幣幤幥幦幧幨幩幪幫幬幭幮幯幰幱干平年幵并幷幸幹幺幻幼幽幾广庀庁庂広庄庅庆庇庈庉床庋庌庍庎序庐庑庒库应底庖店庘庙庚庛府庝庞废庠庡庢庣庤庥度座庨庩庪庫庬庭庮庯庰庱庲庳庴庵庶康庸庹庺庻庼庽庾庿廀廁廂廃廄廅廆廇廈廉廊廋廌廍廎廏廐廑廒廓廔廕廖廗廘廙廚廛廜廝廞廟廠廡廢廣廤廥廦廧廨廩廪廫廬廭廮廯廰廱廲廳廴廵延廷廸廹建廻廼廽廾廿开弁异弃弄弅弆弇弈弉弊弋弌弍弎式弐弑弒弓弔引弖弗弘弙弚弛弜弝弞弟张弡弢弣弤弥弦弧弨弩弪弫弬弭弮弯弰弱弲弳弴張弶強弸弹强弻弼弽弾弿彀彁彂彃彄彅彆彇彈彉彊彋彌彍彎彏彐彑归当彔录彖彗彘彙彚彛彜彝彞彟彠彡形彣彤彥彦彧彨彩彪彫彬彭彮彯彰影彲彳彴彵彶彷彸役彺彻彼彽彾彿往征徂徃径待徆徇很徉徊律後徍徎徏徐徑徒従徔徕徖得徘徙徚徛徜徝從徟徠御徢徣徤徥徦徧徨復循徫徬徭微徯徰徱徲徳徴徵徶德徸徹徺徻徼徽徾徿忀忁忂心忄必忆忇忈忉忊忋忌忍忎忏忐忑忒忓忔忕忖志忘忙忚忛応忝忞忟忠忡忢忣忤忥忦忧忨忩忪快忬忭忮忯忰忱忲忳忴念忶忷忸忹忺忻忼忽忾忿怀态怂怃怄怅怆怇怈怉怊怋怌怍怎怏怐怑怒怓怔怕怖怗怘怙怚怛怜思怞怟怠怡怢怣怤急怦性怨怩怪怫怬怭怮怯怰怱怲怳怴怵怶怷怸怹怺总怼怽怾怿恀恁恂恃恄恅恆恇恈恉恊恋恌恍恎恏恐恑恒恓恔恕恖恗恘恙恚恛恜恝恞恟恠恡恢恣恤恥恦恧恨恩恪恫恬恭恮息恰恱恲恳恴恵恶恷恸恹恺恻恼恽恾恿悀悁悂悃悄悅悆悇悈悉悊悋悌悍悎悏悐悑悒悓悔悕悖悗悘悙悚悛悜悝悞悟悠悡悢患悤悥悦悧您悩悪悫悬悭悮悯悰悱悲悳悴悵悶悷悸悹悺悻悼悽悾悿惀惁惂惃惄情惆惇惈惉惊惋惌惍惎惏惐惑惒惓惔惕惖惗惘惙惚惛惜惝惞惟惠惡惢惣惤惥惦惧惨惩惪惫惬惭惮惯惰惱惲想惴惵惶惷惸惹惺惻惼惽惾惿愀愁愂愃愄愅愆愇愈愉愊愋愌愍愎意愐愑愒愓愔愕愖愗愘愙愚愛愜愝愞感愠愡愢愣愤愥愦愧愨愩愪愫愬愭愮愯愰愱愲愳愴愵愶愷愸愹愺愻愼愽愾愿慀慁慂慃慄慅慆慇慈慉慊態慌慍慎慏慐慑慒慓慔慕慖慗慘慙慚慛慜慝慞慟慠慡慢慣慤慥慦慧慨慩慪慫慬慭慮慯慰慱慲慳慴慵慶慷慸慹慺慻慼慽慾慿憀憁憂憃憄憅憆憇憈憉憊憋憌憍憎憏憐憑憒憓憔憕憖憗憘憙憚憛憜憝憞憟憠憡憢憣憤憥憦憧憨憩憪憫憬憭憮憯憰憱憲憳憴憵憶憷憸憹憺憻憼憽憾憿懀懁懂懃懄懅懆懇懈應懊懋懌懍懎懏懐懑懒懓懔懕懖懗懘懙懚懛懜懝懞懟懠懡懢懣懤懥懦懧懨懩懪懫懬懭懮懯懰懱懲懳懴懵懶懷懸懹懺懻懼懽懾懿戀戁戂戃戄戅戆戇戈戉戊戋戌戍戎戏成我戒戓戔戕或戗战戙戚戛戜戝戞戟戠戡戢戣戤戥戦戧戨戩截戫戬戭戮戯戰戱戲戳戴戵戶户戸戹戺戻戼戽戾房所扁扂扃扄扅扆扇扈扉扊手扌才扎扏扐扑扒打扔払扖扗托扙扚扛扜扝扞扟扠扡扢扣扤扥扦执扨扩扪扫扬扭扮扯扰扱扲扳扴扵扶扷扸批扺扻扼扽找承技抁抂抃抄抅抆抇抈抉把抋抌抍抎抏抐抑抒抓抔投抖抗折抙抚抛抜抝択抟抠抡抢抣护报抦抧抨抩抪披抬抭抮抯抰抱抲抳抴抵抶抷抸抹抺抻押抽抾抿拀拁拂拃拄担拆拇拈拉拊拋拌拍拎拏拐拑拒拓拔拕拖拗拘拙拚招拜拝拞拟拠拡拢拣拤拥拦拧拨择拪拫括拭拮拯拰拱拲拳拴拵拶拷拸拹拺拻拼拽拾拿挀持挂挃挄挅挆指挈按挊挋挌挍挎挏挐挑挒挓挔挕挖挗挘挙挚挛挜挝挞挟挠挡挢挣挤挥挦挧挨挩挪挫挬挭挮振挰挱挲挳挴挵挶挷挸挹挺挻挼挽挾挿捀捁捂捃捄捅捆捇捈捉捊捋捌捍捎捏捐捑捒捓捔捕捖捗捘捙捚捛捜捝捞损捠捡换捣捤捥捦捧捨捩捪捫捬捭据捯捰捱捲捳捴捵捶捷捸捹捺捻捼捽捾捿掀掁掂掃掄掅掆掇授掉掊掋掌掍掎掏掐掑排掓掔掕掖掗掘掙掚掛掜掝掞掟掠採探掣掤接掦控推掩措掫掬掭掮掯掰掱掲掳掴掵掶掷掸掹掺掻掼掽掾掿揀揁揂揃揄揅揆揇揈揉揊揋揌揍揎描提揑插揓揔揕揖揗揘揙揚換揜揝揞揟揠握揢揣揤揥揦揧揨揩揪揫揬揭揮揯揰揱揲揳援揵揶揷揸揹揺揻揼揽揾揿搀搁搂搃搄搅搆搇搈搉搊搋搌損搎搏搐搑搒搓搔搕搖搗搘搙搚搛搜搝搞搟搠搡搢搣搤搥搦搧搨搩搪搫搬搭搮搯搰搱搲搳搴搵搶搷搸搹携搻搼搽搾搿摀摁摂摃摄摅摆摇摈摉摊摋摌摍摎摏摐摑摒摓摔摕摖摗摘摙摚摛摜摝摞摟摠摡摢摣摤摥摦摧摨摩摪摫摬摭摮摯摰摱摲摳摴摵摶摷摸摹摺摻摼摽摾摿撀撁撂撃撄撅撆撇撈撉撊撋撌撍撎撏撐撑撒撓撔撕撖撗撘撙撚撛撜撝撞撟撠撡撢撣撤撥撦撧撨撩撪撫撬播撮撯撰撱撲撳撴撵撶撷撸撹撺撻撼撽撾撿擀擁擂擃擄擅擆擇擈擉擊擋擌操擎擏擐擑擒擓擔擕擖擗擘擙據擛擜擝擞擟擠擡擢擣擤擥擦擧擨擩擪擫擬擭擮擯擰擱擲擳擴擵擶擷擸擹擺擻擼擽擾擿攀攁攂攃攄攅攆攇攈攉攊攋攌攍攎攏攐攑攒攓攔攕攖攗攘攙攚攛攜攝攞攟攠攡攢攣攤攥攦攧攨攩攪攫攬攭攮支攰攱攲攳攴攵收攷攸改攺攻攼攽放政敀敁敂敃敄故敆敇效敉敊敋敌敍敎敏敐救敒敓敔敕敖敗敘教敚敛敜敝敞敟敠敡敢散敤敥敦敧敨敩敪敫敬敭敮敯数敱敲敳整敵敶敷數敹敺敻敼敽敾敿斀斁斂斃斄斅斆文斈斉斊斋斌斍斎斏斐斑斒斓斔斕斖斗斘料斚斛斜斝斞斟斠斡斢斣斤斥斦斧斨斩斪斫斬断斮斯新斱斲斳斴斵斶斷斸方斺斻於施斾斿旀旁旂旃旄旅旆旇旈旉旊旋旌旍旎族旐旑旒旓旔旕旖旗旘旙旚旛旜旝旞旟无旡既旣旤日旦旧旨早旪旫旬旭旮旯旰旱旲旳旴旵时旷旸旹旺旻旼旽旾旿昀昁昂昃昄昅昆昇昈昉昊昋昌昍明昏昐昑昒易昔昕昖昗昘昙昚昛昜昝昞星映昡昢昣昤春昦昧昨昩昪昫昬昭昮是昰昱昲昳昴昵昶昷昸昹昺昻昼昽显昿晀晁時晃晄晅晆晇晈晉晊晋晌晍晎晏晐晑晒晓晔晕晖晗晘晙晚晛晜晝晞晟晠晡晢晣晤晥晦晧晨晩晪晫晬晭普景晰晱晲晳晴晵晶晷晸晹智晻晼晽晾晿暀暁暂暃暄暅暆暇暈暉暊暋暌暍暎暏暐暑暒暓暔暕暖暗暘暙暚暛暜暝暞暟暠暡暢暣暤暥暦暧暨暩暪暫暬暭暮暯暰暱暲暳暴暵暶暷暸暹暺暻暼暽暾暿曀曁曂曃曄曅曆曇曈曉曊曋曌曍曎曏曐曑曒曓曔曕曖曗曘曙曚曛曜曝曞曟曠曡曢曣曤曥曦曧曨曩曪曫曬曭曮曯曰曱曲曳更曵曶曷書曹曺曻曼曽曾替最朁朂會朄朅朆朇月有朊朋朌服朎朏朐朑朒朓朔朕朖朗朘朙朚望朜朝朞期朠朡朢朣朤朥朦朧木朩未末本札朮术朰朱朲朳朴朵朶朷朸朹机朻朼朽朾朿杀杁杂权杄杅杆杇杈杉杊杋杌杍李杏材村杒杓杔杕杖杗杘杙杚杛杜杝杞束杠条杢杣杤来杦杧杨杩杪杫杬杭杮杯杰東杲杳杴杵杶杷杸杹杺杻杼杽松板枀极枂枃构枅枆枇枈枉枊枋枌枍枎枏析枑枒枓枔枕枖林枘枙枚枛果枝枞枟枠枡枢枣枤枥枦枧枨枩枪枫枬枭枮枯枰枱枲枳枴枵架枷枸枹枺枻枼枽枾枿柀柁柂柃柄柅柆柇柈柉柊柋柌柍柎柏某柑柒染柔柕柖柗柘柙柚柛柜柝柞柟柠柡柢柣柤查柦柧柨柩柪柫柬柭柮柯柰柱柲柳柴柵柶柷柸柹柺査柼柽柾柿栀栁栂栃栄栅栆标栈栉栊栋栌栍栎栏栐树栒栓栔栕栖栗栘栙栚栛栜栝栞栟栠校栢栣栤栥栦栧栨栩株栫栬栭栮栯栰栱栲栳栴栵栶样核根栺栻格栽栾栿桀桁桂桃桄桅框桇案桉桊桋桌桍桎桏桐桑桒桓桔桕桖桗桘桙桚桛桜桝桞桟桠桡桢档桤桥桦桧桨桩桪桫桬桭桮桯桰桱桲桳桴桵桶桷桸桹桺桻桼桽桾桿梀梁梂梃梄梅梆梇梈梉梊梋梌梍梎梏梐梑梒梓梔梕梖梗梘梙梚梛梜條梞梟梠梡梢梣梤梥梦梧梨梩梪梫梬梭梮梯械梱梲梳梴梵梶梷梸梹梺梻梼梽梾梿检棁棂棃棄棅棆棇棈棉棊棋棌棍棎棏棐棑棒棓棔棕棖棗棘棙棚棛棜棝棞棟棠棡棢棣棤棥棦棧棨棩棪棫棬棭森棯棰棱棲棳棴棵棶棷棸棹棺棻棼棽棾棿椀椁椂椃椄椅椆椇椈椉椊椋椌植椎椏椐椑椒椓椔椕椖椗椘椙椚椛検椝椞椟椠椡椢椣椤椥椦椧椨椩椪椫椬椭椮椯椰椱椲椳椴椵椶椷椸椹椺椻椼椽椾椿楀楁楂楃楄楅楆楇楈楉楊楋楌楍楎楏楐楑楒楓楔楕楖楗楘楙楚楛楜楝楞楟楠楡楢楣楤楥楦楧楨楩楪楫楬業楮楯楰楱楲楳楴極楶楷楸楹楺楻楼楽楾楿榀榁概榃榄榅榆榇榈榉榊榋榌榍榎榏榐榑榒榓榔榕榖榗榘榙榚榛榜榝榞榟榠榡榢榣榤榥榦榧榨榩榪榫榬榭榮榯榰榱榲榳榴榵榶榷榸榹榺榻榼榽榾榿槀槁槂槃槄槅槆槇槈槉槊構槌槍槎槏槐槑槒槓槔槕槖槗様槙槚槛槜槝槞槟槠槡槢槣槤槥槦槧槨槩槪槫槬槭槮槯槰槱槲槳槴槵槶槷槸槹槺槻槼槽槾槿樀樁樂樃樄樅樆樇樈樉樊樋樌樍樎樏樐樑樒樓樔樕樖樗樘標樚樛樜樝樞樟樠模樢樣樤樥樦樧樨権横樫樬樭樮樯樰樱樲樳樴樵樶樷樸樹樺樻樼樽樾樿橀橁橂橃橄橅橆橇橈橉橊橋橌橍橎橏橐橑橒橓橔橕橖橗橘橙橚橛橜橝橞機橠橡橢橣橤橥橦橧橨橩橪橫橬橭橮橯橰橱橲橳橴橵橶橷橸橹橺橻橼橽橾橿檀檁檂檃檄檅檆檇檈檉檊檋檌檍檎檏檐檑檒檓檔檕檖檗檘檙檚檛檜檝檞檟檠檡檢檣檤檥檦檧檨檩檪檫檬檭檮檯檰檱檲檳檴檵檶檷檸檹檺檻檼檽檾檿櫀櫁櫂櫃櫄櫅櫆櫇櫈櫉櫊櫋櫌櫍櫎櫏櫐櫑櫒櫓櫔櫕櫖櫗櫘櫙櫚櫛櫜櫝櫞櫟櫠櫡櫢櫣櫤櫥櫦櫧櫨櫩櫪櫫櫬櫭櫮櫯櫰櫱櫲櫳櫴櫵櫶櫷櫸櫹櫺櫻櫼櫽櫾櫿欀欁欂欃欄欅欆欇欈欉權欋欌欍欎欏欐欑欒欓欔欕欖欗欘欙欚欛欜欝欞欟欠次欢欣欤欥欦欧欨欩欪欫欬欭欮欯欰欱欲欳欴欵欶欷欸欹欺欻欼欽款欿歀歁歂歃歄歅歆歇歈歉歊歋歌歍歎歏歐歑歒歓歔歕歖歗歘歙歚歛歜歝歞歟歠歡止正此步武歧歨歩歪歫歬歭歮歯歰歱歲歳歴歵歶歷歸歹歺死歼歽歾歿殀殁殂殃殄殅殆殇殈殉殊残殌殍殎殏殐殑殒殓殔殕殖殗殘殙殚殛殜殝殞殟殠殡殢殣殤殥殦殧殨殩殪殫殬殭殮殯殰殱殲殳殴段殶殷殸殹殺殻殼殽殾殿毀毁毂毃毄毅毆毇毈毉毊毋毌母毎每毐毑毒毓比毕毖毗毘毙毚毛毜毝毞毟毠毡毢毣毤毥毦毧毨毩毪毫毬毭毮毯毰毱毲毳毴毵毶毷毸毹毺毻毼毽毾毿氀氁氂氃氄氅氆氇氈氉氊氋氌氍氎氏氐民氒氓气氕氖気氘氙氚氛氜氝氞氟氠氡氢氣氤氥氦氧氨氩氪氫氬氭氮氯氰氱氲氳水氵氶氷永氹氺氻氼氽氾氿汀汁求汃汄汅汆汇汈汉汊汋汌汍汎汏汐汑汒汓汔汕汖汗汘汙汚汛汜汝汞江池污汢汣汤汥汦汧汨汩汪汫汬汭汮汯汰汱汲汳汴汵汶汷汸汹決汻汼汽汾汿沀沁沂沃沄沅沆沇沈沉沊沋沌沍沎沏沐沑沒沓沔沕沖沗沘沙沚沛沜沝沞沟沠没沢沣沤沥沦沧沨沩沪沫沬沭沮沯沰沱沲河沴沵沶沷沸油沺治沼沽沾沿泀況泂泃泄泅泆泇泈泉泊泋泌泍泎泏泐泑泒泓泔法泖泗泘泙泚泛泜泝泞泟泠泡波泣泤泥泦泧注泩泪泫泬泭泮泯泰泱泲泳泴泵泶泷泸泹泺泻泼泽泾泿洀洁洂洃洄洅洆洇洈洉洊洋洌洍洎洏洐洑洒洓洔洕洖洗洘洙洚洛洜洝洞洟洠洡洢洣洤津洦洧洨洩洪洫洬洭洮洯洰洱洲洳洴洵洶洷洸洹洺活洼洽派洿浀流浂浃浄浅浆浇浈浉浊测浌浍济浏浐浑浒浓浔浕浖浗浘浙浚浛浜浝浞浟浠浡浢浣浤浥浦浧浨浩浪浫浬浭浮浯浰浱浲浳浴浵浶海浸浹浺浻浼浽浾浿涀涁涂涃涄涅涆涇消涉涊涋涌涍涎涏涐涑涒涓涔涕涖涗涘涙涚涛涜涝涞涟涠涡涢涣涤涥润涧涨涩涪涫涬涭涮涯涰涱液涳涴涵涶涷涸涹涺涻涼涽涾涿淀淁淂淃淄淅淆淇淈淉淊淋淌淍淎淏淐淑淒淓淔淕淖淗淘淙淚淛淜淝淞淟淠淡淢淣淤淥淦淧淨淩淪淫淬淭淮淯淰深淲淳淴淵淶混淸淹淺添淼淽淾淿渀渁渂渃渄清渆渇済渉渊渋渌渍渎渏渐渑渒渓渔渕渖渗渘渙渚減渜渝渞渟渠渡渢渣渤渥渦渧渨温渪渫測渭渮港渰渱渲渳渴渵渶渷游渹渺渻渼渽渾渿湀湁湂湃湄湅湆湇湈湉湊湋湌湍湎湏湐湑湒湓湔湕湖湗湘湙湚湛湜湝湞湟湠湡湢湣湤湥湦湧湨湩湪湫湬湭湮湯湰湱湲湳湴湵湶湷湸湹湺湻湼湽湾湿満溁溂溃溄溅溆溇溈溉溊溋溌溍溎溏源溑溒溓溔溕準溗溘溙溚溛溜溝溞溟溠溡溢溣溤溥溦溧溨溩溪溫溬溭溮溯溰溱溲溳溴溵溶溷溸溹溺溻溼溽溾溿滀滁滂滃滄滅滆滇滈滉滊滋滌滍滎滏滐滑滒滓滔滕滖滗滘滙滚滛滜滝滞滟滠满滢滣滤滥滦滧滨滩滪滫滬滭滮滯滰滱滲滳滴滵滶滷滸滹滺滻滼滽滾滿漀漁漂漃漄漅漆漇漈漉漊漋漌漍漎漏漐漑漒漓演漕漖漗漘漙漚漛漜漝漞漟漠漡漢漣漤漥漦漧漨漩漪漫漬漭漮漯漰漱漲漳漴漵漶漷漸漹漺漻漼漽漾漿潀潁潂潃潄潅潆潇潈潉潊潋潌潍潎潏潐潑潒潓潔潕潖潗潘潙潚潛潜潝潞潟潠潡潢潣潤潥潦潧潨潩潪潫潬潭潮潯潰潱潲潳潴潵潶潷潸潹潺潻潼潽潾潿澀澁澂澃澄澅澆澇澈澉澊澋澌澍澎澏澐澑澒澓澔澕澖澗澘澙澚澛澜澝澞澟澠澡澢澣澤澥澦澧澨澩澪澫澬澭澮澯澰澱澲澳澴澵澶澷澸澹澺澻澼澽澾澿激濁濂濃濄濅濆濇濈濉濊濋濌濍濎濏濐濑濒濓濔濕濖濗濘濙濚濛濜濝濞濟濠濡濢濣濤濥濦濧濨濩濪濫濬濭濮濯濰濱濲濳濴濵濶濷濸濹濺濻濼濽濾濿瀀瀁瀂瀃瀄瀅瀆瀇瀈瀉瀊瀋瀌瀍瀎瀏瀐瀑瀒瀓瀔瀕瀖瀗瀘瀙瀚瀛瀜瀝瀞瀟瀠瀡瀢瀣瀤瀥瀦瀧瀨瀩瀪瀫瀬瀭瀮瀯瀰瀱瀲瀳瀴瀵瀶瀷瀸瀹瀺瀻瀼瀽瀾瀿灀灁灂灃灄灅灆灇灈灉灊灋灌灍灎灏灐灑灒灓灔灕灖灗灘灙灚灛灜灝灞灟灠灡灢灣灤灥灦灧灨灩灪火灬灭灮灯灰灱灲灳灴灵灶灷灸灹灺灻灼災灾灿炀炁炂炃炄炅炆炇炈炉炊炋炌炍炎炏炐炑炒炓炔炕炖炗炘炙炚炛炜炝炞炟炠炡炢炣炤炥炦炧炨炩炪炫炬炭炮炯炰炱炲炳炴炵炶炷炸点為炻炼炽炾炿烀烁烂烃烄烅烆烇烈烉烊烋烌烍烎烏烐烑烒烓烔烕烖烗烘烙烚烛烜烝烞烟烠烡烢烣烤烥烦烧烨烩烪烫烬热烮烯烰烱烲烳烴烵烶烷烸烹烺烻烼烽烾烿焀焁焂焃焄焅焆焇焈焉焊焋焌焍焎焏焐焑焒焓焔焕焖焗焘焙焚焛焜焝焞焟焠無焢焣焤焥焦焧焨焩焪焫焬焭焮焯焰焱焲焳焴焵然焷焸焹焺焻焼焽焾焿煀煁煂煃煄煅煆煇煈煉煊煋煌煍煎煏煐煑煒煓煔煕煖煗煘煙煚煛煜煝煞煟煠煡煢煣煤煥煦照煨煩煪煫煬煭煮煯煰煱煲煳煴煵煶煷煸煹煺煻煼煽煾煿熀熁熂熃熄熅熆熇熈熉熊熋熌熍熎熏熐熑熒熓熔熕熖熗熘熙熚熛熜熝熞熟熠熡熢熣熤熥熦熧熨熩熪熫熬熭熮熯熰熱熲熳熴熵熶熷熸熹熺熻熼熽熾熿燀燁燂燃燄燅燆燇燈燉燊燋燌燍燎燏燐燑燒燓燔燕燖燗燘燙燚燛燜燝燞營燠燡燢燣燤燥燦燧燨燩燪燫燬燭燮燯燰燱燲燳燴燵燶燷燸燹燺燻燼燽燾燿爀爁爂爃爄爅爆爇爈爉爊爋爌爍爎爏爐爑爒爓爔爕爖爗爘爙爚爛爜爝爞爟爠爡爢爣爤爥爦爧爨爩爪爫爬爭爮爯爰爱爲爳爴爵父爷爸爹爺爻爼爽爾爿牀牁牂牃牄牅牆片版牉牊牋牌牍牎牏牐牑牒牓牔牕牖牗牘牙牚牛牜牝牞牟牠牡牢牣牤牥牦牧牨物牪牫牬牭牮牯牰牱牲牳牴牵牶牷牸特牺牻牼牽牾牿犀犁犂犃犄犅犆犇犈犉犊犋犌犍犎犏犐犑犒犓犔犕犖犗犘犙犚犛犜犝犞犟犠犡犢犣犤犥犦犧犨犩犪犫犬犭犮犯犰犱犲犳犴犵状犷犸犹犺犻犼犽犾犿狀狁狂狃狄狅狆狇狈狉狊狋狌狍狎狏狐狑狒狓狔狕狖狗狘狙狚狛狜狝狞狟狠狡狢狣狤狥狦狧狨狩狪狫独狭狮狯狰狱狲狳狴狵狶狷狸狹狺狻狼狽狾狿猀猁猂猃猄猅猆猇猈猉猊猋猌猍猎猏猐猑猒猓猔猕猖猗猘猙猚猛猜猝猞猟猠猡猢猣猤猥猦猧猨猩猪猫猬猭献猯猰猱猲猳猴猵猶猷猸猹猺猻猼猽猾猿獀獁獂獃獄獅獆獇獈獉獊獋獌獍獎獏獐獑獒獓獔獕獖獗獘獙獚獛獜獝獞獟獠獡獢獣獤獥獦獧獨獩獪獫獬獭獮獯獰獱獲獳獴獵獶獷獸獹獺獻獼獽獾獿玀玁玂玃玄玅玆率玈玉玊王玌玍玎玏玐玑玒玓玔玕玖玗玘玙玚玛玜玝玞玟玠玡玢玣玤玥玦玧玨玩玪玫玬玭玮环现玱玲玳玴玵玶玷玸玹玺玻玼玽玾玿珀珁珂珃珄珅珆珇珈珉珊珋珌珍珎珏珐珑珒珓珔珕珖珗珘珙珚珛珜珝珞珟珠珡珢珣珤珥珦珧珨珩珪珫珬班珮珯珰珱珲珳珴珵珶珷珸珹珺珻珼珽現珿琀琁琂球琄琅理琇琈琉琊琋琌琍琎琏琐琑琒琓琔琕琖琗琘琙琚琛琜琝琞琟琠琡琢琣琤琥琦琧琨琩琪琫琬琭琮琯琰琱琲琳琴琵琶琷琸琹琺琻琼琽琾琿瑀瑁瑂瑃瑄瑅瑆瑇瑈瑉瑊瑋瑌瑍瑎瑏瑐瑑瑒瑓瑔瑕瑖瑗瑘瑙瑚瑛瑜瑝瑞瑟瑠瑡瑢瑣瑤瑥瑦瑧瑨瑩瑪瑫瑬瑭瑮瑯瑰瑱瑲瑳瑴瑵瑶瑷瑸瑹瑺瑻瑼瑽瑾瑿璀璁璂璃璄璅璆璇璈璉璊璋璌璍璎璏璐璑璒璓璔璕璖璗璘璙璚璛璜璝璞璟璠璡璢璣璤璥璦璧璨璩璪璫璬璭璮璯環璱璲璳璴璵璶璷璸璹璺璻璼璽璾璿瓀瓁瓂瓃瓄瓅瓆瓇瓈瓉瓊瓋瓌瓍瓎瓏瓐瓑瓒瓓瓔瓕瓖瓗瓘瓙瓚瓛瓜瓝瓞瓟瓠瓡瓢瓣瓤瓥瓦瓧瓨瓩瓪瓫瓬瓭瓮瓯瓰瓱瓲瓳瓴瓵瓶瓷瓸瓹瓺瓻瓼瓽瓾瓿甀甁甂甃甄甅甆甇甈甉甊甋甌甍甎甏甐甑甒甓甔甕甖甗甘甙甚甛甜甝甞生甠甡產産甤甥甦甧用甩甪甫甬甭甮甯田由甲申甴电甶男甸甹町画甼甽甾甿畀畁畂畃畄畅畆畇畈畉畊畋界畍畎畏畐畑畒畓畔畕畖畗畘留畚畛畜畝畞畟畠畡畢畣畤略畦畧畨畩番畫畬畭畮畯異畱畲畳畴畵當畷畸畹畺畻畼畽畾畿疀疁疂疃疄疅疆疇疈疉疊疋疌疍疎疏疐疑疒疓疔疕疖疗疘疙疚疛疜疝疞疟疠疡疢疣疤疥疦疧疨疩疪疫疬疭疮疯疰疱疲疳疴疵疶疷疸疹疺疻疼疽疾疿痀痁痂痃痄病痆症痈痉痊痋痌痍痎痏痐痑痒痓痔痕痖痗痘痙痚痛痜痝痞痟痠痡痢痣痤痥痦痧痨痩痪痫痬痭痮痯痰痱痲痳痴痵痶痷痸痹痺痻痼痽痾痿瘀瘁瘂瘃瘄瘅瘆瘇瘈瘉瘊瘋瘌瘍瘎瘏瘐瘑瘒瘓瘔瘕瘖瘗瘘瘙瘚瘛瘜瘝瘞瘟瘠瘡瘢瘣瘤瘥瘦瘧瘨瘩瘪瘫瘬瘭瘮瘯瘰瘱瘲瘳瘴瘵瘶瘷瘸瘹瘺瘻瘼瘽瘾瘿癀癁療癃癄癅癆癇癈癉癊癋癌癍癎癏癐癑癒癓癔癕癖癗癘癙癚癛癜癝癞癟癠癡癢癣癤癥癦癧癨癩癪癫癬癭癮癯癰癱癲癳癴癵癶癷癸癹発登發白百癿皀皁皂皃的皅皆皇皈皉皊皋皌皍皎皏皐皑皒皓皔皕皖皗皘皙皚皛皜皝皞皟皠皡皢皣皤皥皦皧皨皩皪皫皬皭皮皯皰皱皲皳皴皵皶皷皸皹皺皻皼皽皾皿盀盁盂盃盄盅盆盇盈盉益盋盌盍盎盏盐监盒盓盔盕盖盗盘盙盚盛盜盝盞盟盠盡盢監盤盥盦盧盨盩盪盫盬盭目盯盰盱盲盳直盵盶盷相盹盺盻盼盽盾盿眀省眂眃眄眅眆眇眈眉眊看県眍眎眏眐眑眒眓眔眕眖眗眘眙眚眛眜眝眞真眠眡眢眣眤眥眦眧眨眩眪眫眬眭眮眯眰眱眲眳眴眵眶眷眸眹眺眻眼眽眾眿着睁睂睃睄睅睆睇睈睉睊睋睌睍睎睏睐睑睒睓睔睕睖睗睘睙睚睛睜睝睞睟睠睡睢督睤睥睦睧睨睩睪睫睬睭睮睯睰睱睲睳睴睵睶睷睸睹睺睻睼睽睾睿瞀瞁瞂瞃瞄瞅瞆瞇瞈瞉瞊瞋瞌瞍瞎瞏瞐瞑瞒瞓瞔瞕瞖瞗瞘瞙瞚瞛瞜瞝瞞瞟瞠瞡瞢瞣瞤瞥瞦瞧瞨瞩瞪瞫瞬瞭瞮瞯瞰瞱瞲瞳瞴瞵瞶瞷瞸瞹瞺瞻瞼瞽瞾瞿矀矁矂矃矄矅矆矇矈矉矊矋矌矍矎矏矐矑矒矓矔矕矖矗矘矙矚矛矜矝矞矟矠矡矢矣矤知矦矧矨矩矪矫矬短矮矯矰矱矲石矴矵矶矷矸矹矺矻矼矽矾矿砀码砂砃砄砅砆砇砈砉砊砋砌砍砎砏砐砑砒砓研砕砖砗砘砙砚砛砜砝砞砟砠砡砢砣砤砥砦砧砨砩砪砫砬砭砮砯砰砱砲砳破砵砶砷砸砹砺砻砼砽砾砿础硁硂硃硄硅硆硇硈硉硊硋硌硍硎硏硐硑硒硓硔硕硖硗硘硙硚硛硜硝硞硟硠硡硢硣硤硥硦硧硨硩硪硫硬硭确硯硰硱硲硳硴硵硶硷硸硹硺硻硼硽硾硿碀碁碂碃碄碅碆碇碈碉碊碋碌碍碎碏碐碑碒碓碔碕碖碗碘碙碚碛碜碝碞碟碠碡碢碣碤碥碦碧碨碩碪碫碬碭碮碯碰碱碲碳碴碵碶碷碸碹確碻碼碽碾碿磀磁磂磃磄磅磆磇磈磉磊磋磌磍磎磏磐磑磒磓磔磕磖磗磘磙磚磛磜磝磞磟磠磡磢磣磤磥磦磧磨磩磪磫磬磭磮磯磰磱磲磳磴磵磶磷磸磹磺磻磼磽磾磿礀礁礂礃礄礅礆礇礈礉礊礋礌礍礎礏礐礑礒礓礔礕礖礗礘礙礚礛礜礝礞礟礠礡礢礣礤礥礦礧礨礩礪礫礬礭礮礯礰礱礲礳礴礵礶礷礸礹示礻礼礽社礿祀祁祂祃祄祅祆祇祈祉祊祋祌祍祎祏祐祑祒祓祔祕祖祗祘祙祚祛祜祝神祟祠祡祢祣祤祥祦祧票祩祪祫祬祭祮祯祰祱祲祳祴祵祶祷祸祹祺祻祼祽祾祿禀禁禂禃禄禅禆禇禈禉禊禋禌禍禎福禐禑禒禓禔禕禖禗禘禙禚禛禜禝禞禟禠禡禢禣禤禥禦禧禨禩禪禫禬禭禮禯禰禱禲禳禴禵禶禷禸禹禺离禼禽禾禿秀私秂秃秄秅秆秇秈秉秊秋秌种秎秏秐科秒秓秔秕秖秗秘秙秚秛秜秝秞租秠秡秢秣秤秥秦秧秨秩秪秫秬秭秮积称秱秲秳秴秵秶秷秸秹秺移秼秽秾秿稀稁稂稃稄稅稆稇稈稉稊程稌稍税稏稐稑稒稓稔稕稖稗稘稙稚稛稜稝稞稟稠稡稢稣稤稥稦稧稨稩稪稫稬稭種稯稰稱稲稳稴稵稶稷稸稹稺稻稼稽稾稿穀穁穂穃穄穅穆穇穈穉穊穋穌積穎穏穐穑穒穓穔穕穖穗穘穙穚穛穜穝穞穟穠穡穢穣穤穥穦穧穨穩穪穫穬穭穮穯穰穱穲穳穴穵究穷穸穹空穻穼穽穾穿窀突窂窃窄窅窆窇窈窉窊窋窌窍窎窏窐窑窒窓窔窕窖窗窘窙窚窛窜窝窞窟窠窡窢窣窤窥窦窧窨窩窪窫窬窭窮窯窰窱窲窳窴窵窶窷窸窹窺窻窼窽窾窿竀竁竂竃竄竅竆竇竈竉竊立竌竍竎竏竐竑竒竓竔竕竖竗竘站竚竛竜竝竞竟章竡竢竣竤童竦竧竨竩竪竫竬竭竮端竰竱竲竳竴竵競竷竸竹竺竻竼竽竾竿笀笁笂笃笄笅笆笇笈笉笊笋笌笍笎笏笐笑笒笓笔笕笖笗笘笙笚笛笜笝笞笟笠笡笢笣笤笥符笧笨笩笪笫第笭笮笯笰笱笲笳笴笵笶笷笸笹笺笻笼笽笾笿筀筁筂筃筄筅筆筇筈等筊筋筌筍筎筏筐筑筒筓答筕策筗筘筙筚筛筜筝筞筟筠筡筢筣筤筥筦筧筨筩筪筫筬筭筮筯筰筱筲筳筴筵筶筷筸筹筺筻筼筽签筿简箁箂箃箄箅箆箇箈箉箊箋箌箍箎箏箐箑箒箓箔箕箖算箘箙箚箛箜箝箞箟箠管箢箣箤箥箦箧箨箩箪箫箬箭箮箯箰箱箲箳箴箵箶箷箸箹箺箻箼箽箾箿節篁篂篃範篅篆篇篈築篊篋篌篍篎篏篐篑篒篓篔篕篖篗篘篙篚篛篜篝篞篟篠篡篢篣篤篥篦篧篨篩篪篫篬篭篮篯篰篱篲篳篴篵篶篷篸篹篺篻篼篽篾篿簀簁簂簃簄簅簆簇簈簉簊簋簌簍簎簏簐簑簒簓簔簕簖簗簘簙簚簛簜簝簞簟簠簡簢簣簤簥簦簧簨簩簪簫簬簭簮簯簰簱簲簳簴簵簶簷簸簹簺簻簼簽簾簿籀籁籂籃籄籅籆籇籈籉籊籋籌籍籎籏籐籑籒籓籔籕籖籗籘籙籚籛籜籝籞籟籠籡籢籣籤籥籦籧籨籩籪籫籬籭籮籯籰籱籲米籴籵籶籷籸籹籺类籼籽籾籿粀粁粂粃粄粅粆粇粈粉粊粋粌粍粎粏粐粑粒粓粔粕粖粗粘粙粚粛粜粝粞粟粠粡粢粣粤粥粦粧粨粩粪粫粬粭粮粯粰粱粲粳粴粵粶粷粸粹粺粻粼粽精粿糀糁糂糃糄糅糆糇糈糉糊糋糌糍糎糏糐糑糒糓糔糕糖糗糘糙糚糛糜糝糞糟糠糡糢糣糤糥糦糧糨糩糪糫糬糭糮糯糰糱糲糳糴糵糶糷糸糹糺系糼糽糾糿紀紁紂紃約紅紆紇紈紉紊紋紌納紎紏紐紑紒紓純紕紖紗紘紙級紛紜紝紞紟素紡索紣紤紥紦紧紨紩紪紫紬紭紮累細紱紲紳紴紵紶紷紸紹紺紻紼紽紾紿絀絁終絃組絅絆絇絈絉絊絋経絍絎絏結絑絒絓絔絕絖絗絘絙絚絛絜絝絞絟絠絡絢絣絤絥給絧絨絩絪絫絬絭絮絯絰統絲絳絴絵絶絷絸絹絺絻絼絽絾絿綀綁綂綃綄綅綆綇綈綉綊綋綌綍綎綏綐綑綒經綔綕綖綗綘継続綛綜綝綞綟綠綡綢綣綤綥綦綧綨綩綪綫綬維綮綯綰綱網綳綴綵綶綷綸綹綺綻綼綽綾綿緀緁緂緃緄緅緆緇緈緉緊緋緌緍緎総緐緑緒緓緔緕緖緗緘緙線緛緜緝緞緟締緡緢緣緤緥緦緧編緩緪緫緬緭緮緯緰緱緲緳練緵緶緷緸緹緺緻緼緽緾緿縀縁縂縃縄縅縆縇縈縉縊縋縌縍縎縏縐縑縒縓縔縕縖縗縘縙縚縛縜縝縞縟縠縡縢縣縤縥縦縧縨縩縪縫縬縭縮縯縰縱縲縳縴縵縶縷縸縹縺縻縼總績縿繀繁繂繃繄繅繆繇繈繉繊繋繌繍繎繏繐繑繒繓織繕繖繗繘繙繚繛繜繝繞繟繠繡繢繣繤繥繦繧繨繩繪繫繬繭繮繯繰繱繲繳繴繵繶繷繸繹繺繻繼繽繾繿纀纁纂纃纄纅纆纇纈纉纊纋續纍纎纏纐纑纒纓纔纕纖纗纘纙纚纛纜纝纞纟纠纡红纣纤纥约级纨纩纪纫纬纭纮纯纰纱纲纳纴纵纶纷纸纹纺纻纼纽纾线绀绁绂练组绅细织终绉绊绋绌绍绎经绐绑绒结绔绕绖绗绘给绚绛络绝绞统绠绡绢绣绤绥绦继绨绩绪绫绬续绮绯绰绱绲绳维绵绶绷绸绹绺绻综绽绾绿缀缁缂缃缄缅缆缇缈缉缊缋缌缍缎缏缐缑缒缓缔缕编缗缘缙缚缛缜缝缞缟缠缡缢缣缤缥缦缧缨缩缪缫缬缭缮缯缰缱缲缳缴缵缶缷缸缹缺缻缼缽缾缿罀罁罂罃罄罅罆罇罈罉罊罋罌罍罎罏罐网罒罓罔罕罖罗罘罙罚罛罜罝罞罟罠罡罢罣罤罥罦罧罨罩罪罫罬罭置罯罰罱署罳罴罵罶罷罸罹罺罻罼罽罾罿羀羁羂羃羄羅羆羇羈羉羊羋羌羍美羏羐羑羒羓羔羕羖羗羘羙羚羛羜羝羞羟羠羡羢羣群羥羦羧羨義羪羫羬羭羮羯羰羱羲羳羴羵羶羷羸羹羺羻羼羽羾羿翀翁翂翃翄翅翆翇翈翉翊翋翌翍翎翏翐翑習翓翔翕翖翗翘翙翚翛翜翝翞翟翠翡翢翣翤翥翦翧翨翩翪翫翬翭翮翯翰翱翲翳翴翵翶翷翸翹翺翻翼翽翾翿耀老耂考耄者耆耇耈耉耊耋而耍耎耏耐耑耒耓耔耕耖耗耘耙耚耛耜耝耞耟耠耡耢耣耤耥耦耧耨耩耪耫耬耭耮耯耰耱耲耳耴耵耶耷耸耹耺耻耼耽耾耿聀聁聂聃聄聅聆聇聈聉聊聋职聍聎聏聐聑聒聓联聕聖聗聘聙聚聛聜聝聞聟聠聡聢聣聤聥聦聧聨聩聪聫聬聭聮聯聰聱聲聳聴聵聶職聸聹聺聻聼聽聾聿肀肁肂肃肄肅肆肇肈肉肊肋肌肍肎肏肐肑肒肓肔肕肖肗肘肙肚肛肜肝肞肟肠股肢肣肤肥肦肧肨肩肪肫肬肭肮肯肰肱育肳肴肵肶肷肸肹肺肻肼肽肾肿胀胁胂胃胄胅胆胇胈胉胊胋背胍胎胏胐胑胒胓胔胕胖胗胘胙胚胛胜胝胞胟胠胡胢胣胤胥胦胧胨胩胪胫胬胭胮胯胰胱胲胳胴胵胶胷胸胹胺胻胼能胾胿脀脁脂脃脄脅脆脇脈脉脊脋脌脍脎脏脐脑脒脓脔脕脖脗脘脙脚脛脜脝脞脟脠脡脢脣脤脥脦脧脨脩脪脫脬脭脮脯脰脱脲脳脴脵脶脷脸脹脺脻脼脽脾脿腀腁腂腃腄腅腆腇腈腉腊腋腌腍腎腏腐腑腒腓腔腕腖腗腘腙腚腛腜腝腞腟腠腡腢腣腤腥腦腧腨腩腪腫腬腭腮腯腰腱腲腳腴腵腶腷腸腹腺腻腼腽腾腿膀膁膂膃膄膅膆膇膈膉膊膋膌膍膎膏膐膑膒膓膔膕膖膗膘膙膚膛膜膝膞膟膠膡膢膣膤膥膦膧膨膩膪膫膬膭膮膯膰膱膲膳膴膵膶膷膸膹膺膻膼膽膾膿臀臁臂臃臄臅臆臇臈臉臊臋臌臍臎臏臐臑臒臓臔臕臖臗臘臙臚臛臜臝臞臟臠臡臢臣臤臥臦臧臨臩自臫臬臭臮臯臰臱臲至致臵臶臷臸臹臺臻臼臽臾臿舀舁舂舃舄舅舆與興舉舊舋舌舍舎舏舐舑舒舓舔舕舖舗舘舙舚舛舜舝舞舟舠舡舢舣舤舥舦舧舨舩航舫般舭舮舯舰舱舲舳舴舵舶舷舸船舺舻舼舽舾舿艀艁艂艃艄艅艆艇艈艉艊艋艌艍艎艏艐艑艒艓艔艕艖艗艘艙艚艛艜艝艞艟艠艡艢艣艤艥艦艧艨艩艪艫艬艭艮良艰艱色艳艴艵艶艷艸艹艺艻艼艽艾艿芀芁节芃芄芅芆芇芈芉芊芋芌芍芎芏芐芑芒芓芔芕芖芗芘芙芚芛芜芝芞芟芠芡芢芣芤芥芦芧芨芩芪芫芬芭芮芯芰花芲芳芴芵芶芷芸芹芺芻芼芽芾芿苀苁苂苃苄苅苆苇苈苉苊苋苌苍苎苏苐苑苒苓苔苕苖苗苘苙苚苛苜苝苞苟苠苡苢苣苤若苦苧苨苩苪苫苬苭苮苯苰英苲苳苴苵苶苷苸苹苺苻苼苽苾苿茀茁茂范茄茅茆茇茈茉茊茋茌茍茎茏茐茑茒茓茔茕茖茗茘茙茚茛茜茝茞茟茠茡茢茣茤茥茦茧茨茩茪茫茬茭茮茯茰茱茲茳茴茵茶茷茸茹茺茻茼茽茾茿荀荁荂荃荄荅荆荇荈草荊荋荌荍荎荏荐荑荒荓荔荕荖荗荘荙荚荛荜荝荞荟荠荡荢荣荤荥荦荧荨荩荪荫荬荭荮药荰荱荲荳荴荵荶荷荸荹荺荻荼荽荾荿莀莁莂莃莄莅莆莇莈莉莊莋莌莍莎莏莐莑莒莓莔莕莖莗莘莙莚莛莜莝莞莟莠莡莢莣莤莥莦莧莨莩莪莫莬莭莮莯莰莱莲莳莴莵莶获莸莹莺莻莼莽莾莿菀菁菂菃菄菅菆菇菈菉菊菋菌菍菎菏菐菑菒菓菔菕菖菗菘菙菚菛菜菝菞菟菠菡菢菣菤菥菦菧菨菩菪菫菬菭菮華菰菱菲菳菴菵菶菷菸菹菺菻菼菽菾菿萀萁萂萃萄萅萆萇萈萉萊萋萌萍萎萏萐萑萒萓萔萕萖萗萘萙萚萛萜萝萞萟萠萡萢萣萤营萦萧萨萩萪萫萬萭萮萯萰萱萲萳萴萵萶萷萸萹萺萻萼落萾萿葀葁葂葃葄葅葆葇葈葉葊葋葌葍葎葏葐葑葒葓葔葕葖著葘葙葚葛葜葝葞葟葠葡葢董葤葥葦葧葨葩葪葫葬葭葮葯葰葱葲葳葴葵葶葷葸葹葺葻葼葽葾葿蒀蒁蒂蒃蒄蒅蒆蒇蒈蒉蒊蒋蒌蒍蒎蒏蒐蒑蒒蒓蒔蒕蒖蒗蒘蒙蒚蒛蒜蒝蒞蒟蒠蒡蒢蒣蒤蒥蒦蒧蒨蒩蒪蒫蒬蒭蒮蒯蒰蒱蒲蒳蒴蒵蒶蒷蒸蒹蒺蒻蒼蒽蒾蒿蓀蓁蓂蓃蓄蓅蓆蓇蓈蓉蓊蓋蓌蓍蓎蓏蓐蓑蓒蓓蓔蓕蓖蓗蓘蓙蓚蓛蓜蓝蓞蓟蓠蓡蓢蓣蓤蓥蓦蓧蓨蓩蓪蓫蓬蓭蓮蓯蓰蓱蓲蓳蓴蓵蓶蓷蓸蓹蓺蓻蓼蓽蓾蓿蔀蔁蔂蔃蔄蔅蔆蔇蔈蔉蔊蔋蔌蔍蔎蔏蔐蔑蔒蔓蔔蔕蔖蔗蔘蔙蔚蔛蔜蔝蔞蔟蔠蔡蔢蔣蔤蔥蔦蔧蔨蔩蔪蔫蔬蔭蔮蔯蔰蔱蔲蔳蔴蔵蔶蔷蔸蔹蔺蔻蔼蔽蔾蔿蕀蕁蕂蕃蕄蕅蕆蕇蕈蕉蕊蕋蕌蕍蕎蕏蕐蕑蕒蕓蕔蕕蕖蕗蕘蕙蕚蕛蕜蕝蕞蕟蕠蕡蕢蕣蕤蕥蕦蕧蕨蕩蕪蕫蕬蕭蕮蕯蕰蕱蕲蕳蕴蕵蕶蕷蕸蕹蕺蕻蕼蕽蕾蕿薀薁薂薃薄薅薆薇薈薉薊薋薌薍薎薏薐薑薒薓薔薕薖薗薘薙薚薛薜薝薞薟薠薡薢薣薤薥薦薧薨薩薪薫薬薭薮薯薰薱薲薳薴薵薶薷薸薹薺薻薼薽薾薿藀藁藂藃藄藅藆藇藈藉藊藋藌藍藎藏藐藑藒藓藔藕藖藗藘藙藚藛藜藝藞藟藠藡藢藣藤藥藦藧藨藩藪藫藬藭藮藯藰藱藲藳藴藵藶藷藸藹藺藻藼藽藾藿蘀蘁蘂蘃蘄蘅蘆蘇蘈蘉蘊蘋蘌蘍蘎蘏蘐蘑蘒蘓蘔蘕蘖蘗蘘蘙蘚蘛蘜蘝蘞蘟蘠蘡蘢蘣蘤蘥蘦蘧蘨蘩蘪蘫蘬蘭蘮蘯蘰蘱蘲蘳蘴蘵蘶蘷蘸蘹蘺蘻蘼蘽蘾蘿虀虁虂虃虄虅虆虇虈虉虊虋虌虍虎虏虐虑虒虓虔處虖虗虘虙虚虛虜虝虞號虠虡虢虣虤虥虦虧虨虩虪虫虬虭虮虯虰虱虲虳虴虵虶虷虸虹虺虻虼虽虾虿蚀蚁蚂蚃蚄蚅蚆蚇蚈蚉蚊蚋蚌蚍蚎蚏蚐蚑蚒蚓蚔蚕蚖蚗蚘蚙蚚蚛蚜蚝蚞蚟蚠蚡蚢蚣蚤蚥蚦蚧蚨蚩蚪蚫蚬蚭蚮蚯蚰蚱蚲蚳蚴蚵蚶蚷蚸蚹蚺蚻蚼蚽蚾蚿蛀蛁蛂蛃蛄蛅蛆蛇蛈蛉蛊蛋蛌蛍蛎蛏蛐蛑蛒蛓蛔蛕蛖蛗蛘蛙蛚蛛蛜蛝蛞蛟蛠蛡蛢蛣蛤蛥蛦蛧蛨蛩蛪蛫蛬蛭蛮蛯蛰蛱蛲蛳蛴蛵蛶蛷蛸蛹蛺蛻蛼蛽蛾蛿蜀蜁蜂蜃蜄蜅蜆蜇蜈蜉蜊蜋蜌蜍蜎蜏蜐蜑蜒蜓蜔蜕蜖蜗蜘蜙蜚蜛蜜蜝蜞蜟蜠蜡蜢蜣蜤蜥蜦蜧蜨蜩蜪蜫蜬蜭蜮蜯蜰蜱蜲蜳蜴蜵蜶蜷蜸蜹蜺蜻蜼蜽蜾蜿蝀蝁蝂蝃蝄蝅蝆蝇蝈蝉蝊蝋蝌蝍蝎蝏蝐蝑蝒蝓蝔蝕蝖蝗蝘蝙蝚蝛蝜蝝蝞蝟蝠蝡蝢蝣蝤蝥蝦蝧蝨蝩蝪蝫蝬蝭蝮蝯蝰蝱蝲蝳蝴蝵蝶蝷蝸蝹蝺蝻蝼蝽蝾蝿螀螁螂螃螄螅螆螇螈螉螊螋螌融螎螏螐螑螒螓螔螕螖螗螘螙螚螛螜螝螞螟螠螡螢螣螤螥螦螧螨螩螪螫螬螭螮螯螰螱螲螳螴螵螶螷螸螹螺螻螼螽螾螿蟀蟁蟂蟃蟄蟅蟆蟇蟈蟉蟊蟋蟌蟍蟎蟏蟐蟑蟒蟓蟔蟕蟖蟗蟘蟙蟚蟛蟜蟝蟞蟟蟠蟡蟢蟣蟤蟥蟦蟧蟨蟩蟪蟫蟬蟭蟮蟯蟰蟱蟲蟳蟴蟵蟶蟷蟸蟹蟺蟻蟼蟽蟾蟿蠀蠁蠂蠃蠄蠅蠆蠇蠈蠉蠊蠋蠌蠍蠎蠏蠐蠑蠒蠓蠔蠕蠖蠗蠘蠙蠚蠛蠜蠝蠞蠟蠠蠡蠢蠣蠤蠥蠦蠧蠨蠩蠪蠫蠬蠭蠮蠯蠰蠱蠲蠳蠴蠵蠶蠷蠸蠹蠺蠻蠼蠽蠾蠿血衁衂衃衄衅衆衇衈衉衊衋行衍衎衏衐衑衒術衔衕衖街衘衙衚衛衜衝衞衟衠衡衢衣衤补衦衧表衩衪衫衬衭衮衯衰衱衲衳衴衵衶衷衸衹衺衻衼衽衾衿袀袁袂袃袄袅袆袇袈袉袊袋袌袍袎袏袐袑袒袓袔袕袖袗袘袙袚袛袜袝袞袟袠袡袢袣袤袥袦袧袨袩袪被袬袭袮袯袰袱袲袳袴袵袶袷袸袹袺袻袼袽袾袿裀裁裂裃裄装裆裇裈裉裊裋裌裍裎裏裐裑裒裓裔裕裖裗裘裙裚裛補裝裞裟裠裡裢裣裤裥裦裧裨裩裪裫裬裭裮裯裰裱裲裳裴裵裶裷裸裹裺裻裼製裾裿褀褁褂褃褄褅褆複褈褉褊褋褌褍褎褏褐褑褒褓褔褕褖褗褘褙褚褛褜褝褞褟褠褡褢褣褤褥褦褧褨褩褪褫褬褭褮褯褰褱褲褳褴褵褶褷褸褹褺褻褼褽褾褿襀襁襂襃襄襅襆襇襈襉襊襋襌襍襎襏襐襑襒襓襔襕襖襗襘襙襚襛襜襝襞襟襠襡襢襣襤襥襦襧襨襩襪襫襬襭襮襯襰襱襲襳襴襵襶襷襸襹襺襻襼襽襾西覀要覂覃覄覅覆覇覈覉覊見覌覍覎規覐覑覒覓覔覕視覗覘覙覚覛覜覝覞覟覠覡覢覣覤覥覦覧覨覩親覫覬覭覮覯覰覱覲観覴覵覶覷覸覹覺覻覼覽覾覿觀见观觃规觅视觇览觉觊觋觌觍觎觏觐觑角觓觔觕觖觗觘觙觚觛觜觝觞觟觠觡觢解觤觥触觧觨觩觪觫觬觭觮觯觰觱觲觳觴觵觶觷觸觹觺觻觼觽觾觿言訁訂訃訄訅訆訇計訉訊訋訌訍討訏訐訑訒訓訔訕訖託記訙訚訛訜訝訞訟訠訡訢訣訤訥訦訧訨訩訪訫訬設訮訯訰許訲訳訴訵訶訷訸訹診註証訽訾訿詀詁詂詃詄詅詆詇詈詉詊詋詌詍詎詏詐詑詒詓詔評詖詗詘詙詚詛詜詝詞詟詠詡詢詣詤詥試詧詨詩詪詫詬詭詮詯詰話該詳詴詵詶詷詸詹詺詻詼詽詾詿誀誁誂誃誄誅誆誇誈誉誊誋誌認誎誏誐誑誒誓誔誕誖誗誘誙誚誛誜誝語誟誠誡誢誣誤誥誦誧誨誩說誫説読誮誯誰誱課誳誴誵誶誷誸誹誺誻誼誽誾調諀諁諂諃諄諅諆談諈諉諊請諌諍諎諏諐諑諒諓諔諕論諗諘諙諚諛諜諝諞諟諠諡諢諣諤諥諦諧諨諩諪諫諬諭諮諯諰諱諲諳諴諵諶諷諸諹諺諻諼諽諾諿謀謁謂謃謄謅謆謇謈謉謊謋謌謍謎謏謐謑謒謓謔謕謖謗謘謙謚講謜謝謞謟謠謡謢謣謤謥謦謧謨謩謪謫謬謭謮謯謰謱謲謳謴謵謶謷謸謹謺謻謼謽謾謿譀譁譂譃譄譅譆譇譈證譊譋譌譍譎譏譐譑譒譓譔譕譖譗識譙譚譛譜譝譞譟譠譡譢譣譤譥警譧譨譩譪譫譬譭譮譯議譱譲譳譴譵譶護譸譹譺譻譼譽譾譿讀讁讂讃讄讅讆讇讈讉變讋讌讍讎讏讐讑讒讓讔讕讖讗讘讙讚讛讜讝讞讟讠计订讣认讥讦讧讨让讪讫讬训议讯记讱讲讳讴讵讶讷许讹论讻讼讽设访诀证诂诃评诅识诇诈诉诊诋诌词诎诏诐译诒诓诔试诖诗诘诙诚诛诜话诞诟诠诡询诣诤该详诧诨诩诪诫诬语诮误诰诱诲诳说诵诶请诸诹诺读诼诽课诿谀谁谂调谄谅谆谇谈谉谊谋谌谍谎谏谐谑谒谓谔谕谖谗谘谙谚谛谜谝谞谟谠谡谢谣谤谥谦谧谨谩谪谫谬谭谮谯谰谱谲谳谴谵谶谷谸谹谺谻谼谽谾谿豀豁豂豃豄豅豆豇豈豉豊豋豌豍豎豏豐豑豒豓豔豕豖豗豘豙豚豛豜豝豞豟豠象豢豣豤豥豦豧豨豩豪豫豬豭豮豯豰豱豲豳豴豵豶豷豸豹豺豻豼豽豾豿貀貁貂貃貄貅貆貇貈貉貊貋貌貍貎貏貐貑貒貓貔貕貖貗貘貙貚貛貜貝貞貟負財貢貣貤貥貦貧貨販貪貫責貭貮貯貰貱貲貳貴貵貶買貸貹貺費貼貽貾貿賀賁賂賃賄賅賆資賈賉賊賋賌賍賎賏賐賑賒賓賔賕賖賗賘賙賚賛賜賝賞賟賠賡賢賣賤賥賦賧賨賩質賫賬賭賮賯賰賱賲賳賴賵賶賷賸賹賺賻購賽賾賿贀贁贂贃贄贅贆贇贈贉贊贋贌贍贎贏贐贑贒贓贔贕贖贗贘贙贚贛贜贝贞负贠贡财责贤败账货质贩贪贫贬购贮贯贰贱贲贳贴贵贶贷贸费贺贻贼贽贾贿赀赁赂赃资赅赆赇赈赉赊赋赌赍赎赏赐赑赒赓赔赕赖赗赘赙赚赛赜赝赞赟赠赡赢赣赤赥赦赧赨赩赪赫赬赭赮赯走赱赲赳赴赵赶起赸赹赺赻赼赽赾赿趀趁趂趃趄超趆趇趈趉越趋趌趍趎趏趐趑趒趓趔趕趖趗趘趙趚趛趜趝趞趟趠趡趢趣趤趥趦趧趨趩趪趫趬趭趮趯趰趱趲足趴趵趶趷趸趹趺趻趼趽趾趿跀跁跂跃跄跅跆跇跈跉跊跋跌跍跎跏跐跑跒跓跔跕跖跗跘跙跚跛跜距跞跟跠跡跢跣跤跥跦跧跨跩跪跫跬跭跮路跰跱跲跳跴践跶跷跸跹跺跻跼跽跾跿踀踁踂踃踄踅踆踇踈踉踊踋踌踍踎踏踐踑踒踓踔踕踖踗踘踙踚踛踜踝踞踟踠踡踢踣踤踥踦踧踨踩踪踫踬踭踮踯踰踱踲踳踴踵踶踷踸踹踺踻踼踽踾踿蹀蹁蹂蹃蹄蹅蹆蹇蹈蹉蹊蹋蹌蹍蹎蹏蹐蹑蹒蹓蹔蹕蹖蹗蹘蹙蹚蹛蹜蹝蹞蹟蹠蹡蹢蹣蹤蹥蹦蹧蹨蹩蹪蹫蹬蹭蹮蹯蹰蹱蹲蹳蹴蹵蹶蹷蹸蹹蹺蹻蹼蹽蹾蹿躀躁躂躃躄躅躆躇躈躉躊躋躌躍躎躏躐躑躒躓躔躕躖躗躘躙躚躛躜躝躞躟躠躡躢躣躤躥躦躧躨躩躪身躬躭躮躯躰躱躲躳躴躵躶躷躸躹躺躻躼躽躾躿軀軁軂軃軄軅軆軇軈軉車軋軌軍軎軏軐軑軒軓軔軕軖軗軘軙軚軛軜軝軞軟軠軡転軣軤軥軦軧軨軩軪軫軬軭軮軯軰軱軲軳軴軵軶軷軸軹軺軻軼軽軾軿輀輁輂較輄輅輆輇輈載輊輋輌輍輎輏輐輑輒輓輔輕輖輗輘輙輚輛輜輝輞輟輠輡輢輣輤輥輦輧輨輩輪輫輬輭輮輯輰輱輲輳輴輵輶輷輸輹輺輻輼輽輾輿轀轁轂轃轄轅轆轇轈轉轊轋轌轍轎轏轐轑轒轓轔轕轖轗轘轙轚轛轜轝轞轟轠轡轢轣轤轥车轧轨轩轪轫转轭轮软轰轱轲轳轴轵轶轷轸轹轺轻轼载轾轿辀辁辂较辄辅辆辇辈辉辊辋辌辍辎辏辐辑辒输辔辕辖辗辘辙辚辛辜辝辞辟辠辡辢辣辤辥辦辧辨辩辪辫辬辭辮辯辰辱農辳辴辵辶辷辸边辺辻込辽达辿迀迁迂迃迄迅迆过迈迉迊迋迌迍迎迏运近迒迓返迕迖迗还这迚进远违连迟迠迡迢迣迤迥迦迧迨迩迪迫迬迭迮迯述迱迲迳迴迵迶迷迸迹迺迻迼追迾迿退送适逃逄逅逆逇逈选逊逋逌逍逎透逐逑递逓途逕逖逗逘這通逛逜逝逞速造逡逢連逤逥逦逧逨逩逪逫逬逭逮逯逰週進逳逴逵逶逷逸逹逺逻逼逽逾逿遀遁遂遃遄遅遆遇遈遉遊運遌遍過遏遐遑遒道達違遖遗遘遙遚遛遜遝遞遟遠遡遢遣遤遥遦遧遨適遪遫遬遭遮遯遰遱遲遳遴遵遶遷選遹遺遻遼遽遾避邀邁邂邃還邅邆邇邈邉邊邋邌邍邎邏邐邑邒邓邔邕邖邗邘邙邚邛邜邝邞邟邠邡邢那邤邥邦邧邨邩邪邫邬邭邮邯邰邱邲邳邴邵邶邷邸邹邺邻邼邽邾邿郀郁郂郃郄郅郆郇郈郉郊郋郌郍郎郏郐郑郒郓郔郕郖郗郘郙郚郛郜郝郞郟郠郡郢郣郤郥郦郧部郩郪郫郬郭郮郯郰郱郲郳郴郵郶郷郸郹郺郻郼都郾郿鄀鄁鄂鄃鄄鄅鄆鄇鄈鄉鄊鄋鄌鄍鄎鄏鄐鄑鄒鄓鄔鄕鄖鄗鄘鄙鄚鄛鄜鄝鄞鄟鄠鄡鄢鄣鄤鄥鄦鄧鄨鄩鄪鄫鄬鄭鄮鄯鄰鄱鄲鄳鄴鄵鄶鄷鄸鄹鄺鄻鄼鄽鄾鄿酀酁酂酃酄酅酆酇酈酉酊酋酌配酎酏酐酑酒酓酔酕酖酗酘酙酚酛酜酝酞酟酠酡酢酣酤酥酦酧酨酩酪酫酬酭酮酯酰酱酲酳酴酵酶酷酸酹酺酻酼酽酾酿醀醁醂醃醄醅醆醇醈醉醊醋醌醍醎醏醐醑醒醓醔醕醖醗醘醙醚醛醜醝醞醟醠醡醢醣醤醥醦醧醨醩醪醫醬醭醮醯醰醱醲醳醴醵醶醷醸醹醺醻醼醽醾醿釀釁釂釃釄釅釆采釈釉释釋里重野量釐金釒釓釔釕釖釗釘釙釚釛釜針釞釟釠釡釢釣釤釥釦釧釨釩釪釫釬釭釮釯釰釱釲釳釴釵釶釷釸釹釺釻釼釽釾釿鈀鈁鈂鈃鈄鈅鈆鈇鈈鈉鈊鈋鈌鈍鈎鈏鈐鈑鈒鈓鈔鈕鈖鈗鈘鈙鈚鈛鈜鈝鈞鈟鈠鈡鈢鈣鈤鈥鈦鈧鈨鈩鈪鈫鈬鈭鈮鈯鈰鈱鈲鈳鈴鈵鈶鈷鈸鈹鈺鈻鈼鈽鈾鈿鉀鉁鉂鉃鉄鉅鉆鉇鉈鉉鉊鉋鉌鉍鉎鉏鉐鉑鉒鉓鉔鉕鉖鉗鉘鉙鉚鉛鉜鉝鉞鉟鉠鉡鉢鉣鉤鉥鉦鉧鉨鉩鉪鉫鉬鉭鉮鉯鉰鉱鉲鉳鉴鉵鉶鉷鉸鉹鉺鉻鉼鉽鉾鉿銀銁銂銃銄銅銆銇銈銉銊銋銌銍銎銏銐銑銒銓銔銕銖銗銘銙銚銛銜銝銞銟銠銡銢銣銤銥銦銧銨銩銪銫銬銭銮銯銰銱銲銳銴銵銶銷銸銹銺銻銼銽銾銿鋀鋁鋂鋃鋄鋅鋆鋇鋈鋉鋊鋋鋌鋍鋎鋏鋐鋑鋒鋓鋔鋕鋖鋗鋘鋙鋚鋛鋜鋝鋞鋟鋠鋡鋢鋣鋤鋥鋦鋧鋨鋩鋪鋫鋬鋭鋮鋯鋰鋱鋲鋳鋴鋵鋶鋷鋸鋹鋺鋻鋼鋽鋾鋿錀錁錂錃錄錅錆錇錈錉錊錋錌錍錎錏錐錑錒錓錔錕錖錗錘錙錚錛錜錝錞錟錠錡錢錣錤錥錦錧錨錩錪錫錬錭錮錯錰錱録錳錴錵錶錷錸錹錺錻錼錽錾錿鍀鍁鍂鍃鍄鍅鍆鍇鍈鍉鍊鍋鍌鍍鍎鍏鍐鍑鍒鍓鍔鍕鍖鍗鍘鍙鍚鍛鍜鍝鍞鍟鍠鍡鍢鍣鍤鍥鍦鍧鍨鍩鍪鍫鍬鍭鍮鍯鍰鍱鍲鍳鍴鍵鍶鍷鍸鍹鍺鍻鍼鍽鍾鍿鎀鎁鎂鎃鎄鎅鎆鎇鎈鎉鎊鎋鎌鎍鎎鎏鎐鎑鎒鎓鎔鎕鎖鎗鎘鎙鎚鎛鎜鎝鎞鎟鎠鎡鎢鎣鎤鎥鎦鎧鎨鎩鎪鎫鎬鎭鎮鎯鎰鎱鎲鎳鎴鎵鎶鎷鎸鎹鎺鎻鎼鎽鎾鎿鏀鏁鏂鏃鏄鏅鏆鏇鏈鏉鏊鏋鏌鏍鏎鏏鏐鏑鏒鏓鏔鏕鏖鏗鏘鏙鏚鏛鏜鏝鏞鏟鏠鏡鏢鏣鏤鏥鏦鏧鏨鏩鏪鏫鏬鏭鏮鏯鏰鏱鏲鏳鏴鏵鏶鏷鏸鏹鏺鏻鏼鏽鏾鏿鐀鐁鐂鐃鐄鐅鐆鐇鐈鐉鐊鐋鐌鐍鐎鐏鐐鐑鐒鐓鐔鐕鐖鐗鐘鐙鐚鐛鐜鐝鐞鐟鐠鐡鐢鐣鐤鐥鐦鐧鐨鐩鐪鐫鐬鐭鐮鐯鐰鐱鐲鐳鐴鐵鐶鐷鐸鐹鐺鐻鐼鐽鐾鐿鑀鑁鑂鑃鑄鑅鑆鑇鑈鑉鑊鑋鑌鑍鑎鑏鑐鑑鑒鑓鑔鑕鑖鑗鑘鑙鑚鑛鑜鑝鑞鑟鑠鑡鑢鑣鑤鑥鑦鑧鑨鑩鑪鑫鑬鑭鑮鑯鑰鑱鑲鑳鑴鑵鑶鑷鑸鑹鑺鑻鑼鑽鑾鑿钀钁钂钃钄钅钆钇针钉钊钋钌钍钎钏钐钑钒钓钔钕钖钗钘钙钚钛钜钝钞钟钠钡钢钣钤钥钦钧钨钩钪钫钬钭钮钯钰钱钲钳钴钵钶钷钸钹钺钻钼钽钾钿铀铁铂铃铄铅铆铇铈铉铊铋铌铍铎铏铐铑铒铓铔铕铖铗铘铙铚铛铜铝铞铟铠铡铢铣铤铥铦铧铨铩铪铫铬铭铮铯铰铱铲铳铴铵银铷铸铹铺铻铼铽链铿销锁锂锃锄锅锆锇锈锉锊锋锌锍锎锏锐锑锒锓锔锕锖锗锘错锚锛锜锝锞锟锠锡锢锣锤锥锦锧锨锩锪锫锬锭键锯锰锱锲锳锴锵锶锷锸锹锺锻锼锽锾锿镀镁镂镃镄镅镆镇镈镉镊镋镌镍镎镏镐镑镒镓镔镕镖镗镘镙镚镛镜镝镞镟镠镡镢镣镤镥镦镧镨镩镪镫镬镭镮镯镰镱镲镳镴镵镶長镸镹镺镻镼镽镾长門閁閂閃閄閅閆閇閈閉閊開閌閍閎閏閐閑閒間閔閕閖閗閘閙閚閛閜閝閞閟閠閡関閣閤閥閦閧閨閩閪閫閬閭閮閯閰閱閲閳閴閵閶閷閸閹閺閻閼閽閾閿闀闁闂闃闄闅闆闇闈闉闊闋闌闍闎闏闐闑闒闓闔闕闖闗闘闙闚闛關闝闞闟闠闡闢闣闤闥闦闧门闩闪闫闬闭问闯闰闱闲闳间闵闶闷闸闹闺闻闼闽闾闿阀阁阂阃阄阅阆阇阈阉阊阋阌阍阎阏阐阑阒阓阔阕阖阗阘阙阚阛阜阝阞队阠阡阢阣阤阥阦阧阨阩阪阫阬阭阮阯阰阱防阳阴阵阶阷阸阹阺阻阼阽阾阿陀陁陂陃附际陆陇陈陉陊陋陌降陎陏限陑陒陓陔陕陖陗陘陙陚陛陜陝陞陟陠陡院陣除陥陦陧陨险陪陫陬陭陮陯陰陱陲陳陴陵陶陷陸陹険陻陼陽陾陿隀隁隂隃隄隅隆隇隈隉隊隋隌隍階随隐隑隒隓隔隕隖隗隘隙隚際障隝隞隟隠隡隢隣隤隥隦隧隨隩險隫隬隭隮隯隰隱隲隳隴隵隶隷隸隹隺隻隼隽难隿雀雁雂雃雄雅集雇雈雉雊雋雌雍雎雏雐雑雒雓雔雕雖雗雘雙雚雛雜雝雞雟雠雡離難雤雥雦雧雨雩雪雫雬雭雮雯雰雱雲雳雴雵零雷雸雹雺電雼雽雾雿需霁霂霃霄霅霆震霈霉霊霋霌霍霎霏霐霑霒霓霔霕霖霗霘霙霚霛霜霝霞霟霠霡霢霣霤霥霦霧霨霩霪霫霬霭霮霯霰霱露霳霴霵霶霷霸霹霺霻霼霽霾霿靀靁靂靃靄靅靆靇靈靉靊靋靌靍靎靏靐靑青靓靔靕靖靗靘静靚靛靜靝非靟靠靡面靣靤靥靦靧靨革靪靫靬靭靮靯靰靱靲靳靴靵靶靷靸靹靺靻靼靽靾靿鞀鞁鞂鞃鞄鞅鞆鞇鞈鞉鞊鞋鞌鞍鞎鞏鞐鞑鞒鞓鞔鞕鞖鞗鞘鞙鞚鞛鞜鞝鞞鞟鞠鞡鞢鞣鞤鞥鞦鞧鞨鞩鞪鞫鞬鞭鞮鞯鞰鞱鞲鞳鞴鞵鞶鞷鞸鞹鞺鞻鞼鞽鞾鞿韀韁韂韃韄韅韆韇韈韉韊韋韌韍韎韏韐韑韒韓韔韕韖韗韘韙韚韛韜韝韞韟韠韡韢韣韤韥韦韧韨韩韪韫韬韭韮韯韰韱韲音韴韵韶韷韸韹韺韻韼韽韾響頀頁頂頃頄項順頇須頉頊頋頌頍頎頏預頑頒頓頔頕頖頗領頙頚頛頜頝頞頟頠頡頢頣頤頥頦頧頨頩頪頫頬頭頮頯頰頱頲頳頴頵頶頷頸頹頺頻頼頽頾頿顀顁顂顃顄顅顆顇顈顉顊顋題額顎顏顐顑顒顓顔顕顖顗願顙顚顛顜顝類顟顠顡顢顣顤顥顦顧顨顩顪顫顬顭顮顯顰顱顲顳顴页顶顷顸项顺须顼顽顾顿颀颁颂颃预颅领颇颈颉颊颋颌颍颎颏颐频颒颓颔颕颖颗题颙颚颛颜额颞颟颠颡颢颣颤颥颦颧風颩颪颫颬颭颮颯颰颱颲颳颴颵颶颷颸颹颺颻颼颽颾颿飀飁飂飃飄飅飆飇飈飉飊飋飌飍风飏飐飑飒飓飔飕飖飗飘飙飚飛飜飝飞食飠飡飢飣飤飥飦飧飨飩飪飫飬飭飮飯飰飱飲飳飴飵飶飷飸飹飺飻飼飽飾飿餀餁餂餃餄餅餆餇餈餉養餋餌餍餎餏餐餑餒餓餔餕餖餗餘餙餚餛餜餝餞餟餠餡餢餣餤餥餦餧館餩餪餫餬餭餮餯餰餱餲餳餴餵餶餷餸餹餺餻餼餽餾餿饀饁饂饃饄饅饆饇饈饉饊饋饌饍饎饏饐饑饒饓饔饕饖饗饘饙饚饛饜饝饞饟饠饡饢饣饤饥饦饧饨饩饪饫饬饭饮饯饰饱饲饳饴饵饶饷饸饹饺饻饼饽饾饿馀馁馂馃馄馅馆馇馈馉馊馋馌馍馎馏馐馑馒馓馔馕首馗馘香馚馛馜馝馞馟馠馡馢馣馤馥馦馧馨馩馪馫馬馭馮馯馰馱馲馳馴馵馶馷馸馹馺馻馼馽馾馿駀駁駂駃駄駅駆駇駈駉駊駋駌駍駎駏駐駑駒駓駔駕駖駗駘駙駚駛駜駝駞駟駠駡駢駣駤駥駦駧駨駩駪駫駬駭駮駯駰駱駲駳駴駵駶駷駸駹駺駻駼駽駾駿騀騁騂騃騄騅騆騇騈騉騊騋騌騍騎騏騐騑騒験騔騕騖騗騘騙騚騛騜騝騞騟騠騡騢騣騤騥騦騧騨騩騪騫騬騭騮騯騰騱騲騳騴騵騶騷騸騹騺騻騼騽騾騿驀驁驂驃驄驅驆驇驈驉驊驋驌驍驎驏驐驑驒驓驔驕驖驗驘驙驚驛驜驝驞驟驠驡驢驣驤驥驦驧驨驩驪驫马驭驮驯驰驱驲驳驴驵驶驷驸驹驺驻驼驽驾驿骀骁骂骃骄骅骆骇骈骉骊骋验骍骎骏骐骑骒骓骔骕骖骗骘骙骚骛骜骝骞骟骠骡骢骣骤骥骦骧骨骩骪骫骬骭骮骯骰骱骲骳骴骵骶骷骸骹骺骻骼骽骾骿髀髁髂髃髄髅髆髇髈髉髊髋髌髍髎髏髐髑髒髓體髕髖髗高髙髚髛髜髝髞髟髠髡髢髣髤髥髦髧髨髩髪髫髬髭髮髯髰髱髲髳髴髵髶髷髸髹髺髻髼髽髾髿鬀鬁鬂鬃鬄鬅鬆鬇鬈鬉鬊鬋鬌鬍鬎鬏鬐鬑鬒鬓鬔鬕鬖鬗鬘鬙鬚鬛鬜鬝鬞鬟鬠鬡鬢鬣鬤鬥鬦鬧鬨鬩鬪鬫鬬鬭鬮鬯鬰鬱鬲鬳鬴鬵鬶鬷鬸鬹鬺鬻鬼鬽鬾鬿魀魁魂魃魄魅魆魇魈魉魊魋魌魍魎魏魐魑魒魓魔魕魖魗魘魙魚魛魜魝魞魟魠魡魢魣魤魥魦魧魨魩魪魫魬魭魮魯魰魱魲魳魴魵魶魷魸魹魺魻魼魽魾魿鮀鮁鮂鮃鮄鮅鮆鮇鮈鮉鮊鮋鮌鮍鮎鮏鮐鮑鮒鮓鮔鮕鮖鮗鮘鮙鮚鮛鮜鮝鮞鮟鮠鮡鮢鮣鮤鮥鮦鮧鮨鮩鮪鮫鮬鮭鮮鮯鮰鮱鮲鮳鮴鮵鮶鮷鮸鮹鮺鮻鮼鮽鮾鮿鯀鯁鯂鯃鯄鯅鯆鯇鯈鯉鯊鯋鯌鯍鯎鯏鯐鯑鯒鯓鯔鯕鯖鯗鯘鯙鯚鯛鯜鯝鯞鯟鯠鯡鯢鯣鯤鯥鯦鯧鯨鯩鯪鯫鯬鯭鯮鯯鯰鯱鯲鯳鯴鯵鯶鯷鯸鯹鯺鯻鯼鯽鯾鯿鰀鰁鰂鰃鰄鰅鰆鰇鰈鰉鰊鰋鰌鰍鰎鰏鰐鰑鰒鰓鰔鰕鰖鰗鰘鰙鰚鰛鰜鰝鰞鰟鰠鰡鰢鰣鰤鰥鰦鰧鰨鰩鰪鰫鰬鰭鰮鰯鰰鰱鰲鰳鰴鰵鰶鰷鰸鰹鰺鰻鰼鰽鰾鰿鱀鱁鱂鱃鱄鱅鱆鱇鱈鱉鱊鱋鱌鱍鱎鱏鱐鱑鱒鱓鱔鱕鱖鱗鱘鱙鱚鱛鱜鱝鱞鱟鱠鱡鱢鱣鱤鱥鱦鱧鱨鱩鱪鱫鱬鱭鱮鱯鱰鱱鱲鱳鱴鱵鱶鱷鱸鱹鱺鱻鱼鱽鱾鱿鲀鲁鲂鲃鲄鲅鲆鲇鲈鲉鲊鲋鲌鲍鲎鲏鲐鲑鲒鲓鲔鲕鲖鲗鲘鲙鲚鲛鲜鲝鲞鲟鲠鲡鲢鲣鲤鲥鲦鲧鲨鲩鲪鲫鲬鲭鲮鲯鲰鲱鲲鲳鲴鲵鲶鲷鲸鲹鲺鲻鲼鲽鲾鲿鳀鳁鳂鳃鳄鳅鳆鳇鳈鳉鳊鳋鳌鳍鳎鳏鳐鳑鳒鳓鳔鳕鳖鳗鳘鳙鳚鳛鳜鳝鳞鳟鳠鳡鳢鳣鳤鳥鳦鳧鳨鳩鳪鳫鳬鳭鳮鳯鳰鳱鳲鳳鳴鳵鳶鳷鳸鳹鳺鳻鳼鳽鳾鳿鴀鴁鴂鴃鴄鴅鴆鴇鴈鴉鴊鴋鴌鴍鴎鴏鴐鴑鴒鴓鴔鴕鴖鴗鴘鴙鴚鴛鴜鴝鴞鴟鴠鴡鴢鴣鴤鴥鴦鴧鴨鴩鴪鴫鴬鴭鴮鴯鴰鴱鴲鴳鴴鴵鴶鴷鴸鴹鴺鴻鴼鴽鴾鴿鵀鵁鵂鵃鵄鵅鵆鵇鵈鵉鵊鵋鵌鵍鵎鵏鵐鵑鵒鵓鵔鵕鵖鵗鵘鵙鵚鵛鵜鵝鵞鵟鵠鵡鵢鵣鵤鵥鵦鵧鵨鵩鵪鵫鵬鵭鵮鵯鵰鵱鵲鵳鵴鵵鵶鵷鵸鵹鵺鵻鵼鵽鵾鵿鶀鶁鶂鶃鶄鶅鶆鶇鶈鶉鶊鶋鶌鶍鶎鶏鶐鶑鶒鶓鶔鶕鶖鶗鶘鶙鶚鶛鶜鶝鶞鶟鶠鶡鶢鶣鶤鶥鶦鶧鶨鶩鶪鶫鶬鶭鶮鶯鶰鶱鶲鶳鶴鶵鶶鶷鶸鶹鶺鶻鶼鶽鶾鶿鷀鷁鷂鷃鷄鷅鷆鷇鷈鷉鷊鷋鷌鷍鷎鷏鷐鷑鷒鷓鷔鷕鷖鷗鷘鷙鷚鷛鷜鷝鷞鷟鷠鷡鷢鷣鷤鷥鷦鷧鷨鷩鷪鷫鷬鷭鷮鷯鷰鷱鷲鷳鷴鷵鷶鷷鷸鷹鷺鷻鷼鷽鷾鷿鸀鸁鸂鸃鸄鸅鸆鸇鸈鸉鸊鸋鸌鸍鸎鸏鸐鸑鸒鸓鸔鸕鸖鸗鸘鸙鸚鸛鸜鸝鸞鸟鸠鸡鸢鸣鸤鸥鸦鸧鸨鸩鸪鸫鸬鸭鸮鸯鸰鸱鸲鸳鸴鸵鸶鸷鸸鸹鸺鸻鸼鸽鸾鸿鹀鹁鹂鹃鹄鹅鹆鹇鹈鹉鹊鹋鹌鹍鹎鹏鹐鹑鹒鹓鹔鹕鹖鹗鹘鹙鹚鹛鹜鹝鹞鹟鹠鹡鹢鹣鹤鹥鹦鹧鹨鹩鹪鹫鹬鹭鹮鹯鹰鹱鹲鹳鹴鹵鹶鹷鹸鹹鹺鹻鹼鹽鹾鹿麀麁麂麃麄麅麆麇麈麉麊麋麌麍麎麏麐麑麒麓麔麕麖麗麘麙麚麛麜麝麞麟麠麡麢麣麤麥麦麧麨麩麪麫麬麭麮麯麰麱麲麳麴麵麶麷麸麹麺麻麼麽麾麿黀黁黂黃黄黅黆黇黈黉黊黋黌黍黎黏黐黑黒黓黔黕黖黗默黙黚黛黜黝點黟黠黡黢黣黤黥黦黧黨黩黪黫黬黭黮黯黰黱黲黳黴黵黶黷黸黹黺黻黼黽黾黿鼀鼁鼂鼃鼄鼅鼆鼇鼈鼉鼊鼋鼌鼍鼎鼏鼐鼑鼒鼓鼔鼕鼖鼗鼘鼙鼚鼛鼜鼝鼞鼟鼠鼡鼢鼣鼤鼥鼦鼧鼨鼩鼪鼫鼬鼭鼮鼯鼰鼱鼲鼳鼴鼵鼶鼷鼸鼹鼺鼻鼼鼽鼾鼿齀齁齂齃齄齅齆齇齈齉齊齋齌齍齎齏齐齑齒齓齔齕齖齗齘齙齚齛齜齝齞齟齠齡齢齣齤齥齦齧齨齩齪齫齬齭齮齯齰齱齲齳齴齵齶齷齸齹齺齻齼齽齾齿龀龁龂龃龄龅龆龇龈龉龊龋龌龍龎龏龐龑龒龓龔龕龖龗龘龙龚龛龜龝龞龟龠龡龢龣龤龥龦龧龨龩龪龫龬龭龮龯龰龱龲龳龴龵龶龷龸龹龺龻龼龽龾龿鿀鿁鿂鿃鿄鿅鿆鿇鿈鿉鿊鿋鿌ꀀꀁꀂꀃꀄꀅꀆꀇꀈꀉꀊꀋꀌꀍꀎꀏꀐꀑꀒꀓꀔꀕꀖꀗꀘꀙꀚꀛꀜꀝꀞꀟꀠꀡꀢꀣꀤꀥꀦꀧꀨꀩꀪꀫꀬꀭꀮꀯꀰꀱꀲꀳꀴꀵꀶꀷꀸꀹꀺꀻꀼꀽꀾꀿꁀꁁꁂꁃꁄꁅꁆꁇꁈꁉꁊꁋꁌꁍꁎꁏꁐꁑꁒꁓꁔꁕꁖꁗꁘꁙꁚꁛꁜꁝꁞꁟꁠꁡꁢꁣꁤꁥꁦꁧꁨꁩꁪꁫꁬꁭꁮꁯꁰꁱꁲꁳꁴꁵꁶꁷꁸꁹꁺꁻꁼꁽꁾꁿꂀꂁꂂꂃꂄꂅꂆꂇꂈꂉꂊꂋꂌꂍꂎꂏꂐꂑꂒꂓꂔꂕꂖꂗꂘꂙꂚꂛꂜꂝꂞꂟꂠꂡꂢꂣꂤꂥꂦꂧꂨꂩꂪꂫꂬꂭꂮꂯꂰꂱꂲꂳꂴꂵꂶꂷꂸꂹꂺꂻꂼꂽꂾꂿꃀꃁꃂꃃꃄꃅꃆꃇꃈꃉꃊꃋꃌꃍꃎꃏꃐꃑꃒꃓꃔꃕꃖꃗꃘꃙꃚꃛꃜꃝꃞꃟꃠꃡꃢꃣꃤꃥꃦꃧꃨꃩꃪꃫꃬꃭꃮꃯꃰꃱꃲꃳꃴꃵꃶꃷꃸꃹꃺꃻꃼꃽꃾꃿꄀꄁꄂꄃꄄꄅꄆꄇꄈꄉꄊꄋꄌꄍꄎꄏꄐꄑꄒꄓꄔꄕꄖꄗꄘꄙꄚꄛꄜꄝꄞꄟꄠꄡꄢꄣꄤꄥꄦꄧꄨꄩꄪꄫꄬꄭꄮꄯꄰꄱꄲꄳꄴꄵꄶꄷꄸꄹꄺꄻꄼꄽꄾꄿꅀꅁꅂꅃꅄꅅꅆꅇꅈꅉꅊꅋꅌꅍꅎꅏꅐꅑꅒꅓꅔꅕꅖꅗꅘꅙꅚꅛꅜꅝꅞꅟꅠꅡꅢꅣꅤꅥꅦꅧꅨꅩꅪꅫꅬꅭꅮꅯꅰꅱꅲꅳꅴꅵꅶꅷꅸꅹꅺꅻꅼꅽꅾꅿꆀꆁꆂꆃꆄꆅꆆꆇꆈꆉꆊꆋꆌꆍꆎꆏꆐꆑꆒꆓꆔꆕꆖꆗꆘꆙꆚꆛꆜꆝꆞꆟꆠꆡꆢꆣꆤꆥꆦꆧꆨꆩꆪꆫꆬꆭꆮꆯꆰꆱꆲꆳꆴꆵꆶꆷꆸꆹꆺꆻꆼꆽꆾꆿꇀꇁꇂꇃꇄꇅꇆꇇꇈꇉꇊꇋꇌꇍꇎꇏꇐꇑꇒꇓꇔꇕꇖꇗꇘꇙꇚꇛꇜꇝꇞꇟꇠꇡꇢꇣꇤꇥꇦꇧꇨꇩꇪꇫꇬꇭꇮꇯꇰꇱꇲꇳꇴꇵꇶꇷꇸꇹꇺꇻꇼꇽꇾꇿꈀꈁꈂꈃꈄꈅꈆꈇꈈꈉꈊꈋꈌꈍꈎꈏꈐꈑꈒꈓꈔꈕꈖꈗꈘꈙꈚꈛꈜꈝꈞꈟꈠꈡꈢꈣꈤꈥꈦꈧꈨꈩꈪꈫꈬꈭꈮꈯꈰꈱꈲꈳꈴꈵꈶꈷꈸꈹꈺꈻꈼꈽꈾꈿꉀꉁꉂꉃꉄꉅꉆꉇꉈꉉꉊꉋꉌꉍꉎꉏꉐꉑꉒꉓꉔꉕꉖꉗꉘꉙꉚꉛꉜꉝꉞꉟꉠꉡꉢꉣꉤꉥꉦꉧꉨꉩꉪꉫꉬꉭꉮꉯꉰꉱꉲꉳꉴꉵꉶꉷꉸꉹꉺꉻꉼꉽꉾꉿꊀꊁꊂꊃꊄꊅꊆꊇꊈꊉꊊꊋꊌꊍꊎꊏꊐꊑꊒꊓꊔꊕꊖꊗꊘꊙꊚꊛꊜꊝꊞꊟꊠꊡꊢꊣꊤꊥꊦꊧꊨꊩꊪꊫꊬꊭꊮꊯꊰꊱꊲꊳꊴꊵꊶꊷꊸꊹꊺꊻꊼꊽꊾꊿꋀꋁꋂꋃꋄꋅꋆꋇꋈꋉꋊꋋꋌꋍꋎꋏꋐꋑꋒꋓꋔꋕꋖꋗꋘꋙꋚꋛꋜꋝꋞꋟꋠꋡꋢꋣꋤꋥꋦꋧꋨꋩꋪꋫꋬꋭꋮꋯꋰꋱꋲꋳꋴꋵꋶꋷꋸꋹꋺꋻꋼꋽꋾꋿꌀꌁꌂꌃꌄꌅꌆꌇꌈꌉꌊꌋꌌꌍꌎꌏꌐꌑꌒꌓꌔꌕꌖꌗꌘꌙꌚꌛꌜꌝꌞꌟꌠꌡꌢꌣꌤꌥꌦꌧꌨꌩꌪꌫꌬꌭꌮꌯꌰꌱꌲꌳꌴꌵꌶꌷꌸꌹꌺꌻꌼꌽꌾꌿꍀꍁꍂꍃꍄꍅꍆꍇꍈꍉꍊꍋꍌꍍꍎꍏꍐꍑꍒꍓꍔꍕꍖꍗꍘꍙꍚꍛꍜꍝꍞꍟꍠꍡꍢꍣꍤꍥꍦꍧꍨꍩꍪꍫꍬꍭꍮꍯꍰꍱꍲꍳꍴꍵꍶꍷꍸꍹꍺꍻꍼꍽꍾꍿꎀꎁꎂꎃꎄꎅꎆꎇꎈꎉꎊꎋꎌꎍꎎꎏꎐꎑꎒꎓꎔꎕꎖꎗꎘꎙꎚꎛꎜꎝꎞꎟꎠꎡꎢꎣꎤꎥꎦꎧꎨꎩꎪꎫꎬꎭꎮꎯꎰꎱꎲꎳꎴꎵꎶꎷꎸꎹꎺꎻꎼꎽꎾꎿꏀꏁꏂꏃꏄꏅꏆꏇꏈꏉꏊꏋꏌꏍꏎꏏꏐꏑꏒꏓꏔꏕꏖꏗꏘꏙꏚꏛꏜꏝꏞꏟꏠꏡꏢꏣꏤꏥꏦꏧꏨꏩꏪꏫꏬꏭꏮꏯꏰꏱꏲꏳꏴꏵꏶꏷꏸꏹꏺꏻꏼꏽꏾꏿꐀꐁꐂꐃꐄꐅꐆꐇꐈꐉꐊꐋꐌꐍꐎꐏꐐꐑꐒꐓꐔꐕꐖꐗꐘꐙꐚꐛꐜꐝꐞꐟꐠꐡꐢꐣꐤꐥꐦꐧꐨꐩꐪꐫꐬꐭꐮꐯꐰꐱꐲꐳꐴꐵꐶꐷꐸꐹꐺꐻꐼꐽꐾꐿꑀꑁꑂꑃꑄꑅꑆꑇꑈꑉꑊꑋꑌꑍꑎꑏꑐꑑꑒꑓꑔꑕꑖꑗꑘꑙꑚꑛꑜꑝꑞꑟꑠꑡꑢꑣꑤꑥꑦꑧꑨꑩꑪꑫꑬꑭꑮꑯꑰꑱꑲꑳꑴꑵꑶꑷꑸꑹꑺꑻꑼꑽꑾꑿꒀꒁꒂꒃꒄꒅꒆꒇꒈꒉꒊꒋꒌ꒐꒑꒒꒓꒔꒕꒖꒗꒘꒙꒚꒛꒜꒝꒞꒟꒠꒡꒢꒣꒤꒥꒦꒧꒨꒩꒪꒫꒬꒭꒮꒯꒰꒱꒲꒳꒴꒵꒶꒷꒸꒹꒺꒻꒼꒽꒾꒿꓀꓁꓂꓃꓄꓅꓆ꓐꓑꓒꓓꓔꓕꓖꓗꓘꓙꓚꓛꓜꓝꓞꓟꓠꓡꓢꓣꓤꓥꓦꓧꓨꓩꓪꓫꓬꓭꓮꓯꓰꓱꓲꓳꓴꓵꓶꓷꓸꓹꓺꓻꓼꓽ꓾꓿ꔀꔁꔂꔃꔄꔅꔆꔇꔈꔉꔊꔋꔌꔍꔎꔏꔐꔑꔒꔓꔔꔕꔖꔗꔘꔙꔚꔛꔜꔝꔞꔟꔠꔡꔢꔣꔤꔥꔦꔧꔨꔩꔪꔫꔬꔭꔮꔯꔰꔱꔲꔳꔴꔵꔶꔷꔸꔹꔺꔻꔼꔽꔾꔿꕀꕁꕂꕃꕄꕅꕆꕇꕈꕉꕊꕋꕌꕍꕎꕏꕐꕑꕒꕓꕔꕕꕖꕗꕘꕙꕚꕛꕜꕝꕞꕟꕠꕡꕢꕣꕤꕥꕦꕧꕨꕩꕪꕫꕬꕭꕮꕯꕰꕱꕲꕳꕴꕵꕶꕷꕸꕹꕺꕻꕼꕽꕾꕿꖀꖁꖂꖃꖄꖅꖆꖇꖈꖉꖊꖋꖌꖍꖎꖏꖐꖑꖒꖓꖔꖕꖖꖗꖘꖙꖚꖛꖜꖝꖞꖟꖠꖡꖢꖣꖤꖥꖦꖧꖨꖩꖪꖫꖬꖭꖮꖯꖰꖱꖲꖳꖴꖵꖶꖷꖸꖹꖺꖻꖼꖽꖾꖿꗀꗁꗂꗃꗄꗅꗆꗇꗈꗉꗊꗋꗌꗍꗎꗏꗐꗑꗒꗓꗔꗕꗖꗗꗘꗙꗚꗛꗜꗝꗞꗟꗠꗡꗢꗣꗤꗥꗦꗧꗨꗩꗪꗫꗬꗭꗮꗯꗰꗱꗲꗳꗴꗵꗶꗷꗸꗹꗺꗻꗼꗽꗾꗿꘀꘁꘂꘃꘄꘅꘆꘇꘈꘉꘊꘋꘌ꘍꘎꘏ꘐꘑꘒꘓꘔꘕꘖꘗꘘꘙꘚꘛꘜꘝꘞꘟ꘠꘡꘢꘣꘤꘥꘦꘧꘨꘩ꘪꘫꙀꙁꙂꙃꙄꙅꙆꙇꙈꙉꙊꙋꙌꙍꙎꙏꙐꙑꙒꙓꙔꙕꙖꙗꙘꙙꙚꙛꙜꙝꙞꙟꙠꙡꙢꙣꙤꙥꙦꙧꙨꙩꙪꙫꙬꙭꙮ꙯꙰꙱꙲꙳ꙴꙵꙶꙷꙸꙹꙺꙻ꙼꙽꙾ꙿꚀꚁꚂꚃꚄꚅꚆꚇꚈꚉꚊꚋꚌꚍꚎꚏꚐꚑꚒꚓꚔꚕꚖꚗꚟꚠꚡꚢꚣꚤꚥꚦꚧꚨꚩꚪꚫꚬꚭꚮꚯꚰꚱꚲꚳꚴꚵꚶꚷꚸꚹꚺꚻꚼꚽꚾꚿꛀꛁꛂꛃꛄꛅꛆꛇꛈꛉꛊꛋꛌꛍꛎꛏꛐꛑꛒꛓꛔꛕꛖꛗꛘꛙꛚꛛꛜꛝꛞꛟꛠꛡꛢꛣꛤꛥꛦꛧꛨꛩꛪꛫꛬꛭꛮꛯ꛰꛱꛲꛳꛴꛵꛶꛷꜀꜁꜂꜃꜄꜅꜆꜇꜈꜉꜊꜋꜌꜍꜎꜏꜐꜑꜒꜓꜔꜕꜖ꜗꜘꜙꜚꜛꜜꜝꜞꜟ꜠꜡ꜢꜣꜤꜥꜦꜧꜨꜩꜪꜫꜬꜭꜮꜯꜰꜱꜲꜳꜴꜵꜶꜷꜸꜹꜺꜻꜼꜽꜾꜿꝀꝁꝂꝃꝄꝅꝆꝇꝈꝉꝊꝋꝌꝍꝎꝏꝐꝑꝒꝓꝔꝕꝖꝗꝘꝙꝚꝛꝜꝝꝞꝟꝠꝡꝢꝣꝤꝥꝦꝧꝨꝩꝪꝫꝬꝭꝮꝯꝰꝱꝲꝳꝴꝵꝶꝷꝸꝹꝺꝻꝼꝽꝾꝿꞀꞁꞂꞃꞄꞅꞆꞇꞈ꞉꞊ꞋꞌꞍꞎꞐꞑꞒꞓꞠꞡꞢꞣꞤꞥꞦꞧꞨꞩꞪꟸꟹꟺꟻꟼꟽꟾꟿꠀꠁꠂꠃꠄꠅ꠆ꠇꠈꠉꠊꠋꠌꠍꠎꠏꠐꠑꠒꠓꠔꠕꠖꠗꠘꠙꠚꠛꠜꠝꠞꠟꠠꠡꠢꠣꠤꠥꠦꠧ꠨꠩꠪꠫꠰꠱꠲꠳꠴꠵꠶꠷꠸꠹ꡀꡁꡂꡃꡄꡅꡆꡇꡈꡉꡊꡋꡌꡍꡎꡏꡐꡑꡒꡓꡔꡕꡖꡗꡘꡙꡚꡛꡜꡝꡞꡟꡠꡡꡢꡣꡤꡥꡦꡧꡨꡩꡪꡫꡬꡭꡮꡯꡰꡱꡲꡳ꡴꡵꡶꡷ꢀꢁꢂꢃꢄꢅꢆꢇꢈꢉꢊꢋꢌꢍꢎꢏꢐꢑꢒꢓꢔꢕꢖꢗꢘꢙꢚꢛꢜꢝꢞꢟꢠꢡꢢꢣꢤꢥꢦꢧꢨꢩꢪꢫꢬꢭꢮꢯꢰꢱꢲꢳꢴꢵꢶꢷꢸꢹꢺꢻꢼꢽꢾꢿꣀꣁꣂꣃ꣄꣎꣏꣐꣑꣒꣓꣔꣕꣖꣗꣘꣙꣠꣡꣢꣣꣤꣥꣦꣧꣨꣩꣪꣫꣬꣭꣮꣯꣰꣱ꣲꣳꣴꣵꣶꣷ꣸꣹꣺ꣻ꤀꤁꤂꤃꤄꤅꤆꤇꤈꤉ꤊꤋꤌꤍꤎꤏꤐꤑꤒꤓꤔꤕꤖꤗꤘꤙꤚꤛꤜꤝꤞꤟꤠꤡꤢꤣꤤꤥꤦꤧꤨꤩꤪ꤫꤬꤭꤮꤯ꤰꤱꤲꤳꤴꤵꤶꤷꤸꤹꤺꤻꤼꤽꤾꤿꥀꥁꥂꥃꥄꥅꥆꥇꥈꥉꥊꥋꥌꥍꥎꥏꥐꥑꥒ꥓꥟ꥠꥡꥢꥣꥤꥥꥦꥧꥨꥩꥪꥫꥬꥭꥮꥯꥰꥱꥲꥳꥴꥵꥶꥷꥸꥹꥺꥻꥼꦀꦁꦂꦃꦄꦅꦆꦇꦈꦉꦊꦋꦌꦍꦎꦏꦐꦑꦒꦓꦔꦕꦖꦗꦘꦙꦚꦛꦜꦝꦞꦟꦠꦡꦢꦣꦤꦥꦦꦧꦨꦩꦪꦫꦬꦭꦮꦯꦰꦱꦲ꦳ꦴꦵꦶꦷꦸꦹꦺꦻꦼꦽꦾꦿ꧀꧁꧂꧃꧄꧅꧆꧇꧈꧉꧊꧋꧌꧍ꧏ꧐꧑꧒꧓꧔꧕꧖꧗꧘꧙꧞꧟ꨀꨁꨂꨃꨄꨅꨆꨇꨈꨉꨊꨋꨌꨍꨎꨏꨐꨑꨒꨓꨔꨕꨖꨗꨘꨙꨚꨛꨜꨝꨞꨟꨠꨡꨢꨣꨤꨥꨦꨧꨨꨩꨪꨫꨬꨭꨮꨯꨰꨱꨲꨳꨴꨵꨶꩀꩁꩂꩃꩄꩅꩆꩇꩈꩉꩊꩋꩌꩍ꩐꩑꩒꩓꩔꩕꩖꩗꩘꩙꩜꩝꩞꩟ꩠꩡꩢꩣꩤꩥꩦꩧꩨꩩꩪꩫꩬꩭꩮꩯꩰꩱꩲꩳꩴꩵꩶ꩷꩸꩹ꩺꩻꪀꪁꪂꪃꪄꪅꪆꪇꪈꪉꪊꪋꪌꪍꪎꪏꪐꪑꪒꪓꪔꪕꪖꪗꪘꪙꪚꪛꪜꪝꪞꪟꪠꪡꪢꪣꪤꪥꪦꪧꪨꪩꪪꪫꪬꪭꪮꪯꪰꪱꪴꪲꪳꪵꪶꪷꪸꪹꪺꪻꪼꪽꪾ꪿ꫀ꫁ꫂꫛꫜꫝ꫞꫟ꫠꫡꫢꫣꫤꫥꫦꫧꫨꫩꫪꫫꫬꫭꫮꫯ꫰꫱ꫲꫳꫴꫵ꫶ꬁꬂꬃꬄꬅꬆꬉꬊꬋꬌꬍꬎꬑꬒꬓꬔꬕꬖꬠꬡꬢꬣꬤꬥꬦꬨꬩꬪꬫꬬꬭꬮꯀꯁꯂꯃꯄꯅꯆꯇꯈꯉꯊꯋꯌꯍꯎꯏꯐꯑꯒꯓꯔꯕꯖꯗꯘꯙꯚꯛꯜꯝꯞꯟꯠꯡꯢꯣꯤꯥꯦꯧꯨꯩꯪ꯫꯬꯭꯰꯱꯲꯳꯴꯵꯶꯷꯸꯹가각갂갃간갅갆갇갈갉갊갋갌갍갎갏감갑값갓갔강갖갗갘같갚갛개객갞갟갠갡갢갣갤갥갦갧갨갩갪갫갬갭갮갯갰갱갲갳갴갵갶갷갸갹갺갻갼갽갾갿걀걁걂걃걄걅걆걇걈걉걊걋걌걍걎걏걐걑걒걓걔걕걖걗걘걙걚걛걜걝걞걟걠걡걢걣걤걥걦걧걨걩걪걫걬걭걮걯거걱걲걳건걵걶걷걸걹걺걻걼걽걾걿검겁겂것겄겅겆겇겈겉겊겋게겍겎겏겐겑겒겓겔겕겖겗겘겙겚겛겜겝겞겟겠겡겢겣겤겥겦겧겨격겪겫견겭겮겯결겱겲겳겴겵겶겷겸겹겺겻겼경겾겿곀곁곂곃계곅곆곇곈곉곊곋곌곍곎곏곐곑곒곓곔곕곖곗곘곙곚곛곜곝곞곟고곡곢곣곤곥곦곧골곩곪곫곬곭곮곯곰곱곲곳곴공곶곷곸곹곺곻과곽곾곿관괁괂괃괄괅괆괇괈괉괊괋괌괍괎괏괐광괒괓괔괕괖괗괘괙괚괛괜괝괞괟괠괡괢괣괤괥괦괧괨괩괪괫괬괭괮괯괰괱괲괳괴괵괶괷괸괹괺괻괼괽괾괿굀굁굂굃굄굅굆굇굈굉굊굋굌굍굎굏교굑굒굓굔굕굖굗굘굙굚굛굜굝굞굟굠굡굢굣굤굥굦굧굨굩굪굫구국굮굯군굱굲굳굴굵굶굷굸굹굺굻굼굽굾굿궀궁궂궃궄궅궆궇궈궉궊궋권궍궎궏궐궑궒궓궔궕궖궗궘궙궚궛궜궝궞궟궠궡궢궣궤궥궦궧궨궩궪궫궬궭궮궯궰궱궲궳궴궵궶궷궸궹궺궻궼궽궾궿귀귁귂귃귄귅귆귇귈귉귊귋귌귍귎귏귐귑귒귓귔귕귖귗귘귙귚귛규귝귞귟균귡귢귣귤귥귦귧귨귩귪귫귬귭귮귯귰귱귲귳귴귵귶귷그극귺귻근귽귾귿글긁긂긃긄긅긆긇금급긊긋긌긍긎긏긐긑긒긓긔긕긖긗긘긙긚긛긜긝긞긟긠긡긢긣긤긥긦긧긨긩긪긫긬긭긮긯기긱긲긳긴긵긶긷길긹긺긻긼긽긾긿김깁깂깃깄깅깆깇깈깉깊깋까깍깎깏깐깑깒깓깔깕깖깗깘깙깚깛깜깝깞깟깠깡깢깣깤깥깦깧깨깩깪깫깬깭깮깯깰깱깲깳깴깵깶깷깸깹깺깻깼깽깾깿꺀꺁꺂꺃꺄꺅꺆꺇꺈꺉꺊꺋꺌꺍꺎꺏꺐꺑꺒꺓꺔꺕꺖꺗꺘꺙꺚꺛꺜꺝꺞꺟꺠꺡꺢꺣꺤꺥꺦꺧꺨꺩꺪꺫꺬꺭꺮꺯꺰꺱꺲꺳꺴꺵꺶꺷꺸꺹꺺꺻꺼꺽꺾꺿껀껁껂껃껄껅껆껇껈껉껊껋껌껍껎껏껐껑껒껓껔껕껖껗께껙껚껛껜껝껞껟껠껡껢껣껤껥껦껧껨껩껪껫껬껭껮껯껰껱껲껳껴껵껶껷껸껹껺껻껼껽껾껿꼀꼁꼂꼃꼄꼅꼆꼇꼈꼉꼊꼋꼌꼍꼎꼏꼐꼑꼒꼓꼔꼕꼖꼗꼘꼙꼚꼛꼜꼝꼞꼟꼠꼡꼢꼣꼤꼥꼦꼧꼨꼩꼪꼫꼬꼭꼮꼯꼰꼱꼲꼳꼴꼵꼶꼷꼸꼹꼺꼻꼼꼽꼾꼿꽀꽁꽂꽃꽄꽅꽆꽇꽈꽉꽊꽋꽌꽍꽎꽏꽐꽑꽒꽓꽔꽕꽖꽗꽘꽙꽚꽛꽜꽝꽞꽟꽠꽡꽢꽣꽤꽥꽦꽧꽨꽩꽪꽫꽬꽭꽮꽯꽰꽱꽲꽳꽴꽵꽶꽷꽸꽹꽺꽻꽼꽽꽾꽿꾀꾁꾂꾃꾄꾅꾆꾇꾈꾉꾊꾋꾌꾍꾎꾏꾐꾑꾒꾓꾔꾕꾖꾗꾘꾙꾚꾛꾜꾝꾞꾟꾠꾡꾢꾣꾤꾥꾦꾧꾨꾩꾪꾫꾬꾭꾮꾯꾰꾱꾲꾳꾴꾵꾶꾷꾸꾹꾺꾻꾼꾽꾾꾿꿀꿁꿂꿃꿄꿅꿆꿇꿈꿉꿊꿋꿌꿍꿎꿏꿐꿑꿒꿓꿔꿕꿖꿗꿘꿙꿚꿛꿜꿝꿞꿟꿠꿡꿢꿣꿤꿥꿦꿧꿨꿩꿪꿫꿬꿭꿮꿯꿰꿱꿲꿳꿴꿵꿶꿷꿸꿹꿺꿻꿼꿽꿾꿿뀀뀁뀂뀃뀄뀅뀆뀇뀈뀉뀊뀋뀌뀍뀎뀏뀐뀑뀒뀓뀔뀕뀖뀗뀘뀙뀚뀛뀜뀝뀞뀟뀠뀡뀢뀣뀤뀥뀦뀧뀨뀩뀪뀫뀬뀭뀮뀯뀰뀱뀲뀳뀴뀵뀶뀷뀸뀹뀺뀻뀼뀽뀾뀿끀끁끂끃끄끅끆끇끈끉끊끋끌끍끎끏끐끑끒끓끔끕끖끗끘끙끚끛끜끝끞끟끠끡끢끣끤끥끦끧끨끩끪끫끬끭끮끯끰끱끲끳끴끵끶끷끸끹끺끻끼끽끾끿낀낁낂낃낄낅낆낇낈낉낊낋낌낍낎낏낐낑낒낓낔낕낖낗나낙낚낛난낝낞낟날낡낢낣낤낥낦낧남납낪낫났낭낮낯낰낱낲낳내낵낶낷낸낹낺낻낼낽낾낿냀냁냂냃냄냅냆냇냈냉냊냋냌냍냎냏냐냑냒냓냔냕냖냗냘냙냚냛냜냝냞냟냠냡냢냣냤냥냦냧냨냩냪냫냬냭냮냯냰냱냲냳냴냵냶냷냸냹냺냻냼냽냾냿넀넁넂넃넄넅넆넇너넉넊넋넌넍넎넏널넑넒넓넔넕넖넗넘넙넚넛넜넝넞넟넠넡넢넣네넥넦넧넨넩넪넫넬넭넮넯넰넱넲넳넴넵넶넷넸넹넺넻넼넽넾넿녀녁녂녃년녅녆녇녈녉녊녋녌녍녎녏념녑녒녓녔녕녖녗녘녙녚녛녜녝녞녟녠녡녢녣녤녥녦녧녨녩녪녫녬녭녮녯녰녱녲녳녴녵녶녷노녹녺녻논녽녾녿놀놁놂놃놄놅놆놇놈놉놊놋놌농놎놏놐놑높놓놔놕놖놗놘놙놚놛놜놝놞놟놠놡놢놣놤놥놦놧놨놩놪놫놬놭놮놯놰놱놲놳놴놵놶놷놸놹놺놻놼놽놾놿뇀뇁뇂뇃뇄뇅뇆뇇뇈뇉뇊뇋뇌뇍뇎뇏뇐뇑뇒뇓뇔뇕뇖뇗뇘뇙뇚뇛뇜뇝뇞뇟뇠뇡뇢뇣뇤뇥뇦뇧뇨뇩뇪뇫뇬뇭뇮뇯뇰뇱뇲뇳뇴뇵뇶뇷뇸뇹뇺뇻뇼뇽뇾뇿눀눁눂눃누눅눆눇눈눉눊눋눌눍눎눏눐눑눒눓눔눕눖눗눘눙눚눛눜눝눞눟눠눡눢눣눤눥눦눧눨눩눪눫눬눭눮눯눰눱눲눳눴눵눶눷눸눹눺눻눼눽눾눿뉀뉁뉂뉃뉄뉅뉆뉇뉈뉉뉊뉋뉌뉍뉎뉏뉐뉑뉒뉓뉔뉕뉖뉗뉘뉙뉚뉛뉜뉝뉞뉟뉠뉡뉢뉣뉤뉥뉦뉧뉨뉩뉪뉫뉬뉭뉮뉯뉰뉱뉲뉳뉴뉵뉶뉷뉸뉹뉺뉻뉼뉽뉾뉿늀늁늂늃늄늅늆늇늈늉늊늋늌늍늎늏느늑늒늓는늕늖늗늘늙늚늛늜늝늞늟늠늡늢늣늤능늦늧늨늩늪늫늬늭늮늯늰늱늲늳늴늵늶늷늸늹늺늻늼늽늾늿닀닁닂닃닄닅닆닇니닉닊닋닌닍닎닏닐닑닒닓닔닕닖닗님닙닚닛닜닝닞닟닠닡닢닣다닥닦닧단닩닪닫달닭닮닯닰닱닲닳담답닶닷닸당닺닻닼닽닾닿대댁댂댃댄댅댆댇댈댉댊댋댌댍댎댏댐댑댒댓댔댕댖댗댘댙댚댛댜댝댞댟댠댡댢댣댤댥댦댧댨댩댪댫댬댭댮댯댰댱댲댳댴댵댶댷댸댹댺댻댼댽댾댿덀덁덂덃덄덅덆덇덈덉덊덋덌덍덎덏덐덑덒덓더덕덖덗던덙덚덛덜덝덞덟덠덡덢덣덤덥덦덧덨덩덪덫덬덭덮덯데덱덲덳덴덵덶덷델덹덺덻덼덽덾덿뎀뎁뎂뎃뎄뎅뎆뎇뎈뎉뎊뎋뎌뎍뎎뎏뎐뎑뎒뎓뎔뎕뎖뎗뎘뎙뎚뎛뎜뎝뎞뎟뎠뎡뎢뎣뎤뎥뎦뎧뎨뎩뎪뎫뎬뎭뎮뎯뎰뎱뎲뎳뎴뎵뎶뎷뎸뎹뎺뎻뎼뎽뎾뎿돀돁돂돃도독돆돇돈돉돊돋돌돍돎돏돐돑돒돓돔돕돖돗돘동돚돛돜돝돞돟돠돡돢돣돤돥돦돧돨돩돪돫돬돭돮돯돰돱돲돳돴돵돶돷돸돹돺돻돼돽돾돿됀됁됂됃됄됅됆됇됈됉됊됋됌됍됎됏됐됑됒됓됔됕됖됗되됙됚됛된됝됞됟될됡됢됣됤됥됦됧됨됩됪됫됬됭됮됯됰됱됲됳됴됵됶됷됸됹됺됻됼됽됾됿둀둁둂둃둄둅둆둇둈둉둊둋둌둍둎둏두둑둒둓둔둕둖둗둘둙둚둛둜둝둞둟둠둡둢둣둤둥둦둧둨둩둪둫둬둭둮둯둰둱둲둳둴둵둶둷둸둹둺둻둼둽둾둿뒀뒁뒂뒃뒄뒅뒆뒇뒈뒉뒊뒋뒌뒍뒎뒏뒐뒑뒒뒓뒔뒕뒖뒗뒘뒙뒚뒛뒜뒝뒞뒟뒠뒡뒢뒣뒤뒥뒦뒧뒨뒩뒪뒫뒬뒭뒮뒯뒰뒱뒲뒳뒴뒵뒶뒷뒸뒹뒺뒻뒼뒽뒾뒿듀듁듂듃듄듅듆듇듈듉듊듋듌듍듎듏듐듑듒듓듔듕듖듗듘듙듚듛드득듞듟든듡듢듣들듥듦듧듨듩듪듫듬듭듮듯듰등듲듳듴듵듶듷듸듹듺듻듼듽듾듿딀딁딂딃딄딅딆딇딈딉딊딋딌딍딎딏딐딑딒딓디딕딖딗딘딙딚딛딜딝딞딟딠딡딢딣딤딥딦딧딨딩딪딫딬딭딮딯따딱딲딳딴딵딶딷딸딹딺딻딼딽딾딿땀땁땂땃땄땅땆땇땈땉땊땋때땍땎땏땐땑땒땓땔땕땖땗땘땙땚땛땜땝땞땟땠땡땢땣땤땥땦땧땨땩땪땫땬땭땮땯땰땱땲땳땴땵땶땷땸땹땺땻땼땽땾땿떀떁떂떃떄떅떆떇떈떉떊떋떌떍떎떏떐떑떒떓떔떕떖떗떘떙떚떛떜떝떞떟떠떡떢떣떤떥떦떧떨떩떪떫떬떭떮떯떰떱떲떳떴떵떶떷떸떹떺떻떼떽떾떿뗀뗁뗂뗃뗄뗅뗆뗇뗈뗉뗊뗋뗌뗍뗎뗏뗐뗑뗒뗓뗔뗕뗖뗗뗘뗙뗚뗛뗜뗝뗞뗟뗠뗡뗢뗣뗤뗥뗦뗧뗨뗩뗪뗫뗬뗭뗮뗯뗰뗱뗲뗳뗴뗵뗶뗷뗸뗹뗺뗻뗼뗽뗾뗿똀똁똂똃똄똅똆똇똈똉똊똋똌똍똎똏또똑똒똓똔똕똖똗똘똙똚똛똜똝똞똟똠똡똢똣똤똥똦똧똨똩똪똫똬똭똮똯똰똱똲똳똴똵똶똷똸똹똺똻똼똽똾똿뙀뙁뙂뙃뙄뙅뙆뙇뙈뙉뙊뙋뙌뙍뙎뙏뙐뙑뙒뙓뙔뙕뙖뙗뙘뙙뙚뙛뙜뙝뙞뙟뙠뙡뙢뙣뙤뙥뙦뙧뙨뙩뙪뙫뙬뙭뙮뙯뙰뙱뙲뙳뙴뙵뙶뙷뙸뙹뙺뙻뙼뙽뙾뙿뚀뚁뚂뚃뚄뚅뚆뚇뚈뚉뚊뚋뚌뚍뚎뚏뚐뚑뚒뚓뚔뚕뚖뚗뚘뚙뚚뚛뚜뚝뚞뚟뚠뚡뚢뚣뚤뚥뚦뚧뚨뚩뚪뚫뚬뚭뚮뚯뚰뚱뚲뚳뚴뚵뚶뚷뚸뚹뚺뚻뚼뚽뚾뚿뛀뛁뛂뛃뛄뛅뛆뛇뛈뛉뛊뛋뛌뛍뛎뛏뛐뛑뛒뛓뛔뛕뛖뛗뛘뛙뛚뛛뛜뛝뛞뛟뛠뛡뛢뛣뛤뛥뛦뛧뛨뛩뛪뛫뛬뛭뛮뛯뛰뛱뛲뛳뛴뛵뛶뛷뛸뛹뛺뛻뛼뛽뛾뛿뜀뜁뜂뜃뜄뜅뜆뜇뜈뜉뜊뜋뜌뜍뜎뜏뜐뜑뜒뜓뜔뜕뜖뜗뜘뜙뜚뜛뜜뜝뜞뜟뜠뜡뜢뜣뜤뜥뜦뜧뜨뜩뜪뜫뜬뜭뜮뜯뜰뜱뜲뜳뜴뜵뜶뜷뜸뜹뜺뜻뜼뜽뜾뜿띀띁띂띃띄띅띆띇띈띉띊띋띌띍띎띏띐띑띒띓띔띕띖띗띘띙띚띛띜띝띞띟띠띡띢띣띤띥띦띧띨띩띪띫띬띭띮띯띰띱띲띳띴띵띶띷띸띹띺띻라락띾띿란랁랂랃랄랅랆랇랈랉랊랋람랍랎랏랐랑랒랓랔랕랖랗래랙랚랛랜랝랞랟랠랡랢랣랤랥랦랧램랩랪랫랬랭랮랯랰랱랲랳랴략랶랷랸랹랺랻랼랽랾랿럀럁럂럃럄럅럆럇럈량럊럋럌럍럎럏럐럑럒럓럔럕럖럗럘럙럚럛럜럝럞럟럠럡럢럣럤럥럦럧럨럩럪럫러럭럮럯런럱럲럳럴럵럶럷럸럹럺럻럼럽럾럿렀렁렂렃렄렅렆렇레렉렊렋렌렍렎렏렐렑렒렓렔렕렖렗렘렙렚렛렜렝렞렟렠렡렢렣려력렦렧련렩렪렫렬렭렮렯렰렱렲렳렴렵렶렷렸령렺렻렼렽렾렿례롁롂롃롄롅롆롇롈롉롊롋롌롍롎롏롐롑롒롓롔롕롖롗롘롙롚롛로록롞롟론롡롢롣롤롥롦롧롨롩롪롫롬롭롮롯롰롱롲롳롴롵롶롷롸롹롺롻롼롽롾롿뢀뢁뢂뢃뢄뢅뢆뢇뢈뢉뢊뢋뢌뢍뢎뢏뢐뢑뢒뢓뢔뢕뢖뢗뢘뢙뢚뢛뢜뢝뢞뢟뢠뢡뢢뢣뢤뢥뢦뢧뢨뢩뢪뢫뢬뢭뢮뢯뢰뢱뢲뢳뢴뢵뢶뢷뢸뢹뢺뢻뢼뢽뢾뢿룀룁룂룃룄룅룆룇룈룉룊룋료룍룎룏룐룑룒룓룔룕룖룗룘룙룚룛룜룝룞룟룠룡룢룣룤룥룦룧루룩룪룫룬룭룮룯룰룱룲룳룴룵룶룷룸룹룺룻룼룽룾룿뤀뤁뤂뤃뤄뤅뤆뤇뤈뤉뤊뤋뤌뤍뤎뤏뤐뤑뤒뤓뤔뤕뤖뤗뤘뤙뤚뤛뤜뤝뤞뤟뤠뤡뤢뤣뤤뤥뤦뤧뤨뤩뤪뤫뤬뤭뤮뤯뤰뤱뤲뤳뤴뤵뤶뤷뤸뤹뤺뤻뤼뤽뤾뤿륀륁륂륃륄륅륆륇륈륉륊륋륌륍륎륏륐륑륒륓륔륕륖륗류륙륚륛륜륝륞륟률륡륢륣륤륥륦륧륨륩륪륫륬륭륮륯륰륱륲륳르륵륶륷른륹륺륻를륽륾륿릀릁릂릃름릅릆릇릈릉릊릋릌릍릎릏릐릑릒릓릔릕릖릗릘릙릚릛릜릝릞릟릠릡릢릣릤릥릦릧릨릩릪릫리릭릮릯린릱릲릳릴릵릶릷릸릹릺릻림립릾릿맀링맂맃맄맅맆맇마막맊맋만맍많맏말맑맒맓맔맕맖맗맘맙맚맛맜망맞맟맠맡맢맣매맥맦맧맨맩맪맫맬맭맮맯맰맱맲맳맴맵맶맷맸맹맺맻맼맽맾맿먀먁먂먃먄먅먆먇먈먉먊먋먌먍먎먏먐먑먒먓먔먕먖먗먘먙먚먛먜먝먞먟먠먡먢먣먤먥먦먧먨먩먪먫먬먭먮먯먰먱먲먳먴먵먶먷머먹먺먻먼먽먾먿멀멁멂멃멄멅멆멇멈멉멊멋멌멍멎멏멐멑멒멓메멕멖멗멘멙멚멛멜멝멞멟멠멡멢멣멤멥멦멧멨멩멪멫멬멭멮멯며멱멲멳면멵멶멷멸멹멺멻멼멽멾멿몀몁몂몃몄명몆몇몈몉몊몋몌몍몎몏몐몑몒몓몔몕몖몗몘몙몚몛몜몝몞몟몠몡몢몣몤몥몦몧모목몪몫몬몭몮몯몰몱몲몳몴몵몶몷몸몹몺못몼몽몾몿뫀뫁뫂뫃뫄뫅뫆뫇뫈뫉뫊뫋뫌뫍뫎뫏뫐뫑뫒뫓뫔뫕뫖뫗뫘뫙뫚뫛뫜뫝뫞뫟뫠뫡뫢뫣뫤뫥뫦뫧뫨뫩뫪뫫뫬뫭뫮뫯뫰뫱뫲뫳뫴뫵뫶뫷뫸뫹뫺뫻뫼뫽뫾뫿묀묁묂묃묄묅묆묇묈묉묊묋묌묍묎묏묐묑묒묓묔묕묖묗묘묙묚묛묜묝묞묟묠묡묢묣묤묥묦묧묨묩묪묫묬묭묮묯묰묱묲묳무묵묶묷문묹묺묻물묽묾묿뭀뭁뭂뭃뭄뭅뭆뭇뭈뭉뭊뭋뭌뭍뭎뭏뭐뭑뭒뭓뭔뭕뭖뭗뭘뭙뭚뭛뭜뭝뭞뭟뭠뭡뭢뭣뭤뭥뭦뭧뭨뭩뭪뭫뭬뭭뭮뭯뭰뭱뭲뭳뭴뭵뭶뭷뭸뭹뭺뭻뭼뭽뭾뭿뮀뮁뮂뮃뮄뮅뮆뮇뮈뮉뮊뮋뮌뮍뮎뮏뮐뮑뮒뮓뮔뮕뮖뮗뮘뮙뮚뮛뮜뮝뮞뮟뮠뮡뮢뮣뮤뮥뮦뮧뮨뮩뮪뮫뮬뮭뮮뮯뮰뮱뮲뮳뮴뮵뮶뮷뮸뮹뮺뮻뮼뮽뮾뮿므믁믂믃믄믅믆믇믈믉믊믋믌믍믎믏믐믑믒믓믔믕믖믗믘믙믚믛믜믝믞믟믠믡믢믣믤믥믦믧믨믩믪믫믬믭믮믯믰믱믲믳믴믵믶믷미믹믺믻민믽믾믿밀밁밂밃밄밅밆밇밈밉밊밋밌밍밎및밐밑밒밓바박밖밗반밙밚받발밝밞밟밠밡밢밣밤밥밦밧밨방밪밫밬밭밮밯배백밲밳밴밵밶밷밸밹밺밻밼밽밾밿뱀뱁뱂뱃뱄뱅뱆뱇뱈뱉뱊뱋뱌뱍뱎뱏뱐뱑뱒뱓뱔뱕뱖뱗뱘뱙뱚뱛뱜뱝뱞뱟뱠뱡뱢뱣뱤뱥뱦뱧뱨뱩뱪뱫뱬뱭뱮뱯뱰뱱뱲뱳뱴뱵뱶뱷뱸뱹뱺뱻뱼뱽뱾뱿벀벁벂벃버벅벆벇번벉벊벋벌벍벎벏벐벑벒벓범법벖벗벘벙벚벛벜벝벞벟베벡벢벣벤벥벦벧벨벩벪벫벬벭벮벯벰벱벲벳벴벵벶벷벸벹벺벻벼벽벾벿변볁볂볃별볅볆볇볈볉볊볋볌볍볎볏볐병볒볓볔볕볖볗볘볙볚볛볜볝볞볟볠볡볢볣볤볥볦볧볨볩볪볫볬볭볮볯볰볱볲볳보복볶볷본볹볺볻볼볽볾볿봀봁봂봃봄봅봆봇봈봉봊봋봌봍봎봏봐봑봒봓봔봕봖봗봘봙봚봛봜봝봞봟봠봡봢봣봤봥봦봧봨봩봪봫봬봭봮봯봰봱봲봳봴봵봶봷봸봹봺봻봼봽봾봿뵀뵁뵂뵃뵄뵅뵆뵇뵈뵉뵊뵋뵌뵍뵎뵏뵐뵑뵒뵓뵔뵕뵖뵗뵘뵙뵚뵛뵜뵝뵞뵟뵠뵡뵢뵣뵤뵥뵦뵧뵨뵩뵪뵫뵬뵭뵮뵯뵰뵱뵲뵳뵴뵵뵶뵷뵸뵹뵺뵻뵼뵽뵾뵿부북붂붃분붅붆붇불붉붊붋붌붍붎붏붐붑붒붓붔붕붖붗붘붙붚붛붜붝붞붟붠붡붢붣붤붥붦붧붨붩붪붫붬붭붮붯붰붱붲붳붴붵붶붷붸붹붺붻붼붽붾붿뷀뷁뷂뷃뷄뷅뷆뷇뷈뷉뷊뷋뷌뷍뷎뷏뷐뷑뷒뷓뷔뷕뷖뷗뷘뷙뷚뷛뷜뷝뷞뷟뷠뷡뷢뷣뷤뷥뷦뷧뷨뷩뷪뷫뷬뷭뷮뷯뷰뷱뷲뷳뷴뷵뷶뷷뷸뷹뷺뷻뷼뷽뷾뷿븀븁븂븃븄븅븆븇븈븉븊븋브븍븎븏븐븑븒븓블븕븖븗븘븙븚븛븜븝븞븟븠븡븢븣븤븥븦븧븨븩븪븫븬븭븮븯븰븱븲븳븴븵븶븷븸븹븺븻븼븽븾븿빀빁빂빃비빅빆빇빈빉빊빋빌빍빎빏빐빑빒빓빔빕빖빗빘빙빚빛빜빝빞빟빠빡빢빣빤빥빦빧빨빩빪빫빬빭빮빯빰빱빲빳빴빵빶빷빸빹빺빻빼빽빾빿뺀뺁뺂뺃뺄뺅뺆뺇뺈뺉뺊뺋뺌뺍뺎뺏뺐뺑뺒뺓뺔뺕뺖뺗뺘뺙뺚뺛뺜뺝뺞뺟뺠뺡뺢뺣뺤뺥뺦뺧뺨뺩뺪뺫뺬뺭뺮뺯뺰뺱뺲뺳뺴뺵뺶뺷뺸뺹뺺뺻뺼뺽뺾뺿뻀뻁뻂뻃뻄뻅뻆뻇뻈뻉뻊뻋뻌뻍뻎뻏뻐뻑뻒뻓뻔뻕뻖뻗뻘뻙뻚뻛뻜뻝뻞뻟뻠뻡뻢뻣뻤뻥뻦뻧뻨뻩뻪뻫뻬뻭뻮뻯뻰뻱뻲뻳뻴뻵뻶뻷뻸뻹뻺뻻뻼뻽뻾뻿뼀뼁뼂뼃뼄뼅뼆뼇뼈뼉뼊뼋뼌뼍뼎뼏뼐뼑뼒뼓뼔뼕뼖뼗뼘뼙뼚뼛뼜뼝뼞뼟뼠뼡뼢뼣뼤뼥뼦뼧뼨뼩뼪뼫뼬뼭뼮뼯뼰뼱뼲뼳뼴뼵뼶뼷뼸뼹뼺뼻뼼뼽뼾뼿뽀뽁뽂뽃뽄뽅뽆뽇뽈뽉뽊뽋뽌뽍뽎뽏뽐뽑뽒뽓뽔뽕뽖뽗뽘뽙뽚뽛뽜뽝뽞뽟뽠뽡뽢뽣뽤뽥뽦뽧뽨뽩뽪뽫뽬뽭뽮뽯뽰뽱뽲뽳뽴뽵뽶뽷뽸뽹뽺뽻뽼뽽뽾뽿뾀뾁뾂뾃뾄뾅뾆뾇뾈뾉뾊뾋뾌뾍뾎뾏뾐뾑뾒뾓뾔뾕뾖뾗뾘뾙뾚뾛뾜뾝뾞뾟뾠뾡뾢뾣뾤뾥뾦뾧뾨뾩뾪뾫뾬뾭뾮뾯뾰뾱뾲뾳뾴뾵뾶뾷뾸뾹뾺뾻뾼뾽뾾뾿뿀뿁뿂뿃뿄뿅뿆뿇뿈뿉뿊뿋뿌뿍뿎뿏뿐뿑뿒뿓뿔뿕뿖뿗뿘뿙뿚뿛뿜뿝뿞뿟뿠뿡뿢뿣뿤뿥뿦뿧뿨뿩뿪뿫뿬뿭뿮뿯뿰뿱뿲뿳뿴뿵뿶뿷뿸뿹뿺뿻뿼뿽뿾뿿쀀쀁쀂쀃쀄쀅쀆쀇쀈쀉쀊쀋쀌쀍쀎쀏쀐쀑쀒쀓쀔쀕쀖쀗쀘쀙쀚쀛쀜쀝쀞쀟쀠쀡쀢쀣쀤쀥쀦쀧쀨쀩쀪쀫쀬쀭쀮쀯쀰쀱쀲쀳쀴쀵쀶쀷쀸쀹쀺쀻쀼쀽쀾쀿쁀쁁쁂쁃쁄쁅쁆쁇쁈쁉쁊쁋쁌쁍쁎쁏쁐쁑쁒쁓쁔쁕쁖쁗쁘쁙쁚쁛쁜쁝쁞쁟쁠쁡쁢쁣쁤쁥쁦쁧쁨쁩쁪쁫쁬쁭쁮쁯쁰쁱쁲쁳쁴쁵쁶쁷쁸쁹쁺쁻쁼쁽쁾쁿삀삁삂삃삄삅삆삇삈삉삊삋삌삍삎삏삐삑삒삓삔삕삖삗삘삙삚삛삜삝삞삟삠삡삢삣삤삥삦삧삨삩삪삫사삭삮삯산삱삲삳살삵삶삷삸삹삺삻삼삽삾삿샀상샂샃샄샅샆샇새색샊샋샌샍샎샏샐샑샒샓샔샕샖샗샘샙샚샛샜생샞샟샠샡샢샣샤샥샦샧샨샩샪샫샬샭샮샯샰샱샲샳샴샵샶샷샸샹샺샻샼샽샾샿섀섁섂섃섄섅섆섇섈섉섊섋섌섍섎섏섐섑섒섓섔섕섖섗섘섙섚섛서석섞섟선섡섢섣설섥섦섧섨섩섪섫섬섭섮섯섰성섲섳섴섵섶섷세섹섺섻센섽섾섿셀셁셂셃셄셅셆셇셈셉셊셋셌셍셎셏셐셑셒셓셔셕셖셗션셙셚셛셜셝셞셟셠셡셢셣셤셥셦셧셨셩셪셫셬셭셮셯셰셱셲셳셴셵셶셷셸셹셺셻셼셽셾셿솀솁솂솃솄솅솆솇솈솉솊솋소속솎솏손솑솒솓솔솕솖솗솘솙솚솛솜솝솞솟솠송솢솣솤솥솦솧솨솩솪솫솬솭솮솯솰솱솲솳솴솵솶솷솸솹솺솻솼솽솾솿쇀쇁쇂쇃쇄쇅쇆쇇쇈쇉쇊쇋쇌쇍쇎쇏쇐쇑쇒쇓쇔쇕쇖쇗쇘쇙쇚쇛쇜쇝쇞쇟쇠쇡쇢쇣쇤쇥쇦쇧쇨쇩쇪쇫쇬쇭쇮쇯쇰쇱쇲쇳쇴쇵쇶쇷쇸쇹쇺쇻쇼쇽쇾쇿숀숁숂숃숄숅숆숇숈숉숊숋숌숍숎숏숐숑숒숓숔숕숖숗수숙숚숛순숝숞숟술숡숢숣숤숥숦숧숨숩숪숫숬숭숮숯숰숱숲숳숴숵숶숷숸숹숺숻숼숽숾숿쉀쉁쉂쉃쉄쉅쉆쉇쉈쉉쉊쉋쉌쉍쉎쉏쉐쉑쉒쉓쉔쉕쉖쉗쉘쉙쉚쉛쉜쉝쉞쉟쉠쉡쉢쉣쉤쉥쉦쉧쉨쉩쉪쉫쉬쉭쉮쉯쉰쉱쉲쉳쉴쉵쉶쉷쉸쉹쉺쉻쉼쉽쉾쉿슀슁슂슃슄슅슆슇슈슉슊슋슌슍슎슏슐슑슒슓슔슕슖슗슘슙슚슛슜슝슞슟슠슡슢슣스슥슦슧슨슩슪슫슬슭슮슯슰슱슲슳슴습슶슷슸승슺슻슼슽슾슿싀싁싂싃싄싅싆싇싈싉싊싋싌싍싎싏싐싑싒싓싔싕싖싗싘싙싚싛시식싞싟신싡싢싣실싥싦싧싨싩싪싫심십싮싯싰싱싲싳싴싵싶싷싸싹싺싻싼싽싾싿쌀쌁쌂쌃쌄쌅쌆쌇쌈쌉쌊쌋쌌쌍쌎쌏쌐쌑쌒쌓쌔쌕쌖쌗쌘쌙쌚쌛쌜쌝쌞쌟쌠쌡쌢쌣쌤쌥쌦쌧쌨쌩쌪쌫쌬쌭쌮쌯쌰쌱쌲쌳쌴쌵쌶쌷쌸쌹쌺쌻쌼쌽쌾쌿썀썁썂썃썄썅썆썇썈썉썊썋썌썍썎썏썐썑썒썓썔썕썖썗썘썙썚썛썜썝썞썟썠썡썢썣썤썥썦썧써썩썪썫썬썭썮썯썰썱썲썳썴썵썶썷썸썹썺썻썼썽썾썿쎀쎁쎂쎃쎄쎅쎆쎇쎈쎉쎊쎋쎌쎍쎎쎏쎐쎑쎒쎓쎔쎕쎖쎗쎘쎙쎚쎛쎜쎝쎞쎟쎠쎡쎢쎣쎤쎥쎦쎧쎨쎩쎪쎫쎬쎭쎮쎯쎰쎱쎲쎳쎴쎵쎶쎷쎸쎹쎺쎻쎼쎽쎾쎿쏀쏁쏂쏃쏄쏅쏆쏇쏈쏉쏊쏋쏌쏍쏎쏏쏐쏑쏒쏓쏔쏕쏖쏗쏘쏙쏚쏛쏜쏝쏞쏟쏠쏡쏢쏣쏤쏥쏦쏧쏨쏩쏪쏫쏬쏭쏮쏯쏰쏱쏲쏳쏴쏵쏶쏷쏸쏹쏺쏻쏼쏽쏾쏿쐀쐁쐂쐃쐄쐅쐆쐇쐈쐉쐊쐋쐌쐍쐎쐏쐐쐑쐒쐓쐔쐕쐖쐗쐘쐙쐚쐛쐜쐝쐞쐟쐠쐡쐢쐣쐤쐥쐦쐧쐨쐩쐪쐫쐬쐭쐮쐯쐰쐱쐲쐳쐴쐵쐶쐷쐸쐹쐺쐻쐼쐽쐾쐿쑀쑁쑂쑃쑄쑅쑆쑇쑈쑉쑊쑋쑌쑍쑎쑏쑐쑑쑒쑓쑔쑕쑖쑗쑘쑙쑚쑛쑜쑝쑞쑟쑠쑡쑢쑣쑤쑥쑦쑧쑨쑩쑪쑫쑬쑭쑮쑯쑰쑱쑲쑳쑴쑵쑶쑷쑸쑹쑺쑻쑼쑽쑾쑿쒀쒁쒂쒃쒄쒅쒆쒇쒈쒉쒊쒋쒌쒍쒎쒏쒐쒑쒒쒓쒔쒕쒖쒗쒘쒙쒚쒛쒜쒝쒞쒟쒠쒡쒢쒣쒤쒥쒦쒧쒨쒩쒪쒫쒬쒭쒮쒯쒰쒱쒲쒳쒴쒵쒶쒷쒸쒹쒺쒻쒼쒽쒾쒿쓀쓁쓂쓃쓄쓅쓆쓇쓈쓉쓊쓋쓌쓍쓎쓏쓐쓑쓒쓓쓔쓕쓖쓗쓘쓙쓚쓛쓜쓝쓞쓟쓠쓡쓢쓣쓤쓥쓦쓧쓨쓩쓪쓫쓬쓭쓮쓯쓰쓱쓲쓳쓴쓵쓶쓷쓸쓹쓺쓻쓼쓽쓾쓿씀씁씂씃씄씅씆씇씈씉씊씋씌씍씎씏씐씑씒씓씔씕씖씗씘씙씚씛씜씝씞씟씠씡씢씣씤씥씦씧씨씩씪씫씬씭씮씯씰씱씲씳씴씵씶씷씸씹씺씻씼씽씾씿앀앁앂앃아악앆앇안앉않앋알앍앎앏앐앑앒앓암압앖앗았앙앚앛앜앝앞앟애액앢앣앤앥앦앧앨앩앪앫앬앭앮앯앰앱앲앳앴앵앶앷앸앹앺앻야약앾앿얀얁얂얃얄얅얆얇얈얉얊얋얌얍얎얏얐양얒얓얔얕얖얗얘얙얚얛얜얝얞얟얠얡얢얣얤얥얦얧얨얩얪얫얬얭얮얯얰얱얲얳어억얶얷언얹얺얻얼얽얾얿엀엁엂엃엄업없엇었엉엊엋엌엍엎엏에엑엒엓엔엕엖엗엘엙엚엛엜엝엞엟엠엡엢엣엤엥엦엧엨엩엪엫여역엮엯연엱엲엳열엵엶엷엸엹엺엻염엽엾엿였영옂옃옄옅옆옇예옉옊옋옌옍옎옏옐옑옒옓옔옕옖옗옘옙옚옛옜옝옞옟옠옡옢옣오옥옦옧온옩옪옫올옭옮옯옰옱옲옳옴옵옶옷옸옹옺옻옼옽옾옿와왁왂왃완왅왆왇왈왉왊왋왌왍왎왏왐왑왒왓왔왕왖왗왘왙왚왛왜왝왞왟왠왡왢왣왤왥왦왧왨왩왪왫왬왭왮왯왰왱왲왳왴왵왶왷외왹왺왻왼왽왾왿욀욁욂욃욄욅욆욇욈욉욊욋욌욍욎욏욐욑욒욓요욕욖욗욘욙욚욛욜욝욞욟욠욡욢욣욤욥욦욧욨용욪욫욬욭욮욯우욱욲욳운욵욶욷울욹욺욻욼욽욾욿움웁웂웃웄웅웆웇웈웉웊웋워웍웎웏원웑웒웓월웕웖웗웘웙웚웛웜웝웞웟웠웡웢웣웤웥웦웧웨웩웪웫웬웭웮웯웰웱웲웳웴웵웶웷웸웹웺웻웼웽웾웿윀윁윂윃위윅윆윇윈윉윊윋윌윍윎윏윐윑윒윓윔윕윖윗윘윙윚윛윜윝윞윟유육윢윣윤윥윦윧율윩윪윫윬윭윮윯윰윱윲윳윴융윶윷윸윹윺윻으윽윾윿은읁읂읃을읅읆읇읈읉읊읋음읍읎읏읐응읒읓읔읕읖읗의읙읚읛읜읝읞읟읠읡읢읣읤읥읦읧읨읩읪읫읬읭읮읯읰읱읲읳이익읶읷인읹읺읻일읽읾읿잀잁잂잃임입잆잇있잉잊잋잌잍잎잏자작잒잓잔잕잖잗잘잙잚잛잜잝잞잟잠잡잢잣잤장잦잧잨잩잪잫재잭잮잯잰잱잲잳잴잵잶잷잸잹잺잻잼잽잾잿쟀쟁쟂쟃쟄쟅쟆쟇쟈쟉쟊쟋쟌쟍쟎쟏쟐쟑쟒쟓쟔쟕쟖쟗쟘쟙쟚쟛쟜쟝쟞쟟쟠쟡쟢쟣쟤쟥쟦쟧쟨쟩쟪쟫쟬쟭쟮쟯쟰쟱쟲쟳쟴쟵쟶쟷쟸쟹쟺쟻쟼쟽쟾쟿저적젂젃전젅젆젇절젉젊젋젌젍젎젏점접젒젓젔정젖젗젘젙젚젛제젝젞젟젠젡젢젣젤젥젦젧젨젩젪젫젬젭젮젯젰젱젲젳젴젵젶젷져젹젺젻젼젽젾젿졀졁졂졃졄졅졆졇졈졉졊졋졌졍졎졏졐졑졒졓졔졕졖졗졘졙졚졛졜졝졞졟졠졡졢졣졤졥졦졧졨졩졪졫졬졭졮졯조족졲졳존졵졶졷졸졹졺졻졼졽졾졿좀좁좂좃좄종좆좇좈좉좊좋좌좍좎좏좐좑좒좓좔좕좖좗좘좙좚좛좜좝좞좟좠좡좢좣좤좥좦좧좨좩좪좫좬좭좮좯좰좱좲좳좴좵좶좷좸좹좺좻좼좽좾좿죀죁죂죃죄죅죆죇죈죉죊죋죌죍죎죏죐죑죒죓죔죕죖죗죘죙죚죛죜죝죞죟죠죡죢죣죤죥죦죧죨죩죪죫죬죭죮죯죰죱죲죳죴죵죶죷죸죹죺죻주죽죾죿준줁줂줃줄줅줆줇줈줉줊줋줌줍줎줏줐중줒줓줔줕줖줗줘줙줚줛줜줝줞줟줠줡줢줣줤줥줦줧줨줩줪줫줬줭줮줯줰줱줲줳줴줵줶줷줸줹줺줻줼줽줾줿쥀쥁쥂쥃쥄쥅쥆쥇쥈쥉쥊쥋쥌쥍쥎쥏쥐쥑쥒쥓쥔쥕쥖쥗쥘쥙쥚쥛쥜쥝쥞쥟쥠쥡쥢쥣쥤쥥쥦쥧쥨쥩쥪쥫쥬쥭쥮쥯쥰쥱쥲쥳쥴쥵쥶쥷쥸쥹쥺쥻쥼쥽쥾쥿즀즁즂즃즄즅즆즇즈즉즊즋즌즍즎즏즐즑즒즓즔즕즖즗즘즙즚즛즜증즞즟즠즡즢즣즤즥즦즧즨즩즪즫즬즭즮즯즰즱즲즳즴즵즶즷즸즹즺즻즼즽즾즿지직짂짃진짅짆짇질짉짊짋짌짍짎짏짐집짒짓짔징짖짗짘짙짚짛짜짝짞짟짠짡짢짣짤짥짦짧짨짩짪짫짬짭짮짯짰짱짲짳짴짵짶짷째짹짺짻짼짽짾짿쨀쨁쨂쨃쨄쨅쨆쨇쨈쨉쨊쨋쨌쨍쨎쨏쨐쨑쨒쨓쨔쨕쨖쨗쨘쨙쨚쨛쨜쨝쨞쨟쨠쨡쨢쨣쨤쨥쨦쨧쨨쨩쨪쨫쨬쨭쨮쨯쨰쨱쨲쨳쨴쨵쨶쨷쨸쨹쨺쨻쨼쨽쨾쨿쩀쩁쩂쩃쩄쩅쩆쩇쩈쩉쩊쩋쩌쩍쩎쩏쩐쩑쩒쩓쩔쩕쩖쩗쩘쩙쩚쩛쩜쩝쩞쩟쩠쩡쩢쩣쩤쩥쩦쩧쩨쩩쩪쩫쩬쩭쩮쩯쩰쩱쩲쩳쩴쩵쩶쩷쩸쩹쩺쩻쩼쩽쩾쩿쪀쪁쪂쪃쪄쪅쪆쪇쪈쪉쪊쪋쪌쪍쪎쪏쪐쪑쪒쪓쪔쪕쪖쪗쪘쪙쪚쪛쪜쪝쪞쪟쪠쪡쪢쪣쪤쪥쪦쪧쪨쪩쪪쪫쪬쪭쪮쪯쪰쪱쪲쪳쪴쪵쪶쪷쪸쪹쪺쪻쪼쪽쪾쪿쫀쫁쫂쫃쫄쫅쫆쫇쫈쫉쫊쫋쫌쫍쫎쫏쫐쫑쫒쫓쫔쫕쫖쫗쫘쫙쫚쫛쫜쫝쫞쫟쫠쫡쫢쫣쫤쫥쫦쫧쫨쫩쫪쫫쫬쫭쫮쫯쫰쫱쫲쫳쫴쫵쫶쫷쫸쫹쫺쫻쫼쫽쫾쫿쬀쬁쬂쬃쬄쬅쬆쬇쬈쬉쬊쬋쬌쬍쬎쬏쬐쬑쬒쬓쬔쬕쬖쬗쬘쬙쬚쬛쬜쬝쬞쬟쬠쬡쬢쬣쬤쬥쬦쬧쬨쬩쬪쬫쬬쬭쬮쬯쬰쬱쬲쬳쬴쬵쬶쬷쬸쬹쬺쬻쬼쬽쬾쬿쭀쭁쭂쭃쭄쭅쭆쭇쭈쭉쭊쭋쭌쭍쭎쭏쭐쭑쭒쭓쭔쭕쭖쭗쭘쭙쭚쭛쭜쭝쭞쭟쭠쭡쭢쭣쭤쭥쭦쭧쭨쭩쭪쭫쭬쭭쭮쭯쭰쭱쭲쭳쭴쭵쭶쭷쭸쭹쭺쭻쭼쭽쭾쭿쮀쮁쮂쮃쮄쮅쮆쮇쮈쮉쮊쮋쮌쮍쮎쮏쮐쮑쮒쮓쮔쮕쮖쮗쮘쮙쮚쮛쮜쮝쮞쮟쮠쮡쮢쮣쮤쮥쮦쮧쮨쮩쮪쮫쮬쮭쮮쮯쮰쮱쮲쮳쮴쮵쮶쮷쮸쮹쮺쮻쮼쮽쮾쮿쯀쯁쯂쯃쯄쯅쯆쯇쯈쯉쯊쯋쯌쯍쯎쯏쯐쯑쯒쯓쯔쯕쯖쯗쯘쯙쯚쯛쯜쯝쯞쯟쯠쯡쯢쯣쯤쯥쯦쯧쯨쯩쯪쯫쯬쯭쯮쯯쯰쯱쯲쯳쯴쯵쯶쯷쯸쯹쯺쯻쯼쯽쯾쯿찀찁찂찃찄찅찆찇찈찉찊찋찌찍찎찏찐찑찒찓찔찕찖찗찘찙찚찛찜찝찞찟찠찡찢찣찤찥찦찧차착찪찫찬찭찮찯찰찱찲찳찴찵찶찷참찹찺찻찼창찾찿챀챁챂챃채책챆챇챈챉챊챋챌챍챎챏챐챑챒챓챔챕챖챗챘챙챚챛챜챝챞챟챠챡챢챣챤챥챦챧챨챩챪챫챬챭챮챯챰챱챲챳챴챵챶챷챸챹챺챻챼챽챾챿첀첁첂첃첄첅첆첇첈첉첊첋첌첍첎첏첐첑첒첓첔첕첖첗처척첚첛천첝첞첟철첡첢첣첤첥첦첧첨첩첪첫첬청첮첯첰첱첲첳체첵첶첷첸첹첺첻첼첽첾첿쳀쳁쳂쳃쳄쳅쳆쳇쳈쳉쳊쳋쳌쳍쳎쳏쳐쳑쳒쳓쳔쳕쳖쳗쳘쳙쳚쳛쳜쳝쳞쳟쳠쳡쳢쳣쳤쳥쳦쳧쳨쳩쳪쳫쳬쳭쳮쳯쳰쳱쳲쳳쳴쳵쳶쳷쳸쳹쳺쳻쳼쳽쳾쳿촀촁촂촃촄촅촆촇초촉촊촋촌촍촎촏촐촑촒촓촔촕촖촗촘촙촚촛촜총촞촟촠촡촢촣촤촥촦촧촨촩촪촫촬촭촮촯촰촱촲촳촴촵촶촷촸촹촺촻촼촽촾촿쵀쵁쵂쵃쵄쵅쵆쵇쵈쵉쵊쵋쵌쵍쵎쵏쵐쵑쵒쵓쵔쵕쵖쵗쵘쵙쵚쵛최쵝쵞쵟쵠쵡쵢쵣쵤쵥쵦쵧쵨쵩쵪쵫쵬쵭쵮쵯쵰쵱쵲쵳쵴쵵쵶쵷쵸쵹쵺쵻쵼쵽쵾쵿춀춁춂춃춄춅춆춇춈춉춊춋춌춍춎춏춐춑춒춓추축춖춗춘춙춚춛출춝춞춟춠춡춢춣춤춥춦춧춨충춪춫춬춭춮춯춰춱춲춳춴춵춶춷춸춹춺춻춼춽춾춿췀췁췂췃췄췅췆췇췈췉췊췋췌췍췎췏췐췑췒췓췔췕췖췗췘췙췚췛췜췝췞췟췠췡췢췣췤췥췦췧취췩췪췫췬췭췮췯췰췱췲췳췴췵췶췷췸췹췺췻췼췽췾췿츀츁츂츃츄츅츆츇츈츉츊츋츌츍츎츏츐츑츒츓츔츕츖츗츘츙츚츛츜츝츞츟츠측츢츣츤츥츦츧츨츩츪츫츬츭츮츯츰츱츲츳츴층츶츷츸츹츺츻츼츽츾츿칀칁칂칃칄칅칆칇칈칉칊칋칌칍칎칏칐칑칒칓칔칕칖칗치칙칚칛친칝칞칟칠칡칢칣칤칥칦칧침칩칪칫칬칭칮칯칰칱칲칳카칵칶칷칸칹칺칻칼칽칾칿캀캁캂캃캄캅캆캇캈캉캊캋캌캍캎캏캐캑캒캓캔캕캖캗캘캙캚캛캜캝캞캟캠캡캢캣캤캥캦캧캨캩캪캫캬캭캮캯캰캱캲캳캴캵캶캷캸캹캺캻캼캽캾캿컀컁컂컃컄컅컆컇컈컉컊컋컌컍컎컏컐컑컒컓컔컕컖컗컘컙컚컛컜컝컞컟컠컡컢컣커컥컦컧컨컩컪컫컬컭컮컯컰컱컲컳컴컵컶컷컸컹컺컻컼컽컾컿케켁켂켃켄켅켆켇켈켉켊켋켌켍켎켏켐켑켒켓켔켕켖켗켘켙켚켛켜켝켞켟켠켡켢켣켤켥켦켧켨켩켪켫켬켭켮켯켰켱켲켳켴켵켶켷켸켹켺켻켼켽켾켿콀콁콂콃콄콅콆콇콈콉콊콋콌콍콎콏콐콑콒콓코콕콖콗콘콙콚콛콜콝콞콟콠콡콢콣콤콥콦콧콨콩콪콫콬콭콮콯콰콱콲콳콴콵콶콷콸콹콺콻콼콽콾콿쾀쾁쾂쾃쾄쾅쾆쾇쾈쾉쾊쾋쾌쾍쾎쾏쾐쾑쾒쾓쾔쾕쾖쾗쾘쾙쾚쾛쾜쾝쾞쾟쾠쾡쾢쾣쾤쾥쾦쾧쾨쾩쾪쾫쾬쾭쾮쾯쾰쾱쾲쾳쾴쾵쾶쾷쾸쾹쾺쾻쾼쾽쾾쾿쿀쿁쿂쿃쿄쿅쿆쿇쿈쿉쿊쿋쿌쿍쿎쿏쿐쿑쿒쿓쿔쿕쿖쿗쿘쿙쿚쿛쿜쿝쿞쿟쿠쿡쿢쿣쿤쿥쿦쿧쿨쿩쿪쿫쿬쿭쿮쿯쿰쿱쿲쿳쿴쿵쿶쿷쿸쿹쿺쿻쿼쿽쿾쿿퀀퀁퀂퀃퀄퀅퀆퀇퀈퀉퀊퀋퀌퀍퀎퀏퀐퀑퀒퀓퀔퀕퀖퀗퀘퀙퀚퀛퀜퀝퀞퀟퀠퀡퀢퀣퀤퀥퀦퀧퀨퀩퀪퀫퀬퀭퀮퀯퀰퀱퀲퀳퀴퀵퀶퀷퀸퀹퀺퀻퀼퀽퀾퀿큀큁큂큃큄큅큆큇큈큉큊큋큌큍큎큏큐큑큒큓큔큕큖큗큘큙큚큛큜큝큞큟큠큡큢큣큤큥큦큧큨큩큪큫크큭큮큯큰큱큲큳클큵큶큷큸큹큺큻큼큽큾큿킀킁킂킃킄킅킆킇킈킉킊킋킌킍킎킏킐킑킒킓킔킕킖킗킘킙킚킛킜킝킞킟킠킡킢킣키킥킦킧킨킩킪킫킬킭킮킯킰킱킲킳킴킵킶킷킸킹킺킻킼킽킾킿타탁탂탃탄탅탆탇탈탉탊탋탌탍탎탏탐탑탒탓탔탕탖탗탘탙탚탛태택탞탟탠탡탢탣탤탥탦탧탨탩탪탫탬탭탮탯탰탱탲탳탴탵탶탷탸탹탺탻탼탽탾탿턀턁턂턃턄턅턆턇턈턉턊턋턌턍턎턏턐턑턒턓턔턕턖턗턘턙턚턛턜턝턞턟턠턡턢턣턤턥턦턧턨턩턪턫턬턭턮턯터턱턲턳턴턵턶턷털턹턺턻턼턽턾턿텀텁텂텃텄텅텆텇텈텉텊텋테텍텎텏텐텑텒텓텔텕텖텗텘텙텚텛템텝텞텟텠텡텢텣텤텥텦텧텨텩텪텫텬텭텮텯텰텱텲텳텴텵텶텷텸텹텺텻텼텽텾텿톀톁톂톃톄톅톆톇톈톉톊톋톌톍톎톏톐톑톒톓톔톕톖톗톘톙톚톛톜톝톞톟토톡톢톣톤톥톦톧톨톩톪톫톬톭톮톯톰톱톲톳톴통톶톷톸톹톺톻톼톽톾톿퇀퇁퇂퇃퇄퇅퇆퇇퇈퇉퇊퇋퇌퇍퇎퇏퇐퇑퇒퇓퇔퇕퇖퇗퇘퇙퇚퇛퇜퇝퇞퇟퇠퇡퇢퇣퇤퇥퇦퇧퇨퇩퇪퇫퇬퇭퇮퇯퇰퇱퇲퇳퇴퇵퇶퇷퇸퇹퇺퇻퇼퇽퇾퇿툀툁툂툃툄툅툆툇툈툉툊툋툌툍툎툏툐툑툒툓툔툕툖툗툘툙툚툛툜툝툞툟툠툡툢툣툤툥툦툧툨툩툪툫투툭툮툯툰툱툲툳툴툵툶툷툸툹툺툻툼툽툾툿퉀퉁퉂퉃퉄퉅퉆퉇퉈퉉퉊퉋퉌퉍퉎퉏퉐퉑퉒퉓퉔퉕퉖퉗퉘퉙퉚퉛퉜퉝퉞퉟퉠퉡퉢퉣퉤퉥퉦퉧퉨퉩퉪퉫퉬퉭퉮퉯퉰퉱퉲퉳퉴퉵퉶퉷퉸퉹퉺퉻퉼퉽퉾퉿튀튁튂튃튄튅튆튇튈튉튊튋튌튍튎튏튐튑튒튓튔튕튖튗튘튙튚튛튜튝튞튟튠튡튢튣튤튥튦튧튨튩튪튫튬튭튮튯튰튱튲튳튴튵튶튷트특튺튻튼튽튾튿틀틁틂틃틄틅틆틇틈틉틊틋틌틍틎틏틐틑틒틓틔틕틖틗틘틙틚틛틜틝틞틟틠틡틢틣틤틥틦틧틨틩틪틫틬틭틮틯티틱틲틳틴틵틶틷틸틹틺틻틼틽틾틿팀팁팂팃팄팅팆팇팈팉팊팋파팍팎팏판팑팒팓팔팕팖팗팘팙팚팛팜팝팞팟팠팡팢팣팤팥팦팧패팩팪팫팬팭팮팯팰팱팲팳팴팵팶팷팸팹팺팻팼팽팾팿퍀퍁퍂퍃퍄퍅퍆퍇퍈퍉퍊퍋퍌퍍퍎퍏퍐퍑퍒퍓퍔퍕퍖퍗퍘퍙퍚퍛퍜퍝퍞퍟퍠퍡퍢퍣퍤퍥퍦퍧퍨퍩퍪퍫퍬퍭퍮퍯퍰퍱퍲퍳퍴퍵퍶퍷퍸퍹퍺퍻퍼퍽퍾퍿펀펁펂펃펄펅펆펇펈펉펊펋펌펍펎펏펐펑펒펓펔펕펖펗페펙펚펛펜펝펞펟펠펡펢펣펤펥펦펧펨펩펪펫펬펭펮펯펰펱펲펳펴펵펶펷편펹펺펻펼펽펾펿폀폁폂폃폄폅폆폇폈평폊폋폌폍폎폏폐폑폒폓폔폕폖폗폘폙폚폛폜폝폞폟폠폡폢폣폤폥폦폧폨폩폪폫포폭폮폯폰폱폲폳폴폵폶폷폸폹폺폻폼폽폾폿퐀퐁퐂퐃퐄퐅퐆퐇퐈퐉퐊퐋퐌퐍퐎퐏퐐퐑퐒퐓퐔퐕퐖퐗퐘퐙퐚퐛퐜퐝퐞퐟퐠퐡퐢퐣퐤퐥퐦퐧퐨퐩퐪퐫퐬퐭퐮퐯퐰퐱퐲퐳퐴퐵퐶퐷퐸퐹퐺퐻퐼퐽퐾퐿푀푁푂푃푄푅푆푇푈푉푊푋푌푍푎푏푐푑푒푓푔푕푖푗푘푙푚푛표푝푞푟푠푡푢푣푤푥푦푧푨푩푪푫푬푭푮푯푰푱푲푳푴푵푶푷푸푹푺푻푼푽푾푿풀풁풂풃풄풅풆풇품풉풊풋풌풍풎풏풐풑풒풓풔풕풖풗풘풙풚풛풜풝풞풟풠풡풢풣풤풥풦풧풨풩풪풫풬풭풮풯풰풱풲풳풴풵풶풷풸풹풺풻풼풽풾풿퓀퓁퓂퓃퓄퓅퓆퓇퓈퓉퓊퓋퓌퓍퓎퓏퓐퓑퓒퓓퓔퓕퓖퓗퓘퓙퓚퓛퓜퓝퓞퓟퓠퓡퓢퓣퓤퓥퓦퓧퓨퓩퓪퓫퓬퓭퓮퓯퓰퓱퓲퓳퓴퓵퓶퓷퓸퓹퓺퓻퓼퓽퓾퓿픀픁픂픃프픅픆픇픈픉픊픋플픍픎픏픐픑픒픓픔픕픖픗픘픙픚픛픜픝픞픟픠픡픢픣픤픥픦픧픨픩픪픫픬픭픮픯픰픱픲픳픴픵픶픷픸픹픺픻피픽픾픿핀핁핂핃필핅핆핇핈핉핊핋핌핍핎핏핐핑핒핓핔핕핖핗하학핚핛한핝핞핟할핡핢핣핤핥핦핧함합핪핫핬항핮핯핰핱핲핳해핵핶핷핸핹핺핻핼핽핾핿햀햁햂햃햄햅햆햇했행햊햋햌햍햎햏햐햑햒햓햔햕햖햗햘햙햚햛햜햝햞햟햠햡햢햣햤향햦햧햨햩햪햫햬햭햮햯햰햱햲햳햴햵햶햷햸햹햺햻햼햽햾햿헀헁헂헃헄헅헆헇허헉헊헋헌헍헎헏헐헑헒헓헔헕헖헗험헙헚헛헜헝헞헟헠헡헢헣헤헥헦헧헨헩헪헫헬헭헮헯헰헱헲헳헴헵헶헷헸헹헺헻헼헽헾헿혀혁혂혃현혅혆혇혈혉혊혋혌혍혎혏혐협혒혓혔형혖혗혘혙혚혛혜혝혞혟혠혡혢혣혤혥혦혧혨혩혪혫혬혭혮혯혰혱혲혳혴혵혶혷호혹혺혻혼혽혾혿홀홁홂홃홄홅홆홇홈홉홊홋홌홍홎홏홐홑홒홓화확홖홗환홙홚홛활홝홞홟홠홡홢홣홤홥홦홧홨황홪홫홬홭홮홯홰홱홲홳홴홵홶홷홸홹홺홻홼홽홾홿횀횁횂횃횄횅횆횇횈횉횊횋회획횎횏횐횑횒횓횔횕횖횗횘횙횚횛횜횝횞횟횠횡횢횣횤횥횦횧효횩횪횫횬횭횮횯횰횱횲횳횴횵횶횷횸횹횺횻횼횽횾횿훀훁훂훃후훅훆훇훈훉훊훋훌훍훎훏훐훑훒훓훔훕훖훗훘훙훚훛훜훝훞훟훠훡훢훣훤훥훦훧훨훩훪훫훬훭훮훯훰훱훲훳훴훵훶훷훸훹훺훻훼훽훾훿휀휁휂휃휄휅휆휇휈휉휊휋휌휍휎휏휐휑휒휓휔휕휖휗휘휙휚휛휜휝휞휟휠휡휢휣휤휥휦휧휨휩휪휫휬휭휮휯휰휱휲휳휴휵휶휷휸휹휺휻휼휽휾휿흀흁흂흃흄흅흆흇흈흉흊흋흌흍흎흏흐흑흒흓흔흕흖흗흘흙흚흛흜흝흞흟흠흡흢흣흤흥흦흧흨흩흪흫희흭흮흯흰흱흲흳흴흵흶흷흸흹흺흻흼흽흾흿힀힁힂힃힄힅힆힇히힉힊힋힌힍힎힏힐힑힒힓힔힕힖힗힘힙힚힛힜힝힞힟힠힡힢힣ힰힱힲힳힴힵힶힷힸힹힺힻힼힽힾힿퟀퟁퟂퟃퟄퟅퟆퟋퟌퟍퟎퟏퟐퟑퟒퟓퟔퟕퟖퟗퟘퟙퟚퟛퟜퟝퟞퟟퟠퟡퟢퟣퟤퟥퟦퟧퟨퟩퟪퟫퟬퟭퟮퟯퟰퟱퟲퟳퟴퟵퟶퟷퟸퟹퟺퟻ???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????􏰀???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????豈更車賈滑串句龜龜契金喇奈懶癩羅蘿螺裸邏樂洛烙珞落酪駱亂卵欄爛蘭鸞嵐濫藍襤拉臘蠟廊朗浪狼郎來冷勞擄櫓爐盧老蘆虜路露魯鷺碌祿綠菉錄鹿論壟弄籠聾牢磊賂雷壘屢樓淚漏累縷陋勒肋凜凌稜綾菱陵讀拏樂諾丹寧怒率異北磻便復不泌數索參塞省葉說殺辰沈拾若掠略亮兩凉梁糧良諒量勵呂女廬旅濾礪閭驪麗黎力曆歷轢年憐戀撚漣煉璉秊練聯輦蓮連鍊列劣咽烈裂說廉念捻殮簾獵令囹寧嶺怜玲瑩羚聆鈴零靈領例禮醴隸惡了僚寮尿料樂燎療蓼遼龍暈阮劉杻柳流溜琉留硫紐類六戮陸倫崙淪輪律慄栗率隆利吏履易李梨泥理痢罹裏裡里離匿溺吝燐璘藺隣鱗麟林淋臨立笠粒狀炙識什茶刺切度拓糖宅洞暴輻行降見廓兀嗀﨎﨏塚﨑晴﨓﨔凞猪益礼神祥福靖精羽﨟蘒﨡諸﨣﨤逸都﨧﨨﨩飯飼館鶴郞隷侮僧免勉勤卑喝嘆器塀墨層屮悔慨憎懲敏既暑梅海渚漢煮爫琢碑社祉祈祐祖祝禍禎穀突節練縉繁署者臭艹艹著褐視謁謹賓贈辶逸難響頻恵𤋮舘並况全侀充冀勇勺喝啕喙嗢塚墳奄奔婢嬨廒廙彩徭惘慎愈憎慠懲戴揄搜摒敖晴朗望杖歹殺流滛滋漢瀞煮瞧爵犯猪瑱甆画瘝瘟益盛直睊着磌窱節类絛練缾者荒華蝹襁覆視調諸請謁諾諭謹變贈輸遲醙鉶陼難靖韛響頋頻鬒龜𢡊𢡄𣏕㮝䀘䀹𥉉𥳐𧻓齃龎fffiflffifflſtstﬓﬔﬕﬖﬗיִﬞײַﬠﬡﬢﬣﬤﬥﬦﬧﬨ﬩שׁשׂשּׁשּׂאַאָאּבּגּדּהּוּזּטּיּךּכּלּמּנּסּףּפּצּקּרּשּתּוֹבֿכֿפֿﭏﭐﭑﭒﭓﭔﭕﭖﭗﭘﭙﭚﭛﭜﭝﭞﭟﭠﭡﭢﭣﭤﭥﭦﭧﭨﭩﭪﭫﭬﭭﭮﭯﭰﭱﭲﭳﭴﭵﭶﭷﭸﭹﭺﭻﭼﭽﭾﭿﮀﮁﮂﮃﮄﮅﮆﮇﮈﮉﮊﮋﮌﮍﮎﮏﮐﮑﮒﮓﮔﮕﮖﮗﮘﮙﮚﮛﮜﮝﮞﮟﮠﮡﮢﮣﮤﮥﮦﮧﮨﮩﮪﮫﮬﮭﮮﮯﮰﮱ﮲﮳﮴﮵﮶﮷﮸﮹﮺﮻﮼﮽﮾﮿﯀﯁ﯓﯔﯕﯖﯗﯘﯙﯚﯛﯜﯝﯞﯟﯠﯡﯢﯣﯤﯥﯦﯧﯨﯩﯪﯫﯬﯭﯮﯯﯰﯱﯲﯳﯴﯵﯶﯷﯸﯹﯺﯻﯼﯽﯾﯿﰀﰁﰂﰃﰄﰅﰆﰇﰈﰉﰊﰋﰌﰍﰎﰏﰐﰑﰒﰓﰔﰕﰖﰗﰘﰙﰚﰛﰜﰝﰞﰟﰠﰡﰢﰣﰤﰥﰦﰧﰨﰩﰪﰫﰬﰭﰮﰯﰰﰱﰲﰳﰴﰵﰶﰷﰸﰹﰺﰻﰼﰽﰾﰿﱀﱁﱂﱃﱄﱅﱆﱇﱈﱉﱊﱋﱌﱍﱎﱏﱐﱑﱒﱓﱔﱕﱖﱗﱘﱙﱚﱛﱜﱝﱞﱟﱠﱡﱢﱣﱤﱥﱦﱧﱨﱩﱪﱫﱬﱭﱮﱯﱰﱱﱲﱳﱴﱵﱶﱷﱸﱹﱺﱻﱼﱽﱾﱿﲀﲁﲂﲃﲄﲅﲆﲇﲈﲉﲊﲋﲌﲍﲎﲏﲐﲑﲒﲓﲔﲕﲖﲗﲘﲙﲚﲛﲜﲝﲞﲟﲠﲡﲢﲣﲤﲥﲦﲧﲨﲩﲪﲫﲬﲭﲮﲯﲰﲱﲲﲳﲴﲵﲶﲷﲸﲹﲺﲻﲼﲽﲾﲿﳀﳁﳂﳃﳄﳅﳆﳇﳈﳉﳊﳋﳌﳍﳎﳏﳐﳑﳒﳓﳔﳕﳖﳗﳘﳙﳚﳛﳜﳝﳞﳟﳠﳡﳢﳣﳤﳥﳦﳧﳨﳩﳪﳫﳬﳭﳮﳯﳰﳱﳲﳳﳴﳵﳶﳷﳸﳹﳺﳻﳼﳽﳾﳿﴀﴁﴂﴃﴄﴅﴆﴇﴈﴉﴊﴋﴌﴍﴎﴏﴐﴑﴒﴓﴔﴕﴖﴗﴘﴙﴚﴛﴜﴝﴞﴟﴠﴡﴢﴣﴤﴥﴦﴧﴨﴩﴪﴫﴬﴭﴮﴯﴰﴱﴲﴳﴴﴵﴶﴷﴸﴹﴺﴻﴼﴽ﴾﴿ﵐﵑﵒﵓﵔﵕﵖﵗﵘﵙﵚﵛﵜﵝﵞﵟﵠﵡﵢﵣﵤﵥﵦﵧﵨﵩﵪﵫﵬﵭﵮﵯﵰﵱﵲﵳﵴﵵﵶﵷﵸﵹﵺﵻﵼﵽﵾﵿﶀﶁﶂﶃﶄﶅﶆﶇﶈﶉﶊﶋﶌﶍﶎﶏﶒﶓﶔﶕﶖﶗﶘﶙﶚﶛﶜﶝﶞﶟﶠﶡﶢﶣﶤﶥﶦﶧﶨﶩﶪﶫﶬﶭﶮﶯﶰﶱﶲﶳﶴﶵﶶﶷﶸﶹﶺﶻﶼﶽﶾﶿﷀﷁﷂﷃﷄﷅﷆﷇﷰﷱﷲﷳﷴﷵﷶﷷﷸﷹﷺﷻ﷼﷽︀︁︂︃︄︅︆︇︈︉︊︋︌︍︎️︐︑︒︓︔︕︖︗︘︙︠︡︢︣︤︥︦︰︱︲︳︴︵︶︷︸︹︺︻︼︽︾︿﹀﹁﹂﹃﹄﹅﹆﹇﹈﹉﹊﹋﹌﹍﹎﹏﹐﹑﹒﹔﹕﹖﹗﹘﹙﹚﹛﹜﹝﹞﹟﹠﹡﹢﹣﹤﹥﹦﹨﹩﹪﹫ﹰﹱﹲﹳﹴﹶﹷﹸﹹﹺﹻﹼﹽﹾﹿﺀﺁﺂﺃﺄﺅﺆﺇﺈﺉﺊﺋﺌﺍﺎﺏﺐﺑﺒﺓﺔﺕﺖﺗﺘﺙﺚﺛﺜﺝﺞﺟﺠﺡﺢﺣﺤﺥﺦﺧﺨﺩﺪﺫﺬﺭﺮﺯﺰﺱﺲﺳﺴﺵﺶﺷﺸﺹﺺﺻﺼﺽﺾﺿﻀﻁﻂﻃﻄﻅﻆﻇﻈﻉﻊﻋﻌﻍﻎﻏﻐﻑﻒﻓﻔﻕﻖﻗﻘﻙﻚﻛﻜﻝﻞﻟﻠﻡﻢﻣﻤﻥﻦﻧﻨﻩﻪﻫﻬﻭﻮﻯﻰﻱﻲﻳﻴﻵﻶﻷﻸﻹﻺﻻﻼ!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~⦅⦆。「」、・ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙゚ᅠᄀᄁᆪᄂᆬᆭᄃᄄᄅᆰᆱᆲᆳᆴᆵᄚᄆᄇᄈᄡᄉᄊᄋᄌᄍᄎᄏᄐᄑ하ᅢᅣᅤᅥᅦᅧᅨᅩᅪᅫᅬᅭᅮᅯᅰᅱᅲᅳᅴᅵ¢£¬ ̄¦¥₩│←↑→↓■○�‬‬‬ +#!#😀😃😁😎😒😞😍🙂😆😊😉 +#!#ऀँंःऄअआइईउऊऋऌऍऎएऐऑऒओऔकखगघङचछजझञटठडढणतथदधनऩपफबभमयरऱलळऴवशषसहऺऻ़ऽािीुूृॄॅॆेैॉॊोौ्ॎॏॐ॒॑॓॔ॕॖॗक़ख़ग़ज़ड़ढ़फ़य़ॠॡॢॣ।॥०१२३४५६७८९॰ॱॲॳॴॵॶॷॹॺॻॼॽॾॿ +~~END~~ + +DROP TABLE TEXT_dt; diff --git a/contrib/test/python/expected/pyodbc/TestTime.out b/contrib/test/python/expected/pyodbc/TestTime.out new file mode 100644 index 00000000000..ef840209b45 --- /dev/null +++ b/contrib/test/python/expected/pyodbc/TestTime.out @@ -0,0 +1,300 @@ +Create table TestTime(a time(6)) + +prepst#!# Insert into TestTime Values(?) #!#Time|-|a|-|12:45:37.123|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.123|-|3 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.12|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.1|-|1 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.1234|-|4 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|6 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|5 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-| +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]column "a" is of type time without time zone but expression is of type "varchar" (33557097) (SQLExecDirectW))~~ + + +select * from TestTime +~~START~~ +time +12:45:37 +12:45:37 +12:45:37 +12:45:37 +12:45:37 +12:45:37 +12:45:37 +~~END~~ + + +Drop table TestTime + +Create table TestTime(a time(5)) + +prepst#!# Insert into TestTime Values(?) #!#Time|-|a|-|12:45:37.123|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.123|-|3 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.12|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.1|-|1 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.1234|-|4 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|6 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|5 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-| +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]column "a" is of type time without time zone but expression is of type "varchar" (33557097) (SQLExecDirectW))~~ + + +select * from TestTime +~~START~~ +time +12:45:37 +12:45:37 +12:45:37 +12:45:37 +12:45:37 +12:45:37 +12:45:37 +~~END~~ + + +Drop table TestTime + +Create table TestTime(a time(4)) + +prepst#!# Insert into TestTime Values(?) #!#Time|-|a|-|12:45:37.123|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.123|-|3 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.12|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.1|-|1 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.1234|-|4 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|6 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|5 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-| +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]column "a" is of type time without time zone but expression is of type "varchar" (33557097) (SQLExecDirectW))~~ + + +select * from TestTime +~~START~~ +time +12:45:37 +12:45:37 +12:45:37 +12:45:37 +12:45:37 +12:45:37 +12:45:37 +~~END~~ + + +Drop table TestTime + +Create table TestTime(a time(3)) + +prepst#!# Insert into TestTime Values(?) #!#Time|-|a|-|12:45:37.123|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.123|-|3 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.12|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.1|-|1 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.1234|-|4 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|6 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|5 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-| +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]column "a" is of type time without time zone but expression is of type "varchar" (33557097) (SQLExecDirectW))~~ + + +select * from TestTime +~~START~~ +time +12:45:37 +12:45:37 +12:45:37 +12:45:37 +12:45:37 +12:45:37 +12:45:37 +~~END~~ + + +Drop table TestTime + +Create table TestTime(a time(2)) + +prepst#!# Insert into TestTime Values(?) #!#Time|-|a|-|12:45:37.123|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.123|-|3 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.12|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.1|-|1 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.1234|-|4 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|6 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|5 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-| +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]column "a" is of type time without time zone but expression is of type "varchar" (33557097) (SQLExecDirectW))~~ + + +select * from TestTime +~~START~~ +time +12:45:37 +12:45:37 +12:45:37 +12:45:37 +12:45:37 +12:45:37 +12:45:37 +~~END~~ + + +Drop table TestTime + +Create table TestTime(a time(1)) + +prepst#!# Insert into TestTime Values(?) #!#Time|-|a|-|12:45:37.123|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.123|-|3 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.12|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.1|-|1 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.1234|-|4 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|6 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|5 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-| +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]column "a" is of type time without time zone but expression is of type "varchar" (33557097) (SQLExecDirectW))~~ + + +select * from TestTime +~~START~~ +time +12:45:37 +12:45:37 +12:45:37 +12:45:37 +12:45:37 +12:45:37 +12:45:37 +~~END~~ + + +Drop table TestTime + +Create table TestTime(a time(0)) + +prepst#!# Insert into TestTime Values(?) #!#Time|-|a|-|12:45:37.123|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.123|-|3 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.12|-|2 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.1|-|1 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.1234|-|4 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|6 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|5 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#Time|-|a|-| +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]column "a" is of type time without time zone but expression is of type "varchar" (33557097) (SQLExecDirectW))~~ + + +select * from TestTime +~~START~~ +time +12:45:37 +12:45:37 +12:45:37 +12:45:37 +12:45:37 +12:45:37 +12:45:37 +~~END~~ + + +Drop table TestTime diff --git a/contrib/test/python/expected/pyodbc/TestTinyInt.out b/contrib/test/python/expected/pyodbc/TestTinyInt.out new file mode 100644 index 00000000000..80debcb6855 --- /dev/null +++ b/contrib/test/python/expected/pyodbc/TestTinyInt.out @@ -0,0 +1,101 @@ +CREATE TABLE TINYINT_dt (a TINYINT) +prepst#!# INSERT INTO TINYINT_dt(a) values(?) #!#TINYINT|-|a|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#TINYINT|-|a|-|-10 +~~ERROR (Code: 220)~~ +~~ERROR (Message: [22003] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]value for domain tinyint violates check constraint "tinyint_check" (220) (SQLExecDirectW))~~ + +prepst#!#exec#!#TINYINT|-|a|-|100 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#TINYINT|-|a|-|002 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#TINYINT|-|a|-|029 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#TINYINT|-|a|-|004 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#TINYINT|-|a|-|87 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#TINYINT|-|a|-|0 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#TINYINT|-|a|-|255 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#TINYINT|-|a|-| +~~ROW COUNT: 1~~ + +SELECT * FROM TINYINT_dt; +~~START~~ +int +0 +100 +2 +29 +4 +87 +0 +255 + +~~END~~ + +INSERT INTO TINYINT_dt(a) values(0) +~~ROW COUNT: 1~~ + +INSERT INTO TINYINT_dt(a) values(120) +~~ROW COUNT: 1~~ + +INSERT INTO TINYINT_dt(a) values(100) +~~ROW COUNT: 1~~ + +INSERT INTO TINYINT_dt(a) values(004) +~~ROW COUNT: 1~~ + +INSERT INTO TINYINT_dt(a) values(0) +~~ROW COUNT: 1~~ + +INSERT INTO TINYINT_dt(a) values(002) +~~ROW COUNT: 1~~ + +INSERT INTO TINYINT_dt(a) values(86) +~~ROW COUNT: 1~~ + +INSERT INTO TINYINT_dt(a) values(1000) +~~ERROR (Code: 220)~~ +~~ERROR (Message: [22003] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]value for domain tinyint violates check constraint "tinyint_check" (220) (SQLExecDirectW))~~ + +INSERT INTO TINYINT_dt(a) values(255) +~~ROW COUNT: 1~~ + +INSERT INTO TINYINT_dt(a) values(NULL) +~~ROW COUNT: 1~~ + +SELECT * FROM TINYINT_dt; +~~START~~ +int +0 +100 +2 +29 +4 +87 +0 +255 + +0 +120 +100 +4 +0 +2 +86 +255 + +~~END~~ + +DROP TABLE TINYINT_dt; diff --git a/contrib/test/python/expected/pyodbc/TestTransactionSupportForProcedure.out b/contrib/test/python/expected/pyodbc/TestTransactionSupportForProcedure.out new file mode 100644 index 00000000000..7bdf559fbcc --- /dev/null +++ b/contrib/test/python/expected/pyodbc/TestTransactionSupportForProcedure.out @@ -0,0 +1,928 @@ +#setup +create table txnproctable (c1 int not null, c2 varchar(100)) + +# PROC +# BEGIN TRAN +# SAVEPOINT +# ROLLBACK SAVEPOINT +# COMMIT +create procedure txnproc1 as begin tran; insert into txnproctable values (1, 'abc'); save tran sp1; update txnproctable set c1 = c1 + 1; rollback tran sp1; commit tran; +select @@trancount; +~~START~~ +int +0 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#str +~~END~~ + +exec txnproc1; +~~ROW COUNT: 1~~ + +select @@trancount; +~~START~~ +int +0 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#str +1#!#abc +~~END~~ + + + +# PROC +# BEGIN TRAN +# SAVEPOINT +# ROLLBACK SAVEPOINT +# ROLLBACK +drop procedure txnproc1; +create procedure txnproc1 as begin tran; insert into txnproctable values(2, 'xyz'); save tran sp1; delete from txnproctable; rollback tran sp1; rollback tran; +select @@trancount; +~~START~~ +int +0 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#str +1#!#abc +~~END~~ + +exec txnproc1; +~~ROW COUNT: 1~~ + +select @@trancount; +~~START~~ +int +0 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#str +1#!#abc +~~END~~ + + + +# PROC +# BEGIN TRAN +# SAVEPOINT +# ROLLBACK SAVEPOINT +# COMMIT +drop procedure txnproc1 +create procedure txnproc1 as begin tran; insert into txnproctable values(3, 'dbd'); save tran sp1; update txnproctable set c1 = c1 + 1; rollback tran sp1; +select @@trancount +~~START~~ +int +0 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#str +1#!#abc +~~END~~ + +exec txnproc1; +~~ROW COUNT: 1~~ + +~~ERROR (Code: 266)~~ +~~ERROR (Message: [25000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Transaction count after execution indicates a mismatch number of BEGIN and COMMIT statements. Previous count 0 current count 1 (266) (SQLMoreResults))~~ + +select @@trancount +~~START~~ +int +1 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#str +1#!#abc +3#!#dbd +~~END~~ + +commit tran; +select @@trancount +~~START~~ +int +0 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#str +1#!#abc +3#!#dbd +~~END~~ + + + +# PROC +# BEGIN TRAN +# SAVEPOINT +# ROLLBACK SAVEPOINT +# COMMIT +drop procedure txnproc1 +create procedure txnproc1 as begin tran; insert into txnproctable values(4, 'sbd'); save tran sp1; update txnproctable set c1 = c1 + 1; +select @@trancount +~~START~~ +int +0 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#str +1#!#abc +3#!#dbd +~~END~~ + +exec txnproc1; +~~ROW COUNT: 1~~ + +~~ERROR (Code: 266)~~ +~~ERROR (Message: [25000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Transaction count after execution indicates a mismatch number of BEGIN and COMMIT statements. Previous count 0 current count 1 (266) (SQLMoreResults))~~ + +select @@trancount +~~START~~ +int +1 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#str +2#!#abc +4#!#dbd +5#!#sbd +~~END~~ + +rollback tran sp1; +select @@trancount +~~START~~ +int +1 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#str +1#!#abc +3#!#dbd +4#!#sbd +~~END~~ + +commit tran; +select @@trancount +~~START~~ +int +0 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#str +1#!#abc +3#!#dbd +4#!#sbd +~~END~~ + + + +# BEGIN TRAN +# PROC +# SAVEPOINT +# ROLLBACK SAVEPOINT +# COMMIT +begin tran; +select @@trancount +~~START~~ +int +1 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#str +1#!#abc +3#!#dbd +4#!#sbd +~~END~~ + +drop procedure txnproc1 +create procedure txnproc1 as insert into txnproctable values(5, 'abc'); save tran sp1; update txnproctable set c1 = c1 + 1; rollback tran sp1; +select @@trancount +~~START~~ +int +1 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#str +1#!#abc +3#!#dbd +4#!#sbd +~~END~~ + +exec txnproc1; +~~ROW COUNT: 1~~ + +select @@trancount +~~START~~ +int +1 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#str +1#!#abc +3#!#dbd +4#!#sbd +5#!#abc +~~END~~ + +commit tran; +select @@trancount +~~START~~ +int +0 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#str +1#!#abc +3#!#dbd +4#!#sbd +5#!#abc +~~END~~ + + + +# BEGIN TRAN +# PROC +# SAVEPOINT +# ROLLBACK SAVEPOINT +# ROLLBACK +begin tran; +select @@trancount +~~START~~ +int +1 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#str +1#!#abc +3#!#dbd +4#!#sbd +5#!#abc +~~END~~ + +drop procedure txnproc1 +create procedure txnproc1 as insert into txnproctable values(6, 'abc'); save tran sp1; update txnproctable set c1 = c1 + 1; rollback tran sp1; +select @@trancount +~~START~~ +int +1 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#str +1#!#abc +3#!#dbd +4#!#sbd +5#!#abc +~~END~~ + +exec txnproc1; +~~ROW COUNT: 1~~ + +select @@trancount +~~START~~ +int +1 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#str +1#!#abc +3#!#dbd +4#!#sbd +5#!#abc +6#!#abc +~~END~~ + +commit tran; +select @@trancount +~~START~~ +int +0 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#str +1#!#abc +3#!#dbd +4#!#sbd +5#!#abc +6#!#abc +~~END~~ + + +# BEGIN TRAN +# PROC +# SAVEPOINT +# ROLLBACK SAVEPOINT +# COMMIT +begin tran; +select @@trancount +~~START~~ +int +1 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#str +1#!#abc +3#!#dbd +4#!#sbd +5#!#abc +6#!#abc +~~END~~ + +drop procedure txnproc1 +create procedure txnproc1 as insert into txnproctable values(7, 'abc'); save tran sp1; update txnproctable set c1 = c1 + 1; rollback tran sp1; update txnproctable set c1 = c1 + 1; commit tran; +select @@trancount +~~START~~ +int +1 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#str +1#!#abc +3#!#dbd +4#!#sbd +5#!#abc +6#!#abc +~~END~~ + +exec txnproc1; +~~ROW COUNT: 1~~ + +~~ERROR (Code: 266)~~ +~~ERROR (Message: [25000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Transaction count after execution indicates a mismatch number of BEGIN and COMMIT statements. Previous count 1 current count 0 (266) (SQLMoreResults))~~ + +select @@trancount +~~START~~ +int +0 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#str +2#!#abc +4#!#dbd +5#!#sbd +6#!#abc +7#!#abc +8#!#abc +~~END~~ + + +# BEGIN TRAN +# PROC +# SAVEPOINT +# ROLLBACK SAVEPOINT +# ROLLBACK +begin tran; +select @@trancount +~~START~~ +int +1 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#str +2#!#abc +4#!#dbd +5#!#sbd +6#!#abc +7#!#abc +8#!#abc +~~END~~ + +drop procedure txnproc1 +create procedure txnproc1 as insert into txnproctable values(8, 'abc'); save tran sp1; update txnproctable set c1 = c1 + 1; rollback tran sp1; update txnproctable set c1 = c1 + 1; rollback tran; +select @@trancount +~~START~~ +int +1 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#str +2#!#abc +4#!#dbd +5#!#sbd +6#!#abc +7#!#abc +8#!#abc +~~END~~ + +exec txnproc1; +~~ROW COUNT: 1~~ + +~~ERROR (Code: 266)~~ +~~ERROR (Message: [25000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Transaction count after execution indicates a mismatch number of BEGIN and COMMIT statements. Previous count 1 current count 0 (266) (SQLMoreResults))~~ + +select @@trancount +~~START~~ +int +0 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#str +2#!#abc +4#!#dbd +5#!#sbd +6#!#abc +7#!#abc +8#!#abc +~~END~~ + + +# BEGIN TRAN +# START SAVEPOINT +# PROC +# ROLLBACK SAVEPOINT +# ROLLBACK +begin tran; +select @@trancount +~~START~~ +int +1 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#str +2#!#abc +4#!#dbd +5#!#sbd +6#!#abc +7#!#abc +8#!#abc +~~END~~ + +save tran sp1; +select @@trancount +~~START~~ +int +1 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#str +2#!#abc +4#!#dbd +5#!#sbd +6#!#abc +7#!#abc +8#!#abc +~~END~~ + +drop procedure txnproc1 +create procedure txnproc1 as insert into txnproctable values(9, 'abc'); update txnproctable set c1 = c1 + 1; +select @@trancount +~~START~~ +int +1 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#str +2#!#abc +4#!#dbd +5#!#sbd +6#!#abc +7#!#abc +8#!#abc +~~END~~ + +exec txnproc1; +~~ROW COUNT: 1~~ + +rollback tran sp1; +select @@trancount +~~START~~ +int +1 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#str +2#!#abc +4#!#dbd +5#!#sbd +6#!#abc +7#!#abc +8#!#abc +~~END~~ + +rollback tran; +select @@trancount +~~START~~ +int +0 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#str +2#!#abc +4#!#dbd +5#!#sbd +6#!#abc +7#!#abc +8#!#abc +~~END~~ + + +# BEGIN TRAN +# START SAVEPOINT +# PROC +# ROLLBACK SAVEPOINT +# ROLLBACK +begin tran; +select @@trancount +~~START~~ +int +1 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#str +2#!#abc +4#!#dbd +5#!#sbd +6#!#abc +7#!#abc +8#!#abc +~~END~~ + +save tran sp1; +select @@trancount +~~START~~ +int +1 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#str +2#!#abc +4#!#dbd +5#!#sbd +6#!#abc +7#!#abc +8#!#abc +~~END~~ + +drop procedure txnproc1 +create procedure txnproc1 as insert into txnproctable values(10, 'abc'); update txnproctable set c1 = c1 + 1; +select @@trancount +~~START~~ +int +1 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#str +2#!#abc +4#!#dbd +5#!#sbd +6#!#abc +7#!#abc +8#!#abc +~~END~~ + +exec txnproc1; +~~ROW COUNT: 1~~ + +rollback tran sp1; +select @@trancount +~~START~~ +int +1 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#str +2#!#abc +4#!#dbd +5#!#sbd +6#!#abc +7#!#abc +8#!#abc +~~END~~ + +commit tran; +select @@trancount +~~START~~ +int +0 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#str +2#!#abc +4#!#dbd +5#!#sbd +6#!#abc +7#!#abc +8#!#abc +~~END~~ + + +# BEGIN TRAN +# START SAVEPOINT +# PROC +# ROLLBACK SAVEPOINT +# ROLLBACK +begin tran; +select @@trancount +~~START~~ +int +1 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#str +2#!#abc +4#!#dbd +5#!#sbd +6#!#abc +7#!#abc +8#!#abc +~~END~~ + +save tran sp1; +select @@trancount +~~START~~ +int +1 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#str +2#!#abc +4#!#dbd +5#!#sbd +6#!#abc +7#!#abc +8#!#abc +~~END~~ + +drop procedure txnproc1 +create procedure txnproc1 as insert into txnproctable values(11, 'abc'); rollback tran sp1; update txnproctable set c1 = c1 + 1; +select @@trancount +~~START~~ +int +1 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#str +2#!#abc +4#!#dbd +5#!#sbd +6#!#abc +7#!#abc +8#!#abc +~~END~~ + +exec txnproc1; +~~ROW COUNT: 1~~ + +commit tran; +select @@trancount +~~START~~ +int +0 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#str +3#!#abc +5#!#dbd +6#!#sbd +7#!#abc +8#!#abc +9#!#abc +~~END~~ + + +# PROC1 +# BEGIN TRAN +# PROC2 +# PROC3 +# BEGIN TRAN +# START SAVEPOINT +# ROLLBACK SAVEPOINT +# COMMIT +# COMMIT +create procedure txnProc3 as begin tran; insert into txnproctable values (16, 'abc'); save tran sp1; update txnproctable set c1 = c1 + 1; rollback tran sp1; +select @@trancount +~~START~~ +int +0 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#str +3#!#abc +5#!#dbd +6#!#sbd +7#!#abc +8#!#abc +9#!#abc +~~END~~ + +create procedure txnProc2 as update txnproctable set c1 = c1 + 1; exec txnProc3; commit tran; +select @@trancount +~~START~~ +int +0 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#str +3#!#abc +5#!#dbd +6#!#sbd +7#!#abc +8#!#abc +9#!#abc +~~END~~ + +drop procedure txnproc1 +create procedure txnproc1 as delete from txnproctable; begin tran; exec txnProc2; +select @@trancount +~~START~~ +int +0 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#str +3#!#abc +5#!#dbd +6#!#sbd +7#!#abc +8#!#abc +9#!#abc +~~END~~ + +exec txnproc1; +~~ROW COUNT: 6~~ + +~~ERROR (Code: 266)~~ +~~ERROR (Message: [25000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Transaction count after execution indicates a mismatch number of BEGIN and COMMIT statements. Previous count 1 current count 2 (266) (SQLMoreResults))~~ + +select @@trancount +~~START~~ +int +1 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#str +16#!#abc +~~END~~ + +commit tran; +select @@trancount +~~START~~ +int +0 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#str +16#!#abc +~~END~~ + + +# PROC1 +# BEGIN TRAN +# PROC2 +# PROC3 +# BEGIN TRAN +# START SAVEPOINT +# ROLLBACK SAVEPOINT +# ROLLBACK TRAN +# COMMIT +drop procedure txnproc3 +create procedure txnProc3 as begin tran; insert into txnproctable values (20, 'abc'); save tran sp1; update txnproctable set c1 = c1 + 1; rollback tran sp1; +select @@trancount +~~START~~ +int +0 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#str +16#!#abc +~~END~~ + +drop procedure txnproc2 +create procedure txnProc2 as update txnproctable set c1 = c1 + 1; exec txnProc3; rollback tran; +select @@trancount +~~START~~ +int +0 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#str +16#!#abc +~~END~~ + +drop procedure txnproc1 +create procedure txnproc1 as delete from txnproctable; begin tran; exec txnProc2; +select @@trancount +~~START~~ +int +0 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#str +16#!#abc +~~END~~ + +exec txnproc1; +~~ROW COUNT: 1~~ + +~~ERROR (Code: 266)~~ +~~ERROR (Message: [25000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Transaction count after execution indicates a mismatch number of BEGIN and COMMIT statements. Previous count 1 current count 2 (266) (SQLMoreResults))~~ + +select @@trancount +~~START~~ +int +0 +~~END~~ + +select * from txnproctable order by c1; +~~START~~ +int#!#str +~~END~~ + + +#cleanup +drop procedure txnproc3 +drop procedure txnproc2 +drop procedure txnproc1 +drop table txnproctable diff --git a/contrib/test/python/expected/pyodbc/TestTransactionsSQLBatch.out b/contrib/test/python/expected/pyodbc/TestTransactionsSQLBatch.out new file mode 100644 index 00000000000..22d290e2467 --- /dev/null +++ b/contrib/test/python/expected/pyodbc/TestTransactionsSQLBatch.out @@ -0,0 +1,492 @@ +create table TxnTable(c1 int); + +# Begin transaction -> commit transaction +begin transaction; +select @@trancount; +~~START~~ +int +1 +~~END~~ + +begin transaction; +select @@trancount; +~~START~~ +int +2 +~~END~~ + +set transaction isolation level read committed; +#show transaction_isolation; +#show default_transaction_isolation; +insert into TxnTable values(1); +~~ROW COUNT: 1~~ + +commit transaction; +select @@trancount; +~~START~~ +int +1 +~~END~~ + +commit transaction; +select @@trancount; +~~START~~ +int +0 +~~END~~ + +select c1 from TxnTable; +~~START~~ +int +1 +~~END~~ + + +# Begin transaction -> rollback transaction +begin transaction; +insert into TxnTable values(2); +~~ROW COUNT: 1~~ + +rollback transaction; +select c1 from TxnTable; +~~START~~ +int +1 +~~END~~ + + +#Begin tran -> commit tran +begin tran; +insert into TxnTable values(2); +~~ROW COUNT: 1~~ + +commit tran; +select c1 from TxnTable; +~~START~~ +int +1 +2 +~~END~~ + + +# Begin tran -> rollback tran +begin tran; +select @@trancount; +~~START~~ +int +1 +~~END~~ + +begin tran; +set transaction isolation level read uncommitted; +#show transaction_isolation; +#show default_transaction_isolation; +insert into TxnTable values(3); +~~ROW COUNT: 1~~ + +select @@trancount; +~~START~~ +int +2 +~~END~~ + +rollback tran; +select @@trancount; +~~START~~ +int +0 +~~END~~ + +select c1 from TxnTable; +~~START~~ +int +1 +2 +~~END~~ + + +set transaction isolation level repeatable read; +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]REPEATABLE READ isolation level is not supported (33557097) (SQLExecDirectW))~~ + +#show transaction_isolation; +#show default_transaction_isolation; + +# Begin transaction -> commit +begin transaction; +insert into TxnTable values(4); +~~ROW COUNT: 1~~ + +commit; +select c1 from TxnTable; +~~START~~ +int +1 +2 +4 +~~END~~ + + +# Begin transaction -> commit work +begin transaction; +insert into TxnTable values(5); +~~ROW COUNT: 1~~ + +commit work; +select c1 from TxnTable; +~~START~~ +int +1 +2 +4 +5 +~~END~~ + + +# Begin transaction -> rollback +begin transaction; +insert into TxnTable values(6); +~~ROW COUNT: 1~~ + +rollback; +select c1 from TxnTable; +~~START~~ +int +1 +2 +4 +5 +~~END~~ + + +# Begin transaction -> rollback work +begin transaction; +insert into TxnTable values(7); +~~ROW COUNT: 1~~ + +rollback work; +select c1 from TxnTable; +~~START~~ +int +1 +2 +4 +5 +~~END~~ + + +# Begin transaction name -> commit transaction name +begin transaction txn1; +insert into TxnTable values(8); +~~ROW COUNT: 1~~ + +commit transaction txn1; +select c1 from TxnTable; +~~START~~ +int +1 +2 +4 +5 +8 +~~END~~ + + +# Begin transaction name -> rollback transaction name +begin transaction txn1; +insert into TxnTable values(9); +~~ROW COUNT: 1~~ + +rollback transaction txn1; +select c1 from TxnTable; +~~START~~ +int +1 +2 +4 +5 +8 +~~END~~ + + +# Begin tran name -> commit tran name +begin tran txn1; +insert into TxnTable values(10); +~~ROW COUNT: 1~~ + +commit tran txn1; +select c1 from TxnTable; +~~START~~ +int +1 +2 +4 +5 +8 +10 +~~END~~ + + +# Begin tran name -> rollback tran name +begin tran txn1; +insert into TxnTable values(10); +~~ROW COUNT: 1~~ + +rollback tran txn1; +select c1 from TxnTable; +~~START~~ +int +1 +2 +4 +5 +8 +10 +~~END~~ + + +truncate table TxnTable; + +# save tran name -> rollback tran name +set transaction isolation level snapshot; +#show transaction_isolation; +#show default_transaction_isolation; +begin transaction txn1; +insert into TxnTable values(1); +~~ROW COUNT: 1~~ + +save transaction sp1; +select @@trancount; +~~START~~ +int +1 +~~END~~ + +insert into TxnTable values(2); +~~ROW COUNT: 1~~ + +save tran sp2; +insert into TxnTable values(3); +~~ROW COUNT: 1~~ + +save tran sp2; +select @@trancount; +~~START~~ +int +1 +~~END~~ + +insert into TxnTable values(4); +~~ROW COUNT: 1~~ + +select c1 from TxnTable; +~~START~~ +int +1 +2 +3 +4 +~~END~~ + +rollback tran sp2; +select @@trancount; +~~START~~ +int +1 +~~END~~ + +select c1 from TxnTable; +~~START~~ +int +1 +2 +3 +~~END~~ + +rollback tran sp2; +select @@trancount; +~~START~~ +int +1 +~~END~~ + +select c1 from TxnTable; +~~START~~ +int +1 +2 +~~END~~ + +rollback tran sp1; +select @@trancount; +~~START~~ +int +1 +~~END~~ + +select c1 from TxnTable; +~~START~~ +int +1 +~~END~~ + +rollback tran txn1; +select @@trancount; +~~START~~ +int +0 +~~END~~ + +select c1 from TxnTable; +~~START~~ +int +~~END~~ + + +# begin transaction name -> save transaction name -> rollback to first savepoint +begin transaction txn1; +insert into TxnTable values(1); +~~ROW COUNT: 1~~ + +save transaction sp1; +insert into TxnTable values(2); +~~ROW COUNT: 1~~ + +save transaction sp2; +insert into TxnTable values(3); +~~ROW COUNT: 1~~ + +save transaction sp3; +insert into TxnTable values(4); +~~ROW COUNT: 1~~ + +rollback tran sp1; +#rollback tran sp1; -- this will give an error +rollback tran; +select c1 from TxnTable; +~~START~~ +int +~~END~~ + + +# begin transaction name -> save transaction name -> rollback tran name, Rollback whole transaction +set transaction isolation level serializable; +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]SERIALIZABLE isolation level is not supported (33557097) (SQLExecDirectW))~~ + +#show transaction_isolation; +#show default_transaction_isolation; +begin transaction txn1; +insert into TxnTable values(1); +~~ROW COUNT: 1~~ + +save transaction sp1; +begin transaction txn1; +insert into TxnTable values(2); +~~ROW COUNT: 1~~ + +save transaction sp1; +insert into TxnTable values(3); +~~ROW COUNT: 1~~ + +select @@trancount; +~~START~~ +int +2 +~~END~~ + +rollback tran txn1; +select @@trancount; +~~START~~ +int +0 +~~END~~ + +select c1 from TxnTable; +~~START~~ +int +~~END~~ + + +# begin transaction -> save transaction name -> rollback to savepoint, commit transaction +begin transaction txn1; +insert into TxnTable values(1); +~~ROW COUNT: 1~~ + +save transaction sp1; +insert into TxnTable values(2); +~~ROW COUNT: 1~~ + +select c1 from TxnTable; +~~START~~ +int +1 +2 +~~END~~ + +rollback tran sp1; +commit transaction; +select c1 from TxnTable; +~~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); +~~ROW COUNT: 1~~ + +save transaction sp1; +insert into TxnTable values(4); +~~ROW COUNT: 1~~ + +select c1 from TxnTable; +~~START~~ +int +1 +3 +4 +~~END~~ + +rollback tran sp1; +save transaction sp2; +insert into TxnTable values(5); +~~ROW COUNT: 1~~ + +commit transaction; +select c1 from TxnTable; +~~START~~ +int +1 +3 +5 +~~END~~ + + +# begin transaction -> save transaction name -> error -> rollback to savepoint +# commit transaction +begin transaction txn1; +insert into TxnTable values(6); +~~ROW COUNT: 1~~ + +save transaction sp1; +insert into TxnTable values(7); +~~ROW COUNT: 1~~ + +#select c1 frm TxnTable; -- error +rollback tran sp1; +commit transaction; +select c1 from TxnTable; +~~START~~ +int +1 +3 +5 +6 +~~END~~ + + +Drop table TxnTable; diff --git a/contrib/test/python/expected/pyodbc/TestUDD.out b/contrib/test/python/expected/pyodbc/TestUDD.out new file mode 100644 index 00000000000..de6e81ccf52 --- /dev/null +++ b/contrib/test/python/expected/pyodbc/TestUDD.out @@ -0,0 +1,128 @@ +CREATE TYPE udd_varchar from varchar(15); +CREATE TYPE udd_nvarchar from nvarchar(15); +CREATE TYPE udd_int from int; +CREATE TYPE udd_char from char(25); +CREATE TYPE udd_nchar from nchar(20) NOT NULL; +CREATE TYPE udd_datetime from datetime; +CREATE TYPE udd_numeric from numeric(4,1); + +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_unique_constraint', 'ignore'; +CREATE TABLE udd_dt (a udd_varchar UNIQUE, b udd_nvarchar, c udd_int PRIMARY KEY, d udd_char DEFAULT 'Whoops!', e udd_nchar, f udd_datetime, g udd_numeric CHECK (g >= 103.5)) + +INSERT INTO udd_dt VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); +~~ROW COUNT: 1~~ + + +#passing a non unique value in column a +#throws error: duplicate key value violates unique constraint +INSERT INTO udd_dt VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); +~~ERROR (Code: 2627)~~ +~~ERROR (Message: [23000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]duplicate key value violates unique constraint "udd_dt_a_key" (2627) (SQLExecDirectW))~~ + + +#passing a non unique value in column c +#throws error: duplicate key value violates unique constraint +INSERT INTO udd_dt VALUES ('Banana', N'green', 1, 'Bangalore', N'Crying😭', '2007-01-14 23:34:23.749', 908.7); +~~ERROR (Code: 2627)~~ +~~ERROR (Message: [23000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]duplicate key value violates unique constraint "udd_dt_pkey" (2627) (SQLExecDirectW))~~ + + +#passing a NULL value in column c +#throws error: null value in column "c" violates not-null constraint +INSERT INTO udd_dt VALUES ('Guava', N'yellow', NULL, 'Mumbai', N'Smirk😏', '1907-05-09 11:14:13.749', 245.6); +~~ERROR (Code: 515)~~ +~~ERROR (Message: [23000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]null value in column "c" of relation "udd_dt" violates not-null constraint (515) (SQLExecDirectW))~~ + + +#passing no value for column d +INSERT INTO udd_dt(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); +~~ROW COUNT: 1~~ + + +#passing a NULL value in column e +#throws error: domain udd_nchar does not allow null values +INSERT INTO udd_dt VALUES ('Kiwi', N'purple', 4, 'Kolkata', NULL, '1907-05-09 11:14:13.749', 874.0); +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]domain udd_nchar does not allow null values (33557097) (SQLExecDirectW))~~ + + +#passing a value less than 103.5 in column g +#throws error: new row for relation "udd_dt" violates check constraint "udd_dt_g_check" +INSERT INTO udd_dt VALUES ('Grape', N'white', 5, 'Pune', N'Angry😠', '2000-02-28 23:59:59.989', 100.1); +~~ERROR (Code: 547)~~ +~~ERROR (Message: [23000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]new row for relation "udd_dt" violates check constraint "udd_dt_g_check" (547) (SQLExecDirectW))~~ + + +SELECT * FROM udd_dt; +~~START~~ +str#!#str#!#int#!#str#!#str#!#datetime#!#Decimal +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123000#!#123.1 +Orange#!##!#3#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.990000#!#342.5 +~~END~~ + + +DROP TABLE udd_dt; + +CREATE TABLE udd_dt (a udd_varchar UNIQUE, b udd_nvarchar, c udd_int PRIMARY KEY, d udd_char DEFAULT 'Whoops!', e udd_nchar, f udd_datetime, g udd_numeric CHECK (g >= 103.5)) + +prepst#!#INSERT INTO udd_dt VALUES (?, ?, ?, ?, ?, ?, ?)#!#varchar|-|a|-|Apple#!#nvarchar|-|b|-|red#!#int|-|c|-|1#!#char|-|d|-|Delhi#!#nchar|-|e|-|Sad😞#!#datetime|-|f|-|2000-12-13 12:58:23.123#!#numeric|-|g|-|123.1|-|4|-|1 +~~ROW COUNT: 1~~ + + +#passing a non unique value in column a +#throws error: duplicate key value violates unique constraint +prepst#!#exec#!#varchar|-|a|-|Apple#!#nvarchar|-|b|-|blue#!#int|-|c|-|2#!#char|-|d|-|Chennai#!#nchar|-|e|-|Neutral😐#!#datetime|-|f|-|2006-11-11 22:47:23.128#!#numeric|-|g|-|512.4|-|4|-|1 +~~ERROR (Code: 2627)~~ +~~ERROR (Message: [23000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]duplicate key value violates unique constraint "udd_dt_a_key" (2627) (SQLExecDirectW))~~ + + +#passing a non unique value in column c +#throws error: duplicate key value violates unique constraint +prepst#!#exec#!#varchar|-|a|-|Banana#!#nvarchar|-|b|-|green#!#int|-|c|-|1#!#char|-|d|-|Bangalore#!#nchar|-|e|-|Crying😭#!#datetime|-|f|-|2007-01-14 23:34:23.749#!#numeric|-|g|-|908.7|-|4|-|1 +~~ERROR (Code: 2627)~~ +~~ERROR (Message: [23000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]duplicate key value violates unique constraint "udd_dt_pkey" (2627) (SQLExecDirectW))~~ + + +#passing a NULL value in column c +#throws error: null value in column "c" violates not-null constraint +prepst#!#exec#!#varchar|-|a|-|Guava#!#nvarchar|-|b|-|yellow#!#int|-|c|-|#!#char|-|d|-|Mumbai#!#nchar|-|e|-|Smirk😏'#!#datetime|-|f|-|1907-05-09 11:14:13.749#!#numeric|-|g|-|245.6|-|4|-|1 +~~ERROR (Code: 515)~~ +~~ERROR (Message: [23000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]null value in column "c" of relation "udd_dt" violates not-null constraint (515) (SQLExecDirectW))~~ + + +#passing a NULL value in column e +#throws error: domain udd_nchar does not allow null values +prepst#!#exec#!#varchar|-|a|-|Kiwi#!#nvarchar|-|b|-|purple#!#int|-|c|-|4#!#char|-|d|-|Kolkata#!#nchar|-|e|-|#!#datetime|-|f|-|1907-05-09 11:14:13.749#!#numeric|-|g|-|874.0|-|4|-|1 +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]domain udd_nchar does not allow null values (33557097) (SQLExecDirectW))~~ + + +#passing a value less than 103.5 in column g +#throws error: new row for relation "udd_dt" violates check constraint "udd_dt_g_check" +prepst#!#exec#!#varchar|-|a|-|Grape#!#nvarchar|-|b|-|white#!#int|-|c|-|5#!#char|-|d|-|Pune#!#nchar|-|e|-|Angry😠#!#datetime|-|f|-|2000-02-28 23:59:59.989#!#numeric|-|g|-|100.1|-|4|-|1 +~~ERROR (Code: 547)~~ +~~ERROR (Message: [23000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]new row for relation "udd_dt" violates check constraint "udd_dt_g_check" (547) (SQLExecDirectW))~~ + + +#passing no value for column d +prepst#!#INSERT INTO udd_dt(a, b, c, e, f, g) VALUES (?, ?, ?, ?, ?, ?)#!#varchar|-|a1|-|Orange#!#nvarchar|-|b1|-|#!#int|-|c1|-|5#!#nchar|-|e1|-|Happy😀#!#datetime|-|f1|-|1900-02-28 23:59:59.989#!#numeric|-|g1|-|342.5|-|4|-|1 +~~ROW COUNT: 1~~ + + +SELECT * FROM udd_dt; +~~START~~ +str#!#str#!#int#!#str#!#str#!#datetime#!#Decimal +Apple#!#red#!#1#!#Delhi #!#Sad😞 #!#2000-12-13 12:58:23.123000#!#123.1 +Orange#!##!#5#!#Whoops! #!#Happy😀 #!#1900-02-28 23:59:59.990000#!#342.5 +~~END~~ + + +DROP TABLE udd_dt; + +DROP TYPE udd_varchar +DROP TYPE udd_nvarchar +DROP TYPE udd_int +DROP TYPE udd_char +DROP TYPE udd_nchar +DROP TYPE udd_datetime +DROP TYPE udd_numeric diff --git a/contrib/test/python/expected/pyodbc/TestUniqueIdentifier.out b/contrib/test/python/expected/pyodbc/TestUniqueIdentifier.out new file mode 100644 index 00000000000..0d0c9cfe812 --- /dev/null +++ b/contrib/test/python/expected/pyodbc/TestUniqueIdentifier.out @@ -0,0 +1,151 @@ +CREATE TABLE uniqueidentifier_dt (a uniqueidentifier); + +INSERT INTO uniqueidentifier_dt VALUES ('51f178a6-53c7-472c-9be1-1c08942342d7') +~~ROW COUNT: 1~~ + +INSERT INTO uniqueidentifier_dt VALUES ('dd8cb046-461d-411e-be40-d219252ce849') +~~ROW COUNT: 1~~ + +INSERT INTO uniqueidentifier_dt VALUES ('b84ebcc9-c927-4cfe-b08e-dc7f25b5087c') +~~ROW COUNT: 1~~ + +INSERT INTO uniqueidentifier_dt VALUES ('bab96bc8-60b9-40dd-b0de-c90a80f5739e') +~~ROW COUNT: 1~~ + +INSERT INTO uniqueidentifier_dt VALUES ('d424fdef-1404-4bac-8289-c725b540f93d') +~~ROW COUNT: 1~~ + +INSERT INTO uniqueidentifier_dt VALUES ('60aeaa5c-e272-4b17-bad0-c25710fd7a60') +~~ROW COUNT: 1~~ + +INSERT INTO uniqueidentifier_dt VALUES ('253fb146-7e45-45ef-9d92-bbe14a8ad1b2') +~~ROW COUNT: 1~~ + +INSERT INTO uniqueidentifier_dt VALUES ('dba2726c-2131-409f-aefa-5c8079571623') +~~ROW COUNT: 1~~ + +INSERT INTO uniqueidentifier_dt VALUES ('b3400fa7-3a60-40ec-b40e-fc85a3eb262d') +~~ROW COUNT: 1~~ + +INSERT INTO uniqueidentifier_dt VALUES ('851763b5-b068-42ae-88ec-764bfb0e5605') +~~ROW COUNT: 1~~ + +INSERT INTO uniqueidentifier_dt VALUES (NULL) +~~ROW COUNT: 1~~ + +SELECT * FROM uniqueidentifier_dt +~~START~~ +str +51F178A6-53C7-472C-9BE1-1C08942342D7 +DD8CB046-461D-411E-BE40-D219252CE849 +B84EBCC9-C927-4CFE-B08E-DC7F25B5087C +BAB96BC8-60B9-40DD-B0DE-C90A80F5739E +D424FDEF-1404-4BAC-8289-C725B540F93D +60AEAA5C-E272-4B17-BAD0-C25710FD7A60 +253FB146-7E45-45EF-9D92-BBE14A8AD1B2 +DBA2726C-2131-409F-AEFA-5C8079571623 +B3400FA7-3A60-40EC-B40E-FC85A3EB262D +851763B5-B068-42AE-88EC-764BFB0E5605 + +~~END~~ + + +prepst#!#INSERT INTO uniqueidentifier_dt VALUES (?)#!#uniqueidentifier|-|a|-|51f178a6-53c7-472c-9be1-1c08942342d7 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#uniqueidentifier|-|a|-|767392df-87d0-450d-9b24-85a86c02811d +~~ROW COUNT: 1~~ + +prepst#!#exec#!#uniqueidentifier|-|a|-|9bcb5632-53c3-4695-b617-d9a7055813ce +~~ROW COUNT: 1~~ + +prepst#!#exec#!#uniqueidentifier|-|a|-|ac81a140-f686-4259-9b90-dd46f10b355f +~~ROW COUNT: 1~~ + +prepst#!#exec#!#uniqueidentifier|-|a|-|3d08372d-770c-48b9-9740-a667d036680e +~~ROW COUNT: 1~~ + +prepst#!#exec#!#uniqueidentifier|-|a|-|518d52c7-4d79-4143-ab33-b3765689fdf4 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#uniqueidentifier|-|a|-|bc3fa456-7391-4060-b5d8-430048075cf4 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#uniqueidentifier|-|a|-|3b75b2dd-01b7-4958-9de7-f92410693547 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#uniqueidentifier|-|a|-|ce8af10a-2709-43b0-9e4e-a02753929d17 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#uniqueidentifier|-|a|-|5b7c2e8d-6d90-411d-8e19-9a81067e6f6c +~~ROW COUNT: 1~~ + +prepst#!#exec#!#uniqueidentifier|-|a|-| +~~ROW COUNT: 1~~ + +SELECT * FROM uniqueidentifier_dt; +~~START~~ +str +51F178A6-53C7-472C-9BE1-1C08942342D7 +DD8CB046-461D-411E-BE40-D219252CE849 +B84EBCC9-C927-4CFE-B08E-DC7F25B5087C +BAB96BC8-60B9-40DD-B0DE-C90A80F5739E +D424FDEF-1404-4BAC-8289-C725B540F93D +60AEAA5C-E272-4B17-BAD0-C25710FD7A60 +253FB146-7E45-45EF-9D92-BBE14A8AD1B2 +DBA2726C-2131-409F-AEFA-5C8079571623 +B3400FA7-3A60-40EC-B40E-FC85A3EB262D +851763B5-B068-42AE-88EC-764BFB0E5605 + +51F178A6-53C7-472C-9BE1-1C08942342D7 +767392DF-87D0-450D-9B24-85A86C02811D +9BCB5632-53C3-4695-B617-D9A7055813CE +AC81A140-F686-4259-9B90-DD46F10B355F +3D08372D-770C-48B9-9740-A667D036680E +518D52C7-4D79-4143-AB33-B3765689FDF4 +BC3FA456-7391-4060-B5D8-430048075CF4 +3B75B2DD-01B7-4958-9DE7-F92410693547 +CE8AF10A-2709-43B0-9E4E-A02753929D17 +5B7C2E8D-6D90-411D-8E19-9A81067E6F6C + +~~END~~ + + +# to demonstrate the truncation of data when the value is too long +INSERT INTO uniqueidentifier_dt VALUES ('51f178a6-53c7-472c-9be1-1c08942342d7thisIsTooLong') +~~ROW COUNT: 1~~ + +prepst#!#exec#!#uniqueidentifier|-|a|-|767392df-87d0-450d-9b24-85a86c02811dthisIsTooLong +~~ERROR (Code: 0)~~ +~~ERROR (Message: [07002] [Microsoft][ODBC Driver 17 for SQL Server]COUNT field incorrect or syntax error (0) (SQLExecDirectW))~~ + +SELECT * FROM uniqueidentifier_dt; +~~START~~ +str +51F178A6-53C7-472C-9BE1-1C08942342D7 +DD8CB046-461D-411E-BE40-D219252CE849 +B84EBCC9-C927-4CFE-B08E-DC7F25B5087C +BAB96BC8-60B9-40DD-B0DE-C90A80F5739E +D424FDEF-1404-4BAC-8289-C725B540F93D +60AEAA5C-E272-4B17-BAD0-C25710FD7A60 +253FB146-7E45-45EF-9D92-BBE14A8AD1B2 +DBA2726C-2131-409F-AEFA-5C8079571623 +B3400FA7-3A60-40EC-B40E-FC85A3EB262D +851763B5-B068-42AE-88EC-764BFB0E5605 + +51F178A6-53C7-472C-9BE1-1C08942342D7 +767392DF-87D0-450D-9B24-85A86C02811D +9BCB5632-53C3-4695-B617-D9A7055813CE +AC81A140-F686-4259-9B90-DD46F10B355F +3D08372D-770C-48B9-9740-A667D036680E +518D52C7-4D79-4143-AB33-B3765689FDF4 +BC3FA456-7391-4060-B5D8-430048075CF4 +3B75B2DD-01B7-4958-9DE7-F92410693547 +CE8AF10A-2709-43B0-9E4E-A02753929D17 +5B7C2E8D-6D90-411D-8E19-9A81067E6F6C + +51F178A6-53C7-472C-9BE1-1C08942342D7 +~~END~~ + + +DROP TABLE uniqueidentifier_dt; diff --git a/contrib/test/python/expected/pyodbc/TestVarChar.out b/contrib/test/python/expected/pyodbc/TestVarChar.out new file mode 100644 index 00000000000..b467a29150d --- /dev/null +++ b/contrib/test/python/expected/pyodbc/TestVarChar.out @@ -0,0 +1,158 @@ +CREATE TABLE VARCHAR_dt (a VARCHAR(20), b NVARCHAR(24)) +prepst#!# INSERT INTO VARCHAR_dt(a, b) values(?, ?) #!#VARCHAR|-|a|-|Dipesh#!#NVARCHAR|-|b|-|Dhameliya +~~ROW COUNT: 1~~ + +prepst#!#exec#!#VARCHAR|-|a|-| Dipesh #!#NVARCHAR|-|b|-| Dhameliya +~~ROW COUNT: 1~~ + +prepst#!#exec#!#VARCHAR|-|a|-| D#!#NVARCHAR|-|b|-| 🤣😃 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#VARCHAR|-|a|-| #!#NVARCHAR|-|b|-| +~~ROW COUNT: 1~~ + +prepst#!#exec#!#VARCHAR|-|a|-|#!#NVARCHAR|-|b|-| +~~ROW COUNT: 1~~ + +prepst#!#exec#!#VARCHAR|-|a|-|d#!#NVARCHAR|-|b|-|D +~~ROW COUNT: 1~~ + +prepst#!#exec#!#VARCHAR|-|a|-|abcdefghijklmnopqrst#!#NVARCHAR|-|b|-|abcdefghijklmnopqrstuvwx +~~ROW COUNT: 1~~ + +prepst#!#exec#!#VARCHAR|-|a|-|abcdefghijklmnopqrstu#!#NVARCHAR|-|b|-|abcdefghijklmnopqrstuvwxy +~~ERROR (Code: 20)~~ +~~ERROR (Message: [22001] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]value too long for type character varying(20) (8152) (SQLExecDirectW))~~ + +prepst#!#exec#!#VARCHAR|-|a|-| #!#NVARCHAR|-|b|-|😊😋😎😍😅😆 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#VARCHAR|-|a|-|#!#NVARCHAR|-|b|-| +~~ROW COUNT: 1~~ + +SELECT * FROM VARCHAR_dt; +~~START~~ +str#!#str +Dipesh#!#Dhameliya + Dipesh #!# Dhameliya + D#!# 🤣😃 + #!# +#!# +d#!#D +abcdefghijklmnopqrst#!#abcdefghijklmnopqrstuvwx + #!#😊😋😎😍😅😆 +#!# +~~END~~ + +INSERT INTO VARCHAR_dt(a,b) values('Dipesh','Dhameliya') +~~ROW COUNT: 1~~ + +INSERT INTO VARCHAR_dt(a,b) values(' Dipesh',' Dhameliya') +~~ROW COUNT: 1~~ + +INSERT INTO VARCHAR_dt(a,b) values(' D',N' 🤣😃') +~~ROW COUNT: 1~~ + +INSERT INTO VARCHAR_dt(a,b) values(' ',' ') +~~ROW COUNT: 1~~ + +INSERT INTO VARCHAR_dt(a,b) values(' ',N'😊😋😎😍😅😆') +~~ROW COUNT: 1~~ + +INSERT INTO VARCHAR_dt(a,b) values('','') +~~ROW COUNT: 1~~ + +INSERT INTO VARCHAR_dt(a,b) values('d','D') +~~ROW COUNT: 1~~ + +INSERT INTO VARCHAR_dt(a,b) values('abcdefghijklmnopqrst','abcdefghijklmnopqrstuvwx') +~~ROW COUNT: 1~~ + +#INSERT INTO VARCHAR_dt(a,b) values('abcdefghijklmnopqrstu','abcdefghijklmnopqrstuvwxy') -- for this case, BABEL and SQL both will throw an error +INSERT INTO VARCHAR_dt(a,b) values(NULL,NULL) +~~ROW COUNT: 1~~ + +SELECT * FROM VARCHAR_dt; +~~START~~ +str#!#str +Dipesh#!#Dhameliya + Dipesh #!# Dhameliya + D#!# 🤣😃 + #!# +#!# +d#!#D +abcdefghijklmnopqrst#!#abcdefghijklmnopqrstuvwx + #!#😊😋😎😍😅😆 +#!# +Dipesh#!#Dhameliya + Dipesh#!# Dhameliya + D#!# 🤣😃 + #!# + #!#😊😋😎😍😅😆 +#!# +d#!#D +abcdefghijklmnopqrst#!#abcdefghijklmnopqrstuvwx +#!# +~~END~~ + +DROP TABLE VARCHAR_dt; + +CREATE TABLE VARCHAR_dt (a varchar(max), b nvarchar(max)); +INSERT INTO VARCHAR_dt values ('hello', N'hello😃'); +~~ROW COUNT: 1~~ + + +#checking with string of length > 65535 +INSERT INTO VARCHAR_dt values ('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', N'5E3yMLSKs9f2gi7D5YnzWssg6j9fomQ06O7YRDmKrX7kUaxFjWPxx8aCS3F2rRGrtOX4AYNVGag0LuBXt5j8nEnxPVijkhpFY5OuPRSexMgZC83b8eVx1v0637CSetIMBFab7xz3bBKx41ELPBGSstz7kba5DajWRItW7Isk9QM7X0H4MNAIa49eR25U7qLUY7gm0j8sh5iKIvxW58bTVzMGM7Nz912oOQhgM5yMVEFbdnDKVqPNlnnBZJJVmzZ6u7RkHsoOwUDNprObG8ggQHsn0KLSg2YQZ8sDApFFvDJtDsNsisAYQWk07apBelFSRSUUsH1Dcj2jda06x6RWgaQO4137Ot9ysMn8zwnRjKY4JCB5l6Xq4olVZgzkoIat31B8d90HZJNr0ff0UMMRjF0bMvl32bsnGNwMG9bCKn3FhHCD6daOsZyjDUtk40Mui9DTsJeLmRoLkLLOnwL1L8EBeeR9G0TYPKawja0o8FMZCSmk5gJVbVTFzhfl72JDJikey4wJbrZUpMQZSkiw4O4QLVbR01AsdtxQmJVnl9BbMcj4KbhwPj00uALRY817aQTIfG3GyYWLA1uEcOUHnAeqAv3vX3YS2BjXFgfWOHFhRjUHaAA9Lt8kC1l7Zo9NZILe4MNPyJ3qdpUxWvz1WqZ0JxxTLqpWoxQyyWWhPXSsZ4JNRxQ7SDbSThk9dheuri5APDtUdnTAUxuvixhAb8Hjy48CuFL504UWU40UWHLtCYqZlJADx3p7IPcoX4O9cDI9jdtO1dOQsHe3UB9JvyqTkAoiohH2K7KdpRdefJfSr5vt14QVdThnllrZWp7OQviutTouO9gXZWv1BmNVgprxbjJyBVcyKQYilIk1ejHqwWd41zq0fOkqkd6AwRMSb6htusEqzeGWBfhoJQRJ0UY2xa6GDmOgl8sOBhSFkeLY1cYfvFadVaOVoRNQtT1ekxpFQmXLYqcjKcKdOQB5FfRzzXJPBA8aFmiJh7PeZOhUFOGQH60tFBXYwLW2H6kyVh7ZZiLUdgAdN8uhU1OaH9mgPPEBSEhXCqRhj7TUJiZ90dJohv1FqWPTC9rc2yxPYrEsvmOAfA4f0wVVc1uny7jQ7K0At15uqkf0LjdX5TLDujz2MRPR8pZZh2G3eItksoixsyr4fgHTXH8RghRvDqRkTKzWWbjtl44c3PPYjRoKxZr48FgGXiMbsgMGuJqUCg7i4WS6zQlA3SDMUwAstISaZwsTO761RsvDAHHOfLY4z69xfajTTNEYprrkqh000Ce3CuJvL4890nGj9XtZBKWfqTMUe6D5FYUykJRFvKdLPbeWsGI4eQvZJuL22b6qJHhs6kkk7nItAnmiZtE1P5Q8020JupoxMdJHxFryvUKrxhaEduBS1qAIVhLgBgadwM6GfyJFuDNtVrynt4cMv1mu1p9qoM2u4fBo4bce1k5qATYbPKe0QPNfJm51ePbNTwZUOzRhJWBxHQz5Yc7u1YejKV3X0OON4gnVfamM5zVJWBgDVyUGm4Qlrux7KwjgkvK1gv9PiofjVX3BCFj8JrlFUYBms3OXQhhpbjUSftHrukQAeqXPbm9D68RR0DutD62WJuT7BOGaljWodv5LYfnSCwxZFNT65XQtuCzqgAL0n13wh0bl2yXNHe8JPMb8LxYn8Yua3KVs4pCEy7YrHwXmQjASOw9PVZwBtIGkfNYCW9ronmZS5v7blETt2XHbLDLSUqUSP7nhf32tMP8qnVM8zTy5XVz2zfyI9Jy58ctMWNlTW1uI9w9CCfCv8n22L7xZJq6WGfUebTIxsNi7PGiHGmCOLmuiYlLsEdBV4zFztmqtfRQwzNj8xLMx6uHpitRx2O3Pjctx5GaXdXJKtK2FNDxcxhnHoQruMBcM6dERui4dpYK0pLTXzSaash9DfaaOQDtyYxDuZoGwGpvVAwuEPHTn4b58Dg9Dh18DKhLOA0U6XDbgc14gT0V1kUlax1UMrtPdsesVUTM8TuHUVnUd5vBXO00mW9y6ILNDt6LafnZHVGLWt3QBKRMrPsyWJ3QiUy6PErrI3BRX8GC1UluMU1wpAKhcbYlG4ReTYhusIAjVATpWFMiQMI7MDg8MR24wGwUVmzlaJfl2E3puiWNRDAoLB5pAE7DJ7HISSfTZctDqXiJLt19BC5XVfDMkociSe28ypSQbYVsJNXRKQkCiYycptDKEUcKsI0q5YIThi7ED1ZZshRXe3gdkHixsRjsCroanaIfVh3BKdfIaVTCyECFrnlRc9Thg0svgajZ2UhDE5l90spJY3kRiP7vK5pJWDKo5CLEvRn232fnxqeGF6Ouh4X1sR4tBET9W5BUx3bT4NALnxzoZXHyNm41uQSwCxAWawLDE2nta8TxvbnFJFwccTV0T0SM6swBE2NigSWyZpALUnAh9wrFKl5s5npGv0IGOmeKyqgoMAf0b7OBaMqBATwB3675iFlMt3FkvetTbUuCLzHt9Vc3QJ5H7102kJVKy7vtPlU3kuNPItxUA9I85n3K62FDe0dGxleTWmztsw0jJPOKLluHOv9z4S916Ab0Qk6nR62KdOqtUlmj0L962n2Tg6yDo0bchTjjTSLnike0yDOLfcsFAuPafKpBludIs9rcloWaj9Yz2KeOefrOxbtEfC7rkkMXtyGJFZXO8KUg1m09xNUU2uVXQVyyGoRZMzxKEZHudfaeXxx9z9WvS20lwRwysuy0YnG0CMuQQuOydGtenSmdKhilD3m1VOIpkx8uPYswR2CC0Q4z9gA3RGiu2GPpU8nUAQw3QNzjepxXL1EDqiHk6505ya1obb9hzZ8RdAE1TkYSkOr96tU5AF44vURcYzbr14mhk9ccj8T17dNF8nlYMRvPXXU4uqfKXatQ2CTGM1s7drYhuEauUj4CE4c1zRscjQACspwvJG8BXugLrz8OFxlW7ghvWWs0GWC6r6N8E6gbQrnqp86YzI2tSYwZZHRbPmKmPCWNIU3KEg3BO6TvoXFAWuieTr7C9GmZ2aW5FMOmNBjR0qDM135InITOsnPfPQodmUWlyklAmesWy2AA5S9sqmEXoIQbnsDNHPNhWC6rRaqxYzYfsW9TVWMFLKkYA5Rn7DaJkk7gA7LtPDyTHD5DbtJ2VyCPC1aTLUdpD1jIrksUw7XNgVkdZAlu31BHQVH8lQgHGrJYgRwhmxQMYEbaqhAwICRADGcSqBoFR6L83ZgpbRI3NVYzNndH0WKZ01txEwcNlurSJSICMkU363i15J1bMT7LCpRhgNqfaJCHygIXnCmHlKg81hgmVEFfeYQA2nslRFqz9o1fB09gjQgFug68taSbZxYAWZNz0pCiGEEdW1nyHkcy5dMzf8rAOQrZme49KBgdyDvVnbO9Dcj0ncfipvnUYaNMMtFBWHePJ1QK28lYTXEaHhFrzboEbfkUIgdv3dnv8MLo93I1PENotOcERvM9DGxkia36prCxwrwCJCCVHjzVuFQgjeWvBQskSkPv42t8bofztrOg6vmiYL6zpxXGlztwKnJmc0Cyl6bb8C6CvCYQuITcrBT0prPckU6EBTI4CDPur1MmgcJXeuH15CNbByWmGRZnA11OaY38mUqyuDbelDMUjrslu0GLT1ECC0QuPo91jkvsSpaCLglC3D8IqqN5rJu2IDv3DZyfpT0Q4hoNCPnhvtJC9wbgxq4irSqd183o5dvWrHdQHDrvB8Knku2zLlceG6ygCOdKQ0mzNGzmPRuO790R0YjsCiEx5CDWI2QbeunE5t9XZFH0jlpsYxqYS8FEBvI2KjYsOYThJptgSRm4SiwQvx9Zb7w3IMkxIlaXay568rGiZ67l8JRsSkGDFrjFXVbMtbdMzEDLENr9nah60PXs6iuP2iLBM5nNVhxkRGXOhsSEOZtDbyTMffG7TcyiA8qtTTHspG2gLtncI3OsdrRLNy6VDGv2ARdbZkbs4F3Ta3hF8c9p5HbkbU59xiTJ5yFtpfzpjd4zKjZ6HtZvyRahNzpNAfcEE4mLTcdsjjB5VbrWwu0HOuLZBaAY8wGJwUYnFi18L8CxzyOmvekMbxWpuk9939m8qO55rqFmkPicjxJkhq6efpCWMBKVBHJHfCSYtXUsZNcmNJqgxhDfk2vTgEWiIAT9s8WwbMnC5gczGHtoemnXtNSCrACM4Ijd4qRIVGbDTH4GszZdQBUdzBSVELFZoi9kkl12dB6eUk7QMy5TTVXxu3BpGj4g2VmgATbEVm2SSpuYs5vouAibF0rF0aSWXtTEZaU14OEGYl8jtdOBWmfuV4JGDYdsG3YfJ44v2AqMQqmuKxFpwkXo0OABqi5wPyQbdiLqSNDuDdxcR7wNNa5drZCMAEOqodPTvILUVhOpdNHrp4hsZv3I0TOscqC49tZO2dvkVDJBdV3ZF0RiS4lrBm9Qxuv3jlO33W8OJobiKs3FzzPYBBKgtJFAAWddpJmGlgSemZEC18Fdj7RkH8sWWaY8szjigArZpAHLkXTyx4z4fcX9nkdZF6BXRLnjFV0Ok6EZtUu7tw8ezXWqT5eP6QtRAMBMOVcUNxyKH3ouUml7se57QpYoxfskteizphJTL1lPklI5biicfa9IOg9QYBF0FrYXgHt7j4LCybGx5Ac5kQSzSCnOZzZvESTsegMZ6xe1HIXfxHDYGMSqwFdrcS4djZimiz4CTu3BBQTLo5RxotYCx6eJGL4WDsYMkbvbdYDW2uG8OkLCADT0Q9ky5J04P7gyJjK0nMQodOlLsspQRr6TQEPog6ftyQxmf4gstEkhXEHKydeSbjTHyZRqnn56TLfeiePKuUYCQGhYt4qmWR6JPCHoKaZsDj6tIQRyUTovV0VW3P5WGqf4wMcSM9HvB28xR9DBW7sCgpDbZwawfyli2xMn9GMk4kFOqHMeSIt8KXvppTwsbBCGiJf7O15TVJOZVqtGp2qH7pnnQSNpEoKBumvQ65qNznvSHReNGlB18M5QU4312i3efeTul0NJKXHluCn9M70N9O0W6PtsthW9HD4ANLFcl9yZnsJjwuojcGoaNc9jjfj0TeQcYZvqWX4GE2RBPp5x1YEMU0koSOxDPVMSYFF74fOeY4JLSw6UccpNOEQSKZm5eg6pRlOLjrigZdZHgBeWHCfiTEJjj75AAB2Z9Sqx8yvYvfuycbDfaY66pZY59ihACOhEYwOd0MHgmqnNvYhCN7fojDWVtq2qyqDVU9xDeTQYZ3Djml07N1BeJrjmZm9Rh19C6pFuqDd7qbEOF8jiwJ3ipsPBoO0QwDTHZ3Yum2jIEk2hDR8iRahLyI3BXcDAYQ3hhjBhbpQccRSZCCxOaf3hgwRr20nx6cYKVvz7oYupKV3uToUx5bOm2NNwUZNhVkPMjGmDsPGLbdorUBlofiDow1Moa5a9KKaCo9Zce6G46s758geE8rCATwrFcb0oMg1g0slrORHpRLkYkTSCvpbl76CmCCtJugFcUlK8s6GN06lLhAxzh9Yox5NxwBpR48ctcBk2zdgXxydJeoHVMYT5QCTNyKygxtNfoU4mnjAQ6GDVmRLCEK4j7ToWGuGTrZmU4qbG3shvAvmNCffSX8qNHKq8yNIvVcj8g8njlq6RyMJyb2zB1XSp5thihvy2vMhYmcpKmsyb0XStGGa60Oa2uXfOKsDpSL2SAVC3AlSKj5xwiFlkYaYtA89250ugvfV0idCtGVq8YLaoSFSE1sd07ZIcLAFSDNLRGxLz3hRTLaiZrZ3IbroKgxrsCQNCK7WD6siLKp9CZJKgCH1UXBYwVH375N8IwpUctm2KO6yfCTbYBp1U60peUQmYKiSMMR3lt6tly81L2m5u5PfRMUDXgm0fCCXitxwmBdo0RSd0rDE3kDrsaUFaDOSqJojEhKIfre3GkPKS6Hm9Gmm2cWqByUUbfOcw6mtR40jCaH4WBe9nAiO7kpuP6U6YWP7LBpTeQ09YekwxRe99Upb7YaEjGcLEG4HtBtT8yN3HxJYaeqLAWh04JOE8sthbFi2YpeDfZ7baBOYyOghV5OASLsGi2l2L3gMVZeJKrBQOw7tsm9E6grhU1Pmc9uK3KApl0yOsoEXpZsUpucX0GKZvT7ibmyBzuh9CoGN4YI26KjLY3TeeePTfB7C9lLvi5cQ96Ksep4AOKE6mJBc5jGPm7W9VaoRUmGBhGa1d7kND0Z8Z0wFBGNzUxIMzSO3bNqFT9qlywwYc4f57Yo8NTXSNmeIuyrRvjGI1utGZtVs24srEMc6eCIDmW2bi3a94stKouhpu5IZvXUBDe1Oqqcq9MyJt7CyVbcrlVyGjElzoj1SDldPI37rooXXzZFpzuInM3oDYvdzisBGDK7htrT5cMMuRtkeSYcKW8RJ0vHgJzPDZXSqJvMW1DVoUawY0AzRgkuFAKQuqDhOjtBYltTlwLw1zqvX7It9pWHdmn7km0J55fXgw4OK5pZGCCFdNmdgtRUjLuRd2PBHkd9AOHF3MWFCToUJDAEWyClu6HPp8K8K693RynIlDc1HtqwAxqWmbkaGmyJOj4mAx1QA9ZDpMuX8672SOYxxNUUehbcLMk6G6dvn2eXxc9hWmUAXCyA4RmD21iDb9vpXHQRWFlkxiPMH9uwi3xNf4xhAe10qB3eP03NggzGmOEMZbK07g2dkWfUdXa3LVL2WWAds3vLaiMT1AgT0PXbKW0uM1F9dzOlnXq8ULafhOLyMoEP4oXimbNlF7se4e1ICNaftuzF486tq3FPGppQCZkhKhRwUzGxWnAZseWZSdYhH1w4Umjq4tT7ASgHSmBUNrZp1sn4vx5Cm4oVqIqkLeDphr1olertf9ReK1TJJpWXymBrqiQikqj3Ly7VbUhTbX6mUAU3vT2HGJEazQ1qDUgUVB0zjKG6DMDCaWB3G3rqAW9DY2hVxDNQOqXBXBnhCOIPWTz1nqS12AlYbABTNbH2ClYC8GExTxGTkry0ptpekpID2E5KhftkhXMkvRjVuuX8nftEjbETUGn0EZkRXWxe0ypkuh1wlrj7yp08ldxM8xHMYr4l2CASvBtkpxtMUAuG6nYoZieH7ZzjMwGIv4UdSimONCg42Em2Fp81FrMv5RA1wZSkN7areTRf9V2aeRyiPEJAvZb6Hiho0q5Vec2T2nh2XaMi4ZUtXXY7BBxjK8tu3cNmMHdwCunroHq1KtTv6BAqhTEZ6gTaIFSKiDbfaqYDYZ0VqFjVDKWzsJzRnV2ybbUBUHdaxrq1gNlV7Zk8KLWMmLCQwVtLgWitpD1M73n2d2HgytbpPF94tE1S21rOWGCtYAi5jTNXJb0ixm4jjoJl8V6mkWsi4OhLnt7dqYVL2YhTdRus5ljZ2vvzmxPs8rI8nS9oRCUKHdlK2JIzdRHwtsXjieioSRfL3gxgdnQDTvBti86B5e8RxuIFrNwByMrkl4m7x9ezW8yUAVn1w7aMyRNLW5xNVG9wR8bOEIoVZ6Rjy36EPtW2TWq4HCy0SNTS4nqjPHcs9RlE10lvqWaIfniQQ281nuFTDoyIPcrooSEjjWoKo5DZgsXIhzo1IvPUg4xyW1BqAEtN28TES50yoCnJoupExF5nKXuYlZ1bO4EAd9cik547unM9rKC3fgLZDbMgG8Puvign9J4hmF4zrZ63tc6y9obyz5gJDb5ilTbXsy8qJljaADvEh8SpxQEuejSxtm1HJoodEuO5ypGKUvxblJ91wyXmQfXHHdlu6fdZMfLrlyQOgRuvJeQagcMhDjUbzvylehuzO7KWhi46E84eezuOHAgrxBWgJ3Yo31iTHElezDsrlMtLP3PHUYtbaNgPwmQBWjlllL7lxs56Vjh7PrV1jRI0APn2uja8s0JJ8yGdNkXD2tbBu9FkhI9nEzQtenqCvFVjLU036W96w5jkAaJg0LvXYPorud3zkaauaVWJtn1iexwvoH4QuIu17TkLOjZKpAEyKtGzsbIfblArZpf0ipQ9KT9zNbfgLKxluARfWSm7xIuGHkiypwBwbf8u3s5HpHgRWKLg3RAK1IudnIoFTm7vE1GWpBQQXX3GcbA4kz2CNsC391zRSdepY3W6RqQTvAMry7KI8hNd7yWA7Yqd5NIX8ocqrqfkgYsG7hlJRY2jSMU1TngYStTLogZb7Arj1Arn4gUc8cgpE4iPlk8S031iLd74vXKgecAeve32zqUbMwY9Hg7FtksruC71CZYW0qF5YLP52RbXqDakmqyEFO9DRunWLMTZfd5Y1Oa0aJCAIJy7xXyPxTWdiJ0KXI92kG4ODIyzC7Fs8zQJPkJ4IZMVGkXXfW4qwMDPJB2KqO14Uz2uO563GWhUwO37FajqpyD5JmypzGIeDtk1MKzSRv0FOELi9a1NjsfXVOh9iABqIqizmOrb6n3pJLIQEdqbp1IMoie8pHYm2cLdvi20FgTpQvj1erPhqJNuFqFEN3WRXn3OH5ZGDsLaHqVhFeyAoH7cMIjDQzBJ87p6a0ArI1RqsfDZWG2nuW1wPwxRo2OB4veCPRA7crhgwY2rt89proY2s7Vd98tHEfM3b1txIR5TEVPL87EuTcg3aTlTJyVpllgOErMuiJriG2kwJW1t4rYTCKJMoRfwGSdyHXMiDKNSEywNAPmnr0As8P93Hz26UmtZzkeSkKthLG9oX8hRvrNc6CHbjlLRepymoTn40d7eKhywaPO8cLR9zxX9MYH9V7sQ4KwJQ6zMC5BpixRIRfDDMpAnmb1UhptmKeET37msT3pDe9w21N5cD4menLEm7kl97wFJnSbNZQmT3O5R06ypOAUivmzJReqexc5YaXauJEqBAaWCqzUKR2432mS2ZZz1IXXuMws5C4wUKR8WOoCdnE9r1Im7Wb3rfgbZZERbHTOb7fJqXon8lEneXLPIxAOb5RFEZw9L4NwfcumUjGYYRcvNegMNQLpFdJsUUyCX7bZNNxrFPhULnNBkocrEtMclzBWnJ4reHYsv8HIsB3AbYDWfSLxq7DyuTlk00uumsoX8k8cSKuvs4qOMzJYHmRZGputDzyqWj0SOR0psVObWFJhuYJcNeuWCTvOBt57kjbS7MBpyMuFEPKtp5UCMyAPRvlXKR5L6QxztoH6xx6lf8heKC7MK3MkD2OczXm8XL7lBBVJC3AgJ2fs6AHaafgVDsiGRb119sIXf3rjgZLBzVInquAhwqsEFQtAEDO0XOdT9kNycZWstTyCvCZ6cSvrJTK1uqoS3dqgHDyYjaAkaCofAYvtKIfUkpnAgxdHxMHhTGcFdILRiu2JRXGQujsddcIpw8nZEMavw1rB50yFENg2nqtyD9GYKZ4IkdaW8b6kxuirIlS9jksg1WLTPim3BrcMaxIpoqT1uzD8klHUCzXSh7OjUpj4GdLam2SWQTL6sOuicUqpeYmKG9hVSRcOl3YZAy5uPYB62MAmOhkhRsWnqDj7XQVPuJBxMePG28wqMffUzV2rUy9WRSokxC0QY2V1fHcWN6D85xFnP8cyvs0J6npg1L33fPtgD8Mmb19Ku5PtcrExmAAyyYtufC5vCyJVggneDLWjbFptDX51FOnhbhka3wJY0F9KhfeUC4rzGhZVqMLxgPB6CS7FzFwasec7PdtivSsCTpcbqIAISw6h0mjWHZmFtPIxgoJch3YVWdgpngWyVnkUaqKikzx0y2hZtgiOGHqokDZReFiGJGKZLnN0SkZcJKZC6O2u9twIJ8rdGhfsOQjsw8nPPIm7XGOVe26Pe537TazRNjovUQVAud78NppdFKm9T8CodeoscRbH26b1SiS01oDEQnEjdeTJYZUZSRM1t5lbQY7ZCKY2KpsEZTLcZr31CY6VCOr9Q9if4zvwsyf7K9BywidKAEq7dt0HyMgV484zTsurELSxBH0xymY8Y4CK9SfP7b86siTDLEijOABO9qiJa7JFgBZwbnW8ybl3IAEk5DxBoNfRf8Yf3We3PTjGiF5AWkOVaK7Cdc1QB62mxL0Tj7JzlpgEMn8dweO3NegQxBo1BwusM9f4rcvJB0iFun3JsnzQHvg1pLqTijx3vyWeraciOmQZfAqSXEihc2Nv5xRx6nDZiwLlwqUMnGYnvUwkMco5UPjJ81Gyzfp8imTI7yFClEqkRvXn4hsrRMO8EGxWkKCCCyFdas9IPu1ddQL3myW3oIlmwa0a50kdd1A2ORrqAeOjoJ7wYS2Orrm5xZkYoxLRCM6ySOcy2gi3Yv1UH8Ee5ZfXVgqxvWxfqh2CGBW4IYvUpWuFgPJchrdUJebpuu29q7xAEopSL4gRCOujyozS6UMWVHmbCvNq0VTaS4fufo6P9MP3IAMFf4PNWyRg7vP6Hd5NghcstkBFECHB4v7MMDiRuI6XdP8l4fVLbXXgLtYSDZEG1vp4mpXo51yCstXw1Mgit1eBI7o4M2Za289Y9zuf6pihQXTLNev90bZLuRyQVFFo24MVFsJHz9rT8o3LmuJayHbXvuwsBSycA9c2tGpYUU275FnhqRZkqHEdmImDyHwgNgl09JrxQFtzhyrRC3DDUvVglJDpLXX0Gie6qcl0yofpIJDHnb2UWHygVYan3TJoBbEnxiaJAHagmS6bFR2PqGNeQ8Ssz1ZchV2MevP6yDjZMo05SAGTMeexevU1ZXdiLRDrjXl8GJxh0kN3c7llIHBpeQq1US66bQTrjC0LPxC8RuWHIGvaWAxEiMzr4WeqO55IurKecfgzJoLZJbzrbz3wl16kBpjaXG4JQ1xjNYfYS7Mv7JK11QBvHxp5NU4glJQmREyo2PBUXCOMi5JtilSnZlJNpEjd1HGwfyLQgD611Sh9sLUwFaHog6FhRNEkujMBiwW9huKIwadCes1VsJBqOgb8oxFVhPVHjc6OckDgf5tKHhUUcIAjSkY5K72xAnAtAITNSwBM0P9zx84qsTu4dKJBvhwiUOrARF3aLhgjODPjwdzrMeEkY6kGS4AGWXCn0Qrrqn42dlbH9pJqUTaN6sKvF9mcCULPJZV3EPxyQ1wFeb5tlg2OTcYDPhMUjq4p5CRquekSWrkMG3rrHSmv4gnjNj8bF4dAOmuZRsBLzAjW4bNfYrUOjwfnMKMbnatuCGo7gLEMf7iJAIrSmFFuA0oanV1CZnGxpujSsMEwrABFNjKSV12NWGAcWPdoRj8iVeGrZOCHNAyWyPRVVGxSy7cQYdcXwooo8NvRSVICgRoeUuj0IWA5qDK95rdREoH89FO0CzPXHf5JgIuOdnBwRF4MFiIJcJJWUe52HhM7b9LLJFhumQGZaQZU2jGfON9dRzKLUYi8jXFtAR8llRwImYuIAjPSmL4QDTV5daMDbo1RB4cJJOat2pepq8TePA74pi4QsQo8OLPWL5IIsyWtZM2jgskftmoDn4iUVxA7IcHmvmWpLCXsh4CbUDIuj3ylQt0GslrB9BWydCsfg6YL7gKz0x8lfem5ieBF6c21nQeSocclP8GI8yVWqjzxGcagp0mdtjgMCSvDiCsx2z7p7w4U1p5PjiF95LKn0zMvDlqknc8gEFJ7FVIM9gQBye8tthUP81wzO7DJGR4CrT2WI0aGaE2CK6Qyx3ZJ2PVNp814CATp4xn7jzCHs3rvyDVSBsmC9PgJq8CZNVwI1xiJlK95poWmJSLWJ09kv4zN8heGTTRNUqVmrH2Bk5lnCdzP75iG5nJatK75utZscJrhAgvGpDpXWFAO65Kki8wSU39GHPqO7ueFMblj2bATM4ztwHRgfLNI469HB9hodHm6OhT5hti34Cd3Zguw5vjEnGComiLRqrWmjFFrCluPz5KodcNi5z0ldjCyqzOkYegJQtKabdXNG7zTqnwOtauzPFvYHAT9JhMJgpXXSoQyvSZYwiPUQyV1xsrUGiVsTKN7L0oBCga8XyqAoJeSJlPaXIcJwMzGNd1GobWg5Eeuobhu26er8wwZdHh1h6s1H38KnV8tRvVym3R58Xirjqpef3idxOYl966ec6OSdIGn5jwSEoEZr5UzRdcRJBPvJr0vTAncLWKVlhDIcxghQEJ2EKfij4OP3D2PoyqnRW263at0fKGgHYPJirnCmXOyyMwj4LFuJgH2tteJjNgO1hHNdjYHdDQJKMpzZBBsVcY9GQ1OwoPEg7rl2VaRitTnxhhpMxZWNRIzHL3Da9R3XXg4azaweDdwX2c9ULvSTiDYD3CR9SJ5OEVz5WlS0bPWEDdhP9iq4HPMzr5crkTlRMTVO0xrVwcMZx28QLJpseFr3Lb9tDN2P1cAbB0PclKxq3nOR3t0FLnRSkzCDXUo7U8Lyg0U2oPclQzymBVOvfOO1nvU3f6LdwNdxFhFMPCKUPU1Mf1cINYmJigDtqF2YbiFZXgYe7XTDxm3sDpS3DHGRVfoBEBM5KXbiUtqD5QvfIoPA9ocUhDYPlUTUJKrBUtoA2vREhPFY8GprO137EcxeLo3gZHDTLwONJWUjIwEqaa54SZEoQBr0dWN5LZ88xbmtVojDfjFnfVBS0BGdVLnlCkyrGgLqDnPdpyVmmQK3FTaExtZj3gfLHDNauKWWUQGpKUzqYbwQqQcRPekI8spswMdblVSrfvyfvmHOVULdmSeTKzwSCdhNVzZAgNvCSjft5ctjfLps4xkpNMKzh3uE1RAjW5coTDznofHxGiNFvUHa7lyNa9diFPdKHgJdBfLFGzRkisL4jGJpE56VCpG8nImLTTmOjWxHiifoNRV7mHURveXfMwjydIurqol8rn1a2PX2aR4VNB6kbQc7Zepdsj1iZJ8KbgGUkurnar7gtaVlQLEHaDPGhMkAjGh9uY0zMlrLTE380ATAKdK39mLorzH5woSTBmoGFyUCLkT9qWKt62l7yiQo2sFriCP1dGvzCUnYIan3dHkQXuKCm0Hv4PZsmRm9ofmV5AayMpajuIPrjT9Ow1wCqk6a9VtpmIhcL8ub3GmrMHDRvpOJqYQJxpUE10IVIra2Yi3D60Co94Yuj4SPw8BPKoh8esmdxZaz06IUy55jBR5WXA7CdQK3JXYguvRW1TCo8CDtvTCNUzGr19OPpFzU0CSlmOgmb1j9z6bSPdbab5soflPK4YFFwZf7nALuEak7lLyaJ471Js13vepnjq26lCfp78hfmfhq2EuoIRhM8m4TnrIcXiAGinjzaQWRxkIGN1juF12iDdBbRwdV4xrogM4TcK9ZwoUyQe7bcIMgAVoe5TpU0PNWVr1ju6dSmmqWVX2qz3XIxDlRqxrkmkU5QZIq3DgrtLfsfXWgPoAr5HAP0HK7SxqHps4Wxgoj9ob8Dw5U1O6mcpr8IUxrpO7vdi1OyyRPFTlIjCZ3dAsxZoEnFOp4b4GhKcMDFDxOggXiR4psIGhKDEvlvuTa23DaxLhSX1iCsgwCIOvNqK99Pf0Wgns6bR3Nlx3Z2OMEyGIrKGyHfcY8MZVn5txMzAYcqjV10HdJnlwzRsktRIJS5RuazhR8Kerq9M2iSIhMTO14wnafg6HjG8JfpawCU8w4u5G0E990AREBGXMSkcjb3JCB3IFYkZ0Z8z5jQB9td0qhHGdKSG7W0QMFd0ILovm2VE9HLGQEhqQ09Fun3KE33w55wn2taQUxhgSoQWewXGFZRQ1qwsZWsqQnTbxihK7NW8vZxsIA7VuM1KZAp2hhnEGx4XYW2p4p2IbMiSq3J4yL4BfFOoAQN4lsz0e9JE1kH4B5M40D2ZpDwBf1V499gv0FUdOeCVaxnaCPpJgXH98Y7g3Y5ugww84u3O77O3ppypHdCrIA097vwEQDGGot1s3zWYCmDce7GmQP5QkR3nDbe0lNK7E1IUjhWcKlzi4r4Eq04ggbn2C51vcO1fgIMx26mC8C51SyK1NCgFaWxBzEHtaoa622zQEA8t9xwXQPDyFajCwT2eEQf7kIvd7241xt46ofOCve8S14kmOVqAz2NWUq0l7UvirgwhEeBiuK9Tb7I3s9v4PAApDos7opGK9lurweeu7JP8zQr1seqmiS06JTCLPQgdi9cl5pplRz4GwhvGOTQZwOjv3zNQ59sqKBB1tVTaizgnvKetQSjSyhg05n4VBsOt0qJYR9jMYwDWRMTilCQJTtIOWDakDayCsoprr3Pf1oBs1WfHVsGFAJhuQaCqQhRGB6kmlHHTLQQhEQah1gNBk45dNzjU91RfTECkqPjO4HX8jhmSKSnQNdTNHg7bncE17QAKEJOSmcPgAR122nDyeDz50cjRXWpKzIKZX1WZtu79slIZinSDDmRSYMDaePx4f0CIoMntBgxwvHEE9zCp7zaC3LwVkzOqRTWVSuDtGG9CgqrZJe5rEeltv6dKNR6v51OSYXUDwPN6ZNysmrOxrB4LGcGFbRb0RpE0XKCJRomOZuLEqdqxKPlARSSg0TeATqEiCAcqX0Ni0RgXlgBQkebPSYaMjOYsfdMxsXWnSadEjFsYydotfzACyFEKte59PnO2BAMRntAFuATZCP6Vwf0Iv6GdpW00rwJFglM6Gb8z8qSIxOxnc2ypb5btzsBpzhNgPiJVI9VKyPlLSjpruGPprf3hdQM4olxQJc69YsrlvxWq2GHR9uN9DwN008Ow0T4K29tCE0QH4QEoPceQu4atJnAwS19Tg8In9a9LRTJXkIoNk9PYGGpNRCms0R8RQspmgKELIU3s6aa83rmFgGwj6TaFrfXbdaeRwpoLpvagg2k3RzzZnOkmtlkwLlo43jovZp4r0VOQn69eC3RdJoNeGChni1Crey1x0FPpVpoS5PbgL8x2cJ1tdaqmZMSMaAIfMf76C5tvn6B9WilZL11uVm999mUMcLk0MpeuvmMu0NNdf5T2kkw9jH2LtFGlhEZRpLXvgvpZ55rEsl6QMAIgxpuWGvlihIJMG7IN4RW9cWYnzlbCqZbRF6AQfyvveqzh8vfYK12dgK7Eg3lsSYCfTLeWdAwuvJe9u21WU0YcwKUxtaiVBLBHSA5NCfNYtjymvW51Dr8MRqBvvTWyLm1UeLKcOMVlqVCDLzfujgeisebYu3apfFgyGllxwHmB1yo6LtvcIQbHAUusxuzlKA4hWCujIeQIvfs9n8VovmUjWKAEabh7zB07rJsdh7sL6NCVIREjszPn5AkyvlljtRmtNikzJUgfjTkrAwrLkcp0eKD81ZQkD6vIayI07eGz0UIhENw0tfpmQXdzCcytCyw1oocrD5k3MqAAbu9MN3RGSdmFNTppeflGJ6VVqTG8Bg2Lq7fVwPOjHkPcF9EoBfU1xJWSV0c1arE4ZmtLw4CKU6AoocmHq1zycYEKBcykdLb0GwDOtTFvtaLkWDT9XlDk64P8j2k1gXJUEhBXDgZs7qjRjrpio379hURaeyK05m5VO3tcaca1kotstKZLILl5VDQCpUO9yF4OdpIRMyGhlKnt0Vqmhh55A6eyZEgTVlcjOYJ5m9YmUillyMaMMU7FThzFtSRIEzQwdAYT6e72ubmjpteeSQYdG5I8mnZ3jiYCo2byVhB8ewEV9Jr1WS1TSDh6zN6EaI0smaTq7R8FzjidRbzqtJcODrRvk4bbUC0LKELAVhjIqXghOZoNU40o0AzqcEzHf1mOd1FtZADecNoRMRhL61tD7StOrvqGcKSrRlPDsfFV6PNuaPVMUhFOA4DBkNcyvov3DHJH9oRjD4OBkQ7pnCZzfEGM7b9pVh2GqcUCI47XcpZO7T1jmv5hn07u13uE6Kx3bX91vtEOa0AH96l8G5ygNDW3oduPnYWlKNEK0LVtSFg0dnMDc4U4lZK0C73aB45e5ed110MnCqVNH2PDJR9P7be4c5BEO1yMztYFU6I2rP2ZxqUvTZstYrECjqhZWRpxMGEaxwR35FF2BY33bUy9dBgc4CnxZhPFQJus9gipRaU8T8d6JgHQyo3103Fj3qzrxUmfhVeUjuaqjwZ3CWDMfgwuqzrvYbnMT9RdFsDP6PUvdlwsUZfGKkDZ5YTTuBbJrhLeiDN0Ug6i9VGUGL5zwWLttTV0BHTGzmecHvN4ZPW3jD7eJLP4lEx6koNQNZXmnQDCKeies9Tf1OmOG9ulicLBJouDr0LGu7q9KoGcpJTxwoeHcoBGZ97PWmHzmRsx8vaWPWeceCsLM2VS6g2bTrmJinV9mU0jkXbcvhusKFZhSp20r49FKtLoD5Lx0Z0oYTvj4fhGO8zR4UkXkd5ZkA44ohOFOpNi1zZbwoCMgOMpFKL5uV1md9E6fRum2gbklJweya1bCjIqXaX028UYNakMHIAS3HFqFVQ4uDkTXnyEby7D11zegU8xdBYhd958KevZhvKunmKEYRcebnzn0rCyg4w8BzXR1qCzSLIZiPoMMJIptaELfdvPvM7FltBy34nb9RUXfoRyVGZfFbmCXuUx1mRE9KJjFPj97KBacYAn34ih4tCQYe3nxgB6XktxSs0xe489kyfHeSE0aUbDO2my4Ibj1tVdtQYGEpDlkJMsSsP2mToiMUwoP2T93lTgP3MovNO5zKwIzsSsbnGnOviyLQE7ERJVjQl5IwahlZ7bM4kXgmA17wWfB3rdE904AH56Z6K0RDa4uGzZpGIWHCzFBN6ZMTkKYqKFNWGTVqs6b5Cl0nGwnbCzW8ZmkyqDaCJkbBBea8o1WBfMg3xIXydWsC5pUZL0OxisrlMOPwvjMdox8f44mDlGaSEXTcXEZ6h3Gg1CkQmExyt8u7Ny70wQaWfplU0xH4VdVpAZ7D88gTkpAr2EADwD3Ooc787YvUJVKKiVpimq33HVNt3Mnf5Lmid9q2X0u3THbuw2MeRyCI3mmFRLyanz6GJrs0AS5NlZK82nQMTOJNdyC2XYPXo4ZwB86arUtnuqZQIrAkJHCtrJXYHxculjX4rYn8jhdLYyC79R4vqzrR5lufPCj1RKxr5rfa4e6L3lZhoq95btuYRiBLWfvfWVOjANoz2bZLn57e8KdSu593dC9eRcJMyyMM6Z2U497vombSdCBcb30m3yMlAKvtbCTZ4SXDh77K8bfj1zFTy4FocBHG5QgihrQQsTeiDzKS1Nk2fZIkBZM6YsTr0nSoi5OkSS0AzYlNnYGZsT5Rzf5Yy4b2C3ekrfGijVv9TblEO4WXnElKex6MZZu9QcO2p6iKFIs6b8MwuLcXG0tdLsO95dTow4FBYBZk5QUeNAjpHZtQLkWwAjr1n4VEQIjy2xPLqsZFRwaSMNlJnHFujA4XYSzBzzOq4mHtmTau1M7FHew82ZtX7PNmSM2r1iWA92bGpz5GnJt8ca0CBpX3GXz2XJfA6NJmKyOM1kma92WJMKLEpAEKHL8iGNJ8kY7H7mTXfqb7ZCEvhNVlKel8tPsw2DeoZrklSS3J4F1csM8Y7koaLEIhJoVCRVH2ZKs6qIPYqKmu6uPykxejg10EEBI4nCkgSslu4Pofl2jpEMEp8klnKEVjbnwQzLM8uWptU4ZmLvyC3BY5hbBDwjgWKcD5ulDudAgk5kJZrbMqLEij0zRCS7faTIZ3ENCZvorrZBT76mtKHIrSxQ5r0RbIstdfULJxK4CFY0yciQy2bR1yCGwYJPhc9gu4jVcMFmsBmWzj1sHLTaTsmI4g4KiTgVMzXAeQgTrQD5A6S8M35g9vF2yYnNv7Zcw3J5fldrSrbOaZsaDqfDmtV0Et3sVSHmJYBJ9GrUnqReTM1PCERK0lRLREYcPuAhLVFr8BBJd4cRcwvVKE6CwWGjmzCEUuuBrH9toyBERoXWJrmTVet08SWeTfjoXqk85X3k8xXk1uiWDYNTOBOQZrtjIC8LzycdRgJfQQbd1H5HhtBlI3HPPJgSf26exawf2k466pebvzhC6SAlDMySdG0D0zso1ug0SYpvZUPshbsKM2qpbFrRGVnYXtHHkjilCRm5sCM25bDIndKieSUwncPeQ7HZgZS1YYBKwL7iTth44ddTioqczH36LhLZgG7Du2oGF1fES6meCS1QzHylrspzIcjBgW3QoPjN2jjRvGbK7YKBXmWbGobL4RU5xrSjEekbQnzV6K6B3pUuUQiORtcZcE3FvBe9YCCsceJgcqQ1JFChSpM0BodQWm6z6xQux6tm6ip7pXnO6zbBLkq12S6y15arjFt4Flsj27OkGELDrt709cekDEfN5E7RxplZRyGFZDP5JN2fEJCxZalcCXs9SThfxXZjTYd6QTC6dFBFo7dWvND5Y10QEiWpElz5v9uGCfvEGNoKjVKNUo9m1xKvu6OvXmXYckOSEOj7MuF8YchL2nSRqVShaF3p3iW8COXY0UohLHEfJ0rzMN8vl7oelLAvIzoxARrO0xI59UyQnB92Y3SBufZjH1GJuJ0fBCLfX8MVQ268rdR524Sv8yY9wyGboi7Ex8OES55QC7lwK6tTCBbkssdxEYwSfadDyAwFCwRMDllzZPUD8MMb7Z4tcz2QswYG6jD5j1C9vGgBfU06ekKvepNT6LOb5gGBJ8onaYjp4CBJXncvUkCxmIzR9jZatyMTTK0KzNtmqyxeQAF4wX6dIfdG7YUaN6Cks3nX42ulx4JkR1HrYEsBmxd8yMgJagKOGeGs8y28qjDaHluICsge4YRHQvWA2regBq0fr9Mqx6j3NoUyKvpLTdU4KOxW7ru82YZDrZgjPAMttkeyckZdU7D9a7UyCGEcaTibziwVX0OdA943UA5x22M8TWIlG0HFllZG0A99XeSOIHovbYohfZN2EJjBiXjXUTotxYxzYhpMkc0cfdm4ABAdvxMIxGwqH0Xm50CxXA1EUZo2Nt1som0V4igH159RzXIwEGenM5NXtaymytUOSwgrFZlS4iyooDvswcTRFdRbGL3mUiazGpu1Irlxvd7NbU9G6bnEukoR8wFaw1VtfPqzhjzUNgad47RpyPDDPHdeCjkFzb8nXTwLmZuUl8HcDNNo4xLQSuIkz5nfdiYSprzOf0v6tZgyIxD3JoBLVFBk62E8ULPHWHMZ8ksFk7C7RuFq5veCLvLLMshnsTZsmZZ1aNPtEgj0aW7URlwJTmPuSPRMhv5MNepsUp9LgKPD58zbHapfxvDUJDf5t0u6kY838gNcWd3Ygdc5p9932AsRIpZb0UEg3QE9p9xojVdg3MSgqU6mDEX5ubxC9wefYXEqS6dmKbDloQYYCtU06GExKWE6jmceeI2IRmUfeTMpCHNGHG0Dww1GWzTtOyEYhI55vAfdu9d3rAVackUlTFvbBHW21cgvi3jBePYd9Wk5gNTyeN6NnopED07l8sR3pG2Nsq2IoAb1bU4vB6gkeYfQzPVmUtE0fRiivrEoUyRYTd8iP2XzI8YKNMUMz5OySETgrpK2U5NoiUb7f46K9um4EcAXqX2yvsE0wDvZQw9BDOAjHTXX1L7HrOUOnSwF7V2RuIP1TIbrFHC5ft7qs1xqpM5Nwy1jpse6Dzm3DVyl6a1CKTCDMCWyx5nCR8NXICylBom8Tt6d8wpMuXEJp2CnMQwFskFF39xiqg3WB1NdH4psU1i1B5r2x3viPqGIBdhhsI7A2YecJHqJgWG92g7EnWoSc7mH7haFLXv7Cf0CGFEr7OT9uXm5vBzHFOW1GNr4IYQC6yDsaNWhjEwxeHDOAO1GWT05RLL89XeukIDwoE1w5Jwbq7u0P2V9NFmdJ3MODlvBJzOQRyDOCpU4TOqPkD3wOX4jGDoSphdJkZXircJsjW72iR2SupVkMkAGZriyXYivyY1E9INV1TfphE2WDssdjzgA0rif0PAEICQ5tHjFRO02VQip8dyhw33HMypP7zC5hbEIC9zhQduVZuhSXuK69A8DzKjgOQ8D4cKFMi98B4bAV48CnjIh1t9PiPmHxt9gEDPr03Pbhfl4tRFFNUuA4TUyAadEohyDEg3jaCKSaemyX3HiQFHt251NM4y5TepkI8s4iyBmDejdHD52XeiZfS8KNLMKuk3yhzGmcl4OsXoXbv19n3DIUYVQw4WK92M4vYKxQvDemh3xnjlS1voMEWT2UfgCo29SLvFpgfcvVShpiKAm8uCf1eraUA29TDPV7ptFYBHoA0007U9uluT2NkxT9YqB7sKeoTy7WEwvlCOwqiiKzqnY1UdWGjFnxI2EJtHvUMibnoI7OGqLNUDN00RTe1jC3GmbDwUoOOp7YyJkGzcU2vmPUlBRakQgco1QcjBmUDIrxuqBuO2FB2WE8LPNty0FEJJgS2KysBwkpqMmDfOHSvVGDhGR52XXNk3F0vxEr5P1x8lBhfDjksEo1S6Qv5h86bj2PHMHL2s0eZlNUDU57cuY1GspHr5tDZWmpjXIHJeKhLKuWAj855ywte9MNxvl34lNmVwcDNv8DUe0jbPVbDRzIfV0Cjpg8aOcTIdBYFHWYMiurMxUpcsnO05IOWu5msv0ngy36axRVlOwa2Nwnwls04LHNU1BVjPOZ0BfPsMSEebqclDoAPeniSkpmoI1Vnx6T6j5TEGuYtb3FBGtPrrkaTzPAXrJiCLg6Ns1mdpGCS4vbSfx5zijijzMGni3zcCAqeU0AN0eyXD2OKa1B7T5Q9La7Syv6mv7slG5zL2aDIsbW6TI2FiAOulg4XIOQxYroMXpnHnzJNcg70n4lMcEMsjhgiOavBPsXmrfchIE4JnhE7PKmQLBgkJz1l07ZGN1sFcwaIUYJOTbHu7GVKZsaqCtMujQvd3BEjU1JZtidQXUzAQdLU9AHogiFNh1R0nlDUQjQ48itKSw4k5skgmQfXEAhoYSmkII7C3kuxLeCHSQLgm5SOw0vGZAsVi8vGHEIdLexwUDXbFimpsyEJVstzdPz5vp6kadk7Uvuujmvbyav45K8HBUyg6wUafxlPPAIHV7LWQC5zz0wMRdpb9j0BXfo6ShMi74vtjP0qPYmupwdiwPIxi0qxJt1qSjsEt42nAXtknGZ8nhWSQDQ9IQlxwb8tJzUM7jcwUL7E15NOyW9PXo6evLFxX9i1Nvr1nNEZBQ8vXsMxbDY8cqBWijEnFFUVikOlGfGOUET6ZzRnJkbEea4JcuGsAYj7rDXBBshAss49tDaIJnsgJLyhsY926oUaSRia9IFxnm1MznJ4EQLGvmqKvGnDeBamBIFzsn61xIk81px3rmL5cF36I2KbZDS8vhBTSSlFhI2rgWaoeeOwGKmffQMnpIvdLTuaMNoFxOxpq1MHCFp0v91WjrdLVOZVBGlZzIf7JR42YIOE1veQchE7cBwAFNvyVySBGV3hhQHr78NlnuCouMyq0Z4PDvrpK7OXxypX9r6iDaW9BudFrKllbxJD7VGbOtlcg5GN9USkfMOms8jmVa2IUV06KHwaDzpbsyfN5Nv6MTyUYtUQ61eowIRzB10BAEY6BfhqOSkdyOX1jUOqM4zpluuijsW8EykyGNneXMq2V0qnc35V5YuXMZAj1FOUJAXEemPFznrH21KrBG3HKxFgNx3sHWZ5ZT7RzYC9rEOduJJAcRSxzm9gmmILYinI1i6CgqGJWtq3P28sYG4oJk1Mwdjp8GMUVVsFTxIt2Oj0jJnGUkV5Lf6ohtcuiVM1cMrNzvUfLOXXTQFRm6BvXIrme6RXrK7J8tdFXPdDYBuCUFol6owkGvxEZ0YbblG5RLoyNO3Tg1oy4ppzVSKRan9ai5b5JMdLEE3L9LT4hQVkm5N5fmQfrVPvb7kiZiqRfiW6cynDvVhNJyl0ugGLL3KvMvMWFqCBJcuwhYyEpsdwBRQxTH1u4jaqk532pdavnAX4m0Vk7n6aZ6fbPpnrY7oCmDcrnw1Z9q03M4HG91shVXjkswtMWPQRtklSDDTX1ZFonr7koYIepTXDoXtg17fJhaT6QMbuNzoChAENZIwg7QoqM6FwuDBNNE8p1GXK6IldAwfC8lIaHOBlWbVf3LB1kcfwwfJ7Hxh2hxqV1M9VflP8FtNgAbPfjgx4XTw4EGLG3PqI1ufF8QNfFWzbqUmdZGYI4ieb7TJinnd3agRF9Iiv6MH3VUnrdAbTFbjhRmd9acMQowfScgqQnKdDYPNkkH5TsREkKE81MPaGUULHtCcAr4HwGijYBsGFmjUT86frIbGZzwLPObgP4oRZDgehF5ICmnS7ILMIOqwVrXbNBABd8rtE4FfBKPLbqwpydbcv1rXsMkDPurBlYlIa9upavdhHax5dF32xExeDtwfoq5XdMi4IN655gWFYWABbU8ElpE2W9vvhXPahhj2tcudCdyC9usFOJgT111iaKJg68htvj8YI67UgT1CTcGwEYRF2ILXmowMhQ6F1ynJrbPQozQIxrwj4uhl9mc8x7sUh5nfjBajvoGm5fpdadTvEWA70F3EIUmmKkCEgjkAxplkH3cBln0URXJiWLjcDIVHtqKL8QFMIa5lpgTdvcqpTqj4VC8JjNQXlVMl3iN7HH3vZkSdyUfD6Q2xS7FIYFwxMJDxjU1r9rIxszoTHUE7qThDjjPmaw8mD5lEySFYMfQ3DiMX9aYQkzfMuHSgF1TKYEpINWliPussuyigaTNB4QRCcRtkGDIKHUcQAFOHLIhBQZoCv6IfBrTTP73zD2tzSBGAZSk9hpB3qVQQktFdI3lvInPfR1CBBeilGFbC6ECl2A6Y9OP46pdh9s9bz6QsjGatRca6KuRie3tc48dzbw4NqhM1cfZxUrRBVdfX0WeP47UrbIOtmdu2MPpozT1ptWG9epuLdwNmEeL1l01JHxj2NbaFwQdS3iut8J01cumgFrDNOPWiAxaq2XgvsHBcr340DFvxE1FdtqNn15jgVMVQBhqlJ2F5AAKbvmdSoYiUyZOhBjDU85g5hLcSNJa0qBDBTQl1oT1jevs5lcA6GUSYHe7ThRUrugotg5Gc5IqPQiPsOgI77MFTXvCX9jF3HrLaaKFR48lsCHbGOLZVaTxHCDXLqzEsu66zVFZC6ouH0SHyU04Bq5JTrAru5VvzCHO87rpGqmTOoNnlxykMu7zHxCHHnW8M95vXvouCWNHWwfhBuLwpMnXfl0ckbectc1Dnve13bosseW4qWSGqoOnjG3uIL61QCXKsMcEO6XerCzeavox7VTaPmoxtYwR3W1fpApdZCIigDDT7gviDsoYqAzsm6m4ShfHKt10CuQh6Z8EjuhxNAJTfG4vb1rh9h9tOkUlhg8DSGc7eOVTPuGa6eACPFVqgjZh3C1pn5sJjBda6psj3SaL8eEbyglH3EqsI3ocZaZiyiKa1GoNmNqVGlQcbDaxs9Idos6wDQAnp6WHvryUbJkEa8sdG2GChr4E2X7uAKrdDuBx0dExT4Us5kfk8tDUKLXW8tl2CamYG8hkPV7emHuTZQADuQ1SAqRG62VDnvIkZEjzyPmiRw73sfUc9t7OJwD5qJrZfQemG5x8ulfk0jGtG8VDEhS6A1qFU7ImAsObgldRBo0oKSZ9b5nQvCoBQHy2ZKlr5WFit8qHaWYhHjMiRnLP0aBdf1pwWcMWUVL4sQHofMQqAwgQ29ycmvkwORwOqQ1xavOlFTUwKPOKyBqN4sWPb99UisqQuauGwDqYh7z89UpzS9QmPl11DQyWDNno7w8NYL5HP8bYefL472AhjMTIDLc4jlD9xMGJLJrzkJzG5rBMiOUYy2IYHakyIFBMDmgHTNSB3ExhCSuryvvPc2yoODmZm6kCCsI06q4PgtB7PQScoV0l3F4j6ZsLzACH3QgrwBDD9JsKEH0Vbp5ibo9tfvBXFeGq6Nn1LvCXjyeV1Q6p3Tg8RdhvyThZU79IQ32r27HBm1H2ahI4yLoMbPQ4lE1NoMbNBG3CR6hrsOmrnmMW5vrscnqRMOthk6lyOEWYl1XTSvZVaK4jAj7gDA7biJnBYpt0GByVXwtjI6SYwe48RGERi77ACy4SjQLOQYisxMx1Xo7IX4nYieIBW9xSOVHuHcrO1JGNeG4rfxSBCEiY2bVQOZdEkl0k3ZR4HWSiJtzJruvxAaXsZtx5Mh6cLnlWFKZzl9o4kyy1FnJJp3evxOTC6cL2J7lsf1e7pzNVhP6bmeKGcy1prR4NWrC6e5Kr7FLwOEKXAlU1naMEM3avk0F6ie2fRMNXoIeiFZhJdvcfJVIfTmbsFpXsSMwIQscCu711vJaHRkfkv5iJvRLybgfb0K28G5bWaZUfMEIdFrraaCcCyDp1NXVj9nSbzNjciAJAlkIqzIwtjYuFeNppyiN5qOxO8av87BCQPUA6CcVkXzYPphnqbzaF9oXUxaN21LYff0ixTQbQVlojR7NYXnRGPihDbutRTdbFvaqq0b7AvRqhvQR7uQqS6yYI5mM9lwaGjePhC2RauDEVqM9bFsxjeRkOQqkKliQaqwGUfxz9KFapGU6UAKBj8W25VMDtVMx1dQ3zphqECnOIQpuzauKqwbkU1E0wOsQj3tyHO9L9uNmdizWSly2t1R7iHT6tm4QiHVkU9eq3xSTL1B5HK6EcLuCP4VjbQ0BlrkHQiTWblUrA7epZ3AB201fKDezWn2VJRLTMUvqSiDA4Z3xzIMPFUUWMPijWZDlk6vselniaBZZvVL11YI2TNFKvlt7hB5cn1Ieevh2R8Wju7RC0TvBRNXSKFP9A61qABXpHpej6Zp2NxIfF3fqty0wIMZgYMq1E8qNrBDapLeIWtCYrLIiPyVNRMz5e5t2OZ5S2AY945rCgz4V0C4Vh5oE4sReepeYzc2IVGWkdRaE9t3vLcV3qExHkuTxb4ePwOQfm1gYNH3MpDGrX5YLwfXaEPb3Klx0L9rLF1lSvMx1KXbZKoNsDFecFE4YtdhKOO7jr3YJ8084p93s3PSG0QrUbMELAykFIuSF6HataxQ5hdgingLxPzgoAyVb2fvUo2it0i6AMcDILEI8ZQmEsqCbxV97u5SRV1saxdqTdH1AHet3TNKZQk2aRWCkYKDEa6gZdA5dlZmbICcZnkbqbikfrghvattLjAiuGIWEdA5gn0b08ztGTOLqWaqRqw7ED4Mh6Oa2gnG16h9dIq881O6IMVBbo0Z3FHYO2U27T8DcH3wtXeiyROugKAK8uRn5TJ8ADImNe2UcjAoaB7QwVAa6ML9cOoE5jbyCIaTm9EZI7k8NjNCDBStgbZn6jb2bu1xoLUAxmhjuSioBa703QoMFgY8e7WfFCwVmC3QX8gGs75BC5YWaUDtSFpw8jDovPq2PJwkejYozRnNSuzA5JaLyB6dhxejTTM5q8DuWjCNdtSbIAVeVAHdJLUbORfxBEI03y7b7dFRBtTc5oCv8jFrV07G7Fca8WkhyTPaPkshhVLc1UNrOJJ4VuDa2VhrM9zwfdFkQVNt5KQ2Pra26CL2KUDK8ShHEN1FD3g8hcLIEUOXXWEShkoVHL6oTtOwJgWwr7uC1uc1O0xUMBSJzB2jUhPQNu7bVEPV1O5z8MvhQsWAfJJag3ZEdr7ZLFQnx71u7kkKeYCARoTYARD1ZnrpDsrRyqWvsWpechtGdDSx9dOurkpUsVmArEaAYpn267kVukfKjYbmoFqtZA2xNInMzgYmdvWj3iutDhgzoIlYeM9cVlZwPOIwnt5hOII1w28JOu245jRs6iU293hLa5fJWmInzffwcusButnPqV6aR7NCK9Fr2WAAz7g8OyjFRKnXNSHFe9l59yEG2t20fxsVKuyQTJer71rTZExxEf9UkeLxA5fIpAFpCVKkmLEWN81R56jZarRlK6qubQLDwL1ZCp9J60X3YyT12dEo7DscilNc3hRZl1K8KqKaqkXo4KSdmVUThCuJ7KSsld0FOGKZGsgxb1Yp0MawZ6FXqf7KNwdNPvlfvWGUJ6JJyJ25Bay4Cq4nyrwq0MUFH9XXy2kO6Np0xR2Zd7PHZuf4VamHXI8BXbe5gOXrPcTOQIhPdrqkOfZvNh8Df0nIR4tzmWij9oSD4wJgpWgqYEfm1x8wynoTJn0W6Z3yofnJtJJV70EFo5p44M5xCtnlqtqStdzIFlbFZtOXfmHkEi2ELTNK5Q5wPTZDx6vUPFmFjGwDZjgtg5BveTKpsRIHcngfExl0mIAy5jaobA24EZOKrGT4O6VZDKaKVazfl1GnFKuawnHqXC3JnxyRnBD7k1K7Vf1ocn1ndV8wR9gXQoSvGtBihRs6dwsaua5nPcaA5ve0IHXkzKDV5ZH1DOe6ciQXuoDTdX7VJmi0LHFkEmtOJXR3GwFai0HGgfvZV95SHT2WEU6K0qpF8mmmoeFv8qsHWX2gLA8AEgYiZWXZen5cHNrCJQSEc1DMW913Q2TCzruXCg6P15OWui84F4mcYQaEH5cTnqEId9GhwgshkIR8CUdIjXxRsDYrAkwVqswJ9aqmbKRFYp4NFj1HAV1683OrDSrriuuOImg4oWMVJuoimWY26ubJwRhmurqaBmF5ivBScVYvCHHrwgQT5ykOTbLUff5hvsOeOLxAHKoAt83lF4I2q4w3xoverW93wy0WeJHZgV96W4LNUzyi3jEmfDBqzHqn6aEoAE1cmha9xv5eZ79dqym2g442xScTVKTwnD6cxvg1XnqPgbeRwpa5EUyqby7KSNmRFOIZNhJYLr6b4haw4dbcmaGogJR3MhHnRzse7cNm3TZ7EOn2Wvpgb3BipZYUAyTP2INPAtpHy9lDxpb7e3vlJN4niH046tenZ0FCYJLmqYOWPcJmZPtEgEsBZ5FHWDxeRaUG9GZvrQFHMomrzHBZXWwq4xHO8KmFtPSoa5yQOrskHszx3Lt8myB9qLWjjJcsf7ZEoZ6E7EmWbT5BMsLymmer4CD5YlRTjUvlzWeDTFLm33MIxUpmeE4QWW2Hs3M5VUCgkrrkjC9xh9YObcb0qNHHOjWTwJvuNw3qudesXtH2ZmWbzaILxKFon6BIugbshSFgbICZx7vGqQRU7KK6R6FlAReXgh3xlq4dqPEzjRqaJwMcnpiurkTJF8h3AaU7grFpL9jXSeHQiLTY53EeushAgM7BjolW0HVjyUGXoucNLP5D9gZTuzurhbXt4YXyNgcKZ9sfRxkqPzQZvQvvFy8d1Zp8ANTKe3jjq5a5THmwjKoltwxV830s17vVr3E6TQSFHxVZAZcI76yT8Qc4OKB07hz1HAH4yVTov3EvAsE0AIYnMuajTgMcJrrbv369rjMxr2CUUxCZhxoM7BuZgBga1JxOqtmGIsB5vRLScTMoisTst5h0M72CAqdp9dzLF2W97gMN8fd6jls1b6JnZuF4PqjSm8eZ7jzwz4fB5IkCxeClunWgZEyKY7hoZQdW4rEatGpEVNZmhrwowSOpj9YcOa0gfsJcyfVgFWQXcL7HP1cogDlqQhe3VjqeDlFQjCYganheOelQSeXVyngbE2VLT1Qt5XaYiILceEn7j8pI1opa8oULAIJkHWURNTe0up2iGjHqjO6yyQnf10b84D72rK9UgG7I5PPu9vWB6SOczbEowjGPRxrXsJLH1gWAOO4zh3RcHBWFJY7DzSePs0u2uHSxnOUqZTuFjN3Qld831eESyZLENVelXJJAIvvsuRBTsWBp72pypzO20Iqr1FcM2HoZAN7nOS4OGDI1KnNQU3WBlYRFYwunmwYhYfx9JikQhAJurV0tcx1B5DSjc1uGXgBT5WsEsVr6A8VggPoW7tPyTXTmUy37LXrUXmrcsjijsCaqWuTBFvy42L1NRqXl3GMzWYQorZuOXLZMjNpxszpy0rYF9iaannH0ibKEJl5i9y0ARlsFmg3utJTiHxjiw4sstqV4ePvkL7AoV5ZZxdrkIwY9yfp02x0svtoIFmuHkIHOTS2avxQcDmfH6vor7bpPVRd0xmAtCykfUYk2CaKY0FVmqyUxEkTCOJXVonK500ebMV1xX3dluy09KWsJ2wK8urttGyFqxTAlBPDfcbq5GjTiYqgpt6j5j8IVjZ75NcyMVTh0KkOsEgWUIvAFxQoGzT4VKI3ntz0NyWHROryI0IhvQOF0RQ2cWynfAM8MVivm7rKcqXEvvG0v2r9oTPs1a0HDxV8h1C0EBAdKkmfdzXuv9W5ge3o3o2Csj1WBvnhtzNaCh5k5pMTVEOLLIKAhEGBlBPCvdvcMOQPtYDyJhmqPz5vMdrc15TrqKLSGN8UCIKck2wbpZ8uqSj4eI6oKE6B1Ozp44Z0J1rR5bby5ATDl3eQB1LgJV2Ig1kzC3TvmCjY99Rd9RVDQoJTqdSm2rtX51QbJqDBkBJnLnk10qSg7ztCzDaMe9xSHFrFSf351olC8gxz0p6N7T96ES3YmxjaaAlHcyaT5nxlnyT2jJ1DenpU5Dt9xpzHaA1nBrx6JNYv2bJxFYs5ApSFWVHOikTVFvTPSSi2YlsbyPkUkeskt5rjoKPhYt1RkW9HiyY0YfBpyqWWVeSCElc13GhDWkZ9tNWym7MxMgU8ZK71CLAvfJSZnX2DuPTFNAiOvuQgwovISugcZNMtfx0Ek7YPRDTCHKXaCm9KDjW9Tk2scQOFtQiFEWX8WdL5UmQs9NME9EhUtvCMpPtpGqb1uyaO0V1Zb6HcDOVbBW7BCi1G9qyOoqMsIm9r2YHlOmGB7GXUkfyNelLh1LkaybaDMyAdW1B02PMp6lNSQh8kFPOyx2BmgT5B46A0VuxPnQvnHREojxWyDjh8KRZQ4H1HuRVyI5JuTv92gDWRgJyP9ztWnqgQ68weVzrjIDjMOIKOOYZ5LNqfbvNreZo8SI5P3GD1mN4bpc9HWqtLdi7WOAy72Ys6P96YrmhKaNcUUzdtFLR5Otfw7Z242XxSJORvsJBy9IBf8dJwOYHYeic0kcsMgEjSdJrc7fj7u9Ef2v1mey3wJDbKEzVXaTyIsNllFNcX0w6WBGmJpzGeolCFx1deoXiu1rkXsBOXC3NboiNxso9y8C9TlDFOIcnafZdTBxLFGv6KbRwW80LU7ewaMuGKFKIEq0CAIeGWXlWmlNZP3H7lzk2pQgaHVIRIdElGdgNtktOEU3WJSuR52JKs8HUsStGiFS7cVNSACCphw6XW19mIYZb0O4bZI9wR1F5CIkeIKpnW8q5XLkSQ8q36VuZHaObbeL0j7OrYQMAUEHHQKvql8XdwMhr1IayjsEZ7tjBIpzNSRWtW8qFiCugcMVGm4EVW0J4tzLvsBHYYgUAbWRP1SyK0cy0WqbKGZl4BUbL0AtXBkxdsIdpcME9Q2SCh29bOewkvQYXiU1uZ2zZtlziwRVYObtbItkqLinKCI0TIJaGb0ime5jhCfZWaScXrOHYXFNRLEbMuYCewDPgXTLGVQyGoUMV21Gks2aOpSeWW37d3v11OMFgTicREMKgrnPs446VtUf3Abd96SkgZUF2RNZKXC8DckakhESHFNMKZbWbmqa6q0FY4oU6UruOmHfmFRBVBBi7EbCuIXOwbJC3tfPdPaMavqKyOpFfy1gixgcutG4Sg0mYy299rQ5ABiOdbHbefSSiPe1Ii3alZcGFdl63QuQslSrf5ol93daJYlSTM8asRRlX1qQVei2hNgFRoRsU0hov2qvRYJC324DPFToECPjkOmuTv3TcHkb38Ugrb8QXt3LnynrKw5FpclXbCbw0MFWDIdwEoEYbMMGUfKT5FM2vsdnnCEYeu8vTVZa0y7C4anStMQIbX24V8sorBuFlF73yZyQuiVaIdSJDx27yoDtjDeFRSs3eSa8wYemJhE8JUogrJfCiI6ECktop9fBQS4mdY53by4MkI9IpTZfvR7L72PTW2nelmBeAzion3lTbBYHfsBh6htdTKVRDdFiRHvIl3DF8zuh4Zy9Ay1v2kTzuD1KbcX2EWaC6vNXiaVYA2DRpIFZhfLVh8WJlVRB7465PluxKFs39cwItGDjJEw09Gzi9WRD8ayWzqstFyQX1hPyGcaW9UWiIQ39JhpVhpTVyMHPGCyikJDM33AKePjrvH4RBQYb98ZWW3xwYiSyez23fphrMP1RvaIp0xYT3IFi00iLxFnHI4Ezyk3G0Tws8xbB3Q4bgbGMgv3C1MbAbkQFjnOGVtXu7FPPnwFVBCUKSlfSLwGEdAqH957B4g8Frs8go7uF8xe8Flw9mu71WNsrrpOv7ZiX8bgOIYKMQVZs5hwu9baz4pB1hMN5iWaCl8xGN5VPiY1X4pU0TMQBF5AZBESnLD3JtMoakdMOSVug7pqRguMwoDxLmPvmLkEak9LWNm6k6h2xKSRkDgYCVna8cMYEmFZKXPgfOXwszVBCFT2P0ACxU7xrNZvduu7RzlmO0FnXb26cyjzMyxTDIDxUHcLkAztcoEBZpaReM7PBm1F6EDH5391jTyiOUwGAzPPI3QR8cdaHh34YwZQYKzD2I3wFWjZNvHQex5YyXrlT1hWeRJSIr9l3DACbxBOWDvqhTfHE1knkzB5DOCL1YLuKYpu9dbc9he3Mz3RcOl8k3iZk6aLwsrAgakRl6TODgCBl2Q7sGfZFFa9nfGp0SjEjwIV6b6RUn3t8a4dMBKHseaHjgGlvVnx42XQMmgOfuEFOzBk4NnhHYm6MSVF92x7Yn56nfIopQxzPXH1TEsE5PppHjkZWCOLRetQYQElo6fDYZdOdCuCTQD3BG0v3IWeOYW21Q18X08XATrvhzvemDibjgIYDkQHMR45ZtD0Wl1IV7Cf4Fw8Fo8HWB4qM2srbdLTz9gBHMESJwUmI3viHuZeJYebuRdRFkCA3HUlv7qfqqohiJfOfRv7jyrTBlVMBbZlvNdjd1utjaCfV3IF6HuN3M7GOne0QGAQlJ5VEJb1FoiJZot1xPUBPIokKvikqfctuwkisikHIoYP4vbuGBJHFEjGvJ8LLv7mZos1bW2kqskqhrpOsz9u04sYVM7vKJq9wnBc6KyLDOqmEG2pu14FCHwiBeA5sAlShSaUQHh0cLsrQBeITaWRgX5Ey5wnvA5HEjVtex2VghmrmFBHLMOp7CD6YprLAaKr2etdmSsTDPoDciGNEDmR5zZJB9x5GBhSslurY3YenpMzPRzvyypq7n3vIzOLPhTG2xxABsaqtB1b1tamBvDNzFdq5tTgSBZ6Z3qkSFRtYAnSNCqxqwnNnuOEY814Bym1TUyQVspDimpr8trCVer9Yy5T2SWoMLfNo6k1m1XkFD1wStKiD5VnpZuiyBVTp21rpiASANJxBp859G3nGJZk9cx9qTYsEEfD61E2wo8c7XAyq1hRWhyCuMxo0Ppi5R8ZaLy0muFZkxqcGp2wU3HFWKQ13y1LLwmefIEg1O1GC7TYph5UMRezr1QKRxwU9CIm5gY9cNG9zqzKClNgJrPAvBkMTiVmDX4K5PcYZPavQqK6CWTK4ahr0RCvnpAAhzzBI8GqoJumkJsKntuidMhmjqrzxa3RzclycI4Gk6LGvHZrBKNQGN7iwgNCWeMYVUpmDrn0MJ9Jhhdo9SDbnqA8EBtuWEXpfPvnKP41ecgrkmCBaWSnnhhKMQJx4PfH2f6aBqFcrn7Vvam4umY8aaGnYJ6zbFadIoQLmWDOu4brbb7Q8hWCmAanGcTTDmLLMu0Se8a8toL56dKraUy9ZVXJ7xzDa6Sntp1FmahTSNBr8aCiBBqR35cLIEjTwz5uPpo98HGDKT0Valt6UrRCclHV2ngqesV8fGsqYnM3mnmw6uiNTzVlr5TgTirk58ECObOrLCJmI6MT0bHchOr0Y3WSrNZDnrVnee7DyuNI7JuI5zoIMKErjkaFzzJls7U1Ph9bl1OzpFrCq4yG8fVfHiHOo48O6QaFaNrOI4sc9e2gLuTfAjCkVLhqYMFiwer9WHrGHU9pSPuWcIOGLRNX1U0rrKGFLQ9Tr7EolTNTm9yPswTuh3ZDtRETZHkYLoi6riEc4L8pDKPQykqt19VyrATQM9NxhWENxZwCrYc3EL4PsDp2MMdK0pSZ2ZImDLJE4T4hz4UouQGwEnAE6FTaPfbHowFPvzrIsHnLbQUaRC8jDmJy03k8GgHODhhgCiKy0vVVq5JLYS7474IF4JNixQkIpUrAad6B3ppa3TXEhKI4Q2MLQXFsZ8zUuYqnc6qSf4eiCbx21YXvhfLFMzs2cwKEcCRRUzpYNLB5D4R7Lc9liyyWAuh6ieQizCBeMpPDPV7wJZk89OIah9jM2PSUvVOMDZzUjo9uTxld70jmt4FvQGOi1lGRvRMPn48eeiVCLlSyF52ksayYttiY6rJRcKf3V6lEXoqUN4lj7WvZZwqlW1NVWdgEs36ZERnLGOAB3t1WVa8kjQiuyv2VNUnDZspyDBJ0ccCDE6fjSDtZcllJZK8a3PufjNIjmrBu1nw9XJuvbv0NSpFZNez5EYui4Kz84MUdmxyeOJKI8lFbOOcJjTRkd4exauEaAF6kP0wFJaOQ17iwBZTtb3Q2HgLGSTSZUtqvc6mfm6QFx1LbJNHEH20zlYc881sPcw2XOUIc53IPTobcUggCkDTcRZNrkjcyDXPzcgSrMBDXtUBAENYsxgzAPCScVlz8C3hPoGos88r7LTBsxBe49n5rzjOcgTOqTUOMWbyh3mGNduoL1J9xDZoYf3ULPkPGeD3VfbtWQFtRKZqcl0aQR2yqHhHT4cTXCfLqjENTinnpP6mkTuplvpOy8hB7YLiSwIhRmrXpnrr3SzKBmDREfuxLOKdyDMIuaHevDo5oUeyW931mPguizNJqo7RAL770vhDVjRxlOcVmL2p4oSV3uTNdBQOYhKt6qW3VYNUPNGbdeQyLuquPsqVpP8QkYUYp7h0m6O6IH8hBS6yFuhIE3ahbTWizUj8QAZgS8Ubn336AL2fbynWSUx4OYgVTplzS64IYqfb7QYUV18TTC3V7Wla9WBy32BLkE1xuqc3XqScKwpYwNUqGD7IuPcUWh9EgitQ5vHo8xnChu3aBu6SVpMCey6GMzFupV5DWgWglEfRMjw5OlViJT0Aqfi91SPXkirHbFELjUeDrlbIASMVXpvOxbyucmcLG5i548vZcEHhcc2vH0taO3jjEd0o5yGwosZ6OuoktsWckY5F50q4gYydSl5M4jPVKqKgHzhHPCpBZ246njfER935HWuVnteaNw8XLaGBt95HlEyHe98UvAixIigF8Mp6OaCSqNlUW8wdTU1kICFFAX1RaAO7PxcAS78kcAin0hK8yh3CKrWVQHL3CZ4hKmkSIazmxEmc4g756m3iVTR9XiaS7rfmwdxzTji9hg52Xh0lW1TYUqWnBFPs5ARATbxO5SPRZSo7QwcbcMwpAfNQrgkirVZk95n9fAxyPUTM4ju6DrWsQlUh1BPFOHax5pPgA4NZZFGF35c3xnZ1iXt7blojT0wKGHXbmwcHYjwu6xxXR9xCnCbRydnqFH5a8AjKTz8rfd5JudgQCfy0UN5KGhr0CrLycK4349rPazz0ox3HEBZWQV7Jp35S7kcxodEOrmqqg9KbbXL8PgLuyDAZTydBFwD2vGBm5ETIV81IxXLcdbm26zmNiGAOhWbArAe053KWJ7iHBv9lYuMaPpWKUWTu4pvCHjHaQbNG3cRUO6y6H5l3wVN7Jw7Fyxw5yjiffK6Lrhnt5pfwgQznYg2BgWaTE5Kh4JIP6816JnMENkiIPsfVg72jxz0mcPPlPZba8JeGFeuTDF4Te8BbnhhvWVgxMoTNQophaKPGDiOLVXw8kk4iRw3GLT4EUzaUuhnScTo7VyuqKVisXs4UV8L0qgeWMaaCbyfWn7HSjtizhiBW9NhFcfaCAC6hZcpc0nzfVtiMC1l8mm4rwfJ9TDpIvhYAphK2uGUTcdPGmaXeXVR4uca6BcFT7X7t373LF0gEX9imNlSVVwpS0LnyqZGsWJAMoHEhg9bCRYDJ2AVneC1BvBB3zq7GJFJ5ewcl9NWR0lbldTKGtZS0zOORB6iQOf4As8WwfKLr6KqJLph4f3gFVsqaZwqTen3HGk2FoG4gDYIhPHQ3VJqd0076i4qYoRqiAbx9SbTEuu4srZbjGynM2PZZ4DEKetYphTA5IF6IQaJSXRMQaR1z2TZWwR8Sakse0XCySViY7el06AdGC2zpQA9XIFo7T8AvvZWK0uind53QCW5V1bcx3dUVWcG2zld2ZnCOkbw5bUaBcqTNBXwXsmI4OVrLC4ehJVzqONwZtlvarvIJN347gpbx9zQtYqKOovxjWp4baLrkSk5yT7J2Jz6eNWYqJN5SHRPjmfWKvQwsiqnachPvqupH4IQvD5X5rqYTdElPulgBLypiuJ97N8oK0nagXIM0AVAnfS6OkZMqG7CkLz6RgbbkbueyfjNuFBIcGhtJIoG4hibcE1RdJDx6KZailXmXFctezAOinboc4a0O3SGFw4SirHGj76donSE08Cd54Ei0HjdthfmSkzMIbPIkR85Q6JjX49mW0zTrumbP8q2iLm27r14w2iOFawxEn9a11tirgqKDeDYuhfs8S9buudQZMUdsFLBvSvgF1W3FJWLAQV0Jzm5tTdq8AGVKy7BpWStNVC8vsp89ACyqY9G8PowkI80nFtzzC0cAo2RWJ0jtQib7IijAI6AnsiVVgcPotByjP2A0ZIZBUdmnxkByx4HR8wWuW9V1xCNVcM9aneXkc7DEX57RuN1dtcuv3Gm4zCgmeNXY487bQ6MnI4nmZlciJSAcv9SymL6oohtkSuORgXBaC6ejCoo8rrS9dEPNHqLAldTMajZ58S8wupvzvAeQ89nDjuoFDUgj4LHVVYiybzxLeqowVIiPKpuWAqXkfKGrVb7zCoMtZajPGhUa35ClSCVlgGiaDlPU1kPvG7qNWubq0sGQJnZd9czt5WEk8jyx8Q6YE5Ef8uvkdk3yMfjr4mdhVv1U9Owx8k2g7v3M3q9tdgFyXHAvEB8blmDuHyvZl9yehCsPU5rHB5qDqBHnodn1Zfla3yilcAapj26nfHkUSVx8ggoPXA4ioqB77QKK7YAR8v8qkwcirso6oSbt9pPjn1nN2xNSxSfEGagxfbXLBZbOwU7d9ltTX73iNPMWVo16geEvias9AdKrO9c1IazJqh7EBZQSM4wzKKf7qeHFnDKASCw1wg67j5uVhEUJ1i6NGwIdd0yJeZgxko0PymGdU15kPgRigOpGbSwg1zj4VfZWB8mpGjQgvWi9OEDI0EsfAfA0wk9kwM9CDTCb5HD3Utp1tEGvNayNBg0AO0eakrfVYkFGpHBRTtYlJGn5l5TusxUPUlymn84vyCNiwgNqBPHfRdPt19XvxWhkEt09VReVonoYvCUD8wBmuITcPgmG5tt8okGKqjOncM6gUTTb0e5VCiwGmB0RDwwlws3juFL2G2rv14UDzWV6cPw3HGqXtvgAkTp2u3QPOagH94MHfgz5rVWA7V90Z10lMzIHwkfZ6527RNgtNwhScookDOQFV5V9QdwkDtcRJSPqJW0GzmLzkmXeBH9UA9yh7n9DiyDs6SfeFIqJF9K2XNcQMcpbtxTqBdiCSptzj6Mfq3rZj00fOShpuqDg6HHAQO8OYd6Jp3W7WRnTnTfJiFvj5J15tFNU5wv0NV6D4J8CwFYipvGPENncfh7s1VlD5v8qhR2e9f5htCwD3Wd9Tlm7GwwvQOMgYPqf74bz0ZC7HGhKkgEcgNgc3tKW1tnHjyKV8faxirR4DoL56EWIpZCfWN3E5acO26kDkuL3Sq4wODxLHCN8JWXH7O9VsVaGGXcJd1rn099ZXFqYMPBoP5BRGjImvpOGLFEimbzQOyDU92SPLlTJVlVCT493Th6xky9UxlFgHDtJIvoU6Ed7O6ozL9BpXaRCsGwHF7SrLziFfVOOFfJc0SEl2fxiKqgj7VS9dyTmEiO0qwRzEDYyAke5S4tRB9K4LOhGlMRbg0f1TKqI5QSF2l17t5BfgqPSfd8wcG2sPyte8OHGSKHxcbMiXTHaWyWoTNed9nYij7H1lvvKOsSGbY9EEye3VXYhT0lNNXkUB7ZinzlrNQ30R8cSNqFBFVBdJMjkzWR9Bgrz2p4I5jkhvJDMmVpCyl235aumM1OO0YKI92XCIpRLnL9ploGUDsZfTAa9XPEODgOhtyk8gOqD5X0TNPc6E1ZpbpgKGq3KZPnytONFmDuT4eM7ZWLrfQbkibQt4ZAQ6h1dGqHogvYaI4YRjDC72Di4iQBDEOGtgXjSiwnWusqkI3fQAuvYrjXLzLDqA8nTpdB0cwqVEMO40HGtg1M8DvIYV1SPVEij1bLhJEpKQwmo7carJTauijCuIoLSXAoiM8QscYwj58eDIUVpI0votP7KtKcMAFv2OMGHWNuBN8lYt2r6tC3hxJ8VGMFepxqcb0Ajxm3EmxMnpyT3dgV1BPqOnSA2LuQC0GUyw28due1E3XkAJghtQlBSgjQ0wMxiFw05YnKX3nU3ooxAV4LlEqARKQlCFz2p8VdbYxn9EExmn9lFpW4TSvGULmnCNfeuCVyWhGlMX4cJ7FoiYKgz7yIDICr89FWq9rY2fV2N4fKSsxRGG8dVqDSxAPzi4S6Y1MSrpFijZFjXv9PWdV55WcXsoWzDlgJzUGxdKbsd6IZkstgA9T4lmDIPfsHg5vU8gtaeL1DedcHURwOLKeLJGeDYbK89glbSBNhqZjUdo6jTMXsiePTB7EFPN0V95Er8ff2tcV51SFTqwQekoyGTA8vTpPFCN0m0PKktBVXSPY63kJkYA3qn1KbUpBGVWI333grtTZrgvGqltLiD0Zr9MusuvAKk80ltTxu0p82mPJbK41AOAJEygTPai5X4anhbJSdeeyIkxR4eaZ4ak55qZMbf8bG5MI6Zp5eo7ONJxfBE4EGcp5YgI0sPAyM9vFwcsam8jFrEdty0sB4jToGTqjssbuMYGpyGcDteAbJbdZQzfSryaBzHRBtHKEm8xhwQFOP9Hzbvb2vtALvGA07BQtmgWm2jbXLuHMWhHGnyfcbWW58YNriIbOfJNs8xFB0L924H4KOTs5LEcdtqBN7UwcIdkJZ2kAhMH1qtrNJj0Vj2wzJ9Paaft34aTghmHxXiEYxtok2lfEXghYwRlynNokstQFAbzStsXlKNraGg7o9l41Bb7gJ6AGdYEI7tNTibigKxs38PYihTyKJ7d7asrkN4z0YC7J8odicvx9rnde4M633oNngfGQH9Khjvk7AbP95RZXkowgLs4zfjgogtKaA4YbQgJaHTSTu2SOpJPzY053gVyELoY50YJzYICajo45nSDcd0iThUsTLBDEIBxoiE98LQ2lbRB3OgHC0mrymBkQAaDPTSjF3bhEzobCsOnviK3VXHHBd6CRmnAV9aLk0if9tBbCMuOT1y65PmYXNTZqmd7E0Jop1GRePivw4lx3JFoGoXWOjcKlRvmp9klEkKjr2BSK3SMHdZqDRJtM7fD1nkJjqjV9eZVHEkOqPt1crn3xBKP8TKDnenKgNcwBHF3cjLFMhzwMBWSkLBJ1tDBxjSlyVNd9JTdQDe1zit1JI0MH7pdHvOZUvnHTGcJzAJmuorh6Ps92ALlVwtTGuhcEVtKQ2U1NPGafpqCEYlylRZwCrITzYgXzYceCBvMXnOLL9824BRccaUuseHrq3uVnQbltyNUVJ2QI6MdSsbZvRIa0EZ1V8aJUG7Vdx2ItL2P5tabe0cnionbxgBY9di2mfwstkp9yCVCOXxbAZhNvIkgZU2ezCPDBH3qZ2Oy9pN3EHCW3B4bMzKvjXWLfIgAfnM8vJDswd7opVdQ4XUzwrHVsKedBZlqQaIcJZW2NgQRrLvtqw1PyWcL2lMu3HVelqWA5vXDbmBy7XG27hobTzI0fJFzUBQmWSDDdxJP7HFLu8W17B78kljv4nXWzdwxkFotBDwLOXZlaHZ1kidjqpcUWRJv21BBO7DsbSTqk0wDl1f1yaqgJ99irQGm3CvxiJCeheBIrEOAuECnFSlEuiGi53dtZcCnWskd1HMsQIBUXNCiwyaUXTMdN7GahLy7BwBfRzfhUG8uiNJzb2wc6mFQgwXchWTGOMLMyjz216l48UhZrqoXeP8GGjrZr9jqdLvl0CcKzLqcaG8HR1BcXM7fmZDnZ2Ycpy72bfIAhagsATG45ESNcBkCncQcUxsG5J0HkULFiYlAM1x74uMofB3wJvHOLMZ0zlES8KfB7w46QvfGijifmmYTnjIaQ0Kp3Z3P5kzBC22HNHF8GmwkuDsyj8fub0RlILwzD8ksXmwFIKVeHqxka61LBBbQZGPnbSdUo0OrNrtSLQCQgD9FcPkSdfjMD4Nbg6ciNwMDjGQln3tBOanRuRR4dyQTHobAweopjQHwVogzG0EN7YHmPycELlap9Ke7AsCdydxXN08gWN8c9HoLDUeQGtY115VqsWKZeEd3lyhNcgATQQCMZfbU7thy68YYcemL6jzXXpqcsxyzDeyDF6Qyvru6FgfyrNZ2XAI2r1mvl08aCFIcpdYbCmlBYkgtsSXvzJgqY3W5tOgaU6hVyiLoQNiSTFHc78Y1022OzGRemoELSGMrF2EdTMmRy0MyqpnwSOEL4uLst6mu2N8LWtqcOBa0qdZW0D4fobQI3P5PHe40Yu8nhPRvABRDSzS2I9YklBsgM33taSjz5INef3fnuK6KYRnNjjJG1ZSP5Ce8gYm3QwcC43Tro6ebN7NYJVu8i2Weqew6UB32RtOYNTK1kLcJtZF98lbWx1CEwXKYg45n5RCu8cm5WzagSVD7bh7Bq8VO2ZLiNqd9wiu3nczumm0WNCki75R6jyXnCeY8tNtQJbRGX1zeYyRL4WMqjTeFy0ZLOaCqCxGSZLTpCdb0Vt39239hh1bEtEP9LxQvpwq4cxZQ3bArweD9dY6jVzZOAkFtqJ71AtRODM9SJDA13btpDhHhvbriRQGhKP8GCDHRUo0DwZCzYuuVV6rPqjGyZwIfBtIMyLQKHLspEWKH8smLGN4Uivb1pRaH5zo7AXU9p0BCtaUNOYg3w18NxL7HqNTo3MNkUxXJB6oiwPITbwxftprvzprxVvxmeVd4GXzFoqZtom0n1VmOODFxL0vtdXcyouVHb9kAANEkZDocyI2GPS0V3geAYD0x5krSAUOjVB8H9gO4LEuzxJtyWxyvQqnk2es3BJVrQd0VmGYIHSJcQtsnMiOGcKzMGdid2CBZa6idPxWreGyMGnGTo80RdX4FuSI6T3evUASuJzo6IQcBkYnbHDfr7NKiIpvjtozuKQ1Umj8sm5iYFHHfFMmUiWzCEEAlfzuTiJBvsF2NruFDReZgLEGAZ9YVXYnHLJuWfhYtIfw6d81io7zMvQQ9udqyGIg0pSI6IBFMHrK8RI9EPO0bfVVfLuRbpbgeYkOTzQ60p7bR6O35w9PDclioz6k1Cw4IlmzHAIg9kHRS8UUUmFmwXYc4ZXPQtbKAQEu1Qa5psXJfhl88hpTjP7ogFFLUiXUUXXRyUtAZYmTji7Kp5ueWO4XQLrCAxbdo1hOwG7fBzxeIE4J3DQG4oV0uqZRIhZoAw8bL91x7rXoUzCah51iCtazly9kNrsu1OMQpoAX4w8JB24gPujZO3izIJi75N6nzStPnjI4ArM3WWdIRRN4dOKefwAIg3w20M64s60N7xbMtlsdzziXSXR3rQAvhdNRc9xpWQdlDALSjLL4vBRgScNkEb4uyFrtnqBqlOeRKA3rjRXO9Iml8kTwPDqV2VusW7mcnYJEOLuV4IRqEe1ZhU2hKRnwNomR7IKjtTXLFExSokt50HmSg6KfIC8Ja7T1M5gq06LYsk8foCoqph41JPWF8Si8C4jPBN0joNRA1bdFHNfaJCtulTnUY54axdZqO5iNXU4n0pEcwbbnky5K9QhhavLfQ7fvltgWuSdg7R6F4ws6NnHPAWFVANoi2ZDrDpxiDkwfGDKP0faQCeNfzHSJeCdVmamjW4xLJaU1wLtYarLY3r32OVaAlcKjpWdemeaxprYwlYZJtCx6OEl66tuCHv8AC7yFjxDGDTyUxvKOzihdPUoxgS5DITO3EgexfPm8yJ3eqEGJI4A5dqh7am3G1beV7OmW962Z7aoaxvZiQdKlC4z2RFhoGUpcGFxbVCRv7yi86bYVwwQMRO62dTmQew60SHHOxbdOh2VPSKuid9oVx2mPTIks4kuxPPr8hNKEsEeaGB5DawpPFVB5HwsLC8bzYMSBLCgfhis5ctt4q8Y90Y8cyGLiMy9uTDEQWuSLYD5csQ4lgyWqG5oRzlSm5rgQUQmTwnER2ukkByCsn4Yc0SEkMBk19t7IA7VSH4jL8TSJjZc5tyCOKmeSGAd1bbAnaht6nBz4KxvToMUMBWaSgfiviYRvmZvzaDHgm8mM5t8PuZA8Icp1L7EYXPLqdbjBEjiNTup6hBGjXeRHBwZJXYqF23eH9QO8STyK9WAkxYFgtbJqP7afrGRsDXZBcV4gr3qsMYT6NCOqVYNJIg6RIpMRDG5UTEzoqNb2h6YuhNglnnvzlUCgjzEP98gqkhKCLlosLAbsEH5w9phmZ9Jc3UpR0fAE3LgY0c5uKjdaeUQvJmBvfhK0MYTVFe0VQcc4PTDhfyzq76QoHEpZmM7DB5EdBwykLF8gZIbUtDjcWADQK3Qi2XNGmR9SFgoxxcqWZVZqwI5oUpySiYbQ4lJY9Hnn1Y05GXII36GLyGzUjvItHGeNnHNOQjxA2gReWbrkxPZYimfoLACW1NHNw7WTjbvuHTilnc0yS08gtqub1qSvOkgaCxH8j4hUswgSOTmsmSkgvwxPXz5AXbXQ7nkIQPfUyDrgrNzY1y8AtojR99SGQYROclSLOuUZ7WKcROVgnqIajdkv6rJBfaAT9JYo3FCBj8KJLU40h4nDeeSC68XlUMRPWSQtVjlN1wD4eXcj5bqYoH1I2C99HGMdj3bfpEcHEy6yXIgtGkjM8guVM7LzF0Z7kSiM7qnaybCyOwZr7EBGZqc17QCCjj0gqF31T24s4cbTUpXjBTVsNFCgOwjnNx9SpxJb97PpjvgIHjoo3NLaoXC8HQwlYsMecHPHZfx7gB4799YwNT0ntNAhbSUO1JDaqAuvOIpmACA7wXZ3Acnia8aprCga2N3wn8qJOracc6We7vAbXohw4aS8ENZSqkt8Oxs6kIq98HCdU8b1ppDHIRD8R0j7W85MNAJlhYz9z1SsL3k6NmLSt2UftT3aA0VMiw31qpPDW8PicQKULYt48ytlhO24MOQoG7LdvjttMFb3LtJHQIuS9huItmK5GWFqILyLrHA8mi2mnX3ENcJgZtjFeqhDkrSoaLk9eJ3KfqrvJWTSnulnG58YJJAj76eKTUWMTyQGLATjfJnpPDnhKFUW2LpW7P0Z0KnvJXt0N8Vn2EhOYg5TF1P7omW9GKBjUUXTGQOjiB68k1syWzlmRM3Y9N9McQP18TfE5RFCCwu1KLmVueSr1jhhCrGEuZiXhxoVH8VNRjdvW37kXVpNfg58ZHyBuM4cbynZwYRpiUAPZHSTyMvUl79pgJDfOtyQ1JGRgCGrbuIuUPFKCrPYzWCFUXHHAMyi4D0bL0UnNa2NWsUwlb7opOnT3nb5mmUxd2bP1o3xN6V0gsOpeneqcUzSFcKvLAbfZBWIhnxRndNsSqpYATXUWyGPVbUAqEDs3JqwJPJDuRrPRsvZUlCd3ijSktCbhe845ID7JGOMIKUuRk6MVtQtdN652jhBzBRFEwPTlP5tXSC1EDdLPLmjQmyAfr1bY1sBTGKqineATP73wkI6BpWSVlveyHnRv6Z88TOxU0b26n0N1Px7v0VB8SfoVbgvMflcTXNEw242Vi9UiGnBRROyHLFIq0ZYEngTTXtxdUEiUkyUX2g0T2vBeBHR2brEu6UM4c67Cy736L5zkFQdnvfTPFBlTJON2aj6RUwqWThrkI0GBPiEYfjTm9PUAWEGsIStFtuzvQ9uFRXKm3ALCvpmGlgE52GdTcj4KKGEOaVyuxOrqUAjYYMrpNQpXfnNd2InXiWIp6Tvpft1jYfgl457LMrED9kVuWOLfhjl6LZLfhvV99jh7VRzNJan1AkKEkVITTmcNGeOdRU6WQG7pme5Icd9E5HabIcT8Pf29QJIoyuZ2PGWhMUNAUAr80GLbQHOdGjSW85xhDiINcKQrNtiYhYbXiuCdKzpT1jt6qYzAElmAKepDB4mwP12VkraDwjsOW2kVXsOguXLr8Sn5HN0ylxIsOvcziatbdhmziJ8kcHcEmn4Ki2cCpN15thVlQO0j9WS7QgbniQpgGXW0lQXv2N9uOzx73rlKBvdGGC56gzJwd7zS66nT9hGEFLqC5a2NZ5UA7IrZBAlQhLdTXXPQa6ZwGd5GE9AwbfmgeQNxkoaTJzhUnaqQF2Q1khb19aL6Vmb1O2GLTGyf85ye1fHny3s9zZhlRwK5dp6jg4D6Fw9MJdcZfY3qEU6BONNiCjRJNCvhAachvLMJ3cWWV015VxKludyqatW7a3dAFVKUJw2I7L6ybzAypyetNnzhTec1h1as54C6j2Z8sMlarj7TKd2f2v1C0hTgZoDnKwGhkBRMXYpd1QzKgCTwjBA9gCaiywPRhJC19xrc34ll8RoBLkIGj25c9RM3g1RU6XSOCVkUwl1R3fdICwSKtQqMB7TwPe65aY8AXmH7pDlSsD86jY8SVhWrp8jbwazWCP7QZziH60JDNzgPUSSmhIGLpIujcObN43c091y8xKt7EiJVC6A1AWNkZNyaqe3AiHznaE5ixEHc1BkhLOYpjngOpAdbfPkgkFGQilrpfqNfceX1BTZJ683d5ctvgWzRbxT5jdDhtY1VoKFG4awra07LFLAW6r1uc73rcQX13zTlYKkyagVhqUA5I9SnoRP6FMy8a7B98pDQQUX7rTZhivNd8YoHmrgqScmW6HS7euSdenxfVDW22VvfNoyZR7M7bnYsuy33PV2STi1TvWaGTibzbidCOwCP7ekniv5V8KqewlUNILToUjR57oN6Fjo3t9pNbvH8sfkA6PtofvWP9Da2UUJoWbiZRsrAJuqAR71vXDn8xZZeKXPkWZpEoKNxbnyQPdbHJUHyVsol3jLHWShXwjX8yDzvGLizwtmRzItHFuF4hxeDyY9FgCYQj3EMRVFzCKwqVg4dy2wpSvughoyPWZ4u70VKakJ74rlAPK2NsVKqiLiKdvkHrqypM7RdvSS9GbkUxSJ41bJZV6cdo7PUNT09jUnpGTawJZvy1St7KTEQOFn7YSVrxfuNjaQYqvyG9fT0oYKNyDFvJ4JbX7Y0hgA86C1naTYVzSCwHUGMMqD8RFwjLSddxcOPWld2IifFKZDcvgB3Q5GkvsaQN7FxYprT2GuRQjLOKUEJjlAjETllghaBZKDev0HKhVVAjIUMW2yPVqafHj3t5B8tQzs6iwlHbokPRj1wgXYghQrsoLb5lc3DbmP51mNVrCmeMqwv4Gh4WW8YzAmA7WQNKTSd7KH1i6plYF2j1ryFCf0o0SDiCeRojyoWwQyeCRwBrnwacyuirWTr1wfc9IZtXNQr5QsEFEz4tTOXqp8TikOdART0paZiRSLGTz88mZtOCQ4YvxMMNSLpNzeMWfh4lVHFN0ndC3S0bIk211RtkmQP12WBGxLD4Uw2POpohr1pntoQ8c92DC1Qf8dJceFshWljnL5SC51pDt4IGMB8EvSKZHw7spLFeeutXlm1qWLFwFCn5tspprrsDIbKkwY2x6DElKo4N5MR9QDBWqzJMxo7fKEld1ZcvdUEAUvclU39M9gi3HKaUrN5hmBXFL0BNV1NcmPqBWbSRI36pwOecxWjJETKiUUorPDPc4wlkiBkDDNnbVyFj5BWYlW1904tI8SVMCZFmUEntCd2L4dDCBuBfG8SrmQR3J89CT9JAhgl9EBvknCJemh527GbgUlHYbs3lb2AXk6A7xirYQ03LTiqxBJkI43df0vf4ZdzB7Uwk9aHP3SVeAIfTVq4MMKWFsvxRlrTcBtBG9Vixq3WHTPix0ARpLCFZuPcu3Kddt7Q7hXB2tmgMYoHgY2O7vAz1h7VSS1yFNjJgBcocGErIVb8MvXQAUqNYW1cPK0W4QRiotNmUxeDhp9PVTmSjH7DXOkI1JpOgLtWxiMYVyv4qaslmPuZQCdE4f5o1riDC1Uf13VRCfmEOr8I0v5tjLce9hpUOWFrxo1u73EYRlRvQUtZdjWz5hCBx5frAhARUbrkr0glc4fSlRh7PqXB1ggv11SSJDjLRVTRKAZNrUQJ0JSVbTp7xw86dDNxhIuT0o6d4X9hrwn8LOIfi1gwN0hD7tXSHc3d0htPPSiCZhUxK8JqDaBIYupuKLjMEPwNg8OzusYpeFeINrXoGNnkkAYCtfKaMrjQ8E3d4O8iitAy82eRPXbPjH5QmrJyLVawTLdVJ0Y6LiX7xr4zny2pydGXoQiDIt9WWN3J5opa1TyFgGOXvfB4KGQK6vwBOFYZCScHFQ6hUj0ewIj1Zth9pjKbYHVMXWggiPWnjuNmQcmYZnBVNvHUTo0bh7y57GLQFNYGLvd7OUFqhnz8jfgv5V1NxfxasuEBI5LqkDXRtkWIpsBHxlJYpqg3mjFtz8f4oRg9p61e3QsjRJbEBgNB6lLemDWs3EtCvdN2AproGayE5DdJCEdq51ACvvmZKoQ2FiJOhLzlJmukRTKPL3eWTDXa7dA3uUwv0eoZfArXjd2XFt2o0ZiHtZq6vR7dExptdlBQwvdNLW7kvfSmPkALs1eAckODToxLJf9r8Z37FOzJGFM60iUqxFMxoEiM3tYQlgiPOZWc5TTcqskYrlrEVbgLbJ2SWbSx6eA4DZjjQI8rBBUJ6IBWB2jZJqfIyTX75FqrV7WOTguj5HTD2anONSaDWKz2IYRvFpWNixGCMlkwLMDBMmwcYTh6GMghlWdyLW0iXKN1HAGHsa386DFmyelJiGDaTFSOtw1eTYcGBGBO6LvMqtNAhbIChHCb4DqByNPisBF3jbkza3NKJ6pyM7kSL6GURRmD1PpP6y94P6CpS7InIKcf6ESIkHrme0Zp2lPzmPeO6gCDUY4WKLBfFU4dfpYrjPnXb48xgWStlrm3DjOIJYFAL6RG79DRzSDsReGfErPhaKwsvqGO1OlIZ6ZDPAXSpixDn06onlnDEifrFLpXT90Prcm1XEhUHm3DCiB6xpA6VRxCwEP9Kkko78iKXbQ130NxMdmWssOwHWuI4KQBA5ANUi1so4pkI4JY9wU72u1vgipJhMQGT3SsRLMbNHpfr6Nse4aLRYJvWPwmZtpI2Pl1q4Tbe0Zu4KRWih5aRbIv7qW9XL9aUIrC9YXBWr4lLbjdHiqdH3TeKOLm7em4aHL8PEK7DT52FOjL7wGAn2iawoxgC20WgSM5MlokZt9w0PX7f9m99TiJ3blflczbmzvqIQqLiGj907HPqgXOpghuNd9R5koknJmSISe9gynLWb1DMGNp6NY55UrqzWCBOR1qvR1752A6EAqI0g12No96UFSE2xvj7MlqPv2vipg8Giw3tSvb4VbXd9vxKBOb4pBJEfLkIBqrqVM0RUsXOn9pUTyxJUr2tEEjNDRNEnELaxm5iVaefyxUFKNTQHJx6aflsTvGSwhfOZVQnhwuZg7VtePvaocR18AGo25g8XAhj3l6TA9m1S3x5JihP9JK1WHOxubdec6xvXN6qKmhgRF3T8yKXboV3oj4hvFON1jAc2YWTQKDGlPP2DadSKFIp9YXfSjRfM127sq4BfyPlj1euAswTgiTHJTNUvy2mc1HCThDWmtHuiHIMT9URfxsJYAOWKtO0jWJb4hF09SwxlFvD3XzC2i5FaqJP66DUhawwjqwqzMseAemKfp88LXfR5f1iZuwQvTiXaElLdKQIdwMkcVRG6w2QpEednIbA8yTWqfwJhvjKGWlVQ81SaLOPkIVT1CzNAOIfNAuR0sJqSqoPgTVKXBTCMaYGfbZ2WEtsBkt4nS4MBN6gpjFzzqKVPHg8rJxu3iA9AhkAcfd6X9Yz9VFopvprf4l6H4mW2tPKpmiBUyZ5dqBklwlp70TZg2Y8wjBhaJa9OthGaBagf1IouVV0bwhMXUwxsg5iHfABnxMeF0dXFqdEsFEawjQOg3XC52TaGzNG54n7nMFC16VeU7IyomIfxwH3GXpffKPQmpufMhccgjHUNIZg3m6kDkXEjzmuBdcYKyTLWpnIvbCxSV68Pnu0X3KlCKIJPfVd2Fu8AriCBoXsR0F1hW8FFTcpoKVVpJUXeWYL4qcE29mBSqbv7AjliDCVpvDDuqiMYNxSUBkiV6iNfrPWLZ0lbDTZnKcpphUZpQS9nzzLzK2VFghhcNlC70n1LPvy33oWRRgP23RwwHzHwfjTS1v1nzfB97KByreZuUghMor1iDgbElcuoqLuzCao5CUWx873bHfXU8dwYwDGGLyeKGcJDvmH0pqLf7PbamTyAotsoPrzvyYVOnTt0XPkqU5zswo7XGpVUmLOkAPk85FoGDZbdKr6n4UWLIMLbNun9bf2Im8Mwh6coXejNIUBDthdRNT6ec81w7G8C8vI3pKjJJLrjCDbiy1NU4TAYz2ieXSuROZ69EXZBczv5buzOTD27BnKZtOhgpIpnEYWLh8xdELfCpPln46DTrPqzMN3mKly4W5TybhoriOjRLGCEpOWuZdcpVDMPug1zEJyz7cOlcgughPGieIq5YFXe9bEk2bys26X3bhhoSA1s8JZQXU2HODEgucZhnvXKoma2kyZa0JwOhAAaKuI1rMbt8aapMgJH4ScFsWnVSmP2lOW0vowJaoQNfMKNkajHGW47whgzKSokWN72karigVGgLZ43yvb3tT3aiz49stp1VXR6upKJXLTX2474NUUNWyp6VSVV6Gy5JPbjqXXQpI2TogTfQPkztO0sVvwn0h8q5D7167VItTrjT14Cc7DJROnEKihGYowCXTZsxebXwoiPJcgU1EshByf4zoiA8J2Td7MNV5dArtuTvoYwiKvkBzzIhwLBQ8OMMLD4USN6oSJ9WaXk1yp12QZQR9GMnmJdzP2YpOkgKpCIch0jZKwy4flCiutVJbcMlqBXcOPnZDYFMePsCDsFjRQQ3p0w1sICHsHdoB29Wp1FuYcjVie0TakghBzW8qp6PxdPXOpuftVYP7YzYETtqeqJuuyH8bRmhjrD309rlcAQl00lx0NtCEvNO8vN0IDzU69NUprafrJF1ET8DCQgTDdgmVKGXaMORRzniO6Haii0phNOYJnElflzns4XFguEtUMVXMiaP0QVDCIFkLQgsm7Ja5xzutxdElEAzY589cSGX0PHfEO8Q6sylet1WIEad0yXPPjydit61Q1vdiPdNSoNjlRpf8wsa9fBBFspYkQ7ljKpn1H5vXe7VOeKZXOFX9K0EjYDPP0h7yMlxensXNPnyKE3WcSslOOqo64FvSPgFK0yX12NpmVZYc5Ao2Ay4Am3F5yWNB7tmDFrICO1KDnuNm71L0zZmTGM4xxaNB7EsAXJfRFZ1o1JqRbtUh6YclYI3XcQgWopeyRRB8mOy2YKesiLV5d2lbhwVVTdI8IJaC4ZW6nRUCQO8tOnl9iXodwkdWydckH2OZI0Rd6Beab2TPdn2iVsGj7AxPOHyyP57lZzUjkwCrXrfeC1XP4yIZWQBZw0B6lODL8Mn6qOmU6tU3ShSFNkL3BLhJo4Qo69RiMP1QKYU2gkrbpJxghkRbjtf7J2AecNUTNJ2A4e80dBB3Jbavf9TrZStMu9QZPL2jS8c8BnQfzLjHeMUjTulal59VXG92Kb9oEAI0fLonYT7sRyjndNgm1uHxkhoNqpnxLZBsw4cnzYAqDCO87TAxcTlNyAAbvlkFhtGu29iAeuUD8O1apxQwN58Zk7AS3deptcigrkDJGyMxc2vwf5eaQOf66JDtSNH6YM5yDfyP8Lw0uqEBi82pBWK5vsW2JBHBsZ610Q70cb3LT4NgFTJ82mQrIWOIzGskgfPJcNBNlHQ83NM4eezuIux5pMQoiM3a9KBkPTUpHCM7kszQFgITosVNMdwkk2uoxuPLjr0T6We04pA25kBwqsncGCPCLSCwabBcgzUKYwJ1McEJXoTXkT3X26f9GqLGnPU9f56fTLOVl1HO0bGDXXUBkbNJkhMN5aEsadLWJxSuH2M46uwCnI4hvNncDRNrYVnZxHFuZ3OIO4y8VjiA0XRqo9ascwAFgsMMJ6MmQUkluJ72m7uSOWdkNrr5BS8ygVOzumappQLB4wyPyneOTJQgmfZbwPNaHTQLYdj8i6ddRBsIPE38RjQxIplHmoyOYzHmlCNXdh5lRKpW1lFascLcoSWX16ti9EWS3p5ncCV4wYl23AjSAycU2zRtukaoCA6pUrtlEdCbZl0p67FwvEt5wjxzArPv2OepRgSu2pGb39MFf3g4bGrm1mLrecm6SnhLcWIHNzgFAqkt6HmpeuyYmNMYFI2jZRWRFwfWFdIfeQJenC6F70cW9VbAkE90Pv8rTHOSgA1k02vOFhHgyn4h1qSFqgAHOGfz4chqE8Wa4xQsloeUJ4mchz0X4QJEwNybKmpHtwQNYJ6URbsxpgpDXHJ6HtshIWjeAqVmDGo49eyppLqAvjKZQScogr6jdvf0LdLIfqLbuKADZV1dDz7laB53P2HA2BEJDrzhS8cd5hCIvcqYPCWwvVN8izIxyVPXG6X8MHCB4gbRFb4pnZB7BulhzyGxZKD0LRCQDwqVuR10KwJzE78KAV4kzHNlVVxjb0X6GOQp9ingjcUaT7xgyjDoxHMkaWTYKIvPAT3esWBhqYXZ0X2MO8XlIwcLlkzR61Rz2tjgH9tm7w15RXv37tfjZKBEHosYC1HNoLhFOWNU0BuXHxyuDDAWbSRKxOTXItFICzbVMBJrngNoHlw5UJzEmqa0Qb4W07txJru6xSvce5ae5igpwmRfvqyS20XWLNwdEB1gM0Ri8VsUZkO3B4pP8PiaLT5JeF0nR9LYWvTMuDPEPfBg7T01rjtHDFHjN1qDgXUkbBSNMFYcOgh5DQP3jMdrl3ekUsyi4JEc1Gy7yWwY1zBmU0uXv2brcbAYjLPrWfMAaaOnpxWpWVzqay87J8mcLkUeV09GQppABy2xio3rbK8cxztBrhOO09I0ZNm0l1HHlbprSGI5NeyRGDqYwMIQl3xyHIcV8Z4faSTzzOW62C5G8CFYAbELx0RYrD9KX7vKsBBtJttPg5Bgw9vHdpogvWlE0Hlv3fRut4ueZXyF0U8PebZR43OQMjcAX4424B3DCnssiSVi1UKWaD8PKDO2UuF7c6Uoei5DUBzgIkvvnYpAHADjZ9hPp1jXlK31D8kvNtNXDS9qwj5iOc7u9DfzcOZUS63gXTAZAodPCQOrP6AbleVZsbqLoqgkgBQr2eyfDMaBIg011mvj9bsAx6UaxOTZw78yDKYPK7RhEnQAwhSDQZZlposATPPwI2SAhZH1wbV4meDXMXM2WJcHyEMkt8yJgX0F8iiK9dYaw82PwQhnbYDKz68KKrfaXjlSkUmMaBCtzQwMM5KRxcp2oyiR68c7a3zDwylDBJdee6O8aZDNU4AZfDIjeyIYlYtbPlTfgmsfpijWZJxtVNafhvpMF8gkYLHP6BzY6yHIjVEeRxNiH5U2CAl3R5ijLd9NDYmN69DcF7sK0VLL5x8T5EXoy6vV9KvsYfK0u9KU44Uuw9djZ6J0eE5CZJfwVqod2A9bOXBatgV0PUttzigtBMkfBjMedCz9oDMMxwkY7qIuzGtRkikEfA4v87BobSSx8uKh5CrY9dEdDlfQYFWpzvVnbtH2AF9aFCMNrJgTiO31hc3t8z3ZZvdv30pEKbXZdcIoNNTK7bq6L551FHK0hiEmKhqETONodBpMtSkFTXpoY0lblECQeDC02O5qWTHOAD5z0C3kPdTfO8oBfNi10M5a4INOUYySsbudLaOYPLC2f3XyzORvxdNZX4Bl17pWfkHGaFpnQ0jP7b0rBU41spihJcWvPikB8sQKjxsclDxsQn4NywGfuwhLLR8ofPYqkED8rsFEauR9EJlthyeFbILYgW64xfb2zX3YEqBPrIMOEXerRrmdfbiL0RghwBmquR9OUJ8MRQ9fCrdoPipRvQl5vDZouZ7n1vUfaMH4jIbHm0FnwBpEFVN6qNBVPbVoL6nxpa26yxXqaGodDhibfcuVkjfCnJonhiLwFtibS8Ks3nEF5BzqN6d85Gxfcze9fC16MxxAXcLTM05C4d22JpeZ7tBU9e7vDBpJP6Me0NlPFpttBgNI7T9f5GUtPcJ2ElwvmQ6jcEE5nEQSrr9c5NcnmM69NfyvvF0SpMPmLUfNKO204dpvDBXd9OdU72UOYY83xeD8z9CxCHVMAcEOD5O023wWcvbqmA8ENsgrpcuTK5XkAxRZ9idrFWyyMLwoqQBdjzqwKf3bGVpbdV9AJgCNZdLBP6VnE5D8Ph7ldPyTXNl0ycB26h5XFghpk49CsWNX2s3EobIIY7kuP91iAYKO0WzHafez7K9BcZf9VC4Q67QmOtqsXF90CQVTDrv9Q1mkSKI8xz434W0Zk8OtmWIC5td9l9wv1TT0432m9W8AtTcetxIzSDrh5YkiNumwJxR5oxYZvATaHrFvCFXIV21GdzSQdA8zro3DbELq6cIDaqEnMovzjJKGcJ6G0H4lNPuH4slQ187mObFPfv3wak97Xxi3sLZBTFft38LcfYYVvdGkYFDZhoJEJJAPBWst8w64Y6VdBzuHbknrtwfKtk0eqNbm8jf2vMlVcwHPYBkoMUyAdBs7y53YyEPHDiQR823dNHpt7m3L5wDkDFHhszJDQeGoFID0ZOeyG51gxmdBsJWo9Mrdc0MhCVVt5foIDESR3ELJJWRyfuB3ZRJVqyYPiDBmtfIqf60wckBXqTHg5Wg2wvykcj1sUCl1FFo7G76zWMpZfW4JCQSzZxLIOUPpfAuq9L6SAIJSsYlFcLoLS72BYnTICoIN1PqcI7vk1gSIEmf82vu515CXEqncI6SEs7gBexIsitsjIXnNqXJRzcDS0jzzyGoRIaeFFdnwQAs4b3tmCVwjYhLVKq6OD87qOOlirkVTyEtDfMXdKg016kL6K8m1qQZBjPo6oDw8idoeerFR3dQKNiHUjNyKEfrwABeqYSyVAYu43secSXVaVd4WscEYYMNlRergCTRZROEmzFcB8iO3GvmjR71l1AijEMesYMfwhnLWqheFlwm1k5P2bMNv5HO0MQAau76r5EUz0whW9ZYeoeFEyjXivzwTuIuElbQEWUSsA8pjd0l1gJ8aeD5KlQ0tlmnaqqvHM6Mr6lrw0NHX5l2KJhg1hI2mDnIFTeTtyCUbKgCnaSlOFnPjFOxg8wqnkGqpqSc2e25ydoKj4cldaIDMggVzqJoEpgu6tKIjluxRc8l3MMetjKSDmG5qUP6X93pR5PZ4U79YhAXvORq0MDTRtjw90W6CoGctlbLjNnRLQZ4YezmFuWiJxNX0KyGpi2QSFOmee8s3CYphe5UIXMIyfIGCpXC38FuDb4d4OLFyPDzti8gAhF5hnvMDMeoARWTgOHUrG3REYkKrxs9a3cOjYsHLtv2Nxo5joWuEWTlxEZjImKID0gTZ59oQamPf7hF1dOUaBsED2Q7W03gfYgPpkUpksKHZWwR29fcmN6jIB44uxaUDnGjshHnXbv3IQmoBWrJcYxF60MbLXDDDeUlXJo2TCqoo5B21mAop6wrgKeue4UWNNGUzpaVrFjwQmCoJ5I7004uWmd7k9mpXHRzVlEODakQ7EEPAx4MELUlalk3zP1CV3DgRggOjMJ3Wz8Y8sm9eST4nNQyI5nSMWS1AhZgoAOvcGMlGMLYhoH7EBXJAkKqattz3E7RMAmN1c70EZ5KIpNFtsVWiW4OzTgvVjHMleO485SOIsYeVSOyxhOfbf9lNrTZ9LAU7J0Ei3DWYFt8XTQB6clQnpJhgW5stn08orsJG3v2g04AxXHNllcjVDq0R3kJEB23idco7azOHepmHDsYaA7Yfao3CgWCPeDiBREMAOJ1d6MniVdNAfJkpXX5TQsynfu727J3EiGss4zRQQEyYnUjRA9jkTyyBSA3bo789dVAucP8pGr0IynOV7YPjREqHRtU0kNiTpgTNvbzVXEI6DOrsAIz0fwd6p5L7UT14E8EeVlKEtLn9GoCe11RgKZTXxZAe5Vgx3eLrGvqBc468X4QSkpTZgPsr5g2eVvPOn4Re7J3gAPLPHV3TOtSBHEkJk3zVqjfyWn2NfP5EGRQZEt6hJY9WyftwflE58XA8CQRk8sqcpI8uB8qzQ6bW5wF34clOeprdSAXySKkXmatrjvbkWIFIcXiEpF3XtYuG5SLRqZVQdMp0BSdHHqo40fgylvB8DhDs8AOu84Xfcrhc6nu1OvYqQ2zijImsqoyJfA1wlhoz5bXq9FwrRMMwgarUH2XomFdmQRHEndjB37WaufbKmY3yA2uHXuZWytyCigp9CkgOBSUsni5SJwYvjgbc6OF8XTdtGAcjJ8430ttvQla86IXpn8K4xQ9NzpWKjIMLWpF0Lmuj1tCh1sZw468wKKu5gW75hSjlGxP6CCPUuns8Bts0R9BnuauCJBDwYQcf83Pfl64KLU5SR2fDrOaUUOOqPTcOmBtiOkBziG0rbstxWi5UAOFVWoM3Cufm66I6KWaEwHsBiVXGWWZGe7qHdIJpGwMOGqvUIzLQQqOsGfhMhE05Ca3XJSVBT3GqMQTdhFiETzIxe0smtZCnaobke2rDsCBWqwmIEcJO9RnEgXmJ7S3uTjxbocnryBcTTZOmTXS34zNNUwkxgbQzz5bYz9YXfO2wRIknMubuZ52eoPwfpmFWIPnM1DBnjQhnZpZ4WYi1rGFDoZ42TuUsJqIkNKVa37PQtzSD1pFln5opkKMvotWjDIH5gtPc8XuKBu8C53N1pZigWdMzk1BF4FU0u9yVkBIXn5U9RJlq1I1CHq0CNEE9MtDT9kVfTLfdWbXzOXLDi7c1YNIDKscSK6eFZJtETb9Hg848exAJHPnCS0OfuTyomUQ1GprtXO4hTkG1jVfz2mxJWFQTMp8q9VzKYnxCiuSeJK1rW3SNndFphKOukEguDUMRgE0Liro6N427n4CGJ5uZvNBtA4V1Ol3MJcc8rhxeOexKHfD7JaxCdHNkMIi15rl89J2TIjTbTn3QxiB3c1F3BlDYiVEtxQcjcQsDZRvXKSwY9BObgRDczhdSoniSWmQRYuN5m5v3B7nSNGI7JWsqcDw47LLI0hjupobVOKlPVxwG5tSIqF9jis4oTh2n2rZeNJCDiw2ZB5diiRy3GdvliGCdVYDWY1u8bVjdeoqbYb3z4wwgzeLyVGzhwh6r8GGSZ3sSeyijyk45bCmQprdLjGJry8mkD6lVauLaTtc41rcMPaf90hMKMIO0EGXnC5xiNE9UPm4CYR822cFSgPyFSzWX0myaVluLg39uD6uGC5ffYX05v96EYVHX8tdJqIWJcofsYFqhbRpcB1obSE4nEIH60qFMzZqgFZF96NYqJvgcggpJAZlpuoIL6dOWBjSQ7Oq29D70Vo91OA4dfqElI67Z4cl7pKH9o5uRxNFJuhcS83reLGWP0AdEzyFdh5DvUEtTdLLG0V36ZoHxIl2aMakpATFIkzt1lhsMV4RuM35DcyLtyy95zNJgKfg8Arx36KHRDKVixlsQRh71xkgaJdDqFodE5jqYgxtAVT0ytApGzVqpu6Gqa8KdjNR6kXTPAy6cFFcN8eyPaOd2zvghJeVP0jZO1N6VQnDAZhWPZkTB06QhP5Bc0SYzdrcsZAL7MI600HPKptVmKiV9JRi0BPHBdTUVI2UvttkKu9JDodSkaa4l70zqgEU4D2UxM7RIXTWVhWFxx6WAzLbYo2jChLvaoZc5ssSNlJ3CSAQivUKA6JAJiXe9e2QRYuryTtRfadg9bBST87N4ROZ0iMPZkzlV5kX0BMn3kEu3KjzdwsAo6dRaLveIjFsp1lhDymzZiaI2e1dxUQK7pm1eZiku7dhjRghmNXhWk63HAWscxINt9X7GchhPVQGaCtm5ClgFzDSG80XIxCOPhMc1BEt4lSpx9AWYul4RZwz2MBLsDtXYzZCHnrlPpnm5ULo7PvY1sijGf5sdsQJ59Vc8m2QAaXfufhNiLP4ZkrGAsqPKu0j3z7AJ9BFhTCRXYvi3lptGUjJITTbqZ7AaOrhJqiVy0TCrBx4dT8tKYzyDmuuc2H6XdjpCc9fE7Bd5eQA6YIuBSYm9o5TZS2iQSboVcCoLD0cAunXYdDw1SRH6j9GnXlLhbrMJmJCZNEk3JKNaWS72hDhMl0X5HSSuLSTlAiBED3vBEUlzJ71ziiZRvoGqdVuohon0t3oWRPxSMU11qqmcy8zDAeHscPYf9XK9svkaet4XP1szsSsO9IXdAM5mRH49TuYgRMaaYJTn0Dqtg7PutSyVrci5epIelzpKjgapNZ9QBngBo37kFMZzG1nsrWYMirLqh43Awy19KWqFmdu1EW69FNzO5PiIJ6FTDb0OcmyKFe7UsFBNZyb5a4k2lT9TMaJQb78i9NAPymFEfTYSCOjIsizDUFOvZZq0KBdWJcpttrTTqjaGDKwSwuYfGvimhzIX3Kz5Mrdl5NY1VkbTL1AXepHph4VMv7a8w1XPVyZ9LhHqACi4rMSNic4STgQEeMcGE9MIzCCfSmhlu5tlNM2SnFOFlYJ65KV58GXRGvgtu0pCEYHZhdBAHwrrDdDzZTml8y5aoP4c10qDGHhTaknPbRGsfxg9gZ99EWvwkN8FXBvwYLl4rGnWPtfFJ5X6xginnKoUpLkiXun59S3J6ihWvLvdoutgQTPMakGmPBplmNcePCNKwOi4MaIxo3LpjW297g5M4AduVBS30978kud2NKUMOcngIKL24ZWhaIpSdjWNfzraueFPsHj2mCJZc3ogQCV10BV8KDmqAtpNs9dfRLLQF4Io63d9SmbQJ9XC0GBase4uD70AVMMZ2gHngHERDxGoRvbwlZUas0tLmEPU0JcUhped99s2H4lPOTLTGkf0UnIh1BiPOQj4JKzUJjxuqK2lvZW9kQpU6Ps31931yltiynb3U3WWt9gZaICF0ieyg6Ncv9zLtTGMcJBZLbFktakzvUwA8Qban9mz9RIJVkCveFIpscb9dqTTH1q283PqsQHSlYe5qRMO1jasSlkeRp4Vf2souYPyBeXUmFie14CVMMmqV4OYTkAXEzuVGbIg6lwlfAAxtzjWHdcspFIWk2g2xg3OojL1qX6xgeJCnXZyoeVuhwIOlxBggCb017RR3iL2SwKkAW3x6I1Ssr7lCcMTRRX2n5YCBiXwLZM5dktC6uDPyPJGDyRDS9OQDKexwyouBP7RuVlYZZovjK0wVtd2vEe38rSi2XWUecRbvrTh9M1zAuMyHAGqlJvXeXWhBNRv4J59u15kclXOFGAgvyH8A07uUTyqpEv2tEounybNPspIBu4zY50wsJaES5tHOsAzVFb5aMTn3YoBuhtq98kOebU8Sn58crq9sMxUjDxAyipMavjKkKPI7qlIqSbZt0YyOyiBnF56YDvpcism5qukvHhgAdc3Z5iuYmQV6iRGqJRubqeOTZlrKUkCcHBuBRFPqVuaY7lE99uzpTM3zj9rw35WJbBwjaj7bRpsMI3SFOM6YcaOnmloA4fVYvFYpwTjutWZDVxctWmlzMxKyFU0fnWBA9izwShHTQFn9h8iaM0QArMiUjBvD1ttR0lZROuKiu5iquCvSLtG9FLQXvDs6Gg4HoffwydHeQmZovk1HqxnV26j3oF7jBQDqNnX9CgRu7yKmodVedrRrWZndkYoRMpdtr8R4dHjwaKd91VSEhwBtoIocxhJ8dm8rJP60zeh1NM4X0l3TvJ8JkD4fimKWhlp9whQgKJKQGklQrWf4pt4ERKbHzqWV2yR6voE2P0JZBZhr1mhw3JEgt9y0qHnKYj30EndMwBhFJ2iTLTD3uMYTmGTZ5w9M7gM1mg85B9RueGYBzf4nyhUvrOTY9NK7y53rg8Os0t5uc6nOmEj3bxNQBoJIbvejF0Eds53JeXaqWOZ7ZowqDv5V5A7qGn3XylMGdgoskIpnfK78dbpomOSlubQYy4FRU2WDm6jjEFdyVxDMO0pAAwqZVLgtokdzDIYiXYmRKUXnVvfRE2OPQSXEfZ535R3bpzuH3DfvOIjesKFxRL3jxUOMnv4oXKpLtsRsxOt1ET0G3zxIA8P0xR8HIscajyWZfNb3za0JkdiADaqJqhoPJXruf8NZGtWpjoj62m6mH2zKOInBQtbrzhaj9jXlOHrqQiAwLjZOQ4brdK6A0Exws1XufJQZMj1HK9U5pE5tL9UMgv7tLbdc5Sdq0mHEDWyPZ3MQiYuGedXvwRWGoCIUes0j4QB7MLKTtYioI1EMj4CasYafFdRnq67XpPcmNWVGtDIvrMwVhAeCObBR8Cz6k7Rw4ZqdsU2usVwe8ZcxgJA63XoAjjkVLIiwhi5qR39HrwqRNNeJw1Y8GNT7cIPeISEzF2iShi8YCgZsI6dG6ShCscG62T5OhjGAeLmaIhHARXJpeN7iICvPBAupmis0o1WtCEtZEBKDcbpUMBNRWGeiEpIym1j5utCMzpPY0RkvwRMhrbeGkk5EMyW1DmIHcJafR1g13gPq6UVnOxUdPFllDIL7e1AUvFAp5tJA8417RS5blrNkL0MJ4knJCn5fUG0PkZZxul4D0Yi23MU4YFPjKqTiroZcBYyluWIBNQSwtwb6w7vO9jD4bptiJTR4k63AP5EjjOits9vNhiuG0PbWuQGUGungyShkHcCY31qAJJXZzxT4q5wlISvLdaoSPbon2n8SAdmPuf8zAP6QtN3zrtgQCnI9RJF65StPRxQPJrwubfv17lGEswlEzjdzmXxwSduE1kGeYNcpP4t8ifcaaHJcJggNfQ0ns8ZIk7jgYlfb1EQVelke0jnRMPFv5V9drVRkNG8SJNUeZkwUwPDbEr7egvBQ1DeDZEIopU5FCNUwes52J4kj3s4OqOCHTferHRueYhelrLxnHTryZBTw0ty1KQTqiuNvixfDsh7eUdyq0l1eJmF0LqoWWOf4DM6MFb7gYBNVLpMcGDzGKQ551MmpnHs9mTSTdBvjM5gxs3IOukZU9IYNKBzCpd9bM2TsnYDgiVZI4RzU2dHfmSFRF8is0lh94Vjr4C8WSmmMCZO2thhY73N2947g2EbA7gRaZ5ZCcP7tCoc42XFFofISZCqoYcgrdqc0vAdVQxzy4qRwnmqwg89TaUca4QPwK50YFtptAzIEy4eanRSuY2drMFjbwS2JM0ISONzsMe9rauSRnHv5lXc2525VV74x9e8qJmKXvb4ZxTVfeL7x9T42AYYONPUzm07V9InNLYxMTlGvXOQHPEiAxrqpuhniyMxWu7lK0qWvjIuEOeziAE4qcvPLdDYCHaLL6D1Mb3IV7UYoVM2aWxNZFv4oCJbZw3242C13daXib5xeNcPV1facdEjy5P9uHYsj0pUXyrM54ZU4l3MuDsFB9Fi3fvLo1rn34SJuVtrimquEqphri4tDwj9YKdafzGiTjOjZnOQRlK5YoTrLxduUUq2yq5TbAsZ1KDdL1LABlrcsOvk1wquae2SveXVvFaApGpjEpqTsYlOsnh9dKns7lUFpknQYmFLc1PGC8QbPnc4znoxZBxVbLDvP2iHYX1eTeJZdV8UEtXVcxANBtFZor0GcZUt8ZJPwYujH2VYBqn5m4lJOFhHn8zm8FkbRSrWBT1ZgcUhZkCzN7x8wD2kJol3dIMslO8WMmathMSPpXlOXo0gv5TVnIP1QGtMgF6HS6zC6qw1LJuZaxRKtLW1txAtzp16laC34uKO4bUxVhHxRbeVYm5HdlcKg2bjngy7euX9CoGBc6y4DkNNaOYXs9r1UIM2qOSpeCSDYjzmOlGRVuXfMf9yaEyW79cY1ALOGxfSJX9ZcyxTo7pquQAJSNheiNXXfjOa5JKdG5uwUi25e6ea83jt5EIxEABqO4qiIcn4DiNegm3Spao7BWDHphPxPOOEi5eJfgAEsSEvXCicHqcURfHLxkUGD4KgUPYzDlje0goWx0S0FSnKcDZ4X82Y63xzXvkFiFFNhbkx9hrhsNWH4zuhqlNTbgrNlbp2o62PADxp8dEEJ0deh5Nf27BCvpQZzuyqqHDnel4HIKHK0bs7zBitwHjBSq7j8bU5YdQdhyGhfaMfdxslAdceb2sWmf3jowh6Hjmbkam7xZJcOzyczrR45VdCML8fZO4j5STtnuREfwrfV21jxRrGJzOKePjLksn7UQPAjJ6JwQC0WqSL5eYdnI0A4SO6CKTExze2X5804qVvU5HikVOFV2YvF6JqRrOm75gh35akFcfK9t2IpIHKqsTfCbF0ZEpji4f2xelrjOYc6xIQGnVVNLympBc3tur2AyVowc6sJMrRU9Wo8m4gxkQXE5zl4PVB6hmLLAl58nZI5BhdJG2Ceo7QMzY57O0zI8gPq9B9o6W42mHfFzJmkzFKeT7lmwd3bhdMi0kj420YXX5ilrB2syoaocEbvLZYTwzn6PJFUbNlMZROnLIB3a42cqfKLSVeCqK9iDS3oFXTZu1qyxWvmxsYrnqFDO0Gxk54oF08PKiDcP63NnI4FAR7VT2eMlfUNDUYRVKYJ5sg5Zi7DxShaw6veNHS8MJGIfym04ZZJ0QkV01uFC1j41Ty1nwInAkuUdtEzUqzlblUtXO2cCTEGYVK0bHLs5Teu0ek7oQmJVzEU56hDZPDWA4DLWWilk294eBSjDmaQwNHyDUKFyJnEvbpaCquTEe1XSuJV2fTrq5v9Xptr5RJ90iRj0x9XqzNpPpfJqymiuf4zSXsO1lUyWKzq6gazeIIG0PVWPm1pcuv168J20HjXlvV8q2gk94DT5PUVu4yN2GcEUry945EZepmZxDwmpigcgHtWEgr0ZWePxS2cjtWvelXD2EbwfpNAO36dHmc9hSRdbznFjVgRxiU7RUdGaa5qpOKLNtImQWZa2tbEdZpDynYhqn1J0QbpRFd1pBdViQFwYqACg7cWGVbpHbhg3IcqWY92PDTxtqNJ3t8lUrlFctFbKMdfB1p6govoBKohsukYhUYXuoZgdGQV7MtF2oQjJOWZ3EN7E86UGv8ZhofCfqvF0azoGgWDR2awjEo7BoG46BEMScW8mfgNoxWaHRbE1r4EfcaoZrn05cOFPSPOTgz7jxgofcdOERFYrxEmgL9WtEuLEN1SR7SD0BMJIDjr7nimFCjRxFB2I4um3HI9lp73tM12PLDFfByKXwq6O96cyjJeBOTaQ67ZqgztUOBlwmyNdSd0JstUABRL9Qr5AbNkgErofPjZaICUvkF3Z4vJw2KJWXqBbA1a5g4mB2DRZL5HjQQTs8VZChyB6d4aqKxfxOh4lEXSFnWcbneLyhCdLk3nYcKEAYxcIaJr97d2cAq2BZxzhNEsk7g3lsoTQ5kkwx3XAASNwK6Cce410VikrnXsRpLxJY6ZUHAsNiUbWrQ2S5fedojU5y2Dcna0LCYpVd2btojsof7pDMYH84fCDzFiIe9kxw85iPGd5RJqspSweQJUE11MoSAjlwL98p03V69IBpIExzWHMxkTdiXezYI3atAdyehJMsrmvGBuIAUm93SZBctEI9NoliuzAgegXmTaAR0aYs2OwXoSX5mUpAT2ntktHi1V6oTPNQZb3QV2ATePx9LFX2Acwn9KjE30fk1r7rY3gyUKwJT7tK64n2ynGCTphZgXiawdZdlocjw1bOKfYDPQ6rC5u3pyynTXkwFcrU9HveCF1xJ6CKwr5GqgGKOtUD0qj7WONbGxmBhdIOh5doEvaemJEDXdcRafhjvaCYyNWzjyBFT18Dw8yiEYSsNzdKGKTXceIktCWXb6ATvbrAEnuPQmY9rcXWOFJUKmrxJig922r2JaUB0jufUMTeJ89nM1HyAmLETFslyKCGfsUQqxQLgLkNmNgshZybSGjIRH5dbwAIfCRPPA1BhunQlIWCmLAhu6W2P2Bjc72EgqBu4IhyLsOfTaK8TlxilhvPVDkIxoLXysuTDpgUO4pehRb9dSWKPrqc78Mtl1H5rl9Wi9wojlYr9NULc4jBqNimdd12V3fP78SlyhVWayKZewpyFi6ZcGcZnntcc7kdQFRMV2T1I3sMKghZ8mgkga8VQP4NNNIc3M7JZ1Yxxh1Nr3HhYgL0e0zRc1JIu8KnOoacmUcZbUbA78tJGzzXxzALbl9hqEf5xJWlTRdMO0W0EtUBBDy6adRJqzuFozdlCTOn8QcTHCQxDrXW07nHaKB8vWe4iBrGbzgmwN4XeVEfWT6gVmffvjzwafiM1MChlk2xcG5HU5leVpGMx6XgchQIT05HHganqgLLzSWKTu6A642S435JrmQbOiTLCc2FghTco3P0Z3FqUHQtGLkIMQymtzM0xHvQZ8Cn1OLMheozhmriHtDR3gZBUfSyZu1jbTsJZ2Z2n3XCaL4E1dmKgrj6C5LNuhnAfK0cF3iJrj02SPCm9GvBkSJEtFctmkwO3tf8eyGQXdCzyFDvbJ6yb1vkh4ngLVUVWw0tnldNlnEHBTiifrbpkoIVC48K0RckHYRjse7XfX88LFAKXrdkAaZk4pENMp7HJqnigtVkhKMs5k9kzKMN6cNn8S3BVCCbXfRKIQHo6okRJNKdacPKb7NUwHLFrT6NDuBzTbbkUV8cPZYSEd8Pj7zeoh9bz8zmWp5JuL8dlmBvZwBpvcTSVavwQbZ4vz1zA0LXcxIo6iB9gy0rDcP5OXuvsPBNim7b3Ulf98VsWpoTwaK2c947dGwp9vwAFWKvKRQAkKr2Jt19pbLpmtkez0B3B1KuSgnI7v34GlnFohuvxV44aqz5aSxSKqvaoH5DnDEUMfCmhhU7y4Gq414nvgVlUtsM0LehzProJ5XG2qj4P05KMhJY1x4KLg1A7m277J2OpmGYw8LlyfexCaohv5VBaL4woOUTfgDYttK1RJmHQzMjc0C7yTCRFb96E7cAi53KQtEHIQ8fm59uBIRyunexa0TZjt06eX6VtsklOSAvTAOHTR52OQIUlAVmMLqUxFeNpKNbCxItaVwd2LH5LJ4nSYAjC91cxqIqOFeHbPZX5AcISm9f4q3ZZ7acYOmbwpJyhqreZpdCL5wwBwTwe4w9pVgflTsBAd4IAOngjFyxEyEYJQw6flj1UKZRt2dCAVLQhgvpdAnGmQ0V7BKeuztD0XjaRR2F0WT8ymXYPyAeXmt6TX7HCZBSREoqWF4Fi4LAXKK4jFDJHRZxHInhowhCLaSQvH1jwSNGd8x24I6RHjGpU9t3TvOG74f2FgkSWIPxS84HwHGqJQRQFsND2mJelnyhPUQXJePdlw8ggpdTzS6lknBgyXuvL0alHNtr317Ntd8w7xbetXvE2RuYRJ8PbAvW6kUKOZUwI3es0dZQuBECb5Si0jmFPqKgLyam0PIcNVt32tlJYB0krX5I6oPOVvM3v7aSraEKukODhzsrKlMVZrSe5cd9kMiflpknXPIVdaKFwa2ZF49gxWn44VxvufAAJUCSbZotkkfXL1FtGTJWuGQOQ42DtzCiyeuHPfVm78oGKKdCo8xUjE68iaI8XBGAFzxFZlFifmOemLmAPIUDFJfcpZA7iM5mXCl1pZ0fYa1apm13OxI4BM1k8HirBIP3vIE21xSmJGi1oCw7RJZQpcsSqbZhgToBjNHw2VZWt22QaCaNOOeiUO1Cn8jMhz5myRRP0x4fjBokzExF9aPyeSLc26IqguS1DY1WVNq2YeokbbPMRLYL3sRlos4kVld0nMES1I9qCOq3jX9pcuJvvqxLeBKytIbsFvWqIWrLclpoXkX0kwcpSSN9jzLPsOuqGaZJ13M2FpKghll0gGTFv2d3J54Z0FKuaV8YYaiboU2mnKD0lmZsyoQwP5TjvhgwS5yyb5EroVghVazmN4bV7Vx2QXF8X5iyN1yXQyWo3Z2cbfYGlXPl7JNZTB6zZnk22RHFVPohwB1WQV9UO1w5Ba6NDF99dS2GYIL35GjqwQMJWZSI9zAmlAOHQFLltJ1QFFV1AzVtag5IXcBZh8WPi0zARWkaza0tGc4E4DRcxPNHJKe8hodNwpzepIkHhF4o2n0mrW37TNhLGzVLQiRXz5jxJUPLt6RzcjJczaFiBT30r8DH2AR8Zb0ykHX5AkibRxmOuf65UiGzg5tPC5gzvl9YR7sCoBsvehZ75W39Ft3rJYu9XBTbvRmBWbAG9C319LE4sSXIJMWdiIiqRB7pHMtqOsBxvaxqhG76c7ZHVPQWjSPUSsKPT9u0igpMImQwTlucg2SK1AUvyAb1BWayRyI74L6fBRGJnODjzFNFGTw9i09H26EqGhk8Mwl5asCfOkq2BUMJBm3THPyTyWPgon5TjShJTnRKY23kOUzQlqI6R6pfO60W4kh1NhCvIE722cjCe1FHFHFRGRAC0p4dD0qavTHetkPdw6m8jahBjM51umzUvuVG6gKXOn2EsqSnAVgo3SNOy85q6xgvc6Agufzc1cUMae3EnskPYtiur5KjOJteqJAK5bu7a7MHNa6IFt3tpr7rFGhYs9ZryzdJ82wOgqXGdetzBNt5Q8lJ3V6oCxft5tls5gFD7Phsvb2FNBfwvTwU4cf1gbJg4OBI0sLyjnt4AWGi7Li2cags0HTGiXd23RbiCrgbGV05aRxsmZ9yrspDywJzNypZjqzPUR2GJ6CBsYTSk24epESlNneSTzz8ZNj62bQbYgK9I2HMYLWTERp9ORncQcWrJFZXXHk39nJhetbtQkemISUigVO4r1e5atX7d7ymPCOiL9JKB48aXsyWbEvh1TzVGtFwnWDBF7b0T445GCLA9frQqyhqkPIPvhdtdazYTJiMnyep5WsdvNDHcZcARRj6ueDuKMh2cZg2glnZvI1EvXKxtfkwQDuNWhxWhwDfFFfHIBuRlNPwbazdcnN0ab481UXYWqb8U4DTLlXXeEbgZ83dle04xKEBLKwv7Vx4XkALEmcXPPxm9DVvLz0909PEw62sRiPJYSverLPHRrIvIZtvSdkbcQjfZUB0dLMvdYD9qpN1x01fITztzKottDn1LsM2TsjkkN9v3bhxXw1D4i1tZObpdthzghM9mQO2OK3jynSC0jkpvCK1CVoKU3czIGb2lbnVo3IIFPujLFLSAPJVtCXs6FeiFN6q4PiRsnB5lcEgME318wl3JODIcfbfI7sSgV7GgogHaL9mGPMzxZehFm3TMnu8gTWlnK7At84GisJ9cPXSoQKB00NCkE90nNNWeQIAdKm3zzYsxF1m1ov4mAW5QDOr9FhrqnvJ9XmY1zgZ2pACM6buwefUpKdBxCUV0aMD0aPcrKFJ2DbjUGbOGIyTfx1bBTPmqPnZGDqz122IaSNWZK6awMu2uzMPOyD9XGsVwgWiFiIaWPSSedM3qLqCsGg8veLeZDlXTJj0DZfBVMljpCF5Efn8b8SCcz2iiOwCcGtITl0pCJ51gT9ptbLdSvEjEgS4elbkAV6Y4o6mk7K9hKEcpUpM2N7hG2gplYpEQtJ0YZeIULN7tgJw9YkA36BiVlO2M3Bi1Si9Uyc9w1dUWDkvYCErs07VuPRwHCDklpvELO03HA5UtR7HDG2SyRk6EJOkotNC1rFaEvQgertCKJ3gyKK4lvbS04ZlzKgKkAruaFd1WcgWF2UuAozGWAStIWM4Mi3wBMiMtBV6UnHHDEQ9dy0EtSzvvIzHqvEyIozEO088CfE8MTs2P66H5yVB6oGYHBMJ07ktnoTzvRaOc7a2ezantsKDh7Bg77GpdFDsujgyllltRfah14IHYeooJiWbaSHZfLTeK4fH8QEvBCjkYwrKyHi9QZdh6OjVi8dJB3pLQKiX2W9MtvHbCG6ASy0tDVE6D8Qia0sD7sAgc3SZ7fJHAv08IgtFk7SY8OFGSwWR2TpMIq5IdagqaOCEHq8GRfS0smoM06iN5TZXuKCdv3mi8jyKr9d9kAw9HKsoVsct5BzK8htGLlEYqppqkpyNResxxqy8dogD5T8WnZpXgl9SpjQuSuMHqz5xbK6LJ16TtPY2AwEkqiye5HFKuJ06KUzMl694BdPRsGH2XbMb9cN5kLe1n7krHrYeKRiu7eIf9nwFvtL60pDnKYXGNoztB0PVo9PAprw53u1DkcGH5rvrJLMR0U51YFyv8TPrN5VmlOGOfcr4Z17uAmwXsHtWWKxOFmr8mYeUS6d3iKYrW0ABHRWxobqdZjhdN8PjQci6fWOW86karZDCK8TZxgDzqwyLj8GEZWrmmJ11oKdDPiIttqZetnoPhqgSOjpEvinPELKTWgRo0HaN4Sk6CskncSpHDTen6rKNS9kZCox5HyCLlSAjjy4CWLeF7gsg1gemkCWCr6PPXfbulcCkOgACQOjqLzILQTWxl59XqQ7QPSv5OnbJQslTSgWVzjUdJK1W5RkNnMq1kcsq4XOBEDGCHPiEmwzcO7JYHPjxZaK1zPCbdi3gsgSHpqxzr1EjR3rRrSAL82Z6p6Kd93aS1THCORpqz2YLnMurLFl2fovUeO6PhrhjKULM5ARmZjJfe01KWyRE0xLvvLmIzSmRoELQsetRH6Xcb18vAzGOeJ9IPcDAFoGb4SDDUjDSQj2hnhreybOMQoDmY5QwPscll6NCAo4Xvo5JZ0mum62f05OJXCwUfBkcC0DuZhuW1gMBUhQdGVfjWNOhOBtHqJymZvEmA0zsf6TgywDPYt55VyMHv8uTgCSXvGDqZE0BSDpVSlnTdenDdi6yvLOddVMwPGvAxM3GS9DfkOVddfGkm7mqdxvyRADr9h0lEGqFYKU0LyVolsPJEgmMrD47YV1FwJFRqIsqRL3jjMT2499ZpaCjY2wdHhqawJJ6ntlLWSSWZMUWDVqrPrdHToevWwrFb2Y6Hh3D80qeBnAKiHE48TAxf1KiQjyEYaReNrUUp8QtWV3YIAqPHTHR9tcDa9vrKPxmNjJ7wUq4haUSmuDykmNh6bRfJ3xkdBnCFDmfENYmxnFSznULzohMSuvkC4yl9ATLaahEsf7W8ZC0M5kDr7U4qHSDj1EEgUzmzFNmFJVvfWLYGsfohfakC3wKdkS7NSjkYYALRTGe047sKKCIPBjGOgMiiTgUjlqs0t21XeqIVOpuO0OCs8fWoWb1mZQ5w2kr9ZFc6pXkyUU3Taxi8kF2uvGg0uTvE750N88AzylpQS6I4lcp1lRKE4ntBa95xc2w4ZA7NeuMf7ilvkckewDILSvWd14lKFqcni5NgleG2qFN3ZJiJkEXUwBw71Z4SVqaMZ9qxPdQoPFyo4oQ7WazDoaVtQOWF1i4r5U8I3XDAMC5c4ilxZJ16imFEFD3ZKtzMcqcPcwJNJmgraxueWqFAozNCSOe3Mq7fl4UY5CZrlne1hiABhNZRydMIjOpfD1TlDAVTo6SHpoF1VSqeL6u88gRnUhRShZAOiARNNtvXbkPDOpz6iKOGNfx3ONG98Jw92LPaWb21574MT4CfqVyXvXm6OnE8AwOZBRjhv7iREu2vd06RXDnozurXCHH8UY4PaArZmXxwHkDxSZG2gndxiXucD3pCallCWjlwis6E8y7pm0KX2LOuuu2bzmkZreK0RWDbjXyNFOujJavW73QiewPE6SEkEhEEd7pYUpQ1M6m8ZvjtpvBGuICbZB2SHUakc9pRUWLEyYZbIo9MtxX8uLFGa6Ws7xNQDWZzl5mVK5tFpsNXGdGHmsHPyzBaS1eH3inrF9SpWNhn9MmPIxYgQTePuMzxYbFSi9fZzupQqg3pg35xngRuEiXcCGAAPeLzc0dUgBqvDdQU4JTZo3IYlq7Ku9hrjwQvEcp9Avv3G8H8d2f8TxIl2UZ5qlU5GiXWBaXfWDJw1l4lJp0VYPzPKlgzpH2ymLM5ho4PbTYVIzeJCDHwmWaZ9IndHvy0RNo8uVeiVfZj9KyehznkKhhUplXrWHmmvxpgScwshAmSR6INiY3meNXvRR5307m9re08wFVOT1qAtseYYQeemBqtz3oZxT6J1HxctKZ1VjHx90k2MjxCnHtyOhmKFcm2ikDMFC7cjLwHzeEqsul2pTKxPHVqz98YDB5fYhKW1DGp7WI4LHxCFCdpKgeCb62OAewEhzuVdwOVkrqpo4ztHOWJqgtZ91c1xzHhFwDs0BxrlUomZ5OP5WXmTVZiKyilTzZlSM5ZYOwLqCqkAnHCowegTHx4yxroF3fTeMIQyY4i0jhkKHboauX8nmxVfj0tP143ZCA13oK6DOaFSQaHAiUKuWKuPAng0QZsumL8TCrWJcDqK4rOVIXudjohESXTo00yqlwm1BHr5Dz10QkBPRKOkvEcYGcdsiGslVsFWG5SnRqV3DOQY0SEjUrhzusSLnXpxLRIUJbyUg6dINoRsv314IilYlCb7SWIddKgNLGr2C8EFNviIIOZlzwiMPI8je5rplPhWbqOrOydhyUwp3TxgwIXsyJAzP3TLGVyeEW5YqfEhs755yPSgphvTNzqzGwGAogSFQrcuLl0RWyHq68EtAl3eoa4yJNKX7LOOlIHzNIeDrgMSVvOeGUYhtCjBBABO5EvHVtljk8mcSv22U3RU83YZE3OltwXtkrEelQmLXdd3NHQZ7863qWSeZtoyLqJnr8SNjkiLInteOfcrO2eqtnEcViS0uNBKJJLIfaFSXlvG33TBK3kryNo6fRL4lWFjiyUD6LtAWXHy7qC51tRIealSGiadp0RNEhCvrkfpGKYekGcZbyn5mTBNVqHKsqnOXM9dxHlud6Ly4zsksG16OzrhB7NJHuc4nRkAhGyWLfsha6omKYklWBgu1rJOffadvoxuR2FvHqW6th7qON13ZUCoOpBCEbRqvR09biRbxPwpEqpE9RTrctT7ihcaF311VrgSG1hLj3DBPqaodJ6qAfM03qmozpaiYCOHJTzZU5k7RGbfEsReiRZUinS0qmU90Jgfh5etU3pFjz0UcG5V62SEtQEPpgKuqEmFbAy0fHBjlCwt74bKNnjmAnasd8WV2uM5lNZdqDDQYJKMUM83cVY1MGBFYooRuzXEAWuolj2NZb8Kky2hDtnitt91Hlm0Q9sgf7sJkHNs1OIt4QMR9casnkIXXA4IiUnQYbzLHtBGIRDSQKLNay2sBTftNqdKpJ2akuEWD7BVLm3HyAixL40zoDf4OP3mdHJrm😃'); +~~ROW COUNT: 1~~ + +INSERT INTO VARCHAR_dt values (NULL, NULL); +~~ROW COUNT: 1~~ + +prepst#!#INSERT INTO VARCHAR_dt values(?, ?)#!#varchar|-|a|-|hello#!#nvarchar|-|b|-|hello😃 +~~ROW COUNT: 1~~ + + +#checking with string of length > 65535 via prep-exec +prepst#!#exec#!#varchar|-|a|-|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#!#nvarchar|-|b|-|5E3yMLSKs9f2gi7D5YnzWssgaxFjWPxx8aCS3F2rRGrtOX4AYNVGag0LuBXt5j8nEnxPVijkhpFY5OuPRSexMgZC83b8eVx1v0637CSetIMBFab7xz3bBKx41ELPBGSstz7kba5DajWRItW7Isk9QM7X0H4MNAIa49eR25U7qLUY7gm0j8sh5iKIvxW58bTVzMGM7Nz912oOQhgM5yMVEFbdnDKVqPNlnnBZJJVmzZ6u7RkHsoOwUDNprObG8ggQHsn0KLSg2YQZ8sDApFFvDJtDsNsisAYQWk07apBelFSRSUUsH1Dcj2jda06x6RWgaQO4137Ot9ysMn8zwnRjKY4JCB5l6Xq4olVZgzkoIat31B8d90HZJNr0ff0UMMRjF0bMvl32bsnGNwMG9bCKn3FhHCD6daOsZyjDUtk40Mui9DTsJeLmRoLkLLOnwL1L8EBeeR9G0TYPKawja0o8FMZCSmk5gJVbVTFzhfl72JDJikey4wJbrZUpMQZSkiw4O4QLVbR01AsdtxQmJVnl9BbMcj4KbhwPj00uALRY817aQTIfG3GyYfyJFuDNtVrynt4cMv1mu1p9qoM2u4fBo4bce1k5qATYbPKe0QPNfJm51ePbNTwZUOzRhJWBxHQz5Yc7u1YejKV3X0OON4gnVfamM5zVJWBgDVyUGm4Qlrux7KwjgkvK1gv9PiofjVX3BCFj8JrlFUYBms3OXQhhpbjUSftHrukQAeqXPbm9D68RR0DutD62WJuT7BOGaljWodv5LYfnSCwxZFNT65XQtuCzqgAL0n13wh0bl2yXNHe8JPMb8LxYn8Yua3KVs4pCEy7YrHwXmQjASOw9PVZwBtIGkfNYCW9ronmZS5v7blETt2XHbLDLSUqUSP7nhf32tMP8qnVM8zTy5XVz2zfyI9Jy58ctMWNlTW1uI9w9CCfCv8n22L7xZJq6WGfUebTIxsNi7PGiHGmCOLmuiYlLsEdBV4zFztmqtfRQwzNj8xLMx6uHpitRx2O3Pjctx5GaXdXJKtK2FNDxcxhnHoQruMBcM6dERui4dpYK0pLTXzSaash9DfaaOQDtyYxDuZoGwGpvVAwuEPHTn4b58Dg9Dh18DKhLOA0U6XDbgc14gT0V1kUlax1UMrtPdsesVUTM8TuHUVnUd5vBXO00mW9y6ILNDt6LafnZHVGLWt3QBKRMrPsyWJ3QiUy6PErrI3BRX8GC1UluMU1wpAKhcbYlG4ReTYhusIAjVATpWFMiQMI7MDg8MR24wGwUVmzlaJfl2E3puiWNRDAoLB5pAE7DJ7HISSfTZctDqXiJLt19BC5XVfDMkociSe28ypSQbYVsJNXRKQkCiYycptDKEUcKsI0q5YIThi7ED1ZZshRXe3gdkHixsRjsCroanaIfVh3BKdfIaVTCyECFrnlRc9Thg0svgajZ2UhDE5l90spJY3kRiP7vK5pJWDKo5CLEvRn232fnxqeGF6Ouh4X1sR4tBET9W5BUx3bT4NALnxzoZXHyNm41uQSwCxAWawLDE2nta8TxvbnFJFwccTV0T0SM6swBE2NigSWyZpALUnAh9wrFKl5s5npGv0IGOmeKyqgoMAf0b7OBaMqBATwB3675iFlMt3FkvetTbUuCLzHt9Vc3QJ5H7102kJVKy7vtPlU3kuNPItxUA9I85n3K62FDe0dGxleTWmztsw0jJPOKLluHOv9z4S916Ab0Qk6nR62KdOqtUlmj0L962n2Tg6yDo0bchTjjTSLnike0yDOLfcsFAuPafKpBludIs9rcloWaj9Yz2KeOefrOxbtEfC7rkkMXtyGJFZXO8KUg1m09xNUU2uVXQVyyGoRZMzxKEZHudfaeXxx9z9WvS20lwRwysuy0YnG0CMuQQuOydGtenSmdKhilD3m1VOIpkx8uPYswR2CC0Q4z9gA3RGiu2GPpU8nUAQw3QNzjepxXL1EDqiHk6505ya1obb9hzZ8RdAE1TkYSkOr96tU5AF44vURcYzbr14mhk9ccj8T17dNF8nlYMRvPXXU4uqfKXatQ2CTGM1s7drYhuEauUj4CE4c1zRscjQACspwvJG8BXugLrz8OFxlW7ghvWWs0GWC6r6N8E6gbQrnqp86YzIWLA1uEcOUHnAeqAv3vX3YS2BjXFgfWOHFhRjUHaAA9Lt8kC1l7Zo9NZILe4MNPyJ3qdpUxWvz1WqZ0JxxTLqpWoxQyyWWhPXSsZ4JNRxQ7SDbSThk9dheuri5APDtUdnTAUxuvixhAb8Hjy48CuFL504UWU40UWHLtCYqZlJADx3p7IPcoX4O9cDI9jdtO1dOQsHe3UB9JvyqTkAoiohH2K7KdpRdefJfSr5vt14QVdThnllrZWp7OQviutTouO9gXZWv1BmNVgprxbjJyBVcyKQYilIk1ejHqwWd41zq0fOkqkd6AwRMSb6htusEqzeGWBfhoJQRJ0UY2xa6GDmOgl8sOBhSFkeLY1cYfvFadVaOVoRNQtT1ekxpFQmXLYqcjKcKdOQB5FfRzzXJPBA8aFmiJh7PeZOhUFOGQH60tFBXYwLW2H6kyVh7ZZiLUdgAdN8uhU1OaH9mgPPEBSEhXCqRhj7TUJiZ90dJohv1FqWPTC9rc2yxPYrEsvmOAfA4f0wVVc1uny7jQ7K0At15uqkf0LjdX5TLDujz2MRPR8pZZh2G3eItksoixsyr4fgHTXH8RghRvDqRkTKzWWbjtl44c3PPYjRoKxZr48FgGXiMbsgMGuJqUCg7i4WS6zQlA3SDMUwAstISaZwsTO761RsvDAHHOfLY4z69xfajTTNEYprrkqh000Ce3CuJvL4890nGj9XtZBKWfqTMUe6D5FYUykJRFvKdLPbeWsGI4eQvZJuL22b6qJHhs6kkk7nItAnmiZtE1P5Q8020JupoxMdJHxFryvUKrxhaEduBS1qAIVhLgBgadwM6G2tSYwZZHRbPmKmPCWNIU3KEg3BO6TvoXFAWuieTr7C9GmZ2aW5FMOmNBjR0qDM135InITOsnPfPQodmUWlyklAmesWy2AA5S9sqmEXoIQbnsDNHPNhWC6rRaqxYzYfsW9TVWMFLKkYA5Rn7DaJkk7gA7LtPDyTHD5DbtJ2VyCPC1aTLUdpD1jIrksUw7XNgVkdZAlu31BHQVH8lQgHGrJYgRwhmxQMYEbaqhAwICRADGcSqBoFR6L83ZgpbRI3NVYzNndH0WKZ01txEwcNlurSJSICMkU363i15J1bMT7LCpRhgNqfaJCHygIXnCmHlKg81hgmVEFfeYQA2nslRFqz9o1fB09gjQgFug68taSbZxYAWZNz0pCiGEEdW1nyHkcy5dMzf8rAOQrZme49KBgdyDvVnbO9Dcj0ncfipvnUYaNMMtFBWHePJ1QK28lYTXEaHhFrzboEbfkUIgdv3dnv8MLo93I1PENotOcERvM9DGxkia36prCxwrwCJCCVHjzVuFQgjeWvBQskSkPv42t8bofztrOg6vmiYL6zpxXGlztwKnJmc0Cyl6bb8C6CvCYQuITcrBT0prPckU6EBTI4CDPur1MmgcJXeuH15CNbByWmGRZnA11OaY38mUqyuDbelDMUjrslu0GLT1ECC0QuPo91jkvsSpaCLglC3D8IqqN5rJu2IDv3DZyfpT0Q4hoNCPnhvtJC9wbgxq4irSqd183o5dvWrHdQHDrvB8Knku2zLlceG6ygCOdKQ0mzNGzmPRuO790R0YjsCiEx5CDWI2QbeunE5t9XZFH0jlpsYxqYS8FEBvI2KjYsOYThJptgSRm4SiwQvx9Zb7w3IMkxIlaXay568rGiZ67l8JRsSkGDFrjFXVbMtbdMzEDLENr9nah60PXs6iuP2iLBM5nNVhxkRGXOhsSEOZtDbyTMffG7TcyiA8qtTTHspG2gLtncI3OsdrRLNy6VDGv2ARdbZkbs4F3Ta3hF8c9p5HbkbU59xiTJ5yFtpfzpjd4zKjZ6HtZvyRahNzpNAfcEE4mLTcdsjjB5VbrWwu0HOuLZBaAY8wGJwUYnFi18L8CxzyOmvekMbxWpuk9939m8qO55rqFmkPicjxJkhq6efpCWMBKVBHJHfCSYtXUsZNcmNJqgxhDfk2vTgEWiIAT9s8WwbMnC5gczGHtoemnXtNSCrACM4Ijd4qRIVGbDTH4GszZdQBUdzBSVELFZoi9kkl12dB6eUk7QMy5TTVXxu3BpGj4g2VmgATbEVm2SSpuYs5vouAibF0rF0aSWXtTEZaU14OEGYl8jtdOBWmfuV4JGDYdsG3YfJ44v2AqMQqmuKxFpwkXo0OABqi5wPyQbdiLqSNDuDdxcR7wNNa5drZCMAEOqodPTvILUVhOpdNHrp4hsZv3I0TOscqC49tZO2dvkVDJBdV3ZF0RiS4lrBm9Qxuv3jlO33W8OJobiKs3FzzPYBBKgtJFAAWddpJmGlgSemZEC18Fdj7RkH8sWWaY8szjigArZpAHLkXTyx4z4fcX9nkdZF6BXRLnjFV0Ok6EZtUu7tw8ezXWqT5eP6QtRAMBMOVcUNxyKH3ouUml7se57QpYoxfskteizphJTL1lPklI5biicfa9IOg9QYBF0FrYXgHt7j4LCybGx5Ac5kQSzSCnOZzZvESTsegMZ6xe1HIXfxHDYGMSqwFdrcS4djZimiz4CTu3BBQTLo5RxotYCx6eJGL4WDsYMkbvbdYDW2uG8OkLCADT0Q9ky5J04P7gyJjK0nMQodOlLsspQRr6TQEPog6ftyQxmf4gstEkhXEHKydeSbjTHyZRqnn56TLfeiePKuUYCQGhYt4qmWR6JPCHoKaZsDj6tIQRyUTovV0VW3P5WGqf4wMcSM9HvB28xR9DBW7sCgpDbZwawfyli2xMn9GMk4kFOqHMeSIt8KXvppTwsbBCGiJf7O15TVJOZVqtGp2qH7pnnQSNpEoKBumvQ65qNznvSHReNGlB18M5QU4312i3efeTul0NJKXHluCn9M70N9O0W6PtsthW9HD4ANLFcl9yZnsJjwuojcGoaNc9jjfj0TeQcYZvqWX4GE2RBPp5x1YEMU0koSOxDPVMSYFF74fOeY4JLSw6UccpNOEQSKZm5eg6pRlOLjrigZdZHgBeWHCfiTEJjj75AAB2Z9Sqx8yvYvfuycbDfaY66pZY59ihACOhEYwOd0MHgmqnNvYhCN7fojDWVtq2qyqDVU9xDeTQYZ3Djml07N1BeJrjmZm9Rh19C6pFuqDd7qbEOF8jiwJ3ipsPBoO0QwDTHZ3Yum2jIEk2hDR8iRahLyI3BXcDAYQ3hhjBhbpQccRSZCCxOaf3hgwRr20nx6cYKVvz7oYupKV3uToUx5bOm2NNwUZNhVkPMjGmDsPGLbdorUBlofiDow1Moa5a9KKaCo9Zce6G46s758geE8rCATwrFcb0oMg1g0slrORHpRLkYkTSCvpbl76CmCCtJugFcUlK8s6GN06lLhAxzh9Yox5NxwBpR48ctcBk2zdgXxydJeoHVMYT5QCTNyKygxtNfoU4mnjAQ6GDVmRLCEK4j7ToWGuGTrZmU4qbG3shvAvmNCffSX8qNHKq8yNIvVcj8g8njlq6RyMJyb2zB1XSp5thihvy2vMhYmcpKmsyb0XStGGa60Oa2uXfOKsDpSL2SAVC3AlSKj5xwiFlkYaYtA89250ugvfV0idCtGVq8YLaoSFSE1sd07ZIcLAFSDNLRGxLz3hRTLaiZrZ3IbroKgxrsCQNCK7WD6siLKp9CZJKgCH1UXBYwVH375N8IwpUctm2KO6yfCTbYBp1U60peUQmYKiSMMR3lt6tly81L2m5u5PfRMUDXgm0fCCXitxwmBdo0RSd0rDE3kDrsaUFaDOSqJojEhKIfre3GkPKS6Hm9Gmm2cWqByUUbfOcw6mtR40jCaH4WBe9nAiO7kpuP6U6YWP7LBpTeQ09YekwxRe99Upb7YaEjGcLEG4HtBtT8yN3HxJYaeqLAWh04JOE8sthbFi2YpeDfZ7baBOYyOghV5OASLsGi2l2L3gMVZeJKrBQOw7tsm9E6grhU1Pmc9uK3KApl0yOsoEXpZsUpucX0GKZvT7ibmyBzuh9CoGN4YI26KjLY3TeeePTfB7C9lLvi5cQ96Ksep4AOKE6mJBc5jGPm7W9VaoRUmGBhGa1d7kND0Z8Z0wFBGNzUxIMzSO3bNqFT9qlywwYc4f57Yo8NTXSNmeIuyrRvjGI1utGZtVs24srEMc6eCIDmW2bi3a94stKouhpu5IZvXUBDe1Oqqcq9MyJt7CyVbcrlVyGjElzoj1SDldPI37rooXXzZFpzuInM3oDYvdzisBGDK7htrT5cMMuRtkeSYcKW8RJ0vHgJzPDZXSqJvMW1DVoUawY0AzRgkuFAKQuqDhOjtBYltTlwLw1zqvX7It9pWHdmn7km0J55fXgw4OK5pZGCCFdNmdgtRUjLuRd2PBHkd9AOHF3MWFCToUJDAEWyClu6HPp8K8K693RynIlDc1HtqwAxqWmbkaGmyJOj4mAx1QA9ZDpMuX8672SOYxxNUUehbcLMk6G6dvn2eXxc9hWmUAXCyA4RmD21iDb9vpXHQRWFlkxiPMH9uwi3xNf4xhAe10qB3eP03NggzGmOEMZbK07g2dkWfUdXa3LVL2WWAds3vLaiMT1AgT0PXbKW0uM1F9dzOlnXq8ULafhOLyMoEP4oXimbNlF7se4e1ICNaftuzF486tq3FPGppQCZkhKhRwUzGxWnAZseWZSdYhH1w4Umjq4tT7ASgHSmBUNrZp1sn4vx5Cm4oVqIqkLeDphr1olertf9ReK1TJJpWXymBrqiQikqj3Ly7VbUhTbX6mUAU3vT2HGJEazQ1qDUgUVB0zjKG6DMDCaWB3G3rqAW9DY2hVxDNQOqXBXBnhCOIPWTz1nqS12AlYbABTNbH2ClYC8GExTxGTkry0ptpekpID2E5KhftkhXMkvRjVuuX8nftEjbETUGn0EZkRXWxe0ypkuh1wlrj7yp08ldxM8xHMYr4l2CASvBtkpxtMUAuG6nYoZieH7ZzjMwGIv4UdSimONCg42Em2Fp81FrMv5RA1wZSkN7areTRf9V2aeRyiPEJAvZb6Hiho0q5Vec2T2nh2XaMi4ZUtXXY7BBxjK8tu3cNmMHdwCunroHq1KtTv6BAqhTEZ6gTaIFSKiDbfaqYDYZ0VqFjVDKWzsJzRnV2ybbUBUHdaxrq1gNlV7Zk8KLWMmLCQwVtLgWitpD1M73n2d2HgytbpPF94tE1S21rOWGCtYAi5jTNXJb0ixm4jjoJl8V6mkWsi4OhLnt7dqYVL2YhTdRus5ljZ2vvzmxPs8rI8nS9oRCUKHdlK2JIzdRHwtsXjieioSRfL3gxgdnQDTvBti86B5e8RxuIFrNwByMrkl4m7x9ezW8yUAVn1w7aMyRNLW5xNVG9wR8bOEIoVZ6Rjy36EPtW2TWq4HCy0SNTS4nqjPHcs9RlE10lvqWaIfniQQ281nuFTDoyIPcrooSEjjWoKo5DZgsXIhzo1IvPUg4xyW1BqAEtN28TES50yoCnJoupExF5nKXuYlZ1bO4EAd9cik547unM9rKC3fgLZDbMgG8Puvign9J4hmF4zrZ63tc6y9obyz5gJDb5ilTbXsy8qJljaADvEh8SpxQEuejSxtm1HJoodEuO5ypGKUvxblJ91wyXmQfXHHdlu6fdZMfLrlyQOgRuvJeQagcMhDjUbzvylehuzO7KWhi46E84eezuOHAgrxBWgJ3Yo31iTHElezDsrlMtLP3PHUYtbaNgPwmQBWjlllL7lxs56Vjh7PrV1jRI0APn2uja8s0JJ8yGdNkXD2tbBu9FkhI9nEzQtenqCvFVjLU036W96w5jkAaJg0LvXYPorud3zkaauaVWJtn1iexwvoH4QuIu17TkLOjZKpAEyKtGzsbIfblArZpf0ipQ9KT9zNbfgLKxluARfWSm7xIuGHkiypwBwbf8u3s5HpHgRWKLg3RAK1IudnIoFTm7vE1GWpBQQXX3GcbA4kz2CNsC391zRSdepY3W6RqQTvAMry7KI8hNd7yWA7Yqd5NIX8ocqrqfkgYsG7hlJRY2jSMU1TngYStTLogZb7Arj1Arn4gUc8cgpE4iPlk8S031iLd74vXKgecAeve32zqUbMwY9Hg7FtksruC71CZYW0qF5YLP52RbXqDakmqyEFO9DRunWLMTZfd5Y1Oa0aJCAIJy7xXyPxTWdiJ0KXI92kG4ODIyzC7Fs8zQJPkJ4IZMVGkXXfW4qwMDPJB2KqO14Uz2uO563GWhUwO37FajqpyD5JmypzGIeDtk1MKzSRv0FOELi9a1NjsfXVOh9iABqIqizmOrb6n3pJLIQEdqbp1IMoie8pHYm2cLdvi20FgTpQvj1erPhqJNuFqFEN3WRXn3OH5ZGDsLaHqVhFeyAoH7cMIjDQzBJ87p6a0ArI1RqsfDZWG2nuW1wPwxRo2OB4veCPRA7crhgwY2rt89proY2s7Vd98tHEfM3b1txIR5TEVPL87EuTcg3aTlTJyVpllgOErMuiJriG2kwJW1t4rYTCKJMoRfwGSdyHXMiDKNSEywNAPmnr0As8P93Hz26UmtZzkeSkKthLG9oX8hRvrNc6CHbjlLRepymoTn40d7eKhywaPO8cLR9zxX9MYH9V7sQ4KwJQ6zMC5BpixRIRfDDMpAnmb1UhptmKeET37msT3pDe9w21N5cD4menLEm7kl97wFJnSbNZQmT3O5R06ypOAUivmzJReqexc5YaXauJEqBAaWCqzUKR2432mS2ZZz1IXXuMws5C4wUKR8WOoCdnE9r1Im7Wb3rfgbZZERbHTOb7fJqXon8lEneXLPIxAOb5RFEZw9L4NwfcumUjGYYRcvNegMNQLpFdJsUUyCX7bZNNxrFPhULnNBkocrEtMclzBWnJ4reHYsv8HIsB3AbYDWfSLxq7DyuTlk00uumsoX8k8cSKuvs4qOMzJYHmRZGputDzyqWj0SOR0psVObWFJhuYJcNeuWCTvOBt57kjbS7MBpyMuFEPKtp5UCMyAPRvlXKR5L6QxztoH6xx6lf8heKC7MK3MkD2OczXm8XL7lBBVJC3AgJ2fs6AHaafgVDsiGRb119sIXf3rjgZLBzVInquAhwqsEFQtAEDO0XOdT9kNycZWstTyCvCZ6cSvrJTK1uqoS3dqgHDyYjaAkaCofAYvtKIfUkpnAgxdHxMHhTGcFdILRiu2JRXGQujsddcIpw8nZEMavw1rB50yFENg2nqtyD9GYKZ4IkdaW8b6kxuirIlS9jksg1WLTPim3BrcMaxIpoqT1uzD8klHUCzXSh7OjUpj4GdLam2SWQTL6sOuicUqpeYmKG9hVSRcOl3YZAy5uPYB62MAmOhkhRsWnqDj7XQVPuJBxMePG28wqMffUzV2rUy9WRSokxC0QY2V1fHcWN6D85xFnP8cyvs0J6npg1L33fPtgD8Mmb19Ku5PtcrExmAAyyYtufC5vCyJVggneDLWjbFptDX51FOnhbhka3wJY0F9KhfeUC4rzGhZVqMLxgPB6CS7FzFwasec7PdtivSsCTpcbqIAISw6h0mjWHZmFtPIxgoJch3YVWdgpngWyVnkUaqKikzx0y2hZtgiOGHqokDZReFiGJGKZLnN0SkZcJKZC6O2u9twIJ8rdGhfsOQjsw8nPPIm7XGOVe26Pe537TazRNjovUQVAud78NppdFKm9T8CodeoscRbH26b1SiS01oDEQnEjdeTJYZUZSRM1t5lbQY7ZCKY2KpsEZTLcZr31CY6VCOr9Q9if4zvwsyf7K9BywidKAEq7dt0HyMgV484zTsurELSxBH0xymY8Y4CK9SfP7b86siTDLEijOABO9qiJa7JFgBZwbnW8ybl3IAEk5DxBoNfRf8Yf3We3PTjGiF5AWkOVaK7Cdc1QB62mxL0Tj7JzlpgEMn8dweO3NegQxBo1BwusM9f4rcvJB0iFun3JsnzQHvg1pLqTijx3vyWeraciOmQZfAqSXEihc2Nv5xRx6nDZiwLlwqUMnGYnvUwkMco5UPjJ81Gyzfp8imTI7yFClEqkRvXn4hsrRMO8EGxWkKCCCyFdas9IPu1ddQL3myW3oIlmwa0a50kdd1A2ORrqAeOjoJ7wYS2Orrm5xZkYoxLRCM6ySOcy2gi3Yv1UH8Ee5ZfXVgqxvWxfqh2CGBW4IYvUpWuFgPJchrdUJebpuu29q7xAEopSL4gRCOujyozS6UMWVHmbCvNq0VTaS4fufo6P9MP3IAMFf4PNWyRg7vP6Hd5NghcstkBFECHB4v7MMDiRuI6XdP8l4fVLbXXgLtYSDZEG1vp4mpXo51yCstXw1Mgit1eBI7o4M2Za289Y9zuf6pihQXTLNev90bZLuRyQVFFo24MVFsJHz9rT8o3LmuJayHbXvuwsBSycA9c2tGpYUU275FnhqRZkqHEdmImDyHwgNgl09JrxQFtzhyrRC3DDUvVglJDpLXX0Gie6qcl0yofpIJDHnb2UWHygVYan3TJoBbEnxiaJAHagmS6bFR2PqGNeQ8Ssz1ZchV2MevP6yDjZMo05SAGTMeexevU1ZXdiLRDrjXl8GJxh0kN3c7llIHBpeQq1US66bQTrjC0LPxC8RuWHIGvaWAxEiMzr4WeqO55IurKecfgzJoLZJbzrbz3wl16kBpjaXG4JQ1xjNYfYS7Mv7JK11QBvHxp5NU4glJQmREyo2PBUXCOMi5JtilSnZlJNpEjd1HGwfyLQgD611Sh9sLUwFaHog6FhRNEkujMBiwW9huKIwadCes1VsJBqOgb8oxFVhPVHjc6OckDgf5tKHhUUcIAjSkY5K72xAnAtAITNSwBM0P9zx84qsTu4dKJBvhwiUOrARF3aLhgjODPjwdzrMeEkY6kGS4AGWXCn0Qrrqn42dlbH9pJqUTaN6sKvF9mcCULPJZV3EPxyQ1wFeb5tlg2OTcYDPhMUjq4p5CRquekSWrkMG3rrHSmv4gnjNj8bF4dAOmuZRsBLzAjW4bNfYrUOjwfnMKMbnatuCGo7gLEMf7iJAIrSmFFuA0oanV1CZnGxpujSsMEwrABFNjKSV12NWGAcWPdoRj8iVeGrZOCHNAyWyPRVVGxSy7cQYdcXwooo8NvRSVICgRoeUuj0IWA5qDK95rdREoH89FO0CzPXHf5JgIuOdnBwRF4MFiIJcJJWUe52HhM7b9LLJFhumQGZaQZU2jGfON9dRzKLUYi8jXFtAR8llRwImYuIAjPSmL4QDTV5daMDbo1RB4cJJOat2pepq8TePA74pi4QsQo8OLPWL5IIsyWtZM2jgskftmoDn4iUVxA7IcHmvmWpLCXsh4CbUDIuj3ylQt0GslrB9BWydCsfg6YL7gKz0x8lfem5ieBF6c21nQeSocclP8GI8yVWqjzxGcagp0mdtjgMCSvDiCsx2z7p7w4U1p5PjiF95LKn0zMvDlqknc8gEFJ7FVIM9gQBye8tthUP81wzO7DJGR4CrT2WI0aGaE2CK6Qyx3ZJ2PVNp814CATp4xn7jzCHs3rvyDVSBsmC9PgJq8CZNVwI1xiJlK95poWmJSLWJ09kv4zN8heGTTRNUqVmrH2Bk5lnCdzP75iG5nJatK75utZscJrhAgvGpDpXWFAO65Kki8wSU39GHPqO7ueFMblj2bATM4ztwHRgfLNI469HB9hodHm6OhT5hti34Cd3Zguw5vjEnGComiLRqrWmjFFrCluPz5KodcNi5z0ldjCyqzOkYegJQtKabdXNG7zTqnwOtauzPFvYHAT9JhMJgpXXSoQyvSZYwiPUQyV1xsrUGiVsTKN7L0oBCga8XyqAoJeSJlPaXIcJwMzGNd1GobWg5Eeuobhu26er8wwZdHh1h6s1H38KnV8tRvVym3R58Xirjqpef3idxOYl966ec6OSdIGn5jwSEoEZr5UzRdcRJBPvJr0vTAncLWKVlhDIcxghQEJ2EKfij4OP3D2PoyqnRW263at0fKGgHYPJirnCmXOyyMwj4LFuJgH2tteJjNgO1hHNdjYHdDQJKMpzZBBsVcY9GQ1OwoPEg7rl2VaRitTnxhhpMxZWNRIzHL3Da9R3XXg4azaweDdwX2c9ULvSTiDYD3CR9SJ5OEVz5WlS0bPWEDdhP9iq4HPMzr5crkTlRMTVO0xrVwcMZx28QLJpseFr3Lb9tDN2P1cAbB0PclKxq3nOR3t0FLnRSkzCDXUo7U8Lyg0U2oPclQzymBVOvfOO1nvU3f6LdwNdxFhFMPCKUPU1Mf1cINYmJigDtqF2YbiFZXgYe7XTDxm3sDpS3DHGRVfoBEBM5KXbiUtqD5QvfIoPA9ocUhDYPlUTUJKrBUtoA2vREhPFY8GprO137EcxeLo3gZHDTLwONJWUjIwEqaa54SZEoQBr0dWN5LZ88xbmtVojDfjFnfVBS0BGdVLnlCkyrGgLqDnPdpyVmmQK3FTaExtZj3gfLHDNauKWWUQGpKUzqYbwQqQcRPekI8spswMdblVSrfvyfvmHOVULdmSeTKzwSCdhNVzZAgNvCSjft5ctjfLps4xkpNMKzh3uE1RAjW5coTDznofHxGiNFvUHa7lyNa9diFPdKHgJdBfLFGzRkisL4jGJpE56VCpG8nImLTTmOjWxHiifoNRV7mHURveXfMwjydIurqol8rn1a2PX2aR4VNB6kbQc7Zepdsj1iZJ8KbgGUkurnar7gtaVlQLEHaDPGhMkAjGh9uY0zMlrLTE380ATAKdK39mLorzH5woSTBmoGFyUCLkT9qWKt62l7yiQo2sFriCP1dGvzCUnYIan3dHkQXuKCm0Hv4PZsmRm9ofmV5AayMpajuIPrjT9Ow1wCqk6a9VtpmIhcL8ub3GmrMHDRvpOJqYQJxpUE10IVIra2Yi3D60Co94Yuj4SPw8BPKoh8esmdxZaz06IUy55jBR5WXA7CdQK3JXYguvRW1TCo8CDtvTCNUzGr19OPpFzU0CSlmOgmb1j9z6bSPdbab5soflPK4YFFwZf7nALuEak7lLyaJ471Js13vepnjq26lCfp78hfmfhq2EuoIRhM8m4TnrIcXiAGinjzaQWRxkIGN1juF12iDdBbRwdV4xrogM4TcK9ZwoUyQe7bcIMgAVoe5TpU0PNWVr1ju6dSmmqWVX2qz3XIxDlRqxrkmkU5QZIq3DgrtLfsfXWgPoAr5HAP0HK7SxqHps4Wxgoj9ob8Dw5U1O6mcpr8IUxrpO7vdi1OyyRPFTlIjCZ3dAsxZoEnFOp4b4GhKcMDFDxOggXiR4psIGhKDEvlvuTa23DaxLhSX1iCsgwCIOvNqK99Pf0Wgns6bR3Nlx3Z2OMEyGIrKGyHfcY8MZVn5txMzAYcqjV10HdJnlwzRsktRIJS5RuazhR8Kerq9M2iSIhMTO14wnafg6HjG8JfpawCU8w4u5G0E990AREBGXMSkcjb3JCB3IFYkZ0Z8z5jQB9td0qhHGdKSG7W0QMFd0ILovm2VE9HLGQEhqQ09Fun3KE33w55wn2taQUxhgSoQWewXGFZRQ1qwsZWsqQnTbxihK7NW8vZxsIA7VuM1KZAp2hhnEGx4XYW2p4p2IbMiSq3J4yL4BfFOoAQN4lsz0e9JE1kH4B5M40D2ZpDwBf1V499gv0FUdOeCVaxnaCPpJgXH98Y7g3Y5ugww84u3O77O3ppypHdCrIA097vwEQDGGot1s3zWYCmDce7GmQP5QkR3nDbe0lNK7E1IUjhWcKlzi4r4Eq04ggbn2C51vcO1fgIMx26mC8C51SyK1NCgFaWxBzEHtaoa622zQEA8t9xwXQPDyFajCwT2eEQf7kIvd7241xt46ofOCve8S14kmOVqAz2NWUq0l7UvirgwhEeBiuK9Tb7I3s9v4PAApDos7opGK9lurweeu7JP8zQr1seqmiS06JTCLPQgdi9cl5pplRz4GwhvGOTQZwOjv3zNQ59sqKBB1tVTaizgnvKetQSjSyhg05n4VBsOt0qJYR9jMYwDWRMTilCQJTtIOWDakDayCsoprr3Pf1oBs1WfHVsGFAJhuQaCqQhRGB6kmlHHTLQQhEQah1gNBk45dNzjU91RfTECkqPjO4HX8jhmSKSnQNdTNHg7bncE17QAKEJOSmcPgAR122nDyeDz50cjRXWpKzIKZX1WZtu79slIZinSDDmRSYMDaePx4f0CIoMntBgxwvHEE9zCp7zaC3LwVkzOqRTWVSuDtGG9CgqrZJe5rEeltv6dKNR6v51OSYXUDwPN6ZNysmrOxrB4LGcGFbRb0RpE0XKCJRomOZuLEqdqxKPlARSSg0TeATqEiCAcqX0Ni0RgXlgBQkebPSYaMjOYsfdMxsXWnSadEjFsYydotfzACyFEKte59PnO2BAMRntAFuATZCP6Vwf0Iv6GdpW00rwJFglM6Gb8z8qSIxOxnc2ypb5btzsBpzhNgPiJVI9VKyPlLSjpruGPprf3hdQM4olxQJc69YsrlvxWq2GHR9uN9DwN008Ow0T4K29tCE0QH4QEoPceQu4atJnAwS19Tg8In9a9LRTJXkIoNk9PYGGpNRCms0R8RQspmgKELIU3s6aa83rmFgGwj6TaFrfXbdaeRwpoLpvagg2k3RzzZnOkmtlkwLlo43jovZp4r0VOQn69eC3RdJoNeGChni1Crey1x0FPpVpoS5PbgL8x2cJ1tdaqmZMSMaAIfMf76C5tvn6B9WilZL11uVm999mUMcLk0MpeuvmMu0NNdf5T2kkw9jH2LtFGlhEZRpLXvgvpZ55rEsl6QMAIgxpuWGvlihIJMG7IN4RW9cWYnzlbCqZbRF6AQfyvveqzh8vfYK12dgK7Eg3lsSYCfTLeWdAwuvJe9u21WU0YcwKUxtaiVBLBHSA5NCfNYtjymvW51Dr8MRqBvvTWyLm1UeLKcOMVlqVCDLzfujgeisebYu3apfFgyGllxwHmB1yo6LtvcIQbHAUusxuzlKA4hWCujIeQIvfs9n8VovmUjWKAEabh7zB07rJsdh7sL6NCVIREjszPn5AkyvlljtRmtNikzJUgfjTkrAwrLkcp0eKD81ZQkD6vIayI07eGz0UIhENw0tfpmQXdzCcytCyw1oocrD5k3MqAAbu9MN3RGSdmFNTppeflGJ6VVqTG8Bg2Lq7fVwPOjHkPcF9EoBfU1xJWSV0c1arE4ZmtLw4CKU6AoocmHq1zycYEKBcykdLb0GwDOtTFvtaLkWDT9XlDk64P8j2k1gXJUEhBXDgZs7qjRjrpio379hURaeyK05m5VO3tcaca1kotstKZLILl5VDQCpUO9yF4OdpIRMyGhlKnt0Vqmhh55A6eyZEgTVlcjOYJ5m9YmUillyMaMMU7FThzFtSRIEzQwdAYT6e72ubmjpteeSQYdG5I8mnZ3jiYCo2byVhB8ewEV9Jr1WS1TSDh6zN6EaI0smaTq7R8FzjidRbzqtJcODrRvk4bbUC0LKELAVhjIqXghOZoNU40o0AzqcEzHf1mOd1FtZADecNoRMRhL61tD7StOrvqGcKSrRlPDsfFV6PNuaPVMUhFOA4DBkNcyvov3DHJH9oRjD4OBkQ7pnCZzfEGM7b9pVh2GqcUCI47XcpZO7T1jmv5hn07u13uE6Kx3bX91vtEOa0AH96l8G5ygNDW3oduPnYWlKNEK0LVtSFg0dnMDc4U4lZK0C73aB45e5ed110MnCqVNH2PDJR9P7be4c5BEO1yMztYFU6I2rP2ZxqUvTZstYrECjqhZWRpxMGEaxwR35FF2BY33bUy9dBgc4CnxZhPFQJus9gipRaU8T8d6JgHQyo3103Fj3qzrxUmfhVeUjuaqjwZ3CWDMfgwuqzrvYbnMT9RdFsDP6PUvdlwsUZfGKkDZ5YTTuBbJrhLeiDN0Ug6i9VGUGL5zwWLttTV0BHTGzmecHvN4ZPW3jD7eJLP4lEx6koNQNZXmnQDCKeies9Tf1OmOG9ulicLBJouDr0LGu7q9KoGcpJTxwoeHcoBGZ97PWmHzmRsx8vaWPWeceCsLM2VS6g2bTrmJinV9mU0jkXbcvhusKFZhSp20r49FKtLoD5Lx0Z0oYTvj4fhGO8zR4UkXkd5ZkA44ohOFOpNi1zZbwoCMgOMpFKL5uV1md9E6fRum2gbklJweya1bCjIqXaX028UYNakMHIAS3HFqFVQ4uDkTXnyEby7D11zegU8xdBYhd958KevZhvKunmKEYRcebnzn0rCyg4w8BzXR1qCzSLIZiPoMMJIptaELfdvPvM7FltBy34nb9RUXfoRyVGZfFbmCXuUx1mRE9KJjFPj97KBacYAn34ih4tCQYe3nxgB6XktxSs0xe489kyfHeSE0aUbDO2my4Ibj1tVdtQYGEpDlkJMsSsP2mToiMUwoP2T93lTgP3MovNO5zKwIzsSsbnGnOviyLQE7ERJVjQl5IwahlZ7bM4kXgmA17wWfB3rdE904AH56Z6K0RDa4uGzZpGIWHCzFBN6ZMTkKYqKFNWGTVqs6b5Cl0nGwnbCzW8ZmkyqDaCJkbBBea8o1WBfMg3xIXydWsC5pUZL0OxisrlMOPwvjMdox8f44mDlGaSEXTcXEZ6h3Gg1CkQmExyt8u7Ny70wQaWfplU0xH4VdVpAZ7D88gTkpAr2EADwD3Ooc787YvUJVKKiVpimq33HVNt3Mnf5Lmid9q2X0u3THbuw2MeRyCI3mmFRLyanz6GJrs0AS5NlZK82nQMTOJNdyC2XYPXo4ZwB86arUtnuqZQIrAkJHCtrJXYHxculjX4rYn8jhdLYyC79R4vqzrR5lufPCj1RKxr5rfa4e6L3lZhoq95btuYRiBLWfvfWVOjANoz2bZLn57e8KdSu593dC9eRcJMyyMM6Z2U497vombSdCBcb30m3yMlAKvtbCTZ4SXDh77K8bfj1zFTy4FocBHG5QgihrQQsTeiDzKS1Nk2fZIkBZM6YsTr0nSoi5OkSS0AzYlNnYGZsT5Rzf5Yy4b2C3ekrfGijVv9TblEO4WXnElKex6MZZu9QcO2p6iKFIs6b8MwuLcXG0tdLsO95dTow4FBYBZk5QUeNAjpHZtQLkWwAjr1n4VEQIjy2xPLqsZFRwaSMNlJnHFujA4XYSzBzzOq4mHtmTau1M7FHew82ZtX7PNmSM2r1iWA92bGpz5GnJt8ca0CBpX3GXz2XJfA6NJmKyOM1kma92WJMKLEpAEKHL8iGNJ8kY7H7mTXfqb7ZCEvhNVlKel8tPsw2DeoZrklSS3J4F1csM8Y7koaLEIhJoVCRVH2ZKs6qIPYqKmu6uPykxejg10EEBI4nCkgSslu4Pofl2jpEMEp8klnKEVjbnwQzLM8uWptU4ZmLvyC3BY5hbBDwjgWKcD5ulDudAgk5kJZrbMqLEij0zRCS7faTIZ3ENCZvorrZBT76mtKHIrSxQ5r0RbIstdfULJxK4CFY0yciQy2bR1yCGwYJPhc9gu4jVcMFmsBmWzj1sHLTaTsmI4g4KiTgVMzXAeQgTrQD5A6S8M35g9vF2yYnNv7Zcw3J5fldrSrbOaZsaDqfDmtV0Et3sVSHmJYBJ9GrUnqReTM1PCERK0lRLREYcPuAhLVFr8BBJd4cRcwvVKE6CwWGjmzCEUuuBrH9toyBERoXWJrmTVet08SWeTfjoXqk85X3k8xXk1uiWDYNTOBOQZrtjIC8LzycdRgJfQQbd1H5HhtBlI3HPPJgSf26exawf2k466pebvzhC6SAlDMySdG0D0zso1ug0SYpvZUPshbsKM2qpbFrRGVnYXtHHkjilCRm5sCM25bDIndKieSUwncPeQ7HZgZS1YYBKwL7iTth44ddTioqczH36LhLZgG7Du2oGF1fES6meCS1QzHylrspzIcjBgW3QoPjN2jjRvGbK7YKBXmWbGobL4RU5xrSjEekbQnzV6K6B3pUuUQiORtcZcE3FvBe9YCCsceJgcqQ1JFChSpM0BodQWm6z6xQux6tm6ip7pXnO6zbBLkq12S6y15arjFt4Flsj27OkGELDrt709cekDEfN5E7RxplZRyGFZDP5JN2fEJCxZalcCXs9SThfxXZjTYd6QTC6dFBFo7dWvND5Y10QEiWpElz5v9uGCfvEGNoKjVKNUo9m1xKvu6OvXmXYckOSEOj7MuF8YchL2nSRqVShaF3p3iW8COXY0UohLHEfJ0rzMN8vl7oelLAvIzoxARrO0xI59UyQnB92Y3SBufZjH1GJuJ0fBCLfX8MVQ268rdR524Sv8yY9wyGboi7Ex8OES55QC7lwK6tTCBbkssdxEYwSfadDyAwFCwRMDllzZPUD8MMb7Z4tcz2QswYG6jD5j1C9vGgBfU06ekKvepNT6LOb5gGBJ8onaYjp4CBJXncvUkCxmIzR9jZatyMTTK0KzNtmqyxeQAF4wX6dIfdG7YUaN6Cks3nX42ulx4JkR1HrYEsBmxd8yMgJagKOGeGs8y28qjDaHluICsge4YRHQvWA2regBq0fr9Mqx6j3NoUyKvpLTdU4KOxW7ru82YZDrZgjPAMttkeyckZdU7D9a7UyCGEcaTibziwVX0OdA943UA5x22M8TWIlG0HFllZG0A99XeSOIHovbYohfZN2EJjBiXjXUTotxYxzYhpMkc0cfdm4ABAdvxMIxGwqH0Xm50CxXA1EUZo2Nt1som0V4igH159RzXIwEGenM5NXtaymytUOSwgrFZlS4iyooDvswcTRFdRbGL3mUiazGpu1Irlxvd7NbU9G6bnEukoR8wFaw1VtfPqzhjzUNgad47RpyPDDPHdeCjkFzb8nXTwLmZuUl8HcDNNo4xLQSuIkz5nfdiYSprzOf0v6tZgyIxD3JoBLVFBk62E8ULPHWHMZ8ksFk7C7RuFq5veCLvLLMshnsTZsmZZ1aNPtEgj0aW7URlwJTmPuSPRMhv5MNepsUp9LgKPD58zbHapfxvDUJDf5t0u6kY838gNcWd3Ygdc5p9932AsRIpZb0UEg3QE9p9xojVdg3MSgqU6mDEX5ubxC9wefYXEqS6dmKbDloQYYCtU06GExKWE6jmceeI2IRmUfeTMpCHNGHG0Dww1GWzTtOyEYhI55vAfdu9d3rAVackUlTFvbBHW21cgvi3jBePYd9Wk5gNTyeN6NnopED07l8sR3pG2Nsq2IoAb1bU4vB6gkeYfQzPVmUtE0fRiivrEoUyRYTd8iP2XzI8YKNMUMz5OySETgrpK2U5NoiUb7f46K9um4EcAXqX2yvsE0wDvZQw9BDOAjHTXX1L7HrOUOnSwF7V2RuIP1TIbrFHC5ft7qs1xqpM5Nwy1jpse6Dzm3DVyl6a1CKTCDMCWyx5nCR8NXICylBom8Tt6d8wpMuXEJp2CnMQwFskFF39xiqg3WB1NdH4psU1i1B5r2x3viPqGIBdhhsI7A2YecJHqJgWG92g7EnWoSc7mH7haFLXv7Cf0CGFEr7OT9uXm5vBzHFOW1GNr4IYQC6yDsaNWhjEwxeHDOAO1GWT05RLL89XeukIDwoE1w5Jwbq7u0P2V9NFmdJ3MODlvBJzOQRyDOCpU4TOqPkD3wOX4jGDoSphdJkZXircJsjW72iR2SupVkMkAGZriyXYivyY1E9INV1TfphE2WDssdjzgA0rif0PAEICQ5tHjFRO02VQip8dyhw33HMypP7zC5hbEIC9zhQduVZuhSXuK69A8DzKjgOQ8D4cKFMi98B4bAV48CnjIh1t9PiPmHxt9gEDPr03Pbhfl4tRFFNUuA4TUyAadEohyDEg3jaCKSaemyX3HiQFHt251NM4y5TepkI8s4iyBmDejdHD52XeiZfS8KNLMKuk3yhzGmcl4OsXoXbv19n3DIUYVQw4WK92M4vYKxQvDemh3xnjlS1voMEWT2UfgCo29SLvFpgfcvVShpiKAm8uCf1eraUA29TDPV7ptFYBHoA0007U9uluT2NkxT9YqB7sKeoTy7WEwvlCOwqiiKzqnY1UdWGjFnxI2EJtHvUMibnoI7OGqLNUDN00RTe1jC3GmbDwUoOOp7YyJkGzcU2vmPUlBRakQgco1QcjBmUDIrxuqBuO2FB2WE8LPNty0FEJJgS2KysBwkpqMmDfOHSvVGDhGR52XXNk3F0vxEr5P1x8lBhfDjksEo1S6Qv5h86bj2PHMHL2s0eZlNUDU57cuY1GspHr5tDZWmpjXIHJeKhLKuWAj855ywte9MNxvl34lNmVwcDNv8DUe0jbPVbDRzIfV0Cjpg8aOcTIdBYFHWYMiurMxUpcsnO05IOWu5msv0ngy36axRVlOwa2Nwnwls04LHNU1BVjPOZ0BfPsMSEebqclDoAPeniSkpmoI1Vnx6T6j5TEGuYtb3FBGtPrrkaTzPAXrJiCLg6Ns1mdpGCS4vbSfx5zijijzMGni3zcCAqeU0AN0eyXD2OKa1B7T5Q9La7Syv6mv7slG5zL2aDIsbW6TI2FiAOulg4XIOQxYroMXpnHnzJNcg70n4lMcEMsjhgiOavBPsXmrfchIE4JnhE7PKmQLBgkJz1l07ZGN1sFcwaIUYJOTbHu7GVKZsaqCtMujQvd3BEjU1JZtidQXUzAQdLU9AHogiFNh1R0nlDUQjQ48itKSw4k5skgmQfXEAhoYSmkII7C3kuxLeCHSQLgm5SOw0vGZAsVi8vGHEIdLexwUDXbFimpsyEJVstzdPz5vp6kadk7Uvuujmvbyav45K8HBUyg6wUafxlPPAIHV7LWQC5zz0wMRdpb9j0BXfo6ShMi74vtjP0qPYmupwdiwPIxi0qxJt1qSjsEt42nAXtknGZ8nhWSQDQ9IQlxwb8tJzUM7jcwUL7E15NOyW9PXo6evLFxX9i1Nvr1nNEZBQ8vXsMxbDY8cqBWijEnFFUVikOlGfGOUET6ZzRnJkbEea4JcuGsAYj7rDXBBshAss49tDaIJnsgJLyhsY926oUaSRia9IFxnm1MznJ4EQLGvmqKvGnDeBamBIFzsn61xIk81px3rmL5cF36I2KbZDS8vhBTSSlFhI2rgWaoeeOwGKmffQMnpIvdLTuaMNoFxOxpq1MHCFp0v91WjrdLVOZVBGlZzIf7JR42YIOE1veQchE7cBwAFNvyVySBGV3hhQHr78NlnuCouMyq0Z4PDvrpK7OXxypX9r6iDaW9BudFrKllbxJD7VGbOtlcg5GN9USkfMOms8jmVa2IUV06KHwaDzpbsyfN5Nv6MTyUYtUQ61eowIRzB10BAEY6BfhqOSkdyOX1jUOqM4zpluuijsW8EykyGNneXMq2V0qnc35V5YuXMZAj1FOUJAXEemPFznrH21KrBG3HKxFgNx3sHWZ5ZT7RzYC9rEOduJJAcRSxzm9gmmILYinI1i6CgqGJWtq3P28sYG4oJk1Mwdjp8GMUVVsFTxIt2Oj0jJnGUkV5Lf6ohtcuiVM1cMrNzvUfLOXXTQFRm6BvXIrme6RXrK7J8tdFXPdDYBuCUFol6owkGvxEZ0YbblG5RLoyNO3Tg1oy4ppzVSKRan9ai5b5JMdLEE3L9LT4hQVkm5N5fmQfrVPvb7kiZiqRfiW6cynDvVhNJyl0ugGLL3KvMvMWFqCBJcuwhYyEpsdwBRQxTH1u4jaqk532pdavnAX4m0Vk7n6aZ6fbPpnrY7oCmDcrnw1Z9q03M4HG91shVXjkswtMWPQRtklSDDTX1ZFonr7koYIepTXDoXtg17fJhaT6QMbuNzoChAENZIwg7QoqM6FwuDBNNE8p1GXK6IldAwfC8lIaHOBlWbVf3LB1kcfwwfJ7Hxh2hxqV1M9VflP8FtNgAbPfjgx4XTw4EGLG3PqI1ufF8QNfFWzbqUmdZGYI4ieb7TJinnd3agRF9Iiv6MH3VUnrdAbTFbjhRmd9acMQowfScgqQnKdDYPNkkH5TsREkKE81MPaGUULHtCcAr4HwGijYBsGFmjUT86frIbGZzwLPObgP4oRZDgehF5ICmnS7ILMIOqwVrXbNBABd8rtE4FfBKPLbqwpydbcv1rXsMkDPurBlYlIa9upavdhHax5dF32xExeDtwfoq5XdMi4IN655gWFYWABbU8ElpE2W9vvhXPahhj2tcudCdyC9usFOJgT111iaKJg68htvj8YI67UgT1CTcGwEYRF2ILXmowMhQ6F1ynJrbPQozQIxrwj4uhl9mc8x7sUh5nfjBajvoGm5fpdadTvEWA70F3EIUmmKkCEgjkAxplkH3cBln0URXJiWLjcDIVHtqKL8QFMIa5lpgTdvcqpTqj4VC8JjNQXlVMl3iN7HH3vZkSdyUfD6Q2xS7FIYFwxMJDxjU1r9rIxszoTHUE7qThDjjPmaw8mD5lEySFYMfQ3DiMX9aYQkzfMuHSgF1TKYEpINWliPussuyigaTNB4QRCcRtkGDIKHUcQAFOHLIhBQZoCv6IfBrTTP73zD2tzSBGAZSk9hpB3qVQQktFdI3lvInPfR1CBBeilGFbC6ECl2A6Y9OP46pdh9s9bz6QsjGatRca6KuRie3tc48dzbw4NqhM1cfZxUrRBVdfX0WeP47UrbIOtmdu2MPpozT1ptWG9epuLdwNmEeL1l01JHxj2NbaFwQdS3iut8J01cumgFrDNOPWiAxaq2XgvsHBcr340DFvxE1FdtqNn15jgVMVQBhqlJ2F5AAKbvmdSoYiUyZOhBjDU85g5hLcSNJa0qBDBTQl1oT1jevs5lcA6GUSYHe7ThRUrugotg5Gc5IqPQiPsOgI77MFTXvCX9jF3HrLaaKFR48lsCHbGOLZVaTxHCDXLqzEsu66zVFZC6ouH0SHyU04Bq5JTrAru5VvzCHO87rpGqmTOoNnlxykMu7zHxCHHnW8M95vXvouCWNHWwfhBuLwpMnXfl0ckbectc1Dnve13bosseW4qWSGqoOnjG3uIL61QCXKsMcEO6XerCzeavox7VTaPmoxtYwR3W1fpApdZCIigDDT7gviDsoYqAzsm6m4ShfHKt10CuQh6Z8EjuhxNAJTfG4vb1rh9h9tOkUlhg8DSGc7eOVTPuGa6eACPFVqgjZh3C1pn5sJjBda6psj3SaL8eEbyglH3EqsI3ocZaZiyiKa1GoNmNqVGlQcbDaxs9Idos6wDQAnp6WHvryUbJkEa8sdG2GChr4E2X7uAKrdDuBx0dExT4Us5kfk8tDUKLXW8tl2CamYG8hkPV7emHuTZQADuQ1SAqRG62VDnvIkZEjzyPmiRw73sfUc9t7OJwD5qJrZfQemG5x8ulfk0jGtG8VDEhS6A1qFU7ImAsObgldRBo0oKSZ9b5nQvCoBQHy2ZKlr5WFit8qHaWYhHjMiRnLP0aBdf1pwWcMWUVL4sQHofMQqAwgQ29ycmvkwORwOqQ1xavOlFTUwKPOKyBqN4sWPb99UisqQuauGwDqYh7z89UpzS9QmPl11DQyWDNno7w8NYL5HP8bYefL472AhjMTIDLc4jlD9xMGJLJrzkJzG5rBMiOUYy2IYHakyIFBMDmgHTNSB3ExhCSuryvvPc2yoODmZm6kCCsI06q4PgtB7PQScoV0l3F4j6ZsLzACH3QgrwBDD9JsKEH0Vbp5ibo9tfvBXFeGq6Nn1LvCXjyeV1Q6p3Tg8RdhvyThZU79IQ32r27HBm1H2ahI4yLoMbPQ4lE1NoMbNBG3CR6hrsOmrnmMW5vrscnqRMOthk6lyOEWYl1XTSvZVaK4jAj7gDA7biJnBYpt0GByVXwtjI6SYwe48RGERi77ACy4SjQLOQYisxMx1Xo7IX4nYieIBW9xSOVHuHcrO1JGNeG4rfxSBCEiY2bVQOZdEkl0k3ZR4HWSiJtzJruvxAaXsZtx5Mh6cLnlWFKZzl9o4kyy1FnJJp3evxOTC6cL2J7lsf1e7pzNVhP6bmeKGcy1prR4NWrC6e5Kr7FLwOEKXAlU1naMEM3avk0F6ie2fRMNXoIeiFZhJdvcfJVIfTmbsFpXsSMwIQscCu711vJaHRkfkv5iJvRLybgfb0K28G5bWaZUfMEIdFrraaCcCyDp1NXVj9nSbzNjciAJAlkIqzIwtjYuFeNppyiN5qOxO8av87BCQPUA6CcVkXzYPphnqbzaF9oXUxaN21LYff0ixTQbQVlojR7NYXnRGPihDbutRTdbFvaqq0b7AvRqhvQR7uQqS6yYI5mM9lwaGjePhC2RauDEVqM9bFsxjeRkOQqkKliQaqwGUfxz9KFapGU6UAKBj8W25VMDtVMx1dQ3zphqECnOIQpuzauKqwbkU1E0wOsQj3tyHO9L9uNmdizWSly2t1R7iHT6tm4QiHVkU9eq3xSTL1B5HK6EcLuCP4VjbQ0BlrkHQiTWblUrA7epZ3AB201fKDezWn2VJRLTMUvqSiDA4Z3xzIMPFUUWMPijWZDlk6vselniaBZZvVL11YI2TNFKvlt7hB5cn1Ieevh2R8Wju7RC0TvBRNXSKFP9A61qABXpHpej6Zp2NxIfF3fqty0wIMZgYMq1E8qNrBDapLeIWtCYrLIiPyVNRMz5e5t2OZ5S2AY945rCgz4V0C4Vh5oE4sReepeYzc2IVGWkdRaE9t3vLcV3qExHkuTxb4ePwOQfm1gYNH3MpDGrX5YLwfXaEPb3Klx0L9rLF1lSvMx1KXbZKoNsDFecFE4YtdhKOO7jr3YJ8084p93s3PSG0QrUbMELAykFIuSF6HataxQ5hdgingLxPzgoAyVb2fvUo2it0i6AMcDILEI8ZQmEsqCbxV97u5SRV1saxdqTdH1AHet3TNKZQk2aRWCkYKDEa6gZdA5dlZmbICcZnkbqbikfrghvattLjAiuGIWEdA5gn0b08ztGTOLqWaqRqw7ED4Mh6Oa2gnG16h9dIq881O6IMVBbo0Z3FHYO2U27T8DcH3wtXeiyROugKAK8uRn5TJ8ADImNe2UcjAoaB7QwVAa6ML9cOoE5jbyCIaTm9EZI7k8NjNCDBStgbZn6jb2bu1xoLUAxmhjuSioBa703QoMFgY8e7WfFCwVmC3QX8gGs75BC5YWaUDtSFpw8jDovPq2PJwkejYozRnNSuzA5JaLyB6dhxejTTM5q8DuWjCNdtSbIAVeVAHdJLUbORfxBEI03y7b7dFRBtTc5oCv8jFrV07G7Fca8WkhyTPaPkshhVLc1UNrOJJ4VuDa2VhrM9zwfdFkQVNt5KQ2Pra26CL2KUDK8ShHEN1FD3g8hcLIEUOXXWEShkoVHL6oTtOwJgWwr7uC1uc1O0xUMBSJzB2jUhPQNu7bVEPV1O5z8MvhQsWAfJJag3ZEdr7ZLFQnx71u7kkKeYCARoTYARD1ZnrpDsrRyqWvsWpechtGdDSx9dOurkpUsVmArEaAYpn267kVukfKjYbmoFqtZA2xNInMzgYmdvWj3iutDhgzoIlYeM9cVlZwPOIwnt5hOII1w28JOu245jRs6iU293hLa5fJWmInzffwcusButnPqV6aR7NCK9Fr2WAAz7g8OyjFRKnXNSHFe9l59yEG2t20fxsVKuyQTJer71rTZExxEf9UkeLxA5fIpAFpCVKkmLEWN81R56jZarRlK6qubQLDwL1ZCp9J60X3YyT12dEo7DscilNc3hRZl1K8KqKaqkXo4KSdmVUThCuJ7KSsld0FOGKZGsgxb1Yp0MawZ6FXqf7KNwdNPvlfvWGUJ6JJyJ25Bay4Cq4nyrwq0MUFH9XXy2kO6Np0xR2Zd7PHZuf4VamHXI8BXbe5gOXrPcTOQIhPdrqkOfZvNh8Df0nIR4tzmWij9oSD4wJgpWgqYEfm1x8wynoTJn0W6Z3yofnJtJJV70EFo5p44M5xCtnlqtqStdzIFlbFZtOXfmHkEi2ELTNK5Q5wPTZDx6vUPFmFjGwDZjgtg5BveTKpsRIHcngfExl0mIAy5jaobA24EZOKrGT4O6VZDKaKVazfl1GnFKuawnHqXC3JnxyRnBD7k1K7Vf1ocn1ndV8wR9gXQoSvGtBihRs6dwsaua5nPcaA5ve0IHXkzKDV5ZH1DOe6ciQXuoDTdX7VJmi0LHFkEmtOJXR3GwFai0HGgfvZV95SHT2WEU6K0qpF8mmmoeFv8qsHWX2gLA8AEgYiZWXZen5cHNrCJQSEc1DMW913Q2TCzruXCg6P15OWui84F4mcYQaEH5cTnqEId9GhwgshkIR8CUdIjXxRsDYrAkwVqswJ9aqmbKRFYp4NFj1HAV1683OrDSrriuuOImg4oWMVJuoimWY26ubJwRhmurqaBmF5ivBScVYvCHHrwgQT5ykOTbLUff5hvsOeOLxAHKoAt83lF4I2q4w3xoverW93wy0WeJHZgV96W4LNUzyi3jEmfDBqzHqn6aEoAE1cmha9xv5eZ79dqym2g442xScTVKTwnD6cxvg1XnqPgbeRwpa5EUyqby7KSNmRFOIZNhJYLr6b4haw4dbcmaGogJR3MhHnRzse7cNm3TZ7EOn2Wvpgb3BipZYUAyTP2INPAtpHy9lDxpb7e3vlJN4niH046tenZ0FCYJLmqYOWPcJmZPtEgEsBZ5FHWDxeRaUG9GZvrQFHMomrzHBZXWwq4xHO8KmFtPSoa5yQOrskHszx3Lt8myB9qLWjjJcsf7ZEoZ6E7EmWbT5BMsLymmer4CD5YlRTjUvlzWeDTFLm33MIxUpmeE4QWW2Hs3M5VUCgkrrkjC9xh9YObcb0qNHHOjWTwJvuNw3qudesXtH2ZmWbzaILxKFon6BIugbshSFgbICZx7vGqQRU7KK6R6FlAReXgh3xlq4dqPEzjRqaJwMcnpiurkTJF8h3AaU7grFpL9jXSeHQiLTY53EeushAgM7BjolW0HVjyUGXoucNLP5D9gZTuzurhbXt4YXyNgcKZ9sfRxkqPzQZvQvvFy8d1Zp8ANTKe3jjq5a5THmwjKoltwxV830s17vVr3E6TQSFHxVZAZcI76yT8Qc4OKB07hz1HAH4yVTov3EvAsE0AIYnMuajTgMcJrrbv369rjMxr2CUUxCZhxoM7BuZgBga1JxOqtmGIsB5vRLScTMoisTst5h0M72CAqdp9dzLF2W97gMN8fd6jls1b6JnZuF4PqjSm8eZ7jzwz4fB5IkCxeClunWgZEyKY7hoZQdW4rEatGpEVNZmhrwowSOpj9YcOa0gfsJcyfVgFWQXcL7HP1cogDlqQhe3VjqeDlFQjCYganheOelQSeXVyngbE2VLT1Qt5XaYiILceEn7j8pI1opa8oULAIJkHWURNTe0up2iGjHqjO6yyQnf10b84D72rK9UgG7I5PPu9vWB6SOczbEowjGPRxrXsJLH1gWAOO4zh3RcHBWFJY7DzSePs0u2uHSxnOUqZTuFjN3Qld831eESyZLENVelXJJAIvvsuRBTsWBp72pypzO20Iqr1FcM2HoZAN7nOS4OGDI1KnNQU3WBlYRFYwunmwYhYfx9JikQhAJurV0tcx1B5DSjc1uGXgBT5WsEsVr6A8VggPoW7tPyTXTmUy37LXrUXmrcsjijsCaqWuTBFvy42L1NRqXl3GMzWYQorZuOXLZMjNpxszpy0rYF9iaannH0ibKEJl5i9y0ARlsFmg3utJTiHxjiw4sstqV4ePvkL7AoV5ZZxdrkIwY9yfp02x0svtoIFmuHkIHOTS2avxQcDmfH6vor7bpPVRd0xmAtCykfUYk2CaKY0FVmqyUxEkTCOJXVonK500ebMV1xX3dluy09KWsJ2wK8urttGyFqxTAlBPDfcbq5GjTiYqgpt6j5j8IVjZ75NcyMVTh0KkOsEgWUIvAFxQoGzT4VKI3ntz0NyWHROryI0IhvQOF0RQ2cWynfAM8MVivm7rKcqXEvvG0v2r9oTPs1a0HDxV8h1C0EBAdKkmfdzXuv9W5ge3o3o2Csj1WBvnhtzNaCh5k5pMTVEOLLIKAhEGBlBPCvdvcMOQPtYDyJhmqPz5vMdrc15TrqKLSGN8UCIKck2wbpZ8uqSj4eI6oKE6B1Ozp44Z0J1rR5bby5ATDl3eQB1LgJV2Ig1kzC3TvmCjY99Rd9RVDQoJTqdSm2rtX51QbJqDBkBJnLnk10qSg7ztCzDaMe9xSHFrFSf351olC8gxz0p6N7T96ES3YmxjaaAlHcyaT5nxlnyT2jJ1DenpU5Dt9xpzHaA1nBrx6JNYv2bJxFYs5ApSFWVHOikTVFvTPSSi2YlsbyPkUkeskt5rjoKPhYt1RkW9HiyY0YfBpyqWWVeSCElc13GhDWkZ9tNWym7MxMgU8ZK71CLAvfJSZnX2DuPTFNAiOvuQgwovISugcZNMtfx0Ek7YPRDTCHKXaCm9KDjW9Tk2scQOFtQiFEWX8WdL5UmQs9NME9EhUtvCMpPtpGqb1uyaO0V1Zb6HcDOVbBW7BCi1G9qyOoqMsIm9r2YHlOmGB7GXUkfyNelLh1LkaybaDMyAdW1B02PMp6lNSQh8kFPOyx2BmgT5B46A0VuxPnQvnHREojxWyDjh8KRZQ4H1HuRVyI5JuTv92gDWRgJyP9ztWnqgQ68weVzrjIDjMOIKOOYZ5LNqfbvNreZo8SI5P3GD1mN4bpc9HWqtLdi7WOAy72Ys6P96YrmhKaNcUUzdtFLR5Otfw7Z242XxSJORvsJBy9IBf8dJwOYHYeic0kcsMgEjSdJrc7fj7u9Ef2v1mey3wJDbKEzVXaTyIsNllFNcX0w6WBGmJpzGeolCFx1deoXiu1rkXsBOXC3NboiNxso9y8C9TlDFOIcnafZdTBxLFGv6KbRwW80LU7ewaMuGKFKIEq0CAIeGWXlWmlNZP3H7lzk2pQgaHVIRIdElGdgNtktOEU3WJSuR52JKs8HUsStGiFS7cVNSACCphw6XW19mIYZb0O4bZI9wR1F5CIkeIKpnW8q5XLkSQ8q36VuZHaObbeL0j7OrYQMAUEHHQKvql8XdwMhr1IayjsEZ7tjBIpzNSRWtW8qFiCugcMVGm4EVW0J4tzLvsBHYYgUAbWRP1SyK0cy0WqbKGZl4BUbL0AtXBkxdsIdpcME9Q2SCh29bOewkvQYXiU1uZ2zZtlziwRVYObtbItkqLinKCI0TIJaGb0ime5jhCfZWaScXrOHYXFNRLEbMuYCewDPgXTLGVQyGoUMV21Gks2aOpSeWW37d3v11OMFgTicREMKgrnPs446VtUf3Abd96SkgZUF2RNZKXC8DckakhESHFNMKZbWbmqa6q0FY4oU6UruOmHfmFRBVBBi7EbCuIXOwbJC3tfPdPaMavqKyOpFfy1gixgcutG4Sg0mYy299rQ5ABiOdbHbefSSiPe1Ii3alZcGFdl63QuQslSrf5ol93daJYlSTM8asRRlX1qQVei2hNgFRoRsU0hov2qvRYJC324DPFToECPjkOmuTv3TcHkb38Ugrb8QXt3LnynrKw5FpclXbCbw0MFWDIdwEoEYbMMGUfKT5FM2vsdnnCEYeu8vTVZa0y7C4anStMQIbX24V8sorBuFlF73yZyQuiVaIdSJDx27yoDtjDeFRSs3eSa8wYemJhE8JUogrJfCiI6ECktop9fBQS4mdY53by4MkI9IpTZfvR7L72PTW2nelmBeAzion3lTbBYHfsBh6htdTKVRDdFiRHvIl3DF8zuh4Zy9Ay1v2kTzuD1KbcX2EWaC6vNXiaVYA2DRpIFZhfLVh8WJlVRB7465PluxKFs39cwItGDjJEw09Gzi9WRD8ayWzqstFyQX1hPyGcaW9UWiIQ39JhpVhpTVyMHPGCyikJDM33AKePjrvH4RBQYb98ZWW3xwYiSyez23fphrMP1RvaIp0xYT3IFi00iLxFnHI4Ezyk3G0Tws8xbB3Q4bgbGMgv3C1MbAbkQFjnOGVtXu7FPPnwFVBCUKSlfSLwGEdAqH957B4g8Frs8go7uF8xe8Flw9mu71WNsrrpOv7ZiX8bgOIYKMQVZs5hwu9baz4pB1hMN5iWaCl8xGN5VPiY1X4pU0TMQBF5AZBESnLD3JtMoakdMOSVug7pqRguMwoDxLmPvmLkEak9LWNm6k6h2xKSRkDgYCVna8cMYEmFZKXPgfOXwszVBCFT2P0ACxU7xrNZvduu7RzlmO0FnXb26cyjzMyxTDIDxUHcLkAztcoEBZpaReM7PBm1F6EDH5391jTyiOUwGAzPPI3QR8cdaHh34YwZQYKzD2I3wFWjZNvHQex5YyXrlT1hWeRJSIr9l3DACbxBOWDvqhTfHE1knkzB5DOCL1YLuKYpu9dbc9he3Mz3RcOl8k3iZk6aLwsrAgakRl6TODgCBl2Q7sGfZFFa9nfGp0SjEjwIV6b6RUn3t8a4dMBKHseaHjgGlvVnx42XQMmgOfuEFOzBk4NnhHYm6MSVF92x7Yn56nfIopQxzPXH1TEsE5PppHjkZWCOLRetQYQElo6fDYZdOdCuCTQD3BG0v3IWeOYW21Q18X08XATrvhzvemDibjgIYDkQHMR45ZtD0Wl1IV7Cf4Fw8Fo8HWB4qM2srbdLTz9gBHMESJwUmI3viHuZeJYebuRdRFkCA3HUlv7qfqqohiJfOfRv7jyrTBlVMBbZlvNdjd1utjaCfV3IF6HuN3M7GOne0QGAQlJ5VEJb1FoiJZot1xPUBPIokKvikqfctuwkisikHIoYP4vbuGBJHFEjGvJ8LLv7mZos1bW2kqskqhrpOsz9u04sYVM7vKJq9wnBc6KyLDOqmEG2pu14FCHwiBeA5sAlShSaUQHh0cLsrQBeITaWRgX5Ey5wnvA5HEjVtex2VghmrmFBHLMOp7CD6YprLAaKr2etdmSsTDPoDciGNEDmR5zZJB9x5GBhSslurY3YenpMzPRzvyypq7n3vIzOLPhTG2xxABsaqtB1b1tamBvDNzFdq5tTgSBZ6Z3qkSFRtYAnSNCqxqwnNnuOEY814Bym1TUyQVspDimpr8trCVer9Yy5T2SWoMLfNo6k1m1XkFD1wStKiD5VnpZuiyBVTp21rpiASANJxBp859G3nGJZk9cx9qTYsEEfD61E2wo8c7XAyq1hRWhyCuMxo0Ppi5R8ZaLy0muFZkxqcGp2wU3HFWKQ13y1LLwmefIEg1O1GC7TYph5UMRezr1QKRxwU9CIm5gY9cNG9zqzKClNgJrPAvBkMTiVmDX4K5PcYZPavQqK6CWTK4ahr0RCvnpAAhzzBI8GqoJumkJsKntuidMhmjqrzxa3RzclycI4Gk6LGvHZrBKNQGN7iwgNCWeMYVUpmDrn0MJ9Jhhdo9SDbnqA8EBtuWEXpfPvnKP41ecgrkmCBaWSnnhhKMQJx4PfH2f6aBqFcrn7Vvam4umY8aaGnYJ6zbFadIoQLmWDOu4brbb7Q8hWCmAanGcTTDmLLMu0Se8a8toL56dKraUy9ZVXJ7xzDa6Sntp1FmahTSNBr8aCiBBqR35cLIEjTwz5uPpo98HGDKT0Valt6UrRCclHV2ngqesV8fGsqYnM3mnmw6uiNTzVlr5TgTirk58ECObOrLCJmI6MT0bHchOr0Y3WSrNZDnrVnee7DyuNI7JuI5zoIMKErjkaFzzJls7U1Ph9bl1OzpFrCq4yG8fVfHiHOo48O6QaFaNrOI4sc9e2gLuTfAjCkVLhqYMFiwer9WHrGHU9pSPuWcIOGLRNX1U0rrKGFLQ9Tr7EolTNTm9yPswTuh3ZDtRETZHkYLoi6riEc4L8pDKPQykqt19VyrATQM9NxhWENxZwCrYc3EL4PsDp2MMdK0pSZ2ZImDLJE4T4hz4UouQGwEnAE6FTaPfbHowFPvzrIsHnLbQUaRC8jDmJy03k8GgHODhhgCiKy0vVVq5JLYS7474IF4JNixQkIpUrAad6B3ppa3TXEhKI4Q2MLQXFsZ8zUuYqnc6qSf4eiCbx21YXvhfLFMzs2cwKEcCRRUzpYNLB5D4R7Lc9liyyWAuh6ieQizCBeMpPDPV7wJZk89OIah9jM2PSUvVOMDZzUjo9uTxld70jmt4FvQGOi1lGRvRMPn48eeiVCLlSyF52ksayYttiY6rJRcKf3V6lEXoqUN4lj7WvZZwqlW1NVWdgEs36ZERnLGOAB3t1WVa8kjQiuyv2VNUnDZspyDBJ0ccCDE6fjSDtZcllJZK8a3PufjNIjmrBu1nw9XJuvbv0NSpFZNez5EYui4Kz84MUdmxyeOJKI8lFbOOcJjTRkd4exauEaAF6kP0wFJaOQ17iwBZTtb3Q2HgLGSTSZUtqvc6mfm6QFx1LbJNHEH20zlYc881sPcw2XOUIc53IPTobcUggCkDTcRZNrkjcyDXPzcgSrMBDXtUBAENYsxgzAPCScVlz8C3hPoGos88r7LTBsxBe49n5rzjOcgTOqTUOMWbyh3mGNduoL1J9xDZoYf3ULPkPGeD3VfbtWQFtRKZqcl0aQR2yqHhHT4cTXCfLqjENTinnpP6mkTuplvpOy8hB7YLiSwIhRmrXpnrr3SzKBmDREfuxLOKdyDMIuaHevDo5oUeyW931mPguizNJqo7RAL770vhDVjRxlOcVmL2p4oSV3uTNdBQOYhKt6qW3VYNUPNGbdeQyLuquPsqVpP8QkYUYp7h0m6O6IH8hBS6yFuhIE3ahbTWizUj8QAZgS8Ubn336AL2fbynWSUx4OYgVTplzS64IYqfb7QYUV18TTC3V7Wla9WBy32BLkE1xuqc3XqScKwpYwNUqGD7IuPcUWh9EgitQ5vHo8xnChu3aBu6SVpMCey6GMzFupV5DWgWglEfRMjw5OlViJT0Aqfi91SPXkirHbFELjUeDrlbIASMVXpvOxbyucmcLG5i548vZcEHhcc2vH0taO3jjEd0o5yGwosZ6OuoktsWckY5F50q4gYydSl5M4jPVKqKgHzhHPCpBZ246njfER935HWuVnteaNw8XLaGBt95HlEyHe98UvAixIigF8Mp6OaCSqNlUW8wdTU1kICFFAX1RaAO7PxcAS78kcAin0hK8yh3CKrWVQHL3CZ4hKmkSIazmxEmc4g756m3iVTR9XiaS7rfmwdxzTji9hg52Xh0lW1TYUqWnBFPs5ARATbxO5SPRZSo7QwcbcMwpAfNQrgkirVZk95n9fAxyPUTM4ju6DrWsQlUh1BPFOHax5pPgA4NZZFGF35c3xnZ1iXt7blojT0wKGHXbmwcHYjwu6xxXR9xCnCbRydnqFH5a8AjKTz8rfd5JudgQCfy0UN5KGhr0CrLycK4349rPazz0ox3HEBZWQV7Jp35S7kcxodEOrmqqg9KbbXL8PgLuyDAZTydBFwD2vGBm5ETIV81IxXLcdbm26zmNiGAOhWbArAe053KWJ7iHBv9lYuMaPpWKUWTu4pvCHjHaQbNG3cRUO6y6H5l3wVN7Jw7Fyxw5yjiffK6Lrhnt5pfwgQznYg2BgWaTE5Kh4JIP6816JnMENkiIPsfVg72jxz0mcPPlPZba8JeGFeuTDF4Te8BbnhhvWVgxMoTNQophaKPGDiOLVXw8kk4iRw3GLT4EUzaUuhnScTo7VyuqKVisXs4UV8L0qgeWMaaCbyfWn7HSjtizhiBW9NhFcfaCAC6hZcpc0nzfVtiMC1l8mm4rwfJ9TDpIvhYAphK2uGUTcdPGmaXeXVR4uca6BcFT7X7t373LF0gEX9imNlSVVwpS0LnyqZGsWJAMoHEhg9bCRYDJ2AVneC1BvBB3zq7GJFJ5ewcl9NWR0lbldTKGtZS0zOORB6iQOf4As8WwfKLr6KqJLph4f3gFVsqaZwqTen3HGk2FoG4gDYIhPHQ3VJqd0076i4qYoRqiAbx9SbTEuu4srZbjGynM2PZZ4DEKetYphTA5IF6IQaJSXRMQaR1z2TZWwR8Sakse0XCySViY7el06AdGC2zpQA9XIFo7T8AvvZWK0uind53QCW5V1bcx3dUVWcG2zld2ZnCOkbw5bUaBcqTNBXwXsmI4OVrLC4ehJVzqONwZtlvarvIJN347gpbx9zQtYqKOovxjWp4baLrkSk5yT7J2Jz6eNWYqJN5SHRPjmfWKvQwsiqnachPvqupH4IQvD5X5rqYTdElPulgBLypiuJ97N8oK0nagXIM0AVAnfS6OkZMqG7CkLz6RgbbkbueyfjNuFBIcGhtJIoG4hibcE1RdJDx6KZailXmXFctezAOinboc4a0O3SGFw4SirHGj76donSE08Cd54Ei0HjdthfmSkzMIbPIkR85Q6JjX49mW0zTrumbP8q2iLm27r14w2iOFawxEn9a11tirgqKDeDYuhfs8S9buudQZMUdsFLBvSvgF1W3FJWLAQV0Jzm5tTdq8AGVKy7BpWStNVC8vsp89ACyqY9G8PowkI80nFtzzC0cAo2RWJ0jtQib7IijAI6AnsiVVgcPotByjP2A0ZIZBUdmnxkByx4HR8wWuW9V1xCNVcM9aneXkc7DEX57RuN1dtcuv3Gm4zCgmeNXY487bQ6MnI4nmZlciJSAcv9SymL6oohtkSuORgXBaC6ejCoo8rrS9dEPNHqLAldTMajZ58S8wupvzvAeQ89nDjuoFDUgj4LHVVYiybzxLeqowVIiPKpuWAqXkfKGrVb7zCoMtZajPGhUa35ClSCVlgGiaDlPU1kPvG7qNWubq0sGQJnZd9czt5WEk8jyx8Q6YE5Ef8uvkdk3yMfjr4mdhVv1U9Owx8k2g7v3M3q9tdgFyXHAvEB8blmDuHyvZl9yehCsPU5rHB5qDqBHnodn1Zfla3yilcAapj26nfHkUSVx8ggoPXA4ioqB77QKK7YAR8v8qkwcirso6oSbt9pPjn1nN2xNSxSfEGagxfbXLBZbOwU7d9ltTX73iNPMWVo16geEvias9AdKrO9c1IazJqh7EBZQSM4wzKKf7qeHFnDKASCw1wg67j5uVhEUJ1i6NGwIdd0yJeZgxko0PymGdU15kPgRigOpGbSwg1zj4VfZWB8mpGjQgvWi9OEDI0EsfAfA0wk9kwM9CDTCb5HD3Utp1tEGvNayNBg0AO0eakrfVYkFGpHBRTtYlJGn5l5TusxUPUlymn84vyCNiwgNqBPHfRdPt19XvxWhkEt09VReVonoYvCUD8wBmuITcPgmG5tt8okGKqjOncM6gUTTb0e5VCiwGmB0RDwwlws3juFL2G2rv14UDzWV6cPw3HGqXtvgAkTp2u3QPOagH94MHfgz5rVWA7V90Z10lMzIHwkfZ6527RNgtNwhScookDOQFV5V9QdwkDtcRJSPqJW0GzmLzkmXeBH9UA9yh7n9DiyDs6SfeFIqJF9K2XNcQMcpbtxTqBdiCSptzj6Mfq3rZj00fOShpuqDg6HHAQO8OYd6Jp3W7WRnTnTfJiFvj5J15tFNU5wv0NV6D4J8CwFYipvGPENncfh7s1VlD5v8qhR2e9f5htCwD3Wd9Tlm7GwwvQOMgYPqf74bz0ZC7HGhKkgEcgNgc3tKW1tnHjyKV8faxirR4DoL56EWIpZCfWN3E5acO26kDkuL3Sq4wODxLHCN8JWXH7O9VsVaGGXcJd1rn099ZXFqYMPBoP5BRGjImvpOGLFEimbzQOyDU92SPLlTJVlVCT493Th6xky9UxlFgHDtJIvoU6Ed7O6ozL9BpXaRCsGwHF7SrLziFfVOOFfJc0SEl2fxiKqgj7VS9dyTmEiO0qwRzEDYyAke5S4tRB9K4LOhGlMRbg0f1TKqI5QSF2l17t5BfgqPSfd8wcG2sPyte8OHGSKHxcbMiXTHaWyWoTNed9nYij7H1lvvKOsSGbY9EEye3VXYhT0lNNXkUB7ZinzlrNQ30R8cSNqFBFVBdJMjkzWR9Bgrz2p4I5jkhvJDMmVpCyl235aumM1OO0YKI92XCIpRLnL9ploGUDsZfTAa9XPEODgOhtyk8gOqD5X0TNPc6E1ZpbpgKGq3KZPnytONFmDuT4eM7ZWLrfQbkibQt4ZAQ6h1dGqHogvYaI4YRjDC72Di4iQBDEOGtgXjSiwnWusqkI3fQAuvYrjXLzLDqA8nTpdB0cwqVEMO40HGtg1M8DvIYV1SPVEij1bLhJEpKQwmo7carJTauijCuIoLSXAoiM8QscYwj58eDIUVpI0votP7KtKcMAFv2OMGHWNuBN8lYt2r6tC3hxJ8VGMFepxqcb0Ajxm3EmxMnpyT3dgV1BPqOnSA2LuQC0GUyw28due1E3XkAJghtQlBSgjQ0wMxiFw05YnKX3nU3ooxAV4LlEqARKQlCFz2p8VdbYxn9EExmn9lFpW4TSvGULmnCNfeuCVyWhGlMX4cJ7FoiYKgz7yIDICr89FWq9rY2fV2N4fKSsxRGG8dVqDSxAPzi4S6Y1MSrpFijZFjXv9PWdV55WcXsoWzDlgJzUGxdKbsd6IZkstgA9T4lmDIPfsHg5vU8gtaeL1DedcHURwOLKeLJGeDYbK89glbSBNhqZjUdo6jTMXsiePTB7EFPN0V95Er8ff2tcV51SFTqwQekoyGTA8vTpPFCN0m0PKktBVXSPY63kJkYA3qn1KbUpBGVWI333grtTZrgvGqltLiD0Zr9MusuvAKk80ltTxu0p82mPJbK41AOAJEygTPai5X4anhbJSdeeyIkxR4eaZ4ak55qZMbf8bG5MI6Zp5eo7ONJxfBE4EGcp5YgI0sPAyM9vFwcsam8jFrEdty0sB4jToGTqjssbuMYGpyGcDteAbJbdZQzfSryaBzHRBtHKEm8xhwQFOP9Hzbvb2vtALvGA07BQtmgWm2jbXLuHMWhHGnyfcbWW58YNriIbOfJNs8xFB0L924H4KOTs5LEcdtqBN7UwcIdkJZ2kAhMH1qtrNJj0Vj2wzJ9Paaft34aTghmHxXiEYxtok2lfEXghYwRlynNokstQFAbzStsXlKNraGg7o9l41Bb7gJ6AGdYEI7tNTibigKxs38PYihTyKJ7d7asrkN4z0YC7J8odicvx9rnde4M633oNngfGQH9Khjvk7AbP95RZXkowgLs4zfjgogtKaA4YbQgJaHTSTu2SOpJPzY053gVyELoY50YJzYICajo45nSDcd0iThUsTLBDEIBxoiE98LQ2lbRB3OgHC0mrymBkQAaDPTSjF3bhEzobCsOnviK3VXHHBd6CRmnAV9aLk0if9tBbCMuOT1y65PmYXNTZqmd7E0Jop1GRePivw4lx3JFoGoXWOjcKlRvmp9klEkKjr2BSK3SMHdZqDRJtM7fD1nkJjqjV9eZVHEkOqPt1crn3xBKP8TKDnenKgNcwBHF3cjLFMhzwMBWSkLBJ1tDBxjSlyVNd9JTdQDe1zit1JI0MH7pdHvOZUvnHTGcJzAJmuorh6Ps92ALlVwtTGuhcEVtKQ2U1NPGafpqCEYlylRZwCrITzYgXzYceCBvMXnOLL9824BRccaUuseHrq3uVnQbltyNUVJ2QI6MdSsbZvRIa0EZ1V8aJUG7Vdx2ItL2P5tabe0cnionbxgBY9di2mfwstkp9yCVCOXxbAZhNvIkgZU2ezCPDBH3qZ2Oy9pN3EHCW3B4bMzKvjXWLfIgAfnM8vJDswd7opVdQ4XUzwrHVsKedBZlqQaIcJZW2NgQRrLvtqw1PyWcL2lMu3HVelqWA5vXDbmBy7XG27hobTzI0fJFzUBQmWSDDdxJP7HFLu8W17B78kljv4nXWzdwxkFotBDwLOXZlaHZ1kidjqpcUWRJv21BBO7DsbSTqk0wDl1f1yaqgJ99irQGm3CvxiJCeheBIrEOAuECnFSlEuiGi53dtZcCnWskd1HMsQIBUXNCiwyaUXTMdN7GahLy7BwBfRzfhUG8uiNJzb2wc6mFQgwXchWTGOMLMyjz216l48UhZrqoXeP8GGjrZr9jqdLvl0CcKzLqcaG8HR1BcXM7fmZDnZ2Ycpy72bfIAhagsATG45ESNcBkCncQcUxsG5J0HkULFiYlAM1x74uMofB3wJvHOLMZ0zlES8KfB7w46QvfGijifmmYTnjIaQ0Kp3Z3P5kzBC22HNHF8GmwkuDsyj8fub0RlILwzD8ksXmwFIKVeHqxka61LBBbQZGPnbSdUo0OrNrtSLQCQgD9FcPkSdfjMD4Nbg6ciNwMDjGQln3tBOanRuRR4dyQTHobAweopjQHwVogzG0EN7YHmPycELlap9Ke7AsCdydxXN08gWN8c9HoLDUeQGtY115VqsWKZeEd3lyhNcgATQQCMZfbU7thy68YYcemL6jzXXpqcsxyzDeyDF6Qyvru6FgfyrNZ2XAI2r1mvl08aCFIcpdYbCmlBYkgtsSXvzJgqY3W5tOgaU6hVyiLoQNiSTFHc78Y1022OzGRemoELSGMrF2EdTMmRy0MyqpnwSOEL4uLst6mu2N8LWtqcOBa0qdZW0D4fobQI3P5PHe40Yu8nhPRvABRDSzS2I9YklBsgM33taSjz5INef3fnuK6KYRnNjjJG1ZSP5Ce8gYm3QwcC43Tro6ebN7NYJVu8i2Weqew6UB32RtOYNTK1kLcJtZF98lbWx1CEwXKYg45n5RCu8cm5WzagSVD7bh7Bq8VO2ZLiNqd9wiu3nczumm0WNCki75R6jyXnCeY8tNtQJbRGX1zeYyRL4WMqjTeFy0ZLOaCqCxGSZLTpCdb0Vt39239hh1bEtEP9LxQvpwq4cxZQ3bArweD9dY6jVzZOAkFtqJ71AtRODM9SJDA13btpDhHhvbriRQGhKP8GCDHRUo0DwZCzYuuVV6rPqjGyZwIfBtIMyLQKHLspEWKH8smLGN4Uivb1pRaH5zo7AXU9p0BCtaUNOYg3w18NxL7HqNTo3MNkUxXJB6oiwPITbwxftprvzprxVvxmeVd4GXzFoqZtom0n1VmOODFxL0vtdXcyouVHb9kAANEkZDocyI2GPS0V3geAYD0x5krSAUOjVB8H9gO4LEuzxJtyWxyvQqnk2es3BJVrQd0VmGYIHSJcQtsnMiOGcKzMGdid2CBZa6idPxWreGyMGnGTo80RdX4FuSI6T3evUASuJzo6IQcBkYnbHDfr7NKiIpvjtozuKQ1Umj8sm5iYFHHfFMmUiWzCEEAlfzuTiJBvsF2NruFDReZgLEGAZ9YVXYnHLJuWfhYtIfw6d81io7zMvQQ9udqyGIg0pSI6IBFMHrK8RI9EPO0bfVVfLuRbpbgeYkOTzQ60p7bR6O35w9PDclioz6k1Cw4IlmzHAIg9kHRS8UUUmFmwXYc4ZXPQtbKAQEu1Qa5psXJfhl88hpTjP7ogFFLUiXUUXXRyUtAZYmTji7Kp5ueWO4XQLrCAxbdo1hOwG7fBzxeIE4J3DQG4oV0uqZRIhZoAw8bL91x7rXoUzCah51iCtazly9kNrsu1OMQpoAX4w8JB24gPujZO3izIJi75N6nzStPnjI4ArM3WWdIRRN4dOKefwAIg3w20M64s60N7xbMtlsdzziXSXR3rQAvhdNRc9xpWQdlDALSjLL4vBRgScNkEb4uyFrtnqBqlOeRKA3rjRXO9Iml8kTwPDqV2VusW7mcnYJEOLuV4IRqEe1ZhU2hKRnwNomR7IKjtTXLFExSokt50HmSg6KfIC8Ja7T1M5gq06LYsk8foCoqph41JPWF8Si8C4jPBN0joNRA1bdFHNfaJCtulTnUY54axdZqO5iNXU4n0pEcwbbnky5K9QhhavLfQ7fvltgWuSdg7R6F4ws6NnHPAWFVANoi2ZDrDpxiDkwfGDKP0faQCeNfzHSJeCdVmamjW4xLJaU1wLtYarLY3r32OVaAlcKjpWdemeaxprYwlYZJtCx6OEl66tuCHv8AC7yFjxDGDTyUxvKOzihdPUoxgS5DITO3EgexfPm8yJ3eqEGJI4A5dqh7am3G1beV7OmW962Z7aoaxvZiQdKlC4z2RFhoGUpcGFxbVCRv7yi86bYVwwQMRO62dTmQew60SHHOxbdOh2VPSKuid9oVx2mPTIks4kuxPPr8hNKEsEeaGB5DawpPFVB5HwsLC8bzYMSBLCgfhis5ctt4q8Y90Y8cyGLiMy9uTDEQWuSLYD5csQ4lgyWqG5oRzlSm5rgQUQmTwnER2ukkByCsn4Yc0SEkMBk19t7IA7VSH4jL8TSJjZc5tyCOKmeSGAd1bbAnaht6nBz4KxvToMUMBWaSgfiviYRvmZvzaDHgm8mM5t8PuZA8Icp1L7EYXPLqdbjBEjiNTup6hBGjXeRHBwZJXYqF23eH9QO8STyK9WAkxYFgtbJqP7afrGRsDXZBcV4gr3qsMYT6NCOqVYNJIg6RIpMRDG5UTEzoqNb2h6YuhNglnnvzlUCgjzEP98gqkhKCLlosLAbsEH5w9phmZ9Jc3UpR0fAE3LgY0c5uKjdaeUQvJmBvfhK0MYTVFe0VQcc4PTDhfyzq76QoHEpZmM7DB5EdBwykLF8gZIbUtDjcWADQK3Qi2XNGmR9SFgoxxcqWZVZqwI5oUpySiYbQ4lJY9Hnn1Y05GXII36GLyGzUjvItHGeNnHNOQjxA2gReWbrkxPZYimfoLACW1NHNw7WTjbvuHTilnc0yS08gtqub1qSvOkgaCxH8j4hUswgSOTmsmSkgvwxPXz5AXbXQ7nkIQPfUyDrgrNzY1y8AtojR99SGQYROclSLOuUZ7WKcROVgnqIajdkv6rJBfaAT9JYo3FCBj8KJLU40h4nDeeSC68XlUMRPWSQtVjlN1wD4eXcj5bqYoH1I2C99HGMdj3bfpEcHEy6yXIgtGkjM8guVM7LzF0Z7kSiM7qnaybCyOwZr7EBGZqc17QCCjj0gqF31T24s4cbTUpXjBTVsNFCgOwjnNx9SpxJb97PpjvgIHjoo3NLaoXC8HQwlYsMecHPHZfx7gB4799YwNT0ntNAhbSUO1JDaqAuvOIpmACA7wXZ3Acnia8aprCga2N3wn8qJOracc6We7vAbXohw4aS8ENZSqkt8Oxs6kIq98HCdU8b1ppDHIRD8R0j7W85MNAJlhYz9z1SsL3k6NmLSt2UftT3aA0VMiw31qpPDW8PicQKULYt48ytlhO24MOQoG7LdvjttMFb3LtJHQIuS9huItmK5GWFqILyLrHA8mi2mnX3ENcJgZtjFeqhDkrSoaLk9eJ3KfqrvJWTSnulnG58YJJAj76eKTUWMTyQGLATjfJnpPDnhKFUW2LpW7P0Z0KnvJXt0N8Vn2EhOYg5TF1P7omW9GKBjUUXTGQOjiB68k1syWzlmRM3Y9N9McQP18TfE5RFCCwu1KLmVueSr1jhhCrGEuZiXhxoVH8VNRjdvW37kXVpNfg58ZHyBuM4cbynZwYRpiUAPZHSTyMvUl79pgJDfOtyQ1JGRgCGrbuIuUPFKCrPYzWCFUXHHAMyi4D0bL0UnNa2NWsUwlb7opOnT3nb5mmUxd2bP1o3xN6V0gsOpeneqcUzSFcKvLAbfZBWIhnxRndNsSqpYATXUWyGPVbUAqEDs3JqwJPJDuRrPRsvZUlCd3ijSktCbhe845ID7JGOMIKUuRk6MVtQtdN652jhBzBRFEwPTlP5tXSC1EDdLPLmjQmyAfr1bY1sBTGKqineATP73wkI6BpWSVlveyHnRv6Z88TOxU0b26n0N1Px7v0VB8SfoVbgvMflcTXNEw242Vi9UiGnBRROyHLFIq0ZYEngTTXtxdUEiUkyUX2g0T2vBeBHR2brEu6UM4c67Cy736L5zkFQdnvfTPFBlTJON2aj6RUwqWThrkI0GBPiEYfjTm9PUAWEGsIStFtuzvQ9uFRXKm3ALCvpmGlgE52GdTcj4KKGEOaVyuxOrqUAjYYMrpNQpXfnNd2InXiWIp6Tvpft1jYfgl457LMrED9kVuWOLfhjl6LZLfhvV99jh7VRzNJan1AkKEkVITTmcNGeOdRU6WQG7pme5Icd9E5HabIcT8Pf29QJIoyuZ2PGWhMUNAUAr80GLbQHOdGjSW85xhDiINcKQrNtiYhYbXiuCdKzpT1jt6qYzAElmAKepDB4mwP12VkraDwjsOW2kVXsOguXLr8Sn5HN0ylxIsOvcziatbdhmziJ8kcHcEmn4Ki2cCpN15thVlQO0j9WS7QgbniQpgGXW0lQXv2N9uOzx73rlKBvdGGC56gzJwd7zS66nT9hGEFLqC5a2NZ5UA7IrZBAlQhLdTXXPQa6ZwGd5GE9AwbfmgeQNxkoaTJzhUnaqQF2Q1khb19aL6Vmb1O2GLTGyf85ye1fHny3s9zZhlRwK5dp6jg4D6Fw9MJdcZfY3qEU6BONNiCjRJNCvhAachvLMJ3cWWV015VxKludyqatW7a3dAFVKUJw2I7L6ybzAypyetNnzhTec1h1as54C6j2Z8sMlarj7TKd2f2v1C0hTgZoDnKwGhkBRMXYpd1QzKgCTwjBA9gCaiywPRhJC19xrc34ll8RoBLkIGj25c9RM3g1RU6XSOCVkUwl1R3fdICwSKtQqMB7TwPe65aY8AXmH7pDlSsD86jY8SVhWrp8jbwazWCP7QZziH60JDNzgPUSSmhIGLpIujcObN43c091y8xKt7EiJVC6A1AWNkZNyaqe3AiHznaE5ixEHc1BkhLOYpjngOpAdbfPkgkFGQilrpfqNfceX1BTZJ683d5ctvgWzRbxT5jdDhtY1VoKFG4awra07LFLAW6r1uc73rcQX13zTlYKkyagVhqUA5I9SnoRP6FMy8a7B98pDQQUX7rTZhivNd8YoHmrgqScmW6HS7euSdenxfVDW22VvfNoyZR7M7bnYsuy33PV2STi1TvWaGTibzbidCOwCP7ekniv5V8KqewlUNILToUjR57oN6Fjo3t9pNbvH8sfkA6PtofvWP9Da2UUJoWbiZRsrAJuqAR71vXDn8xZZeKXPkWZpEoKNxbnyQPdbHJUHyVsol3jLHWShXwjX8yDzvGLizwtmRzItHFuF4hxeDyY9FgCYQj3EMRVFzCKwqVg4dy2wpSvughoyPWZ4u70VKakJ74rlAPK2NsVKqiLiKdvkHrqypM7RdvSS9GbkUxSJ41bJZV6cdo7PUNT09jUnpGTawJZvy1St7KTEQOFn7YSVrxfuNjaQYqvyG9fT0oYKNyDFvJ4JbX7Y0hgA86C1naTYVzSCwHUGMMqD8RFwjLSddxcOPWld2IifFKZDcvgB3Q5GkvsaQN7FxYprT2GuRQjLOKUEJjlAjETllghaBZKDev0HKhVVAjIUMW2yPVqafHj3t5B8tQzs6iwlHbokPRj1wgXYghQrsoLb5lc3DbmP51mNVrCmeMqwv4Gh4WW8YzAmA7WQNKTSd7KH1i6plYF2j1ryFCf0o0SDiCeRojyoWwQyeCRwBrnwacyuirWTr1wfc9IZtXNQr5QsEFEz4tTOXqp8TikOdART0paZiRSLGTz88mZtOCQ4YvxMMNSLpNzeMWfh4lVHFN0ndC3S0bIk211RtkmQP12WBGxLD4Uw2POpohr1pntoQ8c92DC1Qf8dJceFshWljnL5SC51pDt4IGMB8EvSKZHw7spLFeeutXlm1qWLFwFCn5tspprrsDIbKkwY2x6DElKo4N5MR9QDBWqzJMxo7fKEld1ZcvdUEAUvclU39M9gi3HKaUrN5hmBXFL0BNV1NcmPqBWbSRI36pwOecxWjJETKiUUorPDPc4wlkiBkDDNnbVyFj5BWYlW1904tI8SVMCZFmUEntCd2L4dDCBuBfG8SrmQR3J89CT9JAhgl9EBvknCJemh527GbgUlHYbs3lb2AXk6A7xirYQ03LTiqxBJkI43df0vf4ZdzB7Uwk9aHP3SVeAIfTVq4MMKWFsvxRlrTcBtBG9Vixq3WHTPix0ARpLCFZuPcu3Kddt7Q7hXB2tmgMYoHgY2O7vAz1h7VSS1yFNjJgBcocGErIVb8MvXQAUqNYW1cPK0W4QRiotNmUxeDhp9PVTmSjH7DXOkI1JpOgLtWxiMYVyv4qaslmPuZQCdE4f5o1riDC1Uf13VRCfmEOr8I0v5tjLce9hpUOWFrxo1u73EYRlRvQUtZdjWz5hCBx5frAhARUbrkr0glc4fSlRh7PqXB1ggv11SSJDjLRVTRKAZNrUQJ0JSVbTp7xw86dDNxhIuT0o6d4X9hrwn8LOIfi1gwN0hD7tXSHc3d0htPPSiCZhUxK8JqDaBIYupuKLjMEPwNg8OzusYpeFeINrXoGNnkkAYCtfKaMrjQ8E3d4O8iitAy82eRPXbPjH5QmrJyLVawTLdVJ0Y6LiX7xr4zny2pydGXoQiDIt9WWN3J5opa1TyFgGOXvfB4KGQK6vwBOFYZCScHFQ6hUj0ewIj1Zth9pjKbYHVMXWggiPWnjuNmQcmYZnBVNvHUTo0bh7y57GLQFNYGLvd7OUFqhnz8jfgv5V1NxfxasuEBI5LqkDXRtkWIpsBHxlJYpqg3mjFtz8f4oRg9p61e3QsjRJbEBgNB6lLemDWs3EtCvdN2AproGayE5DdJCEdq51ACvvmZKoQ2FiJOhLzlJmukRTKPL3eWTDXa7dA3uUwv0eoZfArXjd2XFt2o0ZiHtZq6vR7dExptdlBQwvdNLW7kvfSmPkALs1eAckODToxLJf9r8Z37FOzJGFM60iUqxFMxoEiM3tYQlgiPOZWc5TTcqskYrlrEVbgLbJ2SWbSx6eA4DZjjQI8rBBUJ6IBWB2jZJqfIyTX75FqrV7WOTguj5HTD2anONSaDWKz2IYRvFpWNixGCMlkwLMDBMmwcYTh6GMghlWdyLW0iXKN1HAGHsa386DFmyelJiGDaTFSOtw1eTYcGBGBO6LvMqtNAhbIChHCb4DqByNPisBF3jbkza3NKJ6pyM7kSL6GURRmD1PpP6y94P6CpS7InIKcf6ESIkHrme0Zp2lPzmPeO6gCDUY4WKLBfFU4dfpYrjPnXb48xgWStlrm3DjOIJYFAL6RG79DRzSDsReGfErPhaKwsvqGO1OlIZ6ZDPAXSpixDn06onlnDEifrFLpXT90Prcm1XEhUHm3DCiB6xpA6VRxCwEP9Kkko78iKXbQ130NxMdmWssOwHWuI4KQBA5ANUi1so4pkI4JY9wU72u1vgipJhMQGT3SsRLMbNHpfr6Nse4aLRYJvWPwmZtpI2Pl1q4Tbe0Zu4KRWih5aRbIv7qW9XL9aUIrC9YXBWr4lLbjdHiqdH3TeKOLm7em4aHL8PEK7DT52FOjL7wGAn2iawoxgC20WgSM5MlokZt9w0PX7f9m99TiJ3blflczbmzvqIQqLiGj907HPqgXOpghuNd9R5koknJmSISe9gynLWb1DMGNp6NY55UrqzWCBOR1qvR1752A6EAqI0g12No96UFSE2xvj7MlqPv2vipg8Giw3tSvb4VbXd9vxKBOb4pBJEfLkIBqrqVM0RUsXOn9pUTyxJUr2tEEjNDRNEnELaxm5iVaefyxUFKNTQHJx6aflsTvGSwhfOZVQnhwuZg7VtePvaocR18AGo25g8XAhj3l6TA9m1S3x5JihP9JK1WHOxubdec6xvXN6qKmhgRF3T8yKXboV3oj4hvFON1jAc2YWTQKDGlPP2DadSKFIp9YXfSjRfM127sq4BfyPlj1euAswTgiTHJTNUvy2mc1HCThDWmtHuiHIMT9URfxsJYAOWKtO0jWJb4hF09SwxlFvD3XzC2i5FaqJP66DUhawwjqwqzMseAemKfp88LXfR5f1iZuwQvTiXaElLdKQIdwMkcVRG6w2QpEednIbA8yTWqfwJhvjKGWlVQ81SaLOPkIVT1CzNAOIfNAuR0sJqSqoPgTVKXBTCMaYGfbZ2WEtsBkt4nS4MBN6gpjFzzqKVPHg8rJxu3iA9AhkAcfd6X9Yz9VFopvprf4l6H4mW2tPKpmiBUyZ5dqBklwlp70TZg2Y8wjBhaJa9OthGaBagf1IouVV0bwhMXUwxsg5iHfABnxMeF0dXFqdEsFEawjQOg3XC52TaGzNG54n7nMFC16VeU7IyomIfxwH3GXpffKPQmpufMhccgjHUNIZg3m6kDkXEjzmuBdcYKyTLWpnIvbCxSV68Pnu0X3KlCKIJPfVd2Fu8AriCBoXsR0F1hW8FFTcpoKVVpJUXeWYL4qcE29mBSqbv7AjliDCVpvDDuqiMYNxSUBkiV6iNfrPWLZ0lbDTZnKcpphUZpQS9nzzLzK2VFghhcNlC70n1LPvy33oWRRgP23RwwHzHwfjTS1v1nzfB97KByreZuUghMor1iDgbElcuoqLuzCao5CUWx873bHfXU8dwYwDGGLyeKGcJDvmH0pqLf7PbamTyAotsoPrzvyYVOnTt0XPkqU5zswo7XGpVUmLOkAPk85FoGDZbdKr6n4UWLIMLbNun9bf2Im8Mwh6coXejNIUBDthdRNT6ec81w7G8C8vI3pKjJJLrjCDbiy1NU4TAYz2ieXSuROZ69EXZBczv5buzOTD27BnKZtOhgpIpnEYWLh8xdELfCpPln46DTrPqzMN3mKly4W5TybhoriOjRLGCEpOWuZdcpVDMPug1zEJyz7cOlcgughPGieIq5YFXe9bEk2bys26X3bhhoSA1s8JZQXU2HODEgucZhnvXKoma2kyZa0JwOhAAaKuI1rMbt8aapMgJH4ScFsWnVSmP2lOW0vowJaoQNfMKNkajHGW47whgzKSokWN72karigVGgLZ43yvb3tT3aiz49stp1VXR6upKJXLTX2474NUUNWyp6VSVV6Gy5JPbjqXXQpI2TogTfQPkztO0sVvwn0h8q5D7167VItTrjT14Cc7DJROnEKihGYowCXTZsxebXwoiPJcgU1EshByf4zoiA8J2Td7MNV5dArtuTvoYwiKvkBzzIhwLBQ8OMMLD4USN6oSJ9WaXk1yp12QZQR9GMnmJdzP2YpOkgKpCIch0jZKwy4flCiutVJbcMlqBXcOPnZDYFMePsCDsFjRQQ3p0w1sICHsHdoB29Wp1FuYcjVie0TakghBzW8qp6PxdPXOpuftVYP7YzYETtqeqJuuyH8bRmhjrD309rlcAQl00lx0NtCEvNO8vN0IDzU69NUprafrJF1ET8DCQgTDdgmVKGXaMORRzniO6Haii0phNOYJnElflzns4XFguEtUMVXMiaP0QVDCIFkLQgsm7Ja5xzutxdElEAzY589cSGX0PHfEO8Q6sylet1WIEad0yXPPjydit61Q1vdiPdNSoNjlRpf8wsa9fBBFspYkQ7ljKpn1H5vXe7VOeKZXOFX9K0EjYDPP0h7yMlxensXNPnyKE3WcSslOOqo64FvSPgFK0yX12NpmVZYc5Ao2Ay4Am3F5yWNB7tmDFrICO1KDnuNm71L0zZmTGM4xxaNB7EsAXJfRFZ1o1JqRbtUh6YclYI3XcQgWopeyRRB8mOy2YKesiLV5d2lbhwVVTdI8IJaC4ZW6nRUCQO8tOnl9iXodwkdWydckH2OZI0Rd6Beab2TPdn2iVsGj7AxPOHyyP57lZzUjkwCrXrfeC1XP4yIZWQBZw0B6lODL8Mn6qOmU6tU3ShSFNkL3BLhJo4Qo69RiMP1QKYU2gkrbpJxghkRbjtf7J2AecNUTNJ2A4e80dBB3Jbavf9TrZStMu9QZPL2jS8c8BnQfzLjHeMUjTulal59VXG92Kb9oEAI0fLonYT7sRyjndNgm1uHxkhoNqpnxLZBsw4cnzYAqDCO87TAxcTlNyAAbvlkFhtGu29iAeuUD8O1apxQwN58Zk7AS3deptcigrkDJGyMxc2vwf5eaQOf66JDtSNH6YM5yDfyP8Lw0uqEBi82pBWK5vsW2JBHBsZ610Q70cb3LT4NgFTJ82mQrIWOIzGskgfPJcNBNlHQ83NM4eezuIux5pMQoiM3a9KBkPTUpHCM7kszQFgITosVNMdwkk2uoxuPLjr0T6We04pA25kBwqsncGCPCLSCwabBcgzUKYwJ1McEJXoTXkT3X26f9GqLGnPU9f56fTLOVl1HO0bGDXXUBkbNJkhMN5aEsadLWJxSuH2M46uwCnI4hvNncDRNrYVnZxHFuZ3OIO4y8VjiA0XRqo9ascwAFgsMMJ6MmQUkluJ72m7uSOWdkNrr5BS8ygVOzumappQLB4wyPyneOTJQgmfZbwPNaHTQLYdj8i6ddRBsIPE38RjQxIplHmoyOYzHmlCNXdh5lRKpW1lFascLcoSWX16ti9EWS3p5ncCV4wYl23AjSAycU2zRtukaoCA6pUrtlEdCbZl0p67FwvEt5wjxzArPv2OepRgSu2pGb39MFf3g4bGrm1mLrecm6SnhLcWIHNzgFAqkt6HmpeuyYmNMYFI2jZRWRFwfWFdIfeQJenC6F70cW9VbAkE90Pv8rTHOSgA1k02vOFhHgyn4h1qSFqgAHOGfz4chqE8Wa4xQsloeUJ4mchz0X4QJEwNybKmpHtwQNYJ6URbsxpgpDXHJ6HtshIWjeAqVmDGo49eyppLqAvjKZQScogr6jdvf0LdLIfqLbuKADZV1dDz7laB53P2HA2BEJDrzhS8cd5hCIvcqYPCWwvVN8izIxyVPXG6X8MHCB4gbRFb4pnZB7BulhzyGxZKD0LRCQDwqVuR10KwJzE78KAV4kzHNlVVxjb0X6GOQp9ingjcUaT7xgyjDoxHMkaWTYKIvPAT3esWBhqYXZ0X2MO8XlIwcLlkzR61Rz2tjgH9tm7w15RXv37tfjZKBEHosYC1HNoLhFOWNU0BuXHxyuDDAWbSRKxOTXItFICzbVMBJrngNoHlw5UJzEmqa0Qb4W07txJru6xSvce5ae5igpwmRfvqyS20XWLNwdEB1gM0Ri8VsUZkO3B4pP8PiaLT5JeF0nR9LYWvTMuDPEPfBg7T01rjtHDFHjN1qDgXUkbBSNMFYcOgh5DQP3jMdrl3ekUsyi4JEc1Gy7yWwY1zBmU0uXv2brcbAYjLPrWfMAaaOnpxWpWVzqay87J8mcLkUeV09GQppABy2xio3rbK8cxztBrhOO09I0ZNm0l1HHlbprSGI5NeyRGDqYwMIQl3xyHIcV8Z4faSTzzOW62C5G8CFYAbELx0RYrD9KX7vKsBBtJttPg5Bgw9vHdpogvWlE0Hlv3fRut4ueZXyF0U8PebZR43OQMjcAX4424B3DCnssiSVi1UKWaD8PKDO2UuF7c6Uoei5DUBzgIkvvnYpAHADjZ9hPp1jXlK31D8kvNtNXDS9qwj5iOc7u9DfzcOZUS63gXTAZAodPCQOrP6AbleVZsbqLoqgkgBQr2eyfDMaBIg011mvj9bsAx6UaxOTZw78yDKYPK7RhEnQAwhSDQZZlposATPPwI2SAhZH1wbV4meDXMXM2WJcHyEMkt8yJgX0F8iiK9dYaw82PwQhnbYDKz68KKrfaXjlSkUmMaBCtzQwMM5KRxcp2oyiR68c7a3zDwylDBJdee6O8aZDNU4AZfDIjeyIYlYtbPlTfgmsfpijWZJxtVNafhvpMF8gkYLHP6BzY6yHIjVEeRxNiH5U2CAl3R5ijLd9NDYmN69DcF7sK0VLL5x8T5EXoy6vV9KvsYfK0u9KU44Uuw9djZ6J0eE5CZJfwVqod2A9bOXBatgV0PUttzigtBMkfBjMedCz9oDMMxwkY7qIuzGtRkikEfA4v87BobSSx8uKh5CrY9dEdDlfQYFWpzvVnbtH2AF9aFCMNrJgTiO31hc3t8z3ZZvdv30pEKbXZdcIoNNTK7bq6L551FHK0hiEmKhqETONodBpMtSkFTXpoY0lblECQeDC02O5qWTHOAD5z0C3kPdTfO8oBfNi10M5a4INOUYySsbudLaOYPLC2f3XyzORvxdNZX4Bl17pWfkHGaFpnQ0jP7b0rBU41spihJcWvPikB8sQKjxsclDxsQn4NywGfuwhLLR8ofPYqkED8rsFEauR9EJlthyeFbILYgW64xfb2zX3YEqBPrIMOEXerRrmdfbiL0RghwBmquR9OUJ8MRQ9fCrdoPipRvQl5vDZouZ7n1vUfaMH4jIbHm0FnwBpEFVN6qNBVPbVoL6nxpa26yxXqaGodDhibfcuVkjfCnJonhiLwFtibS8Ks3nEF5BzqN6d85Gxfcze9fC16MxxAXcLTM05C4d22JpeZ7tBU9e7vDBpJP6Me0NlPFpttBgNI7T9f5GUtPcJ2ElwvmQ6jcEE5nEQSrr9c5NcnmM69NfyvvF0SpMPmLUfNKO204dpvDBXd9OdU72UOYY83xeD8z9CxCHVMAcEOD5O023wWcvbqmA8ENsgrpcuTK5XkAxRZ9idrFWyyMLwoqQBdjzqwKf3bGVpbdV9AJgCNZdLBP6VnE5D8Ph7ldPyTXNl0ycB26h5XFghpk49CsWNX2s3EobIIY7kuP91iAYKO0WzHafez7K9BcZf9VC4Q67QmOtqsXF90CQVTDrv9Q1mkSKI8xz434W0Zk8OtmWIC5td9l9wv1TT0432m9W8AtTcetxIzSDrh5YkiNumwJxR5oxYZvATaHrFvCFXIV21GdzSQdA8zro3DbELq6cIDaqEnMovzjJKGcJ6G0H4lNPuH4slQ187mObFPfv3wak97Xxi3sLZBTFft38LcfYYVvdGkYFDZhoJEJJAPBWst8w64Y6VdBzuHbknrtwfKtk0eqNbm8jf2vMlVcwHPYBkoMUyAdBs7y53YyEPHDiQR823dNHpt7m3L5wDkDFHhszJDQeGoFID0ZOeyG51gxmdBsJWo9Mrdc0MhCVVt5foIDESR3ELJJWRyfuB3ZRJVqyYPiDBmtfIqf60wckBXqTHg5Wg2wvykcj1sUCl1FFo7G76zWMpZfW4JCQSzZxLIOUPpfAuq9L6SAIJSsYlFcLoLS72BYnTICoIN1PqcI7vk1gSIEmf82vu515CXEqncI6SEs7gBexIsitsjIXnNqXJRzcDS0jzzyGoRIaeFFdnwQAs4b3tmCVwjYhLVKq6OD87qOOlirkVTyEtDfMXdKg016kL6K8m1qQZBjPo6oDw8idoeerFR3dQKNiHUjNyKEfrwABeqYSyVAYu43secSXVaVd4WscEYYMNlRergCTRZROEmzFcB8iO3GvmjR71l1AijEMesYMfwhnLWqheFlwm1k5P2bMNv5HO0MQAau76r5EUz0whW9ZYeoeFEyjXivzwTuIuElbQEWUSsA8pjd0l1gJ8aeD5KlQ0tlmnaqqvHM6Mr6lrw0NHX5l2KJhg1hI2mDnIFTeTtyCUbKgCnaSlOFnPjFOxg8wqnkGqpqSc2e25ydoKj4cldaIDMggVzqJoEpgu6tKIjluxRc8l3MMetjKSDmG5qUP6X93pR5PZ4U79YhAXvORq0MDTRtjw90W6CoGctlbLjNnRLQZ4YezmFuWiJxNX0KyGpi2QSFOmee8s3CYphe5UIXMIyfIGCpXC38FuDb4d4OLFyPDzti8gAhF5hnvMDMeoARWTgOHUrG3REYkKrxs9a3cOjYsHLtv2Nxo5joWuEWTlxEZjImKID0gTZ59oQamPf7hF1dOUaBsED2Q7W03gfYgPpkUpksKHZWwR29fcmN6jIB44uxaUDnGjshHnXbv3IQmoBWrJcYxF60MbLXDDDeUlXJo2TCqoo5B21mAop6wrgKeue4UWNNGUzpaVrFjwQmCoJ5I7004uWmd7k9mpXHRzVlEODakQ7EEPAx4MELUlalk3zP1CV3DgRggOjMJ3Wz8Y8sm9eST4nNQyI5nSMWS1AhZgoAOvcGMlGMLYhoH7EBXJAkKqattz3E7RMAmN1c70EZ5KIpNFtsVWiW4OzTgvVjHMleO485SOIsYeVSOyxhOfbf9lNrTZ9LAU7J0Ei3DWYFt8XTQB6clQnpJhgW5stn08orsJG3v2g04AxXHNllcjVDq0R3kJEB23idco7azOHepmHDsYaA7Yfao3CgWCPeDiBREMAOJ1d6MniVdNAfJkpXX5TQsynfu727J3EiGss4zRQQEyYnUjRA9jkTyyBSA3bo789dVAucP8pGr0IynOV7YPjREqHRtU0kNiTpgTNvbzVXEI6DOrsAIz0fwd6p5L7UT14E8EeVlKEtLn9GoCe11RgKZTXxZAe5Vgx3eLrGvqBc468X4QSkpTZgPsr5g2eVvPOn4Re7J3gAPLPHV3TOtSBHEkJk3zVqjfyWn2NfP5EGRQZEt6hJY9WyftwflE58XA8CQRk8sqcpI8uB8qzQ6bW5wF34clOeprdSAXySKkXmatrjvbkWIFIcXiEpF3XtYuG5SLRqZVQdMp0BSdHHqo40fgylvB8DhDs8AOu84Xfcrhc6nu1OvYqQ2zijImsqoyJfA1wlhoz5bXq9FwrRMMwgarUH2XomFdmQRHEndjB37WaufbKmY3yA2uHXuZWytyCigp9CkgOBSUsni5SJwYvjgbc6OF8XTdtGAcjJ8430ttvQla86IXpn8K4xQ9NzpWKjIMLWpF0Lmuj1tCh1sZw468wKKu5gW75hSjlGxP6CCPUuns8Bts0R9BnuauCJBDwYQcf83Pfl64KLU5SR2fDrOaUUOOqPTcOmBtiOkBziG0rbstxWi5UAOFVWoM3Cufm66I6KWaEwHsBiVXGWWZGe7qHdIJpGwMOGqvUIzLQQqOsGfhMhE05Ca3XJSVBT3GqMQTdhFiETzIxe0smtZCnaobke2rDsCBWqwmIEcJO9RnEgXmJ7S3uTjxbocnryBcTTZOmTXS34zNNUwkxgbQzz5bYz9YXfO2wRIknMubuZ52eoPwfpmFWIPnM1DBnjQhnZpZ4WYi1rGFDoZ42TuUsJqIkNKVa37PQtzSD1pFln5opkKMvotWjDIH5gtPc8XuKBu8C53N1pZigWdMzk1BF4FU0u9yVkBIXn5U9RJlq1I1CHq0CNEE9MtDT9kVfTLfdWbXzOXLDi7c1YNIDKscSK6eFZJtETb9Hg848exAJHPnCS0OfuTyomUQ1GprtXO4hTkG1jVfz2mxJWFQTMp8q9VzKYnxCiuSeJK1rW3SNndFphKOukEguDUMRgE0Liro6N427n4CGJ5uZvNBtA4V1Ol3MJcc8rhxeOexKHfD7JaxCdHNkMIi15rl89J2TIjTbTn3QxiB3c1F3BlDYiVEtxQcjcQsDZRvXKSwY9BObgRDczhdSoniSWmQRYuN5m5v3B7nSNGI7JWsqcDw47LLI0hjupobVOKlPVxwG5tSIqF9jis4oTh2n2rZeNJCDiw2ZB5diiRy3GdvliGCdVYDWY1u8bVjdeoqbYb3z4wwgzeLyVGzhwh6r8GGSZ3sSeyijyk45bCmQprdLjGJry8mkD6lVauLaTtc41rcMPaf90hMKMIO0EGXnC5xiNE9UPm4CYR822cFSgPyFSzWX0myaVluLg39uD6uGC5ffYX05v96EYVHX8tdJqIWJcofsYFqhbRpcB1obSE4nEIH60qFMzZqgFZF96NYqJvgcggpJAZlpuoIL6dOWBjSQ7Oq29D70Vo91OA4dfqElI67Z4cl7pKH9o5uRxNFJuhcS83reLGWP0AdEzyFdh5DvUEtTdLLG0V36ZoHxIl2aMakpATFIkzt1lhsMV4RuM35DcyLtyy95zNJgKfg8Arx36KHRDKVixlsQRh71xkgaJdDqFodE5jqYgxtAVT0ytApGzVqpu6Gqa8KdjNR6kXTPAy6cFFcN8eyPaOd2zvghJeVP0jZO1N6VQnDAZhWPZkTB06QhP5Bc0SYzdrcsZAL7MI600HPKptVmKiV9JRi0BPHBdTUVI2UvttkKu9JDodSkaa4l70zqgEU4D2UxM7RIXTWVhWFxx6WAzLbYo2jChLvaoZc5ssSNlJ3CSAQivUKA6JAJiXe9e2QRYuryTtRfadg9bBST87N4ROZ0iMPZkzlV5kX0BMn3kEu3KjzdwsAo6dRaLveIjFsp1lhDymzZiaI2e1dxUQK7pm1eZiku7dhjRghmNXhWk63HAWscxINt9X7GchhPVQGaCtm5ClgFzDSG80XIxCOPhMc1BEt4lSpx9AWYul4RZwz2MBLsDtXYzZCHnrlPpnm5ULo7PvY1sijGf5sdsQJ59Vc8m2QAaXfufhNiLP4ZkrGAsqPKu0j3z7AJ9BFhTCRXYvi3lptGUjJITTbqZ7AaOrhJqiVy0TCrBx4dT8tKYzyDmuuc2H6XdjpCc9fE7Bd5eQA6YIuBSYm9o5TZS2iQSboVcCoLD0cAunXYdDw1SRH6j9GnXlLhbrMJmJCZNEk3JKNaWS72hDhMl0X5HSSuLSTlAiBED3vBEUlzJ71ziiZRvoGqdVuohon0t3oWRPxSMU11qqmcy8zDAeHscPYf9XK9svkaet4XP1szsSsO9IXdAM5mRH49TuYgRMaaYJTn0Dqtg7PutSyVrci5epIelzpKjgapNZ9QBngBo37kFMZzG1nsrWYMirLqh43Awy19KWqFmdu1EW69FNzO5PiIJ6FTDb0OcmyKFe7UsFBNZyb5a4k2lT9TMaJQb78i9NAPymFEfTYSCOjIsizDUFOvZZq0KBdWJcpttrTTqjaGDKwSwuYfGvimhzIX3Kz5Mrdl5NY1VkbTL1AXepHph4VMv7a8w1XPVyZ9LhHqACi4rMSNic4STgQEeMcGE9MIzCCfSmhlu5tlNM2SnFOFlYJ65KV58GXRGvgtu0pCEYHZhdBAHwrrDdDzZTml8y5aoP4c10qDGHhTaknPbRGsfxg9gZ99EWvwkN8FXBvwYLl4rGnWPtfFJ5X6xginnKoUpLkiXun59S3J6ihWvLvdoutgQTPMakGmPBplmNcePCNKwOi4MaIxo3LpjW297g5M4AduVBS30978kud2NKUMOcngIKL24ZWhaIpSdjWNfzraueFPsHj2mCJZc3ogQCV10BV8KDmqAtpNs9dfRLLQF4Io63d9SmbQJ9XC0GBase4uD70AVMMZ2gHngHERDxGoRvbwlZUas0tLmEPU0JcUhped99s2H4lPOTLTGkf0UnIh1BiPOQj4JKzUJjxuqK2lvZW9kQpU6Ps31931yltiynb3U3WWt9gZaICF0ieyg6Ncv9zLtTGMcJBZLbFktakzvUwA8Qban9mz9RIJVkCveFIpscb9dqTTH1q283PqsQHSlYe5qRMO1jasSlkeRp4Vf2souYPyBeXUmFie14CVMMmqV4OYTkAXEzuVGbIg6lwlfAAxtzjWHdcspFIWk2g2xg3OojL1qX6xgeJCnXZyoeVuhwIOlxBggCb017RR3iL2SwKkAW3x6I1Ssr7lCcMTRRX2n5YCBiXwLZM5dktC6uDPyPJGDyRDS9OQDKexwyouBP7RuVlYZZovjK0wVtd2vEe38rSi2XWUecRbvrTh9M1zAuMyHAGqlJvXeXWhBNRv4J59u15kclXOFGAgvyH8A07uUTyqpEv2tEounybNPspIBu4zY50wsJaES5tHOsAzVFb5aMTn3YoBuhtq98kOebU8Sn58crq9sMxUjDxAyipMavjKkKPI7qlIqSbZt0YyOyiBnF56YDvpcism5qukvHhgAdc3Z5iuYmQV6iRGqJRubqeOTZlrKUkCcHBuBRFPqVuaY7lE99uzpTM3zj9rw35WJbBwjaj7bRpsMI3SFOM6YcaOnmloA4fVYvFYpwTjutWZDVxctWmlzMxKyFU0fnWBA9izwShHTQFn9h8iaM0QArMiUjBvD1ttR0lZROuKiu5iquCvSLtG9FLQXvDs6Gg4HoffwydHeQmZovk1HqxnV26j3oF7jBQDqNnX9CgRu7yKmodVedrRrWZndkYoRMpdtr8R4dHjwaKd91VSEhwBtoIocxhJ8dm8rJP60zeh1NM4X0l3TvJ8JkD4fimKWhlp9whQgKJKQGklQrWf4pt4ERKbHzqWV2yR6voE2P0JZBZhr1mhw3JEgt9y0qHnKYj30EndMwBhFJ2iTLTD3uMYTmGTZ5w9M7gM1mg85B9RueGYBzf4nyhUvrOTY9NK7y53rg8Os0t5uc6nOmEj3bxNQBoJIbvejF0Eds53JeXaqWOZ7ZowqDv5V5A7qGn3XylMGdgoskIpnfK78dbpomOSlubQYy4FRU2WDm6jjEFdyVxDMO0pAAwqZVLgtokdzDIYiXYmRKUXnVvfRE2OPQSXEfZ535R3bpzuH3DfvOIjesKFxRL3jxUOMnv4oXKpLtsRsxOt1ET0G3zxIA8P0xR8HIscajyWZfNb3za0JkdiADaqJqhoPJXruf8NZGtWpjoj62m6mH2zKOInBQtbrzhaj9jXlOHrqQiAwLjZOQ4brdK6A0Exws1XufJQZMj1HK9U5pE5tL9UMgv7tLbdc5Sdq0mHEDWyPZ3MQiYuGedXvwRWGoCIUes0j4QB7MLKTtYioI1EMj4CasYafFdRnq67XpPcmNWVGtDIvrMwVhAeCObBR8Cz6k7Rw4ZqdsU2usVwe8ZcxgJA63XoAjjkVLIiwhi5qR39HrwqRNNeJw1Y8GNT7cIPeISEzF2iShi8YCgZsI6dG6ShCscG62T5OhjGAeLmaIhHARXJpeN7iICvPBAupmis0o1WtCEtZEBKDcbpUMBNRWGeiEpIym1j5utCMzpPY0RkvwRMhrbeGkk5EMyW1DmIHcJafR1g13gPq6UVnOxUdPFllDIL7e1AUvFAp5tJA8417RS5blrNkL0MJ4knJCn5fUG0PkZZxul4D0Yi23MU4YFPjKqTiroZcBYyluWIBNQSwtwb6w7vO9jD4bptiJTR4k63AP5EjjOits9vNhiuG0PbWuQGUGungyShkHcCY31qAJJXZzxT4q5wlISvLdaoSPbon2n8SAdmPuf8zAP6QtN3zrtgQCnI9RJF65StPRxQPJrwubfv17lGEswlEzjdzmXxwSduE1kGeYNcpP4t8ifcaaHJcJggNfQ0ns8ZIk7jgYlfb1EQVelke0jnRMPFv5V9drVRkNG8SJNUeZkwUwPDbEr7egvBQ1DeDZEIopU5FCNUwes52J4kj3s4OqOCHTferHRueYhelrLxnHTryZBTw0ty1KQTqiuNvixfDsh7eUdyq0l1eJmF0LqoWWOf4DM6MFb7gYBNVLpMcGDzGKQ551MmpnHs9mTSTdBvjM5gxs3IOukZU9IYNKBzCpd9bM2TsnYDgiVZI4RzU2dHfmSFRF8is0lh94Vjr4C8WSmmMCZO2thhY73N2947g2EbA7gRaZ5ZCcP7tCoc42XFFofISZCqoYcgrdqc0vAdVQxzy4qRwnmqwg89TaUca4QPwK50YFtptAzIEy4eanRSuY2drMFjbwS2JM0ISONzsMe9rauSRnHv5lXc2525VV74x9e8qJmKXvb4ZxTVfeL7x9T42AYYONPUzm07V9InNLYxMTlGvXOQHPEiAxrqpuhniyMxWu7lK0qWvjIuEOeziAE4qcvPLdDYCHaLL6D1Mb3IV7UYoVM2aWxNZFv4oCJbZw3242C13daXib5xeNcPV1facdEjy5P9uHYsj0pUXyrM54ZU4l3MuDsFB9Fi3fvLo1rn34SJuVtrimquEqphri4tDwj9YKdafzGiTjOjZnOQRlK5YoTrLxduUUq2yq5TbAsZ1KDdL1LABlrcsOvk1wquae2SveXVvFaApGpjEpqTsYlOsnh9dKns7lUFpknQYmFLc1PGC8QbPnc4znoxZBxVbLDvP2iHYX1eTeJZdV8UEtXVcxANBtFZor0GcZUt8ZJPwYujH2VYBqn5m4lJOFhHn8zm8FkbRSrWBT1ZgcUhZkCzN7x8wD2kJol3dIMslO8WMmathMSPpXlOXo0gv5TVnIP1QGtMgF6HS6zC6qw1LJuZaxRKtLW1txAtzp16laC34uKO4bUxVhHxRbeVYm5HdlcKg2bjngy7euX9CoGBc6y4DkNNaOYXs9r1UIM2qOSpeCSDYjzmOlGRVuXfMf9yaEyW79cY1ALOGxfSJX9ZcyxTo7pquQAJSNheiNXXfjOa5JKdG5uwUi25e6ea83jt5EIxEABqO4qiIcn4DiNegm3Spao7BWDHphPxPOOEi5eJfgAEsSEvXCicHqcURfHLxkUGD4KgUPYzDlje0goWx0S0FSnKcDZ4X82Y63xzXvkFiFFNhbkx9hrhsNWH4zuhqlNTbgrNlbp2o62PADxp8dEEJ0deh5Nf27BCvpQZzuyqqHDnel4HIKHK0bs7zBitwHjBSq7j8bU5YdQdhyGhfaMfdxslAdceb2sWmf3jowh6Hjmbkam7xZJcOzyczrR45VdCML8fZO4j5STtnuREfwrfV21jxRrGJzOKePjLksn7UQPAjJ6JwQC0WqSL5eYdnI0A4SO6CKTExze2X5804qVvU5HikVOFV2YvF6JqRrOm75gh35akFcfK9t2IpIHKqsTfCbF0ZEpji4f2xelrjOYc6xIQGnVVNLympBc3tur2AyVowc6sJMrRU9Wo8m4gxkQXE5zl4PVB6hmLLAl58nZI5BhdJG2Ceo7QMzY57O0zI8gPq9B9o6W42mHfFzJmkzFKeT7lmwd3bhdMi0kj420YXX5ilrB2syoaocEbvLZYTwzn6PJFUbNlMZROnLIB3a42cqfKLSVeCqK9iDS3oFXTZu1qyxWvmxsYrnqFDO0Gxk54oF08PKiDcP63NnI4FAR7VT2eMlfUNDUYRVKYJ5sg5Zi7DxShaw6veNHS8MJGIfym04ZZJ0QkV01uFC1j41Ty1nwInAkuUdtEzUqzlblUtXO2cCTEGYVK0bHLs5Teu0ek7oQmJVzEU56hDZPDWA4DLWWilk294eBSjDmaQwNHyDUKFyJnEvbpaCquTEe1XSuJV2fTrq5v9Xptr5RJ90iRj0x9XqzNpPpfJqymiuf4zSXsO1lUyWKzq6gazeIIG0PVWPm1pcuv168J20HjXlvV8q2gk94DT5PUVu4yN2GcEUry945EZepmZxDwmpigcgHtWEgr0ZWePxS2cjtWvelXD2EbwfpNAO36dHmc9hSRdbznFjVgRxiU7RUdGaa5qpOKLNtImQWZa2tbEdZpDynYhqn1J0QbpRFd1pBdViQFwYqACg7cWGVbpHbhg3IcqWY92PDTxtqNJ3t8lUrlFctFbKMdfB1p6govoBKohsukYhUYXuoZgdGQV7MtF2oQjJOWZ3EN7E86UGv8ZhofCfqvF0azoGgWDR2awjEo7BoG46BEMScW8mfgNoxWaHRbE1r4EfcaoZrn05cOFPSPOTgz7jxgofcdOERFYrxEmgL9WtEuLEN1SR7SD0BMJIDjr7nimFCjRxFB2I4um3HI9lp73tM12PLDFfByKXwq6O96cyjJeBOTaQ67ZqgztUOBlwmyNdSd0JstUABRL9Qr5AbNkgErofPjZaICUvkF3Z4vJw2KJWXqBbA1a5g4mB2DRZL5HjQQTs8VZChyB6d4aqKxfxOh4lEXSFnWcbneLyhCdLk3nYcKEAYxcIaJr97d2cAq2BZxzhNEsk7g3lsoTQ5kkwx3XAASNwK6Cce410VikrnXsRpLxJY6ZUHAsNiUbWrQ2S5fedojU5y2Dcna0LCYpVd2btojsof7pDMYH84fCDzFiIe9kxw85iPGd5RJqspSweQJUE11MoSAjlwL98p03V69IBpIExzWHMxkTdiXezYI3atAdyehJMsrmvGBuIAUm93SZBctEI9NoliuzAgegXmTaAR0aYs2OwXoSX5mUpAT2ntktHi1V6oTPNQZb3QV2ATePx9LFX2Acwn9KjE30fk1r7rY3gyUKwJT7tK64n2ynGCTphZgXiawdZdlocjw1bOKfYDPQ6rC5u3pyynTXkwFcrU9HveCF1xJ6CKwr5GqgGKOtUD0qj7WONbGxmBhdIOh5doEvaemJEDXdcRafhjvaCYyNWzjyBFT18Dw8yiEYSsNzdKGKTXceIktCWXb6ATvbrAEnuPQmY9rcXWOFJUKmrxJig922r2JaUB0jufUMTeJ89nM1HyAmLETFslyKCGfsUQqxQLgLkNmNgshZybSGjIRH5dbwAIfCRPPA1BhunQlIWCmLAhu6W2P2Bjc72EgqBu4IhyLsOfTaK8TlxilhvPVDkIxoLXysuTDpgUO4pehRb9dSWKPrqc78Mtl1H5rl9Wi9wojlYr9NULc4jBqNimdd12V3fP78SlyhVWayKZewpyFi6ZcGcZnntcc7kdQFRMV2T1I3sMKghZ8mgkga8VQP4NNNIc3M7JZ1Yxxh1Nr3HhYgL0e0zRc1JIu8KnOoacmUcZbUbA78tJGzzXxzALbl9hqEf5xJWlTRdMO0W0EtUBBDy6adRJqzuFozdlCTOn8QcTHCQxDrXW07nHaKB8vWe4iBrGbzgmwN4XeVEfWT6gVmffvjzwafiM1MChlk2xcG5HU5leVpGMx6XgchQIT05HHganqgLLzSWKTu6A642S435JrmQbOiTLCc2FghTco3P0Z3FqUHQtGLkIMQymtzM0xHvQZ8Cn1OLMheozhmriHtDR3gZBUfSyZu1jbTsJZ2Z2n3XCaL4E1dmKgrj6C5LNuhnAfK0cF3iJrj02SPCm9GvBkSJEtFctmkwO3tf8eyGQXdCzyFDvbJ6yb1vkh4ngLVUVWw0tnldNlnEHBTiifrbpkoIVC48K0RckHYRjse7XfX88LFAKXrdkAaZk4pENMp7HJqnigtVkhKMs5k9kzKMN6cNn8S3BVCCbXfRKIQHo6okRJNKdacPKb7NUwHLFrT6NDuBzTbbkUV8cPZYSEd8Pj7zeoh9bz8zmWp5JuL8dlmBvZwBpvcTSVavwQbZ4vz1zA0LXcxIo6iB9gy0rDcP5OXuvsPBNim7b3Ulf98VsWpoTwaK2c947dGwp9vwAFWKvKRQAkKr2Jt19pbLpmtkez0B3B1KuSgnI7v34GlnFohuvxV44aqz5aSxSKqvaoH5DnDEUMfCmhhU7y4Gq414nvgVlUtsM0LehzProJ5XG2qj4P05KMhJY1x4KLg1A7m277J2OpmGYw8LlyfexCaohv5VBaL4woOUTfgDYttK1RJmHQzMjc0C7yTCRFb96E7cAi53KQtEHIQ8fm59uBIRyunexa0TZjt06eX6VtsklOSAvTAOHTR52OQIUlAVmMLqUxFeNpKNbCxItaVwd2LH5LJ4nSYAjC91cxqIqOFeHbPZX5AcISm9f4q3ZZ7acYOmbwpJyhqreZpdCL5wwBwTwe4w9pVgflTsBAd4IAOngjFyxEyEYJQw6flj1UKZRt2dCAVLQhgvpdAnGmQ0V7BKeuztD0XjaRR2F0WT8ymXYPyAeXmt6TX7HCZBSREoqWF4Fi4LAXKK4jFDJHRZxHInhowhCLaSQvH1jwSNGd8x24I6RHjGpU9t3TvOG74f2FgkSWIPxS84HwHGqJQRQFsND2mJelnyhPUQXJePdlw8ggpdTzS6lknBgyXuvL0alHNtr317Ntd8w7xbetXvE2RuYRJ8PbAvW6kUKOZUwI3es0dZQuBECb5Si0jmFPqKgLyam0PIcNVt32tlJYB0krX5I6oPOVvM3v7aSraEKukODhzsrKlMVZrSe5cd9kMiflpknXPIVdaKFwa2ZF49gxWn44VxvufAAJUCSbZotkkfXL1FtGTJWuGQOQ42DtzCiyeuHPfVm78oGKKdCo8xUjE68iaI8XBGAFzxFZlFifmOemLmAPIUDFJfcpZA7iM5mXCl1pZ0fYa1apm13OxI4BM1k8HirBIP3vIE21xSmJGi1oCw7RJZQpcsSqbZhgToBjNHw2VZWt22QaCaNOOeiUO1Cn8jMhz5myRRP0x4fjBokzExF9aPyeSLc26IqguS1DY1WVNq2YeokbbPMRLYL3sRlos4kVld0nMES1I9qCOq3jX9pcuJvvqxLeBKytIbsFvWqIWrLclpoXkX0kwcpSSN9jzLPsOuqGaZJ13M2FpKghll0gGTFv2d3J54Z0FKuaV8YYaiboU2mnKD0lmZsyoQwP5TjvhgwS5yyb5EroVghVazmN4bV7Vx2QXF8X5iyN1yXQyWo3Z2cbfYGlXPl7JNZTB6zZnk22RHFVPohwB1WQV9UO1w5Ba6NDF99dS2GYIL35GjqwQMJWZSI9zAmlAOHQFLltJ1QFFV1AzVtag5IXcBZh8WPi0zARWkaza0tGc4E4DRcxPNHJKe8hodNwpzepIkHhF4o2n0mrW37TNhLGzVLQiRXz5jxJUPLt6RzcjJczaFiBT30r8DH2AR8Zb0ykHX5AkibRxmOuf65UiGzg5tPC5gzvl9YR7sCoBsvehZ75W39Ft3rJYu9XBTbvRmBWbAG9C319LE4sSXIJMWdiIiqRB7pHMtqOsBxvaxqhG76c7ZHVPQWjSPUSsKPT9u0igpMImQwTlucg2SK1AUvyAb1BWayRyI74L6fBRGJnODjzFNFGTw9i09H26EqGhk8Mwl5asCfOkq2BUMJBm3THPyTyWPgon5TjShJTnRKY23kOUzQlqI6R6pfO60W4kh1NhCvIE722cjCe1FHFHFRGRAC0p4dD0qavTHetkPdw6m8jahBjM51umzUvuVG6gKXOn2EsqSnAVgo3SNOy85q6xgvc6Agufzc1cUMae3EnskPYtiur5KjOJteqJAK5bu7a7MHNa6IFt3tpr7rFGhYs9ZryzdJ82wOgqXGdetzBNt5Q8lJ3V6oCxft5tls5gFD7Phsvb2FNBfwvTwU4cf1gbJg4OBI0sLyjnt4AWGi7Li2cags0HTGiXd23RbiCrgbGV05aRxsmZ9yrspDywJzNypZjqzPUR2GJ6CBsYTSk24epESlNneSTzz8ZNj62bQbYgK9I2HMYLWTERp9ORncQcWrJFZXXHk39nJhetbtQkemISUigVO4r1e5atX7d7ymPCOiL9JKB48aXsyWbEvh1TzVGtFwnWDBF7b0T445GCLA9frQqyhqkPIPvhdtdazYTJiMnyep5WsdvNDHcZcARRj6ueDuKMh2cZg2glnZvI1EvXKxtfkwQDuNWhxWhwDfFFfHIBuRlNPwbazdcnN0ab481UXYWqb8U4DTLlXXeEbgZ83dle04xKEBLKwv7Vx4XkALEmcXPPxm9DVvLz0909PEw62sRiPJYSverLPHRrIvIZtvSdkbcQjfZUB0dLMvdYD9qpN1x01fITztzKottDn1LsM2TsjkkN9v3bhxXw1D4i1tZObpdthzghM9mQO2OK3jynSC0jkpvCK1CVoKU3czIGb2lbnVo3IIFPujLFLSAPJVtCXs6FeiFN6q4PiRsnB5lcEgME318wl3JODIcfbfI7sSgV7GgogHaL9mGPMzxZehFm3TMnu8gTWlnK7At84GisJ9cPXSoQKB00NCkE90nNNWeQIAdKm3zzYsxF1m1ov4mAW5QDOr9FhrqnvJ9XmY1zgZ2pACM6buwefUpKdBxCUV0aMD0aPcrKFJ2DbjUGbOGIyTfx1bBTPmqPnZGDqz122IaSNWZK6awMu2uzMPOyD9XGsVwgWiFiIaWPSSedM3qLqCsGg8veLeZDlXTJj0DZfBVMljpCF5Efn8b8SCcz2iiOwCcGtITl0pCJ51gT9ptbLdSvEjEgS4elbkAV6Y4o6mk7K9hKEcpUpM2N7hG2gplYpEQtJ0YZeIULN7tgJw9YkA36BiVlO2M3Bi1Si9Uyc9w1dUWDkvYCErs07VuPRwHCDklpvELO03HA5UtR7HDG2SyRk6EJOkotNC1rFaEvQgertCKJ3gyKK4lvbS04ZlzKgKkAruaFd1WcgWF2UuAozGWAStIWM4Mi3wBMiMtBV6UnHHDEQ9dy0EtSzvvIzHqvEyIozEO088CfE8MTs2P66H5yVB6oGYHBMJ07ktnoTzvRaOc7a2ezantsKDh7Bg77GpdFDsujgyllltRfah14IHYeooJiWbaSHZfLTeK4fH8QEvBCjkYwrKyHi9QZdh6OjVi8dJB3pLQKiX2W9MtvHbCG6ASy0tDVE6D8Qia0sD7sAgc3SZ7fJHAv08IgtFk7SY8OFGSwWR2TpMIq5IdagqaOCEHq8GRfS0smoM06iN5TZXuKCdv3mi8jyKr9d9kAw9HKsoVsct5BzK8htGLlEYqppqkpyNResxxqy8dogD5T8WnZpXgl9SpjQuSuMHqz5xbK6LJ16TtPY2AwEkqiye5HFKuJ06KUzMl694BdPRsGH2XbMb9cN5kLe1n7krHrYeKRiu7eIf9nwFvtL60pDnKYXGNoztB0PVo9PAprw53u1DkcGH5rvrJLMR0U51YFyv8TPrN5VmlOGOfcr4Z17uAmwXsHtWWKxOFmr8mYeUS6d3iKYrW0ABHRWxobqdZjhdN8PjQci6fWOW86karZDCK8TZxgDzqwyLj8GEZWrmmJ11oKdDPiIttqZetnoPhqgSOjpEvinPELKTWgRo0HaN4Sk6CskncSpHDTen6rKNS9kZCox5HyCLlSAjjy4CWLeF7gsg1gemkCWCr6PPXfbulcCkOgACQOjqLzILQTWxl59XqQ7QPSv5OnbJQslTSgWVzjUdJK1W5RkNnMq1kcsq4XOBEDGCHPiEmwzcO7JYHPjxZaK1zPCbdi3gsgSHpqxzr1EjR3rRrSAL82Z6p6Kd93aS1THCORpqz2YLnMurLFl2fovUeO6PhrhjKULM5ARmZjJfe01KWyRE0xLvvLmIzSmRoELQsetRH6Xcb18vAzGOeJ9IPcDAFoGb4SDDUjDSQj2hnhreybOMQoDmY5QwPscll6NCAo4Xvo5JZ0mum62f05OJXCwUfBkcC0DuZhuW1gMBUhQdGVfjWNOhOBtHqJymZvEmA0zsf6TgywDPYt55VyMHv8uTgCSXvGDqZE0BSDpVSlnTdenDdi6yvLOddVMwPGvAxM3GS9DfkOVddfGkm7mqdxvyRADr9h0lEGqFYKU0LyVolsPJEgmMrD47YV1FwJFRqIsqRL3jjMT2499ZpaCjY2wdHhqawJJ6ntlLWSSWZMUWDVqrPrdHToevWwrFb2Y6Hh3D80qeBnAKiHE48TAxf1KiQjyEYaReNrUUp8QtWV3YIAqPHTHR9tcDa9vrKPxmNjJ7wUq4haUSmuDykmNh6bRfJ3xkdBnCFDmfENYmxnFSznULzohMSuvkC4yl9ATLaahEsf7W8ZC0M5kDr7U4qHSDj1EEgUzmzFNmFJVvfWLYGsfohfakC3wKdkS7NSjkYYALRTGe047sKKCIPBjGOgMiiTgUjlqs0t21XeqIVOpuO0OCs8fWoWb1mZQ5w2kr9ZFc6pXkyUU3Taxi8kF2uvGg0uTvE750N88AzylpQS6I4lcp1lRKE4ntBa95xc2w4ZA7NeuMf7ilvkckewDILSvWd14lKFqcni5NgleG2qFN3ZJiJkEXUwBw71Z4SVqaMZ9qxPdQoPFyo4oQ7WazDoaVtQOWF1i4r5U8I3XDAMC5c4ilxZJ16imFEFD3ZKtzMcqcPcwJNJmgraxueWqFAozNCSOe3Mq7fl4UY5CZrlne1hiABhNZRydMIjOpfD1TlDAVTo6SHpoF1VSqeL6u88gRnUhRShZAOiARNNtvXbkPDOpz6iKOGNfx3ONG98Jw92LPaWb21574MT4CfqVyXvXm6OnE8AwOZBRjhv7iREu2vd06RXDnozurXCHH8UY4PaArZmXxwHkDxSZG2gndxiXucD3pCallCWjlwis6E8y7pm0KX2LOuuu2bzmkZreK0RWDbjXyNFOujJavW73QiewPE6SEkEhEEd7pYUpQ1M6m8ZvjtpvBGuICbZB2SHUakc9pRUWLEyYZbIo9MtxX8uLFGa6Ws7xNQDWZzl5mVK5tFpsNXGdGHmsHPyzBaS1eH3inrF9SpWNhn9MmPIxYgQTePuMzxYbFSi9fZzupQqg3pg35xngRuEiXcCGAAPeLzc0dUgBqvDdQU4JTZo3IYlq7Ku9hrjwQvEcp9Avv3G8H8d2f8TxIl2UZ5qlU5GiXWBaXfWDJw1l4lJp0VYPzPKlgzpH2ymLM5ho4PbTYVIzeJCDHwmWaZ9IndHvy0RNo8uVeiVfZj9KyehznkKhhUplXrWHmmvxpgScwshAmSR6INiY3meNXvRR5307m9re08wFVOT1qAtseYYQeemBqtz3oZxT6J1HxctKZ1VjHx90k2MjxCnHtyOhmKFcm2ikDMFC7cjLwHzeEqsul2pTKxPHVqz98YDB5fYhKW1DGp7WI4LHxCFCdpKgeCb62OAewEhzuVdwOVkrqpo4ztHOWJqgtZ91c1xzHhFwDs0BxrlUomZ5OP5WXmTVZiKyilTzZlSM5ZYOwLqCqkAnHCowegTHx4yxroF3fTeMIQyY4i0jhkKHboauX8nmxVfj0tP143ZCA13oK6DOaFSQaHAiUKuWKuPAng0QZsumL8TCrWJcDqK4rOVIXudjohESXTo00yqlwm1BHr5Dz10QkBPRKOkvEcYGcdsiGslVsFWG5SnRqV3DOQY0SEjUrhzusSLnXpxLRIUJbyUg6dINoRsv314IilYlCb7SWIddKgNLGr2C8EFNviIIOZlzwiMPI8je5rplPhWbqOrOydhyUwp3TxgwIXsyJAzP3TLGVyeEW5YqfEhs755yPSgphvTNzqzGwGAogSFQrcuLl0RWyHq68EtAl3eoa4yJNKX7LOOlIHzNIeDrgMSVvOeGUYhtCjBBABO5EvHVtljk8mcSv22U3RU83YZE3OltwXtkrEelQmLXdd3NHQZ7863qWSeZtoyLqJnr8SNjkiLInteOfcrO2eqtnEcViS0uNBKJJLIfaFSXlvG33TBK3kryNo6fRL4lWFjiyUD6LtAWXHy7qC51tRIealSGiadp0RNEhCvrkfpGKYekGcZbyn5mTBNVqHKsqnOXM9dxHlud6Ly4zsksG16OzrhB7NJHuc4nRkAhGyWLfsha6omKYklWBgu1rJOffadvoxuR2FvHqW6th7qON13ZUCoOpBCEbRqvR09biRbxPwpEqpE9RTrctT7ihcaF311VrgSG1hLj3DBPqaodJ6qAfM03qmozpaiYCOHJTzZU5k7RGbfEsReiRZUinS0qmU90Jgfh5etU3pFjz0UcG5V62SEtQEPpgKuqEmFbAy0fHBjlCwt74bKNnjmAnasd8WV2uM5lNZdqDDQYJKMUM83cVY1MGBFYooRuzXEAWuolj2NZb8Kky2hDtnitt91Hlm0Q9sgf7sJkHNs1OIt4QMR9casnkIXXA4IiUnQYbzLHtBGIRDSQKLNay2sBTftNqdKpJ2akuEWD7BVLm3HyAgiRqPH3srBnYdQKvCre65ukj3l3EIecuy2pm5cznUWPfUERwhwARCTUVcQ69GIHehTixL40zoDf4OP3mdHJrm😃 +~~ROW COUNT: 1~~ + +prepst#!#exec#!#varchar|-|a|-|#!#nvarchar|-|b|-| +~~ROW COUNT: 1~~ + +select * from VARCHAR_dt +~~START~~ +str#!#str +hello#!#hello😃 +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#!#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😃 +#!# +hello#!#hello😃 +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#!#5E3yMLSKs9f2gi7D5YnzWssgaxFjWPxx8aCS3F2rRGrtOX4AYNVGag0LuBXt5j8nEnxPVijkhpFY5OuPRSexMgZC83b8eVx1v0637CSetIMBFab7xz3bBKx41ELPBGSstz7kba5DajWRItW7Isk9QM7X0H4MNAIa49eR25U7qLUY7gm0j8sh5iKIvxW58bTVzMGM7Nz912oOQhgM5yMVEFbdnDKVqPNlnnBZJJVmzZ6u7RkHsoOwUDNprObG8ggQHsn0KLSg2YQZ8sDApFFvDJtDsNsisAYQWk07apBelFSRSUUsH1Dcj2jda06x6RWgaQO4137Ot9ysMn8zwnRjKY4JCB5l6Xq4olVZgzkoIat31B8d90HZJNr0ff0UMMRjF0bMvl32bsnGNwMG9bCKn3FhHCD6daOsZyjDUtk40Mui9DTsJeLmRoLkLLOnwL1L8EBeeR9G0TYPKawja0o8FMZCSmk5gJVbVTFzhfl72JDJikey4wJbrZUpMQZSkiw4O4QLVbR01AsdtxQmJVnl9BbMcj4KbhwPj00uALRY817aQTIfG3GyYfyJFuDNtVrynt4cMv1mu1p9qoM2u4fBo4bce1k5qATYbPKe0QPNfJm51ePbNTwZUOzRhJWBxHQz5Yc7u1YejKV3X0OON4gnVfamM5zVJWBgDVyUGm4Qlrux7KwjgkvK1gv9PiofjVX3BCFj8JrlFUYBms3OXQhhpbjUSftHrukQAeqXPbm9D68RR0DutD62WJuT7BOGaljWodv5LYfnSCwxZFNT65XQtuCzqgAL0n13wh0bl2yXNHe8JPMb8LxYn8Yua3KVs4pCEy7YrHwXmQjASOw9PVZwBtIGkfNYCW9ronmZS5v7blETt2XHbLDLSUqUSP7nhf32tMP8qnVM8zTy5XVz2zfyI9Jy58ctMWNlTW1uI9w9CCfCv8n22L7xZJq6WGfUebTIxsNi7PGiHGmCOLmuiYlLsEdBV4zFztmqtfRQwzNj8xLMx6uHpitRx2O3Pjctx5GaXdXJKtK2FNDxcxhnHoQruMBcM6dERui4dpYK0pLTXzSaash9DfaaOQDtyYxDuZoGwGpvVAwuEPHTn4b58Dg9Dh18DKhLOA0U6XDbgc14gT0V1kUlax1UMrtPdsesVUTM8TuHUVnUd5vBXO00mW9y6ILNDt6LafnZHVGLWt3QBKRMrPsyWJ3QiUy6PErrI3BRX8GC1UluMU1wpAKhcbYlG4ReTYhusIAjVATpWFMiQMI7MDg8MR24wGwUVmzlaJfl2E3puiWNRDAoLB5pAE7DJ7HISSfTZctDqXiJLt19BC5XVfDMkociSe28ypSQbYVsJNXRKQkCiYycptDKEUcKsI0q5YIThi7ED1ZZshRXe3gdkHixsRjsCroanaIfVh3BKdfIaVTCyECFrnlRc9Thg0svgajZ2UhDE5l90spJY3kRiP7vK5pJWDKo5CLEvRn232fnxqeGF6Ouh4X1sR4tBET9W5BUx3bT4NALnxzoZXHyNm41uQSwCxAWawLDE2nta8TxvbnFJFwccTV0T0SM6swBE2NigSWyZpALUnAh9wrFKl5s5npGv0IGOmeKyqgoMAf0b7OBaMqBATwB3675iFlMt3FkvetTbUuCLzHt9Vc3QJ5H7102kJVKy7vtPlU3kuNPItxUA9I85n3K62FDe0dGxleTWmztsw0jJPOKLluHOv9z4S916Ab0Qk6nR62KdOqtUlmj0L962n2Tg6yDo0bchTjjTSLnike0yDOLfcsFAuPafKpBludIs9rcloWaj9Yz2KeOefrOxbtEfC7rkkMXtyGJFZXO8KUg1m09xNUU2uVXQVyyGoRZMzxKEZHudfaeXxx9z9WvS20lwRwysuy0YnG0CMuQQuOydGtenSmdKhilD3m1VOIpkx8uPYswR2CC0Q4z9gA3RGiu2GPpU8nUAQw3QNzjepxXL1EDqiHk6505ya1obb9hzZ8RdAE1TkYSkOr96tU5AF44vURcYzbr14mhk9ccj8T17dNF8nlYMRvPXXU4uqfKXatQ2CTGM1s7drYhuEauUj4CE4c1zRscjQACspwvJG8BXugLrz8OFxlW7ghvWWs0GWC6r6N8E6gbQrnqp86YzIWLA1uEcOUHnAeqAv3vX3YS2BjXFgfWOHFhRjUHaAA9Lt8kC1l7Zo9NZILe4MNPyJ3qdpUxWvz1WqZ0JxxTLqpWoxQyyWWhPXSsZ4JNRxQ7SDbSThk9dheuri5APDtUdnTAUxuvixhAb8Hjy48CuFL504UWU40UWHLtCYqZlJADx3p7IPcoX4O9cDI9jdtO1dOQsHe3UB9JvyqTkAoiohH2K7KdpRdefJfSr5vt14QVdThnllrZWp7OQviutTouO9gXZWv1BmNVgprxbjJyBVcyKQYilIk1ejHqwWd41zq0fOkqkd6AwRMSb6htusEqzeGWBfhoJQRJ0UY2xa6GDmOgl8sOBhSFkeLY1cYfvFadVaOVoRNQtT1ekxpFQmXLYqcjKcKdOQB5FfRzzXJPBA8aFmiJh7PeZOhUFOGQH60tFBXYwLW2H6kyVh7ZZiLUdgAdN8uhU1OaH9mgPPEBSEhXCqRhj7TUJiZ90dJohv1FqWPTC9rc2yxPYrEsvmOAfA4f0wVVc1uny7jQ7K0At15uqkf0LjdX5TLDujz2MRPR8pZZh2G3eItksoixsyr4fgHTXH8RghRvDqRkTKzWWbjtl44c3PPYjRoKxZr48FgGXiMbsgMGuJqUCg7i4WS6zQlA3SDMUwAstISaZwsTO761RsvDAHHOfLY4z69xfajTTNEYprrkqh000Ce3CuJvL4890nGj9XtZBKWfqTMUe6D5FYUykJRFvKdLPbeWsGI4eQvZJuL22b6qJHhs6kkk7nItAnmiZtE1P5Q8020JupoxMdJHxFryvUKrxhaEduBS1qAIVhLgBgadwM6G2tSYwZZHRbPmKmPCWNIU3KEg3BO6TvoXFAWuieTr7C9GmZ2aW5FMOmNBjR0qDM135InITOsnPfPQodmUWlyklAmesWy2AA5S9sqmEXoIQbnsDNHPNhWC6rRaqxYzYfsW9TVWMFLKkYA5Rn7DaJkk7gA7LtPDyTHD5DbtJ2VyCPC1aTLUdpD1jIrksUw7XNgVkdZAlu31BHQVH8lQgHGrJYgRwhmxQMYEbaqhAwICRADGcSqBoFR6L83ZgpbRI3NVYzNndH0WKZ01txEwcNlurSJSICMkU363i15J1bMT7LCpRhgNqfaJCHygIXnCmHlKg81hgmVEFfeYQA2nslRFqz9o1fB09gjQgFug68taSbZxYAWZNz0pCiGEEdW1nyHkcy5dMzf8rAOQrZme49KBgdyDvVnbO9Dcj0ncfipvnUYaNMMtFBWHePJ1QK28lYTXEaHhFrzboEbfkUIgdv3dnv8MLo93I1PENotOcERvM9DGxkia36prCxwrwCJCCVHjzVuFQgjeWvBQskSkPv42t8bofztrOg6vmiYL6zpxXGlztwKnJmc0Cyl6bb8C6CvCYQuITcrBT0prPckU6EBTI4CDPur1MmgcJXeuH15CNbByWmGRZnA11OaY38mUqyuDbelDMUjrslu0GLT1ECC0QuPo91jkvsSpaCLglC3D8IqqN5rJu2IDv3DZyfpT0Q4hoNCPnhvtJC9wbgxq4irSqd183o5dvWrHdQHDrvB8Knku2zLlceG6ygCOdKQ0mzNGzmPRuO790R0YjsCiEx5CDWI2QbeunE5t9XZFH0jlpsYxqYS8FEBvI2KjYsOYThJptgSRm4SiwQvx9Zb7w3IMkxIlaXay568rGiZ67l8JRsSkGDFrjFXVbMtbdMzEDLENr9nah60PXs6iuP2iLBM5nNVhxkRGXOhsSEOZtDbyTMffG7TcyiA8qtTTHspG2gLtncI3OsdrRLNy6VDGv2ARdbZkbs4F3Ta3hF8c9p5HbkbU59xiTJ5yFtpfzpjd4zKjZ6HtZvyRahNzpNAfcEE4mLTcdsjjB5VbrWwu0HOuLZBaAY8wGJwUYnFi18L8CxzyOmvekMbxWpuk9939m8qO55rqFmkPicjxJkhq6efpCWMBKVBHJHfCSYtXUsZNcmNJqgxhDfk2vTgEWiIAT9s8WwbMnC5gczGHtoemnXtNSCrACM4Ijd4qRIVGbDTH4GszZdQBUdzBSVELFZoi9kkl12dB6eUk7QMy5TTVXxu3BpGj4g2VmgATbEVm2SSpuYs5vouAibF0rF0aSWXtTEZaU14OEGYl8jtdOBWmfuV4JGDYdsG3YfJ44v2AqMQqmuKxFpwkXo0OABqi5wPyQbdiLqSNDuDdxcR7wNNa5drZCMAEOqodPTvILUVhOpdNHrp4hsZv3I0TOscqC49tZO2dvkVDJBdV3ZF0RiS4lrBm9Qxuv3jlO33W8OJobiKs3FzzPYBBKgtJFAAWddpJmGlgSemZEC18Fdj7RkH8sWWaY8szjigArZpAHLkXTyx4z4fcX9nkdZF6BXRLnjFV0Ok6EZtUu7tw8ezXWqT5eP6QtRAMBMOVcUNxyKH3ouUml7se57QpYoxfskteizphJTL1lPklI5biicfa9IOg9QYBF0FrYXgHt7j4LCybGx5Ac5kQSzSCnOZzZvESTsegMZ6xe1HIXfxHDYGMSqwFdrcS4djZimiz4CTu3BBQTLo5RxotYCx6eJGL4WDsYMkbvbdYDW2uG8OkLCADT0Q9ky5J04P7gyJjK0nMQodOlLsspQRr6TQEPog6ftyQxmf4gstEkhXEHKydeSbjTHyZRqnn56TLfeiePKuUYCQGhYt4qmWR6JPCHoKaZsDj6tIQRyUTovV0VW3P5WGqf4wMcSM9HvB28xR9DBW7sCgpDbZwawfyli2xMn9GMk4kFOqHMeSIt8KXvppTwsbBCGiJf7O15TVJOZVqtGp2qH7pnnQSNpEoKBumvQ65qNznvSHReNGlB18M5QU4312i3efeTul0NJKXHluCn9M70N9O0W6PtsthW9HD4ANLFcl9yZnsJjwuojcGoaNc9jjfj0TeQcYZvqWX4GE2RBPp5x1YEMU0koSOxDPVMSYFF74fOeY4JLSw6UccpNOEQSKZm5eg6pRlOLjrigZdZHgBeWHCfiTEJjj75AAB2Z9Sqx8yvYvfuycbDfaY66pZY59ihACOhEYwOd0MHgmqnNvYhCN7fojDWVtq2qyqDVU9xDeTQYZ3Djml07N1BeJrjmZm9Rh19C6pFuqDd7qbEOF8jiwJ3ipsPBoO0QwDTHZ3Yum2jIEk2hDR8iRahLyI3BXcDAYQ3hhjBhbpQccRSZCCxOaf3hgwRr20nx6cYKVvz7oYupKV3uToUx5bOm2NNwUZNhVkPMjGmDsPGLbdorUBlofiDow1Moa5a9KKaCo9Zce6G46s758geE8rCATwrFcb0oMg1g0slrORHpRLkYkTSCvpbl76CmCCtJugFcUlK8s6GN06lLhAxzh9Yox5NxwBpR48ctcBk2zdgXxydJeoHVMYT5QCTNyKygxtNfoU4mnjAQ6GDVmRLCEK4j7ToWGuGTrZmU4qbG3shvAvmNCffSX8qNHKq8yNIvVcj8g8njlq6RyMJyb2zB1XSp5thihvy2vMhYmcpKmsyb0XStGGa60Oa2uXfOKsDpSL2SAVC3AlSKj5xwiFlkYaYtA89250ugvfV0idCtGVq8YLaoSFSE1sd07ZIcLAFSDNLRGxLz3hRTLaiZrZ3IbroKgxrsCQNCK7WD6siLKp9CZJKgCH1UXBYwVH375N8IwpUctm2KO6yfCTbYBp1U60peUQmYKiSMMR3lt6tly81L2m5u5PfRMUDXgm0fCCXitxwmBdo0RSd0rDE3kDrsaUFaDOSqJojEhKIfre3GkPKS6Hm9Gmm2cWqByUUbfOcw6mtR40jCaH4WBe9nAiO7kpuP6U6YWP7LBpTeQ09YekwxRe99Upb7YaEjGcLEG4HtBtT8yN3HxJYaeqLAWh04JOE8sthbFi2YpeDfZ7baBOYyOghV5OASLsGi2l2L3gMVZeJKrBQOw7tsm9E6grhU1Pmc9uK3KApl0yOsoEXpZsUpucX0GKZvT7ibmyBzuh9CoGN4YI26KjLY3TeeePTfB7C9lLvi5cQ96Ksep4AOKE6mJBc5jGPm7W9VaoRUmGBhGa1d7kND0Z8Z0wFBGNzUxIMzSO3bNqFT9qlywwYc4f57Yo8NTXSNmeIuyrRvjGI1utGZtVs24srEMc6eCIDmW2bi3a94stKouhpu5IZvXUBDe1Oqqcq9MyJt7CyVbcrlVyGjElzoj1SDldPI37rooXXzZFpzuInM3oDYvdzisBGDK7htrT5cMMuRtkeSYcKW8RJ0vHgJzPDZXSqJvMW1DVoUawY0AzRgkuFAKQuqDhOjtBYltTlwLw1zqvX7It9pWHdmn7km0J55fXgw4OK5pZGCCFdNmdgtRUjLuRd2PBHkd9AOHF3MWFCToUJDAEWyClu6HPp8K8K693RynIlDc1HtqwAxqWmbkaGmyJOj4mAx1QA9ZDpMuX8672SOYxxNUUehbcLMk6G6dvn2eXxc9hWmUAXCyA4RmD21iDb9vpXHQRWFlkxiPMH9uwi3xNf4xhAe10qB3eP03NggzGmOEMZbK07g2dkWfUdXa3LVL2WWAds3vLaiMT1AgT0PXbKW0uM1F9dzOlnXq8ULafhOLyMoEP4oXimbNlF7se4e1ICNaftuzF486tq3FPGppQCZkhKhRwUzGxWnAZseWZSdYhH1w4Umjq4tT7ASgHSmBUNrZp1sn4vx5Cm4oVqIqkLeDphr1olertf9ReK1TJJpWXymBrqiQikqj3Ly7VbUhTbX6mUAU3vT2HGJEazQ1qDUgUVB0zjKG6DMDCaWB3G3rqAW9DY2hVxDNQOqXBXBnhCOIPWTz1nqS12AlYbABTNbH2ClYC8GExTxGTkry0ptpekpID2E5KhftkhXMkvRjVuuX8nftEjbETUGn0EZkRXWxe0ypkuh1wlrj7yp08ldxM8xHMYr4l2CASvBtkpxtMUAuG6nYoZieH7ZzjMwGIv4UdSimONCg42Em2Fp81FrMv5RA1wZSkN7areTRf9V2aeRyiPEJAvZb6Hiho0q5Vec2T2nh2XaMi4ZUtXXY7BBxjK8tu3cNmMHdwCunroHq1KtTv6BAqhTEZ6gTaIFSKiDbfaqYDYZ0VqFjVDKWzsJzRnV2ybbUBUHdaxrq1gNlV7Zk8KLWMmLCQwVtLgWitpD1M73n2d2HgytbpPF94tE1S21rOWGCtYAi5jTNXJb0ixm4jjoJl8V6mkWsi4OhLnt7dqYVL2YhTdRus5ljZ2vvzmxPs8rI8nS9oRCUKHdlK2JIzdRHwtsXjieioSRfL3gxgdnQDTvBti86B5e8RxuIFrNwByMrkl4m7x9ezW8yUAVn1w7aMyRNLW5xNVG9wR8bOEIoVZ6Rjy36EPtW2TWq4HCy0SNTS4nqjPHcs9RlE10lvqWaIfniQQ281nuFTDoyIPcrooSEjjWoKo5DZgsXIhzo1IvPUg4xyW1BqAEtN28TES50yoCnJoupExF5nKXuYlZ1bO4EAd9cik547unM9rKC3fgLZDbMgG8Puvign9J4hmF4zrZ63tc6y9obyz5gJDb5ilTbXsy8qJljaADvEh8SpxQEuejSxtm1HJoodEuO5ypGKUvxblJ91wyXmQfXHHdlu6fdZMfLrlyQOgRuvJeQagcMhDjUbzvylehuzO7KWhi46E84eezuOHAgrxBWgJ3Yo31iTHElezDsrlMtLP3PHUYtbaNgPwmQBWjlllL7lxs56Vjh7PrV1jRI0APn2uja8s0JJ8yGdNkXD2tbBu9FkhI9nEzQtenqCvFVjLU036W96w5jkAaJg0LvXYPorud3zkaauaVWJtn1iexwvoH4QuIu17TkLOjZKpAEyKtGzsbIfblArZpf0ipQ9KT9zNbfgLKxluARfWSm7xIuGHkiypwBwbf8u3s5HpHgRWKLg3RAK1IudnIoFTm7vE1GWpBQQXX3GcbA4kz2CNsC391zRSdepY3W6RqQTvAMry7KI8hNd7yWA7Yqd5NIX8ocqrqfkgYsG7hlJRY2jSMU1TngYStTLogZb7Arj1Arn4gUc8cgpE4iPlk8S031iLd74vXKgecAeve32zqUbMwY9Hg7FtksruC71CZYW0qF5YLP52RbXqDakmqyEFO9DRunWLMTZfd5Y1Oa0aJCAIJy7xXyPxTWdiJ0KXI92kG4ODIyzC7Fs8zQJPkJ4IZMVGkXXfW4qwMDPJB2KqO14Uz2uO563GWhUwO37FajqpyD5JmypzGIeDtk1MKzSRv0FOELi9a1NjsfXVOh9iABqIqizmOrb6n3pJLIQEdqbp1IMoie8pHYm2cLdvi20FgTpQvj1erPhqJNuFqFEN3WRXn3OH5ZGDsLaHqVhFeyAoH7cMIjDQzBJ87p6a0ArI1RqsfDZWG2nuW1wPwxRo2OB4veCPRA7crhgwY2rt89proY2s7Vd98tHEfM3b1txIR5TEVPL87EuTcg3aTlTJyVpllgOErMuiJriG2kwJW1t4rYTCKJMoRfwGSdyHXMiDKNSEywNAPmnr0As8P93Hz26UmtZzkeSkKthLG9oX8hRvrNc6CHbjlLRepymoTn40d7eKhywaPO8cLR9zxX9MYH9V7sQ4KwJQ6zMC5BpixRIRfDDMpAnmb1UhptmKeET37msT3pDe9w21N5cD4menLEm7kl97wFJnSbNZQmT3O5R06ypOAUivmzJReqexc5YaXauJEqBAaWCqzUKR2432mS2ZZz1IXXuMws5C4wUKR8WOoCdnE9r1Im7Wb3rfgbZZERbHTOb7fJqXon8lEneXLPIxAOb5RFEZw9L4NwfcumUjGYYRcvNegMNQLpFdJsUUyCX7bZNNxrFPhULnNBkocrEtMclzBWnJ4reHYsv8HIsB3AbYDWfSLxq7DyuTlk00uumsoX8k8cSKuvs4qOMzJYHmRZGputDzyqWj0SOR0psVObWFJhuYJcNeuWCTvOBt57kjbS7MBpyMuFEPKtp5UCMyAPRvlXKR5L6QxztoH6xx6lf8heKC7MK3MkD2OczXm8XL7lBBVJC3AgJ2fs6AHaafgVDsiGRb119sIXf3rjgZLBzVInquAhwqsEFQtAEDO0XOdT9kNycZWstTyCvCZ6cSvrJTK1uqoS3dqgHDyYjaAkaCofAYvtKIfUkpnAgxdHxMHhTGcFdILRiu2JRXGQujsddcIpw8nZEMavw1rB50yFENg2nqtyD9GYKZ4IkdaW8b6kxuirIlS9jksg1WLTPim3BrcMaxIpoqT1uzD8klHUCzXSh7OjUpj4GdLam2SWQTL6sOuicUqpeYmKG9hVSRcOl3YZAy5uPYB62MAmOhkhRsWnqDj7XQVPuJBxMePG28wqMffUzV2rUy9WRSokxC0QY2V1fHcWN6D85xFnP8cyvs0J6npg1L33fPtgD8Mmb19Ku5PtcrExmAAyyYtufC5vCyJVggneDLWjbFptDX51FOnhbhka3wJY0F9KhfeUC4rzGhZVqMLxgPB6CS7FzFwasec7PdtivSsCTpcbqIAISw6h0mjWHZmFtPIxgoJch3YVWdgpngWyVnkUaqKikzx0y2hZtgiOGHqokDZReFiGJGKZLnN0SkZcJKZC6O2u9twIJ8rdGhfsOQjsw8nPPIm7XGOVe26Pe537TazRNjovUQVAud78NppdFKm9T8CodeoscRbH26b1SiS01oDEQnEjdeTJYZUZSRM1t5lbQY7ZCKY2KpsEZTLcZr31CY6VCOr9Q9if4zvwsyf7K9BywidKAEq7dt0HyMgV484zTsurELSxBH0xymY8Y4CK9SfP7b86siTDLEijOABO9qiJa7JFgBZwbnW8ybl3IAEk5DxBoNfRf8Yf3We3PTjGiF5AWkOVaK7Cdc1QB62mxL0Tj7JzlpgEMn8dweO3NegQxBo1BwusM9f4rcvJB0iFun3JsnzQHvg1pLqTijx3vyWeraciOmQZfAqSXEihc2Nv5xRx6nDZiwLlwqUMnGYnvUwkMco5UPjJ81Gyzfp8imTI7yFClEqkRvXn4hsrRMO8EGxWkKCCCyFdas9IPu1ddQL3myW3oIlmwa0a50kdd1A2ORrqAeOjoJ7wYS2Orrm5xZkYoxLRCM6ySOcy2gi3Yv1UH8Ee5ZfXVgqxvWxfqh2CGBW4IYvUpWuFgPJchrdUJebpuu29q7xAEopSL4gRCOujyozS6UMWVHmbCvNq0VTaS4fufo6P9MP3IAMFf4PNWyRg7vP6Hd5NghcstkBFECHB4v7MMDiRuI6XdP8l4fVLbXXgLtYSDZEG1vp4mpXo51yCstXw1Mgit1eBI7o4M2Za289Y9zuf6pihQXTLNev90bZLuRyQVFFo24MVFsJHz9rT8o3LmuJayHbXvuwsBSycA9c2tGpYUU275FnhqRZkqHEdmImDyHwgNgl09JrxQFtzhyrRC3DDUvVglJDpLXX0Gie6qcl0yofpIJDHnb2UWHygVYan3TJoBbEnxiaJAHagmS6bFR2PqGNeQ8Ssz1ZchV2MevP6yDjZMo05SAGTMeexevU1ZXdiLRDrjXl8GJxh0kN3c7llIHBpeQq1US66bQTrjC0LPxC8RuWHIGvaWAxEiMzr4WeqO55IurKecfgzJoLZJbzrbz3wl16kBpjaXG4JQ1xjNYfYS7Mv7JK11QBvHxp5NU4glJQmREyo2PBUXCOMi5JtilSnZlJNpEjd1HGwfyLQgD611Sh9sLUwFaHog6FhRNEkujMBiwW9huKIwadCes1VsJBqOgb8oxFVhPVHjc6OckDgf5tKHhUUcIAjSkY5K72xAnAtAITNSwBM0P9zx84qsTu4dKJBvhwiUOrARF3aLhgjODPjwdzrMeEkY6kGS4AGWXCn0Qrrqn42dlbH9pJqUTaN6sKvF9mcCULPJZV3EPxyQ1wFeb5tlg2OTcYDPhMUjq4p5CRquekSWrkMG3rrHSmv4gnjNj8bF4dAOmuZRsBLzAjW4bNfYrUOjwfnMKMbnatuCGo7gLEMf7iJAIrSmFFuA0oanV1CZnGxpujSsMEwrABFNjKSV12NWGAcWPdoRj8iVeGrZOCHNAyWyPRVVGxSy7cQYdcXwooo8NvRSVICgRoeUuj0IWA5qDK95rdREoH89FO0CzPXHf5JgIuOdnBwRF4MFiIJcJJWUe52HhM7b9LLJFhumQGZaQZU2jGfON9dRzKLUYi8jXFtAR8llRwImYuIAjPSmL4QDTV5daMDbo1RB4cJJOat2pepq8TePA74pi4QsQo8OLPWL5IIsyWtZM2jgskftmoDn4iUVxA7IcHmvmWpLCXsh4CbUDIuj3ylQt0GslrB9BWydCsfg6YL7gKz0x8lfem5ieBF6c21nQeSocclP8GI8yVWqjzxGcagp0mdtjgMCSvDiCsx2z7p7w4U1p5PjiF95LKn0zMvDlqknc8gEFJ7FVIM9gQBye8tthUP81wzO7DJGR4CrT2WI0aGaE2CK6Qyx3ZJ2PVNp814CATp4xn7jzCHs3rvyDVSBsmC9PgJq8CZNVwI1xiJlK95poWmJSLWJ09kv4zN8heGTTRNUqVmrH2Bk5lnCdzP75iG5nJatK75utZscJrhAgvGpDpXWFAO65Kki8wSU39GHPqO7ueFMblj2bATM4ztwHRgfLNI469HB9hodHm6OhT5hti34Cd3Zguw5vjEnGComiLRqrWmjFFrCluPz5KodcNi5z0ldjCyqzOkYegJQtKabdXNG7zTqnwOtauzPFvYHAT9JhMJgpXXSoQyvSZYwiPUQyV1xsrUGiVsTKN7L0oBCga8XyqAoJeSJlPaXIcJwMzGNd1GobWg5Eeuobhu26er8wwZdHh1h6s1H38KnV8tRvVym3R58Xirjqpef3idxOYl966ec6OSdIGn5jwSEoEZr5UzRdcRJBPvJr0vTAncLWKVlhDIcxghQEJ2EKfij4OP3D2PoyqnRW263at0fKGgHYPJirnCmXOyyMwj4LFuJgH2tteJjNgO1hHNdjYHdDQJKMpzZBBsVcY9GQ1OwoPEg7rl2VaRitTnxhhpMxZWNRIzHL3Da9R3XXg4azaweDdwX2c9ULvSTiDYD3CR9SJ5OEVz5WlS0bPWEDdhP9iq4HPMzr5crkTlRMTVO0xrVwcMZx28QLJpseFr3Lb9tDN2P1cAbB0PclKxq3nOR3t0FLnRSkzCDXUo7U8Lyg0U2oPclQzymBVOvfOO1nvU3f6LdwNdxFhFMPCKUPU1Mf1cINYmJigDtqF2YbiFZXgYe7XTDxm3sDpS3DHGRVfoBEBM5KXbiUtqD5QvfIoPA9ocUhDYPlUTUJKrBUtoA2vREhPFY8GprO137EcxeLo3gZHDTLwONJWUjIwEqaa54SZEoQBr0dWN5LZ88xbmtVojDfjFnfVBS0BGdVLnlCkyrGgLqDnPdpyVmmQK3FTaExtZj3gfLHDNauKWWUQGpKUzqYbwQqQcRPekI8spswMdblVSrfvyfvmHOVULdmSeTKzwSCdhNVzZAgNvCSjft5ctjfLps4xkpNMKzh3uE1RAjW5coTDznofHxGiNFvUHa7lyNa9diFPdKHgJdBfLFGzRkisL4jGJpE56VCpG8nImLTTmOjWxHiifoNRV7mHURveXfMwjydIurqol8rn1a2PX2aR4VNB6kbQc7Zepdsj1iZJ8KbgGUkurnar7gtaVlQLEHaDPGhMkAjGh9uY0zMlrLTE380ATAKdK39mLorzH5woSTBmoGFyUCLkT9qWKt62l7yiQo2sFriCP1dGvzCUnYIan3dHkQXuKCm0Hv4PZsmRm9ofmV5AayMpajuIPrjT9Ow1wCqk6a9VtpmIhcL8ub3GmrMHDRvpOJqYQJxpUE10IVIra2Yi3D60Co94Yuj4SPw8BPKoh8esmdxZaz06IUy55jBR5WXA7CdQK3JXYguvRW1TCo8CDtvTCNUzGr19OPpFzU0CSlmOgmb1j9z6bSPdbab5soflPK4YFFwZf7nALuEak7lLyaJ471Js13vepnjq26lCfp78hfmfhq2EuoIRhM8m4TnrIcXiAGinjzaQWRxkIGN1juF12iDdBbRwdV4xrogM4TcK9ZwoUyQe7bcIMgAVoe5TpU0PNWVr1ju6dSmmqWVX2qz3XIxDlRqxrkmkU5QZIq3DgrtLfsfXWgPoAr5HAP0HK7SxqHps4Wxgoj9ob8Dw5U1O6mcpr8IUxrpO7vdi1OyyRPFTlIjCZ3dAsxZoEnFOp4b4GhKcMDFDxOggXiR4psIGhKDEvlvuTa23DaxLhSX1iCsgwCIOvNqK99Pf0Wgns6bR3Nlx3Z2OMEyGIrKGyHfcY8MZVn5txMzAYcqjV10HdJnlwzRsktRIJS5RuazhR8Kerq9M2iSIhMTO14wnafg6HjG8JfpawCU8w4u5G0E990AREBGXMSkcjb3JCB3IFYkZ0Z8z5jQB9td0qhHGdKSG7W0QMFd0ILovm2VE9HLGQEhqQ09Fun3KE33w55wn2taQUxhgSoQWewXGFZRQ1qwsZWsqQnTbxihK7NW8vZxsIA7VuM1KZAp2hhnEGx4XYW2p4p2IbMiSq3J4yL4BfFOoAQN4lsz0e9JE1kH4B5M40D2ZpDwBf1V499gv0FUdOeCVaxnaCPpJgXH98Y7g3Y5ugww84u3O77O3ppypHdCrIA097vwEQDGGot1s3zWYCmDce7GmQP5QkR3nDbe0lNK7E1IUjhWcKlzi4r4Eq04ggbn2C51vcO1fgIMx26mC8C51SyK1NCgFaWxBzEHtaoa622zQEA8t9xwXQPDyFajCwT2eEQf7kIvd7241xt46ofOCve8S14kmOVqAz2NWUq0l7UvirgwhEeBiuK9Tb7I3s9v4PAApDos7opGK9lurweeu7JP8zQr1seqmiS06JTCLPQgdi9cl5pplRz4GwhvGOTQZwOjv3zNQ59sqKBB1tVTaizgnvKetQSjSyhg05n4VBsOt0qJYR9jMYwDWRMTilCQJTtIOWDakDayCsoprr3Pf1oBs1WfHVsGFAJhuQaCqQhRGB6kmlHHTLQQhEQah1gNBk45dNzjU91RfTECkqPjO4HX8jhmSKSnQNdTNHg7bncE17QAKEJOSmcPgAR122nDyeDz50cjRXWpKzIKZX1WZtu79slIZinSDDmRSYMDaePx4f0CIoMntBgxwvHEE9zCp7zaC3LwVkzOqRTWVSuDtGG9CgqrZJe5rEeltv6dKNR6v51OSYXUDwPN6ZNysmrOxrB4LGcGFbRb0RpE0XKCJRomOZuLEqdqxKPlARSSg0TeATqEiCAcqX0Ni0RgXlgBQkebPSYaMjOYsfdMxsXWnSadEjFsYydotfzACyFEKte59PnO2BAMRntAFuATZCP6Vwf0Iv6GdpW00rwJFglM6Gb8z8qSIxOxnc2ypb5btzsBpzhNgPiJVI9VKyPlLSjpruGPprf3hdQM4olxQJc69YsrlvxWq2GHR9uN9DwN008Ow0T4K29tCE0QH4QEoPceQu4atJnAwS19Tg8In9a9LRTJXkIoNk9PYGGpNRCms0R8RQspmgKELIU3s6aa83rmFgGwj6TaFrfXbdaeRwpoLpvagg2k3RzzZnOkmtlkwLlo43jovZp4r0VOQn69eC3RdJoNeGChni1Crey1x0FPpVpoS5PbgL8x2cJ1tdaqmZMSMaAIfMf76C5tvn6B9WilZL11uVm999mUMcLk0MpeuvmMu0NNdf5T2kkw9jH2LtFGlhEZRpLXvgvpZ55rEsl6QMAIgxpuWGvlihIJMG7IN4RW9cWYnzlbCqZbRF6AQfyvveqzh8vfYK12dgK7Eg3lsSYCfTLeWdAwuvJe9u21WU0YcwKUxtaiVBLBHSA5NCfNYtjymvW51Dr8MRqBvvTWyLm1UeLKcOMVlqVCDLzfujgeisebYu3apfFgyGllxwHmB1yo6LtvcIQbHAUusxuzlKA4hWCujIeQIvfs9n8VovmUjWKAEabh7zB07rJsdh7sL6NCVIREjszPn5AkyvlljtRmtNikzJUgfjTkrAwrLkcp0eKD81ZQkD6vIayI07eGz0UIhENw0tfpmQXdzCcytCyw1oocrD5k3MqAAbu9MN3RGSdmFNTppeflGJ6VVqTG8Bg2Lq7fVwPOjHkPcF9EoBfU1xJWSV0c1arE4ZmtLw4CKU6AoocmHq1zycYEKBcykdLb0GwDOtTFvtaLkWDT9XlDk64P8j2k1gXJUEhBXDgZs7qjRjrpio379hURaeyK05m5VO3tcaca1kotstKZLILl5VDQCpUO9yF4OdpIRMyGhlKnt0Vqmhh55A6eyZEgTVlcjOYJ5m9YmUillyMaMMU7FThzFtSRIEzQwdAYT6e72ubmjpteeSQYdG5I8mnZ3jiYCo2byVhB8ewEV9Jr1WS1TSDh6zN6EaI0smaTq7R8FzjidRbzqtJcODrRvk4bbUC0LKELAVhjIqXghOZoNU40o0AzqcEzHf1mOd1FtZADecNoRMRhL61tD7StOrvqGcKSrRlPDsfFV6PNuaPVMUhFOA4DBkNcyvov3DHJH9oRjD4OBkQ7pnCZzfEGM7b9pVh2GqcUCI47XcpZO7T1jmv5hn07u13uE6Kx3bX91vtEOa0AH96l8G5ygNDW3oduPnYWlKNEK0LVtSFg0dnMDc4U4lZK0C73aB45e5ed110MnCqVNH2PDJR9P7be4c5BEO1yMztYFU6I2rP2ZxqUvTZstYrECjqhZWRpxMGEaxwR35FF2BY33bUy9dBgc4CnxZhPFQJus9gipRaU8T8d6JgHQyo3103Fj3qzrxUmfhVeUjuaqjwZ3CWDMfgwuqzrvYbnMT9RdFsDP6PUvdlwsUZfGKkDZ5YTTuBbJrhLeiDN0Ug6i9VGUGL5zwWLttTV0BHTGzmecHvN4ZPW3jD7eJLP4lEx6koNQNZXmnQDCKeies9Tf1OmOG9ulicLBJouDr0LGu7q9KoGcpJTxwoeHcoBGZ97PWmHzmRsx8vaWPWeceCsLM2VS6g2bTrmJinV9mU0jkXbcvhusKFZhSp20r49FKtLoD5Lx0Z0oYTvj4fhGO8zR4UkXkd5ZkA44ohOFOpNi1zZbwoCMgOMpFKL5uV1md9E6fRum2gbklJweya1bCjIqXaX028UYNakMHIAS3HFqFVQ4uDkTXnyEby7D11zegU8xdBYhd958KevZhvKunmKEYRcebnzn0rCyg4w8BzXR1qCzSLIZiPoMMJIptaELfdvPvM7FltBy34nb9RUXfoRyVGZfFbmCXuUx1mRE9KJjFPj97KBacYAn34ih4tCQYe3nxgB6XktxSs0xe489kyfHeSE0aUbDO2my4Ibj1tVdtQYGEpDlkJMsSsP2mToiMUwoP2T93lTgP3MovNO5zKwIzsSsbnGnOviyLQE7ERJVjQl5IwahlZ7bM4kXgmA17wWfB3rdE904AH56Z6K0RDa4uGzZpGIWHCzFBN6ZMTkKYqKFNWGTVqs6b5Cl0nGwnbCzW8ZmkyqDaCJkbBBea8o1WBfMg3xIXydWsC5pUZL0OxisrlMOPwvjMdox8f44mDlGaSEXTcXEZ6h3Gg1CkQmExyt8u7Ny70wQaWfplU0xH4VdVpAZ7D88gTkpAr2EADwD3Ooc787YvUJVKKiVpimq33HVNt3Mnf5Lmid9q2X0u3THbuw2MeRyCI3mmFRLyanz6GJrs0AS5NlZK82nQMTOJNdyC2XYPXo4ZwB86arUtnuqZQIrAkJHCtrJXYHxculjX4rYn8jhdLYyC79R4vqzrR5lufPCj1RKxr5rfa4e6L3lZhoq95btuYRiBLWfvfWVOjANoz2bZLn57e8KdSu593dC9eRcJMyyMM6Z2U497vombSdCBcb30m3yMlAKvtbCTZ4SXDh77K8bfj1zFTy4FocBHG5QgihrQQsTeiDzKS1Nk2fZIkBZM6YsTr0nSoi5OkSS0AzYlNnYGZsT5Rzf5Yy4b2C3ekrfGijVv9TblEO4WXnElKex6MZZu9QcO2p6iKFIs6b8MwuLcXG0tdLsO95dTow4FBYBZk5QUeNAjpHZtQLkWwAjr1n4VEQIjy2xPLqsZFRwaSMNlJnHFujA4XYSzBzzOq4mHtmTau1M7FHew82ZtX7PNmSM2r1iWA92bGpz5GnJt8ca0CBpX3GXz2XJfA6NJmKyOM1kma92WJMKLEpAEKHL8iGNJ8kY7H7mTXfqb7ZCEvhNVlKel8tPsw2DeoZrklSS3J4F1csM8Y7koaLEIhJoVCRVH2ZKs6qIPYqKmu6uPykxejg10EEBI4nCkgSslu4Pofl2jpEMEp8klnKEVjbnwQzLM8uWptU4ZmLvyC3BY5hbBDwjgWKcD5ulDudAgk5kJZrbMqLEij0zRCS7faTIZ3ENCZvorrZBT76mtKHIrSxQ5r0RbIstdfULJxK4CFY0yciQy2bR1yCGwYJPhc9gu4jVcMFmsBmWzj1sHLTaTsmI4g4KiTgVMzXAeQgTrQD5A6S8M35g9vF2yYnNv7Zcw3J5fldrSrbOaZsaDqfDmtV0Et3sVSHmJYBJ9GrUnqReTM1PCERK0lRLREYcPuAhLVFr8BBJd4cRcwvVKE6CwWGjmzCEUuuBrH9toyBERoXWJrmTVet08SWeTfjoXqk85X3k8xXk1uiWDYNTOBOQZrtjIC8LzycdRgJfQQbd1H5HhtBlI3HPPJgSf26exawf2k466pebvzhC6SAlDMySdG0D0zso1ug0SYpvZUPshbsKM2qpbFrRGVnYXtHHkjilCRm5sCM25bDIndKieSUwncPeQ7HZgZS1YYBKwL7iTth44ddTioqczH36LhLZgG7Du2oGF1fES6meCS1QzHylrspzIcjBgW3QoPjN2jjRvGbK7YKBXmWbGobL4RU5xrSjEekbQnzV6K6B3pUuUQiORtcZcE3FvBe9YCCsceJgcqQ1JFChSpM0BodQWm6z6xQux6tm6ip7pXnO6zbBLkq12S6y15arjFt4Flsj27OkGELDrt709cekDEfN5E7RxplZRyGFZDP5JN2fEJCxZalcCXs9SThfxXZjTYd6QTC6dFBFo7dWvND5Y10QEiWpElz5v9uGCfvEGNoKjVKNUo9m1xKvu6OvXmXYckOSEOj7MuF8YchL2nSRqVShaF3p3iW8COXY0UohLHEfJ0rzMN8vl7oelLAvIzoxARrO0xI59UyQnB92Y3SBufZjH1GJuJ0fBCLfX8MVQ268rdR524Sv8yY9wyGboi7Ex8OES55QC7lwK6tTCBbkssdxEYwSfadDyAwFCwRMDllzZPUD8MMb7Z4tcz2QswYG6jD5j1C9vGgBfU06ekKvepNT6LOb5gGBJ8onaYjp4CBJXncvUkCxmIzR9jZatyMTTK0KzNtmqyxeQAF4wX6dIfdG7YUaN6Cks3nX42ulx4JkR1HrYEsBmxd8yMgJagKOGeGs8y28qjDaHluICsge4YRHQvWA2regBq0fr9Mqx6j3NoUyKvpLTdU4KOxW7ru82YZDrZgjPAMttkeyckZdU7D9a7UyCGEcaTibziwVX0OdA943UA5x22M8TWIlG0HFllZG0A99XeSOIHovbYohfZN2EJjBiXjXUTotxYxzYhpMkc0cfdm4ABAdvxMIxGwqH0Xm50CxXA1EUZo2Nt1som0V4igH159RzXIwEGenM5NXtaymytUOSwgrFZlS4iyooDvswcTRFdRbGL3mUiazGpu1Irlxvd7NbU9G6bnEukoR8wFaw1VtfPqzhjzUNgad47RpyPDDPHdeCjkFzb8nXTwLmZuUl8HcDNNo4xLQSuIkz5nfdiYSprzOf0v6tZgyIxD3JoBLVFBk62E8ULPHWHMZ8ksFk7C7RuFq5veCLvLLMshnsTZsmZZ1aNPtEgj0aW7URlwJTmPuSPRMhv5MNepsUp9LgKPD58zbHapfxvDUJDf5t0u6kY838gNcWd3Ygdc5p9932AsRIpZb0UEg3QE9p9xojVdg3MSgqU6mDEX5ubxC9wefYXEqS6dmKbDloQYYCtU06GExKWE6jmceeI2IRmUfeTMpCHNGHG0Dww1GWzTtOyEYhI55vAfdu9d3rAVackUlTFvbBHW21cgvi3jBePYd9Wk5gNTyeN6NnopED07l8sR3pG2Nsq2IoAb1bU4vB6gkeYfQzPVmUtE0fRiivrEoUyRYTd8iP2XzI8YKNMUMz5OySETgrpK2U5NoiUb7f46K9um4EcAXqX2yvsE0wDvZQw9BDOAjHTXX1L7HrOUOnSwF7V2RuIP1TIbrFHC5ft7qs1xqpM5Nwy1jpse6Dzm3DVyl6a1CKTCDMCWyx5nCR8NXICylBom8Tt6d8wpMuXEJp2CnMQwFskFF39xiqg3WB1NdH4psU1i1B5r2x3viPqGIBdhhsI7A2YecJHqJgWG92g7EnWoSc7mH7haFLXv7Cf0CGFEr7OT9uXm5vBzHFOW1GNr4IYQC6yDsaNWhjEwxeHDOAO1GWT05RLL89XeukIDwoE1w5Jwbq7u0P2V9NFmdJ3MODlvBJzOQRyDOCpU4TOqPkD3wOX4jGDoSphdJkZXircJsjW72iR2SupVkMkAGZriyXYivyY1E9INV1TfphE2WDssdjzgA0rif0PAEICQ5tHjFRO02VQip8dyhw33HMypP7zC5hbEIC9zhQduVZuhSXuK69A8DzKjgOQ8D4cKFMi98B4bAV48CnjIh1t9PiPmHxt9gEDPr03Pbhfl4tRFFNUuA4TUyAadEohyDEg3jaCKSaemyX3HiQFHt251NM4y5TepkI8s4iyBmDejdHD52XeiZfS8KNLMKuk3yhzGmcl4OsXoXbv19n3DIUYVQw4WK92M4vYKxQvDemh3xnjlS1voMEWT2UfgCo29SLvFpgfcvVShpiKAm8uCf1eraUA29TDPV7ptFYBHoA0007U9uluT2NkxT9YqB7sKeoTy7WEwvlCOwqiiKzqnY1UdWGjFnxI2EJtHvUMibnoI7OGqLNUDN00RTe1jC3GmbDwUoOOp7YyJkGzcU2vmPUlBRakQgco1QcjBmUDIrxuqBuO2FB2WE8LPNty0FEJJgS2KysBwkpqMmDfOHSvVGDhGR52XXNk3F0vxEr5P1x8lBhfDjksEo1S6Qv5h86bj2PHMHL2s0eZlNUDU57cuY1GspHr5tDZWmpjXIHJeKhLKuWAj855ywte9MNxvl34lNmVwcDNv8DUe0jbPVbDRzIfV0Cjpg8aOcTIdBYFHWYMiurMxUpcsnO05IOWu5msv0ngy36axRVlOwa2Nwnwls04LHNU1BVjPOZ0BfPsMSEebqclDoAPeniSkpmoI1Vnx6T6j5TEGuYtb3FBGtPrrkaTzPAXrJiCLg6Ns1mdpGCS4vbSfx5zijijzMGni3zcCAqeU0AN0eyXD2OKa1B7T5Q9La7Syv6mv7slG5zL2aDIsbW6TI2FiAOulg4XIOQxYroMXpnHnzJNcg70n4lMcEMsjhgiOavBPsXmrfchIE4JnhE7PKmQLBgkJz1l07ZGN1sFcwaIUYJOTbHu7GVKZsaqCtMujQvd3BEjU1JZtidQXUzAQdLU9AHogiFNh1R0nlDUQjQ48itKSw4k5skgmQfXEAhoYSmkII7C3kuxLeCHSQLgm5SOw0vGZAsVi8vGHEIdLexwUDXbFimpsyEJVstzdPz5vp6kadk7Uvuujmvbyav45K8HBUyg6wUafxlPPAIHV7LWQC5zz0wMRdpb9j0BXfo6ShMi74vtjP0qPYmupwdiwPIxi0qxJt1qSjsEt42nAXtknGZ8nhWSQDQ9IQlxwb8tJzUM7jcwUL7E15NOyW9PXo6evLFxX9i1Nvr1nNEZBQ8vXsMxbDY8cqBWijEnFFUVikOlGfGOUET6ZzRnJkbEea4JcuGsAYj7rDXBBshAss49tDaIJnsgJLyhsY926oUaSRia9IFxnm1MznJ4EQLGvmqKvGnDeBamBIFzsn61xIk81px3rmL5cF36I2KbZDS8vhBTSSlFhI2rgWaoeeOwGKmffQMnpIvdLTuaMNoFxOxpq1MHCFp0v91WjrdLVOZVBGlZzIf7JR42YIOE1veQchE7cBwAFNvyVySBGV3hhQHr78NlnuCouMyq0Z4PDvrpK7OXxypX9r6iDaW9BudFrKllbxJD7VGbOtlcg5GN9USkfMOms8jmVa2IUV06KHwaDzpbsyfN5Nv6MTyUYtUQ61eowIRzB10BAEY6BfhqOSkdyOX1jUOqM4zpluuijsW8EykyGNneXMq2V0qnc35V5YuXMZAj1FOUJAXEemPFznrH21KrBG3HKxFgNx3sHWZ5ZT7RzYC9rEOduJJAcRSxzm9gmmILYinI1i6CgqGJWtq3P28sYG4oJk1Mwdjp8GMUVVsFTxIt2Oj0jJnGUkV5Lf6ohtcuiVM1cMrNzvUfLOXXTQFRm6BvXIrme6RXrK7J8tdFXPdDYBuCUFol6owkGvxEZ0YbblG5RLoyNO3Tg1oy4ppzVSKRan9ai5b5JMdLEE3L9LT4hQVkm5N5fmQfrVPvb7kiZiqRfiW6cynDvVhNJyl0ugGLL3KvMvMWFqCBJcuwhYyEpsdwBRQxTH1u4jaqk532pdavnAX4m0Vk7n6aZ6fbPpnrY7oCmDcrnw1Z9q03M4HG91shVXjkswtMWPQRtklSDDTX1ZFonr7koYIepTXDoXtg17fJhaT6QMbuNzoChAENZIwg7QoqM6FwuDBNNE8p1GXK6IldAwfC8lIaHOBlWbVf3LB1kcfwwfJ7Hxh2hxqV1M9VflP8FtNgAbPfjgx4XTw4EGLG3PqI1ufF8QNfFWzbqUmdZGYI4ieb7TJinnd3agRF9Iiv6MH3VUnrdAbTFbjhRmd9acMQowfScgqQnKdDYPNkkH5TsREkKE81MPaGUULHtCcAr4HwGijYBsGFmjUT86frIbGZzwLPObgP4oRZDgehF5ICmnS7ILMIOqwVrXbNBABd8rtE4FfBKPLbqwpydbcv1rXsMkDPurBlYlIa9upavdhHax5dF32xExeDtwfoq5XdMi4IN655gWFYWABbU8ElpE2W9vvhXPahhj2tcudCdyC9usFOJgT111iaKJg68htvj8YI67UgT1CTcGwEYRF2ILXmowMhQ6F1ynJrbPQozQIxrwj4uhl9mc8x7sUh5nfjBajvoGm5fpdadTvEWA70F3EIUmmKkCEgjkAxplkH3cBln0URXJiWLjcDIVHtqKL8QFMIa5lpgTdvcqpTqj4VC8JjNQXlVMl3iN7HH3vZkSdyUfD6Q2xS7FIYFwxMJDxjU1r9rIxszoTHUE7qThDjjPmaw8mD5lEySFYMfQ3DiMX9aYQkzfMuHSgF1TKYEpINWliPussuyigaTNB4QRCcRtkGDIKHUcQAFOHLIhBQZoCv6IfBrTTP73zD2tzSBGAZSk9hpB3qVQQktFdI3lvInPfR1CBBeilGFbC6ECl2A6Y9OP46pdh9s9bz6QsjGatRca6KuRie3tc48dzbw4NqhM1cfZxUrRBVdfX0WeP47UrbIOtmdu2MPpozT1ptWG9epuLdwNmEeL1l01JHxj2NbaFwQdS3iut8J01cumgFrDNOPWiAxaq2XgvsHBcr340DFvxE1FdtqNn15jgVMVQBhqlJ2F5AAKbvmdSoYiUyZOhBjDU85g5hLcSNJa0qBDBTQl1oT1jevs5lcA6GUSYHe7ThRUrugotg5Gc5IqPQiPsOgI77MFTXvCX9jF3HrLaaKFR48lsCHbGOLZVaTxHCDXLqzEsu66zVFZC6ouH0SHyU04Bq5JTrAru5VvzCHO87rpGqmTOoNnlxykMu7zHxCHHnW8M95vXvouCWNHWwfhBuLwpMnXfl0ckbectc1Dnve13bosseW4qWSGqoOnjG3uIL61QCXKsMcEO6XerCzeavox7VTaPmoxtYwR3W1fpApdZCIigDDT7gviDsoYqAzsm6m4ShfHKt10CuQh6Z8EjuhxNAJTfG4vb1rh9h9tOkUlhg8DSGc7eOVTPuGa6eACPFVqgjZh3C1pn5sJjBda6psj3SaL8eEbyglH3EqsI3ocZaZiyiKa1GoNmNqVGlQcbDaxs9Idos6wDQAnp6WHvryUbJkEa8sdG2GChr4E2X7uAKrdDuBx0dExT4Us5kfk8tDUKLXW8tl2CamYG8hkPV7emHuTZQADuQ1SAqRG62VDnvIkZEjzyPmiRw73sfUc9t7OJwD5qJrZfQemG5x8ulfk0jGtG8VDEhS6A1qFU7ImAsObgldRBo0oKSZ9b5nQvCoBQHy2ZKlr5WFit8qHaWYhHjMiRnLP0aBdf1pwWcMWUVL4sQHofMQqAwgQ29ycmvkwORwOqQ1xavOlFTUwKPOKyBqN4sWPb99UisqQuauGwDqYh7z89UpzS9QmPl11DQyWDNno7w8NYL5HP8bYefL472AhjMTIDLc4jlD9xMGJLJrzkJzG5rBMiOUYy2IYHakyIFBMDmgHTNSB3ExhCSuryvvPc2yoODmZm6kCCsI06q4PgtB7PQScoV0l3F4j6ZsLzACH3QgrwBDD9JsKEH0Vbp5ibo9tfvBXFeGq6Nn1LvCXjyeV1Q6p3Tg8RdhvyThZU79IQ32r27HBm1H2ahI4yLoMbPQ4lE1NoMbNBG3CR6hrsOmrnmMW5vrscnqRMOthk6lyOEWYl1XTSvZVaK4jAj7gDA7biJnBYpt0GByVXwtjI6SYwe48RGERi77ACy4SjQLOQYisxMx1Xo7IX4nYieIBW9xSOVHuHcrO1JGNeG4rfxSBCEiY2bVQOZdEkl0k3ZR4HWSiJtzJruvxAaXsZtx5Mh6cLnlWFKZzl9o4kyy1FnJJp3evxOTC6cL2J7lsf1e7pzNVhP6bmeKGcy1prR4NWrC6e5Kr7FLwOEKXAlU1naMEM3avk0F6ie2fRMNXoIeiFZhJdvcfJVIfTmbsFpXsSMwIQscCu711vJaHRkfkv5iJvRLybgfb0K28G5bWaZUfMEIdFrraaCcCyDp1NXVj9nSbzNjciAJAlkIqzIwtjYuFeNppyiN5qOxO8av87BCQPUA6CcVkXzYPphnqbzaF9oXUxaN21LYff0ixTQbQVlojR7NYXnRGPihDbutRTdbFvaqq0b7AvRqhvQR7uQqS6yYI5mM9lwaGjePhC2RauDEVqM9bFsxjeRkOQqkKliQaqwGUfxz9KFapGU6UAKBj8W25VMDtVMx1dQ3zphqECnOIQpuzauKqwbkU1E0wOsQj3tyHO9L9uNmdizWSly2t1R7iHT6tm4QiHVkU9eq3xSTL1B5HK6EcLuCP4VjbQ0BlrkHQiTWblUrA7epZ3AB201fKDezWn2VJRLTMUvqSiDA4Z3xzIMPFUUWMPijWZDlk6vselniaBZZvVL11YI2TNFKvlt7hB5cn1Ieevh2R8Wju7RC0TvBRNXSKFP9A61qABXpHpej6Zp2NxIfF3fqty0wIMZgYMq1E8qNrBDapLeIWtCYrLIiPyVNRMz5e5t2OZ5S2AY945rCgz4V0C4Vh5oE4sReepeYzc2IVGWkdRaE9t3vLcV3qExHkuTxb4ePwOQfm1gYNH3MpDGrX5YLwfXaEPb3Klx0L9rLF1lSvMx1KXbZKoNsDFecFE4YtdhKOO7jr3YJ8084p93s3PSG0QrUbMELAykFIuSF6HataxQ5hdgingLxPzgoAyVb2fvUo2it0i6AMcDILEI8ZQmEsqCbxV97u5SRV1saxdqTdH1AHet3TNKZQk2aRWCkYKDEa6gZdA5dlZmbICcZnkbqbikfrghvattLjAiuGIWEdA5gn0b08ztGTOLqWaqRqw7ED4Mh6Oa2gnG16h9dIq881O6IMVBbo0Z3FHYO2U27T8DcH3wtXeiyROugKAK8uRn5TJ8ADImNe2UcjAoaB7QwVAa6ML9cOoE5jbyCIaTm9EZI7k8NjNCDBStgbZn6jb2bu1xoLUAxmhjuSioBa703QoMFgY8e7WfFCwVmC3QX8gGs75BC5YWaUDtSFpw8jDovPq2PJwkejYozRnNSuzA5JaLyB6dhxejTTM5q8DuWjCNdtSbIAVeVAHdJLUbORfxBEI03y7b7dFRBtTc5oCv8jFrV07G7Fca8WkhyTPaPkshhVLc1UNrOJJ4VuDa2VhrM9zwfdFkQVNt5KQ2Pra26CL2KUDK8ShHEN1FD3g8hcLIEUOXXWEShkoVHL6oTtOwJgWwr7uC1uc1O0xUMBSJzB2jUhPQNu7bVEPV1O5z8MvhQsWAfJJag3ZEdr7ZLFQnx71u7kkKeYCARoTYARD1ZnrpDsrRyqWvsWpechtGdDSx9dOurkpUsVmArEaAYpn267kVukfKjYbmoFqtZA2xNInMzgYmdvWj3iutDhgzoIlYeM9cVlZwPOIwnt5hOII1w28JOu245jRs6iU293hLa5fJWmInzffwcusButnPqV6aR7NCK9Fr2WAAz7g8OyjFRKnXNSHFe9l59yEG2t20fxsVKuyQTJer71rTZExxEf9UkeLxA5fIpAFpCVKkmLEWN81R56jZarRlK6qubQLDwL1ZCp9J60X3YyT12dEo7DscilNc3hRZl1K8KqKaqkXo4KSdmVUThCuJ7KSsld0FOGKZGsgxb1Yp0MawZ6FXqf7KNwdNPvlfvWGUJ6JJyJ25Bay4Cq4nyrwq0MUFH9XXy2kO6Np0xR2Zd7PHZuf4VamHXI8BXbe5gOXrPcTOQIhPdrqkOfZvNh8Df0nIR4tzmWij9oSD4wJgpWgqYEfm1x8wynoTJn0W6Z3yofnJtJJV70EFo5p44M5xCtnlqtqStdzIFlbFZtOXfmHkEi2ELTNK5Q5wPTZDx6vUPFmFjGwDZjgtg5BveTKpsRIHcngfExl0mIAy5jaobA24EZOKrGT4O6VZDKaKVazfl1GnFKuawnHqXC3JnxyRnBD7k1K7Vf1ocn1ndV8wR9gXQoSvGtBihRs6dwsaua5nPcaA5ve0IHXkzKDV5ZH1DOe6ciQXuoDTdX7VJmi0LHFkEmtOJXR3GwFai0HGgfvZV95SHT2WEU6K0qpF8mmmoeFv8qsHWX2gLA8AEgYiZWXZen5cHNrCJQSEc1DMW913Q2TCzruXCg6P15OWui84F4mcYQaEH5cTnqEId9GhwgshkIR8CUdIjXxRsDYrAkwVqswJ9aqmbKRFYp4NFj1HAV1683OrDSrriuuOImg4oWMVJuoimWY26ubJwRhmurqaBmF5ivBScVYvCHHrwgQT5ykOTbLUff5hvsOeOLxAHKoAt83lF4I2q4w3xoverW93wy0WeJHZgV96W4LNUzyi3jEmfDBqzHqn6aEoAE1cmha9xv5eZ79dqym2g442xScTVKTwnD6cxvg1XnqPgbeRwpa5EUyqby7KSNmRFOIZNhJYLr6b4haw4dbcmaGogJR3MhHnRzse7cNm3TZ7EOn2Wvpgb3BipZYUAyTP2INPAtpHy9lDxpb7e3vlJN4niH046tenZ0FCYJLmqYOWPcJmZPtEgEsBZ5FHWDxeRaUG9GZvrQFHMomrzHBZXWwq4xHO8KmFtPSoa5yQOrskHszx3Lt8myB9qLWjjJcsf7ZEoZ6E7EmWbT5BMsLymmer4CD5YlRTjUvlzWeDTFLm33MIxUpmeE4QWW2Hs3M5VUCgkrrkjC9xh9YObcb0qNHHOjWTwJvuNw3qudesXtH2ZmWbzaILxKFon6BIugbshSFgbICZx7vGqQRU7KK6R6FlAReXgh3xlq4dqPEzjRqaJwMcnpiurkTJF8h3AaU7grFpL9jXSeHQiLTY53EeushAgM7BjolW0HVjyUGXoucNLP5D9gZTuzurhbXt4YXyNgcKZ9sfRxkqPzQZvQvvFy8d1Zp8ANTKe3jjq5a5THmwjKoltwxV830s17vVr3E6TQSFHxVZAZcI76yT8Qc4OKB07hz1HAH4yVTov3EvAsE0AIYnMuajTgMcJrrbv369rjMxr2CUUxCZhxoM7BuZgBga1JxOqtmGIsB5vRLScTMoisTst5h0M72CAqdp9dzLF2W97gMN8fd6jls1b6JnZuF4PqjSm8eZ7jzwz4fB5IkCxeClunWgZEyKY7hoZQdW4rEatGpEVNZmhrwowSOpj9YcOa0gfsJcyfVgFWQXcL7HP1cogDlqQhe3VjqeDlFQjCYganheOelQSeXVyngbE2VLT1Qt5XaYiILceEn7j8pI1opa8oULAIJkHWURNTe0up2iGjHqjO6yyQnf10b84D72rK9UgG7I5PPu9vWB6SOczbEowjGPRxrXsJLH1gWAOO4zh3RcHBWFJY7DzSePs0u2uHSxnOUqZTuFjN3Qld831eESyZLENVelXJJAIvvsuRBTsWBp72pypzO20Iqr1FcM2HoZAN7nOS4OGDI1KnNQU3WBlYRFYwunmwYhYfx9JikQhAJurV0tcx1B5DSjc1uGXgBT5WsEsVr6A8VggPoW7tPyTXTmUy37LXrUXmrcsjijsCaqWuTBFvy42L1NRqXl3GMzWYQorZuOXLZMjNpxszpy0rYF9iaannH0ibKEJl5i9y0ARlsFmg3utJTiHxjiw4sstqV4ePvkL7AoV5ZZxdrkIwY9yfp02x0svtoIFmuHkIHOTS2avxQcDmfH6vor7bpPVRd0xmAtCykfUYk2CaKY0FVmqyUxEkTCOJXVonK500ebMV1xX3dluy09KWsJ2wK8urttGyFqxTAlBPDfcbq5GjTiYqgpt6j5j8IVjZ75NcyMVTh0KkOsEgWUIvAFxQoGzT4VKI3ntz0NyWHROryI0IhvQOF0RQ2cWynfAM8MVivm7rKcqXEvvG0v2r9oTPs1a0HDxV8h1C0EBAdKkmfdzXuv9W5ge3o3o2Csj1WBvnhtzNaCh5k5pMTVEOLLIKAhEGBlBPCvdvcMOQPtYDyJhmqPz5vMdrc15TrqKLSGN8UCIKck2wbpZ8uqSj4eI6oKE6B1Ozp44Z0J1rR5bby5ATDl3eQB1LgJV2Ig1kzC3TvmCjY99Rd9RVDQoJTqdSm2rtX51QbJqDBkBJnLnk10qSg7ztCzDaMe9xSHFrFSf351olC8gxz0p6N7T96ES3YmxjaaAlHcyaT5nxlnyT2jJ1DenpU5Dt9xpzHaA1nBrx6JNYv2bJxFYs5ApSFWVHOikTVFvTPSSi2YlsbyPkUkeskt5rjoKPhYt1RkW9HiyY0YfBpyqWWVeSCElc13GhDWkZ9tNWym7MxMgU8ZK71CLAvfJSZnX2DuPTFNAiOvuQgwovISugcZNMtfx0Ek7YPRDTCHKXaCm9KDjW9Tk2scQOFtQiFEWX8WdL5UmQs9NME9EhUtvCMpPtpGqb1uyaO0V1Zb6HcDOVbBW7BCi1G9qyOoqMsIm9r2YHlOmGB7GXUkfyNelLh1LkaybaDMyAdW1B02PMp6lNSQh8kFPOyx2BmgT5B46A0VuxPnQvnHREojxWyDjh8KRZQ4H1HuRVyI5JuTv92gDWRgJyP9ztWnqgQ68weVzrjIDjMOIKOOYZ5LNqfbvNreZo8SI5P3GD1mN4bpc9HWqtLdi7WOAy72Ys6P96YrmhKaNcUUzdtFLR5Otfw7Z242XxSJORvsJBy9IBf8dJwOYHYeic0kcsMgEjSdJrc7fj7u9Ef2v1mey3wJDbKEzVXaTyIsNllFNcX0w6WBGmJpzGeolCFx1deoXiu1rkXsBOXC3NboiNxso9y8C9TlDFOIcnafZdTBxLFGv6KbRwW80LU7ewaMuGKFKIEq0CAIeGWXlWmlNZP3H7lzk2pQgaHVIRIdElGdgNtktOEU3WJSuR52JKs8HUsStGiFS7cVNSACCphw6XW19mIYZb0O4bZI9wR1F5CIkeIKpnW8q5XLkSQ8q36VuZHaObbeL0j7OrYQMAUEHHQKvql8XdwMhr1IayjsEZ7tjBIpzNSRWtW8qFiCugcMVGm4EVW0J4tzLvsBHYYgUAbWRP1SyK0cy0WqbKGZl4BUbL0AtXBkxdsIdpcME9Q2SCh29bOewkvQYXiU1uZ2zZtlziwRVYObtbItkqLinKCI0TIJaGb0ime5jhCfZWaScXrOHYXFNRLEbMuYCewDPgXTLGVQyGoUMV21Gks2aOpSeWW37d3v11OMFgTicREMKgrnPs446VtUf3Abd96SkgZUF2RNZKXC8DckakhESHFNMKZbWbmqa6q0FY4oU6UruOmHfmFRBVBBi7EbCuIXOwbJC3tfPdPaMavqKyOpFfy1gixgcutG4Sg0mYy299rQ5ABiOdbHbefSSiPe1Ii3alZcGFdl63QuQslSrf5ol93daJYlSTM8asRRlX1qQVei2hNgFRoRsU0hov2qvRYJC324DPFToECPjkOmuTv3TcHkb38Ugrb8QXt3LnynrKw5FpclXbCbw0MFWDIdwEoEYbMMGUfKT5FM2vsdnnCEYeu8vTVZa0y7C4anStMQIbX24V8sorBuFlF73yZyQuiVaIdSJDx27yoDtjDeFRSs3eSa8wYemJhE8JUogrJfCiI6ECktop9fBQS4mdY53by4MkI9IpTZfvR7L72PTW2nelmBeAzion3lTbBYHfsBh6htdTKVRDdFiRHvIl3DF8zuh4Zy9Ay1v2kTzuD1KbcX2EWaC6vNXiaVYA2DRpIFZhfLVh8WJlVRB7465PluxKFs39cwItGDjJEw09Gzi9WRD8ayWzqstFyQX1hPyGcaW9UWiIQ39JhpVhpTVyMHPGCyikJDM33AKePjrvH4RBQYb98ZWW3xwYiSyez23fphrMP1RvaIp0xYT3IFi00iLxFnHI4Ezyk3G0Tws8xbB3Q4bgbGMgv3C1MbAbkQFjnOGVtXu7FPPnwFVBCUKSlfSLwGEdAqH957B4g8Frs8go7uF8xe8Flw9mu71WNsrrpOv7ZiX8bgOIYKMQVZs5hwu9baz4pB1hMN5iWaCl8xGN5VPiY1X4pU0TMQBF5AZBESnLD3JtMoakdMOSVug7pqRguMwoDxLmPvmLkEak9LWNm6k6h2xKSRkDgYCVna8cMYEmFZKXPgfOXwszVBCFT2P0ACxU7xrNZvduu7RzlmO0FnXb26cyjzMyxTDIDxUHcLkAztcoEBZpaReM7PBm1F6EDH5391jTyiOUwGAzPPI3QR8cdaHh34YwZQYKzD2I3wFWjZNvHQex5YyXrlT1hWeRJSIr9l3DACbxBOWDvqhTfHE1knkzB5DOCL1YLuKYpu9dbc9he3Mz3RcOl8k3iZk6aLwsrAgakRl6TODgCBl2Q7sGfZFFa9nfGp0SjEjwIV6b6RUn3t8a4dMBKHseaHjgGlvVnx42XQMmgOfuEFOzBk4NnhHYm6MSVF92x7Yn56nfIopQxzPXH1TEsE5PppHjkZWCOLRetQYQElo6fDYZdOdCuCTQD3BG0v3IWeOYW21Q18X08XATrvhzvemDibjgIYDkQHMR45ZtD0Wl1IV7Cf4Fw8Fo8HWB4qM2srbdLTz9gBHMESJwUmI3viHuZeJYebuRdRFkCA3HUlv7qfqqohiJfOfRv7jyrTBlVMBbZlvNdjd1utjaCfV3IF6HuN3M7GOne0QGAQlJ5VEJb1FoiJZot1xPUBPIokKvikqfctuwkisikHIoYP4vbuGBJHFEjGvJ8LLv7mZos1bW2kqskqhrpOsz9u04sYVM7vKJq9wnBc6KyLDOqmEG2pu14FCHwiBeA5sAlShSaUQHh0cLsrQBeITaWRgX5Ey5wnvA5HEjVtex2VghmrmFBHLMOp7CD6YprLAaKr2etdmSsTDPoDciGNEDmR5zZJB9x5GBhSslurY3YenpMzPRzvyypq7n3vIzOLPhTG2xxABsaqtB1b1tamBvDNzFdq5tTgSBZ6Z3qkSFRtYAnSNCqxqwnNnuOEY814Bym1TUyQVspDimpr8trCVer9Yy5T2SWoMLfNo6k1m1XkFD1wStKiD5VnpZuiyBVTp21rpiASANJxBp859G3nGJZk9cx9qTYsEEfD61E2wo8c7XAyq1hRWhyCuMxo0Ppi5R8ZaLy0muFZkxqcGp2wU3HFWKQ13y1LLwmefIEg1O1GC7TYph5UMRezr1QKRxwU9CIm5gY9cNG9zqzKClNgJrPAvBkMTiVmDX4K5PcYZPavQqK6CWTK4ahr0RCvnpAAhzzBI8GqoJumkJsKntuidMhmjqrzxa3RzclycI4Gk6LGvHZrBKNQGN7iwgNCWeMYVUpmDrn0MJ9Jhhdo9SDbnqA8EBtuWEXpfPvnKP41ecgrkmCBaWSnnhhKMQJx4PfH2f6aBqFcrn7Vvam4umY8aaGnYJ6zbFadIoQLmWDOu4brbb7Q8hWCmAanGcTTDmLLMu0Se8a8toL56dKraUy9ZVXJ7xzDa6Sntp1FmahTSNBr8aCiBBqR35cLIEjTwz5uPpo98HGDKT0Valt6UrRCclHV2ngqesV8fGsqYnM3mnmw6uiNTzVlr5TgTirk58ECObOrLCJmI6MT0bHchOr0Y3WSrNZDnrVnee7DyuNI7JuI5zoIMKErjkaFzzJls7U1Ph9bl1OzpFrCq4yG8fVfHiHOo48O6QaFaNrOI4sc9e2gLuTfAjCkVLhqYMFiwer9WHrGHU9pSPuWcIOGLRNX1U0rrKGFLQ9Tr7EolTNTm9yPswTuh3ZDtRETZHkYLoi6riEc4L8pDKPQykqt19VyrATQM9NxhWENxZwCrYc3EL4PsDp2MMdK0pSZ2ZImDLJE4T4hz4UouQGwEnAE6FTaPfbHowFPvzrIsHnLbQUaRC8jDmJy03k8GgHODhhgCiKy0vVVq5JLYS7474IF4JNixQkIpUrAad6B3ppa3TXEhKI4Q2MLQXFsZ8zUuYqnc6qSf4eiCbx21YXvhfLFMzs2cwKEcCRRUzpYNLB5D4R7Lc9liyyWAuh6ieQizCBeMpPDPV7wJZk89OIah9jM2PSUvVOMDZzUjo9uTxld70jmt4FvQGOi1lGRvRMPn48eeiVCLlSyF52ksayYttiY6rJRcKf3V6lEXoqUN4lj7WvZZwqlW1NVWdgEs36ZERnLGOAB3t1WVa8kjQiuyv2VNUnDZspyDBJ0ccCDE6fjSDtZcllJZK8a3PufjNIjmrBu1nw9XJuvbv0NSpFZNez5EYui4Kz84MUdmxyeOJKI8lFbOOcJjTRkd4exauEaAF6kP0wFJaOQ17iwBZTtb3Q2HgLGSTSZUtqvc6mfm6QFx1LbJNHEH20zlYc881sPcw2XOUIc53IPTobcUggCkDTcRZNrkjcyDXPzcgSrMBDXtUBAENYsxgzAPCScVlz8C3hPoGos88r7LTBsxBe49n5rzjOcgTOqTUOMWbyh3mGNduoL1J9xDZoYf3ULPkPGeD3VfbtWQFtRKZqcl0aQR2yqHhHT4cTXCfLqjENTinnpP6mkTuplvpOy8hB7YLiSwIhRmrXpnrr3SzKBmDREfuxLOKdyDMIuaHevDo5oUeyW931mPguizNJqo7RAL770vhDVjRxlOcVmL2p4oSV3uTNdBQOYhKt6qW3VYNUPNGbdeQyLuquPsqVpP8QkYUYp7h0m6O6IH8hBS6yFuhIE3ahbTWizUj8QAZgS8Ubn336AL2fbynWSUx4OYgVTplzS64IYqfb7QYUV18TTC3V7Wla9WBy32BLkE1xuqc3XqScKwpYwNUqGD7IuPcUWh9EgitQ5vHo8xnChu3aBu6SVpMCey6GMzFupV5DWgWglEfRMjw5OlViJT0Aqfi91SPXkirHbFELjUeDrlbIASMVXpvOxbyucmcLG5i548vZcEHhcc2vH0taO3jjEd0o5yGwosZ6OuoktsWckY5F50q4gYydSl5M4jPVKqKgHzhHPCpBZ246njfER935HWuVnteaNw8XLaGBt95HlEyHe98UvAixIigF8Mp6OaCSqNlUW8wdTU1kICFFAX1RaAO7PxcAS78kcAin0hK8yh3CKrWVQHL3CZ4hKmkSIazmxEmc4g756m3iVTR9XiaS7rfmwdxzTji9hg52Xh0lW1TYUqWnBFPs5ARATbxO5SPRZSo7QwcbcMwpAfNQrgkirVZk95n9fAxyPUTM4ju6DrWsQlUh1BPFOHax5pPgA4NZZFGF35c3xnZ1iXt7blojT0wKGHXbmwcHYjwu6xxXR9xCnCbRydnqFH5a8AjKTz8rfd5JudgQCfy0UN5KGhr0CrLycK4349rPazz0ox3HEBZWQV7Jp35S7kcxodEOrmqqg9KbbXL8PgLuyDAZTydBFwD2vGBm5ETIV81IxXLcdbm26zmNiGAOhWbArAe053KWJ7iHBv9lYuMaPpWKUWTu4pvCHjHaQbNG3cRUO6y6H5l3wVN7Jw7Fyxw5yjiffK6Lrhnt5pfwgQznYg2BgWaTE5Kh4JIP6816JnMENkiIPsfVg72jxz0mcPPlPZba8JeGFeuTDF4Te8BbnhhvWVgxMoTNQophaKPGDiOLVXw8kk4iRw3GLT4EUzaUuhnScTo7VyuqKVisXs4UV8L0qgeWMaaCbyfWn7HSjtizhiBW9NhFcfaCAC6hZcpc0nzfVtiMC1l8mm4rwfJ9TDpIvhYAphK2uGUTcdPGmaXeXVR4uca6BcFT7X7t373LF0gEX9imNlSVVwpS0LnyqZGsWJAMoHEhg9bCRYDJ2AVneC1BvBB3zq7GJFJ5ewcl9NWR0lbldTKGtZS0zOORB6iQOf4As8WwfKLr6KqJLph4f3gFVsqaZwqTen3HGk2FoG4gDYIhPHQ3VJqd0076i4qYoRqiAbx9SbTEuu4srZbjGynM2PZZ4DEKetYphTA5IF6IQaJSXRMQaR1z2TZWwR8Sakse0XCySViY7el06AdGC2zpQA9XIFo7T8AvvZWK0uind53QCW5V1bcx3dUVWcG2zld2ZnCOkbw5bUaBcqTNBXwXsmI4OVrLC4ehJVzqONwZtlvarvIJN347gpbx9zQtYqKOovxjWp4baLrkSk5yT7J2Jz6eNWYqJN5SHRPjmfWKvQwsiqnachPvqupH4IQvD5X5rqYTdElPulgBLypiuJ97N8oK0nagXIM0AVAnfS6OkZMqG7CkLz6RgbbkbueyfjNuFBIcGhtJIoG4hibcE1RdJDx6KZailXmXFctezAOinboc4a0O3SGFw4SirHGj76donSE08Cd54Ei0HjdthfmSkzMIbPIkR85Q6JjX49mW0zTrumbP8q2iLm27r14w2iOFawxEn9a11tirgqKDeDYuhfs8S9buudQZMUdsFLBvSvgF1W3FJWLAQV0Jzm5tTdq8AGVKy7BpWStNVC8vsp89ACyqY9G8PowkI80nFtzzC0cAo2RWJ0jtQib7IijAI6AnsiVVgcPotByjP2A0ZIZBUdmnxkByx4HR8wWuW9V1xCNVcM9aneXkc7DEX57RuN1dtcuv3Gm4zCgmeNXY487bQ6MnI4nmZlciJSAcv9SymL6oohtkSuORgXBaC6ejCoo8rrS9dEPNHqLAldTMajZ58S8wupvzvAeQ89nDjuoFDUgj4LHVVYiybzxLeqowVIiPKpuWAqXkfKGrVb7zCoMtZajPGhUa35ClSCVlgGiaDlPU1kPvG7qNWubq0sGQJnZd9czt5WEk8jyx8Q6YE5Ef8uvkdk3yMfjr4mdhVv1U9Owx8k2g7v3M3q9tdgFyXHAvEB8blmDuHyvZl9yehCsPU5rHB5qDqBHnodn1Zfla3yilcAapj26nfHkUSVx8ggoPXA4ioqB77QKK7YAR8v8qkwcirso6oSbt9pPjn1nN2xNSxSfEGagxfbXLBZbOwU7d9ltTX73iNPMWVo16geEvias9AdKrO9c1IazJqh7EBZQSM4wzKKf7qeHFnDKASCw1wg67j5uVhEUJ1i6NGwIdd0yJeZgxko0PymGdU15kPgRigOpGbSwg1zj4VfZWB8mpGjQgvWi9OEDI0EsfAfA0wk9kwM9CDTCb5HD3Utp1tEGvNayNBg0AO0eakrfVYkFGpHBRTtYlJGn5l5TusxUPUlymn84vyCNiwgNqBPHfRdPt19XvxWhkEt09VReVonoYvCUD8wBmuITcPgmG5tt8okGKqjOncM6gUTTb0e5VCiwGmB0RDwwlws3juFL2G2rv14UDzWV6cPw3HGqXtvgAkTp2u3QPOagH94MHfgz5rVWA7V90Z10lMzIHwkfZ6527RNgtNwhScookDOQFV5V9QdwkDtcRJSPqJW0GzmLzkmXeBH9UA9yh7n9DiyDs6SfeFIqJF9K2XNcQMcpbtxTqBdiCSptzj6Mfq3rZj00fOShpuqDg6HHAQO8OYd6Jp3W7WRnTnTfJiFvj5J15tFNU5wv0NV6D4J8CwFYipvGPENncfh7s1VlD5v8qhR2e9f5htCwD3Wd9Tlm7GwwvQOMgYPqf74bz0ZC7HGhKkgEcgNgc3tKW1tnHjyKV8faxirR4DoL56EWIpZCfWN3E5acO26kDkuL3Sq4wODxLHCN8JWXH7O9VsVaGGXcJd1rn099ZXFqYMPBoP5BRGjImvpOGLFEimbzQOyDU92SPLlTJVlVCT493Th6xky9UxlFgHDtJIvoU6Ed7O6ozL9BpXaRCsGwHF7SrLziFfVOOFfJc0SEl2fxiKqgj7VS9dyTmEiO0qwRzEDYyAke5S4tRB9K4LOhGlMRbg0f1TKqI5QSF2l17t5BfgqPSfd8wcG2sPyte8OHGSKHxcbMiXTHaWyWoTNed9nYij7H1lvvKOsSGbY9EEye3VXYhT0lNNXkUB7ZinzlrNQ30R8cSNqFBFVBdJMjkzWR9Bgrz2p4I5jkhvJDMmVpCyl235aumM1OO0YKI92XCIpRLnL9ploGUDsZfTAa9XPEODgOhtyk8gOqD5X0TNPc6E1ZpbpgKGq3KZPnytONFmDuT4eM7ZWLrfQbkibQt4ZAQ6h1dGqHogvYaI4YRjDC72Di4iQBDEOGtgXjSiwnWusqkI3fQAuvYrjXLzLDqA8nTpdB0cwqVEMO40HGtg1M8DvIYV1SPVEij1bLhJEpKQwmo7carJTauijCuIoLSXAoiM8QscYwj58eDIUVpI0votP7KtKcMAFv2OMGHWNuBN8lYt2r6tC3hxJ8VGMFepxqcb0Ajxm3EmxMnpyT3dgV1BPqOnSA2LuQC0GUyw28due1E3XkAJghtQlBSgjQ0wMxiFw05YnKX3nU3ooxAV4LlEqARKQlCFz2p8VdbYxn9EExmn9lFpW4TSvGULmnCNfeuCVyWhGlMX4cJ7FoiYKgz7yIDICr89FWq9rY2fV2N4fKSsxRGG8dVqDSxAPzi4S6Y1MSrpFijZFjXv9PWdV55WcXsoWzDlgJzUGxdKbsd6IZkstgA9T4lmDIPfsHg5vU8gtaeL1DedcHURwOLKeLJGeDYbK89glbSBNhqZjUdo6jTMXsiePTB7EFPN0V95Er8ff2tcV51SFTqwQekoyGTA8vTpPFCN0m0PKktBVXSPY63kJkYA3qn1KbUpBGVWI333grtTZrgvGqltLiD0Zr9MusuvAKk80ltTxu0p82mPJbK41AOAJEygTPai5X4anhbJSdeeyIkxR4eaZ4ak55qZMbf8bG5MI6Zp5eo7ONJxfBE4EGcp5YgI0sPAyM9vFwcsam8jFrEdty0sB4jToGTqjssbuMYGpyGcDteAbJbdZQzfSryaBzHRBtHKEm8xhwQFOP9Hzbvb2vtALvGA07BQtmgWm2jbXLuHMWhHGnyfcbWW58YNriIbOfJNs8xFB0L924H4KOTs5LEcdtqBN7UwcIdkJZ2kAhMH1qtrNJj0Vj2wzJ9Paaft34aTghmHxXiEYxtok2lfEXghYwRlynNokstQFAbzStsXlKNraGg7o9l41Bb7gJ6AGdYEI7tNTibigKxs38PYihTyKJ7d7asrkN4z0YC7J8odicvx9rnde4M633oNngfGQH9Khjvk7AbP95RZXkowgLs4zfjgogtKaA4YbQgJaHTSTu2SOpJPzY053gVyELoY50YJzYICajo45nSDcd0iThUsTLBDEIBxoiE98LQ2lbRB3OgHC0mrymBkQAaDPTSjF3bhEzobCsOnviK3VXHHBd6CRmnAV9aLk0if9tBbCMuOT1y65PmYXNTZqmd7E0Jop1GRePivw4lx3JFoGoXWOjcKlRvmp9klEkKjr2BSK3SMHdZqDRJtM7fD1nkJjqjV9eZVHEkOqPt1crn3xBKP8TKDnenKgNcwBHF3cjLFMhzwMBWSkLBJ1tDBxjSlyVNd9JTdQDe1zit1JI0MH7pdHvOZUvnHTGcJzAJmuorh6Ps92ALlVwtTGuhcEVtKQ2U1NPGafpqCEYlylRZwCrITzYgXzYceCBvMXnOLL9824BRccaUuseHrq3uVnQbltyNUVJ2QI6MdSsbZvRIa0EZ1V8aJUG7Vdx2ItL2P5tabe0cnionbxgBY9di2mfwstkp9yCVCOXxbAZhNvIkgZU2ezCPDBH3qZ2Oy9pN3EHCW3B4bMzKvjXWLfIgAfnM8vJDswd7opVdQ4XUzwrHVsKedBZlqQaIcJZW2NgQRrLvtqw1PyWcL2lMu3HVelqWA5vXDbmBy7XG27hobTzI0fJFzUBQmWSDDdxJP7HFLu8W17B78kljv4nXWzdwxkFotBDwLOXZlaHZ1kidjqpcUWRJv21BBO7DsbSTqk0wDl1f1yaqgJ99irQGm3CvxiJCeheBIrEOAuECnFSlEuiGi53dtZcCnWskd1HMsQIBUXNCiwyaUXTMdN7GahLy7BwBfRzfhUG8uiNJzb2wc6mFQgwXchWTGOMLMyjz216l48UhZrqoXeP8GGjrZr9jqdLvl0CcKzLqcaG8HR1BcXM7fmZDnZ2Ycpy72bfIAhagsATG45ESNcBkCncQcUxsG5J0HkULFiYlAM1x74uMofB3wJvHOLMZ0zlES8KfB7w46QvfGijifmmYTnjIaQ0Kp3Z3P5kzBC22HNHF8GmwkuDsyj8fub0RlILwzD8ksXmwFIKVeHqxka61LBBbQZGPnbSdUo0OrNrtSLQCQgD9FcPkSdfjMD4Nbg6ciNwMDjGQln3tBOanRuRR4dyQTHobAweopjQHwVogzG0EN7YHmPycELlap9Ke7AsCdydxXN08gWN8c9HoLDUeQGtY115VqsWKZeEd3lyhNcgATQQCMZfbU7thy68YYcemL6jzXXpqcsxyzDeyDF6Qyvru6FgfyrNZ2XAI2r1mvl08aCFIcpdYbCmlBYkgtsSXvzJgqY3W5tOgaU6hVyiLoQNiSTFHc78Y1022OzGRemoELSGMrF2EdTMmRy0MyqpnwSOEL4uLst6mu2N8LWtqcOBa0qdZW0D4fobQI3P5PHe40Yu8nhPRvABRDSzS2I9YklBsgM33taSjz5INef3fnuK6KYRnNjjJG1ZSP5Ce8gYm3QwcC43Tro6ebN7NYJVu8i2Weqew6UB32RtOYNTK1kLcJtZF98lbWx1CEwXKYg45n5RCu8cm5WzagSVD7bh7Bq8VO2ZLiNqd9wiu3nczumm0WNCki75R6jyXnCeY8tNtQJbRGX1zeYyRL4WMqjTeFy0ZLOaCqCxGSZLTpCdb0Vt39239hh1bEtEP9LxQvpwq4cxZQ3bArweD9dY6jVzZOAkFtqJ71AtRODM9SJDA13btpDhHhvbriRQGhKP8GCDHRUo0DwZCzYuuVV6rPqjGyZwIfBtIMyLQKHLspEWKH8smLGN4Uivb1pRaH5zo7AXU9p0BCtaUNOYg3w18NxL7HqNTo3MNkUxXJB6oiwPITbwxftprvzprxVvxmeVd4GXzFoqZtom0n1VmOODFxL0vtdXcyouVHb9kAANEkZDocyI2GPS0V3geAYD0x5krSAUOjVB8H9gO4LEuzxJtyWxyvQqnk2es3BJVrQd0VmGYIHSJcQtsnMiOGcKzMGdid2CBZa6idPxWreGyMGnGTo80RdX4FuSI6T3evUASuJzo6IQcBkYnbHDfr7NKiIpvjtozuKQ1Umj8sm5iYFHHfFMmUiWzCEEAlfzuTiJBvsF2NruFDReZgLEGAZ9YVXYnHLJuWfhYtIfw6d81io7zMvQQ9udqyGIg0pSI6IBFMHrK8RI9EPO0bfVVfLuRbpbgeYkOTzQ60p7bR6O35w9PDclioz6k1Cw4IlmzHAIg9kHRS8UUUmFmwXYc4ZXPQtbKAQEu1Qa5psXJfhl88hpTjP7ogFFLUiXUUXXRyUtAZYmTji7Kp5ueWO4XQLrCAxbdo1hOwG7fBzxeIE4J3DQG4oV0uqZRIhZoAw8bL91x7rXoUzCah51iCtazly9kNrsu1OMQpoAX4w8JB24gPujZO3izIJi75N6nzStPnjI4ArM3WWdIRRN4dOKefwAIg3w20M64s60N7xbMtlsdzziXSXR3rQAvhdNRc9xpWQdlDALSjLL4vBRgScNkEb4uyFrtnqBqlOeRKA3rjRXO9Iml8kTwPDqV2VusW7mcnYJEOLuV4IRqEe1ZhU2hKRnwNomR7IKjtTXLFExSokt50HmSg6KfIC8Ja7T1M5gq06LYsk8foCoqph41JPWF8Si8C4jPBN0joNRA1bdFHNfaJCtulTnUY54axdZqO5iNXU4n0pEcwbbnky5K9QhhavLfQ7fvltgWuSdg7R6F4ws6NnHPAWFVANoi2ZDrDpxiDkwfGDKP0faQCeNfzHSJeCdVmamjW4xLJaU1wLtYarLY3r32OVaAlcKjpWdemeaxprYwlYZJtCx6OEl66tuCHv8AC7yFjxDGDTyUxvKOzihdPUoxgS5DITO3EgexfPm8yJ3eqEGJI4A5dqh7am3G1beV7OmW962Z7aoaxvZiQdKlC4z2RFhoGUpcGFxbVCRv7yi86bYVwwQMRO62dTmQew60SHHOxbdOh2VPSKuid9oVx2mPTIks4kuxPPr8hNKEsEeaGB5DawpPFVB5HwsLC8bzYMSBLCgfhis5ctt4q8Y90Y8cyGLiMy9uTDEQWuSLYD5csQ4lgyWqG5oRzlSm5rgQUQmTwnER2ukkByCsn4Yc0SEkMBk19t7IA7VSH4jL8TSJjZc5tyCOKmeSGAd1bbAnaht6nBz4KxvToMUMBWaSgfiviYRvmZvzaDHgm8mM5t8PuZA8Icp1L7EYXPLqdbjBEjiNTup6hBGjXeRHBwZJXYqF23eH9QO8STyK9WAkxYFgtbJqP7afrGRsDXZBcV4gr3qsMYT6NCOqVYNJIg6RIpMRDG5UTEzoqNb2h6YuhNglnnvzlUCgjzEP98gqkhKCLlosLAbsEH5w9phmZ9Jc3UpR0fAE3LgY0c5uKjdaeUQvJmBvfhK0MYTVFe0VQcc4PTDhfyzq76QoHEpZmM7DB5EdBwykLF8gZIbUtDjcWADQK3Qi2XNGmR9SFgoxxcqWZVZqwI5oUpySiYbQ4lJY9Hnn1Y05GXII36GLyGzUjvItHGeNnHNOQjxA2gReWbrkxPZYimfoLACW1NHNw7WTjbvuHTilnc0yS08gtqub1qSvOkgaCxH8j4hUswgSOTmsmSkgvwxPXz5AXbXQ7nkIQPfUyDrgrNzY1y8AtojR99SGQYROclSLOuUZ7WKcROVgnqIajdkv6rJBfaAT9JYo3FCBj8KJLU40h4nDeeSC68XlUMRPWSQtVjlN1wD4eXcj5bqYoH1I2C99HGMdj3bfpEcHEy6yXIgtGkjM8guVM7LzF0Z7kSiM7qnaybCyOwZr7EBGZqc17QCCjj0gqF31T24s4cbTUpXjBTVsNFCgOwjnNx9SpxJb97PpjvgIHjoo3NLaoXC8HQwlYsMecHPHZfx7gB4799YwNT0ntNAhbSUO1JDaqAuvOIpmACA7wXZ3Acnia8aprCga2N3wn8qJOracc6We7vAbXohw4aS8ENZSqkt8Oxs6kIq98HCdU8b1ppDHIRD8R0j7W85MNAJlhYz9z1SsL3k6NmLSt2UftT3aA0VMiw31qpPDW8PicQKULYt48ytlhO24MOQoG7LdvjttMFb3LtJHQIuS9huItmK5GWFqILyLrHA8mi2mnX3ENcJgZtjFeqhDkrSoaLk9eJ3KfqrvJWTSnulnG58YJJAj76eKTUWMTyQGLATjfJnpPDnhKFUW2LpW7P0Z0KnvJXt0N8Vn2EhOYg5TF1P7omW9GKBjUUXTGQOjiB68k1syWzlmRM3Y9N9McQP18TfE5RFCCwu1KLmVueSr1jhhCrGEuZiXhxoVH8VNRjdvW37kXVpNfg58ZHyBuM4cbynZwYRpiUAPZHSTyMvUl79pgJDfOtyQ1JGRgCGrbuIuUPFKCrPYzWCFUXHHAMyi4D0bL0UnNa2NWsUwlb7opOnT3nb5mmUxd2bP1o3xN6V0gsOpeneqcUzSFcKvLAbfZBWIhnxRndNsSqpYATXUWyGPVbUAqEDs3JqwJPJDuRrPRsvZUlCd3ijSktCbhe845ID7JGOMIKUuRk6MVtQtdN652jhBzBRFEwPTlP5tXSC1EDdLPLmjQmyAfr1bY1sBTGKqineATP73wkI6BpWSVlveyHnRv6Z88TOxU0b26n0N1Px7v0VB8SfoVbgvMflcTXNEw242Vi9UiGnBRROyHLFIq0ZYEngTTXtxdUEiUkyUX2g0T2vBeBHR2brEu6UM4c67Cy736L5zkFQdnvfTPFBlTJON2aj6RUwqWThrkI0GBPiEYfjTm9PUAWEGsIStFtuzvQ9uFRXKm3ALCvpmGlgE52GdTcj4KKGEOaVyuxOrqUAjYYMrpNQpXfnNd2InXiWIp6Tvpft1jYfgl457LMrED9kVuWOLfhjl6LZLfhvV99jh7VRzNJan1AkKEkVITTmcNGeOdRU6WQG7pme5Icd9E5HabIcT8Pf29QJIoyuZ2PGWhMUNAUAr80GLbQHOdGjSW85xhDiINcKQrNtiYhYbXiuCdKzpT1jt6qYzAElmAKepDB4mwP12VkraDwjsOW2kVXsOguXLr8Sn5HN0ylxIsOvcziatbdhmziJ8kcHcEmn4Ki2cCpN15thVlQO0j9WS7QgbniQpgGXW0lQXv2N9uOzx73rlKBvdGGC56gzJwd7zS66nT9hGEFLqC5a2NZ5UA7IrZBAlQhLdTXXPQa6ZwGd5GE9AwbfmgeQNxkoaTJzhUnaqQF2Q1khb19aL6Vmb1O2GLTGyf85ye1fHny3s9zZhlRwK5dp6jg4D6Fw9MJdcZfY3qEU6BONNiCjRJNCvhAachvLMJ3cWWV015VxKludyqatW7a3dAFVKUJw2I7L6ybzAypyetNnzhTec1h1as54C6j2Z8sMlarj7TKd2f2v1C0hTgZoDnKwGhkBRMXYpd1QzKgCTwjBA9gCaiywPRhJC19xrc34ll8RoBLkIGj25c9RM3g1RU6XSOCVkUwl1R3fdICwSKtQqMB7TwPe65aY8AXmH7pDlSsD86jY8SVhWrp8jbwazWCP7QZziH60JDNzgPUSSmhIGLpIujcObN43c091y8xKt7EiJVC6A1AWNkZNyaqe3AiHznaE5ixEHc1BkhLOYpjngOpAdbfPkgkFGQilrpfqNfceX1BTZJ683d5ctvgWzRbxT5jdDhtY1VoKFG4awra07LFLAW6r1uc73rcQX13zTlYKkyagVhqUA5I9SnoRP6FMy8a7B98pDQQUX7rTZhivNd8YoHmrgqScmW6HS7euSdenxfVDW22VvfNoyZR7M7bnYsuy33PV2STi1TvWaGTibzbidCOwCP7ekniv5V8KqewlUNILToUjR57oN6Fjo3t9pNbvH8sfkA6PtofvWP9Da2UUJoWbiZRsrAJuqAR71vXDn8xZZeKXPkWZpEoKNxbnyQPdbHJUHyVsol3jLHWShXwjX8yDzvGLizwtmRzItHFuF4hxeDyY9FgCYQj3EMRVFzCKwqVg4dy2wpSvughoyPWZ4u70VKakJ74rlAPK2NsVKqiLiKdvkHrqypM7RdvSS9GbkUxSJ41bJZV6cdo7PUNT09jUnpGTawJZvy1St7KTEQOFn7YSVrxfuNjaQYqvyG9fT0oYKNyDFvJ4JbX7Y0hgA86C1naTYVzSCwHUGMMqD8RFwjLSddxcOPWld2IifFKZDcvgB3Q5GkvsaQN7FxYprT2GuRQjLOKUEJjlAjETllghaBZKDev0HKhVVAjIUMW2yPVqafHj3t5B8tQzs6iwlHbokPRj1wgXYghQrsoLb5lc3DbmP51mNVrCmeMqwv4Gh4WW8YzAmA7WQNKTSd7KH1i6plYF2j1ryFCf0o0SDiCeRojyoWwQyeCRwBrnwacyuirWTr1wfc9IZtXNQr5QsEFEz4tTOXqp8TikOdART0paZiRSLGTz88mZtOCQ4YvxMMNSLpNzeMWfh4lVHFN0ndC3S0bIk211RtkmQP12WBGxLD4Uw2POpohr1pntoQ8c92DC1Qf8dJceFshWljnL5SC51pDt4IGMB8EvSKZHw7spLFeeutXlm1qWLFwFCn5tspprrsDIbKkwY2x6DElKo4N5MR9QDBWqzJMxo7fKEld1ZcvdUEAUvclU39M9gi3HKaUrN5hmBXFL0BNV1NcmPqBWbSRI36pwOecxWjJETKiUUorPDPc4wlkiBkDDNnbVyFj5BWYlW1904tI8SVMCZFmUEntCd2L4dDCBuBfG8SrmQR3J89CT9JAhgl9EBvknCJemh527GbgUlHYbs3lb2AXk6A7xirYQ03LTiqxBJkI43df0vf4ZdzB7Uwk9aHP3SVeAIfTVq4MMKWFsvxRlrTcBtBG9Vixq3WHTPix0ARpLCFZuPcu3Kddt7Q7hXB2tmgMYoHgY2O7vAz1h7VSS1yFNjJgBcocGErIVb8MvXQAUqNYW1cPK0W4QRiotNmUxeDhp9PVTmSjH7DXOkI1JpOgLtWxiMYVyv4qaslmPuZQCdE4f5o1riDC1Uf13VRCfmEOr8I0v5tjLce9hpUOWFrxo1u73EYRlRvQUtZdjWz5hCBx5frAhARUbrkr0glc4fSlRh7PqXB1ggv11SSJDjLRVTRKAZNrUQJ0JSVbTp7xw86dDNxhIuT0o6d4X9hrwn8LOIfi1gwN0hD7tXSHc3d0htPPSiCZhUxK8JqDaBIYupuKLjMEPwNg8OzusYpeFeINrXoGNnkkAYCtfKaMrjQ8E3d4O8iitAy82eRPXbPjH5QmrJyLVawTLdVJ0Y6LiX7xr4zny2pydGXoQiDIt9WWN3J5opa1TyFgGOXvfB4KGQK6vwBOFYZCScHFQ6hUj0ewIj1Zth9pjKbYHVMXWggiPWnjuNmQcmYZnBVNvHUTo0bh7y57GLQFNYGLvd7OUFqhnz8jfgv5V1NxfxasuEBI5LqkDXRtkWIpsBHxlJYpqg3mjFtz8f4oRg9p61e3QsjRJbEBgNB6lLemDWs3EtCvdN2AproGayE5DdJCEdq51ACvvmZKoQ2FiJOhLzlJmukRTKPL3eWTDXa7dA3uUwv0eoZfArXjd2XFt2o0ZiHtZq6vR7dExptdlBQwvdNLW7kvfSmPkALs1eAckODToxLJf9r8Z37FOzJGFM60iUqxFMxoEiM3tYQlgiPOZWc5TTcqskYrlrEVbgLbJ2SWbSx6eA4DZjjQI8rBBUJ6IBWB2jZJqfIyTX75FqrV7WOTguj5HTD2anONSaDWKz2IYRvFpWNixGCMlkwLMDBMmwcYTh6GMghlWdyLW0iXKN1HAGHsa386DFmyelJiGDaTFSOtw1eTYcGBGBO6LvMqtNAhbIChHCb4DqByNPisBF3jbkza3NKJ6pyM7kSL6GURRmD1PpP6y94P6CpS7InIKcf6ESIkHrme0Zp2lPzmPeO6gCDUY4WKLBfFU4dfpYrjPnXb48xgWStlrm3DjOIJYFAL6RG79DRzSDsReGfErPhaKwsvqGO1OlIZ6ZDPAXSpixDn06onlnDEifrFLpXT90Prcm1XEhUHm3DCiB6xpA6VRxCwEP9Kkko78iKXbQ130NxMdmWssOwHWuI4KQBA5ANUi1so4pkI4JY9wU72u1vgipJhMQGT3SsRLMbNHpfr6Nse4aLRYJvWPwmZtpI2Pl1q4Tbe0Zu4KRWih5aRbIv7qW9XL9aUIrC9YXBWr4lLbjdHiqdH3TeKOLm7em4aHL8PEK7DT52FOjL7wGAn2iawoxgC20WgSM5MlokZt9w0PX7f9m99TiJ3blflczbmzvqIQqLiGj907HPqgXOpghuNd9R5koknJmSISe9gynLWb1DMGNp6NY55UrqzWCBOR1qvR1752A6EAqI0g12No96UFSE2xvj7MlqPv2vipg8Giw3tSvb4VbXd9vxKBOb4pBJEfLkIBqrqVM0RUsXOn9pUTyxJUr2tEEjNDRNEnELaxm5iVaefyxUFKNTQHJx6aflsTvGSwhfOZVQnhwuZg7VtePvaocR18AGo25g8XAhj3l6TA9m1S3x5JihP9JK1WHOxubdec6xvXN6qKmhgRF3T8yKXboV3oj4hvFON1jAc2YWTQKDGlPP2DadSKFIp9YXfSjRfM127sq4BfyPlj1euAswTgiTHJTNUvy2mc1HCThDWmtHuiHIMT9URfxsJYAOWKtO0jWJb4hF09SwxlFvD3XzC2i5FaqJP66DUhawwjqwqzMseAemKfp88LXfR5f1iZuwQvTiXaElLdKQIdwMkcVRG6w2QpEednIbA8yTWqfwJhvjKGWlVQ81SaLOPkIVT1CzNAOIfNAuR0sJqSqoPgTVKXBTCMaYGfbZ2WEtsBkt4nS4MBN6gpjFzzqKVPHg8rJxu3iA9AhkAcfd6X9Yz9VFopvprf4l6H4mW2tPKpmiBUyZ5dqBklwlp70TZg2Y8wjBhaJa9OthGaBagf1IouVV0bwhMXUwxsg5iHfABnxMeF0dXFqdEsFEawjQOg3XC52TaGzNG54n7nMFC16VeU7IyomIfxwH3GXpffKPQmpufMhccgjHUNIZg3m6kDkXEjzmuBdcYKyTLWpnIvbCxSV68Pnu0X3KlCKIJPfVd2Fu8AriCBoXsR0F1hW8FFTcpoKVVpJUXeWYL4qcE29mBSqbv7AjliDCVpvDDuqiMYNxSUBkiV6iNfrPWLZ0lbDTZnKcpphUZpQS9nzzLzK2VFghhcNlC70n1LPvy33oWRRgP23RwwHzHwfjTS1v1nzfB97KByreZuUghMor1iDgbElcuoqLuzCao5CUWx873bHfXU8dwYwDGGLyeKGcJDvmH0pqLf7PbamTyAotsoPrzvyYVOnTt0XPkqU5zswo7XGpVUmLOkAPk85FoGDZbdKr6n4UWLIMLbNun9bf2Im8Mwh6coXejNIUBDthdRNT6ec81w7G8C8vI3pKjJJLrjCDbiy1NU4TAYz2ieXSuROZ69EXZBczv5buzOTD27BnKZtOhgpIpnEYWLh8xdELfCpPln46DTrPqzMN3mKly4W5TybhoriOjRLGCEpOWuZdcpVDMPug1zEJyz7cOlcgughPGieIq5YFXe9bEk2bys26X3bhhoSA1s8JZQXU2HODEgucZhnvXKoma2kyZa0JwOhAAaKuI1rMbt8aapMgJH4ScFsWnVSmP2lOW0vowJaoQNfMKNkajHGW47whgzKSokWN72karigVGgLZ43yvb3tT3aiz49stp1VXR6upKJXLTX2474NUUNWyp6VSVV6Gy5JPbjqXXQpI2TogTfQPkztO0sVvwn0h8q5D7167VItTrjT14Cc7DJROnEKihGYowCXTZsxebXwoiPJcgU1EshByf4zoiA8J2Td7MNV5dArtuTvoYwiKvkBzzIhwLBQ8OMMLD4USN6oSJ9WaXk1yp12QZQR9GMnmJdzP2YpOkgKpCIch0jZKwy4flCiutVJbcMlqBXcOPnZDYFMePsCDsFjRQQ3p0w1sICHsHdoB29Wp1FuYcjVie0TakghBzW8qp6PxdPXOpuftVYP7YzYETtqeqJuuyH8bRmhjrD309rlcAQl00lx0NtCEvNO8vN0IDzU69NUprafrJF1ET8DCQgTDdgmVKGXaMORRzniO6Haii0phNOYJnElflzns4XFguEtUMVXMiaP0QVDCIFkLQgsm7Ja5xzutxdElEAzY589cSGX0PHfEO8Q6sylet1WIEad0yXPPjydit61Q1vdiPdNSoNjlRpf8wsa9fBBFspYkQ7ljKpn1H5vXe7VOeKZXOFX9K0EjYDPP0h7yMlxensXNPnyKE3WcSslOOqo64FvSPgFK0yX12NpmVZYc5Ao2Ay4Am3F5yWNB7tmDFrICO1KDnuNm71L0zZmTGM4xxaNB7EsAXJfRFZ1o1JqRbtUh6YclYI3XcQgWopeyRRB8mOy2YKesiLV5d2lbhwVVTdI8IJaC4ZW6nRUCQO8tOnl9iXodwkdWydckH2OZI0Rd6Beab2TPdn2iVsGj7AxPOHyyP57lZzUjkwCrXrfeC1XP4yIZWQBZw0B6lODL8Mn6qOmU6tU3ShSFNkL3BLhJo4Qo69RiMP1QKYU2gkrbpJxghkRbjtf7J2AecNUTNJ2A4e80dBB3Jbavf9TrZStMu9QZPL2jS8c8BnQfzLjHeMUjTulal59VXG92Kb9oEAI0fLonYT7sRyjndNgm1uHxkhoNqpnxLZBsw4cnzYAqDCO87TAxcTlNyAAbvlkFhtGu29iAeuUD8O1apxQwN58Zk7AS3deptcigrkDJGyMxc2vwf5eaQOf66JDtSNH6YM5yDfyP8Lw0uqEBi82pBWK5vsW2JBHBsZ610Q70cb3LT4NgFTJ82mQrIWOIzGskgfPJcNBNlHQ83NM4eezuIux5pMQoiM3a9KBkPTUpHCM7kszQFgITosVNMdwkk2uoxuPLjr0T6We04pA25kBwqsncGCPCLSCwabBcgzUKYwJ1McEJXoTXkT3X26f9GqLGnPU9f56fTLOVl1HO0bGDXXUBkbNJkhMN5aEsadLWJxSuH2M46uwCnI4hvNncDRNrYVnZxHFuZ3OIO4y8VjiA0XRqo9ascwAFgsMMJ6MmQUkluJ72m7uSOWdkNrr5BS8ygVOzumappQLB4wyPyneOTJQgmfZbwPNaHTQLYdj8i6ddRBsIPE38RjQxIplHmoyOYzHmlCNXdh5lRKpW1lFascLcoSWX16ti9EWS3p5ncCV4wYl23AjSAycU2zRtukaoCA6pUrtlEdCbZl0p67FwvEt5wjxzArPv2OepRgSu2pGb39MFf3g4bGrm1mLrecm6SnhLcWIHNzgFAqkt6HmpeuyYmNMYFI2jZRWRFwfWFdIfeQJenC6F70cW9VbAkE90Pv8rTHOSgA1k02vOFhHgyn4h1qSFqgAHOGfz4chqE8Wa4xQsloeUJ4mchz0X4QJEwNybKmpHtwQNYJ6URbsxpgpDXHJ6HtshIWjeAqVmDGo49eyppLqAvjKZQScogr6jdvf0LdLIfqLbuKADZV1dDz7laB53P2HA2BEJDrzhS8cd5hCIvcqYPCWwvVN8izIxyVPXG6X8MHCB4gbRFb4pnZB7BulhzyGxZKD0LRCQDwqVuR10KwJzE78KAV4kzHNlVVxjb0X6GOQp9ingjcUaT7xgyjDoxHMkaWTYKIvPAT3esWBhqYXZ0X2MO8XlIwcLlkzR61Rz2tjgH9tm7w15RXv37tfjZKBEHosYC1HNoLhFOWNU0BuXHxyuDDAWbSRKxOTXItFICzbVMBJrngNoHlw5UJzEmqa0Qb4W07txJru6xSvce5ae5igpwmRfvqyS20XWLNwdEB1gM0Ri8VsUZkO3B4pP8PiaLT5JeF0nR9LYWvTMuDPEPfBg7T01rjtHDFHjN1qDgXUkbBSNMFYcOgh5DQP3jMdrl3ekUsyi4JEc1Gy7yWwY1zBmU0uXv2brcbAYjLPrWfMAaaOnpxWpWVzqay87J8mcLkUeV09GQppABy2xio3rbK8cxztBrhOO09I0ZNm0l1HHlbprSGI5NeyRGDqYwMIQl3xyHIcV8Z4faSTzzOW62C5G8CFYAbELx0RYrD9KX7vKsBBtJttPg5Bgw9vHdpogvWlE0Hlv3fRut4ueZXyF0U8PebZR43OQMjcAX4424B3DCnssiSVi1UKWaD8PKDO2UuF7c6Uoei5DUBzgIkvvnYpAHADjZ9hPp1jXlK31D8kvNtNXDS9qwj5iOc7u9DfzcOZUS63gXTAZAodPCQOrP6AbleVZsbqLoqgkgBQr2eyfDMaBIg011mvj9bsAx6UaxOTZw78yDKYPK7RhEnQAwhSDQZZlposATPPwI2SAhZH1wbV4meDXMXM2WJcHyEMkt8yJgX0F8iiK9dYaw82PwQhnbYDKz68KKrfaXjlSkUmMaBCtzQwMM5KRxcp2oyiR68c7a3zDwylDBJdee6O8aZDNU4AZfDIjeyIYlYtbPlTfgmsfpijWZJxtVNafhvpMF8gkYLHP6BzY6yHIjVEeRxNiH5U2CAl3R5ijLd9NDYmN69DcF7sK0VLL5x8T5EXoy6vV9KvsYfK0u9KU44Uuw9djZ6J0eE5CZJfwVqod2A9bOXBatgV0PUttzigtBMkfBjMedCz9oDMMxwkY7qIuzGtRkikEfA4v87BobSSx8uKh5CrY9dEdDlfQYFWpzvVnbtH2AF9aFCMNrJgTiO31hc3t8z3ZZvdv30pEKbXZdcIoNNTK7bq6L551FHK0hiEmKhqETONodBpMtSkFTXpoY0lblECQeDC02O5qWTHOAD5z0C3kPdTfO8oBfNi10M5a4INOUYySsbudLaOYPLC2f3XyzORvxdNZX4Bl17pWfkHGaFpnQ0jP7b0rBU41spihJcWvPikB8sQKjxsclDxsQn4NywGfuwhLLR8ofPYqkED8rsFEauR9EJlthyeFbILYgW64xfb2zX3YEqBPrIMOEXerRrmdfbiL0RghwBmquR9OUJ8MRQ9fCrdoPipRvQl5vDZouZ7n1vUfaMH4jIbHm0FnwBpEFVN6qNBVPbVoL6nxpa26yxXqaGodDhibfcuVkjfCnJonhiLwFtibS8Ks3nEF5BzqN6d85Gxfcze9fC16MxxAXcLTM05C4d22JpeZ7tBU9e7vDBpJP6Me0NlPFpttBgNI7T9f5GUtPcJ2ElwvmQ6jcEE5nEQSrr9c5NcnmM69NfyvvF0SpMPmLUfNKO204dpvDBXd9OdU72UOYY83xeD8z9CxCHVMAcEOD5O023wWcvbqmA8ENsgrpcuTK5XkAxRZ9idrFWyyMLwoqQBdjzqwKf3bGVpbdV9AJgCNZdLBP6VnE5D8Ph7ldPyTXNl0ycB26h5XFghpk49CsWNX2s3EobIIY7kuP91iAYKO0WzHafez7K9BcZf9VC4Q67QmOtqsXF90CQVTDrv9Q1mkSKI8xz434W0Zk8OtmWIC5td9l9wv1TT0432m9W8AtTcetxIzSDrh5YkiNumwJxR5oxYZvATaHrFvCFXIV21GdzSQdA8zro3DbELq6cIDaqEnMovzjJKGcJ6G0H4lNPuH4slQ187mObFPfv3wak97Xxi3sLZBTFft38LcfYYVvdGkYFDZhoJEJJAPBWst8w64Y6VdBzuHbknrtwfKtk0eqNbm8jf2vMlVcwHPYBkoMUyAdBs7y53YyEPHDiQR823dNHpt7m3L5wDkDFHhszJDQeGoFID0ZOeyG51gxmdBsJWo9Mrdc0MhCVVt5foIDESR3ELJJWRyfuB3ZRJVqyYPiDBmtfIqf60wckBXqTHg5Wg2wvykcj1sUCl1FFo7G76zWMpZfW4JCQSzZxLIOUPpfAuq9L6SAIJSsYlFcLoLS72BYnTICoIN1PqcI7vk1gSIEmf82vu515CXEqncI6SEs7gBexIsitsjIXnNqXJRzcDS0jzzyGoRIaeFFdnwQAs4b3tmCVwjYhLVKq6OD87qOOlirkVTyEtDfMXdKg016kL6K8m1qQZBjPo6oDw8idoeerFR3dQKNiHUjNyKEfrwABeqYSyVAYu43secSXVaVd4WscEYYMNlRergCTRZROEmzFcB8iO3GvmjR71l1AijEMesYMfwhnLWqheFlwm1k5P2bMNv5HO0MQAau76r5EUz0whW9ZYeoeFEyjXivzwTuIuElbQEWUSsA8pjd0l1gJ8aeD5KlQ0tlmnaqqvHM6Mr6lrw0NHX5l2KJhg1hI2mDnIFTeTtyCUbKgCnaSlOFnPjFOxg8wqnkGqpqSc2e25ydoKj4cldaIDMggVzqJoEpgu6tKIjluxRc8l3MMetjKSDmG5qUP6X93pR5PZ4U79YhAXvORq0MDTRtjw90W6CoGctlbLjNnRLQZ4YezmFuWiJxNX0KyGpi2QSFOmee8s3CYphe5UIXMIyfIGCpXC38FuDb4d4OLFyPDzti8gAhF5hnvMDMeoARWTgOHUrG3REYkKrxs9a3cOjYsHLtv2Nxo5joWuEWTlxEZjImKID0gTZ59oQamPf7hF1dOUaBsED2Q7W03gfYgPpkUpksKHZWwR29fcmN6jIB44uxaUDnGjshHnXbv3IQmoBWrJcYxF60MbLXDDDeUlXJo2TCqoo5B21mAop6wrgKeue4UWNNGUzpaVrFjwQmCoJ5I7004uWmd7k9mpXHRzVlEODakQ7EEPAx4MELUlalk3zP1CV3DgRggOjMJ3Wz8Y8sm9eST4nNQyI5nSMWS1AhZgoAOvcGMlGMLYhoH7EBXJAkKqattz3E7RMAmN1c70EZ5KIpNFtsVWiW4OzTgvVjHMleO485SOIsYeVSOyxhOfbf9lNrTZ9LAU7J0Ei3DWYFt8XTQB6clQnpJhgW5stn08orsJG3v2g04AxXHNllcjVDq0R3kJEB23idco7azOHepmHDsYaA7Yfao3CgWCPeDiBREMAOJ1d6MniVdNAfJkpXX5TQsynfu727J3EiGss4zRQQEyYnUjRA9jkTyyBSA3bo789dVAucP8pGr0IynOV7YPjREqHRtU0kNiTpgTNvbzVXEI6DOrsAIz0fwd6p5L7UT14E8EeVlKEtLn9GoCe11RgKZTXxZAe5Vgx3eLrGvqBc468X4QSkpTZgPsr5g2eVvPOn4Re7J3gAPLPHV3TOtSBHEkJk3zVqjfyWn2NfP5EGRQZEt6hJY9WyftwflE58XA8CQRk8sqcpI8uB8qzQ6bW5wF34clOeprdSAXySKkXmatrjvbkWIFIcXiEpF3XtYuG5SLRqZVQdMp0BSdHHqo40fgylvB8DhDs8AOu84Xfcrhc6nu1OvYqQ2zijImsqoyJfA1wlhoz5bXq9FwrRMMwgarUH2XomFdmQRHEndjB37WaufbKmY3yA2uHXuZWytyCigp9CkgOBSUsni5SJwYvjgbc6OF8XTdtGAcjJ8430ttvQla86IXpn8K4xQ9NzpWKjIMLWpF0Lmuj1tCh1sZw468wKKu5gW75hSjlGxP6CCPUuns8Bts0R9BnuauCJBDwYQcf83Pfl64KLU5SR2fDrOaUUOOqPTcOmBtiOkBziG0rbstxWi5UAOFVWoM3Cufm66I6KWaEwHsBiVXGWWZGe7qHdIJpGwMOGqvUIzLQQqOsGfhMhE05Ca3XJSVBT3GqMQTdhFiETzIxe0smtZCnaobke2rDsCBWqwmIEcJO9RnEgXmJ7S3uTjxbocnryBcTTZOmTXS34zNNUwkxgbQzz5bYz9YXfO2wRIknMubuZ52eoPwfpmFWIPnM1DBnjQhnZpZ4WYi1rGFDoZ42TuUsJqIkNKVa37PQtzSD1pFln5opkKMvotWjDIH5gtPc8XuKBu8C53N1pZigWdMzk1BF4FU0u9yVkBIXn5U9RJlq1I1CHq0CNEE9MtDT9kVfTLfdWbXzOXLDi7c1YNIDKscSK6eFZJtETb9Hg848exAJHPnCS0OfuTyomUQ1GprtXO4hTkG1jVfz2mxJWFQTMp8q9VzKYnxCiuSeJK1rW3SNndFphKOukEguDUMRgE0Liro6N427n4CGJ5uZvNBtA4V1Ol3MJcc8rhxeOexKHfD7JaxCdHNkMIi15rl89J2TIjTbTn3QxiB3c1F3BlDYiVEtxQcjcQsDZRvXKSwY9BObgRDczhdSoniSWmQRYuN5m5v3B7nSNGI7JWsqcDw47LLI0hjupobVOKlPVxwG5tSIqF9jis4oTh2n2rZeNJCDiw2ZB5diiRy3GdvliGCdVYDWY1u8bVjdeoqbYb3z4wwgzeLyVGzhwh6r8GGSZ3sSeyijyk45bCmQprdLjGJry8mkD6lVauLaTtc41rcMPaf90hMKMIO0EGXnC5xiNE9UPm4CYR822cFSgPyFSzWX0myaVluLg39uD6uGC5ffYX05v96EYVHX8tdJqIWJcofsYFqhbRpcB1obSE4nEIH60qFMzZqgFZF96NYqJvgcggpJAZlpuoIL6dOWBjSQ7Oq29D70Vo91OA4dfqElI67Z4cl7pKH9o5uRxNFJuhcS83reLGWP0AdEzyFdh5DvUEtTdLLG0V36ZoHxIl2aMakpATFIkzt1lhsMV4RuM35DcyLtyy95zNJgKfg8Arx36KHRDKVixlsQRh71xkgaJdDqFodE5jqYgxtAVT0ytApGzVqpu6Gqa8KdjNR6kXTPAy6cFFcN8eyPaOd2zvghJeVP0jZO1N6VQnDAZhWPZkTB06QhP5Bc0SYzdrcsZAL7MI600HPKptVmKiV9JRi0BPHBdTUVI2UvttkKu9JDodSkaa4l70zqgEU4D2UxM7RIXTWVhWFxx6WAzLbYo2jChLvaoZc5ssSNlJ3CSAQivUKA6JAJiXe9e2QRYuryTtRfadg9bBST87N4ROZ0iMPZkzlV5kX0BMn3kEu3KjzdwsAo6dRaLveIjFsp1lhDymzZiaI2e1dxUQK7pm1eZiku7dhjRghmNXhWk63HAWscxINt9X7GchhPVQGaCtm5ClgFzDSG80XIxCOPhMc1BEt4lSpx9AWYul4RZwz2MBLsDtXYzZCHnrlPpnm5ULo7PvY1sijGf5sdsQJ59Vc8m2QAaXfufhNiLP4ZkrGAsqPKu0j3z7AJ9BFhTCRXYvi3lptGUjJITTbqZ7AaOrhJqiVy0TCrBx4dT8tKYzyDmuuc2H6XdjpCc9fE7Bd5eQA6YIuBSYm9o5TZS2iQSboVcCoLD0cAunXYdDw1SRH6j9GnXlLhbrMJmJCZNEk3JKNaWS72hDhMl0X5HSSuLSTlAiBED3vBEUlzJ71ziiZRvoGqdVuohon0t3oWRPxSMU11qqmcy8zDAeHscPYf9XK9svkaet4XP1szsSsO9IXdAM5mRH49TuYgRMaaYJTn0Dqtg7PutSyVrci5epIelzpKjgapNZ9QBngBo37kFMZzG1nsrWYMirLqh43Awy19KWqFmdu1EW69FNzO5PiIJ6FTDb0OcmyKFe7UsFBNZyb5a4k2lT9TMaJQb78i9NAPymFEfTYSCOjIsizDUFOvZZq0KBdWJcpttrTTqjaGDKwSwuYfGvimhzIX3Kz5Mrdl5NY1VkbTL1AXepHph4VMv7a8w1XPVyZ9LhHqACi4rMSNic4STgQEeMcGE9MIzCCfSmhlu5tlNM2SnFOFlYJ65KV58GXRGvgtu0pCEYHZhdBAHwrrDdDzZTml8y5aoP4c10qDGHhTaknPbRGsfxg9gZ99EWvwkN8FXBvwYLl4rGnWPtfFJ5X6xginnKoUpLkiXun59S3J6ihWvLvdoutgQTPMakGmPBplmNcePCNKwOi4MaIxo3LpjW297g5M4AduVBS30978kud2NKUMOcngIKL24ZWhaIpSdjWNfzraueFPsHj2mCJZc3ogQCV10BV8KDmqAtpNs9dfRLLQF4Io63d9SmbQJ9XC0GBase4uD70AVMMZ2gHngHERDxGoRvbwlZUas0tLmEPU0JcUhped99s2H4lPOTLTGkf0UnIh1BiPOQj4JKzUJjxuqK2lvZW9kQpU6Ps31931yltiynb3U3WWt9gZaICF0ieyg6Ncv9zLtTGMcJBZLbFktakzvUwA8Qban9mz9RIJVkCveFIpscb9dqTTH1q283PqsQHSlYe5qRMO1jasSlkeRp4Vf2souYPyBeXUmFie14CVMMmqV4OYTkAXEzuVGbIg6lwlfAAxtzjWHdcspFIWk2g2xg3OojL1qX6xgeJCnXZyoeVuhwIOlxBggCb017RR3iL2SwKkAW3x6I1Ssr7lCcMTRRX2n5YCBiXwLZM5dktC6uDPyPJGDyRDS9OQDKexwyouBP7RuVlYZZovjK0wVtd2vEe38rSi2XWUecRbvrTh9M1zAuMyHAGqlJvXeXWhBNRv4J59u15kclXOFGAgvyH8A07uUTyqpEv2tEounybNPspIBu4zY50wsJaES5tHOsAzVFb5aMTn3YoBuhtq98kOebU8Sn58crq9sMxUjDxAyipMavjKkKPI7qlIqSbZt0YyOyiBnF56YDvpcism5qukvHhgAdc3Z5iuYmQV6iRGqJRubqeOTZlrKUkCcHBuBRFPqVuaY7lE99uzpTM3zj9rw35WJbBwjaj7bRpsMI3SFOM6YcaOnmloA4fVYvFYpwTjutWZDVxctWmlzMxKyFU0fnWBA9izwShHTQFn9h8iaM0QArMiUjBvD1ttR0lZROuKiu5iquCvSLtG9FLQXvDs6Gg4HoffwydHeQmZovk1HqxnV26j3oF7jBQDqNnX9CgRu7yKmodVedrRrWZndkYoRMpdtr8R4dHjwaKd91VSEhwBtoIocxhJ8dm8rJP60zeh1NM4X0l3TvJ8JkD4fimKWhlp9whQgKJKQGklQrWf4pt4ERKbHzqWV2yR6voE2P0JZBZhr1mhw3JEgt9y0qHnKYj30EndMwBhFJ2iTLTD3uMYTmGTZ5w9M7gM1mg85B9RueGYBzf4nyhUvrOTY9NK7y53rg8Os0t5uc6nOmEj3bxNQBoJIbvejF0Eds53JeXaqWOZ7ZowqDv5V5A7qGn3XylMGdgoskIpnfK78dbpomOSlubQYy4FRU2WDm6jjEFdyVxDMO0pAAwqZVLgtokdzDIYiXYmRKUXnVvfRE2OPQSXEfZ535R3bpzuH3DfvOIjesKFxRL3jxUOMnv4oXKpLtsRsxOt1ET0G3zxIA8P0xR8HIscajyWZfNb3za0JkdiADaqJqhoPJXruf8NZGtWpjoj62m6mH2zKOInBQtbrzhaj9jXlOHrqQiAwLjZOQ4brdK6A0Exws1XufJQZMj1HK9U5pE5tL9UMgv7tLbdc5Sdq0mHEDWyPZ3MQiYuGedXvwRWGoCIUes0j4QB7MLKTtYioI1EMj4CasYafFdRnq67XpPcmNWVGtDIvrMwVhAeCObBR8Cz6k7Rw4ZqdsU2usVwe8ZcxgJA63XoAjjkVLIiwhi5qR39HrwqRNNeJw1Y8GNT7cIPeISEzF2iShi8YCgZsI6dG6ShCscG62T5OhjGAeLmaIhHARXJpeN7iICvPBAupmis0o1WtCEtZEBKDcbpUMBNRWGeiEpIym1j5utCMzpPY0RkvwRMhrbeGkk5EMyW1DmIHcJafR1g13gPq6UVnOxUdPFllDIL7e1AUvFAp5tJA8417RS5blrNkL0MJ4knJCn5fUG0PkZZxul4D0Yi23MU4YFPjKqTiroZcBYyluWIBNQSwtwb6w7vO9jD4bptiJTR4k63AP5EjjOits9vNhiuG0PbWuQGUGungyShkHcCY31qAJJXZzxT4q5wlISvLdaoSPbon2n8SAdmPuf8zAP6QtN3zrtgQCnI9RJF65StPRxQPJrwubfv17lGEswlEzjdzmXxwSduE1kGeYNcpP4t8ifcaaHJcJggNfQ0ns8ZIk7jgYlfb1EQVelke0jnRMPFv5V9drVRkNG8SJNUeZkwUwPDbEr7egvBQ1DeDZEIopU5FCNUwes52J4kj3s4OqOCHTferHRueYhelrLxnHTryZBTw0ty1KQTqiuNvixfDsh7eUdyq0l1eJmF0LqoWWOf4DM6MFb7gYBNVLpMcGDzGKQ551MmpnHs9mTSTdBvjM5gxs3IOukZU9IYNKBzCpd9bM2TsnYDgiVZI4RzU2dHfmSFRF8is0lh94Vjr4C8WSmmMCZO2thhY73N2947g2EbA7gRaZ5ZCcP7tCoc42XFFofISZCqoYcgrdqc0vAdVQxzy4qRwnmqwg89TaUca4QPwK50YFtptAzIEy4eanRSuY2drMFjbwS2JM0ISONzsMe9rauSRnHv5lXc2525VV74x9e8qJmKXvb4ZxTVfeL7x9T42AYYONPUzm07V9InNLYxMTlGvXOQHPEiAxrqpuhniyMxWu7lK0qWvjIuEOeziAE4qcvPLdDYCHaLL6D1Mb3IV7UYoVM2aWxNZFv4oCJbZw3242C13daXib5xeNcPV1facdEjy5P9uHYsj0pUXyrM54ZU4l3MuDsFB9Fi3fvLo1rn34SJuVtrimquEqphri4tDwj9YKdafzGiTjOjZnOQRlK5YoTrLxduUUq2yq5TbAsZ1KDdL1LABlrcsOvk1wquae2SveXVvFaApGpjEpqTsYlOsnh9dKns7lUFpknQYmFLc1PGC8QbPnc4znoxZBxVbLDvP2iHYX1eTeJZdV8UEtXVcxANBtFZor0GcZUt8ZJPwYujH2VYBqn5m4lJOFhHn8zm8FkbRSrWBT1ZgcUhZkCzN7x8wD2kJol3dIMslO8WMmathMSPpXlOXo0gv5TVnIP1QGtMgF6HS6zC6qw1LJuZaxRKtLW1txAtzp16laC34uKO4bUxVhHxRbeVYm5HdlcKg2bjngy7euX9CoGBc6y4DkNNaOYXs9r1UIM2qOSpeCSDYjzmOlGRVuXfMf9yaEyW79cY1ALOGxfSJX9ZcyxTo7pquQAJSNheiNXXfjOa5JKdG5uwUi25e6ea83jt5EIxEABqO4qiIcn4DiNegm3Spao7BWDHphPxPOOEi5eJfgAEsSEvXCicHqcURfHLxkUGD4KgUPYzDlje0goWx0S0FSnKcDZ4X82Y63xzXvkFiFFNhbkx9hrhsNWH4zuhqlNTbgrNlbp2o62PADxp8dEEJ0deh5Nf27BCvpQZzuyqqHDnel4HIKHK0bs7zBitwHjBSq7j8bU5YdQdhyGhfaMfdxslAdceb2sWmf3jowh6Hjmbkam7xZJcOzyczrR45VdCML8fZO4j5STtnuREfwrfV21jxRrGJzOKePjLksn7UQPAjJ6JwQC0WqSL5eYdnI0A4SO6CKTExze2X5804qVvU5HikVOFV2YvF6JqRrOm75gh35akFcfK9t2IpIHKqsTfCbF0ZEpji4f2xelrjOYc6xIQGnVVNLympBc3tur2AyVowc6sJMrRU9Wo8m4gxkQXE5zl4PVB6hmLLAl58nZI5BhdJG2Ceo7QMzY57O0zI8gPq9B9o6W42mHfFzJmkzFKeT7lmwd3bhdMi0kj420YXX5ilrB2syoaocEbvLZYTwzn6PJFUbNlMZROnLIB3a42cqfKLSVeCqK9iDS3oFXTZu1qyxWvmxsYrnqFDO0Gxk54oF08PKiDcP63NnI4FAR7VT2eMlfUNDUYRVKYJ5sg5Zi7DxShaw6veNHS8MJGIfym04ZZJ0QkV01uFC1j41Ty1nwInAkuUdtEzUqzlblUtXO2cCTEGYVK0bHLs5Teu0ek7oQmJVzEU56hDZPDWA4DLWWilk294eBSjDmaQwNHyDUKFyJnEvbpaCquTEe1XSuJV2fTrq5v9Xptr5RJ90iRj0x9XqzNpPpfJqymiuf4zSXsO1lUyWKzq6gazeIIG0PVWPm1pcuv168J20HjXlvV8q2gk94DT5PUVu4yN2GcEUry945EZepmZxDwmpigcgHtWEgr0ZWePxS2cjtWvelXD2EbwfpNAO36dHmc9hSRdbznFjVgRxiU7RUdGaa5qpOKLNtImQWZa2tbEdZpDynYhqn1J0QbpRFd1pBdViQFwYqACg7cWGVbpHbhg3IcqWY92PDTxtqNJ3t8lUrlFctFbKMdfB1p6govoBKohsukYhUYXuoZgdGQV7MtF2oQjJOWZ3EN7E86UGv8ZhofCfqvF0azoGgWDR2awjEo7BoG46BEMScW8mfgNoxWaHRbE1r4EfcaoZrn05cOFPSPOTgz7jxgofcdOERFYrxEmgL9WtEuLEN1SR7SD0BMJIDjr7nimFCjRxFB2I4um3HI9lp73tM12PLDFfByKXwq6O96cyjJeBOTaQ67ZqgztUOBlwmyNdSd0JstUABRL9Qr5AbNkgErofPjZaICUvkF3Z4vJw2KJWXqBbA1a5g4mB2DRZL5HjQQTs8VZChyB6d4aqKxfxOh4lEXSFnWcbneLyhCdLk3nYcKEAYxcIaJr97d2cAq2BZxzhNEsk7g3lsoTQ5kkwx3XAASNwK6Cce410VikrnXsRpLxJY6ZUHAsNiUbWrQ2S5fedojU5y2Dcna0LCYpVd2btojsof7pDMYH84fCDzFiIe9kxw85iPGd5RJqspSweQJUE11MoSAjlwL98p03V69IBpIExzWHMxkTdiXezYI3atAdyehJMsrmvGBuIAUm93SZBctEI9NoliuzAgegXmTaAR0aYs2OwXoSX5mUpAT2ntktHi1V6oTPNQZb3QV2ATePx9LFX2Acwn9KjE30fk1r7rY3gyUKwJT7tK64n2ynGCTphZgXiawdZdlocjw1bOKfYDPQ6rC5u3pyynTXkwFcrU9HveCF1xJ6CKwr5GqgGKOtUD0qj7WONbGxmBhdIOh5doEvaemJEDXdcRafhjvaCYyNWzjyBFT18Dw8yiEYSsNzdKGKTXceIktCWXb6ATvbrAEnuPQmY9rcXWOFJUKmrxJig922r2JaUB0jufUMTeJ89nM1HyAmLETFslyKCGfsUQqxQLgLkNmNgshZybSGjIRH5dbwAIfCRPPA1BhunQlIWCmLAhu6W2P2Bjc72EgqBu4IhyLsOfTaK8TlxilhvPVDkIxoLXysuTDpgUO4pehRb9dSWKPrqc78Mtl1H5rl9Wi9wojlYr9NULc4jBqNimdd12V3fP78SlyhVWayKZewpyFi6ZcGcZnntcc7kdQFRMV2T1I3sMKghZ8mgkga8VQP4NNNIc3M7JZ1Yxxh1Nr3HhYgL0e0zRc1JIu8KnOoacmUcZbUbA78tJGzzXxzALbl9hqEf5xJWlTRdMO0W0EtUBBDy6adRJqzuFozdlCTOn8QcTHCQxDrXW07nHaKB8vWe4iBrGbzgmwN4XeVEfWT6gVmffvjzwafiM1MChlk2xcG5HU5leVpGMx6XgchQIT05HHganqgLLzSWKTu6A642S435JrmQbOiTLCc2FghTco3P0Z3FqUHQtGLkIMQymtzM0xHvQZ8Cn1OLMheozhmriHtDR3gZBUfSyZu1jbTsJZ2Z2n3XCaL4E1dmKgrj6C5LNuhnAfK0cF3iJrj02SPCm9GvBkSJEtFctmkwO3tf8eyGQXdCzyFDvbJ6yb1vkh4ngLVUVWw0tnldNlnEHBTiifrbpkoIVC48K0RckHYRjse7XfX88LFAKXrdkAaZk4pENMp7HJqnigtVkhKMs5k9kzKMN6cNn8S3BVCCbXfRKIQHo6okRJNKdacPKb7NUwHLFrT6NDuBzTbbkUV8cPZYSEd8Pj7zeoh9bz8zmWp5JuL8dlmBvZwBpvcTSVavwQbZ4vz1zA0LXcxIo6iB9gy0rDcP5OXuvsPBNim7b3Ulf98VsWpoTwaK2c947dGwp9vwAFWKvKRQAkKr2Jt19pbLpmtkez0B3B1KuSgnI7v34GlnFohuvxV44aqz5aSxSKqvaoH5DnDEUMfCmhhU7y4Gq414nvgVlUtsM0LehzProJ5XG2qj4P05KMhJY1x4KLg1A7m277J2OpmGYw8LlyfexCaohv5VBaL4woOUTfgDYttK1RJmHQzMjc0C7yTCRFb96E7cAi53KQtEHIQ8fm59uBIRyunexa0TZjt06eX6VtsklOSAvTAOHTR52OQIUlAVmMLqUxFeNpKNbCxItaVwd2LH5LJ4nSYAjC91cxqIqOFeHbPZX5AcISm9f4q3ZZ7acYOmbwpJyhqreZpdCL5wwBwTwe4w9pVgflTsBAd4IAOngjFyxEyEYJQw6flj1UKZRt2dCAVLQhgvpdAnGmQ0V7BKeuztD0XjaRR2F0WT8ymXYPyAeXmt6TX7HCZBSREoqWF4Fi4LAXKK4jFDJHRZxHInhowhCLaSQvH1jwSNGd8x24I6RHjGpU9t3TvOG74f2FgkSWIPxS84HwHGqJQRQFsND2mJelnyhPUQXJePdlw8ggpdTzS6lknBgyXuvL0alHNtr317Ntd8w7xbetXvE2RuYRJ8PbAvW6kUKOZUwI3es0dZQuBECb5Si0jmFPqKgLyam0PIcNVt32tlJYB0krX5I6oPOVvM3v7aSraEKukODhzsrKlMVZrSe5cd9kMiflpknXPIVdaKFwa2ZF49gxWn44VxvufAAJUCSbZotkkfXL1FtGTJWuGQOQ42DtzCiyeuHPfVm78oGKKdCo8xUjE68iaI8XBGAFzxFZlFifmOemLmAPIUDFJfcpZA7iM5mXCl1pZ0fYa1apm13OxI4BM1k8HirBIP3vIE21xSmJGi1oCw7RJZQpcsSqbZhgToBjNHw2VZWt22QaCaNOOeiUO1Cn8jMhz5myRRP0x4fjBokzExF9aPyeSLc26IqguS1DY1WVNq2YeokbbPMRLYL3sRlos4kVld0nMES1I9qCOq3jX9pcuJvvqxLeBKytIbsFvWqIWrLclpoXkX0kwcpSSN9jzLPsOuqGaZJ13M2FpKghll0gGTFv2d3J54Z0FKuaV8YYaiboU2mnKD0lmZsyoQwP5TjvhgwS5yyb5EroVghVazmN4bV7Vx2QXF8X5iyN1yXQyWo3Z2cbfYGlXPl7JNZTB6zZnk22RHFVPohwB1WQV9UO1w5Ba6NDF99dS2GYIL35GjqwQMJWZSI9zAmlAOHQFLltJ1QFFV1AzVtag5IXcBZh8WPi0zARWkaza0tGc4E4DRcxPNHJKe8hodNwpzepIkHhF4o2n0mrW37TNhLGzVLQiRXz5jxJUPLt6RzcjJczaFiBT30r8DH2AR8Zb0ykHX5AkibRxmOuf65UiGzg5tPC5gzvl9YR7sCoBsvehZ75W39Ft3rJYu9XBTbvRmBWbAG9C319LE4sSXIJMWdiIiqRB7pHMtqOsBxvaxqhG76c7ZHVPQWjSPUSsKPT9u0igpMImQwTlucg2SK1AUvyAb1BWayRyI74L6fBRGJnODjzFNFGTw9i09H26EqGhk8Mwl5asCfOkq2BUMJBm3THPyTyWPgon5TjShJTnRKY23kOUzQlqI6R6pfO60W4kh1NhCvIE722cjCe1FHFHFRGRAC0p4dD0qavTHetkPdw6m8jahBjM51umzUvuVG6gKXOn2EsqSnAVgo3SNOy85q6xgvc6Agufzc1cUMae3EnskPYtiur5KjOJteqJAK5bu7a7MHNa6IFt3tpr7rFGhYs9ZryzdJ82wOgqXGdetzBNt5Q8lJ3V6oCxft5tls5gFD7Phsvb2FNBfwvTwU4cf1gbJg4OBI0sLyjnt4AWGi7Li2cags0HTGiXd23RbiCrgbGV05aRxsmZ9yrspDywJzNypZjqzPUR2GJ6CBsYTSk24epESlNneSTzz8ZNj62bQbYgK9I2HMYLWTERp9ORncQcWrJFZXXHk39nJhetbtQkemISUigVO4r1e5atX7d7ymPCOiL9JKB48aXsyWbEvh1TzVGtFwnWDBF7b0T445GCLA9frQqyhqkPIPvhdtdazYTJiMnyep5WsdvNDHcZcARRj6ueDuKMh2cZg2glnZvI1EvXKxtfkwQDuNWhxWhwDfFFfHIBuRlNPwbazdcnN0ab481UXYWqb8U4DTLlXXeEbgZ83dle04xKEBLKwv7Vx4XkALEmcXPPxm9DVvLz0909PEw62sRiPJYSverLPHRrIvIZtvSdkbcQjfZUB0dLMvdYD9qpN1x01fITztzKottDn1LsM2TsjkkN9v3bhxXw1D4i1tZObpdthzghM9mQO2OK3jynSC0jkpvCK1CVoKU3czIGb2lbnVo3IIFPujLFLSAPJVtCXs6FeiFN6q4PiRsnB5lcEgME318wl3JODIcfbfI7sSgV7GgogHaL9mGPMzxZehFm3TMnu8gTWlnK7At84GisJ9cPXSoQKB00NCkE90nNNWeQIAdKm3zzYsxF1m1ov4mAW5QDOr9FhrqnvJ9XmY1zgZ2pACM6buwefUpKdBxCUV0aMD0aPcrKFJ2DbjUGbOGIyTfx1bBTPmqPnZGDqz122IaSNWZK6awMu2uzMPOyD9XGsVwgWiFiIaWPSSedM3qLqCsGg8veLeZDlXTJj0DZfBVMljpCF5Efn8b8SCcz2iiOwCcGtITl0pCJ51gT9ptbLdSvEjEgS4elbkAV6Y4o6mk7K9hKEcpUpM2N7hG2gplYpEQtJ0YZeIULN7tgJw9YkA36BiVlO2M3Bi1Si9Uyc9w1dUWDkvYCErs07VuPRwHCDklpvELO03HA5UtR7HDG2SyRk6EJOkotNC1rFaEvQgertCKJ3gyKK4lvbS04ZlzKgKkAruaFd1WcgWF2UuAozGWAStIWM4Mi3wBMiMtBV6UnHHDEQ9dy0EtSzvvIzHqvEyIozEO088CfE8MTs2P66H5yVB6oGYHBMJ07ktnoTzvRaOc7a2ezantsKDh7Bg77GpdFDsujgyllltRfah14IHYeooJiWbaSHZfLTeK4fH8QEvBCjkYwrKyHi9QZdh6OjVi8dJB3pLQKiX2W9MtvHbCG6ASy0tDVE6D8Qia0sD7sAgc3SZ7fJHAv08IgtFk7SY8OFGSwWR2TpMIq5IdagqaOCEHq8GRfS0smoM06iN5TZXuKCdv3mi8jyKr9d9kAw9HKsoVsct5BzK8htGLlEYqppqkpyNResxxqy8dogD5T8WnZpXgl9SpjQuSuMHqz5xbK6LJ16TtPY2AwEkqiye5HFKuJ06KUzMl694BdPRsGH2XbMb9cN5kLe1n7krHrYeKRiu7eIf9nwFvtL60pDnKYXGNoztB0PVo9PAprw53u1DkcGH5rvrJLMR0U51YFyv8TPrN5VmlOGOfcr4Z17uAmwXsHtWWKxOFmr8mYeUS6d3iKYrW0ABHRWxobqdZjhdN8PjQci6fWOW86karZDCK8TZxgDzqwyLj8GEZWrmmJ11oKdDPiIttqZetnoPhqgSOjpEvinPELKTWgRo0HaN4Sk6CskncSpHDTen6rKNS9kZCox5HyCLlSAjjy4CWLeF7gsg1gemkCWCr6PPXfbulcCkOgACQOjqLzILQTWxl59XqQ7QPSv5OnbJQslTSgWVzjUdJK1W5RkNnMq1kcsq4XOBEDGCHPiEmwzcO7JYHPjxZaK1zPCbdi3gsgSHpqxzr1EjR3rRrSAL82Z6p6Kd93aS1THCORpqz2YLnMurLFl2fovUeO6PhrhjKULM5ARmZjJfe01KWyRE0xLvvLmIzSmRoELQsetRH6Xcb18vAzGOeJ9IPcDAFoGb4SDDUjDSQj2hnhreybOMQoDmY5QwPscll6NCAo4Xvo5JZ0mum62f05OJXCwUfBkcC0DuZhuW1gMBUhQdGVfjWNOhOBtHqJymZvEmA0zsf6TgywDPYt55VyMHv8uTgCSXvGDqZE0BSDpVSlnTdenDdi6yvLOddVMwPGvAxM3GS9DfkOVddfGkm7mqdxvyRADr9h0lEGqFYKU0LyVolsPJEgmMrD47YV1FwJFRqIsqRL3jjMT2499ZpaCjY2wdHhqawJJ6ntlLWSSWZMUWDVqrPrdHToevWwrFb2Y6Hh3D80qeBnAKiHE48TAxf1KiQjyEYaReNrUUp8QtWV3YIAqPHTHR9tcDa9vrKPxmNjJ7wUq4haUSmuDykmNh6bRfJ3xkdBnCFDmfENYmxnFSznULzohMSuvkC4yl9ATLaahEsf7W8ZC0M5kDr7U4qHSDj1EEgUzmzFNmFJVvfWLYGsfohfakC3wKdkS7NSjkYYALRTGe047sKKCIPBjGOgMiiTgUjlqs0t21XeqIVOpuO0OCs8fWoWb1mZQ5w2kr9ZFc6pXkyUU3Taxi8kF2uvGg0uTvE750N88AzylpQS6I4lcp1lRKE4ntBa95xc2w4ZA7NeuMf7ilvkckewDILSvWd14lKFqcni5NgleG2qFN3ZJiJkEXUwBw71Z4SVqaMZ9qxPdQoPFyo4oQ7WazDoaVtQOWF1i4r5U8I3XDAMC5c4ilxZJ16imFEFD3ZKtzMcqcPcwJNJmgraxueWqFAozNCSOe3Mq7fl4UY5CZrlne1hiABhNZRydMIjOpfD1TlDAVTo6SHpoF1VSqeL6u88gRnUhRShZAOiARNNtvXbkPDOpz6iKOGNfx3ONG98Jw92LPaWb21574MT4CfqVyXvXm6OnE8AwOZBRjhv7iREu2vd06RXDnozurXCHH8UY4PaArZmXxwHkDxSZG2gndxiXucD3pCallCWjlwis6E8y7pm0KX2LOuuu2bzmkZreK0RWDbjXyNFOujJavW73QiewPE6SEkEhEEd7pYUpQ1M6m8ZvjtpvBGuICbZB2SHUakc9pRUWLEyYZbIo9MtxX8uLFGa6Ws7xNQDWZzl5mVK5tFpsNXGdGHmsHPyzBaS1eH3inrF9SpWNhn9MmPIxYgQTePuMzxYbFSi9fZzupQqg3pg35xngRuEiXcCGAAPeLzc0dUgBqvDdQU4JTZo3IYlq7Ku9hrjwQvEcp9Avv3G8H8d2f8TxIl2UZ5qlU5GiXWBaXfWDJw1l4lJp0VYPzPKlgzpH2ymLM5ho4PbTYVIzeJCDHwmWaZ9IndHvy0RNo8uVeiVfZj9KyehznkKhhUplXrWHmmvxpgScwshAmSR6INiY3meNXvRR5307m9re08wFVOT1qAtseYYQeemBqtz3oZxT6J1HxctKZ1VjHx90k2MjxCnHtyOhmKFcm2ikDMFC7cjLwHzeEqsul2pTKxPHVqz98YDB5fYhKW1DGp7WI4LHxCFCdpKgeCb62OAewEhzuVdwOVkrqpo4ztHOWJqgtZ91c1xzHhFwDs0BxrlUomZ5OP5WXmTVZiKyilTzZlSM5ZYOwLqCqkAnHCowegTHx4yxroF3fTeMIQyY4i0jhkKHboauX8nmxVfj0tP143ZCA13oK6DOaFSQaHAiUKuWKuPAng0QZsumL8TCrWJcDqK4rOVIXudjohESXTo00yqlwm1BHr5Dz10QkBPRKOkvEcYGcdsiGslVsFWG5SnRqV3DOQY0SEjUrhzusSLnXpxLRIUJbyUg6dINoRsv314IilYlCb7SWIddKgNLGr2C8EFNviIIOZlzwiMPI8je5rplPhWbqOrOydhyUwp3TxgwIXsyJAzP3TLGVyeEW5YqfEhs755yPSgphvTNzqzGwGAogSFQrcuLl0RWyHq68EtAl3eoa4yJNKX7LOOlIHzNIeDrgMSVvOeGUYhtCjBBABO5EvHVtljk8mcSv22U3RU83YZE3OltwXtkrEelQmLXdd3NHQZ7863qWSeZtoyLqJnr8SNjkiLInteOfcrO2eqtnEcViS0uNBKJJLIfaFSXlvG33TBK3kryNo6fRL4lWFjiyUD6LtAWXHy7qC51tRIealSGiadp0RNEhCvrkfpGKYekGcZbyn5mTBNVqHKsqnOXM9dxHlud6Ly4zsksG16OzrhB7NJHuc4nRkAhGyWLfsha6omKYklWBgu1rJOffadvoxuR2FvHqW6th7qON13ZUCoOpBCEbRqvR09biRbxPwpEqpE9RTrctT7ihcaF311VrgSG1hLj3DBPqaodJ6qAfM03qmozpaiYCOHJTzZU5k7RGbfEsReiRZUinS0qmU90Jgfh5etU3pFjz0UcG5V62SEtQEPpgKuqEmFbAy0fHBjlCwt74bKNnjmAnasd8WV2uM5lNZdqDDQYJKMUM83cVY1MGBFYooRuzXEAWuolj2NZb8Kky2hDtnitt91Hlm0Q9sgf7sJkHNs1OIt4QMR9casnkIXXA4IiUnQYbzLHtBGIRDSQKLNay2sBTftNqdKpJ2akuEWD7BVLm3HyAgiRqPH3srBnYdQKvCre65ukj3l3EIecuy2pm5cznUWPfUERwhwARCTUVcQ69GIHehTixL40zoDf4OP3mdHJrm😃 +#!# +~~END~~ + +drop table VARCHAR_dt; + +create table VARCHAR_dt (a varchar(max), b int, c int, d int, e int ,f int, g int, h int, i int); +insert into VARCHAR_dt (a,b,c,d,e,f,g,h,i) values (NULL,1,2,3,4,5,6,7,8); +~~ROW COUNT: 1~~ + +select * from VARCHAR_dt; +~~START~~ +str#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int +#!#1#!#2#!#3#!#4#!#5#!#6#!#7#!#8 +~~END~~ + +drop table VARCHAR_dt; + +create table VARCHAR_dt (a varchar(10), b int, c int, d int, e int ,f int, g int, h int, i int); +insert into VARCHAR_dt (a,b,c,d,e,f,g,h,i) values (NULL,1,2,3,4,5,6,7,8); +~~ROW COUNT: 1~~ + +select * from VARCHAR_dt; +~~START~~ +str#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int +#!#1#!#2#!#3#!#4#!#5#!#6#!#7#!#8 +~~END~~ + +drop table VARCHAR_dt; diff --git a/contrib/test/python/expected/pyodbc/TestXML.out b/contrib/test/python/expected/pyodbc/TestXML.out new file mode 100644 index 00000000000..078c025055a --- /dev/null +++ b/contrib/test/python/expected/pyodbc/TestXML.out @@ -0,0 +1,28 @@ +CREATE TABLE XML_dt (a XML) +#prepst#!# INSERT INTO XML_dt values(@a) #!#XML|-|a|-| +#prepst#!# INSERT INTO XML_dt values(@a) #!#XML|-|a|-|Contact Name 2YYY-YYY-YYYY +#prepst#!#exec#!#XML|-|a|-| +SELECT * FROM XML_dt; +~~START~~ +str +~~END~~ + +INSERT INTO XML_dt values('Contact Name 2YYY-YYY-YYYY') +~~ROW COUNT: 1~~ + +INSERT INTO XML_dt values(NULL) +~~ROW COUNT: 1~~ + +#INSERT INTO XML_dt values('') +INSERT INTO XML_dt values(Contact Name 2YYY-YYY-YYYY) +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]syntax error near '<' at line 1 and character position 26 (33557097) (SQLExecDirectW))~~ + +SELECT * FROM XML_dt; +~~START~~ +str +Contact Name 2YYY-YYY-YYYY + +~~END~~ + +DROP TABLE XML_dt; diff --git a/contrib/test/python/expected/pyodbc/pg_stat_activity.out b/contrib/test/python/expected/pyodbc/pg_stat_activity.out new file mode 100644 index 00000000000..1d397f73178 --- /dev/null +++ b/contrib/test/python/expected/pyodbc/pg_stat_activity.out @@ -0,0 +1,65 @@ +SELECT sys.babelfish_set_role(session_user); +~~START~~ +int +1 +~~END~~ + + +# Babel-1294 Support application_name in pg_stat_activity +select count(*) from pg_stat_activity where pid = pg_backend_pid() and lower(application_name) like 'python%'; +~~START~~ +int +1 +~~END~~ + + +# BABEL-1326: Support query in pg_stat_activity +select query from pg_stat_activity where pid = pg_backend_pid(); +~~START~~ +str +select query from pg_stat_activity where pid = pg_backend_pid(); +~~END~~ + + +# BABEL-1326: Checking if the right query is returned for Prepexec with batch too +prepst#!#select query from pg_stat_activity where pid = pg_backend_pid();select ? as a#!#int|-|a|-|1 +~~START~~ +str +select query from pg_stat_activity where pid = pg_backend_pid();select @P1 as a +~~END~~ + +~~START~~ +int +1 +~~END~~ + +prepst#!#exec#!#int|-|a|-|1 +~~START~~ +str +select query from pg_stat_activity where pid = pg_backend_pid();select @P1 as a +~~END~~ + +~~START~~ +int +1 +~~END~~ + + +# BABEL-1326: Checking if the right query is returned from a procedure and a nested procedure as well +Create procedure proc_pg_stat_activity as begin select query from pg_stat_activity where pid = pg_backend_pid(); end; +exec proc_pg_stat_activity; +~~START~~ +str +exec proc_pg_stat_activity; +~~END~~ + +Create procedure proc1_pg_stat_activity as begin exec proc_pg_stat_activity end; +exec proc1_pg_stat_activity; +~~START~~ +str +exec proc1_pg_stat_activity; +~~END~~ + + +drop procedure proc_pg_stat_activity; +drop procedure proc1_pg_stat_activity; diff --git a/contrib/test/python/file_handler.py b/contrib/test/python/file_handler.py new file mode 100644 index 00000000000..01b2edfcf1d --- /dev/null +++ b/contrib/test/python/file_handler.py @@ -0,0 +1,146 @@ +from pathlib import Path +from utils.config import config_dict as cfg +import logging +from datetime import datetime +from batch_run import batch_run +from utils.db_client import Db_Client_pymssql, Db_Client_pyodbc +import subprocess +import sys + +#compare the generated and expected output files using diff command +def compare_outfiles(outfile, expected_file, logfname, filename, logger): + try: + diff_file = Path.cwd().joinpath("logs", logfname, filename, filename + ".diff") + f_handle = open(diff_file, "wb") + + if "sql_expected" in expected_file.as_uri(): + if sys.platform.startswith("win"): + proc = subprocess.run(args = ["fc", expected_file, outfile], stdout = f_handle, stderr = f_handle) + else: + proc = subprocess.run(args = ["diff", "-a", "-u", "-I", "~~ERROR", expected_file, outfile], stdout = f_handle, stderr = f_handle) + else: + if sys.platform.startswith("win"): + proc = subprocess.run(args = ["fc", expected_file, outfile], stdout = f_handle, stderr = f_handle) + else: + proc = subprocess.run(args = ["diff", "-a", "-u", expected_file, outfile], stdout = f_handle, stderr = f_handle) + + rcode = proc.returncode + f_handle.close() + + if rcode == 0: + return True + elif rcode == 1: + if cfg["printLogsToConsole"] == "true": + with open(diff_file,"r") as f: + print(f.read()) + return False + elif rcode == 2: + if cfg["printLogsToConsole"] == "true": + with open(diff_file,"r") as f: + print(f.read()) + logger.error("There was some trouble when the diff command was executed!") + return False + else: + logger.error("Unknown exit code encountered while running diff!") + return False + + except Exception as e: + logger.error(str(e)) + + return False + +#main function to setup and tear down logger as well as connections for each testcase +def file_handler(file,logfname): + + #initialize variables + passed = 0 + failed = 1 + + #get the filname from absolute path and make a directory for the file logs + filename = file.name + filename = filename.split(".")[0] + logname = datetime.now().strftime(filename + '_%H_%M_%d_%m_%Y.log') + try: + path = Path.cwd().joinpath("logs", logfname, filename) + Path.mkdir(path, parents = True, exist_ok = True) + except: + pass + + #settup logger for the specific file + f_path = path.joinpath(logname) + fh = logging.FileHandler(filename = f_path, mode = "w") + formatter = logging.Formatter('%(asctime)s-%(levelname)s-%(message)s') + fh.setFormatter(formatter) + logger = logging.getLogger(filename) + logger.addHandler(fh) + logger.setLevel(logging.DEBUG) + + #add console logger in printLogsToConsole set + if cfg["runInParallel"] == "false" and cfg["printLogsToConsole"] == "true": + sh = logging.StreamHandler() + sh.setFormatter(formatter) + logger.addHandler(sh) + logger.setLevel(logging.DEBUG) + + bbl_cnxn = None + + #setup the connections to database + if cfg["driver"].lower() == "pyodbc": + bbl_cnxn = Db_Client_pyodbc(cfg["provider"], cfg["fileGenerator_URL"], cfg["fileGenerator_port"], cfg["fileGenerator_databaseName"], cfg["fileGenerator_user"], cfg["fileGenerator_password"], logger) + + elif cfg["driver"].lower() == "pymssql": + bbl_cnxn = Db_Client_pymssql(cfg["fileGenerator_URL"], cfg["fileGenerator_port"], cfg["fileGenerator_databaseName"], cfg["fileGenerator_user"], cfg["fileGenerator_password"], logger) + + #checking wether the connection was succesful or not by getting a cursor object + try: + curs2 = bbl_cnxn.get_cursor() + curs2.close() + except Exception as e: + logger.error(str(e)) + + return (passed, failed) + + #initialise a file_handler + outfile = Path.cwd().joinpath("output",cfg["driver"], filename + ".out") + + try: + file_handler = open(outfile, "w") + passed,failed = batch_run(bbl_cnxn, file_handler, file, logger) + file_handler.close() + if bbl_cnxn: + bbl_cnxn.close() + except Exception as e: + logger.error(str(e)) + + bbl_expected_file = Path.cwd().joinpath("expected", cfg["driver"],filename + ".out") + sql_expected_file = Path.cwd().joinpath("sql_expected", cfg["driver"],filename + ".out") + + #to check for expected file in both sql and babel expected folders + if bbl_expected_file.exists(): + result = compare_outfiles(outfile, bbl_expected_file, logfname, filename, logger) + elif sql_expected_file.exists(): + result = compare_outfiles(outfile, sql_expected_file, logfname, filename, logger) + #if expected file doesnt exist return failed + else: + logger.error("No expected file found with the associated testfile") + result = False + + #based on result set passed and failed test values + if result: + passed = 1 + failed = 0 + else: + passed = 0 + failed = 1 + + + + + #remove log handlers and close file/stream handlers + logger.removeHandler(fh) + fh.close() + if cfg["runInParallel"] == "false" and cfg["printLogsToConsole"] == "true": + logger.removeHandler(sh) + sh.close() + + return (passed, failed) diff --git a/contrib/test/python/input/BABEL-1056.txt b/contrib/test/python/input/BABEL-1056.txt new file mode 100644 index 00000000000..8fe58656633 --- /dev/null +++ b/contrib/test/python/input/BABEL-1056.txt @@ -0,0 +1,14 @@ +CREATE SCHEMA [Babelfish_1056]; + +CREATE TABLE [Babelfish_1056].[employees] (person_id int IDENTITY PRIMARY KEY, firstname nvarchar(20), lastname nvarchar(30), salary money) +CREATE PROCEDURE p_employee_insert @fname nvarchar(20), @lname nvarchar(30), @sal money AS BEGIN DECLARE @next_pers_id INT; SELECT @next_pers_id = MAX(person_id) FROM [Babelfish_1056].[employees]; IF (@next_pers_id IS NULL) SET @next_pers_id = 0 INSERT INTO [Babelfish_1056].[employees] (person_id, firstname, lastname, salary) VALUES (@next_pers_id+1, @fname, @lname, @sal); END + +SET IDENTITY_INSERT [Babelfish_1056].[employees] ON EXEC p_employee_insert @fname='First', @lname='Employee', @sal=123.1231; SET IDENTITY_INSERT [Babelfish_1056].[employees] OFF +SET IDENTITY_INSERT [Babelfish_1056].[employees] ON EXEC p_employee_insert @fname='Second', @lname='Employee', @sal=123.1232; SET IDENTITY_INSERT [Babelfish_1056].[employees] OFF +SET IDENTITY_INSERT [Babelfish_1056].[employees] ON EXEC p_employee_insert @fname='Third', @lname='Employee', @sal=123.1233; SET IDENTITY_INSERT [Babelfish_1056].[employees] OFF + +SELECT * FROM [Babelfish_1056].[employees] + +DROP PROCEDURE p_employee_insert +DROP TABLE [Babelfish_1056].[employees] +DROP SCHEMA [Babelfish_1056]; diff --git a/contrib/test/python/input/BABEL-1270.txt b/contrib/test/python/input/BABEL-1270.txt new file mode 100644 index 00000000000..621166ed248 --- /dev/null +++ b/contrib/test/python/input/BABEL-1270.txt @@ -0,0 +1,12 @@ +CREATE TABLE test_cursors_fetch_next(a INT, b SMALLINT, c BIGINT, d TINYINT, e BIT); +INSERT INTO test_cursors_fetch_next values(0, 0, 0, 0, 0) +INSERT INTO test_cursors_fetch_next values(NULL, NULL, NULL, NULL, NULL) +INSERT INTO test_cursors_fetch_next values(1, 2, 3, 4, 1) +INSERT INTO test_cursors_fetch_next values(211234, 9780, 891372401, 56, 1) +cursor#!#open#!#SELECT * FROM test_cursors_fetch_next#!#TYPE_SCROLL_INSENSITIVE#!#CONCUR_READ_ONLY#!#CLOSE_CURSORS_AT_COMMIT +cursor#!#fetch#!#afterlast +cursor#!#fetch#!#prev +cursor#!#fetch#!#beforefirst +cursor#!#fetch#!#next +cursor#!#close +DROP TABLE test_cursors_fetch_next diff --git a/contrib/test/python/input/TestSimpleErrorsWithImplicitTran.txt b/contrib/test/python/input/TestSimpleErrorsWithImplicitTran.txt new file mode 100644 index 00000000000..c64cd513104 --- /dev/null +++ b/contrib/test/python/input/TestSimpleErrorsWithImplicitTran.txt @@ -0,0 +1,11 @@ +#Setup +CREATE TABLE simpleErrorTable (a varchar(15) UNIQUE, b nvarchar(25), c int PRIMARY KEY, d char(15) DEFAULT 'Whoops!', e nchar(25), f datetime, g numeric(4,1) CHECK (g >= 103.5)) +SET IMPLICIT_TRANSACTIONS ON + +#Run error handling tests +include#!#input/errorHandling/TestSimpleErrors.sql + +#Cleanup +IF @@trancount > 0 ROLLBACK +SET IMPLICIT_TRANSACTIONS OFF +DROP TABLE simpleerrortable diff --git a/contrib/test/python/input/authentication/TestAuth.txt b/contrib/test/python/input/authentication/TestAuth.txt new file mode 100644 index 00000000000..09079cd8a12 --- /dev/null +++ b/contrib/test/python/input/authentication/TestAuth.txt @@ -0,0 +1,13 @@ +#database name, username and password should not exceed 128 characters +py_auth#!#database|-|11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +py_auth#!#database|-|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112 +py_auth#!#user|-|11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +py_auth#!#user|-|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112 +#not sure why any password is accepted during authentication through cloud desktop +#This test should throw error but from cloud desktop a connection is successfully established +#py_auth#!#password|-|11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +py_auth#!#password|-|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112 +py_auth#!#others|-|packetSize=0 +py_auth#!#others|-|packetSize=-1 +py_auth#!#others|-|packetSize=4096 +py_auth#!#database|-|test1 SELECT 1 \ No newline at end of file diff --git a/contrib/test/python/input/cursors/BABEL-1390.txt b/contrib/test/python/input/cursors/BABEL-1390.txt new file mode 100644 index 00000000000..3cb7ce5f761 --- /dev/null +++ b/contrib/test/python/input/cursors/BABEL-1390.txt @@ -0,0 +1,15 @@ +# Setup a table with some data +CREATE TABLE updatable_cursor_table(a INT, b SMALLINT, c BIGINT, d TINYINT, e BIT); +INSERT INTO updatable_cursor_table values(0, 0, 0, 0, 0) +INSERT INTO updatable_cursor_table values(NULL, NULL, NULL, NULL, NULL) +INSERT INTO updatable_cursor_table values(1, 2, 3, 4, 1) +INSERT INTO updatable_cursor_table values(211234, 9780, 891372401, 56, 1) + +# Try opening an updatable cursor using JDBC API +cursor#!#open#!#SELECT * FROM updatable_cursor_table#!#CONCUR_UPDATABLE#!#CLOSE_CURSORS_AT_COMMIT + +# Try opening an updatable (i.e. dynamic) cursor using SQL Batch +DECLARE updatable_cursor CURSOR DYNAMIC FOR SELECT a FROM updatable_cursor_table; OPEN updatable_cursor; CLOSE updatable_cursor; DEALLOCATE updatable_cursor; + +# Drop table +DROP TABLE updatable_cursor_table diff --git a/contrib/test/python/input/cursors/TestCursorFetchNext.txt b/contrib/test/python/input/cursors/TestCursorFetchNext.txt new file mode 100644 index 00000000000..1b147cbdc84 --- /dev/null +++ b/contrib/test/python/input/cursors/TestCursorFetchNext.txt @@ -0,0 +1,86 @@ +CREATE TABLE test_cursors_fetch_next(a INT, b SMALLINT, c BIGINT, d TINYINT, e BIT); +INSERT INTO test_cursors_fetch_next values(0, 0, 0, 0, 0) +INSERT INTO test_cursors_fetch_next values(NULL, NULL, NULL, NULL, NULL) +INSERT INTO test_cursors_fetch_next values(1, 2, 3, 4, 1) +INSERT INTO test_cursors_fetch_next values(211234, 9780, 891372401, 56, 1) +cursor#!#open#!#SELECT * FROM test_cursors_fetch_next#!#TYPE_SCROLL_INSENSITIVE#!#CONCUR_READ_ONLY#!#CLOSE_CURSORS_AT_COMMIT +cursor#!#fetch#!#next +cursor#!#fetch#!#abs#!#2 +cursor#!#fetch#!#next +cursor#!#fetch#!#first +cursor#!#fetch#!#next +cursor#!#fetch#!#last +cursor#!#fetch#!#next +#cursor#!#fetch#!#prev +#cursor#!#fetch#!#next +#cursor#!#fetch#!#beforefirst +#cursor#!#fetch#!#next +#cursor#!#fetch#!#afterlast +#cursor#!#fetch#!#next +cursor#!#close +DROP TABLE test_cursors_fetch_next + +CREATE TABLE test_cursors_fetch_next(a CHAR(30), b VARCHAR(30), c NCHAR(30), d NVARCHAR(30)); +INSERT INTO test_cursors_fetch_next values(' ', ' ', ' ', ' ') +INSERT INTO test_cursors_fetch_next values(NULL, NULL, NULL, NULL) +INSERT INTO test_cursors_fetch_next values('hello', 'from the', N'server', N'side 😆') +INSERT INTO test_cursors_fetch_next values('Its', 'always', N'day', N'1') +cursor#!#open#!#SELECT * FROM test_cursors_fetch_next#!#TYPE_SCROLL_INSENSITIVE#!#CONCUR_READ_ONLY#!#CLOSE_CURSORS_AT_COMMIT +cursor#!#fetch#!#abs#!#3 +cursor#!#fetch#!#next +cursor#!#fetch#!#first +cursor#!#fetch#!#next +cursor#!#fetch#!#last +cursor#!#fetch#!#next +#cursor#!#fetch#!#prev +#cursor#!#fetch#!#next +#cursor#!#fetch#!#beforefirst +#cursor#!#fetch#!#next +#cursor#!#fetch#!#afterlast +#cursor#!#fetch#!#next +cursor#!#close +DROP TABLE test_cursors_fetch_next + +CREATE TABLE test_cursors_fetch_next(a DATE, b DATETIME, c SMALLDATETIME); +INSERT INTO test_cursors_fetch_next values('2000-12-13', '1900-02-28 23:59:59.989', '2000-12-13 12:58:23') +INSERT INTO test_cursors_fetch_next values(NULL, NULL, NULL) +INSERT INTO test_cursors_fetch_next values('1997-05-07', '1900-02-28 11:23:17.895', '2000-12-13 10:23:44') +INSERT INTO test_cursors_fetch_next values('1876-08-07', '1980-02-05 16:11:45.215', '1987-10-01 07:55:24') +cursor#!#open#!#SELECT * FROM test_cursors_fetch_next#!#TYPE_SCROLL_INSENSITIVE#!#CONCUR_READ_ONLY#!#CLOSE_CURSORS_AT_COMMIT +cursor#!#fetch#!#first +cursor#!#fetch#!#abs#!#4 +cursor#!#fetch#!#next +cursor#!#fetch#!#first +cursor#!#fetch#!#next +cursor#!#fetch#!#last +cursor#!#fetch#!#next +#cursor#!#fetch#!#prev +#cursor#!#fetch#!#next +#cursor#!#fetch#!#beforefirst +#cursor#!#fetch#!#next +#cursor#!#fetch#!#afterlast +#cursor#!#fetch#!#next +cursor#!#close +DROP TABLE test_cursors_fetch_next + +CREATE TABLE test_cursors_fetch_next(a FLOAT, b REAL, c MONEY, d SMALLMONEY); +INSERT INTO test_cursors_fetch_next values(0, 0, '$0', '$0') +INSERT INTO test_cursors_fetch_next values(NULL, NULL, NULL, NULL) +INSERT INTO test_cursors_fetch_next values(241.7832, 1214.691236, '62,514.00', '690.817') +INSERT INTO test_cursors_fetch_next values('32546', '980.709', '1,988,232.08', '$86,798') +cursor#!#open#!#SELECT * FROM test_cursors_fetch_next#!#TYPE_SCROLL_INSENSITIVE#!#CONCUR_READ_ONLY#!#CLOSE_CURSORS_AT_COMMIT +cursor#!#fetch#!#next +cursor#!#fetch#!#abs#!#2 +cursor#!#fetch#!#next +cursor#!#fetch#!#first +cursor#!#fetch#!#next +cursor#!#fetch#!#last +cursor#!#fetch#!#next +#cursor#!#fetch#!#prev +#cursor#!#fetch#!#next +#cursor#!#fetch#!#beforefirst +#cursor#!#fetch#!#next +#cursor#!#fetch#!#afterlast +#cursor#!#fetch#!#next +cursor#!#close +DROP TABLE test_cursors_fetch_next \ No newline at end of file diff --git a/contrib/test/python/input/cursors/TestCursorPrepExecFetchNext.txt b/contrib/test/python/input/cursors/TestCursorPrepExecFetchNext.txt new file mode 100644 index 00000000000..95976355da6 --- /dev/null +++ b/contrib/test/python/input/cursors/TestCursorPrepExecFetchNext.txt @@ -0,0 +1,94 @@ +CREATE TABLE test_cursor_prep_exec_fetch_next(a INT, b SMALLINT, c BIGINT, d TINYINT, e BIT); +INSERT INTO test_cursor_prep_exec_fetch_next values(0, 0, 0, 0, 0) +INSERT INTO test_cursor_prep_exec_fetch_next values(NULL, NULL, NULL, NULL, NULL) +INSERT INTO test_cursor_prep_exec_fetch_next values(1, 2, 3, 4, 1) +INSERT INTO test_cursor_prep_exec_fetch_next values(211234, 9780, 891372401, 56, 1) +cursor#!#open#!#prepst#!#SELECT * FROM test_cursor_prep_exec_fetch_next WHERE a > @a #!#INT|-|a|-|-2#!#TYPE_SCROLL_INSENSITIVE#!#CONCUR_READ_ONLY#!#CLOSE_CURSORS_AT_COMMIT +cursor#!#fetch#!#next +cursor#!#fetch#!#abs#!#2 +cursor#!#fetch#!#next +cursor#!#fetch#!#first +cursor#!#fetch#!#next +cursor#!#close +cursor#!#open#!#prepst#!#exec#!#INT|-|a|-|0#!#TYPE_SCROLL_INSENSITIVE#!#CONCUR_READ_ONLY#!#HOLD_CURSORS_OVER_COMMIT +cursor#!#fetch#!#last +cursor#!#fetch#!#next +#cursor#!#fetch#!#prev +#cursor#!#fetch#!#next +#cursor#!#fetch#!#beforefirst +#cursor#!#fetch#!#next +#cursor#!#fetch#!#afterlast +#cursor#!#fetch#!#next +cursor#!#close +DROP TABLE test_cursor_prep_exec_fetch_next + +CREATE TABLE test_cursor_prep_exec_fetch_next(a CHAR(30), b VARCHAR(30), c NCHAR(30), d NVARCHAR(30)); +INSERT INTO test_cursor_prep_exec_fetch_next values(' ', ' ', ' ', ' ') +INSERT INTO test_cursor_prep_exec_fetch_next values(NULL, NULL, NULL, NULL) +INSERT INTO test_cursor_prep_exec_fetch_next values('hello', 'from the', N'server', N'side 😆') +INSERT INTO test_cursor_prep_exec_fetch_next values('Its', 'always', N'day', N'1') +cursor#!#open#!#prepst#!#SELECT * FROM test_cursor_prep_exec_fetch_next WHERE a <> @a #!#CHAR|-|a|-|hello#!#TYPE_SCROLL_INSENSITIVE#!#CONCUR_READ_ONLY#!#CLOSE_CURSORS_AT_COMMIT +cursor#!#fetch#!#abs#!#3 +cursor#!#fetch#!#next +cursor#!#fetch#!#first +cursor#!#fetch#!#next +cursor#!#close +cursor#!#open#!#prepst#!#exec#!#CHAR|-|a|-|Its#!#TYPE_SCROLL_INSENSITIVE#!#CONCUR_READ_ONLY#!#CLOSE_CURSORS_AT_COMMIT +cursor#!#fetch#!#last +cursor#!#fetch#!#next +#cursor#!#fetch#!#prev +#cursor#!#fetch#!#next +#cursor#!#fetch#!#beforefirst +#cursor#!#fetch#!#next +#cursor#!#fetch#!#afterlast +#cursor#!#fetch#!#next +cursor#!#close +DROP TABLE test_cursor_prep_exec_fetch_next + +CREATE TABLE test_cursor_prep_exec_fetch_next(a DATE, b DATETIME, c SMALLDATETIME); +INSERT INTO test_cursor_prep_exec_fetch_next values('2000-12-13', '1900-02-28 23:59:59.989', '2000-12-13 12:58:23') +INSERT INTO test_cursor_prep_exec_fetch_next values(NULL, NULL, NULL) +INSERT INTO test_cursor_prep_exec_fetch_next values('1997-05-07', '1900-02-28 11:23:17.895', '2000-12-13 10:23:44') +INSERT INTO test_cursor_prep_exec_fetch_next values('1876-08-07', '1980-02-05 16:11:45.215', '1987-10-01 07:55:24') +cursor#!#open#!#prepst#!#SELECT * FROM test_cursor_prep_exec_fetch_next WHERE b > @b #!#DATETIME|-|b|-|1753-01-01 00:00:00.000#!#TYPE_SCROLL_INSENSITIVE#!#CONCUR_READ_ONLY#!#CLOSE_CURSORS_AT_COMMIT +cursor#!#fetch#!#first +cursor#!#fetch#!#abs#!#2 +cursor#!#fetch#!#next +cursor#!#fetch#!#first +cursor#!#fetch#!#next +cursor#!#close +cursor#!#open#!#prepst#!#exec#!#DATETIME|-|b|-|1947-01-01 11:23:17.374#!#TYPE_SCROLL_INSENSITIVE#!#CONCUR_READ_ONLY#!#CLOSE_CURSORS_AT_COMMIT +cursor#!#fetch#!#last +cursor#!#fetch#!#next +#cursor#!#fetch#!#prev +#cursor#!#fetch#!#next +#cursor#!#fetch#!#beforefirst +#cursor#!#fetch#!#next +#cursor#!#fetch#!#afterlast +#cursor#!#fetch#!#next +cursor#!#close +DROP TABLE test_cursor_prep_exec_fetch_next + +CREATE TABLE test_cursor_prep_exec_fetch_next(a FLOAT, b REAL, c MONEY, d SMALLMONEY); +INSERT INTO test_cursor_prep_exec_fetch_next values(0, 0, '$0', '$0') +INSERT INTO test_cursor_prep_exec_fetch_next values(NULL, NULL, NULL, NULL) +INSERT INTO test_cursor_prep_exec_fetch_next values(241.7832, 1214.691236, '62,514.00', '690.817') +INSERT INTO test_cursor_prep_exec_fetch_next values('32546', '980.709', '1,988,232.08', '$86,798') +cursor#!#open#!#prepst#!#SELECT * FROM test_cursor_prep_exec_fetch_next WHERE b > @b #!#REAL|-|b|-|12.0834#!#TYPE_SCROLL_INSENSITIVE#!#CONCUR_READ_ONLY#!#CLOSE_CURSORS_AT_COMMIT +cursor#!#fetch#!#next +cursor#!#fetch#!#abs#!#3 +cursor#!#fetch#!#next +cursor#!#fetch#!#first +cursor#!#fetch#!#next +cursor#!#close +cursor#!#open#!#prepst#!#exec#!#REAL|-|b|-|1000.241#!#TYPE_SCROLL_INSENSITIVE#!#CONCUR_READ_ONLY#!#CLOSE_CURSORS_AT_COMMIT +cursor#!#fetch#!#last +cursor#!#fetch#!#next +#cursor#!#fetch#!#prev +#cursor#!#fetch#!#next +#cursor#!#fetch#!#beforefirst +#cursor#!#fetch#!#next +#cursor#!#fetch#!#afterlast +#cursor#!#fetch#!#next +cursor#!#close +DROP TABLE test_cursor_prep_exec_fetch_next diff --git a/contrib/test/python/input/datatypes/BABEL-1643.txt b/contrib/test/python/input/datatypes/BABEL-1643.txt new file mode 100644 index 00000000000..572674bf761 --- /dev/null +++ b/contrib/test/python/input/datatypes/BABEL-1643.txt @@ -0,0 +1,3 @@ +exec sp_datatype_info_100 @data_type = 1; + +exec sp_datatype_info @data_type = 2; diff --git a/contrib/test/python/input/datatypes/TestBIT.txt b/contrib/test/python/input/datatypes/TestBIT.txt new file mode 100644 index 00000000000..8424eadd597 --- /dev/null +++ b/contrib/test/python/input/datatypes/TestBIT.txt @@ -0,0 +1,16 @@ +CREATE TABLE BIT_dt (a BIT) +prepst#!# INSERT INTO BIT_dt(a) values(@a) #!#BIT|-|a|-|false +prepst#!#exec#!#BIT|-|a|-|true +#next two lines are not allowed +#prepst#!#exec#!#BIT|-|a|-|0 +#prepst#!#exec#!#BIT|-|a|-|1 +prepst#!#exec#!#BIT|-|a|-| +SELECT * FROM BIT_dt; +INSERT INTO BIT_dt(a) values(1) +INSERT INTO BIT_dt(a) values(0) +#next two lines are not allowed +#INSERT INTO BIT_dt(a) values(false) +#INSERT INTO BIT_dt(a) values(true) +INSERT INTO BIT_dt(a) values(NULL) +SELECT * FROM BIT_dt; +DROP TABLE BIT_dt; \ No newline at end of file diff --git a/contrib/test/python/input/datatypes/TestBigInt.txt b/contrib/test/python/input/datatypes/TestBigInt.txt new file mode 100644 index 00000000000..ef1451f78e8 --- /dev/null +++ b/contrib/test/python/input/datatypes/TestBigInt.txt @@ -0,0 +1,24 @@ +CREATE TABLE BIGINT_dt (a BIGINT) +prepst#!# INSERT INTO BIGINT_dt(a) values(@a) #!#BIGINT|-|a|-|0 +prepst#!#exec#!#BIGINT|-|a|-|-10 +prepst#!#exec#!#BIGINT|-|a|-|122100 +prepst#!#exec#!#BIGINT|-|a|-|0001202 +prepst#!#exec#!#BIGINT|-|a|-|-024112329 +prepst#!#exec#!#BIGINT|-|a|-|-0000000000000000002 +prepst#!#exec#!#BIGINT|-|a|-|0000000000000000086 +prepst#!#exec#!#BIGINT|-|a|-|-9223372036854775808 +prepst#!#exec#!#BIGINT|-|a|-|9223372036854775807 +prepst#!#exec#!#BIGINT|-|a|-| +SELECT * FROM BIGINT_dt; +INSERT INTO BIGINT_dt(a) values(0) +INSERT INTO BIGINT_dt(a) values(-120) +INSERT INTO BIGINT_dt(a) values(00100) +INSERT INTO BIGINT_dt(a) values(-004) +INSERT INTO BIGINT_dt(a) values(-012245532534) +INSERT INTO BIGINT_dt(a) values(-0000000000000000002) +INSERT INTO BIGINT_dt(a) values(0000000000000000086) +INSERT INTO BIGINT_dt(a) values(-9223372036854775808) +INSERT INTO BIGINT_dt(a) values(9223372036854775807) +INSERT INTO BIGINT_dt(a) values(NULL) +SELECT * FROM BIGINT_dt; +DROP TABLE BIGINT_dt; \ No newline at end of file diff --git a/contrib/test/python/input/datatypes/TestBinary.txt b/contrib/test/python/input/datatypes/TestBinary.txt new file mode 100644 index 00000000000..2aac1c7b110 --- /dev/null +++ b/contrib/test/python/input/datatypes/TestBinary.txt @@ -0,0 +1,19 @@ +CREATE TABLE BINARY_dt(a BINARY(8), b VARBINARY(10)); +#inserting random values +INSERT INTO BINARY_dt(a, b) values (1234, 12345); +INSERT INTO BINARY_dt(a, b) values (NULL, NULL); +#INSERT INTO BINARY_dt(a, b) values (0x31323334, 0x3132333435); +SELECT * FROM BINARY_dt +#prepst#!# INSERT INTO BINARY_dt(a, b) values(@a, @b) #!#binary|-|a|-|1234#!#varbinary|-|b|-|12345 +DROP TABLE BINARY_dt + + +CREATE TABLE BINARY_dt(a VARBINARY(max)); +INSERT INTO BINARY_dt(a) values (NULL); +SELECT * FROM BINARY_dt; +DROP TABLE BINARY_dt; + +create table BINARY_dt (a VARBINARY(max), b int, c int, d int, e int ,f int, g int, h int, i int); +insert into BINARY_dt (a,b,c,d,e,f,g,h,i) values (NULL,1,2,3,4,5,6,7,8); +select * from BINARY_dt; +drop table BINARY_dt; \ No newline at end of file diff --git a/contrib/test/python/input/datatypes/TestChar.txt b/contrib/test/python/input/datatypes/TestChar.txt new file mode 100644 index 00000000000..c982a1e7265 --- /dev/null +++ b/contrib/test/python/input/datatypes/TestChar.txt @@ -0,0 +1,16 @@ +CREATE TABLE CHAR_dt (a CHAR(24), b NCHAR(24)) +prepst#!# INSERT INTO CHAR_dt(a, b) values(@a, @b) #!#CHAR|-|a|-|Dipesh#!#NCHAR|-|b|-|Dhameliya +prepst#!#exec#!#CHAR|-|a|-| Dipesh #!#NCHAR|-|b|-| Dhameliya +prepst#!#exec#!#CHAR|-|a|-| D#!#NCHAR|-|b|-| 🤣😃 +prepst#!#exec#!#CHAR|-|a|-| #!#NCHAR|-|b|-| +prepst#!#exec#!#CHAR|-|a|-| #!#NCHAR|-|b|-|😊😋😎😍😅😆 +prepst#!#exec#!#CHAR|-|a|-|#!#NCHAR|-|b|-| +SELECT * FROM CHAR_dt; +INSERT INTO CHAR_dt(a,b) values('Dipesh','Dhameliya') +INSERT INTO CHAR_dt(a,b) values(' Dipesh',' Dhameliya') +#INSERT INTO CHAR_dt(a,b) values(' D',N' 🤣😃') +INSERT INTO CHAR_dt(a,b) values(' ',' ') +#INSERT INTO CHAR_dt(a,b) values(' ',N'😊😋😎😍😅😆') +INSERT INTO CHAR_dt(a,b) values(NULL,NULL) +SELECT * FROM CHAR_dt; +DROP TABLE CHAR_dt; \ No newline at end of file diff --git a/contrib/test/python/input/datatypes/TestDate.txt b/contrib/test/python/input/datatypes/TestDate.txt new file mode 100644 index 00000000000..5af2f499b2f --- /dev/null +++ b/contrib/test/python/input/datatypes/TestDate.txt @@ -0,0 +1,14 @@ +CREATE TABLE DATE_dt (a DATE) +prepst#!# INSERT INTO DATE_dt(a) values(@a) #!#DATE|-|a|-|2000-12-13 +prepst#!#exec#!#DATE|-|a|-|2000-02-28 +prepst#!#exec#!#DATE|-|a|-|0001-01-01 +prepst#!#exec#!#DATE|-|a|-|9999-12-31 +prepst#!#exec#!#DATE|-|a|-| +SELECT * FROM DATE_dt; +INSERT INTO DATE_dt(a) values('2000-12-13') +INSERT INTO DATE_dt(a) values('1900-02-28') +INSERT INTO DATE_dt(a) values('0001-01-01') +INSERT INTO DATE_dt(a) values('9999-12-31') +INSERT INTO DATE_dt(a) values(NULL) +SELECT * FROM DATE_dt; +DROP TABLE DATE_dt; \ No newline at end of file diff --git a/contrib/test/python/input/datatypes/TestDatetime.txt b/contrib/test/python/input/datatypes/TestDatetime.txt new file mode 100644 index 00000000000..a5df9ff4d9e --- /dev/null +++ b/contrib/test/python/input/datatypes/TestDatetime.txt @@ -0,0 +1,36 @@ +CREATE TABLE DATETIME_dt (a DATETIME) +prepst#!# INSERT INTO DATETIME_dt(a) values(@a) #!#DATETIME|-|a|-|2000-12-13 12:58:23.123 +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.989 +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.990 +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.991 +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.992 +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.993 +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.994 +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.995 +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.996 +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.997 +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.998 +prepst#!#exec#!#DATETIME|-|a|-|2000-02-28 23:59:59.999 +prepst#!#exec#!#DATETIME|-|a|-|1900-02-28 23:59:59.989 +prepst#!#exec#!#DATETIME|-|a|-|1753-01-01 00:00:00.000 +prepst#!#exec#!#DATETIME|-|a|-|9999-12-31 23:59:59.997 +prepst#!#exec#!#DATETIME|-|a|-| +SELECT * FROM DATETIME_dt; +INSERT INTO DATETIME_dt(a) values('2000-12-13 12:58:23.123') +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.989') +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.990') +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.991') +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.992') +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.993') +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.994') +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.995') +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.996') +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.997') +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.998') +INSERT INTO DATETIME_dt(a) values('1900-02-28 23:59:59.999') +INSERT INTO DATETIME_dt(a) values('2000-02-28 23:59:59.989') +INSERT INTO DATETIME_dt(a) values('1753-01-01 00:00:00.000') +INSERT INTO DATETIME_dt(a) values('9999-12-31 23:59:59.997') +INSERT INTO DATETIME_dt(a) values(NULL) +SELECT * FROM DATETIME_dt; +DROP TABLE DATETIME_dt; \ No newline at end of file diff --git a/contrib/test/python/input/datatypes/TestDatetime2.txt b/contrib/test/python/input/datatypes/TestDatetime2.txt new file mode 100644 index 00000000000..2a6062abb25 --- /dev/null +++ b/contrib/test/python/input/datatypes/TestDatetime2.txt @@ -0,0 +1,15 @@ +Create table TestDatetime2(a Datetime2(6)) + +prepst#!# Insert into TestDatetime2 Values(@a) #!#Datetime2|-|a|-|2016-10-23 12:45:37.123|-|0 +prepst#!#exec#!#Datetime2|-|a|-|2016-10-23 12:45:37.123|-|3 +prepst#!#exec#!#Datetime2|-|a|-|2016-10-23 12:45:37.12|-|2 +prepst#!#exec#!#Datetime2|-|a|-|2016-10-23 12:45:37.1|-|1 +prepst#!#exec#!#Datetime2|-|a|-|2016-10-23 12:45:37.1234|-|4 +prepst#!#exec#!#Datetime2|-|a|-|2016-10-23 12:45:37.123456|-|6 +prepst#!#exec#!#Datetime2|-|a|-|2016-10-23 12:45:37.123456|-|5 +#prepst#!#exec#!#Datetime2|-|a|-|12:45:37.123456|-|5 +prepst#!#exec#!#Datetime2|-|a|-| + +select * from TestDatetime2 + +Drop table TestDatetime2 \ No newline at end of file diff --git a/contrib/test/python/input/datatypes/TestDecimal.txt b/contrib/test/python/input/datatypes/TestDecimal.txt new file mode 100644 index 00000000000..531fb023efe --- /dev/null +++ b/contrib/test/python/input/datatypes/TestDecimal.txt @@ -0,0 +1,180 @@ +CREATE TABLE decimal_table(num decimal(5, 2)); + +prepst#!#INSERT INTO decimal_table(num) VALUES(@a) #!#decimal|-|a|-|3|-|5|-|2 +prepst#!#exec#!#decimal|-|a|-|123.456|-|5|-|2 +prepst#!#exec#!#decimal|-|a|-|123.4|-|5|-|2 +prepst#!#exec#!#decimal|-|a|-|123|-|5|-|2 +prepst#!#exec#!#decimal|-|a|-|123.45|-|5|-|2 +prepst#!#exec#!#decimal|-|a|-||-|5|-|2 +prepst#!#exec#!#decimal|-|a|-|-123.456|-|5|-|2 +prepst#!#exec#!#decimal|-|a|-|-123.4|-|5|-|2 +prepst#!#exec#!#decimal|-|a|-|-123|-|5|-|2 +#prepst#!#exec#!#decimal|-|a|-|0|-|5|-|2 +prepst#!#exec#!#decimal|-|a|-|-1|-|3|-|2 +prepst#!#exec#!#decimal|-|a|-|-123|-|9|-|2 + +SELECT * FROM decimal_table; + +DROP TABLE decimal_table; + +CREATE TABLE decimal_table(num decimal(38, 3)); + +prepst#!#INSERT INTO decimal_table(num) VALUES(@a1) #!#decimal|-|a1|-|3|-|5|-|2 +prepst#!#exec#!#decimal|-|a1|-|123.456|-|5|-|2 +prepst#!#exec#!#decimal|-|a1|-|123.4|-|5|-|2 +prepst#!#exec#!#decimal|-|a1|-|123|-|5|-|2 +prepst#!#exec#!#decimal|-|a1|-|123.45|-|5|-|2 +prepst#!#exec#!#decimal|-|a1|-||-|5|-|2 +prepst#!#exec#!#decimal|-|a1|-|-123.456|-|5|-|2 +prepst#!#exec#!#decimal|-|a1|-|-123.4|-|5|-|2 +prepst#!#exec#!#decimal|-|a1|-|-123|-|5|-|2 +#prepst#!#exec#!#decimal|-|a1|-|0|-|5|-|2 +prepst#!#exec#!#decimal|-|a1|-|-1|-|3|-|2 +prepst#!#exec#!#decimal|-|a1|-|-123|-|9|-|2 + +prepst#!#exec#!#decimal|-|a1|-|2147483647|-|10|-|0 +prepst#!#exec#!#decimal|-|a1|-|-2147483647|-|10|-|0 +prepst#!#exec#!#decimal|-|a1|-|2147483646|-|10|-|0 +prepst#!#exec#!#decimal|-|a1|-|-2147483646|-|10|-|0 +prepst#!#exec#!#decimal|-|a1|-|2147483648|-|10|-|0 +prepst#!#exec#!#decimal|-|a1|-|-2147483648|-|10|-|0 + +SELECT * FROM decimal_table; + +DROP TABLE decimal_table; + +# JIRA 507, WORKING FOR BABEL +#CREATE TABLE decimal_table(num decimal(39, 20)); + +CREATE TABLE decimal_table(num decimal(38, 20)); + +prepst#!#INSERT INTO decimal_table(num) VALUES(@a2) #!#decimal|-|a2|-|3|-|5|-|2 +prepst#!#exec#!#decimal|-|a2|-|123.456|-|5|-|2 +prepst#!#exec#!#decimal|-|a2|-|123.4|-|5|-|2 +prepst#!#exec#!#decimal|-|a2|-|123|-|5|-|2 +prepst#!#exec#!#decimal|-|a2|-|123.45|-|5|-|2 +prepst#!#exec#!#decimal|-|a2|-||-|5|-|2 +prepst#!#exec#!#decimal|-|a2|-|-123.456|-|5|-|2 +prepst#!#exec#!#decimal|-|a2|-|-123.4|-|5|-|2 +prepst#!#exec#!#decimal|-|a2|-|-123|-|5|-|2 +#prepst#!#exec#!#decimal|-|a2|-|0|-|5|-|2 +prepst#!#exec#!#decimal|-|a2|-|-1|-|3|-|2 +prepst#!#exec#!#decimal|-|a2|-|-123|-|9|-|2 +prepst#!#exec#!#decimal|-|a2|-|2147483647|-|10|-|0 +SELECT * FROM decimal_table; + +DROP TABLE decimal_table; + +CREATE TABLE decimal_table(num decimal(38, 20)); +prepst#!#INSERT INTO decimal_table(num) VALUES(@a3) #!#decimal|-|a3|-|3|-|5|-|2 +prepst#!#exec#!#decimal|-|a3|-|123.456|-|5|-|2 +prepst#!#exec#!#decimal|-|a3|-|123.4|-|5|-|2 +prepst#!#exec#!#decimal|-|a3|-|123|-|5|-|2 +prepst#!#exec#!#decimal|-|a3|-|123.45|-|5|-|2 +prepst#!#exec#!#decimal|-|a3|-||-|5|-|2 +prepst#!#exec#!#decimal|-|a3|-|-123.456|-|5|-|2 +prepst#!#exec#!#decimal|-|a3|-|-123.4|-|5|-|2 +prepst#!#exec#!#decimal|-|a3|-|-123|-|5|-|2 +#prepst#!#exec#!#decimal|-|a3|-|0|-|5|-|2 +prepst#!#exec#!#decimal|-|a3|-|-1|-|3|-|2 +prepst#!#exec#!#decimal|-|a3|-|-123|-|9|-|2 +prepst#!#exec#!#decimal|-|a3|-|2147483647|-|10|-|0 +SELECT * FROM decimal_table; + +DROP TABLE decimal_table; + +CREATE TABLE decimal_table(num decimal(38, 21)); +prepst#!#INSERT INTO decimal_table(num) VALUES(@a4) #!#decimal|-|a4|-|3|-|5|-|2 +prepst#!#exec#!#decimal|-|a4|-|123.456|-|5|-|2 +prepst#!#exec#!#decimal|-|a4|-|123.4|-|5|-|2 +prepst#!#exec#!#decimal|-|a4|-|123|-|5|-|2 +prepst#!#exec#!#decimal|-|a4|-|123.45|-|5|-|2 +prepst#!#exec#!#decimal|-|a4|-||-|5|-|2 +prepst#!#exec#!#decimal|-|a4|-|-123.456|-|5|-|2 +prepst#!#exec#!#decimal|-|a4|-|-123.4|-|5|-|2 +prepst#!#exec#!#decimal|-|a4|-|-123|-|5|-|2 +#prepst#!#exec#!#decimal|-|a4|-|0|-|5|-|2 +prepst#!#exec#!#decimal|-|a4|-|-1|-|3|-|2 +prepst#!#exec#!#decimal|-|a4|-|-123|-|9|-|2 +prepst#!#exec#!#decimal|-|a4|-|2147483647|-|10|-|0 +SELECT * FROM decimal_table; + +DROP TABLE decimal_table; + +CREATE TABLE decimal_table(num decimal(38, 22)); +prepst#!#INSERT INTO decimal_table(num) VALUES(@a5) #!#decimal|-|a5|-|3|-|5|-|2 +prepst#!#exec#!#decimal|-|a5|-|123.456|-|5|-|2 +prepst#!#exec#!#decimal|-|a5|-|123.4|-|5|-|2 +prepst#!#exec#!#decimal|-|a5|-|123|-|5|-|2 +prepst#!#exec#!#decimal|-|a5|-|123.45|-|5|-|2 +prepst#!#exec#!#decimal|-|a5|-||-|5|-|2 +prepst#!#exec#!#decimal|-|a5|-|-123.456|-|5|-|2 +prepst#!#exec#!#decimal|-|a5|-|-123.4|-|5|-|2 +prepst#!#exec#!#decimal|-|a5|-|-123|-|5|-|2 +#prepst#!#exec#!#decimal|-|a5|-|0|-|5|-|2 +prepst#!#exec#!#decimal|-|a5|-|-1|-|3|-|2 +prepst#!#exec#!#decimal|-|a5|-|-123|-|9|-|2 +prepst#!#exec#!#decimal|-|a5|-|2147483647|-|10|-|0 +SELECT * FROM decimal_table; + +DROP TABLE decimal_table; + +CREATE TABLE decimal_table(num decimal(38, 23)); +prepst#!#INSERT INTO decimal_table(num) VALUES(@a6) #!#decimal|-|a6|-|3|-|5|-|2 +prepst#!#exec#!#decimal|-|a6|-|123.456|-|5|-|2 +prepst#!#exec#!#decimal|-|a6|-|123.4|-|5|-|2 +prepst#!#exec#!#decimal|-|a6|-|123|-|5|-|2 +prepst#!#exec#!#decimal|-|a6|-|123.45|-|5|-|2 +prepst#!#exec#!#decimal|-|a6|-||-|5|-|2 +prepst#!#exec#!#decimal|-|a6|-|-123.456|-|5|-|2 +prepst#!#exec#!#decimal|-|a6|-|-123.4|-|5|-|2 +prepst#!#exec#!#decimal|-|a6|-|-123|-|5|-|2 +#prepst#!#exec#!#decimal|-|a6|-|0|-|5|-|2 +prepst#!#exec#!#decimal|-|a6|-|-1|-|3|-|2 +prepst#!#exec#!#decimal|-|a6|-|-123|-|9|-|2 +prepst#!#exec#!#decimal|-|a6|-|2147483647|-|10|-|0 +SELECT * FROM decimal_table; + +DROP TABLE decimal_table; + +CREATE TABLE decimal_table(num decimal(38, 25)); +prepst#!#INSERT INTO decimal_table(num) VALUES(@a7) #!#decimal|-|a7|-|3|-|5|-|2 +prepst#!#exec#!#decimal|-|a7|-|123.456|-|5|-|2 +prepst#!#exec#!#decimal|-|a7|-|123.4|-|5|-|2 +prepst#!#exec#!#decimal|-|a7|-|123|-|5|-|2 +prepst#!#exec#!#decimal|-|a7|-|123.45|-|5|-|2 +prepst#!#exec#!#decimal|-|a7|-||-|5|-|2 +prepst#!#exec#!#decimal|-|a7|-|-123.456|-|5|-|2 +prepst#!#exec#!#decimal|-|a7|-|-123.4|-|5|-|2 +prepst#!#exec#!#decimal|-|a7|-|-123|-|5|-|2 +#prepst#!#exec#!#decimal|-|a7|-|0|-|5|-|2 +prepst#!#exec#!#decimal|-|a7|-|-1|-|3|-|2 +prepst#!#exec#!#decimal|-|a7|-|-123|-|9|-|2 +prepst#!#exec#!#decimal|-|a7|-|247483647|-|10|-|0 +prepst#!#exec#!#decimal|-|a7|-|-247483647|-|10|-|0 +SELECT * FROM decimal_table; + +DROP TABLE decimal_table; + + +CREATE TABLE decimal_table(num decimal(38, 25)); + +insert into decimal_table values (2147483647) +insert into decimal_table values (-2147483647) + +insert into decimal_table values (2147483646) +insert into decimal_table values (-2147483646) + +insert into decimal_table values (2147483648) +insert into decimal_table values (-2147483648) + +#insert into decimal_table values(123456789123456789.1234567891234567891234567); +#insert into decimal_table values(1234567891234567891.1234567891234567891234567); +#insert into decimal_table values(123456789123456789.12345678912345678912345678); +insert into decimal_table values(0.0); +insert into decimal_table values(0.0000000000000000000000000); +insert into decimal_table values(0.00000000000000000000000000); + +SELECT * FROM decimal_table; + +DROP TABLE decimal_table; \ No newline at end of file diff --git a/contrib/test/python/input/datatypes/TestFloat.txt b/contrib/test/python/input/datatypes/TestFloat.txt new file mode 100644 index 00000000000..37609dbf959 --- /dev/null +++ b/contrib/test/python/input/datatypes/TestFloat.txt @@ -0,0 +1,24 @@ +CREATE TABLE FLOAT_dt (a FLOAT) +prepst#!# INSERT INTO FLOAT_dt(a) values(@a) #!#FLOAT|-|a|-|0 +prepst#!#exec#!#FLOAT|-|a|-|1.050 +prepst#!#exec#!#FLOAT|-|a|-|01.05 +prepst#!#exec#!#FLOAT|-|a|-|0001202 +prepst#!#exec#!#FLOAT|-|a|-|-024112329 +prepst#!#exec#!#FLOAT|-|a|-|-02.5 +prepst#!#exec#!#FLOAT|-|a|-|0000000000000000086 +prepst#!#exec#!#FLOAT|-|a|-|-1.79E+308 +prepst#!#exec#!#FLOAT|-|a|-|1.79E+308 +prepst#!#exec#!#FLOAT|-|a|-| +SELECT * FROM FLOAT_dt; +INSERT INTO FLOAT_dt(a) values(0) +INSERT INTO FLOAT_dt(a) values(1.050) +INSERT INTO FLOAT_dt(a) values(01.05) +INSERT INTO FLOAT_dt(a) values(-004) +INSERT INTO FLOAT_dt(a) values(-0122455324.5) +INSERT INTO FLOAT_dt(a) values(-000002) +INSERT INTO FLOAT_dt(a) values(0000000000000000086) +INSERT INTO FLOAT_dt(a) values(-1.79E+308) +INSERT INTO FLOAT_dt(a) values(1.79E+308) +INSERT INTO FLOAT_dt(a) values(NULL) +SELECT * FROM FLOAT_dt; +DROP TABLE FLOAT_dt; \ No newline at end of file diff --git a/contrib/test/python/input/datatypes/TestInt.txt b/contrib/test/python/input/datatypes/TestInt.txt new file mode 100644 index 00000000000..cd37ee7174d --- /dev/null +++ b/contrib/test/python/input/datatypes/TestInt.txt @@ -0,0 +1,29 @@ +CREATE TABLE INT_dt(a INT); +prepst#!#INSERT INTO INT_dt(a) values(@a) #!#INT|-|a|-|0 +prepst#!#exec#!#INT|-|a|-|-10 +prepst#!#exec#!#INT|-|a|-|10 +prepst#!#exec#!#INT|-|a|-|-12234 +prepst#!#exec#!#INT|-|a|-|22 +prepst#!#exec#!#INT|-|a|-|003 +prepst#!#exec#!#INT|-|a|-|9864 +prepst#!#exec#!#INT|-|a|-|-01625 +prepst#!#exec#!#INT|-|a|-|-2147483648 +prepst#!#exec#!#INT|-|a|-|2147483647 +prepst#!#exec#!#INT|-|a|-| + +SELECT * FROM INT_dt; + +INSERT INTO INT_dt(a) values(0) +INSERT INTO INT_dt(a) values(-10) +INSERT INTO INT_dt(a) values(10) +INSERT INTO INT_dt(a) values(-12345) +INSERT INTO INT_dt(a) values(22) +INSERT INTO INT_dt(a) values(004) +INSERT INTO INT_dt(a) values(-01645) +INSERT INTO INT_dt(a) values(-2147483648) +INSERT INTO INT_dt(a) values(2147483647) +INSERT INTO INT_dt(a) values(NULL) + +SELECT * FROM INT_dt; + +DROP TABLE INT_dt; \ No newline at end of file diff --git a/contrib/test/python/input/datatypes/TestMoney.txt b/contrib/test/python/input/datatypes/TestMoney.txt new file mode 100644 index 00000000000..39dddea4a40 --- /dev/null +++ b/contrib/test/python/input/datatypes/TestMoney.txt @@ -0,0 +1,30 @@ +CREATE TABLE money_dt(a smallmoney, b money); + +prepst#!#INSERT INTO money_dt(a, b) VALUES (@a, @b) #!#smallmoney|-|a|-|100.5#!#money|-|b|-|10.05 +prepst#!#exec#!#smallmoney|-|a|-|10#!#money|-|b|-|10 +prepst#!#exec#!#smallmoney|-|a|-|-10.05 #!#money|-|b|-|-10.0 +prepst#!#exec#!#smallmoney|-|a|-|-214748.3648#!#money|-|b|-|-922337203685477.5808 +prepst#!#exec#!#smallmoney|-|a|-|214748.3647#!#money|-|b|-|22337203685477.5807 +prepst#!#exec#!#smallmoney|-|a|-|214748.3647#!#money|-|b|-|22337203685477.5807 +prepst#!#exec#!#smallmoney|-|a|-|-214,748.3648#!#money|-|b|-|-922,337,203,685,477.5808 +prepst#!#exec#!#smallmoney|-|a|-|214,748.3647#!#money|-|b|-|922,337,203,685,477.5807 +prepst#!#exec#!#smallmoney|-|a|-|214,748.3647#!#money|-|b|-|922,337,203,685,477.5807 +prepst#!#exec#!#smallmoney|-|a|-|#!#money|-|b|-| + +SELECT * FROM money_dt; + +INSERT INTO money_dt(a,b) values(100.5,10.05); +INSERT INTO money_dt(a,b) values('$10','$10'); +INSERT INTO money_dt(a,b) values('-10.05','-10.0'); +INSERT INTO money_dt(a,b) values('10.05','10.0'); +INSERT INTO money_dt(a,b) values(-214748.3648,'-10.0'); +INSERT INTO money_dt(a,b) values(14748.3647,-922337203685477.5808); +INSERT INTO money_dt(a,b) values('$214748.3647','$22337203685477.5807'); +INSERT INTO money_dt(a,b) values('-214,748.3648','-922,337,203,685,477.5808'); +INSERT INTO money_dt(a,b) values('214,748.3647','922,337,203,685,477.5807'); +INSERT INTO money_dt(a,b) values('$214,748.3647','$922,337,203,685,477.5807'); +INSERT INTO money_dt(a,b) values(NULL,NULL); + + +SELECT * FROM money_dt; +DROP TABLE money_dt; \ No newline at end of file diff --git a/contrib/test/python/input/datatypes/TestNumeric.txt b/contrib/test/python/input/datatypes/TestNumeric.txt new file mode 100644 index 00000000000..e643af3a307 --- /dev/null +++ b/contrib/test/python/input/datatypes/TestNumeric.txt @@ -0,0 +1,187 @@ +CREATE TABLE numeric_table(num numeric(5, 2)); + +prepst#!#INSERT INTO numeric_table(num) VALUES(@a) #!#numeric|-|a|-|3|-|5|-|2 +prepst#!#exec#!#numeric|-|a|-|123.456|-|5|-|2 +prepst#!#exec#!#numeric|-|a|-|123.4|-|5|-|2 +prepst#!#exec#!#numeric|-|a|-|123|-|5|-|2 +prepst#!#exec#!#numeric|-|a|-|123.45|-|5|-|2 +prepst#!#exec#!#numeric|-|a|-||-|5|-|2 +prepst#!#exec#!#numeric|-|a|-|-123.456|-|5|-|2 +prepst#!#exec#!#numeric|-|a|-|-123.4|-|5|-|2 +prepst#!#exec#!#numeric|-|a|-|-123|-|5|-|2 +#prepst#!#exec#!#numeric|-|a|-|0|-|5|-|2 +prepst#!#exec#!#numeric|-|a|-|-1|-|3|-|2 +prepst#!#exec#!#numeric|-|a|-|-123|-|9|-|2 + +SELECT * FROM numeric_table; + +DROP TABLE numeric_table; + +CREATE TABLE numeric_table(num numeric(38, 3)); + +prepst#!#INSERT INTO numeric_table(num) VALUES(@a1) #!#numeric|-|a1|-|3|-|5|-|2 +prepst#!#exec#!#numeric|-|a1|-|123.456|-|5|-|2 +prepst#!#exec#!#numeric|-|a1|-|123.4|-|5|-|2 +prepst#!#exec#!#numeric|-|a1|-|123|-|5|-|2 +prepst#!#exec#!#numeric|-|a1|-|123.45|-|5|-|2 +prepst#!#exec#!#numeric|-|a1|-||-|5|-|2 +prepst#!#exec#!#numeric|-|a1|-|-123.456|-|5|-|2 +prepst#!#exec#!#numeric|-|a1|-|-123.4|-|5|-|2 +prepst#!#exec#!#numeric|-|a1|-|-123|-|5|-|2 +#prepst#!#exec#!#numeric|-|a1|-|0|-|5|-|2 +prepst#!#exec#!#numeric|-|a1|-|-1|-|3|-|2 +prepst#!#exec#!#numeric|-|a1|-|-123|-|9|-|2 + +prepst#!#exec#!#numeric|-|a1|-|2147483647|-|10|-|0 +prepst#!#exec#!#numeric|-|a1|-|-2147483647|-|10|-|0 +prepst#!#exec#!#numeric|-|a1|-|2147483646|-|10|-|0 +prepst#!#exec#!#numeric|-|a1|-|-2147483646|-|10|-|0 +prepst#!#exec#!#numeric|-|a1|-|2147483648|-|10|-|0 +prepst#!#exec#!#numeric|-|a1|-|-2147483648|-|10|-|0 + +SELECT * FROM numeric_table; + +DROP TABLE numeric_table; + +# JIRA 507, WORKING FOR BABEL +#CREATE TABLE numeric_table(num numeric(39, 20)); + +CREATE TABLE numeric_table(num numeric(38, 20)); + +prepst#!#INSERT INTO numeric_table(num) VALUES(@a2) #!#numeric|-|a2|-|3|-|5|-|2 +prepst#!#exec#!#numeric|-|a2|-|123.456|-|5|-|2 +prepst#!#exec#!#numeric|-|a2|-|123.4|-|5|-|2 +prepst#!#exec#!#numeric|-|a2|-|123|-|5|-|2 +prepst#!#exec#!#numeric|-|a2|-|123.45|-|5|-|2 +prepst#!#exec#!#numeric|-|a2|-||-|5|-|2 +prepst#!#exec#!#numeric|-|a2|-|-123.456|-|5|-|2 +prepst#!#exec#!#numeric|-|a2|-|-123.4|-|5|-|2 +prepst#!#exec#!#numeric|-|a2|-|-123|-|5|-|2 +#prepst#!#exec#!#numeric|-|a2|-|0|-|5|-|2 +prepst#!#exec#!#numeric|-|a2|-|-1|-|3|-|2 +prepst#!#exec#!#numeric|-|a2|-|-123|-|9|-|2 +prepst#!#exec#!#numeric|-|a2|-|2147483647|-|10|-|0 +SELECT * FROM numeric_table; + +DROP TABLE numeric_table; + +CREATE TABLE numeric_table(num numeric(38, 20)); +prepst#!#INSERT INTO numeric_table(num) VALUES(@a3) #!#numeric|-|a3|-|3|-|5|-|2 +prepst#!#exec#!#numeric|-|a3|-|123.456|-|5|-|2 +prepst#!#exec#!#numeric|-|a3|-|123.4|-|5|-|2 +prepst#!#exec#!#numeric|-|a3|-|123|-|5|-|2 +prepst#!#exec#!#numeric|-|a3|-|123.45|-|5|-|2 +prepst#!#exec#!#numeric|-|a3|-||-|5|-|2 +prepst#!#exec#!#numeric|-|a3|-|-123.456|-|5|-|2 +prepst#!#exec#!#numeric|-|a3|-|-123.4|-|5|-|2 +prepst#!#exec#!#numeric|-|a3|-|-123|-|5|-|2 +#prepst#!#exec#!#numeric|-|a3|-|0|-|5|-|2 +prepst#!#exec#!#numeric|-|a3|-|-1|-|3|-|2 +prepst#!#exec#!#numeric|-|a3|-|-123|-|9|-|2 +prepst#!#exec#!#numeric|-|a3|-|2147483647|-|10|-|0 +SELECT * FROM numeric_table; + +DROP TABLE numeric_table; + +CREATE TABLE numeric_table(num numeric(38, 21)); +prepst#!#INSERT INTO numeric_table(num) VALUES(@a4) #!#numeric|-|a4|-|3|-|5|-|2 +prepst#!#exec#!#numeric|-|a4|-|123.456|-|5|-|2 +prepst#!#exec#!#numeric|-|a4|-|123.4|-|5|-|2 +prepst#!#exec#!#numeric|-|a4|-|123|-|5|-|2 +prepst#!#exec#!#numeric|-|a4|-|123.45|-|5|-|2 +prepst#!#exec#!#numeric|-|a4|-||-|5|-|2 +prepst#!#exec#!#numeric|-|a4|-|-123.456|-|5|-|2 +prepst#!#exec#!#numeric|-|a4|-|-123.4|-|5|-|2 +prepst#!#exec#!#numeric|-|a4|-|-123|-|5|-|2 +#prepst#!#exec#!#numeric|-|a4|-|0|-|5|-|2 +prepst#!#exec#!#numeric|-|a4|-|-1|-|3|-|2 +prepst#!#exec#!#numeric|-|a4|-|-123|-|9|-|2 +prepst#!#exec#!#numeric|-|a4|-|2147483647|-|10|-|0 +SELECT * FROM numeric_table; + +DROP TABLE numeric_table; + +CREATE TABLE numeric_table(num numeric(38, 22)); +prepst#!#INSERT INTO numeric_table(num) VALUES(@a5) #!#numeric|-|a5|-|3|-|5|-|2 +prepst#!#exec#!#numeric|-|a5|-|123.456|-|5|-|2 +prepst#!#exec#!#numeric|-|a5|-|123.4|-|5|-|2 +prepst#!#exec#!#numeric|-|a5|-|123|-|5|-|2 +prepst#!#exec#!#numeric|-|a5|-|123.45|-|5|-|2 +prepst#!#exec#!#numeric|-|a5|-||-|5|-|2 +prepst#!#exec#!#numeric|-|a5|-|-123.456|-|5|-|2 +prepst#!#exec#!#numeric|-|a5|-|-123.4|-|5|-|2 +prepst#!#exec#!#numeric|-|a5|-|-123|-|5|-|2 +#prepst#!#exec#!#numeric|-|a5|-|0|-|5|-|2 +prepst#!#exec#!#numeric|-|a5|-|-1|-|3|-|2 +prepst#!#exec#!#numeric|-|a5|-|-123|-|9|-|2 +prepst#!#exec#!#numeric|-|a5|-|2147483647|-|10|-|0 +SELECT * FROM numeric_table; + +DROP TABLE numeric_table; + +CREATE TABLE numeric_table(num numeric(38, 23)); +prepst#!#INSERT INTO numeric_table(num) VALUES(@a6) #!#numeric|-|a6|-|3|-|5|-|2 +prepst#!#exec#!#numeric|-|a6|-|123.456|-|5|-|2 +prepst#!#exec#!#numeric|-|a6|-|123.4|-|5|-|2 +prepst#!#exec#!#numeric|-|a6|-|123|-|5|-|2 +prepst#!#exec#!#numeric|-|a6|-|123.45|-|5|-|2 +prepst#!#exec#!#numeric|-|a6|-||-|5|-|2 +prepst#!#exec#!#numeric|-|a6|-|-123.456|-|5|-|2 +prepst#!#exec#!#numeric|-|a6|-|-123.4|-|5|-|2 +prepst#!#exec#!#numeric|-|a6|-|-123|-|5|-|2 +#prepst#!#exec#!#numeric|-|a6|-|0|-|5|-|2 +prepst#!#exec#!#numeric|-|a6|-|-1|-|3|-|2 +prepst#!#exec#!#numeric|-|a6|-|-123|-|9|-|2 +prepst#!#exec#!#numeric|-|a6|-|2147483647|-|10|-|0 +SELECT * FROM numeric_table; + +DROP TABLE numeric_table; + +CREATE TABLE numeric_table(num numeric(38, 25)); +prepst#!#INSERT INTO numeric_table(num) VALUES(@a7) #!#numeric|-|a7|-|3|-|5|-|2 +prepst#!#exec#!#numeric|-|a7|-|123.456|-|5|-|2 +prepst#!#exec#!#numeric|-|a7|-|123.4|-|5|-|2 +prepst#!#exec#!#numeric|-|a7|-|123|-|5|-|2 +prepst#!#exec#!#numeric|-|a7|-|123.45|-|5|-|2 +prepst#!#exec#!#numeric|-|a7|-||-|5|-|2 +prepst#!#exec#!#numeric|-|a7|-|-123.456|-|5|-|2 +prepst#!#exec#!#numeric|-|a7|-|-123.4|-|5|-|2 +prepst#!#exec#!#numeric|-|a7|-|-123|-|5|-|2 +#prepst#!#exec#!#numeric|-|a7|-|0|-|5|-|2 +prepst#!#exec#!#numeric|-|a7|-|-1|-|3|-|2 +prepst#!#exec#!#numeric|-|a7|-|-123|-|9|-|2 +prepst#!#exec#!#numeric|-|a7|-|247483647|-|10|-|0 +prepst#!#exec#!#numeric|-|a7|-|-247483647|-|10|-|0 +SELECT * FROM numeric_table; + +DROP TABLE numeric_table; + + +CREATE TABLE numeric_table(num numeric(38, 25)); + +insert into numeric_table values (2147483647) +insert into numeric_table values (-2147483647) + +insert into numeric_table values (2147483646) +insert into numeric_table values (-2147483646) + +insert into numeric_table values (2147483648) +insert into numeric_table values (-2147483648) + +#insert into numeric_table values(123456789123456789.1234567891234567891234567); +#insert into numeric_table values(1234567891234567891.1234567891234567891234567); +#insert into numeric_table values(123456789123456789.12345678912345678912345678); +insert into numeric_table values(0.0); +insert into numeric_table values(0.0000000000000000000000000); +insert into numeric_table values(0.00000000000000000000000000); + +SELECT * FROM numeric_table; + +DROP TABLE numeric_table; + +# BABEL-1459 +declare @numvar numeric(5,4); set @numvar=-0.010; SELECT @numvar as N'@var'; +declare @numvar numeric(4,4); set @numvar=-0.010; SELECT @numvar as N'@var'; +declare @numvar numeric(5,4); set @numvar=1.01; SELECT @numvar as N'@var'; +declare @numvar numeric(4,4); set @numvar=0.01; SELECT @numvar as N'@var'; +declare @numvar numeric(4,4); set @numvar=0; SELECT @numvar as N'@var'; \ No newline at end of file diff --git a/contrib/test/python/input/datatypes/TestReal.txt b/contrib/test/python/input/datatypes/TestReal.txt new file mode 100644 index 00000000000..5c05836a056 --- /dev/null +++ b/contrib/test/python/input/datatypes/TestReal.txt @@ -0,0 +1,24 @@ +CREATE TABLE REAL_dt (a REAL) +prepst#!# INSERT INTO REAL_dt(a) values(@a) #!#REAL|-|a|-|0 +prepst#!#exec#!#REAL|-|a|-|1.050 +prepst#!#exec#!#REAL|-|a|-|01.05 +prepst#!#exec#!#REAL|-|a|-|0001202 +prepst#!#exec#!#REAL|-|a|-|-024112329 +prepst#!#exec#!#REAL|-|a|-|-02.5 +prepst#!#exec#!#REAL|-|a|-|0000000000000000086 +prepst#!#exec#!#REAL|-|a|-|-3.40E+38 +prepst#!#exec#!#REAL|-|a|-|3.40E+38 +prepst#!#exec#!#REAL|-|a|-| +SELECT * FROM REAL_dt; +INSERT INTO REAL_dt(a) values(0) +INSERT INTO REAL_dt(a) values(1.050) +INSERT INTO REAL_dt(a) values(01.05) +INSERT INTO REAL_dt(a) values(-004) +INSERT INTO REAL_dt(a) values(-0122455324.5) +INSERT INTO REAL_dt(a) values(-000002) +INSERT INTO REAL_dt(a) values(0000000000000000086) +INSERT INTO REAL_dt(a) values(-3.40E+38) +INSERT INTO REAL_dt(a) values(3.40E+38) +INSERT INTO REAL_dt(a) values(NULL) +SELECT * FROM REAL_dt; +DROP TABLE REAL_dt; \ No newline at end of file diff --git a/contrib/test/python/input/datatypes/TestSmallDatetime.txt b/contrib/test/python/input/datatypes/TestSmallDatetime.txt new file mode 100644 index 00000000000..748651c6a54 --- /dev/null +++ b/contrib/test/python/input/datatypes/TestSmallDatetime.txt @@ -0,0 +1,35 @@ +CREATE TABLE SMALLDATETIME_dt (a SMALLDATETIME) +prepst#!# INSERT INTO SMALLDATETIME_dt(a) values(@a) #!#SMALLDATETIME|-|a|-|2000-12-13 12:58:23 +prepst#!#exec#!#SMALLDATETIME|-|a|-|2007-05-08 12:35:29 +prepst#!#exec#!#SMALLDATETIME|-|a|-|2007-05-08 12:35:30 +prepst#!#exec#!#SMALLDATETIME|-|a|-|2007-05-08 12:59:59.998 +prepst#!#exec#!#SMALLDATETIME|-|a|-|2000-02-28 23:59:59.999 +prepst#!#exec#!#SMALLDATETIME|-|a|-|1900-02-28 23:59:59.999 +#prepst#!#exec#!#SMALLDATETIME|-|a|-|2000-02-28 23:45:29.999 +prepst#!#exec#!#SMALLDATETIME|-|a|-|2000-02-28 23:45:30 +prepst#!#exec#!#SMALLDATETIME|-|a|-|2000-02-28 23:45:29 +prepst#!#exec#!#SMALLDATETIME|-|a|-|1900-02-28 23:45:30 +prepst#!#exec#!#SMALLDATETIME|-|a|-|1900-02-28 23:45:29 +prepst#!#exec#!#SMALLDATETIME|-|a|-|2000-12-13 12:58:30 +prepst#!#exec#!#SMALLDATETIME|-|a|-|2000-02-28 23:45:29.998 +prepst#!#exec#!#SMALLDATETIME|-|a|-|1900-01-01 00:00:00 +prepst#!#exec#!#SMALLDATETIME|-|a|-|2079-06-06 23:59:29 +prepst#!#exec#!#SMALLDATETIME|-|a|-| +SELECT * FROM SMALLDATETIME_dt; +INSERT INTO SMALLDATETIME_dt(a) values('2000-12-13 12:58:23'); +INSERT INTO SMALLDATETIME_dt(a) values('2007-05-08 12:35:29'); +INSERT INTO SMALLDATETIME_dt(a) values('2007-05-08 12:35:30'); +INSERT INTO SMALLDATETIME_dt(a) values('2007-05-08 12:59:59.998'); +INSERT INTO SMALLDATETIME_dt(a) values('2000-02-28 23:59:59.999'); +INSERT INTO SMALLDATETIME_dt(a) values('1900-02-28 23:59:59.999'); +INSERT INTO SMALLDATETIME_dt(a) values('2000-02-28 23:45:29.999'); +INSERT INTO SMALLDATETIME_dt(a) values('2000-02-28 23:45:30'); +INSERT INTO SMALLDATETIME_dt(a) values('2000-02-28 23:45:29'); +INSERT INTO SMALLDATETIME_dt(a) values('1900-02-28 23:45:29'); +INSERT INTO SMALLDATETIME_dt(a) values('1900-12-13 12:58:30'); +INSERT INTO SMALLDATETIME_dt(a) values('2000-02-28 23:45:29.998'); +INSERT INTO SMALLDATETIME_dt(a) values('1900-01-01 00:00:00'); +INSERT INTO SMALLDATETIME_dt(a) values('2079-06-06 23:59:29'); +INSERT INTO SMALLDATETIME_dt(a) values(NULL); +SELECT * FROM SMALLDATETIME_dt; +DROP TABLE SMALLDATETIME_dt; \ No newline at end of file diff --git a/contrib/test/python/input/datatypes/TestSmallInt.txt b/contrib/test/python/input/datatypes/TestSmallInt.txt new file mode 100644 index 00000000000..79e6427345e --- /dev/null +++ b/contrib/test/python/input/datatypes/TestSmallInt.txt @@ -0,0 +1,24 @@ +CREATE TABLE SMALLINT_dt (a SMALLINT) +prepst#!# INSERT INTO SMALLINT_dt(a) values(@a) #!#SMALLINT|-|a|-|0 +prepst#!#exec#!#SMALLINT|-|a|-|-10 +prepst#!#exec#!#SMALLINT|-|a|-|100 +prepst#!#exec#!#SMALLINT|-|a|-|002 +prepst#!#exec#!#SMALLINT|-|a|-|-029 +prepst#!#exec#!#SMALLINT|-|a|-|-1234 +prepst#!#exec#!#SMALLINT|-|a|-|876 +prepst#!#exec#!#SMALLINT|-|a|-|-32768 +prepst#!#exec#!#SMALLINT|-|a|-|32767 +prepst#!#exec#!#SMALLINT|-|a|-| +SELECT * FROM SMALLINT_dt; +INSERT INTO SMALLINT_dt(a) values(0) +INSERT INTO SMALLINT_dt(a) values(-10) +INSERT INTO SMALLINT_dt(a) values(100) +INSERT INTO SMALLINT_dt(a) values(002) +INSERT INTO SMALLINT_dt(a) values(-029) +INSERT INTO SMALLINT_dt(a) values(-1234) +INSERT INTO SMALLINT_dt(a) values(876) +INSERT INTO SMALLINT_dt(a) values(-32768) +INSERT INTO SMALLINT_dt(a) values(32767) +INSERT INTO SMALLINT_dt(a) values(NULL) +SELECT * FROM SMALLINT_dt; +DROP TABLE SMALLINT_dt; \ No newline at end of file diff --git a/contrib/test/python/input/datatypes/TestText.txt b/contrib/test/python/input/datatypes/TestText.txt new file mode 100644 index 00000000000..30e90391ffa --- /dev/null +++ b/contrib/test/python/input/datatypes/TestText.txt @@ -0,0 +1,10 @@ +CREATE TABLE TEXT_dt (a text, b ntext) +#path to file should be with respect to root of test suite +prepst#!# INSERT INTO TEXT_dt(a, b) values(@a, @b) #!#TEXT|-|a|-|utils/sample.txt#!#NTEXT|-|b|-|utils/sample.txt +prepst#!#exec#!#TEXT|-|a|-|utils/blank.txt#!#NTEXT|-|b|-|utils/blank.txt +prepst#!#exec#!#TEXT|-|a|-|#!#NTEXT|-|b|-| +prepst#!#exec#!#TEXT|-|a|-|#!#NTEXT|-|b|-|utils/utf16.txt +prepst#!#exec#!#TEXT|-|a|-|#!#NTEXT|-|b|-|utils/emojisText.txt +prepst#!#exec#!#TEXT|-|a|-|#!#NTEXT|-|b|-|utils/devanagari.txt +SELECT * FROM TEXT_dt; +DROP TABLE TEXT_dt; \ No newline at end of file diff --git a/contrib/test/python/input/datatypes/TestTime.txt b/contrib/test/python/input/datatypes/TestTime.txt new file mode 100644 index 00000000000..fcb6805a487 --- /dev/null +++ b/contrib/test/python/input/datatypes/TestTime.txt @@ -0,0 +1,104 @@ +Create table TestTime(a time(6)) + +prepst#!# Insert into TestTime Values(@a) #!#Time|-|a|-|12:45:37.123|-|0 +prepst#!#exec#!#Time|-|a|-|12:45:37.123|-|3 +prepst#!#exec#!#Time|-|a|-|12:45:37.12|-|2 +prepst#!#exec#!#Time|-|a|-|12:45:37.1|-|1 +prepst#!#exec#!#Time|-|a|-|12:45:37.1234|-|4 +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|6 +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|5 +prepst#!#exec#!#Time|-|a|-| + +select * from TestTime + +Drop table TestTime + +Create table TestTime(a time(5)) + +prepst#!# Insert into TestTime Values(@a) #!#Time|-|a|-|12:45:37.123|-|0 +prepst#!#exec#!#Time|-|a|-|12:45:37.123|-|3 +prepst#!#exec#!#Time|-|a|-|12:45:37.12|-|2 +prepst#!#exec#!#Time|-|a|-|12:45:37.1|-|1 +prepst#!#exec#!#Time|-|a|-|12:45:37.1234|-|4 +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|6 +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|5 +prepst#!#exec#!#Time|-|a|-| + +select * from TestTime + +Drop table TestTime + +Create table TestTime(a time(4)) + +prepst#!# Insert into TestTime Values(@a) #!#Time|-|a|-|12:45:37.123|-|0 +prepst#!#exec#!#Time|-|a|-|12:45:37.123|-|3 +prepst#!#exec#!#Time|-|a|-|12:45:37.12|-|2 +prepst#!#exec#!#Time|-|a|-|12:45:37.1|-|1 +prepst#!#exec#!#Time|-|a|-|12:45:37.1234|-|4 +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|6 +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|5 +prepst#!#exec#!#Time|-|a|-| + +select * from TestTime + +Drop table TestTime + +Create table TestTime(a time(3)) + +prepst#!# Insert into TestTime Values(@a) #!#Time|-|a|-|12:45:37.123|-|0 +prepst#!#exec#!#Time|-|a|-|12:45:37.123|-|3 +prepst#!#exec#!#Time|-|a|-|12:45:37.12|-|2 +prepst#!#exec#!#Time|-|a|-|12:45:37.1|-|1 +prepst#!#exec#!#Time|-|a|-|12:45:37.1234|-|4 +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|6 +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|5 +prepst#!#exec#!#Time|-|a|-| + +select * from TestTime + +Drop table TestTime + +Create table TestTime(a time(2)) + +prepst#!# Insert into TestTime Values(@a) #!#Time|-|a|-|12:45:37.123|-|0 +prepst#!#exec#!#Time|-|a|-|12:45:37.123|-|3 +prepst#!#exec#!#Time|-|a|-|12:45:37.12|-|2 +prepst#!#exec#!#Time|-|a|-|12:45:37.1|-|1 +prepst#!#exec#!#Time|-|a|-|12:45:37.1234|-|4 +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|6 +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|5 +prepst#!#exec#!#Time|-|a|-| + +select * from TestTime + +Drop table TestTime + +Create table TestTime(a time(1)) + +prepst#!# Insert into TestTime Values(@a) #!#Time|-|a|-|12:45:37.123|-|0 +prepst#!#exec#!#Time|-|a|-|12:45:37.123|-|3 +prepst#!#exec#!#Time|-|a|-|12:45:37.12|-|2 +prepst#!#exec#!#Time|-|a|-|12:45:37.1|-|1 +prepst#!#exec#!#Time|-|a|-|12:45:37.1234|-|4 +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|6 +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|5 +prepst#!#exec#!#Time|-|a|-| + +select * from TestTime + +Drop table TestTime + +Create table TestTime(a time(0)) + +prepst#!# Insert into TestTime Values(@a) #!#Time|-|a|-|12:45:37.123|-|0 +prepst#!#exec#!#Time|-|a|-|12:45:37.123|-|3 +prepst#!#exec#!#Time|-|a|-|12:45:37.12|-|2 +prepst#!#exec#!#Time|-|a|-|12:45:37.1|-|1 +prepst#!#exec#!#Time|-|a|-|12:45:37.1234|-|4 +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|6 +prepst#!#exec#!#Time|-|a|-|12:45:37.123456|-|5 +prepst#!#exec#!#Time|-|a|-| + +select * from TestTime + +Drop table TestTime \ No newline at end of file diff --git a/contrib/test/python/input/datatypes/TestTinyInt.txt b/contrib/test/python/input/datatypes/TestTinyInt.txt new file mode 100644 index 00000000000..077492f45f4 --- /dev/null +++ b/contrib/test/python/input/datatypes/TestTinyInt.txt @@ -0,0 +1,24 @@ +CREATE TABLE TINYINT_dt (a TINYINT) +prepst#!# INSERT INTO TINYINT_dt(a) values(@a) #!#TINYINT|-|a|-|0 +prepst#!#exec#!#TINYINT|-|a|-|-10 +prepst#!#exec#!#TINYINT|-|a|-|100 +prepst#!#exec#!#TINYINT|-|a|-|002 +prepst#!#exec#!#TINYINT|-|a|-|029 +prepst#!#exec#!#TINYINT|-|a|-|004 +prepst#!#exec#!#TINYINT|-|a|-|87 +prepst#!#exec#!#TINYINT|-|a|-|0 +prepst#!#exec#!#TINYINT|-|a|-|255 +prepst#!#exec#!#TINYINT|-|a|-| +SELECT * FROM TINYINT_dt; +INSERT INTO TINYINT_dt(a) values(0) +INSERT INTO TINYINT_dt(a) values(120) +INSERT INTO TINYINT_dt(a) values(100) +INSERT INTO TINYINT_dt(a) values(004) +INSERT INTO TINYINT_dt(a) values(0) +INSERT INTO TINYINT_dt(a) values(002) +INSERT INTO TINYINT_dt(a) values(86) +INSERT INTO TINYINT_dt(a) values(1000) +INSERT INTO TINYINT_dt(a) values(255) +INSERT INTO TINYINT_dt(a) values(NULL) +SELECT * FROM TINYINT_dt; +DROP TABLE TINYINT_dt; \ No newline at end of file diff --git a/contrib/test/python/input/datatypes/TestUDD.txt b/contrib/test/python/input/datatypes/TestUDD.txt new file mode 100644 index 00000000000..7bc06cb5e13 --- /dev/null +++ b/contrib/test/python/input/datatypes/TestUDD.txt @@ -0,0 +1,78 @@ +CREATE TYPE udd_varchar from varchar(15); +CREATE TYPE udd_nvarchar from nvarchar(15); +CREATE TYPE udd_int from int; +CREATE TYPE udd_char from char(25); +CREATE TYPE udd_nchar from nchar(20) NOT NULL; +CREATE TYPE udd_datetime from datetime; +CREATE TYPE udd_numeric from numeric(4,1); + +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_unique_constraint', 'ignore'; +CREATE TABLE udd_dt (a udd_varchar UNIQUE, b udd_nvarchar, c udd_int PRIMARY KEY, d udd_char DEFAULT 'Whoops!', e udd_nchar, f udd_datetime, g udd_numeric CHECK (g >= 103.5)) + +INSERT INTO udd_dt VALUES ('Apple', N'red', 1, 'Delhi', N'Sad😞', '2000-12-13 12:58:23.123', 123.1); + +#passing a non unique value in column a +#throws error: duplicate key value violates unique constraint +INSERT INTO udd_dt VALUES ('Apple', N'blue', 2, 'Chennai', N'Neutral😐', '2006-11-11 22:47:23.128', 512.4); + +#passing a non unique value in column c +#throws error: duplicate key value violates unique constraint +INSERT INTO udd_dt VALUES ('Banana', N'green', 1, 'Bangalore', N'Crying😭', '2007-01-14 23:34:23.749', 908.7); + +#passing a NULL value in column c +#throws error: null value in column "c" violates not-null constraint +INSERT INTO udd_dt VALUES ('Guava', N'yellow', NULL, 'Mumbai', N'Smirk😏', '1907-05-09 11:14:13.749', 245.6); + +#passing no value for column d +INSERT INTO udd_dt(a, b, c, e, f, g) VALUES ('Orange', NULL, 3, N'Happy😀', '1900-02-28 23:59:59.989', 342.5); + +#passing a NULL value in column e +#throws error: domain udd_nchar does not allow null values +INSERT INTO udd_dt VALUES ('Kiwi', N'purple', 4, 'Kolkata', NULL, '1907-05-09 11:14:13.749', 874.0); + +#passing a value less than 103.5 in column g +#throws error: new row for relation "udd_dt" violates check constraint "udd_dt_g_check" +INSERT INTO udd_dt VALUES ('Grape', N'white', 5, 'Pune', N'Angry😠', '2000-02-28 23:59:59.989', 100.1); + +SELECT * FROM udd_dt; + +DROP TABLE udd_dt; + +CREATE TABLE udd_dt (a udd_varchar UNIQUE, b udd_nvarchar, c udd_int PRIMARY KEY, d udd_char DEFAULT 'Whoops!', e udd_nchar, f udd_datetime, g udd_numeric CHECK (g >= 103.5)) + +prepst#!#INSERT INTO udd_dt VALUES (@a, @b, @c, @d, @e, @f, @g)#!#varchar|-|a|-|Apple#!#nvarchar|-|b|-|red#!#int|-|c|-|1#!#char|-|d|-|Delhi#!#nchar|-|e|-|Sad😞#!#datetime|-|f|-|2000-12-13 12:58:23.123#!#numeric|-|g|-|123.1|-|4|-|1 + +#passing a non unique value in column a +#throws error: duplicate key value violates unique constraint +prepst#!#exec#!#varchar|-|a|-|Apple#!#nvarchar|-|b|-|blue#!#int|-|c|-|2#!#char|-|d|-|Chennai#!#nchar|-|e|-|Neutral😐#!#datetime|-|f|-|2006-11-11 22:47:23.128#!#numeric|-|g|-|512.4|-|4|-|1 + +#passing a non unique value in column c +#throws error: duplicate key value violates unique constraint +prepst#!#exec#!#varchar|-|a|-|Banana#!#nvarchar|-|b|-|green#!#int|-|c|-|1#!#char|-|d|-|Bangalore#!#nchar|-|e|-|Crying😭#!#datetime|-|f|-|2007-01-14 23:34:23.749#!#numeric|-|g|-|908.7|-|4|-|1 + +#passing a NULL value in column c +#throws error: null value in column "c" violates not-null constraint +prepst#!#exec#!#varchar|-|a|-|Guava#!#nvarchar|-|b|-|yellow#!#int|-|c|-|#!#char|-|d|-|Mumbai#!#nchar|-|e|-|Smirk😏'#!#datetime|-|f|-|1907-05-09 11:14:13.749#!#numeric|-|g|-|245.6|-|4|-|1 + +#passing a NULL value in column e +#throws error: domain udd_nchar does not allow null values +prepst#!#exec#!#varchar|-|a|-|Kiwi#!#nvarchar|-|b|-|purple#!#int|-|c|-|4#!#char|-|d|-|Kolkata#!#nchar|-|e|-|#!#datetime|-|f|-|1907-05-09 11:14:13.749#!#numeric|-|g|-|874.0|-|4|-|1 + +#passing a value less than 103.5 in column g +#throws error: new row for relation "udd_dt" violates check constraint "udd_dt_g_check" +prepst#!#exec#!#varchar|-|a|-|Grape#!#nvarchar|-|b|-|white#!#int|-|c|-|5#!#char|-|d|-|Pune#!#nchar|-|e|-|Angry😠#!#datetime|-|f|-|2000-02-28 23:59:59.989#!#numeric|-|g|-|100.1|-|4|-|1 + +#passing no value for column d +prepst#!#INSERT INTO udd_dt(a, b, c, e, f, g) VALUES (@a1, @b1, @c1, @e1, @f1, @g1)#!#varchar|-|a1|-|Orange#!#nvarchar|-|b1|-|#!#int|-|c1|-|5#!#nchar|-|e1|-|Happy😀#!#datetime|-|f1|-|1900-02-28 23:59:59.989#!#numeric|-|g1|-|342.5|-|4|-|1 + +SELECT * FROM udd_dt; + +DROP TABLE udd_dt; + +DROP TYPE udd_varchar +DROP TYPE udd_nvarchar +DROP TYPE udd_int +DROP TYPE udd_char +DROP TYPE udd_nchar +DROP TYPE udd_datetime +DROP TYPE udd_numeric \ No newline at end of file diff --git a/contrib/test/python/input/datatypes/TestUniqueIdentifier.txt b/contrib/test/python/input/datatypes/TestUniqueIdentifier.txt new file mode 100644 index 00000000000..b8a33fba24d --- /dev/null +++ b/contrib/test/python/input/datatypes/TestUniqueIdentifier.txt @@ -0,0 +1,34 @@ +CREATE TABLE uniqueidentifier_dt (a uniqueidentifier); + +INSERT INTO uniqueidentifier_dt VALUES ('51f178a6-53c7-472c-9be1-1c08942342d7') +INSERT INTO uniqueidentifier_dt VALUES ('dd8cb046-461d-411e-be40-d219252ce849') +INSERT INTO uniqueidentifier_dt VALUES ('b84ebcc9-c927-4cfe-b08e-dc7f25b5087c') +INSERT INTO uniqueidentifier_dt VALUES ('bab96bc8-60b9-40dd-b0de-c90a80f5739e') +INSERT INTO uniqueidentifier_dt VALUES ('d424fdef-1404-4bac-8289-c725b540f93d') +INSERT INTO uniqueidentifier_dt VALUES ('60aeaa5c-e272-4b17-bad0-c25710fd7a60') +INSERT INTO uniqueidentifier_dt VALUES ('253fb146-7e45-45ef-9d92-bbe14a8ad1b2') +INSERT INTO uniqueidentifier_dt VALUES ('dba2726c-2131-409f-aefa-5c8079571623') +INSERT INTO uniqueidentifier_dt VALUES ('b3400fa7-3a60-40ec-b40e-fc85a3eb262d') +INSERT INTO uniqueidentifier_dt VALUES ('851763b5-b068-42ae-88ec-764bfb0e5605') +INSERT INTO uniqueidentifier_dt VALUES (NULL) +SELECT * FROM uniqueidentifier_dt + +prepst#!#INSERT INTO uniqueidentifier_dt VALUES (@a)#!#uniqueidentifier|-|a|-|51f178a6-53c7-472c-9be1-1c08942342d7 +prepst#!#exec#!#uniqueidentifier|-|a|-|767392df-87d0-450d-9b24-85a86c02811d +prepst#!#exec#!#uniqueidentifier|-|a|-|9bcb5632-53c3-4695-b617-d9a7055813ce +prepst#!#exec#!#uniqueidentifier|-|a|-|ac81a140-f686-4259-9b90-dd46f10b355f +prepst#!#exec#!#uniqueidentifier|-|a|-|3d08372d-770c-48b9-9740-a667d036680e +prepst#!#exec#!#uniqueidentifier|-|a|-|518d52c7-4d79-4143-ab33-b3765689fdf4 +prepst#!#exec#!#uniqueidentifier|-|a|-|bc3fa456-7391-4060-b5d8-430048075cf4 +prepst#!#exec#!#uniqueidentifier|-|a|-|3b75b2dd-01b7-4958-9de7-f92410693547 +prepst#!#exec#!#uniqueidentifier|-|a|-|ce8af10a-2709-43b0-9e4e-a02753929d17 +prepst#!#exec#!#uniqueidentifier|-|a|-|5b7c2e8d-6d90-411d-8e19-9a81067e6f6c +prepst#!#exec#!#uniqueidentifier|-|a|-| +SELECT * FROM uniqueidentifier_dt; + +# to demonstrate the truncation of data when the value is too long +INSERT INTO uniqueidentifier_dt VALUES ('51f178a6-53c7-472c-9be1-1c08942342d7thisIsTooLong') +prepst#!#exec#!#uniqueidentifier|-|a|-|767392df-87d0-450d-9b24-85a86c02811dthisIsTooLong +SELECT * FROM uniqueidentifier_dt; + +DROP TABLE uniqueidentifier_dt; \ No newline at end of file diff --git a/contrib/test/python/input/datatypes/TestVarChar.txt b/contrib/test/python/input/datatypes/TestVarChar.txt new file mode 100644 index 00000000000..c5337b3aba6 --- /dev/null +++ b/contrib/test/python/input/datatypes/TestVarChar.txt @@ -0,0 +1,48 @@ +CREATE TABLE VARCHAR_dt (a VARCHAR(20), b NVARCHAR(24)) +prepst#!# INSERT INTO VARCHAR_dt(a, b) values(@a, @b) #!#VARCHAR|-|a|-|Dipesh#!#NVARCHAR|-|b|-|Dhameliya +prepst#!#exec#!#VARCHAR|-|a|-| Dipesh #!#NVARCHAR|-|b|-| Dhameliya +prepst#!#exec#!#VARCHAR|-|a|-| D#!#NVARCHAR|-|b|-| 🤣😃 +prepst#!#exec#!#VARCHAR|-|a|-| #!#NVARCHAR|-|b|-| +prepst#!#exec#!#VARCHAR|-|a|-|#!#NVARCHAR|-|b|-| +prepst#!#exec#!#VARCHAR|-|a|-|d#!#NVARCHAR|-|b|-|D +prepst#!#exec#!#VARCHAR|-|a|-|abcdefghijklmnopqrst#!#NVARCHAR|-|b|-|abcdefghijklmnopqrstuvwx +prepst#!#exec#!#VARCHAR|-|a|-|abcdefghijklmnopqrstu#!#NVARCHAR|-|b|-|abcdefghijklmnopqrstuvwxy +prepst#!#exec#!#VARCHAR|-|a|-| #!#NVARCHAR|-|b|-|😊😋😎😍😅😆 +prepst#!#exec#!#VARCHAR|-|a|-|#!#NVARCHAR|-|b|-| +SELECT * FROM VARCHAR_dt; +INSERT INTO VARCHAR_dt(a,b) values('Dipesh','Dhameliya') +INSERT INTO VARCHAR_dt(a,b) values(' Dipesh',' Dhameliya') +INSERT INTO VARCHAR_dt(a,b) values(' D',N' 🤣😃') +INSERT INTO VARCHAR_dt(a,b) values(' ',' ') +INSERT INTO VARCHAR_dt(a,b) values(' ',N'😊😋😎😍😅😆') +INSERT INTO VARCHAR_dt(a,b) values('','') +INSERT INTO VARCHAR_dt(a,b) values('d','D') +INSERT INTO VARCHAR_dt(a,b) values('abcdefghijklmnopqrst','abcdefghijklmnopqrstuvwx') +#INSERT INTO VARCHAR_dt(a,b) values('abcdefghijklmnopqrstu','abcdefghijklmnopqrstuvwxy') -- for this case, BABEL and SQL both will throw an error +INSERT INTO VARCHAR_dt(a,b) values(NULL,NULL) +SELECT * FROM VARCHAR_dt; +DROP TABLE VARCHAR_dt; + +CREATE TABLE VARCHAR_dt (a varchar(max), b nvarchar(max)); +INSERT INTO VARCHAR_dt values ('hello', N'hello😃'); + +#checking with string of length > 65535 +INSERT INTO VARCHAR_dt values ('5E3yMLSKs9f2gi7D5YnzWssgaxFjWPxx8aCS3F2rRGrtOX4AYNVGag0LuBXt5j8nEnxPVijkhpFY5OuPRSexMgZC83b8eVx1v0637CSetIMBFab7xz3bBKx41ELPBGSstz7kba5DajWRItW7Isk9QM7X0H4MNAIa49eR25U7qLUY7gm0j8sh5iKIvxW58bTVzMGM7Nz912oOQhgM5yMVEFbdnDKVqPNlnnBZJJVmzZ6u7RkHsoOwUDNprObG8ggQHsn0KLSg2YQZ8sDApFFvDJtDsNsisAYQWk07apBelFSRSUUsH1Dcj2jda06x6RWgaQO4137Ot9ysMn8zwnRjKY4JCB5l6Xq4olVZgzkoIat31B8d90HZJNr0ff0UMMRjF0bMvl32bsnGNwMG9bCKn3FhHCD6daOsZyjDUtk40Mui9DTsJeLmRoLkLLOnwL1L8EBeeR9G0TYPKawja0o8FMZCSmk5gJVbVTFzhfl72JDJikey4wJbrZUpMQZSkiw4O4QLVbR01AsdtxQmJVnl9BbMcj4KbhwPj00uALRY817aQTIfG3GyYfyJFuDNtVrynt4cMv1mu1p9qoM2u4fBo4bce1k5qATYbPKe0QPNfJm51ePbNTwZUOzRhJWBxHQz5Yc7u1YejKV3X0OON4gnVfamM5zVJWBgDVyUGm4Qlrux7KwjgkvK1gv9PiofjVX3BCFj8JrlFUYBms3OXQhhpbjUSftHrukQAeqXPbm9D68RR0DutD62WJuT7BOGaljWodv5LYfnSCwxZFNT65XQtuCzqgAL0n13wh0bl2yXNHe8JPMb8LxYn8Yua3KVs4pCEy7YrHwXmQjASOw9PVZwBtIGkfNYCW9ronmZS5v7blETt2XHbLDLSUqUSP7nhf32tMP8qnVM8zTy5XVz2zfyI9Jy58ctMWNlTW1uI9w9CCfCv8n22L7xZJq6WGfUebTIxsNi7PGiHGmCOLmuiYlLsEdBV4zFztmqtfRQwzNj8xLMx6uHpitRx2O3Pjctx5GaXdXJKtK2FNDxcxhnHoQruMBcM6dERui4dpYK0pLTXzSaash9DfaaOQDtyYxDuZoGwGpvVAwuEPHTn4b58Dg9Dh18DKhLOA0U6XDbgc14gT0V1kUlax1UMrtPdsesVUTM8TuHUVnUd5vBXO00mW9y6ILNDt6LafnZHVGLWt3QBKRMrPsyWJ3QiUy6PErrI3BRX8GC1UluMU1wpAKhcbYlG4ReTYhusIAjVATpWFMiQMI7MDg8MR24wGwUVmzlaJfl2E3puiWNRDAoLB5pAE7DJ7HISSfTZctDqXiJLt19BC5XVfDMkociSe28ypSQbYVsJNXRKQkCiYycptDKEUcKsI0q5YIThi7ED1ZZshRXe3gdkHixsRjsCroanaIfVh3BKdfIaVTCyECFrnlRc9Thg0svgajZ2UhDE5l90spJY3kRiP7vK5pJWDKo5CLEvRn232fnxqeGF6Ouh4X1sR4tBET9W5BUx3bT4NALnxzoZXHyNm41uQSwCxAWawLDE2nta8TxvbnFJFwccTV0T0SM6swBE2NigSWyZpALUnAh9wrFKl5s5npGv0IGOmeKyqgoMAf0b7OBaMqBATwB3675iFlMt3FkvetTbUuCLzHt9Vc3QJ5H7102kJVKy7vtPlU3kuNPItxUA9I85n3K62FDe0dGxleTWmztsw0jJPOKLluHOv9z4S916Ab0Qk6nR62KdOqtUlmj0L962n2Tg6yDo0bchTjjTSLnike0yDOLfcsFAuPafKpBludIs9rcloWaj9Yz2KeOefrOxbtEfC7rkkMXtyGJFZXO8KUg1m09xNUU2uVXQVyyGoRZMzxKEZHudfaeXxx9z9WvS20lwRwysuy0YnG0CMuQQuOydGtenSmdKhilD3m1VOIpkx8uPYswR2CC0Q4z9gA3RGiu2GPpU8nUAQw3QNzjepxXL1EDqiHk6505ya1obb9hzZ8RdAE1TkYSkOr96tU5AF44vURcYzbr14mhk9ccj8T17dNF8nlYMRvPXXU4uqfKXatQ2CTGM1s7drYhuEauUj4CE4c1zRscjQACspwvJG8BXugLrz8OFxlW7ghvWWs0GWC6r6N8E6gbQrnqp86YzIWLA1uEcOUHnAeqAv3vX3YS2BjXFgfWOHFhRjUHaAA9Lt8kC1l7Zo9NZILe4MNPyJ3qdpUxWvz1WqZ0JxxTLqpWoxQyyWWhPXSsZ4JNRxQ7SDbSThk9dheuri5APDtUdnTAUxuvixhAb8Hjy48CuFL504UWU40UWHLtCYqZlJADx3p7IPcoX4O9cDI9jdtO1dOQsHe3UB9JvyqTkAoiohH2K7KdpRdefJfSr5vt14QVdThnllrZWp7OQviutTouO9gXZWv1BmNVgprxbjJyBVcyKQYilIk1ejHqwWd41zq0fOkqkd6AwRMSb6htusEqzeGWBfhoJQRJ0UY2xa6GDmOgl8sOBhSFkeLY1cYfvFadVaOVoRNQtT1ekxpFQmXLYqcjKcKdOQB5FfRzzXJPBA8aFmiJh7PeZOhUFOGQH60tFBXYwLW2H6kyVh7ZZiLUdgAdN8uhU1OaH9mgPPEBSEhXCqRhj7TUJiZ90dJohv1FqWPTC9rc2yxPYrEsvmOAfA4f0wVVc1uny7jQ7K0At15uqkf0LjdX5TLDujz2MRPR8pZZh2G3eItksoixsyr4fgHTXH8RghRvDqRkTKzWWbjtl44c3PPYjRoKxZr48FgGXiMbsgMGuJqUCg7i4WS6zQlA3SDMUwAstISaZwsTO761RsvDAHHOfLY4z69xfajTTNEYprrkqh000Ce3CuJvL4890nGj9XtZBKWfqTMUe6D5FYUykJRFvKdLPbeWsGI4eQvZJuL22b6qJHhs6kkk7nItAnmiZtE1P5Q8020JupoxMdJHxFryvUKrxhaEduBS1qAIVhLgBgadwM6G2tSYwZZHRbPmKmPCWNIU3KEg3BO6TvoXFAWuieTr7C9GmZ2aW5FMOmNBjR0qDM135InITOsnPfPQodmUWlyklAmesWy2AA5S9sqmEXoIQbnsDNHPNhWC6rRaqxYzYfsW9TVWMFLKkYA5Rn7DaJkk7gA7LtPDyTHD5DbtJ2VyCPC1aTLUdpD1jIrksUw7XNgVkdZAlu31BHQVH8lQgHGrJYgRwhmxQMYEbaqhAwICRADGcSqBoFR6L83ZgpbRI3NVYzNndH0WKZ01txEwcNlurSJSICMkU363i15J1bMT7LCpRhgNqfaJCHygIXnCmHlKg81hgmVEFfeYQA2nslRFqz9o1fB09gjQgFug68taSbZxYAWZNz0pCiGEEdW1nyHkcy5dMzf8rAOQrZme49KBgdyDvVnbO9Dcj0ncfipvnUYaNMMtFBWHePJ1QK28lYTXEaHhFrzboEbfkUIgdv3dnv8MLo93I1PENotOcERvM9DGxkia36prCxwrwCJCCVHjzVuFQgjeWvBQskSkPv42t8bofztrOg6vmiYL6zpxXGlztwKnJmc0Cyl6bb8C6CvCYQuITcrBT0prPckU6EBTI4CDPur1MmgcJXeuH15CNbByWmGRZnA11OaY38mUqyuDbelDMUjrslu0GLT1ECC0QuPo91jkvsSpaCLglC3D8IqqN5rJu2IDv3DZyfpT0Q4hoNCPnhvtJC9wbgxq4irSqd183o5dvWrHdQHDrvB8Knku2zLlceG6ygCOdKQ0mzNGzmPRuO790R0YjsCiEx5CDWI2QbeunE5t9XZFH0jlpsYxqYS8FEBvI2KjYsOYThJptgSRm4SiwQvx9Zb7w3IMkxIlaXay568rGiZ67l8JRsSkGDFrjFXVbMtbdMzEDLENr9nah60PXs6iuP2iLBM5nNVhxkRGXOhsSEOZtDbyTMffG7TcyiA8qtTTHspG2gLtncI3OsdrRLNy6VDGv2ARdbZkbs4F3Ta3hF8c9p5HbkbU59xiTJ5yFtpfzpjd4zKjZ6HtZvyRahNzpNAfcEE4mLTcdsjjB5VbrWwu0HOuLZBaAY8wGJwUYnFi18L8CxzyOmvekMbxWpuk9939m8qO55rqFmkPicjxJkhq6efpCWMBKVBHJHfCSYtXUsZNcmNJqgxhDfk2vTgEWiIAT9s8WwbMnC5gczGHtoemnXtNSCrACM4Ijd4qRIVGbDTH4GszZdQBUdzBSVELFZoi9kkl12dB6eUk7QMy5TTVXxu3BpGj4g2VmgATbEVm2SSpuYs5vouAibF0rF0aSWXtTEZaU14OEGYl8jtdOBWmfuV4JGDYdsG3YfJ44v2AqMQqmuKxFpwkXo0OABqi5wPyQbdiLqSNDuDdxcR7wNNa5drZCMAEOqodPTvILUVhOpdNHrp4hsZv3I0TOscqC49tZO2dvkVDJBdV3ZF0RiS4lrBm9Qxuv3jlO33W8OJobiKs3FzzPYBBKgtJFAAWddpJmGlgSemZEC18Fdj7RkH8sWWaY8szjigArZpAHLkXTyx4z4fcX9nkdZF6BXRLnjFV0Ok6EZtUu7tw8ezXWqT5eP6QtRAMBMOVcUNxyKH3ouUml7se57QpYoxfskteizphJTL1lPklI5biicfa9IOg9QYBF0FrYXgHt7j4LCybGx5Ac5kQSzSCnOZzZvESTsegMZ6xe1HIXfxHDYGMSqwFdrcS4djZimiz4CTu3BBQTLo5RxotYCx6eJGL4WDsYMkbvbdYDW2uG8OkLCADT0Q9ky5J04P7gyJjK0nMQodOlLsspQRr6TQEPog6ftyQxmf4gstEkhXEHKydeSbjTHyZRqnn56TLfeiePKuUYCQGhYt4qmWR6JPCHoKaZsDj6tIQRyUTovV0VW3P5WGqf4wMcSM9HvB28xR9DBW7sCgpDbZwawfyli2xMn9GMk4kFOqHMeSIt8KXvppTwsbBCGiJf7O15TVJOZVqtGp2qH7pnnQSNpEoKBumvQ65qNznvSHReNGlB18M5QU4312i3efeTul0NJKXHluCn9M70N9O0W6PtsthW9HD4ANLFcl9yZnsJjwuojcGoaNc9jjfj0TeQcYZvqWX4GE2RBPp5x1YEMU0koSOxDPVMSYFF74fOeY4JLSw6UccpNOEQSKZm5eg6pRlOLjrigZdZHgBeWHCfiTEJjj75AAB2Z9Sqx8yvYvfuycbDfaY66pZY59ihACOhEYwOd0MHgmqnNvYhCN7fojDWVtq2qyqDVU9xDeTQYZ3Djml07N1BeJrjmZm9Rh19C6pFuqDd7qbEOF8jiwJ3ipsPBoO0QwDTHZ3Yum2jIEk2hDR8iRahLyI3BXcDAYQ3hhjBhbpQccRSZCCxOaf3hgwRr20nx6cYKVvz7oYupKV3uToUx5bOm2NNwUZNhVkPMjGmDsPGLbdorUBlofiDow1Moa5a9KKaCo9Zce6G46s758geE8rCATwrFcb0oMg1g0slrORHpRLkYkTSCvpbl76CmCCtJugFcUlK8s6GN06lLhAxzh9Yox5NxwBpR48ctcBk2zdgXxydJeoHVMYT5QCTNyKygxtNfoU4mnjAQ6GDVmRLCEK4j7ToWGuGTrZmU4qbG3shvAvmNCffSX8qNHKq8yNIvVcj8g8njlq6RyMJyb2zB1XSp5thihvy2vMhYmcpKmsyb0XStGGa60Oa2uXfOKsDpSL2SAVC3AlSKj5xwiFlkYaYtA89250ugvfV0idCtGVq8YLaoSFSE1sd07ZIcLAFSDNLRGxLz3hRTLaiZrZ3IbroKgxrsCQNCK7WD6siLKp9CZJKgCH1UXBYwVH375N8IwpUctm2KO6yfCTbYBp1U60peUQmYKiSMMR3lt6tly81L2m5u5PfRMUDXgm0fCCXitxwmBdo0RSd0rDE3kDrsaUFaDOSqJojEhKIfre3GkPKS6Hm9Gmm2cWqByUUbfOcw6mtR40jCaH4WBe9nAiO7kpuP6U6YWP7LBpTeQ09YekwxRe99Upb7YaEjGcLEG4HtBtT8yN3HxJYaeqLAWh04JOE8sthbFi2YpeDfZ7baBOYyOghV5OASLsGi2l2L3gMVZeJKrBQOw7tsm9E6grhU1Pmc9uK3KApl0yOsoEXpZsUpucX0GKZvT7ibmyBzuh9CoGN4YI26KjLY3TeeePTfB7C9lLvi5cQ96Ksep4AOKE6mJBc5jGPm7W9VaoRUmGBhGa1d7kND0Z8Z0wFBGNzUxIMzSO3bNqFT9qlywwYc4f57Yo8NTXSNmeIuyrRvjGI1utGZtVs24srEMc6eCIDmW2bi3a94stKouhpu5IZvXUBDe1Oqqcq9MyJt7CyVbcrlVyGjElzoj1SDldPI37rooXXzZFpzuInM3oDYvdzisBGDK7htrT5cMMuRtkeSYcKW8RJ0vHgJzPDZXSqJvMW1DVoUawY0AzRgkuFAKQuqDhOjtBYltTlwLw1zqvX7It9pWHdmn7km0J55fXgw4OK5pZGCCFdNmdgtRUjLuRd2PBHkd9AOHF3MWFCToUJDAEWyClu6HPp8K8K693RynIlDc1HtqwAxqWmbkaGmyJOj4mAx1QA9ZDpMuX8672SOYxxNUUehbcLMk6G6dvn2eXxc9hWmUAXCyA4RmD21iDb9vpXHQRWFlkxiPMH9uwi3xNf4xhAe10qB3eP03NggzGmOEMZbK07g2dkWfUdXa3LVL2WWAds3vLaiMT1AgT0PXbKW0uM1F9dzOlnXq8ULafhOLyMoEP4oXimbNlF7se4e1ICNaftuzF486tq3FPGppQCZkhKhRwUzGxWnAZseWZSdYhH1w4Umjq4tT7ASgHSmBUNrZp1sn4vx5Cm4oVqIqkLeDphr1olertf9ReK1TJJpWXymBrqiQikqj3Ly7VbUhTbX6mUAU3vT2HGJEazQ1qDUgUVB0zjKG6DMDCaWB3G3rqAW9DY2hVxDNQOqXBXBnhCOIPWTz1nqS12AlYbABTNbH2ClYC8GExTxGTkry0ptpekpID2E5KhftkhXMkvRjVuuX8nftEjbETUGn0EZkRXWxe0ypkuh1wlrj7yp08ldxM8xHMYr4l2CASvBtkpxtMUAuG6nYoZieH7ZzjMwGIv4UdSimONCg42Em2Fp81FrMv5RA1wZSkN7areTRf9V2aeRyiPEJAvZb6Hiho0q5Vec2T2nh2XaMi4ZUtXXY7BBxjK8tu3cNmMHdwCunroHq1KtTv6BAqhTEZ6gTaIFSKiDbfaqYDYZ0VqFjVDKWzsJzRnV2ybbUBUHdaxrq1gNlV7Zk8KLWMmLCQwVtLgWitpD1M73n2d2HgytbpPF94tE1S21rOWGCtYAi5jTNXJb0ixm4jjoJl8V6mkWsi4OhLnt7dqYVL2YhTdRus5ljZ2vvzmxPs8rI8nS9oRCUKHdlK2JIzdRHwtsXjieioSRfL3gxgdnQDTvBti86B5e8RxuIFrNwByMrkl4m7x9ezW8yUAVn1w7aMyRNLW5xNVG9wR8bOEIoVZ6Rjy36EPtW2TWq4HCy0SNTS4nqjPHcs9RlE10lvqWaIfniQQ281nuFTDoyIPcrooSEjjWoKo5DZgsXIhzo1IvPUg4xyW1BqAEtN28TES50yoCnJoupExF5nKXuYlZ1bO4EAd9cik547unM9rKC3fgLZDbMgG8Puvign9J4hmF4zrZ63tc6y9obyz5gJDb5ilTbXsy8qJljaADvEh8SpxQEuejSxtm1HJoodEuO5ypGKUvxblJ91wyXmQfXHHdlu6fdZMfLrlyQOgRuvJeQagcMhDjUbzvylehuzO7KWhi46E84eezuOHAgrxBWgJ3Yo31iTHElezDsrlMtLP3PHUYtbaNgPwmQBWjlllL7lxs56Vjh7PrV1jRI0APn2uja8s0JJ8yGdNkXD2tbBu9FkhI9nEzQtenqCvFVjLU036W96w5jkAaJg0LvXYPorud3zkaauaVWJtn1iexwvoH4QuIu17TkLOjZKpAEyKtGzsbIfblArZpf0ipQ9KT9zNbfgLKxluARfWSm7xIuGHkiypwBwbf8u3s5HpHgRWKLg3RAK1IudnIoFTm7vE1GWpBQQXX3GcbA4kz2CNsC391zRSdepY3W6RqQTvAMry7KI8hNd7yWA7Yqd5NIX8ocqrqfkgYsG7hlJRY2jSMU1TngYStTLogZb7Arj1Arn4gUc8cgpE4iPlk8S031iLd74vXKgecAeve32zqUbMwY9Hg7FtksruC71CZYW0qF5YLP52RbXqDakmqyEFO9DRunWLMTZfd5Y1Oa0aJCAIJy7xXyPxTWdiJ0KXI92kG4ODIyzC7Fs8zQJPkJ4IZMVGkXXfW4qwMDPJB2KqO14Uz2uO563GWhUwO37FajqpyD5JmypzGIeDtk1MKzSRv0FOELi9a1NjsfXVOh9iABqIqizmOrb6n3pJLIQEdqbp1IMoie8pHYm2cLdvi20FgTpQvj1erPhqJNuFqFEN3WRXn3OH5ZGDsLaHqVhFeyAoH7cMIjDQzBJ87p6a0ArI1RqsfDZWG2nuW1wPwxRo2OB4veCPRA7crhgwY2rt89proY2s7Vd98tHEfM3b1txIR5TEVPL87EuTcg3aTlTJyVpllgOErMuiJriG2kwJW1t4rYTCKJMoRfwGSdyHXMiDKNSEywNAPmnr0As8P93Hz26UmtZzkeSkKthLG9oX8hRvrNc6CHbjlLRepymoTn40d7eKhywaPO8cLR9zxX9MYH9V7sQ4KwJQ6zMC5BpixRIRfDDMpAnmb1UhptmKeET37msT3pDe9w21N5cD4menLEm7kl97wFJnSbNZQmT3O5R06ypOAUivmzJReqexc5YaXauJEqBAaWCqzUKR2432mS2ZZz1IXXuMws5C4wUKR8WOoCdnE9r1Im7Wb3rfgbZZERbHTOb7fJqXon8lEneXLPIxAOb5RFEZw9L4NwfcumUjGYYRcvNegMNQLpFdJsUUyCX7bZNNxrFPhULnNBkocrEtMclzBWnJ4reHYsv8HIsB3AbYDWfSLxq7DyuTlk00uumsoX8k8cSKuvs4qOMzJYHmRZGputDzyqWj0SOR0psVObWFJhuYJcNeuWCTvOBt57kjbS7MBpyMuFEPKtp5UCMyAPRvlXKR5L6QxztoH6xx6lf8heKC7MK3MkD2OczXm8XL7lBBVJC3AgJ2fs6AHaafgVDsiGRb119sIXf3rjgZLBzVInquAhwqsEFQtAEDO0XOdT9kNycZWstTyCvCZ6cSvrJTK1uqoS3dqgHDyYjaAkaCofAYvtKIfUkpnAgxdHxMHhTGcFdILRiu2JRXGQujsddcIpw8nZEMavw1rB50yFENg2nqtyD9GYKZ4IkdaW8b6kxuirIlS9jksg1WLTPim3BrcMaxIpoqT1uzD8klHUCzXSh7OjUpj4GdLam2SWQTL6sOuicUqpeYmKG9hVSRcOl3YZAy5uPYB62MAmOhkhRsWnqDj7XQVPuJBxMePG28wqMffUzV2rUy9WRSokxC0QY2V1fHcWN6D85xFnP8cyvs0J6npg1L33fPtgD8Mmb19Ku5PtcrExmAAyyYtufC5vCyJVggneDLWjbFptDX51FOnhbhka3wJY0F9KhfeUC4rzGhZVqMLxgPB6CS7FzFwasec7PdtivSsCTpcbqIAISw6h0mjWHZmFtPIxgoJch3YVWdgpngWyVnkUaqKikzx0y2hZtgiOGHqokDZReFiGJGKZLnN0SkZcJKZC6O2u9twIJ8rdGhfsOQjsw8nPPIm7XGOVe26Pe537TazRNjovUQVAud78NppdFKm9T8CodeoscRbH26b1SiS01oDEQnEjdeTJYZUZSRM1t5lbQY7ZCKY2KpsEZTLcZr31CY6VCOr9Q9if4zvwsyf7K9BywidKAEq7dt0HyMgV484zTsurELSxBH0xymY8Y4CK9SfP7b86siTDLEijOABO9qiJa7JFgBZwbnW8ybl3IAEk5DxBoNfRf8Yf3We3PTjGiF5AWkOVaK7Cdc1QB62mxL0Tj7JzlpgEMn8dweO3NegQxBo1BwusM9f4rcvJB0iFun3JsnzQHvg1pLqTijx3vyWeraciOmQZfAqSXEihc2Nv5xRx6nDZiwLlwqUMnGYnvUwkMco5UPjJ81Gyzfp8imTI7yFClEqkRvXn4hsrRMO8EGxWkKCCCyFdas9IPu1ddQL3myW3oIlmwa0a50kdd1A2ORrqAeOjoJ7wYS2Orrm5xZkYoxLRCM6ySOcy2gi3Yv1UH8Ee5ZfXVgqxvWxfqh2CGBW4IYvUpWuFgPJchrdUJebpuu29q7xAEopSL4gRCOujyozS6UMWVHmbCvNq0VTaS4fufo6P9MP3IAMFf4PNWyRg7vP6Hd5NghcstkBFECHB4v7MMDiRuI6XdP8l4fVLbXXgLtYSDZEG1vp4mpXo51yCstXw1Mgit1eBI7o4M2Za289Y9zuf6pihQXTLNev90bZLuRyQVFFo24MVFsJHz9rT8o3LmuJayHbXvuwsBSycA9c2tGpYUU275FnhqRZkqHEdmImDyHwgNgl09JrxQFtzhyrRC3DDUvVglJDpLXX0Gie6qcl0yofpIJDHnb2UWHygVYan3TJoBbEnxiaJAHagmS6bFR2PqGNeQ8Ssz1ZchV2MevP6yDjZMo05SAGTMeexevU1ZXdiLRDrjXl8GJxh0kN3c7llIHBpeQq1US66bQTrjC0LPxC8RuWHIGvaWAxEiMzr4WeqO55IurKecfgzJoLZJbzrbz3wl16kBpjaXG4JQ1xjNYfYS7Mv7JK11QBvHxp5NU4glJQmREyo2PBUXCOMi5JtilSnZlJNpEjd1HGwfyLQgD611Sh9sLUwFaHog6FhRNEkujMBiwW9huKIwadCes1VsJBqOgb8oxFVhPVHjc6OckDgf5tKHhUUcIAjSkY5K72xAnAtAITNSwBM0P9zx84qsTu4dKJBvhwiUOrARF3aLhgjODPjwdzrMeEkY6kGS4AGWXCn0Qrrqn42dlbH9pJqUTaN6sKvF9mcCULPJZV3EPxyQ1wFeb5tlg2OTcYDPhMUjq4p5CRquekSWrkMG3rrHSmv4gnjNj8bF4dAOmuZRsBLzAjW4bNfYrUOjwfnMKMbnatuCGo7gLEMf7iJAIrSmFFuA0oanV1CZnGxpujSsMEwrABFNjKSV12NWGAcWPdoRj8iVeGrZOCHNAyWyPRVVGxSy7cQYdcXwooo8NvRSVICgRoeUuj0IWA5qDK95rdREoH89FO0CzPXHf5JgIuOdnBwRF4MFiIJcJJWUe52HhM7b9LLJFhumQGZaQZU2jGfON9dRzKLUYi8jXFtAR8llRwImYuIAjPSmL4QDTV5daMDbo1RB4cJJOat2pepq8TePA74pi4QsQo8OLPWL5IIsyWtZM2jgskftmoDn4iUVxA7IcHmvmWpLCXsh4CbUDIuj3ylQt0GslrB9BWydCsfg6YL7gKz0x8lfem5ieBF6c21nQeSocclP8GI8yVWqjzxGcagp0mdtjgMCSvDiCsx2z7p7w4U1p5PjiF95LKn0zMvDlqknc8gEFJ7FVIM9gQBye8tthUP81wzO7DJGR4CrT2WI0aGaE2CK6Qyx3ZJ2PVNp814CATp4xn7jzCHs3rvyDVSBsmC9PgJq8CZNVwI1xiJlK95poWmJSLWJ09kv4zN8heGTTRNUqVmrH2Bk5lnCdzP75iG5nJatK75utZscJrhAgvGpDpXWFAO65Kki8wSU39GHPqO7ueFMblj2bATM4ztwHRgfLNI469HB9hodHm6OhT5hti34Cd3Zguw5vjEnGComiLRqrWmjFFrCluPz5KodcNi5z0ldjCyqzOkYegJQtKabdXNG7zTqnwOtauzPFvYHAT9JhMJgpXXSoQyvSZYwiPUQyV1xsrUGiVsTKN7L0oBCga8XyqAoJeSJlPaXIcJwMzGNd1GobWg5Eeuobhu26er8wwZdHh1h6s1H38KnV8tRvVym3R58Xirjqpef3idxOYl966ec6OSdIGn5jwSEoEZr5UzRdcRJBPvJr0vTAncLWKVlhDIcxghQEJ2EKfij4OP3D2PoyqnRW263at0fKGgHYPJirnCmXOyyMwj4LFuJgH2tteJjNgO1hHNdjYHdDQJKMpzZBBsVcY9GQ1OwoPEg7rl2VaRitTnxhhpMxZWNRIzHL3Da9R3XXg4azaweDdwX2c9ULvSTiDYD3CR9SJ5OEVz5WlS0bPWEDdhP9iq4HPMzr5crkTlRMTVO0xrVwcMZx28QLJpseFr3Lb9tDN2P1cAbB0PclKxq3nOR3t0FLnRSkzCDXUo7U8Lyg0U2oPclQzymBVOvfOO1nvU3f6LdwNdxFhFMPCKUPU1Mf1cINYmJigDtqF2YbiFZXgYe7XTDxm3sDpS3DHGRVfoBEBM5KXbiUtqD5QvfIoPA9ocUhDYPlUTUJKrBUtoA2vREhPFY8GprO137EcxeLo3gZHDTLwONJWUjIwEqaa54SZEoQBr0dWN5LZ88xbmtVojDfjFnfVBS0BGdVLnlCkyrGgLqDnPdpyVmmQK3FTaExtZj3gfLHDNauKWWUQGpKUzqYbwQqQcRPekI8spswMdblVSrfvyfvmHOVULdmSeTKzwSCdhNVzZAgNvCSjft5ctjfLps4xkpNMKzh3uE1RAjW5coTDznofHxGiNFvUHa7lyNa9diFPdKHgJdBfLFGzRkisL4jGJpE56VCpG8nImLTTmOjWxHiifoNRV7mHURveXfMwjydIurqol8rn1a2PX2aR4VNB6kbQc7Zepdsj1iZJ8KbgGUkurnar7gtaVlQLEHaDPGhMkAjGh9uY0zMlrLTE380ATAKdK39mLorzH5woSTBmoGFyUCLkT9qWKt62l7yiQo2sFriCP1dGvzCUnYIan3dHkQXuKCm0Hv4PZsmRm9ofmV5AayMpajuIPrjT9Ow1wCqk6a9VtpmIhcL8ub3GmrMHDRvpOJqYQJxpUE10IVIra2Yi3D60Co94Yuj4SPw8BPKoh8esmdxZaz06IUy55jBR5WXA7CdQK3JXYguvRW1TCo8CDtvTCNUzGr19OPpFzU0CSlmOgmb1j9z6bSPdbab5soflPK4YFFwZf7nALuEak7lLyaJ471Js13vepnjq26lCfp78hfmfhq2EuoIRhM8m4TnrIcXiAGinjzaQWRxkIGN1juF12iDdBbRwdV4xrogM4TcK9ZwoUyQe7bcIMgAVoe5TpU0PNWVr1ju6dSmmqWVX2qz3XIxDlRqxrkmkU5QZIq3DgrtLfsfXWgPoAr5HAP0HK7SxqHps4Wxgoj9ob8Dw5U1O6mcpr8IUxrpO7vdi1OyyRPFTlIjCZ3dAsxZoEnFOp4b4GhKcMDFDxOggXiR4psIGhKDEvlvuTa23DaxLhSX1iCsgwCIOvNqK99Pf0Wgns6bR3Nlx3Z2OMEyGIrKGyHfcY8MZVn5txMzAYcqjV10HdJnlwzRsktRIJS5RuazhR8Kerq9M2iSIhMTO14wnafg6HjG8JfpawCU8w4u5G0E990AREBGXMSkcjb3JCB3IFYkZ0Z8z5jQB9td0qhHGdKSG7W0QMFd0ILovm2VE9HLGQEhqQ09Fun3KE33w55wn2taQUxhgSoQWewXGFZRQ1qwsZWsqQnTbxihK7NW8vZxsIA7VuM1KZAp2hhnEGx4XYW2p4p2IbMiSq3J4yL4BfFOoAQN4lsz0e9JE1kH4B5M40D2ZpDwBf1V499gv0FUdOeCVaxnaCPpJgXH98Y7g3Y5ugww84u3O77O3ppypHdCrIA097vwEQDGGot1s3zWYCmDce7GmQP5QkR3nDbe0lNK7E1IUjhWcKlzi4r4Eq04ggbn2C51vcO1fgIMx26mC8C51SyK1NCgFaWxBzEHtaoa622zQEA8t9xwXQPDyFajCwT2eEQf7kIvd7241xt46ofOCve8S14kmOVqAz2NWUq0l7UvirgwhEeBiuK9Tb7I3s9v4PAApDos7opGK9lurweeu7JP8zQr1seqmiS06JTCLPQgdi9cl5pplRz4GwhvGOTQZwOjv3zNQ59sqKBB1tVTaizgnvKetQSjSyhg05n4VBsOt0qJYR9jMYwDWRMTilCQJTtIOWDakDayCsoprr3Pf1oBs1WfHVsGFAJhuQaCqQhRGB6kmlHHTLQQhEQah1gNBk45dNzjU91RfTECkqPjO4HX8jhmSKSnQNdTNHg7bncE17QAKEJOSmcPgAR122nDyeDz50cjRXWpKzIKZX1WZtu79slIZinSDDmRSYMDaePx4f0CIoMntBgxwvHEE9zCp7zaC3LwVkzOqRTWVSuDtGG9CgqrZJe5rEeltv6dKNR6v51OSYXUDwPN6ZNysmrOxrB4LGcGFbRb0RpE0XKCJRomOZuLEqdqxKPlARSSg0TeATqEiCAcqX0Ni0RgXlgBQkebPSYaMjOYsfdMxsXWnSadEjFsYydotfzACyFEKte59PnO2BAMRntAFuATZCP6Vwf0Iv6GdpW00rwJFglM6Gb8z8qSIxOxnc2ypb5btzsBpzhNgPiJVI9VKyPlLSjpruGPprf3hdQM4olxQJc69YsrlvxWq2GHR9uN9DwN008Ow0T4K29tCE0QH4QEoPceQu4atJnAwS19Tg8In9a9LRTJXkIoNk9PYGGpNRCms0R8RQspmgKELIU3s6aa83rmFgGwj6TaFrfXbdaeRwpoLpvagg2k3RzzZnOkmtlkwLlo43jovZp4r0VOQn69eC3RdJoNeGChni1Crey1x0FPpVpoS5PbgL8x2cJ1tdaqmZMSMaAIfMf76C5tvn6B9WilZL11uVm999mUMcLk0MpeuvmMu0NNdf5T2kkw9jH2LtFGlhEZRpLXvgvpZ55rEsl6QMAIgxpuWGvlihIJMG7IN4RW9cWYnzlbCqZbRF6AQfyvveqzh8vfYK12dgK7Eg3lsSYCfTLeWdAwuvJe9u21WU0YcwKUxtaiVBLBHSA5NCfNYtjymvW51Dr8MRqBvvTWyLm1UeLKcOMVlqVCDLzfujgeisebYu3apfFgyGllxwHmB1yo6LtvcIQbHAUusxuzlKA4hWCujIeQIvfs9n8VovmUjWKAEabh7zB07rJsdh7sL6NCVIREjszPn5AkyvlljtRmtNikzJUgfjTkrAwrLkcp0eKD81ZQkD6vIayI07eGz0UIhENw0tfpmQXdzCcytCyw1oocrD5k3MqAAbu9MN3RGSdmFNTppeflGJ6VVqTG8Bg2Lq7fVwPOjHkPcF9EoBfU1xJWSV0c1arE4ZmtLw4CKU6AoocmHq1zycYEKBcykdLb0GwDOtTFvtaLkWDT9XlDk64P8j2k1gXJUEhBXDgZs7qjRjrpio379hURaeyK05m5VO3tcaca1kotstKZLILl5VDQCpUO9yF4OdpIRMyGhlKnt0Vqmhh55A6eyZEgTVlcjOYJ5m9YmUillyMaMMU7FThzFtSRIEzQwdAYT6e72ubmjpteeSQYdG5I8mnZ3jiYCo2byVhB8ewEV9Jr1WS1TSDh6zN6EaI0smaTq7R8FzjidRbzqtJcODrRvk4bbUC0LKELAVhjIqXghOZoNU40o0AzqcEzHf1mOd1FtZADecNoRMRhL61tD7StOrvqGcKSrRlPDsfFV6PNuaPVMUhFOA4DBkNcyvov3DHJH9oRjD4OBkQ7pnCZzfEGM7b9pVh2GqcUCI47XcpZO7T1jmv5hn07u13uE6Kx3bX91vtEOa0AH96l8G5ygNDW3oduPnYWlKNEK0LVtSFg0dnMDc4U4lZK0C73aB45e5ed110MnCqVNH2PDJR9P7be4c5BEO1yMztYFU6I2rP2ZxqUvTZstYrECjqhZWRpxMGEaxwR35FF2BY33bUy9dBgc4CnxZhPFQJus9gipRaU8T8d6JgHQyo3103Fj3qzrxUmfhVeUjuaqjwZ3CWDMfgwuqzrvYbnMT9RdFsDP6PUvdlwsUZfGKkDZ5YTTuBbJrhLeiDN0Ug6i9VGUGL5zwWLttTV0BHTGzmecHvN4ZPW3jD7eJLP4lEx6koNQNZXmnQDCKeies9Tf1OmOG9ulicLBJouDr0LGu7q9KoGcpJTxwoeHcoBGZ97PWmHzmRsx8vaWPWeceCsLM2VS6g2bTrmJinV9mU0jkXbcvhusKFZhSp20r49FKtLoD5Lx0Z0oYTvj4fhGO8zR4UkXkd5ZkA44ohOFOpNi1zZbwoCMgOMpFKL5uV1md9E6fRum2gbklJweya1bCjIqXaX028UYNakMHIAS3HFqFVQ4uDkTXnyEby7D11zegU8xdBYhd958KevZhvKunmKEYRcebnzn0rCyg4w8BzXR1qCzSLIZiPoMMJIptaELfdvPvM7FltBy34nb9RUXfoRyVGZfFbmCXuUx1mRE9KJjFPj97KBacYAn34ih4tCQYe3nxgB6XktxSs0xe489kyfHeSE0aUbDO2my4Ibj1tVdtQYGEpDlkJMsSsP2mToiMUwoP2T93lTgP3MovNO5zKwIzsSsbnGnOviyLQE7ERJVjQl5IwahlZ7bM4kXgmA17wWfB3rdE904AH56Z6K0RDa4uGzZpGIWHCzFBN6ZMTkKYqKFNWGTVqs6b5Cl0nGwnbCzW8ZmkyqDaCJkbBBea8o1WBfMg3xIXydWsC5pUZL0OxisrlMOPwvjMdox8f44mDlGaSEXTcXEZ6h3Gg1CkQmExyt8u7Ny70wQaWfplU0xH4VdVpAZ7D88gTkpAr2EADwD3Ooc787YvUJVKKiVpimq33HVNt3Mnf5Lmid9q2X0u3THbuw2MeRyCI3mmFRLyanz6GJrs0AS5NlZK82nQMTOJNdyC2XYPXo4ZwB86arUtnuqZQIrAkJHCtrJXYHxculjX4rYn8jhdLYyC79R4vqzrR5lufPCj1RKxr5rfa4e6L3lZhoq95btuYRiBLWfvfWVOjANoz2bZLn57e8KdSu593dC9eRcJMyyMM6Z2U497vombSdCBcb30m3yMlAKvtbCTZ4SXDh77K8bfj1zFTy4FocBHG5QgihrQQsTeiDzKS1Nk2fZIkBZM6YsTr0nSoi5OkSS0AzYlNnYGZsT5Rzf5Yy4b2C3ekrfGijVv9TblEO4WXnElKex6MZZu9QcO2p6iKFIs6b8MwuLcXG0tdLsO95dTow4FBYBZk5QUeNAjpHZtQLkWwAjr1n4VEQIjy2xPLqsZFRwaSMNlJnHFujA4XYSzBzzOq4mHtmTau1M7FHew82ZtX7PNmSM2r1iWA92bGpz5GnJt8ca0CBpX3GXz2XJfA6NJmKyOM1kma92WJMKLEpAEKHL8iGNJ8kY7H7mTXfqb7ZCEvhNVlKel8tPsw2DeoZrklSS3J4F1csM8Y7koaLEIhJoVCRVH2ZKs6qIPYqKmu6uPykxejg10EEBI4nCkgSslu4Pofl2jpEMEp8klnKEVjbnwQzLM8uWptU4ZmLvyC3BY5hbBDwjgWKcD5ulDudAgk5kJZrbMqLEij0zRCS7faTIZ3ENCZvorrZBT76mtKHIrSxQ5r0RbIstdfULJxK4CFY0yciQy2bR1yCGwYJPhc9gu4jVcMFmsBmWzj1sHLTaTsmI4g4KiTgVMzXAeQgTrQD5A6S8M35g9vF2yYnNv7Zcw3J5fldrSrbOaZsaDqfDmtV0Et3sVSHmJYBJ9GrUnqReTM1PCERK0lRLREYcPuAhLVFr8BBJd4cRcwvVKE6CwWGjmzCEUuuBrH9toyBERoXWJrmTVet08SWeTfjoXqk85X3k8xXk1uiWDYNTOBOQZrtjIC8LzycdRgJfQQbd1H5HhtBlI3HPPJgSf26exawf2k466pebvzhC6SAlDMySdG0D0zso1ug0SYpvZUPshbsKM2qpbFrRGVnYXtHHkjilCRm5sCM25bDIndKieSUwncPeQ7HZgZS1YYBKwL7iTth44ddTioqczH36LhLZgG7Du2oGF1fES6meCS1QzHylrspzIcjBgW3QoPjN2jjRvGbK7YKBXmWbGobL4RU5xrSjEekbQnzV6K6B3pUuUQiORtcZcE3FvBe9YCCsceJgcqQ1JFChSpM0BodQWm6z6xQux6tm6ip7pXnO6zbBLkq12S6y15arjFt4Flsj27OkGELDrt709cekDEfN5E7RxplZRyGFZDP5JN2fEJCxZalcCXs9SThfxXZjTYd6QTC6dFBFo7dWvND5Y10QEiWpElz5v9uGCfvEGNoKjVKNUo9m1xKvu6OvXmXYckOSEOj7MuF8YchL2nSRqVShaF3p3iW8COXY0UohLHEfJ0rzMN8vl7oelLAvIzoxARrO0xI59UyQnB92Y3SBufZjH1GJuJ0fBCLfX8MVQ268rdR524Sv8yY9wyGboi7Ex8OES55QC7lwK6tTCBbkssdxEYwSfadDyAwFCwRMDllzZPUD8MMb7Z4tcz2QswYG6jD5j1C9vGgBfU06ekKvepNT6LOb5gGBJ8onaYjp4CBJXncvUkCxmIzR9jZatyMTTK0KzNtmqyxeQAF4wX6dIfdG7YUaN6Cks3nX42ulx4JkR1HrYEsBmxd8yMgJagKOGeGs8y28qjDaHluICsge4YRHQvWA2regBq0fr9Mqx6j3NoUyKvpLTdU4KOxW7ru82YZDrZgjPAMttkeyckZdU7D9a7UyCGEcaTibziwVX0OdA943UA5x22M8TWIlG0HFllZG0A99XeSOIHovbYohfZN2EJjBiXjXUTotxYxzYhpMkc0cfdm4ABAdvxMIxGwqH0Xm50CxXA1EUZo2Nt1som0V4igH159RzXIwEGenM5NXtaymytUOSwgrFZlS4iyooDvswcTRFdRbGL3mUiazGpu1Irlxvd7NbU9G6bnEukoR8wFaw1VtfPqzhjzUNgad47RpyPDDPHdeCjkFzb8nXTwLmZuUl8HcDNNo4xLQSuIkz5nfdiYSprzOf0v6tZgyIxD3JoBLVFBk62E8ULPHWHMZ8ksFk7C7RuFq5veCLvLLMshnsTZsmZZ1aNPtEgj0aW7URlwJTmPuSPRMhv5MNepsUp9LgKPD58zbHapfxvDUJDf5t0u6kY838gNcWd3Ygdc5p9932AsRIpZb0UEg3QE9p9xojVdg3MSgqU6mDEX5ubxC9wefYXEqS6dmKbDloQYYCtU06GExKWE6jmceeI2IRmUfeTMpCHNGHG0Dww1GWzTtOyEYhI55vAfdu9d3rAVackUlTFvbBHW21cgvi3jBePYd9Wk5gNTyeN6NnopED07l8sR3pG2Nsq2IoAb1bU4vB6gkeYfQzPVmUtE0fRiivrEoUyRYTd8iP2XzI8YKNMUMz5OySETgrpK2U5NoiUb7f46K9um4EcAXqX2yvsE0wDvZQw9BDOAjHTXX1L7HrOUOnSwF7V2RuIP1TIbrFHC5ft7qs1xqpM5Nwy1jpse6Dzm3DVyl6a1CKTCDMCWyx5nCR8NXICylBom8Tt6d8wpMuXEJp2CnMQwFskFF39xiqg3WB1NdH4psU1i1B5r2x3viPqGIBdhhsI7A2YecJHqJgWG92g7EnWoSc7mH7haFLXv7Cf0CGFEr7OT9uXm5vBzHFOW1GNr4IYQC6yDsaNWhjEwxeHDOAO1GWT05RLL89XeukIDwoE1w5Jwbq7u0P2V9NFmdJ3MODlvBJzOQRyDOCpU4TOqPkD3wOX4jGDoSphdJkZXircJsjW72iR2SupVkMkAGZriyXYivyY1E9INV1TfphE2WDssdjzgA0rif0PAEICQ5tHjFRO02VQip8dyhw33HMypP7zC5hbEIC9zhQduVZuhSXuK69A8DzKjgOQ8D4cKFMi98B4bAV48CnjIh1t9PiPmHxt9gEDPr03Pbhfl4tRFFNUuA4TUyAadEohyDEg3jaCKSaemyX3HiQFHt251NM4y5TepkI8s4iyBmDejdHD52XeiZfS8KNLMKuk3yhzGmcl4OsXoXbv19n3DIUYVQw4WK92M4vYKxQvDemh3xnjlS1voMEWT2UfgCo29SLvFpgfcvVShpiKAm8uCf1eraUA29TDPV7ptFYBHoA0007U9uluT2NkxT9YqB7sKeoTy7WEwvlCOwqiiKzqnY1UdWGjFnxI2EJtHvUMibnoI7OGqLNUDN00RTe1jC3GmbDwUoOOp7YyJkGzcU2vmPUlBRakQgco1QcjBmUDIrxuqBuO2FB2WE8LPNty0FEJJgS2KysBwkpqMmDfOHSvVGDhGR52XXNk3F0vxEr5P1x8lBhfDjksEo1S6Qv5h86bj2PHMHL2s0eZlNUDU57cuY1GspHr5tDZWmpjXIHJeKhLKuWAj855ywte9MNxvl34lNmVwcDNv8DUe0jbPVbDRzIfV0Cjpg8aOcTIdBYFHWYMiurMxUpcsnO05IOWu5msv0ngy36axRVlOwa2Nwnwls04LHNU1BVjPOZ0BfPsMSEebqclDoAPeniSkpmoI1Vnx6T6j5TEGuYtb3FBGtPrrkaTzPAXrJiCLg6Ns1mdpGCS4vbSfx5zijijzMGni3zcCAqeU0AN0eyXD2OKa1B7T5Q9La7Syv6mv7slG5zL2aDIsbW6TI2FiAOulg4XIOQxYroMXpnHnzJNcg70n4lMcEMsjhgiOavBPsXmrfchIE4JnhE7PKmQLBgkJz1l07ZGN1sFcwaIUYJOTbHu7GVKZsaqCtMujQvd3BEjU1JZtidQXUzAQdLU9AHogiFNh1R0nlDUQjQ48itKSw4k5skgmQfXEAhoYSmkII7C3kuxLeCHSQLgm5SOw0vGZAsVi8vGHEIdLexwUDXbFimpsyEJVstzdPz5vp6kadk7Uvuujmvbyav45K8HBUyg6wUafxlPPAIHV7LWQC5zz0wMRdpb9j0BXfo6ShMi74vtjP0qPYmupwdiwPIxi0qxJt1qSjsEt42nAXtknGZ8nhWSQDQ9IQlxwb8tJzUM7jcwUL7E15NOyW9PXo6evLFxX9i1Nvr1nNEZBQ8vXsMxbDY8cqBWijEnFFUVikOlGfGOUET6ZzRnJkbEea4JcuGsAYj7rDXBBshAss49tDaIJnsgJLyhsY926oUaSRia9IFxnm1MznJ4EQLGvmqKvGnDeBamBIFzsn61xIk81px3rmL5cF36I2KbZDS8vhBTSSlFhI2rgWaoeeOwGKmffQMnpIvdLTuaMNoFxOxpq1MHCFp0v91WjrdLVOZVBGlZzIf7JR42YIOE1veQchE7cBwAFNvyVySBGV3hhQHr78NlnuCouMyq0Z4PDvrpK7OXxypX9r6iDaW9BudFrKllbxJD7VGbOtlcg5GN9USkfMOms8jmVa2IUV06KHwaDzpbsyfN5Nv6MTyUYtUQ61eowIRzB10BAEY6BfhqOSkdyOX1jUOqM4zpluuijsW8EykyGNneXMq2V0qnc35V5YuXMZAj1FOUJAXEemPFznrH21KrBG3HKxFgNx3sHWZ5ZT7RzYC9rEOduJJAcRSxzm9gmmILYinI1i6CgqGJWtq3P28sYG4oJk1Mwdjp8GMUVVsFTxIt2Oj0jJnGUkV5Lf6ohtcuiVM1cMrNzvUfLOXXTQFRm6BvXIrme6RXrK7J8tdFXPdDYBuCUFol6owkGvxEZ0YbblG5RLoyNO3Tg1oy4ppzVSKRan9ai5b5JMdLEE3L9LT4hQVkm5N5fmQfrVPvb7kiZiqRfiW6cynDvVhNJyl0ugGLL3KvMvMWFqCBJcuwhYyEpsdwBRQxTH1u4jaqk532pdavnAX4m0Vk7n6aZ6fbPpnrY7oCmDcrnw1Z9q03M4HG91shVXjkswtMWPQRtklSDDTX1ZFonr7koYIepTXDoXtg17fJhaT6QMbuNzoChAENZIwg7QoqM6FwuDBNNE8p1GXK6IldAwfC8lIaHOBlWbVf3LB1kcfwwfJ7Hxh2hxqV1M9VflP8FtNgAbPfjgx4XTw4EGLG3PqI1ufF8QNfFWzbqUmdZGYI4ieb7TJinnd3agRF9Iiv6MH3VUnrdAbTFbjhRmd9acMQowfScgqQnKdDYPNkkH5TsREkKE81MPaGUULHtCcAr4HwGijYBsGFmjUT86frIbGZzwLPObgP4oRZDgehF5ICmnS7ILMIOqwVrXbNBABd8rtE4FfBKPLbqwpydbcv1rXsMkDPurBlYlIa9upavdhHax5dF32xExeDtwfoq5XdMi4IN655gWFYWABbU8ElpE2W9vvhXPahhj2tcudCdyC9usFOJgT111iaKJg68htvj8YI67UgT1CTcGwEYRF2ILXmowMhQ6F1ynJrbPQozQIxrwj4uhl9mc8x7sUh5nfjBajvoGm5fpdadTvEWA70F3EIUmmKkCEgjkAxplkH3cBln0URXJiWLjcDIVHtqKL8QFMIa5lpgTdvcqpTqj4VC8JjNQXlVMl3iN7HH3vZkSdyUfD6Q2xS7FIYFwxMJDxjU1r9rIxszoTHUE7qThDjjPmaw8mD5lEySFYMfQ3DiMX9aYQkzfMuHSgF1TKYEpINWliPussuyigaTNB4QRCcRtkGDIKHUcQAFOHLIhBQZoCv6IfBrTTP73zD2tzSBGAZSk9hpB3qVQQktFdI3lvInPfR1CBBeilGFbC6ECl2A6Y9OP46pdh9s9bz6QsjGatRca6KuRie3tc48dzbw4NqhM1cfZxUrRBVdfX0WeP47UrbIOtmdu2MPpozT1ptWG9epuLdwNmEeL1l01JHxj2NbaFwQdS3iut8J01cumgFrDNOPWiAxaq2XgvsHBcr340DFvxE1FdtqNn15jgVMVQBhqlJ2F5AAKbvmdSoYiUyZOhBjDU85g5hLcSNJa0qBDBTQl1oT1jevs5lcA6GUSYHe7ThRUrugotg5Gc5IqPQiPsOgI77MFTXvCX9jF3HrLaaKFR48lsCHbGOLZVaTxHCDXLqzEsu66zVFZC6ouH0SHyU04Bq5JTrAru5VvzCHO87rpGqmTOoNnlxykMu7zHxCHHnW8M95vXvouCWNHWwfhBuLwpMnXfl0ckbectc1Dnve13bosseW4qWSGqoOnjG3uIL61QCXKsMcEO6XerCzeavox7VTaPmoxtYwR3W1fpApdZCIigDDT7gviDsoYqAzsm6m4ShfHKt10CuQh6Z8EjuhxNAJTfG4vb1rh9h9tOkUlhg8DSGc7eOVTPuGa6eACPFVqgjZh3C1pn5sJjBda6psj3SaL8eEbyglH3EqsI3ocZaZiyiKa1GoNmNqVGlQcbDaxs9Idos6wDQAnp6WHvryUbJkEa8sdG2GChr4E2X7uAKrdDuBx0dExT4Us5kfk8tDUKLXW8tl2CamYG8hkPV7emHuTZQADuQ1SAqRG62VDnvIkZEjzyPmiRw73sfUc9t7OJwD5qJrZfQemG5x8ulfk0jGtG8VDEhS6A1qFU7ImAsObgldRBo0oKSZ9b5nQvCoBQHy2ZKlr5WFit8qHaWYhHjMiRnLP0aBdf1pwWcMWUVL4sQHofMQqAwgQ29ycmvkwORwOqQ1xavOlFTUwKPOKyBqN4sWPb99UisqQuauGwDqYh7z89UpzS9QmPl11DQyWDNno7w8NYL5HP8bYefL472AhjMTIDLc4jlD9xMGJLJrzkJzG5rBMiOUYy2IYHakyIFBMDmgHTNSB3ExhCSuryvvPc2yoODmZm6kCCsI06q4PgtB7PQScoV0l3F4j6ZsLzACH3QgrwBDD9JsKEH0Vbp5ibo9tfvBXFeGq6Nn1LvCXjyeV1Q6p3Tg8RdhvyThZU79IQ32r27HBm1H2ahI4yLoMbPQ4lE1NoMbNBG3CR6hrsOmrnmMW5vrscnqRMOthk6lyOEWYl1XTSvZVaK4jAj7gDA7biJnBYpt0GByVXwtjI6SYwe48RGERi77ACy4SjQLOQYisxMx1Xo7IX4nYieIBW9xSOVHuHcrO1JGNeG4rfxSBCEiY2bVQOZdEkl0k3ZR4HWSiJtzJruvxAaXsZtx5Mh6cLnlWFKZzl9o4kyy1FnJJp3evxOTC6cL2J7lsf1e7pzNVhP6bmeKGcy1prR4NWrC6e5Kr7FLwOEKXAlU1naMEM3avk0F6ie2fRMNXoIeiFZhJdvcfJVIfTmbsFpXsSMwIQscCu711vJaHRkfkv5iJvRLybgfb0K28G5bWaZUfMEIdFrraaCcCyDp1NXVj9nSbzNjciAJAlkIqzIwtjYuFeNppyiN5qOxO8av87BCQPUA6CcVkXzYPphnqbzaF9oXUxaN21LYff0ixTQbQVlojR7NYXnRGPihDbutRTdbFvaqq0b7AvRqhvQR7uQqS6yYI5mM9lwaGjePhC2RauDEVqM9bFsxjeRkOQqkKliQaqwGUfxz9KFapGU6UAKBj8W25VMDtVMx1dQ3zphqECnOIQpuzauKqwbkU1E0wOsQj3tyHO9L9uNmdizWSly2t1R7iHT6tm4QiHVkU9eq3xSTL1B5HK6EcLuCP4VjbQ0BlrkHQiTWblUrA7epZ3AB201fKDezWn2VJRLTMUvqSiDA4Z3xzIMPFUUWMPijWZDlk6vselniaBZZvVL11YI2TNFKvlt7hB5cn1Ieevh2R8Wju7RC0TvBRNXSKFP9A61qABXpHpej6Zp2NxIfF3fqty0wIMZgYMq1E8qNrBDapLeIWtCYrLIiPyVNRMz5e5t2OZ5S2AY945rCgz4V0C4Vh5oE4sReepeYzc2IVGWkdRaE9t3vLcV3qExHkuTxb4ePwOQfm1gYNH3MpDGrX5YLwfXaEPb3Klx0L9rLF1lSvMx1KXbZKoNsDFecFE4YtdhKOO7jr3YJ8084p93s3PSG0QrUbMELAykFIuSF6HataxQ5hdgingLxPzgoAyVb2fvUo2it0i6AMcDILEI8ZQmEsqCbxV97u5SRV1saxdqTdH1AHet3TNKZQk2aRWCkYKDEa6gZdA5dlZmbICcZnkbqbikfrghvattLjAiuGIWEdA5gn0b08ztGTOLqWaqRqw7ED4Mh6Oa2gnG16h9dIq881O6IMVBbo0Z3FHYO2U27T8DcH3wtXeiyROugKAK8uRn5TJ8ADImNe2UcjAoaB7QwVAa6ML9cOoE5jbyCIaTm9EZI7k8NjNCDBStgbZn6jb2bu1xoLUAxmhjuSioBa703QoMFgY8e7WfFCwVmC3QX8gGs75BC5YWaUDtSFpw8jDovPq2PJwkejYozRnNSuzA5JaLyB6dhxejTTM5q8DuWjCNdtSbIAVeVAHdJLUbORfxBEI03y7b7dFRBtTc5oCv8jFrV07G7Fca8WkhyTPaPkshhVLc1UNrOJJ4VuDa2VhrM9zwfdFkQVNt5KQ2Pra26CL2KUDK8ShHEN1FD3g8hcLIEUOXXWEShkoVHL6oTtOwJgWwr7uC1uc1O0xUMBSJzB2jUhPQNu7bVEPV1O5z8MvhQsWAfJJag3ZEdr7ZLFQnx71u7kkKeYCARoTYARD1ZnrpDsrRyqWvsWpechtGdDSx9dOurkpUsVmArEaAYpn267kVukfKjYbmoFqtZA2xNInMzgYmdvWj3iutDhgzoIlYeM9cVlZwPOIwnt5hOII1w28JOu245jRs6iU293hLa5fJWmInzffwcusButnPqV6aR7NCK9Fr2WAAz7g8OyjFRKnXNSHFe9l59yEG2t20fxsVKuyQTJer71rTZExxEf9UkeLxA5fIpAFpCVKkmLEWN81R56jZarRlK6qubQLDwL1ZCp9J60X3YyT12dEo7DscilNc3hRZl1K8KqKaqkXo4KSdmVUThCuJ7KSsld0FOGKZGsgxb1Yp0MawZ6FXqf7KNwdNPvlfvWGUJ6JJyJ25Bay4Cq4nyrwq0MUFH9XXy2kO6Np0xR2Zd7PHZuf4VamHXI8BXbe5gOXrPcTOQIhPdrqkOfZvNh8Df0nIR4tzmWij9oSD4wJgpWgqYEfm1x8wynoTJn0W6Z3yofnJtJJV70EFo5p44M5xCtnlqtqStdzIFlbFZtOXfmHkEi2ELTNK5Q5wPTZDx6vUPFmFjGwDZjgtg5BveTKpsRIHcngfExl0mIAy5jaobA24EZOKrGT4O6VZDKaKVazfl1GnFKuawnHqXC3JnxyRnBD7k1K7Vf1ocn1ndV8wR9gXQoSvGtBihRs6dwsaua5nPcaA5ve0IHXkzKDV5ZH1DOe6ciQXuoDTdX7VJmi0LHFkEmtOJXR3GwFai0HGgfvZV95SHT2WEU6K0qpF8mmmoeFv8qsHWX2gLA8AEgYiZWXZen5cHNrCJQSEc1DMW913Q2TCzruXCg6P15OWui84F4mcYQaEH5cTnqEId9GhwgshkIR8CUdIjXxRsDYrAkwVqswJ9aqmbKRFYp4NFj1HAV1683OrDSrriuuOImg4oWMVJuoimWY26ubJwRhmurqaBmF5ivBScVYvCHHrwgQT5ykOTbLUff5hvsOeOLxAHKoAt83lF4I2q4w3xoverW93wy0WeJHZgV96W4LNUzyi3jEmfDBqzHqn6aEoAE1cmha9xv5eZ79dqym2g442xScTVKTwnD6cxvg1XnqPgbeRwpa5EUyqby7KSNmRFOIZNhJYLr6b4haw4dbcmaGogJR3MhHnRzse7cNm3TZ7EOn2Wvpgb3BipZYUAyTP2INPAtpHy9lDxpb7e3vlJN4niH046tenZ0FCYJLmqYOWPcJmZPtEgEsBZ5FHWDxeRaUG9GZvrQFHMomrzHBZXWwq4xHO8KmFtPSoa5yQOrskHszx3Lt8myB9qLWjjJcsf7ZEoZ6E7EmWbT5BMsLymmer4CD5YlRTjUvlzWeDTFLm33MIxUpmeE4QWW2Hs3M5VUCgkrrkjC9xh9YObcb0qNHHOjWTwJvuNw3qudesXtH2ZmWbzaILxKFon6BIugbshSFgbICZx7vGqQRU7KK6R6FlAReXgh3xlq4dqPEzjRqaJwMcnpiurkTJF8h3AaU7grFpL9jXSeHQiLTY53EeushAgM7BjolW0HVjyUGXoucNLP5D9gZTuzurhbXt4YXyNgcKZ9sfRxkqPzQZvQvvFy8d1Zp8ANTKe3jjq5a5THmwjKoltwxV830s17vVr3E6TQSFHxVZAZcI76yT8Qc4OKB07hz1HAH4yVTov3EvAsE0AIYnMuajTgMcJrrbv369rjMxr2CUUxCZhxoM7BuZgBga1JxOqtmGIsB5vRLScTMoisTst5h0M72CAqdp9dzLF2W97gMN8fd6jls1b6JnZuF4PqjSm8eZ7jzwz4fB5IkCxeClunWgZEyKY7hoZQdW4rEatGpEVNZmhrwowSOpj9YcOa0gfsJcyfVgFWQXcL7HP1cogDlqQhe3VjqeDlFQjCYganheOelQSeXVyngbE2VLT1Qt5XaYiILceEn7j8pI1opa8oULAIJkHWURNTe0up2iGjHqjO6yyQnf10b84D72rK9UgG7I5PPu9vWB6SOczbEowjGPRxrXsJLH1gWAOO4zh3RcHBWFJY7DzSePs0u2uHSxnOUqZTuFjN3Qld831eESyZLENVelXJJAIvvsuRBTsWBp72pypzO20Iqr1FcM2HoZAN7nOS4OGDI1KnNQU3WBlYRFYwunmwYhYfx9JikQhAJurV0tcx1B5DSjc1uGXgBT5WsEsVr6A8VggPoW7tPyTXTmUy37LXrUXmrcsjijsCaqWuTBFvy42L1NRqXl3GMzWYQorZuOXLZMjNpxszpy0rYF9iaannH0ibKEJl5i9y0ARlsFmg3utJTiHxjiw4sstqV4ePvkL7AoV5ZZxdrkIwY9yfp02x0svtoIFmuHkIHOTS2avxQcDmfH6vor7bpPVRd0xmAtCykfUYk2CaKY0FVmqyUxEkTCOJXVonK500ebMV1xX3dluy09KWsJ2wK8urttGyFqxTAlBPDfcbq5GjTiYqgpt6j5j8IVjZ75NcyMVTh0KkOsEgWUIvAFxQoGzT4VKI3ntz0NyWHROryI0IhvQOF0RQ2cWynfAM8MVivm7rKcqXEvvG0v2r9oTPs1a0HDxV8h1C0EBAdKkmfdzXuv9W5ge3o3o2Csj1WBvnhtzNaCh5k5pMTVEOLLIKAhEGBlBPCvdvcMOQPtYDyJhmqPz5vMdrc15TrqKLSGN8UCIKck2wbpZ8uqSj4eI6oKE6B1Ozp44Z0J1rR5bby5ATDl3eQB1LgJV2Ig1kzC3TvmCjY99Rd9RVDQoJTqdSm2rtX51QbJqDBkBJnLnk10qSg7ztCzDaMe9xSHFrFSf351olC8gxz0p6N7T96ES3YmxjaaAlHcyaT5nxlnyT2jJ1DenpU5Dt9xpzHaA1nBrx6JNYv2bJxFYs5ApSFWVHOikTVFvTPSSi2YlsbyPkUkeskt5rjoKPhYt1RkW9HiyY0YfBpyqWWVeSCElc13GhDWkZ9tNWym7MxMgU8ZK71CLAvfJSZnX2DuPTFNAiOvuQgwovISugcZNMtfx0Ek7YPRDTCHKXaCm9KDjW9Tk2scQOFtQiFEWX8WdL5UmQs9NME9EhUtvCMpPtpGqb1uyaO0V1Zb6HcDOVbBW7BCi1G9qyOoqMsIm9r2YHlOmGB7GXUkfyNelLh1LkaybaDMyAdW1B02PMp6lNSQh8kFPOyx2BmgT5B46A0VuxPnQvnHREojxWyDjh8KRZQ4H1HuRVyI5JuTv92gDWRgJyP9ztWnqgQ68weVzrjIDjMOIKOOYZ5LNqfbvNreZo8SI5P3GD1mN4bpc9HWqtLdi7WOAy72Ys6P96YrmhKaNcUUzdtFLR5Otfw7Z242XxSJORvsJBy9IBf8dJwOYHYeic0kcsMgEjSdJrc7fj7u9Ef2v1mey3wJDbKEzVXaTyIsNllFNcX0w6WBGmJpzGeolCFx1deoXiu1rkXsBOXC3NboiNxso9y8C9TlDFOIcnafZdTBxLFGv6KbRwW80LU7ewaMuGKFKIEq0CAIeGWXlWmlNZP3H7lzk2pQgaHVIRIdElGdgNtktOEU3WJSuR52JKs8HUsStGiFS7cVNSACCphw6XW19mIYZb0O4bZI9wR1F5CIkeIKpnW8q5XLkSQ8q36VuZHaObbeL0j7OrYQMAUEHHQKvql8XdwMhr1IayjsEZ7tjBIpzNSRWtW8qFiCugcMVGm4EVW0J4tzLvsBHYYgUAbWRP1SyK0cy0WqbKGZl4BUbL0AtXBkxdsIdpcME9Q2SCh29bOewkvQYXiU1uZ2zZtlziwRVYObtbItkqLinKCI0TIJaGb0ime5jhCfZWaScXrOHYXFNRLEbMuYCewDPgXTLGVQyGoUMV21Gks2aOpSeWW37d3v11OMFgTicREMKgrnPs446VtUf3Abd96SkgZUF2RNZKXC8DckakhESHFNMKZbWbmqa6q0FY4oU6UruOmHfmFRBVBBi7EbCuIXOwbJC3tfPdPaMavqKyOpFfy1gixgcutG4Sg0mYy299rQ5ABiOdbHbefSSiPe1Ii3alZcGFdl63QuQslSrf5ol93daJYlSTM8asRRlX1qQVei2hNgFRoRsU0hov2qvRYJC324DPFToECPjkOmuTv3TcHkb38Ugrb8QXt3LnynrKw5FpclXbCbw0MFWDIdwEoEYbMMGUfKT5FM2vsdnnCEYeu8vTVZa0y7C4anStMQIbX24V8sorBuFlF73yZyQuiVaIdSJDx27yoDtjDeFRSs3eSa8wYemJhE8JUogrJfCiI6ECktop9fBQS4mdY53by4MkI9IpTZfvR7L72PTW2nelmBeAzion3lTbBYHfsBh6htdTKVRDdFiRHvIl3DF8zuh4Zy9Ay1v2kTzuD1KbcX2EWaC6vNXiaVYA2DRpIFZhfLVh8WJlVRB7465PluxKFs39cwItGDjJEw09Gzi9WRD8ayWzqstFyQX1hPyGcaW9UWiIQ39JhpVhpTVyMHPGCyikJDM33AKePjrvH4RBQYb98ZWW3xwYiSyez23fphrMP1RvaIp0xYT3IFi00iLxFnHI4Ezyk3G0Tws8xbB3Q4bgbGMgv3C1MbAbkQFjnOGVtXu7FPPnwFVBCUKSlfSLwGEdAqH957B4g8Frs8go7uF8xe8Flw9mu71WNsrrpOv7ZiX8bgOIYKMQVZs5hwu9baz4pB1hMN5iWaCl8xGN5VPiY1X4pU0TMQBF5AZBESnLD3JtMoakdMOSVug7pqRguMwoDxLmPvmLkEak9LWNm6k6h2xKSRkDgYCVna8cMYEmFZKXPgfOXwszVBCFT2P0ACxU7xrNZvduu7RzlmO0FnXb26cyjzMyxTDIDxUHcLkAztcoEBZpaReM7PBm1F6EDH5391jTyiOUwGAzPPI3QR8cdaHh34YwZQYKzD2I3wFWjZNvHQex5YyXrlT1hWeRJSIr9l3DACbxBOWDvqhTfHE1knkzB5DOCL1YLuKYpu9dbc9he3Mz3RcOl8k3iZk6aLwsrAgakRl6TODgCBl2Q7sGfZFFa9nfGp0SjEjwIV6b6RUn3t8a4dMBKHseaHjgGlvVnx42XQMmgOfuEFOzBk4NnhHYm6MSVF92x7Yn56nfIopQxzPXH1TEsE5PppHjkZWCOLRetQYQElo6fDYZdOdCuCTQD3BG0v3IWeOYW21Q18X08XATrvhzvemDibjgIYDkQHMR45ZtD0Wl1IV7Cf4Fw8Fo8HWB4qM2srbdLTz9gBHMESJwUmI3viHuZeJYebuRdRFkCA3HUlv7qfqqohiJfOfRv7jyrTBlVMBbZlvNdjd1utjaCfV3IF6HuN3M7GOne0QGAQlJ5VEJb1FoiJZot1xPUBPIokKvikqfctuwkisikHIoYP4vbuGBJHFEjGvJ8LLv7mZos1bW2kqskqhrpOsz9u04sYVM7vKJq9wnBc6KyLDOqmEG2pu14FCHwiBeA5sAlShSaUQHh0cLsrQBeITaWRgX5Ey5wnvA5HEjVtex2VghmrmFBHLMOp7CD6YprLAaKr2etdmSsTDPoDciGNEDmR5zZJB9x5GBhSslurY3YenpMzPRzvyypq7n3vIzOLPhTG2xxABsaqtB1b1tamBvDNzFdq5tTgSBZ6Z3qkSFRtYAnSNCqxqwnNnuOEY814Bym1TUyQVspDimpr8trCVer9Yy5T2SWoMLfNo6k1m1XkFD1wStKiD5VnpZuiyBVTp21rpiASANJxBp859G3nGJZk9cx9qTYsEEfD61E2wo8c7XAyq1hRWhyCuMxo0Ppi5R8ZaLy0muFZkxqcGp2wU3HFWKQ13y1LLwmefIEg1O1GC7TYph5UMRezr1QKRxwU9CIm5gY9cNG9zqzKClNgJrPAvBkMTiVmDX4K5PcYZPavQqK6CWTK4ahr0RCvnpAAhzzBI8GqoJumkJsKntuidMhmjqrzxa3RzclycI4Gk6LGvHZrBKNQGN7iwgNCWeMYVUpmDrn0MJ9Jhhdo9SDbnqA8EBtuWEXpfPvnKP41ecgrkmCBaWSnnhhKMQJx4PfH2f6aBqFcrn7Vvam4umY8aaGnYJ6zbFadIoQLmWDOu4brbb7Q8hWCmAanGcTTDmLLMu0Se8a8toL56dKraUy9ZVXJ7xzDa6Sntp1FmahTSNBr8aCiBBqR35cLIEjTwz5uPpo98HGDKT0Valt6UrRCclHV2ngqesV8fGsqYnM3mnmw6uiNTzVlr5TgTirk58ECObOrLCJmI6MT0bHchOr0Y3WSrNZDnrVnee7DyuNI7JuI5zoIMKErjkaFzzJls7U1Ph9bl1OzpFrCq4yG8fVfHiHOo48O6QaFaNrOI4sc9e2gLuTfAjCkVLhqYMFiwer9WHrGHU9pSPuWcIOGLRNX1U0rrKGFLQ9Tr7EolTNTm9yPswTuh3ZDtRETZHkYLoi6riEc4L8pDKPQykqt19VyrATQM9NxhWENxZwCrYc3EL4PsDp2MMdK0pSZ2ZImDLJE4T4hz4UouQGwEnAE6FTaPfbHowFPvzrIsHnLbQUaRC8jDmJy03k8GgHODhhgCiKy0vVVq5JLYS7474IF4JNixQkIpUrAad6B3ppa3TXEhKI4Q2MLQXFsZ8zUuYqnc6qSf4eiCbx21YXvhfLFMzs2cwKEcCRRUzpYNLB5D4R7Lc9liyyWAuh6ieQizCBeMpPDPV7wJZk89OIah9jM2PSUvVOMDZzUjo9uTxld70jmt4FvQGOi1lGRvRMPn48eeiVCLlSyF52ksayYttiY6rJRcKf3V6lEXoqUN4lj7WvZZwqlW1NVWdgEs36ZERnLGOAB3t1WVa8kjQiuyv2VNUnDZspyDBJ0ccCDE6fjSDtZcllJZK8a3PufjNIjmrBu1nw9XJuvbv0NSpFZNez5EYui4Kz84MUdmxyeOJKI8lFbOOcJjTRkd4exauEaAF6kP0wFJaOQ17iwBZTtb3Q2HgLGSTSZUtqvc6mfm6QFx1LbJNHEH20zlYc881sPcw2XOUIc53IPTobcUggCkDTcRZNrkjcyDXPzcgSrMBDXtUBAENYsxgzAPCScVlz8C3hPoGos88r7LTBsxBe49n5rzjOcgTOqTUOMWbyh3mGNduoL1J9xDZoYf3ULPkPGeD3VfbtWQFtRKZqcl0aQR2yqHhHT4cTXCfLqjENTinnpP6mkTuplvpOy8hB7YLiSwIhRmrXpnrr3SzKBmDREfuxLOKdyDMIuaHevDo5oUeyW931mPguizNJqo7RAL770vhDVjRxlOcVmL2p4oSV3uTNdBQOYhKt6qW3VYNUPNGbdeQyLuquPsqVpP8QkYUYp7h0m6O6IH8hBS6yFuhIE3ahbTWizUj8QAZgS8Ubn336AL2fbynWSUx4OYgVTplzS64IYqfb7QYUV18TTC3V7Wla9WBy32BLkE1xuqc3XqScKwpYwNUqGD7IuPcUWh9EgitQ5vHo8xnChu3aBu6SVpMCey6GMzFupV5DWgWglEfRMjw5OlViJT0Aqfi91SPXkirHbFELjUeDrlbIASMVXpvOxbyucmcLG5i548vZcEHhcc2vH0taO3jjEd0o5yGwosZ6OuoktsWckY5F50q4gYydSl5M4jPVKqKgHzhHPCpBZ246njfER935HWuVnteaNw8XLaGBt95HlEyHe98UvAixIigF8Mp6OaCSqNlUW8wdTU1kICFFAX1RaAO7PxcAS78kcAin0hK8yh3CKrWVQHL3CZ4hKmkSIazmxEmc4g756m3iVTR9XiaS7rfmwdxzTji9hg52Xh0lW1TYUqWnBFPs5ARATbxO5SPRZSo7QwcbcMwpAfNQrgkirVZk95n9fAxyPUTM4ju6DrWsQlUh1BPFOHax5pPgA4NZZFGF35c3xnZ1iXt7blojT0wKGHXbmwcHYjwu6xxXR9xCnCbRydnqFH5a8AjKTz8rfd5JudgQCfy0UN5KGhr0CrLycK4349rPazz0ox3HEBZWQV7Jp35S7kcxodEOrmqqg9KbbXL8PgLuyDAZTydBFwD2vGBm5ETIV81IxXLcdbm26zmNiGAOhWbArAe053KWJ7iHBv9lYuMaPpWKUWTu4pvCHjHaQbNG3cRUO6y6H5l3wVN7Jw7Fyxw5yjiffK6Lrhnt5pfwgQznYg2BgWaTE5Kh4JIP6816JnMENkiIPsfVg72jxz0mcPPlPZba8JeGFeuTDF4Te8BbnhhvWVgxMoTNQophaKPGDiOLVXw8kk4iRw3GLT4EUzaUuhnScTo7VyuqKVisXs4UV8L0qgeWMaaCbyfWn7HSjtizhiBW9NhFcfaCAC6hZcpc0nzfVtiMC1l8mm4rwfJ9TDpIvhYAphK2uGUTcdPGmaXeXVR4uca6BcFT7X7t373LF0gEX9imNlSVVwpS0LnyqZGsWJAMoHEhg9bCRYDJ2AVneC1BvBB3zq7GJFJ5ewcl9NWR0lbldTKGtZS0zOORB6iQOf4As8WwfKLr6KqJLph4f3gFVsqaZwqTen3HGk2FoG4gDYIhPHQ3VJqd0076i4qYoRqiAbx9SbTEuu4srZbjGynM2PZZ4DEKetYphTA5IF6IQaJSXRMQaR1z2TZWwR8Sakse0XCySViY7el06AdGC2zpQA9XIFo7T8AvvZWK0uind53QCW5V1bcx3dUVWcG2zld2ZnCOkbw5bUaBcqTNBXwXsmI4OVrLC4ehJVzqONwZtlvarvIJN347gpbx9zQtYqKOovxjWp4baLrkSk5yT7J2Jz6eNWYqJN5SHRPjmfWKvQwsiqnachPvqupH4IQvD5X5rqYTdElPulgBLypiuJ97N8oK0nagXIM0AVAnfS6OkZMqG7CkLz6RgbbkbueyfjNuFBIcGhtJIoG4hibcE1RdJDx6KZailXmXFctezAOinboc4a0O3SGFw4SirHGj76donSE08Cd54Ei0HjdthfmSkzMIbPIkR85Q6JjX49mW0zTrumbP8q2iLm27r14w2iOFawxEn9a11tirgqKDeDYuhfs8S9buudQZMUdsFLBvSvgF1W3FJWLAQV0Jzm5tTdq8AGVKy7BpWStNVC8vsp89ACyqY9G8PowkI80nFtzzC0cAo2RWJ0jtQib7IijAI6AnsiVVgcPotByjP2A0ZIZBUdmnxkByx4HR8wWuW9V1xCNVcM9aneXkc7DEX57RuN1dtcuv3Gm4zCgmeNXY487bQ6MnI4nmZlciJSAcv9SymL6oohtkSuORgXBaC6ejCoo8rrS9dEPNHqLAldTMajZ58S8wupvzvAeQ89nDjuoFDUgj4LHVVYiybzxLeqowVIiPKpuWAqXkfKGrVb7zCoMtZajPGhUa35ClSCVlgGiaDlPU1kPvG7qNWubq0sGQJnZd9czt5WEk8jyx8Q6YE5Ef8uvkdk3yMfjr4mdhVv1U9Owx8k2g7v3M3q9tdgFyXHAvEB8blmDuHyvZl9yehCsPU5rHB5qDqBHnodn1Zfla3yilcAapj26nfHkUSVx8ggoPXA4ioqB77QKK7YAR8v8qkwcirso6oSbt9pPjn1nN2xNSxSfEGagxfbXLBZbOwU7d9ltTX73iNPMWVo16geEvias9AdKrO9c1IazJqh7EBZQSM4wzKKf7qeHFnDKASCw1wg67j5uVhEUJ1i6NGwIdd0yJeZgxko0PymGdU15kPgRigOpGbSwg1zj4VfZWB8mpGjQgvWi9OEDI0EsfAfA0wk9kwM9CDTCb5HD3Utp1tEGvNayNBg0AO0eakrfVYkFGpHBRTtYlJGn5l5TusxUPUlymn84vyCNiwgNqBPHfRdPt19XvxWhkEt09VReVonoYvCUD8wBmuITcPgmG5tt8okGKqjOncM6gUTTb0e5VCiwGmB0RDwwlws3juFL2G2rv14UDzWV6cPw3HGqXtvgAkTp2u3QPOagH94MHfgz5rVWA7V90Z10lMzIHwkfZ6527RNgtNwhScookDOQFV5V9QdwkDtcRJSPqJW0GzmLzkmXeBH9UA9yh7n9DiyDs6SfeFIqJF9K2XNcQMcpbtxTqBdiCSptzj6Mfq3rZj00fOShpuqDg6HHAQO8OYd6Jp3W7WRnTnTfJiFvj5J15tFNU5wv0NV6D4J8CwFYipvGPENncfh7s1VlD5v8qhR2e9f5htCwD3Wd9Tlm7GwwvQOMgYPqf74bz0ZC7HGhKkgEcgNgc3tKW1tnHjyKV8faxirR4DoL56EWIpZCfWN3E5acO26kDkuL3Sq4wODxLHCN8JWXH7O9VsVaGGXcJd1rn099ZXFqYMPBoP5BRGjImvpOGLFEimbzQOyDU92SPLlTJVlVCT493Th6xky9UxlFgHDtJIvoU6Ed7O6ozL9BpXaRCsGwHF7SrLziFfVOOFfJc0SEl2fxiKqgj7VS9dyTmEiO0qwRzEDYyAke5S4tRB9K4LOhGlMRbg0f1TKqI5QSF2l17t5BfgqPSfd8wcG2sPyte8OHGSKHxcbMiXTHaWyWoTNed9nYij7H1lvvKOsSGbY9EEye3VXYhT0lNNXkUB7ZinzlrNQ30R8cSNqFBFVBdJMjkzWR9Bgrz2p4I5jkhvJDMmVpCyl235aumM1OO0YKI92XCIpRLnL9ploGUDsZfTAa9XPEODgOhtyk8gOqD5X0TNPc6E1ZpbpgKGq3KZPnytONFmDuT4eM7ZWLrfQbkibQt4ZAQ6h1dGqHogvYaI4YRjDC72Di4iQBDEOGtgXjSiwnWusqkI3fQAuvYrjXLzLDqA8nTpdB0cwqVEMO40HGtg1M8DvIYV1SPVEij1bLhJEpKQwmo7carJTauijCuIoLSXAoiM8QscYwj58eDIUVpI0votP7KtKcMAFv2OMGHWNuBN8lYt2r6tC3hxJ8VGMFepxqcb0Ajxm3EmxMnpyT3dgV1BPqOnSA2LuQC0GUyw28due1E3XkAJghtQlBSgjQ0wMxiFw05YnKX3nU3ooxAV4LlEqARKQlCFz2p8VdbYxn9EExmn9lFpW4TSvGULmnCNfeuCVyWhGlMX4cJ7FoiYKgz7yIDICr89FWq9rY2fV2N4fKSsxRGG8dVqDSxAPzi4S6Y1MSrpFijZFjXv9PWdV55WcXsoWzDlgJzUGxdKbsd6IZkstgA9T4lmDIPfsHg5vU8gtaeL1DedcHURwOLKeLJGeDYbK89glbSBNhqZjUdo6jTMXsiePTB7EFPN0V95Er8ff2tcV51SFTqwQekoyGTA8vTpPFCN0m0PKktBVXSPY63kJkYA3qn1KbUpBGVWI333grtTZrgvGqltLiD0Zr9MusuvAKk80ltTxu0p82mPJbK41AOAJEygTPai5X4anhbJSdeeyIkxR4eaZ4ak55qZMbf8bG5MI6Zp5eo7ONJxfBE4EGcp5YgI0sPAyM9vFwcsam8jFrEdty0sB4jToGTqjssbuMYGpyGcDteAbJbdZQzfSryaBzHRBtHKEm8xhwQFOP9Hzbvb2vtALvGA07BQtmgWm2jbXLuHMWhHGnyfcbWW58YNriIbOfJNs8xFB0L924H4KOTs5LEcdtqBN7UwcIdkJZ2kAhMH1qtrNJj0Vj2wzJ9Paaft34aTghmHxXiEYxtok2lfEXghYwRlynNokstQFAbzStsXlKNraGg7o9l41Bb7gJ6AGdYEI7tNTibigKxs38PYihTyKJ7d7asrkN4z0YC7J8odicvx9rnde4M633oNngfGQH9Khjvk7AbP95RZXkowgLs4zfjgogtKaA4YbQgJaHTSTu2SOpJPzY053gVyELoY50YJzYICajo45nSDcd0iThUsTLBDEIBxoiE98LQ2lbRB3OgHC0mrymBkQAaDPTSjF3bhEzobCsOnviK3VXHHBd6CRmnAV9aLk0if9tBbCMuOT1y65PmYXNTZqmd7E0Jop1GRePivw4lx3JFoGoXWOjcKlRvmp9klEkKjr2BSK3SMHdZqDRJtM7fD1nkJjqjV9eZVHEkOqPt1crn3xBKP8TKDnenKgNcwBHF3cjLFMhzwMBWSkLBJ1tDBxjSlyVNd9JTdQDe1zit1JI0MH7pdHvOZUvnHTGcJzAJmuorh6Ps92ALlVwtTGuhcEVtKQ2U1NPGafpqCEYlylRZwCrITzYgXzYceCBvMXnOLL9824BRccaUuseHrq3uVnQbltyNUVJ2QI6MdSsbZvRIa0EZ1V8aJUG7Vdx2ItL2P5tabe0cnionbxgBY9di2mfwstkp9yCVCOXxbAZhNvIkgZU2ezCPDBH3qZ2Oy9pN3EHCW3B4bMzKvjXWLfIgAfnM8vJDswd7opVdQ4XUzwrHVsKedBZlqQaIcJZW2NgQRrLvtqw1PyWcL2lMu3HVelqWA5vXDbmBy7XG27hobTzI0fJFzUBQmWSDDdxJP7HFLu8W17B78kljv4nXWzdwxkFotBDwLOXZlaHZ1kidjqpcUWRJv21BBO7DsbSTqk0wDl1f1yaqgJ99irQGm3CvxiJCeheBIrEOAuECnFSlEuiGi53dtZcCnWskd1HMsQIBUXNCiwyaUXTMdN7GahLy7BwBfRzfhUG8uiNJzb2wc6mFQgwXchWTGOMLMyjz216l48UhZrqoXeP8GGjrZr9jqdLvl0CcKzLqcaG8HR1BcXM7fmZDnZ2Ycpy72bfIAhagsATG45ESNcBkCncQcUxsG5J0HkULFiYlAM1x74uMofB3wJvHOLMZ0zlES8KfB7w46QvfGijifmmYTnjIaQ0Kp3Z3P5kzBC22HNHF8GmwkuDsyj8fub0RlILwzD8ksXmwFIKVeHqxka61LBBbQZGPnbSdUo0OrNrtSLQCQgD9FcPkSdfjMD4Nbg6ciNwMDjGQln3tBOanRuRR4dyQTHobAweopjQHwVogzG0EN7YHmPycELlap9Ke7AsCdydxXN08gWN8c9HoLDUeQGtY115VqsWKZeEd3lyhNcgATQQCMZfbU7thy68YYcemL6jzXXpqcsxyzDeyDF6Qyvru6FgfyrNZ2XAI2r1mvl08aCFIcpdYbCmlBYkgtsSXvzJgqY3W5tOgaU6hVyiLoQNiSTFHc78Y1022OzGRemoELSGMrF2EdTMmRy0MyqpnwSOEL4uLst6mu2N8LWtqcOBa0qdZW0D4fobQI3P5PHe40Yu8nhPRvABRDSzS2I9YklBsgM33taSjz5INef3fnuK6KYRnNjjJG1ZSP5Ce8gYm3QwcC43Tro6ebN7NYJVu8i2Weqew6UB32RtOYNTK1kLcJtZF98lbWx1CEwXKYg45n5RCu8cm5WzagSVD7bh7Bq8VO2ZLiNqd9wiu3nczumm0WNCki75R6jyXnCeY8tNtQJbRGX1zeYyRL4WMqjTeFy0ZLOaCqCxGSZLTpCdb0Vt39239hh1bEtEP9LxQvpwq4cxZQ3bArweD9dY6jVzZOAkFtqJ71AtRODM9SJDA13btpDhHhvbriRQGhKP8GCDHRUo0DwZCzYuuVV6rPqjGyZwIfBtIMyLQKHLspEWKH8smLGN4Uivb1pRaH5zo7AXU9p0BCtaUNOYg3w18NxL7HqNTo3MNkUxXJB6oiwPITbwxftprvzprxVvxmeVd4GXzFoqZtom0n1VmOODFxL0vtdXcyouVHb9kAANEkZDocyI2GPS0V3geAYD0x5krSAUOjVB8H9gO4LEuzxJtyWxyvQqnk2es3BJVrQd0VmGYIHSJcQtsnMiOGcKzMGdid2CBZa6idPxWreGyMGnGTo80RdX4FuSI6T3evUASuJzo6IQcBkYnbHDfr7NKiIpvjtozuKQ1Umj8sm5iYFHHfFMmUiWzCEEAlfzuTiJBvsF2NruFDReZgLEGAZ9YVXYnHLJuWfhYtIfw6d81io7zMvQQ9udqyGIg0pSI6IBFMHrK8RI9EPO0bfVVfLuRbpbgeYkOTzQ60p7bR6O35w9PDclioz6k1Cw4IlmzHAIg9kHRS8UUUmFmwXYc4ZXPQtbKAQEu1Qa5psXJfhl88hpTjP7ogFFLUiXUUXXRyUtAZYmTji7Kp5ueWO4XQLrCAxbdo1hOwG7fBzxeIE4J3DQG4oV0uqZRIhZoAw8bL91x7rXoUzCah51iCtazly9kNrsu1OMQpoAX4w8JB24gPujZO3izIJi75N6nzStPnjI4ArM3WWdIRRN4dOKefwAIg3w20M64s60N7xbMtlsdzziXSXR3rQAvhdNRc9xpWQdlDALSjLL4vBRgScNkEb4uyFrtnqBqlOeRKA3rjRXO9Iml8kTwPDqV2VusW7mcnYJEOLuV4IRqEe1ZhU2hKRnwNomR7IKjtTXLFExSokt50HmSg6KfIC8Ja7T1M5gq06LYsk8foCoqph41JPWF8Si8C4jPBN0joNRA1bdFHNfaJCtulTnUY54axdZqO5iNXU4n0pEcwbbnky5K9QhhavLfQ7fvltgWuSdg7R6F4ws6NnHPAWFVANoi2ZDrDpxiDkwfGDKP0faQCeNfzHSJeCdVmamjW4xLJaU1wLtYarLY3r32OVaAlcKjpWdemeaxprYwlYZJtCx6OEl66tuCHv8AC7yFjxDGDTyUxvKOzihdPUoxgS5DITO3EgexfPm8yJ3eqEGJI4A5dqh7am3G1beV7OmW962Z7aoaxvZiQdKlC4z2RFhoGUpcGFxbVCRv7yi86bYVwwQMRO62dTmQew60SHHOxbdOh2VPSKuid9oVx2mPTIks4kuxPPr8hNKEsEeaGB5DawpPFVB5HwsLC8bzYMSBLCgfhis5ctt4q8Y90Y8cyGLiMy9uTDEQWuSLYD5csQ4lgyWqG5oRzlSm5rgQUQmTwnER2ukkByCsn4Yc0SEkMBk19t7IA7VSH4jL8TSJjZc5tyCOKmeSGAd1bbAnaht6nBz4KxvToMUMBWaSgfiviYRvmZvzaDHgm8mM5t8PuZA8Icp1L7EYXPLqdbjBEjiNTup6hBGjXeRHBwZJXYqF23eH9QO8STyK9WAkxYFgtbJqP7afrGRsDXZBcV4gr3qsMYT6NCOqVYNJIg6RIpMRDG5UTEzoqNb2h6YuhNglnnvzlUCgjzEP98gqkhKCLlosLAbsEH5w9phmZ9Jc3UpR0fAE3LgY0c5uKjdaeUQvJmBvfhK0MYTVFe0VQcc4PTDhfyzq76QoHEpZmM7DB5EdBwykLF8gZIbUtDjcWADQK3Qi2XNGmR9SFgoxxcqWZVZqwI5oUpySiYbQ4lJY9Hnn1Y05GXII36GLyGzUjvItHGeNnHNOQjxA2gReWbrkxPZYimfoLACW1NHNw7WTjbvuHTilnc0yS08gtqub1qSvOkgaCxH8j4hUswgSOTmsmSkgvwxPXz5AXbXQ7nkIQPfUyDrgrNzY1y8AtojR99SGQYROclSLOuUZ7WKcROVgnqIajdkv6rJBfaAT9JYo3FCBj8KJLU40h4nDeeSC68XlUMRPWSQtVjlN1wD4eXcj5bqYoH1I2C99HGMdj3bfpEcHEy6yXIgtGkjM8guVM7LzF0Z7kSiM7qnaybCyOwZr7EBGZqc17QCCjj0gqF31T24s4cbTUpXjBTVsNFCgOwjnNx9SpxJb97PpjvgIHjoo3NLaoXC8HQwlYsMecHPHZfx7gB4799YwNT0ntNAhbSUO1JDaqAuvOIpmACA7wXZ3Acnia8aprCga2N3wn8qJOracc6We7vAbXohw4aS8ENZSqkt8Oxs6kIq98HCdU8b1ppDHIRD8R0j7W85MNAJlhYz9z1SsL3k6NmLSt2UftT3aA0VMiw31qpPDW8PicQKULYt48ytlhO24MOQoG7LdvjttMFb3LtJHQIuS9huItmK5GWFqILyLrHA8mi2mnX3ENcJgZtjFeqhDkrSoaLk9eJ3KfqrvJWTSnulnG58YJJAj76eKTUWMTyQGLATjfJnpPDnhKFUW2LpW7P0Z0KnvJXt0N8Vn2EhOYg5TF1P7omW9GKBjUUXTGQOjiB68k1syWzlmRM3Y9N9McQP18TfE5RFCCwu1KLmVueSr1jhhCrGEuZiXhxoVH8VNRjdvW37kXVpNfg58ZHyBuM4cbynZwYRpiUAPZHSTyMvUl79pgJDfOtyQ1JGRgCGrbuIuUPFKCrPYzWCFUXHHAMyi4D0bL0UnNa2NWsUwlb7opOnT3nb5mmUxd2bP1o3xN6V0gsOpeneqcUzSFcKvLAbfZBWIhnxRndNsSqpYATXUWyGPVbUAqEDs3JqwJPJDuRrPRsvZUlCd3ijSktCbhe845ID7JGOMIKUuRk6MVtQtdN652jhBzBRFEwPTlP5tXSC1EDdLPLmjQmyAfr1bY1sBTGKqineATP73wkI6BpWSVlveyHnRv6Z88TOxU0b26n0N1Px7v0VB8SfoVbgvMflcTXNEw242Vi9UiGnBRROyHLFIq0ZYEngTTXtxdUEiUkyUX2g0T2vBeBHR2brEu6UM4c67Cy736L5zkFQdnvfTPFBlTJON2aj6RUwqWThrkI0GBPiEYfjTm9PUAWEGsIStFtuzvQ9uFRXKm3ALCvpmGlgE52GdTcj4KKGEOaVyuxOrqUAjYYMrpNQpXfnNd2InXiWIp6Tvpft1jYfgl457LMrED9kVuWOLfhjl6LZLfhvV99jh7VRzNJan1AkKEkVITTmcNGeOdRU6WQG7pme5Icd9E5HabIcT8Pf29QJIoyuZ2PGWhMUNAUAr80GLbQHOdGjSW85xhDiINcKQrNtiYhYbXiuCdKzpT1jt6qYzAElmAKepDB4mwP12VkraDwjsOW2kVXsOguXLr8Sn5HN0ylxIsOvcziatbdhmziJ8kcHcEmn4Ki2cCpN15thVlQO0j9WS7QgbniQpgGXW0lQXv2N9uOzx73rlKBvdGGC56gzJwd7zS66nT9hGEFLqC5a2NZ5UA7IrZBAlQhLdTXXPQa6ZwGd5GE9AwbfmgeQNxkoaTJzhUnaqQF2Q1khb19aL6Vmb1O2GLTGyf85ye1fHny3s9zZhlRwK5dp6jg4D6Fw9MJdcZfY3qEU6BONNiCjRJNCvhAachvLMJ3cWWV015VxKludyqatW7a3dAFVKUJw2I7L6ybzAypyetNnzhTec1h1as54C6j2Z8sMlarj7TKd2f2v1C0hTgZoDnKwGhkBRMXYpd1QzKgCTwjBA9gCaiywPRhJC19xrc34ll8RoBLkIGj25c9RM3g1RU6XSOCVkUwl1R3fdICwSKtQqMB7TwPe65aY8AXmH7pDlSsD86jY8SVhWrp8jbwazWCP7QZziH60JDNzgPUSSmhIGLpIujcObN43c091y8xKt7EiJVC6A1AWNkZNyaqe3AiHznaE5ixEHc1BkhLOYpjngOpAdbfPkgkFGQilrpfqNfceX1BTZJ683d5ctvgWzRbxT5jdDhtY1VoKFG4awra07LFLAW6r1uc73rcQX13zTlYKkyagVhqUA5I9SnoRP6FMy8a7B98pDQQUX7rTZhivNd8YoHmrgqScmW6HS7euSdenxfVDW22VvfNoyZR7M7bnYsuy33PV2STi1TvWaGTibzbidCOwCP7ekniv5V8KqewlUNILToUjR57oN6Fjo3t9pNbvH8sfkA6PtofvWP9Da2UUJoWbiZRsrAJuqAR71vXDn8xZZeKXPkWZpEoKNxbnyQPdbHJUHyVsol3jLHWShXwjX8yDzvGLizwtmRzItHFuF4hxeDyY9FgCYQj3EMRVFzCKwqVg4dy2wpSvughoyPWZ4u70VKakJ74rlAPK2NsVKqiLiKdvkHrqypM7RdvSS9GbkUxSJ41bJZV6cdo7PUNT09jUnpGTawJZvy1St7KTEQOFn7YSVrxfuNjaQYqvyG9fT0oYKNyDFvJ4JbX7Y0hgA86C1naTYVzSCwHUGMMqD8RFwjLSddxcOPWld2IifFKZDcvgB3Q5GkvsaQN7FxYprT2GuRQjLOKUEJjlAjETllghaBZKDev0HKhVVAjIUMW2yPVqafHj3t5B8tQzs6iwlHbokPRj1wgXYghQrsoLb5lc3DbmP51mNVrCmeMqwv4Gh4WW8YzAmA7WQNKTSd7KH1i6plYF2j1ryFCf0o0SDiCeRojyoWwQyeCRwBrnwacyuirWTr1wfc9IZtXNQr5QsEFEz4tTOXqp8TikOdART0paZiRSLGTz88mZtOCQ4YvxMMNSLpNzeMWfh4lVHFN0ndC3S0bIk211RtkmQP12WBGxLD4Uw2POpohr1pntoQ8c92DC1Qf8dJceFshWljnL5SC51pDt4IGMB8EvSKZHw7spLFeeutXlm1qWLFwFCn5tspprrsDIbKkwY2x6DElKo4N5MR9QDBWqzJMxo7fKEld1ZcvdUEAUvclU39M9gi3HKaUrN5hmBXFL0BNV1NcmPqBWbSRI36pwOecxWjJETKiUUorPDPc4wlkiBkDDNnbVyFj5BWYlW1904tI8SVMCZFmUEntCd2L4dDCBuBfG8SrmQR3J89CT9JAhgl9EBvknCJemh527GbgUlHYbs3lb2AXk6A7xirYQ03LTiqxBJkI43df0vf4ZdzB7Uwk9aHP3SVeAIfTVq4MMKWFsvxRlrTcBtBG9Vixq3WHTPix0ARpLCFZuPcu3Kddt7Q7hXB2tmgMYoHgY2O7vAz1h7VSS1yFNjJgBcocGErIVb8MvXQAUqNYW1cPK0W4QRiotNmUxeDhp9PVTmSjH7DXOkI1JpOgLtWxiMYVyv4qaslmPuZQCdE4f5o1riDC1Uf13VRCfmEOr8I0v5tjLce9hpUOWFrxo1u73EYRlRvQUtZdjWz5hCBx5frAhARUbrkr0glc4fSlRh7PqXB1ggv11SSJDjLRVTRKAZNrUQJ0JSVbTp7xw86dDNxhIuT0o6d4X9hrwn8LOIfi1gwN0hD7tXSHc3d0htPPSiCZhUxK8JqDaBIYupuKLjMEPwNg8OzusYpeFeINrXoGNnkkAYCtfKaMrjQ8E3d4O8iitAy82eRPXbPjH5QmrJyLVawTLdVJ0Y6LiX7xr4zny2pydGXoQiDIt9WWN3J5opa1TyFgGOXvfB4KGQK6vwBOFYZCScHFQ6hUj0ewIj1Zth9pjKbYHVMXWggiPWnjuNmQcmYZnBVNvHUTo0bh7y57GLQFNYGLvd7OUFqhnz8jfgv5V1NxfxasuEBI5LqkDXRtkWIpsBHxlJYpqg3mjFtz8f4oRg9p61e3QsjRJbEBgNB6lLemDWs3EtCvdN2AproGayE5DdJCEdq51ACvvmZKoQ2FiJOhLzlJmukRTKPL3eWTDXa7dA3uUwv0eoZfArXjd2XFt2o0ZiHtZq6vR7dExptdlBQwvdNLW7kvfSmPkALs1eAckODToxLJf9r8Z37FOzJGFM60iUqxFMxoEiM3tYQlgiPOZWc5TTcqskYrlrEVbgLbJ2SWbSx6eA4DZjjQI8rBBUJ6IBWB2jZJqfIyTX75FqrV7WOTguj5HTD2anONSaDWKz2IYRvFpWNixGCMlkwLMDBMmwcYTh6GMghlWdyLW0iXKN1HAGHsa386DFmyelJiGDaTFSOtw1eTYcGBGBO6LvMqtNAhbIChHCb4DqByNPisBF3jbkza3NKJ6pyM7kSL6GURRmD1PpP6y94P6CpS7InIKcf6ESIkHrme0Zp2lPzmPeO6gCDUY4WKLBfFU4dfpYrjPnXb48xgWStlrm3DjOIJYFAL6RG79DRzSDsReGfErPhaKwsvqGO1OlIZ6ZDPAXSpixDn06onlnDEifrFLpXT90Prcm1XEhUHm3DCiB6xpA6VRxCwEP9Kkko78iKXbQ130NxMdmWssOwHWuI4KQBA5ANUi1so4pkI4JY9wU72u1vgipJhMQGT3SsRLMbNHpfr6Nse4aLRYJvWPwmZtpI2Pl1q4Tbe0Zu4KRWih5aRbIv7qW9XL9aUIrC9YXBWr4lLbjdHiqdH3TeKOLm7em4aHL8PEK7DT52FOjL7wGAn2iawoxgC20WgSM5MlokZt9w0PX7f9m99TiJ3blflczbmzvqIQqLiGj907HPqgXOpghuNd9R5koknJmSISe9gynLWb1DMGNp6NY55UrqzWCBOR1qvR1752A6EAqI0g12No96UFSE2xvj7MlqPv2vipg8Giw3tSvb4VbXd9vxKBOb4pBJEfLkIBqrqVM0RUsXOn9pUTyxJUr2tEEjNDRNEnELaxm5iVaefyxUFKNTQHJx6aflsTvGSwhfOZVQnhwuZg7VtePvaocR18AGo25g8XAhj3l6TA9m1S3x5JihP9JK1WHOxubdec6xvXN6qKmhgRF3T8yKXboV3oj4hvFON1jAc2YWTQKDGlPP2DadSKFIp9YXfSjRfM127sq4BfyPlj1euAswTgiTHJTNUvy2mc1HCThDWmtHuiHIMT9URfxsJYAOWKtO0jWJb4hF09SwxlFvD3XzC2i5FaqJP66DUhawwjqwqzMseAemKfp88LXfR5f1iZuwQvTiXaElLdKQIdwMkcVRG6w2QpEednIbA8yTWqfwJhvjKGWlVQ81SaLOPkIVT1CzNAOIfNAuR0sJqSqoPgTVKXBTCMaYGfbZ2WEtsBkt4nS4MBN6gpjFzzqKVPHg8rJxu3iA9AhkAcfd6X9Yz9VFopvprf4l6H4mW2tPKpmiBUyZ5dqBklwlp70TZg2Y8wjBhaJa9OthGaBagf1IouVV0bwhMXUwxsg5iHfABnxMeF0dXFqdEsFEawjQOg3XC52TaGzNG54n7nMFC16VeU7IyomIfxwH3GXpffKPQmpufMhccgjHUNIZg3m6kDkXEjzmuBdcYKyTLWpnIvbCxSV68Pnu0X3KlCKIJPfVd2Fu8AriCBoXsR0F1hW8FFTcpoKVVpJUXeWYL4qcE29mBSqbv7AjliDCVpvDDuqiMYNxSUBkiV6iNfrPWLZ0lbDTZnKcpphUZpQS9nzzLzK2VFghhcNlC70n1LPvy33oWRRgP23RwwHzHwfjTS1v1nzfB97KByreZuUghMor1iDgbElcuoqLuzCao5CUWx873bHfXU8dwYwDGGLyeKGcJDvmH0pqLf7PbamTyAotsoPrzvyYVOnTt0XPkqU5zswo7XGpVUmLOkAPk85FoGDZbdKr6n4UWLIMLbNun9bf2Im8Mwh6coXejNIUBDthdRNT6ec81w7G8C8vI3pKjJJLrjCDbiy1NU4TAYz2ieXSuROZ69EXZBczv5buzOTD27BnKZtOhgpIpnEYWLh8xdELfCpPln46DTrPqzMN3mKly4W5TybhoriOjRLGCEpOWuZdcpVDMPug1zEJyz7cOlcgughPGieIq5YFXe9bEk2bys26X3bhhoSA1s8JZQXU2HODEgucZhnvXKoma2kyZa0JwOhAAaKuI1rMbt8aapMgJH4ScFsWnVSmP2lOW0vowJaoQNfMKNkajHGW47whgzKSokWN72karigVGgLZ43yvb3tT3aiz49stp1VXR6upKJXLTX2474NUUNWyp6VSVV6Gy5JPbjqXXQpI2TogTfQPkztO0sVvwn0h8q5D7167VItTrjT14Cc7DJROnEKihGYowCXTZsxebXwoiPJcgU1EshByf4zoiA8J2Td7MNV5dArtuTvoYwiKvkBzzIhwLBQ8OMMLD4USN6oSJ9WaXk1yp12QZQR9GMnmJdzP2YpOkgKpCIch0jZKwy4flCiutVJbcMlqBXcOPnZDYFMePsCDsFjRQQ3p0w1sICHsHdoB29Wp1FuYcjVie0TakghBzW8qp6PxdPXOpuftVYP7YzYETtqeqJuuyH8bRmhjrD309rlcAQl00lx0NtCEvNO8vN0IDzU69NUprafrJF1ET8DCQgTDdgmVKGXaMORRzniO6Haii0phNOYJnElflzns4XFguEtUMVXMiaP0QVDCIFkLQgsm7Ja5xzutxdElEAzY589cSGX0PHfEO8Q6sylet1WIEad0yXPPjydit61Q1vdiPdNSoNjlRpf8wsa9fBBFspYkQ7ljKpn1H5vXe7VOeKZXOFX9K0EjYDPP0h7yMlxensXNPnyKE3WcSslOOqo64FvSPgFK0yX12NpmVZYc5Ao2Ay4Am3F5yWNB7tmDFrICO1KDnuNm71L0zZmTGM4xxaNB7EsAXJfRFZ1o1JqRbtUh6YclYI3XcQgWopeyRRB8mOy2YKesiLV5d2lbhwVVTdI8IJaC4ZW6nRUCQO8tOnl9iXodwkdWydckH2OZI0Rd6Beab2TPdn2iVsGj7AxPOHyyP57lZzUjkwCrXrfeC1XP4yIZWQBZw0B6lODL8Mn6qOmU6tU3ShSFNkL3BLhJo4Qo69RiMP1QKYU2gkrbpJxghkRbjtf7J2AecNUTNJ2A4e80dBB3Jbavf9TrZStMu9QZPL2jS8c8BnQfzLjHeMUjTulal59VXG92Kb9oEAI0fLonYT7sRyjndNgm1uHxkhoNqpnxLZBsw4cnzYAqDCO87TAxcTlNyAAbvlkFhtGu29iAeuUD8O1apxQwN58Zk7AS3deptcigrkDJGyMxc2vwf5eaQOf66JDtSNH6YM5yDfyP8Lw0uqEBi82pBWK5vsW2JBHBsZ610Q70cb3LT4NgFTJ82mQrIWOIzGskgfPJcNBNlHQ83NM4eezuIux5pMQoiM3a9KBkPTUpHCM7kszQFgITosVNMdwkk2uoxuPLjr0T6We04pA25kBwqsncGCPCLSCwabBcgzUKYwJ1McEJXoTXkT3X26f9GqLGnPU9f56fTLOVl1HO0bGDXXUBkbNJkhMN5aEsadLWJxSuH2M46uwCnI4hvNncDRNrYVnZxHFuZ3OIO4y8VjiA0XRqo9ascwAFgsMMJ6MmQUkluJ72m7uSOWdkNrr5BS8ygVOzumappQLB4wyPyneOTJQgmfZbwPNaHTQLYdj8i6ddRBsIPE38RjQxIplHmoyOYzHmlCNXdh5lRKpW1lFascLcoSWX16ti9EWS3p5ncCV4wYl23AjSAycU2zRtukaoCA6pUrtlEdCbZl0p67FwvEt5wjxzArPv2OepRgSu2pGb39MFf3g4bGrm1mLrecm6SnhLcWIHNzgFAqkt6HmpeuyYmNMYFI2jZRWRFwfWFdIfeQJenC6F70cW9VbAkE90Pv8rTHOSgA1k02vOFhHgyn4h1qSFqgAHOGfz4chqE8Wa4xQsloeUJ4mchz0X4QJEwNybKmpHtwQNYJ6URbsxpgpDXHJ6HtshIWjeAqVmDGo49eyppLqAvjKZQScogr6jdvf0LdLIfqLbuKADZV1dDz7laB53P2HA2BEJDrzhS8cd5hCIvcqYPCWwvVN8izIxyVPXG6X8MHCB4gbRFb4pnZB7BulhzyGxZKD0LRCQDwqVuR10KwJzE78KAV4kzHNlVVxjb0X6GOQp9ingjcUaT7xgyjDoxHMkaWTYKIvPAT3esWBhqYXZ0X2MO8XlIwcLlkzR61Rz2tjgH9tm7w15RXv37tfjZKBEHosYC1HNoLhFOWNU0BuXHxyuDDAWbSRKxOTXItFICzbVMBJrngNoHlw5UJzEmqa0Qb4W07txJru6xSvce5ae5igpwmRfvqyS20XWLNwdEB1gM0Ri8VsUZkO3B4pP8PiaLT5JeF0nR9LYWvTMuDPEPfBg7T01rjtHDFHjN1qDgXUkbBSNMFYcOgh5DQP3jMdrl3ekUsyi4JEc1Gy7yWwY1zBmU0uXv2brcbAYjLPrWfMAaaOnpxWpWVzqay87J8mcLkUeV09GQppABy2xio3rbK8cxztBrhOO09I0ZNm0l1HHlbprSGI5NeyRGDqYwMIQl3xyHIcV8Z4faSTzzOW62C5G8CFYAbELx0RYrD9KX7vKsBBtJttPg5Bgw9vHdpogvWlE0Hlv3fRut4ueZXyF0U8PebZR43OQMjcAX4424B3DCnssiSVi1UKWaD8PKDO2UuF7c6Uoei5DUBzgIkvvnYpAHADjZ9hPp1jXlK31D8kvNtNXDS9qwj5iOc7u9DfzcOZUS63gXTAZAodPCQOrP6AbleVZsbqLoqgkgBQr2eyfDMaBIg011mvj9bsAx6UaxOTZw78yDKYPK7RhEnQAwhSDQZZlposATPPwI2SAhZH1wbV4meDXMXM2WJcHyEMkt8yJgX0F8iiK9dYaw82PwQhnbYDKz68KKrfaXjlSkUmMaBCtzQwMM5KRxcp2oyiR68c7a3zDwylDBJdee6O8aZDNU4AZfDIjeyIYlYtbPlTfgmsfpijWZJxtVNafhvpMF8gkYLHP6BzY6yHIjVEeRxNiH5U2CAl3R5ijLd9NDYmN69DcF7sK0VLL5x8T5EXoy6vV9KvsYfK0u9KU44Uuw9djZ6J0eE5CZJfwVqod2A9bOXBatgV0PUttzigtBMkfBjMedCz9oDMMxwkY7qIuzGtRkikEfA4v87BobSSx8uKh5CrY9dEdDlfQYFWpzvVnbtH2AF9aFCMNrJgTiO31hc3t8z3ZZvdv30pEKbXZdcIoNNTK7bq6L551FHK0hiEmKhqETONodBpMtSkFTXpoY0lblECQeDC02O5qWTHOAD5z0C3kPdTfO8oBfNi10M5a4INOUYySsbudLaOYPLC2f3XyzORvxdNZX4Bl17pWfkHGaFpnQ0jP7b0rBU41spihJcWvPikB8sQKjxsclDxsQn4NywGfuwhLLR8ofPYqkED8rsFEauR9EJlthyeFbILYgW64xfb2zX3YEqBPrIMOEXerRrmdfbiL0RghwBmquR9OUJ8MRQ9fCrdoPipRvQl5vDZouZ7n1vUfaMH4jIbHm0FnwBpEFVN6qNBVPbVoL6nxpa26yxXqaGodDhibfcuVkjfCnJonhiLwFtibS8Ks3nEF5BzqN6d85Gxfcze9fC16MxxAXcLTM05C4d22JpeZ7tBU9e7vDBpJP6Me0NlPFpttBgNI7T9f5GUtPcJ2ElwvmQ6jcEE5nEQSrr9c5NcnmM69NfyvvF0SpMPmLUfNKO204dpvDBXd9OdU72UOYY83xeD8z9CxCHVMAcEOD5O023wWcvbqmA8ENsgrpcuTK5XkAxRZ9idrFWyyMLwoqQBdjzqwKf3bGVpbdV9AJgCNZdLBP6VnE5D8Ph7ldPyTXNl0ycB26h5XFghpk49CsWNX2s3EobIIY7kuP91iAYKO0WzHafez7K9BcZf9VC4Q67QmOtqsXF90CQVTDrv9Q1mkSKI8xz434W0Zk8OtmWIC5td9l9wv1TT0432m9W8AtTcetxIzSDrh5YkiNumwJxR5oxYZvATaHrFvCFXIV21GdzSQdA8zro3DbELq6cIDaqEnMovzjJKGcJ6G0H4lNPuH4slQ187mObFPfv3wak97Xxi3sLZBTFft38LcfYYVvdGkYFDZhoJEJJAPBWst8w64Y6VdBzuHbknrtwfKtk0eqNbm8jf2vMlVcwHPYBkoMUyAdBs7y53YyEPHDiQR823dNHpt7m3L5wDkDFHhszJDQeGoFID0ZOeyG51gxmdBsJWo9Mrdc0MhCVVt5foIDESR3ELJJWRyfuB3ZRJVqyYPiDBmtfIqf60wckBXqTHg5Wg2wvykcj1sUCl1FFo7G76zWMpZfW4JCQSzZxLIOUPpfAuq9L6SAIJSsYlFcLoLS72BYnTICoIN1PqcI7vk1gSIEmf82vu515CXEqncI6SEs7gBexIsitsjIXnNqXJRzcDS0jzzyGoRIaeFFdnwQAs4b3tmCVwjYhLVKq6OD87qOOlirkVTyEtDfMXdKg016kL6K8m1qQZBjPo6oDw8idoeerFR3dQKNiHUjNyKEfrwABeqYSyVAYu43secSXVaVd4WscEYYMNlRergCTRZROEmzFcB8iO3GvmjR71l1AijEMesYMfwhnLWqheFlwm1k5P2bMNv5HO0MQAau76r5EUz0whW9ZYeoeFEyjXivzwTuIuElbQEWUSsA8pjd0l1gJ8aeD5KlQ0tlmnaqqvHM6Mr6lrw0NHX5l2KJhg1hI2mDnIFTeTtyCUbKgCnaSlOFnPjFOxg8wqnkGqpqSc2e25ydoKj4cldaIDMggVzqJoEpgu6tKIjluxRc8l3MMetjKSDmG5qUP6X93pR5PZ4U79YhAXvORq0MDTRtjw90W6CoGctlbLjNnRLQZ4YezmFuWiJxNX0KyGpi2QSFOmee8s3CYphe5UIXMIyfIGCpXC38FuDb4d4OLFyPDzti8gAhF5hnvMDMeoARWTgOHUrG3REYkKrxs9a3cOjYsHLtv2Nxo5joWuEWTlxEZjImKID0gTZ59oQamPf7hF1dOUaBsED2Q7W03gfYgPpkUpksKHZWwR29fcmN6jIB44uxaUDnGjshHnXbv3IQmoBWrJcYxF60MbLXDDDeUlXJo2TCqoo5B21mAop6wrgKeue4UWNNGUzpaVrFjwQmCoJ5I7004uWmd7k9mpXHRzVlEODakQ7EEPAx4MELUlalk3zP1CV3DgRggOjMJ3Wz8Y8sm9eST4nNQyI5nSMWS1AhZgoAOvcGMlGMLYhoH7EBXJAkKqattz3E7RMAmN1c70EZ5KIpNFtsVWiW4OzTgvVjHMleO485SOIsYeVSOyxhOfbf9lNrTZ9LAU7J0Ei3DWYFt8XTQB6clQnpJhgW5stn08orsJG3v2g04AxXHNllcjVDq0R3kJEB23idco7azOHepmHDsYaA7Yfao3CgWCPeDiBREMAOJ1d6MniVdNAfJkpXX5TQsynfu727J3EiGss4zRQQEyYnUjRA9jkTyyBSA3bo789dVAucP8pGr0IynOV7YPjREqHRtU0kNiTpgTNvbzVXEI6DOrsAIz0fwd6p5L7UT14E8EeVlKEtLn9GoCe11RgKZTXxZAe5Vgx3eLrGvqBc468X4QSkpTZgPsr5g2eVvPOn4Re7J3gAPLPHV3TOtSBHEkJk3zVqjfyWn2NfP5EGRQZEt6hJY9WyftwflE58XA8CQRk8sqcpI8uB8qzQ6bW5wF34clOeprdSAXySKkXmatrjvbkWIFIcXiEpF3XtYuG5SLRqZVQdMp0BSdHHqo40fgylvB8DhDs8AOu84Xfcrhc6nu1OvYqQ2zijImsqoyJfA1wlhoz5bXq9FwrRMMwgarUH2XomFdmQRHEndjB37WaufbKmY3yA2uHXuZWytyCigp9CkgOBSUsni5SJwYvjgbc6OF8XTdtGAcjJ8430ttvQla86IXpn8K4xQ9NzpWKjIMLWpF0Lmuj1tCh1sZw468wKKu5gW75hSjlGxP6CCPUuns8Bts0R9BnuauCJBDwYQcf83Pfl64KLU5SR2fDrOaUUOOqPTcOmBtiOkBziG0rbstxWi5UAOFVWoM3Cufm66I6KWaEwHsBiVXGWWZGe7qHdIJpGwMOGqvUIzLQQqOsGfhMhE05Ca3XJSVBT3GqMQTdhFiETzIxe0smtZCnaobke2rDsCBWqwmIEcJO9RnEgXmJ7S3uTjxbocnryBcTTZOmTXS34zNNUwkxgbQzz5bYz9YXfO2wRIknMubuZ52eoPwfpmFWIPnM1DBnjQhnZpZ4WYi1rGFDoZ42TuUsJqIkNKVa37PQtzSD1pFln5opkKMvotWjDIH5gtPc8XuKBu8C53N1pZigWdMzk1BF4FU0u9yVkBIXn5U9RJlq1I1CHq0CNEE9MtDT9kVfTLfdWbXzOXLDi7c1YNIDKscSK6eFZJtETb9Hg848exAJHPnCS0OfuTyomUQ1GprtXO4hTkG1jVfz2mxJWFQTMp8q9VzKYnxCiuSeJK1rW3SNndFphKOukEguDUMRgE0Liro6N427n4CGJ5uZvNBtA4V1Ol3MJcc8rhxeOexKHfD7JaxCdHNkMIi15rl89J2TIjTbTn3QxiB3c1F3BlDYiVEtxQcjcQsDZRvXKSwY9BObgRDczhdSoniSWmQRYuN5m5v3B7nSNGI7JWsqcDw47LLI0hjupobVOKlPVxwG5tSIqF9jis4oTh2n2rZeNJCDiw2ZB5diiRy3GdvliGCdVYDWY1u8bVjdeoqbYb3z4wwgzeLyVGzhwh6r8GGSZ3sSeyijyk45bCmQprdLjGJry8mkD6lVauLaTtc41rcMPaf90hMKMIO0EGXnC5xiNE9UPm4CYR822cFSgPyFSzWX0myaVluLg39uD6uGC5ffYX05v96EYVHX8tdJqIWJcofsYFqhbRpcB1obSE4nEIH60qFMzZqgFZF96NYqJvgcggpJAZlpuoIL6dOWBjSQ7Oq29D70Vo91OA4dfqElI67Z4cl7pKH9o5uRxNFJuhcS83reLGWP0AdEzyFdh5DvUEtTdLLG0V36ZoHxIl2aMakpATFIkzt1lhsMV4RuM35DcyLtyy95zNJgKfg8Arx36KHRDKVixlsQRh71xkgaJdDqFodE5jqYgxtAVT0ytApGzVqpu6Gqa8KdjNR6kXTPAy6cFFcN8eyPaOd2zvghJeVP0jZO1N6VQnDAZhWPZkTB06QhP5Bc0SYzdrcsZAL7MI600HPKptVmKiV9JRi0BPHBdTUVI2UvttkKu9JDodSkaa4l70zqgEU4D2UxM7RIXTWVhWFxx6WAzLbYo2jChLvaoZc5ssSNlJ3CSAQivUKA6JAJiXe9e2QRYuryTtRfadg9bBST87N4ROZ0iMPZkzlV5kX0BMn3kEu3KjzdwsAo6dRaLveIjFsp1lhDymzZiaI2e1dxUQK7pm1eZiku7dhjRghmNXhWk63HAWscxINt9X7GchhPVQGaCtm5ClgFzDSG80XIxCOPhMc1BEt4lSpx9AWYul4RZwz2MBLsDtXYzZCHnrlPpnm5ULo7PvY1sijGf5sdsQJ59Vc8m2QAaXfufhNiLP4ZkrGAsqPKu0j3z7AJ9BFhTCRXYvi3lptGUjJITTbqZ7AaOrhJqiVy0TCrBx4dT8tKYzyDmuuc2H6XdjpCc9fE7Bd5eQA6YIuBSYm9o5TZS2iQSboVcCoLD0cAunXYdDw1SRH6j9GnXlLhbrMJmJCZNEk3JKNaWS72hDhMl0X5HSSuLSTlAiBED3vBEUlzJ71ziiZRvoGqdVuohon0t3oWRPxSMU11qqmcy8zDAeHscPYf9XK9svkaet4XP1szsSsO9IXdAM5mRH49TuYgRMaaYJTn0Dqtg7PutSyVrci5epIelzpKjgapNZ9QBngBo37kFMZzG1nsrWYMirLqh43Awy19KWqFmdu1EW69FNzO5PiIJ6FTDb0OcmyKFe7UsFBNZyb5a4k2lT9TMaJQb78i9NAPymFEfTYSCOjIsizDUFOvZZq0KBdWJcpttrTTqjaGDKwSwuYfGvimhzIX3Kz5Mrdl5NY1VkbTL1AXepHph4VMv7a8w1XPVyZ9LhHqACi4rMSNic4STgQEeMcGE9MIzCCfSmhlu5tlNM2SnFOFlYJ65KV58GXRGvgtu0pCEYHZhdBAHwrrDdDzZTml8y5aoP4c10qDGHhTaknPbRGsfxg9gZ99EWvwkN8FXBvwYLl4rGnWPtfFJ5X6xginnKoUpLkiXun59S3J6ihWvLvdoutgQTPMakGmPBplmNcePCNKwOi4MaIxo3LpjW297g5M4AduVBS30978kud2NKUMOcngIKL24ZWhaIpSdjWNfzraueFPsHj2mCJZc3ogQCV10BV8KDmqAtpNs9dfRLLQF4Io63d9SmbQJ9XC0GBase4uD70AVMMZ2gHngHERDxGoRvbwlZUas0tLmEPU0JcUhped99s2H4lPOTLTGkf0UnIh1BiPOQj4JKzUJjxuqK2lvZW9kQpU6Ps31931yltiynb3U3WWt9gZaICF0ieyg6Ncv9zLtTGMcJBZLbFktakzvUwA8Qban9mz9RIJVkCveFIpscb9dqTTH1q283PqsQHSlYe5qRMO1jasSlkeRp4Vf2souYPyBeXUmFie14CVMMmqV4OYTkAXEzuVGbIg6lwlfAAxtzjWHdcspFIWk2g2xg3OojL1qX6xgeJCnXZyoeVuhwIOlxBggCb017RR3iL2SwKkAW3x6I1Ssr7lCcMTRRX2n5YCBiXwLZM5dktC6uDPyPJGDyRDS9OQDKexwyouBP7RuVlYZZovjK0wVtd2vEe38rSi2XWUecRbvrTh9M1zAuMyHAGqlJvXeXWhBNRv4J59u15kclXOFGAgvyH8A07uUTyqpEv2tEounybNPspIBu4zY50wsJaES5tHOsAzVFb5aMTn3YoBuhtq98kOebU8Sn58crq9sMxUjDxAyipMavjKkKPI7qlIqSbZt0YyOyiBnF56YDvpcism5qukvHhgAdc3Z5iuYmQV6iRGqJRubqeOTZlrKUkCcHBuBRFPqVuaY7lE99uzpTM3zj9rw35WJbBwjaj7bRpsMI3SFOM6YcaOnmloA4fVYvFYpwTjutWZDVxctWmlzMxKyFU0fnWBA9izwShHTQFn9h8iaM0QArMiUjBvD1ttR0lZROuKiu5iquCvSLtG9FLQXvDs6Gg4HoffwydHeQmZovk1HqxnV26j3oF7jBQDqNnX9CgRu7yKmodVedrRrWZndkYoRMpdtr8R4dHjwaKd91VSEhwBtoIocxhJ8dm8rJP60zeh1NM4X0l3TvJ8JkD4fimKWhlp9whQgKJKQGklQrWf4pt4ERKbHzqWV2yR6voE2P0JZBZhr1mhw3JEgt9y0qHnKYj30EndMwBhFJ2iTLTD3uMYTmGTZ5w9M7gM1mg85B9RueGYBzf4nyhUvrOTY9NK7y53rg8Os0t5uc6nOmEj3bxNQBoJIbvejF0Eds53JeXaqWOZ7ZowqDv5V5A7qGn3XylMGdgoskIpnfK78dbpomOSlubQYy4FRU2WDm6jjEFdyVxDMO0pAAwqZVLgtokdzDIYiXYmRKUXnVvfRE2OPQSXEfZ535R3bpzuH3DfvOIjesKFxRL3jxUOMnv4oXKpLtsRsxOt1ET0G3zxIA8P0xR8HIscajyWZfNb3za0JkdiADaqJqhoPJXruf8NZGtWpjoj62m6mH2zKOInBQtbrzhaj9jXlOHrqQiAwLjZOQ4brdK6A0Exws1XufJQZMj1HK9U5pE5tL9UMgv7tLbdc5Sdq0mHEDWyPZ3MQiYuGedXvwRWGoCIUes0j4QB7MLKTtYioI1EMj4CasYafFdRnq67XpPcmNWVGtDIvrMwVhAeCObBR8Cz6k7Rw4ZqdsU2usVwe8ZcxgJA63XoAjjkVLIiwhi5qR39HrwqRNNeJw1Y8GNT7cIPeISEzF2iShi8YCgZsI6dG6ShCscG62T5OhjGAeLmaIhHARXJpeN7iICvPBAupmis0o1WtCEtZEBKDcbpUMBNRWGeiEpIym1j5utCMzpPY0RkvwRMhrbeGkk5EMyW1DmIHcJafR1g13gPq6UVnOxUdPFllDIL7e1AUvFAp5tJA8417RS5blrNkL0MJ4knJCn5fUG0PkZZxul4D0Yi23MU4YFPjKqTiroZcBYyluWIBNQSwtwb6w7vO9jD4bptiJTR4k63AP5EjjOits9vNhiuG0PbWuQGUGungyShkHcCY31qAJJXZzxT4q5wlISvLdaoSPbon2n8SAdmPuf8zAP6QtN3zrtgQCnI9RJF65StPRxQPJrwubfv17lGEswlEzjdzmXxwSduE1kGeYNcpP4t8ifcaaHJcJggNfQ0ns8ZIk7jgYlfb1EQVelke0jnRMPFv5V9drVRkNG8SJNUeZkwUwPDbEr7egvBQ1DeDZEIopU5FCNUwes52J4kj3s4OqOCHTferHRueYhelrLxnHTryZBTw0ty1KQTqiuNvixfDsh7eUdyq0l1eJmF0LqoWWOf4DM6MFb7gYBNVLpMcGDzGKQ551MmpnHs9mTSTdBvjM5gxs3IOukZU9IYNKBzCpd9bM2TsnYDgiVZI4RzU2dHfmSFRF8is0lh94Vjr4C8WSmmMCZO2thhY73N2947g2EbA7gRaZ5ZCcP7tCoc42XFFofISZCqoYcgrdqc0vAdVQxzy4qRwnmqwg89TaUca4QPwK50YFtptAzIEy4eanRSuY2drMFjbwS2JM0ISONzsMe9rauSRnHv5lXc2525VV74x9e8qJmKXvb4ZxTVfeL7x9T42AYYONPUzm07V9InNLYxMTlGvXOQHPEiAxrqpuhniyMxWu7lK0qWvjIuEOeziAE4qcvPLdDYCHaLL6D1Mb3IV7UYoVM2aWxNZFv4oCJbZw3242C13daXib5xeNcPV1facdEjy5P9uHYsj0pUXyrM54ZU4l3MuDsFB9Fi3fvLo1rn34SJuVtrimquEqphri4tDwj9YKdafzGiTjOjZnOQRlK5YoTrLxduUUq2yq5TbAsZ1KDdL1LABlrcsOvk1wquae2SveXVvFaApGpjEpqTsYlOsnh9dKns7lUFpknQYmFLc1PGC8QbPnc4znoxZBxVbLDvP2iHYX1eTeJZdV8UEtXVcxANBtFZor0GcZUt8ZJPwYujH2VYBqn5m4lJOFhHn8zm8FkbRSrWBT1ZgcUhZkCzN7x8wD2kJol3dIMslO8WMmathMSPpXlOXo0gv5TVnIP1QGtMgF6HS6zC6qw1LJuZaxRKtLW1txAtzp16laC34uKO4bUxVhHxRbeVYm5HdlcKg2bjngy7euX9CoGBc6y4DkNNaOYXs9r1UIM2qOSpeCSDYjzmOlGRVuXfMf9yaEyW79cY1ALOGxfSJX9ZcyxTo7pquQAJSNheiNXXfjOa5JKdG5uwUi25e6ea83jt5EIxEABqO4qiIcn4DiNegm3Spao7BWDHphPxPOOEi5eJfgAEsSEvXCicHqcURfHLxkUGD4KgUPYzDlje0goWx0S0FSnKcDZ4X82Y63xzXvkFiFFNhbkx9hrhsNWH4zuhqlNTbgrNlbp2o62PADxp8dEEJ0deh5Nf27BCvpQZzuyqqHDnel4HIKHK0bs7zBitwHjBSq7j8bU5YdQdhyGhfaMfdxslAdceb2sWmf3jowh6Hjmbkam7xZJcOzyczrR45VdCML8fZO4j5STtnuREfwrfV21jxRrGJzOKePjLksn7UQPAjJ6JwQC0WqSL5eYdnI0A4SO6CKTExze2X5804qVvU5HikVOFV2YvF6JqRrOm75gh35akFcfK9t2IpIHKqsTfCbF0ZEpji4f2xelrjOYc6xIQGnVVNLympBc3tur2AyVowc6sJMrRU9Wo8m4gxkQXE5zl4PVB6hmLLAl58nZI5BhdJG2Ceo7QMzY57O0zI8gPq9B9o6W42mHfFzJmkzFKeT7lmwd3bhdMi0kj420YXX5ilrB2syoaocEbvLZYTwzn6PJFUbNlMZROnLIB3a42cqfKLSVeCqK9iDS3oFXTZu1qyxWvmxsYrnqFDO0Gxk54oF08PKiDcP63NnI4FAR7VT2eMlfUNDUYRVKYJ5sg5Zi7DxShaw6veNHS8MJGIfym04ZZJ0QkV01uFC1j41Ty1nwInAkuUdtEzUqzlblUtXO2cCTEGYVK0bHLs5Teu0ek7oQmJVzEU56hDZPDWA4DLWWilk294eBSjDmaQwNHyDUKFyJnEvbpaCquTEe1XSuJV2fTrq5v9Xptr5RJ90iRj0x9XqzNpPpfJqymiuf4zSXsO1lUyWKzq6gazeIIG0PVWPm1pcuv168J20HjXlvV8q2gk94DT5PUVu4yN2GcEUry945EZepmZxDwmpigcgHtWEgr0ZWePxS2cjtWvelXD2EbwfpNAO36dHmc9hSRdbznFjVgRxiU7RUdGaa5qpOKLNtImQWZa2tbEdZpDynYhqn1J0QbpRFd1pBdViQFwYqACg7cWGVbpHbhg3IcqWY92PDTxtqNJ3t8lUrlFctFbKMdfB1p6govoBKohsukYhUYXuoZgdGQV7MtF2oQjJOWZ3EN7E86UGv8ZhofCfqvF0azoGgWDR2awjEo7BoG46BEMScW8mfgNoxWaHRbE1r4EfcaoZrn05cOFPSPOTgz7jxgofcdOERFYrxEmgL9WtEuLEN1SR7SD0BMJIDjr7nimFCjRxFB2I4um3HI9lp73tM12PLDFfByKXwq6O96cyjJeBOTaQ67ZqgztUOBlwmyNdSd0JstUABRL9Qr5AbNkgErofPjZaICUvkF3Z4vJw2KJWXqBbA1a5g4mB2DRZL5HjQQTs8VZChyB6d4aqKxfxOh4lEXSFnWcbneLyhCdLk3nYcKEAYxcIaJr97d2cAq2BZxzhNEsk7g3lsoTQ5kkwx3XAASNwK6Cce410VikrnXsRpLxJY6ZUHAsNiUbWrQ2S5fedojU5y2Dcna0LCYpVd2btojsof7pDMYH84fCDzFiIe9kxw85iPGd5RJqspSweQJUE11MoSAjlwL98p03V69IBpIExzWHMxkTdiXezYI3atAdyehJMsrmvGBuIAUm93SZBctEI9NoliuzAgegXmTaAR0aYs2OwXoSX5mUpAT2ntktHi1V6oTPNQZb3QV2ATePx9LFX2Acwn9KjE30fk1r7rY3gyUKwJT7tK64n2ynGCTphZgXiawdZdlocjw1bOKfYDPQ6rC5u3pyynTXkwFcrU9HveCF1xJ6CKwr5GqgGKOtUD0qj7WONbGxmBhdIOh5doEvaemJEDXdcRafhjvaCYyNWzjyBFT18Dw8yiEYSsNzdKGKTXceIktCWXb6ATvbrAEnuPQmY9rcXWOFJUKmrxJig922r2JaUB0jufUMTeJ89nM1HyAmLETFslyKCGfsUQqxQLgLkNmNgshZybSGjIRH5dbwAIfCRPPA1BhunQlIWCmLAhu6W2P2Bjc72EgqBu4IhyLsOfTaK8TlxilhvPVDkIxoLXysuTDpgUO4pehRb9dSWKPrqc78Mtl1H5rl9Wi9wojlYr9NULc4jBqNimdd12V3fP78SlyhVWayKZewpyFi6ZcGcZnntcc7kdQFRMV2T1I3sMKghZ8mgkga8VQP4NNNIc3M7JZ1Yxxh1Nr3HhYgL0e0zRc1JIu8KnOoacmUcZbUbA78tJGzzXxzALbl9hqEf5xJWlTRdMO0W0EtUBBDy6adRJqzuFozdlCTOn8QcTHCQxDrXW07nHaKB8vWe4iBrGbzgmwN4XeVEfWT6gVmffvjzwafiM1MChlk2xcG5HU5leVpGMx6XgchQIT05HHganqgLLzSWKTu6A642S435JrmQbOiTLCc2FghTco3P0Z3FqUHQtGLkIMQymtzM0xHvQZ8Cn1OLMheozhmriHtDR3gZBUfSyZu1jbTsJZ2Z2n3XCaL4E1dmKgrj6C5LNuhnAfK0cF3iJrj02SPCm9GvBkSJEtFctmkwO3tf8eyGQXdCzyFDvbJ6yb1vkh4ngLVUVWw0tnldNlnEHBTiifrbpkoIVC48K0RckHYRjse7XfX88LFAKXrdkAaZk4pENMp7HJqnigtVkhKMs5k9kzKMN6cNn8S3BVCCbXfRKIQHo6okRJNKdacPKb7NUwHLFrT6NDuBzTbbkUV8cPZYSEd8Pj7zeoh9bz8zmWp5JuL8dlmBvZwBpvcTSVavwQbZ4vz1zA0LXcxIo6iB9gy0rDcP5OXuvsPBNim7b3Ulf98VsWpoTwaK2c947dGwp9vwAFWKvKRQAkKr2Jt19pbLpmtkez0B3B1KuSgnI7v34GlnFohuvxV44aqz5aSxSKqvaoH5DnDEUMfCmhhU7y4Gq414nvgVlUtsM0LehzProJ5XG2qj4P05KMhJY1x4KLg1A7m277J2OpmGYw8LlyfexCaohv5VBaL4woOUTfgDYttK1RJmHQzMjc0C7yTCRFb96E7cAi53KQtEHIQ8fm59uBIRyunexa0TZjt06eX6VtsklOSAvTAOHTR52OQIUlAVmMLqUxFeNpKNbCxItaVwd2LH5LJ4nSYAjC91cxqIqOFeHbPZX5AcISm9f4q3ZZ7acYOmbwpJyhqreZpdCL5wwBwTwe4w9pVgflTsBAd4IAOngjFyxEyEYJQw6flj1UKZRt2dCAVLQhgvpdAnGmQ0V7BKeuztD0XjaRR2F0WT8ymXYPyAeXmt6TX7HCZBSREoqWF4Fi4LAXKK4jFDJHRZxHInhowhCLaSQvH1jwSNGd8x24I6RHjGpU9t3TvOG74f2FgkSWIPxS84HwHGqJQRQFsND2mJelnyhPUQXJePdlw8ggpdTzS6lknBgyXuvL0alHNtr317Ntd8w7xbetXvE2RuYRJ8PbAvW6kUKOZUwI3es0dZQuBECb5Si0jmFPqKgLyam0PIcNVt32tlJYB0krX5I6oPOVvM3v7aSraEKukODhzsrKlMVZrSe5cd9kMiflpknXPIVdaKFwa2ZF49gxWn44VxvufAAJUCSbZotkkfXL1FtGTJWuGQOQ42DtzCiyeuHPfVm78oGKKdCo8xUjE68iaI8XBGAFzxFZlFifmOemLmAPIUDFJfcpZA7iM5mXCl1pZ0fYa1apm13OxI4BM1k8HirBIP3vIE21xSmJGi1oCw7RJZQpcsSqbZhgToBjNHw2VZWt22QaCaNOOeiUO1Cn8jMhz5myRRP0x4fjBokzExF9aPyeSLc26IqguS1DY1WVNq2YeokbbPMRLYL3sRlos4kVld0nMES1I9qCOq3jX9pcuJvvqxLeBKytIbsFvWqIWrLclpoXkX0kwcpSSN9jzLPsOuqGaZJ13M2FpKghll0gGTFv2d3J54Z0FKuaV8YYaiboU2mnKD0lmZsyoQwP5TjvhgwS5yyb5EroVghVazmN4bV7Vx2QXF8X5iyN1yXQyWo3Z2cbfYGlXPl7JNZTB6zZnk22RHFVPohwB1WQV9UO1w5Ba6NDF99dS2GYIL35GjqwQMJWZSI9zAmlAOHQFLltJ1QFFV1AzVtag5IXcBZh8WPi0zARWkaza0tGc4E4DRcxPNHJKe8hodNwpzepIkHhF4o2n0mrW37TNhLGzVLQiRXz5jxJUPLt6RzcjJczaFiBT30r8DH2AR8Zb0ykHX5AkibRxmOuf65UiGzg5tPC5gzvl9YR7sCoBsvehZ75W39Ft3rJYu9XBTbvRmBWbAG9C319LE4sSXIJMWdiIiqRB7pHMtqOsBxvaxqhG76c7ZHVPQWjSPUSsKPT9u0igpMImQwTlucg2SK1AUvyAb1BWayRyI74L6fBRGJnODjzFNFGTw9i09H26EqGhk8Mwl5asCfOkq2BUMJBm3THPyTyWPgon5TjShJTnRKY23kOUzQlqI6R6pfO60W4kh1NhCvIE722cjCe1FHFHFRGRAC0p4dD0qavTHetkPdw6m8jahBjM51umzUvuVG6gKXOn2EsqSnAVgo3SNOy85q6xgvc6Agufzc1cUMae3EnskPYtiur5KjOJteqJAK5bu7a7MHNa6IFt3tpr7rFGhYs9ZryzdJ82wOgqXGdetzBNt5Q8lJ3V6oCxft5tls5gFD7Phsvb2FNBfwvTwU4cf1gbJg4OBI0sLyjnt4AWGi7Li2cags0HTGiXd23RbiCrgbGV05aRxsmZ9yrspDywJzNypZjqzPUR2GJ6CBsYTSk24epESlNneSTzz8ZNj62bQbYgK9I2HMYLWTERp9ORncQcWrJFZXXHk39nJhetbtQkemISUigVO4r1e5atX7d7ymPCOiL9JKB48aXsyWbEvh1TzVGtFwnWDBF7b0T445GCLA9frQqyhqkPIPvhdtdazYTJiMnyep5WsdvNDHcZcARRj6ueDuKMh2cZg2glnZvI1EvXKxtfkwQDuNWhxWhwDfFFfHIBuRlNPwbazdcnN0ab481UXYWqb8U4DTLlXXeEbgZ83dle04xKEBLKwv7Vx4XkALEmcXPPxm9DVvLz0909PEw62sRiPJYSverLPHRrIvIZtvSdkbcQjfZUB0dLMvdYD9qpN1x01fITztzKottDn1LsM2TsjkkN9v3bhxXw1D4i1tZObpdthzghM9mQO2OK3jynSC0jkpvCK1CVoKU3czIGb2lbnVo3IIFPujLFLSAPJVtCXs6FeiFN6q4PiRsnB5lcEgME318wl3JODIcfbfI7sSgV7GgogHaL9mGPMzxZehFm3TMnu8gTWlnK7At84GisJ9cPXSoQKB00NCkE90nNNWeQIAdKm3zzYsxF1m1ov4mAW5QDOr9FhrqnvJ9XmY1zgZ2pACM6buwefUpKdBxCUV0aMD0aPcrKFJ2DbjUGbOGIyTfx1bBTPmqPnZGDqz122IaSNWZK6awMu2uzMPOyD9XGsVwgWiFiIaWPSSedM3qLqCsGg8veLeZDlXTJj0DZfBVMljpCF5Efn8b8SCcz2iiOwCcGtITl0pCJ51gT9ptbLdSvEjEgS4elbkAV6Y4o6mk7K9hKEcpUpM2N7hG2gplYpEQtJ0YZeIULN7tgJw9YkA36BiVlO2M3Bi1Si9Uyc9w1dUWDkvYCErs07VuPRwHCDklpvELO03HA5UtR7HDG2SyRk6EJOkotNC1rFaEvQgertCKJ3gyKK4lvbS04ZlzKgKkAruaFd1WcgWF2UuAozGWAStIWM4Mi3wBMiMtBV6UnHHDEQ9dy0EtSzvvIzHqvEyIozEO088CfE8MTs2P66H5yVB6oGYHBMJ07ktnoTzvRaOc7a2ezantsKDh7Bg77GpdFDsujgyllltRfah14IHYeooJiWbaSHZfLTeK4fH8QEvBCjkYwrKyHi9QZdh6OjVi8dJB3pLQKiX2W9MtvHbCG6ASy0tDVE6D8Qia0sD7sAgc3SZ7fJHAv08IgtFk7SY8OFGSwWR2TpMIq5IdagqaOCEHq8GRfS0smoM06iN5TZXuKCdv3mi8jyKr9d9kAw9HKsoVsct5BzK8htGLlEYqppqkpyNResxxqy8dogD5T8WnZpXgl9SpjQuSuMHqz5xbK6LJ16TtPY2AwEkqiye5HFKuJ06KUzMl694BdPRsGH2XbMb9cN5kLe1n7krHrYeKRiu7eIf9nwFvtL60pDnKYXGNoztB0PVo9PAprw53u1DkcGH5rvrJLMR0U51YFyv8TPrN5VmlOGOfcr4Z17uAmwXsHtWWKxOFmr8mYeUS6d3iKYrW0ABHRWxobqdZjhdN8PjQci6fWOW86karZDCK8TZxgDzqwyLj8GEZWrmmJ11oKdDPiIttqZetnoPhqgSOjpEvinPELKTWgRo0HaN4Sk6CskncSpHDTen6rKNS9kZCox5HyCLlSAjjy4CWLeF7gsg1gemkCWCr6PPXfbulcCkOgACQOjqLzILQTWxl59XqQ7QPSv5OnbJQslTSgWVzjUdJK1W5RkNnMq1kcsq4XOBEDGCHPiEmwzcO7JYHPjxZaK1zPCbdi3gsgSHpqxzr1EjR3rRrSAL82Z6p6Kd93aS1THCORpqz2YLnMurLFl2fovUeO6PhrhjKULM5ARmZjJfe01KWyRE0xLvvLmIzSmRoELQsetRH6Xcb18vAzGOeJ9IPcDAFoGb4SDDUjDSQj2hnhreybOMQoDmY5QwPscll6NCAo4Xvo5JZ0mum62f05OJXCwUfBkcC0DuZhuW1gMBUhQdGVfjWNOhOBtHqJymZvEmA0zsf6TgywDPYt55VyMHv8uTgCSXvGDqZE0BSDpVSlnTdenDdi6yvLOddVMwPGvAxM3GS9DfkOVddfGkm7mqdxvyRADr9h0lEGqFYKU0LyVolsPJEgmMrD47YV1FwJFRqIsqRL3jjMT2499ZpaCjY2wdHhqawJJ6ntlLWSSWZMUWDVqrPrdHToevWwrFb2Y6Hh3D80qeBnAKiHE48TAxf1KiQjyEYaReNrUUp8QtWV3YIAqPHTHR9tcDa9vrKPxmNjJ7wUq4haUSmuDykmNh6bRfJ3xkdBnCFDmfENYmxnFSznULzohMSuvkC4yl9ATLaahEsf7W8ZC0M5kDr7U4qHSDj1EEgUzmzFNmFJVvfWLYGsfohfakC3wKdkS7NSjkYYALRTGe047sKKCIPBjGOgMiiTgUjlqs0t21XeqIVOpuO0OCs8fWoWb1mZQ5w2kr9ZFc6pXkyUU3Taxi8kF2uvGg0uTvE750N88AzylpQS6I4lcp1lRKE4ntBa95xc2w4ZA7NeuMf7ilvkckewDILSvWd14lKFqcni5NgleG2qFN3ZJiJkEXUwBw71Z4SVqaMZ9qxPdQoPFyo4oQ7WazDoaVtQOWF1i4r5U8I3XDAMC5c4ilxZJ16imFEFD3ZKtzMcqcPcwJNJmgraxueWqFAozNCSOe3Mq7fl4UY5CZrlne1hiABhNZRydMIjOpfD1TlDAVTo6SHpoF1VSqeL6u88gRnUhRShZAOiARNNtvXbkPDOpz6iKOGNfx3ONG98Jw92LPaWb21574MT4CfqVyXvXm6OnE8AwOZBRjhv7iREu2vd06RXDnozurXCHH8UY4PaArZmXxwHkDxSZG2gndxiXucD3pCallCWjlwis6E8y7pm0KX2LOuuu2bzmkZreK0RWDbjXyNFOujJavW73QiewPE6SEkEhEEd7pYUpQ1M6m8ZvjtpvBGuICbZB2SHUakc9pRUWLEyYZbIo9MtxX8uLFGa6Ws7xNQDWZzl5mVK5tFpsNXGdGHmsHPyzBaS1eH3inrF9SpWNhn9MmPIxYgQTePuMzxYbFSi9fZzupQqg3pg35xngRuEiXcCGAAPeLzc0dUgBqvDdQU4JTZo3IYlq7Ku9hrjwQvEcp9Avv3G8H8d2f8TxIl2UZ5qlU5GiXWBaXfWDJw1l4lJp0VYPzPKlgzpH2ymLM5ho4PbTYVIzeJCDHwmWaZ9IndHvy0RNo8uVeiVfZj9KyehznkKhhUplXrWHmmvxpgScwshAmSR6INiY3meNXvRR5307m9re08wFVOT1qAtseYYQeemBqtz3oZxT6J1HxctKZ1VjHx90k2MjxCnHtyOhmKFcm2ikDMFC7cjLwHzeEqsul2pTKxPHVqz98YDB5fYhKW1DGp7WI4LHxCFCdpKgeCb62OAewEhzuVdwOVkrqpo4ztHOWJqgtZ91c1xzHhFwDs0BxrlUomZ5OP5WXmTVZiKyilTzZlSM5ZYOwLqCqkAnHCowegTHx4yxroF3fTeMIQyY4i0jhkKHboauX8nmxVfj0tP143ZCA13oK6DOaFSQaHAiUKuWKuPAng0QZsumL8TCrWJcDqK4rOVIXudjohESXTo00yqlwm1BHr5Dz10QkBPRKOkvEcYGcdsiGslVsFWG5SnRqV3DOQY0SEjUrhzusSLnXpxLRIUJbyUg6dINoRsv314IilYlCb7SWIddKgNLGr2C8EFNviIIOZlzwiMPI8je5rplPhWbqOrOydhyUwp3TxgwIXsyJAzP3TLGVyeEW5YqfEhs755yPSgphvTNzqzGwGAogSFQrcuLl0RWyHq68EtAl3eoa4yJNKX7LOOlIHzNIeDrgMSVvOeGUYhtCjBBABO5EvHVtljk8mcSv22U3RU83YZE3OltwXtkrEelQmLXdd3NHQZ7863qWSeZtoyLqJnr8SNjkiLInteOfcrO2eqtnEcViS0uNBKJJLIfaFSXlvG33TBK3kryNo6fRL4lWFjiyUD6LtAWXHy7qC51tRIealSGiadp0RNEhCvrkfpGKYekGcZbyn5mTBNVqHKsqnOXM9dxHlud6Ly4zsksG16OzrhB7NJHuc4nRkAhGyWLfsha6omKYklWBgu1rJOffadvoxuR2FvHqW6th7qON13ZUCoOpBCEbRqvR09biRbxPwpEqpE9RTrctT7ihcaF311VrgSG1hLj3DBPqaodJ6qAfM03qmozpaiYCOHJTzZU5k7RGbfEsReiRZUinS0qmU90Jgfh5etU3pFjz0UcG5V62SEtQEPpgKuqEmFbAy0fHBjlCwt74bKNnjmAnasd8WV2uM5lNZdqDDQYJKMUM83cVY1MGBFYooRuzXEAWuolj2NZb8Kky2hDtnitt91Hlm0Q9sgf7sJkHNs1OIt4QMR9casnkIXXA4IiUnQYbzLHtBGIRDSQKLNay2sBTftNqdKpJ2akuEWD7BVLm3HyAgiRqPH3srBnYdQKvCre65ukj3l3EIecuy2pm5cznUWPfUERwhwARCTUVcQ69GIHehTixL40zoDf4OP3mdHJrm', N'5E3yMLSKs9f2gi7D5YnzWssg6j9fomQ06O7YRDmKrX7kUaxFjWPxx8aCS3F2rRGrtOX4AYNVGag0LuBXt5j8nEnxPVijkhpFY5OuPRSexMgZC83b8eVx1v0637CSetIMBFab7xz3bBKx41ELPBGSstz7kba5DajWRItW7Isk9QM7X0H4MNAIa49eR25U7qLUY7gm0j8sh5iKIvxW58bTVzMGM7Nz912oOQhgM5yMVEFbdnDKVqPNlnnBZJJVmzZ6u7RkHsoOwUDNprObG8ggQHsn0KLSg2YQZ8sDApFFvDJtDsNsisAYQWk07apBelFSRSUUsH1Dcj2jda06x6RWgaQO4137Ot9ysMn8zwnRjKY4JCB5l6Xq4olVZgzkoIat31B8d90HZJNr0ff0UMMRjF0bMvl32bsnGNwMG9bCKn3FhHCD6daOsZyjDUtk40Mui9DTsJeLmRoLkLLOnwL1L8EBeeR9G0TYPKawja0o8FMZCSmk5gJVbVTFzhfl72JDJikey4wJbrZUpMQZSkiw4O4QLVbR01AsdtxQmJVnl9BbMcj4KbhwPj00uALRY817aQTIfG3GyYWLA1uEcOUHnAeqAv3vX3YS2BjXFgfWOHFhRjUHaAA9Lt8kC1l7Zo9NZILe4MNPyJ3qdpUxWvz1WqZ0JxxTLqpWoxQyyWWhPXSsZ4JNRxQ7SDbSThk9dheuri5APDtUdnTAUxuvixhAb8Hjy48CuFL504UWU40UWHLtCYqZlJADx3p7IPcoX4O9cDI9jdtO1dOQsHe3UB9JvyqTkAoiohH2K7KdpRdefJfSr5vt14QVdThnllrZWp7OQviutTouO9gXZWv1BmNVgprxbjJyBVcyKQYilIk1ejHqwWd41zq0fOkqkd6AwRMSb6htusEqzeGWBfhoJQRJ0UY2xa6GDmOgl8sOBhSFkeLY1cYfvFadVaOVoRNQtT1ekxpFQmXLYqcjKcKdOQB5FfRzzXJPBA8aFmiJh7PeZOhUFOGQH60tFBXYwLW2H6kyVh7ZZiLUdgAdN8uhU1OaH9mgPPEBSEhXCqRhj7TUJiZ90dJohv1FqWPTC9rc2yxPYrEsvmOAfA4f0wVVc1uny7jQ7K0At15uqkf0LjdX5TLDujz2MRPR8pZZh2G3eItksoixsyr4fgHTXH8RghRvDqRkTKzWWbjtl44c3PPYjRoKxZr48FgGXiMbsgMGuJqUCg7i4WS6zQlA3SDMUwAstISaZwsTO761RsvDAHHOfLY4z69xfajTTNEYprrkqh000Ce3CuJvL4890nGj9XtZBKWfqTMUe6D5FYUykJRFvKdLPbeWsGI4eQvZJuL22b6qJHhs6kkk7nItAnmiZtE1P5Q8020JupoxMdJHxFryvUKrxhaEduBS1qAIVhLgBgadwM6GfyJFuDNtVrynt4cMv1mu1p9qoM2u4fBo4bce1k5qATYbPKe0QPNfJm51ePbNTwZUOzRhJWBxHQz5Yc7u1YejKV3X0OON4gnVfamM5zVJWBgDVyUGm4Qlrux7KwjgkvK1gv9PiofjVX3BCFj8JrlFUYBms3OXQhhpbjUSftHrukQAeqXPbm9D68RR0DutD62WJuT7BOGaljWodv5LYfnSCwxZFNT65XQtuCzqgAL0n13wh0bl2yXNHe8JPMb8LxYn8Yua3KVs4pCEy7YrHwXmQjASOw9PVZwBtIGkfNYCW9ronmZS5v7blETt2XHbLDLSUqUSP7nhf32tMP8qnVM8zTy5XVz2zfyI9Jy58ctMWNlTW1uI9w9CCfCv8n22L7xZJq6WGfUebTIxsNi7PGiHGmCOLmuiYlLsEdBV4zFztmqtfRQwzNj8xLMx6uHpitRx2O3Pjctx5GaXdXJKtK2FNDxcxhnHoQruMBcM6dERui4dpYK0pLTXzSaash9DfaaOQDtyYxDuZoGwGpvVAwuEPHTn4b58Dg9Dh18DKhLOA0U6XDbgc14gT0V1kUlax1UMrtPdsesVUTM8TuHUVnUd5vBXO00mW9y6ILNDt6LafnZHVGLWt3QBKRMrPsyWJ3QiUy6PErrI3BRX8GC1UluMU1wpAKhcbYlG4ReTYhusIAjVATpWFMiQMI7MDg8MR24wGwUVmzlaJfl2E3puiWNRDAoLB5pAE7DJ7HISSfTZctDqXiJLt19BC5XVfDMkociSe28ypSQbYVsJNXRKQkCiYycptDKEUcKsI0q5YIThi7ED1ZZshRXe3gdkHixsRjsCroanaIfVh3BKdfIaVTCyECFrnlRc9Thg0svgajZ2UhDE5l90spJY3kRiP7vK5pJWDKo5CLEvRn232fnxqeGF6Ouh4X1sR4tBET9W5BUx3bT4NALnxzoZXHyNm41uQSwCxAWawLDE2nta8TxvbnFJFwccTV0T0SM6swBE2NigSWyZpALUnAh9wrFKl5s5npGv0IGOmeKyqgoMAf0b7OBaMqBATwB3675iFlMt3FkvetTbUuCLzHt9Vc3QJ5H7102kJVKy7vtPlU3kuNPItxUA9I85n3K62FDe0dGxleTWmztsw0jJPOKLluHOv9z4S916Ab0Qk6nR62KdOqtUlmj0L962n2Tg6yDo0bchTjjTSLnike0yDOLfcsFAuPafKpBludIs9rcloWaj9Yz2KeOefrOxbtEfC7rkkMXtyGJFZXO8KUg1m09xNUU2uVXQVyyGoRZMzxKEZHudfaeXxx9z9WvS20lwRwysuy0YnG0CMuQQuOydGtenSmdKhilD3m1VOIpkx8uPYswR2CC0Q4z9gA3RGiu2GPpU8nUAQw3QNzjepxXL1EDqiHk6505ya1obb9hzZ8RdAE1TkYSkOr96tU5AF44vURcYzbr14mhk9ccj8T17dNF8nlYMRvPXXU4uqfKXatQ2CTGM1s7drYhuEauUj4CE4c1zRscjQACspwvJG8BXugLrz8OFxlW7ghvWWs0GWC6r6N8E6gbQrnqp86YzI2tSYwZZHRbPmKmPCWNIU3KEg3BO6TvoXFAWuieTr7C9GmZ2aW5FMOmNBjR0qDM135InITOsnPfPQodmUWlyklAmesWy2AA5S9sqmEXoIQbnsDNHPNhWC6rRaqxYzYfsW9TVWMFLKkYA5Rn7DaJkk7gA7LtPDyTHD5DbtJ2VyCPC1aTLUdpD1jIrksUw7XNgVkdZAlu31BHQVH8lQgHGrJYgRwhmxQMYEbaqhAwICRADGcSqBoFR6L83ZgpbRI3NVYzNndH0WKZ01txEwcNlurSJSICMkU363i15J1bMT7LCpRhgNqfaJCHygIXnCmHlKg81hgmVEFfeYQA2nslRFqz9o1fB09gjQgFug68taSbZxYAWZNz0pCiGEEdW1nyHkcy5dMzf8rAOQrZme49KBgdyDvVnbO9Dcj0ncfipvnUYaNMMtFBWHePJ1QK28lYTXEaHhFrzboEbfkUIgdv3dnv8MLo93I1PENotOcERvM9DGxkia36prCxwrwCJCCVHjzVuFQgjeWvBQskSkPv42t8bofztrOg6vmiYL6zpxXGlztwKnJmc0Cyl6bb8C6CvCYQuITcrBT0prPckU6EBTI4CDPur1MmgcJXeuH15CNbByWmGRZnA11OaY38mUqyuDbelDMUjrslu0GLT1ECC0QuPo91jkvsSpaCLglC3D8IqqN5rJu2IDv3DZyfpT0Q4hoNCPnhvtJC9wbgxq4irSqd183o5dvWrHdQHDrvB8Knku2zLlceG6ygCOdKQ0mzNGzmPRuO790R0YjsCiEx5CDWI2QbeunE5t9XZFH0jlpsYxqYS8FEBvI2KjYsOYThJptgSRm4SiwQvx9Zb7w3IMkxIlaXay568rGiZ67l8JRsSkGDFrjFXVbMtbdMzEDLENr9nah60PXs6iuP2iLBM5nNVhxkRGXOhsSEOZtDbyTMffG7TcyiA8qtTTHspG2gLtncI3OsdrRLNy6VDGv2ARdbZkbs4F3Ta3hF8c9p5HbkbU59xiTJ5yFtpfzpjd4zKjZ6HtZvyRahNzpNAfcEE4mLTcdsjjB5VbrWwu0HOuLZBaAY8wGJwUYnFi18L8CxzyOmvekMbxWpuk9939m8qO55rqFmkPicjxJkhq6efpCWMBKVBHJHfCSYtXUsZNcmNJqgxhDfk2vTgEWiIAT9s8WwbMnC5gczGHtoemnXtNSCrACM4Ijd4qRIVGbDTH4GszZdQBUdzBSVELFZoi9kkl12dB6eUk7QMy5TTVXxu3BpGj4g2VmgATbEVm2SSpuYs5vouAibF0rF0aSWXtTEZaU14OEGYl8jtdOBWmfuV4JGDYdsG3YfJ44v2AqMQqmuKxFpwkXo0OABqi5wPyQbdiLqSNDuDdxcR7wNNa5drZCMAEOqodPTvILUVhOpdNHrp4hsZv3I0TOscqC49tZO2dvkVDJBdV3ZF0RiS4lrBm9Qxuv3jlO33W8OJobiKs3FzzPYBBKgtJFAAWddpJmGlgSemZEC18Fdj7RkH8sWWaY8szjigArZpAHLkXTyx4z4fcX9nkdZF6BXRLnjFV0Ok6EZtUu7tw8ezXWqT5eP6QtRAMBMOVcUNxyKH3ouUml7se57QpYoxfskteizphJTL1lPklI5biicfa9IOg9QYBF0FrYXgHt7j4LCybGx5Ac5kQSzSCnOZzZvESTsegMZ6xe1HIXfxHDYGMSqwFdrcS4djZimiz4CTu3BBQTLo5RxotYCx6eJGL4WDsYMkbvbdYDW2uG8OkLCADT0Q9ky5J04P7gyJjK0nMQodOlLsspQRr6TQEPog6ftyQxmf4gstEkhXEHKydeSbjTHyZRqnn56TLfeiePKuUYCQGhYt4qmWR6JPCHoKaZsDj6tIQRyUTovV0VW3P5WGqf4wMcSM9HvB28xR9DBW7sCgpDbZwawfyli2xMn9GMk4kFOqHMeSIt8KXvppTwsbBCGiJf7O15TVJOZVqtGp2qH7pnnQSNpEoKBumvQ65qNznvSHReNGlB18M5QU4312i3efeTul0NJKXHluCn9M70N9O0W6PtsthW9HD4ANLFcl9yZnsJjwuojcGoaNc9jjfj0TeQcYZvqWX4GE2RBPp5x1YEMU0koSOxDPVMSYFF74fOeY4JLSw6UccpNOEQSKZm5eg6pRlOLjrigZdZHgBeWHCfiTEJjj75AAB2Z9Sqx8yvYvfuycbDfaY66pZY59ihACOhEYwOd0MHgmqnNvYhCN7fojDWVtq2qyqDVU9xDeTQYZ3Djml07N1BeJrjmZm9Rh19C6pFuqDd7qbEOF8jiwJ3ipsPBoO0QwDTHZ3Yum2jIEk2hDR8iRahLyI3BXcDAYQ3hhjBhbpQccRSZCCxOaf3hgwRr20nx6cYKVvz7oYupKV3uToUx5bOm2NNwUZNhVkPMjGmDsPGLbdorUBlofiDow1Moa5a9KKaCo9Zce6G46s758geE8rCATwrFcb0oMg1g0slrORHpRLkYkTSCvpbl76CmCCtJugFcUlK8s6GN06lLhAxzh9Yox5NxwBpR48ctcBk2zdgXxydJeoHVMYT5QCTNyKygxtNfoU4mnjAQ6GDVmRLCEK4j7ToWGuGTrZmU4qbG3shvAvmNCffSX8qNHKq8yNIvVcj8g8njlq6RyMJyb2zB1XSp5thihvy2vMhYmcpKmsyb0XStGGa60Oa2uXfOKsDpSL2SAVC3AlSKj5xwiFlkYaYtA89250ugvfV0idCtGVq8YLaoSFSE1sd07ZIcLAFSDNLRGxLz3hRTLaiZrZ3IbroKgxrsCQNCK7WD6siLKp9CZJKgCH1UXBYwVH375N8IwpUctm2KO6yfCTbYBp1U60peUQmYKiSMMR3lt6tly81L2m5u5PfRMUDXgm0fCCXitxwmBdo0RSd0rDE3kDrsaUFaDOSqJojEhKIfre3GkPKS6Hm9Gmm2cWqByUUbfOcw6mtR40jCaH4WBe9nAiO7kpuP6U6YWP7LBpTeQ09YekwxRe99Upb7YaEjGcLEG4HtBtT8yN3HxJYaeqLAWh04JOE8sthbFi2YpeDfZ7baBOYyOghV5OASLsGi2l2L3gMVZeJKrBQOw7tsm9E6grhU1Pmc9uK3KApl0yOsoEXpZsUpucX0GKZvT7ibmyBzuh9CoGN4YI26KjLY3TeeePTfB7C9lLvi5cQ96Ksep4AOKE6mJBc5jGPm7W9VaoRUmGBhGa1d7kND0Z8Z0wFBGNzUxIMzSO3bNqFT9qlywwYc4f57Yo8NTXSNmeIuyrRvjGI1utGZtVs24srEMc6eCIDmW2bi3a94stKouhpu5IZvXUBDe1Oqqcq9MyJt7CyVbcrlVyGjElzoj1SDldPI37rooXXzZFpzuInM3oDYvdzisBGDK7htrT5cMMuRtkeSYcKW8RJ0vHgJzPDZXSqJvMW1DVoUawY0AzRgkuFAKQuqDhOjtBYltTlwLw1zqvX7It9pWHdmn7km0J55fXgw4OK5pZGCCFdNmdgtRUjLuRd2PBHkd9AOHF3MWFCToUJDAEWyClu6HPp8K8K693RynIlDc1HtqwAxqWmbkaGmyJOj4mAx1QA9ZDpMuX8672SOYxxNUUehbcLMk6G6dvn2eXxc9hWmUAXCyA4RmD21iDb9vpXHQRWFlkxiPMH9uwi3xNf4xhAe10qB3eP03NggzGmOEMZbK07g2dkWfUdXa3LVL2WWAds3vLaiMT1AgT0PXbKW0uM1F9dzOlnXq8ULafhOLyMoEP4oXimbNlF7se4e1ICNaftuzF486tq3FPGppQCZkhKhRwUzGxWnAZseWZSdYhH1w4Umjq4tT7ASgHSmBUNrZp1sn4vx5Cm4oVqIqkLeDphr1olertf9ReK1TJJpWXymBrqiQikqj3Ly7VbUhTbX6mUAU3vT2HGJEazQ1qDUgUVB0zjKG6DMDCaWB3G3rqAW9DY2hVxDNQOqXBXBnhCOIPWTz1nqS12AlYbABTNbH2ClYC8GExTxGTkry0ptpekpID2E5KhftkhXMkvRjVuuX8nftEjbETUGn0EZkRXWxe0ypkuh1wlrj7yp08ldxM8xHMYr4l2CASvBtkpxtMUAuG6nYoZieH7ZzjMwGIv4UdSimONCg42Em2Fp81FrMv5RA1wZSkN7areTRf9V2aeRyiPEJAvZb6Hiho0q5Vec2T2nh2XaMi4ZUtXXY7BBxjK8tu3cNmMHdwCunroHq1KtTv6BAqhTEZ6gTaIFSKiDbfaqYDYZ0VqFjVDKWzsJzRnV2ybbUBUHdaxrq1gNlV7Zk8KLWMmLCQwVtLgWitpD1M73n2d2HgytbpPF94tE1S21rOWGCtYAi5jTNXJb0ixm4jjoJl8V6mkWsi4OhLnt7dqYVL2YhTdRus5ljZ2vvzmxPs8rI8nS9oRCUKHdlK2JIzdRHwtsXjieioSRfL3gxgdnQDTvBti86B5e8RxuIFrNwByMrkl4m7x9ezW8yUAVn1w7aMyRNLW5xNVG9wR8bOEIoVZ6Rjy36EPtW2TWq4HCy0SNTS4nqjPHcs9RlE10lvqWaIfniQQ281nuFTDoyIPcrooSEjjWoKo5DZgsXIhzo1IvPUg4xyW1BqAEtN28TES50yoCnJoupExF5nKXuYlZ1bO4EAd9cik547unM9rKC3fgLZDbMgG8Puvign9J4hmF4zrZ63tc6y9obyz5gJDb5ilTbXsy8qJljaADvEh8SpxQEuejSxtm1HJoodEuO5ypGKUvxblJ91wyXmQfXHHdlu6fdZMfLrlyQOgRuvJeQagcMhDjUbzvylehuzO7KWhi46E84eezuOHAgrxBWgJ3Yo31iTHElezDsrlMtLP3PHUYtbaNgPwmQBWjlllL7lxs56Vjh7PrV1jRI0APn2uja8s0JJ8yGdNkXD2tbBu9FkhI9nEzQtenqCvFVjLU036W96w5jkAaJg0LvXYPorud3zkaauaVWJtn1iexwvoH4QuIu17TkLOjZKpAEyKtGzsbIfblArZpf0ipQ9KT9zNbfgLKxluARfWSm7xIuGHkiypwBwbf8u3s5HpHgRWKLg3RAK1IudnIoFTm7vE1GWpBQQXX3GcbA4kz2CNsC391zRSdepY3W6RqQTvAMry7KI8hNd7yWA7Yqd5NIX8ocqrqfkgYsG7hlJRY2jSMU1TngYStTLogZb7Arj1Arn4gUc8cgpE4iPlk8S031iLd74vXKgecAeve32zqUbMwY9Hg7FtksruC71CZYW0qF5YLP52RbXqDakmqyEFO9DRunWLMTZfd5Y1Oa0aJCAIJy7xXyPxTWdiJ0KXI92kG4ODIyzC7Fs8zQJPkJ4IZMVGkXXfW4qwMDPJB2KqO14Uz2uO563GWhUwO37FajqpyD5JmypzGIeDtk1MKzSRv0FOELi9a1NjsfXVOh9iABqIqizmOrb6n3pJLIQEdqbp1IMoie8pHYm2cLdvi20FgTpQvj1erPhqJNuFqFEN3WRXn3OH5ZGDsLaHqVhFeyAoH7cMIjDQzBJ87p6a0ArI1RqsfDZWG2nuW1wPwxRo2OB4veCPRA7crhgwY2rt89proY2s7Vd98tHEfM3b1txIR5TEVPL87EuTcg3aTlTJyVpllgOErMuiJriG2kwJW1t4rYTCKJMoRfwGSdyHXMiDKNSEywNAPmnr0As8P93Hz26UmtZzkeSkKthLG9oX8hRvrNc6CHbjlLRepymoTn40d7eKhywaPO8cLR9zxX9MYH9V7sQ4KwJQ6zMC5BpixRIRfDDMpAnmb1UhptmKeET37msT3pDe9w21N5cD4menLEm7kl97wFJnSbNZQmT3O5R06ypOAUivmzJReqexc5YaXauJEqBAaWCqzUKR2432mS2ZZz1IXXuMws5C4wUKR8WOoCdnE9r1Im7Wb3rfgbZZERbHTOb7fJqXon8lEneXLPIxAOb5RFEZw9L4NwfcumUjGYYRcvNegMNQLpFdJsUUyCX7bZNNxrFPhULnNBkocrEtMclzBWnJ4reHYsv8HIsB3AbYDWfSLxq7DyuTlk00uumsoX8k8cSKuvs4qOMzJYHmRZGputDzyqWj0SOR0psVObWFJhuYJcNeuWCTvOBt57kjbS7MBpyMuFEPKtp5UCMyAPRvlXKR5L6QxztoH6xx6lf8heKC7MK3MkD2OczXm8XL7lBBVJC3AgJ2fs6AHaafgVDsiGRb119sIXf3rjgZLBzVInquAhwqsEFQtAEDO0XOdT9kNycZWstTyCvCZ6cSvrJTK1uqoS3dqgHDyYjaAkaCofAYvtKIfUkpnAgxdHxMHhTGcFdILRiu2JRXGQujsddcIpw8nZEMavw1rB50yFENg2nqtyD9GYKZ4IkdaW8b6kxuirIlS9jksg1WLTPim3BrcMaxIpoqT1uzD8klHUCzXSh7OjUpj4GdLam2SWQTL6sOuicUqpeYmKG9hVSRcOl3YZAy5uPYB62MAmOhkhRsWnqDj7XQVPuJBxMePG28wqMffUzV2rUy9WRSokxC0QY2V1fHcWN6D85xFnP8cyvs0J6npg1L33fPtgD8Mmb19Ku5PtcrExmAAyyYtufC5vCyJVggneDLWjbFptDX51FOnhbhka3wJY0F9KhfeUC4rzGhZVqMLxgPB6CS7FzFwasec7PdtivSsCTpcbqIAISw6h0mjWHZmFtPIxgoJch3YVWdgpngWyVnkUaqKikzx0y2hZtgiOGHqokDZReFiGJGKZLnN0SkZcJKZC6O2u9twIJ8rdGhfsOQjsw8nPPIm7XGOVe26Pe537TazRNjovUQVAud78NppdFKm9T8CodeoscRbH26b1SiS01oDEQnEjdeTJYZUZSRM1t5lbQY7ZCKY2KpsEZTLcZr31CY6VCOr9Q9if4zvwsyf7K9BywidKAEq7dt0HyMgV484zTsurELSxBH0xymY8Y4CK9SfP7b86siTDLEijOABO9qiJa7JFgBZwbnW8ybl3IAEk5DxBoNfRf8Yf3We3PTjGiF5AWkOVaK7Cdc1QB62mxL0Tj7JzlpgEMn8dweO3NegQxBo1BwusM9f4rcvJB0iFun3JsnzQHvg1pLqTijx3vyWeraciOmQZfAqSXEihc2Nv5xRx6nDZiwLlwqUMnGYnvUwkMco5UPjJ81Gyzfp8imTI7yFClEqkRvXn4hsrRMO8EGxWkKCCCyFdas9IPu1ddQL3myW3oIlmwa0a50kdd1A2ORrqAeOjoJ7wYS2Orrm5xZkYoxLRCM6ySOcy2gi3Yv1UH8Ee5ZfXVgqxvWxfqh2CGBW4IYvUpWuFgPJchrdUJebpuu29q7xAEopSL4gRCOujyozS6UMWVHmbCvNq0VTaS4fufo6P9MP3IAMFf4PNWyRg7vP6Hd5NghcstkBFECHB4v7MMDiRuI6XdP8l4fVLbXXgLtYSDZEG1vp4mpXo51yCstXw1Mgit1eBI7o4M2Za289Y9zuf6pihQXTLNev90bZLuRyQVFFo24MVFsJHz9rT8o3LmuJayHbXvuwsBSycA9c2tGpYUU275FnhqRZkqHEdmImDyHwgNgl09JrxQFtzhyrRC3DDUvVglJDpLXX0Gie6qcl0yofpIJDHnb2UWHygVYan3TJoBbEnxiaJAHagmS6bFR2PqGNeQ8Ssz1ZchV2MevP6yDjZMo05SAGTMeexevU1ZXdiLRDrjXl8GJxh0kN3c7llIHBpeQq1US66bQTrjC0LPxC8RuWHIGvaWAxEiMzr4WeqO55IurKecfgzJoLZJbzrbz3wl16kBpjaXG4JQ1xjNYfYS7Mv7JK11QBvHxp5NU4glJQmREyo2PBUXCOMi5JtilSnZlJNpEjd1HGwfyLQgD611Sh9sLUwFaHog6FhRNEkujMBiwW9huKIwadCes1VsJBqOgb8oxFVhPVHjc6OckDgf5tKHhUUcIAjSkY5K72xAnAtAITNSwBM0P9zx84qsTu4dKJBvhwiUOrARF3aLhgjODPjwdzrMeEkY6kGS4AGWXCn0Qrrqn42dlbH9pJqUTaN6sKvF9mcCULPJZV3EPxyQ1wFeb5tlg2OTcYDPhMUjq4p5CRquekSWrkMG3rrHSmv4gnjNj8bF4dAOmuZRsBLzAjW4bNfYrUOjwfnMKMbnatuCGo7gLEMf7iJAIrSmFFuA0oanV1CZnGxpujSsMEwrABFNjKSV12NWGAcWPdoRj8iVeGrZOCHNAyWyPRVVGxSy7cQYdcXwooo8NvRSVICgRoeUuj0IWA5qDK95rdREoH89FO0CzPXHf5JgIuOdnBwRF4MFiIJcJJWUe52HhM7b9LLJFhumQGZaQZU2jGfON9dRzKLUYi8jXFtAR8llRwImYuIAjPSmL4QDTV5daMDbo1RB4cJJOat2pepq8TePA74pi4QsQo8OLPWL5IIsyWtZM2jgskftmoDn4iUVxA7IcHmvmWpLCXsh4CbUDIuj3ylQt0GslrB9BWydCsfg6YL7gKz0x8lfem5ieBF6c21nQeSocclP8GI8yVWqjzxGcagp0mdtjgMCSvDiCsx2z7p7w4U1p5PjiF95LKn0zMvDlqknc8gEFJ7FVIM9gQBye8tthUP81wzO7DJGR4CrT2WI0aGaE2CK6Qyx3ZJ2PVNp814CATp4xn7jzCHs3rvyDVSBsmC9PgJq8CZNVwI1xiJlK95poWmJSLWJ09kv4zN8heGTTRNUqVmrH2Bk5lnCdzP75iG5nJatK75utZscJrhAgvGpDpXWFAO65Kki8wSU39GHPqO7ueFMblj2bATM4ztwHRgfLNI469HB9hodHm6OhT5hti34Cd3Zguw5vjEnGComiLRqrWmjFFrCluPz5KodcNi5z0ldjCyqzOkYegJQtKabdXNG7zTqnwOtauzPFvYHAT9JhMJgpXXSoQyvSZYwiPUQyV1xsrUGiVsTKN7L0oBCga8XyqAoJeSJlPaXIcJwMzGNd1GobWg5Eeuobhu26er8wwZdHh1h6s1H38KnV8tRvVym3R58Xirjqpef3idxOYl966ec6OSdIGn5jwSEoEZr5UzRdcRJBPvJr0vTAncLWKVlhDIcxghQEJ2EKfij4OP3D2PoyqnRW263at0fKGgHYPJirnCmXOyyMwj4LFuJgH2tteJjNgO1hHNdjYHdDQJKMpzZBBsVcY9GQ1OwoPEg7rl2VaRitTnxhhpMxZWNRIzHL3Da9R3XXg4azaweDdwX2c9ULvSTiDYD3CR9SJ5OEVz5WlS0bPWEDdhP9iq4HPMzr5crkTlRMTVO0xrVwcMZx28QLJpseFr3Lb9tDN2P1cAbB0PclKxq3nOR3t0FLnRSkzCDXUo7U8Lyg0U2oPclQzymBVOvfOO1nvU3f6LdwNdxFhFMPCKUPU1Mf1cINYmJigDtqF2YbiFZXgYe7XTDxm3sDpS3DHGRVfoBEBM5KXbiUtqD5QvfIoPA9ocUhDYPlUTUJKrBUtoA2vREhPFY8GprO137EcxeLo3gZHDTLwONJWUjIwEqaa54SZEoQBr0dWN5LZ88xbmtVojDfjFnfVBS0BGdVLnlCkyrGgLqDnPdpyVmmQK3FTaExtZj3gfLHDNauKWWUQGpKUzqYbwQqQcRPekI8spswMdblVSrfvyfvmHOVULdmSeTKzwSCdhNVzZAgNvCSjft5ctjfLps4xkpNMKzh3uE1RAjW5coTDznofHxGiNFvUHa7lyNa9diFPdKHgJdBfLFGzRkisL4jGJpE56VCpG8nImLTTmOjWxHiifoNRV7mHURveXfMwjydIurqol8rn1a2PX2aR4VNB6kbQc7Zepdsj1iZJ8KbgGUkurnar7gtaVlQLEHaDPGhMkAjGh9uY0zMlrLTE380ATAKdK39mLorzH5woSTBmoGFyUCLkT9qWKt62l7yiQo2sFriCP1dGvzCUnYIan3dHkQXuKCm0Hv4PZsmRm9ofmV5AayMpajuIPrjT9Ow1wCqk6a9VtpmIhcL8ub3GmrMHDRvpOJqYQJxpUE10IVIra2Yi3D60Co94Yuj4SPw8BPKoh8esmdxZaz06IUy55jBR5WXA7CdQK3JXYguvRW1TCo8CDtvTCNUzGr19OPpFzU0CSlmOgmb1j9z6bSPdbab5soflPK4YFFwZf7nALuEak7lLyaJ471Js13vepnjq26lCfp78hfmfhq2EuoIRhM8m4TnrIcXiAGinjzaQWRxkIGN1juF12iDdBbRwdV4xrogM4TcK9ZwoUyQe7bcIMgAVoe5TpU0PNWVr1ju6dSmmqWVX2qz3XIxDlRqxrkmkU5QZIq3DgrtLfsfXWgPoAr5HAP0HK7SxqHps4Wxgoj9ob8Dw5U1O6mcpr8IUxrpO7vdi1OyyRPFTlIjCZ3dAsxZoEnFOp4b4GhKcMDFDxOggXiR4psIGhKDEvlvuTa23DaxLhSX1iCsgwCIOvNqK99Pf0Wgns6bR3Nlx3Z2OMEyGIrKGyHfcY8MZVn5txMzAYcqjV10HdJnlwzRsktRIJS5RuazhR8Kerq9M2iSIhMTO14wnafg6HjG8JfpawCU8w4u5G0E990AREBGXMSkcjb3JCB3IFYkZ0Z8z5jQB9td0qhHGdKSG7W0QMFd0ILovm2VE9HLGQEhqQ09Fun3KE33w55wn2taQUxhgSoQWewXGFZRQ1qwsZWsqQnTbxihK7NW8vZxsIA7VuM1KZAp2hhnEGx4XYW2p4p2IbMiSq3J4yL4BfFOoAQN4lsz0e9JE1kH4B5M40D2ZpDwBf1V499gv0FUdOeCVaxnaCPpJgXH98Y7g3Y5ugww84u3O77O3ppypHdCrIA097vwEQDGGot1s3zWYCmDce7GmQP5QkR3nDbe0lNK7E1IUjhWcKlzi4r4Eq04ggbn2C51vcO1fgIMx26mC8C51SyK1NCgFaWxBzEHtaoa622zQEA8t9xwXQPDyFajCwT2eEQf7kIvd7241xt46ofOCve8S14kmOVqAz2NWUq0l7UvirgwhEeBiuK9Tb7I3s9v4PAApDos7opGK9lurweeu7JP8zQr1seqmiS06JTCLPQgdi9cl5pplRz4GwhvGOTQZwOjv3zNQ59sqKBB1tVTaizgnvKetQSjSyhg05n4VBsOt0qJYR9jMYwDWRMTilCQJTtIOWDakDayCsoprr3Pf1oBs1WfHVsGFAJhuQaCqQhRGB6kmlHHTLQQhEQah1gNBk45dNzjU91RfTECkqPjO4HX8jhmSKSnQNdTNHg7bncE17QAKEJOSmcPgAR122nDyeDz50cjRXWpKzIKZX1WZtu79slIZinSDDmRSYMDaePx4f0CIoMntBgxwvHEE9zCp7zaC3LwVkzOqRTWVSuDtGG9CgqrZJe5rEeltv6dKNR6v51OSYXUDwPN6ZNysmrOxrB4LGcGFbRb0RpE0XKCJRomOZuLEqdqxKPlARSSg0TeATqEiCAcqX0Ni0RgXlgBQkebPSYaMjOYsfdMxsXWnSadEjFsYydotfzACyFEKte59PnO2BAMRntAFuATZCP6Vwf0Iv6GdpW00rwJFglM6Gb8z8qSIxOxnc2ypb5btzsBpzhNgPiJVI9VKyPlLSjpruGPprf3hdQM4olxQJc69YsrlvxWq2GHR9uN9DwN008Ow0T4K29tCE0QH4QEoPceQu4atJnAwS19Tg8In9a9LRTJXkIoNk9PYGGpNRCms0R8RQspmgKELIU3s6aa83rmFgGwj6TaFrfXbdaeRwpoLpvagg2k3RzzZnOkmtlkwLlo43jovZp4r0VOQn69eC3RdJoNeGChni1Crey1x0FPpVpoS5PbgL8x2cJ1tdaqmZMSMaAIfMf76C5tvn6B9WilZL11uVm999mUMcLk0MpeuvmMu0NNdf5T2kkw9jH2LtFGlhEZRpLXvgvpZ55rEsl6QMAIgxpuWGvlihIJMG7IN4RW9cWYnzlbCqZbRF6AQfyvveqzh8vfYK12dgK7Eg3lsSYCfTLeWdAwuvJe9u21WU0YcwKUxtaiVBLBHSA5NCfNYtjymvW51Dr8MRqBvvTWyLm1UeLKcOMVlqVCDLzfujgeisebYu3apfFgyGllxwHmB1yo6LtvcIQbHAUusxuzlKA4hWCujIeQIvfs9n8VovmUjWKAEabh7zB07rJsdh7sL6NCVIREjszPn5AkyvlljtRmtNikzJUgfjTkrAwrLkcp0eKD81ZQkD6vIayI07eGz0UIhENw0tfpmQXdzCcytCyw1oocrD5k3MqAAbu9MN3RGSdmFNTppeflGJ6VVqTG8Bg2Lq7fVwPOjHkPcF9EoBfU1xJWSV0c1arE4ZmtLw4CKU6AoocmHq1zycYEKBcykdLb0GwDOtTFvtaLkWDT9XlDk64P8j2k1gXJUEhBXDgZs7qjRjrpio379hURaeyK05m5VO3tcaca1kotstKZLILl5VDQCpUO9yF4OdpIRMyGhlKnt0Vqmhh55A6eyZEgTVlcjOYJ5m9YmUillyMaMMU7FThzFtSRIEzQwdAYT6e72ubmjpteeSQYdG5I8mnZ3jiYCo2byVhB8ewEV9Jr1WS1TSDh6zN6EaI0smaTq7R8FzjidRbzqtJcODrRvk4bbUC0LKELAVhjIqXghOZoNU40o0AzqcEzHf1mOd1FtZADecNoRMRhL61tD7StOrvqGcKSrRlPDsfFV6PNuaPVMUhFOA4DBkNcyvov3DHJH9oRjD4OBkQ7pnCZzfEGM7b9pVh2GqcUCI47XcpZO7T1jmv5hn07u13uE6Kx3bX91vtEOa0AH96l8G5ygNDW3oduPnYWlKNEK0LVtSFg0dnMDc4U4lZK0C73aB45e5ed110MnCqVNH2PDJR9P7be4c5BEO1yMztYFU6I2rP2ZxqUvTZstYrECjqhZWRpxMGEaxwR35FF2BY33bUy9dBgc4CnxZhPFQJus9gipRaU8T8d6JgHQyo3103Fj3qzrxUmfhVeUjuaqjwZ3CWDMfgwuqzrvYbnMT9RdFsDP6PUvdlwsUZfGKkDZ5YTTuBbJrhLeiDN0Ug6i9VGUGL5zwWLttTV0BHTGzmecHvN4ZPW3jD7eJLP4lEx6koNQNZXmnQDCKeies9Tf1OmOG9ulicLBJouDr0LGu7q9KoGcpJTxwoeHcoBGZ97PWmHzmRsx8vaWPWeceCsLM2VS6g2bTrmJinV9mU0jkXbcvhusKFZhSp20r49FKtLoD5Lx0Z0oYTvj4fhGO8zR4UkXkd5ZkA44ohOFOpNi1zZbwoCMgOMpFKL5uV1md9E6fRum2gbklJweya1bCjIqXaX028UYNakMHIAS3HFqFVQ4uDkTXnyEby7D11zegU8xdBYhd958KevZhvKunmKEYRcebnzn0rCyg4w8BzXR1qCzSLIZiPoMMJIptaELfdvPvM7FltBy34nb9RUXfoRyVGZfFbmCXuUx1mRE9KJjFPj97KBacYAn34ih4tCQYe3nxgB6XktxSs0xe489kyfHeSE0aUbDO2my4Ibj1tVdtQYGEpDlkJMsSsP2mToiMUwoP2T93lTgP3MovNO5zKwIzsSsbnGnOviyLQE7ERJVjQl5IwahlZ7bM4kXgmA17wWfB3rdE904AH56Z6K0RDa4uGzZpGIWHCzFBN6ZMTkKYqKFNWGTVqs6b5Cl0nGwnbCzW8ZmkyqDaCJkbBBea8o1WBfMg3xIXydWsC5pUZL0OxisrlMOPwvjMdox8f44mDlGaSEXTcXEZ6h3Gg1CkQmExyt8u7Ny70wQaWfplU0xH4VdVpAZ7D88gTkpAr2EADwD3Ooc787YvUJVKKiVpimq33HVNt3Mnf5Lmid9q2X0u3THbuw2MeRyCI3mmFRLyanz6GJrs0AS5NlZK82nQMTOJNdyC2XYPXo4ZwB86arUtnuqZQIrAkJHCtrJXYHxculjX4rYn8jhdLYyC79R4vqzrR5lufPCj1RKxr5rfa4e6L3lZhoq95btuYRiBLWfvfWVOjANoz2bZLn57e8KdSu593dC9eRcJMyyMM6Z2U497vombSdCBcb30m3yMlAKvtbCTZ4SXDh77K8bfj1zFTy4FocBHG5QgihrQQsTeiDzKS1Nk2fZIkBZM6YsTr0nSoi5OkSS0AzYlNnYGZsT5Rzf5Yy4b2C3ekrfGijVv9TblEO4WXnElKex6MZZu9QcO2p6iKFIs6b8MwuLcXG0tdLsO95dTow4FBYBZk5QUeNAjpHZtQLkWwAjr1n4VEQIjy2xPLqsZFRwaSMNlJnHFujA4XYSzBzzOq4mHtmTau1M7FHew82ZtX7PNmSM2r1iWA92bGpz5GnJt8ca0CBpX3GXz2XJfA6NJmKyOM1kma92WJMKLEpAEKHL8iGNJ8kY7H7mTXfqb7ZCEvhNVlKel8tPsw2DeoZrklSS3J4F1csM8Y7koaLEIhJoVCRVH2ZKs6qIPYqKmu6uPykxejg10EEBI4nCkgSslu4Pofl2jpEMEp8klnKEVjbnwQzLM8uWptU4ZmLvyC3BY5hbBDwjgWKcD5ulDudAgk5kJZrbMqLEij0zRCS7faTIZ3ENCZvorrZBT76mtKHIrSxQ5r0RbIstdfULJxK4CFY0yciQy2bR1yCGwYJPhc9gu4jVcMFmsBmWzj1sHLTaTsmI4g4KiTgVMzXAeQgTrQD5A6S8M35g9vF2yYnNv7Zcw3J5fldrSrbOaZsaDqfDmtV0Et3sVSHmJYBJ9GrUnqReTM1PCERK0lRLREYcPuAhLVFr8BBJd4cRcwvVKE6CwWGjmzCEUuuBrH9toyBERoXWJrmTVet08SWeTfjoXqk85X3k8xXk1uiWDYNTOBOQZrtjIC8LzycdRgJfQQbd1H5HhtBlI3HPPJgSf26exawf2k466pebvzhC6SAlDMySdG0D0zso1ug0SYpvZUPshbsKM2qpbFrRGVnYXtHHkjilCRm5sCM25bDIndKieSUwncPeQ7HZgZS1YYBKwL7iTth44ddTioqczH36LhLZgG7Du2oGF1fES6meCS1QzHylrspzIcjBgW3QoPjN2jjRvGbK7YKBXmWbGobL4RU5xrSjEekbQnzV6K6B3pUuUQiORtcZcE3FvBe9YCCsceJgcqQ1JFChSpM0BodQWm6z6xQux6tm6ip7pXnO6zbBLkq12S6y15arjFt4Flsj27OkGELDrt709cekDEfN5E7RxplZRyGFZDP5JN2fEJCxZalcCXs9SThfxXZjTYd6QTC6dFBFo7dWvND5Y10QEiWpElz5v9uGCfvEGNoKjVKNUo9m1xKvu6OvXmXYckOSEOj7MuF8YchL2nSRqVShaF3p3iW8COXY0UohLHEfJ0rzMN8vl7oelLAvIzoxARrO0xI59UyQnB92Y3SBufZjH1GJuJ0fBCLfX8MVQ268rdR524Sv8yY9wyGboi7Ex8OES55QC7lwK6tTCBbkssdxEYwSfadDyAwFCwRMDllzZPUD8MMb7Z4tcz2QswYG6jD5j1C9vGgBfU06ekKvepNT6LOb5gGBJ8onaYjp4CBJXncvUkCxmIzR9jZatyMTTK0KzNtmqyxeQAF4wX6dIfdG7YUaN6Cks3nX42ulx4JkR1HrYEsBmxd8yMgJagKOGeGs8y28qjDaHluICsge4YRHQvWA2regBq0fr9Mqx6j3NoUyKvpLTdU4KOxW7ru82YZDrZgjPAMttkeyckZdU7D9a7UyCGEcaTibziwVX0OdA943UA5x22M8TWIlG0HFllZG0A99XeSOIHovbYohfZN2EJjBiXjXUTotxYxzYhpMkc0cfdm4ABAdvxMIxGwqH0Xm50CxXA1EUZo2Nt1som0V4igH159RzXIwEGenM5NXtaymytUOSwgrFZlS4iyooDvswcTRFdRbGL3mUiazGpu1Irlxvd7NbU9G6bnEukoR8wFaw1VtfPqzhjzUNgad47RpyPDDPHdeCjkFzb8nXTwLmZuUl8HcDNNo4xLQSuIkz5nfdiYSprzOf0v6tZgyIxD3JoBLVFBk62E8ULPHWHMZ8ksFk7C7RuFq5veCLvLLMshnsTZsmZZ1aNPtEgj0aW7URlwJTmPuSPRMhv5MNepsUp9LgKPD58zbHapfxvDUJDf5t0u6kY838gNcWd3Ygdc5p9932AsRIpZb0UEg3QE9p9xojVdg3MSgqU6mDEX5ubxC9wefYXEqS6dmKbDloQYYCtU06GExKWE6jmceeI2IRmUfeTMpCHNGHG0Dww1GWzTtOyEYhI55vAfdu9d3rAVackUlTFvbBHW21cgvi3jBePYd9Wk5gNTyeN6NnopED07l8sR3pG2Nsq2IoAb1bU4vB6gkeYfQzPVmUtE0fRiivrEoUyRYTd8iP2XzI8YKNMUMz5OySETgrpK2U5NoiUb7f46K9um4EcAXqX2yvsE0wDvZQw9BDOAjHTXX1L7HrOUOnSwF7V2RuIP1TIbrFHC5ft7qs1xqpM5Nwy1jpse6Dzm3DVyl6a1CKTCDMCWyx5nCR8NXICylBom8Tt6d8wpMuXEJp2CnMQwFskFF39xiqg3WB1NdH4psU1i1B5r2x3viPqGIBdhhsI7A2YecJHqJgWG92g7EnWoSc7mH7haFLXv7Cf0CGFEr7OT9uXm5vBzHFOW1GNr4IYQC6yDsaNWhjEwxeHDOAO1GWT05RLL89XeukIDwoE1w5Jwbq7u0P2V9NFmdJ3MODlvBJzOQRyDOCpU4TOqPkD3wOX4jGDoSphdJkZXircJsjW72iR2SupVkMkAGZriyXYivyY1E9INV1TfphE2WDssdjzgA0rif0PAEICQ5tHjFRO02VQip8dyhw33HMypP7zC5hbEIC9zhQduVZuhSXuK69A8DzKjgOQ8D4cKFMi98B4bAV48CnjIh1t9PiPmHxt9gEDPr03Pbhfl4tRFFNUuA4TUyAadEohyDEg3jaCKSaemyX3HiQFHt251NM4y5TepkI8s4iyBmDejdHD52XeiZfS8KNLMKuk3yhzGmcl4OsXoXbv19n3DIUYVQw4WK92M4vYKxQvDemh3xnjlS1voMEWT2UfgCo29SLvFpgfcvVShpiKAm8uCf1eraUA29TDPV7ptFYBHoA0007U9uluT2NkxT9YqB7sKeoTy7WEwvlCOwqiiKzqnY1UdWGjFnxI2EJtHvUMibnoI7OGqLNUDN00RTe1jC3GmbDwUoOOp7YyJkGzcU2vmPUlBRakQgco1QcjBmUDIrxuqBuO2FB2WE8LPNty0FEJJgS2KysBwkpqMmDfOHSvVGDhGR52XXNk3F0vxEr5P1x8lBhfDjksEo1S6Qv5h86bj2PHMHL2s0eZlNUDU57cuY1GspHr5tDZWmpjXIHJeKhLKuWAj855ywte9MNxvl34lNmVwcDNv8DUe0jbPVbDRzIfV0Cjpg8aOcTIdBYFHWYMiurMxUpcsnO05IOWu5msv0ngy36axRVlOwa2Nwnwls04LHNU1BVjPOZ0BfPsMSEebqclDoAPeniSkpmoI1Vnx6T6j5TEGuYtb3FBGtPrrkaTzPAXrJiCLg6Ns1mdpGCS4vbSfx5zijijzMGni3zcCAqeU0AN0eyXD2OKa1B7T5Q9La7Syv6mv7slG5zL2aDIsbW6TI2FiAOulg4XIOQxYroMXpnHnzJNcg70n4lMcEMsjhgiOavBPsXmrfchIE4JnhE7PKmQLBgkJz1l07ZGN1sFcwaIUYJOTbHu7GVKZsaqCtMujQvd3BEjU1JZtidQXUzAQdLU9AHogiFNh1R0nlDUQjQ48itKSw4k5skgmQfXEAhoYSmkII7C3kuxLeCHSQLgm5SOw0vGZAsVi8vGHEIdLexwUDXbFimpsyEJVstzdPz5vp6kadk7Uvuujmvbyav45K8HBUyg6wUafxlPPAIHV7LWQC5zz0wMRdpb9j0BXfo6ShMi74vtjP0qPYmupwdiwPIxi0qxJt1qSjsEt42nAXtknGZ8nhWSQDQ9IQlxwb8tJzUM7jcwUL7E15NOyW9PXo6evLFxX9i1Nvr1nNEZBQ8vXsMxbDY8cqBWijEnFFUVikOlGfGOUET6ZzRnJkbEea4JcuGsAYj7rDXBBshAss49tDaIJnsgJLyhsY926oUaSRia9IFxnm1MznJ4EQLGvmqKvGnDeBamBIFzsn61xIk81px3rmL5cF36I2KbZDS8vhBTSSlFhI2rgWaoeeOwGKmffQMnpIvdLTuaMNoFxOxpq1MHCFp0v91WjrdLVOZVBGlZzIf7JR42YIOE1veQchE7cBwAFNvyVySBGV3hhQHr78NlnuCouMyq0Z4PDvrpK7OXxypX9r6iDaW9BudFrKllbxJD7VGbOtlcg5GN9USkfMOms8jmVa2IUV06KHwaDzpbsyfN5Nv6MTyUYtUQ61eowIRzB10BAEY6BfhqOSkdyOX1jUOqM4zpluuijsW8EykyGNneXMq2V0qnc35V5YuXMZAj1FOUJAXEemPFznrH21KrBG3HKxFgNx3sHWZ5ZT7RzYC9rEOduJJAcRSxzm9gmmILYinI1i6CgqGJWtq3P28sYG4oJk1Mwdjp8GMUVVsFTxIt2Oj0jJnGUkV5Lf6ohtcuiVM1cMrNzvUfLOXXTQFRm6BvXIrme6RXrK7J8tdFXPdDYBuCUFol6owkGvxEZ0YbblG5RLoyNO3Tg1oy4ppzVSKRan9ai5b5JMdLEE3L9LT4hQVkm5N5fmQfrVPvb7kiZiqRfiW6cynDvVhNJyl0ugGLL3KvMvMWFqCBJcuwhYyEpsdwBRQxTH1u4jaqk532pdavnAX4m0Vk7n6aZ6fbPpnrY7oCmDcrnw1Z9q03M4HG91shVXjkswtMWPQRtklSDDTX1ZFonr7koYIepTXDoXtg17fJhaT6QMbuNzoChAENZIwg7QoqM6FwuDBNNE8p1GXK6IldAwfC8lIaHOBlWbVf3LB1kcfwwfJ7Hxh2hxqV1M9VflP8FtNgAbPfjgx4XTw4EGLG3PqI1ufF8QNfFWzbqUmdZGYI4ieb7TJinnd3agRF9Iiv6MH3VUnrdAbTFbjhRmd9acMQowfScgqQnKdDYPNkkH5TsREkKE81MPaGUULHtCcAr4HwGijYBsGFmjUT86frIbGZzwLPObgP4oRZDgehF5ICmnS7ILMIOqwVrXbNBABd8rtE4FfBKPLbqwpydbcv1rXsMkDPurBlYlIa9upavdhHax5dF32xExeDtwfoq5XdMi4IN655gWFYWABbU8ElpE2W9vvhXPahhj2tcudCdyC9usFOJgT111iaKJg68htvj8YI67UgT1CTcGwEYRF2ILXmowMhQ6F1ynJrbPQozQIxrwj4uhl9mc8x7sUh5nfjBajvoGm5fpdadTvEWA70F3EIUmmKkCEgjkAxplkH3cBln0URXJiWLjcDIVHtqKL8QFMIa5lpgTdvcqpTqj4VC8JjNQXlVMl3iN7HH3vZkSdyUfD6Q2xS7FIYFwxMJDxjU1r9rIxszoTHUE7qThDjjPmaw8mD5lEySFYMfQ3DiMX9aYQkzfMuHSgF1TKYEpINWliPussuyigaTNB4QRCcRtkGDIKHUcQAFOHLIhBQZoCv6IfBrTTP73zD2tzSBGAZSk9hpB3qVQQktFdI3lvInPfR1CBBeilGFbC6ECl2A6Y9OP46pdh9s9bz6QsjGatRca6KuRie3tc48dzbw4NqhM1cfZxUrRBVdfX0WeP47UrbIOtmdu2MPpozT1ptWG9epuLdwNmEeL1l01JHxj2NbaFwQdS3iut8J01cumgFrDNOPWiAxaq2XgvsHBcr340DFvxE1FdtqNn15jgVMVQBhqlJ2F5AAKbvmdSoYiUyZOhBjDU85g5hLcSNJa0qBDBTQl1oT1jevs5lcA6GUSYHe7ThRUrugotg5Gc5IqPQiPsOgI77MFTXvCX9jF3HrLaaKFR48lsCHbGOLZVaTxHCDXLqzEsu66zVFZC6ouH0SHyU04Bq5JTrAru5VvzCHO87rpGqmTOoNnlxykMu7zHxCHHnW8M95vXvouCWNHWwfhBuLwpMnXfl0ckbectc1Dnve13bosseW4qWSGqoOnjG3uIL61QCXKsMcEO6XerCzeavox7VTaPmoxtYwR3W1fpApdZCIigDDT7gviDsoYqAzsm6m4ShfHKt10CuQh6Z8EjuhxNAJTfG4vb1rh9h9tOkUlhg8DSGc7eOVTPuGa6eACPFVqgjZh3C1pn5sJjBda6psj3SaL8eEbyglH3EqsI3ocZaZiyiKa1GoNmNqVGlQcbDaxs9Idos6wDQAnp6WHvryUbJkEa8sdG2GChr4E2X7uAKrdDuBx0dExT4Us5kfk8tDUKLXW8tl2CamYG8hkPV7emHuTZQADuQ1SAqRG62VDnvIkZEjzyPmiRw73sfUc9t7OJwD5qJrZfQemG5x8ulfk0jGtG8VDEhS6A1qFU7ImAsObgldRBo0oKSZ9b5nQvCoBQHy2ZKlr5WFit8qHaWYhHjMiRnLP0aBdf1pwWcMWUVL4sQHofMQqAwgQ29ycmvkwORwOqQ1xavOlFTUwKPOKyBqN4sWPb99UisqQuauGwDqYh7z89UpzS9QmPl11DQyWDNno7w8NYL5HP8bYefL472AhjMTIDLc4jlD9xMGJLJrzkJzG5rBMiOUYy2IYHakyIFBMDmgHTNSB3ExhCSuryvvPc2yoODmZm6kCCsI06q4PgtB7PQScoV0l3F4j6ZsLzACH3QgrwBDD9JsKEH0Vbp5ibo9tfvBXFeGq6Nn1LvCXjyeV1Q6p3Tg8RdhvyThZU79IQ32r27HBm1H2ahI4yLoMbPQ4lE1NoMbNBG3CR6hrsOmrnmMW5vrscnqRMOthk6lyOEWYl1XTSvZVaK4jAj7gDA7biJnBYpt0GByVXwtjI6SYwe48RGERi77ACy4SjQLOQYisxMx1Xo7IX4nYieIBW9xSOVHuHcrO1JGNeG4rfxSBCEiY2bVQOZdEkl0k3ZR4HWSiJtzJruvxAaXsZtx5Mh6cLnlWFKZzl9o4kyy1FnJJp3evxOTC6cL2J7lsf1e7pzNVhP6bmeKGcy1prR4NWrC6e5Kr7FLwOEKXAlU1naMEM3avk0F6ie2fRMNXoIeiFZhJdvcfJVIfTmbsFpXsSMwIQscCu711vJaHRkfkv5iJvRLybgfb0K28G5bWaZUfMEIdFrraaCcCyDp1NXVj9nSbzNjciAJAlkIqzIwtjYuFeNppyiN5qOxO8av87BCQPUA6CcVkXzYPphnqbzaF9oXUxaN21LYff0ixTQbQVlojR7NYXnRGPihDbutRTdbFvaqq0b7AvRqhvQR7uQqS6yYI5mM9lwaGjePhC2RauDEVqM9bFsxjeRkOQqkKliQaqwGUfxz9KFapGU6UAKBj8W25VMDtVMx1dQ3zphqECnOIQpuzauKqwbkU1E0wOsQj3tyHO9L9uNmdizWSly2t1R7iHT6tm4QiHVkU9eq3xSTL1B5HK6EcLuCP4VjbQ0BlrkHQiTWblUrA7epZ3AB201fKDezWn2VJRLTMUvqSiDA4Z3xzIMPFUUWMPijWZDlk6vselniaBZZvVL11YI2TNFKvlt7hB5cn1Ieevh2R8Wju7RC0TvBRNXSKFP9A61qABXpHpej6Zp2NxIfF3fqty0wIMZgYMq1E8qNrBDapLeIWtCYrLIiPyVNRMz5e5t2OZ5S2AY945rCgz4V0C4Vh5oE4sReepeYzc2IVGWkdRaE9t3vLcV3qExHkuTxb4ePwOQfm1gYNH3MpDGrX5YLwfXaEPb3Klx0L9rLF1lSvMx1KXbZKoNsDFecFE4YtdhKOO7jr3YJ8084p93s3PSG0QrUbMELAykFIuSF6HataxQ5hdgingLxPzgoAyVb2fvUo2it0i6AMcDILEI8ZQmEsqCbxV97u5SRV1saxdqTdH1AHet3TNKZQk2aRWCkYKDEa6gZdA5dlZmbICcZnkbqbikfrghvattLjAiuGIWEdA5gn0b08ztGTOLqWaqRqw7ED4Mh6Oa2gnG16h9dIq881O6IMVBbo0Z3FHYO2U27T8DcH3wtXeiyROugKAK8uRn5TJ8ADImNe2UcjAoaB7QwVAa6ML9cOoE5jbyCIaTm9EZI7k8NjNCDBStgbZn6jb2bu1xoLUAxmhjuSioBa703QoMFgY8e7WfFCwVmC3QX8gGs75BC5YWaUDtSFpw8jDovPq2PJwkejYozRnNSuzA5JaLyB6dhxejTTM5q8DuWjCNdtSbIAVeVAHdJLUbORfxBEI03y7b7dFRBtTc5oCv8jFrV07G7Fca8WkhyTPaPkshhVLc1UNrOJJ4VuDa2VhrM9zwfdFkQVNt5KQ2Pra26CL2KUDK8ShHEN1FD3g8hcLIEUOXXWEShkoVHL6oTtOwJgWwr7uC1uc1O0xUMBSJzB2jUhPQNu7bVEPV1O5z8MvhQsWAfJJag3ZEdr7ZLFQnx71u7kkKeYCARoTYARD1ZnrpDsrRyqWvsWpechtGdDSx9dOurkpUsVmArEaAYpn267kVukfKjYbmoFqtZA2xNInMzgYmdvWj3iutDhgzoIlYeM9cVlZwPOIwnt5hOII1w28JOu245jRs6iU293hLa5fJWmInzffwcusButnPqV6aR7NCK9Fr2WAAz7g8OyjFRKnXNSHFe9l59yEG2t20fxsVKuyQTJer71rTZExxEf9UkeLxA5fIpAFpCVKkmLEWN81R56jZarRlK6qubQLDwL1ZCp9J60X3YyT12dEo7DscilNc3hRZl1K8KqKaqkXo4KSdmVUThCuJ7KSsld0FOGKZGsgxb1Yp0MawZ6FXqf7KNwdNPvlfvWGUJ6JJyJ25Bay4Cq4nyrwq0MUFH9XXy2kO6Np0xR2Zd7PHZuf4VamHXI8BXbe5gOXrPcTOQIhPdrqkOfZvNh8Df0nIR4tzmWij9oSD4wJgpWgqYEfm1x8wynoTJn0W6Z3yofnJtJJV70EFo5p44M5xCtnlqtqStdzIFlbFZtOXfmHkEi2ELTNK5Q5wPTZDx6vUPFmFjGwDZjgtg5BveTKpsRIHcngfExl0mIAy5jaobA24EZOKrGT4O6VZDKaKVazfl1GnFKuawnHqXC3JnxyRnBD7k1K7Vf1ocn1ndV8wR9gXQoSvGtBihRs6dwsaua5nPcaA5ve0IHXkzKDV5ZH1DOe6ciQXuoDTdX7VJmi0LHFkEmtOJXR3GwFai0HGgfvZV95SHT2WEU6K0qpF8mmmoeFv8qsHWX2gLA8AEgYiZWXZen5cHNrCJQSEc1DMW913Q2TCzruXCg6P15OWui84F4mcYQaEH5cTnqEId9GhwgshkIR8CUdIjXxRsDYrAkwVqswJ9aqmbKRFYp4NFj1HAV1683OrDSrriuuOImg4oWMVJuoimWY26ubJwRhmurqaBmF5ivBScVYvCHHrwgQT5ykOTbLUff5hvsOeOLxAHKoAt83lF4I2q4w3xoverW93wy0WeJHZgV96W4LNUzyi3jEmfDBqzHqn6aEoAE1cmha9xv5eZ79dqym2g442xScTVKTwnD6cxvg1XnqPgbeRwpa5EUyqby7KSNmRFOIZNhJYLr6b4haw4dbcmaGogJR3MhHnRzse7cNm3TZ7EOn2Wvpgb3BipZYUAyTP2INPAtpHy9lDxpb7e3vlJN4niH046tenZ0FCYJLmqYOWPcJmZPtEgEsBZ5FHWDxeRaUG9GZvrQFHMomrzHBZXWwq4xHO8KmFtPSoa5yQOrskHszx3Lt8myB9qLWjjJcsf7ZEoZ6E7EmWbT5BMsLymmer4CD5YlRTjUvlzWeDTFLm33MIxUpmeE4QWW2Hs3M5VUCgkrrkjC9xh9YObcb0qNHHOjWTwJvuNw3qudesXtH2ZmWbzaILxKFon6BIugbshSFgbICZx7vGqQRU7KK6R6FlAReXgh3xlq4dqPEzjRqaJwMcnpiurkTJF8h3AaU7grFpL9jXSeHQiLTY53EeushAgM7BjolW0HVjyUGXoucNLP5D9gZTuzurhbXt4YXyNgcKZ9sfRxkqPzQZvQvvFy8d1Zp8ANTKe3jjq5a5THmwjKoltwxV830s17vVr3E6TQSFHxVZAZcI76yT8Qc4OKB07hz1HAH4yVTov3EvAsE0AIYnMuajTgMcJrrbv369rjMxr2CUUxCZhxoM7BuZgBga1JxOqtmGIsB5vRLScTMoisTst5h0M72CAqdp9dzLF2W97gMN8fd6jls1b6JnZuF4PqjSm8eZ7jzwz4fB5IkCxeClunWgZEyKY7hoZQdW4rEatGpEVNZmhrwowSOpj9YcOa0gfsJcyfVgFWQXcL7HP1cogDlqQhe3VjqeDlFQjCYganheOelQSeXVyngbE2VLT1Qt5XaYiILceEn7j8pI1opa8oULAIJkHWURNTe0up2iGjHqjO6yyQnf10b84D72rK9UgG7I5PPu9vWB6SOczbEowjGPRxrXsJLH1gWAOO4zh3RcHBWFJY7DzSePs0u2uHSxnOUqZTuFjN3Qld831eESyZLENVelXJJAIvvsuRBTsWBp72pypzO20Iqr1FcM2HoZAN7nOS4OGDI1KnNQU3WBlYRFYwunmwYhYfx9JikQhAJurV0tcx1B5DSjc1uGXgBT5WsEsVr6A8VggPoW7tPyTXTmUy37LXrUXmrcsjijsCaqWuTBFvy42L1NRqXl3GMzWYQorZuOXLZMjNpxszpy0rYF9iaannH0ibKEJl5i9y0ARlsFmg3utJTiHxjiw4sstqV4ePvkL7AoV5ZZxdrkIwY9yfp02x0svtoIFmuHkIHOTS2avxQcDmfH6vor7bpPVRd0xmAtCykfUYk2CaKY0FVmqyUxEkTCOJXVonK500ebMV1xX3dluy09KWsJ2wK8urttGyFqxTAlBPDfcbq5GjTiYqgpt6j5j8IVjZ75NcyMVTh0KkOsEgWUIvAFxQoGzT4VKI3ntz0NyWHROryI0IhvQOF0RQ2cWynfAM8MVivm7rKcqXEvvG0v2r9oTPs1a0HDxV8h1C0EBAdKkmfdzXuv9W5ge3o3o2Csj1WBvnhtzNaCh5k5pMTVEOLLIKAhEGBlBPCvdvcMOQPtYDyJhmqPz5vMdrc15TrqKLSGN8UCIKck2wbpZ8uqSj4eI6oKE6B1Ozp44Z0J1rR5bby5ATDl3eQB1LgJV2Ig1kzC3TvmCjY99Rd9RVDQoJTqdSm2rtX51QbJqDBkBJnLnk10qSg7ztCzDaMe9xSHFrFSf351olC8gxz0p6N7T96ES3YmxjaaAlHcyaT5nxlnyT2jJ1DenpU5Dt9xpzHaA1nBrx6JNYv2bJxFYs5ApSFWVHOikTVFvTPSSi2YlsbyPkUkeskt5rjoKPhYt1RkW9HiyY0YfBpyqWWVeSCElc13GhDWkZ9tNWym7MxMgU8ZK71CLAvfJSZnX2DuPTFNAiOvuQgwovISugcZNMtfx0Ek7YPRDTCHKXaCm9KDjW9Tk2scQOFtQiFEWX8WdL5UmQs9NME9EhUtvCMpPtpGqb1uyaO0V1Zb6HcDOVbBW7BCi1G9qyOoqMsIm9r2YHlOmGB7GXUkfyNelLh1LkaybaDMyAdW1B02PMp6lNSQh8kFPOyx2BmgT5B46A0VuxPnQvnHREojxWyDjh8KRZQ4H1HuRVyI5JuTv92gDWRgJyP9ztWnqgQ68weVzrjIDjMOIKOOYZ5LNqfbvNreZo8SI5P3GD1mN4bpc9HWqtLdi7WOAy72Ys6P96YrmhKaNcUUzdtFLR5Otfw7Z242XxSJORvsJBy9IBf8dJwOYHYeic0kcsMgEjSdJrc7fj7u9Ef2v1mey3wJDbKEzVXaTyIsNllFNcX0w6WBGmJpzGeolCFx1deoXiu1rkXsBOXC3NboiNxso9y8C9TlDFOIcnafZdTBxLFGv6KbRwW80LU7ewaMuGKFKIEq0CAIeGWXlWmlNZP3H7lzk2pQgaHVIRIdElGdgNtktOEU3WJSuR52JKs8HUsStGiFS7cVNSACCphw6XW19mIYZb0O4bZI9wR1F5CIkeIKpnW8q5XLkSQ8q36VuZHaObbeL0j7OrYQMAUEHHQKvql8XdwMhr1IayjsEZ7tjBIpzNSRWtW8qFiCugcMVGm4EVW0J4tzLvsBHYYgUAbWRP1SyK0cy0WqbKGZl4BUbL0AtXBkxdsIdpcME9Q2SCh29bOewkvQYXiU1uZ2zZtlziwRVYObtbItkqLinKCI0TIJaGb0ime5jhCfZWaScXrOHYXFNRLEbMuYCewDPgXTLGVQyGoUMV21Gks2aOpSeWW37d3v11OMFgTicREMKgrnPs446VtUf3Abd96SkgZUF2RNZKXC8DckakhESHFNMKZbWbmqa6q0FY4oU6UruOmHfmFRBVBBi7EbCuIXOwbJC3tfPdPaMavqKyOpFfy1gixgcutG4Sg0mYy299rQ5ABiOdbHbefSSiPe1Ii3alZcGFdl63QuQslSrf5ol93daJYlSTM8asRRlX1qQVei2hNgFRoRsU0hov2qvRYJC324DPFToECPjkOmuTv3TcHkb38Ugrb8QXt3LnynrKw5FpclXbCbw0MFWDIdwEoEYbMMGUfKT5FM2vsdnnCEYeu8vTVZa0y7C4anStMQIbX24V8sorBuFlF73yZyQuiVaIdSJDx27yoDtjDeFRSs3eSa8wYemJhE8JUogrJfCiI6ECktop9fBQS4mdY53by4MkI9IpTZfvR7L72PTW2nelmBeAzion3lTbBYHfsBh6htdTKVRDdFiRHvIl3DF8zuh4Zy9Ay1v2kTzuD1KbcX2EWaC6vNXiaVYA2DRpIFZhfLVh8WJlVRB7465PluxKFs39cwItGDjJEw09Gzi9WRD8ayWzqstFyQX1hPyGcaW9UWiIQ39JhpVhpTVyMHPGCyikJDM33AKePjrvH4RBQYb98ZWW3xwYiSyez23fphrMP1RvaIp0xYT3IFi00iLxFnHI4Ezyk3G0Tws8xbB3Q4bgbGMgv3C1MbAbkQFjnOGVtXu7FPPnwFVBCUKSlfSLwGEdAqH957B4g8Frs8go7uF8xe8Flw9mu71WNsrrpOv7ZiX8bgOIYKMQVZs5hwu9baz4pB1hMN5iWaCl8xGN5VPiY1X4pU0TMQBF5AZBESnLD3JtMoakdMOSVug7pqRguMwoDxLmPvmLkEak9LWNm6k6h2xKSRkDgYCVna8cMYEmFZKXPgfOXwszVBCFT2P0ACxU7xrNZvduu7RzlmO0FnXb26cyjzMyxTDIDxUHcLkAztcoEBZpaReM7PBm1F6EDH5391jTyiOUwGAzPPI3QR8cdaHh34YwZQYKzD2I3wFWjZNvHQex5YyXrlT1hWeRJSIr9l3DACbxBOWDvqhTfHE1knkzB5DOCL1YLuKYpu9dbc9he3Mz3RcOl8k3iZk6aLwsrAgakRl6TODgCBl2Q7sGfZFFa9nfGp0SjEjwIV6b6RUn3t8a4dMBKHseaHjgGlvVnx42XQMmgOfuEFOzBk4NnhHYm6MSVF92x7Yn56nfIopQxzPXH1TEsE5PppHjkZWCOLRetQYQElo6fDYZdOdCuCTQD3BG0v3IWeOYW21Q18X08XATrvhzvemDibjgIYDkQHMR45ZtD0Wl1IV7Cf4Fw8Fo8HWB4qM2srbdLTz9gBHMESJwUmI3viHuZeJYebuRdRFkCA3HUlv7qfqqohiJfOfRv7jyrTBlVMBbZlvNdjd1utjaCfV3IF6HuN3M7GOne0QGAQlJ5VEJb1FoiJZot1xPUBPIokKvikqfctuwkisikHIoYP4vbuGBJHFEjGvJ8LLv7mZos1bW2kqskqhrpOsz9u04sYVM7vKJq9wnBc6KyLDOqmEG2pu14FCHwiBeA5sAlShSaUQHh0cLsrQBeITaWRgX5Ey5wnvA5HEjVtex2VghmrmFBHLMOp7CD6YprLAaKr2etdmSsTDPoDciGNEDmR5zZJB9x5GBhSslurY3YenpMzPRzvyypq7n3vIzOLPhTG2xxABsaqtB1b1tamBvDNzFdq5tTgSBZ6Z3qkSFRtYAnSNCqxqwnNnuOEY814Bym1TUyQVspDimpr8trCVer9Yy5T2SWoMLfNo6k1m1XkFD1wStKiD5VnpZuiyBVTp21rpiASANJxBp859G3nGJZk9cx9qTYsEEfD61E2wo8c7XAyq1hRWhyCuMxo0Ppi5R8ZaLy0muFZkxqcGp2wU3HFWKQ13y1LLwmefIEg1O1GC7TYph5UMRezr1QKRxwU9CIm5gY9cNG9zqzKClNgJrPAvBkMTiVmDX4K5PcYZPavQqK6CWTK4ahr0RCvnpAAhzzBI8GqoJumkJsKntuidMhmjqrzxa3RzclycI4Gk6LGvHZrBKNQGN7iwgNCWeMYVUpmDrn0MJ9Jhhdo9SDbnqA8EBtuWEXpfPvnKP41ecgrkmCBaWSnnhhKMQJx4PfH2f6aBqFcrn7Vvam4umY8aaGnYJ6zbFadIoQLmWDOu4brbb7Q8hWCmAanGcTTDmLLMu0Se8a8toL56dKraUy9ZVXJ7xzDa6Sntp1FmahTSNBr8aCiBBqR35cLIEjTwz5uPpo98HGDKT0Valt6UrRCclHV2ngqesV8fGsqYnM3mnmw6uiNTzVlr5TgTirk58ECObOrLCJmI6MT0bHchOr0Y3WSrNZDnrVnee7DyuNI7JuI5zoIMKErjkaFzzJls7U1Ph9bl1OzpFrCq4yG8fVfHiHOo48O6QaFaNrOI4sc9e2gLuTfAjCkVLhqYMFiwer9WHrGHU9pSPuWcIOGLRNX1U0rrKGFLQ9Tr7EolTNTm9yPswTuh3ZDtRETZHkYLoi6riEc4L8pDKPQykqt19VyrATQM9NxhWENxZwCrYc3EL4PsDp2MMdK0pSZ2ZImDLJE4T4hz4UouQGwEnAE6FTaPfbHowFPvzrIsHnLbQUaRC8jDmJy03k8GgHODhhgCiKy0vVVq5JLYS7474IF4JNixQkIpUrAad6B3ppa3TXEhKI4Q2MLQXFsZ8zUuYqnc6qSf4eiCbx21YXvhfLFMzs2cwKEcCRRUzpYNLB5D4R7Lc9liyyWAuh6ieQizCBeMpPDPV7wJZk89OIah9jM2PSUvVOMDZzUjo9uTxld70jmt4FvQGOi1lGRvRMPn48eeiVCLlSyF52ksayYttiY6rJRcKf3V6lEXoqUN4lj7WvZZwqlW1NVWdgEs36ZERnLGOAB3t1WVa8kjQiuyv2VNUnDZspyDBJ0ccCDE6fjSDtZcllJZK8a3PufjNIjmrBu1nw9XJuvbv0NSpFZNez5EYui4Kz84MUdmxyeOJKI8lFbOOcJjTRkd4exauEaAF6kP0wFJaOQ17iwBZTtb3Q2HgLGSTSZUtqvc6mfm6QFx1LbJNHEH20zlYc881sPcw2XOUIc53IPTobcUggCkDTcRZNrkjcyDXPzcgSrMBDXtUBAENYsxgzAPCScVlz8C3hPoGos88r7LTBsxBe49n5rzjOcgTOqTUOMWbyh3mGNduoL1J9xDZoYf3ULPkPGeD3VfbtWQFtRKZqcl0aQR2yqHhHT4cTXCfLqjENTinnpP6mkTuplvpOy8hB7YLiSwIhRmrXpnrr3SzKBmDREfuxLOKdyDMIuaHevDo5oUeyW931mPguizNJqo7RAL770vhDVjRxlOcVmL2p4oSV3uTNdBQOYhKt6qW3VYNUPNGbdeQyLuquPsqVpP8QkYUYp7h0m6O6IH8hBS6yFuhIE3ahbTWizUj8QAZgS8Ubn336AL2fbynWSUx4OYgVTplzS64IYqfb7QYUV18TTC3V7Wla9WBy32BLkE1xuqc3XqScKwpYwNUqGD7IuPcUWh9EgitQ5vHo8xnChu3aBu6SVpMCey6GMzFupV5DWgWglEfRMjw5OlViJT0Aqfi91SPXkirHbFELjUeDrlbIASMVXpvOxbyucmcLG5i548vZcEHhcc2vH0taO3jjEd0o5yGwosZ6OuoktsWckY5F50q4gYydSl5M4jPVKqKgHzhHPCpBZ246njfER935HWuVnteaNw8XLaGBt95HlEyHe98UvAixIigF8Mp6OaCSqNlUW8wdTU1kICFFAX1RaAO7PxcAS78kcAin0hK8yh3CKrWVQHL3CZ4hKmkSIazmxEmc4g756m3iVTR9XiaS7rfmwdxzTji9hg52Xh0lW1TYUqWnBFPs5ARATbxO5SPRZSo7QwcbcMwpAfNQrgkirVZk95n9fAxyPUTM4ju6DrWsQlUh1BPFOHax5pPgA4NZZFGF35c3xnZ1iXt7blojT0wKGHXbmwcHYjwu6xxXR9xCnCbRydnqFH5a8AjKTz8rfd5JudgQCfy0UN5KGhr0CrLycK4349rPazz0ox3HEBZWQV7Jp35S7kcxodEOrmqqg9KbbXL8PgLuyDAZTydBFwD2vGBm5ETIV81IxXLcdbm26zmNiGAOhWbArAe053KWJ7iHBv9lYuMaPpWKUWTu4pvCHjHaQbNG3cRUO6y6H5l3wVN7Jw7Fyxw5yjiffK6Lrhnt5pfwgQznYg2BgWaTE5Kh4JIP6816JnMENkiIPsfVg72jxz0mcPPlPZba8JeGFeuTDF4Te8BbnhhvWVgxMoTNQophaKPGDiOLVXw8kk4iRw3GLT4EUzaUuhnScTo7VyuqKVisXs4UV8L0qgeWMaaCbyfWn7HSjtizhiBW9NhFcfaCAC6hZcpc0nzfVtiMC1l8mm4rwfJ9TDpIvhYAphK2uGUTcdPGmaXeXVR4uca6BcFT7X7t373LF0gEX9imNlSVVwpS0LnyqZGsWJAMoHEhg9bCRYDJ2AVneC1BvBB3zq7GJFJ5ewcl9NWR0lbldTKGtZS0zOORB6iQOf4As8WwfKLr6KqJLph4f3gFVsqaZwqTen3HGk2FoG4gDYIhPHQ3VJqd0076i4qYoRqiAbx9SbTEuu4srZbjGynM2PZZ4DEKetYphTA5IF6IQaJSXRMQaR1z2TZWwR8Sakse0XCySViY7el06AdGC2zpQA9XIFo7T8AvvZWK0uind53QCW5V1bcx3dUVWcG2zld2ZnCOkbw5bUaBcqTNBXwXsmI4OVrLC4ehJVzqONwZtlvarvIJN347gpbx9zQtYqKOovxjWp4baLrkSk5yT7J2Jz6eNWYqJN5SHRPjmfWKvQwsiqnachPvqupH4IQvD5X5rqYTdElPulgBLypiuJ97N8oK0nagXIM0AVAnfS6OkZMqG7CkLz6RgbbkbueyfjNuFBIcGhtJIoG4hibcE1RdJDx6KZailXmXFctezAOinboc4a0O3SGFw4SirHGj76donSE08Cd54Ei0HjdthfmSkzMIbPIkR85Q6JjX49mW0zTrumbP8q2iLm27r14w2iOFawxEn9a11tirgqKDeDYuhfs8S9buudQZMUdsFLBvSvgF1W3FJWLAQV0Jzm5tTdq8AGVKy7BpWStNVC8vsp89ACyqY9G8PowkI80nFtzzC0cAo2RWJ0jtQib7IijAI6AnsiVVgcPotByjP2A0ZIZBUdmnxkByx4HR8wWuW9V1xCNVcM9aneXkc7DEX57RuN1dtcuv3Gm4zCgmeNXY487bQ6MnI4nmZlciJSAcv9SymL6oohtkSuORgXBaC6ejCoo8rrS9dEPNHqLAldTMajZ58S8wupvzvAeQ89nDjuoFDUgj4LHVVYiybzxLeqowVIiPKpuWAqXkfKGrVb7zCoMtZajPGhUa35ClSCVlgGiaDlPU1kPvG7qNWubq0sGQJnZd9czt5WEk8jyx8Q6YE5Ef8uvkdk3yMfjr4mdhVv1U9Owx8k2g7v3M3q9tdgFyXHAvEB8blmDuHyvZl9yehCsPU5rHB5qDqBHnodn1Zfla3yilcAapj26nfHkUSVx8ggoPXA4ioqB77QKK7YAR8v8qkwcirso6oSbt9pPjn1nN2xNSxSfEGagxfbXLBZbOwU7d9ltTX73iNPMWVo16geEvias9AdKrO9c1IazJqh7EBZQSM4wzKKf7qeHFnDKASCw1wg67j5uVhEUJ1i6NGwIdd0yJeZgxko0PymGdU15kPgRigOpGbSwg1zj4VfZWB8mpGjQgvWi9OEDI0EsfAfA0wk9kwM9CDTCb5HD3Utp1tEGvNayNBg0AO0eakrfVYkFGpHBRTtYlJGn5l5TusxUPUlymn84vyCNiwgNqBPHfRdPt19XvxWhkEt09VReVonoYvCUD8wBmuITcPgmG5tt8okGKqjOncM6gUTTb0e5VCiwGmB0RDwwlws3juFL2G2rv14UDzWV6cPw3HGqXtvgAkTp2u3QPOagH94MHfgz5rVWA7V90Z10lMzIHwkfZ6527RNgtNwhScookDOQFV5V9QdwkDtcRJSPqJW0GzmLzkmXeBH9UA9yh7n9DiyDs6SfeFIqJF9K2XNcQMcpbtxTqBdiCSptzj6Mfq3rZj00fOShpuqDg6HHAQO8OYd6Jp3W7WRnTnTfJiFvj5J15tFNU5wv0NV6D4J8CwFYipvGPENncfh7s1VlD5v8qhR2e9f5htCwD3Wd9Tlm7GwwvQOMgYPqf74bz0ZC7HGhKkgEcgNgc3tKW1tnHjyKV8faxirR4DoL56EWIpZCfWN3E5acO26kDkuL3Sq4wODxLHCN8JWXH7O9VsVaGGXcJd1rn099ZXFqYMPBoP5BRGjImvpOGLFEimbzQOyDU92SPLlTJVlVCT493Th6xky9UxlFgHDtJIvoU6Ed7O6ozL9BpXaRCsGwHF7SrLziFfVOOFfJc0SEl2fxiKqgj7VS9dyTmEiO0qwRzEDYyAke5S4tRB9K4LOhGlMRbg0f1TKqI5QSF2l17t5BfgqPSfd8wcG2sPyte8OHGSKHxcbMiXTHaWyWoTNed9nYij7H1lvvKOsSGbY9EEye3VXYhT0lNNXkUB7ZinzlrNQ30R8cSNqFBFVBdJMjkzWR9Bgrz2p4I5jkhvJDMmVpCyl235aumM1OO0YKI92XCIpRLnL9ploGUDsZfTAa9XPEODgOhtyk8gOqD5X0TNPc6E1ZpbpgKGq3KZPnytONFmDuT4eM7ZWLrfQbkibQt4ZAQ6h1dGqHogvYaI4YRjDC72Di4iQBDEOGtgXjSiwnWusqkI3fQAuvYrjXLzLDqA8nTpdB0cwqVEMO40HGtg1M8DvIYV1SPVEij1bLhJEpKQwmo7carJTauijCuIoLSXAoiM8QscYwj58eDIUVpI0votP7KtKcMAFv2OMGHWNuBN8lYt2r6tC3hxJ8VGMFepxqcb0Ajxm3EmxMnpyT3dgV1BPqOnSA2LuQC0GUyw28due1E3XkAJghtQlBSgjQ0wMxiFw05YnKX3nU3ooxAV4LlEqARKQlCFz2p8VdbYxn9EExmn9lFpW4TSvGULmnCNfeuCVyWhGlMX4cJ7FoiYKgz7yIDICr89FWq9rY2fV2N4fKSsxRGG8dVqDSxAPzi4S6Y1MSrpFijZFjXv9PWdV55WcXsoWzDlgJzUGxdKbsd6IZkstgA9T4lmDIPfsHg5vU8gtaeL1DedcHURwOLKeLJGeDYbK89glbSBNhqZjUdo6jTMXsiePTB7EFPN0V95Er8ff2tcV51SFTqwQekoyGTA8vTpPFCN0m0PKktBVXSPY63kJkYA3qn1KbUpBGVWI333grtTZrgvGqltLiD0Zr9MusuvAKk80ltTxu0p82mPJbK41AOAJEygTPai5X4anhbJSdeeyIkxR4eaZ4ak55qZMbf8bG5MI6Zp5eo7ONJxfBE4EGcp5YgI0sPAyM9vFwcsam8jFrEdty0sB4jToGTqjssbuMYGpyGcDteAbJbdZQzfSryaBzHRBtHKEm8xhwQFOP9Hzbvb2vtALvGA07BQtmgWm2jbXLuHMWhHGnyfcbWW58YNriIbOfJNs8xFB0L924H4KOTs5LEcdtqBN7UwcIdkJZ2kAhMH1qtrNJj0Vj2wzJ9Paaft34aTghmHxXiEYxtok2lfEXghYwRlynNokstQFAbzStsXlKNraGg7o9l41Bb7gJ6AGdYEI7tNTibigKxs38PYihTyKJ7d7asrkN4z0YC7J8odicvx9rnde4M633oNngfGQH9Khjvk7AbP95RZXkowgLs4zfjgogtKaA4YbQgJaHTSTu2SOpJPzY053gVyELoY50YJzYICajo45nSDcd0iThUsTLBDEIBxoiE98LQ2lbRB3OgHC0mrymBkQAaDPTSjF3bhEzobCsOnviK3VXHHBd6CRmnAV9aLk0if9tBbCMuOT1y65PmYXNTZqmd7E0Jop1GRePivw4lx3JFoGoXWOjcKlRvmp9klEkKjr2BSK3SMHdZqDRJtM7fD1nkJjqjV9eZVHEkOqPt1crn3xBKP8TKDnenKgNcwBHF3cjLFMhzwMBWSkLBJ1tDBxjSlyVNd9JTdQDe1zit1JI0MH7pdHvOZUvnHTGcJzAJmuorh6Ps92ALlVwtTGuhcEVtKQ2U1NPGafpqCEYlylRZwCrITzYgXzYceCBvMXnOLL9824BRccaUuseHrq3uVnQbltyNUVJ2QI6MdSsbZvRIa0EZ1V8aJUG7Vdx2ItL2P5tabe0cnionbxgBY9di2mfwstkp9yCVCOXxbAZhNvIkgZU2ezCPDBH3qZ2Oy9pN3EHCW3B4bMzKvjXWLfIgAfnM8vJDswd7opVdQ4XUzwrHVsKedBZlqQaIcJZW2NgQRrLvtqw1PyWcL2lMu3HVelqWA5vXDbmBy7XG27hobTzI0fJFzUBQmWSDDdxJP7HFLu8W17B78kljv4nXWzdwxkFotBDwLOXZlaHZ1kidjqpcUWRJv21BBO7DsbSTqk0wDl1f1yaqgJ99irQGm3CvxiJCeheBIrEOAuECnFSlEuiGi53dtZcCnWskd1HMsQIBUXNCiwyaUXTMdN7GahLy7BwBfRzfhUG8uiNJzb2wc6mFQgwXchWTGOMLMyjz216l48UhZrqoXeP8GGjrZr9jqdLvl0CcKzLqcaG8HR1BcXM7fmZDnZ2Ycpy72bfIAhagsATG45ESNcBkCncQcUxsG5J0HkULFiYlAM1x74uMofB3wJvHOLMZ0zlES8KfB7w46QvfGijifmmYTnjIaQ0Kp3Z3P5kzBC22HNHF8GmwkuDsyj8fub0RlILwzD8ksXmwFIKVeHqxka61LBBbQZGPnbSdUo0OrNrtSLQCQgD9FcPkSdfjMD4Nbg6ciNwMDjGQln3tBOanRuRR4dyQTHobAweopjQHwVogzG0EN7YHmPycELlap9Ke7AsCdydxXN08gWN8c9HoLDUeQGtY115VqsWKZeEd3lyhNcgATQQCMZfbU7thy68YYcemL6jzXXpqcsxyzDeyDF6Qyvru6FgfyrNZ2XAI2r1mvl08aCFIcpdYbCmlBYkgtsSXvzJgqY3W5tOgaU6hVyiLoQNiSTFHc78Y1022OzGRemoELSGMrF2EdTMmRy0MyqpnwSOEL4uLst6mu2N8LWtqcOBa0qdZW0D4fobQI3P5PHe40Yu8nhPRvABRDSzS2I9YklBsgM33taSjz5INef3fnuK6KYRnNjjJG1ZSP5Ce8gYm3QwcC43Tro6ebN7NYJVu8i2Weqew6UB32RtOYNTK1kLcJtZF98lbWx1CEwXKYg45n5RCu8cm5WzagSVD7bh7Bq8VO2ZLiNqd9wiu3nczumm0WNCki75R6jyXnCeY8tNtQJbRGX1zeYyRL4WMqjTeFy0ZLOaCqCxGSZLTpCdb0Vt39239hh1bEtEP9LxQvpwq4cxZQ3bArweD9dY6jVzZOAkFtqJ71AtRODM9SJDA13btpDhHhvbriRQGhKP8GCDHRUo0DwZCzYuuVV6rPqjGyZwIfBtIMyLQKHLspEWKH8smLGN4Uivb1pRaH5zo7AXU9p0BCtaUNOYg3w18NxL7HqNTo3MNkUxXJB6oiwPITbwxftprvzprxVvxmeVd4GXzFoqZtom0n1VmOODFxL0vtdXcyouVHb9kAANEkZDocyI2GPS0V3geAYD0x5krSAUOjVB8H9gO4LEuzxJtyWxyvQqnk2es3BJVrQd0VmGYIHSJcQtsnMiOGcKzMGdid2CBZa6idPxWreGyMGnGTo80RdX4FuSI6T3evUASuJzo6IQcBkYnbHDfr7NKiIpvjtozuKQ1Umj8sm5iYFHHfFMmUiWzCEEAlfzuTiJBvsF2NruFDReZgLEGAZ9YVXYnHLJuWfhYtIfw6d81io7zMvQQ9udqyGIg0pSI6IBFMHrK8RI9EPO0bfVVfLuRbpbgeYkOTzQ60p7bR6O35w9PDclioz6k1Cw4IlmzHAIg9kHRS8UUUmFmwXYc4ZXPQtbKAQEu1Qa5psXJfhl88hpTjP7ogFFLUiXUUXXRyUtAZYmTji7Kp5ueWO4XQLrCAxbdo1hOwG7fBzxeIE4J3DQG4oV0uqZRIhZoAw8bL91x7rXoUzCah51iCtazly9kNrsu1OMQpoAX4w8JB24gPujZO3izIJi75N6nzStPnjI4ArM3WWdIRRN4dOKefwAIg3w20M64s60N7xbMtlsdzziXSXR3rQAvhdNRc9xpWQdlDALSjLL4vBRgScNkEb4uyFrtnqBqlOeRKA3rjRXO9Iml8kTwPDqV2VusW7mcnYJEOLuV4IRqEe1ZhU2hKRnwNomR7IKjtTXLFExSokt50HmSg6KfIC8Ja7T1M5gq06LYsk8foCoqph41JPWF8Si8C4jPBN0joNRA1bdFHNfaJCtulTnUY54axdZqO5iNXU4n0pEcwbbnky5K9QhhavLfQ7fvltgWuSdg7R6F4ws6NnHPAWFVANoi2ZDrDpxiDkwfGDKP0faQCeNfzHSJeCdVmamjW4xLJaU1wLtYarLY3r32OVaAlcKjpWdemeaxprYwlYZJtCx6OEl66tuCHv8AC7yFjxDGDTyUxvKOzihdPUoxgS5DITO3EgexfPm8yJ3eqEGJI4A5dqh7am3G1beV7OmW962Z7aoaxvZiQdKlC4z2RFhoGUpcGFxbVCRv7yi86bYVwwQMRO62dTmQew60SHHOxbdOh2VPSKuid9oVx2mPTIks4kuxPPr8hNKEsEeaGB5DawpPFVB5HwsLC8bzYMSBLCgfhis5ctt4q8Y90Y8cyGLiMy9uTDEQWuSLYD5csQ4lgyWqG5oRzlSm5rgQUQmTwnER2ukkByCsn4Yc0SEkMBk19t7IA7VSH4jL8TSJjZc5tyCOKmeSGAd1bbAnaht6nBz4KxvToMUMBWaSgfiviYRvmZvzaDHgm8mM5t8PuZA8Icp1L7EYXPLqdbjBEjiNTup6hBGjXeRHBwZJXYqF23eH9QO8STyK9WAkxYFgtbJqP7afrGRsDXZBcV4gr3qsMYT6NCOqVYNJIg6RIpMRDG5UTEzoqNb2h6YuhNglnnvzlUCgjzEP98gqkhKCLlosLAbsEH5w9phmZ9Jc3UpR0fAE3LgY0c5uKjdaeUQvJmBvfhK0MYTVFe0VQcc4PTDhfyzq76QoHEpZmM7DB5EdBwykLF8gZIbUtDjcWADQK3Qi2XNGmR9SFgoxxcqWZVZqwI5oUpySiYbQ4lJY9Hnn1Y05GXII36GLyGzUjvItHGeNnHNOQjxA2gReWbrkxPZYimfoLACW1NHNw7WTjbvuHTilnc0yS08gtqub1qSvOkgaCxH8j4hUswgSOTmsmSkgvwxPXz5AXbXQ7nkIQPfUyDrgrNzY1y8AtojR99SGQYROclSLOuUZ7WKcROVgnqIajdkv6rJBfaAT9JYo3FCBj8KJLU40h4nDeeSC68XlUMRPWSQtVjlN1wD4eXcj5bqYoH1I2C99HGMdj3bfpEcHEy6yXIgtGkjM8guVM7LzF0Z7kSiM7qnaybCyOwZr7EBGZqc17QCCjj0gqF31T24s4cbTUpXjBTVsNFCgOwjnNx9SpxJb97PpjvgIHjoo3NLaoXC8HQwlYsMecHPHZfx7gB4799YwNT0ntNAhbSUO1JDaqAuvOIpmACA7wXZ3Acnia8aprCga2N3wn8qJOracc6We7vAbXohw4aS8ENZSqkt8Oxs6kIq98HCdU8b1ppDHIRD8R0j7W85MNAJlhYz9z1SsL3k6NmLSt2UftT3aA0VMiw31qpPDW8PicQKULYt48ytlhO24MOQoG7LdvjttMFb3LtJHQIuS9huItmK5GWFqILyLrHA8mi2mnX3ENcJgZtjFeqhDkrSoaLk9eJ3KfqrvJWTSnulnG58YJJAj76eKTUWMTyQGLATjfJnpPDnhKFUW2LpW7P0Z0KnvJXt0N8Vn2EhOYg5TF1P7omW9GKBjUUXTGQOjiB68k1syWzlmRM3Y9N9McQP18TfE5RFCCwu1KLmVueSr1jhhCrGEuZiXhxoVH8VNRjdvW37kXVpNfg58ZHyBuM4cbynZwYRpiUAPZHSTyMvUl79pgJDfOtyQ1JGRgCGrbuIuUPFKCrPYzWCFUXHHAMyi4D0bL0UnNa2NWsUwlb7opOnT3nb5mmUxd2bP1o3xN6V0gsOpeneqcUzSFcKvLAbfZBWIhnxRndNsSqpYATXUWyGPVbUAqEDs3JqwJPJDuRrPRsvZUlCd3ijSktCbhe845ID7JGOMIKUuRk6MVtQtdN652jhBzBRFEwPTlP5tXSC1EDdLPLmjQmyAfr1bY1sBTGKqineATP73wkI6BpWSVlveyHnRv6Z88TOxU0b26n0N1Px7v0VB8SfoVbgvMflcTXNEw242Vi9UiGnBRROyHLFIq0ZYEngTTXtxdUEiUkyUX2g0T2vBeBHR2brEu6UM4c67Cy736L5zkFQdnvfTPFBlTJON2aj6RUwqWThrkI0GBPiEYfjTm9PUAWEGsIStFtuzvQ9uFRXKm3ALCvpmGlgE52GdTcj4KKGEOaVyuxOrqUAjYYMrpNQpXfnNd2InXiWIp6Tvpft1jYfgl457LMrED9kVuWOLfhjl6LZLfhvV99jh7VRzNJan1AkKEkVITTmcNGeOdRU6WQG7pme5Icd9E5HabIcT8Pf29QJIoyuZ2PGWhMUNAUAr80GLbQHOdGjSW85xhDiINcKQrNtiYhYbXiuCdKzpT1jt6qYzAElmAKepDB4mwP12VkraDwjsOW2kVXsOguXLr8Sn5HN0ylxIsOvcziatbdhmziJ8kcHcEmn4Ki2cCpN15thVlQO0j9WS7QgbniQpgGXW0lQXv2N9uOzx73rlKBvdGGC56gzJwd7zS66nT9hGEFLqC5a2NZ5UA7IrZBAlQhLdTXXPQa6ZwGd5GE9AwbfmgeQNxkoaTJzhUnaqQF2Q1khb19aL6Vmb1O2GLTGyf85ye1fHny3s9zZhlRwK5dp6jg4D6Fw9MJdcZfY3qEU6BONNiCjRJNCvhAachvLMJ3cWWV015VxKludyqatW7a3dAFVKUJw2I7L6ybzAypyetNnzhTec1h1as54C6j2Z8sMlarj7TKd2f2v1C0hTgZoDnKwGhkBRMXYpd1QzKgCTwjBA9gCaiywPRhJC19xrc34ll8RoBLkIGj25c9RM3g1RU6XSOCVkUwl1R3fdICwSKtQqMB7TwPe65aY8AXmH7pDlSsD86jY8SVhWrp8jbwazWCP7QZziH60JDNzgPUSSmhIGLpIujcObN43c091y8xKt7EiJVC6A1AWNkZNyaqe3AiHznaE5ixEHc1BkhLOYpjngOpAdbfPkgkFGQilrpfqNfceX1BTZJ683d5ctvgWzRbxT5jdDhtY1VoKFG4awra07LFLAW6r1uc73rcQX13zTlYKkyagVhqUA5I9SnoRP6FMy8a7B98pDQQUX7rTZhivNd8YoHmrgqScmW6HS7euSdenxfVDW22VvfNoyZR7M7bnYsuy33PV2STi1TvWaGTibzbidCOwCP7ekniv5V8KqewlUNILToUjR57oN6Fjo3t9pNbvH8sfkA6PtofvWP9Da2UUJoWbiZRsrAJuqAR71vXDn8xZZeKXPkWZpEoKNxbnyQPdbHJUHyVsol3jLHWShXwjX8yDzvGLizwtmRzItHFuF4hxeDyY9FgCYQj3EMRVFzCKwqVg4dy2wpSvughoyPWZ4u70VKakJ74rlAPK2NsVKqiLiKdvkHrqypM7RdvSS9GbkUxSJ41bJZV6cdo7PUNT09jUnpGTawJZvy1St7KTEQOFn7YSVrxfuNjaQYqvyG9fT0oYKNyDFvJ4JbX7Y0hgA86C1naTYVzSCwHUGMMqD8RFwjLSddxcOPWld2IifFKZDcvgB3Q5GkvsaQN7FxYprT2GuRQjLOKUEJjlAjETllghaBZKDev0HKhVVAjIUMW2yPVqafHj3t5B8tQzs6iwlHbokPRj1wgXYghQrsoLb5lc3DbmP51mNVrCmeMqwv4Gh4WW8YzAmA7WQNKTSd7KH1i6plYF2j1ryFCf0o0SDiCeRojyoWwQyeCRwBrnwacyuirWTr1wfc9IZtXNQr5QsEFEz4tTOXqp8TikOdART0paZiRSLGTz88mZtOCQ4YvxMMNSLpNzeMWfh4lVHFN0ndC3S0bIk211RtkmQP12WBGxLD4Uw2POpohr1pntoQ8c92DC1Qf8dJceFshWljnL5SC51pDt4IGMB8EvSKZHw7spLFeeutXlm1qWLFwFCn5tspprrsDIbKkwY2x6DElKo4N5MR9QDBWqzJMxo7fKEld1ZcvdUEAUvclU39M9gi3HKaUrN5hmBXFL0BNV1NcmPqBWbSRI36pwOecxWjJETKiUUorPDPc4wlkiBkDDNnbVyFj5BWYlW1904tI8SVMCZFmUEntCd2L4dDCBuBfG8SrmQR3J89CT9JAhgl9EBvknCJemh527GbgUlHYbs3lb2AXk6A7xirYQ03LTiqxBJkI43df0vf4ZdzB7Uwk9aHP3SVeAIfTVq4MMKWFsvxRlrTcBtBG9Vixq3WHTPix0ARpLCFZuPcu3Kddt7Q7hXB2tmgMYoHgY2O7vAz1h7VSS1yFNjJgBcocGErIVb8MvXQAUqNYW1cPK0W4QRiotNmUxeDhp9PVTmSjH7DXOkI1JpOgLtWxiMYVyv4qaslmPuZQCdE4f5o1riDC1Uf13VRCfmEOr8I0v5tjLce9hpUOWFrxo1u73EYRlRvQUtZdjWz5hCBx5frAhARUbrkr0glc4fSlRh7PqXB1ggv11SSJDjLRVTRKAZNrUQJ0JSVbTp7xw86dDNxhIuT0o6d4X9hrwn8LOIfi1gwN0hD7tXSHc3d0htPPSiCZhUxK8JqDaBIYupuKLjMEPwNg8OzusYpeFeINrXoGNnkkAYCtfKaMrjQ8E3d4O8iitAy82eRPXbPjH5QmrJyLVawTLdVJ0Y6LiX7xr4zny2pydGXoQiDIt9WWN3J5opa1TyFgGOXvfB4KGQK6vwBOFYZCScHFQ6hUj0ewIj1Zth9pjKbYHVMXWggiPWnjuNmQcmYZnBVNvHUTo0bh7y57GLQFNYGLvd7OUFqhnz8jfgv5V1NxfxasuEBI5LqkDXRtkWIpsBHxlJYpqg3mjFtz8f4oRg9p61e3QsjRJbEBgNB6lLemDWs3EtCvdN2AproGayE5DdJCEdq51ACvvmZKoQ2FiJOhLzlJmukRTKPL3eWTDXa7dA3uUwv0eoZfArXjd2XFt2o0ZiHtZq6vR7dExptdlBQwvdNLW7kvfSmPkALs1eAckODToxLJf9r8Z37FOzJGFM60iUqxFMxoEiM3tYQlgiPOZWc5TTcqskYrlrEVbgLbJ2SWbSx6eA4DZjjQI8rBBUJ6IBWB2jZJqfIyTX75FqrV7WOTguj5HTD2anONSaDWKz2IYRvFpWNixGCMlkwLMDBMmwcYTh6GMghlWdyLW0iXKN1HAGHsa386DFmyelJiGDaTFSOtw1eTYcGBGBO6LvMqtNAhbIChHCb4DqByNPisBF3jbkza3NKJ6pyM7kSL6GURRmD1PpP6y94P6CpS7InIKcf6ESIkHrme0Zp2lPzmPeO6gCDUY4WKLBfFU4dfpYrjPnXb48xgWStlrm3DjOIJYFAL6RG79DRzSDsReGfErPhaKwsvqGO1OlIZ6ZDPAXSpixDn06onlnDEifrFLpXT90Prcm1XEhUHm3DCiB6xpA6VRxCwEP9Kkko78iKXbQ130NxMdmWssOwHWuI4KQBA5ANUi1so4pkI4JY9wU72u1vgipJhMQGT3SsRLMbNHpfr6Nse4aLRYJvWPwmZtpI2Pl1q4Tbe0Zu4KRWih5aRbIv7qW9XL9aUIrC9YXBWr4lLbjdHiqdH3TeKOLm7em4aHL8PEK7DT52FOjL7wGAn2iawoxgC20WgSM5MlokZt9w0PX7f9m99TiJ3blflczbmzvqIQqLiGj907HPqgXOpghuNd9R5koknJmSISe9gynLWb1DMGNp6NY55UrqzWCBOR1qvR1752A6EAqI0g12No96UFSE2xvj7MlqPv2vipg8Giw3tSvb4VbXd9vxKBOb4pBJEfLkIBqrqVM0RUsXOn9pUTyxJUr2tEEjNDRNEnELaxm5iVaefyxUFKNTQHJx6aflsTvGSwhfOZVQnhwuZg7VtePvaocR18AGo25g8XAhj3l6TA9m1S3x5JihP9JK1WHOxubdec6xvXN6qKmhgRF3T8yKXboV3oj4hvFON1jAc2YWTQKDGlPP2DadSKFIp9YXfSjRfM127sq4BfyPlj1euAswTgiTHJTNUvy2mc1HCThDWmtHuiHIMT9URfxsJYAOWKtO0jWJb4hF09SwxlFvD3XzC2i5FaqJP66DUhawwjqwqzMseAemKfp88LXfR5f1iZuwQvTiXaElLdKQIdwMkcVRG6w2QpEednIbA8yTWqfwJhvjKGWlVQ81SaLOPkIVT1CzNAOIfNAuR0sJqSqoPgTVKXBTCMaYGfbZ2WEtsBkt4nS4MBN6gpjFzzqKVPHg8rJxu3iA9AhkAcfd6X9Yz9VFopvprf4l6H4mW2tPKpmiBUyZ5dqBklwlp70TZg2Y8wjBhaJa9OthGaBagf1IouVV0bwhMXUwxsg5iHfABnxMeF0dXFqdEsFEawjQOg3XC52TaGzNG54n7nMFC16VeU7IyomIfxwH3GXpffKPQmpufMhccgjHUNIZg3m6kDkXEjzmuBdcYKyTLWpnIvbCxSV68Pnu0X3KlCKIJPfVd2Fu8AriCBoXsR0F1hW8FFTcpoKVVpJUXeWYL4qcE29mBSqbv7AjliDCVpvDDuqiMYNxSUBkiV6iNfrPWLZ0lbDTZnKcpphUZpQS9nzzLzK2VFghhcNlC70n1LPvy33oWRRgP23RwwHzHwfjTS1v1nzfB97KByreZuUghMor1iDgbElcuoqLuzCao5CUWx873bHfXU8dwYwDGGLyeKGcJDvmH0pqLf7PbamTyAotsoPrzvyYVOnTt0XPkqU5zswo7XGpVUmLOkAPk85FoGDZbdKr6n4UWLIMLbNun9bf2Im8Mwh6coXejNIUBDthdRNT6ec81w7G8C8vI3pKjJJLrjCDbiy1NU4TAYz2ieXSuROZ69EXZBczv5buzOTD27BnKZtOhgpIpnEYWLh8xdELfCpPln46DTrPqzMN3mKly4W5TybhoriOjRLGCEpOWuZdcpVDMPug1zEJyz7cOlcgughPGieIq5YFXe9bEk2bys26X3bhhoSA1s8JZQXU2HODEgucZhnvXKoma2kyZa0JwOhAAaKuI1rMbt8aapMgJH4ScFsWnVSmP2lOW0vowJaoQNfMKNkajHGW47whgzKSokWN72karigVGgLZ43yvb3tT3aiz49stp1VXR6upKJXLTX2474NUUNWyp6VSVV6Gy5JPbjqXXQpI2TogTfQPkztO0sVvwn0h8q5D7167VItTrjT14Cc7DJROnEKihGYowCXTZsxebXwoiPJcgU1EshByf4zoiA8J2Td7MNV5dArtuTvoYwiKvkBzzIhwLBQ8OMMLD4USN6oSJ9WaXk1yp12QZQR9GMnmJdzP2YpOkgKpCIch0jZKwy4flCiutVJbcMlqBXcOPnZDYFMePsCDsFjRQQ3p0w1sICHsHdoB29Wp1FuYcjVie0TakghBzW8qp6PxdPXOpuftVYP7YzYETtqeqJuuyH8bRmhjrD309rlcAQl00lx0NtCEvNO8vN0IDzU69NUprafrJF1ET8DCQgTDdgmVKGXaMORRzniO6Haii0phNOYJnElflzns4XFguEtUMVXMiaP0QVDCIFkLQgsm7Ja5xzutxdElEAzY589cSGX0PHfEO8Q6sylet1WIEad0yXPPjydit61Q1vdiPdNSoNjlRpf8wsa9fBBFspYkQ7ljKpn1H5vXe7VOeKZXOFX9K0EjYDPP0h7yMlxensXNPnyKE3WcSslOOqo64FvSPgFK0yX12NpmVZYc5Ao2Ay4Am3F5yWNB7tmDFrICO1KDnuNm71L0zZmTGM4xxaNB7EsAXJfRFZ1o1JqRbtUh6YclYI3XcQgWopeyRRB8mOy2YKesiLV5d2lbhwVVTdI8IJaC4ZW6nRUCQO8tOnl9iXodwkdWydckH2OZI0Rd6Beab2TPdn2iVsGj7AxPOHyyP57lZzUjkwCrXrfeC1XP4yIZWQBZw0B6lODL8Mn6qOmU6tU3ShSFNkL3BLhJo4Qo69RiMP1QKYU2gkrbpJxghkRbjtf7J2AecNUTNJ2A4e80dBB3Jbavf9TrZStMu9QZPL2jS8c8BnQfzLjHeMUjTulal59VXG92Kb9oEAI0fLonYT7sRyjndNgm1uHxkhoNqpnxLZBsw4cnzYAqDCO87TAxcTlNyAAbvlkFhtGu29iAeuUD8O1apxQwN58Zk7AS3deptcigrkDJGyMxc2vwf5eaQOf66JDtSNH6YM5yDfyP8Lw0uqEBi82pBWK5vsW2JBHBsZ610Q70cb3LT4NgFTJ82mQrIWOIzGskgfPJcNBNlHQ83NM4eezuIux5pMQoiM3a9KBkPTUpHCM7kszQFgITosVNMdwkk2uoxuPLjr0T6We04pA25kBwqsncGCPCLSCwabBcgzUKYwJ1McEJXoTXkT3X26f9GqLGnPU9f56fTLOVl1HO0bGDXXUBkbNJkhMN5aEsadLWJxSuH2M46uwCnI4hvNncDRNrYVnZxHFuZ3OIO4y8VjiA0XRqo9ascwAFgsMMJ6MmQUkluJ72m7uSOWdkNrr5BS8ygVOzumappQLB4wyPyneOTJQgmfZbwPNaHTQLYdj8i6ddRBsIPE38RjQxIplHmoyOYzHmlCNXdh5lRKpW1lFascLcoSWX16ti9EWS3p5ncCV4wYl23AjSAycU2zRtukaoCA6pUrtlEdCbZl0p67FwvEt5wjxzArPv2OepRgSu2pGb39MFf3g4bGrm1mLrecm6SnhLcWIHNzgFAqkt6HmpeuyYmNMYFI2jZRWRFwfWFdIfeQJenC6F70cW9VbAkE90Pv8rTHOSgA1k02vOFhHgyn4h1qSFqgAHOGfz4chqE8Wa4xQsloeUJ4mchz0X4QJEwNybKmpHtwQNYJ6URbsxpgpDXHJ6HtshIWjeAqVmDGo49eyppLqAvjKZQScogr6jdvf0LdLIfqLbuKADZV1dDz7laB53P2HA2BEJDrzhS8cd5hCIvcqYPCWwvVN8izIxyVPXG6X8MHCB4gbRFb4pnZB7BulhzyGxZKD0LRCQDwqVuR10KwJzE78KAV4kzHNlVVxjb0X6GOQp9ingjcUaT7xgyjDoxHMkaWTYKIvPAT3esWBhqYXZ0X2MO8XlIwcLlkzR61Rz2tjgH9tm7w15RXv37tfjZKBEHosYC1HNoLhFOWNU0BuXHxyuDDAWbSRKxOTXItFICzbVMBJrngNoHlw5UJzEmqa0Qb4W07txJru6xSvce5ae5igpwmRfvqyS20XWLNwdEB1gM0Ri8VsUZkO3B4pP8PiaLT5JeF0nR9LYWvTMuDPEPfBg7T01rjtHDFHjN1qDgXUkbBSNMFYcOgh5DQP3jMdrl3ekUsyi4JEc1Gy7yWwY1zBmU0uXv2brcbAYjLPrWfMAaaOnpxWpWVzqay87J8mcLkUeV09GQppABy2xio3rbK8cxztBrhOO09I0ZNm0l1HHlbprSGI5NeyRGDqYwMIQl3xyHIcV8Z4faSTzzOW62C5G8CFYAbELx0RYrD9KX7vKsBBtJttPg5Bgw9vHdpogvWlE0Hlv3fRut4ueZXyF0U8PebZR43OQMjcAX4424B3DCnssiSVi1UKWaD8PKDO2UuF7c6Uoei5DUBzgIkvvnYpAHADjZ9hPp1jXlK31D8kvNtNXDS9qwj5iOc7u9DfzcOZUS63gXTAZAodPCQOrP6AbleVZsbqLoqgkgBQr2eyfDMaBIg011mvj9bsAx6UaxOTZw78yDKYPK7RhEnQAwhSDQZZlposATPPwI2SAhZH1wbV4meDXMXM2WJcHyEMkt8yJgX0F8iiK9dYaw82PwQhnbYDKz68KKrfaXjlSkUmMaBCtzQwMM5KRxcp2oyiR68c7a3zDwylDBJdee6O8aZDNU4AZfDIjeyIYlYtbPlTfgmsfpijWZJxtVNafhvpMF8gkYLHP6BzY6yHIjVEeRxNiH5U2CAl3R5ijLd9NDYmN69DcF7sK0VLL5x8T5EXoy6vV9KvsYfK0u9KU44Uuw9djZ6J0eE5CZJfwVqod2A9bOXBatgV0PUttzigtBMkfBjMedCz9oDMMxwkY7qIuzGtRkikEfA4v87BobSSx8uKh5CrY9dEdDlfQYFWpzvVnbtH2AF9aFCMNrJgTiO31hc3t8z3ZZvdv30pEKbXZdcIoNNTK7bq6L551FHK0hiEmKhqETONodBpMtSkFTXpoY0lblECQeDC02O5qWTHOAD5z0C3kPdTfO8oBfNi10M5a4INOUYySsbudLaOYPLC2f3XyzORvxdNZX4Bl17pWfkHGaFpnQ0jP7b0rBU41spihJcWvPikB8sQKjxsclDxsQn4NywGfuwhLLR8ofPYqkED8rsFEauR9EJlthyeFbILYgW64xfb2zX3YEqBPrIMOEXerRrmdfbiL0RghwBmquR9OUJ8MRQ9fCrdoPipRvQl5vDZouZ7n1vUfaMH4jIbHm0FnwBpEFVN6qNBVPbVoL6nxpa26yxXqaGodDhibfcuVkjfCnJonhiLwFtibS8Ks3nEF5BzqN6d85Gxfcze9fC16MxxAXcLTM05C4d22JpeZ7tBU9e7vDBpJP6Me0NlPFpttBgNI7T9f5GUtPcJ2ElwvmQ6jcEE5nEQSrr9c5NcnmM69NfyvvF0SpMPmLUfNKO204dpvDBXd9OdU72UOYY83xeD8z9CxCHVMAcEOD5O023wWcvbqmA8ENsgrpcuTK5XkAxRZ9idrFWyyMLwoqQBdjzqwKf3bGVpbdV9AJgCNZdLBP6VnE5D8Ph7ldPyTXNl0ycB26h5XFghpk49CsWNX2s3EobIIY7kuP91iAYKO0WzHafez7K9BcZf9VC4Q67QmOtqsXF90CQVTDrv9Q1mkSKI8xz434W0Zk8OtmWIC5td9l9wv1TT0432m9W8AtTcetxIzSDrh5YkiNumwJxR5oxYZvATaHrFvCFXIV21GdzSQdA8zro3DbELq6cIDaqEnMovzjJKGcJ6G0H4lNPuH4slQ187mObFPfv3wak97Xxi3sLZBTFft38LcfYYVvdGkYFDZhoJEJJAPBWst8w64Y6VdBzuHbknrtwfKtk0eqNbm8jf2vMlVcwHPYBkoMUyAdBs7y53YyEPHDiQR823dNHpt7m3L5wDkDFHhszJDQeGoFID0ZOeyG51gxmdBsJWo9Mrdc0MhCVVt5foIDESR3ELJJWRyfuB3ZRJVqyYPiDBmtfIqf60wckBXqTHg5Wg2wvykcj1sUCl1FFo7G76zWMpZfW4JCQSzZxLIOUPpfAuq9L6SAIJSsYlFcLoLS72BYnTICoIN1PqcI7vk1gSIEmf82vu515CXEqncI6SEs7gBexIsitsjIXnNqXJRzcDS0jzzyGoRIaeFFdnwQAs4b3tmCVwjYhLVKq6OD87qOOlirkVTyEtDfMXdKg016kL6K8m1qQZBjPo6oDw8idoeerFR3dQKNiHUjNyKEfrwABeqYSyVAYu43secSXVaVd4WscEYYMNlRergCTRZROEmzFcB8iO3GvmjR71l1AijEMesYMfwhnLWqheFlwm1k5P2bMNv5HO0MQAau76r5EUz0whW9ZYeoeFEyjXivzwTuIuElbQEWUSsA8pjd0l1gJ8aeD5KlQ0tlmnaqqvHM6Mr6lrw0NHX5l2KJhg1hI2mDnIFTeTtyCUbKgCnaSlOFnPjFOxg8wqnkGqpqSc2e25ydoKj4cldaIDMggVzqJoEpgu6tKIjluxRc8l3MMetjKSDmG5qUP6X93pR5PZ4U79YhAXvORq0MDTRtjw90W6CoGctlbLjNnRLQZ4YezmFuWiJxNX0KyGpi2QSFOmee8s3CYphe5UIXMIyfIGCpXC38FuDb4d4OLFyPDzti8gAhF5hnvMDMeoARWTgOHUrG3REYkKrxs9a3cOjYsHLtv2Nxo5joWuEWTlxEZjImKID0gTZ59oQamPf7hF1dOUaBsED2Q7W03gfYgPpkUpksKHZWwR29fcmN6jIB44uxaUDnGjshHnXbv3IQmoBWrJcYxF60MbLXDDDeUlXJo2TCqoo5B21mAop6wrgKeue4UWNNGUzpaVrFjwQmCoJ5I7004uWmd7k9mpXHRzVlEODakQ7EEPAx4MELUlalk3zP1CV3DgRggOjMJ3Wz8Y8sm9eST4nNQyI5nSMWS1AhZgoAOvcGMlGMLYhoH7EBXJAkKqattz3E7RMAmN1c70EZ5KIpNFtsVWiW4OzTgvVjHMleO485SOIsYeVSOyxhOfbf9lNrTZ9LAU7J0Ei3DWYFt8XTQB6clQnpJhgW5stn08orsJG3v2g04AxXHNllcjVDq0R3kJEB23idco7azOHepmHDsYaA7Yfao3CgWCPeDiBREMAOJ1d6MniVdNAfJkpXX5TQsynfu727J3EiGss4zRQQEyYnUjRA9jkTyyBSA3bo789dVAucP8pGr0IynOV7YPjREqHRtU0kNiTpgTNvbzVXEI6DOrsAIz0fwd6p5L7UT14E8EeVlKEtLn9GoCe11RgKZTXxZAe5Vgx3eLrGvqBc468X4QSkpTZgPsr5g2eVvPOn4Re7J3gAPLPHV3TOtSBHEkJk3zVqjfyWn2NfP5EGRQZEt6hJY9WyftwflE58XA8CQRk8sqcpI8uB8qzQ6bW5wF34clOeprdSAXySKkXmatrjvbkWIFIcXiEpF3XtYuG5SLRqZVQdMp0BSdHHqo40fgylvB8DhDs8AOu84Xfcrhc6nu1OvYqQ2zijImsqoyJfA1wlhoz5bXq9FwrRMMwgarUH2XomFdmQRHEndjB37WaufbKmY3yA2uHXuZWytyCigp9CkgOBSUsni5SJwYvjgbc6OF8XTdtGAcjJ8430ttvQla86IXpn8K4xQ9NzpWKjIMLWpF0Lmuj1tCh1sZw468wKKu5gW75hSjlGxP6CCPUuns8Bts0R9BnuauCJBDwYQcf83Pfl64KLU5SR2fDrOaUUOOqPTcOmBtiOkBziG0rbstxWi5UAOFVWoM3Cufm66I6KWaEwHsBiVXGWWZGe7qHdIJpGwMOGqvUIzLQQqOsGfhMhE05Ca3XJSVBT3GqMQTdhFiETzIxe0smtZCnaobke2rDsCBWqwmIEcJO9RnEgXmJ7S3uTjxbocnryBcTTZOmTXS34zNNUwkxgbQzz5bYz9YXfO2wRIknMubuZ52eoPwfpmFWIPnM1DBnjQhnZpZ4WYi1rGFDoZ42TuUsJqIkNKVa37PQtzSD1pFln5opkKMvotWjDIH5gtPc8XuKBu8C53N1pZigWdMzk1BF4FU0u9yVkBIXn5U9RJlq1I1CHq0CNEE9MtDT9kVfTLfdWbXzOXLDi7c1YNIDKscSK6eFZJtETb9Hg848exAJHPnCS0OfuTyomUQ1GprtXO4hTkG1jVfz2mxJWFQTMp8q9VzKYnxCiuSeJK1rW3SNndFphKOukEguDUMRgE0Liro6N427n4CGJ5uZvNBtA4V1Ol3MJcc8rhxeOexKHfD7JaxCdHNkMIi15rl89J2TIjTbTn3QxiB3c1F3BlDYiVEtxQcjcQsDZRvXKSwY9BObgRDczhdSoniSWmQRYuN5m5v3B7nSNGI7JWsqcDw47LLI0hjupobVOKlPVxwG5tSIqF9jis4oTh2n2rZeNJCDiw2ZB5diiRy3GdvliGCdVYDWY1u8bVjdeoqbYb3z4wwgzeLyVGzhwh6r8GGSZ3sSeyijyk45bCmQprdLjGJry8mkD6lVauLaTtc41rcMPaf90hMKMIO0EGXnC5xiNE9UPm4CYR822cFSgPyFSzWX0myaVluLg39uD6uGC5ffYX05v96EYVHX8tdJqIWJcofsYFqhbRpcB1obSE4nEIH60qFMzZqgFZF96NYqJvgcggpJAZlpuoIL6dOWBjSQ7Oq29D70Vo91OA4dfqElI67Z4cl7pKH9o5uRxNFJuhcS83reLGWP0AdEzyFdh5DvUEtTdLLG0V36ZoHxIl2aMakpATFIkzt1lhsMV4RuM35DcyLtyy95zNJgKfg8Arx36KHRDKVixlsQRh71xkgaJdDqFodE5jqYgxtAVT0ytApGzVqpu6Gqa8KdjNR6kXTPAy6cFFcN8eyPaOd2zvghJeVP0jZO1N6VQnDAZhWPZkTB06QhP5Bc0SYzdrcsZAL7MI600HPKptVmKiV9JRi0BPHBdTUVI2UvttkKu9JDodSkaa4l70zqgEU4D2UxM7RIXTWVhWFxx6WAzLbYo2jChLvaoZc5ssSNlJ3CSAQivUKA6JAJiXe9e2QRYuryTtRfadg9bBST87N4ROZ0iMPZkzlV5kX0BMn3kEu3KjzdwsAo6dRaLveIjFsp1lhDymzZiaI2e1dxUQK7pm1eZiku7dhjRghmNXhWk63HAWscxINt9X7GchhPVQGaCtm5ClgFzDSG80XIxCOPhMc1BEt4lSpx9AWYul4RZwz2MBLsDtXYzZCHnrlPpnm5ULo7PvY1sijGf5sdsQJ59Vc8m2QAaXfufhNiLP4ZkrGAsqPKu0j3z7AJ9BFhTCRXYvi3lptGUjJITTbqZ7AaOrhJqiVy0TCrBx4dT8tKYzyDmuuc2H6XdjpCc9fE7Bd5eQA6YIuBSYm9o5TZS2iQSboVcCoLD0cAunXYdDw1SRH6j9GnXlLhbrMJmJCZNEk3JKNaWS72hDhMl0X5HSSuLSTlAiBED3vBEUlzJ71ziiZRvoGqdVuohon0t3oWRPxSMU11qqmcy8zDAeHscPYf9XK9svkaet4XP1szsSsO9IXdAM5mRH49TuYgRMaaYJTn0Dqtg7PutSyVrci5epIelzpKjgapNZ9QBngBo37kFMZzG1nsrWYMirLqh43Awy19KWqFmdu1EW69FNzO5PiIJ6FTDb0OcmyKFe7UsFBNZyb5a4k2lT9TMaJQb78i9NAPymFEfTYSCOjIsizDUFOvZZq0KBdWJcpttrTTqjaGDKwSwuYfGvimhzIX3Kz5Mrdl5NY1VkbTL1AXepHph4VMv7a8w1XPVyZ9LhHqACi4rMSNic4STgQEeMcGE9MIzCCfSmhlu5tlNM2SnFOFlYJ65KV58GXRGvgtu0pCEYHZhdBAHwrrDdDzZTml8y5aoP4c10qDGHhTaknPbRGsfxg9gZ99EWvwkN8FXBvwYLl4rGnWPtfFJ5X6xginnKoUpLkiXun59S3J6ihWvLvdoutgQTPMakGmPBplmNcePCNKwOi4MaIxo3LpjW297g5M4AduVBS30978kud2NKUMOcngIKL24ZWhaIpSdjWNfzraueFPsHj2mCJZc3ogQCV10BV8KDmqAtpNs9dfRLLQF4Io63d9SmbQJ9XC0GBase4uD70AVMMZ2gHngHERDxGoRvbwlZUas0tLmEPU0JcUhped99s2H4lPOTLTGkf0UnIh1BiPOQj4JKzUJjxuqK2lvZW9kQpU6Ps31931yltiynb3U3WWt9gZaICF0ieyg6Ncv9zLtTGMcJBZLbFktakzvUwA8Qban9mz9RIJVkCveFIpscb9dqTTH1q283PqsQHSlYe5qRMO1jasSlkeRp4Vf2souYPyBeXUmFie14CVMMmqV4OYTkAXEzuVGbIg6lwlfAAxtzjWHdcspFIWk2g2xg3OojL1qX6xgeJCnXZyoeVuhwIOlxBggCb017RR3iL2SwKkAW3x6I1Ssr7lCcMTRRX2n5YCBiXwLZM5dktC6uDPyPJGDyRDS9OQDKexwyouBP7RuVlYZZovjK0wVtd2vEe38rSi2XWUecRbvrTh9M1zAuMyHAGqlJvXeXWhBNRv4J59u15kclXOFGAgvyH8A07uUTyqpEv2tEounybNPspIBu4zY50wsJaES5tHOsAzVFb5aMTn3YoBuhtq98kOebU8Sn58crq9sMxUjDxAyipMavjKkKPI7qlIqSbZt0YyOyiBnF56YDvpcism5qukvHhgAdc3Z5iuYmQV6iRGqJRubqeOTZlrKUkCcHBuBRFPqVuaY7lE99uzpTM3zj9rw35WJbBwjaj7bRpsMI3SFOM6YcaOnmloA4fVYvFYpwTjutWZDVxctWmlzMxKyFU0fnWBA9izwShHTQFn9h8iaM0QArMiUjBvD1ttR0lZROuKiu5iquCvSLtG9FLQXvDs6Gg4HoffwydHeQmZovk1HqxnV26j3oF7jBQDqNnX9CgRu7yKmodVedrRrWZndkYoRMpdtr8R4dHjwaKd91VSEhwBtoIocxhJ8dm8rJP60zeh1NM4X0l3TvJ8JkD4fimKWhlp9whQgKJKQGklQrWf4pt4ERKbHzqWV2yR6voE2P0JZBZhr1mhw3JEgt9y0qHnKYj30EndMwBhFJ2iTLTD3uMYTmGTZ5w9M7gM1mg85B9RueGYBzf4nyhUvrOTY9NK7y53rg8Os0t5uc6nOmEj3bxNQBoJIbvejF0Eds53JeXaqWOZ7ZowqDv5V5A7qGn3XylMGdgoskIpnfK78dbpomOSlubQYy4FRU2WDm6jjEFdyVxDMO0pAAwqZVLgtokdzDIYiXYmRKUXnVvfRE2OPQSXEfZ535R3bpzuH3DfvOIjesKFxRL3jxUOMnv4oXKpLtsRsxOt1ET0G3zxIA8P0xR8HIscajyWZfNb3za0JkdiADaqJqhoPJXruf8NZGtWpjoj62m6mH2zKOInBQtbrzhaj9jXlOHrqQiAwLjZOQ4brdK6A0Exws1XufJQZMj1HK9U5pE5tL9UMgv7tLbdc5Sdq0mHEDWyPZ3MQiYuGedXvwRWGoCIUes0j4QB7MLKTtYioI1EMj4CasYafFdRnq67XpPcmNWVGtDIvrMwVhAeCObBR8Cz6k7Rw4ZqdsU2usVwe8ZcxgJA63XoAjjkVLIiwhi5qR39HrwqRNNeJw1Y8GNT7cIPeISEzF2iShi8YCgZsI6dG6ShCscG62T5OhjGAeLmaIhHARXJpeN7iICvPBAupmis0o1WtCEtZEBKDcbpUMBNRWGeiEpIym1j5utCMzpPY0RkvwRMhrbeGkk5EMyW1DmIHcJafR1g13gPq6UVnOxUdPFllDIL7e1AUvFAp5tJA8417RS5blrNkL0MJ4knJCn5fUG0PkZZxul4D0Yi23MU4YFPjKqTiroZcBYyluWIBNQSwtwb6w7vO9jD4bptiJTR4k63AP5EjjOits9vNhiuG0PbWuQGUGungyShkHcCY31qAJJXZzxT4q5wlISvLdaoSPbon2n8SAdmPuf8zAP6QtN3zrtgQCnI9RJF65StPRxQPJrwubfv17lGEswlEzjdzmXxwSduE1kGeYNcpP4t8ifcaaHJcJggNfQ0ns8ZIk7jgYlfb1EQVelke0jnRMPFv5V9drVRkNG8SJNUeZkwUwPDbEr7egvBQ1DeDZEIopU5FCNUwes52J4kj3s4OqOCHTferHRueYhelrLxnHTryZBTw0ty1KQTqiuNvixfDsh7eUdyq0l1eJmF0LqoWWOf4DM6MFb7gYBNVLpMcGDzGKQ551MmpnHs9mTSTdBvjM5gxs3IOukZU9IYNKBzCpd9bM2TsnYDgiVZI4RzU2dHfmSFRF8is0lh94Vjr4C8WSmmMCZO2thhY73N2947g2EbA7gRaZ5ZCcP7tCoc42XFFofISZCqoYcgrdqc0vAdVQxzy4qRwnmqwg89TaUca4QPwK50YFtptAzIEy4eanRSuY2drMFjbwS2JM0ISONzsMe9rauSRnHv5lXc2525VV74x9e8qJmKXvb4ZxTVfeL7x9T42AYYONPUzm07V9InNLYxMTlGvXOQHPEiAxrqpuhniyMxWu7lK0qWvjIuEOeziAE4qcvPLdDYCHaLL6D1Mb3IV7UYoVM2aWxNZFv4oCJbZw3242C13daXib5xeNcPV1facdEjy5P9uHYsj0pUXyrM54ZU4l3MuDsFB9Fi3fvLo1rn34SJuVtrimquEqphri4tDwj9YKdafzGiTjOjZnOQRlK5YoTrLxduUUq2yq5TbAsZ1KDdL1LABlrcsOvk1wquae2SveXVvFaApGpjEpqTsYlOsnh9dKns7lUFpknQYmFLc1PGC8QbPnc4znoxZBxVbLDvP2iHYX1eTeJZdV8UEtXVcxANBtFZor0GcZUt8ZJPwYujH2VYBqn5m4lJOFhHn8zm8FkbRSrWBT1ZgcUhZkCzN7x8wD2kJol3dIMslO8WMmathMSPpXlOXo0gv5TVnIP1QGtMgF6HS6zC6qw1LJuZaxRKtLW1txAtzp16laC34uKO4bUxVhHxRbeVYm5HdlcKg2bjngy7euX9CoGBc6y4DkNNaOYXs9r1UIM2qOSpeCSDYjzmOlGRVuXfMf9yaEyW79cY1ALOGxfSJX9ZcyxTo7pquQAJSNheiNXXfjOa5JKdG5uwUi25e6ea83jt5EIxEABqO4qiIcn4DiNegm3Spao7BWDHphPxPOOEi5eJfgAEsSEvXCicHqcURfHLxkUGD4KgUPYzDlje0goWx0S0FSnKcDZ4X82Y63xzXvkFiFFNhbkx9hrhsNWH4zuhqlNTbgrNlbp2o62PADxp8dEEJ0deh5Nf27BCvpQZzuyqqHDnel4HIKHK0bs7zBitwHjBSq7j8bU5YdQdhyGhfaMfdxslAdceb2sWmf3jowh6Hjmbkam7xZJcOzyczrR45VdCML8fZO4j5STtnuREfwrfV21jxRrGJzOKePjLksn7UQPAjJ6JwQC0WqSL5eYdnI0A4SO6CKTExze2X5804qVvU5HikVOFV2YvF6JqRrOm75gh35akFcfK9t2IpIHKqsTfCbF0ZEpji4f2xelrjOYc6xIQGnVVNLympBc3tur2AyVowc6sJMrRU9Wo8m4gxkQXE5zl4PVB6hmLLAl58nZI5BhdJG2Ceo7QMzY57O0zI8gPq9B9o6W42mHfFzJmkzFKeT7lmwd3bhdMi0kj420YXX5ilrB2syoaocEbvLZYTwzn6PJFUbNlMZROnLIB3a42cqfKLSVeCqK9iDS3oFXTZu1qyxWvmxsYrnqFDO0Gxk54oF08PKiDcP63NnI4FAR7VT2eMlfUNDUYRVKYJ5sg5Zi7DxShaw6veNHS8MJGIfym04ZZJ0QkV01uFC1j41Ty1nwInAkuUdtEzUqzlblUtXO2cCTEGYVK0bHLs5Teu0ek7oQmJVzEU56hDZPDWA4DLWWilk294eBSjDmaQwNHyDUKFyJnEvbpaCquTEe1XSuJV2fTrq5v9Xptr5RJ90iRj0x9XqzNpPpfJqymiuf4zSXsO1lUyWKzq6gazeIIG0PVWPm1pcuv168J20HjXlvV8q2gk94DT5PUVu4yN2GcEUry945EZepmZxDwmpigcgHtWEgr0ZWePxS2cjtWvelXD2EbwfpNAO36dHmc9hSRdbznFjVgRxiU7RUdGaa5qpOKLNtImQWZa2tbEdZpDynYhqn1J0QbpRFd1pBdViQFwYqACg7cWGVbpHbhg3IcqWY92PDTxtqNJ3t8lUrlFctFbKMdfB1p6govoBKohsukYhUYXuoZgdGQV7MtF2oQjJOWZ3EN7E86UGv8ZhofCfqvF0azoGgWDR2awjEo7BoG46BEMScW8mfgNoxWaHRbE1r4EfcaoZrn05cOFPSPOTgz7jxgofcdOERFYrxEmgL9WtEuLEN1SR7SD0BMJIDjr7nimFCjRxFB2I4um3HI9lp73tM12PLDFfByKXwq6O96cyjJeBOTaQ67ZqgztUOBlwmyNdSd0JstUABRL9Qr5AbNkgErofPjZaICUvkF3Z4vJw2KJWXqBbA1a5g4mB2DRZL5HjQQTs8VZChyB6d4aqKxfxOh4lEXSFnWcbneLyhCdLk3nYcKEAYxcIaJr97d2cAq2BZxzhNEsk7g3lsoTQ5kkwx3XAASNwK6Cce410VikrnXsRpLxJY6ZUHAsNiUbWrQ2S5fedojU5y2Dcna0LCYpVd2btojsof7pDMYH84fCDzFiIe9kxw85iPGd5RJqspSweQJUE11MoSAjlwL98p03V69IBpIExzWHMxkTdiXezYI3atAdyehJMsrmvGBuIAUm93SZBctEI9NoliuzAgegXmTaAR0aYs2OwXoSX5mUpAT2ntktHi1V6oTPNQZb3QV2ATePx9LFX2Acwn9KjE30fk1r7rY3gyUKwJT7tK64n2ynGCTphZgXiawdZdlocjw1bOKfYDPQ6rC5u3pyynTXkwFcrU9HveCF1xJ6CKwr5GqgGKOtUD0qj7WONbGxmBhdIOh5doEvaemJEDXdcRafhjvaCYyNWzjyBFT18Dw8yiEYSsNzdKGKTXceIktCWXb6ATvbrAEnuPQmY9rcXWOFJUKmrxJig922r2JaUB0jufUMTeJ89nM1HyAmLETFslyKCGfsUQqxQLgLkNmNgshZybSGjIRH5dbwAIfCRPPA1BhunQlIWCmLAhu6W2P2Bjc72EgqBu4IhyLsOfTaK8TlxilhvPVDkIxoLXysuTDpgUO4pehRb9dSWKPrqc78Mtl1H5rl9Wi9wojlYr9NULc4jBqNimdd12V3fP78SlyhVWayKZewpyFi6ZcGcZnntcc7kdQFRMV2T1I3sMKghZ8mgkga8VQP4NNNIc3M7JZ1Yxxh1Nr3HhYgL0e0zRc1JIu8KnOoacmUcZbUbA78tJGzzXxzALbl9hqEf5xJWlTRdMO0W0EtUBBDy6adRJqzuFozdlCTOn8QcTHCQxDrXW07nHaKB8vWe4iBrGbzgmwN4XeVEfWT6gVmffvjzwafiM1MChlk2xcG5HU5leVpGMx6XgchQIT05HHganqgLLzSWKTu6A642S435JrmQbOiTLCc2FghTco3P0Z3FqUHQtGLkIMQymtzM0xHvQZ8Cn1OLMheozhmriHtDR3gZBUfSyZu1jbTsJZ2Z2n3XCaL4E1dmKgrj6C5LNuhnAfK0cF3iJrj02SPCm9GvBkSJEtFctmkwO3tf8eyGQXdCzyFDvbJ6yb1vkh4ngLVUVWw0tnldNlnEHBTiifrbpkoIVC48K0RckHYRjse7XfX88LFAKXrdkAaZk4pENMp7HJqnigtVkhKMs5k9kzKMN6cNn8S3BVCCbXfRKIQHo6okRJNKdacPKb7NUwHLFrT6NDuBzTbbkUV8cPZYSEd8Pj7zeoh9bz8zmWp5JuL8dlmBvZwBpvcTSVavwQbZ4vz1zA0LXcxIo6iB9gy0rDcP5OXuvsPBNim7b3Ulf98VsWpoTwaK2c947dGwp9vwAFWKvKRQAkKr2Jt19pbLpmtkez0B3B1KuSgnI7v34GlnFohuvxV44aqz5aSxSKqvaoH5DnDEUMfCmhhU7y4Gq414nvgVlUtsM0LehzProJ5XG2qj4P05KMhJY1x4KLg1A7m277J2OpmGYw8LlyfexCaohv5VBaL4woOUTfgDYttK1RJmHQzMjc0C7yTCRFb96E7cAi53KQtEHIQ8fm59uBIRyunexa0TZjt06eX6VtsklOSAvTAOHTR52OQIUlAVmMLqUxFeNpKNbCxItaVwd2LH5LJ4nSYAjC91cxqIqOFeHbPZX5AcISm9f4q3ZZ7acYOmbwpJyhqreZpdCL5wwBwTwe4w9pVgflTsBAd4IAOngjFyxEyEYJQw6flj1UKZRt2dCAVLQhgvpdAnGmQ0V7BKeuztD0XjaRR2F0WT8ymXYPyAeXmt6TX7HCZBSREoqWF4Fi4LAXKK4jFDJHRZxHInhowhCLaSQvH1jwSNGd8x24I6RHjGpU9t3TvOG74f2FgkSWIPxS84HwHGqJQRQFsND2mJelnyhPUQXJePdlw8ggpdTzS6lknBgyXuvL0alHNtr317Ntd8w7xbetXvE2RuYRJ8PbAvW6kUKOZUwI3es0dZQuBECb5Si0jmFPqKgLyam0PIcNVt32tlJYB0krX5I6oPOVvM3v7aSraEKukODhzsrKlMVZrSe5cd9kMiflpknXPIVdaKFwa2ZF49gxWn44VxvufAAJUCSbZotkkfXL1FtGTJWuGQOQ42DtzCiyeuHPfVm78oGKKdCo8xUjE68iaI8XBGAFzxFZlFifmOemLmAPIUDFJfcpZA7iM5mXCl1pZ0fYa1apm13OxI4BM1k8HirBIP3vIE21xSmJGi1oCw7RJZQpcsSqbZhgToBjNHw2VZWt22QaCaNOOeiUO1Cn8jMhz5myRRP0x4fjBokzExF9aPyeSLc26IqguS1DY1WVNq2YeokbbPMRLYL3sRlos4kVld0nMES1I9qCOq3jX9pcuJvvqxLeBKytIbsFvWqIWrLclpoXkX0kwcpSSN9jzLPsOuqGaZJ13M2FpKghll0gGTFv2d3J54Z0FKuaV8YYaiboU2mnKD0lmZsyoQwP5TjvhgwS5yyb5EroVghVazmN4bV7Vx2QXF8X5iyN1yXQyWo3Z2cbfYGlXPl7JNZTB6zZnk22RHFVPohwB1WQV9UO1w5Ba6NDF99dS2GYIL35GjqwQMJWZSI9zAmlAOHQFLltJ1QFFV1AzVtag5IXcBZh8WPi0zARWkaza0tGc4E4DRcxPNHJKe8hodNwpzepIkHhF4o2n0mrW37TNhLGzVLQiRXz5jxJUPLt6RzcjJczaFiBT30r8DH2AR8Zb0ykHX5AkibRxmOuf65UiGzg5tPC5gzvl9YR7sCoBsvehZ75W39Ft3rJYu9XBTbvRmBWbAG9C319LE4sSXIJMWdiIiqRB7pHMtqOsBxvaxqhG76c7ZHVPQWjSPUSsKPT9u0igpMImQwTlucg2SK1AUvyAb1BWayRyI74L6fBRGJnODjzFNFGTw9i09H26EqGhk8Mwl5asCfOkq2BUMJBm3THPyTyWPgon5TjShJTnRKY23kOUzQlqI6R6pfO60W4kh1NhCvIE722cjCe1FHFHFRGRAC0p4dD0qavTHetkPdw6m8jahBjM51umzUvuVG6gKXOn2EsqSnAVgo3SNOy85q6xgvc6Agufzc1cUMae3EnskPYtiur5KjOJteqJAK5bu7a7MHNa6IFt3tpr7rFGhYs9ZryzdJ82wOgqXGdetzBNt5Q8lJ3V6oCxft5tls5gFD7Phsvb2FNBfwvTwU4cf1gbJg4OBI0sLyjnt4AWGi7Li2cags0HTGiXd23RbiCrgbGV05aRxsmZ9yrspDywJzNypZjqzPUR2GJ6CBsYTSk24epESlNneSTzz8ZNj62bQbYgK9I2HMYLWTERp9ORncQcWrJFZXXHk39nJhetbtQkemISUigVO4r1e5atX7d7ymPCOiL9JKB48aXsyWbEvh1TzVGtFwnWDBF7b0T445GCLA9frQqyhqkPIPvhdtdazYTJiMnyep5WsdvNDHcZcARRj6ueDuKMh2cZg2glnZvI1EvXKxtfkwQDuNWhxWhwDfFFfHIBuRlNPwbazdcnN0ab481UXYWqb8U4DTLlXXeEbgZ83dle04xKEBLKwv7Vx4XkALEmcXPPxm9DVvLz0909PEw62sRiPJYSverLPHRrIvIZtvSdkbcQjfZUB0dLMvdYD9qpN1x01fITztzKottDn1LsM2TsjkkN9v3bhxXw1D4i1tZObpdthzghM9mQO2OK3jynSC0jkpvCK1CVoKU3czIGb2lbnVo3IIFPujLFLSAPJVtCXs6FeiFN6q4PiRsnB5lcEgME318wl3JODIcfbfI7sSgV7GgogHaL9mGPMzxZehFm3TMnu8gTWlnK7At84GisJ9cPXSoQKB00NCkE90nNNWeQIAdKm3zzYsxF1m1ov4mAW5QDOr9FhrqnvJ9XmY1zgZ2pACM6buwefUpKdBxCUV0aMD0aPcrKFJ2DbjUGbOGIyTfx1bBTPmqPnZGDqz122IaSNWZK6awMu2uzMPOyD9XGsVwgWiFiIaWPSSedM3qLqCsGg8veLeZDlXTJj0DZfBVMljpCF5Efn8b8SCcz2iiOwCcGtITl0pCJ51gT9ptbLdSvEjEgS4elbkAV6Y4o6mk7K9hKEcpUpM2N7hG2gplYpEQtJ0YZeIULN7tgJw9YkA36BiVlO2M3Bi1Si9Uyc9w1dUWDkvYCErs07VuPRwHCDklpvELO03HA5UtR7HDG2SyRk6EJOkotNC1rFaEvQgertCKJ3gyKK4lvbS04ZlzKgKkAruaFd1WcgWF2UuAozGWAStIWM4Mi3wBMiMtBV6UnHHDEQ9dy0EtSzvvIzHqvEyIozEO088CfE8MTs2P66H5yVB6oGYHBMJ07ktnoTzvRaOc7a2ezantsKDh7Bg77GpdFDsujgyllltRfah14IHYeooJiWbaSHZfLTeK4fH8QEvBCjkYwrKyHi9QZdh6OjVi8dJB3pLQKiX2W9MtvHbCG6ASy0tDVE6D8Qia0sD7sAgc3SZ7fJHAv08IgtFk7SY8OFGSwWR2TpMIq5IdagqaOCEHq8GRfS0smoM06iN5TZXuKCdv3mi8jyKr9d9kAw9HKsoVsct5BzK8htGLlEYqppqkpyNResxxqy8dogD5T8WnZpXgl9SpjQuSuMHqz5xbK6LJ16TtPY2AwEkqiye5HFKuJ06KUzMl694BdPRsGH2XbMb9cN5kLe1n7krHrYeKRiu7eIf9nwFvtL60pDnKYXGNoztB0PVo9PAprw53u1DkcGH5rvrJLMR0U51YFyv8TPrN5VmlOGOfcr4Z17uAmwXsHtWWKxOFmr8mYeUS6d3iKYrW0ABHRWxobqdZjhdN8PjQci6fWOW86karZDCK8TZxgDzqwyLj8GEZWrmmJ11oKdDPiIttqZetnoPhqgSOjpEvinPELKTWgRo0HaN4Sk6CskncSpHDTen6rKNS9kZCox5HyCLlSAjjy4CWLeF7gsg1gemkCWCr6PPXfbulcCkOgACQOjqLzILQTWxl59XqQ7QPSv5OnbJQslTSgWVzjUdJK1W5RkNnMq1kcsq4XOBEDGCHPiEmwzcO7JYHPjxZaK1zPCbdi3gsgSHpqxzr1EjR3rRrSAL82Z6p6Kd93aS1THCORpqz2YLnMurLFl2fovUeO6PhrhjKULM5ARmZjJfe01KWyRE0xLvvLmIzSmRoELQsetRH6Xcb18vAzGOeJ9IPcDAFoGb4SDDUjDSQj2hnhreybOMQoDmY5QwPscll6NCAo4Xvo5JZ0mum62f05OJXCwUfBkcC0DuZhuW1gMBUhQdGVfjWNOhOBtHqJymZvEmA0zsf6TgywDPYt55VyMHv8uTgCSXvGDqZE0BSDpVSlnTdenDdi6yvLOddVMwPGvAxM3GS9DfkOVddfGkm7mqdxvyRADr9h0lEGqFYKU0LyVolsPJEgmMrD47YV1FwJFRqIsqRL3jjMT2499ZpaCjY2wdHhqawJJ6ntlLWSSWZMUWDVqrPrdHToevWwrFb2Y6Hh3D80qeBnAKiHE48TAxf1KiQjyEYaReNrUUp8QtWV3YIAqPHTHR9tcDa9vrKPxmNjJ7wUq4haUSmuDykmNh6bRfJ3xkdBnCFDmfENYmxnFSznULzohMSuvkC4yl9ATLaahEsf7W8ZC0M5kDr7U4qHSDj1EEgUzmzFNmFJVvfWLYGsfohfakC3wKdkS7NSjkYYALRTGe047sKKCIPBjGOgMiiTgUjlqs0t21XeqIVOpuO0OCs8fWoWb1mZQ5w2kr9ZFc6pXkyUU3Taxi8kF2uvGg0uTvE750N88AzylpQS6I4lcp1lRKE4ntBa95xc2w4ZA7NeuMf7ilvkckewDILSvWd14lKFqcni5NgleG2qFN3ZJiJkEXUwBw71Z4SVqaMZ9qxPdQoPFyo4oQ7WazDoaVtQOWF1i4r5U8I3XDAMC5c4ilxZJ16imFEFD3ZKtzMcqcPcwJNJmgraxueWqFAozNCSOe3Mq7fl4UY5CZrlne1hiABhNZRydMIjOpfD1TlDAVTo6SHpoF1VSqeL6u88gRnUhRShZAOiARNNtvXbkPDOpz6iKOGNfx3ONG98Jw92LPaWb21574MT4CfqVyXvXm6OnE8AwOZBRjhv7iREu2vd06RXDnozurXCHH8UY4PaArZmXxwHkDxSZG2gndxiXucD3pCallCWjlwis6E8y7pm0KX2LOuuu2bzmkZreK0RWDbjXyNFOujJavW73QiewPE6SEkEhEEd7pYUpQ1M6m8ZvjtpvBGuICbZB2SHUakc9pRUWLEyYZbIo9MtxX8uLFGa6Ws7xNQDWZzl5mVK5tFpsNXGdGHmsHPyzBaS1eH3inrF9SpWNhn9MmPIxYgQTePuMzxYbFSi9fZzupQqg3pg35xngRuEiXcCGAAPeLzc0dUgBqvDdQU4JTZo3IYlq7Ku9hrjwQvEcp9Avv3G8H8d2f8TxIl2UZ5qlU5GiXWBaXfWDJw1l4lJp0VYPzPKlgzpH2ymLM5ho4PbTYVIzeJCDHwmWaZ9IndHvy0RNo8uVeiVfZj9KyehznkKhhUplXrWHmmvxpgScwshAmSR6INiY3meNXvRR5307m9re08wFVOT1qAtseYYQeemBqtz3oZxT6J1HxctKZ1VjHx90k2MjxCnHtyOhmKFcm2ikDMFC7cjLwHzeEqsul2pTKxPHVqz98YDB5fYhKW1DGp7WI4LHxCFCdpKgeCb62OAewEhzuVdwOVkrqpo4ztHOWJqgtZ91c1xzHhFwDs0BxrlUomZ5OP5WXmTVZiKyilTzZlSM5ZYOwLqCqkAnHCowegTHx4yxroF3fTeMIQyY4i0jhkKHboauX8nmxVfj0tP143ZCA13oK6DOaFSQaHAiUKuWKuPAng0QZsumL8TCrWJcDqK4rOVIXudjohESXTo00yqlwm1BHr5Dz10QkBPRKOkvEcYGcdsiGslVsFWG5SnRqV3DOQY0SEjUrhzusSLnXpxLRIUJbyUg6dINoRsv314IilYlCb7SWIddKgNLGr2C8EFNviIIOZlzwiMPI8je5rplPhWbqOrOydhyUwp3TxgwIXsyJAzP3TLGVyeEW5YqfEhs755yPSgphvTNzqzGwGAogSFQrcuLl0RWyHq68EtAl3eoa4yJNKX7LOOlIHzNIeDrgMSVvOeGUYhtCjBBABO5EvHVtljk8mcSv22U3RU83YZE3OltwXtkrEelQmLXdd3NHQZ7863qWSeZtoyLqJnr8SNjkiLInteOfcrO2eqtnEcViS0uNBKJJLIfaFSXlvG33TBK3kryNo6fRL4lWFjiyUD6LtAWXHy7qC51tRIealSGiadp0RNEhCvrkfpGKYekGcZbyn5mTBNVqHKsqnOXM9dxHlud6Ly4zsksG16OzrhB7NJHuc4nRkAhGyWLfsha6omKYklWBgu1rJOffadvoxuR2FvHqW6th7qON13ZUCoOpBCEbRqvR09biRbxPwpEqpE9RTrctT7ihcaF311VrgSG1hLj3DBPqaodJ6qAfM03qmozpaiYCOHJTzZU5k7RGbfEsReiRZUinS0qmU90Jgfh5etU3pFjz0UcG5V62SEtQEPpgKuqEmFbAy0fHBjlCwt74bKNnjmAnasd8WV2uM5lNZdqDDQYJKMUM83cVY1MGBFYooRuzXEAWuolj2NZb8Kky2hDtnitt91Hlm0Q9sgf7sJkHNs1OIt4QMR9casnkIXXA4IiUnQYbzLHtBGIRDSQKLNay2sBTftNqdKpJ2akuEWD7BVLm3HyAixL40zoDf4OP3mdHJrm😃'); +INSERT INTO VARCHAR_dt values (NULL, NULL); +prepst#!#INSERT INTO VARCHAR_dt values(@a, @b)#!#varchar|-|a|-|hello#!#nvarchar|-|b|-|hello😃 + +#checking with string of length > 65535 via prep-exec +prepst#!#exec#!#varchar|-|a|-|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#!#nvarchar|-|b|-|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😃 +prepst#!#exec#!#varchar|-|a|-|#!#nvarchar|-|b|-| +select * from VARCHAR_dt +drop table VARCHAR_dt; + +create table VARCHAR_dt (a varchar(max), b int, c int, d int, e int ,f int, g int, h int, i int); +insert into VARCHAR_dt (a,b,c,d,e,f,g,h,i) values (NULL,1,2,3,4,5,6,7,8); +select * from VARCHAR_dt; +drop table VARCHAR_dt; + +create table VARCHAR_dt (a varchar(10), b int, c int, d int, e int ,f int, g int, h int, i int); +insert into VARCHAR_dt (a,b,c,d,e,f,g,h,i) values (NULL,1,2,3,4,5,6,7,8); +select * from VARCHAR_dt; +drop table VARCHAR_dt; diff --git a/contrib/test/python/input/datatypes/TestXML.txt b/contrib/test/python/input/datatypes/TestXML.txt new file mode 100644 index 00000000000..11b9ac8e138 --- /dev/null +++ b/contrib/test/python/input/datatypes/TestXML.txt @@ -0,0 +1,11 @@ +CREATE TABLE XML_dt (a XML) +#prepst#!# INSERT INTO XML_dt values(@a) #!#XML|-|a|-| +#prepst#!# INSERT INTO XML_dt values(@a) #!#XML|-|a|-|Contact Name 2YYY-YYY-YYYY +#prepst#!#exec#!#XML|-|a|-| +SELECT * FROM XML_dt; +INSERT INTO XML_dt values('Contact Name 2YYY-YYY-YYYY') +INSERT INTO XML_dt values(NULL) +#INSERT INTO XML_dt values('') +INSERT INTO XML_dt values(Contact Name 2YYY-YYY-YYYY) +SELECT * FROM XML_dt; +DROP TABLE XML_dt; \ No newline at end of file diff --git a/contrib/test/python/input/pg_stat_activity.txt b/contrib/test/python/input/pg_stat_activity.txt new file mode 100644 index 00000000000..c18508ed9e0 --- /dev/null +++ b/contrib/test/python/input/pg_stat_activity.txt @@ -0,0 +1,20 @@ +SELECT sys.babelfish_set_role(session_user); + +# Babel-1294 Support application_name in pg_stat_activity +select count(*) from pg_stat_activity where pid = pg_backend_pid() and lower(application_name) like 'python%'; + +# BABEL-1326: Support query in pg_stat_activity +select query from pg_stat_activity where pid = pg_backend_pid(); + +# BABEL-1326: Checking if the right query is returned for Prepexec with batch too +prepst#!#select query from pg_stat_activity where pid = pg_backend_pid();select @a as a#!#int|-|a|-|1 +prepst#!#exec#!#int|-|a|-|1 + +# BABEL-1326: Checking if the right query is returned from a procedure and a nested procedure as well +Create procedure proc_pg_stat_activity as begin select query from pg_stat_activity where pid = pg_backend_pid(); end; +exec proc_pg_stat_activity; +Create procedure proc1_pg_stat_activity as begin exec proc_pg_stat_activity end; +exec proc1_pg_stat_activity; + +drop procedure proc_pg_stat_activity; +drop procedure proc1_pg_stat_activity; \ No newline at end of file diff --git a/contrib/test/python/input/sqlBatch/TestSQLQueries.txt b/contrib/test/python/input/sqlBatch/TestSQLQueries.txt new file mode 100644 index 00000000000..247b5f43f90 --- /dev/null +++ b/contrib/test/python/input/sqlBatch/TestSQLQueries.txt @@ -0,0 +1,232 @@ +#1 CREATE TABLE with primary and unique keyword +CREATE TABLE tmp(a int PRIMARY KEY, b int UNIQUE); +INSERT INTO tmp(a,b) values(1,1); +INSERT INTO tmp(a,b) values(2,2); +SELECT * FROM tmp; +DROP TABLE tmp; + +#2 2 table with foreign key relation +#CREATE TABLE tmp1(b int PRIMARY KEY); +#CREATE TABLE tmp2(a int PRIMARY KEY, b int FOREIGN KEY REFERENCES tmp1(b)); +#INSERT INTO tmp1(b) VALUES (1); +#INSERT INTO tmp2(a,b) values(1,1); +#SELECT * FROM tmp1; +#SELECT * FROM tmp2; +#DROP TABLE tmp2; +#DROP TABLE tmp1; + +#3 Repeated #2 with CONSTRAINT keyword +#CREATE TABLE tmp1(b int PRIMARY KEY); +#CREATE TABLE tmp2(a int, b int, PRIMARY KEY(a), CONSTRAINT FK_tmp FOREIGN KEY (b) REFERENCES tmp1(b)); +#INSERT INTO tmp1(b) VALUES (1); +#INSERT INTO tmp2(a,b) values(1,1); +#SELECT * FROM tmp1; +#SELECT * FROM tmp2; +#DROP TABLE tmp2; +#DROP TABLE tmp1; + +#4 CREATE TABLE with NOT NULL column +CREATE TABLE tmp(a int PRIMARY KEY,b int NOT NULL); +INSERT INTO tmp(a,b) values(1,1); +INSERT INTO tmp(a,b) values(2,1); +#INSERT INTO tmp(a,b) values(2,NULL); +SELECT * FROM tmp; +DROP TABLE tmp; + +#5 INSERTION and DELETION +CREATE TABLE tmp(a int PRIMARY KEY); +INSERT INTO tmp(a) VALUES(1); +INSERT INTO tmp(a) VALUES(2); +INSERT INTO tmp(a) VALUES(3); +INSERT INTO tmp(a) VALUES(4); +INSERT INTO tmp(a) VALUES(5); +SELECT * FROM tmp; +DELETE FROM tmp WHERE a>2; +SELECT * FROM tmp; +DROP TABLE tmp; + +#6 IS NOT NULL condition in WHERE clause +CREATE TABLE tmp(a int PRIMARY KEY,b int); +INSERT INTO tmp(a,b) values(1,1); +INSERT INTO tmp(a,b) values(2,1); +INSERT INTO tmp(a,b) values(3,NULL); +INSERT INTO tmp(a,b) values(4,NULL); +SELECT * FROM tmp WHERE b IS NOT NULL; +DROP TABLE tmp; + +#7 Add new column using ALTER TABLE +CREATE TABLE tmp(a int PRIMARY KEY); +INSERT INTO tmp(a) VALUES(1); +INSERT INTO tmp(a) VALUES(2); +SELECT * FROM tmp; +ALTER TABLE tmp ADD b VARCHAR(20) NULL; +SELECT * FROM tmp; +INSERT INTO tmp(a,b) VALUES(4,'Dipesh'); +INSERT INTO tmp(a,b) VALUES(5,' Dipesh'); +SELECT * FROM tmp; +DROP TABLE tmp; + +#8 Repeated #8 with default value for newly added col +CREATE TABLE tmp(a int PRIMARY KEY); +INSERT INTO tmp(a) VALUES(1); +INSERT INTO tmp(a) VALUES(2); +SELECT * FROM tmp; +ALTER TABLE tmp ADD b VARCHAR(20) DEFAULT 'Dipesj'; +SELECT * FROM tmp; +INSERT INTO tmp(a,b) VALUES(4,'Dipesh'); +INSERT INTO tmp(a,b) VALUES(5,' Dipesh'); +SELECT * FROM tmp; +DROP TABLE tmp; + +#9 Change datatype of existing column using ALTER TABLE +CREATE TABLE tmp(a int PRIMARY KEY,b int); +INSERT INTO tmp(a,b) VALUES(1,1); +INSERT INTO tmp(a,b) VALUES(2,2); +SELECT * FROM tmp; +ALTER TABLE tmp ALTER COLUMN b VARCHAR(10); +SELECT * FROM tmp; +INSERT INTO tmp(a,b) VALUES(4,'Dipesh'); +INSERT INTO tmp(a,b) VALUES(5,' Dipesh'); +SELECT * FROM tmp; +DROP TABLE tmp; + +#10 UPDATE TABLE with fancy condition +CREATE TABLE tmp(a int PRIMARY KEY,b int); +INSERT INTO tmp(a,b) VALUES(1,1); +INSERT INTO tmp(a,b) VALUES(2,2); +INSERT INTO tmp(a,b) VALUES(3,3); +INSERT INTO tmp(a,b) VALUES(4,4); +INSERT INTO tmp(a,b) VALUES(5,5); +SELECT * FROM tmp; +UPDATE tmp SET b=b+1 WHERE b>2; +SELECT * FROM tmp; +DROP TABLE tmp; + +#11 DROP some column using ALTER TABLE +CREATE TABLE tmp(a int PRIMARY KEY,b int); +INSERT INTO tmp(a,b) VALUES(1,1); +INSERT INTO tmp(a,b) VALUES(2,2); +INSERT INTO tmp(a,b) VALUES(3,3); +INSERT INTO tmp(a,b) VALUES(4,4); +INSERT INTO tmp(a,b) VALUES(5,5); +SELECT * FROM tmp; +#ALTER TABLE tmp DROP COLUMN b; +#INSERT INTO tmp(a) values (6); +#SELECT * FROM tmp; +DROP TABLE tmp; + +#12 CREATE TABLE with fancy constraint +CREATE TABLE tmp(a int PRIMARY KEY CHECK (a>10),b int); +INSERT INTO tmp(a,b) VALUES(11,1); +INSERT INTO tmp(a,b) VALUES(12,2); +INSERT INTO tmp(a,b) VALUES(13,3); +INSERT INTO tmp(a,b) VALUES(14,4); +INSERT INTO tmp(a,b) VALUES(15,5); +SELECT * FROM tmp; +DROP TABLE tmp; + +#CREATE PROCEDURE tmp AS +#BEGIN +# CREATE TABLE dip(a int PRIMARY KEY CHECK (a>10),b int); +# INSERT INTO dip(a,b) VALUES(11,1); +# INSERT INTO dip(a,b) VALUES(12,2); +# INSERT INTO dip(a,b) VALUES(13,3); +# INSERT INTO dip(a,b) VALUES(14,4); +# INSERT INTO dip(a,b) VALUES(15,5); +# SELECT * FROM dip; +# DROP TABLE dip; +#END; + +#13 invoke simple stored procedure using EXECUTE +EXECUTE tmp; + +#14 invoke simple stored procedure using EXEC +EXEC tmp; + +#DROP PROCEDURE tmp; + +#15 UPDATE rows in existing table +CREATE TABLE tmp(a int PRIMARY KEY,b int); +INSERT INTO tmp(a,b) VALUES(1,1),(2,2),(3,3),(4,4),(5,5); +SELECT * FROM tmp; +UPDATE tmp SET b=b*2+1 WHERE (a>2); +SELECT * FROM tmp; +DROP TABLE tmp; + +#16 TRUNCATE table +CREATE TABLE tmp(a int PRIMARY KEY,b int); +INSERT INTO tmp(a,b) VALUES(1,1),(2,2),(3,3),(4,4),(5,5); +SELECT * FROM tmp; +TRUNCATE TABLE tmp; +SELECT * FROM tmp; +DROP TABLE tmp; + +CREATE TABLE temp1 (i INT,j INT,t TEXT); + +CREATE TABLE temp2 ( i INT,k INT); + +INSERT INTO temp1 VALUES (1, 4, 'one'); +INSERT INTO temp1 VALUES (2, 3, 'two'); +INSERT INTO temp1 VALUES (3, 2, 'three'); +INSERT INTO temp1 VALUES (4, 1, 'four'); +INSERT INTO temp1 VALUES (5, 0, 'five'); +INSERT INTO temp1 VALUES (6, 6, 'six'); +INSERT INTO temp1 VALUES (7, 7, 'seven'); +INSERT INTO temp1 VALUES (8, 8, 'eight'); +INSERT INTO temp1 VALUES (0, NULL, 'zero'); +INSERT INTO temp1 VALUES (NULL, NULL, NULL); +INSERT INTO temp1 VALUES (NULL, 0, 'zero'); + +INSERT INTO temp2 VALUES (1, -1); +INSERT INTO temp2 VALUES (2, 2); +INSERT INTO temp2 VALUES (3, -3); +INSERT INTO temp2 VALUES (2, 4); +INSERT INTO temp2 VALUES (5, -5); +INSERT INTO temp2 VALUES (5, -5); +INSERT INTO temp2 VALUES (0, NULL); +INSERT INTO temp2 VALUES (NULL, NULL); +INSERT INTO temp2 VALUES (NULL, 0); + +#17 CROSS JOIN +SELECT * FROM temp1 CROSS JOIN temp2; + +#18 INNER JOIN +SELECT temp1.i, temp1.j, temp1.t, temp2.k FROM temp1 INNER JOIN temp2 ON temp1.i=temp2.i; +SELECT temp1.i, temp1.j, temp1.t, temp2.k FROM temp1 JOIN temp2 ON temp1.i=temp2.i; + +#19 LEFT JOIN +SELECT * FROM temp1 LEFT OUTER JOIN temp2 ON temp1.i=temp2.k; + +#20 RIGHT JOIN +SELECT * FROM temp1 RIGHT OUTER JOIN temp2 ON temp1.i=temp2.i; + +#21 FULL OUTER JOIN +SELECT * FROM temp1,temp2; + +DROP TABLE temp1; +DROP TABLE temp2; + +#22 dropping all columns +CREATE TABLE tmp(a int PRIMARY KEY,b int); +INSERT INTO tmp(a,b) VALUES(1,1); +INSERT INTO tmp(a,b) VALUES(2,2); +INSERT INTO tmp(a,b) VALUES(3,3); +INSERT INTO tmp(a,b) VALUES(4,4); +INSERT INTO tmp(a,b) VALUES(5,5); +SELECT * FROM tmp; +#ALTER TABLE tmp DROP COLUMN b; +#ALTER TABLE tmp DROP COLUMN a; +#SELECT * FROM tmp; +DROP TABLE tmp; + +#23 +CREATE TABLE DATE_dt (a DATE); +INSERT INTO DATE_dt(a) values('2000-12-13'); +INSERT INTO DATE_dt(a) values('1900-02-28'); +INSERT INTO DATE_dt(a) values('0001-01-01'); +INSERT INTO DATE_dt(a) values('9999-12-31'); +INSERT INTO DATE_dt(a) values(NULL); +SELECT * FROM DATE_dt; +ALTER TABLE DATE_dt ALTER COLUMN a DATETIME; +SELECT * FROM DATE_dt; +DROP TABLE DATE_dt; diff --git a/contrib/test/python/input/storedProcedures/BABEL-1365.sql b/contrib/test/python/input/storedProcedures/BABEL-1365.sql new file mode 100644 index 00000000000..832608d3f4a --- /dev/null +++ b/contrib/test/python/input/storedProcedures/BABEL-1365.sql @@ -0,0 +1,23 @@ +-- Test normal case: @v = SP_EXECUTESQL 'SQL' +DECLARE @SQLString NVARCHAR(100); +DECLARE @P0 int; +set @SQLString = N'SELECT 123;' +EXEC @P0 = sp_executesql @SQLString; +SELECT @P0; +go + +-- Test case: @v = SP_EXECUTESQL 'SQL' where @v is implicitly casted to varchar +DECLARE @SQLString NVARCHAR(100); +DECLARE @P0 varchar(3); +set @SQLString = N'SELECT 321;' +EXEC @P0 = sp_executesql @SQLString; +SELECT @P0; +go + +-- Test case: @v = SP_EXECUTESQL 'SQL' where 'SQL' statement does not return result set +DECLARE @SQLString NVARCHAR(100); +DECLARE @P0 int; +set @SQLString = N'CREATE TABLE t(a INT); DROP TABLE t;'; +EXEC @P0 = sp_executesql @SQLString; +SELECT @P0; +go \ No newline at end of file diff --git a/contrib/test/python/input/storedProcedures/TestSPExecutesql.sql b/contrib/test/python/input/storedProcedures/TestSPExecutesql.sql new file mode 100644 index 00000000000..fb71ce869a4 --- /dev/null +++ b/contrib/test/python/input/storedProcedures/TestSPExecutesql.sql @@ -0,0 +1,194 @@ +CREATE TABLE spExecutesqlTable1 (a INT, b VARCHAR(10)); +CREATE TABLE spExecutesqlTable2 (a INT, b INT, c INT, d INT); +go + +/* 1. Execute a string of statement */ +DECLARE @SQLString NVARCHAR(100); +SET @SQLString = N'SELECT N''hello world'';'; +EXEC sp_executesql @SQLString; +go + +/* 2. Execute a statement string with parameters */ +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'INSERT INTO spExecutesqlTable1 VALUES (@a, @b);'; +SET @ParamDef = N'@a INT, @b VARCHAR(10)'; + +DECLARE @p INT = 1; +EXEC sp_executesql @SQLString, @ParamDef, @p, @b = N'hello'; +SELECT * FROM spExecutesqlTable1; +go + +TRUNCATE TABLE spExecutesqlTable1; +go + +/* 3. Execute a statement string with both unnamed params and named params */ +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'INSERT INTO spExecutesqlTable2 VALUES (@a, @b, @c, @d);'; +SET @ParamDef = N'@a INT, @b INT, @c INT, @d INT'; + +EXEC sp_executesql @SQLString, @ParamDef, 1, 2, @d = 4, @c = 3; +SELECT * FROM spExecutesqlTable2; +go + +TRUNCATE TABLE spExecutesqlTable2; +go + +/* 4. Nested sp_executesql */ +DECLARE @SQLString1 NVARCHAR(100); +DECLARE @SQLString2 NVARCHAR(max); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString1 = N'INSERT INTO spExecutesqlTable1 VALUES (@a, @b);' +SET @SQLString2 = @SQLString1 + N'EXEC sp_executesql N''INSERT INTO spExecutesqlTable1 VALUES (@c + @c, @d + @d);'', N''@c INT, @d VARCHAR(10)'', @a, @b;' +SET @ParamDef = N'@a INT, @b VARCHAR(10)'; +EXEC sp_executesql @SQLString2, @ParamDef, @a = 10, @b = N'str'; +SELECT * FROM spExecutesqlTable1; +go + +TRUNCATE TABLE spExecutesqlTable1; +go + +-- Nested with param name collision +DECLARE @SQLString1 NVARCHAR(100); +DECLARE @SQLString2 NVARCHAR(max); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString1 = N'INSERT INTO spExecutesqlTable1 VALUES (@a, @b);' +SET @SQLString2 = @SQLString1 + N'EXEC sp_executesql N''INSERT INTO spExecutesqlTable1 VALUES (@a + @a, @b + @b);'', N''@a INT, @b VARCHAR(10)'', @a, @b;' +SET @ParamDef = N'@a INT, @b VARCHAR(10)'; +EXEC sp_executesql @SQLString2, @ParamDef, @a = 11, @b = N'rts'; +SELECT * FROM spExecutesqlTable1; +go + +TRUNCATE TABLE spExecutesqlTable1; +go + +/* 5. Execute a statement string with OUT/INOUT param */ +DECLARE @SQLString1 NVARCHAR(100); +DECLARE @SQLString2 NVARCHAR(max); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString1 = N'SET @a = @b + @b'; +SET @SQLString2 = N'EXEC sp_executesql N''SET @a = @b + @b'', N''@a INT OUT, @b INT'', @a OUT, @b;'; +SET @ParamDef = N'@a INT OUTPUT, @b INT'; + +DECLARE @p INT; +DECLARE @a INT; +-- OUT param +EXEC sp_executesql @SQLString1, @ParamDef, @a = @p OUT, @b = 10; +-- Nested with OUT param name collision +EXEC sp_executesql @SQLString2, @ParamDef, @a = @a OUT, @b = 11; +SELECT @p, @a; +go + +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'SET @a = @a + 1;'; +SET @ParamDef = N'@a INT OUT'; + +DECLARE @p1 INT = 1; +DECLARE @p2 INT = 1; +-- Declared as INOUT and called as OUT +EXEC sp_executesql @SQLString, @ParamDef, @a = @p1 OUT; +-- Declared as INOUT and called as IN +EXEC sp_executesql @SQLString, @ParamDef, @a = @p2; +SELECT @p1, @p2; +go + +/* 6. Implicit cast for IN param */ +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'SET @b = @a;'; +SET @ParamDef = N'@a FLOAT, @b FLOAT OUT'; + +DECLARE @p FLOAT; +DECLARE @a MONEY = 3.14; +EXEC sp_executesql @SQLString, @ParamDef, @a = @a, @b = @p OUTPUT; +SELECT @p; +go + +/* 7. Implicit cast for OUT param */ +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'SET @a = CAST(''2020-01-01'' AS DATE); SET @b = @a;'; +SET @ParamDef = N'@a DATE OUT, @b DATETIME OUT'; + +DECLARE @p1 DATETIME; +DECLARE @p2 DATETIME; +EXEC sp_executesql @SQLString, @ParamDef, @a = @p1 OUT, @b = @p2 OUT; +SELECT @p1, @p2; +go + +/* Exceptions */ +/* 1. Wrong order of named/unnamed params */ +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'INSERT INTO spExecutesqlTable2 VALUES (@a, @b, @c, @d);'; +SET @ParamDef = N'@a INT, @b INT, @c INT, @d INT'; +EXEC sp_executesql @SQLString, @ParamDef, @b = 2, @c = 3, 1, @d = 4; +go + +/* 2. Number mismatch of param defs and given params */ +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'INSERT INTO spExecutesqlTable2 VALUES (@a, @b, @c, @d);'; +SET @ParamDef = N'@a INT, @b INT, @c INT, @d INT'; +EXEC sp_executesql @SQLString, @ParamDef, 1, 2, 3; +go + +/* 3. Invalid param name */ +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'INSERT INTO spExecutesqlTable2 VALUES (@a, @b, @c, @d);'; +SET @ParamDef = N'@a INT, @b INT, @c INT, @d INT'; +EXEC sp_executesql @SQLString, @ParamDef, @a = 1, @b = 2, @c = 3, @e = 4; +go + +/* 4. Invalid param def */ +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'INSERT INTO spExecutesqlTable2 VALUES (@a, @b, @c, @d);'; +SET @ParamDef = N'@a INT, @b INT, @c, @d INT'; +EXEC sp_executesql @SQLString, @ParamDef, 1, 2, 3, 4; +go + +/* 5. Unsupported implicit cast */ +-- IN param +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'INSERT INTO spExecutesqlTable2 VALUES (@a, @b, @c, @d);'; +SET @ParamDef = N'@a INT, @b INT, @c INT, @d INT'; +EXEC sp_executesql @SQLString, @ParamDef, 1, 3.14, 'hello', 4; +go + +-- OUT param +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'SET @a = CAST(''abc'' AS VARCHAR(3));'; +SET @ParamDef = N'@a FLOAT OUT'; + +DECLARE @p FLOAT; +EXEC sp_executesql @SQLString, @ParamDef, @a = @p OUT; +go + +/* 6. Invalid OUT param */ +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'SET @a = 20'; +SET @ParamDef = N'@a INT OUT'; +EXEC sp_executesql @SQLString, @ParamDef, @a = 10 OUT; +go + +/* 7. Param declared as IN but called as OUT */ +DECLARE @SQLString NVARCHAR(100); +DECLARE @ParamDef NVARCHAR(100); +SET @SQLString = N'SET @a = 20'; +SET @ParamDef = N'@a INT'; + +DECLARE @p INT; +EXEC sp_executesql @SQLString, @ParamDef, @a = @p OUT; +go + +/* Clean up */ +DROP TABLE spExecutesqlTable1; +DROP TABLE spExecutesqlTable2; +go diff --git a/contrib/test/python/input/storedProcedures/TestSPPrepare.sql b/contrib/test/python/input/storedProcedures/TestSPPrepare.sql new file mode 100644 index 00000000000..8288bc96cab --- /dev/null +++ b/contrib/test/python/input/storedProcedures/TestSPPrepare.sql @@ -0,0 +1,357 @@ +--- Simple SP_PREPARE +DECLARE @handle int; +EXEC SP_PREPARE @handle, NULL, 'SELECT ''OK''' +EXEC SP_EXECUTE @handle +EXEC SP_EXECUTE @handle +EXEC SP_EXECUTE @handle +EXEC SP_UNPREPARE @handle +GO + +--- Simple SP_PREPEXEC +DECLARE @handle int; +EXEC SP_PREPEXEC @handle OUT, NULL, 'SELECT ''OK''' +EXEC SP_EXECUTE @handle +EXEC SP_EXECUTE @handle +EXEC SP_EXECUTE @handle +EXEC SP_UNPREPARE @handle +GO + +--- Basic SP_PREPARE with args +DECLARE @handle int; +EXEC SP_PREPARE @handle out, N'@a int, @b int', N'select @a, @b', 10; +EXEC SP_EXECUTE @handle, 1, 2 +EXEC SP_EXECUTE @handle, 1, 2 +EXEC SP_EXECUTE @handle, 1, 2 +EXEC SP_UNPREPARE @handle; +GO + +--- Basic SP_PREPARE with args +DECLARE @handle int; +EXEC SP_PREPEXEC @handle out, N'@a int, @b int', N'select @a, @b', 1, 2; +EXEC SP_EXECUTE @handle, 1, 2 +EXEC SP_EXECUTE @handle, 1, 2 +EXEC SP_EXECUTE @handle, 1, 2 +EXEC SP_UNPREPARE @handle; +GO + +--- SP_PREPARE Batch Support +DECLARE @handle int; +DECLARE @batch nvarchar(500); +DECLARE @paramdef nvarchar(500); +DECLARE @var int; +SET @batch = 'IF (@cond > 0) SELECT @o = @a ELSE SELECT @o = @b' +SET @paramdef = '@cond int, @a int, @b int, @o int OUTPUT' +EXEC SP_PREPARE @handle, @paramdef, @batch +EXEC SP_EXECUTE @handle, -1, 10, 20, @var OUTPUT +SELECT @var +EXEC SP_EXECUTE @handle, 1, 10, 20, @var OUTPUT +SELECT @var +EXEC SP_UNPREPARE @handle; +GO + +--- SP_PREPEXEC Batch Support +DECLARE @handle int; +DECLARE @batch nvarchar(500); +DECLARE @paramdef nvarchar(500); +DECLARE @var int; +SET @batch = 'IF (@cond > 0) SELECT @o = @a ELSE SELECT @o = @b' +SET @paramdef = '@cond int, @a int, @b int, @o int OUTPUT' +EXEC SP_PREPEXEC @handle out, @paramdef, @batch, 1, 30, 40, @var OUTPUT +SELECT @var +EXEC SP_EXECUTE @handle, -1, 10, 20, @var OUTPUT +SELECT @var +EXEC SP_EXECUTE @handle, 1, 10, 20, @var OUTPUT +SELECT @var +EXEC SP_UNPREPARE @handle; +GO + +--- Parsing specific +DECLARE @handle int; +EXEC SP_PREPEXEC @handle + 1 OUTPUT, NULL, 'SELECT 1' +GO + +DECLARE @handle VARCHAR(20) +EXEC SP_PREPEXEC @handle OUTPUT, NULL, 'SELECT 1' +GO + +DECLARE @handle int; +EXEC SP_PREPEXEC @handle, NULL, 'SELECT 1' +GO + +--- Corner case 1: empty batch +DECLARE @handle int; +EXEC SP_PREPARE @handle out, NULL, NULL +EXEC SP_EXECUTE @handle +EXEC SP_UNPREPARE @handle +GO + +DECLARE @handle int; +EXEC SP_PREPEXEC @handle out, NULL, NULL +EXEC SP_EXECUTE @handle +EXEC SP_UNPREPARE @handle +GO + +--- Corner case 2: nested prepare +DECLARE @handle int; +DECLARE @inner_handle int; +DECLARE @batch VARCHAR(500); +SET @batch = 'EXEC SP_PREPARE @inner_handle OUT, NULL, ''SELECT 1'' ' +EXEC SP_PREPARE @handle out, '@inner_handle int OUT', @batch +EXEC SP_EXECUTE @handle, @inner_handle OUT +EXEC SP_EXECUTE @inner_handle +EXEC SP_UNPREPARE @inner_handle -- unprepare inner first +EXEC SP_UNPREPARE @handle +GO + +DECLARE @handle int; +DECLARE @inner_handle int; +DECLARE @batch VARCHAR(500); +SET @batch = 'EXEC SP_PREPARE @inner_handle OUT, NULL, ''SELECT 1'' ' +EXEC SP_PREPARE @handle out, '@inner_handle int OUT', @batch +EXEC SP_EXECUTE @handle, @inner_handle OUT +EXEC SP_EXECUTE @inner_handle +EXEC SP_UNPREPARE @handle --unprepare outer first +EXEC SP_EXECUTE @inner_handle +EXEC SP_UNPREPARE @inner_handle +GO + +--- Corner case 3: mismatch paramdef and params +DECLARE @handle int; +DECLARE @var int; +DECLARE @batch VARCHAR(500); +DECLARE @paramdef VARCHAR(500); +SET @batch = 'SELECT @a'; +SET @paramdef = '@a int'; +EXEC SP_PREPARE @handle OUT, @paramdef, @batch +EXEC SP_EXECUTE @handle, 100 +EXEC SP_EXECUTE @handle, @var OUT +EXEC SP_UNPREPARE @handle +GO + +--- Prepare DML statement +CREATE TABLE t1 (a int, b int); +GO + +DECLARE @handle int; +DECLARE @batch VARCHAR(500); +DECLARE @paramdef VARCHAR(500); +SET @batch = ' +INSERT INTO t1 VALUES (@v1, @v2) +INSERT INTO t1 VALUES (@v3, @v4) +' +SET @paramdef = '@v1 int, @v2 int, @v3 int, @v4 int' +EXEC SP_PREPARE @handle OUT, @paramdef, @batch +EXEC SP_EXECUTE @handle, 1, 2, 2, 3 +EXEC SP_EXECUTE @handle, 3, 4, 4, 5 +SELECT * FROM t1 ORDER BY 1, 2; +GO + +DECLARE @handle int; +DECLARE @batch VARCHAR(500); +DECLARE @paramdef VARCHAR(500); +SET @batch = ' +UPDATE t1 SET a = a * 10, b = b *10 where a = @var1; +UPDATE t1 SET a = a * 10, b = b *10 where a = @var2; +' +SET @paramdef = '@var1 int, @var2 int' +EXEC SP_PREPARE @handle OUT, @paramdef, @batch +EXEC SP_EXECUTE @handle, 1, 2 +EXEC SP_EXECUTE @handle, 3, 4 +SELECT * FROM t1 ORDER BY 1, 2; + +EXEC SP_UNPREPARE @handle +DROP TABLE t1; +GO + +--- Transaction with SP_EXECUTE +CREATE TABLE t1 (a int, b int); +GO + +DECLARE @handle int; +DECLARE @batch VARCHAR(500); +DECLARE @paramdef VARCHAR(500); +SET @batch = ' +INSERT INTO t1 VALUES (@v1, @v2); +INSERT INTO t1 VALUES (@v3, @v4); +' +SET @paramdef = '@v1 int, @v2 int, @v3 int, @v4 int' + +EXEC SP_PREPARE @handle OUT, @paramdef, @batch + +BEGIN TRANSACTION; +EXEC SP_EXECUTE @handle, 1, 2, 2, 3 +SELECT * FROM t1 ORDER BY 1, 2; +COMMIT; +SELECT * FROM t1 ORDER BY 1, 2; + +BEGIN TRANSACTION; +EXEC SP_EXECUTE @handle, 3, 4, 4, 5 +SELECT * FROM t1 ORDER BY 1, 2; +ROLLBACK; +SELECT * FROM t1 ORDER BY 1, 2; + +EXEC SP_UNPREPARE @handle +GO + +DROP TABLE t1; +GO + +--- PREPARE Batch with Transaction +CREATE TABLE t1 (a int, b int); +GO + +DECLARE @handle int; +DECLARE @batch VARCHAR(500); +DECLARE @paramdef VARCHAR(500); +SET @batch = ' +BEGIN TRANSACTION +INSERT INTO t1 VALUES (@v1, @v2); +INSERT INTO t1 VALUES (@v3, @v4); +SELECT * FROM t1 ORDER BY 1, 2; +IF (@v1 = 10) + COMMIT; +ELSE + ROLLBACK; +' +SET @paramdef = '@v1 int, @v2 int, @v3 int, @v4 int' +EXEC SP_PREPARE @handle OUT, @paramdef, @batch +EXEC SP_EXECUTE @handle, 10, 20, 30, 40 +SELECT * FROM t1 ORDER BY 1, 2; +EXEC SP_EXECUTE @handle, 50, 60, 70, 80 +SELECT * FROM t1 ORDER BY 1, 2; + +EXEC SP_UNPREPARE @handle +GO + +DROP TABLE t1; +GO + +-- Test Save Point +CREATE TABLE t1 ( a int, b int); +GO + +DECLARE @handle int; +DECLARE @batch VARCHAR(500); +SET @batch = ' +DECLARE @handle int; +BEGIN TRANSACTION; +INSERT INTO t1 VALUES (1, 2); +SAVE TRANSACTION my_savept; +EXEC SP_PREPEXEC @handle OUT, NULL, +''INSERT INTO t1 VALUES (3, 4); + SELECT * FROM t1 ORDER BY 1, 2; + ROLLBACK TRANSACTION my_savept; + SELECT * FROM t1 ORDER BY 1, 2; +''; +SELECT * FROM t1 ORDER BY 1, 2; +ROLLBACK; +SELECT * FROM t1 ORDER BY 1, 2; +EXEC SP_UNPREPARE @handle; +' +EXEC SP_PREPARE @handle OUT, NULL, @batch; +PRINT @handle +EXEC SP_EXECUTE @handle; +EXEC SP_UNPREPARE @handle; +GO + +DROP TABLE t1; +GO + +--- Test string type +CREATE TABLE t1 ( a VARCHAR(10), b VARCHAR(10)); +GO + +DECLARE @handle int; +EXEC SP_PREPEXEC @handle OUT, '@v1 VARCHAR(10), @v2 VARCHAR(10)', 'INSERT INTO t1 VALUES (@v1,@v2)', 'abc', 'efg' +EXEC SP_EXECUTE @handle, 'lmn', 'opq' +EXEC SP_UNPREPARE @handle +SELECT * FROM t1 ORDER BY 1, 2; +GO + +DROP TABLE t1; +GO + +-- Test transaction begins outside the batch and commited/rollbacked inside the batch +CREATE TABLE t1 (a INT); +GO + +BEGIN TRAN; +GO +DECLARE @handle INT; +DECLARE @batch VARCHAR(500); +SET @batch = 'insert into t1 values(1); commit; begin tran;' +EXEC sp_prepare @handle OUT, NULL, @batch +EXEC sp_execute @handle +EXEC sp_execute @handle +EXEC SP_UNPREPARE @handle; +COMMIT; +SELECT COUNT(*) FROM t1; +GO + +BEGIN TRAN; +GO +DECLARE @handle INT; +DECLARE @batch VARCHAR(500); +SET @batch = 'insert into t1 values(1); rollback tran; begin tran;' +EXEC sp_prepare @handle OUT, NULL, @batch +EXEC sp_execute @handle +EXEC sp_execute @handle +EXEC SP_UNPREPARE @handle; +COMMIT; +SELECT COUNT(*) FROM t1; +GO + +DROP TABLE t1; +GO + +-- prepare time error 1 +DECLARE @handle int; +EXEC SP_PREPARE @handle OUT, NULL, 'SELECT * FROM t1' +SELECT @handle IS NOT NULL as 'Prepared' +GO + +-- prepare time error 1-2 +DECLARE @handle int; +EXEC SP_PREPARE @handle OUT, NULL, 'DECLARE @var int; SELECT * FROM t1 WHERE c = @var' +SELECT @handle IS NOT NULL as 'Prepared' +GO + +-- prepare time error 2 +DECLARE @handle int; +EXEC SP_PREPARE @handle OUT, NULL, 'EXEC my_proc' +SELECT @handle IS NOT NULL as 'Prepared' +GO + +-- prepare time error 2-2 +DECLARE @handle int; +EXEC SP_PREPARE @handle OUT, NULL, 'DECLARE @var int; EXEC my_proc @var' +SELECT @handle IS NOT NULL as 'Prepared' +GO + +-- runtime error 1 +DECLARE @handle int; +EXEC SP_PREPARE @handle OUT, NULL, 'SELECT * FROM t1; SELECT * FROM t1;' +SELECT @handle IS NOT NULL as 'Prepared' +EXEC SP_EXECUTE @handle +GO + +-- runtime error 2 +DECLARE @handle int; +EXEC SP_PREPARE @handle OUT, NULL, 'EXEC my_proc; EXEC my_proc;' +SELECT @handle IS NOT NULL as 'Prepared' +EXEC SP_EXECUTE @handle +GO + +-- runtime error 3 +DECLARE @handle int; +EXEC SP_PREPARE @handle OUT, NULL, 'IF (1=1) SELECT * FROM t1;' +SELECT @handle IS NOT NULL as 'Prepared' +EXEC SP_EXECUTE @handle +GO + +-- runtime error 4 +DECLARE @handle int; +EXEC SP_PREPARE @handle OUT, NULL, 'DECLARE @var int; SET @var = 1; select * from t1 where c = @var' +SELECT @handle IS NOT NULL as 'Prepared' +EXEC SP_EXECUTE @handle +GO diff --git a/contrib/test/python/input/storedProcedures/TestStoredProcedures.txt b/contrib/test/python/input/storedProcedures/TestStoredProcedures.txt new file mode 100644 index 00000000000..cda18cabbe3 --- /dev/null +++ b/contrib/test/python/input/storedProcedures/TestStoredProcedures.txt @@ -0,0 +1,140 @@ +# PROCEDURE WITH NO BODY, works with babel but not with sql +#create procedure sp_test AS BEGIN END; +# PROCEDURE WITH NO PARAMS +create table temp_sp2(a int); +CREATE PROCEDURE sp_test AS BEGIN insert into temp_sp2 values(1); END; +storedproc#!#prep#!#sp_test#!# +SELECT * FROM temp_sp2; +drop table temp_sp2; +drop Procedure sp_test; +# PROCEDURE WITH INPUT PARAMETER +#drop table temp_sp; +create table temp_sp(a int); +Create Procedure stored_proc1 (@a int) As Begin insert into temp_sp values(@a) End; +# NOT WORKING FOR BABEL,RAISED JIRA 444 +storedproc#!#prep#!#stored_proc1#!#int|-|a|-|-100|-|input +# MISMATCH IN RETURN VALUES +exec stored_proc1 -200 +exec stored_proc1 0 +exec stored_proc1 -1 +exec stored_proc1 2 +# filed Jira on this, doesnt work for babel +#exec stored_proc1 2.2 +SELECT * FROM temp_sp; +DROP table temp_sp; +DROP Procedure stored_proc1 +# input parameter +CREATE PROCEDURE sp_test1 (@a INT) AS BEGIN SET @a=100; Select @a as a; END; +exec sp_test1 2 +Declare @a int;Set @a=1; exec sp_test1 @a;select @a as a; +storedproc#!#prep#!#sp_test1#!#int|-|a|-|1|-|input +storedproc#!#prep#!#sp_test1#!#int|-|a|-|10|-|input +DROP PROCEDURE sp_test1 +# TESTING OUT PARAMETERS FOR ALL THE DATATYPES +# int +CREATE PROCEDURE sp_test1 (@a INT OUTPUT) AS BEGIN SET @a=100; Select @a as a; END; +#Declare @a int;Set @a=1; exec sp_test1 @a;select @a as a; +storedproc#!#prep#!#sp_test1#!#int|-|a|-|1|-|output +storedproc#!#prep#!#sp_test1#!#int|-|a|-|1|-|inputoutput +DROP PROCEDURE sp_test1 +# smallint +CREATE PROCEDURE sp_test2 (@a SMALLINT OUTPUT) AS BEGIN SET @a=100; Select @a as a; END; +#Declare @a smallint;Set @a=1; exec sp_test2 @a;select @a as a; +storedproc#!#prep#!#sp_test2#!#smallint|-|a|-|10|-|output +storedproc#!#prep#!#sp_test2#!#smallint|-|a|-|10|-|inputoutput +DROP PROCEDURE sp_test2 +# bigint +CREATE PROCEDURE sp_test3 (@a BIGINT OUTPUT) AS BEGIN SET @a=100; Select @a as a; END; +storedproc#!#prep#!#sp_test3#!#bigint|-|a|-|10|-|output +storedproc#!#prep#!#sp_test3#!#bigint|-|a|-|10|-|inputoutput +DROP PROCEDURE sp_test3 +# tinyint +#CREATE PROCEDURE sp_test4 (@a tinyint OUTPUT) AS BEGIN SET @a=100; Select @a as a; END; +#storedproc#!#prep#!#sp_test4#!#tinyint|-|a|-|10|-|output +#storedproc#!#prep#!#sp_test4#!#tinyint|-|a|-|10|-|inputoutput +#DROP PROCEDURE sp_test4 +# float +CREATE PROCEDURE sp_test5 (@a float OUTPUT) AS BEGIN SET @a=100.12; Select @a as a; END; +#Declare @a float;Set @a=1.1; exec sp_test5 @a;select @a as a; +storedproc#!#prep#!#sp_test5#!#float|-|a|-|10.1|-|output +storedproc#!#prep#!#sp_test5#!#float|-|a|-|10.1|-|inputoutput +DROP PROCEDURE sp_test5 +# varchar +#CREATE PROCEDURE sp_test6 (@a varchar OUTPUT) AS BEGIN SET @a='helloworld'; Select @a as a; END; +#storedproc#!#prep#!#sp_test6#!#varchar|-|a|-|hello|-|output +#storedproc#!#prep#!#sp_test6#!#varchar|-|a|-|hello|-|inputoutput +#DROP PROCEDURE sp_test6 +# char BABEL-705 +#CREATE PROCEDURE sp_test7 (@a char OUTPUT) AS BEGIN SET @a='b'; Select @a as a; END; +#Declare @a varchar;Set @a='h'; exec sp_test7 @a;select @a as a; +#storedproc#!#prep#!#sp_test7#!#char|-|a|-|t|-|output +#storedproc#!#prep#!#sp_test7#!#char|-|a|-|t|-|inputoutput +#DROP PROCEDURE sp_test7 +# nvarchar +#CREATE PROCEDURE sp_test9 (@a nvarchar OUTPUT) AS BEGIN SET @a='helloworld'; Select @a as a; END; +#Declare @a nvarchar;Set @a='hello'; exec sp_test9 @a;select @a as a; +#storedproc#!#prep#!#sp_test9#!#varchar|-|a|-|hello|-|output +#storedproc#!#prep#!#sp_test9#!#varchar|-|a|-|hello|-|inputoutput +#DROP PROCEDURE sp_test9 +# numeric +CREATE PROCEDURE sp_test10 (@a numeric(10,4) OUTPUT) AS BEGIN SET @a=100.41; Select @a as a; END; +#Declare @a numeric(10,4);Set @a=10.04; exec sp_test10 @a;select @a as a; +#storedproc#!#prep#!#sp_test10#!#numeric|-|a|-|123|-|10|-|3|-|output +#storedproc#!#prep#!#sp_test10#!#numeric|-|a|-|123|-|10|-|2|-|inputoutput +DROP PROCEDURE sp_test10 +# decimal +CREATE PROCEDURE sp_test11 (@a decimal(10,4) OUTPUT) AS BEGIN SET @a=100.41; Select @a as a; END; +#Declare @a decimal(10,4);Set @a=10.04; exec sp_test11 @a;select @a as a; +#storedproc#!#prep#!#sp_test11#!#decimal|-|a|-|123|-|10|-|3|-|output +#storedproc#!#prep#!#sp_test11#!#decimal|-|a|-|123|-|10|-|2|-|inputoutput +DROP PROCEDURE sp_test11 +# binary +#CREATE PROCEDURE sp_test12 (@a binary OUTPUT) AS BEGIN SET @a=0x121; Select @a as a; END; +#exec sp_test12 0x122 +#Declare @a binary;Set @a=0x121; exec sp_test12 @a;select @a as a; +#storedproc#!#prep#!#sp_test12#!#binary|-|a|-|0x122|-|output +#storedproc#!#prep#!#sp_test12#!#binary|-|a|-|0x122|-|inputoutput +#DROP PROCEDURE sp_test12 +# varbinary BABEL-701 +#CREATE PROCEDURE sp_test13 (@a varbinary OUTPUT) AS BEGIN SET @a=0x121; Select @a as a; END; +#exec sp_test13 0x122 +#Declare @a varbinary;Set @a=0x122; exec sp_test13 @a;select @a as a; +#storedproc#!#prep#!#sp_test13#!#varbinary|-|a|-|0x122|-|output +#storedproc#!#prep#!#sp_test13#!#varbinary|-|a|-|0x122|-|inputoutput +#DROP PROCEDURE sp_test13 +# date +CREATE PROCEDURE sp_test14 (@a date output) AS BEGIN SET @a='1999-1-3'; Select @a as a; END; +#Declare @a DATE;Set @a='9999-12-31'; exec sp_test14 @a;select @a as a; +storedproc#!#prep#!#sp_test14#!#DATE|-|a|-|9999-12-31|-|output +storedproc#!#prep#!#sp_test14#!#DATE|-|a|-|9999-12-31|-|inputoutput +DROP PROCEDURE sp_test14 +# time +#CREATE PROCEDURE sp_test15 (@a time(4) OUTPUT) AS BEGIN SET @a='11:25:07.123'; Select @a as a; END; +#Declare @a Time;Set @a='12:45:37.123'; exec sp_test15 @a;select @a as a; +#storedproc#!#prep#!#sp_test15#!#Time|-|a|-|12:45:37.123|-|3|-|output +#storedproc#!#prep#!#sp_test15#!#Time|-|a|-|12:45:37.123|-|3|-|inputoutput +#DROP PROCEDURE sp_test15 +# dateime BABEL-694 +#CREATE PROCEDURE sp_test16 (@a datetime output) AS BEGIN SET @a='2004-05-18 13:59:59.995'; Select @a as a; END; +#Declare @a DATETIME;Set @a='2000-02-28 23:59:59.995'; exec sp_test16 @a;select @a as a; +#storedproc#!#prep#!#sp_test16#!#DATETIME|-|a|-|2000-02-28 23:59:59.995|-|output +#storedproc#!#prep#!#sp_test16#!#DATETIME|-|a|-|2000-02-28 23:59:59.995|-|inputoutput +#DROP PROCEDURE sp_test16 +# datetime2 +#CREATE PROCEDURE sp_test17 (@a datetime2(5) OUTPUT) AS BEGIN SET @a='2014-10-2 1:45:37.123456'; Select @a as a; END; +#Declare @a Datetime2;Set @a='2016-10-23 12:45:37.123456'; exec sp_test17 @a;select @a as a; +#storedproc#!#prep#!#sp_test17#!#Datetime2|-|a|-|2016-10-23 12:45:37.123456|-|5|-|output +#storedproc#!#prep#!#sp_test17#!#Datetime2|-|a|-|2016-10-23 12:45:37.123456|-|5|-|inputoutput +#DROP PROCEDURE sp_test17 +# smalldatetime BABEL-694 +#CREATE PROCEDURE sp_test18 (@a smalldatetime output) AS BEGIN SET @a='2010-02-03 12:58:23'; Select @a as a; END; +#Declare @a SMALLDATETIME;Set @a='2000-12-13 12:58:23'; exec sp_test18 @a;select @a as a; +#storedproc#!#prep#!#sp_test18#!#SMALLDATETIME|-|a|-|2000-12-13 12:58:23|-|output +#storedproc#!#prep#!#sp_test18#!#SMALLDATETIME|-|a|-|2000-12-13 12:58:23|-|inputoutput +#DROP PROCEDURE sp_test18 +# UID +#CREATE PROCEDURE sp_test19 (@a uniqueidentifier OUTPUT) AS BEGIN SET @a='ce8af10a-2709-43b0-9e4e-a02753929d17'; Select @a as a; END; +#Declare @a uniqueidentifier;Set @a='5b7c2e8d-6d90-411d-8e19-9a81067e6f6c'; exec sp_test19 @a;select @a as a; +#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 diff --git a/contrib/test/python/input/transactions/TestTransactionSupportForProcedure.txt b/contrib/test/python/input/transactions/TestTransactionSupportForProcedure.txt new file mode 100644 index 00000000000..a9a997b1c75 --- /dev/null +++ b/contrib/test/python/input/transactions/TestTransactionSupportForProcedure.txt @@ -0,0 +1,260 @@ +#setup +create table txnproctable (c1 int not null, c2 varchar(100)) + +# PROC +# BEGIN TRAN +# SAVEPOINT +# ROLLBACK SAVEPOINT +# COMMIT +create procedure txnproc1 as begin tran; insert into txnproctable values (1, 'abc'); save tran sp1; update txnproctable set c1 = c1 + 1; rollback tran sp1; commit tran; +select @@trancount; +select * from txnproctable order by c1; +exec txnproc1; +select @@trancount; +select * from txnproctable order by c1; + + +# PROC +# BEGIN TRAN +# SAVEPOINT +# ROLLBACK SAVEPOINT +# ROLLBACK +drop procedure txnproc1; +create procedure txnproc1 as begin tran; insert into txnproctable values(2, 'xyz'); save tran sp1; delete from txnproctable; rollback tran sp1; rollback tran; +select @@trancount; +select * from txnproctable order by c1; +exec txnproc1; +select @@trancount; +select * from txnproctable order by c1; + + +# PROC +# BEGIN TRAN +# SAVEPOINT +# ROLLBACK SAVEPOINT +# COMMIT +drop procedure txnproc1 +create procedure txnproc1 as begin tran; insert into txnproctable values(3, 'dbd'); save tran sp1; update txnproctable set c1 = c1 + 1; rollback tran sp1; +select @@trancount +select * from txnproctable order by c1; +exec txnproc1; +select @@trancount +select * from txnproctable order by c1; +commit tran; +select @@trancount +select * from txnproctable order by c1; + + +# PROC +# BEGIN TRAN +# SAVEPOINT +# ROLLBACK SAVEPOINT +# COMMIT +drop procedure txnproc1 +create procedure txnproc1 as begin tran; insert into txnproctable values(4, 'sbd'); save tran sp1; update txnproctable set c1 = c1 + 1; +select @@trancount +select * from txnproctable order by c1; +exec txnproc1; +select @@trancount +select * from txnproctable order by c1; +rollback tran sp1; +select @@trancount +select * from txnproctable order by c1; +commit tran; +select @@trancount +select * from txnproctable order by c1; + + +# BEGIN TRAN +# PROC +# SAVEPOINT +# ROLLBACK SAVEPOINT +# COMMIT +begin tran; +select @@trancount +select * from txnproctable order by c1; +drop procedure txnproc1 +create procedure txnproc1 as insert into txnproctable values(5, 'abc'); save tran sp1; update txnproctable set c1 = c1 + 1; rollback tran sp1; +select @@trancount +select * from txnproctable order by c1; +exec txnproc1; +select @@trancount +select * from txnproctable order by c1; +commit tran; +select @@trancount +select * from txnproctable order by c1; + + +# BEGIN TRAN +# PROC +# SAVEPOINT +# ROLLBACK SAVEPOINT +# ROLLBACK +begin tran; +select @@trancount +select * from txnproctable order by c1; +drop procedure txnproc1 +create procedure txnproc1 as insert into txnproctable values(6, 'abc'); save tran sp1; update txnproctable set c1 = c1 + 1; rollback tran sp1; +select @@trancount +select * from txnproctable order by c1; +exec txnproc1; +select @@trancount +select * from txnproctable order by c1; +commit tran; +select @@trancount +select * from txnproctable order by c1; + +# BEGIN TRAN +# PROC +# SAVEPOINT +# ROLLBACK SAVEPOINT +# COMMIT +begin tran; +select @@trancount +select * from txnproctable order by c1; +drop procedure txnproc1 +create procedure txnproc1 as insert into txnproctable values(7, 'abc'); save tran sp1; update txnproctable set c1 = c1 + 1; rollback tran sp1; update txnproctable set c1 = c1 + 1; commit tran; +select @@trancount +select * from txnproctable order by c1; +exec txnproc1; +select @@trancount +select * from txnproctable order by c1; + +# BEGIN TRAN +# PROC +# SAVEPOINT +# ROLLBACK SAVEPOINT +# ROLLBACK +begin tran; +select @@trancount +select * from txnproctable order by c1; +drop procedure txnproc1 +create procedure txnproc1 as insert into txnproctable values(8, 'abc'); save tran sp1; update txnproctable set c1 = c1 + 1; rollback tran sp1; update txnproctable set c1 = c1 + 1; rollback tran; +select @@trancount +select * from txnproctable order by c1; +exec txnproc1; +select @@trancount +select * from txnproctable order by c1; + +# BEGIN TRAN +# START SAVEPOINT +# PROC +# ROLLBACK SAVEPOINT +# ROLLBACK +begin tran; +select @@trancount +select * from txnproctable order by c1; +save tran sp1; +select @@trancount +select * from txnproctable order by c1; +drop procedure txnproc1 +create procedure txnproc1 as insert into txnproctable values(9, 'abc'); update txnproctable set c1 = c1 + 1; +select @@trancount +select * from txnproctable order by c1; +exec txnproc1; +rollback tran sp1; +select @@trancount +select * from txnproctable order by c1; +rollback tran; +select @@trancount +select * from txnproctable order by c1; + +# BEGIN TRAN +# START SAVEPOINT +# PROC +# ROLLBACK SAVEPOINT +# ROLLBACK +begin tran; +select @@trancount +select * from txnproctable order by c1; +save tran sp1; +select @@trancount +select * from txnproctable order by c1; +drop procedure txnproc1 +create procedure txnproc1 as insert into txnproctable values(10, 'abc'); update txnproctable set c1 = c1 + 1; +select @@trancount +select * from txnproctable order by c1; +exec txnproc1; +rollback tran sp1; +select @@trancount +select * from txnproctable order by c1; +commit tran; +select @@trancount +select * from txnproctable order by c1; + +# BEGIN TRAN +# START SAVEPOINT +# PROC +# ROLLBACK SAVEPOINT +# ROLLBACK +begin tran; +select @@trancount +select * from txnproctable order by c1; +save tran sp1; +select @@trancount +select * from txnproctable order by c1; +drop procedure txnproc1 +create procedure txnproc1 as insert into txnproctable values(11, 'abc'); rollback tran sp1; update txnproctable set c1 = c1 + 1; +select @@trancount +select * from txnproctable order by c1; +exec txnproc1; +commit tran; +select @@trancount +select * from txnproctable order by c1; + +# PROC1 +# BEGIN TRAN +# PROC2 +# PROC3 +# BEGIN TRAN +# START SAVEPOINT +# ROLLBACK SAVEPOINT +# COMMIT +# COMMIT +create procedure txnProc3 as begin tran; insert into txnproctable values (16, 'abc'); save tran sp1; update txnproctable set c1 = c1 + 1; rollback tran sp1; +select @@trancount +select * from txnproctable order by c1; +create procedure txnProc2 as update txnproctable set c1 = c1 + 1; exec txnProc3; commit tran; +select @@trancount +select * from txnproctable order by c1; +drop procedure txnproc1 +create procedure txnproc1 as delete from txnproctable; begin tran; exec txnProc2; +select @@trancount +select * from txnproctable order by c1; +exec txnproc1; +select @@trancount +select * from txnproctable order by c1; +commit tran; +select @@trancount +select * from txnproctable order by c1; + +# PROC1 +# BEGIN TRAN +# PROC2 +# PROC3 +# BEGIN TRAN +# START SAVEPOINT +# ROLLBACK SAVEPOINT +# ROLLBACK TRAN +# COMMIT +drop procedure txnproc3 +create procedure txnProc3 as begin tran; insert into txnproctable values (20, 'abc'); save tran sp1; update txnproctable set c1 = c1 + 1; rollback tran sp1; +select @@trancount +select * from txnproctable order by c1; +drop procedure txnproc2 +create procedure txnProc2 as update txnproctable set c1 = c1 + 1; exec txnProc3; rollback tran; +select @@trancount +select * from txnproctable order by c1; +drop procedure txnproc1 +create procedure txnproc1 as delete from txnproctable; begin tran; exec txnProc2; +select @@trancount +select * from txnproctable order by c1; +exec txnproc1; +select @@trancount +select * from txnproctable order by c1; + +#cleanup +drop procedure txnproc3 +drop procedure txnproc2 +drop procedure txnproc1 +drop table txnproctable \ No newline at end of file diff --git a/contrib/test/python/input/transactions/TestTransactionsSQLBatch.txt b/contrib/test/python/input/transactions/TestTransactionsSQLBatch.txt new file mode 100644 index 00000000000..c767fbbaead --- /dev/null +++ b/contrib/test/python/input/transactions/TestTransactionsSQLBatch.txt @@ -0,0 +1,189 @@ +create table TxnTable(c1 int); + +# Begin transaction -> commit transaction +begin transaction; +select @@trancount; +begin transaction; +select @@trancount; +set transaction isolation level read committed; +#show transaction_isolation; +#show default_transaction_isolation; +insert into TxnTable values(1); +commit transaction; +select @@trancount; +commit transaction; +select @@trancount; +select c1 from TxnTable; + +# Begin transaction -> rollback transaction +begin transaction; +insert into TxnTable values(2); +rollback transaction; +select c1 from TxnTable; + +#Begin tran -> commit tran +begin tran; +insert into TxnTable values(2); +commit tran; +select c1 from TxnTable; + +# Begin tran -> rollback tran +begin tran; +select @@trancount; +begin tran; +set transaction isolation level read uncommitted; +#show transaction_isolation; +#show default_transaction_isolation; +insert into TxnTable values(3); +select @@trancount; +rollback tran; +select @@trancount; +select c1 from TxnTable; + +set transaction isolation level repeatable read; +#show transaction_isolation; +#show default_transaction_isolation; + +# Begin transaction -> commit +begin transaction; +insert into TxnTable values(4); +commit; +select c1 from TxnTable; + +# Begin transaction -> commit work +begin transaction; +insert into TxnTable values(5); +commit work; +select c1 from TxnTable; + +# Begin transaction -> rollback +begin transaction; +insert into TxnTable values(6); +rollback; +select c1 from TxnTable; + +# Begin transaction -> rollback work +begin transaction; +insert into TxnTable values(7); +rollback work; +select c1 from TxnTable; + +# Begin transaction name -> commit transaction name +begin transaction txn1; +insert into TxnTable values(8); +commit transaction txn1; +select c1 from TxnTable; + +# Begin transaction name -> rollback transaction name +begin transaction txn1; +insert into TxnTable values(9); +rollback transaction txn1; +select c1 from TxnTable; + +# Begin tran name -> commit tran name +begin tran txn1; +insert into TxnTable values(10); +commit tran txn1; +select c1 from TxnTable; + +# Begin tran name -> rollback tran name +begin tran txn1; +insert into TxnTable values(10); +rollback tran txn1; +select c1 from TxnTable; + +truncate table TxnTable; + +# save tran name -> rollback tran name +set transaction isolation level snapshot; +#show transaction_isolation; +#show default_transaction_isolation; +begin transaction txn1; +insert into TxnTable values(1); +save transaction sp1; +select @@trancount; +insert into TxnTable values(2); +save tran sp2; +insert into TxnTable values(3); +save tran sp2; +select @@trancount; +insert into TxnTable values(4); +select c1 from TxnTable; +rollback tran sp2; +select @@trancount; +select c1 from TxnTable; +rollback tran sp2; +select @@trancount; +select c1 from TxnTable; +rollback tran sp1; +select @@trancount; +select c1 from TxnTable; +rollback tran txn1; +select @@trancount; +select c1 from TxnTable; + +# begin transaction name -> save transaction name -> rollback to first savepoint +begin transaction txn1; +insert into TxnTable values(1); +save transaction sp1; +insert into TxnTable values(2); +save transaction sp2; +insert into TxnTable values(3); +save transaction sp3; +insert into TxnTable values(4); +rollback tran sp1; +#rollback tran sp1; -- this will give an error +rollback tran; +select c1 from TxnTable; + +# begin transaction name -> save transaction name -> rollback tran name, Rollback whole transaction +set transaction isolation level serializable; +#show transaction_isolation; +#show default_transaction_isolation; +begin transaction txn1; +insert into TxnTable values(1); +save transaction sp1; +begin transaction txn1; +insert into TxnTable values(2); +save transaction sp1; +insert into TxnTable values(3); +select @@trancount; +rollback tran txn1; +select @@trancount; +select c1 from TxnTable; + +# 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; +rollback tran sp1; +commit transaction; +select c1 from TxnTable; + +# 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; +rollback tran sp1; +save transaction sp2; +insert into TxnTable values(5); +commit transaction; +select c1 from TxnTable; + +# 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 +rollback tran sp1; +commit transaction; +select c1 from TxnTable; + +Drop table TxnTable; \ No newline at end of file diff --git a/contrib/test/python/logs/.gitignore b/contrib/test/python/logs/.gitignore new file mode 100644 index 00000000000..5e7d2734cfc --- /dev/null +++ b/contrib/test/python/logs/.gitignore @@ -0,0 +1,4 @@ +# Ignore everything in this directory +* +# Except this file +!.gitignore diff --git a/contrib/test/python/output/pymssql/.gitkeep b/contrib/test/python/output/pymssql/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/contrib/test/python/output/pyodbc/.gitkeep b/contrib/test/python/output/pyodbc/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/contrib/test/python/python_authentication.py b/contrib/test/python/python_authentication.py new file mode 100644 index 00000000000..631797132ff --- /dev/null +++ b/contrib/test/python/python_authentication.py @@ -0,0 +1,47 @@ +import pyodbc +from compare_results import handle_exception_in_file +from utils.config import config_dict as cfg + +#function to perform TestAuth +def py_authentication(file_writer, query, logger): + result = query.split("#!#") + + connection_properties_babel = {} + + if cfg["driver"] == "pyodbc": + connection_properties_babel["serverName"] = cfg["fileGenerator_URL"] + connection_properties_babel["portNumber"] = cfg["fileGenerator_port"] + connection_properties_babel["database"] = cfg["fileGenerator_databaseName"] + connection_properties_babel["user"] = cfg["fileGenerator_user"] + connection_properties_babel["password"] = cfg["fileGenerator_password"] + + other_prop = "" + connection_string_babel = create_connection_string(result, connection_properties_babel, other_prop) + logger.info('Establishing connection with the connection string: {}'.format(connection_string_babel)) + + try: + file_writer.write(query) + file_writer.write("\n") + + babel_cnxn = pyodbc.connect(connection_string_babel) + + file_writer.write("~~SUCCESS~~") + file_writer.write("\n") + except pyodbc.Error as e: + handle_exception_in_file(e, file_writer) + except Exception as e: + logger.error(str(e)) + return False + else: + logger.info("Currently, Driver not supported for TestAuth.") + return True + +def create_connection_string(result, connection_properties, other_prop): + for i in range(1,len(result)): + if result[i].startswith("others"): + other_prop = result[i].replace("others|-|","") + else: + property = result[i].split("|-|") + connection_properties[property[0]] = property[1] + connection_str = 'DRIVER={};SERVER={},{};DATABASE={};UID={};PWD={}'.format(cfg["provider"], connection_properties["serverName"], connection_properties["portNumber"], connection_properties["database"], connection_properties["user"], connection_properties["password"]) + return connection_str + ";" + other_prop \ No newline at end of file diff --git a/contrib/test/python/sql_expected/pymssql/.gitkeep b/contrib/test/python/sql_expected/pymssql/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/contrib/test/python/sql_expected/pyodbc/.gitkeep b/contrib/test/python/sql_expected/pyodbc/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/contrib/test/python/start.py b/contrib/test/python/start.py new file mode 100644 index 00000000000..73a5298666f --- /dev/null +++ b/contrib/test/python/start.py @@ -0,0 +1,24 @@ +#a wrapper on main test container to enable functionality like multithreading and backtracing error +import pytest +from utils.config import config_dict as cfg + +#arguments added to clean the console output to just include test summary +arguments = ["-vs", "--no-header", "--tb=long", "--no-summary"] + + +#Multiprocessing +if cfg["runInParallel"].lower() == "true": + arguments.append("-n 4") + +#add print to console +arguments.append("-s") + +#to remove duplicate arguments from arguments list +arguments=list(set(arguments)) + +#check if driver is supported by the framework +if cfg["driver"] in ["pyodbc", "pymssql"]: + arguments.append("test_main.py") + pytest.main(args = arguments) +else: + print("\nERROR: Driver not supported by the framework\n") diff --git a/contrib/test/python/test_main.py b/contrib/test/python/test_main.py new file mode 100644 index 00000000000..c91b2b6e791 --- /dev/null +++ b/contrib/test/python/test_main.py @@ -0,0 +1,71 @@ +import logging +from file_handler import file_handler +import pytest +from utils.base import add_files +import os +from datetime import datetime +from pathlib import Path + +def get_files(): + lst = add_files() + for item in lst: + yield item + +@pytest.fixture(scope = "session") +def my_setup(): + try: + log_folder_name = datetime.now().strftime('log_%H_%M_%d_%m_%Y') + path = Path.cwd().joinpath("logs", log_folder_name) + Path.mkdir(path, parents = True, exist_ok = True) + + except: + pass + + yield log_folder_name + +# function to parametrize the input files +@pytest.fixture(params = get_files()) +def fx1(request): + return request.param + +#main test fuctions +def test_main(fx1, my_setup): + logfname = my_setup + + #console logger + lgstr = logging.getLogger("Summary-Logger").getChild(fx1.name + "_console") + sh = logging.StreamHandler() + lgstr.addHandler(sh) + lgstr.setLevel(logging.DEBUG) + + #file logger + s_log = Path.cwd().joinpath("logs", logfname, "summary.log") + lg = logging.getLogger("Summary-Logger").getChild(fx1.name) + fh = logging.FileHandler(filename = s_log, mode = "a") + formatter = logging.Formatter('%(message)s') + fh.setFormatter(formatter) + lg.addHandler(fh) + lg.setLevel(logging.DEBUG) + + passed,failed = file_handler(fx1, logfname) + + output_fmt_str="\n{0:30s}{1:10s} passed={2:3d} failed={3:3d}" + + try: + assert passed+failed == passed + lg.info(output_fmt_str.format(os.path.basename(fx1), "PASSED", passed, failed)) + lgstr.info(output_fmt_str.format(os.path.basename(fx1), "PASSED", passed, failed)) + + except AssertionError as e: + lg.error(output_fmt_str.format(os.path.basename(fx1), "FAILED", passed, failed)) + lgstr.error(output_fmt_str.format(os.path.basename(fx1), "FAILED", passed, failed)) + + + lgstr.removeHandler(sh) + lg.removeHandler(fh) + fh.close() + sh.close() + + assert passed+failed == passed + + diff --git a/contrib/test/python/utils/__init__.py b/contrib/test/python/utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/contrib/test/python/utils/base.py b/contrib/test/python/utils/base.py new file mode 100644 index 00000000000..8fd8dffa6bf --- /dev/null +++ b/contrib/test/python/utils/base.py @@ -0,0 +1,57 @@ +from utils.config import read_config +from pathlib import Path +import pymssql +import pyodbc +import re + +#to make list of files paths to run as tests +def add_files(): + cfg = read_config() + + testnames = cfg["testName"] + if ";" in testnames: + testnames = testnames.split(";") + else: + testnames = [testnames] + + testdir = cfg["inputFilesPath"] + #pth = Path.cwd().joinpath(testdir) + pth = Path(testdir) + + #recursively search and return .sql and .txt files + if "all" in testnames: + files = [] + for f in pth.rglob("*.txt"): + files.append(f) + + for f in pth.rglob("*.sql"): + files.append(f) + + return files + #search for testcase name recursively + else: + lst = [] + for item in testnames: + for f in pth.rglob(item): + lst.append(f) + + return lst + +#to handle exceptions for babel server execution and return corresponding error code +def handle_babel_exception(e, logger): + if issubclass(type(e), pyodbc.Error): + code = re.findall(r"\(\d+\)", e.args[1]) + + if len(code) > 0: + code = code[0][1:-1] + logger.warning("Babel Exception: " + str(code)) + + logger.warning("Babel Exception: " + e.args[1]) + + elif issubclass(type(e),pymssql.Error): + logger.warning("Babel Exception: " + str(e.args[0])) + logger.warning("Babel Exception: " + repr(str(e.args[1].decode()))) + + #default + else: + logger.warning("Babel Exception: " + str(e)) diff --git a/contrib/test/python/utils/blank.txt b/contrib/test/python/utils/blank.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/contrib/test/python/utils/config.py b/contrib/test/python/utils/config.py new file mode 100644 index 00000000000..665aa0b10be --- /dev/null +++ b/contrib/test/python/utils/config.py @@ -0,0 +1,28 @@ +import os + +#returns a dictionary with all the configuration details +def read_config(): + with open("config.txt", "r") as f: + lines = f.readlines() + lines = [ line.replace("\n", "") for line in lines ] + configDict = {} + for line in lines: + if line.startswith("#") or len(line) < 1: + continue + else: + data = line.split("=") + + for n, x in enumerate(data): + data[n] = data[n].strip() + + configDict[data[0]] = data[1] + + #check and override key's value if already set in enviornment variables + for key in configDict: + if key in os.environ: + configDict[key] = os.environ[key] + + return configDict + +config_dict = read_config() + diff --git a/contrib/test/python/utils/db_client.py b/contrib/test/python/utils/db_client.py new file mode 100644 index 00000000000..eab2bb38269 --- /dev/null +++ b/contrib/test/python/utils/db_client.py @@ -0,0 +1,106 @@ +import pyodbc +import pymssql + +#format strings for logging +line_formatter = "*" * 30 + "{}" + "*" * 30 +connect_server_formatter = " Connected to {} Server successfully!! " +close_connection_formatter = " Connection closed to {} Server successfully!! " + +#make connection object using pyodbc +class Db_Client_pyodbc: + + def __init__(self,provider, server_url, port, db_name, db_user, db_pass, logger): + + self.provider=provider + self.server_url = server_url + self.port = port + self.db_name = db_name + self.db_user = db_user + self.db_pass = db_pass + self.logger = logger + self.cnxn = None + try: + self.cnxn = pyodbc.connect('DRIVER={};SERVER={},{};DATABASE={};UID={};PWD={}'.format(self.provider,self.server_url, str(self.port), self.db_name, self.db_user, self.db_pass), autocommit = True) + self.logger.info(line_formatter.format(connect_server_formatter.format(self.server_url))) + except Exception as e: + + self.logger.error(str(e)) + self.logger.error(line_formatter.format("Server Connection Failed")) + + + def get_cursor(self): + try: + return self.cnxn.cursor() + except Exception as e: + self.logger.error(str(e)) + self.logger.error(line_formatter.format("Unexpected error in connection")) + + def commit(self): + self.cnxn.commit() + + def rollback(self): + self.cnxn.rollback() + + def set_autocommit(self, val): + self.cnxn.autocommit = val + + def close(self): + try: + self.cnxn.close() + self.logger.info(line_formatter.format(close_connection_formatter.format(self.server_url))) + except Exception as e: + self.logger.error(str(e)) + self.logger.error(line_formatter.format("Error while closing the connection")) + + def set_isolation(self, val): + self.cnxn.setattr(pyodbc.SQL_ATTR_TXN_ISOLATION, val) + +#make connection object using pymssql +class Db_Client_pymssql: + def __init__(self, server_url, port, db_name, db_user, db_pass, logger): + self.server_url = server_url + self.port = port + self.db_name = db_name + self.db_user = db_user + self.db_pass = db_pass + self.logger = logger + self.cnxn = None + try: + self.cnxn = pymssql.connect(server = self.server_url, port = self.port, user = self.db_user, password = self.db_pass, database = self.db_name, autocommit = True) + self.logger.info(line_formatter.format(connect_server_formatter.format(self.server_url))) + except Exception as e: + self.logger.error(str(e)) + self.logger.error(line_formatter.format("Server Connection failed")) + + + def get_cursor(self): + try: + return self.cnxn.cursor() + except Exception as e: + self.logger.error(str(e)) + self.logger.error(line_formatter.format("Error while closing the connection")) + + def commit(self): + self.cnxn.commit() + + def rollback(self): + self.cnxn.rollback() + + def set_autocommit(self, val): + self.cnxn.autocommit = val + + def close(self): + try: + self.cnxn.close() + self.logger.info(line_formatter.format(close_connection_formatter.format(self.server_url))) + except Exception as e: + self.logger.error(str(e)) + self.logger.error(line_formatter.format("Error while closing the connection")) + + + + + + + + diff --git a/contrib/test/python/utils/devanagari.txt b/contrib/test/python/utils/devanagari.txt new file mode 100644 index 00000000000..45f37b695da --- /dev/null +++ b/contrib/test/python/utils/devanagari.txt @@ -0,0 +1 @@ +ऀँंःऄअआइईउऊऋऌऍऎएऐऑऒओऔकखगघङचछजझञटठडढणतथदधनऩपफबभमयरऱलळऴवशषसहऺऻ़ऽािीुूृॄॅॆेैॉॊोौ्ॎॏॐ॒॑॓॔ॕॖॗक़ख़ग़ज़ड़ढ़फ़य़ॠॡॢॣ।॥०१२३४५६७८९॰ॱॲॳॴॵॶॷॹॺॻॼॽॾॿ \ No newline at end of file diff --git a/contrib/test/python/utils/emojisText.txt b/contrib/test/python/utils/emojisText.txt new file mode 100644 index 00000000000..117dfc03289 --- /dev/null +++ b/contrib/test/python/utils/emojisText.txt @@ -0,0 +1 @@ +😀😃😁😎😒😞😍🙂😆😊😉 \ No newline at end of file diff --git a/contrib/test/python/utils/sample.txt b/contrib/test/python/utils/sample.txt new file mode 100644 index 00000000000..352a3fb9297 --- /dev/null +++ b/contrib/test/python/utils/sample.txt @@ -0,0 +1,6 @@ +AAAAAAAAAAAAAAAAAAAA +BBBBBBBBBB +CCCCC +badksjvbajsdcbvjads +sejvhsdbfjhcgvasdhgcvsj +21639812365091264 \ No newline at end of file diff --git a/contrib/test/python/utils/utf16.txt b/contrib/test/python/utils/utf16.txt new file mode 100644 index 00000000000..ee839d6a00c --- /dev/null +++ b/contrib/test/python/utils/utf16.txt @@ -0,0 +1 @@ + !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƻƼƽƾƿǀǁǂǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴǵǶǷǸǹǺǻǼǽǾǿȀȁȂȃȄȅȆȇȈȉȊȋȌȍȎȏȐȑȒȓȔȕȖȗȘșȚțȜȝȞȟȠȡȢȣȤȥȦȧȨȩȪȫȬȭȮȯȰȱȲȳȴȵȶȷȸȹȺȻȼȽȾȿɀɁɂɃɄɅɆɇɈɉɊɋɌɍɎɏɐɑɒɓɔɕɖɗɘəɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯʰʱʲʳʴʵʶʷʸʹʺʻʼʽʾʿˀˁ˂˃˄˅ˆˇˈˉˊˋˌˍˎˏːˑ˒˓˔˕˖˗˘˙˚˛˜˝˞˟ˠˡˢˣˤ˥˦˧˨˩˪˫ˬ˭ˮ˯˰˱˲˳˴˵˶˷˸˹˺˻˼˽˾˿̴̵̶̷̸̡̢̧̨̛̖̗̘̙̜̝̞̟̠̣̤̥̦̩̪̫̬̭̮̯̰̱̲̳̹̺̻̼͇͈͉͍͎̀́̂̃̄̅̆̇̈̉̊̋̌̍̎̏̐̑̒̓̔̽̾̿̀́͂̓̈́͆͊͋͌̕̚ͅ͏͓͔͕͖͙͚͐͑͒͗͛ͣͤͥͦͧͨͩͪͫͬͭͮͯ͘͜͟͢͝͞͠͡ͰͱͲͳʹ͵Ͷͷͺͻͼͽ;΄΅Ά·ΈΉΊΌΎΏΐΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩΪΫάέήίΰαβγδεζηθικλμνξοπρςστυφχψωϊϋόύώϏϐϑϒϓϔϕϖϗϘϙϚϛϜϝϞϟϠϡϢϣϤϥϦϧϨϩϪϫϬϭϮϯϰϱϲϳϴϵ϶ϷϸϹϺϻϼϽϾϿЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяѐёђѓєѕіїјљњћќѝўџѠѡѢѣѤѥѦѧѨѩѪѫѬѭѮѯѰѱѲѳѴѵѶѷѸѹѺѻѼѽѾѿҀҁ҂҃҄҅҆҇҈҉ҊҋҌҍҎҏҐґҒғҔҕҖҗҘҙҚқҜҝҞҟҠҡҢңҤҥҦҧҨҩҪҫҬҭҮүҰұҲҳҴҵҶҷҸҹҺһҼҽҾҿӀӁӂӃӄӅӆӇӈӉӊӋӌӍӎӏӐӑӒӓӔӕӖӗӘәӚӛӜӝӞӟӠӡӢӣӤӥӦӧӨөӪӫӬӭӮӯӰӱӲӳӴӵӶӷӸӹӺӻӼӽӾӿԀԁԂԃԄԅԆԇԈԉԊԋԌԍԎԏԐԑԒԓԔԕԖԗԘԙԚԛԜԝԞԟԠԡԢԣԤԥԦԧԱԲԳԴԵԶԷԸԹԺԻԼԽԾԿՀՁՂՃՄՅՆՇՈՉՊՋՌՍՎՏՐՑՒՓՔՕՖՙ՚՛՜՝՞՟աբգդեզէըթժիլխծկհձղճմյնշոչպջռսվտրցւփքօֆև։֊֏ְֱֲֳִֵֶַָֹֺֻּֽ֑֖֛֢֣֤֥֦֧֪֚֭֮֒֓֔֕֗֘֙֜֝֞֟֠֡֨֩֫֬֯־ֿ׀ׁׂ׃ׅׄ׆ׇאבגדהוזחטיךכלםמןנסעףפץצקרשתװױײ׳״؀؁؂؃؄؆؇؈؉؊؋،؍؎؏ؘؙؚؐؑؒؓؔؕؖؗ؛؞؟ؠءآأؤإئابةتثجحخدذرزسشصضطظعغػؼؽؾؿـفقكلمنهوىيًٌٍَُِّْٕٖٜٟٓٔٗ٘ٙٚٛٝٞ٠١٢٣٤٥٦٧٨٩٪٫٬٭ٮٯٰٱٲٳٴٵٶٷٸٹٺٻټٽپٿڀځڂڃڄڅچڇڈډڊڋڌڍڎڏڐڑڒړڔڕږڗژڙښڛڜڝڞڟڠڡڢڣڤڥڦڧڨکڪګڬڭڮگڰڱڲڳڴڵڶڷڸڹںڻڼڽھڿۀہۂۃۄۅۆۇۈۉۊۋیۍێۏېۑےۓ۔ەۖۗۘۙۚۛۜ۝۞ۣ۟۠ۡۢۤۥۦۧۨ۩۪ۭ۫۬ۮۯ۰۱۲۳۴۵۶۷۸۹ۺۻۼ۽۾ۿ܀܁܂܃܄܅܆܇܈܉܊܋܌܍܏ܐܑܒܓܔܕܖܗܘܙܚܛܜܝܞܟܠܡܢܣܤܥܦܧܨܩܪܫܬܭܮܯܱܴܷܸܹܻܼܾ݂݄݆݈ܰܲܳܵܶܺܽܿ݀݁݃݅݇݉݊ݍݎݏݐݑݒݓݔݕݖݗݘݙݚݛݜݝݞݟݠݡݢݣݤݥݦݧݨݩݪݫݬݭݮݯݰݱݲݳݴݵݶݷݸݹݺݻݼݽݾݿހށނރބޅކއވމފދތލގޏސޑޒޓޔޕޖޗޘޙޚޛޜޝޞޟޠޡޢޣޤޥަާިީުޫެޭޮޯްޱ߀߁߂߃߄߅߆߇߈߉ߊߋߌߍߎߏߐߑߒߓߔߕߖߗߘߙߚߛߜߝߞߟߠߡߢߣߤߥߦߧߨߩߪ߲߫߬߭߮߯߰߱߳ߴߵ߶߷߸߹ߺࠀࠁࠂࠃࠄࠅࠆࠇࠈࠉࠊࠋࠌࠍࠎࠏࠐࠑࠒࠓࠔࠕࠖࠗ࠘࠙ࠚࠛࠜࠝࠞࠟࠠࠡࠢࠣࠤࠥࠦࠧࠨࠩࠪࠫࠬ࠭࠰࠱࠲࠳࠴࠵࠶࠷࠸࠹࠺࠻࠼࠽࠾ࡀࡁࡂࡃࡄࡅࡆࡇࡈࡉࡊࡋࡌࡍࡎࡏࡐࡑࡒࡓࡔࡕࡖࡗࡘ࡙࡚࡛࡞ࢠࢢࢣࢤࢥࢦࢧࢨࢩࢪࢫࢬࣰࣱࣲࣦࣩ࣭࣮࣯ࣶࣹࣺࣤࣥࣧࣨ࣪࣫࣬ࣳࣴࣵࣷࣸࣻࣼࣽࣾऀँंःऄअआइईउऊऋऌऍऎएऐऑऒओऔकखगघङचछजझञटठडढणतथदधनऩपफबभमयरऱलळऴवशषसहऺऻ़ऽािीुूृॄॅॆेैॉॊोौ्ॎॏॐ॒॑॓॔ॕॖॗक़ख़ग़ज़ड़ढ़फ़य़ॠॡॢॣ।॥०१२३४५६७८९॰ॱॲॳॴॵॶॷॹॺॻॼॽॾॿঁংঃঅআইঈউঊঋঌএঐওঔকখগঘঙচছজঝঞটঠডঢণতথদধনপফবভমযরলশষসহ়ঽািীুূৃৄেৈোৌ্ৎৗড়ঢ়য়ৠৡৢৣ০১২৩৪৫৬৭৮৯ৰৱ৲৳৴৵৶৷৸৹৺৻ਁਂਃਅਆਇਈਉਊਏਐਓਔਕਖਗਘਙਚਛਜਝਞਟਠਡਢਣਤਥਦਧਨਪਫਬਭਮਯਰਲਲ਼ਵਸ਼ਸਹ਼ਾਿੀੁੂੇੈੋੌ੍ੑਖ਼ਗ਼ਜ਼ੜਫ਼੦੧੨੩੪੫੬੭੮੯ੰੱੲੳੴੵઁંઃઅઆઇઈઉઊઋઌઍએઐઑઓઔકખગઘઙચછજઝઞટઠડઢણતથદધનપફબભમયરલળવશષસહ઼ઽાિીુૂૃૄૅેૈૉોૌ્ૐૠૡૢૣ૦૧૨૩૪૫૬૭૮૯૰૱ଁଂଃଅଆଇଈଉଊଋଌଏଐଓଔକଖଗଘଙଚଛଜଝଞଟଠଡଢଣତଥଦଧନପଫବଭମଯରଲଳଵଶଷସହ଼ଽାିୀୁୂୃୄେୈୋୌ୍ୖୗଡ଼ଢ଼ୟୠୡୢୣ୦୧୨୩୪୫୬୭୮୯୰ୱ୲୳୴୵୶୷ஂஃஅஆஇஈஉஊஎஏஐஒஓஔகஙசஜஞடணதநனபமயரறலளழவஶஷஸஹாிீுூெேைொோௌ்ௐௗ௦௧௨௩௪௫௬௭௮௯௰௱௲௳௴௵௶௷௸௹௺ఁంఃఅఆఇఈఉఊఋఌఎఏఐఒఓఔకఖగఘఙచఛజఝఞటఠడఢణతథదధనపఫబభమయరఱలళవశషసహఽాిీుూృౄెేైొోౌ్ౕౖౘౙౠౡౢౣ౦౧౨౩౪౫౬౭౮౯౸౹౺౻౼౽౾౿ಂಃಅಆಇಈಉಊಋಌಎಏಐಒಓಔಕಖಗಘಙಚಛಜಝಞಟಠಡಢಣತಥದಧನಪಫಬಭಮಯರಱಲಳವಶಷಸಹ಼ಽಾಿೀುೂೃೄೆೇೈೊೋೌ್ೕೖೞೠೡೢೣ೦೧೨೩೪೫೬೭೮೯ೱೲംഃഅആഇഈഉഊഋഌഎഏഐഒഓഔകഖഗഘങചഛജഝഞടഠഡഢണതഥദധനഩപഫബഭമയരറലളഴവശഷസഹഺഽാിീുൂൃൄെേൈൊോൌ്ൎൗൠൡൢൣ൦൧൨൩൪൫൬൭൮൯൰൱൲൳൴൵൹ൺൻർൽൾൿංඃඅආඇඈඉඊඋඌඍඎඏඐඑඒඓඔඕඖකඛගඝඞඟචඡජඣඤඥඦටඨඩඪණඬතථදධනඳපඵබභමඹයරලවශෂසහළෆ්ාැෑිීුූෘෙේෛොෝෞෟෲෳ෴กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำิีึืฺุู฿เแโใไๅๆ็่้๊๋์ํ๎๏๐๑๒๓๔๕๖๗๘๙๚๛ກຂຄງຈຊຍດຕຖທນບປຜຝພຟມຢຣລວສຫອຮຯະັາຳິີຶືຸູົຼຽເແໂໃໄໆ່້໊໋໌ໍ໐໑໒໓໔໕໖໗໘໙ໜໝໞໟༀ༁༂༃༄༅༆༇༈༉༊་༌།༎༏༐༑༒༓༔༕༖༗༘༙༚༛༜༝༞༟༠༡༢༣༤༥༦༧༨༩༪༫༬༭༮༯༰༱༲༳༴༵༶༷༸༹༺༻༼༽༾༿ཀཁགགྷངཅཆཇཉཊཋཌཌྷཎཏཐདདྷནཔཕབབྷམཙཚཛཛྷཝཞཟའཡརལཤཥསཧཨཀྵཪཫཬཱཱཱིིུུྲྀཷླྀཹེཻོཽཾཿ྄ཱྀྀྂྃ྅྆྇ྈྉྊྋྌྍྎྏྐྑྒྒྷྔྕྖྗྙྚྛྜྜྷྞྟྠྡྡྷྣྤྥྦྦྷྨྩྪྫྫྷྭྮྯྰྱྲླྴྵྶྷྸྐྵྺྻྼ྾྿࿀࿁࿂࿃࿄࿅࿆࿇࿈࿉࿊࿋࿌࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚ကခဂဃငစဆဇဈဉညဋဌဍဎဏတထဒဓနပဖဗဘမယရလဝသဟဠအဢဣဤဥဦဧဨဩဪါာိီုူေဲဳဴဵံ့း္်ျြွှဿ၀၁၂၃၄၅၆၇၈၉၊။၌၍၎၏ၐၑၒၓၔၕၖၗၘၙၚၛၜၝၞၟၠၡၢၣၤၥၦၧၨၩၪၫၬၭၮၯၰၱၲၳၴၵၶၷၸၹၺၻၼၽၾၿႀႁႂႃႄႅႆႇႈႉႊႋႌႍႎႏ႐႑႒႓႔႕႖႗႘႙ႚႛႜႝ႞႟ႠႡႢႣႤႥႦႧႨႩႪႫႬႭႮႯႰႱႲႳႴႵႶႷႸႹႺႻႼႽႾႿჀჁჂჃჄჅჇჍაბგდევზთიკლმნოპჟრსტუფქღყშჩცძწჭხჯჰჱჲჳჴჵჶჷჸჹჺ჻ჼჽჾჿᄀᄁᄂᄃᄄᄅᄆᄇᄈᄉᄊᄋᄌᄍᄎᄏᄐᄑᄒᄓᄔᄕᄖᄗᄘᄙᄚᄛᄜᄝᄞᄟᄠᄡᄢᄣᄤᄥᄦᄧᄨᄩᄪᄫᄬᄭᄮᄯᄰᄱᄲᄳᄴᄵᄶᄷᄸᄹᄺᄻᄼᄽᄾᄿᅀᅁᅂᅃᅄᅅᅆᅇᅈᅉᅊᅋᅌᅍᅎᅏᅐᅑᅒᅓᅔᅕᅖᅗᅘᅙᅚᅛᅜᅝᅞᅟᅠᅡᅢᅣᅤᅥᅦᅧᅨᅩᅪᅫᅬᅭᅮᅯᅰᅱᅲᅳᅴᅵᅶᅷᅸᅹᅺᅻᅼᅽᅾᅿᆀᆁᆂᆃᆄᆅᆆᆇᆈᆉᆊᆋᆌᆍᆎᆏᆐᆑᆒᆓᆔᆕᆖᆗᆘᆙᆚᆛᆜᆝᆞᆟᆠᆡᆢᆣᆤᆥᆦᆧᆨᆩᆪᆫᆬᆭᆮᆯᆰᆱᆲᆳᆴᆵᆶᆷᆸᆹᆺᆻᆼᆽᆾᆿᇀᇁᇂᇃᇄᇅᇆᇇᇈᇉᇊᇋᇌᇍᇎᇏᇐᇑᇒᇓᇔᇕᇖᇗᇘᇙᇚᇛᇜᇝᇞᇟᇠᇡᇢᇣᇤᇥᇦᇧᇨᇩᇪᇫᇬᇭᇮᇯᇰᇱᇲᇳᇴᇵᇶᇷᇸᇹᇺᇻᇼᇽᇾᇿሀሁሂሃሄህሆሇለሉሊላሌልሎሏሐሑሒሓሔሕሖሗመሙሚማሜምሞሟሠሡሢሣሤሥሦሧረሩሪራሬርሮሯሰሱሲሳሴስሶሷሸሹሺሻሼሽሾሿቀቁቂቃቄቅቆቇቈቊቋቌቍቐቑቒቓቔቕቖቘቚቛቜቝበቡቢባቤብቦቧቨቩቪቫቬቭቮቯተቱቲታቴትቶቷቸቹቺቻቼችቾቿኀኁኂኃኄኅኆኇኈኊኋኌኍነኑኒናኔንኖኗኘኙኚኛኜኝኞኟአኡኢኣኤእኦኧከኩኪካኬክኮኯኰኲኳኴኵኸኹኺኻኼኽኾዀዂዃዄዅወዉዊዋዌውዎዏዐዑዒዓዔዕዖዘዙዚዛዜዝዞዟዠዡዢዣዤዥዦዧየዩዪያዬይዮዯደዱዲዳዴድዶዷዸዹዺዻዼዽዾዿጀጁጂጃጄጅጆጇገጉጊጋጌግጎጏጐጒጓጔጕጘጙጚጛጜጝጞጟጠጡጢጣጤጥጦጧጨጩጪጫጬጭጮጯጰጱጲጳጴጵጶጷጸጹጺጻጼጽጾጿፀፁፂፃፄፅፆፇፈፉፊፋፌፍፎፏፐፑፒፓፔፕፖፗፘፙፚ፝፞፟፠፡።፣፤፥፦፧፨፩፪፫፬፭፮፯፰፱፲፳፴፵፶፷፸፹፺፻፼ᎀᎁᎂᎃᎄᎅᎆᎇᎈᎉᎊᎋᎌᎍᎎᎏ᎐᎑᎒᎓᎔᎕᎖᎗᎘᎙ᎠᎡᎢᎣᎤᎥᎦᎧᎨᎩᎪᎫᎬᎭᎮᎯᎰᎱᎲᎳᎴᎵᎶᎷᎸᎹᎺᎻᎼᎽᎾᎿᏀᏁᏂᏃᏄᏅᏆᏇᏈᏉᏊᏋᏌᏍᏎᏏᏐᏑᏒᏓᏔᏕᏖᏗᏘᏙᏚᏛᏜᏝᏞᏟᏠᏡᏢᏣᏤᏥᏦᏧᏨᏩᏪᏫᏬᏭᏮᏯᏰᏱᏲᏳᏴ᐀ᐁᐂᐃᐄᐅᐆᐇᐈᐉᐊᐋᐌᐍᐎᐏᐐᐑᐒᐓᐔᐕᐖᐗᐘᐙᐚᐛᐜᐝᐞᐟᐠᐡᐢᐣᐤᐥᐦᐧᐨᐩᐪᐫᐬᐭᐮᐯᐰᐱᐲᐳᐴᐵᐶᐷᐸᐹᐺᐻᐼᐽᐾᐿᑀᑁᑂᑃᑄᑅᑆᑇᑈᑉᑊᑋᑌᑍᑎᑏᑐᑑᑒᑓᑔᑕᑖᑗᑘᑙᑚᑛᑜᑝᑞᑟᑠᑡᑢᑣᑤᑥᑦᑧᑨᑩᑪᑫᑬᑭᑮᑯᑰᑱᑲᑳᑴᑵᑶᑷᑸᑹᑺᑻᑼᑽᑾᑿᒀᒁᒂᒃᒄᒅᒆᒇᒈᒉᒊᒋᒌᒍᒎᒏᒐᒑᒒᒓᒔᒕᒖᒗᒘᒙᒚᒛᒜᒝᒞᒟᒠᒡᒢᒣᒤᒥᒦᒧᒨᒩᒪᒫᒬᒭᒮᒯᒰᒱᒲᒳᒴᒵᒶᒷᒸᒹᒺᒻᒼᒽᒾᒿᓀᓁᓂᓃᓄᓅᓆᓇᓈᓉᓊᓋᓌᓍᓎᓏᓐᓑᓒᓓᓔᓕᓖᓗᓘᓙᓚᓛᓜᓝᓞᓟᓠᓡᓢᓣᓤᓥᓦᓧᓨᓩᓪᓫᓬᓭᓮᓯᓰᓱᓲᓳᓴᓵᓶᓷᓸᓹᓺᓻᓼᓽᓾᓿᔀᔁᔂᔃᔄᔅᔆᔇᔈᔉᔊᔋᔌᔍᔎᔏᔐᔑᔒᔓᔔᔕᔖᔗᔘᔙᔚᔛᔜᔝᔞᔟᔠᔡᔢᔣᔤᔥᔦᔧᔨᔩᔪᔫᔬᔭᔮᔯᔰᔱᔲᔳᔴᔵᔶᔷᔸᔹᔺᔻᔼᔽᔾᔿᕀᕁᕂᕃᕄᕅᕆᕇᕈᕉᕊᕋᕌᕍᕎᕏᕐᕑᕒᕓᕔᕕᕖᕗᕘᕙᕚᕛᕜᕝᕞᕟᕠᕡᕢᕣᕤᕥᕦᕧᕨᕩᕪᕫᕬᕭᕮᕯᕰᕱᕲᕳᕴᕵᕶᕷᕸᕹᕺᕻᕼᕽᕾᕿᖀᖁᖂᖃᖄᖅᖆᖇᖈᖉᖊᖋᖌᖍᖎᖏᖐᖑᖒᖓᖔᖕᖖᖗᖘᖙᖚᖛᖜᖝᖞᖟᖠᖡᖢᖣᖤᖥᖦᖧᖨᖩᖪᖫᖬᖭᖮᖯᖰᖱᖲᖳᖴᖵᖶᖷᖸᖹᖺᖻᖼᖽᖾᖿᗀᗁᗂᗃᗄᗅᗆᗇᗈᗉᗊᗋᗌᗍᗎᗏᗐᗑᗒᗓᗔᗕᗖᗗᗘᗙᗚᗛᗜᗝᗞᗟᗠᗡᗢᗣᗤᗥᗦᗧᗨᗩᗪᗫᗬᗭᗮᗯᗰᗱᗲᗳᗴᗵᗶᗷᗸᗹᗺᗻᗼᗽᗾᗿᘀᘁᘂᘃᘄᘅᘆᘇᘈᘉᘊᘋᘌᘍᘎᘏᘐᘑᘒᘓᘔᘕᘖᘗᘘᘙᘚᘛᘜᘝᘞᘟᘠᘡᘢᘣᘤᘥᘦᘧᘨᘩᘪᘫᘬᘭᘮᘯᘰᘱᘲᘳᘴᘵᘶᘷᘸᘹᘺᘻᘼᘽᘾᘿᙀᙁᙂᙃᙄᙅᙆᙇᙈᙉᙊᙋᙌᙍᙎᙏᙐᙑᙒᙓᙔᙕᙖᙗᙘᙙᙚᙛᙜᙝᙞᙟᙠᙡᙢᙣᙤᙥᙦᙧᙨᙩᙪᙫᙬ᙭᙮ᙯᙰᙱᙲᙳᙴᙵᙶᙷᙸᙹᙺᙻᙼᙽᙾᙿ ᚁᚂᚃᚄᚅᚆᚇᚈᚉᚊᚋᚌᚍᚎᚏᚐᚑᚒᚓᚔᚕᚖᚗᚘᚙᚚ᚛᚜ᚠᚡᚢᚣᚤᚥᚦᚧᚨᚩᚪᚫᚬᚭᚮᚯᚰᚱᚲᚳᚴᚵᚶᚷᚸᚹᚺᚻᚼᚽᚾᚿᛀᛁᛂᛃᛄᛅᛆᛇᛈᛉᛊᛋᛌᛍᛎᛏᛐᛑᛒᛓᛔᛕᛖᛗᛘᛙᛚᛛᛜᛝᛞᛟᛠᛡᛢᛣᛤᛥᛦᛧᛨᛩᛪ᛫᛬᛭ᛮᛯᛰᜀᜁᜂᜃᜄᜅᜆᜇᜈᜉᜊᜋᜌᜎᜏᜐᜑᜒᜓ᜔ᜠᜡᜢᜣᜤᜥᜦᜧᜨᜩᜪᜫᜬᜭᜮᜯᜰᜱᜲᜳ᜴᜵᜶ᝀᝁᝂᝃᝄᝅᝆᝇᝈᝉᝊᝋᝌᝍᝎᝏᝐᝑᝒᝓᝠᝡᝢᝣᝤᝥᝦᝧᝨᝩᝪᝫᝬᝮᝯᝰᝲᝳកខគឃងចឆជឈញដឋឌឍណតថទធនបផពភមយរលវឝឞសហឡអឣឤឥឦឧឨឩឪឫឬឭឮឯឰឱឲឳ឴឵ាិីឹឺុូួើឿៀេែៃោៅំះៈ៉៊់៌៍៎៏័៑្៓។៕៖ៗ៘៙៚៛ៜ៝០១២៣៤៥៦៧៨៩៰៱៲៳៴៵៶៷៸៹᠀᠁᠂᠃᠄᠅᠆᠇᠈᠉᠊᠋᠌᠍᠎᠐᠑᠒᠓᠔᠕᠖᠗᠘᠙ᠠᠡᠢᠣᠤᠥᠦᠧᠨᠩᠪᠫᠬᠭᠮᠯᠰᠱᠲᠳᠴᠵᠶᠷᠸᠹᠺᠻᠼᠽᠾᠿᡀᡁᡂᡃᡄᡅᡆᡇᡈᡉᡊᡋᡌᡍᡎᡏᡐᡑᡒᡓᡔᡕᡖᡗᡘᡙᡚᡛᡜᡝᡞᡟᡠᡡᡢᡣᡤᡥᡦᡧᡨᡩᡪᡫᡬᡭᡮᡯᡰᡱᡲᡳᡴᡵᡶᡷᢀᢁᢂᢃᢄᢅᢆᢇᢈᢉᢊᢋᢌᢍᢎᢏᢐᢑᢒᢓᢔᢕᢖᢗᢘᢙᢚᢛᢜᢝᢞᢟᢠᢡᢢᢣᢤᢥᢦᢧᢨᢩᢪᢰᢱᢲᢳᢴᢵᢶᢷᢸᢹᢺᢻᢼᢽᢾᢿᣀᣁᣂᣃᣄᣅᣆᣇᣈᣉᣊᣋᣌᣍᣎᣏᣐᣑᣒᣓᣔᣕᣖᣗᣘᣙᣚᣛᣜᣝᣞᣟᣠᣡᣢᣣᣤᣥᣦᣧᣨᣩᣪᣫᣬᣭᣮᣯᣰᣱᣲᣳᣴᣵᤀᤁᤂᤃᤄᤅᤆᤇᤈᤉᤊᤋᤌᤍᤎᤏᤐᤑᤒᤓᤔᤕᤖᤗᤘᤙᤚᤛᤜᤠᤡᤢᤣᤤᤥᤦᤧᤨᤩᤪᤫᤰᤱᤲᤳᤴᤵᤶᤷᤸ᤻᤹᤺᥀᥄᥅᥆᥇᥈᥉᥊᥋᥌᥍᥎᥏ᥐᥑᥒᥓᥔᥕᥖᥗᥘᥙᥚᥛᥜᥝᥞᥟᥠᥡᥢᥣᥤᥥᥦᥧᥨᥩᥪᥫᥬᥭᥰᥱᥲᥳᥴᦀᦁᦂᦃᦄᦅᦆᦇᦈᦉᦊᦋᦌᦍᦎᦏᦐᦑᦒᦓᦔᦕᦖᦗᦘᦙᦚᦛᦜᦝᦞᦟᦠᦡᦢᦣᦤᦥᦦᦧᦨᦩᦪᦫᦰᦱᦲᦳᦴᦵᦶᦷᦸᦹᦺᦻᦼᦽᦾᦿᧀᧁᧂᧃᧄᧅᧆᧇᧈᧉ᧐᧑᧒᧓᧔᧕᧖᧗᧘᧙᧚᧞᧟᧠᧡᧢᧣᧤᧥᧦᧧᧨᧩᧪᧫᧬᧭᧮᧯᧰᧱᧲᧳᧴᧵᧶᧷᧸᧹᧺᧻᧼᧽᧾᧿ᨀᨁᨂᨃᨄᨅᨆᨇᨈᨉᨊᨋᨌᨍᨎᨏᨐᨑᨒᨓᨔᨕᨖᨘᨗᨙᨚᨛ᨞᨟ᨠᨡᨢᨣᨤᨥᨦᨧᨨᨩᨪᨫᨬᨭᨮᨯᨰᨱᨲᨳᨴᨵᨶᨷᨸᨹᨺᨻᨼᨽᨾᨿᩀᩁᩂᩃᩄᩅᩆᩇᩈᩉᩊᩋᩌᩍᩎᩏᩐᩑᩒᩓᩔᩕᩖᩗᩘᩙᩚᩛᩜᩝᩞ᩠ᩡᩢᩣᩤᩥᩦᩧᩨᩩᩪᩫᩬᩭᩮᩯᩰᩱᩲᩳᩴ᩿᩵᩶᩷᩸᩹᩺᩻᩼᪀᪁᪂᪃᪄᪅᪆᪇᪈᪉᪐᪑᪒᪓᪔᪕᪖᪗᪘᪙᪠᪡᪢᪣᪤᪥᪦ᪧ᪨᪩᪪᪫᪬᪭ᬀᬁᬂᬃᬄᬅᬆᬇᬈᬉᬊᬋᬌᬍᬎᬏᬐᬑᬒᬓᬔᬕᬖᬗᬘᬙᬚᬛᬜᬝᬞᬟᬠᬡᬢᬣᬤᬥᬦᬧᬨᬩᬪᬫᬬᬭᬮᬯᬰᬱᬲᬳ᬴ᬵᬶᬷᬸᬹᬺᬻᬼᬽᬾᬿᭀᭁᭂᭃ᭄ᭅᭆᭇᭈᭉᭊᭋ᭐᭑᭒᭓᭔᭕᭖᭗᭘᭙᭚᭛᭜᭝᭞᭟᭠᭡᭢᭣᭤᭥᭦᭧᭨᭩᭪᭬᭫᭭᭮᭯᭰᭱᭲᭳᭴᭵᭶᭷᭸᭹᭺᭻᭼ᮀᮁᮂᮃᮄᮅᮆᮇᮈᮉᮊᮋᮌᮍᮎᮏᮐᮑᮒᮓᮔᮕᮖᮗᮘᮙᮚᮛᮜᮝᮞᮟᮠᮡᮢᮣᮤᮥᮦᮧᮨᮩ᮪᮫ᮬᮭᮮᮯ᮰᮱᮲᮳᮴᮵᮶᮷᮸᮹ᮺᮻᮼᮽᮾᮿᯀᯁᯂᯃᯄᯅᯆᯇᯈᯉᯊᯋᯌᯍᯎᯏᯐᯑᯒᯓᯔᯕᯖᯗᯘᯙᯚᯛᯜᯝᯞᯟᯠᯡᯢᯣᯤᯥ᯦ᯧᯨᯩᯪᯫᯬᯭᯮᯯᯰᯱ᯲᯳᯼᯽᯾᯿ᰀᰁᰂᰃᰄᰅᰆᰇᰈᰉᰊᰋᰌᰍᰎᰏᰐᰑᰒᰓᰔᰕᰖᰗᰘᰙᰚᰛᰜᰝᰞᰟᰠᰡᰢᰣᰤᰥᰦᰧᰨᰩᰪᰫᰬᰭᰮᰯᰰᰱᰲᰳᰴᰵᰶ᰷᰻᰼᰽᰾᰿᱀᱁᱂᱃᱄᱅᱆᱇᱈᱉ᱍᱎᱏ᱐᱑᱒᱓᱔᱕᱖᱗᱘᱙ᱚᱛᱜᱝᱞᱟᱠᱡᱢᱣᱤᱥᱦᱧᱨᱩᱪᱫᱬᱭᱮᱯᱰᱱᱲᱳᱴᱵᱶᱷᱸᱹᱺᱻᱼᱽ᱾᱿᳀᳁᳂᳃᳄᳅᳆᳇᳐᳑᳒᳓᳔᳕᳖᳗᳘᳙᳜᳝᳞᳟᳚᳛᳠᳡᳢᳣᳤᳥᳦᳧᳨ᳩᳪᳫᳬ᳭ᳮᳯᳰᳱᳲᳳ᳴ᳵᳶᴀᴁᴂᴃᴄᴅᴆᴇᴈᴉᴊᴋᴌᴍᴎᴏᴐᴑᴒᴓᴔᴕᴖᴗᴘᴙᴚᴛᴜᴝᴞᴟᴠᴡᴢᴣᴤᴥᴦᴧᴨᴩᴪᴫᴬᴭᴮᴯᴰᴱᴲᴳᴴᴵᴶᴷᴸᴹᴺᴻᴼᴽᴾᴿᵀᵁᵂᵃᵄᵅᵆᵇᵈᵉᵊᵋᵌᵍᵎᵏᵐᵑᵒᵓᵔᵕᵖᵗᵘᵙᵚᵛᵜᵝᵞᵟᵠᵡᵢᵣᵤᵥᵦᵧᵨᵩᵪᵫᵬᵭᵮᵯᵰᵱᵲᵳᵴᵵᵶᵷᵸᵹᵺᵻᵼᵽᵾᵿᶀᶁᶂᶃᶄᶅᶆᶇᶈᶉᶊᶋᶌᶍᶎᶏᶐᶑᶒᶓᶔᶕᶖᶗᶘᶙᶚᶛᶜᶝᶞᶟᶠᶡᶢᶣᶤᶥᶦᶧᶨᶩᶪᶫᶬᶭᶮᶯᶰᶱᶲᶳᶴᶵᶶᶷᶸᶹᶺᶻᶼᶽᶾᶿ᷐᷎᷂᷊᷏᷽᷿᷀᷁᷃᷄᷅᷆᷇᷈᷉᷋᷌᷑᷒ᷓᷔᷕᷖᷗᷘᷙᷚᷛᷜᷝᷞᷟᷠᷡᷢᷣᷤᷥᷦ᷾᷼᷍ḀḁḂḃḄḅḆḇḈḉḊḋḌḍḎḏḐḑḒḓḔḕḖḗḘḙḚḛḜḝḞḟḠḡḢḣḤḥḦḧḨḩḪḫḬḭḮḯḰḱḲḳḴḵḶḷḸḹḺḻḼḽḾḿṀṁṂṃṄṅṆṇṈṉṊṋṌṍṎṏṐṑṒṓṔṕṖṗṘṙṚṛṜṝṞṟṠṡṢṣṤṥṦṧṨṩṪṫṬṭṮṯṰṱṲṳṴṵṶṷṸṹṺṻṼṽṾṿẀẁẂẃẄẅẆẇẈẉẊẋẌẍẎẏẐẑẒẓẔẕẖẗẘẙẚẛẜẝẞẟẠạẢảẤấẦầẨẩẪẫẬậẮắẰằẲẳẴẵẶặẸẹẺẻẼẽẾếỀềỂểỄễỆệỈỉỊịỌọỎỏỐốỒồỔổỖỗỘộỚớỜờỞởỠỡỢợỤụỦủỨứỪừỬửỮữỰựỲỳỴỵỶỷỸỹỺỻỼỽỾỿἀἁἂἃἄἅἆἇἈἉἊἋἌἍἎἏἐἑἒἓἔἕἘἙἚἛἜἝἠἡἢἣἤἥἦἧἨἩἪἫἬἭἮἯἰἱἲἳἴἵἶἷἸἹἺἻἼἽἾἿὀὁὂὃὄὅὈὉὊὋὌὍὐὑὒὓὔὕὖὗὙὛὝὟὠὡὢὣὤὥὦὧὨὩὪὫὬὭὮὯὰάὲέὴήὶίὸόὺύὼώᾀᾁᾂᾃᾄᾅᾆᾇᾈᾉᾊᾋᾌᾍᾎᾏᾐᾑᾒᾓᾔᾕᾖᾗᾘᾙᾚᾛᾜᾝᾞᾟᾠᾡᾢᾣᾤᾥᾦᾧᾨᾩᾪᾫᾬᾭᾮᾯᾰᾱᾲᾳᾴᾶᾷᾸᾹᾺΆᾼ᾽ι᾿῀῁ῂῃῄῆῇῈΈῊΉῌ῍῎῏ῐῑῒΐῖῗῘῙῚΊ῝῞῟ῠῡῢΰῤῥῦῧῨῩῪΎῬ῭΅`ῲῳῴῶῷῸΌῺΏῼ´῾           ​‌‍‎‏‐‑‒–—―‖‗‘’‚‛“”„‟†‡•‣․‥…‧

‪‭‮ ‰‱′″‴‵‶‷‸‹›※‼‽‾‿⁀⁁⁂⁃⁄⁅⁆⁇⁈⁉⁊⁋⁌⁍⁎⁏⁐⁑⁒⁓⁔⁕⁖⁗⁘⁙⁚⁛⁜⁝⁞ ⁠⁡⁢⁣⁤⁰ⁱ⁴⁵⁶⁷⁸⁹⁺⁻⁼⁽⁾ⁿ₀₁₂₃₄₅₆₇₈₉₊₋₌₍₎ₐₑₒₓₔₕₖₗₘₙₚₛₜ₠₡₢₣₤₥₦₧₨₩₪₫€₭₮₯₰₱₲₳₴₵₶₷₸₹₺₻₼₽₾₿⃒⃓⃘⃙⃚⃐⃑⃔⃕⃖⃗⃛⃜⃝⃞⃟⃠⃡⃢⃣⃤⃥⃦⃪⃫⃨⃬⃭⃮⃯⃧⃩⃰℀℁ℂ℃℄℅℆ℇ℈℉ℊℋℌℍℎℏℐℑℒℓ℔ℕ№℗℘ℙℚℛℜℝ℞℟℠℡™℣ℤ℥Ω℧ℨ℩KÅℬℭ℮ℯℰℱℲℳℴℵℶℷℸℹ℺℻ℼℽℾℿ⅀⅁⅂⅃⅄ⅅⅆⅇⅈⅉ⅊⅋⅌⅍ⅎ⅏⅐⅑⅒⅓⅔⅕⅖⅗⅘⅙⅚⅛⅜⅝⅞⅟ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫⅬⅭⅮⅯⅰⅱⅲⅳⅴⅵⅶⅷⅸⅹⅺⅻⅼⅽⅾⅿↀↁↂↃↄↅↆↇↈ↉←↑→↓↔↕↖↗↘↙↚↛↜↝↞↟↠↡↢↣↤↥↦↧↨↩↪↫↬↭↮↯↰↱↲↳↴↵↶↷↸↹↺↻↼↽↾↿⇀⇁⇂⇃⇄⇅⇆⇇⇈⇉⇊⇋⇌⇍⇎⇏⇐⇑⇒⇓⇔⇕⇖⇗⇘⇙⇚⇛⇜⇝⇞⇟⇠⇡⇢⇣⇤⇥⇦⇧⇨⇩⇪⇫⇬⇭⇮⇯⇰⇱⇲⇳⇴⇵⇶⇷⇸⇹⇺⇻⇼⇽⇾⇿∀∁∂∃∄∅∆∇∈∉∊∋∌∍∎∏∐∑−∓∔∕∖∗∘∙√∛∜∝∞∟∠∡∢∣∤∥∦∧∨∩∪∫∬∭∮∯∰∱∲∳∴∵∶∷∸∹∺∻∼∽∾∿≀≁≂≃≄≅≆≇≈≉≊≋≌≍≎≏≐≑≒≓≔≕≖≗≘≙≚≛≜≝≞≟≠≡≢≣≤≥≦≧≨≩≪≫≬≭≮≯≰≱≲≳≴≵≶≷≸≹≺≻≼≽≾≿⊀⊁⊂⊃⊄⊅⊆⊇⊈⊉⊊⊋⊌⊍⊎⊏⊐⊑⊒⊓⊔⊕⊖⊗⊘⊙⊚⊛⊜⊝⊞⊟⊠⊡⊢⊣⊤⊥⊦⊧⊨⊩⊪⊫⊬⊭⊮⊯⊰⊱⊲⊳⊴⊵⊶⊷⊸⊹⊺⊻⊼⊽⊾⊿⋀⋁⋂⋃⋄⋅⋆⋇⋈⋉⋊⋋⋌⋍⋎⋏⋐⋑⋒⋓⋔⋕⋖⋗⋘⋙⋚⋛⋜⋝⋞⋟⋠⋡⋢⋣⋤⋥⋦⋧⋨⋩⋪⋫⋬⋭⋮⋯⋰⋱⋲⋳⋴⋵⋶⋷⋸⋹⋺⋻⋼⋽⋾⋿⌀⌁⌂⌃⌄⌅⌆⌇⌈⌉⌊⌋⌌⌍⌎⌏⌐⌑⌒⌓⌔⌕⌖⌗⌘⌙⌚⌛⌜⌝⌞⌟⌠⌡⌢⌣⌤⌥⌦⌧⌨〈〉⌫⌬⌭⌮⌯⌰⌱⌲⌳⌴⌵⌶⌷⌸⌹⌺⌻⌼⌽⌾⌿⍀⍁⍂⍃⍄⍅⍆⍇⍈⍉⍊⍋⍌⍍⍎⍏⍐⍑⍒⍓⍔⍕⍖⍗⍘⍙⍚⍛⍜⍝⍞⍟⍠⍡⍢⍣⍤⍥⍦⍧⍨⍩⍪⍫⍬⍭⍮⍯⍰⍱⍲⍳⍴⍵⍶⍷⍸⍹⍺⍻⍼⍽⍾⍿⎀⎁⎂⎃⎄⎅⎆⎇⎈⎉⎊⎋⎌⎍⎎⎏⎐⎑⎒⎓⎔⎕⎖⎗⎘⎙⎚⎛⎜⎝⎞⎟⎠⎡⎢⎣⎤⎥⎦⎧⎨⎩⎪⎫⎬⎭⎮⎯⎰⎱⎲⎳⎴⎵⎶⎷⎸⎹⎺⎻⎼⎽⎾⎿⏀⏁⏂⏃⏄⏅⏆⏇⏈⏉⏊⏋⏌⏍⏎⏏⏐⏑⏒⏓⏔⏕⏖⏗⏘⏙⏚⏛⏜⏝⏞⏟⏠⏡⏢⏣⏤⏥⏦⏧⏨⏩⏪⏫⏬⏭⏮⏯⏰⏱⏲⏳␀␁␂␃␄␅␆␇␈␉␊␋␌␍␎␏␐␑␒␓␔␕␖␗␘␙␚␛␜␝␞␟␠␡␢␣␤␥␦⑀⑁⑂⑃⑄⑅⑆⑇⑈⑉⑊①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳⑴⑵⑶⑷⑸⑹⑺⑻⑼⑽⑾⑿⒀⒁⒂⒃⒄⒅⒆⒇⒈⒉⒊⒋⒌⒍⒎⒏⒐⒑⒒⒓⒔⒕⒖⒗⒘⒙⒚⒛⒜⒝⒞⒟⒠⒡⒢⒣⒤⒥⒦⒧⒨⒩⒪⒫⒬⒭⒮⒯⒰⒱⒲⒳⒴⒵ⒶⒷⒸⒹⒺⒻⒼⒽⒾⒿⓀⓁⓂⓃⓄⓅⓆⓇⓈⓉⓊⓋⓌⓍⓎⓏⓐⓑⓒⓓⓔⓕⓖⓗⓘⓙⓚⓛⓜⓝⓞⓟⓠⓡⓢⓣⓤⓥⓦⓧⓨⓩ⓪⓫⓬⓭⓮⓯⓰⓱⓲⓳⓴⓵⓶⓷⓸⓹⓺⓻⓼⓽⓾⓿─━│┃┄┅┆┇┈┉┊┋┌┍┎┏┐┑┒┓└┕┖┗┘┙┚┛├┝┞┟┠┡┢┣┤┥┦┧┨┩┪┫┬┭┮┯┰┱┲┳┴┵┶┷┸┹┺┻┼┽┾┿╀╁╂╃╄╅╆╇╈╉╊╋╌╍╎╏═║╒╓╔╕╖╗╘╙╚╛╜╝╞╟╠╡╢╣╤╥╦╧╨╩╪╫╬╭╮╯╰╱╲╳╴╵╶╷╸╹╺╻╼╽╾╿▀▁▂▃▄▅▆▇█▉▊▋▌▍▎▏▐░▒▓▔▕▖▗▘▙▚▛▜▝▞▟■□▢▣▤▥▦▧▨▩▪▫▬▭▮▯▰▱▲△▴▵▶▷▸▹►▻▼▽▾▿◀◁◂◃◄◅◆◇◈◉◊○◌◍◎●◐◑◒◓◔◕◖◗◘◙◚◛◜◝◞◟◠◡◢◣◤◥◦◧◨◩◪◫◬◭◮◯◰◱◲◳◴◵◶◷◸◹◺◻◼◽◾◿☀☁☂☃☄★☆☇☈☉☊☋☌☍☎☏☐☑☒☓☔☕☖☗☘☙☚☛☜☝☞☟☠☡☢☣☤☥☦☧☨☩☪☫☬☭☮☯☰☱☲☳☴☵☶☷☸☹☺☻☼☽☾☿♀♁♂♃♄♅♆♇♈♉♊♋♌♍♎♏♐♑♒♓♔♕♖♗♘♙♚♛♜♝♞♟♠♡♢♣♤♥♦♧♨♩♪♫♬♭♮♯♰♱♲♳♴♵♶♷♸♹♺♻♼♽♾♿⚀⚁⚂⚃⚄⚅⚆⚇⚈⚉⚊⚋⚌⚍⚎⚏⚐⚑⚒⚓⚔⚕⚖⚗⚘⚙⚚⚛⚜⚝⚞⚟⚠⚡⚢⚣⚤⚥⚦⚧⚨⚩⚪⚫⚬⚭⚮⚯⚰⚱⚲⚳⚴⚵⚶⚷⚸⚹⚺⚻⚼⚽⚾⚿⛀⛁⛂⛃⛄⛅⛆⛇⛈⛉⛊⛋⛌⛍⛎⛏⛐⛑⛒⛓⛔⛕⛖⛗⛘⛙⛚⛛⛜⛝⛞⛟⛠⛡⛢⛣⛤⛥⛦⛧⛨⛩⛪⛫⛬⛭⛮⛯⛰⛱⛲⛳⛴⛵⛶⛷⛸⛹⛺⛻⛼⛽⛾⛿✁✂✃✄✅✆✇✈✉✊✋✌✍✎✏✐✑✒✓✔✕✖✗✘✙✚✛✜✝✞✟✠✡✢✣✤✥✦✧✨✩✪✫✬✭✮✯✰✱✲✳✴✵✶✷✸✹✺✻✼✽✾✿❀❁❂❃❄❅❆❇❈❉❊❋❌❍❎❏❐❑❒❓❔❕❖❗❘❙❚❛❜❝❞❟❠❡❢❣❤❥❦❧❨❩❪❫❬❭❮❯❰❱❲❳❴❵❶❷❸❹❺❻❼❽❾❿➀➁➂➃➄➅➆➇➈➉➊➋➌➍➎➏➐➑➒➓➔➕➖➗➘➙➚➛➜➝➞➟➠➡➢➣➤➥➦➧➨➩➪➫➬➭➮➯➰➱➲➳➴➵➶➷➸➹➺➻➼➽➾➿⟀⟁⟂⟃⟄⟅⟆⟇⟈⟉⟊⟋⟌⟍⟎⟏⟐⟑⟒⟓⟔⟕⟖⟗⟘⟙⟚⟛⟜⟝⟞⟟⟠⟡⟢⟣⟤⟥⟦⟧⟨⟩⟪⟫⟬⟭⟮⟯⟰⟱⟲⟳⟴⟵⟶⟷⟸⟹⟺⟻⟼⟽⟾⟿⠀⠁⠂⠃⠄⠅⠆⠇⠈⠉⠊⠋⠌⠍⠎⠏⠐⠑⠒⠓⠔⠕⠖⠗⠘⠙⠚⠛⠜⠝⠞⠟⠠⠡⠢⠣⠤⠥⠦⠧⠨⠩⠪⠫⠬⠭⠮⠯⠰⠱⠲⠳⠴⠵⠶⠷⠸⠹⠺⠻⠼⠽⠾⠿⡀⡁⡂⡃⡄⡅⡆⡇⡈⡉⡊⡋⡌⡍⡎⡏⡐⡑⡒⡓⡔⡕⡖⡗⡘⡙⡚⡛⡜⡝⡞⡟⡠⡡⡢⡣⡤⡥⡦⡧⡨⡩⡪⡫⡬⡭⡮⡯⡰⡱⡲⡳⡴⡵⡶⡷⡸⡹⡺⡻⡼⡽⡾⡿⢀⢁⢂⢃⢄⢅⢆⢇⢈⢉⢊⢋⢌⢍⢎⢏⢐⢑⢒⢓⢔⢕⢖⢗⢘⢙⢚⢛⢜⢝⢞⢟⢠⢡⢢⢣⢤⢥⢦⢧⢨⢩⢪⢫⢬⢭⢮⢯⢰⢱⢲⢳⢴⢵⢶⢷⢸⢹⢺⢻⢼⢽⢾⢿⣀⣁⣂⣃⣄⣅⣆⣇⣈⣉⣊⣋⣌⣍⣎⣏⣐⣑⣒⣓⣔⣕⣖⣗⣘⣙⣚⣛⣜⣝⣞⣟⣠⣡⣢⣣⣤⣥⣦⣧⣨⣩⣪⣫⣬⣭⣮⣯⣰⣱⣲⣳⣴⣵⣶⣷⣸⣹⣺⣻⣼⣽⣾⣿⤀⤁⤂⤃⤄⤅⤆⤇⤈⤉⤊⤋⤌⤍⤎⤏⤐⤑⤒⤓⤔⤕⤖⤗⤘⤙⤚⤛⤜⤝⤞⤟⤠⤡⤢⤣⤤⤥⤦⤧⤨⤩⤪⤫⤬⤭⤮⤯⤰⤱⤲⤳⤴⤵⤶⤷⤸⤹⤺⤻⤼⤽⤾⤿⥀⥁⥂⥃⥄⥅⥆⥇⥈⥉⥊⥋⥌⥍⥎⥏⥐⥑⥒⥓⥔⥕⥖⥗⥘⥙⥚⥛⥜⥝⥞⥟⥠⥡⥢⥣⥤⥥⥦⥧⥨⥩⥪⥫⥬⥭⥮⥯⥰⥱⥲⥳⥴⥵⥶⥷⥸⥹⥺⥻⥼⥽⥾⥿⦀⦁⦂⦃⦄⦅⦆⦇⦈⦉⦊⦋⦌⦍⦎⦏⦐⦑⦒⦓⦔⦕⦖⦗⦘⦙⦚⦛⦜⦝⦞⦟⦠⦡⦢⦣⦤⦥⦦⦧⦨⦩⦪⦫⦬⦭⦮⦯⦰⦱⦲⦳⦴⦵⦶⦷⦸⦹⦺⦻⦼⦽⦾⦿⧀⧁⧂⧃⧄⧅⧆⧇⧈⧉⧊⧋⧌⧍⧎⧏⧐⧑⧒⧓⧔⧕⧖⧗⧘⧙⧚⧛⧜⧝⧞⧟⧠⧡⧢⧣⧤⧥⧦⧧⧨⧩⧪⧫⧬⧭⧮⧯⧰⧱⧲⧳⧴⧵⧶⧷⧸⧹⧺⧻⧼⧽⧾⧿⨀⨁⨂⨃⨄⨅⨆⨇⨈⨉⨊⨋⨌⨍⨎⨏⨐⨑⨒⨓⨔⨕⨖⨗⨘⨙⨚⨛⨜⨝⨞⨟⨠⨡⨢⨣⨤⨥⨦⨧⨨⨩⨪⨫⨬⨭⨮⨯⨰⨱⨲⨳⨴⨵⨶⨷⨸⨹⨺⨻⨼⨽⨾⨿⩀⩁⩂⩃⩄⩅⩆⩇⩈⩉⩊⩋⩌⩍⩎⩏⩐⩑⩒⩓⩔⩕⩖⩗⩘⩙⩚⩛⩜⩝⩞⩟⩠⩡⩢⩣⩤⩥⩦⩧⩨⩩⩪⩫⩬⩭⩮⩯⩰⩱⩲⩳⩴⩵⩶⩷⩸⩹⩺⩻⩼⩽⩾⩿⪀⪁⪂⪃⪄⪅⪆⪇⪈⪉⪊⪋⪌⪍⪎⪏⪐⪑⪒⪓⪔⪕⪖⪗⪘⪙⪚⪛⪜⪝⪞⪟⪠⪡⪢⪣⪤⪥⪦⪧⪨⪩⪪⪫⪬⪭⪮⪯⪰⪱⪲⪳⪴⪵⪶⪷⪸⪹⪺⪻⪼⪽⪾⪿⫀⫁⫂⫃⫄⫅⫆⫇⫈⫉⫊⫋⫌⫍⫎⫏⫐⫑⫒⫓⫔⫕⫖⫗⫘⫙⫚⫛⫝̸⫝⫞⫟⫠⫡⫢⫣⫤⫥⫦⫧⫨⫩⫪⫫⫬⫭⫮⫯⫰⫱⫲⫳⫴⫵⫶⫷⫸⫹⫺⫻⫼⫽⫾⫿⬀⬁⬂⬃⬄⬅⬆⬇⬈⬉⬊⬋⬌⬍⬎⬏⬐⬑⬒⬓⬔⬕⬖⬗⬘⬙⬚⬛⬜⬝⬞⬟⬠⬡⬢⬣⬤⬥⬦⬧⬨⬩⬪⬫⬬⬭⬮⬯⬰⬱⬲⬳⬴⬵⬶⬷⬸⬹⬺⬻⬼⬽⬾⬿⭀⭁⭂⭃⭄⭅⭆⭇⭈⭉⭊⭋⭌⭐⭑⭒⭓⭔⭕⭖⭗⭘⭙ⰀⰁⰂⰃⰄⰅⰆⰇⰈⰉⰊⰋⰌⰍⰎⰏⰐⰑⰒⰓⰔⰕⰖⰗⰘⰙⰚⰛⰜⰝⰞⰟⰠⰡⰢⰣⰤⰥⰦⰧⰨⰩⰪⰫⰬⰭⰮⰰⰱⰲⰳⰴⰵⰶⰷⰸⰹⰺⰻⰼⰽⰾⰿⱀⱁⱂⱃⱄⱅⱆⱇⱈⱉⱊⱋⱌⱍⱎⱏⱐⱑⱒⱓⱔⱕⱖⱗⱘⱙⱚⱛⱜⱝⱞⱠⱡⱢⱣⱤⱥⱦⱧⱨⱩⱪⱫⱬⱭⱮⱯⱰⱱⱲⱳⱴⱵⱶⱷⱸⱹⱺⱻⱼⱽⱾⱿⲀⲁⲂⲃⲄⲅⲆⲇⲈⲉⲊⲋⲌⲍⲎⲏⲐⲑⲒⲓⲔⲕⲖⲗⲘⲙⲚⲛⲜⲝⲞⲟⲠⲡⲢⲣⲤⲥⲦⲧⲨⲩⲪⲫⲬⲭⲮⲯⲰⲱⲲⲳⲴⲵⲶⲷⲸⲹⲺⲻⲼⲽⲾⲿⳀⳁⳂⳃⳄⳅⳆⳇⳈⳉⳊⳋⳌⳍⳎⳏⳐⳑⳒⳓⳔⳕⳖⳗⳘⳙⳚⳛⳜⳝⳞⳟⳠⳡⳢⳣⳤ⳥⳦⳧⳨⳩⳪ⳫⳬⳭⳮ⳯⳰⳱Ⳳⳳ⳹⳺⳻⳼⳽⳾⳿ⴀⴁⴂⴃⴄⴅⴆⴇⴈⴉⴊⴋⴌⴍⴎⴏⴐⴑⴒⴓⴔⴕⴖⴗⴘⴙⴚⴛⴜⴝⴞⴟⴠⴡⴢⴣⴤⴥⴧⴭⴰⴱⴲⴳⴴⴵⴶⴷⴸⴹⴺⴻⴼⴽⴾⴿⵀⵁⵂⵃⵄⵅⵆⵇⵈⵉⵊⵋⵌⵍⵎⵏⵐⵑⵒⵓⵔⵕⵖⵗⵘⵙⵚⵛⵜⵝⵞⵟⵠⵡⵢⵣⵤⵥⵦⵧⵯ⵰⵿ⶀⶁⶂⶃⶄⶅⶆⶇⶈⶉⶊⶋⶌⶍⶎⶏⶐⶑⶒⶓⶔⶕⶖⶠⶡⶢⶣⶤⶥⶦⶨⶩⶪⶫⶬⶭⶮⶰⶱⶲⶳⶴⶵⶶⶸⶹⶺⶻⶼⶽⶾⷀⷁⷂⷃⷄⷅⷆⷈⷉⷊⷋⷌⷍⷎⷐⷑⷒⷓⷔⷕⷖⷘⷙⷚⷛⷜⷝⷞⷠⷡⷢⷣⷤⷥⷦⷧⷨⷩⷪⷫⷬⷭⷮⷯⷰⷱⷲⷳⷴⷵⷶⷷⷸⷹⷺⷻⷼⷽⷾⷿ⸀⸁⸂⸃⸄⸅⸆⸇⸈⸉⸊⸋⸌⸍⸎⸏⸐⸑⸒⸓⸔⸕⸖⸗⸘⸙⸚⸛⸜⸝⸞⸟⸠⸡⸢⸣⸤⸥⸦⸧⸨⸩⸪⸫⸬⸭⸮ⸯ⸰⸱⸲⸳⸴⸵⸶⸷⸸⸹⸺⸻⺀⺁⺂⺃⺄⺅⺆⺇⺈⺉⺊⺋⺌⺍⺎⺏⺐⺑⺒⺓⺔⺕⺖⺗⺘⺙⺛⺜⺝⺞⺟⺠⺡⺢⺣⺤⺥⺦⺧⺨⺩⺪⺫⺬⺭⺮⺯⺰⺱⺲⺳⺴⺵⺶⺷⺸⺹⺺⺻⺼⺽⺾⺿⻀⻁⻂⻃⻄⻅⻆⻇⻈⻉⻊⻋⻌⻍⻎⻏⻐⻑⻒⻓⻔⻕⻖⻗⻘⻙⻚⻛⻜⻝⻞⻟⻠⻡⻢⻣⻤⻥⻦⻧⻨⻩⻪⻫⻬⻭⻮⻯⻰⻱⻲⻳⼀⼁⼂⼃⼄⼅⼆⼇⼈⼉⼊⼋⼌⼍⼎⼏⼐⼑⼒⼓⼔⼕⼖⼗⼘⼙⼚⼛⼜⼝⼞⼟⼠⼡⼢⼣⼤⼥⼦⼧⼨⼩⼪⼫⼬⼭⼮⼯⼰⼱⼲⼳⼴⼵⼶⼷⼸⼹⼺⼻⼼⼽⼾⼿⽀⽁⽂⽃⽄⽅⽆⽇⽈⽉⽊⽋⽌⽍⽎⽏⽐⽑⽒⽓⽔⽕⽖⽗⽘⽙⽚⽛⽜⽝⽞⽟⽠⽡⽢⽣⽤⽥⽦⽧⽨⽩⽪⽫⽬⽭⽮⽯⽰⽱⽲⽳⽴⽵⽶⽷⽸⽹⽺⽻⽼⽽⽾⽿⾀⾁⾂⾃⾄⾅⾆⾇⾈⾉⾊⾋⾌⾍⾎⾏⾐⾑⾒⾓⾔⾕⾖⾗⾘⾙⾚⾛⾜⾝⾞⾟⾠⾡⾢⾣⾤⾥⾦⾧⾨⾩⾪⾫⾬⾭⾮⾯⾰⾱⾲⾳⾴⾵⾶⾷⾸⾹⾺⾻⾼⾽⾾⾿⿀⿁⿂⿃⿄⿅⿆⿇⿈⿉⿊⿋⿌⿍⿎⿏⿐⿑⿒⿓⿔⿕⿰⿱⿲⿳⿴⿵⿶⿷⿸⿹⿺⿻ 、。〃〄々〆〇〈〉《》「」『』【】〒〓〔〕〖〗〘〙〚〛〜〝〞〟〠〡〢〣〤〥〦〧〨〩〪〭〮〯〫〬〰〱〲〳〴〵〶〷〸〹〺〻〼〽〾〿ぁあぃいぅうぇえぉおかがきぎくぐけげこごさざしじすずせぜそぞただちぢっつづてでとどなにぬねのはばぱひびぴふぶぷへべぺほぼぽまみむめもゃやゅゆょよらりるれろゎわゐゑをんゔゕゖ゙゚゛゜ゝゞゟ゠ァアィイゥウェエォオカガキギクグケゲコゴサザシジスズセゼソゾタダチヂッツヅテデトドナニヌネノハバパヒビピフブプヘベペホボポマミムメモャヤュユョヨラリルレロヮワヰヱヲンヴヵヶヷヸヹヺ・ーヽヾヿㄅㄆㄇㄈㄉㄊㄋㄌㄍㄎㄏㄐㄑㄒㄓㄔㄕㄖㄗㄘㄙㄚㄛㄜㄝㄞㄟㄠㄡㄢㄣㄤㄥㄦㄧㄨㄩㄪㄫㄬㄭㄱㄲㄳㄴㄵㄶㄷㄸㄹㄺㄻㄼㄽㄾㄿㅀㅁㅂㅃㅄㅅㅆㅇㅈㅉㅊㅋㅌㅍㅎㅏㅐㅑㅒㅓㅔㅕㅖㅗㅘㅙㅚㅛㅜㅝㅞㅟㅠㅡㅢㅣㅤㅥㅦㅧㅨㅩㅪㅫㅬㅭㅮㅯㅰㅱㅲㅳㅴㅵㅶㅷㅸㅹㅺㅻㅼㅽㅾㅿㆀㆁㆂㆃㆄㆅㆆㆇㆈㆉㆊㆋㆌㆍㆎ㆐㆑㆒㆓㆔㆕㆖㆗㆘㆙㆚㆛㆜㆝㆞㆟ㆠㆡㆢㆣㆤㆥㆦㆧㆨㆩㆪㆫㆬㆭㆮㆯㆰㆱㆲㆳㆴㆵㆶㆷㆸㆹㆺ㇀㇁㇂㇃㇄㇅㇆㇇㇈㇉㇊㇋㇌㇍㇎㇏㇐㇑㇒㇓㇔㇕㇖㇗㇘㇙㇚㇛㇜㇝㇞㇟㇠㇡㇢㇣ㇰㇱㇲㇳㇴㇵㇶㇷㇸㇹㇺㇻㇼㇽㇾㇿ㈀㈁㈂㈃㈄㈅㈆㈇㈈㈉㈊㈋㈌㈍㈎㈏㈐㈑㈒㈓㈔㈕㈖㈗㈘㈙㈚㈛㈜㈝㈞㈠㈡㈢㈣㈤㈥㈦㈧㈨㈩㈪㈫㈬㈭㈮㈯㈰㈱㈲㈳㈴㈵㈶㈷㈸㈹㈺㈻㈼㈽㈾㈿㉀㉁㉂㉃㉄㉅㉆㉇㉈㉉㉊㉋㉌㉍㉎㉏㉐㉑㉒㉓㉔㉕㉖㉗㉘㉙㉚㉛㉜㉝㉞㉟㉠㉡㉢㉣㉤㉥㉦㉧㉨㉩㉪㉫㉬㉭㉮㉯㉰㉱㉲㉳㉴㉵㉶㉷㉸㉹㉺㉻㉼㉽㉾㉿㊀㊁㊂㊃㊄㊅㊆㊇㊈㊉㊊㊋㊌㊍㊎㊏㊐㊑㊒㊓㊔㊕㊖㊗㊘㊙㊚㊛㊜㊝㊞㊟㊠㊡㊢㊣㊤㊥㊦㊧㊨㊩㊪㊫㊬㊭㊮㊯㊰㊱㊲㊳㊴㊵㊶㊷㊸㊹㊺㊻㊼㊽㊾㊿㋀㋁㋂㋃㋄㋅㋆㋇㋈㋉㋊㋋㋌㋍㋎㋏㋐㋑㋒㋓㋔㋕㋖㋗㋘㋙㋚㋛㋜㋝㋞㋟㋠㋡㋢㋣㋤㋥㋦㋧㋨㋩㋪㋫㋬㋭㋮㋯㋰㋱㋲㋳㋴㋵㋶㋷㋸㋹㋺㋻㋼㋽㋾㋿㌀㌁㌂㌃㌄㌅㌆㌇㌈㌉㌊㌋㌌㌍㌎㌏㌐㌑㌒㌓㌔㌕㌖㌗㌘㌙㌚㌛㌜㌝㌞㌟㌠㌡㌢㌣㌤㌥㌦㌧㌨㌩㌪㌫㌬㌭㌮㌯㌰㌱㌲㌳㌴㌵㌶㌷㌸㌹㌺㌻㌼㌽㌾㌿㍀㍁㍂㍃㍄㍅㍆㍇㍈㍉㍊㍋㍌㍍㍎㍏㍐㍑㍒㍓㍔㍕㍖㍗㍘㍙㍚㍛㍜㍝㍞㍟㍠㍡㍢㍣㍤㍥㍦㍧㍨㍩㍪㍫㍬㍭㍮㍯㍰㍱㍲㍳㍴㍵㍶㍷㍸㍹㍺㍻㍼㍽㍾㍿㎀㎁㎂㎃㎄㎅㎆㎇㎈㎉㎊㎋㎌㎍㎎㎏㎐㎑㎒㎓㎔㎕㎖㎗㎘㎙㎚㎛㎜㎝㎞㎟㎠㎡㎢㎣㎤㎥㎦㎧㎨㎩㎪㎫㎬㎭㎮㎯㎰㎱㎲㎳㎴㎵㎶㎷㎸㎹㎺㎻㎼㎽㎾㎿㏀㏁㏂㏃㏄㏅㏆㏇㏈㏉㏊㏋㏌㏍㏎㏏㏐㏑㏒㏓㏔㏕㏖㏗㏘㏙㏚㏛㏜㏝㏞㏟㏠㏡㏢㏣㏤㏥㏦㏧㏨㏩㏪㏫㏬㏭㏮㏯㏰㏱㏲㏳㏴㏵㏶㏷㏸㏹㏺㏻㏼㏽㏾㏿㐀㐁㐂㐃㐄㐅㐆㐇㐈㐉㐊㐋㐌㐍㐎㐏㐐㐑㐒㐓㐔㐕㐖㐗㐘㐙㐚㐛㐜㐝㐞㐟㐠㐡㐢㐣㐤㐥㐦㐧㐨㐩㐪㐫㐬㐭㐮㐯㐰㐱㐲㐳㐴㐵㐶㐷㐸㐹㐺㐻㐼㐽㐾㐿㑀㑁㑂㑃㑄㑅㑆㑇㑈㑉㑊㑋㑌㑍㑎㑏㑐㑑㑒㑓㑔㑕㑖㑗㑘㑙㑚㑛㑜㑝㑞㑟㑠㑡㑢㑣㑤㑥㑦㑧㑨㑩㑪㑫㑬㑭㑮㑯㑰㑱㑲㑳㑴㑵㑶㑷㑸㑹㑺㑻㑼㑽㑾㑿㒀㒁㒂㒃㒄㒅㒆㒇㒈㒉㒊㒋㒌㒍㒎㒏㒐㒑㒒㒓㒔㒕㒖㒗㒘㒙㒚㒛㒜㒝㒞㒟㒠㒡㒢㒣㒤㒥㒦㒧㒨㒩㒪㒫㒬㒭㒮㒯㒰㒱㒲㒳㒴㒵㒶㒷㒸㒹㒺㒻㒼㒽㒾㒿㓀㓁㓂㓃㓄㓅㓆㓇㓈㓉㓊㓋㓌㓍㓎㓏㓐㓑㓒㓓㓔㓕㓖㓗㓘㓙㓚㓛㓜㓝㓞㓟㓠㓡㓢㓣㓤㓥㓦㓧㓨㓩㓪㓫㓬㓭㓮㓯㓰㓱㓲㓳㓴㓵㓶㓷㓸㓹㓺㓻㓼㓽㓾㓿㔀㔁㔂㔃㔄㔅㔆㔇㔈㔉㔊㔋㔌㔍㔎㔏㔐㔑㔒㔓㔔㔕㔖㔗㔘㔙㔚㔛㔜㔝㔞㔟㔠㔡㔢㔣㔤㔥㔦㔧㔨㔩㔪㔫㔬㔭㔮㔯㔰㔱㔲㔳㔴㔵㔶㔷㔸㔹㔺㔻㔼㔽㔾㔿㕀㕁㕂㕃㕄㕅㕆㕇㕈㕉㕊㕋㕌㕍㕎㕏㕐㕑㕒㕓㕔㕕㕖㕗㕘㕙㕚㕛㕜㕝㕞㕟㕠㕡㕢㕣㕤㕥㕦㕧㕨㕩㕪㕫㕬㕭㕮㕯㕰㕱㕲㕳㕴㕵㕶㕷㕸㕹㕺㕻㕼㕽㕾㕿㖀㖁㖂㖃㖄㖅㖆㖇㖈㖉㖊㖋㖌㖍㖎㖏㖐㖑㖒㖓㖔㖕㖖㖗㖘㖙㖚㖛㖜㖝㖞㖟㖠㖡㖢㖣㖤㖥㖦㖧㖨㖩㖪㖫㖬㖭㖮㖯㖰㖱㖲㖳㖴㖵㖶㖷㖸㖹㖺㖻㖼㖽㖾㖿㗀㗁㗂㗃㗄㗅㗆㗇㗈㗉㗊㗋㗌㗍㗎㗏㗐㗑㗒㗓㗔㗕㗖㗗㗘㗙㗚㗛㗜㗝㗞㗟㗠㗡㗢㗣㗤㗥㗦㗧㗨㗩㗪㗫㗬㗭㗮㗯㗰㗱㗲㗳㗴㗵㗶㗷㗸㗹㗺㗻㗼㗽㗾㗿㘀㘁㘂㘃㘄㘅㘆㘇㘈㘉㘊㘋㘌㘍㘎㘏㘐㘑㘒㘓㘔㘕㘖㘗㘘㘙㘚㘛㘜㘝㘞㘟㘠㘡㘢㘣㘤㘥㘦㘧㘨㘩㘪㘫㘬㘭㘮㘯㘰㘱㘲㘳㘴㘵㘶㘷㘸㘹㘺㘻㘼㘽㘾㘿㙀㙁㙂㙃㙄㙅㙆㙇㙈㙉㙊㙋㙌㙍㙎㙏㙐㙑㙒㙓㙔㙕㙖㙗㙘㙙㙚㙛㙜㙝㙞㙟㙠㙡㙢㙣㙤㙥㙦㙧㙨㙩㙪㙫㙬㙭㙮㙯㙰㙱㙲㙳㙴㙵㙶㙷㙸㙹㙺㙻㙼㙽㙾㙿㚀㚁㚂㚃㚄㚅㚆㚇㚈㚉㚊㚋㚌㚍㚎㚏㚐㚑㚒㚓㚔㚕㚖㚗㚘㚙㚚㚛㚜㚝㚞㚟㚠㚡㚢㚣㚤㚥㚦㚧㚨㚩㚪㚫㚬㚭㚮㚯㚰㚱㚲㚳㚴㚵㚶㚷㚸㚹㚺㚻㚼㚽㚾㚿㛀㛁㛂㛃㛄㛅㛆㛇㛈㛉㛊㛋㛌㛍㛎㛏㛐㛑㛒㛓㛔㛕㛖㛗㛘㛙㛚㛛㛜㛝㛞㛟㛠㛡㛢㛣㛤㛥㛦㛧㛨㛩㛪㛫㛬㛭㛮㛯㛰㛱㛲㛳㛴㛵㛶㛷㛸㛹㛺㛻㛼㛽㛾㛿㜀㜁㜂㜃㜄㜅㜆㜇㜈㜉㜊㜋㜌㜍㜎㜏㜐㜑㜒㜓㜔㜕㜖㜗㜘㜙㜚㜛㜜㜝㜞㜟㜠㜡㜢㜣㜤㜥㜦㜧㜨㜩㜪㜫㜬㜭㜮㜯㜰㜱㜲㜳㜴㜵㜶㜷㜸㜹㜺㜻㜼㜽㜾㜿㝀㝁㝂㝃㝄㝅㝆㝇㝈㝉㝊㝋㝌㝍㝎㝏㝐㝑㝒㝓㝔㝕㝖㝗㝘㝙㝚㝛㝜㝝㝞㝟㝠㝡㝢㝣㝤㝥㝦㝧㝨㝩㝪㝫㝬㝭㝮㝯㝰㝱㝲㝳㝴㝵㝶㝷㝸㝹㝺㝻㝼㝽㝾㝿㞀㞁㞂㞃㞄㞅㞆㞇㞈㞉㞊㞋㞌㞍㞎㞏㞐㞑㞒㞓㞔㞕㞖㞗㞘㞙㞚㞛㞜㞝㞞㞟㞠㞡㞢㞣㞤㞥㞦㞧㞨㞩㞪㞫㞬㞭㞮㞯㞰㞱㞲㞳㞴㞵㞶㞷㞸㞹㞺㞻㞼㞽㞾㞿㟀㟁㟂㟃㟄㟅㟆㟇㟈㟉㟊㟋㟌㟍㟎㟏㟐㟑㟒㟓㟔㟕㟖㟗㟘㟙㟚㟛㟜㟝㟞㟟㟠㟡㟢㟣㟤㟥㟦㟧㟨㟩㟪㟫㟬㟭㟮㟯㟰㟱㟲㟳㟴㟵㟶㟷㟸㟹㟺㟻㟼㟽㟾㟿㠀㠁㠂㠃㠄㠅㠆㠇㠈㠉㠊㠋㠌㠍㠎㠏㠐㠑㠒㠓㠔㠕㠖㠗㠘㠙㠚㠛㠜㠝㠞㠟㠠㠡㠢㠣㠤㠥㠦㠧㠨㠩㠪㠫㠬㠭㠮㠯㠰㠱㠲㠳㠴㠵㠶㠷㠸㠹㠺㠻㠼㠽㠾㠿㡀㡁㡂㡃㡄㡅㡆㡇㡈㡉㡊㡋㡌㡍㡎㡏㡐㡑㡒㡓㡔㡕㡖㡗㡘㡙㡚㡛㡜㡝㡞㡟㡠㡡㡢㡣㡤㡥㡦㡧㡨㡩㡪㡫㡬㡭㡮㡯㡰㡱㡲㡳㡴㡵㡶㡷㡸㡹㡺㡻㡼㡽㡾㡿㢀㢁㢂㢃㢄㢅㢆㢇㢈㢉㢊㢋㢌㢍㢎㢏㢐㢑㢒㢓㢔㢕㢖㢗㢘㢙㢚㢛㢜㢝㢞㢟㢠㢡㢢㢣㢤㢥㢦㢧㢨㢩㢪㢫㢬㢭㢮㢯㢰㢱㢲㢳㢴㢵㢶㢷㢸㢹㢺㢻㢼㢽㢾㢿㣀㣁㣂㣃㣄㣅㣆㣇㣈㣉㣊㣋㣌㣍㣎㣏㣐㣑㣒㣓㣔㣕㣖㣗㣘㣙㣚㣛㣜㣝㣞㣟㣠㣡㣢㣣㣤㣥㣦㣧㣨㣩㣪㣫㣬㣭㣮㣯㣰㣱㣲㣳㣴㣵㣶㣷㣸㣹㣺㣻㣼㣽㣾㣿㤀㤁㤂㤃㤄㤅㤆㤇㤈㤉㤊㤋㤌㤍㤎㤏㤐㤑㤒㤓㤔㤕㤖㤗㤘㤙㤚㤛㤜㤝㤞㤟㤠㤡㤢㤣㤤㤥㤦㤧㤨㤩㤪㤫㤬㤭㤮㤯㤰㤱㤲㤳㤴㤵㤶㤷㤸㤹㤺㤻㤼㤽㤾㤿㥀㥁㥂㥃㥄㥅㥆㥇㥈㥉㥊㥋㥌㥍㥎㥏㥐㥑㥒㥓㥔㥕㥖㥗㥘㥙㥚㥛㥜㥝㥞㥟㥠㥡㥢㥣㥤㥥㥦㥧㥨㥩㥪㥫㥬㥭㥮㥯㥰㥱㥲㥳㥴㥵㥶㥷㥸㥹㥺㥻㥼㥽㥾㥿㦀㦁㦂㦃㦄㦅㦆㦇㦈㦉㦊㦋㦌㦍㦎㦏㦐㦑㦒㦓㦔㦕㦖㦗㦘㦙㦚㦛㦜㦝㦞㦟㦠㦡㦢㦣㦤㦥㦦㦧㦨㦩㦪㦫㦬㦭㦮㦯㦰㦱㦲㦳㦴㦵㦶㦷㦸㦹㦺㦻㦼㦽㦾㦿㧀㧁㧂㧃㧄㧅㧆㧇㧈㧉㧊㧋㧌㧍㧎㧏㧐㧑㧒㧓㧔㧕㧖㧗㧘㧙㧚㧛㧜㧝㧞㧟㧠㧡㧢㧣㧤㧥㧦㧧㧨㧩㧪㧫㧬㧭㧮㧯㧰㧱㧲㧳㧴㧵㧶㧷㧸㧹㧺㧻㧼㧽㧾㧿㨀㨁㨂㨃㨄㨅㨆㨇㨈㨉㨊㨋㨌㨍㨎㨏㨐㨑㨒㨓㨔㨕㨖㨗㨘㨙㨚㨛㨜㨝㨞㨟㨠㨡㨢㨣㨤㨥㨦㨧㨨㨩㨪㨫㨬㨭㨮㨯㨰㨱㨲㨳㨴㨵㨶㨷㨸㨹㨺㨻㨼㨽㨾㨿㩀㩁㩂㩃㩄㩅㩆㩇㩈㩉㩊㩋㩌㩍㩎㩏㩐㩑㩒㩓㩔㩕㩖㩗㩘㩙㩚㩛㩜㩝㩞㩟㩠㩡㩢㩣㩤㩥㩦㩧㩨㩩㩪㩫㩬㩭㩮㩯㩰㩱㩲㩳㩴㩵㩶㩷㩸㩹㩺㩻㩼㩽㩾㩿㪀㪁㪂㪃㪄㪅㪆㪇㪈㪉㪊㪋㪌㪍㪎㪏㪐㪑㪒㪓㪔㪕㪖㪗㪘㪙㪚㪛㪜㪝㪞㪟㪠㪡㪢㪣㪤㪥㪦㪧㪨㪩㪪㪫㪬㪭㪮㪯㪰㪱㪲㪳㪴㪵㪶㪷㪸㪹㪺㪻㪼㪽㪾㪿㫀㫁㫂㫃㫄㫅㫆㫇㫈㫉㫊㫋㫌㫍㫎㫏㫐㫑㫒㫓㫔㫕㫖㫗㫘㫙㫚㫛㫜㫝㫞㫟㫠㫡㫢㫣㫤㫥㫦㫧㫨㫩㫪㫫㫬㫭㫮㫯㫰㫱㫲㫳㫴㫵㫶㫷㫸㫹㫺㫻㫼㫽㫾㫿㬀㬁㬂㬃㬄㬅㬆㬇㬈㬉㬊㬋㬌㬍㬎㬏㬐㬑㬒㬓㬔㬕㬖㬗㬘㬙㬚㬛㬜㬝㬞㬟㬠㬡㬢㬣㬤㬥㬦㬧㬨㬩㬪㬫㬬㬭㬮㬯㬰㬱㬲㬳㬴㬵㬶㬷㬸㬹㬺㬻㬼㬽㬾㬿㭀㭁㭂㭃㭄㭅㭆㭇㭈㭉㭊㭋㭌㭍㭎㭏㭐㭑㭒㭓㭔㭕㭖㭗㭘㭙㭚㭛㭜㭝㭞㭟㭠㭡㭢㭣㭤㭥㭦㭧㭨㭩㭪㭫㭬㭭㭮㭯㭰㭱㭲㭳㭴㭵㭶㭷㭸㭹㭺㭻㭼㭽㭾㭿㮀㮁㮂㮃㮄㮅㮆㮇㮈㮉㮊㮋㮌㮍㮎㮏㮐㮑㮒㮓㮔㮕㮖㮗㮘㮙㮚㮛㮜㮝㮞㮟㮠㮡㮢㮣㮤㮥㮦㮧㮨㮩㮪㮫㮬㮭㮮㮯㮰㮱㮲㮳㮴㮵㮶㮷㮸㮹㮺㮻㮼㮽㮾㮿㯀㯁㯂㯃㯄㯅㯆㯇㯈㯉㯊㯋㯌㯍㯎㯏㯐㯑㯒㯓㯔㯕㯖㯗㯘㯙㯚㯛㯜㯝㯞㯟㯠㯡㯢㯣㯤㯥㯦㯧㯨㯩㯪㯫㯬㯭㯮㯯㯰㯱㯲㯳㯴㯵㯶㯷㯸㯹㯺㯻㯼㯽㯾㯿㰀㰁㰂㰃㰄㰅㰆㰇㰈㰉㰊㰋㰌㰍㰎㰏㰐㰑㰒㰓㰔㰕㰖㰗㰘㰙㰚㰛㰜㰝㰞㰟㰠㰡㰢㰣㰤㰥㰦㰧㰨㰩㰪㰫㰬㰭㰮㰯㰰㰱㰲㰳㰴㰵㰶㰷㰸㰹㰺㰻㰼㰽㰾㰿㱀㱁㱂㱃㱄㱅㱆㱇㱈㱉㱊㱋㱌㱍㱎㱏㱐㱑㱒㱓㱔㱕㱖㱗㱘㱙㱚㱛㱜㱝㱞㱟㱠㱡㱢㱣㱤㱥㱦㱧㱨㱩㱪㱫㱬㱭㱮㱯㱰㱱㱲㱳㱴㱵㱶㱷㱸㱹㱺㱻㱼㱽㱾㱿㲀㲁㲂㲃㲄㲅㲆㲇㲈㲉㲊㲋㲌㲍㲎㲏㲐㲑㲒㲓㲔㲕㲖㲗㲘㲙㲚㲛㲜㲝㲞㲟㲠㲡㲢㲣㲤㲥㲦㲧㲨㲩㲪㲫㲬㲭㲮㲯㲰㲱㲲㲳㲴㲵㲶㲷㲸㲹㲺㲻㲼㲽㲾㲿㳀㳁㳂㳃㳄㳅㳆㳇㳈㳉㳊㳋㳌㳍㳎㳏㳐㳑㳒㳓㳔㳕㳖㳗㳘㳙㳚㳛㳜㳝㳞㳟㳠㳡㳢㳣㳤㳥㳦㳧㳨㳩㳪㳫㳬㳭㳮㳯㳰㳱㳲㳳㳴㳵㳶㳷㳸㳹㳺㳻㳼㳽㳾㳿㴀㴁㴂㴃㴄㴅㴆㴇㴈㴉㴊㴋㴌㴍㴎㴏㴐㴑㴒㴓㴔㴕㴖㴗㴘㴙㴚㴛㴜㴝㴞㴟㴠㴡㴢㴣㴤㴥㴦㴧㴨㴩㴪㴫㴬㴭㴮㴯㴰㴱㴲㴳㴴㴵㴶㴷㴸㴹㴺㴻㴼㴽㴾㴿㵀㵁㵂㵃㵄㵅㵆㵇㵈㵉㵊㵋㵌㵍㵎㵏㵐㵑㵒㵓㵔㵕㵖㵗㵘㵙㵚㵛㵜㵝㵞㵟㵠㵡㵢㵣㵤㵥㵦㵧㵨㵩㵪㵫㵬㵭㵮㵯㵰㵱㵲㵳㵴㵵㵶㵷㵸㵹㵺㵻㵼㵽㵾㵿㶀㶁㶂㶃㶄㶅㶆㶇㶈㶉㶊㶋㶌㶍㶎㶏㶐㶑㶒㶓㶔㶕㶖㶗㶘㶙㶚㶛㶜㶝㶞㶟㶠㶡㶢㶣㶤㶥㶦㶧㶨㶩㶪㶫㶬㶭㶮㶯㶰㶱㶲㶳㶴㶵㶶㶷㶸㶹㶺㶻㶼㶽㶾㶿㷀㷁㷂㷃㷄㷅㷆㷇㷈㷉㷊㷋㷌㷍㷎㷏㷐㷑㷒㷓㷔㷕㷖㷗㷘㷙㷚㷛㷜㷝㷞㷟㷠㷡㷢㷣㷤㷥㷦㷧㷨㷩㷪㷫㷬㷭㷮㷯㷰㷱㷲㷳㷴㷵㷶㷷㷸㷹㷺㷻㷼㷽㷾㷿㸀㸁㸂㸃㸄㸅㸆㸇㸈㸉㸊㸋㸌㸍㸎㸏㸐㸑㸒㸓㸔㸕㸖㸗㸘㸙㸚㸛㸜㸝㸞㸟㸠㸡㸢㸣㸤㸥㸦㸧㸨㸩㸪㸫㸬㸭㸮㸯㸰㸱㸲㸳㸴㸵㸶㸷㸸㸹㸺㸻㸼㸽㸾㸿㹀㹁㹂㹃㹄㹅㹆㹇㹈㹉㹊㹋㹌㹍㹎㹏㹐㹑㹒㹓㹔㹕㹖㹗㹘㹙㹚㹛㹜㹝㹞㹟㹠㹡㹢㹣㹤㹥㹦㹧㹨㹩㹪㹫㹬㹭㹮㹯㹰㹱㹲㹳㹴㹵㹶㹷㹸㹹㹺㹻㹼㹽㹾㹿㺀㺁㺂㺃㺄㺅㺆㺇㺈㺉㺊㺋㺌㺍㺎㺏㺐㺑㺒㺓㺔㺕㺖㺗㺘㺙㺚㺛㺜㺝㺞㺟㺠㺡㺢㺣㺤㺥㺦㺧㺨㺩㺪㺫㺬㺭㺮㺯㺰㺱㺲㺳㺴㺵㺶㺷㺸㺹㺺㺻㺼㺽㺾㺿㻀㻁㻂㻃㻄㻅㻆㻇㻈㻉㻊㻋㻌㻍㻎㻏㻐㻑㻒㻓㻔㻕㻖㻗㻘㻙㻚㻛㻜㻝㻞㻟㻠㻡㻢㻣㻤㻥㻦㻧㻨㻩㻪㻫㻬㻭㻮㻯㻰㻱㻲㻳㻴㻵㻶㻷㻸㻹㻺㻻㻼㻽㻾㻿㼀㼁㼂㼃㼄㼅㼆㼇㼈㼉㼊㼋㼌㼍㼎㼏㼐㼑㼒㼓㼔㼕㼖㼗㼘㼙㼚㼛㼜㼝㼞㼟㼠㼡㼢㼣㼤㼥㼦㼧㼨㼩㼪㼫㼬㼭㼮㼯㼰㼱㼲㼳㼴㼵㼶㼷㼸㼹㼺㼻㼼㼽㼾㼿㽀㽁㽂㽃㽄㽅㽆㽇㽈㽉㽊㽋㽌㽍㽎㽏㽐㽑㽒㽓㽔㽕㽖㽗㽘㽙㽚㽛㽜㽝㽞㽟㽠㽡㽢㽣㽤㽥㽦㽧㽨㽩㽪㽫㽬㽭㽮㽯㽰㽱㽲㽳㽴㽵㽶㽷㽸㽹㽺㽻㽼㽽㽾㽿㾀㾁㾂㾃㾄㾅㾆㾇㾈㾉㾊㾋㾌㾍㾎㾏㾐㾑㾒㾓㾔㾕㾖㾗㾘㾙㾚㾛㾜㾝㾞㾟㾠㾡㾢㾣㾤㾥㾦㾧㾨㾩㾪㾫㾬㾭㾮㾯㾰㾱㾲㾳㾴㾵㾶㾷㾸㾹㾺㾻㾼㾽㾾㾿㿀㿁㿂㿃㿄㿅㿆㿇㿈㿉㿊㿋㿌㿍㿎㿏㿐㿑㿒㿓㿔㿕㿖㿗㿘㿙㿚㿛㿜㿝㿞㿟㿠㿡㿢㿣㿤㿥㿦㿧㿨㿩㿪㿫㿬㿭㿮㿯㿰㿱㿲㿳㿴㿵㿶㿷㿸㿹㿺㿻㿼㿽㿾㿿䀀䀁䀂䀃䀄䀅䀆䀇䀈䀉䀊䀋䀌䀍䀎䀏䀐䀑䀒䀓䀔䀕䀖䀗䀘䀙䀚䀛䀜䀝䀞䀟䀠䀡䀢䀣䀤䀥䀦䀧䀨䀩䀪䀫䀬䀭䀮䀯䀰䀱䀲䀳䀴䀵䀶䀷䀸䀹䀺䀻䀼䀽䀾䀿䁀䁁䁂䁃䁄䁅䁆䁇䁈䁉䁊䁋䁌䁍䁎䁏䁐䁑䁒䁓䁔䁕䁖䁗䁘䁙䁚䁛䁜䁝䁞䁟䁠䁡䁢䁣䁤䁥䁦䁧䁨䁩䁪䁫䁬䁭䁮䁯䁰䁱䁲䁳䁴䁵䁶䁷䁸䁹䁺䁻䁼䁽䁾䁿䂀䂁䂂䂃䂄䂅䂆䂇䂈䂉䂊䂋䂌䂍䂎䂏䂐䂑䂒䂓䂔䂕䂖䂗䂘䂙䂚䂛䂜䂝䂞䂟䂠䂡䂢䂣䂤䂥䂦䂧䂨䂩䂪䂫䂬䂭䂮䂯䂰䂱䂲䂳䂴䂵䂶䂷䂸䂹䂺䂻䂼䂽䂾䂿䃀䃁䃂䃃䃄䃅䃆䃇䃈䃉䃊䃋䃌䃍䃎䃏䃐䃑䃒䃓䃔䃕䃖䃗䃘䃙䃚䃛䃜䃝䃞䃟䃠䃡䃢䃣䃤䃥䃦䃧䃨䃩䃪䃫䃬䃭䃮䃯䃰䃱䃲䃳䃴䃵䃶䃷䃸䃹䃺䃻䃼䃽䃾䃿䄀䄁䄂䄃䄄䄅䄆䄇䄈䄉䄊䄋䄌䄍䄎䄏䄐䄑䄒䄓䄔䄕䄖䄗䄘䄙䄚䄛䄜䄝䄞䄟䄠䄡䄢䄣䄤䄥䄦䄧䄨䄩䄪䄫䄬䄭䄮䄯䄰䄱䄲䄳䄴䄵䄶䄷䄸䄹䄺䄻䄼䄽䄾䄿䅀䅁䅂䅃䅄䅅䅆䅇䅈䅉䅊䅋䅌䅍䅎䅏䅐䅑䅒䅓䅔䅕䅖䅗䅘䅙䅚䅛䅜䅝䅞䅟䅠䅡䅢䅣䅤䅥䅦䅧䅨䅩䅪䅫䅬䅭䅮䅯䅰䅱䅲䅳䅴䅵䅶䅷䅸䅹䅺䅻䅼䅽䅾䅿䆀䆁䆂䆃䆄䆅䆆䆇䆈䆉䆊䆋䆌䆍䆎䆏䆐䆑䆒䆓䆔䆕䆖䆗䆘䆙䆚䆛䆜䆝䆞䆟䆠䆡䆢䆣䆤䆥䆦䆧䆨䆩䆪䆫䆬䆭䆮䆯䆰䆱䆲䆳䆴䆵䆶䆷䆸䆹䆺䆻䆼䆽䆾䆿䇀䇁䇂䇃䇄䇅䇆䇇䇈䇉䇊䇋䇌䇍䇎䇏䇐䇑䇒䇓䇔䇕䇖䇗䇘䇙䇚䇛䇜䇝䇞䇟䇠䇡䇢䇣䇤䇥䇦䇧䇨䇩䇪䇫䇬䇭䇮䇯䇰䇱䇲䇳䇴䇵䇶䇷䇸䇹䇺䇻䇼䇽䇾䇿䈀䈁䈂䈃䈄䈅䈆䈇䈈䈉䈊䈋䈌䈍䈎䈏䈐䈑䈒䈓䈔䈕䈖䈗䈘䈙䈚䈛䈜䈝䈞䈟䈠䈡䈢䈣䈤䈥䈦䈧䈨䈩䈪䈫䈬䈭䈮䈯䈰䈱䈲䈳䈴䈵䈶䈷䈸䈹䈺䈻䈼䈽䈾䈿䉀䉁䉂䉃䉄䉅䉆䉇䉈䉉䉊䉋䉌䉍䉎䉏䉐䉑䉒䉓䉔䉕䉖䉗䉘䉙䉚䉛䉜䉝䉞䉟䉠䉡䉢䉣䉤䉥䉦䉧䉨䉩䉪䉫䉬䉭䉮䉯䉰䉱䉲䉳䉴䉵䉶䉷䉸䉹䉺䉻䉼䉽䉾䉿䊀䊁䊂䊃䊄䊅䊆䊇䊈䊉䊊䊋䊌䊍䊎䊏䊐䊑䊒䊓䊔䊕䊖䊗䊘䊙䊚䊛䊜䊝䊞䊟䊠䊡䊢䊣䊤䊥䊦䊧䊨䊩䊪䊫䊬䊭䊮䊯䊰䊱䊲䊳䊴䊵䊶䊷䊸䊹䊺䊻䊼䊽䊾䊿䋀䋁䋂䋃䋄䋅䋆䋇䋈䋉䋊䋋䋌䋍䋎䋏䋐䋑䋒䋓䋔䋕䋖䋗䋘䋙䋚䋛䋜䋝䋞䋟䋠䋡䋢䋣䋤䋥䋦䋧䋨䋩䋪䋫䋬䋭䋮䋯䋰䋱䋲䋳䋴䋵䋶䋷䋸䋹䋺䋻䋼䋽䋾䋿䌀䌁䌂䌃䌄䌅䌆䌇䌈䌉䌊䌋䌌䌍䌎䌏䌐䌑䌒䌓䌔䌕䌖䌗䌘䌙䌚䌛䌜䌝䌞䌟䌠䌡䌢䌣䌤䌥䌦䌧䌨䌩䌪䌫䌬䌭䌮䌯䌰䌱䌲䌳䌴䌵䌶䌷䌸䌹䌺䌻䌼䌽䌾䌿䍀䍁䍂䍃䍄䍅䍆䍇䍈䍉䍊䍋䍌䍍䍎䍏䍐䍑䍒䍓䍔䍕䍖䍗䍘䍙䍚䍛䍜䍝䍞䍟䍠䍡䍢䍣䍤䍥䍦䍧䍨䍩䍪䍫䍬䍭䍮䍯䍰䍱䍲䍳䍴䍵䍶䍷䍸䍹䍺䍻䍼䍽䍾䍿䎀䎁䎂䎃䎄䎅䎆䎇䎈䎉䎊䎋䎌䎍䎎䎏䎐䎑䎒䎓䎔䎕䎖䎗䎘䎙䎚䎛䎜䎝䎞䎟䎠䎡䎢䎣䎤䎥䎦䎧䎨䎩䎪䎫䎬䎭䎮䎯䎰䎱䎲䎳䎴䎵䎶䎷䎸䎹䎺䎻䎼䎽䎾䎿䏀䏁䏂䏃䏄䏅䏆䏇䏈䏉䏊䏋䏌䏍䏎䏏䏐䏑䏒䏓䏔䏕䏖䏗䏘䏙䏚䏛䏜䏝䏞䏟䏠䏡䏢䏣䏤䏥䏦䏧䏨䏩䏪䏫䏬䏭䏮䏯䏰䏱䏲䏳䏴䏵䏶䏷䏸䏹䏺䏻䏼䏽䏾䏿䐀䐁䐂䐃䐄䐅䐆䐇䐈䐉䐊䐋䐌䐍䐎䐏䐐䐑䐒䐓䐔䐕䐖䐗䐘䐙䐚䐛䐜䐝䐞䐟䐠䐡䐢䐣䐤䐥䐦䐧䐨䐩䐪䐫䐬䐭䐮䐯䐰䐱䐲䐳䐴䐵䐶䐷䐸䐹䐺䐻䐼䐽䐾䐿䑀䑁䑂䑃䑄䑅䑆䑇䑈䑉䑊䑋䑌䑍䑎䑏䑐䑑䑒䑓䑔䑕䑖䑗䑘䑙䑚䑛䑜䑝䑞䑟䑠䑡䑢䑣䑤䑥䑦䑧䑨䑩䑪䑫䑬䑭䑮䑯䑰䑱䑲䑳䑴䑵䑶䑷䑸䑹䑺䑻䑼䑽䑾䑿䒀䒁䒂䒃䒄䒅䒆䒇䒈䒉䒊䒋䒌䒍䒎䒏䒐䒑䒒䒓䒔䒕䒖䒗䒘䒙䒚䒛䒜䒝䒞䒟䒠䒡䒢䒣䒤䒥䒦䒧䒨䒩䒪䒫䒬䒭䒮䒯䒰䒱䒲䒳䒴䒵䒶䒷䒸䒹䒺䒻䒼䒽䒾䒿䓀䓁䓂䓃䓄䓅䓆䓇䓈䓉䓊䓋䓌䓍䓎䓏䓐䓑䓒䓓䓔䓕䓖䓗䓘䓙䓚䓛䓜䓝䓞䓟䓠䓡䓢䓣䓤䓥䓦䓧䓨䓩䓪䓫䓬䓭䓮䓯䓰䓱䓲䓳䓴䓵䓶䓷䓸䓹䓺䓻䓼䓽䓾䓿䔀䔁䔂䔃䔄䔅䔆䔇䔈䔉䔊䔋䔌䔍䔎䔏䔐䔑䔒䔓䔔䔕䔖䔗䔘䔙䔚䔛䔜䔝䔞䔟䔠䔡䔢䔣䔤䔥䔦䔧䔨䔩䔪䔫䔬䔭䔮䔯䔰䔱䔲䔳䔴䔵䔶䔷䔸䔹䔺䔻䔼䔽䔾䔿䕀䕁䕂䕃䕄䕅䕆䕇䕈䕉䕊䕋䕌䕍䕎䕏䕐䕑䕒䕓䕔䕕䕖䕗䕘䕙䕚䕛䕜䕝䕞䕟䕠䕡䕢䕣䕤䕥䕦䕧䕨䕩䕪䕫䕬䕭䕮䕯䕰䕱䕲䕳䕴䕵䕶䕷䕸䕹䕺䕻䕼䕽䕾䕿䖀䖁䖂䖃䖄䖅䖆䖇䖈䖉䖊䖋䖌䖍䖎䖏䖐䖑䖒䖓䖔䖕䖖䖗䖘䖙䖚䖛䖜䖝䖞䖟䖠䖡䖢䖣䖤䖥䖦䖧䖨䖩䖪䖫䖬䖭䖮䖯䖰䖱䖲䖳䖴䖵䖶䖷䖸䖹䖺䖻䖼䖽䖾䖿䗀䗁䗂䗃䗄䗅䗆䗇䗈䗉䗊䗋䗌䗍䗎䗏䗐䗑䗒䗓䗔䗕䗖䗗䗘䗙䗚䗛䗜䗝䗞䗟䗠䗡䗢䗣䗤䗥䗦䗧䗨䗩䗪䗫䗬䗭䗮䗯䗰䗱䗲䗳䗴䗵䗶䗷䗸䗹䗺䗻䗼䗽䗾䗿䘀䘁䘂䘃䘄䘅䘆䘇䘈䘉䘊䘋䘌䘍䘎䘏䘐䘑䘒䘓䘔䘕䘖䘗䘘䘙䘚䘛䘜䘝䘞䘟䘠䘡䘢䘣䘤䘥䘦䘧䘨䘩䘪䘫䘬䘭䘮䘯䘰䘱䘲䘳䘴䘵䘶䘷䘸䘹䘺䘻䘼䘽䘾䘿䙀䙁䙂䙃䙄䙅䙆䙇䙈䙉䙊䙋䙌䙍䙎䙏䙐䙑䙒䙓䙔䙕䙖䙗䙘䙙䙚䙛䙜䙝䙞䙟䙠䙡䙢䙣䙤䙥䙦䙧䙨䙩䙪䙫䙬䙭䙮䙯䙰䙱䙲䙳䙴䙵䙶䙷䙸䙹䙺䙻䙼䙽䙾䙿䚀䚁䚂䚃䚄䚅䚆䚇䚈䚉䚊䚋䚌䚍䚎䚏䚐䚑䚒䚓䚔䚕䚖䚗䚘䚙䚚䚛䚜䚝䚞䚟䚠䚡䚢䚣䚤䚥䚦䚧䚨䚩䚪䚫䚬䚭䚮䚯䚰䚱䚲䚳䚴䚵䚶䚷䚸䚹䚺䚻䚼䚽䚾䚿䛀䛁䛂䛃䛄䛅䛆䛇䛈䛉䛊䛋䛌䛍䛎䛏䛐䛑䛒䛓䛔䛕䛖䛗䛘䛙䛚䛛䛜䛝䛞䛟䛠䛡䛢䛣䛤䛥䛦䛧䛨䛩䛪䛫䛬䛭䛮䛯䛰䛱䛲䛳䛴䛵䛶䛷䛸䛹䛺䛻䛼䛽䛾䛿䜀䜁䜂䜃䜄䜅䜆䜇䜈䜉䜊䜋䜌䜍䜎䜏䜐䜑䜒䜓䜔䜕䜖䜗䜘䜙䜚䜛䜜䜝䜞䜟䜠䜡䜢䜣䜤䜥䜦䜧䜨䜩䜪䜫䜬䜭䜮䜯䜰䜱䜲䜳䜴䜵䜶䜷䜸䜹䜺䜻䜼䜽䜾䜿䝀䝁䝂䝃䝄䝅䝆䝇䝈䝉䝊䝋䝌䝍䝎䝏䝐䝑䝒䝓䝔䝕䝖䝗䝘䝙䝚䝛䝜䝝䝞䝟䝠䝡䝢䝣䝤䝥䝦䝧䝨䝩䝪䝫䝬䝭䝮䝯䝰䝱䝲䝳䝴䝵䝶䝷䝸䝹䝺䝻䝼䝽䝾䝿䞀䞁䞂䞃䞄䞅䞆䞇䞈䞉䞊䞋䞌䞍䞎䞏䞐䞑䞒䞓䞔䞕䞖䞗䞘䞙䞚䞛䞜䞝䞞䞟䞠䞡䞢䞣䞤䞥䞦䞧䞨䞩䞪䞫䞬䞭䞮䞯䞰䞱䞲䞳䞴䞵䞶䞷䞸䞹䞺䞻䞼䞽䞾䞿䟀䟁䟂䟃䟄䟅䟆䟇䟈䟉䟊䟋䟌䟍䟎䟏䟐䟑䟒䟓䟔䟕䟖䟗䟘䟙䟚䟛䟜䟝䟞䟟䟠䟡䟢䟣䟤䟥䟦䟧䟨䟩䟪䟫䟬䟭䟮䟯䟰䟱䟲䟳䟴䟵䟶䟷䟸䟹䟺䟻䟼䟽䟾䟿䠀䠁䠂䠃䠄䠅䠆䠇䠈䠉䠊䠋䠌䠍䠎䠏䠐䠑䠒䠓䠔䠕䠖䠗䠘䠙䠚䠛䠜䠝䠞䠟䠠䠡䠢䠣䠤䠥䠦䠧䠨䠩䠪䠫䠬䠭䠮䠯䠰䠱䠲䠳䠴䠵䠶䠷䠸䠹䠺䠻䠼䠽䠾䠿䡀䡁䡂䡃䡄䡅䡆䡇䡈䡉䡊䡋䡌䡍䡎䡏䡐䡑䡒䡓䡔䡕䡖䡗䡘䡙䡚䡛䡜䡝䡞䡟䡠䡡䡢䡣䡤䡥䡦䡧䡨䡩䡪䡫䡬䡭䡮䡯䡰䡱䡲䡳䡴䡵䡶䡷䡸䡹䡺䡻䡼䡽䡾䡿䢀䢁䢂䢃䢄䢅䢆䢇䢈䢉䢊䢋䢌䢍䢎䢏䢐䢑䢒䢓䢔䢕䢖䢗䢘䢙䢚䢛䢜䢝䢞䢟䢠䢡䢢䢣䢤䢥䢦䢧䢨䢩䢪䢫䢬䢭䢮䢯䢰䢱䢲䢳䢴䢵䢶䢷䢸䢹䢺䢻䢼䢽䢾䢿䣀䣁䣂䣃䣄䣅䣆䣇䣈䣉䣊䣋䣌䣍䣎䣏䣐䣑䣒䣓䣔䣕䣖䣗䣘䣙䣚䣛䣜䣝䣞䣟䣠䣡䣢䣣䣤䣥䣦䣧䣨䣩䣪䣫䣬䣭䣮䣯䣰䣱䣲䣳䣴䣵䣶䣷䣸䣹䣺䣻䣼䣽䣾䣿䤀䤁䤂䤃䤄䤅䤆䤇䤈䤉䤊䤋䤌䤍䤎䤏䤐䤑䤒䤓䤔䤕䤖䤗䤘䤙䤚䤛䤜䤝䤞䤟䤠䤡䤢䤣䤤䤥䤦䤧䤨䤩䤪䤫䤬䤭䤮䤯䤰䤱䤲䤳䤴䤵䤶䤷䤸䤹䤺䤻䤼䤽䤾䤿䥀䥁䥂䥃䥄䥅䥆䥇䥈䥉䥊䥋䥌䥍䥎䥏䥐䥑䥒䥓䥔䥕䥖䥗䥘䥙䥚䥛䥜䥝䥞䥟䥠䥡䥢䥣䥤䥥䥦䥧䥨䥩䥪䥫䥬䥭䥮䥯䥰䥱䥲䥳䥴䥵䥶䥷䥸䥹䥺䥻䥼䥽䥾䥿䦀䦁䦂䦃䦄䦅䦆䦇䦈䦉䦊䦋䦌䦍䦎䦏䦐䦑䦒䦓䦔䦕䦖䦗䦘䦙䦚䦛䦜䦝䦞䦟䦠䦡䦢䦣䦤䦥䦦䦧䦨䦩䦪䦫䦬䦭䦮䦯䦰䦱䦲䦳䦴䦵䦶䦷䦸䦹䦺䦻䦼䦽䦾䦿䧀䧁䧂䧃䧄䧅䧆䧇䧈䧉䧊䧋䧌䧍䧎䧏䧐䧑䧒䧓䧔䧕䧖䧗䧘䧙䧚䧛䧜䧝䧞䧟䧠䧡䧢䧣䧤䧥䧦䧧䧨䧩䧪䧫䧬䧭䧮䧯䧰䧱䧲䧳䧴䧵䧶䧷䧸䧹䧺䧻䧼䧽䧾䧿䨀䨁䨂䨃䨄䨅䨆䨇䨈䨉䨊䨋䨌䨍䨎䨏䨐䨑䨒䨓䨔䨕䨖䨗䨘䨙䨚䨛䨜䨝䨞䨟䨠䨡䨢䨣䨤䨥䨦䨧䨨䨩䨪䨫䨬䨭䨮䨯䨰䨱䨲䨳䨴䨵䨶䨷䨸䨹䨺䨻䨼䨽䨾䨿䩀䩁䩂䩃䩄䩅䩆䩇䩈䩉䩊䩋䩌䩍䩎䩏䩐䩑䩒䩓䩔䩕䩖䩗䩘䩙䩚䩛䩜䩝䩞䩟䩠䩡䩢䩣䩤䩥䩦䩧䩨䩩䩪䩫䩬䩭䩮䩯䩰䩱䩲䩳䩴䩵䩶䩷䩸䩹䩺䩻䩼䩽䩾䩿䪀䪁䪂䪃䪄䪅䪆䪇䪈䪉䪊䪋䪌䪍䪎䪏䪐䪑䪒䪓䪔䪕䪖䪗䪘䪙䪚䪛䪜䪝䪞䪟䪠䪡䪢䪣䪤䪥䪦䪧䪨䪩䪪䪫䪬䪭䪮䪯䪰䪱䪲䪳䪴䪵䪶䪷䪸䪹䪺䪻䪼䪽䪾䪿䫀䫁䫂䫃䫄䫅䫆䫇䫈䫉䫊䫋䫌䫍䫎䫏䫐䫑䫒䫓䫔䫕䫖䫗䫘䫙䫚䫛䫜䫝䫞䫟䫠䫡䫢䫣䫤䫥䫦䫧䫨䫩䫪䫫䫬䫭䫮䫯䫰䫱䫲䫳䫴䫵䫶䫷䫸䫹䫺䫻䫼䫽䫾䫿䬀䬁䬂䬃䬄䬅䬆䬇䬈䬉䬊䬋䬌䬍䬎䬏䬐䬑䬒䬓䬔䬕䬖䬗䬘䬙䬚䬛䬜䬝䬞䬟䬠䬡䬢䬣䬤䬥䬦䬧䬨䬩䬪䬫䬬䬭䬮䬯䬰䬱䬲䬳䬴䬵䬶䬷䬸䬹䬺䬻䬼䬽䬾䬿䭀䭁䭂䭃䭄䭅䭆䭇䭈䭉䭊䭋䭌䭍䭎䭏䭐䭑䭒䭓䭔䭕䭖䭗䭘䭙䭚䭛䭜䭝䭞䭟䭠䭡䭢䭣䭤䭥䭦䭧䭨䭩䭪䭫䭬䭭䭮䭯䭰䭱䭲䭳䭴䭵䭶䭷䭸䭹䭺䭻䭼䭽䭾䭿䮀䮁䮂䮃䮄䮅䮆䮇䮈䮉䮊䮋䮌䮍䮎䮏䮐䮑䮒䮓䮔䮕䮖䮗䮘䮙䮚䮛䮜䮝䮞䮟䮠䮡䮢䮣䮤䮥䮦䮧䮨䮩䮪䮫䮬䮭䮮䮯䮰䮱䮲䮳䮴䮵䮶䮷䮸䮹䮺䮻䮼䮽䮾䮿䯀䯁䯂䯃䯄䯅䯆䯇䯈䯉䯊䯋䯌䯍䯎䯏䯐䯑䯒䯓䯔䯕䯖䯗䯘䯙䯚䯛䯜䯝䯞䯟䯠䯡䯢䯣䯤䯥䯦䯧䯨䯩䯪䯫䯬䯭䯮䯯䯰䯱䯲䯳䯴䯵䯶䯷䯸䯹䯺䯻䯼䯽䯾䯿䰀䰁䰂䰃䰄䰅䰆䰇䰈䰉䰊䰋䰌䰍䰎䰏䰐䰑䰒䰓䰔䰕䰖䰗䰘䰙䰚䰛䰜䰝䰞䰟䰠䰡䰢䰣䰤䰥䰦䰧䰨䰩䰪䰫䰬䰭䰮䰯䰰䰱䰲䰳䰴䰵䰶䰷䰸䰹䰺䰻䰼䰽䰾䰿䱀䱁䱂䱃䱄䱅䱆䱇䱈䱉䱊䱋䱌䱍䱎䱏䱐䱑䱒䱓䱔䱕䱖䱗䱘䱙䱚䱛䱜䱝䱞䱟䱠䱡䱢䱣䱤䱥䱦䱧䱨䱩䱪䱫䱬䱭䱮䱯䱰䱱䱲䱳䱴䱵䱶䱷䱸䱹䱺䱻䱼䱽䱾䱿䲀䲁䲂䲃䲄䲅䲆䲇䲈䲉䲊䲋䲌䲍䲎䲏䲐䲑䲒䲓䲔䲕䲖䲗䲘䲙䲚䲛䲜䲝䲞䲟䲠䲡䲢䲣䲤䲥䲦䲧䲨䲩䲪䲫䲬䲭䲮䲯䲰䲱䲲䲳䲴䲵䲶䲷䲸䲹䲺䲻䲼䲽䲾䲿䳀䳁䳂䳃䳄䳅䳆䳇䳈䳉䳊䳋䳌䳍䳎䳏䳐䳑䳒䳓䳔䳕䳖䳗䳘䳙䳚䳛䳜䳝䳞䳟䳠䳡䳢䳣䳤䳥䳦䳧䳨䳩䳪䳫䳬䳭䳮䳯䳰䳱䳲䳳䳴䳵䳶䳷䳸䳹䳺䳻䳼䳽䳾䳿䴀䴁䴂䴃䴄䴅䴆䴇䴈䴉䴊䴋䴌䴍䴎䴏䴐䴑䴒䴓䴔䴕䴖䴗䴘䴙䴚䴛䴜䴝䴞䴟䴠䴡䴢䴣䴤䴥䴦䴧䴨䴩䴪䴫䴬䴭䴮䴯䴰䴱䴲䴳䴴䴵䴶䴷䴸䴹䴺䴻䴼䴽䴾䴿䵀䵁䵂䵃䵄䵅䵆䵇䵈䵉䵊䵋䵌䵍䵎䵏䵐䵑䵒䵓䵔䵕䵖䵗䵘䵙䵚䵛䵜䵝䵞䵟䵠䵡䵢䵣䵤䵥䵦䵧䵨䵩䵪䵫䵬䵭䵮䵯䵰䵱䵲䵳䵴䵵䵶䵷䵸䵹䵺䵻䵼䵽䵾䵿䶀䶁䶂䶃䶄䶅䶆䶇䶈䶉䶊䶋䶌䶍䶎䶏䶐䶑䶒䶓䶔䶕䶖䶗䶘䶙䶚䶛䶜䶝䶞䶟䶠䶡䶢䶣䶤䶥䶦䶧䶨䶩䶪䶫䶬䶭䶮䶯䶰䶱䶲䶳䶴䶵䷀䷁䷂䷃䷄䷅䷆䷇䷈䷉䷊䷋䷌䷍䷎䷏䷐䷑䷒䷓䷔䷕䷖䷗䷘䷙䷚䷛䷜䷝䷞䷟䷠䷡䷢䷣䷤䷥䷦䷧䷨䷩䷪䷫䷬䷭䷮䷯䷰䷱䷲䷳䷴䷵䷶䷷䷸䷹䷺䷻䷼䷽䷾䷿一丁丂七丄丅丆万丈三上下丌不与丏丐丑丒专且丕世丗丘丙业丛东丝丞丟丠両丢丣两严並丧丨丩个丫丬中丮丯丰丱串丳临丵丶丷丸丹为主丼丽举丿乀乁乂乃乄久乆乇么义乊之乌乍乎乏乐乑乒乓乔乕乖乗乘乙乚乛乜九乞也习乡乢乣乤乥书乧乨乩乪乫乬乭乮乯买乱乲乳乴乵乶乷乸乹乺乻乼乽乾乿亀亁亂亃亄亅了亇予争亊事二亍于亏亐云互亓五井亖亗亘亙亚些亜亝亞亟亠亡亢亣交亥亦产亨亩亪享京亭亮亯亰亱亲亳亴亵亶亷亸亹人亻亼亽亾亿什仁仂仃仄仅仆仇仈仉今介仌仍从仏仐仑仒仓仔仕他仗付仙仚仛仜仝仞仟仠仡仢代令以仦仧仨仩仪仫们仭仮仯仰仱仲仳仴仵件价仸仹仺任仼份仾仿伀企伂伃伄伅伆伇伈伉伊伋伌伍伎伏伐休伒伓伔伕伖众优伙会伛伜伝伞伟传伡伢伣伤伥伦伧伨伩伪伫伬伭伮伯估伱伲伳伴伵伶伷伸伹伺伻似伽伾伿佀佁佂佃佄佅但佇佈佉佊佋佌位低住佐佑佒体佔何佖佗佘余佚佛作佝佞佟你佡佢佣佤佥佦佧佨佩佪佫佬佭佮佯佰佱佲佳佴併佶佷佸佹佺佻佼佽佾使侀侁侂侃侄侅來侇侈侉侊例侌侍侎侏侐侑侒侓侔侕侖侗侘侙侚供侜依侞侟侠価侢侣侤侥侦侧侨侩侪侫侬侭侮侯侰侱侲侳侴侵侶侷侸侹侺侻侼侽侾便俀俁係促俄俅俆俇俈俉俊俋俌俍俎俏俐俑俒俓俔俕俖俗俘俙俚俛俜保俞俟俠信俢俣俤俥俦俧俨俩俪俫俬俭修俯俰俱俲俳俴俵俶俷俸俹俺俻俼俽俾俿倀倁倂倃倄倅倆倇倈倉倊個倌倍倎倏倐們倒倓倔倕倖倗倘候倚倛倜倝倞借倠倡倢倣値倥倦倧倨倩倪倫倬倭倮倯倰倱倲倳倴倵倶倷倸倹债倻值倽倾倿偀偁偂偃偄偅偆假偈偉偊偋偌偍偎偏偐偑偒偓偔偕偖偗偘偙做偛停偝偞偟偠偡偢偣偤健偦偧偨偩偪偫偬偭偮偯偰偱偲偳側偵偶偷偸偹偺偻偼偽偾偿傀傁傂傃傄傅傆傇傈傉傊傋傌傍傎傏傐傑傒傓傔傕傖傗傘備傚傛傜傝傞傟傠傡傢傣傤傥傦傧储傩傪傫催傭傮傯傰傱傲傳傴債傶傷傸傹傺傻傼傽傾傿僀僁僂僃僄僅僆僇僈僉僊僋僌働僎像僐僑僒僓僔僕僖僗僘僙僚僛僜僝僞僟僠僡僢僣僤僥僦僧僨僩僪僫僬僭僮僯僰僱僲僳僴僵僶僷僸價僺僻僼僽僾僿儀儁儂儃億儅儆儇儈儉儊儋儌儍儎儏儐儑儒儓儔儕儖儗儘儙儚儛儜儝儞償儠儡儢儣儤儥儦儧儨儩優儫儬儭儮儯儰儱儲儳儴儵儶儷儸儹儺儻儼儽儾儿兀允兂元兄充兆兇先光兊克兌免兎兏児兑兒兓兔兕兖兗兘兙党兛兜兝兞兟兠兡兢兣兤入兦內全兩兪八公六兮兯兰共兲关兴兵其具典兹兺养兼兽兾兿冀冁冂冃冄内円冇冈冉冊冋册再冎冏冐冑冒冓冔冕冖冗冘写冚军农冝冞冟冠冡冢冣冤冥冦冧冨冩冪冫冬冭冮冯冰冱冲决冴况冶冷冸冹冺冻冼冽冾冿净凁凂凃凄凅准凇凈凉凊凋凌凍凎减凐凑凒凓凔凕凖凗凘凙凚凛凜凝凞凟几凡凢凣凤凥処凧凨凩凪凫凬凭凮凯凰凱凲凳凴凵凶凷凸凹出击凼函凾凿刀刁刂刃刄刅分切刈刉刊刋刌刍刎刏刐刑划刓刔刕刖列刘则刚创刜初刞刟删刡刢刣判別刦刧刨利刪别刬刭刮刯到刱刲刳刴刵制刷券刹刺刻刼刽刾刿剀剁剂剃剄剅剆則剈剉削剋剌前剎剏剐剑剒剓剔剕剖剗剘剙剚剛剜剝剞剟剠剡剢剣剤剥剦剧剨剩剪剫剬剭剮副剰剱割剳剴創剶剷剸剹剺剻剼剽剾剿劀劁劂劃劄劅劆劇劈劉劊劋劌劍劎劏劐劑劒劓劔劕劖劗劘劙劚力劜劝办功加务劢劣劤劥劦劧动助努劫劬劭劮劯劰励劲劳労劵劶劷劸効劺劻劼劽劾势勀勁勂勃勄勅勆勇勈勉勊勋勌勍勎勏勐勑勒勓勔動勖勗勘務勚勛勜勝勞募勠勡勢勣勤勥勦勧勨勩勪勫勬勭勮勯勰勱勲勳勴勵勶勷勸勹勺勻勼勽勾勿匀匁匂匃匄包匆匇匈匉匊匋匌匍匎匏匐匑匒匓匔匕化北匘匙匚匛匜匝匞匟匠匡匢匣匤匥匦匧匨匩匪匫匬匭匮匯匰匱匲匳匴匵匶匷匸匹区医匼匽匾匿區十卂千卄卅卆升午卉半卋卌卍华协卐卑卒卓協单卖南単卙博卛卜卝卞卟占卡卢卣卤卥卦卧卨卩卪卫卬卭卮卯印危卲即却卵卶卷卸卹卺卻卼卽卾卿厀厁厂厃厄厅历厇厈厉厊压厌厍厎厏厐厑厒厓厔厕厖厗厘厙厚厛厜厝厞原厠厡厢厣厤厥厦厧厨厩厪厫厬厭厮厯厰厱厲厳厴厵厶厷厸厹厺去厼厽厾县叀叁参參叄叅叆叇又叉及友双反収叏叐发叒叓叔叕取受变叙叚叛叜叝叞叟叠叡叢口古句另叧叨叩只叫召叭叮可台叱史右叴叵叶号司叹叺叻叼叽叾叿吀吁吂吃各吅吆吇合吉吊吋同名后吏吐向吒吓吔吕吖吗吘吙吚君吜吝吞吟吠吡吢吣吤吥否吧吨吩吪含听吭吮启吰吱吲吳吴吵吶吷吸吹吺吻吼吽吾吿呀呁呂呃呄呅呆呇呈呉告呋呌呍呎呏呐呑呒呓呔呕呖呗员呙呚呛呜呝呞呟呠呡呢呣呤呥呦呧周呩呪呫呬呭呮呯呰呱呲味呴呵呶呷呸呹呺呻呼命呾呿咀咁咂咃咄咅咆咇咈咉咊咋和咍咎咏咐咑咒咓咔咕咖咗咘咙咚咛咜咝咞咟咠咡咢咣咤咥咦咧咨咩咪咫咬咭咮咯咰咱咲咳咴咵咶咷咸咹咺咻咼咽咾咿哀品哂哃哄哅哆哇哈哉哊哋哌响哎哏哐哑哒哓哔哕哖哗哘哙哚哛哜哝哞哟哠員哢哣哤哥哦哧哨哩哪哫哬哭哮哯哰哱哲哳哴哵哶哷哸哹哺哻哼哽哾哿唀唁唂唃唄唅唆唇唈唉唊唋唌唍唎唏唐唑唒唓唔唕唖唗唘唙唚唛唜唝唞唟唠唡唢唣唤唥唦唧唨唩唪唫唬唭售唯唰唱唲唳唴唵唶唷唸唹唺唻唼唽唾唿啀啁啂啃啄啅商啇啈啉啊啋啌啍啎問啐啑啒啓啔啕啖啗啘啙啚啛啜啝啞啟啠啡啢啣啤啥啦啧啨啩啪啫啬啭啮啯啰啱啲啳啴啵啶啷啸啹啺啻啼啽啾啿喀喁喂喃善喅喆喇喈喉喊喋喌喍喎喏喐喑喒喓喔喕喖喗喘喙喚喛喜喝喞喟喠喡喢喣喤喥喦喧喨喩喪喫喬喭單喯喰喱喲喳喴喵営喷喸喹喺喻喼喽喾喿嗀嗁嗂嗃嗄嗅嗆嗇嗈嗉嗊嗋嗌嗍嗎嗏嗐嗑嗒嗓嗔嗕嗖嗗嗘嗙嗚嗛嗜嗝嗞嗟嗠嗡嗢嗣嗤嗥嗦嗧嗨嗩嗪嗫嗬嗭嗮嗯嗰嗱嗲嗳嗴嗵嗶嗷嗸嗹嗺嗻嗼嗽嗾嗿嘀嘁嘂嘃嘄嘅嘆嘇嘈嘉嘊嘋嘌嘍嘎嘏嘐嘑嘒嘓嘔嘕嘖嘗嘘嘙嘚嘛嘜嘝嘞嘟嘠嘡嘢嘣嘤嘥嘦嘧嘨嘩嘪嘫嘬嘭嘮嘯嘰嘱嘲嘳嘴嘵嘶嘷嘸嘹嘺嘻嘼嘽嘾嘿噀噁噂噃噄噅噆噇噈噉噊噋噌噍噎噏噐噑噒噓噔噕噖噗噘噙噚噛噜噝噞噟噠噡噢噣噤噥噦噧器噩噪噫噬噭噮噯噰噱噲噳噴噵噶噷噸噹噺噻噼噽噾噿嚀嚁嚂嚃嚄嚅嚆嚇嚈嚉嚊嚋嚌嚍嚎嚏嚐嚑嚒嚓嚔嚕嚖嚗嚘嚙嚚嚛嚜嚝嚞嚟嚠嚡嚢嚣嚤嚥嚦嚧嚨嚩嚪嚫嚬嚭嚮嚯嚰嚱嚲嚳嚴嚵嚶嚷嚸嚹嚺嚻嚼嚽嚾嚿囀囁囂囃囄囅囆囇囈囉囊囋囌囍囎囏囐囑囒囓囔囕囖囗囘囙囚四囜囝回囟因囡团団囤囥囦囧囨囩囪囫囬园囮囯困囱囲図围囵囶囷囸囹固囻囼国图囿圀圁圂圃圄圅圆圇圈圉圊國圌圍圎圏圐圑園圓圔圕圖圗團圙圚圛圜圝圞土圠圡圢圣圤圥圦圧在圩圪圫圬圭圮圯地圱圲圳圴圵圶圷圸圹场圻圼圽圾圿址坁坂坃坄坅坆均坈坉坊坋坌坍坎坏坐坑坒坓坔坕坖块坘坙坚坛坜坝坞坟坠坡坢坣坤坥坦坧坨坩坪坫坬坭坮坯坰坱坲坳坴坵坶坷坸坹坺坻坼坽坾坿垀垁垂垃垄垅垆垇垈垉垊型垌垍垎垏垐垑垒垓垔垕垖垗垘垙垚垛垜垝垞垟垠垡垢垣垤垥垦垧垨垩垪垫垬垭垮垯垰垱垲垳垴垵垶垷垸垹垺垻垼垽垾垿埀埁埂埃埄埅埆埇埈埉埊埋埌埍城埏埐埑埒埓埔埕埖埗埘埙埚埛埜埝埞域埠埡埢埣埤埥埦埧埨埩埪埫埬埭埮埯埰埱埲埳埴埵埶執埸培基埻埼埽埾埿堀堁堂堃堄堅堆堇堈堉堊堋堌堍堎堏堐堑堒堓堔堕堖堗堘堙堚堛堜堝堞堟堠堡堢堣堤堥堦堧堨堩堪堫堬堭堮堯堰報堲堳場堵堶堷堸堹堺堻堼堽堾堿塀塁塂塃塄塅塆塇塈塉塊塋塌塍塎塏塐塑塒塓塔塕塖塗塘塙塚塛塜塝塞塟塠塡塢塣塤塥塦塧塨塩塪填塬塭塮塯塰塱塲塳塴塵塶塷塸塹塺塻塼塽塾塿墀墁墂境墄墅墆墇墈墉墊墋墌墍墎墏墐墑墒墓墔墕墖増墘墙墚墛墜墝增墟墠墡墢墣墤墥墦墧墨墩墪墫墬墭墮墯墰墱墲墳墴墵墶墷墸墹墺墻墼墽墾墿壀壁壂壃壄壅壆壇壈壉壊壋壌壍壎壏壐壑壒壓壔壕壖壗壘壙壚壛壜壝壞壟壠壡壢壣壤壥壦壧壨壩壪士壬壭壮壯声壱売壳壴壵壶壷壸壹壺壻壼壽壾壿夀夁夂夃处夅夆备夈変夊夋夌复夎夏夐夑夒夓夔夕外夗夘夙多夛夜夝夞够夠夡夢夣夤夥夦大夨天太夫夬夭央夯夰失夲夳头夵夶夷夸夹夺夻夼夽夾夿奀奁奂奃奄奅奆奇奈奉奊奋奌奍奎奏奐契奒奓奔奕奖套奘奙奚奛奜奝奞奟奠奡奢奣奤奥奦奧奨奩奪奫奬奭奮奯奰奱奲女奴奵奶奷奸她奺奻奼好奾奿妀妁如妃妄妅妆妇妈妉妊妋妌妍妎妏妐妑妒妓妔妕妖妗妘妙妚妛妜妝妞妟妠妡妢妣妤妥妦妧妨妩妪妫妬妭妮妯妰妱妲妳妴妵妶妷妸妹妺妻妼妽妾妿姀姁姂姃姄姅姆姇姈姉姊始姌姍姎姏姐姑姒姓委姕姖姗姘姙姚姛姜姝姞姟姠姡姢姣姤姥姦姧姨姩姪姫姬姭姮姯姰姱姲姳姴姵姶姷姸姹姺姻姼姽姾姿娀威娂娃娄娅娆娇娈娉娊娋娌娍娎娏娐娑娒娓娔娕娖娗娘娙娚娛娜娝娞娟娠娡娢娣娤娥娦娧娨娩娪娫娬娭娮娯娰娱娲娳娴娵娶娷娸娹娺娻娼娽娾娿婀婁婂婃婄婅婆婇婈婉婊婋婌婍婎婏婐婑婒婓婔婕婖婗婘婙婚婛婜婝婞婟婠婡婢婣婤婥婦婧婨婩婪婫婬婭婮婯婰婱婲婳婴婵婶婷婸婹婺婻婼婽婾婿媀媁媂媃媄媅媆媇媈媉媊媋媌媍媎媏媐媑媒媓媔媕媖媗媘媙媚媛媜媝媞媟媠媡媢媣媤媥媦媧媨媩媪媫媬媭媮媯媰媱媲媳媴媵媶媷媸媹媺媻媼媽媾媿嫀嫁嫂嫃嫄嫅嫆嫇嫈嫉嫊嫋嫌嫍嫎嫏嫐嫑嫒嫓嫔嫕嫖嫗嫘嫙嫚嫛嫜嫝嫞嫟嫠嫡嫢嫣嫤嫥嫦嫧嫨嫩嫪嫫嫬嫭嫮嫯嫰嫱嫲嫳嫴嫵嫶嫷嫸嫹嫺嫻嫼嫽嫾嫿嬀嬁嬂嬃嬄嬅嬆嬇嬈嬉嬊嬋嬌嬍嬎嬏嬐嬑嬒嬓嬔嬕嬖嬗嬘嬙嬚嬛嬜嬝嬞嬟嬠嬡嬢嬣嬤嬥嬦嬧嬨嬩嬪嬫嬬嬭嬮嬯嬰嬱嬲嬳嬴嬵嬶嬷嬸嬹嬺嬻嬼嬽嬾嬿孀孁孂孃孄孅孆孇孈孉孊孋孌孍孎孏子孑孒孓孔孕孖字存孙孚孛孜孝孞孟孠孡孢季孤孥学孧孨孩孪孫孬孭孮孯孰孱孲孳孴孵孶孷學孹孺孻孼孽孾孿宀宁宂它宄宅宆宇守安宊宋完宍宎宏宐宑宒宓宔宕宖宗官宙定宛宜宝实実宠审客宣室宥宦宧宨宩宪宫宬宭宮宯宰宱宲害宴宵家宷宸容宺宻宼宽宾宿寀寁寂寃寄寅密寇寈寉寊寋富寍寎寏寐寑寒寓寔寕寖寗寘寙寚寛寜寝寞察寠寡寢寣寤寥實寧寨審寪寫寬寭寮寯寰寱寲寳寴寵寶寷寸对寺寻导寽対寿尀封専尃射尅将將專尉尊尋尌對導小尐少尒尓尔尕尖尗尘尙尚尛尜尝尞尟尠尡尢尣尤尥尦尧尨尩尪尫尬尭尮尯尰就尲尳尴尵尶尷尸尹尺尻尼尽尾尿局屁层屃屄居屆屇屈屉届屋屌屍屎屏屐屑屒屓屔展屖屗屘屙屚屛屜屝属屟屠屡屢屣層履屦屧屨屩屪屫屬屭屮屯屰山屲屳屴屵屶屷屸屹屺屻屼屽屾屿岀岁岂岃岄岅岆岇岈岉岊岋岌岍岎岏岐岑岒岓岔岕岖岗岘岙岚岛岜岝岞岟岠岡岢岣岤岥岦岧岨岩岪岫岬岭岮岯岰岱岲岳岴岵岶岷岸岹岺岻岼岽岾岿峀峁峂峃峄峅峆峇峈峉峊峋峌峍峎峏峐峑峒峓峔峕峖峗峘峙峚峛峜峝峞峟峠峡峢峣峤峥峦峧峨峩峪峫峬峭峮峯峰峱峲峳峴峵島峷峸峹峺峻峼峽峾峿崀崁崂崃崄崅崆崇崈崉崊崋崌崍崎崏崐崑崒崓崔崕崖崗崘崙崚崛崜崝崞崟崠崡崢崣崤崥崦崧崨崩崪崫崬崭崮崯崰崱崲崳崴崵崶崷崸崹崺崻崼崽崾崿嵀嵁嵂嵃嵄嵅嵆嵇嵈嵉嵊嵋嵌嵍嵎嵏嵐嵑嵒嵓嵔嵕嵖嵗嵘嵙嵚嵛嵜嵝嵞嵟嵠嵡嵢嵣嵤嵥嵦嵧嵨嵩嵪嵫嵬嵭嵮嵯嵰嵱嵲嵳嵴嵵嵶嵷嵸嵹嵺嵻嵼嵽嵾嵿嶀嶁嶂嶃嶄嶅嶆嶇嶈嶉嶊嶋嶌嶍嶎嶏嶐嶑嶒嶓嶔嶕嶖嶗嶘嶙嶚嶛嶜嶝嶞嶟嶠嶡嶢嶣嶤嶥嶦嶧嶨嶩嶪嶫嶬嶭嶮嶯嶰嶱嶲嶳嶴嶵嶶嶷嶸嶹嶺嶻嶼嶽嶾嶿巀巁巂巃巄巅巆巇巈巉巊巋巌巍巎巏巐巑巒巓巔巕巖巗巘巙巚巛巜川州巟巠巡巢巣巤工左巧巨巩巪巫巬巭差巯巰己已巳巴巵巶巷巸巹巺巻巼巽巾巿帀币市布帄帅帆帇师帉帊帋希帍帎帏帐帑帒帓帔帕帖帗帘帙帚帛帜帝帞帟帠帡帢帣帤帥带帧帨帩帪師帬席帮帯帰帱帲帳帴帵帶帷常帹帺帻帼帽帾帿幀幁幂幃幄幅幆幇幈幉幊幋幌幍幎幏幐幑幒幓幔幕幖幗幘幙幚幛幜幝幞幟幠幡幢幣幤幥幦幧幨幩幪幫幬幭幮幯幰幱干平年幵并幷幸幹幺幻幼幽幾广庀庁庂広庄庅庆庇庈庉床庋庌庍庎序庐庑庒库应底庖店庘庙庚庛府庝庞废庠庡庢庣庤庥度座庨庩庪庫庬庭庮庯庰庱庲庳庴庵庶康庸庹庺庻庼庽庾庿廀廁廂廃廄廅廆廇廈廉廊廋廌廍廎廏廐廑廒廓廔廕廖廗廘廙廚廛廜廝廞廟廠廡廢廣廤廥廦廧廨廩廪廫廬廭廮廯廰廱廲廳廴廵延廷廸廹建廻廼廽廾廿开弁异弃弄弅弆弇弈弉弊弋弌弍弎式弐弑弒弓弔引弖弗弘弙弚弛弜弝弞弟张弡弢弣弤弥弦弧弨弩弪弫弬弭弮弯弰弱弲弳弴張弶強弸弹强弻弼弽弾弿彀彁彂彃彄彅彆彇彈彉彊彋彌彍彎彏彐彑归当彔录彖彗彘彙彚彛彜彝彞彟彠彡形彣彤彥彦彧彨彩彪彫彬彭彮彯彰影彲彳彴彵彶彷彸役彺彻彼彽彾彿往征徂徃径待徆徇很徉徊律後徍徎徏徐徑徒従徔徕徖得徘徙徚徛徜徝從徟徠御徢徣徤徥徦徧徨復循徫徬徭微徯徰徱徲徳徴徵徶德徸徹徺徻徼徽徾徿忀忁忂心忄必忆忇忈忉忊忋忌忍忎忏忐忑忒忓忔忕忖志忘忙忚忛応忝忞忟忠忡忢忣忤忥忦忧忨忩忪快忬忭忮忯忰忱忲忳忴念忶忷忸忹忺忻忼忽忾忿怀态怂怃怄怅怆怇怈怉怊怋怌怍怎怏怐怑怒怓怔怕怖怗怘怙怚怛怜思怞怟怠怡怢怣怤急怦性怨怩怪怫怬怭怮怯怰怱怲怳怴怵怶怷怸怹怺总怼怽怾怿恀恁恂恃恄恅恆恇恈恉恊恋恌恍恎恏恐恑恒恓恔恕恖恗恘恙恚恛恜恝恞恟恠恡恢恣恤恥恦恧恨恩恪恫恬恭恮息恰恱恲恳恴恵恶恷恸恹恺恻恼恽恾恿悀悁悂悃悄悅悆悇悈悉悊悋悌悍悎悏悐悑悒悓悔悕悖悗悘悙悚悛悜悝悞悟悠悡悢患悤悥悦悧您悩悪悫悬悭悮悯悰悱悲悳悴悵悶悷悸悹悺悻悼悽悾悿惀惁惂惃惄情惆惇惈惉惊惋惌惍惎惏惐惑惒惓惔惕惖惗惘惙惚惛惜惝惞惟惠惡惢惣惤惥惦惧惨惩惪惫惬惭惮惯惰惱惲想惴惵惶惷惸惹惺惻惼惽惾惿愀愁愂愃愄愅愆愇愈愉愊愋愌愍愎意愐愑愒愓愔愕愖愗愘愙愚愛愜愝愞感愠愡愢愣愤愥愦愧愨愩愪愫愬愭愮愯愰愱愲愳愴愵愶愷愸愹愺愻愼愽愾愿慀慁慂慃慄慅慆慇慈慉慊態慌慍慎慏慐慑慒慓慔慕慖慗慘慙慚慛慜慝慞慟慠慡慢慣慤慥慦慧慨慩慪慫慬慭慮慯慰慱慲慳慴慵慶慷慸慹慺慻慼慽慾慿憀憁憂憃憄憅憆憇憈憉憊憋憌憍憎憏憐憑憒憓憔憕憖憗憘憙憚憛憜憝憞憟憠憡憢憣憤憥憦憧憨憩憪憫憬憭憮憯憰憱憲憳憴憵憶憷憸憹憺憻憼憽憾憿懀懁懂懃懄懅懆懇懈應懊懋懌懍懎懏懐懑懒懓懔懕懖懗懘懙懚懛懜懝懞懟懠懡懢懣懤懥懦懧懨懩懪懫懬懭懮懯懰懱懲懳懴懵懶懷懸懹懺懻懼懽懾懿戀戁戂戃戄戅戆戇戈戉戊戋戌戍戎戏成我戒戓戔戕或戗战戙戚戛戜戝戞戟戠戡戢戣戤戥戦戧戨戩截戫戬戭戮戯戰戱戲戳戴戵戶户戸戹戺戻戼戽戾房所扁扂扃扄扅扆扇扈扉扊手扌才扎扏扐扑扒打扔払扖扗托扙扚扛扜扝扞扟扠扡扢扣扤扥扦执扨扩扪扫扬扭扮扯扰扱扲扳扴扵扶扷扸批扺扻扼扽找承技抁抂抃抄抅抆抇抈抉把抋抌抍抎抏抐抑抒抓抔投抖抗折抙抚抛抜抝択抟抠抡抢抣护报抦抧抨抩抪披抬抭抮抯抰抱抲抳抴抵抶抷抸抹抺抻押抽抾抿拀拁拂拃拄担拆拇拈拉拊拋拌拍拎拏拐拑拒拓拔拕拖拗拘拙拚招拜拝拞拟拠拡拢拣拤拥拦拧拨择拪拫括拭拮拯拰拱拲拳拴拵拶拷拸拹拺拻拼拽拾拿挀持挂挃挄挅挆指挈按挊挋挌挍挎挏挐挑挒挓挔挕挖挗挘挙挚挛挜挝挞挟挠挡挢挣挤挥挦挧挨挩挪挫挬挭挮振挰挱挲挳挴挵挶挷挸挹挺挻挼挽挾挿捀捁捂捃捄捅捆捇捈捉捊捋捌捍捎捏捐捑捒捓捔捕捖捗捘捙捚捛捜捝捞损捠捡换捣捤捥捦捧捨捩捪捫捬捭据捯捰捱捲捳捴捵捶捷捸捹捺捻捼捽捾捿掀掁掂掃掄掅掆掇授掉掊掋掌掍掎掏掐掑排掓掔掕掖掗掘掙掚掛掜掝掞掟掠採探掣掤接掦控推掩措掫掬掭掮掯掰掱掲掳掴掵掶掷掸掹掺掻掼掽掾掿揀揁揂揃揄揅揆揇揈揉揊揋揌揍揎描提揑插揓揔揕揖揗揘揙揚換揜揝揞揟揠握揢揣揤揥揦揧揨揩揪揫揬揭揮揯揰揱揲揳援揵揶揷揸揹揺揻揼揽揾揿搀搁搂搃搄搅搆搇搈搉搊搋搌損搎搏搐搑搒搓搔搕搖搗搘搙搚搛搜搝搞搟搠搡搢搣搤搥搦搧搨搩搪搫搬搭搮搯搰搱搲搳搴搵搶搷搸搹携搻搼搽搾搿摀摁摂摃摄摅摆摇摈摉摊摋摌摍摎摏摐摑摒摓摔摕摖摗摘摙摚摛摜摝摞摟摠摡摢摣摤摥摦摧摨摩摪摫摬摭摮摯摰摱摲摳摴摵摶摷摸摹摺摻摼摽摾摿撀撁撂撃撄撅撆撇撈撉撊撋撌撍撎撏撐撑撒撓撔撕撖撗撘撙撚撛撜撝撞撟撠撡撢撣撤撥撦撧撨撩撪撫撬播撮撯撰撱撲撳撴撵撶撷撸撹撺撻撼撽撾撿擀擁擂擃擄擅擆擇擈擉擊擋擌操擎擏擐擑擒擓擔擕擖擗擘擙據擛擜擝擞擟擠擡擢擣擤擥擦擧擨擩擪擫擬擭擮擯擰擱擲擳擴擵擶擷擸擹擺擻擼擽擾擿攀攁攂攃攄攅攆攇攈攉攊攋攌攍攎攏攐攑攒攓攔攕攖攗攘攙攚攛攜攝攞攟攠攡攢攣攤攥攦攧攨攩攪攫攬攭攮支攰攱攲攳攴攵收攷攸改攺攻攼攽放政敀敁敂敃敄故敆敇效敉敊敋敌敍敎敏敐救敒敓敔敕敖敗敘教敚敛敜敝敞敟敠敡敢散敤敥敦敧敨敩敪敫敬敭敮敯数敱敲敳整敵敶敷數敹敺敻敼敽敾敿斀斁斂斃斄斅斆文斈斉斊斋斌斍斎斏斐斑斒斓斔斕斖斗斘料斚斛斜斝斞斟斠斡斢斣斤斥斦斧斨斩斪斫斬断斮斯新斱斲斳斴斵斶斷斸方斺斻於施斾斿旀旁旂旃旄旅旆旇旈旉旊旋旌旍旎族旐旑旒旓旔旕旖旗旘旙旚旛旜旝旞旟无旡既旣旤日旦旧旨早旪旫旬旭旮旯旰旱旲旳旴旵时旷旸旹旺旻旼旽旾旿昀昁昂昃昄昅昆昇昈昉昊昋昌昍明昏昐昑昒易昔昕昖昗昘昙昚昛昜昝昞星映昡昢昣昤春昦昧昨昩昪昫昬昭昮是昰昱昲昳昴昵昶昷昸昹昺昻昼昽显昿晀晁時晃晄晅晆晇晈晉晊晋晌晍晎晏晐晑晒晓晔晕晖晗晘晙晚晛晜晝晞晟晠晡晢晣晤晥晦晧晨晩晪晫晬晭普景晰晱晲晳晴晵晶晷晸晹智晻晼晽晾晿暀暁暂暃暄暅暆暇暈暉暊暋暌暍暎暏暐暑暒暓暔暕暖暗暘暙暚暛暜暝暞暟暠暡暢暣暤暥暦暧暨暩暪暫暬暭暮暯暰暱暲暳暴暵暶暷暸暹暺暻暼暽暾暿曀曁曂曃曄曅曆曇曈曉曊曋曌曍曎曏曐曑曒曓曔曕曖曗曘曙曚曛曜曝曞曟曠曡曢曣曤曥曦曧曨曩曪曫曬曭曮曯曰曱曲曳更曵曶曷書曹曺曻曼曽曾替最朁朂會朄朅朆朇月有朊朋朌服朎朏朐朑朒朓朔朕朖朗朘朙朚望朜朝朞期朠朡朢朣朤朥朦朧木朩未末本札朮术朰朱朲朳朴朵朶朷朸朹机朻朼朽朾朿杀杁杂权杄杅杆杇杈杉杊杋杌杍李杏材村杒杓杔杕杖杗杘杙杚杛杜杝杞束杠条杢杣杤来杦杧杨杩杪杫杬杭杮杯杰東杲杳杴杵杶杷杸杹杺杻杼杽松板枀极枂枃构枅枆枇枈枉枊枋枌枍枎枏析枑枒枓枔枕枖林枘枙枚枛果枝枞枟枠枡枢枣枤枥枦枧枨枩枪枫枬枭枮枯枰枱枲枳枴枵架枷枸枹枺枻枼枽枾枿柀柁柂柃柄柅柆柇柈柉柊柋柌柍柎柏某柑柒染柔柕柖柗柘柙柚柛柜柝柞柟柠柡柢柣柤查柦柧柨柩柪柫柬柭柮柯柰柱柲柳柴柵柶柷柸柹柺査柼柽柾柿栀栁栂栃栄栅栆标栈栉栊栋栌栍栎栏栐树栒栓栔栕栖栗栘栙栚栛栜栝栞栟栠校栢栣栤栥栦栧栨栩株栫栬栭栮栯栰栱栲栳栴栵栶样核根栺栻格栽栾栿桀桁桂桃桄桅框桇案桉桊桋桌桍桎桏桐桑桒桓桔桕桖桗桘桙桚桛桜桝桞桟桠桡桢档桤桥桦桧桨桩桪桫桬桭桮桯桰桱桲桳桴桵桶桷桸桹桺桻桼桽桾桿梀梁梂梃梄梅梆梇梈梉梊梋梌梍梎梏梐梑梒梓梔梕梖梗梘梙梚梛梜條梞梟梠梡梢梣梤梥梦梧梨梩梪梫梬梭梮梯械梱梲梳梴梵梶梷梸梹梺梻梼梽梾梿检棁棂棃棄棅棆棇棈棉棊棋棌棍棎棏棐棑棒棓棔棕棖棗棘棙棚棛棜棝棞棟棠棡棢棣棤棥棦棧棨棩棪棫棬棭森棯棰棱棲棳棴棵棶棷棸棹棺棻棼棽棾棿椀椁椂椃椄椅椆椇椈椉椊椋椌植椎椏椐椑椒椓椔椕椖椗椘椙椚椛検椝椞椟椠椡椢椣椤椥椦椧椨椩椪椫椬椭椮椯椰椱椲椳椴椵椶椷椸椹椺椻椼椽椾椿楀楁楂楃楄楅楆楇楈楉楊楋楌楍楎楏楐楑楒楓楔楕楖楗楘楙楚楛楜楝楞楟楠楡楢楣楤楥楦楧楨楩楪楫楬業楮楯楰楱楲楳楴極楶楷楸楹楺楻楼楽楾楿榀榁概榃榄榅榆榇榈榉榊榋榌榍榎榏榐榑榒榓榔榕榖榗榘榙榚榛榜榝榞榟榠榡榢榣榤榥榦榧榨榩榪榫榬榭榮榯榰榱榲榳榴榵榶榷榸榹榺榻榼榽榾榿槀槁槂槃槄槅槆槇槈槉槊構槌槍槎槏槐槑槒槓槔槕槖槗様槙槚槛槜槝槞槟槠槡槢槣槤槥槦槧槨槩槪槫槬槭槮槯槰槱槲槳槴槵槶槷槸槹槺槻槼槽槾槿樀樁樂樃樄樅樆樇樈樉樊樋樌樍樎樏樐樑樒樓樔樕樖樗樘標樚樛樜樝樞樟樠模樢樣樤樥樦樧樨権横樫樬樭樮樯樰樱樲樳樴樵樶樷樸樹樺樻樼樽樾樿橀橁橂橃橄橅橆橇橈橉橊橋橌橍橎橏橐橑橒橓橔橕橖橗橘橙橚橛橜橝橞機橠橡橢橣橤橥橦橧橨橩橪橫橬橭橮橯橰橱橲橳橴橵橶橷橸橹橺橻橼橽橾橿檀檁檂檃檄檅檆檇檈檉檊檋檌檍檎檏檐檑檒檓檔檕檖檗檘檙檚檛檜檝檞檟檠檡檢檣檤檥檦檧檨檩檪檫檬檭檮檯檰檱檲檳檴檵檶檷檸檹檺檻檼檽檾檿櫀櫁櫂櫃櫄櫅櫆櫇櫈櫉櫊櫋櫌櫍櫎櫏櫐櫑櫒櫓櫔櫕櫖櫗櫘櫙櫚櫛櫜櫝櫞櫟櫠櫡櫢櫣櫤櫥櫦櫧櫨櫩櫪櫫櫬櫭櫮櫯櫰櫱櫲櫳櫴櫵櫶櫷櫸櫹櫺櫻櫼櫽櫾櫿欀欁欂欃欄欅欆欇欈欉權欋欌欍欎欏欐欑欒欓欔欕欖欗欘欙欚欛欜欝欞欟欠次欢欣欤欥欦欧欨欩欪欫欬欭欮欯欰欱欲欳欴欵欶欷欸欹欺欻欼欽款欿歀歁歂歃歄歅歆歇歈歉歊歋歌歍歎歏歐歑歒歓歔歕歖歗歘歙歚歛歜歝歞歟歠歡止正此步武歧歨歩歪歫歬歭歮歯歰歱歲歳歴歵歶歷歸歹歺死歼歽歾歿殀殁殂殃殄殅殆殇殈殉殊残殌殍殎殏殐殑殒殓殔殕殖殗殘殙殚殛殜殝殞殟殠殡殢殣殤殥殦殧殨殩殪殫殬殭殮殯殰殱殲殳殴段殶殷殸殹殺殻殼殽殾殿毀毁毂毃毄毅毆毇毈毉毊毋毌母毎每毐毑毒毓比毕毖毗毘毙毚毛毜毝毞毟毠毡毢毣毤毥毦毧毨毩毪毫毬毭毮毯毰毱毲毳毴毵毶毷毸毹毺毻毼毽毾毿氀氁氂氃氄氅氆氇氈氉氊氋氌氍氎氏氐民氒氓气氕氖気氘氙氚氛氜氝氞氟氠氡氢氣氤氥氦氧氨氩氪氫氬氭氮氯氰氱氲氳水氵氶氷永氹氺氻氼氽氾氿汀汁求汃汄汅汆汇汈汉汊汋汌汍汎汏汐汑汒汓汔汕汖汗汘汙汚汛汜汝汞江池污汢汣汤汥汦汧汨汩汪汫汬汭汮汯汰汱汲汳汴汵汶汷汸汹決汻汼汽汾汿沀沁沂沃沄沅沆沇沈沉沊沋沌沍沎沏沐沑沒沓沔沕沖沗沘沙沚沛沜沝沞沟沠没沢沣沤沥沦沧沨沩沪沫沬沭沮沯沰沱沲河沴沵沶沷沸油沺治沼沽沾沿泀況泂泃泄泅泆泇泈泉泊泋泌泍泎泏泐泑泒泓泔法泖泗泘泙泚泛泜泝泞泟泠泡波泣泤泥泦泧注泩泪泫泬泭泮泯泰泱泲泳泴泵泶泷泸泹泺泻泼泽泾泿洀洁洂洃洄洅洆洇洈洉洊洋洌洍洎洏洐洑洒洓洔洕洖洗洘洙洚洛洜洝洞洟洠洡洢洣洤津洦洧洨洩洪洫洬洭洮洯洰洱洲洳洴洵洶洷洸洹洺活洼洽派洿浀流浂浃浄浅浆浇浈浉浊测浌浍济浏浐浑浒浓浔浕浖浗浘浙浚浛浜浝浞浟浠浡浢浣浤浥浦浧浨浩浪浫浬浭浮浯浰浱浲浳浴浵浶海浸浹浺浻浼浽浾浿涀涁涂涃涄涅涆涇消涉涊涋涌涍涎涏涐涑涒涓涔涕涖涗涘涙涚涛涜涝涞涟涠涡涢涣涤涥润涧涨涩涪涫涬涭涮涯涰涱液涳涴涵涶涷涸涹涺涻涼涽涾涿淀淁淂淃淄淅淆淇淈淉淊淋淌淍淎淏淐淑淒淓淔淕淖淗淘淙淚淛淜淝淞淟淠淡淢淣淤淥淦淧淨淩淪淫淬淭淮淯淰深淲淳淴淵淶混淸淹淺添淼淽淾淿渀渁渂渃渄清渆渇済渉渊渋渌渍渎渏渐渑渒渓渔渕渖渗渘渙渚減渜渝渞渟渠渡渢渣渤渥渦渧渨温渪渫測渭渮港渰渱渲渳渴渵渶渷游渹渺渻渼渽渾渿湀湁湂湃湄湅湆湇湈湉湊湋湌湍湎湏湐湑湒湓湔湕湖湗湘湙湚湛湜湝湞湟湠湡湢湣湤湥湦湧湨湩湪湫湬湭湮湯湰湱湲湳湴湵湶湷湸湹湺湻湼湽湾湿満溁溂溃溄溅溆溇溈溉溊溋溌溍溎溏源溑溒溓溔溕準溗溘溙溚溛溜溝溞溟溠溡溢溣溤溥溦溧溨溩溪溫溬溭溮溯溰溱溲溳溴溵溶溷溸溹溺溻溼溽溾溿滀滁滂滃滄滅滆滇滈滉滊滋滌滍滎滏滐滑滒滓滔滕滖滗滘滙滚滛滜滝滞滟滠满滢滣滤滥滦滧滨滩滪滫滬滭滮滯滰滱滲滳滴滵滶滷滸滹滺滻滼滽滾滿漀漁漂漃漄漅漆漇漈漉漊漋漌漍漎漏漐漑漒漓演漕漖漗漘漙漚漛漜漝漞漟漠漡漢漣漤漥漦漧漨漩漪漫漬漭漮漯漰漱漲漳漴漵漶漷漸漹漺漻漼漽漾漿潀潁潂潃潄潅潆潇潈潉潊潋潌潍潎潏潐潑潒潓潔潕潖潗潘潙潚潛潜潝潞潟潠潡潢潣潤潥潦潧潨潩潪潫潬潭潮潯潰潱潲潳潴潵潶潷潸潹潺潻潼潽潾潿澀澁澂澃澄澅澆澇澈澉澊澋澌澍澎澏澐澑澒澓澔澕澖澗澘澙澚澛澜澝澞澟澠澡澢澣澤澥澦澧澨澩澪澫澬澭澮澯澰澱澲澳澴澵澶澷澸澹澺澻澼澽澾澿激濁濂濃濄濅濆濇濈濉濊濋濌濍濎濏濐濑濒濓濔濕濖濗濘濙濚濛濜濝濞濟濠濡濢濣濤濥濦濧濨濩濪濫濬濭濮濯濰濱濲濳濴濵濶濷濸濹濺濻濼濽濾濿瀀瀁瀂瀃瀄瀅瀆瀇瀈瀉瀊瀋瀌瀍瀎瀏瀐瀑瀒瀓瀔瀕瀖瀗瀘瀙瀚瀛瀜瀝瀞瀟瀠瀡瀢瀣瀤瀥瀦瀧瀨瀩瀪瀫瀬瀭瀮瀯瀰瀱瀲瀳瀴瀵瀶瀷瀸瀹瀺瀻瀼瀽瀾瀿灀灁灂灃灄灅灆灇灈灉灊灋灌灍灎灏灐灑灒灓灔灕灖灗灘灙灚灛灜灝灞灟灠灡灢灣灤灥灦灧灨灩灪火灬灭灮灯灰灱灲灳灴灵灶灷灸灹灺灻灼災灾灿炀炁炂炃炄炅炆炇炈炉炊炋炌炍炎炏炐炑炒炓炔炕炖炗炘炙炚炛炜炝炞炟炠炡炢炣炤炥炦炧炨炩炪炫炬炭炮炯炰炱炲炳炴炵炶炷炸点為炻炼炽炾炿烀烁烂烃烄烅烆烇烈烉烊烋烌烍烎烏烐烑烒烓烔烕烖烗烘烙烚烛烜烝烞烟烠烡烢烣烤烥烦烧烨烩烪烫烬热烮烯烰烱烲烳烴烵烶烷烸烹烺烻烼烽烾烿焀焁焂焃焄焅焆焇焈焉焊焋焌焍焎焏焐焑焒焓焔焕焖焗焘焙焚焛焜焝焞焟焠無焢焣焤焥焦焧焨焩焪焫焬焭焮焯焰焱焲焳焴焵然焷焸焹焺焻焼焽焾焿煀煁煂煃煄煅煆煇煈煉煊煋煌煍煎煏煐煑煒煓煔煕煖煗煘煙煚煛煜煝煞煟煠煡煢煣煤煥煦照煨煩煪煫煬煭煮煯煰煱煲煳煴煵煶煷煸煹煺煻煼煽煾煿熀熁熂熃熄熅熆熇熈熉熊熋熌熍熎熏熐熑熒熓熔熕熖熗熘熙熚熛熜熝熞熟熠熡熢熣熤熥熦熧熨熩熪熫熬熭熮熯熰熱熲熳熴熵熶熷熸熹熺熻熼熽熾熿燀燁燂燃燄燅燆燇燈燉燊燋燌燍燎燏燐燑燒燓燔燕燖燗燘燙燚燛燜燝燞營燠燡燢燣燤燥燦燧燨燩燪燫燬燭燮燯燰燱燲燳燴燵燶燷燸燹燺燻燼燽燾燿爀爁爂爃爄爅爆爇爈爉爊爋爌爍爎爏爐爑爒爓爔爕爖爗爘爙爚爛爜爝爞爟爠爡爢爣爤爥爦爧爨爩爪爫爬爭爮爯爰爱爲爳爴爵父爷爸爹爺爻爼爽爾爿牀牁牂牃牄牅牆片版牉牊牋牌牍牎牏牐牑牒牓牔牕牖牗牘牙牚牛牜牝牞牟牠牡牢牣牤牥牦牧牨物牪牫牬牭牮牯牰牱牲牳牴牵牶牷牸特牺牻牼牽牾牿犀犁犂犃犄犅犆犇犈犉犊犋犌犍犎犏犐犑犒犓犔犕犖犗犘犙犚犛犜犝犞犟犠犡犢犣犤犥犦犧犨犩犪犫犬犭犮犯犰犱犲犳犴犵状犷犸犹犺犻犼犽犾犿狀狁狂狃狄狅狆狇狈狉狊狋狌狍狎狏狐狑狒狓狔狕狖狗狘狙狚狛狜狝狞狟狠狡狢狣狤狥狦狧狨狩狪狫独狭狮狯狰狱狲狳狴狵狶狷狸狹狺狻狼狽狾狿猀猁猂猃猄猅猆猇猈猉猊猋猌猍猎猏猐猑猒猓猔猕猖猗猘猙猚猛猜猝猞猟猠猡猢猣猤猥猦猧猨猩猪猫猬猭献猯猰猱猲猳猴猵猶猷猸猹猺猻猼猽猾猿獀獁獂獃獄獅獆獇獈獉獊獋獌獍獎獏獐獑獒獓獔獕獖獗獘獙獚獛獜獝獞獟獠獡獢獣獤獥獦獧獨獩獪獫獬獭獮獯獰獱獲獳獴獵獶獷獸獹獺獻獼獽獾獿玀玁玂玃玄玅玆率玈玉玊王玌玍玎玏玐玑玒玓玔玕玖玗玘玙玚玛玜玝玞玟玠玡玢玣玤玥玦玧玨玩玪玫玬玭玮环现玱玲玳玴玵玶玷玸玹玺玻玼玽玾玿珀珁珂珃珄珅珆珇珈珉珊珋珌珍珎珏珐珑珒珓珔珕珖珗珘珙珚珛珜珝珞珟珠珡珢珣珤珥珦珧珨珩珪珫珬班珮珯珰珱珲珳珴珵珶珷珸珹珺珻珼珽現珿琀琁琂球琄琅理琇琈琉琊琋琌琍琎琏琐琑琒琓琔琕琖琗琘琙琚琛琜琝琞琟琠琡琢琣琤琥琦琧琨琩琪琫琬琭琮琯琰琱琲琳琴琵琶琷琸琹琺琻琼琽琾琿瑀瑁瑂瑃瑄瑅瑆瑇瑈瑉瑊瑋瑌瑍瑎瑏瑐瑑瑒瑓瑔瑕瑖瑗瑘瑙瑚瑛瑜瑝瑞瑟瑠瑡瑢瑣瑤瑥瑦瑧瑨瑩瑪瑫瑬瑭瑮瑯瑰瑱瑲瑳瑴瑵瑶瑷瑸瑹瑺瑻瑼瑽瑾瑿璀璁璂璃璄璅璆璇璈璉璊璋璌璍璎璏璐璑璒璓璔璕璖璗璘璙璚璛璜璝璞璟璠璡璢璣璤璥璦璧璨璩璪璫璬璭璮璯環璱璲璳璴璵璶璷璸璹璺璻璼璽璾璿瓀瓁瓂瓃瓄瓅瓆瓇瓈瓉瓊瓋瓌瓍瓎瓏瓐瓑瓒瓓瓔瓕瓖瓗瓘瓙瓚瓛瓜瓝瓞瓟瓠瓡瓢瓣瓤瓥瓦瓧瓨瓩瓪瓫瓬瓭瓮瓯瓰瓱瓲瓳瓴瓵瓶瓷瓸瓹瓺瓻瓼瓽瓾瓿甀甁甂甃甄甅甆甇甈甉甊甋甌甍甎甏甐甑甒甓甔甕甖甗甘甙甚甛甜甝甞生甠甡產産甤甥甦甧用甩甪甫甬甭甮甯田由甲申甴电甶男甸甹町画甼甽甾甿畀畁畂畃畄畅畆畇畈畉畊畋界畍畎畏畐畑畒畓畔畕畖畗畘留畚畛畜畝畞畟畠畡畢畣畤略畦畧畨畩番畫畬畭畮畯異畱畲畳畴畵當畷畸畹畺畻畼畽畾畿疀疁疂疃疄疅疆疇疈疉疊疋疌疍疎疏疐疑疒疓疔疕疖疗疘疙疚疛疜疝疞疟疠疡疢疣疤疥疦疧疨疩疪疫疬疭疮疯疰疱疲疳疴疵疶疷疸疹疺疻疼疽疾疿痀痁痂痃痄病痆症痈痉痊痋痌痍痎痏痐痑痒痓痔痕痖痗痘痙痚痛痜痝痞痟痠痡痢痣痤痥痦痧痨痩痪痫痬痭痮痯痰痱痲痳痴痵痶痷痸痹痺痻痼痽痾痿瘀瘁瘂瘃瘄瘅瘆瘇瘈瘉瘊瘋瘌瘍瘎瘏瘐瘑瘒瘓瘔瘕瘖瘗瘘瘙瘚瘛瘜瘝瘞瘟瘠瘡瘢瘣瘤瘥瘦瘧瘨瘩瘪瘫瘬瘭瘮瘯瘰瘱瘲瘳瘴瘵瘶瘷瘸瘹瘺瘻瘼瘽瘾瘿癀癁療癃癄癅癆癇癈癉癊癋癌癍癎癏癐癑癒癓癔癕癖癗癘癙癚癛癜癝癞癟癠癡癢癣癤癥癦癧癨癩癪癫癬癭癮癯癰癱癲癳癴癵癶癷癸癹発登發白百癿皀皁皂皃的皅皆皇皈皉皊皋皌皍皎皏皐皑皒皓皔皕皖皗皘皙皚皛皜皝皞皟皠皡皢皣皤皥皦皧皨皩皪皫皬皭皮皯皰皱皲皳皴皵皶皷皸皹皺皻皼皽皾皿盀盁盂盃盄盅盆盇盈盉益盋盌盍盎盏盐监盒盓盔盕盖盗盘盙盚盛盜盝盞盟盠盡盢監盤盥盦盧盨盩盪盫盬盭目盯盰盱盲盳直盵盶盷相盹盺盻盼盽盾盿眀省眂眃眄眅眆眇眈眉眊看県眍眎眏眐眑眒眓眔眕眖眗眘眙眚眛眜眝眞真眠眡眢眣眤眥眦眧眨眩眪眫眬眭眮眯眰眱眲眳眴眵眶眷眸眹眺眻眼眽眾眿着睁睂睃睄睅睆睇睈睉睊睋睌睍睎睏睐睑睒睓睔睕睖睗睘睙睚睛睜睝睞睟睠睡睢督睤睥睦睧睨睩睪睫睬睭睮睯睰睱睲睳睴睵睶睷睸睹睺睻睼睽睾睿瞀瞁瞂瞃瞄瞅瞆瞇瞈瞉瞊瞋瞌瞍瞎瞏瞐瞑瞒瞓瞔瞕瞖瞗瞘瞙瞚瞛瞜瞝瞞瞟瞠瞡瞢瞣瞤瞥瞦瞧瞨瞩瞪瞫瞬瞭瞮瞯瞰瞱瞲瞳瞴瞵瞶瞷瞸瞹瞺瞻瞼瞽瞾瞿矀矁矂矃矄矅矆矇矈矉矊矋矌矍矎矏矐矑矒矓矔矕矖矗矘矙矚矛矜矝矞矟矠矡矢矣矤知矦矧矨矩矪矫矬短矮矯矰矱矲石矴矵矶矷矸矹矺矻矼矽矾矿砀码砂砃砄砅砆砇砈砉砊砋砌砍砎砏砐砑砒砓研砕砖砗砘砙砚砛砜砝砞砟砠砡砢砣砤砥砦砧砨砩砪砫砬砭砮砯砰砱砲砳破砵砶砷砸砹砺砻砼砽砾砿础硁硂硃硄硅硆硇硈硉硊硋硌硍硎硏硐硑硒硓硔硕硖硗硘硙硚硛硜硝硞硟硠硡硢硣硤硥硦硧硨硩硪硫硬硭确硯硰硱硲硳硴硵硶硷硸硹硺硻硼硽硾硿碀碁碂碃碄碅碆碇碈碉碊碋碌碍碎碏碐碑碒碓碔碕碖碗碘碙碚碛碜碝碞碟碠碡碢碣碤碥碦碧碨碩碪碫碬碭碮碯碰碱碲碳碴碵碶碷碸碹確碻碼碽碾碿磀磁磂磃磄磅磆磇磈磉磊磋磌磍磎磏磐磑磒磓磔磕磖磗磘磙磚磛磜磝磞磟磠磡磢磣磤磥磦磧磨磩磪磫磬磭磮磯磰磱磲磳磴磵磶磷磸磹磺磻磼磽磾磿礀礁礂礃礄礅礆礇礈礉礊礋礌礍礎礏礐礑礒礓礔礕礖礗礘礙礚礛礜礝礞礟礠礡礢礣礤礥礦礧礨礩礪礫礬礭礮礯礰礱礲礳礴礵礶礷礸礹示礻礼礽社礿祀祁祂祃祄祅祆祇祈祉祊祋祌祍祎祏祐祑祒祓祔祕祖祗祘祙祚祛祜祝神祟祠祡祢祣祤祥祦祧票祩祪祫祬祭祮祯祰祱祲祳祴祵祶祷祸祹祺祻祼祽祾祿禀禁禂禃禄禅禆禇禈禉禊禋禌禍禎福禐禑禒禓禔禕禖禗禘禙禚禛禜禝禞禟禠禡禢禣禤禥禦禧禨禩禪禫禬禭禮禯禰禱禲禳禴禵禶禷禸禹禺离禼禽禾禿秀私秂秃秄秅秆秇秈秉秊秋秌种秎秏秐科秒秓秔秕秖秗秘秙秚秛秜秝秞租秠秡秢秣秤秥秦秧秨秩秪秫秬秭秮积称秱秲秳秴秵秶秷秸秹秺移秼秽秾秿稀稁稂稃稄稅稆稇稈稉稊程稌稍税稏稐稑稒稓稔稕稖稗稘稙稚稛稜稝稞稟稠稡稢稣稤稥稦稧稨稩稪稫稬稭種稯稰稱稲稳稴稵稶稷稸稹稺稻稼稽稾稿穀穁穂穃穄穅穆穇穈穉穊穋穌積穎穏穐穑穒穓穔穕穖穗穘穙穚穛穜穝穞穟穠穡穢穣穤穥穦穧穨穩穪穫穬穭穮穯穰穱穲穳穴穵究穷穸穹空穻穼穽穾穿窀突窂窃窄窅窆窇窈窉窊窋窌窍窎窏窐窑窒窓窔窕窖窗窘窙窚窛窜窝窞窟窠窡窢窣窤窥窦窧窨窩窪窫窬窭窮窯窰窱窲窳窴窵窶窷窸窹窺窻窼窽窾窿竀竁竂竃竄竅竆竇竈竉竊立竌竍竎竏竐竑竒竓竔竕竖竗竘站竚竛竜竝竞竟章竡竢竣竤童竦竧竨竩竪竫竬竭竮端竰竱竲竳竴竵競竷竸竹竺竻竼竽竾竿笀笁笂笃笄笅笆笇笈笉笊笋笌笍笎笏笐笑笒笓笔笕笖笗笘笙笚笛笜笝笞笟笠笡笢笣笤笥符笧笨笩笪笫第笭笮笯笰笱笲笳笴笵笶笷笸笹笺笻笼笽笾笿筀筁筂筃筄筅筆筇筈等筊筋筌筍筎筏筐筑筒筓答筕策筗筘筙筚筛筜筝筞筟筠筡筢筣筤筥筦筧筨筩筪筫筬筭筮筯筰筱筲筳筴筵筶筷筸筹筺筻筼筽签筿简箁箂箃箄箅箆箇箈箉箊箋箌箍箎箏箐箑箒箓箔箕箖算箘箙箚箛箜箝箞箟箠管箢箣箤箥箦箧箨箩箪箫箬箭箮箯箰箱箲箳箴箵箶箷箸箹箺箻箼箽箾箿節篁篂篃範篅篆篇篈築篊篋篌篍篎篏篐篑篒篓篔篕篖篗篘篙篚篛篜篝篞篟篠篡篢篣篤篥篦篧篨篩篪篫篬篭篮篯篰篱篲篳篴篵篶篷篸篹篺篻篼篽篾篿簀簁簂簃簄簅簆簇簈簉簊簋簌簍簎簏簐簑簒簓簔簕簖簗簘簙簚簛簜簝簞簟簠簡簢簣簤簥簦簧簨簩簪簫簬簭簮簯簰簱簲簳簴簵簶簷簸簹簺簻簼簽簾簿籀籁籂籃籄籅籆籇籈籉籊籋籌籍籎籏籐籑籒籓籔籕籖籗籘籙籚籛籜籝籞籟籠籡籢籣籤籥籦籧籨籩籪籫籬籭籮籯籰籱籲米籴籵籶籷籸籹籺类籼籽籾籿粀粁粂粃粄粅粆粇粈粉粊粋粌粍粎粏粐粑粒粓粔粕粖粗粘粙粚粛粜粝粞粟粠粡粢粣粤粥粦粧粨粩粪粫粬粭粮粯粰粱粲粳粴粵粶粷粸粹粺粻粼粽精粿糀糁糂糃糄糅糆糇糈糉糊糋糌糍糎糏糐糑糒糓糔糕糖糗糘糙糚糛糜糝糞糟糠糡糢糣糤糥糦糧糨糩糪糫糬糭糮糯糰糱糲糳糴糵糶糷糸糹糺系糼糽糾糿紀紁紂紃約紅紆紇紈紉紊紋紌納紎紏紐紑紒紓純紕紖紗紘紙級紛紜紝紞紟素紡索紣紤紥紦紧紨紩紪紫紬紭紮累細紱紲紳紴紵紶紷紸紹紺紻紼紽紾紿絀絁終絃組絅絆絇絈絉絊絋経絍絎絏結絑絒絓絔絕絖絗絘絙絚絛絜絝絞絟絠絡絢絣絤絥給絧絨絩絪絫絬絭絮絯絰統絲絳絴絵絶絷絸絹絺絻絼絽絾絿綀綁綂綃綄綅綆綇綈綉綊綋綌綍綎綏綐綑綒經綔綕綖綗綘継続綛綜綝綞綟綠綡綢綣綤綥綦綧綨綩綪綫綬維綮綯綰綱網綳綴綵綶綷綸綹綺綻綼綽綾綿緀緁緂緃緄緅緆緇緈緉緊緋緌緍緎総緐緑緒緓緔緕緖緗緘緙線緛緜緝緞緟締緡緢緣緤緥緦緧編緩緪緫緬緭緮緯緰緱緲緳練緵緶緷緸緹緺緻緼緽緾緿縀縁縂縃縄縅縆縇縈縉縊縋縌縍縎縏縐縑縒縓縔縕縖縗縘縙縚縛縜縝縞縟縠縡縢縣縤縥縦縧縨縩縪縫縬縭縮縯縰縱縲縳縴縵縶縷縸縹縺縻縼總績縿繀繁繂繃繄繅繆繇繈繉繊繋繌繍繎繏繐繑繒繓織繕繖繗繘繙繚繛繜繝繞繟繠繡繢繣繤繥繦繧繨繩繪繫繬繭繮繯繰繱繲繳繴繵繶繷繸繹繺繻繼繽繾繿纀纁纂纃纄纅纆纇纈纉纊纋續纍纎纏纐纑纒纓纔纕纖纗纘纙纚纛纜纝纞纟纠纡红纣纤纥约级纨纩纪纫纬纭纮纯纰纱纲纳纴纵纶纷纸纹纺纻纼纽纾线绀绁绂练组绅细织终绉绊绋绌绍绎经绐绑绒结绔绕绖绗绘给绚绛络绝绞统绠绡绢绣绤绥绦继绨绩绪绫绬续绮绯绰绱绲绳维绵绶绷绸绹绺绻综绽绾绿缀缁缂缃缄缅缆缇缈缉缊缋缌缍缎缏缐缑缒缓缔缕编缗缘缙缚缛缜缝缞缟缠缡缢缣缤缥缦缧缨缩缪缫缬缭缮缯缰缱缲缳缴缵缶缷缸缹缺缻缼缽缾缿罀罁罂罃罄罅罆罇罈罉罊罋罌罍罎罏罐网罒罓罔罕罖罗罘罙罚罛罜罝罞罟罠罡罢罣罤罥罦罧罨罩罪罫罬罭置罯罰罱署罳罴罵罶罷罸罹罺罻罼罽罾罿羀羁羂羃羄羅羆羇羈羉羊羋羌羍美羏羐羑羒羓羔羕羖羗羘羙羚羛羜羝羞羟羠羡羢羣群羥羦羧羨義羪羫羬羭羮羯羰羱羲羳羴羵羶羷羸羹羺羻羼羽羾羿翀翁翂翃翄翅翆翇翈翉翊翋翌翍翎翏翐翑習翓翔翕翖翗翘翙翚翛翜翝翞翟翠翡翢翣翤翥翦翧翨翩翪翫翬翭翮翯翰翱翲翳翴翵翶翷翸翹翺翻翼翽翾翿耀老耂考耄者耆耇耈耉耊耋而耍耎耏耐耑耒耓耔耕耖耗耘耙耚耛耜耝耞耟耠耡耢耣耤耥耦耧耨耩耪耫耬耭耮耯耰耱耲耳耴耵耶耷耸耹耺耻耼耽耾耿聀聁聂聃聄聅聆聇聈聉聊聋职聍聎聏聐聑聒聓联聕聖聗聘聙聚聛聜聝聞聟聠聡聢聣聤聥聦聧聨聩聪聫聬聭聮聯聰聱聲聳聴聵聶職聸聹聺聻聼聽聾聿肀肁肂肃肄肅肆肇肈肉肊肋肌肍肎肏肐肑肒肓肔肕肖肗肘肙肚肛肜肝肞肟肠股肢肣肤肥肦肧肨肩肪肫肬肭肮肯肰肱育肳肴肵肶肷肸肹肺肻肼肽肾肿胀胁胂胃胄胅胆胇胈胉胊胋背胍胎胏胐胑胒胓胔胕胖胗胘胙胚胛胜胝胞胟胠胡胢胣胤胥胦胧胨胩胪胫胬胭胮胯胰胱胲胳胴胵胶胷胸胹胺胻胼能胾胿脀脁脂脃脄脅脆脇脈脉脊脋脌脍脎脏脐脑脒脓脔脕脖脗脘脙脚脛脜脝脞脟脠脡脢脣脤脥脦脧脨脩脪脫脬脭脮脯脰脱脲脳脴脵脶脷脸脹脺脻脼脽脾脿腀腁腂腃腄腅腆腇腈腉腊腋腌腍腎腏腐腑腒腓腔腕腖腗腘腙腚腛腜腝腞腟腠腡腢腣腤腥腦腧腨腩腪腫腬腭腮腯腰腱腲腳腴腵腶腷腸腹腺腻腼腽腾腿膀膁膂膃膄膅膆膇膈膉膊膋膌膍膎膏膐膑膒膓膔膕膖膗膘膙膚膛膜膝膞膟膠膡膢膣膤膥膦膧膨膩膪膫膬膭膮膯膰膱膲膳膴膵膶膷膸膹膺膻膼膽膾膿臀臁臂臃臄臅臆臇臈臉臊臋臌臍臎臏臐臑臒臓臔臕臖臗臘臙臚臛臜臝臞臟臠臡臢臣臤臥臦臧臨臩自臫臬臭臮臯臰臱臲至致臵臶臷臸臹臺臻臼臽臾臿舀舁舂舃舄舅舆與興舉舊舋舌舍舎舏舐舑舒舓舔舕舖舗舘舙舚舛舜舝舞舟舠舡舢舣舤舥舦舧舨舩航舫般舭舮舯舰舱舲舳舴舵舶舷舸船舺舻舼舽舾舿艀艁艂艃艄艅艆艇艈艉艊艋艌艍艎艏艐艑艒艓艔艕艖艗艘艙艚艛艜艝艞艟艠艡艢艣艤艥艦艧艨艩艪艫艬艭艮良艰艱色艳艴艵艶艷艸艹艺艻艼艽艾艿芀芁节芃芄芅芆芇芈芉芊芋芌芍芎芏芐芑芒芓芔芕芖芗芘芙芚芛芜芝芞芟芠芡芢芣芤芥芦芧芨芩芪芫芬芭芮芯芰花芲芳芴芵芶芷芸芹芺芻芼芽芾芿苀苁苂苃苄苅苆苇苈苉苊苋苌苍苎苏苐苑苒苓苔苕苖苗苘苙苚苛苜苝苞苟苠苡苢苣苤若苦苧苨苩苪苫苬苭苮苯苰英苲苳苴苵苶苷苸苹苺苻苼苽苾苿茀茁茂范茄茅茆茇茈茉茊茋茌茍茎茏茐茑茒茓茔茕茖茗茘茙茚茛茜茝茞茟茠茡茢茣茤茥茦茧茨茩茪茫茬茭茮茯茰茱茲茳茴茵茶茷茸茹茺茻茼茽茾茿荀荁荂荃荄荅荆荇荈草荊荋荌荍荎荏荐荑荒荓荔荕荖荗荘荙荚荛荜荝荞荟荠荡荢荣荤荥荦荧荨荩荪荫荬荭荮药荰荱荲荳荴荵荶荷荸荹荺荻荼荽荾荿莀莁莂莃莄莅莆莇莈莉莊莋莌莍莎莏莐莑莒莓莔莕莖莗莘莙莚莛莜莝莞莟莠莡莢莣莤莥莦莧莨莩莪莫莬莭莮莯莰莱莲莳莴莵莶获莸莹莺莻莼莽莾莿菀菁菂菃菄菅菆菇菈菉菊菋菌菍菎菏菐菑菒菓菔菕菖菗菘菙菚菛菜菝菞菟菠菡菢菣菤菥菦菧菨菩菪菫菬菭菮華菰菱菲菳菴菵菶菷菸菹菺菻菼菽菾菿萀萁萂萃萄萅萆萇萈萉萊萋萌萍萎萏萐萑萒萓萔萕萖萗萘萙萚萛萜萝萞萟萠萡萢萣萤营萦萧萨萩萪萫萬萭萮萯萰萱萲萳萴萵萶萷萸萹萺萻萼落萾萿葀葁葂葃葄葅葆葇葈葉葊葋葌葍葎葏葐葑葒葓葔葕葖著葘葙葚葛葜葝葞葟葠葡葢董葤葥葦葧葨葩葪葫葬葭葮葯葰葱葲葳葴葵葶葷葸葹葺葻葼葽葾葿蒀蒁蒂蒃蒄蒅蒆蒇蒈蒉蒊蒋蒌蒍蒎蒏蒐蒑蒒蒓蒔蒕蒖蒗蒘蒙蒚蒛蒜蒝蒞蒟蒠蒡蒢蒣蒤蒥蒦蒧蒨蒩蒪蒫蒬蒭蒮蒯蒰蒱蒲蒳蒴蒵蒶蒷蒸蒹蒺蒻蒼蒽蒾蒿蓀蓁蓂蓃蓄蓅蓆蓇蓈蓉蓊蓋蓌蓍蓎蓏蓐蓑蓒蓓蓔蓕蓖蓗蓘蓙蓚蓛蓜蓝蓞蓟蓠蓡蓢蓣蓤蓥蓦蓧蓨蓩蓪蓫蓬蓭蓮蓯蓰蓱蓲蓳蓴蓵蓶蓷蓸蓹蓺蓻蓼蓽蓾蓿蔀蔁蔂蔃蔄蔅蔆蔇蔈蔉蔊蔋蔌蔍蔎蔏蔐蔑蔒蔓蔔蔕蔖蔗蔘蔙蔚蔛蔜蔝蔞蔟蔠蔡蔢蔣蔤蔥蔦蔧蔨蔩蔪蔫蔬蔭蔮蔯蔰蔱蔲蔳蔴蔵蔶蔷蔸蔹蔺蔻蔼蔽蔾蔿蕀蕁蕂蕃蕄蕅蕆蕇蕈蕉蕊蕋蕌蕍蕎蕏蕐蕑蕒蕓蕔蕕蕖蕗蕘蕙蕚蕛蕜蕝蕞蕟蕠蕡蕢蕣蕤蕥蕦蕧蕨蕩蕪蕫蕬蕭蕮蕯蕰蕱蕲蕳蕴蕵蕶蕷蕸蕹蕺蕻蕼蕽蕾蕿薀薁薂薃薄薅薆薇薈薉薊薋薌薍薎薏薐薑薒薓薔薕薖薗薘薙薚薛薜薝薞薟薠薡薢薣薤薥薦薧薨薩薪薫薬薭薮薯薰薱薲薳薴薵薶薷薸薹薺薻薼薽薾薿藀藁藂藃藄藅藆藇藈藉藊藋藌藍藎藏藐藑藒藓藔藕藖藗藘藙藚藛藜藝藞藟藠藡藢藣藤藥藦藧藨藩藪藫藬藭藮藯藰藱藲藳藴藵藶藷藸藹藺藻藼藽藾藿蘀蘁蘂蘃蘄蘅蘆蘇蘈蘉蘊蘋蘌蘍蘎蘏蘐蘑蘒蘓蘔蘕蘖蘗蘘蘙蘚蘛蘜蘝蘞蘟蘠蘡蘢蘣蘤蘥蘦蘧蘨蘩蘪蘫蘬蘭蘮蘯蘰蘱蘲蘳蘴蘵蘶蘷蘸蘹蘺蘻蘼蘽蘾蘿虀虁虂虃虄虅虆虇虈虉虊虋虌虍虎虏虐虑虒虓虔處虖虗虘虙虚虛虜虝虞號虠虡虢虣虤虥虦虧虨虩虪虫虬虭虮虯虰虱虲虳虴虵虶虷虸虹虺虻虼虽虾虿蚀蚁蚂蚃蚄蚅蚆蚇蚈蚉蚊蚋蚌蚍蚎蚏蚐蚑蚒蚓蚔蚕蚖蚗蚘蚙蚚蚛蚜蚝蚞蚟蚠蚡蚢蚣蚤蚥蚦蚧蚨蚩蚪蚫蚬蚭蚮蚯蚰蚱蚲蚳蚴蚵蚶蚷蚸蚹蚺蚻蚼蚽蚾蚿蛀蛁蛂蛃蛄蛅蛆蛇蛈蛉蛊蛋蛌蛍蛎蛏蛐蛑蛒蛓蛔蛕蛖蛗蛘蛙蛚蛛蛜蛝蛞蛟蛠蛡蛢蛣蛤蛥蛦蛧蛨蛩蛪蛫蛬蛭蛮蛯蛰蛱蛲蛳蛴蛵蛶蛷蛸蛹蛺蛻蛼蛽蛾蛿蜀蜁蜂蜃蜄蜅蜆蜇蜈蜉蜊蜋蜌蜍蜎蜏蜐蜑蜒蜓蜔蜕蜖蜗蜘蜙蜚蜛蜜蜝蜞蜟蜠蜡蜢蜣蜤蜥蜦蜧蜨蜩蜪蜫蜬蜭蜮蜯蜰蜱蜲蜳蜴蜵蜶蜷蜸蜹蜺蜻蜼蜽蜾蜿蝀蝁蝂蝃蝄蝅蝆蝇蝈蝉蝊蝋蝌蝍蝎蝏蝐蝑蝒蝓蝔蝕蝖蝗蝘蝙蝚蝛蝜蝝蝞蝟蝠蝡蝢蝣蝤蝥蝦蝧蝨蝩蝪蝫蝬蝭蝮蝯蝰蝱蝲蝳蝴蝵蝶蝷蝸蝹蝺蝻蝼蝽蝾蝿螀螁螂螃螄螅螆螇螈螉螊螋螌融螎螏螐螑螒螓螔螕螖螗螘螙螚螛螜螝螞螟螠螡螢螣螤螥螦螧螨螩螪螫螬螭螮螯螰螱螲螳螴螵螶螷螸螹螺螻螼螽螾螿蟀蟁蟂蟃蟄蟅蟆蟇蟈蟉蟊蟋蟌蟍蟎蟏蟐蟑蟒蟓蟔蟕蟖蟗蟘蟙蟚蟛蟜蟝蟞蟟蟠蟡蟢蟣蟤蟥蟦蟧蟨蟩蟪蟫蟬蟭蟮蟯蟰蟱蟲蟳蟴蟵蟶蟷蟸蟹蟺蟻蟼蟽蟾蟿蠀蠁蠂蠃蠄蠅蠆蠇蠈蠉蠊蠋蠌蠍蠎蠏蠐蠑蠒蠓蠔蠕蠖蠗蠘蠙蠚蠛蠜蠝蠞蠟蠠蠡蠢蠣蠤蠥蠦蠧蠨蠩蠪蠫蠬蠭蠮蠯蠰蠱蠲蠳蠴蠵蠶蠷蠸蠹蠺蠻蠼蠽蠾蠿血衁衂衃衄衅衆衇衈衉衊衋行衍衎衏衐衑衒術衔衕衖街衘衙衚衛衜衝衞衟衠衡衢衣衤补衦衧表衩衪衫衬衭衮衯衰衱衲衳衴衵衶衷衸衹衺衻衼衽衾衿袀袁袂袃袄袅袆袇袈袉袊袋袌袍袎袏袐袑袒袓袔袕袖袗袘袙袚袛袜袝袞袟袠袡袢袣袤袥袦袧袨袩袪被袬袭袮袯袰袱袲袳袴袵袶袷袸袹袺袻袼袽袾袿裀裁裂裃裄装裆裇裈裉裊裋裌裍裎裏裐裑裒裓裔裕裖裗裘裙裚裛補裝裞裟裠裡裢裣裤裥裦裧裨裩裪裫裬裭裮裯裰裱裲裳裴裵裶裷裸裹裺裻裼製裾裿褀褁褂褃褄褅褆複褈褉褊褋褌褍褎褏褐褑褒褓褔褕褖褗褘褙褚褛褜褝褞褟褠褡褢褣褤褥褦褧褨褩褪褫褬褭褮褯褰褱褲褳褴褵褶褷褸褹褺褻褼褽褾褿襀襁襂襃襄襅襆襇襈襉襊襋襌襍襎襏襐襑襒襓襔襕襖襗襘襙襚襛襜襝襞襟襠襡襢襣襤襥襦襧襨襩襪襫襬襭襮襯襰襱襲襳襴襵襶襷襸襹襺襻襼襽襾西覀要覂覃覄覅覆覇覈覉覊見覌覍覎規覐覑覒覓覔覕視覗覘覙覚覛覜覝覞覟覠覡覢覣覤覥覦覧覨覩親覫覬覭覮覯覰覱覲観覴覵覶覷覸覹覺覻覼覽覾覿觀见观觃规觅视觇览觉觊觋觌觍觎觏觐觑角觓觔觕觖觗觘觙觚觛觜觝觞觟觠觡觢解觤觥触觧觨觩觪觫觬觭觮觯觰觱觲觳觴觵觶觷觸觹觺觻觼觽觾觿言訁訂訃訄訅訆訇計訉訊訋訌訍討訏訐訑訒訓訔訕訖託記訙訚訛訜訝訞訟訠訡訢訣訤訥訦訧訨訩訪訫訬設訮訯訰許訲訳訴訵訶訷訸訹診註証訽訾訿詀詁詂詃詄詅詆詇詈詉詊詋詌詍詎詏詐詑詒詓詔評詖詗詘詙詚詛詜詝詞詟詠詡詢詣詤詥試詧詨詩詪詫詬詭詮詯詰話該詳詴詵詶詷詸詹詺詻詼詽詾詿誀誁誂誃誄誅誆誇誈誉誊誋誌認誎誏誐誑誒誓誔誕誖誗誘誙誚誛誜誝語誟誠誡誢誣誤誥誦誧誨誩說誫説読誮誯誰誱課誳誴誵誶誷誸誹誺誻誼誽誾調諀諁諂諃諄諅諆談諈諉諊請諌諍諎諏諐諑諒諓諔諕論諗諘諙諚諛諜諝諞諟諠諡諢諣諤諥諦諧諨諩諪諫諬諭諮諯諰諱諲諳諴諵諶諷諸諹諺諻諼諽諾諿謀謁謂謃謄謅謆謇謈謉謊謋謌謍謎謏謐謑謒謓謔謕謖謗謘謙謚講謜謝謞謟謠謡謢謣謤謥謦謧謨謩謪謫謬謭謮謯謰謱謲謳謴謵謶謷謸謹謺謻謼謽謾謿譀譁譂譃譄譅譆譇譈證譊譋譌譍譎譏譐譑譒譓譔譕譖譗識譙譚譛譜譝譞譟譠譡譢譣譤譥警譧譨譩譪譫譬譭譮譯議譱譲譳譴譵譶護譸譹譺譻譼譽譾譿讀讁讂讃讄讅讆讇讈讉變讋讌讍讎讏讐讑讒讓讔讕讖讗讘讙讚讛讜讝讞讟讠计订讣认讥讦讧讨让讪讫讬训议讯记讱讲讳讴讵讶讷许讹论讻讼讽设访诀证诂诃评诅识诇诈诉诊诋诌词诎诏诐译诒诓诔试诖诗诘诙诚诛诜话诞诟诠诡询诣诤该详诧诨诩诪诫诬语诮误诰诱诲诳说诵诶请诸诹诺读诼诽课诿谀谁谂调谄谅谆谇谈谉谊谋谌谍谎谏谐谑谒谓谔谕谖谗谘谙谚谛谜谝谞谟谠谡谢谣谤谥谦谧谨谩谪谫谬谭谮谯谰谱谲谳谴谵谶谷谸谹谺谻谼谽谾谿豀豁豂豃豄豅豆豇豈豉豊豋豌豍豎豏豐豑豒豓豔豕豖豗豘豙豚豛豜豝豞豟豠象豢豣豤豥豦豧豨豩豪豫豬豭豮豯豰豱豲豳豴豵豶豷豸豹豺豻豼豽豾豿貀貁貂貃貄貅貆貇貈貉貊貋貌貍貎貏貐貑貒貓貔貕貖貗貘貙貚貛貜貝貞貟負財貢貣貤貥貦貧貨販貪貫責貭貮貯貰貱貲貳貴貵貶買貸貹貺費貼貽貾貿賀賁賂賃賄賅賆資賈賉賊賋賌賍賎賏賐賑賒賓賔賕賖賗賘賙賚賛賜賝賞賟賠賡賢賣賤賥賦賧賨賩質賫賬賭賮賯賰賱賲賳賴賵賶賷賸賹賺賻購賽賾賿贀贁贂贃贄贅贆贇贈贉贊贋贌贍贎贏贐贑贒贓贔贕贖贗贘贙贚贛贜贝贞负贠贡财责贤败账货质贩贪贫贬购贮贯贰贱贲贳贴贵贶贷贸费贺贻贼贽贾贿赀赁赂赃资赅赆赇赈赉赊赋赌赍赎赏赐赑赒赓赔赕赖赗赘赙赚赛赜赝赞赟赠赡赢赣赤赥赦赧赨赩赪赫赬赭赮赯走赱赲赳赴赵赶起赸赹赺赻赼赽赾赿趀趁趂趃趄超趆趇趈趉越趋趌趍趎趏趐趑趒趓趔趕趖趗趘趙趚趛趜趝趞趟趠趡趢趣趤趥趦趧趨趩趪趫趬趭趮趯趰趱趲足趴趵趶趷趸趹趺趻趼趽趾趿跀跁跂跃跄跅跆跇跈跉跊跋跌跍跎跏跐跑跒跓跔跕跖跗跘跙跚跛跜距跞跟跠跡跢跣跤跥跦跧跨跩跪跫跬跭跮路跰跱跲跳跴践跶跷跸跹跺跻跼跽跾跿踀踁踂踃踄踅踆踇踈踉踊踋踌踍踎踏踐踑踒踓踔踕踖踗踘踙踚踛踜踝踞踟踠踡踢踣踤踥踦踧踨踩踪踫踬踭踮踯踰踱踲踳踴踵踶踷踸踹踺踻踼踽踾踿蹀蹁蹂蹃蹄蹅蹆蹇蹈蹉蹊蹋蹌蹍蹎蹏蹐蹑蹒蹓蹔蹕蹖蹗蹘蹙蹚蹛蹜蹝蹞蹟蹠蹡蹢蹣蹤蹥蹦蹧蹨蹩蹪蹫蹬蹭蹮蹯蹰蹱蹲蹳蹴蹵蹶蹷蹸蹹蹺蹻蹼蹽蹾蹿躀躁躂躃躄躅躆躇躈躉躊躋躌躍躎躏躐躑躒躓躔躕躖躗躘躙躚躛躜躝躞躟躠躡躢躣躤躥躦躧躨躩躪身躬躭躮躯躰躱躲躳躴躵躶躷躸躹躺躻躼躽躾躿軀軁軂軃軄軅軆軇軈軉車軋軌軍軎軏軐軑軒軓軔軕軖軗軘軙軚軛軜軝軞軟軠軡転軣軤軥軦軧軨軩軪軫軬軭軮軯軰軱軲軳軴軵軶軷軸軹軺軻軼軽軾軿輀輁輂較輄輅輆輇輈載輊輋輌輍輎輏輐輑輒輓輔輕輖輗輘輙輚輛輜輝輞輟輠輡輢輣輤輥輦輧輨輩輪輫輬輭輮輯輰輱輲輳輴輵輶輷輸輹輺輻輼輽輾輿轀轁轂轃轄轅轆轇轈轉轊轋轌轍轎轏轐轑轒轓轔轕轖轗轘轙轚轛轜轝轞轟轠轡轢轣轤轥车轧轨轩轪轫转轭轮软轰轱轲轳轴轵轶轷轸轹轺轻轼载轾轿辀辁辂较辄辅辆辇辈辉辊辋辌辍辎辏辐辑辒输辔辕辖辗辘辙辚辛辜辝辞辟辠辡辢辣辤辥辦辧辨辩辪辫辬辭辮辯辰辱農辳辴辵辶辷辸边辺辻込辽达辿迀迁迂迃迄迅迆过迈迉迊迋迌迍迎迏运近迒迓返迕迖迗还这迚进远违连迟迠迡迢迣迤迥迦迧迨迩迪迫迬迭迮迯述迱迲迳迴迵迶迷迸迹迺迻迼追迾迿退送适逃逄逅逆逇逈选逊逋逌逍逎透逐逑递逓途逕逖逗逘這通逛逜逝逞速造逡逢連逤逥逦逧逨逩逪逫逬逭逮逯逰週進逳逴逵逶逷逸逹逺逻逼逽逾逿遀遁遂遃遄遅遆遇遈遉遊運遌遍過遏遐遑遒道達違遖遗遘遙遚遛遜遝遞遟遠遡遢遣遤遥遦遧遨適遪遫遬遭遮遯遰遱遲遳遴遵遶遷選遹遺遻遼遽遾避邀邁邂邃還邅邆邇邈邉邊邋邌邍邎邏邐邑邒邓邔邕邖邗邘邙邚邛邜邝邞邟邠邡邢那邤邥邦邧邨邩邪邫邬邭邮邯邰邱邲邳邴邵邶邷邸邹邺邻邼邽邾邿郀郁郂郃郄郅郆郇郈郉郊郋郌郍郎郏郐郑郒郓郔郕郖郗郘郙郚郛郜郝郞郟郠郡郢郣郤郥郦郧部郩郪郫郬郭郮郯郰郱郲郳郴郵郶郷郸郹郺郻郼都郾郿鄀鄁鄂鄃鄄鄅鄆鄇鄈鄉鄊鄋鄌鄍鄎鄏鄐鄑鄒鄓鄔鄕鄖鄗鄘鄙鄚鄛鄜鄝鄞鄟鄠鄡鄢鄣鄤鄥鄦鄧鄨鄩鄪鄫鄬鄭鄮鄯鄰鄱鄲鄳鄴鄵鄶鄷鄸鄹鄺鄻鄼鄽鄾鄿酀酁酂酃酄酅酆酇酈酉酊酋酌配酎酏酐酑酒酓酔酕酖酗酘酙酚酛酜酝酞酟酠酡酢酣酤酥酦酧酨酩酪酫酬酭酮酯酰酱酲酳酴酵酶酷酸酹酺酻酼酽酾酿醀醁醂醃醄醅醆醇醈醉醊醋醌醍醎醏醐醑醒醓醔醕醖醗醘醙醚醛醜醝醞醟醠醡醢醣醤醥醦醧醨醩醪醫醬醭醮醯醰醱醲醳醴醵醶醷醸醹醺醻醼醽醾醿釀釁釂釃釄釅釆采釈釉释釋里重野量釐金釒釓釔釕釖釗釘釙釚釛釜針釞釟釠釡釢釣釤釥釦釧釨釩釪釫釬釭釮釯釰釱釲釳釴釵釶釷釸釹釺釻釼釽釾釿鈀鈁鈂鈃鈄鈅鈆鈇鈈鈉鈊鈋鈌鈍鈎鈏鈐鈑鈒鈓鈔鈕鈖鈗鈘鈙鈚鈛鈜鈝鈞鈟鈠鈡鈢鈣鈤鈥鈦鈧鈨鈩鈪鈫鈬鈭鈮鈯鈰鈱鈲鈳鈴鈵鈶鈷鈸鈹鈺鈻鈼鈽鈾鈿鉀鉁鉂鉃鉄鉅鉆鉇鉈鉉鉊鉋鉌鉍鉎鉏鉐鉑鉒鉓鉔鉕鉖鉗鉘鉙鉚鉛鉜鉝鉞鉟鉠鉡鉢鉣鉤鉥鉦鉧鉨鉩鉪鉫鉬鉭鉮鉯鉰鉱鉲鉳鉴鉵鉶鉷鉸鉹鉺鉻鉼鉽鉾鉿銀銁銂銃銄銅銆銇銈銉銊銋銌銍銎銏銐銑銒銓銔銕銖銗銘銙銚銛銜銝銞銟銠銡銢銣銤銥銦銧銨銩銪銫銬銭銮銯銰銱銲銳銴銵銶銷銸銹銺銻銼銽銾銿鋀鋁鋂鋃鋄鋅鋆鋇鋈鋉鋊鋋鋌鋍鋎鋏鋐鋑鋒鋓鋔鋕鋖鋗鋘鋙鋚鋛鋜鋝鋞鋟鋠鋡鋢鋣鋤鋥鋦鋧鋨鋩鋪鋫鋬鋭鋮鋯鋰鋱鋲鋳鋴鋵鋶鋷鋸鋹鋺鋻鋼鋽鋾鋿錀錁錂錃錄錅錆錇錈錉錊錋錌錍錎錏錐錑錒錓錔錕錖錗錘錙錚錛錜錝錞錟錠錡錢錣錤錥錦錧錨錩錪錫錬錭錮錯錰錱録錳錴錵錶錷錸錹錺錻錼錽錾錿鍀鍁鍂鍃鍄鍅鍆鍇鍈鍉鍊鍋鍌鍍鍎鍏鍐鍑鍒鍓鍔鍕鍖鍗鍘鍙鍚鍛鍜鍝鍞鍟鍠鍡鍢鍣鍤鍥鍦鍧鍨鍩鍪鍫鍬鍭鍮鍯鍰鍱鍲鍳鍴鍵鍶鍷鍸鍹鍺鍻鍼鍽鍾鍿鎀鎁鎂鎃鎄鎅鎆鎇鎈鎉鎊鎋鎌鎍鎎鎏鎐鎑鎒鎓鎔鎕鎖鎗鎘鎙鎚鎛鎜鎝鎞鎟鎠鎡鎢鎣鎤鎥鎦鎧鎨鎩鎪鎫鎬鎭鎮鎯鎰鎱鎲鎳鎴鎵鎶鎷鎸鎹鎺鎻鎼鎽鎾鎿鏀鏁鏂鏃鏄鏅鏆鏇鏈鏉鏊鏋鏌鏍鏎鏏鏐鏑鏒鏓鏔鏕鏖鏗鏘鏙鏚鏛鏜鏝鏞鏟鏠鏡鏢鏣鏤鏥鏦鏧鏨鏩鏪鏫鏬鏭鏮鏯鏰鏱鏲鏳鏴鏵鏶鏷鏸鏹鏺鏻鏼鏽鏾鏿鐀鐁鐂鐃鐄鐅鐆鐇鐈鐉鐊鐋鐌鐍鐎鐏鐐鐑鐒鐓鐔鐕鐖鐗鐘鐙鐚鐛鐜鐝鐞鐟鐠鐡鐢鐣鐤鐥鐦鐧鐨鐩鐪鐫鐬鐭鐮鐯鐰鐱鐲鐳鐴鐵鐶鐷鐸鐹鐺鐻鐼鐽鐾鐿鑀鑁鑂鑃鑄鑅鑆鑇鑈鑉鑊鑋鑌鑍鑎鑏鑐鑑鑒鑓鑔鑕鑖鑗鑘鑙鑚鑛鑜鑝鑞鑟鑠鑡鑢鑣鑤鑥鑦鑧鑨鑩鑪鑫鑬鑭鑮鑯鑰鑱鑲鑳鑴鑵鑶鑷鑸鑹鑺鑻鑼鑽鑾鑿钀钁钂钃钄钅钆钇针钉钊钋钌钍钎钏钐钑钒钓钔钕钖钗钘钙钚钛钜钝钞钟钠钡钢钣钤钥钦钧钨钩钪钫钬钭钮钯钰钱钲钳钴钵钶钷钸钹钺钻钼钽钾钿铀铁铂铃铄铅铆铇铈铉铊铋铌铍铎铏铐铑铒铓铔铕铖铗铘铙铚铛铜铝铞铟铠铡铢铣铤铥铦铧铨铩铪铫铬铭铮铯铰铱铲铳铴铵银铷铸铹铺铻铼铽链铿销锁锂锃锄锅锆锇锈锉锊锋锌锍锎锏锐锑锒锓锔锕锖锗锘错锚锛锜锝锞锟锠锡锢锣锤锥锦锧锨锩锪锫锬锭键锯锰锱锲锳锴锵锶锷锸锹锺锻锼锽锾锿镀镁镂镃镄镅镆镇镈镉镊镋镌镍镎镏镐镑镒镓镔镕镖镗镘镙镚镛镜镝镞镟镠镡镢镣镤镥镦镧镨镩镪镫镬镭镮镯镰镱镲镳镴镵镶長镸镹镺镻镼镽镾长門閁閂閃閄閅閆閇閈閉閊開閌閍閎閏閐閑閒間閔閕閖閗閘閙閚閛閜閝閞閟閠閡関閣閤閥閦閧閨閩閪閫閬閭閮閯閰閱閲閳閴閵閶閷閸閹閺閻閼閽閾閿闀闁闂闃闄闅闆闇闈闉闊闋闌闍闎闏闐闑闒闓闔闕闖闗闘闙闚闛關闝闞闟闠闡闢闣闤闥闦闧门闩闪闫闬闭问闯闰闱闲闳间闵闶闷闸闹闺闻闼闽闾闿阀阁阂阃阄阅阆阇阈阉阊阋阌阍阎阏阐阑阒阓阔阕阖阗阘阙阚阛阜阝阞队阠阡阢阣阤阥阦阧阨阩阪阫阬阭阮阯阰阱防阳阴阵阶阷阸阹阺阻阼阽阾阿陀陁陂陃附际陆陇陈陉陊陋陌降陎陏限陑陒陓陔陕陖陗陘陙陚陛陜陝陞陟陠陡院陣除陥陦陧陨险陪陫陬陭陮陯陰陱陲陳陴陵陶陷陸陹険陻陼陽陾陿隀隁隂隃隄隅隆隇隈隉隊隋隌隍階随隐隑隒隓隔隕隖隗隘隙隚際障隝隞隟隠隡隢隣隤隥隦隧隨隩險隫隬隭隮隯隰隱隲隳隴隵隶隷隸隹隺隻隼隽难隿雀雁雂雃雄雅集雇雈雉雊雋雌雍雎雏雐雑雒雓雔雕雖雗雘雙雚雛雜雝雞雟雠雡離難雤雥雦雧雨雩雪雫雬雭雮雯雰雱雲雳雴雵零雷雸雹雺電雼雽雾雿需霁霂霃霄霅霆震霈霉霊霋霌霍霎霏霐霑霒霓霔霕霖霗霘霙霚霛霜霝霞霟霠霡霢霣霤霥霦霧霨霩霪霫霬霭霮霯霰霱露霳霴霵霶霷霸霹霺霻霼霽霾霿靀靁靂靃靄靅靆靇靈靉靊靋靌靍靎靏靐靑青靓靔靕靖靗靘静靚靛靜靝非靟靠靡面靣靤靥靦靧靨革靪靫靬靭靮靯靰靱靲靳靴靵靶靷靸靹靺靻靼靽靾靿鞀鞁鞂鞃鞄鞅鞆鞇鞈鞉鞊鞋鞌鞍鞎鞏鞐鞑鞒鞓鞔鞕鞖鞗鞘鞙鞚鞛鞜鞝鞞鞟鞠鞡鞢鞣鞤鞥鞦鞧鞨鞩鞪鞫鞬鞭鞮鞯鞰鞱鞲鞳鞴鞵鞶鞷鞸鞹鞺鞻鞼鞽鞾鞿韀韁韂韃韄韅韆韇韈韉韊韋韌韍韎韏韐韑韒韓韔韕韖韗韘韙韚韛韜韝韞韟韠韡韢韣韤韥韦韧韨韩韪韫韬韭韮韯韰韱韲音韴韵韶韷韸韹韺韻韼韽韾響頀頁頂頃頄項順頇須頉頊頋頌頍頎頏預頑頒頓頔頕頖頗領頙頚頛頜頝頞頟頠頡頢頣頤頥頦頧頨頩頪頫頬頭頮頯頰頱頲頳頴頵頶頷頸頹頺頻頼頽頾頿顀顁顂顃顄顅顆顇顈顉顊顋題額顎顏顐顑顒顓顔顕顖顗願顙顚顛顜顝類顟顠顡顢顣顤顥顦顧顨顩顪顫顬顭顮顯顰顱顲顳顴页顶顷顸项顺须顼顽顾顿颀颁颂颃预颅领颇颈颉颊颋颌颍颎颏颐频颒颓颔颕颖颗题颙颚颛颜额颞颟颠颡颢颣颤颥颦颧風颩颪颫颬颭颮颯颰颱颲颳颴颵颶颷颸颹颺颻颼颽颾颿飀飁飂飃飄飅飆飇飈飉飊飋飌飍风飏飐飑飒飓飔飕飖飗飘飙飚飛飜飝飞食飠飡飢飣飤飥飦飧飨飩飪飫飬飭飮飯飰飱飲飳飴飵飶飷飸飹飺飻飼飽飾飿餀餁餂餃餄餅餆餇餈餉養餋餌餍餎餏餐餑餒餓餔餕餖餗餘餙餚餛餜餝餞餟餠餡餢餣餤餥餦餧館餩餪餫餬餭餮餯餰餱餲餳餴餵餶餷餸餹餺餻餼餽餾餿饀饁饂饃饄饅饆饇饈饉饊饋饌饍饎饏饐饑饒饓饔饕饖饗饘饙饚饛饜饝饞饟饠饡饢饣饤饥饦饧饨饩饪饫饬饭饮饯饰饱饲饳饴饵饶饷饸饹饺饻饼饽饾饿馀馁馂馃馄馅馆馇馈馉馊馋馌馍馎馏馐馑馒馓馔馕首馗馘香馚馛馜馝馞馟馠馡馢馣馤馥馦馧馨馩馪馫馬馭馮馯馰馱馲馳馴馵馶馷馸馹馺馻馼馽馾馿駀駁駂駃駄駅駆駇駈駉駊駋駌駍駎駏駐駑駒駓駔駕駖駗駘駙駚駛駜駝駞駟駠駡駢駣駤駥駦駧駨駩駪駫駬駭駮駯駰駱駲駳駴駵駶駷駸駹駺駻駼駽駾駿騀騁騂騃騄騅騆騇騈騉騊騋騌騍騎騏騐騑騒験騔騕騖騗騘騙騚騛騜騝騞騟騠騡騢騣騤騥騦騧騨騩騪騫騬騭騮騯騰騱騲騳騴騵騶騷騸騹騺騻騼騽騾騿驀驁驂驃驄驅驆驇驈驉驊驋驌驍驎驏驐驑驒驓驔驕驖驗驘驙驚驛驜驝驞驟驠驡驢驣驤驥驦驧驨驩驪驫马驭驮驯驰驱驲驳驴驵驶驷驸驹驺驻驼驽驾驿骀骁骂骃骄骅骆骇骈骉骊骋验骍骎骏骐骑骒骓骔骕骖骗骘骙骚骛骜骝骞骟骠骡骢骣骤骥骦骧骨骩骪骫骬骭骮骯骰骱骲骳骴骵骶骷骸骹骺骻骼骽骾骿髀髁髂髃髄髅髆髇髈髉髊髋髌髍髎髏髐髑髒髓體髕髖髗高髙髚髛髜髝髞髟髠髡髢髣髤髥髦髧髨髩髪髫髬髭髮髯髰髱髲髳髴髵髶髷髸髹髺髻髼髽髾髿鬀鬁鬂鬃鬄鬅鬆鬇鬈鬉鬊鬋鬌鬍鬎鬏鬐鬑鬒鬓鬔鬕鬖鬗鬘鬙鬚鬛鬜鬝鬞鬟鬠鬡鬢鬣鬤鬥鬦鬧鬨鬩鬪鬫鬬鬭鬮鬯鬰鬱鬲鬳鬴鬵鬶鬷鬸鬹鬺鬻鬼鬽鬾鬿魀魁魂魃魄魅魆魇魈魉魊魋魌魍魎魏魐魑魒魓魔魕魖魗魘魙魚魛魜魝魞魟魠魡魢魣魤魥魦魧魨魩魪魫魬魭魮魯魰魱魲魳魴魵魶魷魸魹魺魻魼魽魾魿鮀鮁鮂鮃鮄鮅鮆鮇鮈鮉鮊鮋鮌鮍鮎鮏鮐鮑鮒鮓鮔鮕鮖鮗鮘鮙鮚鮛鮜鮝鮞鮟鮠鮡鮢鮣鮤鮥鮦鮧鮨鮩鮪鮫鮬鮭鮮鮯鮰鮱鮲鮳鮴鮵鮶鮷鮸鮹鮺鮻鮼鮽鮾鮿鯀鯁鯂鯃鯄鯅鯆鯇鯈鯉鯊鯋鯌鯍鯎鯏鯐鯑鯒鯓鯔鯕鯖鯗鯘鯙鯚鯛鯜鯝鯞鯟鯠鯡鯢鯣鯤鯥鯦鯧鯨鯩鯪鯫鯬鯭鯮鯯鯰鯱鯲鯳鯴鯵鯶鯷鯸鯹鯺鯻鯼鯽鯾鯿鰀鰁鰂鰃鰄鰅鰆鰇鰈鰉鰊鰋鰌鰍鰎鰏鰐鰑鰒鰓鰔鰕鰖鰗鰘鰙鰚鰛鰜鰝鰞鰟鰠鰡鰢鰣鰤鰥鰦鰧鰨鰩鰪鰫鰬鰭鰮鰯鰰鰱鰲鰳鰴鰵鰶鰷鰸鰹鰺鰻鰼鰽鰾鰿鱀鱁鱂鱃鱄鱅鱆鱇鱈鱉鱊鱋鱌鱍鱎鱏鱐鱑鱒鱓鱔鱕鱖鱗鱘鱙鱚鱛鱜鱝鱞鱟鱠鱡鱢鱣鱤鱥鱦鱧鱨鱩鱪鱫鱬鱭鱮鱯鱰鱱鱲鱳鱴鱵鱶鱷鱸鱹鱺鱻鱼鱽鱾鱿鲀鲁鲂鲃鲄鲅鲆鲇鲈鲉鲊鲋鲌鲍鲎鲏鲐鲑鲒鲓鲔鲕鲖鲗鲘鲙鲚鲛鲜鲝鲞鲟鲠鲡鲢鲣鲤鲥鲦鲧鲨鲩鲪鲫鲬鲭鲮鲯鲰鲱鲲鲳鲴鲵鲶鲷鲸鲹鲺鲻鲼鲽鲾鲿鳀鳁鳂鳃鳄鳅鳆鳇鳈鳉鳊鳋鳌鳍鳎鳏鳐鳑鳒鳓鳔鳕鳖鳗鳘鳙鳚鳛鳜鳝鳞鳟鳠鳡鳢鳣鳤鳥鳦鳧鳨鳩鳪鳫鳬鳭鳮鳯鳰鳱鳲鳳鳴鳵鳶鳷鳸鳹鳺鳻鳼鳽鳾鳿鴀鴁鴂鴃鴄鴅鴆鴇鴈鴉鴊鴋鴌鴍鴎鴏鴐鴑鴒鴓鴔鴕鴖鴗鴘鴙鴚鴛鴜鴝鴞鴟鴠鴡鴢鴣鴤鴥鴦鴧鴨鴩鴪鴫鴬鴭鴮鴯鴰鴱鴲鴳鴴鴵鴶鴷鴸鴹鴺鴻鴼鴽鴾鴿鵀鵁鵂鵃鵄鵅鵆鵇鵈鵉鵊鵋鵌鵍鵎鵏鵐鵑鵒鵓鵔鵕鵖鵗鵘鵙鵚鵛鵜鵝鵞鵟鵠鵡鵢鵣鵤鵥鵦鵧鵨鵩鵪鵫鵬鵭鵮鵯鵰鵱鵲鵳鵴鵵鵶鵷鵸鵹鵺鵻鵼鵽鵾鵿鶀鶁鶂鶃鶄鶅鶆鶇鶈鶉鶊鶋鶌鶍鶎鶏鶐鶑鶒鶓鶔鶕鶖鶗鶘鶙鶚鶛鶜鶝鶞鶟鶠鶡鶢鶣鶤鶥鶦鶧鶨鶩鶪鶫鶬鶭鶮鶯鶰鶱鶲鶳鶴鶵鶶鶷鶸鶹鶺鶻鶼鶽鶾鶿鷀鷁鷂鷃鷄鷅鷆鷇鷈鷉鷊鷋鷌鷍鷎鷏鷐鷑鷒鷓鷔鷕鷖鷗鷘鷙鷚鷛鷜鷝鷞鷟鷠鷡鷢鷣鷤鷥鷦鷧鷨鷩鷪鷫鷬鷭鷮鷯鷰鷱鷲鷳鷴鷵鷶鷷鷸鷹鷺鷻鷼鷽鷾鷿鸀鸁鸂鸃鸄鸅鸆鸇鸈鸉鸊鸋鸌鸍鸎鸏鸐鸑鸒鸓鸔鸕鸖鸗鸘鸙鸚鸛鸜鸝鸞鸟鸠鸡鸢鸣鸤鸥鸦鸧鸨鸩鸪鸫鸬鸭鸮鸯鸰鸱鸲鸳鸴鸵鸶鸷鸸鸹鸺鸻鸼鸽鸾鸿鹀鹁鹂鹃鹄鹅鹆鹇鹈鹉鹊鹋鹌鹍鹎鹏鹐鹑鹒鹓鹔鹕鹖鹗鹘鹙鹚鹛鹜鹝鹞鹟鹠鹡鹢鹣鹤鹥鹦鹧鹨鹩鹪鹫鹬鹭鹮鹯鹰鹱鹲鹳鹴鹵鹶鹷鹸鹹鹺鹻鹼鹽鹾鹿麀麁麂麃麄麅麆麇麈麉麊麋麌麍麎麏麐麑麒麓麔麕麖麗麘麙麚麛麜麝麞麟麠麡麢麣麤麥麦麧麨麩麪麫麬麭麮麯麰麱麲麳麴麵麶麷麸麹麺麻麼麽麾麿黀黁黂黃黄黅黆黇黈黉黊黋黌黍黎黏黐黑黒黓黔黕黖黗默黙黚黛黜黝點黟黠黡黢黣黤黥黦黧黨黩黪黫黬黭黮黯黰黱黲黳黴黵黶黷黸黹黺黻黼黽黾黿鼀鼁鼂鼃鼄鼅鼆鼇鼈鼉鼊鼋鼌鼍鼎鼏鼐鼑鼒鼓鼔鼕鼖鼗鼘鼙鼚鼛鼜鼝鼞鼟鼠鼡鼢鼣鼤鼥鼦鼧鼨鼩鼪鼫鼬鼭鼮鼯鼰鼱鼲鼳鼴鼵鼶鼷鼸鼹鼺鼻鼼鼽鼾鼿齀齁齂齃齄齅齆齇齈齉齊齋齌齍齎齏齐齑齒齓齔齕齖齗齘齙齚齛齜齝齞齟齠齡齢齣齤齥齦齧齨齩齪齫齬齭齮齯齰齱齲齳齴齵齶齷齸齹齺齻齼齽齾齿龀龁龂龃龄龅龆龇龈龉龊龋龌龍龎龏龐龑龒龓龔龕龖龗龘龙龚龛龜龝龞龟龠龡龢龣龤龥龦龧龨龩龪龫龬龭龮龯龰龱龲龳龴龵龶龷龸龹龺龻龼龽龾龿鿀鿁鿂鿃鿄鿅鿆鿇鿈鿉鿊鿋鿌ꀀꀁꀂꀃꀄꀅꀆꀇꀈꀉꀊꀋꀌꀍꀎꀏꀐꀑꀒꀓꀔꀕꀖꀗꀘꀙꀚꀛꀜꀝꀞꀟꀠꀡꀢꀣꀤꀥꀦꀧꀨꀩꀪꀫꀬꀭꀮꀯꀰꀱꀲꀳꀴꀵꀶꀷꀸꀹꀺꀻꀼꀽꀾꀿꁀꁁꁂꁃꁄꁅꁆꁇꁈꁉꁊꁋꁌꁍꁎꁏꁐꁑꁒꁓꁔꁕꁖꁗꁘꁙꁚꁛꁜꁝꁞꁟꁠꁡꁢꁣꁤꁥꁦꁧꁨꁩꁪꁫꁬꁭꁮꁯꁰꁱꁲꁳꁴꁵꁶꁷꁸꁹꁺꁻꁼꁽꁾꁿꂀꂁꂂꂃꂄꂅꂆꂇꂈꂉꂊꂋꂌꂍꂎꂏꂐꂑꂒꂓꂔꂕꂖꂗꂘꂙꂚꂛꂜꂝꂞꂟꂠꂡꂢꂣꂤꂥꂦꂧꂨꂩꂪꂫꂬꂭꂮꂯꂰꂱꂲꂳꂴꂵꂶꂷꂸꂹꂺꂻꂼꂽꂾꂿꃀꃁꃂꃃꃄꃅꃆꃇꃈꃉꃊꃋꃌꃍꃎꃏꃐꃑꃒꃓꃔꃕꃖꃗꃘꃙꃚꃛꃜꃝꃞꃟꃠꃡꃢꃣꃤꃥꃦꃧꃨꃩꃪꃫꃬꃭꃮꃯꃰꃱꃲꃳꃴꃵꃶꃷꃸꃹꃺꃻꃼꃽꃾꃿꄀꄁꄂꄃꄄꄅꄆꄇꄈꄉꄊꄋꄌꄍꄎꄏꄐꄑꄒꄓꄔꄕꄖꄗꄘꄙꄚꄛꄜꄝꄞꄟꄠꄡꄢꄣꄤꄥꄦꄧꄨꄩꄪꄫꄬꄭꄮꄯꄰꄱꄲꄳꄴꄵꄶꄷꄸꄹꄺꄻꄼꄽꄾꄿꅀꅁꅂꅃꅄꅅꅆꅇꅈꅉꅊꅋꅌꅍꅎꅏꅐꅑꅒꅓꅔꅕꅖꅗꅘꅙꅚꅛꅜꅝꅞꅟꅠꅡꅢꅣꅤꅥꅦꅧꅨꅩꅪꅫꅬꅭꅮꅯꅰꅱꅲꅳꅴꅵꅶꅷꅸꅹꅺꅻꅼꅽꅾꅿꆀꆁꆂꆃꆄꆅꆆꆇꆈꆉꆊꆋꆌꆍꆎꆏꆐꆑꆒꆓꆔꆕꆖꆗꆘꆙꆚꆛꆜꆝꆞꆟꆠꆡꆢꆣꆤꆥꆦꆧꆨꆩꆪꆫꆬꆭꆮꆯꆰꆱꆲꆳꆴꆵꆶꆷꆸꆹꆺꆻꆼꆽꆾꆿꇀꇁꇂꇃꇄꇅꇆꇇꇈꇉꇊꇋꇌꇍꇎꇏꇐꇑꇒꇓꇔꇕꇖꇗꇘꇙꇚꇛꇜꇝꇞꇟꇠꇡꇢꇣꇤꇥꇦꇧꇨꇩꇪꇫꇬꇭꇮꇯꇰꇱꇲꇳꇴꇵꇶꇷꇸꇹꇺꇻꇼꇽꇾꇿꈀꈁꈂꈃꈄꈅꈆꈇꈈꈉꈊꈋꈌꈍꈎꈏꈐꈑꈒꈓꈔꈕꈖꈗꈘꈙꈚꈛꈜꈝꈞꈟꈠꈡꈢꈣꈤꈥꈦꈧꈨꈩꈪꈫꈬꈭꈮꈯꈰꈱꈲꈳꈴꈵꈶꈷꈸꈹꈺꈻꈼꈽꈾꈿꉀꉁꉂꉃꉄꉅꉆꉇꉈꉉꉊꉋꉌꉍꉎꉏꉐꉑꉒꉓꉔꉕꉖꉗꉘꉙꉚꉛꉜꉝꉞꉟꉠꉡꉢꉣꉤꉥꉦꉧꉨꉩꉪꉫꉬꉭꉮꉯꉰꉱꉲꉳꉴꉵꉶꉷꉸꉹꉺꉻꉼꉽꉾꉿꊀꊁꊂꊃꊄꊅꊆꊇꊈꊉꊊꊋꊌꊍꊎꊏꊐꊑꊒꊓꊔꊕꊖꊗꊘꊙꊚꊛꊜꊝꊞꊟꊠꊡꊢꊣꊤꊥꊦꊧꊨꊩꊪꊫꊬꊭꊮꊯꊰꊱꊲꊳꊴꊵꊶꊷꊸꊹꊺꊻꊼꊽꊾꊿꋀꋁꋂꋃꋄꋅꋆꋇꋈꋉꋊꋋꋌꋍꋎꋏꋐꋑꋒꋓꋔꋕꋖꋗꋘꋙꋚꋛꋜꋝꋞꋟꋠꋡꋢꋣꋤꋥꋦꋧꋨꋩꋪꋫꋬꋭꋮꋯꋰꋱꋲꋳꋴꋵꋶꋷꋸꋹꋺꋻꋼꋽꋾꋿꌀꌁꌂꌃꌄꌅꌆꌇꌈꌉꌊꌋꌌꌍꌎꌏꌐꌑꌒꌓꌔꌕꌖꌗꌘꌙꌚꌛꌜꌝꌞꌟꌠꌡꌢꌣꌤꌥꌦꌧꌨꌩꌪꌫꌬꌭꌮꌯꌰꌱꌲꌳꌴꌵꌶꌷꌸꌹꌺꌻꌼꌽꌾꌿꍀꍁꍂꍃꍄꍅꍆꍇꍈꍉꍊꍋꍌꍍꍎꍏꍐꍑꍒꍓꍔꍕꍖꍗꍘꍙꍚꍛꍜꍝꍞꍟꍠꍡꍢꍣꍤꍥꍦꍧꍨꍩꍪꍫꍬꍭꍮꍯꍰꍱꍲꍳꍴꍵꍶꍷꍸꍹꍺꍻꍼꍽꍾꍿꎀꎁꎂꎃꎄꎅꎆꎇꎈꎉꎊꎋꎌꎍꎎꎏꎐꎑꎒꎓꎔꎕꎖꎗꎘꎙꎚꎛꎜꎝꎞꎟꎠꎡꎢꎣꎤꎥꎦꎧꎨꎩꎪꎫꎬꎭꎮꎯꎰꎱꎲꎳꎴꎵꎶꎷꎸꎹꎺꎻꎼꎽꎾꎿꏀꏁꏂꏃꏄꏅꏆꏇꏈꏉꏊꏋꏌꏍꏎꏏꏐꏑꏒꏓꏔꏕꏖꏗꏘꏙꏚꏛꏜꏝꏞꏟꏠꏡꏢꏣꏤꏥꏦꏧꏨꏩꏪꏫꏬꏭꏮꏯꏰꏱꏲꏳꏴꏵꏶꏷꏸꏹꏺꏻꏼꏽꏾꏿꐀꐁꐂꐃꐄꐅꐆꐇꐈꐉꐊꐋꐌꐍꐎꐏꐐꐑꐒꐓꐔꐕꐖꐗꐘꐙꐚꐛꐜꐝꐞꐟꐠꐡꐢꐣꐤꐥꐦꐧꐨꐩꐪꐫꐬꐭꐮꐯꐰꐱꐲꐳꐴꐵꐶꐷꐸꐹꐺꐻꐼꐽꐾꐿꑀꑁꑂꑃꑄꑅꑆꑇꑈꑉꑊꑋꑌꑍꑎꑏꑐꑑꑒꑓꑔꑕꑖꑗꑘꑙꑚꑛꑜꑝꑞꑟꑠꑡꑢꑣꑤꑥꑦꑧꑨꑩꑪꑫꑬꑭꑮꑯꑰꑱꑲꑳꑴꑵꑶꑷꑸꑹꑺꑻꑼꑽꑾꑿꒀꒁꒂꒃꒄꒅꒆꒇꒈꒉꒊꒋꒌ꒐꒑꒒꒓꒔꒕꒖꒗꒘꒙꒚꒛꒜꒝꒞꒟꒠꒡꒢꒣꒤꒥꒦꒧꒨꒩꒪꒫꒬꒭꒮꒯꒰꒱꒲꒳꒴꒵꒶꒷꒸꒹꒺꒻꒼꒽꒾꒿꓀꓁꓂꓃꓄꓅꓆ꓐꓑꓒꓓꓔꓕꓖꓗꓘꓙꓚꓛꓜꓝꓞꓟꓠꓡꓢꓣꓤꓥꓦꓧꓨꓩꓪꓫꓬꓭꓮꓯꓰꓱꓲꓳꓴꓵꓶꓷꓸꓹꓺꓻꓼꓽ꓾꓿ꔀꔁꔂꔃꔄꔅꔆꔇꔈꔉꔊꔋꔌꔍꔎꔏꔐꔑꔒꔓꔔꔕꔖꔗꔘꔙꔚꔛꔜꔝꔞꔟꔠꔡꔢꔣꔤꔥꔦꔧꔨꔩꔪꔫꔬꔭꔮꔯꔰꔱꔲꔳꔴꔵꔶꔷꔸꔹꔺꔻꔼꔽꔾꔿꕀꕁꕂꕃꕄꕅꕆꕇꕈꕉꕊꕋꕌꕍꕎꕏꕐꕑꕒꕓꕔꕕꕖꕗꕘꕙꕚꕛꕜꕝꕞꕟꕠꕡꕢꕣꕤꕥꕦꕧꕨꕩꕪꕫꕬꕭꕮꕯꕰꕱꕲꕳꕴꕵꕶꕷꕸꕹꕺꕻꕼꕽꕾꕿꖀꖁꖂꖃꖄꖅꖆꖇꖈꖉꖊꖋꖌꖍꖎꖏꖐꖑꖒꖓꖔꖕꖖꖗꖘꖙꖚꖛꖜꖝꖞꖟꖠꖡꖢꖣꖤꖥꖦꖧꖨꖩꖪꖫꖬꖭꖮꖯꖰꖱꖲꖳꖴꖵꖶꖷꖸꖹꖺꖻꖼꖽꖾꖿꗀꗁꗂꗃꗄꗅꗆꗇꗈꗉꗊꗋꗌꗍꗎꗏꗐꗑꗒꗓꗔꗕꗖꗗꗘꗙꗚꗛꗜꗝꗞꗟꗠꗡꗢꗣꗤꗥꗦꗧꗨꗩꗪꗫꗬꗭꗮꗯꗰꗱꗲꗳꗴꗵꗶꗷꗸꗹꗺꗻꗼꗽꗾꗿꘀꘁꘂꘃꘄꘅꘆꘇꘈꘉꘊꘋꘌ꘍꘎꘏ꘐꘑꘒꘓꘔꘕꘖꘗꘘꘙꘚꘛꘜꘝꘞꘟ꘠꘡꘢꘣꘤꘥꘦꘧꘨꘩ꘪꘫꙀꙁꙂꙃꙄꙅꙆꙇꙈꙉꙊꙋꙌꙍꙎꙏꙐꙑꙒꙓꙔꙕꙖꙗꙘꙙꙚꙛꙜꙝꙞꙟꙠꙡꙢꙣꙤꙥꙦꙧꙨꙩꙪꙫꙬꙭꙮ꙯꙰꙱꙲꙳ꙴꙵꙶꙷꙸꙹꙺꙻ꙼꙽꙾ꙿꚀꚁꚂꚃꚄꚅꚆꚇꚈꚉꚊꚋꚌꚍꚎꚏꚐꚑꚒꚓꚔꚕꚖꚗꚟꚠꚡꚢꚣꚤꚥꚦꚧꚨꚩꚪꚫꚬꚭꚮꚯꚰꚱꚲꚳꚴꚵꚶꚷꚸꚹꚺꚻꚼꚽꚾꚿꛀꛁꛂꛃꛄꛅꛆꛇꛈꛉꛊꛋꛌꛍꛎꛏꛐꛑꛒꛓꛔꛕꛖꛗꛘꛙꛚꛛꛜꛝꛞꛟꛠꛡꛢꛣꛤꛥꛦꛧꛨꛩꛪꛫꛬꛭꛮꛯ꛰꛱꛲꛳꛴꛵꛶꛷꜀꜁꜂꜃꜄꜅꜆꜇꜈꜉꜊꜋꜌꜍꜎꜏꜐꜑꜒꜓꜔꜕꜖ꜗꜘꜙꜚꜛꜜꜝꜞꜟ꜠꜡ꜢꜣꜤꜥꜦꜧꜨꜩꜪꜫꜬꜭꜮꜯꜰꜱꜲꜳꜴꜵꜶꜷꜸꜹꜺꜻꜼꜽꜾꜿꝀꝁꝂꝃꝄꝅꝆꝇꝈꝉꝊꝋꝌꝍꝎꝏꝐꝑꝒꝓꝔꝕꝖꝗꝘꝙꝚꝛꝜꝝꝞꝟꝠꝡꝢꝣꝤꝥꝦꝧꝨꝩꝪꝫꝬꝭꝮꝯꝰꝱꝲꝳꝴꝵꝶꝷꝸꝹꝺꝻꝼꝽꝾꝿꞀꞁꞂꞃꞄꞅꞆꞇꞈ꞉꞊ꞋꞌꞍꞎꞐꞑꞒꞓꞠꞡꞢꞣꞤꞥꞦꞧꞨꞩꞪꟸꟹꟺꟻꟼꟽꟾꟿꠀꠁꠂꠃꠄꠅ꠆ꠇꠈꠉꠊꠋꠌꠍꠎꠏꠐꠑꠒꠓꠔꠕꠖꠗꠘꠙꠚꠛꠜꠝꠞꠟꠠꠡꠢꠣꠤꠥꠦꠧ꠨꠩꠪꠫꠰꠱꠲꠳꠴꠵꠶꠷꠸꠹ꡀꡁꡂꡃꡄꡅꡆꡇꡈꡉꡊꡋꡌꡍꡎꡏꡐꡑꡒꡓꡔꡕꡖꡗꡘꡙꡚꡛꡜꡝꡞꡟꡠꡡꡢꡣꡤꡥꡦꡧꡨꡩꡪꡫꡬꡭꡮꡯꡰꡱꡲꡳ꡴꡵꡶꡷ꢀꢁꢂꢃꢄꢅꢆꢇꢈꢉꢊꢋꢌꢍꢎꢏꢐꢑꢒꢓꢔꢕꢖꢗꢘꢙꢚꢛꢜꢝꢞꢟꢠꢡꢢꢣꢤꢥꢦꢧꢨꢩꢪꢫꢬꢭꢮꢯꢰꢱꢲꢳꢴꢵꢶꢷꢸꢹꢺꢻꢼꢽꢾꢿꣀꣁꣂꣃ꣄꣎꣏꣐꣑꣒꣓꣔꣕꣖꣗꣘꣙꣠꣡꣢꣣꣤꣥꣦꣧꣨꣩꣪꣫꣬꣭꣮꣯꣰꣱ꣲꣳꣴꣵꣶꣷ꣸꣹꣺ꣻ꤀꤁꤂꤃꤄꤅꤆꤇꤈꤉ꤊꤋꤌꤍꤎꤏꤐꤑꤒꤓꤔꤕꤖꤗꤘꤙꤚꤛꤜꤝꤞꤟꤠꤡꤢꤣꤤꤥꤦꤧꤨꤩꤪ꤫꤬꤭꤮꤯ꤰꤱꤲꤳꤴꤵꤶꤷꤸꤹꤺꤻꤼꤽꤾꤿꥀꥁꥂꥃꥄꥅꥆꥇꥈꥉꥊꥋꥌꥍꥎꥏꥐꥑꥒ꥓꥟ꥠꥡꥢꥣꥤꥥꥦꥧꥨꥩꥪꥫꥬꥭꥮꥯꥰꥱꥲꥳꥴꥵꥶꥷꥸꥹꥺꥻꥼꦀꦁꦂꦃꦄꦅꦆꦇꦈꦉꦊꦋꦌꦍꦎꦏꦐꦑꦒꦓꦔꦕꦖꦗꦘꦙꦚꦛꦜꦝꦞꦟꦠꦡꦢꦣꦤꦥꦦꦧꦨꦩꦪꦫꦬꦭꦮꦯꦰꦱꦲ꦳ꦴꦵꦶꦷꦸꦹꦺꦻꦼꦽꦾꦿ꧀꧁꧂꧃꧄꧅꧆꧇꧈꧉꧊꧋꧌꧍ꧏ꧐꧑꧒꧓꧔꧕꧖꧗꧘꧙꧞꧟ꨀꨁꨂꨃꨄꨅꨆꨇꨈꨉꨊꨋꨌꨍꨎꨏꨐꨑꨒꨓꨔꨕꨖꨗꨘꨙꨚꨛꨜꨝꨞꨟꨠꨡꨢꨣꨤꨥꨦꨧꨨꨩꨪꨫꨬꨭꨮꨯꨰꨱꨲꨳꨴꨵꨶꩀꩁꩂꩃꩄꩅꩆꩇꩈꩉꩊꩋꩌꩍ꩐꩑꩒꩓꩔꩕꩖꩗꩘꩙꩜꩝꩞꩟ꩠꩡꩢꩣꩤꩥꩦꩧꩨꩩꩪꩫꩬꩭꩮꩯꩰꩱꩲꩳꩴꩵꩶ꩷꩸꩹ꩺꩻꪀꪁꪂꪃꪄꪅꪆꪇꪈꪉꪊꪋꪌꪍꪎꪏꪐꪑꪒꪓꪔꪕꪖꪗꪘꪙꪚꪛꪜꪝꪞꪟꪠꪡꪢꪣꪤꪥꪦꪧꪨꪩꪪꪫꪬꪭꪮꪯꪰꪱꪴꪲꪳꪵꪶꪷꪸꪹꪺꪻꪼꪽꪾ꪿ꫀ꫁ꫂꫛꫜꫝ꫞꫟ꫠꫡꫢꫣꫤꫥꫦꫧꫨꫩꫪꫫꫬꫭꫮꫯ꫰꫱ꫲꫳꫴꫵ꫶ꬁꬂꬃꬄꬅꬆꬉꬊꬋꬌꬍꬎꬑꬒꬓꬔꬕꬖꬠꬡꬢꬣꬤꬥꬦꬨꬩꬪꬫꬬꬭꬮꯀꯁꯂꯃꯄꯅꯆꯇꯈꯉꯊꯋꯌꯍꯎꯏꯐꯑꯒꯓꯔꯕꯖꯗꯘꯙꯚꯛꯜꯝꯞꯟꯠꯡꯢꯣꯤꯥꯦꯧꯨꯩꯪ꯫꯬꯭꯰꯱꯲꯳꯴꯵꯶꯷꯸꯹가각갂갃간갅갆갇갈갉갊갋갌갍갎갏감갑값갓갔강갖갗갘같갚갛개객갞갟갠갡갢갣갤갥갦갧갨갩갪갫갬갭갮갯갰갱갲갳갴갵갶갷갸갹갺갻갼갽갾갿걀걁걂걃걄걅걆걇걈걉걊걋걌걍걎걏걐걑걒걓걔걕걖걗걘걙걚걛걜걝걞걟걠걡걢걣걤걥걦걧걨걩걪걫걬걭걮걯거걱걲걳건걵걶걷걸걹걺걻걼걽걾걿검겁겂것겄겅겆겇겈겉겊겋게겍겎겏겐겑겒겓겔겕겖겗겘겙겚겛겜겝겞겟겠겡겢겣겤겥겦겧겨격겪겫견겭겮겯결겱겲겳겴겵겶겷겸겹겺겻겼경겾겿곀곁곂곃계곅곆곇곈곉곊곋곌곍곎곏곐곑곒곓곔곕곖곗곘곙곚곛곜곝곞곟고곡곢곣곤곥곦곧골곩곪곫곬곭곮곯곰곱곲곳곴공곶곷곸곹곺곻과곽곾곿관괁괂괃괄괅괆괇괈괉괊괋괌괍괎괏괐광괒괓괔괕괖괗괘괙괚괛괜괝괞괟괠괡괢괣괤괥괦괧괨괩괪괫괬괭괮괯괰괱괲괳괴괵괶괷괸괹괺괻괼괽괾괿굀굁굂굃굄굅굆굇굈굉굊굋굌굍굎굏교굑굒굓굔굕굖굗굘굙굚굛굜굝굞굟굠굡굢굣굤굥굦굧굨굩굪굫구국굮굯군굱굲굳굴굵굶굷굸굹굺굻굼굽굾굿궀궁궂궃궄궅궆궇궈궉궊궋권궍궎궏궐궑궒궓궔궕궖궗궘궙궚궛궜궝궞궟궠궡궢궣궤궥궦궧궨궩궪궫궬궭궮궯궰궱궲궳궴궵궶궷궸궹궺궻궼궽궾궿귀귁귂귃귄귅귆귇귈귉귊귋귌귍귎귏귐귑귒귓귔귕귖귗귘귙귚귛규귝귞귟균귡귢귣귤귥귦귧귨귩귪귫귬귭귮귯귰귱귲귳귴귵귶귷그극귺귻근귽귾귿글긁긂긃긄긅긆긇금급긊긋긌긍긎긏긐긑긒긓긔긕긖긗긘긙긚긛긜긝긞긟긠긡긢긣긤긥긦긧긨긩긪긫긬긭긮긯기긱긲긳긴긵긶긷길긹긺긻긼긽긾긿김깁깂깃깄깅깆깇깈깉깊깋까깍깎깏깐깑깒깓깔깕깖깗깘깙깚깛깜깝깞깟깠깡깢깣깤깥깦깧깨깩깪깫깬깭깮깯깰깱깲깳깴깵깶깷깸깹깺깻깼깽깾깿꺀꺁꺂꺃꺄꺅꺆꺇꺈꺉꺊꺋꺌꺍꺎꺏꺐꺑꺒꺓꺔꺕꺖꺗꺘꺙꺚꺛꺜꺝꺞꺟꺠꺡꺢꺣꺤꺥꺦꺧꺨꺩꺪꺫꺬꺭꺮꺯꺰꺱꺲꺳꺴꺵꺶꺷꺸꺹꺺꺻꺼꺽꺾꺿껀껁껂껃껄껅껆껇껈껉껊껋껌껍껎껏껐껑껒껓껔껕껖껗께껙껚껛껜껝껞껟껠껡껢껣껤껥껦껧껨껩껪껫껬껭껮껯껰껱껲껳껴껵껶껷껸껹껺껻껼껽껾껿꼀꼁꼂꼃꼄꼅꼆꼇꼈꼉꼊꼋꼌꼍꼎꼏꼐꼑꼒꼓꼔꼕꼖꼗꼘꼙꼚꼛꼜꼝꼞꼟꼠꼡꼢꼣꼤꼥꼦꼧꼨꼩꼪꼫꼬꼭꼮꼯꼰꼱꼲꼳꼴꼵꼶꼷꼸꼹꼺꼻꼼꼽꼾꼿꽀꽁꽂꽃꽄꽅꽆꽇꽈꽉꽊꽋꽌꽍꽎꽏꽐꽑꽒꽓꽔꽕꽖꽗꽘꽙꽚꽛꽜꽝꽞꽟꽠꽡꽢꽣꽤꽥꽦꽧꽨꽩꽪꽫꽬꽭꽮꽯꽰꽱꽲꽳꽴꽵꽶꽷꽸꽹꽺꽻꽼꽽꽾꽿꾀꾁꾂꾃꾄꾅꾆꾇꾈꾉꾊꾋꾌꾍꾎꾏꾐꾑꾒꾓꾔꾕꾖꾗꾘꾙꾚꾛꾜꾝꾞꾟꾠꾡꾢꾣꾤꾥꾦꾧꾨꾩꾪꾫꾬꾭꾮꾯꾰꾱꾲꾳꾴꾵꾶꾷꾸꾹꾺꾻꾼꾽꾾꾿꿀꿁꿂꿃꿄꿅꿆꿇꿈꿉꿊꿋꿌꿍꿎꿏꿐꿑꿒꿓꿔꿕꿖꿗꿘꿙꿚꿛꿜꿝꿞꿟꿠꿡꿢꿣꿤꿥꿦꿧꿨꿩꿪꿫꿬꿭꿮꿯꿰꿱꿲꿳꿴꿵꿶꿷꿸꿹꿺꿻꿼꿽꿾꿿뀀뀁뀂뀃뀄뀅뀆뀇뀈뀉뀊뀋뀌뀍뀎뀏뀐뀑뀒뀓뀔뀕뀖뀗뀘뀙뀚뀛뀜뀝뀞뀟뀠뀡뀢뀣뀤뀥뀦뀧뀨뀩뀪뀫뀬뀭뀮뀯뀰뀱뀲뀳뀴뀵뀶뀷뀸뀹뀺뀻뀼뀽뀾뀿끀끁끂끃끄끅끆끇끈끉끊끋끌끍끎끏끐끑끒끓끔끕끖끗끘끙끚끛끜끝끞끟끠끡끢끣끤끥끦끧끨끩끪끫끬끭끮끯끰끱끲끳끴끵끶끷끸끹끺끻끼끽끾끿낀낁낂낃낄낅낆낇낈낉낊낋낌낍낎낏낐낑낒낓낔낕낖낗나낙낚낛난낝낞낟날낡낢낣낤낥낦낧남납낪낫났낭낮낯낰낱낲낳내낵낶낷낸낹낺낻낼낽낾낿냀냁냂냃냄냅냆냇냈냉냊냋냌냍냎냏냐냑냒냓냔냕냖냗냘냙냚냛냜냝냞냟냠냡냢냣냤냥냦냧냨냩냪냫냬냭냮냯냰냱냲냳냴냵냶냷냸냹냺냻냼냽냾냿넀넁넂넃넄넅넆넇너넉넊넋넌넍넎넏널넑넒넓넔넕넖넗넘넙넚넛넜넝넞넟넠넡넢넣네넥넦넧넨넩넪넫넬넭넮넯넰넱넲넳넴넵넶넷넸넹넺넻넼넽넾넿녀녁녂녃년녅녆녇녈녉녊녋녌녍녎녏념녑녒녓녔녕녖녗녘녙녚녛녜녝녞녟녠녡녢녣녤녥녦녧녨녩녪녫녬녭녮녯녰녱녲녳녴녵녶녷노녹녺녻논녽녾녿놀놁놂놃놄놅놆놇놈놉놊놋놌농놎놏놐놑높놓놔놕놖놗놘놙놚놛놜놝놞놟놠놡놢놣놤놥놦놧놨놩놪놫놬놭놮놯놰놱놲놳놴놵놶놷놸놹놺놻놼놽놾놿뇀뇁뇂뇃뇄뇅뇆뇇뇈뇉뇊뇋뇌뇍뇎뇏뇐뇑뇒뇓뇔뇕뇖뇗뇘뇙뇚뇛뇜뇝뇞뇟뇠뇡뇢뇣뇤뇥뇦뇧뇨뇩뇪뇫뇬뇭뇮뇯뇰뇱뇲뇳뇴뇵뇶뇷뇸뇹뇺뇻뇼뇽뇾뇿눀눁눂눃누눅눆눇눈눉눊눋눌눍눎눏눐눑눒눓눔눕눖눗눘눙눚눛눜눝눞눟눠눡눢눣눤눥눦눧눨눩눪눫눬눭눮눯눰눱눲눳눴눵눶눷눸눹눺눻눼눽눾눿뉀뉁뉂뉃뉄뉅뉆뉇뉈뉉뉊뉋뉌뉍뉎뉏뉐뉑뉒뉓뉔뉕뉖뉗뉘뉙뉚뉛뉜뉝뉞뉟뉠뉡뉢뉣뉤뉥뉦뉧뉨뉩뉪뉫뉬뉭뉮뉯뉰뉱뉲뉳뉴뉵뉶뉷뉸뉹뉺뉻뉼뉽뉾뉿늀늁늂늃늄늅늆늇늈늉늊늋늌늍늎늏느늑늒늓는늕늖늗늘늙늚늛늜늝늞늟늠늡늢늣늤능늦늧늨늩늪늫늬늭늮늯늰늱늲늳늴늵늶늷늸늹늺늻늼늽늾늿닀닁닂닃닄닅닆닇니닉닊닋닌닍닎닏닐닑닒닓닔닕닖닗님닙닚닛닜닝닞닟닠닡닢닣다닥닦닧단닩닪닫달닭닮닯닰닱닲닳담답닶닷닸당닺닻닼닽닾닿대댁댂댃댄댅댆댇댈댉댊댋댌댍댎댏댐댑댒댓댔댕댖댗댘댙댚댛댜댝댞댟댠댡댢댣댤댥댦댧댨댩댪댫댬댭댮댯댰댱댲댳댴댵댶댷댸댹댺댻댼댽댾댿덀덁덂덃덄덅덆덇덈덉덊덋덌덍덎덏덐덑덒덓더덕덖덗던덙덚덛덜덝덞덟덠덡덢덣덤덥덦덧덨덩덪덫덬덭덮덯데덱덲덳덴덵덶덷델덹덺덻덼덽덾덿뎀뎁뎂뎃뎄뎅뎆뎇뎈뎉뎊뎋뎌뎍뎎뎏뎐뎑뎒뎓뎔뎕뎖뎗뎘뎙뎚뎛뎜뎝뎞뎟뎠뎡뎢뎣뎤뎥뎦뎧뎨뎩뎪뎫뎬뎭뎮뎯뎰뎱뎲뎳뎴뎵뎶뎷뎸뎹뎺뎻뎼뎽뎾뎿돀돁돂돃도독돆돇돈돉돊돋돌돍돎돏돐돑돒돓돔돕돖돗돘동돚돛돜돝돞돟돠돡돢돣돤돥돦돧돨돩돪돫돬돭돮돯돰돱돲돳돴돵돶돷돸돹돺돻돼돽돾돿됀됁됂됃됄됅됆됇됈됉됊됋됌됍됎됏됐됑됒됓됔됕됖됗되됙됚됛된됝됞됟될됡됢됣됤됥됦됧됨됩됪됫됬됭됮됯됰됱됲됳됴됵됶됷됸됹됺됻됼됽됾됿둀둁둂둃둄둅둆둇둈둉둊둋둌둍둎둏두둑둒둓둔둕둖둗둘둙둚둛둜둝둞둟둠둡둢둣둤둥둦둧둨둩둪둫둬둭둮둯둰둱둲둳둴둵둶둷둸둹둺둻둼둽둾둿뒀뒁뒂뒃뒄뒅뒆뒇뒈뒉뒊뒋뒌뒍뒎뒏뒐뒑뒒뒓뒔뒕뒖뒗뒘뒙뒚뒛뒜뒝뒞뒟뒠뒡뒢뒣뒤뒥뒦뒧뒨뒩뒪뒫뒬뒭뒮뒯뒰뒱뒲뒳뒴뒵뒶뒷뒸뒹뒺뒻뒼뒽뒾뒿듀듁듂듃듄듅듆듇듈듉듊듋듌듍듎듏듐듑듒듓듔듕듖듗듘듙듚듛드득듞듟든듡듢듣들듥듦듧듨듩듪듫듬듭듮듯듰등듲듳듴듵듶듷듸듹듺듻듼듽듾듿딀딁딂딃딄딅딆딇딈딉딊딋딌딍딎딏딐딑딒딓디딕딖딗딘딙딚딛딜딝딞딟딠딡딢딣딤딥딦딧딨딩딪딫딬딭딮딯따딱딲딳딴딵딶딷딸딹딺딻딼딽딾딿땀땁땂땃땄땅땆땇땈땉땊땋때땍땎땏땐땑땒땓땔땕땖땗땘땙땚땛땜땝땞땟땠땡땢땣땤땥땦땧땨땩땪땫땬땭땮땯땰땱땲땳땴땵땶땷땸땹땺땻땼땽땾땿떀떁떂떃떄떅떆떇떈떉떊떋떌떍떎떏떐떑떒떓떔떕떖떗떘떙떚떛떜떝떞떟떠떡떢떣떤떥떦떧떨떩떪떫떬떭떮떯떰떱떲떳떴떵떶떷떸떹떺떻떼떽떾떿뗀뗁뗂뗃뗄뗅뗆뗇뗈뗉뗊뗋뗌뗍뗎뗏뗐뗑뗒뗓뗔뗕뗖뗗뗘뗙뗚뗛뗜뗝뗞뗟뗠뗡뗢뗣뗤뗥뗦뗧뗨뗩뗪뗫뗬뗭뗮뗯뗰뗱뗲뗳뗴뗵뗶뗷뗸뗹뗺뗻뗼뗽뗾뗿똀똁똂똃똄똅똆똇똈똉똊똋똌똍똎똏또똑똒똓똔똕똖똗똘똙똚똛똜똝똞똟똠똡똢똣똤똥똦똧똨똩똪똫똬똭똮똯똰똱똲똳똴똵똶똷똸똹똺똻똼똽똾똿뙀뙁뙂뙃뙄뙅뙆뙇뙈뙉뙊뙋뙌뙍뙎뙏뙐뙑뙒뙓뙔뙕뙖뙗뙘뙙뙚뙛뙜뙝뙞뙟뙠뙡뙢뙣뙤뙥뙦뙧뙨뙩뙪뙫뙬뙭뙮뙯뙰뙱뙲뙳뙴뙵뙶뙷뙸뙹뙺뙻뙼뙽뙾뙿뚀뚁뚂뚃뚄뚅뚆뚇뚈뚉뚊뚋뚌뚍뚎뚏뚐뚑뚒뚓뚔뚕뚖뚗뚘뚙뚚뚛뚜뚝뚞뚟뚠뚡뚢뚣뚤뚥뚦뚧뚨뚩뚪뚫뚬뚭뚮뚯뚰뚱뚲뚳뚴뚵뚶뚷뚸뚹뚺뚻뚼뚽뚾뚿뛀뛁뛂뛃뛄뛅뛆뛇뛈뛉뛊뛋뛌뛍뛎뛏뛐뛑뛒뛓뛔뛕뛖뛗뛘뛙뛚뛛뛜뛝뛞뛟뛠뛡뛢뛣뛤뛥뛦뛧뛨뛩뛪뛫뛬뛭뛮뛯뛰뛱뛲뛳뛴뛵뛶뛷뛸뛹뛺뛻뛼뛽뛾뛿뜀뜁뜂뜃뜄뜅뜆뜇뜈뜉뜊뜋뜌뜍뜎뜏뜐뜑뜒뜓뜔뜕뜖뜗뜘뜙뜚뜛뜜뜝뜞뜟뜠뜡뜢뜣뜤뜥뜦뜧뜨뜩뜪뜫뜬뜭뜮뜯뜰뜱뜲뜳뜴뜵뜶뜷뜸뜹뜺뜻뜼뜽뜾뜿띀띁띂띃띄띅띆띇띈띉띊띋띌띍띎띏띐띑띒띓띔띕띖띗띘띙띚띛띜띝띞띟띠띡띢띣띤띥띦띧띨띩띪띫띬띭띮띯띰띱띲띳띴띵띶띷띸띹띺띻라락띾띿란랁랂랃랄랅랆랇랈랉랊랋람랍랎랏랐랑랒랓랔랕랖랗래랙랚랛랜랝랞랟랠랡랢랣랤랥랦랧램랩랪랫랬랭랮랯랰랱랲랳랴략랶랷랸랹랺랻랼랽랾랿럀럁럂럃럄럅럆럇럈량럊럋럌럍럎럏럐럑럒럓럔럕럖럗럘럙럚럛럜럝럞럟럠럡럢럣럤럥럦럧럨럩럪럫러럭럮럯런럱럲럳럴럵럶럷럸럹럺럻럼럽럾럿렀렁렂렃렄렅렆렇레렉렊렋렌렍렎렏렐렑렒렓렔렕렖렗렘렙렚렛렜렝렞렟렠렡렢렣려력렦렧련렩렪렫렬렭렮렯렰렱렲렳렴렵렶렷렸령렺렻렼렽렾렿례롁롂롃롄롅롆롇롈롉롊롋롌롍롎롏롐롑롒롓롔롕롖롗롘롙롚롛로록롞롟론롡롢롣롤롥롦롧롨롩롪롫롬롭롮롯롰롱롲롳롴롵롶롷롸롹롺롻롼롽롾롿뢀뢁뢂뢃뢄뢅뢆뢇뢈뢉뢊뢋뢌뢍뢎뢏뢐뢑뢒뢓뢔뢕뢖뢗뢘뢙뢚뢛뢜뢝뢞뢟뢠뢡뢢뢣뢤뢥뢦뢧뢨뢩뢪뢫뢬뢭뢮뢯뢰뢱뢲뢳뢴뢵뢶뢷뢸뢹뢺뢻뢼뢽뢾뢿룀룁룂룃룄룅룆룇룈룉룊룋료룍룎룏룐룑룒룓룔룕룖룗룘룙룚룛룜룝룞룟룠룡룢룣룤룥룦룧루룩룪룫룬룭룮룯룰룱룲룳룴룵룶룷룸룹룺룻룼룽룾룿뤀뤁뤂뤃뤄뤅뤆뤇뤈뤉뤊뤋뤌뤍뤎뤏뤐뤑뤒뤓뤔뤕뤖뤗뤘뤙뤚뤛뤜뤝뤞뤟뤠뤡뤢뤣뤤뤥뤦뤧뤨뤩뤪뤫뤬뤭뤮뤯뤰뤱뤲뤳뤴뤵뤶뤷뤸뤹뤺뤻뤼뤽뤾뤿륀륁륂륃륄륅륆륇륈륉륊륋륌륍륎륏륐륑륒륓륔륕륖륗류륙륚륛륜륝륞륟률륡륢륣륤륥륦륧륨륩륪륫륬륭륮륯륰륱륲륳르륵륶륷른륹륺륻를륽륾륿릀릁릂릃름릅릆릇릈릉릊릋릌릍릎릏릐릑릒릓릔릕릖릗릘릙릚릛릜릝릞릟릠릡릢릣릤릥릦릧릨릩릪릫리릭릮릯린릱릲릳릴릵릶릷릸릹릺릻림립릾릿맀링맂맃맄맅맆맇마막맊맋만맍많맏말맑맒맓맔맕맖맗맘맙맚맛맜망맞맟맠맡맢맣매맥맦맧맨맩맪맫맬맭맮맯맰맱맲맳맴맵맶맷맸맹맺맻맼맽맾맿먀먁먂먃먄먅먆먇먈먉먊먋먌먍먎먏먐먑먒먓먔먕먖먗먘먙먚먛먜먝먞먟먠먡먢먣먤먥먦먧먨먩먪먫먬먭먮먯먰먱먲먳먴먵먶먷머먹먺먻먼먽먾먿멀멁멂멃멄멅멆멇멈멉멊멋멌멍멎멏멐멑멒멓메멕멖멗멘멙멚멛멜멝멞멟멠멡멢멣멤멥멦멧멨멩멪멫멬멭멮멯며멱멲멳면멵멶멷멸멹멺멻멼멽멾멿몀몁몂몃몄명몆몇몈몉몊몋몌몍몎몏몐몑몒몓몔몕몖몗몘몙몚몛몜몝몞몟몠몡몢몣몤몥몦몧모목몪몫몬몭몮몯몰몱몲몳몴몵몶몷몸몹몺못몼몽몾몿뫀뫁뫂뫃뫄뫅뫆뫇뫈뫉뫊뫋뫌뫍뫎뫏뫐뫑뫒뫓뫔뫕뫖뫗뫘뫙뫚뫛뫜뫝뫞뫟뫠뫡뫢뫣뫤뫥뫦뫧뫨뫩뫪뫫뫬뫭뫮뫯뫰뫱뫲뫳뫴뫵뫶뫷뫸뫹뫺뫻뫼뫽뫾뫿묀묁묂묃묄묅묆묇묈묉묊묋묌묍묎묏묐묑묒묓묔묕묖묗묘묙묚묛묜묝묞묟묠묡묢묣묤묥묦묧묨묩묪묫묬묭묮묯묰묱묲묳무묵묶묷문묹묺묻물묽묾묿뭀뭁뭂뭃뭄뭅뭆뭇뭈뭉뭊뭋뭌뭍뭎뭏뭐뭑뭒뭓뭔뭕뭖뭗뭘뭙뭚뭛뭜뭝뭞뭟뭠뭡뭢뭣뭤뭥뭦뭧뭨뭩뭪뭫뭬뭭뭮뭯뭰뭱뭲뭳뭴뭵뭶뭷뭸뭹뭺뭻뭼뭽뭾뭿뮀뮁뮂뮃뮄뮅뮆뮇뮈뮉뮊뮋뮌뮍뮎뮏뮐뮑뮒뮓뮔뮕뮖뮗뮘뮙뮚뮛뮜뮝뮞뮟뮠뮡뮢뮣뮤뮥뮦뮧뮨뮩뮪뮫뮬뮭뮮뮯뮰뮱뮲뮳뮴뮵뮶뮷뮸뮹뮺뮻뮼뮽뮾뮿므믁믂믃믄믅믆믇믈믉믊믋믌믍믎믏믐믑믒믓믔믕믖믗믘믙믚믛믜믝믞믟믠믡믢믣믤믥믦믧믨믩믪믫믬믭믮믯믰믱믲믳믴믵믶믷미믹믺믻민믽믾믿밀밁밂밃밄밅밆밇밈밉밊밋밌밍밎및밐밑밒밓바박밖밗반밙밚받발밝밞밟밠밡밢밣밤밥밦밧밨방밪밫밬밭밮밯배백밲밳밴밵밶밷밸밹밺밻밼밽밾밿뱀뱁뱂뱃뱄뱅뱆뱇뱈뱉뱊뱋뱌뱍뱎뱏뱐뱑뱒뱓뱔뱕뱖뱗뱘뱙뱚뱛뱜뱝뱞뱟뱠뱡뱢뱣뱤뱥뱦뱧뱨뱩뱪뱫뱬뱭뱮뱯뱰뱱뱲뱳뱴뱵뱶뱷뱸뱹뱺뱻뱼뱽뱾뱿벀벁벂벃버벅벆벇번벉벊벋벌벍벎벏벐벑벒벓범법벖벗벘벙벚벛벜벝벞벟베벡벢벣벤벥벦벧벨벩벪벫벬벭벮벯벰벱벲벳벴벵벶벷벸벹벺벻벼벽벾벿변볁볂볃별볅볆볇볈볉볊볋볌볍볎볏볐병볒볓볔볕볖볗볘볙볚볛볜볝볞볟볠볡볢볣볤볥볦볧볨볩볪볫볬볭볮볯볰볱볲볳보복볶볷본볹볺볻볼볽볾볿봀봁봂봃봄봅봆봇봈봉봊봋봌봍봎봏봐봑봒봓봔봕봖봗봘봙봚봛봜봝봞봟봠봡봢봣봤봥봦봧봨봩봪봫봬봭봮봯봰봱봲봳봴봵봶봷봸봹봺봻봼봽봾봿뵀뵁뵂뵃뵄뵅뵆뵇뵈뵉뵊뵋뵌뵍뵎뵏뵐뵑뵒뵓뵔뵕뵖뵗뵘뵙뵚뵛뵜뵝뵞뵟뵠뵡뵢뵣뵤뵥뵦뵧뵨뵩뵪뵫뵬뵭뵮뵯뵰뵱뵲뵳뵴뵵뵶뵷뵸뵹뵺뵻뵼뵽뵾뵿부북붂붃분붅붆붇불붉붊붋붌붍붎붏붐붑붒붓붔붕붖붗붘붙붚붛붜붝붞붟붠붡붢붣붤붥붦붧붨붩붪붫붬붭붮붯붰붱붲붳붴붵붶붷붸붹붺붻붼붽붾붿뷀뷁뷂뷃뷄뷅뷆뷇뷈뷉뷊뷋뷌뷍뷎뷏뷐뷑뷒뷓뷔뷕뷖뷗뷘뷙뷚뷛뷜뷝뷞뷟뷠뷡뷢뷣뷤뷥뷦뷧뷨뷩뷪뷫뷬뷭뷮뷯뷰뷱뷲뷳뷴뷵뷶뷷뷸뷹뷺뷻뷼뷽뷾뷿븀븁븂븃븄븅븆븇븈븉븊븋브븍븎븏븐븑븒븓블븕븖븗븘븙븚븛븜븝븞븟븠븡븢븣븤븥븦븧븨븩븪븫븬븭븮븯븰븱븲븳븴븵븶븷븸븹븺븻븼븽븾븿빀빁빂빃비빅빆빇빈빉빊빋빌빍빎빏빐빑빒빓빔빕빖빗빘빙빚빛빜빝빞빟빠빡빢빣빤빥빦빧빨빩빪빫빬빭빮빯빰빱빲빳빴빵빶빷빸빹빺빻빼빽빾빿뺀뺁뺂뺃뺄뺅뺆뺇뺈뺉뺊뺋뺌뺍뺎뺏뺐뺑뺒뺓뺔뺕뺖뺗뺘뺙뺚뺛뺜뺝뺞뺟뺠뺡뺢뺣뺤뺥뺦뺧뺨뺩뺪뺫뺬뺭뺮뺯뺰뺱뺲뺳뺴뺵뺶뺷뺸뺹뺺뺻뺼뺽뺾뺿뻀뻁뻂뻃뻄뻅뻆뻇뻈뻉뻊뻋뻌뻍뻎뻏뻐뻑뻒뻓뻔뻕뻖뻗뻘뻙뻚뻛뻜뻝뻞뻟뻠뻡뻢뻣뻤뻥뻦뻧뻨뻩뻪뻫뻬뻭뻮뻯뻰뻱뻲뻳뻴뻵뻶뻷뻸뻹뻺뻻뻼뻽뻾뻿뼀뼁뼂뼃뼄뼅뼆뼇뼈뼉뼊뼋뼌뼍뼎뼏뼐뼑뼒뼓뼔뼕뼖뼗뼘뼙뼚뼛뼜뼝뼞뼟뼠뼡뼢뼣뼤뼥뼦뼧뼨뼩뼪뼫뼬뼭뼮뼯뼰뼱뼲뼳뼴뼵뼶뼷뼸뼹뼺뼻뼼뼽뼾뼿뽀뽁뽂뽃뽄뽅뽆뽇뽈뽉뽊뽋뽌뽍뽎뽏뽐뽑뽒뽓뽔뽕뽖뽗뽘뽙뽚뽛뽜뽝뽞뽟뽠뽡뽢뽣뽤뽥뽦뽧뽨뽩뽪뽫뽬뽭뽮뽯뽰뽱뽲뽳뽴뽵뽶뽷뽸뽹뽺뽻뽼뽽뽾뽿뾀뾁뾂뾃뾄뾅뾆뾇뾈뾉뾊뾋뾌뾍뾎뾏뾐뾑뾒뾓뾔뾕뾖뾗뾘뾙뾚뾛뾜뾝뾞뾟뾠뾡뾢뾣뾤뾥뾦뾧뾨뾩뾪뾫뾬뾭뾮뾯뾰뾱뾲뾳뾴뾵뾶뾷뾸뾹뾺뾻뾼뾽뾾뾿뿀뿁뿂뿃뿄뿅뿆뿇뿈뿉뿊뿋뿌뿍뿎뿏뿐뿑뿒뿓뿔뿕뿖뿗뿘뿙뿚뿛뿜뿝뿞뿟뿠뿡뿢뿣뿤뿥뿦뿧뿨뿩뿪뿫뿬뿭뿮뿯뿰뿱뿲뿳뿴뿵뿶뿷뿸뿹뿺뿻뿼뿽뿾뿿쀀쀁쀂쀃쀄쀅쀆쀇쀈쀉쀊쀋쀌쀍쀎쀏쀐쀑쀒쀓쀔쀕쀖쀗쀘쀙쀚쀛쀜쀝쀞쀟쀠쀡쀢쀣쀤쀥쀦쀧쀨쀩쀪쀫쀬쀭쀮쀯쀰쀱쀲쀳쀴쀵쀶쀷쀸쀹쀺쀻쀼쀽쀾쀿쁀쁁쁂쁃쁄쁅쁆쁇쁈쁉쁊쁋쁌쁍쁎쁏쁐쁑쁒쁓쁔쁕쁖쁗쁘쁙쁚쁛쁜쁝쁞쁟쁠쁡쁢쁣쁤쁥쁦쁧쁨쁩쁪쁫쁬쁭쁮쁯쁰쁱쁲쁳쁴쁵쁶쁷쁸쁹쁺쁻쁼쁽쁾쁿삀삁삂삃삄삅삆삇삈삉삊삋삌삍삎삏삐삑삒삓삔삕삖삗삘삙삚삛삜삝삞삟삠삡삢삣삤삥삦삧삨삩삪삫사삭삮삯산삱삲삳살삵삶삷삸삹삺삻삼삽삾삿샀상샂샃샄샅샆샇새색샊샋샌샍샎샏샐샑샒샓샔샕샖샗샘샙샚샛샜생샞샟샠샡샢샣샤샥샦샧샨샩샪샫샬샭샮샯샰샱샲샳샴샵샶샷샸샹샺샻샼샽샾샿섀섁섂섃섄섅섆섇섈섉섊섋섌섍섎섏섐섑섒섓섔섕섖섗섘섙섚섛서석섞섟선섡섢섣설섥섦섧섨섩섪섫섬섭섮섯섰성섲섳섴섵섶섷세섹섺섻센섽섾섿셀셁셂셃셄셅셆셇셈셉셊셋셌셍셎셏셐셑셒셓셔셕셖셗션셙셚셛셜셝셞셟셠셡셢셣셤셥셦셧셨셩셪셫셬셭셮셯셰셱셲셳셴셵셶셷셸셹셺셻셼셽셾셿솀솁솂솃솄솅솆솇솈솉솊솋소속솎솏손솑솒솓솔솕솖솗솘솙솚솛솜솝솞솟솠송솢솣솤솥솦솧솨솩솪솫솬솭솮솯솰솱솲솳솴솵솶솷솸솹솺솻솼솽솾솿쇀쇁쇂쇃쇄쇅쇆쇇쇈쇉쇊쇋쇌쇍쇎쇏쇐쇑쇒쇓쇔쇕쇖쇗쇘쇙쇚쇛쇜쇝쇞쇟쇠쇡쇢쇣쇤쇥쇦쇧쇨쇩쇪쇫쇬쇭쇮쇯쇰쇱쇲쇳쇴쇵쇶쇷쇸쇹쇺쇻쇼쇽쇾쇿숀숁숂숃숄숅숆숇숈숉숊숋숌숍숎숏숐숑숒숓숔숕숖숗수숙숚숛순숝숞숟술숡숢숣숤숥숦숧숨숩숪숫숬숭숮숯숰숱숲숳숴숵숶숷숸숹숺숻숼숽숾숿쉀쉁쉂쉃쉄쉅쉆쉇쉈쉉쉊쉋쉌쉍쉎쉏쉐쉑쉒쉓쉔쉕쉖쉗쉘쉙쉚쉛쉜쉝쉞쉟쉠쉡쉢쉣쉤쉥쉦쉧쉨쉩쉪쉫쉬쉭쉮쉯쉰쉱쉲쉳쉴쉵쉶쉷쉸쉹쉺쉻쉼쉽쉾쉿슀슁슂슃슄슅슆슇슈슉슊슋슌슍슎슏슐슑슒슓슔슕슖슗슘슙슚슛슜슝슞슟슠슡슢슣스슥슦슧슨슩슪슫슬슭슮슯슰슱슲슳슴습슶슷슸승슺슻슼슽슾슿싀싁싂싃싄싅싆싇싈싉싊싋싌싍싎싏싐싑싒싓싔싕싖싗싘싙싚싛시식싞싟신싡싢싣실싥싦싧싨싩싪싫심십싮싯싰싱싲싳싴싵싶싷싸싹싺싻싼싽싾싿쌀쌁쌂쌃쌄쌅쌆쌇쌈쌉쌊쌋쌌쌍쌎쌏쌐쌑쌒쌓쌔쌕쌖쌗쌘쌙쌚쌛쌜쌝쌞쌟쌠쌡쌢쌣쌤쌥쌦쌧쌨쌩쌪쌫쌬쌭쌮쌯쌰쌱쌲쌳쌴쌵쌶쌷쌸쌹쌺쌻쌼쌽쌾쌿썀썁썂썃썄썅썆썇썈썉썊썋썌썍썎썏썐썑썒썓썔썕썖썗썘썙썚썛썜썝썞썟썠썡썢썣썤썥썦썧써썩썪썫썬썭썮썯썰썱썲썳썴썵썶썷썸썹썺썻썼썽썾썿쎀쎁쎂쎃쎄쎅쎆쎇쎈쎉쎊쎋쎌쎍쎎쎏쎐쎑쎒쎓쎔쎕쎖쎗쎘쎙쎚쎛쎜쎝쎞쎟쎠쎡쎢쎣쎤쎥쎦쎧쎨쎩쎪쎫쎬쎭쎮쎯쎰쎱쎲쎳쎴쎵쎶쎷쎸쎹쎺쎻쎼쎽쎾쎿쏀쏁쏂쏃쏄쏅쏆쏇쏈쏉쏊쏋쏌쏍쏎쏏쏐쏑쏒쏓쏔쏕쏖쏗쏘쏙쏚쏛쏜쏝쏞쏟쏠쏡쏢쏣쏤쏥쏦쏧쏨쏩쏪쏫쏬쏭쏮쏯쏰쏱쏲쏳쏴쏵쏶쏷쏸쏹쏺쏻쏼쏽쏾쏿쐀쐁쐂쐃쐄쐅쐆쐇쐈쐉쐊쐋쐌쐍쐎쐏쐐쐑쐒쐓쐔쐕쐖쐗쐘쐙쐚쐛쐜쐝쐞쐟쐠쐡쐢쐣쐤쐥쐦쐧쐨쐩쐪쐫쐬쐭쐮쐯쐰쐱쐲쐳쐴쐵쐶쐷쐸쐹쐺쐻쐼쐽쐾쐿쑀쑁쑂쑃쑄쑅쑆쑇쑈쑉쑊쑋쑌쑍쑎쑏쑐쑑쑒쑓쑔쑕쑖쑗쑘쑙쑚쑛쑜쑝쑞쑟쑠쑡쑢쑣쑤쑥쑦쑧쑨쑩쑪쑫쑬쑭쑮쑯쑰쑱쑲쑳쑴쑵쑶쑷쑸쑹쑺쑻쑼쑽쑾쑿쒀쒁쒂쒃쒄쒅쒆쒇쒈쒉쒊쒋쒌쒍쒎쒏쒐쒑쒒쒓쒔쒕쒖쒗쒘쒙쒚쒛쒜쒝쒞쒟쒠쒡쒢쒣쒤쒥쒦쒧쒨쒩쒪쒫쒬쒭쒮쒯쒰쒱쒲쒳쒴쒵쒶쒷쒸쒹쒺쒻쒼쒽쒾쒿쓀쓁쓂쓃쓄쓅쓆쓇쓈쓉쓊쓋쓌쓍쓎쓏쓐쓑쓒쓓쓔쓕쓖쓗쓘쓙쓚쓛쓜쓝쓞쓟쓠쓡쓢쓣쓤쓥쓦쓧쓨쓩쓪쓫쓬쓭쓮쓯쓰쓱쓲쓳쓴쓵쓶쓷쓸쓹쓺쓻쓼쓽쓾쓿씀씁씂씃씄씅씆씇씈씉씊씋씌씍씎씏씐씑씒씓씔씕씖씗씘씙씚씛씜씝씞씟씠씡씢씣씤씥씦씧씨씩씪씫씬씭씮씯씰씱씲씳씴씵씶씷씸씹씺씻씼씽씾씿앀앁앂앃아악앆앇안앉않앋알앍앎앏앐앑앒앓암압앖앗았앙앚앛앜앝앞앟애액앢앣앤앥앦앧앨앩앪앫앬앭앮앯앰앱앲앳앴앵앶앷앸앹앺앻야약앾앿얀얁얂얃얄얅얆얇얈얉얊얋얌얍얎얏얐양얒얓얔얕얖얗얘얙얚얛얜얝얞얟얠얡얢얣얤얥얦얧얨얩얪얫얬얭얮얯얰얱얲얳어억얶얷언얹얺얻얼얽얾얿엀엁엂엃엄업없엇었엉엊엋엌엍엎엏에엑엒엓엔엕엖엗엘엙엚엛엜엝엞엟엠엡엢엣엤엥엦엧엨엩엪엫여역엮엯연엱엲엳열엵엶엷엸엹엺엻염엽엾엿였영옂옃옄옅옆옇예옉옊옋옌옍옎옏옐옑옒옓옔옕옖옗옘옙옚옛옜옝옞옟옠옡옢옣오옥옦옧온옩옪옫올옭옮옯옰옱옲옳옴옵옶옷옸옹옺옻옼옽옾옿와왁왂왃완왅왆왇왈왉왊왋왌왍왎왏왐왑왒왓왔왕왖왗왘왙왚왛왜왝왞왟왠왡왢왣왤왥왦왧왨왩왪왫왬왭왮왯왰왱왲왳왴왵왶왷외왹왺왻왼왽왾왿욀욁욂욃욄욅욆욇욈욉욊욋욌욍욎욏욐욑욒욓요욕욖욗욘욙욚욛욜욝욞욟욠욡욢욣욤욥욦욧욨용욪욫욬욭욮욯우욱욲욳운욵욶욷울욹욺욻욼욽욾욿움웁웂웃웄웅웆웇웈웉웊웋워웍웎웏원웑웒웓월웕웖웗웘웙웚웛웜웝웞웟웠웡웢웣웤웥웦웧웨웩웪웫웬웭웮웯웰웱웲웳웴웵웶웷웸웹웺웻웼웽웾웿윀윁윂윃위윅윆윇윈윉윊윋윌윍윎윏윐윑윒윓윔윕윖윗윘윙윚윛윜윝윞윟유육윢윣윤윥윦윧율윩윪윫윬윭윮윯윰윱윲윳윴융윶윷윸윹윺윻으윽윾윿은읁읂읃을읅읆읇읈읉읊읋음읍읎읏읐응읒읓읔읕읖읗의읙읚읛읜읝읞읟읠읡읢읣읤읥읦읧읨읩읪읫읬읭읮읯읰읱읲읳이익읶읷인읹읺읻일읽읾읿잀잁잂잃임입잆잇있잉잊잋잌잍잎잏자작잒잓잔잕잖잗잘잙잚잛잜잝잞잟잠잡잢잣잤장잦잧잨잩잪잫재잭잮잯잰잱잲잳잴잵잶잷잸잹잺잻잼잽잾잿쟀쟁쟂쟃쟄쟅쟆쟇쟈쟉쟊쟋쟌쟍쟎쟏쟐쟑쟒쟓쟔쟕쟖쟗쟘쟙쟚쟛쟜쟝쟞쟟쟠쟡쟢쟣쟤쟥쟦쟧쟨쟩쟪쟫쟬쟭쟮쟯쟰쟱쟲쟳쟴쟵쟶쟷쟸쟹쟺쟻쟼쟽쟾쟿저적젂젃전젅젆젇절젉젊젋젌젍젎젏점접젒젓젔정젖젗젘젙젚젛제젝젞젟젠젡젢젣젤젥젦젧젨젩젪젫젬젭젮젯젰젱젲젳젴젵젶젷져젹젺젻젼젽젾젿졀졁졂졃졄졅졆졇졈졉졊졋졌졍졎졏졐졑졒졓졔졕졖졗졘졙졚졛졜졝졞졟졠졡졢졣졤졥졦졧졨졩졪졫졬졭졮졯조족졲졳존졵졶졷졸졹졺졻졼졽졾졿좀좁좂좃좄종좆좇좈좉좊좋좌좍좎좏좐좑좒좓좔좕좖좗좘좙좚좛좜좝좞좟좠좡좢좣좤좥좦좧좨좩좪좫좬좭좮좯좰좱좲좳좴좵좶좷좸좹좺좻좼좽좾좿죀죁죂죃죄죅죆죇죈죉죊죋죌죍죎죏죐죑죒죓죔죕죖죗죘죙죚죛죜죝죞죟죠죡죢죣죤죥죦죧죨죩죪죫죬죭죮죯죰죱죲죳죴죵죶죷죸죹죺죻주죽죾죿준줁줂줃줄줅줆줇줈줉줊줋줌줍줎줏줐중줒줓줔줕줖줗줘줙줚줛줜줝줞줟줠줡줢줣줤줥줦줧줨줩줪줫줬줭줮줯줰줱줲줳줴줵줶줷줸줹줺줻줼줽줾줿쥀쥁쥂쥃쥄쥅쥆쥇쥈쥉쥊쥋쥌쥍쥎쥏쥐쥑쥒쥓쥔쥕쥖쥗쥘쥙쥚쥛쥜쥝쥞쥟쥠쥡쥢쥣쥤쥥쥦쥧쥨쥩쥪쥫쥬쥭쥮쥯쥰쥱쥲쥳쥴쥵쥶쥷쥸쥹쥺쥻쥼쥽쥾쥿즀즁즂즃즄즅즆즇즈즉즊즋즌즍즎즏즐즑즒즓즔즕즖즗즘즙즚즛즜증즞즟즠즡즢즣즤즥즦즧즨즩즪즫즬즭즮즯즰즱즲즳즴즵즶즷즸즹즺즻즼즽즾즿지직짂짃진짅짆짇질짉짊짋짌짍짎짏짐집짒짓짔징짖짗짘짙짚짛짜짝짞짟짠짡짢짣짤짥짦짧짨짩짪짫짬짭짮짯짰짱짲짳짴짵짶짷째짹짺짻짼짽짾짿쨀쨁쨂쨃쨄쨅쨆쨇쨈쨉쨊쨋쨌쨍쨎쨏쨐쨑쨒쨓쨔쨕쨖쨗쨘쨙쨚쨛쨜쨝쨞쨟쨠쨡쨢쨣쨤쨥쨦쨧쨨쨩쨪쨫쨬쨭쨮쨯쨰쨱쨲쨳쨴쨵쨶쨷쨸쨹쨺쨻쨼쨽쨾쨿쩀쩁쩂쩃쩄쩅쩆쩇쩈쩉쩊쩋쩌쩍쩎쩏쩐쩑쩒쩓쩔쩕쩖쩗쩘쩙쩚쩛쩜쩝쩞쩟쩠쩡쩢쩣쩤쩥쩦쩧쩨쩩쩪쩫쩬쩭쩮쩯쩰쩱쩲쩳쩴쩵쩶쩷쩸쩹쩺쩻쩼쩽쩾쩿쪀쪁쪂쪃쪄쪅쪆쪇쪈쪉쪊쪋쪌쪍쪎쪏쪐쪑쪒쪓쪔쪕쪖쪗쪘쪙쪚쪛쪜쪝쪞쪟쪠쪡쪢쪣쪤쪥쪦쪧쪨쪩쪪쪫쪬쪭쪮쪯쪰쪱쪲쪳쪴쪵쪶쪷쪸쪹쪺쪻쪼쪽쪾쪿쫀쫁쫂쫃쫄쫅쫆쫇쫈쫉쫊쫋쫌쫍쫎쫏쫐쫑쫒쫓쫔쫕쫖쫗쫘쫙쫚쫛쫜쫝쫞쫟쫠쫡쫢쫣쫤쫥쫦쫧쫨쫩쫪쫫쫬쫭쫮쫯쫰쫱쫲쫳쫴쫵쫶쫷쫸쫹쫺쫻쫼쫽쫾쫿쬀쬁쬂쬃쬄쬅쬆쬇쬈쬉쬊쬋쬌쬍쬎쬏쬐쬑쬒쬓쬔쬕쬖쬗쬘쬙쬚쬛쬜쬝쬞쬟쬠쬡쬢쬣쬤쬥쬦쬧쬨쬩쬪쬫쬬쬭쬮쬯쬰쬱쬲쬳쬴쬵쬶쬷쬸쬹쬺쬻쬼쬽쬾쬿쭀쭁쭂쭃쭄쭅쭆쭇쭈쭉쭊쭋쭌쭍쭎쭏쭐쭑쭒쭓쭔쭕쭖쭗쭘쭙쭚쭛쭜쭝쭞쭟쭠쭡쭢쭣쭤쭥쭦쭧쭨쭩쭪쭫쭬쭭쭮쭯쭰쭱쭲쭳쭴쭵쭶쭷쭸쭹쭺쭻쭼쭽쭾쭿쮀쮁쮂쮃쮄쮅쮆쮇쮈쮉쮊쮋쮌쮍쮎쮏쮐쮑쮒쮓쮔쮕쮖쮗쮘쮙쮚쮛쮜쮝쮞쮟쮠쮡쮢쮣쮤쮥쮦쮧쮨쮩쮪쮫쮬쮭쮮쮯쮰쮱쮲쮳쮴쮵쮶쮷쮸쮹쮺쮻쮼쮽쮾쮿쯀쯁쯂쯃쯄쯅쯆쯇쯈쯉쯊쯋쯌쯍쯎쯏쯐쯑쯒쯓쯔쯕쯖쯗쯘쯙쯚쯛쯜쯝쯞쯟쯠쯡쯢쯣쯤쯥쯦쯧쯨쯩쯪쯫쯬쯭쯮쯯쯰쯱쯲쯳쯴쯵쯶쯷쯸쯹쯺쯻쯼쯽쯾쯿찀찁찂찃찄찅찆찇찈찉찊찋찌찍찎찏찐찑찒찓찔찕찖찗찘찙찚찛찜찝찞찟찠찡찢찣찤찥찦찧차착찪찫찬찭찮찯찰찱찲찳찴찵찶찷참찹찺찻찼창찾찿챀챁챂챃채책챆챇챈챉챊챋챌챍챎챏챐챑챒챓챔챕챖챗챘챙챚챛챜챝챞챟챠챡챢챣챤챥챦챧챨챩챪챫챬챭챮챯챰챱챲챳챴챵챶챷챸챹챺챻챼챽챾챿첀첁첂첃첄첅첆첇첈첉첊첋첌첍첎첏첐첑첒첓첔첕첖첗처척첚첛천첝첞첟철첡첢첣첤첥첦첧첨첩첪첫첬청첮첯첰첱첲첳체첵첶첷첸첹첺첻첼첽첾첿쳀쳁쳂쳃쳄쳅쳆쳇쳈쳉쳊쳋쳌쳍쳎쳏쳐쳑쳒쳓쳔쳕쳖쳗쳘쳙쳚쳛쳜쳝쳞쳟쳠쳡쳢쳣쳤쳥쳦쳧쳨쳩쳪쳫쳬쳭쳮쳯쳰쳱쳲쳳쳴쳵쳶쳷쳸쳹쳺쳻쳼쳽쳾쳿촀촁촂촃촄촅촆촇초촉촊촋촌촍촎촏촐촑촒촓촔촕촖촗촘촙촚촛촜총촞촟촠촡촢촣촤촥촦촧촨촩촪촫촬촭촮촯촰촱촲촳촴촵촶촷촸촹촺촻촼촽촾촿쵀쵁쵂쵃쵄쵅쵆쵇쵈쵉쵊쵋쵌쵍쵎쵏쵐쵑쵒쵓쵔쵕쵖쵗쵘쵙쵚쵛최쵝쵞쵟쵠쵡쵢쵣쵤쵥쵦쵧쵨쵩쵪쵫쵬쵭쵮쵯쵰쵱쵲쵳쵴쵵쵶쵷쵸쵹쵺쵻쵼쵽쵾쵿춀춁춂춃춄춅춆춇춈춉춊춋춌춍춎춏춐춑춒춓추축춖춗춘춙춚춛출춝춞춟춠춡춢춣춤춥춦춧춨충춪춫춬춭춮춯춰춱춲춳춴춵춶춷춸춹춺춻춼춽춾춿췀췁췂췃췄췅췆췇췈췉췊췋췌췍췎췏췐췑췒췓췔췕췖췗췘췙췚췛췜췝췞췟췠췡췢췣췤췥췦췧취췩췪췫췬췭췮췯췰췱췲췳췴췵췶췷췸췹췺췻췼췽췾췿츀츁츂츃츄츅츆츇츈츉츊츋츌츍츎츏츐츑츒츓츔츕츖츗츘츙츚츛츜츝츞츟츠측츢츣츤츥츦츧츨츩츪츫츬츭츮츯츰츱츲츳츴층츶츷츸츹츺츻츼츽츾츿칀칁칂칃칄칅칆칇칈칉칊칋칌칍칎칏칐칑칒칓칔칕칖칗치칙칚칛친칝칞칟칠칡칢칣칤칥칦칧침칩칪칫칬칭칮칯칰칱칲칳카칵칶칷칸칹칺칻칼칽칾칿캀캁캂캃캄캅캆캇캈캉캊캋캌캍캎캏캐캑캒캓캔캕캖캗캘캙캚캛캜캝캞캟캠캡캢캣캤캥캦캧캨캩캪캫캬캭캮캯캰캱캲캳캴캵캶캷캸캹캺캻캼캽캾캿컀컁컂컃컄컅컆컇컈컉컊컋컌컍컎컏컐컑컒컓컔컕컖컗컘컙컚컛컜컝컞컟컠컡컢컣커컥컦컧컨컩컪컫컬컭컮컯컰컱컲컳컴컵컶컷컸컹컺컻컼컽컾컿케켁켂켃켄켅켆켇켈켉켊켋켌켍켎켏켐켑켒켓켔켕켖켗켘켙켚켛켜켝켞켟켠켡켢켣켤켥켦켧켨켩켪켫켬켭켮켯켰켱켲켳켴켵켶켷켸켹켺켻켼켽켾켿콀콁콂콃콄콅콆콇콈콉콊콋콌콍콎콏콐콑콒콓코콕콖콗콘콙콚콛콜콝콞콟콠콡콢콣콤콥콦콧콨콩콪콫콬콭콮콯콰콱콲콳콴콵콶콷콸콹콺콻콼콽콾콿쾀쾁쾂쾃쾄쾅쾆쾇쾈쾉쾊쾋쾌쾍쾎쾏쾐쾑쾒쾓쾔쾕쾖쾗쾘쾙쾚쾛쾜쾝쾞쾟쾠쾡쾢쾣쾤쾥쾦쾧쾨쾩쾪쾫쾬쾭쾮쾯쾰쾱쾲쾳쾴쾵쾶쾷쾸쾹쾺쾻쾼쾽쾾쾿쿀쿁쿂쿃쿄쿅쿆쿇쿈쿉쿊쿋쿌쿍쿎쿏쿐쿑쿒쿓쿔쿕쿖쿗쿘쿙쿚쿛쿜쿝쿞쿟쿠쿡쿢쿣쿤쿥쿦쿧쿨쿩쿪쿫쿬쿭쿮쿯쿰쿱쿲쿳쿴쿵쿶쿷쿸쿹쿺쿻쿼쿽쿾쿿퀀퀁퀂퀃퀄퀅퀆퀇퀈퀉퀊퀋퀌퀍퀎퀏퀐퀑퀒퀓퀔퀕퀖퀗퀘퀙퀚퀛퀜퀝퀞퀟퀠퀡퀢퀣퀤퀥퀦퀧퀨퀩퀪퀫퀬퀭퀮퀯퀰퀱퀲퀳퀴퀵퀶퀷퀸퀹퀺퀻퀼퀽퀾퀿큀큁큂큃큄큅큆큇큈큉큊큋큌큍큎큏큐큑큒큓큔큕큖큗큘큙큚큛큜큝큞큟큠큡큢큣큤큥큦큧큨큩큪큫크큭큮큯큰큱큲큳클큵큶큷큸큹큺큻큼큽큾큿킀킁킂킃킄킅킆킇킈킉킊킋킌킍킎킏킐킑킒킓킔킕킖킗킘킙킚킛킜킝킞킟킠킡킢킣키킥킦킧킨킩킪킫킬킭킮킯킰킱킲킳킴킵킶킷킸킹킺킻킼킽킾킿타탁탂탃탄탅탆탇탈탉탊탋탌탍탎탏탐탑탒탓탔탕탖탗탘탙탚탛태택탞탟탠탡탢탣탤탥탦탧탨탩탪탫탬탭탮탯탰탱탲탳탴탵탶탷탸탹탺탻탼탽탾탿턀턁턂턃턄턅턆턇턈턉턊턋턌턍턎턏턐턑턒턓턔턕턖턗턘턙턚턛턜턝턞턟턠턡턢턣턤턥턦턧턨턩턪턫턬턭턮턯터턱턲턳턴턵턶턷털턹턺턻턼턽턾턿텀텁텂텃텄텅텆텇텈텉텊텋테텍텎텏텐텑텒텓텔텕텖텗텘텙텚텛템텝텞텟텠텡텢텣텤텥텦텧텨텩텪텫텬텭텮텯텰텱텲텳텴텵텶텷텸텹텺텻텼텽텾텿톀톁톂톃톄톅톆톇톈톉톊톋톌톍톎톏톐톑톒톓톔톕톖톗톘톙톚톛톜톝톞톟토톡톢톣톤톥톦톧톨톩톪톫톬톭톮톯톰톱톲톳톴통톶톷톸톹톺톻톼톽톾톿퇀퇁퇂퇃퇄퇅퇆퇇퇈퇉퇊퇋퇌퇍퇎퇏퇐퇑퇒퇓퇔퇕퇖퇗퇘퇙퇚퇛퇜퇝퇞퇟퇠퇡퇢퇣퇤퇥퇦퇧퇨퇩퇪퇫퇬퇭퇮퇯퇰퇱퇲퇳퇴퇵퇶퇷퇸퇹퇺퇻퇼퇽퇾퇿툀툁툂툃툄툅툆툇툈툉툊툋툌툍툎툏툐툑툒툓툔툕툖툗툘툙툚툛툜툝툞툟툠툡툢툣툤툥툦툧툨툩툪툫투툭툮툯툰툱툲툳툴툵툶툷툸툹툺툻툼툽툾툿퉀퉁퉂퉃퉄퉅퉆퉇퉈퉉퉊퉋퉌퉍퉎퉏퉐퉑퉒퉓퉔퉕퉖퉗퉘퉙퉚퉛퉜퉝퉞퉟퉠퉡퉢퉣퉤퉥퉦퉧퉨퉩퉪퉫퉬퉭퉮퉯퉰퉱퉲퉳퉴퉵퉶퉷퉸퉹퉺퉻퉼퉽퉾퉿튀튁튂튃튄튅튆튇튈튉튊튋튌튍튎튏튐튑튒튓튔튕튖튗튘튙튚튛튜튝튞튟튠튡튢튣튤튥튦튧튨튩튪튫튬튭튮튯튰튱튲튳튴튵튶튷트특튺튻튼튽튾튿틀틁틂틃틄틅틆틇틈틉틊틋틌틍틎틏틐틑틒틓틔틕틖틗틘틙틚틛틜틝틞틟틠틡틢틣틤틥틦틧틨틩틪틫틬틭틮틯티틱틲틳틴틵틶틷틸틹틺틻틼틽틾틿팀팁팂팃팄팅팆팇팈팉팊팋파팍팎팏판팑팒팓팔팕팖팗팘팙팚팛팜팝팞팟팠팡팢팣팤팥팦팧패팩팪팫팬팭팮팯팰팱팲팳팴팵팶팷팸팹팺팻팼팽팾팿퍀퍁퍂퍃퍄퍅퍆퍇퍈퍉퍊퍋퍌퍍퍎퍏퍐퍑퍒퍓퍔퍕퍖퍗퍘퍙퍚퍛퍜퍝퍞퍟퍠퍡퍢퍣퍤퍥퍦퍧퍨퍩퍪퍫퍬퍭퍮퍯퍰퍱퍲퍳퍴퍵퍶퍷퍸퍹퍺퍻퍼퍽퍾퍿펀펁펂펃펄펅펆펇펈펉펊펋펌펍펎펏펐펑펒펓펔펕펖펗페펙펚펛펜펝펞펟펠펡펢펣펤펥펦펧펨펩펪펫펬펭펮펯펰펱펲펳펴펵펶펷편펹펺펻펼펽펾펿폀폁폂폃폄폅폆폇폈평폊폋폌폍폎폏폐폑폒폓폔폕폖폗폘폙폚폛폜폝폞폟폠폡폢폣폤폥폦폧폨폩폪폫포폭폮폯폰폱폲폳폴폵폶폷폸폹폺폻폼폽폾폿퐀퐁퐂퐃퐄퐅퐆퐇퐈퐉퐊퐋퐌퐍퐎퐏퐐퐑퐒퐓퐔퐕퐖퐗퐘퐙퐚퐛퐜퐝퐞퐟퐠퐡퐢퐣퐤퐥퐦퐧퐨퐩퐪퐫퐬퐭퐮퐯퐰퐱퐲퐳퐴퐵퐶퐷퐸퐹퐺퐻퐼퐽퐾퐿푀푁푂푃푄푅푆푇푈푉푊푋푌푍푎푏푐푑푒푓푔푕푖푗푘푙푚푛표푝푞푟푠푡푢푣푤푥푦푧푨푩푪푫푬푭푮푯푰푱푲푳푴푵푶푷푸푹푺푻푼푽푾푿풀풁풂풃풄풅풆풇품풉풊풋풌풍풎풏풐풑풒풓풔풕풖풗풘풙풚풛풜풝풞풟풠풡풢풣풤풥풦풧풨풩풪풫풬풭풮풯풰풱풲풳풴풵풶풷풸풹풺풻풼풽풾풿퓀퓁퓂퓃퓄퓅퓆퓇퓈퓉퓊퓋퓌퓍퓎퓏퓐퓑퓒퓓퓔퓕퓖퓗퓘퓙퓚퓛퓜퓝퓞퓟퓠퓡퓢퓣퓤퓥퓦퓧퓨퓩퓪퓫퓬퓭퓮퓯퓰퓱퓲퓳퓴퓵퓶퓷퓸퓹퓺퓻퓼퓽퓾퓿픀픁픂픃프픅픆픇픈픉픊픋플픍픎픏픐픑픒픓픔픕픖픗픘픙픚픛픜픝픞픟픠픡픢픣픤픥픦픧픨픩픪픫픬픭픮픯픰픱픲픳픴픵픶픷픸픹픺픻피픽픾픿핀핁핂핃필핅핆핇핈핉핊핋핌핍핎핏핐핑핒핓핔핕핖핗하학핚핛한핝핞핟할핡핢핣핤핥핦핧함합핪핫핬항핮핯핰핱핲핳해핵핶핷핸핹핺핻핼핽핾핿햀햁햂햃햄햅햆햇했행햊햋햌햍햎햏햐햑햒햓햔햕햖햗햘햙햚햛햜햝햞햟햠햡햢햣햤향햦햧햨햩햪햫햬햭햮햯햰햱햲햳햴햵햶햷햸햹햺햻햼햽햾햿헀헁헂헃헄헅헆헇허헉헊헋헌헍헎헏헐헑헒헓헔헕헖헗험헙헚헛헜헝헞헟헠헡헢헣헤헥헦헧헨헩헪헫헬헭헮헯헰헱헲헳헴헵헶헷헸헹헺헻헼헽헾헿혀혁혂혃현혅혆혇혈혉혊혋혌혍혎혏혐협혒혓혔형혖혗혘혙혚혛혜혝혞혟혠혡혢혣혤혥혦혧혨혩혪혫혬혭혮혯혰혱혲혳혴혵혶혷호혹혺혻혼혽혾혿홀홁홂홃홄홅홆홇홈홉홊홋홌홍홎홏홐홑홒홓화확홖홗환홙홚홛활홝홞홟홠홡홢홣홤홥홦홧홨황홪홫홬홭홮홯홰홱홲홳홴홵홶홷홸홹홺홻홼홽홾홿횀횁횂횃횄횅횆횇횈횉횊횋회획횎횏횐횑횒횓횔횕횖횗횘횙횚횛횜횝횞횟횠횡횢횣횤횥횦횧효횩횪횫횬횭횮횯횰횱횲횳횴횵횶횷횸횹횺횻횼횽횾횿훀훁훂훃후훅훆훇훈훉훊훋훌훍훎훏훐훑훒훓훔훕훖훗훘훙훚훛훜훝훞훟훠훡훢훣훤훥훦훧훨훩훪훫훬훭훮훯훰훱훲훳훴훵훶훷훸훹훺훻훼훽훾훿휀휁휂휃휄휅휆휇휈휉휊휋휌휍휎휏휐휑휒휓휔휕휖휗휘휙휚휛휜휝휞휟휠휡휢휣휤휥휦휧휨휩휪휫휬휭휮휯휰휱휲휳휴휵휶휷휸휹휺휻휼휽휾휿흀흁흂흃흄흅흆흇흈흉흊흋흌흍흎흏흐흑흒흓흔흕흖흗흘흙흚흛흜흝흞흟흠흡흢흣흤흥흦흧흨흩흪흫희흭흮흯흰흱흲흳흴흵흶흷흸흹흺흻흼흽흾흿힀힁힂힃힄힅힆힇히힉힊힋힌힍힎힏힐힑힒힓힔힕힖힗힘힙힚힛힜힝힞힟힠힡힢힣ힰힱힲힳힴힵힶힷힸힹힺힻힼힽힾힿퟀퟁퟂퟃퟄퟅퟆퟋퟌퟍퟎퟏퟐퟑퟒퟓퟔퟕퟖퟗퟘퟙퟚퟛퟜퟝퟞퟟퟠퟡퟢퟣퟤퟥퟦퟧퟨퟩퟪퟫퟬퟭퟮퟯퟰퟱퟲퟳퟴퟵퟶퟷퟸퟹퟺퟻ???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????􏰀???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????豈更車賈滑串句龜龜契金喇奈懶癩羅蘿螺裸邏樂洛烙珞落酪駱亂卵欄爛蘭鸞嵐濫藍襤拉臘蠟廊朗浪狼郎來冷勞擄櫓爐盧老蘆虜路露魯鷺碌祿綠菉錄鹿論壟弄籠聾牢磊賂雷壘屢樓淚漏累縷陋勒肋凜凌稜綾菱陵讀拏樂諾丹寧怒率異北磻便復不泌數索參塞省葉說殺辰沈拾若掠略亮兩凉梁糧良諒量勵呂女廬旅濾礪閭驪麗黎力曆歷轢年憐戀撚漣煉璉秊練聯輦蓮連鍊列劣咽烈裂說廉念捻殮簾獵令囹寧嶺怜玲瑩羚聆鈴零靈領例禮醴隸惡了僚寮尿料樂燎療蓼遼龍暈阮劉杻柳流溜琉留硫紐類六戮陸倫崙淪輪律慄栗率隆利吏履易李梨泥理痢罹裏裡里離匿溺吝燐璘藺隣鱗麟林淋臨立笠粒狀炙識什茶刺切度拓糖宅洞暴輻行降見廓兀嗀﨎﨏塚﨑晴﨓﨔凞猪益礼神祥福靖精羽﨟蘒﨡諸﨣﨤逸都﨧﨨﨩飯飼館鶴郞隷侮僧免勉勤卑喝嘆器塀墨層屮悔慨憎懲敏既暑梅海渚漢煮爫琢碑社祉祈祐祖祝禍禎穀突節練縉繁署者臭艹艹著褐視謁謹賓贈辶逸難響頻恵𤋮舘並况全侀充冀勇勺喝啕喙嗢塚墳奄奔婢嬨廒廙彩徭惘慎愈憎慠懲戴揄搜摒敖晴朗望杖歹殺流滛滋漢瀞煮瞧爵犯猪瑱甆画瘝瘟益盛直睊着磌窱節类絛練缾者荒華蝹襁覆視調諸請謁諾諭謹變贈輸遲醙鉶陼難靖韛響頋頻鬒龜𢡊𢡄𣏕㮝䀘䀹𥉉𥳐𧻓齃龎fffiflffifflſtstﬓﬔﬕﬖﬗיִﬞײַﬠﬡﬢﬣﬤﬥﬦﬧﬨ﬩שׁשׂשּׁשּׂאַאָאּבּגּדּהּוּזּטּיּךּכּלּמּנּסּףּפּצּקּרּשּתּוֹבֿכֿפֿﭏﭐﭑﭒﭓﭔﭕﭖﭗﭘﭙﭚﭛﭜﭝﭞﭟﭠﭡﭢﭣﭤﭥﭦﭧﭨﭩﭪﭫﭬﭭﭮﭯﭰﭱﭲﭳﭴﭵﭶﭷﭸﭹﭺﭻﭼﭽﭾﭿﮀﮁﮂﮃﮄﮅﮆﮇﮈﮉﮊﮋﮌﮍﮎﮏﮐﮑﮒﮓﮔﮕﮖﮗﮘﮙﮚﮛﮜﮝﮞﮟﮠﮡﮢﮣﮤﮥﮦﮧﮨﮩﮪﮫﮬﮭﮮﮯﮰﮱ﮲﮳﮴﮵﮶﮷﮸﮹﮺﮻﮼﮽﮾﮿﯀﯁ﯓﯔﯕﯖﯗﯘﯙﯚﯛﯜﯝﯞﯟﯠﯡﯢﯣﯤﯥﯦﯧﯨﯩﯪﯫﯬﯭﯮﯯﯰﯱﯲﯳﯴﯵﯶﯷﯸﯹﯺﯻﯼﯽﯾﯿﰀﰁﰂﰃﰄﰅﰆﰇﰈﰉﰊﰋﰌﰍﰎﰏﰐﰑﰒﰓﰔﰕﰖﰗﰘﰙﰚﰛﰜﰝﰞﰟﰠﰡﰢﰣﰤﰥﰦﰧﰨﰩﰪﰫﰬﰭﰮﰯﰰﰱﰲﰳﰴﰵﰶﰷﰸﰹﰺﰻﰼﰽﰾﰿﱀﱁﱂﱃﱄﱅﱆﱇﱈﱉﱊﱋﱌﱍﱎﱏﱐﱑﱒﱓﱔﱕﱖﱗﱘﱙﱚﱛﱜﱝﱞﱟﱠﱡﱢﱣﱤﱥﱦﱧﱨﱩﱪﱫﱬﱭﱮﱯﱰﱱﱲﱳﱴﱵﱶﱷﱸﱹﱺﱻﱼﱽﱾﱿﲀﲁﲂﲃﲄﲅﲆﲇﲈﲉﲊﲋﲌﲍﲎﲏﲐﲑﲒﲓﲔﲕﲖﲗﲘﲙﲚﲛﲜﲝﲞﲟﲠﲡﲢﲣﲤﲥﲦﲧﲨﲩﲪﲫﲬﲭﲮﲯﲰﲱﲲﲳﲴﲵﲶﲷﲸﲹﲺﲻﲼﲽﲾﲿﳀﳁﳂﳃﳄﳅﳆﳇﳈﳉﳊﳋﳌﳍﳎﳏﳐﳑﳒﳓﳔﳕﳖﳗﳘﳙﳚﳛﳜﳝﳞﳟﳠﳡﳢﳣﳤﳥﳦﳧﳨﳩﳪﳫﳬﳭﳮﳯﳰﳱﳲﳳﳴﳵﳶﳷﳸﳹﳺﳻﳼﳽﳾﳿﴀﴁﴂﴃﴄﴅﴆﴇﴈﴉﴊﴋﴌﴍﴎﴏﴐﴑﴒﴓﴔﴕﴖﴗﴘﴙﴚﴛﴜﴝﴞﴟﴠﴡﴢﴣﴤﴥﴦﴧﴨﴩﴪﴫﴬﴭﴮﴯﴰﴱﴲﴳﴴﴵﴶﴷﴸﴹﴺﴻﴼﴽ﴾﴿ﵐﵑﵒﵓﵔﵕﵖﵗﵘﵙﵚﵛﵜﵝﵞﵟﵠﵡﵢﵣﵤﵥﵦﵧﵨﵩﵪﵫﵬﵭﵮﵯﵰﵱﵲﵳﵴﵵﵶﵷﵸﵹﵺﵻﵼﵽﵾﵿﶀﶁﶂﶃﶄﶅﶆﶇﶈﶉﶊﶋﶌﶍﶎﶏﶒﶓﶔﶕﶖﶗﶘﶙﶚﶛﶜﶝﶞﶟﶠﶡﶢﶣﶤﶥﶦﶧﶨﶩﶪﶫﶬﶭﶮﶯﶰﶱﶲﶳﶴﶵﶶﶷﶸﶹﶺﶻﶼﶽﶾﶿﷀﷁﷂﷃﷄﷅﷆﷇﷰﷱﷲﷳﷴﷵﷶﷷﷸﷹﷺﷻ﷼﷽︀︁︂︃︄︅︆︇︈︉︊︋︌︍︎️︐︑︒︓︔︕︖︗︘︙︠︡︢︣︤︥︦︰︱︲︳︴︵︶︷︸︹︺︻︼︽︾︿﹀﹁﹂﹃﹄﹅﹆﹇﹈﹉﹊﹋﹌﹍﹎﹏﹐﹑﹒﹔﹕﹖﹗﹘﹙﹚﹛﹜﹝﹞﹟﹠﹡﹢﹣﹤﹥﹦﹨﹩﹪﹫ﹰﹱﹲﹳﹴﹶﹷﹸﹹﹺﹻﹼﹽﹾﹿﺀﺁﺂﺃﺄﺅﺆﺇﺈﺉﺊﺋﺌﺍﺎﺏﺐﺑﺒﺓﺔﺕﺖﺗﺘﺙﺚﺛﺜﺝﺞﺟﺠﺡﺢﺣﺤﺥﺦﺧﺨﺩﺪﺫﺬﺭﺮﺯﺰﺱﺲﺳﺴﺵﺶﺷﺸﺹﺺﺻﺼﺽﺾﺿﻀﻁﻂﻃﻄﻅﻆﻇﻈﻉﻊﻋﻌﻍﻎﻏﻐﻑﻒﻓﻔﻕﻖﻗﻘﻙﻚﻛﻜﻝﻞﻟﻠﻡﻢﻣﻤﻥﻦﻧﻨﻩﻪﻫﻬﻭﻮﻯﻰﻱﻲﻳﻴﻵﻶﻷﻸﻹﻺﻻﻼ!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~⦅⦆。「」、・ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙゚ᅠᄀᄁᆪᄂᆬᆭᄃᄄᄅᆰᆱᆲᆳᆴᆵᄚᄆᄇᄈᄡᄉᄊᄋᄌᄍᄎᄏᄐᄑ하ᅢᅣᅤᅥᅦᅧᅨᅩᅪᅫᅬᅭᅮᅯᅰᅱᅲᅳᅴᅵ¢£¬ ̄¦¥₩│←↑→↓■○�‬‬‬

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